📄 sock.c
字号:
/* * 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;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -