winsock: getsockopt fix.

Rein Klazes rklazes at xs4all.nl
Wed Oct 6 04:08:19 CDT 2004


Hi,

Changelog:
	dlls/winsock	: socket.c
	dlls/winsock/tests : sock.c
	-Fix WS_getsockopt for the options SO_LINGER, SO_RCVTIMEO and 
	SO_SNDTIMEO by adding data conversion from Unix to windows.
	-Added a test for this.

Rein.
-- 
Rein Klazes
rklazes at xs4all.nl
-------------- next part --------------
--- wine/dlls/winsock/socket.c	2004-10-05 08:03:34.000000000 +0200
+++ mywine/dlls/winsock/socket.c	2004-10-06 09:16:32.000000000 +0200
@@ -1587,6 +1587,7 @@
                                   INT optname, char *optval, INT *optlen)
 {
     int fd;
+    INT ret = 0;
 
     TRACE("socket: %04x, level 0x%x, name 0x%x, ptr %8x, len %d\n", s, level,
           (int) optname, (int) optval, (int) *optlen);
@@ -1665,22 +1666,49 @@
     }
 #endif
 
-    fd = get_sock_fd( s, 0, NULL );
-    if (fd != -1)
-    {
-	if (!convert_sockopt(&level, &optname)) {
-	    SetLastError(WSAENOPROTOOPT);	/* Unknown option */
-        } else {
-	    if (getsockopt(fd, (int) level, optname, optval, optlen) == 0 )
-	    {
-		release_sock_fd( s, fd );
-		return 0;
-	    }
-	    SetLastError((errno == EBADF) ? WSAENOTSOCK : wsaErrno());
-	}
-        release_sock_fd( s, fd );
+    if( (fd = get_sock_fd( s, 0, NULL )) == -1)
+        return SOCKET_ERROR;
+
+    if (!convert_sockopt(&level, &optname)) {
+        SetLastError(WSAENOPROTOOPT);	/* Unknown option */
+        ret = SOCKET_ERROR;
+    } else {
+        struct timeval tv;
+        struct linger lingval;
+        INT len, *plen = optlen;
+        char *pval = optval;
+        if(level == SOL_SOCKET && is_timeout_option(optname)) {
+            len = sizeof(tv);
+            plen = &len;
+            pval = (char *) &tv;
+        } else if( level == SOL_SOCKET && optname == SO_LINGER) {
+            len = sizeof(lingval);
+            plen = &len;
+            pval = (char *) &lingval;
+        }
+        if (getsockopt(fd, (int) level, optname, pval, plen) != 0 ) {
+            SetLastError((errno == EBADF) ? WSAENOTSOCK : wsaErrno());
+            ret = SOCKET_ERROR;
+        } else if(level == SOL_SOCKET && is_timeout_option(optname)) {
+            if( *optlen >= sizeof(INT) ) {
+                *optlen = sizeof(INT);
+                *(INT*)optval = tv.tv_sec * 1000 + tv.tv_usec / 1000;
+            } else {
+                SetLastError(WSAEFAULT);
+                ret = SOCKET_ERROR;
+            }
+        } else if( level == SOL_SOCKET && optname == SO_LINGER) {
+            if( *optlen >=  sizeof( LINGER) ) {
+                (( LINGER *) optval)->l_onoff = lingval.l_onoff;
+                (( LINGER *) optval)->l_linger = lingval.l_linger;
+            } else {
+                SetLastError(WSAEFAULT);
+                ret = SOCKET_ERROR;
+            }
+        }
     }
-    return SOCKET_ERROR;
+    release_sock_fd( s, fd );
+    return ret;
 }
 
 
