Commit adb8fb11 authored by Bruno Jesus's avatar Bruno Jesus Committed by Alexandre Julliard

ws2_32: Implement WSASendMsg().

parent ba2f448d
......@@ -2427,6 +2427,24 @@ static void WINAPI WS2_GetAcceptExSockaddrs(PVOID buffer, DWORD data_size, DWORD
}
/***********************************************************************
* WSASendMsg
*/
int WINAPI WSASendMsg( SOCKET s, LPWSAMSG msg, DWORD dwFlags, LPDWORD lpNumberOfBytesSent,
LPWSAOVERLAPPED lpOverlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
{
if (!msg)
{
SetLastError( WSAEFAULT );
return SOCKET_ERROR;
}
return WS2_sendto( s, msg->lpBuffers, msg->dwBufferCount, lpNumberOfBytesSent,
dwFlags, msg->name, msg->namelen,
lpOverlapped, lpCompletionRoutine );
}
/***********************************************************************
* WSARecvMsg
*
* Perform a receive operation that is capable of returning message
......@@ -3905,7 +3923,8 @@ INT WINAPI WSAIoctl(SOCKET s, DWORD code, LPVOID in_buff, DWORD in_size, LPVOID
}
else if ( IsEqualGUID(&wsasendmsg_guid, in_buff) )
{
FIXME("SIO_GET_EXTENSION_FUNCTION_POINTER: unimplemented WSASendMsg\n");
*(LPFN_WSASENDMSG *)out_buff = WSASendMsg;
break;
}
else
FIXME("SIO_GET_EXTENSION_FUNCTION_POINTER %s: stub\n", debugstr_guid(in_buff));
......
......@@ -4755,6 +4755,181 @@ end:
closesocket(v6);
}
static void test_WSASendMsg(void)
{
SOCKET sock, dst;
struct sockaddr_in sendaddr, sockaddr;
GUID WSASendMsg_GUID = WSAID_WSASENDMSG;
LPFN_WSASENDMSG pWSASendMsg = NULL;
char teststr[12] = "hello world", buffer[32];
WSABUF iovec[2];
WSAMSG msg;
DWORD bytesSent, err;
int ret, addrlen;
/* FIXME: Missing OVERLAPPED and OVERLAPPED COMPLETION ROUTINE tests */
sock = socket(AF_INET, SOCK_DGRAM, 0);
ok(sock != INVALID_SOCKET, "socket() failed\n");
/* Obtain the WSASendMsg function */
WSAIoctl(sock, SIO_GET_EXTENSION_FUNCTION_POINTER, &WSASendMsg_GUID, sizeof(WSASendMsg_GUID),
&pWSASendMsg, sizeof(pWSASendMsg), &err, NULL, NULL);
if (!pWSASendMsg)
{
closesocket(sock);
win_skip("WSASendMsg is unsupported, some tests will be skipped.\n");
return;
}
/* fake address for now */
sendaddr.sin_family = AF_INET;
sendaddr.sin_port = htons(139);
sendaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
memset(&msg, 0, sizeof(msg));
iovec[0].buf = teststr;
iovec[0].len = sizeof(teststr);
iovec[1].buf = teststr;
iovec[1].len = sizeof(teststr) / 2;
msg.name = (struct sockaddr *) &sendaddr;
msg.namelen = sizeof(sendaddr);
msg.lpBuffers = iovec;
msg.dwBufferCount = 1; /* send only one buffer for now */
WSASetLastError(0xdeadbeef);
ret = pWSASendMsg(INVALID_SOCKET, &msg, 0, NULL, NULL, NULL);
ok(ret == SOCKET_ERROR, "WSASendMsg should have failed\n");
err = WSAGetLastError();
ok(err == WSAENOTSOCK, "expected 10038, got %d instead\n", err);
WSASetLastError(0xdeadbeef);
ret = pWSASendMsg(sock, NULL, 0, NULL, NULL, NULL);
ok(ret == SOCKET_ERROR, "WSASendMsg should have failed\n");
err = WSAGetLastError();
ok(err == WSAEFAULT, "expected 10014, got %d instead\n", err);
WSASetLastError(0xdeadbeef);
ret = pWSASendMsg(sock, NULL, 0, &bytesSent, NULL, NULL);
ok(ret == SOCKET_ERROR, "WSASendMsg should have failed\n");
err = WSAGetLastError();
ok(err == WSAEFAULT, "expected 10014, got %d instead\n", err);
WSASetLastError(0xdeadbeef);
ret = pWSASendMsg(sock, &msg, 0, NULL, NULL, NULL);
ok(ret == SOCKET_ERROR, "WSASendMsg should have failed\n");
err = WSAGetLastError();
ok(err == WSAEFAULT, "expected 10014, got %d instead\n", err);
closesocket(sock);
sock = socket(AF_INET, SOCK_DGRAM, 0);
ok(sock != INVALID_SOCKET, "socket() failed\n");
dst = socket(AF_INET, SOCK_DGRAM, 0);
ok(dst != INVALID_SOCKET, "socket() failed\n");
memset(&sockaddr, 0, sizeof(sockaddr));
sockaddr.sin_family = AF_INET;
sockaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
ok(!bind(dst, (struct sockaddr*)&sockaddr, sizeof(sockaddr)),
"bind should have worked\n");
/* read address to find out the port number to be used in send */
memset(&sendaddr, 0, sizeof(sendaddr));
addrlen = sizeof(sendaddr);
ok(!getsockname(dst, (struct sockaddr *) &sendaddr, &addrlen),
"getsockname should have worked\n");
ok(sendaddr.sin_port, "socket port should be != 0\n");
/* ensure the sending socket is not bound */
WSASetLastError(0xdeadbeef);
addrlen = sizeof(sockaddr);
ret = getsockname(sock, (struct sockaddr*)&sockaddr, &addrlen);
ok(ret == SOCKET_ERROR, "getsockname should have failed\n");
err = WSAGetLastError();
ok(err == WSAEINVAL, "expected 10022, got %d instead\n", err);
set_blocking(sock, TRUE);
bytesSent = 0;
ret = pWSASendMsg(sock, &msg, 0, &bytesSent, NULL, NULL);
ok(!ret, "WSASendMsg should have worked\n");
ok(bytesSent == iovec[0].len, "incorret bytes sent, expected %d, sent %d\n",
iovec[0].len, bytesSent);
/* receive data */
addrlen = sizeof(sockaddr);
memset(buffer, 0, sizeof(buffer));
ret = recvfrom(dst, buffer, sizeof(buffer), 0, (struct sockaddr *) &sockaddr, &addrlen);
ok(ret == bytesSent, "got %d, expected %d\n",
ret, bytesSent);
/* A successful call to WSASendMsg must have bound the socket */
addrlen = sizeof(sockaddr);
sockaddr.sin_port = 0;
sockaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
ret = getsockname(sock, (struct sockaddr*)&sockaddr, &addrlen);
ok(!ret, "getsockname should have worked\n");
ok(sockaddr.sin_addr.s_addr == htonl(INADDR_ANY), "expected 0.0.0.0, got %s\n",
inet_ntoa(sockaddr.sin_addr));
ok(sockaddr.sin_port, "sin_port should be != 0\n");
msg.dwBufferCount = 2; /* send both buffers */
bytesSent = 0;
ret = pWSASendMsg(sock, &msg, 0, &bytesSent, NULL, NULL);
ok(!ret, "WSASendMsg should have worked\n");
ok(bytesSent == iovec[0].len + iovec[1].len, "incorret bytes sent, expected %d, sent %d\n",
iovec[0].len + iovec[1].len, bytesSent);
/* receive data */
addrlen = sizeof(sockaddr);
memset(buffer, 0, sizeof(buffer));
ret = recvfrom(dst, buffer, sizeof(buffer), 0, (struct sockaddr *) &sockaddr, &addrlen);
ok(ret == bytesSent, "got %d, expected %d\n",
ret, bytesSent);
closesocket(sock);
closesocket(dst);
/* a bad call to WSASendMsg will also bind the socket */
addrlen = sizeof(sockaddr);
sockaddr.sin_port = 0;
sockaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
sock = socket(AF_INET, SOCK_DGRAM, 0);
ok(sock != INVALID_SOCKET, "socket() failed\n");
ok(pWSASendMsg(sock, &msg, 0, NULL, NULL, NULL) == SOCKET_ERROR, "WSASendMsg should have failed\n");
todo_wine {
ok(!getsockname(sock, (struct sockaddr*)&sockaddr, &addrlen), "getsockname should have worked\n");
ok(sockaddr.sin_addr.s_addr == htonl(INADDR_ANY), "expected 0.0.0.0, got %s\n",
inet_ntoa(sockaddr.sin_addr));
ok(sockaddr.sin_port, "sin_port should be > 0\n");
}
closesocket(sock);
/* a bad call without msg parameter will not trigger the auto-bind */
sock = socket(AF_INET, SOCK_DGRAM, 0);
ok(sock != INVALID_SOCKET, "socket() failed\n");
ok(pWSASendMsg(sock, NULL, 0, NULL, NULL, NULL) == SOCKET_ERROR, "WSASendMsg should have failed\n");
ok(getsockname(sock, (struct sockaddr*)&sockaddr, &addrlen), "getsockname should have failed\n");
err = WSAGetLastError();
ok(err == WSAEINVAL, "expected 10022, got %d instead\n", err);
closesocket(sock);
/* SOCK_STREAM sockets are not supported */
bytesSent = 0;
sock = socket(AF_INET, SOCK_STREAM, 0);
ok(sock != INVALID_SOCKET, "socket() failed\n");
SetLastError(0xdeadbeef);
ret = pWSASendMsg(sock, &msg, 0, &bytesSent, NULL, NULL);
ok(ret == SOCKET_ERROR, "WSASendMsg should have failed\n");
err = WSAGetLastError();
todo_wine
ok(err == WSAEINVAL, "expected 10014, got %d instead\n", err);
closesocket(sock);
}
static void test_WSASendTo(void)
{
SOCKET s;
......@@ -6750,6 +6925,7 @@ START_TEST( sock )
test_dns();
test_gethostbyname_hack();
test_WSASendMsg();
test_WSASendTo();
test_WSARecv();
......
......@@ -97,6 +97,7 @@
@ stdcall WSAResetEvent(long) kernel32.ResetEvent
@ stdcall WSASend(long ptr long ptr long ptr ptr)
@ stdcall WSASendDisconnect(long ptr)
@ stdcall WSASendMsg(long ptr long ptr ptr ptr)
@ stdcall WSASendTo(long ptr long ptr long ptr long ptr ptr)
@ stdcall WSASetEvent(long) kernel32.SetEvent
@ stdcall WSASetServiceA(ptr long long)
......
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