source: rtems/cpukit/httpd/sockGen.c @ cf04e8ac

4.104.114.84.95
Last change on this file since cf04e8ac was 73b5bd5d, checked in by Ralf Corsepius <ralf.corsepius@…>, on 04/15/04 at 13:33:58

Remove stray white spaces.

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