// UDPtoTCP.cpp : Defines the entry point for the console application.
//

#include <stdio.h>

#ifdef WIN32
#include "winsock2.h"
#include "WS2tcpip.h"
#else
#define VOID void
#define SOCKET int 
#define BOOL int
#define TRUE 1
#define FALSE 0
#define SOCKADDR_IN struct sockaddr_in
#define INVALID_SOCKET  -1
#define SOCKET_ERROR    -1
#define closesocket close
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#endif

#define MaxSockets 64


struct SocketConnectionInfo
{
	int Number;					// Number of record - for AGWConnections display
    SOCKET socket;
	struct sockaddr_in sin;  
	BOOL SocketActive;
 };


static struct SocketConnectionInfo Sockets[MaxSockets+1];

int CurrentConnections;

static int CurrentSockets=0;

int TCPPort = 10110;
int UDPPort = 10110;
	
SOCKET tcpsock;
SOCKET udpsock;

void Poll();
int Init();
int Socket_Accept(SOCKET SocketId);
int DataSocket_Disconnect(struct SocketConnectionInfo * sockptr);
int DataSocket_Read(struct SocketConnectionInfo * sockptr, SOCKET sock);


#ifndef WIN32


#include <pthread.h>

pthread_t _beginthread(void(*start_address)(), unsigned stack_size, VOID * arglist)
{
	pthread_t thread;

	if (pthread_create(&thread, NULL, (void * (*)(void *))start_address, (void*) arglist) != 0)
		perror("New Thread");
	else
		pthread_detach(thread);

	return thread;
}

int Sleep(int ms)
{
	usleep(ms * 1000);
	return 0;
}

#endif


int main(int argc, char * argv[])
{
	if (Init() == 0)
		return 0;

	while (1)
	{
		Sleep(1000);
		Poll();
	}
	return 0;
}


VOID Poll()
{
	struct SocketConnectionInfo * sockptr;

	// Look for incoming connects

	fd_set readfd, writefd, exceptfd;
	struct timeval timeout;
	int retval;
	int n;
	int Active = 0;
	SOCKET maxsock;

	// Look for connects

	timeout.tv_sec = 0;
	timeout.tv_usec = 0;				// poll
		
	FD_ZERO(&readfd);

	FD_SET(tcpsock, &readfd);

	retval = select((int)tcpsock + 1, &readfd, NULL, NULL, &timeout);

	if (retval == -1)
	{
		perror("listen select");
	}

	if (retval)
		if (FD_ISSET((int)tcpsock, &readfd))
			Socket_Accept(tcpsock);

	// Look for UDP Data

	timeout.tv_sec = 0;
	timeout.tv_usec = 0;				// poll
		
	FD_ZERO(&readfd);

	FD_SET(udpsock, &readfd);

	retval = select((int)udpsock + 1, &readfd, NULL, NULL, &timeout);

	if (retval == -1)
	{
		perror("udp poll select");
	}

	if (retval)
	{
		if (FD_ISSET((int)udpsock, &readfd))
		{
			char Message[512] = "";
			struct sockaddr_in rxaddr;
			int addrlen = sizeof(struct sockaddr_in);
			int len, n;
			struct SocketConnectionInfo * sockptr;

			len = recvfrom(udpsock, Message, 512, 0, (struct sockaddr *)&rxaddr, &addrlen);

//			if (len > 0)
//				printf"%s", Message);

			// Send to all connected clients

			for (n = 1; n <= CurrentSockets; n++)
			{
				sockptr = &Sockets[n];
		
				if (sockptr->SocketActive)
				{
					send(sockptr->socket, Message, len, 0);
				}
			}
		}
	}


	// look for data on any active sockets

	maxsock = 0;

	FD_ZERO(&readfd);
	FD_ZERO(&writefd);
	FD_ZERO(&exceptfd);

	// Check for data on active streams
	
	for (n = 1; n <= MaxSockets; n++)
	{
		sockptr=&Sockets[n];
		
		if (sockptr->SocketActive)
		{
			SOCKET sock = sockptr->socket;

			FD_SET(sock, &readfd);
			FD_SET(sock, &exceptfd);
				
			Active++;
			if (sock > maxsock)
				maxsock = sock;		
		}
	}

	if (Active)
	{
		retval = select((int)maxsock + 1, &readfd, &writefd, &exceptfd, &timeout);

		if (retval == -1)
		{				
			perror("data select");
		}
		else
		{
			if (retval)
			{
				// see who has data

				for (n = 1; n <= MaxSockets; n++)
				{
					sockptr=&Sockets[n];
		
					if (sockptr->SocketActive)
					{
						SOCKET sock = sockptr->socket;

						if (FD_ISSET(sock, &exceptfd))
							DataSocket_Disconnect(sockptr);

						if (FD_ISSET(sock, &readfd))
							DataSocket_Read(sockptr, sock);

					}
				}
			}		
		}
	}
}


