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