From 70b55a446c2f60f846562ca3350fc0b1ce396fa9 Mon Sep 17 00:00:00 2001 From: Spoike Date: Mon, 28 May 2007 02:31:48 +0000 Subject: [PATCH] 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 --- fteqtv/bsp.c | 2 +- fteqtv/control.c | 16 +++++++++ fteqtv/forward.c | 91 +++++++++++++++++++++++++++++++++++------------- fteqtv/parse.c | 22 +++++++----- fteqtv/qtv.h | 6 ++-- fteqtv/qw.c | 4 ++- fteqtv/rcon.c | 45 +++++++++++++++++------- fteqtv/source.c | 46 +++++++++++++++++++----- 8 files changed, 175 insertions(+), 57 deletions(-) diff --git a/fteqtv/bsp.c b/fteqtv/bsp.c index c55cc8f06..0d1d3214c 100644 --- a/fteqtv/bsp.c +++ b/fteqtv/bsp.c @@ -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; } } diff --git a/fteqtv/control.c b/fteqtv/control.c index 74033aabe..c8dc8cdd2 100644 --- a/fteqtv/control.c +++ b/fteqtv/control.c @@ -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, ...) { diff --git a/fteqtv/forward.c b/fteqtv/forward.c index d6f671408..c90f8a9c9 100644 --- a/fteqtv/forward.c +++ b/fteqtv/forward.c @@ -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)); diff --git a/fteqtv/parse.c b/fteqtv/parse.c index dca8415ee..5ee953aa1 100644 --- a/fteqtv/parse.c +++ b/fteqtv/parse.c @@ -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)); diff --git a/fteqtv/qtv.h b/fteqtv/qtv.h index 8843abbb9..492dd0178 100644 --- a/fteqtv/qtv.h +++ b/fteqtv/qtv.h @@ -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 diff --git a/fteqtv/qw.c b/fteqtv/qw.c index 806d43c49..9113adf87 100644 --- a/fteqtv/qw.c +++ b/fteqtv/qw.c @@ -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"); diff --git a/fteqtv/rcon.c b/fteqtv/rcon.c index 76ccdc450..8160af755 100644 --- a/fteqtv/rcon.c +++ b/fteqtv/rcon.c @@ -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; } } diff --git a/fteqtv/source.c b/fteqtv/source.c index 494620501..a0a3a1e01 100644 --- a/fteqtv/source.c +++ b/fteqtv/source.c @@ -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++;