summaryrefslogblamecommitdiffstats
path: root/cpukit/httpd/socket.c
blob: 200cf232b55ca843b3042e15b1e246f25fc2fc22 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
 
  
                                                                      
  
                                                                       




                                                                                

                                                                               

   

                                

                                                                                

                          
 






                                       

      






                                      


                                                                                



                                                                                                    


                                                                                
                                       
                                            
                                                                         







                                                                                




















                                                       











                                                                                




                                                          
                 
                                    







                                                                                  
                                                                                
 


                                                                                                         
                                            

                                                                      
 


                                     




















                                                                     






















                                                                                            





                                                                         











                                                                                         
                         
                                          


                 





                                             
  

                                                                         
   
                                                                       



                                
                  
                                             
      


                                                         











                                                                                      



                                        

                                                                            
   









                                                                                          
 






























                                                                                            

                
                                                                                    


                                                                                        

                                                                  


                                        
 










                                                                                        
                 










                                                   





                                                                                





















                                                                                




                                   
                            



                                            




                                                                                
                                                                         

   
                                      


                                             

                                                 










                                                                                
                  
                                            
      




                                                                 
                                                                     


                              
                                        




                          





                                                                             


                                                   

                                                                                    
                                        
                 


                              
         



                                                                                

                                                                                

   
                                                                
 


                                                       

                      


                          



                                            
 
  
                                                                     
   


                                     





                                                                            
 
  
                     
   









                                                              
                 

                                            





                                                                                
                                           

   


                                                
 


                                    
 



                                              

                                            
                         
         
 
  
                                                                         
   




                                                     
                                
                                                              
                         
                 
         
 
  

                                                                             
   

                                                                             
         

                                                                     
         
                 
 
                   


                                                                                
                                     

   
                                                          
 
                     
 






                                                                            
         
                   



                                                                                

                                                                                  

   
                                                                   
 
                     
 










                                                                           
                          

                                                     
         



                                               



                                                                                
                                                                        

   
                        
 

                                    
 



                        
         
 










                                                          
  
                                                                               
   






                                                                                    
         
                 



                                                                                

                                                                                

   
             
 











                                                                                              
 

                                             

  
                                                      
   
                          
 


                        

         


                                                     
                 
                             
  
                                                                            
   



















                                                           

  

                                                                                  
   


                               
         
 
  
                                        
   
                                                                                  
 




                                                     
                                 












                                                                                   

                 

                       

 
                         
 
                                      
 



                                                                      



                                          
                                                       








                                     


                                             


                                                      







                                        
                                                     




                                         











                                                                            
                                                        
                                              




                                                           
                 
                                                        
                                               
                                  
                 
                                                         
                                                



                                  



                 

                                                                                 

                                                                 

                                                                
                          



                                                
                                                             




                                                 



                                                                         


                                                                                   

                                                    
                                                                     

                                                     



                                                                      









                              
                      





                                                                                
                           

                            
                                    
 




                        


                           
                                        
                                                     




                                         
                 
                                       

                                          


                              




                                                                                
                                           



                                      

                    



                     

                                                    
                                         
                                              
                                 

                  




                                                                                    

                                                                                    






                                                                         
                                                  


                                                  
                                                     









                                                                             

                                                                        

                                          
                                                                                      
    

                                                                             






                                                                                
                                    

   
                                   
 



                                                 
 
                           

                                            

                            
         



                                              
         
 
  
                                                     
   











                                                                                 
 











                                                                                
         
                        



                                                                                
                                                                        

   
                     
 

                                  
 






                                                                           

                 
                 



                                                                                
                                                                      

   
                                
 

                                  
 





                                                                       


                 
                                       
 
                                                                                

/*
 *	sockGen.c -- Posix Socket 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.
 */

#if (!WIN) || LITTLEFOOT || WEBS

/********************************** 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

#if VXWORKS
	#include	<hostLib.h>
#endif

#if __rtems__
	#include	<sys/select.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 CE || WIN
    WSADATA 	wsaData;
#endif

	if (++socketOpenCount > 1) {
		return 0;
	}

#if CE || 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 ! (NO_GETHOSTBYNAME || 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.
 */

