diff --git a/qtv/source/server.c b/qtv/source/server.c index ef942e575..30ae9e8d5 100644 --- a/qtv/source/server.c +++ b/qtv/source/server.c @@ -96,7 +96,26 @@ server_handler (connection_t *con, void *object) return; if (!Netchan_Process (&sv->netchan)) return; - Con_Printf ("hi\n"); + while (1) { + int cmd; + if (net_message->badread) { + break; + } + cmd = MSG_ReadByte (net_message); + if (cmd == -1) { + net_message->readcount++; + break; + } + switch (cmd) { + default: + qtv_printf ("Illegible server message: %d\n", cmd); + goto bail; + case svc_disconnect: + qtv_printf ("%s: disconnected\n", sv->name); + break; + } + } +bail: Netchan_Transmit (&sv->netchan, 1, &d); } @@ -109,16 +128,16 @@ expect_packet (qmsg_t *msg, int type) MSG_BeginReading (net_message); seq = MSG_ReadLong (net_message); if (seq != -1) { - Con_Printf ("unexpected connected packet\n"); + qtv_printf ("unexpected connected packet\n"); return 0; } str = MSG_ReadString (net_message); if (str[0] == A2C_PRINT) { - Con_Printf ("%s", str + 1); + qtv_printf ("%s", str + 1); return 0; } if (str[0] != type) { - Con_Printf ("unexpected connectionless packet type: %s\n", str); + qtv_printf ("unexpected connectionless packet type: %s\n", str); return 0; } return str; @@ -134,7 +153,7 @@ server_connect (connection_t *con, void *object) if (!(str = expect_packet (net_message, S2C_CONNECTION))) return; - Con_Printf ("connection from %s\n", sv->name); + qtv_printf ("connection from %s\n", sv->name); Netchan_Setup (&sv->netchan, con->address, sv->qport, NC_SEND_QPORT); sv->netchan.outgoing_sequence = 1; sv->connected = 1; @@ -162,17 +181,17 @@ server_challenge (connection_t *con, void *object) for (i = 1; i < Cmd_Argc (); i++) { str = Cmd_Argv (i); if (!strcmp ("QF", str)) { - Con_Printf ("QuakeForge server detected\n"); + qtv_printf ("QuakeForge server detected\n"); } else if (!strcmp ("qtv", str)) { - Con_Printf ("QTV capable server\n"); + qtv_printf ("QTV capable server\n"); qtv = str; } else { - Con_Printf ("%s\n", str); + qtv_printf ("%s\n", str); } } if (!qtv) { - Con_Printf ("%s can't handle qtv.\n", sv->name); + qtv_printf ("%s can't handle qtv.\n", sv->name); Hash_Del (servers, sv->name); Hash_Free (servers, sv); return; @@ -205,17 +224,17 @@ sv_new_f (void) netadr_t adr; if (Cmd_Argc () != 3) { - Con_Printf ("Usage: sv_new
\n"); + qtv_printf ("Usage: sv_new
\n"); return; } name = Cmd_Argv (1); if (Hash_Find (servers, name)) { - Con_Printf ("sv_new: %s already exists\n", name); + qtv_printf ("sv_new: %s already exists\n", name); return; } address = Cmd_Argv (2); if (!NET_StringToAdr (address, &adr)) { - Con_Printf ("Bad server address\n"); + qtv_printf ("Bad server address\n"); return; } if (!adr.port) @@ -245,12 +264,12 @@ sv_del_f (void) server_t *sv; if (Cmd_Argc () != 2) { - Con_Printf ("Usage: sv_del \n"); + qtv_printf ("Usage: sv_del \n"); return; } name = Cmd_Argv (1); if (!(sv = Hash_Del (servers, name))) { - Con_Printf ("sv_new: %s unkown\n", name); + qtv_printf ("sv_new: %s unkown\n", name); return; } Hash_Free (servers, sv); @@ -266,13 +285,13 @@ sv_list_f (void) for (l = list, count = 0; *l; l++) count++; if (!count) { - Con_Printf ("no servers\n"); + qtv_printf ("no servers\n"); return; } qsort (list, count, sizeof (*list), server_compare); for (l = list; *l; l++) { sv = *l; - Con_Printf ("%-20s %s(%s)\n", sv->name, sv->address, + qtv_printf ("%-20s %s(%s)\n", sv->name, sv->address, NET_AdrToString (sv->adr)); } } diff --git a/qw/include/server.h b/qw/include/server.h index aa63e0f70..590de2d9f 100644 --- a/qw/include/server.h +++ b/qw/include/server.h @@ -398,6 +398,8 @@ extern struct cvar_s *sv_highchars; extern struct cvar_s *sv_mintic, *sv_maxtic; extern struct cvar_s *sv_maxspeed; +extern struct cvar_s *timeout; + extern netadr_t master_adr[MAX_MASTERS]; // address of the master server extern struct cvar_s *spawn; diff --git a/qw/include/sv_qtv.h b/qw/include/sv_qtv.h index b51f2a031..41be49102 100644 --- a/qw/include/sv_qtv.h +++ b/qw/include/sv_qtv.h @@ -32,6 +32,9 @@ #ifndef __sv_qtv_h #define __sv_qtv_h -void SV_qtvConnect (void); +struct info_s; +void SV_qtvConnect (int qport, struct info_s *info); +int SV_qtvPacket (int qport); +void SV_qtvCheckTimeouts (void); #endif//__sv_qtv_h diff --git a/qw/source/cl_parse.c b/qw/source/cl_parse.c index 5f4318f31..38c040dc2 100644 --- a/qw/source/cl_parse.c +++ b/qw/source/cl_parse.c @@ -1207,7 +1207,7 @@ CL_ParseServerMessage (void) cmd = MSG_ReadByte (net_message); if (cmd == -1) { - net_message->readcount++; // so the EOM showner has the right + net_message->readcount++; // so the EOM SHOWNET has the right // value SHOWNET ("END OF MESSAGE"); break; diff --git a/qw/source/sv_main.c b/qw/source/sv_main.c index 03121fbf3..677a8e9e4 100644 --- a/qw/source/sv_main.c +++ b/qw/source/sv_main.c @@ -769,7 +769,7 @@ SVC_DirectConnect (void) info_t *userinfo = 0; const char *s; client_t *cl, *newcl; - int challenge, qport, version, i; + int challenge, qport, version, i, qtv = 0; netadr_t adr; qboolean spectator; @@ -778,16 +778,15 @@ SVC_DirectConnect (void) s = Cmd_Argv (1); if (!strcmp (s, "qtv")) { - SV_qtvConnect (); - return; - } - - version = atoi (s); - if (version != PROTOCOL_VERSION) { - Netchan_OutOfBandPrint (net_from, "%c\nServer is version %s.\n", - A2C_PRINT, QW_VERSION); - SV_Printf ("* rejected connect from version %i\n", version); - return; + qtv = 1; + } else { + version = atoi (s); + if (version != PROTOCOL_VERSION) { + Netchan_OutOfBandPrint (net_from, "%c\nServer is version %s.\n", + A2C_PRINT, QW_VERSION); + SV_Printf ("* rejected connect from version %i\n", version); + return; + } } qport = atoi (Cmd_Argv (2)); @@ -821,6 +820,11 @@ SVC_DirectConnect (void) return; } + if (qtv) { + SV_qtvConnect (qport, userinfo); + return; + } + s = Info_ValueForKey (userinfo, "*qf_version"); if ((!s[0]) || sv_minqfversion->string[0]) { // kick old clients? if (ver_compare (s, sv_minqfversion->string) < 0) { @@ -1803,6 +1807,9 @@ SV_ReadPackets (void) if (i != MAX_CLIENTS) continue; + if (SV_qtvPacket (qport)) + continue; + // packet is not from a known client // SV_Printf ("%s:sequenced packet without connection\n", // NET_AdrToString (net_from)); @@ -1846,6 +1853,7 @@ SV_CheckTimeouts (void) svs.num_clients--; } } + SV_qtvCheckTimeouts (); if (sv.paused && !nclients) { // nobody left, unpause the server SV_TogglePause ("Pause released since no players are left.\n"); diff --git a/qw/source/sv_qtv.c b/qw/source/sv_qtv.c index f544e9b2d..6a3b751d8 100644 --- a/qw/source/sv_qtv.c +++ b/qw/source/sv_qtv.c @@ -35,15 +35,105 @@ static __attribute__ ((unused)) const char rcsid[] = "$Id$"; #include "QF/cmd.h" +#include "QF/hash.h" +#include "QF/info.h" #include "server.h" #include "sv_qtv.h" typedef struct { + netchan_t netchan; + backbuf_t backbuf; + info_t *info; + info_key_t *name_key; } sv_qtv_t; -void -SV_qtvConnect (void) +#define MAX_PROXIES 2 + +static sv_qtv_t proxies[MAX_PROXIES]; + +static sv_qtv_t * +alloc_proxy (void) { - SV_Printf ("QTV proxy connection: %d %s\n", Cmd_Argc (), Cmd_Args (1)); + int i; + + for (i = 0; i < MAX_PROXIES; i++) { + if (!proxies[i].info) + return proxies; + } + return 0; +} + +void +SV_qtvConnect (int qport, info_t *info) +{ + sv_qtv_t *proxy; + + SV_Printf ("QTV proxy connection: %d %s\n", Cmd_Argc (), Cmd_Args (1)); + SV_Printf ("qport: %d\n", qport); + + if (!(proxy = alloc_proxy ())) { + SV_Printf ("%s:full proxy connect\n", NET_AdrToString (net_from)); + Netchan_OutOfBandPrint (net_from, "%c\nserver is full\n\n", A2C_PRINT); + return; + } + proxy->info = info; + while (!(proxy->name_key = Hash_Find (proxy->info->tab, "name"))) + Info_SetValueForKey (proxy->info, "name", "\"unnamed proxy\"", 1); + + Netchan_Setup (&proxy->netchan, net_from, qport, NC_READ_QPORT); + proxy->backbuf.netchan = &proxy->netchan; + proxy->backbuf.name = proxy->name_key->value; + + Netchan_OutOfBandPrint (net_from, "%c", S2C_CONNECTION); +} + +int +SV_qtvPacket (int qport) +{ + int i; + + for (i = 0; i < MAX_PROXIES; i++) { + if (!proxies[i].info) + continue; + if (!NET_CompareBaseAdr (net_from, proxies[i].netchan.remote_address)) + continue; + if (proxies[i].netchan.qport != qport) + continue; + if (proxies[i].netchan.remote_address.port != net_from.port) { + Con_DPrintf ("SV_ReadPackets: fixing up a translated port\n"); + proxies[i].netchan.remote_address.port = net_from.port; + } + Con_Printf ("boo\n"); + if (Netchan_Process (&proxies[i].netchan)) { + // this is a valid, sequenced packet, so process it + svs.stats.packets++; + } + Netchan_Transmit (&proxies[i].netchan, 0, 0); + return 1; + } + return 0; +} + +void +SV_qtvCheckTimeouts (void) +{ + int i; + float droptime; + sv_qtv_t *proxy; + + droptime = realtime - timeout->value; + + for (i = 0; i < MAX_PROXIES; i++) { + proxy = proxies + i; + if (proxy->info) { + if (proxy->netchan.last_received < droptime) { + SV_Printf ("%s timed out\n", proxy->name_key->value); + MSG_WriteByte (&proxy->netchan.message, svc_disconnect); + Netchan_Transmit (&proxy->netchan, 0, 0); + Info_Destroy (proxy->info); + proxy->info = 0; + } + } + } }