1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
3
* The contents of this file are subject to the Mozilla Public
4
* License Version 1.1 (the "License"); you may not use this file
5
* except in compliance with the License. You may obtain a copy of
6
* the License at http://www.mozilla.org/MPL/
8
* Software distributed under the License is distributed on an "AS
9
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
10
* implied. See the License for the specific language governing
11
* rights and limitations under the License.
13
* The Original Code is the Netscape Portable Runtime (NSPR).
15
* The Initial Developer of the Original Code is Netscape
16
* Communications Corporation. Portions created by Netscape are
17
* Copyright (C) 1998-2000 Netscape Communications Corporation. All
22
* Alternatively, the contents of this file may be used under the
23
* terms of the GNU General Public License Version 2 or later (the
24
* "GPL"), in which case the provisions of the GPL are applicable
25
* instead of those above. If you wish to allow use of your
26
* version of this file only under the terms of the GPL and not to
27
* allow others to use your version of this file under the MPL,
28
* indicate your decision by deleting the provisions above and
29
* replace them with the notice and other provisions required by
30
* the GPL. If you do not delete the provisions above, a recipient
31
* may use your version of this file under either the MPL or the
48
** Testing layering of I/O
51
** A thread that acts as a server. It creates a TCP listener with a dummy
52
** layer pushed on top. Then listens for incoming connections. Each connection
53
** request for connection will be layered as well, accept one request, echo
57
** Pretty much what you'd expect.
60
static PRFileDesc *logFile;
61
static PRDescIdentity identity;
62
static PRNetAddr server_address;
64
static PRIOMethods myMethods;
66
typedef enum Verbosity {silent, quiet, chatty, noisy} Verbosity;
68
static PRIntn minor_iterations = 5;
69
static PRIntn major_iterations = 1;
70
static Verbosity verbosity = quiet;
71
static PRUint16 default_port = 12273;
73
static PRFileDesc *PushLayer(PRFileDesc *stack)
75
PRFileDesc *layer = PR_CreateIOLayerStub(identity, &myMethods);
76
PRStatus rv = PR_PushIOLayer(stack, PR_GetLayersIdentity(stack), layer);
77
if (verbosity > quiet)
78
PR_fprintf(logFile, "Pushed layer(0x%x) onto stack(0x%x)\n", layer, stack);
79
PR_ASSERT(PR_SUCCESS == rv);
83
static PRFileDesc *PushNewLayers(PRFileDesc *stack)
85
PRDescIdentity tmp_identity;
89
/* push a dummy layer */
90
tmp_identity = PR_GetUniqueIdentity("Dummy 1");
91
layer = PR_CreateIOLayerStub(tmp_identity, PR_GetDefaultIOMethods());
92
rv = PR_PushIOLayer(stack, PR_GetLayersIdentity(stack), layer);
93
if (verbosity > quiet)
94
PR_fprintf(logFile, "Pushed layer(0x%x) onto stack(0x%x)\n", layer,
96
PR_ASSERT(PR_SUCCESS == rv);
98
/* push a data procesing layer */
99
layer = PR_CreateIOLayerStub(identity, &myMethods);
100
rv = PR_PushIOLayer(stack, PR_GetLayersIdentity(stack), layer);
101
if (verbosity > quiet)
102
PR_fprintf(logFile, "Pushed layer(0x%x) onto stack(0x%x)\n", layer,
104
PR_ASSERT(PR_SUCCESS == rv);
106
/* push another dummy layer */
107
tmp_identity = PR_GetUniqueIdentity("Dummy 2");
108
layer = PR_CreateIOLayerStub(tmp_identity, PR_GetDefaultIOMethods());
109
rv = PR_PushIOLayer(stack, PR_GetLayersIdentity(stack), layer);
110
if (verbosity > quiet)
111
PR_fprintf(logFile, "Pushed layer(0x%x) onto stack(0x%x)\n", layer,
113
PR_ASSERT(PR_SUCCESS == rv);
118
static PRFileDesc *PopLayer(PRFileDesc *stack)
120
PRFileDesc *popped = PR_PopIOLayer(stack, identity);
121
if (verbosity > quiet)
122
PR_fprintf(logFile, "Popped layer(0x%x) from stack(0x%x)\n", popped, stack);
123
popped->dtor(popped);
129
static void PR_CALLBACK Client(void *arg)
133
PRIntn empty_flags = 0;
134
PRIntn bytes_read, bytes_sent;
135
PRFileDesc *stack = (PRFileDesc*)arg;
137
/* Initialize the buffer so that Purify won't complain */
138
memset(buffer, 0, sizeof(buffer));
140
rv = PR_Connect(stack, &server_address, PR_INTERVAL_NO_TIMEOUT);
141
PR_ASSERT(PR_SUCCESS == rv);
142
while (minor_iterations-- > 0)
144
bytes_sent = PR_Send(
145
stack, buffer, sizeof(buffer), empty_flags, PR_INTERVAL_NO_TIMEOUT);
146
PR_ASSERT(sizeof(buffer) == bytes_sent);
147
if (verbosity > chatty)
148
PR_fprintf(logFile, "Client sending %d bytes\n", bytes_sent);
149
bytes_read = PR_Recv(
150
stack, buffer, bytes_sent, empty_flags, PR_INTERVAL_NO_TIMEOUT);
151
if (verbosity > chatty)
152
PR_fprintf(logFile, "Client receiving %d bytes\n", bytes_read);
153
PR_ASSERT(bytes_read == bytes_sent);
156
if (verbosity > quiet)
157
PR_fprintf(logFile, "Client shutting down stack\n");
159
rv = PR_Shutdown(stack, PR_SHUTDOWN_BOTH); PR_ASSERT(PR_SUCCESS == rv);
162
static void PR_CALLBACK Server(void *arg)
167
PRUintn empty_flags = 0;
168
PRIntn bytes_read, bytes_sent;
169
PRFileDesc *stack = (PRFileDesc*)arg;
170
PRNetAddr client_address;
172
service = PR_Accept(stack, &client_address, PR_INTERVAL_NO_TIMEOUT);
173
if (verbosity > quiet)
174
PR_fprintf(logFile, "Server accepting connection\n");
178
bytes_read = PR_Recv(
179
service, buffer, sizeof(buffer), empty_flags, PR_INTERVAL_NO_TIMEOUT);
182
if (verbosity > chatty)
183
PR_fprintf(logFile, "Server receiving %d bytes\n", bytes_read);
184
PR_ASSERT(bytes_read > 0);
185
bytes_sent = PR_Send(
186
service, buffer, bytes_read, empty_flags, PR_INTERVAL_NO_TIMEOUT);
187
if (verbosity > chatty)
188
PR_fprintf(logFile, "Server sending %d bytes\n", bytes_sent);
189
PR_ASSERT(bytes_read == bytes_sent);
192
} while (0 != bytes_read);
194
if (verbosity > quiet)
195
PR_fprintf(logFile, "Server shutting down and closing stack\n");
196
rv = PR_Shutdown(service, PR_SHUTDOWN_BOTH); PR_ASSERT(PR_SUCCESS == rv);
197
rv = PR_Close(service); PR_ASSERT(PR_SUCCESS == rv);
201
static PRInt32 PR_CALLBACK MyRecv(
202
PRFileDesc *fd, void *buf, PRInt32 amount,
203
PRIntn flags, PRIntervalTime timeout)
205
char *b = (char*)buf;
206
PRFileDesc *lo = fd->lower;
207
PRInt32 rv, readin = 0, request = 0;
208
rv = lo->methods->recv(lo, &request, sizeof(request), flags, timeout);
209
if (verbosity > chatty) PR_fprintf(
210
logFile, "MyRecv sending permission for %d bytes\n", request);
213
if (verbosity > chatty) PR_fprintf(
214
logFile, "MyRecv received permission request for %d bytes\n", request);
215
rv = lo->methods->send(
216
lo, &request, sizeof(request), flags, timeout);
219
if (verbosity > chatty) PR_fprintf(
220
logFile, "MyRecv sending permission for %d bytes\n", request);
221
while (readin < request)
223
rv = lo->methods->recv(
224
lo, b + readin, amount - readin, flags, timeout);
226
if (verbosity > chatty) PR_fprintf(
227
logFile, "MyRecv received %d bytes\n", rv);
236
static PRInt32 PR_CALLBACK MySend(
237
PRFileDesc *fd, const void *buf, PRInt32 amount,
238
PRIntn flags, PRIntervalTime timeout)
240
PRFileDesc *lo = fd->lower;
241
const char *b = (const char*)buf;
242
PRInt32 rv, wroteout = 0, request;
243
if (verbosity > chatty) PR_fprintf(
244
logFile, "MySend asking permission to send %d bytes\n", amount);
245
rv = lo->methods->send(lo, &amount, sizeof(amount), flags, timeout);
248
rv = lo->methods->recv(
249
lo, &request, sizeof(request), flags, timeout);
252
PR_ASSERT(request == amount);
253
if (verbosity > chatty) PR_fprintf(
254
logFile, "MySend got permission to send %d bytes\n", request);
255
while (wroteout < request)
257
rv = lo->methods->send(
258
lo, b + wroteout, request - wroteout, flags, timeout);
260
if (verbosity > chatty) PR_fprintf(
261
logFile, "MySend wrote %d bytes\n", rv);
270
static Verbosity ChangeVerbosity(Verbosity verbosity, PRIntn delta)
272
PRIntn verbage = (PRIntn)verbosity + delta;
273
if (verbage < (PRIntn)silent) verbage = (PRIntn)silent;
274
else if (verbage > (PRIntn)noisy) verbage = (PRIntn)noisy;
275
return (Verbosity)verbage;
276
} /* ChangeVerbosity */
278
PRIntn main(PRIntn argc, char **argv)
283
PRFileDesc *client, *service;
284
PRFileDesc *client_stack, *service_stack;
285
PRNetAddr any_address;
286
const char *server_name = NULL;
287
const PRIOMethods *stubMethods;
288
PRThread *client_thread, *server_thread;
289
PRThreadScope thread_scope = PR_LOCAL_THREAD;
290
PLOptState *opt = PL_CreateOptState(argc, argv, "dqGC:c:p:");
291
while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
293
if (PL_OPT_BAD == os) continue;
297
server_name = opt->value;
299
case 'd': /* debug mode */
300
if (verbosity < noisy)
301
verbosity = ChangeVerbosity(verbosity, 1);
303
case 'q': /* debug mode */
304
if (verbosity > silent)
305
verbosity = ChangeVerbosity(verbosity, -1);
307
case 'G': /* use global threads */
308
thread_scope = PR_GLOBAL_THREAD;
310
case 'C': /* number of threads waiting */
311
major_iterations = atoi(opt->value);
313
case 'c': /* number of client threads */
314
minor_iterations = atoi(opt->value);
316
case 'p': /* default port */
317
default_port = atoi(opt->value);
323
PL_DestroyOptState(opt);
326
logFile = PR_GetSpecialFD(PR_StandardError);
328
identity = PR_GetUniqueIdentity("Dummy");
329
stubMethods = PR_GetDefaultIOMethods();
332
** The protocol we're going to implement is one where in order to initiate
333
** a send, the sender must first solicit permission. Therefore, every
334
** send is really a send - receive - send sequence.
336
myMethods = *stubMethods; /* first get the entire batch */
337
myMethods.recv = MyRecv; /* then override the ones we care about */
338
myMethods.send = MySend; /* then override the ones we care about */
340
if (NULL == server_name)
341
rv = PR_InitializeNetAddr(
342
PR_IpAddrLoopback, default_port, &server_address);
345
rv = PR_StringToNetAddr(server_name, &server_address);
346
PR_ASSERT(PR_SUCCESS == rv);
347
rv = PR_InitializeNetAddr(
348
PR_IpAddrNull, default_port, &server_address);
350
PR_ASSERT(PR_SUCCESS == rv);
352
/* one type w/o layering */
354
mits = minor_iterations;
355
while (major_iterations-- > 0)
357
if (verbosity > silent)
358
PR_fprintf(logFile, "Beginning non-layered test\n");
359
client = PR_NewTCPSocket(); PR_ASSERT(NULL != client);
360
service = PR_NewTCPSocket(); PR_ASSERT(NULL != service);
361
rv = PR_InitializeNetAddr(PR_IpAddrAny, default_port, &any_address);
362
PR_ASSERT(PR_SUCCESS == rv);
363
rv = PR_Bind(service, &any_address); PR_ASSERT(PR_SUCCESS == rv);
364
rv = PR_Listen(service, 10); PR_ASSERT(PR_SUCCESS == rv);
366
minor_iterations = mits;
367
server_thread = PR_CreateThread(
368
PR_USER_THREAD, Server, service,
369
PR_PRIORITY_HIGH, thread_scope,
370
PR_JOINABLE_THREAD, 16 * 1024);
371
PR_ASSERT(NULL != server_thread);
373
client_thread = PR_CreateThread(
374
PR_USER_THREAD, Client, client,
375
PR_PRIORITY_NORMAL, thread_scope,
376
PR_JOINABLE_THREAD, 16 * 1024);
377
PR_ASSERT(NULL != client_thread);
379
rv = PR_JoinThread(client_thread);
380
PR_ASSERT(PR_SUCCESS == rv);
381
rv = PR_JoinThread(server_thread);
382
PR_ASSERT(PR_SUCCESS == rv);
384
rv = PR_Close(client); PR_ASSERT(PR_SUCCESS == rv);
385
rv = PR_Close(service); PR_ASSERT(PR_SUCCESS == rv);
386
if (verbosity > silent)
387
PR_fprintf(logFile, "Ending non-layered test\n");
390
if (verbosity > silent)
391
PR_fprintf(logFile, "Beginning layered test\n");
392
client = PR_NewTCPSocket(); PR_ASSERT(NULL != client);
394
service = PR_NewTCPSocket(); PR_ASSERT(NULL != service);
396
rv = PR_InitializeNetAddr(PR_IpAddrAny, default_port, &any_address);
397
PR_ASSERT(PR_SUCCESS == rv);
398
rv = PR_Bind(service, &any_address); PR_ASSERT(PR_SUCCESS == rv);
399
rv = PR_Listen(service, 10); PR_ASSERT(PR_SUCCESS == rv);
401
minor_iterations = mits;
402
server_thread = PR_CreateThread(
403
PR_USER_THREAD, Server, service,
404
PR_PRIORITY_HIGH, thread_scope,
405
PR_JOINABLE_THREAD, 16 * 1024);
406
PR_ASSERT(NULL != server_thread);
408
client_thread = PR_CreateThread(
409
PR_USER_THREAD, Client, client,
410
PR_PRIORITY_NORMAL, thread_scope,
411
PR_JOINABLE_THREAD, 16 * 1024);
412
PR_ASSERT(NULL != client_thread);
414
rv = PR_JoinThread(client_thread);
415
PR_ASSERT(PR_SUCCESS == rv);
416
rv = PR_JoinThread(server_thread);
417
PR_ASSERT(PR_SUCCESS == rv);
419
rv = PR_Close(client); PR_ASSERT(PR_SUCCESS == rv);
420
rv = PR_Close(service); PR_ASSERT(PR_SUCCESS == rv);
421
/* with layering, using new style stack */
422
if (verbosity > silent)
424
"Beginning layered test with new style stack\n");
425
client = PR_NewTCPSocket(); PR_ASSERT(NULL != client);
426
client_stack = PR_CreateIOLayer(client);
427
PushNewLayers(client_stack);
428
service = PR_NewTCPSocket(); PR_ASSERT(NULL != service);
429
service_stack = PR_CreateIOLayer(service);
430
PushNewLayers(service_stack);
431
rv = PR_InitializeNetAddr(PR_IpAddrAny, default_port, &any_address);
432
PR_ASSERT(PR_SUCCESS == rv);
433
rv = PR_Bind(service, &any_address); PR_ASSERT(PR_SUCCESS == rv);
434
rv = PR_Listen(service, 10); PR_ASSERT(PR_SUCCESS == rv);
436
minor_iterations = mits;
437
server_thread = PR_CreateThread(
438
PR_USER_THREAD, Server, service_stack,
439
PR_PRIORITY_HIGH, thread_scope,
440
PR_JOINABLE_THREAD, 16 * 1024);
441
PR_ASSERT(NULL != server_thread);
443
client_thread = PR_CreateThread(
444
PR_USER_THREAD, Client, client_stack,
445
PR_PRIORITY_NORMAL, thread_scope,
446
PR_JOINABLE_THREAD, 16 * 1024);
447
PR_ASSERT(NULL != client_thread);
449
rv = PR_JoinThread(client_thread);
450
PR_ASSERT(PR_SUCCESS == rv);
451
rv = PR_JoinThread(server_thread);
452
PR_ASSERT(PR_SUCCESS == rv);
454
rv = PR_Close(client_stack); PR_ASSERT(PR_SUCCESS == rv);
455
rv = PR_Close(service_stack); PR_ASSERT(PR_SUCCESS == rv);
456
if (verbosity > silent)
457
PR_fprintf(logFile, "Ending layered test\n");