1 /*
2  * PROJECT:     ReactOS API Tests
3  * LICENSE:     GPL - See COPYING in the top level directory
4  * PURPOSE:     Test for recv
5  * COPYRIGHT:   Copyright 2008 Colin Finck (colin@reactos.org)
6  *              Copyright 2010 Timo Kreuzer (timo.kreuzer@reactos.org)
7  *              Copyright 2012 Cameron Gutman (cameron.gutman@reactos.org)
8  *              Copyright 2023 Thomas Faber (thomas.faber@reactos.org)
9  */
10 
11 #include "ws2_32.h"
12 
13 #include <ndk/exfuncs.h>
14 #include <ndk/iofuncs.h>
15 #include <ndk/obfuncs.h>
16 
17 #define RECV_BUF   4
18 
19 /* For valid test results, the ReactOS Website needs to return at least 8 bytes on a "GET / HTTP/1.0" request.
20    Also the first 4 bytes and the last 4 bytes need to be different.
21    Both factors usually apply on standard HTTP responses. */
22 
23 int Test_recv()
24 {
25     const char szDummyBytes[RECV_BUF] = {0xFF, 0x00, 0xFF, 0x00};
26 
27     char szBuf1[RECV_BUF];
28     char szBuf2[RECV_BUF];
29     int iResult;
30     SOCKET sck;
31     WSADATA wdata;
32     NTSTATUS status;
33     IO_STATUS_BLOCK readIosb;
34     HANDLE readEvent;
35     LARGE_INTEGER readOffset;
36 
37     /* Start up Winsock */
38     iResult = WSAStartup(MAKEWORD(2, 2), &wdata);
39     ok(iResult == 0, "WSAStartup failed, iResult == %d\n", iResult);
40 
41     /* If we call recv without a socket, it should return with an error and do nothing. */
42     memcpy(szBuf1, szDummyBytes, RECV_BUF);
43     iResult = recv(0, szBuf1, RECV_BUF, 0);
44     ok(iResult == SOCKET_ERROR, "iRseult = %d\n", iResult);
45     ok(!memcmp(szBuf1, szDummyBytes, RECV_BUF), "not equal\n");
46 
47     /* Create the socket */
48     if (!CreateSocket(&sck))
49     {
50         ok(0, "CreateSocket failed. Aborting test.\n");
51         return 0;
52     }
53 
54     /* Now we can pass at least a socket, but we have no connection yet. Should return with an error and do nothing. */
55     memcpy(szBuf1, szDummyBytes, RECV_BUF);
56     iResult = recv(sck, szBuf1, RECV_BUF, 0);
57     ok(iResult == SOCKET_ERROR, "iResult = %d\n", iResult);
58     ok(!memcmp(szBuf1, szDummyBytes, RECV_BUF), "not equal\n");
59 
60     /* Connect to "www.reactos.org" */
61     if (!ConnectToReactOSWebsite(sck))
62     {
63         ok(0, "ConnectToReactOSWebsite failed. Aborting test.\n");
64         return 0;
65     }
66 
67     /* Send the GET request */
68     if (!GetRequestAndWait(sck))
69     {
70         ok(0, "GetRequestAndWait failed. Aborting test.\n");
71         return 0;
72     }
73 
74     /* Receive the data.
75        MSG_PEEK will not change the internal number of bytes read, so that a subsequent request should return the same bytes again. */
76     SCKTEST(recv(sck, szBuf1, RECV_BUF, MSG_PEEK));
77     SCKTEST(recv(sck, szBuf2, RECV_BUF, 0));
78     ok(!memcmp(szBuf1, szBuf2, RECV_BUF), "not equal\n");
79 
80     /* The last recv() call moved the internal file pointer, so that the next request should return different data. */
81     SCKTEST(recv(sck, szBuf1, RECV_BUF, 0));
82     ok(memcmp(szBuf1, szBuf2, RECV_BUF), "equal\n");
83 
84     /* Create an event for NtReadFile */
85     readOffset.QuadPart = 0LL;
86     memcpy(szBuf1, szBuf2, RECV_BUF);
87     status = NtCreateEvent(&readEvent,
88                            EVENT_ALL_ACCESS,
89                            NULL,
90                            NotificationEvent,
91                            FALSE);
92     if (status != 0)
93     {
94         ok(0, "Failed to create event\n");
95         return 0;
96     }
97 
98     /* Try reading the socket using the NT file API */
99     status = NtReadFile((HANDLE)sck,
100                         readEvent,
101                         NULL,
102                         NULL,
103                         &readIosb,
104                         szBuf1,
105                         RECV_BUF,
106                         &readOffset,
107                         NULL);
108     if (status == STATUS_PENDING)
109     {
110         WaitForSingleObject(readEvent, INFINITE);
111         status = readIosb.Status;
112     }
113 
114     ok(status == 0, "Read failed with status 0x%x\n", (unsigned int)status);
115     ok(memcmp(szBuf2, szBuf1, RECV_BUF), "equal\n");
116     ok(readIosb.Information == RECV_BUF, "Short read\n");
117 
118     NtClose(readEvent);
119     closesocket(sck);
120     WSACleanup();
121     return 1;
122 }
123 
124 static void Test_Overread(void)
125 {
126     WSADATA wsaData;
127     SOCKET ListeningSocket = INVALID_SOCKET;
128     SOCKET ServerSocket = INVALID_SOCKET;
129     SOCKET ClientSocket = INVALID_SOCKET;
130     SOCKADDR_IN address;
131     char buffer[32];
132     int ret;
133     int error;
134     int len;
135     struct
136     {
137         char buffer[32];
138         DWORD flags;
139         WSAOVERLAPPED overlapped;
140     } receivers[4] = { 0 };
141     DWORD bytesTransferred;
142     DWORD flags;
143     WSABUF wsaBuf;
144     size_t i;
145 
146     ret = WSAStartup(MAKEWORD(2, 2), &wsaData);
147     if (ret != 0)
148     {
149         skip("Failed to initialize WinSock, error %d\n", ret);
150         goto Exit;
151     }
152 
153     ListeningSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
154     if (ListeningSocket == INVALID_SOCKET)
155     {
156         skip("Failed to create listening socket, error %d\n", WSAGetLastError());
157         goto Exit;
158     }
159 
160     /* Bind to random port */
161     address.sin_family = AF_INET;
162     address.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
163     address.sin_port = 0;
164     ret = bind(ListeningSocket, (SOCKADDR *)&address, sizeof(address));
165     if (ret == SOCKET_ERROR)
166     {
167         skip("Failed to bind socket, error %d\n", WSAGetLastError());
168         goto Exit;
169     }
170 
171     ret = listen(ListeningSocket, 1);
172     if (ret == SOCKET_ERROR)
173     {
174         skip("Failed to listen on socket, error %d\n", WSAGetLastError());
175         goto Exit;
176     }
177 
178     len = sizeof(address);
179     ret = getsockname(ListeningSocket, (SOCKADDR *)&address, &len);
180     if (ret == SOCKET_ERROR)
181     {
182         skip("Failed to get listening port on socket, error %d\n", WSAGetLastError());
183         goto Exit;
184     }
185     ok(len == sizeof(address), "getsocketname length %d\n", len);
186 
187     /**************************************************************************
188      * Test 1: non-overlapped client socket
189      *************************************************************************/
190     ClientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
191     if (ClientSocket == INVALID_SOCKET)
192     {
193         skip("Failed to create client socket, error %d\n", WSAGetLastError());
194         goto Exit;
195     }
196 
197     ret = connect(ClientSocket, (SOCKADDR *)&address, sizeof(address));
198     if (ret == SOCKET_ERROR)
199     {
200         skip("Failed to connect to socket, error %d\n", WSAGetLastError());
201         goto Exit;
202     }
203 
204     ServerSocket = accept(ListeningSocket, NULL, NULL);
205     if (ServerSocket == INVALID_SOCKET)
206     {
207         skip("Failed to accept client socket, error %d\n", WSAGetLastError());
208         goto Exit;
209     }
210 
211     ret = send(ServerSocket, "blah", 4, 0);
212     if (ret == SOCKET_ERROR)
213     {
214         skip("Failed to send to socket, error %d\n", WSAGetLastError());
215         goto Exit;
216     }
217 
218     ret = closesocket(ServerSocket);
219     ServerSocket = INVALID_SOCKET;
220     ok(ret == 0, "Failed to close socket with %d\n", WSAGetLastError());
221 
222     memset(buffer, 0, sizeof(buffer));
223     ret = recv(ClientSocket, buffer, sizeof(buffer), 0);
224     error = WSAGetLastError();
225     ok(ret == 4, "recv (1) returned %d\n", ret);
226     ok(error == NO_ERROR, "recv (1) returned error %d\n", error);
227     buffer[4] = 0;
228     ok(!strcmp(buffer, "blah"), "recv (1) returned data: %s\n", buffer);
229 
230     ret = recv(ClientSocket, buffer, sizeof(buffer), 0);
231     error = WSAGetLastError();
232     ok(ret == 0, "recv (2) returned %d\n", ret);
233     ok(error == NO_ERROR, "recv (2) returned error %d\n", error);
234 
235     ret = recv(ClientSocket, buffer, sizeof(buffer), 0);
236     error = WSAGetLastError();
237     ok(ret == 0, "recv (3) returned %d\n", ret);
238     ok(error == NO_ERROR, "recv (3) returned error %d\n", error);
239 
240     closesocket(ClientSocket);
241 
242     /**************************************************************************
243      * Test 2: overlapped client socket with multiple pending receives
244      *************************************************************************/
245     ClientSocket = WSASocketW(AF_INET,
246                               SOCK_STREAM,
247                               IPPROTO_TCP,
248                               NULL,
249                               0,
250                               WSA_FLAG_OVERLAPPED);
251     if (ClientSocket == INVALID_SOCKET)
252     {
253         skip("Failed to create overlapped client socket, error %d\n", WSAGetLastError());
254         goto Exit;
255     }
256 
257     ret = connect(ClientSocket, (SOCKADDR *)&address, sizeof(address));
258     if (ret == SOCKET_ERROR)
259     {
260         skip("Failed to connect to socket, error %d\n", WSAGetLastError());
261         goto Exit;
262     }
263 
264     ServerSocket = accept(ListeningSocket, NULL, NULL);
265     if (ServerSocket == INVALID_SOCKET)
266     {
267         skip("Failed to accept client socket, error %d\n", WSAGetLastError());
268         goto Exit;
269     }
270 
271     /* Start overlapping receive calls */
272     for (i = 0; i < RTL_NUMBER_OF(receivers); i++)
273     {
274         wsaBuf.len = sizeof(receivers[i].buffer);
275         wsaBuf.buf = receivers[i].buffer;
276         receivers[i].flags = 0;
277         receivers[i].overlapped.hEvent = WSACreateEvent();
278         ret = WSARecv(ClientSocket,
279                       &wsaBuf,
280                       1,
281                       NULL,
282                       &receivers[i].flags,
283                       &receivers[i].overlapped,
284                       NULL);
285         error = WSAGetLastError();
286         ok(ret == SOCKET_ERROR, "[%Iu] WSARecv returned %d\n", i, ret);
287         ok(error == WSA_IO_PENDING, "[%Iu] WSARecv returned error %d\n", i, error);
288     }
289 
290     /* They should all be pending */
291     for (i = 0; i < RTL_NUMBER_OF(receivers); i++)
292     {
293         ret = WSAGetOverlappedResult(ClientSocket,
294                                      &receivers[i].overlapped,
295                                      &bytesTransferred,
296                                      FALSE,
297                                      &flags);
298         error = WSAGetLastError();
299         ok(ret == FALSE, "[%Iu] WSAGetOverlappedResult returned %d\n", i, ret);
300         ok(error == WSA_IO_INCOMPLETE, "[%Iu] WSAGetOverlappedResult returned error %d\n", i, error);
301     }
302 
303     /* Sending some data should complete the first receive */
304     ret = send(ServerSocket, "blah", 4, 0);
305     if (ret == SOCKET_ERROR)
306     {
307         skip("Failed to send to socket, error %d\n", WSAGetLastError());
308         goto Exit;
309     }
310 
311     flags = 0x55555555;
312     bytesTransferred = 0x55555555;
313     ret = WSAGetOverlappedResult(ClientSocket,
314                                  &receivers[0].overlapped,
315                                  &bytesTransferred,
316                                  FALSE,
317                                  &flags);
318     error = WSAGetLastError();
319     ok(ret == TRUE, "WSAGetOverlappedResult returned %d\n", ret);
320     ok(flags == 0, "WSAGetOverlappedResult returned flags 0x%lx\n", flags);
321     ok(bytesTransferred == 4, "WSAGetOverlappedResult returned %lu bytes\n", bytesTransferred);
322     receivers[0].buffer[4] = 0;
323     ok(!strcmp(receivers[0].buffer, "blah"), "WSARecv returned data: %s\n", receivers[0].buffer);
324 
325     /* Others should still be in progress */
326     for (i = 1; i < RTL_NUMBER_OF(receivers); i++)
327     {
328         ret = WSAGetOverlappedResult(ClientSocket,
329                                      &receivers[i].overlapped,
330                                      &bytesTransferred,
331                                      FALSE,
332                                      &flags);
333         error = WSAGetLastError();
334         ok(ret == FALSE, "[%Iu] WSAGetOverlappedResult returned %d\n", i, ret);
335         ok(error == WSA_IO_INCOMPLETE, "[%Iu] WSAGetOverlappedResult returned error %d\n", i, error);
336     }
337 
338     /* Closing the server end should make all receives complete */
339     ret = closesocket(ServerSocket);
340     ServerSocket = INVALID_SOCKET;
341     ok(ret == 0, "Failed to close socket with %d\n", WSAGetLastError());
342 
343     for (i = 1; i < RTL_NUMBER_OF(receivers); i++)
344     {
345         flags = 0x55555555;
346         bytesTransferred = 0x55555555;
347         ret = WSAGetOverlappedResult(ClientSocket,
348                                      &receivers[i].overlapped,
349                                      &bytesTransferred,
350                                      FALSE,
351                                      &flags);
352         error = WSAGetLastError();
353         ok(ret == TRUE, "[%Iu] WSAGetOverlappedResult returned %d\n", i, ret);
354         ok(flags == 0, "[%Iu] WSAGetOverlappedResult returned flags 0x%lx\n", i, flags);
355         ok(bytesTransferred == 0, "[%Iu] WSAGetOverlappedResult returned %lu bytes\n", i, bytesTransferred);
356     }
357 
358     /* Start two more receives -- they should immediately return success */
359     ret = recv(ClientSocket, receivers[0].buffer, sizeof(receivers[0].buffer), 0);
360     error = WSAGetLastError();
361     ok(ret == 0, "recv (N+1) returned %d\n", ret);
362     ok(error == NO_ERROR, "recv (N+1) returned error %d\n", error);
363 
364     ret = recv(ClientSocket, receivers[0].buffer, sizeof(receivers[0].buffer), 0);
365     error = WSAGetLastError();
366     ok(ret == 0, "recv (N+2) returned %d\n", ret);
367     ok(error == NO_ERROR, "recv (N+2) returned error %d\n", error);
368 
369 Exit:
370     for (i = 0; i < RTL_NUMBER_OF(receivers); i++)
371     {
372         if (receivers[i].overlapped.hEvent != NULL)
373         {
374             WSACloseEvent(receivers[i].overlapped.hEvent);
375         }
376     }
377 
378     if (ListeningSocket != INVALID_SOCKET)
379     {
380         ret = closesocket(ListeningSocket);
381         ok(ret == 0, "closesocket (1) failed with %d\n", WSAGetLastError());
382     }
383     if (ClientSocket != INVALID_SOCKET)
384     {
385         ret = closesocket(ClientSocket);
386         ok(ret == 0, "closesocket (2) failed with %d\n", WSAGetLastError());
387     }
388     if (ServerSocket != INVALID_SOCKET)
389     {
390         ret = closesocket(ServerSocket);
391         ok(ret == 0, "closesocket (3) failed with %d\n", WSAGetLastError());
392     }
393     ret = WSACleanup();
394     ok(ret == 0, "WSACleanup failed with %d\n", WSAGetLastError());
395 }
396 
397 START_TEST(recv)
398 {
399     Test_recv();
400     Test_Overread();
401 }
402 
403