diff --git a/lib3270.cbp b/lib3270.cbp index 5f00494..bde1d60 100644 --- a/lib3270.cbp +++ b/lib3270.cbp @@ -337,7 +337,7 @@ - + diff --git a/src/core/host.c b/src/core/host.c index f3935c4..136656b 100644 --- a/src/core/host.c +++ b/src/core/host.c @@ -388,13 +388,14 @@ LIB3270_EXPORT int lib3270_set_url(H3270 *h, const char *n) { 0, "telnet://", "telnet" } }; + int f; */ + lib3270_autoptr(char) str = strdup(n); char * hostname = lib3270_set_network_module_from_url(h,str); const char * srvc; char * ptr; char * query = ""; - int f; trace("%s(%s)",__FUNCTION__,str); diff --git a/src/include/networking.h b/src/include/networking.h index 3143f7e..a4a47c9 100644 --- a/src/include/networking.h +++ b/src/include/networking.h @@ -177,7 +177,7 @@ * @retval -EAGAIN Try again. * */ - LIB3270_INTERNAL int lib3270_network_recv_failed(H3270 *hSession); + LIB3270_INTERNAL int lib3270_socket_recv_failed(H3270 *hSession); /** * @brief Translate system socket send error codes, show popup if needed. @@ -187,7 +187,9 @@ * @return Translated error code. * */ - LIB3270_INTERNAL int lib3270_network_send_failed(H3270 *hSession); + LIB3270_INTERNAL int lib3270_socket_send_failed(H3270 *hSession); + + LIB3270_INTERNAL int lib3270_socket_set_non_blocking(H3270 *hSession, int sock, const unsigned char on); /** * @breif Select the network context from URL. @@ -195,7 +197,8 @@ * @return Pointer to the hostname or NULL if failed (sets errno). * */ - LIB3270_INTERNAL const char * lib3270_set_network_module_from_url(H3270 *hSession, const char *url); + LIB3270_INTERNAL char * lib3270_set_network_module_from_url(H3270 *hSession, const char *url); + /** * @brief Select the default (unsecure) network context. @@ -205,6 +208,10 @@ */ LIB3270_INTERNAL void lib3270_set_default_network_module(H3270 *hSession); +#ifdef HAVE_LIBSSL + LIB3270_INTERNAL void lib3270_set_libssl_network_module(H3270 *hSession); +#endif // HAVE_LIBSSL + LIB3270_INTERNAL int lib3270_activate_ssl_network_module(H3270 *hSession, int sock); #endif // LIB3270_NETWORKING_H_INCLUDED diff --git a/src/network_modules/default/main.c b/src/network_modules/default/main.c index fff9e91..c2fcae8 100644 --- a/src/network_modules/default/main.c +++ b/src/network_modules/default/main.c @@ -33,7 +33,6 @@ */ #include "private.h" - #include static void unsecure_network_finalize(H3270 *hSession) { @@ -70,7 +69,7 @@ if(bytes >= 0) return bytes; - return lib3270_network_send_failed(hSession); + return lib3270_socket_send_failed(hSession); } @@ -82,7 +81,7 @@ return bytes; } - return lib3270_network_recv_failed(hSession); + return lib3270_socket_recv_failed(hSession); } @@ -95,62 +94,7 @@ static void * unsecure_network_add_poll(H3270 *hSession, LIB3270_IO_FLAG flag, v } static int unsecure_network_non_blocking(H3270 *hSession, const unsigned char on) { - - if(hSession->network.context->sock < 0) - return 0; - -#ifdef WIN32 - - WSASetLastError(0); - u_long iMode= on ? 1 : 0; - - if(ioctlsocket(hSession->network.context->sock,FIONBIO,&iMode)) - { - lib3270_popup_dialog( hSession, - LIB3270_NOTIFY_ERROR, - _( "Connection error" ), - _( "ioctlsocket(FIONBIO) failed." ), - "%s", lib3270_win32_strerror(GetLastError())); - return -1; - } - -#else - - int f; - - if ((f = fcntl(hSession->network.context->sock, F_GETFL, 0)) == -1) - { - lib3270_popup_dialog( hSession, - LIB3270_NOTIFY_ERROR, - _( "Socket error" ), - _( "fcntl() error when getting socket state." ), - _( "%s" ), strerror(errno) - ); - - return -1; - } - - if (on) - f |= O_NDELAY; - else - f &= ~O_NDELAY; - - if (fcntl(hSession->network.context->sock, F_SETFL, f) < 0) - { - lib3270_popup_dialog( hSession, - LIB3270_NOTIFY_ERROR, - _( "Socket error" ), - on ? _( "Can't set socket to blocking mode." ) : _( "Can't set socket to non blocking mode" ), - _( "%s" ), strerror(errno) - ); - return -1; - } - -#endif - - debug("Socket %d is now %s",hSession->network.context->sock,(on ? "Non Blocking" : "Blocking")); - - return 0; + return lib3270_socket_set_non_blocking(hSession, hSession->network.context->sock, on); } static int unsecure_network_is_connected(const H3270 *hSession) { diff --git a/src/network_modules/openssl/main.c b/src/network_modules/openssl/main.c index 0e990d3..ce0a506 100644 --- a/src/network_modules/openssl/main.c +++ b/src/network_modules/openssl/main.c @@ -79,45 +79,102 @@ static int openssl_network_disconnect(H3270 *hSession) { ssize_t openssl_network_send(H3270 *hSession, const void *buffer, size_t length) { -/* - if(hSession->network.context->sock < 0) { - return -(errno = ENOTCONN); + int rc = SSL_write(hSession->network.context->con, (const char *) buffer, length); + if(rc > 0) + return rc; + + // https://www.openssl.org/docs/man1.0.2/man3/SSL_get_error.html + int ssl_error = SSL_get_error(hSession->network.context->con, rc); + switch(ssl_error) { + case SSL_ERROR_ZERO_RETURN: + + trace_ssl(hSession,"%s","The secure connection has been closed cleanly"); + + lib3270_popup_dialog( + hSession, + LIB3270_NOTIFY_ERROR, + NULL, + _("Disconnected from host"), + "%s", + _("The secure connection has been closed cleanly.") + ); + return 0; + + case SSL_ERROR_WANT_READ: + case SSL_ERROR_WANT_X509_LOOKUP: + return -EWOULDBLOCK; // Force a new loop. + + case SSL_ERROR_SYSCALL: + return lib3270_socket_send_failed(hSession); + } - ssize_t bytes = SSL_write(hSession->network.context->con, (const char *) buffer, length); + // Build error message. + char err_buf[120]; + (void) ERR_error_string(ssl_error, err_buf); + trace_dsn(hSession,"RCVD SSL_write error %d (%s)\n", ssl_error, err_buf); - debug("%s bytes=%d",__FUNCTION__,(int) bytes); + lib3270_autoptr(char) body = lib3270_strdup_printf(_("The SSL error message was %s"), err_buf); - if(bytes >= 0) - return bytes; + LIB3270_POPUP popup = { + .summary = _("Error writing to host"), + .body = body + }; - // SSL Write has failed, using SSL_get_error to identify what has happened. - int error = SSL_get_error(hSession->network.context->con,(int) bytes); + lib3270_popup(hSession,&popup,0); - if(error == SSL_ERROR_SYSCALL) { + return -1; - #error Use errno! +} - return -1; +static ssize_t openssl_network_recv(H3270 *hSession, void *buf, size_t len) { + + int rc = SSL_read(hSession->network.context->con, (char *) buf, len); + if(rc > 0) { + return rc; } - // Not a system error, inspects the result. + // https://www.openssl.org/docs/man1.0.2/man3/SSL_get_error.html + int ssl_error = SSL_get_error(hSession->network.context->con, rc); + switch(ssl_error) { + case SSL_ERROR_ZERO_RETURN: + trace_ssl(hSession,"%s","The secure connection has been closed cleanly"); + lib3270_popup_dialog( + hSession, + LIB3270_NOTIFY_ERROR, + NULL, + _("Disconnected from host"), + "%s", + _("The secure connection has been closed cleanly.") + ); + return 0; - lib3270_popup(hSession,&popup,0); + case SSL_ERROR_WANT_READ: + case SSL_ERROR_WANT_X509_LOOKUP: + return -EWOULDBLOCK; // Force a new loop. - return -1; -*/ + case SSL_ERROR_SYSCALL: + return lib3270_socket_recv_failed(hSession); -} + } -static ssize_t openssl_network_recv(H3270 *hSession, void *buf, size_t len) { + // Build error message. + char err_buf[120]; + (void) ERR_error_string(ssl_error, err_buf); + trace_dsn(hSession,"RCVD SSL_read error %d (%s)\n", ssl_error, err_buf); -// return SSL_read(hSession->network.context->con, (char *) buf, len); + lib3270_autoptr(char) body = lib3270_strdup_printf(_("The SSL error message was %s"), err_buf); + LIB3270_POPUP popup = { + .summary = _("Error reading from host"), + .body = body + }; + lib3270_popup(hSession,&popup,0); + return -1; } static int openssl_network_getsockname(const H3270 *hSession, struct sockaddr *addr, socklen_t *addrlen) { @@ -125,22 +182,23 @@ static int openssl_network_getsockname(const H3270 *hSession, struct sockaddr *a } static void * openssl_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); } static int openssl_network_non_blocking(H3270 *hSession, const unsigned char on) { - + return lib3270_socket_set_non_blocking(hSession, hSession->network.context->sock, on); } -static int openssl_network_is_connected(H3270 *hSession) { - +static int openssl_network_is_connected(const H3270 *hSession) { + return hSession->network.context->sock > 0; } static int openssl_network_setsockopt(H3270 *hSession, int level, int optname, const void *optval, size_t optlen) { - + return setsockopt(hSession->network.context->sock, level, optname, optval, optlen); } static int openssl_network_getsockopt(H3270 *hSession, int level, int optname, void *optval, socklen_t *optlen) { + return getsockopt(hSession->network.context->sock, level, optname, optval, optlen); } static int openssl_network_init(H3270 *hSession) { @@ -151,8 +209,6 @@ static int openssl_network_init(H3270 *hSession) { if(!ctx_context) return -1; - LIB3270_NET_CONTEXT * context = hSession->network.context; - return 0; } @@ -202,11 +258,13 @@ static int openssl_network_connect(H3270 *hSession, LIB3270_NETWORK_STATE *state hSession->ssl.host = 1; context->sock = lib3270_network_connect(hSession, state); + debug("%s: sock=%d",__FUNCTION__,context->sock); + return (context->sock < 0 ? -1 : 0); } -void lib3270_set_openssl_network_module(H3270 *hSession) { +void lib3270_set_libssl_network_module(H3270 *hSession) { static const LIB3270_NET_MODULE module = { .name = "tn3270s", @@ -244,7 +302,7 @@ void lib3270_set_openssl_network_module(H3270 *hSession) { int lib3270_activate_ssl_network_module(H3270 *hSession, int sock) { - lib3270_set_openssl_network_module(hSession); + lib3270_set_libssl_network_module(hSession); int rc = openssl_network_init(hSession); @@ -261,3 +319,5 @@ void lib3270_openssl_crl_free(LIB3270_NET_CONTEXT *context) { } } + + diff --git a/src/network_modules/select.c b/src/network_modules/select.c index f54ba85..539a3af 100644 --- a/src/network_modules/select.c +++ b/src/network_modules/select.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 unsecure.c e possui - linhas de código. + * Este programa está nomeado como - e possui - linhas de código. * * Contatos: * @@ -41,14 +41,24 @@ /*--[ Implement ]------------------------------------------------------------------------------------*/ - const char * lib3270_set_network_module_from_url(H3270 *hSession, const char *url) { + char * lib3270_set_network_module_from_url(H3270 *hSession, const char *url) { static const struct { const char *scheme; ///< @brief URL scheme for module. void (*activate)(H3270 *hSession); ///< @brief Selection method. } modules[] = { - { "tn3270://", lib3270_set_default_network_module }, + { "tn3270://", lib3270_set_default_network_module }, + +#ifdef HAVE_LIBSSL + + { "tn3270s://", lib3270_set_libssl_network_module }, + + // Compatibility schemes. + { "L://", lib3270_set_libssl_network_module }, + { "L:", lib3270_set_libssl_network_module }, + +#endif // HAVE_LIBSSL }; diff --git a/src/network_modules/tools.c b/src/network_modules/tools.c new file mode 100644 index 0000000..e30ecf9 --- /dev/null +++ b/src/network_modules/tools.c @@ -0,0 +1,214 @@ +/* + * "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 unsecure.c 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 Common methods for send/recv errors. + * + */ + + #include + #include + #include + #include + #include + #include + +/*--[ Implement ]------------------------------------------------------------------------------------*/ + + int lib3270_socket_recv_failed(H3270 *hSession) { + +#ifdef _WIN32 + + int wsaError = WSAGetLastError(); + + // EWOULDBLOCK & EAGAIN should return directly. + if(wsaError == WSAEWOULDBLOCK) + return -EWOULDBLOCK; + + if(wsaError == WSAEINPROGRESS) + return -EAGAIN; + + int rc = -wsaError; + + LIB3270_POPUP popup = { + .name = "RecvFailed", + .type = LIB3270_NOTIFY_ERROR, + .summary = _("Error receiving data from host"), + } + + // TODO: Translate WSA Error, update message body. + + lib3270_popup(hSession,&popup,0); + +#else + + // EWOULDBLOCK & EAGAIN should return directly. + if(errno == EWOULDBLOCK || errno == EAGAIN) + return -errno; + + // Network error, notify user + int rc = -errno; + + lib3270_autoptr(char) body = lib3270_strdup_printf( + _("The system error code was %d (%s)"), + errno, + strerror(errno) + ); + + LIB3270_POPUP popup = { + .name = "RecvFailed", + .type = LIB3270_NOTIFY_ERROR, + .summary = _("Error receiving data from host"), + .body = body + }; + + lib3270_popup(hSession,&popup,0); + +#endif // _WIN32 + + return rc; + + } + + int lib3270_socket_send_failed(H3270 *hSession) { + + #ifdef _WIN32 + + int rc = WSAGetLastError(); + + #error Have work to do. + + #else + + int rc = errno; + + 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) + ); + + } + + + #endif // _WIN32 + + return -1; + + } + +int lib3270_socket_set_non_blocking(H3270 *hSession, int sock, const unsigned char on) { + + if(sock < 0) + return 0; + +#ifdef WIN32 + + WSASetLastError(0); + u_long iMode= on ? 1 : 0; + + if(ioctlsocket(sock,FIONBIO,&iMode)) + { + lib3270_popup_dialog( hSession, + LIB3270_NOTIFY_ERROR, + _( "Connection error" ), + _( "ioctlsocket(FIONBIO) failed." ), + "%s", lib3270_win32_strerror(GetLastError())); + return -1; + } + +#else + + int f; + + if ((f = fcntl(sock, F_GETFL, 0)) == -1) + { + lib3270_popup_dialog( hSession, + LIB3270_NOTIFY_ERROR, + _( "Socket error" ), + _( "fcntl() error when getting socket state." ), + _( "%s" ), strerror(errno) + ); + + return -1; + } + + if (on) + f |= O_NDELAY; + else + f &= ~O_NDELAY; + + if (fcntl(sock, F_SETFL, f) < 0) + { + lib3270_popup_dialog( hSession, + LIB3270_NOTIFY_ERROR, + _( "Socket error" ), + on ? _( "Can't set socket to blocking mode." ) : _( "Can't set socket to non blocking mode" ), + _( "%s" ), strerror(errno) + ); + return -1; + } + +#endif + + debug("Socket %d is now %s",sock,(on ? "Non Blocking" : "Blocking")); + + return 0; + +} diff --git a/src/network_modules/translate.c b/src/network_modules/translate.c deleted file mode 100644 index 995ffa7..0000000 --- a/src/network_modules/translate.c +++ /dev/null @@ -1,151 +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 ', 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 unsecure.c 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 Common methods for send/recv errors. - * - */ - - #include - #include - #include - #include - #include - -/*--[ Implement ]------------------------------------------------------------------------------------*/ - - int lib3270_network_recv_failed(H3270 *hSession) { - -#ifdef _WIN32 - - int wsaError = WSAGetLastError(); - - // EWOULDBLOCK & EAGAIN should return directly. - if(wsaError == WSAEWOULDBLOCK) - return -EWOULDBLOCK; - - if(wsaError == WSAEINPROGRESS) - return -EAGAIN; - - int rc = -wsaError; - - LIB3270_POPUP popup = { - .name = "RecvFailed", - .type = LIB3270_NOTIFY_ERROR, - .summary = _("Error receiving data from host"), - } - - // TODO: Translate WSA Error, update message body. - - lib3270_popup(hSession,&popup,0); - -#else - - // EWOULDBLOCK & EAGAIN should return directly. - if(errno == EWOULDBLOCK || errno == EAGAIN) - return -errno; - - // Network error, notify user - int rc = -errno; - - lib3270_autoptr(char) body = lib3270_strdup_printf( - _("The system error code was %d (%s)"), - errno, - strerror(errno) - ); - - LIB3270_POPUP popup = { - .name = "RecvFailed", - .type = LIB3270_NOTIFY_ERROR, - .summary = _("Error receiving data from host"), - .body = body - }; - - lib3270_popup(hSession,&popup,0); - -#endif // _WIN32 - - return rc; - - } - - int lib3270_network_send_failed(H3270 *hSession) { - - #ifdef _WIN32 - - int rc = WSAGetLastError(); - - #error Have work to do. - - #else - - int rc = errno; - - 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) - ); - - } - - - #endif // _WIN32 - - } -- libgit2 0.21.2