2008-06-01 22:08:45 +00:00
|
|
|
/*
|
2023-03-19 13:26:24 +00:00
|
|
|
* PROJECT: ReactOS API Tests
|
|
|
|
* LICENSE: GPL - See COPYING in the top level directory
|
|
|
|
* PURPOSE: Test for recv
|
|
|
|
* COPYRIGHT: Copyright 2008 Colin Finck (colin@reactos.org)
|
|
|
|
* Copyright 2010 Timo Kreuzer (timo.kreuzer@reactos.org)
|
|
|
|
* Copyright 2012 Cameron Gutman (cameron.gutman@reactos.org)
|
|
|
|
* Copyright 2023 Thomas Faber (thomas.faber@reactos.org)
|
2008-06-01 22:08:45 +00:00
|
|
|
*/
|
|
|
|
|
2010-08-25 08:48:55 +00:00
|
|
|
#include "ws2_32.h"
|
2008-06-01 22:08:45 +00:00
|
|
|
|
2017-12-21 12:36:04 +00:00
|
|
|
#include <ndk/exfuncs.h>
|
|
|
|
#include <ndk/iofuncs.h>
|
|
|
|
#include <ndk/obfuncs.h>
|
|
|
|
|
2008-06-01 22:08:45 +00:00
|
|
|
#define RECV_BUF 4
|
|
|
|
|
|
|
|
/* For valid test results, the ReactOS Website needs to return at least 8 bytes on a "GET / HTTP/1.0" request.
|
|
|
|
Also the first 4 bytes and the last 4 bytes need to be different.
|
|
|
|
Both factors usually apply on standard HTTP responses. */
|
2010-08-25 08:48:55 +00:00
|
|
|
|
|
|
|
int Test_recv()
|
2008-06-01 22:08:45 +00:00
|
|
|
{
|
|
|
|
const char szDummyBytes[RECV_BUF] = {0xFF, 0x00, 0xFF, 0x00};
|
|
|
|
|
|
|
|
char szBuf1[RECV_BUF];
|
|
|
|
char szBuf2[RECV_BUF];
|
|
|
|
int iResult;
|
|
|
|
SOCKET sck;
|
|
|
|
WSADATA wdata;
|
2012-09-04 03:02:40 +00:00
|
|
|
NTSTATUS status;
|
|
|
|
IO_STATUS_BLOCK readIosb;
|
|
|
|
HANDLE readEvent;
|
|
|
|
LARGE_INTEGER readOffset;
|
2008-06-01 22:08:45 +00:00
|
|
|
|
|
|
|
/* Start up Winsock */
|
2010-08-25 08:48:55 +00:00
|
|
|
iResult = WSAStartup(MAKEWORD(2, 2), &wdata);
|
|
|
|
ok(iResult == 0, "WSAStartup failed, iResult == %d\n", iResult);
|
2008-06-01 22:08:45 +00:00
|
|
|
|
|
|
|
/* If we call recv without a socket, it should return with an error and do nothing. */
|
|
|
|
memcpy(szBuf1, szDummyBytes, RECV_BUF);
|
2010-08-25 08:48:55 +00:00
|
|
|
iResult = recv(0, szBuf1, RECV_BUF, 0);
|
|
|
|
ok(iResult == SOCKET_ERROR, "iRseult = %d\n", iResult);
|
|
|
|
ok(!memcmp(szBuf1, szDummyBytes, RECV_BUF), "not equal\n");
|
2008-06-01 22:08:45 +00:00
|
|
|
|
|
|
|
/* Create the socket */
|
2010-08-25 08:48:55 +00:00
|
|
|
if (!CreateSocket(&sck))
|
|
|
|
{
|
|
|
|
ok(0, "CreateSocket failed. Aborting test.\n");
|
|
|
|
return 0;
|
|
|
|
}
|
2008-06-01 22:08:45 +00:00
|
|
|
|
|
|
|
/* Now we can pass at least a socket, but we have no connection yet. Should return with an error and do nothing. */
|
|
|
|
memcpy(szBuf1, szDummyBytes, RECV_BUF);
|
2010-08-25 08:48:55 +00:00
|
|
|
iResult = recv(sck, szBuf1, RECV_BUF, 0);
|
|
|
|
ok(iResult == SOCKET_ERROR, "iResult = %d\n", iResult);
|
|
|
|
ok(!memcmp(szBuf1, szDummyBytes, RECV_BUF), "not equal\n");
|
2008-06-01 22:08:45 +00:00
|
|
|
|
|
|
|
/* Connect to "www.reactos.org" */
|
2010-08-25 08:48:55 +00:00
|
|
|
if (!ConnectToReactOSWebsite(sck))
|
|
|
|
{
|
|
|
|
ok(0, "ConnectToReactOSWebsite failed. Aborting test.\n");
|
|
|
|
return 0;
|
|
|
|
}
|
2008-06-01 22:08:45 +00:00
|
|
|
|
|
|
|
/* Send the GET request */
|
2010-08-25 08:48:55 +00:00
|
|
|
if (!GetRequestAndWait(sck))
|
|
|
|
{
|
|
|
|
ok(0, "GetRequestAndWait failed. Aborting test.\n");
|
|
|
|
return 0;
|
|
|
|
}
|
2008-06-01 22:08:45 +00:00
|
|
|
|
|
|
|
/* Receive the data.
|
|
|
|
MSG_PEEK will not change the internal number of bytes read, so that a subsequent request should return the same bytes again. */
|
|
|
|
SCKTEST(recv(sck, szBuf1, RECV_BUF, MSG_PEEK));
|
|
|
|
SCKTEST(recv(sck, szBuf2, RECV_BUF, 0));
|
2010-08-25 08:48:55 +00:00
|
|
|
ok(!memcmp(szBuf1, szBuf2, RECV_BUF), "not equal\n");
|
2008-06-01 22:08:45 +00:00
|
|
|
|
|
|
|
/* The last recv() call moved the internal file pointer, so that the next request should return different data. */
|
|
|
|
SCKTEST(recv(sck, szBuf1, RECV_BUF, 0));
|
2010-08-25 08:48:55 +00:00
|
|
|
ok(memcmp(szBuf1, szBuf2, RECV_BUF), "equal\n");
|
2008-06-01 22:08:45 +00:00
|
|
|
|
2012-09-04 03:02:40 +00:00
|
|
|
/* Create an event for NtReadFile */
|
|
|
|
readOffset.QuadPart = 0LL;
|
|
|
|
memcpy(szBuf1, szBuf2, RECV_BUF);
|
|
|
|
status = NtCreateEvent(&readEvent,
|
|
|
|
EVENT_ALL_ACCESS,
|
|
|
|
NULL,
|
|
|
|
NotificationEvent,
|
|
|
|
FALSE);
|
|
|
|
if (status != 0)
|
|
|
|
{
|
|
|
|
ok(0, "Failed to create event\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Try reading the socket using the NT file API */
|
|
|
|
status = NtReadFile((HANDLE)sck,
|
|
|
|
readEvent,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
&readIosb,
|
|
|
|
szBuf1,
|
|
|
|
RECV_BUF,
|
|
|
|
&readOffset,
|
|
|
|
NULL);
|
|
|
|
if (status == STATUS_PENDING)
|
|
|
|
{
|
|
|
|
WaitForSingleObject(readEvent, INFINITE);
|
|
|
|
status = readIosb.Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
ok(status == 0, "Read failed with status 0x%x\n", (unsigned int)status);
|
|
|
|
ok(memcmp(szBuf2, szBuf1, RECV_BUF), "equal\n");
|
|
|
|
ok(readIosb.Information == RECV_BUF, "Short read\n");
|
|
|
|
|
|
|
|
NtClose(readEvent);
|
2008-06-01 22:08:45 +00:00
|
|
|
closesocket(sck);
|
|
|
|
WSACleanup();
|
2010-08-25 08:48:55 +00:00
|
|
|
return 1;
|
|
|
|
}
|
2008-06-01 22:08:45 +00:00
|
|
|
|
2023-03-19 13:26:24 +00:00
|
|
|
static void Test_Overread(void)
|
|
|
|
{
|
|
|
|
WSADATA wsaData;
|
|
|
|
SOCKET ListeningSocket = INVALID_SOCKET;
|
|
|
|
SOCKET ServerSocket = INVALID_SOCKET;
|
|
|
|
SOCKET ClientSocket = INVALID_SOCKET;
|
|
|
|
SOCKADDR_IN address;
|
|
|
|
char buffer[32];
|
|
|
|
int ret;
|
|
|
|
int error;
|
|
|
|
int len;
|
|
|
|
|
|
|
|
ret = WSAStartup(MAKEWORD(2, 2), &wsaData);
|
|
|
|
if (ret != 0)
|
|
|
|
{
|
|
|
|
skip("Failed to initialize WinSock, error %d\n", ret);
|
|
|
|
goto Exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
ListeningSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
|
|
|
ClientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
|
|
|
if (ListeningSocket == INVALID_SOCKET || ClientSocket == INVALID_SOCKET)
|
|
|
|
{
|
|
|
|
skip("Failed to create sockets, error %d\n", WSAGetLastError());
|
|
|
|
goto Exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Bind to random port */
|
|
|
|
address.sin_family = AF_INET;
|
|
|
|
address.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
|
|
|
address.sin_port = 0;
|
|
|
|
ret = bind(ListeningSocket, (SOCKADDR *)&address, sizeof(address));
|
|
|
|
if (ret == SOCKET_ERROR)
|
|
|
|
{
|
|
|
|
skip("Failed to bind socket, error %d\n", WSAGetLastError());
|
|
|
|
goto Exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = listen(ListeningSocket, 1);
|
|
|
|
if (ret == SOCKET_ERROR)
|
|
|
|
{
|
|
|
|
skip("Failed to listen on socket, error %d\n", WSAGetLastError());
|
|
|
|
goto Exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
len = sizeof(address);
|
|
|
|
ret = getsockname(ListeningSocket, (SOCKADDR *)&address, &len);
|
|
|
|
if (ret == SOCKET_ERROR)
|
|
|
|
{
|
|
|
|
skip("Failed to get listening port on socket, error %d\n", WSAGetLastError());
|
|
|
|
goto Exit;
|
|
|
|
}
|
|
|
|
ok(len == sizeof(address), "getsocketname length %d\n", len);
|
|
|
|
|
|
|
|
ret = connect(ClientSocket, (SOCKADDR *)&address, sizeof(address));
|
|
|
|
if (ret == SOCKET_ERROR)
|
|
|
|
{
|
|
|
|
skip("Failed to connect to socket, error %d\n", WSAGetLastError());
|
|
|
|
goto Exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
ServerSocket = accept(ListeningSocket, NULL, NULL);
|
|
|
|
if (ServerSocket == INVALID_SOCKET)
|
|
|
|
{
|
|
|
|
skip("Failed to accept client socket, error %d\n", WSAGetLastError());
|
|
|
|
goto Exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = send(ServerSocket, "blah", 4, 0);
|
|
|
|
if (ret == SOCKET_ERROR)
|
|
|
|
{
|
|
|
|
skip("Failed to send to socket, error %d\n", WSAGetLastError());
|
|
|
|
goto Exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = closesocket(ServerSocket);
|
|
|
|
ServerSocket = INVALID_SOCKET;
|
|
|
|
ok(ret == 0, "Failed to close socket with %d\n", WSAGetLastError());
|
|
|
|
|
|
|
|
memset(buffer, 0, sizeof(buffer));
|
|
|
|
ret = recv(ClientSocket, buffer, sizeof(buffer), 0);
|
|
|
|
if (ret == SOCKET_ERROR)
|
|
|
|
{
|
|
|
|
skip("Failed to receive from socket (1), error %d\n", WSAGetLastError());
|
|
|
|
goto Exit;
|
|
|
|
}
|
|
|
|
error = WSAGetLastError();
|
|
|
|
ok(ret == 4, "recv (1) returned %d\n", ret);
|
|
|
|
ok(error == NO_ERROR, "recv (1) returned error %d\n", ret);
|
|
|
|
buffer[4] = 0;
|
|
|
|
ok(!strcmp(buffer, "blah"), "recv (1) returned data: %s\n", buffer);
|
|
|
|
|
|
|
|
ret = recv(ClientSocket, buffer, sizeof(buffer), 0);
|
|
|
|
if (ret == SOCKET_ERROR)
|
|
|
|
{
|
|
|
|
skip("Failed to receive from socket (2), error %d\n", WSAGetLastError());
|
|
|
|
goto Exit;
|
|
|
|
}
|
|
|
|
error = WSAGetLastError();
|
|
|
|
ok(ret == 0, "recv (2) returned %d\n", ret);
|
|
|
|
ok(error == NO_ERROR, "recv (2) returned error %d\n", ret);
|
|
|
|
|
|
|
|
ret = recv(ClientSocket, buffer, sizeof(buffer), 0);
|
|
|
|
if (ret == SOCKET_ERROR)
|
|
|
|
{
|
|
|
|
skip("Failed to receive from socket (3), error %d\n", WSAGetLastError());
|
|
|
|
goto Exit;
|
|
|
|
}
|
|
|
|
error = WSAGetLastError();
|
|
|
|
ok(ret == 0, "recv (3) returned %d\n", ret);
|
|
|
|
ok(error == NO_ERROR, "recv (3) returned error %d\n", ret);
|
|
|
|
|
|
|
|
Exit:
|
|
|
|
if (ListeningSocket != INVALID_SOCKET)
|
|
|
|
{
|
|
|
|
ret = closesocket(ListeningSocket);
|
|
|
|
ok(ret == 0, "closesocket (1) failed with %d\n", WSAGetLastError());
|
|
|
|
}
|
|
|
|
if (ClientSocket != INVALID_SOCKET)
|
|
|
|
{
|
|
|
|
ret = closesocket(ClientSocket);
|
|
|
|
ok(ret == 0, "closesocket (2) failed with %d\n", WSAGetLastError());
|
|
|
|
}
|
|
|
|
if (ServerSocket != INVALID_SOCKET)
|
|
|
|
{
|
|
|
|
ret = closesocket(ServerSocket);
|
|
|
|
ok(ret == 0, "closesocket (3) failed with %d\n", WSAGetLastError());
|
|
|
|
}
|
|
|
|
ret = WSACleanup();
|
|
|
|
ok(ret == 0, "WSACleanup failed with %d\n", WSAGetLastError());
|
|
|
|
}
|
|
|
|
|
2010-08-25 08:48:55 +00:00
|
|
|
START_TEST(recv)
|
|
|
|
{
|
|
|
|
Test_recv();
|
2023-03-19 13:26:24 +00:00
|
|
|
Test_Overread();
|
2008-06-01 22:08:45 +00:00
|
|
|
}
|
2010-08-25 08:48:55 +00:00
|
|
|
|