[wt4hq] Patch for wtTunnelSrv

Mario Lorenz ml at vdazone.org
Fri May 18 20:32:50 CEST 2007


Am 18. May 2007, um 09:05:35 schrieb Olivier F5MZN:
> Hi
> 
> A german guy was kind enough to send me a patch for wtTunnelSrv in order 
> to get gcc -wAll more happy with the code. Unfortunately I don't 
> remember who posted it and I have lost the email. Could you please send 
> it again? Please send me the full patched source code in attachement. 
> You can post it through this list.

Hi Olivier,
I assume that would be me. (say, how many other "german guys" are on this
list ? :))

As you wish, patched source is included. As you will notice its really
not too much.

Having admitted that you have lost the email, there were some questions
and suggestions in that email as well:


You mention that the server has been rewritten; I wonder if the clients
have been rewritten too, to include a similar feature.
(unfortunately you do not publish the source for the client so I couldnt
look). Last year, I suggested some further optimizations in the
network protocol and I wonder if those have been realized.
I am not only concerned about the log sync traffic, but about general
traffic as well. You probably remember  my last year's assessment that
the huge majority of the traffic were the status frames, and over the
wan link I certainly would suggest to proxy them down to a more
sensible rate. (once every two minutes or thereabouts).
I do not know about you, but we will certainly have some stations
with only a low bandwith connection.

>
> The special HQ version of Win-Test will be available later.
>

Do you already know which version this is going to be ?
If you planned to put out a new version in Friedrichshafen like
last year, that'd be fine, tho a thad more test time would be nice.
Are you going to be there, anyway? Maybe we could have a chat ?

There also are, uhm, a few wishlist items that have come up in team
discussions here. I'll list them here for your consideration.
If it is already too late, well, c'est la vie...

- configurable ammount of lines, freely definable font size for the main
  log window. Most other windows have a font size setting allowing
  arbitrary sizes, main log window doesnt...

- A setting restricting the edit mode, and/or cursor movement, to
  the currently active band/mode. This is to allow qso edits only to
  the station doing them, and preventing accidental edits of the
  wrong QSOs

- A (regex/wildcard configurable) filter over the status, chat/gab etc.
  windows. As you are aware, we have a huge number of computers in the
  network, so these lists tend to get large. Using the "support stations
  only" switch in the display options has proven impractical last year.
  A similar filter would be nice for the main log, statistics window.

- Allowing remote commands only from dedicated, pre-defined stations
  (while REMOTE CLEARLOGALLNOW has its uses issued from the master
  command station, we wouldnt want this to happen accidentally :)

Best regards,
for the DA0HQ team,
Mario, DL5MLO
-- 
Mario Lorenz                            Internet:    <ml at vdazone.org>
                                        Ham Radio:   DL5MLO at DB0ERF.#THR.DEU.EU
Trust the computer industry to shorten "Year 2000" to Y2K.  It was this kind
of thinking that caused the problem in the first place.
-------------- next part --------------
#ifdef WIN32
#include <windows.h>
#else
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <errno.h>
#include <unistd.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include <ctype.h>

#ifndef WIN32
typedef int SOCKET;
typedef struct timeval TIMEVAL;
#define SOCKET_ERROR -1
extern int errno;
#define _snprintf snprintf
#define closesocket close
#define Sleep(n) usleep(n*10)
#define ioctlsocket ioctl
#endif

/* Used to know where to route protocols */
typedef struct FROMSTATION
{
	char szStationName[256];
	time_t timeLastSeen;
	struct FROMSTATION* pNext;
} FROMSTATION;

typedef struct TUNNEL
{
	char* pszRxBuffer;
	size_t nRxBufferSize;
	char* pszTxBuffer;
	size_t nTxBufferSize;
	SOCKET sock;
	int nState;
	char szFrom[256];
	char szLogin[256];
	time_t timeout;
	FROMSTATION* plistFromStation;
	struct TUNNEL* pNext;
} TUNNEL;

#ifndef min
#define min(a,b) ((a<b)?a:b)
#endif

#ifndef max
#define max(a,b) ((a>b)?a:b)
#endif

#define WAITLOGIN			1
#define WAITPASS			2
#define RUNNING				3
#define TOBEDISCONNECTED	4

