PageRenderTime 94ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 2ms

/trunk/Common/Overbyte ICS 7/OverbyteIcsWSocket.pas

http://castlesand.googlecode.com/
Pascal | 13101 lines | 8520 code | 1213 blank | 3368 comment | 953 complexity | 18a1064fb08682cabeaaa7b92ee1e260 MD5 | raw file
Possible License(s): MIT, LGPL-2.0, LGPL-3.0
  1. {*_* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2. Author: François PIETTE
  3. Description: TWSocket class encapsulate the Windows Socket paradigm
  4. Creation: April 1996
  5. Version: 7.47
  6. EMail: francois.piette@overbyte.be http://www.overbyte.be
  7. Support: Use the mailing list twsocket@elists.org
  8. Follow "support" link at http://www.overbyte.be for subscription.
  9. Legal issues: Copyright (C) 1996-2010 by François PIETTE
  10. Rue de Grady 24, 4053 Embourg, Belgium. Fax: +32-4-365.74.56
  11. <francois.piette@overbyte.be>
  12. SSL implementation includes code written by Arno Garrels,
  13. Berlin, Germany, contact: <arno.garrels@gmx.de>
  14. This software is provided 'as-is', without any express or
  15. implied warranty. In no event will the author be held liable
  16. for any damages arising from the use of this software.
  17. Permission is granted to anyone to use this software for any
  18. purpose, including commercial applications, and to alter it
  19. and redistribute it freely, subject to the following
  20. restrictions:
  21. 1. The origin of this software must not be misrepresented,
  22. you must not claim that you wrote the original software.
  23. If you use this software in a product, an acknowledgment
  24. in the product documentation would be appreciated but is
  25. not required.
  26. 2. Altered source versions must be plainly marked as such, and
  27. must not be misrepresented as being the original software.
  28. 3. This notice may not be removed or altered from any source
  29. distribution.
  30. 4. You must register this software by sending a picture postcard
  31. to the author. Use a nice stamp and mention your name, street
  32. address, EMail address and any comment you like to say.
  33. History:
  34. If not otherwise noted, changes are by Francois Piette
  35. Jul 18, 1996 Move all low level socket to winsock to be Delphi 2.x compatible
  36. Sep 18, 1996 Use structured exception for handling errors
  37. Sep 19, 1996 Check csDestroying before invoking event handler
  38. Nov 04, 1996 Better error handling
  39. Jan 31, 1997 Changed property assignation for Addr, Port and Proto
  40. Added notification handler
  41. Feb 14, 1997 Corrected bug in property assignation for Addr, Port and Proto
  42. Mar 26, 1997 Make UDP protocol work correctly
  43. Enable UDP broadcasting by using addr 255.255.255.255
  44. Apr 1, 1997 Added class function when independent of any open socket
  45. Moved InitData as global
  46. Added ReceivedFrom function
  47. Added ResolveHost function
  48. Jul 22, 1997 Adapted to Delphi 3 which has a modified winsock.accept
  49. Aug 13, 1997 'sin' member made public
  50. Aug 24, 1997 Create the only help
  51. Makes writing HSocket the same as calling Dup.
  52. Sep 5, 1997 Version 2.01, added WinsockInfo function
  53. Sep 21, 1997 Version 2.02, make it really thread safe
  54. created global WSocketVersion
  55. Sep 25, 1997 Version 2.04, port to C++Builder
  56. Sep 27, 1997 Version 2.05. All class methods converted to global
  57. procedure or function because C++Builder do not like
  58. class method very much.
  59. Old class method New global function
  60. ---------------- -------------------
  61. WinsockInfo WinsockInfo
  62. SocketErrorDesc WSocketErrorDesc
  63. GetHostByAddr WSocketGetHostByAddr
  64. GetHostByName WSocketGetHostByName
  65. ResolveHost WSocketResolveHost
  66. HostName LocalHostName
  67. Oct 02, 1997 V2.06 Added a check in destructor to avoid calling WSACleanup at
  68. design time which crashes the excellent Eagle Software CDK.
  69. Oct 16, 1997 V2.07 Added PortNum property with numeric value for Port.
  70. Added RcvdCount property to return the number of
  71. characters received in the buffer but not read yet. Do not
  72. confuse with ReadCount which returns the number of chars
  73. already received.
  74. Added a check for FWait assignation in front of ReadLine
  75. Prefixed each TSocketState value by 'ws' to avoid name conflict.
  76. Moved FHSocket member to private section because the property
  77. HSocket does the right job.
  78. Added a check for state closed when changing Port, Proto and Addr.
  79. Oct 22, 1997 V2.08 Added Flush method (asked by john@nexnix.co.uk) and
  80. FlushTimeout property (default to 60 seconds).
  81. Oct 22, 1997 V2.09 Added SendFlags property to enable sending in or out of
  82. band data (normal or urgent, see RFC-1122)
  83. Oct 28, 1997 V2.10 Added an OnLineTooLong event and code to handle the case
  84. where ReadLine has been called and the buffer overflowed (line
  85. long)
  86. Oct 29, 1997 V2.11 Added DnsLookup functionnality (DnsLookup method, DnsResult
  87. property and DnsLookupDone event).
  88. Calling the connect method with a hostname work well except that
  89. it could block for a long period (ie: 2 minutes) if DNS do not
  90. respond. Calling the connect method with a numeric IP address will
  91. never block. So you can call DnsLookup to start hostname
  92. resolution in the background, after some time you evenutually
  93. receive the OnDnsLookupDone event. The copy the DnsResult property
  94. to the Addr property and call connect.
  95. Oct 30, 1997 V2.12 added a check in DnsLookup to handel numeric IP which do
  96. not require any lookup. The numeric IP is treated immediately
  97. and immediately trigger the DnsLookupDone event.
  98. I modified the code to be compatible with Delphi 1.
  99. Oct 31, 1997 V2.13 added CancelDnsLookup procedure.
  100. Nov 09, 1997 V2.14 add LocalIPList function to get the list of local IP
  101. addresses (you have two IP addresses when connected to a LAN
  102. and an ISP).
  103. Nov 11, 1997 V2.15 Made TCustomWSocket with virtual functions. This will
  104. allow to easily descend a new component from TCustomWSocket.
  105. Make ReadLine stop when the connection is broken.
  106. Nov 12, 1997 V2.16 Corrected bug (Justin Yunke <yunke@productivity.org>)
  107. in LocalIPList: phe should be checked for nil.
  108. Nov 18, 1997 Added ReceiveStr function (Suggested by FLDKNHA@danisco.com)
  109. Nov 30, 1997 V2.18 Added a call to OnDnsLookupDone when canceling.
  110. Dec 04, 1997 V2.19 Added LocalPort property and SessionConnected event
  111. for UDP socket.
  112. V2.20 Modified MessageLoop and ProcessMessages to process not
  113. only the socket messages, but all messages (necessary if the
  114. thread has several TWSocket for example).
  115. Dec 09, 1997 V2.21 Corrected a minor bug in ReceiveStr. Detected by
  116. david@e.co.za (David Butler).
  117. Dec 10, 1997 V2.22 Corrected a minor bug in Send which now correctly
  118. returns the number of bytes sent. Detected by
  119. james.huggins@blockbuster.com
  120. Dec 16, 1997 V2.23 Corrected a bug which prevented the receiving of datagram
  121. from a UDP socket.
  122. Thank to Mark Melvin (melvin@misrg.ml.org) for pointing it.
  123. Dec 20, 1997 V2.24 Added the PeekData function as suggested by Matt Rose
  124. mcrose@avproinc.com
  125. Dec 26, 1997 V2.25 Added the Text property as suggested by Daniel P. Stasinski
  126. <dse@pacific.net>. Made GetXPort work even when listening as
  127. suggested by is81024@cis.nctu.edu.tw.
  128. Jan 10, 1998 V2.26 Check for null hostname in DNSLookup
  129. Added DnsResultList with all IP addresses returned form DNS
  130. Jan 13, 1998 V2.27 a Added MultiThreaaded property to tell the component that
  131. it is working in a thread and should take care of it (call
  132. internal ProcessMessages in place of Application.ProcessMessages,
  133. and do not use the WaitCtrl object).
  134. Jan 15, 1998 V2.28 WMAsyncSelect revisited to work properly with NT winsock 2.
  135. Feb 10, 1998 V2.29 Added an OnError event. If not assigned, then the component
  136. raise an exception when the error occurs.
  137. Feb 14, 1998 V2.30 Published Text property
  138. Feb 16, 1998 V2.31 Added virtual methods to trigger events
  139. Renamed all event handler variable to begin with FOn
  140. Feb 26, 1998 V2.32 Added procedure PutDataInSendBuffer and PutStringInSendBuffer
  141. Using PutDataInSendBuffer you can place data in the send buffer
  142. without actualy trying to send it. This allows to place several
  143. (probably small) data chunk before the component attempt to send
  144. it. This prevent small packet to be sent. You can call
  145. Send(nil, 0) to force the component to begin to send data.
  146. If the buffer was not empty, PutDataInSendBuffer will just queue
  147. data to the buffer. This data will be sent in sequence.
  148. Mar 02, 1998 V2.33 Changed the error check with WSAstartup as pointed out by
  149. Donald Strenczewilk (dstrenz@servtech.com)
  150. Mar 06, 1998 V2.34 Added a runtime property to change the buffer size.
  151. Mar 27, 1998 V2.35 Adapted for C++Builder 3
  152. Apr 08, 1998 V2.36 Made SetDefaultValue virtual
  153. Apr 13, 1998 V2.37 Reset FDnsLookupHandle to 0 after a failed call to
  154. WSACancelAsyncRequest
  155. Apr 22, 1998 V2.38 Published AllSent property to let outside know if our
  156. buffer has some data unsent.
  157. Apr 28, 1998 V2.39 Added LingerOnOff and LingerTimeout. Default values are
  158. wsLingerOn and timeout = 0 to behave by default as before.
  159. This value is setup just before Connect. Call SetLingerOption to
  160. set the linger option on the fly (the connection must be
  161. established to set the option). See winsock.closesocket on line
  162. help (winsock.hlp or win32.hlp) for a dsicussion of this option
  163. usage.
  164. May 06, 1998 V2.40 Added a workaround for Trumpet winsock inet_addr bug.
  165. Thanks to Andrej Cuckov <andrej@cuckov.com> for his code.
  166. May 18, 1998 V2.41 Jan Tomasek <xtomasej@feld.cvut.cz> found that Trumpet
  167. Winsock (Win 3.11) has some bugs and suggested a workaround in
  168. TryToSend procedure. This workaround makes TWSocket blocking in
  169. some cases. A new property enables the workaround. See code.
  170. Jun 01, 1998 V2.42 In finalization section, check for not assigned IPList.
  171. Jun 15, 1998 V2.43 Added code to finalization section to unload winsock if
  172. still loaded at that point (this happend if no socket where
  173. created but WinsockInfo called). Suggested by Daniel Fazekas
  174. <fdsoft@dns.gyor-ph.hu>
  175. Jun 27, 1998 V2.44 Added checks for valid arguments in SetPort, SetProto
  176. and SetAddr. Deferred address resolution until Connect or Listen.
  177. Jul 08, 1998 V2.45 Adadpted for Delphi 4
  178. Jul 20, 1998 V2.46 Added SetWindowLong(FWindowHandle, 0, 0) in the destructor
  179. and a check for TWSocket class in XSocketWindowProc.
  180. Added virtual method RealSend.
  181. Jul 23, 1998 V2.47 Added a TriggerSessionClosed from TryToSend in case of
  182. send error. This was called before, but with a nul error argument.
  183. Now it correctly gives the error number.
  184. Added a trashcan to receive data if no OnDataAvailable event
  185. handler is installed. Just receive the data and throw it away.
  186. Added reverse dns lookup asynchronous code (IP -> HostName).
  187. Thanks to Daniel Fazekas <fdsoft@dns.gyor-ph.hu> for his code.
  188. Jul 30, 1998 V2.48 Changed local variable "error" by FLastError in SocketError
  189. to make it available from the OnError handler. Thanks to
  190. dana@medical-info.com for finding this bug.
  191. In Abort procedure, deleted all buffered data because it was send
  192. the next time the socket is opened !
  193. Added CancelDnsLookup in Abort procedure.
  194. Aug 28, 1998 V2.49 Made InternalClose and ReceiveStr virtual
  195. Sep 01, 1998 V2.50 Ignore CancelDnsLookup exception during destroy
  196. Sep 29, 1998 V2.51 In InternalClose, protect AssignDefaultValue with
  197. try/except because SessionClosed event handler may have destroyed
  198. the component.
  199. Oct 11, 1998 V2.52 Changed Shutdown(2) to Shutdown(1) in Internal Close to
  200. prevent data lost on send. You may have to call Shutdown(2) in
  201. your own code before calling Close to have the same behaviour as
  202. before.
  203. Changed argument type for ASyncReceive and passed 0 from FD_CLOSE
  204. message handler.
  205. Oct 28, 1998 V2.53 Made WSocketLoadWinsock and WSocketUnloadWinsock public.
  206. Nov 11, 1998 V2.54 Added OnDisplay event for debugging purpose
  207. Nov 16, 1998 V2.55 Ignore WSANOTINITIALIZED error calling CloseSocket. This
  208. occurs when using TWSocket from a DLL and the finalization
  209. section is called before destroying TWSocket components (this is
  210. a program logic error).
  211. Made some properties and methods protected instead of private.
  212. Made some methods virtual.
  213. Added an Error argument to InternalClose.
  214. Added DoRecv virtual function.
  215. Added WSocketResolvePort
  216. Added WSocketResolveProto
  217. Deferred port and protocol resolution until really needed
  218. Transformed Listen to procedure (in case of failure Listen
  219. always calls SocketError which triggers an exception or the
  220. OnError event).
  221. Nov 22, 1998 V3.00 Skipped from V2.55 to V3.00. Socks support is major update!
  222. Added SOCKS5 (RFC-1928) support for TCP connection and
  223. simple usercode passwword authentication.
  224. Consider the socks code as beta !
  225. New properties: SocksServer, SocksPort, SocksUsercode,
  226. SocksPassword, FSocksAuthentication. New events: OnSocksError,
  227. OnSocksConnected, OnSocksAuthState.
  228. I used WinGate 2.1d to test my code. Unfortunately WinGate do
  229. not correctly handle user authentication, so the code here is
  230. just untested...
  231. Dec 05, 1998 V3.10 Removed ReadLine feature using TWait component.
  232. Added new TCustomLineWSocket and TCustomSyncWSocket.
  233. Those modifications implies that the ReadLine functionnality is
  234. slightly changed. Notably, the end of line marker is now
  235. configurable and remains in the received line unless a timeout
  236. occurs or the buffer is too small.
  237. Dec 10, 1998 V3.11 Added missing code to resolve port in the Listen method.
  238. Dec 12, 1998 V3.12 Added write method for LocalPort property. Thanks to
  239. Jan Tomasek <xtomasej@feld.cvut.cz> for his code.
  240. Added background exception handling.
  241. Fixed a bug in TCustomLineWSocket.TriggerDataAvailable which was
  242. not calling the inherited function when it actually should.
  243. Added a check on multithreaded in WaitForClose to call the
  244. correct ProcessMessages procedure.
  245. Added SOCKS4 support (only tcp connect is supported).
  246. Dec 28, 1998 V3.13 Changed WSocketResolveHost to check for invalid numeric
  247. IP addresses whitout trying to use them as hostnames.
  248. Dec 30, 1998 V3.14 Changed SetPort to SetRemotePort to solve the SetPort
  249. syndrome with BCB. Also chnaged GetPort to be consistant.
  250. Jan 12, 1999 V3.15 Introduced DoRecvFrom virtual function. This correct a bug
  251. introduced in V3.14 related to UDP and RecvFrom.
  252. Jan 23, 1999 V3.16 Changed FRcvdFlag computation in DoRecv and DoRecvFrom
  253. because it caused problems with HTTP component and large blocks.
  254. Removed modification by Jan Tomasek in TriggerDataAvailable
  255. Jan 30, 1999 V3.17 Added WSocketResolveIp function.
  256. Checked for tcp protocol before setting linger off in abort.
  257. Moved a lot of variables from private to protected sections.
  258. Removed check for Assigned(FOnDataSent) in WMASyncSelect.
  259. Feb 03, 1999 V3.18 Removed useless units in the uses clause.
  260. Feb 14, 1999 V4.00 Jump to next major version number because lots of
  261. fundamental changes have been done. See below.
  262. Use runtime dynamic link with winsock. All winsock functions
  263. used by TWSocket are linked at runtime instead of loadtime. This
  264. allows programs to run without winsock installed, provided program
  265. doesn't try to use TWSocket or winsock function without first
  266. checking for winsock installation.
  267. Removed WSocketLoadWinsock and all use to DllStarted because it
  268. is no longer necessary because winsock is automatically loaded
  269. and initialized with the first call to a winsock function.
  270. Added MessagePump to centralize call to the message pump.
  271. It is a virtual procedure so that you can override it to
  272. cutomize your message pump. Also changed slightly ProcessMessages
  273. to closely match what is done in the forms unit.
  274. Removed old stuff related to WaitCtrl (was already excluded from
  275. compilation using a conditional directive).
  276. Added NOFORMS conditional compilation to exclude the Forms unit
  277. from wsocket. This will reduce exe or dll size by 100 to 150KB.
  278. To use this feature, you have to add NOFORMS in your project
  279. options in the "defines" edit box in the "directory/conditional"
  280. tab. Then you must add a message pump to your application and
  281. call it from TWSocket.OnMessagePump event handler. TWSocket really
  282. need a message pump in order to receive messages from winsock.
  283. Depending on how your application is built, you can use either
  284. TWSocket.MessageLoop or TWSocket.ProcessMessages to quickly build
  285. a working message pump. Or you may build your own custom message
  286. pump taylored to your needs. Your message pump must set
  287. TWSocket.Terminated property to TRUE when your application
  288. terminates or you may experience long delays when closing your
  289. application.
  290. You may use NOFORMS setting even if you use the forms unit (GUI
  291. application). Simply call Application.ProcessMessages in the
  292. OnMessagePump event handler.
  293. OnMessagePump event is not visible in the object inspector. You
  294. must assign it at run-time before using the component and after
  295. having created it (in a GUI application you can do that in the
  296. FormCreate event, in a console application, you can do it right
  297. after TWSocket.Create call).
  298. Feb 17, 1999 V4.01 Added LineEcho and LineEdit features.
  299. Feb 27, 1999 V4.02 Added TCustomLineWSocket.GetRcvdCount to make RcvdCount
  300. property and ReceiveStr work in line mode.
  301. Mar 01, 1999 V4.03 Added conditional compile for BCB4. Thanks to James
  302. Legg <jlegg@iname.com>.
  303. Mar 14, 1999 V4.04 Corrected a bug: wsocket hangup when there was no
  304. OnDataAvailable handler and line mode was on.
  305. Apr 21, 1999 V4.05 Added H+ (long strings) and X+ (extended syntax)
  306. compilation options
  307. May 07, 1999 V4.06 Added WSAECONNABORTED to valid error codes in TryToSend.
  308. Jul 21, 1999 V4.07 Added GetPeerPort method, PeerPort and PeerAddr propertied
  309. as suggested by J. Punter <JPunter@login-bv.com>.
  310. Aug 20, 1999 V4.05 Changed conditional compilation so that default is same
  311. as latest compiler (currently Delphi 4, Bcb 4). Should be ok for
  312. Delphi 5.
  313. Added LocalAddr property as suggested by Rod Pickering
  314. <fuzzylogic123@yahoo.com>. LocalAddr default to '0.0.0.0' and is
  315. intended to be used by a client when connecting to a server, to
  316. select a local interface for multihomed computer. Note that to
  317. select an interface for a server, use Addr property before
  318. listening.
  319. LocalAddr has to be an IP address in dotted form. Valid values are
  320. '0.0.0.0' for any interface, '127.0.0.1' for localhost or any
  321. value returned by LocalIPList.
  322. Replaced loadtime import for ntohs and getpeername by runtime
  323. load.
  324. Revised check for dotted numeric IP address in WSocketResolveHost
  325. to allow correct handling of hostnames beginning by a digit.
  326. Added OnSendData event. Triggered each time data has been sent
  327. to winsock. Do not confuse with OnDataSent which is triggered
  328. when TWSocket internal buffer is emptyed. This event has been
  329. suggested by Paul Gertzen" <pgertzen@livetechnology.com> to
  330. easyly implement progress bar.
  331. Corrected WSocketGetHostByAddr to make it dynamically link to
  332. winsock.
  333. Sep 5, 1999 V4.09 Added CloseDelayed method.
  334. Make sure that TriggerSessionClosed is called from WMASyncSelect
  335. and InternalClose, even if there is no OnSessionClosed event
  336. handler assigned. This is required to make derived components
  337. work correctly.
  338. Created message WM_TRIGGER_EXCEPTION to help checking background
  339. exception handling (OnBgException event).
  340. Corrected bug for Delphi 1 and ReallocMem.
  341. Oct 02, 1999 V4.10 Added Release method.
  342. Oct 16, 1999 V4.11 Corrected a bug in TCustomLineWSocket.DoRecv: need to move
  343. data in front of buffer instead of changing buffer pointer which
  344. will crash the whole thing at free time.
  345. Oct 23, 1999 V4.12 Made WSocketIsDottedIP a public function
  346. Nov 12, 1999 V4.13 removed 3 calls to TriggerSocksAuthState because it was
  347. called twice. By A. Burlakov <alex@helexis.com>.
  348. Jan 24, 1999 V4.14 Call Receive instead of DoRecv from ReceiveStr to be sure
  349. to set LastError correctly. Thanks to Farkas Balazs
  350. <megasys@www.iridium.hu>
  351. Suppressed FDllName and used winsocket constant directly. I had
  352. troubles with some DLL code and string handling at program
  353. termination.
  354. Apr 09, 2000 V4.15 Added error number when resolving proto and port
  355. Apr 29, 2000 V4.16 Added WSocketForceLoadWinsock and
  356. WSocketCancelForceLoadWinsock. Thanks to Steve Williams.
  357. Created variable FSelectEvent to store current async event mask.
  358. Added ComponentOptions property with currently only one options
  359. wsoNoReceiveLoop which disable a receive loop in AsyncReceive.
  360. This loop breaking was suggested by Davie <smatters@smatters.com>
  361. to lower resource usage with really fast LAN and large transfers.
  362. By default, this option is disabled so there is no change needed
  363. in current code.
  364. May 20, 2000 V4.17 Made TSocket = u_int (same def as in winsock.pas)
  365. Moved bind after setting options.
  366. Thanks to Primoz Gabrijelcic <fab@siol.net>
  367. Jul 15, 2000 V4.18 Alon Gingold <gingold@hiker.org.il> changed
  368. TCustomSocksWSocket calls to inherited triggers of
  369. TriggerSessionConnected and TriggerDataAvailable.
  370. Now, it calls the trigger directly. This solves the problem
  371. of descendent classes with overridden triggers, not being
  372. called when a REAL connection was established, and when real
  373. data starts coming in. Special care MUST be taken in such
  374. overridden triggers to ONLY call the inherited trigger AND
  375. IMMEDIATELY EXIT when FSocksState <> socksData to avoid loopback
  376. Jul 22, 2000 V4.19 John Goodwin <john@jjgoodwin.com> found a failure in the
  377. logic for DnsLookup. He also implemented a workaround.
  378. See DnsLookup comments for explanation.
  379. Aug 09, 2000 V4.20 Alon Gingold <gingold2@mrm-multicat.com> found a bug in
  380. SOCKS4 implementation where a nul byte was incorrectly added
  381. (it should be added only with SOCKS4A version, not straith
  382. SOCKS4).
  383. Sep 17, 2000 V4.21 Eugene Mayevski <Mayevski@eldos.org> added TWndMethod for
  384. NOFORMS applications in other components.
  385. Oct 15, 2000 V4.22 Added method GetXAddr which returns local IP address to
  386. which a socket has been bound. There was already a GetXPort.
  387. Thanks to Wilfried Mestdagh <wilfried_sonal@compuserve.com>
  388. and Steve Williams <stevewilliams@kromestudios.com>.
  389. Nov 08, 2000 V4.23 Moved FSelectEvent from private to protected section.
  390. Nov 11, 2000 V4.24 Added LineLimit property and OnLineLimitExceeded event.
  391. When using line mode, line length is checked as each data block is
  392. comming. If the length is greater than the limit, then the event
  393. is triggered. You have the opportunity to close the socket or
  394. change the limit to a higher value. Thus you can prevent a hacker
  395. from locking your system by sending unlimited line which otherwise
  396. would eat up all system resources.
  397. Changed line handling variables to LongInt
  398. Checked all length involved in StrPCopy calls.
  399. Nov 26, 2000 V4.25 Do not trust GetRcvdCount. Always call Receive to check for
  400. incomming data (sometime NT4 will hang if we don't do that).
  401. Jan 24, 2001 V4.26 Blaine R Southam <bsoutham@iname.com> fixed out of bound
  402. error in TCustomLineWSocket.TriggerDataAvailable
  403. Feb 17, 2001 V4.27 Davie <smatters@smatters.com> fixed a bug causing byte lost
  404. when closing (related to wsoNoReceiveLoop option).
  405. May 04, 2001 V4.28 Fixed W2K bug (winsock message ordering)
  406. Jun 18, 2001 V4.29 Added AllocateHWnd and DeallocateHWnd from Forms unit to
  407. avoid warning from Delphi 6 in all other components.
  408. Jul 08, 2001 V4.30 Fixed small bug related to NOFOMRS and V4.29
  409. Jul 26, 2001 V4.31 Checked csDesigning in GetRcvdCount so that Delphi 6 does'nt
  410. crash when object inspector wants to display RcvdCount value.
  411. Added multicast capability and UDP ReuseAddr. Thanks to Mark
  412. G. Lewis <Lewis@erg.sri.com> for his code.
  413. Added TriggerSessionClosed to SocketError as suggested by Wilfried
  414. Mestdagh <wilfried_sonal@compuserve.com>
  415. Jul 28, 2001 V4.32 New option wsoTcpNoDelay implemented. Code by Arnaldo Braun
  416. <abraun@th.com.br>
  417. Jul 30, 2001 V4.33 Corrected at few glitches with Delphi 1
  418. Sep 08, 2001 V4.34 Added ThreadAttach and related functions
  419. Nov 27, 2001 V4.35 Added type definition for in_addr and Delphi 2 (Yes there are
  420. still some peoples who wants to use it. Don't ask me why !).
  421. Dec 02, 2001 V4.36 david.brock2@btinternet.com found a bug in SOCKS4 where
  422. error check incorrectly checked "FRcvBuf[1] = #$90" instead of
  423. "FRcvBuf[1] <> #90". He also found a bug when receiving domain name
  424. where length of name was incorrectly copyed to the buffer.
  425. Dec 23, 2001 V4.37 Removed bWrite, nMoreCnt, bMoreFlag and nMoreMax which where
  426. not more really used. Thanks to Al Kirk <akirk@pacific.net> for
  427. showing that.
  428. Feb 24, 2002 V4.38 Wilfried Mestdagh <wilfried@mestdagh.biz> added ThreadDetach
  429. and a property editor for LineEnd. XSocketDeallocateHWnd made a
  430. function.
  431. I created a new unit WSocketE.pas to put Wilfried's property
  432. editor so that it works correctly with Delphi 6.
  433. Apr 24, 2002 V4.39 Removed OnLineTooLong event which was not used anywhere.
  434. Use OnLineLimitExceeded event if you used this event.
  435. Thanks to Alex Kook <cookis@mail.ru> for finding this one.
  436. Apr 27, 2002 V4.40 Added procedure WSocketUnregisterClass to be able to
  437. unregister hidden window. This is necessary when TWSocket is
  438. used within a DLL which is unloaded and reloaded by applications,
  439. specially when running with Windows-XP. Thanks to Jean-Michel Aliu
  440. <jmaliu@jmasoftware.com> who provided a test case.
  441. Jun 02, 2002 V4.41 allow SOCK_RAW in Connect method for any protocol which is
  442. not TCP or UDP. Thanks to Holger Lembke <holger@hlembke.de>.
  443. Jun 04, 2002 V4.42 Do not call Listen for SOCK_RAW.
  444. Thanks to Holger Lembke <holger@hlembke.de>.
  445. Jun 08, 2002 V4.43 Add a dummy Register procedure for BCB1.
  446. Thanks to Marc-Alexander Prowe <listen@mohajer.de>.
  447. Jul 07, 2002 V4.44 Added code in Connect method to check if socket still opened
  448. after OnChangeState event. If not, trigger an error WSAINVAL.
  449. Sep 16, 2002 V4.45 Exposed RcvdPtr and RcvdCnt readonly properties.
  450. Sep 17, 2002 V4.46 Used InterlockedIncrement/InterlockedDecrement to Inc/Dec
  451. socket count safely when TWSocket is used within a thread. This
  452. was proposed by Matthew Meadows <matthew.meadows@inquisite.com>
  453. Sep 28, 2002 V4.47 Changed DnsLookup so that a hostname is checked for dotted
  454. IP addresse and resolve it numerically. Thanks to Bogdan Calin
  455. <soul4blade@yahoo.com> who found this bug. Alos loaded the result
  456. list with the address to be consistant with real lookup result.
  457. Nov 17, 2002 V4.48 Roland Klabunde <roland.klabunde@gmx.net> found a bug in
  458. multicast code: listening on a specific interface was ignored.
  459. He fixed Listen and Connect.
  460. Nov 27, 2002 V4.49 Added ListenBacklog property, default to 5.
  461. Dec 17, 2002 V4.50 Moved code to virtual function to permit SSL implementation.
  462. Jan 19, 2003 V5.00 First pre-release for ICS-SSL. New major version number
  463. V5.01 Gabi Slonto <buffne01@gmx.net> found a bug in DnsLookup
  464. when hostname was actulally a dotted IP address.
  465. Mar 18, 2003 V5.02 Fixed WSocketIsDottedIP: reordering of boolean expressions
  466. involaving a string. Thanks to Ian Baker <ibaker@codecutters.org>
  467. Apr 30, 2003 V5.03 Replaced all calls to setsockopt by calls to
  468. WSocket_setsockopt to avoid statically linked winsock DLL.
  469. Thanks to Piotr Dalek <enigmatical@interia.pl>.
  470. Also replaced inet_addr by WSocket_inet_addr.
  471. Aug 27, 2003 V5.04 Marco van de Voort <marcov@stack.nl> added FreePascal (FPC)
  472. conditional compilation. Please contact him for any FPC support
  473. question.
  474. Aug 28, 2003 V5.05 Fixed a multithreading issue related to windows class
  475. registration. Now using a critical section around the code.
  476. Thanks to Bogdan Ureche <bureche@omnivex.com> for his precious help.
  477. Aug 31, 2003 V5.06 Added warning about deprecated procedures Synchronize,
  478. WaitUntilReady and ReadLine. Do not use them in new applications.
  479. Sep 03, 2003 V5.07 Bogdan Ureche <bureche@omnivex.com> added a critical section
  480. to avoid problem when winsock.dll is unloaded by a thread while
  481. another thread is still using some TWSocket.
  482. Sep 15, 2003 V5.08 Fixed finalization section to no free critical section if
  483. a TWSocket is still existing. This happend for example when a
  484. TWSocket is on a form and Halt is called from FormCreate event.
  485. Changed SendStr argument to const.
  486. Nov 09, 2003 V5.09 Added manifest constants for Shutdown
  487. Added TCustomLineWSocket.SendLine method.
  488. Jan 16, 2004 V5.10 Added "const" in front of all method using strings.
  489. Jan 17, 2004 V5.11 Modified TriggerDataAvailable so that when in LineMode, we
  490. check if a line is still in the buffer of already received data.
  491. Also updated WMTriggerDataAvailable to avoid infinite loops.
  492. Introduced FLineFound to flag when a line has been found.
  493. See "OLD_20040117" to find this code.
  494. Jan 21, 2004 V5.12 Checked null string in PutStringInSendBuffer and null
  495. pointer in PutDataInSendBuffer.
  496. Jan 26, 2004 V5.13 Conditional compilation for BCB for constants for Shutdown.
  497. Reordered uses clause for FPC compatibility.
  498. Fixed TCustomLineWSocket.TriggerDataAvailable to deliver data
  499. already received while in line mode but after component user
  500. turned line mode off in the middle of the way. This could occur
  501. for example in a HTTP application where line mode is used to
  502. receive HTTP header line and turned off when last header line is
  503. found. At that point, if posted data (HTTP document) was completely
  504. in the same packet as the last header line, that data was not
  505. delivered until the next packet comes, which could never occur !
  506. Mar 20, 2004 V5.14 Added partial support for RAW socket.
  507. To use RAW sockets, set Proto to 'raw_ip', 'raw_icmp', ...
  508. Set Port to '0' or whatever value is useful for the protocol.
  509. When using IP protocol, you can add option wsoSIO_RCVALL so that
  510. your program receive ALL datagrams when you listen on a given
  511. interface (You can't use 0.0.0.0).
  512. Do not use Connect with RAW socket. Always use Listen and then
  513. use SendTo to send datagrams use the socket.
  514. Added ReqVerHigh and ReqVerLow properties to be able to select
  515. which winsock version you want to load. Default to 1.1 but need
  516. 2.2 for RAW sockets to be used.
  517. Mar 24, 2004 V5.15 Changed WSocket_Synchronized_ResolveProto to hard code
  518. protocol number for tcp, udp and raw.
  519. Apr 17, 2004 V6.00 New major release started. Move all platform and runtime
  520. dependencies to separate units. New base component for handling
  521. component with window handle.
  522. Jun 20, 2004 V 5.16 John Mulvey <john@mulvey.eurobell.co.uk> fixed error message
  523. in GetPeerAddr which incorrectly reported an error about
  524. GetPeerName.
  525. May 23, 2005 V5.17 PutDataInSendBuffer set bAllSent to false.
  526. Jun 03, 2005 V5.18 Added SocketSndBufSize property which gives the size of
  527. winsock internal send buffer. When using TCP, you must make sure
  528. you never use a BufSize equal or greater than this value or
  529. you'll experience bad performances. See description in MSDN
  530. http://support.microsoft.com/default.aspx?scid=kb;en-us;823764
  531. Default value for BufSize is 1460 and SocketSndBufSize is 8192 so
  532. there is no problem when not changing those values.
  533. Jun 18, 2005 V5.19 Made TCustomSocksWSocket.Connect accept 'tcp' as well as '6'
  534. for protocol. By Piotr "Hellrayzer" Dalek.
  535. Renamed event OnDisplay to OnDebugDisplay.
  536. Sept 4, 2005 V5.20 added BufferedByteCount property used to ensure winsock has sent
  537. data, currently used in TFtpCli to check a put has finished correctly
  538. Thanks to Tobias Giesen <tobias@tgtools.de> for the fix
  539. Dec 27, 2005 V6.00a Updated new release with change done in the old release.
  540. Dec 31, 2005 V6.00b added new debug and logging event and log levels, replacing
  541. conditional debug code with optional code to avoid rebuilding apps.
  542. Works in combination with new component TIcsLogger.
  543. This is controlled by the new LogOptions property:
  544. loDestEvent - write to OnIcsLogEvent (called from higher level protocols)
  545. loDestFile - write to file debug_out.myprog.txt
  546. loDestOutDebug - write to OutputDebugString (shown in Debugger Event Log window)
  547. loAddStamp - time stamp each log line (accurate only to about 18ms)
  548. loWsockErr - log wsocket errors
  549. loWsockInfo - log wsocket general information
  550. loWsockDump - log wsocket data (not implemented yet)
  551. loSslErr - log SSL errors
  552. loSslInfo - log SSL general information
  553. loSslDump - log SSL packets and data
  554. loProtSpecErr - log protocol specific error
  555. loProtSpecInfo - log protocol specific general information
  556. loProtSpecDump - log protocol specific data and packets
  557. Jan 22, 2006 V6.00c Added some KeepAlive stuff (seems winsock is bugged and
  558. doesn't care any setting done !).
  559. Jan 28, 2006 V6.00d Gerhard Rattinger fixed SetKeepAliveOption for Delphi 3
  560. Mar 09, 2006 V6.00e Arno made properties to select keepalive parameters.
  561. He also fixed ReverseDnsLookup to return a list of
  562. host names (aliases) instead of just the first entry. Added func.
  563. ReverseDnsLookupSync.
  564. Apr 27, 2006 V6.00f Roger Tinembart <tinembart@brain.ch> added a critical section
  565. around the list of sendbuffers (FBufHandler) to avoid problems when
  566. the data is placed in the sendbuffer (for example with SendStr)
  567. by a different thread than the one that is effectively sending the
  568. data with TryToSend
  569. June 11, 2006 V6.01 Use new TIcsBufferHandler.
  570. Aug 06, 2006 V6.02 Angus added GetWinsockErr to give alpha and numeric winsock
  571. errors and improved many other error messages,
  572. and fixed FReadCount for 64-bit downloads
  573. added some EXTERNALSYM for BCB compatiblity
  574. Aug 18, 2006 V6.03 Fixed a bug in ASyncReceive(). This bug caused data loss.
  575. Oct 28, 2006 V6.04 Added setter for SocketSndBufSize and SocketRcvBufSize
  576. Dec 22, 2006 V6.05 Oliver Grahl fixed SendLine to properly count LineEnd characters.
  577. Jan 18, 2007 V6.06 Fixed constructor and DeleteBufferedData to behave correctly
  578. when an exception occur in AllocateSocketHWnd.
  579. Mar 23, 2007 V6.07 Removed FD_CONNECT from dup().
  580. Apr 04, 2007 V6.08 Arno Garrels updated SetKeepAliveOption
  581. Mar 10, 2008 V6.09 Francois Piette & Arno Garrels made some changes to
  582. prepare code for Unicode
  583. WSocket_gethostname conversion from String to AnsiString
  584. WSocketGetProc and WSocket2GetProc use AnsiString
  585. GetAliasList simplified and use AnsiString
  586. Apr 25, 2008 V6.10 A. Garrels, added some getters/setters to store and use some
  587. string-property-values as AnsiString internally.
  588. This reduced number of string casts with potential data loss to 17.
  589. These ansi-values are used to call winsock API that doesn't provide
  590. W functions. Modified depending code including some type changes
  591. from PChar to PAnsiChar. Made some casts Unicode => Ansi with
  592. potential data loss *explicit* casts (conditionally compiled) some
  593. unicode strings with only 7 bit ASCII characters are casted using
  594. new function UnicodeToAscii() in new unit OverbyteIcsUtils which
  595. should be fast and reliable and doesn't produce compiler warnings.
  596. Added new warning symbols.
  597. Apr 30, 2008 V6.11 A. Garrels - Function names adjusted according to changes in
  598. OverbyteIcsLibrary.pas.
  599. May 11, 2008 V6.12 USchuster removed local atoi implementation (atoi is now in
  600. OverbyteIcsUtils.pas)
  601. May 15, 2008 V6.13 AGarrels type change of some published String properties
  602. to AnsiString, this is an attempt to avoid too many implicit
  603. string casts, only a few higher level components have been adjusted
  604. accordingly so far.
  605. Jun 30, 2008 A.Garrels made some changes to prepare SSL code for Unicode.
  606. Jul 04, 2008 V6.11 Rev.58 SSL - Still lacked a few changes I made last year.
  607. Jul 13, 2008 V6.12 Added SafeWSocketGCount
  608. Aug 03, 2008 V6.16 A. Garrels removed packed from record TExtension.
  609. Jul 07, 2008 V6.17 Still a small fix from December 2007 missing in SSL code.
  610. Aug 11, 2008 V6.18 A. Garrels - Type AnsiString rolled back to String.
  611. Two bugs fixed in SSL code introduced with Unicode change.
  612. Socks was not fully prepared for Unicode.
  613. Sep 19, 2008 V6.19 A. Garrels changed some AnsiString types to RawByteString.
  614. Sep 21, 2008 V6.20 A. Garrels removed BoolToStr(), available since D7
  615. Oct 22, 2008 V7.21 A. Garrels removed the const modifier from parameter Data
  616. in function SendTo to fix a bug in C++ Builder.
  617. Nov 03, 2008 V7.22 Added property Counter, a class reference to TWSocketCounter
  618. which provides some useful automatic counters. By default property
  619. Counter is unassigned and has to be enabled by a call to
  620. CreateCounter.
  621. Apr 24, 2009 V7.23 A. Garrels added *experimental* OpenSSL engine support which
  622. is not compiled in by default. You have to uncomment conditional
  623. define OPENSSL_NO_ENGINE in OverbyteIcsSslDefs.inc and rebuild your
  624. packages to get it included. With engine support included a new
  625. published property AutoEnableBuiltinEngines of TSslContext has to
  626. be set to TRUE in order to enable OpenSSL's built-in hardware
  627. accelerators support, that's all.
  628. ******************************************************************
  629. * Due to the lack of hardware this feature is completely untested*
  630. ******************************************************************
  631. Any feedback and fixes are welcome, please contact the ICS mailing
  632. list. The OpenSSL engine documentation can be found here:
  633. http://openssl.org/docs/crypto/engine.html
  634. Additionally a new component TSslEngine is installed on the palette.
  635. Its purpose is to control (dynamic) engines.
  636. Typically control commands of an OpenSC dynamic pkcs11 engine
  637. (SmartCard) are :
  638. Cmds.Add('SO_PATH=d:\opensc\bin\engine_pkcs11.dll');
  639. Cmds.Add('ID=pkcs11');
  640. Cmds.Add('LIST_ADD=1');
  641. Cmds.Add('LOAD=');
  642. Cmds.Add('MODULE_PATH=d:\opensc\bin\opensc-pkcs11.dll');
  643. Cmds.Add('INIT='); <= Special ICS-control command to initialize the engine
  644. Sample test code (Dod couldn't get it working :(
  645. It assumes that the X509 certificate has been exported from
  646. the SmartCard to PEM file that is available in property
  647. SslCertFile. It's also assumed that SslEngine1 is created
  648. dynamically at run-time in this sample.
  649. We are in new event TSslContext.OnBeforeInit:
  650. if not Assigned(SslEngine1) then
  651. begin
  652. SslEngine1 := TSslEngine.Create(Self);
  653. try
  654. SslEngine1.NameID := 'dynamic';
  655. // The SmartCard holds the private key.
  656. // Next two lines advise SslContext to load the key
  657. // from the engine instead from PEM file.
  658. TSslContext(Sender).CtxEngine := SslEngine1;
  659. SslEngine1.CtxCapabilities := [eccLoadPrivKey];
  660. // The PIN code is expected in property SslPassPhrase
  661. TSslContext(Sender).SslPassPhrase := 'ics';
  662. // Tell the engine which key to use.
  663. SslEngine1.KeyID := KeyIdEdit.Text;
  664. // At first open the engine
  665. if not SslEngine1.Open then
  666. raise Exception.Create(FEngine.LastErrorMsg);
  667. // Now send our vendor specific control commands
  668. for I := 0 to Cmds.Count -1 do
  669. begin
  670. if not SslEngine1.Control(Cmds.Names[I],
  671. Cmds.ValueFromIndex[I]) then
  672. raise Exception.Create(SslEngine1.LastErrorMsg);
  673. end;
  674. Display('Engine set up and loaded successfully');
  675. except
  676. FreeAndNil(SslEngine1);
  677. raise;
  678. end;
  679. end;
  680. Jun 12, 2009 V7.24 Angus added WriteCount property, how many bytes sent since
  681. connection opened
  682. Only reset ReadCount when connection opened, not closed
  683. Jul 16, 2009 V7.25 Arno fixed and changed SetCounterClass()
  684. Jul 19, 2009 V7.26 Arno - SSL code ignored FPaused flag, the change is in
  685. TCustomSslWSocket.TriggerEvent.
  686. Sep 04, 2009 V7.27 Set option TCP_NODELAY in Dup as well as provide a public
  687. method to set this option, similar as suggested by
  688. Samuel Soldat.
  689. Sep 08, 2009 V7.28 Arno - Minor Unicode bugfix in TX509Base.GetExtension().
  690. Sep 09, 2009 V7.29 Arno - Added new public methods TX509Base.WriteToBio() and
  691. TX509Base.ReadFromBio(). Method SafeToPemFile got an arg.
  692. that adds human readable certificate text to the output.
  693. InitializeSsl inlined. Removed a Delphi 1 conditional.
  694. Sep 17, 2009 V7.30 Anton Sviridov optimized setting of SSL options.
  695. Sep 17, 2009 V7.31 Arno fixed a Unicode bug in TX509Base.GetExtension and
  696. a general bug in TX509Base.GetSha1Hash (AnsiString as
  697. digest buffer should really be avoided)
  698. Sep 18, 2009 V7.32 Arno changed visibility of TX509Base.WriteToBio() and
  699. TX509Base.ReadFromBio() to protected.
  700. Nov 01, 2009 V7.33 Arno fixed a memory overwrite bug in
  701. TCustomSocksWSocket.DoRecv().
  702. Nov 07, 2009 V7.34 OpenSSL V0.9.8L disables session renegotiation due to
  703. TLS renegotiation vulnerability.
  704. Dec 20, 2009 V7.35 Arno added support for SSL Server Name Indication (SNI).
  705. SNI has to be turned on in OverbyteIcsSslDefs.inc, see define
  706. "OPENSSL_NO_TLSEXT". Exchanged symbol "NO_ADV_MT" in the
  707. SSL source by "NO_SSL_MT" (This and SNI was sponsored by
  708. Fastream Technologies).
  709. SNI Howto: In SSL server mode assign event OnSslServerName,
  710. it triggers whenever a client sent a server name in the TLS
  711. client helo. From the event handler read public property
  712. SslServerName, lookup and pass a matching, valid and
  713. initialized SslContext instance associated with the server name.
  714. In SSL client mode, if property SslServerName was not empty
  715. this server name is sent to the server in the TLS client helo.
  716. Currently IE 7 and FireFox >= V2 support SNI, note that both
  717. browers don't send both "localhost" and IP addresses as
  718. server names, this is specified in RFC.
  719. Dec 24, 2009 V7.36 SSL SNI - Do not switch context if not initialized.
  720. Dec 26, 2009 V7.37 Arno fixed TCustomSyncWSocket.ReadLine for Unicode. It
  721. now takes an AnsiString buffer. Since this method is highly
  722. deprecated it's also marked as "deprecated". Do not use it
  723. in new applications.
  724. May 08, 2010 V7.38 Arno Garrels added support for OpenSSL 0.9.8n. Read comments
  725. in OverbyteIcsLIBEAY.pas for details.
  726. May 16, 2010 V7.39 Arno Garrels reenabled check for nil in WMAsyncGetHostByName.
  727. Jun 10, 2010 V7.40 Arno Garrels added experimental timeout and throttle feature
  728. to TWSocket. Currently both features have to be enabled
  729. explicitly with conditional defines BUILTIN_TIMEOUT
  730. and/or BUILTIN_THROTTLE (see OverbyteIcsDefs.inc )
  731. Aug 02, 2010 V7.41 Arno removed an option to send plain UTF-16 strings with
  732. SendStr() and SendLine() by passing 1200 (CP_UTF16) in the
  733. codepage parameter. Changed SendLine() to return correct
  734. number of bytes written.
  735. Aug 08, 2010 V7.42 FPiette prevented socket close in TCustomWSocket.Destroy when
  736. socket state is wsInvalidState (this happend when an
  737. exception is raise early in the constructor).
  738. Sep 05, 2010 V7.43 Arno fixed a bug in the experimental throttle and timeout
  739. source which made it impossible to use both features at the
  740. same time. Renamed conditionals EXPERIMENTAL_THROTTLE and
  741. EXPERIMENTAL_TIMEOUT to BUILTIN_THROTTLE and BUILTIN_TIMEOUT.
  742. It's now possible to either enable them in OverbyteIcsDefs.inc
  743. or define them in project options.
  744. Sep 08, 2010 V7.44 Arno reworked the experimental timeout and throttle code.
  745. Method names of TCustomTimeoutWSocket **changed**, they all
  746. got prefix "Timeout". Removed the crappy TCustomTimerWSocket
  747. class, both throttle and timeout use their own TIcsThreadTimer
  748. instance now.
  749. Sep 08, 2010 V7.45 Fixed a typo in experimental throttle code.
  750. Sep 11, 2010 V7.46 Arno added two more SSL debug log entries and a call to
  751. RaiseLastOpenSslError in TCustomSslWSocket.InitSSLConnection.
  752. Added function OpenSslErrMsg.
  753. Sep 23, 2010 V7.47 Arno fixed a bug in the experimental throttle code and made
  754. it more accurate. Thanks to Angus for testing and reporting.
  755. Method Resume with SSL enabled did not always work.
  756. }
  757. {
  758. About multithreading and event-driven:
  759. TWSocket is a pure asynchronous component. It is non-blocking and
  760. event-driven. It means that when you request an operation such as connect,
  761. the component start the operation your requested and give control back
  762. immediately while performing the operation in the background automatically.
  763. When the operation is done, an event is triggered (such as
  764. OnSessionConnected if you called Connect).
  765. This asynchronous non-blocking behaviour is very high performance but a
  766. little bit difficult to start with. For example, you can't call Connect and
  767. immediately call SendStr the line below. If you try, you'll have an
  768. exception triggered saying you are not connected. Calling connect will start
  769. connection process but will return long before connection is established.
  770. Calling SendStr at the next line will not work because the socket is not
  771. connected yet. To make it works the right way, you have to put your SendStr
  772. in the OnSessionConnected event.
  773. The asynchronous operation allows you to do several TCP/IP I/O
  774. simultaneously. Just use as many component as you need. Each one will
  775. operate independently of the other without blocking each other ! So you
  776. basically don't need multi-threading with TWSocket, unless YOUR processing
  777. is lengthy and blocking.
  778. If you have to use multithreading, you have two possibilities:
  779. 1) Create your TWSocket from your thread's Execute method
  780. 2) Attach a TWSocket to a given thread using ThreadAttach.
  781. In both cases, you must set MultiThreaded property to TRUE.
  782. If you don't use one of those methods, you'll end up with a false
  783. multithreaded program: all events will be processed by the main tread !
  784. For both methods to work, you MUST have a message loop withing your thread.
  785. Delphi create a message loop automatically for the main thread (it's in
  786. the Forms unit), but does NOT create one in a thread ! For your convenience,
  787. TWSocket has his own MessageLoop procedure. You can use it from your thread.
  788. Sample program MtSrv uses first method while ThrdSrv uses second method.
  789. Sample program TcpSrv is much the same as ThrdSrv but doesn't use any
  790. thread. You'll see that it is able to server a lot of simultaneous clients
  791. as well and it is much simpler.
  792. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  793. unit OverbyteIcsWSocket;
  794. {$B-} { Enable partial boolean evaluation }
  795. {$T-} { Untyped pointers }
  796. {$X+} { Enable extended syntax }
  797. {$H+} { Use long strings }
  798. {$J+} { Allow typed constant to be modified }
  799. {$ALIGN 8}
  800. {$I OverbyteIcsDefs.inc}
  801. {$IFDEF USE_SSL}
  802. {$I OverbyteIcsSslDefs.inc}
  803. {$ENDIF}
  804. {$IFDEF COMPILER14_UP}
  805. {$IFDEF NO_EXTENDED_RTTI}
  806. {$RTTI EXPLICIT METHODS([]) FIELDS([]) PROPERTIES([])}
  807. {$ENDIF}
  808. {$ENDIF}
  809. {$IFDEF COMPILER12_UP}
  810. { These are usefull for debugging !}
  811. {$WARN IMPLICIT_STRING_CAST ON}
  812. {$WARN IMPLICIT_STRING_CAST_LOSS ON}
  813. {$WARN EXPLICIT_STRING_CAST OFF}
  814. {$WARN EXPLICIT_STRING_CAST_LOSS OFF}
  815. {$ENDIF}
  816. {$IFDEF DELPHI6_UP}
  817. {$WARN SYMBOL_PLATFORM OFF}
  818. {$WARN SYMBOL_LIBRARY OFF}
  819. {$WARN SYMBOL_DEPRECATED OFF}
  820. {$ENDIF}
  821. {$IFDEF BCB3_UP}
  822. {$ObjExportAll On}
  823. {$ENDIF}
  824. {$IFDEF WIN32}
  825. {$DEFINE VCL}
  826. {$ENDIF}
  827. interface
  828. uses
  829. { You must define USE_SSL so that SSL code is included in the component. }
  830. { Either in OverbyteIcsDefs.inc or in the project/package options. }
  831. {$IFDEF USE_SSL}
  832. OverbyteIcsSSLEAY, OverbyteIcsLIBEAY, Contnrs, Masks, { Masks added AG 06/20/07 }
  833. {$ENDIF}
  834. {$IFDEF CLR}
  835. System.ComponentModel,
  836. System.Text,
  837. System.Runtime.InteropServices,
  838. {$IFDEF VCL}
  839. Borland.Vcl.Classes,
  840. {$ENDIF}
  841. {$ENDIF}
  842. {$IFNDEF NO_DEBUG_LOG}
  843. OverbyteIcsLogger,
  844. {$ENDIF}
  845. {$IF DEFINED(BUILTIN_THROTTLE) or DEFINED(BUILTIN_TIMEOUT)}
  846. OverbyteIcsThreadTimer,
  847. {$IFEND}
  848. OverbyteIcsUtils,
  849. OverbyteIcsTypes, OverbyteIcsLibrary,
  850. OverbyteIcsWndControl, OverbyteIcsWSockBuf,
  851. OverbyteIcsWinsock;
  852. const
  853. WSocketVersion = 747;
  854. CopyRight : String = ' TWSocket (c) 1996-2010 Francois Piette V7.47 ';
  855. WSA_WSOCKET_TIMEOUT = 12001;
  856. {$IFNDEF BCB}
  857. { Manifest constants for Shutdown }
  858. SD_RECEIVE = 0;
  859. SD_SEND = 1; { Use this one for graceful close }
  860. SD_BOTH = 2;
  861. {$ENDIF}
  862. {$IFDEF WIN32}
  863. winsocket = 'wsock32.dll'; { 32 bits TCP/IP system DLL }
  864. winsocket2 = 'ws2_32.dll'; { 32 bits TCP/IP system DLL version 2}
  865. {$ELSE}
  866. winsocket = 'winsock.dll'; { 16 bits TCP/IP system DLL }
  867. {$ENDIF}
  868. type
  869. TWndMethod = procedure(var Message: TMessage) of object;
  870. ESocketException = class(Exception);
  871. TBgExceptionEvent = procedure (Sender : TObject;
  872. E : Exception;
  873. var CanClose : Boolean) of object;
  874. TSocketState = (wsInvalidState,
  875. wsOpened, wsBound,
  876. wsConnecting, wsSocksConnected, wsConnected,
  877. wsAccepting, wsListening,
  878. wsClosed);
  879. TSocketSendFlags = (wsSendNormal, wsSendUrgent);
  880. TSocketLingerOnOff = (wsLingerOff, wsLingerOn, wsLingerNoSet);
  881. TSocketKeepAliveOnOff = (wsKeepAliveOff, wsKeepAliveOnCustom,
  882. wsKeepAliveOnSystem);
  883. {$IFDEF CLR}
  884. TSockAddr = OverbyteIcsWinSock.TSockAddr;
  885. {$ENDIF}
  886. {$IFDEF WIN32}
  887. TSockAddr = OverbyteIcsWinsock.TSockAddr;
  888. ip_mreq = record
  889. imr_multiaddr : in_addr;
  890. imr_interface : in_addr;
  891. end;
  892. {$ENDIF}
  893. TDataAvailable = procedure (Sender: TObject; ErrCode: Word) of object;
  894. TDataSent = procedure (Sender: TObject; ErrCode: Word) of object;
  895. TSendData = procedure (Sender: TObject; BytesSent: Integer) of object;
  896. TSessionClosed = procedure (Sender: TObject; ErrCode: Word) of object;
  897. TSessionAvailable = procedure (Sender: TObject; ErrCode: Word) of object;
  898. TSessionConnected = procedure (Sender: TObject; ErrCode: Word) of object;
  899. TDnsLookupDone = procedure (Sender: TObject; ErrCode: Word) of object;
  900. TChangeState = procedure (Sender: TObject;
  901. OldState, NewState : TSocketState) of object;
  902. TDebugDisplay = procedure (Sender: TObject; var Msg : String) of object;
  903. TWSocketSyncNextProc = procedure of object;
  904. {$IFDEF CLR}
  905. [Flags]
  906. TWSocketOptions = (wsoNone = 0,
  907. wsoNoReceiveLoop = 1,
  908. wsoTcpNoDelay = 2,
  909. wsoSIO_RCVALL = 4);
  910. TWSocketOption = TWSocketOptions;
  911. {$ENDIF}
  912. {$IFDEF WIN32}
  913. TWSocketOption = (wsoNoReceiveLoop, wsoTcpNoDelay, wsoSIO_RCVALL);
  914. TWSocketOptions = set of TWSocketOption;
  915. {$ENDIF}
  916. {$IFDEF DELPHI4_UP}
  917. { TSocket type definition has been removed starting from Delphi 4 }
  918. //TSocket = u_int;
  919. {$ENDIF}
  920. TTcpKeepAlive = packed record
  921. OnOff : u_long;
  922. KeepAliveTime : u_long;
  923. KeepAliveInterval : u_long;
  924. end;
  925. type { <== Required to make D7 code explorer happy, AG 05/24/2007 }
  926. TWSocketCounter = class(TObject)
  927. private
  928. FConnectDT : TDateTime;
  929. FConnectTick : Cardinal;
  930. FLastRecvTick : Cardinal;
  931. FLastSendTick : Cardinal;
  932. function GetLastAliveTick : Cardinal;
  933. public
  934. procedure SetConnected; virtual;
  935. property ConnectTick : Cardinal read FConnectTick write FConnectTick;
  936. property ConnectDT : TDateTime read FConnectDT write FConnectDT;
  937. property LastAliveTick : Cardinal read GetLastAliveTick;
  938. property LastRecvTick : Cardinal read FLastRecvTick write FLastRecvTick;
  939. property LastSendTick : Cardinal read FLastSendTick write FLastSendTick;
  940. end;
  941. TWSocketCounterClass = class of TWSocketCounter;
  942. TCustomWSocket = class(TIcsWndControl)
  943. private
  944. FDnsResult : String;
  945. FDnsResultList : TStrings;
  946. FSendFlags : Integer;
  947. FLastError : Integer;
  948. //FWindowHandle : HWND;
  949. {$IFDEF CLR}
  950. FDnsLookupBuffer : TBytes;
  951. FName : String;
  952. {$ENDIF}
  953. {$IFDEF WIN32}
  954. FDnsLookupBuffer : array [0..MAXGETHOSTSTRUCT] of AnsiChar;
  955. {$ENDIF}
  956. FDnsLookupCheckMsg : Boolean;
  957. FDnsLookupTempMsg : TMessage;
  958. // FHandle : HWND;
  959. {$IFDEF CLR}
  960. FDnsLookupGCH : GCHandle;
  961. FDnsLookupIntPtr : IntPtr;
  962. {$ENDIF}
  963. {$IFDEF VER80}
  964. FTrumpetCompability : Boolean;
  965. {$ENDIF}
  966. FCounter : TWSocketCounter;
  967. FCounterClass : TWsocketCounterClass;
  968. protected
  969. FHSocket : TSocket;
  970. FASocket : TSocket; { Accepted socket }
  971. FMsg_WM_ASYNCSELECT : UINT;
  972. FMsg_WM_ASYNCGETHOSTBYNAME : UINT;
  973. FMsg_WM_ASYNCGETHOSTBYADDR : UINT;
  974. FMsg_WM_CLOSE_DELAYED : UINT;
  975. //FMsg_WM_WSOCKET_RELEASE : UINT;
  976. FMsg_WM_TRIGGER_EXCEPTION : UINT;
  977. FMsg_WM_TRIGGER_DATA_AVAILABLE : UINT;
  978. FAddrStr : String;
  979. FAddrResolved : Boolean;
  980. FAddrFormat : Integer;
  981. FAddrAssigned : Boolean;
  982. FProto : Integer;
  983. FProtoAssigned : Boolean;
  984. FProtoResolved : Boolean;
  985. FLocalPortResolved : Boolean;
  986. FProtoStr : String;
  987. FPortStr : String;
  988. FPortAssigned : Boolean;
  989. FPortResolved : Boolean;
  990. FPortNum : Integer;
  991. FLocalPortStr : String;
  992. FLocalPortNum : Integer;
  993. FLocalAddr : String; { IP address for local interface to use }
  994. FType : Integer;
  995. FBufHandler : TIcsBufferHandler;
  996. FLingerOnOff : TSocketLingerOnOff;
  997. FLingerTimeout : Integer; { In seconds, 0 = disabled }
  998. FKeepAliveOnOff : TSocketKeepAliveOnOff;
  999. FKeepAliveTime : Integer; { In milliseconds }
  1000. FKeepAliveInterval : Integer; { In milliseconds }
  1001. FListenBacklog : Integer;
  1002. ReadLineCount : Integer;
  1003. bAllSent : Boolean;
  1004. FReadCount : Int64; { V5.26 }
  1005. FWriteCount : Int64; { V7.24 }
  1006. FPaused : Boolean;
  1007. FCloseInvoked : Boolean;
  1008. FBufferedByteCount : LongInt; { V5.20 how man xmit bytes unsent }
  1009. FFlushTimeout : Integer; { This property is not used anymore }
  1010. FMultiThreaded : Boolean;
  1011. FDnsLookupHandle : THandle;
  1012. { More info about multicast can be found at: }
  1013. { http://ntrg.cs.tcd.ie/undergrad/4ba2/multicast/antony/ }
  1014. { http://www.tldp.org/HOWTO/Multicast-HOWTO-6.html }
  1015. FMultiCast : Boolean;
  1016. { Multicast addresses consists of a range of addresses from 224.0.0.0 to }
  1017. { 239.255.255.255. However, the multicast addresses from 224.0.0.0 to }
  1018. { 224.0.0.255 are reserved for multicast routing information; Application }
  1019. { programs should use multicast addresses outside this range. }
  1020. FMultiCastAddrStr : String;
  1021. FMultiCastIpTTL : Integer;
  1022. FReuseAddr : Boolean;
  1023. FComponentOptions : TWSocketOptions;
  1024. FState : TSocketState;
  1025. FRcvdFlag : Boolean;
  1026. FSelectEvent : LongInt;
  1027. FSelectMessage : WORD;
  1028. {$IFDEF CLR}
  1029. FRecvStrBuf : TBytes;
  1030. {$ENDIF}
  1031. FOnSessionAvailable : TSessionAvailable;
  1032. FOnSessionConnected : TSessionConnected;
  1033. FOnSessionClosed : TSessionClosed;
  1034. FOnChangeState : TChangeState;
  1035. FOnDataAvailable : TDataAvailable;
  1036. FOnDataSent : TDataSent;
  1037. FOnSendData : TSendData;
  1038. { FOnLineTooLong : TNotifyEvent; }
  1039. FOnDnsLookupDone : TDnsLookupDone;
  1040. FOnError : TNotifyEvent;
  1041. FOnBgException : TBgExceptionEvent;
  1042. FOnDebugDisplay : TDebugDisplay; { 18/06/05 }
  1043. FOnMessagePump : TNotifyEvent;
  1044. //FThreadId : THandle;
  1045. FSocketSndBufSize : Integer; { Winsock internal socket send buffer size }
  1046. FSocketRcvBufSize : Integer; { Winsock internal socket Recv buffer size }
  1047. {$IFNDEF NO_DEBUG_LOG}
  1048. FIcsLogger : TIcsLogger; { V5.21 }
  1049. procedure SetIcsLogger(const Value : TIcsLogger); virtual; { V5.21 }
  1050. procedure DebugLog(LogOption : TLogOption; const Msg : String); virtual; { V5.21 }
  1051. function CheckLogOptions(const LogOption: TLogOption): Boolean; virtual; { V5.21 }
  1052. {$ENDIF}
  1053. procedure WndProc(var MsgRec: TMessage); override;
  1054. function MsgHandlersCount: Integer; override;
  1055. procedure AllocateMsgHandlers; override;
  1056. procedure FreeMsgHandlers; override;
  1057. procedure AllocateSocketHWnd; virtual;
  1058. procedure DeallocateSocketHWnd; virtual;
  1059. procedure SocketError(sockfunc: String);
  1060. procedure WMASyncSelect(var msg: TMessage);
  1061. procedure WMAsyncGetHostByName(var msg: TMessage);
  1062. procedure WMAsyncGetHostByAddr(var msg: TMessage);
  1063. procedure WMCloseDelayed(var msg: TMessage);
  1064. //procedure WMRelease(var msg: TMessage);
  1065. procedure ChangeState(NewState : TSocketState);
  1066. procedure TryToSend; virtual;
  1067. procedure ASyncReceive(Error : Word; MySocketOptions : TWSocketOptions);
  1068. procedure AssignDefaultValue; virtual;
  1069. procedure InternalClose(bShut : Boolean; Error : Word); virtual;
  1070. procedure InternalAbort(ErrCode : Word); virtual;
  1071. {$IFDEF WIN32}
  1072. procedure Notification(AComponent: TComponent; operation: TOperation); override;
  1073. {$ENDIF}
  1074. procedure SetSendFlags(newValue : TSocketSendFlags);
  1075. function GetSendFlags : TSocketSendFlags;
  1076. procedure SetAddr(InAddr : String);
  1077. procedure SetCounterClass(const Value: TWSocketCounterClass);
  1078. procedure SetRemotePort(sPort : String); virtual;
  1079. function GetRemotePort : String;
  1080. procedure SetLocalAddr(sLocalAddr : String);
  1081. procedure SetLocalPort(const sLocalPort : String);
  1082. procedure SetProto(sProto : String); virtual;
  1083. function GetRcvdCount : LongInt; virtual;
  1084. procedure SetBufSize(Value : Integer); virtual;
  1085. function GetBufSize: Integer; virtual;
  1086. procedure SetSocketRcvBufSize(BufSize : Integer); virtual;
  1087. procedure SetSocketSndBufSize(BufSize : Integer); virtual;
  1088. procedure BindSocket; virtual;
  1089. procedure SendText(const Str : RawByteString); {$IFDEF COMPILER12_UP} overload;
  1090. procedure SendText(const Str : UnicodeString); overload;
  1091. procedure SendText(const Str : UnicodeString; ACodePage : LongWord); overload;
  1092. {$ENDIF}
  1093. function RealSend(var Data : TWSocketData; Len : Integer) : Integer; virtual;
  1094. // procedure RaiseExceptionFmt(const Fmt : String; args : array of const); virtual;
  1095. procedure RaiseException(const Msg : String); virtual;
  1096. procedure HandleBackGroundException(E: Exception); override;
  1097. function GetReqVerLow: BYTE;
  1098. procedure SetReqVerLow(const Value: BYTE);
  1099. function GetReqVerHigh: BYTE;
  1100. procedure SetReqVerHigh(const Value: BYTE);
  1101. procedure TriggerDebugDisplay(Msg : String); { 18/06/05 }
  1102. procedure TriggerSendData(BytesSent : Integer);
  1103. function TriggerDataAvailable(Error : Word) : Boolean; virtual;
  1104. procedure TriggerSessionAvailable(Error : Word); virtual;
  1105. procedure TriggerSessionConnectedSpecial(Error : Word); virtual;
  1106. procedure TriggerSessionConnected(Error : Word); virtual;
  1107. procedure TriggerSessionClosed(Error : Word); virtual;
  1108. procedure TriggerDataSent(Error : Word); virtual;
  1109. procedure TriggerChangeState(OldState, NewState : TSocketState); virtual;
  1110. procedure TriggerDNSLookupDone(Error : Word); virtual;
  1111. procedure TriggerError; virtual;
  1112. function DoRecv(var Buffer : TWSocketData;
  1113. BufferSize : Integer;
  1114. Flags : Integer) : Integer; virtual;
  1115. function DoRecvFrom(FHSocket : TSocket;
  1116. var Buffer : TWSocketData;
  1117. BufferSize : Integer;
  1118. Flags : Integer;
  1119. var From : TSockAddr;
  1120. var FromLen : Integer) : Integer; virtual;
  1121. procedure Do_FD_CONNECT(var msg: TMessage); virtual;
  1122. procedure Do_FD_READ(var msg: TMessage); virtual;
  1123. procedure Do_FD_WRITE(var msg: TMessage); virtual;
  1124. procedure Do_FD_ACCEPT(var msg: TMessage); virtual;
  1125. procedure Do_FD_CLOSE(var msg: TMessage); virtual;
  1126. procedure DupConnected; virtual;
  1127. public
  1128. sin : TSockAddrIn;
  1129. {$IFDEF CLR}
  1130. constructor Create{$IFDEF VCL}(AOwner : TComponent){$ENDIF}; override;
  1131. {$ENDIF}
  1132. {$IFDEF WIN32}
  1133. constructor Create(AOwner: TComponent); override;
  1134. {$ENDIF}
  1135. destructor Destroy; override;
  1136. procedure Connect; virtual;
  1137. procedure Close; virtual;
  1138. procedure CloseDelayed; virtual;
  1139. //procedure Release; override; { Release is handled in TIcsWndControl }
  1140. procedure Abort; virtual;
  1141. procedure Flush; virtual;
  1142. procedure WaitForClose; virtual;
  1143. procedure Listen; virtual;
  1144. function Accept: TSocket; virtual;
  1145. function Receive(Buffer : TWSocketData; BufferSize: Integer) : Integer; {overload; }virtual;
  1146. //{$IFDEF WIN32}
  1147. // function Receive(Buffer : TBytes; BufferSize: Integer) : Integer; overload; virtual;
  1148. //{$ENDIF}
  1149. function ReceiveStr : String; virtual;
  1150. function ReceiveStrA : AnsiString; virtual;
  1151. {$IFDEF COMPILER12_UP}
  1152. function ReceiveStrW(ACodePage: LongWord) : UnicodeString; overload; virtual;
  1153. function ReceiveStrW : UnicodeString; overload; virtual;
  1154. {$ENDIF}
  1155. function ReceiveFrom(Buffer : TWSocketData;
  1156. BufferSize : Integer;
  1157. var From : TSockAddr;
  1158. var FromLen : Integer) : Integer; virtual;
  1159. function PeekData(Buffer : TWSocketData; BufferSize: Integer) : Integer;
  1160. function Send({$IFDEF CLR} const {$ENDIF} Data : TWSocketData; Len : Integer) : Integer; overload; virtual;
  1161. function Send(DataByte : Byte) : Integer; overload; virtual;
  1162. function SendTo(Dest : TSockAddr;
  1163. DestLen : Integer;
  1164. {$IFDEF CLR} const {$ENDIF} Data : TWSocketData;
  1165. Len : Integer) : Integer; virtual;
  1166. function SendStr(const Str : RawByteString) : Integer; {$IFDEF COMPILER12_UP} overload; {$ENDIF} virtual;
  1167. {$IFDEF COMPILER12_UP}
  1168. function SendStr(const Str : UnicodeString; ACodePage: LongWord) : Integer; overload; virtual;
  1169. function SendStr(const Str : UnicodeString) : Integer; overload; virtual;
  1170. {$ENDIF}
  1171. procedure DnsLookup(const AHostName : String); virtual;
  1172. procedure ReverseDnsLookup(const HostAddr: String); virtual;
  1173. procedure ReverseDnsLookupSync(const HostAddr: String); virtual; {AG 03/03/06}
  1174. procedure CancelDnsLookup; virtual;
  1175. function GetPeerAddr: String; virtual;
  1176. function GetPeerPort: String; virtual;
  1177. function GetPeerName(var Name : TSockAddrIn; NameLen : Integer) : Integer; virtual;
  1178. function GetXPort: String; virtual;
  1179. function GetXAddr: String; virtual;
  1180. function TimerIsSet(var tvp : TTimeVal) : Boolean; virtual;
  1181. procedure TimerClear(var tvp : TTimeVal); virtual;
  1182. function TimerCmp(var tvp : TTimeVal; var uvp : TTimeVal; IsEqual : Boolean) : Boolean; virtual;
  1183. function GetSockName(var saddr : TSockAddrIn; var saddrlen : Integer) : Integer; virtual;
  1184. procedure SetLingerOption;
  1185. procedure SetKeepAliveOption;
  1186. function SetTcpNoDelayOption: Boolean; { V7.27 }
  1187. procedure Dup(NewHSocket : TSocket); virtual;
  1188. procedure Shutdown(How : Integer); virtual;
  1189. procedure Pause; virtual;
  1190. procedure Resume; virtual;
  1191. procedure PutDataInSendBuffer(Data : TWSocketData; Len : Integer); virtual;
  1192. function PutStringInSendBuffer(const Str : RawByteString): Integer; {$IFDEF COMPILER12_UP} overload; {$ENDIF}
  1193. {$IFDEF COMPILER12_UP}
  1194. function PutStringInSendBuffer(const Str : UnicodeString; ACodePage: LongWord): Integer; overload;
  1195. function PutStringInSendBuffer(const Str : UnicodeString): Integer; overload;
  1196. {$ENDIF}
  1197. procedure DeleteBufferedData;
  1198. {$IFDEF COMPILER2_UP}
  1199. procedure ThreadAttach; override;
  1200. procedure ThreadDetach; override;
  1201. {$ENDIF}
  1202. procedure CreateCounter; virtual;
  1203. procedure DestroyCounter;
  1204. {$IFDEF NOFORMS}
  1205. property Terminated : Boolean read FTerminated
  1206. write FTerminated;
  1207. property OnMessagePump : TNotifyEvent read FOnMessagePump
  1208. write FOnMessagePump;
  1209. {$ENDIF}
  1210. property BufferedByteCount : LongInt read FBufferedByteCount; { V5.20 }
  1211. protected
  1212. {$IFDEF CLR}
  1213. property Name : String read FName
  1214. write FName;
  1215. {$ENDIF}
  1216. {$IFNDEF NO_DEBUG_LOG}
  1217. property IcsLogger : TIcsLogger read FIcsLogger { V5.21 }
  1218. write SetIcsLogger; { V5.21 }
  1219. {$ENDIF}
  1220. property PortNum : Integer read FPortNum;
  1221. property FWindowHandle : HWND read FHandle;
  1222. property HSocket : TSocket read FHSocket
  1223. write Dup;
  1224. property Addr : String read FAddrStr
  1225. write SetAddr;
  1226. property Port : String read GetRemotePort
  1227. write SetRemotePort;
  1228. property LocalPort : String read FLocalPortStr
  1229. write SetLocalPort;
  1230. property LocalAddr : String read FLocalAddr
  1231. write SetLocalAddr;
  1232. property Proto : String read FProtoStr
  1233. write SetProto;
  1234. property MultiThreaded : Boolean read FMultiThreaded
  1235. write FMultiThreaded;
  1236. property MultiCast : Boolean read FMultiCast
  1237. write FMultiCast;
  1238. property MultiCastAddrStr: String read FMultiCastAddrStr
  1239. write FMultiCastAddrStr;
  1240. property MultiCastIpTTL : Integer read FMultiCastIpTTL
  1241. write FMultiCastIpTTL;
  1242. property ReuseAddr : Boolean read FReuseAddr
  1243. write FReuseAddr;
  1244. property PeerAddr : String read GetPeerAddr;
  1245. property PeerPort : String read GetPeerPort;
  1246. property DnsResult : String read FDnsResult;
  1247. property DnsResultList : TStrings read FDnsResultList;
  1248. property State : TSocketState read FState;
  1249. property AllSent : Boolean read bAllSent;
  1250. property ReadCount : Int64 read FReadCount; { V5.26 }
  1251. property WriteCount : Int64 read FWriteCount; { V7.24 }
  1252. property RcvdCount : LongInt read GetRcvdCount;
  1253. property LastError : Integer read FLastError
  1254. write FLastError; { V5.20 }
  1255. property ComponentOptions : TWSocketOptions read FComponentOptions
  1256. write FComponentOptions;
  1257. property BufSize : Integer read GetBufSize
  1258. write SetBufSize;
  1259. property SocketRcvBufSize : Integer read FSocketRcvBufSize
  1260. write SetSocketRcvBufSize;
  1261. property SocketSndBufSize : Integer read FSocketSndBufSize
  1262. write SetSocketSndBufSize;
  1263. property ListenBacklog : Integer read FListenBacklog
  1264. write FListenBacklog;
  1265. property ReqVerLow : BYTE read GetReqVerLow
  1266. write SetReqVerLow;
  1267. property ReqVerHigh : BYTE read GetReqVerHigh
  1268. write SetReqVerHigh;
  1269. property OnDataAvailable : TDataAvailable read FOnDataAvailable
  1270. write FOnDataAvailable;
  1271. property OnDataSent : TDataSent read FOnDataSent
  1272. write FOnDataSent;
  1273. property OnSendData : TSendData read FOnSendData
  1274. write FOnSendData;
  1275. property OnSessionClosed : TSessionClosed read FOnSessionClosed
  1276. write FOnSessionClosed;
  1277. property OnSessionAvailable : TSessionAvailable read FOnSessionAvailable
  1278. write FOnSessionAvailable;
  1279. property OnSessionConnected : TSessionConnected read FOnSessionConnected
  1280. write FOnSessionConnected;
  1281. property OnChangeState : TChangeState read FOnChangeState
  1282. write FOnChangeState;
  1283. { property OnLineTooLong : TNotifyEvent read FOnLineTooLong
  1284. write FOnLineTooLong; }
  1285. property OnDnsLookupDone : TDnsLookupDone read FOnDnsLookupDone
  1286. write FOnDnsLookupDone;
  1287. property OnError : TNotifyEvent read FOnError
  1288. write FOnError;
  1289. property OnBgException : TBgExceptionEvent read FOnBgException
  1290. write FOnBgException;
  1291. { FlushTimeout property is not used anymore }
  1292. property FlushTimeout : Integer read FFlushTimeOut
  1293. write FFlushTimeout;
  1294. property SendFlags : TSocketSendFlags read GetSendFlags
  1295. write SetSendFlags;
  1296. property Text: String read ReceiveStr
  1297. write SendText;
  1298. property LingerOnOff : TSocketLingerOnOff read FLingerOnOff
  1299. write FLingerOnOff;
  1300. property LingerTimeout : Integer read FLingerTimeout
  1301. write FLingerTimeout;
  1302. property KeepAliveOnOff: TSocketKeepAliveOnOff read FKeepAliveOnOff
  1303. write FKeepAliveOnOff;
  1304. property KeepAliveTime : Integer read FKeepAliveTime
  1305. write FKeepAliveTime;
  1306. property KeepAliveInterval : Integer read FKeepAliveInterval
  1307. write FKeepAliveInterval;
  1308. {$IFDEF DELPHI1}
  1309. property TrumpetCompability : Boolean read FTrumpetCompability
  1310. write FTrumpetCompability;
  1311. {$ENDIF}
  1312. property OnDebugDisplay : TDebugDisplay read FOnDebugDisplay
  1313. write FOnDebugDisplay;
  1314. property Counter : TWSocketCounter read FCounter;
  1315. property CounterClass : TWsocketCounterClass read FCounterClass
  1316. write SetCounterClass;
  1317. end;
  1318. TSocksState = (socksData, socksNegociateMethods, socksAuthenticate, socksConnect);
  1319. TSocksAuthentication = (socksNoAuthentication, socksAuthenticateUsercode);
  1320. TSocksAuthState = (socksAuthStart, socksAuthSuccess, socksAuthFailure, socksAuthNotRequired);
  1321. TSocksAuthStateEvent = procedure(Sender : TObject; AuthState : TSocksAuthState) of object;
  1322. TSocksErrorEvent = procedure(Sender : TObject; Error : Integer; Msg : String) of Object;
  1323. TCustomSocksWSocket = class(TCustomWSocket)
  1324. protected
  1325. FSocksState : TSocksState;
  1326. FSocksServer : String;
  1327. FSocksLevel : String;
  1328. FSocksPort : String;
  1329. FSocksPortAssigned : Boolean;
  1330. FSocksServerAssigned : Boolean;
  1331. FSocksUsercode : String;
  1332. FSocksPassword : String;
  1333. FSocksAuthentication : TSocksAuthentication;
  1334. FSocksAuthNumber : AnsiChar;
  1335. FBoundAddr : AnsiString;
  1336. FBoundPort : AnsiString;
  1337. {$IFDEF CLR}
  1338. FRcvBuf : TBytes;
  1339. {$ENDIF}
  1340. {$IFDEF WIN32}
  1341. FRcvBuf : array [0..127] of Byte;
  1342. {$ENDIF}
  1343. FRcvCnt : Integer;
  1344. FSocksRcvdCnt : Integer;
  1345. FSocksRcvdPtr : Integer;
  1346. FOnSocksError : TSocksErrorEvent;
  1347. FOnSocksConnected : TSessionConnected;
  1348. FOnSocksAuthState : TSocksAuthStateEvent;
  1349. procedure AssignDefaultValue; override;
  1350. procedure TriggerSessionConnectedSpecial(Error : Word); override;
  1351. procedure TriggerSocksConnected(Error : Word); virtual;
  1352. procedure TriggerSessionClosed(Error : Word); override;
  1353. function TriggerDataAvailable(Error : Word) : Boolean; override;
  1354. function GetSocksPort: String;
  1355. procedure SetSocksPort(sPort : String); virtual;
  1356. function GetSocksServer: String;
  1357. procedure SetSocksServer(sServer : String); virtual;
  1358. procedure TriggerSocksError(Error : Integer; Msg : String); virtual;
  1359. procedure TriggerSocksAuthState(AuthState : TSocksAuthState);
  1360. function GetRcvdCount : LongInt; override;
  1361. procedure SetSocksLevel(newValue : String);
  1362. function DoRecv(var Buffer : TWSocketData;
  1363. BufferSize : Integer;
  1364. Flags : Integer) : Integer; override;
  1365. procedure SocksDoConnect;
  1366. procedure SocksDoAuthenticate;
  1367. procedure DataAvailableError(ErrCode : Integer; Msg : String);
  1368. public
  1369. constructor Create{$IFDEF VCL}(AOwner : TComponent){$ENDIF}; override;
  1370. procedure Connect; override;
  1371. procedure Listen; override;
  1372. protected
  1373. property SocksServer : String read GetSocksServer
  1374. write SetSocksServer;
  1375. property SocksLevel : String read FSocksLevel
  1376. write SetSocksLevel;
  1377. property SocksPort : String read FSocksPort
  1378. write SetSocksPort;
  1379. property SocksUsercode : String read FSocksUsercode
  1380. write FSocksUsercode;
  1381. property SocksPassword : String read FSocksPassword
  1382. write FSocksPassword;
  1383. property SocksAuthentication : TSocksAuthentication
  1384. read FSocksAuthentication
  1385. write FSocksAuthentication;
  1386. property OnSocksError : TSocksErrorEvent read FOnSocksError
  1387. write FOnSocksError;
  1388. property OnSocksConnected : TSessionConnected read FOnSocksConnected
  1389. write FOnSocksConnected;
  1390. property OnSocksAuthState : TSocksAuthStateEvent
  1391. read FOnSocksAuthState
  1392. write FOnSocksAuthState;
  1393. end;
  1394. { You must define USE_SSL so that SSL code is included in the component. }
  1395. { Either in OverbyteIcsDefs.inc or in the project/package options. }
  1396. {$IFDEF USE_SSL}
  1397. {*_* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  1398. Author: François PIETTE
  1399. Description: A component adding SSL support to TWSocket.
  1400. This unit contains the interface for the component.
  1401. It is included in WSocket.pas unit when USE_SSL is defined.
  1402. The implementation part is in WSocketImplSsl.inc.
  1403. Make use of OpenSSL (http://www.openssl.org).
  1404. Make use of freeware TWSocket component from ICS.
  1405. This version has been developped with the excellent collaboration
  1406. and expertize from Arno Garrels <arno.garrels@gmx.de> and
  1407. Benjamin Stadin <stadin@gmx.de>. They worked very hard to make
  1408. this code working.
  1409. Creation: Jan 11, 2003
  1410. Version: 1.00.9
  1411. Reference guide:
  1412. SslCertFile Filename of the certificate sent to the remote site for
  1413. authetification, in PEM format.
  1414. SslPassPhrase Password phrase used to protect SslCertFile.
  1415. SslPrivKeyFile Private key used to encrypt data. Must correspond to the
  1416. public key stored in the certificate identified by
  1417. SslCertFile.
  1418. SslCAFile Filename of CA certificates in PEM format. The file can
  1419. contain several CA certificates identified by
  1420. -----BEGIN CERTIFICATE-----
  1421. ... (CA certificate in base64 encoding) ...
  1422. -----END CERTIFICATE-----
  1423. sequences. Before, between, and after the certificates text
  1424. is allowed which can be used e.g. for descriptions of the
  1425. certificates.
  1426. CAFile can be an empty string if CAPath is used.
  1427. SslCAPath Directory containing CA certificates in PEM format. The
  1428. files each contain one CA certificate. The files are looked
  1429. up by the CA subject name hash value, which must hence be
  1430. available.
  1431. If more than one CA certificate with the same name hash
  1432. value exist, the extension must be different (e.g.
  1433. 9d66eef0.0, 9d66eef0.1 etc). The search is performed in
  1434. the ordering of the extension number, regardless of other
  1435. properties of the certificates.
  1436. To create the hash value for filenames, use the command
  1437. line: openssl x509 -hash -noout -in YourCert.pem
  1438. The output is a 8 digit hex number you _must_ use as file
  1439. name for a given certificate in CAPath directory. Can be
  1440. any extension, using a numeric extension is handy.
  1441. History:
  1442. Jan 19, 2003 V1.00.2 First pre-relase version. Works with TWSocket version 5.00.
  1443. Lot of things remains to do. Currently support basic connections
  1444. (Socks doesn't work, line mode doesn't work).
  1445. Mar 04, 2003 V1.00.3 Socks and LineMode support
  1446. Apr 14, 2003 V1.00.4 Fixed bugs related to premature session close
  1447. Apr 04, 2004 V1.00.5 Verified with new WSocket version
  1448. Aug 31, 2005 V1.00.8 Use the code from Arno Garrels <arno.garrels@gmx.de> and
  1449. Benjamin Stadin <stadin@gmx.de>. They worked very hard to make
  1450. this code working.
  1451. Dec 07, 2005 V1.00.9 A. Garrels fixed an issue with BIO I/O functions.
  1452. Support of OSSL v0.9.8a added. Changed load order of OpenSSL
  1453. libraries. A received SSL shutdown notification in Do_FD_READ was
  1454. not detected, fixed. OpenSSL releases from 0.9.7g up to 0.9.8a
  1455. should be supported. New OpenSSL version check, an exception is
  1456. raised if version is not in the range of supported versions. In
  1457. order to disable the version check uncomment define
  1458. NO_OSSL_VERSION_CHECK in IcsLIBEAY.pas and rebuild all. Two new
  1459. methods of TSslContext to ease verification of client certificates.
  1460. They create/modify the list of acceptable CAs sent to the client
  1461. when a server requests a client certificate, AddClientCAFromFile
  1462. and SetClientCAListFromFile, see comments on top of the functions.
  1463. SslOptions modified. SSLv3 renegotiaton added, there are two
  1464. new functions SslStartRenegotiation and SslRenegotiatePending,
  1465. see comments on top of the functions. When renegotiation is
  1466. requested in server mode a new SslOption should be set also it's
  1467. sslOpt_NO_SESSION_RESUMPTION_ON_RENEGOTIATION.
  1468. Dec 19, 2005 Angus new wsocket logging
  1469. Jan 18, 2006 Arno Garrels: A lot of bugs fixed probably alot of new added ;-)
  1470. bidirectional shutdown added.
  1471. Jan 26, 2006 Type of TSslSessionIdContext changed to AnsiString due to problems
  1472. with BCB.
  1473. Mar 02, 2006 Removed function SslStateToStr which was wrong and not used.
  1474. Arno Garrels fixed TCustomSslWSocket.Do_FD_CLOSE
  1475. Mar 06, 2006 A. Garrels: Removed the so called fix from Mar 02 in Do_FD_CLOSE
  1476. because it it wasn't a real fix. Instead several changes at
  1477. several places were required to fix the shutdown problems. Fixed
  1478. error "Undeclared identifier RaiseLastOpenSslError" when
  1479. NO_DEBUG_LOG was defined. Added properties ValidNotBefore and
  1480. ValidNotAfter to TX509Base.
  1481. Multi-threading: OpenSSL library is thread safe as long as the
  1482. application provides an appropriate locking callback. Implemented
  1483. such callbacks as two components see unit IcsSslThrdLock.
  1484. Changed InitContext to always set session cache options, because
  1485. the default OpenSSL setting is to use the internal cache.
  1486. Jun 20, 2007 Changes by Arno Garrels: Fixed TX509Base.PostConnectionCheck to
  1487. handle wildcard certificates. Property TX509Base.SubjectCName may
  1488. now include a list of strings separated by CRLF (many certificates
  1489. use multiple common name fields). Common name fields encoded
  1490. Unicode or UTF-8 are now converted to ansi string. New properties
  1491. TX509Base.FirstVerifyResult and TX509Base.FirstVerifyErrMsg
  1492. hold the first verify result, because a certificate may pass
  1493. verification process several times which overwrites value of
  1494. VerifyResult.
  1495. Nov 08, 2007 A. Garrels added property PublicKey to TX509Base.
  1496. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  1497. {$IFDEF VER80}
  1498. Bomb('This unit require a 32 bit compiler !');
  1499. {$ENDIF}
  1500. {$B-} { Enable partial boolean evaluation }
  1501. {$T-} { Untyped pointers }
  1502. {$X+} { Enable extended syntax }
  1503. {$H+} { Use long strings }
  1504. {$J+} { Allow typed constant to be modified }
  1505. {$IFDEF DEBUG_DUMP}
  1506. {$DEFINE DEBUG_OUTPUT}
  1507. {$ENDIF}
  1508. const
  1509. SslWSocketVersion = 100;
  1510. SslWSocketDate = 'Jan 18, 2006';
  1511. SslWSocketCopyRight : String = ' TSslWSocket (c) 2003-2010 Francois Piette V1.00.5e ';
  1512. const
  1513. //SSL_POST_CONNECTION_CHECK_FAILED = 12101;
  1514. sslProtocolError = 20100;
  1515. SSL_BUFFER_SIZE = 4096;
  1516. msgSslCtxNotInit = 'SSL context not initialized';
  1517. {$IFNDEF NO_SSL_MT}
  1518. var
  1519. LockPwdCB : TRtlCriticalSection;
  1520. LockVerifyCB : TRtlCriticalSection;
  1521. LockInfoCB : TRtlCriticalSection;
  1522. LockRemSessCB : TRtlCriticalSection;
  1523. LockNewSessCB : TRtlCriticalSection;
  1524. LockGetSessCB : TRtlCriticalSection;
  1525. LockClientCertCB : TRtlCriticalSection;
  1526. {$IFNDEF OPENSSL_NO_TLSEXT}
  1527. LockServerNameCB : TRtlCriticalSection;
  1528. {$ENDIF}
  1529. {$ENDIF}
  1530. procedure UnloadSsl;
  1531. procedure LoadSsl;
  1532. type
  1533. // TSslDebugLevel = (ssldbgNone, ssldbgError, ssldbgInfo, ssldbgDump); angus
  1534. EOpenSslError = class(Exception);
  1535. TSslBaseComponent = class(TComponent)
  1536. protected
  1537. FSslInitialized : Boolean;
  1538. FLastSslError : Integer;
  1539. {$IFNDEF NO_DEBUG_LOG} { V5.21 }
  1540. FIcsLogger : TIcsLogger;
  1541. procedure SetIcsLogger(const Value : TIcsLogger); virtual; { V5.21 }
  1542. procedure Notification(AComponent : TComponent; { V5.21 }
  1543. Operation : TOperation); override;
  1544. procedure DebugLog(LogOption : TLogOption; { V5.21 }
  1545. const Msg : string); virtual;
  1546. function CheckLogOptions(const LogOption: TLogOption): Boolean; virtual; { V5.21 }
  1547. {$ENDIF}
  1548. procedure RaiseLastOpenSslError(EClass : ExceptClass;
  1549. Dump : Boolean = FALSE;
  1550. const CustomMsg : String = ''); virtual;
  1551. procedure InitializeSsl; {$IFDEF USE_INLINE} inline; {$ENDIF}
  1552. procedure FinalizeSsl;
  1553. public
  1554. constructor Create(AOwner: TComponent); override;
  1555. destructor Destroy; override;
  1556. property LastSslError : Integer read FLastSslError;
  1557. {$IFNDEF NO_DEBUG_LOG}
  1558. published
  1559. property IcsLogger : TIcsLogger read FIcsLogger { V5.21 }
  1560. write SetIcsLogger;
  1561. {$ENDIF}
  1562. end;
  1563. (*
  1564. TX509Stack = class(TObject) // Not yet used, but will be soon!
  1565. private
  1566. FStack : PSTACK;
  1567. FCount : Integer;
  1568. protected
  1569. function GetCert(Index : Integer): PX509;
  1570. procedure SetCert(Index : Integer; const Value : PX509);
  1571. procedure SetStack(const Value : PStack);
  1572. function InternalInsert(Cert : PX509; Index : Integer): Integer;
  1573. public
  1574. constructor Create;
  1575. destructor Destroy; override;
  1576. function Add(Cert : PX509): Integer;
  1577. procedure Clear;
  1578. procedure Insert(Cert : PX509; Index : Integer);
  1579. function IndexOf(Cert : PX509): Integer;
  1580. procedure Delete(Index : Integer);
  1581. property Count : Integer read FCount;
  1582. property Certs[index : Integer] : PX509 read GetCert
  1583. write SetCert; default;
  1584. property Stack: PSTACK read FStack
  1585. write SetStack;
  1586. end;
  1587. *)
  1588. {$IFNDEF COMPILER6_UP}
  1589. const {AG 02/06/06}
  1590. MinDateTime: TDateTime = -657434.0; { 01/01/0100 12:00:00.000 AM }
  1591. MaxDateTime: TDateTime = 2958465.99999; { 12/31/9999 11:59:59.999 PM }
  1592. {$ENDIF}
  1593. type
  1594. EX509Exception = class(Exception);
  1595. TExtension = record
  1596. Critical : Boolean;
  1597. ShortName : String;
  1598. Value : String; // may be also one or multiple Name=value pairs,
  1599. end; // separated by a CRLF
  1600. PExtension = ^TExtension;
  1601. TBioOpenMethode = (bomRead, bomWrite);
  1602. TX509Base = class(TSslBaseComponent)
  1603. private
  1604. FX509 : Pointer;
  1605. FPrivateKey : Pointer;
  1606. protected
  1607. FVerifyResult : Integer; // current verify result
  1608. FSha1Hash : AnsiString;
  1609. FVerifyDepth : Integer;
  1610. FCustomVerifyResult : Integer;
  1611. FFirstVerifyResult : Integer; {05/21/2007 AG}
  1612. procedure FreeAndNilX509;
  1613. procedure SetX509(X509: Pointer);
  1614. procedure SetPrivateKey(PKey: Pointer);
  1615. function GetPublicKey: Pointer;
  1616. function GetVerifyErrorMsg: String;
  1617. function GetFirstVerifyErrorMsg: String; {05/21/2007 AG}
  1618. function GetIssuerOneLine: String;
  1619. function GetSubjectOneLine: String;
  1620. function GetSerialNum: Integer; virtual;
  1621. function GetSubjectCName: String;
  1622. function GetSubjectAltName: TExtension; virtual;
  1623. function GetExtension(Index: Integer): TExtension; virtual;
  1624. function GetExtensionCount: Integer;
  1625. function GetValidNotBefore: TDateTime; {AG 02/06/06}
  1626. function GetValidNotAfter: TDateTime; {AG 02/06/06}
  1627. function GetHasExpired: Boolean; {AG 02/06/06}
  1628. procedure AssignDefaults; virtual;
  1629. function UnknownExtDataToStr(Ext: PX509_Extension) : String;
  1630. function GetSha1Hash: AnsiString;
  1631. function OpenFileBio(const FileName : String;
  1632. Methode : TBioOpenMethode): PBIO;
  1633. procedure ReadFromBio(ABio: PBIO; IncludePrivateKey: Boolean = FALSE;
  1634. const Password: String = ''); virtual;
  1635. procedure WriteToBio(ABio: PBIO; IncludePrivateKey: Boolean = FALSE;
  1636. AddRawText: Boolean = FALSE); virtual;
  1637. public
  1638. constructor Create(AOwner: TComponent; X509: Pointer = nil); reintroduce;
  1639. destructor Destroy; override;
  1640. function ExtByName(const ShortName: String): Integer;
  1641. function PostConnectionCheck(HostOrIp: String): Boolean; virtual;
  1642. function GetRawText: String; {05/21/2007 AG}
  1643. procedure LoadFromPemFile(const FileName: String;
  1644. IncludePrivateKey: Boolean = False;
  1645. const Password: String = '');
  1646. procedure SaveToPemFile(const FileName: String;
  1647. IncludePrivateKey: Boolean = FALSE;
  1648. AddRawText: Boolean = FALSE);
  1649. procedure PrivateKeyLoadFromPemFile(const FileName: String;
  1650. const Password: String = '');
  1651. procedure PrivateKeySaveToPemFile(const FileName: String);
  1652. property IssuerOneLine : String read GetIssuerOneLine;
  1653. property SubjectOneLine : String read GetSubjectOneLine;
  1654. property SerialNum : Integer read GetSerialNum;
  1655. property VerifyResult : Integer read FVerifyResult
  1656. write FVerifyResult;
  1657. property VerifyErrMsg : String read GetVerifyErrorMsg;
  1658. property VerifyDepth : Integer read FVerifyDepth
  1659. write FVerifyDepth;
  1660. property CustomVerifyResult : Integer read FCustomVerifyResult
  1661. write FCustomVerifyResult;
  1662. property FirstVerifyResult : Integer read FFirstVerifyResult {05/21/2007 AG}
  1663. write FFirstVerifyResult;
  1664. property FirstVerifyErrMsg : String read GetFirstVerifyErrorMsg; {05/21/2007 AG}
  1665. property X509 : Pointer read FX509
  1666. write SetX509;
  1667. property PrivateKey : Pointer read FPrivateKey
  1668. write SetPrivateKey;
  1669. property PublicKey : Pointer read GetPublicKey; {AG 11/08/07}
  1670. property SubjectCName : String read GetSubjectCName;
  1671. property SubjectAltName : TExtension read GetSubjectAltName;
  1672. property ExtensionCount : Integer read GetExtensionCount;
  1673. property Extensions[index: Integer] : TExtension read GetExtension;
  1674. property Sha1Hash : AnsiString read FSha1Hash;
  1675. property ValidNotBefore : TDateTime read GetValidNotBefore; {AG 02/06/06}
  1676. property ValidNotAfter : TDateTime read GetValidNotAfter; {AG 02/06/06}
  1677. property HasExpired : Boolean read GetHasexpired; {AG 02/06/06}
  1678. end;
  1679. TX509Class = class of TX509Base;
  1680. TCustomSslWSocket = class; //forward
  1681. TX509List = class(TObject)
  1682. { Written by Arno Garrels, for ICS }
  1683. { Contact: email arno.garrels@gmx.de }
  1684. private
  1685. FList : TComponentList;
  1686. FX509Class : TX509Class;
  1687. FOwner : TComponent;
  1688. FLastVerifyResult : Integer;
  1689. protected
  1690. function GetCount: Integer;
  1691. function GetX509Base(Index: Integer): TX509Base;
  1692. procedure SetX509Base(Index: Integer; Value: TX509Base);
  1693. function GetByPX509(const X509: PX509) : TX509Base;
  1694. public
  1695. constructor Create(AOwner: TComponent); reintroduce;
  1696. destructor Destroy; override;
  1697. procedure Clear;
  1698. function Add(X509 : PX509 = nil) : TX509Base;
  1699. procedure Delete(const Index: Integer);
  1700. function IndexOf(const X509Base : TX509Base): Integer;
  1701. function GetByHash(const Sha1Hash : AnsiString): TX509Base;
  1702. property Count : Integer read GetCount;
  1703. property Items[index: Integer] : TX509Base read GetX509Base
  1704. write SetX509Base; default;
  1705. property X509Class : TX509Class read FX509Class
  1706. write FX509Class;
  1707. property LastVerifyResult : Integer read FLastVerifyResult;
  1708. end;
  1709. TSslContextRemoveSession = procedure(Sender: TObject;
  1710. SslSession : Pointer) of object;
  1711. // SSL Version selection
  1712. TSslVersionMethod = (sslV2,
  1713. sslV2_CLIENT,
  1714. sslV2_SERVER,
  1715. sslV3,
  1716. sslV3_CLIENT,
  1717. sslV3_SERVER,
  1718. sslTLS_V1,
  1719. sslTLS_V1_CLIENT,
  1720. sslTLS_V1_SERVER,
  1721. sslV23,
  1722. sslV23_CLIENT,
  1723. sslV23_SERVER);
  1724. TSslVerifyPeerMode = (SslVerifyMode_NONE,
  1725. SslVerifyMode_PEER,
  1726. SslVerifyMode_FAIL_IF_NO_PEER_CERT,
  1727. SslVerifyMode_CLIENT_ONCE);
  1728. TSslVerifyPeerModes = set of TSslVerifyPeerMode;
  1729. TSslOption = (sslOpt_CIPHER_SERVER_PREFERENCE,
  1730. sslOpt_MICROSOFT_SESS_ID_BUG,
  1731. sslOpt_NETSCAPE_CHALLENGE_BUG,
  1732. sslOpt_NETSCAPE_REUSE_CIPHER_CHANGE_BUG,
  1733. sslOpt_SSLREF2_REUSE_CERT_TYPE_BUG,
  1734. sslOpt_MICROSOFT_BIG_SSLV3_BUFFER,
  1735. sslOpt_MSIE_SSLV2_RSA_PADDING,
  1736. sslOpt_SSLEAY_080_CLIENT_DH_BUG,
  1737. sslOpt_TLS_D5_BUG,
  1738. sslOpt_TLS_BLOCK_PADDING_BUG,
  1739. sslOpt_TLS_ROLLBACK_BUG,
  1740. sslOpt_DONT_INSERT_EMPTY_FRAGMENTS,
  1741. sslOpt_SINGLE_DH_USE,
  1742. sslOpt_EPHEMERAL_RSA,
  1743. sslOpt_NO_SSLv2,
  1744. sslOpt_NO_SSLv3,
  1745. sslOpt_NO_TLSv1,
  1746. sslOpt_PKCS1_CHECK_1,
  1747. sslOpt_PKCS1_CHECK_2,
  1748. sslOpt_NETSCAPE_CA_DN_BUG,
  1749. //sslOP_NO_TICKET,
  1750. sslOpt_NO_SESSION_RESUMPTION_ON_RENEGOTIATION, // 12/09/05
  1751. sslOpt_NETSCAPE_DEMO_CIPHER_CHANGE_BUG,
  1752. sslOpt_ALLOW_UNSAFE_LEGACY_RENEGOTIATION); // Since OSSL 0.9.8n
  1753. TSslOptions = set of TSslOption;
  1754. TSslSessCacheMode = (//sslSESS_CACHE_OFF,
  1755. sslSESS_CACHE_CLIENT,
  1756. sslSESS_CACHE_SERVER,
  1757. //sslSESS_CACHE_BOTH,
  1758. sslSESS_CACHE_NO_AUTO_CLEAR,
  1759. sslSESS_CACHE_NO_INTERNAL_LOOKUP,
  1760. sslSESS_CACHE_NO_INTERNAL_STORE{,
  1761. sslSESS_CACHE_NO_INTERNAL});
  1762. TSslSessCacheModes = set of TSslSessCacheMode;
  1763. TSslSessionIdContext = String;//[SSL_MAX_SSL_SESSION_ID_LENGTH];
  1764. {
  1765. TSslX509Trust = (ssl_X509_TRUST_NOT_DEFINED, // Custom value
  1766. ssl_X509_TRUST_COMPAT,
  1767. ssl_X509_TRUST_SSL_CLIENT,
  1768. ssl_X509_TRUST_SSL_SERVER,
  1769. ssl_X509_TRUST_EMAIL,
  1770. ssl_X509_TRUST_OBJECT_SIGN,
  1771. ssl_X509_TRUST_OCSP_SIGN,
  1772. ssl_X509_TRUST_OCSP_REQUEST); }
  1773. {$IFNDEF OPENSSL_NO_ENGINE}
  1774. ESslEngineError = class(Exception);
  1775. TSslEngineState = (esClosed, esOpen, esInit);
  1776. TSslEngineCtxCapabilities = set of (eccLoadPrivKey, eccLoadPubKey{, eccLoadClientCert});
  1777. TSslEngine = class(TSslBaseComponent)
  1778. private
  1779. FEngine : PEngine;
  1780. FNameID : String;
  1781. FState : TSslEngineState;
  1782. FCtxCapabilities : TSslEngineCtxCapabilities;
  1783. FLastErrorMsg : String;
  1784. FKeyID : String;
  1785. procedure SetNameID(const Value: String);
  1786. public
  1787. destructor Destroy; override;
  1788. function Open: Boolean;
  1789. function Control(const Cmd, Arg: String): Boolean;
  1790. procedure Close;
  1791. function Init: Boolean;
  1792. property E : PEngine read FEngine;
  1793. property State : TSslEngineState read FState;
  1794. property LastErrorMsg : String read FLastErrorMsg write FLastErrorMsg;
  1795. published
  1796. property KeyID : String read FKeyID write FKeyID;
  1797. property NameID : String read FNameID write SetNameID;
  1798. property CtxCapabilities : TSslEngineCtxCapabilities read FCtxCapabilities write FCtxCapabilities;
  1799. end;
  1800. {$ENDIF}
  1801. ESslContextException = class(Exception);
  1802. TInfoExtractMode = (emCert, {emKey,} emCRL);
  1803. // TSslCertKeyFormat = (ckfPem {$IFNDEF OPENSSL_NO_ENGINE}, ckfEngine {$ENDIF}); {ckfPkcs12,}
  1804. TSslContext = class(TSslBaseComponent)
  1805. protected
  1806. FSslCtx : PSSL_CTX;
  1807. FSslVersionMethod : TSslVersionMethod;
  1808. FSslCertFile : String;
  1809. FSslPassPhrase : String;
  1810. FSslPrivKeyFile : String;
  1811. FSslCAFile : String;
  1812. FSslCAPath : String;
  1813. FSslCRLFile : String;
  1814. FSslCRLPath : String;
  1815. //FSslIntermCAFile : String;
  1816. //FSslIntermCAPath : String;
  1817. FSslVerifyPeer : Boolean;
  1818. FSslVerifyDepth : Integer;
  1819. FSslOptionsValue : Longint;
  1820. FSslCipherList : String;
  1821. FSslSessCacheModeValue : Longint;
  1822. FSslSessionCacheSize : Longint;
  1823. FSslSessionTimeout : Longword;
  1824. FSslDefaultSessionIDContext : TSslSessionIdContext;
  1825. FOnRemoveSession : TSslContextRemoveSession;
  1826. FSslVerifyPeerModes : TSslVerifyPeerModes;
  1827. FSslVerifyPeerModesValue : Integer;
  1828. //FSslX509Trust : TSslX509Trust;
  1829. FOnBeforeInit : TNotifyEvent;
  1830. //FSslKeyFormat : TSslCertKeyFormat;
  1831. {$IFNDEF OPENSSL_NO_ENGINE}
  1832. FAutoEnableBuiltinEngines : Boolean;
  1833. FCtxEngine : TSslEngine;
  1834. {$ENDIF}
  1835. {$IFNDEF NO_SSL_MT}
  1836. FLock : TRtlCriticalSection;
  1837. procedure Lock;
  1838. procedure Unlock;
  1839. {$ENDIF}
  1840. function InitializeCtx : PSSL_CTX;
  1841. procedure SetSslCertFile(const Value : String);
  1842. procedure SetSslPassPhrase(const Value : String);
  1843. procedure SetSslPrivKeyFile(const Value : String);
  1844. procedure SetSslCAFile(const Value : String);
  1845. procedure SetSslCAPath(const Value : String);
  1846. procedure SetSslCRLFile(const Value : String);
  1847. procedure SetSslCRLPath(const Value : String);
  1848. procedure SetSslSessionCacheSize(Value : Longint);
  1849. procedure SetSslOptions(Value : TSslOptions);
  1850. function GetSslOptions : TSslOptions;
  1851. procedure SetSslSessCacheModes(Value : TSslSessCacheModes);
  1852. function GetSslSessCacheModes : TSslSessCacheModes;
  1853. procedure SetSslCipherList(const Value : String);
  1854. procedure SetSslVerifyPeerModes(const Value : TSslVerifyPeerModes);
  1855. procedure SetSslVerifyPeer(const Value: Boolean);
  1856. procedure SetSslDefaultSessionIDContext(Value: TSslSessionIdContext);
  1857. procedure SetSslSessionTimeout(Value : Longword);
  1858. procedure SetSslVersionMethod(Value : TSslVersionMethod);
  1859. function OpenFileBio(const FileName : String;
  1860. Methode : TBioOpenMethode): PBIO;
  1861. function LoadStackFromInfoFile(const FileName : String;
  1862. Mode : TInfoExtractMode): PStack;
  1863. procedure LoadVerifyLocations(const CAFile, CAPath: String);
  1864. procedure LoadCertFromChainFile(const FileName : String);
  1865. procedure LoadPKeyFromFile(const FileName : String);
  1866. //procedure DebugLogInfo(const Msg: string); { V5.21 }
  1867. //procedure SetSslX509Trust(const Value: TSslX509Trust);
  1868. function GetIsCtxInitialized : Boolean;
  1869. {$IFNDEF OPENSSL_NO_ENGINE}
  1870. procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  1871. procedure SetCtxEngine(const Value: TSslEngine);
  1872. {$ENDIF}
  1873. public
  1874. constructor Create(AOwner: TComponent); override;
  1875. destructor Destroy; override;
  1876. procedure InitContext;
  1877. procedure DeInitContext;
  1878. function TrustCert(Cert : TX509Base): Boolean;
  1879. procedure LoadCrlFromFile(const Filename: String);
  1880. procedure LoadCrlFromPath(const Path: String);
  1881. {$IFNDEF OPENSSL_NO_ENGINE}
  1882. procedure LoadPKeyFromEngine(CtxEngine: TSslEngine);
  1883. //function SetupEngine(Engine: String; Commands: TStrings): PENGINE;
  1884. {$ENDIF}
  1885. procedure AddClientCAFromFile(const FileName: String);
  1886. procedure SetClientCAListFromFile(const FileName: String);
  1887. property IsCtxInitialized : Boolean read GetIsCtxInitialized;
  1888. published
  1889. property SslCertFile : String read FSslCertFile
  1890. write SetSslCertFile;
  1891. property SslPassPhrase : String read FSslPassPhrase
  1892. write SetSslPassPhrase;
  1893. property SslPrivKeyFile : String read FSslPrivKeyFile
  1894. write SetSslPrivKeyFile;
  1895. property SslCAFile : String read FSslCAFile
  1896. write SetSslCAFile;
  1897. property SslCAPath : String read FSslCAPath
  1898. write SetSslCAPath;
  1899. property SslCRLFile : String read FSslCRLFile
  1900. write SetSslCRLFile;
  1901. property SslCRLPath : String read FSslCRLPath
  1902. write SetSslCRLPath;
  1903. {property SslIntermCAFile : String read FSslIntermCAFile
  1904. write FSslIntermCAFile;
  1905. property SslIntermCAPath : String read FSslIntermCAPath
  1906. write FSslIntermCAPath;}
  1907. property SslVerifyPeer : Boolean read FSslVerifyPeer
  1908. write SetSslVerifyPeer;
  1909. property SslVerifyDepth : Integer read FSslVerifyDepth
  1910. write FSslVerifyDepth;
  1911. property SslOptions : TSslOptions read GetSslOptions
  1912. write SetSslOptions;
  1913. property SslVerifyPeerModes : TSslVerifyPeerModes
  1914. read FSslVerifyPeerModes
  1915. write SetSslVerifyPeerModes;
  1916. property SslSessionCacheModes : TSslSessCacheModes
  1917. read GetSslSessCacheModes
  1918. write SetSslSessCacheModes;
  1919. property SslCipherList : String read FSslCipherList
  1920. write SetSslCipherList;
  1921. property SslVersionMethod : TSslVersionMethod
  1922. read FSslVersionMethod
  1923. write SetSslVersionMethod;
  1924. property SslSessionTimeout : Longword read FSslSessionTimeout
  1925. write SetSslSessionTimeout;
  1926. property SslSessionCacheSize : Integer
  1927. read FSslSessionCacheSize
  1928. write SetSslSessionCacheSize;
  1929. property SslDefaultSessionIDContext : TSslSessionIdContext
  1930. read FSslDefaultSessionIDContext
  1931. write SetSslDefaultSessionIDContext;
  1932. {property SslX509Trust : TSslX509Trust read FSslX509Trust
  1933. write SetSslX509Trust;}
  1934. property OnRemoveSession : TSslContextRemoveSession
  1935. read FOnRemoveSession
  1936. write FOnRemoveSession;
  1937. property OnBeforeInit : TNotifyEvent read FOnBeforeInit
  1938. write FOnBeforeInit;
  1939. {property SslKeyFormat : TSslCertKeyFormat
  1940. read FSslKeyFormat
  1941. write FSslKeyFormat;}
  1942. {$IFNDEF OPENSSL_NO_ENGINE}
  1943. property AutoEnableBuiltinEngines : Boolean read FAutoEnableBuiltinEngines
  1944. write FAutoEnableBuiltinEngines;
  1945. property CtxEngine : TSslEngine read FCtxEngine write SetCtxEngine;
  1946. {$ENDIF}
  1947. end;
  1948. {TSslState = (sslNone,
  1949. sslWantConnect,
  1950. sslConnectWantRead,
  1951. sslConnectWantWrite,
  1952. sslConnected,
  1953. sslAccepted,
  1954. sslAcceptWantRead,
  1955. sslAcceptWantWrite,
  1956. sslWriteWantRead,
  1957. sslWriteWantWrite,
  1958. sslShutdown,
  1959. sslShutdownWantRead,
  1960. sslShutdownWantWrite);
  1961. }
  1962. TSslState = (sslNone, // Not yet finished, Francois, could you care about states ??
  1963. sslHandshakeInit,
  1964. sslHandshakeStarted,
  1965. sslHandshakeFailed,
  1966. sslEstablished,
  1967. sslInShutdown,
  1968. sslShutdownComplete);
  1969. TSslVerifyPeerEvent = procedure (Sender : TObject;
  1970. var Ok : Integer;
  1971. Cert : TX509Base) of object;
  1972. TSslHandshakeDoneEvent = procedure (Sender : TObject;
  1973. ErrCode : Word;
  1974. PeerCert : TX509Base;
  1975. var Disconnect : Boolean) of object;
  1976. TSslEvent = (sslFdRead, sslFdWrite, sslFdClose);
  1977. TSslPendingEvents = set of TSslEvent;
  1978. TSslMode = (sslModeClient, sslModeServer);
  1979. //Client-side session caching
  1980. TSslCliGetSession = procedure(Sender : TObject;
  1981. var SslSession : Pointer;
  1982. var FreeSession : Boolean) of object;
  1983. TSslCliNewSession = procedure(Sender : TObject;
  1984. SslSession : Pointer;
  1985. WasReused : Boolean;
  1986. var IncRefCount : Boolean) of object;
  1987. //Server-side session caching
  1988. TSslSetSessionIDContext = procedure(Sender : TObject;
  1989. var SessionIDContext : TSslSessionIdContext) of object;
  1990. TSslSvrNewSession = procedure(Sender : TObject;
  1991. SslSession : Pointer;
  1992. SessId : Pointer;
  1993. Idlen : Integer;
  1994. var AddToInternalCache : Boolean) of object;
  1995. TSslSvrGetSession = procedure(Sender : TObject;
  1996. var SslSession : Pointer;
  1997. SessId : Pointer;
  1998. Idlen : Integer;
  1999. var IncRefCount : Boolean) of object;
  2000. TSslCliCertRequest = procedure(Sender : TObject;
  2001. var Cert : TX509Base) of object;
  2002. TSslShutDownComplete = procedure(Sender : TObject;
  2003. Bidirectional : Boolean;
  2004. ErrCode : Integer) of object;
  2005. {$IFNDEF OPENSSL_NO_TLSEXT}
  2006. TTlsExtError = (teeOk, teeAlertWarning, teeAlertFatal, teeNoAck);
  2007. {
  2008. SSL_TLSEXT_ERR_OK = 0;
  2009. SSL_TLSEXT_ERR_ALERT_WARNING = 1;
  2010. SSL_TLSEXT_ERR_ALERT_FATAL = 2;
  2011. SSL_TLSEXT_ERR_NOACK = 3;
  2012. }
  2013. TSslServerNameEvent = procedure(Sender : TObject;
  2014. var Ctx : TSslContext;
  2015. var ErrCode : TTlsExtError) of object;
  2016. {$ENDIF}
  2017. TCustomSslWSocket = class(TCustomSocksWSocket)
  2018. protected
  2019. FSslContext : TSslContext;
  2020. FOnSslSvrNewSession : TSslSvrNewSession;
  2021. FOnSslSvrGetSession : TSslSvrGetSession;
  2022. FOnSslCliGetSession : TSslCliGetSession;
  2023. FOnSslCliNewSession : TSslCliNewSession;
  2024. FOnSslSetSessionIDContext : TSslSetSessionIDContext;
  2025. {$IFNDEF OPENSSL_NO_TLSEXT}
  2026. FOnSslServerName : TSslServerNameEvent;
  2027. {$ENDIF}
  2028. FOnSslCliCertRequest : TSslCliCertRequest;
  2029. FX509Class : TX509Class;
  2030. FSslCertChain : TX509List;
  2031. FSslMode : TSslMode;
  2032. //FTriggerCount : Integer; //Test
  2033. FSslBufList : TIcsBufferHandler;
  2034. FExplizitSsl : Boolean;
  2035. bSslAllSent : Boolean;
  2036. FMayTriggerFD_Read : Boolean;
  2037. FMayTriggerFD_Write : Boolean;
  2038. FMayTriggerDoRecv : Boolean;
  2039. FMayTriggerSslTryToSend : Boolean;
  2040. //FHandShakeDoneInvoked : Boolean;
  2041. FCloseCalled : Boolean;
  2042. //FCloseReceived : Boolean;
  2043. FPendingSslEvents : TSslPendingEvents;
  2044. FSslIntShutDown : Integer;
  2045. FShutDownHow : Integer;
  2046. FSslEnable : Boolean;
  2047. //FSslEstablished : Boolean;
  2048. FLastSslError : Integer;
  2049. FSslInRenegotiation : Boolean; // <= 01/01/06
  2050. FSslBioWritePendingBytes : Integer;
  2051. FSendPending : Boolean;
  2052. FSslBiShutDownFlag : Boolean; // <= 01/08/06
  2053. FOnSslShutDownComplete : TSslShutDownComplete;
  2054. FNetworkError : Integer;
  2055. FSslInitialized : Boolean;
  2056. FInHandshake : Boolean;
  2057. FHandshakeDone : Boolean;
  2058. FSslVersNum : Integer; //12/09/05
  2059. FSSLState : TSslState;
  2060. FSsl_In_CB : Boolean;
  2061. FSsl : PSSL;
  2062. FSslBio : PBIO;
  2063. FIBio : PBIO;
  2064. FNBio : PBIO;
  2065. FSslAcceptableHosts : TStrings;
  2066. FSslVerifyResult : Integer;
  2067. FSslVersion : String;
  2068. FSslCipher : String;
  2069. FSslTotalBits : Integer;
  2070. FSslSecretBits : Integer;
  2071. FSslSupportsSecureRenegotiation : Boolean;
  2072. FMsg_WM_TRIGGER_DATASENT : UINT;
  2073. FMsg_WM_SSL_ASYNCSELECT : UINT;
  2074. FMsg_WM_RESET_SSL : UINT;
  2075. FMsg_WM_BI_SSL_SHUTDOWN : UINT;
  2076. FMsg_WM_TRIGGER_SSL_SHUTDOWN_COMPLETED : UINT;
  2077. FOnSslVerifyPeer : TSslVerifyPeerEvent;
  2078. FOnSslHandshakeDone : TSslHandshakeDoneEvent;
  2079. FHandShakeCount : Integer;
  2080. {$IFNDEF OPENSSL_NO_TLSEXT}
  2081. FSslServerName : String;
  2082. {$ENDIF}
  2083. //procedure SetSslEnable(const Value: Boolean); virtual;
  2084. procedure RaiseLastOpenSslError(EClass : ExceptClass;
  2085. Dump : Boolean = FALSE;
  2086. const CustomMsg : String = ''); virtual;
  2087. function SocketDataPending : Boolean;
  2088. procedure InternalShutdown(How: Integer);
  2089. procedure PutDataInSslBuffer(Data: Pointer; Len: Integer);
  2090. procedure DeleteBufferedSslData;
  2091. function GetRcvdCount : LongInt; override;
  2092. procedure WMSslBiShutDown(var msg: TMessage);
  2093. procedure WMSslASyncSelect(var msg: TMessage);
  2094. procedure WMTriggerSslShutDownComplete(var msg: TMessage);
  2095. procedure Do_SSL_FD_READ(var Msg: TMessage);
  2096. function TriggerEvent(Event: TSslEvent; ErrCode: Word): Boolean;
  2097. procedure AssignDefaultValue; override;
  2098. procedure Do_FD_CONNECT(var Msg : TMessage); override;
  2099. procedure Do_FD_READ(var Msg : TMessage); override;
  2100. procedure Do_FD_WRITE(var Msg : TMessage); override;
  2101. procedure Do_FD_CLOSE(var Msg : TMessage); override;
  2102. procedure Do_FD_ACCEPT(var Msg : TMessage); override;
  2103. //procedure WMSslHandshakeDone(var msg: TMessage); message WM_TRIGGER_SSLHANDSHAKEDONE;
  2104. function SslShutdownCompleted(How: Integer) : Boolean;
  2105. function DoRecv(var Buffer : TWSocketData;
  2106. BufferSize : Integer;
  2107. Flags : Integer) : Integer; override;
  2108. procedure TryToSend; override;
  2109. procedure InitializeSsl;
  2110. procedure FinalizeSsl;
  2111. procedure InitSSLConnection(ClientMode : Boolean; pSSLContext : PSSL_CTX = nil);
  2112. //function LoadCertificate(out ErrMsg : String) : Boolean;
  2113. procedure DupConnected; override;
  2114. procedure InternalClose(bShut : Boolean; Error : Word); override;
  2115. procedure InternalAbort(ErrCode : Word); override;
  2116. procedure WndProc(var MsgRec: TMessage); override;
  2117. procedure SetSslAcceptableHosts(Value : TStrings);
  2118. procedure TriggerEvents;
  2119. procedure TriggerSessionConnected(ErrCode : Word); override;
  2120. procedure TriggerSslHandshakeDone(ErrCode : Word); virtual;
  2121. procedure TriggerSslVerifyPeer(var Ok : Integer;
  2122. Cert : TX509Base); virtual;
  2123. procedure TriggerSslCliNewSession; virtual;
  2124. procedure SetSslContext(const Value: TSslContext);
  2125. procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  2126. procedure TriggerSslShutDownComplete(ErrCode: Integer); virtual;
  2127. function MsgHandlersCount : Integer; override;
  2128. procedure AllocateMsgHandlers; override;
  2129. procedure FreeMsgHandlers; override;
  2130. property X509Class : TX509Class read FX509Class write FX509Class;
  2131. public
  2132. constructor Create(AOwner : TComponent); override;
  2133. destructor Destroy; override;
  2134. procedure ResetSSL;
  2135. procedure Listen; override;
  2136. function Accept : TSocket; override;
  2137. procedure Close; override;
  2138. procedure Dup(NewHSocket: Integer); override;
  2139. procedure ThreadAttach; override;
  2140. procedure Resume; override;
  2141. //procedure DoSslShutdown;
  2142. procedure ResetSslDelayed;
  2143. procedure SslBiShutDownAsync;
  2144. function SslStartRenegotiation : Boolean;
  2145. function SslRenegotiatePending : Boolean;
  2146. function SslSessionReused : Boolean;
  2147. procedure Shutdown(How : Integer); override;
  2148. procedure PutDataInSendBuffer(Data : TWSocketData; Len : Integer); override;
  2149. procedure StartSslHandshake;
  2150. procedure AcceptSslHandshake;
  2151. procedure SetAcceptableHostsList(const SemiColonSeparatedList : String);
  2152. property LastSslError : Integer read FLastSslError;
  2153. property ExplizitSsl : Boolean read FExplizitSsl
  2154. write FExplizitSsl;
  2155. {$IFNDEF OPENSSL_NO_TLSEXT}
  2156. property SslServerName : String read FSslServerName
  2157. write FSslServerName;
  2158. {$ENDIF}
  2159. property OnSslShutDownComplete : TSslShutDownComplete
  2160. read FOnSslShutDownComplete
  2161. write FOnSslShutDownComplete;
  2162. property SSL : PSsl read FSsl;
  2163. //write FSsl;
  2164. property SslInRenegotiation : Boolean read FSslInRenegotiation; //<= 01/01/06 AG
  2165. property SslEnable : Boolean read FSslEnable
  2166. write FSslEnable;
  2167. //property SslEstablished : Boolean read FSslEstablished;
  2168. property SslState : TSslState read FSslState;
  2169. property SslContext : TSslContext read FSslContext
  2170. write SetSslContext;
  2171. property SslCertChain : TX509List read FSslCertChain;
  2172. property OnSslVerifyPeer : TSslVerifyPeerEvent read FOnSslVerifyPeer
  2173. write FOnSslVerifyPeer;
  2174. property OnSslCliCertRequest : TSslCliCertRequest
  2175. read FOnSslCliCertRequest
  2176. write FOnSslCliCertRequest;
  2177. property OnSslHandshakeDone : TSslHandshakeDoneEvent
  2178. read FOnSslHandshakeDone
  2179. write FOnSslHandshakeDone;
  2180. property OnSslSvrNewSession : TSslSvrNewSession read FOnSslSvrNewSession
  2181. write FOnSslSvrNewSession;
  2182. property OnSslSvrGetSession : TSslSvrGetSession read FOnSslSvrGetSession
  2183. write FOnSslSvrGetSession;
  2184. property OnSslCliGetSession : TSslCliGetSession
  2185. read FOnSslCliGetSession
  2186. write FOnSslCliGetSession;
  2187. property OnSslCliNewSession : TSslCliNewSession read FOnSslCliNewSession
  2188. write FOnSslCliNewSession;
  2189. property OnSslSetSessionIDContext : TSslSetSessionIDContext
  2190. read FOnSslSetSessionIDContext
  2191. write FOnSslSetSessionIDContext;
  2192. {$IFNDEF OPENSSL_NO_TLSEXT}
  2193. property OnSslServerName : TSslServerNameEvent
  2194. read FOnSslServerName
  2195. write FOnSslServerName;
  2196. {$ENDIF}
  2197. property SslAcceptableHosts : TStrings read FSslAcceptableHosts
  2198. write SetSslAcceptableHosts;
  2199. property SslMode : TSslMode read FSslMode
  2200. write FSslMode;
  2201. property SslVersion : String read FSslVersion;
  2202. property SslCipher : String read FSslCipher;
  2203. property SslTotalBits : Integer read FSslTotalBits;
  2204. property SslSecretBits : Integer read FSslSecretBits;
  2205. private
  2206. function my_WSocket_recv(s: TSocket;
  2207. var Buf: TWSocketData; len, flags: Integer): Integer;
  2208. function my_RealSend(Buf : TWSocketData; Len : Integer) : Integer;
  2209. {$IFNDEF NO_DEBUG_LOG}
  2210. function GetMyBioName(B: PBIO) : String;
  2211. {$ENDIF}
  2212. function my_BIO_ctrl_pending(B: PBIO) : integer;
  2213. function my_BIO_read(B: PBIO; Buf: Pointer; Len: Integer): Integer;
  2214. function my_BIO_write(B: PBIO; Buf: Pointer; Len: Integer): Integer;
  2215. function my_BIO_ctrl(bp: PBIO; Cmd: Integer; LArg: LongInt; PArg: Pointer): LongInt;
  2216. function my_BIO_ctrl_get_write_guarantee(b: PBIO): Integer;
  2217. function my_BIO_ctrl_get_read_request(b: PBIO): Integer;
  2218. function my_BIO_should_retry(b: PBIO): Boolean;
  2219. procedure HandleSslError;
  2220. end;
  2221. //procedure OutputDebugString(const Msg: String);
  2222. var
  2223. SslCritSect : TRTLCriticalSection;
  2224. type
  2225. {$ENDIF} // USE_SSL
  2226. TLineLimitEvent = procedure (Sender : TObject;
  2227. RcvdLength : LongInt;
  2228. var ClearData : Boolean) of object;
  2229. { You must define USE_SSL so that SSL code is included in the component. }
  2230. { Either in OverbyteIcsDefs.inc or in the project/package options. }
  2231. {$IFDEF USE_SSL} // Makes the IDE happy
  2232. TBaseParentWSocket = TCustomSslWSocket;
  2233. {$ELSE}
  2234. TBaseParentWSocket = TCustomSocksWSocket;
  2235. {$ENDIF}
  2236. (*
  2237. {$IFDEF USE_SSL}
  2238. TCustomLineWSocket = class (TCustomSslWSocket)
  2239. {$ELSE}
  2240. TCustomLineWSocket = class (TCustomSocksWSocket)
  2241. {$ENDIF}
  2242. *)
  2243. TCustomLineWSocket = class (TBaseParentWSocket)
  2244. protected
  2245. FRcvdPtr : TWSocketData;
  2246. FRcvBufSize : LongInt;
  2247. FRcvdCnt : LongInt;
  2248. {$IFDEF CLR}
  2249. FLocalBuf : TBytes;
  2250. {$ENDIF}
  2251. FLineEnd : AnsiString;
  2252. FLineMode : Boolean;
  2253. FLineLength : Integer; { When a line is available }
  2254. FLineLimit : LongInt; { Max line length we accept }
  2255. FLineReceivedFlag : Boolean;
  2256. FLineFound : Boolean;
  2257. FLineClearData : Boolean;
  2258. FLineEcho : Boolean; { Echo received data }
  2259. FLineEdit : Boolean; { Edit received data }
  2260. FTimeout : LongInt; { Given in milliseconds }
  2261. FTimeStop : LongInt; { Milliseconds }
  2262. FOnLineLimitExceeded : TLineLimitEvent;
  2263. procedure WndProc(var MsgRec: TMessage); override;
  2264. procedure WMTriggerDataAvailable(var msg: TMessage);
  2265. function TriggerDataAvailable(ErrCode : Word) : Boolean; override;
  2266. procedure TriggerSessionClosed(Error : Word); override;
  2267. procedure TriggerLineLimitExceeded(Cnt: Integer;
  2268. var ClearData : Boolean); virtual;
  2269. procedure SetLineMode(newValue : Boolean); virtual;
  2270. procedure EditLine(var Len : Integer); virtual;
  2271. function GetRcvdCount : LongInt; override;
  2272. function DoRecv(var Buffer : TWSocketData;
  2273. BufferSize : Integer;
  2274. Flags : Integer) : Integer; override;
  2275. public
  2276. constructor Create{$IFDEF VCL}(AOwner : TComponent){$ENDIF}; override;
  2277. destructor Destroy; override;
  2278. function SendLine(const Str : RawByteString) : Integer; {$IFDEF COMPILER12_UP} overload; {$ENDIF} virtual;
  2279. {$IFDEF COMPILER12_UP}
  2280. function SendLine(const Str : UnicodeString; ACodePage: LongWord) : Integer; overload; virtual;
  2281. function SendLine(const Str : UnicodeString) : Integer; overload; virtual;
  2282. {$ENDIF}
  2283. property LineLength : Integer read FLineLength;
  2284. property RcvdPtr : TWSocketData read FRcvdPtr;
  2285. property RcvdCnt : LongInt read FRcvdCnt;
  2286. published
  2287. property LineMode : Boolean read FLineMode
  2288. write SetLineMode;
  2289. property LineLimit : LongInt read FLineLimit
  2290. write FLineLimit;
  2291. property LineEnd : AnsiString read FLineEnd
  2292. write FLineEnd;
  2293. property LineEcho : Boolean read FLineEcho
  2294. write FLineEcho;
  2295. property LineEdit : Boolean read FLineEdit
  2296. write FLineEdit;
  2297. property OnLineLimitExceeded : TLineLimitEvent
  2298. read FOnLineLimitExceeded
  2299. write FOnLineLimitExceeded;
  2300. end;
  2301. { DEPRECATED: DO NOT USE Synchronize, WaitUntilReady, ReadLine procedure }
  2302. { for a new application. }
  2303. TCustomSyncWSocket = class(TCustomLineWSocket)
  2304. protected
  2305. {$IFDEF CLR}
  2306. FLinePointer : TBytes;
  2307. {$ENDIF}
  2308. {$IFDEF WIN32}
  2309. FLinePointer : ^AnsiString;
  2310. {$ENDIF}
  2311. function Synchronize(Proc : TWSocketSyncNextProc;
  2312. var DoneFlag : Boolean) : Integer; virtual;
  2313. function WaitUntilReady(var DoneFlag : Boolean) : Integer; virtual;
  2314. procedure InternalDataAvailable(Sender: TObject; Error: Word);
  2315. public
  2316. procedure ReadLine(Timeout : Integer; var Buffer : AnsiString); deprecated
  2317. {$IFDEF COMPILER12_UP}'Do not use in new applications'{$ENDIF};
  2318. end;
  2319. {$IFDEF BUILTIN_TIMEOUT}
  2320. TTimeoutReason = (torConnect, torIdle);
  2321. TTimeoutEvent = procedure (Sender: TObject; Reason: TTimeoutReason) of object;
  2322. TCustomTimeoutWSocket = class(TCustomSyncWSocket)
  2323. private
  2324. FTimeoutConnect : LongWord;
  2325. FTimeoutIdle : LongWord;
  2326. FTimeoutSampling : LongWord;
  2327. FOnTimeout : TTimeoutEvent;
  2328. FTimeoutTimer : TIcsThreadTimer;
  2329. FTimeoutConnectStartTick: LongWord;
  2330. FTimeoutOldTimerEnabled : Boolean;
  2331. FTimeoutKeepThreadAlive : Boolean;
  2332. procedure TimeoutHandleTimer(Sender: TObject);
  2333. procedure SetTimeoutSampling(const Value: LongWord);
  2334. procedure SetTimeoutKeepThreadAlive(const Value: Boolean);
  2335. protected
  2336. procedure TriggerTimeout(Reason: TTimeoutReason); virtual;
  2337. procedure TriggerSessionConnectedSpecial(Error: Word); override;
  2338. procedure TriggerSessionClosed(Error: Word); override;
  2339. procedure DupConnected; override;
  2340. public
  2341. constructor Create(AOwner: TComponent); override;
  2342. procedure Connect; override;
  2343. procedure TimeoutStartSampling;
  2344. procedure TimeoutStopSampling;
  2345. procedure ThreadAttach; override;
  2346. procedure ThreadDetach; override;
  2347. property TimeoutKeepThreadAlive: Boolean read FTimeoutKeepThreadAlive
  2348. write SetTimeoutKeepThreadAlive
  2349. default TRUE;
  2350. //published
  2351. property TimeoutSampling: LongWord read FTimeoutSampling
  2352. write SetTimeoutSampling;
  2353. property TimeoutConnect: LongWord read FTimeoutConnect
  2354. write FTimeoutConnect;
  2355. property TimeoutIdle: LongWord read FTimeoutIdle write FTimeoutIdle;
  2356. property OnTimeout: TTimeoutEvent read FOnTimeout write FOnTimeout;
  2357. end;
  2358. {$ENDIF}
  2359. {$IFDEF BUILTIN_THROTTLE}
  2360. {$IFDEF BUILTIN_TIMEOUT}
  2361. TCustomThrottledWSocket = class(TCustomTimeoutWSocket)
  2362. {$ELSE}
  2363. TCustomThrottledWSocket = class(TCustomSyncWSocket)
  2364. {$ENDIF}
  2365. private
  2366. FBandwidthLimit : LongWord; // Bytes per second, null = disabled
  2367. FBandwidthSampling : LongWord; // Msec sampling interval
  2368. FBandwidthCount : LongWord; // Byte counter
  2369. FBandwidthMaxCount : LongWord; // Bytes during sampling period
  2370. FBandwidthTimer : TIcsThreadTimer;
  2371. FBandwidthPaused : Boolean;
  2372. FBandwidthEnabled : Boolean;
  2373. FBandwidthOldTimerEnabled : Boolean;
  2374. FBandwidthKeepThreadAlive : Boolean;
  2375. procedure BandwidthHandleTimer(Sender: TObject);
  2376. procedure SetBandwidthControl;
  2377. procedure SetBandwidthSampling(const Value: LongWord);
  2378. procedure SetBandwidthKeepThreadAlive(const Value: Boolean);
  2379. protected
  2380. procedure DupConnected; override;
  2381. function RealSend(var Data: TWSocketData; Len : Integer) : Integer; override;
  2382. procedure TriggerSessionConnectedSpecial(Error: Word); override;
  2383. procedure TriggerSessionClosed(Error: Word); override;
  2384. public
  2385. constructor Create(AOwner: TComponent); override;
  2386. function Receive(Buffer: TWSocketData; BufferSize: Integer) : Integer; override;
  2387. procedure ThreadAttach; override;
  2388. procedure ThreadDetach; override;
  2389. property TimeoutKeepThreadAlive: Boolean read FBandwidthKeepThreadAlive
  2390. write SetBandwidthKeepThreadAlive
  2391. default TRUE;
  2392. //published
  2393. property BandwidthLimit : LongWord read FBandwidthLimit
  2394. write FBandwidthLimit;
  2395. property BandwidthSampling : LongWord read FBandwidthSampling
  2396. write SetBandwidthSampling;
  2397. end;
  2398. {$ENDIF}
  2399. {$IFDEF CLR}
  2400. // [DesignTimeVisibleAttribute(TRUE)]
  2401. {$ENDIF}
  2402. {$IFDEF BUILTIN_THROTTLE}
  2403. TWSocket = class(TCustomThrottledWSocket)
  2404. {$ELSE}
  2405. {$IFDEF BUILTIN_TIMEOUT}
  2406. TWSocket = class(TCustomTimeoutWSocket)
  2407. {$ELSE}
  2408. TWSocket = class(TCustomSyncWSocket)
  2409. {$ENDIF}
  2410. {$ENDIF}
  2411. public
  2412. property PortNum;
  2413. property Handle;
  2414. property HSocket;
  2415. property BufSize;
  2416. property Text;
  2417. property AllSent;
  2418. {$IFDEF DELPHI1}
  2419. property TrumpetCompability;
  2420. {$ENDIF}
  2421. property PeerAddr;
  2422. property PeerPort;
  2423. property State;
  2424. property DnsResult;
  2425. property DnsResultList;
  2426. property ReadCount;
  2427. property RcvdCount;
  2428. property SocketRcvBufSize; {AG 03/10/07}
  2429. property SocketSndBufSize; {AG 03/10/07}
  2430. property OnDebugDisplay;
  2431. property Counter;
  2432. published
  2433. property Addr;
  2434. property Port;
  2435. property Proto;
  2436. property LocalAddr;
  2437. property LocalPort;
  2438. property MultiThreaded;
  2439. property MultiCast;
  2440. property MultiCastAddrStr;
  2441. property MultiCastIpTTL;
  2442. property FlushTimeout;
  2443. property SendFlags;
  2444. property LingerOnOff;
  2445. property LingerTimeout;
  2446. property KeepAliveOnOff;
  2447. property KeepAliveTime;
  2448. property KeepAliveInterval;
  2449. property SocksLevel;
  2450. property SocksServer;
  2451. property SocksPort;
  2452. property SocksUsercode;
  2453. property SocksPassword;
  2454. property SocksAuthentication;
  2455. property LastError;
  2456. property ReuseAddr;
  2457. property ComponentOptions;
  2458. property ListenBacklog;
  2459. property ReqVerLow;
  2460. property ReqVerHigh;
  2461. property OnDataAvailable;
  2462. property OnDataSent;
  2463. property OnSendData;
  2464. property OnSessionClosed;
  2465. property OnSessionAvailable;
  2466. property OnSessionConnected;
  2467. property OnSocksConnected;
  2468. property OnChangeState;
  2469. { property OnLineTooLong; }
  2470. property OnDnsLookupDone;
  2471. property OnError;
  2472. property OnBgException;
  2473. property OnSocksError;
  2474. property OnSocksAuthState;
  2475. {$IFNDEF NO_DEBUG_LOG}
  2476. property IcsLogger; { V5.21 }
  2477. {$ENDIF}
  2478. end;
  2479. TSocksWSocket = class(TWSocket)
  2480. end;
  2481. { You must define USE_SSL so that SSL code is included in the component. }
  2482. { Either in OverbyteIcsDefs.inc or in the project/package options. }
  2483. {$IFDEF USE_SSL}
  2484. TSslWSocket = class(TWSocket)
  2485. public
  2486. property SslVersion;
  2487. property SslCipher;
  2488. property SslTotalBits;
  2489. property SslSecretBits;
  2490. property X509Class;
  2491. //property SslEstablished;
  2492. property SslState;
  2493. {$IFNDEF OPENSSL_NO_TLSEXT}
  2494. property SslServerName;
  2495. property OnSslServerName;
  2496. {$ENDIF}
  2497. published
  2498. {$IFNDEF NO_DEBUG_LOG}
  2499. property IcsLogger; { V5.21 }
  2500. {$ENDIF}
  2501. property SslContext;
  2502. property SslEnable;
  2503. property SslAcceptableHosts;
  2504. property SslMode;
  2505. property OnSslVerifyPeer;
  2506. property OnSslHandshakeDone;
  2507. property OnSslCliGetSession;
  2508. property OnSslCliNewSession;
  2509. property OnSslSvrNewSession;
  2510. property OnSslSvrGetSession;
  2511. property OnSslSetSessionIDContext;
  2512. property OnSslShutDownComplete;
  2513. property OnSslCliCertRequest;
  2514. end;
  2515. {$ENDIF}
  2516. function HasOption(OptSet : TWSocketOptions; Opt : TWSocketOption) : Boolean;
  2517. function RemoveOption(OptSet : TWSocketOptions; Opt : TWSocketOption) : TWSocketOptions;
  2518. function AddOptions(Opts: array of TWSocketOption): TWSocketOptions;
  2519. function WinsockInfo : TWSADATA;
  2520. function WSocketErrorDesc(ErrCode: Integer) : String;
  2521. function GetWinsockErr(ErrCode: Integer) : String;
  2522. function GetWindowsErr(ErrCode: Integer): String;
  2523. {$IFDEF CLR}
  2524. function WSocketGetHostByAddr(const Addr : String) : IntPtr;
  2525. function WSocketGetHostByName(const Name : String) : IntPtr;
  2526. {$ENDIF}
  2527. {$IFDEF WIN32}
  2528. function WSocketGetHostByAddr(Addr : AnsiString) : PHostEnt;
  2529. function WSocketGetHostByName(Name : AnsiString) : PHostEnt;
  2530. {$ENDIF}
  2531. function LocalHostName : AnsiString;
  2532. function LocalIPList : TStrings;
  2533. function WSocketResolveIp(IpAddr : AnsiString) : AnsiString;
  2534. function WSocketResolveHost(InAddr : AnsiString) : TInAddr;
  2535. function WSocketResolvePort(Port : AnsiString; Proto : AnsiString) : Word;
  2536. function WSocketResolveProto(sProto : AnsiString) : Integer;
  2537. procedure WSocketForceLoadWinsock;
  2538. procedure WSocketCancelForceLoadWinsock;
  2539. procedure WSocketUnloadWinsock;
  2540. function WSocketIsDottedIP(const S : AnsiString) : Boolean;
  2541. { function WSocketLoadWinsock : Boolean; 14/02/99 }
  2542. {$IFDEF DELPHI1}
  2543. type
  2544. DWORD = LongInt;
  2545. TWSAStartup = function (wVersionRequired: word;
  2546. var WSData: TWSAData): Integer;
  2547. TWSACleanup = function : Integer;
  2548. TWSASetLastError = procedure (iError: Integer);
  2549. TWSAGetLastError = function : Integer;
  2550. TWSACancelAsyncRequest = function (hAsyncTaskHandle: THandle): Integer;
  2551. TWSAAsyncGetHostByName = function (HWindow: HWND;
  2552. wMsg: u_int;
  2553. name, buf: PChar;
  2554. buflen: Integer): THandle;
  2555. TWSAAsyncGetHostByAddr = function (HWindow: HWND;
  2556. wMsg: u_int; addr: PChar;
  2557. len, Struct: Integer;
  2558. buf: PChar;
  2559. buflen: Integer): THandle;
  2560. TWSAAsyncSelect = function (s: TSocket;
  2561. HWindow: HWND;
  2562. wMsg: u_int;
  2563. lEvent: Longint): Integer;
  2564. TGetServByName = function (name, proto: PChar): PServEnt;
  2565. TGetProtoByName = function (name: PChar): PProtoEnt;
  2566. TGetHostByName = function (name: PChar): PHostEnt;
  2567. TGetHostByAddr = function (addr: Pointer; len, Struct: Integer): PHostEnt;
  2568. TGetHostName = function (name: PChar; len: Integer): Integer;
  2569. TOpenSocket = function (af, Struct, protocol: Integer): TSocket;
  2570. TShutdown = function (s: TSocket; how: Integer): Integer;
  2571. TSetSockOpt = function (s: TSocket; level, optname: Integer;
  2572. optval: PChar;
  2573. optlen: Integer): Integer;
  2574. TGetSockOpt = function (s: TSocket; level, optname: Integer; optval: PChar; var optlen: Integer): Integer;
  2575. TSendTo = function (s: TSocket; var Buf;
  2576. len, flags: Integer;
  2577. var addrto: TSockAddr;
  2578. tolen: Integer): Integer;
  2579. TSend = function (s: TSocket; var Buf;
  2580. len, flags: Integer): Integer;
  2581. TRecv = function (s: TSocket;
  2582. var Buf;
  2583. len, flags: Integer): Integer;
  2584. TRecvFrom = function (s: TSocket;
  2585. var Buf; len, flags: Integer;
  2586. var from: TSockAddr;
  2587. var fromlen: Integer): Integer;
  2588. Tntohs = function (netshort: u_short): u_short;
  2589. Tntohl = function (netlong: u_long): u_long;
  2590. TListen = function (s: TSocket; backlog: Integer): Integer;
  2591. TIoctlSocket = function (s: TSocket; cmd: DWORD;
  2592. var arg: u_long): Integer;
  2593. TInet_ntoa = function (inaddr: TInAddr): PChar;
  2594. TInet_addr = function (cp: PChar): u_long;
  2595. Thtons = function (hostshort: u_short): u_short;
  2596. Thtonl = function (hostlong: u_long): u_long;
  2597. TGetSockName = function (s: TSocket; var name: TSockAddr;
  2598. var namelen: Integer): Integer;
  2599. TGetPeerName = function (s: TSocket; var name: TSockAddr;
  2600. var namelen: Integer): Integer;
  2601. TConnect = function (s: TSocket; var name: TSockAddr;
  2602. namelen: Integer): Integer;
  2603. TCloseSocket = function (s: TSocket): Integer;
  2604. TBind = function (s: TSocket; var addr: TSockAddr;
  2605. namelen: Integer): Integer;
  2606. TAccept = function (s: TSocket; var addr: TSockAddr;
  2607. var addrlen: Integer): TSocket;
  2608. {$ELSE}
  2609. {$IFDEF WIN32} // DotNET doesn't support dynamic winsock loading
  2610. type
  2611. TWSAStartup = function (wVersionRequired: word;
  2612. var WSData: TWSAData): Integer; stdcall;
  2613. TWSACleanup = function : Integer; stdcall;
  2614. TWSASetLastError = procedure (iError: Integer); stdcall;
  2615. TWSAGetLastError = function : Integer; stdcall;
  2616. TWSACancelAsyncRequest = function (hAsyncTaskHandle: THandle): Integer; stdcall;
  2617. TWSAAsyncGetHostByName = function (HWindow: HWND;
  2618. wMsg: u_int;
  2619. name, buf: PAnsiChar;
  2620. buflen: Integer): THandle; stdcall;
  2621. TWSAAsyncGetHostByAddr = function (HWindow: HWND;
  2622. wMsg: u_int; addr: PAnsiChar;
  2623. len, Struct: Integer;
  2624. buf: PAnsiChar;
  2625. buflen: Integer): THandle; stdcall;
  2626. TWSAAsyncSelect = function (s: TSocket;
  2627. HWindow: HWND;
  2628. wMsg: u_int;
  2629. lEvent: Longint): Integer; stdcall;
  2630. TGetServByName = function (name, proto: PAnsiChar): PServEnt; stdcall;
  2631. TGetProtoByName = function (name: PAnsiChar): PProtoEnt; stdcall;
  2632. TGetHostByName = function (name: PAnsiChar): PHostEnt; stdcall;
  2633. TGetHostByAddr = function (addr: Pointer; len, Struct: Integer): PHostEnt; stdcall;
  2634. TGetHostName = function (name: PAnsiChar; len: Integer): Integer; stdcall;
  2635. TOpenSocket = function (af, Struct, protocol: Integer): TSocket; stdcall;
  2636. TShutdown = function (s: TSocket; how: Integer): Integer; stdcall;
  2637. TSetSockOpt = function (s: TSocket; level, optname: Integer;
  2638. optval: PAnsiChar;
  2639. optlen: Integer): Integer; stdcall;
  2640. TGetSockOpt = function (s: TSocket; level, optname: Integer;
  2641. optval: PAnsiChar;
  2642. var optlen: Integer): Integer; stdcall;
  2643. TSendTo = function (s: TSocket; var Buf;
  2644. len, flags: Integer;
  2645. var addrto: TSockAddr;
  2646. tolen: Integer): Integer; stdcall;
  2647. TSend = function (s: TSocket; var Buf;
  2648. len, flags: Integer): Integer; stdcall;
  2649. TRecv = function (s: TSocket;
  2650. var Buf;
  2651. len, flags: Integer): Integer; stdcall;
  2652. TRecvFrom = function (s: TSocket;
  2653. var Buf; len, flags: Integer;
  2654. var from: TSockAddr;
  2655. var fromlen: Integer): Integer; stdcall;
  2656. Tntohs = function (netshort: u_short): u_short; stdcall;
  2657. Tntohl = function (netlong: u_long): u_long; stdcall;
  2658. TListen = function (s: TSocket;
  2659. backlog: Integer): Integer; stdcall;
  2660. TIoctlSocket = function (s: TSocket; cmd: DWORD;
  2661. var arg: u_long): Integer; stdcall;
  2662. TWSAIoctl = function (s : TSocket;
  2663. IoControlCode : DWORD;
  2664. InBuffer : Pointer;
  2665. InBufferSize : DWORD;
  2666. OutBuffer : Pointer;
  2667. OutBufferSize : DWORD;
  2668. var BytesReturned : DWORD;
  2669. Overlapped : POverlapped;
  2670. CompletionRoutine : FARPROC): Integer; stdcall;
  2671. TInet_ntoa = function (inaddr: TInAddr): PAnsiChar; stdcall;
  2672. TInet_addr = function (cp: PAnsiChar): u_long; stdcall;
  2673. Thtons = function (hostshort: u_short): u_short; stdcall;
  2674. Thtonl = function (hostlong: u_long): u_long; stdcall;
  2675. TGetSockName = function (s: TSocket; var name: TSockAddr;
  2676. var namelen: Integer): Integer; stdcall;
  2677. TGetPeerName = function (s: TSocket; var name: TSockAddr;
  2678. var namelen: Integer): Integer; stdcall;
  2679. TConnect = function (s: TSocket; var name: TSockAddr;
  2680. namelen: Integer): Integer; stdcall;
  2681. TCloseSocket = function (s: TSocket): Integer; stdcall;
  2682. TBind = function (s: TSocket; var addr: TSockAddr;
  2683. namelen: Integer): Integer; stdcall;
  2684. {$IFDEF VER90} { Delphi 2 has a special definition}
  2685. TAccept = function (s: TSocket; var addr: TSockAddr;
  2686. var addrlen: Integer): TSocket; stdcall;
  2687. {$ELSE}
  2688. TAccept = function (s: TSocket; addr: PSockAddr;
  2689. addrlen: PInteger): TSocket; stdcall;
  2690. {$ENDIF}
  2691. {$ENDIF}
  2692. {$ENDIF}
  2693. {$IFDEF WIN32} // DotNET doesn't support dynamic winsock loading
  2694. var
  2695. FWSAStartup : TWSAStartup;
  2696. FWSACleanup : TWSACleanup;
  2697. FWSASetLastError : TWSASetLastError;
  2698. FWSAGetLastError : TWSAGetLastError;
  2699. FWSACancelAsyncRequest : TWSACancelAsyncRequest;
  2700. FWSAAsyncGetHostByName : TWSAAsyncGetHostByName;
  2701. FWSAAsyncGetHostByAddr : TWSAAsyncGetHostByAddr;
  2702. FWSAAsyncSelect : TWSAAsyncSelect;
  2703. FGetServByName : TGetServByName;
  2704. FGetProtoByName : TGetProtoByName;
  2705. FGetHostByName : TGetHostByName;
  2706. FGetHostByAddr : TGetHostByAddr;
  2707. FGetHostName : TGetHostName;
  2708. FOpenSocket : TOpenSocket;
  2709. FShutdown : TShutdown;
  2710. FSetSockOpt : TSetSockOpt;
  2711. FGetSockOpt : TGetSockOpt;
  2712. FSendTo : TSendTo;
  2713. FSend : TSend;
  2714. FRecv : TRecv;
  2715. FRecvFrom : TRecvFrom;
  2716. Fntohs : Tntohs;
  2717. Fntohl : Tntohl;
  2718. FListen : TListen;
  2719. FIoctlSocket : TIoctlSocket;
  2720. {$IFDEF COMPILER2_UP}
  2721. FWSAIoctl : TWSAIoctl;
  2722. {$ENDIF}
  2723. FInet_ntoa : TInet_ntoa;
  2724. FInet_addr : TInet_addr;
  2725. Fhtons : Thtons;
  2726. Fhtonl : Thtonl;
  2727. FGetSockName : TGetSockName;
  2728. FGetPeerName : TGetPeerName;
  2729. FConnect : TConnect;
  2730. FCloseSocket : TCloseSocket;
  2731. FBind : TBind;
  2732. FAccept : TAccept;
  2733. function WSocketGetProc(const ProcName : AnsiString) : Pointer;
  2734. {$IFDEF COMPILER2_UP}
  2735. function WSocket2GetProc(const ProcName : AnsiString) : Pointer;
  2736. {$ENDIF}
  2737. {$ENDIF}
  2738. function WSocket_WSAStartup(wVersionRequired: word;
  2739. var WSData: TWSAData): Integer;
  2740. function WSocket_WSACleanup : Integer;
  2741. procedure WSocket_WSASetLastError(iError: Integer);
  2742. function WSocket_WSAGetLastError: Integer;
  2743. function WSocket_WSACancelAsyncRequest(hAsyncTaskHandle: THandle): Integer;
  2744. {$IFDEF CLR}
  2745. function WSocket_WSAAsyncGetHostByName(HWindow: HWND; wMsg: u_int;
  2746. const name : String; buf: IntPtr;
  2747. buflen: Integer): THandle;
  2748. function WSocket_WSAAsyncGetHostByAddr(HWindow: HWND;
  2749. wMsg: u_int; var addr: u_long;
  2750. len, Struct: Integer;
  2751. buf: IntPtr;
  2752. buflen: Integer): THandle;
  2753. {$ENDIF}
  2754. {$IFDEF WIN32}
  2755. function WSocket_WSAAsyncGetHostByName(HWindow: HWND; wMsg: u_int;
  2756. name, buf: PAnsiChar;
  2757. buflen: Integer): THandle;
  2758. function WSocket_WSAAsyncGetHostByAddr(HWindow: HWND;
  2759. wMsg: u_int; addr: PAnsiChar;
  2760. len, Struct: Integer;
  2761. buf: PAnsiChar;
  2762. buflen: Integer): THandle;
  2763. {$ENDIF}
  2764. function WSocket_WSAAsyncSelect(s: TSocket; HWindow: HWND; wMsg: u_int; lEvent: Longint): Integer;
  2765. function WSocket_recv(s: TSocket;
  2766. var Buf: TWSocketData; len, flags: Integer): Integer;
  2767. function WSocket_recvfrom(s: TSocket;
  2768. var Buf: TWSocketData; len, flags: Integer;
  2769. var from: TSockAddr;
  2770. var fromlen: Integer): Integer;
  2771. {$IFDEF CLR}
  2772. function WSocket_getservbyname(const name, proto: String): IntPtr;
  2773. function WSocket_getprotobyname(const name: String): IntPtr;
  2774. function WSocket_gethostbyname(const name: String): IntPtr;
  2775. function WSocket_gethostbyaddr(var addr: u_long; len, Struct: Integer): IntPtr;
  2776. {$ENDIF}
  2777. {$IFDEF WIN32}
  2778. function WSocket_getservbyname(name, proto: PAnsiChar): PServEnt;
  2779. function WSocket_getprotobyname(name: PAnsiChar): PProtoEnt;
  2780. function WSocket_gethostbyname(name: PAnsiChar): PHostEnt;
  2781. function WSocket_gethostbyaddr(addr: Pointer; len, Struct: Integer): PHostEnt;
  2782. {$ENDIF}
  2783. function WSocket_gethostname(out name: AnsiString): Integer;
  2784. function WSocket_socket(af, Struct, protocol: Integer): TSocket;
  2785. function WSocket_shutdown(s: TSocket; how: Integer): Integer;
  2786. {$IFDEF CLR}
  2787. function WSocket_getsockopt(s: TSocket; level, optname: Integer;
  2788. var optval: Integer;
  2789. var optlen: Integer): Integer; overload;
  2790. function WSocket_getsockopt(s: TSocket; level, optname: Integer;
  2791. var optval: ip_mreq;
  2792. var optlen: Integer): Integer; overload;
  2793. function WSocket_getsockopt(s: TSocket; level, optname: Integer;
  2794. var optval: TInAddr;
  2795. var optlen: Integer): Integer; overload;
  2796. function WSocket_getsockopt(s: TSocket; level, optname: Integer;
  2797. var optval: TLinger;
  2798. var optlen: Integer): Integer; overload;
  2799. {$ENDIF}
  2800. {$IFDEF WIN32}
  2801. function WSocket_setsockopt(s: TSocket; level, optname: Integer; optval: PAnsiChar;
  2802. optlen: Integer): Integer; overload;
  2803. function WSocket_setsockopt(s: TSocket; level, optname: Integer; var optval: TLinger;
  2804. optlen: Integer): Integer; overload;
  2805. function WSocket_getsockopt(s: TSocket; level, optname: Integer; optval: PAnsiChar;
  2806. var optlen: Integer): Integer;
  2807. {$ENDIF}
  2808. function WSocket_sendto(s: TSocket; var Buf : TWSocketData; len, flags: Integer;
  2809. var addrto: TSockAddr;
  2810. tolen: Integer): Integer;
  2811. function WSocket_send(s: TSocket; var Buf : TWSocketData; len, flags: Integer): Integer;
  2812. function WSocket_ntohs(netshort: u_short): u_short;
  2813. function WSocket_ntohl(netlong: u_long): u_long;
  2814. function WSocket_listen(s: TSocket; backlog: Integer): Integer;
  2815. function WSocket_ioctlsocket(s: TSocket; cmd: DWORD; var arg: u_long): Integer;
  2816. {$IFNDEF VER80}
  2817. {$IFDEF WIN32}
  2818. function WSocket_WSAIoctl(s : TSocket; IoControlCode : DWORD;
  2819. InBuffer : Pointer; InBufferSize : DWORD;
  2820. OutBuffer : Pointer; OutBufferSize : DWORD;
  2821. var BytesReturned : DWORD; Overlapped : POverlapped;
  2822. CompletionRoutine : FARPROC): Integer;
  2823. {$ENDIF}
  2824. {$ENDIF}
  2825. function WSocket_inet_ntoa(inaddr: TInAddr): AnsiString;
  2826. function WSocket_inet_addr(const cp: AnsiString): u_long;
  2827. function WSocket_htons(hostshort: u_short): u_short;
  2828. function WSocket_htonl(hostlong: u_long): u_long;
  2829. function WSocket_getsockname(s: TSocket; var name: TSockAddr;
  2830. var namelen: Integer): Integer;
  2831. function WSocket_getpeername(s: TSocket; var name: TSockAddr;
  2832. var namelen: Integer): Integer;
  2833. function WSocket_connect(s: TSocket; var name: TSockAddr;
  2834. namelen: Integer): Integer;
  2835. function WSocket_closesocket(s: TSocket): Integer;
  2836. function WSocket_bind(s: TSocket; var addr: TSockAddr; namelen: Integer): Integer;
  2837. {$IFDEF DELPHI1}
  2838. function WSocket_accept(s: TSocket; var addr: TSockAddr; var addrlen: Integer): TSocket;
  2839. {$ELSE}
  2840. {$IFDEF VER90}
  2841. function WSocket_accept(s: TSocket; var addr: TSockAddr; var addrlen: Integer): TSocket;
  2842. {$ELSE}
  2843. {$IFDEF CLR}
  2844. function WSocket_accept(s: TSocket; var addr: TSockAddr; var addrlen: Integer): TSocket;
  2845. {$ENDIF}
  2846. {$IFDEF WIN32}
  2847. function WSocket_accept(s: TSocket; addr: PSockAddr; addrlen: PInteger): TSocket;
  2848. {$ENDIF}
  2849. {$ENDIF}
  2850. {$ENDIF}
  2851. {$IFNDEF NO_ADV_MT}
  2852. function SafeWSocketGCount : Integer;
  2853. {$ENDIF}
  2854. {$IFDEF USE_SSL}
  2855. function OpenSslErrMsg(const AErrCode: LongWord): String;
  2856. {$ENDIF}
  2857. const
  2858. WSocketGCount : Integer = 0;
  2859. WSocketGForced : boolean = FALSE;
  2860. GReqVerLow : BYTE = 1;
  2861. GReqVerHigh : BYTE = 1;
  2862. {$EXTERNALSYM IOC_UNIX}
  2863. IOC_UNIX = $00000000; { Do not use this in Windows }
  2864. { IOCPARM_MASK = $000007F7; } { Parameters must be < 128 bytes }
  2865. {$EXTERNALSYM IOC_WS2}
  2866. IOC_WS2 = $08000000;
  2867. {$EXTERNALSYM IOC_PROTOCOL}
  2868. IOC_PROTOCOL = $10000000;
  2869. { IOC_VOID = $20000000; } { No parameters }
  2870. { IOC_OUT = $40000000; } { Copy out parameters }
  2871. {$EXTERNALSYM IOC_IN}
  2872. IOC_IN = $80000000; { Copy in parameters }
  2873. { IOC_INOUT = (IOC_IN or IOC_OUT); }
  2874. {$EXTERNALSYM IOC_VENDOR}
  2875. IOC_VENDOR = $18000000;
  2876. SIO_RCVALL = IOC_IN or IOC_VENDOR or 1;
  2877. SIO_RCVALL_MCAST = IOC_IN or IOC_VENDOR or 2;
  2878. SIO_RCVALL_IGMPMCAST = IOC_IN or IOC_VENDOR or 3;
  2879. SIO_KEEPALIVE_VALS = IOC_IN or IOC_VENDOR or 4;
  2880. SIO_ABSORB_RTRALERT = IOC_IN or IOC_VENDOR or 5;
  2881. SIO_UCAST_IF = IOC_IN or IOC_VENDOR or 6;
  2882. SIO_LIMIT_BROADCASTS = IOC_IN or IOC_VENDOR or 7;
  2883. SIO_INDEX_BIND = IOC_IN or IOC_VENDOR or 8;
  2884. SIO_INDEX_MCASTIF = IOC_IN or IOC_VENDOR or 9;
  2885. SIO_INDEX_ADD_MCAST = IOC_IN or IOC_VENDOR or 10;
  2886. SIO_INDEX_DEL_MCAST = IOC_IN or IOC_VENDOR or 11;
  2887. {$IFNDEF NO_DEBUG_LOG}
  2888. var
  2889. __DataSocket : TCustomWSocket;
  2890. {$ENDIF}
  2891. implementation
  2892. { R 'OverbyteIcsWSocket.TWSocket.bmp'}
  2893. const
  2894. FDllHandle : THandle = 0;
  2895. FDll2Handle : THandle = 0;
  2896. socksNoError = 20000;
  2897. socksProtocolError = 20001;
  2898. socksVersionError = 20002;
  2899. socksAuthMethodError = 20003;
  2900. socksGeneralFailure = 20004;
  2901. socksConnectionNotAllowed = 20005;
  2902. socksNetworkUnreachable = 20006;
  2903. socksHostUnreachable = 20007;
  2904. socksConnectionRefused = 20008;
  2905. socksTtlExpired = 20009;
  2906. socksUnknownCommand = 20010;
  2907. socksUnknownAddressType = 20011;
  2908. socksUnassignedError = 20012;
  2909. socksInternalError = 20013;
  2910. socksDataReceiveError = 20014;
  2911. socksAuthenticationFailed = 20015;
  2912. socksRejectedOrFailed = 20016;
  2913. socksHostResolutionFailed = 20017;
  2914. {$IFDEF DELPHI1}
  2915. IP_DEFAULT_MULTICAST_TTL = 1;
  2916. IP_MULTICAST_IF = 2;
  2917. IP_MULTICAST_TTL = 3;
  2918. IP_MULTICAST_LOOP = 4;
  2919. IP_ADD_MEMBERSHIP = 5;
  2920. IP_DROP_MEMBERSHIP = 6;
  2921. type
  2922. in_addr = TInAddr;
  2923. {$ENDIF}
  2924. {$IFNDEF DELPHI1}
  2925. {$IFNDEF COMPILER4_UP}
  2926. type
  2927. in_addr = TInAddr;
  2928. {$ENDIF}
  2929. {$ENDIF}
  2930. var
  2931. GInitData : TWSADATA;
  2932. IPList : TStrings;
  2933. {$IFDEF CLR}
  2934. GWSAStartupCalled : Boolean = FALSE;
  2935. {$ENDIF}
  2936. {$IFDEF COMPILER2_UP}
  2937. GClassCritSect : TRTLCriticalSection;
  2938. GWSockCritSect : TRTLCriticalSection;
  2939. // V6.01 moved GSendBufCritSect to OverbyteIcsWSocket.pas
  2940. // GSendBufCritSect : TRTLCriticalSection; { v6.00f }
  2941. {$ENDIF}
  2942. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  2943. {$IFDEF DELPHI1}
  2944. { Delphi 1 miss the SetLength procedure. So we rewrite it. }
  2945. procedure SetLength(var S: String; NewLength: Integer);
  2946. begin
  2947. S[0] := chr(NewLength);
  2948. end;
  2949. {$ENDIF}
  2950. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  2951. function IsDigit(Ch : AnsiChar) : Boolean;
  2952. begin
  2953. Result := (ch >= '0') and (ch <= '9');
  2954. end;
  2955. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  2956. { Check for a valid numeric dotted IP address such as 192.161.65.25 }
  2957. { Accept leading and trailing spaces. }
  2958. function WSocketIsDottedIP(const S : AnsiString) : Boolean;
  2959. var
  2960. I : Integer;
  2961. DotCount : Integer;
  2962. NumVal : Integer;
  2963. begin
  2964. Result := FALSE;
  2965. DotCount := 0;
  2966. NumVal := 0;
  2967. I := 1;
  2968. { Skip leading spaces }
  2969. while (I <= Length(S)) and (S[I] = ' ') do
  2970. Inc(I);
  2971. { Can't begin with a dot }
  2972. if (I <= Length(S)) and (S[I] = '.') then
  2973. Exit;
  2974. { Scan full string }
  2975. while I <= Length(S) do begin
  2976. if S[I] = '.' then begin
  2977. Inc(DotCount);
  2978. if (DotCount > 3) or (NumVal > 255) then
  2979. Exit;
  2980. NumVal := 0;
  2981. { A dot must be followed by a digit }
  2982. if (I >= Length(S)) or (not (AnsiChar(S[I + 1]) in ['0'..'9'])) then
  2983. Exit;
  2984. end
  2985. else if AnsiChar(S[I]) in ['0'..'9'] then
  2986. NumVal := NumVal * 10 + Ord(S[I]) - Ord('0')
  2987. else begin
  2988. { Not a digit nor a dot. Accept spaces until end of string }
  2989. while (I <= Length(S)) and (S[I] = ' ') do
  2990. Inc(I);
  2991. if I <= Length(S) then
  2992. Exit; { Not a space, do not accept }
  2993. break; { Only spaces, accept }
  2994. end;
  2995. Inc(I);
  2996. end;
  2997. { We must have exactly 3 dots }
  2998. if (DotCount <> 3) or (NumVal > 255) then
  2999. Exit;
  3000. Result := TRUE;
  3001. end;
  3002. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3003. {$IFDEF DELPHI1}
  3004. function TrimRight(Str : String) : String;
  3005. var
  3006. i : Integer;
  3007. begin
  3008. i := Length(Str);
  3009. while (i > 0) and (Str[i] in [' ', #9]) do
  3010. i := i - 1;
  3011. Result := Copy(Str, 1, i);
  3012. end;
  3013. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3014. function TrimLeft(Str : String) : String;
  3015. var
  3016. i : Integer;
  3017. begin
  3018. if Str[1] <> ' ' then
  3019. Result := Str
  3020. else begin
  3021. i := 1;
  3022. while (i <= Length(Str)) and (Str[i] = ' ') do
  3023. i := i + 1;
  3024. Result := Copy(Str, i, Length(Str) - i + 1);
  3025. end;
  3026. end;
  3027. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3028. function Trim(Str : String) : String;
  3029. begin
  3030. Result := TrimLeft(TrimRight(Str));
  3031. end;
  3032. {$ENDIF}
  3033. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3034. procedure TCustomWSocket.RaiseException(const Msg : String);
  3035. begin
  3036. if Assigned(FOnError) then
  3037. TriggerError { Should be modified to pass Msg ! }
  3038. else
  3039. raise ESocketException.Create(Msg);
  3040. end;
  3041. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3042. //procedure TCustomWSocket.RaiseExceptionFmt(const Fmt : String; args : array of const);
  3043. //begin
  3044. // if Assigned(FOnError) then
  3045. // TriggerError
  3046. // else
  3047. // raise ESocketException.CreateFmt(Fmt, args);
  3048. //end;
  3049. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3050. {$IFDEF WIN32}
  3051. function WSocket_Synchronized_WSAStartup(
  3052. wVersionRequired: word;
  3053. var WSData: TWSAData): Integer;
  3054. begin
  3055. if @FWSAStartup = nil then
  3056. @FWSAStartup := WSocketGetProc('WSAStartup');
  3057. Result := FWSAStartup(wVersionRequired, WSData);
  3058. end;
  3059. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3060. function WSocket_Synchronized_WSACleanup : Integer;
  3061. begin
  3062. if @FWSACleanup = nil then
  3063. @FWSACleanup := WSocketGetProc('WSACleanup');
  3064. Result := FWSACleanup;
  3065. end;
  3066. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3067. procedure WSocket_Synchronized_WSASetLastError(iError: Integer);
  3068. begin
  3069. if @FWSASetLastError = nil then
  3070. @FWSASetLastError := WSocketGetProc('WSASetLastError');
  3071. FWSASetLastError(iError);
  3072. end;
  3073. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3074. function WSocket_Synchronized_WSAGetLastError: Integer;
  3075. begin
  3076. if @FWSAGetLastError = nil then
  3077. @FWSAGetLastError := WSocketGetProc('WSAGetLastError');
  3078. Result := FWSAGetLastError;
  3079. end;
  3080. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3081. function WSocket_Synchronized_WSACancelAsyncRequest(hAsyncTaskHandle: THandle): Integer;
  3082. begin
  3083. if @FWSACancelAsyncRequest = nil then
  3084. @FWSACancelAsyncRequest := WSocketGetProc('WSACancelAsyncRequest');
  3085. Result := FWSACancelAsyncRequest(hAsyncTaskHandle);
  3086. end;
  3087. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3088. function WSocket_Synchronized_WSAAsyncGetHostByName(
  3089. HWindow: HWND; wMsg: u_int;
  3090. name, buf: PAnsiChar;
  3091. buflen: Integer): THandle;
  3092. begin
  3093. if @FWSAAsyncGetHostByName = nil then
  3094. @FWSAAsyncGetHostByName := WSocketGetProc('WSAAsyncGetHostByName');
  3095. Result := FWSAAsyncGetHostByName(HWindow, wMsg, name, buf, buflen);
  3096. end;
  3097. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3098. function WSocket_Synchronized_WSAAsyncGetHostByAddr(
  3099. HWindow: HWND;
  3100. wMsg: u_int; addr: PAnsiChar;
  3101. len, Struct: Integer;
  3102. buf: PAnsiChar;
  3103. buflen: Integer): THandle;
  3104. begin
  3105. if @FWSAAsyncGetHostByAddr = nil then
  3106. @FWSAAsyncGetHostByAddr := WSocketGetProc('WSAAsyncGetHostByAddr');
  3107. Result := FWSAAsyncGetHostByAddr(HWindow, wMsg, addr, len, struct, buf, buflen);
  3108. end;
  3109. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3110. function WSocket_Synchronized_WSAAsyncSelect(
  3111. s: TSocket;
  3112. HWindow: HWND;
  3113. wMsg: u_int;
  3114. lEvent: Longint): Integer;
  3115. begin
  3116. if @FWSAAsyncSelect = nil then
  3117. @FWSAAsyncSelect := WSocketGetProc('WSAAsyncSelect');
  3118. Result := FWSAAsyncSelect(s, HWindow, wMsg, lEvent);
  3119. end;
  3120. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3121. function WSocket_Synchronized_getservbyname(name, proto: PAnsiChar): PServEnt;
  3122. begin
  3123. if @Fgetservbyname = nil then
  3124. @Fgetservbyname := WSocketGetProc('getservbyname');
  3125. Result := Fgetservbyname(name, proto);
  3126. end;
  3127. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3128. function WSocket_Synchronized_getprotobyname(const Name: AnsiString): PProtoEnt;
  3129. begin
  3130. if @Fgetprotobyname = nil then
  3131. @Fgetprotobyname := WSocketGetProc('getprotobyname');
  3132. Result := Fgetprotobyname(PAnsiChar(Name));
  3133. end;
  3134. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3135. function WSocket_Synchronized_gethostbyname(name: PAnsiChar): PHostEnt;
  3136. begin
  3137. if @Fgethostbyname = nil then
  3138. @Fgethostbyname := WSocketGetProc('gethostbyname');
  3139. Result := Fgethostbyname(name);
  3140. end;
  3141. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3142. function WSocket_Synchronized_gethostbyaddr(addr: Pointer; len, Struct: Integer): PHostEnt;
  3143. begin
  3144. if @Fgethostbyaddr = nil then
  3145. @Fgethostbyaddr := WSocketGetProc('gethostbyaddr');
  3146. Result := Fgethostbyaddr(addr, len, Struct);
  3147. end;
  3148. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3149. function WSocket_Synchronized_gethostname(name: PAnsiChar; len: Integer): Integer;
  3150. begin
  3151. if @Fgethostname = nil then
  3152. @Fgethostname := WSocketGetProc('gethostname');
  3153. Result := Fgethostname(name, len);
  3154. end;
  3155. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3156. function WSocket_Synchronized_socket(af, Struct, protocol: Integer): TSocket;
  3157. begin
  3158. if @FOpenSocket= nil then
  3159. @FOpenSocket := WSocketGetProc('socket');
  3160. Result := FOpenSocket(af, Struct, protocol);
  3161. end;
  3162. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3163. function WSocket_Synchronized_shutdown(s: TSocket; how: Integer): Integer;
  3164. begin
  3165. if @FShutdown = nil then
  3166. @FShutdown := WSocketGetProc('shutdown');
  3167. Result := FShutdown(s, how);
  3168. end;
  3169. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3170. function WSocket_Synchronized_setsockopt(s: TSocket; level, optname: Integer; optval: PAnsiChar;
  3171. optlen: Integer): Integer; overload;
  3172. begin
  3173. if @FSetSockOpt = nil then
  3174. @FSetSockOpt := WSocketGetProc('setsockopt');
  3175. Result := FSetSockOpt(s, level, optname, optval, optlen);
  3176. end;
  3177. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3178. function WSocket_Synchronized_setsockopt(s: TSocket; level, optname: Integer; var optval: TLinger;
  3179. optlen: Integer): Integer; overload;
  3180. begin
  3181. if @FSetSockOpt = nil then
  3182. @FSetSockOpt := WSocketGetProc('setsockopt');
  3183. Result := FSetSockOpt(s, level, optname, @optval, optlen);
  3184. end;
  3185. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3186. function WSocket_Synchronized_setsockopt(s: TSocket; level, optname: Integer; var optval: ip_mreq;
  3187. optlen: Integer): Integer; overload;
  3188. begin
  3189. if @FSetSockOpt = nil then
  3190. @FSetSockOpt := WSocketGetProc('setsockopt');
  3191. Result := FSetSockOpt(s, level, optname, @optval, optlen);
  3192. end;
  3193. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3194. function WSocket_Synchronized_setsockopt(s: TSocket; level, optname: Integer; var optval: Integer;
  3195. optlen: Integer): Integer; overload;
  3196. begin
  3197. if @FSetSockOpt = nil then
  3198. @FSetSockOpt := WSocketGetProc('setsockopt');
  3199. Result := FSetSockOpt(s, level, optname, @optval, optlen);
  3200. end;
  3201. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3202. function WSocket_Synchronized_setsockopt(s: TSocket; level, optname: Integer; var optval: TInAddr;
  3203. optlen: Integer): Integer; overload;
  3204. begin
  3205. if @FSetSockOpt = nil then
  3206. @FSetSockOpt := WSocketGetProc('setsockopt');
  3207. Result := FSetSockOpt(s, level, optname, @optval, optlen);
  3208. end;
  3209. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3210. function WSocket_Synchronized_getsockopt(
  3211. s: TSocket; level, optname: Integer;
  3212. optval: PAnsiChar; var optlen: Integer): Integer;
  3213. begin
  3214. if @FGetSockOpt = nil then
  3215. @FGetSockOpt := WSocketGetProc('getsockopt');
  3216. Result := FGetSockOpt(s, level, optname, optval, optlen);
  3217. end;
  3218. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3219. function WSocket_Synchronized_sendto(
  3220. s : TSocket;
  3221. const Buf : TWSocketData;
  3222. len, flags : Integer;
  3223. var addrto : TSockAddr;
  3224. tolen : Integer): Integer;
  3225. begin
  3226. if @FSendTo = nil then
  3227. @FSendTo := WSocketGetProc('sendto');
  3228. Result := FSendTo(s, Buf^, len, flags, addrto, tolen);
  3229. end;
  3230. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3231. function WSocket_Synchronized_send(s: TSocket; var Buf : TWSocketData; len, flags: Integer): Integer;
  3232. begin
  3233. if @FSend = nil then
  3234. @FSend := WSocketGetProc('send');
  3235. Result := FSend(s, Buf^, len, flags);
  3236. end;
  3237. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3238. function WSocket_Synchronized_ntohs(netshort: u_short): u_short;
  3239. begin
  3240. if @Fntohs = nil then
  3241. @Fntohs := WSocketGetProc('ntohs');
  3242. Result := Fntohs(netshort);
  3243. end;
  3244. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3245. function WSocket_Synchronized_ntohl(netlong: u_long): u_long;
  3246. begin
  3247. if @Fntohl = nil then
  3248. @Fntohl := WSocketGetProc('ntohl');
  3249. Result := Fntohl(netlong);
  3250. end;
  3251. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3252. function WSocket_Synchronized_listen(s: TSocket; backlog: Integer): Integer;
  3253. begin
  3254. if @FListen = nil then
  3255. @FListen := WSocketGetProc('listen');
  3256. Result := FListen(s, backlog);
  3257. end;
  3258. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3259. function WSocket_Synchronized_ioctlsocket(s: TSocket; cmd: DWORD; var arg: u_long): Integer;
  3260. begin
  3261. if @FIoctlSocket = nil then
  3262. @FIoctlSocket := WSocketGetProc('ioctlsocket');
  3263. Result := FIoctlSocket(s, cmd, arg);
  3264. end;
  3265. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3266. {$IFDEF COMPILER2_UP}
  3267. function WSocket_Synchronized_WSAIoctl(
  3268. s : TSocket; IoControlCode : DWORD;
  3269. InBuffer : Pointer; InBufferSize : DWORD;
  3270. OutBuffer : Pointer; OutBufferSize : DWORD;
  3271. var BytesReturned : DWORD; Overlapped : POverlapped;
  3272. CompletionRoutine : FARPROC): Integer;
  3273. begin
  3274. if @FWSAIoctl = nil then
  3275. @FWSAIoctl := WSocket2GetProc('WSAIoctl');
  3276. Result := FWSAIoctl(s, IoControlCode, InBuffer, InBufferSize, OutBuffer,
  3277. OutBufferSize, BytesReturned, Overlapped, CompletionRoutine);
  3278. end;
  3279. {$ENDIF}
  3280. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3281. function WSocket_Synchronized_inet_ntoa(inaddr: TInAddr): PAnsiChar;
  3282. begin
  3283. if @FInet_ntoa = nil then
  3284. @FInet_ntoa := WSocketGetProc('inet_ntoa');
  3285. Result := FInet_ntoa(inaddr);
  3286. end;
  3287. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3288. function WSocket_Synchronized_inet_addr(const cp: AnsiString): u_long;
  3289. begin
  3290. if @FInet_addr = nil then
  3291. @FInet_addr := WSocketGetProc('inet_addr');
  3292. Result := FInet_addr(PAnsiChar(cp));
  3293. end;
  3294. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3295. function WSocket_Synchronized_htons(hostshort: u_short): u_short;
  3296. begin
  3297. if @Fhtons = nil then
  3298. @Fhtons := WSocketGetProc('htons');
  3299. Result := Fhtons(hostshort);
  3300. end;
  3301. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3302. function WSocket_Synchronized_htonl(hostlong: u_long): u_long;
  3303. begin
  3304. if @Fhtonl = nil then
  3305. @Fhtonl := WSocketGetProc('htonl');
  3306. Result := Fhtonl(hostlong);
  3307. end;
  3308. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3309. function WSocket_Synchronized_getsockname(
  3310. s : TSocket;
  3311. var name : TSockAddr;
  3312. var namelen : Integer): Integer;
  3313. begin
  3314. if @FGetSockName = nil then
  3315. @FGetSockName := WSocketGetProc('getsockname');
  3316. Result := FGetSockName(s, name, namelen);
  3317. end;
  3318. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3319. function WSocket_Synchronized_getpeername(
  3320. s : TSocket;
  3321. var name : TSockAddr;
  3322. var namelen : Integer): Integer;
  3323. begin
  3324. if @FGetPeerName = nil then
  3325. @FGetPeerName := WSocketGetProc('getpeername');
  3326. Result := FGetPeerName(s, name, namelen);
  3327. end;
  3328. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3329. function WSocket_Synchronized_connect(
  3330. s : TSocket;
  3331. var name : TSockAddr;
  3332. namelen : Integer): Integer;
  3333. begin
  3334. if @FConnect= nil then
  3335. @FConnect := WSocketGetProc('connect');
  3336. Result := FConnect(s, name, namelen);
  3337. end;
  3338. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3339. function WSocket_Synchronized_closesocket(s: TSocket): Integer;
  3340. begin
  3341. if @FCloseSocket = nil then
  3342. @FCloseSocket := WSocketGetProc('closesocket');
  3343. Result := FCloseSocket(s);
  3344. end;
  3345. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3346. function WSocket_Synchronized_bind(
  3347. s: TSocket;
  3348. var addr: TSockAddr;
  3349. namelen: Integer): Integer;
  3350. begin
  3351. if @FBind = nil then
  3352. @FBind := WSocketGetProc('bind');
  3353. Result := FBind(s, addr, namelen);
  3354. end;
  3355. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3356. function WSocket_Synchronized_accept(
  3357. s: TSocket;
  3358. {$IFDEF DELPHI1} { Delphi 1 }
  3359. var addr: TSockAddr;
  3360. var addrlen: Integer): TSocket;
  3361. {$ELSE}
  3362. {$IFDEF VER90} { Delphi 2 }
  3363. var addr: TSockAddr;
  3364. var addrlen: Integer): TSocket;
  3365. {$ELSE}{ Delphi 3/4/5, Bcb 1/3/4 }
  3366. addr: PSockAddr;
  3367. addrlen: PInteger): TSocket;
  3368. {$ENDIF}
  3369. {$ENDIF}
  3370. begin
  3371. if @FAccept = nil then
  3372. @FAccept := WSocketGetProc('accept');
  3373. Result := FAccept(s, addr, addrlen);
  3374. end;
  3375. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3376. function WSocket_Synchronized_recv(s: TSocket; var Buf: TWSocketData; len, flags: Integer): Integer;
  3377. begin
  3378. if @FRecv= nil then
  3379. @FRecv := WSocketGetProc('recv');
  3380. Result := FRecv(s, Buf^, len, flags);
  3381. end;
  3382. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3383. function WSocket_Synchronized_recvfrom(
  3384. s: TSocket;
  3385. var Buf: TWSocketData; len, flags: Integer;
  3386. var from: TSockAddr;
  3387. var fromlen: Integer): Integer;
  3388. begin
  3389. if @FRecvFrom = nil then
  3390. @FRecvFrom := WSocketGetProc('recvfrom');
  3391. Result := FRecvFrom(s, Buf^, len, flags, from, fromlen);
  3392. end;
  3393. {$ENDIF}
  3394. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3395. { Winsock is dynamically loaded and unloaded when needed. In some cases }
  3396. { you may find winsock being loaded and unloaded very often in your app }
  3397. { This happend for example when you dynamically create a TWSocket and }
  3398. { destroy a TWSocket when there is no "permanant" TWSocket (that is a }
  3399. { TWSocket dropped on a persitant form). It is the very inefficiant. }
  3400. { Calling WSocketForceLoadWinsock will increament the reference count so }
  3401. { that winsock will not be unloaded when the last TWSocket is destroyed. }
  3402. procedure WSocketForceLoadWinsock;
  3403. begin
  3404. {$IFDEF WIN32}
  3405. {$IFDEF COMPILER2_UP}
  3406. _EnterCriticalSection(GWSockCritSect);
  3407. try
  3408. {$ENDIF}
  3409. if not WSocketGForced then begin
  3410. WSocketGForced := TRUE;
  3411. Inc(WSocketGCount);
  3412. WSocketGetProc('');
  3413. end;
  3414. {$IFDEF COMPILER2_UP}
  3415. finally
  3416. _LeaveCriticalSection(GWSockCritSect);
  3417. end;
  3418. {$ENDIF}
  3419. {$ENDIF}
  3420. end;
  3421. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3422. { Cancel the operation done with WSocketForceLoadWinsock. }
  3423. procedure WSocketCancelForceLoadWinsock;
  3424. begin
  3425. {$IFDEF WIN32}
  3426. {$IFDEF COMPILER2_UP}
  3427. _EnterCriticalSection(GWSockCritSect);
  3428. try
  3429. {$ENDIF}
  3430. if WSocketGForced then begin
  3431. WSocketGForced := FALSE;
  3432. Dec(WSocketGCount);
  3433. if WSocketGCount <= 0 then
  3434. WSocketUnloadWinsock;
  3435. end;
  3436. {$IFDEF COMPILER2_UP}
  3437. finally
  3438. _LeaveCriticalSection(GWSockCritSect);
  3439. end;
  3440. {$ENDIF}
  3441. {$ENDIF}
  3442. end;
  3443. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3444. procedure WSocketUnloadWinsock;
  3445. begin
  3446. {$IFDEF WIN32}
  3447. {$IFDEF NEVER} { 14/02/99 }
  3448. if DllStarted then begin
  3449. DllStarted := FALSE;
  3450. WSocket_WSACleanup;
  3451. end;
  3452. {$ENDIF}
  3453. {$IFDEF COMPILER2_UP}
  3454. _EnterCriticalSection(GWSockCritSect);
  3455. try
  3456. {$ENDIF}
  3457. if (FDllHandle <> 0) and (WSocketGCount = 0) then begin
  3458. WSocket_Synchronized_WSACleanup;
  3459. {$IFDEF COMPILER2_UP}
  3460. if FDll2Handle <> 0 then begin
  3461. _FreeLibrary(FDll2Handle);
  3462. FDll2Handle := 0;
  3463. FWSAIoctl := nil;
  3464. end;
  3465. {$ENDIF}
  3466. _FreeLibrary(FDllHandle);
  3467. FDllHandle := 0;
  3468. FWSAStartup := nil;
  3469. FWSACleanup := nil;
  3470. FWSASetLastError := nil;
  3471. FWSAGetLastError := nil;
  3472. FWSACancelAsyncRequest := nil;
  3473. FWSAAsyncGetHostByName := nil;
  3474. FWSAAsyncGetHostByAddr := nil;
  3475. FWSAAsyncSelect := nil;
  3476. FGetServByName := nil;
  3477. FGetProtoByName := nil;
  3478. FGetHostByName := nil;
  3479. FGetHostByAddr := nil;
  3480. FGetHostName := nil;
  3481. FOpenSocket := nil;
  3482. FShutdown := nil;
  3483. FSetSockOpt := nil;
  3484. FGetSockOpt := nil;
  3485. FSendTo := nil;
  3486. FSend := nil;
  3487. FRecv := nil;
  3488. FRecvFrom := nil;
  3489. Fntohs := nil;
  3490. Fntohl := nil;
  3491. FListen := nil;
  3492. FIoctlSocket := nil;
  3493. {$IFDEF COMPILER2_UP}
  3494. FWSAIoctl := nil;
  3495. {$ENDIF}
  3496. FInet_ntoa := nil;
  3497. FInet_addr := nil;
  3498. Fhtons := nil;
  3499. Fhtonl := nil;
  3500. FGetSockName := nil;
  3501. FGetPeerName := nil;
  3502. FConnect := nil;
  3503. FCloseSocket := nil;
  3504. FBind := nil;
  3505. FAccept := nil;
  3506. end;
  3507. WSocketGForced := FALSE;
  3508. {$IFDEF COMPILER2_UP}
  3509. finally
  3510. _LeaveCriticalSection(GWSockCritSect);
  3511. end;
  3512. {$ENDIF}
  3513. {$ENDIF}
  3514. end;
  3515. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3516. {$IFDEF WIN32}
  3517. function WSocketGetProc(const ProcName : AnsiString) : Pointer;
  3518. var
  3519. LastError : LongInt;
  3520. begin
  3521. { Prevents compiler warning "Return value might be undefined" }
  3522. Result := nil;
  3523. _EnterCriticalSection(GWSockCritSect);
  3524. try
  3525. if FDllHandle = 0 then begin
  3526. FDllHandle := _LoadLibrary(@winsocket[1]);
  3527. if FDllHandle = 0 then
  3528. { raise ESocketException.Create('Unable to load ' + winsocket +
  3529. ' Error #' + IntToStr(GetLastError));}
  3530. raise ESocketException.Create('Unable to load ' + winsocket +
  3531. ' - ' + GetWindowsErr (GetLastError)); { V5.26 }
  3532. LastError := WSocket_Synchronized_WSAStartup(MAKEWORD(GReqVerLow, GReqVerHigh) { $202 $101}, GInitData);
  3533. if LastError <> 0 then begin
  3534. { raise ESocketException.CreateFmt('%s: WSAStartup error #%d',
  3535. [winsocket, LastError]); }
  3536. raise ESocketException.Create('Winsock startup error ' + winsocket +
  3537. ' - ' + GetWindowsErr (LastError)); { V5.26 }
  3538. end;
  3539. end;
  3540. if Length(ProcName) = 0 then
  3541. Result := nil
  3542. else begin
  3543. Result := _GetProcAddress(FDllHandle, @ProcName[1]);
  3544. if Result = nil then
  3545. raise ESocketException.Create('Procedure ' + String(ProcName) +
  3546. ' not found in ' + winsocket +
  3547. ' - ' + GetWindowsErr (GetLastError)); { V5.26 }
  3548. end;
  3549. finally
  3550. _LeaveCriticalSection(GWSockCritSect);
  3551. end;
  3552. end;
  3553. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3554. function WSocket2GetProc(const ProcName : AnsiString) : Pointer;
  3555. begin
  3556. { Prevents compiler warning "Return value might be undefined" }
  3557. Result := nil;
  3558. _EnterCriticalSection(GWSockCritSect);
  3559. try
  3560. if FDll2Handle = 0 then begin
  3561. { Be sure to have main winsock.dll loaded }
  3562. if FDllHandle = 0 then
  3563. WSocketGetProc('');
  3564. FDll2Handle := _LoadLibrary(@winsocket2[1]);
  3565. if FDll2Handle = 0 then
  3566. { raise ESocketException.Create('Unable to load ' + winsocket2 +
  3567. ' Error #' + IntToStr(GetLastError)); }
  3568. raise ESocketException.Create('Unable to load ' + winsocket2 +
  3569. ' - ' + GetWindowsErr (GetLastError)); { V5.26 }
  3570. end;
  3571. if Length(ProcName) = 0 then
  3572. Result := nil
  3573. else begin
  3574. Result := _GetProcAddress(FDll2Handle, @ProcName[1]);
  3575. if Result = nil then
  3576. raise ESocketException.Create('Procedure ' + String(ProcName) +
  3577. ' not found in ' + winsocket2 +
  3578. ' - ' + GetWindowsErr (GetLastError)); { V5.26 }
  3579. end;
  3580. finally
  3581. _LeaveCriticalSection(GWSockCritSect);
  3582. end;
  3583. end;
  3584. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3585. function WinsockInfo : TWSADATA;
  3586. begin
  3587. { LoadWinsock(winsocket); 14/02/99 }
  3588. { Load winsock and initialize it as needed }
  3589. _EnterCriticalSection(GWSockCritSect);
  3590. try
  3591. WSocketGetProc('');
  3592. Result := GInitData;
  3593. { If no socket created, then unload winsock immediately }
  3594. if WSocketGCount <= 0 then
  3595. WSocketUnloadWinsock;
  3596. finally
  3597. _LeaveCriticalSection(GWSockCritSect);
  3598. end;
  3599. end;
  3600. {$ENDIF}
  3601. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3602. {$IFDEF CLR}
  3603. function WSocket_Synchronized_WSAStartup(
  3604. wVersionRequired : Word;
  3605. out WSData : TWSAData): Integer;
  3606. begin
  3607. if GWSAStartupCalled then
  3608. Result := 0
  3609. else begin
  3610. Result := OverByteIcsWinsock.WSAStartup(wVersionRequired, WSData);
  3611. GWSAStartupCalled := TRUE;
  3612. end;
  3613. end;
  3614. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3615. function WSocket_Synchronized_WSACleanup : Integer;
  3616. begin
  3617. Result := OverByteIcsWinsock.WSACleanup;
  3618. GWSAStartupCalled := FALSE;
  3619. end;
  3620. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3621. procedure WSocket_Synchronized_WSASetLastError(ErrCode: Integer);
  3622. begin
  3623. if not GWSAStartupCalled then
  3624. WSocket_Synchronized_WSAStartup(MAKEWORD(GReqVerLow, GReqVerHigh), GInitData);
  3625. OverByteIcsWinsock.WsaSetLastError(ErrCode);
  3626. end;
  3627. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3628. function WSocket_Synchronized_WSAGetLastError: Integer;
  3629. begin
  3630. if not GWSAStartupCalled then
  3631. WSocket_Synchronized_WSAStartup(MAKEWORD(GReqVerLow, GReqVerHigh), GInitData);
  3632. Result := OverByteIcsWinsock.WSAGetLastError;
  3633. end;
  3634. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3635. function WSocket_Synchronized_WSACancelAsyncRequest(hAsyncTaskHandle: THandle): Integer;
  3636. begin
  3637. if not GWSAStartupCalled then
  3638. WSocket_Synchronized_WSAStartup(MAKEWORD(GReqVerLow, GReqVerHigh), GInitData);
  3639. Result := OverByteIcsWinsock.WSACancelAsyncRequest(hAsyncTaskHandle);
  3640. end;
  3641. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3642. function WSocket_Synchronized_WSAAsyncGetHostByName(
  3643. HWindow: HWND; wMsg: u_int;
  3644. const name : String; buf: IntPtr;
  3645. buflen: Integer): THandle;
  3646. begin
  3647. if not GWSAStartupCalled then
  3648. WSocket_Synchronized_WSAStartup(MAKEWORD(GReqVerLow, GReqVerHigh), GInitData);
  3649. Result := OverByteIcsWinsock.WSAAsyncGetHostByName(
  3650. HWindow, wMsg, name, buf, buflen);
  3651. end;
  3652. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3653. function WSocket_Synchronized_WSAAsyncGetHostByAddr(
  3654. HWindow: HWND;
  3655. wMsg: u_int; var addr: u_long;
  3656. len, Struct: Integer;
  3657. buf: IntPtr;
  3658. buflen: Integer): THandle;
  3659. begin
  3660. if not GWSAStartupCalled then
  3661. WSocket_Synchronized_WSAStartup(MAKEWORD(GReqVerLow, GReqVerHigh), GInitData);
  3662. Result := OverByteIcsWinsock.WSAAsyncGetHostByAddr(
  3663. HWindow, wMsg, addr, len, struct, buf, buflen);
  3664. end;
  3665. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3666. function WSocket_Synchronized_WSAAsyncSelect(
  3667. S : TSocket;
  3668. HWindow : HWND;
  3669. wMsg : u_int;
  3670. lEvent : Longint): Integer;
  3671. begin
  3672. if not GWSAStartupCalled then
  3673. WSocket_Synchronized_WSAStartup(MAKEWORD(GReqVerLow, GReqVerHigh), GInitData);
  3674. Result := OverByteIcsWinsock.WSAAsyncSelect(S, HWindow, wMsg, lEvent);
  3675. end;
  3676. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3677. function WSocket_Synchronized_getservbyname(const Name, Proto: String): IntPtr;
  3678. begin
  3679. if not GWSAStartupCalled then
  3680. WSocket_Synchronized_WSAStartup(MAKEWORD(GReqVerLow, GReqVerHigh), GInitData);
  3681. Result := OverByteIcsWinsock.getservbyname(Name, Proto);
  3682. end;
  3683. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3684. function WSocket_Synchronized_getprotobyname(const name: String): IntPtr;
  3685. begin
  3686. if not GWSAStartupCalled then
  3687. WSocket_Synchronized_WSAStartup(MAKEWORD(GReqVerLow, GReqVerHigh), GInitData);
  3688. Result := OverByteIcsWinsock.getprotobyname(name);
  3689. end;
  3690. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3691. function WSocket_Synchronized_gethostbyname(const Name: String): IntPtr;
  3692. begin
  3693. if not GWSAStartupCalled then
  3694. WSocket_Synchronized_WSAStartup(MAKEWORD(GReqVerLow, GReqVerHigh), GInitData);
  3695. Result := OverByteIcsWinsock.gethostbyname(Name);
  3696. end;
  3697. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3698. function WSocket_Synchronized_gethostbyaddr(
  3699. var addr: u_long; len, Struct: Integer): IntPtr;
  3700. begin
  3701. if not GWSAStartupCalled then
  3702. WSocket_Synchronized_WSAStartup(MAKEWORD(GReqVerLow, GReqVerHigh), GInitData);
  3703. Result := OverByteIcsWinsock.gethostbyaddr(addr, len, Struct);
  3704. end;
  3705. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3706. function WSocket_Synchronized_gethostname(out Name: String): Integer;
  3707. var
  3708. SB: System.Text.StringBuilder;
  3709. begin
  3710. if not GWSAStartupCalled then
  3711. WSocket_Synchronized_WSAStartup(MAKEWORD(GReqVerLow, GReqVerHigh), GInitData);
  3712. SB := System.Text.StringBuilder.Create(256);
  3713. Result := OverByteIcsWinsock.gethostname(SB, SB.Capacity);
  3714. if Result <> 0 then
  3715. Name := ''
  3716. else
  3717. Name := SB.ToString;
  3718. end;
  3719. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3720. function WSocket_Synchronized_socket(af, Struct, protocol: Integer): TSocket;
  3721. begin
  3722. if not GWSAStartupCalled then
  3723. WSocket_Synchronized_WSAStartup(MAKEWORD(GReqVerLow, GReqVerHigh), GInitData);
  3724. Result := OverByteIcsWinsock.socket(af, Struct, protocol);
  3725. end;
  3726. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3727. function WSocket_Synchronized_shutdown(s: TSocket; how: Integer): Integer;
  3728. begin
  3729. if not GWSAStartupCalled then
  3730. WSocket_Synchronized_WSAStartup(MAKEWORD(GReqVerLow, GReqVerHigh), GInitData);
  3731. Result := OverByteIcsWinsock.shutdown(s, how);
  3732. end;
  3733. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3734. function WSocket_Synchronized_setsockopt(
  3735. s : TSocket;
  3736. level, optname : Integer;
  3737. var optval : Integer;
  3738. optlen : Integer): Integer; overload;
  3739. begin
  3740. if not GWSAStartupCalled then
  3741. WSocket_Synchronized_WSAStartup(MAKEWORD(GReqVerLow, GReqVerHigh), GInitData);
  3742. Result := OverByteIcsWinsock.setsockopt_integer(
  3743. S, Level, OptName, OptVal, 4);
  3744. end;
  3745. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3746. function WSocket_Synchronized_setsockopt(
  3747. s : TSocket;
  3748. level, optname : Integer;
  3749. var optval : ip_mreq;
  3750. optlen : Integer): Integer; overload;
  3751. begin
  3752. if not GWSAStartupCalled then
  3753. WSocket_Synchronized_WSAStartup(MAKEWORD(GReqVerLow, GReqVerHigh), GInitData);
  3754. Result := OverByteIcsWinsock.setsockopt_ip_mreq(
  3755. S, Level, OptName, OptVal, 8);
  3756. end;
  3757. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3758. function WSocket_Synchronized_setsockopt(
  3759. s : TSocket;
  3760. level, optname : Integer;
  3761. var optval : TInAddr;
  3762. optlen : Integer): Integer; overload;
  3763. begin
  3764. if not GWSAStartupCalled then
  3765. WSocket_Synchronized_WSAStartup(MAKEWORD(GReqVerLow, GReqVerHigh), GInitData);
  3766. Result := OverByteIcsWinsock.setsockopt_tinaddr(
  3767. S, Level, OptName, OptVal, 4);
  3768. end;
  3769. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3770. function WSocket_Synchronized_setsockopt(
  3771. s : TSocket;
  3772. level, optname : Integer;
  3773. var optval : TLinger;
  3774. optlen : Integer): Integer; overload;
  3775. begin
  3776. if not GWSAStartupCalled then
  3777. WSocket_Synchronized_WSAStartup(MAKEWORD(GReqVerLow, GReqVerHigh), GInitData);
  3778. Result := OverByteIcsWinsock.setsockopt_tlinger(
  3779. S, Level, OptName, OptVal, 4);
  3780. end;
  3781. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3782. function WSocket_Synchronized_getsockopt(
  3783. s: TSocket; level, optname: Integer;
  3784. var optval: Integer; var optlen: Integer): Integer; overload;
  3785. begin
  3786. if not GWSAStartupCalled then
  3787. WSocket_Synchronized_WSAStartup(MAKEWORD(GReqVerLow, GReqVerHigh), GInitData);
  3788. Result := OverByteIcsWinsock.getsockopt_integer(
  3789. s, level, optname, optval, optlen);
  3790. end;
  3791. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3792. function WSocket_Synchronized_getsockopt(
  3793. s: TSocket; level, optname: Integer;
  3794. var optval: ip_mreq; var optlen: Integer): Integer; overload;
  3795. begin
  3796. if not GWSAStartupCalled then
  3797. WSocket_Synchronized_WSAStartup(MAKEWORD(GReqVerLow, GReqVerHigh), GInitData);
  3798. Result := OverByteIcsWinsock.getsockopt_ip_mreq(
  3799. s, level, optname, optval, optlen);
  3800. end;
  3801. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3802. function WSocket_Synchronized_getsockopt(
  3803. s: TSocket; level, optname: Integer;
  3804. var optval: TInAddr; var optlen: Integer): Integer; overload;
  3805. begin
  3806. if not GWSAStartupCalled then
  3807. WSocket_Synchronized_WSAStartup(MAKEWORD(GReqVerLow, GReqVerHigh), GInitData);
  3808. Result := OverByteIcsWinsock.getsockopt_tinaddr(
  3809. s, level, optname, optval, optlen);
  3810. end;
  3811. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3812. function WSocket_Synchronized_getsockopt(
  3813. s: TSocket; level, optname: Integer;
  3814. var optval: TLinger; var optlen: Integer): Integer; overload;
  3815. begin
  3816. if not GWSAStartupCalled then
  3817. WSocket_Synchronized_WSAStartup(MAKEWORD(GReqVerLow, GReqVerHigh), GInitData);
  3818. Result := OverByteIcsWinsock.getsockopt_tlinger(
  3819. s, level, optname, optval, optlen);
  3820. end;
  3821. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3822. function WSocket_Synchronized_sendto(
  3823. s : TSocket;
  3824. const Buf : TBytes;
  3825. len, flags : Integer;
  3826. var addrto : TSockAddr;
  3827. tolen : Integer): Integer;
  3828. begin
  3829. if not GWSAStartupCalled then
  3830. WSocket_Synchronized_WSAStartup(MAKEWORD(GReqVerLow, GReqVerHigh), GInitData);
  3831. Result := OverByteIcsWinsock.sendto(
  3832. s, Buf, len, flags, addrto, SizeOfTSockAddr);
  3833. end;
  3834. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3835. function WSocket_Synchronized_send(
  3836. s: TSocket;
  3837. const Buf : TBytes;
  3838. len, flags: Integer): Integer;
  3839. begin
  3840. if not GWSAStartupCalled then
  3841. WSocket_Synchronized_WSAStartup(MAKEWORD(GReqVerLow, GReqVerHigh), GInitData);
  3842. Result := OverByteIcsWinsock.send(s, Buf, len, flags);
  3843. end;
  3844. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3845. function WSocket_Synchronized_ntohs(netshort: u_short): u_short;
  3846. begin
  3847. if not GWSAStartupCalled then
  3848. WSocket_Synchronized_WSAStartup(MAKEWORD(GReqVerLow, GReqVerHigh), GInitData);
  3849. Result := OverByteIcsWinsock.ntohs(netshort);
  3850. end;
  3851. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3852. function WSocket_Synchronized_ntohl(netlong: u_long): u_long;
  3853. begin
  3854. if not GWSAStartupCalled then
  3855. WSocket_Synchronized_WSAStartup(MAKEWORD(GReqVerLow, GReqVerHigh), GInitData);
  3856. Result := OverByteIcsWinsock.ntohl(netlong);
  3857. end;
  3858. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3859. function WSocket_Synchronized_listen(s: TSocket; backlog: Integer): Integer;
  3860. begin
  3861. if not GWSAStartupCalled then
  3862. WSocket_Synchronized_WSAStartup(MAKEWORD(GReqVerLow, GReqVerHigh), GInitData);
  3863. Result := OverByteIcsWinsock.listen(s, backlog);
  3864. end;
  3865. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3866. function WSocket_Synchronized_ioctlsocket(s: TSocket; cmd: DWORD; var arg: u_long): Integer;
  3867. begin
  3868. if not GWSAStartupCalled then
  3869. WSocket_Synchronized_WSAStartup(MAKEWORD(GReqVerLow, GReqVerHigh), GInitData);
  3870. Result := OverByteIcsWinsock.ioctlsocket(s, cmd, arg);
  3871. end;
  3872. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3873. function WSocket_Synchronized_inet_ntoa(inaddr: TInAddr): String;
  3874. begin
  3875. if not GWSAStartupCalled then
  3876. WSocket_Synchronized_WSAStartup(MAKEWORD(GReqVerLow, GReqVerHigh), GInitData);
  3877. Result := OverByteIcsWinsock.inet_ntoa(inaddr);
  3878. end;
  3879. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3880. function WSocket_Synchronized_inet_addr(const cp: String): u_long;
  3881. begin
  3882. if not GWSAStartupCalled then
  3883. WSocket_Synchronized_WSAStartup(MAKEWORD(GReqVerLow, GReqVerHigh), GInitData);
  3884. Result := OverByteIcsWinsock.inet_addr(cp);
  3885. end;
  3886. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3887. function WSocket_Synchronized_htons(hostshort: u_short): u_short;
  3888. begin
  3889. if not GWSAStartupCalled then
  3890. WSocket_Synchronized_WSAStartup(MAKEWORD(GReqVerLow, GReqVerHigh), GInitData);
  3891. Result := OverByteIcsWinsock.htons(hostshort);
  3892. end;
  3893. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3894. function WSocket_Synchronized_htonl(hostlong: u_long): u_long;
  3895. begin
  3896. if not GWSAStartupCalled then
  3897. WSocket_Synchronized_WSAStartup(MAKEWORD(GReqVerLow, GReqVerHigh), GInitData);
  3898. Result := OverByteIcsWinsock.htonl(hostlong);
  3899. end;
  3900. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3901. function WSocket_Synchronized_getsockname(
  3902. S : TSocket;
  3903. var Name : TSockAddr;
  3904. var NameLen : Integer): Integer;
  3905. var
  3906. APINameLen : Integer;
  3907. begin
  3908. APINameLen := SizeOfTSockAddr;
  3909. if not GWSAStartupCalled then
  3910. WSocket_Synchronized_WSAStartup(MAKEWORD(GReqVerLow, GReqVerHigh), GInitData);
  3911. Result := OverByteIcsWinsock.getsockname(S, Name, APINameLen);
  3912. end;
  3913. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3914. function WSocket_Synchronized_getpeername(
  3915. S : TSocket;
  3916. out Name : TSockAddr;
  3917. var NameLen : Integer): Integer;
  3918. var
  3919. APINameLen : Integer;
  3920. begin
  3921. APINameLen := SizeOfTSockAddr;
  3922. if not GWSAStartupCalled then
  3923. WSocket_Synchronized_WSAStartup(MAKEWORD(GReqVerLow, GReqVerHigh), GInitData);
  3924. Result := OverByteIcsWinsock.getpeername(S, Name, APINameLen);
  3925. end;
  3926. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3927. function WSocket_Synchronized_connect(
  3928. S : TSocket;
  3929. var Name : TSockAddr;
  3930. NameLen : Integer): Integer;
  3931. begin
  3932. if not GWSAStartupCalled then
  3933. WSocket_Synchronized_WSAStartup(MAKEWORD(GReqVerLow, GReqVerHigh), GInitData);
  3934. Result := OverByteIcsWinsock.connect(S, Name, SizeOfTSockAddr);
  3935. end;
  3936. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3937. function WSocket_Synchronized_closesocket(s: TSocket): Integer;
  3938. begin
  3939. if not GWSAStartupCalled then
  3940. WSocket_Synchronized_WSAStartup(MAKEWORD(GReqVerLow, GReqVerHigh), GInitData);
  3941. Result := OverByteIcsWinsock.closesocket(s);
  3942. end;
  3943. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3944. function WSocket_Synchronized_bind(
  3945. S : TSocket;
  3946. var Addr : TSockAddr;
  3947. NameLen : Integer): Integer;
  3948. begin
  3949. if not GWSAStartupCalled then
  3950. WSocket_Synchronized_WSAStartup(MAKEWORD(GReqVerLow, GReqVerHigh), GInitData);
  3951. Result := OverByteIcsWinsock.bind(S, Addr, SizeOfTSockAddr);
  3952. end;
  3953. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3954. function WSocket_Synchronized_accept(
  3955. s : TSocket;
  3956. var addr : TSockAddr;
  3957. var addrlen : Integer): TSocket;
  3958. begin
  3959. if not GWSAStartupCalled then
  3960. WSocket_Synchronized_WSAStartup(MAKEWORD(GReqVerLow, GReqVerHigh), GInitData);
  3961. addrlen := SizeOfTSockAddr;
  3962. Result := OverByteIcsWinsock.accept(s, addr, addrlen);
  3963. end;
  3964. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3965. function WSocket_Synchronized_recv(
  3966. S : TSocket;
  3967. out Buf : TBytes;
  3968. Len, Flags : Integer): Integer;
  3969. begin
  3970. if not GWSAStartupCalled then
  3971. WSocket_Synchronized_WSAStartup(MAKEWORD(GReqVerLow, GReqVerHigh), GInitData);
  3972. Result := OverByteIcsWinsock.recv(s, Buf, len, flags);
  3973. end;
  3974. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3975. function WSocket_Synchronized_recvfrom(
  3976. S : TSocket;
  3977. out Buf : TBytes;
  3978. Len, Flags : Integer;
  3979. var From : TSockAddr;
  3980. var FromLen : Integer): Integer;
  3981. var
  3982. APIFromLen : Integer;
  3983. begin
  3984. if not GWSAStartupCalled then
  3985. WSocket_Synchronized_WSAStartup(MAKEWORD(GReqVerLow, GReqVerHigh), GInitData);
  3986. APIFromLen := SizeOfTSockAddr;
  3987. Result := OverByteIcsWinsock.recvfrom(
  3988. S, Buf, Len, Flags, From, APIFromLen);
  3989. end;
  3990. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3991. function WinsockInfo : TWSADATA;
  3992. begin
  3993. if not GWSAStartupCalled then
  3994. WSocket_Synchronized_WSAStartup(MAKEWORD(GReqVerLow, GReqVerHigh), GInitData);
  3995. Result := GInitData;
  3996. end;
  3997. {$ENDIF}
  3998. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  3999. {$IFNDEF NO_ADV_MT}
  4000. procedure SafeIncrementCount;
  4001. begin
  4002. _EnterCriticalSection(GWSockCritSect);
  4003. Inc(WSocketGCount);
  4004. _LeaveCriticalSection(GWSockCritSect);
  4005. end;
  4006. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  4007. procedure SafeDecrementCount;
  4008. begin
  4009. _EnterCriticalSection(GWSockCritSect);
  4010. Dec(WSocketGCount);
  4011. _LeaveCriticalSection(GWSockCritSect);
  4012. end;
  4013. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  4014. function SafeWSocketGCount : Integer;
  4015. begin
  4016. _EnterCriticalSection(GWSockCritSect);
  4017. Result := WSocketGCount;
  4018. _LeaveCriticalSection(GWSockCritSect);
  4019. end;
  4020. {$ENDIF}
  4021. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  4022. function WSocket_WSAStartup(
  4023. wVersionRequired : WORD;
  4024. var WSData : TWSAData): Integer;
  4025. begin
  4026. {$IFNDEF NO_ADV_MT}
  4027. SafeIncrementCount;
  4028. try
  4029. {$ENDIF}
  4030. Result := WSocket_Synchronized_WSAStartup(wVersionRequired, WSData);
  4031. {$IFNDEF NO_ADV_MT}
  4032. finally
  4033. SafeDecrementCount;
  4034. end;
  4035. {$ENDIF}
  4036. end;
  4037. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  4038. function WSocket_WSACleanup : Integer;
  4039. begin
  4040. {$IFNDEF NO_ADV_MT}
  4041. SafeIncrementCount;
  4042. try
  4043. {$ENDIF}
  4044. Result := WSocket_Synchronized_WSACleanup;
  4045. {$IFNDEF NO_ADV_MT}
  4046. finally
  4047. SafeDecrementCount;
  4048. end;
  4049. {$ENDIF}
  4050. end;
  4051. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  4052. procedure WSocket_WSASetLastError(iError: Integer);
  4053. begin
  4054. {$IFNDEF NO_ADV_MT}
  4055. SafeIncrementCount;
  4056. try
  4057. {$ENDIF}
  4058. WSocket_Synchronized_WSASetLastError(iError);
  4059. {$IFNDEF NO_ADV_MT}
  4060. finally
  4061. SafeDecrementCount;
  4062. end;
  4063. {$ENDIF}
  4064. end;
  4065. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  4066. function WSocket_WSAGetLastError: Integer;
  4067. begin
  4068. {$IFNDEF NO_ADV_MT}
  4069. SafeIncrementCount;
  4070. try
  4071. {$ENDIF}
  4072. Result := WSocket_Synchronized_WSAGetLastError;
  4073. {$IFNDEF NO_ADV_MT}
  4074. finally
  4075. SafeDecrementCount;
  4076. end;
  4077. {$ENDIF}
  4078. end;
  4079. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  4080. function WSocket_WSACancelAsyncRequest(hAsyncTaskHandle: THandle): Integer;
  4081. begin
  4082. {$IFNDEF NO_ADV_MT}
  4083. SafeIncrementCount;
  4084. try
  4085. {$ENDIF}
  4086. Result := WSocket_Synchronized_WSACancelAsyncRequest(hAsyncTaskHandle);
  4087. {$IFNDEF NO_ADV_MT}
  4088. finally
  4089. SafeDecrementCount;
  4090. end;
  4091. {$ENDIF}
  4092. end;
  4093. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  4094. {$IFDEF CLR}
  4095. function WSocket_WSAAsyncGetHostByName(
  4096. HWindow: HWND; wMsg: u_int;
  4097. const name : String; buf: IntPtr;
  4098. buflen: Integer): THandle;
  4099. begin
  4100. Result := OverByteIcsWinsock.WSAAsyncGetHostByName(
  4101. HWindow, wMsg, name, buf, buflen);
  4102. end;
  4103. {$ENDIF}
  4104. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  4105. {$IFDEF CLR}
  4106. function WSocket_WSAAsyncGetHostByAddr(
  4107. HWindow: HWND;
  4108. wMsg: u_int; var addr: u_long;
  4109. len, Struct: Integer;
  4110. buf: IntPtr;
  4111. buflen: Integer): THandle;
  4112. begin
  4113. Result := OverByteIcsWinsock.WSAAsyncGetHostByAddr(
  4114. HWindow, wMsg, addr, len, struct, buf, buflen);
  4115. end;
  4116. {$ENDIF}
  4117. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  4118. {$IFDEF WIN32}
  4119. function WSocket_WSAAsyncGetHostByName(
  4120. HWindow: HWND; wMsg: u_int;
  4121. name, buf: PAnsiChar;
  4122. buflen: Integer): THandle;
  4123. begin
  4124. {$IFNDEF NO_ADV_MT}
  4125. SafeIncrementCount;
  4126. try
  4127. {$ENDIF}
  4128. Result := WSocket_Synchronized_WSAAsyncGetHostByName(
  4129. HWindow, wMsg, name, buf, buflen);
  4130. {$IFNDEF NO_ADV_MT}
  4131. finally
  4132. SafeDecrementCount;
  4133. end;
  4134. {$ENDIF}
  4135. end;
  4136. {$ENDIF}
  4137. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  4138. {$IFDEF WIN32}
  4139. function WSocket_WSAAsyncGetHostByAddr(
  4140. HWindow: HWND;
  4141. wMsg: u_int; addr: PAnsiChar;
  4142. len, Struct: Integer;
  4143. buf: PAnsiChar;
  4144. buflen: Integer): THandle;
  4145. begin
  4146. {$IFNDEF NO_ADV_MT}
  4147. SafeIncrementCount;
  4148. try
  4149. {$ENDIF}
  4150. Result := WSocket_Synchronized_WSAAsyncGetHostByAddr(
  4151. HWindow, wMsg, addr, len, struct, buf, buflen);
  4152. {$IFNDEF NO_ADV_MT}
  4153. finally
  4154. SafeDecrementCount;
  4155. end;
  4156. {$ENDIF}
  4157. end;
  4158. {$ENDIF}
  4159. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  4160. function WSocket_WSAAsyncSelect(
  4161. s: TSocket;
  4162. HWindow: HWND;
  4163. wMsg: u_int;
  4164. lEvent: Longint): Integer;
  4165. begin
  4166. {$IFNDEF NO_ADV_MT}
  4167. SafeIncrementCount;
  4168. try
  4169. {$ENDIF}
  4170. Result := WSocket_Synchronized_WSAAsyncSelect(
  4171. s, HWindow, wMsg, lEvent);
  4172. {$IFNDEF NO_ADV_MT}
  4173. finally
  4174. SafeDecrementCount;
  4175. end;
  4176. {$ENDIF}
  4177. end;
  4178. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  4179. {$IFDEF CLR}
  4180. function WSocket_getservbyname(const Name, Proto: String): IntPtr;
  4181. begin
  4182. Result := OverByteIcsWinsock.getservbyname(Name, Proto);
  4183. end;
  4184. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  4185. function WSocket_getprotobyname(const name: String): IntPtr;
  4186. begin
  4187. Result := OverByteIcsWinsock.getprotobyname(name);
  4188. end;
  4189. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  4190. function WSocket_gethostbyname(const Name: String): IntPtr;
  4191. begin
  4192. Result := OverByteIcsWinsock.gethostbyname(Name);
  4193. end;
  4194. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  4195. function WSocket_gethostbyaddr(
  4196. var addr: u_long; len, Struct: Integer): IntPtr;
  4197. begin
  4198. Result := OverByteIcsWinsock.gethostbyaddr(addr, len, Struct);
  4199. end;
  4200. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  4201. function WSocket_gethostname(out Name: String): Integer;
  4202. var
  4203. SB: System.Text.StringBuilder;
  4204. begin
  4205. SB := System.Text.StringBuilder.Create(256);
  4206. Result := OverByteIcsWinsock.gethostname(SB, SB.Capacity);
  4207. if Result <> 0 then
  4208. Name := ''
  4209. else
  4210. Name := SB.ToString;
  4211. end;
  4212. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  4213. {$ENDIF}
  4214. {$IFDEF WIN32}
  4215. function WSocket_getservbyname(name, proto: PAnsiChar): PServEnt;
  4216. begin
  4217. {$IFNDEF NO_ADV_MT}
  4218. SafeIncrementCount;
  4219. try
  4220. {$ENDIF}
  4221. Result := WSocket_Synchronized_getservbyname(name, proto);
  4222. {$IFNDEF NO_ADV_MT}
  4223. finally
  4224. SafeDecrementCount;
  4225. end;
  4226. {$ENDIF}
  4227. end;
  4228. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  4229. function WSocket_getprotobyname(name: PAnsiChar): PProtoEnt;
  4230. begin
  4231. {$IFNDEF NO_ADV_MT}
  4232. SafeIncrementCount;
  4233. try
  4234. {$ENDIF}
  4235. Result := WSocket_Synchronized_getprotobyname(name);
  4236. {$IFNDEF NO_ADV_MT}
  4237. finally
  4238. SafeDecrementCount;
  4239. end;
  4240. {$ENDIF}
  4241. end;
  4242. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  4243. function WSocket_gethostbyname(name: PAnsiChar): PHostEnt;
  4244. begin
  4245. {$IFNDEF NO_ADV_MT}
  4246. SafeIncrementCount;
  4247. try
  4248. {$ENDIF}
  4249. Result := WSocket_Synchronized_gethostbyname(name);
  4250. {$IFNDEF NO_ADV_MT}
  4251. finally
  4252. SafeDecrementCount;
  4253. end;
  4254. {$ENDIF}
  4255. end;
  4256. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  4257. function WSocket_gethostbyaddr(addr: Pointer; len, Struct: Integer): PHostEnt;
  4258. begin
  4259. {$IFNDEF NO_ADV_MT}
  4260. SafeIncrementCount;
  4261. try
  4262. {$ENDIF}
  4263. Result := WSocket_Synchronized_gethostbyaddr(addr, len, Struct);
  4264. {$IFNDEF NO_ADV_MT}
  4265. finally
  4266. SafeDecrementCount;
  4267. end;
  4268. {$ENDIF}
  4269. end;
  4270. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  4271. function WSocket_gethostname(out name: AnsiString): Integer;
  4272. begin
  4273. {$IFNDEF NO_ADV_MT}
  4274. SafeIncrementCount;
  4275. try
  4276. {$ENDIF}
  4277. SetLength(Name, 256);
  4278. Result := WSocket_Synchronized_gethostname(PAnsiChar(name), 256);
  4279. if Result >= 0 then
  4280. // Unicode will convert on the fly
  4281. SetLength(Name, _StrLen(PAnsiChar(Name))) // Unicode change
  4282. else
  4283. SetLength(Name, 0);
  4284. {$IFNDEF NO_ADV_MT}
  4285. finally
  4286. SafeDecrementCount;
  4287. end;
  4288. {$ENDIF}
  4289. end;
  4290. {$ENDIF}
  4291. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  4292. function WSocket_socket(af, Struct, protocol: Integer): TSocket;
  4293. begin
  4294. {$IFNDEF NO_ADV_MT}
  4295. SafeIncrementCount;
  4296. try
  4297. {$ENDIF}
  4298. Result := WSocket_Synchronized_socket(af, Struct, protocol);
  4299. {$IFNDEF NO_ADV_MT}
  4300. finally
  4301. SafeDecrementCount;
  4302. end;
  4303. {$ENDIF}
  4304. end;
  4305. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  4306. function WSocket_shutdown(s: TSocket; how: Integer): Integer;
  4307. begin
  4308. {$IFNDEF NO_ADV_MT}
  4309. SafeIncrementCount;
  4310. try
  4311. {$ENDIF}
  4312. Result := WSocket_Synchronized_Shutdown(s, how);
  4313. {$IFNDEF NO_ADV_MT}
  4314. finally
  4315. SafeDecrementCount;
  4316. end;
  4317. {$ENDIF}
  4318. end;
  4319. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  4320. {$IFDEF CLR}
  4321. function WSocket_setsockopt(
  4322. s : TSocket;
  4323. level, optname : Integer;
  4324. var optval : Integer;
  4325. optlen : Integer): Integer; overload;
  4326. begin
  4327. Result := OverByteIcsWinsock.setsockopt_integer(
  4328. S, Level, OptName, OptVal, 4);
  4329. end;
  4330. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  4331. function WSocket_setsockopt(
  4332. s : TSocket;
  4333. level, optname : Integer;
  4334. var optval : ip_mreq;
  4335. optlen : Integer): Integer; overload;
  4336. begin
  4337. Result := OverByteIcsWinsock.setsockopt_ip_mreq(
  4338. S, Level, OptName, OptVal, 8);
  4339. end;
  4340. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  4341. function WSocket_setsockopt(
  4342. s : TSocket;
  4343. level, optname : Integer;
  4344. var optval : TInAddr;
  4345. optlen : Integer): Integer; overload;
  4346. begin
  4347. Result := OverByteIcsWinsock.setsockopt_tinaddr(
  4348. S, Level, OptName, OptVal, 4);
  4349. end;
  4350. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  4351. function WSocket_setsockopt(
  4352. s : TSocket;
  4353. level, optname : Integer;
  4354. var optval : TLinger;
  4355. optlen : Integer): Integer; overload;
  4356. begin
  4357. Result := OverByteIcsWinsock.setsockopt_tlinger(
  4358. S, Level, OptName, OptVal, 4);
  4359. end;
  4360. {$ENDIF}
  4361. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  4362. {$IFDEF WIN32}
  4363. function WSocket_setsockopt(s: TSocket; level, optname: Integer; optval: PAnsiChar;
  4364. optlen: Integer): Integer;
  4365. begin
  4366. {$IFNDEF NO_ADV_MT}
  4367. SafeIncrementCount;
  4368. try
  4369. {$ENDIF}
  4370. Result := WSocket_Synchronized_setsockopt(s, level, optname, optval, optlen);
  4371. {$IFNDEF NO_ADV_MT}
  4372. finally
  4373. SafeDecrementCount;
  4374. end;
  4375. {$ENDIF}
  4376. end;
  4377. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  4378. function WSocket_setsockopt(s: TSocket; level, optname: Integer; var optval: TLinger;
  4379. optlen: Integer): Integer;
  4380. begin
  4381. {$IFNDEF NO_ADV_MT}
  4382. SafeIncrementCount;
  4383. try
  4384. {$ENDIF}
  4385. Result := WSocket_Synchronized_setsockopt(s, level, optname, optval, optlen);
  4386. {$IFNDEF NO_ADV_MT}
  4387. finally
  4388. SafeDecrementCount;
  4389. end;
  4390. {$ENDIF}
  4391. end;
  4392. {$ENDIF}
  4393. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  4394. {$IFDEF CLR}
  4395. function WSocket_getsockopt(
  4396. s: TSocket; level, optname: Integer;
  4397. var optval: Integer; var optlen: Integer): Integer;
  4398. begin
  4399. Result := OverByteIcsWinsock.getsockopt_integer(
  4400. s, level, optname, optval, optlen);
  4401. end;
  4402. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  4403. function WSocket_getsockopt(
  4404. s: TSocket; level, optname: Integer;
  4405. var optval: ip_mreq; var optlen: Integer): Integer;
  4406. begin
  4407. Result := OverByteIcsWinsock.getsockopt_ip_mreq(
  4408. s, level, optname, optval, optlen);
  4409. end;
  4410. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  4411. function WSocket_getsockopt(
  4412. s: TSocket; level, optname: Integer;
  4413. var optval: TInAddr; var optlen: Integer): Integer;
  4414. begin
  4415. Result := OverByteIcsWinsock.getsockopt_tinaddr(
  4416. s, level, optname, optval, optlen);
  4417. end;
  4418. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  4419. function WSocket_getsockopt(
  4420. s: TSocket; level, optname: Integer;
  4421. var optval: TLinger; var optlen: Integer): Integer;
  4422. begin
  4423. Result := OverByteIcsWinsock.getsockopt_tlinger(
  4424. s, level, optname, optval, optlen);
  4425. end;
  4426. {$ENDIF}
  4427. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  4428. {$IFDEF WIN32}
  4429. function WSocket_getsockopt(
  4430. s: TSocket; level, optname: Integer;
  4431. optval: PAnsiChar; var optlen: Integer): Integer;
  4432. begin
  4433. {$IFNDEF NO_ADV_MT}
  4434. SafeIncrementCount;
  4435. try
  4436. {$ENDIF}
  4437. Result := WSocket_Synchronized_getsockopt(s, level, optname, optval, optlen);
  4438. {$IFNDEF NO_ADV_MT}
  4439. finally
  4440. SafeDecrementCount;
  4441. end;
  4442. {$ENDIF}
  4443. end;
  4444. {$ENDIF}
  4445. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  4446. function WSocket_sendto(
  4447. s : TSocket;
  4448. var Buf : TWSocketData;
  4449. len, flags : Integer;
  4450. var addrto : TSockAddr;
  4451. tolen : Integer): Integer;
  4452. begin
  4453. {$IFNDEF NO_ADV_MT}
  4454. SafeIncrementCount;
  4455. try
  4456. {$ENDIF}
  4457. Result := WSocket_Synchronized_sendto(s, Buf, len, flags, addrto, tolen);
  4458. {$IFNDEF NO_ADV_MT}
  4459. finally
  4460. SafeDecrementCount;
  4461. end;
  4462. {$ENDIF}
  4463. end;
  4464. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  4465. function WSocket_send(s: TSocket; var Buf : TWSocketData; len, flags: Integer): Integer;
  4466. begin
  4467. {$IFNDEF NO_ADV_MT}
  4468. SafeIncrementCount;
  4469. try
  4470. {$ENDIF}
  4471. Result := WSocket_Synchronized_send(s, Buf, len, flags);
  4472. {$IFNDEF NO_ADV_MT}
  4473. finally
  4474. SafeDecrementCount;
  4475. end;
  4476. {$ENDIF}
  4477. end;
  4478. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  4479. function WSocket_ntohs(netshort: u_short): u_short;
  4480. begin
  4481. {$IFNDEF NO_ADV_MT}
  4482. SafeIncrementCount;
  4483. try
  4484. {$ENDIF}
  4485. Result := WSocket_Synchronized_ntohs(netshort);
  4486. {$IFNDEF NO_ADV_MT}
  4487. finally
  4488. SafeDecrementCount;
  4489. end;
  4490. {$ENDIF}
  4491. end;
  4492. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  4493. function WSocket_ntohl(netlong: u_long): u_long;
  4494. begin
  4495. {$IFNDEF NO_ADV_MT}
  4496. SafeIncrementCount;
  4497. try
  4498. {$ENDIF}
  4499. Result := WSocket_Synchronized_ntohl(netlong);
  4500. {$IFNDEF NO_ADV_MT}
  4501. finally
  4502. SafeDecrementCount;
  4503. end;
  4504. {$ENDIF}
  4505. end;
  4506. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  4507. function WSocket_listen(s: TSocket; backlog: Integer): Integer;
  4508. begin
  4509. {$IFNDEF NO_ADV_MT}
  4510. SafeIncrementCount;
  4511. try
  4512. {$ENDIF}
  4513. Result := WSocket_Synchronized_listen(s, backlog);
  4514. {$IFNDEF NO_ADV_MT}
  4515. finally
  4516. SafeDecrementCount;
  4517. end;
  4518. {$ENDIF}
  4519. end;
  4520. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  4521. function WSocket_ioctlsocket(s: TSocket; cmd: DWORD; var arg: u_long): Integer;
  4522. begin
  4523. {$IFNDEF NO_ADV_MT}
  4524. SafeIncrementCount;
  4525. try
  4526. {$ENDIF}
  4527. Result := WSocket_Synchronized_ioctlsocket(s, cmd, arg);
  4528. {$IFNDEF NO_ADV_MT}
  4529. finally
  4530. SafeDecrementCount;
  4531. end;
  4532. {$ENDIF}
  4533. end;
  4534. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  4535. {$IFDEF WIN32}
  4536. {$IFDEF COMPILER2_UP}
  4537. function WSocket_WSAIoctl(
  4538. s : TSocket; IoControlCode : DWORD;
  4539. InBuffer : Pointer; InBufferSize : DWORD;
  4540. OutBuffer : Pointer; OutBufferSize : DWORD;
  4541. var BytesReturned : DWORD; Overlapped : POverlapped;
  4542. CompletionRoutine : FARPROC): Integer;
  4543. begin
  4544. {$IFNDEF NO_ADV_MT}
  4545. SafeIncrementCount;
  4546. try
  4547. {$ENDIF}
  4548. Result := WSocket_Synchronized_WSAIoctl(
  4549. s, IoControlCode, InBuffer, InBufferSize, OutBuffer,
  4550. OutBufferSize, BytesReturned, Overlapped, CompletionRoutine);
  4551. {$IFNDEF NO_ADV_MT}
  4552. finally
  4553. SafeDecrementCount;
  4554. end;
  4555. {$ENDIF}
  4556. end;
  4557. {$ENDIF}
  4558. {$ENDIF}
  4559. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  4560. {$IFDEF CLR}
  4561. function WSocket_inet_ntoa(inaddr: TInAddr): String;
  4562. begin
  4563. Result := OverByteIcsWinsock.inet_ntoa(inaddr);
  4564. end;
  4565. {$ENDIF}
  4566. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  4567. {$IFDEF WIN32}
  4568. function WSocket_inet_ntoa(inaddr: TInAddr): AnsiString;
  4569. var
  4570. Temp : PAnsiChar;
  4571. begin
  4572. {$IFNDEF NO_ADV_MT}
  4573. SafeIncrementCount;
  4574. try
  4575. {$ENDIF}
  4576. Temp := WSocket_Synchronized_inet_ntoa(inaddr);
  4577. if Temp = nil then
  4578. Result := ''
  4579. else
  4580. Result := Temp;
  4581. {$IFNDEF NO_ADV_MT}
  4582. finally
  4583. SafeDecrementCount;
  4584. end;
  4585. {$ENDIF}
  4586. end;
  4587. {$ENDIF}
  4588. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  4589. function WSocket_inet_addr(const cp: AnsiString): u_long;
  4590. begin
  4591. {$IFNDEF NO_ADV_MT}
  4592. SafeIncrementCount;
  4593. try
  4594. {$ENDIF}
  4595. Result := WSocket_Synchronized_inet_addr(cp);
  4596. {$IFNDEF NO_ADV_MT}
  4597. finally
  4598. SafeDecrementCount;
  4599. end;
  4600. {$ENDIF}
  4601. end;
  4602. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  4603. function WSocket_htons(hostshort: u_short): u_short;
  4604. begin
  4605. {$IFNDEF NO_ADV_MT}
  4606. SafeIncrementCount;
  4607. try
  4608. {$ENDIF}
  4609. Result := WSocket_Synchronized_htons(hostshort);
  4610. {$IFNDEF NO_ADV_MT}
  4611. finally
  4612. SafeDecrementCount;
  4613. end;
  4614. {$ENDIF}
  4615. end;
  4616. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  4617. function WSocket_htonl(hostlong: u_long): u_long;
  4618. begin
  4619. {$IFNDEF NO_ADV_MT}
  4620. SafeIncrementCount;
  4621. try
  4622. {$ENDIF}
  4623. Result := WSocket_Synchronized_htonl(hostlong);
  4624. {$IFNDEF NO_ADV_MT}
  4625. finally
  4626. SafeDecrementCount;
  4627. end;
  4628. {$ENDIF}
  4629. end;
  4630. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  4631. function WSocket_getsockname(
  4632. s : TSocket;
  4633. var name : TSockAddr;
  4634. var namelen : Integer): Integer;
  4635. begin
  4636. {$IFNDEF NO_ADV_MT}
  4637. SafeIncrementCount;
  4638. try
  4639. {$ENDIF}
  4640. Result := WSocket_Synchronized_getsockname(s, name, namelen);
  4641. {$IFNDEF NO_ADV_MT}
  4642. finally
  4643. SafeDecrementCount;
  4644. end;
  4645. {$ENDIF}
  4646. end;
  4647. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  4648. function WSocket_getpeername(
  4649. s : TSocket;
  4650. var name : TSockAddr;
  4651. var namelen : Integer): Integer;
  4652. begin
  4653. {$IFNDEF NO_ADV_MT}
  4654. SafeIncrementCount;
  4655. try
  4656. {$ENDIF}
  4657. Result := WSocket_Synchronized_getpeername(s, name, namelen);
  4658. {$IFNDEF NO_ADV_MT}
  4659. finally
  4660. SafeDecrementCount;
  4661. end;
  4662. {$ENDIF}
  4663. end;
  4664. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  4665. function WSocket_connect(
  4666. s : TSocket;
  4667. var name : TSockAddr;
  4668. namelen : Integer): Integer;
  4669. begin
  4670. {$IFNDEF NO_ADV_MT}
  4671. SafeIncrementCount;
  4672. try
  4673. {$ENDIF}
  4674. Result := WSocket_Synchronized_connect(s, name, namelen);
  4675. {$IFNDEF NO_ADV_MT}
  4676. finally
  4677. SafeDecrementCount;
  4678. end;
  4679. {$ENDIF}
  4680. end;
  4681. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  4682. function WSocket_closesocket(s: TSocket): Integer;
  4683. begin
  4684. {$IFNDEF NO_ADV_MT}
  4685. SafeIncrementCount;
  4686. try
  4687. {$ENDIF}
  4688. Result := WSocket_Synchronized_closesocket(s);
  4689. {$IFNDEF NO_ADV_MT}
  4690. finally
  4691. SafeDecrementCount;
  4692. end;
  4693. {$ENDIF}
  4694. end;
  4695. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  4696. function WSocket_bind(
  4697. s: TSocket;
  4698. var addr: TSockAddr;
  4699. namelen: Integer): Integer;
  4700. begin
  4701. {$IFNDEF NO_ADV_MT}
  4702. SafeIncrementCount;
  4703. try
  4704. {$ENDIF}
  4705. Result := WSocket_Synchronized_bind(s, addr, namelen);
  4706. {$IFNDEF NO_ADV_MT}
  4707. finally
  4708. SafeDecrementCount;
  4709. end;
  4710. {$ENDIF}
  4711. end;
  4712. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  4713. function WSocket_accept(
  4714. s: TSocket;
  4715. {$IFDEF DELPHI1} { Delphi 1 }
  4716. var addr: TSockAddr;
  4717. var addrlen: Integer): TSocket;
  4718. {$ELSE}
  4719. {$IFDEF VER90} { Delphi 2 }
  4720. var addr: TSockAddr;
  4721. var addrlen: Integer): TSocket;
  4722. {$ELSE}{ Delphi 3/4/5, Bcb 1/3/4 }
  4723. {$IFDEF CLR}
  4724. var addr: TSockAddr;
  4725. var addrlen: Integer): TSocket;
  4726. {$ELSE}
  4727. addr: PSockAddr;
  4728. addrlen: PInteger): TSocket;
  4729. {$ENDIF}
  4730. {$ENDIF}
  4731. {$ENDIF}
  4732. begin
  4733. {$IFNDEF NO_ADV_MT}
  4734. SafeIncrementCount;
  4735. try
  4736. {$ENDIF}
  4737. Result := WSocket_Synchronized_accept(s, addr, addrlen);
  4738. {$IFNDEF NO_ADV_MT}
  4739. finally
  4740. SafeDecrementCount;
  4741. end;
  4742. {$ENDIF}
  4743. end;
  4744. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  4745. function WSocket_recv(s: TSocket; var Buf : TWSocketData; len, flags: Integer): Integer;
  4746. begin
  4747. {$IFNDEF NO_ADV_MT}
  4748. SafeIncrementCount;
  4749. try
  4750. {$ENDIF}
  4751. Result := WSocket_Synchronized_recv(s, Buf, len, flags);
  4752. {$IFNDEF NO_ADV_MT}
  4753. finally
  4754. SafeDecrementCount;
  4755. end;
  4756. {$ENDIF}
  4757. end;
  4758. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  4759. function WSocket_recvfrom(
  4760. s: TSocket;
  4761. var Buf: TWSocketData; len, flags: Integer;
  4762. var from: TSockAddr;
  4763. var fromlen: Integer): Integer;
  4764. begin
  4765. {$IFNDEF NO_ADV_MT}
  4766. SafeIncrementCount;
  4767. try
  4768. {$ENDIF}
  4769. Result := WSocket_Synchronized_recvfrom(s, Buf, len, flags, from, fromlen);
  4770. {$IFNDEF NO_ADV_MT}
  4771. finally
  4772. SafeDecrementCount;
  4773. end;
  4774. {$ENDIF}
  4775. end;
  4776. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  4777. function TWSocketCounter.GetLastAliveTick : Cardinal;
  4778. (*
  4779. begin
  4780. if FLastRecvTick > FLastSendTick then
  4781. if FLastRecvTick > FConnectTick then
  4782. Result := FLastRecvTick
  4783. else
  4784. Result := FConnectTick
  4785. else
  4786. if FLastSendTick > FConnectTick then
  4787. Result := FLastSendTick
  4788. else
  4789. Result := FConnectTick;
  4790. *)
  4791. asm
  4792. mov ecx, [eax].FLastRecvTick
  4793. mov edx, [eax].FLastSendTick
  4794. mov eax, [eax].FConnectTick
  4795. cmp eax, edx
  4796. jb @below
  4797. mov edx, ecx
  4798. jmp @more
  4799. @below:
  4800. mov eax, ecx
  4801. @more:
  4802. cmp eax, edx
  4803. jb @done
  4804. ret
  4805. @done:
  4806. mov eax, edx
  4807. end;
  4808. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  4809. procedure TWSocketCounter.SetConnected;
  4810. begin
  4811. FLastRecvTick := 0;
  4812. FLastSendTick := 0;
  4813. FConnectTick := _GetTickCount;
  4814. FConnectDT := _Now;
  4815. end;
  4816. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  4817. {$IFDEF WIN32}
  4818. procedure TCustomWSocket.Notification(AComponent: TComponent; operation: TOperation);
  4819. begin
  4820. inherited Notification(AComponent, operation);
  4821. if operation = opRemove then begin
  4822. {$IFNDEF NO_DEBUG_LOG}
  4823. if AComponent = FIcsLogger then { V5.21 }
  4824. FIcsLogger := nil; { V5.21 }
  4825. {$ENDIF} { V5.21 }
  4826. end;
  4827. end;
  4828. {$ENDIF}
  4829. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  4830. procedure TCustomWSocket.AssignDefaultValue;
  4831. begin
  4832. //FillChar(sin, Sizeof(sin), 0);
  4833. sin.sin_family := AF_INET;
  4834. sin.sin_port := 0;
  4835. sin.sin_addr.S_addr := 0;
  4836. FAddrFormat := PF_INET;
  4837. FPortAssigned := FALSE;
  4838. FAddrAssigned := FALSE;
  4839. FAddrResolved := FALSE;
  4840. FPortResolved := FALSE;
  4841. FProtoResolved := FALSE;
  4842. FLocalPortResolved := FALSE;
  4843. FProtoAssigned := TRUE;
  4844. FProto := IPPROTO_TCP;
  4845. FProtoStr := 'tcp';
  4846. FType := SOCK_STREAM;
  4847. FLocalPortStr := '0';
  4848. FLocalAddr := '0.0.0.0';
  4849. FLingerOnOff := wsLingerOn;
  4850. FLingerTimeout := 0;
  4851. FHSocket := INVALID_SOCKET;
  4852. FSelectEvent := 0;
  4853. FState := wsClosed;
  4854. bAllSent := TRUE;
  4855. FPaused := FALSE;
  4856. { FReadCount := 0; V7.24 only reset when connection opened, not closed }
  4857. FCloseInvoked := FALSE;
  4858. FFlushTimeout := 60;
  4859. end;
  4860. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  4861. { All exceptions *MUST* be handled. If an exception is not handled, the }
  4862. { application will be shut down ! }
  4863. procedure TCustomWSocket.HandleBackGroundException(E: Exception);
  4864. var
  4865. CanAbort : Boolean;
  4866. begin
  4867. CanAbort := TRUE;
  4868. { First call the error event handler, if any }
  4869. if Assigned(FOnBgException) then begin
  4870. try
  4871. FOnBgException(Self, E, CanAbort);
  4872. except
  4873. end;
  4874. end;
  4875. { Then abort the socket }
  4876. if CanAbort then begin
  4877. try
  4878. Abort;
  4879. except
  4880. end;
  4881. end;
  4882. end;
  4883. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  4884. { This procedure handle all messages for TWSocket. All exceptions must be }
  4885. { handled or the application will be shutted down ! }
  4886. { If WndProc is overridden in descendent components, then the same exception }
  4887. { handling *MUST* be setup because descendent component code is executed }
  4888. { before the base class code. }
  4889. procedure TCustomWSocket.WndProc(var MsgRec: TMessage);
  4890. begin
  4891. try
  4892. with MsgRec do begin
  4893. if Msg = FMsg_WM_ASYNCSELECT then
  4894. WMASyncSelect(MsgRec)
  4895. else if Msg = FMsg_WM_ASYNCGETHOSTBYNAME then
  4896. WMAsyncGetHostByName(MsgRec)
  4897. else if Msg = FMsg_WM_ASYNCGETHOSTBYADDR then
  4898. WMAsyncGetHostByAddr(MsgRec)
  4899. else if Msg = FMsg_WM_CLOSE_DELAYED then
  4900. WMCloseDelayed(MsgRec)
  4901. // else if Msg = FMsg_WM_WSOCKET_RELEASE then
  4902. // WMRelease(MsgRec)
  4903. else if Msg = FMsg_WM_TRIGGER_EXCEPTION then
  4904. { This is useful to check for background exceptions }
  4905. { In your application, use following code to test your handler }
  4906. { PostMessage(WSocket1.Handle, WM_TRIGGER_EXCEPTION, 0, 0); }
  4907. raise ESocketException.Create('Test exception in WSocket')
  4908. else
  4909. inherited WndProc(MsgRec);
  4910. //Result := DefWindowProc(Handle, Msg, wParam, LParam);
  4911. end;
  4912. except
  4913. on E:Exception do
  4914. HandleBackGroundException(E);
  4915. end;
  4916. end;
  4917. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  4918. function TCustomWSocket.MsgHandlersCount : Integer;
  4919. begin
  4920. Result := 6 + inherited MsgHandlersCount;
  4921. end;
  4922. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  4923. procedure TCustomWSocket.AllocateMsgHandlers;
  4924. begin
  4925. inherited AllocateMsgHandlers;
  4926. FMsg_WM_ASYNCSELECT := FWndHandler.AllocateMsgHandler(Self);
  4927. FMsg_WM_ASYNCGETHOSTBYNAME := FWndHandler.AllocateMsgHandler(Self);
  4928. FMsg_WM_ASYNCGETHOSTBYADDR := FWndHandler.AllocateMsgHandler(Self);
  4929. FMsg_WM_CLOSE_DELAYED := FWndHandler.AllocateMsgHandler(Self);
  4930. FMsg_WM_TRIGGER_EXCEPTION := FWndHandler.AllocateMsgHandler(Self);
  4931. FMsg_WM_TRIGGER_DATA_AVAILABLE := FWndHandler.AllocateMsgHandler(Self);
  4932. // FMsg_WM_WSOCKET_RELEASE := FWndHandler.AllocateMsgHandler(Self);
  4933. end;
  4934. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  4935. procedure TCustomWSocket.FreeMsgHandlers;
  4936. begin
  4937. if Assigned(FWndHandler) then begin
  4938. FWndHandler.UnregisterMessage(FMsg_WM_ASYNCSELECT);
  4939. FWndHandler.UnregisterMessage(FMsg_WM_ASYNCGETHOSTBYNAME);
  4940. FWndHandler.UnregisterMessage(FMsg_WM_ASYNCGETHOSTBYADDR);
  4941. FWndHandler.UnregisterMessage(FMsg_WM_CLOSE_DELAYED);
  4942. FWndHandler.UnregisterMessage(FMsg_WM_TRIGGER_EXCEPTION);
  4943. FWndHandler.UnregisterMessage(FMsg_WM_TRIGGER_DATA_AVAILABLE);
  4944. end;
  4945. inherited FreeMsgHandlers;
  4946. end;
  4947. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  4948. procedure TCustomWSocket.AllocateSocketHWnd;
  4949. begin
  4950. inherited AllocateHWnd;
  4951. end;
  4952. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  4953. procedure TCustomWSocket.DeallocateSocketHWnd;
  4954. begin
  4955. inherited DeallocateHWnd;
  4956. end;
  4957. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  4958. {$IFDEF COMPILER2_UP}
  4959. procedure TCustomWSocket.ThreadAttach;
  4960. begin
  4961. inherited ThreadAttach;
  4962. if FHSocket <> INVALID_SOCKET then
  4963. WSocket_Synchronized_WSAASyncSelect(FHSocket, Handle,
  4964. FMsg_WM_ASYNCSELECT, FSelectEvent);
  4965. end;
  4966. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  4967. procedure TCustomWSocket.ThreadDetach;
  4968. begin
  4969. if (_GetCurrentThreadID = DWORD(FThreadID)) and (FHSocket <> INVALID_SOCKET) then
  4970. WSocket_Synchronized_WSAASyncSelect(FHSocket, Handle, 0, 0);
  4971. inherited ThreadDetach;
  4972. end;
  4973. {$ENDIF}
  4974. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  4975. constructor TCustomWSocket.Create{$IFDEF VCL}(AOwner: TComponent){$ENDIF};
  4976. begin
  4977. inherited Create{$IFDEF VCL}(AOwner){$ENDIF};
  4978. FHSocket := INVALID_SOCKET; { FP: 18/01/2007 }
  4979. AllocateSocketHWnd;
  4980. FBufHandler := TIcsBufferHandler.Create(Self);
  4981. FBufHandler.BufSize := 1460; {1514;} { Default buffer size }
  4982. FDnsResultList := TStringList.Create;
  4983. FMultiCastIpTTL := IP_DEFAULT_MULTICAST_TTL;
  4984. ListenBacklog := 5;
  4985. FBufferedByteCount := 0; { V5.20 }
  4986. FMultiCastAddrStr := '';
  4987. FAddrStr := '';
  4988. FPortStr := '';
  4989. FCounterClass := TWSocketCounter;
  4990. AssignDefaultValue;
  4991. {$IFDEF COMPILER2_UP}
  4992. _EnterCriticalSection(GWSockCritSect);
  4993. try
  4994. {$ENDIF}
  4995. Inc(WSocketGCount);
  4996. {$IFDEF COMPILER2_UP}
  4997. finally
  4998. _LeaveCriticalSection(GWSockCritSect);
  4999. end;
  5000. {$ENDIF}
  5001. end;
  5002. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  5003. destructor TCustomWSocket.Destroy;
  5004. begin
  5005. try
  5006. CancelDnsLookup; { Cancel any pending dns lookup }
  5007. except
  5008. { Ignore any exception here }
  5009. end;
  5010. if FState <> wsInvalidState then begin { FPiette V7.42 }
  5011. { wsInvalidState happend when an exception is raised early in the constructor }
  5012. { Close the socket if not yet closed }
  5013. if FState <> wsClosed then
  5014. Close;
  5015. {$IFDEF COMPILER2_UP}
  5016. _EnterCriticalSection(GWSockCritSect);
  5017. try
  5018. {$ENDIF}
  5019. Dec(WSocketGCount);
  5020. if WSocketGCount <= 0 then begin
  5021. WSocketUnloadWinsock;
  5022. { WSocketGCount := 0; // it is set to 0 in WSocketUnloadWinsock }
  5023. end;
  5024. {$IFDEF COMPILER2_UP}
  5025. finally
  5026. _LeaveCriticalSection(GWSockCritSect);
  5027. end;
  5028. {$ENDIF}
  5029. end;
  5030. if Assigned(FBufHandler) then begin
  5031. FBufHandler.Free;
  5032. FBufHandler := nil;
  5033. end;
  5034. if Assigned(FDnsResultList) then begin
  5035. FDnsResultList.Free;
  5036. FDnsResultList := nil;
  5037. end;
  5038. if Assigned(FCounter) then begin
  5039. FCounter.Free;
  5040. FCounter := nil;
  5041. end;
  5042. inherited Destroy;
  5043. end;
  5044. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  5045. procedure TCustomWSocket.CreateCounter;
  5046. begin
  5047. if Assigned(FCounter) then
  5048. _FreeAndNil(FCounter);
  5049. FCounter := FCounterClass.Create;
  5050. end;
  5051. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  5052. procedure TCustomWSocket.DestroyCounter;
  5053. begin
  5054. _FreeAndNil(FCounter);
  5055. end;
  5056. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  5057. procedure TCustomWSocket.SetCounterClass(const Value: TWSocketCounterClass);
  5058. var
  5059. NewCounter : TWSocketCounter;
  5060. begin
  5061. if Value = nil then
  5062. raise ESocketException.Create('Property CounterClass may not be nil!');
  5063. if Value <> FCounterClass then begin
  5064. FCounterClass := Value;
  5065. if Assigned(FCounter) then begin
  5066. NewCounter := FCounterClass.Create;
  5067. NewCounter.ConnectDT := FCounter.ConnectDT;
  5068. NewCounter.ConnectTick := FCounter.ConnectTick;
  5069. NewCounter.LastRecvTick := FCounter.LastRecvTick;
  5070. NewCounter.LastSendTick := FCounter.LastSendTick;
  5071. FCounter.Free;
  5072. FCounter := NewCounter;
  5073. end;
  5074. end;
  5075. end;
  5076. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  5077. function TCustomWSocket.GetReqVerLow: BYTE;
  5078. begin
  5079. Result := GReqVerLow;
  5080. end;
  5081. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  5082. procedure TCustomWSocket.SetReqVerLow(const Value: BYTE);
  5083. begin
  5084. if GReqVerLow <> Value then begin
  5085. if FDllHandle <> 0 then
  5086. SocketError('SetReqVerLow: WinSock version can''t be changed now')
  5087. else
  5088. GReqVerLow := Value;
  5089. end;
  5090. end;
  5091. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  5092. function TCustomWSocket.GetReqVerHigh: BYTE;
  5093. begin
  5094. Result := GReqVerHigh;
  5095. end;
  5096. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  5097. procedure TCustomWSocket.SetReqVerHigh(const Value: BYTE);
  5098. begin
  5099. if GReqVerHigh <> Value then begin
  5100. if FDllHandle <> 0 then
  5101. SocketError('SetReqVerHigh: WinSock version can''t be changed now')
  5102. else
  5103. GReqVerHigh := Value;
  5104. end;
  5105. end;
  5106. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  5107. procedure TCustomWSocket.Dup(NewHSocket : TSocket);
  5108. var
  5109. iStatus : Integer;
  5110. optlen : Integer;
  5111. begin
  5112. {$IFDEF CLR}
  5113. if DesignMode then begin
  5114. FHsocket := NewHSocket;
  5115. Exit;
  5116. end;
  5117. {$ENDIF}
  5118. if (NewHSocket = 0) or (NewHSocket = INVALID_SOCKET) then begin
  5119. WSocket_Synchronized_WSASetLastError(WSAEINVAL);
  5120. SocketError('Dup');
  5121. Exit;
  5122. end;
  5123. if FState <> wsClosed then begin
  5124. iStatus := WSocket_Synchronized_closesocket(FHSocket);
  5125. FHSocket := INVALID_SOCKET;
  5126. if iStatus <> 0 then begin
  5127. SocketError('Dup (closesocket)');
  5128. Exit;
  5129. end;
  5130. ChangeState(wsClosed);
  5131. end;
  5132. FHsocket := NewHSocket;
  5133. { Get winsock send buffer size }
  5134. optlen := SizeOf(FSocketSndBufSize);
  5135. {$IFDEF CLR}
  5136. iStatus := WSocket_getsockopt(FHSocket, SOL_SOCKET, SO_SNDBUF,
  5137. FSocketSndBufSize, optlen);
  5138. {$ELSE}
  5139. iStatus := WSocket_getsockopt(FHSocket, SOL_SOCKET, SO_SNDBUF,
  5140. PAnsiChar(@FSocketSndBufSize), optlen);
  5141. {$ENDIF}
  5142. if iStatus <> 0 then begin
  5143. SocketError('getsockopt(SO_SNDBUF)');
  5144. Exit;
  5145. end;
  5146. { Get winsock receive buffer size }
  5147. optlen := SizeOf(FSocketRcvBufSize);
  5148. {$IFDEF CLR}
  5149. iStatus := WSocket_getsockopt(FHSocket, SOL_SOCKET, SO_RCVBUF,
  5150. FSocketRcvBufSize, optlen);
  5151. {$ELSE}
  5152. iStatus := WSocket_getsockopt(FHSocket, SOL_SOCKET, SO_RCVBUF,
  5153. PAnsiChar(@FSocketRcvBufSize), optlen);
  5154. {$ENDIF}
  5155. if iStatus <> 0 then begin
  5156. SocketError('getsockopt(SO_RCVBUF)');
  5157. Exit;
  5158. end;
  5159. if HasOption(FComponentOptions, wsoTcpNoDelay) and { V7.27 }
  5160. (not SetTcpNoDelayOption) then
  5161. Exit;
  5162. SetLingerOption;
  5163. SetKeepAliveOption; // AG { 05/23/07)
  5164. { FD_CONNECT is not needed for dup(): The socket is already connected }
  5165. FSelectEvent := FD_READ or FD_WRITE or FD_CLOSE { or FD_CONNECT };
  5166. iStatus := WSocket_Synchronized_WSAASyncSelect(FHSocket, Handle,
  5167. FMsg_WM_ASYNCSELECT,
  5168. FSelectEvent);
  5169. if iStatus <> 0 then begin
  5170. SocketError('WSAAsyncSelect');
  5171. Exit;
  5172. end;
  5173. DupConnected;
  5174. end;
  5175. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  5176. procedure TCustomWSocket.DupConnected;
  5177. begin
  5178. if Assigned(FCounter) then
  5179. FCounter.SetConnected;
  5180. FReadCount := 0; { 7.24 }
  5181. FWriteCount := 0; { 7.24 }
  5182. ChangeState(wsConnected);
  5183. end;
  5184. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  5185. procedure TCustomWSocket.SetBufSize(Value : Integer);
  5186. begin
  5187. FBufHandler.BufSize := Value;
  5188. end;
  5189. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  5190. function TCustomWSocket.GetBufSize: Integer;
  5191. begin
  5192. Result := FBufHandler.BufSize;
  5193. end;
  5194. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  5195. { Get the number of char received and waiting to be read }
  5196. function TCustomWSocket.GetRcvdCount : LongInt;
  5197. var
  5198. Temp : u_long;
  5199. begin
  5200. {$IFDEF CLR}
  5201. if DesignMode then begin
  5202. {$ENDIF}
  5203. {$IFDEF WIN32}
  5204. if csDesigning in ComponentState then begin
  5205. {$ENDIF}
  5206. Result := -1;
  5207. Exit;
  5208. end;
  5209. if WSocket_Synchronized_ioctlsocket(FHSocket, FIONREAD, Temp) = SOCKET_ERROR then begin
  5210. Result := -1;
  5211. SocketError('ioctlSocket');
  5212. Exit;
  5213. end;
  5214. Result := LongInt(Temp);
  5215. end;
  5216. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  5217. procedure TCustomWSocket.ChangeState(NewState : TSocketState);
  5218. var
  5219. OldState : TSocketState;
  5220. begin
  5221. OldState := FState;
  5222. FState := NewState;
  5223. if OldState <> NewState then { 20030226 }
  5224. TriggerChangeState(OldState, NewState);
  5225. end;
  5226. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  5227. { DoRecv is a simple wrapper around winsock recv function to make it }
  5228. { a virtual function. }
  5229. function TCustomWSocket.DoRecv(
  5230. var Buffer : TWSocketData;
  5231. BufferSize : Integer;
  5232. Flags : Integer) : Integer;
  5233. begin
  5234. { MoulinCnt := (MoulinCnt + 1) and 3; }
  5235. { Write('R', Moulin[MoulinCnt], #13); }
  5236. Result := WSocket_Synchronized_recv(FHSocket, Buffer, BufferSize, Flags);
  5237. { FRcvdFlag := (Result > 0);}
  5238. { If we received the requested size, we may need to receive more }
  5239. FRcvdFlag := (Result >= BufferSize);
  5240. if Assigned(FCounter) and (Result > 0) then
  5241. FCounter.FLastRecvTick := _GetTickCount;
  5242. end;
  5243. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  5244. { The socket is non-blocking, so this routine will only receive as much }
  5245. { data as it is available. }
  5246. function TCustomWSocket.Receive(Buffer : TWSocketData; BufferSize: Integer) : Integer;
  5247. begin
  5248. Result := DoRecv(Buffer, BufferSize, 0);
  5249. if Result < 0 then
  5250. FLastError := WSocket_Synchronized_WSAGetLastError
  5251. else
  5252. { Here we should check for overflows ! It is well possible to }
  5253. { receive more than 2GB during a single session. }
  5254. { Or we could use an Int64 variable... }
  5255. FReadCount := FReadCount + Result;
  5256. end;
  5257. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  5258. {$IFDEF COMPILER12_UP}
  5259. function TCustomWSocket.ReceiveStrW(ACodePage : LongWord) : UnicodeString;
  5260. begin
  5261. Result := AnsiToUniCode(ReceiveStrA, ACodePage);
  5262. end;
  5263. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  5264. function TCustomWSocket.ReceiveStrW : UnicodeString;
  5265. begin
  5266. Result := ReceiveStrW(CP_ACP);
  5267. end;
  5268. {$ENDIF}
  5269. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  5270. function TCustomWSocket.ReceiveStrA : AnsiString;
  5271. var
  5272. lCount : LongInt;
  5273. begin
  5274. lCount := GetRcvdCount;
  5275. if lCount < 0 then begin { GetRcvdCount returned an error }
  5276. SetLength(Result, 0);
  5277. Exit;
  5278. end;
  5279. if lCount = 0 then { GetRcvdCount say nothing, will try anyway }
  5280. LCount := 255; { some reasonable arbitrary value }
  5281. {$IFDEF CLR}
  5282. if Length(FRecvStrBuf) < 1460 then
  5283. SetLength(FRecvStrBuf, 1460);
  5284. if Length(FRecvStrBuf) < lCount then
  5285. SetLength(FRecvStrBuf, lCount);
  5286. lCount := Receive(FRecvStrBuf, Length(FRecvStrBuf));
  5287. if lCount <= 0 then
  5288. Result := ''
  5289. else begin
  5290. Result := System.Text.Encoding.Default.GetString(FRecvStrBuf, 0, lCount);
  5291. // SetLength(Result, lCount);
  5292. // while lCount > 0 do begin
  5293. // Dec(lCount);
  5294. // Result[lCount + 1] := Char(FRecvStrBuf[lCount]);
  5295. // end;
  5296. end;
  5297. {$ENDIF}
  5298. {$IFDEF WIN32}
  5299. SetLength(Result, lCount);
  5300. lCount := Receive(@Result[1], lCount);
  5301. if lCount > 0 then
  5302. SetLength(Result, lCount)
  5303. else
  5304. SetLength(Result, 0);
  5305. {$ENDIF}
  5306. end;
  5307. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  5308. { Receive as much data as possible into a string }
  5309. { You should avoid this function and use Receive. Using string will be }
  5310. { much slower because data will be copied several times. }
  5311. { ReceiveStr will *NOT* wait for a line to be received. It just read }
  5312. { already received characters and return them as a string. }
  5313. function TCustomWSocket.ReceiveStr : String;
  5314. begin
  5315. {$IFDEF COMPILER12_UP}
  5316. Result := ReceiveStrW;
  5317. {$ELSE}
  5318. Result := ReceiveStrA;
  5319. {$ENDIF}
  5320. end;
  5321. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  5322. function TCustomWSocket.DoRecvFrom(
  5323. FHSocket : TSocket;
  5324. var Buffer : TWSocketData;
  5325. BufferSize : Integer;
  5326. Flags : Integer;
  5327. var From : TSockAddr;
  5328. var FromLen : Integer) : Integer;
  5329. begin
  5330. Result := WSocket_Synchronized_recvfrom(FHSocket, Buffer, BufferSize,
  5331. Flags, From, FromLen);
  5332. { FRcvdFlag := (Result > 0); }
  5333. FRcvdFlag := (Result >= BufferSize);
  5334. end;
  5335. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  5336. function TCustomWSocket.ReceiveFrom(
  5337. Buffer : TWSocketData;
  5338. BufferSize : Integer;
  5339. var From : TSockAddr;
  5340. var FromLen : Integer) : Integer;
  5341. begin
  5342. Result := DoRecvFrom(FHSocket, Buffer, BufferSize, 0, From, FromLen);
  5343. if Result < 0 then
  5344. FLastError := WSocket_Synchronized_WSAGetLastError
  5345. else
  5346. FReadCount := FReadCount + Result;
  5347. end;
  5348. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  5349. function TCustomWSocket.PeekData(Buffer : TWSocketData; BufferSize: Integer) : Integer;
  5350. begin
  5351. Result := DoRecv(Buffer, BufferSize, MSG_PEEK);
  5352. if Result < 0 then
  5353. FLastError := WSocket_Synchronized_WSAGetLastError;
  5354. end;
  5355. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  5356. {
  5357. function SearchChar(Data : PChar; Len : Integer; Ch : Char) : PChar;
  5358. begin
  5359. while Len > 0 do begin
  5360. Len := Len - 1;
  5361. if Data^ = Ch then begin
  5362. Result := Data;
  5363. exit;
  5364. end;
  5365. Data := Data + 1;
  5366. end;
  5367. Result := nil;
  5368. end;
  5369. }
  5370. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  5371. { This function should be used with UDP only. Use Send for TCP. }
  5372. function TCustomWSocket.SendTo(
  5373. Dest : TSockAddr;
  5374. DestLen : Integer;
  5375. {$IFDEF CLR} const {$ENDIF} Data : TWSocketData;
  5376. Len : Integer) : Integer;
  5377. begin
  5378. Result := WSocket_Synchronized_SendTo(FHSocket, Data, Len, FSendFlags,
  5379. TSockAddr(Dest), DestLen);
  5380. if Result > 0 then begin
  5381. FWriteCount := FWriteCount + Result; { 7.24 }
  5382. TriggerSendData(Result);
  5383. { Post FD_WRITE message to have OnDataSent event triggered }
  5384. if bAllSent and (FType = SOCK_DGRAM) then
  5385. _PostMessage(Handle,
  5386. FMsg_WM_ASYNCSELECT,
  5387. FHSocket,
  5388. MakeLong(FD_WRITE, 0));
  5389. end;
  5390. end;
  5391. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  5392. function TCustomWSocket.RealSend(var Data : TWSocketData; Len : Integer) : Integer;
  5393. begin
  5394. { MoulinCnt := (MoulinCnt + 1) and 3; }
  5395. { Write('S', Moulin[MoulinCnt], #13); }
  5396. if FType = SOCK_DGRAM then
  5397. Result := WSocket_Synchronized_SendTo(FHSocket, Data, Len, FSendFlags,
  5398. TSockAddr(sin), SizeOf(sin))
  5399. else
  5400. Result := WSocket_Synchronized_Send(FHSocket, Data, Len, FSendFlags);
  5401. if Result > 0 then begin
  5402. FWriteCount := FWriteCount + Result; { 7.24 }
  5403. if Assigned(FCounter) then
  5404. FCounter.FLastSendTick := _GetTickCount;
  5405. TriggerSendData(Result);
  5406. end;
  5407. end;
  5408. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  5409. procedure TCustomWSocket.TryToSend;
  5410. var
  5411. Len : Integer;
  5412. Count : Integer;
  5413. Data : TWSocketData;
  5414. LastError : Integer;
  5415. begin
  5416. FBufHandler.Lock;
  5417. try
  5418. if (FHSocket = INVALID_SOCKET) or (FBufHandler.IsEmpty) then begin
  5419. bAllSent := TRUE;
  5420. Exit;
  5421. end;
  5422. while TRUE do begin
  5423. Len := FBufHandler.Peek(Data);
  5424. if Len <= 0 then begin
  5425. // Buffer is empty, every thing has been sent
  5426. bAllSent := TRUE;
  5427. break;
  5428. end;
  5429. Count := RealSend(Data, Len);
  5430. if Count > 0 then begin
  5431. Dec(FBufferedByteCount, Count);
  5432. if FBufferedByteCount < 0 then
  5433. FBufferedByteCount := 0;
  5434. end;
  5435. if Count = 0 then
  5436. break; // Closed by remote
  5437. if Count = SOCKET_ERROR then begin
  5438. LastError := WSocket_Synchronized_WSAGetLastError;
  5439. if (LastError = WSAECONNRESET) or (LastError = WSAENOTSOCK) or
  5440. (LastError = WSAENOTCONN) or (LastError = WSAEINVAL) or
  5441. (LastError = WSAECONNABORTED) { 07/05/99 }
  5442. then begin
  5443. {$IFNDEF NO_DEBUG_LOG}
  5444. if CheckLogOptions(loWsockErr) then { V5.21 } { replaces $IFDEF DEBUG_OUTPUT }
  5445. DebugLog(loWsockErr, Name +
  5446. ' Winsock Send failed - ' +
  5447. GetWinsockErr(LastError));
  5448. {$ENDIF}
  5449. FCloseInvoked := TRUE; { 23/07/98 }
  5450. Close;
  5451. TriggerSessionClosed(LastError); { 23/07/98 }
  5452. end
  5453. else if LastError <> WSAEWOULDBLOCK then begin
  5454. SocketError('TryToSend failed');
  5455. break;
  5456. end;
  5457. break;
  5458. end;
  5459. FBufHandler.Remove(Count);
  5460. if Count < Len then
  5461. break; // Could not write as much as we wanted. Stop sending
  5462. end;
  5463. finally
  5464. FBufHandler.UnLock;
  5465. end;
  5466. end;
  5467. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  5468. function TCustomWSocket.PutStringInSendBuffer(const Str : RawByteString): Integer;
  5469. {$IFDEF CLR}
  5470. var
  5471. Data : TBytes;
  5472. I : Integer;
  5473. begin
  5474. SetLength(Data, Length(Str));
  5475. for I := 1 to Length(Str) do
  5476. Data[I - 1] := Ord(Str[I]);
  5477. PutDataInSendBuffer(Data, Length(Str));
  5478. {$ENDIF}
  5479. {$IFDEF WIN32}
  5480. begin
  5481. Result := Length(Str);
  5482. if Result > 0 then
  5483. PutDataInSendBuffer(Pointer(Str), Result);
  5484. {$ENDIF}
  5485. end;
  5486. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  5487. {$IFDEF COMPILER12_UP}
  5488. function TCustomWSocket.PutStringInSendBuffer(const Str : UnicodeString; ACodePage : LongWord): Integer;
  5489. begin
  5490. Result := PutStringInSendBuffer(UnicodeToAnsi(Str, ACodePage)); // Explicit cast
  5491. end;
  5492. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  5493. function TCustomWSocket.PutStringInSendBuffer(const Str : UnicodeString): Integer;
  5494. begin
  5495. Result := PutStringInSendBuffer(AnsiString(Str)); // Explicit cast
  5496. end;
  5497. {$ENDIF}
  5498. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  5499. procedure TCustomWSocket.PutDataInSendBuffer(
  5500. Data : TWSocketData;
  5501. Len : Integer);
  5502. begin
  5503. if (Len <= 0) or (Data = nil) then
  5504. Exit;
  5505. FBufHandler.Lock;
  5506. try
  5507. FBufHandler.Write(Data, Len);
  5508. Inc(FBufferedByteCount, Len);
  5509. bAllSent := FALSE;
  5510. finally
  5511. FBufHandler.UnLock;
  5512. end;
  5513. end;
  5514. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  5515. { Return -1 if error, else return number of byte written }
  5516. function TCustomWSocket.Send({$IFDEF CLR} const {$ENDIF} Data : TWSocketData; Len : Integer) : Integer;
  5517. begin
  5518. if (FState <> wsConnected) and (FState <> wsSocksConnected) then begin
  5519. WSocket_Synchronized_WSASetLastError(WSAENOTCONN);
  5520. SocketError('Send');
  5521. Result := -1;
  5522. Exit;
  5523. end;
  5524. bAllSent := FALSE;
  5525. if Len <= 0 then
  5526. Result := 0
  5527. else begin
  5528. Result := Len;
  5529. PutDataInSendBuffer(Data, Len);
  5530. end;
  5531. if bAllSent then
  5532. Exit;
  5533. TryToSend;
  5534. if bAllSent then begin
  5535. { We post a message to fire the FD_WRITE message wich in turn will }
  5536. { fire the OnDataSent event. We cannot fire the event ourself }
  5537. { because the event handler will eventually call send again. }
  5538. { Sending the message prevent recursive call and stack overflow. }
  5539. { The PostMessage function posts (places) a message in a window's }
  5540. { message queue and then returns without waiting for the }
  5541. { corresponding window to process the message. The message will be }
  5542. { seen and routed by Delphi a litle later, when we will be out of }
  5543. { the send function. }
  5544. _PostMessage(Handle,
  5545. FMsg_WM_ASYNCSELECT,
  5546. FHSocket,
  5547. MakeLong(FD_WRITE, 0));
  5548. end;
  5549. end;
  5550. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  5551. function TCustomWSocket.Send(DataByte : Byte) : Integer;
  5552. {$IFDEF CLR}
  5553. var
  5554. Buf : TBytes;
  5555. begin
  5556. SetLength(Buf, 1);
  5557. Buf[1] := DataByte;
  5558. Result := Send(Buf, 1);
  5559. SetLength(Buf, 0);
  5560. end;
  5561. {$ENDIF}
  5562. {$IFDEF WIN32}
  5563. begin
  5564. Result := Send(@DataByte, 1);
  5565. end;
  5566. {$ENDIF}
  5567. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  5568. { Return -1 if error, else return number of bytes written }
  5569. {$IFDEF COMPILER12_UP}
  5570. function TCustomWSocket.SendStr(const Str : UnicodeString; ACodePage : LongWord) : Integer;
  5571. begin
  5572. Result := SendStr(UnicodeToAnsi(Str, ACodePage));
  5573. end;
  5574. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  5575. { Converts UnicodeString to AnsiString using System.DefaultSystemCodePage }
  5576. function TCustomWSocket.SendStr(const Str : UnicodeString) : Integer;
  5577. begin
  5578. Result := SendStr(AnsiString(Str)); // RTL convert
  5579. end;
  5580. {$ENDIF}
  5581. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  5582. { Return -1 if error, else return number of byte written }
  5583. function TCustomWSocket.SendStr(const Str : RawByteString) : Integer;
  5584. begin
  5585. Result := Length(Str);
  5586. if Result > 0 then
  5587. Result := Send({$IFDEF CLR}
  5588. System.Text.Encoding.Default.GetBytes(Str),
  5589. {$ENDIF}
  5590. {$IFDEF WIN32}
  5591. PAnsiChar(Str),
  5592. {$ENDIF}
  5593. Result);
  5594. end;
  5595. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  5596. procedure TCustomWSocket.SendText(const Str : RawByteString);
  5597. begin
  5598. SendStr(Str);
  5599. end;
  5600. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  5601. {$IFDEF COMPILER12_UP}
  5602. procedure TCustomWSocket.SendText(const Str : UnicodeString);
  5603. begin
  5604. SendStr(AnsiString(Str));
  5605. end;
  5606. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  5607. procedure TCustomWSocket.SendText(const Str : UnicodeString; ACodePage : LongWord);
  5608. begin
  5609. SendStr(Str, ACodePage);
  5610. end;
  5611. {$ENDIF}
  5612. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  5613. function HasOption(
  5614. OptSet : TWSocketOptions;
  5615. Opt : TWSocketOption): Boolean;
  5616. begin
  5617. {$IFDEF CLR}
  5618. Result := (Ord(OptSet) and Ord(Opt)) <> 0;
  5619. {$ENDIF}
  5620. {$IFDEF WIN32}
  5621. Result := Opt in OptSet;
  5622. {$ENDIF}
  5623. end;
  5624. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  5625. function AddOptions(Opts: array of TWSocketOption): TWSocketOptions;
  5626. var
  5627. I : Integer;
  5628. begin
  5629. {$IFDEF CLR}
  5630. Result := wsoNone;
  5631. for I := Low(Opts) to High(Opts) do
  5632. Result := TWSocketOptions(Integer(Result) + Integer(Opts[I]));
  5633. {$ENDIF}
  5634. {$IFDEF WIN32}
  5635. Result := [];
  5636. for I := Low(Opts) to High(Opts) do
  5637. //Result := Result + [Opts[I]]; { Anton Sviridov }
  5638. Include(Result, Opts[I]);
  5639. {$ENDIF}
  5640. end;
  5641. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  5642. function RemoveOption(
  5643. OptSet : TWSocketOptions;
  5644. Opt : TWSocketOption) : TWSocketOptions;
  5645. begin
  5646. {$IFDEF CLR}
  5647. Result := TWSocketOptions(Ord(OptSet) and (not Ord(Opt)));
  5648. {$ENDIF}
  5649. {$IFDEF WIN32}
  5650. Result := OptSet - [Opt];
  5651. {$ENDIF}
  5652. end;
  5653. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  5654. procedure TCustomWSocket.ASyncReceive(
  5655. Error : Word;
  5656. MySocketOptions : TWSocketOptions);
  5657. var
  5658. bMore : Boolean;
  5659. lCount : {$IFDEF FPC} LongWord; {$ELSE} u_long; {$ENDIF}
  5660. {$IFDEF WIN32}
  5661. TrashCanBuf : array [0..1023] of AnsiChar; { AG 1/12/08 }
  5662. {$ENDIF}
  5663. TrashCan : TWSocketData;
  5664. TrashCanSize : Integer;
  5665. begin
  5666. bMore := TRUE;
  5667. while bMore do begin
  5668. FLastError := 0;
  5669. try
  5670. if not TriggerDataAvailable(Error) then begin
  5671. { Nothing wants to receive, we will receive and throw away 23/07/98 }
  5672. {$IFDEF CLR}
  5673. TrashCanSize := 1024;
  5674. SetLength(TrashCan, TrashCanSize);
  5675. {$ENDIF}
  5676. {$IFDEF WIN32}
  5677. TrashCanSize := SizeOf(TrashCan);
  5678. TrashCan := @TrashCanBuf;
  5679. {$ENDIF}
  5680. if DoRecv(TrashCan, TrashCanSize, 0) = SOCKET_ERROR then begin
  5681. FLastError := WSocket_Synchronized_WSAGetLastError;
  5682. if FLastError = WSAEWOULDBLOCK then begin
  5683. FLastError := 0;
  5684. break;
  5685. end;
  5686. end;
  5687. end;
  5688. { DLR Honor the socket options being passed as parameters }
  5689. if HasOption({FComponentOptions}MySocketOptions, wsoNoReceiveLoop) then { V6.03 }
  5690. break;
  5691. if FLastError <> 0 then begin
  5692. bMore := FALSE;
  5693. { -1 value is not a true error but is used to break the loop }
  5694. if FLastError = -1 then
  5695. FLastError := 0;
  5696. end
  5697. { Check if we have something new arrived, if yes, process it }
  5698. else if WSocket_Synchronized_ioctlsocket(FHSocket, FIONREAD,
  5699. lCount) = SOCKET_ERROR then begin
  5700. FLastError := WSocket_Synchronized_WSAGetLastError;
  5701. bMore := FALSE;
  5702. end
  5703. else if lCount = 0 then
  5704. bMore := FALSE;
  5705. except
  5706. bMore := FALSE;
  5707. end;
  5708. end;
  5709. end;
  5710. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  5711. procedure TCustomWSocket.Do_FD_CONNECT(var msg: TMessage);
  5712. begin
  5713. if FState <> wsConnected then begin
  5714. ChangeState(wsConnected);
  5715. TriggerSessionConnectedSpecial(HiWord(msg.LParam));
  5716. if (HiWord(msg.LParam) <> 0) and (FState <> wsClosed) then
  5717. Close;
  5718. end;
  5719. end;
  5720. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  5721. procedure TCustomWSocket.Do_FD_READ(var msg: TMessage);
  5722. begin
  5723. if FState <> wsConnected then begin
  5724. ChangeState(wsConnected);
  5725. TriggerSessionConnectedSpecial(HiWord(msg.LParam));
  5726. end;
  5727. ASyncReceive(HiWord(msg.LParam), FComponentOptions);
  5728. end;
  5729. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  5730. procedure TCustomWSocket.Do_FD_WRITE(var msg: TMessage);
  5731. begin
  5732. TryToSend;
  5733. { If you wants to test background exception, uncomment the next 2 lines. }
  5734. { if bAllSent then }
  5735. { raise Exception.Create('Test TWSocket exception'); }
  5736. if bAllSent then
  5737. TriggerDataSent(HiWord(msg.LParam));
  5738. end;
  5739. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  5740. procedure TCustomWSocket.Do_FD_CLOSE(var msg: TMessage);
  5741. begin
  5742. { In some strange situations I found that we receive a FD_CLOSE }
  5743. { during the connection phase, breaking the connection early ! }
  5744. { This occurs for example after a failed FTP transfert Probably }
  5745. { something related to bugged winsock. Doesn't hurt with good }
  5746. { winsock. So let the code there ! }
  5747. if (FState <> wsConnecting) and (FHSocket <> INVALID_SOCKET) then begin
  5748. { Check if we have something arrived, if yes, process it }
  5749. { DLR, since we are closing MAKE SURE WE LOOP in the receive }
  5750. { function to get ALL remaining data }
  5751. ASyncReceive(0, RemoveOption(FComponentOptions, wsoNoReceiveLoop));
  5752. if not FCloseInvoked then begin
  5753. FCloseInvoked := TRUE;
  5754. TriggerSessionClosed(HiWord(msg.LParam));
  5755. end;
  5756. if FState <> wsClosed then
  5757. Close;
  5758. end;
  5759. end;
  5760. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  5761. procedure TCustomWSocket.Do_FD_ACCEPT(var msg: TMessage);
  5762. begin
  5763. TriggerSessionAvailable(HiWord(msg.LParam));
  5764. end;
  5765. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  5766. {$IFNDEF NO_DEBUG_LOG}
  5767. function WinsockMsgToString(var msg: TMessage) : String;
  5768. begin
  5769. Result := '';
  5770. if (msg.lParam and FD_CONNECT) <> 0 then
  5771. Result := Result + ' FD_CONNECT';
  5772. if (msg.lParam and FD_READ) <> 0 then
  5773. Result := Result + ' FD_READ';
  5774. if (msg.lParam and FD_WRITE) <> 0 then
  5775. Result := Result + ' FD_WRITE';
  5776. if (msg.lParam and FD_CLOSE) <> 0 then
  5777. Result := Result + ' FD_CLOSE';
  5778. if (msg.lParam and FD_ACCEPT) <> 0 then
  5779. Result := Result + ' FD_ACCEPT';
  5780. end;
  5781. {$ENDIF}
  5782. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  5783. procedure TCustomWSocket.WMASyncSelect(var msg: TMessage);
  5784. var
  5785. Check : Word;
  5786. ParamLo : Word;
  5787. const
  5788. TTTCount : Integer = 0;
  5789. begin
  5790. {TriggerDisplay('AsyncSelect ' + IntToStr(msg.wParam) + ', ' + IntToStr(msg.LParamLo));}
  5791. { Verify that the socket handle is ours handle }
  5792. if msg.wParam <> FHSocket then
  5793. Exit;
  5794. if FPaused then
  5795. exit;
  5796. ParamLo := LoWord(msg.lParam);
  5797. Check := ParamLo and FD_CONNECT;
  5798. if Check <> 0 then begin
  5799. FSelectMessage := FD_CONNECT;
  5800. Do_FD_CONNECT(msg);
  5801. end;
  5802. Check := ParamLo and FD_READ;
  5803. if Check <> 0 then begin
  5804. FSelectMessage := FD_READ;
  5805. Do_FD_READ(msg);
  5806. end;
  5807. Check := ParamLo and FD_WRITE;
  5808. if Check <> 0 then begin
  5809. FSelectMessage := FD_WRITE;
  5810. Do_FD_WRITE(msg);
  5811. end;
  5812. Check := ParamLo and FD_ACCEPT;
  5813. if Check <> 0 then begin
  5814. FSelectMessage := FD_ACCEPT;
  5815. Do_FD_ACCEPT(msg);
  5816. end;
  5817. Check := ParamLo and FD_CLOSE;
  5818. if Check <> 0 then begin
  5819. FSelectMessage := FD_CLOSE;
  5820. {WriteLn('FD_CLOSE ', FHSocket);}
  5821. Do_FD_CLOSE(msg);
  5822. end;
  5823. FSelectMessage := 0;
  5824. end;
  5825. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  5826. {$IFDEF CLR}
  5827. procedure GetIPList(HostEntry : THostEnt; ToList : TStrings);
  5828. var
  5829. AddrList : IntPtr;
  5830. AddrItem : IntPtr;
  5831. Addr : Integer;
  5832. I : Integer;
  5833. begin
  5834. ToList.Clear;
  5835. I := 0;
  5836. AddrList := Marshal.ReadIntPtr(HostEntry.h_addr_list);
  5837. while TRUE do begin
  5838. AddrItem := Marshal.ReadIntPtr(HostEntry.h_addr_list, I);
  5839. if AddrItem = IntPtr.Zero then
  5840. break;
  5841. Addr := Marshal.ReadInt32(AddrItem);
  5842. ToList.Add(IntToStr((Addr and $FF)) + '.' +
  5843. IntToStr((Addr shr 8) and $FF) + '.' +
  5844. IntToStr((Addr shr 16) and $FF) + '.' +
  5845. IntToStr((Addr shr 24) and $FF));
  5846. Inc(I, 4);
  5847. end;
  5848. end;
  5849. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  5850. procedure GetAliasList(HostEntry : THostEnt; ToList : TStrings);
  5851. var
  5852. AddrItem : IntPtr;
  5853. I : Integer;
  5854. begin
  5855. I := 0;
  5856. while TRUE do begin
  5857. AddrItem := Marshal.ReadIntPtr(HostEntry.h_aliases, I);
  5858. if AddrItem = IntPtr.Zero then
  5859. break;
  5860. ToList.Add(Marshal.PtrToStringAnsi(AddrItem));
  5861. Inc(I);
  5862. end;
  5863. end;
  5864. {$ENDIF}
  5865. {$IFDEF WIN32}
  5866. procedure GetIPList(phe : PHostEnt; ToList : TStrings);
  5867. type
  5868. TaPInAddr = array [0..255] of PInAddr;
  5869. PaPInAddr = ^TaPInAddr;
  5870. var
  5871. pptr : PaPInAddr;
  5872. I : Integer;
  5873. begin
  5874. pptr := PaPInAddr(Phe^.h_addr_list);
  5875. I := 0;
  5876. while pptr^[I] <> nil do begin
  5877. ToList.Add(String(WSocket_inet_ntoa(pptr^[I]^)));
  5878. Inc(I);
  5879. end;
  5880. end;
  5881. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  5882. procedure GetAliasList(phe : PHostEnt; ToList : TStrings);
  5883. type
  5884. TaPAnsiChar = array [0..255] of PAnsiChar;
  5885. PaPAnsiChar = ^TaPAnsiChar;
  5886. var
  5887. pptr : PaPAnsiChar;
  5888. I : Integer;
  5889. begin
  5890. pptr := PaPAnsiChar(Phe^.h_aliases);
  5891. I := 0;
  5892. while pptr^[I] <> nil do begin
  5893. ToList.Add(String(pptr^[I]));
  5894. Inc(I);
  5895. end;
  5896. end;
  5897. {$ENDIF}
  5898. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  5899. procedure TCustomWSocket.WMAsyncGetHostByName(var msg: TMessage);
  5900. var
  5901. ErrCode : Word;
  5902. {$IFDEF CLR}
  5903. HostEntry : THostEnt;
  5904. {$ENDIF}
  5905. {$IFDEF WIN32}
  5906. Phe : Phostent;
  5907. {$ENDIF}
  5908. begin
  5909. if FDnsLookupHandle = 0 then begin
  5910. { We are still executing WSAAsyncGetHostByName and FDnsLookupHandle }
  5911. { has not been assigned yet ! We should proceed later. }
  5912. FDnsLookupTempMsg := msg;
  5913. FDnsLookupCheckMsg := TRUE;
  5914. Exit;
  5915. end
  5916. else if msg.wParam <> WPARAM(FDnsLookupHandle) then
  5917. Exit;
  5918. FDnsLookupHandle := 0;
  5919. ErrCode := HiWord(Msg.LParam);
  5920. {$IFDEF CLR}
  5921. if ErrCode = 0 then begin
  5922. HostEntry := THostEnt(Marshal.PtrToStructure(FDnsLookupIntPtr, TypeOf(THostEnt)));
  5923. GetIpList(HostEntry, FDnsResultList);
  5924. if FDnsResultList.Count > 0 then
  5925. FDnsResult := FDnsResultList.Strings[0];
  5926. end;
  5927. FDnsLookupGCH.Free;
  5928. {$ENDIF}
  5929. {$IFDEF WIN32}
  5930. if ErrCode = 0 then begin
  5931. Phe := PHostent(@FDnsLookupBuffer);
  5932. if phe <> nil then begin
  5933. GetIpList(Phe, FDnsResultList);
  5934. FDnsResult := FDnsResultList.Strings[0];
  5935. end;
  5936. end;
  5937. {$ENDIF}
  5938. TriggerDnsLookupDone(ErrCode);
  5939. end;
  5940. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  5941. procedure TCustomWSocket.WMAsyncGetHostByAddr(var msg: TMessage);
  5942. var
  5943. {$IFDEF CLR}
  5944. HostEntry : THostEnt;
  5945. {$ENDIF}
  5946. {$IFDEF WIN32}
  5947. Phe : Phostent;
  5948. {$ENDIF}
  5949. ErrCode : Word;
  5950. begin
  5951. if msg.wParam <> WPARAM(FDnsLookupHandle) then
  5952. Exit;
  5953. FDnsLookupHandle := 0;
  5954. ErrCode := HiWord(Msg.LParam);
  5955. if ErrCode = 0 then begin
  5956. {$IFDEF CLR}
  5957. if FDnsLookupIntPtr <> IntPtr.Zero then begin
  5958. HostEntry := THostEnt(Marshal.PtrToStructure(FDnsLookupIntPtr, TypeOf(THostEnt)));
  5959. FDnsResult := Marshal.PtrToStringAnsi(HostEntry.h_name);
  5960. {$ENDIF}
  5961. {$IFDEF WIN32}
  5962. Phe := PHostent(@FDnsLookupBuffer);
  5963. if phe <> nil then begin
  5964. //SetLength(FDnsResult, _StrLen(Phe^.h_name));
  5965. //_StrCopy(PAnsiChar(FDnsResult), Phe^.h_name);
  5966. FDnsResult := String(_StrPas(Phe^.h_name));
  5967. {$ENDIF}
  5968. FDnsResultList.Clear;
  5969. FDnsResultList.Add(FDnsResult);
  5970. {$IFDEF CLR}
  5971. GetAliasList(HostEntry, FDnsResultList);
  5972. {$ENDIF}
  5973. {$IFDEF WIN32}
  5974. GetAliasList(Phe, FDnsResultList); {AG 03/03/06}
  5975. {$ENDIF}
  5976. end;
  5977. end;
  5978. TriggerDnsLookupDone(ErrCode);
  5979. end;
  5980. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  5981. procedure TCustomWSocket.SetProto(sProto : String);
  5982. begin
  5983. if FProtoAssigned and (sProto = FProtoStr) then
  5984. Exit;
  5985. if FState <> wsClosed then begin
  5986. RaiseException('Cannot change Proto if not closed');
  5987. Exit;
  5988. end;
  5989. FProtoStr := _Trim(sProto);
  5990. if Length(FProtoStr) = 0 then begin
  5991. FProtoAssigned := FALSE;
  5992. Exit;
  5993. end;
  5994. FProtoResolved := FALSE;
  5995. FProtoAssigned := TRUE;
  5996. end;
  5997. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  5998. procedure TCustomWSocket.SetRemotePort(sPort : String);
  5999. begin
  6000. if FPortAssigned and (FPortStr = sPort) then
  6001. Exit;
  6002. if FState <> wsClosed then begin
  6003. RaiseException('Cannot change Port if not closed');
  6004. Exit;
  6005. end;
  6006. FPortStr := _Trim(sPort);
  6007. if Length(FPortStr) = 0 then begin
  6008. FPortAssigned := FALSE;
  6009. Exit;
  6010. end;
  6011. FPortResolved := FALSE;
  6012. FPortAssigned := TRUE;
  6013. end;
  6014. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  6015. function TCustomWSocket.GetRemotePort : String;
  6016. begin
  6017. Result := FPortStr;
  6018. end;
  6019. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  6020. procedure TCustomWSocket.SetLocalPort(const sLocalPort : String);
  6021. begin
  6022. if FState <> wsClosed then begin
  6023. RaiseException('Cannot change LocalPort if not closed');
  6024. Exit;
  6025. end;
  6026. FLocalPortStr := sLocalPort;
  6027. FLocalPortResolved := FALSE;
  6028. end;
  6029. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  6030. procedure TCustomWSocket.SetLocalAddr(sLocalAddr : String);
  6031. {var
  6032. IPAddr : TInAddr;}
  6033. begin
  6034. if FState <> wsClosed then begin
  6035. RaiseException('Cannot change LocalAddr if not closed');
  6036. Exit;
  6037. end;
  6038. if Length(sLocalAddr) = 0 then
  6039. sLocalAddr := '0.0.0.0';
  6040. {$IFDEF NEVER}
  6041. {$IFDEF DELPHI1}
  6042. sLocalAddr := sLocalAddr + #0;
  6043. {$ENDIF}
  6044. IPAddr.S_addr := WSocket_Synchronized_inet_addr(sLocalAddr);
  6045. if IPAddr.S_addr = u_long(INADDR_NONE) then
  6046. RaiseException('SetLocalAddr(): Invalid IP address');
  6047. FLocalAddr := StrPas(WSocket_Synchronized_inet_ntoa(IPAddr));
  6048. {$ELSE}
  6049. FLocalAddr := sLocalAddr;
  6050. {$ENDIF}
  6051. end;
  6052. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  6053. function TCustomWSocket.GetXPort: String;
  6054. var
  6055. saddr : TSockAddrIn;
  6056. saddrlen : Integer;
  6057. port : Integer;
  6058. begin
  6059. Result := 'error';
  6060. if FState in [wsConnected, wsBound, wsListening] then begin
  6061. saddrlen := sizeof(saddr);
  6062. if WSocket_Synchronized_GetSockName(FHSocket, TSockAddr(saddr), saddrlen) = 0 then begin
  6063. port := WSocket_Synchronized_ntohs(saddr.sin_port);
  6064. Result := _IntToStr(port);
  6065. end;
  6066. end;
  6067. end;
  6068. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  6069. function TCustomWSocket.GetXAddr: String;
  6070. var
  6071. saddr : TSockAddrIn;
  6072. saddrlen : Integer;
  6073. begin
  6074. Result := 'error';
  6075. if FState in [wsConnected, wsBound, wsListening] then begin
  6076. saddrlen := sizeof(saddr);
  6077. if WSocket_Synchronized_GetSockName(FHSocket, TSockAddr(saddr), saddrlen) = 0 then
  6078. Result := String(WSocket_Synchronized_inet_ntoa(saddr.sin_addr));
  6079. end;
  6080. end;
  6081. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  6082. procedure TCustomWSocket.SetAddr(InAddr : String);
  6083. begin
  6084. if FAddrAssigned and (FAddrStr = InAddr) then
  6085. Exit;
  6086. if FState <> wsClosed then begin
  6087. RaiseException('Cannot change Addr if not closed');
  6088. Exit;
  6089. end;
  6090. FAddrStr := _Trim(InAddr);
  6091. if Length(FAddrStr) = 0 then begin
  6092. FAddrAssigned := FALSE;
  6093. Exit;
  6094. end;
  6095. FAddrResolved := FALSE;
  6096. FAddrAssigned := TRUE;
  6097. end;
  6098. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  6099. function WSocket_Synchronized_ResolveHost(InAddr : AnsiString) : TInAddr;
  6100. var
  6101. {$IFDEF CLR}
  6102. Phe : IntPtr;
  6103. HostEntry : THostEnt;
  6104. AddrList : IntPtr;
  6105. AddrItem : IntPtr;
  6106. {$ENDIF}
  6107. {$IFDEF WIN32}
  6108. Phe : Phostent;
  6109. {$ENDIF}
  6110. IPAddr : u_long;
  6111. begin
  6112. if InAddr = '' then
  6113. { raise ESocketException.Create('WSocketResolveHost: ''' + InAddr + ''' Invalid Hostname.'); }
  6114. raise ESocketException.Create('Winsock Resolve Host: ''' + String(InAddr) + ''' Invalid Hostname.'); { V5.26 }
  6115. if WSocketIsDottedIP(InAddr) then begin
  6116. { Address is a dotted numeric address like 192.161.124.32 }
  6117. IPAddr := WSocket_Synchronized_inet_addr(InAddr);
  6118. {$IFDEF DELPHI1}
  6119. { With Trumpet Winsock 2B and 30D (win 3.11), inet_addr returns faulty }
  6120. { results for 0.0.0.0 }
  6121. if (IPAddr = INADDR_NONE) and (InAddr = '0.0.0.0') then begin
  6122. Result.s_addr := 0;
  6123. Exit;
  6124. end;
  6125. {$ENDIF}
  6126. if IPAddr = u_long(INADDR_NONE) then begin
  6127. if InAddr = '255.255.255.255' then begin
  6128. Result.s_addr := u_long(INADDR_BROADCAST);
  6129. Exit;
  6130. end;
  6131. { raise ESocketException.Create('WSocketResolveHost: ''' + InAddr + ''' Invalid IP address.'); }
  6132. raise ESocketException.Create('Winsock Resolve Host: ''' + String(InAddr) +
  6133. ''' Invalid IP address.'); { V5.26 }
  6134. end;
  6135. Result.s_addr := IPAddr;
  6136. Exit;
  6137. end;
  6138. {$IFDEF CLR}
  6139. Phe := OverByteIcsWinsock.GetHostByName(InAddr);
  6140. if Phe = IntPtr.Zero then
  6141. raise ESocketException.Create(
  6142. { 'WSocketResolveHost: Cannot convert host address ''' + InAddr +
  6143. ''', Error #' + IntToStr(WSAGetLastError)); }
  6144. 'Winsocket Resolve Host: Cannot convert host address ''' + InAddr +
  6145. ''', Error #' + IntToStr(WSAGetLastError));
  6146. HostEntry := THostEnt(Marshal.PtrToStructure(Phe, TypeOf(THostEnt)));
  6147. AddrList := Marshal.ReadIntPtr(HostEntry.h_addr_list);
  6148. AddrItem := Marshal.ReadIntPtr(HostEntry.h_addr_list);
  6149. Result.s_addr := Marshal.ReadInt32(AddrItem);
  6150. {$ENDIF}
  6151. {$IFDEF WIN32}
  6152. { Address is a hostname }
  6153. Phe := WSocket_Synchronized_GetHostByName(PAnsiChar(InAddr));
  6154. if Phe = nil then
  6155. raise ESocketException.Create(
  6156. 'Winsock Resolve Host: Cannot convert host address ''' +
  6157. String(InAddr) + ''' - ' +
  6158. GetWinsockErr(WSocket_Synchronized_WSAGetLastError));
  6159. Result.s_addr := PInAddr(Phe^.h_addr_list^)^.s_addr;
  6160. {$ENDIF}
  6161. end;
  6162. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  6163. function WSocketResolveHost(InAddr : AnsiString) : TInAddr;
  6164. begin
  6165. {$IFNDEF NO_ADV_MT}
  6166. SafeIncrementCount;
  6167. try
  6168. {$ENDIF}
  6169. Result := WSocket_Synchronized_ResolveHost(InAddr);
  6170. {$IFNDEF NO_ADV_MT}
  6171. finally
  6172. SafeDecrementCount;
  6173. end;
  6174. {$ENDIF}
  6175. end;
  6176. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  6177. { Convert port name or number to number in host order (ftp -> 21) }
  6178. function WSocket_Synchronized_ResolvePort(Port : AnsiString; Proto : AnsiString) : WORD;
  6179. {$IFDEF CLR}
  6180. var
  6181. Pse : IntPtr;
  6182. ServEntry : TServEnt;
  6183. begin
  6184. if Port = '' then
  6185. { raise ESocketException.Create('WSocketResolvePort: Invalid Port.'); }
  6186. raise ESocketException.Create('Winsock Resolve Port: Invalid Port.'); { V5.26 }
  6187. if IsDigit(Port[1]) then
  6188. Result := atoi(Port)
  6189. else begin
  6190. if not GWSAStartupCalled then
  6191. WSocket_Synchronized_WSAStartup(MAKEWORD(GReqVerLow, GReqVerHigh), GInitData);
  6192. if Proto = '' then
  6193. Pse := OverByteIcsWinsock.GetServByName(Port, '')
  6194. else
  6195. Pse := OverByteIcsWinsock.GetServByName(Port, Proto);
  6196. if Pse = IntPtr.Zero then
  6197. raise ESocketException.Create(
  6198. 'Winsock Resolve Port: Cannot convert port ''' +
  6199. Port + ''' - ' +
  6200. GetWinsockErr(OverByteIcsWinsock.WSAGetLastError)); { V5.26 }
  6201. ServEntry := TServEnt(Marshal.PtrToStructure(Pse, TypeOf(TServEnt)));
  6202. Result := OverByteIcsWinsock.ntohs(ServEntry.s_port);
  6203. end;
  6204. end;
  6205. {$ENDIF}
  6206. {$IFDEF WIN32}
  6207. var
  6208. Pse : Pservent;
  6209. begin
  6210. if Port = '' then
  6211. { raise ESocketException.Create('WSocketResolvePort: Invalid Port.'); }
  6212. raise ESocketException.Create('Winsock Resolve Port: Invalid Port.');
  6213. if Proto = '' then
  6214. raise ESocketException.Create('Winsock Resolve Port: Invalid Proto.');
  6215. if IsDigit(Port[1]) then
  6216. Result := atoi(Port)
  6217. else begin
  6218. Pse := WSocket_Synchronized_GetServByName(PAnsiChar(Port), PAnsiChar(Proto));
  6219. if Pse = nil then
  6220. raise ESocketException.Create(
  6221. 'Winsock Resolve Port: Cannot convert port ''' +
  6222. String(Port) + ''' - ' +
  6223. GetWinsockErr(WSocket_Synchronized_WSAGetLastError)); { V5.26 }
  6224. Result := WSocket_Synchronized_ntohs(Pse^.s_port);
  6225. end;
  6226. end;
  6227. {$ENDIF}
  6228. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  6229. { Convert port name or number to number in host order (ftp -> 21) }
  6230. function WSocketResolvePort(Port : AnsiString; Proto : AnsiString) : Word;
  6231. begin
  6232. {$IFNDEF NO_ADV_MT}
  6233. SafeIncrementCount;
  6234. try
  6235. {$ENDIF}
  6236. Result := WSocket_Synchronized_ResolvePort(Port, Proto);
  6237. {$IFNDEF NO_ADV_MT}
  6238. finally
  6239. SafeDecrementCount;
  6240. end;
  6241. {$ENDIF}
  6242. end;
  6243. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  6244. function WSocket_Synchronized_ResolveProto(sProto : AnsiString) : Integer;
  6245. var
  6246. {$IFDEF CLR}
  6247. Ppe : IntPtr;
  6248. ProtoEntry : TProtoEnt;
  6249. {$ENDIF}
  6250. {$IFDEF WIN32}
  6251. Ppe : Pprotoent;
  6252. {$ENDIF}
  6253. begin
  6254. if sProto = '' then
  6255. { raise ESocketException.Create('WSocketResolveProto: Invalid Protocol.'); }
  6256. raise ESocketException.Create('Winsock Resolve Proto: Invalid Protocol.'); { V5.26 }
  6257. if IsDigit(sProto[1]) then
  6258. Result := atoi(sProto)
  6259. else begin
  6260. sProto := _LowerCase(_Trim(sProto));
  6261. if sProto = 'tcp' then
  6262. Result := IPPROTO_TCP
  6263. else if sProto = 'udp' then
  6264. Result := IPPROTO_UDP
  6265. else if sProto = 'raw' then
  6266. Result := IPPROTO_RAW
  6267. else begin
  6268. {$IFDEF CLR}
  6269. ppe := OverByteIcsWinsock.getprotobyname(sProto);
  6270. if Ppe = IntPtr.Zero then
  6271. raise ESocketException.Create(
  6272. 'Winsock Resolve Proto: Cannot convert protocol ''' +
  6273. sProto + '''- ' +
  6274. GetWinsockErr(OverByteIcsWinsock.WSAGetLastError)); { V5.26 }
  6275. ProtoEntry := TProtoEnt(Marshal.PtrToStructure(Ppe, TypeOf(TProtoEnt)));
  6276. Result := ProtoEntry.p_proto;
  6277. {$ENDIF}
  6278. {$IFDEF WIN32}
  6279. ppe := WSocket_Synchronized_getprotobyname(sProto);
  6280. if Ppe = nil then
  6281. raise ESocketException.Create(
  6282. 'Winsock Resolve Proto: Cannot convert protocol ''' +
  6283. String(sProto) + ''' - ' +
  6284. GetWinsockErr(WSocket_Synchronized_WSAGetLastError)); { V5.26 }
  6285. Result := ppe^.p_proto;
  6286. {$ENDIF}
  6287. end;
  6288. end;
  6289. end;
  6290. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  6291. function WSocketResolveProto(sProto : AnsiString) : Integer;
  6292. begin
  6293. {$IFNDEF NO_ADV_MT}
  6294. SafeIncrementCount;
  6295. try
  6296. {$ENDIF}
  6297. Result := WSocket_Synchronized_ResolveProto(sProto);
  6298. {$IFNDEF NO_ADV_MT}
  6299. finally
  6300. SafeDecrementCount;
  6301. end;
  6302. {$ENDIF}
  6303. end;
  6304. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  6305. function TCustomWSocket.GetSockName(var saddr : TSockAddrIn; var saddrlen : Integer) : Integer;
  6306. begin
  6307. Result := WSocket_Synchronized_GetSockName(FHSocket, TSockAddr(saddr), saddrlen);
  6308. end;
  6309. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  6310. function TCustomWSocket.GetPeerAddr: String;
  6311. var
  6312. saddr : TSockAddrIn;
  6313. saddrlen : Integer;
  6314. begin
  6315. {$IFDEF CLR}
  6316. if DesignMode then begin
  6317. Result := '';
  6318. Exit;
  6319. end;
  6320. {$ENDIF}
  6321. Result := 'error';
  6322. if FState = wsConnected then begin
  6323. saddrlen := sizeof(saddr);
  6324. if WSocket_Synchronized_GetPeerName(FHSocket, TSockAddr(saddr), saddrlen) = 0 then
  6325. Result := String(WSocket_Synchronized_inet_ntoa(saddr.sin_addr))
  6326. else begin
  6327. SocketError('GetPeerName');
  6328. Exit;
  6329. end;
  6330. end;
  6331. end;
  6332. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  6333. function TCustomWSocket.GetPeerPort: String;
  6334. var
  6335. saddr : TSockAddrIn;
  6336. saddrlen : Integer;
  6337. begin
  6338. {$IFDEF CLR}
  6339. if DesignMode then begin
  6340. Result := '';
  6341. Exit;
  6342. end;
  6343. {$ENDIF}
  6344. Result := 'error';
  6345. if FState = wsConnected then begin
  6346. saddrlen := sizeof(saddr);
  6347. if WSocket_Synchronized_GetPeerName(FHSocket, TSockAddr(saddr), saddrlen) = 0 then
  6348. Result := _IntToStr(WSocket_Synchronized_ntohs(saddr.sin_port))
  6349. else begin
  6350. SocketError('GetPeerPort');
  6351. Exit;
  6352. end;
  6353. end;
  6354. end;
  6355. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  6356. function TCustomWSocket.GetPeerName(var Name : TSockAddrIn; NameLen : Integer) : Integer;
  6357. begin
  6358. {$IFDEF CLR}
  6359. if DesignMode then begin
  6360. Result := SOCKET_ERROR;
  6361. Exit;
  6362. end;
  6363. {$ENDIF}
  6364. if FState = wsConnected then
  6365. Result := WSocket_Synchronized_GetPeerName(FHSocket, TSockAddr(Name), NameLen)
  6366. else
  6367. Result := SOCKET_ERROR;
  6368. end;
  6369. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  6370. procedure TCustomWSocket.CancelDnsLookup;
  6371. begin
  6372. if FDnsLookupHandle = 0 then
  6373. Exit;
  6374. if WSocket_Synchronized_WSACancelAsyncRequest(FDnsLookupHandle) <> 0 then begin
  6375. FDnsLookupHandle := 0;
  6376. SocketError('WSACancelAsyncRequest');
  6377. Exit;
  6378. end;
  6379. FDnsLookupHandle := 0;
  6380. {$IFDEF WIN32}
  6381. if not (csDestroying in ComponentState) then
  6382. {$ENDIF}
  6383. TriggerDnsLookupDone(WSAEINTR);
  6384. end;
  6385. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  6386. procedure TCustomWSocket.DnsLookup(const AHostName : String);
  6387. var
  6388. IPAddr : TInAddr;
  6389. HostName : AnsiString;
  6390. begin
  6391. if AHostName = '' then begin
  6392. RaiseException('DNS lookup: invalid host name.');
  6393. TriggerDnsLookupDone(WSAEINVAL);
  6394. Exit;
  6395. end;
  6396. { Cancel any pending lookup }
  6397. if FDnsLookupHandle <> 0 then begin
  6398. WSocket_Synchronized_WSACancelAsyncRequest(FDnsLookupHandle);
  6399. FDnsLookupHandle := 0;
  6400. end;
  6401. FDnsResult := '';
  6402. FDnsResultList.Clear;
  6403. {$IFDEF DELPHI1}
  6404. { Delphi 1 do not automatically add a terminating nul char }
  6405. HostName := AHostName + #0;
  6406. {$ELSE}
  6407. HostName := AnsiString(AHostName);
  6408. {$ENDIF}
  6409. if WSocketIsDottedIP(Hostname) then begin { 28/09/2002 }
  6410. IPAddr.S_addr := WSocket_Synchronized_inet_addr(HostName);
  6411. if IPAddr.S_addr <> u_long(INADDR_NONE) then begin
  6412. FDnsResult := String(WSocket_Synchronized_inet_ntoa(IPAddr));
  6413. FDnsResultList.Add(FDnsResult); { 28/09/2002 }{ 12/02/2003 }
  6414. TriggerDnsLookupDone(0);
  6415. Exit;
  6416. end;
  6417. end;
  6418. if FWindowHandle = 0 then
  6419. RaiseException('DnsLookup: Window not assigned');
  6420. { John Goodwin found a case where winsock dispatch WM_ASYNCGETHOSTBYNAME }
  6421. { message before returning from WSAAsyncGetHostByName call. Because of }
  6422. { that, FDnsLookupHandle is not yet assigned when execution comes in }
  6423. { WMAsyncGetHostByName. John use a flag to check this situation. }
  6424. FDnsLookupCheckMsg := FALSE;
  6425. {$IFDEF CLR}
  6426. SetLength(FDnsLookupBuffer, MAXGETHOSTSTRUCT);
  6427. FDnsLookupGCH := GCHandle.Alloc(FDnsLookupBuffer, GCHandleType.Pinned);
  6428. FDnsLookupIntPtr := FDnsLookupGCH.AddrOfPinnedObject;
  6429. FDnsLookupHandle := WSocket_WSAAsyncGetHostByName(
  6430. FWindowHandle,
  6431. FMsg_WM_ASYNCGETHOSTBYNAME,
  6432. HostName,
  6433. FDnsLookupIntPtr,
  6434. MAXGETHOSTSTRUCT);
  6435. if FDnsLookupHandle = 0 then begin
  6436. FDnsLookupGCH.Free;
  6437. RaiseException(HostName +
  6438. ': can''t start DNS lookup - ' +
  6439. GetWinsockErr(WSocket_WSAGetLastError)); { V5.26 }
  6440. Exit;
  6441. end;
  6442. {$ENDIF}
  6443. {$IFDEF WIN32}
  6444. FDnsLookupHandle := WSocket_Synchronized_WSAAsyncGetHostByName(
  6445. FWindowHandle,
  6446. FMsg_WM_ASYNCGETHOSTBYNAME,
  6447. @HostName[1],
  6448. @FDnsLookupBuffer,
  6449. SizeOf(FDnsLookupBuffer));
  6450. if FDnsLookupHandle = 0 then begin
  6451. RaiseException(String(HostName) + ': can''t start DNS lookup - ' +
  6452. GetWinsockErr(WSocket_Synchronized_WSAGetLastError)); { V5.26 }
  6453. Exit;
  6454. end;
  6455. {$ENDIF}
  6456. if FDnsLookupCheckMsg then begin
  6457. FDnsLookupCheckMsg := FALSE;
  6458. WMAsyncGetHostByName(FDnsLookupTempMsg);
  6459. end;
  6460. end;
  6461. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  6462. procedure TCustomWSocket.ReverseDnsLookup(const HostAddr: String);
  6463. var
  6464. lAddr : u_long;
  6465. begin
  6466. if HostAddr = '' then begin
  6467. RaiseException('Reverse DNS Lookup: Invalid host name.'); { V5.26 }
  6468. TriggerDnsLookupDone(WSAEINVAL);
  6469. Exit;
  6470. end;
  6471. { Cancel any pending lookup }
  6472. if FDnsLookupHandle <> 0 then
  6473. WSocket_Synchronized_WSACancelAsyncRequest(FDnsLookupHandle);
  6474. FDnsResult := '';
  6475. FDnsResultList.Clear;
  6476. lAddr := WSocket_Synchronized_inet_addr(AnsiString(HostAddr));
  6477. if FWindowHandle = 0 then
  6478. RaiseException('Reverse DNS Lookup: Window not assigned'); { V5.26 }
  6479. {$IFDEF CLR}
  6480. SetLength(FDnsLookupBuffer, MAXGETHOSTSTRUCT);
  6481. FDnsLookupGCH := GCHandle.Alloc(FDnsLookupBuffer, GCHandleType.Pinned);
  6482. FDnsLookupIntPtr := FDnsLookupGCH.AddrOfPinnedObject;
  6483. FDnsLookupHandle := WSocket_WSAAsyncGetHostByAddr(
  6484. FWindowHandle,
  6485. FMsg_WM_ASYNCGETHOSTBYADDR,
  6486. lAddr, 4, PF_INET,
  6487. FDnsLookupIntPtr,
  6488. MAXGETHOSTSTRUCT);
  6489. if FDnsLookupHandle = 0 then begin
  6490. FDnsLookupGCH.Free;
  6491. RaiseException(HostAddr + ': can''t start DNS lookup - ' +
  6492. GetWinsockErr(WSocket_WSAGetLastError)); { V5.26 }
  6493. end;
  6494. {$ENDIF}
  6495. {$IFDEF WIN32}
  6496. FDnsLookupHandle := WSocket_Synchronized_WSAAsyncGetHostByAddr(
  6497. FWindowHandle,
  6498. FMsg_WM_ASYNCGETHOSTBYADDR,
  6499. PAnsiChar(@lAddr), 4, PF_INET,
  6500. @FDnsLookupBuffer,
  6501. SizeOf(FDnsLookupBuffer));
  6502. if FDnsLookupHandle = 0 then
  6503. RaiseException(HostAddr + ': can''t start reverse DNS lookup - ' +
  6504. GetWinsockErr(WSocket_Synchronized_WSAGetLastError)); { V5.26 }
  6505. {$ENDIF}
  6506. end;
  6507. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  6508. {$IFDEF CLR}
  6509. procedure TCustomWSocket.ReverseDnsLookupSync(const HostAddr: String);
  6510. var
  6511. lAddr : u_long;
  6512. Phe : IntPtr;
  6513. HostEntry : THostEnt;
  6514. begin
  6515. if Length(HostAddr) = 0 then begin
  6516. RaiseException('ReverseDnsLookup: Invalid host name.');
  6517. TriggerDnsLookupDone(WSAEINVAL);
  6518. Exit;
  6519. end;
  6520. // Cancel any pending lookup
  6521. if FDnsLookupHandle <> 0 then
  6522. WSocket_WSACancelAsyncRequest(FDnsLookupHandle);
  6523. FDnsResult := '';
  6524. FDnsResultList.Clear;
  6525. lAddr := WSocket_Synchronized_inet_addr(HostAddr);
  6526. Phe := WSocket_Synchronized_gethostbyaddr(lAddr, 4, AF_INET);
  6527. if Phe = IntPtr.Zero then
  6528. TriggerDnsLookupDone(WSocket_Synchronized_WSAGetLastError)
  6529. else begin
  6530. HostEntry := THostEnt(Marshal.PtrToStructure(Phe,
  6531. TypeOf(THostEnt)));
  6532. FDnsResult := Marshal.PtrToStringAnsi(HostEntry.h_name);
  6533. FDnsResultList.Add(FDnsResult);
  6534. GetAliasList(HostEntry, FDnsResultList);
  6535. TriggerDnsLookupDone(0);
  6536. end;
  6537. end;
  6538. {$ENDIF}
  6539. {$IFDEF WIN32}
  6540. procedure TCustomWSocket.ReverseDnsLookupSync(const HostAddr: String); {AG 03/03/06}
  6541. var
  6542. szAddr : array [0..256] of AnsiChar;
  6543. lAddr : u_long;
  6544. Phe : Phostent;
  6545. begin
  6546. if (Length(HostAddr) = 0) or (Length(HostAddr) >= SizeOf(szAddr)) then begin
  6547. RaiseException('Reverse DNS Lookup: Invalid host name.'); { V5.26 }
  6548. TriggerDnsLookupDone(WSAEINVAL);
  6549. Exit;
  6550. end;
  6551. { Cancel any pending lookup }
  6552. if FDnsLookupHandle <> 0 then
  6553. WSocket_Synchronized_WSACancelAsyncRequest(FDnsLookupHandle);
  6554. FDnsResult := '';
  6555. FDnsResultList.Clear;
  6556. _StrPCopy(szAddr, AnsiString(HostAddr)); { Length already checked above }
  6557. lAddr := WSocket_Synchronized_inet_addr(szAddr);
  6558. Phe := WSocket_Synchronized_gethostbyaddr(PAnsiChar(@lAddr), 4, AF_INET);
  6559. if Phe = nil then
  6560. TriggerDnsLookupDone(WSocket_Synchronized_WSAGetLastError)
  6561. else begin
  6562. //SetLength(FDnsResult, _StrLen(Phe^.h_name));
  6563. //_StrCopy(@FDnsResult[1], Phe^.h_name);
  6564. FDnsResult := String(_StrPas(Phe^.h_name));
  6565. FDnsResultList.Add(FDnsResult);
  6566. GetAliasList(Phe, FDnsResultList);
  6567. TriggerDnsLookupDone(0);
  6568. end;
  6569. end;
  6570. {$ENDIF}
  6571. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  6572. procedure TCustomWSocket.BindSocket;
  6573. var
  6574. SockName : TSockAddr;
  6575. SockNamelen : Integer;
  6576. LocalSockName : TSockAddrIn;
  6577. {$IFDEF CLR}
  6578. I : Integer;
  6579. begin
  6580. for I := Low(LocalSockName.sin_zero) to High(LocalSockName.sin_zero) do
  6581. LocalSockName.sin_zero[0] := #0;
  6582. {$ENDIF}
  6583. {$IFDEF WIN32}
  6584. begin
  6585. FillChar(LocalSockName, Sizeof(LocalSockName), 0);
  6586. {$ENDIF}
  6587. SockNamelen := SizeOf(LocalSockName);
  6588. LocalSockName.sin_family := AF_INET;
  6589. LocalSockName.sin_port := WSocket_Synchronized_htons(FLocalPortNum);
  6590. LocalSockName.sin_addr.s_addr := WSocket_Synchronized_ResolveHost(AnsiString(FLocalAddr)).s_addr;
  6591. if WSocket_Synchronized_bind(HSocket, LocalSockName, SockNamelen) <> 0 then begin
  6592. RaiseException('Bind socket failed - ' +
  6593. GetWinsockErr(WSocket_Synchronized_WSAGetLastError)); { V5.26 }
  6594. Exit;
  6595. end;
  6596. SockNamelen := sizeof(SockName);
  6597. if WSocket_Synchronized_getsockname(FHSocket, SockName, SockNamelen) <> 0 then begin
  6598. RaiseException('Winsock get socket name failed - ' +
  6599. GetWinsockErr(WSocket_Synchronized_WSAGetLastError)); { V5.26 }
  6600. Exit;
  6601. end;
  6602. FLocalPortNum := WSocket_Synchronized_ntohs(SockName.sin_port);
  6603. FLocalPortStr := _IntToStr(FLocalPortNum);
  6604. end;
  6605. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  6606. {$IFDEF CLR}
  6607. procedure TCustomWSocket.SetKeepAliveOption;
  6608. begin
  6609. // Not implemented !
  6610. end;
  6611. {$ENDIF}
  6612. {$IFDEF WIN32}
  6613. procedure TCustomWSocket.SetKeepAliveOption;
  6614. var
  6615. OptVal : Integer;
  6616. Status : Integer;
  6617. KeepAliveIn : TTcpKeepAlive;
  6618. KeepAliveOut : TTcpKeepAlive;
  6619. {$IFDEF DELPHI3}
  6620. BytesReturned : DWORD;
  6621. {$ELSE}
  6622. BytesReturned : Cardinal;
  6623. {$ENDIF}
  6624. begin
  6625. if FKeepAliveOnOff = wsKeepAliveOff then
  6626. Exit;
  6627. Assert(FHSocket <> INVALID_SOCKET); { V7.27 }
  6628. if FKeepAliveOnOff = wsKeepAliveOnSystem then begin
  6629. OptVal := 1;
  6630. Status := WSocket_Synchronized_setsockopt(FHSocket, SOL_SOCKET,
  6631. SO_KEEPALIVE, @OptVal,
  6632. SizeOf(OptVal));
  6633. if Status <> 0 then
  6634. SocketError('setsockopt(SO_KEEPALIVE)');
  6635. Exit;
  6636. end;
  6637. {$IFNDEF DELPHI1}
  6638. FillChar(KeepAliveIn, SizeOf(KeepAliveIn), 0);
  6639. FillChar(KeepAliveOut, SizeOf(KeepAliveOut), 0);
  6640. BytesReturned := 0;
  6641. KeepAliveIn.OnOff := 1;
  6642. KeepAliveIn.KeepAliveInterval := FKeepAliveInterval;
  6643. KeepAliveIn.KeepAliveTime := FKeepAliveTime;
  6644. Status := WSocket_WSAIoctl(FHSocket, SIO_KEEPALIVE_VALS,
  6645. @KeepAliveIn, SizeOf(KeepAliveIn),
  6646. @KeepAliveOut, SizeOf(KeepAliveOut),
  6647. BytesReturned, nil, nil);
  6648. if Status <> 0 then begin
  6649. SocketError('WSocket_WSAIoctl(SIO_KEEPALIVE_VALS)');
  6650. Exit;
  6651. end;
  6652. {$ENDIF}
  6653. end;
  6654. {$ENDIF}
  6655. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  6656. procedure TCustomWSocket.SetLingerOption;
  6657. var
  6658. iStatus : Integer;
  6659. li : TLinger;
  6660. begin
  6661. if FLingerOnOff = wsLingerNoSet then
  6662. Exit; { Option set is disabled, ignore }
  6663. if FHSocket = INVALID_SOCKET then begin
  6664. RaiseException('Cannot set linger option at this time');
  6665. Exit;
  6666. end;
  6667. li.l_onoff := Ord(FLingerOnOff); { 0/1 = disable/enable linger }
  6668. li.l_linger := FLingerTimeout; { timeout in seconds }
  6669. iStatus := WSocket_Synchronized_setsockopt(FHSocket, SOL_SOCKET,
  6670. SO_LINGER, li, SizeOf(li));
  6671. if iStatus <> 0 then begin
  6672. SocketError('setsockopt(SO_LINGER)');
  6673. Exit;
  6674. end;
  6675. end;
  6676. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  6677. function TCustomWSocket.SetTcpNoDelayOption: Boolean; { V7.27 }
  6678. var
  6679. optval : Integer;
  6680. begin
  6681. Assert(FHSocket <> INVALID_SOCKET);
  6682. if HasOption(FComponentOptions, wsoTcpNoDelay) then
  6683. optval := -1 { true }
  6684. else
  6685. optval := 0; { false }
  6686. Result := WSocket_Synchronized_setsockopt(FHSocket, IPPROTO_TCP,
  6687. TCP_NODELAY,
  6688. optval, SizeOf(optval)) = 0;
  6689. if not Result then
  6690. SocketError('setsockopt(IPPROTO_TCP, TCP_NODELAY)');
  6691. end;
  6692. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  6693. procedure TCustomWSocket.Connect;
  6694. var
  6695. iStatus : Integer;
  6696. optval : Integer;
  6697. optlen : Integer;
  6698. lAddr : TInAddr;
  6699. begin
  6700. if (FHSocket <> INVALID_SOCKET) and (FState <> wsClosed) then begin
  6701. RaiseException('Connect: Socket already in use');
  6702. Exit;
  6703. end;
  6704. if not FPortAssigned then begin
  6705. RaiseException('Connect: No Port Specified');
  6706. Exit;
  6707. end;
  6708. if not FAddrAssigned then begin
  6709. RaiseException('Connect: No IP Address Specified');
  6710. Exit;
  6711. end;
  6712. if not FProtoAssigned then begin
  6713. RaiseException('Connect: No Protocol Specified');
  6714. Exit;
  6715. end;
  6716. try
  6717. if not FProtoResolved then begin
  6718. { The next line will trigger an exception in case of failure }
  6719. FProto := WSocket_Synchronized_ResolveProto(AnsiString(FProtoStr));
  6720. case FProto of
  6721. IPPROTO_UDP: FType := SOCK_DGRAM;
  6722. IPPROTO_TCP: FType := SOCK_STREAM;
  6723. IPPROTO_RAW: FType := SOCK_RAW;
  6724. else
  6725. FType := SOCK_RAW;
  6726. end;
  6727. FProtoResolved := TRUE;
  6728. end;
  6729. if not FPortResolved then begin
  6730. { The next line will trigger an exception in case of failure }
  6731. FPortNum := WSocket_Synchronized_ResolvePort(AnsiString(FPortStr), AnsiString(FProtoStr));
  6732. sin.sin_port := WSocket_Synchronized_htons(FPortNum);
  6733. FPortResolved := TRUE;
  6734. end;
  6735. if not FLocalPortResolved then begin
  6736. { The next line will trigger an exception in case of failure }
  6737. FLocalPortNum := WSocket_Synchronized_ResolvePort(AnsiString(FLocalPortStr), AnsiString(FProtoStr));
  6738. FLocalPortResolved := TRUE;
  6739. end;
  6740. if not FAddrResolved then begin
  6741. { The next line will trigger an exception in case of failure }
  6742. sin.sin_addr.s_addr := WSocket_Synchronized_ResolveHost(AnsiString(FAddrStr)).s_addr;
  6743. FAddrResolved := TRUE;
  6744. end;
  6745. except
  6746. on E:Exception do begin
  6747. RaiseException('connect: ' + E.Message);
  6748. Exit;
  6749. end;
  6750. end;
  6751. { Remove any data from the internal output buffer }
  6752. { (should already be empty !) }
  6753. DeleteBufferedData;
  6754. { Open the socket }
  6755. FHSocket := WSocket_Synchronized_socket(FAddrFormat, FType, FProto);
  6756. if FHSocket = INVALID_SOCKET then begin
  6757. SocketError('Connect (socket)');
  6758. Exit;
  6759. end;
  6760. { Get winsock send buffer size }
  6761. optlen := SizeOf(FSocketSndBufSize);
  6762. {$IFDEF CLR}
  6763. iStatus := WSocket_getsockopt(FHSocket, SOL_SOCKET, SO_SNDBUF,
  6764. FSocketSndBufSize, optlen);
  6765. {$ELSE}
  6766. iStatus := WSocket_getsockopt(FHSocket, SOL_SOCKET, SO_SNDBUF,
  6767. PAnsiChar(@FSocketSndBufSize), optlen);
  6768. {$ENDIF}
  6769. if iStatus <> 0 then begin
  6770. SocketError('getsockopt(SO_SNDBUF)');
  6771. Exit;
  6772. end;
  6773. { Get winsock receive buffer size }
  6774. optlen := SizeOf(FSocketRcvBufSize);
  6775. {$IFDEF CLR}
  6776. iStatus := WSocket_getsockopt(FHSocket, SOL_SOCKET, SO_RCVBUF,
  6777. FSocketRcvBufSize, optlen);
  6778. {$ELSE}
  6779. iStatus := WSocket_getsockopt(FHSocket, SOL_SOCKET, SO_RCVBUF,
  6780. PAnsiChar(@FSocketRcvBufSize), optlen);
  6781. {$ENDIF}
  6782. if iStatus <> 0 then begin
  6783. SocketError('getsockopt(SO_RCVBUF)');
  6784. Exit;
  6785. end;
  6786. { Trigger OnChangeState event }
  6787. ChangeState(wsOpened);
  6788. if FState <> wsOpened then begin { 07/07/02 }
  6789. { Socket has been closed in the OnChangeState event ! }
  6790. WSocket_Synchronized_WSASetLastError(WSAEINVAL);
  6791. SocketError('Connect (Invalid operation in OnChangeState)');
  6792. Exit;
  6793. end;
  6794. if FType = SOCK_DGRAM then begin
  6795. BindSocket;
  6796. if FMultiCast then begin
  6797. if FMultiCastIpTTL <> IP_DEFAULT_MULTICAST_TTL then begin
  6798. optval := FMultiCastIpTTL; { set time-to-live for multicast }
  6799. iStatus := WSocket_Synchronized_SetSockOpt(FHSocket, IPPROTO_IP,
  6800. IP_MULTICAST_TTL,
  6801. optval,
  6802. SizeOf(optval));
  6803. if iStatus <> 0 then begin
  6804. SocketError('setsockopt(IP_MULTICAST_TTL)');
  6805. Exit;
  6806. end;
  6807. end;
  6808. if FLocalAddr <> '0.0.0.0' then begin { RK }
  6809. laddr.s_addr := WSocket_Synchronized_ResolveHost(AnsiString(FLocalAddr)).s_addr;
  6810. iStatus := WSocket_Synchronized_SetSockOpt(FHSocket, IPPROTO_IP,
  6811. IP_MULTICAST_IF,
  6812. laddr,
  6813. SizeOf(laddr));
  6814. if iStatus <> 0 then begin
  6815. SocketError('setsockopt(IP_MULTICAST_IF)');
  6816. Exit;
  6817. end;
  6818. end; { /RK }
  6819. end;
  6820. if sin.sin_addr.S_addr = u_long(INADDR_BROADCAST) then begin
  6821. OptVal := 1;
  6822. iStatus := WSocket_Synchronized_setsockopt(FHSocket, SOL_SOCKET, SO_BROADCAST,
  6823. OptVal, SizeOf(OptVal));
  6824. if iStatus <> 0 then begin
  6825. SocketError('setsockopt(SO_BROADCAST)');
  6826. Exit;
  6827. end;
  6828. end;
  6829. end
  6830. else begin
  6831. { Socket type is SOCK_STREAM }
  6832. optval := -1;
  6833. iStatus := WSocket_Synchronized_setsockopt(FHSocket, SOL_SOCKET,
  6834. SO_REUSEADDR, optval, SizeOf(optval));
  6835. if iStatus <> 0 then begin
  6836. SocketError('setsockopt(SO_REUSEADDR)');
  6837. Exit;
  6838. end;
  6839. if HasOption(FComponentOptions, wsoTcpNoDelay) and { V7.27 }
  6840. (not SetTcpNoDelayOption) then
  6841. Exit;
  6842. SetLingerOption;
  6843. SetKeepAliveOption;
  6844. if (FLocalPortNum <> 0) or (FLocalAddr <> '0.0.0.0') then
  6845. BindSocket;
  6846. end;
  6847. FSelectEvent := FD_READ or FD_WRITE or FD_CLOSE or
  6848. {FD_ACCEPT or} FD_CONNECT; { FD_ACCEPT not needed } {AG 29.03.08}
  6849. iStatus := WSocket_Synchronized_WSAASyncSelect(FHSocket, Handle,
  6850. FMsg_WM_ASYNCSELECT,
  6851. FSelectEvent);
  6852. if iStatus <> 0 then begin
  6853. SocketError('WSAAsyncSelect');
  6854. Exit;
  6855. end;
  6856. if FType = SOCK_DGRAM then begin
  6857. ChangeState(wsConnected);
  6858. TriggerSessionConnectedSpecial(0);
  6859. end
  6860. else begin
  6861. {$IFNDEF NO_DEBUG_LOG}
  6862. if CheckLogOptions(loWsockInfo) then { V5.21 } { replaces $IFDEF DEBUG_OUTPUT }
  6863. DebugLog(loWsockInfo, 'TWSocket will connect to ' +
  6864. WSocket_Synchronized_inet_ntoa(sin.sin_addr) + ':' +
  6865. _IntToStr(WSocket_Synchronized_ntohs(sin.sin_port)));
  6866. {$ENDIF}
  6867. iStatus := WSocket_Synchronized_connect(FHSocket, TSockAddr(sin), sizeof(sin));
  6868. if iStatus = 0 then
  6869. ChangeState(wsConnecting)
  6870. else begin
  6871. iStatus := WSocket_Synchronized_WSAGetLastError;
  6872. if iStatus = WSAEWOULDBLOCK then
  6873. ChangeState(wsConnecting)
  6874. else begin
  6875. FLastError := WSocket_Synchronized_WSAGetLastError;
  6876. SocketError('Connect');
  6877. Exit;
  6878. end;
  6879. end;
  6880. end;
  6881. end;
  6882. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  6883. procedure TCustomWSocket.Listen;
  6884. var
  6885. iStatus : Integer;
  6886. optval : Integer;
  6887. mreq : ip_mreq;
  6888. {$IFDEF WIN32}
  6889. dwBufferInLen : DWORD;
  6890. dwBufferOutLen : DWORD;
  6891. dwDummy : DWORD;
  6892. {$ENDIF}
  6893. begin
  6894. if not FPortAssigned then begin
  6895. WSocket_Synchronized_WSASetLastError(WSAEINVAL);
  6896. SocketError('listen: port not assigned');
  6897. Exit;
  6898. end;
  6899. if not FProtoAssigned then begin
  6900. WSocket_Synchronized_WSASetLastError(WSAEINVAL);
  6901. SocketError('listen: protocol not assigned');
  6902. Exit;
  6903. end;
  6904. if not FAddrAssigned then begin
  6905. WSocket_Synchronized_WSASetLastError(WSAEINVAL);
  6906. SocketError('listen: address not assigned');
  6907. Exit;
  6908. end;
  6909. try
  6910. if not FProtoResolved then begin
  6911. { The next line will trigger an exception in case of failure }
  6912. if _CompareText(Copy(FProtoStr, 1, 4), 'raw_') = 0 then begin
  6913. FType := SOCK_RAW;
  6914. FProto := WSocket_Synchronized_ResolveProto(AnsiString(Copy(FProtoStr, 5, 10)));
  6915. end
  6916. else begin
  6917. FProto := WSocket_Synchronized_ResolveProto(AnsiString(FProtoStr));
  6918. if FProto = IPPROTO_UDP then
  6919. FType := SOCK_DGRAM
  6920. else
  6921. FType := SOCK_STREAM;
  6922. end;
  6923. FProtoResolved := TRUE;
  6924. end;
  6925. if not FPortResolved then begin
  6926. { The next line will trigger an exception in case of failure }
  6927. FPortNum := WSocket_Synchronized_ResolvePort(AnsiString(FPortStr), AnsiString(FProtoStr));
  6928. sin.sin_port := WSocket_Synchronized_htons(FPortNum);
  6929. FPortResolved := TRUE;
  6930. end;
  6931. if not FAddrResolved then begin
  6932. { The next line will trigger an exception in case of failure }
  6933. sin.sin_addr.s_addr := WSocket_Synchronized_ResolveHost(AnsiString(FAddrStr)).s_addr;
  6934. FAddrResolved := TRUE;
  6935. end;
  6936. except
  6937. on E:Exception do begin
  6938. RaiseException('listen: ' + E.Message);
  6939. Exit;
  6940. end;
  6941. end;
  6942. { Remove any data from the internal output buffer }
  6943. { (should already be empty !) }
  6944. DeleteBufferedData;
  6945. FHSocket := WSocket_Synchronized_socket(FAddrFormat, FType, FProto);
  6946. if FHSocket = INVALID_SOCKET then begin
  6947. SocketError('socket');
  6948. exit;
  6949. end;
  6950. if FType = SOCK_DGRAM then begin
  6951. if FReuseAddr then begin
  6952. { Enable multiple tasks to listen on duplicate address and port }
  6953. optval := -1;
  6954. iStatus := WSocket_Synchronized_SetSockOpt(FHSocket, SOL_SOCKET,
  6955. SO_REUSEADDR,
  6956. optval, SizeOf(optval));
  6957. if iStatus <> 0 then begin
  6958. SocketError('setsockopt(SO_REUSEADDR)');
  6959. Close;
  6960. Exit;
  6961. end;
  6962. end;
  6963. end;
  6964. iStatus := WSocket_Synchronized_bind(FHSocket, TSockAddr(sin), sizeof(sin));
  6965. if iStatus = 0 then
  6966. ChangeState(wsBound)
  6967. else begin
  6968. SocketError('Bind');
  6969. Close;
  6970. Exit;
  6971. end;
  6972. case FType of
  6973. {$IFDEF WIN32}
  6974. {$IFDEF COMPILER2_UP}
  6975. SOCK_RAW :
  6976. begin
  6977. if HasOption(FComponentOptions, wsoSIO_RCVALL) then begin
  6978. dwBufferInLen := 1;
  6979. dwBufferOutLen := 0;
  6980. iStatus := WSocket_Synchronized_WSAIoctl(FHSocket, SIO_RCVALL,
  6981. @dwBufferInLen, SizeOf(dwBufferInLen),
  6982. @dwBufferOutLen, SizeOf(dwBufferOutLen),
  6983. dwDummy, nil, nil);
  6984. if iStatus = SOCKET_ERROR then begin
  6985. SocketError('WSAIoctl(SIO_RCVALL)');
  6986. Close;
  6987. Exit;
  6988. end;
  6989. end;
  6990. ChangeState(wsListening);
  6991. ChangeState(wsConnected);
  6992. TriggerSessionConnectedSpecial(0);
  6993. end;
  6994. {$ENDIF}
  6995. {$ENDIF}
  6996. SOCK_DGRAM :
  6997. begin
  6998. if FMultiCast then begin
  6999. { Use setsockopt() to join a multicast group }
  7000. { mreq.imr_multiaddr.s_addr := WSocket_inet_addr('225.0.0.37');}
  7001. { mreq.imr_multiaddr.s_addr := sin.sin_addr.s_addr;}
  7002. { mreq.imr_multiaddr.s_addr := WSocket_inet_addr(FAddrStr);}
  7003. mreq.imr_multiaddr.s_addr := WSocket_Synchronized_inet_addr(AnsiString(FMultiCastAddrStr));
  7004. { mreq.imr_interface.s_addr := htonl(INADDR_ANY);} { RK}
  7005. mreq.imr_interface.s_addr := WSocket_Synchronized_ResolveHost(AnsiString(FAddrStr)).s_addr;
  7006. iStatus := WSocket_Synchronized_SetSockOpt(FHSocket, IPPROTO_IP,
  7007. IP_ADD_MEMBERSHIP,
  7008. mreq, SizeOf(mreq));
  7009. if iStatus <> 0 then begin
  7010. SocketError('setsockopt(IP_ADD_MEMBERSHIP)');
  7011. Exit;
  7012. end;
  7013. end;
  7014. ChangeState(wsListening);
  7015. ChangeState(wsConnected);
  7016. TriggerSessionConnectedSpecial(0);
  7017. end;
  7018. SOCK_STREAM :
  7019. begin
  7020. iStatus := WSocket_Synchronized_listen(FHSocket, FListenBacklog);
  7021. if iStatus = 0 then
  7022. ChangeState(wsListening)
  7023. else begin
  7024. SocketError('Listen');
  7025. Exit;
  7026. end;
  7027. end;
  7028. else
  7029. SocketError('Listen: unexpected protocol.');
  7030. Exit;
  7031. end;
  7032. { FP:26/09/06 Are FD_READ and FD_WRITE really necessary ? Probably not ! }
  7033. { Lodewijk Ellen reported a problem with W2K3SP1 triggering an AV in }
  7034. { accept. Keeping only FD_ACCEPT and FD_CLOSE solved the problem. }
  7035. { Anyway, a listening socket doesn't send nor receive any data so those }
  7036. { notification are useless. }
  7037. FSelectEvent := FD_ACCEPT or FD_CLOSE;
  7038. if FType <> SOCK_STREAM then
  7039. FSelectEvent := FSelectEvent or FD_READ or FD_WRITE;
  7040. iStatus := WSocket_Synchronized_WSAASyncSelect(FHSocket, Handle,
  7041. FMsg_WM_ASYNCSELECT,
  7042. FSelectEvent);
  7043. if iStatus <> 0 then begin
  7044. SocketError('WSAASyncSelect');
  7045. exit;
  7046. end;
  7047. end;
  7048. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  7049. function TCustomWSocket.Accept: TSocket;
  7050. var
  7051. len : Integer;
  7052. begin
  7053. if FState <> wsListening then begin
  7054. WSocket_Synchronized_WSASetLastError(WSAEINVAL);
  7055. SocketError('not a listening socket');
  7056. Result := INVALID_SOCKET;
  7057. Exit;
  7058. end;
  7059. len := sizeof(sin);
  7060. {$IFDEF DELPHI1} { Delphi 1 }
  7061. FASocket := WSocket_Synchronized_accept(FHSocket, TSockAddr(sin), len);
  7062. {$ELSE}
  7063. {$IFDEF VER90} { Delphi 2}
  7064. FASocket := WSocket_Synchronized_accept(FHSocket, TSockAddr(sin), len);
  7065. {$ELSE}
  7066. {$IFDEF CLR}
  7067. FASocket := WSocket_Synchronized_accept(FHSocket, sin, len);
  7068. {$ELSE}
  7069. { Delphi 3/4, Bcb 1/3/4 use pointers instead of var parameters }
  7070. FASocket := WSocket_Synchronized_accept(FHSocket, @sin, @len);
  7071. {$ENDIF}
  7072. {$ENDIF}
  7073. {$ENDIF}
  7074. if FASocket = INVALID_SOCKET then begin
  7075. SocketError('Accept');
  7076. Result := INVALID_SOCKET;
  7077. Exit;
  7078. end
  7079. else
  7080. Result := FASocket;
  7081. end;
  7082. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  7083. procedure TCustomWSocket.Pause;
  7084. begin
  7085. FPaused := TRUE;
  7086. WSocket_Synchronized_WSAASyncSelect(FHSocket, Handle, 0, 0);
  7087. end;
  7088. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  7089. procedure TCustomWSocket.Resume;
  7090. begin
  7091. FPaused := FALSE;
  7092. WSocket_Synchronized_WSAASyncSelect(FHSocket, Handle,
  7093. FMsg_WM_ASYNCSELECT, FSelectEvent);
  7094. end;
  7095. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  7096. procedure TCustomWSocket.Shutdown(How : Integer);
  7097. begin
  7098. {$IFNDEF NO_DEBUG_LOG}
  7099. if CheckLogOptions(loWsockInfo) then { V5.21 } { replaces $IFDEF DEBUG_OUTPUT }
  7100. DebugLog(loWsockInfo, {$IFNDEF CLR}_IntToHex(INT_PTR(Self), SizeOf(Pointer) * 2) + ' ' +{$ENDIF}
  7101. 'TCustomWSocket.Shutdown ' + _IntToStr(How) + ' ' + _IntToStr(FHSocket));
  7102. {$ENDIF}
  7103. if FHSocket <> INVALID_SOCKET then
  7104. WSocket_Synchronized_shutdown(FHSocket, How);
  7105. end;
  7106. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  7107. procedure TCustomWSocket.DeleteBufferedData;
  7108. begin
  7109. if Assigned(FBufHandler) then begin
  7110. FBufHandler.Lock;
  7111. try
  7112. FBufHandler.DeleteAllData;
  7113. FBufferedByteCount := 0;
  7114. finally
  7115. FBufHandler.UnLock;
  7116. end;
  7117. end;
  7118. end;
  7119. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  7120. procedure TCustomWSocket.Abort;
  7121. begin
  7122. InternalAbort(0);
  7123. end;
  7124. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  7125. procedure TCustomWSocket.InternalAbort(ErrCode : Word);
  7126. begin
  7127. CancelDnsLookup;
  7128. DeleteBufferedData;
  7129. { Be sure to close as fast as possible (abortive close) }
  7130. if (State = wsConnected) and (FProto = IPPROTO_TCP) then begin
  7131. LingerOnOff := wsLingerOff;
  7132. SetLingerOption;
  7133. end;
  7134. InternalClose(FALSE, ErrCode);
  7135. end;
  7136. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  7137. procedure TCustomWSocket.Close;
  7138. begin
  7139. InternalClose(TRUE, 0);
  7140. end;
  7141. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  7142. procedure TCustomWSocket.CloseDelayed;
  7143. begin
  7144. _PostMessage(Handle, FMsg_WM_CLOSE_DELAYED, 0, 0);
  7145. end;
  7146. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  7147. //procedure TCustomWSocket.Release;
  7148. //begin
  7149. // PostMessage(Handle, FMsg_WM_WSOCKET_RELEASE, 0, 0);
  7150. //end;
  7151. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  7152. procedure TCustomWSocket.WMCloseDelayed(var msg: TMessage);
  7153. begin
  7154. Close;
  7155. end;
  7156. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  7157. //procedure TCustomWSocket.WMRelease(var msg: TMessage);
  7158. //begin
  7159. // Destroy;
  7160. //end;
  7161. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  7162. procedure TCustomWSocket.Flush;
  7163. begin
  7164. while (FHSocket <> INVALID_SOCKET) and { No more socket }
  7165. (not bAllSent) do begin { Nothing to send }
  7166. { Break; }
  7167. TryToSend;
  7168. MessagePump;
  7169. end;
  7170. end;
  7171. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  7172. procedure TCustomWSocket.InternalClose(bShut : Boolean; Error : Word);
  7173. var
  7174. iStatus : Integer;
  7175. { Buffer : array [0..127] of Char; }
  7176. begin
  7177. if FHSocket = INVALID_SOCKET then begin
  7178. if FState <> wsClosed then begin
  7179. ChangeState(wsClosed);
  7180. AssignDefaultValue;
  7181. end;
  7182. Exit;
  7183. end;
  7184. if FState = wsClosed then
  7185. Exit;
  7186. { 11/10/98 called shutdown(1) instead of shutdown(2). This disables only }
  7187. { sends. Disabling receives as well produced data lost is some cases. }
  7188. { Manifest constants for Shutdown }
  7189. { SD_RECEIVE = 0; disables receives }
  7190. { SD_SEND = 1; disables sends, *Use this one for graceful close* }
  7191. { SD_BOTH = 2; disables both sends and receives }
  7192. if bShut then
  7193. ShutDown(1);
  7194. if FHSocket <> INVALID_SOCKET then begin
  7195. repeat
  7196. { Close the socket }
  7197. iStatus := WSocket_Synchronized_closesocket(FHSocket);
  7198. if iStatus <> 0 then begin
  7199. FLastError := WSocket_Synchronized_WSAGetLastError;
  7200. if FLastError <> WSAEWOULDBLOCK then begin
  7201. FHSocket := INVALID_SOCKET;
  7202. { Ignore the error occuring when winsock DLL not }
  7203. { initialized (occurs when using TWSocket from a DLL) }
  7204. if FLastError = WSANOTINITIALISED then
  7205. break;
  7206. SocketError('Disconnect (closesocket)');
  7207. Exit;
  7208. end;
  7209. MessagePump;
  7210. end;
  7211. until iStatus = 0;
  7212. FHSocket := INVALID_SOCKET;
  7213. end;
  7214. ChangeState(wsClosed);
  7215. if {$IFDEF WIN32}(not (csDestroying in ComponentState)) and {$ENDIF}
  7216. (not FCloseInvoked) {and Assigned(FOnSessionClosed)} then begin
  7217. FCloseInvoked := TRUE;
  7218. TriggerSessionClosed(Error);
  7219. end;
  7220. { 29/09/98 Protect AssignDefaultValue because SessionClosed event handler }
  7221. { may have destroyed the component. }
  7222. try
  7223. AssignDefaultValue;
  7224. except
  7225. end;
  7226. end;
  7227. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  7228. procedure TCustomWSocket.WaitForClose;
  7229. var
  7230. lCount : {$IFDEF FPC} LongWord; {$ELSE} u_long; {$ENDIF}
  7231. Status : Integer;
  7232. DataBuf : TWSocketData;
  7233. {$IFDEF WIN32}
  7234. Ch : Char;
  7235. {$ENDIF}
  7236. begin
  7237. while (FHSocket <> INVALID_SOCKET) and (FState <> wsClosed) do begin
  7238. MessagePump;
  7239. if WSocket_Synchronized_ioctlsocket(FHSocket, FIONREAD, lCount) = SOCKET_ERROR then
  7240. break;
  7241. if lCount > 0 then
  7242. TriggerDataAvailable(0);
  7243. {$IFDEF CLR}
  7244. SetLength(DataBuf, 1);
  7245. {$ENDIF}
  7246. {$IFDEF WIN32}
  7247. DataBuf := @Ch;
  7248. {$ENDIF}
  7249. Status := DoRecv(DataBuf, 1, 0);
  7250. if Status <= 0 then begin
  7251. FLastError := WSocket_Synchronized_WSAGetLastError;
  7252. if FLastError <> WSAEWOULDBLOCK then
  7253. break;
  7254. end;
  7255. MessagePump;
  7256. end;
  7257. end;
  7258. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  7259. {$IFDEF CLR}
  7260. function WSocketGetHostByAddr(const Addr : String) : IntPtr;
  7261. var
  7262. lAddr : u_long;
  7263. LookupIntPtr : IntPtr;
  7264. begin
  7265. if Length(Addr) = 0 then
  7266. raise ESocketException.Create('Winsock Get Host Addr: Invalid address.'); { V5.26 }
  7267. lAddr := WSocket_inet_addr(Addr);
  7268. LookupIntPtr := WSocket_gethostbyaddr(lAddr, 4, PF_INET);
  7269. Result := LookupIntPtr;
  7270. end;
  7271. {$ENDIF}
  7272. {$IFDEF WIN32}
  7273. function WSocketGetHostByAddr(Addr : AnsiString) : PHostEnt;
  7274. var
  7275. szAddr : array[0..256] of AnsiChar;
  7276. lAddr : u_long;
  7277. begin
  7278. if (Length(Addr) = 0) or (Length(Addr) >= SizeOf(szAddr)) then
  7279. raise ESocketException.Create('Winsock Get Host Addr: Invalid address.'); { V5.26 }
  7280. _StrPCopy(szAddr, Addr); { Length already checked above }
  7281. lAddr := WSocket_inet_addr(szAddr);
  7282. Result := WSocket_gethostbyaddr(PAnsiChar(@lAddr), 4, PF_INET);
  7283. end;
  7284. {$ENDIF}
  7285. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  7286. function WSocketResolveIp(IpAddr : AnsiString) : AnsiString;
  7287. {$IFDEF CLR}
  7288. var
  7289. HostEntry : THostEnt;
  7290. LookupIntPtr : IntPtr;
  7291. begin
  7292. LookupIntPtr := WSocketGetHostByAddr(IpAddr);
  7293. if LookupIntPtr = IntPtr.Zero then
  7294. Result := ''
  7295. else begin
  7296. HostEntry := THostEnt(Marshal.PtrToStructure(LookupIntPtr,
  7297. TypeOf(THostEnt)));
  7298. Result := Marshal.PtrToStringAnsi(HostEntry.h_name);
  7299. end;
  7300. end;
  7301. {$ENDIF}
  7302. {$IFDEF WIN32}
  7303. var
  7304. Phe : PHostEnt;
  7305. begin
  7306. phe := WSocketGetHostByAddr(IpAddr);
  7307. if Phe = nil then
  7308. Result := ''
  7309. else begin
  7310. SetLength(Result, _StrLen(Phe^.h_name));
  7311. _StrCopy(@Result[1], Phe^.h_name);
  7312. end;
  7313. end;
  7314. {$ENDIF}
  7315. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  7316. {$IFDEF CLR}
  7317. function WSocketGetHostByName(const Name : String) : IntPtr;
  7318. begin
  7319. if Length(Name) = 0 then
  7320. raise ESocketException.Create('Winsock Get Host Name: Invalid Hostname.'); { V5.26 }
  7321. Result := WSocket_gethostbyname(Name);
  7322. end;
  7323. {$ENDIF}
  7324. {$IFDEF WIN32}
  7325. function WSocketGetHostByName(Name : AnsiString) : PHostEnt;
  7326. var
  7327. szName : array[0..256] of AnsiChar;
  7328. begin
  7329. if (Length(Name) = 0) or (Length(Name) >= SizeOf(szName)) then
  7330. raise ESocketException.Create('Winsock Get Host Name: Invalid Hostname.'); { V5.26 }
  7331. _StrPCopy(szName, Name);
  7332. Result := WSocket_gethostbyname(szName);
  7333. end;
  7334. {$ENDIF}
  7335. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  7336. function LocalIPList : TStrings;
  7337. {$IFDEF CLR}
  7338. var
  7339. HostEntry : THostEnt;
  7340. LookupIntPtr : IntPtr;
  7341. begin
  7342. IPList.Clear;
  7343. Result := IPList;
  7344. LookupIntPtr := WSocketGetHostByName(LocalHostName);
  7345. if LookupIntPtr <> IntPtr.Zero then begin
  7346. HostEntry := THostEnt(Marshal.PtrToStructure(LookupIntPtr,
  7347. TypeOf(THostEnt)));
  7348. GetIpList(HostEntry, IPList);
  7349. end;
  7350. end;
  7351. {$ENDIF}
  7352. {$IFDEF WIN32}
  7353. var
  7354. phe : PHostEnt;
  7355. begin
  7356. IPList.Clear;
  7357. Result := IPList;
  7358. phe := WSocketGetHostByName(LocalHostName);
  7359. if phe <> nil then
  7360. GetIpList(Phe, IPList);
  7361. end;
  7362. {$ENDIF}
  7363. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  7364. function LocalHostName : AnsiString;
  7365. begin
  7366. if WSocket_gethostname(Result) <> 0 then
  7367. raise ESocketException.Create('Winsock Get Host Name failed');
  7368. end;
  7369. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  7370. function TCustomWSocket.TimerIsSet(var tvp : TTimeVal) : Boolean;
  7371. begin
  7372. Result := (tvp.tv_sec <> 0) or (tvp.tv_usec <> 0);
  7373. end;
  7374. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  7375. function TCustomWSocket.TimerCmp(var tvp : TTimeVal; var uvp : TTimeVal; IsEqual : Boolean) : Boolean;
  7376. begin
  7377. Result := (tvp.tv_sec = uvp.tv_sec) and (tvp.tv_usec = uvp.tv_usec);
  7378. if not IsEqual then
  7379. Result := not Result;
  7380. end;
  7381. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  7382. procedure TCustomWSocket.TimerClear(var tvp : TTimeVal);
  7383. begin
  7384. tvp.tv_sec := 0;
  7385. tvp.tv_usec := 0;
  7386. end;
  7387. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  7388. procedure TCustomWSocket.SetSendFlags(newValue : TSocketSendFlags);
  7389. begin
  7390. case newValue of
  7391. wsSendNormal: FSendFlags := 0;
  7392. wsSendUrgent: FSendFlags := MSG_OOB;
  7393. else
  7394. RaiseException('Invalid SendFlags');
  7395. end;
  7396. end;
  7397. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  7398. function TCustomWSocket.GetSendFlags : TSocketSendFlags;
  7399. begin
  7400. case FSendFlags of
  7401. 0 : Result := wsSendNormal;
  7402. MSG_OOB : Result := wsSendUrgent;
  7403. else
  7404. RaiseException('Invalid internal SendFlags');
  7405. Result := wsSendNormal;
  7406. end;
  7407. end;
  7408. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  7409. procedure TCustomWSocket.TriggerDebugDisplay(Msg : String);
  7410. begin
  7411. if Assigned(FOnDebugDisplay) then
  7412. FOnDebugDisplay(Self, Msg);
  7413. end;
  7414. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  7415. procedure TCustomWSocket.TriggerSendData(BytesSent : Integer);
  7416. begin
  7417. if Assigned(FOnSendData) then
  7418. FOnSendData(Self, BytesSent);
  7419. end;
  7420. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  7421. procedure TCustomWSocket.TriggerSessionAvailable(Error : Word);
  7422. begin
  7423. if Assigned(FOnSessionAvailable) then
  7424. FOnSessionAvailable(Self, Error);
  7425. end;
  7426. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  7427. procedure TCustomWSocket.TriggerSessionConnectedSpecial(Error : Word);
  7428. begin
  7429. if Assigned(FCounter) and (FType = SOCK_STREAM) and (Error = 0) then
  7430. FCounter.SetConnected;
  7431. TriggerSessionConnected(Error);
  7432. end;
  7433. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  7434. procedure TCustomWSocket.TriggerSessionConnected(Error : Word);
  7435. begin
  7436. FReadCount := 0; { 7.24 }
  7437. FWriteCount := 0; { 7.24 }
  7438. if Assigned(FOnSessionConnected) then
  7439. FOnSessionConnected(Self, Error);
  7440. end;
  7441. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  7442. procedure TCustomWSocket.TriggerSessionClosed(Error : Word);
  7443. begin
  7444. if Assigned(FOnSessionClosed) then
  7445. FOnSessionClosed(Self, Error);
  7446. end;
  7447. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  7448. function TCustomWSocket.TriggerDataAvailable(Error : Word) : Boolean;
  7449. begin
  7450. Result := Assigned(FOnDataAvailable);
  7451. if not Result then
  7452. Exit;
  7453. {$IFDEF TOMASEK} { 23/01/99 }
  7454. { Do not allow FD_READ messages, this will prevent reentering the }
  7455. { OnDataAvailable event handler. }
  7456. FSelectEvent := FD_WRITE or FD_CLOSE or FD_CONNECT;
  7457. WSocket_Synchronized_WSAASyncSelect(FHSocket, Handle, WM_ASYNCSELECT, FSelectEvent);
  7458. try
  7459. FRcvdFlag := TRUE;
  7460. while Result and FRcvdFlag do begin
  7461. { Trigger user code. This will normally call DoRecv which will }
  7462. { update FRcvdFlag. }
  7463. { If user code is wrong, we'll loop forever ! }
  7464. FOnDataAvailable(Self, Error);
  7465. Result := Assigned(FOnDataAvailable);
  7466. end;
  7467. finally
  7468. { Allow all events now }
  7469. FSelectEvent := FD_READ or FD_WRITE or FD_CLOSE or FD_CONNECT;
  7470. WSocket_Synchronized_WSAASyncSelect(FHSocket, Handle, WM_ASYNCSELECT, FSelectEvent);
  7471. end;
  7472. {$ELSE} { 23/01/99 }
  7473. FOnDataAvailable(Self, Error); { 23/01/99 }
  7474. {$ENDIF} { 23/01/99 }
  7475. end;
  7476. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  7477. procedure TCustomWSocket.TriggerDataSent(Error : Word);
  7478. begin
  7479. {$IFNDEF NO_DEBUG_LOG}
  7480. if CheckLogOptions(loWsockDump) then { V5.21 } { replaces $IFDEF DEBUG_OUTPUT }
  7481. DebugLog(loWsockDump,
  7482. {$IFNDEF CLR}
  7483. _IntToHex(INT_PTR(Self), SizeOf(Pointer) * 2) + ' ' +
  7484. {$ENDIF}
  7485. 'TriggerDataSent ' + _IntToStr(FHSocket));
  7486. {$ENDIF}
  7487. if Assigned(FOnDataSent) then
  7488. FOnDataSent(Self, Error);
  7489. end;
  7490. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  7491. procedure TCustomWSocket.TriggerError;
  7492. begin
  7493. if Assigned(FOnError) then
  7494. FOnError(Self);
  7495. end;
  7496. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  7497. procedure TCustomWSocket.TriggerDNSLookupDone(Error : Word);
  7498. begin
  7499. if Assigned(FOnDNSLookupDone) then
  7500. FOnDNSLookupDone(Self, Error);
  7501. end;
  7502. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  7503. procedure TCustomWSocket.TriggerChangeState(OldState, NewState : TSocketState);
  7504. begin
  7505. if Assigned(FOnChangeState) then
  7506. FOnChangeState(Self, OldState, NewState);
  7507. end;
  7508. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  7509. procedure TCustomWSocket.SocketError(sockfunc: String);
  7510. var
  7511. Error : Integer;
  7512. Line : String;
  7513. begin
  7514. Error := WSocket_Synchronized_WSAGetLastError;
  7515. { Line := 'Error '+ IntToStr(Error) + ' in function ' + sockfunc +
  7516. #13#10 + WSocketErrorDesc(Error); }
  7517. Line := WSocketErrorDesc(Error) + ' (#' + _IntToStr(Error) +
  7518. ' in ' + sockfunc + ')' ; { V5.26 }
  7519. if (Error = WSAECONNRESET) or
  7520. (Error = WSAENOTCONN) then begin
  7521. WSocket_Synchronized_closesocket(FHSocket);
  7522. FHSocket := INVALID_SOCKET;
  7523. if FState <> wsClosed then
  7524. TriggerSessionClosed(Error);
  7525. ChangeState(wsClosed);
  7526. end;
  7527. FLastError := Error;
  7528. RaiseException(Line);
  7529. end;
  7530. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} { V5.21 }
  7531. {$IFNDEF NO_DEBUG_LOG}
  7532. function TCustomWSocket.CheckLogOptions(const LogOption: TLogOption): Boolean;
  7533. begin
  7534. Result := Assigned(FIcsLogger) and (LogOption in FIcsLogger.LogOptions);
  7535. end;
  7536. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  7537. procedure TCustomWSocket.DebugLog(LogOption: TLogOption; const Msg: String); { V5.21 }
  7538. begin
  7539. if Assigned(FIcsLogger) then
  7540. FIcsLogger.DoDebugLog(Self, LogOption, Msg);
  7541. end;
  7542. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} { V5.21 }
  7543. procedure TCustomWSocket.SetIcsLogger(const Value: TIcsLogger);
  7544. begin
  7545. FIcsLogger := Value;
  7546. if Value <> nil then
  7547. Value.FreeNotification(Self);
  7548. end;
  7549. {$ENDIF}
  7550. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  7551. procedure TCustomWSocket.SetSocketRcvBufSize(BufSize : Integer);
  7552. var
  7553. iStatus : Integer;
  7554. optlen : Integer;
  7555. begin
  7556. optlen := SizeOf(BufSize);
  7557. {$IFDEF CLR}
  7558. iStatus := WSocket_setsockopt(FHSocket, SOL_SOCKET, SO_RCVBUF,
  7559. BufSize, optlen);
  7560. {$ELSE}
  7561. iStatus := WSocket_setsockopt(FHSocket, SOL_SOCKET, SO_RCVBUF,
  7562. PAnsiChar(@BufSize), optlen);
  7563. {$ENDIF}
  7564. if iStatus = 0 then
  7565. FSocketSndBufSize := BufSize
  7566. else
  7567. SocketError('setsockopt(SO_RCVBUF)');
  7568. end;
  7569. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  7570. procedure TCustomWSocket.SetSocketSndBufSize(BufSize : Integer);
  7571. var
  7572. iStatus : Integer;
  7573. optlen : Integer;
  7574. begin
  7575. optlen := SizeOf(BufSize);
  7576. {$IFDEF CLR}
  7577. iStatus := WSocket_setsockopt(FHSocket, SOL_SOCKET, SO_SNDBUF,
  7578. BufSize, optlen);
  7579. {$ELSE}
  7580. iStatus := WSocket_setsockopt(FHSocket, SOL_SOCKET, SO_SNDBUF,
  7581. PAnsiChar(@BufSize), optlen);
  7582. {$ENDIF}
  7583. if iStatus = 0 then
  7584. FSocketSndBufSize := BufSize
  7585. else
  7586. SocketError('setsockopt(SO_SNDBUF)');
  7587. end;
  7588. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  7589. function WSocketErrorDesc(ErrCode : Integer) : String;
  7590. begin
  7591. case ErrCode of
  7592. 0:
  7593. WSocketErrorDesc := 'No Error';
  7594. WSAEINTR:
  7595. WSocketErrorDesc := 'Interrupted system call';
  7596. WSAEBADF:
  7597. WSocketErrorDesc := 'Bad file number';
  7598. WSAEACCES:
  7599. WSocketErrorDesc := 'Permission denied';
  7600. WSAEFAULT:
  7601. WSocketErrorDesc := 'Bad address';
  7602. WSAEINVAL:
  7603. WSocketErrorDesc := 'Invalid argument';
  7604. WSAEMFILE:
  7605. WSocketErrorDesc := 'Too many open files';
  7606. WSAEWOULDBLOCK:
  7607. WSocketErrorDesc := 'Operation would block';
  7608. WSAEINPROGRESS:
  7609. WSocketErrorDesc := 'Operation now in progress';
  7610. WSAEALREADY:
  7611. WSocketErrorDesc := 'Operation already in progress';
  7612. WSAENOTSOCK:
  7613. WSocketErrorDesc := 'Socket operation on non-socket';
  7614. WSAEDESTADDRREQ:
  7615. WSocketErrorDesc := 'Destination address required';
  7616. WSAEMSGSIZE:
  7617. WSocketErrorDesc := 'Message too long';
  7618. WSAEPROTOTYPE:
  7619. WSocketErrorDesc := 'Protocol wrong type for socket';
  7620. WSAENOPROTOOPT:
  7621. WSocketErrorDesc := 'Protocol not available';
  7622. WSAEPROTONOSUPPORT:
  7623. WSocketErrorDesc := 'Protocol not supported';
  7624. WSAESOCKTNOSUPPORT:
  7625. WSocketErrorDesc := 'Socket type not supported';
  7626. WSAEOPNOTSUPP:
  7627. WSocketErrorDesc := 'Operation not supported on socket';
  7628. WSAEPFNOSUPPORT:
  7629. WSocketErrorDesc := 'Protocol family not supported';
  7630. WSAEAFNOSUPPORT:
  7631. WSocketErrorDesc := 'Address family not supported by protocol family';
  7632. WSAEADDRINUSE:
  7633. WSocketErrorDesc := 'Address already in use';
  7634. WSAEADDRNOTAVAIL:
  7635. WSocketErrorDesc := 'Address not available';
  7636. WSAENETDOWN:
  7637. WSocketErrorDesc := 'Network is down';
  7638. WSAENETUNREACH:
  7639. WSocketErrorDesc := 'Network is unreachable';
  7640. WSAENETRESET:
  7641. WSocketErrorDesc := 'Network dropped connection on reset';
  7642. WSAECONNABORTED:
  7643. WSocketErrorDesc := 'Connection aborted';
  7644. WSAECONNRESET:
  7645. WSocketErrorDesc := 'Connection reset by peer';
  7646. WSAENOBUFS:
  7647. WSocketErrorDesc := 'No buffer space available';
  7648. WSAEISCONN:
  7649. WSocketErrorDesc := 'Socket is already connected';
  7650. WSAENOTCONN:
  7651. WSocketErrorDesc := 'Socket is not connected';
  7652. WSAESHUTDOWN:
  7653. WSocketErrorDesc := 'Can''t send after socket shutdown';
  7654. WSAETOOMANYREFS:
  7655. WSocketErrorDesc := 'Too many references: can''t splice';
  7656. WSAETIMEDOUT:
  7657. WSocketErrorDesc := 'Connection timed out';
  7658. WSAECONNREFUSED:
  7659. WSocketErrorDesc := 'Connection refused';
  7660. WSAELOOP:
  7661. WSocketErrorDesc := 'Too many levels of symbolic links';
  7662. WSAENAMETOOLONG:
  7663. WSocketErrorDesc := 'File name too long';
  7664. WSAEHOSTDOWN:
  7665. WSocketErrorDesc := 'Host is down';
  7666. WSAEHOSTUNREACH:
  7667. WSocketErrorDesc := 'No route to host';
  7668. WSAENOTEMPTY:
  7669. WSocketErrorDesc := 'Directory not empty';
  7670. WSAEPROCLIM:
  7671. WSocketErrorDesc := 'Too many processes';
  7672. WSAEUSERS:
  7673. WSocketErrorDesc := 'Too many users';
  7674. WSAEDQUOT:
  7675. WSocketErrorDesc := 'Disc quota exceeded';
  7676. WSAESTALE:
  7677. WSocketErrorDesc := 'Stale NFS file handle';
  7678. WSAEREMOTE:
  7679. WSocketErrorDesc := 'Too many levels of remote in path';
  7680. WSASYSNOTREADY:
  7681. WSocketErrorDesc := 'Network sub-system is unusable';
  7682. WSAVERNOTSUPPORTED:
  7683. WSocketErrorDesc := 'WinSock DLL cannot support this application';
  7684. WSANOTINITIALISED:
  7685. WSocketErrorDesc := 'WinSock not initialized';
  7686. WSAHOST_NOT_FOUND:
  7687. WSocketErrorDesc := 'Host not found';
  7688. WSATRY_AGAIN:
  7689. WSocketErrorDesc := 'Non-authoritative host not found';
  7690. WSANO_RECOVERY:
  7691. WSocketErrorDesc := 'Non-recoverable error';
  7692. WSANO_DATA:
  7693. WSocketErrorDesc := 'No Data';
  7694. else
  7695. WSocketErrorDesc := 'Not a WinSock error';
  7696. end;
  7697. end;
  7698. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  7699. function GetWinsockErr(ErrCode: Integer): String ; { V5.26 }
  7700. begin
  7701. Result := WSocketErrorDesc(ErrCode) + ' (#' + _IntToStr(ErrCode) + ')' ;
  7702. end;
  7703. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  7704. function GetWindowsErr(ErrCode: Integer): String ; { V5.26 }
  7705. begin
  7706. Result := _SysErrorMessage(ErrCode) + ' (#' + _IntToStr(ErrCode) + ')' ;
  7707. end;
  7708. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  7709. X X X X X X X X X X X X X X
  7710. X X X X X X X X X X X
  7711. X X X X X X X X
  7712. X X X X X X X X X X X
  7713. X X X X X X X X
  7714. X X X X X X X X X X X X
  7715. X X X X X X X X X X X X
  7716. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  7717. constructor TCustomSocksWSocket.Create{$IFDEF VCL}(AOwner: TComponent){$ENDIF};
  7718. begin
  7719. inherited Create{$IFDEF VCL}(AOwner){$ENDIF};
  7720. FSocksUsercode := '';
  7721. FSocksPassword := '';
  7722. end;
  7723. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  7724. procedure TCustomSocksWSocket.AssignDefaultValue;
  7725. begin
  7726. inherited AssignDefaultValue;
  7727. FSocksState := socksData;
  7728. FSocksServer := '';
  7729. FSocksPort := '';
  7730. FSocksLevel := '5';
  7731. FSocksRcvdCnt := 0;
  7732. FSocksPortAssigned := FALSE;
  7733. FSocksServerAssigned := FALSE;
  7734. end;
  7735. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  7736. procedure TCustomSocksWSocket.SetSocksLevel(newValue : String);
  7737. begin
  7738. if State <> wsClosed then begin
  7739. RaiseException('Can''t change socks level if not closed');
  7740. Exit;
  7741. end;
  7742. if (newValue <> '4') and (newValue <> '5') and
  7743. (newValue <> '4A') and (newValue <> '4a') then begin
  7744. RaiseException('Invalid socks level. Must be 4, 4A or 5.');
  7745. Exit;
  7746. end;
  7747. FSocksLevel := _UpperCase(newValue);
  7748. end;
  7749. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  7750. function TCustomSocksWSocket.GetSocksPort: String;
  7751. begin
  7752. Result := FSocksPort;
  7753. end;
  7754. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  7755. procedure TCustomSocksWSocket.SetSocksPort(sPort : String);
  7756. begin
  7757. if State <> wsClosed then begin
  7758. RaiseException('Can''t change socks port if not closed');
  7759. Exit;
  7760. end;
  7761. FSocksPort := _Trim(sPort);
  7762. if Length(FSocksPort) = 0 then begin
  7763. FSocksPortAssigned := FALSE;
  7764. Exit;
  7765. end;
  7766. FSocksPortAssigned := TRUE;
  7767. end;
  7768. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  7769. function TCustomSocksWSocket.GetSocksServer: String;
  7770. begin
  7771. Result := FSocksServer;
  7772. end;
  7773. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  7774. procedure TCustomSocksWSocket.SetSocksServer(sServer : String);
  7775. begin
  7776. if State <> wsClosed then begin
  7777. RaiseException('Can''t change socks server if not closed');
  7778. Exit;
  7779. end;
  7780. FSocksServer := _Trim(sServer);
  7781. if Length(FSocksServer) = 0 then begin
  7782. FSocksServerAssigned := FALSE;
  7783. Exit;
  7784. end;
  7785. FSocksServerAssigned := TRUE;
  7786. end;
  7787. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  7788. procedure TCustomSocksWSocket.Listen;
  7789. begin
  7790. { Check if we really wants to use socks server }
  7791. if not FSocksServerAssigned then begin
  7792. { No socks server assigned, Listen as usual }
  7793. inherited Listen;
  7794. Exit;
  7795. end;
  7796. RaiseException('Listening is not supported thru socks server');
  7797. end;
  7798. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  7799. procedure TCustomSocksWSocket.Connect;
  7800. begin
  7801. { Check if we really wants to use socks server }
  7802. if not FSocksServerAssigned then begin
  7803. { No socks server assigned, connect as usual }
  7804. inherited Connect;
  7805. Exit;
  7806. end;
  7807. if (_LowerCase(FProtoStr) <> 'tcp') and (_Trim(FProtoStr) <> '6') then begin
  7808. RaiseException('TCP is the only protocol supported thru socks server'); { V5.26 }
  7809. Exit;
  7810. end;
  7811. try
  7812. if not FPortResolved then begin
  7813. { The next line will trigger an exception in case of failure }
  7814. sin.sin_port := WSocket_Synchronized_htons(WSocket_Synchronized_ResolvePort(AnsiString(FSocksPort), AnsiString(FProtoStr)));
  7815. FPortResolved := TRUE;
  7816. end;
  7817. if not FAddrResolved then begin
  7818. { The next line will trigger an exception in case of failure }
  7819. sin.sin_addr.s_addr := WSocket_Synchronized_ResolveHost(AnsiString(FSocksServer)).s_addr;
  7820. FAddrResolved := TRUE;
  7821. end;
  7822. { The next line will trigger an exception in case of failure }
  7823. FPortNum := WSocket_Synchronized_ResolvePort(AnsiString(FPortStr), AnsiString(FProtoStr));
  7824. except
  7825. on E:Exception do begin
  7826. RaiseException('Connect: ' + E.Message); { V5.26 }
  7827. Exit;
  7828. end;
  7829. end;
  7830. FSocksState := socksNegociateMethods;
  7831. FRcvCnt := 0;
  7832. inherited Connect;
  7833. end;
  7834. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  7835. {function BufToStr(Buf : PChar; Cnt : Integer) : String;
  7836. begin
  7837. Result := '';
  7838. while Cnt > 0 do begin
  7839. if Buf^ in [#32..#126] then
  7840. Result := Result + Buf^
  7841. else
  7842. Result := Result + '#' + Format('%2.2d', [ord(Buf^)]);
  7843. Inc(Buf);
  7844. Dec(Cnt);
  7845. end;
  7846. end;}
  7847. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  7848. procedure TCustomSocksWSocket.TriggerSessionConnectedSpecial(Error : Word);
  7849. var
  7850. Buf : {$IFDEF CLR}TBytes;{$ELSE}array [0..2] of AnsiChar;{$ENDIF}
  7851. begin
  7852. if FSocksState = socksNegociateMethods then begin
  7853. {ChangeState(wsSocksConnected);}
  7854. TriggerSocksConnected(Error);
  7855. if Error <> 0 then begin
  7856. inherited TriggerSessionConnectedSpecial(Error);
  7857. Exit;
  7858. end;
  7859. if FSocksLevel[1] = '4' then
  7860. SocksDoConnect
  7861. else begin
  7862. if FSocksAuthentication = socksNoAuthentication then
  7863. FSocksAuthNumber := #$00 { No authentification }
  7864. else
  7865. FSocksAuthNumber := #$02; { Usercode/Password }
  7866. {$IFDEF CLR}
  7867. SetLength(Buf, 3);
  7868. Buf[0] := $05; { Version number }
  7869. Buf[1] := $01; { Number of methods }
  7870. Buf[2] := Ord(FSocksAuthNumber); { Method identifier }
  7871. Send(Buf, 3);
  7872. {$ELSE}
  7873. Buf[0] := #$05; { Version number }
  7874. Buf[1] := #$01; { Number of methods }
  7875. Buf[2] := FSocksAuthNumber; { Method identifier }
  7876. Send(@Buf, 3);
  7877. {$ENDIF}
  7878. end;
  7879. end
  7880. else
  7881. inherited TriggerSessionConnectedSpecial(Error);
  7882. end;
  7883. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  7884. procedure TCustomSocksWSocket.TriggerSessionClosed(Error : Word);
  7885. begin
  7886. if FSocksState = socksAuthenticate then
  7887. TriggerSocksAuthState(socksAuthFailure);
  7888. inherited TriggerSessionClosed(Error);
  7889. end;
  7890. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  7891. procedure TCustomSocksWSocket.TriggerSocksConnected(Error : Word);
  7892. begin
  7893. if Assigned(FOnSocksConnected) then
  7894. FOnSocksConnected(Self, Error);
  7895. end;
  7896. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  7897. procedure TCustomSocksWSocket.TriggerSocksError(Error : Integer; Msg : String);
  7898. begin
  7899. if Assigned(FOnSocksError) then
  7900. FOnSocksError(Self, Error, Msg);
  7901. end;
  7902. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  7903. procedure TCustomSocksWSocket.TriggerSocksAuthState(AuthState : TSocksAuthState);
  7904. begin
  7905. if Assigned(FOnSocksAuthState) then
  7906. FOnSocksAuthState(Self, AuthState);
  7907. end;
  7908. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  7909. { Rfc1929 Username/Password Autentication protocol.
  7910. The UNAME field contains the username as known to the source operating system.
  7911. The PLEN field contains the length of the PASSWD field that follows.
  7912. The PASSWD field contains the password association with the given UNAME.
  7913. Rfc1929 does not mention anything about character sets allowed so currently
  7914. the Win32 code below converts the user name and password to ANSI using the
  7915. default system code page. }
  7916. procedure TCustomSocksWSocket.SocksDoAuthenticate;
  7917. {$IFDEF CLR}
  7918. var
  7919. Buf : TBytes;
  7920. I, J : Integer;
  7921. begin
  7922. FSocksState := socksAuthenticate;
  7923. TriggerSocksAuthState(socksAuthStart);
  7924. SetLength(Buf, 128);
  7925. I := 0;
  7926. Buf[I] := $01; {06/03/99} { Socks version }
  7927. Inc(I);
  7928. Buf[I] := Length(FSocksUsercode);
  7929. for J := 1 to Length(FSocksUsercode) do begin
  7930. Inc(I);
  7931. Buf[I] := Ord(FSocksUsercode[J]);
  7932. end;
  7933. Inc(I);
  7934. Buf[I] := Length(FSocksPassword);
  7935. for J := 1 to Length(FSocksPassword) do begin
  7936. Inc(I);
  7937. Buf[I] := Ord(FSocksPassword[J]);
  7938. end;
  7939. Inc(I);
  7940. try
  7941. {TriggerDisplay('Send = ''' + BufToStr(Buf, I) + '''');}
  7942. Send(Buf, I);
  7943. except
  7944. end;
  7945. end;
  7946. {$ENDIF}
  7947. {$IFDEF WIN32}
  7948. var
  7949. Buf : array [0..127] of AnsiChar;
  7950. I : Integer;
  7951. TempS : AnsiString;
  7952. begin
  7953. FSocksState := socksAuthenticate;
  7954. TriggerSocksAuthState(socksAuthStart);
  7955. Buf[0] := #$01; {06/03/99} { Socks version }
  7956. I := 1;
  7957. TempS := AnsiString(FSocksUsercode);
  7958. Buf[I] := AnsiChar(Length(TempS));
  7959. Move(TempS[1], Buf[I + 1], Length(TempS));
  7960. I := I + 1 + Length(TempS);
  7961. TempS := AnsiString(FSocksPassword);
  7962. Buf[I] := AnsiChar(Length(TempS));
  7963. Move(TempS[1], Buf[I + 1], Length(TempS));
  7964. I := I + 1 + Length(TempS);
  7965. try
  7966. {TriggerDisplay('Send = ''' + BufToStr(Buf, I) + '''');}
  7967. Send(@Buf, I);
  7968. except
  7969. end;
  7970. end;
  7971. {$ENDIF}
  7972. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  7973. procedure TCustomSocksWSocket.SocksDoConnect;
  7974. {$IFDEF CLR}
  7975. var
  7976. Buf : TBytes;
  7977. I, J : Integer;
  7978. ErrCode : Integer;
  7979. IP : u_long;
  7980. begin
  7981. FSocksState := socksConnect;
  7982. if FSocksLevel[1] = '4' then begin
  7983. SetLength(Buf, 128);
  7984. Buf[0] := 4; { Version number }
  7985. Buf[1] := 1; { Connect command }
  7986. { Todo: Check the byte order ! }
  7987. Buf[2] := (FPortNum shr 8) and 255; { Port high byte }
  7988. Buf[3] := FPortNum and 255; { Port low byte }
  7989. if FSocksLevel = '4A' then begin
  7990. { Conventional IP saying we can't convert the destination }
  7991. { host's domain name to find its IP address }
  7992. { The destination must then follow the user ID }
  7993. Buf[4] := 0;
  7994. Buf[5] := 0;
  7995. Buf[6] := 0;
  7996. Buf[7] := 1;
  7997. end
  7998. else begin
  7999. { With original SOCKS4, we have to supply the dest address }
  8000. try
  8001. IP := WSocketResolveHost(FAddrStr).s_addr;
  8002. { Todo: Check the byte order ! }
  8003. Buf[4] := (IP shr 24) and 255;
  8004. Buf[5] := (IP shr 16) and 255;
  8005. Buf[6] := (IP shr 8) and 255;
  8006. Buf[7] := IP and 255;
  8007. except
  8008. on E:Exception do begin
  8009. ErrCode := socksHostResolutionFailed;
  8010. TriggerSocksError(ErrCode, E.ClassName + ' ' + E.Message);
  8011. InternalClose(TRUE, ErrCode);
  8012. Exit;
  8013. end;
  8014. end;
  8015. end;
  8016. I := 8;
  8017. if Length(FSocksUsercode) > 0 then begin
  8018. { I'm not sure it has to be like that ! Should I also use the }
  8019. { password or not ? }
  8020. for J := 1 to Length(FSocksUsercode) do begin
  8021. Buf[I] := Ord(FSocksUsercode[J]);
  8022. Inc(I);
  8023. end;
  8024. end;
  8025. Buf[I] := 0;
  8026. Inc(I);
  8027. if FSocksLevel = '4A' then begin
  8028. { We have to supply the destination host name }
  8029. for J := 1 to Length(FAddrStr) do begin
  8030. Buf[I] := Ord(FaddrStr[J]);
  8031. Inc(I);
  8032. end;
  8033. Buf[I] := 0; { Alon Gingold }
  8034. Inc(I); { Alon Gingold }
  8035. end;
  8036. { Buf[I] := #0; Alon Gingold }
  8037. { Inc(I); Alon Gingold }
  8038. end
  8039. else begin
  8040. SetLength(Buf, 128);
  8041. Buf[0] := $05; { Socks version }
  8042. Buf[1] := $01; { Connect command }
  8043. Buf[2] := $00; { Reserved, must be $00 }
  8044. Buf[3] := $03; { Address type is domain name }
  8045. Buf[4] := Length(FAddrStr);
  8046. { Should check buffer overflow }
  8047. I := 5;
  8048. for J := 1 to Length(FAddrStr) do begin
  8049. Buf[I] := Ord(FaddrStr[J]);
  8050. Inc(I);
  8051. end;
  8052. { Todo: Check the byte order ! }
  8053. Buf[I] := (FPortNum shr 8) and 255; { Port high byte }
  8054. Inc(I);
  8055. Buf[I] := FPortNum and 255; { Port low byte }
  8056. Inc(I);
  8057. end;
  8058. try
  8059. {TriggerDisplay('Send = ''' + BufToStr(Buf, I + 2) + '''');}
  8060. //MessageBox(0, BufToStr(Buf, I), 'SocksDoConnect', MB_OK);
  8061. Send(Buf, I);
  8062. except
  8063. end;
  8064. end;
  8065. {$ENDIF}
  8066. {$IFDEF WIN32}
  8067. type
  8068. pu_long = ^u_long;
  8069. var
  8070. Buf : array [0..127] of AnsiChar;
  8071. I : Integer;
  8072. ErrCode : Integer;
  8073. begin
  8074. FSocksState := socksConnect;
  8075. if FSocksLevel[1] = '4' then begin
  8076. Buf[0] := #4; { Version number }
  8077. Buf[1] := #1; { Connect command }
  8078. PWORD(@Buf[2])^ := WSocket_Synchronized_ntohs(FPortNum); { Dest port }
  8079. if FSocksLevel = '4A' then
  8080. { Conventional IP saying we can't convert the destination }
  8081. { host's domain name to find its IP address }
  8082. { The destination must then follow the user ID }
  8083. pu_long(@Buf[4])^ := WSocket_Synchronized_inet_addr('0.0.0.1')
  8084. else begin
  8085. { With original SOCKS4, we have to supply the dest address }
  8086. try
  8087. pu_long(@Buf[4])^ := WSocket_Synchronized_ResolveHost(AnsiString(FAddrStr)).s_addr;
  8088. except
  8089. on E:Exception do begin
  8090. ErrCode := socksHostResolutionFailed;
  8091. TriggerSocksError(ErrCode, E.ClassName + ' ' + E.Message);
  8092. InternalClose(TRUE, ErrCode);
  8093. Exit;
  8094. end;
  8095. end;
  8096. end;
  8097. I := 8;
  8098. if Length(FSocksUsercode) > 0 then begin
  8099. { I'm not sure it has to be like that ! Should I also use the }
  8100. { password or not ? }
  8101. Move(FSocksUsercode[1], Buf[I], Length(FSocksUsercode));
  8102. I := I + Length(FSocksUsercode);
  8103. end;
  8104. Buf[I] := #0;
  8105. Inc(I);
  8106. if FSocksLevel = '4A' then begin
  8107. { We have to supply the destination host name }
  8108. Move(AnsiString(FAddrStr)[1], Buf[I], Length(FAddrStr)); // No length change expected (ASCII)
  8109. I := I + Length(FAddrStr);
  8110. Buf[I] := #0; { Alon Gingold }
  8111. Inc(I); { Alon Gingold }
  8112. end;
  8113. { Buf[I] := #0; Alon Gingold }
  8114. { Inc(I); Alon Gingold }
  8115. end
  8116. else begin
  8117. Buf[0] := #$05; { Socks version }
  8118. Buf[1] := #$01; { Connect command }
  8119. Buf[2] := #$00; { Reserved, must be $00 }
  8120. Buf[3] := #$03; { Address type is domain name }
  8121. Buf[4] := AnsiChar((Length(FAddrStr)));
  8122. { Should check buffer overflow }
  8123. Move(AnsiString(FAddrStr)[1], Buf[5], Length(FAddrStr)); // No length change expected (ASCII)
  8124. I := 5 + Length(FAddrStr);
  8125. PWord(@Buf[I])^ := WSocket_Synchronized_htons(FPortNum);
  8126. I := I + 2;
  8127. end;
  8128. try
  8129. {TriggerDisplay('Send = ''' + BufToStr(Buf, I + 2) + '''');}
  8130. Send(@Buf, I);
  8131. except
  8132. end;
  8133. end;
  8134. {$ENDIF}
  8135. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  8136. procedure TCustomSocksWSocket.DataAvailableError(
  8137. ErrCode : Integer;
  8138. Msg : String);
  8139. begin
  8140. { TriggerSocksError(ErrCode, Msg); }
  8141. { inherited TriggerSessionConnectedSpecial(ErrCode); }
  8142. { InternalClose(TRUE, ErrCode); }
  8143. TriggerSocksError(ErrCode, Msg);
  8144. FSocksState := socksData;
  8145. {**ALON** Added, so TriggerSessionConnectedSpecial will only call inherited}
  8146. {inherited} TriggerSessionConnectedSpecial(ErrCode);
  8147. {**ALON** removed 'inherited' now calls top level}
  8148. InternalClose(TRUE, ErrCode);
  8149. end;
  8150. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  8151. function TCustomSocksWSocket.TriggerDataAvailable(Error : Word) : Boolean;
  8152. var
  8153. Len : Integer;
  8154. I : Integer;
  8155. ErrCode : Word;
  8156. ErrMsg : String;
  8157. InAddr : TInAddr;
  8158. AnsLen : Integer;
  8159. {$IFDEF CLR}
  8160. J : Integer;
  8161. Buf : TBytes;
  8162. {$ENDIF}
  8163. begin
  8164. if FSocksState = socksData then begin
  8165. Result := inherited TriggerDataAvailable(Error);
  8166. Exit;
  8167. end;
  8168. if Error <> 0 then begin
  8169. DataAvailableError(Error, 'data receive error');
  8170. Result := FALSE;
  8171. Exit;
  8172. end;
  8173. {$IFDEF CLR}
  8174. if Length(FRcvBuf) <> 128 then
  8175. SetLength(FRcvBuf, 128);
  8176. if Length(Buf) <> 128 then
  8177. SetLength(Buf, 128);
  8178. {$ENDIF}
  8179. if FSocksState = socksNegociateMethods then begin
  8180. Result := TRUE;
  8181. {$IFDEF CLR}
  8182. Len := Receive(Buf, Length(Buf) - FRcvCnt - 1);
  8183. if Len < 0 then
  8184. Exit;
  8185. for I := 0 to Len - 1 do begin
  8186. FRcvBuf[FRcvCnt] := Buf[I];
  8187. Inc(FRcvCnt);
  8188. end;
  8189. {$ENDIF}
  8190. {$IFDEF WIN32}
  8191. Len := Receive(@FRcvBuf[FRcvCnt], Sizeof(FRcvBuf) - FRcvCnt - 1);
  8192. if Len < 0 then
  8193. Exit;
  8194. FRcvCnt := FRcvCnt + Len;
  8195. {$ENDIF}
  8196. {TriggerDisplay('socksNegociateMethods FrcvBuf = ''' + BufToStr(FRcvBuf, FRcvCnt) + '''');}
  8197. if FSocksLevel[1] = '4' then begin
  8198. { We should never comes here }
  8199. DataAvailableError(socksProtocolError, 'TWSocket logic error');
  8200. Exit;
  8201. end
  8202. else begin { SOCKS5 }
  8203. { We are waiting only two bytes }
  8204. if FRcvCnt < 2 then
  8205. Exit;
  8206. { if FRcvCnt <> 2 then begin 06/03/99}
  8207. { DataAvailableError(socksProtocolError, 'too much data availaible');}
  8208. { Exit; }
  8209. { end; }
  8210. FRcvCnt := 0; { Clear receive counter }
  8211. if FRcvBuf[0] <> $05 then begin
  8212. DataAvailableError(socksVersionError, 'socks version error');
  8213. Exit;
  8214. end;
  8215. if FRcvBuf[1] = $00 then begin
  8216. { No authentication required }
  8217. if FSocksAuthNumber <> #$00 then
  8218. { We asked for authentification, so complains... }
  8219. TriggerSocksAuthState(socksAuthNotRequired);
  8220. end
  8221. else if FRcvBuf[1] = $02 then begin
  8222. { Usercode/Password authentication required }
  8223. SocksDoAuthenticate;
  8224. Exit;
  8225. end
  8226. else begin
  8227. DataAvailableError(socksAuthMethodError, 'authentification method not acceptable');
  8228. Exit;
  8229. end;
  8230. SocksDoConnect;
  8231. end;
  8232. end
  8233. else if FSocksState = socksConnect then begin
  8234. Result := TRUE;
  8235. {TriggerDisplay('socksConnect FrcvBuf = ''' + BufToStr(FRcvBuf, FRcvCnt) + '''');}
  8236. if FSocksLevel[1] = '4' then begin
  8237. { We wants at most 8 characters }
  8238. {$IFDEF CLR}
  8239. Len := Receive(Buf, 8 - FRcvCnt);
  8240. if Len < 0 then
  8241. Exit;
  8242. for I := 0 to Len - 1 do begin
  8243. FRcvBuf[FRcvCnt] := Buf[I];
  8244. Inc(FRcvCnt);
  8245. end;
  8246. {$ENDIF}
  8247. {$IFDEF WIN32}
  8248. Len := Receive(@FRcvBuf[FRcvCnt], 8 - FRcvCnt);
  8249. if Len < 0 then
  8250. Exit;
  8251. FRcvCnt := FRcvCnt + Len;
  8252. {$ENDIF}
  8253. { We are waiting for 8 bytes }
  8254. if FRcvCnt < 8 then
  8255. Exit;
  8256. FRcvCnt := 0; { Clear receive counter }
  8257. if FRcvBuf[0] <> 0 then begin
  8258. DataAvailableError(socksVersionError, 'socks version error');
  8259. Exit;
  8260. end;
  8261. if FRcvBuf[1] <> 90 then begin { david.brock }
  8262. case FRcvBuf[1] of
  8263. 91: ErrCode := socksRejectedOrFailed;
  8264. 92: ErrCode := socksConnectionRefused;
  8265. 93: ErrCode := socksAuthenticationFailed;
  8266. else
  8267. ErrCode := socksUnassignedError;
  8268. end;
  8269. case ErrCode of
  8270. socksRejectedOrFailed :
  8271. ErrMsg := 'request rejected or failed';
  8272. socksConnectionRefused :
  8273. ErrMsg := 'connection refused';
  8274. socksAuthenticationFailed :
  8275. ErrMsg := 'authentification failed';
  8276. else
  8277. ErrMsg := 'unassigned error #' + _IntToStr(Ord(FRcvBuf[1]));
  8278. end;
  8279. DataAvailableError(ErrCode, ErrMsg);
  8280. Exit;
  8281. end;
  8282. FSocksState := socksData;
  8283. { inherited TriggerSessionConnectedSpecial(0); }
  8284. { Result := inherited TriggerDataAvailable(0); }
  8285. {inherited} TriggerSessionConnectedSpecial(0);
  8286. {**ALON** removed 'inherited' now calls top level}
  8287. Result := {inherited} TriggerDataAvailable(0);
  8288. {**ALON** removed 'inherited' now calls top level}
  8289. end
  8290. else begin { SOCKS5 }
  8291. {$IFDEF CLR}
  8292. Len := Receive(Buf, Length(Buf) - FRcvCnt - 1);
  8293. if Len < 0 then
  8294. Exit;
  8295. for I := 0 to Len - 1 do begin
  8296. FRcvBuf[FRcvCnt] := Buf[I];
  8297. Inc(FRcvCnt);
  8298. end;
  8299. {$ENDIF}
  8300. {$IFDEF WIN32}
  8301. Len := Receive(@FRcvBuf[FRcvCnt], Sizeof(FRcvBuf) - FRcvCnt - 1);
  8302. if Len < 0 then
  8303. Exit;
  8304. FRcvCnt := FRcvCnt + Len;
  8305. {$ENDIF}
  8306. if FRcvCnt >= 1 then begin
  8307. { First byte is version, we expect version 5 }
  8308. if FRcvBuf[0] <> $05 then begin
  8309. DataAvailableError(socksVersionError, 'socks version error');
  8310. Exit;
  8311. end;
  8312. end;
  8313. if FRcvCnt >= 2 then begin
  8314. if FRcvBuf[1] <> $00 then begin
  8315. case FRcvBuf[1] of
  8316. 1: ErrCode := socksGeneralFailure;
  8317. 2: ErrCode := socksConnectionNotAllowed;
  8318. 3: ErrCode := socksNetworkUnreachable;
  8319. 4: ErrCode := socksHostUnreachable;
  8320. 5: ErrCode := socksConnectionRefused;
  8321. 6: ErrCode := socksTtlExpired;
  8322. 7: ErrCode := socksUnknownCommand;
  8323. 8: ErrCode := socksUnknownAddressType;
  8324. else
  8325. ErrCode := socksUnassignedError;
  8326. end;
  8327. case ErrCode of
  8328. socksGeneralFailure :
  8329. ErrMsg := 'general SOCKS server failure';
  8330. socksConnectionNotAllowed :
  8331. ErrMsg := 'connection not allowed by ruleset';
  8332. socksNetworkUnreachable :
  8333. ErrMsg := 'network unreachable';
  8334. socksHostUnreachable :
  8335. ErrMsg := 'host unreachable';
  8336. socksConnectionRefused :
  8337. ErrMsg := 'connection refused';
  8338. socksTtlExpired :
  8339. ErrMsg := 'time to live expired';
  8340. socksUnknownCommand :
  8341. ErrMsg := 'command not supported';
  8342. socksUnknownAddressType :
  8343. ErrMsg := 'address type not supported';
  8344. else
  8345. ErrMsg := 'unassigned error #' + _IntToStr(Ord(FRcvBuf[1]));
  8346. end;
  8347. DataAvailableError(ErrCode, ErrMsg);
  8348. Exit;
  8349. end;
  8350. end;
  8351. if FRcvCnt < 5 then
  8352. Exit;
  8353. { We have enough data to learn the answer length }
  8354. if FRcvBuf[3] = $01 then
  8355. AnsLen := 10 { IP V4 address }
  8356. else if FRcvBuf[3] = $03 then
  8357. AnsLen := 7 + Ord(FRcvBuf[4]) { Domain name }
  8358. else
  8359. AnsLen := 5; { Other unsupported }
  8360. if FRcvCnt < AnsLen then
  8361. Exit;
  8362. if FRcvBuf[3] = $01 then begin
  8363. { IP V4 address }
  8364. //Move(FRcvBuf[4], InAddr, 4);
  8365. InAddr.S_addr := FRcvBuf[4] or
  8366. (FRcvBuf[5] shl 8) or
  8367. (FRcvBuf[6] shl 16) or
  8368. (FRcvBuf[7] shl 24);
  8369. FBoundAddr := WSocket_Synchronized_inet_ntoa(InAddr);
  8370. I := 4 + 4;
  8371. end
  8372. else if FRcvBuf[3] = $03 then begin
  8373. { Domain name }
  8374. SetLength(FBoundAddr, Ord(FRcvBuf[4]));
  8375. {$IFDEF CLR}
  8376. for J := 1 to Ord(FRcvBuf[4]) do
  8377. FBoundAddr[J] := Char(FRcvBuf[4 + J]);
  8378. {$ENDIF}
  8379. {$IFDEF WIN32}
  8380. Move(FRcvBuf[5], FBoundAddr[1], Length(FBoundAddr)); { david.brock }
  8381. {$ENDIF}
  8382. I := 4 + Ord(FRcvBuf[4]) + 1;
  8383. end
  8384. else begin
  8385. { Unsupported address type }
  8386. DataAvailableError(socksUnknownAddressType, 'address type not supported');
  8387. Exit;
  8388. end;
  8389. FBoundPort := IcsIntToStrA(WSocket_Synchronized_ntohs(
  8390. FRcvBuf[I] or (FRcvBuf[I + 1] shl 8)));
  8391. I := I + 2;
  8392. FSocksState := socksData;
  8393. { inherited TriggerSessionConnectedSpecial(0); }
  8394. { if IsConsole then WriteLn('SOCKS5 NEGOCIATION OK');}
  8395. {inherited} TriggerSessionConnectedSpecial(0);
  8396. {**ALON** removed 'inherited' now calls top level}
  8397. FSocksRcvdCnt := FRcvCnt - I;
  8398. if FSocksRcvdCnt < 0 then
  8399. FSocksRcvdCnt := 0
  8400. else
  8401. FSocksRcvdPtr := I; //@FRcvBuf[I];
  8402. { Result := inherited TriggerDataAvailable(0);}
  8403. Result := {inherited} TriggerDataAvailable(0);
  8404. {**ALON** removed 'inherited' now calls top level}
  8405. end;
  8406. end
  8407. else if FSocksState = socksAuthenticate then begin
  8408. Result := TRUE;
  8409. {$IFDEF CLR}
  8410. Len := Receive(Buf, Length(Buf) - FRcvCnt - 1);
  8411. if Len < 0 then
  8412. Exit;
  8413. for I := 0 to Len - 1 do begin
  8414. FRcvBuf[FRcvCnt] := Buf[I];
  8415. Inc(FRcvCnt);
  8416. end;
  8417. {$ENDIF}
  8418. {$IFDEF WIN32}
  8419. Len := Receive(@FRcvBuf[FRcvCnt], Sizeof(FRcvBuf) - FRcvCnt - 1);
  8420. if Len < 0 then
  8421. Exit;
  8422. FRcvCnt := FRcvCnt + Len;
  8423. {$ENDIF}
  8424. {TriggerDisplay('socksAuthenticate FrcvBuf = ''' + BufToStr(FRcvBuf, FRcvCnt) + '''');}
  8425. if FRcvCnt >= 1 then begin
  8426. { First byte is version, we expect version 5 }
  8427. if FRcvBuf[0] <> $01 then begin { 06/03/99 }
  8428. { TriggerSocksAuthState(socksAuthFailure); Burlakov 12/11/99 }
  8429. DataAvailableError(socksVersionError, 'socks version error');
  8430. Exit;
  8431. end;
  8432. end;
  8433. if FRcvCnt = 2 then begin
  8434. { Second byte is status }
  8435. if FRcvBuf[1] <> $00 then begin
  8436. { TriggerSocksAuthState(socksAuthFailure); Burlakov 12/11/99 }
  8437. DataAvailableError(socksAuthenticationFailed, 'socks authentication failed');
  8438. Exit;
  8439. end;
  8440. end
  8441. else if FRcvCnt > 2 then begin
  8442. { TriggerSocksAuthState(socksAuthFailure); Burlakov 12/11/99 }
  8443. DataAvailableError(socksProtocolError, 'too much data availaible');
  8444. Exit;
  8445. end;
  8446. FRcvCnt := 0; { 06/03/99 }
  8447. TriggerSocksAuthState(socksAuthSuccess);
  8448. SocksDoConnect;
  8449. end
  8450. else begin
  8451. { We should never comes here ! }
  8452. DataAvailableError(socksInternalError, 'internal error');
  8453. Result := FALSE;
  8454. end;
  8455. end;
  8456. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  8457. function TCustomSocksWSocket.GetRcvdCount : LongInt;
  8458. begin
  8459. if FSocksRcvdCnt <= 0 then
  8460. Result := inherited GetRcvdCount
  8461. else
  8462. Result := FSocksRcvdCnt;
  8463. end;
  8464. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  8465. function TCustomSocksWSocket.DoRecv(
  8466. var Buffer : TWSocketData;
  8467. BufferSize : Integer;
  8468. Flags : Integer) : Integer;
  8469. {$IFDEF CLR}
  8470. var
  8471. I : Integer;
  8472. {$ENDIF}
  8473. begin
  8474. if FSocksRcvdCnt <= 0 then begin
  8475. Result := inherited DoRecv(Buffer, BufferSize, Flags);
  8476. Exit;
  8477. end;
  8478. { We already have received data into our internal buffer }
  8479. if FSocksRcvdCnt <= BufferSize then begin
  8480. { User buffer is greater than received data, copy all and clear }
  8481. {$IFDEF CLR}
  8482. for I := 0 to FSocksRcvdCnt - 1 do
  8483. Buffer[I] := FRcvBuf[FSocksRcvdPtr + I];
  8484. {$ENDIF}
  8485. {$IFDEF WIN32}
  8486. Move(FRcvBuf[FSocksRcvdPtr], Buffer^, FSocksRcvdCnt); { V7.33 }
  8487. {$ENDIF}
  8488. Result := FSocksRcvdCnt;
  8489. FSocksRcvdCnt := 0;
  8490. Exit;
  8491. end;
  8492. { User buffer is smaller, copy as much as possible }
  8493. {$IFDEF CLR}
  8494. for I := 0 to BufferSize - 1 do
  8495. Buffer[I] := FRcvBuf[FSocksRcvdPtr + I];
  8496. {$ENDIF}
  8497. {$IFDEF WIN32}
  8498. Move(FRcvBuf[FSocksRcvdPtr], Buffer^, BufferSize); { V7.33 }
  8499. {$ENDIF}
  8500. Result := BufferSize;
  8501. FSocksRcvdPtr := FSocksRcvdPtr + BufferSize;
  8502. FSocksRcvdCnt := FSocksRcvdCnt - BufferSize;
  8503. end;
  8504. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  8505. X X X X X X X X
  8506. X X X X X X
  8507. X X X X X X
  8508. X X X X X X X X
  8509. X X X X X
  8510. X X X X X
  8511. X X X X X X X X X X X
  8512. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  8513. constructor TCustomLineWSocket.Create{$IFDEF VCL}(AOwner: TComponent){$ENDIF};
  8514. begin
  8515. inherited Create{$IFDEF VCL}(AOwner){$ENDIF};
  8516. FLineEnd := #13#10;
  8517. FLineMode := FALSE;
  8518. FLineEdit := FALSE; { AG 2/12/07}
  8519. FLineLimit := 65536; { Arbitrary line limit }
  8520. end;
  8521. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  8522. destructor TCustomLineWSocket.Destroy;
  8523. begin
  8524. if FRcvdPtr <> nil then begin
  8525. {$IFDEF CLR}
  8526. SetLength(FRcvdPtr, 0);
  8527. {$ENDIF}
  8528. {$IFDEF WIN32}
  8529. FreeMem(FRcvdPtr, FRcvBufSize);
  8530. FRcvdPtr := nil;
  8531. {$ENDIF}
  8532. FRcvBufSize := 0;
  8533. end;
  8534. inherited Destroy;
  8535. end;
  8536. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  8537. procedure TCustomLineWSocket.WndProc(var MsgRec: TMessage);
  8538. begin
  8539. with MsgRec do begin
  8540. if Msg = FMsg_WM_TRIGGER_DATA_AVAILABLE then begin
  8541. { We *MUST* handle all exception to avoid application shutdown }
  8542. try
  8543. WMTriggerDataAvailable(MsgRec)
  8544. except
  8545. on E:Exception do
  8546. HandleBackGroundException(E);
  8547. end;
  8548. end
  8549. else
  8550. inherited WndProc(MsgRec);
  8551. end;
  8552. end;
  8553. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  8554. procedure TCustomLineWSocket.WMTriggerDataAvailable(var msg: TMessage);
  8555. var
  8556. Count : Integer;
  8557. begin
  8558. {$IFDEF OLD_20040117}
  8559. while FRcvdCnt > 0 do
  8560. TriggerDataAvailable(0);
  8561. {$ELSE}
  8562. Count := 0;
  8563. while FRcvdCnt > 0 do begin
  8564. Inc(Count);
  8565. FLineFound := FALSE;
  8566. TriggerDataAvailable(0);
  8567. if (FRcvdCnt <= 0) or
  8568. (FLineMode and (Count > 3) and (not FLineFound)) then
  8569. Break;
  8570. end;
  8571. {$ENDIF}
  8572. end;
  8573. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  8574. procedure TCustomLineWSocket.SetLineMode(newValue : Boolean);
  8575. begin
  8576. if FLineMode = newValue then
  8577. Exit;
  8578. FLineMode := newValue;
  8579. if (FRcvdCnt > 0) or (FLineLength > 0) then
  8580. _PostMessage(Handle, FMsg_WM_TRIGGER_DATA_AVAILABLE, 0, 0);
  8581. end;
  8582. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  8583. {$IFDEF COMPILER12_UP}
  8584. { Returns -1 on error only if event OnError is assigned, otherwise an }
  8585. { ESocketException may be raised. Returns the number of bytes written on }
  8586. { success. LineEnd is treated as a raw sequence of bytes, hence it's not }
  8587. { converted but sent as is. }
  8588. function TCustomLineWSocket.SendLine(
  8589. const Str : UnicodeString;
  8590. ACodePage : LongWord) : Integer;
  8591. begin
  8592. Result := PutStringInSendBuffer(Str, ACodePage);
  8593. if Result > 0 then begin
  8594. if SendStr(LineEnd) > -1 then
  8595. Inc(Result, Length(LineEnd))
  8596. else
  8597. Result := -1;
  8598. end;
  8599. end;
  8600. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  8601. function TCustomLineWSocket.SendLine(const Str : UnicodeString) : Integer;
  8602. begin
  8603. Result := PutStringInSendBuffer(Str);
  8604. if Result > 0 then begin
  8605. if SendStr(LineEnd) > -1 then
  8606. Inc(Result, Length(LineEnd))
  8607. else
  8608. Result := -1;
  8609. end;
  8610. end;
  8611. {$ENDIF}
  8612. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  8613. { Returns -1 on error only if event OnError is assigned, otherwise an }
  8614. { ESocketException may be raised. Returns the number of bytes written on }
  8615. { success. }
  8616. function TCustomLineWSocket.SendLine(const Str : RawByteString) : Integer;
  8617. begin
  8618. Result := PutStringInSendBuffer(Str);
  8619. if Result > 0 then begin
  8620. if SendStr(LineEnd) > -1 then
  8621. Inc(Result, Length(LineEnd))
  8622. else
  8623. Result := -1;
  8624. end;
  8625. end;
  8626. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  8627. function TCustomLineWSocket.GetRcvdCount : LongInt;
  8628. begin
  8629. if not FLineMode then
  8630. Result := inherited GetRcvdCount
  8631. else
  8632. Result := FLineLength;
  8633. end;
  8634. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  8635. function TCustomLineWSocket.DoRecv(
  8636. var Buffer : TWSocketData;
  8637. BufferSize : Integer;
  8638. Flags : Integer) : Integer;
  8639. {$IFDEF CLR}
  8640. var
  8641. I : Integer;
  8642. {$ENDIF}
  8643. begin
  8644. if FLineMode and (FLineLength > 0) then begin
  8645. { We are in line mode and a line is received }
  8646. if FLineLength <= BufferSize then begin
  8647. { User buffer is greater than received data, copy all and clear }
  8648. {$IFDEF CLR}
  8649. System.Buffer.BlockCopy(FRcvdPtr, 0, Buffer, 0, FLineLength);
  8650. //for I := 0 to FLineLength - 1 do
  8651. // Buffer[I] := FRcvdPtr[I];
  8652. {$ENDIF}
  8653. {$IFDEF WIN32}
  8654. Move(FRcvdPtr^, Buffer^, FLineLength);
  8655. {$ENDIF}
  8656. Result := FLineLength;
  8657. FLineLength := 0;
  8658. Exit;
  8659. end;
  8660. { User buffer is smaller, copy as much as possible }
  8661. {$IFDEF CLR}
  8662. for I := 0 to BufferSize - 1 do
  8663. Buffer[I] := FRcvdPtr[I];
  8664. { Move the end of line to beginning of buffer to be read the next time }
  8665. for I := 0 to FLineLength - BufferSize - 1 do
  8666. FRcvdPtr[I] := FRcvdPtr[BufferSize + I];
  8667. {$ENDIF}
  8668. {$IFDEF WIN32}
  8669. Move(FRcvdPtr^, Buffer^, BufferSize);
  8670. { Move the end of line to beginning of buffer to be read the next time }
  8671. Move(PAnsiChar(FRcvdPtr)[BufferSize], FRcvdPtr^, FLineLength - BufferSize);
  8672. {$ENDIF}
  8673. Result := BufferSize;
  8674. FLineLength := FLineLength - BufferSize;
  8675. Exit;
  8676. end;
  8677. if FLineMode or (FRcvdCnt <= 0) then begin
  8678. { There is nothing in our internal buffer }
  8679. Result := inherited DoRecv(Buffer, BufferSize, Flags);
  8680. Exit;
  8681. end;
  8682. { We already have received data into our internal buffer }
  8683. if FRcvdCnt <= BufferSize then begin
  8684. { User buffer is greater than received data, copy all and clear }
  8685. {$IFDEF CLR}
  8686. for I := 0 to FRcvdCnt - 1 do
  8687. Buffer[I] := FRcvdPtr[I];
  8688. {$ENDIF}
  8689. {$IFDEF WIN32}
  8690. Move(FRcvdPtr^, Buffer^, FRcvdCnt);
  8691. {$ENDIF}
  8692. Result := FRcvdCnt;
  8693. FRcvdCnt := 0;
  8694. Exit;
  8695. end;
  8696. {$IFDEF CLR}
  8697. { User buffer is smaller, copy as much as possible }
  8698. for I := 0 to BufferSize - 1 do
  8699. Buffer[I] := FRcvdPtr[I];
  8700. { Then move remaining data to front of buffer 16/10/99 }
  8701. for I := 0 to FRcvdCnt - BufferSize do
  8702. FRcvdPtr[I] := FRcvdPtr[BufferSize + I];
  8703. {$ENDIF}
  8704. {$IFDEF WIN32}
  8705. { User buffer is smaller, copy as much as possible }
  8706. Move(FRcvdPtr^, Buffer^, BufferSize);
  8707. { Then move remaining data to front og buffer 16/10/99 }
  8708. Move(PAnsiChar(FRcvdPtr)[BufferSize], FRcvdPtr^, FRcvdCnt - BufferSize + 1);
  8709. {$ENDIF}
  8710. Result := BufferSize;
  8711. FRcvdCnt := FRcvdCnt - BufferSize;
  8712. end;
  8713. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  8714. { Edit received data. Handle TAB and BACKSPACE characters. }
  8715. { A data packet has been received into FRcvPtr buffer, starting from }
  8716. { FRcvdCnt offset. Packet size if passed as the Len argument. }
  8717. procedure TCustomLineWSocket.EditLine(var Len : Integer);
  8718. {$IFDEF CLR}
  8719. var
  8720. Buf : TBytes;
  8721. BufSize : LongInt;
  8722. I : LongInt;
  8723. J : LongInt;
  8724. K : Integer;
  8725. Edited : Boolean;
  8726. NewCnt : LongInt;
  8727. NewSize : LongInt;
  8728. const
  8729. BackString : String = #8 + ' ' + #8;
  8730. begin
  8731. BufSize := 0;
  8732. try
  8733. Edited := FALSE;
  8734. I := FRcvdCnt;
  8735. J := FRcvdCnt;
  8736. NewCnt := FRcvdCnt;
  8737. { Loop to process all received char }
  8738. while I < (FRcvdCnt + Len) do begin
  8739. if FRcvdPtr[I] = 8 then begin { BACKSPACE character }
  8740. if FLineEcho and (J > 0) then
  8741. SendStr(BackString);
  8742. if not Edited then begin
  8743. { Not edited yet, so we allocate a buffer to store }
  8744. { edited data and we remember we edited data. }
  8745. Edited := TRUE;
  8746. { Compute buffer size as a multiple of 256 bytes }
  8747. BufSize := ((FRcvdCnt + Len + 256) shr 8) shl 8;
  8748. SetLength(Buf, BufSize);
  8749. { Copy data already processed }
  8750. for K := 0 to I - 1 do
  8751. Buf[K] := FRcvdPtr[K];
  8752. end;
  8753. if J > 0 then begin
  8754. Dec(J);
  8755. if J < NewCnt then
  8756. NewCnt := J;
  8757. end;
  8758. Inc(I);
  8759. end
  8760. else if FRcvdPtr[I] = 9 then begin { TAB character }
  8761. if not Edited then begin
  8762. { Not edited yet, so we allocate a buffer to store }
  8763. { edited data and we remember we edited data. }
  8764. Edited := TRUE;
  8765. { Compute buffer size as a multiple of 256 bytes }
  8766. BufSize := ((FRcvdCnt + Len + 256) shr 8) shl 8;
  8767. SetLength(Buf, BufSize);
  8768. { Copy data already processed }
  8769. for K := 0 to I - 1 do
  8770. Buf[K] := FRcvdPtr[K];
  8771. end;
  8772. repeat
  8773. if FLineEcho then
  8774. SendStr(' ');
  8775. Buf[J] := Ord(' ');
  8776. Inc(J);
  8777. until (J and 7) = 0;
  8778. Inc(I);
  8779. end
  8780. else begin
  8781. if FLineEcho then
  8782. Send(FRcvdPtr[I]);
  8783. if Edited then begin
  8784. if J >= BufSize then begin
  8785. { Need to allocate more buffer space }
  8786. NewSize := BufSize + 256;
  8787. SetLength(Buf, NewSize);
  8788. BufSize := NewSize;
  8789. end;
  8790. Buf[J] := FRcvdPtr[I];
  8791. end;
  8792. Inc(I);
  8793. Inc(J);
  8794. end;
  8795. end;
  8796. if Edited then begin
  8797. if J >= FRcvBufSize then begin
  8798. { Current buffer is too small, allocate larger }
  8799. NewSize := J + 1;
  8800. SetLength(FRcvdPtr, NewSize);
  8801. FRcvBufSize := NewSize;
  8802. end;
  8803. { Move edited data back to original buffer }
  8804. for K := 0 to J - 1 do
  8805. FRcvdPtr[K] := Buf[K];
  8806. FRcvdPtr[J] := 0;
  8807. FRcvdCnt := NewCnt;
  8808. Len := J - FRcvdCnt;
  8809. end;
  8810. finally
  8811. if BufSize > 0 then
  8812. SetLength(Buf, BufSize);
  8813. end;
  8814. end;
  8815. {$ENDIF}
  8816. {$IFDEF WIN32}
  8817. var
  8818. Buf : PAnsiChar;
  8819. BufSize : LongInt;
  8820. I : LongInt;
  8821. J : LongInt;
  8822. Edited : Boolean;
  8823. NewCnt : LongInt;
  8824. NewSize : LongInt;
  8825. const
  8826. BackString : String = #8 + ' ' + #8;
  8827. begin
  8828. BufSize := 0;
  8829. try
  8830. Edited := FALSE;
  8831. I := FRcvdCnt;
  8832. J := FRcvdCnt;
  8833. NewCnt := FRcvdCnt;
  8834. { Loop to process all received char }
  8835. while I < (FRcvdCnt + Len) do begin
  8836. if PAnsiChar(FRcvdPtr)[I] = #8 then begin { BACKSPACE character }
  8837. if FLineEcho and (J > 0) then
  8838. SendStr(BackString);
  8839. if not Edited then begin
  8840. { Not edited yet, so we allocate a buffer to store }
  8841. { edited data and we remember we edited data. }
  8842. Edited := TRUE;
  8843. { Computer buffer size as a multiple of 256 bytes }
  8844. BufSize := ((FRcvdCnt + Len + 256) shr 8) shl 8;
  8845. GetMem(Buf, BufSize);
  8846. { Copy data already processed }
  8847. Move(FRcvdPtr^, Buf^, I);
  8848. end;
  8849. if J > 0 then begin
  8850. Dec(J);
  8851. if J < NewCnt then
  8852. NewCnt := J;
  8853. end;
  8854. Inc(I);
  8855. end
  8856. else if PAnsiChar(FRcvdPtr)[I] = #9 then begin { TAB character }
  8857. if not Edited then begin
  8858. { Not edited yet, so we allocate a buffer to store }
  8859. { edited data and we remember we edited data. }
  8860. Edited := TRUE;
  8861. { Computer buffer size as a multiple of 256 bytes }
  8862. BufSize := ((FRcvdCnt + Len + 256) shr 8) shl 8;
  8863. GetMem(Buf, BufSize);
  8864. { Copy data already processed }
  8865. Move(FRcvdPtr^, Buf^, I);
  8866. end;
  8867. repeat
  8868. if FLineEcho then
  8869. SendStr(' ');
  8870. Buf[J] := ' ';
  8871. Inc(J);
  8872. until (J and 7) = 0;
  8873. Inc(I);
  8874. end
  8875. else begin
  8876. if FLineEcho then
  8877. Send(@PAnsiChar(FRcvdPtr)[I], 1);
  8878. if Edited then begin
  8879. if J >= BufSize then begin
  8880. { Need to allocate more buffer space }
  8881. NewSize := BufSize + 256;
  8882. {$IFDEF DELPHI1}
  8883. Buf := ReallocMem(Buf, BufSize, NewSize);
  8884. {$ELSE}
  8885. ReallocMem(Buf, NewSize);
  8886. {$ENDIF}
  8887. BufSize := NewSize;
  8888. end;
  8889. Buf[J] := PAnsiChar(FRcvdPtr)[I];
  8890. end;
  8891. Inc(I);
  8892. Inc(J);
  8893. end;
  8894. end;
  8895. if Edited then begin
  8896. if J >= FRcvBufSize then begin
  8897. { Current buffer is too small, allocate larger }
  8898. NewSize := J + 1;
  8899. {$IFDEF DELPHI1}
  8900. FRcvdPtr := ReallocMem(FRcvdPtr, FRcvBufSize, NewSize);
  8901. {$ELSE}
  8902. ReallocMem(FRcvdPtr, NewSize);
  8903. {$ENDIF}
  8904. FRcvBufSize := NewSize;
  8905. end;
  8906. { Move edited data back to original buffer }
  8907. Move(Buf^, FRcvdPtr^, J);
  8908. PAnsiChar(FRcvdPtr)[J] := #0;
  8909. FRcvdCnt := NewCnt;
  8910. Len := J - FRcvdCnt;
  8911. end;
  8912. finally
  8913. if BufSize > 0 then
  8914. FreeMem(Buf, BufSize);
  8915. end;
  8916. end;
  8917. {$ENDIF}
  8918. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  8919. procedure TCustomLineWSocket.TriggerLineLimitExceeded(
  8920. Cnt : Integer;
  8921. var ClearData : Boolean);
  8922. begin
  8923. if Assigned(FOnLineLimitExceeded) then
  8924. FOnLineLimitExceeded(Self, Cnt, ClearData);
  8925. end;
  8926. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  8927. function TCustomLineWSocket.TriggerDataAvailable(ErrCode : Word) : Boolean;
  8928. {$IFDEF CLR}
  8929. var
  8930. Cnt : Integer;
  8931. Len : Integer;
  8932. NewSize : LongInt;
  8933. SearchFrom : LongInt;
  8934. I, K : LongInt;
  8935. Found : Boolean;
  8936. begin
  8937. { if (not FLineMode) or (Length(FLineEnd) = 0) then begin }
  8938. if (not FLineMode) or (Length(FLineEnd) = 0) or (FSocksState <> socksData)
  8939. {**ALON** added check so, if data is received while still handshaking }
  8940. { with the socks server, we ask the TCustomSocksWSocket to handle it }
  8941. then begin
  8942. { We are not in line mode }
  8943. Result := inherited TriggerDataAvailable(ErrCode);
  8944. Exit;
  8945. end;
  8946. { We are in line mode. We receive data ourself }
  8947. Result := TRUE;
  8948. Cnt := inherited GetRcvdCount;
  8949. { if Cnt <= 0 then }
  8950. { Exit; }
  8951. if Cnt < 0 then
  8952. Exit;
  8953. if Cnt = 0 then
  8954. Cnt := 255;
  8955. if (FRcvdCnt + Cnt + 1) > FRcvBufSize then begin
  8956. { Current buffer is too small, allocate larger }
  8957. NewSize := FRcvdCnt + Cnt + 1;
  8958. SetLength(FRcvdPtr, NewSize);
  8959. FRcvBufSize := NewSize;
  8960. end;
  8961. if Length(FLocalBuf) < Cnt then
  8962. SetLength(FLocalBuf, ((Cnt + 256) shr 8) shl 8);
  8963. Len := Receive(FLocalBuf, Cnt);
  8964. if Len <= 0 then
  8965. Exit;
  8966. for I := 0 to Len - 1 do
  8967. FRcvdPtr[FRcvdCnt + I] := FLocalBuf[I];
  8968. FRcvdPtr[FRcvdCnt + Len] := 0;
  8969. if FLineEdit then
  8970. EditLine(Len)
  8971. else if FLineEcho then
  8972. Send(FLocalBuf, Len);
  8973. SearchFrom := FRcvdCnt - Length(FLineEnd);
  8974. if SearchFrom < 0 then
  8975. SearchFrom := 0;
  8976. FRcvdCnt := FRcvdCnt + Len;
  8977. while FLineMode do begin
  8978. Found := FALSE;
  8979. I := SearchFrom;
  8980. while I < (FRcvdCnt - Length(FLineEnd) + 1) do begin
  8981. if FRcvdPtr[I] = Ord(FLineEnd[1]) then begin
  8982. Found := TRUE;
  8983. for K := 2 to Length(FLineEnd) do begin
  8984. Found := (FRcvdPtr[I + K - 1] = Ord(FLineEnd[K]));
  8985. if not Found then
  8986. break;
  8987. end;
  8988. if Found then
  8989. break; { Found the end of line marker }
  8990. end;
  8991. Inc(I);
  8992. end;
  8993. if not Found then begin
  8994. if ((FLineLimit > 0) and (FRcvdCnt > FLineLimit)) then begin
  8995. FLineClearData := TRUE;
  8996. TriggerLineLimitExceeded(FRcvdCnt, FLineClearData);
  8997. if FLineClearData then begin
  8998. FLineLength := 0;
  8999. FRcvdCnt := 0;
  9000. FLineClearData := FALSE;
  9001. end;
  9002. end;
  9003. break;
  9004. end;
  9005. FLineLength := I + Length(FLineEnd);
  9006. FLineReceivedFlag := TRUE;
  9007. FLineFound := TRUE;
  9008. { We received a complete line. We need to signal it to application }
  9009. { The application may not have a large buffer so we may need }
  9010. { several events to read the entire line. In the meanwhile, the }
  9011. { application may turn line mode off. }
  9012. while FLineMode and (FLineLength > 0) do begin
  9013. if not inherited TriggerDataAvailable(0) then
  9014. { There is no handler installed }
  9015. FLineLength := 0;
  9016. end;
  9017. { Move remaining data in front of buffer }
  9018. if FLineLength > 0 then begin
  9019. { Line mode was turned off in the middle of a line read. }
  9020. { We preserve unread line and other received data. }
  9021. for K := 0 to FRcvdCnt - I - 1 do
  9022. FRcvdPtr[FLineLength + K] := FRcvdPtr[I + K];
  9023. FRcvdCnt := FRcvdCnt - I + FLineLength;
  9024. end
  9025. else begin
  9026. for K := 0 to FRcvdCnt - I - Length(FLineEnd) - 1 do
  9027. FRcvdPtr[K] := FRcvdPtr[I + Length(FLineEnd) + K];
  9028. FRcvdCnt := FRcvdCnt - I - Length(FLineEnd);
  9029. end;
  9030. if FRcvdCnt >= 0 then
  9031. FRcvdPtr[FRcvdCnt] := 0;
  9032. SearchFrom := 0;
  9033. { It is possible the user has turned line mode to off. If data is }
  9034. { still available in the receive buffer, we will deliver it. }
  9035. while (not FLineMode) and (FRcvdCnt > 0) do { 26/01/04 }
  9036. inherited TriggerDataAvailable(0); { 26/01/04 }
  9037. end;
  9038. end;
  9039. {$ENDIF}
  9040. {$IFDEF WIN32}
  9041. var
  9042. Cnt : Integer;
  9043. Len : Integer;
  9044. NewSize : LongInt;
  9045. SearchFrom : LongInt;
  9046. I : LongInt;
  9047. Found : Boolean;
  9048. begin
  9049. { if (not FLineMode) or (Length(FLineEnd) = 0) then begin }
  9050. if (not FLineMode) or (Length(FLineEnd) = 0) or (FSocksState <> socksData)
  9051. {**ALON** added check so, if data is received while still handshaking }
  9052. { with the socks server, we ask the TCustomSocksWSocket to handle it }
  9053. then begin
  9054. { We are not in line mode }
  9055. Result := inherited TriggerDataAvailable(ErrCode);
  9056. Exit;
  9057. end;
  9058. { We are in line mode. We receive data ourself }
  9059. Result := TRUE;
  9060. Cnt := inherited GetRcvdCount;
  9061. { if Cnt <= 0 then }
  9062. { Exit; }
  9063. if Cnt < 0 then
  9064. Exit;
  9065. if Cnt = 0 then
  9066. Cnt := 255;
  9067. if (FRcvdCnt + Cnt + 1) > FRcvBufSize then begin
  9068. { Current buffer is too small, allocate larger }
  9069. NewSize := FRcvdCnt + Cnt + 1;
  9070. {$IFDEF DELPHI1}
  9071. FRcvdPtr := ReallocMem(FRcvdPtr, FRcvBufSize, NewSize);
  9072. {$ELSE}
  9073. ReallocMem(FRcvdPtr, NewSize);
  9074. {$ENDIF}
  9075. FRcvBufSize := NewSize;
  9076. end;
  9077. Len := Receive(IncPtr(FRcvdPtr, FRcvdCnt), Cnt);
  9078. {$IFDEF OLD_20040117}
  9079. if Len <= 0 then
  9080. Exit;
  9081. FRcvdPtr[FRcvdCnt + Len] := #0;
  9082. {$ELSE}
  9083. if Len <= 0 then begin
  9084. if FRcvdCnt <= 0 then
  9085. Exit;
  9086. Len := 0;
  9087. end;
  9088. {$ENDIF}
  9089. if Len > 0 then begin
  9090. if FLineEdit then
  9091. EditLine(Len)
  9092. else if FLineEcho then
  9093. Send(IncPtr(FRcvdPtr, FRcvdCnt), Len);
  9094. end;
  9095. SearchFrom := FRcvdCnt - Length(FLineEnd);
  9096. if SearchFrom < 0 then
  9097. SearchFrom := 0;
  9098. FRcvdCnt := FRcvdCnt + Len;
  9099. while FLineMode do begin
  9100. Found := FALSE;
  9101. I := SearchFrom;
  9102. while I < (FRcvdCnt - Length(FLineEnd) + 1) do begin
  9103. if PAnsiChar(FRcvdPtr)[I] = AnsiChar(FLineEnd[1]) then begin
  9104. Found := _StrLComp(PAnsiChar(@(PAnsiChar(FRcvdPtr)[I])),
  9105. PAnsiChar(FLineEnd), Length(FLineEnd)) = 0;
  9106. if Found then
  9107. break; { Found the end of line marker }
  9108. end;
  9109. Inc(I);
  9110. end;
  9111. if not Found then begin
  9112. if ((FLineLimit > 0) and (FRcvdCnt > FLineLimit)) then begin
  9113. FLineClearData := TRUE;
  9114. TriggerLineLimitExceeded(FRcvdCnt, FLineClearData);
  9115. if FLineClearData then begin
  9116. FLineLength := 0;
  9117. FRcvdCnt := 0;
  9118. FLineClearData := FALSE;
  9119. end;
  9120. end;
  9121. break;
  9122. end;
  9123. FLineLength := I + Length(FLineEnd);
  9124. FLineReceivedFlag := TRUE;
  9125. FLineFound := TRUE;
  9126. { We received a complete line. We need to signal it to application }
  9127. { The application may not have a large buffer so we may need }
  9128. { several events to read the entire line. In the meanwhile, the }
  9129. { application may turn line mode off. }
  9130. while FLineMode and (FLineLength > 0) do begin
  9131. if not inherited TriggerDataAvailable(0) then
  9132. { There is no handler installed }
  9133. FLineLength := 0;
  9134. end;
  9135. { Move remaining data in front of buffer }
  9136. if FLineLength > 0 then begin
  9137. { Line mode was turned off in the middle of a line read. }
  9138. { We preserve unread line and other received data. }
  9139. Move(PAnsiChar(FRcvdPtr)[I], PAnsiChar(FRcvdPtr)[FLineLength],
  9140. FRcvdCnt - I);
  9141. FRcvdCnt := FRcvdCnt - I + FLineLength;
  9142. end
  9143. else begin
  9144. Move(PAnsiChar(FRcvdPtr)[I + Length(FLineEnd)], PAnsiChar(FRcvdPtr)[0],
  9145. FRcvdCnt - I - Length(FLineEnd));
  9146. FRcvdCnt := FRcvdCnt - I - Length(FLineEnd);
  9147. end;
  9148. if FRcvdCnt >= 0 then
  9149. PAnsiChar(FRcvdPtr)[FRcvdCnt] := #0;
  9150. SearchFrom := 0;
  9151. { It is possible the user has turned line mode to off. If data is }
  9152. { still available in the receive buffer, we will deliver it. }
  9153. while (not FLineMode) and (FRcvdCnt > 0) do { 26/01/04 }
  9154. inherited TriggerDataAvailable(0); { 26/01/04 }
  9155. end;
  9156. end;
  9157. {$ENDIF}
  9158. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  9159. procedure TCustomLineWSocket.TriggerSessionClosed(Error : Word);
  9160. begin
  9161. FLineReceivedFlag := TRUE;
  9162. if FRcvdPtr <> nil then begin
  9163. if FLineMode and (FRcvdCnt > 0) and (not FLineClearData) then begin
  9164. FLineLength := FRcvdCnt;
  9165. while FLineMode and (FLineLength > 0) do
  9166. inherited TriggerDataAvailable(0);
  9167. end;
  9168. {$IFDEF CLR}
  9169. SetLength(FRcvdPtr, FRcvBufSize);
  9170. {$ENDIF}
  9171. {$IFDEF WIN32}
  9172. FreeMem(FRcvdPtr, FRcvBufSize);
  9173. FRcvdPtr := nil;
  9174. {$ENDIF}
  9175. FRcvBufSize := 0;
  9176. FRcvdCnt := 0;
  9177. end;
  9178. inherited TriggerSessionClosed(Error);
  9179. end;
  9180. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  9181. X X X X X X X X X
  9182. X X X X X X X X X
  9183. X X X X X X X
  9184. X X X X X X X
  9185. X X X X X
  9186. X X X X X X X X
  9187. X X X X X X X X X
  9188. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  9189. procedure TCustomSyncWSocket.InternalDataAvailable(
  9190. Sender : TObject;
  9191. Error : Word);
  9192. var
  9193. Len : Integer;
  9194. begin
  9195. {$IFDEF CLR}
  9196. SetLength(FLinePointer, FLineLength);
  9197. Len := Receive(FLinePointer, FLineLength);
  9198. if Len <= 0 then
  9199. Len := 0;
  9200. SetLength(FLinePointer, Len);
  9201. {$ENDIF}
  9202. {$IFDEF WIN32}
  9203. SetLength(FLinePointer^, FLineLength);
  9204. Len := Receive(@FLinePointer^[1], FLineLength);
  9205. if Len <= 0 then
  9206. FLinePointer^ := ''
  9207. else
  9208. SetLength(FLinePointer^, Len);
  9209. {$ENDIF}
  9210. end;
  9211. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  9212. function TCustomSyncWSocket.WaitUntilReady(var DoneFlag : Boolean) : Integer;
  9213. begin
  9214. Result := 0; { Suppose success }
  9215. FTimeStop := Integer(_GetTickCount) + FTimeout;
  9216. while TRUE do begin
  9217. if DoneFlag then begin
  9218. Result := 0;
  9219. break;
  9220. end;
  9221. if ((FTimeout > 0) and (Integer(_GetTickCount) > FTimeStop)) or
  9222. {$IFDEF WIN32}
  9223. {$IFNDEF NOFORMS}
  9224. Application.Terminated or
  9225. {$ENDIF}
  9226. {$ENDIF}
  9227. FTerminated then begin
  9228. { Application is terminated or timeout occured }
  9229. Result := WSA_WSOCKET_TIMEOUT;
  9230. break;
  9231. end;
  9232. MessagePump;
  9233. {$IFDEF COMPILER2_UP}
  9234. { Do not use 100% CPU, but slow down transfert on high speed LAN }
  9235. _Sleep(0);
  9236. {$ENDIF}
  9237. end;
  9238. end;
  9239. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  9240. { DEPRECATED: DO NOT USE Synchronize procedure for a new application. }
  9241. { Instead, use pure event-driven design. }
  9242. function TCustomSyncWSocket.Synchronize(
  9243. Proc : TWSocketSyncNextProc;
  9244. var DoneFlag : Boolean) : Integer;
  9245. begin
  9246. DoneFlag := FALSE;
  9247. if Assigned(Proc) then
  9248. Proc;
  9249. Result := WaitUntilReady(DoneFlag);
  9250. end;
  9251. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  9252. { DEPRECATED: DO NOT USE ReadLine procedure for a new application. }
  9253. { Instead, use pure event-driven design using OnDataAvailable event. }
  9254. procedure TCustomSyncWSocket.ReadLine(
  9255. Timeout : Integer; { seconds if positive, milli-seconds if negative }
  9256. var Buffer : AnsiString);
  9257. var
  9258. OldDataAvailable : TDataAvailable;
  9259. OldLineMode : Boolean;
  9260. Status : Integer;
  9261. {$IFDEF CLR}
  9262. I : Integer;
  9263. {$ENDIF}
  9264. begin
  9265. Buffer := '';
  9266. if FState <> wsConnected then begin
  9267. RaiseException('ReadLine failed: not connected');
  9268. Exit;
  9269. end;
  9270. { Positive timeout means seconds. Negative means milli-seconds }
  9271. { Null means 60 seconds. }
  9272. if TimeOut = 0 then
  9273. FTimeOut := 60000
  9274. else if TimeOut > 0 then
  9275. FTimeOut := Timeout * 1000
  9276. else
  9277. FTimeOut := -Timeout;
  9278. FLineReceivedFlag := FALSE;
  9279. {$IFDEF WIN32}
  9280. FLinePointer := @Buffer;
  9281. {$ENDIF}
  9282. { Save existing OnDataAvailable handler and install our own }
  9283. OldDataAvailable := FOnDataAvailable;
  9284. FOnDataAvailable := InternalDataAvailable;
  9285. { Save existing line mode and turn it on }
  9286. OldLineMode := FLineMode;
  9287. FLineMode := TRUE;
  9288. try
  9289. Status := Synchronize(nil, FLineReceivedFlag);
  9290. if Status = WSA_WSOCKET_TIMEOUT then begin
  9291. { Sender didn't send line end within allowed time. Get all }
  9292. { data available so far. }
  9293. if FRcvdCnt > 0 then begin
  9294. SetLength(Buffer, FRcvdCnt);
  9295. {$IFDEF CLR}
  9296. for I := 0 to FRcvdCnt - 1 do
  9297. Buffer[I + 1] := Char(FRcvdPtr[I]);
  9298. {$ENDIF}
  9299. {$IFDEF WIN32}
  9300. Move(FRcvdPtr^, Buffer[1], FRcvdCnt);
  9301. {$ENDIF}
  9302. FRcvdCnt := 0;
  9303. {$IFDEF CLR}
  9304. end
  9305. else begin
  9306. SetLength(Buffer, Length(FLinePointer));
  9307. for I := 0 to Length(FLinePointer) - 1 do
  9308. Buffer[I + 1] := Char(FLinePointer[I]);
  9309. {$ENDIF}
  9310. end;
  9311. end;
  9312. { Should I raise an exception to tell the application that }
  9313. { some error occured ? }
  9314. finally
  9315. FOnDataAvailable := OldDataAvailable;
  9316. FLineMode := OldLineMode;
  9317. end;
  9318. end;
  9319. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  9320. {$IFDEF BUILTIN_TIMEOUT}
  9321. { TCustomTimeoutWSocket }
  9322. const
  9323. MIN_TIMEOUT_SAMPLING_INTERVAL = 1000;
  9324. constructor TCustomTimeoutWSocket.Create(AOwner: TComponent);
  9325. begin
  9326. inherited;
  9327. FTimeoutKeepThreadAlive := TRUE;
  9328. FTimeoutSampling := 5000;
  9329. end;
  9330. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  9331. procedure TCustomTimeoutWSocket.TimeoutHandleTimer(
  9332. Sender: TObject);
  9333. begin
  9334. if (FTimeoutConnect > 0) and (FState <> wsConnected) then begin
  9335. if IcsCalcTickDiff(FTimeoutConnectStartTick,
  9336. _GetTickCount) > FTimeoutConnect then begin
  9337. TimeoutStopSampling;
  9338. TriggerTimeout(torConnect);
  9339. end;
  9340. end
  9341. else if (FTimeoutIdle > 0) then begin
  9342. if IcsCalcTickDiff(FCounter.GetLastAliveTick,
  9343. _GetTickCount) > FTimeoutIdle then begin
  9344. TimeoutStopSampling;
  9345. TriggerTimeout(torIdle);
  9346. end;
  9347. end
  9348. else
  9349. TimeoutStopSampling;
  9350. end;
  9351. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  9352. procedure TCustomTimeoutWSocket.Connect;
  9353. begin
  9354. if FTimeoutConnect > 0 then begin
  9355. TimeoutStartSampling;
  9356. FTimeoutConnectStartTick := _GetTickCount;
  9357. end
  9358. else if FTimeoutIdle > 0 then
  9359. TimeoutStartSampling;
  9360. inherited Connect;
  9361. end;
  9362. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  9363. procedure TCustomTimeoutWSocket.SetTimeoutKeepThreadAlive(const Value: Boolean);
  9364. begin
  9365. FTimeoutKeepThreadAlive := Value;
  9366. if FTimeoutTimer <> nil then
  9367. FTimeoutTimer.KeepThreadAlive := FTimeoutKeepThreadAlive;
  9368. end;
  9369. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  9370. procedure TCustomTimeoutWSocket.SetTimeoutSampling(const Value: LongWord);
  9371. begin
  9372. if (Value > 0) and (Value < MIN_TIMEOUT_SAMPLING_INTERVAL) then
  9373. FTimeoutSampling := MIN_TIMEOUT_SAMPLING_INTERVAL
  9374. else
  9375. FTimeoutSampling := Value;
  9376. end;
  9377. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  9378. procedure TCustomTimeoutWSocket.TimeoutStartSampling;
  9379. begin
  9380. if not Assigned(FTimeoutTimer) then begin
  9381. FTimeoutTimer := TIcsThreadTimer.Create(Self);
  9382. FTimeoutTimer.KeepThreadAlive := FTimeoutKeepThreadAlive;
  9383. FTimeoutTimer.OnTimer := TimeoutHandleTimer;
  9384. end;
  9385. if not Assigned(FCounter) then
  9386. CreateCounter
  9387. else
  9388. FCounter.LastSendTick := _GetTickCount; // Init
  9389. if FTimeoutTimer.Interval <> FTimeoutSampling then
  9390. FTimeoutTimer.Interval := FTimeoutSampling;
  9391. if not FTimeoutTimer.Enabled then
  9392. FTimeoutTimer.Enabled := TRUE;
  9393. end;
  9394. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  9395. procedure TCustomTimeoutWSocket.TimeoutStopSampling;
  9396. begin
  9397. if Assigned(FTimeoutTimer) then
  9398. FTimeoutTimer.Enabled := FALSE;
  9399. end;
  9400. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  9401. procedure TCustomTimeoutWSocket.DupConnected;
  9402. begin
  9403. if FTimeoutIdle > 0 then
  9404. TimeoutStartSampling
  9405. else
  9406. TimeoutStopSampling;
  9407. inherited DupConnected;
  9408. end;
  9409. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  9410. procedure TCustomTimeoutWSocket.ThreadAttach;
  9411. begin
  9412. inherited ThreadAttach;
  9413. if Assigned(FTimeoutTimer) then
  9414. FTimeoutTimer.Enabled := FTimeoutOldTimerEnabled;
  9415. end;
  9416. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  9417. procedure TCustomTimeoutWSocket.ThreadDetach;
  9418. begin
  9419. if Assigned(FTimeoutTimer) and
  9420. (_GetCurrentThreadID = DWORD(FThreadID)) then begin
  9421. FTimeoutOldTimerEnabled := FTimeoutTimer.Enabled;
  9422. if FTimeoutOldTimerEnabled then
  9423. FTimeoutTimer.Enabled := FALSE;
  9424. end;
  9425. inherited ThreadDetach;
  9426. end;
  9427. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  9428. procedure TCustomTimeoutWSocket.TriggerSessionClosed(Error: Word);
  9429. begin
  9430. TimeoutStopSampling;
  9431. inherited TriggerSessionClosed(Error);
  9432. end;
  9433. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  9434. procedure TCustomTimeoutWSocket.TriggerSessionConnectedSpecial(
  9435. Error: Word);
  9436. begin
  9437. if (Error = 0) and (FTimeoutIdle > 0) then
  9438. TimeoutStartSampling
  9439. else
  9440. TimeoutStopSampling;
  9441. inherited TriggerSessionConnectedSpecial(Error);
  9442. end;
  9443. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  9444. procedure TCustomTimeoutWSocket.TriggerTimeout(Reason: TTimeoutReason);
  9445. begin
  9446. if Assigned(FOnTimeout) then
  9447. FOnTimeout(Self, Reason);
  9448. end;
  9449. {$ENDIF}
  9450. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  9451. {$IFDEF BUILTIN_THROTTLE}
  9452. { TCustomThrottledWSocket }
  9453. constructor TCustomThrottledWSocket.Create(AOwner: TComponent);
  9454. begin
  9455. inherited Create(AOwner);
  9456. FBandwidthKeepThreadAlive := TRUE;
  9457. FBandwidthSampling := 1000; { Msec sampling interval }
  9458. end;
  9459. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  9460. procedure TCustomThrottledWSocket.ThreadAttach;
  9461. begin
  9462. inherited ThreadAttach;
  9463. if Assigned(FBandwidthTimer) then
  9464. FBandwidthTimer.Enabled := FBandwidthOldTimerEnabled;
  9465. end;
  9466. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  9467. procedure TCustomThrottledWSocket.ThreadDetach;
  9468. begin
  9469. if Assigned(FBandwidthTimer) and
  9470. (_GetCurrentThreadID = DWORD(FThreadID)) then begin
  9471. FBandwidthOldTimerEnabled := FBandwidthTimer.Enabled;
  9472. if FBandwidthOldTimerEnabled then
  9473. FBandwidthTimer.Enabled := FALSE;
  9474. end;
  9475. inherited ThreadDetach;
  9476. end;
  9477. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  9478. procedure TCustomThrottledWSocket.DupConnected;
  9479. begin
  9480. inherited DupConnected;
  9481. SetBandwidthControl;
  9482. end;
  9483. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  9484. procedure TCustomThrottledWSocket.SetBandwidthControl;
  9485. var
  9486. I : Int64;
  9487. begin
  9488. FBandwidthCount := 0;
  9489. if FBandwidthLimit > 0 then
  9490. begin
  9491. if not Assigned(FBandwidthTimer) then begin
  9492. FBandwidthTimer := TIcsThreadTimer.Create(Self);
  9493. FBandwidthTimer.KeepThreadAlive := FBandwidthKeepThreadAlive;
  9494. FBandwidthTimer.OnTimer := BandwidthHandleTimer;
  9495. end;
  9496. FBandwidthTimer.Interval := FBandwidthSampling;
  9497. if not FBandwidthTimer.Enabled then
  9498. FBandwidthTimer.Enabled := TRUE;
  9499. // Number of bytes we allow during a sampling period, max integer max.
  9500. I := Int64(FBandwidthLimit) * FBandwidthSampling div 1000;
  9501. if I < MaxInt then
  9502. FBandwidthMaxCount := I
  9503. else
  9504. FBandwidthMaxCount := MaxInt;
  9505. FBandwidthPaused := FALSE;
  9506. Include(FComponentOptions, wsoNoReceiveLoop);
  9507. FBandwidthEnabled := TRUE;
  9508. {$IFNDEF NO_DEBUG_LOG}
  9509. if CheckLogOptions(loWsockInfo) then
  9510. DebugLog(loWsockInfo,
  9511. _IntToHex(INT_PTR(Self), SizeOf(Pointer) * 2) +
  9512. ' Bandwidth ON ' + _IntToStr(FHSocket));
  9513. {$ENDIF}
  9514. end
  9515. else begin
  9516. if Assigned(FBandwidthTimer) then begin
  9517. if FBandwidthTimer.Enabled then
  9518. FBandwidthTimer.Enabled := FALSE;
  9519. if FBandwidthEnabled then begin
  9520. FBandwidthEnabled := FALSE;
  9521. {$IFNDEF NO_DEBUG_LOG}
  9522. if CheckLogOptions(loWsockInfo) then
  9523. DebugLog(loWsockInfo,
  9524. _IntToHex(INT_PTR(Self), SizeOf(Pointer) * 2) +
  9525. ' Bandwidth OFF ' + _IntToStr(FHSocket));
  9526. {$ENDIF}
  9527. end;
  9528. end;
  9529. end;
  9530. end;
  9531. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  9532. procedure TCustomThrottledWSocket.SetBandwidthKeepThreadAlive(
  9533. const Value: Boolean);
  9534. begin
  9535. FBandwidthKeepThreadAlive := Value;
  9536. if FBandwidthTimer <> nil then
  9537. FBandwidthTimer.KeepThreadAlive := FBandwidthKeepThreadAlive;
  9538. end;
  9539. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  9540. procedure TCustomThrottledWSocket.SetBandwidthSampling(const Value: LongWord);
  9541. begin
  9542. if Value < 500 then
  9543. FBandwidthSampling := 500
  9544. else
  9545. FBandwidthSampling := Value;
  9546. end;
  9547. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  9548. function TCustomThrottledWSocket.RealSend(var Data: TWSocketData;
  9549. Len: Integer): Integer;
  9550. begin
  9551. if not FBandwidthEnabled then
  9552. Result := inherited RealSend(Data, Len)
  9553. else begin
  9554. { Try to adjust amount of data actually passed to winsock }
  9555. if (Len > 0) and (FBandwidthCount < FBandwidthMaxCount) and
  9556. (FBandwidthCount + LongWord(Len) > FBandwidthMaxCount) then
  9557. Len := (FBandwidthMaxCount - FBandwidthCount) + 1;
  9558. Result := inherited RealSend(Data, Len);
  9559. if (Result > 0) then begin
  9560. Inc(FBandwidthCount, Result);
  9561. if (FBandwidthCount > FBandwidthMaxCount) and
  9562. (not FBandwidthPaused) then begin
  9563. FBandwidthPaused := TRUE;
  9564. Pause;
  9565. {$IFNDEF NO_DEBUG_LOG}
  9566. if CheckLogOptions(loWsockInfo) then
  9567. DebugLog(loWsockInfo,
  9568. _IntToHex(INT_PTR(Self), SizeOf(Pointer) * 2) +
  9569. ' Bandwidth Paused on send ' + _IntToStr(FHSocket));
  9570. {$ENDIF}
  9571. end;
  9572. end;
  9573. end;
  9574. end;
  9575. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  9576. function TCustomThrottledWSocket.Receive(Buffer: TWSocketData;
  9577. BufferSize: Integer): Integer;
  9578. begin
  9579. { The Receive throttle does not work if FD_CLOSE message has been received }
  9580. { yet since handler Do_FD_CLOSE removes option wsoNoReceiveLoop. }
  9581. if (not FBandwidthEnabled) or not (wsoNoReceiveLoop in ComponentOptions) then
  9582. Result := inherited Receive(Buffer, BufferSize)
  9583. else begin
  9584. { Try to adjust amount of data to be received from winsock }
  9585. if (BufferSize > 0) and (FBandwidthCount < FBandwidthMaxCount) and
  9586. (FBandwidthCount + LongWord(BufferSize) > FBandwidthMaxCount) then
  9587. BufferSize := (FBandwidthMaxCount - FBandwidthCount) + 1;
  9588. Result := inherited Receive(Buffer, BufferSize);
  9589. if (Result > 0) then begin
  9590. Inc(FBandwidthCount, Result);
  9591. if (FBandwidthCount > FBandwidthMaxCount) and
  9592. (not FBandwidthPaused) then begin
  9593. FBandwidthPaused := TRUE;
  9594. Pause;
  9595. {$IFNDEF NO_DEBUG_LOG}
  9596. if CheckLogOptions(loWsockInfo) then
  9597. DebugLog(loWsockInfo,
  9598. _IntToHex(INT_PTR(Self), SizeOf(Pointer) * 2) +
  9599. ' Bandwidth Paused on receive ' + _IntToStr(FHSocket));
  9600. {$ENDIF}
  9601. end;
  9602. end;
  9603. end;
  9604. end;
  9605. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  9606. procedure TCustomThrottledWSocket.BandwidthHandleTimer(
  9607. Sender: TObject);
  9608. begin
  9609. if FBandwidthPaused then begin
  9610. FBandwidthPaused := FALSE;
  9611. Dec(FBandwidthCount, FBandwidthMaxCount);
  9612. if FBandwidthCount > FBandwidthMaxCount then
  9613. FBandwidthCount := FBandwidthMaxCount;
  9614. if (FHSocket <> INVALID_SOCKET) then begin
  9615. {$IFNDEF NO_DEBUG_LOG}
  9616. if CheckLogOptions(loWsockInfo) then
  9617. DebugLog(loWsockInfo,
  9618. _IntToHex(INT_PTR(Self), SizeOf(Pointer) * 2) +
  9619. ' Bandwidth Resume ' + _IntToStr(FHSocket));
  9620. {$ENDIF}
  9621. Resume;
  9622. end;
  9623. end
  9624. else
  9625. FBandwidthCount := 0;
  9626. end;
  9627. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  9628. procedure TCustomThrottledWSocket.TriggerSessionClosed(Error: Word);
  9629. begin
  9630. if Assigned(FBandwidthTimer) then begin
  9631. FBandwidthTimer.Enabled := FALSE;
  9632. FBandwidthEnabled := FALSE;
  9633. end;
  9634. inherited TriggerSessionClosed(Error);
  9635. end;
  9636. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  9637. procedure TCustomThrottledWSocket.TriggerSessionConnectedSpecial(Error: Word);
  9638. begin
  9639. { Turn on the throttle early, inherited TriggerSessionConnectedSpecial }
  9640. { might already process the first data chunk. }
  9641. if (Error = 0) then
  9642. SetBandwidthControl;
  9643. inherited TriggerSessionConnectedSpecial(Error);
  9644. if (Error <> 0) and Assigned(FBandwidthTimer) then begin
  9645. FBandwidthTimer.Enabled := FALSE;
  9646. FBandwidthEnabled := FALSE;
  9647. end;
  9648. end;
  9649. {$ENDIF}
  9650. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  9651. { You must define USE_SSL so that SSL code is included in the component. }
  9652. { Either in OverbyteIcsDefs.inc or in the project/package options. }
  9653. {$IFDEF USE_SSL}
  9654. var
  9655. //GSslInitialized : Integer = 0;
  9656. SslRefCount : Integer = 0;
  9657. GSslRegisterAllCompleted : Boolean = FALSE;
  9658. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  9659. (* procedure OutputDebugString(const Msg : String); angus
  9660. begin
  9661. {$IFDEF DEBUG_OUTPUT}
  9662. WriteLn(LogFile, Msg {+ ' ThreadID: ' + IntToHex(GetCurrentThreadID, 8)});
  9663. Flush(LogFile);
  9664. {#$ELSE}
  9665. //WinProcs.OutputDebugString(PChar(Msg));
  9666. {$ENDIF}
  9667. end; *)
  9668. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  9669. var TraceCount : Integer = 0;
  9670. (*procedure OutputTrace(const Msg: String);
  9671. begin
  9672. OutputDebugString(Msg);
  9673. if TraceCount = 15 then
  9674. TraceCount := 15;
  9675. end; *)
  9676. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  9677. procedure LoadSsl;
  9678. var
  9679. Tick : Cardinal;
  9680. S : String;
  9681. {$IFDEF LOADSSL_ERROR_FILE} // Optional define in OverbyteIcsSslDefs.inc
  9682. F : TextFile;
  9683. I, J : Integer;
  9684. {$ENDIF}
  9685. begin
  9686. _EnterCriticalSection(SslCritSect);
  9687. try
  9688. if SslRefCount = 0 then begin
  9689. // Load LIBEAY DLL
  9690. // Must be loaded before SSlEAY for the versioncheck to work!
  9691. if not OverbyteIcsLIBEAY.Load then begin
  9692. {$IFDEF LOADSSL_ERROR_FILE}
  9693. AssignFile(F, _ExtractFilePath(ParamStr(0)) + 'FailedIcsLIBEAY.txt');
  9694. Rewrite(F);
  9695. S := OverbyteIcsLIBEAY.WhichFailedToLoad;
  9696. I := 1;
  9697. while I < Length(S) do begin
  9698. J := I;
  9699. while (I <= Length(S)) and (S[I] <> ' ') do
  9700. Inc(I);
  9701. Inc(I);
  9702. WriteLn(F, Copy(S, J, I - J));
  9703. end;
  9704. CloseFile(F);
  9705. {$ENDIF}
  9706. if OverbyteIcsLIBEAY.GLIBEAY_DLL_Handle <> 0 then begin
  9707. _FreeLibrary(OverbyteIcsLIBEAY.GLIBEAY_DLL_Handle);
  9708. OverbyteIcsLIBEAY.GLIBEAY_DLL_Handle := 0
  9709. end;
  9710. raise EIcsLibeayException.Create('Unable to load LIBEAY DLL. Can''t find ' + S);
  9711. end;
  9712. // Load SSlEAY DLL
  9713. if not OverbyteIcsSSLEAY.Load then begin
  9714. {$IFDEF LOADSSL_ERROR_FILE}
  9715. AssignFile(F, _ExtractFilePath(ParamStr(0)) + 'FailedIcsSSLEAY.txt');
  9716. Rewrite(F);
  9717. S := OverbyteIcsSSLEAY.WhichFailedToLoad;
  9718. I := 1;
  9719. while I < Length(S) do begin
  9720. J := I;
  9721. while (I <= Length(S)) and (S[I] <> ' ') do
  9722. Inc(I);
  9723. Inc(I);
  9724. WriteLn(F, Copy(S, J, I - J));
  9725. end;
  9726. CloseFile(F);
  9727. {$ENDIF}
  9728. if OverbyteIcsSSLEAY.GSSLEAY_DLL_Handle <> 0 then begin
  9729. _FreeLibrary(OverbyteIcsSSLEAY.GSSLEAY_DLL_Handle);
  9730. OverbyteIcsSSLEAY.GSSLEAY_DLL_Handle := 0;
  9731. end;
  9732. if OverbyteIcsLIBEAY.GLIBEAY_DLL_Handle <> 0 then begin
  9733. _FreeLibrary(OverbyteIcsLIBEAY.GLIBEAY_DLL_Handle);
  9734. OverbyteIcsLIBEAY.GLIBEAY_DLL_Handle := 0
  9735. end;
  9736. raise EIcsSsleayException.Create('Unable to load SSLEAY DLL. Can''t find ' + S);
  9737. end;
  9738. // Global system initialization
  9739. if f_SSL_library_init <> 1 then begin
  9740. if OverbyteIcsSSLEAY.GSSLEAY_DLL_Handle <> 0 then begin
  9741. _FreeLibrary(OverbyteIcsSSLEAY.GSSLEAY_DLL_Handle);
  9742. OverbyteIcsSSLEAY.GSSLEAY_DLL_Handle := 0;
  9743. end;
  9744. if OverbyteIcsLIBEAY.GLIBEAY_DLL_Handle <> 0 then begin
  9745. _FreeLibrary(OverbyteIcsLIBEAY.GLIBEAY_DLL_Handle);
  9746. OverbyteIcsLIBEAY.GLIBEAY_DLL_Handle := 0
  9747. end;
  9748. end;
  9749. f_SSL_load_error_strings;
  9750. Tick := _GetTickCount; // probably weak
  9751. f_RAND_seed(@Tick, SizeOf(Tick));
  9752. {$IFNDEF OPENSSL_NO_ENGINE}
  9753. //* Load all bundled ENGINEs into memory and make them visible */
  9754. f_ENGINE_load_builtin_engines;
  9755. {$ENDIF}
  9756. end; // SslRefCount = 0
  9757. Inc(SslRefCount);
  9758. finally
  9759. _LeaveCriticalSection(SslCritSect);
  9760. end;
  9761. end;
  9762. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  9763. { Reminder:
  9764. /* thread-local cleanup */
  9765. ERR_remove_state(0);
  9766. /* thread-safe cleanup */
  9767. ENGINE_cleanup();
  9768. CONF_modules_unload(1);
  9769. /* global application exit cleanup (after all SSL activity is shutdown) */
  9770. ERR_free_strings();
  9771. EVP_cleanup();
  9772. CRYPTO_cleanup_all_ex_data();
  9773. }
  9774. procedure UnloadSsl;
  9775. begin
  9776. _EnterCriticalSection(SslCritSect);
  9777. try
  9778. if SslRefCount > 0 then {AG 12/30/07}
  9779. Dec(SslRefCount);
  9780. if SslRefCount = 0 then begin {AG 12/30/07}
  9781. //* thread-local cleanup */
  9782. f_ERR_remove_state(0);
  9783. //* thread-safe cleanup */
  9784. f_CONF_modules_unload(1);
  9785. {$IFNDEF OPENSSL_NO_ENGINE}
  9786. f_ENGINE_cleanup;
  9787. {$ENDIF}
  9788. //* global application exit cleanup (after all SSL activity is shutdown) */
  9789. f_ERR_free_strings;
  9790. f_EVP_cleanup;
  9791. f_CRYPTO_cleanup_all_ex_data;
  9792. if OverbyteIcsSSLEAY.GSSLEAY_DLL_Handle <> 0 then begin
  9793. _FreeLibrary(OverbyteIcsSSLEAY.GSSLEAY_DLL_Handle);
  9794. OverbyteIcsSSLEAY.GSSLEAY_DLL_Handle := 0;
  9795. end;
  9796. if OverbyteIcsLIBEAY.GLIBEAY_DLL_Handle <> 0 then begin
  9797. _FreeLibrary(OverbyteIcsLIBEAY.GLIBEAY_DLL_Handle);
  9798. OverbyteIcsLIBEAY.GLIBEAY_DLL_Handle := 0
  9799. end;
  9800. end;
  9801. finally
  9802. _LeaveCriticalSection(SslCritSect);
  9803. end;
  9804. end;
  9805. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  9806. function SslErrorToStr(Err: Integer): String;
  9807. begin
  9808. case Err of
  9809. SSL_ERROR_ZERO_RETURN : Result := 'SSL_ERROR_ZERO_RETURN'; // A closure alert has occurred in the protocol
  9810. SSL_ERROR_WANT_CONNECT : Result := 'SSL_ERROR_WANT_CONNECT';
  9811. SSL_ERROR_WANT_ACCEPT : Result := 'SSL_ERROR_WANT_ACCEPT';
  9812. SSL_ERROR_WANT_READ : Result := 'SSL_ERROR_WANT_READ';
  9813. SSL_ERROR_WANT_WRITE : Result := 'SSL_ERROR_WANT_WRITE';
  9814. SSL_ERROR_WANT_X509_LOOKUP : Result := 'SSL_ERROR_WANT_X509_LOOKUP';
  9815. SSL_ERROR_SYSCALL : Result := 'SSL_ERROR_SYSCALL';
  9816. SSL_ERROR_SSL : Result := 'SSL_ERROR_SSL';
  9817. else
  9818. Result := 'Unknown';
  9819. end;
  9820. end;
  9821. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  9822. function print_errors: AnsiString;
  9823. var
  9824. Flags : Integer;
  9825. Line : Integer;
  9826. Data : PAnsiChar;
  9827. FileName : PAnsiChar;
  9828. ErrCode : Cardinal;
  9829. begin
  9830. result := '' ;
  9831. ErrCode := f_ERR_get_error_line_data(@FileName, @Line, @Data, @Flags);
  9832. while ErrCode <> 0 do begin
  9833. if Result <> '' then Result := Result + #13#10;
  9834. Result := Result + 'error code: ' + IcsIntToStrA(ErrCode) +
  9835. ' in ' + FileName + ' line ' + IcsIntToStrA(line);
  9836. if (Data <> nil) and ((Flags and ERR_TXT_STRING) <> 0) then
  9837. Result := Result + #13#10 + 'error data: ' + _StrPas(Data);
  9838. ErrCode := f_ERR_get_error_line_data(@FileName, @Line, @Data, @Flags);
  9839. end;
  9840. end;
  9841. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  9842. function print_error: AnsiString;
  9843. var
  9844. ErrCode : Integer;
  9845. begin
  9846. ErrCode := f_ERR_peek_error;
  9847. SetLength(result, 255);
  9848. f_ERR_error_string_n(ErrCode, PAnsiChar(Result), Length(Result));
  9849. SetLength(Result, _StrLen(PAnsiChar(Result)));
  9850. end;
  9851. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  9852. function OpenSslErrMsg(const AErrCode: LongWord): String;
  9853. var
  9854. Buf : AnsiString;
  9855. begin
  9856. SetLength(Buf, 127);
  9857. f_ERR_error_string_n(AErrCode, PAnsiChar(Buf), Length(Buf));
  9858. SetLength(Buf, _StrLen(PAnsiChar(Buf)));
  9859. Result := String(Buf);
  9860. end;
  9861. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  9862. function LastOpenSslErrMsg(Dump: Boolean): AnsiString;
  9863. var
  9864. ErrMsg : AnsiString;
  9865. ErrCode : Integer;
  9866. begin
  9867. ErrCode := f_ERR_get_error;
  9868. SetLength(Result, 120);
  9869. f_ERR_error_string_n(ErrCode, PAnsiChar(Result), Length(Result));
  9870. SetLength(Result, _StrLen(PAnsiChar(Result)));
  9871. if Dump then begin
  9872. ErrCode := f_ERR_get_error;
  9873. while ErrCode <> 0 do begin
  9874. SetLength(ErrMsg, 120);
  9875. f_ERR_error_string_n(ErrCode, PAnsiChar(ErrMsg), Length(ErrMsg));
  9876. SetLength(ErrMsg, _StrLen(PAnsiChar(ErrMsg)));
  9877. Result := Result + #13#10 + ErrMsg;
  9878. ErrCode := f_ERR_get_error;
  9879. end;
  9880. end;
  9881. end;
  9882. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  9883. procedure TSslBaseComponent.RaiseLastOpenSslError(
  9884. EClass : ExceptClass;
  9885. Dump : Boolean = FALSE;
  9886. const CustomMsg : String = '');
  9887. begin
  9888. FLastSslError := f_ERR_peek_error;
  9889. if Length(CustomMsg) > 0 then
  9890. raise EClass.Create(#13#10 + CustomMsg + #13#10 +
  9891. String(LastOpenSslErrMsg(Dump)) + #13#10)
  9892. else
  9893. raise EClass.Create(#13#10 + String(LastOpenSslErrMsg(Dump)) + #13#10);
  9894. end;
  9895. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  9896. constructor TSslBaseComponent.Create(AOwner: TComponent);
  9897. begin
  9898. inherited Create(AOwner);
  9899. FLastSslError := 0;
  9900. FSslInitialized := FALSE;
  9901. end;
  9902. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  9903. destructor TSslBaseComponent.Destroy;
  9904. begin
  9905. FinalizeSsl;
  9906. inherited Destroy;
  9907. end;
  9908. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  9909. procedure TSslBaseComponent.FinalizeSsl;
  9910. begin
  9911. if not FSslInitialized then
  9912. Exit;
  9913. UnloadSsl;
  9914. FSslInitialized := FALSE;
  9915. end;
  9916. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  9917. procedure TSslBaseComponent.InitializeSsl;
  9918. begin
  9919. if FSslInitialized then
  9920. Exit;
  9921. LoadSsl;
  9922. FSslInitialized := TRUE;
  9923. end;
  9924. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} { V5.21 }
  9925. {$IFNDEF NO_DEBUG_LOG}
  9926. function TSslBaseComponent.CheckLogOptions(const LogOption: TLogOption): Boolean;
  9927. begin
  9928. Result := Assigned(FIcsLogger) and (LogOption in FIcsLogger.LogOptions);
  9929. end;
  9930. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  9931. procedure TSslBaseComponent.DebugLog(LogOption: TLogOption; const Msg: String);
  9932. begin
  9933. if Assigned(FIcsLogger) then
  9934. {if loAddStamp in FIcsLogger.LogOptions then
  9935. FIcsLogger.DoDebugLog(Self, LogOption,
  9936. IcsLoggerAddTimeStamp + ' ' + Msg)
  9937. else}
  9938. FIcsLogger.DoDebugLog(Self, LogOption, Msg);
  9939. end;
  9940. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  9941. procedure TSslBaseComponent.Notification(
  9942. AComponent : TComponent;
  9943. Operation : TOperation);
  9944. begin
  9945. inherited Notification(AComponent, Operation);
  9946. if Operation = opRemove then begin
  9947. if AComponent = FIcsLogger then
  9948. FIcsLogger := nil;
  9949. end;
  9950. end;
  9951. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  9952. procedure TSslBaseComponent.SetIcsLogger(const Value: TIcsLogger);
  9953. begin
  9954. FIcsLogger := Value;
  9955. if Value <> nil then
  9956. Value.FreeNotification(Self);
  9957. end;
  9958. {$ENDIF}
  9959. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  9960. constructor TX509List.Create(AOwner: TComponent);
  9961. begin
  9962. inherited Create;
  9963. FOwner := AOwner;
  9964. FX509Class := TX509Base;
  9965. FList := TComponentList.Create;
  9966. FList.OwnsObjects := TRUE;
  9967. end;
  9968. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  9969. destructor TX509List.Destroy;
  9970. begin
  9971. _FreeAndNil(FList);
  9972. inherited Destroy;
  9973. end;
  9974. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  9975. procedure TX509List.Clear;
  9976. begin
  9977. FList.Clear;
  9978. end;
  9979. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  9980. procedure TX509List.Delete(const Index: Integer);
  9981. begin
  9982. FList.Delete(Index);
  9983. end;
  9984. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  9985. function TX509List.GetByHash(const Sha1Hash: AnsiString): TX509Base;
  9986. var
  9987. I : Integer;
  9988. begin
  9989. for I := 0 to FList.Count -1 do begin
  9990. if not Assigned(FList[I]) then
  9991. Continue;
  9992. Result := TX509Base(FList[I]);
  9993. if _CompareStr(Result.Sha1Hash, Sha1Hash) = 0 then
  9994. Exit;
  9995. end;
  9996. Result := nil;
  9997. end;
  9998. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  9999. function TX509List.GetCount: Integer;
  10000. begin
  10001. Result := FList.Count;
  10002. end;
  10003. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  10004. function TX509List.GetX509Base(Index: Integer): TX509Base;
  10005. begin
  10006. Result := TX509Base(FList[Index]);
  10007. end;
  10008. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  10009. function TX509List.IndexOf(const X509Base: TX509Base): Integer;
  10010. begin
  10011. Result := FList.IndexOf(X509Base);
  10012. end;
  10013. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  10014. procedure TX509List.SetX509Base(Index: Integer; Value: TX509Base);
  10015. var
  10016. X : TX509Base;
  10017. begin
  10018. X := TX509Base(FList[Index]);
  10019. if Assigned(X) then
  10020. X.Free;
  10021. FList[Index] := Value;
  10022. end;
  10023. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  10024. function TX509List.Add(X509: PX509 = nil): TX509Base;
  10025. begin
  10026. Result := FX509Class.Create(FOwner, X509);
  10027. FList.Add(Result);
  10028. end;
  10029. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  10030. function TX509List.GetByPX509(const X509: PX509): TX509Base;
  10031. var
  10032. Len : Integer;
  10033. Hash : AnsiString;
  10034. begin
  10035. if Assigned(X509) then begin
  10036. Len := 20;
  10037. SetLength(Hash, Len);
  10038. f_X509_digest(X509, f_EVP_sha1, PAnsiChar(Hash), @Len);
  10039. SetLength(Hash, _StrLen(PAnsiChar(Hash)));
  10040. Result := GetByHash(Hash);
  10041. end
  10042. else
  10043. Result := nil;
  10044. end;
  10045. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  10046. { TSslEngine }
  10047. {$IFNDEF OPENSSL_NO_ENGINE}
  10048. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  10049. procedure TSslEngine.Close;
  10050. begin
  10051. try
  10052. case FState of
  10053. esInit : f_ENGINE_finish(FEngine); // release the functional reference
  10054. esOpen : f_ENGINE_free(FEngine); // release the structural reference
  10055. else
  10056. Exit;
  10057. end;
  10058. FEngine := nil;
  10059. FState := esClosed;
  10060. except
  10061. FEngine := nil;
  10062. FState := esClosed;
  10063. raise;
  10064. end;
  10065. end;
  10066. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  10067. function TSslEngine.Control(const Cmd, Arg: String): Boolean;
  10068. var
  10069. PArg : PAnsiChar;
  10070. Msg : String;
  10071. begin
  10072. if FState = esClosed then
  10073. raise ESslEngineError.Create('Cannot control a closed engine');
  10074. if _CompareStr(Cmd, 'INIT') = 0 then // special ICS control command
  10075. begin
  10076. Result := Init;
  10077. Exit;
  10078. end;
  10079. if Arg = '' then
  10080. begin
  10081. PArg := nil;
  10082. Msg := _Format('Executing engine control command %s', [Cmd]);
  10083. end
  10084. else begin
  10085. PArg := PAnsiChar(AnsiString(Arg));
  10086. Msg := _Format('Executing engine control command %s:%s', [Cmd, Arg]);
  10087. end;
  10088. if f_ENGINE_ctrl_cmd_string(FEngine, PAnsiChar(AnsiString(Cmd)), PArg, 0) = 0 then
  10089. begin
  10090. FLastSslError := f_ERR_peek_last_error;
  10091. FLastErrorMsg := Msg + ' ' + String(LastOpenSslErrMsg(TRUE));
  10092. Result := FALSE;
  10093. end
  10094. else begin
  10095. FLastSslError := 0;
  10096. FLastErrorMsg := Msg;
  10097. Result := TRUE;
  10098. end;
  10099. end;
  10100. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  10101. destructor TSslEngine.Destroy;
  10102. begin
  10103. Close;
  10104. inherited;
  10105. end;
  10106. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  10107. function TSslEngine.Init: Boolean;
  10108. begin
  10109. if FState = esClosed then
  10110. raise ESslEngineError.Create('Cannot initialize a closed engine');
  10111. FLastErrorMsg := 'Engine ' + FNameID + 'initialized';
  10112. FLastSslError := 0;
  10113. Result := TRUE;
  10114. if FState = esInit then
  10115. Exit;
  10116. if f_ENGINE_init(FEngine) = 0 then
  10117. begin
  10118. FLastSslError := f_ERR_peek_last_error;
  10119. FLastErrorMsg := 'ENGINE_init'#13#10 + String(LastOpenSslErrMsg(TRUE));
  10120. Result := FALSE;
  10121. end
  10122. else begin
  10123. { This should always succeed if 'FEngine' was initialised OK }
  10124. f_ENGINE_set_default(FEngine, ENGINE_METHOD_ALL);
  10125. FState := esInit;
  10126. f_ENGINE_free(FEngine); // release the structural reference
  10127. end;
  10128. end;
  10129. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  10130. function TSslEngine.Open: Boolean;
  10131. begin
  10132. InitializeSsl;
  10133. {if _CompareStr(FNameID, 'auto') = 0 then
  10134. begin
  10135. f_ENGINE_register_all_complete;
  10136. FLastErrorMsg := 'Auto engine support enabled';
  10137. Result := TRUE;
  10138. Exit;
  10139. end;}
  10140. Close; // close the previous one (if assigned)
  10141. FEngine := f_ENGINE_by_id(PAnsiChar(AnsiString(FNameID)));
  10142. if FEngine = nil then
  10143. begin
  10144. FLastSslError := f_ERR_peek_last_error;
  10145. FLastErrorMsg := String(LastOpenSslErrMsg(TRUE));
  10146. Result := FALSE;
  10147. end
  10148. else begin
  10149. FState := esOpen;
  10150. Result := TRUE;
  10151. end;
  10152. end;
  10153. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  10154. procedure TSslEngine.SetNameID(const Value: String);
  10155. begin
  10156. Close;
  10157. FNameID := Value;
  10158. end;
  10159. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  10160. {$ENDIF OPENSSL_NO_ENGINE}
  10161. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  10162. const
  10163. SslIntOptions: array[TSslOption] of Integer = { V7.30 }
  10164. (SSL_OP_CIPHER_SERVER_PREFERENCE,
  10165. SSL_OP_MICROSOFT_SESS_ID_BUG,
  10166. SSL_OP_NETSCAPE_CHALLENGE_BUG,
  10167. SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG,
  10168. SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG,
  10169. SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER,
  10170. SSL_OP_MSIE_SSLV2_RSA_PADDING,
  10171. SSL_OP_SSLEAY_080_CLIENT_DH_BUG,
  10172. SSL_OP_TLS_D5_BUG,
  10173. SSL_OP_TLS_BLOCK_PADDING_BUG,
  10174. SSL_OP_TLS_ROLLBACK_BUG,
  10175. SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS,
  10176. SSL_OP_SINGLE_DH_USE,
  10177. SSL_OP_EPHEMERAL_RSA,
  10178. SSL_OP_NO_SSLv2,
  10179. SSL_OP_NO_SSLv3,
  10180. SSL_OP_NO_TLSv1,
  10181. SSL_OP_PKCS1_CHECK_1,
  10182. SSL_OP_PKCS1_CHECK_2,
  10183. SSL_OP_NETSCAPE_CA_DN_BUG,
  10184. SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION,
  10185. SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG,
  10186. SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION); // Since OSSL 0.9.8n
  10187. SslIntSessCacheModes: array[TSslSessCacheMode] of Integer = { V7.30 }
  10188. (SSL_SESS_CACHE_CLIENT,
  10189. SSL_SESS_CACHE_SERVER,
  10190. SSL_SESS_CACHE_NO_AUTO_CLEAR,
  10191. SSL_SESS_CACHE_NO_INTERNAL_LOOKUP,
  10192. SSL_SESS_CACHE_NO_INTERNAL_STORE);
  10193. constructor TSslContext.Create(AOwner: TComponent);
  10194. begin
  10195. inherited Create(AOwner);
  10196. {$IFNDEF NO_SSL_MT}
  10197. _InitializeCriticalSection(FLock);
  10198. {$ENDIF}
  10199. FSslCtx := nil;
  10200. SetSslVerifyPeerModes([SslVerifyMode_PEER]);
  10201. SetSslCipherList('ALL:!ADH:RC4+RSA:+SSLv2:@STRENGTH');
  10202. FSslVersionMethod := sslV23;
  10203. SslVerifyDepth := 9;
  10204. FSslSessionTimeOut := 0; // OSSL-default
  10205. FSslSessionCacheSize := SSL_SESSION_CACHE_MAX_SIZE_DEFAULT;
  10206. end;
  10207. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  10208. destructor TSslContext.Destroy;
  10209. begin
  10210. DeInitContext;
  10211. {$IFNDEF NO_SSL_MT}
  10212. _DeleteCriticalSection(FLock);
  10213. {$ENDIF}
  10214. inherited Destroy;
  10215. end;
  10216. (*
  10217. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  10218. procedure TSslContext.TriggerDebugLog (LogOption: TLogOption; { V5.21 }
  10219. const Msg, Data: String);
  10220. var
  10221. S: String;
  10222. begin
  10223. if loOptStamp in FLogOptions then
  10224. S := WSocketAddTimeStamp + ' ' + Msg
  10225. else
  10226. S := Msg;
  10227. if loOptEvent in FLogOptions then begin
  10228. if Assigned (FOnIcsLogEvent) then
  10229. FOnIcsLogEvent(Self, LogOption, S, '');
  10230. end;
  10231. if loOptOutDebug in FLogOptions then OutputDebugString(Pchar(S));
  10232. if loOptFile in FLogOptions then begin
  10233. if WSocketOpenLogFile then WriteLn(WSocketLogFile, S);
  10234. end;
  10235. end; *)
  10236. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  10237. function TSslContext.InitializeCtx: PSSL_CTX;
  10238. var
  10239. Meth : PSSL_METHOD;
  10240. begin
  10241. case FSslVersionMethod of
  10242. sslV2: Meth := f_SSLv2_method;
  10243. sslV2_CLIENT: Meth := f_SSLv2_client_method;
  10244. sslV2_SERVER: Meth := f_SSLv2_server_method;
  10245. sslV3: Meth := f_SSLv3_method;
  10246. sslV3_CLIENT: Meth := f_SSLv3_client_method;
  10247. sslV3_SERVER: Meth := f_SSLv3_server_method;
  10248. sslTLS_V1: Meth := f_TLSv1_method;
  10249. sslTLS_V1_CLIENT: Meth := f_TLSv1_client_method;
  10250. sslTLS_V1_SERVER: Meth := f_TLSv1_server_method;
  10251. sslV23: Meth := f_SSLv23_method;
  10252. sslV23_CLIENT: Meth := f_SSLv23_client_method;
  10253. sslV23_SERVER: Meth := f_SSLv23_server_method;
  10254. else raise ESslContextException.Create('Unknown SslVersionMethod');
  10255. end;
  10256. Result := f_SSL_CTX_new(Meth);
  10257. end;
  10258. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  10259. function TSslContext.GetIsCtxInitialized : Boolean;
  10260. begin
  10261. Result := FSslCtx <> nil;
  10262. end;
  10263. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  10264. function TSslContext.TrustCert(Cert: TX509Base): Boolean;
  10265. var
  10266. St : PX509_STORE;
  10267. begin
  10268. {$IFNDEF NO_SSL_MT}
  10269. Lock;
  10270. try
  10271. {$ENDIF}
  10272. Result := FALSE;
  10273. if (not Assigned(FSslCtx)) then
  10274. raise ESslContextException.Create(msgSslCtxNotInit);
  10275. if (not Assigned(Cert)) or (not Assigned(Cert.X509)) then
  10276. Exit;
  10277. //St := nil;
  10278. St := f_SSL_CTX_get_cert_store(FSslCtx);
  10279. if Assigned(St) then
  10280. Result := f_X509_STORE_add_cert(St, Cert.X509) <> 0;
  10281. { Fails if cert exists in store }
  10282. {$IFNDEF NO_DEBUG_LOG}
  10283. if (not Result) and
  10284. CheckLogOptions(loSslErr) then { V5.21 } { replaces $IFDEF DEBUG_OUTPUT }
  10285. DebugLog(loSslErr, String(LastOpenSslErrMsg(TRUE)));
  10286. {$ELSE}
  10287. if (not Result) then
  10288. f_ERR_clear_error;
  10289. {$ENDIF}
  10290. {$IFNDEF NO_SSL_MT}
  10291. finally
  10292. Unlock;
  10293. end;
  10294. {$ENDIF}
  10295. end;
  10296. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  10297. function PasswordCallBack(
  10298. Buf : PAnsiChar;
  10299. Num : Integer;
  10300. RWFlag : Integer;
  10301. UserData : Pointer) : Integer; cdecl;
  10302. var
  10303. Obj : TSslContext;
  10304. SslPassPhraseA : AnsiString;
  10305. begin
  10306. {$IFNDEF NO_SSL_MT}
  10307. _EnterCriticalSection(LockPwdCB);
  10308. try
  10309. {$ENDIF}
  10310. Obj := TSslContext(UserData);
  10311. if (Num < (Length(Obj.SslPassPhrase) + 1)) or
  10312. (Length(Obj.SslPassPhrase) = 0) then
  10313. Result := 0
  10314. else begin
  10315. SslPassPhraseA := AnsiString(Obj.SslPassPhrase);
  10316. Move(Pointer(SslPassPhraseA)^, Buf^, Length(SslPassPhraseA) + 1);
  10317. Result := Length(SslPassPhraseA);
  10318. end;
  10319. {$IFNDEF NO_SSL_MT}
  10320. finally
  10321. _LeaveCriticalSection(LockPwdCB);
  10322. end;
  10323. {$ENDIF}
  10324. end;
  10325. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  10326. {$IFNDEF OPENSSL_NO_ENGINE}
  10327. function PinCallback(ui: PUI; uis: PUI_STRING): Integer; cdecl;
  10328. var
  10329. Obj : TSslContext;
  10330. begin
  10331. {$IFNDEF NO_SSL_MT}
  10332. _EnterCriticalSection(LockPwdCB);
  10333. try
  10334. {$ENDIF}
  10335. Obj := TSslContext(f_Ics_UI_get_app_data(ui));
  10336. f_UI_set_result(ui, uis, PAnsiChar(AnsiString(Obj.FSslPassPhrase)));
  10337. Result := 1;
  10338. {$IFNDEF NO_SSL_MT}
  10339. finally
  10340. _LeaveCriticalSection(LockPwdCB);
  10341. end;
  10342. {$ENDIF}
  10343. end;
  10344. {$ENDIF}
  10345. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  10346. function PeerVerifyCallback(
  10347. Ok : Integer;
  10348. StoreCtx : PX509_STORE_CTX) : Integer; cdecl;
  10349. var
  10350. MySsl : PSSL;
  10351. Obj : TCustomSslWSocket;
  10352. Cert : PX509;
  10353. CurCert : TX509Base;
  10354. begin
  10355. {$IFNDEF NO_SSL_MT}
  10356. _EnterCriticalSection(LockVerifyCB);
  10357. try
  10358. {$ENDIF}
  10359. // Retrieve the pointer to the SSL of the current connection
  10360. MySsl := f_X509_STORE_CTX_get_ex_data(
  10361. StoreCtx, f_SSL_get_ex_data_X509_STORE_CTX_idx);
  10362. // Retrieve the object reference we stored at index 0
  10363. Obj := TCustomSslWSocket(f_SSL_get_ex_data(MySsl, 0));
  10364. if Assigned(Obj) then begin
  10365. Obj.Pause;
  10366. Obj.FSsl_In_CB := TRUE;
  10367. try
  10368. Cert := f_X509_STORE_CTX_get_current_cert(StoreCtx);
  10369. { Lookup this cert in our custom list (chain) }
  10370. CurCert := Obj.SslCertChain.GetByPX509(Cert);
  10371. { Add it to our list }
  10372. if not Assigned(CurCert) then begin
  10373. Obj.SslCertChain.X509Class := Obj.X509Class;
  10374. CurCert := Obj.SslCertChain.Add(Cert);
  10375. CurCert.VerifyResult := f_X509_STORE_CTX_get_error(StoreCtx);
  10376. CurCert.FFirstVerifyResult := CurCert.VerifyResult;
  10377. end
  10378. else { Unfortunately me must overwrite here }
  10379. CurCert.VerifyResult := f_X509_STORE_CTX_get_error(StoreCtx);
  10380. CurCert.VerifyDepth := f_X509_STORE_CTX_get_error_depth(StoreCtx);
  10381. //CurCert.CustomVerifyResult := CurCert.VerifyResult; // don't overwrite
  10382. Obj.SslCertChain.FLastVerifyResult := CurCert.VerifyResult;
  10383. {$IFNDEF NO_DEBUG_LOG}
  10384. if Obj.CheckLogOptions(loSslInfo) then begin { V5.21 } { replaces $IFDEF DEBUG_OUTPUT }
  10385. Obj.DebugLog(loSslInfo,'VCB> VerifyPeer: Subject = ' + CurCert.SubjectOneLine);
  10386. Obj.DebugLog(loSslInfo,'VCB> VerifyPeer: Serial = $' + _IntToHex(CurCert.SerialNum, 8));
  10387. Obj.DebugLog(loSslInfo,'VCB> VerifyPeer: Error = ' + CurCert.VerifyErrMsg);
  10388. end;
  10389. {$ENDIF}
  10390. // Save verify result
  10391. Obj.FSslVerifyResult := CurCert.VerifyResult;
  10392. Obj.TriggerSslVerifyPeer(Ok, CurCert);
  10393. if Ok <> 0 then
  10394. Obj.FSslVerifyResult := X509_V_OK;
  10395. finally
  10396. Obj.Resume;
  10397. Obj.FSsl_In_CB := FALSE;
  10398. if Obj.FHSocket = INVALID_SOCKET then
  10399. _PostMessage(Obj.FWindowHandle, Obj.FMsg_WM_RESET_SSL, 0, 0);
  10400. end;
  10401. end;
  10402. Result := Ok;
  10403. {$IFNDEF NO_SSL_MT}
  10404. finally
  10405. _LeaveCriticalSection(LockVerifyCB);
  10406. end;
  10407. {$ENDIF}
  10408. end;
  10409. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  10410. procedure RemoveSessionCallback(const Ctx : PSSL_CTX; Sess : PSSL_SESSION); cdecl;
  10411. var
  10412. Obj : TSslContext;
  10413. begin
  10414. { If remove_session_cb is not null, it will be called when }
  10415. { a session-id is removed from the cache. After the call, }
  10416. { OpenSSL will SSL_SESSION_free() it. }
  10417. { Also: It is invoked whenever a SSL_SESSION is destroyed. It is called }
  10418. { just before the session object is destroyed because it is invalid or }
  10419. { has expired. }
  10420. {$IFNDEF NO_SSL_MT}
  10421. _EnterCriticalSection(LockRemSessCB);
  10422. try
  10423. {$ENDIF}
  10424. Obj := TSslContext(f_SSL_CTX_get_ex_data(Ctx, 0));
  10425. if Assigned(Obj) then begin
  10426. {$IFNDEF NO_DEBUG_LOG}
  10427. if Obj.CheckLogOptions(loSslInfo) then { V5.21 } { replaces $IFDEF DEBUG_OUTPUT }
  10428. Obj.DebugLog(loSslInfo,'RSCB> Session removed');
  10429. {$ENDIF}
  10430. if Assigned(Obj.FOnRemoveSession) then
  10431. Obj.FOnRemoveSession(Obj, Sess);
  10432. end;
  10433. {$IFNDEF NO_SSL_MT}
  10434. finally
  10435. _LeaveCriticalSection(LockRemSessCB);
  10436. end;
  10437. {$ENDIF}
  10438. end;
  10439. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  10440. function Ics_EVP_PKEY_dup(PKey: PEVP_PKEY): PEVP_PKEY;
  10441. begin
  10442. Result := nil;
  10443. if PKey <> nil then begin
  10444. _EnterCriticalSection(SslCritSect);
  10445. try
  10446. Inc(PKey^.references);
  10447. Result := PKey;
  10448. finally
  10449. _LeaveCriticalSection(SslCritSect);
  10450. end;
  10451. end;
  10452. end;
  10453. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  10454. function ClientCertCallback(
  10455. Ssl : PSSL;
  10456. X509 : PPX509;
  10457. PKEY : PPEVP_PKEY): Integer; cdecl;
  10458. var
  10459. Obj : TCustomSslWSocket;
  10460. Cert : TX509Base;
  10461. X, P : Pointer;
  10462. begin
  10463. { It's called when a client certificate is requested by a server and no }
  10464. { certificate was yet set for the SSL object. client_cert_cb() is the }
  10465. { application defined callback. If it wants to set a certificate, a }
  10466. { certificate/private key combination must be set using the x509 and pkey }
  10467. { arguments and ``1'' must be returned. The certificate will be installed }
  10468. { into ssl, see the NOTES and BUGS sections. If no certificate should be }
  10469. { set, ``0'' has to be returned and no certificate will be sent. }
  10470. { A negative return value will suspend the handshake and the handshake }
  10471. { function will return immediatly. SSL_get_error(3) will return }
  10472. { SSL_ERROR_WANT_X509_LOOKUP to indicate, that the handshake was suspended.}
  10473. { The next call to the handshake function will again lead to the call of }
  10474. { client_cert_cb(). It is the job of the client_cert_cb() to store }
  10475. { information about the state of the last call, if required to continue. }
  10476. { Called when a client certificate is requested but there is not one set }
  10477. { against the SSL_CTX or the SSL. If the callback returns 1, x509 and }
  10478. { pkey need to point to valid data. The library will free these when }
  10479. { required so if the application wants to keep these around, increment }
  10480. { their reference counts. If 0 is returned, no client cert is }
  10481. { available. If -1 is returned, it is assumed that the callback needs }
  10482. { to be called again at a later point in time. SSL_connect will return }
  10483. { -1 and SSL_want_x509_lookup(ssl) returns TRUE. Remember that }
  10484. { application data can be attached to an SSL structure via the }
  10485. {$IFNDEF NO_SSL_MT}
  10486. _EnterCriticalSection(LockClientCertCB);
  10487. try
  10488. {$ENDIF}
  10489. Result := 0;
  10490. Obj := TCustomSslWSocket(f_SSL_get_ex_data(Ssl, 0));
  10491. if Assigned(Obj) then begin
  10492. Obj.FSsl_In_CB := TRUE;
  10493. Obj.Pause;
  10494. try
  10495. if Assigned(Obj.FOnSslCliCertRequest) then begin
  10496. Cert := nil;
  10497. try
  10498. Obj.FOnSslCliCertRequest(Obj, Cert);
  10499. if (Cert <> nil) and (Cert.X509 <> nil) and
  10500. (Cert.PrivateKey <> nil) then begin
  10501. X := f_X509_dup(Cert.X509);
  10502. P := Ics_EVP_PKEY_dup(Cert.FPrivateKey);
  10503. X509^ := X;
  10504. PKEY^ := P;
  10505. Result := 1;
  10506. end
  10507. else begin
  10508. //X509 := nil;
  10509. //PKEY := nil;
  10510. end;
  10511. except
  10512. // psst
  10513. end;
  10514. end;
  10515. finally
  10516. Obj.Resume;
  10517. Obj.FSsl_In_CB := FALSE;
  10518. if Obj.FHSocket = INVALID_SOCKET then
  10519. _PostMessage(Obj.FWindowHandle, Obj.FMsg_WM_RESET_SSL, 0, 0);
  10520. end;
  10521. end;
  10522. {$IFNDEF NO_SSL_MT}
  10523. finally
  10524. _LeaveCriticalSection(LockClientCertCB)
  10525. end;
  10526. {$ENDIF}
  10527. end;
  10528. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  10529. {$IFNDEF NO_SSL_MT}
  10530. procedure TSslContext.Lock;
  10531. begin
  10532. _EnterCriticalSection(FLock)
  10533. end;
  10534. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  10535. procedure TSslContext.Unlock;
  10536. begin
  10537. _LeaveCriticalSection(FLock)
  10538. end;
  10539. {$ENDIF}
  10540. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  10541. function NewSessionCallback(const SSL : PSSL; Sess : PSSL_SESSION): Integer; cdecl;
  10542. var
  10543. Obj : TCustomSslWSocket;
  10544. AddToInternalCache : Boolean;
  10545. SessID : Pointer;
  10546. IdLen : Integer;
  10547. begin
  10548. { If this callback is not null, it will be called each }
  10549. { time a session id is added to the cache. If this function }
  10550. { returns 1, it means that the callback will do a }
  10551. { SSL_SESSION_free() when it has finished using it. Otherwise, }
  10552. { on 0, it means the callback has finished with it. }
  10553. { Also: If this function returns 0, the session object will not be }
  10554. { cached. A nonzero return allows the session to be cached }
  10555. {$IFNDEF NO_SSL_MT}
  10556. _EnterCriticalSection(LockNewSessCB);
  10557. try
  10558. {$ENDIF}
  10559. Result := 0;
  10560. Obj := TCustomSslWSocket(f_SSL_get_ex_data(SSL, 0));
  10561. if not Assigned(Obj) then
  10562. raise Exception.Create('NewSessionCallback Obj not assigned');
  10563. Obj.FSsl_In_CB := TRUE;
  10564. try
  10565. {$IFNDEF NO_DEBUG_LOG}
  10566. if Obj.CheckLogOptions(loSslInfo) then { V5.21 } { replaces $IFDEF DEBUG_OUTPUT }
  10567. Obj.DebugLog(loSslInfo, 'NSCB> New session created');
  10568. {$ENDIF}
  10569. //f_SSL_session_get_id(Sess, SessID, IdLen); { 03/02/07 AG }
  10570. SessID := f_SSL_SESSION_get_id(Sess, IdLen); { 03/02/07 AG }
  10571. AddToInternalCache := FALSE; // not sure about the default value
  10572. if Assigned(Obj.FOnSslSvrNewSession) then
  10573. Obj.FOnSslSvrNewSession(Obj, Sess, SessID, IdLen, AddToInternalCache);
  10574. if AddToInternalCache then
  10575. Result := 1
  10576. else
  10577. Result := 0;
  10578. finally
  10579. Obj.FSsl_In_CB := FALSE;
  10580. if Obj.FHSocket = INVALID_SOCKET then
  10581. _PostMessage(Obj.FWindowHandle, Obj.FMsg_WM_RESET_SSL, 0, 0);
  10582. end;
  10583. {$IFNDEF NO_SSL_MT}
  10584. finally
  10585. _LeaveCriticalSection(LockNewSessCB);
  10586. end;
  10587. {$ENDIF}
  10588. end;
  10589. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  10590. function GetSessionCallback(
  10591. const SSL : PSSL;
  10592. SessId : Pointer;
  10593. IdLen : Integer;
  10594. Ref : PInteger) : PSSL_SESSION; cdecl;
  10595. var
  10596. Obj : TCustomSslWSocket;
  10597. Sess : Pointer;
  10598. IncRefCount : Boolean;
  10599. begin
  10600. { SessId = Session ID that's being requested by the peer. }
  10601. { The Session ID is distinctly different from the session ID context }
  10602. { Ref = An output from the callback. It is used to allow the }
  10603. { callback to specify whether the reference count on the returned }
  10604. { session object should be incremented or not. It returns as }
  10605. { nonzero if the object's reference count should be incremented; }
  10606. { otherwise, zero is returned }
  10607. {$IFNDEF NO_SSL_MT}
  10608. _EnterCriticalSection(LockGetSessCB);
  10609. try
  10610. {$ENDIF}
  10611. Result := nil;
  10612. Obj := TCustomSslWSocket(f_SSL_get_ex_data(SSL, 0));
  10613. if not Assigned(Obj) then
  10614. raise Exception.Create('GetSessionCallback Obj not assigned');
  10615. Obj.FSsl_In_CB := TRUE;
  10616. try
  10617. {$IFNDEF NO_DEBUG_LOG}
  10618. if Obj.CheckLogOptions(loSslInfo) then { V5.21 } { replaces $IFDEF DEBUG_OUTPUT }
  10619. Obj.DebugLog(loSslInfo, 'GSCB> Get session');
  10620. {$ENDIF}
  10621. Sess := nil;
  10622. IncRefCount := (Ref^ <> 0);
  10623. if Assigned(Obj.FOnSslSvrGetSession) then
  10624. Obj.FOnSslSvrGetSession(Obj, Sess, SessId, IdLen, IncRefCount);
  10625. if IncRefCount then
  10626. Ref^ := 1
  10627. else
  10628. Ref^ := 0;
  10629. Result := Sess;
  10630. finally
  10631. Obj.FSsl_In_CB := FALSE;
  10632. if Obj.FHSocket = INVALID_SOCKET then
  10633. _PostMessage(Obj.FWindowHandle, Obj.FMsg_WM_RESET_SSL, 0, 0);
  10634. end;
  10635. {$IFNDEF NO_SSL_MT}
  10636. finally
  10637. _LeaveCriticalSection(LockGetSessCB);
  10638. end;
  10639. {$ENDIF}
  10640. end;
  10641. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  10642. function TSslContext.OpenFileBio(
  10643. const FileName : String;
  10644. Methode : TBioOpenMethode): PBIO;
  10645. begin
  10646. if Filename = '' then
  10647. raise ESslContextException.Create('File name not specified');
  10648. if (Methode = bomRead) and (not _FileExists(Filename)) then
  10649. raise ESslContextException.Create('File not found "' +
  10650. Filename + '"');
  10651. if Methode = bomRead then
  10652. Result := f_BIO_new_file(PAnsiChar(AnsiString(Filename)), PAnsiChar('r+'))
  10653. else
  10654. Result := f_BIO_new_file(PAnsiChar(AnsiString(Filename)), PAnsiChar('w+'));
  10655. if Result = nil then
  10656. RaiseLastOpenSslError(ESslContextException, FALSE,
  10657. 'Error on opening file "' + Filename + '"');
  10658. end;
  10659. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  10660. { A X509_INFO may contain x509/crl/pkey sets, PEM format only }
  10661. function TSslContext.LoadStackFromInfoFile(const FileName: String;
  10662. Mode: TInfoExtractMode): PStack;
  10663. var
  10664. InfoStack : PStack;
  10665. CertInfo : PX509_INFO;
  10666. InBIO : PBIO;
  10667. //PKey : PX509_PKEY;
  10668. begin
  10669. //InfoStack := nil;
  10670. //CertInfo := nil;
  10671. //InBIO := nil;
  10672. Result := nil;
  10673. if not Assigned(FSslCtx) then
  10674. raise ESslContextException.Create(msgSslCtxNotInit);
  10675. if FileName = '' then
  10676. Exit;
  10677. InBIO := OpenFileBio(FileName, bomRead);
  10678. try
  10679. // This loads from a file, a stack of x509/crl/pkey sets
  10680. InfoStack := PStack(f_PEM_X509_INFO_read_bio(InBIO, nil, nil, nil));
  10681. if not Assigned(InfoStack) then
  10682. raise ESslContextException.CreateFmt('Error reading info file "%s"',
  10683. [FileName]);
  10684. try
  10685. if f_sk_num(InfoStack) > 0 then
  10686. Result := f_sk_new_null
  10687. else
  10688. Exit;
  10689. if Result = nil then
  10690. raise ESslContextException.Create('Error creating Stack');
  10691. // Scan over it and pull out what is needed
  10692. while f_sk_num(InfoStack) > 0 do begin
  10693. CertInfo := PX509_INFO(f_sk_delete(InfoStack, 0));
  10694. case Mode of
  10695. emCert :
  10696. if CertInfo^.x509 <> nil then
  10697. f_sk_insert(Result, PAnsiChar(f_X509_dup(CertInfo^.x509)),
  10698. f_sk_num(Result) + 1);
  10699. { A Dup-function for X509_PKEY is still missing in OpenSsl arrg!
  10700. emKey :
  10701. if CertInfo^.x_pkey <> nil then
  10702. f_sk_insert(Result, PChar(f_X509_PKEY_dup(CertInfo^.x_pkey)),
  10703. f_sk_num(Result) + 1);}
  10704. emCrl :
  10705. if CertInfo^.crl <> nil then
  10706. f_sk_insert(Result, PAnsiChar(f_X509_CRL_dup(CertInfo^.crl)),
  10707. f_sk_num(Result) + 1);
  10708. end; //case
  10709. f_X509_INFO_free(CertInfo);
  10710. end;
  10711. finally
  10712. f_sk_pop_free(InfoStack, @f_X509_INFO_free);
  10713. end;
  10714. finally
  10715. f_Bio_free(InBio);
  10716. end;
  10717. end;
  10718. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  10719. { PEM format only, the file may contain multiple certificates. }
  10720. { Loads intermediate CA certificates needed to build a complete chain. }
  10721. { PEM format only, any file of a given directory }
  10722. { PEM format only, the file may contain multiple CRL's }
  10723. procedure TSslContext.LoadCrlFromFile(const Filename: String);
  10724. var
  10725. CRL : PX509_CRL;
  10726. St : PX509_STORE;
  10727. CrlStack : PStack;
  10728. begin
  10729. {$IFNDEF NO_SSL_MT}
  10730. Lock;
  10731. try
  10732. {$ENDIF}
  10733. if not Assigned(FSslCtx) then
  10734. raise ESslContextException.Create(msgSslCtxNotInit);
  10735. if (Filename <> '') and (not _FileExists(Filename)) then
  10736. raise ESslContextException.Create('CRL file not found "' +
  10737. Filename + '"');
  10738. if Filename <> '' then begin
  10739. //CrlStack := nil;
  10740. CrlStack := LoadStackFromInfoFile(FileName, emCrl);
  10741. if not Assigned(CrlStack) then
  10742. raise ESslContextException.Create('Error on reading CRL file "' +
  10743. Filename + '"');
  10744. try
  10745. //St := nil;
  10746. St := f_SSL_CTX_get_cert_store(FSslCtx);
  10747. if not Assigned(St) then
  10748. raise ESslContextException.Create('Error on opening store');
  10749. while f_sk_num(CrlStack) > 0 do begin
  10750. //Crl := nil;
  10751. Crl := PX509_CRL(f_sk_delete(CrlStack, 0));
  10752. if Assigned(Crl) then
  10753. try
  10754. { Fails if CRL is already in hash table }
  10755. if f_X509_STORE_add_crl(St, Crl) = 0 then
  10756. {$IFNDEF NO_DEBUG_LOG}
  10757. if CheckLogOptions(loSslErr) then { V5.21 }
  10758. DebugLog(loSslErr, String(LastOpenSslErrMsg(True)));
  10759. {$ELSE}
  10760. f_ERR_clear_error;
  10761. {$ENDIF};
  10762. finally
  10763. f_X509_CRL_free(Crl);
  10764. end;
  10765. end;
  10766. finally
  10767. f_sk_pop_free(CrlStack, @f_X509_CRL_free);
  10768. end;
  10769. end;
  10770. {$IFNDEF NO_SSL_MT}
  10771. finally
  10772. Unlock;
  10773. end;
  10774. {$ENDIF}
  10775. end;
  10776. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  10777. { PEM format only, any file of a given directory }
  10778. procedure TSslContext.LoadCrlFromPath(const Path: String);
  10779. var
  10780. SRec : TSearchRec;
  10781. Found : Boolean;
  10782. S : String;
  10783. begin
  10784. if not Assigned(FSslCtx) then
  10785. raise ESslContextException.Create(msgSslCtxNotInit);
  10786. if (Path <> '') and (not _DirectoryExists(Path)) then
  10787. raise ESslContextException.Create('CRL directory not found "' +
  10788. Path + '"');
  10789. if Path <> '' then begin
  10790. S := _IncludeTrailingPathDelimiter(Path);
  10791. Found := _FindFirst(S + '*.*', faAnyFile - faDirectory, SRec) = 0;
  10792. if Found then
  10793. try
  10794. while Found do begin
  10795. LoadCrlFromFile(S + SRec.Name);
  10796. Found := _FindNext(SRec) = 0;
  10797. end;
  10798. finally
  10799. _FindClose(SRec);
  10800. end;
  10801. end;
  10802. end;
  10803. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  10804. procedure TSslContext.LoadVerifyLocations(const CAFile, CAPath: String);
  10805. var
  10806. PCAPath : PAnsiChar;
  10807. PCAFile : PAnsiChar;
  10808. begin
  10809. // Load the CAs we trust
  10810. //
  10811. // If CAfile is not NIL, it points to a file of CA certificates in PEM
  10812. // format. The file can contain several CA certificates.
  10813. //
  10814. // If CApath is not NIL, it points to a directory containing CA
  10815. // certificates in PEM format. The files each contain one CA certificate.
  10816. // The files are looked up by the CA subject name hash value, which must
  10817. // hence be available. If more than one CA certificate with the same name
  10818. // hash value exist, the extension must be different (e.g. 9d66eef0.0,
  10819. // 9d66eef0.1 etc). The search is performed in the ordering of the
  10820. // extension number, regardless of other properties of the certificates.
  10821. // The certificates in CApath are only looked up when required, e.g. when
  10822. // building the certificate chain or when actually performing the
  10823. // verification of a peer certificate. When looking up CA certificates,
  10824. // the OpenSSL library will first search the certificates in CAfile, then
  10825. // those in CApath.
  10826. if FSslCtx = nil then
  10827. raise ESslContextException.Create(msgSslCtxNotInit);
  10828. if (CAFile <> '') and (not _FileExists(CAFile)) then
  10829. raise ESslContextException.Create('File not found "' + CAFile + '"');
  10830. if (Length(CAPath) > 0) and (not _DirectoryExists(CAPath)) then
  10831. raise ESslContextException.Create('Directory not found "' + CAPath + '"');
  10832. if CAPath <> '' then
  10833. PCAPath := PAnsiChar(AnsiString(CAPath))
  10834. else
  10835. PCAPath := nil;
  10836. if CAFile <> '' then
  10837. PCAFile := PAnsiChar(AnsiString(CAFile))
  10838. else
  10839. PCAFile := nil;
  10840. if ((PCAFile <> nil) or (PCAPath <> nil)) and
  10841. (f_SSL_CTX_load_verify_locations(FSslCtx,
  10842. PCAFile, PCAPath) = 0) then
  10843. RaiseLastOpenSslError(ESslContextException, TRUE,
  10844. 'Can''t read CA File "' +
  10845. FSslCAFile + '" or ' +
  10846. 'CA Path "' + CAPath + '"');
  10847. if (PCAFile = nil) and (PCAPath = nil) and
  10848. (f_SSL_CTX_set_default_verify_paths(FSslCtx) <> 1) then
  10849. RaiseLastOpenSslError(ESslContextException, TRUE,
  10850. 'Error loading default CA file ' +
  10851. 'and/or directory');
  10852. end;
  10853. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  10854. procedure TSslContext.LoadCertFromChainFile(const FileName: String);
  10855. begin
  10856. if not Assigned(FSslCtx) then
  10857. raise ESslContextException.Create(msgSslCtxNotInit);
  10858. if (FileName <> '') and (not _FileExists(FileName)) then
  10859. raise ESslContextException.Create('File not found "' + FileName + '"');
  10860. if (FileName <> '') and
  10861. (f_SSL_CTX_use_certificate_chain_file(FSslCtx,
  10862. PAnsiChar(AnsiString(FileName))) = 0) then begin
  10863. {$IFNDEF NO_DEBUG_LOG}
  10864. if CheckLogOptions(loSslErr) then { V5.21 } { replaces $IFDEF DEBUG_OUTPUT }
  10865. DebugLog(loSslErr, String(LastOpenSslErrMsg(TRUE)));
  10866. {$ELSE}
  10867. f_ERR_clear_error;
  10868. {$ENDIF}
  10869. RaiseLastOpenSslError(ESslContextException, TRUE,
  10870. 'Can''t read certificate ' +
  10871. 'file "' + FileName + '"');
  10872. end;
  10873. end;
  10874. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  10875. procedure TSslContext.LoadPKeyFromFile(const FileName: String);
  10876. begin
  10877. if not Assigned(FSslCtx) then
  10878. raise ESslContextException.Create(msgSslCtxNotInit);
  10879. if (FileName <> '') and (not _FileExists(FileName)) then
  10880. raise ESslContextException.Create('File not found "' + FileName + '"');
  10881. if (FileName <> '') and
  10882. (f_SSL_CTX_use_PrivateKey_file(FSslCtx, PAnsiChar(AnsiString(FileName)),
  10883. SSL_FILETYPE_PEM) = 0) then begin
  10884. {$IFNDEF NO_DEBUG_LOG}
  10885. if CheckLogOptions(loSslInfo) then { V5.21 } { replaces $IFDEF DEBUG_OUTPUT }
  10886. DebugLog(loSslInfo, String(LastOpenSslErrMsg(TRUE)));
  10887. {$ELSE}
  10888. f_ERR_clear_error;
  10889. {$ENDIF}
  10890. RaiseLastOpenSslError(ESslContextException, TRUE,
  10891. 'Can''t load private key ' +
  10892. 'file "' + FileName + '"');
  10893. end;
  10894. end;
  10895. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  10896. {$IFNDEF OPENSSL_NO_ENGINE}
  10897. procedure TSslContext.Notification(
  10898. AComponent : TComponent;
  10899. Operation : TOperation);
  10900. begin
  10901. inherited Notification(AComponent, Operation);
  10902. if Operation = opRemove then begin
  10903. if AComponent = FCtxEngine then
  10904. FCtxEngine := nil;
  10905. end;
  10906. end;
  10907. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  10908. procedure TSslContext.SetCtxEngine(const Value: TSslEngine);
  10909. begin
  10910. FCtxEngine := Value;
  10911. if Value <> nil then
  10912. Value.FreeNotification(Self);
  10913. end;
  10914. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  10915. procedure TSslContext.LoadPKeyFromEngine(CtxEngine: TSslEngine);
  10916. var
  10917. PKey : PEVP_PKEY;
  10918. Uim : PUI_METHOD;
  10919. begin
  10920. if not Assigned(FSslCtx) then
  10921. raise ESslContextException.Create(msgSslCtxNotInit);
  10922. if (CtxEngine = nil) or (CtxEngine.KeyID = '') then
  10923. raise ESslContextException.Create('Engine and KeyID may not be empty');
  10924. if CtxEngine.State <> esInit then
  10925. if not CtxEngine.Init then
  10926. raise ESslContextException.Create(CtxEngine.LastErrorMsg);
  10927. Uim := f_UI_create_method(PAnsiChar('ICS WIN32 UI'));
  10928. f_UI_method_set_reader(Uim, PinCallback);
  10929. PKey := f_ENGINE_load_private_key(CtxEngine.E,
  10930. PAnsiChar(AnsiString(CtxEngine.KeyID)),
  10931. Uim, Pointer(Self));
  10932. if PKey = nil then
  10933. RaiseLastOpenSslError(ESslContextException, TRUE,
  10934. 'Can''t load private key from Engine');
  10935. if f_SSL_CTX_use_PrivateKey(FSslCtx, PKey) = 0 then
  10936. RaiseLastOpenSslError(ESslContextException, TRUE,
  10937. 'Can''t use private key');
  10938. end;
  10939. {$ENDIF OPENSSL_NO_ENGINE}
  10940. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  10941. { Open a PEM CA certificate file and add the CA name extracted }
  10942. { to the list of CAs sent to the client when requesting a client }
  10943. { certificate, usefull only in server mode. }
  10944. procedure TSslContext.AddClientCAFromFile(const FileName: String);
  10945. var
  10946. X : TX509Base;
  10947. begin
  10948. if not Assigned(FSslCtx) then
  10949. raise ESslContextException.Create(msgSslCtxNotInit);
  10950. if (Filename <> '') and (not _FileExists(Filename)) then
  10951. raise ESslContextException.Create('Certificate file not found "' +
  10952. Filename + '"');
  10953. if Filename <> '' then begin
  10954. X := TX509Base.Create(nil);
  10955. try
  10956. X.LoadFromPemFile(FileName);
  10957. if f_SSL_CTX_add_client_CA(FSslCtx, X.X509) <> 1 then
  10958. RaiseLastOpenSslError(ESslContextException, TRUE,
  10959. 'Can''t load client CA ' +
  10960. 'file "' + FileName + '"');
  10961. finally
  10962. X.Free;
  10963. end;
  10964. end;
  10965. end;
  10966. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  10967. { Scan all certificates in a PEM CAfile and list their names as acceptable }
  10968. { CAs sent to the client when we request a client certificate. Usefull only }
  10969. { in server mode. }
  10970. procedure TSslContext.SetClientCAListFromFile(const FileName: String);
  10971. var
  10972. Sk : PSTACK_OF_X509_NAME;
  10973. begin
  10974. if not Assigned(FSslCtx) then
  10975. raise ESslContextException.Create(msgSslCtxNotInit);
  10976. if (Filename <> '') and (not _FileExists(Filename)) then
  10977. raise ESslContextException.Create('Certificate file not found "' +
  10978. Filename + '"');
  10979. if Filename <> '' then begin
  10980. Sk := f_SSL_load_client_CA_file(PAnsiChar(AnsiString(FileName)));
  10981. if not Assigned(Sk) then
  10982. raise ESslContextException.Create('Error on reading certificate ' +
  10983. 'file "' + Filename + '"');
  10984. f_SSL_CTX_set_client_CA_list(FSslCTX, Sk); // frees Sk
  10985. end;
  10986. end;
  10987. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  10988. procedure TSslContext.InitContext;
  10989. var
  10990. SslSessCacheModes : TSslSessCacheModes;
  10991. begin
  10992. InitializeSsl; //loads libs
  10993. {$IFNDEF NO_SSL_MT}
  10994. Lock;
  10995. try
  10996. {$ENDIF}
  10997. {$IFNDEF NO_DEBUG_LOG}
  10998. if CheckLogOptions(loSslInfo) then
  10999. DebugLog(loSslInfo, 'InitCtx> OpenSSL version: ' + OpenSslVersion);
  11000. {$ENDIF}
  11001. {$IFNDEF OPENSSL_NO_ENGINE}
  11002. if (not GSslRegisterAllCompleted) and FAutoEnableBuiltinEngines then
  11003. begin
  11004. // Register all of them for every algorithm they collectively implement /
  11005. f_ENGINE_register_all_complete;
  11006. GSslRegisterAllCompleted := TRUE;
  11007. end;
  11008. {$ENDIF}
  11009. if not Assigned(FSslCtx) then begin
  11010. // Create new context
  11011. FSslCtx := InitializeCtx;
  11012. if not Assigned(FSslCtx) then
  11013. raise ESslContextException.Create('Failed to initialize context');
  11014. end;
  11015. try
  11016. if Assigned(FOnBeforeInit) then
  11017. FOnBeforeInit(Self);
  11018. // Load our key and certificate
  11019. {$IFNDEF OPENSSL_NO_ENGINE}
  11020. if (FCtxEngine <> nil) and
  11021. (eccLoadPrivKey in FCtxEngine.CtxCapabilities) then
  11022. LoadPKeyFromEngine(FCtxEngine)
  11023. else begin
  11024. {$ENDIF}
  11025. // Set the password callback and our custom user data
  11026. f_SSL_CTX_set_default_passwd_cb(FSslCtx, PasswordCallBack);
  11027. f_SSL_CTX_set_default_passwd_cb_userdata(FSslCtx, Self);
  11028. LoadPKeyFromFile(FSslPrivKeyFile);
  11029. {$IFNDEF OPENSSL_NO_ENGINE}
  11030. end;
  11031. {$ENDIF}
  11032. LoadCertFromChainFile(FSslCertFile);
  11033. // See notes in the procedure
  11034. LoadVerifyLocations(FSslCAFile, FSslCAPath);
  11035. LoadCRLFromFile(FSslCRLFile);
  11036. LoadCRLFromPath(FSslCRLPath);
  11037. //f_SSL_CTX_ctrl(FSslCtx, SSL_CTRL_MODE, SSL_MODE_ENABLE_PARTIAL_WRITE, nil); // Test
  11038. //raise Exception.Create('Test');
  11039. // Now the verify stuff
  11040. SetSslVerifyPeerModes(SslVerifyPeerModes);
  11041. {if FSslX509Trust <> ssl_X509_TRUST_NOT_DEFINED then
  11042. if f_SSL_CTX_set_trust(FSslCtx, Integer(FSslX509Trust)) = 0 then
  11043. raise Exception.Create('Error setting trust'); }
  11044. if FSslOptionsValue <> 0 then
  11045. { adds the options set via bitmask in options to ssl. }
  11046. { Options already set before are not cleared! }
  11047. f_SSL_CTX_set_options(FSslCtx, FSslOptionsValue);
  11048. if FSslCipherList <> '' then begin
  11049. if f_SSL_CTX_set_cipher_list(FSslCtx,
  11050. PAnsiChar(AnsiString(FSslCipherList))) = 0 then
  11051. RaiseLastOpenSslError(ESslContextException, TRUE,
  11052. 'Error loading cipher list');
  11053. end
  11054. else
  11055. raise ESslContextException.Create('Cipher list empty');
  11056. // Session caching stuff
  11057. SslSessCacheModes := GetSslSessCacheModes;
  11058. //if SslSessCacheModes <> [] then // AG 03/03/06 internal cache is ON by default
  11059. f_SSL_CTX_set_session_cache_mode(FSslCtx, FSslSessCacheModeValue);
  11060. if not (sslSESS_CACHE_NO_INTERNAL_STORE in SslSessCacheModes) then begin
  11061. { Exdata needed in RemoveCallback only }
  11062. if f_SSL_CTX_set_ex_data(FSslCtx, 0, PAnsiChar(Self)) = 0 then
  11063. RaiseLastOpenSslError(ESslContextException, TRUE,
  11064. 'SSL_CTX_set_ex_data failed');
  11065. f_SSL_CTX_sess_set_remove_cb(FSslCtx, RemoveSessionCallback);
  11066. if FSslSessionCacheSize <> SSL_SESSION_CACHE_MAX_SIZE_DEFAULT then
  11067. f_SSL_CTX_sess_set_cache_size(FSslCtx, FSslSessionCacheSize);
  11068. end;
  11069. if (sslSESS_CACHE_SERVER in SslSessCacheModes) then begin
  11070. { Set the timeout for newly created sessions }
  11071. if FSslSessionTimeout > 0 then
  11072. f_SSL_CTX_set_timeout(FSslCtx, FSslSessionTimeout);
  11073. { Set session callbacks, ssl server mode only }
  11074. f_SSL_CTX_sess_set_new_cb(FSslCtx, NewSessionCallback);
  11075. f_SSL_CTX_sess_set_get_cb(FSslCtx, GetSessionCallback);
  11076. if Length(FSslDefaultSessionIDContext) > 0 then
  11077. if f_SSL_CTX_set_session_id_context(FSslCtx,
  11078. @FSslDefaultSessionIDContext[1],
  11079. Length(FSslDefaultSessionIDContext)) = 0 then
  11080. RaiseLastOpenSslError(ESslContextException, TRUE,
  11081. 'ssl_ctx_set_session_id_context ' +
  11082. 'failed');
  11083. end;
  11084. except
  11085. if Assigned(FSslCtx) then begin
  11086. f_SSL_CTX_free(FSslCtx);
  11087. FSslCtx := nil;
  11088. end;
  11089. raise
  11090. end;
  11091. {$IFNDEF NO_SSL_MT}
  11092. finally
  11093. Unlock
  11094. end;
  11095. {$ENDIF}
  11096. end;
  11097. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  11098. procedure TSslContext.DeInitContext;
  11099. begin
  11100. {$IFNDEF NO_SSL_MT}
  11101. Lock;
  11102. try
  11103. {$ENDIF}
  11104. if Assigned(FSslCtx) then begin
  11105. { The context lives as long as there are open sessions associated }
  11106. { even when we called f_SSL_CTX_free(), so some cleanup is needed }
  11107. f_SSL_CTX_set_ex_data(FSslCtx, 0, nil); //MainFix // AG 12/25/07
  11108. { It may be a good idea to disable all callbacks as well }
  11109. { before freeing the context pointer, should not hurt, }
  11110. { otherwise please let me know }
  11111. f_SSL_CTX_sess_set_remove_cb(FSslCtx, nil); // AG 12/25/07
  11112. f_SSL_CTX_sess_set_new_cb(FSslCtx, nil); // AG 12/25/07
  11113. f_SSL_CTX_sess_set_get_cb(FSslCtx, nil); // AG 12/25/07
  11114. f_SSL_CTX_set_default_passwd_cb(FSslCtx, nil); // AG 12/25/07
  11115. f_SSL_CTX_set_default_passwd_cb_userdata(FSslCtx, nil); // AG 12/25/07
  11116. f_SSL_CTX_free(FSslCtx);
  11117. FSslCtx := nil;
  11118. end;
  11119. {$IFNDEF NO_SSL_MT}
  11120. finally
  11121. Unlock;
  11122. end;
  11123. {$ENDIF}
  11124. FinalizeSsl;
  11125. end;
  11126. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  11127. procedure TSslContext.SetSslCAFile(const Value: String);
  11128. begin
  11129. {$IFNDEF NO_SSL_MT}
  11130. Lock;
  11131. try
  11132. {$ENDIF}
  11133. if _CompareStr(FSslCAFile, Value) = 0 then
  11134. Exit;
  11135. FSslCAFile := Value;
  11136. if Assigned(FSslCtx) then
  11137. LoadVerifyLocations(FSslCAFile, FSslCAPath);
  11138. {$IFNDEF NO_SSL_MT}
  11139. finally
  11140. Unlock
  11141. end;
  11142. {$ENDIF}
  11143. end;
  11144. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  11145. procedure TSslContext.SetSslCAPath(const Value: String);
  11146. begin
  11147. {$IFNDEF NO_SSL_MT}
  11148. Lock;
  11149. try
  11150. {$ENDIF}
  11151. if _CompareStr(FSslCAPath, Value) = 0 then
  11152. Exit;
  11153. FSslCAPath := Value;
  11154. if Assigned(FSslCtx) then
  11155. LoadVerifyLocations(FSslCAFile, FSslCAPath);
  11156. {$IFNDEF NO_SSL_MT}
  11157. finally
  11158. Unlock
  11159. end;
  11160. {$ENDIF}
  11161. end;
  11162. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  11163. procedure TSslContext.SetSslCertFile(const Value: String);
  11164. begin
  11165. {$IFNDEF NO_SSL_MT}
  11166. Lock;
  11167. try
  11168. {$ENDIF}
  11169. if _CompareStr(Value, FSslCertFile) = 0 then
  11170. Exit;
  11171. FSslCertFile := Value;
  11172. if Assigned(FSslCtx) then
  11173. LoadCertFromChainFile(FSslCertFile);
  11174. {$IFNDEF NO_SSL_MT}
  11175. finally
  11176. Unlock
  11177. end;
  11178. {$ENDIF}
  11179. end;
  11180. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  11181. procedure TSslContext.SetSslCRLFile(const Value: String);
  11182. begin
  11183. {$IFNDEF NO_SSL_MT}
  11184. Lock;
  11185. try
  11186. {$ENDIF}
  11187. FSslCRLFile := Value
  11188. {$IFNDEF NO_SSL_MT}
  11189. finally
  11190. Unlock
  11191. end;
  11192. {$ENDIF}
  11193. end;
  11194. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  11195. procedure TSslContext.SetSslCRLPath(const Value: String);
  11196. begin
  11197. {$IFNDEF NO_SSL_MT}
  11198. Lock;
  11199. try
  11200. {$ENDIF}
  11201. FSslCRLPath := Value
  11202. {$IFNDEF NO_SSL_MT}
  11203. finally
  11204. Unlock
  11205. end;
  11206. {$ENDIF}
  11207. end;
  11208. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  11209. procedure TSslContext.SetSslPassPhrase(const Value: String);
  11210. begin
  11211. {$IFNDEF NO_SSL_MT}
  11212. Lock;
  11213. try
  11214. {$ENDIF}
  11215. FSslPassPhrase := Value
  11216. {$IFNDEF NO_SSL_MT}
  11217. finally
  11218. Unlock
  11219. end;
  11220. {$ENDIF}
  11221. end;
  11222. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  11223. procedure TSslContext.SetSslPrivKeyFile(const Value: String);
  11224. begin
  11225. {$IFNDEF NO_SSL_MT}
  11226. Lock;
  11227. try
  11228. {$ENDIF}
  11229. if (_CompareStr(Value, FSslPrivKeyFile) = 0) then
  11230. Exit;
  11231. FSslPrivKeyFile := Value;
  11232. if Assigned(FSslCtx) then
  11233. LoadPKeyFromFile(FSslPrivKeyFile);
  11234. {$IFNDEF NO_SSL_MT}
  11235. finally
  11236. Unlock
  11237. end;
  11238. {$ENDIF}
  11239. end;
  11240. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  11241. procedure TSslContext.SetSslSessionCacheSize(Value: Longint);
  11242. begin
  11243. {$IFNDEF NO_SSL_MT}
  11244. Lock;
  11245. try
  11246. {$ENDIF}
  11247. FSslSessionCacheSize := Value
  11248. {$IFNDEF NO_SSL_MT}
  11249. finally
  11250. Unlock
  11251. end;
  11252. {$ENDIF}
  11253. end;
  11254. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  11255. procedure TSslContext.SetSslSessionTimeout(Value: Longword);
  11256. begin
  11257. {$IFNDEF NO_SSL_MT}
  11258. Lock;
  11259. try
  11260. {$ENDIF}
  11261. FSslSessionTimeout := Value
  11262. {$IFNDEF NO_SSL_MT}
  11263. finally
  11264. Unlock
  11265. end;
  11266. {$ENDIF}
  11267. end;
  11268. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  11269. procedure TSslContext.SetSslVersionMethod(Value: TSslVersionMethod);
  11270. begin
  11271. {$IFNDEF NO_SSL_MT}
  11272. Lock;
  11273. try
  11274. {$ENDIF}
  11275. FSslVersionMethod := Value
  11276. {$IFNDEF NO_SSL_MT}
  11277. finally
  11278. Unlock
  11279. end;
  11280. {$ENDIF}
  11281. end;
  11282. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  11283. function TSslContext.GetSslOptions: TSslOptions; { V7.30 }
  11284. var
  11285. Opt: TSslOption;
  11286. begin
  11287. {$IFNDEF NO_SSL_MT}
  11288. Lock;
  11289. try
  11290. {$ENDIF}
  11291. Result := [];
  11292. for Opt := Low(TSslOption) to High(TSslOption) do
  11293. if (FSslOptionsValue and SslIntOptions[Opt]) <> 0 then
  11294. Include(Result, Opt);
  11295. {$IFNDEF NO_SSL_MT}
  11296. finally
  11297. Unlock
  11298. end;
  11299. {$ENDIF}
  11300. end;
  11301. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  11302. procedure TSslContext.SetSslOptions(Value: TSslOptions); { V7.30 }
  11303. var
  11304. Opt: TSslOption;
  11305. begin
  11306. {$IFNDEF NO_SSL_MT}
  11307. Lock;
  11308. try
  11309. {$ENDIF}
  11310. FSslOptionsValue := 0;
  11311. for Opt := Low(TSslOption) to High(TSslOption) do
  11312. if Opt in Value then
  11313. FSslOptionsValue := FSslOptionsValue or SslIntOptions[Opt];
  11314. {$IFNDEF NO_SSL_MT}
  11315. finally
  11316. Unlock;
  11317. end;
  11318. {$ENDIF}
  11319. end;
  11320. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  11321. procedure TSslContext.SetSslSessCacheModes(Value: TSslSessCacheModes); { V7.30 }
  11322. var
  11323. SessMode: TSslSessCacheMode;
  11324. begin
  11325. {$IFNDEF NO_SSL_MT}
  11326. Lock;
  11327. try
  11328. {$ENDIF}
  11329. FSslSessCacheModeValue := SSL_SESS_CACHE_OFF;
  11330. for SessMode := Low(TSslSessCacheMode) to High(TSslSessCacheMode) do
  11331. if SessMode in Value then
  11332. FSslSessCacheModeValue := FSslSessCacheModeValue or SslIntSessCacheModes[SessMode];
  11333. {$IFNDEF NO_SSL_MT}
  11334. finally
  11335. Unlock;
  11336. end;
  11337. {$ENDIF}
  11338. end;
  11339. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  11340. function TSslContext.GetSslSessCacheModes: TSslSessCacheModes; { V7.30 }
  11341. var
  11342. SessMode: TSslSessCacheMode;
  11343. begin
  11344. {$IFNDEF NO_SSL_MT}
  11345. Lock;
  11346. try
  11347. {$ENDIF}
  11348. Result := [];
  11349. for SessMode := Low(TSslSessCacheMode) to High(TSslSessCacheMode) do
  11350. if FSslSessCacheModeValue and SslIntSessCacheModes[SessMode] <> 0 then
  11351. Include(Result, SessMode);
  11352. {$IFNDEF NO_SSL_MT}
  11353. finally
  11354. Unlock;
  11355. end;
  11356. {$ENDIF}
  11357. end;
  11358. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  11359. procedure TSslContext.SetSslCipherList(const Value: String);
  11360. begin
  11361. {$IFNDEF NO_SSL_MT}
  11362. Lock;
  11363. try
  11364. {$ENDIF}
  11365. if FSslCipherList = Value then
  11366. Exit; // No change, do nothing
  11367. // Now should check the syntax. Will do later :-)
  11368. FSslCipherList := Value;
  11369. {$IFNDEF NO_SSL_MT}
  11370. finally
  11371. Unlock
  11372. end;
  11373. {$ENDIF}
  11374. end;
  11375. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  11376. procedure TSslContext.SetSslVerifyPeerModes(
  11377. const Value: TSslVerifyPeerModes);
  11378. begin
  11379. {$IFNDEF NO_SSL_MT}
  11380. Lock;
  11381. try
  11382. {$ENDIF}
  11383. if Value <> FSslVerifyPeerModes then begin
  11384. FSslVerifyPeerModesValue := 0;
  11385. if (SslVerifyMode_NONE in Value) then
  11386. FSslVerifyPeerModesValue := FSslVerifyPeerModesValue or SSL_VERIFY_NONE;
  11387. if (SslVerifyMode_PEER in Value) then
  11388. FSslVerifyPeerModesValue := FSslVerifyPeerModesValue or SSL_VERIFY_PEER;
  11389. if (SslVerifyMode_FAIL_IF_NO_PEER_CERT in Value) then
  11390. FSslVerifyPeerModesValue := FSslVerifyPeerModesValue or SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
  11391. if (SslVerifyMode_CLIENT_ONCE in Value) then
  11392. FSslVerifyPeerModesValue := FSslVerifyPeerModesValue or SSL_VERIFY_CLIENT_ONCE;
  11393. FSslVerifyPeerModes := Value;
  11394. end;
  11395. if not Assigned(FSslCtx) then
  11396. Exit;
  11397. { We may change these settings any time since they won't change active Ssl's }
  11398. if FSslVerifyPeer then begin
  11399. if f_SSL_CTX_get_verify_mode(FSslCtx) <> FSslVerifyPeerModesValue then begin
  11400. f_SSL_CTX_set_verify(FSslCtx, FSslVerifyPeerModesValue, PeerVerifyCallback);
  11401. {$IFDEF OPENSSL_VERSION_NUMBER_LESS_THAN_0x00905100L}
  11402. f_SSL_CTX_set_verify_depth(FSslCtx, 1);
  11403. {$ELSE}
  11404. f_SSL_CTX_set_verify_depth(FSslCtx, FSslVerifyDepth);
  11405. {$ENDIF}
  11406. end;
  11407. end
  11408. else begin
  11409. f_SSL_CTX_set_verify(FSslCtx, 0, nil);
  11410. f_SSL_CTX_set_verify_depth(FSslCtx, 0);
  11411. end;
  11412. {$IFNDEF NO_SSL_MT}
  11413. finally
  11414. Unlock;
  11415. end;
  11416. {$ENDIF}
  11417. end;
  11418. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  11419. procedure TSslContext.SetSslVerifyPeer(const Value: Boolean);
  11420. begin
  11421. {$IFNDEF NO_SSL_MT}
  11422. Lock;
  11423. try
  11424. {$ENDIF}
  11425. if Value <> FSslVerifyPeer then begin
  11426. FSslVerifyPeer := Value;
  11427. SetSslVerifyPeerModes(FSslVerifyPeerModes);
  11428. end;
  11429. {$IFNDEF NO_SSL_MT}
  11430. finally
  11431. Unlock;
  11432. end;
  11433. {$ENDIF}
  11434. end;
  11435. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  11436. procedure TSslContext.SetSslDefaultSessionIDContext(
  11437. Value: TSslSessionIdContext);
  11438. begin
  11439. {$IFNDEF NO_SSL_MT}
  11440. Lock;
  11441. try
  11442. {$ENDIF}
  11443. if Length(Value) > SSL_MAX_SSL_SESSION_ID_LENGTH then
  11444. SetLength(Value, SSL_MAX_SSL_SESSION_ID_LENGTH);
  11445. if FSslDefaultSessionIDContext <> Value then begin
  11446. FSslDefaultSessionIDContext := Value;
  11447. if Assigned(FSslCtx) and (SSL_SESS_CACHE_SERVER and
  11448. FSslSessCacheModeValue <> 1) then begin
  11449. if Length(Value) > 0 then
  11450. f_SSL_CTX_set_session_id_context(FSslCtx,
  11451. @Value[1],
  11452. Length(Value))
  11453. else
  11454. f_SSL_CTX_set_session_id_context(FSslCtx, nil, 0);
  11455. end;
  11456. end;
  11457. {$IFNDEF NO_SSL_MT}
  11458. finally
  11459. Unlock
  11460. end;
  11461. {$ENDIF}
  11462. end;
  11463. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  11464. {procedure TSslContext.SetSslX509Trust(const Value: TSslX509Trust);
  11465. begin
  11466. if Value <> FSslX509Trust then begin
  11467. FSslX509Trust := Value;
  11468. if Assigned(FSslCtx) then
  11469. if FSslX509Trust <> ssl_X509_TRUST_NOT_DEFINED then
  11470. if f_SSL_CTX_set_trust(FSslCtx, Integer(FSslX509Trust)) = 0 then
  11471. raise Exception.Create('Error setting trust');
  11472. end;
  11473. end; }
  11474. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  11475. (*
  11476. { TX509Stack }
  11477. constructor TX509Stack.Create;
  11478. begin
  11479. inherited Create;
  11480. FStack := nil;
  11481. FStack := f_sk_new_null;
  11482. FCount := 0;
  11483. end;
  11484. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  11485. destructor TX509Stack.Destroy;
  11486. begin
  11487. if Assigned(FStack) then begin
  11488. Clear;
  11489. f_sk_free(FStack);
  11490. FStack := nil;
  11491. end;
  11492. inherited Destroy;
  11493. end;
  11494. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  11495. function TX509Stack.Add(Cert: PX509): Integer;
  11496. begin
  11497. Result := InternalInsert(Cert, f_sk_num(FStack)) - 1;
  11498. end;
  11499. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  11500. procedure TX509Stack.Clear;
  11501. begin
  11502. while FCount > 0 do
  11503. Delete(0);
  11504. end;
  11505. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  11506. procedure TX509Stack.SetStack(const Value: PSTACK);
  11507. var
  11508. I: Integer;
  11509. begin
  11510. Clear;
  11511. if Value <> nil then
  11512. for I := 0 to f_sk_num(Value) - 1 do
  11513. Add(PX509(f_sk_value(Value, I)));
  11514. end;
  11515. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  11516. procedure TX509Stack.Delete(Index: Integer);
  11517. var
  11518. P : PChar;
  11519. begin
  11520. P := nil;
  11521. P := f_sk_delete(FStack, Index);
  11522. if P <> nil then begin
  11523. Dec(FCount);
  11524. f_X509_free(PX509(P));
  11525. end else
  11526. raise EX509Exception.Create('Delete failed');
  11527. end;
  11528. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  11529. function TX509Stack.IndexOf(Cert: PX509): Integer;
  11530. begin
  11531. Result := 0;
  11532. while (Result < FCount) and
  11533. (PX509(f_sk_value(FStack, Result)) <> Cert) do
  11534. Inc(Result);
  11535. if Result = FCount then
  11536. Result := -1;
  11537. end;
  11538. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  11539. procedure TX509Stack.Insert(Cert: PX509; Index: Integer);
  11540. begin
  11541. InternalInsert(Cert, Index)
  11542. end;
  11543. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  11544. function TX509Stack.InternalInsert(Cert: PX509; Index: Integer): Integer;
  11545. var
  11546. P : PX509;
  11547. begin
  11548. if (Index < 0) then
  11549. raise EX509Exception.Create('Invalid index');
  11550. if Cert = nil then
  11551. raise EX509Exception.Create('Cert not assigned');
  11552. P := nil;
  11553. P := f_X509_dup(Cert); // increment reference count
  11554. if P = nil then
  11555. raise EX509Exception.Create('X509_dup failed');
  11556. Result := f_sk_insert(FStack, PChar(P), Index);
  11557. if Result = 0 then
  11558. f_X509_free(P)
  11559. else
  11560. FCount := Result;
  11561. end;
  11562. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  11563. function TX509Stack.GetCert(Index: Integer): PX509;
  11564. begin
  11565. Result := PX509(f_sk_value(FStack, Index));
  11566. end;
  11567. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  11568. procedure TX509Stack.SetCert(Index: Integer; const Value: PX509);
  11569. begin
  11570. if (Index < 0) or (Index >= FCount) then
  11571. raise EX509Exception.Create('Invalid index');
  11572. Delete(Index);
  11573. InternalInsert(Value, Index);
  11574. end;
  11575. *)
  11576. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  11577. constructor TX509Base.Create(AOwner: TComponent; X509: Pointer = nil);
  11578. begin
  11579. inherited Create(AOwner);
  11580. FPrivateKey := nil;
  11581. AssignDefaults;
  11582. if Assigned(X509) then begin
  11583. InitializeSsl;
  11584. FX509 := f_X509_dup(X509);
  11585. FSha1Hash := GetSha1Hash;
  11586. end;
  11587. end;
  11588. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  11589. destructor TX509Base.Destroy;
  11590. begin
  11591. FreeAndNilX509;
  11592. if Assigned(FPrivateKey) then begin
  11593. f_EVP_PKEY_free(FPrivateKey);
  11594. FPrivateKey := nil;
  11595. end;
  11596. inherited Destroy;
  11597. end;
  11598. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  11599. procedure TX509Base.FreeAndNilX509;
  11600. begin
  11601. if Assigned(FX509) then begin
  11602. f_X509_free(FX509);
  11603. FX509 := nil;
  11604. end;
  11605. end;
  11606. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  11607. procedure TX509Base.SetX509(X509: Pointer);
  11608. begin
  11609. InitializeSsl;
  11610. FreeAndNilX509;
  11611. AssignDefaults;
  11612. if Assigned(X509) then begin
  11613. FX509 := f_X509_dup(X509);
  11614. FSha1Hash := GetSha1Hash;
  11615. end;
  11616. end;
  11617. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  11618. procedure TX509Base.SetPrivateKey(PKey: Pointer);
  11619. begin
  11620. InitializeSsl;
  11621. if Assigned(FPrivateKey) then begin
  11622. f_EVP_PKEY_free(FPrivateKey);
  11623. FPrivateKey := nil;
  11624. end;
  11625. if Assigned(PKey) then
  11626. FPrivateKey := Ics_EVP_PKEY_dup(PKey);
  11627. end;
  11628. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  11629. function TX509Base.GetPublicKey: Pointer; {AG 11/08/07}
  11630. begin
  11631. if Assigned(FX509) then
  11632. Result := f_X509_get_pubkey(FX509)
  11633. else
  11634. Result := nil;
  11635. end;
  11636. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  11637. function TX509Base.GetExtensionCount: Integer;
  11638. begin
  11639. if Assigned(FX509) then
  11640. Result := f_X509_get_ext_count(FX509)
  11641. else
  11642. Result := 0;
  11643. end;
  11644. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  11645. function TX509Base.ExtByName(const ShortName: String): Integer;
  11646. var
  11647. Ext : PX509_EXTENSION;
  11648. Count : Integer;
  11649. I : Integer;
  11650. Len : Integer;
  11651. ExtStr : PAnsiChar;
  11652. B : PBIO;
  11653. Nid : Integer;
  11654. begin
  11655. Result := -1;
  11656. if Assigned(FX509) then begin
  11657. Count := GetExtensionCount;
  11658. for I := 0 to Count -1 do begin
  11659. //Ext := nil;
  11660. Ext := f_X509_get_ext(FX509, I);
  11661. if not Assigned(Ext) then
  11662. Continue;
  11663. Nid := f_OBJ_obj2nid(f_X509_EXTENSION_get_object(Ext));
  11664. if Nid <> NID_undef then begin
  11665. ExtStr := f_OBJ_nid2sn(Nid);
  11666. if _StrLIComp(ExtStr, PAnsiChar(AnsiString(ShortName)), 255) = 0 then begin
  11667. Result := I;
  11668. Exit;
  11669. end;
  11670. end
  11671. else begin // custom extension
  11672. //B := nil;
  11673. B := f_BIO_new(f_BIO_s_mem);
  11674. if Assigned(B) then begin
  11675. try
  11676. f_i2a_ASN1_OBJECT(B, f_X509_EXTENSION_get_object(Ext));
  11677. Len := f_BIO_ctrl(B, BIO_CTRL_PENDING, 0, nil);
  11678. if Len > 0 then begin
  11679. GetMem(ExtStr, Len);
  11680. try
  11681. f_Bio_read(B, ExtStr, Len);
  11682. if _StrLIComp(ExtStr, PAnsiChar(AnsiString(ShortName)), 255) = 0 then begin
  11683. Result := I;
  11684. Exit;
  11685. end;
  11686. finally
  11687. FreeMem(ExtStr);
  11688. end;
  11689. end;
  11690. finally
  11691. f_bio_free(B);
  11692. end;
  11693. end;
  11694. end;
  11695. end;
  11696. end
  11697. end;
  11698. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  11699. function TX509Base.GetIssuerOneLine: String;
  11700. var
  11701. Str : AnsiString;
  11702. begin
  11703. Result := '';
  11704. if not Assigned(FX509) then
  11705. Exit;
  11706. SetLength(Str, 512);
  11707. Str := f_X509_NAME_oneline(f_X509_get_issuer_name(FX509),
  11708. PAnsiChar(Str),
  11709. Length(Str));
  11710. SetLength(Str, _StrLen(PAnsiChar(Str)));
  11711. Result := String(Str);
  11712. end;
  11713. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  11714. function TX509Base.GetSerialNum: Integer;
  11715. begin
  11716. if Assigned(FX509) then
  11717. Result := f_ASN1_INTEGER_get(f_X509_get_serialNumber(FX509))
  11718. else
  11719. Result := -1;
  11720. end;
  11721. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  11722. function TX509Base.GetSha1Hash: AnsiString; { V7.31 }
  11723. var
  11724. Len : Integer;
  11725. begin
  11726. if Assigned(FX509) then begin
  11727. SetLength(Result, 20);
  11728. if f_X509_digest(FX509, f_EVP_sha1, PAnsiChar(Result), @Len) = 0 then
  11729. Result := '';
  11730. end
  11731. else
  11732. Result := '';
  11733. end;
  11734. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  11735. function TX509Base.UnknownExtDataToStr(Ext: PX509_Extension) : String;
  11736. {var
  11737. B : PBIO;
  11738. Len : Integer; }
  11739. begin
  11740. Result := Asn1ToString(PASN1_STRING(f_X509_EXTENSION_get_data(Ext)));
  11741. {B := f_BIO_new(f_BIO_s_mem);
  11742. if Assigned(B) then begin
  11743. try
  11744. f_ASN1_STRING_print(B, PASN1_STRING(f_X509_EXTENSION_get_data(Ext)));
  11745. Len := f_BIO_ctrl(B, BIO_CTRL_PENDING, 0, nil);
  11746. SetLength(Result, Len);
  11747. if Len > 0 then begin
  11748. f_Bio_read(B, PChar(Result), Len);
  11749. SetLength(Result, StrLen(PChar(Result)));
  11750. end;
  11751. finally
  11752. f_BIO_free(B);
  11753. end;
  11754. end
  11755. else
  11756. Result := '';}
  11757. end;
  11758. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  11759. function TX509Base.GetExtension(Index: Integer): TExtension;
  11760. var
  11761. ExtCount : Integer;
  11762. J : Integer;
  11763. Ext : PX509_EXTENSION;
  11764. Value : PAnsiChar;
  11765. Meth : PX509V3_EXT_METHOD;
  11766. Data : PAnsiChar;
  11767. Val : PSTACK;
  11768. NVal : PCONF_VALUE;
  11769. ext_str : Pointer;
  11770. B : PBIO;
  11771. Nid : Integer;
  11772. ABuf : AnsiString;
  11773. begin
  11774. Result.Critical := FALSE;
  11775. Result.ShortName := '';
  11776. Result.Value := '';
  11777. if not Assigned(FX509) then
  11778. Exit;
  11779. ExtCount := ExtensionCount;
  11780. if (Index < 0) or (Index > ExtCount -1) then
  11781. raise EX509Exception.Create('Extension index out of bounds');
  11782. Value := nil;
  11783. Meth := nil;
  11784. Val := nil;
  11785. ext_str := nil;
  11786. //Ext := nil;
  11787. Ext := f_X509_get_ext(FX509, Index);
  11788. if not Assigned(Ext) then
  11789. raise EX509Exception.Create('Extension not assigned');
  11790. Result.Critical := f_X509_EXTENSION_get_critical(Ext) > 0;
  11791. Nid := f_OBJ_obj2nid(f_X509_EXTENSION_get_object(Ext));
  11792. if Nid <> NID_undef then
  11793. Result.ShortName := String(_StrPas(f_OBJ_nid2sn(Nid)))
  11794. else begin // custom extension
  11795. //B := nil;
  11796. B := f_BIO_new(f_BIO_s_mem);
  11797. if Assigned(B) then begin
  11798. try
  11799. f_i2a_ASN1_OBJECT(B, f_X509_EXTENSION_get_object(Ext));
  11800. J := f_BIO_ctrl(B, BIO_CTRL_PENDING, 0, nil);
  11801. SetLength(ABuf, J);
  11802. if J > 0 then begin
  11803. f_Bio_read(B, PAnsiChar(ABuf), J);
  11804. SetLength(ABuf, _StrLen(PAnsiChar(ABuf)));
  11805. Result.ShortName := String(ABuf);
  11806. end;
  11807. finally
  11808. f_bio_free(B);
  11809. end;
  11810. end;
  11811. end;
  11812. try
  11813. Meth := f_X509V3_EXT_get(Ext);
  11814. if Meth = nil then begin
  11815. Result.Value := UnknownExtDataToStr(Ext);
  11816. Exit;
  11817. end;
  11818. Data := Ext^.value^.data;
  11819. if Assigned(Meth^.it) then
  11820. ext_str := f_ASN1_item_d2i(nil,