ssockets.pp 42 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639
  1. {
  2. This file is part of the Free Component Library (FCL)
  3. Copyright (c) 1999-2000 by the Free Pascal development team
  4. See the file COPYING.FPC, included in this distribution,
  5. for details about the copyright.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  9. **********************************************************************}
  10. {$MODE objfpc}{$H+}
  11. {$R-}
  12. {$IFNDEF FPC_DOTTEDUNITS}
  13. unit ssockets;
  14. {$ENDIF FPC_DOTTEDUNITS}
  15. interface
  16. {$IFDEF FPC_DOTTEDUNITS}
  17. uses
  18. System.SysUtils, System.Classes, System.CTypes, System.Net.Sockets;
  19. {$ELSE FPC_DOTTEDUNITS}
  20. uses
  21. SysUtils, Classes, ctypes, sockets;
  22. {$ENDIF FPC_DOTTEDUNITS}
  23. type
  24. TSocketErrorType = (
  25. seHostNotFound,
  26. seCreationFailed,
  27. seBindFailed,
  28. seListenFailed,
  29. seConnectFailed,
  30. seConnectTimeOut,
  31. seAcceptFailed,
  32. seAcceptWouldBlock,
  33. seIOTimeOut);
  34. TSocketOption = (soDebug,soReuseAddr,soKeepAlive,soDontRoute,soBroadcast,
  35. soOOBinline);
  36. TSocketOptions = Set of TSocketOption;
  37. ESocketError = class(Exception)
  38. Code: TSocketErrorType;
  39. constructor Create(ACode: TSocketErrorType; const MsgArgs: array of const);overload;
  40. end;
  41. TAcceptErrorAction = (aeaRaise,aeaIgnore,aeaStop);
  42. TSocketStream = Class;
  43. TSocketServer = Class;
  44. TInetSocket = Class;
  45. {$IFDEF UNIX}
  46. TUnixSocket = class;
  47. TUnixSocketClass = Class of TUnixSocket;
  48. {$ENDIF}
  49. TSocketStreamClass = Class of TSocketStream;
  50. TInetSocketClass = Class of TInetSocket;
  51. // Handles all OS calls
  52. { TSocketHandler }
  53. TSocketState = (sosCanread,sosCanWrite,sosException);
  54. TSocketStates = Set of TSocketState;
  55. TSocketHandler = Class(TObject)
  56. Private
  57. FSocket: TSocketStream;
  58. Protected
  59. FLastError : integer;
  60. Procedure SetSocket(const AStream: TSocketStream); virtual;
  61. Procedure CheckSocket;
  62. Public
  63. constructor Create; virtual;
  64. // Called after the connect call succeded. Returns True to continue, false to close connection.
  65. function Connect: boolean; virtual;
  66. // Called after the accept call succeded on the NEW client socket
  67. function Accept : Boolean; virtual;
  68. Function Close : Boolean; virtual;
  69. function Shutdown(BiDirectional : Boolean): boolean; virtual;
  70. function Select(aCheck : TSocketStates; TimeOut : Integer): TSocketStates; virtual;
  71. function CanRead(TimeOut : Integer): Boolean; virtual;
  72. function Recv(Const Buffer; Count: Integer): Integer; virtual;
  73. function Send(Const Buffer; Count: Integer): Integer; virtual;
  74. function BytesAvailable: Integer; virtual;
  75. // Call this to get extra error info.
  76. Function GetLastErrorDescription : String; virtual;
  77. Property Socket : TSocketStream Read FSocket;
  78. Property LastError : Integer Read FLastError;
  79. end;
  80. TSocketHandlerClass = Class of TSocketHandler;
  81. { TSocketStream }
  82. TSocketStreamArray = Array of TSocketStream;
  83. TSocketStream = class(THandleStream)
  84. Private
  85. FClosed: Boolean;
  86. FOnClose: TNotifyEvent;
  87. FPeerClosed: Boolean;
  88. FReadFlags: Integer;
  89. FSocketInitialized : Boolean;
  90. FSocketOptions : TSocketOptions;
  91. FWriteFlags: Integer;
  92. FHandler : TSocketHandler;
  93. FIOTimeout : Integer;
  94. FConnectTimeout : Integer;
  95. function GetLastError: Integer;
  96. Procedure GetSockOptions;
  97. procedure SetConnectTimeout(AValue: Integer);
  98. Procedure SetSocketOptions(Value : TSocketOptions);
  99. function GetLocalAddress: {$IFDEF FPC_DOTTEDUNITS}System.Net.{$ENDIF}Sockets.TSockAddr;
  100. function GetRemoteAddress: {$IFDEF FPC_DOTTEDUNITS}System.Net.{$ENDIF}Sockets.TSockAddr;
  101. procedure SetIOTimeout(AValue: Integer);
  102. Protected
  103. Procedure DoOnClose; virtual;
  104. Public
  105. Constructor Create (AHandle : Longint; AHandler : TSocketHandler = Nil);virtual;
  106. destructor Destroy; override;
  107. Class Function Select(Var aRead,aWrite,aExceptions : TSocketStreamArray; aTimeOut: Integer): Boolean; virtual;
  108. Procedure Close;
  109. function Seek(Offset: Longint; Origin: Word): Longint; override;
  110. function Select(aCheck : TSocketStates; TimeOut : Integer): TSocketStates;
  111. Function CanRead(TimeOut : Integer): Boolean; virtual;
  112. Function Read (Var Buffer; Count : Longint) : longint; Override;
  113. Function Write (Const Buffer; Count : Longint) :Longint; Override;
  114. Property SocketOptions : TSocketOptions Read FSocketOptions
  115. Write SetSocketOptions;
  116. property LocalAddress: {$IFDEF FPC_DOTTEDUNITS}System.Net.{$ENDIF}sockets.TSockAddr read GetLocalAddress;
  117. property RemoteAddress: {$IFDEF FPC_DOTTEDUNITS}System.Net.{$ENDIF}sockets.TSockAddr read GetRemoteAddress;
  118. Property LastError : Integer Read GetLastError;
  119. Property ReadFlags : Integer Read FReadFlags Write FReadFlags;
  120. Property WriteFlags : Integer Read FWriteFlags Write FWriteFlags;
  121. Property IOTimeout : Integer read FIOTimeout Write SetIOTimeout;
  122. Property ConnectTimeout : Integer read FConnectTimeout Write SetConnectTimeout;
  123. Property OnClose : TNotifyEvent Read FOnClose Write FOnClose;
  124. Property Handler : TSocketHandler Read FHandler;
  125. // We called close
  126. Property Closed : Boolean read FClosed;
  127. // Peer closed detected when reading.
  128. Property PeerClosed : Boolean Read FPeerClosed;
  129. end;
  130. TSocketClientEvent = Procedure (Sender : TObject; Data : TSocketStream) Of Object;
  131. TConnectEvent = TSocketClientEvent;
  132. TDisconnectEvent = TSocketClientEvent;
  133. TConnectionDroppedEvent = TSocketClientEvent;
  134. TConnectQuery = Procedure (Sender : TObject; ASocket : Longint; Var Allow : Boolean) of Object;
  135. TOnAcceptError = Procedure (Sender : TObject; ASocket : Longint; E : Exception; Var ErrorAction : TAcceptErrorAction) of Object;
  136. TGetClientSocketHandlerEvent = Procedure (Sender : TObject; Out AHandler : TSocketHandler) of object;
  137. TForeachHandler = Procedure (Sender : TObject; aClient : TSocketStream; var aContinue : Boolean) of object;
  138. { TSocketServer }
  139. TSocketServer = Class(TObject)
  140. Private
  141. FIdleTimeOut: Cardinal;
  142. FMaxSimultaneousConnections: longint;
  143. FOnAcceptError: TOnAcceptError;
  144. FOnConnectionDropped: TConnectionDroppedEvent;
  145. FOnCreateClientSocketHandler: TGetClientSocketHandlerEvent;
  146. FOnDisconnect: TDisconnectEvent;
  147. FOnIdle : TNotifyEvent;
  148. FNonBlocking : Boolean;
  149. FSocket : longint;
  150. FAccepting : Boolean;
  151. FMaxConnections : Longint;
  152. FQueueSize : Longint;
  153. FOnConnect : TConnectEvent;
  154. FOnConnectQuery : TConnectQuery;
  155. FHandler : TSocketHandler;
  156. FConnections : TThreadList;
  157. Procedure DoOnIdle;
  158. function GetConnectionCount: Integer;
  159. Function GetReuseAddress: Boolean;
  160. Function GetKeepAlive : Boolean;
  161. Function GetLinger : Integer;
  162. Procedure SetReuseAddress (AValue : Boolean);
  163. Procedure SetKeepAlive (AValue : Boolean);
  164. Procedure SetLinger(ALinger : Integer);
  165. Protected
  166. FSockType : Longint;
  167. FBound : Boolean;
  168. Procedure SocketClosed(aSocket: TSocketStream);
  169. Procedure DoConnectionDropped(aSocket : TSocketStream); virtual;
  170. Procedure DoDisconnect(aSocket : TSocketStream); virtual;
  171. Procedure DoConnect(ASocket : TSocketStream); Virtual;
  172. Function DoConnectQuery(ASocket : longint): Boolean ;Virtual;
  173. Procedure Bind; Virtual; Abstract;
  174. Function Accept: Longint;Virtual;Abstract;
  175. Function SockToStream (ASocket : Longint) : TSocketStream;Virtual;Abstract;
  176. Procedure Close; Virtual;
  177. Procedure Abort;
  178. Procedure RemoveSelfFromConnections; virtual;
  179. Function RunIdleLoop : Boolean;
  180. function GetConnection: TSocketStream; virtual; abstract;
  181. Function HandleAcceptError(E : ESocketError) : TAcceptErrorAction;
  182. Function GetClientSocketHandler(aSocket : Longint) : TSocketHandler; virtual;
  183. Property Handler : TSocketHandler Read FHandler;
  184. Public
  185. Constructor Create(ASocket : Longint; AHandler : TSocketHandler);
  186. Destructor Destroy; Override;
  187. Procedure Listen;
  188. function GetSockopt(ALevel,AOptName : cint; var optval; Var optlen : tsocklen): Boolean;
  189. function SetSockopt(ALevel,AOptName : cint; var optval; optlen : tsocklen): Boolean;
  190. Procedure StartAccepting;
  191. Procedure StopAccepting(DoAbort : Boolean = False);
  192. Procedure SetNonBlocking;
  193. Procedure Foreach(aHandler : TForeachHandler);
  194. Property Bound : Boolean Read FBound;
  195. // Maximium number of connections in total. *Not* the simultaneous connection count. -1 keeps accepting.
  196. Property MaxConnections : longint Read FMaxConnections Write FMaxConnections;
  197. Property MaxSimultaneousConnections : longint Read FMaxSimultaneousConnections Write FMaxSimultaneousConnections;
  198. Property QueueSize : Longint Read FQueueSize Write FQueueSize default 5;
  199. Property OnConnect : TConnectEvent Read FOnConnect Write FOnConnect;
  200. Property OnDisconnect : TDisconnectEvent Read FOnDisconnect Write FOnDisconnect;
  201. Property OnConnectionDropped : TConnectionDroppedEvent Read FOnConnectionDropped Write FOnConnectionDropped;
  202. Property OnConnectQuery : TConnectQuery Read FOnConnectQuery Write FOnConnectQuery;
  203. Property OnAcceptError : TOnAcceptError Read FOnAcceptError Write FOnAcceptError;
  204. Property OnIdle : TNotifyEvent Read FOnIdle Write FOnIdle;
  205. Property NonBlocking : Boolean Read FNonBlocking;
  206. Property Socket : Longint Read FSocket;
  207. Property SockType : Longint Read FSockType;
  208. Property KeepAlive : Boolean Read GetKeepAlive Write SetKeepAlive;
  209. Property ReuseAddress : Boolean Read GetReuseAddress Write SetReuseAddress;
  210. // -1 means no linger. Any value >=0 sets linger on.
  211. Property Linger: Integer Read GetLinger Write Setlinger;
  212. // Accept Timeout in milliseconds.
  213. // If Different from 0, then there will be an idle loop before accepting new connections, Calling OnIdle if no new connection appeared in the specified timeout.
  214. Property AcceptIdleTimeOut : Cardinal Read FIdleTimeOut Write FIdleTimeout;
  215. Property OnCreateClientSocketHandler : TGetClientSocketHandlerEvent Read FOnCreateClientSocketHandler Write FOnCreateClientSocketHandler;
  216. Property ConnectionCount : Integer Read GetConnectionCount;
  217. end;
  218. { TInetServer }
  219. TInetServer = Class(TSocketServer)
  220. private
  221. FAddr : TINetSockAddr;
  222. FPort : Word;
  223. FHost: string;
  224. Protected
  225. Function GetConnection: TSocketStream; override;
  226. Function SockToStream (ASocket : Longint) : TSocketStream;Override;
  227. Function Accept : Longint;override;
  228. Property Addr : TINetSockAddr Read FAddr;
  229. Public
  230. DefaultInetSocketClass : TInetSocketClass;
  231. Public
  232. Procedure Bind; Override;
  233. Constructor Create(APort: Word);
  234. Constructor Create(const aHost: string; const APort: Word; AHandler : TSocketHandler = Nil);
  235. Property Port : Word Read FPort;
  236. Property Host : string Read FHost;
  237. end;
  238. {$ifdef Unix}
  239. { TUnixServer }
  240. TUnixServer = Class(TSocketServer)
  241. Private
  242. FUnixAddr : TUnixSockAddr;
  243. FFileName : String;
  244. Protected
  245. Procedure Bind; Override;
  246. Function Accept : Longint;override;
  247. function GetConnection: TSocketStream; override;
  248. Function SockToStream (ASocket : Longint) : TSocketStream;Override;
  249. Procedure Close; override;
  250. Public
  251. DefaultUnixSocketClass : TUnixSocketClass;
  252. Public
  253. Constructor Create(const AFileName : String; AHandler : TSocketHandler = Nil);
  254. Property FileName : String Read FFileName;
  255. end;
  256. {$endif}
  257. { TInetSocket }
  258. TBlockingMode = (bmBlocking,bmNonBlocking);
  259. TBlockingModes = Set of TBlockingMode;
  260. TCheckTimeoutResult = (ctrTimeout,ctrError,ctrOK);
  261. { TServerSocketStream }
  262. TServerSocketStream = class(TSocketStream)
  263. Protected
  264. FServer : TSocketServer;
  265. Protected
  266. Procedure DoOnClose; override;
  267. Property Server : TSocketServer Read FServer;
  268. Public
  269. Function CanRead(TimeOut : Integer): Boolean; override;
  270. end;
  271. {$if defined(unix) or defined(windows)}
  272. {$DEFINE HAVENONBLOCKING}
  273. {$endif}
  274. TInetSocket = Class(TSocketStream)
  275. Private
  276. FHost : String;
  277. FPort : Word;
  278. Protected
  279. {$IFDEF HAVENONBLOCKING}
  280. function SetSocketBlockingMode(ASocket: cint; ABlockMode: TBlockingMode; AFDSPtr: Pointer): boolean; virtual;
  281. function CheckSocketConnectTimeout(ASocket: cint; AFDSPtr: Pointer; ATimeVPtr: Pointer): TCheckTimeoutResult; virtual;
  282. {$ENDIF}
  283. Public
  284. Constructor Create(const AHost: String; APort: Word; AHandler : TSocketHandler = Nil); Overload;
  285. Constructor Create(const AHost: String; APort: Word; aConnectTimeout : Integer; AHandler : TSocketHandler = Nil); Overload;
  286. Procedure Connect; Virtual;
  287. Property Host : String Read FHost;
  288. Property Port : Word Read FPort;
  289. end;
  290. {$ifdef Unix}
  291. TUnixSocket = Class(TSocketStream)
  292. Private
  293. FFileName : String;
  294. Protected
  295. Procedure DoConnect(ASocket : longint); Virtual;
  296. Public
  297. Constructor Create(ASocket : Longint); Overload;
  298. Constructor Create(const AFileName : String); Overload;
  299. Property FileName : String Read FFileName;
  300. end;
  301. {$endif}
  302. Implementation
  303. {$IFDEF FPC_DOTTEDUNITS}
  304. uses
  305. // This must be here, to prevent it from overriding the sockets definitions... :/
  306. {$ifdef unix}
  307. UnixApi.Base,UnixApi.Unix,
  308. {$endif}
  309. {$ifdef Windows}
  310. WinApi.Winsock2, WinApi.Windows,
  311. {$endif}
  312. System.Net.Resolve;
  313. {$ELSE FPC_DOTTEDUNITS}
  314. uses
  315. // This must be here, to prevent it from overriding the sockets definitions... :/
  316. {$ifdef unix}
  317. BaseUnix,Unix,
  318. {$endif}
  319. {$ifdef windows}
  320. winsock2, windows,
  321. {$endif}
  322. resolve;
  323. {$ENDIF FPC_DOTTEDUNITS}
  324. Const
  325. SocketBlockingMode = 0;
  326. SocketNonBlockingMode = 1;
  327. { ---------------------------------------------------------------------
  328. ESocketError
  329. ---------------------------------------------------------------------}
  330. resourcestring
  331. strHostNotFound = 'Host name resolution for "%s" failed.';
  332. strSocketCreationFailed = 'Creation of socket failed: %s';
  333. strSocketBindFailed = 'Binding of socket failed: %s';
  334. strSocketListenFailed = 'Listening on port #%d failed, error: %d';
  335. strSocketConnectFailed = 'Connect to %s failed: %s';
  336. strSocketAcceptFailed = 'Could not accept a client connection on socket: %d, error %d';
  337. strSocketAcceptWouldBlock = 'Accept would block on socket: %d';
  338. strSocketIOTimeOut = 'Failed to set IO Timeout to %d';
  339. strErrNoStream = 'Socket stream not assigned';
  340. strSocketConnectTimeOut = 'Connection to %s timed out.';
  341. { TServerSocketStream }
  342. function TServerSocketStream.CanRead(TimeOut : Integer): Boolean;
  343. begin
  344. Result:=inherited CanRead(TimeOut);
  345. Result:=Result and Assigned(FServer); // main server is gone, cannot read from it
  346. end;
  347. procedure TServerSocketStream.DoOnClose;
  348. begin
  349. if Assigned(FServer) then
  350. FServer.SocketClosed(Self);
  351. inherited DoOnClose;
  352. end;
  353. { TSocketHandler }
  354. Procedure TSocketHandler.SetSocket(const AStream: TSocketStream);
  355. begin
  356. FSocket:=AStream;
  357. end;
  358. Procedure TSocketHandler.CheckSocket;
  359. begin
  360. If not Assigned(FSocket) then
  361. Raise ESocketError.Create(StrErrNoStream);
  362. end;
  363. constructor TSocketHandler.Create;
  364. begin
  365. FSocket:=Nil;
  366. end;
  367. function TSocketHandler.Connect: boolean;
  368. begin
  369. // Only descendents can change this
  370. Result:=True;
  371. end;
  372. function TSocketHandler.Accept : Boolean;
  373. begin
  374. // Only descendents can change this
  375. Result:=True;
  376. end;
  377. function TSocketHandler.Shutdown(BiDirectional: Boolean): boolean;
  378. begin
  379. CheckSocket ;
  380. Result:=False;
  381. end;
  382. function TSocketHandler.Select(aCheck: TSocketStates; TimeOut: Integer): TSocketStates;
  383. {$if defined(unix) or defined(windows)}
  384. var
  385. FDSR,FDSW,FDSE : TFDSet;
  386. PFDSR,PFDSW,PFDSE : PFDSet;
  387. TimeV: TTimeVal;
  388. PTV : ^TTimeVal;
  389. res : Longint;
  390. Procedure DoSet(var FDS : TFDSet; var PFDS : PFDSet; aState : TSocketState);
  391. begin
  392. if not (aState in aCheck) then
  393. PFDS:=nil
  394. else
  395. begin
  396. FDS := Default(TFDSet);
  397. {$ifdef unix}
  398. fpFD_Zero(FDS);
  399. fpFD_Set(FSocket.Handle, FDS);
  400. {$endif}
  401. {$ifdef windows}
  402. FDS := Default(TFDSet);
  403. FD_Zero(FDS);
  404. FD_Set(FSocket.Handle, FDS);
  405. {$ENDIF}
  406. PFDS:=@FDS;
  407. end
  408. end;
  409. Procedure CheckSet(var FDS : TFDSet; aState : TSocketState);
  410. begin
  411. if aState in aCheck then
  412. begin
  413. {$ifdef unix}
  414. if fpFD_IsSet(FSocket.Handle, FDS)>0 then
  415. Include(Result,aState);
  416. {$endif}
  417. {$ifdef windows}
  418. if FD_IsSet(FSocket.Handle, FDS) then
  419. Include(Result,aState);
  420. {$endif}
  421. end;
  422. end;
  423. {$endif}
  424. begin
  425. Result:=[];
  426. {$if defined(unix) or defined(windows)}
  427. Res:=-1;
  428. if Timeout<0 then
  429. PTV:=Nil
  430. else
  431. begin
  432. TimeV.tv_usec := (TimeOut mod 1000) * 1000;
  433. TimeV.tv_sec := TimeOut div 1000;
  434. PTV:=@TimeV;
  435. end;
  436. DoSet(FDSR,PFDSR,sosCanRead);
  437. DoSet(FDSW,PFDSW,sosCanWrite);
  438. DoSet(FDSE,PFDSE,sosException);
  439. {$endif}
  440. {$ifdef unix}
  441. Res:=fpSelect(Socket.Handle + 1, PFDSR, PFDSW, PFDSE, PTV);
  442. {$endif}
  443. {$ifdef windows}
  444. Res:={$IFDEF FPC_DOTTEDUNITS}WinApi.{$ENDIF}Winsock2.Select(Socket.Handle + 1, PFDSR, PFDSW, PFDSE, @TimeV);
  445. {$endif}
  446. {$if defined(unix) or defined(windows)}
  447. if Res>0 then
  448. begin
  449. CheckSet(FDSR,sosCanRead);
  450. CheckSet(FDSW,sosCanWrite);
  451. CheckSet(FDSE,sosException);
  452. end;
  453. if Res<0 then
  454. FLastError:=SocketError
  455. else
  456. FLastError:=0;
  457. {$else}
  458. FLastError:=0;
  459. {$endif}
  460. end;
  461. function TSocketHandler.CanRead(TimeOut : Integer): Boolean;
  462. begin
  463. Result:=Select([sosCanRead],Timeout)<>[];
  464. end;
  465. function TSocketHandler.Recv(Const Buffer; Count: Integer): Integer;
  466. Var
  467. Flags : longint;
  468. begin
  469. Flags:=Socket.FReadFlags;
  470. {$ifdef unix}
  471. FLastError:=ESysEINTR;
  472. While (FlastError=ESysEINTR) do
  473. {$endif}
  474. begin
  475. Result:=fprecv(Socket.Handle,@Buffer,count,flags);
  476. If (Result<0) then
  477. FLastError:=SocketError
  478. else
  479. FLastError:=0;
  480. end;
  481. end;
  482. function TSocketHandler.Send(Const Buffer; Count: Integer): Integer;
  483. Var
  484. Flags : longint;
  485. begin
  486. Flags:=FSocket.FWriteFlags;
  487. {$ifdef unix}
  488. FLastError:=ESysEINTR;
  489. While (FlastError=ESysEINTR) do
  490. {$endif}
  491. begin
  492. Result:=fpsend(Socket.Handle,@Buffer,count,flags);
  493. If Result<0 then
  494. FLastError:=SocketError
  495. else
  496. FlastError:=0;
  497. end;
  498. end;
  499. function TSocketHandler.BytesAvailable: Integer;
  500. begin
  501. Result:=0;
  502. { we need ioctlsocket here }
  503. end;
  504. function TSocketHandler.GetLastErrorDescription: String;
  505. begin
  506. Result:='';
  507. end;
  508. Function TSocketHandler.Close: Boolean;
  509. begin
  510. Result:=True;
  511. end;
  512. constructor ESocketError.Create(ACode: TSocketErrorType; const MsgArgs: array of const);
  513. var
  514. s: String;
  515. begin
  516. Code := ACode;
  517. case ACode of
  518. seHostNotFound : s := strHostNotFound;
  519. seCreationFailed : s := strSocketCreationFailed;
  520. seBindFailed : s := strSocketBindFailed;
  521. seListenFailed : s := strSocketListenFailed;
  522. seConnectFailed : s := strSocketConnectFailed;
  523. seAcceptFailed : s := strSocketAcceptFailed;
  524. seAcceptWouldBLock : S := strSocketAcceptWouldBlock;
  525. seIOTimeout : S := strSocketIOTimeOut;
  526. seConnectTimeOut : s := strSocketConnectTimeout;
  527. end;
  528. s := Format(s, MsgArgs);
  529. inherited Create(s);
  530. end;
  531. { ---------------------------------------------------------------------
  532. TSocketStream
  533. ---------------------------------------------------------------------}
  534. constructor TSocketStream.Create(AHandle: Longint; AHandler: TSocketHandler);
  535. begin
  536. Inherited Create(AHandle);
  537. FSocketInitialized := true;
  538. GetSockOptions;
  539. FHandler:=AHandler;
  540. If (FHandler=Nil) then
  541. FHandler:=TSocketHandler.Create;
  542. FHandler.SetSocket(Self);
  543. end;
  544. destructor TSocketStream.Destroy;
  545. begin
  546. Close;
  547. inherited Destroy;
  548. end;
  549. class function TSocketStream.Select(var aRead, aWrite,
  550. aExceptions: TSocketStreamArray; aTimeOut: Integer): Boolean;
  551. {$if defined(unix) or defined(windows)}
  552. var
  553. FDR,FDW,FDE: TFDSet;
  554. TimeV: TTimeVal;
  555. MaxHandle : Longint;
  556. Procedure FillFD(var FD : TFDSet; anArray : TSocketStreamArray);
  557. Var
  558. S : TSocketStream;
  559. begin
  560. FD := Default(TFDSet);
  561. {$ifdef unix}
  562. fpFD_Zero(FD);
  563. For S in AnArray do
  564. begin
  565. fpFD_Set(S.Handle, FD);
  566. if S.Handle>MaxHandle then
  567. MaxHandle:=S.Handle;
  568. end;
  569. {$ENDIF}
  570. {$ifdef windows}
  571. FD_Zero(FD);
  572. For S in AnArray do
  573. begin
  574. FD_Set(S.Handle, FD);
  575. if S.Handle>MaxHandle then
  576. MaxHandle:=S.Handle;
  577. end;
  578. {$ENDIF}
  579. end;
  580. function FillArr(FD : TFDSet; Src : TSocketStreamArray) : TSocketStreamArray;
  581. Var
  582. S : TSocketStream;
  583. aLen : Integer;
  584. begin
  585. Result:=nil;
  586. SetLength(Result,Length(Src));
  587. aLen:=0;
  588. For S in Src do
  589. begin
  590. {$IFDEF UNIX}
  591. if fpFD_IsSet(S.Handle, FD)>0 then
  592. {$ENDIF}
  593. {$IFDEF Windows}
  594. if FD_isSet(S.Handle, FD) then
  595. {$ENDIF}
  596. begin
  597. Result[aLen]:=S;
  598. Inc(aLen);
  599. end;
  600. end;
  601. SetLength(Result,aLen);
  602. end;
  603. {$ENDIF} // Unix or windows
  604. begin
  605. Result:=False;
  606. {$if defined(unix) or defined(windows)}
  607. MaxHandle:=0;
  608. TimeV.tv_usec := (aTimeOut mod 1000) * 1000;
  609. TimeV.tv_sec := aTimeOut div 1000;
  610. FillFD(FDR,aRead);
  611. FillFD(FDW,aWrite);
  612. FillFD(FDE,aExceptions);
  613. if MaxHandle=0 then
  614. exit;
  615. {$ifdef unix}
  616. Result := fpSelect(MaxHandle+1, @FDR, @FDW, @FDE, @TimeV) > 0;
  617. {$endif}
  618. {$ifdef windows}
  619. Result := {$IFDEF FPC_DOTTEDUNITS}WinApi.{$ENDIF}Winsock2.Select(MaxHandle+1, @FDR, @FDW, @FDE, @TimeV) > 0;
  620. {$endif}
  621. aRead:=FillArr(FDR,aRead);
  622. aWrite:=FillArr(FDR,aRead);
  623. aExceptions:=FillArr(FDR,aRead);
  624. {$ELSE} // Unix or windows
  625. aRead:=[];
  626. aWrite:=[];
  627. aExceptions:=[];
  628. {$ENDIF}
  629. end;
  630. procedure TSocketStream.Close;
  631. begin
  632. DoOnClose;
  633. if FSocketInitialized then
  634. FHandler.Close; // Ignore the result
  635. FSocketInitialized:=False;
  636. FreeAndNil(FHandler);
  637. CloseSocket(Handle);
  638. FClosed:=True;
  639. end;
  640. procedure TSocketStream.GetSockOptions;
  641. {$ifdef windows}
  642. var
  643. opt: DWord;
  644. olen: tsocklen;
  645. {$endif windows}
  646. {$ifdef unix}
  647. var
  648. time: ttimeval;
  649. olen: tsocklen;
  650. {$endif unix}
  651. begin
  652. {$ifdef windows}
  653. olen:=4;
  654. if fpgetsockopt(Handle, SOL_SOCKET, SO_RCVTIMEO, @opt, @olen) = 0 then
  655. FIOTimeout:=opt;
  656. {$endif windows}
  657. {$ifdef unix}
  658. olen:=sizeof(time);
  659. if fpgetsockopt(Handle, SOL_SOCKET, SO_RCVTIMEO, @time, @olen) = 0 then
  660. FIOTimeout:=(time.tv_sec*1000)+(time.tv_usec div 1000);
  661. {$endif}
  662. end;
  663. procedure TSocketStream.SetConnectTimeout(AValue: Integer);
  664. begin
  665. if FConnectTimeout = AValue then Exit;
  666. FConnectTimeout := AValue;
  667. end;
  668. function TSocketStream.GetLastError: Integer;
  669. begin
  670. Result:=FHandler.LastError;
  671. end;
  672. procedure TSocketStream.SetSocketOptions(Value: TSocketOptions);
  673. begin
  674. FSocketOptions:=Value;
  675. end;
  676. function TSocketStream.Seek(Offset: Longint; Origin: Word): Longint;
  677. begin
  678. Result:=0;
  679. end;
  680. function TSocketStream.Select(aCheck: TSocketStates; TimeOut: Integer): TSocketStates;
  681. begin
  682. Result:=FHandler.Select(aCheck,TimeOut);
  683. end;
  684. function TSocketStream.CanRead(TimeOut: Integer): Boolean;
  685. begin
  686. Result:=FHandler.CanRead(TimeOut);
  687. end;
  688. function TSocketStream.Read(var Buffer; Count: Longint): longint;
  689. begin
  690. Result:=FHandler.Recv(Buffer,Count);
  691. if (Result=0) then
  692. FPeerClosed:=True;
  693. end;
  694. function TSocketStream.Write(const Buffer; Count: Longint): Longint;
  695. begin
  696. Result:=FHandler.Send(Buffer,Count);
  697. end;
  698. function TSocketStream.GetLocalAddress: {$IFDEF FPC_DOTTEDUNITS}System.Net.{$ENDIF}sockets.TSockAddr;
  699. var
  700. len: LongInt;
  701. begin
  702. len := SizeOf({$IFDEF FPC_DOTTEDUNITS}System.Net.{$ENDIF}sockets.TSockAddr);
  703. if fpGetSockName(Handle, @Result, @len) <> 0 then
  704. FillChar(Result, SizeOf(Result), 0);
  705. end;
  706. function TSocketStream.GetRemoteAddress: {$IFDEF FPC_DOTTEDUNITS}System.Net.{$ENDIF}sockets.TSockAddr;
  707. var
  708. len: LongInt;
  709. begin
  710. len := SizeOf({$IFDEF FPC_DOTTEDUNITS}System.Net.{$ENDIF}sockets.TSockAddr);
  711. if fpGetPeerName(Handle, @Result, @len) <> 0 then
  712. FillChar(Result, SizeOf(Result), 0);
  713. end;
  714. procedure TSocketStream.SetIOTimeout(AValue: Integer);
  715. Var
  716. E : Boolean;
  717. {$ifdef windows}
  718. opt: DWord;
  719. {$endif windows}
  720. {$ifdef unix}
  721. time: ttimeval;
  722. {$endif unix}
  723. begin
  724. E:=False;
  725. if FIOTimeout=AValue then Exit;
  726. FIOTimeout:=AValue;
  727. {$ifdef windows}
  728. opt := AValue;
  729. E:=fpsetsockopt(Handle, SOL_SOCKET, SO_RCVTIMEO, @opt, 4)<>0;
  730. if not E then
  731. E:=fpsetsockopt(Handle, SOL_SOCKET, SO_SNDTIMEO, @opt, 4)<>0;
  732. {$endif windows}
  733. {$ifdef unix}
  734. time.tv_sec:=avalue div 1000;
  735. time.tv_usec:=(avalue mod 1000) * 1000;
  736. E:=fpsetsockopt(Handle, SOL_SOCKET, SO_RCVTIMEO, @time, sizeof(time))<>0;
  737. if not E then
  738. E:=fpsetsockopt(Handle, SOL_SOCKET, SO_SNDTIMEO, @time, sizeof(time))<>0;
  739. {$endif}
  740. if E then
  741. Raise ESocketError.Create(seIOTimeout,[AValue]);
  742. end;
  743. procedure TSocketStream.DoOnClose;
  744. begin
  745. If Assigned(FOnClose) then
  746. FOnClose(Self);
  747. end;
  748. { ---------------------------------------------------------------------
  749. TSocketServer
  750. ---------------------------------------------------------------------}
  751. constructor TSocketServer.Create(ASocket: Longint; AHandler: TSocketHandler);
  752. begin
  753. FSocket:=ASocket;
  754. FQueueSize :=5;
  755. FMaxConnections:=-1;
  756. if (AHandler=Nil) then
  757. AHandler:=TSocketHandler.Create;
  758. FHandler:=AHandler;
  759. FConnections:=TThreadList.Create;
  760. end;
  761. destructor TSocketServer.Destroy;
  762. begin
  763. RemoveSelfFromConnections;
  764. FreeAndNil(FConnections);
  765. Close;
  766. FreeAndNil(FHandler);
  767. Inherited;
  768. end;
  769. procedure TSocketServer.Close;
  770. begin
  771. If FSocket<>-1 Then
  772. CloseSocket(FSocket);
  773. FSocket:=-1;
  774. end;
  775. procedure TSocketServer.Abort;
  776. {$if defined(unix) or defined(mswindows) or defined(hasamiga)}
  777. {$else}
  778. var
  779. ASocket: longint;
  780. {$endif}
  781. begin
  782. {$if defined(unix)}
  783. fpShutdown(FSocket,SHUT_RDWR);
  784. {$elseif defined(mswindows) or defined(hasamiga)}
  785. CloseSocket(FSocket);
  786. {$else}
  787. {$WARNING Method Abort is not tested on this platform!}
  788. ASocket:=FSocket;
  789. fpShutdown(ASocket,SHUT_RDWR);
  790. CloseSocket(ASocket);
  791. {$endif}
  792. end;
  793. procedure TSocketServer.RemoveSelfFromConnections;
  794. Var
  795. L : TList;
  796. P: Pointer;
  797. begin
  798. L:=FConnections.LockList;
  799. try
  800. for P in L do
  801. TServerSocketStream(P).FServer:=Nil;
  802. finally
  803. FConnections.UnlockList;
  804. end;
  805. end;
  806. function TSocketServer.RunIdleLoop: Boolean;
  807. // Run Accept idle loop. Return True if there is a new connection waiting
  808. {$if defined(unix) or defined(windows)}
  809. var
  810. FDS: TFDSet;
  811. TimeV: TTimeVal;
  812. {$endif}
  813. begin
  814. Repeat
  815. Result:=False;
  816. {$if defined(unix) or defined(windows)}
  817. TimeV.tv_usec := (AcceptIdleTimeout mod 1000) * 1000;
  818. TimeV.tv_sec := AcceptIdleTimeout div 1000;
  819. {$endif}
  820. {$ifdef unix}
  821. FDS := Default(TFDSet);
  822. fpFD_Zero(FDS);
  823. fpFD_Set(FSocket, FDS);
  824. Result := fpSelect(FSocket + 1, @FDS, @FDS, @FDS, @TimeV) > 0;
  825. {$else}
  826. {$ifdef windows}
  827. FDS := Default(TFDSet);
  828. FD_Zero(FDS);
  829. FD_Set(FSocket, FDS);
  830. Result := {$IFDEF FPC_DOTTEDUNITS}WinApi.{$ENDIF}Winsock2.Select(FSocket + 1, @FDS, @FDS, @FDS, @TimeV) > 0;
  831. {$endif}
  832. {$endif}
  833. If Result then
  834. break;
  835. DoOnIdle;
  836. Until (Not FAccepting);
  837. end;
  838. procedure TSocketServer.Listen;
  839. begin
  840. If Not FBound then
  841. Bind;
  842. If {$IFDEF FPC_DOTTEDUNITS}System.Net.{$ENDIF}Sockets.FpListen(FSocket,FQueueSize)<>0 then
  843. Raise ESocketError.Create(seListenFailed,[FSocket,SocketError]);
  844. end;
  845. function TSocketServer.GetSockopt(ALevel, AOptName: cint; var optval;
  846. var optlen: tsocklen): Boolean;
  847. begin
  848. Result:=fpGetSockOpt(FSocket,ALevel,AOptName,@optval,@optlen)<>-1;
  849. end;
  850. function TSocketServer.SetSockopt(ALevel, AOptName: cint; var optval;
  851. optlen: tsocklen): Boolean;
  852. begin
  853. Result:=fpSetSockOpt(FSocket,ALevel,AOptName,@optval,optlen)<>-1;
  854. end;
  855. function TInetServer.GetConnection: TSocketStream;
  856. var
  857. NewSocket : longint;
  858. begin
  859. Result:=Nil;
  860. NewSocket:=Accept;
  861. if (NewSocket<0) then
  862. if not FAccepting then
  863. exit
  864. else
  865. Raise ESocketError.Create(seAcceptFailed,[Socket,SocketError]);
  866. If FAccepting and DoConnectQuery(NewSocket) Then
  867. Result:=SockToStream(NewSocket)
  868. else
  869. CloseSocket(NewSocket);
  870. end;
  871. function TSocketServer.HandleAcceptError(E: ESocketError): TAcceptErrorAction;
  872. begin
  873. if FAccepting then
  874. Result:=aeaRaise
  875. else
  876. Result:=aeaStop;
  877. if Assigned(FOnAcceptError) then
  878. FOnAcceptError(Self,FSocket,E,Result);
  879. end;
  880. function TSocketServer.GetClientSocketHandler(aSocket : Longint): TSocketHandler;
  881. begin
  882. If Assigned(FOnCreateClientSocketHandler) then
  883. FOnCreateClientSocketHandler(Self,Result)
  884. else
  885. if Assigned(FHandler) then
  886. Result:=TSocketHandlerClass(FHandler.ClassType).Create;
  887. end;
  888. procedure TSocketServer.StartAccepting;
  889. Var
  890. NoConnections : Integer;
  891. Stream : TSocketStream;
  892. begin
  893. FAccepting := True;
  894. NoConnections := 0;
  895. Listen;
  896. Repeat
  897. Repeat
  898. Stream:=Nil;
  899. Try
  900. If (AcceptIdleTimeOut=0) or RunIdleLoop then
  901. Stream:=GetConnection;
  902. if Assigned(Stream) then
  903. if (MaxSimultaneousConnections>0) and (ConnectionCount>=MaxSimultaneousConnections) then
  904. begin
  905. Stream.Close;
  906. DoConnectionDropped(Stream);
  907. FreeAndNil(Stream);
  908. end
  909. else
  910. begin
  911. if Stream is TServerSocketStream then
  912. begin
  913. FConnections.Add(Stream);
  914. TServerSocketStream(Stream).FServer:=Self;
  915. end;
  916. Inc(NoConnections);
  917. DoConnect(Stream);
  918. end;
  919. except
  920. On E : ESocketError do
  921. begin
  922. If E.Code=seAcceptWouldBlock then
  923. DoOnIdle
  924. else
  925. Case HandleAcceptError(E) of
  926. aeaIgnore : ;
  927. aeaStop : FAccepting:=False;
  928. aeaRaise : Raise;
  929. end;
  930. end;
  931. end;
  932. Until (Stream<>Nil) or (Not NonBlocking);
  933. Until Not (FAccepting) or ((FMaxConnections<>-1) and (NoConnections>=FMaxConnections));
  934. end;
  935. procedure TSocketServer.StopAccepting(DoAbort: Boolean = False);
  936. begin
  937. FAccepting:=False;
  938. If DoAbort then
  939. Abort;
  940. end;
  941. procedure TSocketServer.DoOnIdle;
  942. begin
  943. If Assigned(FOnIdle) then
  944. FOnIdle(Self);
  945. end;
  946. function TSocketServer.GetConnectionCount: Integer;
  947. Var
  948. L : TList;
  949. begin
  950. L:=FConnections.LockList;
  951. try
  952. Result:=L.Count;
  953. finally
  954. FConnections.UnlockList;
  955. end;
  956. end;
  957. function TSocketServer.GetReuseAddress: Boolean;
  958. Var
  959. L : cint;
  960. ls : Tsocklen;
  961. begin
  962. L:=0;
  963. ls:=0;
  964. {$IFDEF UNIX}
  965. if not GetSockOpt(SOL_SOCKET, SO_REUSEADDR, L, LS) then
  966. Raise ESocketError.CreateFmt('Failed to get SO_REUSEADDR to %d: %d',[l,socketerror]);
  967. Result:=(L<>0);
  968. {$ELSE}
  969. Result:=True;
  970. {$ENDIF}
  971. end;
  972. function TSocketServer.GetKeepAlive: Boolean;
  973. Var
  974. L : cint;
  975. ls : Tsocklen;
  976. begin
  977. L:=0;
  978. ls:=0;
  979. {$IFDEF UNIX}
  980. if Not GetSockOpt(SOL_SOCKET, SO_KEEPALIVE, L, LS) then
  981. Raise ESocketError.CreateFmt('Failed to get SO_KEEPALIVE: %d',[socketerror]);
  982. Result:=(L<>0);
  983. {$ELSE}
  984. Result:=True;
  985. {$ENDIF}
  986. end;
  987. function TSocketServer.GetLinger: Integer;
  988. Var
  989. L : linger;
  990. ls : tsocklen;
  991. begin
  992. L.l_onoff:=0;
  993. l.l_linger:=0;
  994. if Not GetSockOpt(SOL_SOCKET, SO_LINGER, l, ls) then
  995. Raise ESocketError.CreateFmt('Failed to set linger: %d',[socketerror]);
  996. if l.l_onoff=0 then
  997. Result:=-1
  998. else
  999. Result:=l.l_linger;
  1000. end;
  1001. procedure TSocketServer.DoConnect(ASocket: TSocketStream);
  1002. begin
  1003. If Assigned(FOnConnect) Then
  1004. FOnConnect(Self,ASocket);
  1005. end;
  1006. function TSocketServer.DoConnectQuery(ASocket: longint): Boolean;
  1007. begin
  1008. Result:=True;
  1009. If Assigned(FOnConnectQuery) then
  1010. FOnConnectQuery(Self,ASocket,Result);
  1011. end;
  1012. procedure TSocketServer.SetNonBlocking;
  1013. begin
  1014. {$ifdef Unix}
  1015. fpfcntl(FSocket,F_SETFL,O_NONBLOCK);
  1016. {$endif}
  1017. FNonBlocking:=True;
  1018. end;
  1019. procedure TSocketServer.Foreach(aHandler: TForeachHandler);
  1020. Var
  1021. L : TList;
  1022. P : Pointer;
  1023. aContinue : Boolean;
  1024. begin
  1025. L:=FConnections.LockList;
  1026. try
  1027. aContinue:=True;
  1028. For P in L do
  1029. begin
  1030. aHandler(Self,TSocketStream(P),aContinue);
  1031. if not aContinue then
  1032. break;
  1033. end;
  1034. finally
  1035. FConnections.UnlockList;
  1036. end;
  1037. end;
  1038. procedure TSocketServer.SetLinger(ALinger: Integer);
  1039. Var
  1040. L : linger;
  1041. begin
  1042. L.l_onoff:=Ord(ALinger>0);
  1043. if ALinger<0 then
  1044. l.l_linger:=ALinger
  1045. else
  1046. l.l_linger:=0;
  1047. if Not SetSockOpt(SOL_SOCKET, SO_LINGER, l, SizeOf(L)) then
  1048. Raise ESocketError.CreateFmt('Failed to set linger: %d',[socketerror]);
  1049. end;
  1050. procedure TSocketServer.SocketClosed(aSocket: TSocketStream);
  1051. begin
  1052. FConnections.Remove(aSocket);
  1053. DoDisConnect(aSocket);
  1054. end;
  1055. procedure TSocketServer.DoConnectionDropped(aSocket: TSocketStream);
  1056. begin
  1057. If Assigned(FOnConnectionDropped) then
  1058. FOnConnectionDropped(Self,aSocket);
  1059. end;
  1060. procedure TSocketServer.DoDisconnect(aSocket: TSocketStream);
  1061. begin
  1062. If Assigned(FOnDisconnect) then
  1063. FOnDisconnect(Self,aSocket);
  1064. end;
  1065. procedure TSocketServer.SetReuseAddress(AValue: Boolean);
  1066. Var
  1067. L : cint;
  1068. begin
  1069. L:=Ord(AValue);
  1070. {$IFDEF UNIX}
  1071. if not SetSockOpt(SOL_SOCKET, SO_REUSEADDR , L, SizeOf(L)) then
  1072. Raise ESocketError.CreateFmt('Failed to set SO_REUSEADDR to %d: %d',[l,socketerror]);
  1073. {$ENDIF}
  1074. end;
  1075. procedure TSocketServer.SetKeepAlive(AValue: Boolean);
  1076. Var
  1077. L : cint;
  1078. begin
  1079. L:=Ord(AValue);
  1080. {$IFDEF UNIX}
  1081. if Not SetSockOpt(SOL_SOCKET, SO_KEEPALIVE, L, SizeOf(L)) then
  1082. Raise ESocketError.CreateFmt('Failed to set SO_REUSEADDR to %d: %d',[l,socketerror]);
  1083. {$ENDIF}
  1084. end;
  1085. { ---------------------------------------------------------------------
  1086. TInetServer
  1087. ---------------------------------------------------------------------}
  1088. constructor TInetServer.Create(APort: Word);
  1089. begin
  1090. Create('0.0.0.0', aPort);
  1091. end;
  1092. constructor TInetServer.Create(const aHost: string; const APort: Word;
  1093. AHandler: TSocketHandler);
  1094. Var S : longint;
  1095. begin
  1096. FHost:=aHost;
  1097. FPort:=APort;
  1098. S:={$IFDEF FPC_DOTTEDUNITS}System.Net.{$ENDIF}Sockets.FpSocket(AF_INET,SOCK_STREAM,0);
  1099. If S=-1 Then
  1100. Raise ESocketError.Create(seCreationFailed,[Format('%d',[APort])]);
  1101. Inherited Create(S,AHandler);
  1102. end;
  1103. procedure TInetServer.Bind;
  1104. begin
  1105. Faddr.sin_family := AF_INET;
  1106. Faddr.sin_port := ShortHostToNet(FPort);
  1107. Faddr.sin_addr.s_addr := LongWord(StrToNetAddr(FHost));
  1108. if {$IFDEF FPC_DOTTEDUNITS}System.Net.{$ENDIF}Sockets.fpBind(FSocket, @FAddr, Sizeof(FAddr))<>0 then
  1109. raise ESocketError.Create(seBindFailed, [IntToStr(FPort)]);
  1110. FBound:=True;
  1111. end;
  1112. function TInetServer.SockToStream(ASocket: Longint): TSocketStream;
  1113. Var
  1114. H : TSocketHandler;
  1115. ok : Boolean;
  1116. aClass : TInetSocketClass;
  1117. procedure ShutDownH;
  1118. begin
  1119. H.Shutdown(False);
  1120. FreeAndNil(Result);
  1121. end;
  1122. begin
  1123. H:=GetClientSocketHandler(aSocket);
  1124. aClass:=DefaultInetSocketClass;
  1125. // Should be: Result:=TServerSocketStream.Create(ASocket,H);
  1126. if aClass=Nil then
  1127. aClass:=TInetSocket;
  1128. Result:=aClass.Create(ASocket,H);
  1129. (Result as TInetSocket).FHost:='';
  1130. (Result as TInetSocket).FPort:=FPort;
  1131. ok:=false;
  1132. try
  1133. ok:=H.Accept;
  1134. finally
  1135. if not ok then
  1136. ShutDownH;
  1137. end;
  1138. end;
  1139. function TInetServer.Accept: Longint;
  1140. Var
  1141. L : longint;
  1142. R : integer;
  1143. begin
  1144. L:=SizeOf(FAddr);
  1145. {$IFDEF UNIX}
  1146. R:=ESysEINTR;
  1147. While (R=ESysEINTR) do
  1148. {$ENDIF UNIX}
  1149. begin
  1150. Result:={$IFDEF FPC_DOTTEDUNITS}System.Net.{$ENDIF}Sockets.fpAccept(Socket,@Faddr,@L);
  1151. R:=SocketError;
  1152. end;
  1153. {$ifdef Unix}
  1154. If (Result<0) then
  1155. If R=ESysEWOULDBLOCK then
  1156. Raise ESocketError.Create(seAcceptWouldBlock,[socket]);
  1157. {$endif}
  1158. if (Result<0) or Not FAccepting then
  1159. begin
  1160. If (Result>=0) then
  1161. CloseSocket(Result);
  1162. // Do not raise an error if we've stopped accepting.
  1163. if FAccepting then
  1164. Raise ESocketError.Create(seAcceptFailed,[Socket,SocketError])
  1165. end;
  1166. end;
  1167. { ---------------------------------------------------------------------
  1168. TUnixServer
  1169. ---------------------------------------------------------------------}
  1170. {$ifdef Unix}
  1171. Constructor TUnixServer.Create(const AFileName : String; AHandler : TSocketHandler = Nil);
  1172. Var S : Longint;
  1173. begin
  1174. FFileName:=AFileName;
  1175. S:={$IFDEF FPC_DOTTEDUNITS}System.Net.{$ENDIF}Sockets.fpSocket(AF_UNIX,SOCK_STREAM,0);
  1176. If S=-1 then
  1177. Raise ESocketError.Create(seCreationFailed,[AFileName])
  1178. else
  1179. Inherited Create(S,AHandler);
  1180. end;
  1181. Procedure TUnixServer.Close;
  1182. begin
  1183. Inherited Close;
  1184. DeleteFile(FFileName);
  1185. FFileName:='';
  1186. end;
  1187. Procedure TUnixServer.Bind;
  1188. var
  1189. AddrLen : longint;
  1190. begin
  1191. Str2UnixSockAddr(FFilename,FUnixAddr,AddrLen);
  1192. If {$IFDEF FPC_DOTTEDUNITS}System.Net.{$ENDIF}Sockets.FpBind(Socket,@FUnixAddr,AddrLen)<>0 then
  1193. Raise ESocketError.Create(seBindFailed,[FFileName]);
  1194. FBound:=True;
  1195. end;
  1196. Function TUnixServer.Accept : Longint;
  1197. Var L : longint;
  1198. begin
  1199. L:=Length(FFileName);
  1200. Result:={$IFDEF FPC_DOTTEDUNITS}System.Net.{$ENDIF}Sockets.fpAccept(Socket,@FUnixAddr,@L);
  1201. If Result<0 then
  1202. If SocketError=ESysEWOULDBLOCK then
  1203. Raise ESocketError.Create(seAcceptWouldBlock,[socket])
  1204. else
  1205. Raise ESocketError.Create(seAcceptFailed,[socket,SocketError]);
  1206. end;
  1207. Function TUnixServer.SockToStream (ASocket : Longint) : TSocketStream;
  1208. var
  1209. aClass : TUnixSocketClass;
  1210. begin
  1211. aClass:=DefaultUnixSocketClass;
  1212. if aClass=Nil then
  1213. aClass:=TUnixSocket;
  1214. Result:=aClass.Create(ASocket);
  1215. (Result as TUnixSocket).FFileName:=FFileName;
  1216. end;
  1217. Function TUnixServer.GetConnection : TSocketStream;
  1218. var
  1219. NewSocket : longint;
  1220. begin
  1221. Result:=Nil;
  1222. NewSocket:=Accept;
  1223. if (NewSocket<0) then
  1224. Raise ESocketError.Create(seAcceptFailed,[Socket,SocketError]);
  1225. If FAccepting and DoConnectQuery(NewSocket) Then
  1226. Result:=SockToStream(NewSocket)
  1227. else
  1228. CloseSocket(NewSocket);
  1229. end;
  1230. {$endif}
  1231. { ---------------------------------------------------------------------
  1232. TInetSocket
  1233. ---------------------------------------------------------------------}
  1234. Constructor TInetSocket.Create(const AHost: String; APort: Word;AHandler : TSocketHandler = Nil);
  1235. begin
  1236. Create(AHost,aPort,0,AHandler);
  1237. end;
  1238. Constructor TInetSocket.Create(const AHost: String; APort: Word; aConnectTimeout : Integer; AHandler : TSocketHandler = Nil);
  1239. Var
  1240. S : Longint;
  1241. begin
  1242. FHost:=AHost;
  1243. FPort:=APort;
  1244. ConnectTimeout:=aConnectTimeout;
  1245. S:=fpSocket(AF_INET,SOCK_STREAM,0);
  1246. Inherited Create(S,AHandler);
  1247. if (AHandler=Nil) then // Backwards compatible behaviour.
  1248. Connect;
  1249. end;
  1250. {$IFDEF HAVENONBLOCKING}
  1251. function TInetSocket.SetSocketBlockingMode(ASocket: cint; ABlockMode: TBlockingMode; AFDSPtr: Pointer): Boolean;
  1252. Const
  1253. BlockingModes : Array[TBlockingMode] of DWord =
  1254. (SocketBlockingMode, SocketNonBlockingMode);
  1255. var
  1256. locFDS: PFDSet;
  1257. {$ifdef unix}
  1258. flags: Integer;
  1259. {$endif}
  1260. begin
  1261. locFDS := PFDSet(AFDSPtr);
  1262. if (AblockMode = bmNonBlocking) then
  1263. begin
  1264. {$ifdef unix}
  1265. locFDS^ := Default(TFDSet);
  1266. fpFD_Zero(locFDS^);
  1267. fpFD_Set(ASocket, locFDS^);
  1268. {$else}
  1269. {$ifdef windows}
  1270. locFDS^ := Default(TFDSet);
  1271. FD_Zero(locFDS^);
  1272. FD_Set(ASocket, locFDS^);
  1273. {$endif}
  1274. {$endif}
  1275. end;
  1276. {$ifdef unix}
  1277. flags := FpFcntl(ASocket, F_GetFl, 0);
  1278. if (AblockMode = bmNonBlocking) then
  1279. result := FpFcntl(ASocket, F_SetFl, flags or O_NONBLOCK) = 0
  1280. else
  1281. result := FpFcntl(ASocket, F_SetFl, flags and (not O_NONBLOCK)) = 0;
  1282. {$endif}
  1283. {$ifdef windows}
  1284. result := ioctlsocket(ASocket,longint(FIONBIO),@ABlockMode) = 0;
  1285. {$endif}
  1286. end;
  1287. // Return true if a timeout happened. Will only be called in case of eWouldBlock.
  1288. function TInetSocket.CheckSocketConnectTimeout(ASocket: cint; AFDSPtr: Pointer; ATimeVPtr: Pointer): TCheckTimeoutResult;
  1289. var
  1290. Err,ErrLen : Longint;
  1291. Res : LongInt;
  1292. locTimeVal: PTimeVal;
  1293. locFDS: PFDSet;
  1294. begin
  1295. locTimeVal := PTimeVal(ATimeVPtr);
  1296. locFDS := PFDSet(AFDSPtr);
  1297. locTimeVal^.tv_usec := (FConnectTimeout mod 1000) * 1000;
  1298. locTimeVal^.tv_sec := FConnectTimeout div 1000;
  1299. Res:=-1;
  1300. {$ifdef unix}
  1301. Res:=fpSelect(ASocket + 1, nil, locFDS, nil, locTimeVal); // 0 -> TimeOut
  1302. {$ENDIF}
  1303. {$ifdef windows}
  1304. Res:={$IFDEF FPC_DOTTEDUNITS}WinApi.{$ENDIF}Winsock2.select(ASocket + 1, nil, locFDS, nil, locTimeVal); // 0 -> TimeOut
  1305. {$ENDIF}
  1306. if (Res=0) then
  1307. Result:=ctrTimeout
  1308. else if (Res<0) then
  1309. Result:=ctrError
  1310. else if (Res>0) then
  1311. begin
  1312. Result:=ctrError;
  1313. ErrLen := SizeOf(Err);
  1314. {$ifdef unix}
  1315. if fpFD_ISSET(ASocket, locFDS^)=1 then
  1316. {$ENDIF}
  1317. {$ifdef windows}
  1318. if FD_ISSET(ASocket, locFDS^) then
  1319. {$ENDIF}
  1320. begin
  1321. fpGetSockOpt(ASocket, SOL_SOCKET, SO_ERROR, @Err, @ErrLen);
  1322. if Err=0 then // 0 -> connected
  1323. Result:=ctrOK
  1324. end;
  1325. end;
  1326. end;
  1327. {$ENDIF HAVENONBLOCKING}
  1328. procedure TInetSocket.Connect;
  1329. {$IFDEF HAVENONBLOCKING}
  1330. Const
  1331. {$IFDEF UNIX}
  1332. ErrWouldBlock = ESysEInprogress;
  1333. {$ELSE}
  1334. ErrWouldBlock = WSAEWOULDBLOCK;
  1335. {$ENDIF}
  1336. {$ENDIF}
  1337. Var
  1338. A : THostAddr;
  1339. addr: TInetSockAddr;
  1340. IsError : Boolean;
  1341. TimeOutResult : TCheckTimeOutResult;
  1342. Err: Integer;
  1343. aErrMsg : String;
  1344. {$IFDEF HAVENONBLOCKING}
  1345. FDS: TFDSet;
  1346. TimeV: TTimeVal;
  1347. {$endif}
  1348. begin
  1349. A := StrToHostAddr(FHost);
  1350. if A.s_bytes[1] = 0 then
  1351. With THostResolver.Create(Nil) do
  1352. try
  1353. If Not NameLookup(FHost) then
  1354. raise ESocketError.Create(seHostNotFound, [FHost]);
  1355. A:=HostAddress;
  1356. finally
  1357. free;
  1358. end;
  1359. addr.sin_family := AF_INET;
  1360. addr.sin_port := ShortHostToNet(FPort);
  1361. addr.sin_addr.s_addr := HostToNet(a.s_addr);
  1362. {$IFDEF HAVENONBLOCKING}
  1363. if ConnectTimeOut>0 then
  1364. SetSocketBlockingMode(Handle, bmNonBlocking, @FDS) ;
  1365. {$ENDIF}
  1366. IsError:=True;
  1367. TimeOutResult:=ctrError;
  1368. {$ifdef unix}
  1369. Err:=ESysEINTR;
  1370. While IsError and ((Err=ESysEINTR) or (Err=ESysEAGAIN)) do
  1371. {$endif}
  1372. begin
  1373. IsError:=fpConnect(Handle, @addr, sizeof(addr))<>0;
  1374. if IsError then
  1375. Err:=Socketerror;
  1376. end;
  1377. {$IFDEF HAVENONBLOCKING}
  1378. if (ConnectTimeOut>0) then
  1379. begin
  1380. if IsError and (Err=ErrWouldBlock) then
  1381. begin
  1382. TimeOutResult:=CheckSocketConnectTimeout(Handle, @FDS, @TimeV);
  1383. IsError:=(TimeOutResult<>ctrOK);
  1384. end;
  1385. SetSocketBlockingMode(Handle, bmBlocking, @FDS);
  1386. end;
  1387. {$ENDIF}
  1388. If Not IsError then
  1389. begin
  1390. IsError:=Not FHandler.Connect;
  1391. if IsError then
  1392. CloseSocket(Handle);
  1393. end;
  1394. If IsError then
  1395. if TimeoutResult=ctrTimeout then
  1396. Raise ESocketError.Create(seConnectTimeOut, [Format('%s:%d',[FHost, FPort])])
  1397. else
  1398. begin
  1399. aErrMsg:=FHandler.GetLastErrorDescription;
  1400. Raise ESocketError.Create(seConnectFailed, [Format('%s:%d',[FHost, FPort]),aErrMsg]);
  1401. end;
  1402. end;
  1403. { ---------------------------------------------------------------------
  1404. TUnixSocket
  1405. ---------------------------------------------------------------------}
  1406. {$ifdef Unix}
  1407. Constructor TUnixSocket.Create(ASocket : Longint);
  1408. begin
  1409. Inherited Create(ASocket);
  1410. end;
  1411. Constructor TUnixSocket.Create(const AFileName : String);
  1412. Var S : Longint;
  1413. begin
  1414. FFileName:=AFileName;
  1415. S:=FpSocket(AF_UNIX,SOCK_STREAM,0);
  1416. DoConnect(S);
  1417. Inherited Create(S);
  1418. end;
  1419. Procedure TUnixSocket.DoConnect(ASocket : longint);
  1420. Var
  1421. UnixAddr : TUnixSockAddr;
  1422. AddrLen : longint;
  1423. begin
  1424. Str2UnixSockAddr(FFilename,UnixAddr,AddrLen);
  1425. If FpConnect(ASocket,@UnixAddr,AddrLen)<>0 then
  1426. Raise ESocketError.Create(seConnectFailed,[FFilename,'']);
  1427. end;
  1428. {$endif}
  1429. end.