[PATCH v2 3/7] server: Implement IOCTL_AFD_GETSOCKNAME.

Zebediah Figura z.figura12 at gmail.com
Tue Jun 15 23:13:28 CDT 2021


Signed-off-by: Zebediah Figura <z.figura12 at gmail.com>
---
 dlls/ntdll/unix/socket.c |  6 +++
 include/wine/afd.h       |  1 +
 server/sock.c            | 83 ++++++++++++++++++++++++++++++++++++++--
 3 files changed, 87 insertions(+), 3 deletions(-)

diff --git a/dlls/ntdll/unix/socket.c b/dlls/ntdll/unix/socket.c
index 0d77e417148..02700d37d6a 100644
--- a/dlls/ntdll/unix/socket.c
+++ b/dlls/ntdll/unix/socket.c
@@ -1167,6 +1167,12 @@ NTSTATUS sock_ioctl( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc
             break;
         }
 
+        case IOCTL_AFD_GETSOCKNAME:
+            if (in_size) FIXME( "unexpected input size %u\n", in_size );
+
+            status = STATUS_BAD_DEVICE_TYPE;
+            break;
+
         case IOCTL_AFD_LISTEN:
         {
             const struct afd_listen_params *params = in_buffer;
diff --git a/include/wine/afd.h b/include/wine/afd.h
index 87da44ecca7..04468363673 100644
--- a/include/wine/afd.h
+++ b/include/wine/afd.h
@@ -36,6 +36,7 @@
 #define IOCTL_AFD_LISTEN                    CTL_CODE(FILE_DEVICE_BEEP, 0x802, METHOD_NEITHER,  FILE_ANY_ACCESS)
 #define IOCTL_AFD_RECV                      CTL_CODE(FILE_DEVICE_BEEP, 0x805, METHOD_NEITHER,  FILE_ANY_ACCESS)
 #define IOCTL_AFD_POLL                      CTL_CODE(FILE_DEVICE_BEEP, 0x809, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_AFD_GETSOCKNAME               CTL_CODE(FILE_DEVICE_BEEP, 0x80b, METHOD_NEITHER,  FILE_ANY_ACCESS)
 #define IOCTL_AFD_EVENT_SELECT              CTL_CODE(FILE_DEVICE_BEEP, 0x821, METHOD_NEITHER,  FILE_ANY_ACCESS)
 #define IOCTL_AFD_GET_EVENTS                CTL_CODE(FILE_DEVICE_BEEP, 0x822, METHOD_NEITHER,  FILE_ANY_ACCESS)
 
diff --git a/server/sock.c b/server/sock.c
index 425c07566ac..e5acf585dcc 100644
--- a/server/sock.c
+++ b/server/sock.c
@@ -109,6 +109,15 @@
 #define IP_UNICAST_IF 50
 #endif
 
+union win_sockaddr
+{
+    struct WS_sockaddr addr;
+    struct WS_sockaddr_in in;
+    struct WS_sockaddr_in6 in6;
+    struct WS_sockaddr_ipx ipx;
+    SOCKADDR_IRDA irda;
+};
+
 static struct list poll_list = LIST_INIT( poll_list );
 
 struct poll_req
@@ -194,10 +203,13 @@ struct sock
     struct list         accept_list; /* list of pending accept requests */
     struct accept_req  *accept_recv_req; /* pending accept-into request which will recv on this socket */
     struct connect_req *connect_req; /* pending connection request */
+    union win_sockaddr  addr;        /* socket name */
+    int                 addr_len;    /* socket name length */
     unsigned int        rd_shutdown : 1; /* is the read end shut down? */
     unsigned int        wr_shutdown : 1; /* is the write end shut down? */
     unsigned int        wr_shutdown_pending : 1; /* is a write shutdown pending? */
     unsigned int        nonblocking : 1; /* is the socket nonblocking? */
+    unsigned int        bound : 1;   /* is the socket bound? */
 };
 
 static void sock_dump( struct object *obj, int verbose );
@@ -1365,10 +1377,13 @@ static struct sock *create_socket(void)
     sock->ifchange_obj = NULL;
     sock->accept_recv_req = NULL;
     sock->connect_req = NULL;
+    memset( &sock->addr, 0, sizeof(sock->addr) );
+    sock->addr_len = 0;
     sock->rd_shutdown = 0;
     sock->wr_shutdown = 0;
     sock->wr_shutdown_pending = 0;
     sock->nonblocking = 0;
+    sock->bound = 0;
     init_async_queue( &sock->read_q );
     init_async_queue( &sock->write_q );
     init_async_queue( &sock->ifchange_q );
@@ -1583,6 +1598,9 @@ static struct sock *accept_socket( struct sock *sock )
     }
     else
     {
+        union unix_sockaddr unix_addr;
+        socklen_t unix_len;
+
         if ((acceptfd = accept_new_fd( sock )) == -1) return NULL;
         if (!(acceptsock = create_socket()))
         {
@@ -1592,6 +1610,7 @@ static struct sock *accept_socket( struct sock *sock )
 
         /* newly created socket gets the same properties of the listening socket */
         acceptsock->state   = SOCK_CONNECTED;
+        acceptsock->bound   = 1;
         acceptsock->nonblocking = sock->nonblocking;
         acceptsock->mask    = sock->mask;
         acceptsock->proto   = sock->proto;
@@ -1608,6 +1627,9 @@ static struct sock *accept_socket( struct sock *sock )
             release_object( acceptsock );
             return NULL;
         }
+        unix_len = sizeof(unix_addr);
+        if (!getsockname( acceptfd, &unix_addr.addr, &unix_len ))
+            acceptsock->addr_len = sockaddr_from_unix( &unix_addr, &acceptsock->addr.addr, sizeof(acceptsock->addr) );
     }
     clear_error();
     sock->pending_events &= ~AFD_POLL_ACCEPT;
