rendered paste body//returns true if the pending proxy should be unlinked
//truth does not imply that it should be freed/released, just unlinked.
qboolean SV_ReadPendingProxy(cluster_t *cluster, oproxy_t *pend)
{
char tempbuf[512];
char *s;
char *e;
char *colon;
float clientversion = 0;
int len;
int headersize;
qboolean raw;
sv_t *qtv;
if (pend->drop)
{
if (pend->srcfile)
fclose(pend->srcfile);
closesocket(pend->sock);
free(pend);
cluster->numproxies--;
return true;
}
#define QTVSVHEADER "QTVSV 1.1\n"
Net_TryFlushProxyBuffer(cluster, pend);
if (pend->flushing)
{
if (pend->bufferpos == pend->buffersize)
{
if (pend->srcfile)
{
char buffer[4096];
len = fread(buffer, 1, sizeof(buffer), pend->srcfile);
if (!len)
{
fclose(pend->srcfile);
pend->srcfile = NULL;
}
Net_ProxySend(cluster, pend, buffer, len);
return false; //don't try reading anything yet
}
else
{
pend->drop = true;
return false;
}
}
else
return false;
}
if (pend->droptime < cluster->curtime)
{
pend->drop = true;
return false;
}
len = sizeof(pend->inbuffer) - pend->inbuffersize - 1;
len = recv(pend->sock, pend->inbuffer+pend->inbuffersize, len, 0);
if (len == 0)
{
pend->drop = true;
return false;
}
if (len < 0)
return false;
pend->inbuffersize += len;
pend->inbuffer[pend->inbuffersize] = '\0';
if (pend->inbuffersize >= 4)
{
if (strncmp(pend->inbuffer, "QTV\r", 4) && strncmp(pend->inbuffer, "QTV\n", 4) && strncmp(pend->inbuffer, "GET ", 4) && strncmp(pend->inbuffer, "POST ", 5))
{ //I have no idea what the smeg you are.
pend->drop = true;
return false;
}
}
//make sure there's a double \n somewhere
for (s = pend->inbuffer; *s; s++)
{
if (s[0] == '\n' && (s[1] == '\n' || (s[1] == '\r' && s[2] == '\n')))
break;
}
if (!*s)
return false; //don't have enough yet
s+=3;
headersize = s - pend->inbuffer - 1;
if (!strncmp(pend->inbuffer, "POST ", 5))
{
HTTPSV_PostMethod(cluster, pend, s);
return false; //not keen on this..
}
else if (!strncmp(pend->inbuffer, "GET ", 4))
{
HTTPSV_GetMethod(cluster, pend);
pend->flushing = true;
return false;
}
raw = false;
qtv = pend->defaultstream;
e = pend->inbuffer;
s = e;
while(*e)
{
if (*e == '\n' || *e == '\r')
{
*e = '\0';
colon = strchr(s, ':');
if (*s)
{
if (!colon)
{
if (!strcmp(s, "QTV"))
{
//just a qtv request (as in, not http or some other protocol)
}
else if (!strcmp(s, "SOURCELIST"))
{ //lists sources that are currently playing
s = QTVSVHEADER;
Net_ProxySend(cluster, pend, s, strlen(s));
if (!cluster->servers)
{
s = "PERROR: No sources currently available\n";
Net_ProxySend(cluster, pend, s, strlen(s));
}
else
{
for (qtv = cluster->servers; qtv; qtv = qtv->next)
{
s = tempbuf;
if (clientversion > 1)
{
int plyrs = 0;
int i;
for (i = 0; i < MAX_CLIENTS; i++)
{
if (*qtv->players[i].userinfo)
plyrs++;
}
sprintf(tempbuf, "SRCSRV: %s\n", qtv->server);
Net_ProxySend(cluster, pend, s, strlen(s));
sprintf(tempbuf, "SRCHOST: %s\n", qtv->hostname);
Net_ProxySend(cluster, pend, s, strlen(s));
sprintf(tempbuf, "SRCPLYRS: %i\n", plyrs);
Net_ProxySend(cluster, pend, s, strlen(s));
sprintf(tempbuf, "SRCVIEWS: %i\n", qtv->numviewers);
Net_ProxySend(cluster, pend, s, strlen(s));
sprintf(tempbuf, "SRCID: %i\n", qtv->streamid); //final part of each source
Net_ProxySend(cluster, pend, s, strlen(s));
}
else
{
sprintf(tempbuf, "ASOURCE: %i: %15s: %15s\n", qtv->streamid, qtv->server, qtv->hostname);
Net_ProxySend(cluster, pend, s, strlen(s));
}
}
qtv = NULL;
}
s = "\n";
Net_ProxySend(cluster, pend, s, strlen(s));
pend->flushing = true;
}
else if (!strcmp(s, "REVERSE"))
{ //this is actually a server trying to connect to us
//start up a new stream
//FIXME: does this work?
#if 1 //left disabled until properly tested
qtv = QTV_NewServerConnection(cluster, "reverse"/*server*/, "", true, 2, false, 0);
s = QTVSVHEADER; Net_ProxySend(cluster, pend, s, strlen(s));
s = "REVERSED\n"; Net_ProxySend(cluster, pend, s, strlen(s));
s = "VERSION: 1\n"; Net_ProxySend(cluster, pend, s, strlen(s));
s = "\n"; Net_ProxySend(cluster, pend, s, strlen(s));
//switch over the socket to the actual source connection rather than the pending
Net_TryFlushProxyBuffer(cluster, pend); //flush anything... this isn't ideal, but should be small enough
qtv->sourcesock = pend->sock;
pend->sock = 0;
memcpy(qtv->buffer, pend->inbuffer + headersize, pend->inbuffersize - headersize);
qtv->parsingqtvheader = true;
return false;
#endif
}
else if (!strcmp(s, "RECEIVE"))
{ //a client connection request without a source
if (cluster->numservers == 1)
{ //only one stream anyway
qtv = cluster->servers;
}
else
{ //try and hunt down an explicit stream (rather than a user-recorded one)
int numfound = 0;
sv_t *suitable;
for (qtv = cluster->servers; qtv; qtv = qtv->next)
{
if (!qtv->disconnectwhennooneiswatching)
{
suitable = qtv;
numfound++;
}
}
if (numfound == 1)
qtv = suitable;
}
if (!qtv)
{
s = QTVSVHEADER;
Net_ProxySend(cluster, pend, s, strlen(s));
s = "PERROR: Multiple streams are currently playing\n";
Net_ProxySend(cluster, pend, s, strlen(s));
s = "\n";
Net_ProxySend(cluster, pend, s, strlen(s));
pend->flushing = true;
}
}
else if (!strcmp(s, "DEMOLIST"))
{ //lists sources that are currently playing
int i;
Cluster_BuildAvailableDemoList(cluster);
s = QTVSVHEADER;
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;
}
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);
}
else
{
*colon++ = '\0';
if (!strcmp(s, "VERSION"))
{
clientversion = atof(colon);
}
else if (!strcmp(s, "RAW"))
raw = atoi(colon);
/*else if (!strcmp(s, "ROUTE"))
{ //pure rewroute...
//is this safe? probably not.
s = "QTVSV 1\n"
"PERROR: ROUTE command not yet implemented\n"
"\n";
Net_ProxySend(cluster, pend, s, strlen(s));
pend->flushing = true;
}
*/
else if (!strcmp(s, "SOURCE"))
{ //connects, creating a new source
while (*colon == ' ')
colon++;
for (s = colon; *s; s++)
if (*s < '0' || *s > '9')
break;
if (*s)
qtv = QTV_NewServerConnection(cluster, colon, "", false, true, true, false);
else
{
//numerical source, use a stream id.
for (qtv = cluster->servers; qtv; qtv = qtv->next)
if (qtv->streamid == atoi(colon))
break;
}
}
else if (!strcmp(s, "DEMO"))
{ //starts a demo off the server... source does the same thing though...
char buf[256];
snprintf(buf, sizeof(buf), "demo:%s", colon);
qtv = QTV_NewServerConnection(cluster, buf, "", false, true, true, false);
if (!qtv)
{
s = QTVSVHEADER
"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);
}
}
s = e+1;
}
e++;
}
if (!pend->flushing)
{
if (clientversion < 1)
{
s = QTVSVHEADER
"PERROR: Requested protocol version not supported\n"
"\n";
Net_ProxySend(cluster, pend, s, strlen(s));
pend->flushing = true;
}
if (!qtv)
{
s = QTVSVHEADER
"PERROR: No stream selected\n"
"\n";
Net_ProxySend(cluster, pend, s, strlen(s));
pend->flushing = true;
}
}
if (pend->flushing)
return false;
if (qtv->usequkeworldprotocols)
{
s = QTVSVHEADER
"PERROR: This version of QTV is unable to convert QuakeWorld to QTV protocols\n"
"\n";
Net_ProxySend(cluster, pend, s, strlen(s));
pend->flushing = true;
return false;
}
if (cluster->maxproxies>=0 && cluster->numproxies >= cluster->maxproxies)
{
s = QTVSVHEADER
"TERROR: This QTV has reached it's connection limit\n"
"\n";
Net_ProxySend(cluster, pend, s, strlen(s));
pend->flushing = true;
return false;
}
pend->next = qtv->proxies;
qtv->proxies = pend;
if (!raw)
{
s = QTVSVHEADER;
Net_ProxySend(cluster, pend, s, strlen(s));
s = "BEGIN: ";
Net_ProxySend(cluster, pend, s, strlen(s));
s = qtv->server;
Net_ProxySend(cluster, pend, s, strlen(s));
s = "\n\n";
Net_ProxySend(cluster, pend, s, strlen(s));
}
// else if (passwordprotected) //raw mode doesn't support passwords, so reject them
// {
// pend->flushing = true;
// return;
// }
Net_SendConnectionMVD(qtv, pend);
return true;
}