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) 1998-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 ***** */
51
** Testing layering of I/O
54
** A thread that acts as a server. It creates a TCP listener with a dummy
55
** layer pushed on top. Then listens for incoming connections. Each connection
56
** request for connection will be layered as well, accept one request, echo
60
** Pretty much what you'd expect.
63
static PRFileDesc *logFile;
64
static PRDescIdentity identity;
65
static PRNetAddr server_address;
67
static PRIOMethods myMethods;
69
typedef enum Verbosity {silent, quiet, chatty, noisy} Verbosity;
71
static PRIntn minor_iterations = 5;
72
static PRIntn major_iterations = 1;
73
static Verbosity verbosity = quiet;
74
static PRUint16 default_port = 12273;
76
static PRFileDesc *PushLayer(PRFileDesc *stack)
78
PRFileDesc *layer = PR_CreateIOLayerStub(identity, &myMethods);
79
PRStatus rv = PR_PushIOLayer(stack, PR_GetLayersIdentity(stack), layer);
80
if (verbosity > quiet)
81
PR_fprintf(logFile, "Pushed layer(0x%x) onto stack(0x%x)\n", layer, stack);
82
PR_ASSERT(PR_SUCCESS == rv);
86
static PRFileDesc *PushNewLayers(PRFileDesc *stack)
88
PRDescIdentity tmp_identity;
92
/* push a dummy layer */
93
tmp_identity = PR_GetUniqueIdentity("Dummy 1");
94
layer = PR_CreateIOLayerStub(tmp_identity, PR_GetDefaultIOMethods());
95
rv = PR_PushIOLayer(stack, PR_GetLayersIdentity(stack), layer);
96
if (verbosity > quiet)
97
PR_fprintf(logFile, "Pushed layer(0x%x) onto stack(0x%x)\n", layer,
99
PR_ASSERT(PR_SUCCESS == rv);
101
/* push a data procesing layer */
102
layer = PR_CreateIOLayerStub(identity, &myMethods);
103
rv = PR_PushIOLayer(stack, PR_GetLayersIdentity(stack), layer);
104
if (verbosity > quiet)
105
PR_fprintf(logFile, "Pushed layer(0x%x) onto stack(0x%x)\n", layer,
107
PR_ASSERT(PR_SUCCESS == rv);
109
/* push another dummy layer */
110
tmp_identity = PR_GetUniqueIdentity("Dummy 2");
111
layer = PR_CreateIOLayerStub(tmp_identity, PR_GetDefaultIOMethods());
112
rv = PR_PushIOLayer(stack, PR_GetLayersIdentity(stack), layer);
113
if (verbosity > quiet)
114
PR_fprintf(logFile, "Pushed layer(0x%x) onto stack(0x%x)\n", layer,
116
PR_ASSERT(PR_SUCCESS == rv);
121
static PRFileDesc *PopLayer(PRFileDesc *stack)
123
PRFileDesc *popped = PR_PopIOLayer(stack, identity);
124
if (verbosity > quiet)
125
PR_fprintf(logFile, "Popped layer(0x%x) from stack(0x%x)\n", popped, stack);
126
popped->dtor(popped);
132
static void PR_CALLBACK Client(void *arg)
136
PRIntn empty_flags = 0;
137
PRIntn bytes_read, bytes_sent;
138
PRFileDesc *stack = (PRFileDesc*)arg;
140
/* Initialize the buffer so that Purify won't complain */
141
memset(buffer, 0, sizeof(buffer));
143
rv = PR_Connect(stack, &server_address, PR_INTERVAL_NO_TIMEOUT);
144
PR_ASSERT(PR_SUCCESS == rv);
145
while (minor_iterations-- > 0)
147
bytes_sent = PR_Send(
148
stack, buffer, sizeof(buffer), empty_flags, PR_INTERVAL_NO_TIMEOUT);
149
PR_ASSERT(sizeof(buffer) == bytes_sent);
150
if (verbosity > chatty)
151
PR_fprintf(logFile, "Client sending %d bytes\n", bytes_sent);
152
bytes_read = PR_Recv(
153
stack, buffer, bytes_sent, empty_flags, PR_INTERVAL_NO_TIMEOUT);
154
if (verbosity > chatty)
155
PR_fprintf(logFile, "Client receiving %d bytes\n", bytes_read);
156
PR_ASSERT(bytes_read == bytes_sent);
159
if (verbosity > quiet)
160
PR_fprintf(logFile, "Client shutting down stack\n");
162
rv = PR_Shutdown(stack, PR_SHUTDOWN_BOTH); PR_ASSERT(PR_SUCCESS == rv);
165
static void PR_CALLBACK Server(void *arg)
170
PRUintn empty_flags = 0;
171
PRIntn bytes_read, bytes_sent;
172
PRFileDesc *stack = (PRFileDesc*)arg;
173
PRNetAddr client_address;
175
service = PR_Accept(stack, &client_address, PR_INTERVAL_NO_TIMEOUT);
176
if (verbosity > quiet)
177
PR_fprintf(logFile, "Server accepting connection\n");
181
bytes_read = PR_Recv(
182
service, buffer, sizeof(buffer), empty_flags, PR_INTERVAL_NO_TIMEOUT);
185
if (verbosity > chatty)
186
PR_fprintf(logFile, "Server receiving %d bytes\n", bytes_read);
187
PR_ASSERT(bytes_read > 0);
188
bytes_sent = PR_Send(
189
service, buffer, bytes_read, empty_flags, PR_INTERVAL_NO_TIMEOUT);
190
if (verbosity > chatty)
191
PR_fprintf(logFile, "Server sending %d bytes\n", bytes_sent);
192
PR_ASSERT(bytes_read == bytes_sent);
195
} while (0 != bytes_read);
197
if (verbosity > quiet)
198
PR_fprintf(logFile, "Server shutting down and closing stack\n");
199
rv = PR_Shutdown(service, PR_SHUTDOWN_BOTH); PR_ASSERT(PR_SUCCESS == rv);
200
rv = PR_Close(service); PR_ASSERT(PR_SUCCESS == rv);
204
static PRInt32 PR_CALLBACK MyRecv(
205
PRFileDesc *fd, void *buf, PRInt32 amount,
206
PRIntn flags, PRIntervalTime timeout)
208
char *b = (char*)buf;
209
PRFileDesc *lo = fd->lower;
210
PRInt32 rv, readin = 0, request = 0;
211
rv = lo->methods->recv(lo, &request, sizeof(request), flags, timeout);
212
if (verbosity > chatty) PR_fprintf(
213
logFile, "MyRecv sending permission for %d bytes\n", request);
216
if (verbosity > chatty) PR_fprintf(
217
logFile, "MyRecv received permission request for %d bytes\n", request);
218
rv = lo->methods->send(
219
lo, &request, sizeof(request), flags, timeout);
222
if (verbosity > chatty) PR_fprintf(
223
logFile, "MyRecv sending permission for %d bytes\n", request);
224
while (readin < request)
226
rv = lo->methods->recv(
227
lo, b + readin, amount - readin, flags, timeout);
229
if (verbosity > chatty) PR_fprintf(
230
logFile, "MyRecv received %d bytes\n", rv);
239
static PRInt32 PR_CALLBACK MySend(
240
PRFileDesc *fd, const void *buf, PRInt32 amount,
241
PRIntn flags, PRIntervalTime timeout)
243
PRFileDesc *lo = fd->lower;
244
const char *b = (const char*)buf;
245
PRInt32 rv, wroteout = 0, request;
246
if (verbosity > chatty) PR_fprintf(
247
logFile, "MySend asking permission to send %d bytes\n", amount);
248
rv = lo->methods->send(lo, &amount, sizeof(amount), flags, timeout);
251
rv = lo->methods->recv(
252
lo, &request, sizeof(request), flags, timeout);
255
PR_ASSERT(request == amount);
256
if (verbosity > chatty) PR_fprintf(
257
logFile, "MySend got permission to send %d bytes\n", request);
258
while (wroteout < request)
260
rv = lo->methods->send(
261
lo, b + wroteout, request - wroteout, flags, timeout);
263
if (verbosity > chatty) PR_fprintf(
264
logFile, "MySend wrote %d bytes\n", rv);
273
static Verbosity ChangeVerbosity(Verbosity verbosity, PRIntn delta)
275
PRIntn verbage = (PRIntn)verbosity + delta;
276
if (verbage < (PRIntn)silent) verbage = (PRIntn)silent;
277
else if (verbage > (PRIntn)noisy) verbage = (PRIntn)noisy;
278
return (Verbosity)verbage;
279
} /* ChangeVerbosity */
281
PRIntn main(PRIntn argc, char **argv)
286
PRFileDesc *client, *service;
287
PRFileDesc *client_stack, *service_stack;
288
PRNetAddr any_address;
289
const char *server_name = NULL;
290
const PRIOMethods *stubMethods;
291
PRThread *client_thread, *server_thread;
292
PRThreadScope thread_scope = PR_LOCAL_THREAD;
293
PLOptState *opt = PL_CreateOptState(argc, argv, "dqGC:c:p:");
294
while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
296
if (PL_OPT_BAD == os) continue;
300
server_name = opt->value;
302
case 'd': /* debug mode */
303
if (verbosity < noisy)
304
verbosity = ChangeVerbosity(verbosity, 1);
306
case 'q': /* debug mode */
307
if (verbosity > silent)
308
verbosity = ChangeVerbosity(verbosity, -1);
310
case 'G': /* use global threads */
311
thread_scope = PR_GLOBAL_THREAD;
313
case 'C': /* number of threads waiting */
314
major_iterations = atoi(opt->value);
316
case 'c': /* number of client threads */
317
minor_iterations = atoi(opt->value);
319
case 'p': /* default port */
320
default_port = atoi(opt->value);
326
PL_DestroyOptState(opt);
329
logFile = PR_GetSpecialFD(PR_StandardError);
331
identity = PR_GetUniqueIdentity("Dummy");
332
stubMethods = PR_GetDefaultIOMethods();
335
** The protocol we're going to implement is one where in order to initiate
336
** a send, the sender must first solicit permission. Therefore, every
337
** send is really a send - receive - send sequence.
339
myMethods = *stubMethods; /* first get the entire batch */
340
myMethods.recv = MyRecv; /* then override the ones we care about */
341
myMethods.send = MySend; /* then override the ones we care about */
343
if (NULL == server_name)
344
rv = PR_InitializeNetAddr(
345
PR_IpAddrLoopback, default_port, &server_address);
348
rv = PR_StringToNetAddr(server_name, &server_address);
349
PR_ASSERT(PR_SUCCESS == rv);
350
rv = PR_InitializeNetAddr(
351
PR_IpAddrNull, default_port, &server_address);
353
PR_ASSERT(PR_SUCCESS == rv);
355
/* one type w/o layering */
357
mits = minor_iterations;
358
while (major_iterations-- > 0)
360
if (verbosity > silent)
361
PR_fprintf(logFile, "Beginning non-layered test\n");
362
client = PR_NewTCPSocket(); PR_ASSERT(NULL != client);
363
service = PR_NewTCPSocket(); PR_ASSERT(NULL != service);
364
rv = PR_InitializeNetAddr(PR_IpAddrAny, default_port, &any_address);
365
PR_ASSERT(PR_SUCCESS == rv);
366
rv = PR_Bind(service, &any_address); PR_ASSERT(PR_SUCCESS == rv);
367
rv = PR_Listen(service, 10); PR_ASSERT(PR_SUCCESS == rv);
369
minor_iterations = mits;
370
server_thread = PR_CreateThread(
371
PR_USER_THREAD, Server, service,
372
PR_PRIORITY_HIGH, thread_scope,
373
PR_JOINABLE_THREAD, 16 * 1024);
374
PR_ASSERT(NULL != server_thread);
376
client_thread = PR_CreateThread(
377
PR_USER_THREAD, Client, client,
378
PR_PRIORITY_NORMAL, thread_scope,
379
PR_JOINABLE_THREAD, 16 * 1024);
380
PR_ASSERT(NULL != client_thread);
382
rv = PR_JoinThread(client_thread);
383
PR_ASSERT(PR_SUCCESS == rv);
384
rv = PR_JoinThread(server_thread);
385
PR_ASSERT(PR_SUCCESS == rv);
387
rv = PR_Close(client); PR_ASSERT(PR_SUCCESS == rv);
388
rv = PR_Close(service); PR_ASSERT(PR_SUCCESS == rv);
389
if (verbosity > silent)
390
PR_fprintf(logFile, "Ending non-layered test\n");
393
if (verbosity > silent)
394
PR_fprintf(logFile, "Beginning layered test\n");
395
client = PR_NewTCPSocket(); PR_ASSERT(NULL != client);
397
service = PR_NewTCPSocket(); PR_ASSERT(NULL != service);
399
rv = PR_InitializeNetAddr(PR_IpAddrAny, default_port, &any_address);
400
PR_ASSERT(PR_SUCCESS == rv);
401
rv = PR_Bind(service, &any_address); PR_ASSERT(PR_SUCCESS == rv);
402
rv = PR_Listen(service, 10); PR_ASSERT(PR_SUCCESS == rv);
404
minor_iterations = mits;
405
server_thread = PR_CreateThread(
406
PR_USER_THREAD, Server, service,
407
PR_PRIORITY_HIGH, thread_scope,
408
PR_JOINABLE_THREAD, 16 * 1024);
409
PR_ASSERT(NULL != server_thread);
411
client_thread = PR_CreateThread(
412
PR_USER_THREAD, Client, client,
413
PR_PRIORITY_NORMAL, thread_scope,
414
PR_JOINABLE_THREAD, 16 * 1024);
415
PR_ASSERT(NULL != client_thread);
417
rv = PR_JoinThread(client_thread);
418
PR_ASSERT(PR_SUCCESS == rv);
419
rv = PR_JoinThread(server_thread);
420
PR_ASSERT(PR_SUCCESS == rv);
422
rv = PR_Close(client); PR_ASSERT(PR_SUCCESS == rv);
423
rv = PR_Close(service); PR_ASSERT(PR_SUCCESS == rv);
424
/* with layering, using new style stack */
425
if (verbosity > silent)
427
"Beginning layered test with new style stack\n");
428
client = PR_NewTCPSocket(); PR_ASSERT(NULL != client);
429
client_stack = PR_CreateIOLayer(client);
430
PushNewLayers(client_stack);
431
service = PR_NewTCPSocket(); PR_ASSERT(NULL != service);
432
service_stack = PR_CreateIOLayer(service);
433
PushNewLayers(service_stack);
434
rv = PR_InitializeNetAddr(PR_IpAddrAny, default_port, &any_address);
435
PR_ASSERT(PR_SUCCESS == rv);
436
rv = PR_Bind(service, &any_address); PR_ASSERT(PR_SUCCESS == rv);
437
rv = PR_Listen(service, 10); PR_ASSERT(PR_SUCCESS == rv);
439
minor_iterations = mits;
440
server_thread = PR_CreateThread(
441
PR_USER_THREAD, Server, service_stack,
442
PR_PRIORITY_HIGH, thread_scope,
443
PR_JOINABLE_THREAD, 16 * 1024);
444
PR_ASSERT(NULL != server_thread);
446
client_thread = PR_CreateThread(
447
PR_USER_THREAD, Client, client_stack,
448
PR_PRIORITY_NORMAL, thread_scope,
449
PR_JOINABLE_THREAD, 16 * 1024);
450
PR_ASSERT(NULL != client_thread);
452
rv = PR_JoinThread(client_thread);
453
PR_ASSERT(PR_SUCCESS == rv);
454
rv = PR_JoinThread(server_thread);
455
PR_ASSERT(PR_SUCCESS == rv);
457
rv = PR_Close(client_stack); PR_ASSERT(PR_SUCCESS == rv);
458
rv = PR_Close(service_stack); PR_ASSERT(PR_SUCCESS == rv);
459
if (verbosity > silent)
460
PR_fprintf(logFile, "Ending layered test\n");