⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 net_wins.pas

📁 雷神之锤2(Quake2)Delphi源码
💻 PAS
📖 第 1 页 / 共 2 页
字号:
{----------------------------------------------------------------------------}
{                                                                            }
{ 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 + -