📄 net_wins.pas
字号:
{----------------------------------------------------------------------------}
{ }
{ File(s): QCommon.h (part), net_wins.c }
{ Content: Quake2\QCommon\ network routines implementation (PLATFORM) }
{ }
{ Initial conversion by : Clootie (Alexey Barkovoy) - clootie@reactor.ru }
{ Initial conversion on : 27-Jan-2002 }
{ }
{ This File contains part of convertion of Quake2 source to ObjectPascal. }
{ More information about this project can be found at: }
{ http://www.sulaco.co.za/quake2/ }
{ }
{ 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. }
{ }
{----------------------------------------------------------------------------}
{ * Updated: }
{ 1) 25-Feb-2002 - Clootie (clootie@reactor.ru) }
{ Now all external dependencies are cleaned up. }
{ }
{ 2) 17-Jul-2002 - Sly (stevewilliams@kromestudios.com) }
{ Optionally removed dependency on "JEDI Expanded Win32 API translation" }
{----------------------------------------------------------------------------}
{ * Notes: (Clootie) }
{ To compile this unit requires "JEDI Expanded Win32 API translation" }
{ available at: http://www.delphi-jedi.org/Jedi:APILIBRARY:36949 }
{----------------------------------------------------------------------------}
{ * Still dependent (to compile correctly) on: }
{ NONE }
{----------------------------------------------------------------------------}
{ * TODO: }
{----------------------------------------------------------------------------}
// Remove DOT before $DEFINE in next line to allow non-dependable compilation //
{$DEFINE NODEPEND}
// non-dependable compilation will use STUBS for some external symbols
unit net_wins;
{ Define USE_JWA to use the JEDI Expanded Win32 API translation headers }
{.$DEFINE USE_JWA}
{$Include ..\JEDI.inc}
interface
uses
{$IFDEF USE_JWA}
JwaWinSock,
{$ELSE}
WinSock,
{$ENDIF}
Q_Shared, Common;
{$IFNDEF USE_JWA}
type
sockaddr = TSockAddr;
{$ENDIF}
//Clootie: These routines in Q2 C source code are declared in QCommon.h
procedure NET_Init;
procedure NET_Shutdown;
procedure NET_Config(multiplayer: qboolean);
function NET_GetPacket(sock: netsrc_t; var net_from: netadr_t; var net_message: sizebuf_t): qboolean;
procedure NET_SendPacket(sock: netsrc_t; length: Integer; data: Pointer; const to_: netadr_t);
function NET_CompareAdr(const a, b: netadr_t): qboolean;
function NET_CompareBaseAdr(const a, b: netadr_t): qboolean;
function NET_IsLocalAddress(const adr: netadr_t): qboolean;
function NET_AdrToString(const a: netadr_t): PChar;
function NET_StringToSockaddr(s: PChar; out sadr: sockaddr): qboolean;
procedure NET_Sleep(msec: Integer);
function NET_StringToAdr(s: PChar; out a: netadr_t): qboolean;
implementation
uses
SysUtils, Windows,
{$IFDEF USE_JWA}
JwaWSipx,
{$ENDIF}
CVar;
// net_wins.c
const
MAX_LOOPBACK = 4;
type
loopmsg_p = ^loopmsg_t;
loopmsg_t = record
data: array [0..MAX_MSGLEN-1] of Byte;
datalen: Integer;
end;
loopback_p = ^loopback_t;
loopback_t = record
msgs: array [0..MAX_LOOPBACK-1] of loopmsg_t;
get, send: Integer;
end;
{$IFNDEF USE_JWA}
const
NSPROTO_IPX = 1000;
type
sockaddr_ipx = record
sa_family: Smallint;
sa_netnum: array [0..3] of Char;
sa_nodenum: array [0..5] of Char;
sa_socket: Word;
end;
TSockAddrIPX = sockaddr_ipx;
PSockAddrIPX = ^sockaddr_ipx;
{$ENDIF}
var
net_shownet : cvar_p;
noudp : cvar_p; // static
noipx : cvar_p; // static
loopbacks : array[NS_CLIENT..NS_SERVER] of loopback_t;
ip_sockets : array[NS_CLIENT..NS_SERVER] of Integer;
ipx_sockets : array[NS_CLIENT..NS_SERVER] of Integer;
function NET_ErrorString: PChar; forward;
//=============================================================================
procedure NetadrToSockadr(const a: netadr_t; var s: TSockAddr);
type
Pu_long = ^u_long;
begin
FillChar(s, SizeOf(s), 0);
if (a.type_ = NA_BROADCAST) then
begin
sockaddr_in(s).sin_family := AF_INET;
sockaddr_in(s).sin_port := a.port;
sockaddr_in(s).sin_addr.s_addr := INADDR_BROADCAST;
end
else if (a.type_ = NA_IP) then
begin
sockaddr_in(s).sin_family := AF_INET;
sockaddr_in(s).sin_addr.s_addr := Pu_long(@a.ip)^;
sockaddr_in(s).sin_port := a.port;
end
else if (a.type_ = NA_IPX) then
begin
PSockAddrIPX(@s).sa_family := AF_IPX;
Move(a.ipx[0], PSockAddrIPX(@s).sa_netnum, 4);
Move(a.ipx[4], PSockAddrIPX(@s).sa_nodenum, 6);
PSockAddrIPX(@s).sa_socket := a.port;
end
else if (a.type_ = NA_BROADCAST_IPX) then
begin
PSockAddrIPX(@s).sa_family := AF_IPX;
FillChar(PSockAddrIPX(@s).sa_netnum, 4, 0);
FillChar(PSockAddrIPX(@s).sa_nodenum, 6, $FF);
PSockAddrIPX(@s).sa_socket := a.port;
end;
end;
procedure SockadrToNetadr(const s: sockaddr; var a: netadr_t);
begin
if (s.sa_family = AF_INET) then
begin
a.type_ := NA_IP;
PInteger(@a.ip)^ := sockaddr_in(s).sin_addr.s_addr;
a.port := sockaddr_in(s).sin_port;
end
else if (s.sa_family = AF_IPX) then
begin
a.type_ := NA_IPX;
Move(PSockAddrIPX(@s).sa_netnum, a.ipx[0], 4);
Move(PSockAddrIPX(@s).sa_nodenum, a.ipx[4], 6);
a.port := PSockAddrIPX(@s).sa_socket;
end;
end;
function NET_CompareAdr(const a, b: netadr_t): qboolean;
begin
Result := (a.type_ = b.type_);
if not Result then Exit;
if (a.type_ = NA_LOOPBACK) then
begin
Result:= True;
Exit;
end;
if (a.type_ = NA_IP) then
begin
if (a.ip[0] = b.ip[0]) and (a.ip[1] = b.ip[1]) and
(a.ip[2] = b.ip[2]) and (a.ip[3] = b.ip[3]) and (a.port = b.port) then
begin
Result := True;
Exit;
end;
Result:= False;
Exit;
end;
if (a.type_ = NA_IPX) then
begin
if CompareMem(@a.ipx, @b.ipx, 10) and (a.port = b.port) then
begin
Result:= True;
Exit;
end;
Result:= False;
end;
end;
(*
===================
NET_CompareBaseAdr
Compares without the port
===================
*)
function NET_CompareBaseAdr(const a, b: netadr_t): qboolean;
begin
if (a.type_ <> b.type_) then
begin
Result:= False;
Exit;
end;
if (a.type_ = NA_LOOPBACK) then
begin
Result:= True;
Exit;
end;
if (a.type_ = NA_IP) then
begin
if (a.ip[0] = b.ip[0]) and (a.ip[1] = b.ip[1]) and
(a.ip[2] = b.ip[2]) and (a.ip[3] = b.ip[3]) then
begin
Result := True;
Exit;
end;
Result:= False;
Exit;
end;
if (a.type_ = NA_IPX) then
begin
if CompareMem(@a.ipx, @b.ipx, 10) then
begin
Result:= True;
Exit;
end;
Result:= False;
Exit;
end;
Result:= False;
end;
function NET_AdrToString(const a: netadr_t): PChar;
{$IFDEF COMPILER6_UP}{$WRITEABLECONST ON}{$ENDIF}
const
s: array [0..63] of Char = '';
recursive: qboolean = False;
{$IFDEF COMPILER6_UP}{$WRITEABLECONST OFF}{$ENDIF}
begin
if (a.type_ = NA_LOOPBACK) then
Com_sprintf(s, SizeOf(s), 'loopback', [''])
else if (a.type_ = NA_IP) then
Com_sprintf(s, SizeOf(s), '%d.%d.%d.%d:%d', [a.ip[0], a.ip[1], a.ip[2], a.ip[3], ntohs(a.port)])
else
Com_sprintf(s, SizeOf(s), '%02x%02x%02x%02x:%02x%02x%02x%02x%02x%02x:%d',
[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], ntohs(a.port)]);
Result := s;
end;
(*
=============
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}
//function
function NET_StringToSockaddr(s: PChar; out sadr: sockaddr): qboolean;
type
PCharArray = ^TCharArray;
TCharArray = array[0..MaxInt div SizeOf(Char)-1] of Char;
var
copy: array [0..127] of Char;
val: Integer;
procedure DoIt(src: Integer; var dest: Char);
begin
copy[0] := s[src];
copy[1] := s[src + 1];
// sscanf (copy, "%x", &val);
val := StrToInt(copy);
dest := Chr(val);
end;
{$IFNDEF COMPILER6_UP}
type
PCardinal = ^Cardinal;
{$ENDIF}
var
h: PHostEnt;
colon: PChar;
begin
FillChar(sadr, SizeOf(sadr), 0);
if (StrLen(s) >= 23) and (PCharArray(s)[8] = ':') and (PCharArray(s)[21] = ':') then // check for an IPX address
begin
PSockAddrIPX(@sadr).sa_family := AF_IPX;
copy[2] := #0;
DOit(0, PSockAddrIPX(@sadr).sa_netnum[0]);
DOit(2, PSockAddrIPX(@sadr).sa_netnum[1]);
DOit(4, PSockAddrIPX(@sadr).sa_netnum[2]);
DOit(6, PSockAddrIPX(@sadr).sa_netnum[3]);
DOit(9, PSockAddrIPX(@sadr).sa_nodenum[0]);
DOit(11, PSockAddrIPX(@sadr).sa_nodenum[1]);
DOit(13, PSockAddrIPX(@sadr).sa_nodenum[2]);
DOit(15, PSockAddrIPX(@sadr).sa_nodenum[3]);
DOit(17, PSockAddrIPX(@sadr).sa_nodenum[4]);
DOit(19, PSockAddrIPX(@sadr).sa_nodenum[5]);
// sscanf (&s[22], "%u", &val);
val := StrToInt(PChar(@s[22]));
PSockAddrIPX(@sadr).sa_socket := htons(val);
end
else
begin
PSockAddrIn(@sadr).sin_family := AF_INET;
PSockAddrIn(@sadr).sin_port := 0;
StrCopy(copy, s);
// strip off a trailing :port if present
// for (colon = copy ; *colon ; colon++)
colon := copy;
while (colon^ <> #0) do
begin
if (colon^ = ':') then
begin
colon^ := #0;
PSockAddrIn(@sadr).sin_port := htons(StrToInt(colon+1));
end;
Inc(colon);
end;
if (copy[0] >= '0') and (copy[0] <= '9') then
begin
// *(int *)&((struct sockaddr_in *)sadr)->
PCardinal(@(PSockAddrIn(@sadr).sin_addr))^ := inet_addr(copy);
end
else
begin
h := gethostbyname(copy);
if (h = nil) then
begin
Result:= False;
Exit;
end; // *(int *)
Cardinal(PSockAddrIn(@sadr).sin_addr) := Cardinal(h.h_addr_list^);
end;
end;
Result:= true;
end;
//#undef DO
(*
=============
NET_StringToAdr
localhost
idnewt
idnewt:28000
192.246.40.70
192.246.40.70:28000
=============
*)
function NET_StringToAdr(s: PChar; out a: netadr_t): qboolean;
var
sadr: sockaddr;
begin
if (StrComp(s, 'localhost') = 0)then
begin
FillChar(a, SizeOf(a), 0);
a.type_ := NA_LOOPBACK;
Result:= True;
Exit;
end;
if not NET_StringToSockaddr(s, sadr) then
begin
Result:= false;
Exit;
end;
SockadrToNetadr(sadr, a);
Result:= True;
end;
function NET_IsLocalAddress(const adr: netadr_t): qboolean;
begin
Result:= (adr.type_ = NA_LOOPBACK);
end;
(*
=============================================================================
LOOPBACK BUFFERS FOR LOCAL PLAYER
=============================================================================
*)
function NET_GetLoopPacket(sock: netsrc_t; var net_from: netadr_t;
var net_message: sizebuf_t): qboolean;
var
i: Integer;
loop: loopback_p;
begin
loop := @loopbacks[sock];
if (loop.send - loop.get > MAX_LOOPBACK) then
loop.get := loop.send - MAX_LOOPBACK;
if (loop.get >= loop.send) then
begin
Result:= false;
Exit;
end;
i := loop.get and (MAX_LOOPBACK-1);
Inc(loop.get);
// memcpy (net_message->data, loop->msgs[i].data, loop->msgs[i].datalen);
Move(loop.msgs[i].data, net_message.data^, loop.msgs[i].datalen);
net_message.cursize := loop.msgs[i].datalen;
FillChar(net_from, SizeOf(net_from), 0);
net_from.type_ := NA_LOOPBACK;
Result:= true;
end;
procedure NET_SendLoopPacket(sock: netsrc_t; length: Integer;
data: Pointer; const to_: netadr_t);
var
i: Integer;
loop: loopback_p;
begin
loop := @loopbacks[netsrc_t(Ord(sock) xor 1)];
i := loop.send and (MAX_LOOPBACK-1);
Inc(loop.send);
Move(data^, loop.msgs[i].data, length);
loop.msgs[i].datalen := length;
end;
//=============================================================================
function NET_GetPacket(sock: netsrc_t; var net_from: netadr_t;
var net_message: sizebuf_t): qboolean;
var
ret: Integer;
from: sockaddr;
fromlen: Integer;
net_socket: Integer;
protocol: Integer;
err: Integer;
begin
if (NET_GetLoopPacket(sock, net_from, net_message)) then
begin
Result:= True;
Exit;
end;
for protocol := 0 to 1 do
begin
if (protocol = 0) then
net_socket := ip_sockets[sock]
else
net_socket := ipx_sockets[sock];
if (net_socket = 0) then Continue;
fromlen := SizeOf(from);
ret := recvfrom(net_socket, net_message.data^, net_message.maxsize, 0,
{$IFDEF USE_JWA}
@from, fromlen);
{$ELSE}
from, fromlen);
{$ENDIF}
SockadrToNetadr(from, net_from);
if (ret = -1) then
begin
err := WSAGetLastError;
if (err = WSAEWOULDBLOCK) then
Continue;
if (err = WSAEMSGSIZE) then
begin
Com_Printf('Warning: Oversize packet from %s'#10,
[NET_AdrToString(net_from)]);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -