first version with dtls support. disabled for now.

schannel (ie: windows native) works as a client, not a server.
gnutls provides both client+server support. servers need to load a pre-generated cert from disk.
tweaked gamepads to actually work in the web target.
tweak gamepads a bit. added gp_* bind aliases. xinput+sdl+web should all use the same key mappings.
finally added the itemtimer glsl.
tweaked software renderer to not be quite so buggy, but you probably won't realise that if you try it.
disabled the ill-fated QWOVERQ3 feature.
don't do the oldorigin thing in quakeworld mods. hopefully this'll fix cspree's weird stuck-in-floor issue.
dpp7 is buggy serverside. disabled for now. I'm part way through rewriting its deltas.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5103 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2017-05-18 10:24:09 +00:00
parent e5db7c32ba
commit 5d2ff1286d
47 changed files with 2071 additions and 559 deletions

View File

@ -2904,7 +2904,7 @@ void CL_AddDecal(shader_t *shader, vec3_t origin, vec3_t up, vec3_t side, vec3_t
cl_numstris--;
}
void R_AddItemTimer(vec3_t shadoworg, float yaw, float radius, float percent)
void R_AddItemTimer(vec3_t shadoworg, float yaw, float radius, float percent, vec3_t rgb)
{
vec3_t eang;
shader_t *s;
@ -2963,7 +2963,7 @@ void R_AddItemTimer(vec3_t shadoworg, float yaw, float radius, float percent)
}
ctx.t = t;
Vector4Set(ctx.rgbavalue, 0.1, 0.1, 0.1, percent);
Vector4Set(ctx.rgbavalue, rgb[0], rgb[1], rgb[2], percent);
Mod_ClipDecal(cl.worldmodel, shadoworg, ctx.axis[0], ctx.axis[1], ctx.axis[2], radius, 0,0, CL_AddDecal_Callback, &ctx);
if (!t->numidx)
cl_numstris--;
@ -3781,7 +3781,7 @@ void CL_LinkPacketEntities (void)
if (le->sequence != cl.lerpentssequence)
continue;
}
R_AddItemTimer(timer->origin, cl.time*90 + timer->origin[0] + timer->origin[1] + timer->origin[2], timer->radius, (cl.time - timer->start) / timer->duration);
R_AddItemTimer(timer->origin, cl.time*90 + timer->origin[0] + timer->origin[1] + timer->origin[2], timer->radius, (cl.time - timer->start) / timer->duration, timer->rgb);
}
}

View File

@ -245,6 +245,15 @@ static struct
qboolean trying;
qboolean istransfer; //ignore the user's desired server (don't change connect.adr).
netadr_t adr; //address that we're trying to transfer to. FIXME: support multiple resolved addresses, eg both ::1 AND 127.0.0.1
#ifdef HAVE_DTLS
enum
{
DTLS_DISABLE,
DTLS_TRY,
DTLS_REQUIRE,
DTLS_ACTIVE
} dtlsupgrade;
#endif
int mtu;
unsigned int compresscrc;
int protocol; //nq/qw/q2/q3. guessed based upon server replies
@ -528,8 +537,6 @@ void CL_SendConnectPacket (netadr_t *to, int mtu,
int fteprotextsupported=0;
int fteprotextsupported2=0;
#endif
int clients;
int c;
char *a;
// JACK: Fixed bug where DNS lookups would cause two connects real fast
@ -585,6 +592,7 @@ void CL_SendConnectPacket (netadr_t *to, int mtu,
NET_AdrToString(data, sizeof(data), to);
Cvar_ForceSet(&cl_serveraddress, data);
// Info_SetValueForStarKey (cls.userinfo, "*ip", data, MAX_INFO_STRING);
if (!NET_IsClientLegal(to))
{
@ -606,29 +614,6 @@ void CL_SendConnectPacket (netadr_t *to, int mtu,
if (connectinfo.protocol == CP_QUAKE2 && (connectinfo.subprotocol == PROTOCOL_VERSION_R1Q2 || connectinfo.subprotocol == PROTOCOL_VERSION_Q2PRO))
connectinfo.qport &= 0xff;
// Info_SetValueForStarKey (cls.userinfo, "*ip", NET_AdrToString(adr), MAX_INFO_STRING);
clients = 1;
/*
if (cl_splitscreen.value && (fteprotextsupported & PEXT_SPLITSCREEN))
{
// if (adr.type == NA_LOOPBACK)
clients = cl_splitscreen.value+1;
// else
// Con_Printf("Split screens are still under development\n");
}
if (clients < 1)
clients = 1;
if (clients > MAX_SPLITS)
clients = MAX_SPLITS;
#ifdef Q2CLIENT
if (connectinfo.protocol == CP_QUAKE2) //q2 only supports after-connect seats
clients = 1;
#endif
*/
#ifdef Q3CLIENT
if (connectinfo.protocol == CP_QUAKE3)
{ //q3 requires some very strange things.
@ -639,9 +624,6 @@ void CL_SendConnectPacket (netadr_t *to, int mtu,
Q_snprintfz(data, sizeof(data), "%c%c%c%cconnect", 255, 255, 255, 255);
if (clients>1) //splitscreen 'connect' command specifies the number of userinfos sent.
Q_strncatz(data, va("%i", clients), sizeof(data));
Q_strncatz(data, va(" %i %i %i", connectinfo.subprotocol, connectinfo.qport, connectinfo.challenge), sizeof(data));
//userinfo0 has some twiddles for extensions from other qw engines.
@ -659,8 +641,6 @@ void CL_SendConnectPacket (netadr_t *to, int mtu,
Q_strncatz(data, va("\\*z_ext\\%i", SUPPORTED_Z_EXTENSIONS), sizeof(data));
Q_strncatz(data, "\"", sizeof(data));
for (c = 1; c < clients; c++)
Q_strncatz(data, va(" \"%s\"", cls.userinfo[c]), sizeof(data));
if (connectinfo.protocol == CP_QUAKE2 && connectinfo.subprotocol == PROTOCOL_VERSION_R1Q2)
Q_strncatz(data, va(" %d %d", mtu, 1905), sizeof(data)); //mti, sub-sub-version
@ -721,11 +701,6 @@ char *CL_TryingToConnect(void)
return cls.servername;
}
#ifndef CLIENTONLY
int SV_NewChallenge (void);
client_t *SVC_DirectConnect(void);
#endif
/*
=================
CL_CheckForResend
@ -759,6 +734,7 @@ void CL_CheckForResend (void)
return; //erk?
connectinfo.trying = true;
connectinfo.istransfer = false;
connectinfo.adr.prot = NP_DGRAM;
NET_InitClient(true);
@ -1015,6 +991,24 @@ void CL_CheckForResend (void)
SCR_EndLoadingPlaque();
return;
}
#ifdef HAVE_DTLS
if (connectinfo.dtlsupgrade == DTLS_ACTIVE)
{ //if we've already established a dtls connection, stick with it
if (connectinfo.adr.prot == NP_DGRAM)
connectinfo.adr.prot = NP_DTLS;
}
else if (connectinfo.adr.prot == NP_DTLS)
{ //dtls connections start out with regular udp, and upgrade to dtls once its established that the server supports it.
connectinfo.dtlsupgrade = DTLS_REQUIRE;
connectinfo.adr.prot = NP_DGRAM;
}
else
{
//hostname didn't specify dtls. upgrade if we're allowed, but don't mandate it.
//connectinfo.dtlsupgrade = DTLS_TRY;
}
#endif
}
if (!NET_IsClientLegal(&connectinfo.adr))
{
@ -1132,6 +1126,9 @@ void CL_BeginServerConnect(const char *host, int port, qboolean noproxy)
if (!port)
port = cl_defaultport.value;
#ifdef HAVE_DTLS
NET_DTLS_Disconnect(cls.sockets, &connectinfo.adr);
#endif
memset(&connectinfo, 0, sizeof(connectinfo));
connectinfo.trying = true;
connectinfo.defaultport = port;
@ -1148,6 +1145,10 @@ void CL_BeginServerReconnect(void)
Con_TPrintf ("Connect ignored - dedicated. set a renderer first\n");
return;
}
#endif
#ifdef HAVE_DTLS
NET_DTLS_Disconnect(cls.sockets, &connectinfo.adr);
connectinfo.dtlsupgrade = 0;
#endif
connectinfo.trying = true;
connectinfo.istransfer = false;
@ -1553,6 +1554,13 @@ void CL_ClearState (void)
BZ_Free(cl.item_name[i]);
#endif
while (cl.itemtimers)
{
struct itemtimer_s *t = cl.itemtimers;
cl.itemtimers = t->next;
Z_Free(t);
}
{
downloadlist_t *next;
while(cl.downloadlist)
@ -1792,6 +1800,8 @@ void CL_Disconnect_f (void)
connectinfo.trying = false;
NET_CloseClient();
(void)CSQC_UnconnectedInit();
}
@ -2792,6 +2802,9 @@ void CL_ConnectionlessPacket (void)
static netadr_t lastadr;
unsigned int curtime = Sys_Milliseconds();
unsigned long pext = 0, pext2 = 0, huffcrc=0, mtu=0;
#ifdef HAVE_DTLS
qboolean candtls = false;
#endif
s = MSG_ReadString ();
COM_Parse(s);
@ -2888,6 +2901,7 @@ void CL_ConnectionlessPacket (void)
}
#else
Con_Printf("\nUnable to connect to Quake2\n");
return;
#endif
s+=9;
}
@ -2940,31 +2954,65 @@ void CL_ConnectionlessPacket (void)
for(;;)
{
c = MSG_ReadLong ();
int cmd = MSG_ReadLong ();
if (msg_badread)
break;
if (c == PROTOCOL_VERSION_FTE)
pext = MSG_ReadLong ();
else if (c == PROTOCOL_VERSION_FTE2)
pext2 = MSG_ReadLong ();
else if (c == PROTOCOL_VERSION_FRAGMENT)
mtu = MSG_ReadLong ();
else if (c == PROTOCOL_VERSION_VARLENGTH)
if (cmd == PROTOCOL_VERSION_VARLENGTH)
{
int len = MSG_ReadLong();
if (len < 0 || len > 8192)
break;
c = MSG_ReadLong();/*ident*/
MSG_ReadSkip(len); /*payload*/
switch(c)
{
default:
MSG_ReadSkip(len); /*payload*/
break;
}
}
#ifdef HUFFNETWORK
else if (c == PROTOCOL_VERSION_HUFFMAN)
huffcrc = MSG_ReadLong ();
#endif
//else if (c == PROTOCOL_VERSION_...)
else
MSG_ReadLong ();
{
unsigned int l = MSG_ReadLong();
switch(cmd)
{
case PROTOCOL_VERSION_FTE: pext = l; break;
case PROTOCOL_VERSION_FTE2: pext2 = l; break;
case PROTOCOL_VERSION_FRAGMENT: mtu = l; break;
#ifdef HAVE_DTLS
case PROTOCOL_VERSION_DTLSUPGRADE: candtls = l; break; //0:not enabled. 1:use if you want. 2:require it.
#endif
#ifdef HUFFNETWORK
case PROTOCOL_VERSION_HUFFMAN: huffcrc = l; break;
#endif
default:
break;
}
}
}
#ifdef HAVE_DTLS
if (candtls && connectinfo.adr.prot == NP_DGRAM && (connectinfo.dtlsupgrade || candtls > 1))
{
//c2s getchallenge
//s2c c%u\0DTLS=0
//c2s dtlsconnect %u
//s2c dtlsopened
//c2s DTLS(getchallenge)
//DTLS(etc)
//server says it can do tls.
char *pkt = va("%c%c%c%cdtlsconnect %i", 255, 255, 255, 255, connectinfo.challenge);
NET_SendPacket (NS_CLIENT, strlen(pkt), pkt, &net_from);
return;
}
if (connectinfo.dtlsupgrade == DTLS_REQUIRE)
{
connectinfo.trying = false;
Con_Printf("Server does not support/allow dtls. not connecting.\n");
return;
}
#endif
CL_SendConnectPacket (&net_from, mtu, pext, pext2, huffcrc/*, ...*/);
return;
}
@ -3094,13 +3142,37 @@ void CL_ConnectionlessPacket (void)
}
#endif
if (c == 'd') //note - this conflicts with qw masters, our browser uses a different socket.
if (c == 'd'/*M2C_MASTER_REPLY*/)
{
Con_Printf ("d\n");
if (cls.demoplayback != DPB_NONE)
s = MSG_ReadString ();
COM_Parse(s);
if (!strcmp(com_token, "tlsopened"))
{ //server is letting us know that its now listening for a dtls handshake.
#ifdef HAVE_DTLS
Con_Printf ("dtlsopened\n");
if (!NET_CompareAdr(&connectinfo.adr, &net_from))
return;
connectinfo.dtlsupgrade = DTLS_ACTIVE;
connectinfo.adr.prot = NP_DTLS;
if (!NET_DTLS_Create(cls.sockets, &net_from))
Con_Printf ("unable to establish dtls route\n");
#else
Con_Printf ("dtlsopened (unsupported)\n");
#endif
}
else if (*s != '\n')
{ //qw master server list response
Con_Printf ("server ip list\n");
}
else
{
Con_Printf("Disconnect\n");
CL_Disconnect_f();
Con_Printf ("d\n");
if (cls.demoplayback != DPB_NONE)
{
Con_Printf("Disconnect\n");
CL_Disconnect_f();
}
}
return;
}
@ -3169,7 +3241,12 @@ client_connect: //fixme: make function
CL_SendClientCommand(true, "new");
cls.state = ca_connected;
if (cls.netchan.remote_address.type != NA_LOOPBACK)
Con_TPrintf ("Connected.\n");
{
if (cls.netchan.remote_address.prot == NP_DTLS || cls.netchan.remote_address.prot == NP_TLS || cls.netchan.remote_address.prot == NP_WSS)
Con_TPrintf ("Connected (encrypted).\n");
else
Con_TPrintf ("Connected (plain-text).\n");
}
#ifdef QUAKESPYAPI
allowremotecmd = false; // localid required now for remote cmds
#endif
@ -3369,7 +3446,19 @@ void CL_ReadPackets (void)
for(;;)
{
if (!CL_GetMessage())
#ifndef HAVE_DTLS
break;
#else
{
NET_DTLS_Timeouts(cls.sockets);
break;
}
if (*(int *)net_message.data != -1)
if (NET_DTLS_Decode(cls.sockets))
if (!net_message.cursize)
continue;
#endif
#ifdef NQPROT
if (cls.demoplayback == DPB_NETQUAKE)

View File

@ -6109,7 +6109,7 @@ static void CL_ParseItemTimer(void)
atof(Cmd_Argv(2)),
atof(Cmd_Argv(3))};
float radius = atof(Cmd_Argv(4));
//unsigned int rgb = strtoul(Cmd_Argv(5), NULL, 16);
unsigned int rgb = (Cmd_Argc() > 5)?strtoul(Cmd_Argv(5), NULL, 16):0x202020;
// char *timername = Cmd_Argv(6);
unsigned int entnum = strtoul(Cmd_Argv(7), NULL, 0);
struct itemtimer_s *timer;
@ -6139,6 +6139,9 @@ static void CL_ParseItemTimer(void)
timer->entnum = entnum;
timer->start = cl.time;
timer->end = cl.time + timer->duration;
timer->rgb[0] = ((rgb>>16)&0xff)/255.0;
timer->rgb[1] = ((rgb>> 8)&0xff)/255.0;
timer->rgb[2] = ((rgb )&0xff)/255.0;
}
#ifdef PLUGINS

View File

@ -893,6 +893,7 @@ typedef struct
float start;
float duration;
vec3_t origin;
vec3_t rgb;
float radius;
struct itemtimer_s *next;
} *itemtimers;

View File

@ -93,8 +93,8 @@ static cvar_t joy_anglesens[3] =
};
static cvar_t joy_movesens[3] =
{
CVAR("joyforwardsensitivity", "1.0"),
CVAR("joysidesensitivity", "-1.0"),
CVAR("joyforwardsensitivity", "-1.0"),
CVAR("joysidesensitivity", "1.0"),
CVAR("joyupsensitivity", "1.0")
};
//comments on threshholds comes from microsoft's xinput docs.

View File

