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