Commit 8dc5242e authored by Florian Will's avatar Florian Will Committed by Alexandre Julliard

ws2_32: Implement TCP_KEEP{ALIVE,CNT,INTVL} options.

parent 26136fda
...@@ -2507,6 +2507,34 @@ NTSTATUS sock_ioctl( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc ...@@ -2507,6 +2507,34 @@ NTSTATUS sock_ioctl( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc
case IOCTL_AFD_WINE_SET_TCP_NODELAY: case IOCTL_AFD_WINE_SET_TCP_NODELAY:
return do_setsockopt( handle, io, IPPROTO_TCP, TCP_NODELAY, in_buffer, in_size ); return do_setsockopt( handle, io, IPPROTO_TCP, TCP_NODELAY, in_buffer, in_size );
#if defined(TCP_KEEPIDLE)
/* TCP_KEEPALIVE on Windows is often called TCP_KEEPIDLE on Unix */
case IOCTL_AFD_WINE_GET_TCP_KEEPALIVE:
return do_getsockopt( handle, io, IPPROTO_TCP, TCP_KEEPIDLE, out_buffer, out_size );
case IOCTL_AFD_WINE_SET_TCP_KEEPALIVE:
return do_setsockopt( handle, io, IPPROTO_TCP, TCP_KEEPIDLE, in_buffer, in_size );
#elif defined(TCP_KEEPALIVE)
/* Mac */
case IOCTL_AFD_WINE_GET_TCP_KEEPALIVE:
return do_getsockopt( handle, io, IPPROTO_TCP, TCP_KEEPALIVE, out_buffer, out_size );
case IOCTL_AFD_WINE_SET_TCP_KEEPALIVE:
return do_setsockopt( handle, io, IPPROTO_TCP, TCP_KEEPALIVE, in_buffer, in_size );
#endif
case IOCTL_AFD_WINE_GET_TCP_KEEPINTVL:
return do_getsockopt( handle, io, IPPROTO_TCP, TCP_KEEPINTVL, out_buffer, out_size );
case IOCTL_AFD_WINE_SET_TCP_KEEPINTVL:
return do_setsockopt( handle, io, IPPROTO_TCP, TCP_KEEPINTVL, in_buffer, in_size );
case IOCTL_AFD_WINE_GET_TCP_KEEPCNT:
return do_getsockopt( handle, io, IPPROTO_TCP, TCP_KEEPCNT, out_buffer, out_size );
case IOCTL_AFD_WINE_SET_TCP_KEEPCNT:
return do_setsockopt( handle, io, IPPROTO_TCP, TCP_KEEPCNT, in_buffer, in_size );
default: default:
{ {
if ((code >> 16) == FILE_DEVICE_NETWORK) if ((code >> 16) == FILE_DEVICE_NETWORK)
......
...@@ -1931,6 +1931,36 @@ int WINAPI getsockopt( SOCKET s, int level, int optname, char *optval, int *optl ...@@ -1931,6 +1931,36 @@ int WINAPI getsockopt( SOCKET s, int level, int optname, char *optval, int *optl
*optlen = 1; *optlen = 1;
return server_getsockopt( s, IOCTL_AFD_WINE_GET_TCP_NODELAY, optval, optlen ); return server_getsockopt( s, IOCTL_AFD_WINE_GET_TCP_NODELAY, optval, optlen );
case TCP_KEEPALIVE:
if (*optlen < sizeof(DWORD) || !optval)
{
*optlen = 0;
SetLastError( WSAEFAULT );
return SOCKET_ERROR;
}
*optlen = sizeof(DWORD);
return server_getsockopt( s, IOCTL_AFD_WINE_GET_TCP_KEEPALIVE, optval, optlen );
case TCP_KEEPCNT:
if (*optlen < sizeof(DWORD) || !optval)
{
*optlen = 0;
SetLastError( WSAEFAULT );
return SOCKET_ERROR;
}
*optlen = sizeof(DWORD);
return server_getsockopt( s, IOCTL_AFD_WINE_GET_TCP_KEEPCNT, optval, optlen );
case TCP_KEEPINTVL:
if (*optlen < sizeof(DWORD) || !optval)
{
*optlen = 0;
SetLastError( WSAEFAULT );
return SOCKET_ERROR;
}
*optlen = sizeof(DWORD);
return server_getsockopt( s, IOCTL_AFD_WINE_GET_TCP_KEEPINTVL, optval, optlen );
default: default:
FIXME( "unrecognized TCP option %#x\n", optname ); FIXME( "unrecognized TCP option %#x\n", optname );
SetLastError( WSAENOPROTOOPT ); SetLastError( WSAENOPROTOOPT );
...@@ -3325,6 +3355,12 @@ int WINAPI setsockopt( SOCKET s, int level, int optname, const char *optval, int ...@@ -3325,6 +3355,12 @@ int WINAPI setsockopt( SOCKET s, int level, int optname, const char *optval, int
break; /* case NSPROTO_IPX */ break; /* case NSPROTO_IPX */
case IPPROTO_TCP: case IPPROTO_TCP:
if (optlen < 0)
{
SetLastError(WSAENOBUFS);
return SOCKET_ERROR;
}
switch(optname) switch(optname)
{ {
case TCP_NODELAY: case TCP_NODELAY:
...@@ -3336,6 +3372,33 @@ int WINAPI setsockopt( SOCKET s, int level, int optname, const char *optval, int ...@@ -3336,6 +3372,33 @@ int WINAPI setsockopt( SOCKET s, int level, int optname, const char *optval, int
value = *optval; value = *optval;
return server_setsockopt( s, IOCTL_AFD_WINE_SET_TCP_NODELAY, (char*)&value, sizeof(value) ); return server_setsockopt( s, IOCTL_AFD_WINE_SET_TCP_NODELAY, (char*)&value, sizeof(value) );
case TCP_KEEPALIVE:
if (optlen < sizeof(DWORD) || !optval)
{
SetLastError( WSAEFAULT );
return SOCKET_ERROR;
}
value = *(DWORD*)optval;
return server_setsockopt( s, IOCTL_AFD_WINE_SET_TCP_KEEPALIVE, (char*)&value, sizeof(value) );
case TCP_KEEPCNT:
if (optlen < sizeof(DWORD) || !optval)
{
SetLastError( WSAEFAULT );
return SOCKET_ERROR;
}
value = *(DWORD*)optval;
return server_setsockopt( s, IOCTL_AFD_WINE_SET_TCP_KEEPCNT, (char*)&value, sizeof(value) );
case TCP_KEEPINTVL:
if (optlen < sizeof(DWORD) || !optval)
{
SetLastError( WSAEFAULT );
return SOCKET_ERROR;
}
value = *(DWORD*)optval;
return server_setsockopt( s, IOCTL_AFD_WINE_SET_TCP_KEEPINTVL, (char*)&value, sizeof(value) );
default: default:
FIXME("Unknown IPPROTO_TCP optname 0x%08x\n", optname); FIXME("Unknown IPPROTO_TCP optname 0x%08x\n", optname);
SetLastError(WSAENOPROTOOPT); SetLastError(WSAENOPROTOOPT);
......
...@@ -1193,7 +1193,7 @@ static void test_set_getsockopt(void) ...@@ -1193,7 +1193,7 @@ static void test_set_getsockopt(void)
DWORD values[3]; DWORD values[3];
BOOL accepts_large_value; BOOL accepts_large_value;
BOOL bool_value; BOOL bool_value;
BOOL allow_noprotoopt; /* for old windows or wine todo */ BOOL allow_noprotoopt; /* for old windows only, must work on wine */
} }
test_optsize[] = test_optsize[] =
{ {
...@@ -1211,9 +1211,9 @@ static void test_set_getsockopt(void) ...@@ -1211,9 +1211,9 @@ static void test_set_getsockopt(void)
{AF_INET, SOCK_STREAM, SOL_SOCKET, SO_SNDTIMEO, FALSE, {1, 2, 4}, {0}, TRUE}, {AF_INET, SOCK_STREAM, SOL_SOCKET, SO_SNDTIMEO, FALSE, {1, 2, 4}, {0}, TRUE},
{AF_INET, SOCK_STREAM, SOL_SOCKET, SO_OPENTYPE, FALSE, {1, 2, 4}, {0}, TRUE}, {AF_INET, SOCK_STREAM, SOL_SOCKET, SO_OPENTYPE, FALSE, {1, 2, 4}, {0}, TRUE},
{AF_INET, SOCK_STREAM, IPPROTO_TCP, TCP_NODELAY, TRUE, {1, 1, 1}, {0}, TRUE}, {AF_INET, SOCK_STREAM, IPPROTO_TCP, TCP_NODELAY, TRUE, {1, 1, 1}, {0}, TRUE},
{AF_INET, SOCK_STREAM, IPPROTO_TCP, TCP_KEEPALIVE, FALSE, {0, 0, 4}, {0}, TRUE, FALSE, TRUE}, /* wine todo */ {AF_INET, SOCK_STREAM, IPPROTO_TCP, TCP_KEEPALIVE, FALSE, {0, 0, 4}, {0}, TRUE},
{AF_INET, SOCK_STREAM, IPPROTO_TCP, TCP_KEEPCNT, FALSE, {0, 0, 4}, {0}, FALSE, FALSE, TRUE}, /* win10+, wine todo*/ {AF_INET, SOCK_STREAM, IPPROTO_TCP, TCP_KEEPCNT, FALSE, {0, 0, 4}, {0}, FALSE, FALSE, TRUE}, /* win10+ */
{AF_INET, SOCK_STREAM, IPPROTO_TCP, TCP_KEEPINTVL, FALSE, {0, 0, 4}, {0}, TRUE, FALSE, TRUE}, /* win10+, wine todo */ {AF_INET, SOCK_STREAM, IPPROTO_TCP, TCP_KEEPINTVL, FALSE, {0, 0, 4}, {0}, TRUE, FALSE, TRUE}, /* win10+ */
{AF_INET, SOCK_DGRAM, IPPROTO_IP, IP_MULTICAST_LOOP, TRUE, {1, 1, 4}, {0}, TRUE, TRUE}, {AF_INET, SOCK_DGRAM, IPPROTO_IP, IP_MULTICAST_LOOP, TRUE, {1, 1, 4}, {0}, TRUE, TRUE},
{AF_INET, SOCK_DGRAM, IPPROTO_IP, IP_MULTICAST_TTL, TRUE, {1, 1, 4}, {0}, FALSE}, {AF_INET, SOCK_DGRAM, IPPROTO_IP, IP_MULTICAST_TTL, TRUE, {1, 1, 4}, {0}, FALSE},
{AF_INET, SOCK_DGRAM, IPPROTO_IP, IP_PKTINFO, FALSE, {0, 0, 4}, {0}, TRUE, TRUE}, {AF_INET, SOCK_DGRAM, IPPROTO_IP, IP_PKTINFO, FALSE, {0, 0, 4}, {0}, TRUE, TRUE},
...@@ -1460,16 +1460,16 @@ static void test_set_getsockopt(void) ...@@ -1460,16 +1460,16 @@ static void test_set_getsockopt(void)
size = sizeof(DWORD); size = sizeof(DWORD);
value = 3600; value = 3600;
err = setsockopt(s, IPPROTO_TCP, TCP_KEEPALIVE, (char*)&value, 4); err = setsockopt(s, IPPROTO_TCP, TCP_KEEPALIVE, (char*)&value, 4);
todo_wine ok(!err, "setsockopt TCP_KEEPALIVE failed\n"); ok(!err, "setsockopt TCP_KEEPALIVE failed\n");
value = 0; value = 0;
err = getsockopt(s, IPPROTO_TCP, TCP_KEEPALIVE, (char*)&value, &size); err = getsockopt(s, IPPROTO_TCP, TCP_KEEPALIVE, (char*)&value, &size);
todo_wine ok(!err, "getsockopt TCP_KEEPALIVE failed\n"); ok(!err, "getsockopt TCP_KEEPALIVE failed\n");
todo_wine ok(value == 3600, "TCP_KEEPALIVE should be 3600, is %ld\n", value); ok(value == 3600, "TCP_KEEPALIVE should be 3600, is %ld\n", value);
/* TCP_KEEPCNT and TCP_KEEPINTVL are supported on win10 and later */ /* TCP_KEEPCNT and TCP_KEEPINTVL are supported on win10 and later */
value = 5; value = 5;
err = setsockopt(s, IPPROTO_TCP, TCP_KEEPCNT, (char*)&value, 4); err = setsockopt(s, IPPROTO_TCP, TCP_KEEPCNT, (char*)&value, 4);
todo_wine ok(!err || broken(WSAGetLastError() == WSAENOPROTOOPT), ok(!err || broken(WSAGetLastError() == WSAENOPROTOOPT),
"setsockopt TCP_KEEPCNT failed: %d\n", WSAGetLastError()); "setsockopt TCP_KEEPCNT failed: %d\n", WSAGetLastError());
if (!err) if (!err)
...@@ -1551,7 +1551,7 @@ static void test_set_getsockopt(void) ...@@ -1551,7 +1551,7 @@ static void test_set_getsockopt(void)
size = sizeof(save_value); size = sizeof(save_value);
err = getsockopt(s2, test_optsize[i].level, test_optsize[i].optname, (char*)&save_value, &size); err = getsockopt(s2, test_optsize[i].level, test_optsize[i].optname, (char*)&save_value, &size);
ok(!err || (test_optsize[i].allow_noprotoopt && WSAGetLastError() == WSAENOPROTOOPT), ok(!err || broken(test_optsize[i].allow_noprotoopt && WSAGetLastError() == WSAENOPROTOOPT),
"Unexpected getsockopt result %d.\n", err); "Unexpected getsockopt result %d.\n", err);
if (err) if (err)
......
...@@ -285,6 +285,12 @@ C_ASSERT( sizeof(struct afd_get_events_params) == 56 ); ...@@ -285,6 +285,12 @@ C_ASSERT( sizeof(struct afd_get_events_params) == 56 );
#define IOCTL_AFD_WINE_SET_IP_RECVTOS WINE_AFD_IOC(296) #define IOCTL_AFD_WINE_SET_IP_RECVTOS WINE_AFD_IOC(296)
#define IOCTL_AFD_WINE_GET_SO_EXCLUSIVEADDRUSE WINE_AFD_IOC(297) #define IOCTL_AFD_WINE_GET_SO_EXCLUSIVEADDRUSE WINE_AFD_IOC(297)
#define IOCTL_AFD_WINE_SET_SO_EXCLUSIVEADDRUSE WINE_AFD_IOC(298) #define IOCTL_AFD_WINE_SET_SO_EXCLUSIVEADDRUSE WINE_AFD_IOC(298)
#define IOCTL_AFD_WINE_GET_TCP_KEEPALIVE WINE_AFD_IOC(299)
#define IOCTL_AFD_WINE_SET_TCP_KEEPALIVE WINE_AFD_IOC(300)
#define IOCTL_AFD_WINE_GET_TCP_KEEPCNT WINE_AFD_IOC(301)
#define IOCTL_AFD_WINE_SET_TCP_KEEPCNT WINE_AFD_IOC(302)
#define IOCTL_AFD_WINE_GET_TCP_KEEPINTVL WINE_AFD_IOC(303)
#define IOCTL_AFD_WINE_SET_TCP_KEEPINTVL WINE_AFD_IOC(304)
struct afd_iovec struct afd_iovec
{ {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment