1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/nsprpub/pr/tests/layer.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,434 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "prio.h" 1.10 +#include "prprf.h" 1.11 +#include "prlog.h" 1.12 +#include "prnetdb.h" 1.13 +#include "prthread.h" 1.14 + 1.15 +#include "plerror.h" 1.16 +#include "plgetopt.h" 1.17 +#include "prwin16.h" 1.18 + 1.19 +#include <stdlib.h> 1.20 +#include <string.h> 1.21 + 1.22 +/* 1.23 +** Testing layering of I/O 1.24 +** 1.25 +** The layered server 1.26 +** A thread that acts as a server. It creates a TCP listener with a dummy 1.27 +** layer pushed on top. Then listens for incoming connections. Each connection 1.28 +** request for connection will be layered as well, accept one request, echo 1.29 +** it back and close. 1.30 +** 1.31 +** The layered client 1.32 +** Pretty much what you'd expect. 1.33 +*/ 1.34 + 1.35 +static PRFileDesc *logFile; 1.36 +static PRDescIdentity identity; 1.37 +static PRNetAddr server_address; 1.38 + 1.39 +static PRIOMethods myMethods; 1.40 + 1.41 +typedef enum Verbosity {silent, quiet, chatty, noisy} Verbosity; 1.42 + 1.43 +static PRIntn minor_iterations = 5; 1.44 +static PRIntn major_iterations = 1; 1.45 +static Verbosity verbosity = quiet; 1.46 +static PRUint16 default_port = 12273; 1.47 + 1.48 +static PRFileDesc *PushLayer(PRFileDesc *stack) 1.49 +{ 1.50 + PRFileDesc *layer = PR_CreateIOLayerStub(identity, &myMethods); 1.51 + PRStatus rv = PR_PushIOLayer(stack, PR_GetLayersIdentity(stack), layer); 1.52 + if (verbosity > quiet) 1.53 + PR_fprintf(logFile, "Pushed layer(0x%x) onto stack(0x%x)\n", layer, stack); 1.54 + PR_ASSERT(PR_SUCCESS == rv); 1.55 + return stack; 1.56 +} /* PushLayer */ 1.57 + 1.58 +static PRFileDesc *PushNewLayers(PRFileDesc *stack) 1.59 +{ 1.60 + PRDescIdentity tmp_identity; 1.61 + PRFileDesc *layer; 1.62 + PRStatus rv; 1.63 + 1.64 + /* push a dummy layer */ 1.65 + tmp_identity = PR_GetUniqueIdentity("Dummy 1"); 1.66 + layer = PR_CreateIOLayerStub(tmp_identity, PR_GetDefaultIOMethods()); 1.67 + rv = PR_PushIOLayer(stack, PR_GetLayersIdentity(stack), layer); 1.68 + if (verbosity > quiet) 1.69 + PR_fprintf(logFile, "Pushed layer(0x%x) onto stack(0x%x)\n", layer, 1.70 + stack); 1.71 + PR_ASSERT(PR_SUCCESS == rv); 1.72 + 1.73 + /* push a data procesing layer */ 1.74 + layer = PR_CreateIOLayerStub(identity, &myMethods); 1.75 + rv = PR_PushIOLayer(stack, PR_GetLayersIdentity(stack), layer); 1.76 + if (verbosity > quiet) 1.77 + PR_fprintf(logFile, "Pushed layer(0x%x) onto stack(0x%x)\n", layer, 1.78 + stack); 1.79 + PR_ASSERT(PR_SUCCESS == rv); 1.80 + 1.81 + /* push another dummy layer */ 1.82 + tmp_identity = PR_GetUniqueIdentity("Dummy 2"); 1.83 + layer = PR_CreateIOLayerStub(tmp_identity, PR_GetDefaultIOMethods()); 1.84 + rv = PR_PushIOLayer(stack, PR_GetLayersIdentity(stack), layer); 1.85 + if (verbosity > quiet) 1.86 + PR_fprintf(logFile, "Pushed layer(0x%x) onto stack(0x%x)\n", layer, 1.87 + stack); 1.88 + PR_ASSERT(PR_SUCCESS == rv); 1.89 + return stack; 1.90 +} /* PushLayer */ 1.91 + 1.92 +#if 0 1.93 +static PRFileDesc *PopLayer(PRFileDesc *stack) 1.94 +{ 1.95 + PRFileDesc *popped = PR_PopIOLayer(stack, identity); 1.96 + if (verbosity > quiet) 1.97 + PR_fprintf(logFile, "Popped layer(0x%x) from stack(0x%x)\n", popped, stack); 1.98 + popped->dtor(popped); 1.99 + 1.100 + return stack; 1.101 +} /* PopLayer */ 1.102 +#endif 1.103 + 1.104 +static void PR_CALLBACK Client(void *arg) 1.105 +{ 1.106 + PRStatus rv; 1.107 + PRUint8 buffer[100]; 1.108 + PRIntn empty_flags = 0; 1.109 + PRIntn bytes_read, bytes_sent; 1.110 + PRFileDesc *stack = (PRFileDesc*)arg; 1.111 + 1.112 + /* Initialize the buffer so that Purify won't complain */ 1.113 + memset(buffer, 0, sizeof(buffer)); 1.114 + 1.115 + rv = PR_Connect(stack, &server_address, PR_INTERVAL_NO_TIMEOUT); 1.116 + PR_ASSERT(PR_SUCCESS == rv); 1.117 + while (minor_iterations-- > 0) 1.118 + { 1.119 + bytes_sent = PR_Send( 1.120 + stack, buffer, sizeof(buffer), empty_flags, PR_INTERVAL_NO_TIMEOUT); 1.121 + PR_ASSERT(sizeof(buffer) == bytes_sent); 1.122 + if (verbosity > chatty) 1.123 + PR_fprintf(logFile, "Client sending %d bytes\n", bytes_sent); 1.124 + bytes_read = PR_Recv( 1.125 + stack, buffer, bytes_sent, empty_flags, PR_INTERVAL_NO_TIMEOUT); 1.126 + if (verbosity > chatty) 1.127 + PR_fprintf(logFile, "Client receiving %d bytes\n", bytes_read); 1.128 + PR_ASSERT(bytes_read == bytes_sent); 1.129 + } 1.130 + 1.131 + if (verbosity > quiet) 1.132 + PR_fprintf(logFile, "Client shutting down stack\n"); 1.133 + 1.134 + rv = PR_Shutdown(stack, PR_SHUTDOWN_BOTH); PR_ASSERT(PR_SUCCESS == rv); 1.135 +} /* Client */ 1.136 + 1.137 +static void PR_CALLBACK Server(void *arg) 1.138 +{ 1.139 + PRStatus rv; 1.140 + PRUint8 buffer[100]; 1.141 + PRFileDesc *service; 1.142 + PRUintn empty_flags = 0; 1.143 + PRIntn bytes_read, bytes_sent; 1.144 + PRFileDesc *stack = (PRFileDesc*)arg; 1.145 + PRNetAddr client_address; 1.146 + 1.147 + service = PR_Accept(stack, &client_address, PR_INTERVAL_NO_TIMEOUT); 1.148 + if (verbosity > quiet) 1.149 + PR_fprintf(logFile, "Server accepting connection\n"); 1.150 + 1.151 + do 1.152 + { 1.153 + bytes_read = PR_Recv( 1.154 + service, buffer, sizeof(buffer), empty_flags, PR_INTERVAL_NO_TIMEOUT); 1.155 + if (0 != bytes_read) 1.156 + { 1.157 + if (verbosity > chatty) 1.158 + PR_fprintf(logFile, "Server receiving %d bytes\n", bytes_read); 1.159 + PR_ASSERT(bytes_read > 0); 1.160 + bytes_sent = PR_Send( 1.161 + service, buffer, bytes_read, empty_flags, PR_INTERVAL_NO_TIMEOUT); 1.162 + if (verbosity > chatty) 1.163 + PR_fprintf(logFile, "Server sending %d bytes\n", bytes_sent); 1.164 + PR_ASSERT(bytes_read == bytes_sent); 1.165 + } 1.166 + 1.167 + } while (0 != bytes_read); 1.168 + 1.169 + if (verbosity > quiet) 1.170 + PR_fprintf(logFile, "Server shutting down and closing stack\n"); 1.171 + rv = PR_Shutdown(service, PR_SHUTDOWN_BOTH); PR_ASSERT(PR_SUCCESS == rv); 1.172 + rv = PR_Close(service); PR_ASSERT(PR_SUCCESS == rv); 1.173 + 1.174 +} /* Server */ 1.175 + 1.176 +static PRInt32 PR_CALLBACK MyRecv( 1.177 + PRFileDesc *fd, void *buf, PRInt32 amount, 1.178 + PRIntn flags, PRIntervalTime timeout) 1.179 +{ 1.180 + char *b = (char*)buf; 1.181 + PRFileDesc *lo = fd->lower; 1.182 + PRInt32 rv, readin = 0, request = 0; 1.183 + rv = lo->methods->recv(lo, &request, sizeof(request), flags, timeout); 1.184 + if (verbosity > chatty) PR_fprintf( 1.185 + logFile, "MyRecv sending permission for %d bytes\n", request); 1.186 + if (0 < rv) 1.187 + { 1.188 + if (verbosity > chatty) PR_fprintf( 1.189 + logFile, "MyRecv received permission request for %d bytes\n", request); 1.190 + rv = lo->methods->send( 1.191 + lo, &request, sizeof(request), flags, timeout); 1.192 + if (0 < rv) 1.193 + { 1.194 + if (verbosity > chatty) PR_fprintf( 1.195 + logFile, "MyRecv sending permission for %d bytes\n", request); 1.196 + while (readin < request) 1.197 + { 1.198 + rv = lo->methods->recv( 1.199 + lo, b + readin, amount - readin, flags, timeout); 1.200 + if (rv <= 0) break; 1.201 + if (verbosity > chatty) PR_fprintf( 1.202 + logFile, "MyRecv received %d bytes\n", rv); 1.203 + readin += rv; 1.204 + } 1.205 + rv = readin; 1.206 + } 1.207 + } 1.208 + return rv; 1.209 +} /* MyRecv */ 1.210 + 1.211 +static PRInt32 PR_CALLBACK MySend( 1.212 + PRFileDesc *fd, const void *buf, PRInt32 amount, 1.213 + PRIntn flags, PRIntervalTime timeout) 1.214 +{ 1.215 + PRFileDesc *lo = fd->lower; 1.216 + const char *b = (const char*)buf; 1.217 + PRInt32 rv, wroteout = 0, request; 1.218 + if (verbosity > chatty) PR_fprintf( 1.219 + logFile, "MySend asking permission to send %d bytes\n", amount); 1.220 + rv = lo->methods->send(lo, &amount, sizeof(amount), flags, timeout); 1.221 + if (0 < rv) 1.222 + { 1.223 + rv = lo->methods->recv( 1.224 + lo, &request, sizeof(request), flags, timeout); 1.225 + if (0 < rv) 1.226 + { 1.227 + PR_ASSERT(request == amount); 1.228 + if (verbosity > chatty) PR_fprintf( 1.229 + logFile, "MySend got permission to send %d bytes\n", request); 1.230 + while (wroteout < request) 1.231 + { 1.232 + rv = lo->methods->send( 1.233 + lo, b + wroteout, request - wroteout, flags, timeout); 1.234 + if (rv <= 0) break; 1.235 + if (verbosity > chatty) PR_fprintf( 1.236 + logFile, "MySend wrote %d bytes\n", rv); 1.237 + wroteout += rv; 1.238 + } 1.239 + rv = amount; 1.240 + } 1.241 + } 1.242 + return rv; 1.243 +} /* MySend */ 1.244 + 1.245 +static Verbosity ChangeVerbosity(Verbosity verbosity, PRIntn delta) 1.246 +{ 1.247 + PRIntn verbage = (PRIntn)verbosity + delta; 1.248 + if (verbage < (PRIntn)silent) verbage = (PRIntn)silent; 1.249 + else if (verbage > (PRIntn)noisy) verbage = (PRIntn)noisy; 1.250 + return (Verbosity)verbage; 1.251 +} /* ChangeVerbosity */ 1.252 + 1.253 +int main(int argc, char **argv) 1.254 +{ 1.255 + PRStatus rv; 1.256 + PRIntn mits; 1.257 + PLOptStatus os; 1.258 + PRFileDesc *client, *service; 1.259 + PRFileDesc *client_stack, *service_stack; 1.260 + PRNetAddr any_address; 1.261 + const char *server_name = NULL; 1.262 + const PRIOMethods *stubMethods; 1.263 + PRThread *client_thread, *server_thread; 1.264 + PRThreadScope thread_scope = PR_LOCAL_THREAD; 1.265 + PLOptState *opt = PL_CreateOptState(argc, argv, "dqGC:c:p:"); 1.266 + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) 1.267 + { 1.268 + if (PL_OPT_BAD == os) continue; 1.269 + switch (opt->option) 1.270 + { 1.271 + case 0: 1.272 + server_name = opt->value; 1.273 + break; 1.274 + case 'd': /* debug mode */ 1.275 + if (verbosity < noisy) 1.276 + verbosity = ChangeVerbosity(verbosity, 1); 1.277 + break; 1.278 + case 'q': /* debug mode */ 1.279 + if (verbosity > silent) 1.280 + verbosity = ChangeVerbosity(verbosity, -1); 1.281 + break; 1.282 + case 'G': /* use global threads */ 1.283 + thread_scope = PR_GLOBAL_THREAD; 1.284 + break; 1.285 + case 'C': /* number of threads waiting */ 1.286 + major_iterations = atoi(opt->value); 1.287 + break; 1.288 + case 'c': /* number of client threads */ 1.289 + minor_iterations = atoi(opt->value); 1.290 + break; 1.291 + case 'p': /* default port */ 1.292 + default_port = atoi(opt->value); 1.293 + break; 1.294 + default: 1.295 + break; 1.296 + } 1.297 + } 1.298 + PL_DestroyOptState(opt); 1.299 + PR_STDIO_INIT(); 1.300 + 1.301 + logFile = PR_GetSpecialFD(PR_StandardError); 1.302 + 1.303 + identity = PR_GetUniqueIdentity("Dummy"); 1.304 + stubMethods = PR_GetDefaultIOMethods(); 1.305 + 1.306 + /* 1.307 + ** The protocol we're going to implement is one where in order to initiate 1.308 + ** a send, the sender must first solicit permission. Therefore, every 1.309 + ** send is really a send - receive - send sequence. 1.310 + */ 1.311 + myMethods = *stubMethods; /* first get the entire batch */ 1.312 + myMethods.recv = MyRecv; /* then override the ones we care about */ 1.313 + myMethods.send = MySend; /* then override the ones we care about */ 1.314 + 1.315 + if (NULL == server_name) 1.316 + rv = PR_InitializeNetAddr( 1.317 + PR_IpAddrLoopback, default_port, &server_address); 1.318 + else 1.319 + { 1.320 + rv = PR_StringToNetAddr(server_name, &server_address); 1.321 + PR_ASSERT(PR_SUCCESS == rv); 1.322 + rv = PR_InitializeNetAddr( 1.323 + PR_IpAddrNull, default_port, &server_address); 1.324 + } 1.325 + PR_ASSERT(PR_SUCCESS == rv); 1.326 + 1.327 + /* one type w/o layering */ 1.328 + 1.329 + mits = minor_iterations; 1.330 + while (major_iterations-- > 0) 1.331 + { 1.332 + if (verbosity > silent) 1.333 + PR_fprintf(logFile, "Beginning non-layered test\n"); 1.334 + client = PR_NewTCPSocket(); PR_ASSERT(NULL != client); 1.335 + service = PR_NewTCPSocket(); PR_ASSERT(NULL != service); 1.336 + rv = PR_InitializeNetAddr(PR_IpAddrAny, default_port, &any_address); 1.337 + PR_ASSERT(PR_SUCCESS == rv); 1.338 + rv = PR_Bind(service, &any_address); PR_ASSERT(PR_SUCCESS == rv); 1.339 + rv = PR_Listen(service, 10); PR_ASSERT(PR_SUCCESS == rv); 1.340 + 1.341 + minor_iterations = mits; 1.342 + server_thread = PR_CreateThread( 1.343 + PR_USER_THREAD, Server, service, 1.344 + PR_PRIORITY_HIGH, thread_scope, 1.345 + PR_JOINABLE_THREAD, 16 * 1024); 1.346 + PR_ASSERT(NULL != server_thread); 1.347 + 1.348 + client_thread = PR_CreateThread( 1.349 + PR_USER_THREAD, Client, client, 1.350 + PR_PRIORITY_NORMAL, thread_scope, 1.351 + PR_JOINABLE_THREAD, 16 * 1024); 1.352 + PR_ASSERT(NULL != client_thread); 1.353 + 1.354 + rv = PR_JoinThread(client_thread); 1.355 + PR_ASSERT(PR_SUCCESS == rv); 1.356 + rv = PR_JoinThread(server_thread); 1.357 + PR_ASSERT(PR_SUCCESS == rv); 1.358 + 1.359 + rv = PR_Close(client); PR_ASSERT(PR_SUCCESS == rv); 1.360 + rv = PR_Close(service); PR_ASSERT(PR_SUCCESS == rv); 1.361 + if (verbosity > silent) 1.362 + PR_fprintf(logFile, "Ending non-layered test\n"); 1.363 + 1.364 + /* with layering */ 1.365 + if (verbosity > silent) 1.366 + PR_fprintf(logFile, "Beginning layered test\n"); 1.367 + client = PR_NewTCPSocket(); PR_ASSERT(NULL != client); 1.368 + PushLayer(client); 1.369 + service = PR_NewTCPSocket(); PR_ASSERT(NULL != service); 1.370 + PushLayer(service); 1.371 + rv = PR_InitializeNetAddr(PR_IpAddrAny, default_port, &any_address); 1.372 + PR_ASSERT(PR_SUCCESS == rv); 1.373 + rv = PR_Bind(service, &any_address); PR_ASSERT(PR_SUCCESS == rv); 1.374 + rv = PR_Listen(service, 10); PR_ASSERT(PR_SUCCESS == rv); 1.375 + 1.376 + minor_iterations = mits; 1.377 + server_thread = PR_CreateThread( 1.378 + PR_USER_THREAD, Server, service, 1.379 + PR_PRIORITY_HIGH, thread_scope, 1.380 + PR_JOINABLE_THREAD, 16 * 1024); 1.381 + PR_ASSERT(NULL != server_thread); 1.382 + 1.383 + client_thread = PR_CreateThread( 1.384 + PR_USER_THREAD, Client, client, 1.385 + PR_PRIORITY_NORMAL, thread_scope, 1.386 + PR_JOINABLE_THREAD, 16 * 1024); 1.387 + PR_ASSERT(NULL != client_thread); 1.388 + 1.389 + rv = PR_JoinThread(client_thread); 1.390 + PR_ASSERT(PR_SUCCESS == rv); 1.391 + rv = PR_JoinThread(server_thread); 1.392 + PR_ASSERT(PR_SUCCESS == rv); 1.393 + 1.394 + rv = PR_Close(client); PR_ASSERT(PR_SUCCESS == rv); 1.395 + rv = PR_Close(service); PR_ASSERT(PR_SUCCESS == rv); 1.396 + /* with layering, using new style stack */ 1.397 + if (verbosity > silent) 1.398 + PR_fprintf(logFile, 1.399 + "Beginning layered test with new style stack\n"); 1.400 + client = PR_NewTCPSocket(); PR_ASSERT(NULL != client); 1.401 + client_stack = PR_CreateIOLayer(client); 1.402 + PushNewLayers(client_stack); 1.403 + service = PR_NewTCPSocket(); PR_ASSERT(NULL != service); 1.404 + service_stack = PR_CreateIOLayer(service); 1.405 + PushNewLayers(service_stack); 1.406 + rv = PR_InitializeNetAddr(PR_IpAddrAny, default_port, &any_address); 1.407 + PR_ASSERT(PR_SUCCESS == rv); 1.408 + rv = PR_Bind(service, &any_address); PR_ASSERT(PR_SUCCESS == rv); 1.409 + rv = PR_Listen(service, 10); PR_ASSERT(PR_SUCCESS == rv); 1.410 + 1.411 + minor_iterations = mits; 1.412 + server_thread = PR_CreateThread( 1.413 + PR_USER_THREAD, Server, service_stack, 1.414 + PR_PRIORITY_HIGH, thread_scope, 1.415 + PR_JOINABLE_THREAD, 16 * 1024); 1.416 + PR_ASSERT(NULL != server_thread); 1.417 + 1.418 + client_thread = PR_CreateThread( 1.419 + PR_USER_THREAD, Client, client_stack, 1.420 + PR_PRIORITY_NORMAL, thread_scope, 1.421 + PR_JOINABLE_THREAD, 16 * 1024); 1.422 + PR_ASSERT(NULL != client_thread); 1.423 + 1.424 + rv = PR_JoinThread(client_thread); 1.425 + PR_ASSERT(PR_SUCCESS == rv); 1.426 + rv = PR_JoinThread(server_thread); 1.427 + PR_ASSERT(PR_SUCCESS == rv); 1.428 + 1.429 + rv = PR_Close(client_stack); PR_ASSERT(PR_SUCCESS == rv); 1.430 + rv = PR_Close(service_stack); PR_ASSERT(PR_SUCCESS == rv); 1.431 + if (verbosity > silent) 1.432 + PR_fprintf(logFile, "Ending layered test\n"); 1.433 + } 1.434 + return 0; 1.435 +} /* main */ 1.436 + 1.437 +/* layer.c */