quakeforge-old/uquake/net_wins.c
Jeff Teunissen c3f5581b0a Created new subdir: uquake. Pick your favorite U word for the meaning --
Unchained, Ultimate, Ultra, Up Yours, Underworld, Underground, Unified,
Unity, etc. You know the drill.

This takes care of the "standalone" problem with the wrong name, and the
recent snafu with multiple developers working on the same files
simultaneously...expect me (and probably others) to start locking dirs when
updates are taking place.

And yes, this update is really as large as it looks. Software only at the
moment, but I will have the makefile updated to build the GL builds as
well.
1999-12-26 13:51:52 +00:00

575 lines
14 KiB
C

/*
Copyright (C) 1996-1997 Id Software, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
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, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// net_wins.c
#include "quakedef.h"
#include "winquake.h"
extern cvar_t hostname;
#define MAXHOSTNAMELEN 256
static int net_acceptsocket = -1; // socket for fielding new connections
static int net_controlsocket;
static int net_broadcastsocket = 0;
static struct qsockaddr broadcastaddr;
static unsigned long myAddr;
qboolean winsock_lib_initialized;
int (PASCAL FAR *pWSAStartup)(WORD wVersionRequired, LPWSADATA lpWSAData);
int (PASCAL FAR *pWSACleanup)(void);
int (PASCAL FAR *pWSAGetLastError)(void);
SOCKET (PASCAL FAR *psocket)(int af, int type, int protocol);
int (PASCAL FAR *pioctlsocket)(SOCKET s, long cmd, u_long FAR *argp);
int (PASCAL FAR *psetsockopt)(SOCKET s, int level, int optname,
const char FAR * optval, int optlen);
int (PASCAL FAR *precvfrom)(SOCKET s, char FAR * buf, int len, int flags,
struct sockaddr FAR *from, int FAR * fromlen);
int (PASCAL FAR *psendto)(SOCKET s, const char FAR * buf, int len, int flags,
const struct sockaddr FAR *to, int tolen);
int (PASCAL FAR *pclosesocket)(SOCKET s);
int (PASCAL FAR *pgethostname)(char FAR * name, int namelen);
struct hostent FAR * (PASCAL FAR *pgethostbyname)(const char FAR * name);
struct hostent FAR * (PASCAL FAR *pgethostbyaddr)(const char FAR * addr,
int len, int type);
int (PASCAL FAR *pgetsockname)(SOCKET s, struct sockaddr FAR *name,
int FAR * namelen);
#include "net_wins.h"
int winsock_initialized = 0;
WSADATA winsockdata;
//=============================================================================
static double blocktime;
BOOL PASCAL FAR BlockingHook(void)
{
MSG msg;
BOOL ret;
if ((Sys_DoubleTime() - blocktime) > 2.0)
{
WSACancelBlockingCall();
return FALSE;
}
/* get the next message, if any */
ret = (BOOL) PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
/* if we got one, process it */
if (ret) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
/* TRUE if we got a message */
return ret;
}
void WINS_GetLocalAddress()
{
struct hostent *local = NULL;
char buff[MAXHOSTNAMELEN];
unsigned long addr;
if (myAddr != INADDR_ANY)
return;
if (pgethostname(buff, MAXHOSTNAMELEN) == SOCKET_ERROR)
return;
blocktime = Sys_DoubleTime();
WSASetBlockingHook(BlockingHook);
local = pgethostbyname(buff);
WSAUnhookBlockingHook();
if (local == NULL)
return;
myAddr = *(int *)local->h_addr_list[0];
addr = ntohl(myAddr);
sprintf(my_tcpip_address, "%d.%d.%d.%d", (addr >> 24) & 0xff, (addr >> 16) & 0xff, (addr >> 8) & 0xff, addr & 0xff);
}
int WINS_Init (void)
{
int i;
char buff[MAXHOSTNAMELEN];
char *p;
int r;
WORD wVersionRequested;
HINSTANCE hInst;
// initialize the Winsock function vectors (we do this instead of statically linking
// so we can run on Win 3.1, where there isn't necessarily Winsock)
hInst = LoadLibrary("wsock32.dll");
if (hInst == NULL)
{
Con_SafePrintf ("Failed to load winsock.dll\n");
winsock_lib_initialized = false;
return -1;
}
winsock_lib_initialized = true;
pWSAStartup = (void *)GetProcAddress(hInst, "WSAStartup");
pWSACleanup = (void *)GetProcAddress(hInst, "WSACleanup");
pWSAGetLastError = (void *)GetProcAddress(hInst, "WSAGetLastError");
psocket = (void *)GetProcAddress(hInst, "socket");
pioctlsocket = (void *)GetProcAddress(hInst, "ioctlsocket");
psetsockopt = (void *)GetProcAddress(hInst, "setsockopt");
precvfrom = (void *)GetProcAddress(hInst, "recvfrom");
psendto = (void *)GetProcAddress(hInst, "sendto");
pclosesocket = (void *)GetProcAddress(hInst, "closesocket");
pgethostname = (void *)GetProcAddress(hInst, "gethostname");
pgethostbyname = (void *)GetProcAddress(hInst, "gethostbyname");
pgethostbyaddr = (void *)GetProcAddress(hInst, "gethostbyaddr");
pgetsockname = (void *)GetProcAddress(hInst, "getsockname");
if (!pWSAStartup || !pWSACleanup || !pWSAGetLastError ||
!psocket || !pioctlsocket || !psetsockopt ||
!precvfrom || !psendto || !pclosesocket ||
!pgethostname || !pgethostbyname || !pgethostbyaddr ||
!pgetsockname)
{
Con_SafePrintf ("Couldn't GetProcAddress from winsock.dll\n");
return -1;
}
if (COM_CheckParm ("-noudp"))
return -1;
if (winsock_initialized == 0)
{
wVersionRequested = MAKEWORD(1, 1);
r = pWSAStartup (MAKEWORD(1, 1), &winsockdata);
if (r)
{
Con_SafePrintf ("Winsock initialization failed.\n");
return -1;
}
}
winsock_initialized++;
// determine my name
if (pgethostname(buff, MAXHOSTNAMELEN) == SOCKET_ERROR)
{
Con_DPrintf ("Winsock TCP/IP Initialization failed.\n");
if (--winsock_initialized == 0)
pWSACleanup ();
return -1;
}
// if the quake hostname isn't set, set it to the machine name
if (Q_strcmp(hostname.string, "UNNAMED") == 0)
{
// see if it's a text IP address (well, close enough)
for (p = buff; *p; p++)
if ((*p < '0' || *p > '9') && *p != '.')
break;
// if it is a real name, strip off the domain; we only want the host
if (*p)
{
for (i = 0; i < 15; i++)
if (buff[i] == '.')
break;
buff[i] = 0;
}
Cvar_Set ("hostname", buff);
}
i = COM_CheckParm ("-ip");
if (i)
{
if (i < com_argc-1)
{
myAddr = inet_addr(com_argv[i+1]);
if (myAddr == INADDR_NONE)
Sys_Error ("%s is not a valid IP address", com_argv[i+1]);
strcpy(my_tcpip_address, com_argv[i+1]);
}
else
{
Sys_Error ("NET_Init: you must specify an IP address after -ip");
}
}
else
{
myAddr = INADDR_ANY;
strcpy(my_tcpip_address, "INADDR_ANY");
}
if ((net_controlsocket = WINS_OpenSocket (0)) == -1)
{
Con_Printf("WINS_Init: Unable to open control socket\n");
if (--winsock_initialized == 0)
pWSACleanup ();
return -1;
}
((struct sockaddr_in *)&broadcastaddr)->sin_family = AF_INET;
((struct sockaddr_in *)&broadcastaddr)->sin_addr.s_addr = INADDR_BROADCAST;
((struct sockaddr_in *)&broadcastaddr)->sin_port = htons((unsigned short)net_hostport);
Con_Printf("Winsock TCP/IP Initialized\n");
tcpipAvailable = true;
return net_controlsocket;
}
//=============================================================================
void WINS_Shutdown (void)
{
WINS_Listen (false);
WINS_CloseSocket (net_controlsocket);
if (--winsock_initialized == 0)
pWSACleanup ();
}
//=============================================================================
void WINS_Listen (qboolean state)
{
// enable listening
if (state)
{
if (net_acceptsocket != -1)
return;
WINS_GetLocalAddress();
if ((net_acceptsocket = WINS_OpenSocket (net_hostport)) == -1)
Sys_Error ("WINS_Listen: Unable to open accept socket\n");
return;
}
// disable listening
if (net_acceptsocket == -1)
return;
WINS_CloseSocket (net_acceptsocket);
net_acceptsocket = -1;
}
//=============================================================================
int WINS_OpenSocket (int port)
{
int newsocket;
struct sockaddr_in address;
u_long _true = 1;
if ((newsocket = psocket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
return -1;
if (pioctlsocket (newsocket, FIONBIO, &_true) == -1)
goto ErrorReturn;
address.sin_family = AF_INET;
address.sin_addr.s_addr = myAddr;
address.sin_port = htons((unsigned short)port);
if( bind (newsocket, (void *)&address, sizeof(address)) == 0)
return newsocket;
Sys_Error ("Unable to bind to %s", WINS_AddrToString((struct qsockaddr *)&address));
ErrorReturn:
pclosesocket (newsocket);
return -1;
}
//=============================================================================
int WINS_CloseSocket (int socket)
{
if (socket == net_broadcastsocket)
net_broadcastsocket = 0;
return pclosesocket (socket);
}
//=============================================================================
/*
============
PartialIPAddress
this lets you type only as much of the net address as required, using
the local network components to fill in the rest
============
*/
static int PartialIPAddress (char *in, struct qsockaddr *hostaddr)
{
char buff[256];
char *b;
int addr;
int num;
int mask;
int run;
int port;
buff[0] = '.';
b = buff;
strcpy(buff+1, in);
if (buff[1] == '.')
b++;
addr = 0;
mask=-1;
while (*b == '.')
{
b++;
num = 0;
run = 0;
while (!( *b < '0' || *b > '9'))
{
num = num*10 + *b++ - '0';
if (++run > 3)
return -1;
}
if ((*b < '0' || *b > '9') && *b != '.' && *b != ':' && *b != 0)
return -1;
if (num < 0 || num > 255)
return -1;
mask<<=8;
addr = (addr<<8) + num;
}
if (*b++ == ':')
port = Q_atoi(b);
else
port = net_hostport;
hostaddr->sa_family = AF_INET;
((struct sockaddr_in *)hostaddr)->sin_port = htons((short)port);
((struct sockaddr_in *)hostaddr)->sin_addr.s_addr = (myAddr & htonl(mask)) | htonl(addr);
return 0;
}
//=============================================================================
int WINS_Connect (int socket, struct qsockaddr *addr)
{
return 0;
}
//=============================================================================
int WINS_CheckNewConnections (void)
{
char buf[4096];
if (net_acceptsocket == -1)
return -1;
if (precvfrom (net_acceptsocket, buf, sizeof(buf), MSG_PEEK, NULL, NULL) > 0)
{
return net_acceptsocket;
}
return -1;
}
//=============================================================================
int WINS_Read (int socket, byte *buf, int len, struct qsockaddr *addr)
{
int addrlen = sizeof (struct qsockaddr);
int ret;
ret = precvfrom (socket, buf, len, 0, (struct sockaddr *)addr, &addrlen);
if (ret == -1)
{
int errno = pWSAGetLastError();
if (errno == WSAEWOULDBLOCK || errno == WSAECONNREFUSED)
return 0;
}
return ret;
}
//=============================================================================
int WINS_MakeSocketBroadcastCapable (int socket)
{
int i = 1;
// make this socket broadcast capable
if (psetsockopt(socket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i)) < 0)
return -1;
net_broadcastsocket = socket;
return 0;
}
//=============================================================================
int WINS_Broadcast (int socket, byte *buf, int len)
{
int ret;
if (socket != net_broadcastsocket)
{
if (net_broadcastsocket != 0)
Sys_Error("Attempted to use multiple broadcasts sockets\n");
WINS_GetLocalAddress();
ret = WINS_MakeSocketBroadcastCapable (socket);
if (ret == -1)
{
Con_Printf("Unable to make socket broadcast capable\n");
return ret;
}
}
return WINS_Write (socket, buf, len, &broadcastaddr);
}
//=============================================================================
int WINS_Write (int socket, byte *buf, int len, struct qsockaddr *addr)
{
int ret;
ret = psendto (socket, buf, len, 0, (struct sockaddr *)addr, sizeof(struct qsockaddr));
if (ret == -1)
if (pWSAGetLastError() == WSAEWOULDBLOCK)
return 0;
return ret;
}
//=============================================================================
char *WINS_AddrToString (struct qsockaddr *addr)
{
static char buffer[22];
int haddr;
haddr = ntohl(((struct sockaddr_in *)addr)->sin_addr.s_addr);
sprintf(buffer, "%d.%d.%d.%d:%d", (haddr >> 24) & 0xff, (haddr >> 16) & 0xff, (haddr >> 8) & 0xff, haddr & 0xff, ntohs(((struct sockaddr_in *)addr)->sin_port));
return buffer;
}
//=============================================================================
int WINS_StringToAddr (char *string, struct qsockaddr *addr)
{
int ha1, ha2, ha3, ha4, hp;
int ipaddr;
sscanf(string, "%d.%d.%d.%d:%d", &ha1, &ha2, &ha3, &ha4, &hp);
ipaddr = (ha1 << 24) | (ha2 << 16) | (ha3 << 8) | ha4;
addr->sa_family = AF_INET;
((struct sockaddr_in *)addr)->sin_addr.s_addr = htonl(ipaddr);
((struct sockaddr_in *)addr)->sin_port = htons((unsigned short)hp);
return 0;
}
//=============================================================================
int WINS_GetSocketAddr (int socket, struct qsockaddr *addr)
{
int addrlen = sizeof(struct qsockaddr);
unsigned int a;
Q_memset(addr, 0, sizeof(struct qsockaddr));
pgetsockname(socket, (struct sockaddr *)addr, &addrlen);
a = ((struct sockaddr_in *)addr)->sin_addr.s_addr;
if (a == 0 || a == inet_addr("127.0.0.1"))
((struct sockaddr_in *)addr)->sin_addr.s_addr = myAddr;
return 0;
}
//=============================================================================
int WINS_GetNameFromAddr (struct qsockaddr *addr, char *name)
{
struct hostent *hostentry;
hostentry = pgethostbyaddr ((char *)&((struct sockaddr_in *)addr)->sin_addr, sizeof(struct in_addr), AF_INET);
if (hostentry)
{
Q_strncpy (name, (char *)hostentry->h_name, NET_NAMELEN - 1);
return 0;
}
Q_strcpy (name, WINS_AddrToString (addr));
return 0;
}
//=============================================================================
int WINS_GetAddrFromName(char *name, struct qsockaddr *addr)
{
struct hostent *hostentry;
if (name[0] >= '0' && name[0] <= '9')
return PartialIPAddress (name, addr);
hostentry = pgethostbyname (name);
if (!hostentry)
return -1;
addr->sa_family = AF_INET;
((struct sockaddr_in *)addr)->sin_port = htons((unsigned short)net_hostport);
((struct sockaddr_in *)addr)->sin_addr.s_addr = *(int *)hostentry->h_addr_list[0];
return 0;
}
//=============================================================================
int WINS_AddrCompare (struct qsockaddr *addr1, struct qsockaddr *addr2)
{
if (addr1->sa_family != addr2->sa_family)
return -1;
if (((struct sockaddr_in *)addr1)->sin_addr.s_addr != ((struct sockaddr_in *)addr2)->sin_addr.s_addr)
return -1;
if (((struct sockaddr_in *)addr1)->sin_port != ((struct sockaddr_in *)addr2)->sin_port)
return 1;
return 0;
}
//=============================================================================
int WINS_GetSocketPort (struct qsockaddr *addr)
{
return ntohs(((struct sockaddr_in *)addr)->sin_port);
}
int WINS_SetSocketPort (struct qsockaddr *addr, int port)
{
((struct sockaddr_in *)addr)->sin_port = htons((unsigned short)port);
return 0;
}
//=============================================================================