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;}