/*
 * winstub.c - MS-Windows compatiblity hacks
 * $Id: winstub.c,v 1.10 2005/06/16 20:08:53 rdenisc Exp $
 */

/***********************************************************************
 *  Copyright (C) 2002-2003 Remi Denis-Courmont.                       *
 *  This program is free software; you can redistribute and/or modify  *
 *  it under the terms of the GNU General Public License as published  *
 *  by the Free Software Foundation; version 2 of the license.         *
 *                                                                     *
 *  This program is distributed in the hope that it will be useful,    *
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of     *
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.               *
 *  See the GNU General Public License for more details.               *
 *                                                                     *
 *  You should have received a copy of the GNU General Public License  *
 *  along with this program; if not, you can get it from:              *
 *  http://www.gnu.org/copyleft/gpl.html                               *
 ***********************************************************************/

# if HAVE_CONFIG_H
#  include <config.h>
# endif

#include <stddef.h> /* size_t */
#include <secstdio.h>
#include <errno.h>
#include <stdint.h>

#include <windows.h>
#include <wincon.h> /* SetConsoleTitle() */
#include <winsock2.h>
#include <ws2tcpip.h>
#ifndef WINSOCK_VERSION
# define WINSOCK_VERSION 0x0202
#endif

#undef main
int winstub_main (int argc, char *argv[]);

static SOCKET mysocket = INVALID_SOCKET;

int main (int argc, char *argv[])
{
	WSADATA wsaData;
	int retval;

	SetConsoleTitle ("TCP re-engineering tool v" PACKAGE_VERSION
			" for Windows");

	if (!WSAStartup (WINSOCK_VERSION, &wsaData))
	{
		if (wsaData.wVersion == WINSOCK_VERSION)
		{
			mysocket = WSASocket (PF_INET, SOCK_DGRAM,
						IPPROTO_UDP, NULL, 0, 0);
			if (mysocket != INVALID_SOCKET)
			{
				retval = winstub_main (argc, argv);
				closesocket (mysocket);
				WSACleanup ();
				return retval;
			}
		}
		WSACleanup ();
	}

	fputs ("Winsock unavailable or unsupported version. Aborting.\n",
		stderr);
	return 1;
}


/*
 * Unreliable socket-enabled perror() replacement for Winsock.
 */
#undef perror
void winsock_perror (const char *str)
{
	int num;
	num = WSAGetLastError ();

	if ((num == 0) && (errno >= WSABASEERR))
	{
		num = errno;
		errno = 0;
	}

	if (num)
		fprintf (stderr, "%s: Winsock error %d.\n", str, num);
	else
	{
		if (errno)
			perror (str);
		else
			fprintf (stderr, "%s: unable to trace error.\n", str);
	}
}

/*
 * Unreliable socket-enabled strerror() replacement for Winsock.
 * (NOT THREAD-SAFE)
 */
#undef strerror
const char *winsock_strerror (int errnum)
{
	static char buf[32];

	if (errnum >= WSABASEERR)
	{
		snprintf (buf, sizeof (buf), "Windows socket error %u",
				errnum);
		return buf;
	}
	else
		return strerror (errnum);
}


int winsock_close (int fd)
{
	int errnum;

	errnum = WSAGetLastError ();
	if (closesocket ((SOCKET)fd) != SOCKET_ERROR);
	{
		WSASetLastError (errnum);
		return 0;
	}
	errno = WSAGetLastError ();
	return -1;
}


size_t winsock_recvfrom (int fd, void *buf, size_t len, int flags,
			 struct sockaddr *addr, socklen_t *addrlen)
{
	int errnum;
	WSABUF buffer;
	DWORD count, dwFlags = flags;

	errnum = WSAGetLastError ();
	buffer.len = (unsigned long)len;
	buffer.buf = (char *)buf;

	if (WSARecvFrom ((SOCKET)fd, &buffer, 1, &count, &dwFlags,
			 addr, addrlen, NULL, NULL) == 0)
	{
		WSASetLastError (errnum);
		return (size_t)count;
	}
	errno = WSAGetLastError ();
	return -1;
}


