int socketGetInput(int sid, char *buf, int toRead, int *errCode) { struct sockaddr_in server; socket_t *sp; int len, bytesRead; a_assert(buf); a_assert(errCode); *errCode = 0; if ((sp = socketPtr(sid)) == NULL) { return -1; } /* * If we have previously seen an EOF condition, then just return */ if (sp->flags & SOCKET_EOF) { return 0; } #if ((defined (WIN) || defined (CE)) && (!defined (LITTLEFOOT) && !defined (WEBS))) if ( !(sp->flags & SOCKET_BLOCK) && ! socketWaitForEvent(sp, FD_CONNECT, errCode)) { return -1; } #endif /* * Read the data */ if (sp->flags & SOCKET_DATAGRAM) { len = sizeof(server); bytesRead = recvfrom(sp->sock, buf, toRead, 0, (struct sockaddr *) &server, &len); } else { bytesRead = recv(sp->sock, buf, toRead, 0); } /* * BUG 01865 -- CPU utilization hangs on Windows. The original code used * the 'errno' global variable, which is not set by the winsock functions * as it is under *nix platforms. We use the platform independent * socketGetError() function instead, which does handle Windows correctly. * Other, *nix compatible platforms should work as well, since on those * platforms, socketGetError() just returns the value of errno. * Thanks to Jonathan Burgoyne for the fix. */ if (bytesRead < 0) { *errCode = socketGetError(); if (*errCode == ECONNRESET) { sp->flags |= SOCKET_CONNRESET; return 0; } return -1; } return bytesRead; }
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 (defined (WIN) || defined (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; server.sin_addr.s_addr = INADDR_BROADCAST; 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 (defined (WIN) || defined (CE)) sp->currentEvents &= ~FD_WRITE; #endif return -1; } else if (bytes == 0 && bytes != toWrite) { *errCode = EWOULDBLOCK; #if (defined (WIN) || defined (CE)) sp->currentEvents &= ~FD_WRITE; #endif return -1; } return bytes; }
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 (defined (WIN) || defined (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; }
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 (defined (WIN) || defined (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 (defined (UEMF) || defined (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 (defined (WIN) || defined (CE)) sp->currentEvents &= ~FD_WRITE; #endif return -1; } else if (bytes == 0 && bytes != toWrite) { *errCode = EWOULDBLOCK; #if (defined (WIN) || defined (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 */ #ifndef UEMF #ifdef WIN if (sp->interestEvents & FD_WRITE) { emfTime_t blockTime = { 0, 0 }; emfSetMaxBlockTime(&blockTime); } #endif /* WIN */ #endif return bytes; }
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; }