Back to index

lightning-sunbird  0.9+nobinonly
prpoll.c
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is the Netscape Portable Runtime (NSPR).
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998-2000
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #ifdef WIN32
00039 #include <windows.h>
00040 #endif
00041 
00042 #ifdef XP_OS2_VACPP
00043 #include <io.h>      /* for close() */
00044 #endif
00045 
00046 #ifdef XP_UNIX
00047 #include <unistd.h>  /* for close() */
00048 #endif
00049 
00050 #include "prinit.h"
00051 #include "prio.h"
00052 #include "prlog.h"
00053 #include "prprf.h"
00054 #include "prnetdb.h"
00055 
00056 #ifndef XP_MAC
00057 #include "private/pprio.h"
00058 #else
00059 #include "pprio.h"
00060 #endif
00061 
00062 #define CLIENT_LOOPS 5
00063 #define BUF_SIZE            128
00064 
00065 #include <stdio.h>
00066 #include <string.h>
00067 #include <stdlib.h>
00068 
00069 static void
00070 clientThreadFunc(void *arg)
00071 {
00072     PRUint16 port = (PRUint16) arg;
00073     PRFileDesc *sock;
00074     PRNetAddr addr;
00075     char buf[BUF_SIZE];
00076     int i;
00077 
00078     addr.inet.family = PR_AF_INET;
00079     addr.inet.port = PR_htons(port);
00080     addr.inet.ip = PR_htonl(PR_INADDR_LOOPBACK);
00081     PR_snprintf(buf, sizeof(buf), "%hu", port);
00082 
00083     for (i = 0; i < 5; i++) {
00084        sock = PR_NewTCPSocket();
00085         PR_Connect(sock, &addr, PR_INTERVAL_NO_TIMEOUT);
00086 
00087        PR_Write(sock, buf, sizeof(buf));
00088        PR_Close(sock);
00089     }
00090 }
00091 
00092 int main(int argc, char **argv)
00093 {
00094     PRFileDesc *listenSock1, *listenSock2;
00095     PRFileDesc *badFD;
00096     PRUint16 listenPort1, listenPort2;
00097     PRNetAddr addr;
00098     char buf[BUF_SIZE];
00099     PRThread *clientThread;
00100     PRPollDesc pds0[10], pds1[10], *pds, *other_pds;
00101     PRIntn npds;
00102     PRInt32 retVal;
00103     PRInt32 sd, rv;
00104        struct sockaddr_in saddr;
00105     PRIntn saddr_len;
00106     PRUint16 listenPort3;
00107     PRFileDesc *socket_poll_fd;
00108     PRIntn i, j;
00109 
00110     PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
00111     PR_STDIO_INIT();
00112 
00113     printf("This program tests PR_Poll with sockets.\n");
00114     printf("Timeout, error reporting, and normal operation are tested.\n\n");
00115 
00116     /* Create two listening sockets */
00117     if ((listenSock1 = PR_NewTCPSocket()) == NULL) {
00118        fprintf(stderr, "Can't create a new TCP socket\n");
00119        exit(1);
00120     }
00121     addr.inet.family = PR_AF_INET;
00122     addr.inet.ip = PR_htonl(PR_INADDR_ANY);
00123     addr.inet.port = PR_htons(0);
00124     if (PR_Bind(listenSock1, &addr) == PR_FAILURE) {
00125        fprintf(stderr, "Can't bind socket\n");
00126        exit(1);
00127     }
00128     if (PR_GetSockName(listenSock1, &addr) == PR_FAILURE) {
00129        fprintf(stderr, "PR_GetSockName failed\n");
00130        exit(1);
00131     }
00132     listenPort1 = PR_ntohs(addr.inet.port);
00133     if (PR_Listen(listenSock1, 5) == PR_FAILURE) {
00134        fprintf(stderr, "Can't listen on a socket\n");
00135        exit(1);
00136     }
00137 
00138     if ((listenSock2  = PR_NewTCPSocket()) == NULL) {
00139        fprintf(stderr, "Can't create a new TCP socket\n");
00140        exit(1);
00141     }
00142     addr.inet.family = PR_AF_INET;
00143     addr.inet.ip = PR_htonl(PR_INADDR_ANY);
00144     addr.inet.port = PR_htons(0);
00145     if (PR_Bind(listenSock2, &addr) == PR_FAILURE) {
00146        fprintf(stderr, "Can't bind socket\n");
00147        exit(1);
00148     }
00149     if (PR_GetSockName(listenSock2, &addr) == PR_FAILURE) {
00150        fprintf(stderr, "PR_GetSockName failed\n");
00151        exit(1);
00152     }
00153     listenPort2 = PR_ntohs(addr.inet.port);
00154     if (PR_Listen(listenSock2, 5) == PR_FAILURE) {
00155        fprintf(stderr, "Can't listen on a socket\n");
00156        exit(1);
00157     }
00158     /* Set up the poll descriptor array */
00159     pds = pds0;
00160     other_pds = pds1;
00161     memset(pds, 0, sizeof(pds));
00162        npds = 0;
00163     pds[npds].fd = listenSock1;
00164     pds[npds].in_flags = PR_POLL_READ;
00165        npds++;
00166     pds[npds].fd = listenSock2;
00167     pds[npds].in_flags = PR_POLL_READ;
00168        npds++;
00169 
00170        sd = socket(AF_INET, SOCK_STREAM, 0);
00171        PR_ASSERT(sd >= 0);
00172        memset((char *) &saddr, 0, sizeof(saddr));
00173        saddr.sin_family = AF_INET;
00174        saddr.sin_addr.s_addr = htonl(INADDR_ANY);
00175        saddr.sin_port = htons(0);
00176 
00177        rv = bind(sd, (struct sockaddr *)&saddr, sizeof(saddr));
00178        PR_ASSERT(rv == 0);
00179        saddr_len = sizeof(saddr);
00180        rv = getsockname(sd, (struct sockaddr *) &saddr, &saddr_len);
00181        PR_ASSERT(rv == 0);
00182     listenPort3 = ntohs(saddr.sin_port);
00183 
00184        rv = listen(sd, 5);
00185        PR_ASSERT(rv == 0);
00186     pds[npds].fd = socket_poll_fd = PR_CreateSocketPollFd(sd);
00187        PR_ASSERT(pds[npds].fd);
00188     pds[npds].in_flags = PR_POLL_READ;
00189     npds++;
00190     PR_snprintf(buf, sizeof(buf),
00191            "The server thread is listening on ports %hu, %hu and %hu\n\n",
00192            listenPort1, listenPort2, listenPort3);
00193     printf("%s", buf);
00194 
00195     /* Testing timeout */
00196     printf("PR_Poll should time out in 5 seconds\n");
00197     retVal = PR_Poll(pds, npds, PR_SecondsToInterval(5));
00198     if (retVal != 0) {
00199        PR_snprintf(buf, sizeof(buf),
00200               "PR_Poll should time out and return 0, but it returns %ld\n",
00201               retVal);
00202        fprintf(stderr, "%s", buf);
00203        exit(1);
00204     }
00205     printf("PR_Poll timed out.  Test passed.\n\n");
00206 
00207     /* Testing bad fd */
00208     printf("PR_Poll should detect a bad file descriptor\n");
00209     if ((badFD = PR_NewTCPSocket()) == NULL) {
00210        fprintf(stderr, "Can't create a TCP socket\n");
00211        exit(1);
00212     }
00213 
00214     pds[npds].fd = badFD;
00215     pds[npds].in_flags = PR_POLL_READ;
00216     npds++;
00217     PR_Close(badFD);  /* make the fd bad */
00218 #if 0
00219     retVal = PR_Poll(pds, npds, PR_INTERVAL_NO_TIMEOUT);
00220     if (retVal != 1 || (unsigned short) pds[2].out_flags != PR_POLL_NVAL) {
00221        fprintf(stderr, "Failed to detect the bad fd: "
00222               "PR_Poll returns %d, out_flags is 0x%hx\n",
00223               retVal, pds[npds - 1].out_flags);
00224        exit(1);
00225     }
00226     printf("PR_Poll detected the bad fd.  Test passed.\n\n");
00227 #endif
00228     npds--;
00229 
00230     clientThread = PR_CreateThread(PR_USER_THREAD,
00231            clientThreadFunc, (void *) listenPort1,
00232            PR_PRIORITY_NORMAL, PR_LOCAL_THREAD,
00233            PR_UNJOINABLE_THREAD, 0);
00234     if (clientThread == NULL) {
00235        fprintf(stderr, "can't create thread\n");
00236        exit(1);
00237     }
00238 
00239     clientThread = PR_CreateThread(PR_USER_THREAD,
00240            clientThreadFunc, (void *) listenPort2,
00241            PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
00242            PR_UNJOINABLE_THREAD, 0);
00243     if (clientThread == NULL) {
00244        fprintf(stderr, "can't create thread\n");
00245        exit(1);
00246     }
00247 
00248     clientThread = PR_CreateThread(PR_USER_THREAD,
00249            clientThreadFunc, (void *) listenPort3,
00250            PR_PRIORITY_NORMAL, PR_GLOBAL_BOUND_THREAD,
00251            PR_UNJOINABLE_THREAD, 0);
00252     if (clientThread == NULL) {
00253        fprintf(stderr, "can't create thread\n");
00254        exit(1);
00255     }
00256 
00257 
00258     printf("Three client threads are created.  Each of them will\n");
00259     printf("send data to one of the three ports the server is listening on.\n");
00260     printf("The data they send is the port number.  Each of them send\n");
00261     printf("the data five times, so you should see ten lines below,\n");
00262     printf("interleaved in an arbitrary order.\n");
00263 
00264     /* 30 events total */
00265     i = 0;
00266     while (i < 30) {
00267               PRPollDesc *tmp;
00268               int nextIndex;
00269               int nEvents = 0;
00270 
00271               retVal = PR_Poll(pds, npds, PR_INTERVAL_NO_TIMEOUT);
00272               PR_ASSERT(retVal != 0);  /* no timeout */
00273               if (retVal == -1) {
00274                      fprintf(stderr, "PR_Poll failed\n");
00275                      exit(1);
00276               }
00277 
00278               nextIndex = 3;
00279               /* the three listening sockets */
00280               for (j = 0; j < 3; j++) {
00281                      other_pds[j] = pds[j];
00282                      PR_ASSERT((pds[j].out_flags & PR_POLL_WRITE) == 0
00283                             && (pds[j].out_flags & PR_POLL_EXCEPT) == 0);
00284                      if (pds[j].out_flags & PR_POLL_READ) {
00285                             PRFileDesc *sock;
00286 
00287                             nEvents++;
00288                             if (j == 2) {
00289                                    int newsd;
00290                                    newsd = accept(PR_FileDesc2NativeHandle(pds[j].fd), NULL, 0);
00291                                    if (newsd == -1) {
00292                                           fprintf(stderr, "accept() failed\n");
00293                                           exit(1);
00294                                    }
00295                                    other_pds[nextIndex].fd  = PR_CreateSocketPollFd(newsd);
00296                                    PR_ASSERT(other_pds[nextIndex].fd);
00297                                    other_pds[nextIndex].in_flags = PR_POLL_READ;
00298                             } else {
00299                                    sock = PR_Accept(pds[j].fd, NULL, PR_INTERVAL_NO_TIMEOUT);
00300                                    if (sock == NULL) {
00301                                           fprintf(stderr, "PR_Accept() failed\n");
00302                                           exit(1);
00303                                    }
00304                                    other_pds[nextIndex].fd = sock;
00305                                    other_pds[nextIndex].in_flags = PR_POLL_READ;
00306                             }
00307                             nextIndex++;
00308                      } else if (pds[j].out_flags & PR_POLL_ERR) {
00309                             fprintf(stderr, "PR_Poll() indicates that an fd has error\n");
00310                             exit(1);
00311                      } else if (pds[j].out_flags & PR_POLL_NVAL) {
00312                             fprintf(stderr, "PR_Poll() indicates that fd %d is invalid\n",
00313                                    PR_FileDesc2NativeHandle(pds[j].fd));
00314                             exit(1);
00315                      }
00316               }
00317 
00318               for (j = 3; j < npds; j++) {
00319                      PR_ASSERT((pds[j].out_flags & PR_POLL_WRITE) == 0
00320                             && (pds[j].out_flags & PR_POLL_EXCEPT) == 0);
00321                      if (pds[j].out_flags & PR_POLL_READ) {
00322                             PRInt32 nBytes;
00323 
00324                             nEvents++;
00325                             /* XXX: This call is a hack and should be fixed */
00326                             if (PR_GetDescType(pds[j].fd) == (PRDescType) 0) {
00327                                    nBytes = recv(PR_FileDesc2NativeHandle(pds[j].fd), buf,
00328                                                                       sizeof(buf), 0);
00329                                    if (nBytes == -1) {
00330                                           fprintf(stderr, "recv() failed\n");
00331                                           exit(1);
00332                                    }
00333                                    printf("Server read %d bytes from native fd %d\n",nBytes,
00334                                                                       PR_FileDesc2NativeHandle(pds[j].fd));
00335 #ifdef WIN32
00336                                    closesocket((SOCKET)PR_FileDesc2NativeHandle(pds[j].fd));
00337 #else
00338                                    close(PR_FileDesc2NativeHandle(pds[j].fd));
00339 #endif
00340                                    PR_DestroySocketPollFd(pds[j].fd);
00341                             } else {
00342                                    nBytes = PR_Read(pds[j].fd, buf, sizeof(buf));
00343                                    if (nBytes == -1) {
00344                                           fprintf(stderr, "PR_Read() failed\n");
00345                                           exit(1);
00346                                    }
00347                                    PR_Close(pds[j].fd);
00348                             }
00349                             /* Just to be safe */
00350                             buf[BUF_SIZE - 1] = '\0';
00351                             printf("The server received \"%s\" from a client\n", buf);
00352                      } else if (pds[j].out_flags & PR_POLL_ERR) {
00353                             fprintf(stderr, "PR_Poll() indicates that an fd has error\n");
00354                             exit(1);
00355                      } else if (pds[j].out_flags & PR_POLL_NVAL) {
00356                             fprintf(stderr, "PR_Poll() indicates that an fd is invalid\n");
00357                             exit(1);
00358                      } else {
00359                             other_pds[nextIndex] = pds[j];
00360                             nextIndex++;
00361                      }
00362               }
00363 
00364               PR_ASSERT(retVal == nEvents);
00365               /* swap */
00366               tmp = pds;
00367               pds = other_pds;
00368               other_pds = tmp;
00369               npds = nextIndex;
00370               i += nEvents;
00371     }
00372     PR_DestroySocketPollFd(socket_poll_fd);
00373 
00374     printf("All tests finished\n");
00375     PR_Cleanup();
00376     return 0;
00377 }