source: rtems/cpukit/httpd/sock.c @ f22ebf0

4.104.114.84.95
Last change on this file since f22ebf0 was 527b508, checked in by Joel Sherrill <joel.sherrill@…>, on 09/28/00 at 20:08:07

2000-09-28 Joel Sherrill <joel@…>

  • rtems_webserver/Makefile.am, rtems_webserver/base64.c, rtems_webserver/base64.c: Renamed base64.c to wbase64.c.
  • rtems_webserver/sock.c: Added file missed in merger.
  • Property mode set to 100644
File size: 17.2 KB
Line 
1/*
2 * sock.c -- Posix Socket upper layer support module for general posix use
3 *
4 * Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved.
5 */
6
7/******************************** Description *********************************/
8
9/*
10 *      Posix Socket Module.  This supports blocking and non-blocking buffered
11 *      socket I/O.
12 */
13
14/********************************** Includes **********************************/
15
16#include        <string.h>
17#include        <stdlib.h>
18
19#if UEMF
20        #include        "uemf.h"
21#else
22        #include        <socket.h>
23        #include        <types.h>
24        #include        <unistd.h>
25        #include        "emfInternal.h"
26#endif
27
28/************************************ Locals **********************************/
29
30socket_t        **socketList;                   /* List of open sockets */
31int                     socketMax;                              /* Maximum size of socket */
32int                     socketHighestFd = -1;   /* Highest socket fd opened */
33
34/***************************** Forward Declarations ***************************/
35
36static int      socketDoOutput(socket_t *sp, char *buf, int toWrite, int *errCode);
37static int      tryAlternateSendTo(int sock, char *buf, int toWrite, int i,
38                        struct sockaddr *server);
39
40/*********************************** Code *************************************/
41/*
42 *      Write to a socket. Absorb as much data as the socket can buffer. Block if
43 *      the socket is in blocking mode. Returns -1 on error, otherwise the number
44 *      of bytes written.
45 */
46
47int     socketWrite(int sid, char *buf, int bufsize)
48{
49        socket_t        *sp;
50        ringq_t         *rq;
51        int                     len, bytesWritten, room;
52
53        a_assert(buf);
54        a_assert(bufsize >= 0);
55
56        if ((sp = socketPtr(sid)) == NULL) {
57                return -1;
58        }
59
60/*
61 *      Loop adding as much data to the output ringq as we can absorb. Initiate a
62 *      flush when the ringq is too full and continue. Block in socketFlush if the
63 *      socket is in blocking mode.
64 */
65        rq = &sp->outBuf;
66        for (bytesWritten = 0; bufsize > 0; ) {
67                if ((room = ringqPutBlkMax(rq)) == 0) {
68                        if (socketFlush(sid) < 0) {
69                                return -1;
70                        }
71                        if ((room = ringqPutBlkMax(rq)) == 0) {
72                                if (sp->flags & SOCKET_BLOCK) {
73#if WIN || CE
74                                        int             errCode;
75                                        if (! socketWaitForEvent(sp,  FD_WRITE | SOCKET_WRITABLE,
76                                                &errCode)) {
77                                                return -1;
78                                        }
79#endif
80                                        continue;
81                                }
82                                break;
83                        }
84                        continue;
85                }
86                len = min(room, bufsize);
87                ringqPutBlk(rq, (unsigned char *) buf, len);
88                bytesWritten += len;
89                bufsize -= len;
90                buf += len;
91        }
92        return bytesWritten;
93}
94
95/******************************************************************************/
96/*
97 *      Write a string to a socket
98 */
99
100int     socketWriteString(int sid, char_t *buf)
101{
102 #if UNICODE
103        char    *byteBuf;
104        int             r, len;
105 
106        len = gstrlen(buf);
107        byteBuf = ballocUniToAsc(buf, len);
108        r = socketWrite(sid, byteBuf, len);
109        bfreeSafe(B_L, byteBuf);
110        return r;
111 #else
112        return socketWrite(sid, buf, strlen(buf));
113 #endif /* UNICODE */
114}
115
116/******************************************************************************/
117/*
118 *      Read from a socket. Return the number of bytes read if successful. This
119 *      may be less than the requested "bufsize" and may be zero. Return -1 for
120 *      errors. Return 0 for EOF. Otherwise return the number of bytes read.
121 *      If this routine returns zero it indicates an EOF condition.
122 *  which can be verified with socketEof()
123 
124 *      Note: this ignores the line buffer, so a previous socketGets
125 *      which read a partial line may cause a subsequent socketRead to miss some
126 *      data. This routine may block if the socket is in blocking mode.
127 *
128 */
129
130int     socketRead(int sid, char *buf, int bufsize)
131{
132        socket_t        *sp;
133        ringq_t         *rq;
134        int                     len, room, errCode, bytesRead;
135
136        a_assert(buf);
137        a_assert(bufsize > 0);
138
139        if ((sp = socketPtr(sid)) == NULL) {
140                return -1;
141        }
142
143        if (sp->flags & SOCKET_EOF) {
144                return 0;
145        }
146
147        rq = &sp->inBuf;
148        for (bytesRead = 0; bufsize > 0; ) {
149                len = min(ringqLen(rq), bufsize);
150                if (len <= 0) {
151/*
152 *                      if blocking mode and already have data, exit now or it may block
153 *                      forever.
154 */
155                        if ((sp->flags & SOCKET_BLOCK) &&
156                                (bytesRead > 0)) {
157                                break;
158                        }
159/*
160 *                      This flush is critical for readers of datagram packets. If the
161 *                      buffer is not big enough to read the whole datagram in one hit,
162 *                      the recvfrom call will fail.
163 */
164                        ringqFlush(rq);
165                        room = ringqPutBlkMax(rq);
166                        len = socketGetInput(sid, (char *) rq->endp, room, &errCode);
167                        if (len < 0) {
168                                if (errCode == EWOULDBLOCK) {
169                                        if ((sp->flags & SOCKET_BLOCK) &&
170                                                (bytesRead ==  0)) {
171                                                continue;
172                                        }
173                                        if (bytesRead >= 0) {
174                                                return bytesRead;
175                                        }
176                                }
177                                return -1;
178
179                        } else if (len == 0) {
180/*
181 *                              If bytesRead is 0, this is EOF since socketRead should never
182 *                              be called unless there is data yet to be read.  Set the flag. 
183 *                              Then pass back the number of bytes read.
184 */
185                                if (bytesRead == 0) {
186                                        sp->flags |= SOCKET_EOF;
187                                }
188                                return bytesRead;
189                        }
190                        ringqPutBlkAdj(rq, len);
191                        len = min(len, bufsize);
192                }
193                memcpy(&buf[bytesRead], rq->servp, len);
194                ringqGetBlkAdj(rq, len);
195                bufsize -= len;
196                bytesRead += len;
197        }
198        return bytesRead;
199}
200
201/******************************************************************************/
202/*
203 *      Get a string from a socket. This returns data in *buf in a malloced string
204 *      after trimming the '\n'. If there is zero bytes returned, *buf will be set
205 *      to NULL. If doing non-blocking I/O, it returns -1 for error, EOF or when
206 *      no complete line yet read. If doing blocking I/O, it will block until an
207 *      entire line is read. If a partial line is read socketInputBuffered or
208 *      socketEof can be used to distinguish between EOF and partial line still
209 *      buffered. This routine eats and ignores carriage returns.
210 */
211
212int     socketGets(int sid, char_t **buf)
213{
214        socket_t        *sp;
215        ringq_t         *lq;
216        char            c;
217        int                     rc, len;
218
219        a_assert(buf);
220        *buf = NULL;
221
222        if ((sp = socketPtr(sid)) == NULL) {
223                return -1;
224        }
225        lq = &sp->lineBuf;
226
227        while (1) {
228
229                if ((rc = socketRead(sid, &c, 1)) < 0) {
230                        return rc;
231                }
232               
233                if (rc == 0) {
234/*
235 *                      If there is a partial line and we are at EOF, pretend we saw a '\n'
236 */
237                        if (ringqLen(lq) > 0 && (sp->flags & SOCKET_EOF)) {
238                                c = '\n';
239                        } else {
240                                return -1;
241                        }
242                }
243/*
244 *              If a newline is seen, return the data excluding the new line to the
245 *              caller. If carriage return is seen, just eat it.
246 */
247                if (c == '\n') {
248                        len = ringqLen(lq);
249                        if (len > 0) {
250                                *buf = ballocAscToUni(lq->servp, len);
251                        } else {
252                                *buf = NULL;
253                        }
254                        ringqFlush(lq);
255                        return len;
256
257                } else if (c == '\r') {
258                        continue;
259                }
260                ringqPutcA(lq, c);
261        }
262        return 0;
263}
264
265/******************************************************************************/
266/*
267 *      Flush the socket. Block if the socket is in blocking mode.
268 *      This will return -1 on errors and 0 if successful.
269 */
270
271int socketFlush(int sid)
272{
273        socket_t        *sp;
274        ringq_t         *rq;
275        int                     len, bytesWritten, errCode;
276
277        if ((sp = socketPtr(sid)) == NULL) {
278                return -1;
279        }
280        rq = &sp->outBuf;
281
282/*
283 *      Set the background flushing flag which socketEventProc will check to
284 *      continue the flush.
285 */
286        if (! (sp->flags & SOCKET_BLOCK)) {
287                sp->flags |= SOCKET_FLUSHING;
288        }
289
290/*
291 *      Break from loop if not blocking after initiating output. If we are blocking
292 *      we wait for a write event.
293 */
294        while (ringqLen(rq) > 0) {
295                len = ringqGetBlkMax(&sp->outBuf);
296                bytesWritten = socketDoOutput(sp, (char*) rq->servp, len, &errCode);
297                if (bytesWritten < 0) {
298                        if (errCode == EINTR) {
299                                continue;
300                        } else if (errCode == EWOULDBLOCK || errCode == EAGAIN) {
301#if WIN || CE
302                                if (sp->flags & SOCKET_BLOCK) {
303                                        int             errCode;
304                                        if (! socketWaitForEvent(sp,  FD_WRITE | SOCKET_WRITABLE,
305                                                &errCode)) {
306                                                return -1;
307                                        }
308                                        continue;
309                                }
310#endif
311/*
312 *                              Ensure we get a FD_WRITE message when the socket can absorb
313 *                              more data (non-blocking only.) Store the user's mask if we
314 *                              haven't done it already.
315 */
316                                if (sp->saveMask < 0 ) {
317                                        sp->saveMask = sp->handlerMask;
318                                        socketRegisterInterest(sp,
319                                        sp->handlerMask | SOCKET_WRITABLE);
320                                }
321                                return 0;
322                        }
323                        return -1;
324                }
325                ringqGetBlkAdj(rq, bytesWritten);
326        }
327/*
328 *      If the buffer is empty, reset the ringq pointers to point to the start
329 *      of the buffer. This is essential to ensure that datagrams get written
330 *      in one single I/O operation.
331 */
332        if (ringqLen(rq) == 0) {
333                ringqFlush(rq);
334        }
335/*
336 *      Restore the users mask if it was saved by the non-blocking code above.
337 *      Note: saveMask = -1 if empty. socketRegisterInterest will set handlerMask
338 */
339        if (sp->saveMask >= 0) {
340                socketRegisterInterest(sp, sp->saveMask);
341                sp->saveMask = -1;
342        }
343        sp->flags &= ~SOCKET_FLUSHING;
344        return 0;
345}
346
347/******************************************************************************/
348/*
349 *      Return the count of input characters buffered. We look at both the line
350 *      buffer and the input (raw) buffer. Return -1 on error or EOF.
351 */
352
353int socketInputBuffered(int sid)
354{
355        socket_t        *sp;
356
357        if ((sp = socketPtr(sid)) == NULL) {
358                return -1;
359        }
360        if (socketEof(sid)) {
361                return -1;
362        }
363        return ringqLen(&sp->lineBuf) + ringqLen(&sp->inBuf);
364}
365
366/******************************************************************************/
367/*
368 *      Return true if EOF
369 */
370
371int socketEof(int sid)
372{
373        socket_t        *sp;
374
375        if ((sp = socketPtr(sid)) == NULL) {
376                return -1;
377        }
378        return sp->flags & SOCKET_EOF;
379}
380
381/******************************************************************************/
382/*
383 *      Return the number of bytes the socket can absorb without blocking
384 */
385
386int socketCanWrite(int sid)
387{
388        socket_t        *sp;
389
390        if ((sp = socketPtr(sid)) == NULL) {
391                return -1;
392        }
393        return sp->outBuf.buflen - ringqLen(&sp->outBuf) - 1;
394}
395
396/******************************************************************************/
397/*
398 *      Add one to allow the user to write exactly SOCKET_BUFSIZ
399 */
400
401void socketSetBufferSize(int sid, int in, int line, int out)
402{
403        socket_t        *sp;
404
405        if ((sp = socketPtr(sid)) == NULL) {
406                return;
407        }
408
409        if (in >= 0) {
410                ringqClose(&sp->inBuf);
411                in++;
412                ringqOpen(&sp->inBuf, in, in);
413        }
414
415        if (line >= 0) {
416                ringqClose(&sp->lineBuf);
417                line++;
418                ringqOpen(&sp->lineBuf, line, line);
419        }
420
421        if (out >= 0) {
422                ringqClose(&sp->outBuf);
423                out++;
424                ringqOpen(&sp->outBuf, out, out);
425        }
426}
427
428/******************************************************************************/
429/*
430 *      Create a user handler for this socket. The handler called whenever there
431 *      is an event of interest as defined by handlerMask (SOCKET_READABLE, ...)
432 */
433
434void socketCreateHandler(int sid, int handlerMask, socketHandler_t handler,
435                int data)
436{
437        socket_t        *sp;
438
439        if ((sp = socketPtr(sid)) == NULL) {
440                return;
441        }
442        sp->handler = handler;
443        sp->handler_data = data;
444        socketRegisterInterest(sp, handlerMask);
445}
446
447/******************************************************************************/
448/*
449 *      Delete a handler
450 */
451
452void socketDeleteHandler(int sid)
453{
454        socket_t        *sp;
455
456        if ((sp = socketPtr(sid)) == NULL) {
457                return;
458        }
459        sp->handler = NULL;
460        socketRegisterInterest(sp, 0);
461}
462
463/******************************************************************************/
464/*
465 *      Socket output procedure. Return -1 on errors otherwise return the number
466 *      of bytes written.
467 */
468
469static int socketDoOutput(socket_t *sp, char *buf, int toWrite, int *errCode)
470{
471        struct sockaddr_in      server;
472        int                                     bytes;
473
474        a_assert(sp);
475        a_assert(buf);
476        a_assert(toWrite > 0);
477        a_assert(errCode);
478
479        *errCode = 0;
480
481#if WIN || CE
482        if ((sp->flags & SOCKET_ASYNC)
483                        && ! socketWaitForEvent(sp,  FD_CONNECT, errCode)) {
484                return -1;
485        }
486#endif
487
488/*
489 *      Write the data
490 */
491        if (sp->flags & SOCKET_BROADCAST) {
492                server.sin_family = AF_INET;
493#if UEMF || LITTLEFOOT
494                server.sin_addr.s_addr = INADDR_BROADCAST;
495#else
496                server.sin_addr.s_addr = inet_addr(basicGetBroadcastAddress());
497#endif
498                server.sin_port = htons((short)(sp->port & 0xFFFF));
499                if ((bytes = sendto(sp->sock, buf, toWrite, 0,
500                        (struct sockaddr *) &server, sizeof(server))) < 0) {
501                        bytes = tryAlternateSendTo(sp->sock, buf, toWrite, 0,
502                        (struct sockaddr *) &server);
503                }
504        } else if (sp->flags & SOCKET_DATAGRAM) {
505                server.sin_family = AF_INET;
506                server.sin_addr.s_addr = inet_addr(sp->host);
507                server.sin_port = htons((short)(sp->port & 0xFFFF));
508                bytes = sendto(sp->sock, buf, toWrite, 0,
509                        (struct sockaddr *) &server, sizeof(server));
510
511        } else {
512                bytes = send(sp->sock, buf, toWrite, 0);
513        }
514
515        if (bytes < 0) {
516                *errCode = socketGetError();
517#if WIN || CE
518                sp->currentEvents &= ~FD_WRITE;
519#endif
520
521                return -1;
522
523        } else if (bytes == 0 && bytes != toWrite) {
524                *errCode = EWOULDBLOCK;
525#if WIN || CE
526                sp->currentEvents &= ~FD_WRITE;
527#endif
528                return -1;
529        }
530
531/*
532 *      Ensure we get to write some more data real soon if the socket can absorb
533 *      more data
534 */
535#if !UEMF
536#if WIN
537        if (sp->interestEvents & FD_WRITE) {
538                emfTime_t blockTime = { 0, 0 };
539                emfSetMaxBlockTime(&blockTime);
540        }
541#endif /* WIN */
542#endif
543        return bytes;
544}
545
546/******************************************************************************/
547/*
548 *              If the sendto failed, swap the first two bytes in the
549 *              sockaddr structure.  This is a kludge due to a change in
550 *              VxWorks between versions 5.3 and 5.4, but we want the
551 *              product to run on either.
552 */
553static int tryAlternateSendTo(int sock, char *buf, int toWrite, int i,
554                        struct sockaddr *server)
555{
556#if VXWORKS
557        char *ptr;
558
559        ptr = (char *)server;
560        *ptr = *(ptr+1);
561        *(ptr+1) = 0;
562        return sendto(sock, buf, toWrite, i, server, sizeof(struct sockaddr));
563#else
564        return -1;
565#endif /* VXWORKS */
566}
567
568/******************************************************************************/
569/*
570 *      Allocate a new socket structure
571 */
572
573int socketAlloc(char *host, int port, socketAccept_t accept, int flags)
574{
575        socket_t        *sp;
576        int                     sid;
577
578        if ((sid = hAllocEntry((void***) &socketList, &socketMax,
579                        sizeof(socket_t))) < 0) {
580                return -1;
581        }
582        sp = socketList[sid];
583
584        sp->sid = sid;
585        sp->accept = accept;
586        sp->port = port;
587        sp->fileHandle = -1;
588        sp->saveMask = -1;
589
590        if (host) {
591                strncpy(sp->host, host, sizeof(sp->host));
592        }
593
594/*
595 *      Preserve only specified flags from the callers open
596 */
597        a_assert((flags & ~(SOCKET_BROADCAST|SOCKET_DATAGRAM|SOCKET_BLOCK|
598                                                SOCKET_LISTENING)) == 0);
599        sp->flags = flags & (SOCKET_BROADCAST | SOCKET_DATAGRAM | SOCKET_BLOCK|
600                                                SOCKET_LISTENING);
601
602/*
603 *      Add one to allow the user to write exactly SOCKET_BUFSIZ
604 */
605        ringqOpen(&sp->inBuf, SOCKET_BUFSIZ, SOCKET_BUFSIZ);
606        ringqOpen(&sp->outBuf, SOCKET_BUFSIZ + 1, SOCKET_BUFSIZ + 1);
607        ringqOpen(&sp->lineBuf, SOCKET_BUFSIZ, -1);
608
609        return sid;
610}
611
612/******************************************************************************/
613/*
614 *      Free a socket structure
615 */
616
617void socketFree(int sid)
618{
619        socket_t        *sp;
620        char_t          buf[256];
621        int                     i;
622
623        if ((sp = socketPtr(sid)) == NULL) {
624                return;
625        }
626
627/*
628 *      To close a socket, remove any registered interests, set it to
629 *      non-blocking so that the recv which follows won't block, do a
630 *      shutdown on it so peers on the other end will receive a FIN,
631 *      then read any data not yet retrieved from the receive buffer,
632 *      and finally close it.  If these steps are not all performed
633 *      RESETs may be sent to the other end causing problems.
634 */
635        socketRegisterInterest(sp, 0);
636        if (sp->sock >= 0) {
637                socketSetBlock(sid, 0);
638                if (shutdown(sp->sock, 1) >= 0) {
639                        recv(sp->sock, buf, sizeof(buf), 0);
640                }
641#if WIN || CE
642                closesocket(sp->sock);
643#else
644                close(sp->sock);
645#endif
646        }
647
648        ringqClose(&sp->inBuf);
649        ringqClose(&sp->outBuf);
650        ringqClose(&sp->lineBuf);
651
652        bfree(B_L, sp);
653        socketMax = hFree((void***) &socketList, sid);
654
655/*
656 *      Calculate the new highest socket number
657 */
658        socketHighestFd = -1;
659        for (i = 0; i < socketMax; i++) {
660                if ((sp = socketList[i]) == NULL) {
661                        continue;
662                }
663                socketHighestFd = max(socketHighestFd, sp->sock);
664        }
665}
666
667/******************************************************************************/
668/*
669 *      Validate a socket handle
670 */
671
672socket_t *socketPtr(int sid)
673{
674        if (sid < 0 || sid >= socketMax || socketList[sid] == NULL) {
675                a_assert(NULL);
676                errno = EBADF;
677                return NULL;
678        }
679
680        a_assert(socketList[sid]);
681        return socketList[sid];
682}
683
684/******************************************************************************/
685/*
686 *      Get the operating system error code
687 */
688
689int socketGetError()
690{
691#if WIN || CE
692        switch (WSAGetLastError()) {
693        case WSAEWOULDBLOCK:
694                return EWOULDBLOCK;
695        case WSAECONNRESET:
696                return ECONNRESET;
697        case WSAENETDOWN:
698                return ENETDOWN;
699        case WSAEPROCLIM:
700                return EAGAIN;
701        case WSAEINTR:
702                return EINTR;
703        default:
704                return EINVAL;
705        }
706#else
707        return errno;
708#endif
709}
710
711/******************************************************************************/
712/*
713 *      Return the underlying socket handle
714 */
715
716int socketGetHandle(int sid)
717{
718        socket_t        *sp;
719
720        if ((sp = socketPtr(sid)) == NULL) {
721                return -1;
722        }
723        return sp->sock;
724}
725
726/******************************************************************************/
727/*
728 *      Get blocking mode
729 */
730
731int socketGetBlock(int sid)
732{
733        socket_t        *sp;
734
735        if ((sp = socketPtr(sid)) == NULL) {
736                a_assert(0);
737                return 0;
738        }
739        return (sp->flags & SOCKET_BLOCK);
740}
741
742/******************************************************************************/
743/*
744 *      Get mode
745 */
746
747int socketGetMode(int sid)
748{
749        socket_t        *sp;
750
751        if ((sp = socketPtr(sid)) == NULL) {
752                a_assert(0);
753                return 0;
754        }
755        return sp->flags;
756}
757
758/******************************************************************************/
759/*
760 *      Set mode
761 */
762
763void socketSetMode(int sid, int mode)
764{
765        socket_t        *sp;
766
767        if ((sp = socketPtr(sid)) == NULL) {
768                a_assert(0);
769                return;
770        }
771        sp->flags = mode;
772}
773
774/******************************************************************************/
775/*
776 *      Get port.
777 */
778
779int socketGetPort(int sid)
780{
781        socket_t        *sp;
782
783        if ((sp = socketPtr(sid)) == NULL) {
784                return -1;
785        }
786        return sp->port;
787}
788
789/******************************************************************************/
Note: See TracBrowser for help on using the repository browser.