summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--c/src/libnetworking/rtems_webserver/sock.c789
-rw-r--r--cpukit/httpd/sock.c789
2 files changed, 1578 insertions, 0 deletions
diff --git a/c/src/libnetworking/rtems_webserver/sock.c b/c/src/libnetworking/rtems_webserver/sock.c
new file mode 100644
index 0000000000..f23a63984f
--- /dev/null
+++ b/c/src/libnetworking/rtems_webserver/sock.c
@@ -0,0 +1,789 @@
+/*
+ * sock.c -- Posix Socket upper layer support module for general posix use
+ *
+ * Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved.
+ */
+
+/******************************** Description *********************************/
+
+/*
+ * Posix Socket Module. This supports blocking and non-blocking buffered
+ * socket I/O.
+ */
+
+/********************************** Includes **********************************/
+
+#include <string.h>
+#include <stdlib.h>
+
+#if UEMF
+ #include "uemf.h"
+#else
+ #include <socket.h>
+ #include <types.h>
+ #include <unistd.h>
+ #include "emfInternal.h"
+#endif
+
+/************************************ Locals **********************************/
+
+socket_t **socketList; /* List of open sockets */
+int socketMax; /* Maximum size of socket */
+int socketHighestFd = -1; /* Highest socket fd opened */
+
+/***************************** Forward Declarations ***************************/
+
+static int socketDoOutput(socket_t *sp, char *buf, int toWrite, int *errCode);
+static int tryAlternateSendTo(int sock, char *buf, int toWrite, int i,
+ struct sockaddr *server);
+
+/*********************************** Code *************************************/
+/*
+ * Write to a socket. Absorb as much data as the socket can buffer. Block if
+ * the socket is in blocking mode. Returns -1 on error, otherwise the number
+ * of bytes written.
+ */
+
+int socketWrite(int sid, char *buf, int bufsize)
+{
+ socket_t *sp;
+ ringq_t *rq;
+ int len, bytesWritten, room;
+
+ a_assert(buf);
+ a_assert(bufsize >= 0);
+
+ if ((sp = socketPtr(sid)) == NULL) {
+ return -1;
+ }
+
+/*
+ * Loop adding as much data to the output ringq as we can absorb. Initiate a
+ * flush when the ringq is too full and continue. Block in socketFlush if the
+ * socket is in blocking mode.
+ */
+ rq = &sp->outBuf;
+ for (bytesWritten = 0; bufsize > 0; ) {
+ if ((room = ringqPutBlkMax(rq)) == 0) {
+ if (socketFlush(sid) < 0) {
+ return -1;
+ }
+ if ((room = ringqPutBlkMax(rq)) == 0) {
+ if (sp->flags & SOCKET_BLOCK) {
+#if WIN || CE
+ int errCode;
+ if (! socketWaitForEvent(sp, FD_WRITE | SOCKET_WRITABLE,
+ &errCode)) {
+ return -1;
+ }
+#endif
+ continue;
+ }
+ break;
+ }
+ continue;
+ }
+ len = min(room, bufsize);
+ ringqPutBlk(rq, (unsigned char *) buf, len);
+ bytesWritten += len;
+ bufsize -= len;
+ buf += len;
+ }
+ return bytesWritten;
+}
+
+/******************************************************************************/
+/*
+ * Write a string to a socket
+ */
+
+int socketWriteString(int sid, char_t *buf)
+{
+ #if UNICODE
+ char *byteBuf;
+ int r, len;
+
+ len = gstrlen(buf);
+ byteBuf = ballocUniToAsc(buf, len);
+ r = socketWrite(sid, byteBuf, len);
+ bfreeSafe(B_L, byteBuf);
+ return r;
+ #else
+ return socketWrite(sid, buf, strlen(buf));
+ #endif /* UNICODE */
+}
+
+/******************************************************************************/
+/*
+ * Read from a socket. Return the number of bytes read if successful. This
+ * may be less than the requested "bufsize" and may be zero. Return -1 for
+ * errors. Return 0 for EOF. Otherwise return the number of bytes read.
+ * If this routine returns zero it indicates an EOF condition.
+ * which can be verified with socketEof()
+
+ * Note: this ignores the line buffer, so a previous socketGets
+ * which read a partial line may cause a subsequent socketRead to miss some
+ * data. This routine may block if the socket is in blocking mode.
+ *
+ */
+
+int socketRead(int sid, char *buf, int bufsize)
+{
+ socket_t *sp;
+ ringq_t *rq;
+ int len, room, errCode, bytesRead;
+
+ a_assert(buf);
+ a_assert(bufsize > 0);
+
+ if ((sp = socketPtr(sid)) == NULL) {
+ return -1;
+ }
+
+ if (sp->flags & SOCKET_EOF) {
+ return 0;
+ }
+
+ rq = &sp->inBuf;
+ for (bytesRead = 0; bufsize > 0; ) {
+ len = min(ringqLen(rq), bufsize);
+ if (len <= 0) {
+/*
+ * if blocking mode and already have data, exit now or it may block
+ * forever.
+ */
+ if ((sp->flags & SOCKET_BLOCK) &&
+ (bytesRead > 0)) {
+ break;
+ }
+/*
+ * This flush is critical for readers of datagram packets. If the
+ * buffer is not big enough to read the whole datagram in one hit,
+ * the recvfrom call will fail.
+ */
+ ringqFlush(rq);
+ room = ringqPutBlkMax(rq);
+ len = socketGetInput(sid, (char *) rq->endp, room, &errCode);
+ if (len < 0) {
+ if (errCode == EWOULDBLOCK) {
+ if ((sp->flags & SOCKET_BLOCK) &&
+ (bytesRead == 0)) {
+ continue;
+ }
+ if (bytesRead >= 0) {
+ return bytesRead;
+ }
+ }
+ return -1;
+
+ } else if (len == 0) {
+/*
+ * If bytesRead is 0, this is EOF since socketRead should never
+ * be called unless there is data yet to be read. Set the flag.
+ * Then pass back the number of bytes read.
+ */
+ if (bytesRead == 0) {
+ sp->flags |= SOCKET_EOF;
+ }
+ return bytesRead;
+ }
+ ringqPutBlkAdj(rq, len);
+ len = min(len, bufsize);
+ }
+ memcpy(&buf[bytesRead], rq->servp, len);
+ ringqGetBlkAdj(rq, len);
+ bufsize -= len;
+ bytesRead += len;
+ }
+ return bytesRead;
+}
+
+/******************************************************************************/
+/*
+ * Get a string from a socket. This returns data in *buf in a malloced string
+ * after trimming the '\n'. If there is zero bytes returned, *buf will be set
+ * to NULL. If doing non-blocking I/O, it returns -1 for error, EOF or when
+ * no complete line yet read. If doing blocking I/O, it will block until an
+ * entire line is read. If a partial line is read socketInputBuffered or
+ * socketEof can be used to distinguish between EOF and partial line still
+ * buffered. This routine eats and ignores carriage returns.
+ */
+
+int socketGets(int sid, char_t **buf)
+{
+ socket_t *sp;
+ ringq_t *lq;
+ char c;
+ int rc, len;
+
+ a_assert(buf);
+ *buf = NULL;
+
+ if ((sp = socketPtr(sid)) == NULL) {
+ return -1;
+ }
+ lq = &sp->lineBuf;
+
+ while (1) {
+
+ if ((rc = socketRead(sid, &c, 1)) < 0) {
+ return rc;
+ }
+
+ if (rc == 0) {
+/*
+ * If there is a partial line and we are at EOF, pretend we saw a '\n'
+ */
+ if (ringqLen(lq) > 0 && (sp->flags & SOCKET_EOF)) {
+ c = '\n';
+ } else {
+ return -1;
+ }
+ }
+/*
+ * If a newline is seen, return the data excluding the new line to the
+ * caller. If carriage return is seen, just eat it.
+ */
+ if (c == '\n') {
+ len = ringqLen(lq);
+ if (len > 0) {
+ *buf = ballocAscToUni(lq->servp, len);
+ } else {
+ *buf = NULL;
+ }
+ ringqFlush(lq);
+ return len;
+
+ } else if (c == '\r') {
+ continue;
+ }
+ ringqPutcA(lq, c);
+ }
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Flush the socket. Block if the socket is in blocking mode.
+ * This will return -1 on errors and 0 if successful.
+ */
+
+int socketFlush(int sid)
+{
+ socket_t *sp;
+ ringq_t *rq;
+ int len, bytesWritten, errCode;
+
+ if ((sp = socketPtr(sid)) == NULL) {
+ return -1;
+ }
+ rq = &sp->outBuf;
+
+/*
+ * Set the background flushing flag which socketEventProc will check to
+ * continue the flush.
+ */
+ if (! (sp->flags & SOCKET_BLOCK)) {
+ sp->flags |= SOCKET_FLUSHING;
+ }
+
+/*
+ * Break from loop if not blocking after initiating output. If we are blocking
+ * we wait for a write event.
+ */
+ while (ringqLen(rq) > 0) {
+ len = ringqGetBlkMax(&sp->outBuf);
+ bytesWritten = socketDoOutput(sp, (char*) rq->servp, len, &errCode);
+ if (bytesWritten < 0) {
+ if (errCode == EINTR) {
+ continue;
+ } else if (errCode == EWOULDBLOCK || errCode == EAGAIN) {
+#if WIN || CE
+ if (sp->flags & SOCKET_BLOCK) {
+ int errCode;
+ if (! socketWaitForEvent(sp, FD_WRITE | SOCKET_WRITABLE,
+ &errCode)) {
+ return -1;
+ }
+ continue;
+ }
+#endif
+/*
+ * Ensure we get a FD_WRITE message when the socket can absorb
+ * more data (non-blocking only.) Store the user's mask if we
+ * haven't done it already.
+ */
+ if (sp->saveMask < 0 ) {
+ sp->saveMask = sp->handlerMask;
+ socketRegisterInterest(sp,
+ sp->handlerMask | SOCKET_WRITABLE);
+ }
+ return 0;
+ }
+ return -1;
+ }
+ ringqGetBlkAdj(rq, bytesWritten);
+ }
+/*
+ * If the buffer is empty, reset the ringq pointers to point to the start
+ * of the buffer. This is essential to ensure that datagrams get written
+ * in one single I/O operation.
+ */
+ if (ringqLen(rq) == 0) {
+ ringqFlush(rq);
+ }
+/*
+ * Restore the users mask if it was saved by the non-blocking code above.
+ * Note: saveMask = -1 if empty. socketRegisterInterest will set handlerMask
+ */
+ if (sp->saveMask >= 0) {
+ socketRegisterInterest(sp, sp->saveMask);
+ sp->saveMask = -1;
+ }
+ sp->flags &= ~SOCKET_FLUSHING;
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Return the count of input characters buffered. We look at both the line
+ * buffer and the input (raw) buffer. Return -1 on error or EOF.
+ */
+
+int socketInputBuffered(int sid)
+{
+ socket_t *sp;
+
+ if ((sp = socketPtr(sid)) == NULL) {
+ return -1;
+ }
+ if (socketEof(sid)) {
+ return -1;
+ }
+ return ringqLen(&sp->lineBuf) + ringqLen(&sp->inBuf);
+}
+
+/******************************************************************************/
+/*
+ * Return true if EOF
+ */
+
+int socketEof(int sid)
+{
+ socket_t *sp;
+
+ if ((sp = socketPtr(sid)) == NULL) {
+ return -1;
+ }
+ return sp->flags & SOCKET_EOF;
+}
+
+/******************************************************************************/
+/*
+ * Return the number of bytes the socket can absorb without blocking
+ */
+
+int socketCanWrite(int sid)
+{
+ socket_t *sp;
+
+ if ((sp = socketPtr(sid)) == NULL) {
+ return -1;
+ }
+ return sp->outBuf.buflen - ringqLen(&sp->outBuf) - 1;
+}
+
+/******************************************************************************/
+/*
+ * Add one to allow the user to write exactly SOCKET_BUFSIZ
+ */
+
+void socketSetBufferSize(int sid, int in, int line, int out)
+{
+ socket_t *sp;
+
+ if ((sp = socketPtr(sid)) == NULL) {
+ return;
+ }
+
+ if (in >= 0) {
+ ringqClose(&sp->inBuf);
+ in++;
+ ringqOpen(&sp->inBuf, in, in);
+ }
+
+ if (line >= 0) {
+ ringqClose(&sp->lineBuf);
+ line++;
+ ringqOpen(&sp->lineBuf, line, line);
+ }
+
+ if (out >= 0) {
+ ringqClose(&sp->outBuf);
+ out++;
+ ringqOpen(&sp->outBuf, out, out);
+ }
+}
+
+/******************************************************************************/
+/*
+ * Create a user handler for this socket. The handler called whenever there
+ * is an event of interest as defined by handlerMask (SOCKET_READABLE, ...)
+ */
+
+void socketCreateHandler(int sid, int handlerMask, socketHandler_t handler,
+ int data)
+{
+ socket_t *sp;
+
+ if ((sp = socketPtr(sid)) == NULL) {
+ return;
+ }
+ sp->handler = handler;
+ sp->handler_data = data;
+ socketRegisterInterest(sp, handlerMask);
+}
+
+/******************************************************************************/
+/*
+ * Delete a handler
+ */
+
+void socketDeleteHandler(int sid)
+{
+ socket_t *sp;
+
+ if ((sp = socketPtr(sid)) == NULL) {
+ return;
+ }
+ sp->handler = NULL;
+ socketRegisterInterest(sp, 0);
+}
+
+/******************************************************************************/
+/*
+ * Socket output procedure. Return -1 on errors otherwise return the number
+ * of bytes written.
+ */
+
+static int socketDoOutput(socket_t *sp, char *buf, int toWrite, int *errCode)
+{
+ struct sockaddr_in server;
+ int bytes;
+
+ a_assert(sp);
+ a_assert(buf);
+ a_assert(toWrite > 0);
+ a_assert(errCode);
+
+ *errCode = 0;
+
+#if WIN || CE
+ if ((sp->flags & SOCKET_ASYNC)
+ && ! socketWaitForEvent(sp, FD_CONNECT, errCode)) {
+ return -1;
+ }
+#endif
+
+/*
+ * Write the data
+ */
+ if (sp->flags & SOCKET_BROADCAST) {
+ server.sin_family = AF_INET;
+#if UEMF || LITTLEFOOT
+ server.sin_addr.s_addr = INADDR_BROADCAST;
+#else
+ server.sin_addr.s_addr = inet_addr(basicGetBroadcastAddress());
+#endif
+ server.sin_port = htons((short)(sp->port & 0xFFFF));
+ if ((bytes = sendto(sp->sock, buf, toWrite, 0,
+ (struct sockaddr *) &server, sizeof(server))) < 0) {
+ bytes = tryAlternateSendTo(sp->sock, buf, toWrite, 0,
+ (struct sockaddr *) &server);
+ }
+ } else if (sp->flags & SOCKET_DATAGRAM) {
+ server.sin_family = AF_INET;
+ server.sin_addr.s_addr = inet_addr(sp->host);
+ server.sin_port = htons((short)(sp->port & 0xFFFF));
+ bytes = sendto(sp->sock, buf, toWrite, 0,
+ (struct sockaddr *) &server, sizeof(server));
+
+ } else {
+ bytes = send(sp->sock, buf, toWrite, 0);
+ }
+
+ if (bytes < 0) {
+ *errCode = socketGetError();
+#if WIN || CE
+ sp->currentEvents &= ~FD_WRITE;
+#endif
+
+ return -1;
+
+ } else if (bytes == 0 && bytes != toWrite) {
+ *errCode = EWOULDBLOCK;
+#if WIN || CE
+ sp->currentEvents &= ~FD_WRITE;
+#endif
+ return -1;
+ }
+
+/*
+ * Ensure we get to write some more data real soon if the socket can absorb
+ * more data
+ */
+#if !UEMF
+#if WIN
+ if (sp->interestEvents & FD_WRITE) {
+ emfTime_t blockTime = { 0, 0 };
+ emfSetMaxBlockTime(&blockTime);
+ }
+#endif /* WIN */
+#endif
+ return bytes;
+}
+
+/******************************************************************************/
+/*
+ * If the sendto failed, swap the first two bytes in the
+ * sockaddr structure. This is a kludge due to a change in
+ * VxWorks between versions 5.3 and 5.4, but we want the
+ * product to run on either.
+ */
+static int tryAlternateSendTo(int sock, char *buf, int toWrite, int i,
+ struct sockaddr *server)
+{
+#if VXWORKS
+ char *ptr;
+
+ ptr = (char *)server;
+ *ptr = *(ptr+1);
+ *(ptr+1) = 0;
+ return sendto(sock, buf, toWrite, i, server, sizeof(struct sockaddr));
+#else
+ return -1;
+#endif /* VXWORKS */
+}
+
+/******************************************************************************/
+/*
+ * Allocate a new socket structure
+ */
+
+int socketAlloc(char *host, int port, socketAccept_t accept, int flags)
+{
+ socket_t *sp;
+ int sid;
+
+ if ((sid = hAllocEntry((void***) &socketList, &socketMax,
+ sizeof(socket_t))) < 0) {
+ return -1;
+ }
+ sp = socketList[sid];
+
+ sp->sid = sid;
+ sp->accept = accept;
+ sp->port = port;
+ sp->fileHandle = -1;
+ sp->saveMask = -1;
+
+ if (host) {
+ strncpy(sp->host, host, sizeof(sp->host));
+ }
+
+/*
+ * Preserve only specified flags from the callers open
+ */
+ a_assert((flags & ~(SOCKET_BROADCAST|SOCKET_DATAGRAM|SOCKET_BLOCK|
+ SOCKET_LISTENING)) == 0);
+ sp->flags = flags & (SOCKET_BROADCAST | SOCKET_DATAGRAM | SOCKET_BLOCK|
+ SOCKET_LISTENING);
+
+/*
+ * Add one to allow the user to write exactly SOCKET_BUFSIZ
+ */
+ ringqOpen(&sp->inBuf, SOCKET_BUFSIZ, SOCKET_BUFSIZ);
+ ringqOpen(&sp->outBuf, SOCKET_BUFSIZ + 1, SOCKET_BUFSIZ + 1);
+ ringqOpen(&sp->lineBuf, SOCKET_BUFSIZ, -1);
+
+ return sid;
+}
+
+/******************************************************************************/
+/*
+ * Free a socket structure
+ */
+
+void socketFree(int sid)
+{
+ socket_t *sp;
+ char_t buf[256];
+ int i;
+
+ if ((sp = socketPtr(sid)) == NULL) {
+ return;
+ }
+
+/*
+ * To close a socket, remove any registered interests, set it to
+ * non-blocking so that the recv which follows won't block, do a
+ * shutdown on it so peers on the other end will receive a FIN,
+ * then read any data not yet retrieved from the receive buffer,
+ * and finally close it. If these steps are not all performed
+ * RESETs may be sent to the other end causing problems.
+ */
+ socketRegisterInterest(sp, 0);
+ if (sp->sock >= 0) {
+ socketSetBlock(sid, 0);
+ if (shutdown(sp->sock, 1) >= 0) {
+ recv(sp->sock, buf, sizeof(buf), 0);
+ }
+#if WIN || CE
+ closesocket(sp->sock);
+#else
+ close(sp->sock);
+#endif
+ }
+
+ ringqClose(&sp->inBuf);
+ ringqClose(&sp->outBuf);
+ ringqClose(&sp->lineBuf);
+
+ bfree(B_L, sp);
+ socketMax = hFree((void***) &socketList, sid);
+
+/*
+ * Calculate the new highest socket number
+ */
+ socketHighestFd = -1;
+ for (i = 0; i < socketMax; i++) {
+ if ((sp = socketList[i]) == NULL) {
+ continue;
+ }
+ socketHighestFd = max(socketHighestFd, sp->sock);
+ }
+}
+
+/******************************************************************************/
+/*
+ * Validate a socket handle
+ */
+
+socket_t *socketPtr(int sid)
+{
+ if (sid < 0 || sid >= socketMax || socketList[sid] == NULL) {
+ a_assert(NULL);
+ errno = EBADF;
+ return NULL;
+ }
+
+ a_assert(socketList[sid]);
+ return socketList[sid];
+}
+
+/******************************************************************************/
+/*
+ * Get the operating system error code
+ */
+
+int socketGetError()
+{
+#if WIN || CE
+ switch (WSAGetLastError()) {
+ case WSAEWOULDBLOCK:
+ return EWOULDBLOCK;
+ case WSAECONNRESET:
+ return ECONNRESET;
+ case WSAENETDOWN:
+ return ENETDOWN;
+ case WSAEPROCLIM:
+ return EAGAIN;
+ case WSAEINTR:
+ return EINTR;
+ default:
+ return EINVAL;
+ }
+#else
+ return errno;
+#endif
+}
+
+/******************************************************************************/
+/*
+ * Return the underlying socket handle
+ */
+
+int socketGetHandle(int sid)
+{
+ socket_t *sp;
+
+ if ((sp = socketPtr(sid)) == NULL) {
+ return -1;
+ }
+ return sp->sock;
+}
+
+/******************************************************************************/
+/*
+ * Get blocking mode
+ */
+
+int socketGetBlock(int sid)
+{
+ socket_t *sp;
+
+ if ((sp = socketPtr(sid)) == NULL) {
+ a_assert(0);
+ return 0;
+ }
+ return (sp->flags & SOCKET_BLOCK);
+}
+
+/******************************************************************************/
+/*
+ * Get mode
+ */
+
+int socketGetMode(int sid)
+{
+ socket_t *sp;
+
+ if ((sp = socketPtr(sid)) == NULL) {
+ a_assert(0);
+ return 0;
+ }
+ return sp->flags;
+}
+
+/******************************************************************************/
+/*
+ * Set mode
+ */
+
+void socketSetMode(int sid, int mode)
+{
+ socket_t *sp;
+
+ if ((sp = socketPtr(sid)) == NULL) {
+ a_assert(0);
+ return;
+ }
+ sp->flags = mode;
+}
+
+/******************************************************************************/
+/*
+ * Get port.
+ */
+
+int socketGetPort(int sid)
+{
+ socket_t *sp;
+
+ if ((sp = socketPtr(sid)) == NULL) {
+ return -1;
+ }
+ return sp->port;
+}
+
+/******************************************************************************/
diff --git a/cpukit/httpd/sock.c b/cpukit/httpd/sock.c
new file mode 100644
index 0000000000..f23a63984f
--- /dev/null
+++ b/cpukit/httpd/sock.c
@@ -0,0 +1,789 @@
+/*
+ * sock.c -- Posix Socket upper layer support module for general posix use
+ *
+ * Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved.
+ */
+
+/******************************** Description *********************************/
+
+/*
+ * Posix Socket Module. This supports blocking and non-blocking buffered
+ * socket I/O.
+ */
+
+/********************************** Includes **********************************/
+
+#include <string.h>
+#include <stdlib.h>
+
+#if UEMF
+ #include "uemf.h"
+#else
+ #include <socket.h>
+ #include <types.h>
+ #include <unistd.h>
+ #include "emfInternal.h"
+#endif
+
+/************************************ Locals **********************************/
+
+socket_t **socketList; /* List of open sockets */
+int socketMax; /* Maximum size of socket */
+int socketHighestFd = -1; /* Highest socket fd opened */
+
+/***************************** Forward Declarations ***************************/
+
+static int socketDoOutput(socket_t *sp, char *buf, int toWrite, int *errCode);
+static int tryAlternateSendTo(int sock, char *buf, int toWrite, int i,
+ struct sockaddr *server);
+
+/*********************************** Code *************************************/
+/*
+ * Write to a socket. Absorb as much data as the socket can buffer. Block if
+ * the socket is in blocking mode. Returns -1 on error, otherwise the number
+ * of bytes written.
+ */
+
+int socketWrite(int sid, char *buf, int bufsize)
+{
+ socket_t *sp;
+ ringq_t *rq;
+ int len, bytesWritten, room;
+
+ a_assert(buf);
+ a_assert(bufsize >= 0);
+
+ if ((sp = socketPtr(sid)) == NULL) {
+ return -1;
+ }
+
+/*
+ * Loop adding as much data to the output ringq as we can absorb. Initiate a
+ * flush when the ringq is too full and continue. Block in socketFlush if the
+ * socket is in blocking mode.
+ */
+ rq = &sp->outBuf;
+ for (bytesWritten = 0; bufsize > 0; ) {
+ if ((room = ringqPutBlkMax(rq)) == 0) {
+ if (socketFlush(sid) < 0) {
+ return -1;
+ }
+ if ((room = ringqPutBlkMax(rq)) == 0) {
+ if (sp->flags & SOCKET_BLOCK) {
+#if WIN || CE
+ int errCode;
+ if (! socketWaitForEvent(sp, FD_WRITE | SOCKET_WRITABLE,
+ &errCode)) {
+ return -1;
+ }
+#endif
+ continue;
+ }
+ break;
+ }
+ continue;
+ }
+ len = min(room, bufsize);
+ ringqPutBlk(rq, (unsigned char *) buf, len);
+ bytesWritten += len;
+ bufsize -= len;
+ buf += len;
+ }
+ return bytesWritten;
+}
+
+/******************************************************************************/
+/*
+ * Write a string to a socket
+ */
+
+int socketWriteString(int sid, char_t *buf)
+{
+ #if UNICODE
+ char *byteBuf;
+ int r, len;
+
+ len = gstrlen(buf);
+ byteBuf = ballocUniToAsc(buf, len);
+ r = socketWrite(sid, byteBuf, len);
+ bfreeSafe(B_L, byteBuf);
+ return r;
+ #else
+ return socketWrite(sid, buf, strlen(buf));
+ #endif /* UNICODE */
+}
+
+/******************************************************************************/
+/*
+ * Read from a socket. Return the number of bytes read if successful. This
+ * may be less than the requested "bufsize" and may be zero. Return -1 for
+ * errors. Return 0 for EOF. Otherwise return the number of bytes read.
+ * If this routine returns zero it indicates an EOF condition.
+ * which can be verified with socketEof()
+
+ * Note: this ignores the line buffer, so a previous socketGets
+ * which read a partial line may cause a subsequent socketRead to miss some
+ * data. This routine may block if the socket is in blocking mode.
+ *
+ */
+
+int socketRead(int sid, char *buf, int bufsize)
+{
+ socket_t *sp;
+ ringq_t *rq;
+ int len, room, errCode, bytesRead;
+
+ a_assert(buf);
+ a_assert(bufsize > 0);
+
+ if ((sp = socketPtr(sid)) == NULL) {
+ return -1;
+ }
+
+ if (sp->flags & SOCKET_EOF) {
+ return 0;
+ }
+
+ rq = &sp->inBuf;
+ for (bytesRead = 0; bufsize > 0; ) {
+ len = min(ringqLen(rq), bufsize);
+ if (len <= 0) {
+/*
+ * if blocking mode and already have data, exit now or it may block
+ * forever.
+ */
+ if ((sp->flags & SOCKET_BLOCK) &&
+ (bytesRead > 0)) {
+ break;
+ }
+/*
+ * This flush is critical for readers of datagram packets. If the
+ * buffer is not big enough to read the whole datagram in one hit,
+ * the recvfrom call will fail.
+ */
+ ringqFlush(rq);
+ room = ringqPutBlkMax(rq);
+ len = socketGetInput(sid, (char *) rq->endp, room, &errCode);
+ if (len < 0) {
+ if (errCode == EWOULDBLOCK) {
+ if ((sp->flags & SOCKET_BLOCK) &&
+ (bytesRead == 0)) {
+ continue;
+ }
+ if (bytesRead >= 0) {
+ return bytesRead;
+ }
+ }
+ return -1;
+
+ } else if (len == 0) {
+/*
+ * If bytesRead is 0, this is EOF since socketRead should never
+ * be called unless there is data yet to be read. Set the flag.
+ * Then pass back the number of bytes read.
+ */
+ if (bytesRead == 0) {
+ sp->flags |= SOCKET_EOF;
+ }
+ return bytesRead;
+ }
+ ringqPutBlkAdj(rq, len);
+ len = min(len, bufsize);
+ }
+ memcpy(&buf[bytesRead], rq->servp, len);
+ ringqGetBlkAdj(rq, len);
+ bufsize -= len;
+ bytesRead += len;
+ }
+ return bytesRead;
+}
+
+/******************************************************************************/
+/*
+ * Get a string from a socket. This returns data in *buf in a malloced string
+ * after trimming the '\n'. If there is zero bytes returned, *buf will be set
+ * to NULL. If doing non-blocking I/O, it returns -1 for error, EOF or when
+ * no complete line yet read. If doing blocking I/O, it will block until an
+ * entire line is read. If a partial line is read socketInputBuffered or
+ * socketEof can be used to distinguish between EOF and partial line still
+ * buffered. This routine eats and ignores carriage returns.
+ */
+
+int socketGets(int sid, char_t **buf)
+{
+ socket_t *sp;
+ ringq_t *lq;
+ char c;
+ int rc, len;
+
+ a_assert(buf);
+ *buf = NULL;
+
+ if ((sp = socketPtr(sid)) == NULL) {
+ return -1;
+ }
+ lq = &sp->lineBuf;
+
+ while (1) {
+
+ if ((rc = socketRead(sid, &c, 1)) < 0) {
+ return rc;
+ }
+
+ if (rc == 0) {
+/*
+ * If there is a partial line and we are at EOF, pretend we saw a '\n'
+ */
+ if (ringqLen(lq) > 0 && (sp->flags & SOCKET_EOF)) {
+ c = '\n';
+ } else {
+ return -1;
+ }
+ }
+/*
+ * If a newline is seen, return the data excluding the new line to the
+ * caller. If carriage return is seen, just eat it.
+ */
+ if (c == '\n') {
+ len = ringqLen(lq);
+ if (len > 0) {
+ *buf = ballocAscToUni(lq->servp, len);
+ } else {
+ *buf = NULL;
+ }
+ ringqFlush(lq);
+ return len;
+
+ } else if (c == '\r') {
+ continue;
+ }
+ ringqPutcA(lq, c);
+ }
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Flush the socket. Block if the socket is in blocking mode.
+ * This will return -1 on errors and 0 if successful.
+ */
+
+int socketFlush(int sid)
+{
+ socket_t *sp;
+ ringq_t *rq;
+ int len, bytesWritten, errCode;
+
+ if ((sp = socketPtr(sid)) == NULL) {
+ return -1;
+ }
+ rq = &sp->outBuf;
+
+/*
+ * Set the background flushing flag which socketEventProc will check to
+ * continue the flush.
+ */
+ if (! (sp->flags & SOCKET_BLOCK)) {
+ sp->flags |= SOCKET_FLUSHING;
+ }
+
+/*
+ * Break from loop if not blocking after initiating output. If we are blocking
+ * we wait for a write event.
+ */
+ while (ringqLen(rq) > 0) {
+ len = ringqGetBlkMax(&sp->outBuf);
+ bytesWritten = socketDoOutput(sp, (char*) rq->servp, len, &errCode);
+ if (bytesWritten < 0) {
+ if (errCode == EINTR) {
+ continue;
+ } else if (errCode == EWOULDBLOCK || errCode == EAGAIN) {
+#if WIN || CE
+ if (sp->flags & SOCKET_BLOCK) {
+ int errCode;
+ if (! socketWaitForEvent(sp, FD_WRITE | SOCKET_WRITABLE,
+ &errCode)) {
+ return -1;
+ }
+ continue;
+ }
+#endif
+/*
+ * Ensure we get a FD_WRITE message when the socket can absorb
+ * more data (non-blocking only.) Store the user's mask if we
+ * haven't done it already.
+ */
+ if (sp->saveMask < 0 ) {
+ sp->saveMask = sp->handlerMask;
+ socketRegisterInterest(sp,
+ sp->handlerMask | SOCKET_WRITABLE);
+ }
+ return 0;
+ }
+ return -1;
+ }
+ ringqGetBlkAdj(rq, bytesWritten);
+ }
+/*
+ * If the buffer is empty, reset the ringq pointers to point to the start
+ * of the buffer. This is essential to ensure that datagrams get written
+ * in one single I/O operation.
+ */
+ if (ringqLen(rq) == 0) {
+ ringqFlush(rq);
+ }
+/*
+ * Restore the users mask if it was saved by the non-blocking code above.
+ * Note: saveMask = -1 if empty. socketRegisterInterest will set handlerMask
+ */
+ if (sp->saveMask >= 0) {
+ socketRegisterInterest(sp, sp->saveMask);
+ sp->saveMask = -1;
+ }
+ sp->flags &= ~SOCKET_FLUSHING;
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Return the count of input characters buffered. We look at both the line
+ * buffer and the input (raw) buffer. Return -1 on error or EOF.
+ */
+
+int socketInputBuffered(int sid)
+{
+ socket_t *sp;
+
+ if ((sp = socketPtr(sid)) == NULL) {
+ return -1;
+ }
+ if (socketEof(sid)) {
+ return -1;
+ }
+ return ringqLen(&sp->lineBuf) + ringqLen(&sp->inBuf);
+}
+
+/******************************************************************************/
+/*
+ * Return true if EOF
+ */
+
+int socketEof(int sid)
+{
+ socket_t *sp;
+
+ if ((sp = socketPtr(sid)) == NULL) {
+ return -1;
+ }
+ return sp->flags & SOCKET_EOF;
+}
+
+/******************************************************************************/
+/*
+ * Return the number of bytes the socket can absorb without blocking
+ */
+
+int socketCanWrite(int sid)
+{
+ socket_t *sp;
+
+ if ((sp = socketPtr(sid)) == NULL) {
+ return -1;
+ }
+ return sp->outBuf.buflen - ringqLen(&sp->outBuf) - 1;
+}
+
+/******************************************************************************/
+/*
+ * Add one to allow the user to write exactly SOCKET_BUFSIZ
+ */
+
+void socketSetBufferSize(int sid, int in, int line, int out)
+{
+ socket_t *sp;
+
+ if ((sp = socketPtr(sid)) == NULL) {
+ return;
+ }
+
+ if (in >= 0) {
+ ringqClose(&sp->inBuf);
+ in++;
+ ringqOpen(&sp->inBuf, in, in);
+ }
+
+ if (line >= 0) {
+ ringqClose(&sp->lineBuf);
+ line++;
+ ringqOpen(&sp->lineBuf, line, line);
+ }
+
+ if (out >= 0) {
+ ringqClose(&sp->outBuf);
+ out++;
+ ringqOpen(&sp->outBuf, out, out);
+ }
+}
+
+/******************************************************************************/
+/*
+ * Create a user handler for this socket. The handler called whenever there
+ * is an event of interest as defined by handlerMask (SOCKET_READABLE, ...)
+ */
+
+void socketCreateHandler(int sid, int handlerMask, socketHandler_t handler,
+ int data)
+{
+ socket_t *sp;
+
+ if ((sp = socketPtr(sid)) == NULL) {
+ return;
+ }
+ sp->handler = handler;
+ sp->handler_data = data;
+ socketRegisterInterest(sp, handlerMask);
+}
+
+/******************************************************************************/
+/*
+ * Delete a handler
+ */
+
+void socketDeleteHandler(int sid)
+{
+ socket_t *sp;
+
+ if ((sp = socketPtr(sid)) == NULL) {
+ return;
+ }
+ sp->handler = NULL;
+ socketRegisterInterest(sp, 0);
+}
+
+/******************************************************************************/
+/*
+ * Socket output procedure. Return -1 on errors otherwise return the number
+ * of bytes written.
+ */
+
+static int socketDoOutput(socket_t *sp, char *buf, int toWrite, int *errCode)
+{
+ struct sockaddr_in server;
+ int bytes;
+
+ a_assert(sp);
+ a_assert(buf);
+ a_assert(toWrite > 0);
+ a_assert(errCode);
+
+ *errCode = 0;
+
+#if WIN || CE
+ if ((sp->flags & SOCKET_ASYNC)
+ && ! socketWaitForEvent(sp, FD_CONNECT, errCode)) {
+ return -1;
+ }
+#endif
+
+/*
+ * Write the data
+ */
+ if (sp->flags & SOCKET_BROADCAST) {
+ server.sin_family = AF_INET;
+#if UEMF || LITTLEFOOT
+ server.sin_addr.s_addr = INADDR_BROADCAST;
+#else
+ server.sin_addr.s_addr = inet_addr(basicGetBroadcastAddress());
+#endif
+ server.sin_port = htons((short)(sp->port & 0xFFFF));
+ if ((bytes = sendto(sp->sock, buf, toWrite, 0,
+ (struct sockaddr *) &server, sizeof(server))) < 0) {
+ bytes = tryAlternateSendTo(sp->sock, buf, toWrite, 0,
+ (struct sockaddr *) &server);
+ }
+ } else if (sp->flags & SOCKET_DATAGRAM) {
+ server.sin_family = AF_INET;
+ server.sin_addr.s_addr = inet_addr(sp->host);
+ server.sin_port = htons((short)(sp->port & 0xFFFF));
+ bytes = sendto(sp->sock, buf, toWrite, 0,
+ (struct sockaddr *) &server, sizeof(server));
+
+ } else {
+ bytes = send(sp->sock, buf, toWrite, 0);
+ }
+
+ if (bytes < 0) {
+ *errCode = socketGetError();
+#if WIN || CE
+ sp->currentEvents &= ~FD_WRITE;
+#endif
+
+ return -1;
+
+ } else if (bytes == 0 && bytes != toWrite) {
+ *errCode = EWOULDBLOCK;
+#if WIN || CE
+ sp->currentEvents &= ~FD_WRITE;
+#endif
+ return -1;
+ }
+
+/*
+ * Ensure we get to write some more data real soon if the socket can absorb
+ * more data
+ */
+#if !UEMF
+#if WIN
+ if (sp->interestEvents & FD_WRITE) {
+ emfTime_t blockTime = { 0, 0 };
+ emfSetMaxBlockTime(&blockTime);
+ }
+#endif /* WIN */
+#endif
+ return bytes;
+}
+
+/******************************************************************************/
+/*
+ * If the sendto failed, swap the first two bytes in the
+ * sockaddr structure. This is a kludge due to a change in
+ * VxWorks between versions 5.3 and 5.4, but we want the
+ * product to run on either.
+ */
+static int tryAlternateSendTo(int sock, char *buf, int toWrite, int i,
+ struct sockaddr *server)
+{
+#if VXWORKS
+ char *ptr;
+
+ ptr = (char *)server;
+ *ptr = *(ptr+1);
+ *(ptr+1) = 0;
+ return sendto(sock, buf, toWrite, i, server, sizeof(struct sockaddr));
+#else
+ return -1;
+#endif /* VXWORKS */
+}
+
+/******************************************************************************/
+/*
+ * Allocate a new socket structure
+ */
+
+int socketAlloc(char *host, int port, socketAccept_t accept, int flags)
+{
+ socket_t *sp;
+ int sid;
+
+ if ((sid = hAllocEntry((void***) &socketList, &socketMax,
+ sizeof(socket_t))) < 0) {
+ return -1;
+ }
+ sp = socketList[sid];
+
+ sp->sid = sid;
+ sp->accept = accept;
+ sp->port = port;
+ sp->fileHandle = -1;
+ sp->saveMask = -1;
+
+ if (host) {
+ strncpy(sp->host, host, sizeof(sp->host));
+ }
+
+/*
+ * Preserve only specified flags from the callers open
+ */
+ a_assert((flags & ~(SOCKET_BROADCAST|SOCKET_DATAGRAM|SOCKET_BLOCK|
+ SOCKET_LISTENING)) == 0);
+ sp->flags = flags & (SOCKET_BROADCAST | SOCKET_DATAGRAM | SOCKET_BLOCK|
+ SOCKET_LISTENING);
+
+/*
+ * Add one to allow the user to write exactly SOCKET_BUFSIZ
+ */
+ ringqOpen(&sp->inBuf, SOCKET_BUFSIZ, SOCKET_BUFSIZ);
+ ringqOpen(&sp->outBuf, SOCKET_BUFSIZ + 1, SOCKET_BUFSIZ + 1);
+ ringqOpen(&sp->lineBuf, SOCKET_BUFSIZ, -1);
+
+ return sid;
+}
+
+/******************************************************************************/
+/*
+ * Free a socket structure
+ */
+
+void socketFree(int sid)
+{
+ socket_t *sp;
+ char_t buf[256];
+ int i;
+
+ if ((sp = socketPtr(sid)) == NULL) {
+ return;
+ }
+
+/*
+ * To close a socket, remove any registered interests, set it to
+ * non-blocking so that the recv which follows won't block, do a
+ * shutdown on it so peers on the other end will receive a FIN,
+ * then read any data not yet retrieved from the receive buffer,
+ * and finally close it. If these steps are not all performed
+ * RESETs may be sent to the other end causing problems.
+ */
+ socketRegisterInterest(sp, 0);
+ if (sp->sock >= 0) {
+ socketSetBlock(sid, 0);
+ if (shutdown(sp->sock, 1) >= 0) {
+ recv(sp->sock, buf, sizeof(buf), 0);
+ }
+#if WIN || CE
+ closesocket(sp->sock);
+#else
+ close(sp->sock);
+#endif
+ }
+
+ ringqClose(&sp->inBuf);
+ ringqClose(&sp->outBuf);
+ ringqClose(&sp->lineBuf);
+
+ bfree(B_L, sp);
+ socketMax = hFree((void***) &socketList, sid);
+
+/*
+ * Calculate the new highest socket number
+ */
+ socketHighestFd = -1;
+ for (i = 0; i < socketMax; i++) {
+ if ((sp = socketList[i]) == NULL) {
+ continue;
+ }
+ socketHighestFd = max(socketHighestFd, sp->sock);
+ }
+}
+
+/******************************************************************************/
+/*
+ * Validate a socket handle
+ */
+
+socket_t *socketPtr(int sid)
+{
+ if (sid < 0 || sid >= socketMax || socketList[sid] == NULL) {
+ a_assert(NULL);
+ errno = EBADF;
+ return NULL;
+ }
+
+ a_assert(socketList[sid]);
+ return socketList[sid];
+}
+
+/******************************************************************************/
+/*
+ * Get the operating system error code
+ */
+
+int socketGetError()
+{
+#if WIN || CE
+ switch (WSAGetLastError()) {
+ case WSAEWOULDBLOCK:
+ return EWOULDBLOCK;
+ case WSAECONNRESET:
+ return ECONNRESET;
+ case WSAENETDOWN:
+ return ENETDOWN;
+ case WSAEPROCLIM:
+ return EAGAIN;
+ case WSAEINTR:
+ return EINTR;
+ default:
+ return EINVAL;
+ }
+#else
+ return errno;
+#endif
+}
+
+/******************************************************************************/
+/*
+ * Return the underlying socket handle
+ */
+
+int socketGetHandle(int sid)
+{
+ socket_t *sp;
+
+ if ((sp = socketPtr(sid)) == NULL) {
+ return -1;
+ }
+ return sp->sock;
+}
+
+/******************************************************************************/
+/*
+ * Get blocking mode
+ */
+
+int socketGetBlock(int sid)
+{
+ socket_t *sp;
+
+ if ((sp = socketPtr(sid)) == NULL) {
+ a_assert(0);
+ return 0;
+ }
+ return (sp->flags & SOCKET_BLOCK);
+}
+
+/******************************************************************************/
+/*
+ * Get mode
+ */
+
+int socketGetMode(int sid)
+{
+ socket_t *sp;
+
+ if ((sp = socketPtr(sid)) == NULL) {
+ a_assert(0);
+ return 0;
+ }
+ return sp->flags;
+}
+
+/******************************************************************************/
+/*
+ * Set mode
+ */
+
+void socketSetMode(int sid, int mode)
+{
+ socket_t *sp;
+
+ if ((sp = socketPtr(sid)) == NULL) {
+ a_assert(0);
+ return;
+ }
+ sp->flags = mode;
+}
+
+/******************************************************************************/
+/*
+ * Get port.
+ */
+
+int socketGetPort(int sid)
+{
+ socket_t *sp;
+
+ if ((sp = socketPtr(sid)) == NULL) {
+ return -1;
+ }
+ return sp->port;
+}
+
+/******************************************************************************/