mirror of
https://github.com/nzp-team/fteqw.git
synced 2024-11-25 13:21:36 +00:00
Knocked up some commands and stuff to make qtv not forget about streams that failed. Finally implemented the commands command. Added commands to enable/disable streams.
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@2812 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
parent
81b91a422d
commit
6006580d8a
5 changed files with 303 additions and 141 deletions
|
@ -344,7 +344,7 @@ static void ParseStufftext(sv_t *tv, netmsg_t *m, int to, unsigned int mask)
|
||||||
SendClientCommand(tv, "new\n");
|
SendClientCommand(tv, "new\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
tv->drop = true; //this shouldn't ever happen
|
Sys_Printf(tv->cluster, "packet stuffcmd in an mvd\n"); //shouldn't ever happen, try ignoring it.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (tv->usequakeworldprotocols && !strncmp(text, "setinfo ", 8))
|
else if (tv->usequakeworldprotocols && !strncmp(text, "setinfo ", 8))
|
||||||
|
@ -1380,6 +1380,7 @@ void ParseNails(sv_t *tv, netmsg_t *m, qboolean nails2)
|
||||||
|
|
||||||
void ParseDownload(sv_t *tv, netmsg_t *m)
|
void ParseDownload(sv_t *tv, netmsg_t *m)
|
||||||
{
|
{
|
||||||
|
#warning this needs looking at (controller downloads)
|
||||||
int size, b;
|
int size, b;
|
||||||
unsigned int percent;
|
unsigned int percent;
|
||||||
char buffer[2048];
|
char buffer[2048];
|
||||||
|
@ -1393,7 +1394,7 @@ void ParseDownload(sv_t *tv, netmsg_t *m)
|
||||||
if (tv->downloadfile)
|
if (tv->downloadfile)
|
||||||
fclose(tv->downloadfile);
|
fclose(tv->downloadfile);
|
||||||
tv->downloadfile = NULL;
|
tv->downloadfile = NULL;
|
||||||
tv->drop = true;
|
tv->errored = ERR_PERMANENT;
|
||||||
QW_StreamPrint(tv->cluster, tv, NULL, "Map download failed\n");
|
QW_StreamPrint(tv->cluster, tv, NULL, "Map download failed\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1404,7 +1405,7 @@ void ParseDownload(sv_t *tv, netmsg_t *m)
|
||||||
if (!tv->downloadfile)
|
if (!tv->downloadfile)
|
||||||
{
|
{
|
||||||
Sys_Printf(tv->cluster, "Not downloading anything\n");
|
Sys_Printf(tv->cluster, "Not downloading anything\n");
|
||||||
tv->drop = true;
|
tv->errored = ERR_PERMANENT;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
fwrite(buffer, 1, size, tv->downloadfile);
|
fwrite(buffer, 1, size, tv->downloadfile);
|
||||||
|
@ -1423,7 +1424,7 @@ void ParseDownload(sv_t *tv, netmsg_t *m)
|
||||||
if (!tv->bsp)
|
if (!tv->bsp)
|
||||||
{
|
{
|
||||||
Sys_Printf(tv->cluster, "Failed to read BSP\n");
|
Sys_Printf(tv->cluster, "Failed to read BSP\n");
|
||||||
tv->drop = true;
|
tv->errored = ERR_PERMANENT;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
10
fteqtv/qtv.h
10
fteqtv/qtv.h
|
@ -478,6 +478,14 @@ typedef enum {
|
||||||
SRC_TCP
|
SRC_TCP
|
||||||
} sourcetype_t;
|
} sourcetype_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
ERR_NONE, //stream is fine
|
||||||
|
ERR_RECONNECT, //stream needs to reconnect
|
||||||
|
ERR_PERMANENT, //permanent error, transitioning to disabled next frame
|
||||||
|
ERR_DISABLED, //stream is disabled, can be set to reconnect by admin
|
||||||
|
ERR_DROP //stream _will_ be forgotten about next frame
|
||||||
|
} errorstate_t;
|
||||||
|
|
||||||
struct sv_s { //details about a server connection (also known as stream)
|
struct sv_s { //details about a server connection (also known as stream)
|
||||||
char connectpassword[64]; //password given to server
|
char connectpassword[64]; //password given to server
|
||||||
netadr_t serveraddress;
|
netadr_t serveraddress;
|
||||||
|
@ -580,7 +588,7 @@ struct sv_s { //details about a server connection (also known as stream)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
qboolean drop;
|
errorstate_t errored;
|
||||||
qboolean disconnectwhennooneiswatching;
|
qboolean disconnectwhennooneiswatching;
|
||||||
unsigned int numviewers;
|
unsigned int numviewers;
|
||||||
|
|
||||||
|
|
11
fteqtv/qw.c
11
fteqtv/qw.c
|
@ -3644,13 +3644,14 @@ void ParseQWC(cluster_t *cluster, sv_t *qtv, viewer_t *v, netmsg_t *m)
|
||||||
{
|
{
|
||||||
if (!qtv->bsp)
|
if (!qtv->bsp)
|
||||||
{
|
{
|
||||||
QW_PrintfToViewer(v, "Proxy was unable to check your map version\n");
|
#warning do we still actually need to do this ourselves? Or can we just forward what the user stated?
|
||||||
qtv->drop = true;
|
QW_PrintfToViewer(v, "QTV doesn't have that map (%s), sorry.\n", qtv->modellist[1].name);
|
||||||
|
qtv->errored = ERR_DROP;
|
||||||
}
|
}
|
||||||
else if (crc != BSP_Checksum(qtv->bsp))
|
else if (crc != BSP_Checksum(qtv->bsp))
|
||||||
{
|
{
|
||||||
QW_PrintfToViewer(v, "Your map (%s) does not match the servers\n", qtv->modellist[1].name);
|
QW_PrintfToViewer(v, "QTV's map (%s) does not match the servers\n", qtv->modellist[1].name);
|
||||||
qtv->drop = true;
|
qtv->errored = ERR_DROP;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4484,7 +4485,7 @@ void QW_FreeViewer(cluster_t *cluster, viewer_t *viewer)
|
||||||
if (viewer->server->controller == viewer)
|
if (viewer->server->controller == viewer)
|
||||||
{
|
{
|
||||||
if (viewer->server->disconnectwhennooneiswatching)
|
if (viewer->server->disconnectwhennooneiswatching)
|
||||||
viewer->server->drop = true;
|
viewer->server->errored = ERR_DROP;
|
||||||
else
|
else
|
||||||
viewer->server->controller = NULL;
|
viewer->server->controller = NULL;
|
||||||
}
|
}
|
||||||
|
|
213
fteqtv/rcon.c
213
fteqtv/rcon.c
|
@ -351,7 +351,7 @@ void Cmd_Hostname(cmdctxt_t *ctx)
|
||||||
if (Cmd_Argc(ctx) < 2)
|
if (Cmd_Argc(ctx) < 2)
|
||||||
{
|
{
|
||||||
if (*ctx->cluster->hostname)
|
if (*ctx->cluster->hostname)
|
||||||
Cmd_Printf(ctx, "Current hostname is %s\n", ctx->cluster->hostname);
|
Cmd_Printf(ctx, "Current hostname is \"%s\"\n", ctx->cluster->hostname);
|
||||||
else
|
else
|
||||||
Cmd_Printf(ctx, "No master server is currently set.\n");
|
Cmd_Printf(ctx, "No master server is currently set.\n");
|
||||||
}
|
}
|
||||||
|
@ -429,7 +429,7 @@ void Cmd_AdminPassword(cmdctxt_t *ctx)
|
||||||
if (*ctx->cluster->adminpassword)
|
if (*ctx->cluster->adminpassword)
|
||||||
Cmd_Printf(ctx, "An admin password is currently set\n");
|
Cmd_Printf(ctx, "An admin password is currently set\n");
|
||||||
else
|
else
|
||||||
Cmd_Printf(ctx, "No admin passsword is currently set\n");
|
Cmd_Printf(ctx, "No admin password is currently set\n");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -472,6 +472,7 @@ void Cmd_QTVDemoList(cmdctxt_t *ctx)
|
||||||
|
|
||||||
void Cmd_GenericConnect(cmdctxt_t *ctx, char *method)
|
void Cmd_GenericConnect(cmdctxt_t *ctx, char *method)
|
||||||
{
|
{
|
||||||
|
sv_t *sv;
|
||||||
char *address, *password;
|
char *address, *password;
|
||||||
if (Cmd_Argc(ctx) < 2)
|
if (Cmd_Argc(ctx) < 2)
|
||||||
{
|
{
|
||||||
|
@ -488,10 +489,11 @@ void Cmd_GenericConnect(cmdctxt_t *ctx, char *method)
|
||||||
memmove(address+strlen(method), address, ARG_LEN-(1+strlen(method)));
|
memmove(address+strlen(method), address, ARG_LEN-(1+strlen(method)));
|
||||||
strncpy(address, method, strlen(method));
|
strncpy(address, method, strlen(method));
|
||||||
|
|
||||||
if (!QTV_NewServerConnection(ctx->cluster, address, password, false, false, false, false))
|
sv = QTV_NewServerConnection(ctx->cluster, address, password, false, false, false, false);
|
||||||
|
if (!sv)
|
||||||
Cmd_Printf(ctx, "Failed to connect to \"%s\", connection aborted\n", address);
|
Cmd_Printf(ctx, "Failed to connect to \"%s\", connection aborted\n", address);
|
||||||
|
else
|
||||||
Cmd_Printf(ctx, "Source registered \"%s\"\n", address);
|
Cmd_Printf(ctx, "Source registered \"%s\" as stream %i\n", address, sv->streamid);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cmd_QTVConnect(cmdctxt_t *ctx)
|
void Cmd_QTVConnect(cmdctxt_t *ctx)
|
||||||
|
@ -591,11 +593,12 @@ void Cmd_Say(cmdctxt_t *ctx)
|
||||||
|
|
||||||
void Cmd_Status(cmdctxt_t *ctx)
|
void Cmd_Status(cmdctxt_t *ctx)
|
||||||
{
|
{
|
||||||
Cmd_Printf(ctx, "%i sources\n", ctx->cluster->numservers);
|
Cmd_Printf(ctx, "QTV Status:\n");
|
||||||
Cmd_Printf(ctx, "%i viewers\n", ctx->cluster->numviewers);
|
Cmd_Printf(ctx, " %i sources\n", ctx->cluster->numservers);
|
||||||
Cmd_Printf(ctx, "%i proxies\n", ctx->cluster->numproxies);
|
Cmd_Printf(ctx, " %i viewers\n", ctx->cluster->numviewers);
|
||||||
|
Cmd_Printf(ctx, " %i proxies\n", ctx->cluster->numproxies);
|
||||||
|
|
||||||
Cmd_Printf(ctx, "Options:\n");
|
Cmd_Printf(ctx, "Common Options:\n");
|
||||||
Cmd_Printf(ctx, " Hostname %s\n", ctx->cluster->hostname);
|
Cmd_Printf(ctx, " Hostname %s\n", ctx->cluster->hostname);
|
||||||
|
|
||||||
if (ctx->cluster->chokeonnotupdated)
|
if (ctx->cluster->chokeonnotupdated)
|
||||||
|
@ -622,41 +625,44 @@ void Cmd_Status(cmdctxt_t *ctx)
|
||||||
{
|
{
|
||||||
Cmd_Printf(ctx, "Selected server: %s\n", ctx->qtv->server);
|
Cmd_Printf(ctx, "Selected server: %s\n", ctx->qtv->server);
|
||||||
if (ctx->qtv->sourcefile)
|
if (ctx->qtv->sourcefile)
|
||||||
Cmd_Printf(ctx, "Playing from file\n");
|
Cmd_Printf(ctx, " Playing from file\n");
|
||||||
if (ctx->qtv->sourcesock != INVALID_SOCKET)
|
if (ctx->qtv->sourcesock != INVALID_SOCKET)
|
||||||
Cmd_Printf(ctx, "Connected\n");
|
Cmd_Printf(ctx, " Connected\n");
|
||||||
if (ctx->qtv->parsingqtvheader || ctx->qtv->parsingconnectiondata)
|
if (ctx->qtv->parsingqtvheader || ctx->qtv->parsingconnectiondata)
|
||||||
Cmd_Printf(ctx, "Waiting for gamestate\n");
|
Cmd_Printf(ctx, " Waiting for gamestate\n");
|
||||||
if (ctx->qtv->usequakeworldprotocols)
|
if (ctx->qtv->usequakeworldprotocols)
|
||||||
{
|
{
|
||||||
Cmd_Printf(ctx, "QuakeWorld protocols\n");
|
Cmd_Printf(ctx, " QuakeWorld protocols\n");
|
||||||
if (ctx->qtv->controller)
|
if (ctx->qtv->controller)
|
||||||
{
|
{
|
||||||
Cmd_Printf(ctx, "Controlled by %s\n", ctx->qtv->controller->name);
|
Cmd_Printf(ctx, " Controlled by %s\n", ctx->qtv->controller->name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (ctx->qtv->sourcesock == INVALID_SOCKET && !ctx->qtv->sourcefile)
|
else if (ctx->qtv->sourcesock == INVALID_SOCKET && !ctx->qtv->sourcefile)
|
||||||
Cmd_Printf(ctx, "Connection not established\n");
|
Cmd_Printf(ctx, " Connection not established\n");
|
||||||
|
|
||||||
if (*ctx->qtv->modellist[1].name)
|
if (*ctx->qtv->modellist[1].name)
|
||||||
{
|
{
|
||||||
Cmd_Printf(ctx, "Map name %s\n", ctx->qtv->modellist[1].name);
|
Cmd_Printf(ctx, " Map name %s\n", ctx->qtv->modellist[1].name);
|
||||||
}
|
}
|
||||||
if (*ctx->qtv->connectpassword)
|
if (*ctx->qtv->connectpassword)
|
||||||
Cmd_Printf(ctx, "Using a password\n");
|
Cmd_Printf(ctx, " Using a password\n");
|
||||||
|
|
||||||
|
if (ctx->qtv->errored == ERR_DISABLED)
|
||||||
|
Cmd_Printf(ctx, " Stream is disabled\n");
|
||||||
|
|
||||||
if (ctx->qtv->disconnectwhennooneiswatching)
|
if (ctx->qtv->disconnectwhennooneiswatching)
|
||||||
Cmd_Printf(ctx, "Stream is temporary\n");
|
Cmd_Printf(ctx, " Stream is temporary\n");
|
||||||
|
|
||||||
/* if (ctx->qtv->tcpsocket != INVALID_SOCKET)
|
/* if (ctx->qtv->tcpsocket != INVALID_SOCKET)
|
||||||
{
|
{
|
||||||
Cmd_Printf(ctx, "Listening for proxies (%i)\n", ctx->qtv->tcplistenportnum);
|
Cmd_Printf(ctx, " Listening for proxies (%i)\n", ctx->qtv->tcplistenportnum);
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (ctx->qtv->bsp)
|
if (ctx->qtv->bsp)
|
||||||
{
|
{
|
||||||
Cmd_Printf(ctx, "BSP (%s) is loaded\n", ctx->qtv->mapname);
|
Cmd_Printf(ctx, " BSP (%s) is loaded\n", ctx->qtv->mapname);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -826,11 +832,38 @@ void Cmd_Quit(cmdctxt_t *ctx)
|
||||||
void Cmd_Streams(cmdctxt_t *ctx)
|
void Cmd_Streams(cmdctxt_t *ctx)
|
||||||
{
|
{
|
||||||
sv_t *qtv;
|
sv_t *qtv;
|
||||||
|
char *status;
|
||||||
Cmd_Printf(ctx, "Streams:\n");
|
Cmd_Printf(ctx, "Streams:\n");
|
||||||
|
|
||||||
for (qtv = ctx->cluster->servers; qtv; qtv = qtv->next)
|
for (qtv = ctx->cluster->servers; qtv; qtv = qtv->next)
|
||||||
{
|
{
|
||||||
Cmd_Printf(ctx, "%i: %s\n", qtv->streamid, qtv->server);
|
switch (qtv->errored)
|
||||||
|
{
|
||||||
|
case ERR_NONE:
|
||||||
|
if (qtv->controller)
|
||||||
|
status = " (player controlled)";
|
||||||
|
else if (qtv->parsingconnectiondata)
|
||||||
|
status = " (connecting)";
|
||||||
|
else
|
||||||
|
status = "";
|
||||||
|
break;
|
||||||
|
case ERR_DISABLED:
|
||||||
|
status = " (disabled)";
|
||||||
|
break;
|
||||||
|
case ERR_DROP: //a user should never normally see this, but there is a chance
|
||||||
|
status = " (dropping)";
|
||||||
|
break;
|
||||||
|
case ERR_RECONNECT: //again, rare
|
||||||
|
status = " (reconnecting)";
|
||||||
|
break;
|
||||||
|
default: //some other kind of error, transitioning
|
||||||
|
status = " (errored)";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Cmd_Printf(ctx, "%i: %s%s\n", qtv->streamid, qtv->server, status);
|
||||||
|
|
||||||
|
if (qtv->upstreamacceptschat)
|
||||||
|
Cmd_Printf(ctx, " (dbg) can chat!\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -855,6 +888,27 @@ void Cmd_Disconnect(cmdctxt_t *ctx)
|
||||||
Cmd_Printf(ctx, "Disconnected\n");
|
Cmd_Printf(ctx, "Disconnected\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Cmd_Halt(cmdctxt_t *ctx)
|
||||||
|
{
|
||||||
|
if (ctx->qtv->errored == ERR_DISABLED || ctx->qtv->errored == ERR_PERMANENT)
|
||||||
|
{
|
||||||
|
Cmd_Printf(ctx, "Stream is already halted\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ctx->qtv->errored = ERR_PERMANENT;
|
||||||
|
Cmd_Printf(ctx, "Stream will disconnect\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void Cmd_Resume(cmdctxt_t *ctx)
|
||||||
|
{
|
||||||
|
if (ctx->qtv->errored == ERR_NONE)
|
||||||
|
Cmd_Printf(ctx, "Stream is already functional\n");
|
||||||
|
|
||||||
|
ctx->qtv->errored = ERR_RECONNECT;
|
||||||
|
Cmd_Printf(ctx, "Stream will attempt to reconnect\n");
|
||||||
|
}
|
||||||
|
|
||||||
void Cmd_Record(cmdctxt_t *ctx)
|
void Cmd_Record(cmdctxt_t *ctx)
|
||||||
{
|
{
|
||||||
char *fname = Cmd_Argv(ctx, 1);
|
char *fname = Cmd_Argv(ctx, 1);
|
||||||
|
@ -1000,10 +1054,10 @@ void Cmd_MuteStream(cmdctxt_t *ctx)
|
||||||
if (*val)
|
if (*val)
|
||||||
{
|
{
|
||||||
ctx->qtv->silentstream = atoi(val);
|
ctx->qtv->silentstream = atoi(val);
|
||||||
Cmd_Printf(ctx, "Stream is now %smuted\n", ctx->qtv->silentstream?"un":"");
|
Cmd_Printf(ctx, "Stream is now %smuted\n", ctx->qtv->silentstream?"":"un");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
Cmd_Printf(ctx, "Stream is currently %smuted\n", ctx->qtv->silentstream?"un":"");
|
Cmd_Printf(ctx, "Stream is currently %smuted\n", ctx->qtv->silentstream?"":"un");
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef VIEWER
|
#ifdef VIEWER
|
||||||
|
@ -1028,71 +1082,91 @@ void Cmd_Watch(cmdctxt_t *ctx)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
void Cmd_Commands(cmdctxt_t *ctx)
|
|
||||||
{
|
|
||||||
Cmd_Printf(ctx, "fixme\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef struct rconcommands_s {
|
typedef struct rconcommands_s {
|
||||||
char *name;
|
char *name;
|
||||||
qboolean serverspecific; //works within a qtv context
|
qboolean serverspecific; //works within a qtv context
|
||||||
qboolean clusterspecific; //works without a qtv context (ignores context)
|
qboolean clusterspecific; //works without a qtv context (ignores context)
|
||||||
consolecommand_t func;
|
consolecommand_t func;
|
||||||
|
char *description;
|
||||||
} rconcommands_t;
|
} rconcommands_t;
|
||||||
|
|
||||||
|
extern const rconcommands_t rconcommands[];
|
||||||
|
|
||||||
|
void Cmd_Commands(cmdctxt_t *ctx)
|
||||||
|
{
|
||||||
|
rconcommands_t *cmd;
|
||||||
|
consolecommand_t lastfunc = NULL;
|
||||||
|
|
||||||
|
Cmd_Printf(ctx, "Commands:\n");
|
||||||
|
for (cmd = rconcommands; cmd->name; cmd = cmd++)
|
||||||
|
{
|
||||||
|
if (cmd->func == lastfunc)
|
||||||
|
continue; //no spamming alternative command names
|
||||||
|
|
||||||
|
Cmd_Printf(ctx, "%s: %s\n", cmd->name, cmd->description?cmd->description:"no description available");
|
||||||
|
lastfunc = cmd->func;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const rconcommands_t rconcommands[] =
|
const rconcommands_t rconcommands[] =
|
||||||
{
|
{
|
||||||
{"exec", 1, 1, Cmd_Exec},
|
{"exec", 1, 1, Cmd_Exec, "executes a config file"},
|
||||||
{"status", 1, 1, Cmd_Status},
|
{"status", 1, 1, Cmd_Status, "prints proxy/stream status" },
|
||||||
{"say", 1, 1, Cmd_Say},
|
{"say", 1, 1, Cmd_Say, "says to a stream"},
|
||||||
|
|
||||||
{"help", 0, 1, Cmd_Help},
|
{"help", 0, 1, Cmd_Help, "shows the brief intro help text"},
|
||||||
{"commands", 0, 1, Cmd_Commands},
|
{"commands", 0, 1, Cmd_Commands, "prints the list of commands"},
|
||||||
{"hostname", 0, 1, Cmd_Hostname},
|
{"hostname", 0, 1, Cmd_Hostname, "changes the hostname seen in server browsers"},
|
||||||
{"master", 0, 1, Cmd_Master},
|
{"master", 0, 1, Cmd_Master, "specifies which master server to use"},
|
||||||
{"udpport", 0, 1, Cmd_UDPPort},
|
{"udpport", 0, 1, Cmd_UDPPort, "specifies to listen on a provided udp port for regular qw clients"},
|
||||||
{"port", 0, 1, Cmd_UDPPort},
|
{"port", 0, 1, Cmd_UDPPort},
|
||||||
{"adminpassword",0, 1, Cmd_AdminPassword},
|
{"adminpassword", 0, 1, Cmd_AdminPassword,"specifies the password for qtv administrators"},
|
||||||
{"rconpassword",0, 1, Cmd_AdminPassword},
|
{"rconpassword", 0, 1, Cmd_AdminPassword},
|
||||||
{"qtvlist", 0, 1, Cmd_QTVList},
|
{"qtvlist", 0, 1, Cmd_QTVList, "queries a seperate proxy for a list of available streams"},
|
||||||
{"qtvdemolist", 0, 1, Cmd_QTVDemoList},
|
{"qtvdemolist", 0, 1, Cmd_QTVDemoList, "queries a seperate proxy for a list of available demos"},
|
||||||
{"qtv", 0, 1, Cmd_QTVConnect},
|
{"qtv", 0, 1, Cmd_QTVConnect, "adds a new tcp/qtv stream"},
|
||||||
{"addserver", 0, 1, Cmd_QTVConnect},
|
{"addserver", 0, 1, Cmd_QTVConnect},
|
||||||
{"connect", 0, 1, Cmd_QTVConnect},
|
{"connect", 0, 1, Cmd_QTVConnect},
|
||||||
{"qw", 0, 1, Cmd_QWConnect},
|
{"qw", 0, 1, Cmd_QWConnect, "adds a new udp/qw stream"},
|
||||||
{"observe", 0, 1, Cmd_QWConnect},
|
{"observe", 0, 1, Cmd_QWConnect},
|
||||||
{"demos", 0, 1, Cmd_DemoList},
|
{"demos", 0, 1, Cmd_DemoList, "shows the list of demos available on this proxy"},
|
||||||
{"demo", 0, 1, Cmd_MVDConnect},
|
{"demo", 0, 1, Cmd_MVDConnect, "adds a demo as a new stream"},
|
||||||
{"playdemo", 0, 1, Cmd_MVDConnect},
|
{"playdemo", 0, 1, Cmd_MVDConnect},
|
||||||
{"choke", 0, 1, Cmd_Choke},
|
{"choke", 0, 1, Cmd_Choke, "chokes packets to the data rate in the stream, disables proxy-side interpolation"},
|
||||||
{"late", 0, 1, Cmd_Late},
|
{"late", 0, 1, Cmd_Late, "enforces a time delay on packets sent through this proxy"},
|
||||||
{"talking", 0, 1, Cmd_Talking},
|
{"talking", 0, 1, Cmd_Talking, "permits viewers to talk to each other"},
|
||||||
{"nobsp", 0, 1, Cmd_NoBSP},
|
{"nobsp", 0, 1, Cmd_NoBSP, "disables loading of bsp files"},
|
||||||
{"userconnects", 0, 1, Cmd_UserConnects},
|
{"userconnects", 0, 1, Cmd_UserConnects, "prevents users from creating thier own streams"},
|
||||||
{"maxviewers", 0, 1, Cmd_MaxViewers},
|
{"maxviewers", 0, 1, Cmd_MaxViewers, "sets a limit on udp/qw client connections"},
|
||||||
{"maxproxies", 0, 1, Cmd_MaxProxies},
|
{"maxproxies", 0, 1, Cmd_MaxProxies, "sets a limit on tcp/qtv client connections"},
|
||||||
{"demodir", 0, 1, Cmd_DemoDir},
|
{"demodir", 0, 1, Cmd_DemoDir, "specifies where to get the demo list from"},
|
||||||
{"basedir", 0, 1, Cmd_BaseDir},
|
{"basedir", 0, 1, Cmd_BaseDir, "specifies where to get any files required by the game. this is prefixed to the server-specified game dir."},
|
||||||
{"ping", 0, 1, Cmd_Ping},
|
{"ping", 0, 1, Cmd_Ping, "sends a udp ping to a qtv proxy or server"},
|
||||||
{"reconnect", 0, 1, Cmd_Reconnect},
|
{"reconnect", 0, 1, Cmd_Reconnect, "forces a stream to reconnect to its server (restarts demos)"},
|
||||||
{"echo", 0, 1, Cmd_Echo},
|
{"echo", 0, 1, Cmd_Echo, "a useless command that echos a string"},
|
||||||
{"quit", 0, 1, Cmd_Quit},
|
{"quit", 0, 1, Cmd_Quit, "closes the qtv"},
|
||||||
{"exit", 0, 1, Cmd_Quit},
|
{"exit", 0, 1, Cmd_Quit},
|
||||||
{"streams", 0, 1, Cmd_Streams},
|
{"streams", 0, 1, Cmd_Streams, "shows a list of active streams"},
|
||||||
{"allownq", 0, 1, Cmd_AllowNQ},
|
{"allownq", 0, 1, Cmd_AllowNQ, "permits nq clients to connect. This can be disabled as this code is less tested than the rest"},
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{"halt", 1, 0, Cmd_Halt, "disables a stream, preventing it from reconnecting until someone tries watching it anew"},
|
||||||
|
{"disable", 1, 0, Cmd_Halt},
|
||||||
|
{"resume", 1, 0, Cmd_Resume, "reactivates a stream, allowing it to reconnect"},
|
||||||
|
{"enable", 1, 0, Cmd_Resume},
|
||||||
|
{"mute", 1, 0, Cmd_MuteStream, "hides prints that come from the game server"},
|
||||||
{"mutestream", 1, 0, Cmd_MuteStream},
|
{"mutestream", 1, 0, Cmd_MuteStream},
|
||||||
{"disconnect", 1, 0, Cmd_Disconnect},
|
{"disconnect", 1, 0, Cmd_Disconnect, "fully closes a stream"},
|
||||||
{"record", 1, 0, Cmd_Record},
|
{"record", 1, 0, Cmd_Record, "records a stream to a demo"},
|
||||||
{"stop", 1, 0, Cmd_Stop},
|
{"stop", 1, 0, Cmd_Stop, "stops recording of a demo"},
|
||||||
{"demospeed", 1, 0, Cmd_DemoSpeed},
|
{"demospeed", 1, 0, Cmd_DemoSpeed, "changes the rate the demo is played at"},
|
||||||
{"tcpport", 0, 1, Cmd_MVDPort},
|
{"tcpport", 0, 1, Cmd_MVDPort, "specifies which port to listen on for tcp/qtv connections"},
|
||||||
{"mvdport", 0, 1, Cmd_MVDPort},
|
{"mvdport", 0, 1, Cmd_MVDPort},
|
||||||
|
|
||||||
#ifdef VIEWER
|
#ifdef VIEWER
|
||||||
{"watch", 1, 0, Cmd_Watch},
|
{"watch", 1, 0, Cmd_Watch, "specifies to watch that stream in the built-in viewer"},
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
{NULL}
|
{NULL}
|
||||||
|
@ -1137,6 +1211,7 @@ void Cmd_ExecuteNow(cmdctxt_t *ctx, char *command)
|
||||||
|
|
||||||
cmdname = Cmd_Argv(ctx, 0);
|
cmdname = Cmd_Argv(ctx, 0);
|
||||||
|
|
||||||
|
//if there's only one stream, set that as the selected stream
|
||||||
if (!ctx->qtv && ctx->cluster->numservers==1)
|
if (!ctx->qtv && ctx->cluster->numservers==1)
|
||||||
ctx->qtv = ctx->cluster->servers;
|
ctx->qtv = ctx->cluster->servers;
|
||||||
|
|
||||||
|
|
201
fteqtv/source.c
201
fteqtv/source.c
|
@ -364,7 +364,7 @@ void Net_SendQTVConnectionRequest(sv_t *qtv, char *authmethod, char *challenge)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
qtv->drop = true;
|
qtv->errored = ERR_PERMANENT;
|
||||||
qtv->upstreambuffersize = 0;
|
qtv->upstreambuffersize = 0;
|
||||||
Sys_Printf(qtv->cluster, "Auth method %s was not usable\n", authmethod);
|
Sys_Printf(qtv->cluster, "Auth method %s was not usable\n", authmethod);
|
||||||
return;
|
return;
|
||||||
|
@ -424,6 +424,11 @@ qboolean Net_ConnectToTCPServer(sv_t *qtv, char *ip)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//make sure the buffers are empty. we could have disconnected prematurly
|
||||||
|
qtv->upstreambuffersize = 0;
|
||||||
|
qtv->buffersize = 0;
|
||||||
|
qtv->forwardpoint = 0;
|
||||||
|
|
||||||
//read the notes at the start of this file for what these text strings mean
|
//read the notes at the start of this file for what these text strings mean
|
||||||
Net_SendQTVConnectionRequest(qtv, NULL, NULL);
|
Net_SendQTVConnectionRequest(qtv, NULL, NULL);
|
||||||
return true;
|
return true;
|
||||||
|
@ -615,7 +620,7 @@ void Net_QueueUpstream(sv_t *qtv, int size, char *buffer)
|
||||||
if (qtv->upstreambuffersize + size > sizeof(qtv->upstreambuffer))
|
if (qtv->upstreambuffersize + size > sizeof(qtv->upstreambuffer))
|
||||||
{
|
{
|
||||||
Sys_Printf(qtv->cluster, "Stream %i: Upstream queue overflowed for %s\n", qtv->streamid, qtv->server);
|
Sys_Printf(qtv->cluster, "Stream %i: Upstream queue overflowed for %s\n", qtv->streamid, qtv->server);
|
||||||
qtv->drop = true;
|
qtv->errored = ERR_RECONNECT;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
memcpy(qtv->upstreambuffer + qtv->upstreambuffersize, buffer, size);
|
memcpy(qtv->upstreambuffer + qtv->upstreambuffersize, buffer, size);
|
||||||
|
@ -642,7 +647,7 @@ qboolean Net_WriteUpstream(sv_t *qtv)
|
||||||
Sys_Printf(qtv->cluster, "Stream %i: Error: source socket error %i\n", qtv->streamid, qerrno);
|
Sys_Printf(qtv->cluster, "Stream %i: Error: source socket error %i\n", qtv->streamid, qerrno);
|
||||||
else
|
else
|
||||||
Sys_Printf(qtv->cluster, "Stream %i: Error: server %s disconnected\n", qtv->streamid, qtv->server);
|
Sys_Printf(qtv->cluster, "Stream %i: Error: server %s disconnected\n", qtv->streamid, qtv->server);
|
||||||
qtv->drop = true;
|
qtv->errored = ERR_RECONNECT; //if the server is down, we'll detect it on reconnect
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1034,16 +1039,32 @@ qboolean QTV_Connect(sv_t *qtv, char *serverurl)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void QTV_Shutdown(sv_t *qtv)
|
void QTV_Cleanup(sv_t *qtv, qboolean leaveadmins)
|
||||||
{
|
{ //disconnects the stream
|
||||||
oproxy_t *prox;
|
|
||||||
oproxy_t *old;
|
|
||||||
viewer_t *v;
|
viewer_t *v;
|
||||||
sv_t *peer;
|
|
||||||
cluster_t *cluster;
|
cluster_t *cluster;
|
||||||
int i;
|
int i;
|
||||||
Sys_Printf(qtv->cluster, "Stream %i: Closing source %s\n", qtv->streamid, qtv->server);
|
oproxy_t *prox;
|
||||||
|
oproxy_t *old;
|
||||||
|
|
||||||
|
cluster = qtv->cluster;
|
||||||
|
|
||||||
|
//set connected viewers to a different stream
|
||||||
|
if (cluster->viewserver == qtv)
|
||||||
|
cluster->viewserver = NULL;
|
||||||
|
for (v = cluster->viewers; v; v = v->next)
|
||||||
|
{
|
||||||
|
#warning fixme: honour leaveadmins
|
||||||
|
if (v->server == qtv)
|
||||||
|
{ //they were watching this one
|
||||||
|
QW_SetViewersServer(qtv->cluster, v, NULL);
|
||||||
|
QW_SetMenu(v, MENU_NONE);
|
||||||
|
QTV_SayCommand(cluster, v->server, v, "menu");
|
||||||
|
QW_PrintfToViewer(v, "Stream %s is closing\n", qtv->server);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// close the source handle
|
||||||
if (qtv->sourcesock != INVALID_SOCKET)
|
if (qtv->sourcesock != INVALID_SOCKET)
|
||||||
{
|
{
|
||||||
if (qtv->usequakeworldprotocols)
|
if (qtv->usequakeworldprotocols)
|
||||||
|
@ -1061,17 +1082,57 @@ void QTV_Shutdown(sv_t *qtv)
|
||||||
fclose(qtv->sourcefile);
|
fclose(qtv->sourcefile);
|
||||||
qtv->sourcefile = NULL;
|
qtv->sourcefile = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//cancel downloads
|
||||||
if (qtv->downloadfile)
|
if (qtv->downloadfile)
|
||||||
{
|
{
|
||||||
fclose(qtv->downloadfile);
|
fclose(qtv->downloadfile);
|
||||||
qtv->downloadfile = NULL;
|
qtv->downloadfile = NULL;
|
||||||
unlink(qtv->downloadname);
|
unlink(qtv->downloadname);
|
||||||
|
*qtv->downloadname = '\0';
|
||||||
}
|
}
|
||||||
// if (qtv->tcpsocket != INVALID_SOCKET)
|
//free the bsp
|
||||||
// closesocket(qtv->tcpsocket);
|
|
||||||
BSP_Free(qtv->bsp);
|
BSP_Free(qtv->bsp);
|
||||||
qtv->bsp = NULL;
|
qtv->bsp = NULL;
|
||||||
|
|
||||||
|
//clean up entity state
|
||||||
|
for (i = 0; i < ENTITY_FRAMES; i++)
|
||||||
|
{
|
||||||
|
if (qtv->frame[i].ents)
|
||||||
|
{
|
||||||
|
free(qtv->frame[i].ents);
|
||||||
|
qtv->frame[i].ents = NULL;
|
||||||
|
}
|
||||||
|
if (qtv->frame[i].entnums)
|
||||||
|
{
|
||||||
|
free(qtv->frame[i].entnums);
|
||||||
|
qtv->frame[i].entnums = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//boot connected downstream proxies
|
||||||
|
for (prox = qtv->proxies; prox; )
|
||||||
|
{
|
||||||
|
if (prox->file)
|
||||||
|
fclose(prox->file);
|
||||||
|
if (prox->sock != INVALID_SOCKET)
|
||||||
|
closesocket(prox->sock);
|
||||||
|
old = prox;
|
||||||
|
prox = prox->next;
|
||||||
|
free(old);
|
||||||
|
cluster->numproxies--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QTV_Shutdown(sv_t *qtv)
|
||||||
|
{
|
||||||
|
sv_t *peer;
|
||||||
|
cluster_t *cluster;
|
||||||
|
Sys_Printf(qtv->cluster, "Stream %i: Closing source %s\n", qtv->streamid, qtv->server);
|
||||||
|
|
||||||
|
QTV_Cleanup(qtv, false);
|
||||||
|
|
||||||
|
//unlink it
|
||||||
cluster = qtv->cluster;
|
cluster = qtv->cluster;
|
||||||
if (cluster->servers == qtv)
|
if (cluster->servers == qtv)
|
||||||
cluster->servers = qtv->next;
|
cluster->servers = qtv->next;
|
||||||
|
@ -1087,41 +1148,6 @@ void QTV_Shutdown(sv_t *qtv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cluster->viewserver == qtv)
|
|
||||||
cluster->viewserver = NULL;
|
|
||||||
|
|
||||||
for (v = cluster->viewers; v; v = v->next)
|
|
||||||
{
|
|
||||||
if (v->server == qtv)
|
|
||||||
{
|
|
||||||
QW_SetViewersServer(qtv->cluster, v, NULL);
|
|
||||||
QW_SetMenu(v, MENU_NONE);
|
|
||||||
QTV_SayCommand(cluster, v->server, v, "menu");
|
|
||||||
QW_PrintfToViewer(v, "Stream %s is closing\n", qtv->server);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < ENTITY_FRAMES; i++)
|
|
||||||
{
|
|
||||||
if (qtv->frame[i].ents)
|
|
||||||
free(qtv->frame[i].ents);
|
|
||||||
if (qtv->frame[i].entnums)
|
|
||||||
free(qtv->frame[i].entnums);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (prox = qtv->proxies; prox; )
|
|
||||||
{
|
|
||||||
if (prox->file)
|
|
||||||
fclose(prox->file);
|
|
||||||
if (prox->sock != INVALID_SOCKET)
|
|
||||||
closesocket(prox->sock);
|
|
||||||
old = prox;
|
|
||||||
prox = prox->next;
|
|
||||||
free(old);
|
|
||||||
cluster->numproxies--;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
free(qtv);
|
free(qtv);
|
||||||
cluster->numservers--;
|
cluster->numservers--;
|
||||||
}
|
}
|
||||||
|
@ -1457,15 +1483,32 @@ void QTV_Run(sv_t *qtv)
|
||||||
if (qtv->disconnectwhennooneiswatching == 1 && qtv->numviewers == 0 && qtv->proxies == NULL)
|
if (qtv->disconnectwhennooneiswatching == 1 && qtv->numviewers == 0 && qtv->proxies == NULL)
|
||||||
{
|
{
|
||||||
Sys_Printf(qtv->cluster, "Stream %i: %s became inactive\n", qtv->streamid, qtv->server);
|
Sys_Printf(qtv->cluster, "Stream %i: %s became inactive\n", qtv->streamid, qtv->server);
|
||||||
qtv->drop = true;
|
qtv->errored = ERR_DROP;
|
||||||
}
|
}
|
||||||
if (qtv->drop)
|
if (qtv->errored)
|
||||||
{
|
{
|
||||||
QTV_Shutdown(qtv);
|
if (qtv->errored == ERR_DISABLED)
|
||||||
return;
|
{
|
||||||
|
//this keeps any connected proxies ticking over.
|
||||||
|
//probably we should drop them instead - the connection will only be revived if one of them reconnects.
|
||||||
|
SV_ForwardStream(qtv, NULL, 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (qtv->errored == ERR_PERMANENT)
|
||||||
|
{
|
||||||
|
QTV_Cleanup(qtv, false); //frees various pieces of context
|
||||||
|
qtv->errored = ERR_DISABLED;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (qtv->errored == ERR_DROP)
|
||||||
|
{
|
||||||
|
QTV_Shutdown(qtv); //destroys the stream
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//we will read out as many packets as we can until we're up to date
|
//we will read out as many packets as we can until we're up to date
|
||||||
//note: this can cause real issues when we're overloaded for any length of time
|
//note: this can cause real issues when we're overloaded for any length of time
|
||||||
//each new packet comes with a leading msec byte (msecs from last packet)
|
//each new packet comes with a leading msec byte (msecs from last packet)
|
||||||
|
@ -1488,6 +1531,11 @@ void QTV_Run(sv_t *qtv)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (qtv->errored == ERR_RECONNECT)
|
||||||
|
{
|
||||||
|
qtv->errored = ERR_NONE;
|
||||||
|
qtv->nextconnectattempt = qtv->curtime; //make the reconnect happen _now_
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (qtv->sourcetype == SRC_UDP)
|
if (qtv->sourcetype == SRC_UDP)
|
||||||
|
@ -1499,10 +1547,26 @@ void QTV_Run(sv_t *qtv)
|
||||||
|
|
||||||
if (!qtv->isconnected && (qtv->curtime >= qtv->nextconnectattempt || qtv->curtime < qtv->nextconnectattempt - UDPRECONNECT_TIME*2))
|
if (!qtv->isconnected && (qtv->curtime >= qtv->nextconnectattempt || qtv->curtime < qtv->nextconnectattempt - UDPRECONNECT_TIME*2))
|
||||||
{
|
{
|
||||||
strcpy(qtv->status, "Attemping challenge\n");
|
if (qtv->errored == ERR_DISABLED)
|
||||||
Netchan_OutOfBand(qtv->cluster, qtv->sourcesock, qtv->serveraddress, 13, "getchallenge\n");
|
{
|
||||||
|
strcpy(qtv->status, "Given up connecting\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
strcpy(qtv->status, "Attemping challenge\n");
|
||||||
|
if (qtv->sourcesock == INVALID_SOCKET && !qtv->sourcefile)
|
||||||
|
{
|
||||||
|
if (!QTV_Connect(qtv, qtv->server)) //reconnect it
|
||||||
|
qtv->errored = ERR_PERMANENT;
|
||||||
|
}
|
||||||
|
if (qtv->errored == ERR_NONE)
|
||||||
|
Netchan_OutOfBand(qtv->cluster, qtv->sourcesock, qtv->serveraddress, 13, "getchallenge\n");
|
||||||
|
}
|
||||||
qtv->nextconnectattempt = qtv->curtime + UDPRECONNECT_TIME;
|
qtv->nextconnectattempt = qtv->curtime + UDPRECONNECT_TIME;
|
||||||
}
|
}
|
||||||
|
if (qtv->sourcesock == INVALID_SOCKET && !qtv->sourcefile)
|
||||||
|
return;
|
||||||
|
|
||||||
QTV_ParseQWStream(qtv);
|
QTV_ParseQWStream(qtv);
|
||||||
|
|
||||||
if (qtv->isconnected)
|
if (qtv->isconnected)
|
||||||
|
@ -1637,15 +1701,19 @@ void QTV_Run(sv_t *qtv)
|
||||||
|
|
||||||
if (qtv->sourcesock == INVALID_SOCKET && !qtv->sourcefile)
|
if (qtv->sourcesock == INVALID_SOCKET && !qtv->sourcefile)
|
||||||
{
|
{
|
||||||
|
if (qtv->errored == ERR_DISABLED)
|
||||||
|
return;
|
||||||
|
|
||||||
if (qtv->curtime >= qtv->nextconnectattempt || qtv->curtime < qtv->nextconnectattempt - RECONNECT_TIME*2)
|
if (qtv->curtime >= qtv->nextconnectattempt || qtv->curtime < qtv->nextconnectattempt - RECONNECT_TIME*2)
|
||||||
{
|
{
|
||||||
if (qtv->disconnectwhennooneiswatching == 2)
|
if (qtv->disconnectwhennooneiswatching == 2) //2 means a reverse connection
|
||||||
{
|
{
|
||||||
qtv->drop = true;
|
qtv->errored = ERR_DROP;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!QTV_Connect(qtv, qtv->server))
|
if (!QTV_Connect(qtv, qtv->server)) //reconnect it
|
||||||
{
|
{
|
||||||
|
qtv->errored = ERR_PERMANENT;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1692,7 +1760,7 @@ void QTV_Run(sv_t *qtv)
|
||||||
{
|
{
|
||||||
Sys_Printf(qtv->cluster, "Stream %i: Server is not a QTV server (or is incompatible)\n", qtv->streamid);
|
Sys_Printf(qtv->cluster, "Stream %i: Server is not a QTV server (or is incompatible)\n", qtv->streamid);
|
||||||
//printf("%i, %s\n", qtv->buffersize, qtv->buffer);
|
//printf("%i, %s\n", qtv->buffersize, qtv->buffer);
|
||||||
qtv->drop = true;
|
qtv->errored = ERR_PERMANENT;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (length < 6)
|
if (length < 6)
|
||||||
|
@ -1712,7 +1780,7 @@ void QTV_Run(sv_t *qtv)
|
||||||
if ((int)svversion != 1)
|
if ((int)svversion != 1)
|
||||||
{
|
{
|
||||||
Sys_Printf(qtv->cluster, "Stream %i: QTV server doesn't support a compatible protocol version (returned %i)\n", qtv->streamid, atoi((char*)qtv->buffer + 6));
|
Sys_Printf(qtv->cluster, "Stream %i: QTV server doesn't support a compatible protocol version (returned %i)\n", qtv->streamid, atoi((char*)qtv->buffer + 6));
|
||||||
qtv->drop = true;
|
qtv->errored = ERR_PERMANENT;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1752,13 +1820,13 @@ void QTV_Run(sv_t *qtv)
|
||||||
else if (!strcmp(start, "COMPRESSION"))
|
else if (!strcmp(start, "COMPRESSION"))
|
||||||
{ //we don't support compression, we didn't ask for it.
|
{ //we don't support compression, we didn't ask for it.
|
||||||
Sys_Printf(qtv->cluster, "Stream %i: QTV server wrongly used compression\n", qtv->streamid);
|
Sys_Printf(qtv->cluster, "Stream %i: QTV server wrongly used compression\n", qtv->streamid);
|
||||||
qtv->drop = true;
|
qtv->errored = ERR_PERMANENT;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (!strcmp(start, "PERROR"))
|
else if (!strcmp(start, "PERROR"))
|
||||||
{
|
{
|
||||||
Sys_Printf(qtv->cluster, "\nStream %i: Server PERROR from %s: %s\n\n", qtv->streamid, qtv->server, colon);
|
Sys_Printf(qtv->cluster, "\nStream %i: Server PERROR from %s: %s\n\n", qtv->streamid, qtv->server, colon);
|
||||||
qtv->drop = true;
|
qtv->errored = ERR_PERMANENT;
|
||||||
qtv->buffersize = 0;
|
qtv->buffersize = 0;
|
||||||
qtv->forwardpoint = 0;
|
qtv->forwardpoint = 0;
|
||||||
return;
|
return;
|
||||||
|
@ -1770,7 +1838,7 @@ void QTV_Run(sv_t *qtv)
|
||||||
qtv->forwardpoint = 0;
|
qtv->forwardpoint = 0;
|
||||||
|
|
||||||
if (qtv->disconnectwhennooneiswatching)
|
if (qtv->disconnectwhennooneiswatching)
|
||||||
qtv->drop = true; //if its a user registered stream, drop it immediatly
|
qtv->errored = ERR_DROP; //if its a user registered stream, drop it immediatly
|
||||||
else
|
else
|
||||||
{ //otherwise close the socket (this will result in a timeout and reconnect)
|
{ //otherwise close the socket (this will result in a timeout and reconnect)
|
||||||
if (qtv->sourcesock != INVALID_SOCKET)
|
if (qtv->sourcesock != INVALID_SOCKET)
|
||||||
|
@ -1823,7 +1891,7 @@ void QTV_Run(sv_t *qtv)
|
||||||
if (qtv->serverquery)
|
if (qtv->serverquery)
|
||||||
{
|
{
|
||||||
Sys_Printf(qtv->cluster, "End of list\n");
|
Sys_Printf(qtv->cluster, "End of list\n");
|
||||||
qtv->drop = true;
|
qtv->errored = ERR_DROP;
|
||||||
qtv->buffersize = 0;
|
qtv->buffersize = 0;
|
||||||
qtv->forwardpoint = 0;
|
qtv->forwardpoint = 0;
|
||||||
return;
|
return;
|
||||||
|
@ -1836,7 +1904,7 @@ void QTV_Run(sv_t *qtv)
|
||||||
else if (qtv->parsingqtvheader)
|
else if (qtv->parsingqtvheader)
|
||||||
{
|
{
|
||||||
Sys_Printf(qtv->cluster, "Stream %i: QTV server sent no begin command - assuming incompatible\n\n", qtv->streamid);
|
Sys_Printf(qtv->cluster, "Stream %i: QTV server sent no begin command - assuming incompatible\n\n", qtv->streamid);
|
||||||
qtv->drop = true;
|
qtv->errored = ERR_PERMANENT;
|
||||||
qtv->buffersize = 0;
|
qtv->buffersize = 0;
|
||||||
qtv->forwardpoint = 0;
|
qtv->forwardpoint = 0;
|
||||||
return;
|
return;
|
||||||
|
@ -2008,7 +2076,15 @@ sv_t *QTV_NewServerConnection(cluster_t *cluster, char *server, char *password,
|
||||||
for (qtv = cluster->servers; qtv; qtv = qtv->next)
|
for (qtv = cluster->servers; qtv; qtv = qtv->next)
|
||||||
{
|
{
|
||||||
if (!strcmp(qtv->server, server))
|
if (!strcmp(qtv->server, server))
|
||||||
|
{ //if the stream detected some permanent/config error, try reconnecting again (of course this only happens when someone tries using the stream)
|
||||||
|
#warning review this logic
|
||||||
|
if (qtv->errored == ERR_DISABLED)
|
||||||
|
{
|
||||||
|
if (!(!QTV_Connect(qtv, server) && !force)) //try and wake it up
|
||||||
|
qtv->errored = ERR_NONE;
|
||||||
|
}
|
||||||
return qtv;
|
return qtv;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (autoclose)
|
if (autoclose)
|
||||||
|
@ -2043,6 +2119,7 @@ sv_t *QTV_NewServerConnection(cluster_t *cluster, char *server, char *password,
|
||||||
{
|
{
|
||||||
if (!QTV_Connect(qtv, server) && !force)
|
if (!QTV_Connect(qtv, server) && !force)
|
||||||
{
|
{
|
||||||
|
QTV_Cleanup(qtv, false);
|
||||||
free(qtv);
|
free(qtv);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue