{==============================================================================|
| Project : Delphree - Synapse                        | xxx.xxx.xxx (modified) |
|==============================================================================|
| Content: Socket Independent Platform                                         |
|==============================================================================|
| The contents of this file are subject to the Mozilla Public License Ver. 1.0 |
| (the "License"); you may not use this file except in compliance with the     |
| License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ |
|                                                                              |
| Software distributed under the License is distributed on an "AS IS" basis,   |
| WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for |
| the specific language governing rights and limitations under the License.    |
|==============================================================================|
| The Original Code is Synapse Delphi Library.                                 |
|==============================================================================|
| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).|
| Portions created by Lukas Gebauer are Copyright (c)2001.                     |
| All Rights Reserved.                                                         |
|==============================================================================|
| Original Synapse is available from http://www.ararat.cz/synapse/             |
|                                                                              |
| This version is heavily modified by CyberAlien@users.sourceforge.net         |
|                                                                              |
| The latest version of modified synsock.pas is included in SlavaNap project   |
| source code and available from http://www.slavanap.org                       |
|==============================================================================}

unit SynSock;

interface

uses
{$IFDEF LINUX}
  libc, kernelioctl;
{$ELSE}
  WinSock, Windows;
{$ENDIF}

{$IFDEF LINUX}
const
  WSAEINTR = EINTR;
  WSAEBADF = EBADF;
  WSAEACCES = EACCES;
  WSAEFAULT = EFAULT;
  WSAEINVAL = EINVAL;
  WSAEMFILE = EMFILE;
  WSAEWOULDBLOCK = EWOULDBLOCK;
  WSAEINPROGRESS = EINPROGRESS;
  WSAEALREADY = EALREADY;
  WSAENOTSOCK = ENOTSOCK;
  WSAEDESTADDRREQ = EDESTADDRREQ;
  WSAEMSGSIZE = EMSGSIZE;
  WSAEPROTOTYPE = EPROTOTYPE;
  WSAENOPROTOOPT = ENOPROTOOPT;
  WSAEPROTONOSUPPORT = EPROTONOSUPPORT;
  WSAESOCKTNOSUPPORT = ESOCKTNOSUPPORT;
  WSAEOPNOTSUPP = EOPNOTSUPP;
  WSAEPFNOSUPPORT = EPFNOSUPPORT;
  WSAEAFNOSUPPORT = EAFNOSUPPORT;
  WSAEADDRINUSE = EADDRINUSE;
  WSAEADDRNOTAVAIL = EADDRNOTAVAIL;
  WSAENETDOWN = ENETDOWN;
  WSAENETUNREACH = ENETUNREACH;
  WSAENETRESET = ENETRESET;
  WSAECONNABORTED = ECONNABORTED;
  WSAECONNRESET = ECONNRESET;
  WSAENOBUFS = ENOBUFS;
  WSAEISCONN = EISCONN;
  WSAENOTCONN = ENOTCONN;
  WSAESHUTDOWN = ESHUTDOWN;
  WSAETOOMANYREFS = ETOOMANYREFS;
  WSAETIMEDOUT = ETIMEDOUT;
  WSAECONNREFUSED = ECONNREFUSED;
  WSAELOOP = ELOOP;
  WSAENAMETOOLONG = ENAMETOOLONG;
  WSAEHOSTDOWN = EHOSTDOWN;
  WSAEHOSTUNREACH = EHOSTUNREACH;
  WSAENOTEMPTY = ENOTEMPTY;
  WSAEPROCLIM = -1;
  WSAEUSERS = EUSERS;
  WSAEDQUOT = EDQUOT;
  WSAESTALE = ESTALE;
  WSAEREMOTE = EREMOTE;
  WSASYSNOTREADY = -2;
  WSAVERNOTSUPPORTED = -3;
  WSANOTINITIALISED = -4;
  WSAEDISCON = -5;
  WSAHOST_NOT_FOUND = HOST_NOT_FOUND;
  WSATRY_AGAIN = TRY_AGAIN;
  WSANO_RECOVERY = NO_RECOVERY;
  //  WSANO_DATA         = NO_DATA;
  WSANO_DATA = -6;

