[PATCH 2/3] ws2_32: Reimplement WS_EnumProtocols

Robin Ebert ebertrobin2002 at gmail.com
Thu Aug 13 05:57:43 CDT 2020


WS_EnumProtocols broke with changes to WS_EnterSingleProtocol{W|A} so it needs to be reimplemented.

Signed-off-by: Robin Ebert <ebertrobin2002 at gmail.com>
---
 dlls/ws2_32/socket.c | 92 ++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 88 insertions(+), 4 deletions(-)

diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c
index d6667c78..cb03f8ea 100644
--- a/dlls/ws2_32/socket.c
+++ b/dlls/ws2_32/socket.c
@@ -2348,6 +2348,7 @@ static BOOL WS_AF_IPX_EnterSingleProtocolW( INT protocol, WSAPROTOCOL_INFOW* inf
  *
  * RETURNS
  *    count of returned WSAPROTOCOL_INFOW structs
+ *    *len contains the amount of needed WSAPROTOCOL_INFOW entries available if the buffer was too small
  *
  * BUGS
  *    - only implemented for IPX, SPX, SPXII, TCP, UDP
@@ -2358,6 +2359,7 @@ static INT WS_EnterSingleProtocolW( INT address_family, INT protocol, WSAPROTOCO
 {
     if(address_family)
     {
+        /* the buffer needs to be valid here. This should be checked by the caller */
         memset( info, 0, sizeof(WSAPROTOCOL_INFOW) );
         info->iProtocol = protocol;
 
@@ -2380,8 +2382,39 @@ static INT WS_EnterSingleProtocolW( INT address_family, INT protocol, WSAPROTOCO
     }
     else
     {
-        FIXME("Unspecified address_family not implemented yet\n");
-        return 0;
+        /* the buffer can be too small so we need our own as well */
+        INT ret = 0, min_buffer = 0;
+        WSAPROTOCOL_INFOW infow;
+        WSAPROTOCOL_INFOW* buffer;
+
+        buffer = *info_size - ret ? &info[ret] : &infow;
+        if(WS_AF_INET_EnterSingleProtocolW(protocol, buffer))
+        {
+            min_buffer++;
+            if(buffer != &infow)
+                ret++;
+
+            buffer = *info_size - ret ? &info[ret] : &infow;
+        }
+        if(WS_AF_INET6_EnterSingleProtocolW(protocol, buffer))
+        {
+            min_buffer++;
+            if(buffer != &infow)
+                ret++;
+
+            buffer = *info_size - ret ? &info[ret] : &infow;
+        }
+        if(WS_AF_IPX_EnterSingleProtocolW(protocol, buffer))
+        {
+            min_buffer++;
+            if(buffer != &infow)
+                ret++;
+        }
+
+        if(min_buffer > *info_size)
+            *info_size = min_buffer;
+
+        return ret;
     }
 }
 
@@ -2417,8 +2450,59 @@ static INT WS_EnterSingleProtocolA( INT addressfamily, INT protocol, WSAPROTOCOL
 
 static INT WS_EnumProtocols( BOOL unicode, const INT *protocols, LPWSAPROTOCOL_INFOW buffer, LPDWORD len )
 {
-    FIXME("Not implemented\n");
-    return 0;
+    INT i = 0, items = 0, space, temp, space_temp, min_buffer_size;
+    DWORD size = 0;
+    union _info
+    {
+      LPWSAPROTOCOL_INFOA a;
+      LPWSAPROTOCOL_INFOW w;
+    } info;
+    info.w = buffer;
+
+    if (!protocols) protocols = valid_protocols;
+
+    size = unicode ? sizeof(WSAPROTOCOL_INFOW) : sizeof(WSAPROTOCOL_INFOA);
+
+    TRACE("unicode %d, protocols %p, buffer %p, length %p %d\n",
+          unicode, protocols, buffer, len, len ? *len : 0);
+
+    if (*len < size || !buffer)
+    {
+        /* len should return the count of needed space */
+        *len = 0;
+        SetLastError(WSAENOBUFS);
+    }
+
+
+    min_buffer_size = 0;
+    space = *len / (unicode ? sizeof(WSAPROTOCOL_INFOW) : sizeof(WSAPROTOCOL_INFOA));
+    for (i = items = 0; protocols[i]; i++)
+    {
+        if (!supported_protocol(protocols[i])) continue;
+        space_temp = space; /* WS_EnterSingleProtocol may alter this value */
+        if (unicode)
+        {
+            temp = WS_EnterSingleProtocolW( WS_AF_UNSPEC, protocols[i], &info.w[items], &space_temp );
+        }
+        else
+        {
+            temp = WS_EnterSingleProtocolA( WS_AF_UNSPEC, protocols[i], &info.a[items], &space_temp );
+        }
+        min_buffer_size += space_temp != space ? space_temp : temp; /* if WS_EnterSingleProtocol altered it we need to use this value */
+        items += temp;
+        space -= temp;
+    }
+    size = min_buffer_size * (unicode ? sizeof(WSAPROTOCOL_INFOW) : sizeof(WSAPROTOCOL_INFOA));
+    if(*len == 0)
+    {
+        /* if len is 0 it's either passed in or explicitly set resulting in an error */
+        *len = size;
+        return SOCKET_ERROR;
+    }
+    else if(size > *len)
+        /* len should return the count of needed space */
+        *len = size;
+    return items;
 }
 
 static BOOL ws_protocol_info(SOCKET s, int unicode, WSAPROTOCOL_INFOW *buffer, int *size)
-- 
2.20.1




More information about the wine-devel mailing list