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/. */
22 ** Testing layering of I/O
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
31 ** Pretty much what you'd expect.
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
;
47 PRInt32 rcvreq
, rcvinprogress
;
48 PRInt32 xmtreq
, xmtinprogress
;
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
;
58 #define PORT_INC_DO +100
63 #define PORT_INC_3264 +200
68 static PRUint16 default_port
= 12273 PORT_INC_DO PORT_INC_3264
;
70 static PRFileDesc
*PushLayer(PRFileDesc
*stack
)
73 PRFileDesc
*layer
= PR_CreateIOLayerStub(identity
, &myMethods
);
74 layer
->secret
= PR_NEWZAP(PRFilePrivate
);
75 rv
= PR_PushIOLayer(stack
, PR_GetLayersIdentity(stack
), layer
);
76 PR_ASSERT(PR_SUCCESS
== rv
);
77 if (verbosity
> quiet
) {
78 PR_fprintf(logFile
, "Pushed layer(0x%x) onto stack(0x%x)\n", layer
, stack
);
83 static PRFileDesc
*PopLayer(PRFileDesc
*stack
)
85 PRFileDesc
*popped
= PR_PopIOLayer(stack
, identity
);
86 if (verbosity
> quiet
) {
87 PR_fprintf(logFile
, "Popped layer(0x%x) from stack(0x%x)\n", popped
, stack
);
89 PR_DELETE(popped
->secret
);
94 static void PR_CALLBACK
Client(void *arg
)
101 PRIntn empty_flags
= 0;
102 PRIntn bytes_read
, bytes_sent
;
103 PRFileDesc
*stack
= (PRFileDesc
*)arg
;
105 /* Initialize the buffer so that Purify won't complain */
106 memset(buffer
, 0, sizeof(buffer
));
108 rv
= PR_Connect(stack
, &server_address
, PR_INTERVAL_NO_TIMEOUT
);
109 if ((PR_FAILURE
== rv
) && (PR_IN_PROGRESS_ERROR
== PR_GetError()))
111 if (verbosity
> quiet
) {
112 PR_fprintf(logFile
, "Client connect 'in progress'\n");
117 polldesc
.out_flags
= 0;
118 polldesc
.in_flags
= PR_POLL_WRITE
| PR_POLL_EXCEPT
;
119 ready
= PR_Poll(&polldesc
, 1, PR_INTERVAL_NO_TIMEOUT
);
120 if ((1 != ready
) /* if not 1, then we're dead */
121 || (0 == (polldesc
.in_flags
& polldesc
.out_flags
)))
123 PR_NOT_REACHED("Whoa!");
126 if (verbosity
> quiet
)
128 logFile
, "Client connect 'in progress' [0x%x]\n",
130 rv
= PR_GetConnectStatus(&polldesc
);
131 if ((PR_FAILURE
== rv
)
132 && (PR_IN_PROGRESS_ERROR
!= PR_GetError())) {
135 } while (PR_FAILURE
== rv
);
137 PR_ASSERT(PR_SUCCESS
== rv
);
138 if (verbosity
> chatty
) {
139 PR_fprintf(logFile
, "Client created connection\n");
142 for (mits
= 0; mits
< minor_iterations
; ++mits
)
145 if (verbosity
> quiet
) {
146 PR_fprintf(logFile
, "Client sending %d bytes\n", sizeof(buffer
));
150 if (verbosity
> chatty
)
152 logFile
, "Client sending %d bytes\n",
153 sizeof(buffer
) - bytes_sent
);
155 stack
, buffer
+ bytes_sent
, sizeof(buffer
) - bytes_sent
,
156 empty_flags
, PR_INTERVAL_NO_TIMEOUT
);
157 if (verbosity
> chatty
) {
158 PR_fprintf(logFile
, "Client send status [%d]\n", ready
);
163 else if ((-1 == ready
) && (PR_WOULD_BLOCK_ERROR
== PR_GetError()))
166 polldesc
.out_flags
= 0;
167 polldesc
.in_flags
= PR_POLL_WRITE
;
168 ready
= PR_Poll(&polldesc
, 1, PR_INTERVAL_NO_TIMEOUT
);
169 if ((1 != ready
) /* if not 1, then we're dead */
170 || (0 == (polldesc
.in_flags
& polldesc
.out_flags
)))
172 PR_NOT_REACHED("Whoa!");
179 } while (bytes_sent
< sizeof(buffer
));
180 PR_ASSERT(sizeof(buffer
) == bytes_sent
);
185 if (verbosity
> chatty
)
187 logFile
, "Client receiving %d bytes\n",
188 bytes_sent
- bytes_read
);
190 stack
, buffer
+ bytes_read
, bytes_sent
- bytes_read
,
191 empty_flags
, PR_INTERVAL_NO_TIMEOUT
);
192 if (verbosity
> chatty
)
194 logFile
, "Client receive status [%d]\n", ready
);
198 else if ((-1 == ready
) && (PR_WOULD_BLOCK_ERROR
== PR_GetError()))
201 polldesc
.out_flags
= 0;
202 polldesc
.in_flags
= PR_POLL_READ
;
203 ready
= PR_Poll(&polldesc
, 1, PR_INTERVAL_NO_TIMEOUT
);
204 if ((1 != ready
) /* if not 1, then we're dead */
205 || (0 == (polldesc
.in_flags
& polldesc
.out_flags
)))
207 PR_NOT_REACHED("Whoa!");
214 } while (bytes_read
< bytes_sent
);
215 if (verbosity
> chatty
) {
216 PR_fprintf(logFile
, "Client received %d bytes\n", bytes_read
);
218 PR_ASSERT(bytes_read
== bytes_sent
);
221 if (verbosity
> quiet
) {
222 PR_fprintf(logFile
, "Client shutting down stack\n");
225 rv
= PR_Shutdown(stack
, PR_SHUTDOWN_BOTH
); PR_ASSERT(PR_SUCCESS
== rv
);
228 static void PR_CALLBACK
Server(void *arg
)
234 PRUintn empty_flags
= 0;
235 struct PRPollDesc polldesc
;
236 PRIntn bytes_read
, bytes_sent
;
237 PRFileDesc
*stack
= (PRFileDesc
*)arg
;
238 PRNetAddr client_address
;
242 if (verbosity
> chatty
) {
243 PR_fprintf(logFile
, "Server accepting connection\n");
245 service
= PR_Accept(stack
, &client_address
, PR_INTERVAL_NO_TIMEOUT
);
246 if (verbosity
> chatty
) {
247 PR_fprintf(logFile
, "Server accept status [0x%p]\n", service
);
249 if ((NULL
== service
) && (PR_WOULD_BLOCK_ERROR
== PR_GetError()))
252 polldesc
.out_flags
= 0;
253 polldesc
.in_flags
= PR_POLL_READ
| PR_POLL_EXCEPT
;
254 ready
= PR_Poll(&polldesc
, 1, PR_INTERVAL_NO_TIMEOUT
);
255 if ((1 != ready
) /* if not 1, then we're dead */
256 || (0 == (polldesc
.in_flags
& polldesc
.out_flags
)))
258 PR_NOT_REACHED("Whoa!");
262 } while (NULL
== service
);
263 PR_ASSERT(NULL
!= service
);
265 if (verbosity
> quiet
) {
266 PR_fprintf(logFile
, "Server accepting connection\n");
274 if (verbosity
> chatty
)
276 logFile
, "Server receiving %d bytes\n",
277 sizeof(buffer
) - bytes_read
);
279 service
, buffer
+ bytes_read
, sizeof(buffer
) - bytes_read
,
280 empty_flags
, PR_INTERVAL_NO_TIMEOUT
);
281 if (verbosity
> chatty
) {
282 PR_fprintf(logFile
, "Server receive status [%d]\n", ready
);
287 else if ((-1 == ready
) && (PR_WOULD_BLOCK_ERROR
== PR_GetError()))
289 polldesc
.fd
= service
;
290 polldesc
.out_flags
= 0;
291 polldesc
.in_flags
= PR_POLL_READ
;
292 ready
= PR_Poll(&polldesc
, 1, PR_INTERVAL_NO_TIMEOUT
);
293 if ((1 != ready
) /* if not 1, then we're dead */
294 || (0 == (polldesc
.in_flags
& polldesc
.out_flags
)))
296 PR_NOT_REACHED("Whoa!");
303 } while (bytes_read
< sizeof(buffer
));
307 if (verbosity
> chatty
) {
308 PR_fprintf(logFile
, "Server received %d bytes\n", bytes_read
);
310 PR_ASSERT(bytes_read
> 0);
316 service
, buffer
+ bytes_sent
, bytes_read
- bytes_sent
,
317 empty_flags
, PR_INTERVAL_NO_TIMEOUT
);
322 else if ((-1 == ready
) && (PR_WOULD_BLOCK_ERROR
== PR_GetError()))
324 polldesc
.fd
= service
;
325 polldesc
.out_flags
= 0;
326 polldesc
.in_flags
= PR_POLL_WRITE
;
327 ready
= PR_Poll(&polldesc
, 1, PR_INTERVAL_NO_TIMEOUT
);
328 if ((1 != ready
) /* if not 1, then we're dead */
329 || (0 == (polldesc
.in_flags
& polldesc
.out_flags
)))
331 PR_NOT_REACHED("Whoa!");
338 } while (bytes_sent
< bytes_read
);
339 PR_ASSERT(bytes_read
== bytes_sent
);
340 if (verbosity
> chatty
) {
341 PR_fprintf(logFile
, "Server sent %d bytes\n", bytes_sent
);
344 } while (0 != bytes_read
);
346 if (verbosity
> quiet
) {
347 PR_fprintf(logFile
, "Server shutting down stack\n");
349 rv
= PR_Shutdown(service
, PR_SHUTDOWN_BOTH
); PR_ASSERT(PR_SUCCESS
== rv
);
350 rv
= PR_Close(service
); PR_ASSERT(PR_SUCCESS
== rv
);
354 static PRStatus PR_CALLBACK
MyClose(PRFileDesc
*fd
)
356 PR_DELETE(fd
->secret
); /* manage my secret file object */
357 return (PR_GetDefaultIOMethods())->close(fd
); /* let him do all the work */
360 static PRInt16 PR_CALLBACK
MyPoll(
361 PRFileDesc
*fd
, PRInt16 in_flags
, PRInt16
*out_flags
)
363 PRInt16 my_flags
, new_flags
;
364 PRFilePrivate
*mine
= (PRFilePrivate
*)fd
->secret
;
365 if (0 != (PR_POLL_READ
& in_flags
))
367 /* client thinks he's reading */
368 switch (mine
->rcvstate
)
370 case rcv_send_credit
:
371 my_flags
= (in_flags
& ~PR_POLL_READ
) | PR_POLL_WRITE
;
379 else if (0 != (PR_POLL_WRITE
& in_flags
))
381 /* client thinks he's writing */
382 switch (mine
->xmtstate
)
384 case xmt_recv_credit
:
385 my_flags
= (in_flags
& ~PR_POLL_WRITE
) | PR_POLL_READ
;
394 PR_NOT_REACHED("How'd I get here?");
396 new_flags
= (fd
->lower
->methods
->poll
)(fd
->lower
, my_flags
, out_flags
);
397 if (verbosity
> chatty
)
399 logFile
, "Poll [i: 0x%x, m: 0x%x, o: 0x%x, n: 0x%x]\n",
400 in_flags
, my_flags
, *out_flags
, new_flags
);
404 static PRFileDesc
* PR_CALLBACK
MyAccept(
405 PRFileDesc
*fd
, PRNetAddr
*addr
, PRIntervalTime timeout
)
408 PRFileDesc
*newfd
, *layer
= fd
;
409 PRFileDesc
*newstack
;
410 PRFilePrivate
*newsecret
;
412 PR_ASSERT(fd
!= NULL
);
413 PR_ASSERT(fd
->lower
!= NULL
);
415 newstack
= PR_NEW(PRFileDesc
);
416 if (NULL
== newstack
)
418 PR_SetError(PR_OUT_OF_MEMORY_ERROR
, 0);
421 newsecret
= PR_NEW(PRFilePrivate
);
422 if (NULL
== newsecret
)
425 PR_SetError(PR_OUT_OF_MEMORY_ERROR
, 0);
428 *newstack
= *fd
; /* make a copy of the accepting layer */
429 *newsecret
= *fd
->secret
;
430 newstack
->secret
= newsecret
;
432 newfd
= (fd
->lower
->methods
->accept
)(fd
->lower
, addr
, timeout
);
435 PR_DELETE(newsecret
);
440 /* this PR_PushIOLayer call cannot fail */
441 rv
= PR_PushIOLayer(newfd
, PR_TOP_IO_LAYER
, newstack
);
442 PR_ASSERT(PR_SUCCESS
== rv
);
443 return newfd
; /* that's it */
446 static PRInt32 PR_CALLBACK
MyRecv(
447 PRFileDesc
*fd
, void *buf
, PRInt32 amount
,
448 PRIntn flags
, PRIntervalTime timeout
)
452 PRFileDesc
*lo
= fd
->lower
;
453 PRFilePrivate
*mine
= (PRFilePrivate
*)fd
->secret
;
457 switch (mine
->rcvstate
)
460 b
= (char*)&mine
->rcvreq
;
461 mine
->rcvreq
= amount
;
462 rv
= lo
->methods
->recv(
463 lo
, b
+ mine
->rcvinprogress
,
464 sizeof(mine
->rcvreq
) - mine
->rcvinprogress
, flags
, timeout
);
468 if ((-1 == rv
) && (PR_WOULD_BLOCK_ERROR
== PR_GetError())) {
471 mine
->rcvinprogress
+= rv
; /* accumulate the read */
472 if (mine
->rcvinprogress
< sizeof(mine
->rcvreq
)) {
475 mine
->rcvstate
= rcv_send_credit
;
476 mine
->rcvinprogress
= 0;
477 case rcv_send_credit
:
478 b
= (char*)&mine
->rcvreq
;
479 rv
= lo
->methods
->send(
480 lo
, b
+ mine
->rcvinprogress
,
481 sizeof(mine
->rcvreq
) - mine
->rcvinprogress
, flags
, timeout
);
482 if ((-1 == rv
) && (PR_WOULD_BLOCK_ERROR
== PR_GetError())) {
485 mine
->rcvinprogress
+= rv
; /* accumulate the read */
486 if (mine
->rcvinprogress
< sizeof(mine
->rcvreq
)) {
489 mine
->rcvstate
= rcv_data
;
490 mine
->rcvinprogress
= 0;
493 rv
= lo
->methods
->recv(
494 lo
, b
+ mine
->rcvinprogress
,
495 mine
->rcvreq
- mine
->rcvinprogress
, flags
, timeout
);
499 if ((-1 == rv
) && (PR_WOULD_BLOCK_ERROR
== PR_GetError())) {
502 mine
->rcvinprogress
+= rv
; /* accumulate the read */
503 if (mine
->rcvinprogress
< amount
) {
506 mine
->rcvstate
= rcv_get_debit
;
507 mine
->rcvinprogress
= 0;
508 return mine
->rcvreq
; /* << -- that's it! */
515 mine
->rcvinprogress
= 0;
516 mine
->rcvstate
= rcv_get_debit
;
520 static PRInt32 PR_CALLBACK
MySend(
521 PRFileDesc
*fd
, const void *buf
, PRInt32 amount
,
522 PRIntn flags
, PRIntervalTime timeout
)
526 PRFileDesc
*lo
= fd
->lower
;
527 PRFilePrivate
*mine
= (PRFilePrivate
*)fd
->secret
;
531 switch (mine
->xmtstate
)
534 b
= (char*)&mine
->xmtreq
;
535 mine
->xmtreq
= amount
;
536 rv
= lo
->methods
->send(
537 lo
, b
- mine
->xmtinprogress
,
538 sizeof(mine
->xmtreq
) - mine
->xmtinprogress
, flags
, timeout
);
539 if ((-1 == rv
) && (PR_WOULD_BLOCK_ERROR
== PR_GetError())) {
542 mine
->xmtinprogress
+= rv
;
543 if (mine
->xmtinprogress
< sizeof(mine
->xmtreq
)) {
546 mine
->xmtstate
= xmt_recv_credit
;
547 mine
->xmtinprogress
= 0;
548 case xmt_recv_credit
:
549 b
= (char*)&mine
->xmtreq
;
550 rv
= lo
->methods
->recv(
551 lo
, b
+ mine
->xmtinprogress
,
552 sizeof(mine
->xmtreq
) - mine
->xmtinprogress
, flags
, timeout
);
553 if ((-1 == rv
) && (PR_WOULD_BLOCK_ERROR
== PR_GetError())) {
556 mine
->xmtinprogress
+= rv
;
557 if (mine
->xmtinprogress
< sizeof(mine
->xmtreq
)) {
560 mine
->xmtstate
= xmt_data
;
561 mine
->xmtinprogress
= 0;
564 rv
= lo
->methods
->send(
565 lo
, b
+ mine
->xmtinprogress
,
566 mine
->xmtreq
- mine
->xmtinprogress
, flags
, timeout
);
567 if ((-1 == rv
) && (PR_WOULD_BLOCK_ERROR
== PR_GetError())) {
570 mine
->xmtinprogress
+= rv
;
571 if (mine
->xmtinprogress
< amount
) {
574 mine
->xmtstate
= xmt_send_debit
;
575 mine
->xmtinprogress
= 0;
576 return mine
->xmtreq
; /* <<-- That's the one! */
584 static Verbosity
ChangeVerbosity(Verbosity verbosity
, PRIntn delta
)
586 PRIntn verbage
= (PRIntn
)verbosity
+ delta
;
587 if (verbage
< (PRIntn
)silent
) {
588 verbage
= (PRIntn
)silent
;
590 else if (verbage
> (PRIntn
)noisy
) {
591 verbage
= (PRIntn
)noisy
;
593 return (Verbosity
)verbage
;
594 } /* ChangeVerbosity */
596 int main(int argc
, char **argv
)
600 PRFileDesc
*client
, *service
;
601 PRNetAddr any_address
;
602 const char *server_name
= NULL
;
603 const PRIOMethods
*stubMethods
;
604 PRThread
*client_thread
, *server_thread
;
605 PRThreadScope thread_scope
= PR_LOCAL_THREAD
;
606 PRSocketOptionData socket_noblock
, socket_nodelay
;
607 PLOptState
*opt
= PL_CreateOptState(argc
, argv
, "dqGC:c:p:");
608 while (PL_OPT_EOL
!= (os
= PL_GetNextOpt(opt
)))
610 if (PL_OPT_BAD
== os
) {
616 server_name
= opt
->value
;
618 case 'd': /* debug mode */
619 if (verbosity
< noisy
) {
620 verbosity
= ChangeVerbosity(verbosity
, 1);
623 case 'q': /* debug mode */
624 if (verbosity
> silent
) {
625 verbosity
= ChangeVerbosity(verbosity
, -1);
628 case 'G': /* use global threads */
629 thread_scope
= PR_GLOBAL_THREAD
;
631 case 'C': /* number of threads waiting */
632 major_iterations
= atoi(opt
->value
);
634 case 'c': /* number of client threads */
635 minor_iterations
= atoi(opt
->value
);
637 case 'p': /* default port */
638 default_port
= atoi(opt
->value
);
644 PL_DestroyOptState(opt
);
647 logFile
= PR_GetSpecialFD(PR_StandardError
);
648 identity
= PR_GetUniqueIdentity("Dummy");
649 stubMethods
= PR_GetDefaultIOMethods();
652 ** The protocol we're going to implement is one where in order to initiate
653 ** a send, the sender must first solicit permission. Therefore, every
654 ** send is really a send - receive - send sequence.
656 myMethods
= *stubMethods
; /* first get the entire batch */
657 myMethods
.accept
= MyAccept
; /* then override the ones we care about */
658 myMethods
.recv
= MyRecv
; /* then override the ones we care about */
659 myMethods
.send
= MySend
; /* then override the ones we care about */
660 myMethods
.close
= MyClose
; /* then override the ones we care about */
661 myMethods
.poll
= MyPoll
; /* then override the ones we care about */
663 if (NULL
== server_name
)
664 rv
= PR_InitializeNetAddr(
665 PR_IpAddrLoopback
, default_port
, &server_address
);
668 rv
= PR_StringToNetAddr(server_name
, &server_address
);
669 PR_ASSERT(PR_SUCCESS
== rv
);
670 rv
= PR_InitializeNetAddr(
671 PR_IpAddrNull
, default_port
, &server_address
);
673 PR_ASSERT(PR_SUCCESS
== rv
);
675 socket_noblock
.value
.non_blocking
= PR_TRUE
;
676 socket_noblock
.option
= PR_SockOpt_Nonblocking
;
677 socket_nodelay
.value
.no_delay
= PR_TRUE
;
678 socket_nodelay
.option
= PR_SockOpt_NoDelay
;
680 /* one type w/o layering */
682 while (major_iterations
-- > 0)
684 if (verbosity
> silent
) {
685 PR_fprintf(logFile
, "Beginning non-layered test\n");
688 client
= PR_NewTCPSocket(); PR_ASSERT(NULL
!= client
);
689 service
= PR_NewTCPSocket(); PR_ASSERT(NULL
!= service
);
691 rv
= PR_SetSocketOption(client
, &socket_noblock
);
692 PR_ASSERT(PR_SUCCESS
== rv
);
693 rv
= PR_SetSocketOption(service
, &socket_noblock
);
694 PR_ASSERT(PR_SUCCESS
== rv
);
695 rv
= PR_SetSocketOption(client
, &socket_nodelay
);
696 PR_ASSERT(PR_SUCCESS
== rv
);
697 rv
= PR_SetSocketOption(service
, &socket_nodelay
);
698 PR_ASSERT(PR_SUCCESS
== rv
);
700 rv
= PR_InitializeNetAddr(PR_IpAddrAny
, default_port
, &any_address
);
701 PR_ASSERT(PR_SUCCESS
== rv
);
702 rv
= PR_Bind(service
, &any_address
); PR_ASSERT(PR_SUCCESS
== rv
);
703 rv
= PR_Listen(service
, 10); PR_ASSERT(PR_SUCCESS
== rv
);
705 server_thread
= PR_CreateThread(
706 PR_USER_THREAD
, Server
, service
,
707 PR_PRIORITY_HIGH
, thread_scope
,
708 PR_JOINABLE_THREAD
, 16 * 1024);
709 PR_ASSERT(NULL
!= server_thread
);
711 client_thread
= PR_CreateThread(
712 PR_USER_THREAD
, Client
, client
,
713 PR_PRIORITY_NORMAL
, thread_scope
,
714 PR_JOINABLE_THREAD
, 16 * 1024);
715 PR_ASSERT(NULL
!= client_thread
);
717 rv
= PR_JoinThread(client_thread
);
718 PR_ASSERT(PR_SUCCESS
== rv
);
719 rv
= PR_JoinThread(server_thread
);
720 PR_ASSERT(PR_SUCCESS
== rv
);
722 rv
= PR_Close(client
); PR_ASSERT(PR_SUCCESS
== rv
);
723 rv
= PR_Close(service
); PR_ASSERT(PR_SUCCESS
== rv
);
724 if (verbosity
> silent
) {
725 PR_fprintf(logFile
, "Ending non-layered test\n");
729 if (verbosity
> silent
) {
730 PR_fprintf(logFile
, "Beginning layered test\n");
732 client
= PR_NewTCPSocket(); PR_ASSERT(NULL
!= client
);
733 service
= PR_NewTCPSocket(); PR_ASSERT(NULL
!= service
);
735 rv
= PR_SetSocketOption(client
, &socket_noblock
);
736 PR_ASSERT(PR_SUCCESS
== rv
);
737 rv
= PR_SetSocketOption(service
, &socket_noblock
);
738 PR_ASSERT(PR_SUCCESS
== rv
);
739 rv
= PR_SetSocketOption(client
, &socket_nodelay
);
740 PR_ASSERT(PR_SUCCESS
== rv
);
741 rv
= PR_SetSocketOption(service
, &socket_nodelay
);
742 PR_ASSERT(PR_SUCCESS
== rv
);
747 rv
= PR_InitializeNetAddr(PR_IpAddrAny
, default_port
, &any_address
);
748 PR_ASSERT(PR_SUCCESS
== rv
);
749 rv
= PR_Bind(service
, &any_address
); PR_ASSERT(PR_SUCCESS
== rv
);
750 rv
= PR_Listen(service
, 10); PR_ASSERT(PR_SUCCESS
== rv
);
752 server_thread
= PR_CreateThread(
753 PR_USER_THREAD
, Server
, service
,
754 PR_PRIORITY_HIGH
, thread_scope
,
755 PR_JOINABLE_THREAD
, 16 * 1024);
756 PR_ASSERT(NULL
!= server_thread
);
758 client_thread
= PR_CreateThread(
759 PR_USER_THREAD
, Client
, client
,
760 PR_PRIORITY_NORMAL
, thread_scope
,
761 PR_JOINABLE_THREAD
, 16 * 1024);
762 PR_ASSERT(NULL
!= client_thread
);
764 rv
= PR_JoinThread(client_thread
);
765 PR_ASSERT(PR_SUCCESS
== rv
);
766 rv
= PR_JoinThread(server_thread
);
767 PR_ASSERT(PR_SUCCESS
== rv
);
769 rv
= PR_Close(PopLayer(client
)); PR_ASSERT(PR_SUCCESS
== rv
);
770 rv
= PR_Close(PopLayer(service
)); PR_ASSERT(PR_SUCCESS
== rv
);
771 if (verbosity
> silent
) {
772 PR_fprintf(logFile
, "Ending layered test\n");