diff --git a/Makefile.in b/Makefile.in index 33acbff..9ebfbae 100644 --- a/Makefile.in +++ b/Makefile.in @@ -45,6 +45,8 @@ SOURCES= \ $(wildcard src/selection/*.c) \ $(wildcard src/ssl/*.c) \ $(wildcard src/ssl/@OSNAME@/*.c) \ + $(wildcard src/network_modules/*.c) \ + $(wildcard src/network_modules/@OSNAME@/*.c) \ $(BASEDIR)/.tmp/$(LIBNAME)/fallbacks.c TEST_SOURCES= \ diff --git a/lib3270.cbp b/lib3270.cbp index 0e12ad8..8c77087 100644 --- a/lib3270.cbp +++ b/lib3270.cbp @@ -307,6 +307,10 @@ + + + diff --git a/src/core/connect.c b/src/core/connect.c index afbc2f8..26207c3 100644 --- a/src/core/connect.c +++ b/src/core/connect.c @@ -62,7 +62,7 @@ if(ssl_ctx_init(hSession, (SSL_ERROR_MESSAGE *) ssl_error)) return -1; -#if defined(SSL_ENABLE_CRL_CHECK) +#if defined(HAVE_LIBSSL) && defined(SSL_ENABLE_CRL_CHECK) lib3270_crl_free_if_expired(hSession); #endif // defined(SSL_ENABLE_CRL_CHECK) @@ -71,6 +71,7 @@ #endif // HAVE_LIBSSL +/* void connection_failed(H3270 *hSession, const char *message) { lib3270_disconnect(hSession); @@ -94,6 +95,7 @@ lib3270_activate_auto_reconnect(hSession,1000); } +*/ int lib3270_allow_reconnect(const H3270 *hSession) { @@ -169,16 +171,11 @@ } - static int bg_start_tls(H3270 *hSession, void *message) - { - - } - - int lib3270_start_tls(H3270 *hSession) + int lib3270_start_tls(H3270 *hSession, Bool required) { int rc = 0; - if(hSession->network.module->start_tls) + if(hSession->network.module->start_tls,required) { LIB3270_NETWORK_STATE state; memset(&state,0,sizeof(state)); diff --git a/src/core/host.c b/src/core/host.c index d182d99..fbb06a3 100644 --- a/src/core/host.c +++ b/src/core/host.c @@ -42,6 +42,7 @@ #endif // HAVE_MALLOC_H #include +#include #include "resources.h" #include "hostc.h" @@ -279,7 +280,7 @@ static void update_url(H3270 *hSession) lib3270_free(hSession->host.url); hSession->host.url = url; -#ifdef SSL_ENABLE_CRL_CHECK +#if defined(HAVE_LIBSSL) && defined(SSL_ENABLE_CRL_CHECK) lib3270_crl_free(hSession); #endif // SSL_ENABLE_CRL_CHECK diff --git a/src/core/iocalls.c b/src/core/iocalls.c index cb6e64e..aa34aa7 100644 --- a/src/core/iocalls.c +++ b/src/core/iocalls.c @@ -299,13 +299,10 @@ static void internal_remove_poll(H3270 *session, void *id) } -/* LIB3270_EXPORT void lib3270_remove_poll(H3270 *session, void *id) { - debug("%s(%d,%p)",__FUNCTION__,session->connection.sock,id); remove_poll(session, id); } -*/ LIB3270_EXPORT void lib3270_set_poll_state(H3270 *session, void *id, int enabled) { @@ -520,7 +517,7 @@ LIB3270_EXPORT int lib3270_run_task(H3270 *hSession, int(*callback)(H3270 *h, vo int non_blocking(H3270 *hSession, Boolean on) { - if(hSession->network.module->non_blocking,on) + if(hSession->network.module->non_blocking(hSession,on)) return 0; lib3270_set_poll_state(hSession,hSession->xio.read, on); diff --git a/src/core/linux/connect.c b/src/core/linux/connect.c index b8847b8..b33baef 100644 --- a/src/core/linux/connect.c +++ b/src/core/linux/connect.c @@ -42,8 +42,6 @@ #include #include -// #define SOCK_CLOSE(s) close(s->connection.sock); s->connection.sock = -1; - #include #include "hostc.h" @@ -58,8 +56,8 @@ /*---[ Implement ]-------------------------------------------------------------------------------*/ -static void net_connected(H3270 *hSession, int GNUC_UNUSED(fd), LIB3270_IO_FLAG GNUC_UNUSED(flag), void GNUC_UNUSED(*dunno)) -{ + 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); @@ -83,91 +81,94 @@ static void net_connected(H3270 *hSession, int GNUC_UNUSED(fd), LIB3270_IO_FLAG } else if(err) { - lib3270_autoptr(char) body = lib3270_strdup_printf(_("%s (rc=%d)"),strerror(err),err); - connection_failed(hSession,body); + 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\" (rc=%d)"), + strerror(err), + err + ); + + if(hSession->cbk.popup(hSession,popup,!hSession->auto_reconnect_inprogress) == 0) + lib3270_activate_auto_reconnect(hSession,1000); + return; } 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); - if(lib3270_start_tls(hSession)) + if(lib3270_start_tls(hSession,0)) return; lib3270_setup_session(hSession); lib3270_set_connected_initial(hSession); -} - - struct resolver - { - const char * message; - }; + } - static int background_connect(H3270 *hSession, void *host) + int net_reconnect(H3270 *hSession, int seconds) { + LIB3270_NETWORK_STATE state; + memset(&state,0,sizeof(state)); - 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 - - status_resolving(hSession); - - int rc = getaddrinfo(hSession->host.current, hSession->host.srvc, &hints, &result); - if(rc != 0) + // Initialize and connect to host + if(lib3270_run_task(hSession, (int(*)(H3270 *, void *)) hSession->network.module->connect, &state)) { - ((struct resolver *) host)->message = gai_strerror(rc); - return -1; - } - - status_connecting(hSession); - - for(rp = result; hSession->connection.sock < 0 && rp != NULL; rp = rp->ai_next) - { - hSession->connection.sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); - if(hSession->connection.sock < 0) + 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) { - ((struct resolver *) host)->message = strerror(errno); - continue; + popup->summary = popup->body; + popup->body = NULL; } - // Connected! - if(connect(hSession->connection.sock, rp->ai_addr, rp->ai_addrlen)) + lib3270_autoptr(char) syserror = NULL; + if(state.syserror) { - SOCK_CLOSE(hSession); - ((struct resolver *) host)->message = strerror(errno); - continue; + syserror = lib3270_strdup_printf( + _("The system error was \"%s\" (rc=%d)"), + strerror(state.syserror), + state.syserror + ); } +#ifdef _WIN32 + else if(state.winerror) + { + #error TODO + } +#endif // _WIN32 - } - - freeaddrinfo(result); - - return 0; - - } + if(!popup->body) + { + if(state.error_message) + popup->body = state.error_message; + else + popup->body = syserror; + } - int net_reconnect(H3270 *hSession, int seconds) - { - struct resolver host; - memset(&host,0,sizeof(host)); + if(hSession->cbk.popup(hSession,popup,!hSession->auto_reconnect_inprogress) == 0) + lib3270_activate_auto_reconnect(hSession,1000); - // Connect to host - if(lib3270_run_task(hSession, background_connect, &host) || hSession->connection.sock < 0) - { - connection_failed(hSession,host.message); return errno = ENOTCONN; } - /* don't share the socket with our children */ - (void) fcntl(hSession->connection.sock, F_SETFD, 1); + // + // Connected + // hSession->ever_3270 = False; #if defined(HAVE_LIBSSL) @@ -182,7 +183,7 @@ static void net_connected(H3270 *hSession, int GNUC_UNUSED(fd), LIB3270_IO_FLAG // set options for inline out-of-band data and keepalives int optval = 1; - if (setsockopt(hSession->connection.sock, SOL_SOCKET, SO_OOBINLINE, (char *)&optval,sizeof(optval)) < 0) + if(hSession->network.module->setsockopt(hSession, SOL_SOCKET, SO_OOBINLINE, &optval, sizeof(optval)) < 0) { int rc = errno; lib3270_popup_dialog( hSession, @@ -191,12 +192,12 @@ static void net_connected(H3270 *hSession, int GNUC_UNUSED(fd), LIB3270_IO_FLAG _( "setsockopt(SO_OOBINLINE) has failed" ), "%s", strerror(rc)); - SOCK_CLOSE(hSession); + hSession->network.module->disconnect(hSession); return rc; } 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) + if (hSession->network.module->setsockopt(hSession, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval)) < 0) { int rc = errno; @@ -209,7 +210,8 @@ static void net_connected(H3270 *hSession, int GNUC_UNUSED(fd), LIB3270_IO_FLAG buffer, "%s", strerror(rc)); - SOCK_CLOSE(hSession); + + hSession->network.module->disconnect(hSession); return rc; } else @@ -254,7 +256,7 @@ static void net_connected(H3270 *hSession, int GNUC_UNUSED(fd), LIB3270_IO_FLAG case LIB3270_CONNECTED_INITIAL_E: case LIB3270_CONNECTED_NVT: case LIB3270_CONNECTED_SSCP: - case LIB3270_RESOLVING: + case LIB3270_CONNECTING: break; case LIB3270_NOT_CONNECTED: diff --git a/src/core/popup.c b/src/core/popup.c index b4a0929..f6412fa 100644 --- a/src/core/popup.c +++ b/src/core/popup.c @@ -135,7 +135,14 @@ LIB3270_POPUP * lib3270_popup_clone_printf(const LIB3270_POPUP *origin, const ch // Alocate new struct LIB3270_POPUP * popup = lib3270_malloc(sizeof(LIB3270_POPUP)+strlen(body)+1); - *popup = *origin; + if(origin) + { + *popup = *origin; + } + else + { + memset(popup,0,sizeof(LIB3270_POPUP)); + } strcpy((char *)(popup+1),body); popup->body = (char *)(popup+1); @@ -154,7 +161,8 @@ static int def_popup(H3270 *hSession, const LIB3270_POPUP *popup, unsigned char for(ix = 0; ix < (sizeof(text)/sizeof(text[0])); ix++) { - lib3270_write_log(hSession,"popup","%s",text[ix]); + if(text[ix]) + lib3270_write_log(hSession,"popup","%s",text[ix]); } return ENOTSUP; diff --git a/src/core/properties/boolean.c b/src/core/properties/boolean.c index ffe901b..74ff459 100644 --- a/src/core/properties/boolean.c +++ b/src/core/properties/boolean.c @@ -47,7 +47,7 @@ void lib3270_disable_crl_download(H3270 *hSession) { -#ifdef SSL_ENABLE_CRL_CHECK +#if defined(HAVE_LIBSSL) && defined(SSL_ENABLE_CRL_CHECK) hSession->ssl.crl.download = 0; #endif // SSL_ENABLE_CRL_CHECK } diff --git a/src/core/properties/string.c b/src/core/properties/string.c index 06b102a..93c348c 100644 --- a/src/core/properties/string.c +++ b/src/core/properties/string.c @@ -28,6 +28,7 @@ */ #include + #include #include #include #include diff --git a/src/core/rpq.c b/src/core/rpq.c index 4ce873f..0473d0b 100644 --- a/src/core/rpq.c +++ b/src/core/rpq.c @@ -686,7 +686,7 @@ static int get_rpq_address(H3270 *hSession, unsigned char *buf, const int maxlen struct sockaddr_in6 sa6; #endif // HAVE_GETADDRINFO } u; - int addrlen = sizeof(u); + socklen_t addrlen = sizeof(u); void *src = NULL; int len = 0; diff --git a/src/core/screen.c b/src/core/screen.c index 9869ae2..8459b6a 100644 --- a/src/core/screen.c +++ b/src/core/screen.c @@ -550,19 +550,21 @@ void status_oerr(H3270 *session, int error_type) */ void status_resolving(H3270 *hSession) { - lib3270_set_cstate(hSession,LIB3270_RESOLVING); - lib3270_st_changed(hSession, LIB3270_STATE_RESOLVING, True); + debug("%s",__FUNCTION__); mcursor_set(hSession,LIB3270_POINTER_LOCKED); + + lib3270_st_changed(hSession, LIB3270_STATE_RESOLVING, True); status_changed(hSession, LIB3270_MESSAGE_RESOLVING); } void status_connecting(H3270 *hSession) { - lib3270_set_cstate(hSession,LIB3270_RESOLVING); - lib3270_st_changed(hSession, LIB3270_STATE_CONNECTING, True); + debug("%s",__FUNCTION__); mcursor_set(hSession,LIB3270_POINTER_LOCKED); + + lib3270_st_changed(hSession, LIB3270_STATE_CONNECTING, True); status_changed(hSession, LIB3270_MESSAGE_CONNECTING); } diff --git a/src/core/session.c b/src/core/session.c index e8e53b9..7921ed4 100644 --- a/src/core/session.c +++ b/src/core/session.c @@ -84,11 +84,17 @@ void lib3270_session_free(H3270 *h) lib3270_crl_free(h); #endif // SSL_ENABLE_CRL_CHECK + // Release network module + if(h->network.module) + { + h->network.module->finalize(h); + h->network.module = NULL; + } + // Release state change callbacks for(f=0;flisteners.state[f]); - // Release toggle change listeners. for(f=0;flisteners.toggle[f]); @@ -316,7 +322,11 @@ static void lib3270_session_init(H3270 *hSession, const char *model, const char int f; memset(hSession,0,sizeof(H3270)); -// hSession->sz = sizeof(H3270); + lib3270_set_default_network_module(hSession); + +#if defined(SSL_ENABLE_CRL_CHECK) && defined(HAVE_LIBSSL) + hSession->ssl.crl.download = 1; +#endif // SSL_ENABLE_CRL_CHECK lib3270_set_host_charset(hSession,charset); lib3270_reset_callbacks(hSession); @@ -438,22 +448,11 @@ H3270 * lib3270_session_new(const char *model) trace("%s - configured=%s",__FUNCTION__,default_session ? "Yes" : "No"); hSession = lib3270_malloc(sizeof(H3270)); - hSession->id = 0; - -#ifdef HAVE_LIBSSL - hSession->ssl.protocol.min_version = 0; - hSession->ssl.protocol.max_version = 0; -#endif // HAVE_LIBSSL - -#if defined(SSL_ENABLE_CRL_CHECK) && defined(HAVE_LIBSSL) - hSession->ssl.crl.download = 1; -#endif // SSL_ENABLE_CRL_CHECK + lib3270_session_init(hSession, model, "bracket" ); if(!default_session) default_session = hSession; - lib3270_session_init(hSession, model, "bracket" ); - if(screen_init(hSession)) return NULL; diff --git a/src/core/state.c b/src/core/state.c index 1f59643..bfdf34b 100644 --- a/src/core/state.c +++ b/src/core/state.c @@ -38,12 +38,12 @@ LIB3270_EXPORT LIB3270_CSTATE lib3270_get_connection_state(const H3270 *h) LIB3270_EXPORT int lib3270_pconnected(const H3270 *h) { - return (((int) h->connection.state) >= (int)LIB3270_RESOLVING); + return (((int) h->connection.state) >= (int)LIB3270_CONNECTING); } LIB3270_EXPORT int lib3270_half_connected(const H3270 *h) { - return (h->connection.state == LIB3270_RESOLVING || h->connection.state == LIB3270_PENDING); + return (h->connection.state == LIB3270_CONNECTING || h->connection.state == LIB3270_PENDING); } LIB3270_EXPORT int lib3270_is_disconnected(const H3270 *h) diff --git a/src/core/telnet.c b/src/core/telnet.c index 2c35576..be37c3c 100644 --- a/src/core/telnet.c +++ b/src/core/telnet.c @@ -261,7 +261,6 @@ static const char *trsp_flag[2] = { "POSITIVE-RESPONSE", "NEGATIVE-RESPONSE" }; #define SE_EAGAIN WSAEINPROGRESS #define SE_EPIPE WSAECONNABORTED #define SE_EINPROGRESS WSAEINPROGRESS - #define SOCK_CLOSE(s) closesocket(s) #define SOCK_IOCTL(s, f, v) ioctlsocket(s, f, (void *)v) #else /*][*/ #define socket_errno() errno @@ -275,7 +274,6 @@ static const char *trsp_flag[2] = { "POSITIVE-RESPONSE", "NEGATIVE-RESPONSE" }; #define SE_EINPROGRESS EINPROGRESS #endif /*]*/ - #define SOCK_CLOSE(s) close(s) #define SOCK_IOCTL ioctl #endif /*]*/ @@ -539,8 +537,6 @@ LIB3270_INTERNAL void lib3270_sock_disconnect(H3270 *hSession) */ void net_disconnect(H3270 *hSession) { - LIB3270_NETWORK_STATE state; - memset(&state,0,sizeof(state)); // Disconnect from host #if defined(HAVE_LIBSSL) @@ -563,7 +559,7 @@ void net_disconnect(H3270 *hSession) hSession->xio.write = 0; } - hSession->network.module->disconnect(hSession,&state); + hSession->network.module->disconnect(hSession); trace_dsn(hSession,"SENT disconnect\n"); @@ -641,9 +637,9 @@ void net_input(H3270 *hSession, int GNUC_UNUSED(fd), LIB3270_IO_FLAG GNUC_UNUSED if (hSession->ssl.con != NULL) nr = SSL_read(hSession->ssl.con, (char *) buffer, BUFSZ); else - nr = hSession->network.module->recv(hSession->network.context, buffer, BUFSZ); + nr = hSession->network.module->recv(hSession, buffer, BUFSZ); #else - nr = hSession->network.module->recv(hSession->network.context, buffer, BUFSZ); + nr = hSession->network.module->recv(hSession, buffer, BUFSZ); #endif // HAVE_LIBSSL if (nr < 0) @@ -1602,13 +1598,10 @@ static int process_eor(H3270 *hSession) return 0; } - -/** - * @brief Called when there is an exceptional condition on the socket. - */ +/// @brief Called when there is an exceptional condition on the socket. void net_exception(H3270 *session, int GNUC_UNUSED(fd), LIB3270_IO_FLAG GNUC_UNUSED(flag), void GNUC_UNUSED(*dunno)) { - CHECK_SESSION_HANDLE(session); + debug("%s",__FUNCTION__); trace_dsn(session,"RCVD urgent data indication\n"); if (!session->syncing) @@ -1655,9 +1648,10 @@ LIB3270_INTERNAL int lib3270_sock_send(H3270 *hSession, unsigned const char *buf if(rc > 0) return rc; - // Recv error, notify + // Send error, notify #if defined(HAVE_LIBSSL) + #error TODO - The send method should emit popup messages. if(hSession->ssl.con != NULL) { unsigned long e; @@ -1671,25 +1665,7 @@ LIB3270_INTERNAL int lib3270_sock_send(H3270 *hSession, unsigned const char *buf } #endif // HAVE_LIBSSL - trace_dsn(hSession,"RCVD socket error %d\n", socket_errno()); - - switch(socket_errno()) - { - case SE_EPIPE: - popup_an_error(hSession, "%s", _( "Broken pipe" )); - break; - - case SE_ECONNRESET: - popup_an_error(hSession, "%s", _( "Connection reset by peer" )); - break; - - case SE_EINTR: - return 0; - - default: - popup_a_sockerr(NULL, "%s", _( "Socket write error" ) ); - - } + trace_dsn(hSession,"RCVD socket error %d\n", -rc); return -1; } @@ -2029,7 +2005,7 @@ const char * lib3270_connection_state_get_name(const LIB3270_CSTATE cstate) static const char *state_names[] = { "unconnected", - "resolving", + "connecting", "pending", "connected initial", "TN3270 NVT", diff --git a/src/core/toggles/init.c b/src/core/toggles/init.c index be02226..14df67c 100644 --- a/src/core/toggles/init.c +++ b/src/core/toggles/init.c @@ -77,19 +77,22 @@ static void toggle_nop(H3270 GNUC_UNUSED(*session), const struct lib3270_toggle { } -static void toggle_keepalive(H3270 *session, const struct lib3270_toggle GNUC_UNUSED(*t), LIB3270_TOGGLE_TYPE GNUC_UNUSED(tt)) +static void toggle_keepalive(H3270 *hSession, const struct lib3270_toggle GNUC_UNUSED(*t), LIB3270_TOGGLE_TYPE GNUC_UNUSED(tt)) { - // Update keep-alive option - int optval = t->value ? 1 : 0; - - if(session->network.module->setsockopt(session, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval)) < 0) - { - if(errno != ENOTCONN) - popup_a_sockerr(session, _( "Can't %s network keep-alive" ), optval ? _( "enable" ) : _( "disable" )); - } - else + if(hSession->network.context) { - trace_dsn(session,"Network keep-alive is %s\n",optval ? "enabled" : "disabled" ); + // Has network context, update keep-alive option + int optval = t->value ? 1 : 0; + + if(hSession->network.module->setsockopt(hSession, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval)) < 0) + { + if(errno != ENOTCONN) + popup_a_sockerr(hSession, _( "Can't %s network keep-alive" ), optval ? _( "enable" ) : _( "disable" )); + } + else + { + trace_dsn(hSession,"Network keep-alive is %s\n",optval ? "enabled" : "disabled" ); + } } } diff --git a/src/core/util.c b/src/core/util.c index a00d02a..5a67f9d 100644 --- a/src/core/util.c +++ b/src/core/util.c @@ -44,6 +44,10 @@ #include #endif // HAVE_LIBSSL +#if defined(HAVE_MALLOC_H) + #include +#endif // defined + #define my_isspace(c) isspace((unsigned char)c) /** diff --git a/src/core/windows/connect.c b/src/core/windows/connect.c index ced762a..91daf41 100644 --- a/src/core/windows/connect.c +++ b/src/core/windows/connect.c @@ -47,8 +47,6 @@ #include #endif // HAVE_ICONV -#define SOCK_CLOSE(s) closesocket(s->connection.sock); s->connection.sock = -1; - #include "hostc.h" #include "trace_dsc.h" #include "telnetc.h" diff --git a/src/include/internals.h b/src/include/internals.h index 40f2885..5414361 100644 --- a/src/include/internals.h +++ b/src/include/internals.h @@ -883,10 +883,16 @@ LIB3270_INTERNAL int non_blocking(H3270 *session, Boolean on); /// @brief Fire CState change. LIB3270_INTERNAL int lib3270_set_cstate(H3270 *hSession, LIB3270_CSTATE cstate); - inline LIB3270_NET_CONTEXT * lib3270_get_net_context(H3270 *hSession) { - return hSession->network.context; - } - - LIB3270_INTERNAL int lib3270_start_tls(H3270 *hSession); + /// + /// @brief Start TLS/SSL + /// + /// @param hSession Session handle. + /// @param required Non zero if the SSL/TLS is not optional. + /// + /// @return 0 if ok, non zero if failed. + /// + /// @retval ENOTSUP TLS/SSL is not supported by library. + /// + LIB3270_INTERNAL int lib3270_start_tls(H3270 *hSession, Bool required); diff --git a/src/include/lib3270.h b/src/include/lib3270.h index 6e49a94..62fe9a2 100644 --- a/src/include/lib3270.h +++ b/src/include/lib3270.h @@ -252,7 +252,7 @@ typedef enum lib3270_cstate { LIB3270_NOT_CONNECTED, ///< @brief no socket, disconnected - LIB3270_RESOLVING, ///< @brief resolving hostname + LIB3270_CONNECTING, ///< @brief connecting to host LIB3270_PENDING, ///< @brief connection pending LIB3270_CONNECTED_INITIAL, ///< @brief connected, no mode yet LIB3270_CONNECTED_ANSI, ///< @brief connected in NVT ANSI mode diff --git a/src/include/networking.h b/src/include/networking.h index ab73371..3bc2b68 100644 --- a/src/include/networking.h +++ b/src/include/networking.h @@ -41,34 +41,23 @@ DWORD winerror; ///< @brief Win32 error got from GetLastError() #endif // _WIN32 + const char * error_message; /// @brief System error message. + const LIB3270_POPUP *popup; /// @brief Detailed info for popup. } LIB3270_NETWORK_STATE; - typedef struct _lib3270_new_context LIB3270_NET_CONTEXT; + typedef struct _lib3270_net_context LIB3270_NET_CONTEXT; typedef struct lib3270_net_module { - const char * name; ///< @brief The network module name. - - /// @brief Initialize network module - /// - /// @param hSession TN3270 session. - /// @param state Pointer to state message. - /// - /// @return Allocated network context. - /// - /// @retval NULL Initialization failed. - /// - LIB3270_NET_CONTEXT * (*init)(H3270 *hSession, LIB3270_NETWORK_STATE *state); - /// @brief Deinitialize network module. /// /// @param context Network context. /// @param hSession TN3270 session. /// @param state Pointer to state message. /// - void (*deinit)(H3270 *hSession, LIB3270_NETWORK_STATE *state); + void (*finalize)(H3270 *hSession); /// @brief Connect to host. /// @@ -77,7 +66,7 @@ /// @param seconds Seconds for timeout. /// @param state Pointer to state message. /// - int (*connect)(H3270 *hSession, int seconds, LIB3270_NETWORK_STATE *state); + int (*connect)(H3270 *hSession, LIB3270_NETWORK_STATE *state); /// @brief Disconnect from host. /// @@ -85,9 +74,9 @@ /// @param hSession TN3270 session. /// @param state Pointer to state message. /// - int (*disconnect)(H3270 *hSession, LIB3270_NETWORK_STATE *state); + int (*disconnect)(H3270 *hSession); - int (*start_tls)(H3270 *hSession, LIB3270_NETWORK_STATE *msg); + int (*start_tls)(H3270 *hSession, LIB3270_NETWORK_STATE *msg, unsigned char required); /// @brief Send on network context. /// @@ -126,16 +115,26 @@ int (*getsockname)(const H3270 *hSession, struct sockaddr *addr, socklen_t *addrlen); /// @brief Set socket options. - int (*setsockopt)(H3270 *hSession, int level, int optname, void *optval, size_t optlen); + int (*setsockopt)(H3270 *hSession, int level, int optname, const void *optval, size_t optlen); /// @brief Get socket options. int (*getsockopt)(H3270 *hSession, int level, int optname, void *optval, socklen_t *optlen); } LIB3270_NET_MODULE; - LIB3270_NET_CONTEXT * lib3270_get_net_context(H3270 *hSession); - LIB3270_NET_CONTEXT * lib3270_get_default_net_context(void); - + /** + * @brief Activate the default (and insecure) network module. + * + */ + LIB3270_INTERNAL void lib3270_set_default_network_module(H3270 *hSession); + + /** + * @brief Connect to host, returns a connected socket. + * + * @return The Socket number or -1 in case of failure. + * + */ + LIB3270_INTERNAL int lib3270_network_connect(H3270 *hSession, LIB3270_NETWORK_STATE *state); #endif // LIB3270_NETWORKING_H_INCLUDED diff --git a/src/network_modules/linux/connect.c b/src/network_modules/linux/connect.c new file mode 100644 index 0000000..c273992 --- /dev/null +++ b/src/network_modules/linux/connect.c @@ -0,0 +1,118 @@ +/* + * "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 ', 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 networking.h e possui - linhas de código. + * + * Contatos: + * + * perry.werneck@gmail.com (Alexandre Perry de Souza Werneck) + * erico.mendonca@gmail.com (Erico Mascarenhas de Mendonça) + * + */ + + /** + * @brief Default networking methods. + * + */ + + #include + #include + #include + #include + #include + #include + + #include + #include + #include + +int lib3270_network_connect(H3270 *hSession, LIB3270_NETWORK_STATE *state) { + + // + // Resolve hostname + // + struct addrinfo hints; + struct addrinfo * result = 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 + + status_resolving(hSession); + + int rc = getaddrinfo(hSession->host.current, hSession->host.srvc, &hints, &result); + if(rc) + { + 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; sock < 0 && rp != NULL; rp = rp->ai_next) + { + // Got socket from host definition. + sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); + if(sock < 0) + { + // Can't get socket. + state->syserror = errno; + continue; + } + + // Try connect. + if(connect(sock, rp->ai_addr, rp->ai_addrlen)) + { + // Can't connect to host + state->syserror = errno; + close(sock); + sock = -1; + continue; + } + + } + + freeaddrinfo(result); + + 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; + } + + // don't share the socket with our children + (void) fcntl(sock, F_SETFD, 1); + + return sock; +} diff --git a/src/network_modules/private.h b/src/network_modules/private.h new file mode 100644 index 0000000..e45ae92 --- /dev/null +++ b/src/network_modules/private.h @@ -0,0 +1,52 @@ +/* + * "Software G3270, 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 ', 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 private.h e possui - linhas de código. + * + * Contatos: + * + * perry.werneck@gmail.com (Alexandre Perry de Souza Werneck) + * erico.mendonca@gmail.com (Erico Mascarenhas de Mendonça) + * + */ + +#ifndef LIB3270_NETWORK_MODULES_PRIVATE_H_INCLUDED + + #define LIB3270_NETWORK_MODULES_PRIVATE_H_INCLUDED + + #include + + #ifdef _WIN32 + #include + #include + #else + #include + #include + #endif // _WIN32 + + #include + #include + + #include + #include + + LIB3270_INTERNAL ssize_t unsecure_network_send(H3270 *hSession, const void *buffer, size_t length); + +#endif // !LIB3270_NETWORK_MODULES_PRIVATE_H_INCLUDED diff --git a/src/network_modules/unsecure.c b/src/network_modules/unsecure.c index 998e1eb..f764a82 100644 --- a/src/network_modules/unsecure.c +++ b/src/network_modules/unsecure.c @@ -32,45 +32,41 @@ * */ - #include - #ifdef _WIN32 - #include - #include - #endif // _WIN32 + #include "private.h" - #include - #include + #include + #include + #include - struct _lib3270_new_context { + struct _lib3270_net_context { int sock; }; - LIB3270_NET_CONTEXT * unsecure_network_init(H3270 *hSession, LIB3270_NETWORK_STATE *state) { + static void unsecure_network_finalize(H3270 *hSession) { - LIB3270_NET_CONTEXT * context = lib3270_malloc(sizeof(LIB3270_NET_CONTEXT)); - - context->sock = -1; + debug("%s",__FUNCTION__); - return context; - } + if(hSession->network.context) { + lib3270_free(hSession->network.context); + hSession->network.context = NULL; + } - void unsecure_network_deinit(H3270 *hSession, LIB3270_NETWORK_STATE *state) { - unsecure_network_disconnect(hSession->network.context,hSession,state); - lib3270_free(context); } -int unsecure_network_disconnect(H3270 *hSession, LIB3270_NETWORK_STATE *state) { + static int unsecure_network_disconnect(H3270 *hSession) { debug("%s",__FUNCTION__); - if(context->sock >= 0) { - shutdown(hSession.network.context->sock, 2); + + if(hSession->network.context->sock >= 0) { + shutdown(hSession->network.context->sock, 2); close(hSession->network.context->sock); - hSession.network.context->sock = -1; + hSession->network.context->sock = -1; } -} + return 0; + } -ssize_t unsecure_network_send(H3270 *hSession, const void *buffer, size_t length) { + ssize_t unsecure_network_send(H3270 *hSession, const void *buffer, size_t length) { if(hSession->network.context->sock < 0) { return -(errno = ENOTCONN); @@ -78,19 +74,68 @@ ssize_t unsecure_network_send(H3270 *hSession, const void *buffer, size_t length ssize_t bytes = send(hSession->network.context->sock,buffer,length,0); - if(bytes < 0) - return -errno; + debug("%s bytes=%d",__FUNCTION__,(int) bytes); - return 0; -} + if(bytes >= 0) + return bytes; + + int rc = errno; -ssize_t unsecure_network_recv(H3270 *hSession, void *buf, size_t len) { + debug("%s: %s",__FUNCTION__,strerror(rc)); + + switch(rc) + { + case EPIPE: + lib3270_popup_dialog( + hSession, + LIB3270_NOTIFY_ERROR, + NULL, + _("Broken pipe"), + _("The system error code was %d"), + rc + ); + break; + + case ECONNRESET: + lib3270_popup_dialog( + hSession, + LIB3270_NOTIFY_ERROR, + NULL, + _("Connection reset by peer"), + _("The system error code was %d"), + rc + ); + break; + + case EINTR: + return 0; + + default: + lib3270_popup_dialog( + hSession, + LIB3270_NOTIFY_ERROR, + NULL, + _("Unexpected error writing to network socket"), + _("The system error code was %d (%s)"), + rc, strerror(rc) + ); + + } + + return -rc; + } + + static ssize_t unsecure_network_recv(H3270 *hSession, void *buf, size_t len) { + + debug("%s",__FUNCTION__); if(hSession->network.context->sock < 0) { return -(errno = ENOTCONN); } - ssize_t bytes = recv(hSession->network.context->sock, (char *) buffer, len, 0); + ssize_t bytes = recv(hSession->network.context->sock, (char *) buf, len, 0); + + debug("%s bytes=%d",__FUNCTION__,(int) bytes); if(bytes < 0) { return -errno; @@ -99,17 +144,17 @@ ssize_t unsecure_network_recv(H3270 *hSession, void *buf, size_t len) { return bytes; } -int unsecure_getsockname(const H3270 *hSession, struct sockaddr *addr, socklen_t *addrlen) { +static int unsecure_network_getsockname(const H3270 *hSession, struct sockaddr *addr, socklen_t *addrlen) { if(hSession->network.context->sock < 0) return -(errno = ENOTCONN); - return getsockname(hSession->network.context->sock, buf, addrlen); + return getsockname(hSession->network.context->sock, addr, addrlen); } -void * unsecure_add_poll(H3270 *hSession, LIB3270_IO_FLAG flag, void(*call)(H3270 *, int, LIB3270_IO_FLAG, void *), void *userdata) { +static void * unsecure_network_add_poll(H3270 *hSession, LIB3270_IO_FLAG flag, void(*call)(H3270 *, int, LIB3270_IO_FLAG, void *), void *userdata) { return lib3270_add_poll_fd(hSession,hSession->network.context->sock,flag,call,userdata); } -int unsecure_non_blocking(H3270 *hSession, const unsigned char on) { +static int unsecure_network_non_blocking(H3270 *hSession, const unsigned char on) { if(hSession->network.context->sock < 0) return 0; @@ -165,29 +210,93 @@ int unsecure_non_blocking(H3270 *hSession, const unsigned char on) { debug("Socket %d is now %s",hSession->network.context->sock,(on ? "Non Blocking" : "Blocking")); + return 0; } -int unsecure_is_connected(H3270 *hSession) { - return hSession->network.context.sock > 0; +static int unsecure_network_is_connected(H3270 *hSession) { + return hSession->network.context->sock > 0; } -int unsecure_setsockopt(H3270 *hSession, int level, int optname, const void *optval, size_t optlen) { +static int unsecure_network_setsockopt(H3270 *hSession, int level, int optname, const void *optval, size_t optlen) { - if(hSession->network.context.sock < 0) { + if(hSession->network.context->sock < 0) { errno = ENOTCONN; return -1; } - return setsockopt(hSession->network.context.sock, level, optname, optval, optlen); + return setsockopt(hSession->network.context->sock, level, optname, optval, optlen); } -int unsecure_getsockopt(H3270 *hSession, int level, int optname, void *optval, socklen_t *optlen) { +static int unsecure_network_getsockopt(H3270 *hSession, int level, int optname, void *optval, socklen_t *optlen) { - if(hSession->network.context.sock < 0) { + if(hSession->network.context->sock < 0) { errno = ENOTCONN; return -1; } - return getsockopt(hSession->network.context.sock, level, optname, optval, optlen) + return getsockopt(hSession->network.context->sock, level, optname, optval, optlen); +} + +static int unsecure_network_connect(H3270 *hSession, LIB3270_NETWORK_STATE *state) { + + hSession->network.context->sock = lib3270_network_connect(hSession, state); + if(hSession->network.context->sock < 0) + return hSession->network.context->sock; + + return 0; } + +static int unsecure_network_start_tls(H3270 GNUC_UNUSED(*hSession), LIB3270_NETWORK_STATE *msg, unsigned char required) { + + if(required) { + + // TODO: Replace network module with the openssl version, initialize and execute start_tls on it. + + static const LIB3270_POPUP popup = { + .type = LIB3270_NOTIFY_ERROR, + .summary = N_("Can't activate SSL/TLS"), + .body = N_("The protocol library was build without SSL/TLS support") + }; + + msg->popup = &popup; + + return ENOTSUP; + + } + + return 0; +} + +void lib3270_set_default_network_module(H3270 *hSession) { + + static const LIB3270_NET_MODULE module = { + .finalize = unsecure_network_finalize, + .connect = unsecure_network_connect, + .disconnect = unsecure_network_disconnect, + .start_tls = unsecure_network_start_tls, + .send = unsecure_network_send, + .recv = unsecure_network_recv, + .add_poll = unsecure_network_add_poll, + .non_blocking = unsecure_network_non_blocking, + .is_connected = unsecure_network_is_connected, + .getsockname = unsecure_network_getsockname, + .setsockopt = unsecure_network_setsockopt, + .getsockopt = unsecure_network_getsockopt + }; + + debug("%s",__FUNCTION__); + + if(hSession->network.context) { + // Has context, finalize it. + hSession->network.module->finalize(hSession); + } + + hSession->network.context = lib3270_malloc(sizeof(LIB3270_NET_CONTEXT)); + memset(hSession->network.context,0,sizeof(LIB3270_NET_CONTEXT)); + hSession->network.context->sock = -1; + + hSession->network.module = &module; + +} + diff --git a/src/ssl/linux/private.h b/src/ssl/linux/private.h index e3096e7..89f2317 100644 --- a/src/ssl/linux/private.h +++ b/src/ssl/linux/private.h @@ -45,14 +45,14 @@ #include #include - #ifdef HAVE_LDAP + #if defined(HAVE_LIBSSL) && defined(HAVE_LDAP) /// @brief Use libldap to get CRL. LIB3270_INTERNAL X509_CRL * get_crl_using_ldap(H3270 *hSession, SSL_ERROR_MESSAGE * message, const char *consturl); #endif // HAVE_LDAP - #ifdef HAVE_LIBCURL + #if defined (HAVE_LIBSSL) && defined(HAVE_LIBCURL) /// @brief Use libcurl to get CRL. LIB3270_INTERNAL X509_CRL * get_crl_using_url(H3270 *hSession, SSL_ERROR_MESSAGE * message, const char *consturl); diff --git a/src/ssl/properties.c b/src/ssl/properties.c index c3f49ac..3300149 100644 --- a/src/ssl/properties.c +++ b/src/ssl/properties.c @@ -51,7 +51,7 @@ LIB3270_EXPORT int lib3270_get_secure_host(const H3270 *hSession) } -#ifdef SSL_ENABLE_CRL_CHECK +#if defined(HAVE_LIBSSL) && defined(SSL_ENABLE_CRL_CHECK) LIB3270_EXPORT char * lib3270_get_ssl_crl_text(const H3270 *hSession) { @@ -120,7 +120,7 @@ LIB3270_EXPORT char * lib3270_get_ssl_peer_certificate_text(const H3270 *hSessio #pragma GCC diagnostic ignored "-Wunused-parameter" const char * lib3270_crl_get_url(const H3270 *hSession) { -#ifdef SSL_ENABLE_CRL_CHECK +#if defined(HAVE_LIBSSL) && defined(SSL_ENABLE_CRL_CHECK) if(hSession->ssl.crl.url) return hSession->ssl.crl.url; @@ -144,7 +144,7 @@ LIB3270_EXPORT char * lib3270_get_ssl_peer_certificate_text(const H3270 *hSessio FAIL_IF_ONLINE(hSession); -#ifdef SSL_ENABLE_CRL_CHECK +#if defined(HAVE_LIBSS) && defined(SSL_ENABLE_CRL_CHECK) if(hSession->ssl.crl.url) { @@ -197,7 +197,7 @@ LIB3270_EXPORT char * lib3270_get_ssl_peer_certificate_text(const H3270 *hSessio #pragma GCC diagnostic ignored "-Wunused-parameter" const char * lib3270_crl_get_preferred_protocol(const H3270 *hSession) { -#ifdef SSL_ENABLE_CRL_CHECK +#if defined(HAVE_LIBSSL) && defined(SSL_ENABLE_CRL_CHECK) if(hSession->ssl.crl.prefer) return hSession->ssl.crl.prefer; #endif @@ -213,7 +213,7 @@ LIB3270_EXPORT char * lib3270_get_ssl_peer_certificate_text(const H3270 *hSessio FAIL_IF_ONLINE(hSession); -#ifdef SSL_ENABLE_CRL_CHECK +#if defined(HAVE_LIBSSL) && defined(HAVE_SSL_ENABLE_CRL_CHECK) if(hSession->ssl.crl.prefer) { -- libgit2 0.21.2