Commit d1f5765e authored by Julian Klemann's avatar Julian Klemann Committed by Alexandre Julliard

ws2_32: Add WSAConnectByName() functions.

parent ff31e132
......@@ -1284,6 +1284,174 @@ static BOOL WINAPI WS2_ConnectEx( SOCKET s, const struct sockaddr *name, int nam
}
/***********************************************************************
* WSAConnectByNameA (WS2_32.@)
*/
BOOL WINAPI WSAConnectByNameA(SOCKET s, const char *node_name, const char *service_name,
DWORD *local_addr_len, struct sockaddr *local_addr,
DWORD *remote_addr_len, struct sockaddr *remote_addr,
const struct timeval *timeout, WSAOVERLAPPED *reserved)
{
WSAPROTOCOL_INFOA proto_info;
WSAPOLLFD pollout;
struct addrinfo *service, hints;
int ret, proto_len, sockaddr_size, sockname_size, sock_err, int_len;
TRACE("socket %#Ix, node_name %s, service_name %s, local_addr_len %p, local_addr %p, \
remote_addr_len %p, remote_addr %p, timeout %p, reserved %p\n",
s, debugstr_a(node_name), debugstr_a(service_name), local_addr_len, local_addr,
remote_addr_len, remote_addr, timeout, reserved );
if (!node_name || !service_name || reserved)
{
SetLastError(WSAEINVAL);
return FALSE;
}
if (!s)
{
SetLastError(WSAENOTSOCK);
return FALSE;
}
if (timeout)
FIXME("WSAConnectByName timeout stub\n");
proto_len = sizeof(WSAPROTOCOL_INFOA);
ret = getsockopt(s, SOL_SOCKET, SO_PROTOCOL_INFOA, (char *)&proto_info, &proto_len);
if (ret)
return FALSE;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_socktype = proto_info.iSocketType;
hints.ai_family = proto_info.iAddressFamily;
hints.ai_protocol = proto_info.iProtocol;
ret = getaddrinfo(node_name, service_name, &hints, &service);
if (ret)
return FALSE;
if (proto_info.iSocketType != SOCK_STREAM)
{
freeaddrinfo(service);
SetLastError(WSAEFAULT);
return FALSE;
}
switch (proto_info.iAddressFamily)
{
case AF_INET:
sockaddr_size = sizeof(SOCKADDR_IN);
break;
case AF_INET6:
sockaddr_size = sizeof(SOCKADDR_IN6);
break;
default:
freeaddrinfo(service);
SetLastError(WSAENOTSOCK);
return FALSE;
}
ret = connect(s, service->ai_addr, sockaddr_size);
if (ret)
{
freeaddrinfo(service);
return FALSE;
}
pollout.fd = s;
pollout.events = POLLWRNORM;
ret = WSAPoll(&pollout, 1, -1);
if (ret == SOCKET_ERROR)
{
freeaddrinfo(service);
return FALSE;
}
if (pollout.revents & (POLLERR | POLLHUP | POLLNVAL))
{
freeaddrinfo(service);
int_len = sizeof(int);
ret = getsockopt(s, SOL_SOCKET, SO_ERROR, (char *)&sock_err, &int_len);
if (ret == SOCKET_ERROR)
return FALSE;
SetLastError(sock_err);
return FALSE;
}
if (remote_addr_len && remote_addr)
{
if (*remote_addr_len >= sockaddr_size)
{
memcpy(remote_addr, service->ai_addr, sockaddr_size);
*remote_addr_len = sockaddr_size;
}
else
{
freeaddrinfo(service);
SetLastError(WSAEFAULT);
return FALSE;
}
}
freeaddrinfo(service);
if (local_addr_len && local_addr)
{
if (*local_addr_len >= sockaddr_size)
{
sockname_size = sockaddr_size;
ret = getsockname(s, local_addr, &sockname_size);
if (ret)
return FALSE;
if (proto_info.iAddressFamily == AF_INET6)
((SOCKADDR_IN6 *)local_addr)->sin6_port = 0;
else
((SOCKADDR_IN *)local_addr)->sin_port = 0;
*local_addr_len = sockaddr_size;
}
else
{
SetLastError(WSAEFAULT);
return FALSE;
}
}
return TRUE;
}
/***********************************************************************
* WSAConnectByNameW (WS2_32.@)
*/
BOOL WINAPI WSAConnectByNameW(SOCKET s, const WCHAR *node_name, const WCHAR *service_name,
DWORD *local_addr_len, struct sockaddr *local_addr,
DWORD *remote_addr_len, struct sockaddr *remote_addr,
const struct timeval *timeout, WSAOVERLAPPED *reserved)
{
char *node_nameA, *service_nameA;
BOOL ret;
if (!node_name || !service_name)
{
SetLastError(WSAEINVAL);
return FALSE;
}
node_nameA = strdupWtoA(node_name);
service_nameA = strdupWtoA(service_name);
if (!node_nameA || !service_nameA)
{
SetLastError(WSAENOBUFS);
return FALSE;
}
ret = WSAConnectByNameA(s, node_nameA, service_nameA, local_addr_len, local_addr,
remote_addr_len, remote_addr, timeout, reserved);
free(node_nameA);
free(service_nameA);
return ret;
}
static BOOL WINAPI WS2_DisconnectEx( SOCKET s, OVERLAPPED *overlapped, DWORD flags, DWORD reserved )
{
IO_STATUS_BLOCK iosb, *piosb = &iosb;
......
......@@ -3197,6 +3197,156 @@ static void test_WSADuplicateSocket(void)
closesocket(source);
}
static void test_WSAConnectByName(void)
{
SOCKET s;
SOCKADDR_IN local_addr = {0}, remote_addr = {0},
sock_addr = {0}, peer_addr = {0};
DWORD local_len, remote_len, conn_ctx;
int ret, err, sock_len, peer_len;
WSAOVERLAPPED overlap;
struct addrinfo *first_addrinfo, first_hints;
conn_ctx = TRUE;
/* First call of getaddrinfo fails on w8adm */
first_addrinfo = NULL;
memset(&first_hints, 0, sizeof(struct addrinfo));
first_hints.ai_socktype = SOCK_STREAM;
first_hints.ai_family = AF_INET;
first_hints.ai_protocol = IPPROTO_TCP;
getaddrinfo("winehq.org", "http", &first_hints, &first_addrinfo);
if (first_addrinfo)
freeaddrinfo(first_addrinfo);
SetLastError(0xdeadbeef);
/* Fill all fields */
s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
local_len = remote_len = sizeof(SOCKADDR_IN);
ret = WSAConnectByNameA(s, "winehq.org", "http", &local_len, (struct sockaddr *)&local_addr,
&remote_len, (struct sockaddr *)&remote_addr, NULL, NULL);
ok(ret, "WSAConnectByNameA should have succeeded, error %u\n", WSAGetLastError());
setsockopt(s, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, (char *)&conn_ctx, sizeof(DWORD));
sock_len = peer_len = sizeof(SOCKADDR_IN);
ret = getsockname(s, (struct sockaddr *)&sock_addr, &sock_len);
ok(!ret, "getsockname should have succeeded, error %u\n", WSAGetLastError());
ret = getpeername(s, (struct sockaddr *)&peer_addr, &peer_len);
ok(!ret, "getpeername should have succeeded, error %u\n", WSAGetLastError());
ok(sock_len == sizeof(SOCKADDR_IN), "got sockname size of %d\n", sock_len);
ok(peer_len == sizeof(SOCKADDR_IN), "got peername size of %d\n", peer_len);
ok(local_len == sizeof(SOCKADDR_IN), "got local size of %lu\n", local_len);
ok(remote_len == sizeof(SOCKADDR_IN), "got remote size of %lu\n", remote_len);
ok(!local_addr.sin_port, "local_addr has non-zero sin_port: %hu.\n", local_addr.sin_port);
ok(!memcmp(&sock_addr.sin_addr, &local_addr.sin_addr, sizeof(struct in_addr)),
"local_addr did not receive data.\n");
ok(!memcmp(&peer_addr, &remote_addr, sizeof(SOCKADDR_IN)), "remote_addr did not receive data.\n");
closesocket(s);
/* Passing NULL length but a pointer to a sockaddr */
s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
local_len = remote_len = sizeof(SOCKADDR_IN);
memset(&local_addr, 0, sizeof(SOCKADDR_IN));
memset(&remote_addr, 0, sizeof(SOCKADDR_IN));
memset(&sock_addr, 0, sizeof(SOCKADDR_IN));
memset(&peer_addr, 0, sizeof(SOCKADDR_IN));
ret = WSAConnectByNameA(s, "winehq.org", "http", NULL, (struct sockaddr *)&local_addr,
NULL, (struct sockaddr *)&remote_addr, NULL, NULL);
ok(ret, "WSAConnectByNameA should have succeeded, error %u\n", WSAGetLastError());
setsockopt(s, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, (char *)&conn_ctx, sizeof(DWORD));
sock_len = peer_len = sizeof(SOCKADDR_IN);
ret = getsockname(s, (struct sockaddr *)&sock_addr, &sock_len);
ok(!ret, "getsockname should have succeeded, error %u\n", WSAGetLastError());
ret = getpeername(s, (struct sockaddr *)&peer_addr, &peer_len);
ok(!ret, "getpeername should have succeeded, error %u\n", WSAGetLastError());
ok(sock_len == sizeof(SOCKADDR_IN), "got sockname size of %d\n", sock_len);
ok(peer_len == sizeof(SOCKADDR_IN), "got peername size of %d\n", peer_len);
ok(!local_addr.sin_family, "local_addr received data.\n");
ok(!remote_addr.sin_family, "remote_addr received data.\n");
closesocket(s);
/* Passing NULLs for node or service */
s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
ret = WSAConnectByNameA(s, NULL, "http", NULL, NULL, NULL, NULL, NULL, NULL);
err = WSAGetLastError();
ok(!ret, "WSAConnectByNameA should have failed\n");
ok(err == WSAEINVAL, "expected error %u (WSAEINVAL), got %u\n", WSAEINVAL, err);
s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
closesocket(s);
ret = WSAConnectByNameA(s, "winehq.org", NULL, NULL, NULL, NULL, NULL, NULL, NULL);
err = WSAGetLastError();
ok(!ret, "WSAConnectByNameA should have failed\n");
ok(err == WSAEINVAL, "expected error %u (WSAEINVAL), got %u\n", WSAEINVAL, err);
closesocket(s);
/* Passing NULL for the addresses and address lengths */
s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
ret = WSAConnectByNameA(s, "winehq.org", "http", NULL, NULL, NULL, NULL, NULL, NULL);
ok(ret, "WSAConnectByNameA should have succeeded, error %u\n", WSAGetLastError());
closesocket(s);
/* Passing NULL for the addresses and passing correct lengths */
local_len = remote_len = sizeof(SOCKADDR_IN);
s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
ret = WSAConnectByNameA(s, "winehq.org", "http", &local_len, NULL,
&remote_len, NULL, NULL, NULL);
ok(ret, "WSAConnectByNameA should have succeeded, error %u\n", WSAGetLastError());
ok(local_len == sizeof(SOCKADDR_IN), "local_len should have been %Iu, got %ld\n", sizeof(SOCKADDR_IN),
local_len);
ok(remote_len == sizeof(SOCKADDR_IN), "remote_len should have been %Iu, got %ld\n", sizeof(SOCKADDR_IN),
remote_len);
closesocket(s);
/* Passing addresses and passing short lengths */
local_len = remote_len = 3;
s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
ret = WSAConnectByNameA(s, "winehq.org", "http", &local_len, (struct sockaddr *)&local_addr,
&remote_len, (struct sockaddr *)&remote_addr, NULL, NULL);
err = WSAGetLastError();
ok(!ret, "WSAConnectByNameA should have failed\n");
ok(err == WSAEFAULT, "expected error %u (WSAEFAULT), got %u\n", WSAEFAULT, err);
ok(local_len == 3, "local_len should have been 3, got %ld\n", local_len);
ok(remote_len == 3, "remote_len should have been 3, got %ld\n", remote_len);
closesocket(s);
/* Passing addresses and passing long lengths */
local_len = remote_len = 50;
s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
ret = WSAConnectByNameA(s, "winehq.org", "http", &local_len, (struct sockaddr *)&local_addr,
&remote_len, (struct sockaddr *)&remote_addr, NULL, NULL);
ok(ret, "WSAConnectByNameA should have succeeded, error %u\n", WSAGetLastError());
ok(local_len == sizeof(SOCKADDR_IN), "local_len should have been %Iu, got %ld\n", sizeof(SOCKADDR_IN),
local_len);
ok(remote_len == sizeof(SOCKADDR_IN), "remote_len should have been %Iu, got %ld\n", sizeof(SOCKADDR_IN),
remote_len);
closesocket(s);
/* Unknown service */
s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
ret = WSAConnectByNameA(s, "winehq.org", "nonexistentservice", NULL, NULL, NULL, NULL, NULL, NULL);
err = WSAGetLastError();
ok(!ret, "WSAConnectByNameA should have failed\n");
ok(err == WSATYPE_NOT_FOUND, "expected error %u (WSATYPE_NOT_FOUND), got %u\n",
WSATYPE_NOT_FOUND, err);
closesocket(s);
/* Connecting with a UDP socket */
s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
ret = WSAConnectByNameA(s, "winehq.org", "https", NULL, NULL, NULL, NULL, NULL, NULL);
err = WSAGetLastError();
ok(!ret, "WSAConnectByNameA should have failed\n");
ok(err == WSAEINVAL || err == WSAEFAULT, "expected error %u (WSAEINVAL) or %u (WSAEFAULT), got %u\n",
WSAEINVAL, WSAEFAULT, err); /* WSAEFAULT win10 >= 1809 */
closesocket(s);
/* Passing non-null as the reserved parameter */
s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
ret = WSAConnectByNameA(s, "winehq.org", "http", NULL, NULL, NULL, NULL, NULL, &overlap);
err = WSAGetLastError();
ok(!ret, "WSAConnectByNameA should have failed\n");
ok(err == WSAEINVAL, "expected error %u (WSAEINVAL), got %u\n", WSAEINVAL, err);
closesocket(s);
}
static void test_WSAEnumNetworkEvents(void)
{
SOCKET s, s2;
......@@ -12573,6 +12723,7 @@ START_TEST( sock )
test_WSASocket();
test_WSADuplicateSocket();
test_WSAConnectByName();
test_WSAEnumNetworkEvents();
test_errors();
......
......@@ -68,6 +68,8 @@
@ stdcall WSAAddressToStringW(ptr long ptr ptr ptr)
@ stdcall WSACloseEvent(long)
@ stdcall WSAConnect(long ptr long ptr ptr ptr ptr)
@ stdcall WSAConnectByNameA(long str str ptr ptr ptr ptr ptr ptr)
@ stdcall WSAConnectByNameW(long str str ptr ptr ptr ptr ptr ptr)
@ stdcall WSACreateEvent ()
@ stdcall WSADuplicateSocketA(long long ptr)
@ stdcall WSADuplicateSocketW(long long ptr)
......
......@@ -61,6 +61,18 @@
0, 0, { (DWORD_PTR)(__FILE__ ": " # cs) }}; \
static CRITICAL_SECTION cs = { &cs##_debug, -1, 0, 0, 0, 0 }
static inline char *strdupWtoA( const WCHAR *str )
{
char *ret = NULL;
if (str)
{
DWORD len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL );
if ((ret = malloc( len )))
WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
}
return ret;
}
static const char magic_loopback_addr[] = {127, 12, 34, 56};
const char *debugstr_sockaddr( const struct sockaddr *addr ) DECLSPEC_HIDDEN;
......
......@@ -1157,6 +1157,9 @@ int WINAPI WSACancelBlockingCall(void);
int WINAPI WSACleanup(void);
BOOL WINAPI WSACloseEvent(WSAEVENT);
int WINAPI WSAConnect(SOCKET,const struct WS(sockaddr)*,int,LPWSABUF,LPWSABUF,LPQOS,LPQOS);
BOOL WINAPI WSAConnectByNameA(SOCKET,const char *,const char *,DWORD *,struct WS(sockaddr) *,DWORD *,struct WS(sockaddr) *,const struct WS(timeval) *,WSAOVERLAPPED *);
BOOL WINAPI WSAConnectByNameW(SOCKET,const WCHAR *,const WCHAR *,DWORD *,struct WS(sockaddr) *,DWORD *,struct WS(sockaddr) *,const struct WS(timeval) *,WSAOVERLAPPED *);
#define WSAConnectByName WINELIB_NAME_AW(WSAConnectByName)
WSAEVENT WINAPI WSACreateEvent(void);
INT WINAPI WSADuplicateSocketA(SOCKET,DWORD,LPWSAPROTOCOL_INFOA);
INT WINAPI WSADuplicateSocketW(SOCKET,DWORD,LPWSAPROTOCOL_INFOW);
......
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