1 : /*
2 : * Copyright (c) 2011 The Native Client Authors. All rights reserved.
3 : * Use of this source code is governed by a BSD-style license that can be
4 : * found in the LICENSE file.
5 : */
6 :
7 : // Test that SIGPIPE is not raised when using NaClSendDatagram or
8 : // NaClSendDatagramTo when the peer has been closed for various
9 : // flavors of sockets.
10 :
11 : #include <stdio.h>
12 : #include <sys/types.h>
13 : #include <stdlib.h>
14 : #include <string.h>
15 : #include <errno.h>
16 :
17 : #include <vector>
18 :
19 : #include "native_client/src/include/checked_cast.h"
20 : #include "native_client/src/include/nacl_macros.h"
21 : #include "native_client/src/include/nacl_string.h"
22 : #include "native_client/src/include/portability.h"
23 : #include "native_client/src/include/portability_process.h"
24 : #include "native_client/src/shared/imc/nacl_imc_c.h"
25 : #include "native_client/src/shared/platform/nacl_log.h"
26 : #include "native_client/src/shared/platform/nacl_sync.h"
27 : #include "native_client/src/shared/platform/nacl_sync_checked.h"
28 : #include "native_client/src/shared/platform/nacl_threads.h"
29 :
30 : #if NACL_WINDOWS
31 : #define PRIHANDLE "p"
32 : #else
33 : #define PRIHANDLE "d"
34 : #endif
35 :
36 : namespace {
37 :
38 : const bool kPlatformUsesBoundSockets = NACL_WINDOWS;
39 :
40 : bool gSleepBeforeReceive(false);
41 2 : std::vector<int> gTestSequence;
42 :
43 : /*
44 : * PickRandomSocketAddress: choses a random socket address.
45 : *
46 : * NB: this uses rand() and thus is not thread-safe. However, this is
47 : * only used in the main thread.
48 : */
49 : void PickRandomSocketAddress(NaClSocketAddress *addr) {
50 : static const char alphabet[] =
51 : "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
52 : #if !NACL_WINDOWS
53 : "abcdefghijklmnopqrstuvwxyz"
54 : #endif
55 : "0123456789";
56 : static bool seeded = false; // not thread safe
57 :
58 : if (!(sizeof alphabet - 1 == 36 ||
59 : sizeof alphabet - 1 == 62)) {
60 : printf("Alphabet size error\n");
61 : abort();
62 : }
63 : if (!seeded) {
64 : srand(GETPID());
65 : seeded = 1;
66 : }
67 : for (int i = 0; i < NACL_PATH_MAX - 1; ++i) {
68 : addr->path[i] = alphabet[rand() % (sizeof alphabet - 1)];
69 : }
70 : addr->path[NACL_PATH_MAX - 1] = '\0';
71 : printf("PickRandomSocketAddress: returning %s\n", addr->path);
72 : }
73 :
74 :
75 0 : void MyPerror(nacl::string s) {
76 0 : char error_msg[512];
77 0 : int err = errno;
78 0 : if (0 == NaClGetLastErrorString(error_msg, sizeof error_msg)) {
79 0 : printf("%s: %s\n", s.c_str(), error_msg);
80 0 : } else {
81 0 : printf("%s: errno %d\n", s.c_str(), err);
82 : }
83 0 : errno = err;
84 0 : }
85 :
86 :
87 0 : void SplitString(std::vector<nacl::string> *result, nacl::string s, char sep) {
88 0 : nacl::string::size_type start;
89 0 : nacl::string::size_type sep_pos;
90 :
91 0 : for (start = 0;
92 0 : nacl::string::npos != (sep_pos = s.find(sep, start));
93 0 : start = sep_pos + 1) {
94 0 : result->push_back(s.substr(start, sep_pos - start));
95 0 : }
96 0 : if (start < s.length()) {
97 0 : result->push_back(s.substr(start));
98 0 : }
99 0 : }
100 :
101 0 : void ApplyInt(std::vector<int> *result, std::vector<nacl::string> const &vs) {
102 0 : for (std::vector<nacl::string>::const_iterator it = vs.begin();
103 0 : vs.end() != it;
104 0 : ++it) {
105 0 : result->push_back(strtol((*it).c_str(), static_cast<char **>(0), 0));
106 0 : }
107 0 : }
108 :
109 : struct TestState {
110 : NaClSocketAddress cli_addr;
111 : NaClSocketAddress srv_addr;
112 : NaClHandle cli_sock;
113 : NaClHandle srv_sock;
114 : NaClHandle pair[2];
115 :
116 : bool new_sock_only; // false to run only the single thread/socket
117 : // tests, true to do the complement
118 : int repetitions;
119 : int outer_rep;
120 :
121 : std::vector<int> *test_sequence;
122 :
123 : NaClMutex mu;
124 : NaClCondVar cv;
125 : int errors;
126 : int cur_test;
127 :
128 : int msg_len;
129 : char msg_buffer[512];
130 :
131 : TestState(std::vector<int> *, bool nso, int reps, int outer_rep);
132 : int Init();
133 : ~TestState();
134 : };
135 :
136 402 : TestState::TestState(std::vector<int> *seqp, bool nso, int reps,
137 402 : int out_rep)
138 : : cli_sock(NACL_INVALID_HANDLE),
139 : srv_sock(NACL_INVALID_HANDLE),
140 : new_sock_only(nso),
141 : repetitions(reps),
142 : outer_rep(out_rep),
143 : test_sequence(seqp),
144 : errors(-1),
145 201 : cur_test(-1) {
146 201 : pair[0] = NACL_INVALID_HANDLE;
147 201 : pair[1] = NACL_INVALID_HANDLE;
148 201 : NaClXMutexCtor(&mu);
149 201 : NaClXCondVarCtor(&cv);
150 402 : }
151 :
152 : int TestState::Init() {
153 : if (kPlatformUsesBoundSockets) {
154 : PickRandomSocketAddress(&cli_addr);
155 : cli_sock = NaClBoundSocket(&cli_addr);
156 : if (NACL_INVALID_HANDLE == cli_sock) {
157 : MyPerror("BoundSocket");
158 : printf("ERROR: No client socket\n");
159 : return 1;
160 : }
161 : PickRandomSocketAddress(&srv_addr);
162 : srv_sock = NaClBoundSocket(&srv_addr);
163 : if (NACL_INVALID_HANDLE == srv_sock) {
164 : MyPerror("BoundSocket");
165 : printf("ERROR: No server socket\n");
166 : return 1;
167 : }
168 : }
169 :
170 201 : if (-1 == NaClSocketPair(pair)) {
171 0 : MyPerror("SocketPair");
172 0 : printf("ERROR: no socket pair\n");
173 0 : return 1;
174 : }
175 :
176 201 : strncpy(msg_buffer, "hello world\n", sizeof msg_buffer);
177 201 : msg_buffer[sizeof msg_buffer - 1] = '\0';
178 201 : msg_len = nacl::assert_cast<int>(strlen(msg_buffer));
179 :
180 201 : printf("cli_sock %" PRIHANDLE ", srv_sock %" PRIHANDLE ","
181 : "pair[0] %" PRIHANDLE ", pair[1] %" PRIHANDLE "\n",
182 : cli_sock, srv_sock, pair[0], pair[1]);
183 :
184 201 : return 0;
185 201 : }
186 :
187 :
188 201 : TestState::~TestState() {
189 201 : if (NACL_INVALID_HANDLE != cli_sock) {
190 0 : printf("NaClClose(%" PRIHANDLE ")\n", cli_sock);
191 0 : (void) NaClClose(cli_sock);
192 0 : }
193 201 : if (NACL_INVALID_HANDLE != srv_sock) {
194 0 : printf("NaClClose(%" PRIHANDLE ")\n", srv_sock);
195 0 : (void) NaClClose(srv_sock);
196 0 : }
197 1206 : for (int i = 0; i < 2; ++i) {
198 402 : if (NACL_INVALID_HANDLE != pair[i]) {
199 401 : printf("NaClClose(%" PRIHANDLE ")\n", pair[i]);
200 401 : (void) NaClClose(pair[i]);
201 401 : }
202 402 : }
203 201 : (void) NaClCondVarDtor(&cv);
204 201 : (void) NaClMutexDtor(&mu);
205 402 : }
206 :
207 :
208 200 : int SendDescriptor(TestState *tsp, int mode) {
209 200 : int errors(0);
210 200 : NaClMessageHeader hdr;
211 200 : NaClHandle xfer[2];
212 200 : hdr.iov = NULL;
213 200 : hdr.iov_length = 0;
214 200 : hdr.handle_count = 1;
215 200 : hdr.handles = xfer;
216 : // &tsp->pair[0]; // bug w/ OSX, kernel oops
217 : // &tsp->cli_sock; // bug w/ bound sockets, eager NaClClose unlink
218 200 : if (-1 == NaClSocketPair(xfer)) { // an otherwise unused NaClHandle.
219 0 : ++errors;
220 0 : printf("SendDescriptr: could not create (unused) NaClSocketPair\n");
221 0 : return errors;
222 : }
223 200 : if (-1 == NaClClose(xfer[1])) {
224 0 : ++errors;
225 0 : printf("SendDescriptor: could not NaClClose the unused"
226 : " end of SocketPair\n");
227 0 : return errors;
228 : }
229 200 : hdr.flags = 0;
230 200 : printf("Sending a descriptor, mode %d\n", mode);
231 200 : int result(-1);
232 200 : nacl::string op;
233 200 : switch (mode) {
234 : case 0: {
235 0 : op = "SendDatagramTo";
236 0 : result = NaClSendDatagramTo(&hdr, 0, &tsp->srv_addr);
237 0 : break;
238 : }
239 : case 1: {
240 200 : op = "SendDatagram";
241 400 : result = NaClSendDatagram(tsp->pair[1], &hdr, 0);
242 200 : break;
243 : }
244 : default: {
245 0 : printf("ERROR: illegal test mode\n");
246 0 : ++errors;
247 0 : break;
248 : }
249 : }
250 200 : if (-1 == result) {
251 0 : MyPerror("SendDescriptor, " + op);
252 0 : printf("ERROR: SendDescriptor: %s failed.\n", op.c_str());
253 0 : ++errors;
254 200 : } else if (0 != result) {
255 0 : printf("ERROR: SendDescriptor: %s returned %d, expected 0.\n",
256 0 : op.c_str(),
257 : result);
258 0 : ++errors;
259 0 : } else {
260 200 : printf("SendDescriptor: OK\n");
261 : }
262 200 : NaClClose(xfer[0]);
263 200 : return errors;
264 400 : }
265 :
266 :
267 200 : int ReceiveDescriptor(TestState *tsp, int mode) {
268 200 : int errors(0);
269 200 : NaClMessageHeader hdr;
270 200 : NaClIOVec vec;
271 200 : char buffer[512];
272 200 : NaClHandle handle[8];
273 200 : int nbytes(-1);
274 200 : printf("ReceiverThread: receive a handle, mode %d\n", mode);
275 200 : vec.base = buffer;
276 200 : vec.length = sizeof buffer;
277 200 : hdr.iov = &vec;
278 200 : hdr.iov_length = 1;
279 200 : hdr.handles = handle;
280 200 : hdr.handle_count = NACL_ARRAY_SIZE(handle);
281 200 : hdr.flags = 0;
282 200 : switch (mode) {
283 : case 0: {
284 0 : nbytes = NaClReceiveDatagram(tsp->srv_sock, &hdr, 0);
285 0 : break;
286 : }
287 : case 1: {
288 200 : nbytes = NaClReceiveDatagram(tsp->pair[0], &hdr, 0);
289 200 : break;
290 : }
291 : default: {
292 0 : printf("ERROR: illegal test mode\n");
293 0 : ++errors;
294 0 : break;
295 : }
296 : }
297 200 : if (-1 == nbytes) {
298 0 : MyPerror("ReceiverThread, ReceiveDatagram");
299 0 : printf("ERROR: ReceiveDatagram failed, did not receive any handles.\n");
300 0 : ++errors;
301 0 : } else {
302 200 : if (0 != nbytes) {
303 0 : printf("ERROR: ReceiveDatagram should have received zero bytes"
304 : " of data, got %d.\n", nbytes);
305 0 : printf("ERROR: received \"%.*s\"\n", nbytes, buffer);
306 0 : ++errors;
307 0 : }
308 200 : if (1 != hdr.handle_count) {
309 0 : printf("ERROR: Did not receive a single handle.\n");
310 0 : ++errors;
311 0 : }
312 :
313 200 : if (NACL_ARRAY_SIZE(handle) < hdr.handle_count) {
314 0 : printf("ERROR: Too many handles: %" NACL_PRIu32, hdr.handle_count);
315 0 : return ++errors;
316 : }
317 800 : for (size_t i = 0; i < hdr.handle_count; ++i) {
318 200 : if (hdr.handles[i] == tsp->srv_sock) {
319 0 : printf("ERROR: received handle is same as srv_sock!\n");
320 0 : ++errors;
321 0 : continue;
322 : }
323 200 : if (hdr.handles[i] == tsp->cli_sock) {
324 0 : printf("ERROR: received handle is same as cli_sock!\n");
325 0 : ++errors;
326 0 : continue;
327 : }
328 200 : if (hdr.handles[i] == tsp->pair[0]) {
329 0 : printf("ERROR: received handle is same as pair[0]!\n");
330 0 : ++errors;
331 0 : continue;
332 : }
333 200 : if (hdr.handles[i] == tsp->pair[1]) {
334 0 : printf("ERROR: received handle is same as pair[1]!\n");
335 0 : ++errors;
336 0 : continue;
337 : }
338 200 : printf("close(%" PRIHANDLE ")\n", hdr.handles[i]);
339 200 : if (-1 == NaClClose(hdr.handles[i])) {
340 0 : MyPerror("ReceiverThread, Close");
341 0 : printf("ERROR: Close on received handle failed\n");
342 0 : ++errors;
343 0 : }
344 200 : }
345 : }
346 200 : if (0 == errors) {
347 200 : printf("ReceiverThread, receive handle: OK\n");
348 200 : } else {
349 0 : printf("ReceiverThread, receive handle: FAILED\n");
350 : }
351 200 : return errors;
352 200 : }
353 :
354 :
355 200 : int SendData(TestState *tsp, int mode) {
356 200 : int errors(0);
357 200 : NaClMessageHeader hdr;
358 200 : NaClIOVec vec;
359 200 : int nbytes(-1);
360 200 : vec.base = tsp->msg_buffer;
361 200 : vec.length = tsp->msg_len;
362 200 : hdr.iov = &vec;
363 200 : hdr.iov_length = 1;
364 200 : hdr.handle_count = 0;
365 200 : hdr.flags = 0;
366 200 : nacl::string op;
367 :
368 200 : printf("Sending data, mode %d\n", mode);
369 200 : switch (mode) {
370 : case 0: {
371 0 : op = "SendDatagramTo";
372 0 : nbytes = NaClSendDatagramTo(&hdr, 0, &tsp->srv_addr);
373 0 : break;
374 : }
375 : case 1: {
376 200 : op = "SendDatagram";
377 400 : nbytes = NaClSendDatagram(tsp->pair[1], &hdr, 0);
378 200 : } break;
379 : default: {
380 0 : printf("ERROR: Illegal test mode\n");
381 0 : ++errors;
382 0 : break;
383 : }
384 : }
385 200 : if (-1 == nbytes) {
386 0 : MyPerror("send thread " + op);
387 0 : printf("Send thread, %s failed\n", op.c_str());
388 0 : }
389 200 : if (nbytes != tsp->msg_len) {
390 0 : printf("ERROR: send thread, send data: %s did not send"
391 : " all bytes. Tried to send %d, but only %d actually sent.\n",
392 0 : op.c_str(), tsp->msg_len, nbytes);
393 0 : if (0 == mode) {
394 0 : printf("sock addr %s\n", tsp->srv_addr.path);
395 0 : }
396 0 : ++errors;
397 0 : } else {
398 200 : printf("Send thread, send data: OK\n");
399 : }
400 200 : return errors;
401 200 : }
402 :
403 200 : int ReceiveData(TestState *tsp, int mode) {
404 200 : int errors(0);
405 200 : NaClMessageHeader hdr;
406 200 : NaClIOVec vec;
407 200 : NaClHandle handle[8];
408 200 : int nbytes(-1);
409 200 : printf("ReceiverThread: receive data, mode %d\n", mode);
410 200 : char recv_buf[1024];
411 200 : memset(recv_buf, 0, sizeof recv_buf);
412 200 : vec.base = recv_buf;
413 200 : vec.length = sizeof recv_buf;
414 200 : hdr.iov = &vec;
415 200 : hdr.iov_length = 1;
416 200 : hdr.handles = handle;
417 200 : hdr.handle_count = NACL_ARRAY_SIZE(handle);
418 200 : hdr.flags = 0;
419 200 : switch (mode) {
420 : case 0: {
421 0 : nbytes = NaClReceiveDatagram(tsp->srv_sock, &hdr, 0);
422 0 : break;
423 : }
424 : case 1: {
425 200 : nbytes = NaClReceiveDatagram(tsp->pair[0], &hdr, 0);
426 200 : break;
427 : }
428 : default: {
429 0 : printf("ERROR: illegal test mode\n");
430 0 : ++errors;
431 0 : break;
432 : }
433 : }
434 200 : if (-1 == nbytes) {
435 0 : MyPerror("ReceiverThread, ReceiveDatagram");
436 0 : printf("ERROR: ReceiveDatagram failed, did not receive anything.\n");
437 0 : ++errors;
438 0 : } else {
439 200 : if (nbytes != tsp->msg_len) {
440 0 : MyPerror("ReceiveDatagram");
441 0 : printf("ERROR: ReceiveDatagram did not receive all bytes."
442 : " Buffer %" NACL_PRIuS ", expected %d, got %d bytes.\n",
443 : sizeof recv_buf, tsp->msg_len, nbytes);
444 0 : ++errors;
445 0 : }
446 200 : if (0 != strcmp(recv_buf, tsp->msg_buffer)) {
447 0 : printf("Received %s, sent %s\n", recv_buf, tsp->msg_buffer);
448 0 : ++errors;
449 0 : }
450 200 : if (0 != hdr.handle_count) {
451 0 : printf("ERROR: Did not receive zero handles.\n");
452 0 : ++errors;
453 0 : }
454 200 : if (NACL_ARRAY_SIZE(handle) < hdr.handle_count) {
455 0 : printf("Too many handles: %" NACL_PRIu32, hdr.handle_count);
456 0 : return ++errors;
457 : }
458 400 : for (size_t i = 0; i < hdr.handle_count; ++i) {
459 0 : if (hdr.handles[i] == tsp->srv_sock) {
460 0 : printf("ERROR: received handle is same as srv_sock!\n");
461 0 : ++errors;
462 0 : continue;
463 : }
464 0 : if (hdr.handles[i] == tsp->cli_sock) {
465 0 : printf("ERROR: received handle is same as cli_sock!\n");
466 0 : ++errors;
467 0 : continue;
468 : }
469 0 : if (hdr.handles[i] == tsp->pair[0]) {
470 0 : printf("ERROR: received handle is same as pair[0]!\n");
471 0 : ++errors;
472 0 : continue;
473 : }
474 0 : if (hdr.handles[i] == tsp->pair[1]) {
475 0 : printf("ERROR: received handle is same as pair[1]!\n");
476 0 : ++errors;
477 0 : continue;
478 : }
479 0 : printf("close(%" PRIHANDLE ")\n", hdr.handles[i]);
480 0 : if (-1 == NaClClose(hdr.handles[i])) {
481 0 : MyPerror("ReceiverThread, Close");
482 0 : printf("ERROR: Close on received handle failed\n");
483 0 : ++errors;
484 0 : }
485 0 : }
486 : }
487 200 : if (0 == errors) {
488 200 : printf("ReceiverThread, receive data: OK\n");
489 200 : } else {
490 0 : printf("ReceiverThread, receive data: FAILED\n");
491 : }
492 200 : return errors;
493 200 : }
494 :
495 1 : int SendDataNoPeer(TestState *tsp, int mode) {
496 1 : int errors(0);
497 1 : NaClMessageHeader hdr;
498 1 : NaClIOVec vec;
499 1 : int nbytes(-1);
500 1 : vec.base = tsp->msg_buffer;
501 1 : vec.length = tsp->msg_len;
502 1 : hdr.iov = &vec;
503 1 : hdr.iov_length = 1;
504 1 : hdr.handle_count = 0;
505 1 : hdr.flags = 0;
506 1 : nacl::string op;
507 1 : switch (mode) {
508 : case 0: {
509 0 : op = "SendDatagramTo";
510 0 : nbytes = NaClSendDatagramTo(&hdr, 0, &tsp->srv_addr);
511 0 : break;
512 : }
513 : case 1: {
514 1 : op = "SendDatagram";
515 2 : nbytes = NaClSendDatagram(tsp->pair[1], &hdr, 0);
516 1 : break;
517 : }
518 : default: {
519 0 : printf("ERROR: illegal test mode\n");
520 0 : ++errors;
521 0 : break;
522 : }
523 : }
524 :
525 : #if NACL_WINDOWS
526 : if (-1 != nbytes
527 : || (0 == mode && ERROR_FILE_NOT_FOUND != GetLastError())
528 : || (1 == mode && ERROR_NO_DATA != GetLastError())) {
529 : MyPerror(op);
530 : printf("ERROR: no peer, nbytes %d, GetLastError => %d\n",
531 : nbytes,
532 : GetLastError());
533 : ++errors;
534 : } else {
535 : printf("OK\n");
536 : }
537 : #else
538 2 : if (-1 != nbytes
539 1 : || (0 == mode && ECONNREFUSED != errno)
540 2 : || (1 == mode && EPIPE != errno)) {
541 0 : MyPerror(op);
542 0 : printf("ERROR: no peer, nbytes %d, errno %d\n", nbytes, errno);
543 0 : ++errors;
544 0 : } else {
545 1 : printf("OK\n");
546 : }
547 : #endif
548 1 : return errors;
549 1 : }
550 :
551 : struct TestFn {
552 : char const *name;
553 : int (*sender)(TestState *, int);
554 : int (*receiver)(TestState *, int);
555 : int mode; // currently, only 0,1 for using bound socket and socketpair
556 : bool new_socks; // run test w/ per-test sockets
557 : bool flakey; // known-to-be-flakey test (known IMC implementation bug)
558 : } test_fn[] = { {
559 : "Send one descriptor via bound socket, shared socket",
560 : SendDescriptor,
561 : ReceiveDescriptor,
562 : 0,
563 : false,
564 : false,
565 : }, {
566 : "Send some data via bound socket, shared socket",
567 : SendData,
568 : ReceiveData,
569 : 0,
570 : false,
571 : #if NACL_WINDOWS
572 : true, // known not to be flakey
573 : #else
574 : false,
575 : #endif
576 : }, {
577 : "Send one descriptor via socket pair, shared socket",
578 : SendDescriptor,
579 : ReceiveDescriptor,
580 : 1,
581 : false,
582 : false,
583 : }, {
584 : "Send some data via socket pair, shared socket",
585 : SendData,
586 : ReceiveData,
587 : 1,
588 : false,
589 : false,
590 : }, {
591 : "Send one descriptor via bound socket, per test socket",
592 : SendDescriptor,
593 : ReceiveDescriptor,
594 : 0,
595 : true,
596 : false,
597 : }, {
598 : "Send some data via bound socket, per test socket",
599 : SendData,
600 : ReceiveData,
601 : 0,
602 : true,
603 : #if NACL_WINDOWS
604 : true, // known not to work: first msg must be a desc xfer
605 : #else
606 : false,
607 : #endif
608 : }, {
609 : "Send one descriptor via socket pair, per test socket",
610 : SendDescriptor,
611 : ReceiveDescriptor,
612 : 1,
613 : true,
614 : false,
615 : }, {
616 : "Send some data via socket pair, per test socket",
617 : SendData,
618 : ReceiveData,
619 : 1,
620 : true,
621 : false,
622 : },
623 : // add more tests here
624 : };
625 :
626 201 : void WINAPI PeerThread(void *state) {
627 201 : int errors(0);
628 201 : TestState *tsp = reinterpret_cast<TestState *>(state);
629 :
630 1002 : for (int i = 0; i < tsp->repetitions; ++i) {
631 300 : if (-1 == tsp->outer_rep)
632 100 : printf("\n======== PEER THREAD, REPETITION %d ========\n", i);
633 : else
634 200 : printf("\n======== INDEPENDENT PEER THREAD, REPETITION %d ========\n",
635 : tsp->outer_rep);
636 300 : for (std::vector<int>::const_iterator it = tsp->test_sequence->begin();
637 900 : tsp->test_sequence->end() != it;
638 600 : ++it) {
639 600 : int test = *it;
640 :
641 600 : if (test_fn[test].new_socks != tsp->new_sock_only) {
642 200 : printf("PeerThread: new_socks mismatch, skipping\n");
643 200 : continue;
644 : }
645 :
646 400 : printf("PeerThread: Locking for test %d to start\n", test);
647 400 : NaClXMutexLock(&tsp->mu);
648 999 : while (tsp->cur_test != test) {
649 199 : printf("PeerThread: waiting for test %d to start\n", test);
650 199 : printf("tsp->cur_test %d\n", tsp->cur_test);
651 199 : NaClXCondVarWait(&tsp->cv, &tsp->mu);
652 199 : }
653 400 : NaClXMutexUnlock(&tsp->mu);
654 :
655 400 : printf("PeerThread: START test %d, %s\n", test, test_fn[test].name);
656 400 : errors += test_fn[test].sender(tsp, test_fn[test].mode);
657 400 : printf("PeerThread: END test %d, %s\n", test, test_fn[test].name);
658 :
659 400 : printf("PeerThread: Locking for test %d to end\n", test);
660 400 : NaClXMutexLock(&tsp->mu);
661 400 : tsp->cur_test = -1;
662 400 : NaClXCondVarSignal(&tsp->cv);
663 400 : NaClXMutexUnlock(&tsp->mu);
664 400 : }
665 300 : }
666 201 : if (-1 == tsp->outer_rep)
667 1 : printf("\n======== EXITING PEER THREAD ========\n");
668 : else
669 200 : printf("\n======== EXITING INDEPENDENT PEER THREAD"
670 : " ========\n");
671 :
672 201 : printf("%sPEER THREAD EXITING, LOCKING\n",
673 : (-1 == tsp->outer_rep) ? "" : "INDEPENDENT ");
674 201 : NaClXMutexLock(&tsp->mu);
675 201 : tsp->errors = errors;
676 201 : printf("%sPEER THREAD EXITING, SIGNALING\n",
677 : (-1 == tsp->outer_rep) ? "" : "INDEPENDENT ");
678 201 : fflush(NULL);
679 201 : NaClXCondVarSignal(&tsp->cv);
680 201 : NaClXMutexUnlock(&tsp->mu);
681 201 : }
682 :
683 :
684 1 : int TestNaClSocket(int rep_count) {
685 1 : int errors = 0;
686 1 : TestState tstate(&gTestSequence, false, rep_count, -1);
687 :
688 2 : errors += tstate.Init();
689 1 : if (0 != errors) return errors;
690 :
691 : // The Windows IMC implementation deadlocks if SendDatagramTo is
692 : // invoked while nobody is doing a ReceiveDatagram. Thus, we spawn
693 : // a receiver thread.
694 :
695 1 : printf("Starting receiver thread.\n");
696 1 : struct NaClThread thr;
697 2 : if (!NaClThreadCtor(&thr, PeerThread, static_cast<void *>(&tstate),
698 : 128*1024)) {
699 0 : NaClLog(LOG_FATAL, "TestNaClSocket could not create receiver thread!\n");
700 0 : }
701 :
702 202 : for (int rep = 0; rep < rep_count; ++rep) {
703 100 : printf("\n======== MAIN THREAD, START REPETITION %d ========\n", rep);
704 300 : for (std::vector<int>::const_iterator it = gTestSequence.begin();
705 1500 : gTestSequence.end() != it;
706 800 : ++it) {
707 800 : int test = *it;
708 400 : printf("MainThread: test %d, %s\n", test, test_fn[test].name);
709 400 : fflush(NULL);
710 :
711 400 : if (gSleepBeforeReceive) {
712 0 : printf("Sleeping.\n");
713 0 : fflush(NULL);
714 : #if NACL_WINDOWS
715 : Sleep(1000);
716 : #else
717 0 : sleep(1);
718 : #endif
719 0 : }
720 :
721 400 : if (!test_fn[test].new_socks) {
722 200 : printf("Locking to start test %d\n", test);
723 200 : NaClXMutexLock(&tstate.mu);
724 200 : tstate.cur_test = test;
725 200 : NaClXCondVarSignal(&tstate.cv);
726 200 : NaClXMutexUnlock(&tstate.mu);
727 200 : printf("Signaled test %d start\n", test);
728 :
729 400 : errors += test_fn[test].receiver(&tstate, test_fn[test].mode);
730 :
731 200 : printf("Locking to wait for test %d end\n", test);
732 200 : NaClXMutexLock(&tstate.mu);
733 401 : while (-1 != tstate.cur_test) {
734 1 : printf("Waiting for test %d to be finished\n", test);
735 1 : printf("tstate.cur_test %d\n", tstate.cur_test);
736 1 : NaClXCondVarWait(&tstate.cv, &tstate.mu);
737 1 : }
738 200 : NaClXMutexUnlock(&tstate.mu);
739 200 : } else {
740 200 : printf("test %d requests independent socket/thread\n", test);
741 400 : std::vector<int> seq;
742 200 : seq.push_back(test);
743 200 : TestState private_sock(&seq, true, 1, rep);
744 400 : int private_errors(private_sock.Init());
745 200 : if (0 != private_errors) {
746 0 : printf("Could not create/initialize TestState.\n");
747 0 : errors += private_errors;
748 0 : continue;
749 : }
750 200 : struct NaClThread private_thr;
751 400 : if (!NaClThreadCtor(&private_thr, PeerThread,
752 : static_cast<void *>(&private_sock), 128*1024)) {
753 0 : NaClLog(LOG_FATAL, "TestNaClSocket could not create PeerThread\n");
754 0 : }
755 :
756 200 : printf("Locking to start test %d\n", test);
757 200 : NaClXMutexLock(&private_sock.mu);
758 200 : private_sock.cur_test = test;
759 200 : NaClXCondVarSignal(&private_sock.cv);
760 200 : NaClXMutexUnlock(&private_sock.mu);
761 200 : printf("Signaled test %d start\n", test);
762 :
763 400 : errors += test_fn[test].receiver(&private_sock, test_fn[test].mode);
764 :
765 200 : printf("Locking to wait for test %d end\n", test);
766 200 : NaClXMutexLock(&private_sock.mu);
767 410 : while (-1 != private_sock.cur_test) {
768 10 : printf("Waiting for test %d to be finished\n", test);
769 10 : printf("private_sock %d\n", private_sock.cur_test);
770 10 : NaClXCondVarWait(&private_sock.cv, &private_sock.mu);
771 10 : }
772 200 : NaClXMutexUnlock(&private_sock.mu);
773 :
774 200 : fflush(NULL);
775 200 : NaClXMutexLock(&private_sock.mu);
776 409 : while (-1 == private_sock.errors) {
777 9 : NaClXCondVarWait(&private_sock.cv, &private_sock.mu);
778 9 : }
779 200 : NaClXMutexUnlock(&private_sock.mu);
780 200 : errors += private_sock.errors;
781 200 : if (private_sock.outer_rep != rep) {
782 0 : printf("Threads out of sync!?!\n");
783 0 : abort();
784 : }
785 600 : }
786 400 : }
787 100 : }
788 :
789 :
790 1 : printf("MainThread: Waiting for receiver thread to exit.\n");
791 1 : fflush(NULL);
792 1 : NaClXMutexLock(&tstate.mu);
793 2 : while (-1 == tstate.errors) {
794 0 : NaClXCondVarWait(&tstate.cv, &tstate.mu);
795 0 : }
796 1 : NaClXMutexUnlock(&tstate.mu);
797 1 : NaClThreadDtor(&thr);
798 1 : errors += tstate.errors;
799 :
800 : // now close server side and attempt to send again.
801 1 : printf("NaClClose(%" PRIHANDLE ")\n", tstate.srv_sock);
802 1 : (void) NaClClose(tstate.srv_sock);
803 1 : tstate.srv_sock = NACL_INVALID_HANDLE;
804 1 : printf("NaClClose(%" PRIHANDLE ")\n", tstate.pair[0]);
805 1 : (void) NaClClose(tstate.pair[0]);
806 1 : tstate.pair[0] = NACL_INVALID_HANDLE;
807 :
808 : if (kPlatformUsesBoundSockets) {
809 : printf("Sending a datagram to an address with closed bound socket.\n");
810 : SendDataNoPeer(&tstate, 0);
811 : }
812 1 : printf("Sending a datagram to a socketpair where peer was closed.\n");
813 1 : SendDataNoPeer(&tstate, 1);
814 :
815 1 : return errors;
816 1 : }
817 :
818 : void ListTests() {
819 0 : for (size_t ix = 0; ix < NACL_ARRAY_SIZE(test_fn); ++ix) {
820 0 : printf("%3" NACL_PRIuS ": %s\n", ix, test_fn[ix].name);
821 0 : if (test_fn[ix].flakey) {
822 0 : printf(" NB: known to be flakey on this platform\n");
823 0 : }
824 0 : }
825 0 : }
826 :
827 : } // anonymous namespace
828 :
829 :
830 1 : int main(int ac,
831 1 : char **av) {
832 1 : int errors(0);
833 1 : int opt;
834 1 : int rep_count(100);
835 :
836 1 : char obuf[BUFSIZ];
837 :
838 1 : setvbuf(stdout, obuf, _IOLBF, sizeof obuf);
839 :
840 1 : NaClLogModuleInit();
841 :
842 2 : while (-1 != (opt = getopt(ac, av, "lr:st:"))) {
843 0 : switch (opt) {
844 : case 'l': {
845 0 : ListTests();
846 0 : return 0;
847 : }
848 : case 'r': {
849 0 : rep_count = strtol(optarg, static_cast<char **>(NULL), 0);
850 0 : break;
851 : }
852 : case 's': {
853 0 : gSleepBeforeReceive = true;
854 0 : break;
855 : }
856 : case 't': {
857 0 : std::vector<nacl::string> vs;
858 0 : SplitString(&vs, optarg, ',');
859 0 : ApplyInt(&gTestSequence, vs);
860 : break;
861 0 : }
862 : default: {
863 0 : fprintf(stderr,
864 : "Usage: sigpipe_test [-l] [-r reps] [-s] [-t tests]\n"
865 : " -l list available tests\n"
866 : " -r run test sequence reps number of times\n"
867 : " -s sleep between receiving handle and data\n"
868 : " -t test sequence, a comma separated integers specifying\n"
869 : " which tests to run and in what order\n");
870 0 : exit(1);
871 : }
872 : }
873 0 : }
874 1 : if (gTestSequence.empty()) {
875 18 : for (size_t i = 0; i < NACL_ARRAY_SIZE(test_fn); ++i) {
876 16 : if (!test_fn[i].flakey &&
877 : (kPlatformUsesBoundSockets || test_fn[i].mode != 0)) {
878 4 : gTestSequence.push_back(nacl::assert_cast<int>(i));
879 4 : }
880 8 : }
881 1 : }
882 1 : printf("Test sequence:\n");
883 1 : for (std::vector<int>::const_iterator it = gTestSequence.begin();
884 5 : gTestSequence.end() != it;
885 4 : ++it) {
886 4 : if ((unsigned) *it >= NACL_ARRAY_SIZE(test_fn)) {
887 0 : fprintf(stderr, "No test %d\n", *it);
888 0 : ++errors;
889 0 : } else {
890 4 : printf(" %d: %s\n", *it, test_fn[*it].name);
891 : }
892 4 : }
893 :
894 1 : if (errors) {
895 0 : printf("Test specification error.\n");
896 0 : return errors;
897 : }
898 : #if NACL_WINDOWS
899 : if (0 != gTestSequence[0]) {
900 : printf("WARNING: it is known that the Windows IMC implementation\n"
901 : "fails if the first operation is not send descriptor\n");
902 : fflush(NULL);
903 : }
904 : #endif
905 :
906 1 : errors += TestNaClSocket(rep_count);
907 :
908 3 : printf("%s\n", (errors == 0) ? "PASSED" : "FAILED");
909 :
910 1 : NaClLogModuleFini();
911 :
912 1 : return errors;
913 1 : }
|