nsprpub/pr/tests/tmoacc.c

Wed, 31 Dec 2014 06:55:46 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:46 +0100
changeset 1
ca08bd8f51b2
permissions
-rw-r--r--

Added tag TORBROWSER_REPLICA for changeset 6474c204b198

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

mercurial