layer.c (14576B)
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/. */ 5 6 #include "prio.h" 7 #include "prprf.h" 8 #include "prlog.h" 9 #include "prnetdb.h" 10 #include "prthread.h" 11 12 #include "plerror.h" 13 #include "plgetopt.h" 14 15 #include <stdlib.h> 16 #include <string.h> 17 18 /* 19 ** Testing layering of I/O 20 ** 21 ** The layered server 22 ** A thread that acts as a server. It creates a TCP listener with a dummy 23 ** layer pushed on top. Then listens for incoming connections. Each connection 24 ** request for connection will be layered as well, accept one request, echo 25 ** it back and close. 26 ** 27 ** The layered client 28 ** Pretty much what you'd expect. 29 */ 30 31 static PRFileDesc* logFile; 32 static PRDescIdentity identity; 33 static PRNetAddr server_address; 34 35 static PRIOMethods myMethods; 36 37 typedef enum Verbosity { silent, quiet, chatty, noisy } Verbosity; 38 39 static PRIntn minor_iterations = 5; 40 static PRIntn major_iterations = 1; 41 static Verbosity verbosity = quiet; 42 43 #ifdef DEBUG 44 # define PORT_INC_DO +100 45 #else 46 # define PORT_INC_DO 47 #endif 48 #ifdef IS_64 49 # define PORT_INC_3264 +200 50 #else 51 # define PORT_INC_3264 52 #endif 53 54 static PRUint16 default_port = 12273 PORT_INC_DO PORT_INC_3264; 55 56 static PRFileDesc* PushLayer(PRFileDesc* stack) { 57 PRFileDesc* layer = PR_CreateIOLayerStub(identity, &myMethods); 58 PRStatus rv = PR_PushIOLayer(stack, PR_GetLayersIdentity(stack), layer); 59 if (verbosity > quiet) { 60 PR_fprintf(logFile, "Pushed layer(0x%x) onto stack(0x%x)\n", layer, stack); 61 } 62 PR_ASSERT(PR_SUCCESS == rv); 63 return stack; 64 } /* PushLayer */ 65 66 static PRFileDesc* PushNewLayers(PRFileDesc* stack) { 67 PRDescIdentity tmp_identity; 68 PRFileDesc* layer; 69 PRStatus rv; 70 71 /* push a dummy layer */ 72 tmp_identity = PR_GetUniqueIdentity("Dummy 1"); 73 layer = PR_CreateIOLayerStub(tmp_identity, PR_GetDefaultIOMethods()); 74 rv = PR_PushIOLayer(stack, PR_GetLayersIdentity(stack), layer); 75 if (verbosity > quiet) 76 PR_fprintf(logFile, "Pushed layer(0x%x) onto stack(0x%x)\n", layer, stack); 77 PR_ASSERT(PR_SUCCESS == rv); 78 79 /* push a data processing layer */ 80 layer = PR_CreateIOLayerStub(identity, &myMethods); 81 rv = PR_PushIOLayer(stack, PR_GetLayersIdentity(stack), layer); 82 if (verbosity > quiet) 83 PR_fprintf(logFile, "Pushed layer(0x%x) onto stack(0x%x)\n", layer, stack); 84 PR_ASSERT(PR_SUCCESS == rv); 85 86 /* push another dummy layer */ 87 tmp_identity = PR_GetUniqueIdentity("Dummy 2"); 88 layer = PR_CreateIOLayerStub(tmp_identity, PR_GetDefaultIOMethods()); 89 rv = PR_PushIOLayer(stack, PR_GetLayersIdentity(stack), layer); 90 if (verbosity > quiet) 91 PR_fprintf(logFile, "Pushed layer(0x%x) onto stack(0x%x)\n", layer, stack); 92 PR_ASSERT(PR_SUCCESS == rv); 93 return stack; 94 } /* PushLayer */ 95 96 #if 0 97 static PRFileDesc *PopLayer(PRFileDesc *stack) 98 { 99 PRFileDesc *popped = PR_PopIOLayer(stack, identity); 100 if (verbosity > quiet) { 101 PR_fprintf(logFile, "Popped layer(0x%x) from stack(0x%x)\n", popped, stack); 102 } 103 popped->dtor(popped); 104 105 return stack; 106 } /* PopLayer */ 107 #endif 108 109 static void PR_CALLBACK Client(void* arg) { 110 PRStatus rv; 111 PRUint8 buffer[100]; 112 PRIntn empty_flags = 0; 113 PRIntn bytes_read, bytes_sent; 114 PRFileDesc* stack = (PRFileDesc*)arg; 115 116 /* Initialize the buffer so that Purify won't complain */ 117 memset(buffer, 0, sizeof(buffer)); 118 119 rv = PR_Connect(stack, &server_address, PR_INTERVAL_NO_TIMEOUT); 120 PR_ASSERT(PR_SUCCESS == rv); 121 while (minor_iterations-- > 0) { 122 bytes_sent = PR_Send(stack, buffer, sizeof(buffer), empty_flags, 123 PR_INTERVAL_NO_TIMEOUT); 124 PR_ASSERT(sizeof(buffer) == bytes_sent); 125 if (verbosity > chatty) { 126 PR_fprintf(logFile, "Client sending %d bytes\n", bytes_sent); 127 } 128 bytes_read = 129 PR_Recv(stack, buffer, bytes_sent, empty_flags, PR_INTERVAL_NO_TIMEOUT); 130 if (verbosity > chatty) { 131 PR_fprintf(logFile, "Client receiving %d bytes\n", bytes_read); 132 } 133 PR_ASSERT(bytes_read == bytes_sent); 134 } 135 136 if (verbosity > quiet) { 137 PR_fprintf(logFile, "Client shutting down stack\n"); 138 } 139 140 rv = PR_Shutdown(stack, PR_SHUTDOWN_BOTH); 141 PR_ASSERT(PR_SUCCESS == rv); 142 } /* Client */ 143 144 static void PR_CALLBACK Server(void* arg) { 145 PRStatus rv; 146 PRUint8 buffer[100]; 147 PRFileDesc* service; 148 PRUintn empty_flags = 0; 149 PRIntn bytes_read, bytes_sent; 150 PRFileDesc* stack = (PRFileDesc*)arg; 151 PRNetAddr client_address; 152 153 service = PR_Accept(stack, &client_address, PR_INTERVAL_NO_TIMEOUT); 154 if (verbosity > quiet) { 155 PR_fprintf(logFile, "Server accepting connection\n"); 156 } 157 158 do { 159 bytes_read = PR_Recv(service, buffer, sizeof(buffer), empty_flags, 160 PR_INTERVAL_NO_TIMEOUT); 161 if (0 != bytes_read) { 162 if (verbosity > chatty) { 163 PR_fprintf(logFile, "Server receiving %d bytes\n", bytes_read); 164 } 165 PR_ASSERT(bytes_read > 0); 166 bytes_sent = PR_Send(service, buffer, bytes_read, empty_flags, 167 PR_INTERVAL_NO_TIMEOUT); 168 if (verbosity > chatty) { 169 PR_fprintf(logFile, "Server sending %d bytes\n", bytes_sent); 170 } 171 PR_ASSERT(bytes_read == bytes_sent); 172 } 173 174 } while (0 != bytes_read); 175 176 if (verbosity > quiet) { 177 PR_fprintf(logFile, "Server shutting down and closing stack\n"); 178 } 179 rv = PR_Shutdown(service, PR_SHUTDOWN_BOTH); 180 PR_ASSERT(PR_SUCCESS == rv); 181 rv = PR_Close(service); 182 PR_ASSERT(PR_SUCCESS == rv); 183 184 } /* Server */ 185 186 static PRInt32 PR_CALLBACK MyRecv(PRFileDesc* fd, void* buf, PRInt32 amount, 187 PRIntn flags, PRIntervalTime timeout) { 188 char* b = (char*)buf; 189 PRFileDesc* lo = fd->lower; 190 PRInt32 rv, readin = 0, request = 0; 191 rv = lo->methods->recv(lo, &request, sizeof(request), flags, timeout); 192 if (verbosity > chatty) 193 PR_fprintf(logFile, "MyRecv sending permission for %d bytes\n", request); 194 if (0 < rv) { 195 if (verbosity > chatty) 196 PR_fprintf(logFile, "MyRecv received permission request for %d bytes\n", 197 request); 198 rv = lo->methods->send(lo, &request, sizeof(request), flags, timeout); 199 if (0 < rv) { 200 if (verbosity > chatty) 201 PR_fprintf(logFile, "MyRecv sending permission for %d bytes\n", 202 request); 203 while (readin < request) { 204 rv = lo->methods->recv(lo, b + readin, amount - readin, flags, timeout); 205 if (rv <= 0) { 206 break; 207 } 208 if (verbosity > chatty) 209 PR_fprintf(logFile, "MyRecv received %d bytes\n", rv); 210 readin += rv; 211 } 212 rv = readin; 213 } 214 } 215 return rv; 216 } /* MyRecv */ 217 218 static PRInt32 PR_CALLBACK MySend(PRFileDesc* fd, const void* buf, 219 PRInt32 amount, PRIntn flags, 220 PRIntervalTime timeout) { 221 PRFileDesc* lo = fd->lower; 222 const char* b = (const char*)buf; 223 PRInt32 rv, wroteout = 0, request; 224 if (verbosity > chatty) 225 PR_fprintf(logFile, "MySend asking permission to send %d bytes\n", amount); 226 rv = lo->methods->send(lo, &amount, sizeof(amount), flags, timeout); 227 if (0 < rv) { 228 rv = lo->methods->recv(lo, &request, sizeof(request), flags, timeout); 229 if (0 < rv) { 230 PR_ASSERT(request == amount); 231 if (verbosity > chatty) 232 PR_fprintf(logFile, "MySend got permission to send %d bytes\n", 233 request); 234 while (wroteout < request) { 235 rv = lo->methods->send(lo, b + wroteout, request - wroteout, flags, 236 timeout); 237 if (rv <= 0) { 238 break; 239 } 240 if (verbosity > chatty) 241 PR_fprintf(logFile, "MySend wrote %d bytes\n", rv); 242 wroteout += rv; 243 } 244 rv = amount; 245 } 246 } 247 return rv; 248 } /* MySend */ 249 250 static Verbosity ChangeVerbosity(Verbosity verbosity, PRIntn delta) { 251 PRIntn verbage = (PRIntn)verbosity + delta; 252 if (verbage < (PRIntn)silent) { 253 verbage = (PRIntn)silent; 254 } else if (verbage > (PRIntn)noisy) { 255 verbage = (PRIntn)noisy; 256 } 257 return (Verbosity)verbage; 258 } /* ChangeVerbosity */ 259 260 int main(int argc, char** argv) { 261 PRStatus rv; 262 PRIntn mits; 263 PLOptStatus os; 264 PRFileDesc *client, *service; 265 PRFileDesc *client_stack, *service_stack; 266 PRNetAddr any_address; 267 const char* server_name = NULL; 268 const PRIOMethods* stubMethods; 269 PRThread *client_thread, *server_thread; 270 PRThreadScope thread_scope = PR_LOCAL_THREAD; 271 PLOptState* opt = PL_CreateOptState(argc, argv, "dqGC:c:p:"); 272 while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) { 273 if (PL_OPT_BAD == os) { 274 continue; 275 } 276 switch (opt->option) { 277 case 0: 278 server_name = opt->value; 279 break; 280 case 'd': /* debug mode */ 281 if (verbosity < noisy) { 282 verbosity = ChangeVerbosity(verbosity, 1); 283 } 284 break; 285 case 'q': /* debug mode */ 286 if (verbosity > silent) { 287 verbosity = ChangeVerbosity(verbosity, -1); 288 } 289 break; 290 case 'G': /* use global threads */ 291 thread_scope = PR_GLOBAL_THREAD; 292 break; 293 case 'C': /* number of threads waiting */ 294 major_iterations = atoi(opt->value); 295 break; 296 case 'c': /* number of client threads */ 297 minor_iterations = atoi(opt->value); 298 break; 299 case 'p': /* default port */ 300 default_port = atoi(opt->value); 301 break; 302 default: 303 break; 304 } 305 } 306 PL_DestroyOptState(opt); 307 308 logFile = PR_GetSpecialFD(PR_StandardError); 309 310 identity = PR_GetUniqueIdentity("Dummy"); 311 stubMethods = PR_GetDefaultIOMethods(); 312 313 /* 314 ** The protocol we're going to implement is one where in order to initiate 315 ** a send, the sender must first solicit permission. Therefore, every 316 ** send is really a send - receive - send sequence. 317 */ 318 myMethods = *stubMethods; /* first get the entire batch */ 319 myMethods.recv = MyRecv; /* then override the ones we care about */ 320 myMethods.send = MySend; /* then override the ones we care about */ 321 322 if (NULL == server_name) 323 rv = PR_InitializeNetAddr(PR_IpAddrLoopback, default_port, &server_address); 324 else { 325 rv = PR_StringToNetAddr(server_name, &server_address); 326 PR_ASSERT(PR_SUCCESS == rv); 327 rv = PR_InitializeNetAddr(PR_IpAddrNull, default_port, &server_address); 328 } 329 PR_ASSERT(PR_SUCCESS == rv); 330 331 /* one type w/o layering */ 332 333 mits = minor_iterations; 334 while (major_iterations-- > 0) { 335 if (verbosity > silent) { 336 PR_fprintf(logFile, "Beginning non-layered test\n"); 337 } 338 client = PR_NewTCPSocket(); 339 PR_ASSERT(NULL != client); 340 service = PR_NewTCPSocket(); 341 PR_ASSERT(NULL != service); 342 rv = PR_InitializeNetAddr(PR_IpAddrAny, default_port, &any_address); 343 PR_ASSERT(PR_SUCCESS == rv); 344 rv = PR_Bind(service, &any_address); 345 PR_ASSERT(PR_SUCCESS == rv); 346 rv = PR_Listen(service, 10); 347 PR_ASSERT(PR_SUCCESS == rv); 348 349 minor_iterations = mits; 350 server_thread = 351 PR_CreateThread(PR_USER_THREAD, Server, service, PR_PRIORITY_HIGH, 352 thread_scope, PR_JOINABLE_THREAD, 16 * 1024); 353 PR_ASSERT(NULL != server_thread); 354 355 client_thread = 356 PR_CreateThread(PR_USER_THREAD, Client, client, PR_PRIORITY_NORMAL, 357 thread_scope, PR_JOINABLE_THREAD, 16 * 1024); 358 PR_ASSERT(NULL != client_thread); 359 360 rv = PR_JoinThread(client_thread); 361 PR_ASSERT(PR_SUCCESS == rv); 362 rv = PR_JoinThread(server_thread); 363 PR_ASSERT(PR_SUCCESS == rv); 364 365 rv = PR_Close(client); 366 PR_ASSERT(PR_SUCCESS == rv); 367 rv = PR_Close(service); 368 PR_ASSERT(PR_SUCCESS == rv); 369 if (verbosity > silent) { 370 PR_fprintf(logFile, "Ending non-layered test\n"); 371 } 372 373 /* with layering */ 374 if (verbosity > silent) { 375 PR_fprintf(logFile, "Beginning layered test\n"); 376 } 377 client = PR_NewTCPSocket(); 378 PR_ASSERT(NULL != client); 379 PushLayer(client); 380 service = PR_NewTCPSocket(); 381 PR_ASSERT(NULL != service); 382 PushLayer(service); 383 rv = PR_InitializeNetAddr(PR_IpAddrAny, default_port, &any_address); 384 PR_ASSERT(PR_SUCCESS == rv); 385 rv = PR_Bind(service, &any_address); 386 PR_ASSERT(PR_SUCCESS == rv); 387 rv = PR_Listen(service, 10); 388 PR_ASSERT(PR_SUCCESS == rv); 389 390 minor_iterations = mits; 391 server_thread = 392 PR_CreateThread(PR_USER_THREAD, Server, service, PR_PRIORITY_HIGH, 393 thread_scope, PR_JOINABLE_THREAD, 16 * 1024); 394 PR_ASSERT(NULL != server_thread); 395 396 client_thread = 397 PR_CreateThread(PR_USER_THREAD, Client, client, PR_PRIORITY_NORMAL, 398 thread_scope, PR_JOINABLE_THREAD, 16 * 1024); 399 PR_ASSERT(NULL != client_thread); 400 401 rv = PR_JoinThread(client_thread); 402 PR_ASSERT(PR_SUCCESS == rv); 403 rv = PR_JoinThread(server_thread); 404 PR_ASSERT(PR_SUCCESS == rv); 405 406 rv = PR_Close(client); 407 PR_ASSERT(PR_SUCCESS == rv); 408 rv = PR_Close(service); 409 PR_ASSERT(PR_SUCCESS == rv); 410 /* with layering, using new style stack */ 411 if (verbosity > silent) 412 PR_fprintf(logFile, "Beginning layered test with new style stack\n"); 413 client = PR_NewTCPSocket(); 414 PR_ASSERT(NULL != client); 415 client_stack = PR_CreateIOLayer(client); 416 PushNewLayers(client_stack); 417 service = PR_NewTCPSocket(); 418 PR_ASSERT(NULL != service); 419 service_stack = PR_CreateIOLayer(service); 420 PushNewLayers(service_stack); 421 rv = PR_InitializeNetAddr(PR_IpAddrAny, default_port, &any_address); 422 PR_ASSERT(PR_SUCCESS == rv); 423 rv = PR_Bind(service, &any_address); 424 PR_ASSERT(PR_SUCCESS == rv); 425 rv = PR_Listen(service, 10); 426 PR_ASSERT(PR_SUCCESS == rv); 427 428 minor_iterations = mits; 429 server_thread = 430 PR_CreateThread(PR_USER_THREAD, Server, service_stack, PR_PRIORITY_HIGH, 431 thread_scope, PR_JOINABLE_THREAD, 16 * 1024); 432 PR_ASSERT(NULL != server_thread); 433 434 client_thread = PR_CreateThread(PR_USER_THREAD, Client, client_stack, 435 PR_PRIORITY_NORMAL, thread_scope, 436 PR_JOINABLE_THREAD, 16 * 1024); 437 PR_ASSERT(NULL != client_thread); 438 439 rv = PR_JoinThread(client_thread); 440 PR_ASSERT(PR_SUCCESS == rv); 441 rv = PR_JoinThread(server_thread); 442 PR_ASSERT(PR_SUCCESS == rv); 443 444 rv = PR_Close(client_stack); 445 PR_ASSERT(PR_SUCCESS == rv); 446 rv = PR_Close(service_stack); 447 PR_ASSERT(PR_SUCCESS == rv); 448 if (verbosity > silent) { 449 PR_fprintf(logFile, "Ending layered test\n"); 450 } 451 } 452 return 0; 453 } /* main */ 454 455 /* layer.c */