#include "cygwin.h"
#include "cSocket.h"

#define TCP_ACK 40

size_t	global_ul_count	=  0;		// Values important for the UL/DL Management
size_t 	global_dl_count	=  0;
int 	ul_left		=  0;
int	dl_left		=  0;
size_t 	ulSecond	= 10 * 1024;
size_t 	dlSecond	= 80 * 1024;
//struct in_addr		 my_ip;
size_t cSocket::count = 0;
extern bool	 running;
extern time_t	 currentTime;
void every_sec (void);
#ifdef CDONKEY
#include "donkey.h"
extern struct sPref    pref;
#endif
const char *txtType (const cSocket *list1) {{{
	if (list1 == NULL) return "(NULL)";
	switch(list1->Type) {
	case tNone    	: return "none    ";
	case tSocket  	: return "socket  ";
	case tServer  	: return "server  ";
	case tSource  	: return "source  ";
	case tGui     	: return "gui     ";
	case tCommand 	: return "source  ";
	case tKademlia	: return "kademlia";
	case tServerUDP	: return "udp_port";
		}
	return "";
	}}}

const char* GetSockTypeString( int type ) {{{
	switch( type ) {
		case SOCK_STREAM:	return "SOCK_STREAM";		// stream socket
		case SOCK_DGRAM:	return "SOCK_DGRAM";		// datagram socket
		case SOCK_RAW:		return "SOCK_RAW";		// raw-protocol interface
		case SOCK_RDM:		return "SOCK_RDM";		// reliably-delivered message
		case SOCK_SEQPACKET:	return "SOCK_SEQPACKET";	// sequenced packet stream
		default: return "UNKNOWN SOCK TYPE!";
		}
	}}}	

void cSocket::resetAccept(void) {{{
	printf("do not accept connection !!!\n");
	printf("closing fd: %d\n", fd_new);
	closesocket(fd_new);
	fd_new =INVALID_SOCKET;
	}}}
 
typedef std::map<SOCKET,cSocket*> cSocketMap;
cSocketMap g_SocketMap;
cSocketList event_list;
cSocketList timer_list;

#undef  HAVE_ASYNCIO
#define HAVE_POLLIO	1

#ifdef _WIN32
#define GetErrno()              WSAGetLastError()
#define SOCKET_WOULD_BLOCK	WSAEWOULDBLOCK
#define SOCKET_RETRY		WSAEWOULDBLOCK

#define	WAIT_EVENT 1
u_long read_avail = 0;	// cSocket::do Read
// {{{
HINSTANCE asyncIO_prc;
HWND 	  asyncIO_win;
ATOM 	  asyncIO;
void Win32_PrintErrorString( int err ) {{{
	char*  msg;
  	FormatMessage( 
    		FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
    		NULL,
    		err,
    		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
    		(LPTSTR) &msg,
    		0,
    		NULL 
  		);
  	printf( msg );
  	LocalFree( msg );
	}}}
char* GetWSAErrorString( int err ) {{{	// WINDOWS spezific
char* pMsg;
	switch(err) {
  	case WSAVERNOTSUPPORTED: pMsg = "WSAVERNOTSUPPORTED: version of WinSock not supported"; break;
  	case WSASYSNOTREADY:     pMsg = "WSASYSNOTREADY: WinSock not present or not responding"; break;
  	case WSAEINVAL:          pMsg = "WSAEINVAL: app version not supported by DLL"; break;
  	case WSAHOST_NOT_FOUND:  pMsg = "WSAHOST_NOT_FOUND: Authoritive: Host not found"; break;
  	case WSATRY_AGAIN:       pMsg = "WSATRY_AGAIN: Non-authoritive: host not found or server failure"; break;
  	case WSANO_RECOVERY:     pMsg = "WSANO_RECOVERY: Non-recoverable: refused or not implemented"; break;
  	case WSANO_DATA:         pMsg = "WSANO_DATA: Valid name, no data record for type"; break;
  	case WSANOTINITIALISED:  pMsg = "WSANOTINITIALISED: WSA Startup not initialized"; break;
  	case WSAENETDOWN:        pMsg = "WSAENETDOWN: Network subsystem failed"; break;
  	case WSAEINPROGRESS:     pMsg = "WSAEINPROGRESS: Blocking operation in progress"; break;
  	case WSAEINTR:           pMsg = "WSAEINTR: Blocking call cancelled"; break;
  	case WSAEAFNOSUPPORT:    pMsg = "WSAEAFNOSUPPORT: address family not supported"; break;
  	case WSAEMFILE:          pMsg = "WSAEMFILE: no file descriptors available"; break;
  	case WSAENOBUFS:         pMsg = "WSAENOBUFS: no buffer space available"; break;
  	case WSAEPROTONOSUPPORT: pMsg = "WSAEPROTONOSUPPORT: specified protocol not supported"; break;
  	case WSAEPROTOTYPE:      pMsg = "WSAEPROTOTYPE: protocol wrong type for this socket"; break;
  	case WSAESOCKTNOSUPPORT: pMsg = "WSAESOCKTNOSUPPORT: socket type not supported for address family"; break;
  	case WSAENOTSOCK:        pMsg = "WSAENOTSOCK: descriptor is not a socket"; break;
  	case WSAEWOULDBLOCK:     pMsg = "WSAEWOULDBLOCK: socket marked as non-blocking and SO_LINGER set not 0"; break;
  	case WSAEADDRINUSE:      pMsg = "WSAEADDRINUSE: address already in use"; break;
  	case WSAECONNABORTED:    pMsg = "WSAECONNABORTED: connection aborted"; break;
  	case WSAECONNRESET:      pMsg = "WSAECONNRESET: connection reset"; break;
  	case WSAENOTCONN:        pMsg = "WSAENOTCONN: not connected"; break;
  	case WSAETIMEDOUT:       pMsg = "WSAETIMEDOUT: connection timed out"; break;
  	case WSAECONNREFUSED:    pMsg = "WSAECONNREFUSED: connection refused"; break;
  	case WSAEHOSTDOWN:       pMsg = "WSAEHOSTDOWN: host down"; break;
  	case WSAEHOSTUNREACH:    pMsg = "WSAEHOSTUNREACH: host unreachable"; break;
  	case WSAEADDRNOTAVAIL:   pMsg = "WSAEADDRNOTAVAIL: address not available"; break;
  	default:                 pMsg = "WSA UNKNOWN ERROR!"; break;
	}
	return pMsg; 
	}}}
void Win32_SocketEventToString( WORD ev, std::string& str ) {{{
	if( ev & FD_ACCEPT )    str += "ACCEPT ";
	if( ev & FD_CONNECT )   str += "CONNECT ";
	if( ev & FD_OOB )       str += "OOB ";
	if( ev & FD_READ )      str += "READ ";
	if( ev & FD_WRITE )     str += "WRITE ";
	if( ev & FD_CLOSE )     str += "CLOSE ";
//	if( ev & FD_QOS )       str += "QOS ";
//	if( ev & FD_GROUP_QOS ) str += "GROUP_QOS ";
	}}}