{$ELSE}

const
  // constants for ShutDown
  SD_RECEIVE = 0;
  SD_SEND = 1;
  SD_BOTH = 2;

const
  DLLStackName = 'wsock32.dll';
var
  LibHandle: THandle = 0;
{$ENDIF}

{$IFDEF LINUX}
const
  WSADESCRIPTION_LEN = 256;
  WSASYS_STATUS_LEN = 128;
type
  PWSAData = ^TWSAData;
  TWSAData = packed record
    wVersion: Word;
    wHighVersion: Word;
    szDescription: array[0..WSADESCRIPTION_LEN] of Char;
    szSystemStatus: array[0..WSASYS_STATUS_LEN] of Char;
    iMaxSockets: Word;
    iMaxUdpDg: Word;
    lpVendorInfo: PChar;
  end;
  DWORD = Integer;
  TLinger = Linger;
{$ENDIF}

type
  TWSAStartup = function(wVersionRequired: Word;
    var WSData: TWSAData): Integer; stdcall;
  TWSACleanup = function: Integer; stdcall;
  TWSAGetLastError = function: Integer; stdcall;
  TWSASetLastError = procedure(iError: Integer); stdcall;
  TGetServByName = function(name, proto: PChar): PServEnt; stdcall;
  TGetServByPort = function(port: Integer; proto: PChar): PServEnt; stdcall;
  TGetProtoByName = function(name: PChar): PProtoEnt; stdcall;
  TGetProtoByNumber = function(proto: Integer): PProtoEnt; stdcall;
  TGetHostByName = function(name: PChar): PHostEnt; stdcall;
  TGetHostByAddr = function(addr: Pointer; len, Struct: Integer): PHostEnt;
  stdcall;
  TGetHostName = function(name: PChar; len: Integer): Integer; stdcall;
  TShutdown = function(s: TSocket; how: Integer): Integer; stdcall;
  TSetSockOpt = function(s: TSocket; level, optname: Integer;
    optval: PChar;
    optlen: Integer): Integer; stdcall;
  TGetSockOpt = function(s: TSocket; level, optname: Integer;
    optval: PChar;
    var optlen: Integer): Integer; stdcall;
  TSendTo = function(s: TSocket; var Buf;
    len, flags: Integer;
    var addrto: TSockAddr;
    tolen: Integer): Integer; stdcall;
  TSend = function(s: TSocket; var Buf;
    len, flags: Integer): Integer; stdcall;
  TRecv = function(s: TSocket;
    var Buf;
    len, flags: Integer): Integer; stdcall;
  TRecvFrom = function(s: TSocket;
    var Buf; len, flags: Integer;
    var from: TSockAddr;
    var fromlen: Integer): Integer; stdcall;
  Tntohs = function(netshort: u_short): u_short; stdcall;
  Tntohl = function(netlong: u_long): u_long; stdcall;
  TListen = function(s: TSocket;
    backlog: Integer): Integer; stdcall;
  TIoctlSocket = function(s: TSocket; cmd: DWORD;
    var arg: u_long): Integer; stdcall;
  TInet_ntoa = function(inaddr: TInAddr): PChar; stdcall;
  TInet_addr = function(cp: PChar): u_long; stdcall;
  Thtons = function(hostshort: u_short): u_short; stdcall;
  Thtonl = function(hostlong: u_long): u_long; stdcall;
  TGetSockName = function(s: TSocket; var name: TSockAddr;
    var namelen: Integer): Integer; stdcall;
  TGetPeerName = function(s: TSocket; var name: TSockAddr;
    var namelen: Integer): Integer; stdcall;
  TConnect = function(s: TSocket; var name: TSockAddr;
    namelen: Integer): Integer; stdcall;
  TCloseSocket = function(s: TSocket): Integer; stdcall;
  TBind = function(s: TSocket; var addr: TSockAddr;
    namelen: Integer): Integer; stdcall;
  TAccept = function(s: TSocket; addr: PSockAddr;
    addrLen: PInteger): TSocket; stdcall;
  TSocketProc = function(af, Struct, protocol: Integer): TSocket; stdcall;
  TSelect = function(nfds: Integer; readfds, writefds, exceptfds: PFDSet;
    timeout: PTimeVal): LongInt; stdcall;

