1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/nsprpub/pr/tests/tmocon.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,378 @@ 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 +/*********************************************************************** 1.10 +** 1.11 +** Name: tmocon.c 1.12 +** 1.13 +** Description: test client socket connection. 1.14 +** 1.15 +** Modification History: 1.16 +** 19-May-97 AGarcia- Converted the test to accomodate the debug_mode flag. 1.17 +** The debug mode will print all of the printfs associated with this test. 1.18 +** The regress mode will be the default mode. Since the regress tool limits 1.19 +** the output to a one line status:PASS or FAIL,all of the printf statements 1.20 +** have been handled with an if (debug_mode) statement. 1.21 +***********************************************************************/ 1.22 + 1.23 +/*********************************************************************** 1.24 +** Includes 1.25 +***********************************************************************/ 1.26 +/* Used to get the command line option */ 1.27 +#include "plgetopt.h" 1.28 + 1.29 +#include "nspr.h" 1.30 +#include "pprio.h" 1.31 + 1.32 +#include "plerror.h" 1.33 +#include "plgetopt.h" 1.34 + 1.35 +#include <stdio.h> 1.36 +#include <stdlib.h> 1.37 +#include <string.h> 1.38 + 1.39 +/* for getcwd */ 1.40 +#if defined(XP_UNIX) || defined (XP_OS2) || defined(XP_BEOS) 1.41 +#include <unistd.h> 1.42 +#elif defined(XP_PC) 1.43 +#include <direct.h> 1.44 +#endif 1.45 + 1.46 +#ifdef WINCE 1.47 +#include <windows.h> 1.48 +char *getcwd(char *buf, size_t size) 1.49 +{ 1.50 + wchar_t wpath[MAX_PATH]; 1.51 + _wgetcwd(wpath, MAX_PATH); 1.52 + WideCharToMultiByte(CP_ACP, 0, wpath, -1, buf, size, 0, 0); 1.53 +} 1.54 +#endif 1.55 + 1.56 +#define BASE_PORT 9867 1.57 + 1.58 +#define DEFAULT_DALLY 1 1.59 +#define DEFAULT_THREADS 1 1.60 +#define DEFAULT_TIMEOUT 10 1.61 +#define DEFAULT_MESSAGES 100 1.62 +#define DEFAULT_MESSAGESIZE 100 1.63 + 1.64 +static PRFileDesc *debug_out = NULL; 1.65 + 1.66 +typedef struct Shared 1.67 +{ 1.68 + PRBool random; 1.69 + PRBool failed; 1.70 + PRBool intermittant; 1.71 + PRIntn debug; 1.72 + PRInt32 messages; 1.73 + PRIntervalTime dally; 1.74 + PRIntervalTime timeout; 1.75 + PRInt32 message_length; 1.76 + PRNetAddr serverAddress; 1.77 +} Shared; 1.78 + 1.79 +static PRIntervalTime Timeout(const Shared *shared) 1.80 +{ 1.81 + PRIntervalTime timeout = shared->timeout; 1.82 + if (shared->random) 1.83 + { 1.84 + PRIntervalTime quarter = timeout >> 2; /* one quarter of the interval */ 1.85 + PRUint32 random = rand() % quarter; /* something in[0..timeout / 4) */ 1.86 + timeout = (((3 * quarter) + random) >> 2) + quarter; /* [75..125)% */ 1.87 + } 1.88 + return timeout; 1.89 +} /* Timeout */ 1.90 + 1.91 +static void CauseTimeout(const Shared *shared) 1.92 +{ 1.93 + if (shared->intermittant) PR_Sleep(Timeout(shared)); 1.94 +} /* CauseTimeout */ 1.95 + 1.96 +static PRStatus MakeReceiver(Shared *shared) 1.97 +{ 1.98 + PRStatus rv = PR_FAILURE; 1.99 + if (PR_IsNetAddrType(&shared->serverAddress, PR_IpAddrLoopback)) 1.100 + { 1.101 + char *argv[3]; 1.102 + char path[1024 + sizeof("/tmoacc")]; 1.103 + 1.104 + getcwd(path, sizeof(path)); 1.105 + 1.106 + (void)strcat(path, "/tmoacc"); 1.107 +#ifdef XP_PC 1.108 + (void)strcat(path, ".exe"); 1.109 +#endif 1.110 + argv[0] = path; 1.111 + if (shared->debug > 0) 1.112 + { 1.113 + argv[1] = "-d"; 1.114 + argv[2] = NULL; 1.115 + } 1.116 + else argv[1] = NULL; 1.117 + if (shared->debug > 1) 1.118 + PR_fprintf(debug_out, " creating accept process %s ...", path); 1.119 + fflush(stdout); 1.120 + rv = PR_CreateProcessDetached(path, argv, NULL, NULL); 1.121 + if (PR_SUCCESS == rv) 1.122 + { 1.123 + if (shared->debug > 1) 1.124 + PR_fprintf(debug_out, " wait 5 seconds"); 1.125 + if (shared->debug > 1) 1.126 + PR_fprintf(debug_out, " before connecting to accept process ..."); 1.127 + fflush(stdout); 1.128 + PR_Sleep(PR_SecondsToInterval(5)); 1.129 + return rv; 1.130 + } 1.131 + shared->failed = PR_TRUE; 1.132 + if (shared->debug > 0) 1.133 + PL_FPrintError(debug_out, "PR_CreateProcessDetached failed"); 1.134 + } 1.135 + return rv; 1.136 +} /* MakeReceiver */ 1.137 + 1.138 +static void Connect(void *arg) 1.139 +{ 1.140 + PRStatus rv; 1.141 + char *buffer = NULL; 1.142 + PRFileDesc *clientSock; 1.143 + Shared *shared = (Shared*)arg; 1.144 + PRInt32 loop, bytes, flags = 0; 1.145 + struct Descriptor { PRInt32 length; PRUint32 checksum; } descriptor; 1.146 + debug_out = (0 == shared->debug) ? NULL : PR_GetSpecialFD(PR_StandardError); 1.147 + 1.148 + buffer = (char*)PR_MALLOC(shared->message_length); 1.149 + 1.150 + for (bytes = 0; bytes < shared->message_length; ++bytes) 1.151 + buffer[bytes] = (char)bytes; 1.152 + 1.153 + descriptor.checksum = 0; 1.154 + for (bytes = 0; bytes < shared->message_length; ++bytes) 1.155 + { 1.156 + PRUint32 overflow = descriptor.checksum & 0x80000000; 1.157 + descriptor.checksum = (descriptor.checksum << 1); 1.158 + if (0x00000000 != overflow) descriptor.checksum += 1; 1.159 + descriptor.checksum += buffer[bytes]; 1.160 + } 1.161 + descriptor.checksum = PR_htonl(descriptor.checksum); 1.162 + 1.163 + for (loop = 0; loop < shared->messages; ++loop) 1.164 + { 1.165 + if (shared->debug > 1) 1.166 + PR_fprintf(debug_out, "[%d]socket ... ", loop); 1.167 + clientSock = PR_NewTCPSocket(); 1.168 + if (clientSock) 1.169 + { 1.170 + /* 1.171 + * We need to slow down the rate of generating connect requests, 1.172 + * otherwise the listen backlog queue on the accept side may 1.173 + * become full and we will get connection refused or timeout 1.174 + * error. 1.175 + */ 1.176 + 1.177 + PR_Sleep(shared->dally); 1.178 + if (shared->debug > 1) 1.179 + { 1.180 + char buf[128]; 1.181 + PR_NetAddrToString(&shared->serverAddress, buf, sizeof(buf)); 1.182 + PR_fprintf(debug_out, "connecting to %s ... ", buf); 1.183 + } 1.184 + rv = PR_Connect( 1.185 + clientSock, &shared->serverAddress, Timeout(shared)); 1.186 + if (PR_SUCCESS == rv) 1.187 + { 1.188 + PRInt32 descriptor_length = (loop < (shared->messages - 1)) ? 1.189 + shared->message_length : 0; 1.190 + descriptor.length = PR_htonl(descriptor_length); 1.191 + if (shared->debug > 1) 1.192 + PR_fprintf( 1.193 + debug_out, "sending %d bytes ... ", descriptor_length); 1.194 + CauseTimeout(shared); /* might cause server to timeout */ 1.195 + bytes = PR_Send( 1.196 + clientSock, &descriptor, sizeof(descriptor), 1.197 + flags, Timeout(shared)); 1.198 + if (bytes != sizeof(descriptor)) 1.199 + { 1.200 + shared->failed = PR_TRUE; 1.201 + if (shared->debug > 0) 1.202 + PL_FPrintError(debug_out, "PR_Send failed"); 1.203 + } 1.204 + if (0 != descriptor_length) 1.205 + { 1.206 + CauseTimeout(shared); 1.207 + bytes = PR_Send( 1.208 + clientSock, buffer, descriptor_length, 1.209 + flags, Timeout(shared)); 1.210 + if (bytes != descriptor_length) 1.211 + { 1.212 + shared->failed = PR_TRUE; 1.213 + if (shared->debug > 0) 1.214 + PL_FPrintError(debug_out, "PR_Send failed"); 1.215 + } 1.216 + } 1.217 + if (shared->debug > 1) PR_fprintf(debug_out, "closing ... "); 1.218 + rv = PR_Shutdown(clientSock, PR_SHUTDOWN_BOTH); 1.219 + rv = PR_Close(clientSock); 1.220 + if (shared->debug > 1) 1.221 + { 1.222 + if (PR_SUCCESS == rv) PR_fprintf(debug_out, "\n"); 1.223 + else PL_FPrintError(debug_out, "shutdown failed"); 1.224 + } 1.225 + } 1.226 + else 1.227 + { 1.228 + if (shared->debug > 1) PL_FPrintError(debug_out, "connect failed"); 1.229 + PR_Close(clientSock); 1.230 + if ((loop == 0) && (PR_GetError() == PR_CONNECT_REFUSED_ERROR)) 1.231 + { 1.232 + if (MakeReceiver(shared) == PR_FAILURE) break; 1.233 + } 1.234 + else 1.235 + { 1.236 + if (shared->debug > 1) PR_fprintf(debug_out, " exiting\n"); 1.237 + break; 1.238 + } 1.239 + } 1.240 + } 1.241 + else 1.242 + { 1.243 + shared->failed = PR_TRUE; 1.244 + if (shared->debug > 0) PL_FPrintError(debug_out, "create socket"); 1.245 + break; 1.246 + } 1.247 + } 1.248 + 1.249 + PR_DELETE(buffer); 1.250 +} /* Connect */ 1.251 + 1.252 +int Tmocon(int argc, char **argv) 1.253 +{ 1.254 + /* 1.255 + * USAGE 1.256 + * -d turn on debugging output (default = off) 1.257 + * -v turn on verbose output (default = off) 1.258 + * -h <n> dns name of host serving the connection (default = self) 1.259 + * -i dally intermittantly to cause timeouts (default = off) 1.260 + * -m <n> number of messages to send (default = 100) 1.261 + * -s <n> size of each message (default = 100) 1.262 + * -t <n> number of threads sending (default = 1) 1.263 + * -G use global threads (default = local) 1.264 + * -T <n> timeout on I/O operations (seconds) (default = 10) 1.265 + * -D <n> dally between connect requests (seconds)(default = 0) 1.266 + * -R randomize the dally types around 'T' (default = no) 1.267 + */ 1.268 + 1.269 + PRStatus rv; 1.270 + int exitStatus; 1.271 + PLOptStatus os; 1.272 + Shared *shared = NULL; 1.273 + PRThread **thread = NULL; 1.274 + PRIntn index, threads = DEFAULT_THREADS; 1.275 + PRThreadScope thread_scope = PR_LOCAL_THREAD; 1.276 + PRInt32 dally = DEFAULT_DALLY, timeout = DEFAULT_TIMEOUT; 1.277 + PLOptState *opt = PL_CreateOptState(argc, argv, "divGRh:m:s:t:T:D:"); 1.278 + 1.279 + shared = PR_NEWZAP(Shared); 1.280 + 1.281 + shared->debug = 0; 1.282 + shared->failed = PR_FALSE; 1.283 + shared->random = PR_FALSE; 1.284 + shared->messages = DEFAULT_MESSAGES; 1.285 + shared->message_length = DEFAULT_MESSAGESIZE; 1.286 + 1.287 + PR_STDIO_INIT(); 1.288 + memset(&shared->serverAddress, 0, sizeof(shared->serverAddress)); 1.289 + rv = PR_InitializeNetAddr(PR_IpAddrLoopback, BASE_PORT, &shared->serverAddress); 1.290 + PR_ASSERT(PR_SUCCESS == rv); 1.291 + 1.292 + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) 1.293 + { 1.294 + if (PL_OPT_BAD == os) continue; 1.295 + switch (opt->option) 1.296 + { 1.297 + case 'd': 1.298 + if (0 == shared->debug) shared->debug = 1; 1.299 + break; 1.300 + case 'v': 1.301 + if (0 == shared->debug) shared->debug = 2; 1.302 + break; 1.303 + case 'i': 1.304 + shared->intermittant = PR_TRUE; 1.305 + break; 1.306 + case 'R': 1.307 + shared->random = PR_TRUE; 1.308 + break; 1.309 + case 'G': 1.310 + thread_scope = PR_GLOBAL_THREAD; 1.311 + break; 1.312 + case 'h': /* the value for backlock */ 1.313 + { 1.314 + PRIntn es = 0; 1.315 + PRHostEnt host; 1.316 + char buffer[1024]; 1.317 + (void)PR_GetHostByName( 1.318 + opt->value, buffer, sizeof(buffer), &host); 1.319 + es = PR_EnumerateHostEnt( 1.320 + es, &host, BASE_PORT, &shared->serverAddress); 1.321 + PR_ASSERT(es > 0); 1.322 + } 1.323 + break; 1.324 + case 'm': /* number of messages to send */ 1.325 + shared->messages = atoi(opt->value); 1.326 + break; 1.327 + case 't': /* number of threads sending */ 1.328 + threads = atoi(opt->value); 1.329 + break; 1.330 + case 'D': /* dally time between transmissions */ 1.331 + dally = atoi(opt->value); 1.332 + break; 1.333 + case 'T': /* timeout on I/O operations */ 1.334 + timeout = atoi(opt->value); 1.335 + break; 1.336 + case 's': /* total size of each message */ 1.337 + shared->message_length = atoi(opt->value); 1.338 + break; 1.339 + default: 1.340 + break; 1.341 + } 1.342 + } 1.343 + PL_DestroyOptState(opt); 1.344 + 1.345 + if (0 == timeout) timeout = DEFAULT_TIMEOUT; 1.346 + if (0 == threads) threads = DEFAULT_THREADS; 1.347 + if (0 == shared->messages) shared->messages = DEFAULT_MESSAGES; 1.348 + if (0 == shared->message_length) shared->message_length = DEFAULT_MESSAGESIZE; 1.349 + 1.350 + shared->dally = PR_SecondsToInterval(dally); 1.351 + shared->timeout = PR_SecondsToInterval(timeout); 1.352 + 1.353 + thread = (PRThread**)PR_CALLOC(threads * sizeof(PRThread*)); 1.354 + 1.355 + for (index = 0; index < threads; ++index) 1.356 + thread[index] = PR_CreateThread( 1.357 + PR_USER_THREAD, Connect, shared, 1.358 + PR_PRIORITY_NORMAL, thread_scope, 1.359 + PR_JOINABLE_THREAD, 0); 1.360 + for (index = 0; index < threads; ++index) 1.361 + rv = PR_JoinThread(thread[index]); 1.362 + 1.363 + PR_DELETE(thread); 1.364 + 1.365 + PR_fprintf( 1.366 + PR_GetSpecialFD(PR_StandardError), "%s\n", 1.367 + ((shared->failed) ? "FAILED" : "PASSED")); 1.368 + exitStatus = (shared->failed) ? 1 : 0; 1.369 + PR_DELETE(shared); 1.370 + return exitStatus; 1.371 +} 1.372 + 1.373 +int main(int argc, char **argv) 1.374 +{ 1.375 + return (PR_VersionCheck(PR_VERSION)) ? 1.376 + PR_Initialize(Tmocon, argc, argv, 4) : -1; 1.377 +} /* main */ 1.378 + 1.379 +/* tmocon.c */ 1.380 + 1.381 +