nsprpub/pr/tests/tmoacc.c

Fri, 16 Jan 2015 04:50:19 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 04:50:19 +0100
branch
TOR_BUG_9701
changeset 13
44a2da4a2ab2
permissions
-rw-r--r--

Replace accessor implementation with direct member state manipulation, by
request https://trac.torproject.org/projects/tor/ticket/9701#comment:32

     1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include "nspr.h"
     8 #include <stdlib.h>
     9 #include <string.h>
    11 #include "plerror.h"
    12 #include "plgetopt.h"
    14 #define BASE_PORT 9867
    15 #define DEFAULT_THREADS 1
    16 #define DEFAULT_BACKLOG 10
    17 #define DEFAULT_TIMEOUT 10
    18 #define RANDOM_RANGE 100  /* should be significantly smaller than RAND_MAX */
    20 typedef enum {running, stopped} Status;
    22 typedef struct Shared
    23 {
    24     PRLock *ml;
    25     PRCondVar *cv;
    26     PRBool passed;
    27     PRBool random;
    28     PRFileDesc *debug;
    29     PRIntervalTime timeout;
    30     PRFileDesc *listenSock;
    31     Status status;
    32 } Shared;
    34 static PRIntervalTime Timeout(const Shared *shared)
    35 {
    36     PRIntervalTime timeout = shared->timeout;
    37     if (shared->random)
    38     {
    39         PRIntervalTime half = timeout >> 1;  /* one half of the interval */
    40         PRIntervalTime quarter = half >> 1;  /* one quarter of the interval */
    41         /* something in [0..timeout / 2) */
    42         PRUint32 random = (rand() % RANDOM_RANGE) * half / RANDOM_RANGE;
    43         timeout = (3 * quarter) + random;  /* [75..125)% */
    44     }
    45     return timeout;
    46 }  /* Timeout */
    48 static void Accept(void *arg)
    49 {
    50     PRStatus rv;
    51     char *buffer = NULL;
    52     PRNetAddr clientAddr;
    53     Shared *shared = (Shared*)arg;
    54     PRInt32 recv_length = 0, flags = 0;
    55     PRFileDesc *clientSock;
    56     PRIntn toread, byte, bytes, loop = 0;
    57     struct Descriptor { PRInt32 length; PRUint32 checksum; } descriptor;
    59     do
    60     {
    61         PRUint32 checksum = 0;
    62         if (NULL != shared->debug)
    63             PR_fprintf(shared->debug, "[%d]accepting ... ", loop++);
    64         clientSock = PR_Accept(
    65             shared->listenSock, &clientAddr, Timeout(shared));
    66         if (clientSock != NULL)
    67         {
    68             if (NULL != shared->debug)
    69                 PR_fprintf(shared->debug, "reading length ... ");
    70             bytes = PR_Recv(
    71                 clientSock, &descriptor, sizeof(descriptor),
    72                 flags, Timeout(shared));
    73             if (sizeof(descriptor) == bytes)
    74             {
    75                 /* and, before doing something stupid ... */
    76                 descriptor.length = PR_ntohl(descriptor.length);
    77                 descriptor.checksum = PR_ntohl(descriptor.checksum);
    78                 if (NULL != shared->debug)
    79                     PR_fprintf(shared->debug, "%d bytes ... ", descriptor.length);
    80                 toread = descriptor.length;
    81                 if (recv_length < descriptor.length)
    82                 {
    83                     if (NULL != buffer) PR_DELETE(buffer);
    84                     buffer = (char*)PR_MALLOC(descriptor.length);
    85                     recv_length = descriptor.length;
    86                 }
    87                 for (toread = descriptor.length; toread > 0; toread -= bytes)
    88                 {
    89                     bytes = PR_Recv(
    90                         clientSock, &buffer[descriptor.length - toread],
    91                         toread, flags, Timeout(shared));
    92                     if (-1 == bytes)
    93                     {
    94                         if (NULL != shared->debug)
    95                             PR_fprintf(shared->debug, "read data failed...");
    96                         bytes = 0;
    97                     }
    98                 }
    99             }
   100             else if (NULL != shared->debug)
   101             {
   102                 PR_fprintf(shared->debug, "read desciptor failed...");
   103                 descriptor.length = -1;
   104             }
   105             if (NULL != shared->debug)
   106                 PR_fprintf(shared->debug, "closing");
   107             rv = PR_Shutdown(clientSock, PR_SHUTDOWN_BOTH);
   108             if ((PR_FAILURE == rv) && (NULL != shared->debug))
   109             {
   110                 PR_fprintf(shared->debug, " failed");
   111                 shared->passed = PR_FALSE;
   112             }
   113             rv = PR_Close(clientSock);
   114             if (PR_FAILURE == rv) if (NULL != shared->debug)
   115             {
   116                 PR_fprintf(shared->debug, " failed");
   117                 shared->passed = PR_FALSE;
   118             }
   119             if (descriptor.length > 0)
   120             {
   121                 for (byte = 0; byte < descriptor.length; ++byte)
   122                 {
   123                     PRUint32 overflow = checksum & 0x80000000;
   124                     checksum = (checksum << 1);
   125                     if (0x00000000 != overflow) checksum += 1;
   126                     checksum += buffer[byte];
   127                 }
   128                 if ((descriptor.checksum != checksum) && (NULL != shared->debug))
   129                 {
   130                     PR_fprintf(shared->debug, " ... data mismatch");
   131                     shared->passed = PR_FALSE;
   132                 }
   133             }
   134             else if (0 == descriptor.length)
   135             {
   136                 PR_Lock(shared->ml);
   137                 shared->status = stopped;
   138                 PR_NotifyCondVar(shared->cv);
   139                 PR_Unlock(shared->ml);
   140             }
   141             if (NULL != shared->debug)
   142                 PR_fprintf(shared->debug, "\n");
   143         }
   144         else
   145         {
   146             if (PR_PENDING_INTERRUPT_ERROR != PR_GetError())
   147             {
   148                 if (NULL != shared->debug) PL_PrintError("Accept");
   149                 shared->passed = PR_FALSE;
   150             }
   151         }        
   152     } while (running == shared->status);
   153     if (NULL != buffer) PR_DELETE(buffer);
   154 }  /* Accept */
   156 PRIntn Tmoacc(PRIntn argc, char **argv)
   157 {
   158     PRStatus rv;
   159     PRIntn exitStatus;
   160     PRIntn index;
   161 	Shared *shared;
   162 	PLOptStatus os;
   163 	PRThread **thread;
   164     PRNetAddr listenAddr;
   165     PRSocketOptionData sockOpt;
   166     PRIntn timeout = DEFAULT_TIMEOUT;
   167     PRIntn threads = DEFAULT_THREADS;
   168     PRIntn backlog = DEFAULT_BACKLOG;
   169     PRThreadScope thread_scope = PR_LOCAL_THREAD;
   171 	PLOptState *opt = PL_CreateOptState(argc, argv, "dGb:t:T:R");
   173     shared = PR_NEWZAP(Shared);
   175     shared->debug = NULL;
   176     shared->passed = PR_TRUE;
   177     shared->random = PR_TRUE;
   178     shared->status = running;
   179     shared->ml = PR_NewLock();
   180     shared->cv = PR_NewCondVar(shared->ml);
   182 	while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
   183     {
   184         if (PL_OPT_BAD == os) continue;
   185         switch (opt->option)
   186         {
   187         case 'd':  /* debug mode */
   188             shared->debug = PR_GetSpecialFD(PR_StandardError);
   189             break;
   190         case 'G':  /* use global threads */
   191             thread_scope = PR_GLOBAL_THREAD;
   192             break;
   193         case 'b':  /* size of listen backlog */
   194             backlog = atoi(opt->value);
   195             break;
   196         case 't':  /* number of threads doing accept */
   197             threads = atoi(opt->value);
   198             break;
   199         case 'T':  /* timeout used for network operations */
   200             timeout = atoi(opt->value);
   201             break;
   202         case 'R':  /* randomize the timeout values */
   203             shared->random = PR_TRUE;
   204             break;
   205         default:
   206             break;
   207         }
   208     }
   209 	PL_DestroyOptState(opt);
   210     if (0 == threads) threads = DEFAULT_THREADS;
   211     if (0 == backlog) backlog = DEFAULT_BACKLOG;
   212     if (0 == timeout) timeout = DEFAULT_TIMEOUT;
   214     PR_STDIO_INIT();
   215     memset(&listenAddr, 0, sizeof(listenAddr));
   216     rv = PR_InitializeNetAddr(PR_IpAddrAny, BASE_PORT, &listenAddr);
   217     PR_ASSERT(PR_SUCCESS == rv);
   219     shared->timeout = PR_SecondsToInterval(timeout);
   221     /* First bind to the socket */
   222     shared->listenSock = PR_NewTCPSocket();
   223     if (shared->listenSock)
   224     {
   225         sockOpt.option = PR_SockOpt_Reuseaddr;
   226         sockOpt.value.reuse_addr = PR_TRUE;
   227         rv = PR_SetSocketOption(shared->listenSock, &sockOpt);
   228         PR_ASSERT(PR_SUCCESS == rv);
   229         rv = PR_Bind(shared->listenSock, &listenAddr);
   230         if (rv != PR_FAILURE)
   231         {
   232             rv = PR_Listen(shared->listenSock, threads + backlog);
   233             if (PR_SUCCESS == rv)
   234             {
   235                 thread = (PRThread**)PR_CALLOC(threads * sizeof(PRThread*));
   236                 for (index = 0; index < threads; ++index)
   237                 {
   238                     thread[index] = PR_CreateThread(
   239                         PR_USER_THREAD, Accept, shared,
   240                         PR_PRIORITY_NORMAL, thread_scope,
   241                         PR_JOINABLE_THREAD, 0);
   242                     PR_ASSERT(NULL != thread[index]);
   243                 }
   245                 PR_Lock(shared->ml);
   246                 while (shared->status == running)
   247                     PR_WaitCondVar(shared->cv, PR_INTERVAL_NO_TIMEOUT);
   248                 PR_Unlock(shared->ml);
   249                 for (index = 0; index < threads; ++index)
   250                 {
   251                     rv = PR_Interrupt(thread[index]);
   252                     PR_ASSERT(PR_SUCCESS== rv);
   253                     rv = PR_JoinThread(thread[index]);
   254                     PR_ASSERT(PR_SUCCESS== rv);
   255                 }
   256                 PR_DELETE(thread);
   257             }
   258             else
   259             {
   260                 if (shared->debug) PL_PrintError("Listen");
   261                 shared->passed = PR_FALSE;
   262             }
   263         }
   264         else
   265         {
   266             if (shared->debug) PL_PrintError("Bind");
   267             shared->passed = PR_FALSE;
   268         }
   270         PR_Close(shared->listenSock);
   271     }
   272     else
   273     {
   274         if (shared->debug) PL_PrintError("Create");
   275         shared->passed = PR_FALSE;
   276     }
   278     PR_DestroyCondVar(shared->cv);
   279     PR_DestroyLock(shared->ml);
   281     PR_fprintf(
   282         PR_GetSpecialFD(PR_StandardError), "%s\n",
   283         ((shared->passed) ? "PASSED" : "FAILED"));
   285     exitStatus = (shared->passed) ? 0 : 1;
   286     PR_DELETE(shared);
   287     return exitStatus;
   288 }
   290 int main(int argc, char **argv)
   291 {
   292     return (PR_VersionCheck(PR_VERSION)) ?
   293         PR_Initialize(Tmoacc, argc, argv, 4) : -1;
   294 }  /* main */
   296 /* tmoacc */

mercurial