var
  WSAStartup: TWSAStartup = nil;
  WSACleanup: TWSACleanup = nil;
  WSAGetLastError: TWSAGetLastError = nil;
  WSASetLastError: TWSASetLastError = nil;
  GetServByName: TGetServByName = nil;
  GetServByPort: TGetServByPort = nil;
  GetProtoByName: TGetProtoByName = nil;
  GetProtoByNumber: TGetProtoByNumber = nil;
  GetHostByName: TGetHostByName = nil;
  GetHostByAddr: TGetHostByAddr = nil;
  GetHostName: TGetHostName = nil;
  Shutdown: TShutdown = nil;
  SetSockOpt: TSetSockOpt = nil;
  GetSockOpt: TGetSockOpt = nil;
  SendTo: TSendTo = nil;
  Send: TSend = nil;
  Recv: TRecv = nil;
  RecvFrom: TRecvFrom = nil;
  ntohs: Tntohs = nil;
  ntohl: Tntohl = nil;
  Listen: TListen = nil;
  IoctlSocket: TIoctlSocket = nil;
  inet_ntoa: TInet_ntoa = nil;
  inet_addr: TInet_addr = nil;
  htons: Thtons = nil;
  htonl: Thtonl = nil;
  GetSockName: TGetSockName = nil;
  GetPeerName: TGetPeerName = nil;
  Connect: TConnect = nil;
  CloseSocket: TCloseSocket = nil;
  Bind: TBind = nil;
  Accept: TAccept = nil;
  Socket: TSocketProc = nil;
  Select: TSelect = nil;

function InitSocketInterface(Stack: string): Boolean;
function DestroySocketInterface: Boolean;

{$IFDEF LINUX}
function LSWSAStartup(wVersionRequired: Word; var WSData: TWSAData): Integer;
stdcall;
function LSWSACleanup: Integer; stdcall;
function LSWSAGetLastError: Integer; stdcall;
procedure LSWSASetLastError(iError: Integer); stdcall;
function LSGetServByName(name, proto: PChar): PServEnt; stdcall;
function LSGetServByPort(port: Integer; proto: PChar): PServEnt; stdcall;
function LSGetProtoByName(name: PChar): PProtoEnt; stdcall;
function LSGetProtoByNumber(proto: Integer): PProtoEnt; stdcall;
function LSGetHostByName(name: PChar): PHostEnt; stdcall;
function LSGetHostByAddr(addr: Pointer; len, Struct: Integer): PHostEnt;
stdcall;
function LSGetHostName(name: PChar; len: Integer): Integer; stdcall;
function LSShutdown(s: TSocket; how: Integer): Integer; stdcall;
function LSSetSockOpt(s: TSocket; level, optname: Integer; optval: PChar;
  optlen: Integer): Integer; stdcall;
function LSGetSockOpt(s: TSocket; level, optname: Integer; optval: PChar; var
  optlen: Integer): Integer; stdcall;
function LSSendTo(s: TSocket; var Buf; len, flags: Integer; var addrto:
  TSockAddr; tolen: Integer): Integer; stdcall;
function LSSend(s: TSocket; var Buf; len, flags: Integer): Integer; stdcall;
function LSRecv(s: TSocket; var Buf; len, flags: Integer): Integer; stdcall;
function LSRecvFrom(s: TSocket; var Buf; len, flags: Integer; var from:
  TSockAddr; var fromlen: Integer): Integer; stdcall;
