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
}
case IOCTL_AFD_WINE_GETPEERNAME:
{
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;
}
if (in_size) FIXME( "unexpected input size %u\n", in_size );
len = sockaddr_from_unix( &unix_addr, out_buffer, out_size );
if (out_size < len)
{
status = STATUS_BUFFER_TOO_SMALL;
break;
}
io->Information = len;
status = STATUS_SUCCESS;
status = STATUS_BAD_DEVICE_TYPE;
break;
}
case IOCTL_AFD_WINE_GET_SO_BROADCAST:
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 )
{
IO_STATUS_BLOCK io;
NTSTATUS status;
int safe_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 )
return -1;
}
if (!len)
{
SetLastError( WSAEFAULT );
return -1;
}
/* Windows checks the validity of the socket before checking len, so
* let wineserver do the same. Since len being NULL and *len being 0
* yield the same error, we can substitute in 0 if len is NULL. */
if (len)
safe_len = *len;
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)
*len = io.Information;
SetLastError( NtStatusToWSAError( status ) );
......
......@@ -9329,16 +9329,16 @@ static void test_shutdown(void)
addrlen = sizeof(addr);
ret = getpeername(client, (struct sockaddr *)&addr, &addrlen);
todo_wine ok(!ret, "got error %u\n", WSAGetLastError());
todo_wine ok(!memcmp(&addr, &server_addr, sizeof(server_addr)), "address didn't match\n");
ok(!ret, "got error %u\n", WSAGetLastError());
ok(!memcmp(&addr, &server_addr, sizeof(server_addr)), "address didn't match\n");
addrlen = sizeof(client_addr);
ret = getsockname(client, (struct sockaddr *)&client_addr, &addrlen);
ok(!ret, "got error %u\n", WSAGetLastError());
addrlen = sizeof(addr);
ret = getpeername(server, (struct sockaddr *)&addr, &addrlen);
todo_wine ok(!ret, "got error %u\n", WSAGetLastError());
todo_wine ok(!memcmp(&addr, &client_addr, sizeof(addr)), "address didn't match\n");
ok(!ret, "got error %u\n", WSAGetLastError());
ok(!memcmp(&addr, &client_addr, sizeof(addr)), "address didn't match\n");
WSASetLastError(0xdeadbeef);
ret = connect(client, (struct sockaddr *)&server_addr, sizeof(server_addr));
......@@ -9397,16 +9397,16 @@ static void test_shutdown(void)
addrlen = sizeof(addr);
ret = getpeername(client, (struct sockaddr *)&addr, &addrlen);
todo_wine ok(!ret, "got error %u\n", WSAGetLastError());
todo_wine ok(!memcmp(&addr, &server_addr, sizeof(server_addr)), "address didn't match\n");
ok(!ret, "got error %u\n", WSAGetLastError());
ok(!memcmp(&addr, &server_addr, sizeof(server_addr)), "address didn't match\n");
addrlen = sizeof(client_addr);
ret = getsockname(client, (struct sockaddr *)&client_addr, &addrlen);
ok(!ret, "got error %u\n", WSAGetLastError());
addrlen = sizeof(addr);
ret = getpeername(server, (struct sockaddr *)&addr, &addrlen);
todo_wine ok(!ret, "got error %u\n", WSAGetLastError());
todo_wine ok(!memcmp(&addr, &client_addr, sizeof(addr)), "address didn't match\n");
ok(!ret, "got error %u\n", WSAGetLastError());
ok(!memcmp(&addr, &client_addr, sizeof(addr)), "address didn't match\n");
closesocket(client);
closesocket(server);
......@@ -9913,7 +9913,7 @@ static void test_getpeername(void)
ret = getpeername(sock, NULL, NULL);
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());
memset(&sa, 0, sizeof(sa));
......@@ -9928,7 +9928,7 @@ static void test_getpeername(void)
ret = getpeername(sock, NULL, NULL);
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());
ret = connect(sock, (struct sockaddr*)&sa, sizeof(sa));
......@@ -12629,13 +12629,7 @@ static void test_connecting_socket(void)
len = sizeof(addr);
ret = getpeername(client, (struct sockaddr *)&addr, &len);
todo_wine 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");
}
ok(!ret, "got error %u\n", WSAGetLastError());
ret = recv(client, buffer, sizeof(buffer), 0);
ok(ret == -1, "got %d\n", ret);
......
......@@ -242,6 +242,8 @@ struct sock
struct poll_req *main_poll; /* main poll */
union win_sockaddr addr; /* socket name */
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 sndbuf; /* advisory send buffer size */
unsigned int rcvtimeo; /* receive timeout in ms */
......@@ -1728,6 +1730,8 @@ static struct sock *create_socket(void)
sock->main_poll = NULL;
memset( &sock->addr, 0, sizeof(sock->addr) );
sock->addr_len = 0;
memset( &sock->peer_addr, 0, sizeof(sock->peer_addr) );
sock->peer_addr_len = 0;
sock->rd_shutdown = 0;
sock->wr_shutdown = 0;
sock->wr_shutdown_pending = 0;
......@@ -2037,8 +2041,15 @@ static struct sock *accept_socket( struct sock *sock )
}
unix_len = sizeof(unix_addr);
if (!getsockname( acceptfd, &unix_addr.addr, &unix_len ))
{
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();
sock->pending_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 )
unix_len = sizeof(unix_addr);
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) );
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();
sock->pending_events &= ~AFD_POLL_ACCEPT;
......@@ -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 WS_sockaddr *addr;
union unix_sockaddr unix_addr;
union unix_sockaddr unix_addr, peer_addr;
struct connect_req *req;
socklen_t unix_len;
int send_len, ret;
......@@ -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 ))
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 );
if (ret < 0 && errno == ECONNABORTED)
{
......@@ -2652,8 +2670,10 @@ static void sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async )
allow_fd_caching( sock->fd );
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->peer_addr_len = sockaddr_from_unix( &peer_addr, &sock->peer_addr.addr, sizeof(sock->peer_addr));
sock->bound = 1;
if (!ret)
......@@ -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 );
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:
{
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