1 /*
2 * PROJECT:         ReactOS api tests
3 * LICENSE:         GPL - See COPYING in the top level directory
4 * PURPOSE:         Test for WSAAsync
5 * PROGRAMMERS:     Miroslav Mastny
6 */
7 
8 #include "ws2_32.h"
9 
10 #define SVR_PORT 5000
11 #define WAIT_TIMEOUT_ 10000
12 #define EXIT_FLAGS (FD_ACCEPT|FD_CONNECT)
13 #define MAX_LOOPCOUNT 9u
14 
15 START_TEST(WSAAsync)
16 {
17     WSADATA    WsaData;
18     SOCKET     ServerSocket = INVALID_SOCKET,
19                ClientSocket = INVALID_SOCKET;
20     WSAEVENT   ServerEvent = WSA_INVALID_EVENT,
21                ClientEvent = WSA_INVALID_EVENT;
22     struct hostent *ent = NULL;
23     struct sockaddr_in server_addr_in;
24     struct sockaddr_in addr_remote;
25     struct sockaddr_in addr_con_loc;
26     int nConRes, nSockNameRes;
27     int addrsize, len;
28     WSAEVENT fEvents[2];
29     SOCKET fSockets[2];
30     SOCKET sockaccept;
31     WSANETWORKEVENTS WsaNetworkEvents;
32     ULONG ulValue = 1;
33     DWORD dwWait;
34     DWORD dwFlags = 0;
35     struct fd_set select_rfds;
36     struct fd_set select_wfds;
37     struct fd_set select_efds;
38     struct timeval timeval;
39     BOOL ConnectSent = FALSE;
40     unsigned int Addr_con_locLoopCount = 0,
41                  ServerSocketLoopCount = 0;
42 
43     if (WSAStartup(MAKEWORD(2, 2), &WsaData) != 0)
44     {
45         skip("WSAStartup failed\n");
46         return;
47     }
48 
49     ServerSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
50     ClientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
51     ServerEvent  = WSACreateEvent();
52     ClientEvent  = WSACreateEvent();
53 
54     if (ServerSocket == INVALID_SOCKET)
55     {
56         skip("ERROR: Server socket creation failed\n");
57         return;
58     }
59     if (ClientSocket == INVALID_SOCKET)
60     {
61         skip("ERROR: Client socket creation failed\n");
62         closesocket(ServerSocket);
63         return;
64     }
65     if (ServerEvent == WSA_INVALID_EVENT)
66     {
67         skip("ERROR: Server WSAEvent creation failed\n");
68         closesocket(ClientSocket);
69         closesocket(ServerSocket);
70         return;
71     }
72     if (ClientEvent == WSA_INVALID_EVENT)
73     {
74         skip("ERROR: Client WSAEvent creation failed\n");
75         WSACloseEvent(ServerEvent);
76         closesocket(ClientSocket);
77         closesocket(ServerSocket);
78         return;
79     }
80     ent = gethostbyname("127.0.0.1");
81     if (ent == NULL)
82     {
83         ok(ent != NULL, "ERROR: gethostbyname '127.0.0.1' failed, trying 'localhost'\n");
84         ent = gethostbyname("localhost");
85 
86         if (ent == NULL)
87         {
88             skip("ERROR: gethostbyname 'localhost' failed\n");
89             goto done;
90         }
91     }
92 
93     server_addr_in.sin_family = AF_INET;
94     server_addr_in.sin_port   = htons(SVR_PORT);
95     memcpy(&server_addr_in.sin_addr.S_un.S_addr, ent->h_addr_list[0], 4);
96 
97     // Server initialization.
98     trace("Initializing server and client connections ...\n");
99     ok(bind(ServerSocket, (struct sockaddr*)&server_addr_in, sizeof(server_addr_in)) == 0, "ERROR: server bind failed\n");
100     ok(ioctlsocket(ServerSocket, FIONBIO, &ulValue) == 0, "ERROR: server ioctlsocket FIONBIO failed\n");
101     ok(WSAEventSelect(ServerSocket, ServerEvent, FD_ACCEPT | FD_CLOSE) == 0, "ERROR: server accept EventSelect failed\n");
102 
103     // Client initialization.
104     ok(WSAEventSelect(ClientSocket, ClientEvent, FD_CONNECT | FD_CLOSE) == 0, "ERROR: client EventSelect failed\n");
105     ok(ioctlsocket(ClientSocket, FIONBIO, &ulValue) == 0, "ERROR: client ioctlsocket FIONBIO failed\n");
106 
107     // listen
108     trace("Starting server listening mode ...\n");
109     ok(listen(ServerSocket, SOMAXCONN) == 0, "ERROR: cannot initialize server listen\n");
110 
111     trace("Starting client to server connection ...\n");
112     // connect
113     nConRes = connect(ClientSocket, (struct sockaddr*)&server_addr_in, sizeof(server_addr_in));
114     ok(nConRes == SOCKET_ERROR, "ERROR: client connect() result is not SOCKET_ERROR\n");
115     ok(WSAGetLastError() == WSAEWOULDBLOCK, "ERROR: client connect() last error is not WSAEWOULDBLOCK\n");
116 
117     fSockets[0] = ServerSocket;
118     fSockets[1] = ClientSocket;
119 
120     fEvents[0] = ServerEvent;
121     fEvents[1] = ClientEvent;
122 
123     while (dwFlags != EXIT_FLAGS)
124     {
125         dwWait = WaitForMultipleObjects(2, fEvents, FALSE, WAIT_TIMEOUT_);
126 
127         if (dwWait != WAIT_OBJECT_0 && // server socket event
128             dwWait != WAIT_OBJECT_0+1) // client socket event
129         {
130             ok(FALSE, "Unknown event received %lu\n", dwWait);
131             skip("ERROR: Connection timeout\n");
132             break;
133         }
134 
135         WSAEnumNetworkEvents(fSockets[dwWait-WAIT_OBJECT_0], fEvents[dwWait-WAIT_OBJECT_0], &WsaNetworkEvents);
136 
137         if ((WsaNetworkEvents.lNetworkEvents & FD_ACCEPT) != 0)
138         {// connection accepted
139             trace("Event FD_ACCEPT...\n");
140             ok(WsaNetworkEvents.iErrorCode[FD_ACCEPT_BIT] == 0, "Error on accept %d\n", WsaNetworkEvents.iErrorCode[FD_ACCEPT_BIT]);
141             if (WsaNetworkEvents.iErrorCode[FD_ACCEPT_BIT] == 0)
142             {
143                 addrsize = sizeof(addr_remote);
144                 sockaccept = accept(fSockets[dwWait - WAIT_OBJECT_0], (struct sockaddr*)&addr_remote, &addrsize);
145                 ok(sockaccept != INVALID_SOCKET, "ERROR: Connection accept function failed, error %d\n", WSAGetLastError());
146                 dwFlags |= FD_ACCEPT;
147             }
148         }
149 
150         if ((WsaNetworkEvents.lNetworkEvents & FD_CONNECT) != 0)
151         {// client connected
152             trace("Event FD_CONNECT...\n");
153             ok(WsaNetworkEvents.iErrorCode[FD_CONNECT_BIT] == 0, "Error on connect %d\n", WsaNetworkEvents.iErrorCode[FD_CONNECT_BIT]);
154             if (WsaNetworkEvents.iErrorCode[FD_CONNECT_BIT] == 0)
155             {
156                 len = sizeof(addr_con_loc);
157                 ok(getsockname(fSockets[dwWait - WAIT_OBJECT_0], (struct sockaddr*)&addr_con_loc, &len) == 0, "\n");
158                 dwFlags |= FD_CONNECT;
159             }
160         }
161     }
162     closesocket(sockaccept);
163     closesocket(ServerSocket);
164     closesocket(ClientSocket);
165 
166     /* same test but with waiting select and getsockname to return proper values */
167     ServerSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
168     ClientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
169 
170     if (ServerSocket == INVALID_SOCKET)
171     {
172         skip("ERROR: Server socket creation failed\n");
173         return;
174     }
175     if (ClientSocket == INVALID_SOCKET)
176     {
177         skip("ERROR: Client socket creation failed\n");
178         closesocket(ServerSocket);
179         return;
180     }
181     ent = gethostbyname("127.0.0.1");
182     if (ent == NULL)
183     {
184         ok(ent != NULL, "ERROR: gethostbyname '127.0.0.1' failed, trying 'localhost'\n");
185         ent = gethostbyname("localhost");
186 
187         if (ent == NULL)
188         {
189             skip("ERROR: gethostbyname 'localhost' failed\n");
190             goto done;
191         }
192     }
193 
194     server_addr_in.sin_family = AF_INET;
195     server_addr_in.sin_port = htons(SVR_PORT);
196     memcpy(&server_addr_in.sin_addr.S_un.S_addr, ent->h_addr_list[0], 4);
197 
198     // Server initialization.
199     trace("Initializing server and client connections ...\n");
200     ok(bind(ServerSocket, (struct sockaddr*)&server_addr_in, sizeof(server_addr_in)) == 0, "ERROR: server bind failed\n");
201     ok(ioctlsocket(ServerSocket, FIONBIO, &ulValue) == 0, "ERROR: server ioctlsocket FIONBIO failed\n");
202 
203     // Client initialization.
204     ok(ioctlsocket(ClientSocket, FIONBIO, &ulValue) == 0, "ERROR: client ioctlsocket FIONBIO failed\n");
205 
206     // listen
207     trace("Starting server listening mode ...\n");
208     ok(listen(ServerSocket, SOMAXCONN) == 0, "ERROR: cannot initialize server listen\n");
209 
210     memset(&timeval, 0, sizeof(timeval));
211     timeval.tv_usec = WAIT_TIMEOUT_;
212     dwFlags = 0;
213 
214     while (dwFlags != EXIT_FLAGS)
215     {
216         len = sizeof(addr_con_loc);
217         nSockNameRes = getsockname(ClientSocket, (struct sockaddr*)&addr_con_loc, &len);
218         if (dwFlags == 0 && !ConnectSent)
219         {
220             ok(nSockNameRes == SOCKET_ERROR, "ERROR: getsockname function failed, expected %d error %d\n", SOCKET_ERROR, nSockNameRes);
221             ok(WSAGetLastError() == WSAEINVAL, "ERROR: getsockname function failed, expected %ld error %d\n", WSAEINVAL, WSAGetLastError());
222             trace("Starting client to server connection ...\n");
223             // connect
224             nConRes = connect(ClientSocket, (struct sockaddr*)&server_addr_in, sizeof(server_addr_in));
225             ok(nConRes == SOCKET_ERROR, "ERROR: client connect() result is not SOCKET_ERROR\n");
226             ok(WSAGetLastError() == WSAEWOULDBLOCK, "ERROR: client connect() last error is not WSAEWOULDBLOCK\n");
227             ConnectSent = TRUE;
228             continue;
229         }
230         else
231         {
232             if (nSockNameRes != 0)
233                 ok(FALSE, "ERROR: getsockname function failed, expected 0 error %d\n", nSockNameRes);
234             if (len != sizeof(addr_con_loc))
235                 ok(FALSE, "ERROR: getsockname function wrong size, expected %Iu returned %d\n", sizeof(addr_con_loc), len);
236 
237             if (addr_con_loc.sin_addr.s_addr == 0ul)
238             {
239                 if (++Addr_con_locLoopCount >= MAX_LOOPCOUNT)
240                 {
241                     ok(FALSE, "Giving up, on getsockname() (%u/%u), as addr_con_loc is not set yet\n",
242                        Addr_con_locLoopCount, MAX_LOOPCOUNT);
243                     goto done;
244                 }
245 
246                 trace("Looping, for getsockname() (%u/%u), as addr_con_loc is not set yet\n",
247                       Addr_con_locLoopCount, MAX_LOOPCOUNT);
248                 Sleep(1);
249                 continue;
250             }
251 
252             if (addr_con_loc.sin_addr.s_addr != server_addr_in.sin_addr.s_addr)
253                 ok(FALSE, "ERROR: getsockname function wrong addr, expected %08lx returned %08lx\n", server_addr_in.sin_addr.s_addr, addr_con_loc.sin_addr.s_addr);
254         }
255         if ((dwFlags & FD_ACCEPT) != 0)
256         {// client connected
257             trace("Select CONNECT...\n");
258             dwFlags |= FD_CONNECT;
259         }
260 
261         FD_ZERO(&select_rfds);
262         FD_ZERO(&select_wfds);
263         FD_ZERO(&select_efds);
264         FD_SET(ServerSocket, &select_rfds);
265         FD_SET(ClientSocket, &select_rfds);
266         FD_SET(ServerSocket, &select_wfds);
267         FD_SET(ClientSocket, &select_wfds);
268         FD_SET(ServerSocket, &select_efds);
269         FD_SET(ClientSocket, &select_efds);
270         if ((dwFlags & FD_ACCEPT) != 0)
271         {
272             FD_SET(sockaccept, &select_rfds);
273             FD_SET(sockaccept, &select_wfds);
274             FD_SET(sockaccept, &select_efds);
275         }
276         if (select(0, &select_rfds, &select_wfds, &select_efds, &timeval) != 0)
277         {// connection accepted
278             if (dwFlags == (FD_ACCEPT | FD_CONNECT))
279             {
280                 trace("Select ACCEPT&CONNECT...\n");
281                 ok(FD_ISSET(ClientSocket, &select_wfds), "ClientSocket is not writable\n");
282                 ok(FD_ISSET(sockaccept, &select_wfds), "sockaccept is not writable\n");
283                 ok(!FD_ISSET(ServerSocket, &select_rfds), "ServerSocket is readable\n");
284             }
285             if (dwFlags == FD_ACCEPT)
286             {
287                 trace("Select ACCEPT...\n");
288                 ok(!FD_ISSET(ClientSocket, &select_wfds), "ClientSocket is writable\n");
289                 ok(FD_ISSET(sockaccept, &select_wfds), "sockaccept is not writable\n");
290                 ok(FD_ISSET(ServerSocket, &select_rfds), "ServerSocket is not readable\n");
291             }
292             if (dwFlags == 0)
293             {
294                 if (FD_ISSET(ServerSocket, &select_rfds))
295                 {
296                     trace("Select ACCEPT...\n");
297                     addrsize = sizeof(addr_remote);
298                     sockaccept = accept(ServerSocket, (struct sockaddr*)&addr_remote, &addrsize);
299                     ok(sockaccept != INVALID_SOCKET, "ERROR: Connection accept function failed, error %d\n", WSAGetLastError());
300                     dwFlags |= FD_ACCEPT;
301                 }
302                 else
303                 {
304                     if (++ServerSocketLoopCount >= MAX_LOOPCOUNT)
305                     {
306                         ok(FALSE, "Giving up, on select() (%u/%u), as ServerSocket is not readable yet\n",
307                            ServerSocketLoopCount, MAX_LOOPCOUNT);
308                         goto done;
309                     }
310 
311                     trace("Looping, for select() (%u/%u), as ServerSocket is not readable yet\n",
312                           ServerSocketLoopCount, MAX_LOOPCOUNT);
313                     Sleep(1);
314                     continue;
315                 }
316             }
317         }
318     }
319 
320 done:
321     WSACloseEvent(ServerEvent);
322     WSACloseEvent(ClientEvent);
323     closesocket(sockaccept);
324     closesocket(ServerSocket);
325     closesocket(ClientSocket);
326 
327     WSACleanup();
328 }
329