UNIT
{$IFDEF NODebug}
  A10;
{$ELSE}
  Sockets;
{$ENDIF}

INTERFACE

USES
{$IFDEF NODebug}
  A1, A6, B1;
{$ELSE}
  Email, Utils, ACLUtils;
{$ENDIF}

TYPE
  PLongint = ^Longint;
  TClientSocket = CLASS(TObject)
  PRIVATE
  PROTECTED
  PUBLIC
    portn    : Word;
    peerip   : STRING;
    PeerName : STRING;
    sock     : tSocket;
    CONSTRUCTOR Create;
    DESTRUCTOR  Destroy; OVERRIDE;
    FUNCTION Disconnect: BOOL;
    FUNCTION WaitForData : BOOL;
    FUNCTION Read(VAR Buf;len:Word) : Word;
    FUNCTION Write(VAR Buf;len:Word) : Word;
    FUNCTION WaitForDataTime(A:Word) : Integer;
    FUNCTION Connect(adr:STRING;PORT:STRING) : BOOL;
  END;

  TServerSocket = CLASS(TObject)
  PROTECTED
    sock     : tSocket;
  PRIVATE
    portn    : Word;
    peerip   : STRING;
    PeerName : STRING;
  public
    FUNCTION  Listen : BOOL;
    FUNCTION  Disconnect : BOOL;
    FUNCTION  WaitForConnection : BOOL;
    PROPERTY  FPeerIP : STRING READ peerip;
    PROPERTY  FPeerName: STRING READ PeerName;
    PROCEDURE AcceptConnection(Socket:TClientSocket);
    DESTRUCTOR Destroy; OVERRIDE;
    CONSTRUCTOR Create(PORT: STRING);
  END;

PROCEDURE StartWSA;

VAR
  WSAData  : TWSAData;
  WSAReady : BOOL = False;

IMPLEMENTATION

PROCEDURE StartWSA;
BEGIN
  WSAStartUp(257,WSAData);
  WSAReady:=True;
END;

CONSTRUCTOR TServerSocket.Create(PORT:STRING);
VAR
  sn  : TSockAddrIn;
  PSE : PServEnt;
BEGIN
  INHERITED Create;
  sock:=INVALID_SOCKET;
  PeerName:='';
  peerip:='';
  sock:=socket(PF_INET,SOCK_STREAM,GetProtoByName('tcp').p_proto);
  IF sock=INVALID_SOCKET THEN Exit;
  sn.sin_family:=AF_INET;
  sn.sin_addr.s_addr:=INADDR_ANY;
  PSE:=getservbyname(PChar(PORT),PChar('tcp'));
  IF PSE=NIL THEN BEGIN
    sn.sin_port:=htons(StrToInt(PORT));
    portn:=StrToInt(PORT);
  end
  ELSE BEGIN
    sn.sin_port:=PSE^.s_port;
    portn:=ntohs(PSE^.s_port);
  END;
  bind(sock,sn,sizeof(sn));
END;

DESTRUCTOR TServerSocket.Destroy;
BEGIN
  IF sock<>INVALID_SOCKET THEN Disconnect;
  INHERITED Destroy;
END;

FUNCTION TServerSocket.Listen: Bool;
BEGIN
  {$IFDEF NODebug}
  IF A1.Listen(sock,5)<>0 THEN Result:=False;
  {$ELSE}
  IF Email.Listen(sock,5)<>0 THEN Result:=False;
  {$ENDIF}
END;

FUNCTION TServerSocket.WaitForConnection : BOOL;
VAR
  fdset: TFDset;
BEGIN
  fdset.fd_count:=1;
  fdset.fd_array[0]:=sock;
  Select(0,@fdset,0,0,0);
  Result:=True;
END;

PROCEDURE TServerSocket.AcceptConnection;
VAR
  sad   : TSockAddr;
  I     : Integer;
  phe   : PHostEnt;
  TmpCs : TClientSocket;
