Signed-off-by: Alex Henrie alexhenrie24@gmail.com --- v3: No changes --- dlls/ws2_32/socket.c | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c index 3d88e45c66e..9a45124cd9e 100644 --- a/dlls/ws2_32/socket.c +++ b/dlls/ws2_32/socket.c @@ -2842,6 +2842,7 @@ int WINAPI setsockopt( SOCKET s, int level, int optname, const char *optval, int
default: FIXME("opt_name:%x\n", optname); + SetLastError(WSAENOPROTOOPT); return SOCKET_ERROR; } break; /* case NSPROTO_IPX */ @@ -2854,6 +2855,7 @@ int WINAPI setsockopt( SOCKET s, int level, int optname, const char *optval, int
default: FIXME("Unknown IPPROTO_TCP optname 0x%08x\n", optname); + SetLastError(WSAENOPROTOOPT); return SOCKET_ERROR; } break; @@ -2911,6 +2913,7 @@ int WINAPI setsockopt( SOCKET s, int level, int optname, const char *optval, int
default: FIXME("Unknown IPPROTO_IP optname 0x%08x\n", optname); + SetLastError(WSAENOPROTOOPT); return SOCKET_ERROR; } break; @@ -2960,6 +2963,7 @@ int WINAPI setsockopt( SOCKET s, int level, int optname, const char *optval, int
default: FIXME("Unknown IPPROTO_IPV6 optname 0x%08x\n", optname); + SetLastError(WSAENOPROTOOPT); return SOCKET_ERROR; } break;
Windows only supports setting this option, not getting it.
Signed-off-by: Alex Henrie alexhenrie24@gmail.com --- v3: Set WSAEINVAL
I moved the case statement near the bottom of the list because we will need to add cases for other options that also merely set WSAEINVAL and return -1. --- dlls/ntdll/unix/socket.c | 3 --- dlls/ws2_32/socket.c | 7 ++++--- dlls/ws2_32/tests/sock.c | 18 ++++++------------ include/wine/afd.h | 1 - 4 files changed, 10 insertions(+), 19 deletions(-)
diff --git a/dlls/ntdll/unix/socket.c b/dlls/ntdll/unix/socket.c index 4f0c83597df..1ac4365c012 100644 --- a/dlls/ntdll/unix/socket.c +++ b/dlls/ntdll/unix/socket.c @@ -1762,9 +1762,6 @@ NTSTATUS sock_ioctl( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc return do_setsockopt( handle, io, IPPROTO_IP, IP_DROP_SOURCE_MEMBERSHIP, in_buffer, in_size );
#ifdef IP_HDRINCL - case IOCTL_AFD_WINE_GET_IP_HDRINCL: - return do_getsockopt( handle, io, IPPROTO_IP, IP_HDRINCL, out_buffer, out_size ); - case IOCTL_AFD_WINE_SET_IP_HDRINCL: return do_setsockopt( handle, io, IPPROTO_IP, IP_HDRINCL, in_buffer, in_size ); #endif diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c index 9a45124cd9e..c991d212a07 100644 --- a/dlls/ws2_32/socket.c +++ b/dlls/ws2_32/socket.c @@ -1677,9 +1677,6 @@ int WINAPI getsockopt( SOCKET s, int level, int optname, char *optval, int *optl case IP_DONTFRAGMENT: return server_getsockopt( s, IOCTL_AFD_WINE_GET_IP_DONTFRAGMENT, optval, optlen );
- case IP_HDRINCL: - return server_getsockopt( s, IOCTL_AFD_WINE_GET_IP_HDRINCL, optval, optlen ); - case IP_MULTICAST_IF: return server_getsockopt( s, IOCTL_AFD_WINE_GET_IP_MULTICAST_IF, optval, optlen );
@@ -1704,6 +1701,10 @@ int WINAPI getsockopt( SOCKET s, int level, int optname, char *optval, int *optl case IP_UNICAST_IF: return server_getsockopt( s, IOCTL_AFD_WINE_GET_IP_UNICAST_IF, optval, optlen );
+ case IP_HDRINCL: + SetLastError( WSAEINVAL ); + return -1; + default: FIXME( "unrecognized IP option %u\n", optname ); /* fall through */ diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c index 6693c469dce..51aa0e61282 100644 --- a/dlls/ws2_32/tests/sock.c +++ b/dlls/ws2_32/tests/sock.c @@ -1437,12 +1437,9 @@ todo_wine k = 99; SetLastError(0xdeadbeef); err = getsockopt(s, IPPROTO_IP, IP_HDRINCL, (char *) &k, &size); - todo_wine - { - ok(err == -1, "Expected -1, got %d\n", err); - ok(GetLastError() == WSAEINVAL, "Expected 10022, got %d\n", GetLastError()); - ok(k == 99, "Expected 99, got %d\n", k); - } + ok(err == -1, "Expected -1, got %d\n", err); + ok(GetLastError() == WSAEINVAL, "Expected 10022, got %d\n", GetLastError()); + ok(k == 99, "Expected 99, got %d\n", k);
size = sizeof(k); k = 0; @@ -1453,12 +1450,9 @@ todo_wine k = 99; SetLastError(0xdeadbeef); err = getsockopt(s, IPPROTO_IP, IP_HDRINCL, (char *) &k, &size); - todo_wine - { - ok(err == -1, "Expected -1, got %d\n", err); - ok(GetLastError() == WSAEINVAL, "Expected 10022, got %d\n", GetLastError()); - ok(k == 99, "Expected 99, got %d\n", k); - } + ok(err == -1, "Expected -1, got %d\n", err); + ok(GetLastError() == WSAEINVAL, "Expected 10022, got %d\n", GetLastError()); + ok(k == 99, "Expected 99, got %d\n", k); } else /* <= 2003 the tests differ between TCP and UDP, UDP silently accepts */ { diff --git a/include/wine/afd.h b/include/wine/afd.h index 49bbcccd3af..43e140c91c6 100644 --- a/include/wine/afd.h +++ b/include/wine/afd.h @@ -187,7 +187,6 @@ struct afd_get_events_params #define IOCTL_AFD_WINE_SET_IP_DONTFRAGMENT WINE_AFD_IOC(243) #define IOCTL_AFD_WINE_SET_IP_DROP_MEMBERSHIP WINE_AFD_IOC(244) #define IOCTL_AFD_WINE_SET_IP_DROP_SOURCE_MEMBERSHIP WINE_AFD_IOC(245) -#define IOCTL_AFD_WINE_GET_IP_HDRINCL WINE_AFD_IOC(246) #define IOCTL_AFD_WINE_SET_IP_HDRINCL WINE_AFD_IOC(247) #define IOCTL_AFD_WINE_GET_IP_MULTICAST_IF WINE_AFD_IOC(248) #define IOCTL_AFD_WINE_SET_IP_MULTICAST_IF WINE_AFD_IOC(249)
Signed-off-by: Zebediah Figura zfigura@codeweavers.com
Windows supports none of these options on TCP. Linux supports all of them on TCP. Mac OS supports some of them on TCP, but sets EOPNOTSUPP instead of EINVAL for the ones that it doesn't support. So, Wine needs to do its own check for whether the option may be used with the socket.
Signed-off-by: Alex Henrie alexhenrie24@gmail.com --- v3: No changes --- dlls/ntdll/unix/socket.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+)
diff --git a/dlls/ntdll/unix/socket.c b/dlls/ntdll/unix/socket.c index 1ac4365c012..4523ded1be7 100644 --- a/dlls/ntdll/unix/socket.c +++ b/dlls/ntdll/unix/socket.c @@ -1200,6 +1200,14 @@ static NTSTATUS do_setsockopt( HANDLE handle, IO_STATUS_BLOCK *io, int level, }
+static BOOL is_datagram_socket( HANDLE handle, IO_STATUS_BLOCK *io ) +{ + int sock_type = -1; + do_getsockopt( handle, io, SOL_SOCKET, SO_TYPE, &sock_type, sizeof(sock_type) ); + return sock_type == SOCK_DGRAM; +} + + NTSTATUS sock_ioctl( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc_user, IO_STATUS_BLOCK *io, ULONG code, void *in_buffer, ULONG in_size, void *out_buffer, ULONG out_size ) { @@ -1767,18 +1775,23 @@ NTSTATUS sock_ioctl( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc #endif
case IOCTL_AFD_WINE_GET_IP_MULTICAST_IF: + if (!is_datagram_socket( handle, io )) return STATUS_INVALID_PARAMETER; return do_getsockopt( handle, io, IPPROTO_IP, IP_MULTICAST_IF, out_buffer, out_size );
case IOCTL_AFD_WINE_SET_IP_MULTICAST_IF: + if (!is_datagram_socket( handle, io )) return STATUS_INVALID_PARAMETER; return do_setsockopt( handle, io, IPPROTO_IP, IP_MULTICAST_IF, in_buffer, in_size );
case IOCTL_AFD_WINE_GET_IP_MULTICAST_LOOP: + if (!is_datagram_socket( handle, io )) return STATUS_INVALID_PARAMETER; return do_getsockopt( handle, io, IPPROTO_IP, IP_MULTICAST_LOOP, out_buffer, out_size );
case IOCTL_AFD_WINE_SET_IP_MULTICAST_LOOP: + if (!is_datagram_socket( handle, io )) return STATUS_INVALID_PARAMETER; return do_setsockopt( handle, io, IPPROTO_IP, IP_MULTICAST_LOOP, in_buffer, in_size );
case IOCTL_AFD_WINE_GET_IP_MULTICAST_TTL: + if (!is_datagram_socket( handle, io )) return STATUS_INVALID_PARAMETER; return do_getsockopt( handle, io, IPPROTO_IP, IP_MULTICAST_TTL, out_buffer, out_size );
case IOCTL_AFD_WINE_SET_IP_MULTICAST_TTL: @@ -1792,15 +1805,19 @@ NTSTATUS sock_ioctl( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc
#ifdef IP_PKTINFO case IOCTL_AFD_WINE_GET_IP_PKTINFO: + if (!is_datagram_socket( handle, io )) return STATUS_INVALID_PARAMETER; return do_getsockopt( handle, io, IPPROTO_IP, IP_PKTINFO, out_buffer, out_size );
case IOCTL_AFD_WINE_SET_IP_PKTINFO: + if (!is_datagram_socket( handle, io )) return STATUS_INVALID_PARAMETER; return do_setsockopt( handle, io, IPPROTO_IP, IP_PKTINFO, in_buffer, in_size ); #elif defined(IP_RECVDSTADDR) case IOCTL_AFD_WINE_GET_IP_PKTINFO: + if (!is_datagram_socket( handle, io )) return STATUS_INVALID_PARAMETER; return do_getsockopt( handle, io, IPPROTO_IP, IP_RECVDSTADDR, out_buffer, out_size );
case IOCTL_AFD_WINE_SET_IP_PKTINFO: + if (!is_datagram_socket( handle, io )) return STATUS_INVALID_PARAMETER; return do_setsockopt( handle, io, IPPROTO_IP, IP_RECVDSTADDR, in_buffer, in_size ); #endif
@@ -1890,18 +1907,21 @@ NTSTATUS sock_ioctl( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc #endif
case IOCTL_AFD_WINE_GET_IPV6_MULTICAST_HOPS: + if (!is_datagram_socket( handle, io )) return STATUS_INVALID_PARAMETER; return do_getsockopt( handle, io, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, out_buffer, out_size );
case IOCTL_AFD_WINE_SET_IPV6_MULTICAST_HOPS: return do_setsockopt( handle, io, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, in_buffer, in_size );
case IOCTL_AFD_WINE_GET_IPV6_MULTICAST_IF: + if (!is_datagram_socket( handle, io )) return STATUS_INVALID_PARAMETER; return do_getsockopt( handle, io, IPPROTO_IPV6, IPV6_MULTICAST_IF, out_buffer, out_size );
case IOCTL_AFD_WINE_SET_IPV6_MULTICAST_IF: return do_setsockopt( handle, io, IPPROTO_IPV6, IPV6_MULTICAST_IF, in_buffer, in_size );
case IOCTL_AFD_WINE_GET_IPV6_MULTICAST_LOOP: + if (!is_datagram_socket( handle, io )) return STATUS_INVALID_PARAMETER; return do_getsockopt( handle, io, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, out_buffer, out_size );
case IOCTL_AFD_WINE_SET_IPV6_MULTICAST_LOOP: @@ -1909,25 +1929,31 @@ NTSTATUS sock_ioctl( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc
#ifdef IPV6_RECVHOPLIMIT case IOCTL_AFD_WINE_GET_IPV6_RECVHOPLIMIT: + if (!is_datagram_socket( handle, io )) return STATUS_INVALID_PARAMETER; return do_getsockopt( handle, io, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, out_buffer, out_size );
case IOCTL_AFD_WINE_SET_IPV6_RECVHOPLIMIT: + if (!is_datagram_socket( handle, io )) return STATUS_INVALID_PARAMETER; return do_setsockopt( handle, io, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, in_buffer, in_size ); #endif
#ifdef IPV6_RECVPKTINFO case IOCTL_AFD_WINE_GET_IPV6_RECVPKTINFO: + if (!is_datagram_socket( handle, io )) return STATUS_INVALID_PARAMETER; return do_getsockopt( handle, io, IPPROTO_IPV6, IPV6_RECVPKTINFO, out_buffer, out_size );
case IOCTL_AFD_WINE_SET_IPV6_RECVPKTINFO: + if (!is_datagram_socket( handle, io )) return STATUS_INVALID_PARAMETER; return do_setsockopt( handle, io, IPPROTO_IPV6, IPV6_RECVPKTINFO, in_buffer, in_size ); #endif
#ifdef IPV6_RECVTCLASS case IOCTL_AFD_WINE_GET_IPV6_RECVTCLASS: + if (!is_datagram_socket( handle, io )) return STATUS_INVALID_PARAMETER; return do_getsockopt( handle, io, IPPROTO_IPV6, IPV6_RECVTCLASS, out_buffer, out_size );
case IOCTL_AFD_WINE_SET_IPV6_RECVTCLASS: + if (!is_datagram_socket( handle, io )) return STATUS_INVALID_PARAMETER; return do_setsockopt( handle, io, IPPROTO_IPV6, IPV6_RECVTCLASS, in_buffer, in_size ); #endif
On 8/16/21 11:58 PM, Alex Henrie wrote:
Windows supports none of these options on TCP. Linux supports all of them on TCP. Mac OS supports some of them on TCP, but sets EOPNOTSUPP instead of EINVAL for the ones that it doesn't support. So, Wine needs to do its own check for whether the option may be used with the socket.
Signed-off-by: Alex Henrie alexhenrie24@gmail.com
v3: No changes
dlls/ntdll/unix/socket.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+)
diff --git a/dlls/ntdll/unix/socket.c b/dlls/ntdll/unix/socket.c index 1ac4365c012..4523ded1be7 100644 --- a/dlls/ntdll/unix/socket.c +++ b/dlls/ntdll/unix/socket.c @@ -1200,6 +1200,14 @@ static NTSTATUS do_setsockopt( HANDLE handle, IO_STATUS_BLOCK *io, int level, }
+static BOOL is_datagram_socket( HANDLE handle, IO_STATUS_BLOCK *io ) +{
- int sock_type = -1;
- do_getsockopt( handle, io, SOL_SOCKET, SO_TYPE, &sock_type, sizeof(sock_type) );
- return sock_type == SOCK_DGRAM;
+}
- NTSTATUS sock_ioctl( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc_user, IO_STATUS_BLOCK *io, ULONG code, void *in_buffer, ULONG in_size, void *out_buffer, ULONG out_size ) {
@@ -1767,18 +1775,23 @@ NTSTATUS sock_ioctl( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc #endif
case IOCTL_AFD_WINE_GET_IP_MULTICAST_IF:
if (!is_datagram_socket( handle, io )) return STATUS_INVALID_PARAMETER; return do_getsockopt( handle, io, IPPROTO_IP, IP_MULTICAST_IF, out_buffer, out_size );
While this will do the right thing if the socket handle is invalid, it's a bit ugly. I think it'd be better to check the return value of do_getsockopt() in is_datagram_socket(), in which case you also don't need to initialize sock_type.
I also don't think it makes sense to pass the IOSB to is_datagram_socket(); I'd probably just add a dummy IOSB to is_datagram_socket() instead.
Sorry for not mentioning this last time... this was bothering me, but I couldn't put my finger on why.
Signed-off-by: Alex Henrie alexhenrie24@gmail.com --- v3: - Replace BROKEN flag with blanket broken case - Only test the options in the tables - Add IP(V6)_(ADD|DROP)_MEMBERSHIP to the tables - Remove undocumented options from the tables - Add socket option -1 (always nonexistent) to the tables --- dlls/ws2_32/tests/sock.c | 235 +++++++++++++++++++++++++++++++++------ 1 file changed, 204 insertions(+), 31 deletions(-)
diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c index 51aa0e61282..f60c9d3c75d 100644 --- a/dlls/ws2_32/tests/sock.c +++ b/dlls/ws2_32/tests/sock.c @@ -11429,45 +11429,218 @@ static void test_so_debug(void) closesocket(s); }
-static void test_set_only_options(void) +struct sockopt_validity_test { - unsigned int i; - int ret, len; - int value; - SOCKET s; + int opt; + int get_error; + BOOL get_todo; + int set_error; + BOOL set_todo; +};
- static const struct +static void do_sockopt_validity_tests(const char *type, SOCKET sock, int level, + const struct sockopt_validity_test *tests) +{ + char value[256]; + int count, rc, expected_rc, i; + + for (i = 0; tests[i].opt; i++) { - int level; - int option; + memset(value, 0, sizeof(value)); + count = sizeof(value); + + WSASetLastError(0); + rc = getsockopt(sock, level, tests[i].opt, value, &count); + expected_rc = tests[i].get_error ? SOCKET_ERROR : 0; +todo_wine_if(!tests[i].get_error && tests[i].get_todo) + ok(rc == expected_rc || broken(rc == SOCKET_ERROR && WSAGetLastError() == WSAENOPROTOOPT), + "expected getting %s option %i to return %i, got %i\n", + type, tests[i].opt, expected_rc, rc); +todo_wine_if(tests[i].get_todo) + ok(WSAGetLastError() == tests[i].get_error || broken(rc == SOCKET_ERROR && WSAGetLastError() == WSAENOPROTOOPT), + "expected getting %s option %i to cause error %i, got %i\n", + type, tests[i].opt, tests[i].get_error, WSAGetLastError()); + + if (tests[i].get_error) + continue; + + WSASetLastError(0); + rc = setsockopt(sock, level, tests[i].opt, value, count); + expected_rc = tests[i].set_error ? SOCKET_ERROR : 0; +todo_wine_if(!tests[i].set_error && tests[i].set_todo) + ok(rc == expected_rc || broken(rc == SOCKET_ERROR && WSAGetLastError() == WSAENOPROTOOPT), + "expected setting %s option %i to return %i, got %i\n", + type, tests[i].opt, expected_rc, rc); +todo_wine_if(tests[i].set_todo) + ok(WSAGetLastError() == tests[i].set_error || broken(rc == SOCKET_ERROR && WSAGetLastError() == WSAENOPROTOOPT), + "expected setting %s option %i to cause error %i, got %i\n", + type, tests[i].opt, tests[i].set_error, WSAGetLastError()); } - tests[] = +} + +static void test_sockopt_validity(void) +{ + static const struct sockopt_validity_test ipv4_tcp_tests[] = { - {IPPROTO_IP, IP_ADD_MEMBERSHIP}, - {IPPROTO_IP, IP_DROP_MEMBERSHIP}, - {IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP}, - {IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP}, + { -1, WSAENOPROTOOPT }, + { IP_OPTIONS }, + { IP_HDRINCL, WSAEINVAL, TRUE }, + { IP_TOS }, + { IP_TTL }, + { IP_MULTICAST_IF, WSAEINVAL }, + { IP_MULTICAST_TTL, WSAEINVAL }, + { IP_MULTICAST_LOOP, WSAEINVAL }, + { IP_ADD_MEMBERSHIP, WSAENOPROTOOPT }, + { IP_DROP_MEMBERSHIP, WSAENOPROTOOPT }, + { IP_DONTFRAGMENT }, + { IP_PKTINFO, WSAEINVAL }, + { IP_RECVTTL, WSAEINVAL, TRUE }, + { IP_RECEIVE_BROADCAST, WSAEINVAL, TRUE }, + { IP_RECVIF, WSAEINVAL, TRUE }, + { IP_RECVDSTADDR, WSAEINVAL, TRUE }, + { IP_IFLIST, 0, TRUE, 0, TRUE }, + { IP_UNICAST_IF }, + { IP_RTHDR, 0, TRUE, 0, TRUE }, + { IP_GET_IFLIST, WSAEINVAL, TRUE }, + { IP_RECVRTHDR, WSAEINVAL, TRUE }, + { IP_RECVTCLASS, WSAEINVAL, TRUE }, + { IP_ORIGINAL_ARRIVAL_IF, WSAEINVAL, TRUE }, + { IP_ECN, WSAEINVAL, TRUE }, + { IP_PKTINFO_EX, WSAEINVAL, TRUE }, + { IP_WFP_REDIRECT_RECORDS, WSAEINVAL, TRUE }, + { IP_WFP_REDIRECT_CONTEXT, WSAEINVAL, TRUE }, + { IP_MTU_DISCOVER, 0, TRUE, WSAEINVAL, TRUE }, + { IP_MTU, WSAENOTCONN, TRUE }, + { IP_RECVERR, WSAEINVAL, TRUE }, + { IP_USER_MTU, 0, TRUE, 0, TRUE }, + {} }; - - for (i = 0; i < ARRAY_SIZE(tests); ++i) + static const struct sockopt_validity_test ipv4_udp_tests[] = { - if (tests[i].level == IPPROTO_IPV6) - { - s = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); - if (s == INVALID_SOCKET) continue; - } - else - { - s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - } + { -1, WSAENOPROTOOPT }, + { IP_OPTIONS }, + { IP_HDRINCL, WSAEINVAL, TRUE }, + { IP_TOS }, + { IP_TTL }, + { IP_MULTICAST_IF }, + { IP_MULTICAST_TTL }, + { IP_MULTICAST_LOOP }, + { IP_ADD_MEMBERSHIP, WSAENOPROTOOPT }, + { IP_DROP_MEMBERSHIP, WSAENOPROTOOPT }, + { IP_DONTFRAGMENT }, + { IP_PKTINFO }, + { IP_RECVTTL, 0, TRUE, 0, TRUE }, + { IP_RECEIVE_BROADCAST, 0, TRUE, 0, TRUE }, + { IP_RECVIF, 0, TRUE, 0, TRUE }, + { IP_RECVDSTADDR, 0, TRUE, 0, TRUE }, + { IP_IFLIST, 0, TRUE, 0, TRUE }, + { IP_UNICAST_IF }, + { IP_RTHDR, 0, TRUE, 0, TRUE }, + { IP_GET_IFLIST, WSAEINVAL, TRUE }, + { IP_RECVRTHDR, 0, TRUE, 0, TRUE }, + { IP_RECVTCLASS, 0, TRUE, 0, TRUE }, + { IP_ORIGINAL_ARRIVAL_IF, 0, TRUE, 0, TRUE }, + { IP_ECN, 0, TRUE, 0, TRUE }, + { IP_PKTINFO_EX, 0, TRUE, 0, TRUE }, + { IP_WFP_REDIRECT_RECORDS, 0, TRUE, 0, TRUE }, + { IP_WFP_REDIRECT_CONTEXT, 0, TRUE, 0, TRUE }, + { IP_MTU_DISCOVER, 0, TRUE, WSAEINVAL, TRUE }, + { IP_MTU, WSAENOTCONN, TRUE }, + { IP_RECVERR, 0, TRUE, 0, TRUE }, + { IP_USER_MTU, 0, TRUE, 0, TRUE }, + {} + }; + static const struct sockopt_validity_test ipv6_tcp_tests[] = + { + { -1, WSAENOPROTOOPT }, + { IPV6_HOPOPTS, 0, TRUE, 0, TRUE }, + { 2, WSAEINVAL, TRUE }, + { 3, 0, TRUE, 0, TRUE }, + { IPV6_UNICAST_HOPS }, + { IPV6_MULTICAST_IF, WSAEINVAL }, + { IPV6_MULTICAST_HOPS, WSAEINVAL }, + { IPV6_MULTICAST_LOOP, WSAEINVAL }, + { IPV6_ADD_MEMBERSHIP, WSAENOPROTOOPT }, + { IPV6_DROP_MEMBERSHIP, WSAENOPROTOOPT }, + { IPV6_DONTFRAG }, + { IPV6_PKTINFO, WSAEINVAL }, + { IPV6_HOPLIMIT, WSAEINVAL }, + { IPV6_PROTECTION_LEVEL, 0, TRUE }, + { IPV6_RECVIF, WSAEINVAL, TRUE }, + { IPV6_RECVDSTADDR, WSAEINVAL, TRUE }, + { IPV6_V6ONLY }, + { IPV6_IFLIST, 0, TRUE, 0, TRUE }, + { IPV6_UNICAST_IF }, + { IPV6_RTHDR, 0, TRUE, 0, TRUE }, + { IPV6_GET_IFLIST, WSAEINVAL, TRUE }, + { IPV6_RECVRTHDR, WSAEINVAL, TRUE }, + { IPV6_RECVTCLASS, WSAEINVAL }, + { IP_ORIGINAL_ARRIVAL_IF, WSAEINVAL, TRUE }, + { IPV6_ECN, WSAEINVAL, TRUE }, + { IPV6_PKTINFO_EX, WSAEINVAL, TRUE }, + { IPV6_WFP_REDIRECT_RECORDS, WSAEINVAL, TRUE }, + { IPV6_WFP_REDIRECT_CONTEXT, WSAEINVAL, TRUE }, + { IPV6_MTU_DISCOVER, 0, TRUE, WSAEINVAL, TRUE }, + { IPV6_MTU, WSAENOTCONN, TRUE }, + { IPV6_RECVERR, WSAEINVAL, TRUE }, + { IPV6_USER_MTU, 0, TRUE, 0, TRUE }, + {} + }; + static const struct sockopt_validity_test ipv6_udp_tests[] = + { + { -1, WSAENOPROTOOPT }, + { IPV6_HOPOPTS, 0, TRUE, 0, TRUE }, + { IPV6_HDRINCL, WSAEINVAL, TRUE }, + { IPV6_UNICAST_HOPS }, + { IPV6_MULTICAST_IF }, + { IPV6_MULTICAST_HOPS }, + { IPV6_MULTICAST_LOOP }, + { IPV6_ADD_MEMBERSHIP, WSAENOPROTOOPT }, + { IPV6_DROP_MEMBERSHIP, WSAENOPROTOOPT }, + { IPV6_DONTFRAG }, + { IPV6_PKTINFO }, + { IPV6_HOPLIMIT }, + { IPV6_PROTECTION_LEVEL, 0, TRUE }, + { IPV6_RECVIF, 0, TRUE, 0, TRUE }, + { IPV6_RECVDSTADDR, 0, TRUE, 0, TRUE }, + { IPV6_V6ONLY }, + { IPV6_IFLIST, 0, TRUE, 0, TRUE }, + { IPV6_UNICAST_IF }, + { IPV6_RTHDR, 0, TRUE, 0, TRUE }, + { IPV6_GET_IFLIST, WSAEINVAL, TRUE }, + { IPV6_RECVRTHDR, 0, TRUE, 0, TRUE }, + { IPV6_RECVTCLASS }, + { IPV6_ECN, 0, TRUE, 0, TRUE }, + { IPV6_PKTINFO_EX, 0, TRUE, 0, TRUE }, + { IPV6_WFP_REDIRECT_RECORDS, 0, TRUE, 0, TRUE }, + { IPV6_WFP_REDIRECT_CONTEXT, 0, TRUE, 0, TRUE }, + { IPV6_MTU_DISCOVER, 0, TRUE, WSAEINVAL, TRUE }, + { IPV6_MTU, WSAENOTCONN, TRUE }, + { IPV6_RECVERR, 0, TRUE, 0, TRUE }, + { IPV6_USER_MTU, 0, TRUE, 0, TRUE }, + {} + }; + SOCKET sock;
- len = sizeof(value); - ret = getsockopt(s, tests[i].level, tests[i].option, (char *)&value, &len); - ok(ret == -1, "expected failure\n"); - ok(WSAGetLastError() == WSAENOPROTOOPT, "got error %u\n", WSAGetLastError()); + sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + ok(sock != INVALID_SOCKET, "failed to create socket, error %u\n", WSAGetLastError()); + do_sockopt_validity_tests("IPv4 TCP", sock, IPPROTO_IP, ipv4_tcp_tests); + closesocket(sock);
- closesocket(s); - } + sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + ok(sock != INVALID_SOCKET, "failed to create socket, error %u\n", WSAGetLastError()); + do_sockopt_validity_tests("IPv4 UDP", sock, IPPROTO_IP, ipv4_udp_tests); + closesocket(sock); + + sock = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); + ok(sock != INVALID_SOCKET, "failed to create socket, error %u\n", WSAGetLastError()); + do_sockopt_validity_tests("IPv6 TCP", sock, IPPROTO_IPV6, ipv6_tcp_tests); + closesocket(sock); + + sock = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); + ok(sock != INVALID_SOCKET, "failed to create socket, error %u\n", WSAGetLastError()); + do_sockopt_validity_tests("IPv6 UDP", sock, IPPROTO_IPV6, ipv6_udp_tests); + closesocket(sock); }
START_TEST( sock ) @@ -11487,7 +11660,7 @@ START_TEST( sock ) test_ipv6_cmsg(); test_extendedSocketOptions(); test_so_debug(); - test_set_only_options(); + test_sockopt_validity();
for (i = 0; i < ARRAY_SIZE(tests); i++) do_test(&tests[i]);
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=95692
Your paranoid android.
=== debiant2 (32 bit report) ===
ws2_32: sock.c:11460: Test succeeded inside todo block: expected getting IPv4 TCP option 2 to cause error 10022, got 10022 sock.c:11460: Test succeeded inside todo block: expected getting IPv4 UDP option 2 to cause error 10022, got 10022
=== debiant2 (32 bit Arabic:Morocco report) ===
ws2_32: sock.c:11460: Test succeeded inside todo block: expected getting IPv4 TCP option 2 to cause error 10022, got 10022 sock.c:11460: Test succeeded inside todo block: expected getting IPv4 UDP option 2 to cause error 10022, got 10022 sock.c:1135: Test failed: wait failed, error 258
=== debiant2 (32 bit German report) ===
ws2_32: sock.c:11460: Test succeeded inside todo block: expected getting IPv4 TCP option 2 to cause error 10022, got 10022 sock.c:11460: Test succeeded inside todo block: expected getting IPv4 UDP option 2 to cause error 10022, got 10022
=== debiant2 (32 bit French report) ===
ws2_32: sock.c:11460: Test succeeded inside todo block: expected getting IPv4 TCP option 2 to cause error 10022, got 10022 sock.c:11460: Test succeeded inside todo block: expected getting IPv4 UDP option 2 to cause error 10022, got 10022
=== debiant2 (32 bit Hebrew:Israel report) ===
ws2_32: sock.c:11460: Test succeeded inside todo block: expected getting IPv4 TCP option 2 to cause error 10022, got 10022 sock.c:11460: Test succeeded inside todo block: expected getting IPv4 UDP option 2 to cause error 10022, got 10022
=== debiant2 (32 bit Hindi:India report) ===
ws2_32: sock.c:11460: Test succeeded inside todo block: expected getting IPv4 TCP option 2 to cause error 10022, got 10022 sock.c:11460: Test succeeded inside todo block: expected getting IPv4 UDP option 2 to cause error 10022, got 10022
=== debiant2 (32 bit Japanese:Japan report) ===
ws2_32: sock.c:11460: Test succeeded inside todo block: expected getting IPv4 TCP option 2 to cause error 10022, got 10022 sock.c:11460: Test succeeded inside todo block: expected getting IPv4 UDP option 2 to cause error 10022, got 10022
=== debiant2 (32 bit Chinese:China report) ===
ws2_32: sock.c:11460: Test succeeded inside todo block: expected getting IPv4 TCP option 2 to cause error 10022, got 10022 sock.c:11460: Test succeeded inside todo block: expected getting IPv4 UDP option 2 to cause error 10022, got 10022
=== debiant2 (32 bit WoW report) ===
ws2_32: sock.c:11460: Test succeeded inside todo block: expected getting IPv4 TCP option 2 to cause error 10022, got 10022 sock.c:11460: Test succeeded inside todo block: expected getting IPv4 UDP option 2 to cause error 10022, got 10022
=== debiant2 (64 bit WoW report) ===
ws2_32: sock.c:11460: Test succeeded inside todo block: expected getting IPv4 TCP option 2 to cause error 10022, got 10022 sock.c:11460: Test succeeded inside todo block: expected getting IPv4 UDP option 2 to cause error 10022, got 10022
On 8/16/21 11:58 PM, Alex Henrie wrote:
Signed-off-by: Alex Henrie alexhenrie24@gmail.com
v3:
- Replace BROKEN flag with blanket broken case
- Only test the options in the tables
- Add IP(V6)_(ADD|DROP)_MEMBERSHIP to the tables
- Remove undocumented options from the tables
- Add socket option -1 (always nonexistent) to the tables
dlls/ws2_32/tests/sock.c | 235 +++++++++++++++++++++++++++++++++------ 1 file changed, 204 insertions(+), 31 deletions(-)
Looks a lot better, thanks. Since I've already added a comment to patch 3 I'll just add one here as well:
diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c index 51aa0e61282..f60c9d3c75d 100644 --- a/dlls/ws2_32/tests/sock.c +++ b/dlls/ws2_32/tests/sock.c @@ -11429,45 +11429,218 @@ static void test_so_debug(void) closesocket(s); }
-static void test_set_only_options(void) +struct sockopt_validity_test {
- unsigned int i;
- int ret, len;
- int value;
- SOCKET s;
- int opt;
- int get_error;
- BOOL get_todo;
- int set_error;
- BOOL set_todo;
+};
- static const struct
+static void do_sockopt_validity_tests(const char *type, SOCKET sock, int level,
const struct sockopt_validity_test *tests)
+{
- char value[256];
- int count, rc, expected_rc, i;
- for (i = 0; tests[i].opt; i++) {
int level;
int option;
memset(value, 0, sizeof(value));
count = sizeof(value);
WSASetLastError(0);
rc = getsockopt(sock, level, tests[i].opt, value, &count);
expected_rc = tests[i].get_error ? SOCKET_ERROR : 0;
+todo_wine_if(!tests[i].get_error && tests[i].get_todo)
ok(rc == expected_rc || broken(rc == SOCKET_ERROR && WSAGetLastError() == WSAENOPROTOOPT),
"expected getting %s option %i to return %i, got %i\n",
type, tests[i].opt, expected_rc, rc);
You could consider simplifying these messages a bit with winetest_push_context()/winetest_pop_context().