#if 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 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 (WIN || CE) && !(LITTLEFOOT || 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 WIN || 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;
			}
#if !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)
{
#if 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;

	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, &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);
		}
#if 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 (WIN || CE) && !(LITTLEFOOT || 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);
	}
	if (bytesRead < 0) {
		if (errno == ECONNRESET) {
			return 0;
		}
		*errCode = socketGetError();
		return -1;
	}
	return bytesRead;
}

/******************************************************************************/
/*
 *	Process an event on the event queue
 */

#ifndef UEMF

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;
}
#endif /* ! UEMF */

/******************************************************************************/
/*
 *	Define the events of interest
 */

void socketRegisterInterest(socket_t *sp, int handlerMask)
{
	a_assert(sp);

	sp->handlerMask = handlerMask;
#if !UEMF
	if (handlerMask) {
		sp->fileHandle = emfCreateFileHandler(sp->sock, handlerMask,
			(emfFileProc *) socketEventProc, (void *) sp->sid);
	} else {
		emfDeleteFileHandler(sp->fileHandle);
	}
#endif /* ! UEMF */
}

/******************************************************************************/
/*
 *	Wait until an event occurs on a socket. Return 1 on success, 0 on failure.
 *	or -1 on exception (UEMF only)
 */

int socketWaitForEvent(socket_t *sp, int handlerMask, int *errCode)
{
	int	mask;

	a_assert(sp);

	mask = sp->handlerMask;
	sp->handlerMask |= handlerMask;
	while (socketSelect(sp->sid, 1000)) {
		if (sp->currentEvents & (handlerMask | SOCKET_EXCEPTION)) {
			break;
		}
	}
	sp->handlerMask = mask;
	if (sp->currentEvents & SOCKET_EXCEPTION) {
		return -1;
	} else if (sp->currentEvents & handlerMask) {
		return 1;
	}
	if (errCode) {
		*errCode = errno = EWOULDBLOCK;
	}
	return 0;
}

/******************************************************************************/
/*
 *	Return TRUE if there is a socket with an event ready to process,
 */

int socketReady(int sid)
{
	socket_t 	*sp;
	int			all;

	all = 0;
	if (sid < 0) {
		sid = 0;
		all = 1;
	}

	for (; sid < socketMax; sid++) {
		if ((sp = socketList[sid]) == NULL) {
			if (! all) {
				break;
			} else {
				continue;
			}
		} 
		if (sp->currentEvents & sp->handlerMask) {
			return 1;
		}
/*
 *		If there is input data, also call select to test for new events
 */
		if (sp->handlerMask & SOCKET_READABLE && socketInputBuffered(sid)) {
			socketSelect(sid, 0);
			return 1;
		}
		if (! all) {
			break;
		}
	}
	return 0;
}

/******************************************************************************/
/*
 * 	Wait for a handle to become readable or writable and return a number of 
 *	noticed events. Timeout is in milliseconds.
 */

#if WIN || CE

