/* Copyright (C) 1996-1997 Id Software, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the included (GNU.txt) GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifdef __GNUC__ #define LittleLong(x) ({ typeof(x) _x = (x); _x = (((unsigned char *)&_x)[0]|(((unsigned char *)&_x)[1]<<8)|(((unsigned char *)&_x)[2]<<16)|(((unsigned char *)&_x)[3]<<24)); _x; }) #define LittleShort(x) ({ typeof(x) _x = (x); _x = (((unsigned char *)&_x)[0]|(((unsigned char *)&_x)[1]<<8)); _x; }) #else #define LittleLong(x) (x) #define LittleShort(x) (x) #endif //this is for a future version //#define COMMENTARY //each server that we are connected to has it's own state. //it should be easy enough to use one thread per server. //mvd info is forwarded to other proxies instantly //qwd stuff is buffered and delayed. :( //this means that when a new proxy connects, we have to send initial state as well as a chunk of pending state, expect to need to send new data before the proxy even has all the init stuff. We may need to raise MAX_PROXY_BUFFER to be larger than on the server #ifdef __GNUC__ #define PRINTFWARNING(x) __attribute__((format(printf, x, (x+1)))) #else #define PRINTFWARNING(x) /*nothing*/ #endif //how does multiple servers work //each proxy acts as a cluster of connections to servers //when a viewer connects, they are given a list of active server connections //if there's only one server connection, they are given that one automatically. #if defined(__APPLE__) && defined(__MACH__) #define MACOSX #endif #include /*work around fucked MSVC functions. we use our own for these*/ #if _MSC_VER >= 1300 && _MSC_VER < 1900 #include #ifndef _CRT_SECURE_NO_WARNINGS #define _CRT_SECURE_NO_WARNINGS #endif #define vsnprintf q_vsnprintf /*msvc doesn't null terminate. its insecute and thus useless*/ #define stricmp _stricmp /*msvc just doesn't work properly*/ #define chdir _chdir #define gwtcwd _getcwd #endif #ifdef _WIN32 #include #include //this includes windows.h and is the reason for much compiling slowness with windows builds. #ifdef IPPROTO_IPV6 #include #else #define IPPROTO_IPV6 41 #ifndef EAI_NONAME #define EAI_NONAME 8 #endif struct ip6_scope_id { union { struct { u_long Zone : 28; u_long Level : 4; }; u_long Value; }; }; struct in6_addr { u_char s6_addr[16]; /* IPv6 address */ }; typedef struct sockaddr_in6 { short sin6_family; u_short sin6_port; u_long sin6_flowinfo; struct in6_addr sin6_addr; union { u_long sin6_scope_id; struct ip6_scope_id sin6_scope_struct; }; }; #if !(_MSC_VER >= 1500) struct addrinfo { int ai_flags; int ai_family; int ai_socktype; int ai_protocol; size_t ai_addrlen; char* ai_canonname; struct sockaddr * ai_addr; struct addrinfo * ai_next; }; #endif #endif #ifdef _MSC_VER #pragma comment (lib, "wsock32.lib") #endif #define qerrno WSAGetLastError() #define NET_EWOULDBLOCK WSAEWOULDBLOCK #define NET_EINPROGRESS WSAEINPROGRESS #define NET_ECONNREFUSED WSAECONNREFUSED #define NET_ENOTCONN WSAENOTCONN //we have special functions to properly terminate sprintf buffers in windows. //we assume other systems are designed with even a minor thought to security. #if !defined(__MINGW32__) #define unlink _unlink //why do MS have to be so awkward? int snprintf(char *buffer, int buffersize, char *format, ...) PRINTFWARNING(3); int vsnprintf(char *buffer, int buffersize, const char *format, va_list argptr); #else #define unlink remove //seems mingw misses something #endif #ifdef _MSC_VER //okay, so warnings are here to help... they're ugly though. #pragma warning(disable: 4761) //integral size mismatch in argument #pragma warning(disable: 4244) //conversion from float to short #pragma warning(disable: 4018) //signed/unsigned mismatch #endif #elif defined(__CYGWIN__) #include #include #include #include #include #include #include #include #include #define ioctlsocket ioctl #define closesocket close #elif defined(linux) || defined(ixemul) || defined(MACOSX) // I hope by adding MACOSX here it doesnt stop it from being natively built on macosx #include #include #include #include #include #include #include #include #include #include #include #include #define ioctlsocket ioctl #define closesocket close #elif (defined(__MORPHOS__) && !defined(ixemul)) #include #include #include #include #include #include #include #define qerrno Errno() #define ioctlsocket IoctlSocket #define closesocket CloseSocket #else #error "Please insert required headers here" //try the cygwin ones #endif #ifndef NET_EWOULDBLOCK #define NET_EWOULDBLOCK EWOULDBLOCK #define NET_EINPROGRESS EINPROGRESS #define NET_ECONNREFUSED ECONNREFUSED #define NET_ENOTCONN ENOTCONN #endif #ifndef NET_EAGAIN #define NET_EAGAIN NET_EWOULDBLOCK #endif #ifndef IPV6_V6ONLY #define IPV6_V6ONLY 27 #endif #ifndef pgetaddrinfo #ifndef _WIN32 #define pgetaddrinfo getaddrinfo #define pfreeaddrinfo freeaddrinfo #endif #endif #ifndef SOCKET #define SOCKET int #endif #ifndef INVALID_SOCKET #define INVALID_SOCKET -1 #endif #ifndef qerrno #define qerrno errno #endif #include #include #ifndef _WIN32 //stricmp is ansi, strcasecmp is unix. #define stricmp strcasecmp #define strnicmp strncasecmp #endif #define ustrlen(s) strlen((char*)(s)) #define ustrcmp(s1,s2) strcmp((char*)(s1),(char*)(s2)) #define ustrncmp(s1,s2,l) strncmp((char*)(s1),(char*)(s2),l) size_t strlcpy(char *dst, const char *src, size_t siz); typedef struct { unsigned int digestsize; unsigned int contextsize; //you need to alloca(te) this much memory... void (*init) (void *context); void (*process) (void *context, const void *data, size_t datasize); void (*terminate) (unsigned char *digest, void *context); } hashfunc_t; extern hashfunc_t hash_sha1; /*extern hashfunc_t hash_sha2_224; extern hashfunc_t hash_sha2_256; extern hashfunc_t hash_sha2_384; extern hashfunc_t hash_sha2_512;*/ #define HMAC HMAC_quake //stop conflicts... size_t CalcHash(hashfunc_t *hash, unsigned char *digest, size_t maxdigestsize, const unsigned char *string, size_t stringlen); size_t HMAC(hashfunc_t *hashfunc, unsigned char *digest, size_t maxdigestsize, const unsigned char *data, size_t datalen, const unsigned char *key, size_t keylen); #ifdef LIBQTV #define Sys_Printf QTVSys_Printf #endif #ifndef STRINGIFY #define STRINGIFY2(s) #s #define STRINGIFY(s) STRINGIFY2(s) #endif #ifdef SVNREVISION #define QTV_VERSION_STRING STRINGIFY(SVNREVISION) #else //#include "../engine/common/bothdefs.h" //#define QTV_VERSION_STRING STRINGIFY(FTE_VER_MAJOR)"."STRINGIFY(FTE_VER_MINOR) #define QTV_VERSION_STRING "v?""?""?" #endif #define PROX_DEFAULTSERVERPORT 27500 #define PROX_DEFAULTLISTENPORT 27501 #define PROX_DEFAULTSERVER "localhost:27500" #define DEFAULT_HOSTNAME "FTEQTV" #define PROXYWEBSITE "http://fte.triptohell.info" //url for program #define MAX_ENTITY_LEAFS 32 #include "protocol.h" #ifndef __cplusplus typedef enum {false, true} qboolean; #else typedef int qboolean; extern "C" { #endif typedef struct { void *tcpcon; /*value not indirected, only compared*/ char sockaddr[64]; } netadr_t; #ifdef COMMENTARY typedef struct soundcapt_s { int (*update)(struct soundcapt_s *ghnd, int samplechunks, char *buffer); void (*close)(struct soundcapt_s *ptr); } soundcapt_t; typedef struct soundplay_s { int (*update)(struct soundplay_s *ghnd, int samplechunks, char *buffer); void (*close)(struct soundplay_s *ptr); } soundplay_t; #endif typedef struct { unsigned int readpos; unsigned int cursize; unsigned int maxsize; void *data; unsigned int startpos; qboolean overflowed; qboolean allowoverflow; } netmsg_t; typedef struct { SOCKET sock; netadr_t remote_address; unsigned short qport; unsigned int last_received; unsigned int cleartime; int maxdatagramlen; int maxreliablelen; int reliable_length; qboolean drop; qboolean isclient; qboolean isnqprotocol; netmsg_t message; char message_buf[MAX_MSGLEN]; //reliable message being built char reliable_buf[MAX_MSGLEN]; //reliable message that we're making sure arrives. float rate; unsigned int incoming_acknowledged; unsigned int last_reliable_sequence; unsigned int incoming_reliable_acknowledged; unsigned int incoming_reliable_sequence; unsigned int reliable_sequence; unsigned int incoming_sequence; unsigned int outgoing_sequence; unsigned int reliable_start; unsigned int outgoing_unreliable; unsigned int incoming_unreliable; unsigned int in_fragment_length; char in_fragment_buf[MAX_NQMSGLEN]; } netchan_t; typedef struct { #define MAX_QPATH 64 char name[MAX_QPATH]; } filename_t; typedef struct { unsigned char frame; unsigned short modelindex; unsigned char colormap; unsigned char skinnum; float origin[3]; float angles[3]; unsigned short effects; unsigned char alpha; unsigned char scale; // unsigned char fatness; // unsigned char abslight; // unsigned char h2flags; // unsigned char colormod[3]; // unsigned short light[4]; // unsigned char lightstyle; // unsigned char lightpflags; // unsigned char tagentity; // unsigned char tagindex; } entity_state_t; typedef struct { unsigned char frame; unsigned char modelindex; //colormap unsigned char skinnum; float origin[3]; float angles[3]; unsigned char effects; short velocity[3]; unsigned char weaponframe; } player_state_t; typedef struct { unsigned int stats[MAX_STATS]; char userinfo[MAX_USERINFO]; int ping; int packetloss; int frags; float entertime; int leafcount; unsigned short leafs[MAX_ENTITY_LEAFS]; qboolean oldactive:1; qboolean active:1; qboolean gibbed:1; qboolean dead:1; player_state_t current; player_state_t old; } playerinfo_t; typedef struct { entity_state_t ents[ENTS_PER_FRAME]; //ouchie ouchie! unsigned short entnum[ENTS_PER_FRAME]; int numents; } packet_entities_t; typedef struct { unsigned char msec; float angles[3]; short forwardmove, sidemove, upmove; unsigned char buttons; unsigned char impulse; } usercmd_t; extern const usercmd_t nullcmd; typedef float vec3_t[3]; typedef struct { float gravity; float maxspeed; float spectatormaxspeed; float accelerate; float airaccelerate; float waterfriction; float entgrav; float stopspeed; float wateraccelerate; float friction; } movevars_t; typedef struct { //in / out vec3_t origin; vec3_t velocity; //in usercmd_t cmd; movevars_t movevars; //internal vec3_t angles; float frametime; vec3_t forward, right, up; } pmove_t; #define MBTN_UP (1u<<0) #define MBTN_DOWN (1u<<1) #define MBTN_LEFT (1u<<2) #define MBTN_RIGHT (1u<<3) #define MBTN_ENTER (1u<<4) #define MAX_BACK_BUFFERS 16 typedef struct sv_s sv_t; typedef struct cluster_s cluster_t; typedef struct viewer_s { //viewers are regular clients connected over udp. //they may be watching a communal stream, or they might themselves be playing through the proxy, directly controlling the stream. qboolean drop; unsigned int timeout; unsigned int nextpacket; //for nq clients netchan_t netchan; qboolean maysend; qboolean chokeme; qboolean thinksitsconnected; qboolean conmenussupported; qboolean isproxy; unsigned int pext1, pext2; int servercount; netmsg_t backbuf[MAX_BACK_BUFFERS]; //note data is malloced! int backbuffered; unsigned int currentstats[MAX_STATS]; int trackplayer; int thisplayer; int userid; packet_entities_t frame[ENTITY_FRAMES]; int delta_frames[ENTITY_FRAMES]; struct viewer_s *next; struct viewer_s *commentator; char name[32]; char userinfo[1024]; int lost; //packets usercmd_t ucmds[3]; unsigned int lasttime; unsigned int menubuttons; int settime; //the time that we last told the client. vec3_t velocity; vec3_t origin; int isadmin; char expectcommand[16]; sv_t *server; int menuspamtime; int menunum; int menuop; int fwdval; //for scrolling up/down the menu using +forward/+back :) int firstconnect; } viewer_t; typedef struct { qboolean websocket; //true if we need to use special handling unsigned char wsbuf[16]; int wsbuflen; int wspushed; int wsbits; } wsrbuf_t; //'other proxy', these are mvd stream clients. typedef struct oproxy_s { int authkey; unsigned int droptime; qboolean flushing; qboolean drop; sv_t *defaultstream; sv_t *stream; FILE *srcfile; //buffer is padded with data from this file when its empty FILE *file; //recording a demo (written to) SOCKET sock; //playing to a proxy wsrbuf_t websocket; unsigned char inbuffer[MAX_PROXY_INBUFFER]; unsigned int inbuffersize; //amount of data available. unsigned char buffer[MAX_PROXY_BUFFER]; unsigned int buffersize; //use cyclic buffering. unsigned int bufferpos; struct oproxy_s *next; } oproxy_t; typedef struct tcpconnect_s { struct tcpconnect_s *next; SOCKET sock; wsrbuf_t websocket; netadr_t peeraddr; char *initialstreamname; unsigned char inbuffer[MAX_PROXY_INBUFFER]; unsigned int inbuffersize; //amount of data available. unsigned char outbuffer[MAX_PROXY_INBUFFER]; unsigned int outbuffersize; //amount of data available. } tcpconnect_t; typedef struct { float origin[3]; unsigned short soundindex; unsigned char volume; unsigned char attenuation; } staticsound_t; typedef struct bsp_s bsp_t; typedef struct { entity_state_t baseline; // entity_state_t current; // entity_state_t old; // unsigned int updatetime; //to stop lerping when it's an old entity (bodies, stationary grenades, ...) int leafcount; unsigned short leafs[MAX_ENTITY_LEAFS]; } entity_t; #define MAX_ENTITY_FRAMES 64 typedef struct { int oldframe; int numents; int maxents; entity_state_t *ents; //dynamically allocated unsigned short *entnums; //dynamically allocated } frame_t; typedef struct { unsigned char number; char bits[6]; } nail_t; typedef struct { float pos[3]; float angle[3]; } intermission_t; typedef enum { SRC_BAD, SRC_DEMO, SRC_DEMODIR, SRC_UDP, SRC_TCP } sourcetype_t; typedef enum { ERR_NONE, //stream is fine ERR_PAUSED, ERR_RECONNECT, //stream needs to reconnect ERR_PERMANENT, //permanent error, transitioning to disabled next frame ERR_DISABLED, //stream is disabled, can be set to reconnect by admin ERR_DROP //stream _will_ be forgotten about next frame } errorstate_t; 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; sourcetype_t sourcetype; //proxy chaining qboolean serverisproxy; qboolean proxyisselected; qboolean upstreamacceptschat; qboolean upstreamacceptsdownload; // qboolean parsingqtvheader; unsigned char upstreambuffer[2048]; int upstreambuffersize; unsigned int parsetime; unsigned int parsespeed; FILE *downloadfile; char downloadname[256]; char status[64]; qboolean silentstream; qboolean usequakeworldprotocols; unsigned int pext1; unsigned int pext2; int challenge; unsigned short qport; int isconnected; int clservercount; unsigned int nextsendpings; unsigned int timeout; unsigned int packetratelimiter; viewer_t *controller; int controllersquencebias; qboolean proxyplayer; //a player is actually playing on the proxy. usercmd_t proxyplayerucmds[3]; int proxyplayerucmdnum; int proxyplayerbuttons; float proxyplayerangles[3]; float proxyplayerimpulse; qboolean maysend; FILE *sourcefile; unsigned int filelength; SOCKET sourcesock; int last_random_number; // for demo directories randomizing stuff // SOCKET tcpsocket; //tcp + mvd protocol // int tcplistenportnum; oproxy_t *proxies; qboolean parsingconnectiondata; //so reject any new connects for now unsigned int mapstarttime; unsigned int physicstime; //the last time all the ents moved. unsigned int simtime; unsigned int curtime; unsigned int oldpackettime; unsigned int nextpackettime; unsigned int nextconnectattempt; errorstate_t errored; enum autodisconnect_e { AD_NO, AD_WHENEMPTY, AD_REVERSECONNECT, AD_STATUSPOLL } autodisconnect; unsigned int numviewers; cluster_t *cluster; sv_t *next; //next proxy->server connection #ifdef COMMENTARY //audio stuff soundcapt_t *comentrycapture; #endif //options: char server[MAX_QPATH]; int streamid; struct mapstate_s { //this structure is freed+memset in QTV_CleanupMap bsp_t *bsp; int numinlines; nail_t nails[32]; int nailcount; char gamedir[MAX_QPATH]; char mapname[256]; //world.message movevars_t movevars; int cdtrack; entity_t entity[MAX_ENTITIES]; frame_t frame[MAX_ENTITY_FRAMES]; // int maxents; staticsound_t staticsound[MAX_STATICSOUNDS]; int staticsound_count; entity_state_t spawnstatic[MAX_STATICENTITIES]; int spawnstatic_count; filename_t lightstyle[MAX_LIGHTSTYLES]; char serverinfo[MAX_SERVERINFO_STRING]; char hostname[MAX_QPATH]; playerinfo_t players[MAX_CLIENTS]; filename_t modellist[MAX_MODELS]; filename_t soundlist[MAX_SOUNDS]; int modelindex_spike; // qw is wierd. int modelindex_player; // qw is wierd. int trackplayer; int thisplayer; qboolean ispaused; } map; unsigned char buffer[MAX_PROXY_BUFFER]; //this doesn't cycle. int buffersize; //it memmoves down int forwardpoint; //the point in the stream that we've forwarded up to. }; typedef struct { char name[128]; int size; int time, smalltime; } availdemo_t; enum { SG_IPV4, SG_IPV6, SG_UNIX, SOCKETGROUPS }; struct cluster_s { SOCKET qwdsocket[SOCKETGROUPS]; //udp + quakeworld protocols SOCKET tcpsocket[SOCKETGROUPS]; //tcp listening socket (for mvd and listings and stuff) tcpconnect_t *tcpconnects; //'tcpconnect' qizmo-compatible quakeworld-over-tcp connection char commandinput[512]; int inputlength; unsigned int mastersendtime; unsigned int mastersequence; unsigned int curtime; viewer_t *viewers; int numviewers; sv_t *servers; int numservers; int nextstreamid; int nextuserid; sv_t *viewserver; //options char autojoinadr[128]; //new clients automatically .join this server int qwlistenportnum; int tcplistenportnum; char adminpassword[256];//password required for rcon etc char qtvpassword[256]; //password required to connect a proxy char hostname[256]; char master[MAX_QPATH]; char demodir[MAX_QPATH]; char downloaddir[MAX_QPATH]; //must be slash terminated, or empty. char plugindatasource[256]; //sued by the http server for use with npfte char mapsource[256]; //sued by the http server for use with npfte qboolean chokeonnotupdated; qboolean lateforward; qboolean notalking; qboolean nobsp; qboolean allownqclients; //nq clients require no challenge qboolean nouserconnects; //prohibit users from connecting to new streams. qboolean reverseallowed; //demos can be submitted from servers via 'qtvreverse' without needing to keep idle connections live. int anticheattime; //intial connection buffer delay (set high to block specing enemies) int tooslowdelay; //if stream ran out of data, stop parsing for this long int maxviewers; int numproxies; int maxproxies; qboolean wanttoexit; oproxy_t *pendingproxies; availdemo_t availdemos[2048]; int availdemoscount; }; #define MENU_NONE 0 #define MENU_MAIN 1//MENU_SERVERS #define MENU_SERVERS 2 #define MENU_CLIENTS 3 #define MENU_ADMIN 4 #define MENU_ADMINSERVER 5 #define MENU_DEMOS 6 #define MENU_FORWARDING 7 #define MENU_SERVERBROWSER 8 #define MENU_HELP 9 #define MENU_DEFAULT MENU_MAIN enum { MENU_MAIN_STREAMS, MENU_MAIN_NEWSTREAM, MENU_MAIN_SERVERBROWSER, MENU_MAIN_PREVPROX, MENU_MAIN_HELP, MENU_MAIN_CLIENTLIST, MENU_MAIN_DEMOS, MENU_MAIN_ADMIN, MENU_MAIN_NEXTPROX, MENU_MAIN_ITEMCOUNT }; unsigned char ReadByte(netmsg_t *b); unsigned short ReadShort(netmsg_t *b); unsigned int ReadLong(netmsg_t *b); float ReadFloat(netmsg_t *b); void ReadString(netmsg_t *b, char *string, int maxlen); float ReadCoord(netmsg_t *b, unsigned int pext); float ReadAngle(netmsg_t *b, unsigned int pext); unsigned int SwapLong(unsigned int val); unsigned int BigLong(unsigned int val); //flags for where a message can be sent, for easy broadcasting #define Q1 (NQ|QW) #define QW 1 #define NQ 2 #define CONNECTING 4 #include "cmd.h" void InitNetMsg(netmsg_t *b, void *buffer, int bufferlength); unsigned char ReadByte(netmsg_t *b); unsigned short ReadShort(netmsg_t *b); unsigned int ReadLong(netmsg_t *b); float ReadFloat(netmsg_t *b); void ReadString(netmsg_t *b, char *string, int maxlen); void WriteByte(netmsg_t *b, unsigned char c); void WriteShort(netmsg_t *b, unsigned short l); void WriteLong(netmsg_t *b, unsigned int l); void WriteFloat(netmsg_t *b, float f); void WriteCoord(netmsg_t *b, float c, unsigned int pext); void WriteAngle(netmsg_t *b, float a, unsigned int pext); void WriteString2(netmsg_t *b, const char *str); void WriteString(netmsg_t *b, const char *str); void WriteData(netmsg_t *b, const void *data, int length); void Multicast(sv_t *tv, void *buffer, int length, int to, unsigned int playermask,int suitablefor); void Broadcast(cluster_t *cluster, void *buffer, int length, int suitablefor); void ParseMessage(sv_t *tv, void *buffer, int length, int to, int mask); void BuildServerData(sv_t *tv, netmsg_t *msg, int servercount, viewer_t *spectatorflag); void BuildNQServerData(sv_t *tv, netmsg_t *msg, qboolean mvd, int servercount); void QW_UpdateUDPStuff(cluster_t *qtv); void QW_TCPConnection(cluster_t *cluster, oproxy_t *sock, char *initialstringname/*strduped*/); unsigned int Sys_Milliseconds(void); void Prox_SendInitialEnts(sv_t *qtv, oproxy_t *prox, netmsg_t *msg); qboolean QTV_ConnectStream(sv_t *qtv, char *serverurl); void QTV_ShutdownStream(sv_t *qtv); qboolean NET_StringToAddr (char *s, netadr_t *sadr, int defaultport); void QTV_Printf(sv_t *qtv, char *format, ...) PRINTFWARNING(2); void QTV_UpdatedServerInfo(sv_t *tv); void QTV_CleanupMap(sv_t *qtv); void SendBufferToViewer(viewer_t *v, const char *buffer, int length, qboolean reliable); void QW_PrintfToViewer(viewer_t *v, char *format, ...) PRINTFWARNING(2); void QW_StuffcmdToViewer(viewer_t *v, char *format, ...) PRINTFWARNING(2); void QW_StreamPrint(cluster_t *cluster, sv_t *server, viewer_t *allbut, char *message); void QW_StreamStuffcmd(cluster_t *cluster, sv_t *server, char *fmt, ...) PRINTFWARNING(3); void QTV_SayCommand(cluster_t *cluster, sv_t *qtv, viewer_t *v, char *fullcommand); //execute a command from a view void QW_SetViewersServer(cluster_t *cluster, viewer_t *viewer, sv_t *sv); void QW_SetMenu(viewer_t *v, int menunum); void QW_SetCommentator(cluster_t *cluster, viewer_t *v, viewer_t *commentator); void QW_FreeViewer(cluster_t *cluster, viewer_t *viewer); void QW_ClearViewerState(viewer_t *viewer); void PM_PlayerMove (pmove_t *pmove); void Netchan_Setup (SOCKET sock, netchan_t *chan, netadr_t adr, int qport, qboolean isclient); void Netchan_OutOfBandPrint (cluster_t *cluster, netadr_t adr, char *format, ...) PRINTFWARNING(3); //int Netchan_IsLocal (netadr_t adr); void NET_InitUDPSocket(cluster_t *cluster, int port, int socketid); void NET_SendPacket(cluster_t *cluster, SOCKET sock, int length, void *data, netadr_t adr); SOCKET NET_ChooseSocket(SOCKET sock[SOCKETGROUPS], netadr_t *toadr, netadr_t in); qboolean Net_CompareAddress(netadr_t *s1, netadr_t *s2, int qp1, int qp2); qboolean Netchan_Process (netchan_t *chan, netmsg_t *msg); qboolean NQNetchan_Process(cluster_t *cluster, netchan_t *chan, netmsg_t *msg); void Netchan_Transmit (cluster_t *cluster, netchan_t *chan, int length, const void *data); void Netchan_OutOfBandSocket (cluster_t *cluster, SOCKET sock, netadr_t *adr, int length, void *data); void Netchan_OutOfBand(cluster_t *cluster, netadr_t adr, int length, void *data); qboolean Netchan_CanPacket (netchan_t *chan); int NET_WebSocketRecv(SOCKET sock, wsrbuf_t *ws, unsigned char *out, unsigned int outlen, int *wslen); int SendList(sv_t *qtv, int first, const filename_t *list, int svc, netmsg_t *msg); int Prespawn(sv_t *qtv, int curmsgsize, netmsg_t *msg, int bufnum, int thisplayer); bsp_t *BSP_LoadModel(cluster_t *cluster, char *gamedir, char *bspname); void BSP_Free(bsp_t *bsp); int BSP_LeafNum(bsp_t *bsp, float x, float y, float z); unsigned int BSP_Checksum(bsp_t *bsp); int BSP_SphereLeafNums(bsp_t *bsp, int maxleafs, unsigned short *list, float x, float y, float z, float radius); qboolean BSP_Visible(bsp_t *bsp, int leafcount, unsigned short *list); void BSP_SetupForPosition(bsp_t *bsp, float x, float y, float z); const intermission_t *BSP_IntermissionSpot(bsp_t *bsp); unsigned short QCRC_Block (void *start, int count); unsigned short QCRC_Value(unsigned short crcvalue); void WriteDeltaUsercmd (netmsg_t *m, const usercmd_t *from, usercmd_t *move); void SendClientCommand(sv_t *qtv, char *fmt, ...) PRINTFWARNING(2); void QTV_Run(sv_t *qtv); char *COM_ParseToken (char *data, char *out, int outsize, const char *punctuation); char *Info_ValueForKey (char *s, const char *key, char *buffer, int buffersize); void Info_SetValueForStarKey (char *s, const char *key, const char *value, int maxsize); void ReadDeltaUsercmd (netmsg_t *m, const usercmd_t *from, usercmd_t *move); unsigned Com_BlockChecksum (void *buffer, int length); void Com_BlockFullChecksum (void *buffer, int len, unsigned char *outbuf); void Cluster_BuildAvailableDemoList(cluster_t *cluster); void Sys_Printf(cluster_t *cluster, char *fmt, ...) PRINTFWARNING(2); //void Sys_mkdir(char *path); void QTV_mkdir(char *path); void Net_ProxySend(cluster_t *cluster, oproxy_t *prox, void *buffer, int length); oproxy_t *Net_FileProxy(sv_t *qtv, char *filename); sv_t *QTV_NewServerConnection(cluster_t *cluster, int streamid, char *server, char *password, qboolean force, enum autodisconnect_e autodisconnect, qboolean noduplicates, qboolean query); void Net_TCPListen(cluster_t *cluster, int port, int socketid); qboolean Net_StopFileProxy(sv_t *qtv); void SV_FindProxies(SOCKET sock, cluster_t *cluster, sv_t *defaultqtv); qboolean SV_ReadPendingProxy(cluster_t *cluster, oproxy_t *pend); void SV_ForwardStream(sv_t *qtv, void *buffer, int length); int SV_SayToUpstream(sv_t *qtv, char *message); void SV_SayToViewers(sv_t *qtv, char *message); unsigned char *FS_ReadFile(char *gamedir, char *filename, unsigned int *size); void ChooseFavoriteTrack(sv_t *tv); void DemoViewer_Update(sv_t *svtest); void Fwd_SayToDownstream(sv_t *qtv, char *message); //httpsv.c char *HTTPSV_GetMethod(cluster_t *cluster, oproxy_t *pend); //if a websocket request, return value is the stream name void HTTPSV_PostMethod(cluster_t *cluster, oproxy_t *pend, char *postdata); void tobase64(unsigned char *out, int outlen, unsigned char *in, int inlen); //menu.c void Menu_Enter(cluster_t *cluster, viewer_t *viewer, int buttonnum); void Menu_Draw(cluster_t *cluster, viewer_t *viewer); #ifdef __cplusplus } #endif