size_t winsock_sendto (int fd, const void *buf, size_t len, int flags,
			const struct sockaddr *addr, socklen_t addrlen)
{
	int errnum;
	WSABUF buffer;
	DWORD count;

	errnum = WSAGetLastError ();
	buffer.len = (unsigned long)len;
	buffer.buf = (char *)buf;

	if (WSASendTo ((SOCKET)fd, &buffer, 1, &count, (DWORD)flags,
			addr, addrlen, NULL, NULL) == 0)
	{
		if (!WSAGetLastError ())
			WSASetLastError (errnum);
		return (size_t)count;
	}
	errno = WSAGetLastError ();
	return -1;
}


size_t winsock_read (int fd, void *buf, size_t len)
{
	return winsock_recv (fd, buf, len, 0);
}


size_t winsock_write (int fd, const void *buf, size_t len)
{
	return winsock_send (fd, buf, len, 0);
}


size_t winsock_recv (int fd, void *buf, size_t len, int flags)
{
	return winsock_recvfrom (fd, buf, len, flags, NULL, 0);
}


size_t winsock_send (int fd, const void *buf, size_t len, int flags)
{
	return winsock_sendto (fd, buf, len, flags, NULL, 0);
}


int winsock_socket (int pf, int type, int proto)
{
	int errnum;
	SOCKET fd;

	errnum = WSAGetLastError ();

	fd = WSASocket (pf, type, proto, NULL, 0, 0);
	if (fd != INVALID_SOCKET)
	{
		WSASetLastError (errnum);
		return (int)fd;
	}
	errno = WSAGetLastError ();
	return -1;
}


#undef bind
int winsock_bind (int fd, struct sockaddr *addr, socklen_t addrlen)
{
	int errnum;

	errnum = WSAGetLastError ();
	if (bind ((SOCKET)fd, (LPSOCKADDR)addr, addrlen) != SOCKET_ERROR)
	{
		WSASetLastError (errnum);
		return 0;
	}
	errno = WSAGetLastError ();
	return -1;
}


#undef listen
int winsock_listen (int fd, int max)
{
	int errnum;

	errnum = WSAGetLastError ();
	if (listen ((SOCKET)fd, max) != SOCKET_ERROR)
	{
		WSASetLastError (errnum);
		return 0;
	}
	errno = WSAGetLastError ();
	return -1;
}


int winsock_accept (int fd, struct sockaddr *addr, socklen_t *len)
{
	int errnum;
	SOCKET newfd;

	errnum = WSAGetLastError ();
	newfd = WSAAccept ((SOCKET)fd, addr, len, NULL, 0);
	if (newfd != INVALID_SOCKET)
	{
		WSASetLastError (errnum);
		return (int)newfd;
	}
	errno = WSAGetLastError ();
	return -1;
}


int winsock_connect (int fd, struct sockaddr *addr, socklen_t len)
{
	int errnum;

	errnum = WSAGetLastError ();
	if (WSAConnect ((SOCKET)fd, addr, len, NULL, NULL, NULL, NULL)
			!= SOCKET_ERROR)
	{
		WSASetLastError (errnum);
		return 0;
	}
	errno = WSAGetLastError ();
	return -1;
}


#undef shutdown
int winsock_shutdown (int fd, int how)
{
	int errnum;

	errnum = WSAGetLastError ();
	if (shutdown ((SOCKET)fd, how) != SOCKET_ERROR)
	{
		WSASetLastError (errnum);
		return 0;
	}
	errno = WSAGetLastError ();
	return -1;
}


#undef setsockopt
int winsock_setsockopt (int fd, int lvl, int opt, const void *data,
			socklen_t len)
{
	int errnum;

	errnum = WSAGetLastError ();
	if (setsockopt ((SOCKET)fd, lvl, opt, (const char *)data, len)
			!= SOCKET_ERROR)
	{
		WSASetLastError (errnum);
		return 0;
	}
	errno = WSAGetLastError ();
	return -1;
}


#undef getsockopt
int winsock_getsockopt (int fd, int lvl, int opt, void *data, socklen_t *len)
{
	int errnum;

	errnum = WSAGetLastError ();
	if (getsockopt ((SOCKET)fd, lvl, opt, (char *)data, len)
			!= SOCKET_ERROR)
	{
		WSASetLastError (errnum);
		return 0;
	}
	errno = WSAGetLastError ();
	return -1;
}


