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