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; } } /* * Validate length of request. Ignore long strings without newlines to * safeguard against long URL attacks. */ if (ringqLen(lq) > E_MAX_REQUEST) { c = '\n'; } /* * 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((char *)lq->servp, len); } else { *buf = NULL; } ringqFlush(lq); return len; } else if (c == '\r') { continue; } ringqPutcA(lq, c); } return 0; }
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); }
static int inputGetc(ej_t* ep) { ejinput_t *ip; int c, len; a_assert(ep); ip = ep->input; if ((len = ringqLen(&ip->script)) == 0) { return -1; } c = ringqGetc(&ip->script); if (c == '\n') { ip->lineNumber++; ip->lineColumn = 0; } else { if ((ip->lineColumn + 2) >= ip->lineLength) { ip->lineLength += EJ_INC; ip->line = brealloc(B_L, ip->line, ip->lineLength * sizeof(char_t)); } ip->line[ip->lineColumn++] = c; ip->line[ip->lineColumn] = '\0'; } return c; }
int socketCanWrite(int sid) { socket_t *sp; if ((sp = socketPtr(sid)) == NULL) { return -1; } return sp->outBuf.buflen - ringqLen(&sp->outBuf) - 1; }
static int socketDoEvent(socket_t *sp) { ringq_t *rq; int sid; a_assert(sp); sid = sp->sid; if (sp->currentEvents & SOCKET_READABLE) { if (sp->flags & SOCKET_LISTENING) { socketAccept(sp); sp->currentEvents = 0; return 1; } } else { /* * If there is still read data in the buffers, trigger the read handler * NOTE: this may busy spin if the read handler doesn't read the data */ if (sp->handlerMask & SOCKET_READABLE && socketInputBuffered(sid) > 0) { sp->currentEvents |= SOCKET_READABLE; } } /* * If now writable and flushing in the background, continue flushing */ if (sp->currentEvents & SOCKET_WRITABLE) { if (sp->flags & SOCKET_FLUSHING) { rq = &sp->outBuf; if (ringqLen(rq) > 0) { socketFlush(sp->sid); } else { sp->flags &= ~SOCKET_FLUSHING; } } } /* * Now invoke the users socket handler. NOTE: the handler may delete the * socket, so we must be very careful after calling the handler. */ if (sp->handler && (sp->handlerMask & sp->currentEvents)) { (sp->handler)(sid, sp->handlerMask & sp->currentEvents, sp->handler_data); /* * Make sure socket pointer is still valid, then reset the currentEvents. */ if (socketList && sid < socketMax && socketList[sid] == sp) { sp->currentEvents = 0; } } return 1; }
static int socketEventProc(void *data, int mask) { socket_t *sp; ringq_t *rq; int sid; sid = (int) data; a_assert(sid >= 0 && sid < socketMax); a_assert(socketList[sid]); if ((sp = socketPtr(sid)) == NULL) { return 1; } /* * If now writable and flushing in the background, continue flushing */ if (mask & SOCKET_WRITABLE) { if (sp->flags & SOCKET_FLUSHING) { rq = &sp->outBuf; if (ringqLen(rq) > 0) { socketFlush(sp->sid); } else { sp->flags &= ~SOCKET_FLUSHING; } } } /* * Now invoke the users socket handler. NOTE: the handler may delete the * socket, so we must be very careful after calling the handler. */ if (sp->handler && (sp->handlerMask & mask)) { (sp->handler)(sid, mask & sp->handlerMask, sp->handler_data); } if (socketList && sid < socketMax && socketList[sid] == sp) { socketRegisterInterest(sp, sp->handlerMask); } return 1; }
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 (defined (WIN) || defined (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; }
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; }