@@ -2442,9 +2470,8 @@
             return SOCKET_ERROR;
         }
         if (optname == SO_LINGER && optval) {
-            /* yes, uses unsigned short in both win16/win32 */
-            linger.l_onoff  = ((UINT16*)optval)[0];
-            linger.l_linger = ((UINT16*)optval)[1];
+            linger.l_onoff  = ((LINGER*)optval)->l_onoff;
+            linger.l_linger  = ((LINGER*)optval)->l_linger;
             /* FIXME: what is documented behavior if SO_LINGER optval
                is null?? */
             optval = (char*)&linger;
--- wine/dlls/winsock/tests/sock.c	2004-08-10 08:12:55.000000000 +0200
+++ mywine/dlls/winsock/tests/sock.c	2004-10-06 09:50:57.000000000 +0200
@@ -625,6 +625,65 @@
         CloseHandle ( client_ready[i] );
 }
 
+/********* some tests for getsockopt(setsockopt(X)) == X ***********/
+/* optname = SO_LINGER */
+LINGER linger_testvals[] = {
+    {0,0},
+    {0,73}, 
+    {1,0},
+    {5,189}
+};
+
+/* optname = SO_RCVTIMEO, SOSNDTIMEO */
+#define SOCKTIMEOUT1 63000 /* 63 seconds. Do not test fractional part because of a
+                        bug in the linux kernel (fixed in 2.6.8) */ 
+#define SOCKTIMEOUT2 997000 /* 997 seconds */
+
+static void test_set_getsockopt()
+{
+    SOCKET s;
+    int i, err;
+    int timeout;
+    LINGER lingval;
+    int size;
+
+    s = socket(AF_INET, SOCK_STREAM, 0);
+    ok(s!=INVALID_SOCKET, "socket() failed error: %d\n", WSAGetLastError());
+    if( s == INVALID_SOCKET) return;
+    /* SO_RCVTIMEO */
+    timeout = SOCKTIMEOUT1;
+    size = sizeof(timeout);
+    err = setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (char *) &timeout, size); 
+    if( !err)
+        err = getsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (char *) &timeout, &size); 
+    ok( !err, "get/setsockopt(SO_RCVTIMEO) failed error: %d\n", WSAGetLastError());
+    ok( timeout == SOCKTIMEOUT1, "getsockopt(SO_RCVTIMEO) returned wrong value %d\n", timeout);
+    /* SO_SNDTIMEO */
+    timeout = SOCKTIMEOUT2; /* 54 seconds. See remark above */ 
+    size = sizeof(timeout);
+    err = setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, (char *) &timeout, size); 
+    if( !err)
+        err = getsockopt(s, SOL_SOCKET, SO_SNDTIMEO, (char *) &timeout, &size); 
+    ok( !err, "get/setsockopt(SO_SNDTIMEO) failed error: %d\n", WSAGetLastError());
+    ok( timeout == SOCKTIMEOUT2, "getsockopt(SO_SNDTIMEO) returned wrong value %d\n", timeout);
+    /* SO_LINGER */
+    for( i = 0; i < sizeof(linger_testvals)/sizeof(LINGER);i++) {
+        size =  sizeof(lingval);
+        lingval = linger_testvals[i];
+        err = setsockopt(s, SOL_SOCKET, SO_LINGER, (char *) &lingval, size); 
+        if( !err)
+            err = getsockopt(s, SOL_SOCKET, SO_LINGER, (char *) &lingval, &size); 
+        ok( !err, "get/setsockopt(SO_LINGER) failed error: %d\n", WSAGetLastError());
+        ok( !lingval.l_onoff == !linger_testvals[i].l_onoff &&
+                (lingval.l_linger == linger_testvals[i].l_linger ||
+                 (!lingval.l_linger && !linger_testvals[i].l_onoff))
+                , "getsockopt(SO_LINGER #%d) returned wrong value %d,%d not %d,%d \n", i, 
+                 lingval.l_onoff, lingval.l_linger,
+                 linger_testvals[i].l_onoff, linger_testvals[i].l_linger);
+    }
+    closesocket(s);
+}
+
 static void test_so_reuseaddr()
 {
     struct sockaddr_in saddr;
@@ -725,6 +784,7 @@
     int i;
     Init();
 
+    test_set_getsockopt();
     test_so_reuseaddr();
 
     for (i = 0; i < NUM_TESTS; i++)


More information about the wine-patches mailing list