#define READ_PEEK			1

#define RX_BUFFER_SIZE_MAX	10000
#define TX_BUFFER_SIZE_MAX	1000000

#define FROMSTATION_TIMEOUT 15

/* Global variables */
TUNNEL* tunnel = NULL;
SOCKET sock;
char g_szLogin[256];
char g_szPassword[256];

#define LOG_LEVEL	        10

static void _log(int level, const char *type, const char *data)
{
	time_t when;
	struct tm *t;
	FILE* fp;

	if( level > LOG_LEVEL )
		return;

	time(&when);
	t = localtime(&when);

	fp = fopen("wtTunnelSrv.log.txt", "a+t");
	if(fp)
	{
		fprintf(fp, "%02d:%02d:%02d %02d/%02d/%04d %s: %s\n",
			t->tm_hour,
			t->tm_min,
			t->tm_sec,
			t->tm_mday,
			t->tm_mon + 1,
			t->tm_year + 1900,
			type,
			data);
		fclose(fp);
	}

	printf("%02d:%02d:%02d %02d/%02d/%04d %s: %s\n",
		t->tm_hour,
		t->tm_min,
		t->tm_sec,
		t->tm_mday,
		t->tm_mon + 1,
		t->tm_year + 1900,
		type,
		data);
}

/*
 * Parse a string (straight from jNOS)
 */
static char *parse_string(char *str)
{
	char *cp = str;
	unsigned long num;

	while (*str != '\0' && *str != '\"') {
		if (*str == '\\') {
			str++;
			switch (*str++) {
			case 'n':
				*cp++ = '\n';
				break;
			case 't':
				*cp++ = '\t';
				break;
			case 'v':
				*cp++ = '\v';
				break;
			case 'b':
				*cp++ = '\b';
				break;
			case 'r':
				*cp++ = '\r';
				break;
			case 'f':
				*cp++ = '\f';
				break;
			case 'a':
				*cp++ = '\007';
				break;
			case '\\':
				*cp++ = '\\';
				break;
			case '\"':
				*cp++ = '\"';
				break;
			case 'x':
				--str;
				num = strtoul(str, &str, 16);
				*cp++ = (char) num;
				break;
			case '0':
			case '1':
			case '2':
			case '3':
			case '4':
			case '5':
			case '6':
			case '7':
				--str;
				num = strtoul(str, &str, 8);
				*cp++ = (char) num;
				break;
			case '\0':
				return NULL;
			default:
				*cp++ = *(str - 1);
				break;
			};
		} else {
			*cp++ = *str++;
		}
	}
	if (*str == '\"')
		str++;		/* skip final quote */
	*cp = '\0';		/* terminate string */
	return str;
}

/*
 * Add a station in the FROMSTATION chained list
 * If that station already exist: only update timeLastSeen
 * Also remove old entries from the list (timeouts) 
 */
static void from_station_add(FROMSTATION** pplistFromStation, const char* lpszStationName)
{
	FROMSTATION* pPrevious = NULL;
	FROMSTATION* pCurrent = *pplistFromStation;
	time_t now = time(NULL);
	int ok = 0;

	while(pCurrent) {
		/* Is that? */
		if (!strcmp(pCurrent->szStationName, lpszStationName)) {
			/* This station is already known: update the timeLastSeen and basta! */
			pCurrent->timeLastSeen = now;
			ok = 1;
		}

		/* Remove old entries, if any */
		if (pCurrent->timeLastSeen + FROMSTATION_TIMEOUT < now) {
			if (pPrevious) {
				/* In the middle of the list... */
				pPrevious->pNext = pCurrent->pNext;
				free(pCurrent);
				pCurrent = pPrevious->pNext;
			} else {
				/* On the head! */
				*pplistFromStation = (*pplistFromStation)->pNext;
				free(pCurrent);
				pCurrent = *pplistFromStation;
				pPrevious = NULL;
			}
			continue;
		}

		pPrevious = pCurrent;
		pCurrent = pCurrent->pNext;
	}

	if (ok)
		return;

	/* Callsign not found, create a new element in the list */
	if (pPrevious) {
		/* Add a new element at the tail of the list */
		pPrevious->pNext = (FROMSTATION*) malloc(sizeof(FROMSTATION));
		pCurrent = pPrevious->pNext;
	} else {
		/* List does not yet exist: create it */
		*pplistFromStation = (FROMSTATION*) malloc(sizeof(FROMSTATION));
		pCurrent = *pplistFromStation;
	}

	if (pCurrent) {	
		memset(pCurrent, 0, sizeof(FROMSTATION));

		strncpy(pCurrent->szStationName, lpszStationName, sizeof(pCurrent->szStationName) - 1);
		pCurrent->szStationName[sizeof(pCurrent->szStationName) - 1] = '\0';

		pCurrent->timeLastSeen = now;
	}
}