LRESULT CALLBACK handleSocket (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {{{ // WINDOWS spezific
	if (uMsg != WM_USER) return DefWindowProc(hwnd, uMsg, wParam, lParam);	// not our async message
	int fd = (int)wParam;
	class cSocket *sock = NULL;
	cSocketMap::iterator so_it = g_SocketMap.find(fd);
	if (so_it != g_SocketMap.end()) sock = so_it->second;
	int  event = 0;
	WORD win_event = LOWORD(lParam);
	int err = HIWORD(lParam);
	std::string strEvent;

	if( err || sock == NULL ) {
		Win32_SocketEventToString( win_event, strEvent );
		printf( "handleSocket: fd = %i, event = %s\n", fd, strEvent.c_str() );
		if( err ) printf( "  ERRNO:%i => %s\n", err, GetWSAErrorString(err) );
		if( sock == NULL ) printf( "  Received event for an unregistered socket.\n" );
//		else sock->last_err = err;
		return 0;
		}

	if( win_event & FD_CLOSE )	{
		delete sock;
		return 0;
		}
	if( win_event & (FD_ACCEPT | FD_READ) )
		event |= 1;
	if( win_event & (FD_CONNECT | FD_OOB | FD_WRITE) )
		event |= 2;

	if( event )	sock->doWork( event );
	else {
		Win32_SocketEventToString( win_event, strEvent );
		printf( "handleSocket: unhandled event = %s\n", strEvent.c_str() );
		}

	return 0;
	}}}
// TimerProc is called every second.
VOID CALLBACK TimerProc( HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime ) {{{
	// *** call every_sec() here ***
//	printf("TimerProc: called every second. Time (ms) = %li\n", dwTime);
	}}}
void cSocket::Start (void) {{{	// WINDOWS spezific
	cSocket::local_external_ip.s_addr = 0;
	cSocket::local_internal_ip.s_addr = 0;
	const char name[] = "asyncio";
	WNDCLASS wc;					// Hidden window for async-io message tracking
	wc.style=0;
	wc.lpfnWndProc=(WNDPROC)handleSocket;
	wc.cbClsExtra=0;
	wc.cbWndExtra=0;
	wc.hIcon=0;
	wc.hCursor=0;
	wc.hbrBackground=0;
	wc.lpszMenuName=(LPSTR)0;
	wc.lpszClassName= name;
	asyncIO_prc = (HINSTANCE) wc.hInstance = GetModuleHandle(NULL);
	if (!(asyncIO = RegisterClass(&wc))) {
		printf("RegisterClass failed :-(\n");
		exit(0);
		}
	if (!(asyncIO_win = CreateWindow(name,"win-io",WS_POPUP,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,0,0,asyncIO_prc,0))) {
		printf("CreateWindow failed :-(\n");
		exit(0);
		}
	WSADATA wsadata;
	if (0 == SetTimer(asyncIO_win, 1, 1000, TimerProc)) { // TimerProc is called once every second
		printf("Timer failed\n");
		exit(0);
		}
	if (WSAStartup(0x0101, &wsadata)) {
		WSACleanup();
		printf("WSAStartup failed\n");
		exit(0);
		}
	if (wsadata.wVersion < 0x0101) {
		WSACleanup();
		printf("Wrong winsock version\n");
		exit(0);
		}
	}}}
void     cSocket::doUnblock   (void) {{{ // WINDOWS spezific
	if (fd == INVALID_SOCKET) return;
        u_long command = 1;
        int ret = ioctlsocket (fd, FIONBIO, &command);        //  Redirect events and set non-blocking mode
        if(ret != 0) {
		printf("Seting socket to nonblocking failed ERR: %i\n", ret);
                }
	if (WSAAsyncSelect(fd, asyncIO_win, WM_USER, FD_READ|FD_WRITE|FD_ACCEPT|FD_CLOSE|FD_OOB) < 0) {
		printf("ERROR: WSAAsyncSelect failed\n");
		exit(0);
		}
	}}}
const char*	cSocket::Strerror (int err) { return GetWSAErrorString(err); }
void     cSocket::printError  (int err) {{{	// WINDOWS spezific
	printf("ERRNO %u => %s\n", err, cSocket::Strerror(err) );
	printf("  fd %i, port %u, peer %s:%u\n", fd, this_port, inet_ntoa(peer_ip), peer_port );
	}}}
void cSocket::doBlock(void) { }
// }}}
#else
#define GetErrno()              errno
#define SOCKET_WOULD_BLOCK  	EINPROGRESS
#define SOCKET_RETRY		EAGAIN
size_t read_avail = 0;	// cSocket::do Read
// {{{
#ifdef HAVE_ASYNCIO
#	define USE_SIGNAL      (SIGRTMIN+5)
#	define WAIT_EVENT 4
void handleSocket 	(int, siginfo_t *, void *) { printf("handleSocket\n"); }
void handlePipe   	(int, siginfo_t *, void *) { printf("handlePipe  \n"); }	// SIGPIPE
void handleIO     	(int, siginfo_t *info, void *) { 
	printf("handleIO\n"); 
	printf("info->si_signo => %i\n", info->si_signo);
	printf("info->si_errno => %i\n", info->si_errno);
	printf("info->si_code  => %i\n", info->si_code);
	}	// SIGIO
void handleSEGV		(int, siginfo_t *, void *) { printf("handleSEGV  \n"); }
void handleFPE		(int, siginfo_t *, void *) { printf("handleFPE   \n"); }
void handleILL		(int, siginfo_t *, void *) { printf("handleILL   \n"); }
void handleBUS		(int, siginfo_t *, void *) { printf("handleBUS   \n"); }
#elif HAVE_POLLIO
#	define WAIT_EVENT 3
#else
#	define WAIT_EVENT 2
#endif

#ifdef HAVE_ASYNCIO
typedef void (*action_hdl)(int, siginfo_t *, void *);
static void SigAction(int signum, action_hdl action) {{{
	struct sigaction act;
	bzero (&act, sizeof(act));
	sigemptyset(&act.sa_mask);
	act.sa_flags = SA_SIGINFO;
	act.sa_sigaction = action;
	if (0 != sigaction(signum, &act, NULL)) {
		printf("sigaction(%i,*) => %i : %s\n", signum, errno, cSocket::Strerror(errno));
		abort();
		}
	}}}
void     cSocket::doUnblock   (void) {{{ // LINUX spezific
	if (fd == INVALID_SOCKET) return;
	int opt = 1; // sec to wait for data
	int async = O_ASYNC | O_NONBLOCK;
	if (0 != fcntl (fd, F_SETOWN, getpid())) {{{ // abort
		printf("fcntl (fd, F_SETOWN, getpid()) => %i : %s\n", errno, cSocket::Strerror(errno));
		abort();
		}}}
	if (0 != fcntl (fd, F_SETSIG, USE_SIGNAL)) {{{ // abort
		printf("fcntl (fd, F_SETSIG, USE_SIGNAL) => %i : %s\n", errno, cSocket::Strerror(errno));
		abort();
		}}}
	if (0 != fcntl (fd, F_SETFL , async | fcntl (fd, F_GETFL, 0))) {{{ // abort
		printf("fcntl (fd, F_SETFL , O_ASYNC) => %i : %s\n", errno, cSocket::Strerror(errno));
		abort();
		}}}
	if (type != SOCK_DGRAM)
		if (0 != setsockopt(fd, SOL_TCP, TCP_NODELAY, &opt, sizeof(int))) {
			printf("setsockopt(fd, SOL_TCP, TCP_NODELAY, [1], 4)  => %i : %s\n", errno, cSocket::Strerror(errno));
			}
	struct pollfd check;
	check.fd = fd;
	check.events = POLLIN | POLLOUT | POLLERR;
	if (0 < poll (&check, 1, 0)) {
		mask &= 32;
		if (check.revents & POLLIN ) mask |= 1;
		if (check.revents & POLLOUT) mask |= 2;
		if (check.revents & POLLERR) mask |= 4;
		}
	}}}
void cSocket::doBlock (void) {{{
	int async = O_ASYNC | O_NONBLOCK;
	if (0 != fcntl (fd, F_SETFL , (~async) & fcntl (fd, F_GETFL, 0))) {
		printf("fcntl (fd, F_SETFL , O_ASYNC) => %i : %s\n", errno, cSocket::Strerror(errno));
		}
	}}}
#else
void     cSocket::doUnblock   (void) {{{ // LINUX spezific
	int async =           O_NONBLOCK;
	if (fd == INVALID_SOCKET) return;
	int opt = 1; // sec to wait for data
	if (0 != fcntl (fd, F_SETFL , async | fcntl (fd, F_GETFL, 0))) {{{ // abort
		printf("fcntl (fd, F_SETFL , O_ASYNC) => %i : %s\n", errno, cSocket::Strerror(errno));
		abort();
		}}}
	if (type == SOCK_DGRAM) return;
	if (0 != setsockopt(fd, SOL_TCP, TCP_NODELAY, &opt, sizeof(int))) {
		printf("setsockopt(fd, SOL_TCP, TCP_NODELAY, [1], 4)  => %i : %s\n", errno, cSocket::Strerror(errno));
		}
	}}}
void cSocket::doBlock(void) { }
#endif
void cSocket::Start (void) {{{ // LINUX spezific
	cSocket::local_external_ip.s_addr = 0;
	cSocket::local_internal_ip.s_addr = 0;
#ifdef HAVE_ASYNCIO	
	SigAction (USE_SIGNAL, handleSocket);
	SigAction (SIGPIPE   , handlePipe  );
	SigAction (SIGIO     , handleIO    );
//	SigAction (SIGSEGV   , handleSEGV  ); // These can cause big trouble
	SigAction (SIGFPE    , handleFPE   );
	SigAction (SIGILL    , handleILL   );
	SigAction (SIGBUS    , handleBUS   );
	// Block "USE_SIGNAL" so we can dequeue it in the wait process
	sigset_t block_rtmin;
	sigemptyset (&block_rtmin);
	sigaddset   (&block_rtmin, USE_SIGNAL);
	sigaddset   (&block_rtmin, SIGALRM   );
	sigprocmask (SIG_BLOCK, &block_rtmin, NULL);
	struct itimerval cur_timer;
	struct itimerval old_timer;
	cur_timer.it_interval.tv_sec  = 1;
	cur_timer.it_interval.tv_usec = 0;
	cur_timer.it_value   .tv_sec  = 1;
	cur_timer.it_value   .tv_usec = 0;
	setitimer(ITIMER_REAL, &cur_timer, &old_timer);
#endif	
	}}}
const char*     cSocket::Strerror (int err) { return strerror(err); }
void     cSocket::printError  (int err) {{{	// LINUX spezific
	ASSERT(err != 11);	// EAGAIN
	ASSERT(err != 13);
//	ASSERT(err != 22);	// EINVAL
	ASSERT(err != SOCKET_WOULD_BLOCK);
	printf("%15s:%5u ERRNO %5u => %s\n", inet_ntoa(peer_ip), peer_port, err , cSocket::Strerror(err));
	}}}
// }}}
#endif

#if   WAIT_EVENT == 1
void cSocket::waitEvent (int     ) {{{	// Windows version
	MSG msg;
	BOOL bRet;
	if ((bRet = GetMessage( &msg, NULL, 0, 0 )) != 0) {   // Main message loop: 
		if (bRet == -1) {
			printf( "GetMessage error: " );
			Win32_PrintErrorString( GetLastError() );
			}
		else {
			TranslateMessage(&msg); 
			DispatchMessage(&msg); 
//			cSocket::hdlEvent();
			}
		}
	}}}
#elif WAIT_EVENT == 2
void cSocket::waitEvent (int usec) {{{ // Select Version
	struct timeval timeout;
	timeout.tv_sec  = (usec / 1000000); // Set timeout for the select()
	timeout.tv_usec = (usec % 1000000); 
	fd_set	fd_1;
	fd_set	fd_2;
	fd_set	fd_4;
	FD_ZERO(&fd_1);
	FD_ZERO(&fd_2);
	FD_ZERO(&fd_4);
	int max = 0;
	for (cSocketMap::iterator so_it = g_SocketMap.begin(); so_it != g_SocketMap.end(); so_it++) {
		class cSocket *akt = so_it->second;
		if (akt == NULL) continue;
		if (akt->fd < 0) continue;
		if (akt->fd > 1023) continue;
		if (akt->fd > max) max = akt->fd + 1;
					 FD_SET(akt->fd, &fd_1);
		if (akt->send_len  >  0) FD_SET(akt->fd, &fd_2);
		if (akt->connected == 0) FD_SET(akt->fd, &fd_2);
				 	 FD_SET(akt->fd, &fd_4);
		}
	int cnt = select (max + 1, &fd_1, &fd_2, &fd_4, &timeout);
	if (cnt <= 0) {
		if (cnt < 0) ; // printf("Error %i in select()\n", errno);
		return;
		}
	for (cSocketMap::iterator so_it = g_SocketMap.begin(); so_it != g_SocketMap.end(); so_it++) {
		class cSocket *akt = so_it->second;
		if (akt == NULL) continue;
		if (akt->fd <    0) continue;
		if (akt->fd > 1023) continue;
		if (cnt   <=   0) continue;
		if (FD_ISSET(akt->fd, &fd_1)) { akt->addEvent(1); cnt--; }
		if (FD_ISSET(akt->fd, &fd_2)) { akt->addEvent(2); cnt--; }
		if (FD_ISSET(akt->fd, &fd_4)) { akt->addEvent(4); cnt--; }
		}
	}}}
#elif WAIT_EVENT == 3
#define POLL_LIMIT 8192
void cSocket::waitEvent (int usec) {{{ // Poll Version
	usec = usec / 1000;
	struct pollfd poll_fds[POLL_LIMIT]; // limited file descriptors!
	cSocket *sockets[POLL_LIMIT];
	unsigned int num, i = 0;
	cSocketMap::iterator so_it;
	for (so_it = g_SocketMap.begin(); so_it != g_SocketMap.end(); so_it++) {
		class cSocket *akt = so_it->second;
		if (akt == NULL) continue;
		poll_fds[i].fd = akt->fd;
		poll_fds[i].events = POLLIN | POLLERR | POLLHUP | POLLNVAL;
		if (akt->send_len > 0)   poll_fds[i].events |= POLLOUT;
		if (akt->connected == 0) poll_fds[i].events |= POLLOUT;
		poll_fds[i].revents = 0;
		sockets[i] = akt;
		if (++i >= POLL_LIMIT) break; // should crash here?!?
		}
	num = i;
	int cnt = poll (poll_fds, i, usec);
	if (cnt <= 0) {
		if (cnt == 0) return;	// Timeout
		if (errno == EINTR) return; // A signal occurred before any requested event.
		printf("poll ([poll_fds], %u, %i) => %4i = %s\n", i, usec, errno, strerror(errno));
		return;
		}
	i = 0;
	for (i = 0; i < num && cnt > 0; i++) {
		class cSocket *akt = sockets[i];
		if (akt == NULL) continue;
		if ( poll_fds[i].revents == 0) continue;
		// Here we handle only sockets with new events,
		// Other there handled each seconed
		cnt--;									// cnt more events to handle
		int m = akt->mask;
		akt->mask &= 32;
		if ((poll_fds[i].revents & POLLIN  ) != 0)   m |=  1;
		if ((poll_fds[i].revents & POLLPRI ) != 0) { m |= 16; printf("urgent data\n"); }
		if ((poll_fds[i].revents & POLLOUT ) != 0)   m |=  2;
		if ((poll_fds[i].revents & POLLERR ) != 0)   m |=  4;
		if ((poll_fds[i].revents & POLLHUP ) != 0)
			if (akt->connected != 2 && akt->connected != 3) m |= 16;	// This does not close listen sockets
		if ((poll_fds[i].revents & POLLNVAL) != 0)   m |= 16;
		if (m == 0) continue;							// Listen socket, wich was not closed
		if ((m & 16) == 0) akt->doWork(m);
		if (((m | akt->mask) & 16) != 0) { 
		  	log(1, "cSocket::waitEvent delete %x\n", akt);
			for (int j=i+1;j<cnt;j++) ASSERT(sockets[j]!=akt);
		  	delete akt; 
			}
		}
	}}}
#elif WAIT_EVENT == 4
void cSocket::waitEvent (int     ) {{{ // Async-IO Version
	if (!running) return; 
	timespec timeout;
	sigset_t 	block_rtmin;
	siginfo_t 	info;
	sigemptyset (&block_rtmin);
	sigaddset   (&block_rtmin, SIGTERM);
	sigaddset   (&block_rtmin, SIGINT);
	sigaddset   (&block_rtmin, USE_SIGNAL);
	sigaddset   (&block_rtmin, SIGALRM   );
	while (running) {
		mcheck(NULL);
		if (cSocket::count != g_SocketMap.size()) {
			printf("cSocket::coutn %i\n", cSocket::count);
			printf("g_SocketMap.count() %i\n", g_SocketMap.size());
			ASSERT(0);
			}
		timeout.tv_sec  = 1;                            // Set timeout for the select
		timeout.tv_nsec = 0;
		int ret = sigtimedwait (&block_rtmin, &info, &timeout);
		if (!running) return;
		if (ret < 0) continue;
		if (info.si_signo == SIGINT ) { running = false; return; }
		if (info.si_signo == SIGTERM) { running = false; return; }
		if (info.si_signo == SIGALRM) { every_sec ();  continue; }
		if (info.si_signo == USE_SIGNAL) {
			cSocketMap::iterator so_it = g_SocketMap.find(info.si_fd);
			class cSocket *sock = NULL;
			if (so_it != g_SocketMap.end()) sock = so_it->second;
			if (sock == NULL) {
//				printf("Unhandeld socket %4i code %i\n", info.si_fd ,info.si_code);
				/*
				  I (thomas) checked that unhandeld socket result from events that happen
				  after close the socket and remove the handler.
				  That mean they should cause no problem. Please do not remove the comment,
				  from time to time it can make sense to check if there was no code error.
				  */
				continue;
				}
			info.si_code |= sock->mask;
			sock->mask &= 32;
			if ( 4 == (info.si_code &  4)) sock->last_err = info.si_errno;
			if ( 0 == (info.si_code & 16)) sock->doWork(info.si_code); // ORDER IS IMPORTANT
			if (16 == (info.si_code & 16)) {
			  log(1, "cSocket::waitEventASYNC delete %x\n", sock);
			  delete sock;
			}
			continue;
			}
		printf("SIGNAL %i unhandeld\n", info.si_signo);
		} // while (running)
	}}}
#else
#error "Undefined Socket waiting"
#endif

void     cSocket::Stop (void) {{{
	size_t safe = g_SocketMap.size();
	for (cSocketMap::iterator so_it = g_SocketMap.begin(); so_it != g_SocketMap.end(); so_it = g_SocketMap.begin()) {
	         log(1, "cSocket::Stop delete %x\n", so_it->second);
		delete so_it->second;	// ~cSocket delete itself from g_SocketMap
		size_t check = g_SocketMap.size();
		ASSERT(check < safe);
		safe = check;
		}
#ifdef _WIN32
	WSACleanup();
	DestroyWindow(asyncIO_win);
	UnregisterClass((LPCTSTR) MAKEINTATOM(asyncIO), asyncIO_prc);
#endif
	}}}
void     cSocket::Init0     (void) {{{
	last_err  = 0;
	Type 	  = tNone;
	event 	  = NULL;
	mask 	  = 0;
	prio 	  = 1;
	fd_new 	  = INVALID_SOCKET;
	event 	  = NULL;
	send_buf  = NULL;
	send_len  = 0;
	read_buf  = NULL;
	read_len  = 0;
	last_read = 0;
	last_send = 0;
	since 	  = currentTime;
	work_last = currentTime;
	timer 	  = NULL;
	destr_callback = NULL;
	}}}
cSocket         :: cSocket  (class cSocket *FD) {{{
	printf("(create.1) cSocket %p\n", this);
	count++;
	Init0();
	fd = FD->fd_new;
	if (fd == INVALID_SOCKET) {
		printf("ERROR %s %i\n", __FILE__, __LINE__);
		addEvent(16);
		return;
		}

	g_SocketMap[fd] = this;
	doUnblock();
	timer = timer_list.add_back (this);
	
	FD->fd_new = INVALID_SOCKET;
	type = SOCK_STREAM;
	connected = 1;
	ready_send = 1;
	dl_count = ul_count = 0 ;
	struct sockaddr_in addr;
	socklen_t len = sizeof(addr);
	getpeername(fd, reinterpret_cast<struct sockaddr*>(&addr), &len);
	this_ip.s_addr   = 0;
	this_port = FD->this_port;
	peer_port = 0;
	peer_ip   = addr.sin_addr;
	peer_port = addr.sin_port;
	last_conn = currentTime;
	if (!guessSocketLocalIP())
		addEvent(16); // if op. failed, there's something wrong with the socket anyway
	}}}
cSocket         :: cSocket  (unsigned int IP, uint16_t PORT, int TYPE) {{{
	printf("(create.2) cSocket %p\n", this);
	count++;
	Init0();
	type = TYPE;
	if (PORT == 0 || (type != SOCK_STREAM && type != SOCK_DGRAM)) {
		printf("ERROR %s %i\n", __FILE__, __LINE__);
		addEvent(16);
		return;
		}
	// {{{ Create Socket, aktivate Handling
	fd = socket (AF_INET, type, 0);
	if (fd == INVALID_SOCKET) {{{
		last_err = GetErrno();
		printf("cSocket::cSocket(IP,PORT,TYPE) :");
		printError (last_err);
		addEvent(16);
		if (EMFILE == last_err) {
			if (TCP_CLIENT_COUNT > cSocket::count)  TCP_CLIENT_COUNT = cSocket::count - 10;
			else					TCP_CLIENT_COUNT -= 10;
			return;
			}
		assert(0);
		return;
		}}}
	g_SocketMap[fd] = this;
	timer = timer_list.add_back (this);
	doUnblock();
	// }}}
	struct sockaddr_in srv_addr;
    	srv_addr.sin_family = AF_INET;
	srv_addr.sin_addr   = cSocket::getLocalInternalIP ();
    	srv_addr.sin_port   = htons(0);
    	if (0 != bind(fd, reinterpret_cast<struct sockaddr*>(&srv_addr), sizeof(srv_addr))) {{{
		int err = GetErrno();
	        printf("bind(%i,  %15s:%5u <%u>, %u) => %s\n", fd, inet_ntoa(srv_addr.sin_addr), htons(srv_addr.sin_port), type, 
				sizeof(srv_addr),cSocket::Strerror(err));
		addEvent(16);
		assert(0);
        	return;
    		}}}
	dl_count = ul_count = 0 ;
	this_ip.s_addr	  = 0;
	this_port = 0;
	peer_port = PORT;
	peer_ip.s_addr = IP;
	struct sockaddr_in server_addr;
	bzero (&server_addr, sizeof(struct sockaddr_in));
	server_addr.sin_family  	= AF_INET;
	server_addr.sin_addr.s_addr	= IP;
	server_addr.sin_port    	= htons (PORT);
	int ret = connect(fd, reinterpret_cast<struct sockaddr*>(&server_addr), sizeof(server_addr));
	if (ret == -1) {{{ // Erro happened maybe only deffered connection
		int err = GetErrno();
		if (err != SOCKET_WOULD_BLOCK) {
			printf ("BIND ");
			printError (err);
			addEvent(16);
			return;
			}
		}}}
	if (!guessSocketLocalIP())
		addEvent(16); // if op. failed, there's something wrong with the socket anyway
	connected  = (ret == 0);
	ready_send = (ret == 0);
	}}}
cSocket         :: cSocket  (unsigned short PORT, int TYPE) {{{
	printf("(create.3) cSocket %p\n", this);
	count++;
	Init0();
	if (TYPE == SOCK_STREAM) connected = 2;
	else			 connected = 3;
	dl_count = ul_count = 0 ;
	peer_port = 0;
	peer_ip.s_addr   = 0;
	last_err = 0;
	type = TYPE;
	if (PORT == 0 || (type != SOCK_STREAM && type != SOCK_DGRAM)) {
		printf("ERROR %s %i\n", __FILE__, __LINE__);
		addEvent(16);
		return;
		}
	fd = socket (AF_INET, type, 0);
	if (fd == INVALID_SOCKET) {{{
		printf("cSocket::cSocket(PORT,TYPE) :");
		printError (GetErrno());
		addEvent(16);
		return;
		}}}
	g_SocketMap[fd] = this;
	doUnblock();
	timer = timer_list.add_back (this);
	this_ip.s_addr = 0;
	struct sockaddr_in client_addr;
	bzero (&client_addr, sizeof client_addr);	// clear sin_zero
	client_addr.sin_family = AF_INET;
	client_addr.sin_addr   = cSocket::getLocalInternalIP ();
	client_addr.sin_port   = htons(PORT);
#ifndef _WIN32
	int opt = 1; // sec to wait for data
	setsockopt(fd, SOL_SOCKET, SO_REUSEADDR    , &opt, sizeof(int));
#endif
	if (0 != bind(fd, reinterpret_cast<struct sockaddr*>(&client_addr), sizeof(client_addr))) {
		int err = GetErrno();
	        printf("bind(%i,  %15s:%5u <%u>, %u) => %s\n", fd, inet_ntoa(client_addr.sin_addr), htons(client_addr.sin_port), type, 
			sizeof(client_addr),cSocket::Strerror(err));
		addEvent(16);
		return;
		} 
	bzero (&client_addr, sizeof client_addr);
	socklen_t len = sizeof(client_addr);
	getsockname(fd, reinterpret_cast<struct sockaddr*>(&client_addr), &len);
	this_port = htons(client_addr.sin_port);
	printf("Listen on %15s:%5u (Proto: %u) ", inet_ntoa( client_addr.sin_addr), this_port, type);
	if (type == SOCK_STREAM)printf("(TCP) "); else
	if (type == SOCK_DGRAM )printf("(UDP) "); else
				printf("(Proto %u) ", type);
#ifdef CDONKEY	
	if (this_port == pref.ports.server  ) printf("eDonkey-Server (should be forwarded)\n"); else
	if (this_port == pref.ports.client  ) printf("eDonkey-Client (should be forwarded)\n"); else
	if (this_port == pref.ports.emule   ) printf("eDonkey-UDP    (should be forwarded)\n"); else
	if (this_port == pref.ports.kademlia) printf("Overnet-UDP    (should be forwarded)\n"); else
	if (this_port == pref.ports.gui     ) printf("eDonkey-Gui    (password protected, should not be forwarded)\n"); else
	if (this_port == pref.ports.clc     ) printf("eDonkey-CLC    (password protected, should not be forwarded)\n"); else
	if (this_port == pref.ports.web     ) printf("eDonkey-Web    (password protected, should not be forwarded)\n"); else
	if (this_port == this_port	) printf("TODO: Document it!\n");
#endif	
	if (type == SOCK_STREAM) listen(fd,64);
	}}}
cSocket         ::~cSocket  () {{{
//	ASSERT(connected != 2);
	count--;
	if (event != NULL) delete event;
	if (timer != NULL) delete timer;
	doBlock ();
	shutdown (fd, 2);
	if (fd != INVALID_SOCKET) g_SocketMap.erase(fd);
	if (g_SocketMap.size() != count)
	  printf("WARNING: SocketMap: %d count: %d\n", g_SocketMap.size(),count);
	ASSERT (fd != -1); 
	printf("(destr.)closing fd: %u this: %p:\n", fd, this);
	closesocket(fd);
	if (send_buf != NULL) free (send_buf);
	if (read_buf != NULL) free (read_buf);
	if (destr_callback != NULL) (*destr_callback)(this);
	}}}
void     cSocket::Close     (void) {{{
	ASSERT(connected != 2);
	addEvent(16);	// let safely delete hdl event this
	}}}
void     cSocket::setDestructorCallback(void (*callback)(cSocket *)) {{{
         if (callback != NULL)
	         destr_callback = callback;
        }}}
void     cSocket::doAccept  (void) {{{
	do {
		if (fd_new != INVALID_SOCKET)  {
			printf("cSocket::doAccept: ERROR! An accepted connection was left dangling.\n");
			printf("  this_port=%u, fd_new=%u\n", this_port, fd_new);
			printf("  CLOSING SOCKET!\n");
			printf("(doAcc) closing fd: %d\n", fd_new);
			closesocket(fd_new);
			}
		struct sockaddr_in addr;
		socklen_t len = sizeof (addr);
		do {{{ 	fd_new = accept(fd, reinterpret_cast<struct sockaddr*>(&addr), &len);
			if (fd_new != INVALID_SOCKET) break;
			last_err = GetErrno();
			if (last_err == EINTR) continue;
			if (last_err == SOCKET_RETRY) return;
			printf("accept()");
			printError(last_err);
			}}} while (true);
		if (fd_new == INVALID_SOCKET) return;
		peer_ip   = addr.sin_addr;
		peer_port = htons(addr.sin_port);
		Work();
		} while (true);				// Handle multiple connects
	                                                // hl: Doesn't seem wise to me,
                                                        //     Maybe some upper limit?
	}}}
void     cSocket::doSend    (void) {{{
	mask = mask & (~2);
	if (type == SOCK_DGRAM    ) return;
	if (fd   == INVALID_SOCKET) return;
	if (connected == 2) { doAccept (); return; }
	if (connected == 0) {{{ // maintain connection state
		last_conn = currentTime;
		connected = 1;
		ready_send = 1;
		socklen_t len = sizeof(last_err);
		getsockopt (fd, SOL_SOCKET, SO_ERROR, reinterpret_cast<char*>(&last_err), &len);
		if (last_err == ECONNREFUSED) { addEvent(16); return; }
		if (last_err == EHOSTUNREACH) { addEvent(16); return; }
		if (last_err) printf("ERR 666 => %i\n", last_err);
		}}}
	if (send_len == 0) return;
	int done = 0;
	do {{{ 	done = send (fd, send_buf, send_len, 0);
		if (done > 0) break;
		ready_send = 0;
		last_err = GetErrno();
		if (last_err == EINTR			) continue;
		if (last_err == SOCKET_RETRY		) return;
		if (last_err == SOCKET_WOULD_BLOCK	) return;
		addEvent(16);
		if (last_err == ECONNREFUSED		) return; 
		if (last_err == EHOSTUNREACH		) return;
		if (last_err == 104			) return;
		if (last_err == 32) return;  //  EPIPE
		printf("675 err ");
		printError(last_err);		
		return;
		}}} while (true);
	last_send = currentTime;
	if (done <= 0) return;
	if (prio != 0) {{{ // Handle traffic accounting
		global_dl_count += TCP_ACK;
		//we do only count all finished bytes of that file
		//dl_count += TCP_ACK;
		global_ul_count += TCP_ACK + done;
		//ul_count += TCP_ACK + done ;
		dl_left -= TCP_ACK;
		ul_left -= TCP_ACK + done;
		}}}
	send_len -= done;
	if (send_len > 0) {
		memcpy (send_buf, send_buf + done, send_len);
//		send_buf = (char*)REALLOC(send_buf, send_len);	// become smaller (leave it safe time and fragmention
		}
	else	{
//		free (send_buf);	// become smaller (leave it safe time and fragmention
//		send_buf = NULL;
		}
	ready_send = (send_len == 0);
	}}}
void     cSocket::doRead    (void) {{{
	if (16 == (16 & mask)) return;
	if (fd == INVALID_SOCKET) {
		addEvent(16);
		return;
		}
	int done  = 0;
	int err	  = 0;
	if (connected == 2) { doAccept (); return; }
	do {{{ 	done = ioctlsocket(fd, FIONREAD, &read_avail);
		if (done == 0) break;
		err = GetErrno();
		if (err == EINTR) continue;
		printf("ioctlsocket %15s", inet_ntoa(peer_ip));
		printError(err);
		addEvent(16);
		return;
		}}} while(true);
	if (type == SOCK_DGRAM ) {{{ // return
		if (read_avail == 0) return;
		last_read = currentTime;
		struct sockaddr_in addr;
		do {	
			if (read_buf == NULL) {
				read_buf = reinterpret_cast<unsigned char*>(MALLOC (read_avail));
				read_buf_length = read_avail;
				}
			else {
			  if (read_buf_length < read_avail) {
					read_buf = reinterpret_cast<unsigned char*>(REALLOC(read_buf, read_avail));
				read_buf_length = read_avail;
				}
			}
			socklen_t s_len = sizeof(addr);
			do {{{ done = recvfrom(fd, read_buf, read_avail, 0, reinterpret_cast<struct sockaddr *>(&addr), &s_len);
				if (done >= 0) break;
				err = GetErrno();
				if (err != EINTR) break;
				}}} while(true);
			if (done <= 0) {{{ // return
//				if (read_buf != NULL) free (read_buf);	// become smaller (leave it safe time and fragmention
//				read_buf = NULL;
				return;
				}}}
			if (prio != 0) {{{ // count the traffic
				//global_dl_count += TCP_ACK + done;
				//dl_count 	+= TCP_ACK + done;
				dl_left  	-= TCP_ACK + done;
				}}}
			peer_ip   = addr.sin_addr;
			peer_port = htons(addr.sin_port);
			read_len  = done;
			doRead_high();
//			if (read_buf != NULL) free (read_buf);		// become smaller (leave it safe time and fragmention
//			read_buf    = NULL;
			read_avail -= done;
			last_read = currentTime;
			} while (read_avail > 0);
		return;
		}}}
	if (read_avail <= 0) read_avail = 4;
	if (type == SOCK_STREAM) {{{ // return
		if (read_buf == NULL) {
			read_buf = reinterpret_cast<unsigned char*>(MALLOC (read_len + read_avail));
			read_buf_length = read_len + read_avail;
			}
		else {
		  if (read_buf_length < read_len + read_avail) {
				read_buf = reinterpret_cast<unsigned char*>(REALLOC(read_buf, read_len + read_avail));
				read_buf_length = read_len + read_avail;
			}
		}
		do {{{	done = recv (fd, read_buf + read_len, read_avail, 0);
			if (done == 0) {
//				free (read_buf);	// deleted in destructor
//				read_buf = NULL;
				read_avail = 0;
				read_len = 0;
				addEvent(16);
				return;
				}
			int done_old = done;
			if (done > 0) break;
			err = GetErrno();
			if (err == EINTR) continue;
			done = 0;
			if (err == SOCKET_RETRY      ) break;
			if (err == SOCKET_WOULD_BLOCK) break;
			addEvent(16);
//			free (read_buf);
//			read_buf = NULL;		// deleted in destructor
			read_avail = 0;
			read_len = 0;
			if (err == ECONNREFUSED      ) return;
			if (err == 0		     ) return;
			if (err == ENOTCONN	     ) return; // 107 notconnected
			if (err == ECONNRESET	     ) return; // 104 connection reset by peer
			if (err == EHOSTUNREACH	     ) return; // 113 connection reset by peer
			if (err == ETIMEDOUT         ) return; // 110 ETIMEDOUT
			if (err == 10054	     ) return;
			if (done_old == 0 && read_avail > 0) return;
			printf("%5i %s recv () = %i\n", __LINE__, __FILE__, done_old);
			printError(err);
			return;
			}}} while (true);
		if (done > 0) {{{ // we have realy read someting
			if (connected == 0) {
				connected  = 1;
				ready_send = 1;
				last_conn = currentTime;
				}
			read_len += done;
			last_read = currentTime;
			if (prio != 0) {{{ // count traffic
				global_ul_count += TCP_ACK;
				//ul_count += TCP_ACK;
				global_dl_count += TCP_ACK + done;
				//dl_count += TCP_ACK + done ;
				ul_left -= TCP_ACK;
				dl_left -= TCP_ACK + done;
				}}}
			}}}
		if (read_len != 0) {
		  if (read_buf_length < read_len) {
				read_buf = reinterpret_cast<unsigned char*>(REALLOC (read_buf, read_len)); 
				read_buf_length = read_len;
			}
		}
		return;
		}}}
	}}}
bool     cSocket::Write     (const unsigned char *buf, size_t len) {{{
	ASSERT(fd != INVALID_SOCKET);
	ASSERT(fd < 100000);
	if (type == SOCK_DGRAM) {{{ // Handle UDP sending
		struct sockaddr_in addr;
		bzero (&addr, sizeof(addr));
		socklen_t addr_len = sizeof(addr);
		addr.sin_addr	= peer_ip;
		addr.sin_port   = htons(peer_port);
		addr.sin_family = AF_INET;
		last_send = currentTime;
		ASSERT(buf[0] != 0x07);
		int ret = 0;
		const char *c_buf = reinterpret_cast<const char*>(buf);
		ret = sendto (fd, c_buf, len, 0 , reinterpret_cast<struct sockaddr*>(&addr), addr_len);
		size_t RET = ret;
		if (ret < 0) {{{ // display error
			int err = GetErrno();
			if (err == 22) return false;
			if (err == 11) return false;
			if (err == 101) {
				printf("UNREACHABLE %s\n", inet_ntoa(addr.sin_addr));
				return false;
				}
			printf("IP 13 %s\n", inet_ntoa(addr.sin_addr));
			printf("LEN %i\n", len);
			if (err == 13) printf("IP 13 %s\n", inet_ntoa(addr.sin_addr));
			printf("fd: %u this %p:\n", fd, this);
			printError(err);
			return false;
			}}}
		if (prio != 0) {{{ //  count traffic
			global_ul_count += TCP_ACK + ret;
			//ul_count += TCP_ACK + ret ;
			ul_left -= TCP_ACK + ret;
			}}}	
		return RET == len;
		}}}
	if (fd == INVALID_SOCKET) return false;
	if (send_buf == NULL) {{{
	  	send_buf = reinterpret_cast<unsigned char*>(MALLOC (send_len + len));
	  	send_buf_length = send_len + len;
		}}}
	else {{{
		if (send_buf_length < send_len + len) {
	    		send_buf = reinterpret_cast<unsigned char*>(REALLOC (send_buf, send_len + len));
	    		send_buf_length = send_len + len;
	  		}
		}}}
	memcpy (send_buf + send_len, buf, len);
	send_len += len;
	if (0 == (mask & 2)) addEvent(2);
	return (ready_send == 1);
	}} }
size_t   cSocket::Read      (unsigned char *buf, size_t len) {{{
	if (fd   == INVALID_SOCKET) return 0;
	if (read_len < len) len = read_len;
	if (len == 0) return 0;
	ASSERT(read_len > 0    );
	ASSERT(read_buf != NULL);
	memmove (buf, read_buf, len);
	read_len -= len;
	if (read_len == 0) {
//		free (read_buf);				// become smaller (leave it safe time and fragmention
//		read_buf = NULL;
		}
	else	{
		memmove (read_buf, read_buf + len, read_len);
//		read_buf = (char*)REALLOC(read_buf, read_len);	// become smaller (leave it safe time and fragmention
		}
	return len;
	}}}
bool     cSocket::doInternal(int Event) {{{
	ASSERT (fd != INVALID_SOCKET);
	if (4 == (4 & Event)) {	// Error
		socklen_t len = sizeof(last_err);
		getsockopt (fd, SOL_SOCKET, SO_ERROR, reinterpret_cast<char*>(&last_err), &len);	// Error happend
		if (last_err != 0) {
//			printError(last_err);
			addEvent(16);	// error's should not be able to recover
			if (last_err == 0	     ) return false;
			if (last_err == ECONNREFUSED ) return false;	// 111
			if (last_err == ECONNRESET   ) return false;	// 104
			if (last_err == EHOSTUNREACH ) return false;	// 113
			if (last_err == 32	     ) return false; // EPIPE because read ignore read len = 0
			return false;
			}
		}
	ASSERT (fd != INVALID_SOCKET);
	if (2 == (2 & Event)) doSend ();	// Send data if posible
	if (send_len == 0 && 32 == (mask & 32)) mask = 16;
	ASSERT (fd != INVALID_SOCKET);
	if (mask & 16) return false;
	if (1 == (1 & Event)) doRead ();
	ASSERT (fd != INVALID_SOCKET);
	if (16 == (mask & 16)) return false;
	if (fd != INVALID_SOCKET) return false;
	if (type == SOCK_DGRAM) return false;
	return (send_len == 0 || read_len > 0);
	}}}
void     cSocket::doWork    (int Event) {{{
	ASSERT((mask&16)==0);
	ASSERT (fd != INVALID_SOCKET);
	if (mask & 16) return;
	Event = Event | mask;
	mask &= 32;
	bool work = (8 == (8 & Event));
	ASSERT (fd != INVALID_SOCKET);
	if (connected == 0) work = true;
	doInternal (Event);
	if (16 == (mask & 16)) return;
	if (connected == 2) return;
	if (!work && (read_len == 0) && (send_len > 0)) return;

	// NOTE: if there's no 1 event, 
        // doInternal might not have done any reading
	// and doRead_high might kill the whole thing
        // (because read_buf == NULL)
	bool  worked = false;
	while (read_len > 0 && fd != INVALID_SOCKET) {
	  if (mask & 16) return;
	  doRead_high();
	  if (mask & 16) return;
	  if (!canWork()) break;
	  readWork();
	  mask = mask & (~8);
	  Work();
	  work = false;
	  worked = true;
	}
	if (work) {
		ASSERT((mask&16)==0);
	  	Work   ();
	  	worked = true;
		}
	if (worked) {
	  work_last = currentTime;
	  if (timer != NULL) delete timer;
	  timer = timer_list.add_back (this);
	}
	else	{
	  if (timer == NULL) timer = timer_list.add_back (this);
	}
	if (mask & 2) {
	  mask = mask & (~2);
	  doSend();
	}
	if (send_len == 0 && 32 == (mask & 32)) mask = 16;
	}}}
void     cSocket::addEvent  (int Event) {{{
	if (Event == 0) return;
	mask |= Event;
	if (event != NULL) return;
	if (prio == 0) 	event = event_list.add_front(this);
	else		event = event_list.add_back (this);
	}}}
void     cSocket::hdlEvent  (void     ) {{{
	class cSocket *stop = NULL;
	while (!event_list.empty() && ul_left > 0 && dl_left > 0) {
		class cSocket *akt = event_list.peek();
		if (stop == akt) return;
		cSocketList::remove(&akt->event);
		unsigned mask_tmp = akt->mask;
		akt->mask &= 32;
		if (!akt->validSocket()) mask_tmp = 16;
		if (mask_tmp == 0) continue;
		if (0 == (16 & mask_tmp)) akt->doWork(mask_tmp);
		if (mask_tmp & 16) { 
		  log(1, "cSocket::hdlEvent delete %x\n", akt);
		  delete akt;
		}
		else if (akt->event != NULL && stop == NULL) stop = akt;
		}
	}}}


//
// utility funtions for IP handling
// 

#define MAX_HOSTNAME_LENGTH 256

struct in_addr	cSocket::local_internal_ip;
bool		cSocket::local_internal_ip_forced = false;
struct in_addr	cSocket::local_external_ip;
bool		cSocket::local_external_ip_forced = false;
int		cSocket::local_external_ip_repeats = 0;

// is an IP in private address space (in general) (swiped from gtk-gnutella)
bool	cSocket::isPrivateIP(struct in_addr addr) {{{
	uint32_t ip = ntohl(addr.s_addr);
	// 10.0.0.0 -- (10/8 prefix)
	if ((ip & 0xff000000) == 0xa000000) return true;
	// 172.16.0.0 -- (172.16/12 prefix)
	if ((ip & 0xfff00000) == 0xac100000) return true;
	// 169.254.0.0 -- (169.254/16 prefix) -- since Jan 2001 
	if ((ip & 0xffff0000) == 0xa9fe0000) return true;
	// 192.168.0.0 -- (192.168/16 prefix) 
	if ((ip & 0xffff0000) == 0xc0a80000) return true;

	return false;
	}}}
// is an IP in the same LAN as our internal address (swiped from gtk-gnutella)
bool    cSocket::isInternalIP(struct in_addr addr) {{{
	uint32_t ip = ntohl(addr.s_addr);
	uint32_t local_ip = ntohl(local_internal_ip.s_addr);
	return	ip == local_ip					||	// quick check
		(ip & 0xffffff00) == (local_ip & 0xffffff00)	||	// same LAN/24
		(ip & 0xff000000) == 0x7f000000;			// loopback 127.xxx
	}}}
// try to set our local LAN address
void	cSocket::setLocalInternalIP(struct in_addr new_addr) {{{
	if (!local_internal_ip_forced)
		local_internal_ip.s_addr = new_addr.s_addr;	
	}}}
// set our local LAN address by forcing it, also set forcing on
// when forcing=true calls that don't have forcing parameter shall
// not set the address
void	cSocket::setLocalInternalIP(struct in_addr new_addr, bool forcing) {{{
	local_internal_ip.s_addr = new_addr.s_addr;
	local_internal_ip_forced = forcing;
	}}}
// try to set our local externally visible address
void	cSocket::setLocalExternalIP(struct in_addr new_addr) {{{
	static struct in_addr	last_ip_seen = 0;
	static int		same_ip_count = 0;

	if (new_addr.s_addr != last_ip_seen.s_addr) {
		last_ip_seen.s_addr = new_addr.s_addr;
		same_ip_count = 1;
		return;
	}

	if (++same_ip_count < (local_external_ip_repeats+1))
		return;

	last_ip_seen.s_addr = 0;
	same_ip_count = 0;
	local_external_ip.s_addr = new_addr.s_addr;
	log(1, "local_external_ip changed to %s\n", inet_ntoa(local_external_ip));
}}}
// set our local externally visible address
void	cSocket::setLocalExternalIP(struct in_addr new_addr, bool forcing) {{{
	local_external_ip.s_addr = new_addr.s_addr;
	local_external_ip_forced = forcing;
	}}}
// how many repeats (in all: one time + repeats) are required before IP change
void	cSocket::setLocalExternalIPRepeatCount(int repeats) {{{
	if (repeats >= 0)
		local_external_ip_repeats = repeats;
	}}}
struct in_addr	cSocket::getLocalInternalIP () {{{
	return local_internal_ip;
	}}}
struct in_addr	cSocket::getLocalExternalIP () {{{
	return local_external_ip;
	}}}
// find out local IP 
struct in_addr	cSocket::hostIP(const char *bind_to) {{{
	struct in_addr addr;
	if ((bind_to == NULL) || (strcmp(bind_to,"0") == 0)) {
		// if there's no bind_to specified, find hostip by ourselves
		char name[MAX_HOSTNAME_LENGTH];
		addr.s_addr = 0;
		if (-1 == gethostname(name, MAX_HOSTNAME_LENGTH))
			log(1, "cSocket::localInterfaceIP: couldn't get hostname (%d)\n", errno);
		else {
			struct hostent *he = gethostbyname(name);
			if (he != 0) addr.s_addr = *(uint32_t *)(he->h_addr_list[0]);
			}
		}
	else 	addr.s_addr = inet_addr(bind_to);
        return addr;
	}}}

// guess the local-end IP of this socket
// updates socket.this_ip
bool	cSocket::guessSocketLocalIP(void) {{{
	if ((this_ip.s_addr != 0) && (!connected)) return true;
	struct sockaddr_in sa;
	socklen_t sa_len = sizeof (sa);

	if (0 != getsockname (fd, reinterpret_cast<struct sockaddr*>(&sa), &sa_len)) return false;	

	// logic:
	// if peer_ip is on local network -> use ip from here
	// if peer_ip is not on local network -> use local_external_ip
	// is peer_ip is not known (= 0) -> use ip from here
	if ((peer_ip.s_addr == 0) || isInternalIP(peer_ip)) {
		this_ip.s_addr = sa.sin_addr.s_addr;
		//log(1, "guessSocketIP: setting to private: %p %s\n", this, inet_ntoa(this_ip));
		}
	else {
		this_ip = getLocalExternalIP();
		//log(1, "guessSocketIP: setting to public: %p %s\n", this, inet_ntoa(this_ip));
		}
	
	return true;
	}}}

off_t FD_LSEEK  (int fd, off_t offset, int whence) {{{
	off_t err = FD_lseek (fd, offset, whence);
	if (err == offset - 1) {
		printf("lseek failes %4i %s\n", errno, cSocket::Strerror(errno));
		ASSERT(0);
		}
	return err;
	}}}
bool  FD_READ2  (int fd, unsigned char *buf, size_t len) {{{
	while (len > 0) {
		int err = FD_read (fd, buf, len);
		if (err > 0) {
			len -= err;
			buf += err;
			continue;
			}
		if (err == 0) {
			printf("read over file end\n");
			fflush(stdout);
			return false;
			}
		if (errno == EINTR ) continue;
		if (errno == EAGAIN) continue;
		printf("READ error %4i %s\n", errno, cSocket::Strerror(errno));
		assert(0);
		ASSERT(0);
		}
	return true;
	}}}
void  FD_WRITE2 (int fd, const unsigned char *buf, size_t len) {{{
	while (len > 0) {
		int err = FD_write (fd, buf, len);
		if (err > 0) {
			len -= err;
			buf += err;
			continue;
			}
		if (errno == EAGAIN) continue;
		if (errno == EINTR ) continue;
		if (errno == ENOSPC) {
			printf("Disk full\n");
			sleep (1);
			continue;
			}
		printf("WRITE error %4i %s\n", errno, cSocket::Strerror(errno));
		ASSERT(0);
		}
	}}}
unsigned char *file(const char *name, size_t *ret_size) {{{
	int src_fd = -1;
	int size = 0;
	if (-1 == (src_fd = FD_open (name, O_RDONLY | O_BINARY))) return NULL;
	size = FD_LSEEK (src_fd, 0, SEEK_END);
	if (size == 0) {
		*ret_size = 0;
		return NULL;
		}
	FD_LSEEK (src_fd, 0, SEEK_SET);
	unsigned char *INPUT = reinterpret_cast<unsigned char*>(MALLOC(size+1));
	INPUT[size] = 0;
	if (!FD_READ2(src_fd, INPUT, size)) {
		free (INPUT);
		*ret_size = 0;
		return NULL;
		}
	*ret_size = size;
	goto ende_0;
	if(INPUT == NULL) free(INPUT);
	INPUT = NULL;
ende_0:	if(src_fd != -1) FD_close(src_fd);
	return INPUT;
	}}}