#undef getpeername
int winsock_getpeername (int fd, struct sockaddr *addr, socklen_t *len)
{
	int errnum;

	errnum = WSAGetLastError ();
	if (getpeername ((SOCKET)fd, addr, len) != SOCKET_ERROR)
	{
		WSASetLastError (errnum);
		return 0;
	}
	errno = WSAGetLastError ();
	return -1;
}


#undef getsockname
int winsock_getsockname (int fd, struct sockaddr *addr, socklen_t *len)
{
	int errnum;

	errnum = WSAGetLastError ();
	if (getsockname ((SOCKET)fd, addr, len) != SOCKET_ERROR)
	{
		WSASetLastError (errnum);
		return 0;
	}
	errno = WSAGetLastError ();
	return -1;
}


#undef gethostbyaddr
struct hostent *winsock_gethostbyaddr (const char *addr, int len,
						int type)
{
	int errnum;
	struct hostent *retval;

	errnum = WSAGetLastError ();
	retval = gethostbyaddr (addr, len, type);
	if (retval != NULL)
		WSASetLastError (errnum);
	else
		errno = WSAGetLastError ();

	return retval;
}


#undef gethostbyname
struct hostent *winsock_gethostbyname (const char *name)
{
	int errnum;
	struct hostent *retval;

	errnum = WSAGetLastError ();
	retval = gethostbyname (name);
	if (retval != NULL)
		WSASetLastError (errnum);
	else
		errno = WSAGetLastError ();

	return retval;
}


#undef inet_ntoa
char *winsock_inet_ntoa (struct in_addr in)
{
	int errnum;
	char *retval;

	errnum = WSAGetLastError ();
	retval = inet_ntoa (in);
	WSASetLastError (errnum);

	return retval;
}


#undef inet_addr
unsigned long winsock_inet_addr (const char *dotip)
{
	int errnum;
	unsigned long retval;

	errnum = WSAGetLastError ();
	retval = inet_addr (dotip);
	WSASetLastError (errnum);

	return retval;
}


#undef getservbyport
struct servent *winsock_getservbyport (int port, const char *proto)
{
	int errnum;
	struct servent *retval;

	errnum = WSAGetLastError ();
	retval = getservbyport (port, proto);
	if (retval != NULL)
		WSASetLastError (errnum);
	else
		errno = WSAGetLastError ();

	return retval;
}


#undef getservbyname
struct servent *winsock_getservbyname (const char *name, const char *proto)
{
	int errnum;
	struct servent *retval;

	errnum = WSAGetLastError ();
	retval = getservbyname (name, proto);
	if (retval != NULL)
		WSASetLastError (errnum);
	else
		errno = WSAGetLastError ();

	return retval;
}


uint16_t winsock_ntohs (uint16_t s)
{
	int errnum;
	u_short retval;

	errnum = WSAGetLastError ();
	WSANtohs (mysocket, (u_short)s, &retval);
	WSASetLastError (errnum);

	return (uint16_t)retval;
}
	

uint16_t winsock_htons (uint16_t s)
{
	int errnum;
	u_short retval;

	errnum = WSAGetLastError ();
	WSAHtons (mysocket, (u_short)s, &retval);
	WSASetLastError (errnum);

	return (uint16_t)retval;
}


uint32_t winsock_ntohl (uint32_t l)
{
	int errnum;
	u_long retval;

	errnum = WSAGetLastError ();
	WSANtohl (mysocket, (u_long)l, &retval);
	WSASetLastError (errnum);

	return (uint32_t)retval;
}


uint32_t winsock_htonl (uint32_t l)
{
	int errnum;
	u_long retval;

	errnum = WSAGetLastError ();
	WSAHtonl (mysocket, (u_long)l, &retval);
	WSASetLastError (errnum);

	return (uint32_t)retval;
}


