📄 nblayer.c
字号:
break; case xmt_send_debit: case xmt_data: my_flags = in_flags; default: break; } } else PR_ASSERT(!"How'd I get here?"); new_flags = (fd->lower->methods->poll)(fd->lower, my_flags, out_flags); if (verbosity > chatty) PR_fprintf( logFile, "Poll [i: 0x%x, m: 0x%x, o: 0x%x, n: 0x%x]\n", in_flags, my_flags, *out_flags, new_flags); return new_flags;} /* MyPoll */static PRFileDesc * PR_CALLBACK MyAccept( PRFileDesc *fd, PRNetAddr *addr, PRIntervalTime timeout){ PRStatus rv; PRFileDesc *newfd, *layer = fd; PRFileDesc *newstack; PRFilePrivate *newsecret; PR_ASSERT(fd != NULL); PR_ASSERT(fd->lower != NULL); newstack = PR_NEW(PRFileDesc); if (NULL == newstack) { PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); return NULL; } newsecret = PR_NEW(PRFilePrivate); if (NULL == newsecret) { PR_DELETE(newstack); PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); return NULL; } *newstack = *fd; /* make a copy of the accepting layer */ *newsecret = *fd->secret; newstack->secret = newsecret; newfd = (fd->lower->methods->accept)(fd->lower, addr, timeout); if (NULL == newfd) { PR_DELETE(newsecret); PR_DELETE(newstack); return NULL; } /* this PR_PushIOLayer call cannot fail */ rv = PR_PushIOLayer(newfd, PR_TOP_IO_LAYER, newstack); PR_ASSERT(PR_SUCCESS == rv); return newfd; /* that's it */}static PRInt32 PR_CALLBACK MyRecv( PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, PRIntervalTime timeout){ char *b; PRInt32 rv; PRFileDesc *lo = fd->lower; PRFilePrivate *mine = (PRFilePrivate*)fd->secret; do { switch (mine->rcvstate) { case rcv_get_debit: b = (char*)&mine->rcvreq; mine->rcvreq = amount; rv = lo->methods->recv( lo, b + mine->rcvinprogress, sizeof(mine->rcvreq) - mine->rcvinprogress, flags, timeout); if (0 == rv) goto closed; if ((-1 == rv) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) break; mine->rcvinprogress += rv; /* accumulate the read */ if (mine->rcvinprogress < sizeof(mine->rcvreq)) break; /* loop */ mine->rcvstate = rcv_send_credit; mine->rcvinprogress = 0; case rcv_send_credit: b = (char*)&mine->rcvreq; rv = lo->methods->send( lo, b + mine->rcvinprogress, sizeof(mine->rcvreq) - mine->rcvinprogress, flags, timeout); if ((-1 == rv) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) break; mine->rcvinprogress += rv; /* accumulate the read */ if (mine->rcvinprogress < sizeof(mine->rcvreq)) break; /* loop */ mine->rcvstate = rcv_data; mine->rcvinprogress = 0; case rcv_data: b = (char*)buf; rv = lo->methods->recv( lo, b + mine->rcvinprogress, mine->rcvreq - mine->rcvinprogress, flags, timeout); if (0 == rv) goto closed; if ((-1 == rv) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) break; mine->rcvinprogress += rv; /* accumulate the read */ if (mine->rcvinprogress < amount) break; /* loop */ mine->rcvstate = rcv_get_debit; mine->rcvinprogress = 0; return mine->rcvreq; /* << -- that's it! */ default: break; } } while (-1 != rv); return rv;closed: mine->rcvinprogress = 0; mine->rcvstate = rcv_get_debit; return 0;} /* MyRecv */static PRInt32 PR_CALLBACK MySend( PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags, PRIntervalTime timeout){ char *b; PRInt32 rv; PRFileDesc *lo = fd->lower; PRFilePrivate *mine = (PRFilePrivate*)fd->secret; do { switch (mine->xmtstate) { case xmt_send_debit: b = (char*)&mine->xmtreq; mine->xmtreq = amount; rv = lo->methods->send( lo, b - mine->xmtinprogress, sizeof(mine->xmtreq) - mine->xmtinprogress, flags, timeout); if ((-1 == rv) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) break; mine->xmtinprogress += rv; if (mine->xmtinprogress < sizeof(mine->xmtreq)) break; mine->xmtstate = xmt_recv_credit; mine->xmtinprogress = 0; case xmt_recv_credit: b = (char*)&mine->xmtreq; rv = lo->methods->recv( lo, b + mine->xmtinprogress, sizeof(mine->xmtreq) - mine->xmtinprogress, flags, timeout); if ((-1 == rv) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) break; mine->xmtinprogress += rv; if (mine->xmtinprogress < sizeof(mine->xmtreq)) break; mine->xmtstate = xmt_data; mine->xmtinprogress = 0; case xmt_data: b = (char*)buf; rv = lo->methods->send( lo, b + mine->xmtinprogress, mine->xmtreq - mine->xmtinprogress, flags, timeout); if ((-1 == rv) && (PR_WOULD_BLOCK_ERROR == PR_GetError())) break; mine->xmtinprogress += rv; if (mine->xmtinprogress < amount) break; mine->xmtstate = xmt_send_debit; mine->xmtinprogress = 0; return mine->xmtreq; /* <<-- That's the one! */ default: break; } } while (-1 != rv); return rv;} /* MySend */static Verbosity ChangeVerbosity(Verbosity verbosity, PRIntn delta){ PRIntn verbage = (PRIntn)verbosity + delta; if (verbage < (PRIntn)silent) verbage = (PRIntn)silent; else if (verbage > (PRIntn)noisy) verbage = (PRIntn)noisy; return (Verbosity)verbage;} /* ChangeVerbosity */PRIntn main(PRIntn argc, char **argv){ PRStatus rv; PLOptStatus os; PRFileDesc *client, *service; PRNetAddr any_address; const char *server_name = NULL; const PRIOMethods *stubMethods; PRThread *client_thread, *server_thread; PRThreadScope thread_scope = PR_LOCAL_THREAD; PRSocketOptionData socket_noblock, socket_nodelay; PLOptState *opt = PL_CreateOptState(argc, argv, "dqGC:c:p:"); while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) { if (PL_OPT_BAD == os) continue; switch (opt->option) { case 0: server_name = opt->value; break; case 'd': /* debug mode */ if (verbosity < noisy) verbosity = ChangeVerbosity(verbosity, 1); break; case 'q': /* debug mode */ if (verbosity > silent) verbosity = ChangeVerbosity(verbosity, -1); break; case 'G': /* use global threads */ thread_scope = PR_GLOBAL_THREAD; break; case 'C': /* number of threads waiting */ major_iterations = atoi(opt->value); break; case 'c': /* number of client threads */ minor_iterations = atoi(opt->value); break; case 'p': /* default port */ default_port = atoi(opt->value); break; default: break; } } PL_DestroyOptState(opt); PR_STDIO_INIT(); logFile = PR_GetSpecialFD(PR_StandardError); identity = PR_GetUniqueIdentity("Dummy"); stubMethods = PR_GetDefaultIOMethods(); /* ** The protocol we're going to implement is one where in order to initiate ** a send, the sender must first solicit permission. Therefore, every ** send is really a send - receive - send sequence. */ myMethods = *stubMethods; /* first get the entire batch */ myMethods.accept = MyAccept; /* then override the ones we care about */ myMethods.recv = MyRecv; /* then override the ones we care about */ myMethods.send = MySend; /* then override the ones we care about */ myMethods.close = MyClose; /* then override the ones we care about */ myMethods.poll = MyPoll; /* then override the ones we care about */ if (NULL == server_name) rv = PR_InitializeNetAddr( PR_IpAddrLoopback, default_port, &server_address); else { rv = PR_StringToNetAddr(server_name, &server_address); PR_ASSERT(PR_SUCCESS == rv); rv = PR_InitializeNetAddr( PR_IpAddrNull, default_port, &server_address); } PR_ASSERT(PR_SUCCESS == rv); socket_noblock.value.non_blocking = PR_TRUE; socket_noblock.option = PR_SockOpt_Nonblocking; socket_nodelay.value.no_delay = PR_TRUE; socket_nodelay.option = PR_SockOpt_NoDelay; /* one type w/o layering */ while (major_iterations-- > 0) { if (verbosity > silent) PR_fprintf(logFile, "Beginning non-layered test\n"); client = PR_NewTCPSocket(); PR_ASSERT(NULL != client); service = PR_NewTCPSocket(); PR_ASSERT(NULL != service); rv = PR_SetSocketOption(client, &socket_noblock); PR_ASSERT(PR_SUCCESS == rv); rv = PR_SetSocketOption(service, &socket_noblock); PR_ASSERT(PR_SUCCESS == rv); rv = PR_SetSocketOption(client, &socket_nodelay); PR_ASSERT(PR_SUCCESS == rv); rv = PR_SetSocketOption(service, &socket_nodelay); PR_ASSERT(PR_SUCCESS == rv); rv = PR_InitializeNetAddr(PR_IpAddrAny, default_port, &any_address); PR_ASSERT(PR_SUCCESS == rv); rv = PR_Bind(service, &any_address); PR_ASSERT(PR_SUCCESS == rv); rv = PR_Listen(service, 10); PR_ASSERT(PR_SUCCESS == rv); server_thread = PR_CreateThread( PR_USER_THREAD, Server, service, PR_PRIORITY_HIGH, thread_scope, PR_JOINABLE_THREAD, 16 * 1024); PR_ASSERT(NULL != server_thread); client_thread = PR_CreateThread( PR_USER_THREAD, Client, client, PR_PRIORITY_NORMAL, thread_scope, PR_JOINABLE_THREAD, 16 * 1024); PR_ASSERT(NULL != client_thread); rv = PR_JoinThread(client_thread); PR_ASSERT(PR_SUCCESS == rv); rv = PR_JoinThread(server_thread); PR_ASSERT(PR_SUCCESS == rv); rv = PR_Close(client); PR_ASSERT(PR_SUCCESS == rv); rv = PR_Close(service); PR_ASSERT(PR_SUCCESS == rv); if (verbosity > silent) PR_fprintf(logFile, "Ending non-layered test\n"); /* with layering */ if (verbosity > silent) PR_fprintf(logFile, "Beginning layered test\n"); client = PR_NewTCPSocket(); PR_ASSERT(NULL != client); service = PR_NewTCPSocket(); PR_ASSERT(NULL != service); rv = PR_SetSocketOption(client, &socket_noblock); PR_ASSERT(PR_SUCCESS == rv); rv = PR_SetSocketOption(service, &socket_noblock); PR_ASSERT(PR_SUCCESS == rv); rv = PR_SetSocketOption(client, &socket_nodelay); PR_ASSERT(PR_SUCCESS == rv); rv = PR_SetSocketOption(service, &socket_nodelay); PR_ASSERT(PR_SUCCESS == rv); PushLayer(client); PushLayer(service); rv = PR_InitializeNetAddr(PR_IpAddrAny, default_port, &any_address); PR_ASSERT(PR_SUCCESS == rv); rv = PR_Bind(service, &any_address); PR_ASSERT(PR_SUCCESS == rv); rv = PR_Listen(service, 10); PR_ASSERT(PR_SUCCESS == rv); server_thread = PR_CreateThread( PR_USER_THREAD, Server, service, PR_PRIORITY_HIGH, thread_scope, PR_JOINABLE_THREAD, 16 * 1024); PR_ASSERT(NULL != server_thread); client_thread = PR_CreateThread( PR_USER_THREAD, Client, client, PR_PRIORITY_NORMAL, thread_scope, PR_JOINABLE_THREAD, 16 * 1024); PR_ASSERT(NULL != client_thread); rv = PR_JoinThread(client_thread); PR_ASSERT(PR_SUCCESS == rv); rv = PR_JoinThread(server_thread); PR_ASSERT(PR_SUCCESS == rv); rv = PR_Close(PopLayer(client)); PR_ASSERT(PR_SUCCESS == rv); rv = PR_Close(PopLayer(service)); PR_ASSERT(PR_SUCCESS == rv); if (verbosity > silent) PR_fprintf(logFile, "Ending layered test\n"); } return 0;} /* main *//* nblayer.c */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -