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

📄 sockgen.c

📁 一个典型的用于嵌入式Linux环境的Webserver
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *	sockGen.c -- Posix Socket support module for general posix use * *	Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved. * * $Id: sockGen.c,v 1.6 2003/04/11 18:00:12 bporter Exp $ *//******************************** Description *********************************//* *	Posix Socket Module.  This supports blocking and non-blocking buffered  *	socket I/O. */#if (!defined (WIN) || defined (LITTLEFOOT) || defined (WEBS))/********************************** Includes **********************************/#ifndef CE#include	<errno.h>#include	<fcntl.h>#include	<string.h>#include	<stdlib.h>#endif#ifdef UEMF	#include	"uemf.h"#else	#include	<socket.h>	#include	<types.h>	#include	<unistd.h>	#include	"emfInternal.h"#endif#ifdef VXWORKS	#include	<hostLib.h>#endif/************************************ Locals **********************************/extern socket_t		**socketList;			/* List of open sockets */extern int			socketMax;				/* Maximum size of socket */extern int			socketHighestFd;		/* Highest socket fd opened */static int			socketOpenCount = 0;	/* Number of task using sockets *//***************************** Forward Declarations ***************************/static void socketAccept(socket_t *sp);static int 	socketDoEvent(socket_t *sp);static int	tryAlternateConnect(int sock, struct sockaddr *sockaddr);/*********************************** Code *************************************//* *	Open socket module */int socketOpen(){#if (defined (CE) || defined (WIN))    WSADATA 	wsaData;#endif	if (++socketOpenCount > 1) {		return 0;	}#if (defined (CE) || defined (WIN))	if (WSAStartup(MAKEWORD(1,1), &wsaData) != 0) {		return -1;	}	if (wsaData.wVersion != MAKEWORD(1,1)) {		WSACleanup();		return -1;	}#endif	socketList = NULL;	socketMax = 0;	socketHighestFd = -1;	return 0;}/******************************************************************************//* *	Close the socket module, by closing all open connections */void socketClose(){	int		i;	if (--socketOpenCount <= 0) {		for (i = socketMax; i >= 0; i--) {			if (socketList && socketList[i]) {				socketCloseConnection(i);			}		}		socketOpenCount = 0;	}}/******************************************************************************//* *	Open a client or server socket. Host is NULL if we want server capability. */int socketOpenConnection(char *host, int port, socketAccept_t accept, int flags){#if (!defined (NO_GETHOSTBYNAME) && !defined (VXWORKS))	struct hostent		*hostent;					/* Host database entry */#endif /* ! (NO_GETHOSTBYNAME || VXWORKS) */	socket_t			*sp;	struct sockaddr_in	sockaddr;	int					sid, bcast, dgram, rc;	if (port > SOCKET_PORT_MAX) {		return -1;	}/* *	Allocate a socket structure */	if ((sid = socketAlloc(host, port, accept, flags)) < 0) {		return -1;	}	sp = socketList[sid];	a_assert(sp);/* *	Create the socket address structure */	memset((char *) &sockaddr, '\0', sizeof(struct sockaddr_in));	sockaddr.sin_family = AF_INET;	sockaddr.sin_port = htons((short) (port & 0xFFFF));	if (host == NULL) {		sockaddr.sin_addr.s_addr = INADDR_ANY;	} else {		sockaddr.sin_addr.s_addr = inet_addr(host);		if (sockaddr.sin_addr.s_addr == INADDR_NONE) {/* *			If the OS does not support gethostbyname functionality, the macro: *			NO_GETHOSTBYNAME should be defined to skip the use of gethostbyname. *			Unfortunatly there is no easy way to recover, the following code *			simply uses the basicGetHost IP for the sockaddr. */#ifdef NO_GETHOSTBYNAME			if (strcmp(host, basicGetHost()) == 0) {				sockaddr.sin_addr.s_addr = inet_addr(basicGetAddress());			}			if (sockaddr.sin_addr.s_addr == INADDR_NONE) {				socketFree(sid);				return -1;			}#elif (defined (VXWORKS))			sockaddr.sin_addr.s_addr = (unsigned long) hostGetByName(host);			if (sockaddr.sin_addr.s_addr == NULL) {				errno = ENXIO;				socketFree(sid);				return -1;			}#else			hostent = gethostbyname(host);			if (hostent != NULL) {				memcpy((char *) &sockaddr.sin_addr, 					(char *) hostent->h_addr_list[0],					(size_t) hostent->h_length);			} else {				char	*asciiAddress;				char_t	*address;				address = basicGetAddress();				asciiAddress = ballocUniToAsc(address, gstrlen(address));				sockaddr.sin_addr.s_addr = inet_addr(asciiAddress);				bfree(B_L, asciiAddress);				if (sockaddr.sin_addr.s_addr == INADDR_NONE) {					errno = ENXIO;					socketFree(sid);					return -1;				}			}#endif /* (NO_GETHOSTBYNAME || VXWORKS) */		}	}	bcast = sp->flags & SOCKET_BROADCAST;	if (bcast) {		sp->flags |= SOCKET_DATAGRAM;	}	dgram = sp->flags & SOCKET_DATAGRAM;/* *	Create the socket. Support for datagram sockets. Set the close on *	exec flag so children don't inherit the socket. */	sp->sock = socket(AF_INET, dgram ? SOCK_DGRAM: SOCK_STREAM, 0);	if (sp->sock < 0) {		socketFree(sid);		return -1;	}#ifndef __NO_FCNTL	fcntl(sp->sock, F_SETFD, FD_CLOEXEC);#endif	socketHighestFd = max(socketHighestFd, sp->sock);/* *	If broadcast, we need to turn on broadcast capability. */	if (bcast) {		int broadcastFlag = 1;		if (setsockopt(sp->sock, SOL_SOCKET, SO_BROADCAST,				(char *) &broadcastFlag, sizeof(broadcastFlag)) < 0) {			socketFree(sid);			return -1;		}	}/* *	Host is set if we are the client */	if (host) {/* *		Connect to the remote server in blocking mode, then go into  *		non-blocking mode if desired. */		if (!dgram) {			if (! (sp->flags & SOCKET_BLOCK)) {/* *				sockGen.c is only used for Windows products when blocking *				connects are expected.  This applies to FieldUpgrader *				agents and open source webserver connectws.  Therefore the *				asynchronous connect code here is not compiled. */#if (defined (WIN) || defined (CE)) && (!defined (LITTLEFOOT) && !defined (WEBS))				int flag;				sp->flags |= SOCKET_ASYNC;/* *				Set to non-blocking for an async connect */				flag = 1;				if (ioctlsocket(sp->sock, FIONBIO, &flag) == SOCKET_ERROR) {					socketFree(sid);					return -1;				}#else				socketSetBlock(sid, 1);#endif /* #if (WIN || CE) && !(LITTLEFOOT || WEBS) */			}			if ((rc = connect(sp->sock, (struct sockaddr *) &sockaddr,				sizeof(sockaddr))) < 0 && 				(rc = tryAlternateConnect(sp->sock,				(struct sockaddr *) &sockaddr)) < 0) {#if (defined (WIN) || defined (CE))				if (socketGetError() != EWOULDBLOCK) {					socketFree(sid);					return -1;				}#else				socketFree(sid);				return -1;#endif /* WIN || CE */			}		}	} else {/* *		Bind to the socket endpoint and the call listen() to start listening */		rc = 1;		setsockopt(sp->sock, SOL_SOCKET, SO_REUSEADDR, (char *)&rc, sizeof(rc));		if (bind(sp->sock, (struct sockaddr *) &sockaddr, 				sizeof(sockaddr)) < 0) {			socketFree(sid);			return -1;		}		if (! dgram) {			if (listen(sp->sock, SOMAXCONN) < 0) {				socketFree(sid);				return -1;			}#ifndef UEMF			sp->fileHandle = emfCreateFileHandler(sp->sock, SOCKET_READABLE,				(emfFileProc *) socketAccept, (void *) sp);#else			sp->flags |= SOCKET_LISTENING;#endif		}		sp->handlerMask |= SOCKET_READABLE;	}/* *	Set the blocking mode */	if (flags & SOCKET_BLOCK) {		socketSetBlock(sid, 1);	} else {		socketSetBlock(sid, 0);	}	return sid;}/******************************************************************************//* *	If the connection failed, swap the first two bytes in the  *	sockaddr structure.  This is a kludge due to a change in *	VxWorks between versions 5.3 and 5.4, but we want the  *	product to run on either. */static int tryAlternateConnect(int sock, struct sockaddr *sockaddr){#ifdef VXWORKS	char *ptr;	ptr = (char *)sockaddr;	*ptr = *(ptr+1);	*(ptr+1) = 0;	return connect(sock, sockaddr, sizeof(struct sockaddr));#else	return -1;#endif /* VXWORKS */}/******************************************************************************//* *	Close a socket */void socketCloseConnection(int sid){	socket_t	*sp;	if ((sp = socketPtr(sid)) == NULL) {		return;	}	socketFree(sid);}/******************************************************************************//* *	Accept a connection. Called as a callback on incoming connection. */static void socketAccept(socket_t *sp){	struct sockaddr_in	addr;	socket_t 			*nsp;	size_t				len;	char				*pString;	int 				newSock, nid;#ifdef NW	NETINET_DEFINE_CONTEXT;#endif	a_assert(sp);/* *	Accept the connection and prevent inheriting by children (F_SETFD) */	len = sizeof(struct sockaddr_in);	if ((newSock = accept(sp->sock, (struct sockaddr *) &addr, (int *) &len)) < 0) {		return;	}#ifndef __NO_FCNTL	fcntl(newSock, F_SETFD, FD_CLOEXEC);#endif	socketHighestFd = max(socketHighestFd, newSock);/* *	Create a socket structure and insert into the socket list */	nid = socketAlloc(sp->host, sp->port, sp->accept, sp->flags);	nsp = socketList[nid];	a_assert(nsp);	nsp->sock = newSock;	nsp->flags &= ~SOCKET_LISTENING;	if (nsp == NULL) {		return;	}/* *	Set the blocking mode before calling the accept callback. */	socketSetBlock(nid, (nsp->flags & SOCKET_BLOCK) ? 1: 0);/* *	Call the user accept callback. The user must call socketCreateHandler *	to register for further events of interest. */	if (sp->accept != NULL) {		pString = inet_ntoa(addr.sin_addr);		if ((sp->accept)(nid, pString, ntohs(addr.sin_port), sp->sid) < 0) {			socketFree(nid);		}#ifdef VXWORKS		free(pString);#endif	}}/******************************************************************************//* *	Get more input from the socket and return in buf. *	Returns 0 for EOF, -1 for errors and otherwise the number of bytes read. */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;}/******************************************************************************//* *	Process an event on the event queue */#ifndef UEMFstatic 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;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -