- 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:
parent
1b2dd4ba35
commit
fd19a1f9e8
|
@ -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;
|
||||
|
|
|
@ -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++)
|
||||
|
|
Loading…
Reference in New Issue