SOCKADDR_IN local_sin; 
SOCKADDR_IN sinx;

SOCKADDR_IN * psin;

int Init()
{	
	BOOL opt = TRUE;
#ifdef WIN32	
	WSADATA WsaData;            // receives data from WSAStartup
    WSAStartup(MAKEWORD(2, 0), &WsaData);
#endif

	if (TCPPort == 0)
		return 0;

//	Create listening socket

	tcpsock = socket( AF_INET, SOCK_STREAM, 0);

    if (tcpsock == INVALID_SOCKET)
	{
        fprintf(stderr, "socket() failed error %d", errno);
		return 0;        
	}

	setsockopt (tcpsock, SOL_SOCKET, SO_REUSEADDR, &opt,4);

	psin=&local_sin;

	psin->sin_family = AF_INET;
	psin->sin_addr.s_addr = INADDR_ANY;
    psin->sin_port = htons(TCPPort);        /* Convert to network ordering */

    if (bind(tcpsock, (struct sockaddr *)&local_sin, sizeof(local_sin)) == SOCKET_ERROR)
	{
        fprintf(stderr, "bind(sock) failed Port %d Error %d", TCPPort, errno);
        closesocket(tcpsock);

		return 0;
	}

	udpsock = socket(AF_INET,SOCK_DGRAM,0);

	sinx.sin_family = AF_INET;
	sinx.sin_addr.s_addr = INADDR_ANY;		
	sinx.sin_port = htons(UDPPort);

	if (bind(udpsock, (struct sockaddr *) &sinx, sizeof(sinx)) != 0 )
	{
		//	Bind Failed

		int err = errno;
		fprintf(stderr, "Bind Failed for UDP port %d - error code = %d\r\n", UDPPort, err);
		return 0;
	}

    if (listen(tcpsock, 5) < 0)
	{
		fprintf(stderr, "listen(sock) failed Error %d", errno);
		return 0;
	} 

	_beginthread(Poll,0,0);

	return 1;
}







int Socket_Accept(SOCKET SocketId)
{
	int n,addrlen;
	struct SocketConnectionInfo * sockptr;
	SOCKET sock;
	unsigned char work[4];

//   Find a free Socket

	for (n = 1; n <= MaxSockets; n++)
	{
		sockptr=&Sockets[n];
		
		if (sockptr->SocketActive == FALSE)
		{
			addrlen=sizeof(struct sockaddr);
		
			memset(sockptr, 0, sizeof(struct SocketConnectionInfo));

			sock = accept(SocketId, (struct sockaddr *)&sockptr->sin, &addrlen);

			if (sock == INVALID_SOCKET)
			{
				printf("accept() failed Error %d\r", errno);
				return FALSE;
			}

			sockptr->socket = sock;
			sockptr->SocketActive = TRUE;
			sockptr->Number = n;

			if (CurrentSockets < n) CurrentSockets = n;  //Record max used to save searching all entries

			memcpy(work, &sockptr->sin.sin_addr.s_addr, 4);

			fprintf(stderr, "Connected Session %d from %d.%d.%d.%d\r\n", n, work[0], work[1], work[2], work[3]);
			return 0;
		}
	}

	// Should accept, then immediately close

	return 0;
}

int DataSocket_Read(struct SocketConnectionInfo * sockptr, SOCKET sock)
{
	int i;
	int DataLength;
	char Message[512] = "";

    i = recv(sock, Message, 512, 0);

	if (i == SOCKET_ERROR || i == 0)
	{
		// Failed or closed - clear connection

		DataSocket_Disconnect(sockptr);
		return 0;
	}
    
	fprintf(stderr, Message);

	return 0;
}

int DataSocket_Disconnect(struct SocketConnectionInfo * sockptr)
{
	closesocket(sockptr->socket);

	sockptr->SocketActive = FALSE;

	fprintf(stderr, "Session %d Disconnected\r\n", sockptr->Number);

	return 0;
}