function LSntohs(netshort: u_short): u_short; stdcall;
function LSntohl(netlong: u_long): u_long; stdcall;
function LSListen(s: TSocket; backlog: Integer): Integer; stdcall;
function LSIoctlSocket(s: TSocket; cmd: DWORD; var arg: u_long): Integer;
stdcall;
function LSInet_ntoa(inaddr: TInAddr): PChar; stdcall;
function LSInet_addr(cp: PChar): u_long; stdcall;
function LShtons(hostshort: u_short): u_short; stdcall;
function LShtonl(hostlong: u_long): u_long; stdcall;
function LSGetSockName(s: TSocket; var name: TSockAddr; var namelen: Integer):
  Integer; stdcall;
function LSGetPeerName(s: TSocket; var name: TSockAddr; var namelen: Integer):
  Integer; stdcall;
function LSConnect(s: TSocket; var name: TSockAddr; namelen: Integer): Integer;
stdcall;
function LSCloseSocket(s: TSocket): Integer; stdcall;
function LSBind(s: TSocket; var addr: TSockAddr; namelen: Integer): Integer;
stdcall;
function LSAccept(s: TSocket; addr: PSockAddr; addrLen: PInteger): TSocket;
stdcall;
function LSSocketProc(af, Struct, protocol: Integer): TSocket; stdcall;
function LSSelect(nfds: Integer; readfds, writefds, exceptfds: PFDSet; timeout:
  PTimeVal): LongInt; stdcall;
{$ENDIF}

implementation

{$IFDEF LINUX}

function LSWSAStartup(wVersionRequired: Word; var WSData: TWSAData): Integer;
begin
  WSData.wVersion := wVersionRequired;
  WSData.wHighVersion := $101;
  WSData.szDescription := 'Synapse Platform Independent Socket Layer';
  WSData.szSystemStatus := 'On Linux';
  WSData.iMaxSockets := 32768;
  WSData.iMaxUdpDg := 8192;
  Result := 0;
end;

function LSWSACleanup: Integer;
begin
  Result := 0;
end;

function LSWSAGetLastError: Integer;
begin
  Result := System.GetLastError;
end;

procedure LSWSASetLastError(iError: Integer);
begin
  System.SetLastError(iError);
end;

function LSGetServByName(name, proto: PChar): PServEnt;
begin
  Result := libc.GetServByName(name, proto);
end;

function LSGetServByPort(port: Integer; proto: PChar): PServEnt;
begin
  Result := libc.GetServByPort(port, proto);
end;

function LSGetProtoByName(name: PChar): PProtoEnt;
begin
  Result := libc.getprotobyname(name);
end;

function LSGetProtoByNumber(proto: Integer): PProtoEnt;
begin
  Result := libc.getprotobynumber(proto);
end;

function LSGetHostByName(name: PChar): PHostEnt;
begin
  Result := libc.GetHostByName(name);
end;

function LSGetHostByAddr(addr: Pointer; len, Struct: Integer): PHostEnt;
begin
  Result := libc.GetHostByAddr(addr, len, struct);
end;

function LSGetHostName(name: PChar; len: Integer): Integer;
begin
  Result := libc.GetHostName(name, len);
end;

function LSShutdown(s: TSocket; how: Integer): Integer;
begin
  Result := libc.Shutdown(s, how);
end;

function LSSetSockOpt(s: TSocket; level, optname: Integer; optval: PChar;
  optlen: Integer): Integer;
begin
  Result := libc.SetSockOpt(s, level, optname, optval, optlen);
end;

function LSGetSockOpt(s: TSocket; level, optname: Integer; optval: PChar; var
  optlen: Integer): Integer;
begin
  Result := libc.getsockopt(s, level, optname, optval, Cardinal(optlen));
end;

function LSSendTo(s: TSocket; var Buf; len, flags: Integer; var addrto:
  TSockAddr; tolen: Integer): Integer;
begin
  Result := libc.SendTo(s, Buf, len, flags, addrto, tolen);
end;

function LSSend(s: TSocket; var Buf; len, flags: Integer): Integer;
begin
  Result := libc.Send(s, Buf, len, flags);
