1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
3
* The contents of this file are subject to the Mozilla Public
4
* License Version 1.1 (the "License"); you may not use this file
5
* except in compliance with the License. You may obtain a copy of
6
* the License at http://www.mozilla.org/MPL/
8
* Software distributed under the License is distributed on an "AS
9
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
10
* implied. See the License for the specific language governing
11
* rights and limitations under the License.
13
* The Original Code is the Netscape Portable Runtime (NSPR).
15
* The Initial Developer of the Original Code is Netscape
16
* Communications Corporation. Portions created by Netscape are
17
* Copyright (C) 1998-2000 Netscape Communications Corporation. All
22
* Alternatively, the contents of this file may be used under the
23
* terms of the GNU General Public License Version 2 or later (the
24
* "GPL"), in which case the provisions of the GPL are applicable
25
* instead of those above. If you wish to allow use of your
26
* version of this file only under the terms of the GPL and not to
27
* allow others to use your version of this file under the MPL,
28
* indicate your decision by deleting the provisions above and
29
* replace them with the notice and other provisions required by
30
* the GPL. If you do not delete the provisions above, a recipient
31
* may use your version of this file under either the MPL or the
40
#include <io.h> /* for close() */
50
#include "private/pprio.h"
55
#define CLIENT_LOOPS 5
63
clientThreadFunc(void *arg)
65
PRUint16 port = (PRUint16) arg;
71
addr.inet.family = PR_AF_INET;
72
addr.inet.port = PR_htons(port);
73
addr.inet.ip = PR_htonl(PR_INADDR_LOOPBACK);
74
PR_snprintf(buf, sizeof(buf), "%hu", port);
76
for (i = 0; i < 5; i++) {
77
sock = PR_NewTCPSocket();
78
PR_Connect(sock, &addr, PR_INTERVAL_NO_TIMEOUT);
80
PR_Write(sock, buf, sizeof(buf));
85
int main(int argc, char **argv)
87
PRFileDesc *listenSock1, *listenSock2;
89
PRUint16 listenPort1, listenPort2;
92
PRThread *clientThread;
93
PRPollDesc pds0[10], pds1[10], *pds, *other_pds;
97
struct sockaddr_in saddr;
100
PRFileDesc *socket_poll_fd;
103
PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
106
printf("This program tests PR_Poll with sockets.\n");
107
printf("Timeout, error reporting, and normal operation are tested.\n\n");
109
/* Create two listening sockets */
110
if ((listenSock1 = PR_NewTCPSocket()) == NULL) {
111
fprintf(stderr, "Can't create a new TCP socket\n");
114
addr.inet.family = PR_AF_INET;
115
addr.inet.ip = PR_htonl(PR_INADDR_ANY);
116
addr.inet.port = PR_htons(0);
117
if (PR_Bind(listenSock1, &addr) == PR_FAILURE) {
118
fprintf(stderr, "Can't bind socket\n");
121
if (PR_GetSockName(listenSock1, &addr) == PR_FAILURE) {
122
fprintf(stderr, "PR_GetSockName failed\n");
125
listenPort1 = PR_ntohs(addr.inet.port);
126
if (PR_Listen(listenSock1, 5) == PR_FAILURE) {
127
fprintf(stderr, "Can't listen on a socket\n");
131
if ((listenSock2 = PR_NewTCPSocket()) == NULL) {
132
fprintf(stderr, "Can't create a new TCP socket\n");
135
addr.inet.family = PR_AF_INET;
136
addr.inet.ip = PR_htonl(PR_INADDR_ANY);
137
addr.inet.port = PR_htons(0);
138
if (PR_Bind(listenSock2, &addr) == PR_FAILURE) {
139
fprintf(stderr, "Can't bind socket\n");
142
if (PR_GetSockName(listenSock2, &addr) == PR_FAILURE) {
143
fprintf(stderr, "PR_GetSockName failed\n");
146
listenPort2 = PR_ntohs(addr.inet.port);
147
if (PR_Listen(listenSock2, 5) == PR_FAILURE) {
148
fprintf(stderr, "Can't listen on a socket\n");
151
/* Set up the poll descriptor array */
154
memset(pds, 0, sizeof(pds));
156
pds[npds].fd = listenSock1;
157
pds[npds].in_flags = PR_POLL_READ;
159
pds[npds].fd = listenSock2;
160
pds[npds].in_flags = PR_POLL_READ;
163
sd = socket(AF_INET, SOCK_STREAM, 0);
165
memset((char *) &saddr, 0, sizeof(saddr));
166
saddr.sin_family = AF_INET;
167
saddr.sin_addr.s_addr = htonl(INADDR_ANY);
168
saddr.sin_port = htons(0);
170
rv = bind(sd, (struct sockaddr *)&saddr, sizeof(saddr));
172
saddr_len = sizeof(saddr);
173
rv = getsockname(sd, (struct sockaddr *) &saddr, &saddr_len);
175
listenPort3 = ntohs(saddr.sin_port);
179
pds[npds].fd = socket_poll_fd = PR_CreateSocketPollFd(sd);
180
PR_ASSERT(pds[npds].fd);
181
pds[npds].in_flags = PR_POLL_READ;
183
PR_snprintf(buf, sizeof(buf),
184
"The server thread is listening on ports %hu, %hu and %hu\n\n",
185
listenPort1, listenPort2, listenPort3);
188
/* Testing timeout */
189
printf("PR_Poll should time out in 5 seconds\n");
190
retVal = PR_Poll(pds, npds, PR_SecondsToInterval(5));
192
PR_snprintf(buf, sizeof(buf),
193
"PR_Poll should time out and return 0, but it returns %ld\n",
195
fprintf(stderr, "%s", buf);
198
printf("PR_Poll timed out. Test passed.\n\n");
201
printf("PR_Poll should detect a bad file descriptor\n");
202
if ((badFD = PR_NewTCPSocket()) == NULL) {
203
fprintf(stderr, "Can't create a TCP socket\n");
207
pds[npds].fd = badFD;
208
pds[npds].in_flags = PR_POLL_READ;
210
PR_Close(badFD); /* make the fd bad */
212
retVal = PR_Poll(pds, npds, PR_INTERVAL_NO_TIMEOUT);
213
if (retVal != 1 || (unsigned short) pds[2].out_flags != PR_POLL_NVAL) {
214
fprintf(stderr, "Failed to detect the bad fd: "
215
"PR_Poll returns %d, out_flags is 0x%hx\n",
216
retVal, pds[npds - 1].out_flags);
219
printf("PR_Poll detected the bad fd. Test passed.\n\n");
223
clientThread = PR_CreateThread(PR_USER_THREAD,
224
clientThreadFunc, (void *) listenPort1,
225
PR_PRIORITY_NORMAL, PR_LOCAL_THREAD,
226
PR_UNJOINABLE_THREAD, 0);
227
if (clientThread == NULL) {
228
fprintf(stderr, "can't create thread\n");
232
clientThread = PR_CreateThread(PR_USER_THREAD,
233
clientThreadFunc, (void *) listenPort2,
234
PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
235
PR_UNJOINABLE_THREAD, 0);
236
if (clientThread == NULL) {
237
fprintf(stderr, "can't create thread\n");
241
clientThread = PR_CreateThread(PR_USER_THREAD,
242
clientThreadFunc, (void *) listenPort3,
243
PR_PRIORITY_NORMAL, PR_GLOBAL_BOUND_THREAD,
244
PR_UNJOINABLE_THREAD, 0);
245
if (clientThread == NULL) {
246
fprintf(stderr, "can't create thread\n");
251
printf("Three client threads are created. Each of them will\n");
252
printf("send data to one of the three ports the server is listening on.\n");
253
printf("The data they send is the port number. Each of them send\n");
254
printf("the data five times, so you should see ten lines below,\n");
255
printf("interleaved in an arbitrary order.\n");
257
/* 30 events total */
264
retVal = PR_Poll(pds, npds, PR_INTERVAL_NO_TIMEOUT);
265
PR_ASSERT(retVal != 0); /* no timeout */
267
fprintf(stderr, "PR_Poll failed\n");
272
/* the three listening sockets */
273
for (j = 0; j < 3; j++) {
274
other_pds[j] = pds[j];
275
PR_ASSERT((pds[j].out_flags & PR_POLL_WRITE) == 0
276
&& (pds[j].out_flags & PR_POLL_EXCEPT) == 0);
277
if (pds[j].out_flags & PR_POLL_READ) {
283
newsd = accept(PR_FileDesc2NativeHandle(pds[j].fd), NULL, 0);
285
fprintf(stderr, "accept() failed\n");
288
other_pds[nextIndex].fd = PR_CreateSocketPollFd(newsd);
289
PR_ASSERT(other_pds[nextIndex].fd);
290
other_pds[nextIndex].in_flags = PR_POLL_READ;
292
sock = PR_Accept(pds[j].fd, NULL, PR_INTERVAL_NO_TIMEOUT);
294
fprintf(stderr, "PR_Accept() failed\n");
297
other_pds[nextIndex].fd = sock;
298
other_pds[nextIndex].in_flags = PR_POLL_READ;
301
} else if (pds[j].out_flags & PR_POLL_ERR) {
302
fprintf(stderr, "PR_Poll() indicates that an fd has error\n");
304
} else if (pds[j].out_flags & PR_POLL_NVAL) {
305
fprintf(stderr, "PR_Poll() indicates that fd %d is invalid\n",
306
PR_FileDesc2NativeHandle(pds[j].fd));
311
for (j = 3; j < npds; j++) {
312
PR_ASSERT((pds[j].out_flags & PR_POLL_WRITE) == 0
313
&& (pds[j].out_flags & PR_POLL_EXCEPT) == 0);
314
if (pds[j].out_flags & PR_POLL_READ) {
318
/* XXX: This call is a hack and should be fixed */
319
if (PR_GetDescType(pds[j].fd) == (PRDescType) 0) {
320
nBytes = recv(PR_FileDesc2NativeHandle(pds[j].fd), buf,
323
fprintf(stderr, "recv() failed\n");
326
printf("Server read %d bytes from native fd %d\n",nBytes,
327
PR_FileDesc2NativeHandle(pds[j].fd));
329
closesocket((SOCKET)PR_FileDesc2NativeHandle(pds[j].fd));
331
close(PR_FileDesc2NativeHandle(pds[j].fd));
333
PR_DestroySocketPollFd(pds[j].fd);
335
nBytes = PR_Read(pds[j].fd, buf, sizeof(buf));
337
fprintf(stderr, "PR_Read() failed\n");
342
/* Just to be safe */
343
buf[BUF_SIZE - 1] = '\0';
344
printf("The server received \"%s\" from a client\n", buf);
345
} else if (pds[j].out_flags & PR_POLL_ERR) {
346
fprintf(stderr, "PR_Poll() indicates that an fd has error\n");
348
} else if (pds[j].out_flags & PR_POLL_NVAL) {
349
fprintf(stderr, "PR_Poll() indicates that an fd is invalid\n");
352
other_pds[nextIndex] = pds[j];
357
PR_ASSERT(retVal == nEvents);
365
PR_DestroySocketPollFd(socket_poll_fd);
367
printf("All tests finished\n");