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;
}
Beispiel #2
0
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;
}
Beispiel #3
0
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;
}
Beispiel #4
0
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;
}
Beispiel #5
0
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;
}