nsprpub/pr/tests/nblayer.c

Wed, 31 Dec 2014 07:53:36 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:53:36 +0100
branch
TOR_BUG_3246
changeset 5
4ab42b5ab56c
permissions
-rw-r--r--

Correct small whitespace inconsistency, lost while renaming variables.

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

mercurial