source: rtems/cpukit/httpd/socket.c @ 2419e17

4.104.114.84.95
Last change on this file since 2419e17 was 2419e17, checked in by Joel Sherrill <joel.sherrill@…>, on 10/31/02 at 20:13:54

2002-10-31 Joel Sherrill <joel@…>

  • rtems_webserver/socket.c, rtems_webserver/uemf.h: Removed warnings.
  • Property mode set to 100644
File size: 21.1 KB
RevLine 
[a6b4c0df]1
[c1cdaa0]2/*
[a6b4c0df]3 *      sockGen.c -- Posix Socket support module for general posix use
[c1cdaa0]4 *
[a6b4c0df]5 * Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved.
[c1cdaa0]6 */
7
8/******************************** Description *********************************/
9
10/*
[a6b4c0df]11 *      Posix Socket Module.  This supports blocking and non-blocking buffered
12 *      socket I/O.
[c1cdaa0]13 */
14
[a6b4c0df]15#if (!WIN) || LITTLEFOOT || WEBS
16
[c1cdaa0]17/********************************** Includes **********************************/
18
19#include        <string.h>
20#include        <stdlib.h>
21
[a6b4c0df]22#if UEMF
23        #include        "uemf.h"
24#else
25        #include        <socket.h>
26        #include        <types.h>
27        #include        <unistd.h>
28        #include        "emfInternal.h"
[b8d9f41]29#endif
30
[a6b4c0df]31#if VXWORKS
32        #include        <hostLib.h>
33#endif
34
35#if __rtems__
36        #include        <sys/select.h>
37#endif
[c1cdaa0]38
39/************************************ Locals **********************************/
40
[a6b4c0df]41extern socket_t         **socketList;                   /* List of open sockets */
42extern int                      socketMax;                              /* Maximum size of socket */
43extern int                      socketHighestFd;                /* Highest socket fd opened */
44static int                      socketOpenCount = 0;    /* Number of task using sockets */
[c1cdaa0]45
46/***************************** Forward Declarations ***************************/
47
[a6b4c0df]48static void socketAccept(socket_t *sp);
[c1cdaa0]49static int      socketDoEvent(socket_t *sp);
[a6b4c0df]50static int      tryAlternateConnect(int sock, struct sockaddr *sockaddr);
[c1cdaa0]51
52/*********************************** Code *************************************/
53/*
54 *      Open socket module
55 */
56
57int socketOpen()
58{
[a6b4c0df]59#if CE || WIN
60    WSADATA     wsaData;
61#endif
62
63        if (++socketOpenCount > 1) {
64                return 0;
65        }
66
67#if CE || WIN
68        if (WSAStartup(MAKEWORD(1,1), &wsaData) != 0) {
69                return -1;
70        }
71        if (wsaData.wVersion != MAKEWORD(1,1)) {
72                WSACleanup();
73                return -1;
74        }
75#endif
76        socketList = NULL;
77        socketMax = 0;
78        socketHighestFd = -1;
79
[c1cdaa0]80        return 0;
81}
82
83/******************************************************************************/
84/*
85 *      Close the socket module, by closing all open connections
86 */
87
88void socketClose()
89{
90        int             i;
91
[a6b4c0df]92        if (--socketOpenCount <= 0) {
93                for (i = socketMax; i >= 0; i--) {
94                        if (socketList && socketList[i]) {
95                                socketCloseConnection(i);
96                        }
[c1cdaa0]97                }
[a6b4c0df]98                socketOpenCount = 0;
[c1cdaa0]99        }
100}
101
102/******************************************************************************/
103/*
104 *      Open a client or server socket. Host is NULL if we want server capability.
105 */
106
[a6b4c0df]107int socketOpenConnection(char *host, int port, socketAccept_t accept, int flags)
[c1cdaa0]108{
[a6b4c0df]109#if ! (NO_GETHOSTBYNAME || VXWORKS)
110        struct hostent          *hostent;                                       /* Host database entry */
111#endif /* ! (NO_GETHOSTBYNAME || VXWORKS) */
[c1cdaa0]112        socket_t                        *sp;
[a6b4c0df]113        struct sockaddr_in      sockaddr;
114        int                                     sid, bcast, dgram, rc;
[c1cdaa0]115
[a6b4c0df]116        if (port > SOCKET_PORT_MAX) {
117                return -1;
118        }
[c1cdaa0]119/*
120 *      Allocate a socket structure
121 */
122        if ((sid = socketAlloc(host, port, accept, flags)) < 0) {
123                return -1;
124        }
125        sp = socketList[sid];
126        a_assert(sp);
127
128/*
129 *      Create the socket address structure
130 */
131        memset((char *) &sockaddr, '\0', sizeof(struct sockaddr_in));
132        sockaddr.sin_family = AF_INET;
133        sockaddr.sin_port = htons((short) (port & 0xFFFF));
134
135        if (host == NULL) {
136                sockaddr.sin_addr.s_addr = INADDR_ANY;
137        } else {
138                sockaddr.sin_addr.s_addr = inet_addr(host);
139                if (sockaddr.sin_addr.s_addr == INADDR_NONE) {
[a6b4c0df]140/*
141 *                      If the OS does not support gethostbyname functionality, the macro:
142 *                      NO_GETHOSTBYNAME should be defined to skip the use of gethostbyname.
143 *                      Unfortunatly there is no easy way to recover, the following code
144 *                      simply uses the basicGetHost IP for the sockaddr.
145 */
146
147#if NO_GETHOSTBYNAME
148                        if (strcmp(host, basicGetHost()) == 0) {
149                                sockaddr.sin_addr.s_addr = inet_addr(basicGetAddress());
150                        }
151                        if (sockaddr.sin_addr.s_addr == INADDR_NONE) {
152                                socketFree(sid);
153                                return -1;
154                        }
155#elif VXWORKS
156                        sockaddr.sin_addr.s_addr = (unsigned long) hostGetByName(host);
157                        if (sockaddr.sin_addr.s_addr == NULL) {
158                                errno = ENXIO;
159                                socketFree(sid);
160                                return -1;
161                        }
162#else
[c1cdaa0]163                        hostent = gethostbyname(host);
164                        if (hostent != NULL) {
165                                memcpy((char *) &sockaddr.sin_addr,
166                                        (char *) hostent->h_addr_list[0],
167                                        (size_t) hostent->h_length);
168                        } else {
[a6b4c0df]169                                char    *asciiAddress;
170                                char_t  *address;
171
172                                address = basicGetAddress();
173                                asciiAddress = ballocUniToAsc(address, gstrlen(address));
174                                sockaddr.sin_addr.s_addr = inet_addr(asciiAddress);
175                                bfree(B_L, asciiAddress);
176                                if (sockaddr.sin_addr.s_addr == INADDR_NONE) {
177                                        errno = ENXIO;
178                                        socketFree(sid);
179                                        return -1;
180                                }
[c1cdaa0]181                        }
[a6b4c0df]182#endif /* (NO_GETHOSTBYNAME || VXWORKS) */
[c1cdaa0]183                }
184        }
185
[a6b4c0df]186        bcast = sp->flags & SOCKET_BROADCAST;
187        if (bcast) {
188                sp->flags |= SOCKET_DATAGRAM;
189        }
190        dgram = sp->flags & SOCKET_DATAGRAM;
191
[c1cdaa0]192/*
[a6b4c0df]193 *      Create the socket. Support for datagram sockets. Set the close on
194 *      exec flag so children don't inherit the socket.
[c1cdaa0]195 */
[a6b4c0df]196        sp->sock = socket(AF_INET, dgram ? SOCK_DGRAM: SOCK_STREAM, 0);
[c1cdaa0]197        if (sp->sock < 0) {
198                socketFree(sid);
199                return -1;
200        }
[a6b4c0df]201#ifndef __NO_FCNTL
[c1cdaa0]202        fcntl(sp->sock, F_SETFD, FD_CLOEXEC);
[a6b4c0df]203#endif
[c1cdaa0]204        socketHighestFd = max(socketHighestFd, sp->sock);
205
[a6b4c0df]206/*
207 *      If broadcast, we need to turn on broadcast capability.
208 */
209        if (bcast) {
210                int broadcastFlag = 1;
211                if (setsockopt(sp->sock, SOL_SOCKET, SO_BROADCAST,
212                                (char *) &broadcastFlag, sizeof(broadcastFlag)) < 0) {
213                        socketFree(sid);
214                        return -1;
215                }
216        }
217
[c1cdaa0]218/*
219 *      Host is set if we are the client
220 */
221        if (host) {
222/*
[a6b4c0df]223 *              Connect to the remote server in blocking mode, then go into
224 *              non-blocking mode if desired.
[c1cdaa0]225 */
[a6b4c0df]226                if (!dgram) {
227                        if (! (sp->flags & SOCKET_BLOCK)) {
228/*
229 *                              sockGen.c is only used for Windows products when blocking
230 *                              connects are expected.  This applies to FieldUpgrader
231 *                              agents and open source webserver connectws.  Therefore the
232 *                              asynchronous connect code here is not compiled.
233 */
234#if (WIN || CE) && !(LITTLEFOOT || WEBS)
235                                int flag;
[c1cdaa0]236
[a6b4c0df]237                                sp->flags |= SOCKET_ASYNC;
238/*
239 *                              Set to non-blocking for an async connect
240 */
241                                flag = 1;
242                                if (ioctlsocket(sp->sock, FIONBIO, &flag) == SOCKET_ERROR) {
243                                        socketFree(sid);
244                                        return -1;
245                                }
246#else
247                                socketSetBlock(sid, 1);
248#endif /* #if (WIN || CE) && !(LITTLEFOOT || WEBS) */
249
250                        }
251                        if ((rc = connect(sp->sock, (struct sockaddr *) &sockaddr,
252                                sizeof(sockaddr))) < 0 &&
253                                (rc = tryAlternateConnect(sp->sock,
254                                (struct sockaddr *) &sockaddr)) < 0) {
255#if WIN || CE
256                                if (socketGetError() != EWOULDBLOCK) {
257                                        socketFree(sid);
258                                        return -1;
259                                }
260#else
261                                socketFree(sid);
262                                return -1;
263
264#endif /* WIN || CE */
265
266                        }
267                }
[c1cdaa0]268        } else {
269/*
[a6b4c0df]270 *              Bind to the socket endpoint and the call listen() to start listening
[c1cdaa0]271 */
272                rc = 1;
273                setsockopt(sp->sock, SOL_SOCKET, SO_REUSEADDR, (char *)&rc, sizeof(rc));
[a6b4c0df]274                if (bind(sp->sock, (struct sockaddr *) &sockaddr,
275                                sizeof(sockaddr)) < 0) {
[c1cdaa0]276                        socketFree(sid);
277                        return -1;
278                }
279
[a6b4c0df]280                if (! dgram) {
281                        if (listen(sp->sock, SOMAXCONN) < 0) {
282                                socketFree(sid);
283                                return -1;
284                        }
285#if !UEMF
286                        sp->fileHandle = emfCreateFileHandler(sp->sock, SOCKET_READABLE,
287                                (emfFileProc *) socketAccept, (void *) sp);
288#else
289                        sp->flags |= SOCKET_LISTENING;
290#endif
[c1cdaa0]291                }
[a6b4c0df]292                sp->handlerMask |= SOCKET_READABLE;
293        }
294
295/*
296 *      Set the blocking mode
297 */
298
299        if (flags & SOCKET_BLOCK) {
300                socketSetBlock(sid, 1);
301        } else {
302                socketSetBlock(sid, 0);
[c1cdaa0]303        }
304        return sid;
305}
306
[a6b4c0df]307/******************************************************************************/
308/*
309 *      If the connection failed, swap the first two bytes in the
310 *      sockaddr structure.  This is a kludge due to a change in
311 *      VxWorks between versions 5.3 and 5.4, but we want the
312 *      product to run on either.
313 */
314
315static int tryAlternateConnect(int sock, struct sockaddr *sockaddr)
316{
317#if VXWORKS
318        char *ptr;
319
320        ptr = (char *)sockaddr;
321        *ptr = *(ptr+1);
322        *(ptr+1) = 0;
323        return connect(sock, sockaddr, sizeof(struct sockaddr));
324#else
325        return -1;
326#endif /* VXWORKS */
327}
328
[c1cdaa0]329/******************************************************************************/
330/*
331 *      Close a socket
332 */
333
334void socketCloseConnection(int sid)
335{
[a6b4c0df]336        socket_t        *sp;
[c1cdaa0]337
338        if ((sp = socketPtr(sid)) == NULL) {
339                return;
340        }
341        socketFree(sid);
342}
343
344/******************************************************************************/
345/*
[a6b4c0df]346 *      Accept a connection. Called as a callback on incoming connection.
[c1cdaa0]347 */
348
[a6b4c0df]349static void socketAccept(socket_t *sp)
[c1cdaa0]350{
351        struct sockaddr_in      addr;
352        socket_t                        *nsp;
[a6b4c0df]353        size_t                          len;
354        char                            *pString;
[c1cdaa0]355        int                             newSock, nid;
356
357        a_assert(sp);
358
359/*
360 *      Accept the connection and prevent inheriting by children (F_SETFD)
361 */
362        len = sizeof(struct sockaddr_in);
[2419e17]363        if ((newSock = accept(sp->sock, (struct sockaddr *) &addr, (int *)&len)) < 0) {
[c1cdaa0]364                return;
365        }
[a6b4c0df]366#ifndef __NO_FCNTL
[c1cdaa0]367        fcntl(newSock, F_SETFD, FD_CLOEXEC);
[a6b4c0df]368#endif
[c1cdaa0]369        socketHighestFd = max(socketHighestFd, newSock);
370
371/*
372 *      Create a socket structure and insert into the socket list
373 */
[a6b4c0df]374        nid = socketAlloc(sp->host, sp->port, sp->accept, sp->flags);
[c1cdaa0]375        nsp = socketList[nid];
376        a_assert(nsp);
377        nsp->sock = newSock;
[a6b4c0df]378        nsp->flags &= ~SOCKET_LISTENING;
[c1cdaa0]379
380        if (nsp == NULL) {
381                return;
382        }
383/*
[a6b4c0df]384 *      Set the blocking mode before calling the accept callback.
385 */
386
387        socketSetBlock(nid, (nsp->flags & SOCKET_BLOCK) ? 1: 0);
388/*
389 *      Call the user accept callback. The user must call socketCreateHandler
[c1cdaa0]390 *      to register for further events of interest.
391 */
392        if (sp->accept != NULL) {
[a6b4c0df]393                pString = inet_ntoa(addr.sin_addr);
394                if ((sp->accept)(nid, pString, ntohs(addr.sin_port), sp->sid) < 0) {
[c1cdaa0]395                        socketFree(nid);
396                }
[a6b4c0df]397#if VXWORKS
398                free(pString);
399#endif
[c1cdaa0]400        }
401}
402
403/******************************************************************************/
404/*
[a6b4c0df]405 *      Get more input from the socket and return in buf.
406 *      Returns 0 for EOF, -1 for errors and otherwise the number of bytes read.
[c1cdaa0]407 */
408
[a6b4c0df]409int socketGetInput(int sid, char *buf, int toRead, int *errCode)
[c1cdaa0]410{
[a6b4c0df]411        struct sockaddr_in      server;
412        socket_t                        *sp;
413        int                             len, bytesRead;
[c1cdaa0]414
415        a_assert(buf);
[a6b4c0df]416        a_assert(errCode);
417
418        *errCode = 0;
[c1cdaa0]419
420        if ((sp = socketPtr(sid)) == NULL) {
421                return -1;
422        }
423
424/*
[a6b4c0df]425 *      If we have previously seen an EOF condition, then just return
[c1cdaa0]426 */
427        if (sp->flags & SOCKET_EOF) {
428                return 0;
429        }
[a6b4c0df]430#if (WIN || CE) && !(LITTLEFOOT || WEBS)
431        if ( !(sp->flags & SOCKET_BLOCK)
432                        && ! socketWaitForEvent(sp,  FD_CONNECT, errCode)) {
433                return -1;
434        }
435#endif
[c1cdaa0]436
437/*
[a6b4c0df]438 *      Read the data
[c1cdaa0]439 */
[a6b4c0df]440        if (sp->flags & SOCKET_DATAGRAM) {
441                len = sizeof(server);
442                bytesRead = recvfrom(sp->sock, buf, toRead, 0,
443                        (struct sockaddr *) &server, &len);
444        } else {
445                bytesRead = recv(sp->sock, buf, toRead, 0);
446        }
447        if (bytesRead < 0) {
448                if (errno == ECONNRESET) {
449                        return 0;
[c1cdaa0]450                }
[a6b4c0df]451                *errCode = socketGetError();
452                return -1;
[c1cdaa0]453        }
454        return bytesRead;
455}
456
457/******************************************************************************/
458/*
[a6b4c0df]459 *      Process an event on the event queue
[c1cdaa0]460 */
461
[a6b4c0df]462#ifndef UEMF
463
464static int socketEventProc(void *data, int mask)
[c1cdaa0]465{
[a6b4c0df]466        socket_t                *sp;
467        ringq_t                 *rq;
468        int                     sid;
[c1cdaa0]469
[a6b4c0df]470        sid = (int) data;
471
472        a_assert(sid >= 0 && sid < socketMax);
473        a_assert(socketList[sid]);
[c1cdaa0]474
475        if ((sp = socketPtr(sid)) == NULL) {
[a6b4c0df]476                return 1;
[c1cdaa0]477        }
478
479/*
[a6b4c0df]480 *      If now writable and flushing in the background, continue flushing
[c1cdaa0]481 */
[a6b4c0df]482        if (mask & SOCKET_WRITABLE) {
483                if (sp->flags & SOCKET_FLUSHING) {
484                        rq = &sp->outBuf;
485                        if (ringqLen(rq) > 0) {
486                                socketFlush(sp->sid);
[c1cdaa0]487                        } else {
[a6b4c0df]488                                sp->flags &= ~SOCKET_FLUSHING;
[c1cdaa0]489                        }
490                }
491        }
492
493/*
[a6b4c0df]494 *      Now invoke the users socket handler. NOTE: the handler may delete the
495 *      socket, so we must be very careful after calling the handler.
[c1cdaa0]496 */
[a6b4c0df]497        if (sp->handler && (sp->handlerMask & mask)) {
498                (sp->handler)(sid, mask & sp->handlerMask, sp->handler_data);
[c1cdaa0]499        }
[a6b4c0df]500        if (socketList && sid < socketMax && socketList[sid] == sp) {
501                socketRegisterInterest(sp, sp->handlerMask);
[c1cdaa0]502        }
[a6b4c0df]503        return 1;
[c1cdaa0]504}
[a6b4c0df]505#endif /* ! UEMF */
[c1cdaa0]506
507/******************************************************************************/
508/*
[a6b4c0df]509 *      Define the events of interest
[c1cdaa0]510 */
511
[a6b4c0df]512void socketRegisterInterest(socket_t *sp, int handlerMask)
[c1cdaa0]513{
[a6b4c0df]514        a_assert(sp);
[c1cdaa0]515
[a6b4c0df]516        sp->handlerMask = handlerMask;
517#if !UEMF
518        if (handlerMask) {
519                sp->fileHandle = emfCreateFileHandler(sp->sock, handlerMask,
520                        (emfFileProc *) socketEventProc, (void *) sp->sid);
521        } else {
522                emfDeleteFileHandler(sp->fileHandle);
[c1cdaa0]523        }
[a6b4c0df]524#endif /* ! UEMF */
[c1cdaa0]525}
526
527/******************************************************************************/
528/*
[a6b4c0df]529 *      Wait until an event occurs on a socket. Return 1 on success, 0 on failure.
530 *      or -1 on exception (UEMF only)
[c1cdaa0]531 */
532
[a6b4c0df]533int socketWaitForEvent(socket_t *sp, int handlerMask, int *errCode)
[c1cdaa0]534{
[a6b4c0df]535        int     mask;
[c1cdaa0]536
[a6b4c0df]537        a_assert(sp);
538
539        mask = sp->handlerMask;
540        sp->handlerMask |= handlerMask;
541        while (socketSelect(sp->sid, 1000)) {
542                if (sp->currentEvents & (handlerMask | SOCKET_EXCEPTION)) {
543                        break;
544                }
545        }
546        sp->handlerMask = mask;
547        if (sp->currentEvents & SOCKET_EXCEPTION) {
[c1cdaa0]548                return -1;
[a6b4c0df]549        } else if (sp->currentEvents & handlerMask) {
550                return 1;
[c1cdaa0]551        }
[a6b4c0df]552        if (errCode) {
553                *errCode = errno = EWOULDBLOCK;
554        }
555        return 0;
[c1cdaa0]556}
557
558/******************************************************************************/
559/*
[a6b4c0df]560 *      Return TRUE if there is a socket with an event ready to process,
[c1cdaa0]561 */
562
[a6b4c0df]563int socketReady(int sid)
[c1cdaa0]564{
[a6b4c0df]565        socket_t        *sp;
566        int                     all;
[c1cdaa0]567
[a6b4c0df]568        all = 0;
569        if (sid < 0) {
570                sid = 0;
571                all = 1;
[c1cdaa0]572        }
573
[a6b4c0df]574        for (; sid < socketMax; sid++) {
575                if ((sp = socketList[sid]) == NULL) {
576                        if (! all) {
577                                break;
578                        } else {
579                                continue;
580                        }
581                }
582                if (sp->currentEvents & sp->handlerMask) {
583                        return 1;
584                }
[c1cdaa0]585/*
[a6b4c0df]586 *              If there is input data, also call select to test for new events
[c1cdaa0]587 */
[a6b4c0df]588                if (sp->handlerMask & SOCKET_READABLE && socketInputBuffered(sid)) {
589                        socketSelect(sid, 0);
590                        return 1;
591                }
592                if (! all) {
593                        break;
594                }
[c1cdaa0]595        }
[a6b4c0df]596        return 0;
[c1cdaa0]597}
598
599/******************************************************************************/
600/*
[a6b4c0df]601 *      Wait for a handle to become readable or writable and return a number of
602 *      noticed events. Timeout is in milliseconds.
[c1cdaa0]603 */
604
[a6b4c0df]605#if WIN || CE
[c1cdaa0]606
[a6b4c0df]607int socketSelect(int sid, int timeout)
608{
609        struct timeval  tv;
610        socket_t                *sp;
611        fd_set                  readFds, writeFds, exceptFds;
612        int                     nEvents;
613        int                             all, socketHighestFd;   /* Highest socket fd opened */
614
615        FD_ZERO(&readFds);
616        FD_ZERO(&writeFds);
617        FD_ZERO(&exceptFds);
618        socketHighestFd = -1;
[c1cdaa0]619
[a6b4c0df]620        tv.tv_sec = timeout / 1000;
621        tv.tv_usec = (timeout % 1000) * 1000;
[c1cdaa0]622
623/*
[a6b4c0df]624 *      Set the select event masks for events to watch
[c1cdaa0]625 */
[a6b4c0df]626        all = nEvents = 0;
[c1cdaa0]627
[a6b4c0df]628        if (sid < 0) {
629                all++;
630                sid = 0;
[c1cdaa0]631        }
632
[a6b4c0df]633        for (; sid < socketMax; sid++) {
634                if ((sp = socketList[sid]) == NULL) {
635                        continue;
[c1cdaa0]636                }
[a6b4c0df]637                a_assert(sp);
[c1cdaa0]638/*
[a6b4c0df]639 *              Set the appropriate bit in the ready masks for the sp->sock.
[c1cdaa0]640 */
[a6b4c0df]641                if (sp->handlerMask & SOCKET_READABLE) {
642                        FD_SET(sp->sock, &readFds);
643                        nEvents++;
644                        if (socketInputBuffered(sid) > 0) {
645                                tv.tv_sec = 0;
646                                tv.tv_usec = 0;
647                        }
648                }
649                if (sp->handlerMask & SOCKET_WRITABLE) {
650                        FD_SET(sp->sock, &writeFds);
651                        nEvents++;
652                }
653                if (sp->handlerMask & SOCKET_EXCEPTION) {
654                        FD_SET(sp->sock, &exceptFds);
655                        nEvents++;
656                }
657                if (! all) {
658                        break;
659                }
660        }
[c1cdaa0]661
662/*
[a6b4c0df]663 *      Windows select() fails if no descriptors are set, instead of just sleeping
664 *      like other, nice select() calls. So, if WIN, sleep.
[c1cdaa0]665 */
[a6b4c0df]666        if (nEvents == 0) {
667                Sleep(timeout);
668                return 0;
[c1cdaa0]669        }
670
671/*
[a6b4c0df]672 *      Wait for the event or a timeout.
[c1cdaa0]673 */
[a6b4c0df]674        nEvents = select(socketHighestFd+1, &readFds, &writeFds, &exceptFds, &tv);
[c1cdaa0]675
[a6b4c0df]676        if (all) {
677                sid = 0;
678        }
679        for (; sid < socketMax; sid++) {
680                if ((sp = socketList[sid]) == NULL) {
[c1cdaa0]681                        continue;
[a6b4c0df]682                }
683
684                if (FD_ISSET(sp->sock, &readFds) || socketInputBuffered(sid) > 0) {
685                                sp->currentEvents |= SOCKET_READABLE;
686                }
687                if (FD_ISSET(sp->sock, &writeFds)) {
688                                sp->currentEvents |= SOCKET_WRITABLE;
689                }
690                if (FD_ISSET(sp->sock, &exceptFds)) {
691                                sp->currentEvents |= SOCKET_EXCEPTION;
692                }
693                if (! all) {
694                        break;
[c1cdaa0]695                }
696        }
[a6b4c0df]697
698        return nEvents;
[c1cdaa0]699}
700
[a6b4c0df]701#else /* not WIN || CE */
[c1cdaa0]702
[a6b4c0df]703int socketSelect(int sid, int timeout)
[c1cdaa0]704{
[a6b4c0df]705        socket_t                *sp;
706        struct timeval  tv;
707        fd_mask                 *readFds, *writeFds, *exceptFds;
708        int                     all, len, nwords, index, bit, nEvents;
[c1cdaa0]709
710/*
711 *      Allocate and zero the select masks
712 */
[a6b4c0df]713        nwords = (socketHighestFd + NFDBITS) / NFDBITS;
[c1cdaa0]714        len = nwords * sizeof(int);
715
716        readFds = balloc(B_L, len);
717        memset(readFds, 0, len);
718        writeFds = balloc(B_L, len);
719        memset(writeFds, 0, len);
720        exceptFds = balloc(B_L, len);
721        memset(exceptFds, 0, len);
722
[a6b4c0df]723        tv.tv_sec = timeout / 1000;
724        tv.tv_usec = (timeout % 1000) * 1000;
725
[c1cdaa0]726/*
727 *      Set the select event masks for events to watch
728 */
[a6b4c0df]729        all = nEvents = 0;
730
731        if (sid < 0) {
732                all++;
733                sid = 0;
734        }
735
736        for (; sid < socketMax; sid++) {
[c1cdaa0]737                if ((sp = socketList[sid]) == NULL) {
[a6b4c0df]738                        if (all == 0) {
739                                break;
740                        } else {
741                                continue;
742                        }
[c1cdaa0]743                }
744                a_assert(sp);
745
746/*
747 *              Initialize the ready masks and compute the mask offsets.
748 */
749                index = sp->sock / (NBBY * sizeof(fd_mask));
750                bit = 1 << (sp->sock % (NBBY * sizeof(fd_mask)));
751               
752/*
753 *              Set the appropriate bit in the ready masks for the sp->sock.
754 */
[a6b4c0df]755                if (sp->handlerMask & SOCKET_READABLE) {
[c1cdaa0]756                        readFds[index] |= bit;
[a6b4c0df]757                        nEvents++;
758                        if (socketInputBuffered(sid) > 0) {
759                                tv.tv_sec = 0;
760                                tv.tv_usec = 0;
761                        }
[c1cdaa0]762                }
[a6b4c0df]763                if (sp->handlerMask & SOCKET_WRITABLE) {
[c1cdaa0]764                        writeFds[index] |= bit;
[a6b4c0df]765                        nEvents++;
[c1cdaa0]766                }
[a6b4c0df]767                if (sp->handlerMask & SOCKET_EXCEPTION) {
[c1cdaa0]768                        exceptFds[index] |= bit;
[a6b4c0df]769                        nEvents++;
770                }
771                if (! all) {
772                        break;
[c1cdaa0]773                }
774        }
775
776/*
[a6b4c0df]777 *      Wait for the event or a timeout. Reset nEvents to be the number of actual
778 *      events now.
[c1cdaa0]779 */
780        nEvents = select(socketHighestFd + 1, (fd_set *) readFds,
[a6b4c0df]781                (fd_set *) writeFds, (fd_set *) exceptFds, &tv);
782
[c1cdaa0]783        if (nEvents > 0) {
[a6b4c0df]784                if (all) {
785                        sid = 0;
786                }
787                for (; sid < socketMax; sid++) {
[c1cdaa0]788                        if ((sp = socketList[sid]) == NULL) {
[a6b4c0df]789                                if (all == 0) {
790                                        break;
791                                } else {
792                                        continue;
793                                }
[c1cdaa0]794                        }
795
796                        index = sp->sock / (NBBY * sizeof(fd_mask));
797                        bit = 1 << (sp->sock % (NBBY * sizeof(fd_mask)));
[a6b4c0df]798
799                        if (readFds[index] & bit || socketInputBuffered(sid) > 0) {
800                                sp->currentEvents |= SOCKET_READABLE;
[c1cdaa0]801                        }
802                        if (writeFds[index] & bit) {
[a6b4c0df]803                                sp->currentEvents |= SOCKET_WRITABLE;
[c1cdaa0]804                        }
805                        if (exceptFds[index] & bit) {
[a6b4c0df]806                                sp->currentEvents |= SOCKET_EXCEPTION;
807                        }
808                        if (! all) {
809                                break;
[c1cdaa0]810                        }
811                }
812        }
813
814        bfree(B_L, readFds);
815        bfree(B_L, writeFds);
816        bfree(B_L, exceptFds);
817
818        return nEvents;
819}
[a6b4c0df]820#endif /* WIN || CE */
[c1cdaa0]821
822/******************************************************************************/
823/*
824 *      Process socket events
825 */
826
[a6b4c0df]827void socketProcess(int sid)
[c1cdaa0]828{
829        socket_t        *sp;
[a6b4c0df]830        int                     all;
[c1cdaa0]831
[a6b4c0df]832        all = 0;
833        if (sid < 0) {
834                all = 1;
835                sid = 0;
836        }
[c1cdaa0]837/*
838 *      Process each socket
839 */
[a6b4c0df]840        for (; sid < socketMax; sid++) {
[c1cdaa0]841                if ((sp = socketList[sid]) == NULL) {
[a6b4c0df]842                        if (! all) {
843                                break;
844                        } else {
845                                continue;
846                        }
[c1cdaa0]847                }
[a6b4c0df]848                if (socketReady(sid)) {
[c1cdaa0]849                        socketDoEvent(sp);
850                }
[a6b4c0df]851                if (! all) {
852                        break;
853                }
[c1cdaa0]854        }
855}
856
857/******************************************************************************/
858/*
[a6b4c0df]859 *      Process an event on the event queue
[c1cdaa0]860 */
861
862static int socketDoEvent(socket_t *sp)
863{
[a6b4c0df]864        ringq_t *rq;
865        int     sid;
[c1cdaa0]866
867        a_assert(sp);
868
869    sid = sp->sid;
[a6b4c0df]870        if (sp->currentEvents & SOCKET_READABLE) {
871                if (sp->flags & SOCKET_LISTENING) {
[c1cdaa0]872                        socketAccept(sp);
[a6b4c0df]873                        sp->currentEvents = 0;
[c1cdaa0]874                        return 1;
[a6b4c0df]875                }
876
[c1cdaa0]877        } else {
878/*
879 *              If there is still read data in the buffers, trigger the read handler
880 *              NOTE: this may busy spin if the read handler doesn't read the data
881 */
[a6b4c0df]882                if (sp->handlerMask & SOCKET_READABLE && socketInputBuffered(sid)) {
883                        sp->currentEvents |= SOCKET_READABLE;
[c1cdaa0]884                }
885        }
886
887
888/*
889 *      If now writable and flushing in the background, continue flushing
890 */
[a6b4c0df]891        if (sp->currentEvents & SOCKET_WRITABLE) {
[c1cdaa0]892                if (sp->flags & SOCKET_FLUSHING) {
893                        rq = &sp->outBuf;
894                        if (ringqLen(rq) > 0) {
[a6b4c0df]895                                socketFlush(sp->sid);
[c1cdaa0]896                        } else {
897                                sp->flags &= ~SOCKET_FLUSHING;
898                        }
899                }
900        }
901
902/*
903 *      Now invoke the users socket handler. NOTE: the handler may delete the
904 *      socket, so we must be very careful after calling the handler.
905 */
[a6b4c0df]906        if (sp->handler && (sp->handlerMask & sp->currentEvents)) {
907                (sp->handler)(sid, sp->handlerMask & sp->currentEvents,
[c1cdaa0]908                        sp->handler_data);
909/*
[a6b4c0df]910 *              Make sure socket pointer is still valid, then reset the currentEvents.
[c1cdaa0]911 */
[a6b4c0df]912                if (socketList && sid < socketMax && socketList[sid] == sp) {
913                        sp->currentEvents = 0;
[c1cdaa0]914                }
915        }
916        return 1;
917}
918
919/******************************************************************************/
920/*
[a6b4c0df]921 *      Set the socket blocking mode
[c1cdaa0]922 */
923
[a6b4c0df]924int socketSetBlock(int sid, int on)
[c1cdaa0]925{
[a6b4c0df]926        socket_t                *sp;
927        unsigned long   flag;
928        int                             iflag;
929        int                             oldBlock;
[c1cdaa0]930
[a6b4c0df]931        flag = iflag = !on;
[c1cdaa0]932
933        if ((sp = socketPtr(sid)) == NULL) {
[a6b4c0df]934                a_assert(0);
935                return 0;
[c1cdaa0]936        }
[a6b4c0df]937        oldBlock = (sp->flags & SOCKET_BLOCK);
938        sp->flags &= ~(SOCKET_BLOCK);
939        if (on) {
940                sp->flags |= SOCKET_BLOCK;
[c1cdaa0]941        }
942
943/*
[a6b4c0df]944 *      Put the socket into block / non-blocking mode
[c1cdaa0]945 */
[a6b4c0df]946        if (sp->flags & SOCKET_BLOCK) {
947#if CE || WIN
948                ioctlsocket(sp->sock, FIONBIO, &flag);
949#elif ECOS
950                int off;
951                off = 0;
952                ioctl(sp->sock, FIONBIO, &off);
953#elif VXWORKS
954                ioctl(sp->sock, FIONBIO, (int)&iflag);
955#else
956                fcntl(sp->sock, F_SETFL, fcntl(sp->sock, F_GETFL) & ~O_NONBLOCK);
957#endif
[c1cdaa0]958
[a6b4c0df]959        } else {
960#if CE || WIN
961                ioctlsocket(sp->sock, FIONBIO, &flag);
962#elif ECOS
963                int on;
964                on = 1;
965                ioctl(sp->sock, FIONBIO, &on);
966#elif VXWORKS
967                ioctl(sp->sock, FIONBIO, (int)&iflag);
968#else
969                fcntl(sp->sock, F_SETFL, fcntl(sp->sock, F_GETFL) | O_NONBLOCK);
970#endif
[c1cdaa0]971        }
[a6b4c0df]972        return oldBlock;
[c1cdaa0]973}
974
975/******************************************************************************/
976/*
[a6b4c0df]977 *      Return true if a readable socket has buffered data. - not public
[c1cdaa0]978 */
979
[a6b4c0df]980int socketDontBlock()
[c1cdaa0]981{
[a6b4c0df]982        socket_t        *sp;
983        int                     i;
[c1cdaa0]984
[a6b4c0df]985        for (i = 0; i < socketMax; i++) {
986                if ((sp = socketList[i]) == NULL ||
987                                (sp->handlerMask & SOCKET_READABLE) == 0) {
988                        continue;
989                }
990                if (socketInputBuffered(i) > 0) {
991                        return 1;
[c1cdaa0]992                }
993        }
[a6b4c0df]994        return 0;
[c1cdaa0]995}
996
997/******************************************************************************/
998/*
[a6b4c0df]999 *      Return true if a particular socket buffered data. - not public
[c1cdaa0]1000 */
1001
[a6b4c0df]1002int socketSockBuffered(int sock)
[c1cdaa0]1003{
[a6b4c0df]1004        socket_t        *sp;
1005        int                     i;
[c1cdaa0]1006
[a6b4c0df]1007        for (i = 0; i < socketMax; i++) {
1008                if ((sp = socketList[i]) == NULL || sp->sock != sock) {
1009                        continue;
1010                }
1011                return socketInputBuffered(i);
1012        }
[c1cdaa0]1013        return 0;
1014}
1015
[a6b4c0df]1016#endif /* (!WIN) | LITTLEFOOT | WEBS */
[c1cdaa0]1017
[a6b4c0df]1018/******************************************************************************/
Note: See TracBrowser for help on using the repository browser.