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