diff --git a/src/core/rpq.c b/src/core/rpq.c index 0473d0b..1cb594d 100644 --- a/src/core/rpq.c +++ b/src/core/rpq.c @@ -455,7 +455,10 @@ static int get_rpq_timezone(H3270 *hSession) delta = difftime(mktime(&here_tm), mktime(utc_tm)) / 60L; } - /* sanity check: difference cannot exceed +/- 12 hours */ + // sanity check: difference cannot exceed +/- 12 hours +#ifdef _WIN32 + #pragma GCC diagnostic ignored "-Wabsolute-value" +#endif // _WIN32 if (labs(delta) > 720L) rpq_warning(hSession, _("RPQ timezone exceeds 12 hour UTC offset")); return (labs(delta) > 720L)? 3 : (int) delta; diff --git a/src/core/windows/connect.c b/src/core/windows/connect.c index ec43c12..6c4aedb 100644 --- a/src/core/windows/connect.c +++ b/src/core/windows/connect.c @@ -18,7 +18,7 @@ * programa; se não, escreva para a Free Software Foundation, Inc., 51 Franklin * St, Fifth Floor, Boston, MA 02110-1301 USA * - * Este programa está nomeado como connect.c e possui - linhas de código. + * Este programa está nomeado como - e possui - linhas de código. * * Contatos: * @@ -29,284 +29,324 @@ #include -// Compiling for WinXP or later: Expose getaddrinfo()/freeaddrinfo(). -#undef _WIN32_WINNT -#define _WIN32_WINNT 0x0501 - #include #include #include #include -#include -#include #include -#include - -#ifdef HAVE_ICONV - #include -#endif // HAVE_ICONV +#include +#include "telnetc.h" #include "hostc.h" #include "trace_dsc.h" -#include "telnetc.h" #include "screen.h" -#include - /*---[ Implement ]-------------------------------------------------------------------------------*/ + static int sock_connect(H3270 *hSession, int sock, const struct sockaddr *address, socklen_t address_len) { -static void net_connected(H3270 *hSession, int GNUC_UNUSED(fd), LIB3270_IO_FLAG GNUC_UNUSED(flag), void GNUC_UNUSED(*dunno)) -{ - int err; - socklen_t len = sizeof(err); + lib3270_socket_set_non_blocking(hSession, sock, 1); - if(hSession->xio.write) { - trace("%s write=%p",__FUNCTION__,hSession->xio.write); - lib3270_remove_poll(hSession, hSession->xio.write); - hSession->xio.write = NULL; - } + WSASetLastError(0); - if(getsockopt(hSession->connection.sock, SOL_SOCKET, SO_ERROR, (char *) &err, &len) < 0) - { - lib3270_disconnect(hSession); - lib3270_popup_dialog( hSession, - LIB3270_NOTIFY_ERROR, - _( "Network error" ), - _( "Unable to get connection state." ), - "%s", lib3270_win32_strerror(WSAGetLastError()) - ); - return; - } - else if(err) - { - lib3270_autoptr(char) body = lib3270_strdup_printf(_("%s (rc=%d)"),strerror(err),err); + if(!connect(sock,address,address_len)) + return 0; - connection_failed(hSession,body); - return; - } + debug("WSAGetLastError=%d",(int) WSAGetLastError()); - hSession->xio.except = lib3270_add_poll_fd(hSession,hSession->connection.sock,LIB3270_IO_FLAG_EXCEPTION,net_exception,0); - hSession->xio.read = lib3270_add_poll_fd(hSession,hSession->connection.sock,LIB3270_IO_FLAG_READ,net_input,0); + unsigned int timer; + for(timer = 0; timer < hSession->connection.timeout; timer += 10) { + + if(lib3270_get_connection_state(hSession) != LIB3270_CONNECTING) + return errno = ECANCELED; + + struct timeval tm; + + tm.tv_sec = 0; + tm.tv_usec = 10; + + fd_set wfds; + FD_ZERO(&wfds); + FD_SET(sock, &wfds); + + int ns = select(sock+1, NULL, &wfds, NULL, &tm); + + if (ns < 0 && errno != EINTR) { + return errno; + } + + if(FD_ISSET(sock, &wfds)) + return 0; -#if defined(HAVE_LIBSSL) - if(hSession->ssl.con && hSession->ssl.state == LIB3270_SSL_UNDEFINED) - { - if(ssl_negotiate(hSession)) - return; } -#endif - lib3270_setup_session(hSession); - lib3270_set_connected_initial(hSession); + return errno = ETIMEDOUT; -} + } -static void sockstart(H3270 *session) -{ - static int initted = 0; - WORD wVersionRequested; - WSADATA wsaData; - if (initted) - return; + int lib3270_network_connect(H3270 *hSession, LIB3270_NETWORK_STATE *state) { - initted = 1; + // Do we need to start wsa? + static unsigned char wsa_is_started = 0; + if(!wsa_is_started) { - wVersionRequested = MAKEWORD(2, 2); + WORD wVersionRequested; + WSADATA wsaData; - if (WSAStartup(wVersionRequested, &wsaData) != 0) - { - lib3270_popup_dialog( session, - LIB3270_NOTIFY_CRITICAL, - _( "Network startup error" ), - _( "WSAStartup failed" ), - "%s", lib3270_win32_strerror(GetLastError()) ); + wVersionRequested = MAKEWORD(2, 2); - _exit(1); - } + if (WSAStartup(wVersionRequested, &wsaData) != 0) + { + static const LIB3270_POPUP popup = { + .type = LIB3270_NOTIFY_CRITICAL, + .summary = N_("WSAStartup failed") + }; - if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) - { - lib3270_popup_dialog( session, - LIB3270_NOTIFY_CRITICAL, - _( "Network startup error" ), - _( "Bad winsock version" ), - _( "Can't use winsock version %d.%d" ), LOBYTE(wsaData.wVersion), HIBYTE(wsaData.wVersion)); - _exit(1); + state->popup = &popup; + state->winerror = GetLastError(); + + return -1; + } + + if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) + { + static const LIB3270_POPUP popup = { + .type = LIB3270_NOTIFY_CRITICAL, + .summary = N_("Bad winsock version"), + .body = N_("Can't use this system winsock") + }; + + state->popup = &popup; + state->winerror = GetLastError(); + + return -1; + } + + wsa_is_started = 1; } -} - struct resolver - { - int rc; - int convert; - const char * message; - }; + // Reset state + set_ssl_state(hSession,LIB3270_SSL_UNDEFINED); - static int background_connect(H3270 *hSession, void *host) - { + // + // Resolve hostname + // struct addrinfo hints; struct addrinfo * result = NULL; - struct addrinfo * rp = NULL; - - if(!(hSession->host.current && hSession->host.srvc)) - return errno = ENOENT; - memset(&hints,0,sizeof(hints)); hints.ai_family = AF_UNSPEC; // Allow IPv4 or IPv6 hints.ai_socktype = SOCK_STREAM; // Stream socket hints.ai_flags = AI_PASSIVE; // For wildcard IP address hints.ai_protocol = 0; // Any protocol - debug("%s(%s,%s)",__FUNCTION__,hSession->host.current, hSession->host.srvc); - status_resolving(hSession); int rc = getaddrinfo(hSession->host.current, hSession->host.srvc, &hints, &result); - debug("getaddrinfo(%s,%s) returns %d",hSession->host.current,hSession->host.srvc,rc); - - if(rc != 0) + if(rc) { - ((struct resolver *) host)->rc = rc; - ((struct resolver *) host)->message = gai_strerror(rc); - ((struct resolver *) host)->convert = 1; + state->error_message = gai_strerror(rc); return -1; } + // + // Try connecting to hosts. + // + int sock = -1; + struct addrinfo * rp = NULL; + status_connecting(hSession); - for(rp = result; hSession->connection.sock < 0 && rp != NULL; rp = rp->ai_next) + for(rp = result; sock < 0 && rp != NULL && state->syserror != ECANCELED; rp = rp->ai_next) { - hSession->connection.sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); - - if(hSession->connection.sock < 0) + // Got socket from host definition. + sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); + if(sock < 0) { - ((struct resolver *) host)->rc = errno; - ((struct resolver *) host)->message = strerror(errno); - debug("Socket error %d: %s",((struct resolver *) host)->rc,((struct resolver *) host)->message); + // Can't get socket. + state->syserror = errno; continue; } - // Connected! - if(connect(hSession->connection.sock, rp->ai_addr, rp->ai_addrlen)) + // Try connect. + if(sock_connect(hSession, sock, rp->ai_addr, rp->ai_addrlen)) { - ((struct resolver *) host)->rc = errno; - ((struct resolver *) host)->message = strerror(errno); - debug("Connection error %d: %s",((struct resolver *) host)->rc,((struct resolver *) host)->message); - SOCK_CLOSE(hSession); + // Can't connect to host + state->syserror = errno; + closesocket(sock); + sock = -1; continue; } + lib3270_socket_set_non_blocking(hSession,sock,0); } freeaddrinfo(result); - debug("%s: Connected using socket %d",__FUNCTION__,hSession->connection.sock); + if(sock < 0) + { + static const LIB3270_POPUP popup = { + .name = "CantConnect", + .type = LIB3270_NOTIFY_ERROR, + .summary = N_("Can't connect to host"), + .label = N_("Try again") + }; + + state->popup = &popup; + return sock; + } - return 0; + return sock; + } -} + static void net_connected(H3270 *hSession, int GNUC_UNUSED(fd), LIB3270_IO_FLAG GNUC_UNUSED(flag), void GNUC_UNUSED(*dunno)) + { + int err; + socklen_t len = sizeof(err); -int net_reconnect(H3270 *hSession, int seconds) -{ - struct resolver host; + if(hSession->xio.write) { + trace("%s write=%p",__FUNCTION__,hSession->xio.write); + lib3270_remove_poll(hSession, hSession->xio.write); + hSession->xio.write = NULL; + } - memset(&host,0,sizeof(host)); + if(hSession->network.module->getsockopt(hSession, SOL_SOCKET, SO_ERROR, (char *) &err, &len) < 0) + { + lib3270_disconnect(hSession); + lib3270_popup_dialog( + hSession, + LIB3270_NOTIFY_ERROR, + _( "Network error" ), + _( "Unable to get connection state." ), + _( "The system error was %s" ), lib3270_win32_strerror(WSAGetLastError()) + ); + return; + } + else if(err) + { + lib3270_autoptr(LIB3270_POPUP) popup = + lib3270_popup_clone_printf( + NULL, + _( "Can't connect to %s:%s"), + hSession->host.current, + hSession->host.srvc + ); + + lib3270_autoptr(char) syserror = + lib3270_strdup_printf( + _("The system error was \"%s\""), + lib3270_win32_strerror(WSAGetLastError()) + ); + + if(lib3270_popup(hSession,popup,!hSession->auto_reconnect_inprogress) == 0) + lib3270_activate_auto_reconnect(hSession,1000); + + return; + } - sockstart(hSession); + if(lib3270_start_tls(hSession)) { + lib3270_disconnect(hSession); + return; + } - if(lib3270_run_task(hSession, background_connect, &host) || hSession->connection.sock < 0) + hSession->xio.except = hSession->network.module->add_poll(hSession,LIB3270_IO_FLAG_EXCEPTION,net_exception,0); + hSession->xio.read = hSession->network.module->add_poll(hSession,LIB3270_IO_FLAG_READ,net_input,0); + + lib3270_setup_session(hSession); + lib3270_set_connected_initial(hSession); + + lib3270_notify_tls(hSession); + + } + + int net_reconnect(H3270 *hSession, int seconds) + { + LIB3270_NETWORK_STATE state; + memset(&state,0,sizeof(state)); + + // Initialize and connect to host + set_ssl_state(hSession,LIB3270_SSL_UNDEFINED); + lib3270_set_cstate(hSession,LIB3270_CONNECTING); + + if(lib3270_run_task(hSession, (int(*)(H3270 *, void *)) hSession->network.module->connect, &state)) { - if(host.message) + lib3270_autoptr(LIB3270_POPUP) popup = + lib3270_popup_clone_printf( + NULL, + _( "Can't connect to %s:%s"), + hSession->host.current, + hSession->host.srvc + ); + + if(!popup->summary) { - // Have windows message, convert charset. - - char msg[4096]; - snprintf(msg,sizeof(msg),"%s (RC=%d)",host.message,host.rc); - - if(hEventLog) - { - // Register on event log - lib3270_autoptr(char) username = lib3270_get_user_name(); - - const char *outMsg[] = { - username, - "networking", - msg - }; - - ReportEvent( - hEventLog, - EVENTLOG_ERROR_TYPE, - 1, - 0, - NULL, - (sizeof(outMsg)/sizeof(outMsg[0])), - 0, - outMsg, - NULL - ); - - } - - -#ifdef HAVE_ICONV - if(host.convert) - { - char * ptr = msg; - size_t out = 4096; - size_t in = strlen(host.message); - - iconv_t hConv = iconv_open("UTF-8",lib3270_win32_local_charset()); - if(iconv( - hConv, - (ICONV_CONST char **) &host.message, - &in, - &ptr,&out - ) == ((size_t) -1)) - { - strncpy(msg,host.message,4095); - } - iconv_close(hConv); - - } -#endif // HAVE_ICONV - - connection_failed(hSession,msg); + popup->summary = popup->body; + popup->body = NULL; + } + lib3270_autoptr(char) syserror = NULL; + if(state.syserror) + { + syserror = lib3270_strdup_printf( + _("The system error was \"%s\" (rc=%d)"), + strerror(state.syserror), + state.syserror + ); } - else +#ifdef _WIN32 + else if(state.winerror) { - connection_failed(hSession,NULL); + syserror = lib3270_strdup_printf( + _("The system error was \"%s\""), + lib3270_win32_strerror(WSAGetLastError()) + ); } +#endif // _WIN32 + + if(!popup->body) + { + if(state.error_message) + popup->body = state.error_message; + else + popup->body = syserror; + } + + lib3270_disconnect(hSession); // To cleanup states. + + popup->label = _("_Retry"); + if(lib3270_popup(hSession,popup,!hSession->auto_reconnect_inprogress) == 0) + lib3270_activate_auto_reconnect(hSession,1000); - lib3270_set_disconnected(hSession); return errno = ENOTCONN; } + // + // Connected + // hSession->ever_3270 = False; -#if defined(HAVE_LIBSSL) - hSession->ssl.host = 0; - - if(hSession->ssl.enabled) + // set options for inline out-of-band data and keepalives + int optval = 1; + if(hSession->network.module->setsockopt(hSession, SOL_SOCKET, SO_OOBINLINE, &optval, sizeof(optval)) < 0) { - hSession->ssl.host = 1; - if(ssl_init(hSession)) - return errno = ENOTCONN; - + int rc = errno; + lib3270_popup_dialog( hSession, + LIB3270_NOTIFY_ERROR, + _( "Connection error" ), + _( "setsockopt(SO_OOBINLINE) has failed" ), + _( "The system error was %s" ), + lib3270_win32_strerror(WSAGetLastError()) + ); + hSession->network.module->disconnect(hSession); + return rc; } -#endif // HAVE_LIBSSL - /* connect */ - - WSASetLastError(0); - - int optval = lib3270_get_toggle(hSession,LIB3270_TOGGLE_KEEP_ALIVE) ? 1 : 0; - if (setsockopt(hSession->connection.sock, SOL_SOCKET, SO_KEEPALIVE, (char *)&optval, sizeof(optval)) < 0) + optval = lib3270_get_toggle(hSession,LIB3270_TOGGLE_KEEP_ALIVE) ? 1 : 0; + if (hSession->network.module->setsockopt(hSession, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval)) < 0) { + int rc = errno; + char buffer[4096]; snprintf(buffer,4095,_( "Can't %s network keep-alive" ), optval ? _( "enable" ) : _( "disable" )); @@ -314,32 +354,23 @@ int net_reconnect(H3270 *hSession, int seconds) LIB3270_NOTIFY_ERROR, _( "Connection error" ), buffer, - "%s", lib3270_win32_strerror(WSAGetLastError())); - SOCK_CLOSE(hSession); - return errno = ENOTCONN; + _( "The system error was %s" ), + lib3270_win32_strerror(WSAGetLastError()) + ); + + hSession->network.module->disconnect(hSession); + return rc; } else { trace_dsn(hSession,"Network keep-alive is %s\n",optval ? "enabled" : "disabled" ); } - optval = 1; - if (setsockopt(hSession->connection.sock, SOL_SOCKET, SO_OOBINLINE, (char *)&optval,sizeof(optval)) < 0) - { - lib3270_popup_dialog( hSession, - LIB3270_NOTIFY_ERROR, - _( "Connection error" ), - _( "setsockopt(SO_OOBINLINE) has failed" ), - "%s", lib3270_win32_strerror(WSAGetLastError())); - SOCK_CLOSE(hSession); - return errno = ENOTCONN; - } - // Connecting, set callbacks, wait for connection lib3270_set_cstate(hSession, LIB3270_PENDING); lib3270_st_changed(hSession, LIB3270_STATE_HALF_CONNECT, True); - hSession->xio.write = lib3270_add_poll_fd(hSession,hSession->connection.sock,LIB3270_IO_FLAG_WRITE,net_connected,0); + hSession->xio.write = hSession->network.module->add_poll(hSession,LIB3270_IO_FLAG_WRITE,net_connected,0); trace("%s: Connection in progress",__FUNCTION__); @@ -349,50 +380,11 @@ int net_reconnect(H3270 *hSession, int seconds) if(rc) { lib3270_disconnect(hSession); - lib3270_write_log(hSession,"connect", "%s: %s",__FUNCTION__,strerror(rc)); + lib3270_write_log(hSession,"connect", "%s: %s",__FUNCTION__,strerror(ETIMEDOUT)); return errno = rc; } - } - - /* - if(seconds) - { - time_t end = time(0)+seconds; - - while(time(0) < end) - { - lib3270_main_iterate(hSession,1); - - switch(hSession->connection.state) - { - case LIB3270_PENDING: - case LIB3270_CONNECTED_INITIAL: - case LIB3270_CONNECTED_ANSI: - case LIB3270_CONNECTED_3270: - case LIB3270_CONNECTED_INITIAL_E: - case LIB3270_CONNECTED_NVT: - case LIB3270_CONNECTED_SSCP: - case LIB3270_RESOLVING: - break; - - case LIB3270_NOT_CONNECTED: - return errno = ENOTCONN; - - case LIB3270_CONNECTED_TN3270E: - return 0; - - default: - lib3270_write_log(hSession,"connect", "%s: State changed to unexpected state %d",__FUNCTION__,hSession->connection.state); - return -1; - } - - } - lib3270_disconnect(hSession); - lib3270_write_log(hSession,"connect", "%s: %s",__FUNCTION__,strerror(ETIMEDOUT)); - return errno = ETIMEDOUT; } - */ return 0; diff --git a/src/include/networking.h b/src/include/networking.h index 1407838..afe99e3 100644 --- a/src/include/networking.h +++ b/src/include/networking.h @@ -31,8 +31,17 @@ #define LIB3270_NETWORKING_H_INCLUDED - #include +#ifdef _WIN32 + #include + #include + + typedef int socklen_t; + +#else #include +#endif // _WIN32 + + #include typedef struct _lib3270_network_popup LIB3270_NETWORK_POPUP; typedef struct _lib3270_net_context LIB3270_NET_CONTEXT; @@ -207,7 +216,7 @@ * @return Pointer to the hostname or NULL if failed (sets errno). * */ - LIB3270_INTERNAL char * lib3270_set_network_module_from_url(H3270 *hSession, const char *url); + LIB3270_INTERNAL char * lib3270_set_network_module_from_url(H3270 *hSession, char *url); /** diff --git a/src/network_modules/default/main.c b/src/network_modules/default/main.c index d82e869..44664f4 100644 --- a/src/network_modules/default/main.c +++ b/src/network_modules/default/main.c @@ -52,7 +52,7 @@ if(hSession->network.context->sock > 0) { shutdown(hSession->network.context->sock, 2); #ifdef _WIN32 - sockclose(hSession->network.context->sock); + closesocket(hSession->network.context->sock); #else close(hSession->network.context->sock); #endif // _WIN32 diff --git a/src/network_modules/openssl/main.c b/src/network_modules/openssl/main.c index 7e2c919..b352426 100644 --- a/src/network_modules/openssl/main.c +++ b/src/network_modules/openssl/main.c @@ -68,7 +68,7 @@ static int openssl_network_disconnect(H3270 *hSession) { if(context->sock > 0) { shutdown(context->sock, 2); #ifdef _WIN32 - sockclose(context->sock); + closesocket(context->sock); #else close(context->sock); #endif // _WIN32 diff --git a/src/network_modules/openssl/private.h b/src/network_modules/openssl/private.h index a12fda2..b6ce2b0 100644 --- a/src/network_modules/openssl/private.h +++ b/src/network_modules/openssl/private.h @@ -34,7 +34,7 @@ #include #ifdef _WIN32 - #include + #include #include #else #include diff --git a/src/network_modules/openssl/start.c b/src/network_modules/openssl/start.c index 62906c2..672ea2d 100644 --- a/src/network_modules/openssl/start.c +++ b/src/network_modules/openssl/start.c @@ -49,7 +49,7 @@ #else - *error_message = _("No LDAP support"); + error_message = _("No LDAP support"); #endif // HAVE_LDAP diff --git a/src/network_modules/select.c b/src/network_modules/select.c index 539a3af..ad60799 100644 --- a/src/network_modules/select.c +++ b/src/network_modules/select.c @@ -41,7 +41,7 @@ /*--[ Implement ]------------------------------------------------------------------------------------*/ - char * lib3270_set_network_module_from_url(H3270 *hSession, const char *url) { +char * lib3270_set_network_module_from_url(H3270 *hSession, char *url) { static const struct { const char *scheme; ///< @brief URL scheme for module. diff --git a/src/network_modules/tools.c b/src/network_modules/tools.c index 21f6a51..1a11ddd 100644 --- a/src/network_modules/tools.c +++ b/src/network_modules/tools.c @@ -60,7 +60,7 @@ .name = "RecvFailed", .type = LIB3270_NOTIFY_ERROR, .summary = _("Error receiving data from host"), - } + }; // TODO: Translate WSA Error, update message body. @@ -102,7 +102,15 @@ int rc = WSAGetLastError(); - #error Have work to do. + lib3270_popup_dialog( + hSession, + LIB3270_NOTIFY_ERROR, + NULL, + _("Erro sending data to host"), + _( "The system error was %s (%d)" ), + lib3270_win32_strerror(rc), + rc + ); #else -- libgit2 0.21.2