$OpenBSD: patch-arch_network_tcp_c,v 1.3 2020/08/24 21:08:02 bluhm Exp $

https://github.com/open62541/open62541/commit/30ac5ddd892e6ce82bef4de7890f06854aca9736

https://github.com/open62541/open62541/commit/1654d021012b93ff669c022499fd80c47a73e72e

https://github.com/open62541/open62541/commit/f9ceec7be7940495cf2ee091bed1bb5acec74551

Index: arch/network_tcp.c
--- arch/network_tcp.c.orig
+++ arch/network_tcp.c
@@ -339,11 +339,18 @@ addServerSocket(ServerNetworkLayerTCP *layer, struct a
 
 static UA_StatusCode
 ServerNetworkLayerTCP_start(UA_ServerNetworkLayer *nl, const UA_String *customHostname) {
-  UA_initialize_architecture_network();
+    UA_initialize_architecture_network();
 
     ServerNetworkLayerTCP *layer = (ServerNetworkLayerTCP *)nl->handle;
 
     /* Get addrinfo of the server and create server sockets */
+    char hostname[512];
+    if(customHostname->length) {
+        if(customHostname->length >= sizeof(hostname))
+            return UA_STATUSCODE_BADOUTOFMEMORY;
+        memcpy(hostname, customHostname->data, customHostname->length);
+        hostname[customHostname->length] = '\0';
+    }
     char portno[6];
     UA_snprintf(portno, 6, "%d", layer->port);
     struct addrinfo hints, *res;
@@ -352,7 +359,8 @@ ServerNetworkLayerTCP_start(UA_ServerNetworkLayer *nl,
     hints.ai_socktype = SOCK_STREAM;
     hints.ai_flags = AI_PASSIVE;
     hints.ai_protocol = IPPROTO_TCP;
-    if(UA_getaddrinfo(NULL, portno, &hints, &res) != 0)
+    if(UA_getaddrinfo(customHostname->length ? hostname : NULL,
+        portno, &hints, &res) != 0)
         return UA_STATUSCODE_BADINTERNALERROR;
 
     /* There might be serveral addrinfos (for different network cards,
@@ -442,7 +450,7 @@ ServerNetworkLayerTCP_listen(UA_ServerNetworkLayer *nl
 
         struct sockaddr_storage remote;
         socklen_t remote_size = sizeof(remote);
-        UA_SOCKET newsockfd = UA_accept((UA_SOCKET)layer->serverSockets[i],
+        UA_SOCKET newsockfd = UA_accept(layer->serverSockets[i],
                                   (struct sockaddr*)&remote, &remote_size);
         if(newsockfd == UA_INVALID_SOCKET)
             continue;
@@ -609,7 +617,6 @@ UA_StatusCode UA_ClientConnectionTCP_poll(UA_Client *c
                     (TCPClientConnection*) connection->handle;
 
     UA_DateTime connStart = UA_DateTime_nowMonotonic();
-    UA_SOCKET clientsockfd = connection->sockfd;
 
     UA_ClientConfig *config = UA_Client_getConfig(client);
 
@@ -631,22 +638,22 @@ UA_StatusCode UA_ClientConnectionTCP_poll(UA_Client *c
     /* Thus use a loop and retry until timeout is reached */
 
     /* Get a socket */
-    if(clientsockfd <= 0) {
-        clientsockfd = UA_socket(tcpConnection->server->ai_family,
+    if(connection->sockfd == UA_INVALID_SOCKET) {
+        connection->sockfd = UA_socket(tcpConnection->server->ai_family,
                                  tcpConnection->server->ai_socktype,
                                  tcpConnection->server->ai_protocol);
-        connection->sockfd = (UA_Int32)clientsockfd; /* cast for win32 */
+        if(connection->sockfd == UA_INVALID_SOCKET) {
+            UA_LOG_WARNING(&config->logger, UA_LOGCATEGORY_NETWORK,
+                    "Could not create client socket: %s", strerror(UA_ERRNO));
+            ClientNetworkLayerTCP_close(connection);
+            return UA_STATUSCODE_BADDISCONNECT;
+        }
     }
 
-    if(clientsockfd == UA_INVALID_SOCKET) {
-        UA_LOG_WARNING(&config->logger, UA_LOGCATEGORY_NETWORK,
-                       "Could not create client socket: %s", strerror(UA_ERRNO));
-        ClientNetworkLayerTCP_close(connection);
-        return UA_STATUSCODE_BADDISCONNECT;
-    }
 
+
     /* Non blocking connect to be able to timeout */
-    if(UA_socket_set_nonblocking(clientsockfd) != UA_STATUSCODE_GOOD) {
+    if(UA_socket_set_nonblocking(connection->sockfd) != UA_STATUSCODE_GOOD) {
         UA_LOG_WARNING(&config->logger, UA_LOGCATEGORY_NETWORK,
                        "Could not set the client socket to nonblocking");
         ClientNetworkLayerTCP_close(connection);
@@ -654,7 +661,7 @@ UA_StatusCode UA_ClientConnectionTCP_poll(UA_Client *c
     }
 
     /* Non blocking connect */
-    int error = UA_connect(clientsockfd, tcpConnection->server->ai_addr,
+    int error = UA_connect(connection->sockfd, tcpConnection->server->ai_addr,
                     tcpConnection->server->ai_addrlen);
 
     if ((error == -1) && (UA_ERRNO != UA_ERR_CONNECTION_PROGRESS)) {
@@ -686,7 +693,7 @@ UA_StatusCode UA_ClientConnectionTCP_poll(UA_Client *c
                 break;
 
             _os_sleep(&time,&sig);
-            error = connect(clientsockfd, tcpConnection->server->ai_addr,
+            error = connect(connection->sockfd, tcpConnection->server->ai_addr,
                         tcpConnection->server->ai_addrlen);
             if ((error == -1 && UA_ERRNO == EISCONN) || (error == 0))
                 resultsize = 1;
@@ -697,26 +704,25 @@ UA_StatusCode UA_ClientConnectionTCP_poll(UA_Client *c
 #else
         fd_set fdset;
         FD_ZERO(&fdset);
-        UA_fd_set(clientsockfd, &fdset);
+        UA_fd_set(connection->sockfd, &fdset);
         UA_UInt32 timeout_usec = (tcpConnection->timeout - timeSinceStart)
                         * 1000;
         struct timeval tmptv = { (long int) (timeout_usec / 1000000),
                         (int) (timeout_usec % 1000000) };
 
-        int resultsize = UA_select((UA_Int32) (clientsockfd + 1), NULL, &fdset,
-        NULL, &tmptv);
+        int resultsize = UA_select((UA_Int32) (connection->sockfd + 1), NULL,
+                               &fdset, NULL, &tmptv);
 #endif
         if (resultsize == 1) {
             /* Windows does not have any getsockopt equivalent and it is not needed there */
 #ifdef _WIN32
-            connection->sockfd = clientsockfd;
             connection->state = UA_CONNECTION_ESTABLISHED;
             return UA_STATUSCODE_GOOD;
 #else
             OPTVAL_TYPE so_error;
             socklen_t len = sizeof so_error;
 
-            int ret = UA_getsockopt(clientsockfd, SOL_SOCKET, SO_ERROR, &so_error,
+            int ret = UA_getsockopt(connection->sockfd, SOL_SOCKET, SO_ERROR, &so_error,
                             &len);
 
             if (ret != 0 || so_error != 0) {
@@ -765,6 +771,7 @@ UA_ClientConnectionTCP_init(UA_ConnectionConfig config
 
     connection.state = UA_CONNECTION_OPENING;
     connection.config = config;
+    connection.sockfd = UA_INVALID_SOCKET;
     connection.send = connection_write;
     connection.recv = connection_recv;
     connection.close = ClientNetworkLayerTCP_close;
@@ -775,6 +782,7 @@ UA_ClientConnectionTCP_init(UA_ConnectionConfig config
 
     TCPClientConnection *tcpClientConnection = (TCPClientConnection*) UA_malloc(
                     sizeof(TCPClientConnection));
+    memset(tcpClientConnection, 0, sizeof(TCPClientConnection));
     connection.handle = (void*) tcpClientConnection;
     tcpClientConnection->timeout = timeout;
     UA_String hostnameString = UA_STRING_NULL;
@@ -826,6 +834,7 @@ UA_ClientConnectionTCP(UA_ConnectionConfig config, con
     memset(&connection, 0, sizeof(UA_Connection));
     connection.state = UA_CONNECTION_CLOSED;
     connection.config = config;
+    connection.sockfd = UA_INVALID_SOCKET;
     connection.send = connection_write;
     connection.recv = connection_recv;
     connection.close = ClientNetworkLayerTCP_close;
@@ -874,17 +883,16 @@ UA_ClientConnectionTCP(UA_ConnectionConfig config, con
     UA_Boolean connected = false;
     UA_DateTime dtTimeout = timeout * UA_DATETIME_MSEC;
     UA_DateTime connStart = UA_DateTime_nowMonotonic();
-    UA_SOCKET clientsockfd;
 
     /* On linux connect may immediately return with ECONNREFUSED but we still
      * want to try to connect. So use a loop and retry until timeout is
      * reached. */
     do {
         /* Get a socket */
-        clientsockfd = UA_socket(server->ai_family,
+        connection.sockfd = UA_socket(server->ai_family,
                               server->ai_socktype,
                               server->ai_protocol);
-        if(clientsockfd == UA_INVALID_SOCKET) {
+        if(connection.sockfd == UA_INVALID_SOCKET) {
             UA_LOG_SOCKET_ERRNO_WRAP(UA_LOG_WARNING(logger, UA_LOGCATEGORY_NETWORK,
                                                     "Could not create client socket: %s", errno_str));
             UA_freeaddrinfo(server);
@@ -894,10 +902,9 @@ UA_ClientConnectionTCP(UA_ConnectionConfig config, con
         connection.state = UA_CONNECTION_OPENING;
 
         /* Connect to the server */
-        connection.sockfd = clientsockfd;
 
         /* Non blocking connect to be able to timeout */
-        if (UA_socket_set_nonblocking(clientsockfd) != UA_STATUSCODE_GOOD) {
+        if (UA_socket_set_nonblocking(connection.sockfd) != UA_STATUSCODE_GOOD) {
             UA_LOG_WARNING(logger, UA_LOGCATEGORY_NETWORK,
                            "Could not set the client socket to nonblocking");
             ClientNetworkLayerTCP_close(&connection);
@@ -906,7 +913,8 @@ UA_ClientConnectionTCP(UA_ConnectionConfig config, con
         }
 
         /* Non blocking connect */
-        error = UA_connect(clientsockfd, server->ai_addr, (socklen_t)server->ai_addrlen);
+        error = UA_connect(connection.sockfd, server->ai_addr,
+		(socklen_t) server->ai_addrlen);
 
         if ((error == -1) && (UA_ERRNO != UA_ERR_CONNECTION_PROGRESS)) {
             ClientNetworkLayerTCP_close(&connection);
@@ -940,7 +948,7 @@ UA_ClientConnectionTCP(UA_ConnectionConfig config, con
                     break;
 
                 _os_sleep(&time,&sig);
-                error = connect(clientsockfd, server->ai_addr, server->ai_addrlen);
+                error = connect(connection.sockfd, server->ai_addr, server->ai_addrlen);
                 if ((error == -1 && UA_ERRNO == EISCONN) || (error == 0))
                     resultsize = 1;
                 if (error == -1 && UA_ERRNO != EALREADY && UA_ERRNO != EINPROGRESS)
@@ -950,12 +958,13 @@ UA_ClientConnectionTCP(UA_ConnectionConfig config, con
 #else
             fd_set fdset;
             FD_ZERO(&fdset);
-            UA_fd_set(clientsockfd, &fdset);
+            UA_fd_set(connection.sockfd, &fdset);
             UA_DateTime timeout_usec = (dtTimeout - timeSinceStart) / UA_DATETIME_USEC;
             struct timeval tmptv = {(long int) (timeout_usec / 1000000),
                                     (int) (timeout_usec % 1000000)};
 
-            int resultsize = UA_select((UA_Int32)(clientsockfd + 1), NULL, &fdset, NULL, &tmptv);
+            int resultsize = UA_select((UA_Int32)(connection.sockfd + 1), NULL,
+                    &fdset, NULL, &tmptv);
 #endif
 
             if(resultsize == 1) {
@@ -968,7 +977,7 @@ UA_ClientConnectionTCP(UA_ConnectionConfig config, con
                 OPTVAL_TYPE so_error;
                 socklen_t len = sizeof so_error;
 
-                int ret = UA_getsockopt(clientsockfd, SOL_SOCKET, SO_ERROR, &so_error, &len);
+                int ret = UA_getsockopt(connection.sockfd, SOL_SOCKET, SO_ERROR, &so_error, &len);
 
                 if (ret != 0 || so_error != 0) {
                     /* on connection refused we should still try to connect */
@@ -1013,7 +1022,7 @@ UA_ClientConnectionTCP(UA_ConnectionConfig config, con
 
 
     /* We are connected. Reset socket to blocking */
-    if(UA_socket_set_blocking(clientsockfd) != UA_STATUSCODE_GOOD) {
+    if(UA_socket_set_blocking(connection.sockfd) != UA_STATUSCODE_GOOD) {
         UA_LOG_WARNING(logger, UA_LOGCATEGORY_NETWORK,
                        "Could not set the client socket to blocking");
         ClientNetworkLayerTCP_close(&connection);
