- 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.
This commit is contained in:
Rein Klazes 2004-10-06 18:52:51 +00:00 committed by Alexandre Julliard
parent 1b2dd4ba35
commit fd19a1f9e8
2 changed files with 105 additions and 18 deletions

View File

@ -1587,6 +1587,7 @@ INT WINAPI WS_getsockopt(SOCKET s, INT level,
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 @@ INT WINAPI WS_getsockopt(SOCKET s, INT level,
}
#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 @@ int WINAPI WS_setsockopt(SOCKET s, int level, int optname,
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;

View File

@ -625,6 +625,65 @@ static void do_test( test_setup *test )
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 @@ START_TEST( sock )
int i;
Init();
test_set_getsockopt();
test_so_reuseaddr();
for (i = 0; i < NUM_TESTS; i++)