/*
 * Return 1 if the specified station is in the list
 */
static int from_station_is_callsign_in(FROMSTATION* plistFromStation, const char* lpszStationName)
{
	while(plistFromStation)
	{
		if (!strcmp(plistFromStation->szStationName, lpszStationName))
			return 1;
		plistFromStation = plistFromStation->pNext;
	}

	return 0;
}

/*
 * Free all FromStation structs of the list
 */
static void from_station_free(FROMSTATION* plistFromStation)
{
	FROMSTATION* pNext;

	while(plistFromStation)
	{
		pNext = plistFromStation->pNext;
		free(plistFromStation);
		plistFromStation = pNext;
	}
}

/*
 * Parse a string, return results in a table
 */
static int parse_args(char **argv, char *cmd)
{
	int ct = 0;
	int quoted;

	while (ct < 31)
	{
		quoted = 0;
		while (*cmd && isspace(*cmd))
			cmd++;
		if (*cmd == 0)
			break;
		if (*cmd == '"') {
			quoted++;
			cmd++;
		}
		argv[ct++] = cmd;
		if (quoted) {
			if ((cmd = parse_string(cmd)) == NULL)
				return 0;
		} else {
			while (*cmd && !isspace(*cmd))
				cmd++;
		}
		if (*cmd)
			*cmd++ = 0;
	}
	argv[ct] = NULL;
	return ct;
}

/*
 * Verify a CRC 
 */
static int verify_crc(const char *lpszBuffer)
{
	// Verify CRC
	unsigned char crc  = 0;
	//unsigned char lastbyte = 0;
	unsigned char *ptr = (unsigned char*) lpszBuffer;
	while( ! (*ptr & 0x80) && *ptr )
		crc += *ptr++;
	crc |= 0x80;
	return ((crc == *ptr) && (*(ptr+1) == '\0'));
}

/*
 * Send a buffers to the socket
 */
static int _send(SOCKET s, const char * buf, int len, int flags)
{
	return send(s, buf, len, flags);
}

/*
 * Send a null-terminated string of any length to a client
 */
void send_buf(SOCKET sock, const char *buffer)
{
	_send(sock, buffer, strlen(buffer), 0);
}

/*
 * Add some data to a dynamically allocated buffer
 * Return 1 in case of success else 0
 */
static int buffer_add(char** pszBuffer, size_t* pnBufferSize, const char* pszNewData, size_t nNewDataSize)
{
	size_t nNewSize = *pnBufferSize + nNewDataSize;
	char* pszNewAllocatedBuffer;
	
	if (pszBuffer)
		pszNewAllocatedBuffer = realloc(*pszBuffer, max(256, nNewSize));
	else
		pszNewAllocatedBuffer = malloc(max(256, nNewSize));

	if (pszNewAllocatedBuffer) {
		*pszBuffer = pszNewAllocatedBuffer;
		memcpy(*pszBuffer + *pnBufferSize, pszNewData, nNewDataSize);
		*pnBufferSize = nNewSize;
		return 1;
	} else {
		return 0;	/* buffer not reallocated */
	}
}

/*
 * Read the beginning of the buffer
 * Return the size of the buffer read (or 0 if none)
 */