BEGIN
  I:=sizeof(TSockAddr);
  Socket.sock:=Accept(sock, @sad, @I);
  IF Socket.sock=INVALID_SOCKET THEN exit;
  peerip:=IntToStr(Ord(sad.sa_data[2]))+'.'+IntToStr(Ord(sad.sa_data[3]))+'.'+IntToStr(Ord(sad.sa_data[4]))+'.'+IntToStr(Ord(sad.sa_data[5]));
  Socket.peerip:=peerip;
  Socket.PeerName:=PeerName;
  phe:=gethostbyaddr(@(sad.sa_data[2]),4,PF_INET);
  IF phe=NIL THEN PeerName:='' ELSE PeerName:=phe^.h_name;
END;

FUNCTION TServerSocket.Disconnect: BOOL;
BEGIN
  IF closesocket(sock)=SOCKET_ERROR THEN Result:=False;
  sock:=INVALID_SOCKET;
  PeerName:='';
END;

CONSTRUCTOR TClientSocket.Create;
BEGIN
  INHERITED Create;
  sock:=INVALID_SOCKET;
  PeerName:='';
  peerip:='';
END;

FUNCTION TClientSocket.Connect(adr:STRING;PORT:STRING) : BOOL;
VAR
  phe    : PHostEnt;
  sin    : TSockAddrIn;
  PSE    : PServEnt;
  szData : PChar;
BEGIN
  Result:=True;
  adr:=NameToIp(adr);
  sock:=socket(PF_INET,SOCK_STREAM,getprotobyname('tcp').p_proto);
  IF sock=INVALID_SOCKET THEN BEGIN
    Result:=False;
    Exit;
  END;
  sin.sin_family:=AF_INET;
  PSE:=getservbyname(PChar(PORT),pChar('tcp'));
  IF PSE=NIL THEN BEGIN
    sin.sin_port:=htons(StrToInt(PORT));
    portn:=StrToInt(PORT);
  END ELSE BEGIN
    sin.sin_port:=PSE^.s_port;
    portn:=ntohs(PSE^.s_port);
  END;
  szData:=PChar(adr);
  sin.sin_addr.s_addr:=inet_addr(szData);
  IF sin.sin_addr.s_addr=INADDR_NONE THEN BEGIN
    phe:=gethostbyname(szData);
    IF phe=NIL THEN BEGIN
      Result:=False;
      Exit;
    END;
    sin.sin_addr.s_addr:=Longint(PLongint(phe^.h_addr_list^)^);
  END;
  {$IFDEF NODebug}
  IF A1.Connect(sock,sin,sizeof(sin))<>0 THEN Result:=False;
  {$ELSE}
  IF Email.Connect(sock,sin,sizeof(sin))<>0 THEN Result:=False;
  {$ENDIF}
  PeerName:=adr;
END;

FUNCTION TClientSocket.WaitForData;
VAR
  fdset : TFDset;
BEGIN
  IF sock=INVALID_SOCKET THEN BEGIN
    Result:=False;
    Exit;
  END;
  fdset.fd_count:=1;
  fdset.fd_array[0]:=sock;
  Select(0,@fdset,NIL,NIL,NIL);
  Result:=True;
END;

FUNCTION TClientSocket.WaitForDataTime(A:Word):integer;
VAR
  fdset : TFDset;
  TM    : TTimeVal;
  Res   : Integer;
BEGIN
  TM.tv_sec:=A;
  TM.tv_usec:=A;
  fdset.fd_count:=1;
  fdset.fd_array[0]:=sock;
  Res:=Select(0,@fdset,NIL,NIL,@TM);
  IF Res=0 THEN Result:=0 ELSE IF Res=SOCKET_ERROR THEN Result:=0 ELSE Result:=res;
END;

FUNCTION TClientSocket.read;
BEGIN
  Result:=recv(sock,Buf,len,0);
END;

FUNCTION TClientSocket.write;
BEGIN
  Result:=send(sock,Buf,len,0);
END;

FUNCTION TClientSocket.Disconnect : BOOL;
BEGIN
  IF closesocket(sock)=SOCKET_ERROR THEN Result:=False;
  sock:=-1;
  PeerName:='';
END;

DESTRUCTOR TClientSocket.Destroy;
BEGIN
  IF sock<>INVALID_SOCKET THEN Disconnect;
  INHERITED Destroy;
END;

end.
