Bug 1909163 - make select dropdowns more properly tabspecific, r=emilio
[gecko.git] / nsprpub / pr / tests / socket.c
blob232898f69e7aa6cb278368c1018fd4014ebab390
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 /***********************************************************************
7 **
8 ** Name: socket.c
9 **
10 ** Description: Test socket functionality.
12 ** Modification History:
14 #include "primpl.h"
16 #include "plgetopt.h"
18 #include <stdio.h>
19 #include <string.h>
20 #include <errno.h>
21 #ifdef XP_UNIX
22 #include <sys/mman.h>
23 #endif
24 #if defined(_PR_PTHREADS)
25 #include <pthread.h>
26 #endif
28 #ifdef WIN32
29 #include <process.h>
30 #endif
32 static int _debug_on = 0;
33 static int test_cancelio = 0;
35 #include "obsolete/prsem.h"
37 #ifdef XP_PC
38 #define mode_t int
39 #endif
41 #define DPRINTF(arg) if (_debug_on) printf arg
43 #ifdef XP_PC
44 char *TEST_DIR = "prdir";
45 char *SMALL_FILE_NAME = "prsmallf";
46 char *LARGE_FILE_NAME = "prlargef";
47 #else
48 char *TEST_DIR = "./tmp-prsocket_test_dir";
49 char *SMALL_FILE_NAME = "./tmp-prsocket_test_dir/small_file";
50 char *LARGE_FILE_NAME = "./tmp-prsocket_test_dir/large_file";
51 #endif
52 #define SMALL_FILE_SIZE (3 * 1024) /* 3 KB */
53 #define SMALL_FILE_OFFSET_1 (512)
54 #define SMALL_FILE_LEN_1 (1 * 1024) /* 1 KB */
55 #define SMALL_FILE_OFFSET_2 (75)
56 #define SMALL_FILE_LEN_2 (758)
57 #define SMALL_FILE_OFFSET_3 (1024)
58 #define SMALL_FILE_LEN_3 (SMALL_FILE_SIZE - SMALL_FILE_OFFSET_3)
59 #define SMALL_FILE_HEADER_SIZE (64) /* 64 bytes */
60 #define SMALL_FILE_TRAILER_SIZE (128) /* 128 bytes */
62 #define LARGE_FILE_SIZE (3 * 1024 * 1024) /* 3 MB */
63 #define LARGE_FILE_OFFSET_1 (0)
64 #define LARGE_FILE_LEN_1 (2 * 1024 * 1024) /* 2 MB */
65 #define LARGE_FILE_OFFSET_2 (64)
66 #define LARGE_FILE_LEN_2 (1 * 1024 * 1024 + 75)
67 #define LARGE_FILE_OFFSET_3 (2 * 1024 * 1024 - 128)
68 #define LARGE_FILE_LEN_3 (LARGE_FILE_SIZE - LARGE_FILE_OFFSET_3)
69 #define LARGE_FILE_OFFSET_4 PR_GetPageSize()
70 #define LARGE_FILE_LEN_4 769
71 #define LARGE_FILE_HEADER_SIZE (512)
72 #define LARGE_FILE_TRAILER_SIZE (64)
74 #define BUF_DATA_SIZE (2 * 1024)
75 #define TCP_MESG_SIZE 1024
77 * set UDP datagram size small enough that datagrams sent to a port on the
78 * local host will not be lost
80 #define UDP_DGRAM_SIZE 128
81 #define NUM_TCP_CLIENTS 5 /* for a listen queue depth of 5 */
82 #define NUM_UDP_CLIENTS 10
84 #define NUM_TRANSMITFILE_CLIENTS 4
86 #define NUM_TCP_CONNECTIONS_PER_CLIENT 5
87 #define NUM_TCP_MESGS_PER_CONNECTION 10
88 #define NUM_UDP_DATAGRAMS_PER_CLIENT 5
89 #define TCP_SERVER_PORT 10000
90 #define UDP_SERVER_PORT TCP_SERVER_PORT
91 #define SERVER_MAX_BIND_COUNT 100
93 #ifdef WINCE
94 #define perror(s)
95 #endif
97 static PRInt32 num_tcp_clients = NUM_TCP_CLIENTS;
98 static PRInt32 num_udp_clients = NUM_UDP_CLIENTS;
99 static PRInt32 num_transmitfile_clients = NUM_TRANSMITFILE_CLIENTS;
100 static PRInt32 num_tcp_connections_per_client = NUM_TCP_CONNECTIONS_PER_CLIENT;
101 static PRInt32 tcp_mesg_size = TCP_MESG_SIZE;
102 static PRInt32 num_tcp_mesgs_per_connection = NUM_TCP_MESGS_PER_CONNECTION;
103 static PRInt32 num_udp_datagrams_per_client = NUM_UDP_DATAGRAMS_PER_CLIENT;
104 static PRInt32 udp_datagram_size = UDP_DGRAM_SIZE;
106 static PRInt32 thread_count;
107 PRUint16 server_domain = PR_AF_INET, client_domain = PR_AF_INET;
109 /* an I/O layer that uses the emulated senfile method */
110 static PRDescIdentity emuSendFileIdentity;
111 static PRIOMethods emuSendFileMethods;
113 int failed_already=0;
114 typedef struct buffer {
115 char data[BUF_DATA_SIZE];
116 } buffer;
118 PRNetAddr tcp_server_addr, udp_server_addr;
120 typedef struct Serve_Client_Param {
121 PRFileDesc *sockfd; /* socket to read from/write to */
122 PRInt32 datalen; /* bytes of data transfered in each read/write */
123 } Serve_Client_Param;
125 typedef struct Server_Param {
126 PRSemaphore *addr_sem; /* sem to post on, after setting up the address */
127 PRMonitor *exit_mon; /* monitor to signal on exit */
128 PRInt32 *exit_counter; /* counter to decrement, before exit */
129 PRInt32 datalen; /* bytes of data transfered in each read/write */
130 } Server_Param;
133 typedef struct Client_Param {
134 PRNetAddr server_addr;
135 PRMonitor *exit_mon; /* monitor to signal on exit */
136 PRInt32 *exit_counter; /* counter to decrement, before exit */
137 PRInt32 datalen;
138 PRInt32 udp_connect; /* if set clients connect udp sockets */
139 } Client_Param;
141 /* the sendfile method in emuSendFileMethods */
142 static PRInt32 PR_CALLBACK
143 emu_SendFile(PRFileDesc *sd, PRSendFileData *sfd,
144 PRTransmitFileFlags flags, PRIntervalTime timeout)
146 return PR_EmulateSendFile(sd, sfd, flags, timeout);
149 /* the transmitfile method in emuSendFileMethods */
150 static PRInt32 PR_CALLBACK
151 emu_TransmitFile(PRFileDesc *sd, PRFileDesc *fd, const void *headers,
152 PRInt32 hlen, PRTransmitFileFlags flags, PRIntervalTime timeout)
154 PRSendFileData sfd;
156 sfd.fd = fd;
157 sfd.file_offset = 0;
158 sfd.file_nbytes = 0;
159 sfd.header = headers;
160 sfd.hlen = hlen;
161 sfd.trailer = NULL;
162 sfd.tlen = 0;
163 return emu_SendFile(sd, &sfd, flags, timeout);
167 * readn
168 * read data from sockfd into buf
170 static PRInt32
171 readn(PRFileDesc *sockfd, char *buf, int len)
173 int rem;
174 int bytes;
175 int offset = 0;
176 int err;
177 PRIntervalTime timeout = PR_INTERVAL_NO_TIMEOUT;
179 if (test_cancelio) {
180 timeout = PR_SecondsToInterval(2);
183 for (rem=len; rem; offset += bytes, rem -= bytes) {
184 DPRINTF(("thread = 0x%lx: calling PR_Recv, bytes = %d\n",
185 PR_GetCurrentThread(), rem));
186 retry:
187 bytes = PR_Recv(sockfd, buf + offset, rem, 0,
188 timeout);
189 DPRINTF(("thread = 0x%lx: returning from PR_Recv, bytes = %d\n",
190 PR_GetCurrentThread(), bytes));
191 if (bytes < 0) {
192 #ifdef WINNT
193 printf("PR_Recv: error = %d oserr = %d\n",(err = PR_GetError()),
194 PR_GetOSError());
195 if ((test_cancelio) && (err == PR_IO_TIMEOUT_ERROR)) {
196 if (PR_NT_CancelIo(sockfd) != PR_SUCCESS) {
197 printf("PR_NT_CancelIO: error = %d\n",PR_GetError());
199 timeout = PR_INTERVAL_NO_TIMEOUT;
200 goto retry;
202 #endif
203 return -1;
206 return len;
210 * writen
211 * write data from buf to sockfd
213 static PRInt32
214 writen(PRFileDesc *sockfd, char *buf, int len)
216 int rem;
217 int bytes;
218 int offset = 0;
220 for (rem=len; rem; offset += bytes, rem -= bytes) {
221 DPRINTF(("thread = 0x%lx: calling PR_Send, bytes = %d\n",
222 PR_GetCurrentThread(), rem));
223 bytes = PR_Send(sockfd, buf + offset, rem, 0,
224 PR_INTERVAL_NO_TIMEOUT);
225 DPRINTF(("thread = 0x%lx: returning from PR_Send, bytes = %d\n",
226 PR_GetCurrentThread(), bytes));
227 if (bytes <= 0) {
228 return -1;
231 return len;
235 * Serve_Client
236 * Thread, started by the server, for serving a client connection.
237 * Reads data from socket and writes it back, unmodified, and
238 * closes the socket
240 static void PR_CALLBACK
241 Serve_Client(void *arg)
243 Serve_Client_Param *scp = (Serve_Client_Param *) arg;
244 PRFileDesc *sockfd;
245 buffer *in_buf;
246 PRInt32 bytes, j;
248 sockfd = scp->sockfd;
249 bytes = scp->datalen;
250 in_buf = PR_NEW(buffer);
251 if (in_buf == NULL) {
252 fprintf(stderr,"prsocket_test: failed to alloc buffer struct\n");
253 failed_already=1;
254 goto exit;
258 for (j = 0; j < num_tcp_mesgs_per_connection; j++) {
260 * Read data from client and send it back to the client unmodified
262 if (readn(sockfd, in_buf->data, bytes) < bytes) {
263 fprintf(stderr,"prsocket_test: ERROR - Serve_Client:readn\n");
264 failed_already=1;
265 goto exit;
267 /* Shutdown only RCV will cause error on Symbian OS */
269 * shutdown reads, after the last read
271 if (j == num_tcp_mesgs_per_connection - 1)
272 if (PR_Shutdown(sockfd, PR_SHUTDOWN_RCV) < 0) {
273 fprintf(stderr,"prsocket_test: ERROR - PR_Shutdown\n");
275 DPRINTF(("Serve_Client [0x%lx]: inbuf[0] = 0x%lx\n",PR_GetCurrentThread(),
276 (*((int *) in_buf->data))));
277 if (writen(sockfd, in_buf->data, bytes) < bytes) {
278 fprintf(stderr,"prsocket_test: ERROR - Serve_Client:writen\n");
279 failed_already=1;
280 goto exit;
284 * shutdown reads and writes
286 if (PR_Shutdown(sockfd, PR_SHUTDOWN_BOTH) < 0) {
287 fprintf(stderr,"prsocket_test: ERROR - PR_Shutdown\n");
288 failed_already=1;
291 exit:
292 PR_Close(sockfd);
293 if (in_buf) {
294 PR_DELETE(in_buf);
298 PRThread* create_new_thread(PRThreadType type,
299 void (*start)(void *arg),
300 void *arg,
301 PRThreadPriority priority,
302 PRThreadScope scope,
303 PRThreadState state,
304 PRUint32 stackSize, PRInt32 index)
306 PRInt32 native_thread = 0;
308 PR_ASSERT(state == PR_UNJOINABLE_THREAD);
309 #if defined(_PR_PTHREADS) || defined(WIN32)
310 switch(index % 4) {
311 case 0:
312 scope = (PR_LOCAL_THREAD);
313 break;
314 case 1:
315 scope = (PR_GLOBAL_THREAD);
316 break;
317 case 2:
318 scope = (PR_GLOBAL_BOUND_THREAD);
319 break;
320 case 3:
321 native_thread = 1;
322 break;
323 default:
324 PR_NOT_REACHED("Invalid scope");
325 break;
327 if (native_thread) {
328 #if defined(_PR_PTHREADS)
329 pthread_t tid;
330 if (!pthread_create(&tid, NULL, (void * (*)(void *)) start, arg)) {
331 return((PRThread *) tid);
333 else {
334 return (NULL);
336 #else
337 HANDLE thandle;
338 unsigned tid;
340 thandle = (HANDLE) _beginthreadex(
341 NULL,
342 stackSize,
343 (unsigned (__stdcall *)(void *))start,
344 arg,
345 STACK_SIZE_PARAM_IS_A_RESERVATION,
346 &tid);
347 return((PRThread *) thandle);
348 #endif
349 } else {
350 return(PR_CreateThread(type,start,arg,priority,scope,state,stackSize));
352 #else
353 return(PR_CreateThread(type,start,arg,priority,scope,state,stackSize));
354 #endif
358 * TCP Server
359 * Server Thread
360 * Bind an address to a socket and listen for incoming connections
361 * Start a Serve_Client thread for each incoming connection.
363 static void PR_CALLBACK
364 TCP_Server(void *arg)
366 PRThread *t;
367 Server_Param *sp = (Server_Param *) arg;
368 Serve_Client_Param *scp;
369 PRFileDesc *sockfd, *newsockfd;
370 PRNetAddr netaddr;
371 PRInt32 i;
373 * Create a tcp socket
375 if ((sockfd = PR_OpenTCPSocket(server_domain)) == NULL) {
376 fprintf(stderr,"prsocket_test: PR_NewTCPSocket failed\n");
377 goto exit;
379 memset(&netaddr, 0, sizeof(netaddr));
381 if (PR_SetNetAddr(PR_IpAddrAny, server_domain, TCP_SERVER_PORT,
382 &netaddr) == PR_FAILURE) {
383 fprintf(stderr,"prsocket_test: PR_SetNetAddr failed\n");
384 goto exit;
387 * try a few times to bind server's address, if addresses are in
388 * use
390 i = 0;
392 while (PR_Bind(sockfd, &netaddr) < 0) {
393 if (PR_GetError() == PR_ADDRESS_IN_USE_ERROR) {
394 netaddr.inet.port += 2;
395 if (i++ < SERVER_MAX_BIND_COUNT) {
396 continue;
399 fprintf(stderr,"prsocket_test: ERROR - PR_Bind failed\n");
400 perror("PR_Bind");
401 failed_already=1;
402 goto exit;
405 if (PR_Listen(sockfd, 32) < 0) {
406 fprintf(stderr,"prsocket_test: ERROR - PR_Listen failed\n");
407 failed_already=1;
408 goto exit;
411 if (PR_GetSockName(sockfd, &netaddr) < 0) {
412 fprintf(stderr,"prsocket_test: ERROR - PR_GetSockName failed\n");
413 failed_already=1;
414 goto exit;
417 DPRINTF(("TCP_Server: PR_BIND netaddr.inet.ip = 0x%lx, netaddr.inet.port = %d\n",
418 netaddr.inet.ip, netaddr.inet.port));
419 if (PR_SetNetAddr(PR_IpAddrLoopback, client_domain,
420 PR_ntohs(PR_NetAddrInetPort(&netaddr)),
421 &tcp_server_addr) == PR_FAILURE) {
422 fprintf(stderr,"prsocket_test: PR_SetNetAddr failed\n");
423 goto exit;
425 if ((client_domain == PR_AF_INET6) && (server_domain == PR_AF_INET))
426 PR_ConvertIPv4AddrToIPv6(PR_htonl(INADDR_LOOPBACK),
427 &tcp_server_addr.ipv6.ip);
430 * Wake up parent thread because server address is bound and made
431 * available in the global variable 'tcp_server_addr'
433 PR_PostSem(sp->addr_sem);
435 for (i = 0; i < (num_tcp_clients * num_tcp_connections_per_client); i++) {
436 /* test both null and non-null 'addr' argument to PR_Accept */
437 PRNetAddr *addrp = (i%2 ? &netaddr: NULL);
439 DPRINTF(("TCP_Server: Accepting connection\n"));
440 if ((newsockfd = PR_Accept(sockfd, addrp,
441 PR_INTERVAL_NO_TIMEOUT)) == NULL) {
442 fprintf(stderr,"prsocket_test: ERROR - PR_Accept failed\n");
443 goto exit;
445 DPRINTF(("TCP_Server: Accepted connection\n"));
446 scp = PR_NEW(Serve_Client_Param);
447 if (scp == NULL) {
448 fprintf(stderr,"prsocket_test: PR_NEW failed\n");
449 goto exit;
453 * Start a Serve_Client thread for each incoming connection
455 scp->sockfd = newsockfd;
456 scp->datalen = sp->datalen;
458 t = create_new_thread(PR_USER_THREAD,
459 Serve_Client, (void *)scp,
460 PR_PRIORITY_NORMAL,
461 PR_LOCAL_THREAD,
462 PR_UNJOINABLE_THREAD,
463 0, i);
464 if (t == NULL) {
465 fprintf(stderr,"prsocket_test: PR_CreateThread failed\n");
466 failed_already=1;
467 goto exit;
469 DPRINTF(("TCP_Server: Created Serve_Client = 0x%lx\n", t));
472 exit:
473 if (sockfd) {
474 PR_Close(sockfd);
478 * Decrement exit_counter and notify parent thread
481 PR_EnterMonitor(sp->exit_mon);
482 --(*sp->exit_counter);
483 PR_Notify(sp->exit_mon);
484 PR_ExitMonitor(sp->exit_mon);
485 DPRINTF(("TCP_Server [0x%lx] exiting\n", PR_GetCurrentThread()));
489 * UDP Server
490 * Server Thread
491 * Bind an address to a socket, read data from clients and send data
492 * back to clients
494 static void PR_CALLBACK
495 UDP_Server(void *arg)
497 Server_Param *sp = (Server_Param *) arg;
498 PRFileDesc *sockfd;
499 buffer *in_buf;
500 PRNetAddr netaddr;
501 PRInt32 bytes, i, rv = 0;
504 bytes = sp->datalen;
506 * Create a udp socket
508 if ((sockfd = PR_OpenUDPSocket(server_domain)) == NULL) {
509 fprintf(stderr,"prsocket_test: PR_NewUDPSocket failed\n");
510 failed_already=1;
511 return;
513 memset(&netaddr, 0, sizeof(netaddr));
514 if (PR_SetNetAddr(PR_IpAddrAny, server_domain, UDP_SERVER_PORT,
515 &netaddr) == PR_FAILURE) {
516 fprintf(stderr,"prsocket_test: PR_SetNetAddr failed\n");
517 failed_already=1;
518 return;
521 * try a few times to bind server's address, if addresses are in
522 * use
524 i = 0;
525 while (PR_Bind(sockfd, &netaddr) < 0) {
526 if (PR_GetError() == PR_ADDRESS_IN_USE_ERROR) {
527 netaddr.inet.port += 2;
528 if (i++ < SERVER_MAX_BIND_COUNT) {
529 continue;
532 fprintf(stderr,"prsocket_test: ERROR - PR_Bind failed\n");
533 perror("PR_Bind");
534 failed_already=1;
535 return;
538 if (PR_GetSockName(sockfd, &netaddr) < 0) {
539 fprintf(stderr,"prsocket_test: ERROR - PR_GetSockName failed\n");
540 failed_already=1;
541 return;
544 DPRINTF(("PR_Bind: UDP Server netaddr.inet.ip = 0x%lx, netaddr.inet.port = %d\n",
545 netaddr.inet.ip, netaddr.inet.port));
547 * We can't use the IP address returned by PR_GetSockName in
548 * netaddr.inet.ip because netaddr.inet.ip is returned
549 * as 0 (= PR_INADDR_ANY).
552 if (PR_SetNetAddr(PR_IpAddrLoopback, client_domain,
553 PR_ntohs(PR_NetAddrInetPort(&netaddr)),
554 &udp_server_addr) == PR_FAILURE) {
555 fprintf(stderr,"prsocket_test: PR_SetNetAddr failed\n");
556 failed_already=1;
557 return;
559 if ((client_domain == PR_AF_INET6) && (server_domain == PR_AF_INET))
560 PR_ConvertIPv4AddrToIPv6(PR_htonl(INADDR_LOOPBACK),
561 &udp_server_addr.ipv6.ip);
564 * Wake up parent thread because server address is bound and made
565 * available in the global variable 'udp_server_addr'
567 PR_PostSem(sp->addr_sem);
569 bytes = sp->datalen;
570 in_buf = PR_NEW(buffer);
571 if (in_buf == NULL) {
572 fprintf(stderr,"prsocket_test: failed to alloc buffer struct\n");
573 failed_already=1;
574 return;
577 * Receive datagrams from clients and send them back, unmodified, to the
578 * clients
580 memset(&netaddr, 0, sizeof(netaddr));
581 for (i = 0; i < (num_udp_clients * num_udp_datagrams_per_client); i++) {
582 DPRINTF(("UDP_Server: calling PR_RecvFrom client - ip = 0x%lx, port = %d bytes = %d inbuf = 0x%lx, inbuf[0] = 0x%lx\n",
583 netaddr.inet.ip, netaddr.inet.port, bytes, in_buf->data,
584 in_buf->data[0]));
586 rv = PR_RecvFrom(sockfd, in_buf->data, bytes, 0, &netaddr,
587 PR_INTERVAL_NO_TIMEOUT);
588 DPRINTF(("UDP_Server: PR_RecvFrom client - ip = 0x%lx, port = %d bytes = %d inbuf = 0x%lx, inbuf[0] = 0x%lx\n",
589 netaddr.inet.ip, netaddr.inet.port, rv, in_buf->data,
590 in_buf->data[0]));
591 if (rv != bytes) {
592 return;
594 rv = PR_SendTo(sockfd, in_buf->data, bytes, 0, &netaddr,
595 PR_INTERVAL_NO_TIMEOUT);
596 if (rv != bytes) {
597 return;
601 PR_DELETE(in_buf);
602 PR_Close(sockfd);
605 * Decrement exit_counter and notify parent thread
607 PR_EnterMonitor(sp->exit_mon);
608 --(*sp->exit_counter);
609 PR_Notify(sp->exit_mon);
610 PR_ExitMonitor(sp->exit_mon);
611 DPRINTF(("UDP_Server [0x%x] exiting\n", PR_GetCurrentThread()));
615 * TCP_Client
616 * Client Thread
617 * Connect to the server at the address specified in the argument.
618 * Fill in a buffer, write data to server, read it back and check
619 * for data corruption.
620 * Close the socket for server connection
622 static void PR_CALLBACK
623 TCP_Client(void *arg)
625 Client_Param *cp = (Client_Param *) arg;
626 PRFileDesc *sockfd;
627 buffer *in_buf, *out_buf;
628 union PRNetAddr netaddr;
629 PRInt32 bytes, i, j;
632 bytes = cp->datalen;
633 out_buf = PR_NEW(buffer);
634 if (out_buf == NULL) {
635 fprintf(stderr,"prsocket_test: failed to alloc buffer struct\n");
636 failed_already=1;
637 return;
639 in_buf = PR_NEW(buffer);
640 if (in_buf == NULL) {
641 fprintf(stderr,"prsocket_test: failed to alloc buffer struct\n");
642 failed_already=1;
643 return;
645 netaddr = cp->server_addr;
647 for (i = 0; i < num_tcp_connections_per_client; i++) {
648 if ((sockfd = PR_OpenTCPSocket(client_domain)) == NULL) {
649 fprintf(stderr,"prsocket_test: PR_OpenTCPSocket failed\n");
650 failed_already=1;
651 return;
653 if (PR_Connect(sockfd, &netaddr,PR_INTERVAL_NO_TIMEOUT) < 0) {
654 fprintf(stderr, "PR_Connect failed: (%ld, %ld)\n",
655 PR_GetError(), PR_GetOSError());
656 failed_already=1;
657 return;
659 for (j = 0; j < num_tcp_mesgs_per_connection; j++) {
661 * fill in random data
663 memset(out_buf->data, ((PRInt32) (&netaddr)) + i + j, bytes);
665 * write to server
667 #ifdef WINNT
668 if (test_cancelio && (j == 0)) {
669 PR_Sleep(PR_SecondsToInterval(12));
671 #endif
672 if (writen(sockfd, out_buf->data, bytes) < bytes) {
673 fprintf(stderr,"prsocket_test: ERROR - TCP_Client:writen\n");
674 failed_already=1;
675 return;
677 DPRINTF(("TCP Client [0x%lx]: out_buf = 0x%lx out_buf[0] = 0x%lx\n",
678 PR_GetCurrentThread(), out_buf, (*((int *) out_buf->data))));
679 if (readn(sockfd, in_buf->data, bytes) < bytes) {
680 fprintf(stderr,"prsocket_test: ERROR - TCP_Client:readn\n");
681 failed_already=1;
682 return;
685 * verify the data read
687 if (memcmp(in_buf->data, out_buf->data, bytes) != 0) {
688 fprintf(stderr,"prsocket_test: ERROR - data corruption\n");
689 failed_already=1;
690 return;
694 * shutdown reads and writes
696 if (PR_Shutdown(sockfd, PR_SHUTDOWN_BOTH) < 0) {
697 fprintf(stderr,"prsocket_test: ERROR - PR_Shutdown\n");
698 failed_already=1;
700 PR_Close(sockfd);
703 PR_DELETE(out_buf);
704 PR_DELETE(in_buf);
707 * Decrement exit_counter and notify parent thread
710 PR_EnterMonitor(cp->exit_mon);
711 --(*cp->exit_counter);
712 PR_Notify(cp->exit_mon);
713 PR_ExitMonitor(cp->exit_mon);
714 DPRINTF(("TCP_Client [0x%x] exiting\n", PR_GetCurrentThread()));
718 * UDP_Client
719 * Client Thread
720 * Create a socket and bind an address
721 * Communicate with the server at the address specified in the argument.
722 * Fill in a buffer, write data to server, read it back and check
723 * for data corruption.
724 * Close the socket
726 static void PR_CALLBACK
727 UDP_Client(void *arg)
729 Client_Param *cp = (Client_Param *) arg;
730 PRFileDesc *sockfd;
731 buffer *in_buf, *out_buf;
732 union PRNetAddr netaddr;
733 PRInt32 bytes, i, rv;
736 bytes = cp->datalen;
737 out_buf = PR_NEW(buffer);
738 if (out_buf == NULL) {
739 fprintf(stderr,"prsocket_test: failed to alloc buffer struct\n");
740 failed_already=1;
741 return;
743 in_buf = PR_NEW(buffer);
744 if (in_buf == NULL) {
745 fprintf(stderr,"prsocket_test: failed to alloc buffer struct\n");
746 failed_already=1;
747 return;
749 if ((sockfd = PR_OpenUDPSocket(client_domain)) == NULL) {
750 fprintf(stderr,"prsocket_test: PR_OpenUDPSocket failed\n");
751 failed_already=1;
752 return;
756 * bind an address for the client, let the system chose the port
757 * number
759 memset(&netaddr, 0, sizeof(netaddr));
760 if (PR_SetNetAddr(PR_IpAddrAny, client_domain, 0,
761 &netaddr) == PR_FAILURE) {
762 fprintf(stderr,"prsocket_test: PR_SetNetAddr failed\n");
763 failed_already=1;
764 return;
766 if (PR_Bind(sockfd, &netaddr) < 0) {
767 fprintf(stderr,"prsocket_test: ERROR - PR_Bind failed\n");
768 perror("PR_Bind");
769 return;
772 if (PR_GetSockName(sockfd, &netaddr) < 0) {
773 fprintf(stderr,"prsocket_test: ERROR - PR_GetSockName failed\n");
774 failed_already=1;
775 return;
778 DPRINTF(("PR_Bind: UDP Client netaddr.inet.ip = 0x%lx, netaddr.inet.port = %d\n",
779 netaddr.inet.ip, netaddr.inet.port));
781 netaddr = cp->server_addr;
783 if (cp->udp_connect) {
784 if (PR_Connect(sockfd, &netaddr,PR_INTERVAL_NO_TIMEOUT) < 0) {
785 fprintf(stderr,"prsocket_test: PR_Connect failed\n");
786 failed_already=1;
787 return;
791 for (i = 0; i < num_udp_datagrams_per_client; i++) {
793 * fill in random data
795 DPRINTF(("UDP_Client [0x%lx]: out_buf = 0x%lx bytes = 0x%lx\n",
796 PR_GetCurrentThread(), out_buf->data, bytes));
797 memset(out_buf->data, ((PRInt32) (&netaddr)) + i, bytes);
799 * write to server
801 if (cp->udp_connect)
802 rv = PR_Send(sockfd, out_buf->data, bytes, 0,
803 PR_INTERVAL_NO_TIMEOUT);
804 else
805 rv = PR_SendTo(sockfd, out_buf->data, bytes, 0, &netaddr,
806 PR_INTERVAL_NO_TIMEOUT);
807 if (rv != bytes) {
808 return;
810 DPRINTF(("UDP_Client [0x%lx]: out_buf = 0x%lx out_buf[0] = 0x%lx\n",
811 PR_GetCurrentThread(), out_buf, (*((int *) out_buf->data))));
812 if (cp->udp_connect)
813 rv = PR_Recv(sockfd, in_buf->data, bytes, 0,
814 PR_INTERVAL_NO_TIMEOUT);
815 else
816 rv = PR_RecvFrom(sockfd, in_buf->data, bytes, 0, &netaddr,
817 PR_INTERVAL_NO_TIMEOUT);
818 if (rv != bytes) {
819 return;
821 DPRINTF(("UDP_Client [0x%lx]: in_buf = 0x%lx in_buf[0] = 0x%lx\n",
822 PR_GetCurrentThread(), in_buf, (*((int *) in_buf->data))));
824 * verify the data read
826 if (memcmp(in_buf->data, out_buf->data, bytes) != 0) {
827 fprintf(stderr,"prsocket_test: ERROR - UDP data corruption\n");
828 failed_already=1;
829 return;
832 PR_Close(sockfd);
834 PR_DELETE(in_buf);
835 PR_DELETE(out_buf);
838 * Decrement exit_counter and notify parent thread
841 PR_EnterMonitor(cp->exit_mon);
842 --(*cp->exit_counter);
843 PR_Notify(cp->exit_mon);
844 PR_ExitMonitor(cp->exit_mon);
845 PR_DELETE(cp);
846 DPRINTF(("UDP_Client [0x%x] exiting\n", PR_GetCurrentThread()));
850 * TCP_Socket_Client_Server_Test - concurrent server test
852 * One server and several clients are started
853 * Each client connects to the server and sends a chunk of data
854 * For each connection, server starts another thread to read the data
855 * from the client and send it back to the client, unmodified.
856 * Each client checks that data received from server is same as the
857 * data it sent to the server.
861 static PRInt32
862 TCP_Socket_Client_Server_Test(void)
864 int i;
865 PRThread *t;
866 PRSemaphore *server_sem;
867 Server_Param *sparamp;
868 Client_Param *cparamp;
869 PRMonitor *mon2;
870 PRInt32 datalen;
873 datalen = tcp_mesg_size;
874 thread_count = 0;
876 * start the server thread
878 sparamp = PR_NEW(Server_Param);
879 if (sparamp == NULL) {
880 fprintf(stderr,"prsocket_test: PR_NEW failed\n");
881 failed_already=1;
882 return -1;
884 server_sem = PR_NewSem(0);
885 if (server_sem == NULL) {
886 fprintf(stderr,"prsocket_test: PR_NewSem failed\n");
887 failed_already=1;
888 return -1;
890 mon2 = PR_NewMonitor();
891 if (mon2 == NULL) {
892 fprintf(stderr,"prsocket_test: PR_NewMonitor failed\n");
893 failed_already=1;
894 return -1;
896 PR_EnterMonitor(mon2);
898 sparamp->addr_sem = server_sem;
899 sparamp->exit_mon = mon2;
900 sparamp->exit_counter = &thread_count;
901 sparamp->datalen = datalen;
902 t = PR_CreateThread(PR_USER_THREAD,
903 TCP_Server, (void *)sparamp,
904 PR_PRIORITY_NORMAL,
905 PR_LOCAL_THREAD,
906 PR_UNJOINABLE_THREAD,
908 if (t == NULL) {
909 fprintf(stderr,"prsocket_test: PR_CreateThread failed\n");
910 failed_already=1;
911 return -1;
913 DPRINTF(("Created TCP server = 0x%lx\n", t));
914 thread_count++;
917 * wait till the server address is setup
919 PR_WaitSem(server_sem);
922 * Now start a bunch of client threads
925 cparamp = PR_NEW(Client_Param);
926 if (cparamp == NULL) {
927 fprintf(stderr,"prsocket_test: PR_NEW failed\n");
928 failed_already=1;
929 return -1;
931 cparamp->server_addr = tcp_server_addr;
932 cparamp->exit_mon = mon2;
933 cparamp->exit_counter = &thread_count;
934 cparamp->datalen = datalen;
935 for (i = 0; i < num_tcp_clients; i++) {
936 t = create_new_thread(PR_USER_THREAD,
937 TCP_Client, (void *) cparamp,
938 PR_PRIORITY_NORMAL,
939 PR_LOCAL_THREAD,
940 PR_UNJOINABLE_THREAD,
941 0, i);
942 if (t == NULL) {
943 fprintf(stderr,"prsocket_test: PR_CreateThread failed\n");
944 failed_already=1;
945 return -1;
947 DPRINTF(("Created TCP client = 0x%lx\n", t));
948 thread_count++;
950 /* Wait for server and client threads to exit */
951 while (thread_count) {
952 PR_Wait(mon2, PR_INTERVAL_NO_TIMEOUT);
953 DPRINTF(("TCP Server - thread_count = %d\n", thread_count));
955 PR_ExitMonitor(mon2);
956 printf("%30s","TCP_Socket_Client_Server_Test:");
957 printf("%2ld Server %2ld Clients %2ld connections_per_client\n",1l,
958 num_tcp_clients, num_tcp_connections_per_client);
959 printf("%30s %2ld messages_per_connection %4ld bytes_per_message\n",":",
960 num_tcp_mesgs_per_connection, tcp_mesg_size);
962 return 0;
966 * UDP_Socket_Client_Server_Test - iterative server test
968 * One server and several clients are started
969 * Each client connects to the server and sends a chunk of data
970 * For each connection, server starts another thread to read the data
971 * from the client and send it back to the client, unmodified.
972 * Each client checks that data received from server is same as the
973 * data it sent to the server.
977 static PRInt32
978 UDP_Socket_Client_Server_Test(void)
980 int i;
981 PRThread *t;
982 PRSemaphore *server_sem;
983 Server_Param *sparamp;
984 Client_Param *cparamp;
985 PRMonitor *mon2;
986 PRInt32 datalen;
987 PRInt32 udp_connect = 1;
990 datalen = udp_datagram_size;
991 thread_count = 0;
993 * start the server thread
995 sparamp = PR_NEW(Server_Param);
996 if (sparamp == NULL) {
997 fprintf(stderr,"prsocket_test: PR_NEW failed\n");
998 failed_already=1;
999 return -1;
1001 server_sem = PR_NewSem(0);
1002 if (server_sem == NULL) {
1003 fprintf(stderr,"prsocket_test: PR_NewSem failed\n");
1004 failed_already=1;
1005 return -1;
1007 mon2 = PR_NewMonitor();
1008 if (mon2 == NULL) {
1009 fprintf(stderr,"prsocket_test: PR_NewMonitor failed\n");
1010 failed_already=1;
1011 return -1;
1013 PR_EnterMonitor(mon2);
1015 sparamp->addr_sem = server_sem;
1016 sparamp->exit_mon = mon2;
1017 sparamp->exit_counter = &thread_count;
1018 sparamp->datalen = datalen;
1019 DPRINTF(("Creating UDP server"));
1020 t = PR_CreateThread(PR_USER_THREAD,
1021 UDP_Server, (void *)sparamp,
1022 PR_PRIORITY_NORMAL,
1023 PR_LOCAL_THREAD,
1024 PR_UNJOINABLE_THREAD,
1026 if (t == NULL) {
1027 fprintf(stderr,"prsocket_test: PR_CreateThread failed\n");
1028 failed_already=1;
1029 return -1;
1031 thread_count++;
1034 * wait till the server address is setup
1036 PR_WaitSem(server_sem);
1039 * Now start a bunch of client threads
1042 for (i = 0; i < num_udp_clients; i++) {
1043 cparamp = PR_NEW(Client_Param);
1044 if (cparamp == NULL) {
1045 fprintf(stderr,"prsocket_test: PR_NEW failed\n");
1046 failed_already=1;
1047 return -1;
1049 cparamp->server_addr = udp_server_addr;
1050 cparamp->exit_mon = mon2;
1051 cparamp->exit_counter = &thread_count;
1052 cparamp->datalen = datalen;
1054 * Cause every other client thread to connect udp sockets
1056 cparamp->udp_connect = udp_connect;
1057 if (udp_connect) {
1058 udp_connect = 0;
1060 else {
1061 udp_connect = 1;
1063 DPRINTF(("Creating UDP client %d\n", i));
1064 t = PR_CreateThread(PR_USER_THREAD,
1065 UDP_Client, (void *) cparamp,
1066 PR_PRIORITY_NORMAL,
1067 PR_LOCAL_THREAD,
1068 PR_UNJOINABLE_THREAD,
1070 if (t == NULL) {
1071 fprintf(stderr,"prsocket_test: PR_CreateThread failed\n");
1072 failed_already=1;
1073 return -1;
1075 thread_count++;
1077 /* Wait for server and client threads to exit */
1078 while (thread_count) {
1079 PR_Wait(mon2, PR_INTERVAL_NO_TIMEOUT);
1080 DPRINTF(("UDP Server - thread_count = %d\n", thread_count));
1082 PR_ExitMonitor(mon2);
1083 printf("%30s","UDP_Socket_Client_Server_Test: ");
1084 printf("%2ld Server %2ld Clients\n",1l, num_udp_clients);
1085 printf("%30s %2ld datagrams_per_client %4ld bytes_per_datagram\n",":",
1086 num_udp_datagrams_per_client, udp_datagram_size);
1088 return 0;
1091 static PRFileDesc *small_file_fd, *large_file_fd;
1092 static void *small_file_addr, *small_file_header, *large_file_addr;
1093 static void *small_file_trailer, *large_file_header, *large_file_trailer;
1095 * TransmitFile_Client
1096 * Client Thread
1098 static void
1099 TransmitFile_Client(void *arg)
1101 PRFileDesc *sockfd;
1102 union PRNetAddr netaddr;
1103 char *small_buf, *large_buf;
1104 Client_Param *cp = (Client_Param *) arg;
1105 PRInt32 rlen;
1107 small_buf = (char*)PR_Malloc(SMALL_FILE_SIZE + SMALL_FILE_HEADER_SIZE +
1108 SMALL_FILE_TRAILER_SIZE);
1109 if (small_buf == NULL) {
1110 fprintf(stderr,"prsocket_test: failed to alloc buffer\n");
1111 failed_already=1;
1112 return;
1114 large_buf = (char*)PR_Malloc(LARGE_FILE_SIZE + LARGE_FILE_HEADER_SIZE +
1115 LARGE_FILE_TRAILER_SIZE);
1116 if (large_buf == NULL) {
1117 fprintf(stderr,"prsocket_test: failed to alloc buffer\n");
1118 failed_already=1;
1119 return;
1121 netaddr.inet.family = cp->server_addr.inet.family;
1122 netaddr.inet.port = cp->server_addr.inet.port;
1123 netaddr.inet.ip = cp->server_addr.inet.ip;
1125 if ((sockfd = PR_NewTCPSocket()) == NULL) {
1126 fprintf(stderr,"prsocket_test: PR_NewTCPSocket failed\n");
1127 failed_already=1;
1128 return;
1131 if (PR_Connect(sockfd, &netaddr,PR_INTERVAL_NO_TIMEOUT) < 0) {
1132 fprintf(stderr,"prsocket_test: PR_Connect failed\n");
1133 failed_already=1;
1134 return;
1137 * read the small file and verify the data
1139 if (readn(sockfd, small_buf, SMALL_FILE_SIZE + SMALL_FILE_HEADER_SIZE)
1140 != (SMALL_FILE_SIZE + SMALL_FILE_HEADER_SIZE)) {
1141 fprintf(stderr,
1142 "prsocket_test: TransmitFile_Client failed to receive file\n");
1143 failed_already=1;
1144 return;
1146 #if defined(XP_UNIX)
1147 /* File transmission test can not be done because of large file's size */
1148 if (memcmp(small_file_header, small_buf, SMALL_FILE_HEADER_SIZE) != 0) {
1149 fprintf(stderr,
1150 "prsocket_test: TransmitFile_Client ERROR - small file header data corruption\n");
1151 failed_already=1;
1152 return;
1154 if (memcmp(small_file_addr, small_buf + SMALL_FILE_HEADER_SIZE,
1155 SMALL_FILE_SIZE) != 0) {
1156 fprintf(stderr,
1157 "prsocket_test: TransmitFile_Client ERROR - small file data corruption\n");
1158 failed_already=1;
1159 return;
1161 #endif
1163 * read the large file and verify the data
1165 if (readn(sockfd, large_buf, LARGE_FILE_SIZE) != LARGE_FILE_SIZE) {
1166 fprintf(stderr,
1167 "prsocket_test: TransmitFile_Client failed to receive file\n");
1168 failed_already=1;
1169 return;
1171 #if defined(XP_UNIX)
1172 if (memcmp(large_file_addr, large_buf, LARGE_FILE_SIZE) != 0) {
1173 fprintf(stderr,
1174 "prsocket_test: TransmitFile_Client ERROR - large file data corruption\n");
1175 failed_already=1;
1177 #endif
1181 * receive data from PR_SendFile
1184 * case 1: small file with header and trailer
1186 rlen = SMALL_FILE_SIZE + SMALL_FILE_HEADER_SIZE +
1187 SMALL_FILE_TRAILER_SIZE;
1188 if (readn(sockfd, small_buf, rlen) != rlen) {
1189 fprintf(stderr,
1190 "prsocket_test: SendFile_Client failed to receive file\n");
1191 failed_already=1;
1192 return;
1194 #if defined(XP_UNIX)
1195 if (memcmp(small_file_header, small_buf, SMALL_FILE_HEADER_SIZE) != 0) {
1196 fprintf(stderr,
1197 "SendFile 1. ERROR - small file header corruption\n");
1198 failed_already=1;
1199 return;
1201 if (memcmp(small_file_addr, small_buf + SMALL_FILE_HEADER_SIZE,
1202 SMALL_FILE_SIZE) != 0) {
1203 fprintf(stderr,
1204 "SendFile 1. ERROR - small file data corruption\n");
1205 failed_already=1;
1206 return;
1208 if (memcmp(small_file_trailer,
1209 small_buf + SMALL_FILE_HEADER_SIZE + SMALL_FILE_SIZE,
1210 SMALL_FILE_TRAILER_SIZE) != 0) {
1211 fprintf(stderr,
1212 "SendFile 1. ERROR - small file trailer corruption\n");
1213 failed_already=1;
1214 return;
1216 #endif
1218 * case 2: partial large file at zero offset, file with header and trailer
1220 rlen = LARGE_FILE_LEN_1 + LARGE_FILE_HEADER_SIZE +
1221 LARGE_FILE_TRAILER_SIZE;
1222 if (readn(sockfd, large_buf, rlen) != rlen) {
1223 fprintf(stderr,
1224 "prsocket_test: SendFile_Client failed to receive file\n");
1225 failed_already=1;
1226 return;
1228 #if defined(XP_UNIX)
1229 if (memcmp(large_file_header, large_buf, LARGE_FILE_HEADER_SIZE) != 0) {
1230 fprintf(stderr,
1231 "SendFile 2. ERROR - large file header corruption\n");
1232 failed_already=1;
1233 return;
1235 if (memcmp(large_file_addr, large_buf + LARGE_FILE_HEADER_SIZE,
1236 LARGE_FILE_LEN_1) != 0) {
1237 fprintf(stderr,
1238 "SendFile 2. ERROR - large file data corruption\n");
1239 failed_already=1;
1240 return;
1242 if (memcmp(large_file_trailer,
1243 large_buf + LARGE_FILE_HEADER_SIZE + LARGE_FILE_LEN_1,
1244 LARGE_FILE_TRAILER_SIZE) != 0) {
1245 fprintf(stderr,
1246 "SendFile 2. ERROR - large file trailer corruption\n");
1247 failed_already=1;
1248 return;
1250 #endif
1252 * case 3: partial small file at non-zero offset, with header
1254 rlen = SMALL_FILE_LEN_1 + SMALL_FILE_HEADER_SIZE;
1255 if (readn(sockfd, small_buf, rlen) != rlen) {
1256 fprintf(stderr,
1257 "prsocket_test: SendFile_Client failed to receive file\n");
1258 failed_already=1;
1259 return;
1261 #if defined(XP_UNIX)
1262 if (memcmp(small_file_header, small_buf, SMALL_FILE_HEADER_SIZE) != 0) {
1263 fprintf(stderr,
1264 "SendFile 3. ERROR - small file header corruption\n");
1265 failed_already=1;
1266 return;
1268 if (memcmp((char *) small_file_addr + SMALL_FILE_OFFSET_1,
1269 small_buf + SMALL_FILE_HEADER_SIZE, SMALL_FILE_LEN_1) != 0) {
1270 fprintf(stderr,
1271 "SendFile 3. ERROR - small file data corruption\n");
1272 failed_already=1;
1273 return;
1275 #endif
1277 * case 4: partial small file at non-zero offset, with trailer
1279 rlen = SMALL_FILE_LEN_2 + SMALL_FILE_TRAILER_SIZE;
1280 if (readn(sockfd, small_buf, rlen) != rlen) {
1281 fprintf(stderr,
1282 "prsocket_test: SendFile_Client failed to receive file\n");
1283 failed_already=1;
1284 return;
1286 #if defined(XP_UNIX)
1287 if (memcmp((char *) small_file_addr + SMALL_FILE_OFFSET_2, small_buf,
1288 SMALL_FILE_LEN_2) != 0) {
1289 fprintf(stderr,
1290 "SendFile 4. ERROR - small file data corruption\n");
1291 failed_already=1;
1292 return;
1294 if (memcmp(small_file_trailer, small_buf + SMALL_FILE_LEN_2,
1295 SMALL_FILE_TRAILER_SIZE) != 0) {
1296 fprintf(stderr,
1297 "SendFile 4. ERROR - small file trailer corruption\n");
1298 failed_already=1;
1299 return;
1301 #endif
1303 * case 5: partial large file at non-zero offset, file with header
1305 rlen = LARGE_FILE_LEN_2 + LARGE_FILE_HEADER_SIZE;
1306 if (readn(sockfd, large_buf, rlen) != rlen) {
1307 fprintf(stderr,
1308 "prsocket_test: SendFile_Client failed to receive file\n");
1309 failed_already=1;
1310 return;
1312 #if defined(XP_UNIX)
1313 if (memcmp(large_file_header, large_buf, LARGE_FILE_HEADER_SIZE) != 0) {
1314 fprintf(stderr,
1315 "SendFile 5. ERROR - large file header corruption\n");
1316 failed_already=1;
1317 return;
1319 if (memcmp((char *)large_file_addr + LARGE_FILE_OFFSET_2,
1320 large_buf + LARGE_FILE_HEADER_SIZE,
1321 LARGE_FILE_LEN_2) != 0) {
1322 fprintf(stderr,
1323 "SendFile 5. ERROR - large file data corruption\n");
1324 failed_already=1;
1325 return;
1327 #endif
1329 * case 6: partial small file at non-zero offset, with header
1331 rlen = SMALL_FILE_LEN_3 + SMALL_FILE_HEADER_SIZE;
1332 if (readn(sockfd, small_buf, rlen) != rlen) {
1333 fprintf(stderr,
1334 "prsocket_test: SendFile_Client failed to receive file\n");
1335 failed_already=1;
1336 return;
1338 #if defined(XP_UNIX)
1339 if (memcmp(small_file_header, small_buf, SMALL_FILE_HEADER_SIZE) != 0) {
1340 fprintf(stderr,
1341 "SendFile 6. ERROR - small file header corruption\n");
1342 return;
1344 if (memcmp((char *) small_file_addr + SMALL_FILE_OFFSET_3,
1345 small_buf + SMALL_FILE_HEADER_SIZE, SMALL_FILE_LEN_3) != 0) {
1346 #if 0
1347 char *i, *j;
1348 int k;
1350 i = (char *) small_file_addr + SMALL_FILE_OFFSET_3;
1351 j = small_buf + SMALL_FILE_HEADER_SIZE;
1352 k = SMALL_FILE_LEN_3;
1353 while (k-- > 0) {
1354 if (*i++ != *j++)
1355 printf("i = %d j = %d\n",
1356 (int) (i - ((char *) small_file_addr + SMALL_FILE_OFFSET_3)),
1357 (int) (j - (small_buf + SMALL_FILE_HEADER_SIZE)));
1359 #endif
1360 fprintf(stderr,
1361 "SendFile 6. ERROR - small file data corruption\n");
1362 failed_already=1;
1363 return;
1365 #endif
1367 * case 7: partial large file at non-zero offset, with header
1369 rlen = LARGE_FILE_LEN_3 + LARGE_FILE_HEADER_SIZE;
1370 if (readn(sockfd, large_buf, rlen) != rlen) {
1371 fprintf(stderr,
1372 "prsocket_test: SendFile_Client failed to receive file\n");
1373 failed_already=1;
1374 return;
1376 #if defined(XP_UNIX)
1377 if (memcmp(large_file_header, large_buf, LARGE_FILE_HEADER_SIZE) != 0) {
1378 fprintf(stderr,
1379 "SendFile 7. ERROR - large file header corruption\n");
1380 failed_already=1;
1381 return;
1383 if (memcmp((char *)large_file_addr + LARGE_FILE_OFFSET_3,
1384 large_buf + LARGE_FILE_HEADER_SIZE,
1385 LARGE_FILE_LEN_3) != 0) {
1386 fprintf(stderr,
1387 "SendFile 7. ERROR - large file data corruption\n");
1388 failed_already=1;
1389 return;
1391 #endif
1393 * case 8: partial large file at non-zero, page-aligned offset, with
1394 * header and trailer
1396 rlen = LARGE_FILE_LEN_4 + LARGE_FILE_HEADER_SIZE +
1397 LARGE_FILE_TRAILER_SIZE;
1398 if (readn(sockfd, large_buf, rlen) != rlen) {
1399 fprintf(stderr,
1400 "prsocket_test: SendFile_Client failed to receive file\n");
1401 failed_already=1;
1402 return;
1404 #if defined(XP_UNIX)
1405 if (memcmp(large_file_header, large_buf, LARGE_FILE_HEADER_SIZE) != 0) {
1406 fprintf(stderr,
1407 "SendFile 2. ERROR - large file header corruption\n");
1408 failed_already=1;
1409 return;
1411 if (memcmp((char *)large_file_addr + LARGE_FILE_OFFSET_4,
1412 large_buf + LARGE_FILE_HEADER_SIZE,
1413 LARGE_FILE_LEN_4) != 0) {
1414 fprintf(stderr,
1415 "SendFile 2. ERROR - large file data corruption\n");
1416 failed_already=1;
1417 return;
1419 if (memcmp(large_file_trailer,
1420 large_buf + LARGE_FILE_HEADER_SIZE + LARGE_FILE_LEN_4,
1421 LARGE_FILE_TRAILER_SIZE) != 0) {
1422 fprintf(stderr,
1423 "SendFile 2. ERROR - large file trailer corruption\n");
1424 failed_already=1;
1425 return;
1427 #endif
1428 PR_DELETE(small_buf);
1429 PR_DELETE(large_buf);
1430 PR_Close(sockfd);
1434 * Decrement exit_counter and notify parent thread
1437 PR_EnterMonitor(cp->exit_mon);
1438 --(*cp->exit_counter);
1439 PR_Notify(cp->exit_mon);
1440 PR_ExitMonitor(cp->exit_mon);
1441 DPRINTF(("TransmitFile_Client [0x%lx] exiting\n", PR_GetCurrentThread()));
1445 * Serve_TransmitFile_Client
1446 * Thread, started by the server, for serving a client connection.
1447 * Trasmits a small file, with a header, and a large file, without
1448 * a header
1450 static void
1451 Serve_TransmitFile_Client(void *arg)
1453 Serve_Client_Param *scp = (Serve_Client_Param *) arg;
1454 PRFileDesc *sockfd;
1455 PRInt32 bytes;
1456 PRFileDesc *local_small_file_fd=NULL;
1457 PRFileDesc *local_large_file_fd=NULL;
1458 PRSendFileData sfd;
1459 PRInt32 slen;
1461 sockfd = scp->sockfd;
1462 local_small_file_fd = PR_Open(SMALL_FILE_NAME, PR_RDONLY,0);
1464 if (local_small_file_fd == NULL) {
1465 fprintf(stderr,"prsocket_test failed to open file for transmitting %s\n",
1466 SMALL_FILE_NAME);
1467 failed_already=1;
1468 goto done;
1470 local_large_file_fd = PR_Open(LARGE_FILE_NAME, PR_RDONLY,0);
1472 if (local_large_file_fd == NULL) {
1473 fprintf(stderr,"prsocket_test failed to open file for transmitting %s\n",
1474 LARGE_FILE_NAME);
1475 failed_already=1;
1476 goto done;
1478 bytes = PR_TransmitFile(sockfd, local_small_file_fd, small_file_header,
1479 SMALL_FILE_HEADER_SIZE, PR_TRANSMITFILE_KEEP_OPEN,
1480 PR_INTERVAL_NO_TIMEOUT);
1481 if (bytes != (SMALL_FILE_SIZE+ SMALL_FILE_HEADER_SIZE)) {
1482 fprintf(stderr,
1483 "prsocet_test: PR_TransmitFile failed: (%ld, %ld)\n",
1484 PR_GetError(), PR_GetOSError());
1485 failed_already=1;
1487 bytes = PR_TransmitFile(sockfd, local_large_file_fd, NULL, 0,
1488 PR_TRANSMITFILE_KEEP_OPEN, PR_INTERVAL_NO_TIMEOUT);
1489 if (bytes != LARGE_FILE_SIZE) {
1490 fprintf(stderr,
1491 "prsocket_test: PR_TransmitFile failed: (%ld, %ld)\n",
1492 PR_GetError(), PR_GetOSError());
1493 failed_already=1;
1497 * PR_SendFile test cases
1501 * case 1: small file with header and trailer
1503 sfd.fd = local_small_file_fd;
1504 sfd.file_offset = 0;
1505 sfd.file_nbytes = 0;
1506 sfd.header = small_file_header;
1507 sfd.hlen = SMALL_FILE_HEADER_SIZE;
1508 sfd.trailer = small_file_trailer;
1509 sfd.tlen = SMALL_FILE_TRAILER_SIZE;
1510 bytes = PR_SendFile(sockfd, &sfd, PR_TRANSMITFILE_KEEP_OPEN,
1511 PR_INTERVAL_NO_TIMEOUT);
1512 slen = SMALL_FILE_SIZE+ SMALL_FILE_HEADER_SIZE +
1513 SMALL_FILE_TRAILER_SIZE;
1514 if (bytes != slen) {
1515 fprintf(stderr,
1516 "socket: Error - 1. PR_SendFile send_size = %d, bytes sent = %d\n",
1517 slen, bytes);
1518 fprintf(stderr,
1519 "prsocket_test: PR_SendFile failed: (%ld, %ld)\n",
1520 PR_GetError(), PR_GetOSError());
1521 failed_already=1;
1525 * case 2: partial large file at zero offset, file with header and trailer
1527 sfd.fd = local_large_file_fd;
1528 sfd.file_offset = 0;
1529 sfd.file_nbytes = LARGE_FILE_LEN_1;
1530 sfd.header = large_file_header;
1531 sfd.hlen = LARGE_FILE_HEADER_SIZE;
1532 sfd.trailer = large_file_trailer;
1533 sfd.tlen = LARGE_FILE_TRAILER_SIZE;
1534 bytes = PR_SendFile(sockfd, &sfd, PR_TRANSMITFILE_KEEP_OPEN,
1535 PR_INTERVAL_NO_TIMEOUT);
1536 slen = LARGE_FILE_LEN_1 + LARGE_FILE_HEADER_SIZE +
1537 LARGE_FILE_TRAILER_SIZE;
1538 if (bytes != slen) {
1539 fprintf(stderr,
1540 "socket: Error - 2. PR_SendFile send_size = %d, bytes sent = %d\n",
1541 slen, bytes);
1542 fprintf(stderr,
1543 "prsocket_test: PR_SendFile failed: (%ld, %ld)\n",
1544 PR_GetError(), PR_GetOSError());
1545 failed_already=1;
1548 * case 3: partial small file at non-zero offset, with header
1550 sfd.fd = local_small_file_fd;
1551 sfd.file_offset = SMALL_FILE_OFFSET_1;
1552 sfd.file_nbytes = SMALL_FILE_LEN_1;
1553 sfd.header = small_file_header;
1554 sfd.hlen = SMALL_FILE_HEADER_SIZE;
1555 sfd.trailer = NULL;
1556 sfd.tlen = 0;
1557 bytes = PR_SendFile(sockfd, &sfd, PR_TRANSMITFILE_KEEP_OPEN,
1558 PR_INTERVAL_NO_TIMEOUT);
1559 slen = SMALL_FILE_LEN_1 + SMALL_FILE_HEADER_SIZE;
1560 if (bytes != slen) {
1561 fprintf(stderr,
1562 "socket: Error - 3. PR_SendFile send_size = %d, bytes sent = %d\n",
1563 slen, bytes);
1564 fprintf(stderr,
1565 "prsocket_test: PR_SendFile failed: (%ld, %ld)\n",
1566 PR_GetError(), PR_GetOSError());
1567 failed_already=1;
1570 * case 4: partial small file at non-zero offset, with trailer
1572 sfd.fd = local_small_file_fd;
1573 sfd.file_offset = SMALL_FILE_OFFSET_2;
1574 sfd.file_nbytes = SMALL_FILE_LEN_2;
1575 sfd.header = NULL;
1576 sfd.hlen = 0;
1577 sfd.trailer = small_file_trailer;
1578 sfd.tlen = SMALL_FILE_TRAILER_SIZE;
1579 bytes = PR_SendFile(sockfd, &sfd, PR_TRANSMITFILE_KEEP_OPEN,
1580 PR_INTERVAL_NO_TIMEOUT);
1581 slen = SMALL_FILE_LEN_2 + SMALL_FILE_TRAILER_SIZE;
1582 if (bytes != slen) {
1583 fprintf(stderr,
1584 "socket: Error - 4. PR_SendFile send_size = %d, bytes sent = %d\n",
1585 slen, bytes);
1586 fprintf(stderr,
1587 "prsocket_test: PR_SendFile failed: (%ld, %ld)\n",
1588 PR_GetError(), PR_GetOSError());
1589 failed_already=1;
1592 * case 5: partial large file at non-zero offset, file with header
1594 sfd.fd = local_large_file_fd;
1595 sfd.file_offset = LARGE_FILE_OFFSET_2;
1596 sfd.file_nbytes = LARGE_FILE_LEN_2;
1597 sfd.header = large_file_header;
1598 sfd.hlen = LARGE_FILE_HEADER_SIZE;
1599 sfd.trailer = NULL;
1600 sfd.tlen = 0;
1601 bytes = PR_SendFile(sockfd, &sfd, PR_TRANSMITFILE_KEEP_OPEN,
1602 PR_INTERVAL_NO_TIMEOUT);
1603 slen = LARGE_FILE_LEN_2 + LARGE_FILE_HEADER_SIZE;
1604 if (bytes != slen) {
1605 fprintf(stderr,
1606 "socket: Error - 5. PR_SendFile send_size = %d, bytes sent = %d\n",
1607 slen, bytes);
1608 fprintf(stderr,
1609 "prsocket_test: PR_SendFile failed: (%ld, %ld)\n",
1610 PR_GetError(), PR_GetOSError());
1611 failed_already=1;
1614 * case 6: partial small file from non-zero offset till end of file, with header
1616 sfd.fd = local_small_file_fd;
1617 sfd.file_offset = SMALL_FILE_OFFSET_3;
1618 sfd.file_nbytes = 0; /* data from offset to end-of-file */
1619 sfd.header = small_file_header;
1620 sfd.hlen = SMALL_FILE_HEADER_SIZE;
1621 sfd.trailer = NULL;
1622 sfd.tlen = 0;
1623 bytes = PR_SendFile(sockfd, &sfd, PR_TRANSMITFILE_KEEP_OPEN,
1624 PR_INTERVAL_NO_TIMEOUT);
1625 slen = SMALL_FILE_LEN_3 + SMALL_FILE_HEADER_SIZE;
1626 if (bytes != slen) {
1627 fprintf(stderr,
1628 "socket: Error - 6. PR_SendFile send_size = %d, bytes sent = %d\n",
1629 slen, bytes);
1630 fprintf(stderr,
1631 "prsocket_test: PR_SendFile failed: (%ld, %ld)\n",
1632 PR_GetError(), PR_GetOSError());
1633 failed_already=1;
1636 * case 7: partial large file at non-zero offset till end-of-file, with header
1638 sfd.fd = local_large_file_fd;
1639 sfd.file_offset = LARGE_FILE_OFFSET_3;
1640 sfd.file_nbytes = 0; /* data until end-of-file */
1641 sfd.header = large_file_header;
1642 sfd.hlen = LARGE_FILE_HEADER_SIZE;
1643 sfd.trailer = NULL;
1644 sfd.tlen = 0;
1645 bytes = PR_SendFile(sockfd, &sfd, PR_TRANSMITFILE_KEEP_OPEN,
1646 PR_INTERVAL_NO_TIMEOUT);
1647 slen = LARGE_FILE_LEN_3 + LARGE_FILE_HEADER_SIZE;
1648 if (bytes != slen) {
1649 fprintf(stderr,
1650 "socket: Error - 7. PR_SendFile send_size = %d, bytes sent = %d\n",
1651 slen, bytes);
1652 fprintf(stderr,
1653 "prsocket_test: PR_SendFile failed: (%ld, %ld)\n",
1654 PR_GetError(), PR_GetOSError());
1655 failed_already=1;
1658 * case 8: partial large file at non-zero page-aligned offset,
1659 * with header and trailer
1661 sfd.fd = local_large_file_fd;
1662 sfd.file_offset = LARGE_FILE_OFFSET_4;
1663 sfd.file_nbytes = LARGE_FILE_LEN_4;
1664 sfd.header = large_file_header;
1665 sfd.hlen = LARGE_FILE_HEADER_SIZE;
1666 sfd.trailer = large_file_trailer;
1667 sfd.tlen = LARGE_FILE_TRAILER_SIZE;
1668 bytes = PR_SendFile(sockfd, &sfd, PR_TRANSMITFILE_CLOSE_SOCKET,
1669 PR_INTERVAL_NO_TIMEOUT);
1670 slen = LARGE_FILE_LEN_4 + LARGE_FILE_HEADER_SIZE +
1671 LARGE_FILE_TRAILER_SIZE;
1672 if (bytes != slen) {
1673 fprintf(stderr,
1674 "socket: Error - 2. PR_SendFile send_size = %d, bytes sent = %d\n",
1675 slen, bytes);
1676 fprintf(stderr,
1677 "prsocket_test: PR_SendFile failed: (%ld, %ld)\n",
1678 PR_GetError(), PR_GetOSError());
1679 failed_already=1;
1681 done:
1682 if (local_small_file_fd != NULL) {
1683 PR_Close(local_small_file_fd);
1685 if (local_large_file_fd != NULL) {
1686 PR_Close(local_large_file_fd);
1691 * TransmitFile Server
1692 * Server Thread
1693 * Bind an address to a socket and listen for incoming connections
1694 * Create worker threads to service clients
1696 static void
1697 TransmitFile_Server(void *arg)
1699 PRThread **t = NULL; /* an array of PRThread pointers */
1700 Server_Param *sp = (Server_Param *) arg;
1701 Serve_Client_Param *scp;
1702 PRFileDesc *sockfd = NULL, *newsockfd;
1703 PRNetAddr netaddr;
1704 PRInt32 i;
1706 t = (PRThread**)PR_MALLOC(num_transmitfile_clients * sizeof(PRThread *));
1707 if (t == NULL) {
1708 fprintf(stderr, "prsocket_test: run out of memory\n");
1709 failed_already=1;
1710 goto exit;
1713 * Create a tcp socket
1715 if ((sockfd = PR_OpenTCPSocket(PR_AF_INET)) == NULL) {
1716 fprintf(stderr,"prsocket_test: PR_OpenTCPSocket failed\n");
1717 failed_already=1;
1718 goto exit;
1720 memset(&netaddr, 0, sizeof(netaddr));
1721 netaddr.inet.family = PR_AF_INET;
1722 netaddr.inet.port = PR_htons(TCP_SERVER_PORT);
1723 netaddr.inet.ip = PR_htonl(PR_INADDR_ANY);
1725 * try a few times to bind server's address, if addresses are in
1726 * use
1728 i = 0;
1729 while (PR_Bind(sockfd, &netaddr) < 0) {
1730 if (PR_GetError() == PR_ADDRESS_IN_USE_ERROR) {
1731 netaddr.inet.port += 2;
1732 if (i++ < SERVER_MAX_BIND_COUNT) {
1733 continue;
1736 fprintf(stderr,"prsocket_test: ERROR - PR_Bind failed\n");
1737 failed_already=1;
1738 perror("PR_Bind");
1739 goto exit;
1742 if (PR_Listen(sockfd, 32) < 0) {
1743 fprintf(stderr,"prsocket_test: ERROR - PR_Listen failed\n");
1744 failed_already=1;
1745 goto exit;
1748 if (PR_GetSockName(sockfd, &netaddr) < 0) {
1749 fprintf(stderr,
1750 "prsocket_test: ERROR - PR_GetSockName failed\n");
1751 failed_already=1;
1752 goto exit;
1755 DPRINTF(("TCP_Server: PR_BIND netaddr.inet.ip = 0x%lx, netaddr.inet.port = %d\n",
1756 netaddr.inet.ip, netaddr.inet.port));
1757 tcp_server_addr.inet.family = netaddr.inet.family;
1758 tcp_server_addr.inet.port = netaddr.inet.port;
1759 tcp_server_addr.inet.ip = netaddr.inet.ip;
1762 * Wake up parent thread because server address is bound and made
1763 * available in the global variable 'tcp_server_addr'
1765 PR_PostSem(sp->addr_sem);
1767 for (i = 0; i < num_transmitfile_clients ; i++) {
1768 /* test both null and non-null 'addr' argument to PR_Accept */
1769 PRNetAddr *addrp = (i%2 ? &netaddr: NULL);
1771 if ((newsockfd = PR_Accept(sockfd, addrp,
1772 PR_INTERVAL_NO_TIMEOUT)) == NULL) {
1773 fprintf(stderr,
1774 "prsocket_test: ERROR - PR_Accept failed\n");
1775 failed_already=1;
1776 goto exit;
1778 /* test both regular and emulated PR_SendFile */
1779 if (i%2) {
1780 PRFileDesc *layer = PR_CreateIOLayerStub(
1781 emuSendFileIdentity, &emuSendFileMethods);
1782 if (layer == NULL) {
1783 fprintf(stderr,
1784 "prsocket_test: ERROR - PR_CreateIOLayerStub failed\n");
1785 failed_already=1;
1786 goto exit;
1788 if (PR_PushIOLayer(newsockfd, PR_TOP_IO_LAYER, layer)
1789 == PR_FAILURE) {
1790 fprintf(stderr,
1791 "prsocket_test: ERROR - PR_PushIOLayer failed\n");
1792 failed_already=1;
1793 goto exit;
1796 scp = PR_NEW(Serve_Client_Param);
1797 if (scp == NULL) {
1798 fprintf(stderr,"prsocket_test: PR_NEW failed\n");
1799 failed_already=1;
1800 goto exit;
1804 * Start a Serve_Client thread for each incoming connection
1806 scp->sockfd = newsockfd;
1807 scp->datalen = sp->datalen;
1809 t[i] = PR_CreateThread(PR_USER_THREAD,
1810 Serve_TransmitFile_Client, (void *)scp,
1811 PR_PRIORITY_NORMAL,
1812 PR_LOCAL_THREAD,
1813 PR_JOINABLE_THREAD,
1815 if (t[i] == NULL) {
1816 fprintf(stderr,
1817 "prsocket_test: PR_CreateThread failed\n");
1818 failed_already=1;
1819 goto exit;
1821 DPRINTF(("TransmitFile_Server: Created Serve_TransmitFile_Client = 0x%lx\n", t));
1825 * Wait for all the worker threads to end, so that we know
1826 * they are no longer using the small and large file fd's.
1829 for (i = 0; i < num_transmitfile_clients; i++) {
1830 PR_JoinThread(t[i]);
1833 exit:
1834 if (t) {
1835 PR_DELETE(t);
1837 if (sockfd) {
1838 PR_Close(sockfd);
1842 * Decrement exit_counter and notify parent thread
1845 PR_EnterMonitor(sp->exit_mon);
1846 --(*sp->exit_counter);
1847 PR_Notify(sp->exit_mon);
1848 PR_ExitMonitor(sp->exit_mon);
1849 DPRINTF(("TransmitFile_Server [0x%lx] exiting\n", PR_GetCurrentThread()));
1853 * Socket_Misc_Test - test miscellaneous functions
1856 static PRInt32
1857 Socket_Misc_Test(void)
1859 PRIntn i, rv = 0, bytes, count, len;
1860 PRThread *t;
1861 PRSemaphore *server_sem;
1862 Server_Param *sparamp;
1863 Client_Param *cparamp;
1864 PRMonitor *mon2;
1865 PRInt32 datalen;
1868 * We deliberately pick a buffer size that is not a nice multiple
1869 * of 1024.
1871 #define TRANSMITFILE_BUF_SIZE (4 * 1024 - 11)
1873 typedef struct {
1874 char data[TRANSMITFILE_BUF_SIZE];
1875 } file_buf;
1876 file_buf *buf = NULL;
1879 * create file(s) to be transmitted
1881 if ((PR_MkDir(TEST_DIR, 0777)) < 0) {
1882 printf("prsocket_test failed to create dir %s\n",TEST_DIR);
1883 failed_already=1;
1884 return -1;
1887 small_file_fd = PR_Open(SMALL_FILE_NAME, PR_RDWR | PR_CREATE_FILE,0777);
1889 if (small_file_fd == NULL) {
1890 fprintf(stderr,"prsocket_test failed to create/open file %s\n",
1891 SMALL_FILE_NAME);
1892 failed_already=1;
1893 rv = -1;
1894 goto done;
1896 buf = PR_NEW(file_buf);
1897 if (buf == NULL) {
1898 fprintf(stderr,"prsocket_test failed to allocate buffer\n");
1899 failed_already=1;
1900 rv = -1;
1901 goto done;
1904 * fill in random data
1906 for (i = 0; i < TRANSMITFILE_BUF_SIZE; i++) {
1907 buf->data[i] = i;
1909 count = 0;
1910 do {
1911 len = (SMALL_FILE_SIZE - count) > TRANSMITFILE_BUF_SIZE ?
1912 TRANSMITFILE_BUF_SIZE : (SMALL_FILE_SIZE - count);
1913 bytes = PR_Write(small_file_fd, buf->data, len);
1914 if (bytes <= 0) {
1915 fprintf(stderr,
1916 "prsocket_test failed to write to file %s\n",
1917 SMALL_FILE_NAME);
1918 failed_already=1;
1919 rv = -1;
1920 goto done;
1922 count += bytes;
1923 } while (count < SMALL_FILE_SIZE);
1924 #ifdef XP_UNIX
1926 * map the small file; used in checking for data corruption
1928 small_file_addr = mmap(0, SMALL_FILE_SIZE, PROT_READ,
1929 MAP_SHARED, small_file_fd->secret->md.osfd, 0);
1930 if (small_file_addr == (void *) -1) {
1931 fprintf(stderr,"prsocket_test failed to mmap file %s\n",
1932 SMALL_FILE_NAME);
1933 failed_already=1;
1934 rv = -1;
1935 goto done;
1937 #endif
1939 * header for small file
1941 small_file_header = PR_MALLOC(SMALL_FILE_HEADER_SIZE);
1942 if (small_file_header == NULL) {
1943 fprintf(stderr,"prsocket_test failed to malloc header file\n");
1944 failed_already=1;
1945 rv = -1;
1946 goto done;
1948 memset(small_file_header, (int) PR_IntervalNow(),
1949 SMALL_FILE_HEADER_SIZE);
1951 * trailer for small file
1953 small_file_trailer = PR_MALLOC(SMALL_FILE_TRAILER_SIZE);
1954 if (small_file_trailer == NULL) {
1955 fprintf(stderr,"prsocket_test failed to malloc header trailer\n");
1956 failed_already=1;
1957 rv = -1;
1958 goto done;
1960 memset(small_file_trailer, (int) PR_IntervalNow(),
1961 SMALL_FILE_TRAILER_SIZE);
1963 * setup large file
1965 large_file_fd = PR_Open(LARGE_FILE_NAME, PR_RDWR | PR_CREATE_FILE,0777);
1967 if (large_file_fd == NULL) {
1968 fprintf(stderr,"prsocket_test failed to create/open file %s\n",
1969 LARGE_FILE_NAME);
1970 failed_already=1;
1971 rv = -1;
1972 goto done;
1975 * fill in random data
1977 for (i = 0; i < TRANSMITFILE_BUF_SIZE; i++) {
1978 buf->data[i] = i;
1980 count = 0;
1981 do {
1982 len = (LARGE_FILE_SIZE - count) > TRANSMITFILE_BUF_SIZE ?
1983 TRANSMITFILE_BUF_SIZE : (LARGE_FILE_SIZE - count);
1984 bytes = PR_Write(large_file_fd, buf->data, len);
1985 if (bytes <= 0) {
1986 fprintf(stderr,
1987 "prsocket_test failed to write to file %s: (%ld, %ld)\n",
1988 LARGE_FILE_NAME,
1989 PR_GetError(), PR_GetOSError());
1990 failed_already=1;
1991 rv = -1;
1992 goto done;
1994 count += bytes;
1995 } while (count < LARGE_FILE_SIZE);
1996 #if defined(XP_UNIX)
1998 * map the large file; used in checking for data corruption
2000 large_file_addr = mmap(0, LARGE_FILE_SIZE, PROT_READ,
2001 MAP_SHARED, large_file_fd->secret->md.osfd, 0);
2002 if (large_file_addr == (void *) -1) {
2003 fprintf(stderr,"prsocket_test failed to mmap file %s\n",
2004 LARGE_FILE_NAME);
2005 failed_already=1;
2006 rv = -1;
2007 goto done;
2009 #endif
2011 * header for large file
2013 large_file_header = PR_MALLOC(LARGE_FILE_HEADER_SIZE);
2014 if (large_file_header == NULL) {
2015 fprintf(stderr,"prsocket_test failed to malloc header file\n");
2016 failed_already=1;
2017 rv = -1;
2018 goto done;
2020 memset(large_file_header, (int) PR_IntervalNow(),
2021 LARGE_FILE_HEADER_SIZE);
2023 * trailer for large file
2025 large_file_trailer = PR_MALLOC(LARGE_FILE_TRAILER_SIZE);
2026 if (large_file_trailer == NULL) {
2027 fprintf(stderr,"prsocket_test failed to malloc header trailer\n");
2028 failed_already=1;
2029 rv = -1;
2030 goto done;
2032 memset(large_file_trailer, (int) PR_IntervalNow(),
2033 LARGE_FILE_TRAILER_SIZE);
2035 datalen = tcp_mesg_size;
2036 thread_count = 0;
2038 * start the server thread
2040 sparamp = PR_NEW(Server_Param);
2041 if (sparamp == NULL) {
2042 fprintf(stderr,"prsocket_test: PR_NEW failed\n");
2043 failed_already=1;
2044 rv = -1;
2045 goto done;
2047 server_sem = PR_NewSem(0);
2048 if (server_sem == NULL) {
2049 fprintf(stderr,"prsocket_test: PR_NewSem failed\n");
2050 failed_already=1;
2051 rv = -1;
2052 goto done;
2054 mon2 = PR_NewMonitor();
2055 if (mon2 == NULL) {
2056 fprintf(stderr,"prsocket_test: PR_NewMonitor failed\n");
2057 failed_already=1;
2058 rv = -1;
2059 goto done;
2061 PR_EnterMonitor(mon2);
2063 sparamp->addr_sem = server_sem;
2064 sparamp->exit_mon = mon2;
2065 sparamp->exit_counter = &thread_count;
2066 sparamp->datalen = datalen;
2067 t = PR_CreateThread(PR_USER_THREAD,
2068 TransmitFile_Server, (void *)sparamp,
2069 PR_PRIORITY_NORMAL,
2070 PR_LOCAL_THREAD,
2071 PR_UNJOINABLE_THREAD,
2073 if (t == NULL) {
2074 fprintf(stderr,"prsocket_test: PR_CreateThread failed\n");
2075 failed_already=1;
2076 rv = -1;
2077 goto done;
2079 DPRINTF(("Created TCP server = 0x%x\n", t));
2080 thread_count++;
2083 * wait till the server address is setup
2085 PR_WaitSem(server_sem);
2088 * Now start a bunch of client threads
2091 cparamp = PR_NEW(Client_Param);
2092 if (cparamp == NULL) {
2093 fprintf(stderr,"prsocket_test: PR_NEW failed\n");
2094 failed_already=1;
2095 rv = -1;
2096 goto done;
2098 cparamp->server_addr = tcp_server_addr;
2099 cparamp->server_addr.inet.ip = PR_htonl(PR_INADDR_LOOPBACK);
2100 cparamp->exit_mon = mon2;
2101 cparamp->exit_counter = &thread_count;
2102 cparamp->datalen = datalen;
2103 for (i = 0; i < num_transmitfile_clients; i++) {
2104 t = create_new_thread(PR_USER_THREAD,
2105 TransmitFile_Client, (void *) cparamp,
2106 PR_PRIORITY_NORMAL,
2107 PR_LOCAL_THREAD,
2108 PR_UNJOINABLE_THREAD,
2109 0, i);
2110 if (t == NULL) {
2111 fprintf(stderr,"prsocket_test: PR_CreateThread failed\n");
2112 rv = -1;
2113 failed_already=1;
2114 goto done;
2116 DPRINTF(("Created TransmitFile client = 0x%lx\n", t));
2117 thread_count++;
2119 /* Wait for server and client threads to exit */
2120 while (thread_count) {
2121 PR_Wait(mon2, PR_INTERVAL_NO_TIMEOUT);
2122 DPRINTF(("Socket_Misc_Test - thread_count = %d\n", thread_count));
2124 PR_ExitMonitor(mon2);
2125 done:
2126 if (buf) {
2127 PR_DELETE(buf);
2129 #if defined(XP_UNIX)
2130 munmap((char*)small_file_addr, SMALL_FILE_SIZE);
2131 munmap((char*)large_file_addr, LARGE_FILE_SIZE);
2132 #endif
2133 PR_Close(small_file_fd);
2134 PR_Close(large_file_fd);
2135 if ((PR_Delete(SMALL_FILE_NAME)) == PR_FAILURE) {
2136 fprintf(stderr,"prsocket_test: failed to unlink file %s\n",
2137 SMALL_FILE_NAME);
2138 failed_already=1;
2140 if ((PR_Delete(LARGE_FILE_NAME)) == PR_FAILURE) {
2141 fprintf(stderr,"prsocket_test: failed to unlink file %s\n",
2142 LARGE_FILE_NAME);
2143 failed_already=1;
2145 if ((PR_RmDir(TEST_DIR)) == PR_FAILURE) {
2146 fprintf(stderr,"prsocket_test failed to rmdir %s: (%ld, %ld)\n",
2147 TEST_DIR, PR_GetError(), PR_GetOSError());
2148 failed_already=1;
2151 printf("%-29s%s","Socket_Misc_Test",":");
2152 printf("%2d Server %2d Clients\n",1, num_transmitfile_clients);
2153 printf("%30s Sizes of Transmitted Files - %4d KB, %2d MB \n",":",
2154 SMALL_FILE_SIZE/1024, LARGE_FILE_SIZE/(1024 * 1024));
2157 return rv;
2159 /************************************************************************/
2162 * Test Socket NSPR APIs
2165 int main(int argc, char **argv)
2168 * -d debug mode
2171 PLOptStatus os;
2172 PLOptState *opt = PL_CreateOptState(argc, argv, "d");
2173 while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
2175 if (PL_OPT_BAD == os) {
2176 continue;
2178 switch (opt->option)
2180 case 'd': /* debug mode */
2181 _debug_on = 1;
2182 break;
2183 default:
2184 break;
2187 PL_DestroyOptState(opt);
2189 PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
2190 PR_STDIO_INIT();
2192 PR_SetConcurrency(4);
2194 emuSendFileIdentity = PR_GetUniqueIdentity("Emulated SendFile");
2195 emuSendFileMethods = *PR_GetDefaultIOMethods();
2196 emuSendFileMethods.transmitfile = emu_TransmitFile;
2197 emuSendFileMethods.sendfile = emu_SendFile;
2200 * run client-server test with TCP, Ipv4-Ipv4
2202 printf("TCP Client/Server Test - IPv4/Ipv4\n");
2203 if (TCP_Socket_Client_Server_Test() < 0) {
2204 printf("TCP_Socket_Client_Server_Test failed\n");
2205 goto done;
2206 } else {
2207 printf("TCP_Socket_Client_Server_Test Passed\n");
2210 * client-server test, Ipv6-Ipv4
2212 client_domain = PR_AF_INET6;
2213 printf("TCP Client/Server Test - IPv6/Ipv4\n");
2214 if (TCP_Socket_Client_Server_Test() < 0) {
2215 printf("TCP_Socket_Client_Server_Test failed\n");
2216 goto done;
2217 } else {
2218 printf("TCP_Socket_Client_Server_Test Passed\n");
2221 * client-server test, Ipv4-Ipv6
2223 client_domain = PR_AF_INET;
2224 server_domain = PR_AF_INET6;
2225 printf("TCP Client/Server Test - IPv4/Ipv6\n");
2226 if (TCP_Socket_Client_Server_Test() < 0) {
2227 printf("TCP_Socket_Client_Server_Test failed\n");
2228 goto done;
2229 } else {
2230 printf("TCP_Socket_Client_Server_Test Passed\n");
2233 * client-server test, Ipv6-Ipv6
2235 client_domain = PR_AF_INET6;
2236 server_domain = PR_AF_INET6;
2237 printf("TCP Client/Server Test - IPv6/Ipv6\n");
2238 if (TCP_Socket_Client_Server_Test() < 0) {
2239 printf("TCP_Socket_Client_Server_Test failed\n");
2240 goto done;
2241 } else {
2242 printf("TCP_Socket_Client_Server_Test Passed\n");
2244 test_cancelio = 0;
2247 * Misc socket tests - including transmitfile, etc.
2250 /* File transmission test can not be done in Symbian OS because of
2251 * large file's size and the incomplete mmap() implementation. */
2252 #if !defined(WIN16)
2254 ** The 'transmit file' test does not run because
2255 ** transmit file is not implemented in NSPR yet.
2258 if (Socket_Misc_Test() < 0) {
2259 printf("Socket_Misc_Test failed\n");
2260 failed_already=1;
2261 goto done;
2262 } else {
2263 printf("Socket_Misc_Test passed\n");
2267 * run client-server test with TCP again to test
2268 * recycling used sockets from PR_TransmitFile().
2270 if (TCP_Socket_Client_Server_Test() < 0) {
2271 printf("TCP_Socket_Client_Server_Test failed\n");
2272 goto done;
2273 } else {
2274 printf("TCP_Socket_Client_Server_Test Passed\n");
2276 #endif
2278 done:
2279 PR_Cleanup();
2280 if (failed_already) {
2281 return 1;
2283 else {
2284 return 0;