static int buffer_read(char** pszBuffer, size_t* pnBufferSize, char* pszDestination, size_t nDestinationSize, int nFlags)
{
	int nRemainingSize, nNewSize;
	char* pszNewAllocatedBuffer;

	if (pszBuffer == NULL || *pszBuffer == NULL)
		return 0;

	if (nDestinationSize == 0)
		return 1;

	nDestinationSize = min(*pnBufferSize, nDestinationSize);	
	nRemainingSize = *pnBufferSize - nDestinationSize;

	memcpy(pszDestination, *pszBuffer, nDestinationSize);

	if (! (nFlags & READ_PEEK)) {
		memmove(*pszBuffer, *pszBuffer + nDestinationSize, nRemainingSize);

		nNewSize = max(256, nRemainingSize);
		pszNewAllocatedBuffer = realloc(*pszBuffer, nNewSize);

		if (pszNewAllocatedBuffer) {
			*pszBuffer = pszNewAllocatedBuffer;
			*pnBufferSize = nRemainingSize;
		} else {
			return 0;
		}
	}
	
	return nDestinationSize;
}

/*
 * Read a string in the buffer, if any
 * Return the number of bytes read, including the NULL terminating character (0 means that no string were found)
 */
static int buffer_read_string(char** ppszBuffer, size_t* pnBufferSize, char* pszDestination, size_t nDestinationSize)
{
	int nIndex;
	int nPos = -1;
	char* ptr = *ppszBuffer;

	/* Search for the next EOL character */
	for(nIndex = 0; nIndex < (int) *pnBufferSize; nIndex++)
	{
		if (*ptr++ == '\n') {
			nPos = nIndex;
			break;
		}
	}

	if (nPos < 0) 
		return 0;
	
	nPos = min(nPos, (int) nDestinationSize);
	if (buffer_read(ppszBuffer, pnBufferSize, pszDestination, nPos + 1, 0)) {
		/* If the client does send a CRLF EOL... */
		if (nPos > 0 && pszDestination[nPos - 1] == '\r')
			nPos--;
		pszDestination[nPos] = '\0';
		return ++nPos;
	}
	else
		return 0;
}

/*
 * Read a protocol in the buffer, if any
 * Return the number of bytes read, including the NULL terminating character (0 means that no string were found)
 */
static int buffer_read_protocol(char** ppszBuffer, size_t* pnBufferSize, char* pszDestination, size_t nDestinationSize)
{
	int nIndex;
	int nPos = -1;
	char* ptr = *ppszBuffer;

	/* Search for the next CRC */
	for(nIndex = 0; nIndex < (int) *pnBufferSize; nIndex++)
	{
		if (((unsigned int) *ptr++) >= 0x80) {
			nPos = nIndex;
			break;
		}
	}

	if (nPos < 0)
		return 0;

	/* Extract that protocol from the RX buffer */
	nPos = min(nPos + 1, (int) nDestinationSize);
	if (! buffer_read(ppszBuffer, pnBufferSize, pszDestination, nPos, 0))
		return 0;	/* error on read */

	pszDestination[nPos] = '\0';

	/* Verify CRC */
	if (! verify_crc(pszDestination))
		return 0;	/* bad CRC */
	
	return ++nPos;	
}

/*
 * Close a socket connection and clean up the dynamically allocated datas which are associated with
 */
TUNNEL* closeconn(SOCKET sock, const char *reason)
{
	TUNNEL *tun;

	tun = tunnel;
	while(tun)
	{
		if (tun->pNext->sock == sock) {
			char szError[256];
			TUNNEL *todelete = tun->pNext;

			if (reason)
				sprintf(szError, "disconnected (%s)", reason);
			else
				strcpy(szError, "logged out");

			_log(2, szError, todelete->szFrom);
			free(todelete->pszRxBuffer);
			free(todelete->pszTxBuffer);
			from_station_free(todelete->plistFromStation);
			tun->pNext = tun->pNext->pNext;
			free(todelete);
			break;
		}
		tun = tun->pNext;
	}
	if (reason)
		_send(sock, reason, strlen(reason), 0);
	closesocket(sock);
	return tun->pNext;
}

/*
 * Send a protocol to every connected client
 */