end;

function LSRecv(s: TSocket; var Buf; len, flags: Integer): Integer;
begin
  Result := libc.Recv(s, Buf, len, flags);
end;

function LSRecvFrom(s: TSocket; var Buf; len, flags: Integer; var from:
  TSockAddr; var fromlen: Integer): Integer;
begin
  Result := libc.RecvFrom(s, Buf, len, flags, @from, @fromlen);
end;

function LSntohs(netshort: u_short): u_short;
begin
  Result := libc.ntohs(netshort);
end;

function LSntohl(netlong: u_long): u_long;
begin
  Result := libc.ntohl(netlong);
end;

function LSListen(s: TSocket; backlog: Integer): Integer;
begin
  Result := libc.Listen(s, backlog);
end;

function LSIoctlSocket(s: TSocket; cmd: DWORD; var arg: u_long): Integer;
begin
  Result := libc.ioctl(s, cmd, @arg);
end;

function LSInet_ntoa(inaddr: TInAddr): PChar;
begin
  Result := libc.inet_ntoa(inaddr);
end;

function LSInet_addr(cp: PChar): u_long;
begin
  Result := libc.inet_addr(cp);
end;

function LShtons(hostshort: u_short): u_short;
begin
  Result := libc.htons(hostshort);
end;

function LShtonl(hostlong: u_long): u_long;
begin
  Result := libc.htonl(hostlong);
end;

function LSGetSockName(s: TSocket; var name: TSockAddr; var namelen: Integer):
  Integer;
begin
  Result := libc.GetSockName(s, name, Cardinal(namelen));
end;

function LSGetPeerName(s: TSocket; var name: TSockAddr; var namelen: Integer):
  Integer;
begin
  Result := libc.GetPeerName(s, name, Cardinal(namelen));
end;

function LSConnect(s: TSocket; var name: TSockAddr; namelen: Integer): Integer;
begin
  Result := libc.Connect(s, name, namelen);
end;

function LSCloseSocket(s: TSocket): Integer;
begin
  Result := libc.__close(s);
end;

function LSBind(s: TSocket; var addr: TSockAddr; namelen: Integer): Integer;
begin
  Result := libc.Bind(s, addr, namelen);
end;

function LSAccept(s: TSocket; addr: PSockAddr; addrLen: PInteger): TSocket;
begin
  Result := libc.Accept(s, addr, PSocketLength(addrLen));
end;

function LSSocketProc(af, Struct, protocol: Integer): TSocket;
begin
  Result := libc.Socket(af, Struct, protocol);
end;

function LSSelect(nfds: Integer; readfds, writefds, exceptfds: PFDSet; timeout:
  PTimeVal): LongInt;
begin
  Result := libc.Select(nfds, readfds, writefds, exceptfds, timeout);
end;

{$ENDIF}

