1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is the Netscape Portable Runtime (NSPR).
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1999-2000
20 * the Initial Developer. All Rights Reserved.
24 * Alternatively, the contents of this file may be used under the terms of
25 * either the GNU General Public License Version 2 or later (the "GPL"), or
26 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
38 /***********************************************************************
40 ** Name: thrpool_client.c
42 ** Description: Test threadpool functionality.
44 ** Modification History:
56 #if defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS)
64 static int _debug_on
= 0;
65 static int server_port
= -1;
66 static char *program_name
= NULL
;
71 int fprintf(FILE *stream
, const char *fmt
, ...)
76 #define printf PR_LogPrint
77 extern void SetupMacPrintfLog(char *logFile
);
79 #include "obsolete/prsem.h"
86 #define DPRINTF(arg) if (_debug_on) printf arg
88 #define BUF_DATA_SIZE (2 * 1024)
89 #define TCP_MESG_SIZE 1024
90 #define NUM_TCP_CLIENTS 10 /* for a listen queue depth of 5 */
92 #define NUM_TCP_CONNECTIONS_PER_CLIENT 10
93 #define NUM_TCP_MESGS_PER_CONNECTION 10
94 #define TCP_SERVER_PORT 10000
96 static PRInt32 num_tcp_clients
= NUM_TCP_CLIENTS
;
97 static PRInt32 num_tcp_connections_per_client
= NUM_TCP_CONNECTIONS_PER_CLIENT
;
98 static PRInt32 tcp_mesg_size
= TCP_MESG_SIZE
;
99 static PRInt32 num_tcp_mesgs_per_connection
= NUM_TCP_MESGS_PER_CONNECTION
;
101 int failed_already
=0;
103 typedef struct buffer
{
104 char data
[BUF_DATA_SIZE
];
107 PRNetAddr tcp_server_addr
, udp_server_addr
;
109 typedef struct Client_Param
{
110 PRNetAddr server_addr
;
111 PRMonitor
*exit_mon
; /* monitor to signal on exit */
112 PRInt32
*exit_counter
; /* counter to decrement, before exit */
118 * read data from sockfd into buf
121 readn(PRFileDesc
*sockfd
, char *buf
, int len
)
126 PRIntervalTime timeout
= PR_INTERVAL_NO_TIMEOUT
;
128 for (rem
=len
; rem
; offset
+= bytes
, rem
-= bytes
) {
129 DPRINTF(("thread = 0x%lx: calling PR_Recv, bytes = %d\n",
130 PR_GetCurrentThread(), rem
));
131 bytes
= PR_Recv(sockfd
, buf
+ offset
, rem
, 0,
133 DPRINTF(("thread = 0x%lx: returning from PR_Recv, bytes = %d\n",
134 PR_GetCurrentThread(), bytes
));
144 * write data from buf to sockfd
147 writen(PRFileDesc
*sockfd
, char *buf
, int len
)
153 for (rem
=len
; rem
; offset
+= bytes
, rem
-= bytes
) {
154 DPRINTF(("thread = 0x%lx: calling PR_Send, bytes = %d\n",
155 PR_GetCurrentThread(), rem
));
156 bytes
= PR_Send(sockfd
, buf
+ offset
, rem
, 0,
157 PR_INTERVAL_NO_TIMEOUT
);
158 DPRINTF(("thread = 0x%lx: returning from PR_Send, bytes = %d\n",
159 PR_GetCurrentThread(), bytes
));
169 * Connect to the server at the address specified in the argument.
170 * Fill in a buffer, write data to server, read it back and check
171 * for data corruption.
172 * Close the socket for server connection
174 static void PR_CALLBACK
175 TCP_Client(void *arg
)
177 Client_Param
*cp
= (Client_Param
*) arg
;
179 buffer
*in_buf
, *out_buf
;
180 union PRNetAddr netaddr
;
184 DPRINTF(("TCP client started\n"));
186 out_buf
= PR_NEW(buffer
);
187 if (out_buf
== NULL
) {
188 fprintf(stderr
,"%s: failed to alloc buffer struct\n", program_name
);
192 in_buf
= PR_NEW(buffer
);
193 if (in_buf
== NULL
) {
194 fprintf(stderr
,"%s: failed to alloc buffer struct\n", program_name
);
198 netaddr
.inet
.family
= cp
->server_addr
.inet
.family
;
199 netaddr
.inet
.port
= cp
->server_addr
.inet
.port
;
200 netaddr
.inet
.ip
= cp
->server_addr
.inet
.ip
;
202 for (i
= 0; i
< num_tcp_connections_per_client
; i
++) {
203 if ((sockfd
= PR_OpenTCPSocket(PR_AF_INET
)) == NULL
) {
204 fprintf(stderr
,"%s: PR_OpenTCPSocket failed\n", program_name
);
209 DPRINTF(("TCP client connecting to server:%d\n", server_port
));
210 if (PR_Connect(sockfd
, &netaddr
,PR_INTERVAL_NO_TIMEOUT
) < 0){
211 fprintf(stderr
, "PR_Connect failed: (%ld, %ld)\n",
212 PR_GetError(), PR_GetOSError());
216 for (j
= 0; j
< num_tcp_mesgs_per_connection
; j
++) {
218 * fill in random data
220 memset(out_buf
->data
, ((PRInt32
) (&netaddr
)) + i
+ j
, bytes
);
224 if (writen(sockfd
, out_buf
->data
, bytes
) < bytes
) {
225 fprintf(stderr
,"%s: ERROR - TCP_Client:writen\n", program_name
);
230 DPRINTF(("TCP Client [0x%lx]: out_buf = 0x%lx out_buf[0] = 0x%lx\n",
231 PR_GetCurrentThread(), out_buf, (*((int *) out_buf->data))));
233 if (readn(sockfd
, in_buf
->data
, bytes
) < bytes
) {
234 fprintf(stderr
,"%s: ERROR - TCP_Client:readn\n", program_name
);
239 * verify the data read
241 if (memcmp(in_buf
->data
, out_buf
->data
, bytes
) != 0) {
242 fprintf(stderr
,"%s: ERROR - data corruption\n", program_name
);
248 * shutdown reads and writes
250 if (PR_Shutdown(sockfd
, PR_SHUTDOWN_BOTH
) < 0) {
251 fprintf(stderr
,"%s: ERROR - PR_Shutdown\n", program_name
);
261 * Decrement exit_counter and notify parent thread
264 PR_EnterMonitor(cp
->exit_mon
);
265 --(*cp
->exit_counter
);
266 PR_Notify(cp
->exit_mon
);
267 PR_ExitMonitor(cp
->exit_mon
);
268 DPRINTF(("TCP_Client exiting\n"));
272 * TCP_Socket_Client_Server_Test - concurrent server test
274 * Each client connects to the server and sends a chunk of data
275 * For each connection, server reads the data
276 * from the client and sends it back to the client, unmodified.
277 * Each client checks that data received from server is same as the
278 * data it sent to the server.
283 TCP_Socket_Client_Server_Test(void)
286 Client_Param
*cparamp
;
289 PRInt32 connections
= 0;
292 datalen
= tcp_mesg_size
;
295 mon2
= PR_NewMonitor();
297 fprintf(stderr
,"%s: PR_NewMonitor failed\n", program_name
);
305 cparamp
= PR_NEW(Client_Param
);
306 if (cparamp
== NULL
) {
307 fprintf(stderr
,"%s: PR_NEW failed\n", program_name
);
311 cparamp
->server_addr
.inet
.family
= PR_AF_INET
;
312 cparamp
->server_addr
.inet
.port
= PR_htons(server_port
);
313 cparamp
->server_addr
.inet
.ip
= PR_htonl(PR_INADDR_LOOPBACK
);
314 cparamp
->exit_mon
= mon2
;
315 cparamp
->exit_counter
= &connections
;
316 cparamp
->datalen
= datalen
;
317 for (i
= 0; i
< num_tcp_clients
; i
++) {
318 thr
= PR_CreateThread(PR_USER_THREAD
, TCP_Client
, (void *)cparamp
,
319 PR_PRIORITY_NORMAL
, PR_GLOBAL_THREAD
, PR_UNJOINABLE_THREAD
, 0);
321 fprintf(stderr
,"%s: PR_CreateThread failed\n", program_name
);
325 PR_EnterMonitor(mon2
);
327 PR_ExitMonitor(mon2
);
328 DPRINTF(("Created TCP client = 0x%lx\n", thr
));
330 /* Wait for client jobs to exit */
331 PR_EnterMonitor(mon2
);
332 while (0 != connections
) {
333 PR_Wait(mon2
, PR_INTERVAL_NO_TIMEOUT
);
334 DPRINTF(("Client job count = %d\n", connections
));
336 PR_ExitMonitor(mon2
);
337 printf("%30s","TCP_Socket_Client_Server_Test:");
338 printf("%2ld Server %2ld Clients %2ld connections_per_client\n",1l,
339 num_tcp_clients
, num_tcp_connections_per_client
);
340 printf("%30s %2ld messages_per_connection %4ld bytes_per_message\n",":",
341 num_tcp_mesgs_per_connection
, tcp_mesg_size
);
347 /************************************************************************/
350 main(int argc
, char **argv
)
357 program_name
= argv
[0];
359 opt
= PL_CreateOptState(argc
, argv
, "dp:");
360 while (PL_OPT_EOL
!= (os
= PL_GetNextOpt(opt
)))
362 if (PL_OPT_BAD
== os
) continue;
365 case 'd': /* debug mode */
369 server_port
= atoi(opt
->value
);
375 PL_DestroyOptState(opt
);
377 PR_Init(PR_USER_THREAD
, PR_PRIORITY_NORMAL
, 0);
381 SetupMacPrintfLog("socket.log");
383 PR_SetConcurrency(4);
385 TCP_Socket_Client_Server_Test();