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