nblayer.c (22872B)
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 #include "prio.h" 7 #include "prmem.h" 8 #include "prprf.h" 9 #include "prlog.h" 10 #include "prerror.h" 11 #include "prnetdb.h" 12 #include "prthread.h" 13 14 #include "plerror.h" 15 #include "plgetopt.h" 16 17 #include <stdlib.h> 18 #include <string.h> 19 20 /* 21 ** Testing layering of I/O 22 ** 23 ** The layered server 24 ** A thread that acts as a server. It creates a TCP listener with a dummy 25 ** layer pushed on top. Then listens for incoming connections. Each connection 26 ** request for connection will be layered as well, accept one request, echo 27 ** it back and close. 28 ** 29 ** The layered client 30 ** Pretty much what you'd expect. 31 */ 32 33 static PRFileDesc* logFile; 34 static PRDescIdentity identity; 35 static PRNetAddr server_address; 36 37 static PRIOMethods myMethods; 38 39 typedef enum { rcv_get_debit, rcv_send_credit, rcv_data } RcvState; 40 typedef enum { xmt_send_debit, xmt_recv_credit, xmt_data } XmtState; 41 42 struct PRFilePrivate { 43 RcvState rcvstate; 44 XmtState xmtstate; 45 PRInt32 rcvreq, rcvinprogress; 46 PRInt32 xmtreq, xmtinprogress; 47 }; 48 49 typedef enum Verbosity { silent, quiet, chatty, noisy } Verbosity; 50 51 static PRIntn minor_iterations = 5; 52 static PRIntn major_iterations = 1; 53 static Verbosity verbosity = quiet; 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 static PRUint16 default_port = 12273 PORT_INC_DO PORT_INC_3264; 67 68 static PRFileDesc* PushLayer(PRFileDesc* stack) { 69 PRStatus rv; 70 PRFileDesc* layer = PR_CreateIOLayerStub(identity, &myMethods); 71 layer->secret = PR_NEWZAP(PRFilePrivate); 72 rv = PR_PushIOLayer(stack, PR_GetLayersIdentity(stack), layer); 73 PR_ASSERT(PR_SUCCESS == rv); 74 if (verbosity > quiet) { 75 PR_fprintf(logFile, "Pushed layer(0x%x) onto stack(0x%x)\n", layer, stack); 76 } 77 return stack; 78 } /* PushLayer */ 79 80 static PRFileDesc* PopLayer(PRFileDesc* stack) { 81 PRFileDesc* popped = PR_PopIOLayer(stack, identity); 82 if (verbosity > quiet) { 83 PR_fprintf(logFile, "Popped layer(0x%x) from stack(0x%x)\n", popped, stack); 84 } 85 PR_DELETE(popped->secret); 86 popped->dtor(popped); 87 return stack; 88 } /* PopLayer */ 89 90 static void PR_CALLBACK Client(void* arg) { 91 PRStatus rv; 92 PRIntn mits; 93 PRInt32 ready; 94 PRUint8 buffer[100]; 95 PRPollDesc polldesc; 96 PRIntn empty_flags = 0; 97 PRIntn bytes_read, bytes_sent; 98 PRFileDesc* stack = (PRFileDesc*)arg; 99 100 /* Initialize the buffer so that Purify won't complain */ 101 memset(buffer, 0, sizeof(buffer)); 102 103 rv = PR_Connect(stack, &server_address, PR_INTERVAL_NO_TIMEOUT); 104 if ((PR_FAILURE == rv) && (PR_IN_PROGRESS_ERROR == PR_GetError())) { 105 if (verbosity > quiet) { 106 PR_fprintf(logFile, "Client connect 'in progress'\n"); 107 } 108 do { 109 polldesc.fd = stack; 110 polldesc.out_flags = 0; 111 polldesc.in_flags = PR_POLL_WRITE | PR_POLL_EXCEPT; 112 ready = PR_Poll(&polldesc, 1, PR_INTERVAL_NO_TIMEOUT); 113 if ((1 != ready) /* if not 1, then we're dead */ 114 || (0 == (polldesc.in_flags & polldesc.out_flags))) { 115 PR_NOT_REACHED("Whoa!"); 116 break; 117 } 118 if (verbosity > quiet) 119 PR_fprintf(logFile, "Client connect 'in progress' [0x%x]\n", 120 polldesc.out_flags); 121 rv = PR_GetConnectStatus(&polldesc); 122 if ((PR_FAILURE == rv) && (PR_IN_PROGRESS_ERROR != PR_GetError())) { 123 break; 124 } 125 } while (PR_FAILURE == rv); 126 } 127 PR_ASSERT(PR_SUCCESS == rv); 128 if (verbosity > chatty) { 129 PR_fprintf(logFile, "Client created connection\n"); 130 } 131 132 for (mits = 0; mits < minor_iterations; ++mits) { 133 bytes_sent = 0; 134 if (verbosity > quiet) { 135 PR_fprintf(logFile, "Client sending %d bytes\n", sizeof(buffer)); 136 } 137 do { 138 if (verbosity > chatty) 139 PR_fprintf(logFile, "Client sending %d bytes\n", 140 sizeof(buffer) - bytes_sent); 141 ready = PR_Send(stack, buffer + bytes_sent, sizeof(buffer) - bytes_sent, 142 empty_flags, PR_INTERVAL_NO_TIMEOUT); 143 if (verbosity > chatty) { 144 PR_fprintf(logFile, "Client send status [%d]\n", ready); 145 } 146 if (0 < ready) { 147 bytes_sent += ready; 148 } else if ((-1 == ready) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) { 149 polldesc.fd = stack; 150 polldesc.out_flags = 0; 151 polldesc.in_flags = PR_POLL_WRITE; 152 ready = PR_Poll(&polldesc, 1, PR_INTERVAL_NO_TIMEOUT); 153 if ((1 != ready) /* if not 1, then we're dead */ 154 || (0 == (polldesc.in_flags & polldesc.out_flags))) { 155 PR_NOT_REACHED("Whoa!"); 156 break; 157 } 158 } else { 159 break; 160 } 161 } while (bytes_sent < sizeof(buffer)); 162 PR_ASSERT(sizeof(buffer) == bytes_sent); 163 164 bytes_read = 0; 165 do { 166 if (verbosity > chatty) 167 PR_fprintf(logFile, "Client receiving %d bytes\n", 168 bytes_sent - bytes_read); 169 ready = PR_Recv(stack, buffer + bytes_read, bytes_sent - bytes_read, 170 empty_flags, PR_INTERVAL_NO_TIMEOUT); 171 if (verbosity > chatty) 172 PR_fprintf(logFile, "Client receive status [%d]\n", ready); 173 if (0 < ready) { 174 bytes_read += ready; 175 } else if ((-1 == ready) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) { 176 polldesc.fd = stack; 177 polldesc.out_flags = 0; 178 polldesc.in_flags = PR_POLL_READ; 179 ready = PR_Poll(&polldesc, 1, PR_INTERVAL_NO_TIMEOUT); 180 if ((1 != ready) /* if not 1, then we're dead */ 181 || (0 == (polldesc.in_flags & polldesc.out_flags))) { 182 PR_NOT_REACHED("Whoa!"); 183 break; 184 } 185 } else { 186 break; 187 } 188 } while (bytes_read < bytes_sent); 189 if (verbosity > chatty) { 190 PR_fprintf(logFile, "Client received %d bytes\n", bytes_read); 191 } 192 PR_ASSERT(bytes_read == bytes_sent); 193 } 194 195 if (verbosity > quiet) { 196 PR_fprintf(logFile, "Client shutting down stack\n"); 197 } 198 199 rv = PR_Shutdown(stack, PR_SHUTDOWN_BOTH); 200 PR_ASSERT(PR_SUCCESS == rv); 201 } /* Client */ 202 203 static void PR_CALLBACK Server(void* arg) { 204 PRStatus rv; 205 PRInt32 ready; 206 PRUint8 buffer[100]; 207 PRFileDesc* service; 208 PRUintn empty_flags = 0; 209 struct PRPollDesc polldesc; 210 PRIntn bytes_read, bytes_sent; 211 PRFileDesc* stack = (PRFileDesc*)arg; 212 PRNetAddr client_address; 213 214 do { 215 if (verbosity > chatty) { 216 PR_fprintf(logFile, "Server accepting connection\n"); 217 } 218 service = PR_Accept(stack, &client_address, PR_INTERVAL_NO_TIMEOUT); 219 if (verbosity > chatty) { 220 PR_fprintf(logFile, "Server accept status [0x%p]\n", service); 221 } 222 if ((NULL == service) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) { 223 polldesc.fd = stack; 224 polldesc.out_flags = 0; 225 polldesc.in_flags = PR_POLL_READ | PR_POLL_EXCEPT; 226 ready = PR_Poll(&polldesc, 1, PR_INTERVAL_NO_TIMEOUT); 227 if ((1 != ready) /* if not 1, then we're dead */ 228 || (0 == (polldesc.in_flags & polldesc.out_flags))) { 229 PR_NOT_REACHED("Whoa!"); 230 break; 231 } 232 } 233 } while (NULL == service); 234 PR_ASSERT(NULL != service); 235 236 if (verbosity > quiet) { 237 PR_fprintf(logFile, "Server accepting connection\n"); 238 } 239 240 do { 241 bytes_read = 0; 242 do { 243 if (verbosity > chatty) 244 PR_fprintf(logFile, "Server receiving %d bytes\n", 245 sizeof(buffer) - bytes_read); 246 ready = PR_Recv(service, buffer + bytes_read, sizeof(buffer) - bytes_read, 247 empty_flags, PR_INTERVAL_NO_TIMEOUT); 248 if (verbosity > chatty) { 249 PR_fprintf(logFile, "Server receive status [%d]\n", ready); 250 } 251 if (0 < ready) { 252 bytes_read += ready; 253 } else if ((-1 == ready) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) { 254 polldesc.fd = service; 255 polldesc.out_flags = 0; 256 polldesc.in_flags = PR_POLL_READ; 257 ready = PR_Poll(&polldesc, 1, PR_INTERVAL_NO_TIMEOUT); 258 if ((1 != ready) /* if not 1, then we're dead */ 259 || (0 == (polldesc.in_flags & polldesc.out_flags))) { 260 PR_NOT_REACHED("Whoa!"); 261 break; 262 } 263 } else { 264 break; 265 } 266 } while (bytes_read < sizeof(buffer)); 267 268 if (0 != bytes_read) { 269 if (verbosity > chatty) { 270 PR_fprintf(logFile, "Server received %d bytes\n", bytes_read); 271 } 272 PR_ASSERT(bytes_read > 0); 273 274 bytes_sent = 0; 275 do { 276 ready = PR_Send(service, buffer + bytes_sent, bytes_read - bytes_sent, 277 empty_flags, PR_INTERVAL_NO_TIMEOUT); 278 if (0 < ready) { 279 bytes_sent += ready; 280 } else if ((-1 == ready) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) { 281 polldesc.fd = service; 282 polldesc.out_flags = 0; 283 polldesc.in_flags = PR_POLL_WRITE; 284 ready = PR_Poll(&polldesc, 1, PR_INTERVAL_NO_TIMEOUT); 285 if ((1 != ready) /* if not 1, then we're dead */ 286 || (0 == (polldesc.in_flags & polldesc.out_flags))) { 287 PR_NOT_REACHED("Whoa!"); 288 break; 289 } 290 } else { 291 break; 292 } 293 } while (bytes_sent < bytes_read); 294 PR_ASSERT(bytes_read == bytes_sent); 295 if (verbosity > chatty) { 296 PR_fprintf(logFile, "Server sent %d bytes\n", bytes_sent); 297 } 298 } 299 } while (0 != bytes_read); 300 301 if (verbosity > quiet) { 302 PR_fprintf(logFile, "Server shutting down stack\n"); 303 } 304 rv = PR_Shutdown(service, PR_SHUTDOWN_BOTH); 305 PR_ASSERT(PR_SUCCESS == rv); 306 rv = PR_Close(service); 307 PR_ASSERT(PR_SUCCESS == rv); 308 309 } /* Server */ 310 311 static PRStatus PR_CALLBACK MyClose(PRFileDesc* fd) { 312 PR_DELETE(fd->secret); /* manage my secret file object */ 313 return (PR_GetDefaultIOMethods())->close(fd); /* let him do all the work */ 314 } /* MyClose */ 315 316 static PRInt16 PR_CALLBACK MyPoll(PRFileDesc* fd, PRInt16 in_flags, 317 PRInt16* out_flags) { 318 PRInt16 my_flags, new_flags; 319 PRFilePrivate* mine = (PRFilePrivate*)fd->secret; 320 if (0 != (PR_POLL_READ & in_flags)) { 321 /* client thinks he's reading */ 322 switch (mine->rcvstate) { 323 case rcv_send_credit: 324 my_flags = (in_flags & ~PR_POLL_READ) | PR_POLL_WRITE; 325 break; 326 case rcv_data: 327 case rcv_get_debit: 328 my_flags = in_flags; 329 default: 330 break; 331 } 332 } else if (0 != (PR_POLL_WRITE & in_flags)) { 333 /* client thinks he's writing */ 334 switch (mine->xmtstate) { 335 case xmt_recv_credit: 336 my_flags = (in_flags & ~PR_POLL_WRITE) | PR_POLL_READ; 337 break; 338 case xmt_send_debit: 339 case xmt_data: 340 my_flags = in_flags; 341 default: 342 break; 343 } 344 } else { 345 PR_NOT_REACHED("How'd I get here?"); 346 } 347 new_flags = (fd->lower->methods->poll)(fd->lower, my_flags, out_flags); 348 if (verbosity > chatty) 349 PR_fprintf(logFile, "Poll [i: 0x%x, m: 0x%x, o: 0x%x, n: 0x%x]\n", in_flags, 350 my_flags, *out_flags, new_flags); 351 return new_flags; 352 } /* MyPoll */ 353 354 static PRFileDesc* PR_CALLBACK MyAccept(PRFileDesc* fd, PRNetAddr* addr, 355 PRIntervalTime timeout) { 356 PRStatus rv; 357 PRFileDesc *newfd, *layer = fd; 358 PRFileDesc* newstack; 359 PRFilePrivate* newsecret; 360 361 PR_ASSERT(fd != NULL); 362 PR_ASSERT(fd->lower != NULL); 363 364 newstack = PR_NEW(PRFileDesc); 365 if (NULL == newstack) { 366 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); 367 return NULL; 368 } 369 newsecret = PR_NEW(PRFilePrivate); 370 if (NULL == newsecret) { 371 PR_DELETE(newstack); 372 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); 373 return NULL; 374 } 375 *newstack = *fd; /* make a copy of the accepting layer */ 376 *newsecret = *fd->secret; 377 newstack->secret = newsecret; 378 379 newfd = (fd->lower->methods->accept)(fd->lower, addr, timeout); 380 if (NULL == newfd) { 381 PR_DELETE(newsecret); 382 PR_DELETE(newstack); 383 return NULL; 384 } 385 386 /* this PR_PushIOLayer call cannot fail */ 387 rv = PR_PushIOLayer(newfd, PR_TOP_IO_LAYER, newstack); 388 PR_ASSERT(PR_SUCCESS == rv); 389 return newfd; /* that's it */ 390 } 391 392 static PRInt32 PR_CALLBACK MyRecv(PRFileDesc* fd, void* buf, PRInt32 amount, 393 PRIntn flags, PRIntervalTime timeout) { 394 char* b; 395 PRInt32 rv; 396 PRFileDesc* lo = fd->lower; 397 PRFilePrivate* mine = (PRFilePrivate*)fd->secret; 398 399 do { 400 switch (mine->rcvstate) { 401 case rcv_get_debit: 402 b = (char*)&mine->rcvreq; 403 mine->rcvreq = amount; 404 rv = lo->methods->recv(lo, b + mine->rcvinprogress, 405 sizeof(mine->rcvreq) - mine->rcvinprogress, 406 flags, timeout); 407 if (0 == rv) { 408 goto closed; 409 } 410 if ((-1 == rv) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) { 411 break; 412 } 413 mine->rcvinprogress += rv; /* accumulate the read */ 414 if (mine->rcvinprogress < sizeof(mine->rcvreq)) { 415 break; /* loop */ 416 } 417 mine->rcvstate = rcv_send_credit; 418 mine->rcvinprogress = 0; 419 case rcv_send_credit: 420 b = (char*)&mine->rcvreq; 421 rv = lo->methods->send(lo, b + mine->rcvinprogress, 422 sizeof(mine->rcvreq) - mine->rcvinprogress, 423 flags, timeout); 424 if ((-1 == rv) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) { 425 break; 426 } 427 mine->rcvinprogress += rv; /* accumulate the read */ 428 if (mine->rcvinprogress < sizeof(mine->rcvreq)) { 429 break; /* loop */ 430 } 431 mine->rcvstate = rcv_data; 432 mine->rcvinprogress = 0; 433 case rcv_data: 434 b = (char*)buf; 435 rv = lo->methods->recv(lo, b + mine->rcvinprogress, 436 mine->rcvreq - mine->rcvinprogress, flags, 437 timeout); 438 if (0 == rv) { 439 goto closed; 440 } 441 if ((-1 == rv) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) { 442 break; 443 } 444 mine->rcvinprogress += rv; /* accumulate the read */ 445 if (mine->rcvinprogress < amount) { 446 break; /* loop */ 447 } 448 mine->rcvstate = rcv_get_debit; 449 mine->rcvinprogress = 0; 450 return mine->rcvreq; /* << -- that's it! */ 451 default: 452 break; 453 } 454 } while (-1 != rv); 455 return rv; 456 closed: 457 mine->rcvinprogress = 0; 458 mine->rcvstate = rcv_get_debit; 459 return 0; 460 } /* MyRecv */ 461 462 static PRInt32 PR_CALLBACK MySend(PRFileDesc* fd, const void* buf, 463 PRInt32 amount, PRIntn flags, 464 PRIntervalTime timeout) { 465 char* b; 466 PRInt32 rv; 467 PRFileDesc* lo = fd->lower; 468 PRFilePrivate* mine = (PRFilePrivate*)fd->secret; 469 470 do { 471 switch (mine->xmtstate) { 472 case xmt_send_debit: 473 b = (char*)&mine->xmtreq; 474 mine->xmtreq = amount; 475 rv = lo->methods->send(lo, b - mine->xmtinprogress, 476 sizeof(mine->xmtreq) - mine->xmtinprogress, 477 flags, timeout); 478 if ((-1 == rv) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) { 479 break; 480 } 481 mine->xmtinprogress += rv; 482 if (mine->xmtinprogress < sizeof(mine->xmtreq)) { 483 break; 484 } 485 mine->xmtstate = xmt_recv_credit; 486 mine->xmtinprogress = 0; 487 case xmt_recv_credit: 488 b = (char*)&mine->xmtreq; 489 rv = lo->methods->recv(lo, b + mine->xmtinprogress, 490 sizeof(mine->xmtreq) - mine->xmtinprogress, 491 flags, timeout); 492 if ((-1 == rv) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) { 493 break; 494 } 495 mine->xmtinprogress += rv; 496 if (mine->xmtinprogress < sizeof(mine->xmtreq)) { 497 break; 498 } 499 mine->xmtstate = xmt_data; 500 mine->xmtinprogress = 0; 501 case xmt_data: 502 b = (char*)buf; 503 rv = lo->methods->send(lo, b + mine->xmtinprogress, 504 mine->xmtreq - mine->xmtinprogress, flags, 505 timeout); 506 if ((-1 == rv) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) { 507 break; 508 } 509 mine->xmtinprogress += rv; 510 if (mine->xmtinprogress < amount) { 511 break; 512 } 513 mine->xmtstate = xmt_send_debit; 514 mine->xmtinprogress = 0; 515 return mine->xmtreq; /* <<-- That's the one! */ 516 default: 517 break; 518 } 519 } while (-1 != rv); 520 return rv; 521 } /* MySend */ 522 523 static Verbosity ChangeVerbosity(Verbosity verbosity, PRIntn delta) { 524 PRIntn verbage = (PRIntn)verbosity + delta; 525 if (verbage < (PRIntn)silent) { 526 verbage = (PRIntn)silent; 527 } else if (verbage > (PRIntn)noisy) { 528 verbage = (PRIntn)noisy; 529 } 530 return (Verbosity)verbage; 531 } /* ChangeVerbosity */ 532 533 int main(int argc, char** argv) { 534 PRStatus rv; 535 PLOptStatus os; 536 PRFileDesc *client, *service; 537 PRNetAddr any_address; 538 const char* server_name = NULL; 539 const PRIOMethods* stubMethods; 540 PRThread *client_thread, *server_thread; 541 PRThreadScope thread_scope = PR_LOCAL_THREAD; 542 PRSocketOptionData socket_noblock, socket_nodelay; 543 PLOptState* opt = PL_CreateOptState(argc, argv, "dqGC:c:p:"); 544 while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) { 545 if (PL_OPT_BAD == os) { 546 continue; 547 } 548 switch (opt->option) { 549 case 0: 550 server_name = opt->value; 551 break; 552 case 'd': /* debug mode */ 553 if (verbosity < noisy) { 554 verbosity = ChangeVerbosity(verbosity, 1); 555 } 556 break; 557 case 'q': /* debug mode */ 558 if (verbosity > silent) { 559 verbosity = ChangeVerbosity(verbosity, -1); 560 } 561 break; 562 case 'G': /* use global threads */ 563 thread_scope = PR_GLOBAL_THREAD; 564 break; 565 case 'C': /* number of threads waiting */ 566 major_iterations = atoi(opt->value); 567 break; 568 case 'c': /* number of client threads */ 569 minor_iterations = atoi(opt->value); 570 break; 571 case 'p': /* default port */ 572 default_port = atoi(opt->value); 573 break; 574 default: 575 break; 576 } 577 } 578 PL_DestroyOptState(opt); 579 580 logFile = PR_GetSpecialFD(PR_StandardError); 581 identity = PR_GetUniqueIdentity("Dummy"); 582 stubMethods = PR_GetDefaultIOMethods(); 583 584 /* 585 ** The protocol we're going to implement is one where in order to initiate 586 ** a send, the sender must first solicit permission. Therefore, every 587 ** send is really a send - receive - send sequence. 588 */ 589 myMethods = *stubMethods; /* first get the entire batch */ 590 myMethods.accept = MyAccept; /* then override the ones we care about */ 591 myMethods.recv = MyRecv; /* then override the ones we care about */ 592 myMethods.send = MySend; /* then override the ones we care about */ 593 myMethods.close = MyClose; /* then override the ones we care about */ 594 myMethods.poll = MyPoll; /* then override the ones we care about */ 595 596 if (NULL == server_name) 597 rv = PR_InitializeNetAddr(PR_IpAddrLoopback, default_port, &server_address); 598 else { 599 rv = PR_StringToNetAddr(server_name, &server_address); 600 PR_ASSERT(PR_SUCCESS == rv); 601 rv = PR_InitializeNetAddr(PR_IpAddrNull, default_port, &server_address); 602 } 603 PR_ASSERT(PR_SUCCESS == rv); 604 605 socket_noblock.value.non_blocking = PR_TRUE; 606 socket_noblock.option = PR_SockOpt_Nonblocking; 607 socket_nodelay.value.no_delay = PR_TRUE; 608 socket_nodelay.option = PR_SockOpt_NoDelay; 609 610 /* one type w/o layering */ 611 612 while (major_iterations-- > 0) { 613 if (verbosity > silent) { 614 PR_fprintf(logFile, "Beginning non-layered test\n"); 615 } 616 617 client = PR_NewTCPSocket(); 618 PR_ASSERT(NULL != client); 619 service = PR_NewTCPSocket(); 620 PR_ASSERT(NULL != service); 621 622 rv = PR_SetSocketOption(client, &socket_noblock); 623 PR_ASSERT(PR_SUCCESS == rv); 624 rv = PR_SetSocketOption(service, &socket_noblock); 625 PR_ASSERT(PR_SUCCESS == rv); 626 rv = PR_SetSocketOption(client, &socket_nodelay); 627 PR_ASSERT(PR_SUCCESS == rv); 628 rv = PR_SetSocketOption(service, &socket_nodelay); 629 PR_ASSERT(PR_SUCCESS == rv); 630 631 rv = PR_InitializeNetAddr(PR_IpAddrAny, default_port, &any_address); 632 PR_ASSERT(PR_SUCCESS == rv); 633 rv = PR_Bind(service, &any_address); 634 PR_ASSERT(PR_SUCCESS == rv); 635 rv = PR_Listen(service, 10); 636 PR_ASSERT(PR_SUCCESS == rv); 637 638 server_thread = 639 PR_CreateThread(PR_USER_THREAD, Server, service, PR_PRIORITY_HIGH, 640 thread_scope, PR_JOINABLE_THREAD, 16 * 1024); 641 PR_ASSERT(NULL != server_thread); 642 643 client_thread = 644 PR_CreateThread(PR_USER_THREAD, Client, client, PR_PRIORITY_NORMAL, 645 thread_scope, PR_JOINABLE_THREAD, 16 * 1024); 646 PR_ASSERT(NULL != client_thread); 647 648 rv = PR_JoinThread(client_thread); 649 PR_ASSERT(PR_SUCCESS == rv); 650 rv = PR_JoinThread(server_thread); 651 PR_ASSERT(PR_SUCCESS == rv); 652 653 rv = PR_Close(client); 654 PR_ASSERT(PR_SUCCESS == rv); 655 rv = PR_Close(service); 656 PR_ASSERT(PR_SUCCESS == rv); 657 if (verbosity > silent) { 658 PR_fprintf(logFile, "Ending non-layered test\n"); 659 } 660 661 /* with layering */ 662 if (verbosity > silent) { 663 PR_fprintf(logFile, "Beginning layered test\n"); 664 } 665 client = PR_NewTCPSocket(); 666 PR_ASSERT(NULL != client); 667 service = PR_NewTCPSocket(); 668 PR_ASSERT(NULL != service); 669 670 rv = PR_SetSocketOption(client, &socket_noblock); 671 PR_ASSERT(PR_SUCCESS == rv); 672 rv = PR_SetSocketOption(service, &socket_noblock); 673 PR_ASSERT(PR_SUCCESS == rv); 674 rv = PR_SetSocketOption(client, &socket_nodelay); 675 PR_ASSERT(PR_SUCCESS == rv); 676 rv = PR_SetSocketOption(service, &socket_nodelay); 677 PR_ASSERT(PR_SUCCESS == rv); 678 679 PushLayer(client); 680 PushLayer(service); 681 682 rv = PR_InitializeNetAddr(PR_IpAddrAny, default_port, &any_address); 683 PR_ASSERT(PR_SUCCESS == rv); 684 rv = PR_Bind(service, &any_address); 685 PR_ASSERT(PR_SUCCESS == rv); 686 rv = PR_Listen(service, 10); 687 PR_ASSERT(PR_SUCCESS == rv); 688 689 server_thread = 690 PR_CreateThread(PR_USER_THREAD, Server, service, PR_PRIORITY_HIGH, 691 thread_scope, PR_JOINABLE_THREAD, 16 * 1024); 692 PR_ASSERT(NULL != server_thread); 693 694 client_thread = 695 PR_CreateThread(PR_USER_THREAD, Client, client, PR_PRIORITY_NORMAL, 696 thread_scope, PR_JOINABLE_THREAD, 16 * 1024); 697 PR_ASSERT(NULL != client_thread); 698 699 rv = PR_JoinThread(client_thread); 700 PR_ASSERT(PR_SUCCESS == rv); 701 rv = PR_JoinThread(server_thread); 702 PR_ASSERT(PR_SUCCESS == rv); 703 704 rv = PR_Close(PopLayer(client)); 705 PR_ASSERT(PR_SUCCESS == rv); 706 rv = PR_Close(PopLayer(service)); 707 PR_ASSERT(PR_SUCCESS == rv); 708 if (verbosity > silent) { 709 PR_fprintf(logFile, "Ending layered test\n"); 710 } 711 } 712 return 0; 713 } /* main */ 714 715 /* nblayer.c */