diff --git a/lib3270.cbp b/lib3270.cbp index a0435ec..50ee724 100644 --- a/lib3270.cbp +++ b/lib3270.cbp @@ -157,6 +157,9 @@ + + @@ -245,6 +248,9 @@ + + diff --git a/src/lib3270/connect.c b/src/lib3270/connect.c deleted file mode 100644 index c76fef4..0000000 --- a/src/lib3270/connect.c +++ /dev/null @@ -1,560 +0,0 @@ -/* - * "Software pw3270, desenvolvido com base nos códigos fontes do WC3270 e X3270 - * (Paul Mattes Paul.Mattes@usa.net), de emulação de terminal 3270 para acesso a - * aplicativos mainframe. Registro no INPI sob o nome G3270. - * - * Copyright (C) <2008> - * - * Este programa é software livre. Você pode redistribuí-lo e/ou modificá-lo sob - * os termos da GPL v.2 - Licença Pública Geral GNU, conforme publicado pela - * Free Software Foundation. - * - * Este programa é distribuído na expectativa de ser útil, mas SEM QUALQUER - * GARANTIA; sem mesmo a garantia implícita de COMERCIALIZAÇÃO ou de ADEQUAÇÃO - * A QUALQUER PROPÓSITO EM PARTICULAR. Consulte a Licença Pública Geral GNU para - * obter mais detalhes. - * - * Você deve ter recebido uma cópia da Licença Pública Geral GNU junto com este - * 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. - * - * Contatos: - * - * perry.werneck@gmail.com (Alexandre Perry de Souza Werneck) - * erico.mendonca@gmail.com (Erico Mascarenhas Mendonça) - * - */ - -#include - -#if defined(_WIN32) - - // Compiling for WinXP or later: Expose getaddrinfo()/freeaddrinfo(). - #undef _WIN32_WINNT - #define _WIN32_WINNT 0x0501 - - #include - #include - #include - -#endif - -#include "private.h" -#include - -#if defined(_WIN32) - #include -#else - #include - #include - #include - #include - #include - #include - #include -#endif - -#ifdef HAVE_ICONV - #include -#endif // HAVE_ICONV - -#if defined(_WIN32) /*[*/ - #define SOCK_CLOSE(s) closesocket(s->sock); s->sock = -1; -#else /*][*/ - #define SOCK_CLOSE(s) close(s->sock); s->sock = -1; -#endif /*]*/ - -#include -#include "statusc.h" -#include "hostc.h" -#include "trace_dsc.h" -#include "utilc.h" -#include "telnetc.h" -#include "screen.h" -#include - -/*---[ Implement ]-------------------------------------------------------------------------------*/ - - -//static void net_connected(H3270 *hSession) -static void net_connected(H3270 *hSession, int fd unused, LIB3270_IO_FLAG flag unused, void *dunno unused) -{ - int err; - socklen_t len = sizeof(err); - - if(hSession->xio.write) { - trace("%s write=%p",__FUNCTION__,hSession->xio.write); - lib3270_remove_poll(hSession, hSession->xio.write); - hSession->xio.write = NULL; - } - - if(getsockopt(hSession->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." ), -#ifdef _WIN32 - "%s", lib3270_win32_strerror(WSAGetLastError()) -#else - _( "%s" ), strerror(errno) -#endif // _WIN32 - ); - return; - } - else if(err) - { - char buffer[4096]; - snprintf(buffer,4095,_( "Can't connect to %s" ), hSession->host.current ); - - lib3270_disconnect(hSession); - lib3270_popup_dialog( hSession, - LIB3270_NOTIFY_ERROR, - _( "Connection failed" ), - buffer, -#ifdef _WIN32 - _( "%s"), lib3270_win32_strerror(err) -#else - _( "%s" ), strerror(err) -#endif // _WIN32 - ); - trace("%s",__FUNCTION__); - return; - } - - hSession->xio.except = lib3270_add_poll_fd(hSession,hSession->sock,LIB3270_IO_FLAG_EXCEPTION,net_exception,0); - hSession->xio.read = lib3270_add_poll_fd(hSession,hSession->sock,LIB3270_IO_FLAG_READ,net_input,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); - -} - - -#if defined(_WIN32) - - static void sockstart(H3270 *session) - { - static int initted = 0; - WORD wVersionRequested; - WSADATA wsaData; - - if (initted) - return; - - initted = 1; - - wVersionRequested = MAKEWORD(2, 2); - - if (WSAStartup(wVersionRequested, &wsaData) != 0) - { - lib3270_popup_dialog( session, - LIB3270_NOTIFY_CRITICAL, - N_( "Network startup error" ), - N_( "WSAStartup failed" ), - "%s", lib3270_win32_strerror(GetLastError()) ); - - _exit(1); - } - - if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) - { - lib3270_popup_dialog( session, - LIB3270_NOTIFY_CRITICAL, - N_( "Network startup error" ), - N_( "Bad winsock version" ), - N_( "Can't use winsock version %d.%d" ), LOBYTE(wsaData.wVersion), HIBYTE(wsaData.wVersion)); - _exit(1); - } - } -#endif // WIN32 - - LIB3270_EXPORT int lib3270_connect_url(H3270 *hSession, const char *url, int wait) - { - CHECK_SESSION_HANDLE(hSession); - - if(url && *url) - { - lib3270_set_url(hSession,url); - } - - return lib3270_connect(hSession, wait); - - } - - LIB3270_EXPORT int lib3270_connect_host(H3270 *hSession, const char *hostname, const char *srvc, LIB3270_OPTION opt) - { - CHECK_SESSION_HANDLE(hSession); - - if(!hostname) - return EINVAL; - - if(!srvc) - srvc = "telnet"; - - if(*hostname == '$') - { - const char *name = getenv(hostname+1); - if(!name) - { - lib3270_popup_dialog( hSession, - LIB3270_NOTIFY_ERROR, - _( "Connection error" ), - _( "Unable to find selected hostname." ), - _( "Can't determine value for environment variable \"%s\" " ), - hostname); - lib3270_set_disconnected(hSession); - return ENOENT; - } - hostname = name; - } - - hSession->options = opt & ~LIB3270_OPTION_WAIT; - Replace(hSession->host.current,strdup(hostname)); - Replace(hSession->host.srvc,strdup(srvc)); - - Replace(hSession->host.full, - lib3270_strdup_printf( - "%s%s:%s", - opt&LIB3270_OPTION_SSL ? "tn3270s://" : "tn3270://", - hostname, - srvc )); - - trace("current_host=\"%s\"",hSession->host.current); - - return lib3270_connect(hSession,opt & LIB3270_OPTION_WAIT); - - } - - int lib3270_connect(H3270 *hSession, int seconds) - { - int s; - int optval; - struct addrinfo hints; - struct addrinfo * result = NULL; - struct addrinfo * rp = NULL; - - CHECK_SESSION_HANDLE(hSession); - - lib3270_main_iterate(hSession,0); - - if(hSession->auto_reconnect_inprogress) - return errno = EAGAIN; - - if(hSession->sock > 0) - return errno = EBUSY; - -#if defined(_WIN32) - sockstart(hSession); -#endif - -#if defined(HAVE_LIBSSL) - set_ssl_state(hSession,LIB3270_SSL_UNSECURE); -#endif // HAVE_LIBSSL - - snprintf(hSession->full_model_name,LIB3270_FULL_MODEL_NAME_LENGTH,"IBM-327%c-%d",hSession->m3279 ? '9' : '8', hSession->model_num); - - hSession->ever_3270 = False; - - memset(&hints, 0, sizeof(struct addrinfo)); - 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 */ - hints.ai_canonname = NULL; - hints.ai_addr = NULL; - hints.ai_next = NULL; - - hSession->cstate = LIB3270_RESOLVING; - lib3270_st_changed(hSession, LIB3270_STATE_RESOLVING, True); - - s = getaddrinfo(hSession->host.current, hSession->host.srvc, &hints, &result); - - if(s != 0) - { - char buffer[4096]; - - snprintf(buffer,4095,_( "Can't connect to %s:%s"), hSession->host.current, hSession->host.srvc); - -#if defined(WIN32) && defined(HAVE_ICONV) - { - char tmpbuffer[4096]; - const char * msg = gai_strerror(s); - size_t in = strlen(msg); - size_t out = 4096; - char * ptr = tmpbuffer; - - iconv_t hConv = iconv_open(lib3270_win32_local_charset(),"UTF-8"); - - trace("Antes: [%s]",msg); - if(iconv(hConv,&msg,&in,&ptr,&out) != ((size_t) -1)) - msg = tmpbuffer; - trace("Depois: [%s]",msg); - - iconv_close(hConv); - - lib3270_popup_dialog( hSession, - LIB3270_NOTIFY_ERROR, - _( "Connection error" ), - buffer, - "%s", - msg); - } - -#else - lib3270_popup_dialog( hSession, - LIB3270_NOTIFY_ERROR, - _( "Connection error" ), - buffer, - "%s", - gai_strerror(s)); -#endif // WIN32 - - - lib3270_set_disconnected(hSession); - return errno = ENOENT; - } - - -#if !defined(_WIN32) - /* don't share the socket with our children */ - (void) fcntl(hSession->sock, F_SETFD, 1); -#endif - - hSession->ever_3270 = False; - hSession->ssl.host = 0; - - if(hSession->options&LIB3270_OPTION_SSL) - { -#if defined(HAVE_LIBSSL) - hSession->ssl.host = 1; - ssl_init(hSession); -#else - lib3270_popup_dialog( hSession, - LIB3270_NOTIFY_ERROR, - _( "SSL error" ), - _( "Unable to connect to secure hosts" ), - _( "This version of %s was built without support for secure sockets layer (SSL)." ), - PACKAGE_NAME); - - return errno = EINVAL; -#endif // HAVE_LIBSSL - } - - /* connect */ - status_connecting(hSession,1); - - for(rp = result; hSession->sock < 0 && rp != NULL; rp = rp->ai_next) - { - hSession->sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); - if(hSession->sock < 0) - continue; - - trace("sock=%d",hSession->sock); - -#ifdef WIN32 - - WSASetLastError(0); - u_long iMode=1; - trace("sock=%d",hSession->sock); - - optval = lib3270_get_toggle(hSession,LIB3270_TOGGLE_KEEP_ALIVE) ? 1 : 0; - if (setsockopt(hSession->sock, SOL_SOCKET, SO_KEEPALIVE, (char *)&optval, sizeof(optval)) < 0) - { - char buffer[4096]; - snprintf(buffer,4095,N_( "Can't %s network keep-alive" ), optval ? _( "enable" ) : _( "disable" )); - - lib3270_popup_dialog( hSession, - LIB3270_NOTIFY_ERROR, - _( "Connection error" ), - buffer, - "%s", lib3270_win32_strerror(WSAGetLastError())); - SOCK_CLOSE(hSession); - continue; - } - else - { - trace_dsn(hSession,"Network keep-alive is %s\n",optval ? "enabled" : "disabled" ); - } - - if(ioctlsocket(hSession->sock,FIONBIO,&iMode)) - { - lib3270_popup_dialog( hSession, - LIB3270_NOTIFY_ERROR, - _( "Connection error" ), - _( "ioctlsocket(FIONBIO) failed." ), - "%s", lib3270_win32_strerror(WSAGetLastError())); - SOCK_CLOSE(hSession); - continue; - } - else if(connect(hSession->sock, rp->ai_addr, rp->ai_addrlen)) - { - int err = WSAGetLastError(); - if(err != WSAEWOULDBLOCK) - { - char buffer[4096]; - snprintf(buffer,4095,_( "Can't connect to %s"), lib3270_get_host(hSession)); - - lib3270_popup_dialog( hSession, - LIB3270_NOTIFY_ERROR, - _( "Connection error" ), - buffer, - "%s", lib3270_win32_strerror(err)); - SOCK_CLOSE(hSession); - continue; - - } - } - - optval = 1; - if (setsockopt(hSession->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); - continue; - } - -#else - fcntl(hSession->sock, F_SETFL,fcntl(hSession->sock,F_GETFL,0)|O_NONBLOCK); - - errno = 0; - if(connect(hSession->sock, rp->ai_addr, rp->ai_addrlen)) - { - if( errno != EINPROGRESS ) - { - char buffer[4096]; - snprintf(buffer,4095,_( "Can't connect to %s:%s"), hSession->host.current, hSession->host.srvc); - - lib3270_popup_dialog( hSession, - LIB3270_NOTIFY_ERROR, - _( "Connection error" ), - buffer, - "%s", - strerror(errno)); - SOCK_CLOSE(hSession); - continue; - } - } - - optval = 1; - if (setsockopt(hSession->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", - strerror(errno)); - SOCK_CLOSE(hSession); - continue; - } - - optval = lib3270_get_toggle(hSession,LIB3270_TOGGLE_KEEP_ALIVE) ? 1 : 0; - if (setsockopt(hSession->sock, SOL_SOCKET, SO_KEEPALIVE, (char *)&optval, sizeof(optval)) < 0) - { - char buffer[4096]; - snprintf(buffer,4095,N_( "Can't %s network keep-alive" ), optval ? _( "enable" ) : _( "disable" )); - - lib3270_popup_dialog( hSession, - LIB3270_NOTIFY_ERROR, - _( "Connection error" ), - buffer, - "%s", - strerror(errno)); - SOCK_CLOSE(hSession); - continue; - } - else - { - trace_dsn(hSession,"Network keep-alive is %s\n",optval ? "enabled" : "disabled" ); - } - -#endif // WIN32 - } - - freeaddrinfo(result); - - // set options for inline out-of-band data and keepalives - - /* -#if defined(OMTU) - else if (setsockopt(hSession->sock, SOL_SOCKET, SO_SNDBUF, (char *)&mtu,sizeof(mtu)) < 0) - { - popup_a_sockerr(hSession, N_( "setsockopt(%s)" ), "SO_SNDBUF"); - SOCK_CLOSE(hSession); - } -#endif - - */ - - if(hSession->sock < 0) - { - lib3270_set_disconnected(hSession); - return errno = ENOTCONN; - } - - // Connecting, set callbacks, wait for connection - hSession->cstate = LIB3270_PENDING; - lib3270_st_changed(hSession, LIB3270_STATE_HALF_CONNECT, True); - - hSession->xio.write = lib3270_add_poll_fd(hSession,hSession->sock,LIB3270_IO_FLAG_WRITE,net_connected,0); - // hSession->ns_write_id = AddOutput(hSession->sock, hSession, net_connected); - - trace("%s: Connection in progress",__FUNCTION__); - - if(seconds) - { - time_t end = time(0)+seconds; - - while(time(0) < end) - { - lib3270_main_iterate(hSession,1); - - switch(hSession->cstate) - { - 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: - 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->cstate); - return -1; - } - - } - - lib3270_disconnect(hSession); - lib3270_write_log(hSession,"connect", "%s: %s",__FUNCTION__,strerror(ETIMEDOUT)); - return errno = ETIMEDOUT; - } - - return 0; - - } - diff --git a/src/lib3270/linux/connect.c b/src/lib3270/linux/connect.c new file mode 100644 index 0000000..ce5beb5 --- /dev/null +++ b/src/lib3270/linux/connect.c @@ -0,0 +1,407 @@ +/* + * "Software pw3270, desenvolvido com base nos códigos fontes do WC3270 e X3270 + * (Paul Mattes Paul.Mattes@usa.net), de emulação de terminal 3270 para acesso a + * aplicativos mainframe. Registro no INPI sob o nome G3270. + * + * Copyright (C) <2008> + * + * Este programa é software livre. Você pode redistribuí-lo e/ou modificá-lo sob + * os termos da GPL v.2 - Licença Pública Geral GNU, conforme publicado pela + * Free Software Foundation. + * + * Este programa é distribuído na expectativa de ser útil, mas SEM QUALQUER + * GARANTIA; sem mesmo a garantia implícita de COMERCIALIZAÇÃO ou de ADEQUAÇÃO + * A QUALQUER PROPÓSITO EM PARTICULAR. Consulte a Licença Pública Geral GNU para + * obter mais detalhes. + * + * Você deve ter recebido uma cópia da Licença Pública Geral GNU junto com este + * 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 - e possui - linhas de código. + * + * Contatos: + * + * perry.werneck@gmail.com (Alexandre Perry de Souza Werneck) + * erico.mendonca@gmail.com (Erico Mascarenhas Mendonça) + * + */ + +#include +#include "../private.h" +#include + +#include +#include +#include +#include +#include +#include +#include + +// #ifdef HAVE_ICONV +// #include +// #endif // HAVE_ICONV + +#define SOCK_CLOSE(s) close(s->sock); s->sock = -1; + +#include + +//#include "statusc.h" +#include "hostc.h" +#include "trace_dsc.h" +//#include "utilc.h" +#include "telnetc.h" +#include "screen.h" + +#include + +/*---[ Implement ]-------------------------------------------------------------------------------*/ + + +//static void net_connected(H3270 *hSession) +static void net_connected(H3270 *hSession, int fd unused, LIB3270_IO_FLAG flag unused, void *dunno unused) +{ + int err; + socklen_t len = sizeof(err); + + if(hSession->xio.write) { + trace("%s write=%p",__FUNCTION__,hSession->xio.write); + lib3270_remove_poll(hSession, hSession->xio.write); + hSession->xio.write = NULL; + } + + if(getsockopt(hSession->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" ), strerror(errno) + ); + return; + } + else if(err) + { + char buffer[4096]; + snprintf(buffer,4095,_( "Can't connect to %s" ), hSession->host.current ); + + lib3270_disconnect(hSession); + lib3270_popup_dialog( + hSession, + LIB3270_NOTIFY_ERROR, + _( "Connection failed" ), + buffer, + _( "%s" ), strerror(err) + ); + return; + } + + hSession->xio.except = lib3270_add_poll_fd(hSession,hSession->sock,LIB3270_IO_FLAG_EXCEPTION,net_exception,0); + hSession->xio.read = lib3270_add_poll_fd(hSession,hSession->sock,LIB3270_IO_FLAG_READ,net_input,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); + +} + + LIB3270_EXPORT int lib3270_connect_url(H3270 *hSession, const char *url, int wait) + { + CHECK_SESSION_HANDLE(hSession); + + if(url && *url) + { + lib3270_set_url(hSession,url); + } + + return lib3270_connect(hSession, wait); + + } + + LIB3270_EXPORT int lib3270_connect_host(H3270 *hSession, const char *hostname, const char *srvc, LIB3270_OPTION opt) + { + CHECK_SESSION_HANDLE(hSession); + + if(!hostname) + return EINVAL; + + if(!srvc) + srvc = "telnet"; + + if(*hostname == '$') + { + const char *name = getenv(hostname+1); + if(!name) + { + lib3270_popup_dialog( hSession, + LIB3270_NOTIFY_ERROR, + _( "Connection error" ), + _( "Unable to find selected hostname." ), + _( "Can't determine value for environment variable \"%s\" " ), + hostname); + lib3270_set_disconnected(hSession); + return ENOENT; + } + hostname = name; + } + + hSession->options = opt & ~LIB3270_OPTION_WAIT; + Replace(hSession->host.current,strdup(hostname)); + Replace(hSession->host.srvc,strdup(srvc)); + + Replace(hSession->host.full, + lib3270_strdup_printf( + "%s%s:%s", + opt&LIB3270_OPTION_SSL ? "tn3270s://" : "tn3270://", + hostname, + srvc )); + + trace("current_host=\"%s\"",hSession->host.current); + + return lib3270_connect(hSession,opt & LIB3270_OPTION_WAIT); + + } + + struct resolver + { + const char * message; + }; + + static int background_connect(H3270 *hSession, void *host) + { + struct addrinfo hints; + struct addrinfo * result = NULL; + struct addrinfo * rp = NULL; + + 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 + + int rc = getaddrinfo(hSession->host.current, hSession->host.srvc, &hints, &result); + if(rc != 0) + { + ((struct resolver *) host)->message = gai_strerror(rc); + return -1; + } + + status_connecting(hSession,1); + + for(rp = result; hSession->sock < 0 && rp != NULL; rp = rp->ai_next) + { + hSession->sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); + if(hSession->sock < 0) + { + ((struct resolver *) host)->message = strerror(errno); + continue; + } + + // Connected! + if(connect(hSession->sock, rp->ai_addr, rp->ai_addrlen)) + { + SOCK_CLOSE(hSession); + ((struct resolver *) host)->message = strerror(errno); + continue; + } + + } + + freeaddrinfo(result); + + return 0; + + } + + int lib3270_connect(H3270 *hSession, int seconds) + { + int optval; + struct resolver host; + + CHECK_SESSION_HANDLE(hSession); + + memset(&host,0,sizeof(host)); + + lib3270_main_iterate(hSession,0); + + if(hSession->auto_reconnect_inprogress) + return errno = EAGAIN; + + if(hSession->sock > 0) + return errno = EBUSY; + +#if defined(HAVE_LIBSSL) + set_ssl_state(hSession,LIB3270_SSL_UNSECURE); +#endif // HAVE_LIBSSL + + snprintf(hSession->full_model_name,LIB3270_FULL_MODEL_NAME_LENGTH,"IBM-327%c-%d",hSession->m3279 ? '9' : '8', hSession->model_num); + + hSession->ever_3270 = False; + hSession->cstate = LIB3270_RESOLVING; + + lib3270_st_changed(hSession, LIB3270_STATE_RESOLVING, True); + + // s = getaddrinfo(hSession->host.current, hSession->host.srvc, &hints, &result); + if(lib3270_run_task(hSession, background_connect, &host)) + { + char buffer[4096]; + snprintf(buffer,4095,_( "Can't connect to %s:%s"), hSession->host.current, hSession->host.srvc); + + lib3270_popup_dialog( hSession, + LIB3270_NOTIFY_ERROR, + _( "Connection error" ), + buffer, + "%s", + host.message); + + lib3270_set_disconnected(hSession); + return errno = ENOENT; + } + + /* don't share the socket with our children */ + (void) fcntl(hSession->sock, F_SETFD, 1); + + hSession->ever_3270 = False; + hSession->ssl.host = 0; + + if(hSession->options&LIB3270_OPTION_SSL) + { +#if defined(HAVE_LIBSSL) + hSession->ssl.host = 1; + ssl_init(hSession); +#else + lib3270_popup_dialog( hSession, + LIB3270_NOTIFY_ERROR, + _( "SSL error" ), + _( "Unable to connect to secure hosts" ), + _( "This version of %s was built without support for secure sockets layer (SSL)." ), + PACKAGE_NAME); + + return errno = EINVAL; +#endif // HAVE_LIBSSL + } + + /* connect */ + if(hSession->sock < 0) + { + lib3270_set_disconnected(hSession); + + char buffer[4096]; + snprintf(buffer,4095,_( "Can't connect to %s:%s"), hSession->host.current, hSession->host.srvc); + + lib3270_popup_dialog( + hSession, + LIB3270_NOTIFY_ERROR, + _( "Connection error" ), + buffer, + "%s", + host.message + ); + + return errno = ENOTCONN; + } + + // set options for inline out-of-band data and keepalives + optval = 1; + if (setsockopt(hSession->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", + strerror(errno)); + SOCK_CLOSE(hSession); + } + + optval = lib3270_get_toggle(hSession,LIB3270_TOGGLE_KEEP_ALIVE) ? 1 : 0; + if (setsockopt(hSession->sock, SOL_SOCKET, SO_KEEPALIVE, (char *)&optval, sizeof(optval)) < 0) + { + char buffer[4096]; + snprintf(buffer,4095,N_( "Can't %s network keep-alive" ), optval ? _( "enable" ) : _( "disable" )); + + lib3270_popup_dialog( hSession, + LIB3270_NOTIFY_ERROR, + _( "Connection error" ), + buffer, + "%s", + strerror(errno)); + SOCK_CLOSE(hSession); + } + else + { + trace_dsn(hSession,"Network keep-alive is %s\n",optval ? "enabled" : "disabled" ); + } + + + /* +#if defined(OMTU) + else if (setsockopt(hSession->sock, SOL_SOCKET, SO_SNDBUF, (char *)&mtu,sizeof(mtu)) < 0) + { + popup_a_sockerr(hSession, N_( "setsockopt(%s)" ), "SO_SNDBUF"); + SOCK_CLOSE(hSession); + } +#endif + + */ + + // Connecting, set callbacks, wait for connection + hSession->cstate = LIB3270_PENDING; + lib3270_st_changed(hSession, LIB3270_STATE_HALF_CONNECT, True); + + hSession->xio.write = lib3270_add_poll_fd(hSession,hSession->sock,LIB3270_IO_FLAG_WRITE,net_connected,0); + // hSession->ns_write_id = AddOutput(hSession->sock, hSession, net_connected); + + trace("%s: Connection in progress",__FUNCTION__); + + if(seconds) + { + time_t end = time(0)+seconds; + + while(time(0) < end) + { + lib3270_main_iterate(hSession,1); + + switch(hSession->cstate) + { + 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: + 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->cstate); + return -1; + } + + } + + lib3270_disconnect(hSession); + lib3270_write_log(hSession,"connect", "%s: %s",__FUNCTION__,strerror(ETIMEDOUT)); + return errno = ETIMEDOUT; + } + + return 0; + + } + diff --git a/src/lib3270/windows/connect.c b/src/lib3270/windows/connect.c new file mode 100644 index 0000000..c76fef4 --- /dev/null +++ b/src/lib3270/windows/connect.c @@ -0,0 +1,560 @@ +/* + * "Software pw3270, desenvolvido com base nos códigos fontes do WC3270 e X3270 + * (Paul Mattes Paul.Mattes@usa.net), de emulação de terminal 3270 para acesso a + * aplicativos mainframe. Registro no INPI sob o nome G3270. + * + * Copyright (C) <2008> + * + * Este programa é software livre. Você pode redistribuí-lo e/ou modificá-lo sob + * os termos da GPL v.2 - Licença Pública Geral GNU, conforme publicado pela + * Free Software Foundation. + * + * Este programa é distribuído na expectativa de ser útil, mas SEM QUALQUER + * GARANTIA; sem mesmo a garantia implícita de COMERCIALIZAÇÃO ou de ADEQUAÇÃO + * A QUALQUER PROPÓSITO EM PARTICULAR. Consulte a Licença Pública Geral GNU para + * obter mais detalhes. + * + * Você deve ter recebido uma cópia da Licença Pública Geral GNU junto com este + * 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. + * + * Contatos: + * + * perry.werneck@gmail.com (Alexandre Perry de Souza Werneck) + * erico.mendonca@gmail.com (Erico Mascarenhas Mendonça) + * + */ + +#include + +#if defined(_WIN32) + + // Compiling for WinXP or later: Expose getaddrinfo()/freeaddrinfo(). + #undef _WIN32_WINNT + #define _WIN32_WINNT 0x0501 + + #include + #include + #include + +#endif + +#include "private.h" +#include + +#if defined(_WIN32) + #include +#else + #include + #include + #include + #include + #include + #include + #include +#endif + +#ifdef HAVE_ICONV + #include +#endif // HAVE_ICONV + +#if defined(_WIN32) /*[*/ + #define SOCK_CLOSE(s) closesocket(s->sock); s->sock = -1; +#else /*][*/ + #define SOCK_CLOSE(s) close(s->sock); s->sock = -1; +#endif /*]*/ + +#include +#include "statusc.h" +#include "hostc.h" +#include "trace_dsc.h" +#include "utilc.h" +#include "telnetc.h" +#include "screen.h" +#include + +/*---[ Implement ]-------------------------------------------------------------------------------*/ + + +//static void net_connected(H3270 *hSession) +static void net_connected(H3270 *hSession, int fd unused, LIB3270_IO_FLAG flag unused, void *dunno unused) +{ + int err; + socklen_t len = sizeof(err); + + if(hSession->xio.write) { + trace("%s write=%p",__FUNCTION__,hSession->xio.write); + lib3270_remove_poll(hSession, hSession->xio.write); + hSession->xio.write = NULL; + } + + if(getsockopt(hSession->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." ), +#ifdef _WIN32 + "%s", lib3270_win32_strerror(WSAGetLastError()) +#else + _( "%s" ), strerror(errno) +#endif // _WIN32 + ); + return; + } + else if(err) + { + char buffer[4096]; + snprintf(buffer,4095,_( "Can't connect to %s" ), hSession->host.current ); + + lib3270_disconnect(hSession); + lib3270_popup_dialog( hSession, + LIB3270_NOTIFY_ERROR, + _( "Connection failed" ), + buffer, +#ifdef _WIN32 + _( "%s"), lib3270_win32_strerror(err) +#else + _( "%s" ), strerror(err) +#endif // _WIN32 + ); + trace("%s",__FUNCTION__); + return; + } + + hSession->xio.except = lib3270_add_poll_fd(hSession,hSession->sock,LIB3270_IO_FLAG_EXCEPTION,net_exception,0); + hSession->xio.read = lib3270_add_poll_fd(hSession,hSession->sock,LIB3270_IO_FLAG_READ,net_input,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); + +} + + +#if defined(_WIN32) + + static void sockstart(H3270 *session) + { + static int initted = 0; + WORD wVersionRequested; + WSADATA wsaData; + + if (initted) + return; + + initted = 1; + + wVersionRequested = MAKEWORD(2, 2); + + if (WSAStartup(wVersionRequested, &wsaData) != 0) + { + lib3270_popup_dialog( session, + LIB3270_NOTIFY_CRITICAL, + N_( "Network startup error" ), + N_( "WSAStartup failed" ), + "%s", lib3270_win32_strerror(GetLastError()) ); + + _exit(1); + } + + if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) + { + lib3270_popup_dialog( session, + LIB3270_NOTIFY_CRITICAL, + N_( "Network startup error" ), + N_( "Bad winsock version" ), + N_( "Can't use winsock version %d.%d" ), LOBYTE(wsaData.wVersion), HIBYTE(wsaData.wVersion)); + _exit(1); + } + } +#endif // WIN32 + + LIB3270_EXPORT int lib3270_connect_url(H3270 *hSession, const char *url, int wait) + { + CHECK_SESSION_HANDLE(hSession); + + if(url && *url) + { + lib3270_set_url(hSession,url); + } + + return lib3270_connect(hSession, wait); + + } + + LIB3270_EXPORT int lib3270_connect_host(H3270 *hSession, const char *hostname, const char *srvc, LIB3270_OPTION opt) + { + CHECK_SESSION_HANDLE(hSession); + + if(!hostname) + return EINVAL; + + if(!srvc) + srvc = "telnet"; + + if(*hostname == '$') + { + const char *name = getenv(hostname+1); + if(!name) + { + lib3270_popup_dialog( hSession, + LIB3270_NOTIFY_ERROR, + _( "Connection error" ), + _( "Unable to find selected hostname." ), + _( "Can't determine value for environment variable \"%s\" " ), + hostname); + lib3270_set_disconnected(hSession); + return ENOENT; + } + hostname = name; + } + + hSession->options = opt & ~LIB3270_OPTION_WAIT; + Replace(hSession->host.current,strdup(hostname)); + Replace(hSession->host.srvc,strdup(srvc)); + + Replace(hSession->host.full, + lib3270_strdup_printf( + "%s%s:%s", + opt&LIB3270_OPTION_SSL ? "tn3270s://" : "tn3270://", + hostname, + srvc )); + + trace("current_host=\"%s\"",hSession->host.current); + + return lib3270_connect(hSession,opt & LIB3270_OPTION_WAIT); + + } + + int lib3270_connect(H3270 *hSession, int seconds) + { + int s; + int optval; + struct addrinfo hints; + struct addrinfo * result = NULL; + struct addrinfo * rp = NULL; + + CHECK_SESSION_HANDLE(hSession); + + lib3270_main_iterate(hSession,0); + + if(hSession->auto_reconnect_inprogress) + return errno = EAGAIN; + + if(hSession->sock > 0) + return errno = EBUSY; + +#if defined(_WIN32) + sockstart(hSession); +#endif + +#if defined(HAVE_LIBSSL) + set_ssl_state(hSession,LIB3270_SSL_UNSECURE); +#endif // HAVE_LIBSSL + + snprintf(hSession->full_model_name,LIB3270_FULL_MODEL_NAME_LENGTH,"IBM-327%c-%d",hSession->m3279 ? '9' : '8', hSession->model_num); + + hSession->ever_3270 = False; + + memset(&hints, 0, sizeof(struct addrinfo)); + 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 */ + hints.ai_canonname = NULL; + hints.ai_addr = NULL; + hints.ai_next = NULL; + + hSession->cstate = LIB3270_RESOLVING; + lib3270_st_changed(hSession, LIB3270_STATE_RESOLVING, True); + + s = getaddrinfo(hSession->host.current, hSession->host.srvc, &hints, &result); + + if(s != 0) + { + char buffer[4096]; + + snprintf(buffer,4095,_( "Can't connect to %s:%s"), hSession->host.current, hSession->host.srvc); + +#if defined(WIN32) && defined(HAVE_ICONV) + { + char tmpbuffer[4096]; + const char * msg = gai_strerror(s); + size_t in = strlen(msg); + size_t out = 4096; + char * ptr = tmpbuffer; + + iconv_t hConv = iconv_open(lib3270_win32_local_charset(),"UTF-8"); + + trace("Antes: [%s]",msg); + if(iconv(hConv,&msg,&in,&ptr,&out) != ((size_t) -1)) + msg = tmpbuffer; + trace("Depois: [%s]",msg); + + iconv_close(hConv); + + lib3270_popup_dialog( hSession, + LIB3270_NOTIFY_ERROR, + _( "Connection error" ), + buffer, + "%s", + msg); + } + +#else + lib3270_popup_dialog( hSession, + LIB3270_NOTIFY_ERROR, + _( "Connection error" ), + buffer, + "%s", + gai_strerror(s)); +#endif // WIN32 + + + lib3270_set_disconnected(hSession); + return errno = ENOENT; + } + + +#if !defined(_WIN32) + /* don't share the socket with our children */ + (void) fcntl(hSession->sock, F_SETFD, 1); +#endif + + hSession->ever_3270 = False; + hSession->ssl.host = 0; + + if(hSession->options&LIB3270_OPTION_SSL) + { +#if defined(HAVE_LIBSSL) + hSession->ssl.host = 1; + ssl_init(hSession); +#else + lib3270_popup_dialog( hSession, + LIB3270_NOTIFY_ERROR, + _( "SSL error" ), + _( "Unable to connect to secure hosts" ), + _( "This version of %s was built without support for secure sockets layer (SSL)." ), + PACKAGE_NAME); + + return errno = EINVAL; +#endif // HAVE_LIBSSL + } + + /* connect */ + status_connecting(hSession,1); + + for(rp = result; hSession->sock < 0 && rp != NULL; rp = rp->ai_next) + { + hSession->sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); + if(hSession->sock < 0) + continue; + + trace("sock=%d",hSession->sock); + +#ifdef WIN32 + + WSASetLastError(0); + u_long iMode=1; + trace("sock=%d",hSession->sock); + + optval = lib3270_get_toggle(hSession,LIB3270_TOGGLE_KEEP_ALIVE) ? 1 : 0; + if (setsockopt(hSession->sock, SOL_SOCKET, SO_KEEPALIVE, (char *)&optval, sizeof(optval)) < 0) + { + char buffer[4096]; + snprintf(buffer,4095,N_( "Can't %s network keep-alive" ), optval ? _( "enable" ) : _( "disable" )); + + lib3270_popup_dialog( hSession, + LIB3270_NOTIFY_ERROR, + _( "Connection error" ), + buffer, + "%s", lib3270_win32_strerror(WSAGetLastError())); + SOCK_CLOSE(hSession); + continue; + } + else + { + trace_dsn(hSession,"Network keep-alive is %s\n",optval ? "enabled" : "disabled" ); + } + + if(ioctlsocket(hSession->sock,FIONBIO,&iMode)) + { + lib3270_popup_dialog( hSession, + LIB3270_NOTIFY_ERROR, + _( "Connection error" ), + _( "ioctlsocket(FIONBIO) failed." ), + "%s", lib3270_win32_strerror(WSAGetLastError())); + SOCK_CLOSE(hSession); + continue; + } + else if(connect(hSession->sock, rp->ai_addr, rp->ai_addrlen)) + { + int err = WSAGetLastError(); + if(err != WSAEWOULDBLOCK) + { + char buffer[4096]; + snprintf(buffer,4095,_( "Can't connect to %s"), lib3270_get_host(hSession)); + + lib3270_popup_dialog( hSession, + LIB3270_NOTIFY_ERROR, + _( "Connection error" ), + buffer, + "%s", lib3270_win32_strerror(err)); + SOCK_CLOSE(hSession); + continue; + + } + } + + optval = 1; + if (setsockopt(hSession->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); + continue; + } + +#else + fcntl(hSession->sock, F_SETFL,fcntl(hSession->sock,F_GETFL,0)|O_NONBLOCK); + + errno = 0; + if(connect(hSession->sock, rp->ai_addr, rp->ai_addrlen)) + { + if( errno != EINPROGRESS ) + { + char buffer[4096]; + snprintf(buffer,4095,_( "Can't connect to %s:%s"), hSession->host.current, hSession->host.srvc); + + lib3270_popup_dialog( hSession, + LIB3270_NOTIFY_ERROR, + _( "Connection error" ), + buffer, + "%s", + strerror(errno)); + SOCK_CLOSE(hSession); + continue; + } + } + + optval = 1; + if (setsockopt(hSession->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", + strerror(errno)); + SOCK_CLOSE(hSession); + continue; + } + + optval = lib3270_get_toggle(hSession,LIB3270_TOGGLE_KEEP_ALIVE) ? 1 : 0; + if (setsockopt(hSession->sock, SOL_SOCKET, SO_KEEPALIVE, (char *)&optval, sizeof(optval)) < 0) + { + char buffer[4096]; + snprintf(buffer,4095,N_( "Can't %s network keep-alive" ), optval ? _( "enable" ) : _( "disable" )); + + lib3270_popup_dialog( hSession, + LIB3270_NOTIFY_ERROR, + _( "Connection error" ), + buffer, + "%s", + strerror(errno)); + SOCK_CLOSE(hSession); + continue; + } + else + { + trace_dsn(hSession,"Network keep-alive is %s\n",optval ? "enabled" : "disabled" ); + } + +#endif // WIN32 + } + + freeaddrinfo(result); + + // set options for inline out-of-band data and keepalives + + /* +#if defined(OMTU) + else if (setsockopt(hSession->sock, SOL_SOCKET, SO_SNDBUF, (char *)&mtu,sizeof(mtu)) < 0) + { + popup_a_sockerr(hSession, N_( "setsockopt(%s)" ), "SO_SNDBUF"); + SOCK_CLOSE(hSession); + } +#endif + + */ + + if(hSession->sock < 0) + { + lib3270_set_disconnected(hSession); + return errno = ENOTCONN; + } + + // Connecting, set callbacks, wait for connection + hSession->cstate = LIB3270_PENDING; + lib3270_st_changed(hSession, LIB3270_STATE_HALF_CONNECT, True); + + hSession->xio.write = lib3270_add_poll_fd(hSession,hSession->sock,LIB3270_IO_FLAG_WRITE,net_connected,0); + // hSession->ns_write_id = AddOutput(hSession->sock, hSession, net_connected); + + trace("%s: Connection in progress",__FUNCTION__); + + if(seconds) + { + time_t end = time(0)+seconds; + + while(time(0) < end) + { + lib3270_main_iterate(hSession,1); + + switch(hSession->cstate) + { + 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: + 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->cstate); + return -1; + } + + } + + lib3270_disconnect(hSession); + lib3270_write_log(hSession,"connect", "%s: %s",__FUNCTION__,strerror(ETIMEDOUT)); + return errno = ETIMEDOUT; + } + + return 0; + + } + -- libgit2 0.21.2