ws2_32: Implement get socket option SO_PROTOCOL_INFO (try 2)

Bruno Jesus 00cpxxx at gmail.com
Mon Sep 2 21:51:37 CDT 2013


try 2:
Narrow the loop for the specified protocol
Add a new test for invalid sockets
-------------- next part --------------
diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c
index 462f153..60419d8 100644
--- a/dlls/ws2_32/socket.c
+++ b/dlls/ws2_32/socket.c
@@ -1116,6 +1116,65 @@ convert_socktype_u2w(int unixsocktype) {
     return -1;
 }
 
+static int fill_protocol_info(SOCKET s, int unicode, char *optval)
+{
+    int items, sz, i, targetproto[2] = {0, 0};
+    DWORD listsize = 0;
+    WSAPROTOCOL_INFOW *buffer = NULL;
+
+    union _info
+    {
+        WSAPROTOCOL_INFOA *a;
+        WSAPROTOCOL_INFOA *w;
+    } info;
+    info.a = (WSAPROTOCOL_INFOA *) optval;
+
+    sz = unicode ? sizeof(WSAPROTOCOL_INFOW) : sizeof(WSAPROTOCOL_INFOA);
+    memset(optval, 0, sz);
+    info.a->iAddressFamily = WS_AF_UNSPEC;
+
+    SERVER_START_REQ( get_socket_info )
+    {
+        req->handle  = wine_server_obj_handle( SOCKET2HANDLE(s) );
+        wine_server_call( req );
+        info.a->iAddressFamily = convert_af_u2w(reply->family);
+        info.a->iSocketType = convert_socktype_u2w(reply->type);
+        info.a->iProtocol = convert_proto_u2w(reply->protocol);
+    }
+    SERVER_END_REQ;
+
+    if(info.a->iAddressFamily == WS_AF_UNSPEC)
+        return 0;
+
+    targetproto[0] = info.a->iProtocol;
+    items = WSAEnumProtocolsW(targetproto, NULL, &listsize);
+    if (items == SOCKET_ERROR && WSAGetLastError() == WSAENOBUFS &&
+       (buffer = HeapAlloc(GetProcessHeap(), 0, listsize)))
+    {
+        items = WSAEnumProtocolsW(targetproto, buffer, &listsize);
+        for (i = 0; i < items; i++)
+        {
+            if (buffer[i].iAddressFamily == info.a->iAddressFamily && 
+                buffer[i].iSocketType == info.a->iSocketType)
+            {
+                if (unicode)
+                    memcpy(info.w, &buffer[i], sz);
+                else
+                {
+                    /* convert the structure from W to A */
+                    memcpy(info.a, &buffer[i], FIELD_OFFSET(WSAPROTOCOL_INFOA, szProtocol));
+                    WideCharToMultiByte(CP_ACP, 0, buffer[i].szProtocol, -1,
+                                        info.a->szProtocol, WSAPROTOCOL_LEN+1, NULL, NULL);
+                }
+                break;
+            }
+        }
+    }
+
+    HeapFree(GetProcessHeap(), 0, buffer);
+    return sz;
+}
+
 /* ----------------------------------- API -----
  *
  * Init / cleanup / error checking.
@@ -2776,6 +2835,26 @@ INT WINAPI WS_getsockopt(SOCKET s, INT level,
             TRACE("getting global SO_OPENTYPE = 0x%x\n", *((int*)optval) );
             return 0;
 
+        case WS_SO_PROTOCOL_INFOA:
+        case WS_SO_PROTOCOL_INFOW:
+            if ( (fd = get_sock_fd( s, 0, NULL )) == -1)
+            {
+                SetLastError(WSAENOTSOCK);
+                return SOCKET_ERROR;
+            }
+            release_sock_fd( s, fd );
+
+            if (!optlen || !optval ||
+                *optlen < (optname == WS_SO_PROTOCOL_INFOA ?
+                 sizeof(WSAPROTOCOL_INFOA) : sizeof(WSAPROTOCOL_INFOW)))
+            {
+                SetLastError(WSAEFAULT);
+                return SOCKET_ERROR;
+            }
+
+            *optlen = fill_protocol_info(s, optname == WS_SO_PROTOCOL_INFOW, optval);
+            return *optlen ? 0 : SOCKET_ERROR;
+
 #ifdef SO_RCVTIMEO
         case WS_SO_RCVTIMEO:
 #endif
diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c
index 5d80fca..85de960 100644
--- a/dlls/ws2_32/tests/sock.c
+++ b/dlls/ws2_32/tests/sock.c
@@ -1235,28 +1235,28 @@ todo_wine
     closesocket(s);
 
     /* test SO_PROTOCOL_INFOA invalid parameters */
