Commit 3582ba9d authored by Ally Sommers's avatar Ally Sommers Committed by Alexandre Julliard

server: Move getpeername() implementation from ntdll/unix.

This brings getpeername() in line with getsockname(), which is also implemented in wineserver. It also allows getpeername() to return a possibly-more-accurate peer name, as in the case of AF_UNIX sockets.
parent 4b9a095e
...@@ -1939,30 +1939,10 @@ NTSTATUS sock_ioctl( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc ...@@ -1939,30 +1939,10 @@ NTSTATUS sock_ioctl( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc
} }
case IOCTL_AFD_WINE_GETPEERNAME: case IOCTL_AFD_WINE_GETPEERNAME:
{ if (in_size) FIXME( "unexpected input size %u\n", in_size );
union unix_sockaddr unix_addr;
socklen_t unix_len = sizeof(unix_addr);
int len;
if ((status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL )))
return status;
if (getpeername( fd, &unix_addr.addr, &unix_len ) < 0)
{
status = sock_errno_to_status( errno );
break;
}
len = sockaddr_from_unix( &unix_addr, out_buffer, out_size ); status = STATUS_BAD_DEVICE_TYPE;
if (out_size < len)
{
status = STATUS_BUFFER_TOO_SMALL;
break;
}
io->Information = len;
status = STATUS_SUCCESS;
break; break;
}
case IOCTL_AFD_WINE_GET_SO_BROADCAST: case IOCTL_AFD_WINE_GET_SO_BROADCAST:
return do_getsockopt( handle, io, SOL_SOCKET, SO_BROADCAST, out_buffer, out_size ); return do_getsockopt( handle, io, SOL_SOCKET, SO_BROADCAST, out_buffer, out_size );
......
...@@ -1514,6 +1514,7 @@ int WINAPI getpeername( SOCKET s, struct sockaddr *addr, int *len ) ...@@ -1514,6 +1514,7 @@ int WINAPI getpeername( SOCKET s, struct sockaddr *addr, int *len )
{ {
IO_STATUS_BLOCK io; IO_STATUS_BLOCK io;
NTSTATUS status; NTSTATUS status;
int safe_len = 0;
TRACE( "socket %#Ix, addr %p, len %d\n", s, addr, len ? *len : 0 ); TRACE( "socket %#Ix, addr %p, len %d\n", s, addr, len ? *len : 0 );
...@@ -1523,14 +1524,14 @@ int WINAPI getpeername( SOCKET s, struct sockaddr *addr, int *len ) ...@@ -1523,14 +1524,14 @@ int WINAPI getpeername( SOCKET s, struct sockaddr *addr, int *len )
return -1; return -1;
} }
if (!len) /* Windows checks the validity of the socket before checking len, so
{ * let wineserver do the same. Since len being NULL and *len being 0
SetLastError( WSAEFAULT ); * yield the same error, we can substitute in 0 if len is NULL. */
return -1; if (len)
} safe_len = *len;
status = NtDeviceIoControlFile( (HANDLE)s, NULL, NULL, NULL, &io, status = NtDeviceIoControlFile( (HANDLE)s, NULL, NULL, NULL, &io,
IOCTL_AFD_WINE_GETPEERNAME, NULL, 0, addr, *len ); IOCTL_AFD_WINE_GETPEERNAME, NULL, 0, addr, safe_len );
if (!status) if (!status)
*len = io.Information; *len = io.Information;
SetLastError( NtStatusToWSAError( status ) ); SetLastError( NtStatusToWSAError( status ) );
......
...@@ -9329,16 +9329,16 @@ static void test_shutdown(void) ...@@ -9329,16 +9329,16 @@ static void test_shutdown(void)
addrlen = sizeof(addr); addrlen = sizeof(addr);
ret = getpeername(client, (struct sockaddr *)&addr, &addrlen); ret = getpeername(client, (struct sockaddr *)&addr, &addrlen);
todo_wine ok(!ret, "got error %u\n", WSAGetLastError()); ok(!ret, "got error %u\n", WSAGetLastError());
todo_wine ok(!memcmp(&addr, &server_addr, sizeof(server_addr)), "address didn't match\n"); ok(!memcmp(&addr, &server_addr, sizeof(server_addr)), "address didn't match\n");
addrlen = sizeof(client_addr); addrlen = sizeof(client_addr);
ret = getsockname(client, (struct sockaddr *)&client_addr, &addrlen); ret = getsockname(client, (struct sockaddr *)&client_addr, &addrlen);
ok(!ret, "got error %u\n", WSAGetLastError()); ok(!ret, "got error %u\n", WSAGetLastError());
addrlen = sizeof(addr); addrlen = sizeof(addr);
ret = getpeername(server, (struct sockaddr *)&addr, &addrlen); ret = getpeername(server, (struct sockaddr *)&addr, &addrlen);
todo_wine ok(!ret, "got error %u\n", WSAGetLastError()); ok(!ret, "got error %u\n", WSAGetLastError());
todo_wine ok(!memcmp(&addr, &client_addr, sizeof(addr)), "address didn't match\n"); ok(!memcmp(&addr, &client_addr, sizeof(addr)), "address didn't match\n");
WSASetLastError(0xdeadbeef); WSASetLastError(0xdeadbeef);
ret = connect(client, (struct sockaddr *)&server_addr, sizeof(server_addr)); ret = connect(client, (struct sockaddr *)&server_addr, sizeof(server_addr));
...@@ -9397,16 +9397,16 @@ static void test_shutdown(void) ...@@ -9397,16 +9397,16 @@ static void test_shutdown(void)
addrlen = sizeof(addr); addrlen = sizeof(addr);
ret = getpeername(client, (struct sockaddr *)&addr, &addrlen); ret = getpeername(client, (struct sockaddr *)&addr, &addrlen);
todo_wine ok(!ret, "got error %u\n", WSAGetLastError()); ok(!ret, "got error %u\n", WSAGetLastError());
todo_wine ok(!memcmp(&addr, &server_addr, sizeof(server_addr)), "address didn't match\n"); ok(!memcmp(&addr, &server_addr, sizeof(server_addr)), "address didn't match\n");
addrlen = sizeof(client_addr); addrlen = sizeof(client_addr);
ret = getsockname(client, (struct sockaddr *)&client_addr, &addrlen); ret = getsockname(client, (struct sockaddr *)&client_addr, &addrlen);
ok(!ret, "got error %u\n", WSAGetLastError()); ok(!ret, "got error %u\n", WSAGetLastError());
addrlen = sizeof(addr); addrlen = sizeof(addr);
ret = getpeername(server, (struct sockaddr *)&addr, &addrlen); ret = getpeername(server, (struct sockaddr *)&addr, &addrlen);
todo_wine ok(!ret, "got error %u\n", WSAGetLastError()); ok(!ret, "got error %u\n", WSAGetLastError());
todo_wine ok(!memcmp(&addr, &client_addr, sizeof(addr)), "address didn't match\n"); ok(!memcmp(&addr, &client_addr, sizeof(addr)), "address didn't match\n");
closesocket(client); closesocket(client);
closesocket(server); closesocket(server);
...@@ -9913,7 +9913,7 @@ static void test_getpeername(void) ...@@ -9913,7 +9913,7 @@ static void test_getpeername(void)
ret = getpeername(sock, NULL, NULL); ret = getpeername(sock, NULL, NULL);
ok(ret == SOCKET_ERROR, "Expected getpeername to return SOCKET_ERROR, got %d\n", ret); ok(ret == SOCKET_ERROR, "Expected getpeername to return SOCKET_ERROR, got %d\n", ret);
todo_wine ok(WSAGetLastError() == WSAENOTCONN, ok(WSAGetLastError() == WSAENOTCONN,
"Expected WSAGetLastError() to return WSAENOTCONN, got %d\n", WSAGetLastError()); "Expected WSAGetLastError() to return WSAENOTCONN, got %d\n", WSAGetLastError());
memset(&sa, 0, sizeof(sa)); memset(&sa, 0, sizeof(sa));
...@@ -9928,7 +9928,7 @@ static void test_getpeername(void) ...@@ -9928,7 +9928,7 @@ static void test_getpeername(void)
ret = getpeername(sock, NULL, NULL); ret = getpeername(sock, NULL, NULL);
ok(ret == SOCKET_ERROR, "Expected getpeername to return SOCKET_ERROR, got %d\n", ret); ok(ret == SOCKET_ERROR, "Expected getpeername to return SOCKET_ERROR, got %d\n", ret);
todo_wine ok(WSAGetLastError() == WSAENOTCONN, ok(WSAGetLastError() == WSAENOTCONN,
"Expected WSAGetLastError() to return WSAENOTCONN, got %d\n", WSAGetLastError()); "Expected WSAGetLastError() to return WSAENOTCONN, got %d\n", WSAGetLastError());
ret = connect(sock, (struct sockaddr*)&sa, sizeof(sa)); ret = connect(sock, (struct sockaddr*)&sa, sizeof(sa));
...@@ -12629,13 +12629,7 @@ static void test_connecting_socket(void) ...@@ -12629,13 +12629,7 @@ static void test_connecting_socket(void)
len = sizeof(addr); len = sizeof(addr);
ret = getpeername(client, (struct sockaddr *)&addr, &len); ret = getpeername(client, (struct sockaddr *)&addr, &len);
todo_wine ok(!ret, "got error %u\n", WSAGetLastError()); ok(!ret, "got error %u\n", WSAGetLastError());
if (!ret)
{
ok(addr.sin_family == AF_INET, "got family %u\n", addr.sin_family);
ok(addr.sin_addr.s_addr == inet_addr("192.0.2.0"), "got address %#08lx\n", addr.sin_addr.s_addr);
ok(addr.sin_port == 255, "expected nonzero port\n");
}
ret = recv(client, buffer, sizeof(buffer), 0); ret = recv(client, buffer, sizeof(buffer), 0);
ok(ret == -1, "got %d\n", ret); ok(ret == -1, "got %d\n", ret);
......
...@@ -242,6 +242,8 @@ struct sock ...@@ -242,6 +242,8 @@ struct sock
struct poll_req *main_poll; /* main poll */ struct poll_req *main_poll; /* main poll */
union win_sockaddr addr; /* socket name */ union win_sockaddr addr; /* socket name */
int addr_len; /* socket name length */ int addr_len; /* socket name length */
union win_sockaddr peer_addr; /* peer name */
int peer_addr_len; /* peer name length */
unsigned int rcvbuf; /* advisory recv buffer size */ unsigned int rcvbuf; /* advisory recv buffer size */
unsigned int sndbuf; /* advisory send buffer size */ unsigned int sndbuf; /* advisory send buffer size */
unsigned int rcvtimeo; /* receive timeout in ms */ unsigned int rcvtimeo; /* receive timeout in ms */
...@@ -1728,6 +1730,8 @@ static struct sock *create_socket(void) ...@@ -1728,6 +1730,8 @@ static struct sock *create_socket(void)
sock->main_poll = NULL; sock->main_poll = NULL;
memset( &sock->addr, 0, sizeof(sock->addr) ); memset( &sock->addr, 0, sizeof(sock->addr) );
sock->addr_len = 0; sock->addr_len = 0;
memset( &sock->peer_addr, 0, sizeof(sock->peer_addr) );
sock->peer_addr_len = 0;
sock->rd_shutdown = 0; sock->rd_shutdown = 0;
sock->wr_shutdown = 0; sock->wr_shutdown = 0;
sock->wr_shutdown_pending = 0; sock->wr_shutdown_pending = 0;
...@@ -2037,8 +2041,15 @@ static struct sock *accept_socket( struct sock *sock ) ...@@ -2037,8 +2041,15 @@ static struct sock *accept_socket( struct sock *sock )
} }
unix_len = sizeof(unix_addr); unix_len = sizeof(unix_addr);
if (!getsockname( acceptfd, &unix_addr.addr, &unix_len )) if (!getsockname( acceptfd, &unix_addr.addr, &unix_len ))
{
acceptsock->addr_len = sockaddr_from_unix( &unix_addr, &acceptsock->addr.addr, sizeof(acceptsock->addr) ); acceptsock->addr_len = sockaddr_from_unix( &unix_addr, &acceptsock->addr.addr, sizeof(acceptsock->addr) );
if (!getpeername( acceptfd, &unix_addr.addr, &unix_len ))
acceptsock->peer_addr_len = sockaddr_from_unix( &unix_addr,
&acceptsock->peer_addr.addr,
sizeof(acceptsock->peer_addr) );
}
} }
clear_error(); clear_error();
sock->pending_events &= ~AFD_POLL_ACCEPT; sock->pending_events &= ~AFD_POLL_ACCEPT;
sock->reported_events &= ~AFD_POLL_ACCEPT; sock->reported_events &= ~AFD_POLL_ACCEPT;
...@@ -2093,7 +2104,13 @@ static int accept_into_socket( struct sock *sock, struct sock *acceptsock ) ...@@ -2093,7 +2104,13 @@ static int accept_into_socket( struct sock *sock, struct sock *acceptsock )
unix_len = sizeof(unix_addr); unix_len = sizeof(unix_addr);
if (!getsockname( get_unix_fd( newfd ), &unix_addr.addr, &unix_len )) if (!getsockname( get_unix_fd( newfd ), &unix_addr.addr, &unix_len ))
{
acceptsock->addr_len = sockaddr_from_unix( &unix_addr, &acceptsock->addr.addr, sizeof(acceptsock->addr) ); acceptsock->addr_len = sockaddr_from_unix( &unix_addr, &acceptsock->addr.addr, sizeof(acceptsock->addr) );
if (!getpeername( get_unix_fd( newfd ), &unix_addr.addr, &unix_len ))
acceptsock->peer_addr_len = sockaddr_from_unix( &unix_addr,
&acceptsock->peer_addr.addr,
sizeof(acceptsock->peer_addr) );
}
clear_error(); clear_error();
sock->pending_events &= ~AFD_POLL_ACCEPT; sock->pending_events &= ~AFD_POLL_ACCEPT;
...@@ -2568,7 +2585,7 @@ static void sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async ) ...@@ -2568,7 +2585,7 @@ static void sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async )
{ {
const struct afd_connect_params *params = get_req_data(); const struct afd_connect_params *params = get_req_data();
const struct WS_sockaddr *addr; const struct WS_sockaddr *addr;
union unix_sockaddr unix_addr; union unix_sockaddr unix_addr, peer_addr;
struct connect_req *req; struct connect_req *req;
socklen_t unix_len; socklen_t unix_len;
int send_len, ret; int send_len, ret;
...@@ -2630,6 +2647,7 @@ static void sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async ) ...@@ -2630,6 +2647,7 @@ static void sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async )
if (unix_addr.addr.sa_family == AF_INET && !memcmp( &unix_addr.in.sin_addr, magic_loopback_addr, 4 )) if (unix_addr.addr.sa_family == AF_INET && !memcmp( &unix_addr.in.sin_addr, magic_loopback_addr, 4 ))
unix_addr.in.sin_addr.s_addr = htonl( INADDR_LOOPBACK ); unix_addr.in.sin_addr.s_addr = htonl( INADDR_LOOPBACK );
memcpy( &peer_addr, &unix_addr, sizeof(unix_addr) );
ret = connect( unix_fd, &unix_addr.addr, unix_len ); ret = connect( unix_fd, &unix_addr.addr, unix_len );
if (ret < 0 && errno == ECONNABORTED) if (ret < 0 && errno == ECONNABORTED)
{ {
...@@ -2652,8 +2670,10 @@ static void sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async ) ...@@ -2652,8 +2670,10 @@ static void sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async )
allow_fd_caching( sock->fd ); allow_fd_caching( sock->fd );
unix_len = sizeof(unix_addr); unix_len = sizeof(unix_addr);
if (!getsockname( unix_fd, &unix_addr.addr, &unix_len )) getsockname( unix_fd, &unix_addr.addr, &unix_len );
sock->addr_len = sockaddr_from_unix( &unix_addr, &sock->addr.addr, sizeof(sock->addr) ); sock->addr_len = sockaddr_from_unix( &unix_addr, &sock->addr.addr, sizeof(sock->addr) );
sock->peer_addr_len = sockaddr_from_unix( &peer_addr, &sock->peer_addr.addr, sizeof(sock->peer_addr));
sock->bound = 1; sock->bound = 1;
if (!ret) if (!ret)
...@@ -2988,6 +3008,41 @@ static void sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async ) ...@@ -2988,6 +3008,41 @@ static void sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async )
set_reply_data( &sock->addr, sock->addr_len ); set_reply_data( &sock->addr, sock->addr_len );
return; return;
case IOCTL_AFD_WINE_GETPEERNAME:
if (sock->state != SOCK_CONNECTED &&
sock->state != SOCK_CONNECTING &&
sock->state != SOCK_CONNECTIONLESS)
{
set_error( STATUS_INVALID_CONNECTION );
return;
}
/* If ConnectEx() hasn't finished connecting (or failing to connect) the provided
* socket, getpeername() can't be called on it. This seems to be undocumented
* and is *not* the case for connect(), but we do test for it in ws2_32.
* connect_req is non-NULL iff ConnectEx() was used and has not finished,
* so we can use it as a check for ConnectEx() usage here. */
if (sock->connect_req)
{
set_error( STATUS_INVALID_CONNECTION );
return;
}
if (!sock->peer_addr_len && sock->type == WS_SOCK_DGRAM)
{
set_error( STATUS_INVALID_CONNECTION );
return;
}
if (get_reply_max_size() < sock->peer_addr_len)
{
set_error( STATUS_BUFFER_TOO_SMALL );
return;
}
set_reply_data( &sock->peer_addr, sock->peer_addr_len );
return;
case IOCTL_AFD_WINE_DEFER: case IOCTL_AFD_WINE_DEFER:
{ {
const obj_handle_t *handle = get_req_data(); const obj_handle_t *handle = get_req_data();
......
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