int winsock_getaddrinfo (const char *node, const char *service,
                 const struct addrinfo *hints, struct addrinfo **res)
{
	typedef int (CALLBACK * GETADDRINFO) (const char *, const char *,
	                                      const struct addrinfo *,
	                                      struct addrinfo **);
	HINSTANCE wship6_module;
	GETADDRINFO ws2_getaddrinfo;
         
	wship6_module = LoadLibrary ("wship6.dll");
	if (wship6_module != NULL)
	{
		ws2_getaddrinfo = (GETADDRINFO)GetProcAddress (wship6_module,
		                                               "getaddrinfo");
		if (ws2_getaddrinfo != NULL)
		{
			int ret;

			ret = ws2_getaddrinfo (node, service, hints, res);
			FreeLibrary (wship6_module); /* is this wise ? */
			return ret;
		}
            
		FreeLibrary (wship6_module);
	}

	return stub_getaddrinfo (node, service, hints, res);
}


void winsock_freeaddrinfo (struct addrinfo *infos)
{
	typedef void (CALLBACK * FREEADDRINFO) (struct addrinfo *);
	HINSTANCE wship6_module;
	FREEADDRINFO ws2_freeaddrinfo;
     
	wship6_module = LoadLibrary ("wship6.dll");
	if (wship6_module != NULL)
	{
		ws2_freeaddrinfo = (FREEADDRINFO)GetProcAddress (wship6_module,
		                                                 "freeaddrinfo");

		/*
		 * NOTE: it is assumed that wship6.dll defines either both
		 * getaddrinfo and freeaddrinfo or none of them.
		 */
		if (ws2_freeaddrinfo != NULL)
		{
			ws2_freeaddrinfo (infos);
			FreeLibrary (wship6_module);
			return;
        }

		FreeLibrary (wship6_module);
	}
	stub_freeaddrinfo (infos);
}


int winsock_getnameinfo (const struct sockaddr *sa, int salen, char *host,
                         int hostlen, char *serv, int servlen, int flags)
{
	/*
	 * Here is the kind of kludge you need to keep binary compatibility among
	 * varying OS versions...
	 */
	typedef int (CALLBACK * GETNAMEINFO) (const struct sockaddr*, socklen_t,
	                                      char*, DWORD, char*, DWORD, int);
	HINSTANCE wship6_module;
	GETNAMEINFO ws2_getnameinfo;
     
	wship6_module = LoadLibrary ("wship6.dll");
	if( wship6_module != NULL )
	{
		ws2_getnameinfo = (GETNAMEINFO)GetProcAddress (wship6_module,
		                                               "getnameinfo");

		if (ws2_getnameinfo != NULL)
		{
			int ret;

			ret = ws2_getnameinfo (sa, salen, host, hostlen, serv, servlen, 
			                       flags);
			FreeLibrary (wship6_module);
			return ret;
		}

		FreeLibrary (wship6_module);
	}
	return stub_getnameinfo (sa, salen, host, hostlen, serv, servlen, flags);
}

static uid_t _uid = 1000; /* anything but 0, please */

int setuid (uid_t uid)
{
	_uid = uid;
	return 0;
}


uid_t getuid (void)
{
	return _uid;
}


static uid_t _euid = 0;

int seteuid (uid_t euid)
{
	_euid = euid;
	return 0;
}

uid_t geteuid (void)
{
	return _euid;
}


struct passwd *getpwnam (const char *username)
{
	return NULL;
}


struct passwd *getpwuid (uid_t uid)
{
	return NULL;
}


void openlog (const char *ident, int option, int facility)
{
	/* RegisterEventSource */
	fprintf (stderr,
		"WARNING: no system logging available for %s\n"
		"(requested facility number %d, option=0x%x)\n"
		"Any further logging information will be dropped.\n",
		ident, facility, option);
}


void
syslog (int priority, const char *fmt, ... )
{
	/* ReportEvent */
}


void closelog (void)
{
	/* DeregisterEventSource */
}


# include <stdarg.h>
void
vsyslog (int priority, const char *fmt, va_list ap)
{
	/* ReportEvent */
}


unsigned int sleep (unsigned int sec)
{
	Sleep (sec * 1000);
	return 0;
}


syntax highlighted by Code2HTML, v. 0.9.1