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