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 */
emu_AcceptRead(PRFileDesc * sd,PRFileDesc ** nd,PRNetAddr ** raddr,void * buf,PRInt32 amount,PRIntervalTime timeout)42 static PRInt32 PR_CALLBACK emu_AcceptRead(PRFileDesc *sd, PRFileDesc **nd,
43 PRNetAddr **raddr, void *buf, PRInt32 amount, PRIntervalTime timeout)
44 {
45 return PR_EmulateAcceptRead(sd, nd, raddr, buf, amount, timeout);
46 }
47
PrintAddress(const PRNetAddr * address)48 static PRStatus PrintAddress(const PRNetAddr* address)
49 {
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 }
55 else PR_fprintf(
56 std_out, "Accepted connection from (0x%p)%s:%d\n",
57 address, buffer, address->inet.port);
58 return rv;
59 } /* PrintAddress */
60
ConnectingThread(void * arg)61 static void ConnectingThread(void *arg)
62 {
63 PRInt32 nbytes;
64 char buf[1024];
65 PRFileDesc *sock;
66 PRNetAddr peer_addr, *addr;
67
68 addr = (PRNetAddr*)arg;
69
70 sock = PR_NewTCPSocket();
71 if (sock == NULL)
72 {
73 PL_FPrintError(err_out, "PR_NewTCPSocket (client) failed");
74 PR_ProcessExit(1);
75 }
76
77 if (PR_Connect(sock, addr, PR_INTERVAL_NO_TIMEOUT) == PR_FAILURE)
78 {
79 PL_FPrintError(err_out, "PR_Connect (client) failed");
80 PR_ProcessExit(1);
81 }
82 if (PR_GetPeerName(sock, &peer_addr) == PR_FAILURE)
83 {
84 PL_FPrintError(err_out, "PR_GetPeerName (client) failed");
85 PR_ProcessExit(1);
86 }
87
88 /*
89 ** Then wait between the connection coming up and sending the expected
90 ** data. At some point in time, the server should fail due to a timeou
91 ** on the AcceptRead() operation, which according to the document is
92 ** only due to the read() portion.
93 */
94 PR_Sleep(write_dally);
95
96 nbytes = PR_Send(sock, GET, sizeof(GET), 0, PR_INTERVAL_NO_TIMEOUT);
97 if (nbytes == -1) {
98 PL_FPrintError(err_out, "PR_Send (client) failed");
99 }
100
101 nbytes = PR_Recv(sock, buf, sizeof(buf), 0, PR_INTERVAL_NO_TIMEOUT);
102 if (nbytes == -1) {
103 PL_FPrintError(err_out, "PR_Recv (client) failed");
104 }
105 else
106 {
107 PR_fprintf(std_out, "PR_Recv (client) succeeded: %d bytes\n", nbytes);
108 buf[sizeof(buf) - 1] = '\0';
109 PR_fprintf(std_out, "%s\n", buf);
110 }
111
112 if (PR_FAILURE == PR_Shutdown(sock, PR_SHUTDOWN_BOTH)) {
113 PL_FPrintError(err_out, "PR_Shutdown (client) failed");
114 }
115
116 if (PR_FAILURE == PR_Close(sock)) {
117 PL_FPrintError(err_out, "PR_Close (client) failed");
118 }
119
120 return;
121 } /* ConnectingThread */
122
123 #define BUF_SIZE 117
AcceptingThread(void * arg)124 static void AcceptingThread(void *arg)
125 {
126 PRStatus rv;
127 PRInt32 bytes;
128 PRSize buf_size = BUF_SIZE;
129 PRUint8 buf[BUF_SIZE + (2 * sizeof(PRNetAddr)) + 32];
130 PRNetAddr *accept_addr, *listen_addr = (PRNetAddr*)arg;
131 PRFileDesc *accept_sock, *listen_sock = PR_NewTCPSocket();
132 PRFileDesc *layer;
133 PRSocketOptionData sock_opt;
134
135 if (NULL == listen_sock)
136 {
137 PL_FPrintError(err_out, "PR_NewTCPSocket (server) failed");
138 PR_ProcessExit(1);
139 }
140 layer = PR_CreateIOLayerStub(emu_layer_ident, &emu_layer_methods);
141 if (NULL == layer)
142 {
143 PL_FPrintError(err_out, "PR_CreateIOLayerStub (server) failed");
144 PR_ProcessExit(1);
145 }
146 if (PR_PushIOLayer(listen_sock, PR_TOP_IO_LAYER, layer) == PR_FAILURE)
147 {
148 PL_FPrintError(err_out, "PR_PushIOLayer (server) failed");
149 PR_ProcessExit(1);
150 }
151 sock_opt.option = PR_SockOpt_Reuseaddr;
152 sock_opt.value.reuse_addr = PR_TRUE;
153 rv = PR_SetSocketOption(listen_sock, &sock_opt);
154 if (PR_FAILURE == rv)
155 {
156 PL_FPrintError(err_out, "PR_SetSocketOption (server) failed");
157 PR_ProcessExit(1);
158 }
159 rv = PR_Bind(listen_sock, listen_addr);
160 if (PR_FAILURE == rv)
161 {
162 PL_FPrintError(err_out, "PR_Bind (server) failed");
163 PR_ProcessExit(1);
164 }
165 rv = PR_Listen(listen_sock, 10);
166 if (PR_FAILURE == rv)
167 {
168 PL_FPrintError(err_out, "PR_Listen (server) failed");
169 PR_ProcessExit(1);
170 }
171 bytes = PR_AcceptRead(
172 listen_sock, &accept_sock, &accept_addr, buf, buf_size, accept_timeout);
173
174 if (-1 == bytes) {
175 PL_FPrintError(err_out, "PR_AcceptRead (server) failed");
176 }
177 else
178 {
179 PrintAddress(accept_addr);
180 PR_fprintf(
181 std_out, "(Server) read [0x%p..0x%p) %s\n",
182 buf, &buf[BUF_SIZE], buf);
183 bytes = PR_Write(accept_sock, buf, bytes);
184 rv = PR_Shutdown(accept_sock, PR_SHUTDOWN_BOTH);
185 if (PR_FAILURE == rv) {
186 PL_FPrintError(err_out, "PR_Shutdown (server) failed");
187 }
188 }
189
190 if (-1 != bytes)
191 {
192 rv = PR_Close(accept_sock);
193 if (PR_FAILURE == rv) {
194 PL_FPrintError(err_out, "PR_Close (server) failed");
195 }
196 }
197
198 rv = PR_Close(listen_sock);
199 if (PR_FAILURE == rv) {
200 PL_FPrintError(err_out, "PR_Close (server) failed");
201 }
202 } /* AcceptingThread */
203
main(int argc,char ** argv)204 int main(int argc, char **argv)
205 {
206 PRHostEnt he;
207 PRStatus status;
208 PRIntn next_index;
209 PRUint16 port_number;
210 char netdb_buf[PR_NETDB_BUF_SIZE];
211 PRNetAddr client_addr, server_addr;
212 PRThread *client_thread, *server_thread;
213 PRIntervalTime delta = PR_MillisecondsToInterval(500);
214
215 err_out = PR_STDERR;
216 std_out = PR_STDOUT;
217 accept_timeout = PR_SecondsToInterval(2);
218 emu_layer_ident = PR_GetUniqueIdentity("Emulated AcceptRead");
219 emu_layer_methods = *PR_GetDefaultIOMethods();
220 emu_layer_methods.acceptread = emu_AcceptRead;
221
222 if (argc != 2 && argc != 3) {
223 port_number = DEFAULT_PORT;
224 }
225 else {
226 port_number = (PRUint16)atoi(argv[(argc == 2) ? 1 : 2]);
227 }
228
229 status = PR_InitializeNetAddr(PR_IpAddrAny, port_number, &server_addr);
230 if (PR_SUCCESS != status)
231 {
232 PL_FPrintError(err_out, "PR_InitializeNetAddr failed");
233 PR_ProcessExit(1);
234 }
235 if (argc < 3)
236 {
237 status = PR_InitializeNetAddr(
238 PR_IpAddrLoopback, port_number, &client_addr);
239 if (PR_SUCCESS != status)
240 {
241 PL_FPrintError(err_out, "PR_InitializeNetAddr failed");
242 PR_ProcessExit(1);
243 }
244 }
245 else
246 {
247 status = PR_GetHostByName(
248 argv[1], netdb_buf, sizeof(netdb_buf), &he);
249 if (status == PR_FAILURE)
250 {
251 PL_FPrintError(err_out, "PR_GetHostByName failed");
252 PR_ProcessExit(1);
253 }
254 next_index = PR_EnumerateHostEnt(0, &he, port_number, &client_addr);
255 if (next_index == -1)
256 {
257 PL_FPrintError(err_out, "PR_EnumerateHostEnt failed");
258 PR_ProcessExit(1);
259 }
260 }
261
262 for (
263 write_dally = 0;
264 write_dally < accept_timeout + (2 * delta);
265 write_dally += delta)
266 {
267 PR_fprintf(
268 std_out, "Testing w/ write_dally = %d msec\n",
269 PR_IntervalToMilliseconds(write_dally));
270 server_thread = PR_CreateThread(
271 PR_USER_THREAD, AcceptingThread, &server_addr,
272 PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0);
273 if (server_thread == NULL)
274 {
275 PL_FPrintError(err_out, "PR_CreateThread (server) failed");
276 PR_ProcessExit(1);
277 }
278
279 PR_Sleep(delta); /* let the server pot thicken */
280
281 client_thread = PR_CreateThread(
282 PR_USER_THREAD, ConnectingThread, &client_addr,
283 PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0);
284 if (client_thread == NULL)
285 {
286 PL_FPrintError(err_out, "PR_CreateThread (client) failed");
287 PR_ProcessExit(1);
288 }
289
290 if (PR_JoinThread(client_thread) == PR_FAILURE) {
291 PL_FPrintError(err_out, "PR_JoinThread (client) failed");
292 }
293
294 if (PR_JoinThread(server_thread) == PR_FAILURE) {
295 PL_FPrintError(err_out, "PR_JoinThread (server) failed");
296 }
297 }
298
299 return 0;
300 }
301