function InitSocketInterface(Stack: string): Boolean;
begin
{$IFDEF LINUX}
  Accept := LSAccept;
  Bind := LSBind;
  CloseSocket := LSCloseSocket;
  Connect := LSConnect;
  GetPeerName := LSGetPeerName;
  GetSockName := LSGetSockName;
  GetSockOpt := LSGetSockOpt;
  htonl := LShtonl;
  htons := LShtons;
  inet_addr := LSinet_addr;
  inet_ntoa := LSinet_ntoa;
  IoctlSocket := LSioctlsocket;
  Listen := LSlisten;
  ntohl := LSntohl;
  ntohs := LSntohs;
  Recv := LSrecv;
  RecvFrom := LSrecvfrom;
  Select := LSselect;
  Send := LSsend;
  SendTo := LSsendto;
  SetSockOpt := LSsetsockopt;
  ShutDown := LSshutdown;
  Socket := LSsocketProc;
  GetHostByAddr := LSgethostbyaddr;
  GetHostByName := LSgethostbyname;
  GetProtoByName := LSgetprotobyname;
  GetProtoByNumber := LSgetprotobynumber;
  GetServByName := LSgetservbyname;
  GetServByPort := LSgetservbyport;
  GetHostName := LSgethostname;
  WSAGetLastError := LSWSAGetLastError;
  WSASetLastError := LSWSASetLastError;
  WSAStartup := LSWSAStartup;
  WSACleanup := LSWSACleanup;
  Result := True;
{$ELSE}
  Result := False;
  if Stack = '' then
    Stack := DLLStackName;
  LibHandle := Windows.LoadLibrary(PChar(Stack));
  if LibHandle <> 0 then
  begin
    Accept := Windows.GetProcAddress(LibHandle, PChar('accept'));
    Bind := Windows.GetProcAddress(LibHandle, PChar('bind'));
    CloseSocket := Windows.GetProcAddress(LibHandle, PChar('closesocket'));
    Connect := Windows.GetProcAddress(LibHandle, PChar('connect'));
    GetPeerName := Windows.GetProcAddress(LibHandle, PChar('getpeername'));
    GetSockName := Windows.GetProcAddress(LibHandle, PChar('getsockname'));
    GetSockOpt := Windows.GetProcAddress(LibHandle, PChar('getsockopt'));
    htonl := Windows.GetProcAddress(LibHandle, PChar('htonl'));
    htons := Windows.GetProcAddress(LibHandle, PChar('htons'));
    inet_addr := Windows.GetProcAddress(LibHandle, PChar('inet_addr'));
    inet_ntoa := Windows.GetProcAddress(LibHandle, PChar('inet_ntoa'));
    IoctlSocket := Windows.GetProcAddress(LibHandle, PChar('ioctlsocket'));
    Listen := Windows.GetProcAddress(LibHandle, PChar('listen'));
    ntohl := Windows.GetProcAddress(LibHandle, PChar('ntohl'));
    ntohs := Windows.GetProcAddress(LibHandle, PChar('ntohs'));
    Recv := Windows.GetProcAddress(LibHandle, PChar('recv'));
    RecvFrom := Windows.GetProcAddress(LibHandle, PChar('recvfrom'));
    Select := Windows.GetProcAddress(LibHandle, PChar('select'));
    Send := Windows.GetProcAddress(LibHandle, PChar('send'));
    SendTo := Windows.GetProcAddress(LibHandle, PChar('sendto'));
    SetSockOpt := Windows.GetProcAddress(LibHandle, PChar('setsockopt'));
    ShutDown := Windows.GetProcAddress(LibHandle, PChar('shutdown'));
    Socket := Windows.GetProcAddress(LibHandle, PChar('socket'));
    GetHostByAddr := Windows.GetProcAddress(LibHandle, PChar('gethostbyaddr'));
    GetHostByName := Windows.GetProcAddress(LibHandle, PChar('gethostbyname'));
    GetProtoByName := Windows.GetProcAddress(LibHandle,
      PChar('getprotobyname'));
    GetProtoByNumber := Windows.GetProcAddress(LibHandle,
      PChar('getprotobynumber'));
    GetServByName := Windows.GetProcAddress(LibHandle, PChar('getservbyname'));
    GetServByPort := Windows.GetProcAddress(LibHandle, PChar('getservbyport'));
    GetHostName := Windows.GetProcAddress(LibHandle, PChar('gethostname'));
    WSAGetLastError := Windows.GetProcAddress(LibHandle,
      PChar('WSAGetLastError'));
    WSASetLastError := Windows.GetProcAddress(LibHandle,
      PChar('WSASetLastError'));
    WSAStartup := Windows.GetProcAddress(LibHandle, PChar('WSAStartup'));
    WSACleanup := Windows.GetProcAddress(LibHandle, PChar('WSACleanup'));
    Result := True;
  end;
{$ENDIF}
end;

function DestroySocketInterface: Boolean;
begin
{$IFDEF LINUX}
{$ELSE}
  if LibHandle <> 0 then
  begin
    Windows.FreeLibrary(LibHandle);
  end;
  LibHandle := 0;
{$ENDIF}
  Result := True;
end;

end.
