2008-11-11 13:24:05 +00:00
|
|
|
|
/*
|
|
|
|
|
* "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman
|
|
|
|
|
* Ken Silverman's official web site: "http://www.advsys.net/ken"
|
|
|
|
|
* See the included license file "BUILDLIC.TXT" for license info.
|
|
|
|
|
* This file has been modified from Ken Silverman's original release
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <stdarg.h>
|
|
|
|
|
#include <ctype.h>
|
|
|
|
|
#include <time.h>
|
|
|
|
|
|
|
|
|
|
#include "mmulti_unstable.h"
|
2008-11-12 04:16:41 +00:00
|
|
|
|
// #include <enet/enet.h>
|
2008-11-11 13:24:05 +00:00
|
|
|
|
#include "compat.h"
|
2008-11-11 13:45:12 +00:00
|
|
|
|
#include "baselayer.h"
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
|
|
|
|
//STL
|
|
|
|
|
//#include <vector>
|
|
|
|
|
//#include "buildqueue.h"
|
|
|
|
|
|
|
|
|
|
// #include "platform.h"
|
|
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
|
#define PLATFORM_WIN32 1
|
|
|
|
|
#else
|
|
|
|
|
#define PLATFORM_UNIX 1
|
2009-07-24 02:31:34 +00:00
|
|
|
|
|
|
|
|
|
#include <sys/time.h>
|
|
|
|
|
static int32_t GetTickCount(void)
|
|
|
|
|
{
|
|
|
|
|
struct timeval tv;
|
|
|
|
|
int32_t ti;
|
|
|
|
|
if (gettimeofday(&tv,NULL) < 0) return 0;
|
|
|
|
|
// tv is sec.usec, GTC gives msec
|
|
|
|
|
ti = tv.tv_sec * 1000;
|
|
|
|
|
ti += tv.tv_usec / 1000;
|
|
|
|
|
return ti;
|
|
|
|
|
}
|
2008-11-11 13:24:05 +00:00
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#define UDP_NETWORKING 1
|
|
|
|
|
|
|
|
|
|
#include "pragmas.h"
|
|
|
|
|
|
|
|
|
|
#define MAXPLAYERS 16
|
|
|
|
|
#define BAKSIZ 16384
|
|
|
|
|
#define SIMULATEERRORS 0
|
|
|
|
|
#define SHOWSENDPACKETS 0
|
|
|
|
|
#define SHOWGETPACKETS 0
|
|
|
|
|
#define PRINTERRORS 0
|
|
|
|
|
|
2009-01-09 09:29:17 +00:00
|
|
|
|
#define updatecrc16(crc,dat) crc = (((crc<<8)&65535)^crctable[((((uint16_t)crc)>>8)&65535)^dat])
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
2009-01-09 09:29:17 +00:00
|
|
|
|
static int32_t incnt[MAXPLAYERS], outcntplc[MAXPLAYERS], outcntend[MAXPLAYERS];
|
2008-11-11 13:24:05 +00:00
|
|
|
|
static char errorgotnum[MAXPLAYERS];
|
|
|
|
|
static char errorfixnum[MAXPLAYERS];
|
|
|
|
|
static char errorresendnum[MAXPLAYERS];
|
|
|
|
|
#if (PRINTERRORS)
|
2008-11-12 04:16:41 +00:00
|
|
|
|
static char lasterrorgotnum[MAXPLAYERS];
|
2008-11-11 13:24:05 +00:00
|
|
|
|
#endif
|
|
|
|
|
|
2009-01-09 09:29:17 +00:00
|
|
|
|
int32_t crctable[256];
|
|
|
|
|
int32_t tmpmax[8]; //addfaz variable addition (you could probs think of something better)
|
|
|
|
|
int32_t itmp = 0; //addfaz router fix STUN
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
2009-01-10 07:38:50 +00:00
|
|
|
|
static uint8_t lastpacket[576];
|
|
|
|
|
char inlastpacket = 0;
|
2009-01-09 09:29:17 +00:00
|
|
|
|
static int32_t lastpacketfrom, lastpacketleng;
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
2009-01-09 09:29:17 +00:00
|
|
|
|
extern int32_t totalclock; /* MUST EXTERN 1 ANNOYING VARIABLE FROM GAME */
|
|
|
|
|
static int32_t timeoutcount = 60, resendagaincount = 4, lastsendtime[MAXPLAYERS];
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
2009-01-09 09:29:17 +00:00
|
|
|
|
int32_t natfree; //NatFree mode flag
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
2009-01-09 09:29:17 +00:00
|
|
|
|
static int16_t bakpacketptr[MAXPLAYERS][256], bakpacketlen[MAXPLAYERS][256];
|
2009-01-10 07:38:50 +00:00
|
|
|
|
static uint16_t bakpacketbuf[BAKSIZ];
|
2009-01-09 09:29:17 +00:00
|
|
|
|
static int32_t bakpacketplc = 0;
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
2009-01-09 09:29:17 +00:00
|
|
|
|
int32_t myconnectindex, numplayers;
|
|
|
|
|
int32_t connecthead, connectpoint2[MAXPLAYERS];
|
2008-11-11 13:24:05 +00:00
|
|
|
|
char syncstate = 0;
|
|
|
|
|
|
|
|
|
|
#define MAXPACKETSIZE 2048
|
2008-11-20 14:06:36 +00:00
|
|
|
|
#define PACKET_START_GAME 0x1337
|
|
|
|
|
|
2009-01-10 07:38:50 +00:00
|
|
|
|
enum commit_cmd_t
|
|
|
|
|
{
|
|
|
|
|
COMMIT_CMD_SEND = 1,
|
|
|
|
|
COMMIT_CMD_GET = 2,
|
|
|
|
|
COMMIT_CMD_SENDTOALL = 3,
|
|
|
|
|
COMMIT_CMD_SENDTOALLOTHERS = 4,
|
|
|
|
|
COMMIT_CMD_SCORE = 5,
|
|
|
|
|
};
|
|
|
|
|
|
2009-01-09 09:29:17 +00:00
|
|
|
|
typedef struct gcomtype_t
|
2008-11-11 13:24:05 +00:00
|
|
|
|
{
|
2009-01-09 09:29:17 +00:00
|
|
|
|
int16_t command; /* 1-send, 2-get */
|
|
|
|
|
int16_t other; /* dest for send, set by get (-1 = no packet) */
|
|
|
|
|
int16_t numbytes;
|
|
|
|
|
int16_t myconnectindex;
|
|
|
|
|
int16_t numplayers;
|
|
|
|
|
int16_t filler;
|
2008-11-12 04:16:41 +00:00
|
|
|
|
char buffer[MAXPACKETSIZE];
|
2008-11-11 13:24:05 +00:00
|
|
|
|
} gcomtype;
|
|
|
|
|
static gcomtype *gcom;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
//
|
|
|
|
|
// Packet queue data structs
|
|
|
|
|
//
|
|
|
|
|
typedef struct packet_wrapper
|
|
|
|
|
{
|
|
|
|
|
unsigned long packetnumber;
|
|
|
|
|
gcomtype packet;
|
|
|
|
|
} PACKETWRAPPER;
|
|
|
|
|
|
|
|
|
|
typedef PACKETWRAPPER packet_buffer;
|
|
|
|
|
|
|
|
|
|
unsigned long currentpacketnumber[MAXPLAYERS];
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Packet Buffer
|
|
|
|
|
//
|
|
|
|
|
packet_buffer pBuff[256];
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
2008-11-12 04:16:41 +00:00
|
|
|
|
typedef struct
|
2008-11-11 13:24:05 +00:00
|
|
|
|
{
|
2009-01-09 09:29:17 +00:00
|
|
|
|
char buffer[MAXPACKETSIZE];
|
2008-11-11 13:24:05 +00:00
|
|
|
|
}PACKET;
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
//typedef std::vector<PACKET> PacketQueue;
|
|
|
|
|
|
2009-01-09 09:29:17 +00:00
|
|
|
|
static struct allowed_addr_t
|
2008-11-20 14:06:36 +00:00
|
|
|
|
{
|
2009-01-09 09:29:17 +00:00
|
|
|
|
int32_t host;
|
|
|
|
|
uint16_t port;
|
2008-11-20 14:06:36 +00:00
|
|
|
|
} allowed_addresses[MAXPLAYERS]; /* only respond to these IPs. */
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
|
|
|
|
// Queue of out going packets.
|
|
|
|
|
//PacketQueue outgoingPacketQueue;
|
|
|
|
|
//outgoingPacketQueue.reserve(128);
|
|
|
|
|
|
2009-01-09 09:29:17 +00:00
|
|
|
|
gcomtype *init_network_transport(int32_t argc, char **argv);
|
2008-11-11 13:24:05 +00:00
|
|
|
|
void deinit_network_transport(gcomtype *gcom);
|
|
|
|
|
//void callcommit(void);
|
2009-01-09 09:29:17 +00:00
|
|
|
|
void mmulti_dosendpackets(int32_t other);
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
|
|
|
|
|
2009-04-29 06:20:07 +00:00
|
|
|
|
static void initcrc(void)
|
2008-11-11 13:24:05 +00:00
|
|
|
|
{
|
2009-01-09 09:29:17 +00:00
|
|
|
|
int32_t i, j, k, a;
|
2008-11-12 04:16:41 +00:00
|
|
|
|
|
2009-02-19 16:47:54 +00:00
|
|
|
|
for (j=0; j<256; j++) /* Calculate CRC table */
|
2008-11-12 04:16:41 +00:00
|
|
|
|
{
|
|
|
|
|
k = (j<<8); a = 0;
|
2009-02-19 16:47:54 +00:00
|
|
|
|
for (i=7; i>=0; i--)
|
2008-11-12 04:16:41 +00:00
|
|
|
|
{
|
|
|
|
|
if (((k^a)&0x8000) > 0)
|
|
|
|
|
a = ((a<<1)&65535) ^ 0x1021; /* 0x1021 = genpoly */
|
|
|
|
|
else
|
|
|
|
|
a = ((a<<1)&65535);
|
|
|
|
|
k = ((k<<1)&65535);
|
|
|
|
|
}
|
|
|
|
|
crctable[j] = (a&65535);
|
|
|
|
|
}
|
2008-11-11 13:24:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2009-01-09 09:29:17 +00:00
|
|
|
|
int32_t getcrc(char *buffer, int32_t bufleng)
|
2008-11-11 13:24:05 +00:00
|
|
|
|
{
|
2009-01-09 09:29:17 +00:00
|
|
|
|
int32_t i, j;
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
2008-11-12 04:16:41 +00:00
|
|
|
|
j = 0;
|
2009-02-19 16:47:54 +00:00
|
|
|
|
for (i=bufleng-1; i>=0; i--) updatecrc16(j,buffer[i]);
|
2008-11-12 04:16:41 +00:00
|
|
|
|
return(j&65535);
|
2008-11-11 13:24:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
2009-01-09 09:29:17 +00:00
|
|
|
|
void mmulti_initmultiplayers(int32_t argc, char **argv)
|
2008-11-11 13:24:05 +00:00
|
|
|
|
{
|
2009-01-09 09:29:17 +00:00
|
|
|
|
int32_t i;
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
2008-11-11 13:45:12 +00:00
|
|
|
|
UNREFERENCED_PARAMETER(argc);
|
|
|
|
|
|
2008-11-12 04:16:41 +00:00
|
|
|
|
initcrc();
|
2009-02-19 16:47:54 +00:00
|
|
|
|
for (i=0; i<MAXPLAYERS; i++)
|
2008-11-12 04:16:41 +00:00
|
|
|
|
{
|
|
|
|
|
incnt[i] = 0L;
|
|
|
|
|
outcntplc[i] = 0L;
|
|
|
|
|
outcntend[i] = 0L;
|
|
|
|
|
bakpacketlen[i][255] = -1;
|
2008-11-20 14:06:36 +00:00
|
|
|
|
allowed_addresses[i].host = 0;
|
|
|
|
|
allowed_addresses[i].port = 0;
|
2008-11-12 04:16:41 +00:00
|
|
|
|
}
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
2008-11-12 04:16:41 +00:00
|
|
|
|
// clear out the packet ordering
|
2008-11-11 13:24:05 +00:00
|
|
|
|
// memset(¤tpacketnumber, 0, sizeof(unsigned long) * MAXPLAYERS);
|
|
|
|
|
#if 0
|
2008-11-12 04:16:41 +00:00
|
|
|
|
for (i = argc - 1; i > 0; i--)
|
2008-11-11 13:24:05 +00:00
|
|
|
|
{
|
|
|
|
|
const char *arg = argv[i];
|
|
|
|
|
char ch = *arg;
|
|
|
|
|
if ((ch == '-') || (ch == '/'))
|
|
|
|
|
{
|
2008-11-12 04:16:41 +00:00
|
|
|
|
if (Bstrcasecmp(arg + 1, "net") == 0)
|
2008-11-11 13:24:05 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2008-11-12 22:28:02 +00:00
|
|
|
|
#endif
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
2008-11-12 22:28:02 +00:00
|
|
|
|
if (!argc)
|
2008-11-12 04:16:41 +00:00
|
|
|
|
{
|
2009-03-14 02:55:39 +00:00
|
|
|
|
// initprintf("network: No configuration file specified!\n");
|
2008-11-12 04:16:41 +00:00
|
|
|
|
numplayers = 1; myconnectindex = 0;
|
|
|
|
|
connecthead = 0; connectpoint2[0] = -1;
|
|
|
|
|
return;
|
|
|
|
|
}
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
2008-11-14 08:22:57 +00:00
|
|
|
|
gcom = init_network_transport(argc, argv);
|
2008-11-11 13:24:05 +00:00
|
|
|
|
if (gcom == NULL)
|
2008-11-12 04:16:41 +00:00
|
|
|
|
{
|
2008-11-11 13:24:05 +00:00
|
|
|
|
initprintf("Network transport initialization failed. Aborting...\n");
|
2008-11-14 08:22:57 +00:00
|
|
|
|
numplayers = 1; myconnectindex = 0;
|
|
|
|
|
connecthead = 0; connectpoint2[0] = -1;
|
|
|
|
|
return;
|
2008-11-12 04:16:41 +00:00
|
|
|
|
}
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
2008-11-12 04:16:41 +00:00
|
|
|
|
numplayers = gcom->numplayers;
|
|
|
|
|
myconnectindex = gcom->myconnectindex-1;
|
2008-11-11 13:24:05 +00:00
|
|
|
|
#if (SIMULATEERRORS != 0)
|
2008-11-12 04:16:41 +00:00
|
|
|
|
srand(myconnectindex*24572457+345356);
|
2008-11-11 13:24:05 +00:00
|
|
|
|
#endif
|
2008-11-12 04:16:41 +00:00
|
|
|
|
connecthead = 0;
|
2009-02-19 16:47:54 +00:00
|
|
|
|
for (i=0; i<numplayers-1; i++) connectpoint2[i] = i+1;
|
2008-11-12 04:16:41 +00:00
|
|
|
|
connectpoint2[numplayers-1] = -1;
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
2009-02-19 16:47:54 +00:00
|
|
|
|
for (i=0; i<numplayers; i++) lastsendtime[i] = totalclock;
|
2008-11-11 13:24:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2009-01-09 09:29:17 +00:00
|
|
|
|
void mmulti_dosendpackets(int32_t other)
|
2008-11-11 13:24:05 +00:00
|
|
|
|
{
|
2009-01-09 09:29:17 +00:00
|
|
|
|
int32_t i, j, k, messleng;
|
|
|
|
|
uint16_t dacrc;
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
2008-11-12 04:16:41 +00:00
|
|
|
|
if (outcntplc[other] == outcntend[other]) return;
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
|
|
|
|
#if (PRINTERRORS)
|
2008-11-12 04:16:41 +00:00
|
|
|
|
if (errorgotnum[other] > lasterrorgotnum[other])
|
|
|
|
|
{
|
|
|
|
|
lasterrorgotnum[other]++;
|
|
|
|
|
initprintf(" MeWant %ld",incnt[other]&255);
|
|
|
|
|
}
|
2008-11-11 13:24:05 +00:00
|
|
|
|
#endif
|
|
|
|
|
|
2008-11-12 04:16:41 +00:00
|
|
|
|
if (outcntplc[other]+1 == outcntend[other])
|
|
|
|
|
{ /* Send 1 sub-packet */
|
|
|
|
|
k = 0;
|
|
|
|
|
gcom->buffer[k++] = (outcntplc[other]&255);
|
|
|
|
|
gcom->buffer[k++] = (errorgotnum[other]&7)+((errorresendnum[other]&7)<<3);
|
|
|
|
|
gcom->buffer[k++] = (incnt[other]&255);
|
|
|
|
|
|
|
|
|
|
j = bakpacketptr[other][outcntplc[other]&255];
|
|
|
|
|
messleng = bakpacketlen[other][outcntplc[other]&255];
|
2009-02-19 16:47:54 +00:00
|
|
|
|
for (i=0; i<messleng; i++)
|
2008-11-12 04:16:41 +00:00
|
|
|
|
gcom->buffer[k++] = bakpacketbuf[(i+j)&(BAKSIZ-1)];
|
|
|
|
|
outcntplc[other]++;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{ /* Send 2 sub-packets */
|
|
|
|
|
k = 0;
|
|
|
|
|
gcom->buffer[k++] = (outcntplc[other]&255);
|
|
|
|
|
gcom->buffer[k++] = (errorgotnum[other]&7)+((errorresendnum[other]&7)<<3)+128;
|
|
|
|
|
gcom->buffer[k++] = (incnt[other]&255);
|
|
|
|
|
|
|
|
|
|
/* First half-packet */
|
|
|
|
|
j = bakpacketptr[other][outcntplc[other]&255];
|
|
|
|
|
messleng = bakpacketlen[other][outcntplc[other]&255];
|
2009-01-09 09:29:17 +00:00
|
|
|
|
gcom->buffer[k++] = (uint8_t)(messleng&255);
|
|
|
|
|
gcom->buffer[k++] = (uint8_t)(messleng>>8);
|
2009-02-19 16:47:54 +00:00
|
|
|
|
for (i=0; i<messleng; i++)
|
2008-11-12 04:16:41 +00:00
|
|
|
|
gcom->buffer[k++] = bakpacketbuf[(i+j)&(BAKSIZ-1)];
|
|
|
|
|
outcntplc[other]++;
|
|
|
|
|
|
|
|
|
|
/* Second half-packet */
|
|
|
|
|
j = bakpacketptr[other][outcntplc[other]&255];
|
|
|
|
|
messleng = bakpacketlen[other][outcntplc[other]&255];
|
2009-02-19 16:47:54 +00:00
|
|
|
|
for (i=0; i<messleng; i++)
|
2008-11-12 04:16:41 +00:00
|
|
|
|
gcom->buffer[k++] = bakpacketbuf[(i+j)&(BAKSIZ-1)];
|
|
|
|
|
outcntplc[other]++;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2009-01-09 09:29:17 +00:00
|
|
|
|
dacrc = getcrc(gcom->buffer,(int16_t)k);
|
2008-11-12 04:16:41 +00:00
|
|
|
|
gcom->buffer[k++] = (dacrc&255);
|
|
|
|
|
gcom->buffer[k++] = (dacrc>>8);
|
|
|
|
|
|
|
|
|
|
gcom->other = other+1;
|
|
|
|
|
gcom->numbytes = k;
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
|
|
|
|
#if (SHOWSENDPACKETS)
|
2008-11-12 04:16:41 +00:00
|
|
|
|
initprintf("Send(%ld): ",gcom->other);
|
2009-02-19 16:47:54 +00:00
|
|
|
|
for (i=0; i<gcom->numbytes; i++) initprintf("%2x ",gcom->buffer[i]);
|
2008-11-12 04:16:41 +00:00
|
|
|
|
initprintf("\n");
|
2008-11-11 13:24:05 +00:00
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if (SIMULATEERRORS != 0)
|
2008-11-12 04:16:41 +00:00
|
|
|
|
if (!(rand()&SIMULATEERRORS)) gcom->buffer[rand()%gcom->numbytes] = (rand()&255);
|
|
|
|
|
if (rand()&SIMULATEERRORS)
|
2008-11-11 13:24:05 +00:00
|
|
|
|
#endif
|
2008-11-12 04:16:41 +00:00
|
|
|
|
{
|
|
|
|
|
gcom->command = COMMIT_CMD_SEND;
|
|
|
|
|
callcommit();
|
|
|
|
|
}
|
2008-11-11 13:24:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2009-01-09 09:29:17 +00:00
|
|
|
|
void mmulti_sendpacket(int32_t other, char *bufptr, int32_t messleng)
|
2008-11-11 13:24:05 +00:00
|
|
|
|
{
|
2009-01-09 09:29:17 +00:00
|
|
|
|
int32_t i = 0;
|
|
|
|
|
int32_t j = 0;
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
2008-11-12 04:16:41 +00:00
|
|
|
|
if (numplayers < 2) return;
|
|
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
|
if (bakpacketlen[other][(outcntend[other]-1)&255] == messleng)
|
|
|
|
|
{
|
|
|
|
|
j = bakpacketptr[other][(outcntend[other]-1)&255];
|
2009-02-19 16:47:54 +00:00
|
|
|
|
for (i=messleng-1; i>=0; i--)
|
2008-11-12 04:16:41 +00:00
|
|
|
|
if (bakpacketbuf[(i+j)&(BAKSIZ-1)] != bufptr[i]) break;
|
|
|
|
|
}
|
|
|
|
|
bakpacketlen[other][outcntend[other]&255] = messleng;
|
|
|
|
|
|
|
|
|
|
if (i < 0) /* Point to last packet to save space on bakpacketbuf */
|
|
|
|
|
bakpacketptr[other][outcntend[other]&255] = j;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
bakpacketptr[other][outcntend[other]&255] = bakpacketplc;
|
2009-02-19 16:47:54 +00:00
|
|
|
|
for (i=0; i<messleng; i++)
|
2008-11-12 04:16:41 +00:00
|
|
|
|
bakpacketbuf[(bakpacketplc+i)&(BAKSIZ-1)] = bufptr[i];
|
|
|
|
|
bakpacketplc = ((bakpacketplc+messleng)&(BAKSIZ-1));
|
|
|
|
|
}
|
|
|
|
|
outcntend[other]++;
|
|
|
|
|
|
|
|
|
|
lastsendtime[other] = totalclock;
|
2009-01-09 09:29:17 +00:00
|
|
|
|
mmulti_dosendpackets(other);
|
2008-11-11 13:24:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2009-01-09 09:29:17 +00:00
|
|
|
|
void mmulti_setpackettimeout(int32_t datimeoutcount, int32_t daresendagaincount)
|
2008-11-11 13:24:05 +00:00
|
|
|
|
{
|
2008-11-11 13:45:12 +00:00
|
|
|
|
UNREFERENCED_PARAMETER(datimeoutcount);
|
|
|
|
|
UNREFERENCED_PARAMETER(daresendagaincount);
|
2008-11-12 04:16:41 +00:00
|
|
|
|
// Don't do this it keeps '/f4' from working
|
|
|
|
|
// Though /f4 feels weird on my mouse.... slugish is the word...
|
|
|
|
|
/*
|
2009-01-09 09:29:17 +00:00
|
|
|
|
int32_t i;
|
2008-11-12 04:16:41 +00:00
|
|
|
|
|
|
|
|
|
timeoutcount = datimeoutcount;
|
|
|
|
|
resendagaincount = daresendagaincount;
|
|
|
|
|
for(i=0;i<numplayers;i++) lastsendtime[i] = totalclock;
|
|
|
|
|
*/
|
2008-11-11 13:24:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2009-01-09 09:29:17 +00:00
|
|
|
|
void mmulti_uninitmultiplayers(void)
|
2008-11-11 13:24:05 +00:00
|
|
|
|
{
|
|
|
|
|
deinit_network_transport(gcom);
|
|
|
|
|
gcom = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2008-11-12 22:28:02 +00:00
|
|
|
|
typedef enum
|
|
|
|
|
{
|
|
|
|
|
udpmode_peer,
|
|
|
|
|
udpmode_server,
|
|
|
|
|
udpmode_client
|
2009-01-10 07:38:50 +00:00
|
|
|
|
} udpmode_t;
|
|
|
|
|
static udpmode_t udpmode = udpmode_peer;
|
2008-11-12 22:28:02 +00:00
|
|
|
|
|
2009-01-10 07:38:50 +00:00
|
|
|
|
void mmulti_sendlogon(void)
|
2008-11-11 13:24:05 +00:00
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2009-01-10 07:38:50 +00:00
|
|
|
|
void mmulti_sendlogoff(void)
|
2008-11-11 13:24:05 +00:00
|
|
|
|
{
|
2009-01-09 09:29:17 +00:00
|
|
|
|
int32_t i;
|
2008-11-12 04:16:41 +00:00
|
|
|
|
char tempbuf[2];
|
|
|
|
|
|
|
|
|
|
tempbuf[0] = 255;
|
|
|
|
|
tempbuf[1] = myconnectindex;
|
2009-02-19 16:47:54 +00:00
|
|
|
|
for (i=connecthead; i>=0; i=connectpoint2[i])
|
2008-11-12 22:28:02 +00:00
|
|
|
|
{
|
2008-11-12 04:16:41 +00:00
|
|
|
|
if (i != myconnectindex)
|
2009-01-09 09:29:17 +00:00
|
|
|
|
mmulti_sendpacket(i,tempbuf,2L);
|
2008-11-12 22:28:02 +00:00
|
|
|
|
if ((udpmode == udpmode_client) && (myconnectindex != connecthead)) break; //slaves in M/S mode only send to master
|
|
|
|
|
}
|
2008-11-11 13:24:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
2009-01-10 07:38:50 +00:00
|
|
|
|
int32_t mmulti_getoutputcirclesize(void)
|
2008-11-11 13:24:05 +00:00
|
|
|
|
{
|
2008-11-12 04:16:41 +00:00
|
|
|
|
return(0);
|
2008-11-11 13:24:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
2009-01-09 09:29:17 +00:00
|
|
|
|
int32_t mmulti_getpacket(int32_t *other, char *bufptr)
|
2008-11-11 13:24:05 +00:00
|
|
|
|
{
|
2009-01-09 09:29:17 +00:00
|
|
|
|
int32_t i, messleng;
|
|
|
|
|
uint16_t dacrc;
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
2008-11-12 22:28:02 +00:00
|
|
|
|
if (numplayers < 2 || gcom == NULL) return(0);
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
2009-02-19 16:47:54 +00:00
|
|
|
|
for (i=connecthead; i>=0; i=connectpoint2[i])
|
2008-11-12 22:28:02 +00:00
|
|
|
|
{
|
2008-11-12 04:16:41 +00:00
|
|
|
|
if (i != myconnectindex)
|
|
|
|
|
{
|
2008-11-13 13:58:53 +00:00
|
|
|
|
// FIXME: this is probably not so great
|
2009-01-09 09:29:17 +00:00
|
|
|
|
if (udpmode != udpmode_peer) mmulti_dosendpackets(i);
|
2008-11-12 04:16:41 +00:00
|
|
|
|
if (totalclock < lastsendtime[i]) lastsendtime[i] = totalclock;
|
|
|
|
|
if (totalclock > lastsendtime[i]+timeoutcount)
|
|
|
|
|
{
|
2008-11-11 13:24:05 +00:00
|
|
|
|
#if (PRINTERRORS)
|
2008-11-12 04:16:41 +00:00
|
|
|
|
initprintf(" TimeOut!");
|
2008-11-11 13:24:05 +00:00
|
|
|
|
#endif
|
2008-11-12 04:16:41 +00:00
|
|
|
|
errorgotnum[i] = errorfixnum[i]+1;
|
|
|
|
|
|
|
|
|
|
if ((outcntplc[i] == outcntend[i]) && (outcntplc[i] > 0))
|
|
|
|
|
{ outcntplc[i]--; lastsendtime[i] = totalclock; }
|
|
|
|
|
else
|
|
|
|
|
lastsendtime[i] += resendagaincount;
|
2009-01-09 09:29:17 +00:00
|
|
|
|
mmulti_dosendpackets(i);
|
2008-11-12 04:16:41 +00:00
|
|
|
|
/* } */
|
|
|
|
|
}
|
|
|
|
|
}
|
2008-11-12 22:28:02 +00:00
|
|
|
|
if ((udpmode == udpmode_client) && (myconnectindex != connecthead)) break; //slaves in M/S mode only send to master
|
|
|
|
|
}
|
2008-11-12 04:16:41 +00:00
|
|
|
|
|
|
|
|
|
if (inlastpacket != 0)
|
|
|
|
|
{
|
|
|
|
|
/* 2ND half of good double-packet */
|
|
|
|
|
inlastpacket = 0;
|
|
|
|
|
*other = lastpacketfrom;
|
2009-06-09 06:19:58 +00:00
|
|
|
|
Bmemcpy(bufptr,lastpacket,lastpacketleng);
|
2008-11-12 04:16:41 +00:00
|
|
|
|
return(lastpacketleng);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gcom->command = COMMIT_CMD_GET;
|
|
|
|
|
callcommit();
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
|
|
|
|
#if (SHOWGETPACKETS)
|
2008-11-12 04:16:41 +00:00
|
|
|
|
if (gcom->other != -1)
|
|
|
|
|
{
|
|
|
|
|
initprintf(" Get(%ld): ",gcom->other);
|
2009-02-19 16:47:54 +00:00
|
|
|
|
for (i=0; i<gcom->numbytes; i++) initprintf("%2x ",gcom->buffer[i]);
|
2008-11-12 04:16:41 +00:00
|
|
|
|
initprintf("\n");
|
|
|
|
|
}
|
2008-11-11 13:24:05 +00:00
|
|
|
|
#endif
|
|
|
|
|
|
2008-11-12 04:16:41 +00:00
|
|
|
|
if (gcom->other < 0) return(0);
|
|
|
|
|
*other = gcom->other-1;
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
2008-11-12 04:16:41 +00:00
|
|
|
|
messleng = gcom->numbytes;
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
2009-01-09 09:29:17 +00:00
|
|
|
|
dacrc = ((uint16_t)gcom->buffer[messleng-2]);
|
|
|
|
|
dacrc += (((uint16_t)gcom->buffer[messleng-1])<<8);
|
|
|
|
|
if (dacrc != getcrc(gcom->buffer,(int16_t)(messleng-2))) /* CRC check */
|
2008-11-12 04:16:41 +00:00
|
|
|
|
{
|
2008-11-11 13:24:05 +00:00
|
|
|
|
#if (PRINTERRORS)
|
2008-11-12 04:16:41 +00:00
|
|
|
|
initprintf("\n%ld CRC",gcom->buffer[0]);
|
2008-11-11 13:24:05 +00:00
|
|
|
|
#endif
|
2008-11-12 04:16:41 +00:00
|
|
|
|
errorgotnum[*other] = errorfixnum[*other]+1;
|
|
|
|
|
return(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while ((errorfixnum[*other]&7) != ((gcom->buffer[1]>>3)&7))
|
|
|
|
|
errorfixnum[*other]++;
|
|
|
|
|
|
|
|
|
|
if ((gcom->buffer[1]&7) != (errorresendnum[*other]&7))
|
|
|
|
|
{
|
|
|
|
|
errorresendnum[*other]++;
|
|
|
|
|
outcntplc[*other] = (outcntend[*other]&0xffffff00)+gcom->buffer[2];
|
|
|
|
|
if (outcntplc[*other] > outcntend[*other]) outcntplc[*other] -= 256;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (gcom->buffer[0] != (incnt[*other]&255)) /* CNT check */
|
|
|
|
|
{
|
|
|
|
|
if (((incnt[*other]-gcom->buffer[0])&255) > 32)
|
|
|
|
|
{
|
|
|
|
|
errorgotnum[*other] = errorfixnum[*other]+1;
|
2008-11-11 13:24:05 +00:00
|
|
|
|
#if (PRINTERRORS)
|
2008-11-12 04:16:41 +00:00
|
|
|
|
initprintf("\n%ld CNT",gcom->buffer[0]);
|
2008-11-11 13:24:05 +00:00
|
|
|
|
#endif
|
2008-11-12 04:16:41 +00:00
|
|
|
|
}
|
2008-11-11 13:24:05 +00:00
|
|
|
|
#if (PRINTERRORS)
|
2008-11-12 04:16:41 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (!(gcom->buffer[1]&128)) /* single else double packet */
|
|
|
|
|
initprintf("\n%ld cnt",gcom->buffer[0]);
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (((gcom->buffer[0]+1)&255) == (incnt[*other]&255))
|
|
|
|
|
{
|
|
|
|
|
/* GOOD! Take second half of double packet */
|
2008-11-11 13:24:05 +00:00
|
|
|
|
#if (PRINTERRORS)
|
2008-11-12 04:16:41 +00:00
|
|
|
|
initprintf("\n%ld-%ld .<2E> ",gcom->buffer[0],(gcom->buffer[0]+1)&255);
|
2008-11-11 13:24:05 +00:00
|
|
|
|
#endif
|
2009-01-09 09:29:17 +00:00
|
|
|
|
messleng = ((int32_t)gcom->buffer[3]) + (((int32_t)gcom->buffer[4])<<8);
|
2008-11-12 04:16:41 +00:00
|
|
|
|
lastpacketleng = gcom->numbytes-7-messleng;
|
2009-06-09 06:19:58 +00:00
|
|
|
|
Bmemcpy(bufptr,&gcom->buffer[messleng+5],lastpacketleng);
|
2008-11-12 04:16:41 +00:00
|
|
|
|
incnt[*other]++;
|
|
|
|
|
return(lastpacketleng);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
initprintf("\n%ld-%ld cnt ",gcom->buffer[0],(gcom->buffer[0]+1)&255);
|
|
|
|
|
}
|
|
|
|
|
}
|
2008-11-11 13:24:05 +00:00
|
|
|
|
#endif
|
2008-11-12 04:16:41 +00:00
|
|
|
|
return(0);
|
|
|
|
|
}
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
2008-11-12 04:16:41 +00:00
|
|
|
|
/* PACKET WAS GOOD! */
|
|
|
|
|
if ((gcom->buffer[1]&128) == 0) /* Single packet */
|
|
|
|
|
{
|
2008-11-11 13:24:05 +00:00
|
|
|
|
#if (PRINTERRORS)
|
2008-11-12 04:16:41 +00:00
|
|
|
|
initprintf("\n%ld <20> ",gcom->buffer[0]);
|
2008-11-11 13:24:05 +00:00
|
|
|
|
#endif
|
|
|
|
|
|
2008-11-12 04:16:41 +00:00
|
|
|
|
messleng = gcom->numbytes-5;
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
2009-06-09 06:19:58 +00:00
|
|
|
|
Bmemcpy(bufptr,&gcom->buffer[3],messleng);
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
2008-11-12 04:16:41 +00:00
|
|
|
|
incnt[*other]++;
|
|
|
|
|
return(messleng);
|
|
|
|
|
}
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
2008-11-12 04:16:41 +00:00
|
|
|
|
/* Double packet */
|
2008-11-11 13:24:05 +00:00
|
|
|
|
#if (PRINTERRORS)
|
2008-11-12 04:16:41 +00:00
|
|
|
|
initprintf("\n%ld-%ld <20><> ",gcom->buffer[0],(gcom->buffer[0]+1)&255);
|
2008-11-11 13:24:05 +00:00
|
|
|
|
#endif
|
|
|
|
|
|
2009-01-09 09:29:17 +00:00
|
|
|
|
messleng = ((int32_t)gcom->buffer[3]) + (((int32_t)gcom->buffer[4])<<8);
|
2008-11-12 04:16:41 +00:00
|
|
|
|
lastpacketleng = gcom->numbytes-7-messleng;
|
|
|
|
|
inlastpacket = 1; lastpacketfrom = *other;
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
2009-06-09 06:19:58 +00:00
|
|
|
|
Bmemcpy(bufptr,&gcom->buffer[5],messleng);
|
|
|
|
|
Bmemcpy(lastpacket,&gcom->buffer[messleng+5],lastpacketleng);
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
2008-11-12 04:16:41 +00:00
|
|
|
|
incnt[*other] += 2;
|
|
|
|
|
return(messleng);
|
2008-11-11 13:24:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
2009-01-09 09:29:17 +00:00
|
|
|
|
void mmulti_flushpackets()
|
2008-11-11 13:24:05 +00:00
|
|
|
|
{
|
2008-11-20 14:06:36 +00:00
|
|
|
|
#if 1
|
2009-01-09 09:29:17 +00:00
|
|
|
|
int32_t i;
|
2008-11-12 04:16:41 +00:00
|
|
|
|
|
|
|
|
|
if (numplayers < 2) return;
|
|
|
|
|
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
gcom->command = COMMIT_CMD_GET;
|
|
|
|
|
callcommit();
|
|
|
|
|
}
|
|
|
|
|
while (gcom->other >= 0);
|
|
|
|
|
|
2009-02-19 16:47:54 +00:00
|
|
|
|
for (i=connecthead; i>=0; i=connectpoint2[i])
|
2008-11-12 04:16:41 +00:00
|
|
|
|
{
|
|
|
|
|
incnt[i] = 0L;
|
|
|
|
|
outcntplc[i] = 0L;
|
|
|
|
|
outcntend[i] = 0L;
|
|
|
|
|
errorgotnum[i] = 0;
|
|
|
|
|
errorfixnum[i] = 0;
|
|
|
|
|
errorresendnum[i] = 0;
|
|
|
|
|
lastsendtime[i] = totalclock;
|
|
|
|
|
}
|
2008-11-11 13:24:05 +00:00
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
2009-01-10 07:38:50 +00:00
|
|
|
|
void mmulti_generic(int32_t other, char *bufptr, int32_t messleng, int32_t command)
|
2008-11-11 13:24:05 +00:00
|
|
|
|
{
|
2008-11-12 04:16:41 +00:00
|
|
|
|
if (numplayers < 2) return;
|
|
|
|
|
|
|
|
|
|
gcom->command = command;
|
|
|
|
|
gcom->numbytes = min(messleng,MAXPACKETSIZE);
|
|
|
|
|
copybuf(bufptr,gcom->buffer,(gcom->numbytes+3)>>2);
|
|
|
|
|
gcom->other = other+1;
|
|
|
|
|
callcommit();
|
|
|
|
|
|
2008-11-11 13:24:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if PLATFORM_WIN32
|
|
|
|
|
# include <winsock.h>
|
|
|
|
|
# define EWOULDBLOCK WSAEWOULDBLOCK
|
|
|
|
|
# define ECONNREFUSED WSAECONNRESET
|
|
|
|
|
# define socklen_t size_t
|
|
|
|
|
# define netstrerror() win32netstrerror()
|
|
|
|
|
# define neterrno() WSAGetLastError()
|
|
|
|
|
# define sockettype SOCKET
|
|
|
|
|
# define socketclose(x) closesocket(x)
|
|
|
|
|
#else
|
|
|
|
|
# include <sys/types.h>
|
|
|
|
|
# include <sys/socket.h>
|
|
|
|
|
# include <netinet/in.h>
|
|
|
|
|
# include <arpa/inet.h>
|
|
|
|
|
# include <netdb.h>
|
|
|
|
|
# include <sys/uio.h>
|
|
|
|
|
# include <sys/ioctl.h>
|
|
|
|
|
# include <sys/time.h>
|
|
|
|
|
# include <errno.h>
|
|
|
|
|
# include <fcntl.h>
|
|
|
|
|
# include <time.h>
|
|
|
|
|
# define netstrerror() strerror(errno)
|
|
|
|
|
# define neterrno() errno
|
2009-01-09 09:29:17 +00:00
|
|
|
|
# define sockettype int32_t
|
2008-11-11 13:24:05 +00:00
|
|
|
|
# define socketclose(x) close(x)
|
|
|
|
|
# ifndef MSG_ERRQUEUE /* legacy glibc header workaround... */
|
|
|
|
|
# define MSG_ERRQUEUE 0x2000
|
|
|
|
|
# endif
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#define SOCKET_SHUTDOWN_BOTH 2
|
|
|
|
|
|
|
|
|
|
#include "cache1d.h" /* kopen4load for cfg file. */
|
|
|
|
|
|
2009-01-09 09:29:17 +00:00
|
|
|
|
#define IPSEG1(ip) ((((uint32_t) ip) & 0xFF000000) >> 24)
|
|
|
|
|
#define IPSEG2(ip) ((((uint32_t) ip) & 0x00FF0000) >> 16)
|
|
|
|
|
#define IPSEG3(ip) ((((uint32_t) ip) & 0x0000FF00) >> 8)
|
|
|
|
|
#define IPSEG4(ip) ((((uint32_t) ip) & 0x000000FF) )
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
2008-11-12 04:16:41 +00:00
|
|
|
|
#define BUILD_DEFAULT_UDP_PORT 23513 /* eh...why not? */
|
|
|
|
|
#define CLIENT_POLL_DELAY 5000 /* ms between pings at peer-to-peer startup. */
|
2008-11-11 13:24:05 +00:00
|
|
|
|
#define HEADER_PEER_GREETING 245
|
|
|
|
|
|
|
|
|
|
static sockettype udpsocket = -1;
|
2009-01-09 09:29:17 +00:00
|
|
|
|
static uint16_t udpport = BUILD_DEFAULT_UDP_PORT;
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
|
|
|
|
#if PLATFORM_WIN32
|
|
|
|
|
/*
|
|
|
|
|
* Figure out what the last failing Win32 API call was, and
|
|
|
|
|
* generate a human-readable string for the error message.
|
|
|
|
|
*
|
|
|
|
|
* The return value is a static buffer that is overwritten with
|
|
|
|
|
* each call to this function.
|
|
|
|
|
*
|
|
|
|
|
* Code lifted from PhysicsFS: http://icculus.org/physfs/
|
|
|
|
|
*/
|
|
|
|
|
static const char *win32netstrerror(void)
|
|
|
|
|
{
|
|
|
|
|
static TCHAR msgbuf[255];
|
|
|
|
|
TCHAR *ptr = msgbuf;
|
|
|
|
|
|
|
|
|
|
FormatMessage(
|
|
|
|
|
FORMAT_MESSAGE_FROM_SYSTEM |
|
|
|
|
|
FORMAT_MESSAGE_IGNORE_INSERTS,
|
|
|
|
|
NULL,
|
|
|
|
|
WSAGetLastError(), /*GetLastError(),*/
|
|
|
|
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */
|
|
|
|
|
msgbuf,
|
2008-11-12 04:16:41 +00:00
|
|
|
|
sizeof(msgbuf) / sizeof(TCHAR),
|
|
|
|
|
NULL
|
2008-11-11 13:24:05 +00:00
|
|
|
|
);
|
|
|
|
|
|
2008-11-12 04:16:41 +00:00
|
|
|
|
/* chop off newlines. */
|
2008-11-11 13:24:05 +00:00
|
|
|
|
for (ptr = msgbuf; *ptr; ptr++)
|
|
|
|
|
{
|
|
|
|
|
if ((*ptr == '\n') || (*ptr == '\r'))
|
|
|
|
|
{
|
|
|
|
|
*ptr = ' ';
|
|
|
|
|
break;
|
|
|
|
|
} /* if */
|
|
|
|
|
} /* for */
|
|
|
|
|
|
|
|
|
|
return((const char *) msgbuf);
|
|
|
|
|
} /* win32strerror */
|
|
|
|
|
#endif
|
|
|
|
|
|
2009-01-09 09:29:17 +00:00
|
|
|
|
static char *static_ipstring(int32_t ip)
|
2008-11-11 13:24:05 +00:00
|
|
|
|
{
|
|
|
|
|
static char s[16];
|
2009-02-02 01:49:14 +00:00
|
|
|
|
Bsprintf(s, "%u.%u.%u.%u", IPSEG1(ip), IPSEG2(ip), IPSEG3(ip), IPSEG4(ip));
|
2008-11-11 13:24:05 +00:00
|
|
|
|
return(s);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2009-01-09 09:29:17 +00:00
|
|
|
|
static int32_t send_udp_packet(int32_t ip, uint16_t port, void *pkt, size_t pktsize)
|
2008-11-11 13:24:05 +00:00
|
|
|
|
{
|
|
|
|
|
/* !!! FIXME: See if this would ever block. */
|
|
|
|
|
/* !!! FIXME: See if this would send a partial packet. */
|
|
|
|
|
struct sockaddr_in addr;
|
2009-01-09 09:29:17 +00:00
|
|
|
|
int32_t rc;
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
2008-11-12 04:16:41 +00:00
|
|
|
|
addr.sin_family = AF_INET;
|
|
|
|
|
addr.sin_addr.s_addr = htonl(ip);
|
|
|
|
|
addr.sin_port = htons(port);
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
|
|
|
|
rc = sendto(udpsocket, pkt, pktsize, 0,
|
2008-11-12 04:16:41 +00:00
|
|
|
|
(struct sockaddr *) &addr, sizeof(addr));
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
2009-01-09 09:29:17 +00:00
|
|
|
|
if (rc != (int32_t) pktsize)
|
2008-11-11 13:24:05 +00:00
|
|
|
|
{
|
|
|
|
|
initprintf("sendto err rc==%d when sending %d to %s:%d [%s].\n",
|
2009-01-09 09:29:17 +00:00
|
|
|
|
rc, (int32_t) pktsize, static_ipstring(ip), (int32_t) port,
|
2008-11-12 04:16:41 +00:00
|
|
|
|
netstrerror());
|
2008-11-11 13:24:05 +00:00
|
|
|
|
return(0);
|
|
|
|
|
}
|
|
|
|
|
|
2009-01-09 09:29:17 +00:00
|
|
|
|
/*initprintf("Sent %d byte packet to %s:%d\n", (int32_t) pktsize, static_ipstring(ip), (int32_t) port);*/
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
|
|
|
|
return(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void process_udp_send_queue(void)
|
|
|
|
|
{
|
|
|
|
|
/* Fill this in if the non-blocking socket becomes an issue. */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2009-01-09 09:29:17 +00:00
|
|
|
|
static int32_t get_udp_packet(int32_t *ip, uint16_t *_port, void *pkt, size_t pktsize)
|
2008-11-11 13:24:05 +00:00
|
|
|
|
{
|
2009-01-09 09:29:17 +00:00
|
|
|
|
int32_t err = 0;
|
2008-11-11 13:24:05 +00:00
|
|
|
|
struct sockaddr_in addr;
|
2009-01-09 09:29:17 +00:00
|
|
|
|
uint16_t port;
|
2008-11-12 04:16:41 +00:00
|
|
|
|
socklen_t fromlen = sizeof(addr);
|
2009-01-09 09:29:17 +00:00
|
|
|
|
int32_t valid = 0;
|
|
|
|
|
int32_t i;
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
|
|
|
|
/* FIXME: Will this ever receive a partial packet? */
|
2009-01-09 09:29:17 +00:00
|
|
|
|
int32_t rc = recvfrom(udpsocket, pkt, pktsize, 0, (struct sockaddr *) &addr,
|
2008-11-11 14:48:59 +00:00
|
|
|
|
#ifdef _WIN32
|
2009-02-19 16:47:54 +00:00
|
|
|
|
(int32_t *)&fromlen);
|
2008-11-11 14:48:59 +00:00
|
|
|
|
#else
|
2009-02-19 16:47:54 +00:00
|
|
|
|
(uint32_t *)&fromlen);
|
2008-11-11 14:48:59 +00:00
|
|
|
|
#endif
|
2008-11-12 04:16:41 +00:00
|
|
|
|
|
|
|
|
|
if (rc == -1)
|
2008-11-11 13:24:05 +00:00
|
|
|
|
err = neterrno();
|
|
|
|
|
|
|
|
|
|
#if !PLATFORM_WIN32
|
2008-11-12 04:16:41 +00:00
|
|
|
|
/* !!! FIXME: Linux specific? */
|
2008-11-11 13:24:05 +00:00
|
|
|
|
if (rc == -1) /* fill in the addr structure on error... */
|
|
|
|
|
{
|
2008-11-12 04:16:41 +00:00
|
|
|
|
socklen_t l = sizeof(addr);
|
2008-11-11 13:24:05 +00:00
|
|
|
|
recvfrom(udpsocket, NULL, 0, MSG_ERRQUEUE,
|
|
|
|
|
(struct sockaddr *) &addr, &l);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
*ip = ntohl(addr.sin_addr.s_addr);
|
|
|
|
|
port = ntohs(addr.sin_port);
|
|
|
|
|
if (_port)
|
|
|
|
|
*_port = port;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Reject packets from unallowed IPs. Prevents (ha) DoS attacks and
|
|
|
|
|
* other confusion...
|
|
|
|
|
*/
|
|
|
|
|
if (gcom == NULL)
|
2008-11-12 04:16:41 +00:00
|
|
|
|
{
|
|
|
|
|
if (natfree) //if stun is enabled
|
|
|
|
|
{
|
|
|
|
|
if ((allowed_addresses[itmp].host == *ip)
|
|
|
|
|
&& (allowed_addresses[itmp].port == port))
|
|
|
|
|
{
|
|
|
|
|
valid = 1; //only accept packets from the current player (itmp) and no one else
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return 0; //reject packets from other players
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
2008-11-11 13:24:05 +00:00
|
|
|
|
{
|
2008-11-12 04:16:41 +00:00
|
|
|
|
valid = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
2008-11-11 13:24:05 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
for (i = 1; i <= gcom->numplayers; i++)
|
|
|
|
|
{
|
|
|
|
|
if ((allowed_addresses[i].host == *ip)
|
2008-11-12 04:16:41 +00:00
|
|
|
|
&& (allowed_addresses[i].port == port))
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
|
|
|
|
{
|
2008-11-12 04:16:41 +00:00
|
|
|
|
valid = i;
|
|
|
|
|
|
2009-01-09 09:29:17 +00:00
|
|
|
|
//initprintf ("Packet received from %s:%d\n",static_ipstring(*ip), (int32_t) port);
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2008-11-12 04:16:41 +00:00
|
|
|
|
}
|
2008-11-11 13:24:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*if (!valid)
|
|
|
|
|
{
|
2008-11-12 04:16:41 +00:00
|
|
|
|
|
2009-01-09 09:29:17 +00:00
|
|
|
|
static int32_t unallowed_ip_spam = 0;
|
2008-11-11 13:24:05 +00:00
|
|
|
|
if (unallowed_ip_spam <= 100)
|
|
|
|
|
{
|
|
|
|
|
initprintf("Packet received from unallowed IP %s:%d\n",
|
2009-01-09 09:29:17 +00:00
|
|
|
|
static_ipstring(*ip), (int32_t) port);
|
2008-11-11 13:24:05 +00:00
|
|
|
|
if (unallowed_ip_spam == 100)
|
|
|
|
|
initprintf("(Disabling further unallowed IP spam.)\n");
|
|
|
|
|
unallowed_ip_spam++;
|
|
|
|
|
}
|
2008-11-12 04:16:41 +00:00
|
|
|
|
|
2008-11-11 13:24:05 +00:00
|
|
|
|
return(0);
|
|
|
|
|
} */
|
|
|
|
|
|
|
|
|
|
if (rc == -1)
|
|
|
|
|
{
|
|
|
|
|
if ((err == EAGAIN) || (err == EWOULDBLOCK))
|
|
|
|
|
rc = 0;
|
|
|
|
|
|
2008-11-12 04:16:41 +00:00
|
|
|
|
else if (err == ECONNREFUSED) //"connection reset by peer" in winsock
|
2008-11-11 13:24:05 +00:00
|
|
|
|
{
|
2008-11-12 04:16:41 +00:00
|
|
|
|
|
|
|
|
|
// This means that we sent a packet to an unopened port, and
|
|
|
|
|
// it responded by telling us to piss off. Take them out of the
|
|
|
|
|
// allowed list. We check gcom so that we don't worry about this
|
|
|
|
|
// during detection when game might still be loading elsewhere.
|
|
|
|
|
|
2008-11-11 13:24:05 +00:00
|
|
|
|
if (gcom != NULL)
|
|
|
|
|
{
|
|
|
|
|
allowed_addresses[valid].host = 0;
|
|
|
|
|
initprintf("%s:%d refused packets. Removed from game.\n",
|
2009-01-09 09:29:17 +00:00
|
|
|
|
static_ipstring(*ip), (int32_t) port);
|
2008-11-11 13:24:05 +00:00
|
|
|
|
}
|
2008-11-12 04:16:41 +00:00
|
|
|
|
// !!! FIXME: Actually boot player, too.
|
2008-11-11 13:24:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
initprintf("recvfrom err rc==%d when getting %d from %s:%d [%s].\n",
|
2009-01-09 09:29:17 +00:00
|
|
|
|
rc, (int32_t) pktsize, static_ipstring(*ip), (int32_t) port,
|
2008-11-12 04:16:41 +00:00
|
|
|
|
netstrerror());
|
2008-11-11 13:24:05 +00:00
|
|
|
|
}
|
2008-11-12 04:16:41 +00:00
|
|
|
|
}
|
2009-01-09 09:29:17 +00:00
|
|
|
|
//else initprintf("Got %d byte packet from %s:%d\n", (int32_t) rc, static_ipstring(*ip), (int32_t) port);
|
2008-11-12 04:16:41 +00:00
|
|
|
|
//initprintf( "IP from client %d", *ip);
|
2008-11-11 13:24:05 +00:00
|
|
|
|
return(rc);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static char *read_whole_file(const char *cfgfile)
|
|
|
|
|
{
|
|
|
|
|
char *buf;
|
2009-01-09 09:29:17 +00:00
|
|
|
|
int32_t len, rc;
|
|
|
|
|
int32_t handle;
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
|
|
|
|
if (cfgfile == NULL)
|
|
|
|
|
return(NULL);
|
|
|
|
|
|
2008-11-11 13:45:12 +00:00
|
|
|
|
handle = kopen4load((char *)cfgfile, 0);
|
2008-11-11 13:24:05 +00:00
|
|
|
|
if (handle == -1)
|
|
|
|
|
{
|
2008-11-14 08:22:57 +00:00
|
|
|
|
// initprintf("ERROR: Failed to open config file [%s].\n", cfgfile);
|
2008-11-11 13:24:05 +00:00
|
|
|
|
return(NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
len = kfilelength(handle);
|
|
|
|
|
buf = (char *) malloc(len + 2);
|
|
|
|
|
if (!buf)
|
|
|
|
|
{
|
|
|
|
|
kclose(handle);
|
|
|
|
|
return(NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rc = kread(handle, buf, len);
|
|
|
|
|
kclose(handle);
|
|
|
|
|
if (rc != len)
|
|
|
|
|
{
|
|
|
|
|
free(buf);
|
|
|
|
|
return(NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
buf[len] = '\0';
|
|
|
|
|
buf[len+1] = '\0';
|
|
|
|
|
return(buf);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char *get_token(char **ptr)
|
|
|
|
|
{
|
|
|
|
|
char *retval;
|
|
|
|
|
char *p = *ptr;
|
|
|
|
|
if (*p == '\0')
|
|
|
|
|
return(NULL);
|
|
|
|
|
|
|
|
|
|
while ((*p != '\0') && (isspace(*p)))
|
|
|
|
|
p++;
|
|
|
|
|
|
|
|
|
|
if (*p == '\0') /* nothing but whitespace. */
|
|
|
|
|
return(NULL);
|
|
|
|
|
|
|
|
|
|
retval = p;
|
|
|
|
|
while ((*p != '\0') && (!isspace(*p)))
|
|
|
|
|
p++;
|
|
|
|
|
|
|
|
|
|
*p = '\0';
|
|
|
|
|
*ptr = p + 1;
|
|
|
|
|
|
|
|
|
|
/*initprintf("Got token [%s].\n", retval);*/
|
|
|
|
|
return(retval);
|
|
|
|
|
}
|
|
|
|
|
|
2009-01-09 09:29:17 +00:00
|
|
|
|
static int32_t set_socket_blockmode(int32_t onOrOff)
|
2008-11-11 13:24:05 +00:00
|
|
|
|
{
|
2009-01-09 09:29:17 +00:00
|
|
|
|
uint32_t flags;
|
|
|
|
|
int32_t rc = 0;
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
|
|
|
|
/* set socket to be (non-)blocking. */
|
|
|
|
|
|
|
|
|
|
#if PLATFORM_WIN32
|
|
|
|
|
flags = (onOrOff) ? 0 : 1;
|
2008-11-11 14:48:59 +00:00
|
|
|
|
rc = (ioctlsocket(udpsocket, FIONBIO, (void *) &flags) == 0);
|
2008-11-11 13:24:05 +00:00
|
|
|
|
#else
|
|
|
|
|
flags = fcntl(udpsocket, F_GETFL, 0);
|
2008-11-11 13:45:12 +00:00
|
|
|
|
if ((signed)flags != -1)
|
2008-11-11 13:24:05 +00:00
|
|
|
|
{
|
|
|
|
|
if (onOrOff)
|
|
|
|
|
flags &= ~O_NONBLOCK;
|
|
|
|
|
else
|
2008-11-12 04:16:41 +00:00
|
|
|
|
flags |= O_NONBLOCK;
|
|
|
|
|
rc = (fcntl(udpsocket, F_SETFL, flags) == 0);
|
2008-11-11 13:24:05 +00:00
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
if (!rc)
|
|
|
|
|
{
|
|
|
|
|
initprintf("set socket %sblocking failed: %s\n",
|
2008-11-12 04:16:41 +00:00
|
|
|
|
((onOrOff) ? "" : "non-"), netstrerror());
|
2008-11-11 13:24:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return(rc);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2009-01-09 09:29:17 +00:00
|
|
|
|
static int32_t set_socket_broadcast(int32_t onOrOff)
|
2008-11-11 13:24:05 +00:00
|
|
|
|
{
|
2009-01-09 09:29:17 +00:00
|
|
|
|
int32_t f = (onOrOff) ? 1 : 0;
|
|
|
|
|
int32_t rc;
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
|
|
|
|
/* give socket clearance to broadcast. */
|
2008-11-12 04:16:41 +00:00
|
|
|
|
rc = setsockopt(udpsocket, SOL_SOCKET, SO_BROADCAST, (char *)(&f), sizeof(f)) == 0;
|
2008-11-11 13:24:05 +00:00
|
|
|
|
if (!rc)
|
|
|
|
|
{
|
|
|
|
|
initprintf("%sset SO_BROADCAST failed: %s\n",
|
2008-11-12 04:16:41 +00:00
|
|
|
|
((onOrOff) ? "" : "un"), netstrerror());
|
2008-11-11 13:24:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return(rc);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2009-01-09 09:29:17 +00:00
|
|
|
|
static int32_t open_udp_socket(int32_t ip, int32_t port)
|
2008-11-11 13:24:05 +00:00
|
|
|
|
{
|
|
|
|
|
struct sockaddr_in addr;
|
|
|
|
|
|
2008-11-12 04:16:41 +00:00
|
|
|
|
// initprintf("Setting up UDP interface %s:%d...\n", static_ipstring(ip), port);
|
|
|
|
|
if (natfree)
|
|
|
|
|
{
|
2008-11-13 11:45:34 +00:00
|
|
|
|
//initprintf("Stun is currently %s\n", (natfree) ? "Enabled":"Disabled");
|
2009-03-14 02:55:39 +00:00
|
|
|
|
initprintf("network: Stun enabled\n");
|
2008-11-12 04:16:41 +00:00
|
|
|
|
}
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
|
|
|
|
udpsocket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
2008-11-11 13:45:12 +00:00
|
|
|
|
if ((signed)udpsocket == -1)
|
2008-11-11 13:24:05 +00:00
|
|
|
|
{
|
2009-03-14 02:55:39 +00:00
|
|
|
|
initprintf("network: socket creation failed: %s\n", netstrerror());
|
2008-11-11 13:24:05 +00:00
|
|
|
|
return(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!set_socket_blockmode(0))
|
|
|
|
|
return(0);
|
|
|
|
|
|
2008-11-12 04:16:41 +00:00
|
|
|
|
#if !PLATFORM_WIN32
|
2008-11-11 13:24:05 +00:00
|
|
|
|
{
|
|
|
|
|
/* !!! FIXME: Might be Linux (not Unix, not BSD, not WinSock) specific. */
|
2009-01-09 09:29:17 +00:00
|
|
|
|
int32_t flags = 1;
|
2009-03-27 21:54:55 +00:00
|
|
|
|
setsockopt(udpsocket, IPPROTO_IP, IP_RECVERR, &flags, sizeof(flags));
|
2008-11-11 13:24:05 +00:00
|
|
|
|
}
|
2008-11-12 04:16:41 +00:00
|
|
|
|
#endif
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
2008-11-12 04:16:41 +00:00
|
|
|
|
memset(&addr, '\0', sizeof(addr));
|
2008-11-11 13:24:05 +00:00
|
|
|
|
addr.sin_family = AF_INET;
|
|
|
|
|
addr.sin_addr.s_addr = htonl(ip);
|
2009-01-09 09:29:17 +00:00
|
|
|
|
addr.sin_port = htons((uint16_t)port);
|
2008-11-12 04:16:41 +00:00
|
|
|
|
if (bind(udpsocket, (struct sockaddr *) &addr, sizeof(addr)) == -1)
|
2008-11-11 13:24:05 +00:00
|
|
|
|
{
|
2009-03-14 02:55:39 +00:00
|
|
|
|
initprintf("network: socket binding failed: %s\n", netstrerror());
|
2008-11-11 13:24:05 +00:00
|
|
|
|
return(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return(1);
|
|
|
|
|
}
|
|
|
|
|
|
2009-01-09 09:29:17 +00:00
|
|
|
|
typedef struct peergreeting_t
|
2008-11-11 13:24:05 +00:00
|
|
|
|
{
|
2009-01-09 09:29:17 +00:00
|
|
|
|
char dummy1; /* so these don't confuse game after load. */
|
|
|
|
|
char dummy2; /* so these don't confuse game after load. */
|
|
|
|
|
char dummy3; /* so these don't confuse game after load. */
|
|
|
|
|
char header; /* always HEADER_PEER_GREETING (245). */
|
|
|
|
|
uint16_t id;
|
2008-11-11 13:24:05 +00:00
|
|
|
|
} PacketPeerGreeting;
|
|
|
|
|
|
|
|
|
|
|
2009-01-09 09:29:17 +00:00
|
|
|
|
static void send_peer_greeting(int32_t ip, uint16_t port, int16_t myid)
|
2008-11-11 13:24:05 +00:00
|
|
|
|
{
|
|
|
|
|
PacketPeerGreeting packet;
|
2008-11-12 04:16:41 +00:00
|
|
|
|
memset(&packet, '\0', sizeof(packet));
|
2008-11-11 13:24:05 +00:00
|
|
|
|
packet.header = HEADER_PEER_GREETING;
|
|
|
|
|
packet.id = B_SWAP16(myid);
|
2008-11-12 04:16:41 +00:00
|
|
|
|
send_udp_packet(ip, port, &packet, sizeof(packet));
|
2008-11-11 13:24:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
2008-11-12 22:28:02 +00:00
|
|
|
|
/* server init. */
|
2009-01-09 09:29:17 +00:00
|
|
|
|
static int32_t wait_for_other_players(gcomtype *gcom, int32_t myip)
|
2008-11-12 22:28:02 +00:00
|
|
|
|
{
|
|
|
|
|
PacketPeerGreeting packet;
|
2009-01-09 09:29:17 +00:00
|
|
|
|
uint16_t my_id = 1; // we're always 1 so we sort as the first player
|
|
|
|
|
int32_t i, j;
|
|
|
|
|
int32_t rc;
|
|
|
|
|
int32_t ip;
|
|
|
|
|
uint16_t port;
|
|
|
|
|
uint16_t heard_from[MAXPLAYERS];
|
|
|
|
|
int32_t max;
|
|
|
|
|
int32_t remaining;
|
2008-11-12 22:28:02 +00:00
|
|
|
|
|
|
|
|
|
memset(heard_from, '\0', sizeof(heard_from));
|
|
|
|
|
|
|
|
|
|
remaining = max = gcom->numplayers - 1;
|
|
|
|
|
|
|
|
|
|
initprintf("Waiting for %d player%s...\n", remaining, remaining==1 ? "":"s");
|
|
|
|
|
if (remaining == 0)
|
|
|
|
|
{
|
|
|
|
|
initprintf("Hmmm... don't have time to play with myself!\n");
|
|
|
|
|
return(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while (remaining && !quitevent)
|
|
|
|
|
{
|
|
|
|
|
handleevents();
|
|
|
|
|
|
|
|
|
|
idle();
|
|
|
|
|
|
|
|
|
|
process_udp_send_queue();
|
|
|
|
|
|
|
|
|
|
rc = get_udp_packet(&ip, &port, &packet, sizeof(packet));
|
|
|
|
|
|
|
|
|
|
//this is so we don't get unexpected packet errors from players already heard from
|
|
|
|
|
|
|
|
|
|
if ((rc > 0) && (ip) && ((ip != myip) || (port != udpport)))
|
|
|
|
|
{
|
|
|
|
|
char *ipstr = static_ipstring(ip);
|
|
|
|
|
|
2008-11-13 11:45:34 +00:00
|
|
|
|
if (rc != sizeof(packet))
|
|
|
|
|
{
|
2009-03-14 02:55:39 +00:00
|
|
|
|
initprintf("network: Missized packet or fragment from %s:%i ?!\n", ipstr, port);
|
2008-11-13 11:45:34 +00:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
else if (packet.header != HEADER_PEER_GREETING)
|
|
|
|
|
{
|
2009-03-14 02:55:39 +00:00
|
|
|
|
initprintf("network: Unexpected packet type from %s:%i ?!\n", ipstr, port);
|
2008-11-13 11:45:34 +00:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2008-11-12 22:28:02 +00:00
|
|
|
|
for (i = 0; i < max; i++)
|
|
|
|
|
{
|
2008-11-13 11:45:34 +00:00
|
|
|
|
if (!heard_from[i] || heard_from[i] == B_SWAP16(packet.id))
|
2008-11-12 22:28:02 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (i == max)
|
2009-03-14 02:55:39 +00:00
|
|
|
|
initprintf("network: Disallowed player %s:%d ?!\n", ipstr, port);
|
2008-11-12 22:28:02 +00:00
|
|
|
|
else if (heard_from[i] == 0)
|
|
|
|
|
{
|
|
|
|
|
packet.id = B_SWAP16(packet.id);
|
|
|
|
|
heard_from[i] = packet.id;
|
|
|
|
|
allowed_addresses[i].host = ip; /* bcast needs this. */
|
|
|
|
|
allowed_addresses[i].port = port;
|
|
|
|
|
remaining--;
|
|
|
|
|
|
2008-11-13 11:45:34 +00:00
|
|
|
|
initprintf("%s:%i (id 0x%X) connected, %d player%s left.\n",
|
2009-01-09 09:29:17 +00:00
|
|
|
|
ipstr, (unsigned)port ,(int32_t) packet.id,
|
2008-11-12 22:28:02 +00:00
|
|
|
|
remaining, remaining == 1 ? "" : "s");
|
|
|
|
|
|
|
|
|
|
/* make sure they've heard from us at all... */
|
|
|
|
|
/* !!! FIXME: Could be fatal if packet is dropped... */
|
2008-11-13 11:45:34 +00:00
|
|
|
|
|
2008-11-12 22:28:02 +00:00
|
|
|
|
send_peer_greeting(allowed_addresses[i].host,
|
|
|
|
|
allowed_addresses[i].port,
|
|
|
|
|
my_id);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (quitevent)
|
|
|
|
|
{
|
2009-03-14 02:55:39 +00:00
|
|
|
|
initprintf("network: Connection attempt aborted.\n");
|
2008-11-12 22:28:02 +00:00
|
|
|
|
return(0);
|
|
|
|
|
}
|
2008-11-13 11:45:34 +00:00
|
|
|
|
|
2008-11-15 05:18:07 +00:00
|
|
|
|
// found all the clients expected so relay all greetings
|
2009-02-19 16:47:54 +00:00
|
|
|
|
for (j=max; j>=0; j--)
|
2008-11-13 11:45:34 +00:00
|
|
|
|
if (allowed_addresses[j].host)
|
|
|
|
|
{
|
2009-01-09 09:29:17 +00:00
|
|
|
|
int32_t ii;
|
2008-11-15 05:18:07 +00:00
|
|
|
|
|
|
|
|
|
// send another copy of our greeting just in case they missed it
|
|
|
|
|
send_peer_greeting(allowed_addresses[j].host,
|
2009-02-19 16:47:54 +00:00
|
|
|
|
allowed_addresses[j].port,
|
|
|
|
|
my_id);
|
2008-11-15 05:18:07 +00:00
|
|
|
|
|
2008-11-13 11:45:34 +00:00
|
|
|
|
for (ii = 0; ii < max; ii++)
|
2008-11-12 22:28:02 +00:00
|
|
|
|
send_peer_greeting(allowed_addresses[j].host,
|
2008-11-13 11:45:34 +00:00
|
|
|
|
allowed_addresses[j].port,
|
|
|
|
|
heard_from[ii]);
|
|
|
|
|
|
2008-11-15 05:18:07 +00:00
|
|
|
|
// greeting with 0x1337 id starts the game for clients
|
2008-11-13 11:45:34 +00:00
|
|
|
|
send_peer_greeting(allowed_addresses[j].host,
|
|
|
|
|
allowed_addresses[j].port,
|
2008-11-20 14:06:36 +00:00
|
|
|
|
PACKET_START_GAME);
|
2008-11-13 11:45:34 +00:00
|
|
|
|
}
|
2008-11-12 22:28:02 +00:00
|
|
|
|
|
|
|
|
|
/* ok, now everyone is talking to you. Sort them into player numbers... */
|
|
|
|
|
|
|
|
|
|
heard_from[max] = my_id; /* so we sort, too... */
|
|
|
|
|
allowed_addresses[max].host = myip;
|
|
|
|
|
allowed_addresses[max].port = udpport;
|
|
|
|
|
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
remaining = 0;
|
|
|
|
|
for (i = 0; i < max; i++)
|
|
|
|
|
{
|
|
|
|
|
if (heard_from[i] == heard_from[i+1]) /* blah. */
|
|
|
|
|
{
|
2009-03-14 02:55:39 +00:00
|
|
|
|
initprintf("network: ERROR: Two players have the same random ID!\n");
|
|
|
|
|
initprintf("network: ERROR: Please restart the game to generate new IDs.\n");
|
2008-11-12 22:28:02 +00:00
|
|
|
|
return(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else if (heard_from[i] > heard_from[i+1])
|
|
|
|
|
{
|
2009-01-09 09:29:17 +00:00
|
|
|
|
int32_t tmpi;
|
|
|
|
|
int16_t tmps;
|
2008-11-12 22:28:02 +00:00
|
|
|
|
|
|
|
|
|
tmps = heard_from[i];
|
|
|
|
|
heard_from[i] = heard_from[i+1];
|
|
|
|
|
heard_from[i+1] = tmps;
|
|
|
|
|
|
|
|
|
|
tmpi = allowed_addresses[i].host;
|
|
|
|
|
allowed_addresses[i].host = allowed_addresses[i+1].host;
|
|
|
|
|
allowed_addresses[i+1].host = tmpi;
|
|
|
|
|
|
|
|
|
|
tmps = allowed_addresses[i].port;
|
|
|
|
|
allowed_addresses[i].port = allowed_addresses[i+1].port;
|
|
|
|
|
allowed_addresses[i+1].port = tmps;
|
|
|
|
|
|
|
|
|
|
remaining = 1; /* yay for bubble sorting! */
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
while (remaining);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Now we're sorted. But, the local player is referred to by both his
|
|
|
|
|
* player number and player index ZERO, so bump everyone up one to
|
|
|
|
|
* their actual index and fill in local player as item zero.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
memmove(&allowed_addresses[1], &allowed_addresses[0],
|
|
|
|
|
sizeof(allowed_addresses) - sizeof(allowed_addresses[0]));
|
|
|
|
|
allowed_addresses[0].host = myip;
|
|
|
|
|
|
|
|
|
|
gcom->myconnectindex = 0;
|
|
|
|
|
for (i = 1; i <= gcom->numplayers; i++)
|
|
|
|
|
{
|
|
|
|
|
ip = (allowed_addresses[i].host);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (ip == myip)
|
|
|
|
|
{
|
|
|
|
|
if (udpport == allowed_addresses[i].port)
|
|
|
|
|
gcom->myconnectindex = i;
|
|
|
|
|
}
|
|
|
|
|
|
2009-03-14 02:55:39 +00:00
|
|
|
|
initprintf("network: player #%i at %s:%i\n", i,static_ipstring(ip),allowed_addresses[i].port);
|
2008-11-12 22:28:02 +00:00
|
|
|
|
}
|
|
|
|
|
// assert(gcom->myconnectindex);
|
|
|
|
|
|
2009-03-14 02:55:39 +00:00
|
|
|
|
initprintf("network: We are player #%i\n", gcom->myconnectindex);
|
2008-11-12 22:28:02 +00:00
|
|
|
|
|
|
|
|
|
return(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* client init. */
|
2009-01-09 09:29:17 +00:00
|
|
|
|
static int32_t connect_to_server(gcomtype *gcom, int32_t myip)
|
2008-11-12 22:28:02 +00:00
|
|
|
|
{
|
|
|
|
|
PacketPeerGreeting packet;
|
2009-01-09 09:29:17 +00:00
|
|
|
|
uint16_t my_id = 0;
|
|
|
|
|
int32_t i;
|
|
|
|
|
int32_t rc;
|
|
|
|
|
int32_t ip;
|
|
|
|
|
uint16_t port;
|
|
|
|
|
int32_t first_send = 1;
|
|
|
|
|
uint16_t heard_from[MAXPLAYERS];
|
|
|
|
|
uint32_t resendat;
|
|
|
|
|
int32_t max;
|
|
|
|
|
int32_t remaining;
|
2008-11-12 22:28:02 +00:00
|
|
|
|
|
|
|
|
|
memset(heard_from, '\0', sizeof(heard_from));
|
|
|
|
|
|
2008-11-13 11:45:34 +00:00
|
|
|
|
gcom->numplayers = 2;
|
|
|
|
|
|
2008-11-12 22:28:02 +00:00
|
|
|
|
while (my_id == 0) /* player number is based on id, low to high. */
|
|
|
|
|
{
|
2009-07-24 02:31:34 +00:00
|
|
|
|
my_id = (unsigned short)GetTickCount();
|
|
|
|
|
// my_id = (uint16_t) rand();
|
2008-11-12 22:28:02 +00:00
|
|
|
|
}
|
|
|
|
|
|
2009-03-14 02:55:39 +00:00
|
|
|
|
initprintf("network: Using 0x%X as client ID\n", my_id);
|
2008-11-12 22:28:02 +00:00
|
|
|
|
|
|
|
|
|
resendat = getticks();
|
|
|
|
|
remaining = max = gcom->numplayers - 1;
|
|
|
|
|
|
2009-03-14 02:55:39 +00:00
|
|
|
|
initprintf("network: Waiting for %d player%s...\n", remaining, remaining==1 ? "":"s");
|
2008-11-12 22:28:02 +00:00
|
|
|
|
if (remaining == 0)
|
|
|
|
|
{
|
|
|
|
|
initprintf("Hmmm... don't have time to play with myself!\n");
|
|
|
|
|
return(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while (remaining && !quitevent)
|
|
|
|
|
{
|
|
|
|
|
handleevents();
|
|
|
|
|
|
|
|
|
|
if (resendat <= getticks())
|
|
|
|
|
{
|
2008-11-13 11:45:34 +00:00
|
|
|
|
for (i = 0; (i < max) || natfree ; i++)
|
|
|
|
|
{
|
2008-11-12 22:28:02 +00:00
|
|
|
|
|
2008-11-13 11:45:34 +00:00
|
|
|
|
//only checking one player at a time works
|
|
|
|
|
//this is where special formatting of allow lines comes in
|
|
|
|
|
if (!heard_from[i])
|
|
|
|
|
{
|
2009-03-14 02:55:39 +00:00
|
|
|
|
initprintf("network: %s %s:%d...\n",first_send?"Connecting to":"Retrying",
|
2008-11-13 11:45:34 +00:00
|
|
|
|
static_ipstring(allowed_addresses[i].host),allowed_addresses[i].port);
|
2008-11-12 22:28:02 +00:00
|
|
|
|
|
2008-11-13 11:45:34 +00:00
|
|
|
|
send_peer_greeting(allowed_addresses[i].host,
|
|
|
|
|
allowed_addresses[i].port,
|
|
|
|
|
my_id);
|
2008-11-12 22:28:02 +00:00
|
|
|
|
}
|
2008-11-13 11:45:34 +00:00
|
|
|
|
}
|
2008-11-12 22:28:02 +00:00
|
|
|
|
first_send = 0;
|
|
|
|
|
resendat += CLIENT_POLL_DELAY;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
idle();
|
|
|
|
|
process_udp_send_queue();
|
|
|
|
|
|
|
|
|
|
rc = get_udp_packet(&ip, &port, &packet, sizeof(packet));
|
|
|
|
|
|
|
|
|
|
//this is so we don't get unexpected packet errors from players already heard from
|
|
|
|
|
|
|
|
|
|
if ((rc > 0) && (ip) && ((ip != myip) || (port != udpport)))
|
|
|
|
|
{
|
|
|
|
|
char *ipstr = static_ipstring(ip);
|
|
|
|
|
|
2008-11-13 11:45:34 +00:00
|
|
|
|
if (rc != sizeof(packet))
|
2008-11-12 22:28:02 +00:00
|
|
|
|
{
|
2009-03-14 02:55:39 +00:00
|
|
|
|
initprintf("network: Missized packet or fragment from %s:%i ?!\n", ipstr, port);
|
2008-11-13 11:45:34 +00:00
|
|
|
|
continue;
|
|
|
|
|
}
|
2008-11-12 22:28:02 +00:00
|
|
|
|
else if (packet.header != HEADER_PEER_GREETING)
|
|
|
|
|
{
|
2009-03-14 02:55:39 +00:00
|
|
|
|
initprintf("network: Unexpected packet type from %s:%i ?!\n", ipstr, port);
|
2008-11-13 11:45:34 +00:00
|
|
|
|
continue;
|
|
|
|
|
}
|
2008-11-12 22:28:02 +00:00
|
|
|
|
|
2009-02-19 16:47:54 +00:00
|
|
|
|
for (i=0; i<MAXPLAYERS; i++)
|
2008-11-13 11:45:34 +00:00
|
|
|
|
if (!heard_from[i] || heard_from[i] == B_SWAP16(packet.id)) break; // only increase once
|
2008-11-12 22:28:02 +00:00
|
|
|
|
|
2008-11-15 05:18:07 +00:00
|
|
|
|
// greeting with 0x1337 id starts the game
|
2008-11-20 14:06:36 +00:00
|
|
|
|
if (B_SWAP16(packet.id) == PACKET_START_GAME)
|
2008-11-13 11:45:34 +00:00
|
|
|
|
{
|
|
|
|
|
remaining = 0;
|
|
|
|
|
continue;
|
2008-11-12 22:28:02 +00:00
|
|
|
|
}
|
2008-11-15 05:18:07 +00:00
|
|
|
|
// packet.id == 1 is always the server
|
2008-11-13 11:45:34 +00:00
|
|
|
|
else if (heard_from[i] == 0 && B_SWAP16(packet.id) == 1)
|
2008-11-12 22:28:02 +00:00
|
|
|
|
{
|
|
|
|
|
packet.id = B_SWAP16(packet.id);
|
|
|
|
|
heard_from[i] = packet.id;
|
|
|
|
|
|
2009-03-14 02:55:39 +00:00
|
|
|
|
initprintf("network: Connected to %s:%i\n",
|
2008-11-14 11:04:22 +00:00
|
|
|
|
ipstr, (unsigned)port);
|
2009-03-14 02:55:39 +00:00
|
|
|
|
initprintf("network: Waiting for server to launch game\n");
|
2008-11-13 11:45:34 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2008-11-15 05:18:07 +00:00
|
|
|
|
if (heard_from[i] == 0 && B_SWAP16(packet.id) != my_id)
|
2008-11-13 11:45:34 +00:00
|
|
|
|
{
|
2008-11-15 05:18:07 +00:00
|
|
|
|
packet.id = B_SWAP16(packet.id);
|
|
|
|
|
heard_from[i] = packet.id;
|
|
|
|
|
|
2009-03-14 02:55:39 +00:00
|
|
|
|
initprintf("network: New player with id 0x%X\n",
|
2009-02-19 16:47:54 +00:00
|
|
|
|
(int32_t) packet.id);
|
2008-11-15 05:18:07 +00:00
|
|
|
|
gcom->numplayers++;
|
|
|
|
|
max++;
|
2008-11-13 11:45:34 +00:00
|
|
|
|
}
|
2008-11-12 22:28:02 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (quitevent)
|
|
|
|
|
{
|
2009-03-14 02:55:39 +00:00
|
|
|
|
initprintf("network: Connection attempt aborted.\n");
|
2008-11-12 22:28:02 +00:00
|
|
|
|
return(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ok, now everyone is talking to you. Sort them into player numbers... */
|
|
|
|
|
|
|
|
|
|
heard_from[max] = my_id; /* so we sort, too... */
|
|
|
|
|
allowed_addresses[max].host = myip;
|
|
|
|
|
allowed_addresses[max].port = udpport;
|
|
|
|
|
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
remaining = 0;
|
|
|
|
|
for (i = 0; i < max; i++)
|
|
|
|
|
{
|
|
|
|
|
if (heard_from[i] == heard_from[i+1]) /* blah. */
|
|
|
|
|
{
|
2009-03-14 02:55:39 +00:00
|
|
|
|
initprintf("network: ERROR: Two players have the same random ID!\n");
|
|
|
|
|
initprintf("network: ERROR: Please restart the game to generate new IDs.\n");
|
2008-11-12 22:28:02 +00:00
|
|
|
|
return(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else if (heard_from[i] > heard_from[i+1])
|
|
|
|
|
{
|
2009-01-09 09:29:17 +00:00
|
|
|
|
int32_t tmpi;
|
|
|
|
|
int16_t tmps;
|
2008-11-12 22:28:02 +00:00
|
|
|
|
|
|
|
|
|
tmps = heard_from[i];
|
|
|
|
|
heard_from[i] = heard_from[i+1];
|
|
|
|
|
heard_from[i+1] = tmps;
|
|
|
|
|
|
|
|
|
|
tmpi = allowed_addresses[i].host;
|
|
|
|
|
allowed_addresses[i].host = allowed_addresses[i+1].host;
|
|
|
|
|
allowed_addresses[i+1].host = tmpi;
|
|
|
|
|
|
|
|
|
|
tmps = allowed_addresses[i].port;
|
|
|
|
|
allowed_addresses[i].port = allowed_addresses[i+1].port;
|
|
|
|
|
allowed_addresses[i+1].port = tmps;
|
|
|
|
|
|
|
|
|
|
remaining = 1; /* yay for bubble sorting! */
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
while (remaining);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Now we're sorted. But, the local player is referred to by both his
|
|
|
|
|
* player number and player index ZERO, so bump everyone up one to
|
|
|
|
|
* their actual index and fill in local player as item zero.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
memmove(&allowed_addresses[1], &allowed_addresses[0],
|
|
|
|
|
sizeof(allowed_addresses) - sizeof(allowed_addresses[0]));
|
|
|
|
|
allowed_addresses[0].host = myip;
|
|
|
|
|
|
|
|
|
|
gcom->myconnectindex = 0;
|
|
|
|
|
for (i = 1; i <= gcom->numplayers; i++)
|
|
|
|
|
{
|
|
|
|
|
ip = (allowed_addresses[i].host);
|
|
|
|
|
|
|
|
|
|
if (ip == myip)
|
|
|
|
|
{
|
|
|
|
|
if (udpport == allowed_addresses[i].port)
|
|
|
|
|
gcom->myconnectindex = i;
|
|
|
|
|
}
|
|
|
|
|
|
2009-03-14 02:55:39 +00:00
|
|
|
|
// initprintf("network: player #%i with id %d\n",i,heard_from[i]);
|
2008-11-12 22:28:02 +00:00
|
|
|
|
}
|
|
|
|
|
// assert(gcom->myconnectindex);
|
|
|
|
|
|
2009-03-14 02:55:39 +00:00
|
|
|
|
// initprintf("network: We are player #%i\n", gcom->myconnectindex);
|
2008-11-12 22:28:02 +00:00
|
|
|
|
|
|
|
|
|
return(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2008-11-11 13:24:05 +00:00
|
|
|
|
/* peer to peer init. */
|
2009-01-09 09:29:17 +00:00
|
|
|
|
static int32_t connect_to_everyone(gcomtype *gcom, int32_t myip, int32_t bcast)
|
2008-11-11 13:24:05 +00:00
|
|
|
|
{
|
|
|
|
|
PacketPeerGreeting packet;
|
2009-01-09 09:29:17 +00:00
|
|
|
|
uint16_t my_id = 0;
|
|
|
|
|
int32_t i;
|
|
|
|
|
int32_t rc;
|
|
|
|
|
int32_t ip;
|
|
|
|
|
uint16_t port;
|
|
|
|
|
int32_t first_send = 1;
|
|
|
|
|
uint16_t heard_from[MAXPLAYERS];
|
|
|
|
|
uint32_t resendat;
|
|
|
|
|
int32_t max;
|
|
|
|
|
int32_t remaining;
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
|
|
|
|
if (bcast)
|
|
|
|
|
{
|
|
|
|
|
if (gcom->numplayers > 1)
|
|
|
|
|
{
|
2009-03-14 02:55:39 +00:00
|
|
|
|
initprintf("network: Error: can't do both 'broadcast' and 'allow'.\n");
|
2008-11-11 13:24:05 +00:00
|
|
|
|
return(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!set_socket_broadcast(1))
|
|
|
|
|
return(0);
|
|
|
|
|
|
|
|
|
|
gcom->numplayers = bcast + 1;
|
|
|
|
|
}
|
|
|
|
|
|
2008-11-12 04:16:41 +00:00
|
|
|
|
memset(heard_from, '\0', sizeof(heard_from));
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
|
|
|
|
while (my_id == 0) /* player number is based on id, low to high. */
|
2008-11-12 22:28:02 +00:00
|
|
|
|
{
|
2009-02-19 16:47:54 +00:00
|
|
|
|
/* struct timeval tv;
|
|
|
|
|
gettimeofday(&tv, NULL);
|
|
|
|
|
my_id = (unsigned short)tv.tv_usec; //HACK */
|
2009-01-09 09:29:17 +00:00
|
|
|
|
my_id = (uint16_t) rand();
|
2008-11-12 22:28:02 +00:00
|
|
|
|
}
|
|
|
|
|
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
2009-03-14 02:55:39 +00:00
|
|
|
|
initprintf("network: Using 0x%X as client ID\n", my_id);
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
|
|
|
|
resendat = getticks();
|
|
|
|
|
remaining = max = gcom->numplayers - 1;
|
|
|
|
|
|
|
|
|
|
initprintf("Waiting for %d player%s...\n", remaining, remaining==1 ? "":"s");
|
|
|
|
|
if (remaining == 0)
|
|
|
|
|
{
|
2008-11-12 04:16:41 +00:00
|
|
|
|
initprintf("Hmmm... don't have time to play with myself!\n");
|
2008-11-11 13:24:05 +00:00
|
|
|
|
return(0);
|
|
|
|
|
}
|
|
|
|
|
|
2008-11-12 22:28:02 +00:00
|
|
|
|
while (remaining && !quitevent)
|
2008-11-11 13:24:05 +00:00
|
|
|
|
{
|
2008-11-12 04:16:41 +00:00
|
|
|
|
handleevents();
|
2008-11-11 14:48:59 +00:00
|
|
|
|
|
2008-11-11 13:24:05 +00:00
|
|
|
|
if (resendat <= getticks())
|
|
|
|
|
{
|
|
|
|
|
if (bcast)
|
|
|
|
|
{
|
|
|
|
|
initprintf("%sroadcasting greeting...\n", first_send ? "B":"Reb");
|
|
|
|
|
/* !!! FIXME: This is...probably not right. */
|
|
|
|
|
send_peer_greeting(0xFFFFFFFF, udpport, my_id);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
for (i = 0; (i < max) || natfree ; i++)
|
|
|
|
|
{
|
2008-11-12 04:16:41 +00:00
|
|
|
|
|
|
|
|
|
//only checking one player at a time works
|
|
|
|
|
//this is where special formatting of allow lines comes in
|
|
|
|
|
if (natfree)
|
|
|
|
|
{
|
|
|
|
|
i = itmp; //addfaz router fix
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!heard_from[i])
|
|
|
|
|
{
|
2009-03-14 02:55:39 +00:00
|
|
|
|
initprintf("network: %s %s:%d...\n",first_send?"Connecting to":"Retrying",
|
2008-11-13 11:45:34 +00:00
|
|
|
|
static_ipstring(allowed_addresses[i].host),allowed_addresses[i].port);
|
2008-11-12 04:16:41 +00:00
|
|
|
|
|
|
|
|
|
send_peer_greeting(allowed_addresses[i].host,
|
2008-11-11 13:24:05 +00:00
|
|
|
|
allowed_addresses[i].port,
|
|
|
|
|
my_id);
|
|
|
|
|
}
|
|
|
|
|
|
2008-11-12 04:16:41 +00:00
|
|
|
|
// If this is stun-enabled then don't loop.
|
|
|
|
|
if (natfree)
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
2008-11-11 13:24:05 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
first_send = 0;
|
|
|
|
|
resendat += CLIENT_POLL_DELAY;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
idle();
|
|
|
|
|
process_udp_send_queue();
|
|
|
|
|
|
2008-11-12 04:16:41 +00:00
|
|
|
|
rc = get_udp_packet(&ip, &port, &packet, sizeof(packet));
|
|
|
|
|
|
|
|
|
|
//this is so we don't get unexpected packet errors from players already heard from
|
|
|
|
|
|
|
|
|
|
if (natfree)
|
|
|
|
|
{
|
|
|
|
|
//addfaz router/stun addition *Start*
|
|
|
|
|
//this is so we are not dealing with players already heard from.
|
|
|
|
|
for (i = 0; i < max; i++)
|
|
|
|
|
{
|
|
|
|
|
if (ip == allowed_addresses[i].host &&
|
|
|
|
|
port == allowed_addresses[i].port)
|
|
|
|
|
{
|
|
|
|
|
if (heard_from[i] != 0) //if we've heard from player already.
|
|
|
|
|
{
|
|
|
|
|
rc = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
//addfaz router/stun addition *End*
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if ((rc > 0) && (ip) && ((ip != myip) || (port != udpport)))
|
2008-11-11 13:24:05 +00:00
|
|
|
|
{
|
|
|
|
|
char *ipstr = static_ipstring(ip);
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < max; i++)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
////addfaz NAT addition *START*////
|
2008-11-12 22:28:02 +00:00
|
|
|
|
if (natfree)
|
2008-11-12 04:16:41 +00:00
|
|
|
|
{
|
|
|
|
|
if (tmpmax[i] != 1)
|
|
|
|
|
{
|
|
|
|
|
if (allowed_addresses[i].host == ip)
|
|
|
|
|
{
|
|
|
|
|
if (allowed_addresses[i].port != port)
|
|
|
|
|
{
|
2009-03-14 02:55:39 +00:00
|
|
|
|
initprintf("network: Port number for player %d changed from %d to %d.\n",i,allowed_addresses[i].port,port);
|
2008-11-12 04:16:41 +00:00
|
|
|
|
/* initprintf("Different player Port Number detected. %s:%i\n",ipstr,
|
|
|
|
|
allowed_addresses[i].port);
|
|
|
|
|
initprintf("Changed to %s:%i, player may be behind a firewall.\n", ipstr, port); //addfaz NAT addition */
|
|
|
|
|
allowed_addresses[i].port = port;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
////addfaz NAT addition *END*////
|
|
|
|
|
|
|
|
|
|
if ((ip == allowed_addresses[i].host) &&
|
|
|
|
|
(port == allowed_addresses[i].port)) //addfaz NAT line addition
|
2008-11-11 13:24:05 +00:00
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((bcast) && (allowed_addresses[i].host == 0))
|
|
|
|
|
break; /* select this slot. */
|
2008-11-12 04:16:41 +00:00
|
|
|
|
|
2008-11-11 13:24:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (i == max)
|
2009-03-14 02:55:39 +00:00
|
|
|
|
initprintf("network: Disallowed player %s:%d ?!\n", ipstr, port);
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
2008-11-12 04:16:41 +00:00
|
|
|
|
else if (rc != sizeof(packet))
|
2009-03-14 02:55:39 +00:00
|
|
|
|
initprintf("network: Missized packet or fragment from %s:%i ?!\n", ipstr, port);
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
|
|
|
|
else if (packet.header != HEADER_PEER_GREETING)
|
2009-03-14 02:55:39 +00:00
|
|
|
|
initprintf("network: Unexpected packet type from %s:%i ?!\n", ipstr, port);
|
2008-11-12 04:16:41 +00:00
|
|
|
|
|
2008-11-11 13:24:05 +00:00
|
|
|
|
else if (heard_from[i] == 0)
|
|
|
|
|
{
|
|
|
|
|
packet.id = B_SWAP16(packet.id);
|
|
|
|
|
heard_from[i] = packet.id;
|
|
|
|
|
allowed_addresses[i].host = ip; /* bcast needs this. */
|
|
|
|
|
allowed_addresses[i].port = port;
|
|
|
|
|
remaining--;
|
|
|
|
|
|
2009-03-14 02:55:39 +00:00
|
|
|
|
initprintf("network: Connected to %s:%i (id 0x%X). %d player%s left.\n",
|
2009-01-09 09:29:17 +00:00
|
|
|
|
ipstr, port ,(int32_t) packet.id,
|
2008-11-12 04:16:41 +00:00
|
|
|
|
remaining, remaining == 1 ? "" : "s");
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
|
|
|
|
/* make sure they've heard from us at all... */
|
|
|
|
|
/* !!! FIXME: Could be fatal if packet is dropped... */
|
|
|
|
|
send_peer_greeting(allowed_addresses[i].host,
|
|
|
|
|
allowed_addresses[i].port,
|
|
|
|
|
my_id);
|
2008-11-12 04:16:41 +00:00
|
|
|
|
|
|
|
|
|
if (natfree)
|
|
|
|
|
{
|
|
|
|
|
itmp++; //addfaz router/stun addition (goto next player)
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
tmpmax[i] = 1; //addfaz line addition
|
|
|
|
|
}
|
2008-11-11 13:24:05 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2008-11-12 04:16:41 +00:00
|
|
|
|
|
2008-11-12 22:28:02 +00:00
|
|
|
|
if (quitevent)
|
2008-11-11 13:24:05 +00:00
|
|
|
|
{
|
2009-03-14 02:55:39 +00:00
|
|
|
|
initprintf("network: Connection attempt aborted.\n");
|
2008-11-11 13:24:05 +00:00
|
|
|
|
return(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ok, now everyone is talking to you. Sort them into player numbers... */
|
|
|
|
|
|
|
|
|
|
heard_from[max] = my_id; /* so we sort, too... */
|
|
|
|
|
allowed_addresses[max].host = myip;
|
|
|
|
|
allowed_addresses[max].port = udpport;
|
|
|
|
|
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
remaining = 0;
|
|
|
|
|
for (i = 0; i < max; i++)
|
|
|
|
|
{
|
|
|
|
|
if (heard_from[i] == heard_from[i+1]) /* blah. */
|
|
|
|
|
{
|
2009-03-14 02:55:39 +00:00
|
|
|
|
initprintf("network: ERROR: Two players have the same random ID!\n");
|
|
|
|
|
initprintf("network: ERROR: Please restart the game to generate new IDs.\n");
|
2008-11-11 13:24:05 +00:00
|
|
|
|
return(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else if (heard_from[i] > heard_from[i+1])
|
|
|
|
|
{
|
2009-01-09 09:29:17 +00:00
|
|
|
|
int32_t tmpi;
|
|
|
|
|
int16_t tmps;
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
|
|
|
|
tmps = heard_from[i];
|
|
|
|
|
heard_from[i] = heard_from[i+1];
|
|
|
|
|
heard_from[i+1] = tmps;
|
|
|
|
|
|
|
|
|
|
tmpi = allowed_addresses[i].host;
|
|
|
|
|
allowed_addresses[i].host = allowed_addresses[i+1].host;
|
|
|
|
|
allowed_addresses[i+1].host = tmpi;
|
|
|
|
|
|
|
|
|
|
tmps = allowed_addresses[i].port;
|
|
|
|
|
allowed_addresses[i].port = allowed_addresses[i+1].port;
|
|
|
|
|
allowed_addresses[i+1].port = tmps;
|
|
|
|
|
|
|
|
|
|
remaining = 1; /* yay for bubble sorting! */
|
|
|
|
|
}
|
|
|
|
|
}
|
2008-11-12 04:16:41 +00:00
|
|
|
|
}
|
|
|
|
|
while (remaining);
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Now we're sorted. But, the local player is referred to by both his
|
|
|
|
|
* player number and player index ZERO, so bump everyone up one to
|
|
|
|
|
* their actual index and fill in local player as item zero.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
memmove(&allowed_addresses[1], &allowed_addresses[0],
|
2008-11-12 04:16:41 +00:00
|
|
|
|
sizeof(allowed_addresses) - sizeof(allowed_addresses[0]));
|
2008-11-11 13:24:05 +00:00
|
|
|
|
allowed_addresses[0].host = myip;
|
|
|
|
|
|
|
|
|
|
gcom->myconnectindex = 0;
|
|
|
|
|
for (i = 1; i <= gcom->numplayers; i++)
|
|
|
|
|
{
|
|
|
|
|
ip = (allowed_addresses[i].host);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (ip == myip)
|
2008-11-12 04:16:41 +00:00
|
|
|
|
{
|
2008-11-11 13:24:05 +00:00
|
|
|
|
if (udpport == allowed_addresses[i].port)
|
2008-11-12 04:16:41 +00:00
|
|
|
|
gcom->myconnectindex = i;
|
|
|
|
|
}
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
2009-03-14 02:55:39 +00:00
|
|
|
|
initprintf("network: player #%i at %s:%i\n", i,static_ipstring(ip),allowed_addresses[i].port);
|
2008-11-11 13:24:05 +00:00
|
|
|
|
}
|
|
|
|
|
// assert(gcom->myconnectindex);
|
|
|
|
|
|
2009-03-14 02:55:39 +00:00
|
|
|
|
initprintf("network: We are player #%i\n", gcom->myconnectindex);
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Ok, we should have specific IPs and ports for all players, and
|
|
|
|
|
* therefore shouldn't broadcast anymore. Disable permission to do so,
|
|
|
|
|
* just in case, so we aren't flooding the LAN with broadcasted packets.
|
|
|
|
|
*/
|
|
|
|
|
set_socket_broadcast(0);
|
|
|
|
|
|
|
|
|
|
return(1);
|
|
|
|
|
}
|
|
|
|
|
|
2009-01-09 09:29:17 +00:00
|
|
|
|
static int32_t parse_ip(const char *str, int32_t *ip)
|
2008-11-11 13:24:05 +00:00
|
|
|
|
{
|
2009-01-09 09:29:17 +00:00
|
|
|
|
int32_t ip1, ip2, ip3, ip4;
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
|
|
|
|
if (Bstrcasecmp(str, "any") == 0)
|
|
|
|
|
{
|
|
|
|
|
*ip = 0;
|
|
|
|
|
return(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (sscanf(str, "%d.%d.%d.%d", &ip1, &ip2, &ip3, &ip4) != 4)
|
|
|
|
|
{
|
|
|
|
|
initprintf("\"%s\" is not a valid IP address.\n", str);
|
|
|
|
|
return(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* we _should_ check that 0 <= ip? <= 255, but it'll fail later anyhow. */
|
|
|
|
|
|
2008-11-12 04:16:41 +00:00
|
|
|
|
*ip = (((ip1 & 0xFF) << 24) |
|
|
|
|
|
((ip2 & 0xFF) << 16) |
|
|
|
|
|
((ip3 & 0xFF) << 8) |
|
|
|
|
|
((ip4 & 0xFF)));
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
|
|
|
|
return(1);
|
|
|
|
|
}
|
|
|
|
|
|
2009-01-09 09:29:17 +00:00
|
|
|
|
static int32_t parse_interface(char *str, int32_t *ip, uint16_t *udpport)
|
2008-11-11 13:24:05 +00:00
|
|
|
|
{
|
|
|
|
|
char *ptr = strchr(str, ':');
|
|
|
|
|
if (ptr) /* portnum specified? */
|
|
|
|
|
*ptr = '\0';
|
|
|
|
|
|
|
|
|
|
if (!parse_ip(str, ip))
|
|
|
|
|
return(0);
|
|
|
|
|
|
|
|
|
|
*udpport = BUILD_DEFAULT_UDP_PORT;
|
|
|
|
|
if (ptr != NULL) /* port specified? */
|
|
|
|
|
{
|
|
|
|
|
ptr++;
|
|
|
|
|
if (Bstrcasecmp(ptr, "any") == 0)
|
|
|
|
|
*udpport = 0;
|
|
|
|
|
else
|
2009-01-09 09:29:17 +00:00
|
|
|
|
*udpport = (int16_t) atoi(ptr);
|
2008-11-11 13:24:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return(1);
|
|
|
|
|
}
|
|
|
|
|
|
2009-01-09 09:29:17 +00:00
|
|
|
|
static int32_t initialize_sockets(void)
|
2008-11-11 13:24:05 +00:00
|
|
|
|
{
|
|
|
|
|
#if PLATFORM_WIN32
|
2009-01-09 09:29:17 +00:00
|
|
|
|
int32_t rc;
|
2008-11-11 13:24:05 +00:00
|
|
|
|
WSADATA data;
|
2008-11-12 04:16:41 +00:00
|
|
|
|
// initprintf("initializing WinSock...\n");
|
2008-11-11 13:24:05 +00:00
|
|
|
|
rc = WSAStartup(0x0101, &data);
|
|
|
|
|
if (rc != 0)
|
|
|
|
|
{
|
|
|
|
|
initprintf("WinSock failed to initialize! [err==%d].\n", rc);
|
|
|
|
|
return(0);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2008-11-13 11:45:34 +00:00
|
|
|
|
/* initprintf("WinSock initialized.\n");
|
|
|
|
|
initprintf(" - Caller uses version %d.%d, highest supported is %d.%d.\n",
|
|
|
|
|
data.wVersion >> 8, data.wVersion & 0xFF,
|
|
|
|
|
data.wHighVersion >> 8, data.wHighVersion & 0xFF);
|
|
|
|
|
initprintf(" - Implementation description: [%s].\n", data.szDescription);
|
|
|
|
|
initprintf(" - System status: [%s].\n", data.szSystemStatus);
|
|
|
|
|
initprintf(" - Max sockets: %d.\n", data.iMaxSockets);
|
|
|
|
|
initprintf(" - Max UDP datagram size: %d.\n", data.iMaxUdpDg); */
|
2008-11-11 13:24:05 +00:00
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
return(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void deinitialize_sockets(void)
|
|
|
|
|
{
|
|
|
|
|
#if PLATFORM_WIN32
|
|
|
|
|
WSACleanup();
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
2009-01-09 09:29:17 +00:00
|
|
|
|
int32_t isvalidipaddress(char *st)
|
2008-11-14 19:55:48 +00:00
|
|
|
|
{
|
2009-01-09 09:29:17 +00:00
|
|
|
|
int32_t i, bcnt, num;
|
2008-11-14 19:55:48 +00:00
|
|
|
|
|
|
|
|
|
bcnt = 0; num = 0;
|
2009-02-19 16:47:54 +00:00
|
|
|
|
for (i=0; st[i]; i++)
|
2008-11-14 19:55:48 +00:00
|
|
|
|
{
|
|
|
|
|
if (st[i] == '.') { bcnt++; num = 0; continue; }
|
|
|
|
|
if (st[i] == ':')
|
|
|
|
|
{
|
|
|
|
|
if (bcnt != 3) return(0);
|
|
|
|
|
num = 0;
|
2009-02-19 16:47:54 +00:00
|
|
|
|
for (i++; st[i]; i++)
|
2008-11-14 19:55:48 +00:00
|
|
|
|
{
|
|
|
|
|
if ((st[i] >= '0') && (st[i] <= '9'))
|
|
|
|
|
{ num = num*10+st[i]-'0'; if (num >= 65536) return(0); }
|
|
|
|
|
else return(0);
|
|
|
|
|
}
|
|
|
|
|
return(1);
|
|
|
|
|
}
|
|
|
|
|
if ((st[i] >= '0') && (st[i] <= '9'))
|
|
|
|
|
{ num = num*10+st[i]-'0'; if (num >= 256) return(0); }
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
return(bcnt == 3);
|
|
|
|
|
}
|
2008-11-14 08:22:57 +00:00
|
|
|
|
|
2009-01-09 09:29:17 +00:00
|
|
|
|
static int32_t parse_udp_config(int32_t argc, char **argv, gcomtype *gcom)
|
2008-11-11 13:24:05 +00:00
|
|
|
|
{
|
|
|
|
|
char *buf;
|
|
|
|
|
char *tok;
|
|
|
|
|
char *ptr;
|
2009-01-09 09:29:17 +00:00
|
|
|
|
int32_t ip = 0; /* interface */
|
|
|
|
|
int32_t bcast = 0;
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
2008-11-14 08:22:57 +00:00
|
|
|
|
buf = read_whole_file(argv[0]); /* we must free this. */
|
2008-11-11 13:24:05 +00:00
|
|
|
|
if (buf == NULL)
|
|
|
|
|
{
|
2008-11-14 08:22:57 +00:00
|
|
|
|
// do JF-style argv parsing here
|
2009-01-09 09:29:17 +00:00
|
|
|
|
int32_t i, j, daindex;
|
|
|
|
|
int32_t danetmode = 255;
|
2008-11-14 19:55:48 +00:00
|
|
|
|
char *st;
|
|
|
|
|
|
|
|
|
|
daindex = 0;
|
|
|
|
|
|
|
|
|
|
// if (!argv) return 0;
|
|
|
|
|
// go looking for the port, if specified
|
2009-02-19 16:47:54 +00:00
|
|
|
|
for (i=0; i<argc; i++)
|
2008-11-14 19:55:48 +00:00
|
|
|
|
{
|
|
|
|
|
if (argv[i][0] != '-' && argv[i][0] != '/') continue;
|
|
|
|
|
if ((argv[i][1] == 'p' || argv[i][1] == 'P') && argv[i][2])
|
|
|
|
|
{
|
|
|
|
|
char *p;
|
|
|
|
|
j = strtol(argv[i]+2, &p, 10);
|
|
|
|
|
if (!(*p) && j > 1024 && j<65535) udpport = j;
|
|
|
|
|
|
2009-03-14 02:55:39 +00:00
|
|
|
|
initprintf("network: Using port %d\n", udpport);
|
2008-11-14 19:55:48 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-19 16:47:54 +00:00
|
|
|
|
for (i=0; i<argc; i++)
|
2008-11-14 19:55:48 +00:00
|
|
|
|
{
|
|
|
|
|
if ((argv[i][0] == '-') || (argv[i][0] == '/'))
|
|
|
|
|
{
|
|
|
|
|
if ((argv[i][1] == 'N') || (argv[i][1] == 'n') || (argv[i][1] == 'I') || (argv[i][1] == 'i'))
|
|
|
|
|
{
|
|
|
|
|
gcom->numplayers = 1;
|
|
|
|
|
if (argv[i][2] == '0')
|
|
|
|
|
{
|
|
|
|
|
danetmode = 0;
|
|
|
|
|
udpmode = udpmode_client;
|
|
|
|
|
if ((argv[i][3] == ':') && (argv[i][4] >= '0') && (argv[i][4] <= '9'))
|
|
|
|
|
{
|
|
|
|
|
udpmode = udpmode_server;
|
|
|
|
|
gcom->numplayers = (argv[i][4]-'0');
|
|
|
|
|
if ((argv[i][5] >= '0') && (argv[i][5] <= '9')) gcom->numplayers = gcom->numplayers*10+(argv[i][5]-'0');
|
2009-03-14 02:55:39 +00:00
|
|
|
|
initprintf("network: %d-player game server\n", gcom->numplayers--);
|
2008-11-14 19:55:48 +00:00
|
|
|
|
}
|
2009-03-14 02:55:39 +00:00
|
|
|
|
initprintf("network: Master-slave mode\n");
|
2008-11-14 19:55:48 +00:00
|
|
|
|
}
|
|
|
|
|
else if (argv[i][2] == '1')
|
|
|
|
|
{
|
|
|
|
|
danetmode = 1;
|
|
|
|
|
udpmode = udpmode_peer;
|
|
|
|
|
myconnectindex = daindex;
|
|
|
|
|
// daindex++;
|
2009-03-14 02:55:39 +00:00
|
|
|
|
initprintf("network: Peer-to-peer mode\n");
|
2008-11-14 19:55:48 +00:00
|
|
|
|
}
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
else if ((argv[i][1] == 'P') || (argv[i][1] == 'p')) continue;
|
|
|
|
|
}
|
|
|
|
|
|
2008-11-15 05:18:07 +00:00
|
|
|
|
st = strdup(argv[i]);
|
|
|
|
|
if (!st) break;
|
2008-11-14 19:55:48 +00:00
|
|
|
|
if (isvalidipaddress(st))
|
|
|
|
|
{
|
|
|
|
|
// if ((danetmode == 1) && (daindex == myconnectindex)) daindex++;
|
|
|
|
|
parse_interface(st, &allowed_addresses[daindex].host, &allowed_addresses[daindex].port);
|
2009-03-14 02:55:39 +00:00
|
|
|
|
initprintf("network: Player %d at %s:%d\n",daindex,st,allowed_addresses[daindex].port);
|
2008-11-14 19:55:48 +00:00
|
|
|
|
daindex++;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
struct hostent * lph;
|
2009-01-09 09:29:17 +00:00
|
|
|
|
uint16_t pt = BUILD_DEFAULT_UDP_PORT;
|
2008-11-14 19:55:48 +00:00
|
|
|
|
|
2009-02-19 16:47:54 +00:00
|
|
|
|
for (j=0; st[j]; j++)
|
2008-11-14 19:55:48 +00:00
|
|
|
|
if (st[j] == ':')
|
2009-01-09 09:29:17 +00:00
|
|
|
|
{ pt = (uint16_t)atol(&st[j+1]); st[j] = 0; break; }
|
2008-11-14 19:55:48 +00:00
|
|
|
|
if ((lph = gethostbyname(st)))
|
|
|
|
|
{
|
|
|
|
|
// if ((danetmode == 1) && (daindex == myconnectindex)) daindex++;
|
2009-01-09 09:29:17 +00:00
|
|
|
|
allowed_addresses[daindex].host = ntohl(*(int32_t *)lph->h_addr);
|
2008-11-14 19:55:48 +00:00
|
|
|
|
allowed_addresses[daindex].port = pt;
|
2009-03-14 02:55:39 +00:00
|
|
|
|
initprintf("network: Player %d at %s:%d (%s)\n",daindex,
|
2008-11-14 19:55:48 +00:00
|
|
|
|
inet_ntoa(*(struct in_addr *)lph->h_addr),pt,argv[i]);
|
|
|
|
|
daindex++;
|
|
|
|
|
}
|
2009-03-14 02:55:39 +00:00
|
|
|
|
else initprintf("network: Failed resolving %s\n",argv[i]);
|
2008-11-14 19:55:48 +00:00
|
|
|
|
}
|
|
|
|
|
free(st);
|
|
|
|
|
}
|
|
|
|
|
if ((danetmode == 255) && (daindex)) { gcom->numplayers = 2; udpmode = udpmode_client; } //an IP w/o /n# defaults to /n0
|
|
|
|
|
// if ((numplayers >= 2) && (daindex) && (!danetmode)) myconnectindex = 1;
|
|
|
|
|
if (daindex > gcom->numplayers) gcom->numplayers = daindex;
|
2008-11-14 08:22:57 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2009-03-14 02:55:39 +00:00
|
|
|
|
initprintf("network: Using '%s' as configuration file\n", argv[0]);
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
2008-11-14 08:22:57 +00:00
|
|
|
|
ptr = buf;
|
|
|
|
|
while ((tok = get_token(&ptr)) != NULL)
|
2008-11-11 13:24:05 +00:00
|
|
|
|
{
|
2009-01-09 09:29:17 +00:00
|
|
|
|
int32_t bogus = 1;
|
2008-11-14 08:22:57 +00:00
|
|
|
|
|
|
|
|
|
if (Bstrcasecmp(tok, "interface") == 0)
|
|
|
|
|
{
|
|
|
|
|
if ((tok = get_token(&ptr)) &&
|
2008-11-14 19:55:48 +00:00
|
|
|
|
(parse_interface(tok, &ip, &udpport)))
|
2008-11-14 08:22:57 +00:00
|
|
|
|
{
|
|
|
|
|
bogus = 0;
|
|
|
|
|
}
|
2009-03-14 02:55:39 +00:00
|
|
|
|
initprintf("network: Using interface %s:%d\n",
|
2009-01-09 09:29:17 +00:00
|
|
|
|
static_ipstring(ip), (int32_t) udpport);
|
2008-11-14 08:22:57 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else if (Bstrcasecmp(tok, "mode") == 0)
|
2008-11-11 13:24:05 +00:00
|
|
|
|
{
|
2008-11-14 08:22:57 +00:00
|
|
|
|
if ((tok = get_token(&ptr)) != NULL)
|
|
|
|
|
{
|
|
|
|
|
bogus = 0;
|
|
|
|
|
if (Bstrcasecmp(tok, "server") == 0)
|
|
|
|
|
udpmode = udpmode_server;
|
|
|
|
|
else if (Bstrcasecmp(tok, "client") == 0)
|
|
|
|
|
udpmode = udpmode_client;
|
|
|
|
|
else if (Bstrcasecmp(tok, "peer") == 0)
|
|
|
|
|
udpmode = udpmode_peer;
|
|
|
|
|
else
|
|
|
|
|
bogus = 1;
|
|
|
|
|
|
|
|
|
|
if (!bogus)
|
|
|
|
|
initprintf("You want to be in [%s] mode\n", tok);
|
|
|
|
|
}
|
2008-11-11 13:24:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
2008-11-14 08:22:57 +00:00
|
|
|
|
else if (Bstrcasecmp(tok, "broadcast") == 0)
|
2008-11-11 13:24:05 +00:00
|
|
|
|
{
|
2008-11-14 08:22:57 +00:00
|
|
|
|
if ((tok = get_token(&ptr)) != NULL)
|
|
|
|
|
{
|
|
|
|
|
bcast = atoi(tok);
|
2008-11-17 00:38:26 +00:00
|
|
|
|
if (bcast > MAXPLAYERS - 1)
|
2008-11-14 08:22:57 +00:00
|
|
|
|
{
|
|
|
|
|
initprintf("WARNING: Too many broadcast players.\n");
|
2008-11-17 00:38:26 +00:00
|
|
|
|
bcast = MAXPLAYERS - 1;
|
2008-11-14 08:22:57 +00:00
|
|
|
|
}
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
2008-11-14 08:22:57 +00:00
|
|
|
|
bogus = 0;
|
|
|
|
|
}
|
2008-11-11 13:24:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
2008-11-14 08:22:57 +00:00
|
|
|
|
else if (Bstrcasecmp(tok, "allow") == 0)
|
2008-11-11 13:24:05 +00:00
|
|
|
|
{
|
2009-01-09 09:29:17 +00:00
|
|
|
|
int32_t host;
|
|
|
|
|
uint16_t port=BUILD_DEFAULT_UDP_PORT;
|
2008-11-14 08:22:57 +00:00
|
|
|
|
if ((tok = get_token(&ptr)) != NULL)
|
2008-11-11 13:24:05 +00:00
|
|
|
|
{
|
2008-11-17 00:38:26 +00:00
|
|
|
|
if (gcom->numplayers >= MAXPLAYERS - 1)
|
2008-11-14 08:22:57 +00:00
|
|
|
|
initprintf("WARNING: Too many allowed IP addresses.\n");
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
2008-11-14 08:22:57 +00:00
|
|
|
|
else if (parse_interface(tok, &host, &port))
|
|
|
|
|
{
|
|
|
|
|
allowed_addresses[gcom->numplayers].host = host;
|
|
|
|
|
allowed_addresses[gcom->numplayers].port = port;
|
|
|
|
|
gcom->numplayers++;
|
|
|
|
|
bogus = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
2008-11-11 13:24:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
2008-11-14 08:22:57 +00:00
|
|
|
|
else if (Bstrcasecmp(tok, "players") == 0)
|
2008-11-11 13:24:05 +00:00
|
|
|
|
{
|
2008-11-14 08:22:57 +00:00
|
|
|
|
if ((tok = get_token(&ptr)) != NULL)
|
2008-11-11 13:24:05 +00:00
|
|
|
|
{
|
|
|
|
|
bogus = 0;
|
2008-11-14 08:22:57 +00:00
|
|
|
|
if (udpmode == udpmode_server)
|
|
|
|
|
gcom->numplayers = atoi(tok)-1;
|
|
|
|
|
else
|
|
|
|
|
bogus = 1;
|
2008-11-11 13:24:05 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2008-11-14 08:22:57 +00:00
|
|
|
|
if (bogus)
|
|
|
|
|
initprintf("bogus token! [%s]\n", tok);
|
2008-11-13 11:45:34 +00:00
|
|
|
|
}
|
|
|
|
|
|
2008-11-14 08:22:57 +00:00
|
|
|
|
free(buf);
|
2008-11-14 19:55:48 +00:00
|
|
|
|
}
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
|
|
|
|
if (open_udp_socket(ip, udpport))
|
|
|
|
|
{
|
|
|
|
|
gcom->numplayers++; /* that's you. */
|
|
|
|
|
if (udpmode == udpmode_server)
|
|
|
|
|
return(wait_for_other_players(gcom, ip));
|
|
|
|
|
else if (udpmode == udpmode_client)
|
|
|
|
|
return(connect_to_server(gcom, ip));
|
|
|
|
|
else if (udpmode == udpmode_peer)
|
|
|
|
|
return(connect_to_everyone(gcom, ip, bcast));
|
|
|
|
|
|
|
|
|
|
initprintf("wtf?!"); /* Should be handled by a udpmode above... */
|
|
|
|
|
// assert(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2009-01-09 09:29:17 +00:00
|
|
|
|
gcomtype *init_network_transport(int32_t argc, char **argv)
|
2008-11-11 13:24:05 +00:00
|
|
|
|
{
|
|
|
|
|
gcomtype *retval;
|
|
|
|
|
|
2008-11-12 04:16:41 +00:00
|
|
|
|
// initprintf("\n\nUDP NETWORK TRANSPORT INITIALIZING...\n");
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
|
|
|
|
if (!initialize_sockets())
|
|
|
|
|
return(NULL);
|
|
|
|
|
|
|
|
|
|
srand(time(NULL));
|
|
|
|
|
|
2008-11-12 04:16:41 +00:00
|
|
|
|
retval = (gcomtype *)malloc(sizeof(gcomtype));
|
2008-11-11 13:24:05 +00:00
|
|
|
|
if (retval != NULL)
|
|
|
|
|
{
|
2009-01-09 09:29:17 +00:00
|
|
|
|
int32_t rc;
|
2008-11-14 08:22:57 +00:00
|
|
|
|
// char *cfgfile = ARGV[argpos];
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
2008-11-12 04:16:41 +00:00
|
|
|
|
memset(retval, '\0', sizeof(gcomtype));
|
|
|
|
|
memset(allowed_addresses, '\0', sizeof(allowed_addresses));
|
2008-11-11 13:24:05 +00:00
|
|
|
|
udpsocket = -1;
|
|
|
|
|
udpport = BUILD_DEFAULT_UDP_PORT;
|
|
|
|
|
udpmode = udpmode_peer;
|
|
|
|
|
|
2008-11-14 08:22:57 +00:00
|
|
|
|
rc = parse_udp_config(argc, argv, retval);
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
|
|
|
|
if (!rc)
|
|
|
|
|
{
|
|
|
|
|
free(retval);
|
|
|
|
|
deinit_network_transport(NULL);
|
|
|
|
|
return(NULL);
|
|
|
|
|
}
|
2008-11-17 00:38:26 +00:00
|
|
|
|
// retval->gametype = 3; /* gametype: 1-serial,2-modem,3-net */
|
2008-11-11 13:24:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return(retval);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void deinit_network_transport(gcomtype *gcom)
|
|
|
|
|
{
|
2008-11-12 04:16:41 +00:00
|
|
|
|
// initprintf("\n\nUDP NETWORK TRANSPORT DEINITIALIZING...\n");
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
|
|
|
|
if (gcom != NULL)
|
|
|
|
|
{
|
|
|
|
|
initprintf(" ...freeing gcom structure...\n");
|
|
|
|
|
free(gcom);
|
|
|
|
|
}
|
|
|
|
|
|
2008-11-11 13:45:12 +00:00
|
|
|
|
if ((signed)udpsocket != -1)
|
2008-11-11 13:24:05 +00:00
|
|
|
|
{
|
|
|
|
|
initprintf(" ...closing socket...\n");
|
|
|
|
|
set_socket_blockmode(1); /* block while socket drains. */
|
|
|
|
|
shutdown(udpsocket, SOCKET_SHUTDOWN_BOTH);
|
|
|
|
|
socketclose(udpsocket);
|
|
|
|
|
udpsocket = -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
deinitialize_sockets();
|
|
|
|
|
|
2009-03-14 02:55:39 +00:00
|
|
|
|
initprintf("UDP networking uninitialized successfully.\n");
|
2008-11-11 13:24:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void callcommit(void)
|
|
|
|
|
{
|
2009-01-09 09:29:17 +00:00
|
|
|
|
int32_t ip, i, rc;
|
|
|
|
|
uint16_t port;
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
2008-11-11 13:45:12 +00:00
|
|
|
|
if ((signed)udpsocket == -1)
|
2008-11-11 13:24:05 +00:00
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
process_udp_send_queue();
|
|
|
|
|
|
|
|
|
|
switch (gcom->command)
|
|
|
|
|
{
|
2008-11-12 04:16:41 +00:00
|
|
|
|
case COMMIT_CMD_GET:
|
|
|
|
|
rc = get_udp_packet(&ip, &port, gcom->buffer, sizeof(gcom->buffer));
|
|
|
|
|
if (rc > 0)
|
|
|
|
|
{
|
|
|
|
|
gcom->numbytes = rc; /* size of new packet. */
|
|
|
|
|
for (i = 1; i <= gcom->numplayers; i++)
|
2008-11-11 13:24:05 +00:00
|
|
|
|
{
|
2008-11-12 04:16:41 +00:00
|
|
|
|
if ((allowed_addresses[i].host == ip) &&
|
|
|
|
|
(allowed_addresses[i].port == port))
|
2008-11-11 13:24:05 +00:00
|
|
|
|
{
|
2008-11-12 04:16:41 +00:00
|
|
|
|
gcom->other = i;
|
|
|
|
|
return;
|
2008-11-11 13:24:05 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2008-11-12 04:16:41 +00:00
|
|
|
|
/* if you manage to hit this, it'll report no packet avail. */
|
|
|
|
|
}
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
2008-11-12 04:16:41 +00:00
|
|
|
|
gcom->numbytes = 0;
|
|
|
|
|
gcom->other = -1; /* no packet available. */
|
|
|
|
|
break;
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
2008-11-12 04:16:41 +00:00
|
|
|
|
case COMMIT_CMD_SEND:
|
|
|
|
|
if ((gcom->other < 0) || (gcom->other > gcom->numplayers))
|
|
|
|
|
{
|
|
|
|
|
initprintf("NET TRANSPORT ERROR: send to player out of range\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ip = allowed_addresses[gcom->other].host;
|
|
|
|
|
if (ip == 0) /* dropped player? */
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
port = allowed_addresses[gcom->other].port;
|
|
|
|
|
|
|
|
|
|
if (!send_udp_packet(ip, port, gcom->buffer, gcom->numbytes))
|
|
|
|
|
{
|
|
|
|
|
initprintf("NET TRANSPORT ERROR: send failed to %s:%d\n",
|
2009-01-09 09:29:17 +00:00
|
|
|
|
static_ipstring(ip), (int32_t) port);
|
2008-11-12 04:16:41 +00:00
|
|
|
|
}
|
|
|
|
|
break;
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
2008-11-12 04:16:41 +00:00
|
|
|
|
case COMMIT_CMD_SENDTOALL:
|
|
|
|
|
/* skip player zero, 'cause that's a duplicate of local IP. */
|
|
|
|
|
for (i = 1; i <= gcom->numplayers; i++)
|
|
|
|
|
{
|
|
|
|
|
ip = allowed_addresses[i].host;
|
2008-11-11 13:24:05 +00:00
|
|
|
|
if (ip == 0) /* dropped player? */
|
2008-11-12 04:16:41 +00:00
|
|
|
|
continue;
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
2008-11-12 04:16:41 +00:00
|
|
|
|
port = allowed_addresses[i].port;
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
|
|
|
|
if (!send_udp_packet(ip, port, gcom->buffer, gcom->numbytes))
|
|
|
|
|
{
|
|
|
|
|
initprintf("NET TRANSPORT ERROR: send failed to %s:%d\n",
|
2009-01-09 09:29:17 +00:00
|
|
|
|
static_ipstring(ip), (int32_t) port);
|
2008-11-11 13:24:05 +00:00
|
|
|
|
}
|
2008-11-12 04:16:41 +00:00
|
|
|
|
}
|
|
|
|
|
break;
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
2008-11-12 04:16:41 +00:00
|
|
|
|
case COMMIT_CMD_SENDTOALLOTHERS:
|
|
|
|
|
/* skip player zero, 'cause that's a duplicate of local IP. */
|
|
|
|
|
for (i = 1; i <= gcom->numplayers; i++)
|
|
|
|
|
{
|
|
|
|
|
if (i == gcom->myconnectindex) /* local player. */
|
|
|
|
|
continue;
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
2008-11-12 04:16:41 +00:00
|
|
|
|
ip = allowed_addresses[i].host;
|
|
|
|
|
if (ip == 0) /* dropped player? */
|
|
|
|
|
continue;
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
2008-11-12 04:16:41 +00:00
|
|
|
|
port = allowed_addresses[i].port;
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
2008-11-12 04:16:41 +00:00
|
|
|
|
if (!send_udp_packet(ip, port, gcom->buffer, gcom->numbytes))
|
2008-11-11 13:24:05 +00:00
|
|
|
|
{
|
2008-11-12 04:16:41 +00:00
|
|
|
|
initprintf("NET TRANSPORT ERROR: send failed to %s:%d\n",
|
2009-01-09 09:29:17 +00:00
|
|
|
|
static_ipstring(ip), (int32_t) port);
|
2008-11-11 13:24:05 +00:00
|
|
|
|
}
|
2008-11-12 04:16:41 +00:00
|
|
|
|
}
|
|
|
|
|
break;
|
2008-11-11 13:24:05 +00:00
|
|
|
|
|
|
|
|
|
/* ?!
|
|
|
|
|
case COMMIT_CMD_SCORE:
|
|
|
|
|
break;
|
|
|
|
|
*/
|
|
|
|
|
|
2008-11-12 04:16:41 +00:00
|
|
|
|
default:
|
|
|
|
|
initprintf("NET TRANSPORT ERROR: Unknown command %d\n", gcom->command);
|
|
|
|
|
gcom->other = -1; /* oh well. */
|
|
|
|
|
break;
|
2008-11-11 13:24:05 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* end of mmulti.c ... */
|
|
|
|
|
|