Extra Systems Database
unit inet;

interface

uses
     winsock, windows;

type
     TSocket = class(TObject)
     private
          FWaitRead      : Integer;
          FWaitWrite     : Integer;
          function ResolveHost(const HostName:PChar; var HostAddress:TInAddr):Boolean;
          function IsIpDone(const Server:PChar):Boolean;
     public
          Handle         : Integer;
          ServerAddress  : TSockAddrIn;
          ClientAddress  : TSockAddrIn;
          constructor Create(const WaitRead,WaitWrite:Integer);
          destructor Destroy; override;
          function SendBuffer(const BufAddr:Pointer; const BufSize:Integer):Boolean;
          function ReadToBuffer(const BufAddr:Pointer; const BufSize:Integer):Integer;
          procedure Close;
          function TestRead:Boolean;
          function Connect(const Server:PChar; const Port:Integer):Boolean;
     end;

{$EXTERNALSYM socket}
function socket(af, Struct, protocol: Integer): Integer; stdcall;

implementation

function socket; external 'wsock32.dll' name 'socket';

constructor TSocket.Create(const WaitRead,WaitWrite:Integer);
var
     WSAData: TWSAData;
begin
     inherited Create;
     Handle:=0;
     FWaitRead:=WaitRead;
     FWaitWrite:=WaitWrite;
     WinSock.WSAStartup($0101, WSAData);
end;

destructor TSocket.Destroy;
begin
     if (Handle <> 0) then Close;
     inherited Destroy;
     WSACleanup;
end;

function TSocket.SendBuffer(const BufAddr:Pointer; const BufSize:Integer):Boolean;
var
     i:Integer;
     TimeVal:TTimeVal;
     FDSet:TFDSet;
     Done,ToSend,CurSend:Integer;
begin
     Result:=False;
     if ((Handle = 0) or (BufSize = 0)) then Exit;
     Result:=True;
     Done:=0;
     ToSend:=BufSize;
     while (Result and (ToSend > 0)) do begin
          CurSend:=ToSend;
          if (CurSend > 1024) then CurSend:=1024;
          TimeVal.tv_sec := FWaitWrite;
          TimeVal.tv_usec := 0;
          FD_ZERO(FDSet);
          FD_SET(Handle, FDSet);
          i:=select(0, nil, @FDSet, nil, @TimeVal);
          if (i > 0) then begin
               Result:=(send(Handle, Pointer(Longint(BufAddr) + Done)^, CurSend, 0) = CurSend);
          end else begin
               Result:=False;
          end;
          if Result then begin
               Done:=Done + CurSend;
               ToSend:=ToSend - CurSend;
          end;
     end;
end;

procedure TSocket.Close;
begin
     if (Handle = 0) then Exit;
     shutdown(Handle, 2);
     closesocket(Handle);
     Handle:=0;
end;

function TSocket.TestRead:Boolean;
var
     TimeVal : TTimeVal;
     FDSet   : TFDSet;
begin
     Result:=(Handle <> 0);
     if not Result then Exit;
     TimeVal.tv_sec:=FWaitRead;
     TimeVal.tv_usec:=0;
     FD_ZERO(FDSet);
     FD_SET(Handle, FDSet);
     Result:=(select(0, @FDSet, nil, nil, @TimeVal) > 0);
end;

function TSocket.ReadToBuffer(const BufAddr:Pointer; const BufSize:Integer):Integer;
begin
     Result:=0;
     if TestRead then begin
          Result:=recv(Handle, BufAddr^, BufSize, 0);
     end;
end;

function TSocket.ResolveHost(const HostName:PChar; var HostAddress:TInAddr):Boolean;
var
     HostEnt:PHostEnt;
begin
     HostEnt:=WinSock.gethostbyname(HostName);
     if (HostEnt = nil) then begin
          Result:=False;
     end else begin
          HostAddress.S_un_b.s_b1:=HostEnt^.h_addr^[0];
          HostAddress.S_un_b.s_b2:=HostEnt^.h_addr^[1];
          HostAddress.S_un_b.s_b3:=HostEnt^.h_addr^[2];
          HostAddress.S_un_b.s_b4:=HostEnt^.h_addr^[3];
          Result:=True;
     end;
end;

function TSocket.IsIpDone(const Server:PChar):Boolean;
var
     i:Integer;
     j:Pointer;
     k:Char;
begin
     Result:=True;
     i:=0;
     j:=Server;
     while Result do begin
          k:=PChar(Longint(j) + i)^;
          if (k = #0) then Break;
          Result:=((k = '.') or (k in ['0'..'9']));
          i:=i + 1;
     end;
end;

function TSocket.Connect(const Server:PChar; const Port:Integer):Boolean;
var
     i,j:Integer;
begin
     Result:=False;
     Handle:=WinSock.socket(PF_INET, SOCK_STREAM, IPPROTO_IP);
     if (Handle = -1) then begin
          Handle:=0;
          Exit;
     end;
     ServerAddress.sin_family:=PF_INET;
     ServerAddress.sin_port:=htons(Port);
     if IsIpDone(Server) then begin
          ServerAddress.sin_addr.s_addr:=inet_addr(Server);
     end else begin
          if not ResolveHost(Server, ServerAddress.sin_addr) then begin
               Close;
               Exit;
          end;
     end;
     if (WinSock.connect(Handle, ServerAddress, SizeOf(ServerAddress)) <> 0) then begin
          Close;
     end else begin
          Result:=True;
          i:=1;
          j:=Sizeof(i);
          setsockopt(Handle, IPPROTO_TCP, TCP_NODELAY, @i, j);
     end;
end;

end.