+    ok(getsockopt(INVALID_SOCKET, SOL_SOCKET, SO_PROTOCOL_INFOA, NULL, NULL),
+       "getsockopt should have failed\n");
+    err = WSAGetLastError();
+    ok(err == WSAENOTSOCK, "expected 10038, got %d instead\n", err);
     s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
     ok(getsockopt(s, SOL_SOCKET, SO_PROTOCOL_INFOA, NULL, NULL),
        "getsockopt should have failed\n");
     err = WSAGetLastError();
-todo_wine
     ok(err == WSAEFAULT, "expected 10014, got %d instead\n", err);
     ok(getsockopt(s, SOL_SOCKET, SO_PROTOCOL_INFOA, (char *) &infoA, NULL),
        "getsockopt should have failed\n");
     err = WSAGetLastError();
-todo_wine
     ok(err == WSAEFAULT, "expected 10014, got %d instead\n", err);
     ok(getsockopt(s, SOL_SOCKET, SO_PROTOCOL_INFOA, NULL, &size),
        "getsockopt should have failed\n");
     err = WSAGetLastError();
-todo_wine
     ok(err == WSAEFAULT, "expected 10014, got %d instead\n", err);
 
     size = sizeof(WSAPROTOCOL_INFOA) / 2;
     ok(getsockopt(s, SOL_SOCKET, SO_PROTOCOL_INFOA, (char *) &infoA, &size),
        "getsockopt should have failed\n");
     err = WSAGetLastError();
-todo_wine
     ok(err == WSAEFAULT, "expected 10014, got %d instead\n", err);
     closesocket(s);
 
@@ -1273,21 +1273,28 @@ todo_wine
         infoA.szProtocol[0] = 0;
         size = sizeof(WSAPROTOCOL_INFOA);
         err = getsockopt(s, SOL_SOCKET, SO_PROTOCOL_INFOA, (char *) &infoA, &size);
-todo_wine
         ok(!err,"getsockopt failed with %d\n", WSAGetLastError());
 
         infoW.szProtocol[0] = 0;
         size = sizeof(WSAPROTOCOL_INFOW);
         err = getsockopt(s, SOL_SOCKET, SO_PROTOCOL_INFOW, (char *) &infoW, &size);
-todo_wine
         ok(!err,"getsockopt failed with %d\n", WSAGetLastError());
 
         trace("provider name '%s', family %d, type %d, proto %d\n",
               infoA.szProtocol, prottest[i].family, prottest[i].type, prottest[i].proto);
 
-        todo_wine {
-        ok(infoA.szProtocol[0], "WSAPROTOCOL_INFOA was not filled\n");
-        ok(infoW.szProtocol[0], "WSAPROTOCOL_INFOW was not filled\n");
+        /* Remove IF when WSAEnumProtocols is fixed to return AF_INET6 data */
+        if (prottest[i].family == AF_INET6)
+        {
+            todo_wine {
+            ok(infoA.szProtocol[0], "WSAPROTOCOL_INFOA was not filled\n");
+            ok(infoW.szProtocol[0], "WSAPROTOCOL_INFOW was not filled\n");
+            }
+        }
+        else
+        {
+            ok(infoA.szProtocol[0], "WSAPROTOCOL_INFOA was not filled\n");
+            ok(infoW.szProtocol[0], "WSAPROTOCOL_INFOW was not filled\n");
         }
 
         WideCharToMultiByte(CP_ACP, 0, infoW.szProtocol, -1,
@@ -1295,7 +1302,6 @@ todo_wine
         ok(!strcmp(infoA.szProtocol,providername),
            "different provider names '%s' != '%s'\n", infoA.szProtocol, providername);
 
-        todo_wine {
         ok(!memcmp(&infoA, &infoW, FIELD_OFFSET(WSAPROTOCOL_INFOA, szProtocol)),
            "SO_PROTOCOL_INFO[A/W] comparison failed\n");
         ok(infoA.iAddressFamily == prottest[i].family, "socket family invalid, expected %d received %d\n",
@@ -1304,7 +1310,6 @@ todo_wine
            prottest[i].type, infoA.iSocketType);
         ok(infoA.iProtocol == prottest[i].proto, "socket protocol invalid, expected %d received %d\n",
            prottest[i].proto, infoA.iProtocol);
-        }
 
         closesocket(s);
     }


More information about the wine-patches mailing list