@ -166,8 +166,12 @@ static struct sdljoy_s *J_DevId(SDL_JoystickID jid)
return NULL;
}
static void J_ControllerAxis(SDL_JoystickID jid, int axis, int value)
{
int axismap[] = {0,1,3,4,2,5};
{ //FIXME: sdlaxis 4 and 5 should trigger K_GP_LEFT_TRIGGER and K_GP_RIGHT_TRIGGER
int axismap[] = {
// SDL_CONTROLLER_AXIS_LEFTX, SDL_CONTROLLER_AXIS_LEFTY, SDL_CONTROLLER_AXIS_RIGHTX,
GPAXIS_LT_RIGHT, GPAXIS_LT_DOWN, GPAXIS_RT_RIGHT,
// SDL_CONTROLLER_AXIS_RIGHTY, SDL_CONTROLLER_AXIS_TRIGGERLEFT,SDL_CONTROLLER_AXIS_TRIGGERRIGHT,
GPAXIS_RT_DOWN, GPAXIS_LT_TRIGGER, GPAXIS_RT_TRIGGER};
struct sdljoy_s *joy = J_DevId(jid);
if (joy && axis < sizeof(axismap)/sizeof(axismap[0]) && joy->qdevid != DEVID_UNSET)
@ -186,41 +190,23 @@ static void J_ControllerButton(SDL_JoystickID jid, int button, qboolean pressed)
{
//controllers have reliable button maps.
//but that doesn't meant that fte has specific k_ names for those buttons, but the mapping should be reliable, at least until they get mapped to proper k_ values.
int buttonmap[] = {
#if 0
//NOTE: DP has specific 'X360' buttons for many of these. of course, its not an exact mapping...
K_X360_A, /*SDL_CONTROLLER_BUTTON_A*/
K_X360_B, /*SDL_CONTROLLER_BUTTON_B*/
K_X360_X, /*SDL_CONTROLLER_BUTTON_X*/
K_X360_Y, /*SDL_CONTROLLER_BUTTON_Y*/
K_X360_BACK, /*SDL_CONTROLLER_BUTTON_BACK*/
K_AUX2, /*SDL_CONTROLLER_BUTTON_GUIDE*/
K_X360_START, /*SDL_CONTROLLER_BUTTON_START*/
K_X360_LEFT_THUMB, /*SDL_CONTROLLER_BUTTON_LEFTSTICK*/
K_X360_RIGHT_THUMB, /*SDL_CONTROLLER_BUTTON_RIGHTSTICK*/
K_X360_LEFT_SHOULDER, /*SDL_CONTROLLER_BUTTON_LEFTSHOULDER*/
K_X360_RIGHT_SHOULDER, /*SDL_CONTROLLER_BUTTON_RIGHTSHOULDER*/
K_X360_DPAD_UP, /*SDL_CONTROLLER_BUTTON_DPAD_UP*/
K_X360_DPAD_DOWN, /*SDL_CONTROLLER_BUTTON_DPAD_DOWN*/
K_X360_DPAD_LEFT, /*SDL_CONTROLLER_BUTTON_DPAD_LEFT*/
K_X360_DPAD_RIGHT /*SDL_CONTROLLER_BUTTON_DPAD_RIGHT*/
#else
K_JOY1, /*SDL_CONTROLLER_BUTTON_A*/
K_JOY2, /*SDL_CONTROLLER_BUTTON_B*/
K_JOY3, /*SDL_CONTROLLER_BUTTON_X*/
K_JOY4, /*SDL_CONTROLLER_BUTTON_Y*/
K_AUX1, /*SDL_CONTROLLER_BUTTON_BACK*/
K_AUX2, /*SDL_CONTROLLER_BUTTON_GUIDE*/
K_AUX3, /*SDL_CONTROLLER_BUTTON_START*/
K_AUX4, /*SDL_CONTROLLER_BUTTON_LEFTSTICK*/
K_AUX5, /*SDL_CONTROLLER_BUTTON_RIGHTSTICK*/
K_AUX6, /*SDL_CONTROLLER_BUTTON_LEFTSHOULDER*/
K_AUX7, /*SDL_CONTROLLER_BUTTON_RIGHTSHOULDER*/
K_AUX8, /*SDL_CONTROLLER_BUTTON_DPAD_UP*/
K_AUX9, /*SDL_CONTROLLER_BUTTON_DPAD_DOWN*/
K_AUX10, /*SDL_CONTROLLER_BUTTON_DPAD_LEFT*/
K_AUX11 /*SDL_CONTROLLER_BUTTON_DPAD_RIGHT*/
#endif
int buttonmap[] =
{
K_GP_A, /*SDL_CONTROLLER_BUTTON_A*/
K_GP_B, /*SDL_CONTROLLER_BUTTON_B*/
K_GP_X, /*SDL_CONTROLLER_BUTTON_X*/
K_GP_Y, /*SDL_CONTROLLER_BUTTON_Y*/
K_GP_BACK, /*SDL_CONTROLLER_BUTTON_BACK*/
K_GP_GUIDE, /*SDL_CONTROLLER_BUTTON_GUIDE*/
K_GP_START, /*SDL_CONTROLLER_BUTTON_START*/
K_GP_LEFT_THUMB, /*SDL_CONTROLLER_BUTTON_LEFTSTICK*/
K_GP_RIGHT_THUMB, /*SDL_CONTROLLER_BUTTON_RIGHTSTICK*/
K_GP_LEFT_SHOULDER, /*SDL_CONTROLLER_BUTTON_LEFTSHOULDER*/
K_GP_RIGHT_SHOULDER, /*SDL_CONTROLLER_BUTTON_RIGHTSHOULDER*/
K_GP_DPAD_UP, /*SDL_CONTROLLER_BUTTON_DPAD_UP*/
K_GP_DPAD_DOWN, /*SDL_CONTROLLER_BUTTON_DPAD_DOWN*/
K_GP_DPAD_LEFT, /*SDL_CONTROLLER_BUTTON_DPAD_LEFT*/
K_GP_DPAD_RIGHT /*SDL_CONTROLLER_BUTTON_DPAD_RIGHT*/
};
struct sdljoy_s *joy = J_DevId(jid);
@ -721,10 +707,10 @@ static unsigned int tbl_sdltoquake[] =
0,//K_NUMLOCK, //SDLK_NUMLOCK = 300,
K_CAPSLOCK, //SDLK_CAPSLOCK = 301,
0,//K_SCROLLOCK,//SDLK_SCROLLOCK= 302,
K_SHIFT, //SDLK_RSHIFT = 303,
K_SHIFT, //SDLK_LSHIFT = 304,
K_CTRL, //SDLK_RCTRL = 305,
K_CTRL, //SDLK_LCTRL = 306,
K_RSHIFT, //SDLK_RSHIFT = 303,
K_LSHIFT, //SDLK_LSHIFT = 304,
K_RCTRL, //SDLK_RCTRL = 305,
K_LCTRL, //SDLK_LCTRL = 306,
K_RALT, //SDLK_RALT = 307,
K_LALT, //SDLK_LALT = 308,
0, //SDLK_RMETA = 309,

View File

@ -357,6 +357,7 @@ static void INS_HideMouse (void)
//scan for an unused device id for joysticks (now that something was pressed).
static int Joy_AllocateDevID(void)
{
extern cvar_t cl_splitscreen;
int id = 0, j;
for (id = 0; ; id++)
{
@ -366,12 +367,17 @@ static int Joy_AllocateDevID(void)
break;
}
if (j == joy_count)
{
if (id > cl_splitscreen.ival && !*cl_splitscreen.string)
cl_splitscreen.ival = id;
return id;
}
}
}
#ifdef USINGRAWINPUT
static int Mouse_AllocateDevID(void)
{
extern cvar_t cl_splitscreen;
int id = 0, j;
for (id = 0; ; id++)
{
@ -381,11 +387,16 @@ static int Mouse_AllocateDevID(void)
break;
}
if (j == rawmicecount)
{
if (id > cl_splitscreen.ival && !*cl_splitscreen.string)
cl_splitscreen.ival = id;
return id;
}
}
}
static int Keyboard_AllocateDevID(void)
{
extern cvar_t cl_splitscreen;
int id = 0, j;
for (id = 0; ; id++)
{
@ -395,7 +406,11 @@ static int Keyboard_AllocateDevID(void)
break;
}
if (j == rawkbdcount)
{
if (id > cl_splitscreen.ival && !*cl_splitscreen.string)
cl_splitscreen.ival = id;
return id;
}
}
}
#endif
@ -1817,26 +1832,27 @@ void INS_Commands (void)
static const int xinputjbuttons[] =
{
K_UPARROW, //XINPUT_GAMEPAD_DPAD_UP
K_DOWNARROW, //XINPUT_GAMEPAD_DPAD_DOWN
K_LEFTARROW, //XINPUT_GAMEPAD_DPAD_LEFT
K_RIGHTARROW, //XINPUT_GAMEPAD_DPAD_RIGHT
K_AUX5, //XINPUT_GAMEPAD_START
K_AUX6, //XINPUT_GAMEPAD_BACK
K_AUX3, //XINPUT_GAMEPAD_LEFT_THUMB
K_AUX4, //XINPUT_GAMEPAD_RIGHT_THUMB
K_GP_DPAD_UP,
K_GP_DPAD_DOWN,
K_GP_DPAD_LEFT,
K_GP_DPAD_RIGHT,
K_GP_START,
K_GP_BACK,
K_GP_LEFT_THUMB,
K_GP_RIGHT_THUMB,
K_AUX1, //XINPUT_GAMEPAD_LEFT_SHOULDER
K_AUX2, //XINPUT_GAMEPAD_RIGHT_SHOULDER
K_AUX7, //unused
K_AUX8, //unused
K_JOY2, //XINPUT_GAMEPAD_A
K_JOY4, //XINPUT_GAMEPAD_B
K_JOY1, //XINPUT_GAMEPAD_X
K_JOY3, //XINPUT_GAMEPAD_Y
K_GP_LEFT_SHOULDER,
K_GP_RIGHT_SHOULDER,
K_GP_GUIDE, //officially, this is 'reserved'
K_GP_UNKNOWN, //reserved
K_GP_A,
K_GP_B,
K_GP_X,
K_GP_Y,
K_AUX9, //left trigger
K_AUX10 //right trigger
//not part of xinput specs, but appended by us from analog triggers
K_GP_LEFT_TRIGGER,
K_GP_RIGHT_TRIGGER
};
static const int mmjbuttons[32] =
{
@ -2009,12 +2025,12 @@ qboolean INS_ReadJoystick (struct wjoy_s *joy)
if (joy->devid != DEVID_UNSET)
{
IN_JoystickAxisEvent(joy->devid, 0, xistate.Gamepad.sThumbRX / 32768.0);
IN_JoystickAxisEvent(joy->devid, 1, xistate.Gamepad.sThumbRY / 32768.0);
IN_JoystickAxisEvent(joy->devid, 2, xistate.Gamepad.bRightTrigger/255.0);
IN_JoystickAxisEvent(joy->devid, 3, xistate.Gamepad.sThumbLX / 32768.0);
IN_JoystickAxisEvent(joy->devid, 4, xistate.Gamepad.sThumbLY / 32768.0);
IN_JoystickAxisEvent(joy->devid, 5, xistate.Gamepad.bLeftTrigger/255.0);
IN_JoystickAxisEvent(joy->devid, GPAXIS_LT_RIGHT, xistate.Gamepad.sThumbLX / 32768.0);
IN_JoystickAxisEvent(joy->devid, GPAXIS_LT_DOWN, xistate.Gamepad.sThumbLY / 32768.0);
IN_JoystickAxisEvent(joy->devid, GPAXIS_LT_TRIGGER, xistate.Gamepad.bLeftTrigger/255.0);
IN_JoystickAxisEvent(joy->devid, GPAXIS_RT_RIGHT, xistate.Gamepad.sThumbRX / 32768.0);
IN_JoystickAxisEvent(joy->devid, GPAXIS_RT_DOWN, xistate.Gamepad.sThumbRY / 32768.0);
IN_JoystickAxisEvent(joy->devid, GPAXIS_RT_TRIGGER, xistate.Gamepad.bRightTrigger/255.0);
vibrator.wLeftMotorSpeed = xinput_leftvibrator.value * 0xffff;
vibrator.wRightMotorSpeed = xinput_rightvibrator.value * 0xffff;
@ -2036,12 +2052,12 @@ qboolean INS_ReadJoystick (struct wjoy_s *joy)
joy->buttonstate = ji.dwButtons;
if (joy->devid != DEVID_UNSET)
{
IN_JoystickAxisEvent(joy->devid, 0, (ji.dwXpos - 32768.0) / 32768);
IN_JoystickAxisEvent(joy->devid, 1, (ji.dwYpos - 32768.0) / 32768);
IN_JoystickAxisEvent(joy->devid, 2, (ji.dwZpos - 32768.0) / 32768);
IN_JoystickAxisEvent(joy->devid, 3, (ji.dwRpos - 32768.0) / 32768);
IN_JoystickAxisEvent(joy->devid, 4, (ji.dwUpos - 32768.0) / 32768);
IN_JoystickAxisEvent(joy->devid, 5, (ji.dwVpos - 32768.0) / 32768);
IN_JoystickAxisEvent(joy->devid, GPAXIS_LT_RIGHT, (ji.dwXpos - 32768.0) / 32768);
IN_JoystickAxisEvent(joy->devid, GPAXIS_LT_DOWN, (ji.dwYpos - 32768.0) / 32768);
IN_JoystickAxisEvent(joy->devid, GPAXIS_LT_AUX, (ji.dwZpos - 32768.0) / 32768);
IN_JoystickAxisEvent(joy->devid, GPAXIS_RT_RIGHT, (ji.dwRpos - 32768.0) / 32768);
IN_JoystickAxisEvent(joy->devid, GPAXIS_RT_DOWN, (ji.dwUpos - 32768.0) / 32768);
IN_JoystickAxisEvent(joy->devid, GPAXIS_RT_AUX, (ji.dwVpos - 32768.0) / 32768);
}
return true;
}

View File

@ -260,6 +260,25 @@ keyname_t keynames[] =
{"BACKQUOTE", '`'},
{"BACKSLASH", '\\'},
{"GP_A", K_GP_A},
{"GP_B", K_GP_B},
{"GP_X", K_GP_X},
{"GP_Y", K_GP_Y},
{"GP_LSHOULDER", K_GP_LEFT_SHOULDER},
{"GP_RSHOULDER", K_GP_RIGHT_SHOULDER},
{"GP_LTRIGGER", K_GP_LEFT_TRIGGER},
{"GP_RTRIGGER", K_GP_RIGHT_TRIGGER},
{"GP_BACK", K_GP_BACK},
{"GP_START", K_GP_START},
{"GP_LTHUMB", K_GP_LEFT_THUMB},
{"GP_RTHUMB", K_GP_RIGHT_THUMB},
{"GP_DPAD_UP", K_GP_DPAD_UP},
{"GP_DPAD_DOWN", K_GP_DPAD_DOWN},
{"GP_DPAD_LEFT", K_GP_DPAD_LEFT},
{"GP_DPAD_RIGHT", K_GP_DPAD_RIGHT},
{"GP_GUIDE", K_GP_GUIDE},
{"GP_UNKNOWN", K_GP_UNKNOWN},
{NULL, 0}
};
@ -777,7 +796,10 @@ void Key_DefaultLinkClicked(console_t *con, char *text, char *info)
else
{
char cmdprefix[6];
snprintf(cmdprefix, sizeof(cmdprefix), "%i ", i+1);
if (i == 0)
*cmdprefix = 0;
else
snprintf(cmdprefix, sizeof(cmdprefix), "%i ", i+1);
//hey look! its you!

View File

@ -21,6 +21,43 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#ifndef __CLIENT_KEYS_H__
#define __CLIENT_KEYS_H__
enum
{ //fte's assumed gamepad axis
GPAXIS_LT_RIGHT = 0,
GPAXIS_LT_DOWN = 1,
GPAXIS_LT_AUX = 2,
GPAXIS_RT_RIGHT = 3,
GPAXIS_RT_DOWN = 4,
GPAXIS_RT_AUX = 5,
//gah
#define GPAXIS_LT_TRIGGER GPAXIS_LT_AUX
#define GPAXIS_RT_TRIGGER GPAXIS_RT_AUX
};
#if 1
//gamepad alises, because I'm too lazy to define actual keys that are distinct from joysticks
#define K_GP_A K_JOY2
#define K_GP_B K_JOY4
#define K_GP_X K_JOY1
#define K_GP_Y K_JOY3
#define K_GP_LEFT_SHOULDER K_AUX1
#define K_GP_RIGHT_SHOULDER K_AUX2
#define K_GP_LEFT_TRIGGER K_AUX9
#define K_GP_RIGHT_TRIGGER K_AUX10
#define K_GP_BACK K_AUX6
#define K_GP_START K_AUX5
#define K_GP_LEFT_THUMB K_AUX3
#define K_GP_RIGHT_THUMB K_AUX4
#define K_GP_DPAD_UP K_UPARROW
#define K_GP_DPAD_DOWN K_DOWNARROW
#define K_GP_DPAD_LEFT K_LEFTARROW
#define K_GP_DPAD_RIGHT K_RIGHTARROW
#define K_GP_GUIDE K_AUX7
#define K_GP_UNKNOWN K_AUX8
#endif
//
// these are the key numbers that should be passed to Key_Event
//
@ -108,6 +145,22 @@ K_MOUSE10,
K_MWHEELUP,
K_MWHEELDOWN, // 189
#ifndef K_GP_A
K_GP_A = 190,
K_GP_B = 191,
K_GP_X = 192,
K_GP_Y = 193,
K_GP_LEFT_SHOULDER = 194,
K_GP_RIGHT_SHOULDER = 195,
K_GP_LEFT_TRIGGER = 196,
K_GP_RIGHT_TRIGGER = 197,
K_GP_BACK = 198,
K_GP_START = 199,
K_GP_LEFT_THUMB = 200,
K_GP_RIGHT_THUMB = 201,
K_GP_GUIDE = 202,
#endif
//
// joystick buttons
//
@ -163,6 +216,17 @@ K_RCTRL = 246,
K_RSHIFT = 247,
K_PRINTSCREEN = 248,
//K_UNUSED = 249,
//K_UNUSED = 250,
#ifndef K_GP_DPAD_UP
K_GP_DPAD_UP = 251,
K_GP_DPAD_DOWN = 252,
K_GP_DPAD_LEFT = 253,
K_GP_DPAD_RIGHT = 254,
K_GP_UNKNOWN = 255,
#endif
K_MAX = 256
};
@ -172,6 +236,7 @@ K_MAX = 256
#define KEY_MODIFIER_ALTBINDMAP (1<<3)
#define KEY_MODIFIERSTATES (1<<4)
//legacy aliases, lest we ever forget!
#define K_SHIFT K_LSHIFT
#define K_CTRL K_LCTRL
#define K_ALT K_LALT

View File

@ -64,6 +64,9 @@ extern cvar_t sv_listen_qw;
extern cvar_t sv_listen_nq;
extern cvar_t sv_listen_dp;
extern cvar_t sv_listen_q3;
#ifdef HAVE_DTLS
extern cvar_t sv_listen_dtls;
#endif
typedef struct {
enum masterprotocol_e protocol;
@ -3310,7 +3313,7 @@ void CL_MasterListParse(netadrtype_t adrtype, int type, qboolean slashpad)
return;
}
MSG_ReadByte ();
MSG_ReadByte (); //should be \n
last = firstserver;

View File

@ -140,6 +140,25 @@ int MP_TranslateFTEtoQCCodes(int code)
case K_AUX31: return 814;
case K_AUX32: return 815;
#ifndef K_GP_DPAD_UP // these are probably just aliases, so dupe cases. left for completeness.
case K_GP_DPAD_UP: return 816;
case K_GP_DPAD_DOWN: return 817;
case K_GP_DPAD_LEFT: return 818;
case K_GP_DPAD_RIGHT: return 819;
case K_GP_START: return 820;
case K_GP_BACK: return 821;
case K_GP_LEFT_THUMB: return 822;
case K_GP_RIGHT_THUMB: return 823;
case K_GP_LEFT_SHOULDER:return 824;
case K_GP_RIGHT_SHOULDER:return 825;
case K_GP_A: return 826;
case K_GP_B: return 827;
case K_GP_X: return 828;
case K_GP_Y: return 829;
case K_GP_LEFT_TRIGGER: return 830;
case K_GP_RIGHT_TRIGGER:return 831;
#endif
case K_VOLUP: return -code;
case K_VOLDOWN: return -code;
case K_APP: return -code;
@ -274,6 +293,32 @@ int MP_TranslateQCtoFTECodes(int code)
case 813: return K_AUX30;
case 814: return K_AUX31;
case 815: return K_AUX32;
//WARNING: these are currently aliases in FTE.
case 816: return K_GP_DPAD_UP;
case 817: return K_GP_DPAD_DOWN;
case 818: return K_GP_DPAD_LEFT;
case 819: return K_GP_DPAD_RIGHT;
case 820: return K_GP_START;
case 821: return K_GP_BACK;
case 822: return K_GP_LEFT_THUMB;
case 823: return K_GP_RIGHT_THUMB;
case 824: return K_GP_LEFT_SHOULDER;
case 825: return K_GP_RIGHT_SHOULDER;
case 826: return K_GP_A;
case 827: return K_GP_B;
case 828: return K_GP_X;
case 829: return K_GP_Y;
case 830: return K_GP_LEFT_TRIGGER;
case 831: return K_GP_RIGHT_TRIGGER;
// case 832: return K_GP_LEFT_THUMB_UP;
// case 833: return K_GP_LEFT_THUMB_DOWN;
// case 834: return K_GP_LEFT_THUMB_LEFT;
// case 835: return K_GP_LEFT_THUMB_RIGHT;
// case 836: return K_GP_RIGHT_THUMB_UP;
// case 837: return K_GP_RIGHT_THUMB_DOWN;
// case 838: return K_GP_RIGHT_THUMB_LEFT;
// case 839: return K_GP_RIGHT_THUMB_RIGHT;
default:
if (code < 0) //negative values are 'fte-native' keys, for stuff that the api lacks.
return -code;

View File

@ -135,13 +135,12 @@ qboolean Sys_rmdir (const char *path)
#if WIN32
ret = _rmdir (path);
#else
//user, group, others
ret = rmdir (path, 0755); //WARNING: DO NOT RUN AS ROOT!
ret = rmdir (path);
#endif
if (ret == 0)
return true;
if (errno == ENOENT)
return true;
// if (errno == ENOENT)
// return true;
return false;
}

View File

@ -293,6 +293,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define RTLIGHTS //realtime lighting
#endif
// #define QWOVERQ3 //allows qw servers with q3 clients. requires specific cgame.
#define VM_Q1 //q1 qvm gamecode interface
//#define VM_LUA //q1 lua gamecode interface
@ -531,6 +533,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#if defined(HAVE_WINSSPI) || defined(HAVE_GNUTLS)
#define HAVE_SSL
#endif
#if defined(HAVE_GNUTLS) || defined(HAVE_WINSSPI)
//FIXME: HAVE_WINSSPI does not work as a server.
//FIXME: advertising dtls without a valid certificate will probably bug out if a client tries to auto-upgrade.
// #define HAVE_DTLS
#endif
#if defined(USE_SQLITE) || defined(USE_MYSQL)
#define SQL
@ -545,6 +552,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define Q3BSPS //rbsp might as well depend upon q3bsp - its the same thing but with more lightstyles (support for which can bog down the renderer a little).
#endif
#if defined(QWOVERQ3) && !defined(Q3SERVER)
#undef QWOVERQ3
#endif
//fix things a little...
#ifdef NPQTV
#define NPFTE

View File

@ -48,7 +48,6 @@ typedef enum {
NP_TLS,
NP_WS,
NP_WSS,
NP_IRC,
NP_NATPMP
} netproto_t;
@ -114,6 +113,7 @@ void NET_Init (void);
void NET_Tick (void);
void SVNET_RegisterCvars(void);
void NET_InitClient (qboolean loopbackonly);
void NET_CloseClient(void);
void NET_InitServer (void);
qboolean NET_WasSpecialPacket(netsrc_t netsrc);
void NET_CloseServer (void);
@ -161,6 +161,13 @@ qboolean NET_CompareAdrMasked(netadr_t *a, netadr_t *b, netadr_t *mask);
qboolean FTENET_AddToCollection(struct ftenet_connections_s *col, const char *name, const char *address, netadrtype_t addrtype, netproto_t addrprot, qboolean islisten);
#ifdef HAVE_DTLS
qboolean NET_DTLS_Create(struct ftenet_connections_s *col, netadr_t *to);
qboolean NET_DTLS_Decode(struct ftenet_connections_s *col);
qboolean NET_DTLS_Disconnect(struct ftenet_connections_s *col, netadr_t *to);
void NET_DTLS_Timeouts(struct ftenet_connections_s *col);
#endif
//============================================================================
#define OLD_AVG 0.99 // total = oldtotal*OLD_AVG + new*(1-OLD_AVG)

View File

@ -575,16 +575,6 @@ int Netchan_Transmit (netchan_t *chan, int length, qbyte *data, int rate)
send.maxsize = MAX_NQMSGLEN + PACKET_HEADER;
send.cursize = 0;
if (NET_AddrIsReliable(&chan->remote_address) && chan->reliable_length)
{
//if over tcp, everything is assumed to be reliable. pretend it got acked.
chan->reliable_length = 0; //they got the entire message
chan->reliable_start = 0;
chan->incoming_reliable_acknowledged = chan->reliable_sequence;
chan->reliable_sequence++;
chan->nqreliable_allowed = true;
}
/*unreliables flood out, but reliables are tied to server sequences*/
if (chan->nqreliable_resendtime < realtime)
chan->nqreliable_allowed = true;
@ -606,6 +596,9 @@ int Netchan_Transmit (netchan_t *chan, int length, qbyte *data, int rate)
{
MSG_WriteLong(&send, 0);
MSG_WriteLong(&send, LongSwap(chan->reliable_sequence));
//limit the payload length to nq's datagram max size.
//relax the limitation if its reliable (ie: over tcp) where its assumed to have no real limit
if (i > MAX_NQDATAGRAM && !NET_AddrIsReliable(&chan->remote_address))
i = MAX_NQDATAGRAM;
@ -623,20 +616,31 @@ int Netchan_Transmit (netchan_t *chan, int length, qbyte *data, int rate)
}
else
*(int*)send_buf = BigLong(NETFLAG_DATA | send.cursize);
NET_SendPacket (chan->sock, send.cursize, send.data, &chan->remote_address);
chan->bytesout += send.cursize;
sentsize += send.cursize;
if (showpackets.value)
Con_Printf ("out %s r s=%i %i\n"
, chan->sock == NS_SERVER?"s2c":"c2s"
, chan->reliable_sequence
, send.cursize);
send.cursize = 0;
chan->nqreliable_allowed = false;
chan->nqreliable_resendtime = realtime + 0.3; //resend reliables after 0.3 seconds. nq transports suck.
if (NET_SendPacket (chan->sock, send.cursize, send.data, &chan->remote_address) == NETERR_SENT && NET_AddrIsReliable(&chan->remote_address))
{ //if over tcp, everything is assumed to be reliable. pretend it got acked now.
//if we get an ack later, then who cares.
chan->reliable_start += i;
if (chan->reliable_start >= chan->reliable_length)
{
chan->reliable_length = 0; //they got the entire message
chan->reliable_start = 0;
}
chan->incoming_reliable_acknowledged = chan->reliable_sequence;
chan->reliable_sequence++;
chan->nqreliable_allowed = true;
}
send.cursize = 0;
}
}

View File

