acceptreademu.c (8370B)
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 /* 7 * This test is the same as acceptread.c except that it uses the 8 * emulated acceptread method instead of the regular acceptread. 9 */ 10 11 #include <prio.h> 12 #include <prprf.h> 13 #include <prinit.h> 14 #include <prnetdb.h> 15 #include <prinrval.h> 16 #include <prthread.h> 17 #include <pprio.h> 18 19 #include <plerror.h> 20 21 #include <stdlib.h> 22 23 #ifdef DEBUG 24 # define PORT_INC_DO +100 25 #else 26 # define PORT_INC_DO 27 #endif 28 #ifdef IS_64 29 # define PORT_INC_3264 +200 30 #else 31 # define PORT_INC_3264 32 #endif 33 34 #define DEFAULT_PORT 12273 PORT_INC_DO PORT_INC_3264 35 #define GET "GET / HTTP/1.0\n\n" 36 static PRFileDesc *std_out, *err_out; 37 static PRIntervalTime write_dally, accept_timeout; 38 static PRDescIdentity emu_layer_ident; 39 static PRIOMethods emu_layer_methods; 40 41 /* the acceptread method in emu_layer_methods */ 42 static PRInt32 PR_CALLBACK emu_AcceptRead(PRFileDesc* sd, PRFileDesc** nd, 43 PRNetAddr** raddr, void* buf, 44 PRInt32 amount, 45 PRIntervalTime timeout) { 46 return PR_EmulateAcceptRead(sd, nd, raddr, buf, amount, timeout); 47 } 48 49 static PRStatus PrintAddress(const PRNetAddr* address) { 50 char buffer[100]; 51 PRStatus rv = PR_NetAddrToString(address, buffer, sizeof(buffer)); 52 if (PR_FAILURE == rv) { 53 PL_FPrintError(err_out, "PR_NetAddrToString"); 54 } else 55 PR_fprintf(std_out, "Accepted connection from (0x%p)%s:%d\n", address, 56 buffer, address->inet.port); 57 return rv; 58 } /* PrintAddress */ 59 60 static void ConnectingThread(void* arg) { 61 PRInt32 nbytes; 62 char buf[1024]; 63 PRFileDesc* sock; 64 PRNetAddr peer_addr, *addr; 65 66 addr = (PRNetAddr*)arg; 67 68 sock = PR_NewTCPSocket(); 69 if (sock == NULL) { 70 PL_FPrintError(err_out, "PR_NewTCPSocket (client) failed"); 71 PR_ProcessExit(1); 72 } 73 74 if (PR_Connect(sock, addr, PR_INTERVAL_NO_TIMEOUT) == PR_FAILURE) { 75 PL_FPrintError(err_out, "PR_Connect (client) failed"); 76 PR_ProcessExit(1); 77 } 78 if (PR_GetPeerName(sock, &peer_addr) == PR_FAILURE) { 79 PL_FPrintError(err_out, "PR_GetPeerName (client) failed"); 80 PR_ProcessExit(1); 81 } 82 83 /* 84 ** Then wait between the connection coming up and sending the expected 85 ** data. At some point in time, the server should fail due to a timeou 86 ** on the AcceptRead() operation, which according to the document is 87 ** only due to the read() portion. 88 */ 89 PR_Sleep(write_dally); 90 91 nbytes = PR_Send(sock, GET, sizeof(GET), 0, PR_INTERVAL_NO_TIMEOUT); 92 if (nbytes == -1) { 93 PL_FPrintError(err_out, "PR_Send (client) failed"); 94 } 95 96 nbytes = PR_Recv(sock, buf, sizeof(buf), 0, PR_INTERVAL_NO_TIMEOUT); 97 if (nbytes == -1) { 98 PL_FPrintError(err_out, "PR_Recv (client) failed"); 99 } else { 100 PR_fprintf(std_out, "PR_Recv (client) succeeded: %d bytes\n", nbytes); 101 buf[sizeof(buf) - 1] = '\0'; 102 PR_fprintf(std_out, "%s\n", buf); 103 } 104 105 if (PR_FAILURE == PR_Shutdown(sock, PR_SHUTDOWN_BOTH)) { 106 PL_FPrintError(err_out, "PR_Shutdown (client) failed"); 107 } 108 109 if (PR_FAILURE == PR_Close(sock)) { 110 PL_FPrintError(err_out, "PR_Close (client) failed"); 111 } 112 113 return; 114 } /* ConnectingThread */ 115 116 #define BUF_SIZE 117 117 static void AcceptingThread(void* arg) { 118 PRStatus rv; 119 PRInt32 bytes; 120 PRSize buf_size = BUF_SIZE; 121 PRUint8 buf[BUF_SIZE + (2 * sizeof(PRNetAddr)) + 32]; 122 PRNetAddr *accept_addr, *listen_addr = (PRNetAddr*)arg; 123 PRFileDesc *accept_sock, *listen_sock = PR_NewTCPSocket(); 124 PRFileDesc* layer; 125 PRSocketOptionData sock_opt; 126 127 if (NULL == listen_sock) { 128 PL_FPrintError(err_out, "PR_NewTCPSocket (server) failed"); 129 PR_ProcessExit(1); 130 } 131 layer = PR_CreateIOLayerStub(emu_layer_ident, &emu_layer_methods); 132 if (NULL == layer) { 133 PL_FPrintError(err_out, "PR_CreateIOLayerStub (server) failed"); 134 PR_ProcessExit(1); 135 } 136 if (PR_PushIOLayer(listen_sock, PR_TOP_IO_LAYER, layer) == PR_FAILURE) { 137 PL_FPrintError(err_out, "PR_PushIOLayer (server) failed"); 138 PR_ProcessExit(1); 139 } 140 sock_opt.option = PR_SockOpt_Reuseaddr; 141 sock_opt.value.reuse_addr = PR_TRUE; 142 rv = PR_SetSocketOption(listen_sock, &sock_opt); 143 if (PR_FAILURE == rv) { 144 PL_FPrintError(err_out, "PR_SetSocketOption (server) failed"); 145 PR_ProcessExit(1); 146 } 147 rv = PR_Bind(listen_sock, listen_addr); 148 if (PR_FAILURE == rv) { 149 PL_FPrintError(err_out, "PR_Bind (server) failed"); 150 PR_ProcessExit(1); 151 } 152 rv = PR_Listen(listen_sock, 10); 153 if (PR_FAILURE == rv) { 154 PL_FPrintError(err_out, "PR_Listen (server) failed"); 155 PR_ProcessExit(1); 156 } 157 bytes = PR_AcceptRead(listen_sock, &accept_sock, &accept_addr, buf, buf_size, 158 accept_timeout); 159 160 if (-1 == bytes) { 161 PL_FPrintError(err_out, "PR_AcceptRead (server) failed"); 162 } else { 163 PrintAddress(accept_addr); 164 PR_fprintf(std_out, "(Server) read [0x%p..0x%p) %s\n", buf, &buf[BUF_SIZE], 165 buf); 166 bytes = PR_Write(accept_sock, buf, bytes); 167 rv = PR_Shutdown(accept_sock, PR_SHUTDOWN_BOTH); 168 if (PR_FAILURE == rv) { 169 PL_FPrintError(err_out, "PR_Shutdown (server) failed"); 170 } 171 } 172 173 if (-1 != bytes) { 174 rv = PR_Close(accept_sock); 175 if (PR_FAILURE == rv) { 176 PL_FPrintError(err_out, "PR_Close (server) failed"); 177 } 178 } 179 180 rv = PR_Close(listen_sock); 181 if (PR_FAILURE == rv) { 182 PL_FPrintError(err_out, "PR_Close (server) failed"); 183 } 184 } /* AcceptingThread */ 185 186 int main(int argc, char** argv) { 187 PRHostEnt he; 188 PRStatus status; 189 PRIntn next_index; 190 PRUint16 port_number; 191 char netdb_buf[PR_NETDB_BUF_SIZE]; 192 PRNetAddr client_addr, server_addr; 193 PRThread *client_thread, *server_thread; 194 PRIntervalTime delta = PR_MillisecondsToInterval(500); 195 196 err_out = PR_STDERR; 197 std_out = PR_STDOUT; 198 accept_timeout = PR_SecondsToInterval(2); 199 emu_layer_ident = PR_GetUniqueIdentity("Emulated AcceptRead"); 200 emu_layer_methods = *PR_GetDefaultIOMethods(); 201 emu_layer_methods.acceptread = emu_AcceptRead; 202 203 if (argc != 2 && argc != 3) { 204 port_number = DEFAULT_PORT; 205 } else { 206 port_number = (PRUint16)atoi(argv[(argc == 2) ? 1 : 2]); 207 } 208 209 status = PR_InitializeNetAddr(PR_IpAddrAny, port_number, &server_addr); 210 if (PR_SUCCESS != status) { 211 PL_FPrintError(err_out, "PR_InitializeNetAddr failed"); 212 PR_ProcessExit(1); 213 } 214 if (argc < 3) { 215 status = PR_InitializeNetAddr(PR_IpAddrLoopback, port_number, &client_addr); 216 if (PR_SUCCESS != status) { 217 PL_FPrintError(err_out, "PR_InitializeNetAddr failed"); 218 PR_ProcessExit(1); 219 } 220 } else { 221 status = PR_GetHostByName(argv[1], netdb_buf, sizeof(netdb_buf), &he); 222 if (status == PR_FAILURE) { 223 PL_FPrintError(err_out, "PR_GetHostByName failed"); 224 PR_ProcessExit(1); 225 } 226 next_index = PR_EnumerateHostEnt(0, &he, port_number, &client_addr); 227 if (next_index == -1) { 228 PL_FPrintError(err_out, "PR_EnumerateHostEnt failed"); 229 PR_ProcessExit(1); 230 } 231 } 232 233 for (write_dally = 0; write_dally < accept_timeout + (2 * delta); 234 write_dally += delta) { 235 PR_fprintf(std_out, "Testing w/ write_dally = %d msec\n", 236 PR_IntervalToMilliseconds(write_dally)); 237 server_thread = PR_CreateThread(PR_USER_THREAD, AcceptingThread, 238 &server_addr, PR_PRIORITY_NORMAL, 239 PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0); 240 if (server_thread == NULL) { 241 PL_FPrintError(err_out, "PR_CreateThread (server) failed"); 242 PR_ProcessExit(1); 243 } 244 245 PR_Sleep(delta); /* let the server pot thicken */ 246 247 client_thread = PR_CreateThread(PR_USER_THREAD, ConnectingThread, 248 &client_addr, PR_PRIORITY_NORMAL, 249 PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0); 250 if (client_thread == NULL) { 251 PL_FPrintError(err_out, "PR_CreateThread (client) failed"); 252 PR_ProcessExit(1); 253 } 254 255 if (PR_JoinThread(client_thread) == PR_FAILURE) { 256 PL_FPrintError(err_out, "PR_JoinThread (client) failed"); 257 } 258 259 if (PR_JoinThread(server_thread) == PR_FAILURE) { 260 PL_FPrintError(err_out, "PR_JoinThread (server) failed"); 261 } 262 } 263 264 return 0; 265 }