1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/nsprpub/pr/tests/tmoacc.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,296 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "nspr.h" 1.10 + 1.11 +#include <stdlib.h> 1.12 +#include <string.h> 1.13 + 1.14 +#include "plerror.h" 1.15 +#include "plgetopt.h" 1.16 + 1.17 +#define BASE_PORT 9867 1.18 +#define DEFAULT_THREADS 1 1.19 +#define DEFAULT_BACKLOG 10 1.20 +#define DEFAULT_TIMEOUT 10 1.21 +#define RANDOM_RANGE 100 /* should be significantly smaller than RAND_MAX */ 1.22 + 1.23 +typedef enum {running, stopped} Status; 1.24 + 1.25 +typedef struct Shared 1.26 +{ 1.27 + PRLock *ml; 1.28 + PRCondVar *cv; 1.29 + PRBool passed; 1.30 + PRBool random; 1.31 + PRFileDesc *debug; 1.32 + PRIntervalTime timeout; 1.33 + PRFileDesc *listenSock; 1.34 + Status status; 1.35 +} Shared; 1.36 + 1.37 +static PRIntervalTime Timeout(const Shared *shared) 1.38 +{ 1.39 + PRIntervalTime timeout = shared->timeout; 1.40 + if (shared->random) 1.41 + { 1.42 + PRIntervalTime half = timeout >> 1; /* one half of the interval */ 1.43 + PRIntervalTime quarter = half >> 1; /* one quarter of the interval */ 1.44 + /* something in [0..timeout / 2) */ 1.45 + PRUint32 random = (rand() % RANDOM_RANGE) * half / RANDOM_RANGE; 1.46 + timeout = (3 * quarter) + random; /* [75..125)% */ 1.47 + } 1.48 + return timeout; 1.49 +} /* Timeout */ 1.50 + 1.51 +static void Accept(void *arg) 1.52 +{ 1.53 + PRStatus rv; 1.54 + char *buffer = NULL; 1.55 + PRNetAddr clientAddr; 1.56 + Shared *shared = (Shared*)arg; 1.57 + PRInt32 recv_length = 0, flags = 0; 1.58 + PRFileDesc *clientSock; 1.59 + PRIntn toread, byte, bytes, loop = 0; 1.60 + struct Descriptor { PRInt32 length; PRUint32 checksum; } descriptor; 1.61 + 1.62 + do 1.63 + { 1.64 + PRUint32 checksum = 0; 1.65 + if (NULL != shared->debug) 1.66 + PR_fprintf(shared->debug, "[%d]accepting ... ", loop++); 1.67 + clientSock = PR_Accept( 1.68 + shared->listenSock, &clientAddr, Timeout(shared)); 1.69 + if (clientSock != NULL) 1.70 + { 1.71 + if (NULL != shared->debug) 1.72 + PR_fprintf(shared->debug, "reading length ... "); 1.73 + bytes = PR_Recv( 1.74 + clientSock, &descriptor, sizeof(descriptor), 1.75 + flags, Timeout(shared)); 1.76 + if (sizeof(descriptor) == bytes) 1.77 + { 1.78 + /* and, before doing something stupid ... */ 1.79 + descriptor.length = PR_ntohl(descriptor.length); 1.80 + descriptor.checksum = PR_ntohl(descriptor.checksum); 1.81 + if (NULL != shared->debug) 1.82 + PR_fprintf(shared->debug, "%d bytes ... ", descriptor.length); 1.83 + toread = descriptor.length; 1.84 + if (recv_length < descriptor.length) 1.85 + { 1.86 + if (NULL != buffer) PR_DELETE(buffer); 1.87 + buffer = (char*)PR_MALLOC(descriptor.length); 1.88 + recv_length = descriptor.length; 1.89 + } 1.90 + for (toread = descriptor.length; toread > 0; toread -= bytes) 1.91 + { 1.92 + bytes = PR_Recv( 1.93 + clientSock, &buffer[descriptor.length - toread], 1.94 + toread, flags, Timeout(shared)); 1.95 + if (-1 == bytes) 1.96 + { 1.97 + if (NULL != shared->debug) 1.98 + PR_fprintf(shared->debug, "read data failed..."); 1.99 + bytes = 0; 1.100 + } 1.101 + } 1.102 + } 1.103 + else if (NULL != shared->debug) 1.104 + { 1.105 + PR_fprintf(shared->debug, "read desciptor failed..."); 1.106 + descriptor.length = -1; 1.107 + } 1.108 + if (NULL != shared->debug) 1.109 + PR_fprintf(shared->debug, "closing"); 1.110 + rv = PR_Shutdown(clientSock, PR_SHUTDOWN_BOTH); 1.111 + if ((PR_FAILURE == rv) && (NULL != shared->debug)) 1.112 + { 1.113 + PR_fprintf(shared->debug, " failed"); 1.114 + shared->passed = PR_FALSE; 1.115 + } 1.116 + rv = PR_Close(clientSock); 1.117 + if (PR_FAILURE == rv) if (NULL != shared->debug) 1.118 + { 1.119 + PR_fprintf(shared->debug, " failed"); 1.120 + shared->passed = PR_FALSE; 1.121 + } 1.122 + if (descriptor.length > 0) 1.123 + { 1.124 + for (byte = 0; byte < descriptor.length; ++byte) 1.125 + { 1.126 + PRUint32 overflow = checksum & 0x80000000; 1.127 + checksum = (checksum << 1); 1.128 + if (0x00000000 != overflow) checksum += 1; 1.129 + checksum += buffer[byte]; 1.130 + } 1.131 + if ((descriptor.checksum != checksum) && (NULL != shared->debug)) 1.132 + { 1.133 + PR_fprintf(shared->debug, " ... data mismatch"); 1.134 + shared->passed = PR_FALSE; 1.135 + } 1.136 + } 1.137 + else if (0 == descriptor.length) 1.138 + { 1.139 + PR_Lock(shared->ml); 1.140 + shared->status = stopped; 1.141 + PR_NotifyCondVar(shared->cv); 1.142 + PR_Unlock(shared->ml); 1.143 + } 1.144 + if (NULL != shared->debug) 1.145 + PR_fprintf(shared->debug, "\n"); 1.146 + } 1.147 + else 1.148 + { 1.149 + if (PR_PENDING_INTERRUPT_ERROR != PR_GetError()) 1.150 + { 1.151 + if (NULL != shared->debug) PL_PrintError("Accept"); 1.152 + shared->passed = PR_FALSE; 1.153 + } 1.154 + } 1.155 + } while (running == shared->status); 1.156 + if (NULL != buffer) PR_DELETE(buffer); 1.157 +} /* Accept */ 1.158 + 1.159 +PRIntn Tmoacc(PRIntn argc, char **argv) 1.160 +{ 1.161 + PRStatus rv; 1.162 + PRIntn exitStatus; 1.163 + PRIntn index; 1.164 + Shared *shared; 1.165 + PLOptStatus os; 1.166 + PRThread **thread; 1.167 + PRNetAddr listenAddr; 1.168 + PRSocketOptionData sockOpt; 1.169 + PRIntn timeout = DEFAULT_TIMEOUT; 1.170 + PRIntn threads = DEFAULT_THREADS; 1.171 + PRIntn backlog = DEFAULT_BACKLOG; 1.172 + PRThreadScope thread_scope = PR_LOCAL_THREAD; 1.173 + 1.174 + PLOptState *opt = PL_CreateOptState(argc, argv, "dGb:t:T:R"); 1.175 + 1.176 + shared = PR_NEWZAP(Shared); 1.177 + 1.178 + shared->debug = NULL; 1.179 + shared->passed = PR_TRUE; 1.180 + shared->random = PR_TRUE; 1.181 + shared->status = running; 1.182 + shared->ml = PR_NewLock(); 1.183 + shared->cv = PR_NewCondVar(shared->ml); 1.184 + 1.185 + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) 1.186 + { 1.187 + if (PL_OPT_BAD == os) continue; 1.188 + switch (opt->option) 1.189 + { 1.190 + case 'd': /* debug mode */ 1.191 + shared->debug = PR_GetSpecialFD(PR_StandardError); 1.192 + break; 1.193 + case 'G': /* use global threads */ 1.194 + thread_scope = PR_GLOBAL_THREAD; 1.195 + break; 1.196 + case 'b': /* size of listen backlog */ 1.197 + backlog = atoi(opt->value); 1.198 + break; 1.199 + case 't': /* number of threads doing accept */ 1.200 + threads = atoi(opt->value); 1.201 + break; 1.202 + case 'T': /* timeout used for network operations */ 1.203 + timeout = atoi(opt->value); 1.204 + break; 1.205 + case 'R': /* randomize the timeout values */ 1.206 + shared->random = PR_TRUE; 1.207 + break; 1.208 + default: 1.209 + break; 1.210 + } 1.211 + } 1.212 + PL_DestroyOptState(opt); 1.213 + if (0 == threads) threads = DEFAULT_THREADS; 1.214 + if (0 == backlog) backlog = DEFAULT_BACKLOG; 1.215 + if (0 == timeout) timeout = DEFAULT_TIMEOUT; 1.216 + 1.217 + PR_STDIO_INIT(); 1.218 + memset(&listenAddr, 0, sizeof(listenAddr)); 1.219 + rv = PR_InitializeNetAddr(PR_IpAddrAny, BASE_PORT, &listenAddr); 1.220 + PR_ASSERT(PR_SUCCESS == rv); 1.221 + 1.222 + shared->timeout = PR_SecondsToInterval(timeout); 1.223 + 1.224 + /* First bind to the socket */ 1.225 + shared->listenSock = PR_NewTCPSocket(); 1.226 + if (shared->listenSock) 1.227 + { 1.228 + sockOpt.option = PR_SockOpt_Reuseaddr; 1.229 + sockOpt.value.reuse_addr = PR_TRUE; 1.230 + rv = PR_SetSocketOption(shared->listenSock, &sockOpt); 1.231 + PR_ASSERT(PR_SUCCESS == rv); 1.232 + rv = PR_Bind(shared->listenSock, &listenAddr); 1.233 + if (rv != PR_FAILURE) 1.234 + { 1.235 + rv = PR_Listen(shared->listenSock, threads + backlog); 1.236 + if (PR_SUCCESS == rv) 1.237 + { 1.238 + thread = (PRThread**)PR_CALLOC(threads * sizeof(PRThread*)); 1.239 + for (index = 0; index < threads; ++index) 1.240 + { 1.241 + thread[index] = PR_CreateThread( 1.242 + PR_USER_THREAD, Accept, shared, 1.243 + PR_PRIORITY_NORMAL, thread_scope, 1.244 + PR_JOINABLE_THREAD, 0); 1.245 + PR_ASSERT(NULL != thread[index]); 1.246 + } 1.247 + 1.248 + PR_Lock(shared->ml); 1.249 + while (shared->status == running) 1.250 + PR_WaitCondVar(shared->cv, PR_INTERVAL_NO_TIMEOUT); 1.251 + PR_Unlock(shared->ml); 1.252 + for (index = 0; index < threads; ++index) 1.253 + { 1.254 + rv = PR_Interrupt(thread[index]); 1.255 + PR_ASSERT(PR_SUCCESS== rv); 1.256 + rv = PR_JoinThread(thread[index]); 1.257 + PR_ASSERT(PR_SUCCESS== rv); 1.258 + } 1.259 + PR_DELETE(thread); 1.260 + } 1.261 + else 1.262 + { 1.263 + if (shared->debug) PL_PrintError("Listen"); 1.264 + shared->passed = PR_FALSE; 1.265 + } 1.266 + } 1.267 + else 1.268 + { 1.269 + if (shared->debug) PL_PrintError("Bind"); 1.270 + shared->passed = PR_FALSE; 1.271 + } 1.272 + 1.273 + PR_Close(shared->listenSock); 1.274 + } 1.275 + else 1.276 + { 1.277 + if (shared->debug) PL_PrintError("Create"); 1.278 + shared->passed = PR_FALSE; 1.279 + } 1.280 + 1.281 + PR_DestroyCondVar(shared->cv); 1.282 + PR_DestroyLock(shared->ml); 1.283 + 1.284 + PR_fprintf( 1.285 + PR_GetSpecialFD(PR_StandardError), "%s\n", 1.286 + ((shared->passed) ? "PASSED" : "FAILED")); 1.287 + 1.288 + exitStatus = (shared->passed) ? 0 : 1; 1.289 + PR_DELETE(shared); 1.290 + return exitStatus; 1.291 +} 1.292 + 1.293 +int main(int argc, char **argv) 1.294 +{ 1.295 + return (PR_VersionCheck(PR_VERSION)) ? 1.296 + PR_Initialize(Tmoacc, argc, argv, 4) : -1; 1.297 +} /* main */ 1.298 + 1.299 +/* tmoacc */