void broadcast_protocol(SOCKET from_sock, const char *lpszProtocol, int nProtocolLength, const char* lpszToStation)
{
	TUNNEL *tun;

	tun = tunnel->pNext;
	while(tun)
	{
		if (tun->nState == RUNNING && tun->sock != from_sock) {		
			/* Broadcast the protocol to every station, or only to lpszToStation if specified */
			if (lpszToStation[0] == '\0' || from_station_is_callsign_in(tun->plistFromStation, lpszToStation)) {
				int nResult = buffer_add(&(tun->pszTxBuffer), &(tun->nTxBufferSize), lpszProtocol, nProtocolLength);
				if (nResult == 0) {
					char errmsg[1024];

					/* Unexpected error! */
					tun->nState = TOBEDISCONNECTED;
#ifdef WIN32
					sprintf(errmsg, "Socket error #%d in send_to_all", WSAGetLastError());
#else
					sprintf(errmsg, "Socket error #%d (%s) in send_to_all", errno, strerror(errno));
#endif
					_log(1, errmsg, tun->szFrom);
				}
			}
		}
		tun = tun->pNext;
	}
}

/*
 * Wait for new events on the sockets
 */
int wait(void)
{
	int ret;
	TIMEVAL timeout;
	TUNNEL *tun;
	time_t t;

	fd_set sock_read, sock_excp;

	/* listen for events */
	FD_ZERO(&sock_read);
	FD_ZERO(&sock_excp);

	FD_SET(sock, &sock_read);
	FD_SET(sock, &sock_excp);

	t = time(NULL) - 60;	/* timeout, 60 sec of inactivity => disconnect */
	tun = tunnel->pNext;
	while(tun)
	{
		if (t > tun->timeout) {
			/* disconnect in case of inactivity */
			closeconn(tun->sock, "timeout");
			return 0;
		}
		FD_SET(tun->sock, &sock_read);
		FD_SET(tun->sock, &sock_excp);
		tun = tun->pNext;
	}

	/* Wait for a socket event */
	timeout.tv_usec = 500L;
	timeout.tv_sec  = 0;
	ret = select(FD_SETSIZE, &sock_read, (fd_set *) 0, &sock_excp, &timeout);

	/* gestion des erreur */
	if (ret == SOCKET_ERROR)
		_log(0, "SOCKET ERROR in SWITCH_wait", "select\n");

	if (ret == 0)
		return 0;

	/* New connection */
	if (FD_ISSET(sock, &sock_read)) {
		unsigned long value;		
		socklen_t addr_len;
		struct sockaddr_in sock_addr;
		struct hostent *from_host;
		
		/* Position of the last tunnel in the list */
		TUNNEL *tun = tunnel;
		while(tun->pNext != NULL)
			tun = tun->pNext;

		/* allocate a new tunnel structure */
		tun->pNext = (TUNNEL*) malloc(sizeof(TUNNEL));
		tun = tun->pNext;

		/* and initialize it */
		memset(tun, 0, sizeof(TUNNEL));
		addr_len = sizeof sock_addr;
		tun->sock = accept(sock, (struct sockaddr *) &sock_addr, &addr_len);
		tun->nState = WAITLOGIN;

		/* Non blocking socket */
		value = 1;
		ioctlsocket(tun->sock, FIONBIO, &value);

		from_host = gethostbyaddr((char *)&sock_addr.sin_addr, 4, AF_INET);
		
		if (from_host)
			_snprintf(tun->szFrom, sizeof(tun->szFrom) - 1, "%s [%s]", from_host->h_name, inet_ntoa(sock_addr.sin_addr));
		else
			_snprintf(tun->szFrom, sizeof(tun->szFrom) - 1, "[%s]", inet_ntoa(sock_addr.sin_addr));

		_log(2, "Connected to", tun->szFrom);
		tun->szFrom[sizeof(tun->szFrom) - 1] = '\0';
		tun->timeout = time(NULL);
		send_buf(tun->sock, "login:");
	}

	/* Event on a client socket? */
	tun = tunnel->pNext;
	while(tun) 
	{
		SOCKET sock = tun->sock;
		TUNNEL* current = tun;
		tun = tun->pNext;

		if (FD_ISSET(sock, &sock_excp))	{
			/* Exception on socket: disctonnect immediatly */
			tun = closeconn(sock, NULL);
			_log(1, "srv", "socket exception");
			continue;
		}

		if (current->nState == TOBEDISCONNECTED)	{
			tun = closeconn(sock, NULL);
			continue;
		}

		if (FD_ISSET(sock, &sock_read)) {
			int nb;
			char buffer[256];
			char logbuf[4096];

			/* Read the socket */
			nb = recv(sock, buffer, sizeof(buffer) - 1, 0);

			if (nb < 0) {
				/* Error on receive: disconnect */
				int err;
				char szError[256];
#ifdef WIN32
				err = WSAGetLastError();
#else
				err = errno;
#endif
				sprintf(szError, "error %d on recv", err);
				tun = closeconn(sock, szError);
				continue;
			}
				
			if (nb == 0) {
				/* Client closed the connection */
				tun = closeconn(sock, NULL);
				continue;
			}

			current->timeout = time(NULL);

			buffer[nb] = '\0';
			sprintf(logbuf, "from %s", current->szFrom);
			_log(3, logbuf, buffer);

			/* Bufferize the received datas */
			if (! buffer_add(&(current->pszRxBuffer), &(current->nRxBufferSize), buffer, nb)) {
				tun = closeconn(sock, NULL);
				continue;
			}

			if (current->nRxBufferSize > RX_BUFFER_SIZE_MAX) {
				tun = closeconn(current->sock, "RX buffer overflow!\n");
				continue;
			}
		}
	}

	/* Socket exception */
	if( FD_ISSET(sock, &sock_excp) )
	{
		closesocket(sock);
		perror("TELNET socket exception\n");
	}
	
	return 0;
}

