WSOCKET.PAS
上传用户:xdgkgcw
上传日期:2007-01-04
资源大小:92k
文件大小:177k
源码类别:

Delphi控件源码

开发平台:

WINDOWS

  1.            bMore := FALSE;
  2.         end;
  3.     end;
  4. end;
  5. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  6. procedure TCustomWSocket.WMASyncSelect(var msg: TMessage);
  7. var
  8.     Check  : Word;
  9. begin
  10. {TriggerDisplay('AsyncSelect ' + IntToStr(msg.wParam) + ', ' + IntToStr(msg.lParamLo));}
  11.     { Verify that the socket handle is ours handle }
  12.     if msg.wParam <> FHSocket then
  13.         Exit;
  14.     if FPaused then
  15.         exit;
  16.     Check := msg.lParamLo and FD_CONNECT;
  17.     if Check <> 0 then begin
  18.         ChangeState(wsConnected);
  19.         TriggerSessionConnected(msg.lParamHi);
  20.         if (msg.lParamHi <> 0) and (FState <> wsClosed) then
  21.             Close;
  22.     end;
  23.     Check := msg.lParamLo and FD_READ;
  24.     if Check <> 0 then begin
  25.         ASyncReceive(msg.lParamHi);
  26.     end;
  27.     Check := msg.lParamLo and FD_WRITE;
  28.     if Check <> 0 then begin
  29.         TryToSend;
  30. { If you wants to test background exception, uncomment the next 2 lines. }
  31. {        if bAllSent then                                                }
  32. {            raise Exception.Create('Test TWSocket exception');          }
  33.         if bAllSent then
  34.             TriggerDataSent(msg.lParamHi);
  35.     end;
  36.     Check := msg.lParamLo and FD_ACCEPT;
  37.     if Check <> 0 then begin
  38.         TriggerSessionAvailable(msg.lParamHi);
  39.     end;
  40.     Check := msg.lParamLo and FD_CLOSE;
  41.     if Check <> 0 then begin
  42.         {* In some strange situations I found that we receive a FD_CLOSE *}
  43.         {* during the connection phase, breaking the connection early !  *}
  44.         {* This occurs for example after a failed FTP transfert          *}
  45.         if FState <> wsConnecting then begin
  46.             {* Check if we have something arrived, if yes, process it *}
  47.             ASyncReceive(0);
  48.             if Assigned(FOnSessionClosed) and (not FCloseInvoked) then begin
  49.                 FCloseInvoked := TRUE;
  50.                 TriggerSessionClosed(msg.lParamHi);
  51.             end;
  52.             if FState <> wsClosed then
  53.                 Close;
  54.         end;
  55.     end;
  56. end;
  57. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  58. procedure GetIPList(phe  : PHostEnt; ToList : TStrings);
  59. type
  60.     TaPInAddr = array [0..255] of PInAddr;
  61.     PaPInAddr = ^TaPInAddr;
  62. var
  63.     pptr : PaPInAddr;
  64.     I    : Integer;
  65. begin
  66.     pptr := PaPInAddr(Phe^.h_addr_list);
  67.     I := 0;
  68.     while pptr^[I] <> nil do begin
  69.         ToList.Add(StrPas(WSocket_inet_ntoa(pptr^[I]^)));
  70.         Inc(I);
  71.     end;
  72. end;
  73. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  74. procedure TCustomWSocket.WMAsyncGetHostByName(var msg: TMessage);
  75. var
  76.     Phe     : Phostent;
  77.     Error   : Word;
  78. begin
  79.     if msg.wParam <> LongInt(FDnsLookupHandle) then
  80.         Exit;
  81.     FDnsLookupHandle := 0;
  82.     Error := Msg.LParamHi;
  83.     if Error = 0 then begin
  84.         Phe        := PHostent(@FDnsLookupBuffer);
  85.         if phe <> nil then begin
  86.             GetIpList(Phe, FDnsResultList);
  87.             FDnsResult := FDnsResultList.Strings[0];
  88.         end;
  89.     end;
  90.     TriggerDnsLookupDone(Error);
  91. end;
  92. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  93. procedure TCustomWSocket.WMAsyncGetHostByAddr(var msg: TMessage);
  94. var
  95.     Phe   : Phostent;
  96.     Error : Word;
  97. begin
  98.     if msg.wParam <> LongInt(FDnsLookupHandle) then
  99.         Exit;
  100.     FDnsLookupHandle := 0;
  101.     Error            := Msg.LParamHi;
  102.     if Error = 0 then begin
  103.         Phe := PHostent(@FDnsLookupBuffer);
  104.         if phe <> nil then begin
  105.             SetLength(FDnsResult, StrLen(Phe^.h_name));
  106.             StrCopy(@FDnsResult[1], Phe^.h_name);
  107.             FDnsResultList.Clear;
  108.             FDnsResultList.Add(FDnsResult);
  109.         end;
  110.     end;
  111.     TriggerDnsLookupDone(Error);
  112. end;
  113. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  114. procedure TCustomWSocket.SetProto(sProto : String);
  115. begin
  116.     if FProtoAssigned and (sProto = FProtoStr) then
  117.         Exit;
  118.     if FState <> wsClosed then begin
  119.         RaiseException('Cannot change Proto if not closed');
  120.         Exit;
  121.     end;
  122.     FProtoStr := Trim(sProto);
  123.     if Length(FProtoStr) = 0 then begin
  124.         FProtoAssigned := FALSE;
  125.         Exit;
  126.     end;
  127.     FProtoResolved := FALSE;
  128.     FProtoAssigned := TRUE;
  129. end;
  130. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  131. function TCustomWSocket.GetProto : String;
  132. begin
  133.     Result := FProtoStr;
  134. end;
  135. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  136. procedure TCustomWSocket.SetRemotePort(sPort : String);
  137. begin
  138.     if FPortAssigned and (FPortStr = sPort) then
  139.         Exit;
  140.     if FState <> wsClosed then begin
  141.         RaiseException('Cannot change Port if not closed');
  142.         Exit;
  143.     end;
  144.     FPortStr := Trim(sPort);
  145.     if Length(FPortStr) = 0 then begin
  146.         FPortAssigned := FALSE;
  147.         Exit;
  148.     end;
  149.     FPortResolved := FALSE;
  150.     FPortAssigned := TRUE;
  151. end;
  152. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  153. function TCustomWSocket.GetRemotePort : String;
  154. begin
  155.     Result := FPortStr;
  156. end;
  157. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  158. procedure TCustomWSocket.SetLocalPort(sLocalPort : String);
  159. begin
  160.     if FState <> wsClosed then begin
  161.         RaiseException('Cannot change LocalPort if not closed');
  162.         Exit;
  163.     end;
  164.     FLocalPortStr      := sLocalPort;
  165.     FLocalPortResolved := FALSE;
  166. end;
  167. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  168. function TCustomWSocket.GetXPort: string;
  169. var
  170.     saddr    : TSockAddrIn;
  171.     saddrlen : integer;
  172.     port     : integer;
  173. begin
  174.     Result := 'error';
  175.     if FState in [wsConnected, wsBound, wsListening] then begin
  176.         saddrlen := sizeof(saddr);
  177.         if WSocket_GetSockName(FHSocket, TSockAddr(saddr), saddrlen) = 0 then begin
  178.             port     := WSocket_ntohs(saddr.sin_port);
  179.             Result   := Format('%d',[port]);
  180.         end;
  181.     end;
  182. end;
  183. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  184. procedure TCustomWSocket.SetAddr(InAddr : String);
  185. begin
  186.     if FAddrAssigned and (FAddrStr = InAddr) then
  187.         Exit;
  188.     if FState <> wsClosed then begin
  189.         RaiseException('Cannot change Addr if not closed');
  190.         Exit;
  191.     end;
  192.     FAddrStr := Trim(InAddr);
  193.     if Length(FAddrStr) = 0 then begin
  194.         FAddrAssigned := FALSE;
  195.         Exit;
  196.     end;
  197.     FAddrResolved       := FALSE;
  198.     FAddrAssigned       := TRUE;
  199. end;
  200. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  201. function WSocketResolveHost(InAddr : String) : TInAddr;
  202. var
  203.     szData  : array [0..256] of char;
  204.     Phe     : Phostent;
  205.     IPAddr  : u_long;
  206. begin
  207.     if (Length(InAddr) = 0) or (Length(InAddr) >= SizeOf(szData)) then
  208.         raise ESocketException.Create('WSocketResolveHost: ''' + InAddr + ''' Invalid Hostname.');
  209.     StrPCopy(szData, Trim(InAddr));
  210. {    if not DllStarted then
  211.         LoadWinsock(WINSOCKET);   14/02/99 }
  212.     if IsDigit(szData[0]) then begin
  213.         { Address is a dotted numeric address like 192.161.124.32 }
  214.         IPAddr := WSocket_inet_addr(szData);
  215. {$IFDEF VER80}
  216.         { With Trumpet Winsock 2B and 30D (win 3.11), inet_addr returns faulty }
  217.         { results for 0.0.0.0                                                  }
  218.         if (IPAddr = INADDR_NONE) and (StrComp(szData, '0.0.0.0') = 0) then begin
  219.             Result.s_addr := 0;
  220.             Exit;
  221.         end;
  222. {$ENDIF}
  223.         if IPAddr = u_long(INADDR_NONE) then begin
  224.             if StrComp(szData, '255.255.255.255') = 0 then begin
  225.                 Result.s_addr := u_long(INADDR_BROADCAST);
  226.                 Exit;
  227.             end;
  228.             raise ESocketException.Create('WSocketResolveHost: ''' + InAddr + ''' Invalid IP address.');
  229.         end;
  230.         Result.s_addr := IPAddr;
  231.         Exit;
  232.     end;
  233.     { Address is a hostname }
  234.     Phe := WSocket_GetHostByName(szData);
  235.     if Phe = nil then
  236.         raise ESocketException.CreateFmt(
  237.                  'WSocketResolveHost: Cannot convert host address ''%s''',
  238.                  [InAddr]);
  239.     Result.s_addr := PInAddr(Phe^.h_addr_list^)^.s_addr;
  240. end;
  241. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  242. { Convert port name or number to number in host order (ftp -> 21)           }
  243. function WSocketResolvePort(Port : String; Proto : String) : Word;
  244. var
  245.     szPort   : array [0..31] of char;
  246.     szProto  : array [0..31] of char;
  247.     Pse      : Pservent;
  248. begin
  249.     if (Length(Port) = 0) or (Length(Port) >= SizeOf(szPort)) then
  250.         raise ESocketException.Create('WSocketResolvePort: Invalid Port.');
  251.     if IsDigit(Port[1]) then
  252.         Result := atoi(Port)
  253.     else begin
  254.         StrPCopy(szPort, Trim(Port));
  255.         StrPCopy(szProto, Trim(Proto));
  256. {        if not DllStarted then
  257.             LoadWinsock(WINSOCKET); 14/02/99 }
  258.         if szProto[0] = #0 then
  259.             Pse := WSocket_GetServByName(szPort, nil)
  260.         else
  261.             Pse := WSocket_GetServByName(szPort, szProto);
  262.         if Pse = nil then
  263.             raise ESocketException.CreateFmt(
  264.                      'WSocketResolvePort: Cannot convert port ''%s''',
  265.                      [Port]);
  266.         Result := WSocket_ntohs(Pse^.s_port);
  267.     end;
  268. end;
  269. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  270. function WSocketResolveProto(sProto : String) : integer;
  271. var
  272.     szProto : array [0..31] of char;
  273.     Ppe     : Pprotoent;
  274. begin
  275.     if (Length(sProto) = 0) or (Length(sProto) >= SizeOf(szProto)) then
  276.         raise ESocketException.Create('WSocketResolveProto: Invalid Protocol.');
  277.     sProto := Trim(sProto);
  278.     if IsDigit(sProto[1]) then
  279.         Result := atoi(sProto)
  280.     else begin
  281.         StrPCopy(szProto, sProto);
  282. {        if not DllStarted then
  283.             LoadWinsock(WINSOCKET); 14/02/99 }
  284.         ppe := WSocket_getprotobyname(szProto);
  285.         if Ppe = nil then
  286.             raise ESocketException.CreateFmt(
  287.                       'WSocketResolveProto: Cannot convert protocol ''%s''',
  288.                       [sProto]);
  289.         Result := ppe^.p_proto;
  290.     end;
  291. end;
  292. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  293. function TCustomWSocket.GetAddr : String;
  294. begin
  295.     Result := FAddrStr;
  296. end;
  297. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  298. function TCustomWSocket.GetSockName(var saddr : TSockAddrIn; var saddrlen : Integer) : integer;
  299. begin
  300.     Result := WSocket_GetSockName(FHSocket, TSockAddr(saddr), saddrlen);
  301. end;
  302. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  303. function TCustomWSocket.GetPeerAddr: string;
  304. var
  305.     saddr    : TSockAddrIn;
  306.     saddrlen : integer;
  307.     szAddr   : PChar;
  308. begin
  309.     Result := 'error';
  310.     if FState = wsConnected then begin
  311.         saddrlen := sizeof(saddr);
  312.         if WSocket_GetPeerName(FHSocket, TSockAddr(saddr), saddrlen) = 0 then begin
  313.             szAddr := WSocket_inet_ntoa(saddr.sin_addr);
  314.             Result := StrPas(szAddr);
  315.         end
  316.         else begin
  317.             SocketError('GetPeerName');
  318.             Exit;
  319.         end;
  320.     end;
  321. end;
  322. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  323. function TCustomWSocket.GetPeerPort: string;
  324. var
  325.     saddr    : TSockAddrIn;
  326.     saddrlen : integer;
  327. begin
  328.     Result := 'error';
  329.     if FState = wsConnected then begin
  330.         saddrlen := sizeof(saddr);
  331.         if WinSock.GetPeerName(FHSocket, TSockAddr(saddr), saddrlen) = 0 then
  332.             Result := IntToStr(ntohs(saddr.sin_port))
  333.         else begin
  334.             SocketError('GetPeerPort');
  335.             Exit;
  336.         end;
  337.     end;
  338. end;
  339. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  340. function TCustomWSocket.GetPeerName(var Name : TSockAddrIn; NameLen : Integer) : integer;
  341. begin
  342.     if FState = wsConnected then
  343.         Result := WSocket_GetPeerName(FHSocket, TSockAddr(Name), NameLen)
  344.     else
  345.         Result := SOCKET_ERROR;
  346. end;
  347. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  348. procedure TCustomWSocket.CancelDnsLookup;
  349. begin
  350.     if FDnsLookupHandle = 0 then
  351.         Exit;
  352.     if WSocket_WSACancelAsyncRequest(FDnsLookupHandle) <> 0 then begin
  353.         FDnsLookupHandle := 0;
  354.         SocketError('WSACancelAsyncRequest');
  355.         Exit;
  356.     end;
  357.     FDnsLookupHandle := 0;
  358.     if not (csDestroying in ComponentState) then
  359.         TriggerDnsLookupDone(WSAEINTR);
  360. end;
  361. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  362. procedure TCustomWSocket.DnsLookup(HostName : String);
  363. var
  364.     IPAddr  : TInAddr;
  365. begin
  366.     if HostName = '' then begin
  367.         RaiseException('DNS lookup: invalid host name.');
  368.         TriggerDnsLookupDone(WSAEINVAL);
  369.         Exit;
  370.     end;
  371.     { Cancel any pending lookup }
  372.     if FDnsLookupHandle <> 0 then
  373.         WSocket_WSACancelAsyncRequest(FDnsLookupHandle);
  374.     FDnsResult := '';
  375.     FDnsResultList.Clear;
  376. {$IFDEF VER80}
  377.     { Delphi 1 do not automatically add a terminating nul char }
  378.     HostName := HostName + #0;
  379. {$ENDIF}
  380.     IPAddr.S_addr := WSocket_inet_addr(@HostName[1]);
  381.     if IPAddr.S_addr <> u_long(INADDR_NONE) then begin
  382.         FDnsResult := StrPas(WSocket_inet_ntoa(IPAddr));
  383.         TriggerDnsLookupDone(0);
  384.         Exit;
  385.     end;
  386.     FDnsLookupHandle := WSocket_WSAAsyncGetHostByName(
  387.                             FWindowHandle,
  388.                             WM_ASYNCGETHOSTBYNAME,
  389.                             @HostName[1],
  390.                             @FDnsLookupBuffer,
  391.                             SizeOf(FDnsLookupBuffer));
  392.     if FDnsLookupHandle = 0 then begin
  393.         RaiseExceptionFmt(
  394.                   '%s: can''t start DNS lookup, error #%d',
  395.                   [HostName, WSocket_WSAGetLastError]);
  396.         Exit;
  397.     end;
  398. end;
  399. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  400. procedure TCustomWSocket.ReverseDnsLookup(HostAddr: String);
  401. var
  402.     szAddr : array [0..256] of Char;
  403.     lAddr  : u_long;
  404. begin
  405.     if HostAddr = '' then begin
  406.         RaiseException('DNS lookup: invalid host name.');
  407.         TriggerDnsLookupDone(WSAEINVAL);
  408.         Exit;
  409.     end;
  410.     { Cancel any pending lookup }
  411.     if FDnsLookupHandle <> 0 then
  412.         WSocket_WSACancelAsyncRequest(FDnsLookupHandle);
  413.     FDnsResult := '';
  414.     FDnsResultList.Clear;
  415.     StrPCopy(szAddr, HostAddr);
  416.     lAddr := WSocket_inet_addr(szAddr);
  417.     FDnsLookupHandle := WSocket_WSAAsyncGetHostByAddr(
  418.                             FWindowHandle,
  419.                             WM_ASYNCGETHOSTBYADDR,
  420.                             PChar(@lAddr), 4, PF_INET,
  421.                             @FDnsLookupBuffer,
  422.                             SizeOf(FDnsLookupBuffer));
  423.     if FDnsLookupHandle = 0 then
  424.         RaiseExceptionFmt('%s: can''t start DNS lookup, error #%d',
  425.                           [HostAddr, WSocket_WSAGetLastError]);
  426. end;
  427. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  428. procedure TCustomWSocket.BindSocket;
  429. var
  430.     SockName      : TSockAddr;
  431.     SockNamelen   : Integer;
  432.     LocalSockName : TSockAddrIn;
  433. begin
  434.     FillChar(LocalSockName, Sizeof(LocalSockName), 0);
  435.     SockNamelen                   := sizeof(LocalSockName);
  436.     LocalSockName.sin_family      := AF_INET;
  437.     LocalSockName.sin_port        := WSocket_htons(FLocalPortNum);
  438.     LocalSockName.sin_addr.s_addr := INADDR_ANY;
  439.     if WSocket_bind(HSocket, LocalSockName, SockNamelen) <> 0 then begin
  440.         RaiseExceptionFmt('winsock.bind failed, error #%d', [WSocket_WSAGetLastError]);
  441.         Exit;
  442.     end;
  443.     SockNamelen := sizeof(SockName);
  444.     if WSocket_getsockname(FHSocket, SockName, SockNamelen) <> 0 then begin
  445.         RaiseExceptionFmt('winsock.getsockname failed, error #%d',
  446.                           [WSocket_WSAGetLastError]);
  447.         Exit;
  448.     end;
  449. {    FLocalPort := ntohs(SockName.sin_port); }
  450.     FLocalPortNum := WSocket_ntohs(SockName.sin_port);
  451.     FLocalPortStr := IntToStr(FLocalPortNum);
  452. end;
  453. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  454. procedure TCustomWSocket.SetLingerOption;
  455. var
  456.     iStatus : integer;
  457.     li      : TLinger;
  458. begin
  459.     if FLingerOnOff = wsLingerNoSet then
  460.         Exit;                            { Option set is disabled, ignore }
  461.     if FHSocket = INVALID_SOCKET then begin
  462.         RaiseException('Cannot set linger option at this time');
  463.         Exit;
  464.     end;
  465.     li.l_onoff  := Ord(FLingerOnOff);    { 0/1 = disable/enable linger }
  466.     li.l_linger := FLingerTimeout;       { timeout in seconds          }
  467.     iStatus     := WSocket_setsockopt(FHSocket, SOL_SOCKET,
  468.                                       SO_LINGER, @li, SizeOf(li));
  469.     if iStatus <> 0 then begin
  470.         SocketError('setsockopt(SO_LINGER)');
  471.         Exit;
  472.     end;
  473. end;
  474. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  475. procedure TCustomWSocket.Connect;
  476. var
  477.     iStatus : integer;
  478.     optval  : integer;
  479. begin
  480.     if (FHSocket <> INVALID_SOCKET) and (FState <> wsClosed) then begin
  481.         RaiseException('Connect: Socket already in use');
  482.         Exit;
  483.     end;
  484.     if  not FPortAssigned then begin
  485.         RaiseException('Connect: No Port Specified');
  486.         Exit;
  487.     end;
  488.     if not FAddrAssigned then begin
  489.         RaiseException('Connect: No IP Address Specified');
  490.         Exit;
  491.     end;
  492.     if not FProtoAssigned then begin
  493.         RaiseException('Connect: No Protocol Specified');
  494.         Exit;
  495.     end;
  496.     try
  497.         if not FProtoResolved then begin
  498.             { The next line will trigger an exception in case of failure }
  499.             FProto := WSocketResolveProto(FProtoStr);
  500.             if FProto = IPPROTO_UDP then
  501.                 FType := SOCK_DGRAM
  502.             else
  503.                 FType := SOCK_STREAM;
  504.             FProtoResolved := TRUE;
  505.         end;
  506.         if not FPortResolved then begin
  507.             { The next line will trigger an exception in case of failure }
  508.             FPortNum      := WSocketResolvePort(FPortStr, GetProto);
  509.             sin.sin_port  := WSocket_htons(FPortNum);
  510.             FPortResolved := TRUE;
  511.         end;
  512.         if not FLocalPortResolved then begin
  513.             { The next line will trigger an exception in case of failure }
  514.             FLocalPortNum      := WSocketResolvePort(FLocalPortStr, GetProto);
  515.             FLocalPortResolved := TRUE;
  516.         end;
  517.         if not FAddrResolved then begin
  518.             { The next line will trigger an exception in case of failure }
  519.             sin.sin_addr.s_addr := WSocketResolveHost(FAddrStr).s_addr;
  520.             FAddrResolved := TRUE;
  521.         end;
  522.     except
  523.         on E:Exception do begin
  524.             RaiseException('connect: ' + E.Message);
  525.             Exit;
  526.         end;
  527.     end;
  528.     { Remove any data from the internal output buffer }
  529.     { (should already be empty !)                     }
  530.     DeleteBufferedData;
  531.     FHSocket := WSocket_socket(FAddrFormat, FType, FProto);
  532.     if FHSocket = INVALID_SOCKET then begin
  533.         SocketError('Connect (socket)');
  534.         Exit;
  535.     end;
  536.     ChangeState(wsOpened);
  537.     if FType = SOCK_DGRAM then begin
  538.         BindSocket;
  539.         if sin.sin_addr.S_addr = u_long(INADDR_BROADCAST) then begin
  540.             OptVal  := 1;
  541.             iStatus := WSocket_setsockopt(FHSocket, SOL_SOCKET, SO_BROADCAST,
  542.                                           PChar(@OptVal), SizeOf(OptVal));
  543.             if iStatus <> 0 then begin
  544.                 SocketError('setsockopt(SO_BROADCAST)');
  545.                 Exit;
  546.             end;
  547.         end;
  548.     end
  549.     else begin
  550.         { Socket type is SOCK_STREAM }
  551.         if FLocalPortNum <> 0 then
  552.             BindSocket;
  553.         SetLingerOption;
  554.         optval  := -1;
  555.         iStatus := WSocket_setsockopt(FHSocket, SOL_SOCKET,
  556.                                       SO_KEEPALIVE, @optval, SizeOf(optval));
  557.         if iStatus <> 0 then begin
  558.             SocketError('setsockopt(SO_KEEPALIVE)');
  559.             Exit;
  560.         end;
  561.         optval  := -1;
  562.         iStatus := WSocket_setsockopt(FHSocket, SOL_SOCKET,
  563.                                       SO_REUSEADDR, @optval, SizeOf(optval));
  564.         if iStatus <> 0 then begin
  565.             SocketError('setsockopt(SO_REUSEADDR)');
  566.             Exit;
  567.         end;
  568.     end;
  569.     iStatus := WSocket_WSAASyncSelect(FHSocket, Handle, WM_ASYNCSELECT,
  570.                                       FD_READ   or FD_WRITE or FD_CLOSE or
  571.                                       FD_ACCEPT or FD_CONNECT);
  572.     if iStatus <> 0 then begin
  573.         SocketError('WSAAsyncSelect');
  574.         Exit;
  575.     end;
  576.     if FType = SOCK_DGRAM then begin
  577.         ChangeState(wsConnected);
  578.         TriggerSessionConnected(0);
  579.     end
  580.     else begin
  581.         iStatus := WSocket_connect(FHSocket, TSockAddr(sin), sizeof(sin));
  582.         if iStatus = 0 then
  583.             ChangeState(wsConnecting)
  584.         else begin
  585.             iStatus := WSocket_WSAGetLastError;
  586.             if iStatus = WSAEWOULDBLOCK then
  587.                 ChangeState(wsConnecting)
  588.             else begin
  589.                 FLastError := WSocket_WSAGetLastError;
  590.                 SocketError('Connect');
  591.                 Exit;
  592.             end;
  593.         end;
  594.     end;
  595. end;
  596. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  597. procedure TCustomWSocket.Listen;
  598. var
  599.     iStatus : integer;
  600. begin
  601.     if not FPortAssigned then begin
  602.         WSocket_WSASetLastError(WSAEINVAL);
  603.         SocketError('listen: port not assigned');
  604.         Exit;
  605.     end;
  606.     if not FProtoAssigned then begin
  607.         WSocket_WSASetLastError(WSAEINVAL);
  608.         SocketError('listen: protocol not assigned');
  609.         Exit;
  610.     end;
  611.     if not FAddrAssigned then begin
  612.         WSocket_WSASetLastError(WSAEINVAL);
  613.         SocketError('listen: address not assigned');
  614.         Exit;
  615.     end;
  616.     try
  617.         if not FProtoResolved then begin
  618.             { The next line will trigger an exception in case of failure }
  619.             FProto := WSocketResolveProto(FProtoStr);
  620.             if FProto = IPPROTO_UDP then
  621.                 FType := SOCK_DGRAM
  622.             else
  623.                 FType := SOCK_STREAM;
  624.             FProtoResolved := TRUE;
  625.         end;
  626.         if not FPortResolved then begin
  627.             { The next line will trigger an exception in case of failure }
  628.             FPortNum      := WSocketResolvePort(FPortStr, GetProto);
  629.             sin.sin_port  := WSocket_htons(FPortNum);
  630.             FPortResolved := TRUE;
  631.         end;
  632.         if not FAddrResolved then begin
  633.             { The next line will trigger an exception in case of failure }
  634.             sin.sin_addr.s_addr := WSocketResolveHost(FAddrStr).s_addr;
  635.             FAddrResolved       := TRUE;
  636.         end;
  637.     except
  638.         on E:Exception do begin
  639.             RaiseException('listen: ' + E.Message);
  640.             Exit;
  641.         end;
  642.     end;
  643.     { Remove any data from the internal output buffer }
  644.     { (should already be empty !)                     }
  645.     DeleteBufferedData;
  646.     FHSocket := WSocket_socket(FAddrFormat, FType, FProto);
  647.     if FHSocket = INVALID_SOCKET then begin
  648.         SocketError('socket');
  649.         exit;
  650.     end;
  651.     iStatus := WSocket_bind(FHSocket, TSockAddr(sin), sizeof(sin));
  652.     if iStatus = 0 then
  653.         ChangeState(wsBound)
  654.     else begin
  655.         SocketError('Bind');
  656.         Close;
  657.         exit;
  658.     end;
  659.     if FType = SOCK_DGRAM then begin
  660.         ChangeState(wsListening);
  661.         ChangeState(wsConnected);
  662.         TriggerSessionConnected(0);
  663.     end
  664.     else if FType = SOCK_STREAM then begin
  665.         iStatus := WSocket_listen(FHSocket, 5);
  666.         if iStatus = 0 then
  667.             ChangeState(wsListening)
  668.         else begin
  669.             SocketError('Listen');
  670.             Exit;
  671.         end;
  672.     end;
  673.     iStatus := WSocket_WSAASyncSelect(FHSocket, Handle, WM_ASYNCSELECT,
  674.                                       FD_READ   or FD_WRITE or
  675.                                       FD_ACCEPT or FD_CLOSE);
  676.     if iStatus <> 0 then begin
  677.         SocketError('WSAASyncSelect');
  678.         exit;
  679.     end;
  680. end;
  681. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  682. function TCustomWSocket.Accept: TSocket; 
  683. var
  684.    len     : integer;
  685. begin
  686.     if FState <> wsListening then begin
  687.         WSocket_WSASetLastError(WSAEINVAL);
  688.         SocketError('not a listening socket');
  689.         Result := INVALID_SOCKET;
  690.         Exit;
  691.     end;
  692.     len := sizeof(sin);
  693. {$IFDEF VER100}
  694.     { Delphi 3 has changed var parameters to pointers }
  695.     FASocket := WSocket_accept(FHSocket, @sin, @len);
  696. {$ELSE}
  697. {$IFDEF VER93}
  698.     { C++Builder 1 has changed var parameters to pointers }
  699.     FASocket := WSocket_accept(FHSocket, @sin, @len);
  700. {$ELSE}
  701. {$IFDEF VER110}
  702.     { C++Builder 3 has changed var parameters to pointers }
  703.     FASocket := WSocket_accept(FHSocket, @sin, @len);
  704. {$ELSE}
  705. {$IFDEF VER120}
  706.     { Delphi 4 has changed var parameters to pointers }
  707.     FASocket := WSocket_accept(FHSocket, @sin, @len);
  708. {$ELSE}
  709. {$IFDEF VER125}
  710.     { C++Builder 4 has changed var parameters to pointers }
  711.     FASocket := WSocket_accept(FHSocket, @sin, @len);
  712. {$ELSE}
  713.     FASocket := WSocket_accept(FHSocket, TSockAddr(sin), len);
  714. {$ENDIF}
  715. {$ENDIF}
  716. {$ENDIF}
  717. {$ENDIF}
  718. {$ENDIF}
  719.     if FASocket = INVALID_SOCKET then begin
  720.         SocketError('Accept');
  721.         Result := INVALID_SOCKET;
  722.         Exit;
  723.     end
  724.     else
  725.         Result := FASocket;
  726. end;
  727. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  728. procedure TCustomWSocket.Pause;
  729. begin
  730.     FPaused := TRUE;
  731.     WSocket_WSAASyncSelect(FHSocket, Handle, 0, 0);
  732. end;
  733. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  734. procedure TCustomWSocket.Resume;
  735. begin
  736.     FPaused := FALSE;
  737.     WSocket_WSAASyncSelect(FHSocket, Handle, WM_ASYNCSELECT,
  738.                            FD_READ or FD_WRITE or FD_CLOSE or FD_CONNECT);
  739. end;
  740. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  741. procedure TCustomWSocket.Shutdown(How : Integer);
  742. begin
  743.     if FHSocket <> INVALID_SOCKET then
  744.         WSocket_shutdown(FHSocket, How);
  745. end;
  746. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  747. procedure TCustomWSocket.DeleteBufferedData;
  748. var
  749.     nItem : Integer;
  750. begin
  751.     { Delete all data buffer }
  752.     for nItem := 0 to FBufList.Count - 1 do
  753.         TBuffer(FBufList.Items[nItem]).Free;
  754.     FBufList.Clear;
  755. end;
  756. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  757. procedure TCustomWSocket.Abort;
  758. begin
  759.     CancelDnsLookup;
  760.     DeleteBufferedData;
  761.     { Be sure to close as fast as possible (abortive close) }
  762.     if (State = wsConnected) and (FProto = IPPROTO_TCP) then begin
  763.         LingerOnOff := wsLingerOff;
  764.         SetLingerOption;
  765.     end;
  766.     InternalClose(FALSE, 0);
  767. end;
  768. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  769. procedure TCustomWSocket.Close;
  770. begin
  771.     InternalClose(TRUE, 0);
  772. end;
  773. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  774. procedure TCustomWSocket.Flush;
  775. begin
  776.     while (FHSocket <> INVALID_SOCKET) and     { No more socket   }
  777.           (not bAllSent) do begin              { Nothing to send  }
  778.             { Break; }
  779.         TryToSend;
  780.         MessagePump;
  781.     end;
  782. end;
  783. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  784. procedure TCustomWSocket.InternalClose(bShut : Boolean; Error : Word);
  785. var
  786.     iStatus : integer;
  787. {    Buffer  : array [0..127] of Char; }
  788. begin
  789.     if FHSocket = INVALID_SOCKET then begin
  790.         if FState <> wsClosed then begin
  791.             ChangeState(wsClosed);
  792.             AssignDefaultValue;
  793.         end;
  794.         exit;
  795.     end;
  796.     if FState = wsClosed then
  797.         Exit;
  798. { 11/10/98 called shutdown(1) instead of shutdonw(2). This disable only     }
  799. { reception. Disabling data send produced data lost is some cases. For      }
  800. { example when a client open the connection, send some data fast then close }
  801. { the connection immediately, even using the linger option.                 }
  802.     if bShut then
  803.         ShutDown(1);
  804.     if FHSocket <> INVALID_SOCKET then begin
  805.         repeat
  806.             { Close the socket }
  807.             iStatus := WSocket_closesocket(FHSocket);
  808.             FHSocket := INVALID_SOCKET;
  809.             if iStatus <> 0 then begin
  810.                 FLastError := WSocket_WSAGetLastError;
  811.                 if FLastError <> WSAEWOULDBLOCK then begin
  812.                     { Ignore the error occuring when winsock DLL not      }
  813.                     { initialized (occurs when using TWSocket from a DLL) }
  814.                     if FLastError = WSANOTINITIALISED then
  815.                         break;
  816.                     SocketError('Disconnect (closesocket)');
  817.                     Exit;
  818.                 end;
  819.                 MessagePump;
  820.             end;
  821.         until iStatus = 0;
  822.     end;
  823.     ChangeState(wsClosed);
  824.     if (not (csDestroying in ComponentState)) and
  825.        (not FCloseInvoked) and Assigned(FOnSessionClosed) then begin
  826.         FCloseInvoked := TRUE;
  827.         TriggerSessionClosed(Error);
  828.     end;
  829.     { 29/09/98 Protect AssignDefaultValue because SessionClosed event handler }
  830.     { may have destroyed the component.                                       }
  831.     try
  832.         AssignDefaultValue;
  833.     except
  834.     end;
  835. end;
  836. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  837. procedure TCustomWSocket.WaitForClose;
  838. var
  839.     lCount    : LongInt;
  840.     Status    : Integer;
  841.     Ch        : Char;
  842. begin
  843.     while (FHSocket <> INVALID_SOCKET) and (FState <> wsClosed) do begin
  844.         MessagePump;
  845.         if WSocket_ioctlsocket(FHSocket, FIONREAD, lCount) = SOCKET_ERROR then
  846.             break;
  847.         if lCount > 0 then
  848.             TriggerDataAvailable(0);
  849.         Status := DoRecv(Ch, 0, 0);
  850.         if Status <= 0 then begin
  851.             FLastError := WSocket_WSAGetLastError;
  852.             if FLastError <> WSAEWOULDBLOCK then
  853.                 break;
  854.         end;
  855.         MessagePump;
  856.     end;
  857. end;
  858. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  859. function WSocketGetHostByAddr(Addr : String) : PHostEnt;
  860. var
  861.     szAddr : array[0..256] of char;
  862.     lAddr  : u_long;
  863. begin
  864. {    if not DllStarted then
  865.         LoadWinsock(WINSOCKET); 14/02/99 }
  866.     StrPCopy(szAddr, Addr);
  867.     lAddr  := WSocket_inet_addr(szAddr);
  868.     Result := winsock.gethostbyaddr(PChar(@lAddr), 4, PF_INET);
  869. end;
  870. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  871. function WSocketResolveIp(IpAddr : String) : String;
  872. var
  873.     Phe : PHostEnt;
  874. begin
  875.     phe := WSocketGetHostByAddr(IpAddr);
  876.     if Phe = nil then
  877.         Result := ''
  878.     else begin
  879.         SetLength(Result, StrLen(Phe^.h_name));
  880.         StrCopy(@Result[1], Phe^.h_name);
  881.     end;
  882. end;
  883. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  884. function WSocketGetHostByName(Name : String) : PHostEnt;
  885. var
  886.     szName : array[0..256] of char;
  887. begin
  888. {    if not DllStarted then
  889.         LoadWinsock(WINSOCKET); 14/02/99 }
  890.     StrPCopy(szName, Name);
  891.     Result := WSocket_gethostbyname(szName);
  892. end;
  893. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  894. function LocalIPList : TStrings;
  895. var
  896.     phe  : PHostEnt;
  897. begin
  898.     IPList.Clear;
  899.     Result := IPList;
  900.     phe  := WSocketGetHostByName(LocalHostName);
  901.     if phe <> nil then
  902.         GetIpList(Phe, IPList);
  903. end;
  904. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  905. function LocalHostName : String;
  906. var
  907.     Buffer     : array [0..63] of char;
  908. begin
  909. {    if not DllStarted then
  910.         LoadWinsock(WINSOCKET); 14/02/99 }
  911.     if WSocket_gethostname(Buffer, SizeOf(Buffer)) <> 0 then
  912.         raise ESocketException.Create('Winsock.GetHostName failed');
  913.     Result := StrPas(Buffer);
  914. end;
  915. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  916. function TCustomWSocket.TimerIsSet(var tvp : TTimeVal) : Boolean;
  917. begin
  918.     Result := (tvp.tv_sec <> 0) or (tvp.tv_usec <> 0);
  919. end;
  920. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  921. function TCustomWSocket.TimerCmp(var tvp : TTimeVal; var uvp : TTimeVal; IsEqual : Boolean) : Boolean;
  922. begin
  923.     Result := (tvp.tv_sec = uvp.tv_sec) and (tvp.tv_usec = uvp.tv_usec);
  924.     if not IsEqual then
  925.         Result := not Result;
  926. end;
  927. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  928. procedure TCustomWSocket.TimerClear(var tvp : TTimeVal);
  929. begin
  930.    tvp.tv_sec  := 0;
  931.    tvp.tv_usec := 0;
  932. end;
  933. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  934. procedure TCustomWSocket.SetSendFlags(newValue : TSocketSendFlags);
  935. begin
  936.     case newValue of
  937.     wsSendNormal: FSendFlags := 0;
  938.     wsSendUrgent: FSendFlags := MSG_OOB;
  939.     else
  940.         RaiseException('Invalid SendFlags');
  941.     end;
  942. end;
  943. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  944. function TCustomWSocket.GetSendFlags : TSocketSendFlags;
  945. begin
  946.     case FSendFlags of
  947.     0       : Result := wsSendNormal;
  948.     MSG_OOB : Result := wsSendUrgent;
  949.     else
  950.         RaiseException('Invalid internal SendFlags');
  951.         Result := wsSendNormal;
  952.     end;
  953. end;
  954. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  955. procedure TCustomWSocket.TriggerDisplay(Msg : String);
  956. begin
  957.     if Assigned(FOnDisplay) then
  958.         FOnDisplay(Self, Msg);
  959. end;
  960. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  961. procedure TCustomWSocket.TriggerSessionAvailable(Error : Word);
  962. begin
  963.     if Assigned(FOnSessionAvailable) then
  964.         FOnSessionAvailable(Self, Error);
  965. end;
  966. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  967. procedure TCustomWSocket.TriggerSessionConnected(Error : Word);
  968. begin
  969.     if Assigned(FOnSessionConnected) then
  970.         FOnSessionConnected(Self, Error);
  971. end;
  972. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  973. procedure TCustomWSocket.TriggerSessionClosed(Error : Word);
  974. begin
  975.     if Assigned(FOnSessionClosed) then
  976.         FOnSessionClosed(Self, Error);
  977. end;
  978. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  979. function TCustomWSocket.TriggerDataAvailable(Error : Word) : Boolean;
  980. begin
  981.     Result := Assigned(FOnDataAvailable);
  982.     if not Result then
  983.         Exit;
  984. {$IFDEF TOMASEK}                    { 23/01/99 }
  985.     { Do not allow FD_READ messages, this will prevent reentering the }
  986.     { OnDataAvailable event handler.                                  }
  987.     WSocket_WSAASyncSelect(FHSocket, Handle, WM_ASYNCSELECT,
  988.                            FD_WRITE or FD_CLOSE or FD_CONNECT);
  989.     try
  990.         FRcvdFlag := TRUE;
  991.         while Result and FRcvdFlag do begin
  992.             { Trigger user code. This will normally call DoRecv which will }
  993.             { update FRcvdFlag.                                            }
  994.             { If user code is wrong, we'll loop forever !                  }
  995.             FOnDataAvailable(Self, Error);
  996.             Result := Assigned(FOnDataAvailable);
  997.         end;
  998.     finally
  999.         { Allow all events now }
  1000.         WSocket_WSAASyncSelect(FHSocket, Handle, WM_ASYNCSELECT,
  1001.                                FD_READ or FD_WRITE or FD_CLOSE or FD_CONNECT);
  1002.     end;
  1003. {$ELSE}                             { 23/01/99 }
  1004.     FOnDataAvailable(Self, Error);  { 23/01/99 }
  1005. {$ENDIF}                            { 23/01/99 }
  1006. end;
  1007. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1008. procedure TCustomWSocket.TriggerDataSent(Error : Word);
  1009. begin
  1010.     if Assigned(FOnDataSent) then
  1011.         FOnDataSent(Self, Error);
  1012. end;
  1013. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1014. procedure TCustomWSocket.TriggerError;
  1015. begin
  1016.     if Assigned(FOnError) then
  1017.         FOnError(Self);
  1018. end;
  1019. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1020. procedure TCustomWSocket.TriggerDNSLookupDone(Error : Word);
  1021. begin
  1022.     if Assigned(FOnDNSLookupDone) then
  1023.         FOnDNSLookupDone(Self, Error);
  1024. end;
  1025. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1026. procedure TCustomWSocket.TriggerChangeState(OldState, NewState : TSocketState);
  1027. begin
  1028.     if Assigned(FOnChangeState) then
  1029.         FOnChangeState(Self, OldState, NewState);
  1030. end;
  1031. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1032. procedure TCustomWSocket.SocketError(sockfunc: string);
  1033. var
  1034.     Error  : integer;
  1035.     Line   : string;
  1036. begin
  1037.     Error := WSocket_WSAGetLastError;
  1038.     Line  := 'Error '+ IntToStr(Error) + ' in function ' + sockfunc +
  1039.              #13#10 + WSocketErrorDesc(Error);
  1040.     if (Error = WSAECONNRESET) or
  1041.        (Error = WSAENOTCONN)   then begin
  1042.         WSocket_closesocket(FHSocket);
  1043.         FHSocket := INVALID_SOCKET;
  1044.         ChangeState(wsClosed);
  1045.     end;
  1046.     FLastError := Error;
  1047.     RaiseException(Line);
  1048. end;
  1049. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1050. function WSocketErrorDesc(error: integer) : string;
  1051. begin
  1052.     case error of
  1053.     0:
  1054.       WSocketErrorDesc := 'No Error';
  1055.     WSAEINTR:
  1056.       WSocketErrorDesc := 'Interrupted system call';
  1057.     WSAEBADF:
  1058.       WSocketErrorDesc := 'Bad file number';
  1059.     WSAEACCES:
  1060.       WSocketErrorDesc := 'Permission denied';
  1061.     WSAEFAULT:
  1062.       WSocketErrorDesc := 'Bad address';
  1063.     WSAEINVAL:
  1064.       WSocketErrorDesc := 'Invalid argument';
  1065.     WSAEMFILE:
  1066.       WSocketErrorDesc := 'Too many open files';
  1067.     WSAEWOULDBLOCK:
  1068.       WSocketErrorDesc := 'Operation would block';
  1069.     WSAEINPROGRESS:
  1070.       WSocketErrorDesc := 'Operation now in progress';
  1071.     WSAEALREADY:
  1072.       WSocketErrorDesc := 'Operation already in progress';
  1073.     WSAENOTSOCK:
  1074.       WSocketErrorDesc := 'Socket operation on non-socket';
  1075.     WSAEDESTADDRREQ:
  1076.       WSocketErrorDesc := 'Destination address required';
  1077.     WSAEMSGSIZE:
  1078.       WSocketErrorDesc := 'Message too long';
  1079.     WSAEPROTOTYPE:
  1080.       WSocketErrorDesc := 'Protocol wrong type for socket';
  1081.     WSAENOPROTOOPT:
  1082.       WSocketErrorDesc := 'Protocol not available';
  1083.     WSAEPROTONOSUPPORT:
  1084.       WSocketErrorDesc := 'Protocol not supported';
  1085.     WSAESOCKTNOSUPPORT:
  1086.       WSocketErrorDesc := 'Socket type not supported';
  1087.     WSAEOPNOTSUPP:
  1088.       WSocketErrorDesc := 'Operation not supported on socket';
  1089.     WSAEPFNOSUPPORT:
  1090.       WSocketErrorDesc := 'Protocol family not supported';
  1091.     WSAEAFNOSUPPORT:
  1092.       WSocketErrorDesc := 'Address family not supported by protocol family';
  1093.     WSAEADDRINUSE:
  1094.       WSocketErrorDesc := 'Address already in use';
  1095.     WSAEADDRNOTAVAIL:
  1096.       WSocketErrorDesc := 'Address not available';
  1097.     WSAENETDOWN:
  1098.       WSocketErrorDesc := 'Network is down';
  1099.     WSAENETUNREACH:
  1100.       WSocketErrorDesc := 'Network is unreachable';
  1101.     WSAENETRESET:
  1102.       WSocketErrorDesc := 'Network dropped connection on reset';
  1103.     WSAECONNABORTED:
  1104.       WSocketErrorDesc := 'Connection aborted';
  1105.     WSAECONNRESET:
  1106.       WSocketErrorDesc := 'Connection reset by peer';
  1107.     WSAENOBUFS:
  1108.       WSocketErrorDesc := 'No buffer space available';
  1109.     WSAEISCONN:
  1110.       WSocketErrorDesc := 'Socket is already connected';
  1111.     WSAENOTCONN:
  1112.       WSocketErrorDesc := 'Socket is not connected';
  1113.     WSAESHUTDOWN:
  1114.       WSocketErrorDesc := 'Can''t send after socket shutdown';
  1115.     WSAETOOMANYREFS:
  1116.       WSocketErrorDesc := 'Too many references: can''t splice';
  1117.     WSAETIMEDOUT:
  1118.       WSocketErrorDesc := 'Connection timed out';
  1119.     WSAECONNREFUSED:
  1120.       WSocketErrorDesc := 'Connection refused';
  1121.     WSAELOOP:
  1122.       WSocketErrorDesc := 'Too many levels of symbolic links';
  1123.     WSAENAMETOOLONG:
  1124.       WSocketErrorDesc := 'File name too long';
  1125.     WSAEHOSTDOWN:
  1126.       WSocketErrorDesc := 'Host is down';
  1127.     WSAEHOSTUNREACH:
  1128.       WSocketErrorDesc := 'No route to host';
  1129.     WSAENOTEMPTY:
  1130.       WSocketErrorDesc := 'Directory not empty';
  1131.     WSAEPROCLIM:
  1132.       WSocketErrorDesc := 'Too many processes';
  1133.     WSAEUSERS:
  1134.       WSocketErrorDesc := 'Too many users';
  1135.     WSAEDQUOT:
  1136.       WSocketErrorDesc := 'Disc quota exceeded';
  1137.     WSAESTALE:
  1138.       WSocketErrorDesc := 'Stale NFS file handle';
  1139.     WSAEREMOTE:
  1140.       WSocketErrorDesc := 'Too many levels of remote in path';
  1141.     WSASYSNOTREADY:
  1142.       WSocketErrorDesc := 'Network sub-system is unusable';
  1143.     WSAVERNOTSUPPORTED:
  1144.       WSocketErrorDesc := 'WinSock DLL cannot support this application';
  1145.     WSANOTINITIALISED:
  1146.       WSocketErrorDesc := 'WinSock not initialized';
  1147.     WSAHOST_NOT_FOUND:
  1148.       WSocketErrorDesc := 'Host not found';
  1149.     WSATRY_AGAIN:
  1150.       WSocketErrorDesc := 'Non-authoritative host not found';
  1151.     WSANO_RECOVERY:
  1152.       WSocketErrorDesc := 'Non-recoverable error';
  1153.     WSANO_DATA:
  1154.       WSocketErrorDesc := 'No Data';
  1155.     else
  1156.       WSocketErrorDesc := 'Not a WinSock error';
  1157.     end;
  1158. end;
  1159. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  1160.          X X        X X        X X       X      X      X X      X X X X
  1161.        X     X    X     X    X     X     X     X     X     X    X
  1162.        X          X     X    X           X   X       X          X
  1163.          X X      X     X    X           X X           X X        X X
  1164.              X    X     X    X           X   X             X          X
  1165.        X     X    X     X    X     X     X     X     X     X    X     X
  1166.          X X        X X        X X       X      X      X  X       X X
  1167.  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1168. procedure TCustomSocksWSocket.AssignDefaultValue;
  1169. begin
  1170.     inherited AssignDefaultValue;
  1171.     FSocksState          := socksData;
  1172.     FSocksServer         := '';
  1173.     FSocksPort           := '';
  1174.     FSocksLevel          := '5';
  1175.     FRcvdCnt             := 0;
  1176.     FSocksPortAssigned   := FALSE;
  1177.     FSocksServerAssigned := FALSE;
  1178. end;
  1179. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1180. procedure TCustomSocksWSocket.SetSocksLevel(newValue : String);
  1181. begin
  1182.     if State <> wsClosed then begin
  1183.         RaiseException('Can''t change socks level if not closed');
  1184.         Exit;
  1185.     end;
  1186.     if (newValue <> '4')  and (newValue <> '5') and
  1187.        (newValue <> '4A') and (newValue <> '4a') then begin
  1188.         RaiseException('Invalid socks level. Must be 4, 4A or 5.');
  1189.         Exit;
  1190.     end;
  1191.     FSocksLevel := UpperCase(newValue);
  1192. end;
  1193. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1194. procedure TCustomSocksWSocket.SetSocksPort(sPort : String);
  1195. begin
  1196.     if State <> wsClosed then begin
  1197.         RaiseException('Can''t change socks port if not closed');
  1198.         Exit;
  1199.     end;
  1200.     FSocksPort := Trim(sPort);
  1201.     if Length(FSocksPort) = 0 then begin
  1202.         FSocksPortAssigned := FALSE;
  1203.         Exit;
  1204.     end;
  1205.     FSocksPortAssigned := TRUE;
  1206. end;
  1207. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1208. procedure TCustomSocksWSocket.SetSocksServer(sServer : String);
  1209. begin
  1210.     if State <> wsClosed then begin
  1211.         RaiseException('Can''t change socks server if not closed');
  1212.         Exit;
  1213.     end;
  1214.     FSocksServer := Trim(sServer);
  1215.     if Length(FSocksServer) = 0 then begin
  1216.         FSocksServerAssigned := FALSE;
  1217.         Exit;
  1218.     end;
  1219.     FSocksServerAssigned := TRUE;
  1220. end;
  1221. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1222. procedure TCustomSocksWSocket.Listen;
  1223. begin
  1224.     { Check if we really wants to use socks server }
  1225.     if not FSocksServerAssigned then begin
  1226.         { No socks server assigned, Listen as usual }
  1227.         inherited Listen;
  1228.         Exit;
  1229.     end;
  1230.     RaiseException('listening is not supported thru socks server');
  1231. end;
  1232. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1233. procedure TCustomSocksWSocket.Connect;
  1234. begin
  1235.     { Check if we really wants to use socks server }
  1236.     if not FSocksServerAssigned then begin
  1237.         { No socks server assigned, connect as usual }
  1238.         inherited Connect;
  1239.         Exit;
  1240.     end;
  1241.     if LowerCase(FProtoStr) <> 'tcp' then begin
  1242.         RaiseException('tcp is the only protocol supported thru socks server');
  1243.         Exit;
  1244.     end;
  1245.     try
  1246.         if not FPortResolved then begin
  1247.             { The next line will trigger an exception in case of failure }
  1248.             sin.sin_port  := WSocket_htons(WSocketResolvePort(FSocksPort, FProtoStr));
  1249.             FPortResolved := TRUE;
  1250.         end;
  1251.         if not FAddrResolved then begin
  1252.             { The next line will trigger an exception in case of failure }
  1253.             sin.sin_addr.s_addr := WSocketResolveHost(FSocksServer).s_addr;
  1254.             FAddrResolved       := TRUE;
  1255.         end;
  1256.         { The next line will trigger an exception in case of failure }
  1257.         FPortNum := WSocketResolvePort(FPortStr, FProtoStr);
  1258.     except
  1259.         on E:Exception do begin
  1260.             RaiseException('connect: ' + E.Message);
  1261.             Exit;
  1262.         end;
  1263.     end;
  1264.     FSocksState := socksNegociateMethods;
  1265.     FRcvCnt     := 0;
  1266.     inherited Connect;
  1267. end;
  1268. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1269. {function BufToStr(Buf : PChar; Cnt : Integer) : String;
  1270. begin
  1271.     Result := '';
  1272.     while Cnt > 0 do begin
  1273.         if Buf^ in [#32..#126] then
  1274.             Result := Result + Buf^
  1275.         else
  1276.             Result := Result + '#' + Format('%2.2d', [ord(Buf^)]);
  1277.         Inc(Buf);
  1278.         Dec(Cnt);
  1279.     end;
  1280. end;}
  1281. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1282. procedure TCustomSocksWSocket.TriggerSessionConnected(Error : Word);
  1283. var
  1284.     Buf : array [0..2] of char;
  1285. begin
  1286.     if FSocksState = socksNegociateMethods then begin
  1287.         TriggerSocksConnected(Error);
  1288.         if Error <> 0 then begin
  1289.             inherited TriggerSessionConnected(Error);
  1290.             Exit;
  1291.         end;
  1292.         if FSocksLevel[1] = '4' then
  1293.             SocksDoConnect
  1294.         else begin
  1295.             if FSocksAuthentication = socksNoAuthentication then
  1296.                 FSocksAuthNumber := #$00   { No authentification }
  1297.             else
  1298.                 FSocksAuthNumber := #$02;  { Usercode/Password   }
  1299.             Buf[0] := #$05;                { Version number      }
  1300.             Buf[1] := #$01;                { Number of methods   }
  1301.             Buf[2] := FSocksAuthNumber;    { Method identifier   }
  1302. {TriggerDisplay('Send = ''' + BufToStr(Buf, 3) + '''');}
  1303.             Send(@Buf, 3);
  1304.     end;
  1305.     end
  1306.     else
  1307.         inherited TriggerSessionConnected(Error);
  1308. end;
  1309. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1310. procedure TCustomSocksWSocket.TriggerSessionClosed(Error : Word);
  1311. begin
  1312.     if FSocksState = socksAuthenticate then
  1313.         TriggerSocksAuthState(socksAuthFailure);
  1314.     inherited TriggerSessionClosed(Error);
  1315. end;
  1316. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1317. procedure TCustomSocksWSocket.TriggerSocksConnected(Error : Word);
  1318. begin
  1319.     if Assigned(FOnSocksConnected) then
  1320.         FOnSocksConnected(Self, Error);
  1321. end;
  1322. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1323. procedure TCustomSocksWSocket.TriggerSocksError(Error : Integer; Msg : String);
  1324. begin
  1325.     if Assigned(FOnSocksError) then
  1326.         FOnSocksError(Self, Error, Msg);
  1327. end;
  1328. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1329. procedure TCustomSocksWSocket.TriggerSocksAuthState(AuthState : TSocksAuthState);
  1330. begin
  1331.     if Assigned(FOnSocksAuthState) then
  1332.         FOnSocksAuthState(Self, AuthState);
  1333. end;
  1334. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1335. procedure TCustomSocksWSocket.SocksDoAuthenticate;
  1336. var
  1337.     Buf     : array [0..127] of char;
  1338.     I       : Integer;
  1339. begin
  1340.     FSocksState := socksAuthenticate;
  1341.     TriggerSocksAuthState(socksAuthStart);
  1342.     Buf[0] := #$01; {06/03/99}           { Socks version }
  1343.     I      := 1;
  1344.     Buf[I] := chr(Length(FSocksUsercode));
  1345.     Move(FSocksUsercode[1], Buf[I + 1], Length(FSocksUsercode));
  1346.     I := I + 1 + Length(FSocksUsercode);
  1347.     Buf[I] := chr(Length(FSocksPassword));
  1348.     Move(FSocksPassword[1], Buf[I + 1], Length(FSocksPassword));
  1349.     I := I + 1 + Length(FSocksPassword);
  1350.     try
  1351. {TriggerDisplay('Send = ''' + BufToStr(Buf, I) + '''');}
  1352.         Send(@Buf, I);
  1353.     except
  1354.     end;
  1355. end;
  1356. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1357. procedure TCustomSocksWSocket.SocksDoConnect;
  1358. type
  1359.     pu_long = ^u_long;
  1360. var
  1361.     Buf     : array [0..127] of char;
  1362.     I       : Integer;
  1363.     ErrCode : Integer;
  1364. begin
  1365.     FSocksState := socksConnect;
  1366.     if FSocksLevel[1] = '4' then begin
  1367.         Buf[0] := #4;
  1368.         Buf[1] := #1;
  1369.         PWORD(@Buf[2])^  := WSocket_ntohs(FPortNum);
  1370.         if FSocksLevel = '4A' then
  1371.             pu_long(@Buf[4])^ := WSocket_inet_addr('0.0.0.1')
  1372.         else begin
  1373.             try
  1374.                 pu_long(@Buf[4])^ := WSocketResolveHost(FAddrStr).s_addr;
  1375.             except
  1376.                 on E:Exception do begin
  1377.                      ErrCode := socksHostResolutionFailed;
  1378.                      TriggerSocksError(ErrCode, E.ClassName + ' ' + E.Message);
  1379.                      InternalClose(TRUE, ErrCode);
  1380.                      Exit;
  1381.                 end;
  1382.             end;
  1383.         end;
  1384.         I := 8;
  1385.         if Length(FSocksUsercode) > 0 then begin
  1386.             { I'm not sure it has to be like that ! Should I also use the }
  1387.             { password or not ?                                           }
  1388.             Move(FSocksUsercode[1], Buf[I], Length(FSocksUsercode));
  1389.             I := I + Length(FSocksUsercode);
  1390.         end;
  1391.         Buf[I] := #0;
  1392.         Inc(I);
  1393.         if FSocksLevel = '4A' then begin
  1394.             Move(FAddrStr[1], Buf[I], Length(FAddrStr));
  1395.             I := I + Length(FAddrStr);
  1396.         end;
  1397.         Buf[I] := #0;
  1398.         Inc(I);
  1399.     end
  1400.     else begin
  1401.         Buf[0] := #$05;            { Socks version }
  1402.         Buf[1] := #$01;            { Connect command }
  1403.         Buf[2] := #$00;            { Reserved, must be $00 }
  1404.         Buf[3] := #$03;            { Address type is domain name }
  1405.         Buf[4] := chr(Length(FAddrStr));
  1406.         { Should check buffer overflow }
  1407.         Move(FAddrStr[1], Buf[5], Length(FAddrStr));
  1408.         I := 5 + Length(FAddrStr);
  1409.         PWord(@Buf[I])^ := WSocket_htons(FPortNum);
  1410.         I := I + 2;
  1411.     end;
  1412.     try
  1413. {TriggerDisplay('Send = ''' + BufToStr(Buf, I + 2) + '''');}
  1414.         Send(@Buf, I);
  1415.     except
  1416.     end;
  1417. end;
  1418. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1419. procedure TCustomSocksWSocket.DataAvailableError(
  1420.     ErrCode : Integer;
  1421.     Msg     : String);
  1422. begin
  1423.     TriggerSocksError(ErrCode, Msg);
  1424.     inherited TriggerSessionConnected(ErrCode);
  1425.     InternalClose(TRUE, ErrCode);
  1426. end;
  1427. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1428. function TCustomSocksWSocket.TriggerDataAvailable(Error : Word) : Boolean;
  1429. var
  1430.     Len     : Integer;
  1431.     I       : Integer;
  1432.     ErrCode : Word;
  1433.     ErrMsg  : String;
  1434.     InAddr  : TInAddr;
  1435.     AnsLen  : Integer;
  1436. begin
  1437.     if FSocksState = socksData then begin
  1438.         Result := inherited TriggerDataAvailable(Error);
  1439.         Exit;
  1440.     end;
  1441.     if Error <> 0 then begin
  1442.         DataAvailableError(Error, 'data receive error');
  1443.         Result := FALSE;
  1444.         Exit;
  1445.     end;
  1446.     if FSocksState = socksNegociateMethods then begin
  1447.         Result := TRUE;
  1448.         Len := Receive(@FRcvBuf[FRcvCnt], Sizeof(FRcvBuf) - FRcvCnt - 1);
  1449.         if Len < 0 then
  1450.             Exit;
  1451.         FRcvCnt := FRcvCnt + Len;
  1452. {TriggerDisplay('socksNegociateMethods FrcvBuf = ''' + BufToStr(FRcvBuf, FRcvCnt) + '''');}
  1453.         if FSocksLevel[1] = '4' then begin
  1454.             { We should never comes here }
  1455.             DataAvailableError(socksProtocolError, 'TWSocket logic error');
  1456.             Exit;
  1457.         end
  1458.         else begin  { SOCKS5 }
  1459.             { We are waiting only two bytes }
  1460.             if FRcvCnt < 2 then
  1461.                 Exit;
  1462. {            if FRcvCnt <> 2 then begin  06/03/99}
  1463. {                DataAvailableError(socksProtocolError, 'too much data availaible');}
  1464. {                Exit;                                                              }
  1465. {            end;                                                                   }
  1466.             FRcvCnt := 0; { Clear receive counter }
  1467.             if FRcvBuf[0] <> #$05 then begin
  1468.                 DataAvailableError(socksVersionError, 'socks version error');
  1469.                 Exit;
  1470.             end;
  1471.             if FRcvBuf[1] = #$00 then begin
  1472.                 { No authentication required }
  1473.                 if FSocksAuthNumber <> #$00 then
  1474.                     { We asked for authentification, so complains... }
  1475.                     TriggerSocksAuthState(socksAuthNotRequired);
  1476.             end
  1477.             else if FRcvBuf[1] = #$02 then begin
  1478.                 { Usercode/Password authentication required }
  1479.                 SocksDoAuthenticate;
  1480.                 Exit;
  1481.             end
  1482.             else begin
  1483.                 DataAvailableError(socksAuthMethodError, 'authentification method not acceptable');
  1484.                 Exit;
  1485.             end;
  1486.             SocksDoConnect;
  1487.         end;
  1488.     end
  1489.     else if FSocksState = socksConnect then begin
  1490.         Result := TRUE;
  1491. {TriggerDisplay('socksConnect FrcvBuf = ''' + BufToStr(FRcvBuf, FRcvCnt) + '''');}
  1492.         if FSocksLevel[1] = '4' then begin
  1493.             { We wants at most 8 characters }
  1494.             Len := Receive(@FRcvBuf[FRcvCnt], 8 - FRcvCnt);
  1495.             if Len < 0 then
  1496.                 Exit;
  1497.             FRcvCnt := FRcvCnt + Len;
  1498.             { We are waiting for 8 bytes }
  1499.             if FRcvCnt < 8 then
  1500.                 Exit;
  1501.             FRcvCnt := 0; { Clear receive counter }
  1502.             if FRcvBuf[0] <> #0 then begin
  1503.                 DataAvailableError(socksVersionError, 'socks version error');
  1504.                 Exit;
  1505.             end;
  1506.             if FRcvBuf[1] = #$90 then begin
  1507.                 case FRcvBuf[1] of
  1508.                 #$91: ErrCode := socksRejectedOrFailed;
  1509.                 #$92: ErrCode := socksConnectionRefused;
  1510.                 #$93: ErrCode := socksAuthenticationFailed;
  1511.                 else
  1512.                    ErrCode := socksUnassignedError;
  1513.                 end;
  1514.                 case ErrCode of
  1515.                 socksRejectedOrFailed :
  1516.                     ErrMsg := 'request rejected or failed';
  1517.                 socksConnectionRefused :
  1518.                     ErrMsg := 'connection refused';
  1519.                 socksAuthenticationFailed :
  1520.                     ErrMsg := 'authentification failed';
  1521.                 else
  1522.                     ErrMsg := 'unassigned error #' + IntToStr(Ord(FRcvBuf[1]));
  1523.                 end;
  1524.                 DataAvailableError(ErrCode, ErrMsg);
  1525.                 Exit;
  1526.             end;
  1527.             FSocksState := socksData;
  1528.             inherited TriggerSessionConnected(0);
  1529.             Result := inherited TriggerDataAvailable(0);
  1530.         end
  1531.         else begin { SOCKS5 }
  1532.             Len := Receive(@FRcvBuf[FRcvCnt], Sizeof(FRcvBuf) - FRcvCnt - 1);
  1533.             if Len < 0 then
  1534.                 Exit;
  1535.             FRcvCnt := FRcvCnt + Len;
  1536.             if FRcvCnt >= 1 then begin
  1537.                 { First byte is version, we expect version 5 }
  1538.                 if FRcvBuf[0] <> #$05 then begin
  1539.                     DataAvailableError(socksVersionError, 'socks version error');
  1540.                     Exit;
  1541.                 end;
  1542.             end;
  1543.             if FRcvCnt >= 2 then begin
  1544.                 if FRcvBuf[1] <> #$00 then begin
  1545.                     case FRcvBuf[1] of
  1546.                     #1: ErrCode := socksGeneralFailure;
  1547.                     #2: ErrCode := socksConnectionNotAllowed;
  1548.                     #3: ErrCode := socksNetworkUnreachable;
  1549.                     #4: ErrCode := socksHostUnreachable;
  1550.                     #5: ErrCode := socksConnectionRefused;
  1551.                     #6: ErrCode := socksTtlExpired;
  1552.                     #7: ErrCode := socksUnknownCommand;
  1553.                     #8: ErrCode := socksUnknownAddressType;
  1554.                     else
  1555.                        ErrCode := socksUnassignedError;
  1556.                     end;
  1557.                     case ErrCode of
  1558.                     socksGeneralFailure :
  1559.                         ErrMsg := 'general SOCKS server failure';
  1560.                     socksConnectionNotAllowed :
  1561.                         ErrMsg := 'connection not allowed by ruleset';
  1562.                     socksNetworkUnreachable :
  1563.                         ErrMsg := 'network unreachable';
  1564.                     socksHostUnreachable :
  1565.                         ErrMsg := 'host unreachable';
  1566.                     socksConnectionRefused :
  1567.                         ErrMsg := 'connection refused';
  1568.                     socksTtlExpired :
  1569.                         ErrMsg := 'time to live expired';
  1570.                     socksUnknownCommand :
  1571.                         ErrMsg := 'command not supported';
  1572.                     socksUnknownAddressType :
  1573.                         ErrMsg := 'address type not supported';
  1574.                     else
  1575.                         ErrMsg := 'unassigned error #' + IntToStr(Ord(FRcvBuf[1]));
  1576.                     end;
  1577.                     DataAvailableError(ErrCode, ErrMsg);
  1578.                     Exit;
  1579.                 end;
  1580.             end;
  1581.             if FRcvCnt < 5 then
  1582.                 Exit;
  1583.             { We have enough data to learn the answer length }
  1584.             if FRcvBuf[3] = #$01 then
  1585.                 AnsLen := 10                     { IP V4 address }
  1586.             else if FRcvBuf[3] = #$03 then
  1587.                 AnsLen := 7 + Ord(FRcvBuf[4])    { Domain name   }
  1588.             else
  1589.                 AnsLen := 5;                     { Other unsupported }
  1590.             if FRcvCnt < AnsLen then
  1591.                 Exit;
  1592.             if FRcvBuf[3] = #$01 then begin
  1593.                 { IP V4 address }
  1594.                 Move(FRcvBuf[4], InAddr, 4);
  1595.                 FBoundAddr := StrPas(WSocket_inet_ntoa(InAddr));
  1596.                 I := 4 + 4;
  1597.             end
  1598.             else if FRcvBuf[3] = #$03 then begin
  1599.                 { Domain name }
  1600.                 SetLength(FBoundAddr, Ord(FRcvBuf[4]));
  1601.                 Move(FRcvBuf[4], FBoundAddr[1], Length(FBoundAddr));
  1602.                 I := 4 + Ord(FRcvBuf[4]) + 1;
  1603.             end
  1604.             else begin
  1605.                 { Unsupported address type }
  1606.                 DataAvailableError(socksUnknownAddressType, 'address type not supported');
  1607.                 Exit;
  1608.             end;
  1609.             FBoundPort  := format('%d', [WSocket_ntohs(PWord(@FRcvBuf[I])^)]);
  1610.             I           := I + 2;
  1611.             FSocksState := socksData;
  1612.             inherited TriggerSessionConnected(0);
  1613.             FRcvdCnt := FRcvCnt - I;
  1614.             if FRcvdCnt < 0 then
  1615.                 FRcvdCnt := 0
  1616.             else
  1617.                 FRcvdPtr := @FRcvBuf[I];
  1618.             Result := inherited TriggerDataAvailable(0);
  1619.         end;
  1620.     end
  1621.     else if FSocksState = socksAuthenticate then begin
  1622.         Result := TRUE;
  1623.         Len := Receive(@FRcvBuf[FRcvCnt], Sizeof(FRcvBuf) - FRcvCnt - 1);
  1624.         if Len < 0 then
  1625.             Exit;
  1626.         FRcvCnt := FRcvCnt + Len;
  1627. {TriggerDisplay('socksAuthenticate FrcvBuf = ''' + BufToStr(FRcvBuf, FRcvCnt) + '''');}
  1628.         if FRcvCnt >= 1 then begin
  1629.             { First byte is version, we expect version 5 }
  1630.             if FRcvBuf[0] <> #$01 then begin { 06/03/99 }
  1631.                 TriggerSocksAuthState(socksAuthFailure);
  1632.                 DataAvailableError(socksVersionError, 'socks version error');
  1633.                 Exit;
  1634.             end;
  1635.         end;
  1636.         if FRcvCnt = 2 then begin
  1637.             { Second byte is status }
  1638.             if FRcvBuf[1] <> #$00 then begin
  1639.                 TriggerSocksAuthState(socksAuthFailure);
  1640.                 DataAvailableError(socksAuthenticationFailed, 'socks authentication failed');
  1641.                 Exit;
  1642.             end;
  1643.         end
  1644.         else if FRcvCnt > 2 then begin
  1645.             TriggerSocksAuthState(socksAuthFailure);
  1646.             DataAvailableError(socksProtocolError, 'too much data availaible');
  1647.             Exit;
  1648.         end;
  1649.         FRcvCnt := 0; { 06/03/99 }
  1650.         TriggerSocksAuthState(socksAuthSuccess);
  1651.         SocksDoConnect;
  1652.     end
  1653.     else begin
  1654.         { We should never comes here ! }
  1655.         DataAvailableError(socksInternalError, 'internal error');
  1656.         Result := FALSE;
  1657.     end;
  1658. end;
  1659. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1660. function TCustomSocksWSocket.GetRcvdCount : LongInt;
  1661. begin
  1662.     if FRcvdCnt <= 0 then
  1663.         Result := inherited GetRcvdCount
  1664.     else
  1665.         Result := FRcvdCnt;
  1666. end;
  1667. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1668. function TCustomSocksWSocket.DoRecv(
  1669.     var Buffer;
  1670.     BufferSize : Integer;
  1671.     Flags      : Integer) : Integer;
  1672. begin
  1673.     if FRcvdCnt <= 0 then begin
  1674.         Result := inherited DoRecv(Buffer, BufferSize, Flags);
  1675.         Exit;
  1676.     end;
  1677.     { We already have received data into our internal buffer }
  1678.     if FRcvdCnt <= BufferSize then begin
  1679.         { User buffer is greater than received data, copy all and clear }
  1680.         Move(FRcvdPtr^, Buffer, FRcvdCnt);
  1681.         Result   := FRcvdCnt;
  1682.         FRcvdCnt := 0;
  1683.         Exit;
  1684.     end;
  1685.     { User buffer is smaller, copy as much as possible }
  1686.     Move(FRcvdPtr^, Buffer, BufferSize);
  1687.     Result   := BufferSize;
  1688.     FRcvdPtr := FRcvdPtr + BufferSize;
  1689.     FRcvdCnt := FRcvdCnt - BufferSize;
  1690. end;
  1691. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  1692.               X          X     X       X      X X X X
  1693.               X          X     X X     X      X
  1694.               X          X     X   X   X      X
  1695.               X          X     X     X X      X X X
  1696.               X          X     X       X      X
  1697.               X          X     X       X      X
  1698.               X X X X    X     X       X      X X X X
  1699.  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1700. constructor TCustomLineWSocket.Create(AOwner: TComponent);
  1701. begin
  1702.     inherited Create(AOwner);
  1703.     FLineEnd  := #13#10;
  1704.     FLineMode := FALSE;
  1705. end;
  1706. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1707. destructor TCustomLineWSocket.Destroy;
  1708. begin
  1709.     if FRcvdPtr <> nil then begin
  1710.         FreeMem(FRcvdPtr, FRcvBufSize);
  1711.         FRcvdPtr     := nil;
  1712.         FRcvBufSize := 0;
  1713.     end;
  1714.     inherited Destroy;
  1715. end;
  1716. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1717. procedure TCustomLineWSocket.WndProc(var MsgRec: TMessage);
  1718. begin
  1719.     with MsgRec do begin
  1720.         if Msg = WM_TRIGGER_DATA_AVAILABLE then begin
  1721.             { We *MUST* handle all exception to avoid application shutdown }
  1722.             try
  1723.                 WMTriggerDataAvailable(MsgRec)
  1724.             except
  1725.                 on E:Exception do
  1726.                     HandleBackGroundException(E);
  1727.             end;
  1728.         end
  1729.         else
  1730.             inherited WndProc(MsgRec);
  1731.     end;
  1732. end;
  1733. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1734. procedure TCustomLineWSocket.WMTriggerDataAvailable(var msg: TMessage);
  1735. begin
  1736.     while FRcvdCnt > 0 do
  1737.         TriggerDataAvailable(0);
  1738. end;
  1739. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1740. procedure TCustomLineWSocket.SetLineMode(newValue : Boolean);
  1741. begin
  1742.     if FLineMode = newValue then
  1743.         Exit;
  1744.     FLineMode := newValue;
  1745.     if (FRcvdCnt > 0) or (FLineLength > 0) then
  1746.         PostMessage(Handle, WM_TRIGGER_DATA_AVAILABLE, 0, 0);
  1747. end;
  1748. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1749. function TCustomLineWSocket.GetRcvdCount : LongInt;
  1750. begin
  1751.     if not FLineMode then
  1752.         Result := inherited GetRcvdCount
  1753.     else
  1754.         Result := FLineLength;
  1755. end;
  1756. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1757. function TCustomLineWSocket.DoRecv(
  1758.     var Buffer;
  1759.     BufferSize : Integer;
  1760.     Flags      : Integer) : Integer;
  1761. begin
  1762.     if FLineMode and (FLineLength > 0) then begin
  1763.         { We are in line mode an a line is received }
  1764.         if FLineLength <= BufferSize then begin
  1765.             { User buffer is greater than received data, copy all and clear }
  1766.             Move(FRcvdPtr^, Buffer, FLineLength);
  1767.             Result      := FLineLength;
  1768.             FLineLength := 0;
  1769.             Exit;
  1770.         end;
  1771.         { User buffer is smaller, copy as much as possible }
  1772.         Move(FRcvdPtr^, Buffer, BufferSize);
  1773.         Result   := BufferSize;
  1774.         { Move the end of line to beginning of buffer to be read the next time }
  1775.         Move(FRcvdPtr[BufferSize], FRcvdPtr^, FLineLength - BufferSize);
  1776.         FLineLength := FLineLength - BufferSize;
  1777.         Exit;
  1778.     end;
  1779.     if FLineMode or (FRcvdCnt <= 0) then begin
  1780.         { There is nothing in our internal buffer }
  1781.         Result := inherited DoRecv(Buffer, BufferSize, Flags);
  1782.         Exit;
  1783.     end;
  1784.     { We already have received data into our internal buffer }
  1785.     if FRcvdCnt <= BufferSize then begin
  1786.         { User buffer is greater than received data, copy all and clear }
  1787.         Move(FRcvdPtr^, Buffer, FRcvdCnt);
  1788.         Result   := FRcvdCnt;
  1789.         FRcvdCnt := 0;
  1790.         Exit;
  1791.     end;
  1792.     { User buffer is smaller, copy as much as possible }
  1793.     Move(FRcvdPtr^, Buffer, BufferSize);
  1794.     Result   := BufferSize;
  1795.     FRcvdPtr := FRcvdPtr + BufferSize;
  1796.     FRcvdCnt := FRcvdCnt - BufferSize;
  1797. end;
  1798. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1799. { Edit received data. Handle TAB and BACKSPACE characters.                  }
  1800. { A data packet has been received into FRcvPtr buffer, starting from        }
  1801. { FRcvdCnt offset. Packet size if passed as the Len argument.               }
  1802. procedure TCustomLineWSocket.EditLine(var Len : Integer);
  1803. var
  1804.     Buf     : PChar;
  1805.     BufSize : Integer;
  1806.     I       : Integer;
  1807.     J       : Integer;
  1808.     Edited  : Boolean;
  1809.     NewCnt  : Integer;
  1810.     NewSize : Integer;
  1811. const
  1812.     BackString : String = #8 + ' ' + #8;
  1813. begin
  1814.     BufSize := 0;
  1815.     try
  1816.         Edited := FALSE;
  1817.         I      := FRcvdCnt;
  1818.         J      := FRcvdCnt;
  1819.         NewCnt := FRcvdCnt;
  1820.         { Loop to process all received char }
  1821.         while I < (FRcvdCnt + Len) do begin
  1822.             if FRcvdPtr[I] = #8 then begin   { BACKSPACE character }
  1823.                 if FLineEcho and (J > 0) then
  1824.                     SendStr(BackString);
  1825.                 if not Edited then begin
  1826.                     { Not edited yet, so we allocate a buffer to store }
  1827.                     { edited data and we remember we edited data.      }
  1828.                     Edited := TRUE;
  1829.                     { Computer buffer size as a multiple of 256 bytes  }
  1830.                     BufSize := ((FRcvdCnt + Len + 256) shr 8) shl 8;
  1831.                     GetMem(Buf, BufSize);
  1832.                     { Copy data already processed }
  1833.                     Move(FRcvdPtr^, Buf^, I);
  1834.                 end;
  1835.                 if J > 0 then begin
  1836.                     Dec(J);
  1837.                     if J < NewCnt then
  1838.                         NewCnt := J;
  1839.                 end;
  1840.                 Inc(I);
  1841.             end
  1842.             else if FRcvdPtr[I] = #9 then begin  { TAB character }
  1843.                 if not Edited then begin
  1844.                     { Not edited yet, so we allocate a buffer to store }
  1845.                     { edited data and we remember we edited data.      }
  1846.                     Edited := TRUE;
  1847.                     { Computer buffer size as a multiple of 256 bytes  }
  1848.                     BufSize := ((FRcvdCnt + Len + 256) shr 8) shl 8;
  1849.                     GetMem(Buf, BufSize);
  1850.                     { Copy data already processed }
  1851.                     Move(FRcvdPtr^, Buf^, I);
  1852.                 end;
  1853.                 repeat
  1854.                     if FLineEcho then
  1855.                         SendStr(' ');
  1856.                     Buf[J] := ' ';
  1857.                     Inc(J);
  1858.                 until (J and 7) = 0;
  1859.                 Inc(I);
  1860.             end
  1861.             else begin
  1862.                 if FLineEcho then
  1863.                     Send(@FRcvdPtr[I], 1);
  1864.                 if Edited then begin
  1865.                     if J >= BufSize then begin
  1866.                         { Need to allocate more buffer space }
  1867.                         NewSize := BufSize + 256;
  1868.                         {$IFDEF VER80}
  1869.                         ReallocMem(Buf, BufSize, NewSize);
  1870.                         {$ELSE}
  1871.                         ReallocMem(Buf, NewSize);
  1872.                         {$ENDIF}
  1873.                         BufSize := NewSize;
  1874.                     end;
  1875.                     Buf[J] := FRcvdPtr[I];
  1876.                 end;
  1877.                 Inc(I);
  1878.                 Inc(J);
  1879.             end;
  1880.         end;
  1881.         if Edited then begin
  1882.             if J >= FRcvBufSize then begin
  1883.                 { Current buffer is too small, allocate larger }
  1884.                 NewSize := J + 1;
  1885.                 {$IFDEF VER80}
  1886.                 ReallocMem(FRcvdPtr, FRcvBufSize, NewSize);
  1887.                 {$ELSE}
  1888.                 ReallocMem(FRcvdPtr, NewSize);
  1889.                 {$ENDIF}
  1890.                 FRcvBufSize := NewSize;
  1891.             end;
  1892.             { Move edited data back to original buffer }
  1893.             Move(Buf^, FRcvdPtr^, J);
  1894.             FRcvdPtr[J] := #0;
  1895.             FRcvdCnt := NewCnt;
  1896.             Len      := J - FRcvdCnt;
  1897.         end;
  1898.     finally
  1899.         if BufSize > 0 then
  1900.             FreeMem(Buf, BufSize);
  1901.     end;
  1902. end;
  1903. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1904. function TCustomLineWSocket.TriggerDataAvailable(Error : Word) : Boolean;
  1905. var
  1906.     Cnt        : Integer;
  1907.     Len        : Integer;
  1908.     NewSize    : Integer;
  1909.     SearchFrom : Integer;
  1910.     I          : Integer;
  1911.     Found      : Boolean;
  1912. begin
  1913.     if (not FLineMode) or (Length(FLineEnd) = 0) then begin
  1914.         { We are not in line mode }
  1915.         Result := inherited TriggerDataAvailable(Error);
  1916.         Exit;
  1917.     end;
  1918.     { We are in line mode. We receive data ourself }
  1919.     Result := TRUE;
  1920.     Cnt    := inherited GetRcvdCount;
  1921.     if Cnt <= 0 then
  1922.         Exit;
  1923.     if (FRcvdCnt + Cnt + 1) > FRcvBufSize then begin
  1924.         { Current buffer is too small, allocate larger }
  1925.         NewSize := FRcvdCnt + Cnt + 1;
  1926.         {$IFDEF VER80}
  1927.         ReallocMem(FRcvdPtr, FRcvBufSize, NewSize);
  1928.         {$ELSE}
  1929.         ReallocMem(FRcvdPtr, NewSize);
  1930.         {$ENDIF}
  1931.         FRcvBufSize := NewSize;
  1932.     end;
  1933.     Len := Receive(FRcvdPtr + FRcvdCnt, Cnt);
  1934.     if Len <= 0 then
  1935.         Exit;
  1936.     FRcvdPtr[FRcvdCnt + Len] := #0;
  1937.     if FLineEdit then
  1938.         EditLine(Len)
  1939.     else if FLineEcho then
  1940.         Send(FRcvdPtr + FRcvdCnt, Len);
  1941.     SearchFrom := FRcvdCnt - Length(FLineEnd);
  1942.     if SearchFrom < 0 then
  1943.         SearchFrom := 0;
  1944.     FRcvdCnt := FRcvdCnt + Len;
  1945.     while FLineMode do begin
  1946.         Found := FALSE;
  1947.         I := SearchFrom;
  1948.         while I < (FRcvdCnt - Length(FLineEnd) + 1) do begin
  1949.             if FRcvdPtr[I] = FLineEnd[1] then begin
  1950.                 Found := (StrLComp(@FRcvdPtr[I], @FLineEnd[1], Length(FLineEnd)) = 0);
  1951.                 if Found then
  1952.                     break;    { Found the end of line marker }
  1953.             end;
  1954.             Inc(I);
  1955.         end;
  1956.         if not Found then
  1957.             break;
  1958.         FLineLength       := I + Length(FLineEnd);
  1959.         FLineReceivedFlag := TRUE;
  1960.         { We received a complete line. We need to signal it to application }
  1961.         { The application may not have a large buffer so we may need       }
  1962.         { several events to read the entire line. In the meanwhile, the    }
  1963.         { application may turn line mode off.                              }
  1964.         while FLineMode and (FLineLength > 0) do begin
  1965.             if not inherited TriggerDataAvailable(0) then
  1966.                 { There is no handler installed }
  1967.                 FLineLength := 0;
  1968.         end;
  1969.         { Move remaining data in front of buffer }
  1970.         if FLineLength > 0 then begin
  1971.             { Line mode was turned off in the middle of a line read. }
  1972.             { We preserve unread line and other received data.       }
  1973.             Move(FRcvdPtr[I], FRcvdPtr[FLineLength],
  1974.                  FRcvdCnt - I);
  1975.             FRcvdCnt := FRcvdCnt - I + FLineLength;
  1976.         end
  1977.         else begin
  1978.             Move(FRcvdPtr[I + Length(FLineEnd)], FRcvdPtr[0],
  1979.                  FRcvdCnt - I - Length(FLineEnd));
  1980.             FRcvdCnt := FRcvdCnt - I - Length(FLineEnd);
  1981.         end;
  1982.         FRcvdPtr[FRcvdCnt] := #0;
  1983.         SearchFrom         := 0;
  1984.     end;
  1985. end;
  1986. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1987. procedure TCustomLineWSocket.TriggerSessionClosed(Error : Word);
  1988. begin
  1989.     FLineReceivedFlag := TRUE;
  1990.     if FRcvdPtr <> nil then begin
  1991.         if FLineMode and (FRcvdCnt > 0) then begin
  1992.             FLineLength       := FRcvdCnt;
  1993.             while FLineMode and (FLineLength > 0) do
  1994.                 inherited TriggerDataAvailable(0);
  1995.         end;
  1996.         FreeMem(FRcvdPtr, FRcvBufSize);
  1997.         FRcvdPtr    := nil;
  1998.         FRcvBufSize := 0;
  1999.         FRcvdCnt    := 0;
  2000.     end;
  2001.     inherited TriggerSessionClosed(Error);
  2002. end;
  2003. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2004.                  X X      X     X    X       X     X X X
  2005.                X     X      X   X    X X     X   X      X
  2006.                X              X X    X   X   X   X
  2007.                  X X            X    X     X X   X
  2008.                      X          X    X       X   X
  2009.                X     X    X     X    X       X   X      X
  2010.                  X X        X X      X       X     X X X
  2011.  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  2012. procedure TCustomSyncWSocket.InternalDataAvailable(
  2013.     Sender : TObject;
  2014.     Error  : Word);
  2015. var
  2016.     Len : Integer;
  2017. begin
  2018.     SetLength(FLinePointer^, FLineLength);
  2019.     Len := Receive(@FLinePointer^[1], FLineLength);
  2020.     if Len <= 0 then
  2021.         FLinePointer^ := ''
  2022.     else
  2023.         SetLength(FLinePointer^, Len);
  2024. end;
  2025. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  2026. function TCustomSyncWSocket.WaitUntilReady(var DoneFlag : Boolean) : Integer;
  2027. begin
  2028.     Result := 0;           { Suppose success }
  2029.     FTimeStop := Integer(GetTickCount) + FTimeout;
  2030.     while TRUE do begin
  2031.         if DoneFlag then begin
  2032.             Result := 0;
  2033.             break;
  2034.         end;
  2035.         if ((FTimeout > 0) and (Integer(GetTickCount) > FTimeStop)) or
  2036. {$IFNDEF NOFORMS}
  2037.            Application.Terminated or
  2038. {$ENDIF}
  2039.            FTerminated then begin
  2040.             { Application is terminated or timeout occured }
  2041.             Result := WSA_WSOCKET_TIMEOUT;
  2042.             break;
  2043.         end;
  2044.         MessagePump;
  2045. {$IFNDEF VER80}
  2046.         { Do not use 100% CPU, but slow down transfert on high speed LAN }
  2047.         Sleep(0);
  2048. {$ENDIF}
  2049.     end;
  2050. end;
  2051. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  2052. function TCustomSyncWSocket.Synchronize(
  2053.     Proc : TWSocketSyncNextProc;
  2054.     var DoneFlag : Boolean) : Integer;
  2055. begin
  2056.     DoneFlag := FALSE;
  2057.     if Assigned(Proc) then
  2058.         Proc;
  2059.     Result := WaitUntilReady(DoneFlag);
  2060. end;
  2061. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  2062. procedure TCustomSyncWSocket.ReadLine(
  2063.     Timeout    : Integer;  { seconds if positive, milli-seconds if negative }
  2064.     var Buffer : String);
  2065. var
  2066.     OldDataAvailable : TDataAvailable;
  2067.     OldLineMode      : Boolean;
  2068.     Status           : Integer;
  2069. begin
  2070.     Buffer            := '';
  2071.     if FState <> wsConnected then begin
  2072.         RaiseException('ReadLine failed: not connected');
  2073.         Exit;
  2074.     end;
  2075.     { Positive timeout means seconds. Negative means milli-seconds }
  2076.     { Null means 60 seconds.                                       }
  2077.     if TimeOut = 0 then
  2078.         FTimeOut      := 60000
  2079.     else if TimeOut > 0 then
  2080.         FTimeOut      := Timeout * 1000
  2081.     else
  2082.         FTimeOut      := -Timeout;
  2083.         
  2084.     FLineReceivedFlag := FALSE;
  2085.     FLinePointer      := @Buffer;
  2086.     { Save existing OnDataAvailable handler and install our own }
  2087.     OldDataAvailable  := FOnDataAvailable;
  2088.     FOnDataAvailable  := InternalDataAvailable;
  2089.     { Save existing line mode and turn it on }
  2090.     OldLineMode       := FLineMode;
  2091.     FLineMode         := TRUE;
  2092.     try
  2093.         Status := Synchronize(nil, FLineReceivedFlag);
  2094.         if Status = WSA_WSOCKET_TIMEOUT then begin
  2095.              { Sender didn't send line end within allowed time. Get all }
  2096.              { data available so far.                                   }
  2097.              if FRcvdCnt > 0 then begin
  2098.                  SetLength(Buffer, FRcvdCnt);
  2099.                  Move(FRcvdPtr^, Buffer[1], FRcvdCnt);
  2100.                  FRcvdCnt := 0;
  2101.              end;
  2102.         end;
  2103.         { Should I raise an exception to tell the application that       }
  2104.         { some error occured ?                                           }
  2105.     finally
  2106.         FOnDataAvailable := OldDataAvailable;
  2107.         FLineMode        := OldLineMode;
  2108.     end;
  2109. end;
  2110. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  2111. {$IFDEF VER80}
  2112. begin
  2113.     IPList := TStringList.Create;
  2114.     {
  2115.       Delphi 1 has no finalization. When your application terminates, you
  2116.       should add a call to WSocketUnloadWinsock to unload winsock from memory.
  2117.       It is done automatically for you when the last TWSocket component is
  2118.       destroyed but if you do any winsock call after that, you must call
  2119.       WSocketUnloadWinsock yourself. It is safe to call WSocketUnloadWinsock
  2120.       even if it has already been done.
  2121.     }
  2122. {$ELSE}
  2123. initialization
  2124.     IPList := TStringList.Create;
  2125. finalization
  2126.     if Assigned(IPList) then begin
  2127.         IPList.Destroy;
  2128.         IPList := nil;
  2129.     end;
  2130.     WSocketUnloadWinsock;
  2131. {$ENDIF}
  2132. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  2133. end.