Some tweeks to stop qqshka from moaning. Also added qtvlist and qtvdemolist commands. Tweeked the webpage generation to be more informative.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@2472 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2007-03-03 21:39:06 +00:00
parent 4175b342ea
commit 6210ed87be
6 changed files with 420 additions and 190 deletions

View file

@ -435,6 +435,7 @@ int main(int argc, char **argv)
cluster.allownqclients = true;
strcpy(cluster.hostname, DEFAULT_HOSTNAME);
cluster.buildnumber = build_number();
cluster.maxproxies = -1;
Sys_Printf(&cluster, "QTV Build %i.\n", cluster.buildnumber);

View file

@ -70,7 +70,7 @@ void SV_FindProxies(SOCKET sock, cluster_t *cluster, sv_t *defaultqtv)
if (sock == INVALID_SOCKET)
return;
if (cluster->numproxies >= cluster->maxproxies && cluster->maxproxies)
if (cluster->maxproxies >= 0 && cluster->numproxies >= cluster->maxproxies)
{
const char buffer[] = {dem_all, 1, 'P','r','o','x','y',' ','i','s',' ','f','u','l','l','.'};
send(sock, buffer, strlen(buffer), 0);
@ -437,6 +437,100 @@ void SV_ForwardStream(sv_t *qtv, char *buffer, int length)
}
}
static const char qfont_table[256] = {
'\0', '#', '#', '#', '#', '.', '#', '#',
'#', 9, 10, '#', ' ', 13, '.', '.',
'[', ']', '0', '1', '2', '3', '4', '5',
'6', '7', '8', '9', '.', '<', '=', '>',
' ', '!', '"', '#', '$', '%', '&', '\'',
'(', ')', '*', '+', ',', '-', '.', '/',
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', ':', ';', '<', '=', '>', '?',
'@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
'`', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
'x', 'y', 'z', '{', '|', '}', '~', '<',
'<', '=', '>', '#', '#', '.', '#', '#',
'#', '#', ' ', '#', ' ', '>', '.', '.',
'[', ']', '0', '1', '2', '3', '4', '5',
'6', '7', '8', '9', '.', '<', '=', '>',
' ', '!', '"', '#', '$', '%', '&', '\'',
'(', ')', '*', '+', ',', '-', '.', '/',
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', ':', ';', '<', '=', '>', '?',
'@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
'`', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
'x', 'y', 'z', '{', '|', '}', '~', '<'
};
void HTMLprintf(char *outb, int outl, char *fmt, ...)
{
va_list val;
char qfmt[8192*4];
char *inb = qfmt;
va_start(val, fmt);
vsnprintf(qfmt, sizeof(qfmt), fmt, val);
va_end(val);
qfmt[sizeof(qfmt)-1] = 0;
outl--;
outl -= 5;
while (outl > 0 && *inb)
{
if (*inb == '<')
{
*outb++ = '&';
*outb++ = 'l';
*outb++ = 't';
*outb++ = ';';
outl -= 4;
}
else if (*inb == '>')
{
*outb++ = '&';
*outb++ = 'g';
*outb++ = 't';
*outb++ = ';';
outl -= 4;
}
else if (*inb == '\n')
{
*outb++ = '<';
*outb++ = 'b';
*outb++ = 'r';
*outb++ = '/';
*outb++ = '>';
outl -= 5;
}
else if (*inb == '&')
{
*outb++ = '&';
*outb++ = 'a';
*outb++ = 'm';
*outb++ = 'p';
*outb++ = ';';
outl -= 5;
}
else
{
*outb++ = qfont_table[*(unsigned char*)inb];
}
inb++;
}
*outb++ = 0;
}
void SV_GenerateNowPlayingHTTP(cluster_t *cluster, oproxy_t *dest)
{
int player;
@ -462,28 +556,41 @@ void SV_GenerateNowPlayingHTTP(cluster_t *cluster, oproxy_t *dest)
for (streams = cluster->servers; streams; streams = streams->next)
{
sprintf(buffer, "<A HREF=\"watch.qtv?sid=%i\">%s (%s: %s)</A><br/>", streams->streamid, streams->server, streams->gamedir, streams->mapname);
sprintf(buffer, "<A HREF=\"watch.qtv?sid=%i\">", streams->streamid);
Net_ProxySend(cluster, dest, buffer, strlen(buffer));
HTMLprintf(buffer, sizeof(buffer), "%s (%s: %s)", streams->server, streams->gamedir, streams->mapname);
Net_ProxySend(cluster, dest, buffer, strlen(buffer));
s = "</A><br/>";
Net_ProxySend(cluster, dest, s, strlen(s));
for (player = 0; player < MAX_CLIENTS; player++)
{
if (*streams->players[player].userinfo)
{
Info_ValueForKey(streams->players[player].userinfo, "name", plname, sizeof(plname));
sprintf(buffer, "&nbsp;%s<br/>", plname);
s = "&nbsp;";
Net_ProxySend(cluster, dest, s, strlen(s));
HTMLprintf(buffer, sizeof(buffer), "%s", plname);
Net_ProxySend(cluster, dest, buffer, strlen(buffer));
s = "<br/>";
Net_ProxySend(cluster, dest, s, strlen(s));
}
}
}
if (!cluster->servers)
{
s = "No streams are currently being played<br />";
Net_ProxySend(cluster, dest, s, strlen(s));
}
s = "<br /><A href=\"/demos.html\">Available Demos</A>";
s = "<br /><A href=\"/demos.html\">Available Demos</A><br />";
Net_ProxySend(cluster, dest, s, strlen(s));
s = "<A href=\"/admin.html\">Admin</A><br />";
Net_ProxySend(cluster, dest, s, strlen(s));
sprintf(buffer, "<br/>QTV Version: %i <a href=\"http://www.fteqw.com\">www.fteqw.com</a><br />", cluster->buildnumber);
Net_ProxySend(cluster, dest, buffer, strlen(buffer));
sprintf(buffer, "</BODY>");
Net_ProxySend(cluster, dest, buffer, strlen(buffer));
@ -750,13 +857,22 @@ void SV_GenerateAdminHTTP(cluster_t *cluster, oproxy_t *dest, int streamid, char
s = strchr(o, '\n');
if (s)
*s = 0;
Net_ProxySend(cluster, dest, o, strlen(o));
HTMLprintf(cmd, sizeof(cmd), "%s", o);
Net_ProxySend(cluster, dest, cmd, strlen(cmd));
Net_ProxySend(cluster, dest, "<BR />", 6);
if (!s)
break;
o = s+1;
}
s = "<br /><A href=\"/nowplaying.html\">Now Playing</A><br />";
Net_ProxySend(cluster, dest, s, strlen(s));
s = "<A href=\"/demos.html\">Available Demos</A><br />";
Net_ProxySend(cluster, dest, s, strlen(s));
sprintf(result, "<br/>QTV Version: %i <a href=\"http://www.fteqw.com\">www.fteqw.com</a><br />", cluster->buildnumber);
Net_ProxySend(cluster, dest, result, strlen(result));
s = "</BODY>"
"</HTML>";
Net_ProxySend(cluster, dest, s, strlen(s));
@ -768,7 +884,7 @@ void SV_GenerateAdminHTTP(cluster_t *cluster, oproxy_t *dest, int streamid, char
void SV_GenerateQTVDemoListing(cluster_t *cluster, oproxy_t *dest)
{
int numdemos = 0;
int i;
char link[256];
char *s;
s = "HTTP/1.1 200 OK\n"
@ -781,68 +897,25 @@ void SV_GenerateQTVDemoListing(cluster_t *cluster, oproxy_t *dest)
s = "<H1>QTV Demo listing</H1>";
Net_ProxySend(cluster, dest, s, strlen(s));
#ifdef _WIN32
Cluster_BuildAvailableDemoList(cluster);
for (i = 0; i < cluster->availdemoscount; i++)
{
WIN32_FIND_DATA ffd;
HANDLE h;
h = FindFirstFile("*.mvd", &ffd);
if (h != INVALID_HANDLE_VALUE)
{
do
{
numdemos++;
snprintf(link, sizeof(link), "<A HREF=\"watch.qtv?demo=%s\">%s</A><br/>", ffd.cFileName, ffd.cFileName);
Net_ProxySend(cluster, dest, link, strlen(link));
} while(FindNextFile(h, &ffd));
FindClose(h);
}
snprintf(link, sizeof(link), "<A HREF=\"watch.qtv?demo=%s\">%s</A> (%ikb)<br/>", cluster->availdemos[i].name, cluster->availdemos[i].name, cluster->availdemos[i].size/1024);
Net_ProxySend(cluster, dest, link, strlen(link));
}
#else
{
int namelen;
DIR *dir;
struct dirent *oneentry;
dir=opendir(".");
if (!dir)
{
s = "QTV Proxy is unable to search for available demos.";
Net_ProxySend(cluster, dest, s, strlen(s));
}
else
{
for(;;)
{
oneentry=readdir(dir);
if(!oneentry)
break;
#ifndef __CYGWIN__
if (oneentry->d_type == DT_DIR || oneentry->d_type == DT_LNK)
{
continue;
}
#endif
namelen = strlen(oneentry->d_name);
if (namelen > 4 && !strcmp(oneentry->d_name + namelen-4, ".mvd"))
{
numdemos++;
snprintf(link, sizeof(link), "<A HREF=\"watch.qtv?demo=%s\">%s</A><br/>", oneentry->d_name, oneentry->d_name);
Net_ProxySend(cluster, dest, link, strlen(link));
}
}
closedir(dir);
}
}
/*
s = "QTV Proxy is running on a platform for which file system listing is not coded.<br />Demo listing is not available.";
Net_ProxySend(cluster, dest, s, strlen(s));
*/
#endif
sprintf(link, "<P>Total: %i demos</P>", numdemos);
sprintf(link, "<P>Total: %i demos</P>", cluster->availdemoscount);
Net_ProxySend(cluster, dest, link, strlen(link));
s = "<br /><A href=\"/nowplaying.html\">Now Playing</A><br />";
Net_ProxySend(cluster, dest, s, strlen(s));
s = "<A href=\"/admin.html\">Admin</A><br />";
Net_ProxySend(cluster, dest, s, strlen(s));
sprintf(link, "<br/>QTV Version: %i <a href=\"http://www.fteqw.com\">www.fteqw.com</a><br />", cluster->buildnumber);
Net_ProxySend(cluster, dest, link, strlen(link));
s = "</BODY>"
"</HTML>";
Net_ProxySend(cluster, dest, s, strlen(s));
@ -1102,11 +1175,28 @@ qboolean SV_ReadPendingProxy(cluster_t *cluster, oproxy_t *pend)
}
}
else if (!strcmp(s, "DEMOLIST"))
{ //lists the demos available on this proxy
{ //lists sources that are currently playing
int i;
Cluster_BuildAvailableDemoList(cluster);
s = "QTVSV 1\n";
Net_ProxySend(cluster, pend, s, strlen(s));
s = "PERROR: DEMOLIST command not yet implemented\n";
Net_ProxySend(cluster, pend, s, strlen(s));
if (!cluster->availdemoscount)
{
s = "PERROR: No demos currently available\n";
Net_ProxySend(cluster, pend, s, strlen(s));
}
else
{
for (i = 0; i < cluster->availdemoscount; i++)
{
sprintf(tempbuf, "ADEMO: %i: %15s\n", cluster->availdemos[i].size, cluster->availdemos[i].name);
s = tempbuf;
Net_ProxySend(cluster, pend, s, strlen(s));
}
qtv = NULL;
}
s = "\n";
Net_ProxySend(cluster, pend, s, strlen(s));
pend->flushing = true;
@ -1154,7 +1244,7 @@ qboolean SV_ReadPendingProxy(cluster_t *cluster, oproxy_t *pend)
if (*s < '0' || *s > '9')
break;
if (*s)
qtv = QTV_NewServerConnection(cluster, colon, "", false, true, true);
qtv = QTV_NewServerConnection(cluster, colon, "", false, true, true, false);
else
{
//numerical source, use a stream id.
@ -1162,18 +1252,25 @@ qboolean SV_ReadPendingProxy(cluster_t *cluster, oproxy_t *pend)
if (qtv->streamid == atoi(colon))
break;
}
// s = "QTVSV 1\n"
// "PERROR: SOURCE command not yet implemented\n"
// "\n";
// Net_ProxySend(cluster, pend, s, strlen(s));
}
else if (!strcmp(s, "DEMO"))
{ //starts a demo off the server... source does the same thing though...
s = "QTVSV 1\n"
"PERROR: DEMO command not yet implemented\n"
"\n";
Net_ProxySend(cluster, pend, s, strlen(s));
pend->flushing = true;
char buf[256];
sprintf(buf, sizeof(buf), "demo:%s", colon);
qtv = QTV_NewServerConnection(cluster, buf, "", false, true, true, false);
if (!qtv)
{
s = "QTVSV 1\n"
"PERROR: couldn't open demo\n"
"\n";
Net_ProxySend(cluster, pend, s, strlen(s));
pend->flushing = true;
}
}
else if (!strcmp(s, "AUTH"))
{ //lists the demos available on this proxy
//part of the connection process, can be ignored if there's no password
}
else
printf("Unrecognised token in QTV connection request (%s)\n", s);
@ -1217,7 +1314,7 @@ qboolean SV_ReadPendingProxy(cluster_t *cluster, oproxy_t *pend)
pend->flushing = true;
return false;
}
if (cluster->maxproxies && cluster->numproxies >= cluster->maxproxies)
if (cluster->maxproxies>=0 && cluster->numproxies >= cluster->maxproxies)
{
s = "QTVSV 1\n"
"TERROR: This QTV has reached it's connection limit\n"

View file

@ -509,6 +509,7 @@ struct sv_s { //details about a server connection (also known as stream)
char connectpassword[64]; //password given to server
netadr_t serveraddress;
netchan_t netchan;
qboolean serverquery;
unsigned char buffer[MAX_PROXY_BUFFER]; //this doesn't cycle.
int buffersize; //it memmoves down
@ -924,7 +925,7 @@ void Com_BlockFullChecksum (void *buffer, int len, unsigned char *outbuf);
void Sys_Printf(cluster_t *cluster, char *fmt, ...);
oproxy_t *Net_FileProxy(sv_t *qtv, char *filename);
sv_t *QTV_NewServerConnection(cluster_t *cluster, char *server, char *password, qboolean force, qboolean autoclose, qboolean noduplicates);
sv_t *QTV_NewServerConnection(cluster_t *cluster, char *server, char *password, qboolean force, qboolean autoclose, qboolean noduplicates, qboolean query);
SOCKET Net_MVDListen(int port);
qboolean Net_StopFileProxy(sv_t *qtv);

View file

@ -2300,7 +2300,7 @@ void QTV_Say(cluster_t *cluster, sv_t *qtv, viewer_t *v, char *message, qboolean
else if (!strcmp(v->expectcommand, "addserver"))
{
snprintf(buf, sizeof(buf), "tcp:%s", message);
qtv = QTV_NewServerConnection(cluster, buf, "", false, false, false);
qtv = QTV_NewServerConnection(cluster, buf, "", false, false, false, false);
if (qtv)
{
QW_SetViewersServer(cluster, v, qtv);
@ -2326,7 +2326,7 @@ void QTV_Say(cluster_t *cluster, sv_t *qtv, viewer_t *v, char *message, qboolean
else if (!strcmp(v->expectcommand, "insecadddemo"))
{
snprintf(buf, sizeof(buf), "file:%s", message);
qtv = QTV_NewServerConnection(cluster, buf, "", false, false, false);
qtv = QTV_NewServerConnection(cluster, buf, "", false, false, false, false);
if (!qtv)
QW_PrintfToViewer(v, "Failed to play demo \"%s\"\n", message);
else
@ -2339,7 +2339,7 @@ void QTV_Say(cluster_t *cluster, sv_t *qtv, viewer_t *v, char *message, qboolean
else if (!strcmp(v->expectcommand, "adddemo"))
{
snprintf(buf, sizeof(buf), "file:%s", message);
qtv = QTV_NewServerConnection(cluster, buf, "", false, false, false);
qtv = QTV_NewServerConnection(cluster, buf, "", false, false, false, false);
if (!qtv)
QW_PrintfToViewer(v, "Failed to play demo \"%s\"\n", message);
else
@ -2681,7 +2681,7 @@ tuidemos:
else
message += 9;
snprintf(buf, sizeof(buf), "udp:%s", message);
qtv = QTV_NewServerConnection(cluster, buf, "", false, true, true);
qtv = QTV_NewServerConnection(cluster, buf, "", false, true, true, false);
if (qtv)
{
QW_SetMenu(v, MENU_NONE);
@ -2695,7 +2695,7 @@ tuidemos:
{
message += 6;
snprintf(buf, sizeof(buf), "udp:%s", message);
qtv = QTV_NewServerConnection(cluster, buf, "", false, true, false);
qtv = QTV_NewServerConnection(cluster, buf, "", false, true, false, false);
if (qtv)
{
QW_SetMenu(v, MENU_NONE);
@ -2710,7 +2710,7 @@ tuidemos:
{
message += 5;
snprintf(buf, sizeof(buf), "tcp:%s", message);
qtv = QTV_NewServerConnection(cluster, buf, "", false, true, true);
qtv = QTV_NewServerConnection(cluster, buf, "", false, true, true, false);
if (qtv)
{
QW_SetMenu(v, MENU_NONE);
@ -2747,7 +2747,7 @@ tuidemos:
{
message += 6;
snprintf(buf, sizeof(buf), "file:%s", message);
qtv = QTV_NewServerConnection(cluster, buf, "", false, true, true);
qtv = QTV_NewServerConnection(cluster, buf, "", false, true, true, false);
if (qtv)
{
QW_SetMenu(v, MENU_NONE);

View file

@ -27,18 +27,22 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
FTEQTV proxy commands: (build "__DATE__")\n\
----------------------\n\
connect, qtv, addserver\n\
- connect to a MVD stream (TCP)\n\
connect to a MVD stream (TCP)\n\
qtvlist\n\
lists available streams on a proxy\n\
qw\n\
- connect to a server as a player (UDP)\n\
connect to a server as a player (UDP)\n\
adddemo\n\
- play a demo from a MVD file\n\
play a demo from a MVD file\n\
port\n\
- UDP port for QuakeWorld client connections\n\
UDP port for QuakeWorld client connections\n\
mvdport\n\
- specify TCP port for MVD broadcasting\n\
specify TCP port for MVD broadcasting\n\
maxviewers, maxproxies\n\
- limit number of connections\n\
status, choke, late, talking, nobsp, reconnect, exec, password, master, hostname, record, stop, quit\n\n"
limit number of connections\n\
status, choke, late, talking, nobsp, reconnect, exec, password, master, hostname, record, stop, quit\n\
other random commands\n\
\n"
@ -402,6 +406,33 @@ char *Cmd_AdminPassword(cluster_t *cluster, sv_t *qtv, char *arg[MAX_ARGS], char
strncpy(cluster->adminpassword, arg[1], sizeof(cluster->adminpassword)-1);
return "Password changed.\n";
}
char *Cmd_QTVList(cluster_t *cluster, sv_t *qtv, char *arg[MAX_ARGS], char *buffer, int sizeofbuffer, qboolean localcommand)
{
if (!*arg[1])
return "connect requires an ip:port parameter\n";
memmove(arg[1]+4, arg[1], ARG_LEN-5);
strncpy(arg[1], "tcp:", 4);
qtv = QTV_NewServerConnection(cluster, arg[1], arg[2], false, false, false, true);
if (!qtv)
return "Failed to connect to server, connection aborted\n";
return "Querying proxy\n";
}
char *Cmd_QTVDemoList(cluster_t *cluster, sv_t *qtv, char *arg[MAX_ARGS], char *buffer, int sizeofbuffer, qboolean localcommand)
{
if (!*arg[1])
return "connect requires an ip:port parameter\n";
memmove(arg[1]+4, arg[1], ARG_LEN-5);
strncpy(arg[1], "tcp:", 4);
qtv = QTV_NewServerConnection(cluster, arg[1], arg[2], false, false, false, 2);
if (!qtv)
return "Failed to connect to server, connection aborted\n";
return "Querying proxy\n";
}
char *Cmd_QTVConnect(cluster_t *cluster, sv_t *qtv, char *arg[MAX_ARGS], char *buffer, int sizeofbuffer, qboolean localcommand)
{
if (!*arg[1])
@ -410,7 +441,7 @@ char *Cmd_QTVConnect(cluster_t *cluster, sv_t *qtv, char *arg[MAX_ARGS], char *b
memmove(arg[1]+4, arg[1], ARG_LEN-5);
strncpy(arg[1], "tcp:", 4);
if (!QTV_NewServerConnection(cluster, arg[1], arg[2], false, false, false))
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";
}
@ -422,7 +453,7 @@ char *Cmd_QWConnect(cluster_t *cluster, sv_t *qtv, char *arg[MAX_ARGS], char *bu
memmove(arg[1]+4, arg[1], ARG_LEN-5);
strncpy(arg[1], "udp:", 4);
if (!QTV_NewServerConnection(cluster, arg[1], arg[2], false, false, false))
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";
}
@ -438,7 +469,7 @@ char *Cmd_MVDConnect(cluster_t *cluster, sv_t *qtv, char *arg[MAX_ARGS], char *b
memmove(arg[1]+5, arg[1], ARG_LEN-6);
strncpy(arg[1], "file:", 5);
if (!QTV_NewServerConnection(cluster, arg[1], arg[2], false, false, false))
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";
}
@ -847,6 +878,8 @@ const rconcommands_t rconcommands[] =
{"port", 0, 1, Cmd_UDPPort},
{"adminpassword",0, 1, Cmd_AdminPassword},
{"rconpassword",0, 1, Cmd_AdminPassword},
{"qtvlist", 0, 1, Cmd_QTVList},
{"qtvdemolist", 0, 1, Cmd_QTVDemoList},
{"qtv", 0, 1, Cmd_QTVConnect},
{"addserver", 0, 1, Cmd_QTVConnect},
{"connect", 0, 1, Cmd_QTVConnect},

View file

@ -272,80 +272,110 @@ void Net_SendQTVConnectionRequest(sv_t *qtv, char *authmethod, char *challenge)
str = "QTV\n"; Net_QueueUpstream(qtv, strlen(str), str);
str = "VERSION: 1\n"; Net_QueueUpstream(qtv, strlen(str), str);
at = strchrrev(qtv->server, '@');
if (at)
if (qtv->serverquery)
{
*at = '\0';
str = "SOURCE: "; Net_QueueUpstream(qtv, strlen(str), str);
str = qtv->server; Net_QueueUpstream(qtv, strlen(str), str);
str = "\n"; Net_QueueUpstream(qtv, strlen(str), str);
*at = '@';
}
else
{
str = "RECEIVE\n"; Net_QueueUpstream(qtv, strlen(str), str);
}
if (!qtv->parsingqtvheader)
{
str = "RAW: 1\n"; Net_QueueUpstream(qtv, strlen(str), str);
}
else
{
if (authmethod)
if (qtv->serverquery == 2)
{
if (!strcmp(authmethod, "PLAIN"))
{
str = "AUTH: PLAIN\n"; Net_QueueUpstream(qtv, strlen(str), str);
str = "PASSWORD: \""; Net_QueueUpstream(qtv, strlen(str), str);
str = qtv->connectpassword; Net_QueueUpstream(qtv, strlen(str), str);
str = "\"\n"; Net_QueueUpstream(qtv, strlen(str), str);
}
else if (challenge && strlen(challenge)>=32 && !strcmp(authmethod, "CCITT"))
{
unsigned short crcvalue;
str = "AUTH: CCITT\n"; Net_QueueUpstream(qtv, strlen(str), str);
str = "PASSWORD: \""; Net_QueueUpstream(qtv, strlen(str), str);
snprintf(hash, sizeof(hash), "%s%s", challenge, qtv->connectpassword);
crcvalue = QCRC_Block(hash, strlen(hash));
sprintf(hash, "0x%X", (unsigned int)QCRC_Value(crcvalue));
str = hash; Net_QueueUpstream(qtv, strlen(str), str);
str = "\"\n"; Net_QueueUpstream(qtv, strlen(str), str);
}
else if (challenge && strlen(challenge)>=8 && !strcmp(authmethod, "MD4"))
{
unsigned int md4sum[4];
str = "AUTH: MD4\n"; Net_QueueUpstream(qtv, strlen(str), str);
str = "PASSWORD: \""; Net_QueueUpstream(qtv, strlen(str), str);
snprintf(hash, sizeof(hash), "%s%s", challenge, qtv->connectpassword);
Com_BlockFullChecksum (hash, strlen(hash), (unsigned char*)md4sum);
sprintf(hash, "%X%X%X%X", md4sum[0], md4sum[1], md4sum[2], md4sum[3]);
str = hash; Net_QueueUpstream(qtv, strlen(str), str);
str = "\"\n"; Net_QueueUpstream(qtv, strlen(str), str);
}
else if (!strcmp(authmethod, "NONE"))
{
str = "AUTH: NONE\n"; Net_QueueUpstream(qtv, strlen(str), str);
str = "PASSWORD: \n"; Net_QueueUpstream(qtv, strlen(str), str);
}
else
{
qtv->drop = true;
qtv->upstreambuffersize = 0;
Sys_Printf(qtv->cluster, "Auth method %s was not usable\n", authmethod);
return;
}
str = "DEMOLIST\n"; Net_QueueUpstream(qtv, strlen(str), str);
}
else
{
str = "AUTH: MD4\n"; Net_QueueUpstream(qtv, strlen(str), str);
str = "AUTH: CCITT\n"; Net_QueueUpstream(qtv, strlen(str), str);
str = "AUTH: PLAIN\n"; Net_QueueUpstream(qtv, strlen(str), str);
str = "AUTH: NONE\n"; Net_QueueUpstream(qtv, strlen(str), str);
str = "SOURCELIST\n"; Net_QueueUpstream(qtv, strlen(str), str);
}
}
else
{
at = strchrrev(qtv->server, '@');
if (at)
{
*at = '\0';
str = "SOURCE: "; Net_QueueUpstream(qtv, strlen(str), str);
if (strncmp(qtv->server, "tcp:", 4))
{
str = qtv->server;
Net_QueueUpstream(qtv, strlen(str), str);
}
else
{
str = strchr(qtv->server, ':');
if (str)
{
str++;
Net_QueueUpstream(qtv, strlen(str), str);
}
}
str = "\n"; Net_QueueUpstream(qtv, strlen(str), str);
*at = '@';
}
else
{
str = "RECEIVE\n"; Net_QueueUpstream(qtv, strlen(str), str);
}
if (!qtv->parsingqtvheader)
{
str = "RAW: 1\n"; Net_QueueUpstream(qtv, strlen(str), str);
}
else
{
if (authmethod)
{
if (!strcmp(authmethod, "PLAIN"))
{
str = "AUTH: PLAIN\n"; Net_QueueUpstream(qtv, strlen(str), str);
str = "PASSWORD: \""; Net_QueueUpstream(qtv, strlen(str), str);
str = qtv->connectpassword; Net_QueueUpstream(qtv, strlen(str), str);
str = "\"\n"; Net_QueueUpstream(qtv, strlen(str), str);
}
else if (challenge && strlen(challenge)>=32 && !strcmp(authmethod, "CCITT"))
{
unsigned short crcvalue;
str = "AUTH: CCITT\n"; Net_QueueUpstream(qtv, strlen(str), str);
str = "PASSWORD: \""; Net_QueueUpstream(qtv, strlen(str), str);
snprintf(hash, sizeof(hash), "%s%s", challenge, qtv->connectpassword);
crcvalue = QCRC_Block(hash, strlen(hash));
sprintf(hash, "0x%X", (unsigned int)QCRC_Value(crcvalue));
str = hash; Net_QueueUpstream(qtv, strlen(str), str);
str = "\"\n"; Net_QueueUpstream(qtv, strlen(str), str);
}
else if (challenge && strlen(challenge)>=8 && !strcmp(authmethod, "MD4"))
{
unsigned int md4sum[4];
str = "AUTH: MD4\n"; Net_QueueUpstream(qtv, strlen(str), str);
str = "PASSWORD: \""; Net_QueueUpstream(qtv, strlen(str), str);
snprintf(hash, sizeof(hash), "%s%s", challenge, qtv->connectpassword);
Com_BlockFullChecksum (hash, strlen(hash), (unsigned char*)md4sum);
sprintf(hash, "%X%X%X%X", md4sum[0], md4sum[1], md4sum[2], md4sum[3]);
str = hash; Net_QueueUpstream(qtv, strlen(str), str);
str = "\"\n"; Net_QueueUpstream(qtv, strlen(str), str);
}
else if (!strcmp(authmethod, "NONE"))
{
str = "AUTH: NONE\n"; Net_QueueUpstream(qtv, strlen(str), str);
str = "PASSWORD: \n"; Net_QueueUpstream(qtv, strlen(str), str);
}
else
{
qtv->drop = true;
qtv->upstreambuffersize = 0;
Sys_Printf(qtv->cluster, "Auth method %s was not usable\n", authmethod);
return;
}
}
else
{
str = "AUTH: MD4\n"; Net_QueueUpstream(qtv, strlen(str), str);
str = "AUTH: CCITT\n"; Net_QueueUpstream(qtv, strlen(str), str);
str = "AUTH: PLAIN\n"; Net_QueueUpstream(qtv, strlen(str), str);
str = "AUTH: NONE\n"; Net_QueueUpstream(qtv, strlen(str), str);
}
}
}
str = "\n"; Net_QueueUpstream(qtv, strlen(str), str);
@ -357,7 +387,7 @@ qboolean Net_ConnectToTCPServer(sv_t *qtv, char *ip)
netadr_t from;
unsigned long nonblocking = true;
if (!NET_StringToAddr(ip+4, &qtv->serveraddress, 27500))
if (!NET_StringToAddr(ip, &qtv->serveraddress, 27500))
{
Sys_Printf(qtv->cluster, "Unable to resolve %s\n", ip);
return false;
@ -402,7 +432,7 @@ qboolean Net_ConnectToUDPServer(sv_t *qtv, char *ip)
netadr_t from;
unsigned long nonblocking = true;
if (!NET_StringToAddr(ip+4, &qtv->serveraddress, 27500))
if (!NET_StringToAddr(ip, &qtv->serveraddress, 27500))
{
Sys_Printf(qtv->cluster, "Unable to resolve %s\n", ip);
return false;
@ -478,22 +508,56 @@ qboolean DemoFilenameIsOkay(char *fname)
*/
}
qboolean Net_ConnectToServer(sv_t *qtv, char *ip)
qboolean Net_ConnectToServer(sv_t *qtv)
{
char *at;
qboolean status;
enum {
SRC_BAD,
SRC_DEMO,
SRC_UDP,
SRC_TCP
} type = SRC_BAD;
char *ip = qtv->server;
if (!strncmp(ip, "udp:", 4))
{
type = SRC_UDP;
ip += 4;
}
else if (!strncmp(ip, "tcp:", 4))
{
type = SRC_TCP;
ip += 4;
}
else if (!strncmp(ip, "demo:", 5))
{
type = SRC_DEMO;
ip += 5;
}
else if (!strncmp(ip, "file:", 5))
{
type = SRC_DEMO;
ip += 5;
}
at = strchrrev(ip, '@');
if (at)
if (at && (type == SRC_DEMO || type == SRC_TCP))
{
if (type == SRC_DEMO)
type = SRC_TCP;
ip = at+1;
}
qtv->usequkeworldprotocols = false;
if (!strncmp(ip, "file:", 5) || !strncmp(ip, "demo:", 5))
qtv->nextconnectattempt = qtv->curtime + RECONNECT_TIME; //wait half a minuite before trying to reconnect
switch(type)
{
case SRC_DEMO:
qtv->sourcesock = INVALID_SOCKET;
if (DemoFilenameIsOkay(ip+5))
qtv->sourcefile = fopen(ip+5, "rb");
if (DemoFilenameIsOkay(ip))
qtv->sourcefile = fopen(ip, "rb");
else
qtv->sourcefile = NULL;
if (qtv->sourcefile)
@ -505,23 +569,19 @@ qboolean Net_ConnectToServer(sv_t *qtv, char *ip)
}
Sys_Printf(qtv->cluster, "Unable to open file %s\n", ip+5);
return false;
}
qtv->nextconnectattempt = qtv->curtime + RECONNECT_TIME; //wait half a minuite before trying to reconnect
if (!strncmp(ip, "udp:", 4))
{
case SRC_UDP:
qtv->usequkeworldprotocols = true;
status = Net_ConnectToUDPServer(qtv, ip);
}
else if (!strncmp(ip, "tcp:", 4) || at!=NULL)
status = Net_ConnectToTCPServer(qtv, ip);
else
{
return Net_ConnectToUDPServer(qtv, ip);
case SRC_TCP:
return Net_ConnectToTCPServer(qtv, ip);
default:
Sys_Printf(qtv->cluster, "Unknown source type %s\n", ip);
status = false;
return false;
}
return status;
}
void Net_QueueUpstream(sv_t *qtv, int size, char *buffer)
@ -847,7 +907,7 @@ qboolean QTV_Connect(sv_t *qtv, char *serverurl)
memcpy(qtv->server, serverurl, sizeof(qtv->server)-1);
if (!Net_ConnectToServer(qtv, qtv->server))
if (!Net_ConnectToServer(qtv))
{
Sys_Printf(qtv->cluster, "Couldn't connect (%s)\n", qtv->server);
return false;
@ -1566,13 +1626,43 @@ void QTV_Run(sv_t *qtv)
qtv->buffersize = 0;
return;
}
else if (!strcmp(start, "TERROR"))
else if (!strcmp(start, "TERROR") || !strcmp(start, "ERROR"))
{ //we don't support compression, we didn't ask for it.
Sys_Printf(qtv->cluster, "\nQTV server error: %s\n\n", colon);
qtv->drop = true;
qtv->buffersize = 0;
if (qtv->disconnectwhennooneiswatching)
qtv->drop = true; //if its a user registered stream, drop it immediatly
else
{ //otherwise close the socket (this will result in a timeout and reconnect)
if (qtv->sourcesock != INVALID_SOCKET)
{
closesocket(qtv->sourcesock);
qtv->sourcesock = INVALID_SOCKET;
}
}
return;
}
else if (!strcmp(start, "ASOURCE"))
{
Sys_Printf(qtv->cluster, "SRC: %s\n", colon);
}
else if (!strcmp(start, "ADEMO"))
{
int size;
size = atoi(colon);
colon = strchr(colon, ':');
if (!colon)
colon = "";
else
colon = colon+1;
while(*colon == ' ')
colon++;
if (size > 1024*1024)
Sys_Printf(qtv->cluster, "DEMO: (%3imb) %s\n", size/(1024*1024), colon);
else
Sys_Printf(qtv->cluster, "DEMO: (%3ikb) %s\n", size/1024, colon);
}
else if (!strcmp(start, "PRINT"))
{
Sys_Printf(qtv->cluster, "QTV server: %s\n", colon);
@ -1592,7 +1682,14 @@ void QTV_Run(sv_t *qtv)
qtv->buffersize -= length;
memmove(qtv->buffer, qtv->buffer + length, qtv->buffersize);
if (*authmethod)
if (qtv->serverquery)
{
Sys_Printf(qtv->cluster, "End of sources\n", colon);
qtv->drop = true;
qtv->buffersize = 0;
return;
}
else if (*authmethod)
{ //we need to send a challenge response now.
Net_SendQTVConnectionRequest(qtv, authmethod, challenge);
return;
@ -1750,7 +1847,7 @@ void QTV_Run(sv_t *qtv)
}
}
sv_t *QTV_NewServerConnection(cluster_t *cluster, char *server, char *password, qboolean force, qboolean autoclose, qboolean noduplicates)
sv_t *QTV_NewServerConnection(cluster_t *cluster, char *server, char *password, qboolean force, qboolean autoclose, qboolean noduplicates, qboolean query)
{
sv_t *qtv;
@ -1781,6 +1878,7 @@ sv_t *QTV_NewServerConnection(cluster_t *cluster, char *server, char *password,
qtv->sourcesock = INVALID_SOCKET;
qtv->disconnectwhennooneiswatching = autoclose;
qtv->parsingconnectiondata = true;
qtv->serverquery = query;
qtv->streamid = ++cluster->nextstreamid;