/*
 * Process RX buffer
 */
int rx_proc(void)
{
	TUNNEL* tun;
	char szBuffer[4096];
	int nLen;

	tun = tunnel->pNext;
	while(tun)
	{
		if (tun->nRxBufferSize) {
			switch(tun->nState)
			{
			case RUNNING :
				nLen = buffer_read_protocol(&(tun->pszRxBuffer), &(tun->nRxBufferSize), szBuffer, sizeof(szBuffer) - 1);
				if (nLen) {
					char szTemp[sizeof(szBuffer)];
					char* argv[34];
					char* pszFromStation;
					char* pszToStation;
					
					/* Extract from and to stations */
					memcpy(szTemp, szBuffer, nLen);
					if (parse_args(argv, szTemp) < 3)
						continue;	/* strange protocol! */

					pszFromStation = argv[1];
					pszToStation = argv[2];

					from_station_add(&(tun->plistFromStation), pszFromStation);

					broadcast_protocol(tun->sock, szBuffer, nLen, pszToStation);
				}
				break;

			case WAITLOGIN :
				nLen = buffer_read_string(&(tun->pszRxBuffer), &(tun->nRxBufferSize), tun->szLogin, sizeof(tun->szLogin) - 1);
				if (nLen) {
					tun->nState = WAITPASS;
					send_buf(tun->sock, "password:");
				}
				break;

			case WAITPASS :
				nLen = buffer_read_string(&(tun->pszRxBuffer), &(tun->nRxBufferSize), szBuffer, sizeof(szBuffer) - 1);
				if (nLen) {
					if (strcmp(tun->szLogin, g_szLogin) || strcmp(szBuffer, g_szPassword)) {
						/* login/pass does not match: disconnect */
						tun = closeconn(tun->sock, NULL);
						continue;
					} else {
						/* logged in */
						tun->nState = RUNNING;
						_log(2, "logged in", tun->szFrom);
					}
				}
				break;
			}
		}
		tun = tun->pNext;
	}

	return 0;
}

/*
 * Send the TX buffer datas to the client
 */
