1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/nsprpub/pr/tests/nblayer.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,675 @@ 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 "prio.h" 1.10 +#include "prmem.h" 1.11 +#include "prprf.h" 1.12 +#include "prlog.h" 1.13 +#include "prerror.h" 1.14 +#include "prnetdb.h" 1.15 +#include "prthread.h" 1.16 + 1.17 +#include "plerror.h" 1.18 +#include "plgetopt.h" 1.19 +#include "prwin16.h" 1.20 + 1.21 +#include <stdlib.h> 1.22 +#include <string.h> 1.23 + 1.24 +/* 1.25 +** Testing layering of I/O 1.26 +** 1.27 +** The layered server 1.28 +** A thread that acts as a server. It creates a TCP listener with a dummy 1.29 +** layer pushed on top. Then listens for incoming connections. Each connection 1.30 +** request for connection will be layered as well, accept one request, echo 1.31 +** it back and close. 1.32 +** 1.33 +** The layered client 1.34 +** Pretty much what you'd expect. 1.35 +*/ 1.36 + 1.37 +static PRFileDesc *logFile; 1.38 +static PRDescIdentity identity; 1.39 +static PRNetAddr server_address; 1.40 + 1.41 +static PRIOMethods myMethods; 1.42 + 1.43 +typedef enum {rcv_get_debit, rcv_send_credit, rcv_data} RcvState; 1.44 +typedef enum {xmt_send_debit, xmt_recv_credit, xmt_data} XmtState; 1.45 + 1.46 +struct PRFilePrivate 1.47 +{ 1.48 + RcvState rcvstate; 1.49 + XmtState xmtstate; 1.50 + PRInt32 rcvreq, rcvinprogress; 1.51 + PRInt32 xmtreq, xmtinprogress; 1.52 +}; 1.53 + 1.54 +typedef enum Verbosity {silent, quiet, chatty, noisy} Verbosity; 1.55 + 1.56 +static PRIntn minor_iterations = 5; 1.57 +static PRIntn major_iterations = 1; 1.58 +static Verbosity verbosity = quiet; 1.59 +static PRUint16 default_port = 12273; 1.60 + 1.61 +static PRFileDesc *PushLayer(PRFileDesc *stack) 1.62 +{ 1.63 + PRStatus rv; 1.64 + PRFileDesc *layer = PR_CreateIOLayerStub(identity, &myMethods); 1.65 + layer->secret = PR_NEWZAP(PRFilePrivate); 1.66 + rv = PR_PushIOLayer(stack, PR_GetLayersIdentity(stack), layer); 1.67 + PR_ASSERT(PR_SUCCESS == rv); 1.68 + if (verbosity > quiet) 1.69 + PR_fprintf(logFile, "Pushed layer(0x%x) onto stack(0x%x)\n", layer, stack); 1.70 + return stack; 1.71 +} /* PushLayer */ 1.72 + 1.73 +static PRFileDesc *PopLayer(PRFileDesc *stack) 1.74 +{ 1.75 + PRFileDesc *popped = PR_PopIOLayer(stack, identity); 1.76 + if (verbosity > quiet) 1.77 + PR_fprintf(logFile, "Popped layer(0x%x) from stack(0x%x)\n", popped, stack); 1.78 + PR_DELETE(popped->secret); 1.79 + popped->dtor(popped); 1.80 + return stack; 1.81 +} /* PopLayer */ 1.82 + 1.83 +static void PR_CALLBACK Client(void *arg) 1.84 +{ 1.85 + PRStatus rv; 1.86 + PRIntn mits; 1.87 + PRInt32 ready; 1.88 + PRUint8 buffer[100]; 1.89 + PRPollDesc polldesc; 1.90 + PRIntn empty_flags = 0; 1.91 + PRIntn bytes_read, bytes_sent; 1.92 + PRFileDesc *stack = (PRFileDesc*)arg; 1.93 + 1.94 + /* Initialize the buffer so that Purify won't complain */ 1.95 + memset(buffer, 0, sizeof(buffer)); 1.96 + 1.97 + rv = PR_Connect(stack, &server_address, PR_INTERVAL_NO_TIMEOUT); 1.98 + if ((PR_FAILURE == rv) && (PR_IN_PROGRESS_ERROR == PR_GetError())) 1.99 + { 1.100 + if (verbosity > quiet) 1.101 + PR_fprintf(logFile, "Client connect 'in progress'\n"); 1.102 + do 1.103 + { 1.104 + polldesc.fd = stack; 1.105 + polldesc.out_flags = 0; 1.106 + polldesc.in_flags = PR_POLL_WRITE | PR_POLL_EXCEPT; 1.107 + ready = PR_Poll(&polldesc, 1, PR_INTERVAL_NO_TIMEOUT); 1.108 + if ((1 != ready) /* if not 1, then we're dead */ 1.109 + || (0 == (polldesc.in_flags & polldesc.out_flags))) 1.110 + { PR_ASSERT(!"Whoa!"); break; } 1.111 + if (verbosity > quiet) 1.112 + PR_fprintf( 1.113 + logFile, "Client connect 'in progress' [0x%x]\n", 1.114 + polldesc.out_flags); 1.115 + rv = PR_GetConnectStatus(&polldesc); 1.116 + if ((PR_FAILURE == rv) 1.117 + && (PR_IN_PROGRESS_ERROR != PR_GetError())) break; 1.118 + } while (PR_FAILURE == rv); 1.119 + } 1.120 + PR_ASSERT(PR_SUCCESS == rv); 1.121 + if (verbosity > chatty) 1.122 + PR_fprintf(logFile, "Client created connection\n"); 1.123 + 1.124 + for (mits = 0; mits < minor_iterations; ++mits) 1.125 + { 1.126 + bytes_sent = 0; 1.127 + if (verbosity > quiet) 1.128 + PR_fprintf(logFile, "Client sending %d bytes\n", sizeof(buffer)); 1.129 + do 1.130 + { 1.131 + if (verbosity > chatty) 1.132 + PR_fprintf( 1.133 + logFile, "Client sending %d bytes\n", 1.134 + sizeof(buffer) - bytes_sent); 1.135 + ready = PR_Send( 1.136 + stack, buffer + bytes_sent, sizeof(buffer) - bytes_sent, 1.137 + empty_flags, PR_INTERVAL_NO_TIMEOUT); 1.138 + if (verbosity > chatty) 1.139 + PR_fprintf(logFile, "Client send status [%d]\n", ready); 1.140 + if (0 < ready) bytes_sent += ready; 1.141 + else if ((-1 == ready) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) 1.142 + { 1.143 + polldesc.fd = stack; 1.144 + polldesc.out_flags = 0; 1.145 + polldesc.in_flags = PR_POLL_WRITE; 1.146 + ready = PR_Poll(&polldesc, 1, PR_INTERVAL_NO_TIMEOUT); 1.147 + if ((1 != ready) /* if not 1, then we're dead */ 1.148 + || (0 == (polldesc.in_flags & polldesc.out_flags))) 1.149 + { PR_ASSERT(!"Whoa!"); break; } 1.150 + } 1.151 + else break; 1.152 + } while (bytes_sent < sizeof(buffer)); 1.153 + PR_ASSERT(sizeof(buffer) == bytes_sent); 1.154 + 1.155 + bytes_read = 0; 1.156 + do 1.157 + { 1.158 + if (verbosity > chatty) 1.159 + PR_fprintf( 1.160 + logFile, "Client receiving %d bytes\n", 1.161 + bytes_sent - bytes_read); 1.162 + ready = PR_Recv( 1.163 + stack, buffer + bytes_read, bytes_sent - bytes_read, 1.164 + empty_flags, PR_INTERVAL_NO_TIMEOUT); 1.165 + if (verbosity > chatty) 1.166 + PR_fprintf( 1.167 + logFile, "Client receive status [%d]\n", ready); 1.168 + if (0 < ready) bytes_read += ready; 1.169 + else if ((-1 == ready) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) 1.170 + { 1.171 + polldesc.fd = stack; 1.172 + polldesc.out_flags = 0; 1.173 + polldesc.in_flags = PR_POLL_READ; 1.174 + ready = PR_Poll(&polldesc, 1, PR_INTERVAL_NO_TIMEOUT); 1.175 + if ((1 != ready) /* if not 1, then we're dead */ 1.176 + || (0 == (polldesc.in_flags & polldesc.out_flags))) 1.177 + { PR_ASSERT(!"Whoa!"); break; } 1.178 + } 1.179 + else break; 1.180 + } while (bytes_read < bytes_sent); 1.181 + if (verbosity > chatty) 1.182 + PR_fprintf(logFile, "Client received %d bytes\n", bytes_read); 1.183 + PR_ASSERT(bytes_read == bytes_sent); 1.184 + } 1.185 + 1.186 + if (verbosity > quiet) 1.187 + PR_fprintf(logFile, "Client shutting down stack\n"); 1.188 + 1.189 + rv = PR_Shutdown(stack, PR_SHUTDOWN_BOTH); PR_ASSERT(PR_SUCCESS == rv); 1.190 +} /* Client */ 1.191 + 1.192 +static void PR_CALLBACK Server(void *arg) 1.193 +{ 1.194 + PRStatus rv; 1.195 + PRInt32 ready; 1.196 + PRUint8 buffer[100]; 1.197 + PRFileDesc *service; 1.198 + PRUintn empty_flags = 0; 1.199 + struct PRPollDesc polldesc; 1.200 + PRIntn bytes_read, bytes_sent; 1.201 + PRFileDesc *stack = (PRFileDesc*)arg; 1.202 + PRNetAddr client_address; 1.203 + 1.204 + do 1.205 + { 1.206 + if (verbosity > chatty) 1.207 + PR_fprintf(logFile, "Server accepting connection\n"); 1.208 + service = PR_Accept(stack, &client_address, PR_INTERVAL_NO_TIMEOUT); 1.209 + if (verbosity > chatty) 1.210 + PR_fprintf(logFile, "Server accept status [0x%p]\n", service); 1.211 + if ((NULL == service) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) 1.212 + { 1.213 + polldesc.fd = stack; 1.214 + polldesc.out_flags = 0; 1.215 + polldesc.in_flags = PR_POLL_READ | PR_POLL_EXCEPT; 1.216 + ready = PR_Poll(&polldesc, 1, PR_INTERVAL_NO_TIMEOUT); 1.217 + if ((1 != ready) /* if not 1, then we're dead */ 1.218 + || (0 == (polldesc.in_flags & polldesc.out_flags))) 1.219 + { PR_ASSERT(!"Whoa!"); break; } 1.220 + } 1.221 + } while (NULL == service); 1.222 + PR_ASSERT(NULL != service); 1.223 + 1.224 + if (verbosity > quiet) 1.225 + PR_fprintf(logFile, "Server accepting connection\n"); 1.226 + 1.227 + do 1.228 + { 1.229 + bytes_read = 0; 1.230 + do 1.231 + { 1.232 + if (verbosity > chatty) 1.233 + PR_fprintf( 1.234 + logFile, "Server receiving %d bytes\n", 1.235 + sizeof(buffer) - bytes_read); 1.236 + ready = PR_Recv( 1.237 + service, buffer + bytes_read, sizeof(buffer) - bytes_read, 1.238 + empty_flags, PR_INTERVAL_NO_TIMEOUT); 1.239 + if (verbosity > chatty) 1.240 + PR_fprintf(logFile, "Server receive status [%d]\n", ready); 1.241 + if (0 < ready) bytes_read += ready; 1.242 + else if ((-1 == ready) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) 1.243 + { 1.244 + polldesc.fd = service; 1.245 + polldesc.out_flags = 0; 1.246 + polldesc.in_flags = PR_POLL_READ; 1.247 + ready = PR_Poll(&polldesc, 1, PR_INTERVAL_NO_TIMEOUT); 1.248 + if ((1 != ready) /* if not 1, then we're dead */ 1.249 + || (0 == (polldesc.in_flags & polldesc.out_flags))) 1.250 + { PR_ASSERT(!"Whoa!"); break; } 1.251 + } 1.252 + else break; 1.253 + } while (bytes_read < sizeof(buffer)); 1.254 + 1.255 + if (0 != bytes_read) 1.256 + { 1.257 + if (verbosity > chatty) 1.258 + PR_fprintf(logFile, "Server received %d bytes\n", bytes_read); 1.259 + PR_ASSERT(bytes_read > 0); 1.260 + 1.261 + bytes_sent = 0; 1.262 + do 1.263 + { 1.264 + ready = PR_Send( 1.265 + service, buffer + bytes_sent, bytes_read - bytes_sent, 1.266 + empty_flags, PR_INTERVAL_NO_TIMEOUT); 1.267 + if (0 < ready) 1.268 + { 1.269 + bytes_sent += ready; 1.270 + } 1.271 + else if ((-1 == ready) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) 1.272 + { 1.273 + polldesc.fd = service; 1.274 + polldesc.out_flags = 0; 1.275 + polldesc.in_flags = PR_POLL_WRITE; 1.276 + ready = PR_Poll(&polldesc, 1, PR_INTERVAL_NO_TIMEOUT); 1.277 + if ((1 != ready) /* if not 1, then we're dead */ 1.278 + || (0 == (polldesc.in_flags & polldesc.out_flags))) 1.279 + { PR_ASSERT(!"Whoa!"); break; } 1.280 + } 1.281 + else break; 1.282 + } while (bytes_sent < bytes_read); 1.283 + PR_ASSERT(bytes_read == bytes_sent); 1.284 + if (verbosity > chatty) 1.285 + PR_fprintf(logFile, "Server sent %d bytes\n", bytes_sent); 1.286 + } 1.287 + } while (0 != bytes_read); 1.288 + 1.289 + if (verbosity > quiet) 1.290 + PR_fprintf(logFile, "Server shutting down stack\n"); 1.291 + rv = PR_Shutdown(service, PR_SHUTDOWN_BOTH); PR_ASSERT(PR_SUCCESS == rv); 1.292 + rv = PR_Close(service); PR_ASSERT(PR_SUCCESS == rv); 1.293 + 1.294 +} /* Server */ 1.295 + 1.296 +static PRStatus PR_CALLBACK MyClose(PRFileDesc *fd) 1.297 +{ 1.298 + PR_DELETE(fd->secret); /* manage my secret file object */ 1.299 + return (PR_GetDefaultIOMethods())->close(fd); /* let him do all the work */ 1.300 +} /* MyClose */ 1.301 + 1.302 +static PRInt16 PR_CALLBACK MyPoll( 1.303 + PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags) 1.304 +{ 1.305 + PRInt16 my_flags, new_flags; 1.306 + PRFilePrivate *mine = (PRFilePrivate*)fd->secret; 1.307 + if (0 != (PR_POLL_READ & in_flags)) 1.308 + { 1.309 + /* client thinks he's reading */ 1.310 + switch (mine->rcvstate) 1.311 + { 1.312 + case rcv_send_credit: 1.313 + my_flags = (in_flags & ~PR_POLL_READ) | PR_POLL_WRITE; 1.314 + break; 1.315 + case rcv_data: 1.316 + case rcv_get_debit: 1.317 + my_flags = in_flags; 1.318 + default: break; 1.319 + } 1.320 + } 1.321 + else if (0 != (PR_POLL_WRITE & in_flags)) 1.322 + { 1.323 + /* client thinks he's writing */ 1.324 + switch (mine->xmtstate) 1.325 + { 1.326 + case xmt_recv_credit: 1.327 + my_flags = (in_flags & ~PR_POLL_WRITE) | PR_POLL_READ; 1.328 + break; 1.329 + case xmt_send_debit: 1.330 + case xmt_data: 1.331 + my_flags = in_flags; 1.332 + default: break; 1.333 + } 1.334 + } 1.335 + else PR_ASSERT(!"How'd I get here?"); 1.336 + new_flags = (fd->lower->methods->poll)(fd->lower, my_flags, out_flags); 1.337 + if (verbosity > chatty) 1.338 + PR_fprintf( 1.339 + logFile, "Poll [i: 0x%x, m: 0x%x, o: 0x%x, n: 0x%x]\n", 1.340 + in_flags, my_flags, *out_flags, new_flags); 1.341 + return new_flags; 1.342 +} /* MyPoll */ 1.343 + 1.344 +static PRFileDesc * PR_CALLBACK MyAccept( 1.345 + PRFileDesc *fd, PRNetAddr *addr, PRIntervalTime timeout) 1.346 +{ 1.347 + PRStatus rv; 1.348 + PRFileDesc *newfd, *layer = fd; 1.349 + PRFileDesc *newstack; 1.350 + PRFilePrivate *newsecret; 1.351 + 1.352 + PR_ASSERT(fd != NULL); 1.353 + PR_ASSERT(fd->lower != NULL); 1.354 + 1.355 + newstack = PR_NEW(PRFileDesc); 1.356 + if (NULL == newstack) 1.357 + { 1.358 + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); 1.359 + return NULL; 1.360 + } 1.361 + newsecret = PR_NEW(PRFilePrivate); 1.362 + if (NULL == newsecret) 1.363 + { 1.364 + PR_DELETE(newstack); 1.365 + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); 1.366 + return NULL; 1.367 + } 1.368 + *newstack = *fd; /* make a copy of the accepting layer */ 1.369 + *newsecret = *fd->secret; 1.370 + newstack->secret = newsecret; 1.371 + 1.372 + newfd = (fd->lower->methods->accept)(fd->lower, addr, timeout); 1.373 + if (NULL == newfd) 1.374 + { 1.375 + PR_DELETE(newsecret); 1.376 + PR_DELETE(newstack); 1.377 + return NULL; 1.378 + } 1.379 + 1.380 + /* this PR_PushIOLayer call cannot fail */ 1.381 + rv = PR_PushIOLayer(newfd, PR_TOP_IO_LAYER, newstack); 1.382 + PR_ASSERT(PR_SUCCESS == rv); 1.383 + return newfd; /* that's it */ 1.384 +} 1.385 + 1.386 +static PRInt32 PR_CALLBACK MyRecv( 1.387 + PRFileDesc *fd, void *buf, PRInt32 amount, 1.388 + PRIntn flags, PRIntervalTime timeout) 1.389 +{ 1.390 + char *b; 1.391 + PRInt32 rv; 1.392 + PRFileDesc *lo = fd->lower; 1.393 + PRFilePrivate *mine = (PRFilePrivate*)fd->secret; 1.394 + 1.395 + do 1.396 + { 1.397 + switch (mine->rcvstate) 1.398 + { 1.399 + case rcv_get_debit: 1.400 + b = (char*)&mine->rcvreq; 1.401 + mine->rcvreq = amount; 1.402 + rv = lo->methods->recv( 1.403 + lo, b + mine->rcvinprogress, 1.404 + sizeof(mine->rcvreq) - mine->rcvinprogress, flags, timeout); 1.405 + if (0 == rv) goto closed; 1.406 + if ((-1 == rv) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) break; 1.407 + mine->rcvinprogress += rv; /* accumulate the read */ 1.408 + if (mine->rcvinprogress < sizeof(mine->rcvreq)) break; /* loop */ 1.409 + mine->rcvstate = rcv_send_credit; 1.410 + mine->rcvinprogress = 0; 1.411 + case rcv_send_credit: 1.412 + b = (char*)&mine->rcvreq; 1.413 + rv = lo->methods->send( 1.414 + lo, b + mine->rcvinprogress, 1.415 + sizeof(mine->rcvreq) - mine->rcvinprogress, flags, timeout); 1.416 + if ((-1 == rv) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) break; 1.417 + mine->rcvinprogress += rv; /* accumulate the read */ 1.418 + if (mine->rcvinprogress < sizeof(mine->rcvreq)) break; /* loop */ 1.419 + mine->rcvstate = rcv_data; 1.420 + mine->rcvinprogress = 0; 1.421 + case rcv_data: 1.422 + b = (char*)buf; 1.423 + rv = lo->methods->recv( 1.424 + lo, b + mine->rcvinprogress, 1.425 + mine->rcvreq - mine->rcvinprogress, flags, timeout); 1.426 + if (0 == rv) goto closed; 1.427 + if ((-1 == rv) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) break; 1.428 + mine->rcvinprogress += rv; /* accumulate the read */ 1.429 + if (mine->rcvinprogress < amount) break; /* loop */ 1.430 + mine->rcvstate = rcv_get_debit; 1.431 + mine->rcvinprogress = 0; 1.432 + return mine->rcvreq; /* << -- that's it! */ 1.433 + default: 1.434 + break; 1.435 + } 1.436 + } while (-1 != rv); 1.437 + return rv; 1.438 +closed: 1.439 + mine->rcvinprogress = 0; 1.440 + mine->rcvstate = rcv_get_debit; 1.441 + return 0; 1.442 +} /* MyRecv */ 1.443 + 1.444 +static PRInt32 PR_CALLBACK MySend( 1.445 + PRFileDesc *fd, const void *buf, PRInt32 amount, 1.446 + PRIntn flags, PRIntervalTime timeout) 1.447 +{ 1.448 + char *b; 1.449 + PRInt32 rv; 1.450 + PRFileDesc *lo = fd->lower; 1.451 + PRFilePrivate *mine = (PRFilePrivate*)fd->secret; 1.452 + 1.453 + do 1.454 + { 1.455 + switch (mine->xmtstate) 1.456 + { 1.457 + case xmt_send_debit: 1.458 + b = (char*)&mine->xmtreq; 1.459 + mine->xmtreq = amount; 1.460 + rv = lo->methods->send( 1.461 + lo, b - mine->xmtinprogress, 1.462 + sizeof(mine->xmtreq) - mine->xmtinprogress, flags, timeout); 1.463 + if ((-1 == rv) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) break; 1.464 + mine->xmtinprogress += rv; 1.465 + if (mine->xmtinprogress < sizeof(mine->xmtreq)) break; 1.466 + mine->xmtstate = xmt_recv_credit; 1.467 + mine->xmtinprogress = 0; 1.468 + case xmt_recv_credit: 1.469 + b = (char*)&mine->xmtreq; 1.470 + rv = lo->methods->recv( 1.471 + lo, b + mine->xmtinprogress, 1.472 + sizeof(mine->xmtreq) - mine->xmtinprogress, flags, timeout); 1.473 + if ((-1 == rv) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) break; 1.474 + mine->xmtinprogress += rv; 1.475 + if (mine->xmtinprogress < sizeof(mine->xmtreq)) break; 1.476 + mine->xmtstate = xmt_data; 1.477 + mine->xmtinprogress = 0; 1.478 + case xmt_data: 1.479 + b = (char*)buf; 1.480 + rv = lo->methods->send( 1.481 + lo, b + mine->xmtinprogress, 1.482 + mine->xmtreq - mine->xmtinprogress, flags, timeout); 1.483 + if ((-1 == rv) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) break; 1.484 + mine->xmtinprogress += rv; 1.485 + if (mine->xmtinprogress < amount) break; 1.486 + mine->xmtstate = xmt_send_debit; 1.487 + mine->xmtinprogress = 0; 1.488 + return mine->xmtreq; /* <<-- That's the one! */ 1.489 + default: 1.490 + break; 1.491 + } 1.492 + } while (-1 != rv); 1.493 + return rv; 1.494 +} /* MySend */ 1.495 + 1.496 +static Verbosity ChangeVerbosity(Verbosity verbosity, PRIntn delta) 1.497 +{ 1.498 + PRIntn verbage = (PRIntn)verbosity + delta; 1.499 + if (verbage < (PRIntn)silent) verbage = (PRIntn)silent; 1.500 + else if (verbage > (PRIntn)noisy) verbage = (PRIntn)noisy; 1.501 + return (Verbosity)verbage; 1.502 +} /* ChangeVerbosity */ 1.503 + 1.504 +int main(int argc, char **argv) 1.505 +{ 1.506 + PRStatus rv; 1.507 + PLOptStatus os; 1.508 + PRFileDesc *client, *service; 1.509 + PRNetAddr any_address; 1.510 + const char *server_name = NULL; 1.511 + const PRIOMethods *stubMethods; 1.512 + PRThread *client_thread, *server_thread; 1.513 + PRThreadScope thread_scope = PR_LOCAL_THREAD; 1.514 + PRSocketOptionData socket_noblock, socket_nodelay; 1.515 + PLOptState *opt = PL_CreateOptState(argc, argv, "dqGC:c:p:"); 1.516 + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) 1.517 + { 1.518 + if (PL_OPT_BAD == os) continue; 1.519 + switch (opt->option) 1.520 + { 1.521 + case 0: 1.522 + server_name = opt->value; 1.523 + break; 1.524 + case 'd': /* debug mode */ 1.525 + if (verbosity < noisy) 1.526 + verbosity = ChangeVerbosity(verbosity, 1); 1.527 + break; 1.528 + case 'q': /* debug mode */ 1.529 + if (verbosity > silent) 1.530 + verbosity = ChangeVerbosity(verbosity, -1); 1.531 + break; 1.532 + case 'G': /* use global threads */ 1.533 + thread_scope = PR_GLOBAL_THREAD; 1.534 + break; 1.535 + case 'C': /* number of threads waiting */ 1.536 + major_iterations = atoi(opt->value); 1.537 + break; 1.538 + case 'c': /* number of client threads */ 1.539 + minor_iterations = atoi(opt->value); 1.540 + break; 1.541 + case 'p': /* default port */ 1.542 + default_port = atoi(opt->value); 1.543 + break; 1.544 + default: 1.545 + break; 1.546 + } 1.547 + } 1.548 + PL_DestroyOptState(opt); 1.549 + PR_STDIO_INIT(); 1.550 + 1.551 + logFile = PR_GetSpecialFD(PR_StandardError); 1.552 + identity = PR_GetUniqueIdentity("Dummy"); 1.553 + stubMethods = PR_GetDefaultIOMethods(); 1.554 + 1.555 + /* 1.556 + ** The protocol we're going to implement is one where in order to initiate 1.557 + ** a send, the sender must first solicit permission. Therefore, every 1.558 + ** send is really a send - receive - send sequence. 1.559 + */ 1.560 + myMethods = *stubMethods; /* first get the entire batch */ 1.561 + myMethods.accept = MyAccept; /* then override the ones we care about */ 1.562 + myMethods.recv = MyRecv; /* then override the ones we care about */ 1.563 + myMethods.send = MySend; /* then override the ones we care about */ 1.564 + myMethods.close = MyClose; /* then override the ones we care about */ 1.565 + myMethods.poll = MyPoll; /* then override the ones we care about */ 1.566 + 1.567 + if (NULL == server_name) 1.568 + rv = PR_InitializeNetAddr( 1.569 + PR_IpAddrLoopback, default_port, &server_address); 1.570 + else 1.571 + { 1.572 + rv = PR_StringToNetAddr(server_name, &server_address); 1.573 + PR_ASSERT(PR_SUCCESS == rv); 1.574 + rv = PR_InitializeNetAddr( 1.575 + PR_IpAddrNull, default_port, &server_address); 1.576 + } 1.577 + PR_ASSERT(PR_SUCCESS == rv); 1.578 + 1.579 + socket_noblock.value.non_blocking = PR_TRUE; 1.580 + socket_noblock.option = PR_SockOpt_Nonblocking; 1.581 + socket_nodelay.value.no_delay = PR_TRUE; 1.582 + socket_nodelay.option = PR_SockOpt_NoDelay; 1.583 + 1.584 + /* one type w/o layering */ 1.585 + 1.586 + while (major_iterations-- > 0) 1.587 + { 1.588 + if (verbosity > silent) 1.589 + PR_fprintf(logFile, "Beginning non-layered test\n"); 1.590 + 1.591 + client = PR_NewTCPSocket(); PR_ASSERT(NULL != client); 1.592 + service = PR_NewTCPSocket(); PR_ASSERT(NULL != service); 1.593 + 1.594 + rv = PR_SetSocketOption(client, &socket_noblock); 1.595 + PR_ASSERT(PR_SUCCESS == rv); 1.596 + rv = PR_SetSocketOption(service, &socket_noblock); 1.597 + PR_ASSERT(PR_SUCCESS == rv); 1.598 + rv = PR_SetSocketOption(client, &socket_nodelay); 1.599 + PR_ASSERT(PR_SUCCESS == rv); 1.600 + rv = PR_SetSocketOption(service, &socket_nodelay); 1.601 + PR_ASSERT(PR_SUCCESS == rv); 1.602 + 1.603 + rv = PR_InitializeNetAddr(PR_IpAddrAny, default_port, &any_address); 1.604 + PR_ASSERT(PR_SUCCESS == rv); 1.605 + rv = PR_Bind(service, &any_address); PR_ASSERT(PR_SUCCESS == rv); 1.606 + rv = PR_Listen(service, 10); PR_ASSERT(PR_SUCCESS == rv); 1.607 + 1.608 + server_thread = PR_CreateThread( 1.609 + PR_USER_THREAD, Server, service, 1.610 + PR_PRIORITY_HIGH, thread_scope, 1.611 + PR_JOINABLE_THREAD, 16 * 1024); 1.612 + PR_ASSERT(NULL != server_thread); 1.613 + 1.614 + client_thread = PR_CreateThread( 1.615 + PR_USER_THREAD, Client, client, 1.616 + PR_PRIORITY_NORMAL, thread_scope, 1.617 + PR_JOINABLE_THREAD, 16 * 1024); 1.618 + PR_ASSERT(NULL != client_thread); 1.619 + 1.620 + rv = PR_JoinThread(client_thread); 1.621 + PR_ASSERT(PR_SUCCESS == rv); 1.622 + rv = PR_JoinThread(server_thread); 1.623 + PR_ASSERT(PR_SUCCESS == rv); 1.624 + 1.625 + rv = PR_Close(client); PR_ASSERT(PR_SUCCESS == rv); 1.626 + rv = PR_Close(service); PR_ASSERT(PR_SUCCESS == rv); 1.627 + if (verbosity > silent) 1.628 + PR_fprintf(logFile, "Ending non-layered test\n"); 1.629 + 1.630 + /* with layering */ 1.631 + if (verbosity > silent) 1.632 + PR_fprintf(logFile, "Beginning layered test\n"); 1.633 + client = PR_NewTCPSocket(); PR_ASSERT(NULL != client); 1.634 + service = PR_NewTCPSocket(); PR_ASSERT(NULL != service); 1.635 + 1.636 + rv = PR_SetSocketOption(client, &socket_noblock); 1.637 + PR_ASSERT(PR_SUCCESS == rv); 1.638 + rv = PR_SetSocketOption(service, &socket_noblock); 1.639 + PR_ASSERT(PR_SUCCESS == rv); 1.640 + rv = PR_SetSocketOption(client, &socket_nodelay); 1.641 + PR_ASSERT(PR_SUCCESS == rv); 1.642 + rv = PR_SetSocketOption(service, &socket_nodelay); 1.643 + PR_ASSERT(PR_SUCCESS == rv); 1.644 + 1.645 + PushLayer(client); 1.646 + PushLayer(service); 1.647 + 1.648 + rv = PR_InitializeNetAddr(PR_IpAddrAny, default_port, &any_address); 1.649 + PR_ASSERT(PR_SUCCESS == rv); 1.650 + rv = PR_Bind(service, &any_address); PR_ASSERT(PR_SUCCESS == rv); 1.651 + rv = PR_Listen(service, 10); PR_ASSERT(PR_SUCCESS == rv); 1.652 + 1.653 + server_thread = PR_CreateThread( 1.654 + PR_USER_THREAD, Server, service, 1.655 + PR_PRIORITY_HIGH, thread_scope, 1.656 + PR_JOINABLE_THREAD, 16 * 1024); 1.657 + PR_ASSERT(NULL != server_thread); 1.658 + 1.659 + client_thread = PR_CreateThread( 1.660 + PR_USER_THREAD, Client, client, 1.661 + PR_PRIORITY_NORMAL, thread_scope, 1.662 + PR_JOINABLE_THREAD, 16 * 1024); 1.663 + PR_ASSERT(NULL != client_thread); 1.664 + 1.665 + rv = PR_JoinThread(client_thread); 1.666 + PR_ASSERT(PR_SUCCESS == rv); 1.667 + rv = PR_JoinThread(server_thread); 1.668 + PR_ASSERT(PR_SUCCESS == rv); 1.669 + 1.670 + rv = PR_Close(PopLayer(client)); PR_ASSERT(PR_SUCCESS == rv); 1.671 + rv = PR_Close(PopLayer(service)); PR_ASSERT(PR_SUCCESS == rv); 1.672 + if (verbosity > silent) 1.673 + PR_fprintf(logFile, "Ending layered test\n"); 1.674 + } 1.675 + return 0; 1.676 +} /* main */ 1.677 + 1.678 +/* nblayer.c */