source: rtems/cpukit/httpd/socket.c @ 120b59e

4.104.114.84.95
Last change on this file since 120b59e was bfb4c547, checked in by Joel Sherrill <joel.sherrill@…>, on 03/05/04 at 18:14:27

2004-03-05 Joel Sherrill <joel@…>

  • libnetworking/rtems_webserver/ejparse.c, libnetworking/rtems_webserver/emfdb.c, libnetworking/rtems_webserver/sock.c, libnetworking/rtems_webserver/socket.c, libnetworking/rtems_webserver/sym.c, libnetworking/rtems_webserver/webs.c, libnetworking/rtems_webserver/websuemf.c: Remove warnings.
  • Property mode set to 100644
File size: 21.1 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
8/******************************** Description *********************************/
9
10/*
11 *      Posix Socket Module.  This supports blocking and non-blocking buffered
12 *      socket I/O.
13 */
14
15#if (!WIN) || LITTLEFOOT || WEBS
16
17/********************************** Includes **********************************/
18
19#include        <string.h>
20#include        <stdlib.h>
21
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"
29#endif
30
31#if VXWORKS
32        #include        <hostLib.h>
33#endif
34
35#if __rtems__
36        #include        <sys/select.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 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
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
92        if (--socketOpenCount <= 0) {
93                for (i = socketMax; i >= 0; i--) {
94                        if (socketList && socketList[i]) {
95                                socketCloseConnection(i);
96                        }
97                }
98                socketOpenCount = 0;
99        }
100}
101
102/******************************************************************************/
103/*
104 *      Open a client or server socket. Host is NULL if we want server capability.
105 */
106
107int socketOpenConnection(char *host, int port, socketAccept_t accept, int flags)
108{
109#if ! (NO_GETHOSTBYNAME || VXWORKS)
110        struct hostent          *hostent;                                       /* Host database entry */
111#endif /* ! (NO_GETHOSTBYNAME || VXWORKS) */
112        socket_t                        *sp;
113        struct sockaddr_in      sockaddr;
114        int                                     sid, bcast, dgram, rc;
115
116        if (port > SOCKET_PORT_MAX) {
117                return -1;
118        }
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) {
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
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 {
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                                }
181                        }
182#endif /* (NO_GETHOSTBYNAME || VXWORKS) */
183                }
184        }
185
186        bcast = sp->flags & SOCKET_BROADCAST;
187        if (bcast) {
188                sp->flags |= SOCKET_DATAGRAM;
189        }
190        dgram = sp->flags & SOCKET_DATAGRAM;
191
192/*
193 *      Create the socket. Support for datagram sockets. Set the close on
194 *      exec flag so children don't inherit the socket.
195 */
196        sp->sock = socket(AF_INET, dgram ? SOCK_DGRAM: SOCK_STREAM, 0);
197        if (sp->sock < 0) {
198                socketFree(sid);
199                return -1;
200        }
201#ifndef __NO_FCNTL
202        fcntl(sp->sock, F_SETFD, FD_CLOEXEC);
203#endif
204        socketHighestFd = max(socketHighestFd, sp->sock);
205
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
218/*
219 *      Host is set if we are the client
220 */
221        if (host) {
222/*
223 *              Connect to the remote server in blocking mode, then go into
224 *              non-blocking mode if desired.
225 */
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;
236
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                }
268        } else {
269/*
270 *              Bind to the socket endpoint and the call listen() to start listening
271 */
272                rc = 1;
273                setsockopt(sp->sock, SOL_SOCKET, SO_REUSEADDR, (char *)&rc, sizeof(rc));
274                if (bind(sp->sock, (struct sockaddr *) &sockaddr,
275                                sizeof(sockaddr)) < 0) {
276                        socketFree(sid);
277                        return -1;
278                }
279
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
291                }
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);
303        }
304        return sid;
305}
306
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
329/******************************************************************************/
330/*
331 *      Close a socket
332 */
333
334void socketCloseConnection(int sid)
335{
336        socket_t        *sp;
337
338        if ((sp = socketPtr(sid)) == NULL) {
339                return;
340        }
341        socketFree(sid);
342}
343
344/******************************************************************************/
345/*
346 *      Accept a connection. Called as a callback on incoming connection.
347 */
348
349static void socketAccept(socket_t *sp)
350{
351        union {
352          struct sockaddr       addr;
353          struct sockaddr_in    addr_in;
354        } overlay;
355        struct sockaddr_in      *addr;
356        socket_t                        *nsp;
357        int                             len;
358        char                            *pString;
359        int                             newSock, nid;
360
361        a_assert(sp);
362        addr = &overlay.addr_in;
363
364/*
365 *      Accept the connection and prevent inheriting by children (F_SETFD)
366 */
367        len = sizeof(struct sockaddr_in);
368        if ((newSock = accept(sp->sock, &overlay.addr, &len)) < 0) {
369                return;
370        }
371#ifndef __NO_FCNTL
372        fcntl(newSock, F_SETFD, FD_CLOEXEC);
373#endif
374        socketHighestFd = max(socketHighestFd, newSock);
375
376/*
377 *      Create a socket structure and insert into the socket list
378 */
379        nid = socketAlloc(sp->host, sp->port, sp->accept, sp->flags);
380        nsp = socketList[nid];
381        a_assert(nsp);
382        nsp->sock = newSock;
383        nsp->flags &= ~SOCKET_LISTENING;
384
385        if (nsp == NULL) {
386                return;
387        }
388/*
389 *      Set the blocking mode before calling the accept callback.
390 */
391
392        socketSetBlock(nid, (nsp->flags & SOCKET_BLOCK) ? 1: 0);
393/*
394 *      Call the user accept callback. The user must call socketCreateHandler
395 *      to register for further events of interest.
396 */
397        if (sp->accept != NULL) {
398                pString = inet_ntoa(addr->sin_addr);
399                if ((sp->accept)(nid, pString, ntohs(addr->sin_port), sp->sid) < 0) {
400                        socketFree(nid);
401                }
402#if VXWORKS
403                free(pString);
404#endif
405        }
406}
407
408/******************************************************************************/
409/*
410 *      Get more input from the socket and return in buf.
411 *      Returns 0 for EOF, -1 for errors and otherwise the number of bytes read.
412 */
413
414int socketGetInput(int sid, char *buf, int toRead, int *errCode)
415{
416        struct sockaddr_in      server;
417        socket_t                        *sp;
418        int                             len, bytesRead;
419
420        a_assert(buf);
421        a_assert(errCode);
422
423        *errCode = 0;
424
425        if ((sp = socketPtr(sid)) == NULL) {
426                return -1;
427        }
428
429/*
430 *      If we have previously seen an EOF condition, then just return
431 */
432        if (sp->flags & SOCKET_EOF) {
433                return 0;
434        }
435#if (WIN || CE) && !(LITTLEFOOT || WEBS)
436        if ( !(sp->flags & SOCKET_BLOCK)
437                        && ! socketWaitForEvent(sp,  FD_CONNECT, errCode)) {
438                return -1;
439        }
440#endif
441
442/*
443 *      Read the data
444 */
445        if (sp->flags & SOCKET_DATAGRAM) {
446                len = sizeof(server);
447                bytesRead = recvfrom(sp->sock, buf, toRead, 0,
448                        (struct sockaddr *) &server, &len);
449        } else {
450                bytesRead = recv(sp->sock, buf, toRead, 0);
451        }
452        if (bytesRead < 0) {
453                if (errno == ECONNRESET) {
454                        return 0;
455                }
456                *errCode = socketGetError();
457                return -1;
458        }
459        return bytesRead;
460}
461
462/******************************************************************************/
463/*
464 *      Process an event on the event queue
465 */
466
467#ifndef UEMF
468
469static int socketEventProc(void *data, int mask)
470{
471        socket_t                *sp;
472        ringq_t                 *rq;
473        int                     sid;
474
475        sid = (int) data;
476
477        a_assert(sid >= 0 && sid < socketMax);
478        a_assert(socketList[sid]);
479
480        if ((sp = socketPtr(sid)) == NULL) {
481                return 1;
482        }
483
484/*
485 *      If now writable and flushing in the background, continue flushing
486 */
487        if (mask & SOCKET_WRITABLE) {
488                if (sp->flags & SOCKET_FLUSHING) {
489                        rq = &sp->outBuf;
490                        if (ringqLen(rq) > 0) {
491                                socketFlush(sp->sid);
492                        } else {
493                                sp->flags &= ~SOCKET_FLUSHING;
494                        }
495                }
496        }
497
498/*
499 *      Now invoke the users socket handler. NOTE: the handler may delete the
500 *      socket, so we must be very careful after calling the handler.
501 */
502        if (sp->handler && (sp->handlerMask & mask)) {
503                (sp->handler)(sid, mask & sp->handlerMask, sp->handler_data);
504        }
505        if (socketList && sid < socketMax && socketList[sid] == sp) {
506                socketRegisterInterest(sp, sp->handlerMask);
507        }
508        return 1;
509}
510#endif /* ! UEMF */
511
512/******************************************************************************/
513/*
514 *      Define the events of interest
515 */
516
517void socketRegisterInterest(socket_t *sp, int handlerMask)
518{
519        a_assert(sp);
520
521        sp->handlerMask = handlerMask;
522#if !UEMF
523        if (handlerMask) {
524                sp->fileHandle = emfCreateFileHandler(sp->sock, handlerMask,
525                        (emfFileProc *) socketEventProc, (void *) sp->sid);
526        } else {
527                emfDeleteFileHandler(sp->fileHandle);
528        }
529#endif /* ! UEMF */
530}
531
532/******************************************************************************/
533/*
534 *      Wait until an event occurs on a socket. Return 1 on success, 0 on failure.
535 *      or -1 on exception (UEMF only)
536 */
537
538int socketWaitForEvent(socket_t *sp, int handlerMask, int *errCode)
539{
540        int     mask;
541
542        a_assert(sp);
543
544        mask = sp->handlerMask;
545        sp->handlerMask |= handlerMask;
546        while (socketSelect(sp->sid, 1000)) {
547                if (sp->currentEvents & (handlerMask | SOCKET_EXCEPTION)) {
548                        break;
549                }
550        }
551        sp->handlerMask = mask;
552        if (sp->currentEvents & SOCKET_EXCEPTION) {
553                return -1;
554        } else if (sp->currentEvents & handlerMask) {
555                return 1;
556        }
557        if (errCode) {
558                *errCode = errno = EWOULDBLOCK;
559        }
560        return 0;
561}
562
563/******************************************************************************/
564/*
565 *      Return TRUE if there is a socket with an event ready to process,
566 */
567
568int socketReady(int sid)
569{
570        socket_t        *sp;
571        int                     all;
572
573        all = 0;
574        if (sid < 0) {
575                sid = 0;
576                all = 1;
577        }
578
579        for (; sid < socketMax; sid++) {
580                if ((sp = socketList[sid]) == NULL) {
581                        if (! all) {
582                                break;
583                        } else {
584                                continue;
585                        }
586                }
587                if (sp->currentEvents & sp->handlerMask) {
588                        return 1;
589                }
590/*
591 *              If there is input data, also call select to test for new events
592 */
593                if (sp->handlerMask & SOCKET_READABLE && socketInputBuffered(sid)) {
594                        socketSelect(sid, 0);
595                        return 1;
596                }
597                if (! all) {
598                        break;
599                }
600        }
601        return 0;
602}
603
604/******************************************************************************/
605/*
606 *      Wait for a handle to become readable or writable and return a number of
607 *      noticed events. Timeout is in milliseconds.
608 */
609
610#if WIN || CE
611
612int socketSelect(int sid, int timeout)
613{
614        struct timeval  tv;
615        socket_t                *sp;
616        fd_set                  readFds, writeFds, exceptFds;
617        int                     nEvents;
618        int                             all, socketHighestFd;   /* Highest socket fd opened */
619
620        FD_ZERO(&readFds);
621        FD_ZERO(&writeFds);
622        FD_ZERO(&exceptFds);
623        socketHighestFd = -1;
624
625        tv.tv_sec = timeout / 1000;
626        tv.tv_usec = (timeout % 1000) * 1000;
627
628/*
629 *      Set the select event masks for events to watch
630 */
631        all = nEvents = 0;
632
633        if (sid < 0) {
634                all++;
635                sid = 0;
636        }
637
638        for (; sid < socketMax; sid++) {
639                if ((sp = socketList[sid]) == NULL) {
640                        continue;
641                }
642                a_assert(sp);
643/*
644 *              Set the appropriate bit in the ready masks for the sp->sock.
645 */
646                if (sp->handlerMask & SOCKET_READABLE) {
647                        FD_SET(sp->sock, &readFds);
648                        nEvents++;
649                        if (socketInputBuffered(sid) > 0) {
650                                tv.tv_sec = 0;
651                                tv.tv_usec = 0;
652                        }
653                }
654                if (sp->handlerMask & SOCKET_WRITABLE) {
655                        FD_SET(sp->sock, &writeFds);
656                        nEvents++;
657                }
658                if (sp->handlerMask & SOCKET_EXCEPTION) {
659                        FD_SET(sp->sock, &exceptFds);
660                        nEvents++;
661                }
662                if (! all) {
663                        break;
664                }
665        }
666
667/*
668 *      Windows select() fails if no descriptors are set, instead of just sleeping
669 *      like other, nice select() calls. So, if WIN, sleep.
670 */
671        if (nEvents == 0) {
672                Sleep(timeout);
673                return 0;
674        }
675
676/*
677 *      Wait for the event or a timeout.
678 */
679        nEvents = select(socketHighestFd+1, &readFds, &writeFds, &exceptFds, &tv);
680
681        if (all) {
682                sid = 0;
683        }
684        for (; sid < socketMax; sid++) {
685                if ((sp = socketList[sid]) == NULL) {
686                        continue;
687                }
688
689                if (FD_ISSET(sp->sock, &readFds) || socketInputBuffered(sid) > 0) {
690                                sp->currentEvents |= SOCKET_READABLE;
691                }
692                if (FD_ISSET(sp->sock, &writeFds)) {
693                                sp->currentEvents |= SOCKET_WRITABLE;
694                }
695                if (FD_ISSET(sp->sock, &exceptFds)) {
696                                sp->currentEvents |= SOCKET_EXCEPTION;
697                }
698                if (! all) {
699                        break;
700                }
701        }
702
703        return nEvents;
704}
705
706#else /* not WIN || CE */
707
708int socketSelect(int sid, int timeout)
709{
710        socket_t                *sp;
711        struct timeval  tv;
712        fd_mask                 *readFds, *writeFds, *exceptFds;
713        int                     all, len, nwords, index, bit, nEvents;
714
715/*
716 *      Allocate and zero the select masks
717 */
718        nwords = (socketHighestFd + NFDBITS) / NFDBITS;
719        len = nwords * sizeof(int);
720
721        readFds = balloc(B_L, len);
722        memset(readFds, 0, len);
723        writeFds = balloc(B_L, len);
724        memset(writeFds, 0, len);
725        exceptFds = balloc(B_L, len);
726        memset(exceptFds, 0, len);
727
728        tv.tv_sec = timeout / 1000;
729        tv.tv_usec = (timeout % 1000) * 1000;
730
731/*
732 *      Set the select event masks for events to watch
733 */
734        all = nEvents = 0;
735
736        if (sid < 0) {
737                all++;
738                sid = 0;
739        }
740
741        for (; sid < socketMax; sid++) {
742                if ((sp = socketList[sid]) == NULL) {
743                        if (all == 0) {
744                                break;
745                        } else {
746                                continue;
747                        }
748                }
749                a_assert(sp);
750
751/*
752 *              Initialize the ready masks and compute the mask offsets.
753 */
754                index = sp->sock / (NBBY * sizeof(fd_mask));
755                bit = 1 << (sp->sock % (NBBY * sizeof(fd_mask)));
756               
757/*
758 *              Set the appropriate bit in the ready masks for the sp->sock.
759 */
760                if (sp->handlerMask & SOCKET_READABLE) {
761                        readFds[index] |= bit;
762                        nEvents++;
763                        if (socketInputBuffered(sid) > 0) {
764                                tv.tv_sec = 0;
765                                tv.tv_usec = 0;
766                        }
767                }
768                if (sp->handlerMask & SOCKET_WRITABLE) {
769                        writeFds[index] |= bit;
770                        nEvents++;
771                }
772                if (sp->handlerMask & SOCKET_EXCEPTION) {
773                        exceptFds[index] |= bit;
774                        nEvents++;
775                }
776                if (! all) {
777                        break;
778                }
779        }
780
781/*
782 *      Wait for the event or a timeout. Reset nEvents to be the number of actual
783 *      events now.
784 */
785        nEvents = select(socketHighestFd + 1, (fd_set *) readFds,
786                (fd_set *) writeFds, (fd_set *) exceptFds, &tv);
787
788        if (nEvents > 0) {
789                if (all) {
790                        sid = 0;
791                }
792                for (; sid < socketMax; sid++) {
793                        if ((sp = socketList[sid]) == NULL) {
794                                if (all == 0) {
795                                        break;
796                                } else {
797                                        continue;
798                                }
799                        }
800
801                        index = sp->sock / (NBBY * sizeof(fd_mask));
802                        bit = 1 << (sp->sock % (NBBY * sizeof(fd_mask)));
803
804                        if (readFds[index] & bit || socketInputBuffered(sid) > 0) {
805                                sp->currentEvents |= SOCKET_READABLE;
806                        }
807                        if (writeFds[index] & bit) {
808                                sp->currentEvents |= SOCKET_WRITABLE;
809                        }
810                        if (exceptFds[index] & bit) {
811                                sp->currentEvents |= SOCKET_EXCEPTION;
812                        }
813                        if (! all) {
814                                break;
815                        }
816                }
817        }
818
819        bfree(B_L, readFds);
820        bfree(B_L, writeFds);
821        bfree(B_L, exceptFds);
822
823        return nEvents;
824}
825#endif /* WIN || CE */
826
827/******************************************************************************/
828/*
829 *      Process socket events
830 */
831
832void socketProcess(int sid)
833{
834        socket_t        *sp;
835        int                     all;
836
837        all = 0;
838        if (sid < 0) {
839                all = 1;
840                sid = 0;
841        }
842/*
843 *      Process each socket
844 */
845        for (; sid < socketMax; sid++) {
846                if ((sp = socketList[sid]) == NULL) {
847                        if (! all) {
848                                break;
849                        } else {
850                                continue;
851                        }
852                }
853                if (socketReady(sid)) {
854                        socketDoEvent(sp);
855                }
856                if (! all) {
857                        break;
858                }
859        }
860}
861
862/******************************************************************************/
863/*
864 *      Process an event on the event queue
865 */
866
867static int socketDoEvent(socket_t *sp)
868{
869        ringq_t *rq;
870        int     sid;
871
872        a_assert(sp);
873
874    sid = sp->sid;
875        if (sp->currentEvents & SOCKET_READABLE) {
876                if (sp->flags & SOCKET_LISTENING) {
877                        socketAccept(sp);
878                        sp->currentEvents = 0;
879                        return 1;
880                }
881
882        } else {
883/*
884 *              If there is still read data in the buffers, trigger the read handler
885 *              NOTE: this may busy spin if the read handler doesn't read the data
886 */
887                if (sp->handlerMask & SOCKET_READABLE && socketInputBuffered(sid)) {
888                        sp->currentEvents |= SOCKET_READABLE;
889                }
890        }
891
892
893/*
894 *      If now writable and flushing in the background, continue flushing
895 */
896        if (sp->currentEvents & SOCKET_WRITABLE) {
897                if (sp->flags & SOCKET_FLUSHING) {
898                        rq = &sp->outBuf;
899                        if (ringqLen(rq) > 0) {
900                                socketFlush(sp->sid);
901                        } else {
902                                sp->flags &= ~SOCKET_FLUSHING;
903                        }
904                }
905        }
906
907/*
908 *      Now invoke the users socket handler. NOTE: the handler may delete the
909 *      socket, so we must be very careful after calling the handler.
910 */
911        if (sp->handler && (sp->handlerMask & sp->currentEvents)) {
912                (sp->handler)(sid, sp->handlerMask & sp->currentEvents,
913                        sp->handler_data);
914/*
915 *              Make sure socket pointer is still valid, then reset the currentEvents.
916 */
917                if (socketList && sid < socketMax && socketList[sid] == sp) {
918                        sp->currentEvents = 0;
919                }
920        }
921        return 1;
922}
923
924/******************************************************************************/
925/*
926 *      Set the socket blocking mode
927 */
928
929int socketSetBlock(int sid, int on)
930{
931        socket_t                *sp;
932        unsigned long   flag;
933        int                             iflag;
934        int                             oldBlock;
935
936        flag = iflag = !on;
937
938        if ((sp = socketPtr(sid)) == NULL) {
939                a_assert(0);
940                return 0;
941        }
942        oldBlock = (sp->flags & SOCKET_BLOCK);
943        sp->flags &= ~(SOCKET_BLOCK);
944        if (on) {
945                sp->flags |= SOCKET_BLOCK;
946        }
947
948/*
949 *      Put the socket into block / non-blocking mode
950 */
951        if (sp->flags & SOCKET_BLOCK) {
952#if CE || WIN
953                ioctlsocket(sp->sock, FIONBIO, &flag);
954#elif ECOS
955                int off;
956                off = 0;
957                ioctl(sp->sock, FIONBIO, &off);
958#elif VXWORKS
959                ioctl(sp->sock, FIONBIO, (int)&iflag);
960#else
961                fcntl(sp->sock, F_SETFL, fcntl(sp->sock, F_GETFL) & ~O_NONBLOCK);
962#endif
963
964        } else {
965#if CE || WIN
966                ioctlsocket(sp->sock, FIONBIO, &flag);
967#elif ECOS
968                int on;
969                on = 1;
970                ioctl(sp->sock, FIONBIO, &on);
971#elif VXWORKS
972                ioctl(sp->sock, FIONBIO, (int)&iflag);
973#else
974                fcntl(sp->sock, F_SETFL, fcntl(sp->sock, F_GETFL) | O_NONBLOCK);
975#endif
976        }
977        return oldBlock;
978}
979
980/******************************************************************************/
981/*
982 *      Return true if a readable socket has buffered data. - not public
983 */
984
985int socketDontBlock()
986{
987        socket_t        *sp;
988        int                     i;
989
990        for (i = 0; i < socketMax; i++) {
991                if ((sp = socketList[i]) == NULL ||
992                                (sp->handlerMask & SOCKET_READABLE) == 0) {
993                        continue;
994                }
995                if (socketInputBuffered(i) > 0) {
996                        return 1;
997                }
998        }
999        return 0;
1000}
1001
1002/******************************************************************************/
1003/*
1004 *      Return true if a particular socket buffered data. - not public
1005 */
1006
1007int socketSockBuffered(int sock)
1008{
1009        socket_t        *sp;
1010        int                     i;
1011
1012        for (i = 0; i < socketMax; i++) {
1013                if ((sp = socketList[i]) == NULL || sp->sock != sock) {
1014                        continue;
1015                }
1016                return socketInputBuffered(i);
1017        }
1018        return 0;
1019}
1020
1021#endif /* (!WIN) | LITTLEFOOT | WEBS */
1022
1023/******************************************************************************/
Note: See TracBrowser for help on using the repository browser.