diff --git a/include/Makefile.am b/include/Makefile.am index 0a0189b90..2fae3f241 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -12,6 +12,8 @@ EXTRA_DIST = asm_i386.h alsa_funcs_list.h adivtab.h anorm_dots.h anorms.h \ r_local.h r_screen.h r_shared.h rua_internal.h sbar.h skin_stencil.h \ snd_render.h varrays.h vgamodes.h view.h vregset.h winquake.h world.h \ \ + qw/protocol.h \ + \ win32/fnmatch.h \ \ win32/resources/icon1.ico win32/resources/quakeforge.rc \ diff --git a/qw/include/protocol.h b/include/qw/protocol.h similarity index 100% rename from qw/include/protocol.h rename to include/qw/protocol.h diff --git a/qtv/include/connection.h b/qtv/include/connection.h index 0056ddef2..fbfd4b6b5 100644 --- a/qtv/include/connection.h +++ b/qtv/include/connection.h @@ -37,12 +37,13 @@ typedef struct connection_s { netadr_t address; void *object; - void (*handler) (void *obj); + void (*handler) (struct connection_s *con, void *obj); } connection_t; void Connection_Init (void); -void Connection_Add (netadr_t *address, void *object, void (*handler)(void*)); -void Connection_Del (netadr_t *address); +connection_t *Connection_Add (netadr_t *address, void *object, + void (*handler)(connection_t *, void *)); +void Connection_Del (connection_t *con); connection_t *Connection_Find (netadr_t *address); #endif//__connection_h diff --git a/qtv/include/server.h b/qtv/include/server.h index ef45b0356..c5612a772 100644 --- a/qtv/include/server.h +++ b/qtv/include/server.h @@ -37,6 +37,10 @@ typedef struct server_s { const char *name; const char *address; + int qport; + struct info_s *info; + struct connection_s *con; + netadr_t adr; netchan_t netchan; } server_t; diff --git a/qtv/source/client.c b/qtv/source/client.c index 99bf76dd8..6ca62f6b5 100644 --- a/qtv/source/client.c +++ b/qtv/source/client.c @@ -58,7 +58,7 @@ Client_Init (void) } static void -client_handler (void *object) +client_handler (connection_t *con, void *object) { client_t *cl = (client_t *) object; byte d[1]; diff --git a/qtv/source/connection.c b/qtv/source/connection.c index a5e349e58..8cd1fb1e1 100644 --- a/qtv/source/connection.c +++ b/qtv/source/connection.c @@ -57,8 +57,11 @@ static unsigned long connection_get_hash (void *_c, void *unused) { connection_t *c = (connection_t *) _c; + unsigned long hash; - return Hash_Buffer (c->address.ip, sizeof (c->address.ip)); + hash = Hash_Buffer (c->address.ip, sizeof (c->address.ip)); + hash ^= c->address.port; + return hash; } static int @@ -67,7 +70,7 @@ connection_compare (void *_c1, void *_c2, void *unused) connection_t *c1 = (connection_t *) _c1; connection_t *c2 = (connection_t *) _c2; - return NET_CompareBaseAdr (c1->address, c2->address); + return NET_CompareAdr (c1->address, c2->address); } void @@ -77,8 +80,9 @@ Connection_Init (void) Hash_SetHashCompare (connections, connection_get_hash, connection_compare); } -void -Connection_Add (netadr_t *address, void *object, void (*handler)(void*)) +connection_t * +Connection_Add (netadr_t *address, void *object, + void (*handler)(connection_t *, void *)) { connection_t *con; @@ -89,15 +93,13 @@ Connection_Add (netadr_t *address, void *object, void (*handler)(void*)) if (Hash_FindElement (connections, con)) Sys_Error ("duplicate connection"); Hash_AddElement (connections, con); + return con; } void -Connection_Del (netadr_t *address) +Connection_Del (connection_t *con) { - connection_t con; - - con.address = *address; - Hash_DelElement (connections, &con); + Hash_DelElement (connections, con); } connection_t * diff --git a/qtv/source/qtv.c b/qtv/source/qtv.c index 644d0f3ca..3a928d743 100644 --- a/qtv/source/qtv.c +++ b/qtv/source/qtv.c @@ -58,6 +58,8 @@ static __attribute__ ((unused)) const char rcsid[] = #include "QF/va.h" #include "QF/zone.h" +#include "qw/protocol.h" + #include "client.h" #include "compat.h" #include "connection.h" @@ -65,12 +67,6 @@ static __attribute__ ((unused)) const char rcsid[] = #include "server.h" #define PORT_QTV 27501 -#define A2A_PING 'k' -#define A2A_ACK 'l' -#define A2C_PRINT 'n' -#define S2C_CHALLENGE 'c' -#define S2C_CONNECTION 'j' -#define PROTOCOL_VERSION 28 typedef enum { RD_NONE, @@ -356,6 +352,17 @@ qtv_client_connect (void) Netchan_OutOfBandPrint (net_from, "%c", S2C_CONNECTION); } +static void +qtv_server_packet (void) +{ + connection_t *con; + + if (!(con = Connection_Find (&net_from))) + return; + if (con->handler) + con->handler (con, con->object); +} + static void qtv_connectionless_packet (void) { @@ -369,8 +376,7 @@ qtv_connectionless_packet (void) cmd_args = qtv_args; cmd = qtv_args->argv[0]->str; - if (!strcmp (cmd, "ping") - || (cmd[0] == A2A_PING && (cmd[1] == 0 || cmd[1] == '\n'))) { + if (!strcmp (cmd, "ping")) { qtv_ping (); } else if (!strcmp (cmd, "status")) { qtv_status (); @@ -378,7 +384,23 @@ qtv_connectionless_packet (void) qtv_getchallenge (); } else if (!strcmp (cmd, "connect")) { qtv_client_connect (); + } else if (cmd[0]) { + switch (cmd[0]) { + default: + goto bad_packet; + case A2C_PRINT: + Con_Printf ("%s", MSG_ReadString (net_message)); + break; + case A2A_PING: + qtv_ping (); + break; + case S2C_CHALLENGE: + case S2C_CONNECTION: + qtv_server_packet (); + break; + } } else { +bad_packet: Con_Printf ("bad connectionless packet from %s:\n%s\n", NET_AdrToString (net_from), str); } @@ -390,13 +412,11 @@ qtv_read_packets (void) connection_t *con; while (NET_GetPacket ()) { - if (*(int *) net_message->message->data == -1) { + if ((con = Connection_Find (&net_from))) { + con->handler (con, con->object); + } else if (*(int *) net_message->message->data == -1) { qtv_connectionless_packet (); - continue; } - - if ((con = Connection_Find (&net_from))) - con->handler (con->object); } } diff --git a/qtv/source/server.c b/qtv/source/server.c index bde54306a..207044dac 100644 --- a/qtv/source/server.c +++ b/qtv/source/server.c @@ -46,8 +46,17 @@ static __attribute__ ((unused)) const char rcsid[] = #include "QF/cmd.h" #include "QF/console.h" +#include "QF/dstring.h" #include "QF/hash.h" +#include "QF/info.h" +#include "QF/msg.h" +#include "QF/qendian.h" +#include "QF/sys.h" +#include "QF/va.h" +#include "qw/protocol.h" + +#include "connection.h" #include "server.h" static hashtab_t *servers; @@ -61,6 +70,11 @@ server_get_key (void *sv, void *unused) static void server_free (void *_sv, void *unused) { + server_t *sv = (server_t *) _sv; + static byte final[6] = {clc_stringcmd, 'd', 'r', 'o', 'p', 0}; + + Netchan_Transmit (&sv->netchan, 6, final); + Connection_Del (sv->con); } static int @@ -69,12 +83,93 @@ server_compare (const void *a, const void *b) return strcmp ((*(server_t **) a)->name, (*(server_t **) b)->name); } +static void +server_handler (connection_t *con, void *object) +{ + server_t *sv = (server_t *) object; + byte d[1] = { clc_nop }; + + Con_Printf ("hi\n"); + Netchan_Transmit (&sv->netchan, 1, d); +} + +static inline const char * +expect_packet (qmsg_t *msg, int type) +{ + const char *str; + int seq; + + MSG_BeginReading (net_message); + seq = MSG_ReadLong (net_message); + if (seq != -1) { + Con_Printf ("unexpected connected packet\n"); + return 0; + } + str = MSG_ReadString (net_message); + if (str[0] != type) { + Con_Printf ("unexpected connectionless packet type: %s\n", str); + return 0; + } + return str; +} + +static void +server_connect (connection_t *con, void *object) +{ + server_t *sv = (server_t *) object; + sizebuf_t *msg = &sv->netchan.message; + const char *str; + + if (!(str = expect_packet (net_message, S2C_CONNECTION))) + return; + + Con_Printf ("connection from %s\n", sv->name); + Netchan_Setup (&sv->netchan, con->address, sv->qport, NC_SEND_QPORT); + sv->netchan.outgoing_sequence = 1; + MSG_WriteByte (msg, clc_stringcmd); + MSG_WriteString (msg, "new"); + Netchan_Transmit (&sv->netchan, 0, 0); + con->handler = server_handler; +} + +static void +server_challenge (connection_t *con, void *object) +{ + server_t *sv = (server_t *) object; + const char *str; + int challenge; + dstring_t *data; + + if (!(str = expect_packet (net_message, S2C_CHALLENGE))) + return; + + challenge = atoi (str + 1); + Con_Printf ("%d %s\n", challenge, Cmd_Argv (1)); + + data = dstring_new (); + dsprintf (data, "%c%c%c%cconnect %i %i %i \"%s\"\n", 255, 255, 255, 255, + PROTOCOL_VERSION, sv->qport, challenge, + Info_MakeString (sv->info, 0)); + Netchan_SendPacket (strlen (data->str), data->str, net_from); + dstring_delete (data); + con->handler = server_connect; +} + +static void +server_getchallenge (connection_t *con, server_t *sv) +{ + static const char *getchallenge = "\377\377\377\377getchallenge\n"; + + Netchan_SendPacket (strlen (getchallenge), (void *) getchallenge, sv->adr); +} + static void sv_new_f (void) { const char *name; const char *address; server_t *sv; + netadr_t adr; if (Cmd_Argc () != 3) { Con_Printf ("Usage: sv_new
\n"); @@ -86,10 +181,28 @@ sv_new_f (void) return; } address = Cmd_Argv (2); + if (!NET_StringToAdr (address, &adr)) { + Con_Printf ("Bad server address\n"); + return; + } + if (!adr.port) + adr.port = BigShort (27500); + sv = calloc (1, sizeof (server_t)); sv->name = strdup (name); sv->address = strdup (address); + sv->adr = adr; + sv->qport = qport->int_val; + sv->info = Info_ParseString ("", MAX_INFO_STRING, 0); + Info_SetValueForStarKey (sv->info, "*ver", + va ("%s QTV %s", QW_VERSION, VERSION), 0); + Info_SetValueForStarKey (sv->info, "*qsg_version", QW_QSG_VERSION, 0); + Info_SetValueForKey (sv->info, "name", "QTV Proxy", 0); Hash_Add (servers, sv); + + sv->con = Connection_Add (&adr, sv, server_challenge); + + server_getchallenge (sv->con, sv); } static void @@ -126,13 +239,21 @@ sv_list_f (void) qsort (list, count, sizeof (*list), server_compare); for (l = list; *l; l++) { sv = *l; - Con_Printf ("%-20s %s\n", sv->name, sv->address); + Con_Printf ("%-20s %s(%s)\n", sv->name, sv->address, + NET_AdrToString (sv->adr)); } } +static void +server_shutdown (void) +{ + Hash_FlushTable (servers); +} + void Server_Init (void) { + Sys_RegisterShutdown (server_shutdown); servers = Hash_NewTable (61, server_get_key, server_free, 0); Cmd_AddCommand ("sv_new", sv_new_f, "Add a new server"); Cmd_AddCommand ("sv_del", sv_del_f, "Remove an existing server"); diff --git a/qw/include/Makefile.am b/qw/include/Makefile.am index d8e3ca166..72953f35e 100644 --- a/qw/include/Makefile.am +++ b/qw/include/Makefile.am @@ -4,5 +4,5 @@ AUTOMAKE_OPTIONS= foreign EXTRA_DIST = \ bothdefs.h cl_cam.h cl_chat.h cl_demo.h cl_ents.h cl_input.h \ cl_main.h cl_parse.h cl_pred.h cl_skin.h cl_slist.h cl_tent.h \ - client.h crudefile.h game.h host.h msg_ucmd.h pmove.h protocol.h \ + client.h crudefile.h game.h host.h msg_ucmd.h pmove.h \ server.h sv_gib.h sv_demo.h sv_pr_cmds.h sv_pr_qwe.h sv_progs.h diff --git a/qw/include/cl_cam.h b/qw/include/cl_cam.h index 2d9c6f1ae..51806fcc5 100644 --- a/qw/include/cl_cam.h +++ b/qw/include/cl_cam.h @@ -34,7 +34,7 @@ // headers they might need -#include "protocol.h" +#include "qw/protocol.h" #define CAM_NONE 0 #define CAM_TRACK 1 diff --git a/qw/include/cl_demo.h b/qw/include/cl_demo.h index 5c6daa612..6a1cb32fb 100644 --- a/qw/include/cl_demo.h +++ b/qw/include/cl_demo.h @@ -30,7 +30,7 @@ #define _CL_DEMO_H #include "QF/qtypes.h" -#include "protocol.h" +#include "qw/protocol.h" void CL_StopPlayback (void); qboolean CL_GetMessage (void); diff --git a/qw/include/cl_input.h b/qw/include/cl_input.h index cb6e6e6fa..bbe4c10a4 100644 --- a/qw/include/cl_input.h +++ b/qw/include/cl_input.h @@ -31,7 +31,7 @@ #include "QF/input.h" -#include "protocol.h" +#include "qw/protocol.h" void CL_Input_Init (void); void CL_Input_Init_Cvars (void); diff --git a/qw/include/client.h b/qw/include/client.h index be9797b05..6e3ea49d6 100644 --- a/qw/include/client.h +++ b/qw/include/client.h @@ -35,7 +35,7 @@ #include "QF/zone.h" #include "netchan.h" -#include "protocol.h" +#include "qw/protocol.h" #include "r_local.h" #include "QF/render.h" diff --git a/qw/include/pmove.h b/qw/include/pmove.h index ac22d0ff1..0328dc13c 100644 --- a/qw/include/pmove.h +++ b/qw/include/pmove.h @@ -29,7 +29,7 @@ #ifndef _PMOVE_H #define _PMOVE_H -#include "protocol.h" +#include "qw/protocol.h" #include "QF/mathlib.h" #include "QF/model.h" diff --git a/qw/include/server.h b/qw/include/server.h index 95cf68342..f38a5c694 100644 --- a/qw/include/server.h +++ b/qw/include/server.h @@ -39,7 +39,7 @@ #include "host.h" #include "netchan.h" -#include "protocol.h" +#include "qw/protocol.h" #define QW_SERVER diff --git a/qw/source/cl_parse.c b/qw/source/cl_parse.c index dd3532fbc..f6ddd1348 100644 --- a/qw/source/cl_parse.c +++ b/qw/source/cl_parse.c @@ -74,7 +74,7 @@ static __attribute__ ((unused)) const char rcsid[] = #include "compat.h" #include "host.h" #include "pmove.h" -#include "protocol.h" +#include "qw/protocol.h" #include "sbar.h" #include "view.h" diff --git a/qw/source/master.c b/qw/source/master.c index d52badb6b..020119677 100644 --- a/qw/source/master.c +++ b/qw/source/master.c @@ -71,7 +71,7 @@ static __attribute__ ((unused)) const char rcsid[] = #include #include -#include "protocol.h" +#include "qw/protocol.h" static void __attribute__ ((format (printf, 1, 2))) ma_log (const char *fmt, ...); diff --git a/qw/source/msg_ucmd.c b/qw/source/msg_ucmd.c index 27954a2c2..83aeff145 100644 --- a/qw/source/msg_ucmd.c +++ b/qw/source/msg_ucmd.c @@ -44,7 +44,7 @@ static __attribute__ ((unused)) const char rcsid[] = #include "msg_ucmd.h" #include "netchan.h" -#include "protocol.h" +#include "qw/protocol.h" struct usercmd_s nullcmd; diff --git a/qw/source/net_packetlog.c b/qw/source/net_packetlog.c index bee1b6ede..b9bba2cdd 100644 --- a/qw/source/net_packetlog.c +++ b/qw/source/net_packetlog.c @@ -57,7 +57,7 @@ static __attribute__ ((unused)) const char rcsid[] = #include "compat.h" #include "netchan.h" -#include "protocol.h" +#include "qw/protocol.h" #include "server.h" cvar_t *net_packetlog; @@ -818,7 +818,7 @@ Parse_Client_Packet (int has_sequence) Net_LogPrintf ("\nSeq: %ld Ack: %ld ", seq1 & 0x7FFFFFFF, seq2 & 0x7FFFFFFF); - Net_LogPrintf ("QP: %u\n", MSG_ReadShort (&packet)); + Net_LogPrintf ("QP: %u\n", MSG_ReadShort (&packet) & 0xFFFF); } while (1) { diff --git a/qw/source/sv_user.c b/qw/source/sv_user.c index 1f16832c5..3e8404529 100644 --- a/qw/source/sv_user.c +++ b/qw/source/sv_user.c @@ -113,7 +113,7 @@ SV_New_f (void *unused) if (host_client->state == cs_spawned) return; - +SV_Printf ("SV_New_f\n"); host_client->state = cs_connected; host_client->connection_started = realtime;