@ -615,9 +615,8 @@ qboolean QDECL ICE_Set(struct icestate_s *con, const char *prop, const char *val
#ifndef CLIENTONLY
else if (con->proto == ICEP_QWSERVER)
{
extern void SVC_GetChallenge(qboolean nodpresponse);
net_from = con->chosenpeer;
SVC_GetChallenge(true);
SVC_GetChallenge(false);
}
#endif
if (con->state == ICE_CONNECTED)
@ -873,12 +872,13 @@ qboolean QDECL ICE_Get(struct icestate_s *con, const char *prop, char *value, si
if (con->proto == ICEP_QWSERVER || con->proto == ICEP_QWCLIENT)
{
#ifdef HAVE_DTLS
Q_strncatz(value, "m=application 9 DTLS/SCTP 5000\n", valuelen);
#endif
}
for (i = 0; i < countof(con->codec); i++)
{
int codec = atoi(prop+5);
if (!con->codec[i])
continue;
@ -917,7 +917,6 @@ qboolean QDECL ICE_GetLCandidateSDP(struct icestate_s *con, char *out, size_t ou
{
if (can->dirty)
{
struct icecandinfo_s *c = &can->info;
can->dirty = false;
ICE_CandidateToSDP(can, out, outsize);

View File

@ -4,12 +4,14 @@
#include "quakedef.h"
#define GNUTLS_DYNAMIC //statically linking is bad, because that just dynamically links to a .so that probably won't exist.
//on the other hand, it does validate that the function types are correct.
#ifndef GNUTLS_STATIC
#define GNUTLS_DYNAMIC //statically linking is bad, because that just dynamically links to a .so that probably won't exist.
//on the other hand, it does validate that the function types are correct.
#endif
#ifdef HAVE_GNUTLS
#if defined(_WIN32) && !defined(MINGW)
#if defined(_WIN32) && !defined(MINGW) && 0
#define GNUTLS_VERSION "2.12.23"
#define GNUTLS_SOPREFIX ""
@ -92,6 +94,7 @@ typedef int (VARGS gnutls_certificate_verify_function)(gnutls_session_t session)
#else
#include <gnutls/gnutls.h>
#include <gnutls/dtls.h>
#define gnutls_connection_end_t unsigned int
#if GNUTLS_VERSION_MAJOR < 3 || (GNUTLS_VERSION_MAJOR == 3 && GNUTLS_VERSION_MINOR < 3)
@ -152,6 +155,7 @@ static int (VARGS *qgnutls_certificate_set_x509_system_trust)(gnutls_certificate
#else
static int (VARGS *qgnutls_certificate_set_x509_trust_file)(gnutls_certificate_credentials_t cred, const char * cafile, gnutls_x509_crt_fmt_t type);
#endif
static int (VARGS *qgnutls_certificate_set_x509_key_file)(gnutls_certificate_credentials_t res, const char * certfile, const char * keyfile, gnutls_x509_crt_fmt_t type);
#ifdef GNUTLS_HAVE_VERIFY3
static int (VARGS *qgnutls_certificate_verify_peers3)(gnutls_session_t session, const char* hostname, unsigned int * status);
static int (VARGS *qgnutls_certificate_verification_status_print)(unsigned int status, gnutls_certificate_type_t type, gnutls_datum_t * out, unsigned int flags);
@ -166,6 +170,15 @@ static gnutls_certificate_type_t (VARGS *qgnutls_certificate_type_get)(gnutls_se
static void (VARGS *qgnutls_free)(void * ptr);
static int (VARGS *qgnutls_server_name_set)(gnutls_session_t session, gnutls_server_name_type_t type, const void * name, size_t name_length);
#ifdef HAVE_DTLS
static int (VARGS *qgnutls_key_generate)(gnutls_datum_t * key, unsigned int key_size);
static void (VARGS *qgnutls_transport_set_pull_timeout_function)(gnutls_session_t session, gnutls_pull_timeout_func func);
static int (VARGS *qgnutls_dtls_cookie_verify)(gnutls_datum_t * key, void *client_data, size_t client_data_size, void *_msg, size_t msg_size, gnutls_dtls_prestate_st * prestate);
static int (VARGS *qgnutls_dtls_cookie_send)(gnutls_datum_t * key, void *client_data, size_t client_data_size, gnutls_dtls_prestate_st * prestate, gnutls_transport_ptr_t ptr, gnutls_push_func push_func);
static void (VARGS *qgnutls_dtls_prestate_set)(gnutls_session_t session, gnutls_dtls_prestate_st * prestate);
static void (VARGS *qgnutls_dtls_set_mtu)(gnutls_session_t session, unsigned int mtu);
#endif
static qboolean Init_GNUTLS(void)
{
#ifdef GNUTLS_HAVE_SYSTEMTRUST
@ -186,6 +199,18 @@ static qboolean Init_GNUTLS(void)
GNUTLS_FUNC(gnutls_certificate_get_peers)
#endif
#ifdef HAVE_DTLS
#define GNUTLS_DTLS_STUFF \
GNUTLS_FUNC(gnutls_key_generate) \
GNUTLS_FUNC(gnutls_transport_set_pull_timeout_function) \
GNUTLS_FUNC(gnutls_dtls_cookie_verify) \
GNUTLS_FUNC(gnutls_dtls_cookie_send) \
GNUTLS_FUNC(gnutls_dtls_prestate_set) \
GNUTLS_FUNC(gnutls_dtls_set_mtu)
#else
#define GNUTLS_DTLS_STUFF
#endif
#define GNUTLS_FUNCS \
GNUTLS_FUNC(gnutls_bye) \
@ -208,10 +233,12 @@ static qboolean Init_GNUTLS(void)
GNUTLS_FUNC(gnutls_session_get_ptr) \
GNUTLS_FUNC(gnutls_session_set_ptr) \
GNUTLS_TRUSTFUNCS \
GNUTLS_FUNC(gnutls_certificate_set_x509_key_file) \
GNUTLS_VERIFYFUNCS \
GNUTLS_FUNC(gnutls_certificate_type_get) \
GNUTLS_FUNC(gnutls_free) \
GNUTLS_FUNC(gnutls_server_name_set) \
GNUTLS_DTLS_STUFF
#ifdef GNUTLS_DYNAMIC
dllhandle_t *hmod;
@ -247,6 +274,7 @@ static qboolean Init_GNUTLS(void)
#else
{(void**)&qgnutls_certificate_set_x509_trust_file, "gnutls_certificate_set_x509_trust_file"},
#endif
{(void**)&qgnutls_certificate_set_x509_key_file, "gnutls_certificate_set_x509_key_file"},
#ifdef GNUTLS_HAVE_VERIFY3
{(void**)&qgnutls_certificate_verify_peers3, "gnutls_certificate_verify_peers3"},
{(void**)&qgnutls_certificate_verification_status_print, "gnutls_certificate_verification_status_print"},
@ -260,6 +288,16 @@ static qboolean Init_GNUTLS(void)
{(void**)&qgnutls_certificate_type_get, "gnutls_certificate_type_get"},
{(void**)&qgnutls_free, "gnutls_free"},
{(void**)&qgnutls_server_name_set, "gnutls_server_name_set"},
#ifdef HAVE_DTLS
{(void**)&qgnutls_key_generate, "gnutls_key_generate"},
{(void**)&qgnutls_transport_set_pull_timeout_function, "gnutls_transport_set_pull_timeout_function"},
{(void**)&qgnutls_dtls_cookie_verify, "gnutls_dtls_cookie_verify"},
{(void**)&qgnutls_dtls_cookie_send, "gnutls_dtls_cookie_send"},
{(void**)&qgnutls_dtls_prestate_set, "gnutls_dtls_prestate_set"},
{(void**)&qgnutls_dtls_set_mtu, "gnutls_dtls_set_mtu"},
#endif
{NULL, NULL}
};
@ -282,11 +320,6 @@ static qboolean Init_GNUTLS(void)
return true;
}
struct sslbuf
{
char data[8192];
int avail;
};
typedef struct
{
vfsfile_t funcs;
@ -298,10 +331,13 @@ typedef struct
qboolean handshaking;
qboolean datagram;
struct sslbuf outplain;
struct sslbuf outcrypt;
struct sslbuf inplain;
struct sslbuf incrypt;
qboolean challenging; //not sure this is actually needed, but hey.
void *cbctx;
neterr_t(*cbpush)(void *cbctx, const qbyte *data, size_t datasize);
qbyte *readdata;
size_t readsize;
gnutls_dtls_prestate_st prestate;
// int mtu;
} gnutlsfile_t;
#define CAFILE "/etc/ssl/certs/ca-certificates.crt"
@ -456,7 +492,10 @@ int SSL_DoHandshake(gnutlsfile_t *file)
int err;
//session was previously closed = error
if (!file->session)
{
Sys_Printf("null session\n");
return -1;
}
err = qgnutls_handshake (file->session);
if (err < 0)
@ -466,7 +505,7 @@ int SSL_DoHandshake(gnutlsfile_t *file)
return 0;
//certificate errors etc
// qgnutls_perror (err);
qgnutls_perror (err);
SSL_Close(&file->funcs);
// Con_Printf("%s: abort\n", file->certname);
@ -560,6 +599,7 @@ static qofs_t QDECL SSL_GetLen (struct vfsfile_s *file)
static ssize_t SSL_Push(gnutls_transport_ptr_t p, const void *data, size_t size)
{
gnutlsfile_t *file = p;
// Sys_Printf("SSL_Push: %u\n", size);
int done = VFS_WRITE(file->stream, data, size);
if (!done)
{
@ -571,32 +611,10 @@ static ssize_t SSL_Push(gnutls_transport_ptr_t p, const void *data, size_t size)
return 0;
return done;
}
/*static ssize_t SSL_PushV(gnutls_transport_ptr_t p, giovec_t *iov, int iovcnt)
{
int i;
ssize_t written;
ssize_t total;
gnutlsfile_t *file = p;
for (i = 0; i < iovcnt; i++)
{
written = SSL_Push(file, iov[i].iov_base, iov[i].iov_len);
if (written <= 0)
break;
total += written;
if (written < iov[i].iov_len)
break;
}
if (!total)
{
qgnutls_transport_set_errno(file->session, EAGAIN);
return -1;
}
qgnutls_transport_set_errno(file->session, 0);
return total;
}*/
static ssize_t SSL_Pull(gnutls_transport_ptr_t p, void *data, size_t size)
{
gnutlsfile_t *file = p;
// Sys_Printf("SSL_Pull: %u\n", size);
int done = VFS_READ(file->stream, data, size);
if (!done)
{
@ -611,62 +629,174 @@ static ssize_t SSL_Pull(gnutls_transport_ptr_t p, void *data, size_t size)
return done;
}
vfsfile_t *FS_OpenSSL(const char *hostname, vfsfile_t *source, qboolean server, qboolean datagram)
static ssize_t DTLS_Push(gnutls_transport_ptr_t p, const void *data, size_t size)
{
gnutlsfile_t *file = p;
neterr_t ne = file->cbpush(file->cbctx, data, size);
// Sys_Printf("DTLS_Push: %u, err=%i\n", (unsigned)size, (int)ne);
switch(ne)
{
case NETERR_CLOGGED:
qgnutls_transport_set_errno(file->session, EAGAIN);
return -1;
case NETERR_MTU:
qgnutls_transport_set_errno(file->session, EMSGSIZE);
return -1;
case NETERR_DISCONNECTED:
qgnutls_transport_set_errno(file->session, EPERM);
return -1;
default:
qgnutls_transport_set_errno(file->session, 0);
return size;
}
}
static ssize_t DTLS_Pull(gnutls_transport_ptr_t p, void *data, size_t size)
{
gnutlsfile_t *file = p;
// Sys_Printf("DTLS_Pull: %u of %u\n", size, file->readsize);
if (!file->readsize)
{ //no data left
// Sys_Printf("DTLS_Pull: EAGAIN\n");
qgnutls_transport_set_errno(file->session, EAGAIN);
return -1;
}
else if (file->readsize > size)
{ //buffer passed is smaller than available data
// Sys_Printf("DTLS_Pull: EMSGSIZE\n");
memcpy(data, file->readdata, size);
file->readsize = 0;
qgnutls_transport_set_errno(file->session, EMSGSIZE);
return -1;
}
else
{ //buffer is big enough to read it all
size = file->readsize;
file->readsize = 0;
// Sys_Printf("DTLS_Pull: reading %i\n", size);
memcpy(data, file->readdata, size);
qgnutls_transport_set_errno(file->session, 0);
return size;
}
}
static int DTLS_Pull_Timeout(gnutls_transport_ptr_t p, unsigned int timeout)
{ //gnutls (pointlessly) requires this function for dtls.
gnutlsfile_t *f = p;
// Sys_Printf("DTLS_Pull_Timeout %i, %i\n", timeout, f->readsize);
return f->readsize>0?1:0;
}
#ifdef USE_ANON
static gnutls_anon_client_credentials_t anoncred[2];
#else
static gnutls_certificate_credentials_t xcred[2];
#endif
static gnutls_datum_t cookie_key;
qboolean SSL_InitGlobal(qboolean isserver)
{
static int initstatus[2];
if (!initstatus[isserver])
{
if (!Init_GNUTLS())
{
Con_Printf("GnuTLS "GNUTLS_VERSION" library not available.\n");
return false;
}
initstatus[isserver] = true;
qgnutls_global_init ();
if (isserver)
qgnutls_key_generate(&cookie_key, GNUTLS_COOKIE_KEY_SIZE);
#ifdef USE_ANON
qgnutls_anon_allocate_client_credentials (&anoncred[isserver]);
#else
qgnutls_certificate_allocate_credentials (&xcred[isserver]);
#ifdef GNUTLS_HAVE_SYSTEMTRUST
qgnutls_certificate_set_x509_system_trust (xcred[isserver]);
#else
qgnutls_certificate_set_x509_trust_file (xcred[isserver], CAFILE, GNUTLS_X509_FMT_PEM);
#endif
if (isserver)
{
#define KEYFILE "c:/games/tools/ssl/key.pem"
#define CERTFILE "c:/games/tools/ssl/cert.pem"
int ret = qgnutls_certificate_set_x509_key_file(xcred[isserver], CERTFILE, KEYFILE, GNUTLS_X509_FMT_PEM);
if (ret < 0)
{
Con_Printf("No certificate or key were found\n");
initstatus[isserver] = -1;
}
}
else
qgnutls_certificate_set_verify_function (xcred[isserver], SSL_CheckCert);
#endif
}
if (initstatus[isserver] < 0)
return false;
return true;
}
qboolean SSL_InitConnection(gnutlsfile_t *newf, qboolean isserver, qboolean datagram)
{
// Initialize TLS session
qgnutls_init (&newf->session, GNUTLS_NONBLOCK|(isserver?GNUTLS_SERVER:GNUTLS_CLIENT)|(datagram?GNUTLS_DATAGRAM:0));
if (!isserver)
qgnutls_server_name_set(newf->session, GNUTLS_NAME_DNS, newf->certname, strlen(newf->certname));
qgnutls_session_set_ptr(newf->session, newf);
#ifdef USE_ANON
//qgnutls_kx_set_priority (newf->session, kx_prio);
qgnutls_credentials_set (newf->session, GNUTLS_CRD_ANON, anoncred[isserver]);
#else
//#if GNUTLS_VERSION_MAJOR >= 3
//gnutls_priority_set_direct();
//#else
//qgnutls_certificate_type_set_priority (newf->session, cert_type_priority);
//#endif
qgnutls_credentials_set (newf->session, GNUTLS_CRD_CERTIFICATE, xcred[isserver]);
#endif
// Use default priorities
qgnutls_set_default_priority (newf->session);
// tell gnutls how to send/receive data
qgnutls_transport_set_ptr (newf->session, newf);
qgnutls_transport_set_push_function(newf->session, datagram?DTLS_Push:SSL_Push);
//qgnutls_transport_set_vec_push_function(newf->session, SSL_PushV);
qgnutls_transport_set_pull_function(newf->session, datagram?DTLS_Pull:SSL_Pull);
if (datagram)
qgnutls_transport_set_pull_timeout_function(newf->session, DTLS_Pull_Timeout);
// if (isserver) //don't bother to auth any client certs
// qgnutls_certificate_server_set_request(newf->session, GNUTLS_CERT_IGNORE);
newf->handshaking = true;
return true;
}
vfsfile_t *FS_OpenSSL(const char *hostname, vfsfile_t *source, qboolean isserver)
{
gnutlsfile_t *newf;
qboolean anon = false;
static gnutls_anon_client_credentials_t anoncred;
static gnutls_certificate_credentials_t xcred;
// long _false = false;
// long _true = true;
/* Need to enable anonymous KX specifically. */
// const int kx_prio[] = {GNUTLS_KX_ANON_DH, 0};
// const int cert_type_priority[3] = {GNUTLS_CRT_X509, 0};
if (!source)
return NULL;
if (datagram)
{
VFS_CLOSE(source);
return NULL;
}
#ifdef GNUTLS_DATAGRAM
if (datagram)
return NULL;
#endif
{
static qboolean needinit = true;
if (needinit)
{
if (!Init_GNUTLS())
{
Con_Printf("GnuTLS "GNUTLS_VERSION" library not available.\n");
VFS_CLOSE(source);
return NULL;
}
qgnutls_global_init ();
qgnutls_anon_allocate_client_credentials (&anoncred);
qgnutls_certificate_allocate_credentials (&xcred);
#ifdef GNUTLS_HAVE_SYSTEMTRUST
qgnutls_certificate_set_x509_system_trust (xcred);
#else
qgnutls_certificate_set_x509_trust_file (xcred, CAFILE, GNUTLS_X509_FMT_PEM);
#endif
qgnutls_certificate_set_verify_function (xcred, SSL_CheckCert);
needinit = false;
}
}
newf = Z_Malloc(sizeof(*newf));
if (!SSL_InitGlobal(isserver))
newf = NULL;
else
newf = Z_Malloc(sizeof(*newf));
if (!newf)
{
VFS_CLOSE(source);
@ -682,51 +812,189 @@ vfsfile_t *FS_OpenSSL(const char *hostname, vfsfile_t *source, qboolean server,
newf->funcs.Tell = SSL_Tell;
newf->funcs.seekstyle = SS_UNSEEKABLE;
Q_strncpyz(newf->certname, hostname, sizeof(newf->certname));
// Initialize TLS session
qgnutls_init (&newf->session, GNUTLS_CLIENT/*|(datagram?GNUTLS_DATAGRAM:0)*/);
qgnutls_server_name_set(newf->session, GNUTLS_NAME_DNS, newf->certname, strlen(newf->certname));
qgnutls_session_set_ptr(newf->session, newf);
// Use default priorities
qgnutls_set_default_priority (newf->session);
if (anon)
{
//qgnutls_kx_set_priority (newf->session, kx_prio);
qgnutls_credentials_set (newf->session, GNUTLS_CRD_ANON, anoncred);
}
if (hostname)
Q_strncpyz(newf->certname, hostname, sizeof(newf->certname));
else
Q_strncpyz(newf->certname, "", sizeof(newf->certname));
if (!SSL_InitConnection(newf, isserver, false))
{
//#if GNUTLS_VERSION_MAJOR >= 3
//gnutls_priority_set_direct();
//#else
//qgnutls_certificate_type_set_priority (newf->session, cert_type_priority);
//#endif
qgnutls_credentials_set (newf->session, GNUTLS_CRD_CERTIFICATE, xcred);
VFS_CLOSE(&newf->funcs);
return NULL;
}
// tell gnutls how to send/receive data
qgnutls_transport_set_ptr (newf->session, newf);
qgnutls_transport_set_push_function(newf->session, SSL_Push);
//qgnutls_transport_set_vec_push_function(newf->session, SSL_PushV);
qgnutls_transport_set_pull_function(newf->session, SSL_Pull);
//qgnutls_transport_set_pull_timeout_function(newf->session, NULL);
newf->handshaking = true;
return &newf->funcs;
}
/*
vfsfile_t *FS_OpenSSL(const char *hostname, vfsfile_t *source, qboolean server, qboolean datagram)
#ifdef HAVE_DTLS
void DTLS_DestroyContext(void *ctx)
{
if (source)
VFS_CLOSE(source);
return NULL;
SSL_Close(ctx);
}
qboolean DTLS_HasServerCertificate(void)
{
if (!SSL_InitGlobal(true))
return false;
return true;
}
void *DTLS_CreateContext(void *cbctx, neterr_t(*push)(void *cbctx, const qbyte *data, size_t datasize), qboolean isserver)
{
gnutlsfile_t *newf;
if (!SSL_InitGlobal(isserver))
newf = NULL;
else
newf = Z_Malloc(sizeof(*newf));
if (!newf)
return NULL;
newf->datagram = true;
newf->cbctx = cbctx;
newf->cbpush = push;
newf->challenging = isserver;
// Sys_Printf("DTLS_CreateContext: server=%i\n", isserver);
Q_strncpyz(newf->certname, "", sizeof(newf->certname));
if (!SSL_InitConnection(newf, isserver, true))
{
SSL_Close(&newf->funcs);
return NULL;
}
return newf;
}
neterr_t DTLS_Transmit(void *ctx, const qbyte *data, size_t datasize)
{
int ret;
gnutlsfile_t *f = (gnutlsfile_t *)ctx;
// Sys_Printf("DTLS_Transmit: %u\n", datasize);
// Sys_Printf("%su\n", data);
if (f->challenging)
return NETERR_CLOGGED;
if (f->handshaking)
{
ret = SSL_DoHandshake(f);
if (!ret)
return NETERR_CLOGGED;
if (ret < 0)
return NETERR_DISCONNECTED;
}
ret = qgnutls_record_send(f->session, data, datasize);
if (ret < 0)
{
if (ret == GNUTLS_E_LARGE_PACKET)
return NETERR_MTU;
//Sys_Error("qgnutls_record_send returned %i\n", ret);
if (qgnutls_error_is_fatal(ret))
return NETERR_DISCONNECTED;
return NETERR_CLOGGED;
}
return NETERR_SENT;
}
neterr_t DTLS_Received(void *ctx, qbyte *data, size_t datasize)
{
int cli_addr = 0xdeadbeef;
int ret;
gnutlsfile_t *f = (gnutlsfile_t *)ctx;
//Sys_Printf("DTLS_Received: %u\n", datasize);
if (f->challenging)
{
memset(&f->prestate, 0, sizeof(f->prestate));
ret = qgnutls_dtls_cookie_verify(&cookie_key,
&cli_addr, sizeof(cli_addr),
data, datasize,
&f->prestate);
if (ret < 0)
{
//Sys_Printf("Sending cookie\n");
qgnutls_dtls_cookie_send(&cookie_key,
&cli_addr, sizeof(cli_addr),
&f->prestate,
(gnutls_transport_ptr_t)f, DTLS_Push);
return NETERR_CLOGGED;
}
//Sys_Printf("Got correct cookie\n");
f->challenging = false;
qgnutls_dtls_prestate_set(f->session, &f->prestate);
qgnutls_dtls_set_mtu(f->session, 1440);
// qgnutls_transport_set_push_function(f->session, DTLS_Push);
// qgnutls_transport_set_pull_function(f->session, DTLS_Pull);
f->handshaking = true;
}
f->readdata = data;
f->readsize = datasize;
if (f->handshaking)
{
ret = SSL_DoHandshake(f);
if (ret <= 0)
f->readsize = 0;
if (!ret)
return NETERR_CLOGGED;
if (ret < 0)
return NETERR_DISCONNECTED;
}
ret = qgnutls_record_recv(f->session, net_message_buffer, sizeof(net_message_buffer));
//Sys_Printf("DTLS_Received returned %i of %i\n", ret, f->readsize);
f->readsize = 0;
if (ret <= 0)
{
if (!ret)
{
// Sys_Printf("DTLS_Received peer terminated connection\n");
return NETERR_DISCONNECTED;
}
if (qgnutls_error_is_fatal(ret))
{
// Sys_Printf("DTLS_Received fail error\n");
return NETERR_DISCONNECTED;
}
// Sys_Printf("DTLS_Received temp error\n");
return NETERR_CLOGGED;
}
net_message.cursize = ret;
data[ret] = 0;
// Sys_Printf("DTLS_Received returned %s\n", data);
return NETERR_SENT;
}
neterr_t DTLS_Timeouts(void *ctx)
{
gnutlsfile_t *f = (gnutlsfile_t *)ctx;
int ret;
if (f->challenging)
return NETERR_CLOGGED;
if (f->handshaking)
{
f->readsize = 0;
ret = SSL_DoHandshake(f);
f->readsize = 0;
if (!ret)
return NETERR_CLOGGED;
if (ret < 0)
return NETERR_DISCONNECTED;
// Sys_Printf("handshaking over?\n");
}
return NETERR_SENT;
}
*/
#endif
#endif

View File

@ -1,5 +1,12 @@
#include "quakedef.h"
#if defined(HAVE_WINSSPI)
/*regarding HAVE_DTLS
DTLS1.0 is supported from win8 onwards
Its also meant to be supported from some RDP server patch on win7, but I can't get it to work.
I've given up for now.
*/
cvar_t *tls_ignorecertificateerrors;
#include "winquake.h"
@ -32,6 +39,10 @@ cvar_t *tls_ignorecertificateerrors;
#define SCH_CRED_SNI_CREDENTIAL 0x00080000
#endif
#define SEC_I_MESSAGE_FRAGMENT 0x00090364L
#define SEC_E_INVALID_PARAMETER 0x8009035DL
//hungarian ensures we hit no macros.
static struct
{
@ -39,7 +50,7 @@ static struct
SECURITY_STATUS (WINAPI *pDecryptMessage) (PCtxtHandle,PSecBufferDesc,ULONG,PULONG);
SECURITY_STATUS (WINAPI *pEncryptMessage) (PCtxtHandle,ULONG,PSecBufferDesc,ULONG);
SECURITY_STATUS (WINAPI *pAcquireCredentialsHandleA) (SEC_CHAR*,SEC_CHAR*,ULONG,PLUID,PVOID,SEC_GET_KEY_FN,PVOID,PCredHandle,PTimeStamp);
SECURITY_STATUS (WINAPI *pInitializeSecurityContextA) (PCredHandle,PCtxtHandle,SEC_CHAR*,ULONG,ULONG,ULONG,PSecBufferDesc,ULONG,PCtxtHandle,PSecBufferDesc,PULONG,PTimeStamp);
// SECURITY_STATUS (WINAPI *pInitializeSecurityContextA) (PCredHandle,PCtxtHandle,SEC_CHAR*,ULONG,ULONG,ULONG,PSecBufferDesc,ULONG,PCtxtHandle,PSecBufferDesc,PULONG,PTimeStamp);
SECURITY_STATUS (WINAPI *pInitializeSecurityContextW) (PCredHandle,PCtxtHandle,SEC_WCHAR*,ULONG,ULONG,ULONG,PSecBufferDesc,ULONG,PCtxtHandle,PSecBufferDesc,PULONG,PTimeStamp);
SECURITY_STATUS (WINAPI *pAcceptSecurityContext) (PCredHandle,PCtxtHandle,PSecBufferDesc,unsigned long,unsigned long,PCtxtHandle,PSecBufferDesc,unsigned long SEC_FAR *,PTimeStamp);
SECURITY_STATUS (WINAPI *pCompleteAuthToken) (PCtxtHandle,PSecBufferDesc);
@ -65,7 +76,7 @@ void SSL_Init(void)
{(void**)&secur.pDecryptMessage, "DecryptMessage"},
{(void**)&secur.pEncryptMessage, "EncryptMessage"},
{(void**)&secur.pAcquireCredentialsHandleA, "AcquireCredentialsHandleA"},
{(void**)&secur.pInitializeSecurityContextA, "InitializeSecurityContextA"},
// {(void**)&secur.pInitializeSecurityContextA, "InitializeSecurityContextA"},
{(void**)&secur.pInitializeSecurityContextW, "InitializeSecurityContextW"},
{(void**)&secur.pAcceptSecurityContext, "AcceptSecurityContext"},
{(void**)&secur.pCompleteAuthToken, "CompleteAuthToken"},
@ -98,14 +109,13 @@ qboolean SSL_Inited(void)
return !!secur.lib && !!crypt.lib;
}
#define MessageAttribute (ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT | ISC_REQ_CONFIDENTIALITY | ISC_RET_EXTENDED_ERROR | ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_MANUAL_CRED_VALIDATION)
#define MessageAttribute (ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT | ISC_REQ_CONFIDENTIALITY | ISC_REQ_EXTENDED_ERROR | ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_MANUAL_CRED_VALIDATION)
struct sslbuf
{
size_t datasize;
char *data;
size_t avail;
size_t newd;
};
typedef struct {
@ -137,6 +147,11 @@ typedef struct {
SecHandle sechnd;
int headersize, footersize;
char headerdata[1024], footerdata[1024];
#ifdef HAVE_DTLS
void *cbctx;
void (*transmit)(void *cbctx, qbyte *data, size_t datasize);
#endif
} sslfile_t;
static int SSPI_ExpandBuffer(struct sslbuf *buf, size_t bytes)
@ -162,8 +177,15 @@ static int SSPI_CopyIntoBuffer(struct sslbuf *buf, const void *data, unsigned in
static void SSPI_Error(sslfile_t *f, char *error, ...)
{
va_list argptr;
char string[1024];
va_start (argptr, error);
vsnprintf (string,sizeof(string)-1, error,argptr);
va_end (argptr);
f->handshaking = HS_ERROR;
Sys_Printf("%s", error);
if (*string)
Sys_Printf("%s", string);
if (f->stream)
VFS_CLOSE(f->stream);
@ -176,7 +198,17 @@ static void SSPI_TryFlushCryptOut(sslfile_t *f)
{
int sent;
if (f->outcrypt.avail)
{
#ifdef HAVE_DTLS
if (f->transmit)
{
f->transmit(f->cbctx, f->outcrypt.data, f->outcrypt.avail);
f->outcrypt.avail = 0;
return;
}
#endif
sent = VFS_WRITE(f->stream, f->outcrypt.data, f->outcrypt.avail);
}
else
return;
@ -215,7 +247,7 @@ static void SSPI_Decode(sslfile_t *f)
return;
BuffDesc.ulVersion = SECBUFFER_VERSION;
BuffDesc.cBuffers = 4;
BuffDesc.cBuffers = countof(SecBuff);
BuffDesc.pBuffers = SecBuff;
SecBuff[0].BufferType = SECBUFFER_DATA;
@ -238,6 +270,7 @@ static void SSPI_Decode(sslfile_t *f)
}
switch(ss)
{
case SEC_E_DECRYPT_FAILURE: SSPI_Error(f, "DecryptMessage failed: SEC_E_DECRYPT_FAILURE\n", ss); break;
case SEC_E_INVALID_HANDLE: SSPI_Error(f, "DecryptMessage failed: SEC_E_INVALID_HANDLE\n"); break;
default: SSPI_Error(f, "DecryptMessage failed: %0#lx\n", ss); break;
}
@ -318,6 +351,8 @@ static void SSPI_Encode(sslfile_t *f)
SecBuff[2].pvBuffer = f->footerdata;
SecBuff[3].BufferType = SECBUFFER_EMPTY;
SecBuff[3].cbBuffer = 0;
SecBuff[3].pvBuffer = NULL;
ss = secur.pEncryptMessage(&f->sechnd, ulQop, &BuffDesc, 0);
@ -367,9 +402,19 @@ static struct
};
char *narrowen(char *out, size_t outlen, wchar_t *wide);
static DWORD VerifyKnownCertificates(DWORD status, wchar_t *domain, qbyte *data, size_t datasize)
static DWORD VerifyKnownCertificates(DWORD status, wchar_t *domain, qbyte *data, size_t datasize, qboolean datagram)
{
int i;
if (datagram)
{
Con_Printf("FIXME: Ring of trust not yet implemented\n");
if (status == CERT_E_UNTRUSTEDROOT)
{
Con_Printf("Allowing (probably) self-signed cert.\n");
status = SEC_E_OK;
}
return status;
}
for (i = 0; knowncerts[i].hostname; i++)
{
if (!wcscmp(domain, knowncerts[i].hostname))
@ -409,7 +454,7 @@ static DWORD VerifyKnownCertificates(DWORD status, wchar_t *domain, qbyte *data,
return status;
}
static DWORD VerifyServerCertificate(PCCERT_CONTEXT pServerCert, PWSTR pwszServerName, DWORD dwCertFlags)
static DWORD VerifyServerCertificate(PCCERT_CONTEXT pServerCert, PWSTR pwszServerName, DWORD dwCertFlags, qboolean datagram)
{
HTTPSPolicyCallbackData polHttps;
CERT_CHAIN_POLICY_PARA PolicyPara;
@ -465,7 +510,7 @@ static DWORD VerifyServerCertificate(PCCERT_CONTEXT pServerCert, PWSTR pwszServe
}
else
{
Status = VerifyKnownCertificates(PolicyStatus.dwError, pwszServerName, pServerCert->pbCertEncoded, pServerCert->cbCertEncoded);
Status = VerifyKnownCertificates(PolicyStatus.dwError, pwszServerName, pServerCert->pbCertEncoded, pServerCert->cbCertEncoded, datagram);
if (Status)
{
char fmsg[512];
@ -598,14 +643,18 @@ static void SSPI_Handshake (sslfile_t *f)
SECURITY_STATUS ss;
TimeStamp Lifetime;
SecBufferDesc OutBuffDesc;
SecBuffer OutSecBuff[2];
SecBuffer OutSecBuff[8];
SecBufferDesc InBuffDesc;
SecBuffer InSecBuff[3];
SecBuffer InSecBuff[8];
ULONG ContextAttributes;
SCHANNEL_CRED SchannelCred;
int i;
qboolean retries = 5;
char buf1[128];
char buf2[128];
// char buf1[128];
// char buf2[128];
retry:
if (f->outcrypt.avail)
{
@ -618,16 +667,19 @@ static void SSPI_Handshake (sslfile_t *f)
//FIXME: skip this if we've had no new data since last time
OutBuffDesc.ulVersion = SECBUFFER_VERSION;
OutBuffDesc.cBuffers = 2;
OutBuffDesc.cBuffers = countof(OutSecBuff);
OutBuffDesc.pBuffers = OutSecBuff;
OutSecBuff[0].cbBuffer = f->outcrypt.datasize - f->outcrypt.avail;
OutSecBuff[0].BufferType = SECBUFFER_TOKEN;
OutSecBuff[0].cbBuffer = f->outcrypt.datasize - f->outcrypt.avail;
OutSecBuff[0].pvBuffer = f->outcrypt.data + f->outcrypt.avail;
OutSecBuff[1].BufferType = 16;//SECBUFFER_TARGET_HOST;
OutSecBuff[1].pvBuffer = buf1;
OutSecBuff[1].cbBuffer = sizeof(buf1);
for (i = 0; i < OutBuffDesc.cBuffers; i++)
{
OutSecBuff[i].BufferType = SECBUFFER_EMPTY;
OutSecBuff[i].pvBuffer = NULL;
OutSecBuff[i].cbBuffer = 0;
}
if (f->handshaking == HS_ERROR)
return; //gave up.
@ -653,29 +705,52 @@ static void SSPI_Handshake (sslfile_t *f)
else if (f->handshaking == HS_CLIENT)
{
//only if we actually have data.
if (!f->incrypt.avail)
if (!f->incrypt.avail && !f->datagram)
return;
InBuffDesc.ulVersion = SECBUFFER_VERSION;
InBuffDesc.cBuffers = 2;
InBuffDesc.cBuffers = 4;
InBuffDesc.pBuffers = InSecBuff;
InSecBuff[0].BufferType = SECBUFFER_TOKEN;
InSecBuff[0].cbBuffer = f->incrypt.avail;
InSecBuff[0].pvBuffer = f->incrypt.data;
i = 0;
InSecBuff[1].BufferType = SECBUFFER_EMPTY;
InSecBuff[1].pvBuffer = NULL;
InSecBuff[1].cbBuffer = 0;
if (f->incrypt.avail)
{
InSecBuff[i].BufferType = SECBUFFER_TOKEN;
InSecBuff[i].cbBuffer = f->incrypt.avail;
InSecBuff[i].pvBuffer = f->incrypt.data;
i++;
}
ss = secur.pInitializeSecurityContextA (&f->cred, &f->sechnd, NULL, MessageAttribute|(f->datagram?ISC_REQ_DATAGRAM:ISC_REQ_STREAM), 0, SECURITY_NATIVE_DREP, &InBuffDesc, 0, &f->sechnd, &OutBuffDesc, &ContextAttributes, &Lifetime);
for (; i < InBuffDesc.cBuffers; i++)
{
InSecBuff[i].BufferType = SECBUFFER_EMPTY;
InSecBuff[i].pvBuffer = NULL;
InSecBuff[i].cbBuffer = 0;
}
ss = secur.pInitializeSecurityContextW (&f->cred, &f->sechnd, NULL, MessageAttribute|(f->datagram?ISC_REQ_DATAGRAM:ISC_REQ_STREAM), 0, SECURITY_NETWORK_DREP, &InBuffDesc, 0, &f->sechnd, &OutBuffDesc, &ContextAttributes, &Lifetime);
if (ss == SEC_E_INCOMPLETE_MESSAGE)
{
if (f->incrypt.avail == f->incrypt.datasize)
// Con_Printf("SEC_E_INCOMPLETE_MESSAGE\n");
if (!f->datagram && f->incrypt.avail == f->incrypt.datasize)
SSPI_ExpandBuffer(&f->incrypt, f->incrypt.datasize+1024);
return;
}
else if (ss == SEC_E_INVALID_TOKEN)
{
// Con_Printf("SEC_E_INVALID_TOKEN\n");
if (f->datagram)
return; //our udp protocol may have non-dtls packets mixed in. besides, we don't want to die from spoofed packets.
}
// else if (ss == SEC_I_MESSAGE_FRAGMENT)
// Con_Printf("SEC_I_MESSAGE_FRAGMENT\n");
// else if (ss == SEC_I_CONTINUE_NEEDED)
// Con_Printf("SEC_I_CONTINUE_NEEDED\n");
// else
// Con_Printf("InitializeSecurityContextA %x\n", ss);
//any extra data should still remain for the next time around. this might be more handshake data or payload data.
if (InSecBuff[1].BufferType == SECBUFFER_EXTRA)
@ -692,29 +767,49 @@ static void SSPI_Handshake (sslfile_t *f)
return;
InBuffDesc.ulVersion = SECBUFFER_VERSION;
InBuffDesc.cBuffers = 3;
InBuffDesc.cBuffers = countof(InSecBuff);
InBuffDesc.pBuffers = InSecBuff;
i = 0;
InSecBuff[0].BufferType = SECBUFFER_TOKEN;
InSecBuff[0].cbBuffer = f->incrypt.avail;
InSecBuff[0].pvBuffer = f->incrypt.data;
InSecBuff[1].BufferType = SECBUFFER_EMPTY;
InSecBuff[1].pvBuffer = NULL;
InSecBuff[1].cbBuffer = 0;
InSecBuff[2].BufferType = 16;//SECBUFFER_TARGET_HOST;
InSecBuff[2].pvBuffer = buf2;
InSecBuff[2].cbBuffer = sizeof(buf2);
ss = secur.pAcceptSecurityContext(&f->cred, (f->handshaking==HS_SERVER)?&f->sechnd:NULL, &InBuffDesc, ASC_REQ_ALLOCATE_MEMORY|ASC_REQ_STREAM|ASC_REQ_CONFIDENTIALITY, SECURITY_NATIVE_DREP, &f->sechnd, &OutBuffDesc, &ContextAttributes, &Lifetime);
if (ss == SEC_E_INCOMPLETE_MESSAGE)
if (f->incrypt.avail)
{
if (f->incrypt.avail == f->incrypt.datasize)
InSecBuff[i].BufferType = SECBUFFER_TOKEN;
InSecBuff[i].cbBuffer = f->incrypt.avail;
InSecBuff[i].pvBuffer = f->incrypt.data;
i++;
}
for (; i < InBuffDesc.cBuffers; i++)
{
InSecBuff[i].BufferType = SECBUFFER_EMPTY;
InSecBuff[i].pvBuffer = NULL;
InSecBuff[i].cbBuffer = 0;
}
i = 1;
OutSecBuff[i++].BufferType = SECBUFFER_EXTRA;
OutSecBuff[i++].BufferType = 17/*SECBUFFER_ALERT*/;
#define ServerMessageAttribute (ASC_REQ_SEQUENCE_DETECT | ASC_REQ_REPLAY_DETECT | ASC_REQ_CONFIDENTIALITY /*| ASC_REQ_EXTENDED_ERROR*/ | ASC_REQ_ALLOCATE_MEMORY)
ss = secur.pAcceptSecurityContext(&f->cred, (f->handshaking==HS_SERVER)?&f->sechnd:NULL, &InBuffDesc,
ServerMessageAttribute|(f->datagram?ASC_REQ_DATAGRAM:ASC_REQ_STREAM), SECURITY_NETWORK_DREP, &f->sechnd,
&OutBuffDesc, &ContextAttributes, NULL);
if (ss == SEC_E_INVALID_TOKEN)
{
// Con_Printf("SEC_E_INVALID_TOKEN\n");
if (f->datagram)
return;
}
else if (ss == SEC_E_INCOMPLETE_MESSAGE)
{
// Con_Printf("SEC_E_INCOMPLETE_MESSAGE\n");
if (!f->datagram && f->incrypt.avail == f->incrypt.datasize)
SSPI_ExpandBuffer(&f->incrypt, f->incrypt.datasize+1024);
return;
}
// else
// Con_Printf("InitializeSecurityContextA %x\n", ss);
f->handshaking = HS_SERVER;
//any extra data should still remain for the next time around. this might be more handshake data or payload data.
@ -743,7 +838,8 @@ static void SSPI_Handshake (sslfile_t *f)
case SEC_E_INVALID_HANDLE: SSPI_Error(f, "InitializeSecurityContext failed: SEC_E_INVALID_HANDLE\n"); break;
case SEC_E_ILLEGAL_MESSAGE: SSPI_Error(f, "InitializeSecurityContext failed: SEC_E_ILLEGAL_MESSAGE\n"); break;
case SEC_E_INVALID_TOKEN: SSPI_Error(f, "InitializeSecurityContext failed: SEC_E_INVALID_TOKEN\n"); break;
default: SSPI_Error(f, "InitializeSecurityContext failed: %#lx\n", ss); break;
case SEC_E_INVALID_PARAMETER: SSPI_Error(f, "InitializeSecurityContext failed: SEC_E_INVALID_PARAMETER\n"); break;
default: SSPI_Error(f, "InitializeSecurityContext failed: %lx\n", (long)ss); break;
}
return;
}
@ -758,15 +854,6 @@ static void SSPI_Handshake (sslfile_t *f)
}
}
if (SSPI_CopyIntoBuffer(&f->outcrypt, OutSecBuff[0].pvBuffer, OutSecBuff[0].cbBuffer, true) < OutSecBuff[0].cbBuffer)
{
SSPI_Error(f, "crypt overflow\n");
return;
}
//send early, send often.
SSPI_TryFlushCryptOut(f);
//its all okay and established if we get this far.
if (ss == SEC_E_OK)
{
@ -787,7 +874,7 @@ static void SSPI_Handshake (sslfile_t *f)
SSPI_Error(f, "unable to read server's certificate\n");
return;
}
if (VerifyServerCertificate(remotecert, f->wpeername, 0))
if (VerifyServerCertificate(remotecert, f->wpeername, 0, f->datagram))
{
f->handshaking = HS_ERROR;
SSPI_Error(f, "Error validating certificante\n");
@ -799,9 +886,33 @@ static void SSPI_Handshake (sslfile_t *f)
}
f->handshaking = HS_ESTABLISHED;
SSPI_Encode(f);
}
//send early, send often.
#ifdef HAVE_DTLS
if (f->transmit)
{
for (i = 0; i < OutBuffDesc.cBuffers; i++)
if (OutSecBuff[i].BufferType == SECBUFFER_TOKEN && OutSecBuff[i].cbBuffer)
f->transmit(f->cbctx, OutSecBuff[i].pvBuffer, OutSecBuff[i].cbBuffer);
}
else
#endif
{
i = 0;
if (SSPI_CopyIntoBuffer(&f->outcrypt, OutSecBuff[i].pvBuffer, OutSecBuff[i].cbBuffer, true) < OutSecBuff[i].cbBuffer)
{
SSPI_Error(f, "crypt overflow\n");
return;
}
SSPI_TryFlushCryptOut(f);
}
if (f->handshaking == HS_ESTABLISHED)
SSPI_Encode(f);
else if (ss == SEC_I_MESSAGE_FRAGMENT) //looks like we can connect faster if we loop when we get this result.
if (retries --> 0)
goto retry;
}
static int QDECL SSPI_ReadBytes (struct vfsfile_s *file, void *buffer, int bytestoread)
@ -886,7 +997,7 @@ static qboolean QDECL SSPI_Close (struct vfsfile_s *file)
}
#include <wchar.h>
vfsfile_t *FS_OpenSSL(const char *servername, vfsfile_t *source, qboolean server, qboolean datagram)
vfsfile_t *FS_OpenSSL(const char *servername, vfsfile_t *source, qboolean server)
{
sslfile_t *newf;
int i = 0;
@ -938,7 +1049,6 @@ vfsfile_t *FS_OpenSSL(const char *servername, vfsfile_t *source, qboolean server
}
newf->wpeername[i] = 0;
newf->datagram = datagram;
newf->handshaking = server?HS_STARTSERVER:HS_STARTCLIENT;
newf->stream = source;
newf->funcs.Close = SSPI_Close;
@ -960,4 +1070,163 @@ vfsfile_t *FS_OpenSSL(const char *servername, vfsfile_t *source, qboolean server
return &newf->funcs;
}
#if 0
struct nulldtls_s
{
void *cbctx;
neterr_t(*push)(void *cbctx, const qbyte *data, size_t datasize);
};
void *DTLS_CreateContext(void *cbctx, neterr_t(*push)(void *cbctx, const qbyte *data, size_t datasize), qboolean isserver)
{
struct nulldtls_s *ctx = Z_Malloc(sizeof(*ctx));
ctx->cbctx = cbctx;
ctx->push = push;
return ctx;
}
qboolean DTLS_HasServerCertificate(void)
{
//FIXME: at this point, schannel is still returning errors when I try acting as a server.
//so just block any attempt to use this as a server.
//clients don't need certs!
return false;
}
neterr_t DTLS_Transmit(void *vctx, const qbyte *data, size_t datasize)
{
struct nulldtls_s *ctx = vctx;
neterr_t r;
*(int*)data ^= 0xdeadbeef;
r = ctx->push(ctx->cbctx, data, datasize);
*(int*)data ^= 0xdeadbeef;
return r;
}
neterr_t DTLS_Received(void *ctx, qbyte *data, size_t datasize)
{
*(int*)data ^= 0xdeadbeef;
return NETERR_SENT;
}
#elif defined(HAVE_DTLS)
void *DTLS_CreateContext(char *remotehost, void *cbctx, neterr_t(*push)(void *cbctx, const qbyte *data, size_t datasize), qboolean isserver)
{
int i = 0;
sslfile_t *ctx;
if (!SSL_Inited())
return NULL;
ctx = Z_Malloc(sizeof(*ctx));
ctx->datagram = true;
ctx->handshaking = isserver?HS_STARTSERVER:HS_STARTCLIENT;
ctx->cbctx = cbctx;
ctx->transmit = push;
while(*remotehost)
{
int err;
int c = utf8_decode(&err, remotehost, (void*)&remotehost);
if (c > WCHAR_MAX)
err = true; //no 16bit surrogates. they're evil.
else if (i == sizeof(ctx->wpeername)/sizeof(ctx->wpeername[0]) - 1)
err = true; //no space to store it
else
ctx->wpeername[i++] = c;
if (err)
{
Z_Free(ctx);
return NULL;
}
}
ctx->wpeername[i] = 0;
SSPI_ExpandBuffer(&ctx->outraw, 8192);
SSPI_ExpandBuffer(&ctx->outcrypt, 65536);
SSPI_ExpandBuffer(&ctx->inraw, 8192);
SSPI_ExpandBuffer(&ctx->incrypt, 65536);
if (isserver)
SSPI_GenServerCredentials(ctx);
else
SSPI_Handshake(ctx); //begin the initial handshake now
return ctx;
}
void DTLS_DestroyContext(void *vctx)
{
SSPI_Close(vctx);
}
neterr_t DTLS_Transmit(void *ctx, const qbyte *data, size_t datasize)
{
int ret;
sslfile_t *f = (sslfile_t *)ctx;
//Con_Printf("DTLS_Transmit: %i\n", datasize);
//sspi likes writing over the source data. make sure nothing is hurt by copying it out first.
f->outraw.avail = 0;
SSPI_CopyIntoBuffer(&f->outraw, data, datasize, true);
if (f->handshaking)
{
SSPI_Handshake(f);
if (f->handshaking == HS_ERROR)
ret = NETERR_DISCONNECTED;
ret = NETERR_CLOGGED; //not ready yet
}
else
{
SSPI_Encode(f);
ret = NETERR_SENT;
}
return ret;
}
neterr_t DTLS_Received(void *ctx, qbyte *data, size_t datasize)
{
int ret;
sslfile_t *f = (sslfile_t *)ctx;
//Con_Printf("DTLS_Received: %i\n", datasize);
f->incrypt.data = data;
f->incrypt.avail = f->incrypt.datasize = datasize;
if (f->handshaking)
{
SSPI_Handshake(f);
ret = NETERR_CLOGGED; //not ready yet
if (f->handshaking == HS_ERROR)
ret = NETERR_DISCONNECTED;
}
else
{
SSPI_Decode(f);
ret = NETERR_SENT;
memcpy(net_message_buffer, f->inraw.data, f->inraw.avail);
net_message.cursize = f->inraw.avail;
f->inraw.avail = 0;
net_message_buffer[net_message.cursize] = 0;
// Con_Printf("returning %i bytes: %s\n", net_message.cursize, net_message_buffer);
}
f->incrypt.data = NULL;
return ret;
}
neterr_t DTLS_Timeouts(void *ctx)
{
sslfile_t *f = (sslfile_t *)ctx;
if (f->handshaking)
{
// SSPI_Handshake(f);
return NETERR_CLOGGED;
}
return NETERR_SENT;
}
#endif
#endif

View File

@ -97,13 +97,16 @@ cvar_t net_enabled = CVARD("net_enabled", "1", "If 0, disables all network
#if defined(TCPCONNECT) && !defined(CLIENTONLY)
cvar_t net_enable_qizmo = CVARD("net_enable_qizmo", "1", "Enables compatibility with qizmo's tcp connections serverside. Frankly, using sv_port_tcp without this is a bit pointless.");
cvar_t net_enable_qtv = CVARD("net_enable_qtv", "1", "Listens for qtv proxies, or clients using the qtvplay command.");
cvar_t net_enable_tls = CVARD("net_enable_tls", "1", "If enabled, binary data sent to a tcp connection will be interpretted as a tls handshake (enabling https or wss over the same tcp port.");
cvar_t net_enable_tls = CVARD("net_enable_tls", "1", "If enabled, binary data sent to a non-tls tcp port will be interpretted as a tls handshake (enabling https or wss over the same tcp port.");
cvar_t net_enable_http = CVARD("net_enable_http", "1", "If enabled, tcp ports will accept http clients, potentially serving large files which could distrupt gameplay.");
cvar_t net_enable_websockets = CVARD("net_enable_websockets", "1", "If enabled, tcp ports will accept websocket game clients.");
cvar_t net_enable_webrtcbroker = CVARD("net_enable_webrtcbroker", "1", "If 1, tcp ports will accept websocket connections from clients trying to broker direct webrtc connections. This should be low traffic, but might involve a lot of mostly-idle connections.");
#endif
extern cvar_t sv_public, sv_listen_qw, sv_listen_nq, sv_listen_dp, sv_listen_q3;
extern cvar_t sv_public, sv_listen_qw, sv_listen_nq, sv_listen_dp;
#ifdef QWOVERQ3
extern cvar_t sv_listen_q3;
#endif
#define MAX_LOOPBACK 64
typedef struct
@ -121,6 +124,14 @@ typedef struct
} loopback_t;
loopback_t loopbacks[2];
#ifdef HAVE_DTLS
static neterr_t FTENET_DTLS_SendPacket(ftenet_connections_t *col, int length, const void *data, netadr_t *to);
#endif
//=============================================================================
int NetadrToSockadr (netadr_t *a, struct sockaddr_qstorage *s)
@ -234,7 +245,6 @@ qboolean NET_AddrIsReliable(netadr_t *adr) //hints that the protocol is reliable
case NP_TLS:
case NP_WS:
case NP_WSS:
case NP_IRC:
return true;
}
}
@ -495,7 +505,6 @@ char *NET_AdrToString (char *s, int len, netadr_t *a)
case NP_TLS: prot = "tls://"; break;
case NP_WS: prot = "ws://"; break;
case NP_WSS: prot = "wss://"; break;
case NP_IRC: prot = "irc://"; break;
case NP_NATPMP: prot = "natpmp://"; break;
}
@ -679,7 +688,6 @@ char *NET_BaseAdrToString (char *s, int len, netadr_t *a)
case NP_TLS: prot = "tls://"; break;
case NP_WS: prot = "ws://"; break;
case NP_WSS: prot = "wss://"; break;
case NP_IRC: prot = "irc://"; break;
case NP_NATPMP: prot = "natpmp://"; break;
}
@ -1141,11 +1149,11 @@ size_t NET_StringToAdr2 (const char *s, int defaultport, netadr_t *a, size_t num
a->prot = NP_STREAM;
return true;
}
if (!strncmp (s, "ws://", 7))
if (!strncmp (s, "ws://", 5))
{
//make sure that the rest of the address is a valid ip address (4 or 6)
if (!NET_StringToSockaddr (s+6, defaultport, &sadr[0], NULL, NULL))
if (!NET_StringToSockaddr (s+5, defaultport, &sadr[0], NULL, NULL))
{
a->type = NA_INVALID;
return false;
@ -1155,7 +1163,7 @@ size_t NET_StringToAdr2 (const char *s, int defaultport, netadr_t *a, size_t num
a->prot = NP_WS;
return true;
}
if (!strncmp (s, "wss://", 7))
if (!strncmp (s, "wss://", 6))
{
//make sure that the rest of the address is a valid ip address (4 or 6)
@ -1171,9 +1179,10 @@ size_t NET_StringToAdr2 (const char *s, int defaultport, netadr_t *a, size_t num
}
if (!strncmp (s, "dtls://", 7))
{
#ifdef HAVE_DTLS
//make sure that the rest of the address is a valid ip address (4 or 6)
if (!NET_StringToSockaddr (s+6, defaultport, &sadr[0], NULL, NULL))
if (!NET_StringToSockaddr (s+7, defaultport, &sadr[0], NULL, NULL))
{
a->type = NA_INVALID;
return false;
@ -1182,6 +1191,9 @@ size_t NET_StringToAdr2 (const char *s, int defaultport, netadr_t *a, size_t num
SockadrToNetadr (&sadr[0], a);
a->prot = NP_DTLS;
return true;
#else
return false;
#endif
}
if (!strncmp (s, "tls://", 6))
{
@ -2217,6 +2229,144 @@ ftenet_generic_connection_t *FTENET_NATPMP_EstablishConnection(qboolean isserver
}
#endif
#ifdef HAVE_DTLS
struct dtlspeer_s
{
ftenet_connections_t *col;
void *dtlsstate;
netadr_t addr;
float timeout;
struct dtlspeer_s *next;
struct dtlspeer_s **link;
};
void NET_DTLS_Timeouts(ftenet_connections_t *col)
{
struct dtlspeer_s *peer;
if (!col)
return;
for (peer = col->dtls; peer; peer = peer->next)
{
DTLS_Timeouts(peer->dtlsstate);
}
}
static neterr_t NET_SendPacketCol (ftenet_connections_t *collection, int length, const void *data, netadr_t *to);
static neterr_t FTENET_DTLS_DoSendPacket(void *cbctx, const qbyte *data, size_t length)
{ //callback that does the actual sending
struct dtlspeer_s *peer = cbctx;
return NET_SendPacketCol(peer->col, length, data, &peer->addr);
}
qboolean NET_DTLS_Create(ftenet_connections_t *col, netadr_t *to)
{
struct dtlspeer_s *peer;
if (to->prot != NP_DGRAM)
return false;
for (peer = col->dtls; peer; peer = peer->next)
{
if (NET_CompareAdr(&peer->addr, to))
break;
}
if (!peer)
{
char hostname[256];
peer = Z_Malloc(sizeof(*peer));
peer->addr = *to;
peer->col = col;
peer->dtlsstate = DTLS_CreateContext(NET_BaseAdrToString(hostname, sizeof(hostname), to), peer, FTENET_DTLS_DoSendPacket, col->islisten);
Sys_Printf("Created %p\n", peer->dtlsstate);
if (peer->next)
peer->next->link = &peer->next;
peer->link = &col->dtls;
peer->next = col->dtls;
col->dtls = peer;
}
return true;
}
static void NET_DTLS_DisconnectPeer(ftenet_connections_t *col, struct dtlspeer_s *peer)
{
// Sys_Printf("Destroy %p\n", peer->dtlsstate);
if (peer->next)
peer->next->link = peer->link;
*peer->link = peer->next;
DTLS_DestroyContext(peer->dtlsstate);
Z_Free(peer);
}
qboolean NET_DTLS_Disconnect(ftenet_connections_t *col, netadr_t *to)
{
struct dtlspeer_s *peer;
netadr_t n = *to;
if (!col || (to->prot != NP_DGRAM && to->prot != NP_DTLS))
return false;
n.prot = NP_DGRAM;
for (peer = col->dtls; peer; peer = peer->next)
{
if (NET_CompareAdr(&peer->addr, &n))
{
NET_DTLS_DisconnectPeer(col, peer);
break;
}
}
return peer?true:false;
}
static neterr_t FTENET_DTLS_SendPacket(ftenet_connections_t *col, int length, const void *data, netadr_t *to)
{
struct dtlspeer_s *peer;
to->prot = NP_DGRAM;
for (peer = col->dtls; peer; peer = peer->next)
{
if (NET_CompareAdr(&peer->addr, to))
break;
}
to->prot = NP_DTLS;
if (peer)
return DTLS_Transmit(peer->dtlsstate, data, length);
else
return NETERR_NOROUTE;
}
qboolean NET_DTLS_Decode(ftenet_connections_t *col)
{
struct dtlspeer_s *peer;
for (peer = col->dtls; peer; peer = peer->next)
{
if (NET_CompareAdr(&peer->addr, &net_from))
{
switch(DTLS_Received(peer->dtlsstate, net_message.data, net_message.cursize))
{
case NETERR_DISCONNECTED:
Sys_Printf("disconnected %p\n", peer->dtlsstate);
NET_DTLS_DisconnectPeer(col, peer);
break;
case NETERR_NOROUTE:
return false; //not a valid dtls packet.
default:
case NETERR_CLOGGED:
//ate it
net_message.cursize = 0;
break;
case NETERR_SENT:
//we decoded it properly
break;
}
net_from.prot = NP_DTLS;
return true;
}
}
return false;
}
#endif
static qboolean FTENET_AddToCollection_Ptr(ftenet_connections_t *col, const char *name, ftenet_generic_connection_t *(*establish)(qboolean isserver, const char *address, netadr_t adr), qboolean islisten, const char *address, netadr_t *adr)
{
int count = 0;
@ -2300,10 +2450,10 @@ qboolean FTENET_AddToCollection(ftenet_connections_t *col, const char *name, con
if (adr[i].prot == NP_DGRAM && adr[i].type == NA_LOOPBACK) establish[i] = FTENET_Loop_EstablishConnection; else
#endif
#ifdef HAVE_IPV4
if (adr[i].prot == NP_DGRAM && adr[i].type == NA_IP) establish[i] = FTENET_Datagram_EstablishConnection; else
if ((adr[i].prot == NP_DGRAM) && adr[i].type == NA_IP) establish[i] = FTENET_Datagram_EstablishConnection; else
#endif
#ifdef HAVE_IPV6
if (adr[i].prot == NP_DGRAM && adr[i].type == NA_IPV6) establish[i] = FTENET_Datagram_EstablishConnection; else
if ((adr[i].prot == NP_DGRAM) && adr[i].type == NA_IPV6) establish[i] = FTENET_Datagram_EstablishConnection; else
#endif
#ifdef USEIPX
if (adr[i].prot == NP_DGRAM && adr[i].type == NA_IPX) establish[i] = FTENET_Datagram_EstablishConnection; else
@ -4021,7 +4171,8 @@ static int QDECL TLSPromoteRead (struct vfsfile_s *file, void *buffer, int bytes
if (bytestoread > net_message.cursize)
bytestoread = net_message.cursize;
memcpy(buffer, net_message_buffer, bytestoread);
net_message.cursize = 0;
net_message.cursize -= bytestoread;
memmove(net_message_buffer, net_message_buffer+bytestoread, net_message.cursize);
return bytestoread;
}
#endif
@ -4120,7 +4271,8 @@ qboolean FTENET_TCPConnect_GetPacket(ftenet_generic_connection_t *gcon)
{
Con_Printf ("tcp peer %s closed connection\n", NET_AdrToString (adr, sizeof(adr), &st->remoteaddr));
closesvstream:
VFS_CLOSE(st->clientstream);
if (st->clientstream)
VFS_CLOSE(st->clientstream);
st->clientstream = NULL;
continue;
}
@ -4143,13 +4295,16 @@ closesvstream:
memcpy(net_message_buffer, st->inbuffer, st->inlen);
net_message.cursize = st->inlen;
//wrap the stream now
st->clientstream = FS_OpenSSL(NULL, st->clientstream, true, false);
st->clientstream = FS_OpenSSL(NULL, st->clientstream, true);
st->remoteaddr.prot = NP_TLS;
//try and reclaim it all
st->inlen = VFS_READ(st->clientstream, st->inbuffer, sizeof(st->inbuffer)-1);
//make sure we actually read from the proper stream again
stream->ReadBytes = realread;
if (net_message.cursize)
if (st->clientstream)
{
//try and reclaim it all
st->inlen = VFS_READ(st->clientstream, st->inbuffer, sizeof(st->inbuffer)-1);
//make sure we actually read from the proper stream again
stream->ReadBytes = realread;
}
if (!st->clientstream || net_message.cursize)
goto closesvstream; //something cocked up. we didn't give the tls stream all the data.
net_message.cursize = 0;
continue;
@ -4564,7 +4719,7 @@ closesvstream:
#ifdef HAVE_SSL
if (con->tls && st->clientstream) //if we're meant to be using tls, wrap the stream in a tls connection
{
st->clientstream = FS_OpenSSL(NULL, st->clientstream, true, false);
st->clientstream = FS_OpenSSL(NULL, st->clientstream, true);
/*sockadr doesn't contain transport info, so fix that up here*/
st->remoteaddr.prot = NP_TLS;
}
@ -4890,7 +5045,7 @@ ftenet_generic_connection_t *FTENET_TCPConnect_EstablishConnection(qboolean isse
#ifdef HAVE_SSL
if (newcon->tls) //if we're meant to be using tls, wrap the stream in a tls connection
newcon->tcpstreams->clientstream = FS_OpenSSL(address, newcon->tcpstreams->clientstream, false, false);
newcon->tcpstreams->clientstream = FS_OpenSSL(address, newcon->tcpstreams->clientstream, false);
#endif
//send the qizmo greeting.
@ -6202,21 +6357,20 @@ int NET_GetPacket (netsrc_t netsrc, int firstsock)
while (firstsock < MAX_CONNECTIONS)
{
if (!collection->conn[firstsock])
break;
if (collection->conn[firstsock]->GetPacket(collection->conn[firstsock]))
{
if (net_fakeloss.value)
if (collection->conn[firstsock])
if (collection->conn[firstsock]->GetPacket(collection->conn[firstsock]))
{
if (frandom () < net_fakeloss.value)
continue;
}
if (net_fakeloss.value)
{
if (frandom () < net_fakeloss.value)
continue;
}
collection->bytesin += net_message.cursize;
collection->packetsin += 1;
net_from.connum = firstsock+1;
return firstsock;
}
collection->bytesin += net_message.cursize;
collection->packetsin += 1;
net_from.connum = firstsock+1;
return firstsock;
}
firstsock += 1;
}
@ -6254,32 +6408,11 @@ int NET_LocalAddressForRemote(ftenet_connections_t *collection, netadr_t *remote
return collection->conn[remote->connum-1]->GetLocalAddresses(collection->conn[remote->connum-1], &adrflags, local, 1);
}
neterr_t NET_SendPacket (netsrc_t netsrc, int length, const void *data, netadr_t *to)
static neterr_t NET_SendPacketCol (ftenet_connections_t *collection, int length, const void *data, netadr_t *to)
{
neterr_t err;
// char buffer[64];
ftenet_connections_t *collection;
int i;
if (netsrc == NS_SERVER)
{
#ifdef CLIENTONLY
Sys_Error("NET_GetPacket: Bad netsrc");
return NETERR_NOROUTE;
#else
collection = svs.sockets;
#endif
}
else
{
#ifdef SERVERONLY
Sys_Error("NET_GetPacket: Bad netsrc");
return NETERR_NOROUTE;
#else
collection = cls.sockets;
#endif
}
if (!collection)
return NETERR_NOROUTE;
@ -6338,6 +6471,35 @@ neterr_t NET_SendPacket (netsrc_t netsrc, int length, const void *data, netadr_t
return NETERR_NOROUTE;
}
neterr_t NET_SendPacket (netsrc_t netsrc, int length, const void *data, netadr_t *to)
{
ftenet_connections_t *collection;
if (netsrc == NS_SERVER)
{
#ifdef CLIENTONLY
Sys_Error("NET_GetPacket: Bad netsrc");
return NETERR_NOROUTE;
#else
collection = svs.sockets;
#endif
}
else
{
#ifdef SERVERONLY
Sys_Error("NET_GetPacket: Bad netsrc");
return NETERR_NOROUTE;
#else
collection = cls.sockets;
#endif
}
#ifdef HAVE_DTLS
if (to->prot == NP_DTLS)
return FTENET_DTLS_SendPacket(collection, length, data, to);
#endif
return NET_SendPacketCol (collection, length, data, to);
}
qboolean NET_EnsureRoute(ftenet_connections_t *collection, char *routename, char *host, qboolean islisten)
{
netadr_t adr;
@ -6347,11 +6509,15 @@ qboolean NET_EnsureRoute(ftenet_connections_t *collection, char *routename, char
switch(adr.prot)
{
case NP_DTLS:
#ifdef HAVE_DTLS
// if (FTENET_DTLS_Create(collection, &adr) == NETERR_NOROUTE)
/// return false;
break;
#endif
case NP_WS:
case NP_WSS:
case NP_TLS:
case NP_STREAM:
case NP_IRC:
if (!FTENET_AddToCollection(collection, routename, host, adr.type, adr.prot, islisten))
return false;
Con_Printf("Establishing connection to %s\n", host);
@ -6496,6 +6662,15 @@ void NET_PrintConnectionsStatus(ftenet_connections_t *collection)
if (collection->conn[i]->PrintStatus)
collection->conn[i]->PrintStatus(collection->conn[i]);
}
#ifdef HAVE_DTLS
{
struct dtlspeer_s *dtls;
char adr[64];
for (dtls = collection->dtls; dtls; dtls = dtls->next)
Con_Printf("dtls: %s\n", NET_AdrToString(adr, sizeof(adr), &dtls->addr));
}
#endif
}
//=============================================================================
@ -6977,7 +7152,7 @@ void NET_ClientPort_f(void)
qboolean NET_WasSpecialPacket(netsrc_t netsrc)
{
#ifdef HAVE_NATPMP
#if defined(HAVE_NATPMP)
ftenet_connections_t *collection = NULL;
if (netsrc == NS_SERVER)
{
@ -6991,16 +7166,18 @@ qboolean NET_WasSpecialPacket(netsrc_t netsrc)
collection = cls.sockets;
#endif
}
#ifdef HAVE_NATPMP
if (NET_Was_NATPMP(collection))
return true;
#endif
#endif
#ifdef SUPPORT_ICE
if (ICE_WasStun(netsrc))
return true;
#endif
#ifdef HAVE_NATPMP
if (NET_Was_NATPMP(collection))
return true;
#endif
return false;
}
@ -7065,6 +7242,11 @@ void NET_Init (void)
Net_Master_Init();
}
#ifndef SERVERONLY
void NET_CloseClient(void)
{ //called by disconnect console command
FTENET_CloseCollection(cls.sockets);
cls.sockets = NULL;
}
void NET_InitClient(qboolean loopbackonly)
{
const char *port;
@ -7201,6 +7383,16 @@ void SVNET_RegisterCvars(void)
Cvar_Register (&sv_port_natpmp, "networking");
sv_port_natpmp.restriction = RESTRICT_MAX;
#endif
#if defined(TCPCONNECT) && !defined(CLIENTONLY)
Cvar_Register (&net_enable_qizmo, "networking");
Cvar_Register (&net_enable_qtv, "networking");
Cvar_Register (&net_enable_tls, "networking");
Cvar_Register (&net_enable_http, "networking");
Cvar_Register (&net_enable_websockets, "networking");
Cvar_Register (&net_enable_webrtcbroker, "networking");
#endif
}
void NET_CloseServer(void)
@ -7211,7 +7403,11 @@ void NET_CloseServer(void)
void NET_InitServer(void)
{
if (sv_listen_nq.value || sv_listen_dp.value || sv_listen_qw.value || sv_listen_q3.ival)
if (sv_listen_nq.value || sv_listen_dp.value || sv_listen_qw.value
#ifdef QWOVERQ3
|| sv_listen_q3.ival
#endif
)
{
if (!svs.sockets)
{

View File

@ -292,6 +292,17 @@ typedef struct ftenet_generic_connection_s {
#endif
} ftenet_generic_connection_t;
#ifdef HAVE_DTLS
void *DTLS_CreateContext(char *remotehost, void *cbctx, neterr_t(*push)(void *cbctx, const qbyte *data, size_t datasize), qboolean isserver); //if remotehost is null then their certificate will not be validated.
void DTLS_DestroyContext(void *ctx);
neterr_t DTLS_Transmit(void *ctx, const qbyte *data, size_t datasize);
neterr_t DTLS_Received(void *ctx, qbyte *data, size_t datasize);
neterr_t DTLS_Timeouts(void *ctx);
qboolean DTLS_HasServerCertificate(void);
#endif
#define MAX_CONNECTIONS 8
typedef struct ftenet_connections_s
{
@ -306,6 +317,10 @@ typedef struct ftenet_connections_s
float bytesinrate;
float bytesoutrate;
ftenet_generic_connection_t *conn[MAX_CONNECTIONS];
#ifdef HAVE_DTLS
struct dtlspeer_s *dtls; //linked list. linked lists are shit, but at least it keeps pointers valid when things are resized.
#endif
} ftenet_connections_t;
void ICE_Tick(void);
@ -318,7 +333,7 @@ void FTENET_CloseCollection(ftenet_connections_t *col);
qboolean FTENET_AddToCollection(struct ftenet_connections_s *col, const char *name, const char *address, netadrtype_t addrtype, netproto_t addrprot, qboolean islisten);
int NET_EnumerateAddresses(ftenet_connections_t *collection, struct ftenet_generic_connection_s **con, unsigned int *adrflags, netadr_t *addresses, int maxaddresses);
vfsfile_t *FS_OpenSSL(const char *hostname, vfsfile_t *source, qboolean server, qboolean datagram);
vfsfile_t *FS_OpenSSL(const char *hostname, vfsfile_t *source, qboolean server);
#ifdef HAVE_PACKET
vfsfile_t *FS_OpenTCPSocket(SOCKET socket, qboolean conpending, const char *peername); //conpending allows us to reject any writes until the connection has succeeded
#endif

View File

@ -1085,7 +1085,7 @@ qintptr_t VARGS Plug_Net_SetTLSClient(void *offset, quintptr_t mask, const qintp
return -2;
}
stream->vfs = FS_OpenSSL(VM_POINTER(arg[1]), stream->vfs, false, false);
stream->vfs = FS_OpenSSL(VM_POINTER(arg[1]), stream->vfs, false);
if (!stream->vfs)
{
Plug_Net_Close_Internal(handle);

View File

@ -98,11 +98,15 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#endif
#define PROTOCOL_VERSION_VARLENGTH (('v'<<0) + ('l'<<8) + ('e'<<16) + ('n' << 24)) //variable length handshake
#define PROTOCOL_VERSION_FTE (('F'<<0) + ('T'<<8) + ('E'<<16) + ('X' << 24)) //fte extensions.
#define PROTOCOL_VERSION_FTE2 (('F'<<0) + ('T'<<8) + ('E'<<16) + ('2' << 24)) //fte extensions.
#define PROTOCOL_VERSION_HUFFMAN (('H'<<0) + ('U'<<8) + ('F'<<16) + ('F' << 24)) //packet compression
#define PROTOCOL_VERSION_VARLENGTH (('v'<<0) + ('l'<<8) + ('e'<<16) + ('n' << 24)) //variable length handshake
#define PROTOCOL_VERSION_FRAGMENT (('F'<<0) + ('R'<<8) + ('A'<<16) + ('G' << 24)) //supports fragmentation/packets larger than 1450
#ifdef HAVE_DTLS
#define PROTOCOL_VERSION_DTLSUPGRADE (('D'<<0) + ('T'<<8) + ('L'<<16) + ('S' << 24)) //server supports dtls. clients should dtlsconnect THEN continue connecting (also allows dtls rcon!).
#endif
#define PROTOCOL_INFO_GUID (('G'<<0) + ('U'<<8) + ('I'<<16) + ('D' << 24)) //globally 'unique' client id info.
@ -1733,3 +1737,5 @@ typedef struct q1usercmd_s
#define E5_EXTEND4 (1<<31)
#define E5_ALLUNUSED (E5_UNUSED27|E5_UNUSED28|E5_UNUSED29|E5_UNUSED30)
#define E5_SERVERPRIVATE (E5_EXTEND1|E5_EXTEND2|E5_EXTEND3|E5_EXTEND4)
#define E5_SERVERREMOVE E5_EXTEND1

View File

@ -556,7 +556,8 @@ Global
{482A886A-5755-4DAE-AD5F-D7CD4A990F9E}.Debug|Win32.ActiveCfg = Debug Dedicated Server|x64
{482A886A-5755-4DAE-AD5F-D7CD4A990F9E}.Debug|x64.ActiveCfg = Debug Dedicated Server|x64
{482A886A-5755-4DAE-AD5F-D7CD4A990F9E}.Debug|x64.Build.0 = Debug Dedicated Server|x64
{482A886A-5755-4DAE-AD5F-D7CD4A990F9E}.GLDebug|Win32.ActiveCfg = Debug Dedicated Server|x64
{482A886A-5755-4DAE-AD5F-D7CD4A990F9E}.GLDebug|Win32.ActiveCfg = Debug Dedicated Server|Win32
{482A886A-5755-4DAE-AD5F-D7CD4A990F9E}.GLDebug|Win32.Build.0 = Debug Dedicated Server|Win32
{482A886A-5755-4DAE-AD5F-D7CD4A990F9E}.GLDebug|x64.ActiveCfg = Debug Dedicated Server|x64
{482A886A-5755-4DAE-AD5F-D7CD4A990F9E}.GLRelease|Win32.ActiveCfg = Debug Dedicated Server|x64
{482A886A-5755-4DAE-AD5F-D7CD4A990F9E}.GLRelease|x64.ActiveCfg = Debug Dedicated Server|x64
@ -580,7 +581,7 @@ Global
{482A886A-5755-4DAE-AD5F-D7CD4A990F9E}.Release|Win32.ActiveCfg = Release Dedicated Server|x64
{482A886A-5755-4DAE-AD5F-D7CD4A990F9E}.Release|x64.ActiveCfg = Release Dedicated Server|x64
{482A886A-5755-4DAE-AD5F-D7CD4A990F9E}.Release|x64.Build.0 = Release Dedicated Server|x64
{482A886A-5755-4DAE-AD5F-D7CD4A990F9E}.VkDebug|Win32.ActiveCfg = Debug Dedicated Server|x64
{482A886A-5755-4DAE-AD5F-D7CD4A990F9E}.VkDebug|Win32.ActiveCfg = Debug Dedicated Server|Win32
{482A886A-5755-4DAE-AD5F-D7CD4A990F9E}.VkDebug|x64.ActiveCfg = Debug Dedicated Server|x64
{482A886A-5755-4DAE-AD5F-D7CD4A990F9E}.VkRelease|Win32.ActiveCfg = Debug Dedicated Server|x64
{482A886A-5755-4DAE-AD5F-D7CD4A990F9E}.VkRelease|x64.ActiveCfg = Debug Dedicated Server|x64

View File

@ -7250,6 +7250,53 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND
"}\n"
"#endif\n"
},
#endif
#ifdef GLQUAKE
{QR_OPENGL, 110, "itemtimer",
"!!permu FOG\n"
"#include \"sys/defs.h\"\n"
"#include \"sys/fog.h\"\n"
"varying vec2 tc;\n"
"varying vec4 vc;\n"
"#ifdef VERTEX_SHADER\n"
"void main ()\n"
"{\n"
"tc = v_texcoord;\n"
"vc = v_colour;\n"
"gl_Position = ftetransform();\n"
"}\n"
"#endif\n"
"#ifdef FRAGMENT_SHADER\n"
"void main ()\n"
"{\n"
"gl_FragColor = vec4(0.5,0.5,0.5,1);//texture2D(s_diffuse, tc.xy);\n"
"vec2 st = (tc-floor(tc)) - 0.5;\n"
"st *= 2.0;\n"
"float dist = sqrt(dot(st,st));\n"
"float ring = 1.0 + smoothstep(0.9, 1.0, dist)\n"
"- smoothstep(0.8, 0.9, dist);\n"
//fade out the rim
"if ((atan(st.t, st.s)+3.14)/6.28 > vc.a)\n"
"gl_FragColor.a *= 0.25;\n"
"gl_FragColor.rgb *= mix(vc.rgb, vec3(0.0), ring);\n"
//gl_FragColor.a;
//and finally hide it all if we're fogged.
"#ifdef FOG\n"
"gl_FragColor = fog4additive(gl_FragColor);\n"
"#endif\n"
"}\n"
"#endif\n"
},
#endif
#ifdef GLQUAKE

View File

@ -1485,8 +1485,10 @@ unsigned long _true = true;
cl->controlaf = 1;
else if (((struct sockaddr *)&from)->sa_family == AF_INET6)
cl->controlaf = 2;
#ifdef USEIPX
else if (((struct sockaddr *)&from)->sa_family == AF_IPX)
cl->controlaf = 11;
#endif
else
cl->controlaf = 0;

View File

@ -1061,7 +1061,7 @@ void HTTPDL_Establish(struct dl_download *dl)
if (https)
{
//https has an extra ssl/tls layer between tcp and http.
con->stream = FS_OpenSSL(con->server, con->stream, false, false);
con->stream = FS_OpenSSL(con->server, con->stream, false);
con->secure = true;
}
#endif

View File

@ -601,6 +601,9 @@ void *Sys_CreateThread(char *name, int (*func)(void *), void *args, int priority
{
return NULL;
}
void Sys_WaitOnThread(void *thread)
{
}
qboolean FS_Remove(const char *fname, enum fs_relative relativeto)
{
return false;

View File

@ -2948,6 +2948,8 @@ static void QCC_PR_ExpandStrCat(char **buffer, size_t *bufferlen, size_t *buffer
static char *QCC_PR_CheckBuiltinCompConst(char *constname, char *retbuf, size_t retbufsize)
{
if (constname[0] != '_' || constname[1] != '_')
return NULL;
if (!strcmp(constname, "__TIME__"))
{
time_t long_time;
@ -2969,7 +2971,7 @@ static char *QCC_PR_CheckBuiltinCompConst(char *constname, char *retbuf, size_t
}
if (!strcmp(constname, "__QCCVER__"))
{
return "FTEQCC "__DATE__","__TIME__"";
return "\"FTEQCC "__DATE__","__TIME__"\"";
}
if (!strcmp(constname, "__FILE__"))
{
@ -2986,7 +2988,7 @@ static char *QCC_PR_CheckBuiltinCompConst(char *constname, char *retbuf, size_t
QC_snprintfz(retbuf, retbufsize, "\"%i\"", pr_source_line);
return retbuf;
}
if (!strcmp(constname, "__FUNC__"))
if (!strcmp(constname, "__FUNC__") || !strcmp(constname, "__func__"))
{
QC_snprintfz(retbuf, retbufsize, "\"%s\"",pr_scope?pr_scope->name:"<NO FUNCTION>");
return retbuf;

View File

@ -56,6 +56,11 @@ void AddSourceFile(const char *parentsrc, const char *filename);
#define SCI_GETANCHOR 2009
#define SCI_SETSAVEPOINT 2014
#define SCI_GETCURLINE 2027
#define SCI_CONVERTEOLS 2029
#define SC_EOL_CRLF 0
#define SC_EOL_CR 1
#define SC_EOL_LF 2
#define SCI_SETEOLMODE 2031
#define SCI_SETCODEPAGE 2037
#define SCI_MARKERDEFINE 2040
#define SCI_MARKERSETFORE 2041
@ -114,6 +119,7 @@ void AddSourceFile(const char *parentsrc, const char *filename);
#define SCI_BRACEHIGHLIGHT 2351
#define SCI_BRACEBADLIGHT 2352
#define SCI_BRACEMATCH 2353
#define SCI_SETVIEWEOL 2356
#define SCI_ANNOTATIONSETTEXT 2540
#define SCI_ANNOTATIONGETTEXT 2541
#define SCI_ANNOTATIONSETSTYLE 2542
@ -1295,6 +1301,8 @@ enum {
IDM_DEBUG_TOGGLEBREAK,
IDM_ENCODING_PRIVATEUSE,
IDM_ENCODING_DEPRIVATEUSE,
IDM_ENCODING_UNIX,
IDM_ENCODING_WINDOWS,
IDM_CREATEINSTALLER_WINDOWS,
IDM_CREATEINSTALLER_ANDROID,
@ -1816,6 +1824,15 @@ void EditorMenu(editor_t *editor, WPARAM wParam)
GUI_Recode(editor, UTF_ANSI);
break;
case IDM_ENCODING_UNIX:
SendMessage(editor->editpane, SCI_CONVERTEOLS, SC_EOL_LF, 0);
SendMessage(editor->editpane, SCI_SETVIEWEOL, false, 0);
break;
case IDM_ENCODING_WINDOWS:
SendMessage(editor->editpane, SCI_CONVERTEOLS, SC_EOL_CRLF, 0);
SendMessage(editor->editpane, SCI_SETVIEWEOL, false, 0);
break;
default:
GenericMenu(wParam);
break;
@ -2416,7 +2433,6 @@ static void EditorReload(editor_t *editor)
char *file;
unsigned int flen;
pbool dofree;
rawfile = QCC_ReadFile(editor->filename, NULL, 0, &flensz);
flen = flensz;
@ -2427,6 +2443,50 @@ static void EditorReload(editor_t *editor)
if (editor->scintilla)
{
int endings = 0;
char *e, *stop;
for (e = file, stop=file+flen; e < stop; )
{
if (*e == '\r')
{
e++;
if (*e == '\n')
{
e++;
endings |= 4;
}
else
endings |= 2;
}
else if (*e == '\n')
{
e++;
endings |= 1;
}
else
e++;
}
switch(endings)
{
case 0: //new file with no endings, default to windows on windows.
case 4: //windows
SendMessage(editor->editpane, SCI_SETEOLMODE, SC_EOL_CRLF, 0);
SendMessage(editor->editpane, SCI_SETVIEWEOL, false, 0);
break;
case 1: //unix
SendMessage(editor->editpane, SCI_SETEOLMODE, SC_EOL_LF, 0);
SendMessage(editor->editpane, SCI_SETVIEWEOL, false, 0);
break;
case 2: //mac. traditionally qccs have never supported this. one of the mission packs has a \r in the middle of some single-line comment.
SendMessage(editor->editpane, SCI_SETEOLMODE, SC_EOL_CR, 0);
SendMessage(editor->editpane, SCI_SETVIEWEOL, false, 0);
break;
default: //panic! everyone panic!
SendMessage(editor->editpane, SCI_SETEOLMODE, SC_EOL_LF, 0);
SendMessage(editor->editpane, SCI_SETVIEWEOL, true, 0);
break;
}
// SendMessage(editor->editpane, SCI_SETTEXT, 0, (LPARAM)file);
// SendMessage(editor->editpane, SCI_SETUNDOCOLLECTION, 0, 0);
SendMessage(editor->editpane, SCI_SETTEXT, 0, (LPARAM)file);
@ -5301,6 +5361,8 @@ static LRESULT CALLBACK MainWndProc(HWND hWnd,UINT message,
AppendMenu(m, MF_SEPARATOR, 0, NULL);
AppendMenu(m, 0, IDM_ENCODING_PRIVATEUSE, "Convert to UTF-8");
AppendMenu(m, 0, IDM_ENCODING_DEPRIVATEUSE, "Convert to Quake encoding");
AppendMenu(m, 0, IDM_ENCODING_UNIX, "Convert to Unix Endings");
AppendMenu(m, 0, IDM_ENCODING_WINDOWS, "Convert to Dos Endings");
AppendMenu(rootmenu, MF_POPUP, (UINT_PTR)(m = windowmenu = CreateMenu()), "&Window");
AppendMenu(m, 0, IDM_CASCADE, "Cascade");

View File

@ -9345,7 +9345,7 @@ static void QCBUILTIN PF_runclientphys(pubprogfuncs_t *prinst, struct globalvars
pmove.cmd.upmove = bound(-32767, (pr_global_struct->input_movevalues)[2], 32767);
pmove.cmd.buttons = pr_global_struct->input_buttons;
pmove.safeorigin_known = true;
pmove.safeorigin_known = progstype != PROG_QW;
VectorCopy(ent->v->oldorigin, pmove.safeorigin);
VectorCopy(ent->v->origin, pmove.origin);
VectorCopy(ent->v->velocity, pmove.velocity);

View File

@ -299,6 +299,20 @@ typedef struct
} server_t;
void SV_WipeServerState(void);
/*
#define CS_EMPTY 0
#define CS_ZOMBIE (1u<<0) //just stops the slot from being reused for a bit.
#define CS_CLUSTER (1u<<1) //is managed by the cluster host (and will appear on scoreboards).
#define CS_SPAWNED (1u<<2) //has an active entity.
#define CS_ACTIVE (1u<<3) //has a connection
#define cs_free (CS_EMPTY)
#define cs_zombie (CS_ZOMBIE)
#define cs_loadzombie (CS_SPAWNED)
#define cs_connected (CS_ACTIVE)
#define cs_spawned (CS_ACTIVE|CS_SPAWNED)
*/
typedef enum
{
cs_free, // can be reused for a new connection
@ -413,6 +427,7 @@ enum
#define STUFFCMD_IGNOREINDEMO ( 1<<0) // do not put in mvd demo
#define STUFFCMD_DEMOONLY ( 1<<1) // put in mvd demo only
#define STUFFCMD_BROADCAST ( 1<<2) // everyone sees it.
typedef struct client_s
{
@ -545,14 +560,7 @@ typedef struct client_s
//true/false/persist
unsigned int penalties;
/* qbyte ismuted;
qbyte iscuffed;
qbyte iscrippled;
qbyte isdeaf;
qbyte islagged;
qbyte isvip;
*/
qbyte istobeloaded; //loadgame creates place holders for clients to connect to. Effectivly loading a game reconnects all clients, but has precreated ents.
qbyte istobeloaded; //loadgame creates place holders for clients to connect to. Effectivly loading a game reconnects all clients, but has precreated ents.
double floodprotmessage;
double lastspoke;
@ -1092,6 +1100,10 @@ void SV_FullClientUpdate (client_t *client, client_t *to);
void SV_GeneratePublicUserInfo(int pext, client_t *cl, char *info, int infolength);
char *SV_PlayerPublicAddress(client_t *cl);
qboolean SVC_GetChallenge (qboolean respond_dp);
int SV_NewChallenge (void);
client_t *SVC_DirectConnect(void);
int SV_ModelIndex (const char *name);
void SV_WriteClientdataToMessage (client_t *client, sizebuf_t *msg);

View File

@ -1776,7 +1776,13 @@ static void SV_Status_f (void)
float pi, po, bi, bo;
int columns = 80;
extern cvar_t sv_listen_qw, sv_listen_nq, sv_listen_dp, sv_listen_q3;
extern cvar_t sv_listen_qw, sv_listen_nq, sv_listen_dp;
#ifdef QWOVERQ3
extern cvar_t sv_listen_q3;
#endif
#ifdef HAVE_DTLS
extern cvar_t sv_listen_dtls;
#endif
#ifndef SERVERONLY
if (!sv.state && cls.state >= ca_connected && !cls.demoplayback && cls.protocol == CP_NETQUAKE)
@ -1815,7 +1821,47 @@ static void SV_Status_f (void)
Con_Printf("packets,bytes/sec: in: %g %g out: %g %g\n", pi, bi, po, bo); //not relevent as a limit.
Con_Printf("server uptime : %s\n", ShowTime(realtime));
Con_Printf("public : %s\n", sv_public.value?"yes":"no");
Con_Printf("client types :%s%s%s%s\n", sv_listen_qw.ival?" QW":"", sv_listen_nq.ival?" NQ":"", sv_listen_dp.ival?" DP":"", sv_listen_q3.ival?" Q3":"");
switch(svs.gametype)
{
#ifdef Q3SERVER
case GT_QUAKE3:
Con_Printf("client types :%s\n", sv_listen_qw.ival?" Q3":"");
break;
#endif
#ifdef Q2SERVER
case GT_QUAKE2:
Con_Printf("client types :%s\n", sv_listen_qw.ival?" Q2":"");
break;
#endif
default:
Con_Printf("client types :%s", sv_listen_qw.ival?" QW":"");
#ifdef NQPROT
Con_Printf("%s%s", (sv_listen_nq.ival==2)?" -NQ":(sv_listen_nq.ival?" NQ":""), sv_listen_dp.ival?" DP":"");
#endif
#ifdef QWOVERQ3
if (sv_listen_q3.ival) Con_Printf(" Q3");
#endif
#ifdef HAVE_DTLS
if (sv_listen_dtls.ival >= 2)
Con_Printf(" +DTLS");
else if (sv_listen_dtls.ival)
Con_Printf(" DTLS");
#endif
/*if (net_enable_tls.ival)
Con_Printf(" TLS");
if (net_enable_http.ival)
Con_Printf(" HTTP");
if (net_enable_webrtcbroker.ival)
Con_Printf(" WebRTC");
if (net_enable_websockets.ival)
Con_Printf(" WS");
if (net_enable_qizmo.ival)
Con_Printf(" QZ");
if (net_enable_qtv.ival)
Con_Printf(" QTV");*/
Con_Printf("\n");
break;
}
#ifdef SUBSERVERS
if (sv.state == ss_clustermode)
{

View File

@ -1786,17 +1786,12 @@ unsigned int SVDP_CalcDelta(entity_state_t *from, qbyte *frombonedatabase, entit
return bits;
}
void SVDP_EmitEntityDelta(entity_state_t *from, entity_state_t *to, sizebuf_t *msg, qboolean isnew, qbyte *bonedatabase)
void SVDP_EmitEntityDelta(unsigned int bits, entity_state_t *to, sizebuf_t *msg, qbyte *bonedatabase)
{
int bits;
bits &= ~E5_SERVERPRIVATE;
bits = 0;
if (isnew)
bits |= E5_FULLUPDATE;
//FIXME: this stuff should be outside of this function
//with the whole nack stuff
bits = SVDP_CalcDelta(from, NULL, to, bonedatabase);
if (!bits)
return;
if (bits >= 256)
bits |= E5_EXTEND1;
@ -1805,9 +1800,6 @@ void SVDP_EmitEntityDelta(entity_state_t *from, entity_state_t *to, sizebuf_t *m
if (bits >= 16777216)
bits |= E5_EXTEND3;
if (!bits)
return;
MSG_WriteShort(msg, to->number);
MSG_WriteByte(msg, bits & 0xFF);
if (bits & E5_EXTEND1)
@ -1930,6 +1922,7 @@ void SVDP_EmitEntitiesUpdate (client_t *client, packet_entities_t *to, sizebuf_t
int oldindex, newindex;
int oldnum, newnum;
int oldmax;
int j;
// this is the frame that we are going to delta update from
if (!client->netchan.incoming_sequence)
@ -1939,11 +1932,59 @@ void SVDP_EmitEntitiesUpdate (client_t *client, packet_entities_t *to, sizebuf_t
}
else
{
client_frame_t *fromframe = &client->frameunion.frames[(client->netchan.incoming_sequence-1) & UPDATE_MASK];
from = &fromframe->entities;
from = &client->sentents;
oldmax = from->num_entities;
}
if (to->num_entities)
{
j = to->entities[to->num_entities-1].number+1;
if (j > from->max_entities)
{
from->entities = BZ_Realloc(from->entities, sizeof(*from->entities) * j);
memset(&from->entities[from->max_entities], 0, sizeof(from->entities[0]) * (j - from->max_entities));
from->max_entities = j;
}
while(j > client->sentents.num_entities)
{
from->entities[from->num_entities].number = 0;
from->num_entities++;
}
}
//diff the from+to states, flagging any changed state (which is combined with any state from previous packet loss
newindex = 0;
oldindex = 0;
while (newindex < to->num_entities || oldindex < oldmax)
{
newnum = newindex >= to->num_entities ? 0x7fff : to->entities[newindex].number;
oldnum = oldindex >= oldmax ? 0x7fff : from->entities[oldindex].number;
if (newnum < oldnum)
{ // this is a new entity, send it from the baseline... as far as dp understands it...
client->pendingdeltabits[newnum] |= E5_FULLUPDATE | SVDP_CalcDelta(&nullentitystate, NULL, &to->entities[oldindex], to->bonedata);
newindex++;
}
else if (newnum > oldnum)
{ // the old entity isn't present in the new message
client->pendingdeltabits[oldnum] = E5_SERVERREMOVE;
oldindex++;
}
else
{ // delta update from old position
client->pendingdeltabits[newnum] |= SVDP_CalcDelta(&from->entities[oldindex], NULL/*from->bonedata*/, &to->entities[oldindex], to->bonedata);
if (client->pendingdeltabits[newnum] & E5_SERVERREMOVE)
{ //if it got flagged for removal, but its actually a valid entity, then assume that its an outdated remove and just flag it for a full update in case stuff got lost.
client->pendingdeltabits[newnum] &= ~E5_SERVERREMOVE;
client->pendingdeltabits[newnum] |= E5_FULLUPDATE;
}
oldindex++;
newindex++;
}
}
//loop through all ents and send them as required
// Con_Printf ("frame %i\n", client->netchan.incoming_sequence);
MSG_WriteByte(msg, svcdp_entities);
@ -1955,7 +1996,7 @@ void SVDP_EmitEntitiesUpdate (client_t *client, packet_entities_t *to, sizebuf_t
//add in the bitmasks of dropped packets.
newindex = 0;
/* newindex = 0;
oldindex = 0;
//Con_Printf ("---%i to %i ----\n", client->delta_sequence & UPDATE_MASK
// , client->netchan.outgoing_sequence & UPDATE_MASK);
@ -1989,7 +2030,7 @@ void SVDP_EmitEntitiesUpdate (client_t *client, packet_entities_t *to, sizebuf_t
continue;
}
}
*/
MSG_WriteShort(msg, 0x8000);
}
#endif
@ -3862,6 +3903,7 @@ void SV_Snapshot_Clear(packet_entities_t *pack)
numnails = 0;
}
#ifdef QWOVERQ3
/*
=============
SVQ3Q1_BuildEntityPacket
@ -3876,6 +3918,7 @@ void SVQ3Q1_BuildEntityPacket(client_t *client, packet_entities_t *pack)
SV_Snapshot_SetupPVS(client, &cameras);
SV_Snapshot_BuildQ1(client, pack, &cameras, client->edict);
}
#endif
/*
=============

View File

@ -41,6 +41,14 @@ void SV_Tcpport6_Callback(struct cvar_s *var, char *oldvalue);
void SV_Port_Callback(struct cvar_s *var, char *oldvalue);
void SV_PortIPv6_Callback(struct cvar_s *var, char *oldvalue);
void SV_PortIPX_Callback(struct cvar_s *var, char *oldvalue);
#ifdef HAVE_DTLS
void SV_Listen_Dtls_Changed(struct cvar_s *var, char *oldvalue)
{
if (var->ival)
if (!DTLS_HasCertificate())
var->ival = 0; //disable the cvar (internally) if we don't have a usable certificate. this allows us to default the cvar to enabled without it breaking otherwise.
}
#endif
client_t *host_client; // current client
@ -97,10 +105,15 @@ extern cvar_t sv_allow_splitscreen;
cvar_t sv_serverip = CVARD("sv_serverip", "", "Set this cvar to the server's public ip address if the server is behind a firewall and cannot detect its own public address. Providing a port is required if the firewall/nat remaps it, but is otherwise optional.");
cvar_t sv_public = CVAR("sv_public", "0");
cvar_t sv_listen_qw = CVARAF("sv_listen_qw", "1", "sv_listen", 0);
cvar_t sv_listen_qw = CVARAFD("sv_listen_qw", "1", "sv_listen", 0, "Specifies whether normal clients are allowed to connect.");
cvar_t sv_listen_nq = CVARD("sv_listen_nq", "2", "Allow new (net)quake clients to connect to the server.\n0 = don't let them in.\n1 = allow them in (WARNING: this allows 'qsmurf' DOS attacks).\n2 = accept (net)quake clients by emulating a challenge (as secure as QW/Q2 but does not fully conform to the NQ protocol).");
cvar_t sv_listen_dp = CVARD("sv_listen_dp", "0", "Allows the server to respond with the DP-specific handshake protocol.\nWarning: this can potentially get confused with quake2, and results in race conditions with both vanilla netquake and quakeworld protocols.\nOn the plus side, DP clients can usually be identified correctly, enabling a model+sound limit boost.");
#ifdef QWOVERQ3
cvar_t sv_listen_q3 = CVAR("sv_listen_q3", "0");
#endif
#ifdef HAVE_DTLS
cvar_t sv_listen_dtls = CVARCD("net_enable_dtls", "", SV_Listen_Dtls_Changed, "Controls serverside dtls support.\n0: dtls blocked, not advertised.\n1: available in desired.\n2: used where possible.\n3: disallow non-dtls clients (sv_port_tcp should be eg tls://[::]:27500 to also disallow unencrypted tcp connections).");
#endif
cvar_t sv_reportheartbeats = CVAR("sv_reportheartbeats", "1");
cvar_t sv_highchars = CVAR("sv_highchars", "1");
cvar_t sv_maxrate = CVAR("sv_maxrate", "30000");
@ -679,6 +692,10 @@ void SV_DropClient (client_t *drop)
//send twice, to cover packetloss a little.
Netchan_Transmit (&drop->netchan, termmsg.cursize, termmsg.data, 10000);
Netchan_Transmit (&drop->netchan, termmsg.cursize, termmsg.data, 10000);
#ifdef HAVE_DTLS
NET_DTLS_Disconnect(svs.sockets, &drop->netchan.remote_address);
#endif
}
if (svs.gametype == GT_PROGS || svs.gametype == GT_Q1QVM) //gamecode should do it all for us.
@ -1071,7 +1088,7 @@ Responds with all the info that qplug or qspy can see
This message can be up to around 5k with worst case string lengths.
================
*/
void SVC_Status (void)
static void SVC_Status (void)
{
int displayflags;
int i;
@ -1150,7 +1167,7 @@ void SVC_Status (void)
}
#ifdef NQPROT
void SVC_GetInfo (char *challenge, int fullstatus)
static void SVC_GetInfo (char *challenge, int fullstatus)
{
//dpmaster support
char response[MAX_UDP_PACKET];
@ -1267,7 +1284,7 @@ void SVC_GetInfo (char *challenge, int fullstatus)
#endif
#ifdef Q2SERVER
void SVC_InfoQ2 (void)
static void SVC_InfoQ2 (void)
{
char string[64];
int i, count;
@ -1301,7 +1318,7 @@ SV_CheckLog
===================
*/
#define LOG_FLUSH 10*60
void SV_CheckLog (void)
static void SV_CheckLog (void)
{
sizebuf_t *sz;
@ -1332,7 +1349,7 @@ the same as the current sequence, an A2A_NACK will be returned
instead of the data.
================
*/
void SVC_Log (void)
static void SVC_Log (void)
{
unsigned int seq;
char data[MAX_DATAGRAM+64];
@ -1439,7 +1456,7 @@ flood the server with invalid connection IPs. With a
challenge, they must give a valid IP address.
=================
*/
void SVC_GetChallenge (qboolean nodpresponse)
qboolean SVC_GetChallenge (qboolean respond_dp)
{
#ifdef HUFFNETWORK
int compressioncrc;
@ -1449,24 +1466,71 @@ void SVC_GetChallenge (qboolean nodpresponse)
int lng;
char *over;
if (!sv_listen_qw.value && !sv_listen_dp.value && !sv_listen_q3.ival)
return;
qboolean respond_std = true;
#ifdef QWOVERQ3
qboolean respond_qwoverq3 = true;
respond_qwoverq3 &= !!sv_listen_q3.value;
#else
const qboolean respond_qwoverq3 = false;
#endif
respond_std &= !!sv_listen_qw.value;
respond_dp &= !!sv_listen_dp.value;
if (progstype == PROG_H2)
respond_dp = false; //don't bother. dp doesn't support the maps anyway.
//dp's connections result in race conditions or are ambiguous in certain regards
//race: dp vs nq.
// the dp request will generally arrive first. we check if there was a recent challenge requested, and inhibit the nq response, ensuring that dp clients connect with a known protocol
//race: dp vs qw.
// DP clients will just bindly respond to both with a connection request. sending the dp one usually means the server will see the dp connection request first
// FTE clients explicitly ignore dp challenges with the specific 'FTE' prefix so you get qw connections there.
//conflict: dp vs q2. dp challenge responses USUALLY contain letters. vanilla q2 is always a 32bit int. FTE clients will check that before sending an appropriate response.
//so:
// vanilla nq doesn't send getchallenge, its nq connect is not inhibited, and connects directly (we optionally hack a challenge over stuffcmds, as well as protocol extensions).
// dp gets a dp+qw challenge, its nq request is ignored due to packet ordering and a small timeout, the server sees the dp connection request first and ignores the qw connect.
// fte's nq request is treated as a getchallenge. fte clients ignore the dp challenge response (if qw protocols are still enabled). ends up with a qw/fte connection
if (!(sv_listen_nq.value || sv_bigcoords.value || !respond_std))
respond_dp = false;
#ifdef QWOVERQ3
if (svs.gametype != GT_PROGS && svs.gametype != GT_Q1QVM)
respond_qwoverq3 = false; //should probably just nuke this feature.
#endif
if (!respond_std && !respond_dp && !respond_qwoverq3)
return false;
if (svs.gametype != GT_PROGS && svs.gametype != GT_Q1QVM)
{ //if we're running q2 or q3, just ignore the whole DP thing. its irrelevent in those game modes.
respond_std |= true;
#ifdef QWOVERQ3
respond_qwoverq3 = false;
#endif
respond_dp = false;
}
if (respond_dp)
respond_std = false;
challenge = SV_NewChallenge();
// send it back
//different game modes require different types of responses
switch(svs.gametype)
{
#ifdef Q3SERVER
if (svs.gametype == GT_QUAKE3) //q3 servers
case GT_QUAKE3: //q3 servers
buf = va("challengeResponse %i", challenge);
else
break;
#endif
#ifdef Q2SERVER
if (svs.gametype == GT_QUAKE2)
case GT_QUAKE2:
buf = va("challenge %i", challenge); //quake 2 servers give a different challenge response
else
break;
#endif
default:
buf = va("%c%i", S2C_CHALLENGE, challenge); //quakeworld's response is a bit poo.
break;
}
over = buf + strlen(buf) + 1;
@ -1527,12 +1591,25 @@ void SVC_GetChallenge (qboolean nodpresponse)
over+=sizeof(lng);
}
#endif
#ifdef HAVE_DTLS
if (sv_listen_dtls.ival/* || !*sv_listen_dtls.string*/)
{
lng = LittleLong(PROTOCOL_VERSION_DTLSUPGRADE);
memcpy(over, &lng, sizeof(lng));
over+=sizeof(lng);
if (sv_listen_dtls.ival >= 2)
lng = LittleLong(2); //required
else
lng = LittleLong(1); //supported
memcpy(over, &lng, sizeof(lng));
over+=sizeof(lng);
}
#endif
}
if (progstype == PROG_H2)
nodpresponse = true;
if (!nodpresponse && sv_listen_dp.value && (sv_listen_nq.value || sv_bigcoords.value || !sv_listen_qw.value))
if (respond_dp)
{
char *dp;
if (sv_listen_qw.value)
@ -1542,22 +1619,23 @@ void SVC_GetChallenge (qboolean nodpresponse)
Netchan_OutOfBand(NS_SERVER, &net_from, strlen(dp)+1, dp);
}
if (sv_listen_qw.value || (svs.gametype != GT_PROGS && svs.gametype != GT_Q1QVM))
if (respond_std)
Netchan_OutOfBand(NS_SERVER, &net_from, over-buf, buf);
#ifdef Q3SERVER
#ifdef QWOVERQ3
if (svs.gametype == GT_PROGS || svs.gametype == GT_Q1QVM)
{
if (sv_listen_q3.ival)
if (respond_qwoverq3)
{
buf = va("challengeResponse %i", challenge);
Netchan_OutOfBand(NS_SERVER, &net_from, strlen(buf), buf);
}
}
#endif
return true;
}
void VARGS SV_OutOfBandPrintf (int q2, netadr_t *adr, char *format, ...)
static void VARGS SV_OutOfBandPrintf (int q2, netadr_t *adr, char *format, ...)
{
va_list argptr;
char string[8192];
@ -1579,7 +1657,7 @@ void VARGS SV_OutOfBandPrintf (int q2, netadr_t *adr, char *format, ...)
Netchan_OutOfBand (NS_SERVER, adr, strlen(string), (qbyte *)string);
}
void VARGS SV_OutOfBandTPrintf (int q2, netadr_t *adr, int language, translation_t text, ...)
static void VARGS SV_OutOfBandTPrintf (int q2, netadr_t *adr, int language, translation_t text, ...)
{
va_list argptr;
char string[8192];
@ -1621,7 +1699,7 @@ qboolean SV_ChallengePasses(int challenge)
//this means that DP clients tend to connect as generic NQ clients.
//and because DP _REQUIRES_ sv_bigcoords, they tend to end up being given fitz/rmq protocols
//thus we don't respond to the connect if sv_listen_dp is 1, and we had a recent getchallenge request. recent is 2 secs.
qboolean SV_ChallengeRecent(void)
static qboolean SV_ChallengeRecent(void)
{
int curtime = realtime; //yeah, evil. sue me. consitent with challenges.
int i;
@ -1872,7 +1950,7 @@ void SV_ClientProtocolExtensionsChanged(client_t *client)
if (client->frameunion.frames)
Z_Free(client->frameunion.frames);
if ((client->fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS))// || ISDPCLIENT(&temp))
if ((client->fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS) || ISDPCLIENT(client))
{
char *ptr;
int maxents = maxpacketentities*4; /*this is the max number of ents updated per frame. we can't track more, so...*/
@ -2144,11 +2222,15 @@ client_t *SVC_DirectConnect(void)
if (*Cmd_Argv(1) == '\\')
{ //connect "\key\val"
#ifndef QWOVERQ3
SV_RejectMessage (SCP_QUAKE3, "This is not a q3 server: %s\n", version_string());
Con_TPrintf ("* rejected connect from q3 client\n");
return NULL;
#else
//this is used by q3 (note, we already decrypted the huffman connection packet in a hack)
if (!sv_listen_q3.ival)
{
SV_RejectMessage (SCP_QUAKE3, "Server is not accepting quake3 clients at this time.\n", version_string());
SV_RejectMessage (SCP_QUAKE3, "Server is not accepting quake3 clients at this time: %s\n", version_string());
Con_TPrintf ("* rejected connect from q3 client\n");
return NULL;
}
@ -2181,6 +2263,7 @@ client_t *SVC_DirectConnect(void)
#ifdef HUFFNETWORK
huffcrc = HUFFCRC_QUAKE3;
#endif
#endif
}
else if (*(Cmd_Argv(0)+7) == '\\')
@ -2237,7 +2320,7 @@ client_t *SVC_DirectConnect(void)
{"NEHAHRABJP", 0},
{"NEHAHRABJP2", 0},
{"NEHAHRABJP3", 1u<<SCP_BJP3},
{"DP7DP6", (1u<<SCP_DARKPLACES7)|(1u<<SCP_DARKPLACES6)}, //stupid shitty crappy client
{"DP7DP6", (1u<<SCP_DARKPLACES7)|(1u<<SCP_DARKPLACES6)}, //stupid shitty buggy crappy client
};
int p;
@ -2337,6 +2420,14 @@ client_t *SVC_DirectConnect(void)
}
}
#ifdef HAVE_DTLS
if (sv_listen_dtls.ival > 2 && (net_from.prot == NP_DGRAM || net_from.prot == NP_STREAM || net_from.prot == NP_WS))
{
SV_RejectMessage (protocol, "This server requires the use of DTLS/TLS/WSS.\n");
return NULL;
}
#endif
{
char *banreason = SV_BannedReason(&net_from);
if (banreason)
@ -2509,7 +2600,7 @@ client_t *SVC_DirectConnect(void)
else if (!strcmp(sv_protocol_nq.string, "dp6"))
protocol = SCP_DARKPLACES6;
else if (!strcmp(sv_protocol_nq.string, "dp7"))
protocol = SCP_DARKPLACES6;
protocol = SCP_DARKPLACES7;
else if (!strcmp(sv_protocol_nq.string, "id") || !strcmp(sv_protocol_nq.string, "vanilla"))
protocol = SCP_NETQUAKE;
else switch(sv_protocol_nq.ival)
@ -3451,6 +3542,11 @@ qboolean SV_ConnectionlessPacket (void)
#endif
else if (!strncmp(c,"connect", 7))
{
#ifdef HAVE_DTLS
if (net_from.prot == NP_DGRAM)
NET_DTLS_Disconnect(svs.sockets, &net_from);
#endif
#ifdef Q3SERVER
if (svs.gametype == GT_QUAKE3)
{
@ -3458,6 +3554,7 @@ qboolean SV_ConnectionlessPacket (void)
return true;
}
#ifdef QWOVERQ3
if (sv_listen_q3.ival)
{
if (!strstr(s, "\\name\\"))
@ -3473,7 +3570,9 @@ qboolean SV_ConnectionlessPacket (void)
}
}
#endif
if (secure.value) //FIXME: possible problem for nq clients when enabled
#endif
if (secure.value) //FIXME: possible problem for nq clients when enabled
{
Netchan_OutOfBandTPrintf (NS_SERVER, &net_from, svs.language, "%c\nThis server requires client validation.\nPlease use the "FULLENGINENAME" validation program\n", A2C_PRINT);
}
@ -3483,13 +3582,44 @@ qboolean SV_ConnectionlessPacket (void)
return true;
}
}
else if (!strcmp(c,"\xad\xad\xad\xad""getchallenge"))
else if (!strcmp(c,"dtlsconnect"))
{
SVC_GetChallenge (true);
#ifdef HAVE_DTLS
if (net_from.prot == NP_DGRAM && (sv_listen_dtls.ival /*|| !*sv_listen_dtls.ival*/))
{
if (SV_ChallengePasses(atoi(Cmd_Argv(1))))
{
char *banreason = SV_BannedReason(&net_from);
if (banreason)
{
if (*banreason)
SV_RejectMessage (SCP_QUAKEWORLD, "You were banned.\nReason: %s\n", banreason);
else
SV_RejectMessage (SCP_QUAKEWORLD, "You were banned.\n");
}
else
{
//NET_DTLS_Disconnect(svs.sockets, &net_from);
if (NET_DTLS_Create(svs.sockets, &net_from))
Netchan_OutOfBandPrint(NS_SERVER, &net_from, "dtlsopened");
}
}
else
SV_RejectMessage (SCP_QUAKEWORLD, "Bad challenge.\n");
}
return true;
#endif
}
else if (!strcmp(c,"getchallenge"))
/*else if (!strcmp(c,"\xad\xad\xad\xad""getchallenge"))
{
SVC_GetChallenge (false);
}*/
else if (!strcmp(c,"getchallenge"))
{
//qw+q2 always sends "\xff\xff\xff\xffgetchallenge\n"
//dp+q3 always sends "\xff\xff\xff\xffgetchallenge"
//its a subtle difference, but means we can avoid wasteful spam for real qw clients.
SVC_GetChallenge ((net_message.cursize==16)?true:false);
}
#ifdef NQPROT
/*for DP*/
@ -3537,6 +3667,7 @@ qboolean SVNQ_ConnectionlessPacket(void)
char buffer[256], buffer2[256];
netadr_t localaddr;
char *banreason;
if (net_from.type == NA_LOOPBACK)
return false;
@ -3689,7 +3820,7 @@ qboolean SVNQ_ConnectionlessPacket(void)
else if (!strncmp(MSG_ReadString(), "getchallenge", 12) && (sv_listen_qw.ival || sv_listen_dp.ival))
{
/*dual-stack client, supporting either DP or QW protocols*/
SVC_GetChallenge (true);
SVC_GetChallenge (false);
}
else
{
@ -4024,6 +4155,21 @@ qboolean SV_ReadPackets (float *delay)
SV_ConnectionlessPacket();
continue;
}
#ifdef HAVE_DTLS
else
{
if (NET_DTLS_Decode(svs.sockets))
{
if (!net_message.cursize)
continue;
if (*(unsigned int *)net_message.data == ~0)
{
SV_ConnectionlessPacket();
continue;
}
}
}
#endif
#ifdef Q3SERVER
if (svs.gametype == GT_QUAKE3)
@ -4139,7 +4285,7 @@ dominping:
if (i != svs.allocated_client_slots)
continue;
#ifdef Q3SERVER
#ifdef QWOVERQ3
if (sv_listen_q3.ival && SVQ3_HandleClient())
{
received++;
@ -4162,6 +4308,10 @@ dominping:
Con_Printf ("%s:sequenced packet without connection\n", NET_AdrToString (com_token, sizeof(com_token), &net_from)); //hack: com_token cos we need some random temp buffer.
}
#ifdef HAVE_DTLS
NET_DTLS_Timeouts(svs.sockets);
#endif
return received;
}
@ -4848,8 +4998,13 @@ void SV_InitLocal (void)
Cvar_Register (&sv_listen_qw, cvargroup_servercontrol);
Cvar_Register (&sv_listen_nq, cvargroup_servercontrol);
Cvar_Register (&sv_listen_dp, cvargroup_servercontrol);
#ifdef QWOVERQ3
Cvar_Register (&sv_listen_q3, cvargroup_servercontrol);
sv_listen_qw.restriction = RESTRICT_MAX;
#endif
#ifdef HAVE_DTLS
Cvar_Register (&sv_listen_dtls, cvargroup_servercontrol);
#endif
sv_listen_qw.restriction = RESTRICT_MAX; //no disabling this over rcon.
Cvar_Register (&fraglog_public, cvargroup_servercontrol);
SVNET_RegisterCvars();

View File

@ -2389,7 +2389,11 @@ void SV_UserCmdMVDList_HTML (vfsfile_t *pipe)
VFS_PRINTF(pipe, "*%d: %s %dk<br/>\n", i, list->name, d->totalsize/1024);
}
if (!d)
VFS_PRINTF(pipe, "%d: <a href='/demos/%s'>%s</a> %dk <a href='javascript:void(0)' onclick='playdemo(\"%s\")'>play</a><br/>\n", i, list->name, list->name, list->size/1024, list->name);
{
char datetime[64];
strftime(datetime, sizeof(datetime), "%Y-%m-%d %H:%M:%S", localtime(&list->mtime));
VFS_PRINTF(pipe, "%d: <a href='/demos/%s'>%s</a> %dk <a href='javascript:void(0)' onclick='playdemo(\"%s\")'>play</a> %s<br/>\n", i, list->name, list->name, list->size/1024, list->name, datetime);
}
}
for (d = demo.dest; d; d = d->nextdest)

View File

@ -528,8 +528,8 @@ void SVNQ_New_f (void)
qboolean big; //used as a filter to exclude protocols that don't match our coord+angles mode
} preferedprot[] =
{
{SCP_DARKPLACES7, true},
{SCP_DARKPLACES6, true},
// {SCP_DARKPLACES7, true},
// {SCP_DARKPLACES6, true},
{SCP_FITZ666, true}, //actually 999... shh...
{SCP_FITZ666, false},
{SCP_BJP3, false}
@ -604,7 +604,7 @@ void SVNQ_New_f (void)
protoname = "NQ";
}
break;
case SCP_DARKPLACES6:
/*case SCP_DARKPLACES6:
SV_LogPlayer(host_client, "new (DP6)");
protmain = PROTOCOL_VERSION_DP6;
protext1 &= ~PEXT_FLOATCOORDS; //always enabled, try not to break things
@ -615,7 +615,7 @@ void SVNQ_New_f (void)
protmain = PROTOCOL_VERSION_DP7;
protext1 &= ~PEXT_FLOATCOORDS; //always enabled, try not to break things
protoname = "DPP7";
break;
break;*/
default:
host_client->drop = true;
protoname = "?""?""?";
@ -6869,7 +6869,7 @@ void SV_RunCmd (usercmd_t *ucmd, qboolean recurse)
VectorCopy(sv_player->v->origin, pmove.origin);
VectorCopy(sv_player->v->oldorigin, pmove.safeorigin);
pmove.safeorigin_known = true;
pmove.safeorigin_known = progstype != PROG_QW;
VectorCopy (sv_player->v->velocity, pmove.velocity);
VectorCopy (sv_player->v->v_angle, pmove.angles);

View File

@ -78,7 +78,9 @@ static qboolean BoundsIntersect (vec3_t mins1, vec3_t maxs1, vec3_t mins2, vec3_
void SVQ3_CreateBaseline(void);
void SVQ3_ClientThink(client_t *cl);
void SVQ3Q1_ConvertEntStateQ1ToQ3(entity_state_t *q1, q3entityState_t *q3);
#ifdef QWOVERQ3
static void SVQ3Q1_ConvertEntStateQ1ToQ3(entity_state_t *q1, q3entityState_t *q3);
#endif
const char *mapentspointer;
@ -1991,9 +1993,8 @@ void SVQ3_EmitPacketEntities(client_t *client, q3client_frame_t *from, q3client_
if(newnum < oldnum)
{
// this is a new entity, send it from the baseline
if (svs.gametype == GT_QUAKE3)
MSGQ3_WriteDeltaEntity( msg, &q3_baselines[newnum], newent, true );
else
#ifdef QWOVERQ3
if (svs.gametype != GT_QUAKE3)
{
q3entityState_t q3base;
edict_t *e;
@ -2001,6 +2002,9 @@ void SVQ3_EmitPacketEntities(client_t *client, q3client_frame_t *from, q3client_
SVQ3Q1_ConvertEntStateQ1ToQ3(&e->baseline, &q3base);
MSGQ3_WriteDeltaEntity( msg, &q3base, newent, true );
}
else
#endif
MSGQ3_WriteDeltaEntity( msg, &q3_baselines[newnum], newent, true );
newindex++;
continue;
}
@ -2230,7 +2234,7 @@ static qboolean SVQ3_EntityIsVisible(q3client_frame_t *snap, q3sharedEntity_t *e
return true;
}
q3playerState_t *SVQ3Q1_BuildPlayerState(client_t *client)
static q3playerState_t *SVQ3Q1_BuildPlayerState(client_t *client)
{
static q3playerState_t state;
extern cvar_t sv_gravity;
@ -2411,6 +2415,7 @@ void SVQ3_BuildClientSnapshot( client_t *client )
}
}
}
#ifdef QWOVERQ3
else
{ //our q1->q3 converter
packet_entities_t pack;
@ -2426,6 +2431,7 @@ void SVQ3_BuildClientSnapshot( client_t *client )
entityStates[snap->num_entities++] = &q3packentities[i];
}
}
#endif
if( q3_next_snapshot_entities + snap->num_entities >= 0x7FFFFFFE )
{
@ -2450,10 +2456,10 @@ void SVQ3_BuildClientSnapshot( client_t *client )
{ //fix areabits, q2->q3 style..
snap->areabits[i]^=255;
}
}
void SVQ3Q1_ConvertEntStateQ1ToQ3(entity_state_t *q1, q3entityState_t *q3)
#ifdef QWOVERQ3
static void SVQ3Q1_ConvertEntStateQ1ToQ3(entity_state_t *q1, q3entityState_t *q3)
{
#ifdef warningmsg
#pragma warningmsg("qwoverq3: This _WILL_ need extending")
@ -2511,31 +2517,9 @@ void SVQ3Q1_ConvertEntStateQ1ToQ3(entity_state_t *q1, q3entityState_t *q3)
q3->angles2[2] = 0;
q3->constantLight = q1->abslight;
q3->frame = q1->frame;
#if 0
//these are the things I've not packed in to the above structure yet.
#if defined(Q2CLIENT) || defined(Q2SERVER)
int renderfx; //q2
qbyte modelindex3; //q2
qbyte modelindex4; //q2
#endif
qbyte glowsize;
qbyte glowcolour;
qbyte scale;
char fatness;
qbyte hexen2flags;
qbyte dpflags;
qbyte colormod[3];//multiply this by 8 to read as 0 to 1...
qbyte lightstyle;
qbyte lightpflags;
unsigned short light[4];
unsigned short tagentity;
unsigned short tagindex;
#endif
}
void SVQ3Q1_SendGamestateConfigstrings(sizebuf_t *msg)
static void SVQ3Q1_SendGamestateConfigstrings(sizebuf_t *msg)
{
const int cs_models = 32;
const int cs_sounds = cs_models + 256;
@ -2614,6 +2598,7 @@ void SVQ3Q1_SendGamestateConfigstrings(sizebuf_t *msg)
MSG_WriteBits(msg, 0, 8);
}
}
#endif
//writes initial gamestate
void SVQ3_SendGameState(client_t *client)
@ -2664,6 +2649,7 @@ void SVQ3_SendGameState(client_t *client)
MSGQ3_WriteDeltaEntity( &msg, NULL, &q3_baselines[i], true );
}
break;
#ifdef QWOVERQ3
case GT_PROGS:
case GT_Q1QVM:
SVQ3Q1_SendGamestateConfigstrings(&msg);
@ -2680,10 +2666,9 @@ void SVQ3_SendGameState(client_t *client)
}
}
break;
// warning: enumeration value GT_? not handled in switch
case GT_HALFLIFE:
case GT_QUAKE2:
case GT_MAX:
#endif
default:
client->drop = true;
break;
}

View File

@ -25,6 +25,7 @@ char shaders[][64] =
"defaultgammacb",
"drawflat_wall",
"wireframe",
"itemtimer",
"lpp_depthnorm",
"lpp_light",
"lpp_wall",

View File

@ -0,0 +1,43 @@
!!permu FOG
#include "sys/defs.h"
#include "sys/fog.h"
varying vec2 tc;
varying vec4 vc;
#ifdef VERTEX_SHADER
void main ()
{
tc = v_texcoord;
vc = v_colour;
gl_Position = ftetransform();
}
#endif
#ifdef FRAGMENT_SHADER
void main ()
{
gl_FragColor = vec4(0.5,0.5,0.5,1);//texture2D(s_diffuse, tc.xy);
vec2 st = (tc-floor(tc)) - 0.5;
st *= 2.0;
float dist = sqrt(dot(st,st));
float ring = 1.0 + smoothstep(0.9, 1.0, dist)
- smoothstep(0.8, 0.9, dist);
//fade out the rim
if ((atan(st.t, st.s)+3.14)/6.28 > vc.a)
gl_FragColor.a *= 0.25;
gl_FragColor.rgb *= mix(vc.rgb, vec3(0.0), ring);
//gl_FragColor.a;
//and finally hide it all if we're fogged.
#ifdef FOG
gl_FragColor = fog4additive(gl_FragColor);
#endif
}
#endif

View File

@ -149,7 +149,7 @@ void SWRast_Sync(struct workqueue_s *wq);
qboolean SW_VID_Init(rendererstate_t *info, unsigned char *palette);
void SW_VID_DeInit(void);
qboolean SW_VID_ApplyGammaRamps (unsigned int rampcount, unsigned short *ramps);
char *SW_VID_GetRGBInfo(int *truevidwidth, int *truevidheight, enum uploadfmt *fmt);
char *SW_VID_GetRGBInfo(int *bytestride, int *truevidwidth, int *truevidheight, enum uploadfmt *fmt);
void SW_VID_SetWindowCaption(const char *msg);
void SW_VID_SwapBuffers(void);
void SW_VID_UpdateViewport(wqcom_t *com);

View File

@ -575,6 +575,12 @@ void SWBE_Set2D(void)
float ang, rad, w, h;
float tmp[16];
float tmp2[16];
vid.fbvwidth = vid.width;
vid.fbvheight = vid.height;
vid.fbpwidth = vid.pixelwidth;
vid.fbpheight = vid.pixelheight;
ang = (gl_screenangle.value>0?(gl_screenangle.value+45):(gl_screenangle.value-45))/90;
ang = (int)ang * 90;
if (ang)

View File

@ -906,7 +906,26 @@ void SW_R_RenderView(void)
if (!cl.worldmodel || (!cl.worldmodel->nodes && cl.worldmodel->type != mod_heightmap))
r_refdef.flags |= RDF_NOWORLDMODEL;
// R_SetupGL ();
//no fbos here
vid.fbvwidth = vid.width;
vid.fbvheight = vid.height;
vid.fbpwidth = vid.pixelwidth;
vid.fbpheight = vid.pixelheight;
{
//figure out the viewport that we should be using.
int x = floor(r_refdef.vrect.x * (float)vid.fbpwidth/(float)vid.width);
int x2 = ceil((r_refdef.vrect.x + r_refdef.vrect.width) * (float)vid.fbpwidth/(float)vid.width);
int y = floor(r_refdef.vrect.y * (float)vid.fbpheight/(float)vid.height);
int y2 = ceil((r_refdef.vrect.y + r_refdef.vrect.height) * (float)vid.fbpheight/(float)vid.height);
int w = x2 - x;
int h = y2 - y;
r_refdef.pxrect.x = x;
r_refdef.pxrect.y = y;
r_refdef.pxrect.width = w;
r_refdef.pxrect.height = h;
r_refdef.pxrect.maxheight = vid.fbpheight;
}
AngleVectors (r_refdef.viewangles, vpn, vright, vup);
VectorCopy (r_refdef.vieworg, r_origin);
@ -982,7 +1001,6 @@ qboolean SW_SCR_UpdateScreen(void)
if (!CSQC_DrawView())
V_RenderView ();
R2D_PolyBlend ();
R2D_BrightenScreen();
}

View File

@ -774,7 +774,7 @@ qboolean SW_VID_ApplyGammaRamps (unsigned int gammarampsize, unsigned short *ra
{
return false;
}
char *SW_VID_GetRGBInfo(int *truevidwidth, int *truevidheight, enum uploadfmt *fmt)
char *SW_VID_GetRGBInfo(int *bytestride, int *truevidwidth, int *truevidheight, enum uploadfmt *fmt)
{
char *buf = NULL;
char *src, *dst;
@ -790,6 +790,7 @@ char *SW_VID_GetRGBInfo(int *truevidwidth, int *truevidheight, enum uploadfmt *f
dst[2] = src[0];
}
}
*bytestride = vid.pixelwidth*3;
*truevidwidth = vid.pixelwidth;
*truevidheight = vid.pixelheight;
*fmt = TF_BGR24;

View File

@ -53,8 +53,8 @@ int emscriptenfte_setupcanvas(
void(*Button)(unsigned int devid, int down, int mbutton),
int(*Keyboard)(unsigned int devid, int down, int keycode, int unicode),
void(*LoadFile)(char *url, char *mime, int filehandle),
void(*buttonevent)(unsigned int joydev, int button, int ispressed),
void(*axisevent)(unsigned int joydev, int axis, float value),
void(*buttonevent)(unsigned int joydev, int button, int ispressed, int isstandard),
void(*axisevent)(unsigned int joydev, int axis, float value, int isstandard),
int (*ShouldSwitchToFullscreen)(void)
);

View File

@ -266,10 +266,10 @@ mergeInto(LibraryManager.library,
delete FTEH.gamepads[gp.index];
if (FTEC.evcb.jaxis) //try and clear out the axis when released.
for (var j = 0; j < 6; j+=1)
Runtime.dynCall('viid', FTEC.evcb.jaxis, [gp.index, j, 0]);
Runtime.dynCall('viidi', FTEC.evcb.jaxis, [gp.index, j, 0, true]);
if (FTEC.evcb.jbutton) //try and clear out the axis when released.
for (var j = 0; j < 32+4; j+=1)
Runtime.dynCall('viid', FTEC.evcb.jbutton, [gp.index, j, 0]);
Runtime.dynCall('viiii', FTEC.evcb.jbutton, [gp.index, j, 0, true]);
console.log("Gamepad disconnected from index %d: %s", gp.index, gp.id);
break;
case 'pointerlockchange':
@ -362,9 +362,9 @@ mergeInto(LibraryManager.library,
//with events, we can do unplug stuff properly.
//otherwise hot unplug might be buggy.
var gamepads;
if (FTEH.gamepads !== undefined)
gamepads = FTEH.gamepads;
else
// if (FTEH.gamepads !== undefined)
// gamepads = FTEH.gamepads;
// else
gamepads = navigator.getGamepads ? navigator.getGamepads() : (navigator.webkitGetGamepads ? navigator.webkitGetGamepads : []);
if (gamepads !== undefined)
@ -380,23 +380,18 @@ mergeInto(LibraryManager.library,
var b = gp.buttons[j];
var p;
if (typeof(b) == "object")
{
p = b.pressed;
if (b.lastframe != p)
{ //cache it to avoid spam
b.lastframe = p;
Runtime.dynCall('viii', FTEC.evcb.jbutton, [gp.index, j, p]);
}
}
p = b.pressed; //.value is a fractional thing. oh well.
else
{//old chrome bug
p = b==1.0;
//warning: no cache. this is going to be spammy.
Runtime.dynCall('viii', FTEC.evcb.jbutton, [gp.index, j, p]);
p = b > 0.5; //old chrome bug
if (b.lastframe != p)
{ //cache it to avoid spam
b.lastframe = p;
Runtime.dynCall('viiii', FTEC.evcb.jbutton, [gp.index, j, p, gp.mapping=="standard"]);
}
}
for (var j = 0; j < gp.axes.length; j+=1)
Runtime.dynCall('viid', FTEC.evcb.jaxis, [gp.index, j, gp.axes[j]]);
Runtime.dynCall('viidi', FTEC.evcb.jaxis, [gp.index, j, gp.axes[j], gp.mapping=="standard"]);
}
},
emscriptenfte_setupcanvas__deps: ['$FTEC', '$Browser', 'emscriptenfte_buf_createfromarraybuf'],
@ -437,7 +432,6 @@ mergeInto(LibraryManager.library,
'keypress', 'keydown', 'keyup',
'touchstart', 'touchend', 'touchcancel', 'touchleave', 'touchmove',
'dragenter', 'dragover', 'drop',
'gamepadconnected', 'gamepaddisconnected',
'message',
'pointerlockchange', 'mozpointerlockchange', 'webkitpointerlockchange',
'focus', 'blur']; //try to fix alt-tab
@ -453,7 +447,7 @@ mergeInto(LibraryManager.library,
document.addEventListener(event, FTEC.handleevent, true);
});
var windowevents = ['message','vrdisplaypresentchange','vrdisplayactivate','vrdisplaydeactivate'];
var windowevents = ['message','vrdisplaypresentchange','vrdisplayactivate','vrdisplaydeactivate','gamepadconnected', 'gamepaddisconnected'];
windowevents.forEach(function(event)
{
window.addEventListener(event, FTEC.handleevent, true);

View File

@ -11,17 +11,79 @@ extern qboolean vid_isfullscreen;
qboolean mouseactive;
extern qboolean mouseusedforgui;
static int gamepaddeviceids[] = {DEVID_UNSET,DEVID_UNSET,DEVID_UNSET,DEVID_UNSET,DEVID_UNSET,DEVID_UNSET,DEVID_UNSET,DEVID_UNSET};
static int keyboardid[] = {0};
static int mouseid[] = {0};
static void *GLVID_getsdlglfunction(char *functionname)
{
return NULL;
}
static void IN_JoystickButtonEvent(unsigned int joydevid, int button, int ispressed)
static void IN_GamePadButtonEvent(unsigned int joydevid, int button, int ispressed, int isstandardmapping)
{
if (button >= 32+4)
return;
IN_KeyEvent(joydevid, ispressed, K_JOY1+button, 0);
int standardmapping[] =
{ //the order of these keys is different from that of xinput
//however, the quake button codes should be the same. I really ought to define some K_ aliases for them.
K_GP_A,
K_GP_B,
K_GP_X,
K_GP_Y,
K_GP_LEFT_SHOULDER,
K_GP_RIGHT_SHOULDER,
K_GP_LEFT_TRIGGER,
K_GP_RIGHT_TRIGGER,
K_GP_BACK,
K_GP_START,
K_GP_LEFT_THUMB,
K_GP_RIGHT_THUMB,
K_GP_DPAD_UP,
K_GP_DPAD_DOWN,
K_GP_DPAD_LEFT,
K_GP_DPAD_RIGHT,
K_GP_GUIDE,
//K_GP_UNKNOWN
};
if (joydevid < countof(gamepaddeviceids))
{
if (joydevid == gamepaddeviceids[joydevid])
{
if (!ispressed)
return; //don't send axis events until its enabled.
gamepaddeviceids[joydevid] = joydevid;
}
joydevid = gamepaddeviceids[joydevid];
}
if (isstandardmapping)
{
if (button < countof(standardmapping))
IN_KeyEvent(joydevid, ispressed, standardmapping[button], 0);
}
else
{
if (button < 32+4)
IN_KeyEvent(joydevid, ispressed, K_JOY1+button, 0);
}
}
static void IN_GamePadAxisEvent(unsigned int joydevid, int axis, float value, int isstandardmapping)
{
if (joydevid < countof(gamepaddeviceids))
{
joydevid = gamepaddeviceids[joydevid];
if (joydevid == DEVID_UNSET)
return; //don't send axis events until its enabled.
}
if (isstandardmapping)
{
int axismap[] = {GPAXIS_LT_RIGHT,GPAXIS_LT_DOWN,GPAXIS_RT_RIGHT,GPAXIS_RT_DOWN};
if (axis < countof(axismap))
IN_JoystickAxisEvent(joydevid, axismap[axis], value);
}
else
IN_JoystickAxisEvent(joydevid, axis, value);
}
static void VID_Resized(int width, int height)
@ -119,7 +181,7 @@ static int DOM_KeyEvent(unsigned int devid, int down, int scan, int uni)
scan = domkeytoquake(scan);
uni = (scan >= 32 && scan <= 127)?scan:0;
}
IN_KeyEvent(devid, down, scan, uni);
IN_KeyEvent(keyboardid[devid], down, scan, uni);
//Chars which don't map to some printable ascii value get preventDefaulted.
//This is to stop fucking annoying fucking things like backspace randomly destroying the page and thus game.
//And it has to be conditional, or we don't get any unicode chars at all.
@ -137,12 +199,12 @@ static void DOM_ButtonEvent(unsigned int devid, int down, int button)
//fixme: the event is a float. we ignore that.
while(button < 0)
{
IN_KeyEvent(devid, true, K_MWHEELUP, 0);
IN_KeyEvent(mouseid[devid], true, K_MWHEELUP, 0);
button += 1;
}
while(button > 0)
{
IN_KeyEvent(devid, true, K_MWHEELDOWN, 0);
IN_KeyEvent(mouseid[devid], true, K_MWHEELDOWN, 0);
button -= 1;
}
}
@ -154,9 +216,13 @@ static void DOM_ButtonEvent(unsigned int devid, int down, int button)
else if (button == 1)
button = 2;
IN_KeyEvent(devid, down, K_MOUSE1+button, 0);
IN_KeyEvent(mouseid[devid], down, K_MOUSE1+button, 0);
}
}
void DOM_MouseMove(unsigned int devid, int abs, float x, float y, float z, float size)
{
IN_MouseMove(mouseid[devid], abs, x, y, z, size);
}
void DOM_LoadFile(char *loc, char *mime, int handle)
{
@ -206,12 +272,12 @@ qboolean GLVID_Init (rendererstate_t *info, unsigned char *palette)
info->width,
info->height,
VID_Resized,
IN_MouseMove,
DOM_MouseMove,
DOM_ButtonEvent,
DOM_KeyEvent,
DOM_LoadFile,
IN_JoystickButtonEvent,
IN_JoystickAxisEvent,
IN_GamePadButtonEvent,
IN_GamePadAxisEvent,
VID_ShouldSwitchToFullscreen
))
{
@ -307,5 +373,22 @@ void INS_Commands (void)
}
void INS_EnumerateDevices(void *ctx, void(*callback)(void *ctx, const char *type, const char *devicename, unsigned int *qdevid))
{
size_t i;
char foobar[64];
for (i = 0; i < countof(gamepaddeviceids); i++)
{
Q_snprintfz(foobar, sizeof(foobar), "gp%i", i);
callback(ctx, "gamepad", foobar, &gamepaddeviceids[i]);
}
for (i = 0; i < countof(mouseid); i++)
{
Q_snprintfz(foobar, sizeof(foobar), "m%i", i);
callback(ctx, "mouse", foobar, &mouseid[i]);
}
for (i = 0; i < countof(keyboardid); i++)
{
Q_snprintfz(foobar, sizeof(foobar), "kb%i", i);
callback(ctx, "keyboard", foobar, &keyboardid[i]);
}
}

View File

@ -1,6 +1,3 @@
FIXME: verify+clarify these docs...
There are multiple ways to embed a program into a browser. The 'web'/emscripten port, the nacl port, the npapi port, and the activex port.
Quick start with browser-servers:
@ -31,7 +28,7 @@ sv_port_rtc - This says the broker+resource used to register a webrtc server.
cfg_save - This command saves your config to your browser's local storage. In combination with seta, you can save most settings this way.
Beware that browsers might still wipe it all eventually.
Hosting:
Hosting Quake:
To get fte running on a web page, you will need:
ftewebgl.html - An html file that embeds the javascript. You can probably modify fte's default if you want to integrate it better with your site, it doesn't change much.
ftewebgl.js - This is the meat of the engine. All in a single file. pre-gzip it if you can, to keep sizes down.
@ -48,11 +45,14 @@ The browser port is set up to ignore most args when linked to from another site.
Built-in http server:
The http server provided by sv_port_tcp will provide a page (either directly or with a redirect) to a version of the webgl client.
Thanks to allow_download_* cvars, only certain things may be downloaded.
Unlike over game connections, the server will transparently also provide http content compression only where a .gz file has also been provided (and is more recent and in the same gamedir).
Additionally, there are also some files generated by the server.
index.html (and no resource) - attempts to provide a link to the webgl version of fte.
default.fmf - provides a redirect to the manifest's update url.
all other files match what you would be able to download over udp.
Manifest files:
These are FTE's way of reconfiguring FTE for standalone mods. They offer basic rebranding features as well as content updates.
They contain a number of attributes, and frankly its easier to start with an example. Check http://triptohell.info/moodles/web/ for a few.