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/. */
6 /***********************************************************************
7 ** 1997 - Netscape Communications Corporation
9 ** Name: prselect_err.c
11 ** Description: tests PR_Select with sockets Error condition functions.
13 ** Modification History:
14 ** 14-May-97 AGarcia- Converted the test to accomodate the debug_mode flag.
15 ** The debug mode will print all of the printfs associated with this test.
16 ** The regress mode will be the default mode. Since the regress tool limits
17 ** the output to a one line status:PASS or FAIL,all of the printf statements
18 ** have been handled with an if (debug_mode) statement.
19 ***********************************************************************/
21 /***********************************************************************
23 ***********************************************************************/
24 /* Used to get the command line option */
40 /***********************************************************************
41 ** PRIVATE FUNCTION: Test_Result
42 ** DESCRIPTION: Used in conjunction with the regress tool, prints out the
43 ** status of the test case.
52 ** ALGORITHM: Determine what the status is and print accordingly.
54 ***********************************************************************/
57 static Test_Result (int result
)
68 clientThreadFunc(void *arg
)
70 PRUint16 port
= (PRUint16
) arg
;
76 addr
.inet
.family
= AF_INET
;
77 addr
.inet
.port
= PR_htons(port
);
78 addr
.inet
.ip
= PR_htonl(INADDR_LOOPBACK
);
79 PR_snprintf(buf
, sizeof(buf
), "%hu", port
);
81 for (i
= 0; i
< 5; i
++) {
82 sock
= PR_NewTCPSocket();
83 PR_Connect(sock
, &addr
, PR_INTERVAL_NO_TIMEOUT
);
84 PR_Write(sock
, buf
, sizeof(buf
));
89 int main(int argc
, char **argv
)
91 PRFileDesc
*listenSock1
, *listenSock2
;
93 PRFileDesc
*fds0
[10], *fds1
[10], **fds
, **other_fds
;
95 PRUint16 listenPort1
, listenPort2
;
99 PRThread
*clientThread
;
103 /* The command line argument: -d is used to determine if the test is being run
104 in debug mode. The regress tool requires only one line output:PASS or FAIL.
105 All of the printfs associated with this test has been handled with a if (debug_mode)
110 PLOptState
*opt
= PL_CreateOptState(argc
, argv
, "d:");
111 while (PL_OPT_EOL
!= (os
= PL_GetNextOpt(opt
)))
113 if (PL_OPT_BAD
== os
) {
118 case 'd': /* debug mode */
125 PL_DestroyOptState(opt
);
129 PR_Init(PR_USER_THREAD
, PR_PRIORITY_NORMAL
, 0);
133 printf("This program tests PR_Select with sockets. Timeout, error\n");
134 printf("reporting, and normal operation are tested.\n\n");
137 /* Create two listening sockets */
138 if ((listenSock1
= PR_NewTCPSocket()) == NULL
) {
139 fprintf(stderr
, "Can't create a new TCP socket\n");
145 addr
.inet
.family
= AF_INET
;
146 addr
.inet
.ip
= PR_htonl(INADDR_ANY
);
147 addr
.inet
.port
= PR_htons(0);
148 if (PR_Bind(listenSock1
, &addr
) == PR_FAILURE
) {
149 fprintf(stderr
, "Can't bind socket\n");
155 if (PR_GetSockName(listenSock1
, &addr
) == PR_FAILURE
) {
156 fprintf(stderr
, "PR_GetSockName failed\n");
162 listenPort1
= PR_ntohs(addr
.inet
.port
);
163 if (PR_Listen(listenSock1
, 5) == PR_FAILURE
) {
164 fprintf(stderr
, "Can't listen on a socket\n");
171 if ((listenSock2
= PR_NewTCPSocket()) == NULL
) {
172 fprintf(stderr
, "Can't create a new TCP socket\n");
178 addr
.inet
.family
= AF_INET
;
179 addr
.inet
.ip
= PR_htonl(INADDR_ANY
);
180 addr
.inet
.port
= PR_htons(0);
181 if (PR_Bind(listenSock2
, &addr
) == PR_FAILURE
) {
182 fprintf(stderr
, "Can't bind socket\n");
188 if (PR_GetSockName(listenSock2
, &addr
) == PR_FAILURE
) {
189 fprintf(stderr
, "PR_GetSockName failed\n");
195 listenPort2
= PR_ntohs(addr
.inet
.port
);
196 if (PR_Listen(listenSock2
, 5) == PR_FAILURE
) {
197 fprintf(stderr
, "Can't listen on a socket\n");
203 PR_snprintf(buf
, sizeof(buf
),
204 "The server thread is listening on ports %hu and %hu\n\n",
205 listenPort1
, listenPort2
);
208 /* Set up the fd set */
209 PR_FD_ZERO(&readFdSet
);
210 PR_FD_SET(listenSock1
, &readFdSet
);
211 PR_FD_SET(listenSock2
, &readFdSet
);
213 /* Testing timeout */
215 printf("PR_Select should time out in 5 seconds\n");
217 retVal
= PR_Select(0 /* unused */, &readFdSet
, NULL
, NULL
,
218 PR_SecondsToInterval(5));
220 PR_snprintf(buf
, sizeof(buf
),
221 "PR_Select should time out and return 0, but it returns %ld\n",
223 fprintf(stderr
, "%s", buf
);
225 fprintf(stderr
, "Error %d, oserror %d\n", PR_GetError(),
234 printf("PR_Select timed out. Test passed.\n\n");
241 printf("PR_Select should detect a bad file descriptor\n");
242 if ((badFD
= PR_NewTCPSocket()) == NULL
) {
243 fprintf(stderr
, "Can't create a TCP socket\n");
247 PR_FD_SET(listenSock1
, &readFdSet
);
248 PR_FD_SET(listenSock2
, &readFdSet
);
249 PR_FD_SET(badFD
, &readFdSet
);
250 PR_Close(badFD
); /* make the fd bad */
251 retVal
= PR_Select(0 /* unused */, &readFdSet
, NULL
, NULL
,
252 PR_INTERVAL_NO_TIMEOUT
);
253 if (retVal
!= -1 || PR_GetError() != PR_BAD_DESCRIPTOR_ERROR
) {
254 fprintf(stderr
, "Failed to detect the bad fd: "
255 "PR_Select returns %d\n", retVal
);
257 fprintf(stderr
, "Error %d, oserror %d\n", PR_GetError(),
262 printf("PR_Select detected a bad fd. Test passed.\n\n");
263 PR_FD_CLR(badFD
, &readFdSet
);
265 clientThread
= PR_CreateThread(PR_USER_THREAD
,
266 clientThreadFunc
, (void *) listenPort1
,
267 PR_PRIORITY_NORMAL
, PR_LOCAL_THREAD
,
268 PR_UNJOINABLE_THREAD
, 0);
269 if (clientThread
== NULL
) {
270 fprintf(stderr
, "can't create thread\n");
274 clientThread
= PR_CreateThread(PR_USER_THREAD
,
275 clientThreadFunc
, (void *) listenPort2
,
276 PR_PRIORITY_NORMAL
, PR_LOCAL_THREAD
,
277 PR_UNJOINABLE_THREAD
, 0);
278 if (clientThread
== NULL
) {
279 fprintf(stderr
, "can't create thread\n");
283 printf("Two client threads are created. Each of them will\n");
284 printf("send data to one of the two ports the server is listening on.\n");
285 printf("The data they send is the port number. Each of them send\n");
286 printf("the data five times, so you should see ten lines below,\n");
287 printf("interleaved in an arbitrary order.\n");
289 /* set up the fd array */
292 fds
[0] = listenSock1
;
293 fds
[1] = listenSock2
;
295 PR_FD_SET(listenSock1
, &readFdSet
);
296 PR_FD_SET(listenSock2
, &readFdSet
);
298 /* 20 events total */
305 retVal
= PR_Select(0 /* unused */, &readFdSet
, NULL
, NULL
,
306 PR_INTERVAL_NO_TIMEOUT
);
307 PR_ASSERT(retVal
!= 0); /* no timeout */
309 fprintf(stderr
, "PR_Select failed (%d, %d)\n", PR_GetError(),
315 /* the two listening sockets */
316 for (j
= 0; j
< 2; j
++) {
317 other_fds
[j
] = fds
[j
];
318 if (PR_FD_ISSET(fds
[j
], &readFdSet
)) {
322 sock
= PR_Accept(fds
[j
], NULL
, PR_INTERVAL_NO_TIMEOUT
);
324 fprintf(stderr
, "PR_Accept() failed\n");
327 other_fds
[nextIndex
] = sock
;
328 PR_FD_SET(sock
, &readFdSet
);
331 PR_FD_SET(fds
[j
], &readFdSet
);
334 for (j
= 2; j
< nfds
; j
++) {
335 if (PR_FD_ISSET(fds
[j
], &readFdSet
)) {
338 PR_FD_CLR(fds
[j
], &readFdSet
);
340 nBytes
= PR_Read(fds
[j
], buf
, sizeof(buf
));
342 fprintf(stderr
, "PR_Read() failed\n");
345 /* Just to be safe */
348 printf("The server received \"%s\" from a client\n", buf
);
350 PR_FD_SET(fds
[j
], &readFdSet
);
351 other_fds
[nextIndex
] = fds
[j
];
356 PR_ASSERT(retVal
== nEvents
);
365 printf("All tests finished\n");