mirror of
https://git.do.srb2.org/KartKrew/Kart-Public.git
synced 2024-12-28 13:21:10 +00:00
455 lines
10 KiB
C
455 lines
10 KiB
C
// Emacs style mode select -*- C++ -*-
|
|
//-----------------------------------------------------------------------------
|
|
// Copyright (C) 1993-1996 by id Software, Inc.
|
|
// Portions Copyright (C) 2005 by Sonic Team Jr.
|
|
//
|
|
// 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.
|
|
//-----------------------------------------------------------------------------
|
|
/// \file
|
|
/// \brief KOS UDP network interface
|
|
|
|
#include "../../doomdef.h"
|
|
|
|
#include "../../i_system.h"
|
|
#include "../../d_event.h"
|
|
#include "../../d_net.h"
|
|
#include "../../m_argv.h"
|
|
|
|
#include "../../doomstat.h"
|
|
|
|
#include "../../i_net.h"
|
|
|
|
#include "../../z_zone.h"
|
|
|
|
#include "../../i_tcp.h"
|
|
|
|
#include <kos/net.h>
|
|
//#include <net/net_ipv4.h>
|
|
#define NET_NONE 0x00000000
|
|
#define NET_LOCAL 0x0100007F
|
|
#define NET_ANY 0xFFFFFFFF
|
|
|
|
#define MAXBANS 20
|
|
|
|
typedef struct
|
|
{
|
|
uint32 host;
|
|
uint16 port;
|
|
} IPaddress;
|
|
|
|
static IPaddress clientaddress[MAXNETNODES+1];
|
|
static boolean nodeconnected[MAXNETNODES+1];
|
|
|
|
static int mysocket = 0;
|
|
static boolean init_KOSUDP_driver = false;
|
|
|
|
static size_t numbans = 0;
|
|
static IPaddress banned[MAXBANS];
|
|
static boolean KOSUDP_bannednode[MAXNETNODES+1]; /// \note do we really need the +1?
|
|
|
|
static inline int net_udp_sendto(int sock, const uint8 *data, int size, uint16 rem_port, uint32 rem_addr)
|
|
{
|
|
uint8 dst_ip[4] = {((uint8*)(&(rem_addr)))[0],
|
|
((uint8*)(&(rem_addr)))[1],
|
|
((uint8*)(&(rem_addr)))[2],
|
|
((uint8*)(&(rem_addr)))[3]};
|
|
return net_udp_send_raw(net_default_dev, clientaddress[0].port, rem_port, dst_ip, data, size);
|
|
(void)sock;
|
|
}
|
|
|
|
static inline int net_udp_recvfrom(int sock, uint8 *buf, int size, uint16 *rem_port, uint32 *rem_addr)
|
|
{
|
|
return net_udp_recv(sock, buf, size);
|
|
(void)rem_port;
|
|
(void)rem_addr;
|
|
}
|
|
|
|
static const char *KOSUDP_AddrToStr(IPaddress* sk)
|
|
{
|
|
static char s[22]; // 255.255.255.255:65535
|
|
sprintf(s,"%d.%d.%d.%d:%d",
|
|
((uint8*)(&(sk->host)))[3],
|
|
((uint8*)(&(sk->host)))[2],
|
|
((uint8*)(&(sk->host)))[1],
|
|
((uint8*)(&(sk->host)))[0],
|
|
net_ntohs(sk->port));
|
|
return s;
|
|
}
|
|
|
|
static const char *KOSUDP_GetNodeAddress(int node)
|
|
{
|
|
if (!nodeconnected[node])
|
|
return NULL;
|
|
return KOSUDP_AddrToStr(&clientaddress[node]);
|
|
}
|
|
|
|
static const char *KOSUDP_GetBanAddress(size_t ban)
|
|
{
|
|
if (ban > numbans)
|
|
return NULL;
|
|
return KOSUDP_AddrToStr(&banned[ban]);
|
|
}
|
|
|
|
static boolean KOSUDP_cmpaddr(IPaddress* a, IPaddress* b)
|
|
{
|
|
return (a->host == b->host && (b->port == 0 || a->port == b->port));
|
|
}
|
|
|
|
static SINT8 getfreenode(void)
|
|
{
|
|
SINT8 j;
|
|
|
|
for (j = 0; j < MAXNETNODES; j++)
|
|
if (!nodeconnected[j])
|
|
{
|
|
nodeconnected[j] = true;
|
|
return j;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
static void KOSUDP_Get(void)
|
|
{
|
|
int size;
|
|
size_t i;
|
|
SINT8 j;
|
|
IPaddress temp = {clientaddress[BROADCASTADDR].host,clientaddress[BROADCASTADDR].port};
|
|
|
|
size = net_udp_recvfrom(mysocket,(char *)&doomcom->data, MAXPACKETLENGTH, &temp.port, &temp.host);
|
|
if (size == 0)
|
|
{
|
|
doomcom->remotenode = -1; // no packet
|
|
return;
|
|
}
|
|
|
|
// find remote node number
|
|
for (i = 0; i < MAXNETNODES; i++)
|
|
if (KOSUDP_cmpaddr(&temp, &(clientaddress[i])))
|
|
{
|
|
doomcom->remotenode = (INT16)i; // good packet from a game player
|
|
doomcom->datalength = (INT16)size;
|
|
return;
|
|
}
|
|
|
|
// not found
|
|
|
|
// find a free slot
|
|
j = getfreenode();
|
|
if (j > 0)
|
|
{
|
|
M_Memcpy(&clientaddress[j], &temp, sizeof (temp));
|
|
DEBFILE(va("New node detected: node:%d address:%s\n", j,
|
|
KOSUDP_GetNodeAddress(j)));
|
|
doomcom->remotenode = (INT16)j; // good packet from a game player
|
|
doomcom->datalength = (INT16)size;
|
|
// check if it's a banned dude so we can send a refusal later
|
|
for (i = 0; i < numbans; i++)
|
|
if (KOSUDP_cmpaddr(&temp, &banned[i]))
|
|
{
|
|
KOSUDP_bannednode[j] = true;
|
|
DEBFILE("This dude has been banned\n");
|
|
break;
|
|
}
|
|
if (i == numbans)
|
|
KOSUDP_bannednode[j] = false;
|
|
return;
|
|
}
|
|
|
|
DEBFILE("New node detected: No more free slots\n");
|
|
doomcom->remotenode = -1; // no packet
|
|
}
|
|
|
|
#if 0
|
|
static boolean KOSUDP_CanSend(void)
|
|
{
|
|
return true;
|
|
}
|
|
#endif
|
|
|
|
static void KOSUDP_Send(void)
|
|
{
|
|
const IPaddress *nodeinfo;
|
|
|
|
if (!doomcom->remotenode || !nodeconnected[doomcom->remotenode])
|
|
return;
|
|
|
|
nodeinfo = clientaddress + doomcom->remotenode;
|
|
|
|
if (net_udp_sendto(mysocket, (char *)&doomcom->data, doomcom->datalength, nodeinfo->port, nodeinfo->host) == -1)
|
|
{
|
|
CONS_Printf("KOSUDP: error sending data\n");
|
|
}
|
|
}
|
|
|
|
static void KOSUDP_FreeNodenum(int numnode)
|
|
{
|
|
// can't disconnect from self :)
|
|
if (!numnode)
|
|
return;
|
|
|
|
DEBFILE(va("Free node %d (%s)\n", numnode, KOSUDP_GetNodeAddress(numnode)));
|
|
|
|
nodeconnected[numnode] = false;
|
|
|
|
memset(&clientaddress[numnode], 0, sizeof (IPaddress));
|
|
}
|
|
|
|
static int KOSUDP_Socket(void)
|
|
{
|
|
int temp = 0;
|
|
uint16 portnum = 0;
|
|
const uint32 hostip = net_default_dev?net_ntohl(net_ipv4_address(net_default_dev->ip_addr)):NET_LOCAL;
|
|
//Hurdler: I'd like to put a server and a client on the same computer
|
|
//Logan: Me too
|
|
//BP: in fact for client we can use any free port we want i have read
|
|
// in some doc that connect in udp can do it for us...
|
|
//Alam: where?
|
|
if (M_CheckParm("-clientport"))
|
|
{
|
|
if (!M_IsNextParm())
|
|
I_Error("syntax: -clientport <portnum>");
|
|
portnum = net_ntohs(atoi(M_GetNextParm()));
|
|
}
|
|
else
|
|
portnum = net_ntohs(sock_port);
|
|
|
|
temp = net_udp_sock_open(portnum, hostip, portnum, NET_NONE);
|
|
if (temp)
|
|
{
|
|
int btemp = net_udp_sock_open(portnum, hostip, portnum, NET_ANY);
|
|
clientaddress[0].port = portnum;
|
|
clientaddress[0].host = NET_NONE;
|
|
if (btemp)
|
|
{
|
|
clientaddress[BROADCASTADDR].port = net_ntohs(sock_port);
|
|
clientaddress[BROADCASTADDR].host = NET_ANY;
|
|
}
|
|
else
|
|
{
|
|
CONS_Printf("KOSUDP: can't setup broadcast sock\n");
|
|
net_udp_sock_close(temp);
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CONS_Printf("KOSUDP: can't setup main sock\n");
|
|
return 0;
|
|
}
|
|
|
|
doomcom->extratics = 1; // internet is very high ping
|
|
|
|
return temp;
|
|
}
|
|
|
|
static void I_ShutdownKOSUDPDriver(void)
|
|
{
|
|
//net_shutdown();
|
|
init_KOSUDP_driver = false;
|
|
}
|
|
|
|
static void I_InitKOSUDPDriver(void)
|
|
{
|
|
if (init_KOSUDP_driver)
|
|
I_ShutdownKOSUDPDriver();
|
|
else
|
|
net_init();
|
|
D_SetDoomcom();
|
|
memset(&clientaddress,0,sizeof (clientaddress));
|
|
init_KOSUDP_driver = true;
|
|
}
|
|
|
|
static void KOSUDP_CloseSocket(void)
|
|
{
|
|
if (mysocket)
|
|
net_udp_sock_close(mysocket);
|
|
mysocket = 0;
|
|
}
|
|
|
|
static SINT8 KOSUDP_NetMakeNodewPort(const char *hostname, const char* port)
|
|
{
|
|
SINT8 newnode;
|
|
uint16 portnum = net_ntohs(sock_port);
|
|
|
|
if (port && !port[0])
|
|
portnum = net_ntohs((UINT16)atoi(port));
|
|
|
|
newnode = getfreenode();
|
|
if (newnode == -1)
|
|
return -1;
|
|
// find ip of the server
|
|
clientaddress[newnode].port = portnum;
|
|
clientaddress[newnode].host = inet_addr(hostname);
|
|
|
|
if (clientaddress[newnode].host == NET_NONE)
|
|
{
|
|
free(hostname);
|
|
return -1;
|
|
}
|
|
return newnode;
|
|
}
|
|
|
|
static boolean KOSUDP_OpenSocket(void)
|
|
{
|
|
size_t i;
|
|
|
|
memset(clientaddress, 0, sizeof (clientaddress));
|
|
|
|
for (i = 0; i < MAXNETNODES; i++)
|
|
nodeconnected[i] = false;
|
|
|
|
//CONS_Printf("KOSUDP Code starting up\n");
|
|
|
|
nodeconnected[0] = true; // always connected to self
|
|
nodeconnected[BROADCASTADDR] = true;
|
|
I_NetSend = KOSUDP_Send;
|
|
I_NetGet = KOSUDP_Get;
|
|
I_NetCloseSocket = KOSUDP_CloseSocket;
|
|
I_NetFreeNodenum = KOSUDP_FreeNodenum;
|
|
I_NetMakeNodewPort = KOSUDP_NetMakeNodewPort;
|
|
|
|
//I_NetCanSend = KOSUDP_CanSend;
|
|
|
|
// build the socket but close it first
|
|
KOSUDP_CloseSocket();
|
|
mysocket = KOSUDP_Socket();
|
|
|
|
if (mysocket)
|
|
{
|
|
#if 0
|
|
// for select
|
|
myset = SDLNet_AllocSocketSet(1);
|
|
if (!myset)
|
|
{
|
|
CONS_Printf("SDL_Net: %s",SDLNet_GetError());
|
|
return false;
|
|
}
|
|
if (SDLNet_UDP_AddSocket(myset,mysocket) == -1)
|
|
{
|
|
CONS_Printf("SDL_Net: %s",SDLNet_GetError());
|
|
return false;
|
|
}
|
|
#endif
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static boolean KOSUDP_Ban(int node)
|
|
{
|
|
if (numbans == MAXBANS)
|
|
return false;
|
|
|
|
M_Memcpy(&banned[numbans], &clientaddress[node], sizeof (IPaddress));
|
|
banned[numbans].port = 0'
|
|
numbans++;
|
|
return true;
|
|
}
|
|
|
|
static void KOSUDP_ClearBans(void)
|
|
{
|
|
numbans = 0;
|
|
}
|
|
|
|
//
|
|
// I_InitNetwork
|
|
// Only required for DOS, so this is more a dummy
|
|
//
|
|
boolean I_InitNetwork(void)
|
|
{
|
|
char serverhostname[255];
|
|
boolean ret = false;
|
|
//if (!M_CheckParm ("-kosnet"))
|
|
// return false;
|
|
// initilize the driver
|
|
I_InitKOSUDPDriver();
|
|
I_AddExitFunc(I_ShutdownKOSUDPDriver);
|
|
if (!init_KOSUDP_driver)
|
|
return false;
|
|
|
|
if (M_CheckParm("-udpport"))
|
|
{
|
|
if (M_IsNextParm())
|
|
sock_port = (UINT16)atoi(M_GetNextParm());
|
|
else
|
|
sock_port = 0;
|
|
}
|
|
|
|
// parse network game options,
|
|
if (M_CheckParm("-server") || dedicated)
|
|
{
|
|
server = true;
|
|
|
|
// If a number of clients (i.e. nodes) is specified, the server will wait for the clients
|
|
// to connect before starting.
|
|
// If no number is specified here, the server starts with 1 client, and others can join
|
|
// in-game.
|
|
// Since Boris has implemented join in-game, there is no actual need for specifying a
|
|
// particular number here.
|
|
// FIXME: for dedicated server, numnodes needs to be set to 0 upon start
|
|
/* if (M_IsNextParm())
|
|
doomcom->numnodes = (INT16)atoi(M_GetNextParm());
|
|
else */if (dedicated)
|
|
doomcom->numnodes = 0;
|
|
else
|
|
doomcom->numnodes = 1;
|
|
|
|
if (doomcom->numnodes < 0)
|
|
doomcom->numnodes = 0;
|
|
if (doomcom->numnodes > MAXNETNODES)
|
|
doomcom->numnodes = MAXNETNODES;
|
|
|
|
// server
|
|
servernode = 0;
|
|
// FIXME:
|
|
// ??? and now ?
|
|
// server on a big modem ??? 4*isdn
|
|
net_bandwidth = 16000;
|
|
hardware_MAXPACKETLENGTH = INETPACKETLENGTH;
|
|
|
|
ret = true;
|
|
}
|
|
else if (M_CheckParm("-connect"))
|
|
{
|
|
if (M_IsNextParm())
|
|
strcpy(serverhostname, M_GetNextParm());
|
|
else
|
|
serverhostname[0] = 0; // assuming server in the LAN, use broadcast to detect it
|
|
|
|
// server address only in ip
|
|
if (serverhostname[0])
|
|
{
|
|
COM_BufAddText("connect \"");
|
|
COM_BufAddText(serverhostname);
|
|
COM_BufAddText("\"\n");
|
|
|
|
// probably modem
|
|
hardware_MAXPACKETLENGTH = INETPACKETLENGTH;
|
|
}
|
|
else
|
|
{
|
|
// so we're on a LAN
|
|
COM_BufAddText("connect any\n");
|
|
|
|
net_bandwidth = 800000;
|
|
hardware_MAXPACKETLENGTH = MAXPACKETLENGTH;
|
|
}
|
|
}
|
|
|
|
I_NetOpenSocket = KOSUDP_OpenSocket;
|
|
I_Ban = KOSUDP_Ban;
|
|
I_ClearBans = KOSUDP_ClearBans;
|
|
I_GetNodeAddress = KOSUDP_GetNodeAddress;
|
|
I_GetBanAddress = KOSUDP_GetBanAddress;
|
|
bannednode = KOSUDP_bannednode;
|
|
|
|
return ret;
|
|
}
|