All pastes #622272 Raw Edit

Untitled

public text v1 · immutable
·published 2007-07-16 19:30 UTC
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;
}