|
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 * A test case for the PR_MSG_PEEK flag of PR_Recv(). |
|
8 * |
|
9 * Test both blocking and non-blocking sockets. |
|
10 */ |
|
11 |
|
12 #include "nspr.h" |
|
13 |
|
14 #include <stdio.h> |
|
15 #include <stdlib.h> |
|
16 #include <string.h> |
|
17 |
|
18 #define BUFFER_SIZE 1024 |
|
19 |
|
20 static int iterations = 10; |
|
21 |
|
22 /* |
|
23 * In iteration i, recv_amount[i] is the number of bytes we |
|
24 * wish to receive, and send_amount[i] is the number of bytes |
|
25 * we actually send. Therefore, the number of elements in the |
|
26 * recv_amount or send_amount array should equal to 'iterations'. |
|
27 * For this test to pass we need to ensure that |
|
28 * recv_amount[i] <= BUFFER_SIZE, |
|
29 * send_amount[i] <= BUFFER_SIZE, |
|
30 * send_amount[i] <= recv_amount[i]. |
|
31 */ |
|
32 static PRInt32 recv_amount[10] = { |
|
33 16, 128, 256, 1024, 512, 512, 128, 256, 32, 32}; |
|
34 static PRInt32 send_amount[10] = { |
|
35 16, 64, 128, 1024, 512, 256, 128, 64, 16, 32}; |
|
36 |
|
37 /* Blocking I/O */ |
|
38 static void ServerB(void *arg) |
|
39 { |
|
40 PRFileDesc *listenSock = (PRFileDesc *) arg; |
|
41 PRFileDesc *sock; |
|
42 char buf[BUFFER_SIZE]; |
|
43 PRInt32 nbytes; |
|
44 int i; |
|
45 int j; |
|
46 |
|
47 sock = PR_Accept(listenSock, NULL, PR_INTERVAL_NO_TIMEOUT); |
|
48 if (NULL == sock) { |
|
49 fprintf(stderr, "PR_Accept failed\n"); |
|
50 exit(1); |
|
51 } |
|
52 |
|
53 for (i = 0; i < iterations; i++) { |
|
54 memset(buf, 0, sizeof(buf)); |
|
55 nbytes = PR_Recv(sock, buf, recv_amount[i], |
|
56 PR_MSG_PEEK, PR_INTERVAL_NO_TIMEOUT); |
|
57 if (-1 == nbytes) { |
|
58 fprintf(stderr, "PR_Recv failed\n"); |
|
59 exit(1); |
|
60 } |
|
61 if (send_amount[i] != nbytes) { |
|
62 fprintf(stderr, "PR_Recv returned %d, absurd!\n", nbytes); |
|
63 exit(1); |
|
64 } |
|
65 for (j = 0; j < nbytes; j++) { |
|
66 if (buf[j] != 2*i) { |
|
67 fprintf(stderr, "byte %d should be %d but is %d\n", |
|
68 j, 2*i, buf[j]); |
|
69 exit(1); |
|
70 } |
|
71 } |
|
72 fprintf(stderr, "server: peeked expected data\n"); |
|
73 |
|
74 memset(buf, 0, sizeof(buf)); |
|
75 nbytes = PR_Recv(sock, buf, recv_amount[i], |
|
76 PR_MSG_PEEK, PR_INTERVAL_NO_TIMEOUT); |
|
77 if (-1 == nbytes) { |
|
78 fprintf(stderr, "PR_Recv failed\n"); |
|
79 exit(1); |
|
80 } |
|
81 if (send_amount[i] != nbytes) { |
|
82 fprintf(stderr, "PR_Recv returned %d, absurd!\n", nbytes); |
|
83 exit(1); |
|
84 } |
|
85 for (j = 0; j < nbytes; j++) { |
|
86 if (buf[j] != 2*i) { |
|
87 fprintf(stderr, "byte %d should be %d but is %d\n", |
|
88 j, 2*i, buf[j]); |
|
89 exit(1); |
|
90 } |
|
91 } |
|
92 fprintf(stderr, "server: peeked expected data\n"); |
|
93 |
|
94 memset(buf, 0, sizeof(buf)); |
|
95 nbytes = PR_Recv(sock, buf, recv_amount[i], |
|
96 0, PR_INTERVAL_NO_TIMEOUT); |
|
97 if (-1 == nbytes) { |
|
98 fprintf(stderr, "PR_Recv failed\n"); |
|
99 exit(1); |
|
100 } |
|
101 if (send_amount[i] != nbytes) { |
|
102 fprintf(stderr, "PR_Recv returned %d, absurd!\n", nbytes); |
|
103 exit(1); |
|
104 } |
|
105 for (j = 0; j < nbytes; j++) { |
|
106 if (buf[j] != 2*i) { |
|
107 fprintf(stderr, "byte %d should be %d but is %d\n", |
|
108 j, 2*i, buf[j]); |
|
109 exit(1); |
|
110 } |
|
111 } |
|
112 fprintf(stderr, "server: received expected data\n"); |
|
113 |
|
114 PR_Sleep(PR_SecondsToInterval(1)); |
|
115 memset(buf, 2*i+1, send_amount[i]); |
|
116 nbytes = PR_Send(sock, buf, send_amount[i], |
|
117 0, PR_INTERVAL_NO_TIMEOUT); |
|
118 if (-1 == nbytes) { |
|
119 fprintf(stderr, "PR_Send failed\n"); |
|
120 exit(1); |
|
121 } |
|
122 if (send_amount[i] != nbytes) { |
|
123 fprintf(stderr, "PR_Send returned %d, absurd!\n", nbytes); |
|
124 exit(1); |
|
125 } |
|
126 } |
|
127 if (PR_Close(sock) == PR_FAILURE) { |
|
128 fprintf(stderr, "PR_Close failed\n"); |
|
129 exit(1); |
|
130 } |
|
131 } |
|
132 |
|
133 /* Non-blocking I/O */ |
|
134 static void ClientNB(void *arg) |
|
135 { |
|
136 PRFileDesc *sock; |
|
137 PRSocketOptionData opt; |
|
138 PRUint16 port = (PRUint16) arg; |
|
139 PRNetAddr addr; |
|
140 char buf[BUFFER_SIZE]; |
|
141 PRPollDesc pd; |
|
142 PRInt32 npds; |
|
143 PRInt32 nbytes; |
|
144 int i; |
|
145 int j; |
|
146 |
|
147 sock = PR_OpenTCPSocket(PR_AF_INET6); |
|
148 if (NULL == sock) { |
|
149 fprintf(stderr, "PR_OpenTCPSocket failed\n"); |
|
150 exit(1); |
|
151 } |
|
152 opt.option = PR_SockOpt_Nonblocking; |
|
153 opt.value.non_blocking = PR_TRUE; |
|
154 if (PR_SetSocketOption(sock, &opt) == PR_FAILURE) { |
|
155 fprintf(stderr, "PR_SetSocketOption failed\n"); |
|
156 exit(1); |
|
157 } |
|
158 memset(&addr, 0, sizeof(addr)); |
|
159 if (PR_SetNetAddr(PR_IpAddrLoopback, PR_AF_INET6, port, &addr) |
|
160 == PR_FAILURE) { |
|
161 fprintf(stderr, "PR_SetNetAddr failed\n"); |
|
162 exit(1); |
|
163 } |
|
164 if (PR_Connect(sock, &addr, PR_INTERVAL_NO_TIMEOUT) == PR_FAILURE) { |
|
165 if (PR_GetError() != PR_IN_PROGRESS_ERROR) { |
|
166 fprintf(stderr, "PR_Connect failed\n"); |
|
167 exit(1); |
|
168 } |
|
169 pd.fd = sock; |
|
170 pd.in_flags = PR_POLL_WRITE | PR_POLL_EXCEPT; |
|
171 npds = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT); |
|
172 if (-1 == npds) { |
|
173 fprintf(stderr, "PR_Poll failed\n"); |
|
174 exit(1); |
|
175 } |
|
176 if (1 != npds) { |
|
177 fprintf(stderr, "PR_Poll returned %d, absurd!\n", npds); |
|
178 exit(1); |
|
179 } |
|
180 if (PR_GetConnectStatus(&pd) == PR_FAILURE) { |
|
181 fprintf(stderr, "PR_GetConnectStatus failed\n"); |
|
182 exit(1); |
|
183 } |
|
184 } |
|
185 |
|
186 for (i = 0; i < iterations; i++) { |
|
187 PR_Sleep(PR_SecondsToInterval(1)); |
|
188 memset(buf, 2*i, send_amount[i]); |
|
189 while ((nbytes = PR_Send(sock, buf, send_amount[i], |
|
190 0, PR_INTERVAL_NO_TIMEOUT)) == -1) { |
|
191 if (PR_GetError() != PR_WOULD_BLOCK_ERROR) { |
|
192 fprintf(stderr, "PR_Send failed\n"); |
|
193 exit(1); |
|
194 } |
|
195 pd.fd = sock; |
|
196 pd.in_flags = PR_POLL_WRITE; |
|
197 npds = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT); |
|
198 if (-1 == npds) { |
|
199 fprintf(stderr, "PR_Poll failed\n"); |
|
200 exit(1); |
|
201 } |
|
202 if (1 != npds) { |
|
203 fprintf(stderr, "PR_Poll returned %d, absurd!\n", npds); |
|
204 exit(1); |
|
205 } |
|
206 } |
|
207 if (send_amount[i] != nbytes) { |
|
208 fprintf(stderr, "PR_Send returned %d, absurd!\n", nbytes); |
|
209 exit(1); |
|
210 } |
|
211 |
|
212 memset(buf, 0, sizeof(buf)); |
|
213 while ((nbytes = PR_Recv(sock, buf, recv_amount[i], |
|
214 PR_MSG_PEEK, PR_INTERVAL_NO_TIMEOUT)) == -1) { |
|
215 if (PR_GetError() != PR_WOULD_BLOCK_ERROR) { |
|
216 fprintf(stderr, "PR_Recv failed\n"); |
|
217 exit(1); |
|
218 } |
|
219 pd.fd = sock; |
|
220 pd.in_flags = PR_POLL_READ; |
|
221 npds = PR_Poll(&pd, 1, PR_INTERVAL_NO_TIMEOUT); |
|
222 if (-1 == npds) { |
|
223 fprintf(stderr, "PR_Poll failed\n"); |
|
224 exit(1); |
|
225 } |
|
226 if (1 != npds) { |
|
227 fprintf(stderr, "PR_Poll returned %d, absurd!\n", npds); |
|
228 exit(1); |
|
229 } |
|
230 } |
|
231 if (send_amount[i] != nbytes) { |
|
232 fprintf(stderr, "PR_Recv returned %d, absurd!\n", nbytes); |
|
233 exit(1); |
|
234 } |
|
235 for (j = 0; j < nbytes; j++) { |
|
236 if (buf[j] != 2*i+1) { |
|
237 fprintf(stderr, "byte %d should be %d but is %d\n", |
|
238 j, 2*i+1, buf[j]); |
|
239 exit(1); |
|
240 } |
|
241 } |
|
242 fprintf(stderr, "client: peeked expected data\n"); |
|
243 |
|
244 memset(buf, 0, sizeof(buf)); |
|
245 nbytes = PR_Recv(sock, buf, recv_amount[i], |
|
246 PR_MSG_PEEK, PR_INTERVAL_NO_TIMEOUT); |
|
247 if (-1 == nbytes) { |
|
248 fprintf(stderr, "PR_Recv failed\n"); |
|
249 exit(1); |
|
250 } |
|
251 if (send_amount[i] != nbytes) { |
|
252 fprintf(stderr, "PR_Recv returned %d, absurd!\n", nbytes); |
|
253 exit(1); |
|
254 } |
|
255 for (j = 0; j < nbytes; j++) { |
|
256 if (buf[j] != 2*i+1) { |
|
257 fprintf(stderr, "byte %d should be %d but is %d\n", |
|
258 j, 2*i+1, buf[j]); |
|
259 exit(1); |
|
260 } |
|
261 } |
|
262 fprintf(stderr, "client: peeked expected data\n"); |
|
263 |
|
264 memset(buf, 0, sizeof(buf)); |
|
265 nbytes = PR_Recv(sock, buf, recv_amount[i], |
|
266 0, PR_INTERVAL_NO_TIMEOUT); |
|
267 if (-1 == nbytes) { |
|
268 fprintf(stderr, "PR_Recv failed\n"); |
|
269 exit(1); |
|
270 } |
|
271 if (send_amount[i] != nbytes) { |
|
272 fprintf(stderr, "PR_Recv returned %d, absurd!\n", nbytes); |
|
273 exit(1); |
|
274 } |
|
275 for (j = 0; j < nbytes; j++) { |
|
276 if (buf[j] != 2*i+1) { |
|
277 fprintf(stderr, "byte %d should be %d but is %d\n", |
|
278 j, 2*i+1, buf[j]); |
|
279 exit(1); |
|
280 } |
|
281 } |
|
282 fprintf(stderr, "client: received expected data\n"); |
|
283 } |
|
284 if (PR_Close(sock) == PR_FAILURE) { |
|
285 fprintf(stderr, "PR_Close failed\n"); |
|
286 exit(1); |
|
287 } |
|
288 } |
|
289 |
|
290 static void |
|
291 RunTest(PRThreadScope scope, PRFileDesc *listenSock, PRUint16 port) |
|
292 { |
|
293 PRThread *server, *client; |
|
294 |
|
295 server = PR_CreateThread(PR_USER_THREAD, ServerB, listenSock, |
|
296 PR_PRIORITY_NORMAL, scope, PR_JOINABLE_THREAD, 0); |
|
297 if (NULL == server) { |
|
298 fprintf(stderr, "PR_CreateThread failed\n"); |
|
299 exit(1); |
|
300 } |
|
301 client = PR_CreateThread( |
|
302 PR_USER_THREAD, ClientNB, (void *) port, |
|
303 PR_PRIORITY_NORMAL, scope, PR_JOINABLE_THREAD, 0); |
|
304 if (NULL == client) { |
|
305 fprintf(stderr, "PR_CreateThread failed\n"); |
|
306 exit(1); |
|
307 } |
|
308 |
|
309 if (PR_JoinThread(server) == PR_FAILURE) { |
|
310 fprintf(stderr, "PR_JoinThread failed\n"); |
|
311 exit(1); |
|
312 } |
|
313 if (PR_JoinThread(client) == PR_FAILURE) { |
|
314 fprintf(stderr, "PR_JoinThread failed\n"); |
|
315 exit(1); |
|
316 } |
|
317 } |
|
318 |
|
319 int main(int argc, char **argv) |
|
320 { |
|
321 PRFileDesc *listenSock; |
|
322 PRNetAddr addr; |
|
323 PRUint16 port; |
|
324 |
|
325 listenSock = PR_OpenTCPSocket(PR_AF_INET6); |
|
326 if (NULL == listenSock) { |
|
327 fprintf(stderr, "PR_OpenTCPSocket failed\n"); |
|
328 exit(1); |
|
329 } |
|
330 memset(&addr, 0, sizeof(addr)); |
|
331 if (PR_SetNetAddr(PR_IpAddrAny, PR_AF_INET6, 0, &addr) == PR_FAILURE) { |
|
332 fprintf(stderr, "PR_SetNetAddr failed\n"); |
|
333 exit(1); |
|
334 } |
|
335 if (PR_Bind(listenSock, &addr) == PR_FAILURE) { |
|
336 fprintf(stderr, "PR_Bind failed\n"); |
|
337 exit(1); |
|
338 } |
|
339 if (PR_GetSockName(listenSock, &addr) == PR_FAILURE) { |
|
340 fprintf(stderr, "PR_GetSockName failed\n"); |
|
341 exit(1); |
|
342 } |
|
343 port = PR_ntohs(addr.ipv6.port); |
|
344 if (PR_Listen(listenSock, 5) == PR_FAILURE) { |
|
345 fprintf(stderr, "PR_Listen failed\n"); |
|
346 exit(1); |
|
347 } |
|
348 |
|
349 fprintf(stderr, "Running the test with local threads\n"); |
|
350 RunTest(PR_LOCAL_THREAD, listenSock, port); |
|
351 fprintf(stderr, "Running the test with global threads\n"); |
|
352 RunTest(PR_GLOBAL_THREAD, listenSock, port); |
|
353 |
|
354 if (PR_Close(listenSock) == PR_FAILURE) { |
|
355 fprintf(stderr, "PR_Close failed\n"); |
|
356 exit(1); |
|
357 } |
|
358 printf("PASS\n"); |
|
359 return 0; |
|
360 } |