Support for reverse connections, and added a few stdout cleanups. Added two svcs which can happen in single player/coop.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@2512 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2007-05-28 02:31:48 +00:00
parent e7f6c231e7
commit 70b55a446c
8 changed files with 175 additions and 57 deletions

View File

@ -299,7 +299,7 @@ bsp_t *BSP_LoadModel(cluster_t *cluster, char *gamedir, char *bspname)
if (LittleLong(header->lumps[i].fileofs) + LittleLong(header->lumps[i].filelen) > size)
{
free(data);
Sys_Printf(cluster, "BSP appears truncated\n", bspname, gamedir);
Sys_Printf(cluster, "BSP appears truncated (%s in gamedir %s)\n", bspname, gamedir);
return NULL;
}
}

View File

@ -408,6 +408,7 @@ void DoCommandLine(cluster_t *cluster, int argc, char **argv)
start = end;
}
Sys_Printf(cluster, "\n");
}
int main(int argc, char **argv)
@ -481,6 +482,21 @@ int main(int argc, char **argv)
return 0;
}
void QTV_Printf(sv_t *qtv, char *fmt, ...)
{
va_list argptr;
char string[2048];
va_start (argptr, fmt);
vsnprintf (string, sizeof(string)-1, fmt,argptr);
string[sizeof(string)-1] = 0;
va_end (argptr);
if (qtv->silentstream)
return;
Sys_Printf(qtv->cluster, "%s", string);
}
void Sys_Printf(cluster_t *cluster, char *fmt, ...)
{

View File

@ -90,6 +90,7 @@ void SV_FindProxies(SOCKET sock, cluster_t *cluster, sv_t *defaultqtv)
cluster->numproxies++;
prox->droptime = cluster->curtime + 5*1000;
#if 1
prox->defaultstream = defaultqtv;
@ -500,8 +501,9 @@ qboolean SV_ReadPendingProxy(cluster_t *cluster, oproxy_t *pend)
char *s;
char *e;
char *colon;
int usableversion = 0;
float clientversion = 0;
int len;
int headersize;
qboolean raw;
sv_t *qtv;
@ -514,6 +516,7 @@ qboolean SV_ReadPendingProxy(cluster_t *cluster, oproxy_t *pend)
cluster->numproxies--;
return true;
}
#define QTVSVHEADER "QTVSV 1.1\n"
Net_TryFlushProxyBuffer(cluster, pend);
@ -543,6 +546,12 @@ qboolean SV_ReadPendingProxy(cluster_t *cluster, oproxy_t *pend)
return false;
}
if (pend->droptime < cluster->curtime)
{
pend->drop = true;
return false;
}
len = sizeof(pend->inbuffer) - pend->inbuffersize - 1;
len = recv(pend->sock, pend->inbuffer+pend->inbuffersize, len, 0);
if (len == 0)
@ -575,6 +584,7 @@ qboolean SV_ReadPendingProxy(cluster_t *cluster, oproxy_t *pend)
if (!*s)
return false; //don't have enough yet
s+=3;
headersize = s - pend->inbuffer - 1;
if (!strncmp(pend->inbuffer, "POST ", 5))
{
@ -608,11 +618,11 @@ qboolean SV_ReadPendingProxy(cluster_t *cluster, oproxy_t *pend)
{
if (!strcmp(s, "QTV"))
{
//just a qtv request
//just a qtv request (as in, not http or some other protocol)
}
else if (!strcmp(s, "SOURCELIST"))
{ //lists sources that are currently playing
s = "QTVSV 1\n";
s = QTVSVHEADER;
Net_ProxySend(cluster, pend, s, strlen(s));
if (!cluster->servers)
{
@ -623,9 +633,32 @@ qboolean SV_ReadPendingProxy(cluster_t *cluster, oproxy_t *pend)
{
for (qtv = cluster->servers; qtv; qtv = qtv->next)
{
sprintf(tempbuf, "ASOURCE: %i: %15s: %15s\n", qtv->streamid, qtv->server, qtv->hostname);
s = tempbuf;
Net_ProxySend(cluster, pend, s, strlen(s));
if (clientversion > 1)
{
int plyrs = 0;
int i;
for (i = 0; i < MAX_CLIENTS; i++)
{
if (*qtv->players[i].userinfo)
plyrs++;
}
sprintf(tempbuf, "SRCSRV: %s\n", qtv->server);
Net_ProxySend(cluster, pend, s, strlen(s));
sprintf(tempbuf, "SRCHOST: %s\n", qtv->hostname);
Net_ProxySend(cluster, pend, s, strlen(s));
sprintf(tempbuf, "SRCPLYRS: %i\n", plyrs);
Net_ProxySend(cluster, pend, s, strlen(s));
sprintf(tempbuf, "SRCVIEWS: %i\n", qtv->numviewers);
Net_ProxySend(cluster, pend, s, strlen(s));
sprintf(tempbuf, "SRCID: %i\n", qtv->streamid); //final part of each source
Net_ProxySend(cluster, pend, s, strlen(s));
}
else
{
sprintf(tempbuf, "ASOURCE: %i: %15s: %15s\n", qtv->streamid, qtv->server, qtv->hostname);
Net_ProxySend(cluster, pend, s, strlen(s));
}
}
qtv = NULL;
}
@ -636,6 +669,25 @@ qboolean SV_ReadPendingProxy(cluster_t *cluster, oproxy_t *pend)
else if (!strcmp(s, "REVERSE"))
{ //this is actually a server trying to connect to us
//start up a new stream
//FIXME: does this work?
#if 1 //left disabled until properly tested
qtv = QTV_NewServerConnection(cluster, "reverse"/*server*/, "", true, 2, false, 0);
s = QTVSVHEADER; Net_ProxySend(cluster, pend, s, strlen(s));
s = "REVERSED\n"; Net_ProxySend(cluster, pend, s, strlen(s));
s = "VERSION: 1\n"; Net_ProxySend(cluster, pend, s, strlen(s));
s = "\n"; Net_ProxySend(cluster, pend, s, strlen(s));
//switch over the socket to the actual source connection rather than the pending
Net_TryFlushProxyBuffer(cluster, pend); //flush anything... this isn't ideal, but should be small enough
qtv->sourcesock = pend->sock;
pend->sock = 0;
memcpy(qtv->buffer, pend->inbuffer + headersize, pend->inbuffersize - headersize);
qtv->parsingqtvheader = true;
return false;
#endif
}
else if (!strcmp(s, "RECEIVE"))
{ //a client connection request without a source
@ -660,7 +712,7 @@ qboolean SV_ReadPendingProxy(cluster_t *cluster, oproxy_t *pend)
}
if (!qtv)
{
s = "QTVSV 1\n";
s = QTVSVHEADER;
Net_ProxySend(cluster, pend, s, strlen(s));
s = "PERROR: Multiple streams are currently playing\n";
Net_ProxySend(cluster, pend, s, strlen(s));
@ -675,7 +727,7 @@ qboolean SV_ReadPendingProxy(cluster_t *cluster, oproxy_t *pend)
Cluster_BuildAvailableDemoList(cluster);
s = "QTVSV 1\n";
s = QTVSVHEADER;
Net_ProxySend(cluster, pend, s, strlen(s));
if (!cluster->availdemoscount)
{
@ -708,16 +760,7 @@ qboolean SV_ReadPendingProxy(cluster_t *cluster, oproxy_t *pend)
*colon++ = '\0';
if (!strcmp(s, "VERSION"))
{
switch(atoi(colon))
{
case 1:
//got a usable version
usableversion = 1;
break;
default:
//not recognised.
break;
}
clientversion = atof(colon);
}
else if (!strcmp(s, "RAW"))
raw = atoi(colon);
@ -756,7 +799,7 @@ qboolean SV_ReadPendingProxy(cluster_t *cluster, oproxy_t *pend)
qtv = QTV_NewServerConnection(cluster, buf, "", false, true, true, false);
if (!qtv)
{
s = "QTVSV 1\n"
s = QTVSVHEADER
"PERROR: couldn't open demo\n"
"\n";
Net_ProxySend(cluster, pend, s, strlen(s));
@ -779,9 +822,9 @@ qboolean SV_ReadPendingProxy(cluster_t *cluster, oproxy_t *pend)
if (!pend->flushing)
{
if (!usableversion)
if (clientversion < 1)
{
s = "QTVSV 1\n"
s = QTVSVHEADER
"PERROR: Requested protocol version not supported\n"
"\n";
Net_ProxySend(cluster, pend, s, strlen(s));
@ -789,7 +832,7 @@ qboolean SV_ReadPendingProxy(cluster_t *cluster, oproxy_t *pend)
}
if (!qtv)
{
s = "QTVSV 1\n"
s = QTVSVHEADER
"PERROR: No stream selected\n"
"\n";
Net_ProxySend(cluster, pend, s, strlen(s));
@ -802,7 +845,7 @@ qboolean SV_ReadPendingProxy(cluster_t *cluster, oproxy_t *pend)
if (qtv->usequkeworldprotocols)
{
s = "QTVSV 1\n"
s = QTVSVHEADER
"PERROR: This version of QTV is unable to convert QuakeWorld to QTV protocols\n"
"\n";
Net_ProxySend(cluster, pend, s, strlen(s));
@ -811,7 +854,7 @@ qboolean SV_ReadPendingProxy(cluster_t *cluster, oproxy_t *pend)
}
if (cluster->maxproxies>=0 && cluster->numproxies >= cluster->maxproxies)
{
s = "QTVSV 1\n"
s = QTVSVHEADER
"TERROR: This QTV has reached it's connection limit\n"
"\n";
Net_ProxySend(cluster, pend, s, strlen(s));
@ -824,7 +867,7 @@ qboolean SV_ReadPendingProxy(cluster_t *cluster, oproxy_t *pend)
if (!raw)
{
s = "QTVSV 1\n";
s = QTVSVHEADER;
Net_ProxySend(cluster, pend, s, strlen(s));
s = "BEGIN: ";
Net_ProxySend(cluster, pend, s, strlen(s));

View File

@ -267,10 +267,10 @@ static void ParseServerData(sv_t *tv, netmsg_t *m, int to, unsigned int playerma
}
ReadString(m, tv->mapname, sizeof(tv->mapname));
Sys_Printf(tv->cluster, "Gamedir: %s\n", tv->gamedir);
Sys_Printf(tv->cluster, "---------------------\n");
Sys_Printf(tv->cluster, "%s\n", tv->mapname);
Sys_Printf(tv->cluster, "---------------------\n");
QTV_Printf(tv, "Gamedir: %s\n", tv->gamedir);
QTV_Printf(tv, "---------------------\n");
Sys_Printf(tv->cluster, "Stream %i: %s\n", tv->streamid, tv->mapname);
QTV_Printf(tv, "---------------------\n");
// get the movevars
tv->movevars.gravity = ReadFloat(m);
@ -514,7 +514,7 @@ static void ParsePrint(sv_t *tv, netmsg_t *m, int to, unsigned int mask)
{
if (level > 1)
{
Sys_Printf(tv->cluster, "%s", text);
QTV_Printf(tv, "%s", text);
}
}
@ -1563,7 +1563,7 @@ void ParseMessage(sv_t *tv, char *buffer, int length, int to, int mask)
Sys_Printf(tv->cluster, "ParseMessage: svc_bad\n");
return;
case svc_nop: //quakeworld isn't meant to send these.
Sys_Printf(tv->cluster, "nop\n");
QTV_Printf(tv, "nop\n");
break;
case svc_disconnect:
@ -1812,12 +1812,11 @@ void ParseMessage(sv_t *tv, char *buffer, int length, int to, int mask)
ParsePacketEntities(tv, &buf, ReadByte(&buf));
break;
//#define svc_maxspeed 49 // maxspeed change, for prediction
case svc_entgravity: // gravity change, for prediction
ReadFloat(&buf);
Multicast(tv, buf.data+buf.startpos, buf.readpos - buf.startpos, to, mask, QW);
break;
case svc_maxspeed:
case svc_maxspeed: // maxspeed change, for prediction
ReadFloat(&buf);
Multicast(tv, buf.data+buf.startpos, buf.readpos - buf.startpos, to, mask, QW);
break;
@ -1834,6 +1833,13 @@ void ParseMessage(sv_t *tv, char *buffer, int length, int to, int mask)
ParseNails(tv, &buf, true);
break;
case svc_killedmonster:
Multicast(tv, buf.data+buf.startpos, buf.readpos - buf.startpos, to, mask, Q1);
break;
case svc_foundsecret:
Multicast(tv, buf.data+buf.startpos, buf.readpos - buf.startpos, to, mask, Q1);
break;
default:
buf.readpos = buf.startpos;
Sys_Printf(tv->cluster, "Can't handle svc %i\n", (unsigned int)ReadByte(&buf));

View File

@ -559,6 +559,8 @@ struct sv_s { //details about a server connection (also known as stream)
nail_t nails[32];
int nailcount;
qboolean silentstream;
qboolean usequkeworldprotocols;
int challenge;
unsigned short qport;
@ -767,8 +769,8 @@ unsigned int BigLong(unsigned int val);
#define svc_centerprint 26 // [string] to put in center of the screen
//#define svc_killedmonster 27
//#define svc_foundsecret 28
#define svc_killedmonster 27
#define svc_foundsecret 28
#define svc_spawnstaticsound 29 // [coord3] [qbyte] samp [qbyte] vol [qbyte] aten

View File

@ -4168,7 +4168,9 @@ void Menu_Draw(cluster_t *cluster, viewer_t *viewer)
WriteString2(&m, " auto disconnect");
WriteString2(&m, (viewer->menuop==(i++))?" \r ":" : ");
if (viewer->server->disconnectwhennooneiswatching)
if (viewer->server->disconnectwhennooneiswatching == 2)
sprintf(str, "%-20s", "when server disconnects");
else if (viewer->server->disconnectwhennooneiswatching)
sprintf(str, "%-20s", "when inactive");
else
sprintf(str, "%-20s", "never");

View File

@ -338,7 +338,9 @@ char *Cmd_Hostname(cluster_t *cluster, sv_t *qtv, char *arg[MAX_ARGS], char *buf
return buffer;
}
strncpy(cluster->hostname, arg[1], sizeof(cluster->hostname)-1);
return "hostname set (might have a slight delay)\n"; //I'm too lazy to alter the serverinfo here.
snprintf(buffer, sizeofbuffer, "hostname set to \"%s\"\n", cluster->hostname);
return buffer;
}
char *Cmd_Master(cluster_t *cluster, sv_t *qtv, char *arg[MAX_ARGS], char *buffer, int sizeofbuffer, qboolean localcommand)
{
@ -385,10 +387,12 @@ char *Cmd_UDPPort(cluster_t *cluster, sv_t *qtv, char *arg[MAX_ARGS], char *buff
closesocket(cluster->qwdsocket);
cluster->qwdsocket = news;
cluster->qwlistenportnum = newp;
return "Opened udp port (all connected qw clients will time out)\n";
snprintf(buffer, sizeofbuffer, "Opened udp port %i (all connected qw clients will time out)\n", newp);
}
else
return "Failed to open udp port\n";
snprintf(buffer, sizeofbuffer, "Failed to open udp port %i\n", newp);
return buffer;
}
char *Cmd_AdminPassword(cluster_t *cluster, sv_t *qtv, char *arg[MAX_ARGS], char *buffer, int sizeofbuffer, qboolean localcommand)
{
@ -443,7 +447,9 @@ char *Cmd_QTVConnect(cluster_t *cluster, sv_t *qtv, char *arg[MAX_ARGS], char *b
if (!QTV_NewServerConnection(cluster, arg[1], arg[2], false, false, false, false))
return "Failed to connect to server, connection aborted\n";
return "Source registered\n";
snprintf(buffer, sizeofbuffer, "Source registered \"%s\"\n", arg[1]);
return buffer;
}
char *Cmd_QWConnect(cluster_t *cluster, sv_t *qtv, char *arg[MAX_ARGS], char *buffer, int sizeofbuffer, qboolean localcommand)
{
@ -455,7 +461,9 @@ char *Cmd_QWConnect(cluster_t *cluster, sv_t *qtv, char *arg[MAX_ARGS], char *bu
if (!QTV_NewServerConnection(cluster, arg[1], arg[2], false, false, false, false))
return "Failed to connect to server, connection aborted\n";
return "Source registered\n";
snprintf(buffer, sizeofbuffer, "Source registered \"%s\"\n", arg[1]);
return buffer;
}
char *Cmd_MVDConnect(cluster_t *cluster, sv_t *qtv, char *arg[MAX_ARGS], char *buffer, int sizeofbuffer, qboolean localcommand)
{
@ -471,12 +479,14 @@ char *Cmd_MVDConnect(cluster_t *cluster, sv_t *qtv, char *arg[MAX_ARGS], char *b
if (!QTV_NewServerConnection(cluster, arg[1], arg[2], false, false, false, false))
return "Failed to connect to server, connection aborted\n";
return "Source registered\n";
snprintf(buffer, sizeofbuffer, "Source registered \"%s\"\n", arg[1]);
return buffer;
}
char *Cmd_Exec(cluster_t *cluster, sv_t *qtv, char *arg[MAX_ARGS], char *buffer, int sizeofbuffer, qboolean localcommand)
{
FILE *f;
char line[512], *res;
char line[512], *res, *l;
if (!localcommand)
{
@ -496,14 +506,19 @@ char *Cmd_Exec(cluster_t *cluster, sv_t *qtv, char *arg[MAX_ARGS], char *buffer,
{
while(fgets(line, sizeof(line)-1, f))
{
if (*line)
l = line;
while(*(unsigned char*)l <= ' ' && *l)
l++;
if (*l && l[0] != '/' && l[1] != '/')
{
res = Rcon_Command(cluster, qtv, line, buffer, sizeofbuffer, localcommand);
res = Rcon_Command(cluster, qtv, l, buffer, sizeofbuffer, localcommand);
Sys_Printf(cluster, "%s", res); //this is perhaps wrong.
}
}
fclose(f);
return "Execed\n";
snprintf(buffer, sizeofbuffer, "Execed \"%s\"\n", arg[1]);
return buffer;
}
}
@ -794,7 +809,9 @@ char *Cmd_Stop(cluster_t *cluster, sv_t *qtv, char *arg[MAX_ARGS], char *buffer,
char *Cmd_Reconnect(cluster_t *cluster, sv_t *qtv, char *arg[MAX_ARGS], char *buffer, int sizeofbuffer, qboolean localcommand)
{
if (QTV_Connect(qtv, qtv->server))
if (qtv->disconnectwhennooneiswatching == 2)
return "Stream is a reverse connection (command rejected)\n";
else if (QTV_Connect(qtv, qtv->server))
return "Reconnected\n";
else
return "Failed to reconnect (will keep trying)\n";
@ -827,10 +844,12 @@ char *Cmd_MVDPort(cluster_t *cluster, sv_t *qtv, char *arg[MAX_ARGS], char *buff
closesocket(cluster->tcpsocket);
cluster->tcpsocket = news;
cluster->tcplistenportnum = newp;
return "Opened tcp port\n";
snprintf(buffer, sizeofbuffer, "Opened tcp port %i\n", newp);
}
else
return "Failed to open tcp port\n";
snprintf(buffer, sizeofbuffer, "Failed to open tcp port %i\n", newp);
return buffer;
}
}

View File

@ -760,6 +760,20 @@ unsigned int Sys_Milliseconds(void)
#ifdef _MSC_VER
#pragma comment(lib, "winmm.lib")
#endif
#if 0
static firsttime = 1;
static starttime;
if (firsttime)
{
starttime = timeGetTime() + 1000*20;
firsttime = 0;
}
return timeGetTime() - starttime;
#endif
return timeGetTime();
#else
//assume every other system follows standards.
@ -907,7 +921,12 @@ qboolean QTV_Connect(sv_t *qtv, char *serverurl)
memcpy(qtv->server, serverurl, sizeof(qtv->server)-1);
if (!Net_ConnectToServer(qtv))
if (qtv->disconnectwhennooneiswatching)
{ //added because of paranoia rather than need. Should never occur.
printf("bug: autoclose==2\n");
return false;
}
else if (!Net_ConnectToServer(qtv))
{
Sys_Printf(qtv->cluster, "Couldn't connect (%s)\n", qtv->server);
return false;
@ -916,7 +935,7 @@ qboolean QTV_Connect(sv_t *qtv, char *serverurl)
if (qtv->sourcesock == INVALID_SOCKET)
{
qtv->parsetime = Sys_Milliseconds();
Sys_Printf(qtv->cluster, "Playing from file\n");
// Sys_Printf(qtv->cluster, "Playing from file\n");
}
else
{
@ -1331,7 +1350,7 @@ void QTV_Run(sv_t *qtv)
int oldcurtime;
int packettime;
if (qtv->disconnectwhennooneiswatching && qtv->numviewers == 0 && qtv->proxies == NULL)
if (qtv->disconnectwhennooneiswatching == 1 && qtv->numviewers == 0 && qtv->proxies == NULL)
{
Sys_Printf(qtv->cluster, "Stream %s became inactive\n", qtv->server);
qtv->drop = true;
@ -1516,9 +1535,16 @@ void QTV_Run(sv_t *qtv)
if (qtv->sourcesock == INVALID_SOCKET && !qtv->sourcefile)
{
if (qtv->curtime >= qtv->nextconnectattempt || qtv->curtime < qtv->nextconnectattempt - RECONNECT_TIME*2)
if (!QTV_Connect(qtv, qtv->server))
{
return;
if (qtv->disconnectwhennooneiswatching == 2)
{
qtv->drop = true;
return;
}
if (!QTV_Connect(qtv, qtv->server))
{
return;
}
}
}
@ -1879,16 +1905,20 @@ sv_t *QTV_NewServerConnection(cluster_t *cluster, char *server, char *password,
qtv->disconnectwhennooneiswatching = autoclose;
qtv->parsingconnectiondata = true;
qtv->serverquery = query;
qtv->silentstream = true;
qtv->streamid = ++cluster->nextstreamid;
qtv->cluster = cluster;
qtv->next = cluster->servers;
if (!QTV_Connect(qtv, server) && !force)
if (autoclose != 2) //2 means reverse connection (don't ever try reconnecting)
{
free(qtv);
return NULL;
if (!QTV_Connect(qtv, server) && !force)
{
free(qtv);
return NULL;
}
}
cluster->servers = qtv;
cluster->numservers++;