tmocon.c (11765B)
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/. */ 5 6 /*********************************************************************** 7 ** 8 ** Name: tmocon.c 9 ** 10 ** Description: test client socket connection. 11 ** 12 ** Modification History: 13 ** 19-May-97 AGarcia- Converted the test to accomodate the debug_mode flag. 14 ** The debug mode will print all of the printfs associated with this 15 *test. 16 ** The regress mode will be the default mode. Since the regress tool 17 *limits 18 ** the output to a one line status:PASS or FAIL,all of the printf 19 *statements 20 ** have been handled with an if (debug_mode) statement. 21 ***********************************************************************/ 22 23 /*********************************************************************** 24 ** Includes 25 ***********************************************************************/ 26 /* Used to get the command line option */ 27 #include "plgetopt.h" 28 29 #include "nspr.h" 30 #include "pprio.h" 31 32 #include "plerror.h" 33 #include "plgetopt.h" 34 35 #include <stdio.h> 36 #include <stdlib.h> 37 #include <string.h> 38 39 /* for getcwd */ 40 #if defined(XP_UNIX) 41 # include <unistd.h> 42 #elif defined(XP_PC) 43 # include <direct.h> 44 #endif 45 46 #ifdef WINCE 47 # include <windows.h> 48 char* getcwd(char* buf, size_t size) { 49 wchar_t wpath[MAX_PATH]; 50 _wgetcwd(wpath, MAX_PATH); 51 WideCharToMultiByte(CP_ACP, 0, wpath, -1, buf, size, 0, 0); 52 } 53 #endif 54 55 #ifdef DEBUG 56 # define PORT_INC_DO +100 57 #else 58 # define PORT_INC_DO 59 #endif 60 #ifdef IS_64 61 # define PORT_INC_3264 +200 62 #else 63 # define PORT_INC_3264 64 #endif 65 66 #define BASE_PORT 9867 PORT_INC_DO PORT_INC_3264 67 68 #define DEFAULT_DALLY 1 69 #define DEFAULT_THREADS 1 70 #define DEFAULT_TIMEOUT 10 71 #define DEFAULT_MESSAGES 100 72 #define DEFAULT_MESSAGESIZE 100 73 74 static PRFileDesc* debug_out = NULL; 75 76 typedef struct Shared { 77 PRBool random; 78 PRBool failed; 79 PRBool intermittant; 80 PRIntn debug; 81 PRInt32 messages; 82 PRIntervalTime dally; 83 PRIntervalTime timeout; 84 PRInt32 message_length; 85 PRNetAddr serverAddress; 86 } Shared; 87 88 static PRIntervalTime Timeout(const Shared* shared) { 89 PRIntervalTime timeout = shared->timeout; 90 if (shared->random) { 91 PRIntervalTime quarter = timeout >> 2; /* one quarter of the interval */ 92 PRUint32 random = rand() % quarter; /* something in[0..timeout / 4) */ 93 timeout = (((3 * quarter) + random) >> 2) + quarter; /* [75..125)% */ 94 } 95 return timeout; 96 } /* Timeout */ 97 98 static void CauseTimeout(const Shared* shared) { 99 if (shared->intermittant) { 100 PR_Sleep(Timeout(shared)); 101 } 102 } /* CauseTimeout */ 103 104 static PRStatus MakeReceiver(Shared* shared) { 105 PRStatus rv = PR_FAILURE; 106 if (PR_IsNetAddrType(&shared->serverAddress, PR_IpAddrLoopback)) { 107 char* argv[3]; 108 char path[1024 + sizeof("/tmoacc")]; 109 110 getcwd(path, sizeof(path)); 111 112 (void)strcat(path, "/tmoacc"); 113 #ifdef XP_PC 114 (void)strcat(path, ".exe"); 115 #endif 116 argv[0] = path; 117 if (shared->debug > 0) { 118 argv[1] = "-d"; 119 argv[2] = NULL; 120 } else { 121 argv[1] = NULL; 122 } 123 if (shared->debug > 1) { 124 PR_fprintf(debug_out, " creating accept process %s ...", path); 125 } 126 fflush(stdout); 127 rv = PR_CreateProcessDetached(path, argv, NULL, NULL); 128 if (PR_SUCCESS == rv) { 129 if (shared->debug > 1) { 130 PR_fprintf(debug_out, " wait 5 seconds"); 131 } 132 if (shared->debug > 1) { 133 PR_fprintf(debug_out, " before connecting to accept process ..."); 134 } 135 fflush(stdout); 136 PR_Sleep(PR_SecondsToInterval(5)); 137 return rv; 138 } 139 shared->failed = PR_TRUE; 140 if (shared->debug > 0) { 141 PL_FPrintError(debug_out, "PR_CreateProcessDetached failed"); 142 } 143 } 144 return rv; 145 } /* MakeReceiver */ 146 147 static void Connect(void* arg) { 148 PRStatus rv; 149 char* buffer = NULL; 150 PRFileDesc* clientSock; 151 Shared* shared = (Shared*)arg; 152 PRInt32 loop, bytes, flags = 0; 153 struct Descriptor { 154 PRInt32 length; 155 PRUint32 checksum; 156 } descriptor; 157 debug_out = (0 == shared->debug) ? NULL : PR_GetSpecialFD(PR_StandardError); 158 159 buffer = (char*)PR_MALLOC(shared->message_length); 160 161 for (bytes = 0; bytes < shared->message_length; ++bytes) { 162 buffer[bytes] = (char)bytes; 163 } 164 165 descriptor.checksum = 0; 166 for (bytes = 0; bytes < shared->message_length; ++bytes) { 167 PRUint32 overflow = descriptor.checksum & 0x80000000; 168 descriptor.checksum = (descriptor.checksum << 1); 169 if (0x00000000 != overflow) { 170 descriptor.checksum += 1; 171 } 172 descriptor.checksum += buffer[bytes]; 173 } 174 descriptor.checksum = PR_htonl(descriptor.checksum); 175 176 for (loop = 0; loop < shared->messages; ++loop) { 177 if (shared->debug > 1) { 178 PR_fprintf(debug_out, "[%d]socket ... ", loop); 179 } 180 clientSock = PR_NewTCPSocket(); 181 if (clientSock) { 182 /* 183 * We need to slow down the rate of generating connect requests, 184 * otherwise the listen backlog queue on the accept side may 185 * become full and we will get connection refused or timeout 186 * error. 187 */ 188 189 PR_Sleep(shared->dally); 190 if (shared->debug > 1) { 191 char buf[128]; 192 PR_NetAddrToString(&shared->serverAddress, buf, sizeof(buf)); 193 PR_fprintf(debug_out, "connecting to %s ... ", buf); 194 } 195 rv = PR_Connect(clientSock, &shared->serverAddress, Timeout(shared)); 196 if (PR_SUCCESS == rv) { 197 PRInt32 descriptor_length = 198 (loop < (shared->messages - 1)) ? shared->message_length : 0; 199 descriptor.length = PR_htonl(descriptor_length); 200 if (shared->debug > 1) 201 PR_fprintf(debug_out, "sending %d bytes ... ", descriptor_length); 202 CauseTimeout(shared); /* might cause server to timeout */ 203 bytes = PR_Send(clientSock, &descriptor, sizeof(descriptor), flags, 204 Timeout(shared)); 205 if (bytes != sizeof(descriptor)) { 206 shared->failed = PR_TRUE; 207 if (shared->debug > 0) { 208 PL_FPrintError(debug_out, "PR_Send failed"); 209 } 210 } 211 if (0 != descriptor_length) { 212 CauseTimeout(shared); 213 bytes = PR_Send(clientSock, buffer, descriptor_length, flags, 214 Timeout(shared)); 215 if (bytes != descriptor_length) { 216 shared->failed = PR_TRUE; 217 if (shared->debug > 0) { 218 PL_FPrintError(debug_out, "PR_Send failed"); 219 } 220 } 221 } 222 if (shared->debug > 1) { 223 PR_fprintf(debug_out, "closing ... "); 224 } 225 rv = PR_Shutdown(clientSock, PR_SHUTDOWN_BOTH); 226 rv = PR_Close(clientSock); 227 if (shared->debug > 1) { 228 if (PR_SUCCESS == rv) { 229 PR_fprintf(debug_out, "\n"); 230 } else { 231 PL_FPrintError(debug_out, "shutdown failed"); 232 } 233 } 234 } else { 235 if (shared->debug > 1) { 236 PL_FPrintError(debug_out, "connect failed"); 237 } 238 PR_Close(clientSock); 239 if ((loop == 0) && (PR_GetError() == PR_CONNECT_REFUSED_ERROR)) { 240 if (MakeReceiver(shared) == PR_FAILURE) { 241 break; 242 } 243 } else { 244 if (shared->debug > 1) { 245 PR_fprintf(debug_out, " exiting\n"); 246 } 247 break; 248 } 249 } 250 } else { 251 shared->failed = PR_TRUE; 252 if (shared->debug > 0) { 253 PL_FPrintError(debug_out, "create socket"); 254 } 255 break; 256 } 257 } 258 259 PR_DELETE(buffer); 260 } /* Connect */ 261 262 int Tmocon(int argc, char** argv) { 263 /* 264 * USAGE 265 * -d turn on debugging output (default = off) 266 * -v turn on verbose output (default = off) 267 * -h <n> dns name of host serving the connection (default = self) 268 * -i dally intermittantly to cause timeouts (default = off) 269 * -m <n> number of messages to send (default = 100) 270 * -s <n> size of each message (default = 100) 271 * -t <n> number of threads sending (default = 1) 272 * -G use global threads (default = local) 273 * -T <n> timeout on I/O operations (seconds) (default = 10) 274 * -D <n> dally between connect requests (seconds)(default = 0) 275 * -R randomize the dally types around 'T' (default = no) 276 */ 277 278 PRStatus rv; 279 int exitStatus; 280 PLOptStatus os; 281 Shared* shared = NULL; 282 PRThread** thread = NULL; 283 PRIntn index, threads = DEFAULT_THREADS; 284 PRThreadScope thread_scope = PR_LOCAL_THREAD; 285 PRInt32 dally = DEFAULT_DALLY, timeout = DEFAULT_TIMEOUT; 286 PLOptState* opt = PL_CreateOptState(argc, argv, "divGRh:m:s:t:T:D:"); 287 288 shared = PR_NEWZAP(Shared); 289 290 shared->debug = 0; 291 shared->failed = PR_FALSE; 292 shared->random = PR_FALSE; 293 shared->messages = DEFAULT_MESSAGES; 294 shared->message_length = DEFAULT_MESSAGESIZE; 295 296 memset(&shared->serverAddress, 0, sizeof(shared->serverAddress)); 297 rv = PR_InitializeNetAddr(PR_IpAddrLoopback, BASE_PORT, 298 &shared->serverAddress); 299 PR_ASSERT(PR_SUCCESS == rv); 300 301 while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) { 302 if (PL_OPT_BAD == os) { 303 continue; 304 } 305 switch (opt->option) { 306 case 'd': 307 if (0 == shared->debug) { 308 shared->debug = 1; 309 } 310 break; 311 case 'v': 312 if (0 == shared->debug) { 313 shared->debug = 2; 314 } 315 break; 316 case 'i': 317 shared->intermittant = PR_TRUE; 318 break; 319 case 'R': 320 shared->random = PR_TRUE; 321 break; 322 case 'G': 323 thread_scope = PR_GLOBAL_THREAD; 324 break; 325 case 'h': /* the value for backlock */ 326 { 327 PRIntn es = 0; 328 PRHostEnt host; 329 char buffer[1024]; 330 (void)PR_GetHostByName(opt->value, buffer, sizeof(buffer), &host); 331 es = PR_EnumerateHostEnt(es, &host, BASE_PORT, &shared->serverAddress); 332 PR_ASSERT(es > 0); 333 } break; 334 case 'm': /* number of messages to send */ 335 shared->messages = atoi(opt->value); 336 break; 337 case 't': /* number of threads sending */ 338 threads = atoi(opt->value); 339 break; 340 case 'D': /* dally time between transmissions */ 341 dally = atoi(opt->value); 342 break; 343 case 'T': /* timeout on I/O operations */ 344 timeout = atoi(opt->value); 345 break; 346 case 's': /* total size of each message */ 347 shared->message_length = atoi(opt->value); 348 break; 349 default: 350 break; 351 } 352 } 353 PL_DestroyOptState(opt); 354 355 if (0 == timeout) { 356 timeout = DEFAULT_TIMEOUT; 357 } 358 if (0 == threads) { 359 threads = DEFAULT_THREADS; 360 } 361 if (0 == shared->messages) { 362 shared->messages = DEFAULT_MESSAGES; 363 } 364 if (0 == shared->message_length) { 365 shared->message_length = DEFAULT_MESSAGESIZE; 366 } 367 368 shared->dally = PR_SecondsToInterval(dally); 369 shared->timeout = PR_SecondsToInterval(timeout); 370 371 thread = (PRThread**)PR_CALLOC(threads * sizeof(PRThread*)); 372 373 for (index = 0; index < threads; ++index) 374 thread[index] = 375 PR_CreateThread(PR_USER_THREAD, Connect, shared, PR_PRIORITY_NORMAL, 376 thread_scope, PR_JOINABLE_THREAD, 0); 377 for (index = 0; index < threads; ++index) { 378 rv = PR_JoinThread(thread[index]); 379 } 380 381 PR_DELETE(thread); 382 383 PR_fprintf(PR_GetSpecialFD(PR_StandardError), "%s\n", 384 ((shared->failed) ? "FAILED" : "PASSED")); 385 exitStatus = (shared->failed) ? 1 : 0; 386 PR_DELETE(shared); 387 return exitStatus; 388 } 389 390 int main(int argc, char** argv) { 391 return (PR_VersionCheck(PR_VERSION)) ? PR_Initialize(Tmocon, argc, argv, 4) 392 : -1; 393 } /* main */ 394 395 /* tmocon.c */