int socketSelect(int sid, int timeout)
{
	struct timeval	tv;
	socket_t		*sp;
	fd_set		 	readFds, writeFds, exceptFds;
	int 			nEvents;
	int				all, socketHighestFd;	/* Highest socket fd opened */

	FD_ZERO(&readFds);
	FD_ZERO(&writeFds);
	FD_ZERO(&exceptFds);
	socketHighestFd = -1;

	tv.tv_sec = timeout / 1000;
	tv.tv_usec = (timeout % 1000) * 1000;

/*
 *	Set the select event masks for events to watch
 */
	all = nEvents = 0;

	if (sid < 0) {
		all++;
		sid = 0;
	}

	for (; sid < socketMax; sid++) {
		if ((sp = socketList[sid]) == NULL) {
			continue;
		}
		a_assert(sp);
/*
 * 		Set the appropriate bit in the ready masks for the sp->sock.
 */
		if (sp->handlerMask & SOCKET_READABLE) {
			FD_SET(sp->sock, &readFds);
			nEvents++;
			if (socketInputBuffered(sid) > 0) {
				tv.tv_sec = 0;
				tv.tv_usec = 0;
			}
		}
		if (sp->handlerMask & SOCKET_WRITABLE) {
			FD_SET(sp->sock, &writeFds);
			nEvents++;
		}
		if (sp->handlerMask & SOCKET_EXCEPTION) {
			FD_SET(sp->sock, &exceptFds);
			nEvents++;
		}
		if (! all) {
			break;
		}
	}

/*
 *	Windows select() fails if no descriptors are set, instead of just sleeping
 *	like other, nice select() calls. So, if WIN, sleep.
 */
	if (nEvents == 0) {
		Sleep(timeout);
		return 0;
	}

/*
 * 	Wait for the event or a timeout.
 */
	nEvents = select(socketHighestFd+1, &readFds, &writeFds, &exceptFds, &tv);

	if (all) {
		sid = 0;
	}
	for (; sid < socketMax; sid++) {
		if ((sp = socketList[sid]) == NULL) {
			continue;
		}

		if (FD_ISSET(sp->sock, &readFds) || socketInputBuffered(sid) > 0) {
				sp->currentEvents |= SOCKET_READABLE;
		}
		if (FD_ISSET(sp->sock, &writeFds)) {
				sp->currentEvents |= SOCKET_WRITABLE;
		}
		if (FD_ISSET(sp->sock, &exceptFds)) {
				sp->currentEvents |= SOCKET_EXCEPTION;
		}
		if (! all) {
			break;
		}
	}

	return nEvents;
}

#else /* not WIN || CE */

int socketSelect(int sid, int timeout)
{
	socket_t		*sp;
	struct timeval	tv;
	fd_mask 		*readFds, *writeFds, *exceptFds;
	int 			all, len, nwords, index, bit, nEvents;

/*
 *	Allocate and zero the select masks
 */
	nwords = (socketHighestFd + NFDBITS) / NFDBITS;
	len = nwords * sizeof(int);

	readFds = balloc(B_L, len);
	memset(readFds, 0, len);
	writeFds = balloc(B_L, len);
	memset(writeFds, 0, len);
	exceptFds = balloc(B_L, len);
	memset(exceptFds, 0, len);

	tv.tv_sec = timeout / 1000;
	tv.tv_usec = (timeout % 1000) * 1000;

/*
 *	Set the select event masks for events to watch
 */
	all = nEvents = 0;

	if (sid < 0) {
		all++;
		sid = 0;
	}

	for (; sid < socketMax; sid++) {
		if ((sp = socketList[sid]) == NULL) {
			if (all == 0) {
				break;
			} else {
				continue;
			}
		}
		a_assert(sp);

/*
 * 		Initialize the ready masks and compute the mask offsets.
 */
		index = sp->sock / (NBBY * sizeof(fd_mask));
		bit = 1 << (sp->sock % (NBBY * sizeof(fd_mask)));
		
/*
 * 		Set the appropriate bit in the ready masks for the sp->sock.
 */
		if (sp->handlerMask & SOCKET_READABLE) {
			readFds[index] |= bit;
			nEvents++;
			if (socketInputBuffered(sid) > 0) {
				tv.tv_sec = 0;
				tv.tv_usec = 0;
			}
		}
		if (sp->handlerMask & SOCKET_WRITABLE) {
			writeFds[index] |= bit;
			nEvents++;
		}
		if (sp->handlerMask & SOCKET_EXCEPTION) {
			exceptFds[index] |= bit;
			nEvents++;
		}
		if (! all) {
			break;
		}
	}

/*
 * 	Wait for the event or a timeout. Reset nEvents to be the number of actual
 *	events now.
 */
	nEvents = select(socketHighestFd + 1, (fd_set *) readFds,
		(fd_set *) writeFds, (fd_set *) exceptFds, &tv);

	if (nEvents > 0) {
		if (all) {
			sid = 0;
		}
		for (; sid < socketMax; sid++) {
			if ((sp = socketList[sid]) == NULL) {
				if (all == 0) {
					break;
				} else {
					continue;
				}
			}

			index = sp->sock / (NBBY * sizeof(fd_mask));
			bit = 1 << (sp->sock % (NBBY * sizeof(fd_mask)));

			if (readFds[index] & bit || socketInputBuffered(sid) > 0) {
				sp->currentEvents |= SOCKET_READABLE;
			}
			if (writeFds[index] & bit) {
				sp->currentEvents |= SOCKET_WRITABLE;
			}
			if (exceptFds[index] & bit) {
				sp->currentEvents |= SOCKET_EXCEPTION;
			}
			if (! all) {
				break;
			}
		}
	}

	bfree(B_L, readFds);
	bfree(B_L, writeFds);
	bfree(B_L, exceptFds);

	return nEvents;
}
#endif /* WIN || CE */

