home *** CD-ROM | disk | FTP | other *** search
/ Freelog 11 / Freelog011.iso / BestOf / PhoenixMail / Source / comps / WinSocket.pas < prev    next >
Pascal/Delphi Source File  |  1999-02-20  |  19KB  |  584 lines

  1. {*****************************************************************************
  2.  *
  3.  *  WinSocket.pas - TWinSocket Component
  4.  *
  5.  *  Copyright (c) 1999 Michael Haller
  6.  *
  7.  *  Based on the component from Tom Bradford
  8.  *    (C) 1997 By Beach Dog Software, Inc.
  9.  *    http://www.beachdogsoftware.com
  10.  *  parts copied from Gary Desrosiers
  11.  *
  12.  *  Author:     Michael Haller
  13.  *  E-mail:     michael@discountdrive.com
  14.  *  Homepage:   http://www.discountdrive.com/sunrise/
  15.  *
  16.  *  This program is free software; you can redistribute it and/or
  17.  *  modify it under the terms of the GNU General Public License
  18.  *  as published by the Free Software Foundation;
  19.  *
  20.  *  This program is distributed in the hope that it will be useful,
  21.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  22.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  23.  *  GNU General Public License for more details.
  24.  *
  25.  *  You should have received a copy of the GNU General Public License
  26.  *  along with this program; if not, write to the Free Software
  27.  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
  28.  *
  29.  *----------------------------------------------------------------------------
  30.  *
  31.  *  Revision history:
  32.  *
  33.  *     DATE     REV                 DESCRIPTION
  34.  *  ----------- --- ----------------------------------------------------------
  35.  *
  36.  *****************************************************************************}
  37.  
  38. unit WinSocket;
  39.  
  40. interface
  41.  
  42. uses
  43.   Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  44.   Winsock;
  45.  
  46. const
  47.   WM_ASYNCSELECT = WM_USER + 60;
  48.  
  49. type
  50.   TWinSocket = class;
  51.  
  52.   TOnErrorEvent = procedure(Sender: TObject; Msg: String) of object;
  53.   TOnConnectEvent = procedure(Sender: TObject) of object;
  54.   TOnCloseEvent = procedure(Sender: TObject) of object;
  55.   TOnReadEvent = procedure(Sender: TObject; Value: String) of object;
  56.   TOnWriteEvent = procedure(Sender: TObject; Value: String) of object;
  57.   TOnAcceptEvent = procedure(Sender: TObject) of object;
  58.   TOnAutoAcceptEvent = procedure(Sender: TObject; ListenSocket, OpenSocket: TWinSocket) of object;
  59.  
  60.   TWinSocket = class(TCustomControl)
  61.   private
  62.     FSocket: TSocket;
  63.     FConnected: Boolean;
  64.     FHostName: String;
  65.     FPortName: String;
  66.     FListen: Boolean;
  67.     FAutoAccept: Boolean;
  68.     FOutBuffer: String;
  69.     FInBuffer: String;
  70.     FCharBuf: array[1..32768] of Char;
  71.     FBlocking: Boolean;
  72.     FBlockTime: Integer;
  73.     FOnError: TOnErrorEvent;
  74.     FOnConnect: TOnConnectEvent;
  75.     FOnClose: TOnCloseEvent;
  76.     FOnRead: TOnReadEvent;
  77.     FOnWrite: TOnWriteEvent;
  78.     FOnAccept: TOnAcceptEvent;
  79.     FOnAutoAccept: TOnAutoAcceptEvent;
  80.     procedure SetBlocking(Value: Boolean);
  81.     //private
  82.     function PortLookup(Value: String): U_Short;
  83.     function HostLookup(Value: String): TInAddr;
  84.     procedure SocketError(SockFunc: String; Error: Integer);
  85.   protected
  86.     procedure WMAsyncSelect(var Message: TMessage); message WM_ASYNCSELECT;
  87.     procedure WMPaint(var Message: TWMPaint); message WM_PAINT;
  88.     procedure WMSize(var Message: TWMSize); message WM_SIZE;
  89.   public
  90.     constructor Create(AOwner: TComponent); override;
  91.     destructor Destroy; override;
  92.     procedure Open;
  93.     procedure Listen;
  94.     procedure Close;
  95.     procedure Send(Value: String);
  96.     function Receive: String;
  97.     property Connected: Boolean read FConnected;
  98.     property Socket: TSocket read FSocket;
  99.   published
  100.     property PortName: String read FPortName write FPortName;
  101.     property HostName: String read FHostName write FHostName;
  102.     property AutoAccept: Boolean read FAutoAccept write FAutoAccept;
  103.     property Blocking: Boolean read FBlocking write SetBlocking;
  104.     property BlockTime: Integer read FBlockTime write FBlockTime;
  105.     property OnError: TOnErrorEvent read FOnError write FOnError;
  106.     property OnConnect: TOnConnectEvent read FOnConnect write FOnConnect;
  107.     property OnClose: TOnCloseEvent read FOnClose write FOnClose;
  108.     property OnWrite: TOnWriteEvent read FOnWrite write FOnWrite;
  109.     property OnRead: TOnReadEvent read FOnRead write FOnRead;
  110.     property OnAccept: TOnAcceptEvent read FOnAccept write FOnAccept;
  111.     property OnAutoAccept: TOnAutoAcceptEvent read FOnAutoAccept write FOnAutoAccept;
  112.   end;
  113.  
  114. function GetWinsockDescription: String;
  115. function GetWinsockSystemStatus: String;
  116. function GetLocalHostName: String;
  117.  
  118. procedure Register;
  119.  
  120. implementation
  121.  
  122. type
  123.   TSockThread = class(TThread)
  124.   private
  125.     ParentSocket: TWinSocket;
  126.     ListenSocket: TWinSocket;
  127.     OpenSocket: TWinSocket;
  128.   public
  129.     procedure Execute; override;
  130.     procedure RunThread(ParentSocket, ListenSocket, OpenSocket: TWinSocket);
  131.   end;
  132.  
  133. //const
  134.   //INADDR_NONE: Longint = -1;
  135.  
  136. var
  137.   WSAData: TWSAData;
  138.   IPCache: TStringList;
  139.  
  140. ////////////////////////////////////////////////////////////////////////////////
  141.  
  142. procedure TSockThread.Execute;
  143. begin
  144.   ParentSocket.OnAutoAccept(ParentSocket, ListenSocket, OpenSocket);
  145.   ListenSocket.Close;
  146.   OpenSocket.Close;
  147.   ListenSocket.Free;
  148.   OpenSocket.Free;
  149.   ListenSocket := nil;
  150.   OpenSocket := nil;
  151.   ParentSocket := nil;
  152.   Terminate;
  153. end;
  154.  
  155. procedure TSockThread.RunThread(ParentSocket, ListenSocket, OpenSocket: TWinSocket);
  156. begin
  157.   Self.ParentSocket := ParentSocket;
  158.   Self.ListenSocket := ListenSocket;
  159.   Self.OpenSocket := OpenSocket;
  160.   FreeOnTerminate := True;
  161.   Resume;
  162. end;
  163.  
  164. ////////////////////////////////////////////////////////////////////////////////
  165.  
  166. constructor TWinSocket.Create(AOwner: TComponent);
  167. begin
  168.   inherited Create(AOwner);
  169.   FHostName := '';
  170.   FPortName := '';
  171.   FConnected := False;
  172.   FListen := False;
  173.   FBlocking := True;
  174.   FAutoAccept := False;
  175.   FBlockTime := 0;
  176.   FSocket := INVALID_SOCKET;
  177.   FOutBuffer := '';
  178.   FInBuffer := '';
  179.   if csDesigning in ComponentState then begin
  180.     SetZOrder(True);
  181.   end else begin
  182.     Width := 0;
  183.     Height := 0;
  184.     SetZOrder(False);
  185.     Visible := False;
  186.   end;
  187. end;
  188.  
  189. destructor TWinSocket.Destroy;
  190. begin
  191.   if FListen or FConnected then Close;
  192.   inherited Destroy;
  193. end;
  194.  
  195. procedure TWinSocket.WMSize(var Message: TWMSize);
  196. begin
  197.   inherited;
  198.   if csDesigning in ComponentState then begin
  199.     Width := 120;
  200.     Height := 40;
  201.   end;
  202.   Message.Result := 0;
  203. end;
  204.  
  205. procedure TWinSocket.Send(Value: String);
  206. var
  207.   Remain : Integer;
  208.   S: String;
  209. begin
  210.   if FSocket = INVALID_SOCKET then Exit;
  211.   if FListen then Exit;
  212.   FOutBuffer := FOutBuffer + Value;
  213.   if FOutBuffer = '' then Exit;
  214.   if FBlocking then begin
  215.     Remain := Length(FOutBuffer);
  216.     while Remain > 0 do begin
  217.       S := FOutBuffer;
  218.       Remain := WinSock.Send(FSocket, FOutBuffer[1], Length(FOutBuffer), 0);
  219.       if (Remain = SOCKET_ERROR) and (WinSock.WSAGetLastError <> WSAEINPROGRESS) then begin
  220.         SocketError('Send', WSAGetLastError);
  221.         Exit;
  222.       end;
  223.       if Remain > 0 then Delete(FOutBuffer, 1, Remain);
  224.       Remain := Length(FOutBuffer);
  225.     end;
  226.     FOutBuffer := '';
  227.     if Assigned(FOnWrite) then FOnWrite(Self, S);
  228.   end else begin
  229.     Remain := WinSock.Send(FSocket, FOutBuffer[1], Length(FOutBuffer), 0);
  230.     if Assigned(FOnWrite) then FOnWrite(Self, Copy(FOutBuffer, 1, Remain));
  231.     if Remain > 0 then Delete(FOutBuffer, 1, Remain);
  232.   end;
  233. end;
  234.  
  235. function TWinSocket.Receive: String;
  236. var
  237.   Res: Integer;
  238.   FDSet: PFDSet;
  239.   TV: PTimeVal;
  240. begin
  241.   Result := '';
  242.   if (FSocket = INVALID_SOCKET) and (FInBuffer = '') then Exit;
  243.   if FListen then Exit;
  244.   if FBlocking then begin
  245.     FDSet := New(PFDSet);
  246.     FDSet^.FD_Count := 1;
  247.     FDSet^.FD_Array[0] := FSocket;
  248.     if FBlockTime >= 0 then begin
  249.       TV := New(PTimeVal);
  250.       TV^.tv_sec := FBlockTime;
  251.     end else TV := nil;
  252.     if FConnected and (Select(FSocket, FDSet, nil, nil, TV) > 0) then begin
  253.       Res := Recv(FSocket, FCharBuf, SizeOf(FCharBuf), 0);
  254.       if (Res = SOCKET_ERROR) then begin
  255.         FInBuffer := '';
  256.         Dispose(FDSet);
  257.         Dispose(TV);
  258.         SocketError('Receive', WSAGetLastError);
  259.         Exit;
  260.       end;
  261.       if Res > 0 then FInBuffer := FInBuffer + Copy(FCharBuf, 1, Res);
  262.       if Res = 0 then begin
  263.         Close;
  264.         if Assigned(FOnClose) then FOnClose(Self);
  265.       end;
  266.     end;
  267.     Result := FInBuffer;
  268.     FInBuffer := '';
  269.     Dispose(FDSet);
  270.     Dispose(TV);
  271.   end else begin
  272.     Result := FInBuffer;
  273.     FInBuffer := '';
  274.   end;
  275. end;
  276.  
  277. procedure TWinSocket.WMAsyncSelect(var Message: TMessage);
  278. var
  279.   Error: Word;
  280.   Res, AddrL: Integer;
  281.   Addr: TSockAddrIn;
  282.   ListenSocket, OpenSocket: TWinSocket;
  283.   SockThread : TSockThread;
  284. begin
  285.   inherited;
  286.   Error := WinSock.WSAGetSelectError(Message.LParam);
  287.   if Error > WSABASEERR then begin
  288.     SocketError('WSAAsyncSelect', Error);
  289.     Exit;
  290.   end;
  291.   case WinSock.WSAGetSelectEvent(Message.LParam) of
  292.     FD_ACCEPT: begin
  293.       if FAutoAccept and Assigned(FOnAutoAccept) then begin
  294.         // the main program is responsible to free ListenSocket and...
  295.         // ...OpenSocket in Non Blocking Mode
  296.         ListenSocket := TWinSocket.Create(Self);
  297.         ListenSocket.Parent := Self;
  298.         AddrL := SizeOf(Addr);
  299.         FillChar(Addr, AddrL, #0);
  300.         ListenSocket.FSocket := Accept(FSocket, @Addr, @AddrL);
  301.         ListenSocket.FBlockTime := FBlockTime;
  302.         ListenSocket.FOnRead := FOnRead;
  303.         ListenSocket.FOnWrite := FOnWrite;
  304.         ListenSocket.FOnClose := FOnClose;
  305.         ListenSocket.FOnError := FOnError;
  306.         ListenSocket.FPortname := FPortName;
  307.         ListenSocket.FHostName := INet_NToA(Addr.SIn_Addr);
  308.         ListenSocket.SetBlocking(FBlocking);
  309.         ListenSocket.FConnected := True;
  310.         OpenSocket := TWinSocket.Create(Self);
  311.         OpenSocket.Parent := Self;
  312.         OpenSocket.FBlockTime := FBlockTime;
  313.         OpenSocket.FOnError := FOnError;
  314.         OpenSocket.SetBlocking(FBlocking);
  315.         if FBlocking then begin
  316.           SockThread := TSockThread.Create(True);
  317.           SockThread.RunThread(Self, ListenSocket, OpenSocket);
  318.         end else
  319.           FOnAutoAccept(Self, ListenSocket, OpenSocket);
  320.       end else
  321.         if Assigned(FOnAccept) then FOnAccept(Self);
  322.     end;
  323.     FD_CONNECT: begin
  324.       FConnected := True;
  325.       if Assigned(FOnConnect) then FOnConnect(Self);
  326.     end;
  327.     FD_CLOSE: begin
  328.       Close;
  329.       if Assigned(FOnClose) then FOnClose(Self);
  330.     end;
  331.     FD_WRITE: if FOutBuffer <> '' then Send('');
  332.     FD_READ: begin
  333.       Res := Recv(FSocket, FCharBuf, SizeOf(FCharBuf), 0);
  334.       if Res > 0 then begin
  335.         FInBuffer := FInBuffer + Copy(FCharBuf, 1, Res);
  336.         if Assigned(FOnRead) then FOnRead(Self, Copy(FCharBuf, 1, Res));
  337.       end;
  338.     end;
  339.   end;
  340.   Message.Result := 0;
  341. end;
  342.  
  343. procedure TWinSocket.WMPaint(var Message: TWMPaint);
  344. begin
  345.   inherited;
  346.   if csDesigning in ComponentState then begin
  347.     Canvas.Brush.Color := clBtnFace;
  348.     Canvas.Pen.Color := clBlack;
  349.     Canvas.RectAngle(0, 0, Width, Height);
  350.     Canvas.TextOut(4, 4, 'TWinSocket');
  351.     Canvas.TextOut(4, 20, '(c) 1999 Michael Haller');
  352.   end;
  353.   Message.Result := 0;
  354. end;
  355.  
  356. function TWinSocket.PortLookup(Value: String): U_Short;
  357. var
  358.   PEnt: PServEnt;
  359. begin
  360.   Result := 0;
  361.   if Pos(Value[1], '0123456789') > 0 then Result := HToNS(StrToInt(Value)) else begin
  362.     PEnt := WinSock.GetServByName(PChar(Value), PChar('tcp'));
  363.     if PEnt <> nil then Result := PEnt^.S_Port else SocketError('GetServByName', WSAGetLastError);
  364.   end;
  365. end;
  366.  
  367. function TWinSocket.HostLookup(Value: String): TInAddr;
  368. type
  369.   PLongInt = ^Longint;
  370. var
  371.   PHost: PHostEnt;
  372.   Res: Integer;
  373. begin
  374.    Result.S_Addr := HToNL(INADDR_ANY);
  375.    if Value = '' then Exit;
  376.    FillChar(Result, SizeOf(TInAddr), #0);
  377.    if Pos(Value[1],'0123456789') > 0 then Result := TInAddr(WinSock.Inet_Addr(PChar(Value))) else begin
  378.      Res := IPCache.IndexOf(Value);
  379.      if Res >= 0 then Result.S_Addr := U_Long(IPCache.Objects[Res]) else begin
  380.        PHost := GetHostByName(PChar(Value));
  381.        if PHost <> nil then begin
  382.          Result.S_Addr := Longint(PLongInt(PHost^.H_Addr_List^)^);
  383.          IPCache.AddObject(Value, Pointer(Result.S_Addr));
  384.        end else SocketError('GetHostByName', WSAGetLastError);
  385.      end;
  386.    end;
  387. end;
  388.  
  389. procedure TWinSocket.SetBlocking(Value: Boolean);
  390. var
  391.   I: U_Long;
  392. begin
  393.   if (not (csDesigning in ComponentState)) and (csReading in ComponentState) then begin
  394.     FBlocking := Value;
  395.     Exit;
  396.   end;
  397.   if FSocket = INVALID_SOCKET then FBlocking := Value else begin
  398.     FBlocking := Value;
  399.     if Parent = nil then begin
  400.       Parent := Screen.Forms[0];
  401.       HandleNeeded;
  402.     end;
  403.     if FBlocking and (FListen = False) then begin
  404.       //WSAAsyncSelect(FSocket, Handle, WM_ASYNCSELECT, 0);
  405.       //I := 0;
  406.       //IOCtlSocket(FSocket, FIONBIO, I);
  407.     end else begin
  408.       if FListen then I := FD_ACCEPT else I := FD_READ or FD_CLOSE or FD_CONNECT or FD_WRITE or FD_READ;
  409.       WSAAsyncSelect(FSocket, Handle, WM_ASYNCSELECT, I);
  410.     end;
  411.   end;
  412. end;
  413.  
  414. procedure TWinSocket.Open;
  415. var
  416.   Res: Integer;
  417.   FSockAddrIn: TSockAddrIn;
  418. begin
  419.   FConnected := False;
  420.   if FSocket <> INVALID_SOCKET then Exit;
  421.   FSocket := WinSock.Socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
  422.   SetBlocking(FBlocking);
  423.   FSockAddrIn.SIn_Family := AF_INET;
  424.   FSockAddrIn.SIn_Port := PortLookup(FPortName);
  425.   FSockAddrIn.SIn_Addr := HostLookup(FHostName);
  426.   Res := Connect(FSocket, FSockAddrIn, SizeOf(TSockAddrIn));
  427.   if FBlocking = False then Exit;
  428.   if Res = 0 then begin
  429.     FConnected := True;
  430.     if Assigned(FOnConnect) then FOnConnect(Self);
  431.   end else begin
  432.     SocketError('Connect', WSAGetLastError);
  433.     Close;
  434.   end;
  435. end;
  436.  
  437. procedure TWinSocket.Close;
  438. begin
  439.   WSACancelBlockingCall;
  440.   ShutDown(FSocket, 2);
  441.   if FBlocking = False then
  442.     try WSAAsyncSelect(FSocket, Handle, WM_ASYNCSELECT, 0); except end;
  443.   CloseSocket(FSocket);
  444.   FSocket := INVALID_SOCKET;
  445.   FConnected := False;
  446.   FListen := False;
  447. end;
  448.  
  449. procedure TWinSocket.Listen;
  450. var
  451.   Addr: TSockAddr;
  452. begin
  453.   FSocket := WinSock.Socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
  454.   FillChar(Addr, SizeOf(Addr), #0);
  455.   Addr.SIn_Family := AF_INET;
  456.   Addr.SIn_Port := PortLookup(FPortName);
  457.   Addr.SIn_Addr.S_Addr := HToNL(INADDR_ANY);
  458.   FListen := True;
  459.   SetBlocking(FBlocking);
  460.   FListen := False;
  461.   if Bind(FSocket, Addr, SizeOf(Addr)) <> 0 then begin
  462.     SocketError('Bind', WSAGetLastError);
  463.     Exit;
  464.   end;
  465.   if Winsock.Listen(FSocket, 5) <> 0 then begin
  466.     SocketError('Listen', WSAGetLastError);
  467.     Exit;
  468.   end;
  469.   FListen := True;
  470. end;
  471.  
  472. procedure TWinSocket.SocketError(SockFunc: String; Error: Integer);
  473. var
  474.   S: String;
  475. begin
  476.   case Error of
  477.     WSAEINTR: S := 'Interrupted system call';
  478.     WSAEBADF: S := 'Bad file number';
  479.     WSAEACCES: S := 'Permission denied';
  480.     WSAEFAULT: S := 'Bad address';
  481.     WSAEINVAL: S := 'Invalid argument';
  482.     WSAEMFILE: S := 'Too many open files';
  483.     WSAEWOULDBLOCK: S := 'Operation would block, but socket in nonblock mode';
  484.     WSAEINPROGRESS: S := 'Operation now in progress';
  485.     WSAEALREADY: S := 'Operation already in progress';
  486.     WSAENOTSOCK: S := 'Socket operation on non-socket';
  487.     WSAEDESTADDRREQ: S := 'Destination address required';
  488.     WSAEMSGSIZE: S := 'Message too long';
  489.     WSAEPROTOTYPE: S := 'Protocol wrong type for socket';
  490.     WSAENOPROTOOPT: S := 'Protocol not available';
  491.     WSAEPROTONOSUPPORT: S := 'Protocol not supported';
  492.     WSAESOCKTNOSUPPORT: S := 'Socket type not supported';
  493.     WSAEOPNOTSUPP: S := 'Operation not supported on socket';
  494.     WSAEPFNOSUPPORT: S := 'Protocol family not supported';
  495.     WSAEAFNOSUPPORT: S := 'Address family not supported by protocol family';
  496.     WSAEADDRINUSE: S := 'Address already in use';
  497.     WSAEADDRNOTAVAIL: S := 'Can''t assign requested address';
  498.     WSAENETDOWN: S := 'Network is down';
  499.     WSAENETUNREACH: S := 'Network is unreachable';
  500.     WSAENETRESET: S := 'Network dropped connection on reset';
  501.     WSAECONNABORTED: S := 'Software caused connection abort';
  502.     WSAECONNRESET: S := 'Connection reset by peer';
  503.     WSAENOBUFS: S := 'No buffer space available';
  504.     WSAEISCONN: S := 'Socket is already connected';
  505.     WSAENOTCONN: S := 'Socket is not connected';
  506.     WSAESHUTDOWN: S := 'Can''t send after socket ShutDown';
  507.     WSAETOOMANYREFS: S := 'Too many references: can''t splice';
  508.     WSAETIMEDOUT: S := 'Connection timed out';
  509.     WSAECONNREFUSED: S := 'Connection refused';
  510.     WSAELOOP: S := 'Too many levels of symbolic links';
  511.     WSAENAMETOOLONG: S := 'File name too long';
  512.     WSAEHOSTDOWN: S := 'Host is down';
  513.     WSAEHOSTUNREACH: S := 'No route to host';
  514.     WSAENOTEMPTY: S := 'Directory not empty';
  515.     WSAEPROCLIM: S := 'Too many processes';
  516.     WSAEUSERS: S := 'Too many users';
  517.     WSAEDQUOT: S := 'Disk quota exceeded';
  518.     WSAESTALE: S := 'Stale NFS file handle';
  519.     WSAEREMOTE: S := 'Too many levels of remote in path';
  520.     WSASYSNOTREADY: S := 'WinSock DLL not found, or not responding';
  521.     WSAVERNOTSUPPORTED: S := 'Your WinSock DLL is an old version';
  522.     WSANOTINITIALISED: S := 'WinSock has not yet been initialized';
  523.     WSAHOST_NOT_FOUND: S := 'Host not found';
  524.     WSATRY_AGAIN: S := 'Host not found';
  525.     WSANO_RECOVERY: S := 'Non-recoverable error';
  526.     WSANO_DATA: S := 'No Data; perhaps no route to host';
  527.     else S := 'Error undefined in WinSock v1.1 spec';
  528.   end;
  529.   if SockFunc = '' then S := S else S := 'Code '+IntToStr(Error)+' in function '+SockFunc+#13+#10+S;
  530.   if Assigned(FOnError) then FOnError(Self, S) else raise Exception.Create(S);
  531. end;
  532.  
  533. ////////////////////////////////////////////////////////////////////////////////
  534.  
  535. function GetWinsockDescription: String;
  536. begin
  537.   Result := StrPas(WSAData.szDescription);
  538. end;
  539.  
  540. function GetWinsockSystemStatus: String;
  541. begin
  542.   Result := StrPas(WSAData.szSystemStatus);
  543. end;
  544.  
  545. function GetLocalHostName: String;
  546. var
  547.   szHostName: array[0..255] of char;
  548.   pHost: PHostEnt;
  549.   addr: TSockAddrIn;
  550.   Paddr: ^TSockAddrIn;
  551.   LocalHName: String;
  552. begin
  553.   GetHostName(szHostName, 255);
  554.   pHost := GetHostByName(szHostName);
  555.   if pHost = nil then
  556.     Result := 'localhost'
  557.   else begin
  558.     LocalHName := StrPas(pHost^.h_name);
  559.     if Length(LocalHName) = 0 then Result := 'localhost' else begin
  560.       addr.sin_addr.s_addr := longint(pLongInt(pHost^.h_addr_list^)^);
  561.       Paddr:= @addr.sin_addr.s_addr;
  562.       pHost := GetHostByAddr(pLongInt(Paddr), 4, PF_INET);
  563.       if pHost = nil then Result := LocalHName else Result:= StrPas(pHost^.h_name);
  564.     end;
  565.   end;
  566. end;
  567.  
  568. procedure Register;
  569. begin
  570.    RegisterComponents('Phoenix', [TWinSocket]);
  571. end;
  572.  
  573. ////////////////////////////////////////////////////////////////////////////////
  574.  
  575. initialization
  576.   if WSAStartup($101, WSAData) <> 0 then raise Exception.Create('Could Not Initialize WinSock');
  577.   IPCache := TStringList.Create;
  578.  
  579. finalization
  580.   IPCache.Free;
  581.   WSACleanup;
  582.  
  583. end.
  584.