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

Delphi控件源码

开发平台:

WINDOWS

  1. {*_* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2. Author:       Fran鏾is PIETTE
  3. Description:  TWSocket class encapsulate the Windows Socket paradigm
  4. EMail:        francois.piette@pophost.eunet.be    francois.piette@rtfm.be
  5.               http://www.rtfm.be/fpiette
  6. Creation:     April 1996
  7. Version:      4.07
  8. Support:      Use the mailing list twsocket@rtfm.be See website for details.
  9. Legal issues: Copyright (C) 1996, 1997, 1998, 1999 by Fran鏾is PIETTE
  10.               Rue de Grady 24, 4053 Embourg, Belgium. Fax: +32-4-365.74.56
  11.               <francois.piette@pophost.eunet.be>
  12.               This software is provided 'as-is', without any express or
  13.               implied warranty.  In no event will the author be held liable
  14.               for any  damages arising from the use of this software.
  15.               Permission is granted to anyone to use this software for any
  16.               purpose, including commercial applications, and to alter it
  17.               and redistribute it freely, subject to the following
  18.               restrictions:
  19.               1. The origin of this software must not be misrepresented,
  20.                  you must not claim that you wrote the original software.
  21.                  If you use this software in a product, an acknowledgment
  22.                  in the product documentation would be appreciated but is
  23.                  not required.
  24.               2. Altered source versions must be plainly marked as such, and
  25.                  must not be misrepresented as being the original software.
  26.               3. This notice may not be removed or altered from any source
  27.                  distribution.
  28.               4. You must register this software by sending a picture postcard
  29.                  to the author. Use a nice stamp and mention your name, street
  30.                  address, EMail address and any comment you like to say.
  31. History:
  32. Jul 18, 1996  Move all low level socket to winsock to be Delphi 2.x compatible
  33. Sep 18, 1996  Use structured exception for handling errors
  34. Sep 19, 1996  Check csDestroying before invoking event handler
  35. Nov 04, 1996  Better error handling
  36. Jan 31, 1997  Changed property assignation for Addr, Port and Proto
  37.               Added notification handler
  38. Feb 14, 1997  Corrected bug in property assignation for Addr, Port and Proto
  39. Mar 26, 1997  Make UDP protocol work correctly
  40.               Enable UDP broadcasting by using addr 255.255.255.255
  41. Apr 1, 1997   Added class function when independent of any open socket
  42.               Moved InitData as global
  43.               Added ReceivedFrom function
  44.               Added ResolveHost function
  45. Jul 22, 1997  Adapted to Delphi 3 which has a modified winsock.accept
  46. Aug 13, 1997  'sin' member made public
  47. Aug 24, 1997  Create the only help
  48.               Makes writing HSocket the same as calling Dup.
  49. Sep 5, 1997   Version 2.01, added WinsockInfo function
  50. Sep 21, 1997  Version 2.02, make it really thread safe
  51.                             created global WSocketVersion
  52. Sep 25, 1997  Version 2.04, port to C++Builder
  53. Sep 27, 1997  Version 2.05. All class methods converted to global
  54.               procedure or function because C++Builder do not like
  55.               class method very much.
  56.               Old class method              New global function
  57.               ----------------              -------------------
  58.               WinsockInfo                   WinsockInfo
  59.               SocketErrorDesc               WSocketErrorDesc
  60.               GetHostByAddr                 WSocketGetHostByAddr
  61.               GetHostByName                 WSocketGetHostByName
  62.               ResolveHost                   WSocketResolveHost
  63.               HostName                      LocalHostName
  64. Oct 02, 1997  V2.06 Added a check in destructor to avoid calling WSACleanup at
  65.               design time which crashes the excellent Eagle Software CDK.
  66. Oct 16, 1997  V2.07 Added PortNum property with numeric value for Port.
  67.               Added RcvdCount property to return the number of
  68.               characters received in the buffer but not read yet. Do not
  69.               confuse with ReadCount which returns the number of chars
  70.               already received.
  71.               Added a check for FWait assignation in front of ReadLine
  72.               Prefixed each TSocketState value by 'ws' to avoid name conflict.
  73.               Moved FHSocket member to private section because the property
  74.               HSocket does the right job.
  75.               Added a check for state closed when changing Port, Proto and Addr.
  76. Oct 22, 1997  V2.08 Added Flush method (asked by john@nexnix.co.uk) and
  77.               FlushTimeout property (default to 60 seconds).
  78. Oct 22, 1997  V2.09 Added SendFlags property to enable sending in or out of
  79.               band data (normal or urgent, see RFC-1122)
  80. Oct 28, 1997  V2.10 Added an OnLineTooLong event and code to handle the case
  81.               where ReadLine has been called and the buffer overflowed (line
  82.               long)
  83. Oct 29, 1997  V2.11 Added DnsLookup functionnality (DnsLookup method, DnsResult
  84.               property and DnsLookupDone event).
  85.               Calling the connect method with a hostname work well except that
  86.               it could block for a long period (ie: 2 minutes) if DNS do not
  87.               respond. Calling the connect method with a numeric IP address will
  88.               never block. So you can call DnsLookup to start hostname
  89.               resolution in the background, after some time you evenutually
  90.               receive the OnDnsLookupDone event. The copy the DnsResult property
  91.               to the Addr property and call connect.
  92. Oct 30, 1997  V2.12 added a check in DnsLookup to handel numeric IP which do
  93.               not require any lookup. The numeric IP is treated immediately
  94.               and immediately trigger the DnsLookupDone event.
  95.               I modified the code to be compatible with Delphi 1.
  96. Oct 31, 1997  V2.13 added CancelDnsLookup procedure.
  97. Nov 09, 1997  V2.14 add LocalIPList function to get the list of local IP
  98.               addresses (you have two IP addresses when connected to a LAN
  99.               and an ISP).
  100. Nov 11, 1997  V2.15 Made TCustomWSocket with virtual functions. This will
  101.               allow to easily descend a new component from TCustomWSocket.
  102.               Make ReadLine stop when the connection is broken.
  103. Nov 12, 1997  V2.16 Corrected bug (Justin Yunke <yunke@productivity.org>)
  104.               in LocalIPList: phe should be checked for nil.
  105. Nov 18, 1997  Added ReceiveStr function (Suggested by FLDKNHA@danisco.com)
  106. Nov 30, 1997  V2.18 Added a call to OnDnsLookupDone when canceling.
  107. Dec 04, 1997  V2.19 Added LocalPort property and SessionConnected event
  108.               for UDP socket.
  109.               V2.20 Modified MessageLoop and ProcessMessages to process not
  110.               only the socket messages, but all messages (necessary if the
  111.               thread has several TWSocket for example).
  112. Dec 09, 1997  V2.21 Corrected a minor bug in ReceiveStr. Detected by
  113.               david@e.co.za (David Butler).
  114. Dec 10, 1997  V2.22 Corrected a minor bug in Send which now correctly
  115.               returns the number of bytes sent. Detected by
  116.               james.huggins@blockbuster.com
  117. Dec 16, 1997  V2.23 Corrected a bug which prevented the receiving of datagram
  118.               from a UDP socket.
  119.               Thank to Mark Melvin (melvin@misrg.ml.org) for pointing it.
  120. Dec 20, 1997  V2.24 Added the PeekData function as suggested by Matt Rose
  121.               mcrose@avproinc.com
  122. Dec 26, 1997  V2.25 Added the Text property as suggested by Daniel P. Stasinski
  123.               <dse@pacific.net>. Made GetXPort work even when listening as
  124.               suggested by is81024@cis.nctu.edu.tw.
  125. Jan 10, 1998  V2.26 Check for null hostname in DNSLookup
  126.               Added DnsResultList with all IP addresses returned form DNS
  127. Jan 13, 1998  V2.27 a Added MultiThreaaded property to tell the component that
  128.               it is working in a thread and should take care of it (call
  129.               internal ProcessMessages in place of Application.ProcessMessages,
  130.               and do not use the WaitCtrl object).
  131. Jan 15, 1998  V2.28 WMAsyncSelect revisited to work properly with NT winsock 2.
  132. Feb 10, 1998  V2.29 Added an OnError event. If not assigned, then the component
  133.               raise an exception when the error occurs.
  134. Feb 14, 1998  V2.30 Published Text property
  135. Feb 16, 1998  V2.31 Added virtual methods to trigger events
  136.               Renamed all event handler variable to begin with FOn
  137. Feb 26, 1998  V2.32 Added procedure PutDataInSendBuffer and PutStringInSendBuffer
  138.               Using PutDataInSendBuffer you can place data in the send buffer
  139.               without actualy trying to send it. This allows to place several
  140.               (probably small) data chunk before the component attempt to send
  141.               it. This prevent small packet to be sent. You can call
  142.               Send(nil, 0) to force the component to begin to send data.
  143.               If the buffer was not empty, PutDataInSendBuffer will just queue
  144.               data to the buffer. This data will be sent in sequence.
  145. Mar 02, 1998  V2.33 Changed the error check with WSAstartup as pointed out by
  146.               Donald Strenczewilk (dstrenz@servtech.com)
  147. Mar 06, 1998  V2.34 Added a runtime property to change the buffer size.
  148. Mar 27, 1998  V2.35 Adapted for C++Builder 3
  149. Apr 08, 1998  V2.36 Made SetDefaultValue virtual
  150. Apr 13, 1998  V2.37 Reset FDnsLookupHandle to 0 after a failed call to
  151.               WSACancelAsyncRequest
  152. Apr 22, 1998  V2.38 Published AllSent property to let outside know if our
  153.               buffer has some data unsent.
  154. Apr 28, 1998  V2.39 Added LingerOnOff and LingerTimeout. Default values are
  155.               wsLingerOn and timeout = 0 to behave by default as before.
  156.               This value is setup just before Connect. Call SetLingerOption to
  157.               set the linger option on the fly (the connection must be
  158.               established to set the option). See winsock.closesocket on line
  159.               help (winsock.hlp or win32.hlp) for a dsicussion of this option
  160.               usage.
  161. May 06, 1998  V2.40 Added a workaround for Trumpet winsock inet_addr bug.
  162.               Thanks to Andrej Cuckov <andrej@cuckov.com> for his code.
  163. May 18, 1998  V2.41 Jan Tomasek <xtomasej@feld.cvut.cz> found that Trumpet
  164.               Winsock (Win 3.11) has some bugs and suggested a workaround in
  165.               TryToSend procedure. This workaround makes TWSocket blocking in
  166.               some cases. A new property enables the workaround. See code.
  167. Jun 01, 1998  V2.42 In finalization section, check for not assigned IPList.
  168. Jun 15, 1998  V2.43 Added code to finalization section to unload winsock if
  169.               still loaded at that point (this happend if no socket where
  170.               created but WinsockInfo called). Suggested by Daniel Fazekas
  171.               <fdsoft@dns.gyor-ph.hu>
  172. Jun 27, 1998  V2.44 Added checks for valid arguments in SetPort, SetProto
  173.               and SetAddr. Deferred address resolution until Connect or Listen.
  174. Jul 08, 1998  V2.45 Adadpted for Delphi 4
  175. Jul 20, 1998  V2.46 Added SetWindowLong(FWindowHandle, 0, 0) in the destructor
  176.               and a check for TWSocket class in XSocketWindowProc.
  177.               Added virtual method RealSend.
  178. Jul 23, 1998  V2.47 Added a TriggerSessionClosed from TryToSend in case of
  179.               send error. This was called before, but with a nul error argument.
  180.               Now it correctly gives the error number.
  181.               Added a trashcan to receive data if no OnDataAvailable event
  182.               handler is installed. Just receive the data and throw it away.
  183.               Added reverse dns lookup asynchronous code (IP -> HostName).
  184.               Thanks to Daniel Fazekas <fdsoft@dns.gyor-ph.hu> for his code.
  185. Jul 30, 1998  V2.48 Changed local variable "error" by FLastError in SocketError
  186.               to make it available from the OnError handler. Thanks to
  187.               dana@medical-info.com for finding this bug.
  188.               In Abort procedure, deleted all buffered data because it was send
  189.               the next time the socket is opened !
  190.               Added CancelDnsLookup in Abort procedure.
  191. Aug 28, 1998  V2.49 Made InternalClose and ReceiveStr virtual
  192. Sep 01, 1998  V2.50 Ignore CancelDnsLookup exception during destroy
  193. Sep 29, 1998  V2.51 In InternalClose, protect AssignDefaultValue with
  194.               try/except because SessionClosed event handler may have destroyed
  195.               the component.
  196. Oct 11, 1998  V2.52 Changed Shutdown(2) to Shutdown(1) in Internal Close to
  197.               prevent data lost on send. You may have to call Shutdown(2) in
  198.               your own code before calling Close to have the same behaviour as
  199.               before.
  200.               Changed argument type for ASyncReceive and passed 0 from FD_CLOSE
  201.               message handler.
  202. Oct 28, 1998  V2.53 Made WSocketLoadWinsock and WSocketUnloadWinsock public.
  203. Nov 11, 1998  V2.54 Added OnDisplay event for debugging purpose
  204. Nov 16, 1998  V2.55 Ignore WSANOTINITIALIZED error calling CloseSocket. This
  205.               occurs when using TWSocket from a DLL and the finalization
  206.               section is called before destroying TWSocket components (this is
  207.               a program logic error).
  208.               Made some properties and methods protected instead of private.
  209.               Made some methods virtual.
  210.               Added an Error argument to InternalClose.
  211.               Added DoRecv virtual function.
  212.               Added WSocketResolvePort
  213.               Added WSocketResolveProto
  214.               Deferred port and protocol resolution until really needed
  215.               Transformed Listen to procedure (in case of failure Listen
  216.               always calls SocketError which triggers an exception or the
  217.               OnError event).
  218. Nov 22, 1998  V3.00 Skipped from V2.55 to V3.00. Socks support is major update!
  219.               Added SOCKS5 support for TCP connection and simple usercode
  220.               paswword authentication. Consider the socks code as beta !
  221.               New properties: SocksServer, SocksPort, SocksUsercode,
  222.               SocksPassword, FSocksAuthentication. New events: OnSocksError,
  223.               OnSocksConnected, OnSocksAuthState.
  224.               I used WinGate 2.1d to test my code. Unfortunately WinGate do
  225.               not correctly handle user authentication, so the code here is
  226.               just untested...
  227. Dec 05, 1998  V3.10 Removed ReadLine feature using TWait component.
  228.               Added new TCustomLineWSocket and TCustomSyncWSocket.
  229.               Those modifications implies that the ReadLine functionnality is
  230.               slightly changed. Notably, the end of line marker is now
  231.               configurable and remains in the received line unless a timeout
  232.               occurs or the buffer is too small.
  233. Dec 10, 1998  V3.11 Added missing code to resolve port in the Listen method.
  234. Dec 12, 1998  V3.12 Added write method for LocalPort property. Thanks to
  235.               Jan Tomasek <xtomasej@feld.cvut.cz> for his code.
  236.               Added background exception handling.
  237.               Fixed a bug in TCustomLineWSocket.TriggerDataAvailable which was
  238.               not calling the inherited function when it actually should.
  239.               Added a check on multithreaded in WaitForClose to call the
  240.               correct ProcessMessages procedure.
  241.               Added SOCKS4 support (only tcp connect is supported).
  242. Dec 28, 1998  V3.13 Changed WSocketResolveHost to check for invalid numeric
  243.               IP addresses whitout trying to use them as hostnames.
  244. Dec 30, 1998  V3.14 Changed SetPort to SetRemotePort to solve the SetPort
  245.               syndrome with BCB. Also chnaged GetPort to be consistant.
  246. Jan 12, 1999  V3.15 Introduced DoRecvFrom virtual function. This correct a bug
  247.               introduced in V3.14 related to UDP and RecvFrom.
  248. Jan 23, 1999  V3.16 Changed FRcvdFlag computation in DoRecv and DoRecvFrom
  249.               because it caused problems with HTTP component and large blocks.
  250.               Removed modification by Jan Tomasek in TriggerDataAvailable
  251. Jan 30, 1999  V3.17 Added WSocketResolveIp function.
  252.               Checked for tcp protocol before setting linger off in abort.
  253.               Moved a lot of variables from private to protected sections.
  254.               Removed check for Assigned(FOnDataSent) in WMASyncSelect.
  255. Feb 03, 1999  V3.18 Removed useless units in the uses clause.
  256. Feb 14, 1999  V4.00 Jump to next major version number because lots of
  257.               fundamental changes have been done. See below.
  258.               Use runtime dynamic link with winsock. All winsock functions
  259.               used by TWSocket are linked at runtime instead of loadtime. This
  260.               allows programs to run without winsock installed, provided program
  261.               doesn't try to use TWSocket or winsock function without first
  262.               checking for winsock installation.
  263.               Removed WSocketLoadWinsock and all use to DllStarted because it
  264.               is no longer necessary because winsock is automatically loaded
  265.               and initialized with the first call to a winsock function.
  266.               Added MessagePump to centralize call to the message pump.
  267.               It is a virtual procedure so that you can override it to
  268.               cutomize your message pump. Also changed slightly ProcessMessages
  269.               to closely match what is done in the forms unit.
  270.               Removed old stuff related to WaitCtrl (was already excluded from
  271.               compilation using a conditional directive).
  272.               Added NOFORMS conditional compilation to exclude the Forms unit
  273.               from wsocket. This will reduce exe or dll size by 100 to 150KB.
  274.               To use this feature, you have to add NOFORMS in your project
  275.               options in the "defines" edit box in the "directory/conditional"
  276.               tab. Then you must add a message pump to your application and
  277.               call it from TWSocket.OnMessagePump event handler. TWSocket really
  278.               need a message pump in order to receive messages from winsock.
  279.               Depending on how your application is built, you can use either
  280.               TWSocket.MessageLoop or TWSocket.ProcessMessages to quickly build
  281.               a working message pump. Or you may build your own custom message
  282.               pump taylored to your needs. Your message pump must set
  283.               TWSocket.Terminated property to TRUE when your application
  284.               terminates or you may experience long delays when closing your
  285.               application.
  286.               You may use NOFORMS setting even if you use the forms unit (GUI
  287.               application). Simply call Application.ProcessMessages in the
  288.               OnMessagePump event handler.
  289.               OnMessagePump event is not visible in the object inspector. You
  290.               must assign it at run-time before using the component and after
  291.               having created it (in a GUI application you can do that in the
  292.               FormCreate event, in a console application, you can do it right
  293.               after TWSocket.Create call).
  294. Feb 17, 1999  V4.01 Added LineEcho and LineEdit features.
  295. Feb 27, 1999  V4.02 Added TCustomLineWSocket.GetRcvdCount to make RcvdCount
  296.               property and ReceiveStr work in line mode.
  297. Mar 01, 1999  V4.03 Added conditional compile for BCB4. Thanks to James
  298.               Legg <jlegg@iname.com>.
  299. Mar 14, 1999  V4.04 Corrected a bug: wsocket hangup when there was no
  300.               OnDataAvailable handler and line mode was on.
  301. Apr 21, 1999  V4.05 Added H+ (long strings) and X+ (extended syntax)
  302.               compilation options
  303. May 07, 1999  V4.06 Added WSAECONNABORTED to valid error codes in TryToSend.
  304. Jul 21, 1999  V4.07 Added GetPeerPort method, PeerPort and PeerAddr propertied
  305.               as suggested by J. Punter <JPunter@login-bv.com>.
  306.  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  307. unit WSocket;
  308. {$B-}           { Enable partial boolean evaluation   }
  309. {$T-}           { Untyped pointers                    }
  310. {$X+}           { Enable extended syntax              }
  311. {$IFNDEF VER80} { Not for Delphi 1                    }
  312.     {$H+}       { Use long strings                    }
  313.     {$J+}       { Allow typed constant to be modified }
  314. {$ENDIF}
  315. {$IFDEF VER110} { C++ Builder V3.0                    }
  316.     {$ObjExportAll On}
  317. {$ENDIF}
  318. interface
  319. uses
  320.   WinTypes, WinProcs, Messages, Classes, SysUtils,
  321. {$IFNDEF NOFORMS} { See comments in history at 14/02/99 }
  322.   Forms,
  323. {$ENDIF}
  324.   WSockBuf, WinSock;
  325. const
  326.   WSocketVersion            = 407;
  327.   CopyRight    : String     = ' TWSocket (c) 96-99 F. Piette V4.07 ';
  328.   WM_ASYNCSELECT            = WM_USER + 1;
  329.   WM_ASYNCGETHOSTBYNAME     = WM_USER + 2;
  330.   WM_ASYNCGETHOSTBYADDR     = WM_USER + 3;
  331.   WM_TRIGGER_DATA_AVAILABLE = WM_USER + 20;
  332.   WSA_WSOCKET_TIMEOUT       = 12001;
  333. {$IFDEF WIN32}
  334.   winsocket = 'wsock32.dll';      { 32 bits TCP/IP system DLL }
  335. {$ELSE}
  336.   winsocket = 'winsock.dll';      { 16 bits TCP/IP system DLL }
  337. {$ENDIF}
  338. type
  339.   ESocketException = class(Exception);
  340.   TBgExceptionEvent = procedure (Sender : TObject;
  341.                                  E : Exception;
  342.                                  var CanClose : Boolean) of object;
  343.   TSocketState = (wsInvalidState,
  344.                   wsOpened,     wsBound,
  345.                   wsConnecting, wsConnected,
  346.                   wsAccepting,  wsListening,
  347.                   wsClosed);
  348.   TSocketSendFlags = (wsSendNormal, wsSendUrgent);
  349.   TSocketLingerOnOff = (wsLingerOff, wsLingerOn, wsLingerNoSet);
  350.   TDataAvailable    = procedure (Sender: TObject; Error: word) of object;
  351.   TDataSent         = procedure (Sender: TObject; Error: word) of object;
  352.   TSessionClosed    = procedure (Sender: TObject; Error: word) of object;
  353.   TSessionAvailable = procedure (Sender: TObject; Error: word) of object;
  354.   TSessionConnected = procedure (Sender: TObject; Error: word) of object;
  355.   TDnsLookupDone    = procedure (Sender: TObject; Error: Word) of object;
  356.   TChangeState      = procedure (Sender: TObject;
  357.                                  OldState, NewState : TSocketState) of object;
  358.   TDebugDisplay     = procedure (Sender: TObject; var Msg : String) of object;
  359.   TWSocketSyncNextProc = procedure of object;
  360. {$IFDEF VER110}  { C++Builder V3 }
  361.   TSocket = integer;
  362. {$ENDIF}
  363. {$IFDEF VER120} { C++Builder V4 }
  364.   TSocket = integer;
  365. {$ENDIF}
  366.   TCustomWSocket = class(TComponent)
  367.   private
  368.     FDnsResult          : String;
  369.     FDnsResultList      : TStrings;
  370.     FASocket            : TSocket;               { Accepted socket }
  371.     FBufList            : TList;
  372.     FBufSize            : Integer;
  373.     FSendFlags          : Integer;
  374.     FLastError          : Integer;
  375.     FWindowHandle       : HWND;
  376.     FDnsLookupBuffer    : array [0..MAXGETHOSTSTRUCT] of char;
  377.     FDnsLookupHandle    : THandle;
  378.   {$IFDEF VER80}
  379.     FTrumpetCompability : Boolean;
  380.   {$ENDIF}
  381.   protected
  382.     FHSocket            : TSocket;
  383.     FAddrStr            : String;
  384.     FAddrResolved       : Boolean;
  385.     FAddrFormat         : Integer;
  386.     FAddrAssigned       : Boolean;
  387.     FProto              : integer;
  388.     FProtoAssigned      : Boolean;
  389.     FProtoResolved      : Boolean;
  390.     FLocalPortResolved  : Boolean;
  391.     FProtoStr           : String;
  392.     FPortStr            : String;
  393.     FPortAssigned       : Boolean;
  394.     FPortResolved       : Boolean;
  395.     FPortNum            : Integer;
  396.     FLocalPortStr       : String;
  397.     FLocalPortNum       : Integer;
  398.     FType               : integer;
  399.     FLingerOnOff        : TSocketLingerOnOff;
  400.     FLingerTimeout      : Integer;              { In seconds, 0 = disabled }
  401.     ReadLineCount       : Integer;
  402.     bWrite              : Boolean;
  403.     nMoreCnt            : Integer;
  404.     bMoreFlag           : Boolean;
  405.     nMoreMax            : Integer;
  406.     bAllSent            : Boolean;
  407.     FReadCount          : LongInt;
  408.     FPaused             : Boolean;
  409.     FCloseInvoked       : Boolean;
  410.     FFlushTimeout       : Integer;
  411.     FMultiThreaded      : Boolean;
  412.     FState              : TSocketState;
  413.     FRcvdFlag           : Boolean;
  414.     FTerminated         : Boolean;
  415.     FOnSessionAvailable : TSessionAvailable;
  416.     FOnSessionConnected : TSessionConnected;
  417.     FOnSessionClosed    : TSessionClosed;
  418.     FOnChangeState      : TChangeState;
  419.     FOnDataAvailable    : TDataAvailable;
  420.     FOnDataSent         : TDataSent;
  421.     FOnLineTooLong      : TNotifyEvent;
  422.     FOnDnsLookupDone    : TDnsLookupDone;
  423.     FOnError            : TNotifyEvent;
  424.     FOnBgException      : TBgExceptionEvent;
  425.     FOnDisplay          : TDebugDisplay;
  426.     FOnMessagePump      : TNotifyEvent;
  427.     procedure   WndProc(var MsgRec: TMessage); virtual;
  428.     procedure   SocketError(sockfunc: string);
  429.     procedure   WMASyncSelect(var msg: TMessage); message WM_ASYNCSELECT;
  430.     procedure   WMAsyncGetHostByName(var msg: TMessage); message WM_ASYNCGETHOSTBYNAME;
  431.     procedure   WMAsyncGetHostByAddr(var msg: TMessage); message WM_ASYNCGETHOSTBYADDR;
  432.     procedure   ChangeState(NewState : TSocketState);
  433.     procedure   TryToSend;
  434.     procedure   ASyncReceive(Error : Word);
  435.     procedure   AssignDefaultValue; virtual;
  436.     procedure   InternalClose(bShut : Boolean; Error : Word); virtual;
  437.     procedure   Notification(AComponent: TComponent; operation: TOperation); override;
  438.     procedure   SetSendFlags(newValue : TSocketSendFlags);
  439.     function    GetSendFlags : TSocketSendFlags;
  440.     procedure   SetAddr(InAddr : String);
  441.     function    GetAddr : String;
  442.     procedure   SetRemotePort(sPort : String); virtual;
  443.     function    GetRemotePort : String;
  444.     procedure   SetLocalPort(sLocalPort : String);
  445.     procedure   SetProto(sProto : String); virtual;
  446.     function    GetProto : String;
  447.     function    GetRcvdCount : LongInt; virtual;
  448.     procedure   BindSocket; virtual;
  449.     procedure   SendText(Str : String);
  450.     function    RealSend(Data : Pointer; Len : Integer) : Integer; virtual;
  451.     procedure   RaiseExceptionFmt(const Fmt : String; args : array of const); virtual;
  452.     procedure   RaiseException(const Msg : String); virtual;
  453.     procedure   HandleBackGroundException(E: Exception); virtual;
  454.     procedure   TriggerDisplay(Msg : String);
  455.     function    TriggerDataAvailable(Error : Word) : Boolean; virtual;
  456.     procedure   TriggerSessionAvailable(Error : Word); virtual;
  457.     procedure   TriggerSessionConnected(Error : Word); virtual;
  458.     procedure   TriggerSessionClosed(Error : Word); virtual;
  459.     procedure   TriggerDataSent(Error : Word); virtual;
  460.     procedure   TriggerChangeState(OldState, NewState : TSocketState); virtual;
  461.     procedure   TriggerDNSLookupDone(Error : Word); virtual;
  462.     procedure   TriggerError; virtual;
  463.     function    DoRecv(var Buffer;
  464.                        BufferSize : Integer;
  465.                        Flags      : Integer) : Integer; virtual;
  466.     function    DoRecvFrom(FHSocket    : TSocket;
  467.                            var Buffer;
  468.                            BufferSize  : Integer;
  469.                            Flags       : Integer;
  470.                            var From    : TSockAddr;
  471.                            var FromLen : Integer) : Integer; virtual;
  472.   public
  473.     sin         : TSockAddrIn;
  474.     constructor Create(AOwner: TComponent); override;
  475.     destructor  Destroy; override;
  476.     procedure   Connect; virtual;
  477.     procedure   Close; virtual;
  478.     procedure   Abort; virtual;
  479.     procedure   Flush; virtual;
  480.     procedure   WaitForClose; virtual;
  481.     procedure   Listen; virtual;
  482.     function    Accept: TSocket; virtual;
  483.     function    Receive(Buffer : Pointer; BufferSize: integer) : integer; virtual;
  484.     function    ReceiveStr : string; virtual;
  485.     function    ReceiveFrom(Buffer      : Pointer;
  486.                             BufferSize  : Integer;
  487.                             var From    : TSockAddr;
  488.                             var FromLen : Integer) : integer; virtual;
  489.     function    PeekData(Buffer : Pointer; BufferSize: integer) : integer;
  490.     function    Send(Data : Pointer; Len : Integer) : integer; virtual;
  491.     function    SendTo(Dest    : TSockAddr;
  492.                        DestLen : Integer;
  493.                        Data    : Pointer;
  494.                        Len     : Integer) : integer; virtual;
  495.     function    SendStr(Str : String) : Integer; virtual;
  496.     procedure   DnsLookup(HostName : String); virtual;
  497.     procedure   ReverseDnsLookup(HostAddr: String); virtual;
  498.     procedure   CancelDnsLookup; virtual;
  499.     function    GetPeerAddr: string; virtual;
  500.     function    GetPeerPort: string; virtual;
  501.     function    GetPeerName(var Name : TSockAddrIn; NameLen : Integer) : integer; virtual;
  502.     function    GetXPort: string; virtual;
  503.     function    TimerIsSet(var tvp : TTimeVal) : Boolean; virtual;
  504.     procedure   TimerClear(var tvp : TTimeVal); virtual;
  505.     function    TimerCmp(var tvp : TTimeVal; var uvp : TTimeVal; IsEqual : Boolean) : Boolean; virtual;
  506.     function    GetSockName(var saddr : TSockAddrIn; var saddrlen : Integer) : integer; virtual;
  507.     procedure   SetLingerOption;
  508.     procedure   Dup(NewHSocket : TSocket); virtual;
  509.     procedure   Shutdown(How : Integer); virtual;
  510.     procedure   Pause; virtual;
  511.     procedure   Resume; virtual;
  512.     procedure   PutDataInSendBuffer(Data : Pointer; Len : Integer);
  513.     procedure   PutStringInSendBuffer(Str : String);
  514.     procedure   DeleteBufferedData;
  515.     procedure   MessagePump; virtual;
  516. {$IFNDEF VER80}
  517.     procedure   MessageLoop;
  518.     function    ProcessMessage : Boolean;
  519.     procedure   ProcessMessages;
  520. {$ENDIF}
  521. {$IFDEF NOFORMS}
  522.     property    Terminated         : Boolean        read  FTerminated
  523.                                                     write FTerminated;
  524.     property    OnMessagePump      : TNotifyEvent   read  FOnMessagePump
  525.                                                     write FOnMessagePump;
  526. {$ENDIF}
  527.   protected
  528.     property PortNum : Integer                      read  FPortNum;
  529.     property Handle : HWND                          read  FWindowHandle;
  530.     property HSocket : TSocket                      read  FHSocket
  531.                                                     write Dup;
  532.     property Addr : string                          read  GetAddr
  533.                                                     write SetAddr;
  534.     property Port : string                          read  GetRemotePort
  535.                                                     write SetRemotePort;
  536.     property LocalPort : string                     read  FLocalPortStr
  537.                                                     write SetLocalPort;
  538.     property Proto : String                         read  GetProto
  539.                                                     write SetProto;
  540.     property MultiThreaded   : Boolean              read  FMultiThreaded
  541.                                                     write FMultiThreaded;
  542.     property PeerAddr : String                      read  GetPeerAddr;
  543.     property PeerPort : String                      read  GetPeerPort;
  544.     property DnsResult : String                     read  FDnsResult;
  545.     property DnsResultList : TStrings               read  FDnsResultList;
  546.     property State : TSocketState                   read  FState;
  547.     property AllSent   : Boolean                    read  bAllSent;
  548.     property ReadCount : LongInt                    read  FReadCount;
  549.     property RcvdCount : LongInt                    read  GetRcvdCount;
  550.     property LastError : Integer                    read  FLastError;
  551.     property BufSize   : Integer                    read  FBufSize
  552.                                                     write FBufSize;
  553.     property OnDataAvailable : TDataAvailable       read  FOnDataAvailable
  554.                                                     write FOnDataAvailable;
  555.     property OnDataSent : TDataSent                 read  FOnDataSent
  556.                                                     write FOnDataSent;
  557.     property OnSessionClosed : TSessionClosed       read  FOnSessionClosed
  558.                                                     write FOnSessionClosed;
  559.     property OnSessionAvailable : TSessionAvailable read  FOnSessionAvailable
  560.                                                     write FOnSessionAvailable;
  561.     property OnSessionConnected : TSessionConnected read  FOnSessionConnected
  562.                                                     write FOnSessionConnected;
  563.     property OnChangeState      : TChangeState      read  FOnChangeState
  564.                                                     write FOnChangeState;
  565.     property OnLineTooLong      : TNotifyEvent      read  FOnLineTooLong
  566.                                                     write FOnLineTooLong;
  567.     property OnDnsLookupDone    : TDnsLookupDone    read  FOnDnsLookupDone
  568.                                                     write FOnDnsLookupDone;
  569.     property OnError            : TNotifyEvent      read  FOnError
  570.                                                     write FOnError;
  571.     property OnBgException      : TBgExceptionEvent read  FOnBgException
  572.                                                     write FOnBgException;
  573.     property FlushTimeout : Integer                 read  FFlushTimeOut
  574.                                                     write FFlushTimeout;
  575.     property SendFlags : TSocketSendFlags           read  GetSendFlags
  576.                                                     write SetSendFlags;
  577.     property Text: String                           read  ReceiveStr
  578.                                                     write SendText;
  579.     property LingerOnOff   : TSocketLingerOnOff     read  FLingerOnOff
  580.                                                     write FLingerOnOff;
  581.     property LingerTimeout : Integer                read  FLingerTimeout
  582.                                                     write FLingerTimeout;
  583. {$IFDEF VER80}
  584.     property TrumpetCompability : Boolean           read  FTrumpetCompability
  585.                                                     write FTrumpetCompability;
  586. {$ENDIF}
  587.     property OnDisplay : TDebugDisplay              read  FOnDisplay
  588.                                                     write FOnDisplay;
  589.   end;
  590.   TSocksState          = (socksData, socksNegociateMethods, socksAuthenticate, socksConnect);
  591.   TSocksAuthentication = (socksNoAuthentication, socksAuthenticateUsercode);
  592.   TSocksAuthState      = (socksAuthStart, socksAuthSuccess, socksAuthFailure, socksAuthNotRequired);
  593.   TSocksAuthStateEvent = procedure(Sender : TObject; AuthState : TSocksAuthState) of object;
  594.   TSocksErrorEvent     = procedure(Sender : TObject; Error : Integer; Msg : String) of Object;
  595.   TCustomSocksWSocket = class(TCustomWSocket)
  596.   protected
  597.       FSocksState          : TSocksState;
  598.       FSocksServer         : String;
  599.       FSocksLevel          : String;
  600.       FSocksPort           : String;
  601.       FSocksPortAssigned   : Boolean;
  602.       FSocksServerAssigned : Boolean;
  603.       FSocksUsercode       : String;
  604.       FSocksPassword       : String;
  605.       FSocksAuthentication : TSocksAuthentication;
  606.       FSocksAuthNumber     : char;
  607.       FBoundAddr           : String;
  608.       FBoundPort           : String;
  609.       FRcvBuf              : array [0..127] of char;
  610.       FRcvCnt              : Integer;
  611.       FRcvdCnt             : Integer;
  612.       FRcvdPtr             : PChar;
  613.       FOnSocksError        : TSocksErrorEvent;
  614.       FOnSocksConnected    : TSessionConnected;
  615.       FOnSocksAuthState    : TSocksAuthStateEvent;
  616.       procedure   AssignDefaultValue; override;
  617.       procedure   TriggerSessionConnected(Error : Word); override;
  618.       procedure   TriggerSocksConnected(Error : Word); virtual;
  619.       procedure   TriggerSessionClosed(Error : Word); override;
  620.       function    TriggerDataAvailable(Error : Word) : Boolean; override;
  621.       procedure   SetSocksPort(sPort : String); virtual;
  622.       procedure   SetSocksServer(sServer : String); virtual;
  623.       procedure   TriggerSocksError(Error : Integer; Msg : String); virtual;
  624.       procedure   TriggerSocksAuthState(AuthState : TSocksAuthState);
  625.       function    GetRcvdCount : LongInt; override;
  626.       procedure   SetSocksLevel(newValue : String);
  627.       function    DoRecv(var Buffer;
  628.                          BufferSize : Integer;
  629.                          Flags      : Integer) : Integer; override;
  630.       procedure   SocksDoConnect;
  631.       procedure   SocksDoAuthenticate;
  632.       procedure   DataAvailableError(ErrCode : Integer; Msg : String);
  633.   public
  634.       procedure   Connect; override;
  635.       procedure   Listen; override;
  636.   protected
  637.       property SocksServer   : String               read  FSocksServer
  638.                                                     write SetSocksServer;
  639.       property SocksLevel    : String               read  FSocksLevel
  640.                                                     write SetSocksLevel;
  641.       property SocksPort     : String               read  FSocksPort
  642.                                                     write SetSocksPort;
  643.       property SocksUsercode : String               read  FSocksUsercode
  644.                                                     write FSocksUsercode;
  645.       property SocksPassword : String               read  FSocksPassword
  646.                                                     write FSocksPassword;
  647.       property SocksAuthentication : TSocksAuthentication
  648.                                                     read  FSocksAuthentication
  649.                                                     write FSocksAuthentication;
  650.       property OnSocksError  : TSocksErrorEvent     read  FOnSocksError
  651.                                                     write FOnSocksError;
  652.       property OnSocksConnected : TSessionConnected read  FOnSocksConnected
  653.                                                     write FOnSocksConnected;
  654.       property OnSocksAuthState : TSocksAuthStateEvent
  655.                                                     read  FOnSocksAuthState
  656.                                                     write FOnSocksAuthState;
  657.   end;
  658.     TCustomLineWSocket = class (TCustomSocksWSocket)
  659.     protected
  660.         FRcvdPtr             : PChar;
  661.         FRcvBufSize          : Integer;
  662.         FRcvdCnt             : Integer;
  663.         FLineEnd             : String;
  664.         FLineMode            : Boolean;
  665.         FLineLength          : Integer;    { When a line is available }
  666.         FLineReceivedFlag    : Boolean;
  667.         FLineEcho            : Boolean;    { Echo received data    }
  668.         FLineEdit            : Boolean;    { Edit received data    }
  669.         FTimeout             : LongInt;    { Given in milliseconds }
  670.         FTimeStop            : LongInt;    { Milliseconds          }
  671.         procedure   WndProc(var MsgRec: TMessage); override;
  672.         procedure   WMTriggerDataAvailable(var msg: TMessage); message WM_TRIGGER_DATA_AVAILABLE;
  673.         function    TriggerDataAvailable(Error : Word) : Boolean; override;
  674.         procedure   TriggerSessionClosed(Error : Word); override;
  675.         procedure   SetLineMode(newValue : Boolean); virtual;
  676.         procedure   EditLine(var Len : Integer); virtual;
  677.         function    GetRcvdCount : LongInt; override;
  678.         function    DoRecv(var Buffer;
  679.                            BufferSize : Integer;
  680.                            Flags      : Integer) : Integer; override;
  681.     public
  682.         constructor Create(AOwner: TComponent); override;
  683.         destructor  Destroy; override;
  684.         property    LineLength : Integer     read  FLineLength;
  685.     published
  686.         property LineMode : Boolean          read  FLineMode
  687.                                              write SetLineMode;
  688.         property LineEnd  : String           read  FLineEnd
  689.                                              write FLineEnd;
  690.         property LineEcho : Boolean          read  FLineEcho
  691.                                              write FLineEcho;
  692.         property LineEdit : Boolean          read  FLineEdit
  693.                                              write FLineEdit;
  694.     end;
  695.     TCustomSyncWSocket = class(TCustomLineWSocket)
  696.     protected
  697.         FLinePointer : ^String;
  698.         function    Synchronize(Proc : TWSocketSyncNextProc; var DoneFlag : Boolean) : Integer; virtual;
  699.         function    WaitUntilReady(var DoneFlag : Boolean) : Integer; virtual;
  700.         procedure   InternalDataAvailable(Sender: TObject; Error: Word);
  701.     public
  702.         procedure   ReadLine(Timeout : integer; var Buffer : String);
  703.     end;
  704.   TWSocket = class(TCustomSyncWSocket)
  705.   public
  706.     property PortNum;
  707.     property Handle;
  708.     property HSocket;
  709.     property BufSize;
  710.     property Text;
  711.     property AllSent;
  712.   {$IFDEF VER80}
  713.     property TrumpetCompability;
  714.   {$ENDIF}
  715.     property OnDisplay;
  716.   published
  717.     property Addr;
  718.     property Port;
  719.     property Proto;
  720.     property LocalPort;
  721.     property PeerPort;
  722.     property PeerAddr;
  723.     property DnsResult;
  724.     property DnsResultList;
  725.     property State;
  726.     property ReadCount;
  727.     property RcvdCount;
  728.     property LastError;
  729.     property MultiThreaded;
  730.     property OnDataAvailable;
  731.     property OnDataSent;
  732.     property OnSessionClosed;
  733.     property OnSessionAvailable;
  734.     property OnSessionConnected;
  735.     property OnSocksConnected;
  736.     property OnChangeState;
  737.     property OnLineTooLong;
  738.     property OnDnsLookupDone;
  739.     property OnError;
  740.     property OnBgException;
  741.     property FlushTimeout;
  742.     property SendFlags;
  743.     property LingerOnOff;
  744.     property LingerTimeout;
  745.     property SocksLevel;
  746.     property SocksServer;
  747.     property SocksPort;
  748.     property SocksUsercode;
  749.     property SocksPassword;
  750.     property SocksAuthentication;
  751.     property OnSocksError;
  752.     property OnSocksAuthState;
  753.   end;
  754.   TSocksWSocket = class(TWSocket)
  755.   end;
  756. procedure Register;
  757. function  WinsockInfo : TWSADATA;
  758. function  WSocketErrorDesc(error: integer) : string;
  759. function  WSocketGetHostByAddr(Addr : String) : PHostEnt;
  760. function  WSocketGetHostByName(Name : String) : PHostEnt;
  761. function  LocalHostName : String;
  762. function  LocalIPList : TStrings;
  763. function  WSocketResolveIp(IpAddr : String) : String;
  764. function  WSocketResolveHost(InAddr : String) : TInAddr;
  765. function  WSocketResolvePort(Port : String; Proto : String) : Word;
  766. function  WSocketResolveProto(sProto : String) : integer;
  767. procedure WSocketUnloadWinsock;
  768. { function  WSocketLoadWinsock : Boolean; 14/02/99 }
  769. type
  770. {$IFDEF VER80}
  771.     DWORD = LongInt;
  772.     TWSAStartup            = function (wVersionRequired: word;
  773.                                        var WSData: TWSAData): Integer;
  774.     TWSACleanup            = function : Integer;
  775.     TWSASetLastError       = procedure (iError: Integer);
  776.     TWSAGetLastError       = function : Integer;
  777.     TWSACancelAsyncRequest = function (hAsyncTaskHandle: THandle): Integer;
  778.     TWSAAsyncGetHostByName = function (HWindow: HWND;
  779.                                        wMsg: u_int;
  780.                                        name, buf: PChar;
  781.                                        buflen: Integer): THandle;
  782.     TWSAAsyncGetHostByAddr = function (HWindow: HWND;
  783.                                        wMsg: u_int; addr: PChar;
  784.                                        len, Struct: Integer;
  785.                                        buf: PChar;
  786.                                        buflen: Integer): THandle;
  787.     TWSAAsyncSelect        = function (s: TSocket;
  788.                                       HWindow: HWND;
  789.                                       wMsg: u_int;
  790.                                       lEvent: Longint): Integer;
  791.     TGetServByName         = function (name, proto: PChar): PServEnt;
  792.     TGetProtoByName        = function (name: PChar): PProtoEnt;
  793.     TGetHostByName         = function (name: PChar): PHostEnt;
  794.     TGetHostName           = function (name: PChar; len: Integer): Integer;
  795.     TOpenSocket            = function (af, Struct, protocol: Integer): TSocket;
  796.     TShutdown              = function (s: TSocket; how: Integer): Integer;
  797.     TSetSockOpt            = function (s: TSocket; level, optname: Integer;
  798.                                        optval: PChar;
  799.                                        optlen: Integer): Integer; 
  800.     TGetSockOpt            = function (s: TSocket; level, optname: Integer; optval: PChar; var optlen: Integer): Integer; 
  801.     TSendTo                = function (s: TSocket; var Buf;
  802.                                        len, flags: Integer;
  803.                                        var addrto: TSockAddr;
  804.                                        tolen: Integer): Integer; 
  805.     TSend                  = function (s: TSocket; var Buf;
  806.                                        len, flags: Integer): Integer;
  807.     TRecv                  = function (s: TSocket;
  808.                                        var Buf;
  809.                                        len, flags: Integer): Integer; 
  810.     TRecvFrom              = function (s: TSocket;
  811.                                        var Buf; len, flags: Integer;
  812.                                        var from: TSockAddr;
  813.                                        var fromlen: Integer): Integer; 
  814.     Tntohs                 = function (netshort: u_short): u_short; 
  815.     Tntohl                 = function (netlong: u_long): u_long; 
  816.     TListen                = function (s: TSocket; backlog: Integer): Integer; 
  817.     TIoctlSocket           = function (s: TSocket; cmd: DWORD;
  818.                                        var arg: u_long): Integer; 
  819.     TInet_ntoa             = function (inaddr: TInAddr): PChar;
  820.     TInet_addr             = function (cp: PChar): u_long;
  821.     Thtons                 = function (hostshort: u_short): u_short;
  822.     Thtonl                 = function (hostlong: u_long): u_long;
  823.     TGetSockName           = function (s: TSocket; var name: TSockAddr;
  824.                                        var namelen: Integer): Integer;
  825.     TGetPeerName           = function (s: TSocket; var name: TSockAddr;
  826.                                        var namelen: Integer): Integer;
  827.     TConnect               = function (s: TSocket; var name: TSockAddr;
  828.                                        namelen: Integer): Integer;
  829.     TCloseSocket           = function (s: TSocket): Integer;
  830.     TBind                  = function (s: TSocket; var addr: TSockAddr;
  831.                                        namelen: Integer): Integer;
  832.     TAccept                = function (s: TSocket; var addr: TSockAddr;
  833.                                        var addrlen: Integer): TSocket;
  834. {$ELSE}
  835.     TWSAStartup            = function (wVersionRequired: word;
  836.                                        var WSData: TWSAData): Integer; stdcall;
  837.     TWSACleanup            = function : Integer; stdcall;
  838.     TWSASetLastError       = procedure (iError: Integer); stdcall;
  839.     TWSAGetLastError       = function : Integer; stdcall;
  840.     TWSACancelAsyncRequest = function (hAsyncTaskHandle: THandle): Integer; stdcall;
  841.     TWSAAsyncGetHostByName = function (HWindow: HWND;
  842.                                        wMsg: u_int;
  843.                                        name, buf: PChar;
  844.                                        buflen: Integer): THandle; stdcall;
  845.     TWSAAsyncGetHostByAddr = function (HWindow: HWND;
  846.                                        wMsg: u_int; addr: PChar;
  847.                                        len, Struct: Integer;
  848.                                        buf: PChar;
  849.                                        buflen: Integer): THandle; stdcall;
  850.     TWSAAsyncSelect        = function (s: TSocket;
  851.                                        HWindow: HWND;
  852.                                        wMsg: u_int;
  853.                                        lEvent: Longint): Integer; stdcall;
  854.     TGetServByName         = function (name, proto: PChar): PServEnt; stdcall;
  855.     TGetProtoByName        = function (name: PChar): PProtoEnt; stdcall;
  856.     TGetHostByName         = function (name: PChar): PHostEnt; stdcall;
  857.     TGetHostName           = function (name: PChar; len: Integer): Integer; stdcall;
  858.     TOpenSocket            = function (af, Struct, protocol: Integer): TSocket; stdcall;
  859.     TShutdown              = function (s: TSocket; how: Integer): Integer; stdcall;
  860.     TSetSockOpt            = function (s: TSocket; level, optname: Integer;
  861.                                        optval: PChar;
  862.                                        optlen: Integer): Integer; stdcall;
  863.     TGetSockOpt            = function (s: TSocket; level, optname: Integer;
  864.                                        optval: PChar;
  865.                                        var optlen: Integer): Integer; stdcall;
  866.     TSendTo                = function (s: TSocket; var Buf;
  867.                                        len, flags: Integer;
  868.                                        var addrto: TSockAddr;
  869.                                        tolen: Integer): Integer; stdcall;
  870.     TSend                  = function (s: TSocket; var Buf;
  871.                                        len, flags: Integer): Integer; stdcall;
  872.     TRecv                  = function (s: TSocket;
  873.                                        var Buf;
  874.                                        len, flags: Integer): Integer; stdcall;
  875.     TRecvFrom              = function (s: TSocket;
  876.                                        var Buf; len, flags: Integer;
  877.                                        var from: TSockAddr;
  878.                                        var fromlen: Integer): Integer; stdcall;
  879.     Tntohs                 = function (netshort: u_short): u_short; stdcall;
  880.     Tntohl                 = function (netlong: u_long): u_long; stdcall;
  881.     TListen                = function (s: TSocket;
  882.                                        backlog: Integer): Integer; stdcall;
  883.     TIoctlSocket           = function (s: TSocket; cmd: DWORD;
  884.                                        var arg: u_long): Integer; stdcall;
  885.     TInet_ntoa             = function (inaddr: TInAddr): PChar; stdcall;
  886.     TInet_addr             = function (cp: PChar): u_long; stdcall;
  887.     Thtons                 = function (hostshort: u_short): u_short; stdcall;
  888.     Thtonl                 = function (hostlong: u_long): u_long; stdcall;
  889.     TGetSockName           = function (s: TSocket; var name: TSockAddr;
  890.                                        var namelen: Integer): Integer; stdcall;
  891.     TGetPeerName           = function (s: TSocket; var name: TSockAddr;
  892.                                        var namelen: Integer): Integer; stdcall;
  893.     TConnect               = function (s: TSocket; var name: TSockAddr;
  894.                                        namelen: Integer): Integer; stdcall;
  895.     TCloseSocket           = function (s: TSocket): Integer; stdcall;
  896.     TBind                  = function (s: TSocket; var addr: TSockAddr;
  897.                                        namelen: Integer): Integer; stdcall;
  898. {$IFDEF VER90} { Delphi 2 has a special definition}
  899.     TAccept                = function (s: TSocket; var addr: TSockAddr;
  900.                                        var addrlen: Integer): TSocket; stdcall;
  901. {$ELSE}
  902.     TAccept                = function (s: TSocket; addr: PSockAddr;
  903.                                        addrlen: PInteger): TSocket; stdcall;
  904. {$ENDIF}
  905. {$ENDIF}
  906. var
  907.    FWSAStartup            : TWSAStartup;
  908.    FWSACleanup            : TWSACleanup;
  909.    FWSASetLastError       : TWSASetLastError;
  910.    FWSAGetLastError       : TWSAGetLastError;
  911.    FWSACancelAsyncRequest : TWSACancelAsyncRequest;
  912.    FWSAAsyncGetHostByName : TWSAAsyncGetHostByName;
  913.    FWSAAsyncGetHostByAddr : TWSAAsyncGetHostByAddr;
  914.    FWSAAsyncSelect        : TWSAAsyncSelect;
  915.    FGetServByName         : TGetServByName;
  916.    FGetProtoByName        : TGetProtoByName;
  917.    FGetHostByName         : TGetHostByName;
  918.    FGetHostName           : TGetHostName;
  919.    FOpenSocket            : TOpenSocket;
  920.    FShutdown              : TShutdown;
  921.    FSetSockOpt            : TSetSockOpt;
  922.    FGetSockOpt            : TGetSockOpt;
  923.    FSendTo                : TSendTo;
  924.    FSend                  : TSend;
  925.    FRecv                  : TRecv;
  926.    FRecvFrom              : TRecvFrom;
  927.    Fntohs                 : Tntohs;
  928.    Fntohl                 : Tntohl;
  929.    FListen                : TListen;
  930.    FIoctlSocket           : TIoctlSocket;
  931.    FInet_ntoa             : TInet_ntoa;
  932.    FInet_addr             : TInet_addr;
  933.    Fhtons                 : Thtons;
  934.    Fhtonl                 : Thtonl;
  935.    FGetSockName           : TGetSockName;
  936.    FGetPeerName           : TGetPeerName;
  937.    FConnect               : TConnect;
  938.    FCloseSocket           : TCloseSocket;
  939.    FBind                  : TBind;
  940.    FAccept                : TAccept;
  941. function WSocketGetProc(const ProcName : String) : Pointer;
  942. function WSocket_WSAStartup(wVersionRequired: word;
  943.                            var WSData: TWSAData): Integer;
  944. function WSocket_WSACleanup : Integer;
  945. procedure WSocket_WSASetLastError(iError: Integer);
  946. function WSocket_WSAGetLastError: Integer;
  947. function WSocket_WSACancelAsyncRequest(hAsyncTaskHandle: THandle): Integer;
  948. function WSocket_WSAAsyncGetHostByName(HWindow: HWND; wMsg: u_int;
  949.                                       name, buf: PChar;
  950.                                       buflen: Integer): THandle;
  951. function WSocket_WSAAsyncGetHostByAddr(HWindow: HWND;
  952.                                       wMsg: u_int; addr: PChar;
  953.                                       len, Struct: Integer;
  954.                                       buf: PChar;
  955.                                       buflen: Integer): THandle;
  956. function WSocket_WSAAsyncSelect(s: TSocket; HWindow: HWND; wMsg: u_int; lEvent: Longint): Integer;
  957. function WSocket_recv(s: TSocket;
  958.                      var Buf; len, flags: Integer): Integer;
  959. function WSocket_recvfrom(s: TSocket;
  960.                          var Buf; len, flags: Integer;
  961.                          var from: TSockAddr;
  962.                          var fromlen: Integer): Integer;
  963. function WSocket_getservbyname(name, proto: PChar): PServEnt;
  964. function WSocket_getprotobyname(name: PChar): PProtoEnt;
  965. function WSocket_gethostbyname(name: PChar): PHostEnt;
  966. function WSocket_gethostname(name: PChar; len: Integer): Integer;
  967. function WSocket_socket(af, Struct, protocol: Integer): TSocket;
  968. function WSocket_shutdown(s: TSocket; how: Integer): Integer;
  969. function WSocket_setsockopt(s: TSocket; level, optname: Integer; optval: PChar;
  970.                             optlen: Integer): Integer;
  971. function WSocket_getsockopt(s: TSocket; level, optname: Integer; optval: PChar;
  972.                             var optlen: Integer): Integer;
  973. function WSocket_sendto(s: TSocket; var Buf; len, flags: Integer;
  974.                         var addrto: TSockAddr;
  975.                         tolen: Integer): Integer;
  976. function WSocket_send(s: TSocket; var Buf; len, flags: Integer): Integer;
  977. function WSocket_ntohs(netshort: u_short): u_short;
  978. function WSocket_ntohl(netlong: u_long): u_long;
  979. function WSocket_listen(s: TSocket; backlog: Integer): Integer;
  980. function WSocket_ioctlsocket(s: TSocket; cmd: DWORD; var arg: u_long): Integer;
  981. function WSocket_inet_ntoa(inaddr: TInAddr): PChar;
  982. function WSocket_inet_addr(cp: PChar): u_long;
  983. function WSocket_htons(hostshort: u_short): u_short;
  984. function WSocket_htonl(hostlong: u_long): u_long;
  985. function WSocket_getsockname(s: TSocket; var name: TSockAddr;
  986.                              var namelen: Integer): Integer;
  987. function WSocket_getpeername(s: TSocket; var name: TSockAddr;
  988.                              var namelen: Integer): Integer;
  989. function WSocket_connect(s: TSocket; var name: TSockAddr;
  990.                          namelen: Integer): Integer;
  991. function WSocket_closesocket(s: TSocket): Integer;
  992. function WSocket_bind(s: TSocket; var addr: TSockAddr; namelen: Integer): Integer;
  993. {$IFDEF VER80}
  994. function WSocket_accept(s: TSocket; var addr: TSockAddr; var addrlen: Integer): TSocket;
  995. {$ELSE}
  996. {$IFDEF VER90}
  997. function WSocket_accept(s: TSocket; var addr: TSockAddr; var addrlen: Integer): TSocket;
  998. {$ELSE}
  999. function WSocket_accept(s: TSocket; addr: PSockAddr; addrlen: PInteger): TSocket;
  1000. {$ENDIF}
  1001. {$ENDIF}
  1002. implementation
  1003. const
  1004.     GSocketCount   : integer  = 0;
  1005. {    DllStarted     : Boolean  = FALSE;  14/02/99}
  1006.     FDllHandle     : THandle  = 0;
  1007.     FDllName       : String   = winsocket;
  1008.     socksNoError              = 20000;
  1009.     socksProtocolError        = 20001;
  1010.     socksVersionError         = 20002;
  1011.     socksAuthMethodError      = 20003;
  1012.     socksGeneralFailure       = 20004;
  1013.     socksConnectionNotAllowed = 20005;
  1014.     socksNetworkUnreachable   = 20006;
  1015.     socksHostUnreachable      = 20007;
  1016.     socksConnectionRefused    = 20008;
  1017.     socksTtlExpired           = 20009;
  1018.     socksUnknownCommand       = 20010;
  1019.     socksUnknownAddressType   = 20011;
  1020.     socksUnassignedError      = 20012;
  1021.     socksInternalError        = 20013;
  1022.     socksDataReceiveError     = 20014;
  1023.     socksAuthenticationFailed = 20015;
  1024.     socksRejectedOrFailed     = 20016;
  1025.     socksHostResolutionFailed = 20017;
  1026. var
  1027.     GInitData      : TWSADATA;
  1028.     IPList         : TStrings;
  1029. procedure Register;
  1030. begin
  1031.     RegisterComponents('FPiette', [TWSocket]);
  1032. end;
  1033. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1034. {$IFDEF VER80}
  1035. procedure SetLength(var S: string; NewLength: Integer);
  1036. begin
  1037.     S[0] := chr(NewLength);
  1038. end;
  1039. {$ENDIF}
  1040. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1041. function atoi(value : string) : Integer;
  1042. var
  1043.     i : Integer;
  1044. begin
  1045.     Result := 0;
  1046.     i := 1;
  1047.     while (i <= Length(Value)) and (Value[i] = ' ') do
  1048.         i := i + 1;
  1049.     while (i <= Length(Value)) and (Value[i] >= '0') and (Value[i] <= '9')do begin
  1050.         Result := Result * 10 + ord(Value[i]) - ord('0');
  1051.         i := i + 1;
  1052.     end;
  1053. end;
  1054. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1055. function IsDigit(Ch : Char) : Boolean;
  1056. begin
  1057.     Result := (ch >= '0') and (ch <= '9');
  1058. end;
  1059. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1060. {$IFDEF VER80}
  1061. function TrimRight(Str : String) : String;
  1062. var
  1063.     i : Integer;
  1064. begin
  1065.     i := Length(Str);
  1066.     while (i > 0) and (Str[i] = ' ') do
  1067.         i := i - 1;
  1068.     Result := Copy(Str, 1, i);
  1069. end;
  1070. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1071. function TrimLeft(Str : String) : String;
  1072. var
  1073.     i : Integer;
  1074. begin
  1075.     if Str[1] <> ' ' then
  1076.         Result := Str
  1077.     else begin
  1078.         i := 1;
  1079.         while (i <= Length(Str)) and (Str[i] = ' ') do
  1080.             i := i + 1;
  1081.         Result := Copy(Str, i, Length(Str) - i + 1);
  1082.     end;
  1083. end;
  1084. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1085. function Trim(Str : String) : String;
  1086. begin
  1087.     Result := TrimLeft(TrimRight(Str));
  1088. end;
  1089. {$ENDIF}
  1090. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1091. procedure TCustomWSocket.RaiseException(const Msg : String);
  1092. begin
  1093.     if Assigned(FOnError) then
  1094.         TriggerError
  1095.     else
  1096.         raise ESocketException.Create(Msg);
  1097. end;
  1098. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1099. procedure TCustomWSocket.RaiseExceptionFmt(const Fmt : String; args : array of const);
  1100. begin
  1101.     if Assigned(FOnError) then
  1102.         TriggerError
  1103.     else
  1104.         raise ESocketException.CreateFmt(Fmt, args);
  1105. end;
  1106. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1107. {$IFDEF NEVER}       { 14/02/99 }
  1108. function LoadWinsock(FileName : PChar) : Boolean;
  1109. var
  1110.     LastError : LongInt;
  1111. begin
  1112.     if not DllStarted then begin
  1113.         LastError := WSocket_WSAStartup($101, GInitData);
  1114.         if LastError <> 0 then begin
  1115.             raise ESocketException.CreateFmt('%s: WSAStartup error #%d',
  1116.                                              [FileName, LastError]);
  1117.         end;
  1118.         DllStarted := TRUE;
  1119.     end;
  1120.     Result := TRUE;
  1121. end;
  1122. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1123. function WSocketLoadWinsock : Boolean;
  1124. begin
  1125.     Result := LoadWinsock(winsocket);
  1126. end;
  1127. {$ENDIF}
  1128. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1129. procedure WSocketUnloadWinsock;
  1130. begin
  1131. {$IFDEF NEVER}   { 14/02/99 }
  1132.     if DllStarted then begin
  1133.         DllStarted := FALSE;
  1134.         WSocket_WSACleanup;
  1135.     end;
  1136. {$ENDIF}
  1137.     if FDllHandle <> 0 then begin
  1138.         WSocket_WSACleanup;
  1139.         FreeLibrary(FDllHandle);
  1140.         FDllHandle    := 0;
  1141.         FWSAStartup            := nil;
  1142.         FWSACleanup            := nil;
  1143.         FWSASetLastError       := nil;
  1144.         FWSAGetLastError       := nil;
  1145.         FWSACancelAsyncRequest := nil;
  1146.         FWSAAsyncGetHostByName := nil;
  1147.         FWSAAsyncGetHostByAddr := nil;
  1148.         FWSAAsyncSelect        := nil;
  1149.         FGetServByName         := nil;
  1150.         FGetProtoByName        := nil;
  1151.         FGetHostByName         := nil;
  1152.         FGetHostName           := nil; 
  1153.         FOpenSocket            := nil; 
  1154.         FShutdown              := nil; 
  1155.         FSetSockOpt            := nil;
  1156.         FGetSockOpt            := nil;
  1157.         FSendTo                := nil;
  1158.         FSend                  := nil;
  1159.         FRecv                  := nil; 
  1160.         FRecvFrom              := nil; 
  1161.         Fntohs                 := nil; 
  1162.         Fntohl                 := nil; 
  1163.         FListen                := nil; 
  1164.         FIoctlSocket           := nil; 
  1165.         FInet_ntoa             := nil; 
  1166.         FInet_addr             := nil; 
  1167.         Fhtons                 := nil; 
  1168.         Fhtonl                 := nil; 
  1169.         FGetSockName           := nil;
  1170.         FGetPeerName           := nil; 
  1171.         FConnect               := nil; 
  1172.         FCloseSocket           := nil;
  1173.         FBind                  := nil; 
  1174.         FAccept                := nil;
  1175.     end;
  1176. end;
  1177. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1178. function WSocketGetProc(const ProcName : String) : Pointer;
  1179. {$IFDEF VER80}
  1180. var
  1181.     Error     : THandle;
  1182.     Buf       : String;
  1183.     LastError : LongInt;
  1184. begin
  1185.     if FDllHandle = 0 then begin
  1186.        { Delphi 1 strings are not nul terminated }
  1187.         Buf := FDllName + #0;
  1188.         FDllHandle := LoadLibrary(@Buf[1]);
  1189.         if FDllHandle < HINSTANCE_ERROR then begin
  1190.             Error      := FDllHandle;
  1191.             FDllHandle := 0;
  1192.             raise ESocketException.Create('Unable to load ' + FDllName +
  1193.                                           ' Error #' + IntToStr(Error));
  1194.         end;
  1195.         LastError := WSocket_WSAStartup($101, GInitData);
  1196.         if LastError <> 0 then begin
  1197.             raise ESocketException.CreateFmt('%s: WSAStartup error #%d',
  1198.                                              [FDllName, LastError]);
  1199.         end;
  1200.     end;
  1201.     if Length(ProcName) = 0 then
  1202.         Result := nil
  1203.     else begin
  1204.         { Delphi 1 strings are not nul terminated }
  1205.         Buf := ProcName + #0;
  1206.         Result := GetProcAddress(FDllHandle, @Buf[1]);
  1207.         if Result = nil then
  1208.             raise ESocketException.Create('Procedure ' + ProcName +
  1209.                                           ' not found in ' + FDllName);
  1210.     end;
  1211. end;
  1212. {$ELSE}
  1213. var
  1214.     LastError : LongInt;
  1215. begin
  1216.     if FDllHandle = 0 then begin
  1217.         FDllHandle := LoadLibrary(@FDllName[1]);
  1218.         if FDllHandle = 0 then
  1219.             raise ESocketException.Create('Unable to load ' + FDllName +
  1220.                                           ' Error #' + IntToStr(GetLastError));
  1221.         LastError := WSocket_WSAStartup($101, GInitData);
  1222.         if LastError <> 0 then begin
  1223.             raise ESocketException.CreateFmt('%s: WSAStartup error #%d',
  1224.                                              [FDllName, LastError]);
  1225.         end;
  1226.     end;
  1227.     if Length(ProcName) = 0 then
  1228.         Result := nil
  1229.     else begin
  1230.         Result := GetProcAddress(FDllHandle, @ProcName[1]);
  1231.         if Result = nil then
  1232.             raise ESocketException.Create('Procedure ' + ProcName +
  1233.                                           ' not found in ' + winsocket +
  1234.                                           ' Error #' + IntToStr(GetLastError));
  1235.     end;
  1236. end;
  1237. {$ENDIF}
  1238. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1239. function WSocket_WSAStartup(
  1240.     wVersionRequired: word;
  1241.     var WSData: TWSAData): Integer;
  1242. begin
  1243.     if @FWSAStartup = nil then
  1244.         @FWSAStartup := WSocketGetProc('WSAStartup');
  1245.     Result := FWSAStartup(wVersionRequired, WSData);
  1246. end;
  1247. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1248. function WSocket_WSACleanup : Integer;
  1249. begin
  1250.     if @FWSACleanup = nil then
  1251.         @FWSACleanup := WSocketGetProc('WSACleanup');
  1252.     Result := FWSACleanup;
  1253. end;
  1254. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1255. procedure WSocket_WSASetLastError(iError: Integer);
  1256. begin
  1257.     if @FWSASetLastError = nil then
  1258.         @FWSASetLastError := WSocketGetProc('WSASetLastError');
  1259.     FWSASetLastError(iError);
  1260. end;
  1261. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1262. function WSocket_WSAGetLastError: Integer;
  1263. begin
  1264.     if @FWSAGetLastError = nil then
  1265.         @FWSAGetLastError := WSocketGetProc('WSAGetLastError');
  1266.     Result := FWSAGetLastError;
  1267. end;
  1268. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1269. function WSocket_WSACancelAsyncRequest(hAsyncTaskHandle: THandle): Integer;
  1270. begin
  1271.     if @FWSACancelAsyncRequest = nil then
  1272.         @FWSACancelAsyncRequest := WSocketGetProc('WSACancelAsyncRequest');
  1273.     Result := FWSACancelAsyncRequest(hAsyncTaskHandle);
  1274. end;
  1275. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1276. function WSocket_WSAAsyncGetHostByName(
  1277.     HWindow: HWND; wMsg: u_int;
  1278.     name, buf: PChar;
  1279.     buflen: Integer): THandle;
  1280. begin
  1281.     if @FWSAAsyncGetHostByName = nil then
  1282.         @FWSAAsyncGetHostByName := WSocketGetProc('WSAAsyncGetHostByName');
  1283.     Result := FWSAAsyncGetHostByName(HWindow, wMsg, name, buf, buflen);
  1284. end;
  1285. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1286. function WSocket_WSAAsyncGetHostByAddr(
  1287.     HWindow: HWND;
  1288.     wMsg: u_int; addr: PChar;
  1289.     len, Struct: Integer;
  1290.     buf: PChar;
  1291.     buflen: Integer): THandle;
  1292. begin
  1293.     if @FWSAAsyncGetHostByAddr = nil then
  1294.         @FWSAAsyncGetHostByAddr := WSocketGetProc('WSAAsyncGetHostByAddr');
  1295.     Result := FWSAAsyncGetHostByAddr(HWindow, wMsg, addr, len, struct, buf, buflen);
  1296. end;
  1297. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1298. function WSocket_WSAAsyncSelect(
  1299.     s: TSocket;
  1300.     HWindow: HWND;
  1301.     wMsg: u_int;
  1302.     lEvent: Longint): Integer;
  1303. begin
  1304.     if @FWSAAsyncSelect = nil then
  1305.         @FWSAAsyncSelect := WSocketGetProc('WSAAsyncSelect');
  1306.     Result := FWSAAsyncSelect(s, HWindow, wMsg, lEvent);
  1307. end;
  1308. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1309. function WSocket_getservbyname(name, proto: PChar): PServEnt;
  1310. begin
  1311.     if @Fgetservbyname = nil then
  1312.         @Fgetservbyname := WSocketGetProc('getservbyname');
  1313.     Result := Fgetservbyname(name, proto);
  1314. end;
  1315. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1316. function WSocket_getprotobyname(name: PChar): PProtoEnt;
  1317. begin
  1318.     if @Fgetprotobyname = nil then
  1319.         @Fgetprotobyname := WSocketGetProc('getprotobyname');
  1320.     Result := Fgetprotobyname(name);
  1321. end;
  1322. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1323. function WSocket_gethostbyname(name: PChar): PHostEnt;
  1324. begin
  1325.     if @Fgethostbyname = nil then
  1326.         @Fgethostbyname := WSocketGetProc('gethostbyname');
  1327.     Result := Fgethostbyname(name);
  1328. end;
  1329. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1330. function WSocket_gethostname(name: PChar; len: Integer): Integer;
  1331. begin
  1332.     if @Fgethostname = nil then
  1333.         @Fgethostname := WSocketGetProc('gethostname');
  1334.     Result := Fgethostname(name, len);
  1335. end;
  1336. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1337. function WSocket_socket(af, Struct, protocol: Integer): TSocket;
  1338. begin
  1339.     if @FOpenSocket= nil then
  1340.         @FOpenSocket := WSocketGetProc('socket');
  1341.     Result := FOpenSocket(af, Struct, protocol);
  1342. end;
  1343. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1344. function WSocket_shutdown(s: TSocket; how: Integer): Integer;
  1345. begin
  1346.     if @FShutdown = nil then
  1347.         @FShutdown := WSocketGetProc('shutdown');
  1348.     Result := FShutdown(s, how);
  1349. end;
  1350. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1351. function WSocket_setsockopt(s: TSocket; level, optname: Integer; optval: PChar;
  1352.                             optlen: Integer): Integer;
  1353. begin
  1354.     if @FSetSockOpt = nil then
  1355.         @FSetSockOpt := WSocketGetProc('setsockopt');
  1356.     Result := FSetSockOpt(s, level, optname, optval, optlen);
  1357. end;
  1358. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1359. function WSocket_getsockopt(
  1360.     s: TSocket; level, optname: Integer;
  1361.     optval: PChar; var optlen: Integer): Integer;
  1362. begin
  1363.     if @FGetSockOpt = nil then
  1364.         @FGetSockOpt := WSocketGetProc('getsockopt');
  1365.     Result := FGetSockOpt(s, level, optname, optval, optlen);
  1366. end;
  1367. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1368. function WSocket_sendto(
  1369.     s: TSocket;
  1370.     var Buf;
  1371.     len, flags: Integer;
  1372.     var addrto: TSockAddr;
  1373.     tolen: Integer): Integer;
  1374. begin
  1375.     if @FSendTo = nil then
  1376.         @FSendTo := WSocketGetProc('sendto');
  1377.     Result := FSendTo(s, Buf, len, flags, addrto, tolen);
  1378. end;
  1379. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1380. function WSocket_send(s: TSocket; var Buf; len, flags: Integer): Integer;
  1381. begin
  1382.     if @FSend = nil then
  1383.         @FSend := WSocketGetProc('send');
  1384.     Result := FSend(s, Buf, len, flags);
  1385. end;
  1386. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1387. function WSocket_ntohs(netshort: u_short): u_short;
  1388. begin
  1389.     if @Fntohs = nil then
  1390.         @Fntohs := WSocketGetProc('ntohs');
  1391.     Result := Fntohs(netshort);
  1392. end;
  1393. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1394. function WSocket_ntohl(netlong: u_long): u_long;
  1395. begin
  1396.     if @Fntohl = nil then
  1397.         @Fntohl := WSocketGetProc('ntohl');
  1398.     Result := Fntohl(netlong);
  1399. end;
  1400. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1401. function WSocket_listen(s: TSocket; backlog: Integer): Integer;
  1402. begin
  1403.     if @FListen = nil then
  1404.         @FListen := WSocketGetProc('listen');
  1405.     Result := FListen(s, backlog);
  1406. end;
  1407. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1408. function WSocket_ioctlsocket(s: TSocket; cmd: DWORD; var arg: u_long): Integer;
  1409. begin
  1410.     if @FIoctlSocket = nil then
  1411.         @FIoctlSocket := WSocketGetProc('ioctlsocket');
  1412.     Result := FIoctlSocket(s, cmd, arg);
  1413. end;
  1414. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1415. function WSocket_inet_ntoa(inaddr: TInAddr): PChar;
  1416. begin
  1417.     if @FInet_ntoa = nil then
  1418.         @FInet_ntoa := WSocketGetProc('inet_ntoa');
  1419.     Result := FInet_ntoa(inaddr);
  1420. end;
  1421. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1422. function WSocket_inet_addr(cp: PChar): u_long;
  1423. begin
  1424.     if @FInet_addr = nil then
  1425.         @FInet_addr := WSocketGetProc('inet_addr');
  1426.     Result := FInet_addr(cp);
  1427. end;
  1428. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1429. function WSocket_htons(hostshort: u_short): u_short;
  1430. begin
  1431.     if @Fhtons = nil then
  1432.         @Fhtons := WSocketGetProc('htons');
  1433.     Result := Fhtons(hostshort);
  1434. end;
  1435. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1436. function WSocket_htonl(hostlong: u_long): u_long;
  1437. begin
  1438.     if @Fhtonl = nil then
  1439.         @Fhtonl := WSocketGetProc('htonl');
  1440.     Result := Fhtonl(hostlong);
  1441. end;
  1442. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1443. function WSocket_getsockname(
  1444.     s: TSocket;
  1445.     var name: TSockAddr;
  1446.     var namelen: Integer): Integer;
  1447. begin
  1448.     if @FGetSockName = nil then
  1449.         @FGetSockName := WSocketGetProc('getsockname');
  1450.     Result := FGetSockName(s, name, namelen);
  1451. end;
  1452. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1453. function WSocket_getpeername(
  1454.     s: TSocket;
  1455.     var name: TSockAddr;
  1456.     var namelen: Integer): Integer;
  1457. begin
  1458.     if @FGetPeerName = nil then
  1459.         @FGetPeerName := WSocketGetProc('getpeername');
  1460.     Result := FGetPeerName(s, name, namelen);
  1461. end;
  1462. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1463. function WSocket_connect(
  1464.     s: TSocket;
  1465.     var name: TSockAddr;
  1466.     namelen: Integer): Integer;
  1467. begin
  1468.     if @FConnect= nil then
  1469.         @FConnect := WSocketGetProc('connect');
  1470.     Result := FConnect(s, name, namelen);
  1471. end;
  1472. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1473. function WSocket_closesocket(s: TSocket): Integer;
  1474. begin
  1475.     if @FCloseSocket = nil then
  1476.         @FCloseSocket := WSocketGetProc('closesocket');
  1477.     Result := FCloseSocket(s);
  1478. end;
  1479. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1480. function WSocket_bind(
  1481.     s: TSocket;
  1482.     var addr: TSockAddr;
  1483.     namelen: Integer): Integer;
  1484. begin
  1485.     if @FBind = nil then
  1486.         @FBind := WSocketGetProc('bind');
  1487.     Result := FBind(s, addr, namelen);
  1488. end;
  1489. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1490. function WSocket_accept(
  1491.     s: TSocket;
  1492. {$IFDEF VER80} { Delphi 1 }
  1493.     var addr: TSockAddr;
  1494.     var addrlen: Integer): TSocket;
  1495. {$ELSE}
  1496. {$IFDEF VER90} { Delphi 2 }
  1497.     var addr: TSockAddr;
  1498.     var addrlen: Integer): TSocket;
  1499. {$ELSE}{ Delphi 3/4 }
  1500.     addr: PSockAddr;
  1501.     addrlen: PInteger): TSocket;
  1502. {$ENDIF}
  1503. {$ENDIF}
  1504. begin
  1505.     if @FAccept = nil then
  1506.         @FAccept := WSocketGetProc('accept');
  1507.     Result := FAccept(s, addr, addrlen);
  1508. end;
  1509. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1510. function WSocket_recv(s: TSocket; var Buf; len, flags: Integer): Integer;
  1511. begin
  1512.     if @FRecv= nil then
  1513.         @FRecv := WSocketGetProc('recv');
  1514.     Result := FRecv(s, Buf, len, flags);
  1515. end;
  1516. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1517. function WSocket_recvfrom(
  1518.     s: TSocket;
  1519.     var Buf; len, flags: Integer;
  1520.     var from: TSockAddr;
  1521.     var fromlen: Integer): Integer;
  1522. begin
  1523.     if @FRecvFrom = nil then
  1524.         @FRecvFrom := WSocketGetProc('recvfrom');
  1525.     Result := FRecvFrom(s, Buf, len, flags, from, fromlen);
  1526. end;
  1527. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1528. function WinsockInfo : TWSADATA;
  1529. begin
  1530. {    LoadWinsock(winsocket); 14/02/99 }
  1531.     { Load winsock and initialize it as needed }
  1532.     WSocketGetProc('');
  1533.     Result := GInitData;
  1534.     { If no socket created, then unload winsock immediately }
  1535.     if GSocketCount <= 0 then
  1536.         WSocketUnloadWinsock;
  1537. end;
  1538. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1539. procedure TCustomWSocket.Notification(AComponent: TComponent; operation: TOperation);
  1540. begin
  1541.     inherited Notification(AComponent, operation);
  1542.     if operation = opRemove then begin
  1543.     end;
  1544. end;
  1545. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1546. procedure TCustomWSocket.AssignDefaultValue;
  1547. begin
  1548.     FillChar(sin, 0, Sizeof(sin));
  1549.     sin.sin_family     := AF_INET;
  1550.     FAddrFormat        := PF_INET;
  1551.     FPortAssigned      := FALSE;
  1552.     FAddrAssigned      := FALSE;
  1553.     FAddrResolved      := FALSE;
  1554.     FPortResolved      := FALSE;
  1555.     FProtoResolved     := FALSE;
  1556.     FLocalPortResolved := FALSE;
  1557.     FProtoAssigned     := TRUE;
  1558.     FProto             := IPPROTO_TCP;
  1559.     FProtoStr          := 'tcp';
  1560.     FType              := SOCK_STREAM;
  1561.     FLocalPortStr      := '0';
  1562.     FLingerOnOff       := wsLingerOn;
  1563.     FLingerTimeout     := 0;
  1564.     FHSocket           := INVALID_SOCKET;
  1565.     FState             := wsClosed;
  1566.     bMoreFlag          := FALSE;
  1567.     nMoreCnt           := 0;
  1568.     nMoreMax           := 24;
  1569.     bWrite             := FALSE;
  1570.     bAllSent           := TRUE;
  1571.     FPaused            := FALSE;
  1572.     FReadCount         := 0;
  1573.     FCloseInvoked      := FALSE;
  1574.     FFlushTimeout      := 60;
  1575. end;
  1576. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1577. { All exceptions *MUST* be handled. If an exception is not handled, the     }
  1578. { application will be shut down !                                           }
  1579. procedure TCustomWSocket.HandleBackGroundException(E: Exception);
  1580. var
  1581.     CanAbort : Boolean;
  1582. begin
  1583.     CanAbort := TRUE;
  1584.     { First call the error event handler, if any }
  1585.     if Assigned(FOnBgException) then begin
  1586.         try
  1587.             FOnBgException(Self, E, CanAbort);
  1588.         except
  1589.         end;
  1590.     end;
  1591.     { Then abort the socket }
  1592.     if CanAbort then begin
  1593.         try
  1594.             Abort;
  1595.         except
  1596.         end;
  1597.     end;
  1598. end;
  1599. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1600. { This procedure handle all messages for TWSocket. All exceptions must be   }
  1601. { handled or the application will be shutted down !                         }
  1602. { If WndProc is overriden in descendent components, then the same exception }
  1603. { handling *MUST* be setup because descendent component code is executed    }
  1604. { before the base class code.                                               }
  1605. procedure TCustomWSocket.WndProc(var MsgRec: TMessage);
  1606. begin
  1607.     try
  1608.         with MsgRec do begin
  1609.             if Msg = WM_ASYNCSELECT then
  1610.                 WMASyncSelect(MsgRec)
  1611.             else if Msg = WM_ASYNCGETHOSTBYNAME then
  1612.                 WMAsyncGetHostByName(MsgRec)
  1613.             else if Msg = WM_ASYNCGETHOSTBYADDR then
  1614.                 WMAsyncGetHostByAddr(MsgRec)
  1615.             else
  1616.                 Result := DefWindowProc(Handle, Msg, wParam, lParam);
  1617.         end;
  1618.     except
  1619.         on E:Exception do
  1620.             HandleBackGroundException(E);
  1621.     end;
  1622. end;
  1623. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1624. {$IFNDEF VER80}
  1625. { This function is a callback function. It means that it is called by       }
  1626. { windows. This is the very low level message handler procedure setup to    }
  1627. { handle the message sent by windows (winsock) to handle messages.          }
  1628. function XSocketWindowProc(
  1629.     ahWnd   : HWND;
  1630.     auMsg   : Integer;
  1631.     awParam : WPARAM;
  1632.     alParam : LPARAM): Integer; stdcall;
  1633. var
  1634.     Obj    : TObject;
  1635.     MsgRec : TMessage;
  1636. begin
  1637.     { At window creation asked windows to store a pointer to our object     }
  1638.     Obj := TObject(GetWindowLong(ahWnd, 0));
  1639.     { If the pointer doesn't represent a TWSocket, just call the default procedure}
  1640.     if not (Obj is TCustomWSocket) then
  1641.         Result := DefWindowProc(ahWnd, auMsg, awParam, alParam)
  1642.     else begin
  1643.         { Delphi use a TMessage type to pass parameter to his own kind of   }
  1644.         { windows procedure. So we are doing the same...                    }
  1645.         MsgRec.Msg    := auMsg;
  1646.         MsgRec.wParam := awParam;
  1647.         MsgRec.lParam := alParam;
  1648.         { May be a try/except around next line is needed. Not sure ! }
  1649.         TWSocket(Obj).WndProc(MsgRec);
  1650.         Result := MsgRec.Result;
  1651.     end;
  1652. end;
  1653. {$ENDIF}
  1654. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1655. procedure TCustomWSocket.MessagePump;
  1656. begin
  1657. {$IFDEF NOFORMS}
  1658.     { The Forms unit (TApplication object) has not been included.           }
  1659.     { We used either an external message pump or our internal message pump. }
  1660.     { External message pump has to set Terminated property to TRUE when the }
  1661.     { application is terminated.                                            }
  1662.     if Assigned(FOnMessagePump) then
  1663.         FOnMessagePump(Self)
  1664.     else
  1665.         Self.ProcessMessages;  
  1666. {$ELSE}
  1667. {$IFNDEF VER80}
  1668.     { Delphi 1 doesn't support multithreading }
  1669.     if FMultiThreaded then
  1670.         Self.ProcessMessages
  1671.     else
  1672. {$ENDIF}
  1673.         Application.ProcessMessages;
  1674. {$ENDIF}
  1675. end;
  1676. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1677. { This function is very similar to TApplication.ProcessMessage              }
  1678. { You can also use it if your application has no TApplication object (Forms }
  1679. { unit not referenced at all).                                              }
  1680. {$IFNDEF VER80}
  1681. function TCustomWSocket.ProcessMessage : Boolean;
  1682. var
  1683.     Msg : TMsg;
  1684. begin
  1685.     Result := FALSE;
  1686.     if PeekMessage(Msg, 0, 0, 0, PM_REMOVE) then begin
  1687.         Result := TRUE;
  1688.         if Msg.Message = WM_QUIT then
  1689.             FTerminated := TRUE
  1690.         else begin
  1691.             TranslateMessage(Msg);
  1692.             DispatchMessage(Msg);
  1693.         end;
  1694.     end;
  1695. end;
  1696. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1697. { Loop thru message processing until all messages are processed.            }
  1698. { This function is very similar to TApplication.ProcessMessage              }
  1699. { This is intended for multithreaded application using TWSocket.            }
  1700. { You can also use it if your application has no TApplication object (Forms }
  1701. { unit not referenced at all).                                              }
  1702. procedure TCustomWSocket.ProcessMessages;
  1703. begin
  1704.     while Self.ProcessMessage do { loop };
  1705. end;
  1706. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1707. { Loop thru message processing until the WM_QUIT message is received        }
  1708. { This is intended for multithreaded application using TWSocket.            }
  1709. { MessageLoop is different from ProcessMessages because it actually block   }
  1710. { if no message is available. The loop is broken when WM_QUIT is retrieved. }
  1711. procedure TCustomWSocket.MessageLoop;
  1712. var
  1713.     MsgRec : TMsg;
  1714. begin
  1715.     { If GetMessage retrieves the WM_QUIT, the return value is FALSE and    }
  1716.     { the message loop is broken.                                           }
  1717.     while GetMessage(MsgRec, 0, 0, 0) do begin
  1718.         TranslateMessage(MsgRec);
  1719.         DispatchMessage(MsgRec)
  1720.     end;
  1721.     FTerminated := TRUE;
  1722. end;
  1723. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1724. { This global variable is used to store the windows class characteristic    }
  1725. { and is needed to register the window class used by TWSocket               }
  1726. var
  1727.     XSocketWindowClass: TWndClass = (
  1728.         style         : 0;
  1729.         lpfnWndProc   : @XSocketWindowProc;
  1730.         cbClsExtra    : 0;
  1731.         cbWndExtra    : SizeOf(Pointer);
  1732.         hInstance     : 0;
  1733.         hIcon         : 0;
  1734.         hCursor       : 0;
  1735.         hbrBackground : 0;
  1736.         lpszMenuName  : nil;
  1737.         lpszClassName : 'XSocketWindowClass');
  1738. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1739. { Allocate a window handle. This means registering a window class the first }
  1740. { time we are called, and creating a new window each time we are called.    }
  1741. function XSocketAllocateHWnd(Obj : TObject): HWND;
  1742. var
  1743.     TempClass       : TWndClass;
  1744.     ClassRegistered : Boolean;
  1745. begin
  1746.     { Check if the window class is already registered                       }
  1747.     XSocketWindowClass.hInstance := HInstance;
  1748.     ClassRegistered := GetClassInfo(HInstance,
  1749.                                     XSocketWindowClass.lpszClassName,
  1750.                                     TempClass);
  1751.     if not ClassRegistered then begin
  1752.        { Not yet registered, do it right now                                }
  1753.        Result := WinProcs.RegisterClass(XSocketWindowClass);
  1754.        if Result = 0 then
  1755.            Exit;
  1756.     end;
  1757.     { Now create a new window                                               }
  1758.     Result := CreateWindowEx(WS_EX_TOOLWINDOW,
  1759.                              XSocketWindowClass.lpszClassName,
  1760.                              '',        { Window name   }
  1761.                              WS_POPUP,  { Window Style  }
  1762.                              0, 0,      { X, Y          }
  1763.                              0, 0,      { Width, Height }
  1764.                              0,         { hWndParent    }
  1765.                              0,         { hMenu         }
  1766.                              HInstance, { hInstance     }
  1767.                              nil);      { CreateParam   }
  1768.     { if successfull, the ask windows to store the object reference         }
  1769.     { into the reserved byte (see RegisterClass)                            }
  1770.     if (Result <> 0) and Assigned(Obj) then
  1771.         SetWindowLong(Result, 0, Integer(Obj));
  1772. end;
  1773. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1774. { Free the window handle                                                    }
  1775. procedure XSocketDeallocateHWnd(Wnd: HWND);
  1776. begin
  1777.     DestroyWindow(Wnd);
  1778. end;
  1779. {$ENDIF}
  1780. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1781. constructor TCustomWSocket.Create(AOwner: TComponent);
  1782. begin
  1783.     inherited Create(AOwner);
  1784. {$IFDEF VER80}
  1785.     { Delphi 16 bits has no thread, we can use the VCL                      }
  1786.     FWindowHandle := AllocateHWnd(WndProc);
  1787. {$ELSE}
  1788.     { Delphi 32 bits has threads and VCL is not thread safe.                }
  1789.     { We need to do our own way to be thread safe.                          }
  1790.     FWindowHandle := XSocketAllocateHWnd(Self);
  1791. {$ENDIF}
  1792.     FBufList       := TList.Create;
  1793.     FBufSize       := 1514;                { Default buffer size }
  1794.     FDnsResultList := TStringList.Create;
  1795.     AssignDefaultValue;
  1796.     GSocketCount := GSocketCount + 1;
  1797. {   LoadWinsock(WINSOCKET);}
  1798. end;
  1799. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1800. destructor TCustomWSocket.Destroy;
  1801. begin
  1802.     try
  1803.         CancelDnsLookup;             { Cancel any pending dns lookup      }
  1804.     except
  1805.         { Ignore any exception here }
  1806.     end;
  1807.     if FState <> wsClosed then       { Close the socket if not yet closed }
  1808.         Close;
  1809.     GSocketCount := GSocketCount - 1;
  1810.     if {**(not (csDesigning in ComponentState)) and **}
  1811. {       (DllStarted) and  14/02/99 }
  1812.        (GSocketCount <= 0) then begin
  1813.         WSocketUnloadWinsock;
  1814.         GSocketCount := 0;
  1815.     end;
  1816.     DeleteBufferedData;
  1817.     FBufList.Free;
  1818.     FDnsResultList.Free;
  1819.     { Remove the object reference from the window }
  1820.     SetWindowLong(FWindowHandle, 0, 0);
  1821. {$IFDEF VER80}
  1822.     DeallocateHWnd(FWindowHandle);
  1823. {$ELSE}
  1824.     XSocketDeallocateHWnd(FWindowHandle);
  1825. {$ENDIF}
  1826.     inherited Destroy;
  1827. end;
  1828. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1829. procedure TCustomWSocket.Dup(NewHSocket : TSocket);
  1830. var
  1831.     iStatus : Integer;
  1832. begin
  1833.     if (NewHSocket = 0) or (NewHSocket = INVALID_SOCKET) then begin
  1834.         WSocket_WSASetLastError(WSAEINVAL);
  1835.         SocketError('Dup');
  1836.         Exit;
  1837.     end;
  1838.     if FState <> wsClosed then begin
  1839.         iStatus := WSocket_closesocket(FHSocket);
  1840.         FHSocket := INVALID_SOCKET;
  1841.         if iStatus <> 0 then begin
  1842.             SocketError('Dup (closesocket)');
  1843.             Exit;
  1844.         end;
  1845.         ChangeState(wsClosed);
  1846.     end;
  1847.     FHsocket := NewHSocket;
  1848.     SetLingerOption;
  1849.     iStatus := WSocket_WSAASyncSelect(
  1850.                    FHSocket, Handle, WM_ASYNCSELECT,
  1851.                    FD_READ or FD_WRITE or FD_CLOSE or FD_CONNECT);
  1852.     if iStatus <> 0 then begin
  1853.         SocketError('WSAAsyncSelect');
  1854.         Exit;
  1855.     end;
  1856.     ChangeState(wsConnected);
  1857. end;
  1858. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1859. { Get the number of char received and waiting to be read                    }
  1860. function TCustomWSocket.GetRcvdCount : LongInt;
  1861. begin
  1862.     if WSocket_ioctlsocket(FHSocket, FIONREAD, Result) = SOCKET_ERROR then begin
  1863.         Result := -1;
  1864.         SocketError('ioctlSocket');
  1865.         Exit;
  1866.     end;
  1867. end;
  1868. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1869. procedure TCustomWSocket.ChangeState(NewState : TSocketState);
  1870. var
  1871.     OldState : TSocketState;
  1872. begin
  1873.     OldState := FState;
  1874.     FState   := NewState;
  1875.     TriggerChangeState(OldState, NewState);
  1876. end;
  1877. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1878. { DoRecv is a simple wrapper around winsock recv function to make it        }
  1879. { a virtual function.                                                       }
  1880. function TCustomWSocket.DoRecv(
  1881.     var Buffer;
  1882.     BufferSize : Integer;
  1883.     Flags      : Integer) : Integer;
  1884. begin
  1885.     Result := WSocket_recv(FHSocket, Buffer, BufferSize, Flags);
  1886. {   FRcvdFlag := (Result > 0);}
  1887.     { If we received the requested size, we may need to receive more }
  1888.     FRcvdFlag := (Result >= BufferSize);
  1889. end;
  1890. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1891. { The socket is non-blocking, so this routine will only receive as much     }
  1892. { data as it is available.                                                  }
  1893. function TCustomWSocket.Receive(Buffer : Pointer; BufferSize: integer) : integer;
  1894. begin
  1895.     Result := DoRecv(Buffer^, BufferSize, 0);
  1896.     if Result < 0 then
  1897.         FLastError := WSocket_WSAGetLastError
  1898.     else
  1899.         FReadCount := FReadCount + Result;
  1900. end;
  1901. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1902. { Receive as much data as possible into a string                            }
  1903. { You should avoid this function and use Receive. Using string will be      }
  1904. { much slower because data will be copied several times.                    }
  1905. { ReceiveStr will *NOT* wait for a line to be received. It just read        }
  1906. { already received characters and return them as a string.                  }
  1907. function TCustomWSocket.ReceiveStr : string;
  1908. var
  1909.     lCount : LongInt;
  1910. begin
  1911.     SetLength(Result, 0);
  1912.     lCount := GetRcvdCount;
  1913. {$IFDEF VER80}
  1914.     { Delphi 1 strings are limited }
  1915.     if lCount > High(Result) then
  1916.         lCount := High(Result);
  1917. {$ENDIF}
  1918.     if lCount > 0 then begin
  1919.         SetLength(Result, lCount);
  1920.         lCount := DoRecv(Result[1], lCount, 0);
  1921.         if lCount > 0 then
  1922.             SetLength(Result, lCount)
  1923.         else
  1924.             SetLength(Result, 0);
  1925.     end;
  1926. end;
  1927. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1928. function TCustomWSocket.DoRecvFrom(
  1929.     FHSocket    : TSocket;
  1930.     var Buffer;
  1931.     BufferSize  : Integer;
  1932.     Flags       : Integer;
  1933.     var From    : TSockAddr;
  1934.     var FromLen : Integer) : Integer;
  1935. begin
  1936.     Result := WSocket_recvfrom(FHSocket, Buffer, BufferSize,
  1937.                                Flags, From, FromLen);
  1938. {   FRcvdFlag := (Result > 0); }
  1939.     FRcvdFlag := (Result >= BufferSize);
  1940. end;
  1941. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1942. function TCustomWSocket.ReceiveFrom(
  1943.     Buffer      : Pointer;
  1944.     BufferSize  : Integer;
  1945.     var From    : TSockAddr;
  1946.     var FromLen : Integer) : integer;
  1947. begin
  1948.     Result := DoRecvFrom(FHSocket, Buffer^, BufferSize, 0, From, FromLen);
  1949.     if Result < 0 then
  1950.         FLastError := WSocket_WSAGetLastError
  1951.     else
  1952.         FReadCount := FReadCount + Result;
  1953. end;
  1954. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1955. function TCustomWSocket.PeekData(Buffer : Pointer; BufferSize: integer) : integer;
  1956. begin
  1957.     Result := DoRecv(Buffer^, BufferSize, MSG_PEEK);
  1958.     if Result < 0 then
  1959.         FLastError := WSocket_WSAGetLastError;
  1960. end;
  1961. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1962. function SearchChar(Data : PChar; Len : Integer; Ch : Char) : PChar;
  1963. begin
  1964.     while Len > 0 do begin
  1965.         Len := Len - 1;
  1966.         if Data^ = Ch then begin
  1967.             Result := Data;
  1968.             exit;
  1969.         end;
  1970.         Data := Data + 1;
  1971.     end;
  1972.     Result := nil;
  1973. end;
  1974. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1975. function TCustomWSocket.SendTo(
  1976.     Dest    : TSockAddr;
  1977.     DestLen : Integer;
  1978.     Data    : Pointer;
  1979.     Len     : Integer) : integer;
  1980. begin
  1981.     Result := WSocket_SendTo(FHSocket, Data^, Len, FSendFlags,
  1982.                              TSockAddr(Dest), DestLen)
  1983. end;
  1984. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1985. function TCustomWSocket.RealSend(Data : Pointer; Len : Integer) : Integer;
  1986. begin
  1987.     if FType = SOCK_DGRAM then
  1988.         Result := WSocket_SendTo(FHSocket, Data^, Len, FSendFlags,
  1989.                                  TSockAddr(sin), SizeOf(sin))
  1990.     else
  1991.         Result := WSocket_Send(FHSocket, Data^, Len, FSendFlags);
  1992. end;
  1993. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1994. procedure TCustomWSocket.TryToSend;
  1995. var
  1996.     oBuffer   : TBuffer;
  1997.     Len       : Integer;
  1998.     Count     : Integer;
  1999.     Data      : Pointer;
  2000.     LastError : Integer;
  2001.     p         : PChar;
  2002.     bMore     : Boolean;
  2003. begin
  2004.     if (FHSocket = INVALID_SOCKET) or                { No more socket      }
  2005.        (FBufList.Count = 0) or                       { Nothing to send     }
  2006.        (bMoreFlag and (nMoreCnt >= nMoreMax)) then   { Waiting more signal }
  2007.         exit;
  2008.     bMore := TRUE;
  2009.     while bMore do begin
  2010.         oBuffer := FBufList.First;
  2011.         Data    := oBuffer.Peek(Len);
  2012.         if Len <= 0 then begin
  2013.             { Buffer is empty }
  2014.             if FBufList.Count <= 1 then begin
  2015.                 { Every thing has been sent }
  2016.                 bAllSent := TRUE;
  2017.                 bMore    := FALSE;
  2018.             end
  2019.             else begin
  2020.                 oBuffer.Free;
  2021.                 FBufList.Delete(0);
  2022.                 FBufList.Pack;
  2023.             end;
  2024.         end
  2025.         else begin
  2026.             if bMoreFlag then begin
  2027.                 p := SearchChar(Data, Len, #10);
  2028.                 if Assigned(p) then begin
  2029.                     len := p - PChar(Data) + 1;
  2030.                     nMoreCnt := nMoreCnt + 1;
  2031.                     if nMoreCnt >= nMoreMax then
  2032.                         bMore := FALSE;
  2033.                 end;
  2034.             end;
  2035.             Count := RealSend(Data, Len);
  2036.             if Count = 0 then
  2037.                 bMore := FALSE  { Closed by remote }
  2038.             else if count = SOCKET_ERROR then begin
  2039.                 LastError := WSocket_WSAGetLastError;
  2040.                 if (LastError = WSAECONNRESET) or (LastError = WSAENOTSOCK) or
  2041.                    (LastError = WSAENOTCONN)   or (LastError = WSAEINVAL)   or
  2042.                    (LastError = WSAECONNABORTED)     { 07/05/99 }
  2043.                 then begin
  2044.                     FCloseInvoked := TRUE;           { 23/07/98 }
  2045.                     Close;
  2046.                     TriggerSessionClosed(LastError); { 23/07/98 }
  2047.                 end
  2048.                 else if LastError <> WSAEWOULDBLOCK then begin
  2049.                     SocketError('TryToSend failed');
  2050.                     Exit;
  2051.                 end;
  2052.                 bMore := FALSE;
  2053.             end
  2054.             else begin
  2055.                 oBuffer.Remove(Count);
  2056.                 if Count < Len then begin
  2057.                     { Could not write as much as we wanted. Stop sending }
  2058. {$IFDEF VER80}
  2059.                     { A bug in some Trumpet Winsock implementation break the  }
  2060.                     { background sending. Jan Tomasek <xtomasej@feld.cvut.cz> }
  2061.                     if not TrumpetCompability then begin
  2062.                         bWrite := FALSE;
  2063.                         bMore  := FALSE;
  2064.                     end;
  2065. {$ELSE}
  2066.                     bWrite := FALSE;
  2067.                     bMore  := FALSE;
  2068. {$ENDIF}
  2069.                 end;
  2070.             end;
  2071.         end;
  2072.     end;
  2073. end;
  2074. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  2075. procedure TCustomWSocket.PutStringInSendBuffer(Str : String);
  2076. begin
  2077.     PutDataInSendBuffer(@Str[1], Length(Str));
  2078. end;
  2079. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  2080. procedure TCustomWSocket.PutDataInSendBuffer(Data : Pointer; Len : Integer);
  2081. var
  2082.     oBuffer  : TBuffer;
  2083.     cWritten : Integer;
  2084.     bMore    : Boolean;
  2085. begin
  2086.     if Len <= 0 then
  2087.         exit;
  2088.     if FBufList.Count = 0 then begin
  2089.         oBuffer := TBuffer.Create(FBufSize);
  2090.         FBufList.Add(oBuffer);
  2091.     end
  2092.     else
  2093.         oBuffer := FBufList.Last;
  2094.     bMore := TRUE;
  2095.     while bMore do begin
  2096.         cWritten := oBuffer.Write(Data, Len);
  2097.         if cWritten >= Len then
  2098.             bMore := FALSE
  2099.         else begin
  2100.             Len  := Len - cWritten;
  2101.             Data := PChar(Data) + cWritten;
  2102.             if Len < 0 then
  2103.                 bMore := FALSE
  2104.             else begin
  2105.                 oBuffer := TBuffer.Create(FBufSize);
  2106.                 FBufList.Add(oBuffer);
  2107.             end;
  2108.         end;
  2109.     end;
  2110. end;
  2111. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  2112. { Return -1 if error, else return number of byte written                    }
  2113. function TCustomWSocket.Send(Data : Pointer; Len : Integer) : integer;
  2114. begin
  2115.     if FState <> wsConnected then begin
  2116.         WSocket_WSASetLastError(WSAENOTCONN);
  2117.         SocketError('Send');
  2118.         Result := -1;
  2119.         Exit;
  2120.     end;
  2121.     bAllSent := FALSE;
  2122.     if Len <= 0 then
  2123.         Result := 0
  2124.     else begin
  2125.         Result   := Len;
  2126.         PutDataInSendBuffer(Data, Len);
  2127.     end;
  2128.     if bAllSent then
  2129.         Exit;
  2130.     TryToSend;
  2131.     if bAllSent then begin
  2132.         { We post a message to fire the FD_WRITE message wich in turn will }
  2133.         { fire the OnDataSent event. We cannot fire the event ourself      }
  2134.         { because the event handler will eventually call send again.       }
  2135.         { Sending the message prevent recursive call and stack overflow.   }
  2136.         { The PostMessage function posts (places) a message in a window's  }
  2137.         { message queue and then returns without waiting for the           }
  2138.         { corresponding window to process the message. The message will be }
  2139.         { seen and routed by Delphi a litle later, when we will be out of  }
  2140.         { the send function.                                               }
  2141.         PostMessage(Handle,
  2142.                     WM_ASYNCSELECT,
  2143.                     FHSocket,
  2144.                     MakeLong(FD_WRITE, 0));
  2145.     end;
  2146. end;
  2147. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  2148. { Return -1 if error, else return number of byte written                    }
  2149. function TCustomWSocket.SendStr(Str : String) : integer;
  2150. begin
  2151.    Result := Send(@Str[1], Length(Str));
  2152. end;
  2153. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  2154. procedure TCustomWSocket.SendText(Str : String);
  2155. begin
  2156.     SendStr(Str);
  2157. end;
  2158. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  2159. procedure TCustomWSocket.ASyncReceive(Error : Word);
  2160. var
  2161.     bMore  : Boolean;
  2162.     lCount : LongInt;
  2163.     TrashCan : array [0..1023] of char;
  2164. begin
  2165.     bMore := TRUE;
  2166.     while bMore do begin
  2167.         FLastError := 0;
  2168.         try
  2169.            if not TriggerDataAvailable(Error) then begin
  2170.                { Nothing wants to receive, we will receive and throw away  23/07/98 }
  2171.                if DoRecv(TrashCan, SizeOf(TrashCan), 0) = SOCKET_ERROR then begin
  2172.                    FLastError := WSocket_WSAGetLastError;
  2173.                    if FLastError = WSAEWOULDBLOCK then begin
  2174.                        FLastError := 0;
  2175.                        break;
  2176.                    end;
  2177.                end;
  2178.            end;
  2179.            if FLastError <> 0 then
  2180.                bMore := FALSE
  2181.            {* Check if we have something new arrived, if yes, process it *}
  2182.            else if WSocket_ioctlsocket(FHSocket, FIONREAD,
  2183.                                        lCount) = SOCKET_ERROR then begin
  2184.                FLastError := WSocket_WSAGetLastError;
  2185.                bMore      := FALSE;
  2186.            end
  2187.            else if lCount = 0 then
  2188.                bMore := FALSE;
  2189.         except