@@ -1618,6 +1640,8 @@ static struct sock *accept_socket( struct sock *sock )
 
 static int accept_into_socket( struct sock *sock, struct sock *acceptsock )
 {
+    union unix_sockaddr unix_addr;
+    socklen_t unix_len;
     int acceptfd;
     struct fd *newfd;
 
@@ -1658,6 +1682,10 @@ static int accept_into_socket( struct sock *sock, struct sock *acceptsock )
     release_object( acceptsock->fd );
     acceptsock->fd = newfd;
 
+    unix_len = sizeof(unix_addr);
+    if (!getsockname( get_unix_fd( newfd ), &unix_addr.addr, &unix_len ))
+        acceptsock->addr_len = sockaddr_from_unix( &unix_addr, &acceptsock->addr.addr, sizeof(acceptsock->addr) );
+
     clear_error();
     sock->pending_events &= ~AFD_POLL_ACCEPT;
     sock->reported_events &= ~AFD_POLL_ACCEPT;
@@ -2075,8 +2103,10 @@ static int sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async )
     case IOCTL_AFD_WINE_CONNECT:
     {
         const struct afd_connect_params *params = get_req_data();
+        union unix_sockaddr unix_addr;
         const struct sockaddr *addr;
         struct connect_req *req;
+        socklen_t unix_len;
         int send_len, ret;
 
         if (get_req_data_size() < sizeof(*params) ||
@@ -2118,6 +2148,11 @@ static int sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async )
         /* a connected or connecting socket can no longer be accepted into */
         allow_fd_caching( sock->fd );
 
+        unix_len = sizeof(unix_addr);
+        if (!sock->bound && !getsockname( unix_fd, &unix_addr.addr, &unix_len ))
+            sock->addr_len = sockaddr_from_unix( &unix_addr, &sock->addr.addr, sizeof(sock->addr) );
+        sock->bound = 1;
+
         if (!ret)
         {
             sock->state = SOCK_CONNECTED;
@@ -2351,7 +2386,7 @@ static int sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async )
     case IOCTL_AFD_BIND:
     {
         const struct afd_bind_params *params = get_req_data();
-        union unix_sockaddr unix_addr;
+        union unix_sockaddr unix_addr, bind_addr;
         data_size_t in_size;
         socklen_t unix_len;
 
@@ -2376,6 +2411,7 @@ static int sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async )
             set_error( STATUS_INVALID_ADDRESS );
             return 0;
         }
+        bind_addr = unix_addr;
 
         if (unix_addr.addr.sa_family == WS_AF_INET)
         {
@@ -2383,10 +2419,10 @@ static int sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async )
 
             if (!memcmp( &unix_addr.in.sin_addr, magic_loopback_addr, 4 )
                     || bind_to_interface( sock, &unix_addr.in ))
-                unix_addr.in.sin_addr.s_addr = htonl( INADDR_ANY );
+                bind_addr.in.sin_addr.s_addr = htonl( INADDR_ANY );
         }
 
-        if (bind( unix_fd, &unix_addr.addr, unix_len ) < 0)
+        if (bind( unix_fd, &bind_addr.addr, unix_len ) < 0)
         {
             if (errno == EADDRINUSE)
             {
@@ -2398,10 +2434,40 @@ static int sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async )
             }
 
             set_error( sock_get_ntstatus( errno ) );
+            return 1;
         }
+
+        sock->bound = 1;
+
+        unix_len = sizeof(bind_addr);
+        if (!getsockname( unix_fd, &bind_addr.addr, &unix_len ))
+        {
+            /* store the interface or magic loopback address instead of the
+             * actual unix address */
+            if (bind_addr.addr.sa_family == AF_INET)
+                bind_addr.in.sin_addr = unix_addr.in.sin_addr;
+            sock->addr_len = sockaddr_from_unix( &bind_addr, &sock->addr.addr, sizeof(sock->addr) );
+        }
+
         return 1;
     }
 
+    case IOCTL_AFD_GETSOCKNAME:
+        if (!sock->bound)
+        {
+            set_error( STATUS_INVALID_PARAMETER );
+            return 0;
+        }
+
+        if (get_reply_max_size() < sock->addr_len)
+        {
+            set_error( STATUS_BUFFER_TOO_SMALL );
+            return 0;
+        }
+
+        set_reply_data( &sock->addr, sock->addr_len );
+        return 1;
+
     default:
         set_error( STATUS_NOT_SUPPORTED );
         return 0;
@@ -2972,6 +3038,17 @@ DECL_HANDLER(send_socket)
     if (!sock) return;
     fd = sock->fd;
 
+    if (sock->type == WS_SOCK_DGRAM)
+    {
+        /* sendto() and sendmsg() implicitly binds a socket */
+        union unix_sockaddr unix_addr;
+        socklen_t unix_len = sizeof(unix_addr);
+
+        if (!sock->bound && !getsockname( get_unix_fd( fd ), &unix_addr.addr, &unix_len ))
+            sock->addr_len = sockaddr_from_unix( &unix_addr, &sock->addr.addr, sizeof(sock->addr) );
+        sock->bound = 1;
+    }
+
     if (status != STATUS_SUCCESS)
     {
         /* send() calls only clear and reselect events if unsuccessful. */
-- 
2.30.2




More information about the wine-devel mailing list