LCOV - code coverage report
Current view: directory - src/shared/imc - sigpipe_test.cc (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 437 266 60.9 %
Date: 2012-02-16 Functions: 0 0 -

       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 : }

Generated by: LCOV version 1.7