master
c 649 lines 13.6 KB
Raw
1 /*++
2
3 Copyright (c) Microsoft. All rights reserved.
4
5 Module Name:
6
7 socket_nonblock.c
8
9 Abstract:
10
11 This file is a simple test for nonblocking sockets.
12
13 --*/
14
15 #include "lxtcommon.h"
16 #include "unittests.h"
17 #include <sys/epoll.h>
18 #include <fcntl.h>
19 #include <errno.h>
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <sys/types.h>
26 #include <sys/socket.h>
27 #include <sys/un.h>
28 #include <netinet/in.h>
29 #include <netdb.h>
30 #include "common.h"
31
32 #include <sys/wait.h>
33
34 #define LXT_NAME "socket_nonblocking"
35
36 int SocketAsyncTest(PLXT_ARGS Args);
37
38 #define SOCKET_NAME "PartyInTheUsa"
39
40 //
41 // Global constants
42 //
43
44 static const LXT_VARIATION g_LxtVariations[] = {
45 {"Socket_Async_Simple", SocketAsyncTest},
46 };
47
48 int SocketNonblockTestEntry(int Argc, char* Argv[])
49
50 /*++
51 --*/
52
53 {
54
55 LXT_ARGS Args;
56 int Result;
57
58 LxtCheckResult(LxtInitialize(Argc, Argv, &Args, LXT_NAME));
59 LxtCheckResult(LxtRunVariations(&Args, g_LxtVariations, LXT_COUNT_OF(g_LxtVariations)));
60
61 ErrorExit:
62 LxtUninitialize();
63 return !LXT_SUCCESS(Result);
64 }
65
66 #ifndef EPOLLONESHOT
67 #define EPOLLONESHOT (1 << 30)
68 #endif
69
70 int NonblockEpollCreateClientSocket(int IsNonBlocking)
71
72 /*++
73 --*/
74
75 {
76 int Result;
77 struct sockaddr_in ServerAddress = {0};
78 int Socket;
79
80 //
81 // Create a socket.
82 //
83
84 Socket = socket(AF_INET, SOCK_STREAM, 0);
85 if (Socket < 0)
86 {
87 LxtLogError("socket(AF_INET, SOCK_STREAM, 0) - %s", strerror(errno));
88 Result = -1;
89 goto cleanup;
90 }
91
92 //
93 // Connect to the server.
94 //
95
96 ServerAddress.sin_family = AF_INET;
97 ServerAddress.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
98 ServerAddress.sin_port = htons(LXT_SOCKET_DEFAULT_PORT);
99
100 Result = connect(Socket, (struct sockaddr*)&ServerAddress, sizeof(ServerAddress));
101
102 if (Result < 0)
103 {
104 LxtLogError("connect(%d) - %s", Socket, strerror(errno));
105 Result = -1;
106 goto cleanup;
107 }
108
109 //
110 // Set the socket as non blocking.
111 //
112
113 if (IsNonBlocking != 0)
114 {
115 Result = fcntl(Socket, F_SETFL, O_NONBLOCK);
116 if (Result < 0)
117 {
118 LxtLogError("fcntl(%d) - %d", Socket, errno);
119 Result = -1;
120 goto cleanup;
121 }
122 }
123
124 Result = Socket;
125 Socket = 0;
126
127 cleanup:
128 if (Socket > 0)
129 {
130 if (close(Socket) != 0)
131 {
132 LxtLogError("close(%d) - %s", Socket, strerror(errno));
133 Result = LXT_RESULT_FAILURE;
134 }
135 }
136
137 return Result;
138 }
139
140 int NonblockEpollCreateClientUnixSocket(int IsNonBlocking)
141
142 /*++
143 --*/
144
145 {
146 int Result;
147 struct sockaddr_un ServerAddress = {0};
148 int Socket;
149
150 //
151 // Create a socket.
152 //
153
154 Socket = socket(AF_UNIX, SOCK_STREAM, 0);
155 if (Socket < 0)
156 {
157 LxtLogError("socket(AF_UNIX, SOCK_STREAM, 0) - %s", strerror(errno));
158 Result = -1;
159 goto cleanup;
160 }
161
162 //
163 // Connect to the server.
164 //
165
166 ServerAddress.sun_family = AF_UNIX;
167 strcpy(ServerAddress.sun_path, SOCKET_NAME);
168
169 Result = connect(Socket, (struct sockaddr*)&ServerAddress, sizeof(ServerAddress));
170
171 if (Result < 0)
172 {
173 LxtLogError("connect(%d) - %s", Socket, strerror(errno));
174 Result = -1;
175 goto cleanup;
176 }
177
178 //
179 // Set the socket as non blocking.
180 //
181
182 if (IsNonBlocking != 0)
183 {
184 Result = fcntl(Socket, F_SETFL, O_NONBLOCK);
185 if (Result < 0)
186 {
187 LxtLogError("fcntl(%d) - %d", Socket, errno);
188 Result = -1;
189 goto cleanup;
190 }
191 }
192
193 Result = Socket;
194 Socket = 0;
195
196 cleanup:
197 if (Socket > 0)
198 {
199 if (close(Socket) != 0)
200 {
201 LxtLogError("close(%d) - %s", Socket, strerror(errno));
202 Result = LXT_RESULT_FAILURE;
203 }
204 }
205
206 return Result;
207 }
208
209 int NonblockEpollCreateListenSocket(int IsNonBlocking)
210
211 /*++
212 --*/
213
214 {
215
216 struct sockaddr_in ServerAddress = {0};
217 int Result;
218 int Socket;
219
220 //
221 // Create a socket.
222 //
223
224 Socket = socket(AF_INET, SOCK_STREAM, 0);
225 if (Socket < 0)
226 {
227 LxtLogError("socket - %s", strerror(errno));
228 Result = -1;
229 goto cleanup;
230 }
231
232 //
233 // Bind the socket to an ipv4 socket.
234 //
235
236 ServerAddress.sin_family = AF_INET;
237 ServerAddress.sin_addr.s_addr = INADDR_ANY;
238 ServerAddress.sin_port = htons(LXT_SOCKET_DEFAULT_PORT);
239
240 Result = bind(Socket, (struct sockaddr*)&ServerAddress, sizeof(ServerAddress));
241
242 if (Result < 0)
243 {
244 LxtLogError("bind(%d) - %s", Socket, strerror(errno));
245 Result = -1;
246 goto cleanup;
247 }
248
249 //
250 // Mark the socket as a listen socket.
251 //
252
253 Result = listen(Socket, LXT_SOCKET_SERVER_MAX_BACKLOG_NUM);
254 if (Result < 0)
255 {
256 LxtLogError("listen(%d) - %s", Socket, strerror(errno));
257 Result = -1;
258 goto cleanup;
259 }
260
261 //
262 // Set the socket as non blocking.
263 //
264
265 if (IsNonBlocking != 0)
266 {
267 Result = fcntl(Socket, F_SETFL, O_NONBLOCK);
268 if (Result < 0)
269 {
270 LxtLogError("fcntl(%d) - %d", Socket, errno);
271 Result = -1;
272 goto cleanup;
273 }
274 }
275
276 Result = Socket;
277 Socket = 0;
278
279 cleanup:
280
281 if (Socket > 0)
282 {
283 if (close(Socket) != 0)
284 {
285 LxtLogError("close(%d) - %s", Socket, strerror(errno));
286 }
287 }
288
289 return Result;
290 }
291
292 int NonblockEpollCreateListenUnixSocket(int IsNonBlocking)
293
294 /*++
295 --*/
296
297 {
298
299 struct sockaddr_un ServerAddress = {0};
300 int Result;
301 int Socket;
302
303 //
304 // Create a socket.
305 //
306
307 Socket = socket(AF_UNIX, SOCK_STREAM, 0);
308 if (Socket < 0)
309 {
310 LxtLogError("socket - %s", strerror(errno));
311 Result = -1;
312 goto cleanup;
313 }
314
315 //
316 // Bind the socket to an ipv4 socket.
317 //
318
319 ServerAddress.sun_family = AF_UNIX;
320 strcpy(ServerAddress.sun_path, SOCKET_NAME);
321
322 Result = bind(Socket, (struct sockaddr*)&ServerAddress, sizeof(ServerAddress));
323
324 if (Result < 0)
325 {
326 LxtLogError("bind(%d) - %s", Socket, strerror(errno));
327 Result = -1;
328 goto cleanup;
329 }
330
331 //
332 // Mark the socket as a listen socket.
333 //
334
335 Result = listen(Socket, LXT_SOCKET_SERVER_MAX_BACKLOG_NUM);
336 if (Result < 0)
337 {
338 LxtLogError("listen(%d) - %s", Socket, strerror(errno));
339 Result = -1;
340 goto cleanup;
341 }
342
343 //
344 // Set the socket as non blocking.
345 //
346
347 if (IsNonBlocking != 0)
348 {
349 Result = fcntl(Socket, F_SETFL, O_NONBLOCK);
350 if (Result < 0)
351 {
352 LxtLogError("fcntl(%d) - %d", Socket, errno);
353 Result = -1;
354 goto cleanup;
355 }
356 }
357
358 Result = Socket;
359 Socket = 0;
360
361 cleanup:
362
363 if (Socket > 0)
364 {
365 if (close(Socket) != 0)
366 {
367 LxtLogError("close(%d) - %s", Socket, strerror(errno));
368 }
369 }
370
371 return Result;
372 }
373 int NonblockEpollHandleClientAccept(int Socket)
374
375 /*++
376 --*/
377
378 {
379
380 struct sockaddr_in ClientAddress = {0};
381 socklen_t ClientLength;
382 int Error;
383 int Result;
384 int RetryCount;
385
386 ClientLength = sizeof(ClientAddress);
387 Result = -1;
388 RetryCount = 0;
389
390 while (1)
391 {
392 Result = accept(Socket, (struct sockaddr*)&ClientAddress, &ClientLength);
393 if (Result < 0)
394 {
395 Error = errno;
396 LxtLogInfo("[Server] accept(%d) returned %d (error %d)", Socket, Result, Error);
397
398 if (Error == EAGAIN)
399 {
400 LxtLogInfo("[Server] nonblocking accept said try again, sleeping...");
401 usleep(1 * 1000 * 1000);
402
403 RetryCount += 1;
404 if (RetryCount > 10)
405 {
406 LxtLogInfo("[Server] too many retries, exiting...");
407 Result = -1;
408 goto cleanup;
409 }
410
411 continue;
412 }
413 }
414
415 break;
416 }
417
418 cleanup:
419
420 return Result;
421 }
422
423 const char* NonblockDataToWrite[] = {
424 "<This is the first message> ",
425 "<This is another message> ",
426 "<Dumbledore is dead> ",
427 "<Harry Potter must not go back to Hogwarts> ",
428 "<There must always be a stark in Winterfell>",
429 };
430
431 const int NonblockWriteItemCount = sizeof(NonblockDataToWrite) / sizeof(NonblockDataToWrite[0]);
432
433 int SocketAsyncTest(PLXT_ARGS Args)
434
435 /*++
436 --*/
437
438 {
439
440 char Buffer[256];
441 int Result;
442 int EpollFileDescriptor;
443 int FileDescriptor1;
444 int FileDescriptor2;
445 struct epoll_event EpollControlEvent;
446 struct epoll_event EpollWaitEvent[2];
447 int ChildPid;
448 int Index;
449 int ChildStatus;
450 int RetryCount;
451
452 //
453 // Initialize locals.
454 //
455
456 FileDescriptor1 = -1;
457 FileDescriptor2 = -1;
458 EpollFileDescriptor = -1;
459 ChildPid = -1;
460
461 //
462 // Create the server socket.
463 //
464
465 LxtLogInfo("[Setup] About to create server socket...");
466
467 FileDescriptor1 = NonblockEpollCreateListenSocket(1);
468 if (FileDescriptor1 == -1)
469 {
470 Result = errno;
471 LxtLogError("[Setup] Could not create socket! %d", Result);
472 goto cleanup;
473 }
474
475 //
476 // Fork to create a server and a client.
477 //
478
479 LxtLogInfo("[Setup] About to fork...");
480
481 ChildPid = fork();
482
483 if (ChildPid == -1)
484 {
485 Result = errno;
486 LxtLogError("[Setup] Fork failed! %d", Result);
487 goto cleanup;
488 }
489
490 if (ChildPid == 0)
491 {
492
493 LxtLogInfo("[Client] Waiting 5 seconds to let server block...");
494
495 usleep(5 * 1000 * 1000);
496
497 LxtLogInfo("[Client] Connecting to server...");
498
499 FileDescriptor2 = NonblockEpollCreateClientSocket(1);
500 if (FileDescriptor2 == -1)
501 {
502 Result = errno;
503 LxtLogError("[Client] Could not connect to server! %d", Result);
504 goto cleanup;
505 }
506
507 LxtLogInfo("[Client] Connected to server, fd = %d", FileDescriptor2);
508
509 //
510 // Wait for data to be available in a loop.
511 //
512
513 RetryCount = 0;
514 while (1)
515 {
516
517 LxtLogInfo("[Client] Trying to read data ...");
518
519 memset(Buffer, 0, sizeof(Buffer));
520
521 Result = read(FileDescriptor2, Buffer, sizeof(Buffer));
522 if (Result < 0)
523 {
524 Result = errno;
525 if (Result = EAGAIN)
526 {
527 LxtLogInfo("[Client] No data available, will try again...");
528 usleep(1 * 1000 * 1000);
529
530 RetryCount += 1;
531 if (RetryCount > 10)
532 {
533 LxtLogInfo("[Client] Too many retries, exiting...");
534 Result = -1;
535
536 goto cleanup;
537 }
538
539 continue;
540 }
541
542 Result = -1;
543 goto cleanup;
544 }
545
546 LxtLogInfo("[Client] read %d bytes: %s ...", Result, Buffer);
547
548 if (Result == 0)
549 {
550 LxtLogInfo("[Client] exiting after reading 0 bytes ...");
551 goto cleanup;
552 }
553
554 //
555 // Reset the retry count after a successful read.
556 //
557
558 RetryCount = 0;
559 }
560 }
561
562 //
563 // Accept an incoming connection.
564 //
565
566 FileDescriptor2 = NonblockEpollHandleClientAccept(FileDescriptor1);
567 if (FileDescriptor2 == -1)
568 {
569 Result = errno;
570 LxtLogError("[Server] Could not accept! %d", Result);
571 goto cleanup;
572 }
573
574 LxtLogInfo("[Server] Writing to socket %d times!", NonblockWriteItemCount);
575
576 for (Index = 0; Index < NonblockWriteItemCount; Index += 1)
577 {
578
579 Result = write(FileDescriptor2, NonblockDataToWrite[Index], strlen(NonblockDataToWrite[Index]));
580
581 if (Result < 0)
582 {
583 LxtLogError("[Server] Write %d failed %d", Index, Result);
584
585 goto cleanup;
586 }
587
588 LxtLogInfo(
589 "[Server] Write (%d, %s, %d) -> %d!",
590 FileDescriptor2,
591 NonblockDataToWrite[Index],
592 strlen(NonblockDataToWrite[Index]) + (Index == NonblockWriteItemCount - 1),
593 Result);
594
595 usleep(1 * 1000 * 1000);
596 }
597
598 LxtLogInfo("[Server] Closing client fd = %d", FileDescriptor2);
599 if (FileDescriptor2 != -1)
600 {
601 close(FileDescriptor2);
602 FileDescriptor2 = -1;
603 }
604
605 LxtLogInfo("[Server] Waiting for child to exit");
606
607 ChildStatus = 0;
608 wait(&ChildStatus);
609
610 LxtLogInfo("[Server] Child WIFEXITED=%d WEXITSTATUS=%d", WIFEXITED(ChildStatus), WEXITSTATUS(ChildStatus));
611
612 //
613 // Determine if the test passed or failed.
614 //
615
616 if ((Result < 0) || (WIFEXITED(ChildStatus) == 0) || (WEXITSTATUS(ChildStatus) != 0))
617 {
618
619 LxtLogInfo("[Server] Test failed!");
620 Result = -1;
621 }
622
623 LxtLogInfo("[Server] Done");
624
625 cleanup:
626
627 if (FileDescriptor1 != -1)
628 {
629 close(FileDescriptor1);
630 }
631
632 if (EpollFileDescriptor != -1)
633 {
634 close(EpollFileDescriptor);
635 }
636
637 if (FileDescriptor2 != -1)
638 {
639 close(FileDescriptor2);
640 }
641
642 if (ChildPid == 0)
643 {
644 LxtLogInfo("[Child] Exit with %d!", Result);
645 _exit(Result);
646 }
647
648 return Result;
649 }