1 /*
2 * test_socket.c
3 *
4 * Test Socket Type
5 *
6 * Copyright 2004-2005 Sun Microsystems, Inc. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are met:
10 *
11 * 1. Redistribution of source code must retain the above copyright notice,
12 * this list of conditions and the following disclaimer.
13 *
14 * 2. Redistribution in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * Neither the name of Sun Microsystems, Inc. or the names of contributors may
19 * be used to endorse or promote products derived from this software without
20 * specific prior written permission.
21 *
22 * This software is provided "AS IS," without a warranty of any kind. ALL
23 * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
24 * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
25 * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN")
26 * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
27 * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
28 * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST
29 * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL,
30 * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY
31 * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
32 * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
33 *
34 * You acknowledge that this software is not designed or intended for use in
35 * the design, construction, operation or maintenance of any nuclear facility.
36 */
37
38 #include "testutil.h"
39 #include "testutil_nss.h"
40 #include "pkix_pl_common.h"
41
42 #define LDAP_PORT 389
43
44 static void *plContext = NULL;
45
46 typedef enum {
47 SERVER_LISTENING,
48 SERVER_RECV1,
49 SERVER_POLL1,
50 SERVER_SEND2,
51 SERVER_POLL2,
52 SERVER_RECV3,
53 SERVER_POLL3,
54 SERVER_SEND4,
55 SERVER_POLL4,
56 SERVER_DONE,
57 SERVER_FAILED
58 } SERVER_STATE;
59
60 typedef enum {
61 CLIENT_WAITFORCONNECT,
62 CLIENT_SEND1,
63 CLIENT_POLL1,
64 CLIENT_RECV2,
65 CLIENT_POLL2,
66 CLIENT_SEND3,
67 CLIENT_POLL3,
68 CLIENT_RECV4,
69 CLIENT_POLL4,
70 CLIENT_DONE,
71 CLIENT_FAILED
72 } CLIENT_STATE;
73
74 SERVER_STATE serverState;
75 CLIENT_STATE clientState;
76 PKIX_PL_Socket *sSock = NULL;
77 PKIX_PL_Socket *cSock = NULL;
78 PKIX_PL_Socket *rendezvousSock = NULL;
79 PKIX_PL_Socket_Callback *sCallbackList;
80 PKIX_PL_Socket_Callback *cCallbackList;
81 PKIX_PL_Socket_Callback *rvCallbackList;
82 PRNetAddr serverNetAddr;
83 PRNetAddr clientNetAddr;
84 PRIntn backlog = 0;
85 PRIntervalTime timeout = 0;
86 char *sendBuf1 = "Hello, world!";
87 char *sendBuf2 = "Ack";
88 char *sendBuf3 = "What do you mean, \"Ack\"?";
89 char *sendBuf4 = "What do you mean, \"What do you mean, \'Ack\'?\"?";
90 char rcvBuf1[100];
91 char rcvBuf2[100];
92
93 static void
printUsage(char * testname)94 printUsage(char *testname)
95 {
96 char *fmt = "USAGE: %s [-arenas] server:port\n";
97 printf(fmt, testname);
98 }
99
100 /* Functional tests for Socket public functions */
101 static void
do_other_work(void)102 do_other_work(void)
103 { /* while waiting for nonblocking I/O to complete */
104 (void)PR_Sleep(2 * 60);
105 }
106
107 static PKIX_Boolean
server()108 server()
109 {
110 PKIX_Int32 bytesRead = 0;
111 PKIX_Int32 bytesWritten = 0;
112 PKIX_Boolean keepGoing = PKIX_FALSE;
113
114 PKIX_TEST_STD_VARS();
115
116 switch (serverState) {
117 case SERVER_LISTENING:
118 subTest("SERVER_LISTENING");
119 PKIX_TEST_EXPECT_NO_ERROR(sCallbackList->acceptCallback(sSock, &rendezvousSock, plContext));
120 if (rendezvousSock) {
121 PKIX_TEST_EXPECT_NO_ERROR(pkix_pl_Socket_GetCallbackList(rendezvousSock, &rvCallbackList, plContext));
122
123 serverState = SERVER_RECV1;
124 }
125 break;
126 case SERVER_RECV1:
127 subTest("SERVER_RECV1");
128 PKIX_TEST_EXPECT_NO_ERROR(rvCallbackList->recvCallback(rendezvousSock,
129 rcvBuf1,
130 sizeof(rcvBuf1),
131 &bytesRead,
132 plContext));
133
134 if (bytesRead > 0) {
135 /* confirm that rcvBuf1 = sendBuf1 */
136 if ((bytesRead != (PRInt32)PL_strlen(sendBuf1) + 1) ||
137 (strncmp(sendBuf1, rcvBuf1, bytesRead) != 0)) {
138 testError("Receive buffer mismatch\n");
139 }
140
141 serverState = SERVER_SEND2;
142 keepGoing = PKIX_TRUE;
143 } else {
144 serverState = SERVER_POLL1;
145 }
146 break;
147 case SERVER_POLL1:
148 subTest("SERVER_POLL1");
149 PKIX_TEST_EXPECT_NO_ERROR(rvCallbackList->pollCallback(rendezvousSock, NULL, &bytesRead, plContext));
150
151 if (bytesRead > 0) {
152 /* confirm that rcvBuf1 = sendBuf1 */
153 if ((bytesRead != (PRInt32)PL_strlen(sendBuf1) + 1) ||
154 (strncmp(sendBuf1, rcvBuf1, bytesRead) != 0)) {
155 testError("Receive buffer mismatch\n");
156 }
157
158 serverState = SERVER_SEND2;
159 keepGoing = PKIX_TRUE;
160 }
161 break;
162 case SERVER_SEND2:
163 subTest("SERVER_SEND2");
164 PKIX_TEST_EXPECT_NO_ERROR(rvCallbackList->sendCallback(rendezvousSock,
165 sendBuf2,
166 strlen(sendBuf2) +
167 1,
168 &bytesWritten,
169 plContext));
170 if (bytesWritten > 0) {
171 serverState = SERVER_RECV3;
172 } else {
173 serverState = SERVER_POLL2;
174 }
175 break;
176 case SERVER_POLL2:
177 subTest("SERVER_POLL2");
178 PKIX_TEST_EXPECT_NO_ERROR(rvCallbackList->pollCallback(rendezvousSock, &bytesWritten, NULL, plContext));
179 if (bytesWritten > 0) {
180 serverState = SERVER_RECV3;
181 }
182 break;
183 case SERVER_RECV3:
184 subTest("SERVER_RECV3");
185 PKIX_TEST_EXPECT_NO_ERROR(rvCallbackList->recvCallback(rendezvousSock,
186 rcvBuf1,
187 sizeof(rcvBuf1),
188 &bytesRead,
189 plContext));
190
191 if (bytesRead > 0) {
192 serverState = SERVER_SEND4;
193 keepGoing = PKIX_TRUE;
194 } else {
195 serverState = SERVER_POLL3;
196 }
197 break;
198 case SERVER_POLL3:
199 subTest("SERVER_POLL3");
200 PKIX_TEST_EXPECT_NO_ERROR(rvCallbackList->pollCallback(rendezvousSock, NULL, &bytesRead, plContext));
201 if (bytesRead > 0) {
202 serverState = SERVER_SEND4;
203 keepGoing = PKIX_TRUE;
204 }
205 break;
206 case SERVER_SEND4:
207 subTest("SERVER_SEND4");
208 PKIX_TEST_EXPECT_NO_ERROR(rvCallbackList->sendCallback(rendezvousSock,
209 sendBuf4,
210 strlen(sendBuf4) +
211 1,
212 &bytesWritten,
213 plContext));
214
215 if (bytesWritten > 0) {
216 PKIX_TEST_EXPECT_NO_ERROR(rvCallbackList->shutdownCallback(rendezvousSock, plContext));
217 PKIX_TEST_DECREF_BC(sSock);
218 PKIX_TEST_DECREF_BC(rendezvousSock);
219 serverState = SERVER_DONE;
220 } else {
221 serverState = SERVER_POLL4;
222 }
223 break;
224 case SERVER_POLL4:
225 subTest("SERVER_POLL4");
226 PKIX_TEST_EXPECT_NO_ERROR(rvCallbackList->pollCallback(rendezvousSock, &bytesWritten, NULL, plContext));
227 if (bytesWritten > 0) {
228 PKIX_TEST_EXPECT_NO_ERROR(rvCallbackList->shutdownCallback(rendezvousSock, plContext));
229 PKIX_TEST_DECREF_BC(sSock);
230 PKIX_TEST_DECREF_BC(rendezvousSock);
231 serverState = SERVER_DONE;
232 }
233 break;
234 case SERVER_DONE:
235 default:
236 subTest("SERVER_DONE");
237 break;
238 }
239
240 cleanup:
241
242 PKIX_TEST_RETURN();
243
244 return (keepGoing);
245 }
246
247 static PKIX_Boolean
client()248 client()
249 {
250 PKIX_Boolean keepGoing = PKIX_FALSE;
251 PKIX_Int32 bytesRead = 0;
252 PKIX_Int32 bytesWritten = 0;
253 PRErrorCode cStat = 0;
254
255 /* At 2 seconds each cycle, this should suffice! */
256 PKIX_UInt32 giveUpCount = 10;
257
258 PKIX_TEST_STD_VARS();
259
260 switch (clientState) {
261 case CLIENT_WAITFORCONNECT:
262 subTest("CLIENT_WAITFORCONNECT");
263 clientState = CLIENT_FAILED;
264 PKIX_TEST_EXPECT_NO_ERROR(cCallbackList->connectcontinueCallback(cSock, &cStat, plContext));
265 if (cStat == 0) {
266 clientState = CLIENT_SEND1;
267 keepGoing = PKIX_TRUE;
268 } else {
269 clientState = CLIENT_WAITFORCONNECT;
270 if (--giveUpCount == 0) {
271 testError("Client unable to connect");
272 }
273 }
274 break;
275 case CLIENT_SEND1:
276 subTest("CLIENT_SEND1");
277 clientState = CLIENT_FAILED;
278 PKIX_TEST_EXPECT_NO_ERROR(cCallbackList->sendCallback(cSock,
279 sendBuf1,
280 strlen(sendBuf1) +
281 1,
282 &bytesWritten,
283 plContext));
284 if (bytesWritten > 0) {
285 clientState = CLIENT_RECV2;
286 } else {
287 clientState = CLIENT_POLL1;
288 }
289 break;
290 case CLIENT_POLL1:
291 subTest("CLIENT_POLL1");
292 clientState = CLIENT_FAILED;
293 PKIX_TEST_EXPECT_NO_ERROR(cCallbackList->pollCallback(cSock, &bytesWritten, NULL, plContext));
294 if (bytesWritten > 0) {
295 clientState = CLIENT_RECV2;
296 } else {
297 clientState = CLIENT_POLL1;
298 }
299 break;
300 case CLIENT_RECV2:
301 subTest("CLIENT_RECV2");
302 clientState = CLIENT_FAILED;
303 PKIX_TEST_EXPECT_NO_ERROR(cCallbackList->recvCallback(cSock,
304 rcvBuf2,
305 sizeof(rcvBuf2),
306 &bytesRead,
307 plContext));
308
309 if (bytesRead > 0) {
310 /* confirm that rcvBuf2 = sendBuf2 */
311 if ((bytesRead != (PRInt32)PL_strlen(sendBuf2) + 1) ||
312 (strncmp(sendBuf2, rcvBuf2, bytesRead) != 0)) {
313 testError("Receive buffer mismatch\n");
314 }
315 clientState = CLIENT_SEND3;
316 keepGoing = PKIX_TRUE;
317 } else {
318 clientState = CLIENT_POLL2;
319 }
320 break;
321 case CLIENT_POLL2:
322 subTest("CLIENT_POLL2");
323 clientState = CLIENT_FAILED;
324 PKIX_TEST_EXPECT_NO_ERROR(cCallbackList->pollCallback(cSock, NULL, &bytesRead, plContext));
325 if (bytesRead > 0) {
326 /* confirm that rcvBuf2 = sendBuf2 */
327 if ((bytesRead != (PRInt32)PL_strlen(sendBuf2) + 1) ||
328 (strncmp(sendBuf2, rcvBuf2, bytesRead) != 0)) {
329 testError("Receive buffer mismatch\n");
330 }
331 clientState = CLIENT_SEND3;
332 } else {
333 clientState = CLIENT_POLL2;
334 }
335 break;
336 case CLIENT_SEND3:
337 subTest("CLIENT_SEND3");
338 clientState = CLIENT_FAILED;
339 PKIX_TEST_EXPECT_NO_ERROR(cCallbackList->sendCallback(cSock,
340 sendBuf3,
341 strlen(sendBuf3) +
342 1,
343 &bytesWritten,
344 plContext));
345
346 if (bytesWritten > 0) {
347 clientState = CLIENT_RECV4;
348 } else {
349 clientState = CLIENT_POLL3;
350 }
351 break;
352 case CLIENT_POLL3:
353 subTest("CLIENT_POLL3");
354 clientState = CLIENT_FAILED;
355 PKIX_TEST_EXPECT_NO_ERROR(cCallbackList->pollCallback(cSock, &bytesWritten, NULL, plContext));
356 if (bytesWritten > 0) {
357 clientState = CLIENT_RECV4;
358 } else {
359 clientState = CLIENT_POLL3;
360 }
361 break;
362 case CLIENT_RECV4:
363 subTest("CLIENT_RECV4");
364 clientState = CLIENT_FAILED;
365 PKIX_TEST_EXPECT_NO_ERROR(cCallbackList->recvCallback(cSock,
366 rcvBuf2,
367 sizeof(rcvBuf2),
368 &bytesRead,
369 plContext));
370
371 if (bytesRead > 0) {
372 PKIX_TEST_EXPECT_NO_ERROR(cCallbackList->shutdownCallback(cSock, plContext));
373 PKIX_TEST_DECREF_BC(cSock);
374 clientState = CLIENT_DONE;
375 } else {
376 clientState = CLIENT_POLL4;
377 }
378 break;
379 case CLIENT_POLL4:
380 subTest("CLIENT_POLL4");
381 clientState = CLIENT_FAILED;
382 PKIX_TEST_EXPECT_NO_ERROR(cCallbackList->pollCallback(cSock, NULL, &bytesRead, plContext));
383 if (bytesRead > 0) {
384 PKIX_TEST_EXPECT_NO_ERROR(cCallbackList->shutdownCallback(cSock, plContext));
385 PKIX_TEST_DECREF_BC(cSock);
386 clientState = CLIENT_DONE;
387 } else {
388 clientState = CLIENT_POLL4;
389 }
390 break;
391 case CLIENT_DONE:
392 default:
393 subTest("CLIENT_DONE");
394 break;
395 }
396
397 cleanup:
398
399 PKIX_TEST_RETURN();
400
401 return (keepGoing);
402 }
403
404 static void
dispatcher()405 dispatcher()
406 {
407 PKIX_Boolean keepGoing = PKIX_FALSE;
408
409 PKIX_TEST_STD_VARS();
410
411 do {
412 if (serverState < SERVER_DONE) {
413 do {
414 keepGoing = server();
415 } while (keepGoing == PKIX_TRUE);
416 }
417 if (clientState < CLIENT_DONE) {
418 do {
419 keepGoing = client();
420 } while (keepGoing == PKIX_TRUE);
421 }
422 do_other_work();
423
424 } while ((serverState < SERVER_DONE) || (clientState < CLIENT_DONE));
425
426 PKIX_TEST_RETURN();
427 }
428
429 int
test_socket(int argc,char * argv[])430 test_socket(int argc, char *argv[])
431 {
432
433 int j = 0;
434 PKIX_UInt32 actualMinorVersion;
435 char buf[PR_NETDB_BUF_SIZE];
436 char *serverName = NULL;
437 char *sepPtr = NULL;
438 PRHostEnt hostent;
439 PRUint16 portNum = 0;
440 PRStatus prstatus = PR_FAILURE;
441 PRErrorCode cStat = 0;
442 void *ipaddr = NULL;
443 PKIX_Error *bindError = NULL;
444 PRIntn hostenum;
445
446 PKIX_TEST_STD_VARS();
447
448 startTests("Socket");
449
450 PKIX_TEST_EXPECT_NO_ERROR(
451 PKIX_PL_NssContext_Create(0, PKIX_FALSE, NULL, &plContext));
452
453 if (argc != (j + 2)) {
454 printUsage(argv[0]);
455 pkixTestErrorMsg = "Missing command line argument.";
456 goto cleanup;
457 }
458
459 serverName = argv[j + 1];
460
461 subTest("Using pkix_pl_Socket_CreateByName");
462
463 PKIX_TEST_EXPECT_NO_ERROR(pkix_pl_Socket_CreateByName(PKIX_TRUE, timeout, serverName, &cStat, &sSock, plContext));
464
465 PKIX_TEST_EXPECT_NO_ERROR(pkix_pl_Socket_GetCallbackList(sSock, &sCallbackList, plContext));
466
467 PKIX_TEST_EXPECT_NO_ERROR(sCallbackList->listenCallback(sSock, backlog, plContext));
468
469 serverState = SERVER_LISTENING;
470
471 PKIX_TEST_EXPECT_NO_ERROR(pkix_pl_Socket_CreateByName(PKIX_FALSE, timeout, serverName, &cStat, &cSock, plContext));
472
473 PKIX_TEST_EXPECT_NO_ERROR(pkix_pl_Socket_GetCallbackList(cSock, &cCallbackList, plContext));
474
475 if ((timeout == 0) && (cStat == PR_IN_PROGRESS_ERROR)) {
476 clientState = CLIENT_WAITFORCONNECT;
477 } else {
478 clientState = CLIENT_SEND1;
479 }
480
481 dispatcher();
482
483 subTest("Using pkix_pl_Socket_Create");
484
485 sepPtr = strchr(serverName, ':');
486 /* First strip off the portnum, if present, from the end of the name */
487 if (sepPtr) {
488 *sepPtr++ = '\0';
489 portNum = (PRUint16)atoi(sepPtr);
490 } else {
491 portNum = (PRUint16)LDAP_PORT;
492 }
493 /*
494 * The hostname may be a fully-qualified name. Just
495 * use the leftmost component in our lookup.
496 */
497 sepPtr = strchr(serverName, '.');
498 if (sepPtr) {
499 *sepPtr++ = '\0';
500 }
501 prstatus = PR_GetHostByName(serverName, buf, sizeof(buf), &hostent);
502
503 if ((prstatus != PR_SUCCESS) || (hostent.h_length != 4)) {
504 printUsage(argv[0]);
505 pkixTestErrorMsg =
506 "PR_GetHostByName rejects command line argument.";
507 goto cleanup;
508 }
509
510 serverNetAddr.inet.family = PR_AF_INET;
511 serverNetAddr.inet.port = PR_htons(portNum);
512 serverNetAddr.inet.ip = PR_INADDR_ANY;
513
514 hostenum = PR_EnumerateHostEnt(0, &hostent, portNum, &clientNetAddr);
515 if (hostenum == -1) {
516 pkixTestErrorMsg =
517 "PR_EnumerateHostEnt failed.";
518 goto cleanup;
519 }
520
521 backlog = 5;
522
523 /* timeout = PR_INTERVAL_NO_TIMEOUT; */
524 /* timeout = 0; nonblocking */
525 timeout = 0;
526
527 bindError = pkix_pl_Socket_Create(PKIX_TRUE, timeout, &serverNetAddr, &cStat, &sSock, plContext);
528
529 /* If PR_Bind can't handle INADDR_ANY, try it with the real name */
530 if (bindError) {
531 PKIX_TEST_DECREF_BC(bindError);
532 serverNetAddr.inet.ip = PR_htonl(*(PRUint32 *)ipaddr);
533
534 PKIX_TEST_EXPECT_NO_ERROR(pkix_pl_Socket_Create(PKIX_TRUE,
535 timeout,
536 &serverNetAddr,
537 &cStat,
538 &sSock,
539 plContext));
540 }
541
542 PKIX_TEST_EXPECT_NO_ERROR(pkix_pl_Socket_GetCallbackList(sSock, &sCallbackList, plContext));
543
544 PKIX_TEST_EXPECT_NO_ERROR(sCallbackList->listenCallback(sSock, backlog, plContext));
545
546 serverState = SERVER_LISTENING;
547
548 PKIX_TEST_EXPECT_NO_ERROR(pkix_pl_Socket_Create(PKIX_FALSE, timeout, &clientNetAddr, &cStat, &cSock, plContext));
549
550 PKIX_TEST_EXPECT_NO_ERROR(pkix_pl_Socket_GetCallbackList(cSock, &cCallbackList, plContext));
551
552 if ((timeout == 0) && (cStat == PR_IN_PROGRESS_ERROR)) {
553 clientState = CLIENT_WAITFORCONNECT;
554 } else {
555 clientState = CLIENT_SEND1;
556 }
557
558 dispatcher();
559
560 cleanup:
561
562 PKIX_TEST_DECREF_AC(sSock);
563 PKIX_TEST_DECREF_AC(cSock);
564 PKIX_TEST_DECREF_AC(rendezvousSock);
565
566 PKIX_TEST_RETURN();
567
568 endTests("Socket");
569
570 return (0);
571 }
572