int tx_proc(void)
{
	TUNNEL* tun;
	char szBuffer[4096];
	int nBufferLen, nBytesSent;

	tun = tunnel->pNext;
	while(tun)
	{
		for(;;)
		{
			nBufferLen = buffer_read(&(tun->pszTxBuffer), &(tun->nTxBufferSize), szBuffer, sizeof(szBuffer) - 1, READ_PEEK);

			/* Nothing to send? */
			if (nBufferLen == 0)
				break;

			/* Try to send the bloc of data to the client */
			/* Note that one must not send the null-terminal character! */
			nBytesSent = _send(tun->sock, szBuffer, nBufferLen - 1, 0) + 1;

			if (nBufferLen == SOCKET_ERROR) {
#ifdef WIN32
				switch(WSAGetLastError())
				{
				case WSAENOBUFS :
				case WSAEWOULDBLOCK :
					/* Socket buffer is full: will try to send the datas later */
					break;

				default :
					/* Other errors: disconnect */
					tun = closeconn(tun->sock, NULL);
					continue;
				}
#else
				switch(errno)
				{
#if EAGAIN != EWOULDBLOCK 
				case EAGAIN :
#endif
				case EWOULDBLOCK :
				case ENOBUFS :
					/* Socket buffer is full: will try to send the datas later */
					break;

				default :
					/* Other errors: disconnect */
					tun = closeconn(tun->sock, NULL);
					continue;
				}
#endif
			}
			/* Remove the sent bytes from the TX buffer */
			buffer_read(&(tun->pszTxBuffer), &(tun->nTxBufferSize), szBuffer, nBytesSent, 0);
		}
		tun = tun->pNext;
	}

	return 0;
}

int main(int argc, char *argv[])
{
#ifdef WIN32
	WORD    wVersionRequested = 2;
	WSADATA wsaData;
#endif
	//int nRet;
	int val;
	struct sockaddr_in SockAddrInet;
	int   addrlen;
	int port;

	printf("wtTunnelServer version 2.0\n");
	Sleep(1000);

	if (argc != 4)
	{
		printf("Usage: wtTunnelSrv <port_number> <login> <password>\n\n");
		exit(EXIT_SUCCESS);
	}
	port = atoi((char*) argv[1]);
	strncpy(g_szLogin, (const char*) argv[2], sizeof(g_szLogin) - 1);
	g_szLogin[sizeof(g_szLogin) - 1] = '\0';
	strncpy(g_szPassword, (const char*) argv[3], sizeof(g_szPassword) - 1);
	g_szPassword[sizeof(g_szPassword) - 1] = '\0';

	if (port == 0)
	{
		printf("port cannot be null!\n");
		exit(EXIT_FAILURE);
	}
	
	_log(0, "srv", "starting server");

#ifdef WIN32
	/* start winsock library */
	nRet = WSAStartup(wVersionRequested, &wsaData);
	if (nRet)
	{
		OutputDebugString("NO WINSOCK LIBRARY!\n");
		WSACleanup();
		exit(EXIT_FAILURE);
	}

	/* Check WinSock version */
	if (wsaData.wVersion != wVersionRequested)
	{
		OutputDebugString("WinSock version not supported");
		WSACleanup();
		exit(EXIT_FAILURE);
	}
#endif

	/* Create socket */
	if( (sock = socket(AF_INET, SOCK_STREAM, 0)) == SOCKET_ERROR )
	{
		perror ("socket");
		exit(EXIT_FAILURE);
	}

	val = 1;
	addrlen = sizeof(val);
	if( (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &val, addrlen)) == SOCKET_ERROR )
	{
		perror ("opn_tcp : setsockopt SO_REUSEADDR");
		exit(EXIT_FAILURE);
	}

	SockAddrInet.sin_family = AF_INET;
	SockAddrInet.sin_port = htons((short) port);
    SockAddrInet.sin_addr.s_addr = htonl(INADDR_ANY);

	addrlen = sizeof (struct sockaddr_in);
	if (bind(sock, (struct sockaddr *) &SockAddrInet, addrlen) == SOCKET_ERROR)
	{
		perror ("bind");
		closesocket(sock);
		exit(EXIT_FAILURE);
	}

	if (listen(sock, SOMAXCONN) == SOCKET_ERROR)
	{
		perror ("listen");
		closesocket(sock);
		exit(EXIT_FAILURE);
	}

	tunnel = (TUNNEL*) malloc(sizeof(TUNNEL));
	memset(tunnel, 0, sizeof(TUNNEL));

	for(;;)
	{
		wait();
		rx_proc();
		tx_proc();
	}

	printf("Exiting ...");
	Sleep(2000);
	exit(EXIT_SUCCESS);
	return 0;
}


More information about the Wt4hq mailing list