Index: src/vortex_connection.c =================================================================== --- src/vortex_connection.c (revision 3338) +++ src/vortex_connection.c (working copy) @@ -28,9 +28,9 @@ * * Postal address: * Advanced Software Production Line, S.L. - * C/ Antonio Suarez Nº 10, + * C/ Antonio Suarez N∫ 10, * Edificio Alius A, Despacho 102 - * Alcalá de Henares 28802 (Madrid) + * Alcal· de Henares 28802 (Madrid) * Spain * * Email address: @@ -108,6 +108,11 @@ char * port; /** + * @brief Local port number used by an outgoing connection (optional) + */ + uint16_t localPort; + + /** * @brief Allows to hold and report current connection status. */ bool is_connected; @@ -1151,6 +1156,47 @@ } /** + * @internal wrapper around "bind" system call, which also sets SO_REUSEADDR option. + * + * @param sock The socket to bind. + * @param addr The raw 32-bit address to bind to (network byte-order) + * @param port The port number (host byte-order) + * + * @return 0 on success, -1 on failure + */ +int vortex_bind (int sock, + in_addr_t addr, + uint16_t port, + bool reusePort ) +{ + struct sockaddr_in saddr; + int result; +#if defined(AXL_OS_WIN32) + BOOL unit = true; +#else + int unit = 1; +#endif + result = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*)&unit, sizeof (unit)); + + if( result==0 && reusePort ) { + // If supported (BSD and OS X), also set REUSEPORT, to allow simultaneous listening and + // outgoing connection on the same port. (This is used in NAT hole-punching.) +#ifdef SO_REUSEPORT + result = setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (void*)&unit, sizeof (unit)); +#endif + } + + if( result < 0 ) + return result; + + memset(&saddr, 0, sizeof(saddr)); + saddr.sin_family = AF_INET; + saddr.sin_addr.s_addr = addr; + saddr.sin_port = htons(port); + return bind(sock,(struct sockaddr*)&saddr,sizeof(saddr)); +} + +/** * @internal Function to perform a wait operation on the provided * socket, assuming the wait operation will be performed on a * nonblocking socket. The function configure the socket to be @@ -1302,6 +1348,16 @@ goto __vortex_connection_new_finalize; } + /* bind to a local port number, if the client requested it */ + if (connection->localPort > 0) { + if( vortex_bind(connection->session,INADDR_ANY,connection->localPort,true) < 0 ) { + connection->message = axl_strdup_printf("unable to bind socket to local port: %s (%i)", + strerror(errno),errno); + vortex_log (LOG_DOMAIN, VORTEX_LEVEL_CRITICAL, "%s",connection->message); + goto __vortex_connection_new_finalize; + } + } + /* prepare socket configuration to operate using TCP/IP * socket */ memset(&saddr, 0, sizeof(saddr)); @@ -1470,9 +1526,24 @@ /* seems that current Vortex Library have TLS * profile built-in support and auto TLS is * activated */ - connection = vortex_tls_start_negociation_sync (connection, + //jpa: Patch: Don't lose the VortexConnection if negotiation fails! + VortexStatus status; + char *message = NULL; + vortex_connection_ref(connection, "__vortex_connection_new"); + VortexConnection *newConnection = vortex_tls_start_negociation_sync (connection, ctx->connection_auto_tls_server_name, - NULL, NULL); + &status,&message); + if (!newConnection) { + __vortex_connection_set_not_connected (connection, message); + if (connection->message) + axl_free (connection->message); + connection->message = axl_strdup (message); + goto __vortex_connection_new_invoke_caller; + } + vortex_connection_unref(connection, "__vortex_connection_new"); + connection = newConnection; + //jpa: END + if (!vortex_connection_is_ok (connection, false)) { goto __vortex_connection_new_invoke_caller; } @@ -1612,17 +1683,45 @@ VortexConnectionNew on_connected, axlPointer user_data) { + return vortex_connection_new2(host,(uint16_t)strtod(port,NULL),0,on_connected,user_data); +} +/** + * @brief Allows to create a new BEEP session (connection) to the given host:port, + * with the port specified as an integer, and optionally specifying a local port number. + * + * See vortex_connection_new for more information. + * + * @param host The remote peer to connect to. + * @param port The peer's port to connect to. + * @param localPort The local port number to use, or zero if you don't care (the usual case). + * @param on_connected Optional handler to process connection new status. + * @param user_data Optional handler to process connection new status + * + * @return A newly created \ref VortexConnection if called in a + * blocking manner, or NULL if you provide the on_connected handler. + */ +VortexConnection * vortex_connection_new2 (const char * host, + uint16_t port, + uint16_t localPort, + VortexConnectionNew on_connected, + axlPointer user_data) +{ + VortexConnectionNewData * data; v_return_val_if_fail (host, NULL); v_return_val_if_fail (port, NULL); + + char portStr[10]; + sprintf(portStr,"%hu",port); data = axl_new (VortexConnectionNewData, 1); data->connection = axl_new (VortexConnection, 1); data->connection->id = __vortex_connection_get_next_id (); data->connection->host = axl_strdup (host); - data->connection->port = axl_strdup (port); + data->connection->port = axl_strdup (portStr); + data->connection->localPort = localPort; data->connection->channels = vortex_hash_new_full (axl_hash_int, axl_hash_equal_int, NULL, (axlDestroyFunc) vortex_channel_unref); Index: src/vortex_connection.h =================================================================== --- src/vortex_connection.h (revision 3338) +++ src/vortex_connection.h (working copy) @@ -70,6 +70,12 @@ VortexConnectionNew on_connected, axlPointer user_data); +VortexConnection * vortex_connection_new2 (const char * host, + uint16_t port, + uint16_t localPort, + VortexConnectionNew on_connected, + axlPointer user_data); + bool vortex_connection_reconnect (VortexConnection * connection, VortexConnectionNew on_connected, axlPointer user_data); @@ -312,6 +318,11 @@ bool __vortex_connection_parse_greetings (VortexConnection * connection, VortexFrame * frame); +int vortex_bind (int sock, + in_addr_t addr, + uint16_t port, + bool reusePort); + #endif /* @} */ Index: src/vortex_listener.c =================================================================== --- src/vortex_listener.c (revision 3338) +++ src/vortex_listener.c (working copy) @@ -370,14 +370,11 @@ VortexCtx * ctx = vortex_ctx_get (); struct hostent * he; struct in_addr * haddr; - struct sockaddr_in saddr; struct sockaddr_in sin; VORTEX_SOCKET fd; #if defined(AXL_OS_WIN32) - BOOL unit = true; int sin_size = sizeof (sin); #else - int unit = 1; socklen_t sin_size = sizeof (sin); #endif char * host = data->host; @@ -407,18 +404,7 @@ goto error; } -#if defined(AXL_OS_WIN32) - setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&unit, sizeof(BOOL)); -#else - setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &unit, sizeof (unit)); -#endif - - memset(&saddr, 0, sizeof(struct sockaddr_in)); - saddr.sin_family = AF_INET; - saddr.sin_port = htons(int_port); - memcpy(&saddr.sin_addr, haddr, sizeof(struct in_addr)); - - if (bind(fd, (struct sockaddr *)&saddr, sizeof (struct sockaddr_in)) == VORTEX_SOCKET_ERROR) { + if (vortex_bind(fd,haddr->s_addr,int_port,false) == VORTEX_SOCKET_ERROR ) { vortex_close_socket (fd); message = "unable to bind address"; goto error;