/******************************************************************************/
/*
 *	Process socket events
 */

void socketProcess(int sid)
{
	socket_t	*sp;
	int			all;

	all = 0;
	if (sid < 0) {
		all = 1;
		sid = 0;
	}
/*
 * 	Process each socket
 */
	for (; sid < socketMax; sid++) {
		if ((sp = socketList[sid]) == NULL) {
			if (! all) {
				break;
			} else {
				continue;
			}
		}
		if (socketReady(sid)) {
			socketDoEvent(sp);
		}
		if (! all) {
			break;
		}
	}
}

/******************************************************************************/
/*
 *	Process an event on the event queue
 */

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)) {
			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;
}

/******************************************************************************/
/*
 *	Set the socket blocking mode
 */

int socketSetBlock(int sid, int on)
{
	socket_t		*sp;
	unsigned long	flag;
	int				iflag;
	int				oldBlock;

	flag = iflag = !on;

	if ((sp = socketPtr(sid)) == NULL) {
		a_assert(0);
		return 0;
	}
	oldBlock = (sp->flags & SOCKET_BLOCK);
	sp->flags &= ~(SOCKET_BLOCK);
	if (on) {
		sp->flags |= SOCKET_BLOCK;
	}

/*
 *	Put the socket into block / non-blocking mode
 */
	if (sp->flags & SOCKET_BLOCK) {
#if CE || WIN
		ioctlsocket(sp->sock, FIONBIO, &flag);
#elif ECOS
		int off;
		off = 0;
		ioctl(sp->sock, FIONBIO, &off);
#elif VXWORKS
		ioctl(sp->sock, FIONBIO, (int)&iflag);
#else
		fcntl(sp->sock, F_SETFL, fcntl(sp->sock, F_GETFL) & ~O_NONBLOCK);
#endif

	} else {
#if CE || WIN
		ioctlsocket(sp->sock, FIONBIO, &flag);
#elif ECOS
		int on;
		on = 1;
		ioctl(sp->sock, FIONBIO, &on);
#elif VXWORKS
		ioctl(sp->sock, FIONBIO, (int)&iflag);
#else
		fcntl(sp->sock, F_SETFL, fcntl(sp->sock, F_GETFL) | O_NONBLOCK);
#endif
	}
	return oldBlock;
}

/******************************************************************************/
/*
 *	Return true if a readable socket has buffered data. - not public
 */

int socketDontBlock()
{
	socket_t	*sp;
	int			i;

	for (i = 0; i < socketMax; i++) {
		if ((sp = socketList[i]) == NULL || 
				(sp->handlerMask & SOCKET_READABLE) == 0) {
			continue;
		}
		if (socketInputBuffered(i) > 0) {
			return 1;
		}
	}
	return 0;
}

/******************************************************************************/
/*
 *	Return true if a particular socket buffered data. - not public
 */

int socketSockBuffered(int sock)
{
	socket_t	*sp;
	int			i;

	for (i = 0; i < socketMax; i++) {
		if ((sp = socketList[i]) == NULL || sp->sock != sock) {
			continue;
		}
		return socketInputBuffered(i);
	}
	return 0;
}

#endif /* (!WIN) | LITTLEFOOT | WEBS */

/******************************************************************************/