⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sock.c

📁 RTEMS (Real-Time Executive for Multiprocessor Systems) is a free open source real-time operating sys
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * 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 + -