07 Jul 2008
This commit is contained in:
parent
bb1224b532
commit
9a4dd30714
|
@ -275,9 +275,12 @@ void Con_Print( const char *txt )
|
|||
bool skipnotify = false;
|
||||
int prev;
|
||||
|
||||
if( !con.initialized )
|
||||
return;
|
||||
|
||||
// client not running
|
||||
if(host.type == HOST_DEDICATED) return;
|
||||
if(!con.initialized) return;
|
||||
if( host.type == HOST_DEDICATED )
|
||||
return;
|
||||
|
||||
if(!com.strncmp( txt, "[skipnotify]", 12 ))
|
||||
{
|
||||
|
|
|
@ -22,6 +22,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#include "common.h"
|
||||
#include "client.h"
|
||||
|
||||
void CL_PacketEvent( netadr_t from, sizebuf_t *msg )
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
=========================================================================
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1084,7 +1084,7 @@ CL_KeyEvent
|
|||
Called by the system for both key up and key down events
|
||||
===================
|
||||
*/
|
||||
void Key_Event(int key, bool down, uint time)
|
||||
void Key_Event( int key, bool down, uint time )
|
||||
{
|
||||
char *kb;
|
||||
char cmd[1024];
|
||||
|
|
|
@ -22,7 +22,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#include "common.h"
|
||||
#include "client.h"
|
||||
|
||||
cvar_t *freelook;
|
||||
cvar_t *rcon_client_password;
|
||||
cvar_t *rcon_address;
|
||||
|
||||
|
@ -37,11 +36,11 @@ cvar_t *cl_add_particles;
|
|||
cvar_t *cl_add_lights;
|
||||
cvar_t *cl_add_entities;
|
||||
cvar_t *cl_add_blend;
|
||||
|
||||
cvar_t *cl_maxpackets;
|
||||
cvar_t *cl_shownet;
|
||||
cvar_t *cl_showmiss;
|
||||
cvar_t *cl_showclamp;
|
||||
|
||||
cvar_t *cl_mouselook;
|
||||
cvar_t *cl_paused;
|
||||
|
||||
cvar_t *lookspring;
|
||||
|
@ -339,7 +338,7 @@ void CL_Rcon_f (void)
|
|||
to.port = BigShort (PORT_SERVER);
|
||||
}
|
||||
|
||||
NET_SendPacket (NS_CLIENT, strlen(message)+1, message, to);
|
||||
NET_SendPacket( NS_CLIENT, strlen(message)+1, message, to);
|
||||
}
|
||||
|
||||
|
||||
|
@ -459,7 +458,7 @@ void CL_Packet_f (void)
|
|||
}
|
||||
*out = 0;
|
||||
|
||||
NET_SendPacket (NS_CLIENT, out-send, send, adr);
|
||||
NET_SendPacket( NS_CLIENT, out-send, send, adr);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -804,7 +803,7 @@ when they overflow
|
|||
*/
|
||||
void CL_DumpPackets (void)
|
||||
{
|
||||
while (NET_GetPacket (NS_CLIENT, &net_from, &net_message))
|
||||
while (Sys_RecvPacket (&net_from, &net_message))
|
||||
{
|
||||
Msg ("dumnping a packet\n");
|
||||
}
|
||||
|
@ -812,7 +811,7 @@ void CL_DumpPackets (void)
|
|||
|
||||
void CL_ReadNetMessage( void )
|
||||
{
|
||||
while (NET_GetPacket (NS_CLIENT, &net_from, &net_message))
|
||||
while (Sys_RecvPacket (&net_from, &net_message))
|
||||
{
|
||||
// remote command packet
|
||||
if(*(int *)net_message.data == -1)
|
||||
|
@ -1178,9 +1177,10 @@ void CL_InitLocal (void)
|
|||
cl_yawspeed = Cvar_Get ("cl_yawspeed", "140", 0, "client yaw speed" );
|
||||
cl_pitchspeed = Cvar_Get ("cl_pitchspeed", "150", 0, "client pitch speed" );
|
||||
cl_anglespeedkey = Cvar_Get ("cl_anglespeedkey", "1.5", 0, "client anglespeed" );
|
||||
cl_maxpackets = Cvar_Get( "cl_maxpackets", "30", CVAR_ARCHIVE, "number of usercmd packets" );
|
||||
|
||||
cl_run = Cvar_Get ("cl_run", "0", CVAR_ARCHIVE, "keep client for always run mode" );
|
||||
freelook = Cvar_Get( "freelook", "1", CVAR_ARCHIVE, "enables mouse look" );
|
||||
cl_mouselook = Cvar_Get( "cl_mouselook", "1", CVAR_ARCHIVE, "enables mouse look" );
|
||||
lookspring = Cvar_Get ("lookspring", "0", CVAR_ARCHIVE, "allow look spring" );
|
||||
lookstrafe = Cvar_Get ("lookstrafe", "0", CVAR_ARCHIVE, "allow look strafe" );
|
||||
|
||||
|
@ -1405,7 +1405,12 @@ void CL_Frame( dword time )
|
|||
{
|
||||
static dword extratime;
|
||||
|
||||
if( dedicated->integer ) return;
|
||||
if( host.type == HOST_DEDICATED )
|
||||
return;
|
||||
|
||||
// get server to client packets
|
||||
Host_EventLoop();
|
||||
Cbuf_Execute();
|
||||
|
||||
extratime += time;
|
||||
|
||||
|
@ -1414,9 +1419,6 @@ void CL_Frame( dword time )
|
|||
if( extratime < 1000 / cl_maxfps->value)
|
||||
return; // framerate is too high
|
||||
|
||||
// let the mouse activate or deactivate
|
||||
CL_UpdateMouse();
|
||||
|
||||
// decide the simulation time
|
||||
cl.time += extratime;
|
||||
cls.realtime = Sys_Milliseconds();
|
||||
|
@ -1473,7 +1475,8 @@ CL_Init
|
|||
*/
|
||||
void CL_Init( void )
|
||||
{
|
||||
if (dedicated->value) return; // nothing running on the client
|
||||
if( host.type == HOST_DEDICATED )
|
||||
return; // nothing running on the client
|
||||
|
||||
// all archived variables will now be loaded
|
||||
scr_loading = Cvar_Get("scr_loading", "0", 0, "loading bar progress" );
|
||||
|
@ -1490,6 +1493,7 @@ void CL_Init( void )
|
|||
UI_Init();
|
||||
SCR_Init();
|
||||
CL_InitLocal();
|
||||
host.cl_running = true;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1511,6 +1515,7 @@ void CL_Shutdown(void)
|
|||
UI_Shutdown();
|
||||
S_Shutdown();
|
||||
CL_ShutdownInput();
|
||||
host.cl_running = false;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -340,8 +340,8 @@ void PF_getmousepos( void )
|
|||
if(!VM_ValidateArgs( "getmousepos", 0 ))
|
||||
return;
|
||||
|
||||
PRVM_G_VECTOR(OFS_RETURN)[0] = mouse_x;
|
||||
PRVM_G_VECTOR(OFS_RETURN)[1] = mouse_y;
|
||||
PRVM_G_VECTOR(OFS_RETURN)[0] = cls.mouse_x;
|
||||
PRVM_G_VECTOR(OFS_RETURN)[1] = cls.mouse_y;
|
||||
PRVM_G_VECTOR(OFS_RETURN)[2] = 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -67,7 +67,8 @@ typedef struct
|
|||
extern char cl_weaponmodels[MAX_CLIENTWEAPONMODELS][MAX_QPATH];
|
||||
extern int num_cl_weaponmodels;
|
||||
|
||||
#define CMD_BACKUP 64 // allow a lot of command backups for very fast systems
|
||||
#define CMD_BACKUP 64 // allow a lot of command backups for very fast systems
|
||||
#define CMD_MASK (CMD_BACKUP - 1)
|
||||
|
||||
//
|
||||
// the client_t structure is wiped completely at every
|
||||
|
@ -85,8 +86,8 @@ typedef struct
|
|||
|
||||
usercmd_t cmd;
|
||||
usercmd_t cmds[CMD_BACKUP]; // each mesage will send several old cmds
|
||||
dword cmd_time[CMD_BACKUP]; // time sent, for calculating pings
|
||||
float predicted_origins[CMD_BACKUP][3]; // for debug comparing against server
|
||||
int cmd_number;
|
||||
|
||||
float predicted_step; // for stair up smoothing
|
||||
uint predicted_step_time;
|
||||
|
@ -98,6 +99,13 @@ typedef struct
|
|||
frame_t frame; // received from server
|
||||
int surpressCount; // number of messages rate supressed
|
||||
frame_t frames[UPDATE_BACKUP];
|
||||
outpacket_t packets[PACKET_BACKUP]; // information about each packet we have sent out
|
||||
|
||||
// mouse current position
|
||||
int mouse_x[2];
|
||||
int mouse_y[2];
|
||||
int mouse_step;
|
||||
float mouse_sens;
|
||||
|
||||
// the client maintains its own idea of view angles, which are
|
||||
// sent to the server each frame. It is cleared to 0 upon entering each level.
|
||||
|
@ -230,6 +238,12 @@ typedef struct
|
|||
serverinfo_t serverlist[MAX_SERVERS]; // servers to join
|
||||
int numservers;
|
||||
int pingtime; // servers timebase
|
||||
|
||||
int last_sent; // for retransmits
|
||||
|
||||
// cursor mouse pos for uimenu
|
||||
int mouse_x;
|
||||
int mouse_y;
|
||||
} client_static_t;
|
||||
|
||||
extern client_static_t cls;
|
||||
|
@ -298,7 +312,7 @@ extern cvar_t *cl_pitchspeed;
|
|||
extern cvar_t *cl_run;
|
||||
|
||||
extern cvar_t *cl_anglespeedkey;
|
||||
|
||||
extern cvar_t *cl_maxpackets;
|
||||
extern cvar_t *cl_shownet;
|
||||
extern cvar_t *cl_showmiss;
|
||||
extern cvar_t *cl_showclamp;
|
||||
|
@ -310,11 +324,10 @@ extern cvar_t *ui_sensitivity;
|
|||
|
||||
extern cvar_t *m_pitch;
|
||||
extern cvar_t *m_yaw;
|
||||
extern cvar_t *m_forward;
|
||||
extern cvar_t *m_side;
|
||||
extern cvar_t *m_mouse;
|
||||
extern cvar_t *m_forward;
|
||||
extern cvar_t *cl_mouselook;
|
||||
|
||||
extern cvar_t *freelook;
|
||||
|
||||
extern cvar_t *cl_lightlevel; // FIXME HACK
|
||||
|
||||
|
@ -446,18 +459,6 @@ void CL_RequestNextDownload (void);
|
|||
//
|
||||
// cl_input
|
||||
//
|
||||
typedef struct
|
||||
{
|
||||
int down[2]; // key nums holding it down
|
||||
unsigned downtime; // msec timestamp
|
||||
unsigned msec; // msec down this frame
|
||||
int state;
|
||||
} kbutton_t;
|
||||
|
||||
extern kbutton_t in_mlook, in_klook;
|
||||
extern kbutton_t in_strafe;
|
||||
extern kbutton_t in_speed;
|
||||
|
||||
void CL_InitInput( void );
|
||||
void CL_ShutdownInput( void );
|
||||
void CL_UpdateMouse( void );
|
||||
|
@ -473,9 +474,8 @@ void CL_WriteToServer (usercmd_t *cmd);
|
|||
void CL_BaseMove (usercmd_t *cmd);
|
||||
|
||||
void IN_CenterView (void);
|
||||
|
||||
float CL_KeyState (kbutton_t *key);
|
||||
void CL_CharEvent( int key );
|
||||
void CL_MouseEvent( int dx, int dy, int time );
|
||||
char *Key_KeynumToString (int keynum);
|
||||
|
||||
//
|
||||
|
|
|
@ -43,20 +43,6 @@ void Sys_Error( const char *error, ... )
|
|||
com.error("%s", errorstring );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
Sys_SendKeyEvents
|
||||
|
||||
Send Key_Event calls
|
||||
================
|
||||
*/
|
||||
void Sys_SendKeyEvents( void )
|
||||
{
|
||||
// grab frame time
|
||||
host.sv_timer = Sys_GetKeyEvents();
|
||||
host.cl_timer = Sys_Milliseconds();
|
||||
}
|
||||
|
||||
/*
|
||||
=======================================================================
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ extern vsound_exp_t *se;
|
|||
#define MAX_ENTNUMBER 99999 // for server and client parsing
|
||||
#define MAX_HEARTBEAT -99999 // connection time
|
||||
#define HOST_FRAMETIME 100 // host.frametime in msecs (change with caution)
|
||||
#define MAX_EVENTS 1024
|
||||
|
||||
//#define USE_COORD_FRAC
|
||||
|
||||
|
@ -48,6 +49,7 @@ INPUT
|
|||
|
||||
==============================================================
|
||||
*/
|
||||
#define WM_MOUSEWHEEL ( WM_MOUSELAST + 1 ) // message that will be supported by the OS
|
||||
|
||||
typedef enum e_keycodes
|
||||
{
|
||||
|
@ -133,15 +135,15 @@ static byte scan_to_key[128] =
|
|||
0,0,0,K_F11,K_F12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
};
|
||||
|
||||
// mouse support
|
||||
void M_Activate( void );
|
||||
void M_Event( int mstate );
|
||||
#define WM_MOUSEWHEEL (WM_MOUSELAST + 1) // message that will be supported by the OS
|
||||
extern int mouse_x, mouse_y, old_mouse_x, old_mouse_y, mx_accum, my_accum;
|
||||
//
|
||||
// input.c
|
||||
//
|
||||
void IN_Init( void );
|
||||
void IN_Frame( void );
|
||||
void IN_Shutdown( void );
|
||||
void IN_MouseEvent( int mstate );
|
||||
|
||||
// cvars
|
||||
extern cvar_t *dedicated;
|
||||
extern cvar_t *host_serverstate;
|
||||
extern cvar_t *host_frametime;
|
||||
extern cvar_t *cm_paused;
|
||||
|
@ -184,17 +186,23 @@ typedef struct host_parm_s
|
|||
jmp_buf abortframe; // abort current frame
|
||||
|
||||
string finalmsg; // server shutdown final message
|
||||
|
||||
dword framecount; // global framecount
|
||||
uint sv_timer; // SV_Input msg time
|
||||
uint cl_timer; // CL_Input msg time
|
||||
uint old_cl_timer; // save old msg time
|
||||
|
||||
HWND hWnd; // main window
|
||||
|
||||
int developer; // show all developer's message
|
||||
bool paused; // freeze server
|
||||
bool stuffcmdsrun; // sturtup script
|
||||
dword framecount; // global framecount
|
||||
dword frametime[2]; // second value is old frametime
|
||||
|
||||
int events_head;
|
||||
int events_tail;
|
||||
sys_event_t events[MAX_EVENTS];
|
||||
file_t *journal; // journal file
|
||||
|
||||
// get rid of this
|
||||
bool sv_running; // server is running ?
|
||||
bool cl_running; // client is running ?
|
||||
|
||||
} host_parm_t;
|
||||
|
||||
extern host_parm_t host;
|
||||
|
@ -206,6 +214,7 @@ void Host_SetServerState( int state );
|
|||
int Host_ServerState( void );
|
||||
float Host_FrameTime( void );
|
||||
void Host_AbortCurrentFrame( void );
|
||||
dword Host_EventLoop( void );
|
||||
|
||||
// message functions
|
||||
void Host_Print(const char *txt);
|
||||
|
@ -228,10 +237,12 @@ CLIENT / SERVER SYSTEMS
|
|||
void CL_Init( void );
|
||||
void CL_Shutdown( void );
|
||||
void CL_Frame( dword time );
|
||||
void CL_PacketEvent( netadr_t from, sizebuf_t *msg );
|
||||
|
||||
void SV_Init( void );
|
||||
void SV_Shutdown( bool reconnect );
|
||||
void SV_Frame( dword time );
|
||||
void SV_PacketEvent( netadr_t from, sizebuf_t *msg );
|
||||
|
||||
/*
|
||||
==============================================================
|
||||
|
@ -423,7 +434,6 @@ bool Cmd_GetMusicList(const char *s, char *completedname, int length );
|
|||
bool Cmd_GetSoundList(const char *s, char *completedname, int length );
|
||||
bool Cmd_CheckMapsList( void );
|
||||
void Sys_Error( const char *msg, ... );
|
||||
void Sys_SendKeyEvents( void );
|
||||
|
||||
// get rid of this
|
||||
float frand(void); // 0 to 1
|
||||
|
|
|
@ -22,6 +22,7 @@ launch_exp_t DLLEXPORT *CreateAPI( stdlib_api_t *input, void *unused )
|
|||
Host.Free = Host_Free;
|
||||
Host.Cmd = Cmd_ForwardToServer;
|
||||
Host.CPrint = Host_Print;
|
||||
Host.SZInit = SZ_Init;
|
||||
|
||||
return &Host;
|
||||
}
|
|
@ -190,6 +190,10 @@ SOURCE=.\host.c
|
|||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\input.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\network\net_chan.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
@ -198,10 +202,6 @@ SOURCE=.\network\net_msg.c
|
|||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\network\net_wins.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\server\sv_client.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
|
398
engine/host.c
398
engine/host.c
|
@ -25,7 +25,7 @@ dll_info_t vprogs_dll = { "vprogs.dll", NULL, "CreateAPI", NULL, NULL, true, siz
|
|||
dll_info_t vsound_dll = { "vsound.dll", NULL, "CreateAPI", NULL, NULL, true, sizeof(vsound_exp_t) };
|
||||
|
||||
cvar_t *timescale;
|
||||
cvar_t *dedicated;
|
||||
cvar_t *host_journal;
|
||||
cvar_t *host_serverstate;
|
||||
cvar_t *host_frametime;
|
||||
cvar_t *host_cheats;
|
||||
|
@ -35,6 +35,8 @@ cvar_t *r_xpos; // X coordinate of window position
|
|||
cvar_t *r_ypos; // Y coordinate of window position
|
||||
cvar_t *cm_paused;
|
||||
|
||||
cvar_t *host_maxfps;
|
||||
|
||||
/*
|
||||
=======
|
||||
Host_MapKey
|
||||
|
@ -85,29 +87,6 @@ static int Host_MapKey( int key )
|
|||
}
|
||||
}
|
||||
|
||||
void Host_InitCommon( uint funcname, int argc, char **argv )
|
||||
{
|
||||
char dev_level[4];
|
||||
|
||||
newcom = com;
|
||||
|
||||
// overload some funcs
|
||||
newcom.error = Host_Error;
|
||||
|
||||
// check developer mode
|
||||
if(FS_GetParmFromCmdLine("-dev", dev_level ))
|
||||
host.developer = com.atoi(dev_level);
|
||||
|
||||
// TODO: init basedir here
|
||||
FS_LoadGameInfo("gameinfo.txt");
|
||||
zonepool = Mem_AllocPool("Zone Engine");
|
||||
}
|
||||
|
||||
void Host_FreeCommon( void )
|
||||
{
|
||||
Mem_FreePool( &zonepool );
|
||||
}
|
||||
|
||||
void Host_InitPhysic( void )
|
||||
{
|
||||
static physic_imp_t pi;
|
||||
|
@ -312,11 +291,308 @@ void VID_Init( void )
|
|||
Host_InitSound();
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
Host_InitJournaling
|
||||
=================
|
||||
*/
|
||||
void Host_InitJournaling( void )
|
||||
{
|
||||
host_journal = Cvar_Get( "host_journal", "0", CVAR_SYSTEMINFO, "journaling system events (1 = record, 2 = playback)" );
|
||||
if( !host_journal->integer ) return;
|
||||
|
||||
if( host_journal->integer == 1 )
|
||||
{
|
||||
MsgDev( D_NOTE, "Host_InitJournaling: record mode\n" );
|
||||
host.journal = FS_Open( "vprogs/events.dat", "wb" );
|
||||
}
|
||||
else if( host_journal->integer == 2 )
|
||||
{
|
||||
MsgDev( D_NOTE, "Host_InitJournaling: playback mode\n" );
|
||||
host.journal = FS_Open( "vprogs/events.dat", "rb" );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
Host_GetRealEvent
|
||||
=================
|
||||
*/
|
||||
sys_event_t Host_GetRealEvent( void )
|
||||
{
|
||||
sys_event_t ev;
|
||||
int r;
|
||||
|
||||
// either get an event from the system or the journal file
|
||||
if( host_journal->integer == 2 )
|
||||
{
|
||||
r = FS_Read( host.journal, &ev, sizeof(ev) );
|
||||
if( r != sizeof(ev))
|
||||
{
|
||||
Sys_Error( "Host_GetRealEvent: error reading from journal file\n" );
|
||||
return ev;
|
||||
}
|
||||
if( ev.length )
|
||||
{
|
||||
ev.data = Z_Malloc( ev.length );
|
||||
r = FS_Read( host.journal, ev.data, ev.length );
|
||||
if( r != ev.length )
|
||||
{
|
||||
Sys_Error( "Host_GetRealEvent: error reading from journal file\n" );
|
||||
return ev;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ev = Sys_GetEvent();
|
||||
|
||||
// write the journal value out if needed
|
||||
if( host_journal->integer == 1 )
|
||||
{
|
||||
r = FS_Write( host.journal, &ev, sizeof(ev));
|
||||
if( r != sizeof(ev) )
|
||||
{
|
||||
Sys_Error( "Host_GetRealEvent: error writing to journal file" );
|
||||
return ev;
|
||||
}
|
||||
if( ev.length )
|
||||
{
|
||||
r = FS_Write( host.journal, ev.data, ev.length );
|
||||
if( r != ev.length )
|
||||
{
|
||||
Sys_Error( "Host_GetRealEvent: error writing to journal file" );
|
||||
return ev;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ev;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
Host_InitPushEvent
|
||||
=================
|
||||
*/
|
||||
void Host_InitPushEvent( void )
|
||||
{
|
||||
memset( host.events, 0, sizeof(host.events));
|
||||
host.events_head = 0;
|
||||
host.events_tail = 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
Host_PushEvent
|
||||
=================
|
||||
*/
|
||||
void Host_PushEvent( sys_event_t *event )
|
||||
{
|
||||
sys_event_t *ev;
|
||||
static bool overflow = false;
|
||||
|
||||
ev = &host.events[host.events_head & (MAX_EVENTS-1)];
|
||||
|
||||
if( host.events_head - host.events_tail >= MAX_EVENTS )
|
||||
{
|
||||
if( !overflow )
|
||||
{
|
||||
MsgDev( D_WARN, "Host_PushEvent overflow\n" );
|
||||
overflow = true;
|
||||
}
|
||||
if( ev->data ) Mem_Free( ev->data );
|
||||
host.events_tail++;
|
||||
}
|
||||
else overflow = false;
|
||||
|
||||
*ev = *event;
|
||||
host.events_head++;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
Host_GetEvent
|
||||
=================
|
||||
*/
|
||||
sys_event_t Host_GetEvent( void )
|
||||
{
|
||||
if( host.events_head > host.events_tail )
|
||||
{
|
||||
host.events_tail++;
|
||||
return host.events[(host.events_tail - 1)&(MAX_EVENTS-1)];
|
||||
}
|
||||
return Host_GetRealEvent();
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
Host_EventLoop
|
||||
|
||||
Returns last event time
|
||||
=================
|
||||
*/
|
||||
dword Host_EventLoop( void )
|
||||
{
|
||||
sys_event_t ev;
|
||||
netadr_t ev_from;
|
||||
byte bufData[MAX_MSGLEN];
|
||||
sizebuf_t buf;
|
||||
|
||||
SZ_Init( &buf, bufData, sizeof( bufData ));
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
ev = Host_GetEvent();
|
||||
|
||||
// if no more events are available
|
||||
if( ev.type == SE_NONE )
|
||||
{
|
||||
// manually send packet events for the loopback channel
|
||||
while( NET_GetLoopPacket( NS_CLIENT, &ev_from, &buf ))
|
||||
{
|
||||
CL_PacketEvent( ev_from, &buf );
|
||||
}
|
||||
while( NET_GetLoopPacket( NS_SERVER, &ev_from, &buf ))
|
||||
{
|
||||
SV_PacketEvent( ev_from, &buf );
|
||||
}
|
||||
return ev.time;
|
||||
}
|
||||
switch ( ev.type )
|
||||
{
|
||||
case SE_NONE:
|
||||
break;
|
||||
case SE_KEY:
|
||||
Key_Event( ev.value[0], ev.value[1], ev.time );
|
||||
break;
|
||||
case SE_CHAR:
|
||||
CL_CharEvent( ev.value[0] );
|
||||
break;
|
||||
case SE_MOUSE:
|
||||
CL_MouseEvent( ev.value[0], ev.value[1], ev.time );
|
||||
break;
|
||||
case SE_CONSOLE:
|
||||
Cbuf_AddText( va( "%s\n", ev.data ));
|
||||
break;
|
||||
case SE_PACKET:
|
||||
ev_from = *(netadr_t *)ev.data;
|
||||
buf.cursize = ev.length - sizeof( ev_from );
|
||||
|
||||
// we must copy the contents of the message out, because
|
||||
// the event buffers are only large enough to hold the
|
||||
// exact payload, but channel messages need to be large
|
||||
// enough to hold fragment reassembly
|
||||
if((uint)buf.cursize > buf.maxsize )
|
||||
{
|
||||
MsgDev( D_WARN, "Host_EventLoop: oversize packet\n");
|
||||
continue;
|
||||
}
|
||||
Mem_Copy( buf.data, (byte *)((netadr_t *)ev.data + 1), buf.cursize );
|
||||
if ( host.sv_running ) SV_PacketEvent( ev_from, &buf );
|
||||
else CL_PacketEvent( ev_from, &buf );
|
||||
break;
|
||||
default:
|
||||
Host_Error( "Host_EventLoop: bad event type %i", ev.type );
|
||||
break;
|
||||
}
|
||||
if( ev.data ) Mem_Free( ev.data );
|
||||
}
|
||||
return 0; // never reached
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
Host_Milliseconds
|
||||
|
||||
Can be used for profiling, but will be journaled accurately
|
||||
================
|
||||
*/
|
||||
int Host_Milliseconds( void )
|
||||
{
|
||||
sys_event_t ev;
|
||||
|
||||
// get events and push them until we get a null event with the current time
|
||||
do {
|
||||
ev = Host_GetRealEvent();
|
||||
if( ev.type != SE_NONE )
|
||||
Host_PushEvent( &ev );
|
||||
} while( ev.type != SE_NONE );
|
||||
|
||||
return ev.time;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
Host_ModifyMsec
|
||||
================
|
||||
*/
|
||||
int Host_ModifyTime( int msec )
|
||||
{
|
||||
int clamp_time;
|
||||
|
||||
// modify time for debugging values
|
||||
if( timescale->value ) msec *= timescale->value;
|
||||
if( msec < 1 && timescale->value ) msec = 1;
|
||||
|
||||
if( host.type == HOST_DEDICATED )
|
||||
{
|
||||
// dedicated servers don't want to clamp for a much longer
|
||||
// period, because it would mess up all the client's views of time.
|
||||
if( msec > 500 ) MsgDev( D_WARN, "Host_ModifyTimer: %i msec frame time\n", msec );
|
||||
clamp_time = 5000;
|
||||
}
|
||||
else
|
||||
{
|
||||
// for local single player gaming
|
||||
// we may want to clamp the time to prevent players from
|
||||
// flying off edges when something hitches.
|
||||
clamp_time = 200;
|
||||
}
|
||||
if( msec > clamp_time ) msec = clamp_time;
|
||||
return msec;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
Host_Frame
|
||||
=================
|
||||
*/
|
||||
void Host_Frame( void )
|
||||
{
|
||||
dword time, min_time;
|
||||
static int last_time;
|
||||
|
||||
if( setjmp(host.abortframe))
|
||||
return;
|
||||
|
||||
rand(); // keep the random time dependent
|
||||
// we may want to spin here if things are going too fast
|
||||
if( host.type != HOST_DEDICATED && host_maxfps->integer > 0 )
|
||||
min_time = 1000 / host_maxfps->integer;
|
||||
else min_time = 1;
|
||||
|
||||
do {
|
||||
host.frametime[0] = Host_EventLoop();
|
||||
if( last_time > host.frametime[0] )
|
||||
last_time = host.frametime[0];
|
||||
time = host.frametime[0] - last_time;
|
||||
} while( time < min_time );
|
||||
Cbuf_Execute();
|
||||
|
||||
last_time = host.frametime[0];
|
||||
time = Host_ModifyTime( time );
|
||||
|
||||
SV_Frame( time ); // server frame
|
||||
CL_Frame( time ); // client frame
|
||||
|
||||
host.framecount++;
|
||||
}
|
||||
|
||||
/*
|
||||
void Host_Frame( dword time )
|
||||
{
|
||||
char *s;
|
||||
|
@ -344,6 +620,7 @@ void Host_Frame( dword time )
|
|||
|
||||
host.framecount++;
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
====================
|
||||
|
@ -361,13 +638,13 @@ long Host_WndProc( void *hWnd, uint uMsg, uint wParam, long lParam )
|
|||
case WM_MOUSEWHEEL:
|
||||
if((short)HIWORD(wParam) > 0)
|
||||
{
|
||||
Key_Event( K_MWHEELUP, true, host.sv_timer );
|
||||
Key_Event( K_MWHEELUP, false, host.sv_timer );
|
||||
Sys_QueEvent( -1, SE_KEY, K_MWHEELUP, true, 0, NULL );
|
||||
Sys_QueEvent( -1, SE_KEY, K_MWHEELUP, false, 0, NULL );
|
||||
}
|
||||
else
|
||||
{
|
||||
Key_Event( K_MWHEELDOWN, true, host.sv_timer );
|
||||
Key_Event( K_MWHEELDOWN, false, host.sv_timer );
|
||||
Sys_QueEvent( -1, SE_KEY, K_MWHEELDOWN, true, 0, NULL );
|
||||
Sys_QueEvent( -1, SE_KEY, K_MWHEELDOWN, false, 0, NULL );
|
||||
}
|
||||
break;
|
||||
case WM_CREATE:
|
||||
|
@ -392,7 +669,6 @@ long Host_WndProc( void *hWnd, uint uMsg, uint wParam, long lParam )
|
|||
|
||||
if( host.state == HOST_FRAME )
|
||||
{
|
||||
M_Activate();
|
||||
SetForegroundWindow( hWnd );
|
||||
ShowWindow( hWnd, SW_RESTORE );
|
||||
}
|
||||
|
@ -419,7 +695,6 @@ long Host_WndProc( void *hWnd, uint uMsg, uint wParam, long lParam )
|
|||
Cvar_SetValue( "r_ypos", yPos + r.top);
|
||||
r_xpos->modified = false;
|
||||
r_ypos->modified = false;
|
||||
M_Activate();
|
||||
}
|
||||
break;
|
||||
case WM_LBUTTONDOWN:
|
||||
|
@ -432,27 +707,27 @@ long Host_WndProc( void *hWnd, uint uMsg, uint wParam, long lParam )
|
|||
if(wParam & MK_LBUTTON) temp |= 1;
|
||||
if(wParam & MK_RBUTTON) temp |= 2;
|
||||
if(wParam & MK_MBUTTON) temp |= 4;
|
||||
M_Event( temp );
|
||||
IN_MouseEvent( temp );
|
||||
break;
|
||||
case WM_SYSCOMMAND:
|
||||
if( wParam == SC_SCREENSAVE ) return 0;
|
||||
break;
|
||||
case WM_SYSKEYDOWN:
|
||||
if( wParam == 13 && r_fullscreen)
|
||||
if( wParam == 13 && r_fullscreen )
|
||||
{
|
||||
Cvar_SetValue( "fullscreen", !r_fullscreen->value );
|
||||
return 0;
|
||||
}
|
||||
// intentional fallthrough
|
||||
case WM_KEYDOWN:
|
||||
Key_Event( Host_MapKey( lParam ), true, host.sv_timer);
|
||||
Sys_QueEvent( -1, SE_KEY, Host_MapKey( lParam ), true, 0, NULL );
|
||||
break;
|
||||
case WM_SYSKEYUP:
|
||||
case WM_KEYUP:
|
||||
Key_Event( Host_MapKey( lParam ), false, host.sv_timer);
|
||||
Sys_QueEvent( -1, SE_KEY, Host_MapKey( lParam ), false, 0, NULL );
|
||||
break;
|
||||
case WM_CHAR:
|
||||
CL_CharEvent( wParam );
|
||||
Sys_QueEvent( -1, SE_CHAR, wParam, 0, 0, NULL );
|
||||
break;
|
||||
}
|
||||
return DefWindowProc( hWnd, uMsg, wParam, lParam );
|
||||
|
@ -541,6 +816,35 @@ static void Host_Crash_f (void)
|
|||
*(int *)0 = 0xffffffff;
|
||||
}
|
||||
|
||||
void Host_InitCommon( uint funcname, int argc, char **argv )
|
||||
{
|
||||
char dev_level[4];
|
||||
|
||||
newcom = com;
|
||||
|
||||
// overload some funcs
|
||||
newcom.error = Host_Error;
|
||||
|
||||
// check developer mode
|
||||
if(FS_GetParmFromCmdLine("-dev", dev_level ))
|
||||
host.developer = com.atoi(dev_level);
|
||||
|
||||
Host_InitPushEvent();
|
||||
Host_InitJournaling();
|
||||
|
||||
// TODO: init basedir here
|
||||
FS_LoadGameInfo("gameinfo.txt");
|
||||
zonepool = Mem_AllocPool("Zone Engine");
|
||||
|
||||
IN_Init();
|
||||
}
|
||||
|
||||
void Host_FreeCommon( void )
|
||||
{
|
||||
IN_Shutdown();
|
||||
Mem_FreePool( &zonepool );
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
Host_Init
|
||||
|
@ -575,18 +879,16 @@ void Host_Init (uint funcname, int argc, char **argv)
|
|||
Cmd_AddCommand ("error", Host_Error_f, "just throw a fatal error to test shutdown procedures" );
|
||||
Cmd_AddCommand ("crash", Host_Crash_f, "a way to force a bus error for development reasons");
|
||||
}
|
||||
|
||||
|
||||
host_maxfps = Cvar_Get( "host_maxfps", "100", CVAR_ARCHIVE, "host fps upper limit" );
|
||||
cm_paused = Cvar_Get("cm_paused", "0", 0, "physics module pause" );
|
||||
host_frametime = Cvar_Get ("host_frametime", "0.1", 0, "host frametime" );
|
||||
host_serverstate = Cvar_Get ("host_serverstate", "0", 0, "displays current server state" );
|
||||
timescale = Cvar_Get ("timescale", "1", 0, "physics world timescale" );
|
||||
if(host.type == HOST_DEDICATED) dedicated = Cvar_Get ("dedicated", "1", CVAR_INIT, "currently server is in dedicated mode" );
|
||||
else dedicated = Cvar_Get ("dedicated", "0", CVAR_INIT, "currently server is in shared mode" );
|
||||
|
||||
s = va("^1Xash %g ^3%s", GI->version, buildstring );
|
||||
Cvar_Get( "version", s, CVAR_SERVERINFO|CVAR_INIT, "engine current version" );
|
||||
|
||||
if(dedicated->value) Cmd_AddCommand ("quit", Sys_Quit, "quit the game" );
|
||||
if( host.type == HOST_DEDICATED ) Cmd_AddCommand ("quit", Sys_Quit, "quit the game" );
|
||||
|
||||
NET_Init();
|
||||
Netchan_Init();
|
||||
|
@ -595,6 +897,8 @@ void Host_Init (uint funcname, int argc, char **argv)
|
|||
|
||||
SV_Init();
|
||||
CL_Init();
|
||||
|
||||
host.frametime[0] = Host_Milliseconds();
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -604,21 +908,11 @@ Host_Main
|
|||
*/
|
||||
void Host_Main( void )
|
||||
{
|
||||
static dword time, oldtime, newtime;
|
||||
|
||||
oldtime = Sys_Milliseconds(); // initialize timer
|
||||
|
||||
// main window message loop
|
||||
while( host.type != HOST_OFFLINE )
|
||||
{
|
||||
do {
|
||||
newtime = Sys_Milliseconds();
|
||||
time = newtime - oldtime;
|
||||
} while( time < 1 );
|
||||
|
||||
// engine frame
|
||||
Host_Frame( time );
|
||||
oldtime = newtime;
|
||||
IN_Frame();
|
||||
Host_Frame();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,200 @@
|
|||
//=======================================================================
|
||||
// Copyright XashXT Group 2007 ©
|
||||
// input.c - win32 input devices
|
||||
//=======================================================================
|
||||
|
||||
#include "common.h"
|
||||
#include "client.h"
|
||||
|
||||
bool in_mouseactive; // false when not focus app
|
||||
bool in_restore_spi;
|
||||
bool in_mouseinitialized;
|
||||
int in_originalmouseparms[3];
|
||||
int in_newmouseparms[3] = { 0, 0, 1 };
|
||||
bool in_mouseparmsvalid;
|
||||
int in_mouse_buttons;
|
||||
int in_mouse_oldbuttonstate;
|
||||
int window_center_x, window_center_y;
|
||||
RECT window_rect;
|
||||
POINT cur_pos;
|
||||
|
||||
/*
|
||||
===========
|
||||
IN_StartupMouse
|
||||
===========
|
||||
*/
|
||||
void IN_StartupMouse( void )
|
||||
{
|
||||
cvar_t *cv;
|
||||
|
||||
cv = Cvar_Get( "in_initmouse", "1", CVAR_SYSTEMINFO, "allow mouse device" );
|
||||
if ( !cv->value ) return;
|
||||
|
||||
in_mouse_buttons = 3;
|
||||
in_mouseparmsvalid = SystemParametersInfo( SPI_GETMOUSE, 0, in_originalmouseparms, 0 );
|
||||
in_mouseinitialized = true;
|
||||
}
|
||||
|
||||
/*
|
||||
===========
|
||||
IN_ActivateMouse
|
||||
|
||||
Called when the window gains focus or changes in some way
|
||||
===========
|
||||
*/
|
||||
void IN_ActivateMouse( void )
|
||||
{
|
||||
int width, height;
|
||||
|
||||
if( !in_mouseinitialized )
|
||||
return;
|
||||
|
||||
if( in_mouseactive ) return;
|
||||
in_mouseactive = true;
|
||||
|
||||
if( in_mouseparmsvalid )
|
||||
in_restore_spi = SystemParametersInfo( SPI_SETMOUSE, 0, in_newmouseparms, 0 );
|
||||
|
||||
width = GetSystemMetrics(SM_CXSCREEN);
|
||||
height = GetSystemMetrics(SM_CYSCREEN);
|
||||
|
||||
GetWindowRect( host.hWnd, &window_rect);
|
||||
if (window_rect.left < 0) window_rect.left = 0;
|
||||
if (window_rect.top < 0) window_rect.top = 0;
|
||||
if (window_rect.right >= width) window_rect.right = width - 1;
|
||||
if (window_rect.bottom >= height-1) window_rect.bottom = height - 1;
|
||||
|
||||
window_center_x = (window_rect.right + window_rect.left)/2;
|
||||
window_center_y = (window_rect.top + window_rect.bottom)/2;
|
||||
SetCursorPos( window_center_x, window_center_y );
|
||||
|
||||
SetCapture( host.hWnd );
|
||||
ClipCursor(&window_rect);
|
||||
while( ShowCursor(false) >= 0 );
|
||||
}
|
||||
|
||||
/*
|
||||
===========
|
||||
IN_DeactivateMouse
|
||||
|
||||
Called when the window loses focus
|
||||
===========
|
||||
*/
|
||||
void IN_DeactivateMouse( void )
|
||||
{
|
||||
if( !in_mouseinitialized || !in_mouseactive )
|
||||
return;
|
||||
|
||||
if( in_restore_spi )
|
||||
SystemParametersInfo( SPI_SETMOUSE, 0, in_originalmouseparms, 0 );
|
||||
|
||||
in_mouseactive = false;
|
||||
ClipCursor( NULL );
|
||||
ReleaseCapture();
|
||||
while( ShowCursor(true) < 0 );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
IN_Mouse
|
||||
================
|
||||
*/
|
||||
void IN_MouseMove( void )
|
||||
{
|
||||
POINT current_pos;
|
||||
int mx, my;
|
||||
|
||||
if( !in_mouseinitialized )
|
||||
return;
|
||||
|
||||
// find mouse movement
|
||||
GetCursorPos( ¤t_pos );
|
||||
|
||||
// force the mouse to the center, so there's room to move
|
||||
SetCursorPos( window_center_x, window_center_y );
|
||||
mx = current_pos.x - window_center_x;
|
||||
my = current_pos.y - window_center_y;
|
||||
|
||||
if( !mx && !my ) return;
|
||||
Sys_QueEvent( 0, SE_MOUSE, mx, my, 0, NULL );
|
||||
}
|
||||
|
||||
/*
|
||||
===========
|
||||
IN_MouseEvent
|
||||
===========
|
||||
*/
|
||||
void IN_MouseEvent( int mstate )
|
||||
{
|
||||
int i;
|
||||
|
||||
if( !in_mouseinitialized )
|
||||
return;
|
||||
|
||||
// perform button actions
|
||||
for( i = 0; i < in_mouse_buttons; i++ )
|
||||
{
|
||||
if((mstate & (1<<i)) && !(in_mouse_oldbuttonstate & (1<<i)) )
|
||||
{
|
||||
Sys_QueEvent( -1, SE_KEY, K_MOUSE1 + i, true, 0, NULL );
|
||||
}
|
||||
if ( !(mstate & (1<<i)) && (in_mouse_oldbuttonstate & (1<<i)) )
|
||||
{
|
||||
Sys_QueEvent( -1, SE_KEY, K_MOUSE1 + i, false, 0, NULL );
|
||||
}
|
||||
}
|
||||
in_mouse_oldbuttonstate = mstate;
|
||||
}
|
||||
|
||||
/*
|
||||
===========
|
||||
IN_Shutdown
|
||||
===========
|
||||
*/
|
||||
void IN_Shutdown( void )
|
||||
{
|
||||
IN_DeactivateMouse();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===========
|
||||
IN_Init
|
||||
===========
|
||||
*/
|
||||
void IN_Init( void )
|
||||
{
|
||||
IN_StartupMouse();
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
IN_Frame
|
||||
|
||||
Called every frame, even if not generating commands
|
||||
==================
|
||||
*/
|
||||
void IN_Frame( void )
|
||||
{
|
||||
if( !in_mouseinitialized )
|
||||
return;
|
||||
if( host.state != HOST_FRAME )
|
||||
{
|
||||
IN_DeactivateMouse();
|
||||
return;
|
||||
}
|
||||
|
||||
// uimenu.dat using mouse
|
||||
if((!cl.refresh_prepped && cls.key_dest != key_menu) || cls.key_dest == key_console )
|
||||
{
|
||||
if(!Cvar_VariableValue( "fullscreen"))
|
||||
{
|
||||
IN_DeactivateMouse();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
IN_ActivateMouse();
|
||||
IN_MouseMove();
|
||||
|
||||
}
|
|
@ -23,7 +23,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
|
||||
/*
|
||||
|
||||
packet header
|
||||
packet header (quake2)
|
||||
-------------
|
||||
31 sequence
|
||||
1 does this message contain a reliable payload
|
||||
|
@ -31,35 +31,17 @@ packet header
|
|||
1 acknowledge receipt of even/odd message
|
||||
16 qport
|
||||
|
||||
The remote connection never knows if it missed a reliable message, the
|
||||
local side detects that it has been dropped by seeing a sequence acknowledge
|
||||
higher thatn the last reliable sequence, but without the correct evon/odd
|
||||
bit for the reliable set.
|
||||
packet header (quake3)
|
||||
-------------
|
||||
4 outgoing sequence. high bit will be set if this is a fragmented message
|
||||
[2 qport (only for client to server)]
|
||||
[2 fragment start byte]
|
||||
[2 fragment length. if < FRAGMENT_SIZE, this is the last fragment]
|
||||
|
||||
If the sender notices that a reliable message has been dropped, it will be
|
||||
retransmitted. It will not be retransmitted again until a message after
|
||||
the retransmit has been acknowledged and the reliable still failed to get there.
|
||||
|
||||
if the sequence number is -1, the packet should be handled without a netcon
|
||||
|
||||
The reliable message can be added to at any time by doing
|
||||
MSG_Write* (&netchan->message, <data>).
|
||||
|
||||
If the message buffer is overflowed, either by a single message, or by
|
||||
multiple frames worth piling up while the last reliable transmit goes
|
||||
unacknowledged, the netchan signals a fatal error.
|
||||
|
||||
Reliable messages are always placed first in a packet, then the unreliable
|
||||
message is included if there is sufficient room.
|
||||
|
||||
To the receiver, there is no distinction between the reliable and unreliable
|
||||
parts of the message, they are just processed out as a single larger message.
|
||||
|
||||
Illogical packet sequence numbers cause the packet to be dropped, but do
|
||||
not kill the connection. This, combined with the tight window of valid
|
||||
reliable acknowledgement numbers provides protection against malicious
|
||||
address spoofing.
|
||||
if the sequence number is -1, the packet should be handled as an out-of-band
|
||||
message instead of as part of a netcon.
|
||||
|
||||
All fragments will have the same sequence numbers.
|
||||
|
||||
The qport field is a workaround for bad address translating routers that
|
||||
sometimes remap the client's source port on a packet during gameplay.
|
||||
|
@ -67,21 +49,40 @@ sometimes remap the client's source port on a packet during gameplay.
|
|||
If the base part of the net address matches and the qport matches, then the
|
||||
channel matches even if the IP port differs. The IP port should be updated
|
||||
to the new value before sending out any replies.
|
||||
|
||||
|
||||
If there is no information that needs to be transfered on a given frame,
|
||||
such as during the connection stage while waiting for the client to load,
|
||||
then a packet only needs to be delivered if there is something in the
|
||||
unacknowledged reliable
|
||||
*/
|
||||
|
||||
cvar_t *showpackets;
|
||||
cvar_t *showdrop;
|
||||
cvar_t *qport;
|
||||
#define MAX_PACKETLEN 1400 // max size of a network packet
|
||||
#define FRAGMENT_SIZE (MAX_PACKETLEN - 100)
|
||||
#define PACKET_HEADER 10 // two ints and a short
|
||||
#define MAX_LOOPBACK 16
|
||||
#define FRAGMENT_BIT (1<<31)
|
||||
|
||||
netadr_t net_from;
|
||||
sizebuf_t net_message;
|
||||
byte net_message_buffer[MAX_MSGLEN];
|
||||
cvar_t *showpackets;
|
||||
cvar_t *showdrop;
|
||||
cvar_t *qport;
|
||||
|
||||
static char *netsrcString[2] =
|
||||
{
|
||||
"client",
|
||||
"server"
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
byte data[MAX_PACKETLEN];
|
||||
int datalen;
|
||||
} loopmsg_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
loopmsg_t msgs[MAX_LOOPBACK];
|
||||
int get, send;
|
||||
} loopback_t;
|
||||
|
||||
loopback_t loopbacks[2];
|
||||
netadr_t net_from;
|
||||
sizebuf_t net_message;
|
||||
byte net_message_buffer[MAX_MSGLEN];
|
||||
|
||||
/*
|
||||
===============
|
||||
|
@ -89,38 +90,266 @@ Netchan_Init
|
|||
|
||||
===============
|
||||
*/
|
||||
void Netchan_Init (void)
|
||||
void Netchan_Init( void )
|
||||
{
|
||||
int port;
|
||||
|
||||
// pick a port value that should be nice and random
|
||||
port = RANDOM_LONG(1, 65535);
|
||||
int port = RANDOM_LONG( 1, 65535 );
|
||||
|
||||
showpackets = Cvar_Get ("showpackets", "0", 0, "show network packets" );
|
||||
showdrop = Cvar_Get ("showdrop", "0", 0, "show packets that are dropped" );
|
||||
qport = Cvar_Get( "qport", va("%i", port), CVAR_INIT, "current netport" );
|
||||
showpackets = Cvar_Get ("net_showpackets", "0", CVAR_TEMP, "show network packets" );
|
||||
showdrop = Cvar_Get ("net_showdrop", "0", CVAR_TEMP, "show packets that are dropped" );
|
||||
qport = Cvar_Get ("net_qport", va("%i", port), CVAR_INIT, "current quake netport" );
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
Netchan_Setup
|
||||
|
||||
called to open a channel to a remote system
|
||||
==============
|
||||
*/
|
||||
void Netchan_Setup( netsrc_t sock, netchan_t *chan, netadr_t adr, int qport )
|
||||
{
|
||||
memset( chan, 0, sizeof(*chan));
|
||||
|
||||
chan->sock = sock;
|
||||
chan->remote_address = adr;
|
||||
chan->qport = qport;
|
||||
chan->incoming_sequence = 0;
|
||||
chan->outgoing_sequence = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
Netchan_TransmitNextFragment
|
||||
|
||||
Send one fragment of the current message
|
||||
=================
|
||||
*/
|
||||
void Netchan_TransmitNextFragment( netchan_t *chan )
|
||||
{
|
||||
sizebuf_t send;
|
||||
byte send_buf[MAX_PACKETLEN];
|
||||
int fragment_length;
|
||||
|
||||
// write the packet header
|
||||
SZ_Init( &send, send_buf, sizeof(send_buf));
|
||||
MSG_WriteLong( &send, chan->outgoing_sequence | FRAGMENT_BIT );
|
||||
|
||||
// send the qport if we are a client
|
||||
if( chan->sock == NS_CLIENT )
|
||||
{
|
||||
MSG_WriteShort( &send, qport->integer );
|
||||
}
|
||||
|
||||
// copy the reliable message to the packet first
|
||||
fragment_length = FRAGMENT_SIZE;
|
||||
if( chan->unsent_fragment_start + fragment_length > chan->unsent_length )
|
||||
{
|
||||
fragment_length = chan->unsent_length - chan->unsent_fragment_start;
|
||||
}
|
||||
|
||||
MSG_WriteShort( &send, chan->unsent_fragment_start );
|
||||
MSG_WriteShort( &send, fragment_length );
|
||||
MSG_WriteData( &send, chan->unsent_buffer + chan->unsent_fragment_start, fragment_length );
|
||||
|
||||
// send the datagram
|
||||
NET_SendPacket( chan->sock, send.cursize, send.data, chan->remote_address );
|
||||
|
||||
if( showpackets->integer )
|
||||
MsgDev( D_INFO, "%s send %4i : s=%i fragment=%i,%i\n", netsrcString[chan->sock], send.cursize, chan->outgoing_sequence, chan->unsent_fragment_start, fragment_length );
|
||||
|
||||
chan->unsent_fragment_start += fragment_length;
|
||||
if ( chan->unsent_fragment_start == chan->unsent_length && fragment_length != FRAGMENT_SIZE )
|
||||
{
|
||||
chan->outgoing_sequence++;
|
||||
chan->unsent_fragments = false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
Netchan_Transmit
|
||||
|
||||
Sends a message to a connection, fragmenting if necessary
|
||||
A 0 length will still generate a packet.
|
||||
================
|
||||
*/
|
||||
void Netchan_Transmit( netchan_t *chan, int length, const byte *data )
|
||||
{
|
||||
sizebuf_t send;
|
||||
byte send_buf[MAX_PACKETLEN];
|
||||
|
||||
if( length > MAX_MSGLEN ) Host_Error( "Netchan_Transmit: %i > MAX_MSGLEN\n", length );
|
||||
chan->unsent_fragment_start = 0;
|
||||
|
||||
// fragment large reliable messages
|
||||
if( length >= FRAGMENT_SIZE )
|
||||
{
|
||||
chan->unsent_fragments = true;
|
||||
chan->unsent_length = length;
|
||||
Mem_Copy( chan->unsent_buffer, data, length );
|
||||
// only send the first fragment now
|
||||
Netchan_TransmitNextFragment( chan );
|
||||
return;
|
||||
}
|
||||
|
||||
// write the packet header
|
||||
SZ_Init( &send, send_buf, sizeof(send_buf));
|
||||
MSG_WriteLong( &send, chan->outgoing_sequence );
|
||||
chan->outgoing_sequence++;
|
||||
|
||||
// send the qport if we are a client
|
||||
if( chan->sock == NS_CLIENT )
|
||||
MSG_WriteShort( &send, qport->integer );
|
||||
|
||||
MSG_WriteData( &send, data, length );
|
||||
NET_SendPacket( chan->sock, send.cursize, send.data, chan->remote_address ); // send the datagram
|
||||
|
||||
if( showpackets->integer )
|
||||
MsgDev( D_INFO, "%s send %4i : s=%i ack=%i\n", netsrcString[chan->sock], send.cursize, chan->outgoing_sequence - 1, chan->incoming_sequence );
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
Netchan_Process
|
||||
|
||||
Returns qfalse if the message should not be processed due to being
|
||||
out of order or a fragment.
|
||||
|
||||
Msg must be large enough to hold MAX_MSGLEN, because if this is the
|
||||
final fragment of a multi-part message, the entire thing will be
|
||||
copied out.
|
||||
=================
|
||||
*/
|
||||
bool Netchan_Process( netchan_t *chan, sizebuf_t *msg )
|
||||
{
|
||||
int sequence;
|
||||
int qport;
|
||||
int fragment_start = 0, fragment_length = 0;
|
||||
bool fragmented = false;
|
||||
|
||||
// get sequence numbers
|
||||
MSG_BeginReading( msg );
|
||||
sequence = MSG_ReadLong( msg );
|
||||
|
||||
// check for fragment information
|
||||
if( sequence & FRAGMENT_BIT )
|
||||
{
|
||||
sequence &= ~FRAGMENT_BIT;
|
||||
fragmented = true;
|
||||
}
|
||||
|
||||
// read the qport if we are a server
|
||||
if( chan->sock == NS_SERVER )
|
||||
qport = MSG_ReadShort( msg );
|
||||
|
||||
// read the fragment information
|
||||
if( fragmented )
|
||||
{
|
||||
fragment_start = MSG_ReadShort( msg );
|
||||
fragment_length = MSG_ReadShort( msg );
|
||||
}
|
||||
|
||||
if( showpackets->integer )
|
||||
{
|
||||
if( fragmented )
|
||||
MsgDev( D_INFO, "%s recv %4i : s=%i fragment=%i,%i\n", netsrcString[chan->sock], msg->cursize, sequence, fragment_start, fragment_length );
|
||||
else MsgDev( D_INFO, "%s recv %4i : s=%i\n", netsrcString[chan->sock], msg->cursize, sequence );
|
||||
}
|
||||
|
||||
// discard out of order or duplicated packets
|
||||
if( sequence <= chan->incoming_sequence )
|
||||
{
|
||||
if( showdrop->integer || showpackets->integer )
|
||||
MsgDev( D_INFO, "%s:Out of order packet %i at %i\n", NET_AdrToString(chan->remote_address), sequence, chan->incoming_sequence );
|
||||
return false;
|
||||
}
|
||||
|
||||
// dropped packets don't keep the message from being used
|
||||
chan->dropped = sequence - (chan->incoming_sequence + 1);
|
||||
if( chan->dropped > 0 )
|
||||
{
|
||||
if( showdrop->integer || showpackets->integer )
|
||||
MsgDev( D_INFO, "%s:Dropped %i packets at %i\n", NET_AdrToString( chan->remote_address ), chan->dropped, sequence );
|
||||
}
|
||||
|
||||
|
||||
// if this is the final framgent of a reliable message, bump incoming_reliable_sequence
|
||||
if( fragmented )
|
||||
{
|
||||
if( sequence != chan->fragment_sequence )
|
||||
{
|
||||
chan->fragment_sequence = sequence;
|
||||
chan->fragment_length = 0;
|
||||
}
|
||||
// if we missed a fragment, dump the message
|
||||
if( fragment_start != chan->fragment_length )
|
||||
{
|
||||
if( showdrop->integer || showpackets->integer )
|
||||
MsgDev( D_INFO, "%s:Dropped a message fragment\n", NET_AdrToString( chan->remote_address ), sequence);
|
||||
return false;
|
||||
}
|
||||
|
||||
// copy the fragment to the fragment buffer
|
||||
if( fragment_length < 0 || msg->readcount + fragment_length > msg->cursize || chan->fragment_length + fragment_length > sizeof( chan->fragment_buffer ))
|
||||
{
|
||||
if( showdrop->integer || showpackets->integer )
|
||||
MsgDev( D_INFO, "%s:illegal fragment length\n", NET_AdrToString (chan->remote_address ));
|
||||
return false;
|
||||
}
|
||||
|
||||
Mem_Copy( chan->fragment_buffer + chan->fragment_length, msg->data + msg->readcount, fragment_length );
|
||||
chan->fragment_length += fragment_length;
|
||||
|
||||
// if this wasn't the last fragment, don't process anything
|
||||
if( fragment_length == FRAGMENT_SIZE )
|
||||
return false;
|
||||
|
||||
if( chan->fragment_length > msg->maxsize )
|
||||
{
|
||||
MsgDev( D_INFO, "%s:fragmentLength %i > msg->maxsize\n", NET_AdrToString (chan->remote_address ), chan->fragment_length );
|
||||
return false;
|
||||
}
|
||||
|
||||
// copy the full message over the partial fragment
|
||||
// make sure the sequence number is still there
|
||||
*(int *)msg->data = LittleLong( sequence );
|
||||
|
||||
Mem_Copy( msg->data + 4, chan->fragment_buffer, chan->fragment_length );
|
||||
msg->cursize = chan->fragment_length + 4;
|
||||
chan->fragment_length = 0;
|
||||
msg->readcount = 4; // past the sequence number
|
||||
msg->bit = 32; // past the sequence number
|
||||
|
||||
// clients were not acking fragmented messages
|
||||
chan->incoming_sequence = sequence;
|
||||
return true;
|
||||
}
|
||||
// the message can now be read from the current message pointer
|
||||
chan->incoming_sequence = sequence;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
Netchan_OutOfBand
|
||||
|
||||
Sends an out-of-band datagram
|
||||
Sends a data message in an out-of-band datagram (only used for "connect")
|
||||
================
|
||||
*/
|
||||
void Netchan_OutOfBand (int net_socket, netadr_t adr, int length, byte *data)
|
||||
void Netchan_OutOfBand( netsrc_t sock, netadr_t adr, int length, byte *data )
|
||||
{
|
||||
sizebuf_t send;
|
||||
byte send_buf[MAX_MSGLEN];
|
||||
byte send_buf[MAX_MSGLEN];
|
||||
|
||||
// write the packet header
|
||||
SZ_Init (&send, send_buf, sizeof(send_buf));
|
||||
|
||||
MSG_WriteLong (&send, -1); // -1 sequence means out of band
|
||||
SZ_Write(&send, data, length);
|
||||
SZ_Init( &send, send_buf, sizeof(send_buf));
|
||||
MSG_WriteLong( &send, 0xffffffff ); // -1 sequence means out of band
|
||||
SZ_Write( &send, data, length );
|
||||
|
||||
// send the datagram
|
||||
NET_SendPacket (net_socket, send.cursize, send.data, adr);
|
||||
NET_SendPacket( sock, send.cursize, send.data, adr );
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -130,246 +359,184 @@ Netchan_OutOfBandPrint
|
|||
Sends a text message in an out-of-band datagram
|
||||
================
|
||||
*/
|
||||
void Netchan_OutOfBandPrint (int net_socket, netadr_t adr, char *format, ...)
|
||||
void Netchan_OutOfBandPrint( netsrc_t sock, netadr_t adr, const char *format, ... )
|
||||
{
|
||||
va_list argptr;
|
||||
static char string[MAX_MSGLEN - 4];
|
||||
static char string[MAX_MSGLEN - 4];
|
||||
|
||||
va_start (argptr, format);
|
||||
com.vsprintf (string, format,argptr);
|
||||
va_end (argptr);
|
||||
va_start( argptr, format );
|
||||
com.vsprintf( string, format, argptr );
|
||||
va_end( argptr );
|
||||
|
||||
Netchan_OutOfBand (net_socket, adr, strlen(string), (byte *)string);
|
||||
Netchan_OutOfBand( sock, adr, com.strlen(string), (byte *)string );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==============
|
||||
Netchan_Setup
|
||||
=============================================================================
|
||||
|
||||
called to open a channel to a remote system
|
||||
==============
|
||||
NET MISC HELPER FUNCTIONS
|
||||
|
||||
=============================================================================
|
||||
*/
|
||||
void Netchan_Setup (netsrc_t sock, netchan_t *chan, netadr_t adr, int qport)
|
||||
{
|
||||
memset (chan, 0, sizeof(*chan));
|
||||
|
||||
chan->sock = sock;
|
||||
chan->remote_address = adr;
|
||||
chan->qport = qport;
|
||||
chan->last_received = Sys_Milliseconds();
|
||||
chan->incoming_sequence = 0;
|
||||
chan->outgoing_sequence = 1;
|
||||
|
||||
SZ_Init (&chan->message, chan->message_buf, sizeof(chan->message_buf));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
Netchan_CanReliable
|
||||
===================
|
||||
NET_CompareBaseAdr
|
||||
|
||||
Returns true if the last reliable message has acked
|
||||
================
|
||||
Compares without the port
|
||||
===================
|
||||
*/
|
||||
bool Netchan_CanReliable (netchan_t *chan)
|
||||
bool NET_CompareBaseAdr( netadr_t a, netadr_t b )
|
||||
{
|
||||
if (chan->reliable_length)
|
||||
return false; // waiting for ack
|
||||
return true;
|
||||
}
|
||||
if( a.type != b.type )
|
||||
return false;
|
||||
if( a.type == NA_LOOPBACK )
|
||||
return true;
|
||||
|
||||
|
||||
bool Netchan_NeedReliable (netchan_t *chan)
|
||||
{
|
||||
bool send_reliable;
|
||||
|
||||
// if the remote side dropped the last reliable message, resend it
|
||||
send_reliable = false;
|
||||
|
||||
if (chan->incoming_acknowledged > chan->last_reliable_sequence
|
||||
&& chan->incoming_reliable_acknowledged != chan->reliable_sequence)
|
||||
send_reliable = true;
|
||||
|
||||
// if the reliable transmit buffer is empty, copy the current message out
|
||||
if (!chan->reliable_length && chan->message.cursize)
|
||||
if( a.type == NA_IP )
|
||||
{
|
||||
send_reliable = true;
|
||||
if(!memcmp(a.ip, b.ip, 4 ))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
MsgDev( D_ERROR, "NET_CompareBaseAdr: bad address type\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
return send_reliable;
|
||||
bool NET_CompareAdr( netadr_t a, netadr_t b )
|
||||
{
|
||||
if( a.type != b.type )
|
||||
return false;
|
||||
if( a.type == NA_LOOPBACK )
|
||||
return true;
|
||||
|
||||
if( a.type == NA_IP )
|
||||
{
|
||||
if((memcmp(a.ip, b.ip, 4 ) == 0) && a.port == b.port)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
MsgDev( D_ERROR, "NET_CompareAdr: bad address type\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NET_IsLocalAddress( netadr_t adr )
|
||||
{
|
||||
return adr.type == NA_LOOPBACK;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
Netchan_Transmit
|
||||
=============================================================================
|
||||
|
||||
tries to send an unreliable message to a connection, and handles the
|
||||
transmition / retransmition of the reliable messages.
|
||||
LOOPBACK BUFFERS FOR LOCAL PLAYER
|
||||
|
||||
A 0 length will still generate a packet and deal with the reliable messages.
|
||||
================
|
||||
=============================================================================
|
||||
*/
|
||||
void Netchan_Transmit (netchan_t *chan, int length, byte *data)
|
||||
bool NET_GetLoopPacket( netsrc_t sock, netadr_t *net_from, sizebuf_t *net_message )
|
||||
{
|
||||
sizebuf_t send;
|
||||
byte send_buf[MAX_MSGLEN];
|
||||
bool send_reliable;
|
||||
uint w1, w2;
|
||||
int i;
|
||||
loopback_t *loop;
|
||||
|
||||
// check for message overflow
|
||||
if (chan->message.overflowed)
|
||||
loop = &loopbacks[sock];
|
||||
|
||||
if( loop->send - loop->get > MAX_LOOPBACK )
|
||||
loop->get = loop->send - MAX_LOOPBACK;
|
||||
|
||||
if( loop->get >= loop->send )
|
||||
return false;
|
||||
|
||||
i = loop->get & (MAX_LOOPBACK-1);
|
||||
loop->get++;
|
||||
|
||||
Mem_Copy( net_message->data, loop->msgs[i].data, loop->msgs[i].datalen );
|
||||
net_message->cursize = loop->msgs[i].datalen;
|
||||
memset( net_from, 0, sizeof(*net_from));
|
||||
net_from->type = NA_LOOPBACK;
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
void NET_SendLoopPacket( netsrc_t sock, int length, const void *data, netadr_t to )
|
||||
{
|
||||
int i;
|
||||
loopback_t *loop;
|
||||
|
||||
loop = &loopbacks[sock^1];
|
||||
|
||||
i = loop->send & (MAX_LOOPBACK-1);
|
||||
loop->send++;
|
||||
|
||||
Mem_Copy( loop->msgs[i].data, data, length );
|
||||
loop->msgs[i].datalen = length;
|
||||
}
|
||||
|
||||
/*
|
||||
=============================================================================
|
||||
|
||||
NETCHAN TRANSMIT UTILS
|
||||
|
||||
=============================================================================
|
||||
*/
|
||||
void NET_SendPacket( netsrc_t sock, int length, const void *data, netadr_t to )
|
||||
{
|
||||
// sequenced packets are shown in netchan, so just show oob
|
||||
if( showpackets->integer && *(int *)data == -1 )
|
||||
MsgDev( D_INFO, "send packet %4i\n", length);
|
||||
|
||||
if( to.type == NA_LOOPBACK )
|
||||
{
|
||||
chan->fatal_error = true;
|
||||
Msg ("%s:Outgoing message overflow\n", NET_AdrToString (chan->remote_address));
|
||||
NET_SendLoopPacket( sock, length, data, to );
|
||||
return;
|
||||
}
|
||||
|
||||
send_reliable = Netchan_NeedReliable (chan);
|
||||
|
||||
if (!chan->reliable_length && chan->message.cursize)
|
||||
{
|
||||
memcpy (chan->reliable_buf, chan->message_buf, chan->message.cursize);
|
||||
chan->reliable_length = chan->message.cursize;
|
||||
chan->message.cursize = 0;
|
||||
chan->reliable_sequence ^= 1;
|
||||
}
|
||||
|
||||
|
||||
// write the packet header
|
||||
SZ_Init (&send, send_buf, sizeof(send_buf));
|
||||
|
||||
w1 = ( chan->outgoing_sequence & ~(1<<31) ) | (send_reliable<<31);
|
||||
w2 = ( chan->incoming_sequence & ~(1<<31) ) | (chan->incoming_reliable_sequence<<31);
|
||||
|
||||
chan->outgoing_sequence++;
|
||||
chan->last_sent = Sys_Milliseconds();
|
||||
|
||||
MSG_WriteLong (&send, w1);
|
||||
MSG_WriteLong (&send, w2);
|
||||
|
||||
// send the qport if we are a client
|
||||
if (chan->sock == NS_CLIENT) MSG_WriteWord (&send, qport->value);
|
||||
|
||||
// copy the reliable message to the packet first
|
||||
if (send_reliable)
|
||||
{
|
||||
SZ_Write (&send, chan->reliable_buf, chan->reliable_length);
|
||||
chan->last_reliable_sequence = chan->outgoing_sequence;
|
||||
}
|
||||
|
||||
// add the unreliable part if space is available
|
||||
if (send.maxsize - send.cursize >= length)
|
||||
SZ_Write (&send, data, length);
|
||||
else MsgDev( D_WARN, "Netchan_Transmit: dumped unreliable\n");
|
||||
|
||||
// send the datagram
|
||||
NET_SendPacket (chan->sock, send.cursize, send.data, chan->remote_address);
|
||||
|
||||
if (showpackets->value)
|
||||
{
|
||||
if (send_reliable)
|
||||
Msg ("send %4i : s=%i reliable=%i ack=%i rack=%i\n"
|
||||
, send.cursize
|
||||
, chan->outgoing_sequence - 1
|
||||
, chan->reliable_sequence
|
||||
, chan->incoming_sequence
|
||||
, chan->incoming_reliable_sequence);
|
||||
else
|
||||
Msg ("send %4i : s=%i ack=%i rack=%i\n"
|
||||
, send.cursize
|
||||
, chan->outgoing_sequence - 1
|
||||
, chan->incoming_sequence
|
||||
, chan->incoming_reliable_sequence);
|
||||
}
|
||||
if( to.type == NA_NONE ) return;
|
||||
Sys_SendPacket( length, data, to );
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
Netchan_Process
|
||||
=============
|
||||
NET_StringToAdr
|
||||
|
||||
called when the current net_message is from remote_address
|
||||
modifies net_message so that it points to the packet payload
|
||||
=================
|
||||
Traps "localhost" for loopback, passes everything else to system
|
||||
=============
|
||||
*/
|
||||
bool Netchan_Process (netchan_t *chan, sizebuf_t *msg)
|
||||
bool NET_StringToAdr( const char *s, netadr_t *a )
|
||||
{
|
||||
uint sequence, sequence_ack;
|
||||
uint reliable_ack, reliable_message;
|
||||
int qport;
|
||||
bool r;
|
||||
char *port, base[MAX_STRING_CHARS];
|
||||
|
||||
// get sequence numbers
|
||||
MSG_BeginReading (msg);
|
||||
sequence = MSG_ReadLong (msg);
|
||||
sequence_ack = MSG_ReadLong (msg);
|
||||
|
||||
// read the qport if we are a server
|
||||
if (chan->sock == NS_SERVER)
|
||||
qport = MSG_ReadShort (msg);
|
||||
|
||||
reliable_message = sequence >> 31;
|
||||
reliable_ack = sequence_ack >> 31;
|
||||
|
||||
sequence &= ~(1<<31);
|
||||
sequence_ack &= ~(1<<31);
|
||||
|
||||
if (showpackets->value)
|
||||
if(!com.strcmp( s, "localhost" ))
|
||||
{
|
||||
if (reliable_message)
|
||||
Msg ("recv %4i : s=%i reliable=%i ack=%i rack=%i\n"
|
||||
, msg->cursize
|
||||
, sequence
|
||||
, chan->incoming_reliable_sequence ^ 1
|
||||
, sequence_ack
|
||||
, reliable_ack);
|
||||
else
|
||||
Msg ("recv %4i : s=%i ack=%i rack=%i\n"
|
||||
, msg->cursize
|
||||
, sequence
|
||||
, sequence_ack
|
||||
, reliable_ack);
|
||||
memset( a, 0, sizeof(*a));
|
||||
a->type = NA_LOOPBACK;
|
||||
return true;
|
||||
}
|
||||
|
||||
// discard stale or duplicated packets
|
||||
if (sequence <= chan->incoming_sequence)
|
||||
// look for a port number
|
||||
com.strncpy( base, s, sizeof( base ));
|
||||
port = com.strstr( base, ":" );
|
||||
if( port )
|
||||
{
|
||||
if (showdrop->value)
|
||||
Msg ("%s:Out of order packet %i at %i\n"
|
||||
, NET_AdrToString (chan->remote_address)
|
||||
, sequence
|
||||
, chan->incoming_sequence);
|
||||
*port = 0;
|
||||
port++;
|
||||
}
|
||||
|
||||
r = Sys_StringToAdr( base, a );
|
||||
|
||||
if( !r )
|
||||
{
|
||||
a->type = NA_NONE;
|
||||
return false;
|
||||
}
|
||||
|
||||
// dropped packets don't keep the message from being used
|
||||
chan->dropped = sequence - (chan->incoming_sequence+1);
|
||||
if (chan->dropped > 0)
|
||||
// inet_addr returns this if out of range
|
||||
if( a->ip[0] == 255 && a->ip[1] == 255 && a->ip[2] == 255 && a->ip[3] == 255 )
|
||||
{
|
||||
if (showdrop->value)
|
||||
Msg ("%s:Dropped %i packets at %i\n"
|
||||
, NET_AdrToString (chan->remote_address)
|
||||
, chan->dropped
|
||||
, sequence);
|
||||
a->type = NA_NONE;
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
// if the current outgoing reliable message has been acknowledged
|
||||
// clear the buffer to make way for the next
|
||||
//
|
||||
if (reliable_ack == chan->reliable_sequence)
|
||||
chan->reliable_length = 0; // it has been received
|
||||
|
||||
// if this message contains a reliable message, bump incoming_reliable_sequence
|
||||
chan->incoming_sequence = sequence;
|
||||
chan->incoming_acknowledged = sequence_ack;
|
||||
chan->incoming_reliable_acknowledged = reliable_ack;
|
||||
if (reliable_message)
|
||||
{
|
||||
chan->incoming_reliable_sequence ^= 1;
|
||||
}
|
||||
if( port ) a->port = BigShort((short)com.atoi( port ));
|
||||
else a->port = BigShort( PORT_SERVER );
|
||||
|
||||
// the message can now be read from the current message pointer
|
||||
chan->last_received = Sys_Milliseconds();
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -41,6 +41,16 @@ void _MSG_WriteByte (sizebuf_t *sb, int c, const char *filename, int fileline)
|
|||
buf[0] = c;
|
||||
}
|
||||
|
||||
void _MSG_WriteData( sizebuf_t *sb, const void *data, size_t length, const char *filename, int fileline )
|
||||
{
|
||||
int i;
|
||||
|
||||
for( i = 0; i < length; i++ )
|
||||
{
|
||||
_MSG_WriteByte( sb, ((byte *)data)[i], filename, fileline );
|
||||
}
|
||||
}
|
||||
|
||||
void _MSG_WriteShort (sizebuf_t *sb, int c, const char *filename, int fileline)
|
||||
{
|
||||
byte *buf;
|
||||
|
@ -554,7 +564,7 @@ void MSG_ReadData (sizebuf_t *msg_read, void *data, int len)
|
|||
=======================
|
||||
*/
|
||||
|
||||
void SZ_Init (sizebuf_t *buf, byte *data, int length)
|
||||
void SZ_Init( sizebuf_t *buf, byte *data, size_t length )
|
||||
{
|
||||
memset (buf, 0, sizeof(*buf));
|
||||
buf->data = data;
|
||||
|
|
|
@ -5,6 +5,9 @@
|
|||
#ifndef NET_MSG_H
|
||||
#define NET_MSG_H
|
||||
|
||||
#define PACKET_BACKUP 32
|
||||
#define PACKET_MASK ( PACKET_BACKUP - 1 )
|
||||
|
||||
// server to client
|
||||
enum svc_ops_e
|
||||
{
|
||||
|
@ -29,6 +32,7 @@ enum svc_ops_e
|
|||
svc_packetentities, // [...]
|
||||
svc_deltapacketentities, // [...]
|
||||
svc_frame, // server frame
|
||||
svc_eof, // end of messages
|
||||
};
|
||||
|
||||
// client to server
|
||||
|
@ -38,7 +42,8 @@ enum clc_ops_e
|
|||
clc_nop,
|
||||
clc_move, // [[usercmd_t]
|
||||
clc_userinfo, // [[userinfo string]
|
||||
clc_stringcmd // [string] message
|
||||
clc_stringcmd, // [string] message
|
||||
clc_eof, // end of messages
|
||||
};
|
||||
|
||||
typedef enum
|
||||
|
@ -53,6 +58,13 @@ typedef enum
|
|||
MSG_PVS_R,
|
||||
} msgtype_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int cmdnumber; // cl.cmdnumber when packet was sent
|
||||
int servertime; // usercmd->servertime when packet was sent
|
||||
int realtime; // cls.realtime when packet was sent
|
||||
} outpacket_t;
|
||||
|
||||
#define PS_M_TYPE (1<<0)
|
||||
#define PS_M_ORIGIN (1<<1)
|
||||
#define PS_M_VELOCITY (1<<2)
|
||||
|
@ -229,8 +241,8 @@ typedef struct entity_state_s
|
|||
*/
|
||||
#define SZ_GetSpace(buf, len) _SZ_GetSpace(buf, len, __FILE__, __LINE__ )
|
||||
#define SZ_Write(buf, data, len) _SZ_Write(buf, data, len, __FILE__, __LINE__ )
|
||||
void SZ_Init (sizebuf_t *buf, byte *data, int length);
|
||||
void SZ_Clear (sizebuf_t *buf);
|
||||
void SZ_Init( sizebuf_t *buf, byte *data, size_t length );
|
||||
void SZ_Clear( sizebuf_t *buf );
|
||||
void *_SZ_GetSpace (sizebuf_t *buf, int length, const char *filename, int fileline);
|
||||
void _SZ_Write (sizebuf_t *buf, const void *data, int length, const char *filename, int fileline);
|
||||
void SZ_Print (sizebuf_t *buf, char *data); // strcats onto the sizebuf
|
||||
|
@ -250,6 +262,7 @@ void _MSG_WriteAngle32(sizebuf_t *sb, float f, const char *filename, int filelin
|
|||
void _MSG_WritePos16(sizebuf_t *sb, vec3_t pos, const char *filename, int fileline);
|
||||
void _MSG_WritePos32(sizebuf_t *sb, vec3_t pos, const char *filename, int fileline);
|
||||
void _MSG_WriteUnterminatedString (sizebuf_t *sb, const char *s, const char *filename, int fileline);
|
||||
void _MSG_WriteData (sizebuf_t *sb, const void *data, size_t length, const char *filename, int fileline);
|
||||
void _MSG_WriteDeltaUsercmd (sizebuf_t *sb, struct usercmd_s *from, struct usercmd_s *cmd, const char *filename, int fileline);
|
||||
void _MSG_WriteDeltaEntity (struct entity_state_s *from, struct entity_state_s *to, sizebuf_t *msg, bool force, bool newentity, const char *filename, int fileline);
|
||||
void _MSG_Send (msgtype_t to, vec3_t origin, edict_t *ent, const char *filename, int fileline);
|
||||
|
@ -257,6 +270,7 @@ void _MSG_Send (msgtype_t to, vec3_t origin, edict_t *ent, const char *filename,
|
|||
#define MSG_Begin( x ) _MSG_Begin( x, __FILE__, __LINE__);
|
||||
#define MSG_WriteChar(x,y) _MSG_WriteChar (x, y, __FILE__, __LINE__);
|
||||
#define MSG_WriteByte(x,y) _MSG_WriteByte (x, y, __FILE__, __LINE__);
|
||||
#define MSG_WriteData(x,y,z) _MSG_WriteData (x, y, z,__FILE__, __LINE__);
|
||||
#define MSG_WriteShort(x,y) _MSG_WriteShort (x, y, __FILE__, __LINE__);
|
||||
#define MSG_WriteWord(x,y) _MSG_WriteWord (x, y, __FILE__, __LINE__);
|
||||
#define MSG_WriteLong(x,y) _MSG_WriteLong (x, y, __FILE__, __LINE__);
|
||||
|
@ -298,71 +312,45 @@ NET
|
|||
|
||||
==============================================================
|
||||
*/
|
||||
#define PORT_ANY -1
|
||||
#define MAX_MSGLEN 1600 // max length of a message
|
||||
#define PACKET_HEADER 10 // two ints and a short
|
||||
|
||||
typedef enum { NA_LOOPBACK, NA_BROADCAST, NA_IP, NA_IPX, NA_BROADCAST_IPX } netadrtype_t;
|
||||
typedef enum { NS_CLIENT, NS_SERVER } netsrc_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
netadrtype_t type;
|
||||
byte ip[4];
|
||||
byte ipx[10];
|
||||
word port;
|
||||
|
||||
} netadr_t;
|
||||
|
||||
void NET_Init (void);
|
||||
void NET_Shutdown (void);
|
||||
void NET_Config (bool multiplayer);
|
||||
bool NET_GetPacket (netsrc_t sock, netadr_t *net_from, sizebuf_t *net_message);
|
||||
void NET_SendPacket (netsrc_t sock, int length, void *data, netadr_t to);
|
||||
bool NET_CompareAdr (netadr_t a, netadr_t b);
|
||||
bool NET_CompareBaseAdr (netadr_t a, netadr_t b);
|
||||
bool NET_IsLocalAddress (netadr_t adr);
|
||||
char *NET_AdrToString (netadr_t a);
|
||||
bool NET_StringToAdr (char *s, netadr_t *a);
|
||||
void NET_Sleep(int msec);
|
||||
void NET_SendPacket( netsrc_t sock, int length, const void *data, netadr_t to );
|
||||
bool NET_GetLoopPacket( netsrc_t sock, netadr_t *net_from, sizebuf_t *message );
|
||||
bool NET_StringToAdr( const char *s, netadr_t *a );
|
||||
bool NET_CompareBaseAdr( netadr_t a, netadr_t b );
|
||||
bool NET_CompareAdr( netadr_t a, netadr_t b );
|
||||
bool NET_IsLocalAddress( netadr_t adr );
|
||||
|
||||
//============================================================================
|
||||
|
||||
#define OLD_AVG 0.99 // total = oldtotal*OLD_AVG + new*(1-OLD_AVG)
|
||||
#define MAX_LATENT 32
|
||||
|
||||
typedef struct netchan_s
|
||||
{
|
||||
bool fatal_error;
|
||||
netsrc_t sock;
|
||||
netsrc_t sock;
|
||||
|
||||
int dropped; // between last packet and previous
|
||||
|
||||
int last_received; // for timeouts
|
||||
int last_sent; // for retransmits
|
||||
|
||||
netadr_t remote_address;
|
||||
int qport; // qport value to write when transmitting
|
||||
netadr_t remote_address;
|
||||
int qport; // qport value to write when transmitting
|
||||
int dropped; // between last packet and previous
|
||||
|
||||
// sequencing variables
|
||||
int incoming_sequence;
|
||||
int incoming_acknowledged;
|
||||
int incoming_reliable_acknowledged; // single bit
|
||||
int incoming_sequence;
|
||||
int outgoing_sequence;
|
||||
|
||||
int incoming_reliable_sequence; // single bit, maintained local
|
||||
// incoming fragment assembly buffer
|
||||
int fragment_sequence;
|
||||
int fragment_length;
|
||||
byte fragment_buffer[MAX_MSGLEN];
|
||||
|
||||
int outgoing_sequence;
|
||||
int reliable_sequence; // single bit
|
||||
int last_reliable_sequence; // sequence number of last send
|
||||
// outgoing fragment buffer
|
||||
// we need to space out the sending of large fragmented messages
|
||||
bool unsent_fragments;
|
||||
int unsent_fragment_start;
|
||||
int unsent_length;
|
||||
byte unsent_buffer[MAX_MSGLEN];
|
||||
|
||||
// legacy variables
|
||||
// reliable staging and holding areas
|
||||
sizebuf_t message; // writing buffer to send to server
|
||||
byte message_buf[MAX_MSGLEN-16]; // leave space for header
|
||||
|
||||
// message is copied to this buffer when it is first transfered
|
||||
int reliable_length;
|
||||
byte reliable_buf[MAX_MSGLEN-16]; // unacked reliable message
|
||||
|
||||
sizebuf_t message; // writing buffer to send to server
|
||||
byte message_buf[MAX_MSGLEN-16]; // leave space for header
|
||||
int incoming_acknowledged;
|
||||
int last_received; // for timeouts
|
||||
int last_sent; // for retransmits
|
||||
} netchan_t;
|
||||
|
||||
extern netadr_t net_from;
|
||||
|
@ -376,13 +364,12 @@ extern byte net_message_buffer[MAX_MSGLEN];
|
|||
#define UPDATE_BACKUP 64 // copies of entity_state_t to keep buffered, must be power of two
|
||||
#define UPDATE_MASK (UPDATE_BACKUP - 1)
|
||||
|
||||
void Netchan_Init (void);
|
||||
void Netchan_Setup (netsrc_t sock, netchan_t *chan, netadr_t adr, int qport);
|
||||
bool Netchan_NeedReliable (netchan_t *chan);
|
||||
void Netchan_Transmit (netchan_t *chan, int length, byte *data);
|
||||
void Netchan_Init( void );
|
||||
void Netchan_Setup( netsrc_t sock, netchan_t *chan, netadr_t adr, int qport );
|
||||
void Netchan_Transmit( netchan_t *chan, int length, const byte *data );
|
||||
void Netchan_TransmitNextFragment( netchan_t *chan );
|
||||
bool Netchan_Process( netchan_t *chan, sizebuf_t *msg );
|
||||
void Netchan_OutOfBand (int net_socket, netadr_t adr, int length, byte *data);
|
||||
void Netchan_OutOfBandPrint (int net_socket, netadr_t adr, char *format, ...);
|
||||
bool Netchan_Process (netchan_t *chan, sizebuf_t *msg);
|
||||
bool Netchan_CanReliable (netchan_t *chan);
|
||||
void Netchan_OutOfBandPrint (int net_socket, netadr_t adr, const char *format, ...);
|
||||
|
||||
#endif//NET_MSG_H
|
|
@ -1,891 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 1997-2001 Id Software, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// net_wins.c
|
||||
|
||||
#include "winsock.h"
|
||||
#include "wsipx.h"
|
||||
#include "common.h"
|
||||
|
||||
#define MAX_LOOPBACK 4
|
||||
|
||||
typedef struct
|
||||
{
|
||||
byte data[MAX_MSGLEN];
|
||||
int datalen;
|
||||
} loopmsg_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
loopmsg_t msgs[MAX_LOOPBACK];
|
||||
int get, send;
|
||||
} loopback_t;
|
||||
|
||||
|
||||
cvar_t *net_shownet;
|
||||
static cvar_t *noudp;
|
||||
static cvar_t *noipx;
|
||||
|
||||
loopback_t loopbacks[2];
|
||||
int ip_sockets[2];
|
||||
int ipx_sockets[2];
|
||||
|
||||
// wsock32.dll exports
|
||||
static int (_stdcall *pWSACleanup)( void );
|
||||
static word (_stdcall *pNtohs)( word netshort );
|
||||
static int (_stdcall *pWSAGetLastError)( void );
|
||||
static int (_stdcall *pCloseSocket)( SOCKET s );
|
||||
static word (_stdcall *pHtons)( word hostshort );
|
||||
static dword (_stdcall *pInet_Addr)( const char* cp );
|
||||
static SOCKET (_stdcall *pSocket)( int af, int type, int protocol );
|
||||
static struct hostent *(_stdcall *pGetHostByName)( const char* name );
|
||||
static int (_stdcall *pIoctlSocket)( SOCKET s, long cmd, dword* argp );
|
||||
static int (_stdcall *pWSAStartup)( word wVersionRequired, LPWSADATA lpWSAData );
|
||||
static int (_stdcall *pBind)( SOCKET s, const struct sockaddr* addr, int namelen );
|
||||
static int (_stdcall *pSetSockopt)( SOCKET s, int level, int optname, const char* optval, int optlen );
|
||||
static int (_stdcall *pRecvFrom)( SOCKET s, char* buf, int len, int flags, struct sockaddr* from, int* fromlen );
|
||||
static int (_stdcall *pSendTo)( SOCKET s, const char* buf, int len, int flags, const struct sockaddr* to, int tolen );
|
||||
static int (_stdcall *pSelect)( int nfds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds, const struct timeval* timeout );
|
||||
|
||||
static dllfunc_t winsock_funcs[] =
|
||||
{
|
||||
{"bind", (void **) &pBind },
|
||||
{"ntohs", (void **) &pNtohs },
|
||||
{"htons", (void **) &pHtons },
|
||||
{"socket", (void **) &pSocket },
|
||||
{"select", (void **) &pSelect },
|
||||
{"sendto", (void **) &pSendTo },
|
||||
{"recvfrom", (void **) &pRecvFrom },
|
||||
{"inet_addr", (void **) &pInet_Addr },
|
||||
{"WSAStartup", (void **) &pWSAStartup },
|
||||
{"WSACleanup", (void **) &pWSACleanup },
|
||||
{"setsockopt", (void **) &pSetSockopt },
|
||||
{"ioctlsocket", (void **) &pIoctlSocket },
|
||||
{"closesocket", (void **) &pCloseSocket },
|
||||
{"gethostbyname", (void **) &pGetHostByName },
|
||||
{"WSAGetLastError", (void **) &pWSAGetLastError },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
dll_info_t winsock_dll = { "wsock32.dll", winsock_funcs, NULL, NULL, NULL, true, 0 };
|
||||
|
||||
char *NET_ErrorString (void);
|
||||
|
||||
//=============================================================================
|
||||
|
||||
void NET_OpenWinSock( void )
|
||||
{
|
||||
Sys_LoadLibrary( &winsock_dll );
|
||||
}
|
||||
|
||||
void NET_FreeWinSock( void )
|
||||
{
|
||||
Sys_FreeLibrary( &winsock_dll );
|
||||
}
|
||||
|
||||
void NetadrToSockadr (netadr_t *a, struct sockaddr *s)
|
||||
{
|
||||
memset (s, 0, sizeof(*s));
|
||||
|
||||
if (a->type == NA_BROADCAST)
|
||||
{
|
||||
((struct sockaddr_in *)s)->sin_family = AF_INET;
|
||||
((struct sockaddr_in *)s)->sin_port = a->port;
|
||||
((struct sockaddr_in *)s)->sin_addr.s_addr = INADDR_BROADCAST;
|
||||
}
|
||||
else if (a->type == NA_IP)
|
||||
{
|
||||
((struct sockaddr_in *)s)->sin_family = AF_INET;
|
||||
((struct sockaddr_in *)s)->sin_addr.s_addr = *(int *)&a->ip;
|
||||
((struct sockaddr_in *)s)->sin_port = a->port;
|
||||
}
|
||||
else if (a->type == NA_IPX)
|
||||
{
|
||||
((struct sockaddr_ipx *)s)->sa_family = AF_IPX;
|
||||
memcpy(((struct sockaddr_ipx *)s)->sa_netnum, &a->ipx[0], 4);
|
||||
memcpy(((struct sockaddr_ipx *)s)->sa_nodenum, &a->ipx[4], 6);
|
||||
((struct sockaddr_ipx *)s)->sa_socket = a->port;
|
||||
}
|
||||
else if (a->type == NA_BROADCAST_IPX)
|
||||
{
|
||||
((struct sockaddr_ipx *)s)->sa_family = AF_IPX;
|
||||
memset(((struct sockaddr_ipx *)s)->sa_netnum, 0, 4);
|
||||
memset(((struct sockaddr_ipx *)s)->sa_nodenum, 0xff, 6);
|
||||
((struct sockaddr_ipx *)s)->sa_socket = a->port;
|
||||
}
|
||||
}
|
||||
|
||||
void SockadrToNetadr (struct sockaddr *s, netadr_t *a)
|
||||
{
|
||||
if (s->sa_family == AF_INET)
|
||||
{
|
||||
a->type = NA_IP;
|
||||
*(int *)&a->ip = ((struct sockaddr_in *)s)->sin_addr.s_addr;
|
||||
a->port = ((struct sockaddr_in *)s)->sin_port;
|
||||
}
|
||||
else if (s->sa_family == AF_IPX)
|
||||
{
|
||||
a->type = NA_IPX;
|
||||
memcpy(&a->ipx[0], ((struct sockaddr_ipx *)s)->sa_netnum, 4);
|
||||
memcpy(&a->ipx[4], ((struct sockaddr_ipx *)s)->sa_nodenum, 6);
|
||||
a->port = ((struct sockaddr_ipx *)s)->sa_socket;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool NET_CompareAdr (netadr_t a, netadr_t b)
|
||||
{
|
||||
if (a.type != b.type)
|
||||
return false;
|
||||
|
||||
if (a.type == NA_LOOPBACK)
|
||||
return TRUE;
|
||||
|
||||
if (a.type == NA_IP)
|
||||
{
|
||||
if (a.ip[0] == b.ip[0] && a.ip[1] == b.ip[1] && a.ip[2] == b.ip[2] && a.ip[3] == b.ip[3] && a.port == b.port)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (a.type == NA_IPX)
|
||||
{
|
||||
if ((memcmp(a.ipx, b.ipx, 10) == 0) && a.port == b.port)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
===================
|
||||
NET_CompareBaseAdr
|
||||
|
||||
Compares without the port
|
||||
===================
|
||||
*/
|
||||
bool NET_CompareBaseAdr (netadr_t a, netadr_t b)
|
||||
{
|
||||
if (a.type != b.type)
|
||||
return false;
|
||||
|
||||
if (a.type == NA_LOOPBACK)
|
||||
return TRUE;
|
||||
|
||||
if (a.type == NA_IP)
|
||||
{
|
||||
if (a.ip[0] == b.ip[0] && a.ip[1] == b.ip[1] && a.ip[2] == b.ip[2] && a.ip[3] == b.ip[3])
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (a.type == NA_IPX)
|
||||
{
|
||||
if ((memcmp(a.ipx, b.ipx, 10) == 0))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
char *NET_AdrToString (netadr_t a)
|
||||
{
|
||||
static char s[64];
|
||||
|
||||
if (a.type == NA_LOOPBACK) com.sprintf (s, "loopback");
|
||||
else if (a.type == NA_IP) com.sprintf (s, "%i.%i.%i.%i:%i", a.ip[0], a.ip[1], a.ip[2], a.ip[3], pNtohs(a.port));
|
||||
else com.sprintf (s, "%02x%02x%02x%02x:%02x%02x%02x%02x%02x%02x:%i", a.ipx[0], a.ipx[1], a.ipx[2], a.ipx[3], a.ipx[4], a.ipx[5], a.ipx[6], a.ipx[7], a.ipx[8], a.ipx[9], pNtohs(a.port));
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
NET_StringToAdr
|
||||
|
||||
localhost
|
||||
idnewt
|
||||
idnewt:28000
|
||||
192.246.40.70
|
||||
192.246.40.70:28000
|
||||
=============
|
||||
*/
|
||||
#define DO(src,dest) \
|
||||
copy[0] = s[src]; \
|
||||
copy[1] = s[src + 1]; \
|
||||
sscanf (copy, "%x", &val); \
|
||||
((struct sockaddr_ipx *)sadr)->dest = val
|
||||
|
||||
bool NET_StringToSockaddr (char *s, struct sockaddr *sadr)
|
||||
{
|
||||
struct hostent *h;
|
||||
char *colon;
|
||||
int val;
|
||||
char copy[128];
|
||||
|
||||
memset (sadr, 0, sizeof(*sadr));
|
||||
|
||||
if ((strlen(s) >= 23) && (s[8] == ':') && (s[21] == ':')) // check for an IPX address
|
||||
{
|
||||
((struct sockaddr_ipx *)sadr)->sa_family = AF_IPX;
|
||||
copy[2] = 0;
|
||||
DO(0, sa_netnum[0]);
|
||||
DO(2, sa_netnum[1]);
|
||||
DO(4, sa_netnum[2]);
|
||||
DO(6, sa_netnum[3]);
|
||||
DO(9, sa_nodenum[0]);
|
||||
DO(11, sa_nodenum[1]);
|
||||
DO(13, sa_nodenum[2]);
|
||||
DO(15, sa_nodenum[3]);
|
||||
DO(17, sa_nodenum[4]);
|
||||
DO(19, sa_nodenum[5]);
|
||||
sscanf (&s[22], "%u", &val);
|
||||
((struct sockaddr_ipx *)sadr)->sa_socket = pHtons((unsigned short)val);
|
||||
}
|
||||
else
|
||||
{
|
||||
((struct sockaddr_in *)sadr)->sin_family = AF_INET;
|
||||
|
||||
((struct sockaddr_in *)sadr)->sin_port = 0;
|
||||
|
||||
strcpy (copy, s);
|
||||
// strip off a trailing :port if present
|
||||
for (colon = copy ; *colon ; colon++)
|
||||
if (*colon == ':')
|
||||
{
|
||||
*colon = 0;
|
||||
((struct sockaddr_in *)sadr)->sin_port = pHtons((short)atoi(colon+1));
|
||||
}
|
||||
|
||||
if (copy[0] >= '0' && copy[0] <= '9')
|
||||
{
|
||||
*(int *)&((struct sockaddr_in *)sadr)->sin_addr = pInet_Addr(copy);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (! (h = pGetHostByName(copy)) )
|
||||
return 0;
|
||||
*(int *)&((struct sockaddr_in *)sadr)->sin_addr = *(int *)h->h_addr_list[0];
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#undef DO
|
||||
|
||||
/*
|
||||
=============
|
||||
NET_StringToAdr
|
||||
|
||||
localhost
|
||||
idnewt
|
||||
idnewt:28000
|
||||
192.246.40.70
|
||||
192.246.40.70:28000
|
||||
=============
|
||||
*/
|
||||
bool NET_StringToAdr (char *s, netadr_t *a)
|
||||
{
|
||||
struct sockaddr sadr;
|
||||
|
||||
if (!strcmp (s, "localhost"))
|
||||
{
|
||||
memset (a, 0, sizeof(*a));
|
||||
a->type = NA_LOOPBACK;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!NET_StringToSockaddr (s, &sadr))
|
||||
return false;
|
||||
|
||||
SockadrToNetadr (&sadr, a);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool NET_IsLocalAddress (netadr_t adr)
|
||||
{
|
||||
return adr.type == NA_LOOPBACK;
|
||||
}
|
||||
|
||||
/*
|
||||
=============================================================================
|
||||
|
||||
LOOPBACK BUFFERS FOR LOCAL PLAYER
|
||||
|
||||
=============================================================================
|
||||
*/
|
||||
|
||||
bool NET_GetLoopPacket (netsrc_t sock, netadr_t *net_from, sizebuf_t *net_message)
|
||||
{
|
||||
int i;
|
||||
loopback_t *loop;
|
||||
|
||||
loop = &loopbacks[sock];
|
||||
|
||||
if (loop->send - loop->get > MAX_LOOPBACK)
|
||||
loop->get = loop->send - MAX_LOOPBACK;
|
||||
|
||||
if (loop->get >= loop->send)
|
||||
return false;
|
||||
|
||||
i = loop->get & (MAX_LOOPBACK-1);
|
||||
loop->get++;
|
||||
|
||||
memcpy (net_message->data, loop->msgs[i].data, loop->msgs[i].datalen);
|
||||
net_message->cursize = loop->msgs[i].datalen;
|
||||
memset (net_from, 0, sizeof(*net_from));
|
||||
net_from->type = NA_LOOPBACK;
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void NET_SendLoopPacket (netsrc_t sock, int length, void *data, netadr_t to)
|
||||
{
|
||||
int i;
|
||||
loopback_t *loop;
|
||||
|
||||
loop = &loopbacks[sock^1];
|
||||
|
||||
i = loop->send & (MAX_LOOPBACK-1);
|
||||
loop->send++;
|
||||
|
||||
Mem_Copy(loop->msgs[i].data, data, length);
|
||||
loop->msgs[i].datalen = length;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
bool NET_GetPacket (netsrc_t sock, netadr_t *net_from, sizebuf_t *net_message)
|
||||
{
|
||||
int ret;
|
||||
struct sockaddr from;
|
||||
int fromlen;
|
||||
int net_socket;
|
||||
int protocol;
|
||||
int err;
|
||||
|
||||
if (NET_GetLoopPacket (sock, net_from, net_message))
|
||||
return true;
|
||||
|
||||
for (protocol = 0 ; protocol < 2 ; protocol++)
|
||||
{
|
||||
if (protocol == 0)
|
||||
net_socket = ip_sockets[sock];
|
||||
else
|
||||
net_socket = ipx_sockets[sock];
|
||||
|
||||
if (!net_socket)
|
||||
continue;
|
||||
|
||||
fromlen = sizeof(from);
|
||||
ret = pRecvFrom (net_socket, net_message->data, net_message->maxsize
|
||||
, 0, (struct sockaddr *)&from, &fromlen);
|
||||
|
||||
SockadrToNetadr (&from, net_from);
|
||||
|
||||
if (ret == -1)
|
||||
{
|
||||
err = pWSAGetLastError();
|
||||
|
||||
if (err == WSAEWOULDBLOCK)
|
||||
continue;
|
||||
if (err == WSAEMSGSIZE)
|
||||
{
|
||||
MsgDev( D_ERROR, "NET_GetPacket: Oversize packet from %s\n", NET_AdrToString(*net_from));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dedicated->value) // let dedicated servers continue after errors
|
||||
Msg ("NET_GetPacket: %s from %s\n", NET_ErrorString(), NET_AdrToString(*net_from));
|
||||
else Host_Error("NET_GetPacket: %s from %s\n", NET_ErrorString(), NET_AdrToString(*net_from));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ret == net_message->maxsize)
|
||||
{
|
||||
Msg ("Oversize packet from %s\n", NET_AdrToString (*net_from));
|
||||
continue;
|
||||
}
|
||||
|
||||
net_message->cursize = ret;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
void NET_SendPacket (netsrc_t sock, int length, void *data, netadr_t to)
|
||||
{
|
||||
int ret;
|
||||
struct sockaddr addr;
|
||||
int net_socket;
|
||||
|
||||
if ( to.type == NA_LOOPBACK )
|
||||
{
|
||||
NET_SendLoopPacket (sock, length, data, to);
|
||||
return;
|
||||
}
|
||||
|
||||
if (to.type == NA_BROADCAST)
|
||||
{
|
||||
net_socket = ip_sockets[sock];
|
||||
if (!net_socket) return;
|
||||
}
|
||||
else if (to.type == NA_IP)
|
||||
{
|
||||
net_socket = ip_sockets[sock];
|
||||
if (!net_socket) return;
|
||||
}
|
||||
else if (to.type == NA_IPX)
|
||||
{
|
||||
net_socket = ipx_sockets[sock];
|
||||
if (!net_socket) return;
|
||||
}
|
||||
else if (to.type == NA_BROADCAST_IPX)
|
||||
{
|
||||
net_socket = ipx_sockets[sock];
|
||||
if (!net_socket) return;
|
||||
}
|
||||
else
|
||||
{
|
||||
MsgDev( D_ERROR, "NET_SendPacket: bad address type\n");
|
||||
return;
|
||||
}
|
||||
|
||||
NetadrToSockadr (&to, &addr);
|
||||
|
||||
ret = pSendTo (net_socket, data, length, 0, &addr, sizeof(addr) );
|
||||
if (ret == -1)
|
||||
{
|
||||
int err = pWSAGetLastError();
|
||||
|
||||
// wouldblock is silent
|
||||
if (err == WSAEWOULDBLOCK)
|
||||
return;
|
||||
|
||||
// some PPP links dont allow broadcasts
|
||||
if ((err == WSAEADDRNOTAVAIL) && ((to.type == NA_BROADCAST) || (to.type == NA_BROADCAST_IPX)))
|
||||
return;
|
||||
|
||||
if (dedicated->value) // let dedicated servers continue after errors
|
||||
{
|
||||
Msg ("NET_SendPacket ERROR: %s to %s\n", NET_ErrorString(), NET_AdrToString (to));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (err == WSAEADDRNOTAVAIL)
|
||||
{
|
||||
MsgDev( D_ERROR, "NET_SendPacket: %s : %s\n", NET_ErrorString(), NET_AdrToString (to));
|
||||
}
|
||||
else
|
||||
{
|
||||
Host_Error("NET_SendPacket: %s to %s\n", NET_ErrorString(), NET_AdrToString(to));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
|
||||
|
||||
/*
|
||||
====================
|
||||
NET_Socket
|
||||
====================
|
||||
*/
|
||||
int NET_IPSocket (char *net_interface, int port)
|
||||
{
|
||||
int newsocket;
|
||||
struct sockaddr_in address;
|
||||
bool _true = true;
|
||||
int i = 1;
|
||||
int err;
|
||||
|
||||
if ((newsocket = pSocket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
|
||||
{
|
||||
err = pWSAGetLastError();
|
||||
if (err != WSAEAFNOSUPPORT)
|
||||
Msg ("WARNING: UDP_OpenSocket: socket: %s", NET_ErrorString());
|
||||
return 0;
|
||||
}
|
||||
|
||||
// make it non-blocking
|
||||
if (pIoctlSocket (newsocket, FIONBIO, &_true) == -1)
|
||||
{
|
||||
Msg ("WARNING: UDP_OpenSocket: ioctl FIONBIO: %s\n", NET_ErrorString());
|
||||
return 0;
|
||||
}
|
||||
|
||||
// make it broadcast capable
|
||||
if (pSetSockopt(newsocket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i)) == -1)
|
||||
{
|
||||
Msg ("WARNING: UDP_OpenSocket: setsockopt SO_BROADCAST: %s\n", NET_ErrorString());
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!net_interface || !net_interface[0] || !stricmp(net_interface, "localhost"))
|
||||
address.sin_addr.s_addr = INADDR_ANY;
|
||||
else
|
||||
NET_StringToSockaddr (net_interface, (struct sockaddr *)&address);
|
||||
|
||||
if (port == PORT_ANY)
|
||||
address.sin_port = 0;
|
||||
else
|
||||
address.sin_port = pHtons((short)port);
|
||||
|
||||
address.sin_family = AF_INET;
|
||||
|
||||
if( pBind (newsocket, (void *)&address, sizeof(address)) == -1)
|
||||
{
|
||||
Msg ("WARNING: UDP_OpenSocket: bind: %s\n", NET_ErrorString());
|
||||
pCloseSocket (newsocket);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return newsocket;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
====================
|
||||
NET_OpenIP
|
||||
====================
|
||||
*/
|
||||
void NET_OpenIP (void)
|
||||
{
|
||||
cvar_t *ip;
|
||||
int port;
|
||||
int dedicated;
|
||||
|
||||
ip = Cvar_Get ("ip", "localhost", CVAR_INIT, "network ip address" );
|
||||
|
||||
dedicated = Cvar_VariableValue ("dedicated");
|
||||
|
||||
if (!ip_sockets[NS_SERVER])
|
||||
{
|
||||
port = Cvar_Get("ip_hostport", "0", CVAR_INIT, "no description" )->value;
|
||||
if (!port)
|
||||
{
|
||||
port = Cvar_Get("hostport", "0", CVAR_INIT, "no description" )->value;
|
||||
if (!port)
|
||||
{
|
||||
port = Cvar_Get("port", va("%i", PORT_SERVER), CVAR_INIT, "no description" )->value;
|
||||
}
|
||||
}
|
||||
ip_sockets[NS_SERVER] = NET_IPSocket (ip->string, port);
|
||||
if (!ip_sockets[NS_SERVER] && dedicated) Sys_Error("Couldn't allocate dedicated server IP port");
|
||||
}
|
||||
|
||||
|
||||
// dedicated servers don't need client ports
|
||||
if (dedicated) return;
|
||||
|
||||
if (!ip_sockets[NS_CLIENT])
|
||||
{
|
||||
port = Cvar_Get("ip_clientport", "0", CVAR_INIT, "no description" )->value;
|
||||
if (!port)
|
||||
{
|
||||
port = Cvar_Get("clientport", va("%i", PORT_CLIENT), CVAR_INIT, "no description" )->value;
|
||||
if (!port)
|
||||
port = PORT_ANY;
|
||||
}
|
||||
ip_sockets[NS_CLIENT] = NET_IPSocket (ip->string, port);
|
||||
if (!ip_sockets[NS_CLIENT])
|
||||
ip_sockets[NS_CLIENT] = NET_IPSocket (ip->string, PORT_ANY);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
====================
|
||||
IPX_Socket
|
||||
====================
|
||||
*/
|
||||
int NET_IPXSocket (int port)
|
||||
{
|
||||
int newsocket;
|
||||
struct sockaddr_ipx address;
|
||||
int _true = 1;
|
||||
int err;
|
||||
|
||||
if ((newsocket = pSocket (PF_IPX, SOCK_DGRAM, NSPROTO_IPX)) == -1)
|
||||
{
|
||||
err = pWSAGetLastError();
|
||||
if (err != WSAEAFNOSUPPORT)
|
||||
Msg ("WARNING: IPX_Socket: socket: %s\n", NET_ErrorString());
|
||||
return 0;
|
||||
}
|
||||
|
||||
// make it non-blocking
|
||||
if (pIoctlSocket (newsocket, FIONBIO, &_true) == -1)
|
||||
{
|
||||
Msg ("WARNING: IPX_Socket: ioctl FIONBIO: %s\n", NET_ErrorString());
|
||||
return 0;
|
||||
}
|
||||
|
||||
// make it broadcast capable
|
||||
if (pSetSockopt(newsocket, SOL_SOCKET, SO_BROADCAST, (char *)&_true, sizeof(_true)) == -1)
|
||||
{
|
||||
Msg ("WARNING: IPX_Socket: setsockopt SO_BROADCAST: %s\n", NET_ErrorString());
|
||||
return 0;
|
||||
}
|
||||
|
||||
address.sa_family = AF_IPX;
|
||||
memset (address.sa_netnum, 0, 4);
|
||||
memset (address.sa_nodenum, 0, 6);
|
||||
if (port == PORT_ANY)
|
||||
address.sa_socket = 0;
|
||||
else
|
||||
address.sa_socket = pHtons((short)port);
|
||||
|
||||
if( pBind (newsocket, (void *)&address, sizeof(address)) == -1)
|
||||
{
|
||||
Msg ("WARNING: IPX_Socket: bind: %s\n", NET_ErrorString());
|
||||
pCloseSocket (newsocket);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return newsocket;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
====================
|
||||
NET_OpenIPX
|
||||
====================
|
||||
*/
|
||||
void NET_OpenIPX (void)
|
||||
{
|
||||
int port;
|
||||
int dedicated;
|
||||
|
||||
dedicated = Cvar_VariableValue ("dedicated");
|
||||
|
||||
if (!ipx_sockets[NS_SERVER])
|
||||
{
|
||||
port = Cvar_Get("ipx_hostport", "0", CVAR_INIT, "no description" )->value;
|
||||
if (!port)
|
||||
{
|
||||
port = Cvar_Get("hostport", "0", CVAR_INIT, "no description" )->value;
|
||||
if (!port)
|
||||
{
|
||||
port = Cvar_Get("port", va("%i", PORT_SERVER ), CVAR_INIT, "no description" )->value;
|
||||
}
|
||||
}
|
||||
ipx_sockets[NS_SERVER] = NET_IPXSocket (port);
|
||||
}
|
||||
|
||||
// dedicated servers don't need client ports
|
||||
if (dedicated)
|
||||
return;
|
||||
|
||||
if (!ipx_sockets[NS_CLIENT])
|
||||
{
|
||||
port = Cvar_Get("ipx_clientport", "0", CVAR_INIT, "no description" )->value;
|
||||
if (!port)
|
||||
{
|
||||
port = Cvar_Get("clientport", va("%i", PORT_CLIENT), CVAR_INIT, "no description" )->value;
|
||||
if (!port)
|
||||
port = PORT_ANY;
|
||||
}
|
||||
ipx_sockets[NS_CLIENT] = NET_IPXSocket (port);
|
||||
if (!ipx_sockets[NS_CLIENT]) ipx_sockets[NS_CLIENT] = NET_IPXSocket (PORT_ANY);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
====================
|
||||
NET_Config
|
||||
|
||||
A single player game will only use the loopback code
|
||||
====================
|
||||
*/
|
||||
void NET_Config (bool multiplayer)
|
||||
{
|
||||
int i;
|
||||
static bool old_config;
|
||||
|
||||
if (old_config == multiplayer)
|
||||
return;
|
||||
|
||||
old_config = multiplayer;
|
||||
|
||||
if (!multiplayer)
|
||||
{ // shut down any existing sockets
|
||||
for (i=0 ; i<2 ; i++)
|
||||
{
|
||||
if (ip_sockets[i])
|
||||
{
|
||||
pCloseSocket (ip_sockets[i]);
|
||||
ip_sockets[i] = 0;
|
||||
}
|
||||
if (ipx_sockets[i])
|
||||
{
|
||||
pCloseSocket (ipx_sockets[i]);
|
||||
ipx_sockets[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // open sockets
|
||||
if (! noudp->value)
|
||||
NET_OpenIP ();
|
||||
if (! noipx->value)
|
||||
NET_OpenIPX ();
|
||||
}
|
||||
}
|
||||
|
||||
// sleeps msec or until net socket is ready
|
||||
void NET_Sleep(int msec)
|
||||
{
|
||||
struct timeval timeout;
|
||||
fd_set fdset;
|
||||
extern cvar_t *dedicated;
|
||||
int i;
|
||||
|
||||
if (!dedicated || !dedicated->value)
|
||||
return; // we're not a server, just run full speed
|
||||
|
||||
FD_ZERO(&fdset);
|
||||
i = 0;
|
||||
if (ip_sockets[NS_SERVER]) {
|
||||
FD_SET(ip_sockets[NS_SERVER], &fdset); // network socket
|
||||
i = ip_sockets[NS_SERVER];
|
||||
}
|
||||
if (ipx_sockets[NS_SERVER]) {
|
||||
FD_SET(ipx_sockets[NS_SERVER], &fdset); // network socket
|
||||
if (ipx_sockets[NS_SERVER] > i)
|
||||
i = ipx_sockets[NS_SERVER];
|
||||
}
|
||||
timeout.tv_sec = msec/1000;
|
||||
timeout.tv_usec = (msec%1000)*1000;
|
||||
pSelect(i+1, &fdset, NULL, NULL, &timeout);
|
||||
}
|
||||
|
||||
//===================================================================
|
||||
|
||||
|
||||
static WSADATA winsockdata;
|
||||
|
||||
/*
|
||||
====================
|
||||
NET_Init
|
||||
====================
|
||||
*/
|
||||
void NET_Init (void)
|
||||
{
|
||||
WORD wVersionRequested;
|
||||
int r;
|
||||
|
||||
wVersionRequested = MAKEWORD(1, 1);
|
||||
NET_OpenWinSock(); // loading wsock32.dll
|
||||
|
||||
r = pWSAStartup (MAKEWORD(1, 1), &winsockdata);
|
||||
if(r) Sys_Error("Winsock initialization failed.");
|
||||
|
||||
MsgDev(D_NOTE, "NET_Init()\n");
|
||||
|
||||
noudp = Cvar_Get ("noudp", "0", CVAR_INIT, "no description" );
|
||||
noipx = Cvar_Get ("noipx", "0", CVAR_INIT, "no description" );
|
||||
|
||||
net_shownet = Cvar_Get ("net_shownet", "0", 0, "show network status" );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
====================
|
||||
NET_Shutdown
|
||||
====================
|
||||
*/
|
||||
void NET_Shutdown (void)
|
||||
{
|
||||
NET_Config (false); // close sockets
|
||||
pWSACleanup ();
|
||||
NET_FreeWinSock();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
====================
|
||||
NET_ErrorString
|
||||
====================
|
||||
*/
|
||||
char *NET_ErrorString (void)
|
||||
{
|
||||
int code;
|
||||
|
||||
code = pWSAGetLastError ();
|
||||
switch (code)
|
||||
{
|
||||
case WSAEINTR: return "WSAEINTR";
|
||||
case WSAEBADF: return "WSAEBADF";
|
||||
case WSAEACCES: return "WSAEACCES";
|
||||
case WSAEDISCON: return "WSAEDISCON";
|
||||
case WSAEFAULT: return "WSAEFAULT";
|
||||
case WSAEINVAL: return "WSAEINVAL";
|
||||
case WSAEMFILE: return "WSAEMFILE";
|
||||
case WSAEWOULDBLOCK: return "WSAEWOULDBLOCK";
|
||||
case WSAEINPROGRESS: return "WSAEINPROGRESS";
|
||||
case WSAEALREADY: return "WSAEALREADY";
|
||||
case WSAENOTSOCK: return "WSAENOTSOCK";
|
||||
case WSAEDESTADDRREQ: return "WSAEDESTADDRREQ";
|
||||
case WSAEMSGSIZE: return "WSAEMSGSIZE";
|
||||
case WSAEPROTOTYPE: return "WSAEPROTOTYPE";
|
||||
case WSAENOPROTOOPT: return "WSAENOPROTOOPT";
|
||||
case WSAEPROTONOSUPPORT: return "WSAEPROTONOSUPPORT";
|
||||
case WSAESOCKTNOSUPPORT: return "WSAESOCKTNOSUPPORT";
|
||||
case WSAEOPNOTSUPP: return "WSAEOPNOTSUPP";
|
||||
case WSAEPFNOSUPPORT: return "WSAEPFNOSUPPORT";
|
||||
case WSAEAFNOSUPPORT: return "WSAEAFNOSUPPORT";
|
||||
case WSAEADDRINUSE: return "WSAEADDRINUSE";
|
||||
case WSAEADDRNOTAVAIL: return "WSAEADDRNOTAVAIL";
|
||||
case WSAENETDOWN: return "WSAENETDOWN";
|
||||
case WSAENETUNREACH: return "WSAENETUNREACH";
|
||||
case WSAENETRESET: return "WSAENETRESET";
|
||||
case WSAECONNABORTED: return "WSWSAECONNABORTEDAEINTR";
|
||||
case WSAECONNRESET: return "WSAECONNRESET";
|
||||
case WSAENOBUFS: return "WSAENOBUFS";
|
||||
case WSAEISCONN: return "WSAEISCONN";
|
||||
case WSAENOTCONN: return "WSAENOTCONN";
|
||||
case WSAESHUTDOWN: return "WSAESHUTDOWN";
|
||||
case WSAETOOMANYREFS: return "WSAETOOMANYREFS";
|
||||
case WSAETIMEDOUT: return "WSAETIMEDOUT";
|
||||
case WSAECONNREFUSED: return "WSAECONNREFUSED";
|
||||
case WSAELOOP: return "WSAELOOP";
|
||||
case WSAENAMETOOLONG: return "WSAENAMETOOLONG";
|
||||
case WSAEHOSTDOWN: return "WSAEHOSTDOWN";
|
||||
case WSASYSNOTREADY: return "WSASYSNOTREADY";
|
||||
case WSAVERNOTSUPPORTED: return "WSAVERNOTSUPPORTED";
|
||||
case WSANOTINITIALISED: return "WSANOTINITIALISED";
|
||||
case WSAHOST_NOT_FOUND: return "WSAHOST_NOT_FOUND";
|
||||
case WSATRY_AGAIN: return "WSATRY_AGAIN";
|
||||
case WSANO_RECOVERY: return "WSANO_RECOVERY";
|
||||
case WSANO_DATA: return "WSANO_DATA";
|
||||
default: return "NO ERROR";
|
||||
}
|
||||
}
|
|
@ -69,6 +69,7 @@ typedef struct server_s
|
|||
sv_state_t state; // precache commands are only valid during load
|
||||
|
||||
bool loadgame; // client begins should reuse existing entity
|
||||
bool autosaved;
|
||||
|
||||
float time; // always sv.framenum * 50 msec
|
||||
float frametime;
|
||||
|
@ -77,7 +78,7 @@ typedef struct server_s
|
|||
char name[MAX_QPATH]; // map name, or cinematic name
|
||||
cmodel_t *models[MAX_MODELS];
|
||||
|
||||
char configstrings[MAX_CONFIGSTRINGS][MAX_QPATH];
|
||||
string configstrings[MAX_CONFIGSTRINGS];
|
||||
entity_state_t baselines[MAX_EDICTS];
|
||||
|
||||
// the multicast buffer is used to send a message to a set of clients
|
||||
|
@ -87,8 +88,6 @@ typedef struct server_s
|
|||
|
||||
int lastchecktime;
|
||||
int lastcheck;
|
||||
|
||||
bool autosaved;
|
||||
} server_t;
|
||||
|
||||
typedef struct
|
||||
|
|
|
@ -18,7 +18,7 @@ void SV_SetMaster_f( void )
|
|||
int i, slot;
|
||||
|
||||
// only dedicated servers send heartbeats
|
||||
if(!dedicated->value)
|
||||
if( host.type == HOST_DEDICATED )
|
||||
{
|
||||
Msg("Only dedicated servers use masters.\n");
|
||||
return;
|
||||
|
@ -492,7 +492,7 @@ void SV_InitOperatorCommands( void )
|
|||
Cmd_AddCommand("restart", SV_Restart_f, "restarting current level" );
|
||||
Cmd_AddCommand("sectorlist", SV_SectorList_f, "display pvs sectors" );
|
||||
|
||||
if( dedicated->value )
|
||||
if( host.type == HOST_DEDICATED )
|
||||
{
|
||||
Cmd_AddCommand ("say", SV_ConSay_f, "send a chat message to everyone on the server" );
|
||||
Cmd_AddCommand("setmaster", SV_SetMaster_f, "set ip address for dedicated server" );
|
||||
|
@ -518,7 +518,7 @@ void SV_KillOperatorCommands( void )
|
|||
Cmd_RemoveCommand("restart");
|
||||
Cmd_RemoveCommand("sectorlist");
|
||||
|
||||
if( dedicated->integer )
|
||||
if( host.type == HOST_DEDICATED )
|
||||
{
|
||||
Cmd_RemoveCommand("say");
|
||||
Cmd_RemoveCommand("setmaster");
|
||||
|
|
|
@ -21,6 +21,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#include "common.h"
|
||||
#include "server.h"
|
||||
|
||||
void SV_PacketEvent( netadr_t from, sizebuf_t *msg )
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
=============================================================================
|
||||
|
||||
|
|
|
@ -273,7 +273,7 @@ void SV_InitGame (void)
|
|||
|
||||
// dedicated servers are can't be single player and are usually DM
|
||||
// so unless they explicity set coop, force it to deathmatch
|
||||
if (dedicated->value)
|
||||
if( host.type == HOST_DEDICATED )
|
||||
{
|
||||
if (!Cvar_VariableValue ("coop"))
|
||||
Cvar_FullSet ("deathmatch", "1", CVAR_SERVERINFO | CVAR_LATCH);
|
||||
|
|
|
@ -576,7 +576,7 @@ void SV_ReadPackets (void)
|
|||
client_state_t *cl;
|
||||
int qport;
|
||||
|
||||
while (NET_GetPacket (NS_SERVER, &net_from, &net_message))
|
||||
while (Sys_RecvPacket(&net_from, &net_message))
|
||||
{
|
||||
// check for connectionless packet (0xffffffff) first
|
||||
if (*(int *)net_message.data == -1)
|
||||
|
@ -730,7 +730,7 @@ void SV_Frame( dword time )
|
|||
svs.realtime = (sv.time * 1000 ) - HOST_FRAMETIME;
|
||||
}
|
||||
|
||||
NET_Sleep((sv.time*1000) - svs.realtime);
|
||||
//NET_Sleep((sv.time*1000) - svs.realtime);
|
||||
SV_VM_End(); //end frame
|
||||
return;
|
||||
}
|
||||
|
@ -770,9 +770,8 @@ void Master_Heartbeat (void)
|
|||
char *string;
|
||||
int i;
|
||||
|
||||
// pgm post3.19 change, cvar pointer not validated before dereferencing
|
||||
if (!dedicated || !dedicated->value)
|
||||
return; // only dedicated servers send heartbeats
|
||||
if( host.type == HOST_DEDICATED )
|
||||
return; // only dedicated servers send heartbeats
|
||||
|
||||
// pgm post3.19 change, cvar pointer not validated before dereferencing
|
||||
if (!public_server || !public_server->value)
|
||||
|
@ -811,9 +810,8 @@ void Master_Shutdown (void)
|
|||
{
|
||||
int i;
|
||||
|
||||
// pgm post3.19 change, cvar pointer not validated before dereferencing
|
||||
if (!dedicated || !dedicated->value)
|
||||
return; // only dedicated servers send heartbeats
|
||||
if( host.type == HOST_DEDICATED )
|
||||
return; // only dedicated servers send heartbeats
|
||||
|
||||
// pgm post3.19 change, cvar pointer not validated before dereferencing
|
||||
if (!public_server || !public_server->value)
|
||||
|
@ -929,6 +927,8 @@ void SV_Init (void)
|
|||
sv_reconnect_limit = Cvar_Get ("sv_reconnect_limit", "3", CVAR_ARCHIVE, "max reconnect attempts" );
|
||||
|
||||
SZ_Init (&net_message, net_message_buffer, sizeof(net_message_buffer));
|
||||
|
||||
host.sv_running = true;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1000,5 +1000,6 @@ void SV_Shutdown( bool reconnect )
|
|||
if (svs.clients) Mem_Free (svs.clients);
|
||||
if (svs.client_entities) Mem_Free (svs.client_entities);
|
||||
memset (&svs, 0, sizeof(svs));
|
||||
host.sv_running = false;
|
||||
}
|
||||
|
||||
|
|
|
@ -99,7 +99,7 @@ void SV_BroadcastPrintf (int level, char *fmt, ...)
|
|||
va_end (argptr);
|
||||
|
||||
// echo to console
|
||||
if (dedicated->value)
|
||||
if( host.type == HOST_DEDICATED )
|
||||
{
|
||||
char echo[1024];
|
||||
int i;
|
||||
|
@ -530,5 +530,4 @@ void SV_SendClientMessages (void)
|
|||
Netchan_Transmit( &c->netchan, 0, NULL );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -678,7 +678,7 @@ void Cmd_Say_f (edict_t *ent, bool team, bool arg0)
|
|||
|
||||
com.strcat(text, "\n");
|
||||
|
||||
if (dedicated->value)
|
||||
if( host.type == HOST_DEDICATED )
|
||||
PF_cprintf(NULL, PRINT_CHAT, "%s", text);
|
||||
|
||||
for (j = 1; j <= maxclients->value; j++)
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============
|
||||
//
|
||||
// Purpose: Generalized 32-bit random number generator
|
||||
// Range is 0x00000000 - 0x7FFFFFFF
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================
|
||||
|
||||
#ifndef RANDOM_H
|
||||
#define RANDOM_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
// the random number seeding is automatic
|
||||
|
||||
#define MAX_RANDOM_RANGE 0x7FFFFFFFUL
|
||||
|
||||
// restarts random generator
|
||||
// setting lSeed to 0 causes the current time to be used as the seed
|
||||
// random number generator will automatically seed itself on first use with current time if this is not called
|
||||
extern void SeedRandomNumberGenerator(long lSeed = 0);
|
||||
|
||||
// returns a random integer of range [low, high]
|
||||
extern long RandomLong( long lLow, long lHigh );
|
||||
|
||||
// returns a random float of range [low, high)
|
||||
extern float RandomFloat( float flLow, float flHigh );
|
||||
|
||||
#endif // RANDOM_H
|
|
@ -8,21 +8,21 @@
|
|||
// Processor Information:
|
||||
typedef struct cpuinfo_s
|
||||
{
|
||||
bool m_bRDTSC : 1; // Is RDTSC supported?
|
||||
bool m_bCMOV : 1; // Is CMOV supported?
|
||||
bool m_bFCMOV : 1; // Is FCMOV supported?
|
||||
bool m_bSSE : 1; // Is SSE supported?
|
||||
bool m_bSSE2 : 1; // Is SSE2 Supported?
|
||||
bool m_b3DNow : 1; // Is 3DNow! Supported?
|
||||
bool m_bMMX : 1; // Is MMX supported?
|
||||
bool m_bHT : 1; // Is HyperThreading supported?
|
||||
bool m_bRDTSC : 1; // Is RDTSC supported?
|
||||
bool m_bCMOV : 1; // Is CMOV supported?
|
||||
bool m_bFCMOV : 1; // Is FCMOV supported?
|
||||
bool m_bSSE : 1; // Is SSE supported?
|
||||
bool m_bSSE2 : 1; // Is SSE2 Supported?
|
||||
bool m_b3DNow : 1; // Is 3DNow! Supported?
|
||||
bool m_bMMX : 1; // Is MMX supported?
|
||||
bool m_bHT : 1; // Is HyperThreading supported?
|
||||
|
||||
byte m_usNumLogicCore; // Number op logical processors.
|
||||
byte m_usNumPhysCore; // Number of physical processors
|
||||
byte m_usNumLogicCore; // Number op logical processors.
|
||||
byte m_usNumPhysCore; // Number of physical processors
|
||||
|
||||
int64 m_speed; // In cycles per second.
|
||||
int m_size; // structure size
|
||||
char* m_szCPUID; // Processor vendor Identification.
|
||||
int64 m_speed; // In cycles per second.
|
||||
int m_size; // structure size
|
||||
char* m_szCPUID; // Processor vendor Identification.
|
||||
} cpuinfo_t;
|
||||
|
||||
typedef struct register_s
|
||||
|
@ -34,7 +34,7 @@ typedef struct register_s
|
|||
bool retval;
|
||||
} register_t;
|
||||
|
||||
static register_t cpuid(uint function )
|
||||
static register_t cpuid( uint function )
|
||||
{
|
||||
register_t local;
|
||||
|
||||
|
@ -65,7 +65,7 @@ static register_t cpuid(uint function )
|
|||
return local;
|
||||
}
|
||||
|
||||
bool CheckMMXTechnology(void)
|
||||
bool CheckMMXTechnology( void )
|
||||
{
|
||||
register_t mmx = cpuid(1);
|
||||
|
||||
|
@ -73,7 +73,7 @@ bool CheckMMXTechnology(void)
|
|||
return ( mmx.edx & 0x800000 ) != 0;
|
||||
}
|
||||
|
||||
bool CheckSSETechnology(void)
|
||||
bool CheckSSETechnology( void )
|
||||
{
|
||||
register_t sse = cpuid(1);
|
||||
|
||||
|
@ -81,7 +81,7 @@ bool CheckSSETechnology(void)
|
|||
return ( sse.edx & 0x2000000L ) != 0;
|
||||
}
|
||||
|
||||
bool CheckSSE2Technology(void)
|
||||
bool CheckSSE2Technology( void )
|
||||
{
|
||||
register_t sse2 = cpuid(1);
|
||||
|
||||
|
@ -89,7 +89,7 @@ bool CheckSSE2Technology(void)
|
|||
return ( sse2.edx & 0x04000000 ) != 0;
|
||||
}
|
||||
|
||||
bool Check3DNowTechnology(void)
|
||||
bool Check3DNowTechnology( void )
|
||||
{
|
||||
register_t amd = cpuid( 0x80000000 );
|
||||
|
||||
|
@ -103,7 +103,7 @@ bool Check3DNowTechnology(void)
|
|||
return false;
|
||||
}
|
||||
|
||||
bool CheckCMOVTechnology()
|
||||
bool CheckCMOVTechnology( void )
|
||||
{
|
||||
register_t cmov = cpuid(1);
|
||||
|
||||
|
@ -111,7 +111,7 @@ bool CheckCMOVTechnology()
|
|||
return ( cmov.edx & (1<<15) ) != 0;
|
||||
}
|
||||
|
||||
bool CheckFCMOVTechnology(void)
|
||||
bool CheckFCMOVTechnology( void )
|
||||
{
|
||||
register_t fcmov = cpuid(1);
|
||||
|
||||
|
@ -119,7 +119,7 @@ bool CheckFCMOVTechnology(void)
|
|||
return ( fcmov.edx & (1<<16) ) != 0;
|
||||
}
|
||||
|
||||
bool CheckRDTSCTechnology(void)
|
||||
bool CheckRDTSCTechnology( void )
|
||||
{
|
||||
register_t rdtsc = cpuid(1);
|
||||
|
||||
|
@ -132,7 +132,7 @@ bool CheckRDTSCTechnology(void)
|
|||
Return the Processor's vendor identification string, or "Generic_x86" if it doesn't exist on this CPU
|
||||
================
|
||||
*/
|
||||
const char* GetProcessorVendorId()
|
||||
const char* GetProcessorVendorId( void )
|
||||
{
|
||||
static char VendorID[13];
|
||||
register_t vendor = cpuid(0);
|
||||
|
@ -157,7 +157,7 @@ Returns non-zero if Hyper-Threading Technology is supported on the processors an
|
|||
This does not mean that Hyper-Threading Technology is necessarily enabled.
|
||||
================
|
||||
*/
|
||||
static bool HTSupported(void)
|
||||
static bool HTSupported( void )
|
||||
{
|
||||
const uint HT_BIT = 0x10000000; // EDX[28] - Bit 28 set indicates Hyper-Threading Technology is supported in hardware.
|
||||
const uint FAMILY_ID = 0x0f00; // EAX[11:8] - Bit 11 thru 8 contains family processor id
|
||||
|
@ -182,7 +182,7 @@ static bool HTSupported(void)
|
|||
Returns the number of logical processors per physical processors.
|
||||
================
|
||||
*/
|
||||
static byte LogicalProcessorsPerPackage(void)
|
||||
static byte LogicalProcessorsPerPackage( void )
|
||||
{
|
||||
const unsigned NUM_LOGICAL_BITS = 0x00FF0000; // EBX[23:16] indicate number of logical processors per package
|
||||
register_t core = cpuid(1);
|
||||
|
@ -213,7 +213,7 @@ Measure the processor clock speed by sampling the cycle count, waiting
|
|||
for some fraction of a second, then measuring the elapsed number of cycles.
|
||||
================
|
||||
*/
|
||||
static int64 CalculateClockSpeed()
|
||||
static int64 CalculateClockSpeed( void )
|
||||
{
|
||||
LARGE_INTEGER waitTime, startCount, curCount;
|
||||
int scale = 5; // Take 1/32 of a second for the measurement.
|
||||
|
@ -309,10 +309,10 @@ void Sys_InitCPU( void )
|
|||
if( cpu.m_bCMOV ) com_strcat(szFeatureString, "CMOV " );
|
||||
if( cpu.m_bFCMOV ) com_strcat(szFeatureString, "FCMOV " );
|
||||
|
||||
// Remove the trailing space. There will always be one.
|
||||
// remove the trailing space. There will always be one.
|
||||
szFeatureString[com_strlen(szFeatureString)-1] = '\0';
|
||||
|
||||
// Dump CPU information:
|
||||
// dump CPU information:
|
||||
if( cpu.m_usNumLogicCore == 1 ) MsgDev( D_INFO, "CPU: %s [1 core]. Frequency: %.01f %s\n", cpu.m_szCPUID, fFrequency, szFrequencyDenomination );
|
||||
else
|
||||
{
|
||||
|
|
|
@ -0,0 +1,870 @@
|
|||
//=======================================================================
|
||||
// Copyright XashXT Group 2007 ©
|
||||
// network.c - network interface
|
||||
//=======================================================================
|
||||
|
||||
#include <winsock.h>
|
||||
#include "launch.h"
|
||||
|
||||
#define MAX_IPS 16
|
||||
#define PORT_ANY -1
|
||||
#define PORT_SERVER 27960
|
||||
|
||||
// wsock32.dll exports
|
||||
static int (_stdcall *pWSACleanup)( void );
|
||||
static word (_stdcall *pNtohs)( word netshort );
|
||||
static int (_stdcall *pWSAGetLastError)( void );
|
||||
static int (_stdcall *pCloseSocket)( SOCKET s );
|
||||
static word (_stdcall *pHtons)( word hostshort );
|
||||
static dword (_stdcall *pInet_Addr)( const char* cp );
|
||||
static SOCKET (_stdcall *pSocket)( int af, int type, int protocol );
|
||||
static struct hostent *(_stdcall *pGetHostByName)( const char* name );
|
||||
static int (_stdcall *pIoctlSocket)( SOCKET s, long cmd, dword* argp );
|
||||
static int (_stdcall *pWSAStartup)( word wVersionRequired, LPWSADATA lpWSAData );
|
||||
static int (_stdcall *pBind)( SOCKET s, const struct sockaddr* addr, int namelen );
|
||||
static int (_stdcall *pSetSockopt)( SOCKET s, int level, int optname, const char* optval, int optlen );
|
||||
static int (_stdcall *pRecvFrom)( SOCKET s, char* buf, int len, int flags, struct sockaddr* from, int* fromlen );
|
||||
static int (_stdcall *pSendTo)( SOCKET s, const char* buf, int len, int flags, const struct sockaddr* to, int tolen );
|
||||
static int (_stdcall *pSelect)( int nfds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds, const struct timeval* timeout );
|
||||
static int (_stdcall *pConnect)( SOCKET s, const struct sockaddr *name, int namelen );
|
||||
static int (_stdcall *pSend)( SOCKET s, const char *buf, int len, int flags );
|
||||
static int (_stdcall *pRecv)( SOCKET s, char *buf, int len, int flags );
|
||||
static int (_stdcall *pGetHostName)( char *name, int namelen );
|
||||
static dword (_stdcall *pNtohl)( dword netlong );
|
||||
|
||||
static dllfunc_t winsock_funcs[] =
|
||||
{
|
||||
{"bind", (void **) &pBind },
|
||||
{"send", (void **) &pSend },
|
||||
{"recv", (void **) &pRecv },
|
||||
{"ntohs", (void **) &pNtohs },
|
||||
{"htons", (void **) &pHtons },
|
||||
{"ntohl", (void **) &pNtohl },
|
||||
{"socket", (void **) &pSocket },
|
||||
{"select", (void **) &pSelect },
|
||||
{"sendto", (void **) &pSendTo },
|
||||
{"connect", (void **) &pConnect },
|
||||
{"recvfrom", (void **) &pRecvFrom },
|
||||
{"inet_addr", (void **) &pInet_Addr },
|
||||
{"WSAStartup", (void **) &pWSAStartup },
|
||||
{"WSACleanup", (void **) &pWSACleanup },
|
||||
{"setsockopt", (void **) &pSetSockopt },
|
||||
{"ioctlsocket", (void **) &pIoctlSocket },
|
||||
{"closesocket", (void **) &pCloseSocket },
|
||||
{"gethostname", (void **) &pGetHostName },
|
||||
{"gethostbyname", (void **) &pGetHostByName },
|
||||
{"WSAGetLastError", (void **) &pWSAGetLastError },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
dll_info_t winsock_dll = { "wsock32.dll", winsock_funcs, NULL, NULL, NULL, true, 0 };
|
||||
|
||||
static WSADATA winsockdata;
|
||||
static bool winsockInitialized = false;
|
||||
static bool usingSocks = false;
|
||||
static bool networkingEnabled = false;
|
||||
|
||||
static cvar_t *net_socks_enabled;
|
||||
static cvar_t *net_socks_server;
|
||||
static cvar_t *net_socks_port;
|
||||
static cvar_t *net_socks_username;
|
||||
static cvar_t *net_socks_password;
|
||||
static struct sockaddr socksRelayAddr;
|
||||
static SOCKET ip_socket;
|
||||
static SOCKET socks_socket;
|
||||
static char socksBuf[4096];
|
||||
static byte localIP[MAX_IPS][4];
|
||||
static int numIP;
|
||||
|
||||
void NET_OpenWinSock( void )
|
||||
{
|
||||
Sys_LoadLibrary( &winsock_dll );
|
||||
}
|
||||
|
||||
void NET_FreeWinSock( void )
|
||||
{
|
||||
Sys_FreeLibrary( &winsock_dll );
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
NET_ErrorString
|
||||
====================
|
||||
*/
|
||||
char *NET_ErrorString( void )
|
||||
{
|
||||
switch(pWSAGetLastError())
|
||||
{
|
||||
case WSAEINTR: return "WSAEINTR";
|
||||
case WSAEBADF: return "WSAEBADF";
|
||||
case WSAEACCES: return "WSAEACCES";
|
||||
case WSAEDISCON: return "WSAEDISCON";
|
||||
case WSAEFAULT: return "WSAEFAULT";
|
||||
case WSAEINVAL: return "WSAEINVAL";
|
||||
case WSAEMFILE: return "WSAEMFILE";
|
||||
case WSAEWOULDBLOCK: return "WSAEWOULDBLOCK";
|
||||
case WSAEINPROGRESS: return "WSAEINPROGRESS";
|
||||
case WSAEALREADY: return "WSAEALREADY";
|
||||
case WSAENOTSOCK: return "WSAENOTSOCK";
|
||||
case WSAEDESTADDRREQ: return "WSAEDESTADDRREQ";
|
||||
case WSAEMSGSIZE: return "WSAEMSGSIZE";
|
||||
case WSAEPROTOTYPE: return "WSAEPROTOTYPE";
|
||||
case WSAENOPROTOOPT: return "WSAENOPROTOOPT";
|
||||
case WSAEPROTONOSUPPORT: return "WSAEPROTONOSUPPORT";
|
||||
case WSAESOCKTNOSUPPORT: return "WSAESOCKTNOSUPPORT";
|
||||
case WSAEOPNOTSUPP: return "WSAEOPNOTSUPP";
|
||||
case WSAEPFNOSUPPORT: return "WSAEPFNOSUPPORT";
|
||||
case WSAEAFNOSUPPORT: return "WSAEAFNOSUPPORT";
|
||||
case WSAEADDRINUSE: return "WSAEADDRINUSE";
|
||||
case WSAEADDRNOTAVAIL: return "WSAEADDRNOTAVAIL";
|
||||
case WSAENETDOWN: return "WSAENETDOWN";
|
||||
case WSAENETUNREACH: return "WSAENETUNREACH";
|
||||
case WSAENETRESET: return "WSAENETRESET";
|
||||
case WSAECONNABORTED: return "WSWSAECONNABORTEDAEINTR";
|
||||
case WSAECONNRESET: return "WSAECONNRESET";
|
||||
case WSAENOBUFS: return "WSAENOBUFS";
|
||||
case WSAEISCONN: return "WSAEISCONN";
|
||||
case WSAENOTCONN: return "WSAENOTCONN";
|
||||
case WSAESHUTDOWN: return "WSAESHUTDOWN";
|
||||
case WSAETOOMANYREFS: return "WSAETOOMANYREFS";
|
||||
case WSAETIMEDOUT: return "WSAETIMEDOUT";
|
||||
case WSAECONNREFUSED: return "WSAECONNREFUSED";
|
||||
case WSAELOOP: return "WSAELOOP";
|
||||
case WSAENAMETOOLONG: return "WSAENAMETOOLONG";
|
||||
case WSAEHOSTDOWN: return "WSAEHOSTDOWN";
|
||||
case WSASYSNOTREADY: return "WSASYSNOTREADY";
|
||||
case WSAVERNOTSUPPORTED: return "WSAVERNOTSUPPORTED";
|
||||
case WSANOTINITIALISED: return "WSANOTINITIALISED";
|
||||
case WSAHOST_NOT_FOUND: return "WSAHOST_NOT_FOUND";
|
||||
case WSATRY_AGAIN: return "WSATRY_AGAIN";
|
||||
case WSANO_RECOVERY: return "WSANO_RECOVERY";
|
||||
case WSANO_DATA: return "WSANO_DATA";
|
||||
default: return "NO ERROR";
|
||||
}
|
||||
}
|
||||
|
||||
void NetadrToSockadr( netadr_t *a, struct sockaddr *s )
|
||||
{
|
||||
memset( s, 0, sizeof(*s));
|
||||
|
||||
if( a->type == NA_BROADCAST )
|
||||
{
|
||||
((struct sockaddr_in *)s)->sin_family = AF_INET;
|
||||
((struct sockaddr_in *)s)->sin_port = a->port;
|
||||
((struct sockaddr_in *)s)->sin_addr.s_addr = INADDR_BROADCAST;
|
||||
}
|
||||
else if( a->type == NA_IP )
|
||||
{
|
||||
((struct sockaddr_in *)s)->sin_family = AF_INET;
|
||||
((struct sockaddr_in *)s)->sin_addr.s_addr = *(int *)&a->ip;
|
||||
((struct sockaddr_in *)s)->sin_port = a->port;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SockadrToNetadr( struct sockaddr *s, netadr_t *a )
|
||||
{
|
||||
if( s->sa_family == AF_INET )
|
||||
{
|
||||
a->type = NA_IP;
|
||||
*(int *)&a->ip = ((struct sockaddr_in *)s)->sin_addr.s_addr;
|
||||
a->port = ((struct sockaddr_in *)s)->sin_port;
|
||||
}
|
||||
else a->type = NA_NONE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
NET_StringToAdr
|
||||
|
||||
idnewt
|
||||
192.246.40.70
|
||||
=============
|
||||
*/
|
||||
bool NET_StringToSockaddr( const char *s, struct sockaddr *sadr )
|
||||
{
|
||||
struct hostent *h;
|
||||
|
||||
memset( sadr, 0, sizeof( *sadr ) );
|
||||
|
||||
((struct sockaddr_in *)sadr)->sin_family = AF_INET;
|
||||
((struct sockaddr_in *)sadr)->sin_port = 0;
|
||||
|
||||
if( s[0] >= '0' && s[0] <= '9' )
|
||||
{
|
||||
*(int *)&((struct sockaddr_in *)sadr)->sin_addr = pInet_Addr(s);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(( h = pGetHostByName(s)) == 0 )
|
||||
return 0;
|
||||
*(int *)&((struct sockaddr_in *)sadr)->sin_addr = *(int *)h->h_addr_list[0];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
char *NET_AdrToString( netadr_t a )
|
||||
{
|
||||
static char s[64];
|
||||
|
||||
if( a.type == NA_LOOPBACK ) com_sprintf (s, "loopback");
|
||||
else if( a.type == NA_IP )
|
||||
{
|
||||
com_sprintf( s, "%i.%i.%i.%i:%i", a.ip[0], a.ip[1], a.ip[2], a.ip[3], pNtohs(a.port));
|
||||
}
|
||||
else memset( s, 0, sizeof(s));
|
||||
return s;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
NET_StringToAdr
|
||||
|
||||
idnewt
|
||||
192.246.40.70
|
||||
=============
|
||||
*/
|
||||
bool NET_StringToAdr( const char *s, netadr_t *a )
|
||||
{
|
||||
struct sockaddr sadr;
|
||||
|
||||
if( !NET_StringToSockaddr( s, &sadr ))
|
||||
return false;
|
||||
|
||||
SockadrToNetadr( &sadr, a );
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
NET_GetPacket
|
||||
|
||||
Never called by the game logic, just the system event queing
|
||||
==================
|
||||
*/
|
||||
bool NET_GetPacket( netadr_t *net_from, sizebuf_t *net_message )
|
||||
{
|
||||
int ret;
|
||||
struct sockaddr from;
|
||||
int fromlen;
|
||||
int net_socket;
|
||||
int err;
|
||||
|
||||
net_socket = ip_socket;
|
||||
fromlen = sizeof(from);
|
||||
ret = pRecvFrom( ip_socket, net_message->data, net_message->maxsize, 0, (struct sockaddr *)&from, &fromlen );
|
||||
if( ret == SOCKET_ERROR )
|
||||
{
|
||||
err = pWSAGetLastError();
|
||||
if( err == WSAEWOULDBLOCK || err == WSAECONNRESET )
|
||||
return false;
|
||||
MsgDev( D_ERROR, "NET_GetPacket: %s\n", NET_ErrorString());
|
||||
return false;
|
||||
}
|
||||
memset(((struct sockaddr_in *)&from)->sin_zero, 0, 8 );
|
||||
|
||||
if( usingSocks && memcmp( &from, &socksRelayAddr, fromlen ) == 0 )
|
||||
{
|
||||
if( ret < 10 || net_message->data[0] != 0 || net_message->data[1] != 0 || net_message->data[2] != 0 || net_message->data[3] != 1 )
|
||||
return false;
|
||||
net_from->type = NA_IP;
|
||||
net_from->ip[0] = net_message->data[4];
|
||||
net_from->ip[1] = net_message->data[5];
|
||||
net_from->ip[2] = net_message->data[6];
|
||||
net_from->ip[3] = net_message->data[7];
|
||||
net_from->port = *(short *)&net_message->data[8];
|
||||
net_message->readcount = 10;
|
||||
}
|
||||
else
|
||||
{
|
||||
SockadrToNetadr( &from, net_from );
|
||||
net_message->readcount = 0;
|
||||
}
|
||||
if( ret == net_message->maxsize )
|
||||
{
|
||||
MsgDev( D_ERROR, "NET_GetPacket: Oversize packet from %s\n", NET_AdrToString(*net_from));
|
||||
return false;
|
||||
}
|
||||
|
||||
net_message->cursize = ret;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
NET_SendPacket
|
||||
==================
|
||||
*/
|
||||
void NET_SendPacket( int length, const void *data, netadr_t to )
|
||||
{
|
||||
int ret;
|
||||
struct sockaddr addr;
|
||||
SOCKET net_socket;
|
||||
|
||||
switch( to.type )
|
||||
{
|
||||
case NA_IP:
|
||||
case NA_BROADCAST:
|
||||
net_socket = ip_socket;
|
||||
default:
|
||||
MsgDev( D_ERROR, "NET_SendPacket: bad address type\n");
|
||||
return;
|
||||
}
|
||||
|
||||
NetadrToSockadr( &to, &addr );
|
||||
if( usingSocks && to.type == NA_IP )
|
||||
{
|
||||
socksBuf[0] = 0; // reserved
|
||||
socksBuf[1] = 0; // reserved
|
||||
socksBuf[2] = 0; // fragment ( not fragmented )
|
||||
socksBuf[3] = 1; // address type: IPV4
|
||||
*(int *)&socksBuf[4] = ((struct sockaddr_in *)&addr)->sin_addr.s_addr;
|
||||
*(short *)&socksBuf[8] = ((struct sockaddr_in *)&addr)->sin_port;
|
||||
Mem_Copy( &socksBuf[10], data, length );
|
||||
ret = pSendTo( net_socket, socksBuf, length + 10, 0, &socksRelayAddr, sizeof(socksRelayAddr));
|
||||
}
|
||||
else ret = pSendTo( net_socket, data, length, 0, &addr, sizeof(addr));
|
||||
|
||||
if( ret == SOCKET_ERROR )
|
||||
{
|
||||
int err = pWSAGetLastError();
|
||||
|
||||
// wouldblock is silent
|
||||
if( err == WSAEWOULDBLOCK ) return;
|
||||
|
||||
// some PPP links do not allow broadcasts and return an error
|
||||
if( err == WSAEADDRNOTAVAIL && to.type == NA_BROADCAST )
|
||||
return;
|
||||
MsgDev( D_ERROR, "NET_SendPacket: %s\n", NET_ErrorString());
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
NET_IsLANAddress
|
||||
|
||||
LAN clients will have their rate var ignored
|
||||
==================
|
||||
*/
|
||||
bool NET_IsLANAddress( netadr_t adr )
|
||||
{
|
||||
int i;
|
||||
|
||||
if( adr.type == NA_LOOPBACK )
|
||||
return true;
|
||||
|
||||
if( adr.type != NA_IP )
|
||||
return false;
|
||||
|
||||
// choose which comparison to use based on the class of the address being tested
|
||||
// any local adresses of a different class than the address being tested will fail based on the first byte
|
||||
if( adr.ip[0] == 127 && adr.ip[1] == 0 && adr.ip[2] == 0 && adr.ip[3] == 1 )
|
||||
return true;
|
||||
|
||||
// class A
|
||||
if(( adr.ip[0] & 0x80) == 0x00 )
|
||||
{
|
||||
for( i = 0; i < numIP; i++ )
|
||||
{
|
||||
if( adr.ip[0] == localIP[i][0] )
|
||||
return true;
|
||||
}
|
||||
// the RFC1918 class a block will pass the above test
|
||||
return false;
|
||||
}
|
||||
|
||||
// class B
|
||||
if(( adr.ip[0] & 0xc0) == 0x80 )
|
||||
{
|
||||
for( i = 0; i < numIP; i++ )
|
||||
{
|
||||
if( adr.ip[0] == localIP[i][0] && adr.ip[1] == localIP[i][1] )
|
||||
return true;
|
||||
// also check against the RFC1918 class b blocks
|
||||
if( adr.ip[0] == 172 && localIP[i][0] == 172 && (adr.ip[1] & 0xf0) == 16 && (localIP[i][1] & 0xf0) == 16 )
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// class C
|
||||
for( i = 0; i < numIP; i++ )
|
||||
{
|
||||
if( adr.ip[0] == localIP[i][0] && adr.ip[1] == localIP[i][1] && adr.ip[2] == localIP[i][2] )
|
||||
return true;
|
||||
// also check against the RFC1918 class c blocks
|
||||
if( adr.ip[0] == 192 && localIP[i][0] == 192 && adr.ip[1] == 168 && localIP[i][1] == 168 )
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
NET_ShowIP
|
||||
==================
|
||||
*/
|
||||
void NET_ShowIP( void )
|
||||
{
|
||||
int i;
|
||||
|
||||
for( i = 0; i < numIP; i++ )
|
||||
{
|
||||
Msg( "IP: %i.%i.%i.%i\n", localIP[i][0], localIP[i][1], localIP[i][2], localIP[i][3] );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
NET_IPSocket
|
||||
====================
|
||||
*/
|
||||
int NET_IPSocket( char *net_interface, int port )
|
||||
{
|
||||
SOCKET newsocket;
|
||||
struct sockaddr_in address;
|
||||
bool _true = true;
|
||||
int i = 1;
|
||||
int err;
|
||||
|
||||
if( net_interface ) MsgDev( D_INFO, "Opening IP socket: %s:%i\n", net_interface, port );
|
||||
else MsgDev( D_INFO, "Opening IP socket: localhost:%i\n", port );
|
||||
|
||||
if(( newsocket = pSocket( AF_INET, SOCK_DGRAM, IPPROTO_UDP )) == INVALID_SOCKET )
|
||||
{
|
||||
err = pWSAGetLastError();
|
||||
if( err != WSAEAFNOSUPPORT )
|
||||
MsgDev( D_WARN, "NET_IPSocket: socket: %s\n", NET_ErrorString());
|
||||
return 0;
|
||||
}
|
||||
// make it non-blocking
|
||||
if( pIoctlSocket( newsocket, FIONBIO, &_true ) == SOCKET_ERROR )
|
||||
{
|
||||
MsgDev( D_WARN, "NET_IPSocket: ioctl FIONBIO: %s\n", NET_ErrorString());
|
||||
return 0;
|
||||
}
|
||||
|
||||
// make it broadcast capable
|
||||
if( pSetSockopt( newsocket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i) ) == SOCKET_ERROR )
|
||||
{
|
||||
MsgDev( D_WARN, "NET_IPSocket: setsockopt SO_BROADCAST: %s\n", NET_ErrorString());
|
||||
return 0;
|
||||
}
|
||||
|
||||
if( !net_interface || !net_interface[0] || !com_stricmp( net_interface, "localhost"))
|
||||
address.sin_addr.s_addr = INADDR_ANY;
|
||||
else NET_StringToSockaddr( net_interface, (struct sockaddr *)&address );
|
||||
|
||||
if( port == PORT_ANY ) address.sin_port = 0;
|
||||
else address.sin_port = pHtons((short)port);
|
||||
address.sin_family = AF_INET;
|
||||
|
||||
if( pBind( newsocket, (void *)&address, sizeof(address) ) == SOCKET_ERROR )
|
||||
{
|
||||
MsgDev( D_WARN, "UDP_OpenSocket: bind: %s\n", NET_ErrorString());
|
||||
pCloseSocket( newsocket );
|
||||
return 0;
|
||||
}
|
||||
return newsocket;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
====================
|
||||
NET_OpenSocks
|
||||
====================
|
||||
*/
|
||||
void NET_OpenSocks( int port )
|
||||
{
|
||||
struct sockaddr_in address;
|
||||
bool rfc1929 = false;
|
||||
int err;
|
||||
struct hostent *h;
|
||||
int len;
|
||||
byte buf[64];
|
||||
|
||||
usingSocks = false;
|
||||
|
||||
MsgDev( D_INFO, "Opening connection to SOCKS server.\n" );
|
||||
|
||||
if(( socks_socket = pSocket( AF_INET, SOCK_STREAM, IPPROTO_TCP )) == INVALID_SOCKET )
|
||||
{
|
||||
err = pWSAGetLastError();
|
||||
MsgDev( D_WARN, "NET_OpenSocks: socket: %s\n", NET_ErrorString());
|
||||
return;
|
||||
}
|
||||
|
||||
h = pGetHostByName( net_socks_server->string );
|
||||
if( h == NULL )
|
||||
{
|
||||
err = pWSAGetLastError();
|
||||
MsgDev( D_WARN, "NET_OpenSocks: gethostbyname: %s\n", NET_ErrorString());
|
||||
return;
|
||||
}
|
||||
if( h->h_addrtype != AF_INET )
|
||||
{
|
||||
MsgDev( D_WARN, "NET_OpenSocks: gethostbyname: address type was not AF_INET\n");
|
||||
return;
|
||||
}
|
||||
|
||||
address.sin_family = AF_INET;
|
||||
address.sin_addr.s_addr = *(int *)h->h_addr_list[0];
|
||||
address.sin_port = pHtons( (short)net_socks_port->integer );
|
||||
|
||||
if( pConnect( socks_socket, (struct sockaddr *)&address, sizeof( address )) == SOCKET_ERROR )
|
||||
{
|
||||
err = pWSAGetLastError();
|
||||
MsgDev( D_WARN, "NET_OpenSocks: connect: %s\n", NET_ErrorString());
|
||||
return;
|
||||
}
|
||||
|
||||
// send socks authentication handshake
|
||||
if( *net_socks_username->string || *net_socks_password->string )
|
||||
rfc1929 = true;
|
||||
|
||||
buf[0] = 5; // SOCKS version
|
||||
|
||||
// method count
|
||||
if( rfc1929 )
|
||||
{
|
||||
buf[1] = 2;
|
||||
len = 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
buf[1] = 1;
|
||||
len = 3;
|
||||
}
|
||||
buf[2] = 0; // method #1 - method id #00: no authentication
|
||||
if( rfc1929 ) buf[2] = 2; // method #2 - method id #02: username/password
|
||||
|
||||
if( pSend( socks_socket, buf, len, 0 ) == SOCKET_ERROR )
|
||||
{
|
||||
err = pWSAGetLastError();
|
||||
MsgDev( D_WARN, "NET_OpenSocks: send: %s\n", NET_ErrorString());
|
||||
return;
|
||||
}
|
||||
|
||||
// get the response
|
||||
len = pRecv( socks_socket, buf, 64, 0 );
|
||||
if( len == SOCKET_ERROR )
|
||||
{
|
||||
err = pWSAGetLastError();
|
||||
MsgDev( D_WARN, "NET_OpenSocks: recv: %s\n", NET_ErrorString());
|
||||
return;
|
||||
}
|
||||
if( len != 2 || buf[0] != 5 )
|
||||
{
|
||||
MsgDev( D_WARN, "NET_OpenSocks: bad response\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
switch( buf[1] )
|
||||
{
|
||||
case 0: // no authentication
|
||||
case 2: // username/password authentication
|
||||
break;
|
||||
default:
|
||||
MsgDev( D_WARN, "NET_OpenSocks: request denied\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
// do username/password authentication if needed
|
||||
if( buf[1] == 2 )
|
||||
{
|
||||
int ulen, plen;
|
||||
|
||||
// build the request
|
||||
ulen = com_strlen( net_socks_username->string );
|
||||
plen = com_strlen( net_socks_password->string );
|
||||
|
||||
buf[0] = 1; // username/password authentication version
|
||||
buf[1] = ulen;
|
||||
if( ulen ) Mem_Copy( &buf[2], net_socks_username->string, ulen );
|
||||
buf[2 + ulen] = plen;
|
||||
if( plen ) Mem_Copy( &buf[3 + ulen], net_socks_password->string, plen );
|
||||
|
||||
// send it
|
||||
if( pSend( socks_socket, buf, 3 + ulen + plen, 0 ) == SOCKET_ERROR )
|
||||
{
|
||||
err = pWSAGetLastError();
|
||||
MsgDev( D_WARN, "NET_OpenSocks: send: %s\n", NET_ErrorString());
|
||||
return;
|
||||
}
|
||||
|
||||
// get the response
|
||||
len = pRecv( socks_socket, buf, 64, 0 );
|
||||
if( len == SOCKET_ERROR )
|
||||
{
|
||||
err = pWSAGetLastError();
|
||||
MsgDev( D_WARN, "NET_OpenSocks: recv: %s\n", NET_ErrorString());
|
||||
return;
|
||||
}
|
||||
if( len != 2 || buf[0] != 1 )
|
||||
{
|
||||
MsgDev( D_WARN, "NET_OpenSocks: bad response\n" );
|
||||
return;
|
||||
}
|
||||
if( buf[1] != 0 )
|
||||
{
|
||||
MsgDev( D_WARN, "NET_OpenSocks: authentication failed\n" );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// send the UDP associate request
|
||||
buf[0] = 5; // SOCKS version
|
||||
buf[1] = 3; // command: UDP associate
|
||||
buf[2] = 0; // reserved
|
||||
buf[3] = 1; // address type: IPV4
|
||||
*(int *)&buf[4] = INADDR_ANY;
|
||||
*(short *)&buf[8] = pHtons((short)port); // port
|
||||
|
||||
if( pSend( socks_socket, buf, 10, 0 ) == SOCKET_ERROR )
|
||||
{
|
||||
err = pWSAGetLastError();
|
||||
MsgDev( D_WARN, "NET_OpenSocks: send: %s\n", NET_ErrorString());
|
||||
return;
|
||||
}
|
||||
|
||||
// get the response
|
||||
len = pRecv( socks_socket, buf, 64, 0 );
|
||||
if( len == SOCKET_ERROR )
|
||||
{
|
||||
err = pWSAGetLastError();
|
||||
MsgDev( D_WARN, "NET_OpenSocks: recv: %s\n", NET_ErrorString());
|
||||
return;
|
||||
}
|
||||
if( len < 2 || buf[0] != 5 )
|
||||
{
|
||||
MsgDev( D_WARN, "NET_OpenSocks: bad response\n" );
|
||||
return;
|
||||
}
|
||||
// check completion code
|
||||
if( buf[1] != 0 )
|
||||
{
|
||||
MsgDev( D_WARN, "NET_OpenSocks: request denied: %i\n", buf[1] );
|
||||
return;
|
||||
}
|
||||
if( buf[3] != 1 )
|
||||
{
|
||||
MsgDev( D_WARN, "NET_OpenSocks: relay address is not IPV4: %i\n", buf[3] );
|
||||
return;
|
||||
}
|
||||
((struct sockaddr_in *)&socksRelayAddr)->sin_family = AF_INET;
|
||||
((struct sockaddr_in *)&socksRelayAddr)->sin_addr.s_addr = *(int *)&buf[4];
|
||||
((struct sockaddr_in *)&socksRelayAddr)->sin_port = *(short *)&buf[8];
|
||||
memset(((struct sockaddr_in *)&socksRelayAddr)->sin_zero, 0, 8 );
|
||||
usingSocks = true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=====================
|
||||
NET_GetLocalAddress
|
||||
=====================
|
||||
*/
|
||||
void NET_GetLocalAddress( void )
|
||||
{
|
||||
string hostname;
|
||||
int error, ip, i = 0;
|
||||
struct hostent *hostInfo;
|
||||
char *p;
|
||||
|
||||
if( pGetHostName( hostname, MAX_STRING ) == SOCKET_ERROR )
|
||||
{
|
||||
error = pWSAGetLastError();
|
||||
return;
|
||||
}
|
||||
|
||||
hostInfo = pGetHostByName( hostname );
|
||||
if( !hostInfo )
|
||||
{
|
||||
error = pWSAGetLastError();
|
||||
return;
|
||||
}
|
||||
|
||||
MsgDev( D_INFO, "Hostname: %s\n", hostInfo->h_name );
|
||||
while(( p = hostInfo->h_aliases[i++] ) != NULL )
|
||||
MsgDev( D_INFO, "Alias: %s\n", p );
|
||||
|
||||
if( hostInfo->h_addrtype != AF_INET )
|
||||
return;
|
||||
|
||||
numIP = 0;
|
||||
while(( p = hostInfo->h_addr_list[numIP] ) != NULL && numIP < MAX_IPS )
|
||||
{
|
||||
ip = pNtohl( *(int *)p);
|
||||
localIP[ numIP ][0] = p[0];
|
||||
localIP[ numIP ][1] = p[1];
|
||||
localIP[ numIP ][2] = p[2];
|
||||
localIP[ numIP ][3] = p[3];
|
||||
MsgDev( D_INFO, "IP: %i.%i.%i.%i\n", (ip>>24) & 0xff, (ip>>16) & 0xff, (ip>>8) & 0xff, ip & 0xff );
|
||||
numIP++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
NET_OpenIP
|
||||
====================
|
||||
*/
|
||||
void NET_OpenIP( void )
|
||||
{
|
||||
cvar_t *ip;
|
||||
int i, port;
|
||||
|
||||
ip = Cvar_Get( "net_ip", "localhost", CVAR_LATCH, "network ip address" );
|
||||
port = Cvar_Get( "net_port", va( "%i", PORT_SERVER ), CVAR_LATCH, "network default port" )->integer;
|
||||
|
||||
// automatically scan for a valid port, so multiple
|
||||
// dedicated servers can be started without requiring
|
||||
// a different net_port for each one
|
||||
for( i = 0; i < 10; i++ )
|
||||
{
|
||||
ip_socket = NET_IPSocket( ip->string, port + i );
|
||||
if( ip_socket )
|
||||
{
|
||||
Cvar_SetValue( "net_port", port + i );
|
||||
if( net_socks_enabled->integer )
|
||||
NET_OpenSocks( port + i );
|
||||
NET_GetLocalAddress();
|
||||
return;
|
||||
}
|
||||
}
|
||||
MsgDev( D_WARN, "Couldn't allocate IP port\n" );
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
NET_GetCvars
|
||||
====================
|
||||
*/
|
||||
static bool NET_GetCvars( void )
|
||||
{
|
||||
bool modified = false;
|
||||
|
||||
if( net_socks_enabled && net_socks_enabled->modified )
|
||||
modified = true;
|
||||
net_socks_enabled = Cvar_Get( "net_socksenabled", "0", CVAR_LATCH|CVAR_ARCHIVE, "network using socks" );
|
||||
|
||||
if( net_socks_server && net_socks_server->modified )
|
||||
modified = true;
|
||||
net_socks_server = Cvar_Get( "net_socksserver", "", CVAR_LATCH|CVAR_ARCHIVE, "network server socket" );
|
||||
|
||||
if( net_socks_port && net_socks_port->modified )
|
||||
modified = true;
|
||||
net_socks_port = Cvar_Get( "net_socksport", "1080", CVAR_LATCH|CVAR_ARCHIVE, "using socks port" );
|
||||
|
||||
if( net_socks_username && net_socks_username->modified )
|
||||
modified = true;
|
||||
net_socks_username = Cvar_Get( "net_socksusername", "", CVAR_LATCH|CVAR_ARCHIVE, "autorization login" );
|
||||
|
||||
if( net_socks_password && net_socks_password->modified )
|
||||
modified = true;
|
||||
net_socks_password = Cvar_Get( "net_sockspassword", "", CVAR_LATCH|CVAR_ARCHIVE, "autorization password" );
|
||||
|
||||
return modified;
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
NET_Config
|
||||
====================
|
||||
*/
|
||||
void NET_Config( bool net_enable )
|
||||
{
|
||||
bool modified, start, stop;
|
||||
|
||||
// get any latched changes to cvars
|
||||
modified = NET_GetCvars();
|
||||
|
||||
// if enable state is the same and no cvars were modified, we have nothing to do
|
||||
if( net_enable == networkingEnabled && !modified )
|
||||
return;
|
||||
|
||||
if( net_enable == networkingEnabled )
|
||||
{
|
||||
if( net_enable )
|
||||
{
|
||||
stop = true;
|
||||
start = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
stop = false;
|
||||
start = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( net_enable )
|
||||
{
|
||||
stop = false;
|
||||
start = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
stop = true;
|
||||
start = false;
|
||||
}
|
||||
networkingEnabled = net_enable;
|
||||
}
|
||||
|
||||
if( stop )
|
||||
{
|
||||
if( ip_socket && ip_socket != INVALID_SOCKET )
|
||||
{
|
||||
pCloseSocket( ip_socket );
|
||||
ip_socket = 0;
|
||||
}
|
||||
|
||||
if( socks_socket && socks_socket != INVALID_SOCKET )
|
||||
{
|
||||
pCloseSocket( socks_socket );
|
||||
socks_socket = 0;
|
||||
}
|
||||
}
|
||||
if( start ) NET_OpenIP();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
====================
|
||||
NET_Init
|
||||
====================
|
||||
*/
|
||||
void NET_Init( void )
|
||||
{
|
||||
int r;
|
||||
|
||||
NET_OpenWinSock(); // loading wsock32.dll
|
||||
r = pWSAStartup(MAKEWORD( 1, 1 ), &winsockdata );
|
||||
if( r )
|
||||
{
|
||||
MsgDev( D_WARN, "NET_Init: winsock initialization failed: %d\n", r );
|
||||
return;
|
||||
}
|
||||
|
||||
winsockInitialized = true;
|
||||
MsgDev( D_NOTE, "NET_Init: suceeded\n" );
|
||||
NET_GetCvars(); // register cvars
|
||||
NET_Config( true ); // FIXME: testing!
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
====================
|
||||
NET_Shutdown
|
||||
====================
|
||||
*/
|
||||
void NET_Shutdown( void )
|
||||
{
|
||||
if( !winsockInitialized )
|
||||
return;
|
||||
NET_Config( false );
|
||||
pWSACleanup();
|
||||
NET_FreeWinSock();
|
||||
winsockInitialized = false;
|
||||
}
|
|
@ -6,9 +6,14 @@
|
|||
#include "launch.h"
|
||||
#include "mathlib.h"
|
||||
|
||||
#define MAX_QUED_EVENTS 256
|
||||
#define MASK_QUED_EVENTS (MAX_QUED_EVENTS - 1)
|
||||
|
||||
system_t Sys;
|
||||
stdlib_api_t com;
|
||||
launch_exp_t *Host; // callback to mainframe
|
||||
sys_event_t event_que[MAX_QUED_EVENTS];
|
||||
int event_head, event_tail;
|
||||
FILE *logfile;
|
||||
|
||||
dll_info_t common_dll = { "common.dll", NULL, "CreateAPI", NULL, NULL, true, sizeof(launch_exp_t) };
|
||||
|
@ -16,7 +21,7 @@ dll_info_t engine_dll = { "engine.dll", NULL, "CreateAPI", NULL, NULL, true, siz
|
|||
dll_info_t viewer_dll = { "viewer.dll", NULL, "CreateAPI", NULL, NULL, true, sizeof(launch_exp_t) };
|
||||
dll_info_t ripper_dll = { "ripper.dll", NULL, "CreateAPI", NULL, NULL, true, sizeof(launch_exp_t) };
|
||||
|
||||
static const char *show_credits = "\n\n\n\n\tCopyright XashXT Group 2007 ©\n\t\
|
||||
static const char *show_credits = "\n\n\n\n\tCopyright XashXT Group 2008 ©\n\t\
|
||||
All Rights Reserved\n\n\t Visit www.xash.ru\n";
|
||||
|
||||
// stubs
|
||||
|
@ -39,6 +44,8 @@ void Sys_GetStdAPI( void )
|
|||
com.input = Sys_Input;
|
||||
com.sleep = Sys_Sleep;
|
||||
com.clipboard = Sys_GetClipboardData;
|
||||
com.queevent = Sys_QueEvent; // new system event
|
||||
com.getevent = Sys_GetEvent; // get system events
|
||||
com.keyevents = Sys_SendKeyEvents;
|
||||
|
||||
// crclib.c funcs
|
||||
|
@ -66,6 +73,17 @@ void Sys_GetStdAPI( void )
|
|||
com.getelement = _mem_get_array_element;
|
||||
com.arraysize = _mem_array_size;
|
||||
|
||||
// network.c funcs
|
||||
com.NET_Init = NET_Init;
|
||||
com.NET_Shutdown = NET_Shutdown;
|
||||
com.NET_ShowIP = NET_ShowIP;
|
||||
com.NET_Config = NET_Config;
|
||||
com.NET_AdrToString = NET_AdrToString;
|
||||
com.NET_IsLANAddress = NET_IsLANAddress;
|
||||
com.NET_StringToAdr = NET_StringToAdr;
|
||||
com.NET_RecvPacket = NET_GetPacket;
|
||||
com.NET_SendPacket = NET_SendPacket;
|
||||
|
||||
// common functions
|
||||
com.Com_InitRootDir = FS_InitRootDir; // init custom rootdir
|
||||
com.Com_LoadGameInfo = FS_LoadGameInfo; // gate game info from script file
|
||||
|
@ -404,6 +422,7 @@ void Sys_CreateInstance( void )
|
|||
Sys.Free = Host->Free;
|
||||
Sys.CPrint = Host->CPrint;
|
||||
Sys.Cmd = Host->Cmd;
|
||||
Sys.SZ_Init = Host->SZInit;
|
||||
break;
|
||||
case HOST_CREDITS:
|
||||
Sys_Break( show_credits );
|
||||
|
@ -684,7 +703,7 @@ double Sys_DoubleTime( void )
|
|||
|
||||
if( firsttimegettime )
|
||||
{
|
||||
timeBeginPeriod (1);
|
||||
timeBeginPeriod( 1 );
|
||||
firsttimegettime = false;
|
||||
}
|
||||
newtime = ( double )timeGetTime() * 0.001;
|
||||
|
@ -757,6 +776,25 @@ char *Sys_GetClipboardData( void )
|
|||
return data;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
Sys_GetCurrentUser
|
||||
|
||||
returns username for current profile
|
||||
================
|
||||
*/
|
||||
char *Sys_GetCurrentUser( void )
|
||||
{
|
||||
static string s_userName;
|
||||
dword size = sizeof( s_userName );
|
||||
|
||||
if( !GetUserName( s_userName, &size ))
|
||||
com_strcpy( s_userName, "player" );
|
||||
if( !s_userName[0] )
|
||||
com_strcpy( s_userName, "player" );
|
||||
|
||||
return s_userName;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
|
@ -1197,6 +1235,118 @@ void Sys_RunThreadsOn( int workcnt, bool showpacifier, void(*func)(int))
|
|||
if( pacifier ) Msg(" Done [%.2f sec]\n", end - start);
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
Sys_QueEvent
|
||||
|
||||
A time of 0 will get the current time
|
||||
Ptr should either be null, or point to a block of data that can
|
||||
be freed by the game later.
|
||||
================
|
||||
*/
|
||||
void Sys_QueEvent( dword time, ev_type_t type, int value, int value2, int length, void *ptr )
|
||||
{
|
||||
sys_event_t *ev;
|
||||
|
||||
ev = &event_que[event_head & MASK_QUED_EVENTS];
|
||||
if( event_head - event_tail >= MAX_QUED_EVENTS )
|
||||
{
|
||||
MsgDev( D_ERROR, "Sys_QueEvent: overflow\n");
|
||||
// make sure what memory is allocated by engine
|
||||
if(Mem_IsAllocated( ev->data )) Mem_Free( ev->data );
|
||||
event_tail++;
|
||||
}
|
||||
event_head++;
|
||||
|
||||
// presets
|
||||
if( time == 0 ) time = Sys_Milliseconds();
|
||||
else if( time == -1 ) time = Sys.msg_time;
|
||||
|
||||
ev->time = time;
|
||||
ev->type = type;
|
||||
ev->value[0] = value;
|
||||
ev->value[1] = value2;
|
||||
ev->length = length;
|
||||
ev->data = ptr;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
Sys_GetEvent
|
||||
|
||||
================
|
||||
*/
|
||||
sys_event_t Sys_GetEvent( void )
|
||||
{
|
||||
MSG msg;
|
||||
sys_event_t ev;
|
||||
char *s;
|
||||
sizebuf_t netmsg;
|
||||
netadr_t adr;
|
||||
|
||||
// return if we have data
|
||||
if( event_head > event_tail )
|
||||
{
|
||||
event_tail++;
|
||||
return event_que[(event_tail-1) & MASK_QUED_EVENTS];
|
||||
}
|
||||
|
||||
// pump the message loop
|
||||
while( PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ))
|
||||
{
|
||||
if(!GetMessage( &msg, NULL, 0, 0))
|
||||
{
|
||||
Sys.error = true;
|
||||
Sys_Exit();
|
||||
}
|
||||
Sys.msg_time = msg.time;
|
||||
TranslateMessage(&msg );
|
||||
DispatchMessage( &msg );
|
||||
}
|
||||
|
||||
// check for console commands
|
||||
s = Sys_Input();
|
||||
if( s )
|
||||
{
|
||||
char *b;
|
||||
int len;
|
||||
|
||||
len = com_strlen( s ) + 1;
|
||||
b = Malloc( len );
|
||||
com_strncpy( b, s, len - 1 );
|
||||
Sys_QueEvent( 0, SE_CONSOLE, 0, 0, len, b );
|
||||
}
|
||||
|
||||
// check for network packets
|
||||
if( Sys.SZ_Init ) Sys.SZ_Init( &netmsg, Sys.packet_received, sizeof( Sys.packet_received ));
|
||||
if( NET_GetPacket( &adr, &netmsg ))
|
||||
{
|
||||
netadr_t *buf;
|
||||
int len;
|
||||
|
||||
// copy out to a seperate buffer for qeueing
|
||||
// the readcount stepahead is for SOCKS support
|
||||
len = sizeof(netadr_t) + netmsg.cursize - netmsg.readcount;
|
||||
buf = Malloc( len );
|
||||
*buf = adr;
|
||||
Mem_Copy( buf + 1, &netmsg.data[netmsg.readcount], netmsg.cursize - netmsg.readcount );
|
||||
Sys_QueEvent( 0, SE_PACKET, 0, 0, len, buf );
|
||||
}
|
||||
|
||||
// return if we have data
|
||||
if( event_head > event_tail )
|
||||
{
|
||||
event_tail++;
|
||||
return event_que[(event_tail - 1) & MASK_QUED_EVENTS];
|
||||
}
|
||||
|
||||
// create an empty event to return
|
||||
memset( &ev, 0, sizeof(ev));
|
||||
ev.time = timeGetTime();
|
||||
|
||||
return ev;
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
// REGISTRY COMMON TOOLS
|
||||
//=======================================================================
|
||||
|
|
|
@ -144,6 +144,10 @@ SOURCE=.\common\memlib.c
|
|||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\common\network.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\common\parselib.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
|
|
@ -45,6 +45,8 @@ typedef struct system_s
|
|||
char log_path[MAX_SYSPATH];
|
||||
bool hooked_out;
|
||||
bool stuffcmdsrun;
|
||||
byte packet_received[MAX_MSGLEN]; // network data
|
||||
uint msg_time; // GetMessage time
|
||||
|
||||
HINSTANCE hInstance;
|
||||
LPTOP_LEVEL_EXCEPTION_FILTER oldFilter;
|
||||
|
@ -70,7 +72,8 @@ typedef struct system_s
|
|||
void ( *Main ) ( void ); // host frame
|
||||
void ( *Free ) ( void ); // close host
|
||||
void ( *Cmd ) ( void ); // cmd forward to server
|
||||
void (*CPrint)( const char *msg ); // console print
|
||||
void (*CPrint) ( const char *msg ); // console print
|
||||
void (*SZ_Init)( sizebuf_t *buf, byte *data, size_t length );
|
||||
} system_t;
|
||||
|
||||
typedef struct cvar_s
|
||||
|
@ -117,6 +120,7 @@ void Sys_LookupInstance( void );
|
|||
double Sys_DoubleTime( void );
|
||||
dword Sys_Milliseconds( void );
|
||||
char *Sys_GetClipboardData( void );
|
||||
char *Sys_GetCurrentUser( void );
|
||||
void Sys_Sleep( int msec );
|
||||
void Sys_Init( void );
|
||||
void Sys_Exit( void );
|
||||
|
@ -133,6 +137,8 @@ void Sys_PrintLog( const char *pMsg );
|
|||
void Sys_Print(const char *pMsg);
|
||||
void Sys_Msg( const char *pMsg, ... );
|
||||
void Sys_MsgDev( int level, const char *pMsg, ... );
|
||||
sys_event_t Sys_GetEvent( void );
|
||||
void Sys_QueEvent( dword time, ev_type_t type, int value, int value2, int length, void *ptr );
|
||||
int Sys_GetThreadWork( void );
|
||||
void Sys_ThreadWorkerFunction (int threadnum);
|
||||
void Sys_ThreadSetDefault (void);
|
||||
|
@ -149,6 +155,19 @@ void Sys_RunThreadsOn (int workcnt, bool showpacifier, void(*func)(int));
|
|||
bool REG_GetValue( HKEY hKey, const char *SubKey, const char *Value, char *pBuffer);
|
||||
bool REG_SetValue( HKEY hKey, const char *SubKey, const char *Value, char *pBuffer);
|
||||
|
||||
//
|
||||
// network.c
|
||||
//
|
||||
void NET_Init( void );
|
||||
void NET_Shutdown( void );
|
||||
void NET_ShowIP( void ); // just for debug
|
||||
void NET_Config( bool net_enable );
|
||||
char *NET_AdrToString( netadr_t a );
|
||||
bool NET_IsLANAddress( netadr_t adr );
|
||||
bool NET_StringToAdr( const char *s, netadr_t *a );
|
||||
bool NET_GetPacket( netadr_t *net_from, sizebuf_t *net_message );
|
||||
void NET_SendPacket( int length, const void *data, netadr_t to );
|
||||
|
||||
//
|
||||
// stdlib.c
|
||||
//
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#define MAX_STRING_TOKENS 80
|
||||
#define MAX_TOKEN_CHARS 128
|
||||
#define MAX_STRING_CHARS 1024
|
||||
#define MAX_MSGLEN 16384 // max length of a message, which may be fragmented into multiple packets
|
||||
|
||||
#define COLOR_BLACK '0'
|
||||
#define COLOR_RED '1'
|
||||
|
@ -162,6 +163,47 @@ enum host_state
|
|||
HOST_NULL, // terminator
|
||||
};
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SE_NONE = 0, // ev.time is still valid
|
||||
SE_KEY, // ev.value is a key code, ev.value2 is the down flag
|
||||
SE_CHAR, // ev.value is an ascii char
|
||||
SE_MOUSE, // ev.value and ev.value2 are reletive signed x / y moves
|
||||
SE_CONSOLE, // ev.data is a char*
|
||||
SE_PACKET // ev.data is a netadr_t followed by data bytes to ev.length
|
||||
} ev_type_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
dword time;
|
||||
ev_type_t type;
|
||||
int value[2];
|
||||
void *data;
|
||||
size_t length;
|
||||
} sys_event_t;
|
||||
|
||||
typedef enum { NA_NONE, NA_LOOPBACK, NA_BROADCAST, NA_IP } netadrtype_t;
|
||||
typedef enum { NS_CLIENT, NS_SERVER } netsrc_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
netadrtype_t type;
|
||||
byte ip[4];
|
||||
word port;
|
||||
} netadr_t;
|
||||
|
||||
typedef struct sizebuf_s
|
||||
{
|
||||
bool overflowed; // set to true if the buffer size failed
|
||||
|
||||
byte *data;
|
||||
int maxsize;
|
||||
int cursize;
|
||||
int readcount;
|
||||
int errorcount; // cause by errors
|
||||
int bit; // for bitwise reads and writes
|
||||
} sizebuf_t;
|
||||
|
||||
enum dev_level
|
||||
{
|
||||
D_INFO = 1, // "-dev 1", shows various system messages
|
||||
|
|
|
@ -60,9 +60,9 @@
|
|||
|
||||
// button bits
|
||||
#define BUTTON_ATTACK 1
|
||||
#define BUTTON_USE 2
|
||||
#define BUTTON_ATTACK2 4
|
||||
#define BUTTONS_ATTACK (BUTTON_ATTACK | BUTTON_ATTACK2)
|
||||
#define BUTTON_ATTACK2 2
|
||||
#define BUTTON_USE 4
|
||||
#define BUTTON_WALKING 8
|
||||
#define BUTTON_ANY 128 // any key whatsoever
|
||||
|
||||
#define PM_MAXTOUCH 32
|
||||
|
@ -268,12 +268,17 @@ typedef struct player_state_s
|
|||
// user_cmd_t communication
|
||||
typedef struct usercmd_s
|
||||
{
|
||||
byte msec;
|
||||
byte buttons;
|
||||
short angles[3];
|
||||
byte impulse; // remove?
|
||||
int buttons;
|
||||
int angles[3];
|
||||
int servertime;
|
||||
byte impulse;
|
||||
signed char forwardmove;
|
||||
signed char sidemove;
|
||||
signed char upmove;
|
||||
|
||||
// get rid of this
|
||||
byte lightlevel; // light level the player is standing on
|
||||
short forwardmove, sidemove, upmove;
|
||||
byte msec;
|
||||
} usercmd_t;
|
||||
|
||||
typedef struct pmove_s
|
||||
|
@ -299,16 +304,6 @@ typedef struct pmove_s
|
|||
int (*pointcontents)( vec3_t point );
|
||||
} pmove_t;
|
||||
|
||||
typedef struct sizebuf_s
|
||||
{
|
||||
bool overflowed; // set to true if the buffer size failed
|
||||
byte *data;
|
||||
int maxsize;
|
||||
int cursize;
|
||||
int readcount;
|
||||
int errorcount; // cause by errors
|
||||
} sizebuf_t;
|
||||
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
|
@ -325,6 +320,7 @@ typedef struct launch_exp_s
|
|||
void ( *Free ) ( void ); // close host
|
||||
void ( *Cmd ) ( void ); // forward cmd to server
|
||||
void (*CPrint) ( const char *msg ); // host print
|
||||
void (*SZInit)( sizebuf_t *buf, byte *data, size_t length );// init sizebuf from events
|
||||
} launch_exp_t;
|
||||
|
||||
/*
|
||||
|
|
|
@ -28,7 +28,9 @@ typedef struct stdilib_api_s
|
|||
char *(*input)( void ); // system console input
|
||||
void (*sleep)( int msec ); // sleep for some msec
|
||||
char *(*clipboard)( void ); // get clipboard data
|
||||
uint (*keyevents)( void ); // peek windows message
|
||||
void (*queevent)( dword time, ev_type_t type, int value, int value2, int length, void *ptr );
|
||||
sys_event_t (*getevent)( void ); // get system events
|
||||
uint (*keyevents)( void ); // peek windows message (remove this)
|
||||
|
||||
// crclib.c funcs
|
||||
void (*crc_init)(word *crcvalue); // set initial crc value
|
||||
|
@ -59,6 +61,17 @@ typedef struct stdilib_api_s
|
|||
void *(*getelement)( byte *array, size_t index );
|
||||
size_t (*arraysize)( byte *arrayptr );
|
||||
|
||||
// network.c funcs
|
||||
void (*NET_Init)( void );
|
||||
void (*NET_Shutdown)( void );
|
||||
void (*NET_ShowIP)( void );
|
||||
void (*NET_Config)( bool net_enable );
|
||||
char *(*NET_AdrToString)( netadr_t a );
|
||||
bool (*NET_IsLANAddress)( netadr_t adr );
|
||||
bool (*NET_StringToAdr)( const char *s, netadr_t *a );
|
||||
bool (*NET_RecvPacket)( netadr_t *net_from, sizebuf_t *net_message );
|
||||
void (*NET_SendPacket)( int length, const void *data, netadr_t to );
|
||||
|
||||
// common functions
|
||||
void (*Com_InitRootDir)( char *path ); // init custom rootdir
|
||||
void (*Com_LoadGameInfo)( const char *filename ); // gate game info from script file
|
||||
|
@ -278,6 +291,21 @@ filesystem manager
|
|||
#define FS_CheckParm com.Com_CheckParm
|
||||
#define FS_GetParmFromCmdLine com.Com_GetParm
|
||||
|
||||
/*
|
||||
===========================================
|
||||
network messages
|
||||
===========================================
|
||||
*/
|
||||
#define NET_Init com.NET_Init
|
||||
#define NET_Shutdown com.NET_Shutdown
|
||||
#define NET_ShowIP com.NET_ShowIP
|
||||
#define NET_Config com.NET_Config
|
||||
#define NET_AdrToString com.NET_AdrToString
|
||||
#define NET_IsLANAddress com.NET_IsLANAddress
|
||||
#define Sys_StringToAdr com.NET_StringToAdr
|
||||
#define Sys_RecvPacket com.NET_RecvPacket
|
||||
#define Sys_SendPacket com.NET_SendPacket
|
||||
|
||||
/*
|
||||
===========================================
|
||||
console variables
|
||||
|
@ -357,6 +385,8 @@ misc utils
|
|||
#define Sys_Sleep com.sleep
|
||||
#define Sys_Print com.print
|
||||
#define Sys_ConsoleInput com.input
|
||||
#define Sys_GetEvent com.getevent
|
||||
#define Sys_QueEvent com.queevent
|
||||
#define Sys_GetKeyEvents com.keyevents
|
||||
#define Sys_GetClipboardData com.clipboard
|
||||
#define Sys_Quit com.exit
|
||||
|
|
Reference in New Issue