mirror of
https://github.com/nzp-team/fteqw.git
synced 2024-11-22 12:01:25 +00:00
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:
parent
4175b342ea
commit
6210ed87be
6 changed files with 420 additions and 190 deletions
|
@ -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);
|
||||
|
||||
|
|
253
fteqtv/forward.c
253
fteqtv/forward.c
|
@ -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, " %s<br/>", plname);
|
||||
|
||||
s = " ";
|
||||
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"
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
14
fteqtv/qw.c
14
fteqtv/qw.c
|
@ -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);
|
||||
|
|
|
@ -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},
|
||||
|
|
286
fteqtv/source.c
286
fteqtv/source.c
|
@ -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;
|
||||
|
||||
|
|
Loading…
Reference in a new issue