ws2_32: Implement getsockopt(SO_BSP_STATE)

Bruno Jesus 00cpxxx at gmail.com
Mon Dec 8 16:55:45 CST 2014


I ended up finding a bug in WSASocket that I'll fix later, that's why
I changed the way the sockets are created in the tests.
-------------- next part --------------
diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c
index 1864dfd..b6aad67 100644
--- a/dlls/ws2_32/socket.c
+++ b/dlls/ws2_32/socket.c
@@ -3095,6 +3095,79 @@ INT WINAPI WS_getsockopt(SOCKET s, INT level,
             }
             release_sock_fd( s, fd );
             return ret;
+        case WS_SO_BSP_STATE:
+        {
+            int req_size, addr_size;
+            WSAPROTOCOL_INFOW infow;
+            CSADDR_INFO *csinfo;
+
+            ret = ws_protocol_info(s, TRUE, &infow, &addr_size);
+            if (ret)
+            {
+                if (infow.iAddressFamily == WS_AF_INET)
+                    addr_size = sizeof(struct sockaddr_in);
+                else if (infow.iAddressFamily == WS_AF_INET6)
+                    addr_size = sizeof(struct sockaddr_in6);
+                else
+                {
+                    FIXME("Family %d is unsupported for SO_BSP_STATE", infow.iAddressFamily);
+                    SetLastError(WSAEAFNOSUPPORT);
+                    return SOCKET_ERROR;
+                }
+
+                req_size = sizeof(CSADDR_INFO) + addr_size * 2;
+                if (*optlen < req_size)
+                {
+                    ret = 0;
+                    SetLastError(WSAEFAULT);
+                }
+                else
+                {
+                    union generic_unix_sockaddr uaddr;
+                    socklen_t uaddrlen = sizeof(uaddr);
+
+                    if ( (fd = get_sock_fd( s, 0, NULL )) == -1)
+                        return SOCKET_ERROR;
+
+                    csinfo = (CSADDR_INFO*) optval;
+
+                    /* Check if the sock is bound */
+                    if (!getsockname(fd, &uaddr.addr, &uaddrlen) &&
+                        is_sockaddr_bound(&uaddr.addr, uaddrlen))
+                    {
+                        csinfo->LocalAddr.lpSockaddr =
+                            (LPSOCKADDR) (optval + sizeof(CSADDR_INFO));
+                        ws_sockaddr_u2ws(&uaddr.addr, csinfo->LocalAddr.lpSockaddr, &addr_size);
+                        csinfo->LocalAddr.iSockaddrLength = addr_size;
+                    }
+                    else
+                    {
+                        csinfo->LocalAddr.lpSockaddr = NULL;
+                        csinfo->LocalAddr.iSockaddrLength = 0;
+                    }
+
+                    /* Check if the sock is connected */
+                    if (!getpeername(fd, &uaddr.addr, &uaddrlen) &&
+                        is_sockaddr_bound(&uaddr.addr, uaddrlen))
+                    {
+                        csinfo->RemoteAddr.lpSockaddr =
+                            (LPSOCKADDR) (optval + sizeof(CSADDR_INFO) + addr_size);
+                        ws_sockaddr_u2ws(&uaddr.addr, csinfo->RemoteAddr.lpSockaddr, &addr_size);
+                        csinfo->RemoteAddr.iSockaddrLength = addr_size;
+                    }
+                    else
+                    {
+                        csinfo->RemoteAddr.lpSockaddr = NULL;
+                        csinfo->RemoteAddr.iSockaddrLength = 0;
+                    }
+
+                    csinfo->iSocketType = infow.iSocketType;
+                    csinfo->iProtocol = infow.iProtocol;
+                    release_sock_fd( s, fd );
+                }
+            }
+            return ret ? 0 : SOCKET_ERROR;
+        }
         case WS_SO_DONTLINGER:
         {
             struct linger lingval;
diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c
index f0946c9..79d5991 100644
--- a/dlls/ws2_32/tests/sock.c
+++ b/dlls/ws2_32/tests/sock.c
@@ -1486,9 +1486,9 @@ todo_wine
     }
 
     /* Test SO_BSP_STATE - Present only in >= Win 2008 */
-    s = socket(AF_INET, SOCK_STREAM, 0);
+    s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
     ok(s != INVALID_SOCKET, "Failed to create socket\n");
-    s2 = socket(AF_INET, SOCK_STREAM, 0);
+    s2 = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
     ok(s2 != INVALID_SOCKET, "Failed to create socket\n");
 
     SetLastError(0xdeadbeef);
@@ -1571,6 +1571,23 @@ todo_wine
         ok(!err, "Expected 0, got %d\n", err);
         ok(!memcmp(&saddr, csinfoB.cs.LocalAddr.lpSockaddr, size), "Expected matching addresses\n");
         ok(!memcmp(&saddr, csinfoA.cs.RemoteAddr.lpSockaddr, size), "Expected matching addresses\n");
+
+        SetLastError(0xdeadbeef);
+        size = sizeof(CSADDR_INFO);
+        err = getsockopt(s, SOL_SOCKET, SO_BSP_STATE, (char *) &csinfoA, &size);
+        ok(err, "Expected non-zero\n");
+        ok(size == sizeof(CSADDR_INFO), "Expected %d, got %d\n", sizeof(CSADDR_INFO), size);
+        ok(GetLastError() == WSAEFAULT, "Expected 10014, got %d\n", GetLastError());
+
+        /* At least for IPv4 the size is exactly 56 bytes */
+        size = sizeof(*csinfoA.cs.LocalAddr.lpSockaddr) * 2 + sizeof(csinfoA.cs);
+        err = getsockopt(s, SOL_SOCKET, SO_BSP_STATE, (char *) &csinfoA, &size);
+        ok(!err, "Expected 0, got %d\n", err);
+        size--;
+        SetLastError(0xdeadbeef);
+        err = getsockopt(s, SOL_SOCKET, SO_BSP_STATE, (char *) &csinfoA, &size);
+        ok(err, "Expected non-zero\n");
+        ok(GetLastError() == WSAEFAULT, "Expected 10014, got %d\n", GetLastError());
     }
     else
         ok(GetLastError() == WSAENOPROTOOPT, "Expected 10042, got %d\n", GetLastError());
diff --git a/include/winsock.h b/include/winsock.h
index 21e984c..50237e8 100644
--- a/include/winsock.h
+++ b/include/winsock.h
@@ -697,6 +697,7 @@ typedef struct WS(WSAData)
 #define WS_SO_RCVTIMEO             0x1006
 #define WS_SO_ERROR                0x1007
 #define WS_SO_TYPE                 0x1008
+#define WS_SO_BSP_STATE            0x1009
 
 #define WS_IOCPARM_MASK            0x7f
 #define WS_IOC_VOID                0x20000000


More information about the wine-patches mailing list