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