accept.c (14010B)
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 ** 1996 - Netscape Communications Corporation 8 ** 9 ** Name: accept.c 10 ** 11 ** Description: Run accept() sucessful connection tests. 12 ** 13 ** Modification History: 14 ** 04-Jun-97 AGarcia - Reconvert test file to return a 0 for PASS and a 1 for 15 *FAIL 16 ** 13-May-97 AGarcia- Converted the test to accomodate the debug_mode 17 ** The debug mode will print all of the printfs associated with this 18 *test. 19 ** The regress mode will be the default mode. Since the regress tool 20 *limits 21 ** the output to a one line status:PASS or FAIL,all of the printf 22 *statements 23 ** have been handled with an if (debug_mode) statement. 24 ** 04-June-97 AGarcia removed the Test_Result function. Regress tool has been 25 *updated to 26 ** recognize the return code from tha main program. 27 ** 12-June-97 Revert to return code 0 and 1. 28 ***********************************************************************/ 29 30 /*********************************************************************** 31 ** Includes 32 ***********************************************************************/ 33 34 #include "nspr.h" 35 #include "prpriv.h" 36 37 #include <stdlib.h> 38 #include <string.h> 39 40 #include "plgetopt.h" 41 #include "plerror.h" 42 43 #define BASE_PORT 10000 44 45 #define CLIENT_DATA 128 46 47 #define ACCEPT_NORMAL 0x1 48 #define ACCEPT_FAST 0x2 49 #define ACCEPT_READ 0x3 50 #define ACCEPT_READ_FAST 0x4 51 #define ACCEPT_READ_FAST_CB 0x5 52 53 #define CLIENT_NORMAL 0x1 54 #define CLIENT_TIMEOUT_ACCEPT 0x2 55 #define CLIENT_TIMEOUT_SEND 0x3 56 57 #define SERVER_MAX_BIND_COUNT 100 58 59 #define TIMEOUTSECS 2 60 PRIntervalTime timeoutTime; 61 62 static PRInt32 count = 1; 63 static PRFileDesc* output; 64 static PRNetAddr serverAddr; 65 static PRThreadScope thread_scope = PR_LOCAL_THREAD; 66 static PRInt32 clientCommand; 67 static PRInt32 iterations; 68 static PRStatus rv; 69 static PRFileDesc* listenSock; 70 static PRFileDesc* clientSock = NULL; 71 static PRNetAddr listenAddr; 72 static PRNetAddr clientAddr; 73 static PRThread* clientThread; 74 static PRNetAddr* raddr; 75 static char buf[4096 + 2 * sizeof(PRNetAddr) + 32]; 76 static PRInt32 status; 77 static PRInt32 bytesRead; 78 79 PRIntn failed_already = 0; 80 PRIntn debug_mode; 81 82 void Test_Assert(const char* msg, const char* file, PRIntn line) { 83 failed_already = 1; 84 if (debug_mode) { 85 PR_fprintf(output, "@%s:%d ", file, line); 86 PR_fprintf(output, msg); 87 } 88 } /* Test_Assert */ 89 90 #define TEST_ASSERT(expr) \ 91 if (!(expr)) Test_Assert(#expr, __FILE__, __LINE__) 92 93 #ifdef WINNT 94 # define CALLBACK_MAGIC 0x12345678 95 96 void timeout_callback(void* magic) { 97 TEST_ASSERT(magic == (void*)CALLBACK_MAGIC); 98 if (debug_mode) { 99 PR_fprintf(output, "timeout callback called okay\n"); 100 } 101 } 102 #endif 103 104 static void PR_CALLBACK ClientThread(void* _action) { 105 PRInt32 action = *(PRInt32*)_action; 106 PRInt32 iterations = count; 107 PRFileDesc* sock = NULL; 108 109 serverAddr.inet.family = PR_AF_INET; 110 serverAddr.inet.port = listenAddr.inet.port; 111 serverAddr.inet.ip = PR_htonl(PR_INADDR_LOOPBACK); 112 113 for (; iterations--;) { 114 PRInt32 rv; 115 char buf[CLIENT_DATA]; 116 117 memset(buf, 0xaf, sizeof(buf)); /* initialize with arbitrary data */ 118 sock = PR_NewTCPSocket(); 119 if (!sock) { 120 if (!debug_mode) { 121 failed_already = 1; 122 } else { 123 PR_fprintf(output, "client: unable to create socket\n"); 124 } 125 return; 126 } 127 128 if (action != CLIENT_TIMEOUT_ACCEPT) { 129 if ((rv = PR_Connect(sock, &serverAddr, timeoutTime)) < 0) { 130 if (!debug_mode) { 131 failed_already = 1; 132 } else 133 PR_fprintf( 134 output, 135 "client: unable to connect to server (%ld, %ld, %ld, %ld)\n", 136 iterations, rv, PR_GetError(), PR_GetOSError()); 137 goto ErrorExit; 138 } 139 140 if (action != CLIENT_TIMEOUT_SEND) { 141 if ((rv = PR_Send(sock, buf, CLIENT_DATA, 0, timeoutTime)) < 0) { 142 if (!debug_mode) { 143 failed_already = 1; 144 } else { 145 PR_fprintf(output, 146 "client: unable to send to server (%d, %ld, %ld)\n", 147 CLIENT_DATA, rv, PR_GetError()); 148 } 149 goto ErrorExit; 150 } 151 } else { 152 PR_Sleep(PR_SecondsToInterval(TIMEOUTSECS + 1)); 153 } 154 } else { 155 PR_Sleep(PR_SecondsToInterval(TIMEOUTSECS + 1)); 156 } 157 if (debug_mode) { 158 PR_fprintf(output, "."); 159 } 160 PR_Close(sock); 161 sock = NULL; 162 } 163 if (debug_mode) { 164 PR_fprintf(output, "\n"); 165 } 166 167 ErrorExit: 168 if (sock != NULL) { 169 PR_Close(sock); 170 } 171 } 172 173 static void RunTest(PRInt32 acceptType, PRInt32 clientAction) { 174 int i; 175 176 /* First bind to the socket */ 177 listenSock = PR_NewTCPSocket(); 178 if (!listenSock) { 179 failed_already = 1; 180 if (debug_mode) { 181 PR_fprintf(output, "unable to create listen socket\n"); 182 } 183 return; 184 } 185 memset(&listenAddr, 0, sizeof(listenAddr)); 186 listenAddr.inet.family = PR_AF_INET; 187 listenAddr.inet.port = PR_htons(BASE_PORT); 188 listenAddr.inet.ip = PR_htonl(PR_INADDR_ANY); 189 /* 190 * try a few times to bind server's address, if addresses are in 191 * use 192 */ 193 i = 0; 194 while (PR_Bind(listenSock, &listenAddr) == PR_FAILURE) { 195 if (PR_GetError() == PR_ADDRESS_IN_USE_ERROR) { 196 listenAddr.inet.port += 2; 197 if (i++ < SERVER_MAX_BIND_COUNT) { 198 continue; 199 } 200 } 201 failed_already = 1; 202 if (debug_mode) { 203 PR_fprintf(output, "accept: ERROR - PR_Bind failed\n"); 204 } 205 return; 206 } 207 208 rv = PR_Listen(listenSock, 100); 209 if (rv == PR_FAILURE) { 210 failed_already = 1; 211 if (debug_mode) { 212 PR_fprintf(output, "unable to listen\n"); 213 } 214 return; 215 } 216 217 clientCommand = clientAction; 218 clientThread = 219 PR_CreateThread(PR_USER_THREAD, ClientThread, (void*)&clientCommand, 220 PR_PRIORITY_NORMAL, thread_scope, PR_JOINABLE_THREAD, 0); 221 if (!clientThread) { 222 failed_already = 1; 223 if (debug_mode) { 224 PR_fprintf(output, "error creating client thread\n"); 225 } 226 return; 227 } 228 229 iterations = count; 230 for (; iterations--;) { 231 switch (acceptType) { 232 case ACCEPT_NORMAL: 233 clientSock = PR_Accept(listenSock, &clientAddr, timeoutTime); 234 switch (clientAction) { 235 case CLIENT_TIMEOUT_ACCEPT: 236 TEST_ASSERT(clientSock == 0); 237 TEST_ASSERT(PR_GetError() == PR_IO_TIMEOUT_ERROR); 238 break; 239 case CLIENT_NORMAL: 240 TEST_ASSERT(clientSock); 241 bytesRead = PR_Recv(clientSock, buf, CLIENT_DATA, 0, timeoutTime); 242 TEST_ASSERT(bytesRead == CLIENT_DATA); 243 break; 244 case CLIENT_TIMEOUT_SEND: 245 TEST_ASSERT(clientSock); 246 bytesRead = PR_Recv(clientSock, buf, CLIENT_DATA, 0, timeoutTime); 247 TEST_ASSERT(bytesRead == -1); 248 TEST_ASSERT(PR_GetError() == PR_IO_TIMEOUT_ERROR); 249 break; 250 } 251 break; 252 case ACCEPT_READ: 253 status = PR_AcceptRead(listenSock, &clientSock, &raddr, buf, 254 CLIENT_DATA, timeoutTime); 255 switch (clientAction) { 256 case CLIENT_TIMEOUT_ACCEPT: 257 /* Invalid test case */ 258 TEST_ASSERT(0); 259 break; 260 case CLIENT_NORMAL: 261 TEST_ASSERT(clientSock); 262 TEST_ASSERT(status == CLIENT_DATA); 263 break; 264 case CLIENT_TIMEOUT_SEND: 265 TEST_ASSERT(status == -1); 266 TEST_ASSERT(PR_GetError() == PR_IO_TIMEOUT_ERROR); 267 break; 268 } 269 break; 270 #ifdef WINNT 271 case ACCEPT_FAST: 272 clientSock = PR_NTFast_Accept(listenSock, &clientAddr, timeoutTime); 273 switch (clientAction) { 274 case CLIENT_TIMEOUT_ACCEPT: 275 TEST_ASSERT(clientSock == 0); 276 if (debug_mode) { 277 PR_fprintf(output, "PR_GetError is %ld\n", PR_GetError()); 278 } 279 TEST_ASSERT(PR_GetError() == PR_IO_TIMEOUT_ERROR); 280 break; 281 case CLIENT_NORMAL: 282 TEST_ASSERT(clientSock); 283 bytesRead = PR_Recv(clientSock, buf, CLIENT_DATA, 0, timeoutTime); 284 TEST_ASSERT(bytesRead == CLIENT_DATA); 285 break; 286 case CLIENT_TIMEOUT_SEND: 287 TEST_ASSERT(clientSock); 288 bytesRead = PR_Recv(clientSock, buf, CLIENT_DATA, 0, timeoutTime); 289 TEST_ASSERT(bytesRead == -1); 290 TEST_ASSERT(PR_GetError() == PR_IO_TIMEOUT_ERROR); 291 break; 292 } 293 break; 294 break; 295 case ACCEPT_READ_FAST: 296 status = PR_NTFast_AcceptRead(listenSock, &clientSock, &raddr, buf, 297 4096, timeoutTime); 298 switch (clientAction) { 299 case CLIENT_TIMEOUT_ACCEPT: 300 /* Invalid test case */ 301 TEST_ASSERT(0); 302 break; 303 case CLIENT_NORMAL: 304 TEST_ASSERT(clientSock); 305 TEST_ASSERT(status == CLIENT_DATA); 306 break; 307 case CLIENT_TIMEOUT_SEND: 308 TEST_ASSERT(clientSock == NULL); 309 TEST_ASSERT(status == -1); 310 TEST_ASSERT(PR_GetError() == PR_IO_TIMEOUT_ERROR); 311 break; 312 } 313 break; 314 case ACCEPT_READ_FAST_CB: 315 status = PR_NTFast_AcceptRead_WithTimeoutCallback( 316 listenSock, &clientSock, &raddr, buf, 4096, timeoutTime, 317 timeout_callback, (void*)CALLBACK_MAGIC); 318 switch (clientAction) { 319 case CLIENT_TIMEOUT_ACCEPT: 320 /* Invalid test case */ 321 TEST_ASSERT(0); 322 break; 323 case CLIENT_NORMAL: 324 TEST_ASSERT(clientSock); 325 TEST_ASSERT(status == CLIENT_DATA); 326 break; 327 case CLIENT_TIMEOUT_SEND: 328 if (debug_mode) { 329 PR_fprintf(output, "clientSock = 0x%8.8lx\n", clientSock); 330 } 331 TEST_ASSERT(clientSock == NULL); 332 TEST_ASSERT(status == -1); 333 TEST_ASSERT(PR_GetError() == PR_IO_TIMEOUT_ERROR); 334 break; 335 } 336 break; 337 #endif 338 } 339 if (clientSock != NULL) { 340 PR_Close(clientSock); 341 clientSock = NULL; 342 } 343 } 344 PR_Close(listenSock); 345 346 PR_JoinThread(clientThread); 347 } 348 349 void AcceptUpdatedTest(void) { RunTest(ACCEPT_NORMAL, CLIENT_NORMAL); } 350 void AcceptNotUpdatedTest(void) { RunTest(ACCEPT_FAST, CLIENT_NORMAL); } 351 void AcceptReadTest(void) { RunTest(ACCEPT_READ, CLIENT_NORMAL); } 352 void AcceptReadNotUpdatedTest(void) { 353 RunTest(ACCEPT_READ_FAST, CLIENT_NORMAL); 354 } 355 void AcceptReadCallbackTest(void) { 356 RunTest(ACCEPT_READ_FAST_CB, CLIENT_NORMAL); 357 } 358 359 void TimeoutAcceptUpdatedTest(void) { 360 RunTest(ACCEPT_NORMAL, CLIENT_TIMEOUT_ACCEPT); 361 } 362 void TimeoutAcceptNotUpdatedTest(void) { 363 RunTest(ACCEPT_FAST, CLIENT_TIMEOUT_ACCEPT); 364 } 365 void TimeoutAcceptReadCallbackTest(void) { 366 RunTest(ACCEPT_READ_FAST_CB, CLIENT_TIMEOUT_ACCEPT); 367 } 368 369 void TimeoutReadUpdatedTest(void) { 370 RunTest(ACCEPT_NORMAL, CLIENT_TIMEOUT_SEND); 371 } 372 void TimeoutReadNotUpdatedTest(void) { 373 RunTest(ACCEPT_FAST, CLIENT_TIMEOUT_SEND); 374 } 375 void TimeoutReadReadTest(void) { RunTest(ACCEPT_READ, CLIENT_TIMEOUT_SEND); } 376 void TimeoutReadReadNotUpdatedTest(void) { 377 RunTest(ACCEPT_READ_FAST, CLIENT_TIMEOUT_SEND); 378 } 379 void TimeoutReadReadCallbackTest(void) { 380 RunTest(ACCEPT_READ_FAST_CB, CLIENT_TIMEOUT_SEND); 381 } 382 383 /************************************************************************/ 384 385 static void Measure(void (*func)(void), const char* msg) { 386 PRIntervalTime start, stop; 387 double d; 388 389 start = PR_IntervalNow(); 390 (*func)(); 391 stop = PR_IntervalNow(); 392 393 d = (double)PR_IntervalToMicroseconds(stop - start); 394 if (debug_mode) { 395 PR_fprintf(output, "%40s: %6.2f usec\n", msg, d / count); 396 } 397 } 398 399 int main(int argc, char** argv) { 400 /* The command line argument: -d is used to determine if the test is being run 401 in debug mode. The regress tool requires only one line output:PASS or FAIL. 402 All of the printfs associated with this test has been handled with a if 403 (debug_mode) test. Usage: test_name [-d] [-c n] 404 */ 405 PLOptStatus os; 406 PLOptState* opt = PL_CreateOptState(argc, argv, "Gdc:"); 407 while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) { 408 if (PL_OPT_BAD == os) { 409 continue; 410 } 411 switch (opt->option) { 412 case 'G': /* global threads */ 413 thread_scope = PR_GLOBAL_THREAD; 414 break; 415 case 'd': /* debug mode */ 416 debug_mode = 1; 417 break; 418 case 'c': /* loop counter */ 419 count = atoi(opt->value); 420 break; 421 default: 422 break; 423 } 424 } 425 PL_DestroyOptState(opt); 426 427 PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); 428 output = PR_STDERR; 429 430 timeoutTime = PR_SecondsToInterval(TIMEOUTSECS); 431 if (debug_mode) { 432 PR_fprintf(output, "\nRun accept() sucessful connection tests\n"); 433 } 434 435 Measure(AcceptUpdatedTest, "PR_Accept()"); 436 Measure(AcceptReadTest, "PR_AcceptRead()"); 437 #ifdef WINNT 438 Measure(AcceptNotUpdatedTest, "PR_NTFast_Accept()"); 439 Measure(AcceptReadNotUpdatedTest, "PR_NTFast_AcceptRead()"); 440 Measure(AcceptReadCallbackTest, "PR_NTFast_AcceptRead_WithTimeoutCallback()"); 441 #endif 442 if (debug_mode) { 443 PR_fprintf(output, "\nRun accept() timeout in the accept tests\n"); 444 } 445 #ifdef WINNT 446 Measure(TimeoutReadReadCallbackTest, 447 "PR_NTFast_AcceptRead_WithTimeoutCallback()"); 448 #endif 449 Measure(TimeoutReadUpdatedTest, "PR_Accept()"); 450 if (debug_mode) { 451 PR_fprintf(output, "\nRun accept() timeout in the read tests\n"); 452 } 453 Measure(TimeoutReadReadTest, "PR_AcceptRead()"); 454 #ifdef WINNT 455 Measure(TimeoutReadNotUpdatedTest, "PR_NTFast_Accept()"); 456 Measure(TimeoutReadReadNotUpdatedTest, "PR_NTFast_AcceptRead()"); 457 Measure(TimeoutReadReadCallbackTest, 458 "PR_NTFast_AcceptRead_WithTimeoutCallback()"); 459 #endif 460 PR_fprintf(output, "%s\n", (failed_already) ? "FAIL" : "PASS"); 461 return failed_already; 462 }