ssockets.pp 42 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642
  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. TServerSocketStream = class;
  45. TInetSocket = Class;
  46. {$IFDEF UNIX}
  47. TUnixSocket = class;
  48. TUnixSocketClass = Class of TUnixSocket;
  49. {$ENDIF}
  50. TSocketStreamClass = Class of TSocketStream;
  51. TInetSocketClass = Class of TInetSocket;
  52. TServerSocketStreamClass = Class of TServerSocketStream;
  53. // Handles all OS calls
  54. { TSocketHandler }
  55. TSocketState = (sosCanread,sosCanWrite,sosException);
  56. TSocketStates = Set of TSocketState;
  57. TSocketHandler = Class(TObject)
  58. Private
  59. FSocket: TSocketStream;
  60. Protected
  61. FLastError : integer;
  62. Procedure SetSocket(const AStream: TSocketStream); virtual;
  63. Procedure CheckSocket;
  64. Public
  65. constructor Create; virtual;
  66. // Called after the connect call succeded. Returns True to continue, false to close connection.
  67. function Connect: boolean; virtual;
  68. // Called after the accept call succeded on the NEW client socket
  69. function Accept : Boolean; virtual;
  70. Function Close : Boolean; virtual;
  71. function Shutdown(BiDirectional : Boolean): boolean; virtual;
  72. function Select(aCheck : TSocketStates; TimeOut : Integer): TSocketStates; virtual;
  73. function CanRead(TimeOut : Integer): Boolean; virtual;
  74. function Recv(Const Buffer; Count: Integer): Integer; virtual;
  75. function Send(Const Buffer; Count: Integer): Integer; virtual;
  76. function BytesAvailable: Integer; virtual;
  77. // Call this to get extra error info.
  78. Function GetLastErrorDescription : String; virtual;
  79. Property Socket : TSocketStream Read FSocket;
  80. Property LastError : Integer Read FLastError;
  81. end;
  82. TSocketHandlerClass = Class of TSocketHandler;
  83. { TSocketStream }
  84. TSocketStreamArray = Array of TSocketStream;
  85. TSocketStream = class(THandleStream)
  86. Private
  87. FClosed: Boolean;
  88. FOnClose: TNotifyEvent;
  89. FPeerClosed: Boolean;
  90. FReadFlags: Integer;
  91. FSocketInitialized : Boolean;
  92. FSocketOptions : TSocketOptions;
  93. FWriteFlags: Integer;
  94. FHandler : TSocketHandler;
  95. FIOTimeout : Integer;
  96. FConnectTimeout : Integer;
  97. function GetLastError: Integer;
  98. Procedure GetSockOptions;
  99. procedure SetConnectTimeout(AValue: Integer);
  100. Procedure SetSocketOptions(Value : TSocketOptions);
  101. function GetLocalAddress: {$IFDEF FPC_DOTTEDUNITS}System.Net.{$ENDIF}Sockets.TSockAddr;
  102. function GetRemoteAddress: {$IFDEF FPC_DOTTEDUNITS}System.Net.{$ENDIF}Sockets.TSockAddr;
  103. procedure SetIOTimeout(AValue: Integer);
  104. Protected
  105. Procedure DoOnClose; virtual;
  106. Public
  107. Constructor Create (AHandle : Longint; AHandler : TSocketHandler = Nil);virtual;
  108. destructor Destroy; override;
  109. Class Function Select(Var aRead,aWrite,aExceptions : TSocketStreamArray; aTimeOut: Integer): Boolean; virtual;
  110. Procedure Close;
  111. function Seek(Offset: Longint; Origin: Word): Longint; override;
  112. function Select(aCheck : TSocketStates; TimeOut : Integer): TSocketStates;
  113. Function CanRead(TimeOut : Integer): Boolean; virtual;
  114. Function Read (Var Buffer; Count : Longint) : longint; Override;
  115. Function Write (Const Buffer; Count : Longint) :Longint; Override;
  116. Property SocketOptions : TSocketOptions Read FSocketOptions
  117. Write SetSocketOptions;
  118. property LocalAddress: {$IFDEF FPC_DOTTEDUNITS}System.Net.{$ENDIF}sockets.TSockAddr read GetLocalAddress;
  119. property RemoteAddress: {$IFDEF FPC_DOTTEDUNITS}System.Net.{$ENDIF}sockets.TSockAddr read GetRemoteAddress;
  120. Property LastError : Integer Read GetLastError;
  121. Property ReadFlags : Integer Read FReadFlags Write FReadFlags;
  122. Property WriteFlags : Integer Read FWriteFlags Write FWriteFlags;
  123. Property IOTimeout : Integer read FIOTimeout Write SetIOTimeout;
  124. Property ConnectTimeout : Integer read FConnectTimeout Write SetConnectTimeout;
  125. Property OnClose : TNotifyEvent Read FOnClose Write FOnClose;
  126. Property Handler : TSocketHandler Read FHandler;
  127. // We called close
  128. Property Closed : Boolean read FClosed;
  129. // Peer closed detected when reading.
  130. Property PeerClosed : Boolean Read FPeerClosed;
  131. end;
  132. TSocketClientEvent = Procedure (Sender : TObject; Data : TSocketStream) Of Object;
  133. TConnectEvent = TSocketClientEvent;
  134. TDisconnectEvent = TSocketClientEvent;
  135. TConnectionDroppedEvent = TSocketClientEvent;
  136. TConnectQuery = Procedure (Sender : TObject; ASocket : Longint; Var Allow : Boolean) of Object;
  137. TOnAcceptError = Procedure (Sender : TObject; ASocket : Longint; E : Exception; Var ErrorAction : TAcceptErrorAction) of Object;
  138. TGetClientSocketHandlerEvent = Procedure (Sender : TObject; Out AHandler : TSocketHandler) of object;
  139. TForeachHandler = Procedure (Sender : TObject; aClient : TSocketStream; var aContinue : Boolean) of object;
  140. { TSocketServer }
  141. TSocketServer = Class(TObject)
  142. Private
  143. FIdleTimeOut: Cardinal;
  144. FMaxSimultaneousConnections: longint;
  145. FOnAcceptError: TOnAcceptError;
  146. FOnConnectionDropped: TConnectionDroppedEvent;
  147. FOnCreateClientSocketHandler: TGetClientSocketHandlerEvent;
  148. FOnDisconnect: TDisconnectEvent;
  149. FOnIdle : TNotifyEvent;
  150. FNonBlocking : Boolean;
  151. FSocket : longint;
  152. FAccepting : Boolean;
  153. FMaxConnections : Longint;
  154. FQueueSize : Longint;
  155. FOnConnect : TConnectEvent;
  156. FOnConnectQuery : TConnectQuery;
  157. FHandler : TSocketHandler;
  158. FConnections : TThreadList;
  159. Procedure DoOnIdle;
  160. function GetConnectionCount: Integer;
  161. Function GetReuseAddress: Boolean;
  162. Function GetKeepAlive : Boolean;
  163. Function GetLinger : Integer;
  164. Procedure SetReuseAddress (AValue : Boolean);
  165. Procedure SetKeepAlive (AValue : Boolean);
  166. Procedure SetLinger(ALinger : Integer);
  167. Protected
  168. FSockType : Longint;
  169. FBound : Boolean;
  170. Procedure SocketClosed(aSocket: TSocketStream);
  171. Procedure DoConnectionDropped(aSocket : TSocketStream); virtual;
  172. Procedure DoDisconnect(aSocket : TSocketStream); virtual;
  173. Procedure DoConnect(ASocket : TSocketStream); Virtual;
  174. Function DoConnectQuery(ASocket : longint): Boolean ;Virtual;
  175. Procedure Bind; Virtual; Abstract;
  176. Function Accept: Longint;Virtual;Abstract;
  177. Function SockToStream (ASocket : Longint) : TSocketStream;Virtual;Abstract;
  178. Procedure Close; Virtual;
  179. Procedure Abort;
  180. Procedure RemoveSelfFromConnections; virtual;
  181. Function RunIdleLoop : Boolean;
  182. function GetConnection: TSocketStream; virtual; abstract;
  183. Function HandleAcceptError(E : ESocketError) : TAcceptErrorAction;
  184. Function GetClientSocketHandler(aSocket : Longint) : TSocketHandler; virtual;
  185. Property Handler : TSocketHandler Read FHandler;
  186. Public
  187. Constructor Create(ASocket : Longint; AHandler : TSocketHandler);
  188. Destructor Destroy; Override;
  189. Procedure Listen;
  190. function GetSockopt(ALevel,AOptName : cint; var optval; Var optlen : tsocklen): Boolean;
  191. function SetSockopt(ALevel,AOptName : cint; var optval; optlen : tsocklen): Boolean;
  192. Procedure StartAccepting;
  193. Procedure StopAccepting(DoAbort : Boolean = False);
  194. Procedure SetNonBlocking;
  195. Procedure Foreach(aHandler : TForeachHandler);
  196. Property Bound : Boolean Read FBound;
  197. // Maximium number of connections in total. *Not* the simultaneous connection count. -1 keeps accepting.
  198. Property MaxConnections : longint Read FMaxConnections Write FMaxConnections;
  199. Property MaxSimultaneousConnections : longint Read FMaxSimultaneousConnections Write FMaxSimultaneousConnections;
  200. Property QueueSize : Longint Read FQueueSize Write FQueueSize default 5;
  201. Property OnConnect : TConnectEvent Read FOnConnect Write FOnConnect;
  202. Property OnDisconnect : TDisconnectEvent Read FOnDisconnect Write FOnDisconnect;
  203. Property OnConnectionDropped : TConnectionDroppedEvent Read FOnConnectionDropped Write FOnConnectionDropped;
  204. Property OnConnectQuery : TConnectQuery Read FOnConnectQuery Write FOnConnectQuery;
  205. Property OnAcceptError : TOnAcceptError Read FOnAcceptError Write FOnAcceptError;
  206. Property OnIdle : TNotifyEvent Read FOnIdle Write FOnIdle;
  207. Property NonBlocking : Boolean Read FNonBlocking;
  208. Property Socket : Longint Read FSocket;
  209. Property SockType : Longint Read FSockType;
  210. Property KeepAlive : Boolean Read GetKeepAlive Write SetKeepAlive;
  211. Property ReuseAddress : Boolean Read GetReuseAddress Write SetReuseAddress;
  212. // -1 means no linger. Any value >=0 sets linger on.
  213. Property Linger: Integer Read GetLinger Write Setlinger;
  214. // Accept Timeout in milliseconds.
  215. // 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.
  216. Property AcceptIdleTimeOut : Cardinal Read FIdleTimeOut Write FIdleTimeout;
  217. Property OnCreateClientSocketHandler : TGetClientSocketHandlerEvent Read FOnCreateClientSocketHandler Write FOnCreateClientSocketHandler;
  218. Property ConnectionCount : Integer Read GetConnectionCount;
  219. end;
  220. { TInetServer }
  221. TInetServer = Class(TSocketServer)
  222. private
  223. FAddr : TINetSockAddr;
  224. FPort : Word;
  225. FHost: string;
  226. Protected
  227. Function GetConnection: TSocketStream; override;
  228. Function SockToStream (ASocket : Longint) : TSocketStream;Override;
  229. Function Accept : Longint;override;
  230. Property Addr : TINetSockAddr Read FAddr;
  231. Public
  232. DefaultServerSocketClass : TServerSocketStreamClass;
  233. Public
  234. Procedure Bind; Override;
  235. Constructor Create(APort: Word);
  236. Constructor Create(const aHost: string; const APort: Word; AHandler : TSocketHandler = Nil);
  237. Property Port : Word Read FPort;
  238. Property Host : string Read FHost;
  239. end;
  240. {$ifdef Unix}
  241. { TUnixServer }
  242. TUnixServer = Class(TSocketServer)
  243. Private
  244. FUnixAddr : TUnixSockAddr;
  245. FFileName : String;
  246. Protected
  247. Procedure Bind; Override;
  248. Function Accept : Longint;override;
  249. function GetConnection: TSocketStream; override;
  250. Function SockToStream (ASocket : Longint) : TSocketStream;Override;
  251. Procedure Close; override;
  252. Public
  253. DefaultUnixSocketClass : TUnixSocketClass;
  254. Public
  255. Constructor Create(const AFileName : String; AHandler : TSocketHandler = Nil);
  256. Property FileName : String Read FFileName;
  257. end;
  258. {$endif}
  259. { TInetSocket }
  260. TBlockingMode = (bmBlocking,bmNonBlocking);
  261. TBlockingModes = Set of TBlockingMode;
  262. TCheckTimeoutResult = (ctrTimeout,ctrError,ctrOK);
  263. {$if defined(unix) or defined(windows)}
  264. {$DEFINE HAVENONBLOCKING}
  265. {$endif}
  266. TNonBlockingSocketStream = class(TSocketStream)
  267. {$IFDEF HAVENONBLOCKING}
  268. function SetSocketBlockingMode(ASocket: cint; ABlockMode: TBlockingMode; AFDSPtr: Pointer): boolean; virtual;
  269. function CheckSocketConnectTimeout(ASocket: cint; AFDSPtr: Pointer; ATimeVPtr: Pointer): TCheckTimeoutResult; virtual;
  270. {$ENDIF}
  271. end;
  272. { TServerSocketStream }
  273. TServerSocketStream = class(TNonBlockingSocketStream)
  274. Protected
  275. FServer : TSocketServer;
  276. Protected
  277. Procedure DoOnClose; override;
  278. Property Server : TSocketServer Read FServer;
  279. Public
  280. Function CanRead(TimeOut : Integer): Boolean; override;
  281. end;
  282. TInetSocket = Class(TNonBlockingSocketStream)
  283. Private
  284. FHost : String;
  285. FPort : Word;
  286. Public
  287. Constructor Create(const AHost: String; APort: Word; AHandler : TSocketHandler = Nil); Overload;
  288. Constructor Create(const AHost: String; APort: Word; aConnectTimeout : Integer; AHandler : TSocketHandler = Nil); Overload;
  289. Procedure Connect; Virtual;
  290. Property Host : String Read FHost;
  291. Property Port : Word Read FPort;
  292. end;
  293. {$ifdef Unix}
  294. TUnixSocket = Class(TNonBlockingSocketStream)
  295. Private
  296. FFileName : String;
  297. Protected
  298. Procedure DoConnect(ASocket : longint); Virtual;
  299. Public
  300. Constructor Create(ASocket : Longint); Overload;
  301. Constructor Create(const AFileName : String); Overload;
  302. Property FileName : String Read FFileName;
  303. end;
  304. {$endif}
  305. Implementation
  306. {$IFDEF FPC_DOTTEDUNITS}
  307. uses
  308. // This must be here, to prevent it from overriding the sockets definitions... :/
  309. {$ifdef unix}
  310. UnixApi.Base,UnixApi.Unix,
  311. {$endif}
  312. {$ifdef Windows}
  313. WinApi.Winsock2, WinApi.Windows,
  314. {$endif}
  315. System.Net.Resolve;
  316. {$ELSE FPC_DOTTEDUNITS}
  317. uses
  318. // This must be here, to prevent it from overriding the sockets definitions... :/
  319. {$ifdef unix}
  320. BaseUnix,Unix,
  321. {$endif}
  322. {$ifdef windows}
  323. winsock2, windows,
  324. {$endif}
  325. resolve;
  326. {$ENDIF FPC_DOTTEDUNITS}
  327. Const
  328. SocketBlockingMode = 0;
  329. SocketNonBlockingMode = 1;
  330. { ---------------------------------------------------------------------
  331. ESocketError
  332. ---------------------------------------------------------------------}
  333. resourcestring
  334. strHostNotFound = 'Host name resolution for "%s" failed.';
  335. strSocketCreationFailed = 'Creation of socket failed: %s';
  336. strSocketBindFailed = 'Binding of socket failed: %s';
  337. strSocketListenFailed = 'Listening on port #%d failed, error: %d';
  338. strSocketConnectFailed = 'Connect to %s failed: %s';
  339. strSocketAcceptFailed = 'Could not accept a client connection on socket: %d, error %d';
  340. strSocketAcceptWouldBlock = 'Accept would block on socket: %d';
  341. strSocketIOTimeOut = 'Failed to set IO Timeout to %d';
  342. strErrNoStream = 'Socket stream not assigned';
  343. strSocketConnectTimeOut = 'Connection to %s timed out.';
  344. { TServerSocketStream }
  345. function TServerSocketStream.CanRead(TimeOut : Integer): Boolean;
  346. begin
  347. Result:=inherited CanRead(TimeOut);
  348. Result:=Result and Assigned(FServer); // main server is gone, cannot read from it
  349. end;
  350. procedure TServerSocketStream.DoOnClose;
  351. begin
  352. if Assigned(FServer) then
  353. FServer.SocketClosed(Self);
  354. inherited DoOnClose;
  355. end;
  356. { TSocketHandler }
  357. Procedure TSocketHandler.SetSocket(const AStream: TSocketStream);
  358. begin
  359. FSocket:=AStream;
  360. end;
  361. Procedure TSocketHandler.CheckSocket;
  362. begin
  363. If not Assigned(FSocket) then
  364. Raise ESocketError.Create(StrErrNoStream);
  365. end;
  366. constructor TSocketHandler.Create;
  367. begin
  368. FSocket:=Nil;
  369. end;
  370. function TSocketHandler.Connect: boolean;
  371. begin
  372. // Only descendents can change this
  373. Result:=True;
  374. end;
  375. function TSocketHandler.Accept : Boolean;
  376. begin
  377. // Only descendents can change this
  378. Result:=True;
  379. end;
  380. function TSocketHandler.Shutdown(BiDirectional: Boolean): boolean;
  381. begin
  382. CheckSocket ;
  383. Result:=False;
  384. end;
  385. function TSocketHandler.Select(aCheck: TSocketStates; TimeOut: Integer): TSocketStates;
  386. {$if defined(unix) or defined(windows)}
  387. var
  388. FDSR,FDSW,FDSE : TFDSet;
  389. PFDSR,PFDSW,PFDSE : PFDSet;
  390. TimeV: TTimeVal;
  391. PTV : ^TTimeVal;
  392. res : Longint;
  393. Procedure DoSet(var FDS : TFDSet; var PFDS : PFDSet; aState : TSocketState);
  394. begin
  395. if not (aState in aCheck) then
  396. PFDS:=nil
  397. else
  398. begin
  399. FDS := Default(TFDSet);
  400. {$ifdef unix}
  401. fpFD_Zero(FDS);
  402. fpFD_Set(FSocket.Handle, FDS);
  403. {$endif}
  404. {$ifdef windows}
  405. FDS := Default(TFDSet);
  406. FD_Zero(FDS);
  407. FD_Set(FSocket.Handle, FDS);
  408. {$ENDIF}
  409. PFDS:=@FDS;
  410. end
  411. end;
  412. Procedure CheckSet(var FDS : TFDSet; aState : TSocketState);
  413. begin
  414. if aState in aCheck then
  415. begin
  416. {$ifdef unix}
  417. if fpFD_IsSet(FSocket.Handle, FDS)>0 then
  418. Include(Result,aState);
  419. {$endif}
  420. {$ifdef windows}
  421. if FD_IsSet(FSocket.Handle, FDS) then
  422. Include(Result,aState);
  423. {$endif}
  424. end;
  425. end;
  426. {$endif}
  427. begin
  428. Result:=[];
  429. {$if defined(unix) or defined(windows)}
  430. Res:=-1;
  431. if Timeout<0 then
  432. PTV:=Nil
  433. else
  434. begin
  435. TimeV.tv_usec := (TimeOut mod 1000) * 1000;
  436. TimeV.tv_sec := TimeOut div 1000;
  437. PTV:=@TimeV;
  438. end;
  439. DoSet(FDSR,PFDSR,sosCanRead);
  440. DoSet(FDSW,PFDSW,sosCanWrite);
  441. DoSet(FDSE,PFDSE,sosException);
  442. {$endif}
  443. {$ifdef unix}
  444. Res:=fpSelect(Socket.Handle + 1, PFDSR, PFDSW, PFDSE, PTV);
  445. {$endif}
  446. {$ifdef windows}
  447. Res:={$IFDEF FPC_DOTTEDUNITS}WinApi.{$ENDIF}Winsock2.Select(Socket.Handle + 1, PFDSR, PFDSW, PFDSE, @TimeV);
  448. {$endif}
  449. {$if defined(unix) or defined(windows)}
  450. if Res>0 then
  451. begin
  452. CheckSet(FDSR,sosCanRead);
  453. CheckSet(FDSW,sosCanWrite);
  454. CheckSet(FDSE,sosException);
  455. end;
  456. if Res<0 then
  457. FLastError:=SocketError
  458. else
  459. FLastError:=0;
  460. {$else}
  461. FLastError:=0;
  462. {$endif}
  463. end;
  464. function TSocketHandler.CanRead(TimeOut : Integer): Boolean;
  465. begin
  466. Result:=Select([sosCanRead],Timeout)<>[];
  467. end;
  468. function TSocketHandler.Recv(Const Buffer; Count: Integer): Integer;
  469. Var
  470. Flags : longint;
  471. begin
  472. Flags:=Socket.FReadFlags;
  473. {$ifdef unix}
  474. FLastError:=ESysEINTR;
  475. While (FlastError=ESysEINTR) do
  476. {$endif}
  477. begin
  478. Result:=fprecv(Socket.Handle,@Buffer,count,flags);
  479. If (Result<0) then
  480. FLastError:=SocketError
  481. else
  482. FLastError:=0;
  483. end;
  484. end;
  485. function TSocketHandler.Send(Const Buffer; Count: Integer): Integer;
  486. Var
  487. Flags : longint;
  488. begin
  489. Flags:=FSocket.FWriteFlags;
  490. {$ifdef unix}
  491. FLastError:=ESysEINTR;
  492. While (FlastError=ESysEINTR) do
  493. {$endif}
  494. begin
  495. Result:=fpsend(Socket.Handle,@Buffer,count,flags);
  496. If Result<0 then
  497. FLastError:=SocketError
  498. else
  499. FlastError:=0;
  500. end;
  501. end;
  502. function TSocketHandler.BytesAvailable: Integer;
  503. begin
  504. Result:=0;
  505. { we need ioctlsocket here }
  506. end;
  507. function TSocketHandler.GetLastErrorDescription: String;
  508. begin
  509. Result:='';
  510. end;
  511. Function TSocketHandler.Close: Boolean;
  512. begin
  513. Result:=True;
  514. end;
  515. constructor ESocketError.Create(ACode: TSocketErrorType; const MsgArgs: array of const);
  516. var
  517. s: String;
  518. begin
  519. Code := ACode;
  520. case ACode of
  521. seHostNotFound : s := strHostNotFound;
  522. seCreationFailed : s := strSocketCreationFailed;
  523. seBindFailed : s := strSocketBindFailed;
  524. seListenFailed : s := strSocketListenFailed;
  525. seConnectFailed : s := strSocketConnectFailed;
  526. seAcceptFailed : s := strSocketAcceptFailed;
  527. seAcceptWouldBLock : S := strSocketAcceptWouldBlock;
  528. seIOTimeout : S := strSocketIOTimeOut;
  529. seConnectTimeOut : s := strSocketConnectTimeout;
  530. end;
  531. s := Format(s, MsgArgs);
  532. inherited Create(s);
  533. end;
  534. { ---------------------------------------------------------------------
  535. TSocketStream
  536. ---------------------------------------------------------------------}
  537. constructor TSocketStream.Create(AHandle: Longint; AHandler: TSocketHandler);
  538. begin
  539. Inherited Create(AHandle);
  540. FSocketInitialized := true;
  541. GetSockOptions;
  542. FHandler:=AHandler;
  543. If (FHandler=Nil) then
  544. FHandler:=TSocketHandler.Create;
  545. FHandler.SetSocket(Self);
  546. end;
  547. destructor TSocketStream.Destroy;
  548. begin
  549. Close;
  550. inherited Destroy;
  551. end;
  552. class function TSocketStream.Select(var aRead, aWrite,
  553. aExceptions: TSocketStreamArray; aTimeOut: Integer): Boolean;
  554. {$if defined(unix) or defined(windows)}
  555. var
  556. FDR,FDW,FDE: TFDSet;
  557. TimeV: TTimeVal;
  558. MaxHandle : Longint;
  559. Procedure FillFD(var FD : TFDSet; anArray : TSocketStreamArray);
  560. Var
  561. S : TSocketStream;
  562. begin
  563. FD := Default(TFDSet);
  564. {$ifdef unix}
  565. fpFD_Zero(FD);
  566. For S in AnArray do
  567. begin
  568. fpFD_Set(S.Handle, FD);
  569. if S.Handle>MaxHandle then
  570. MaxHandle:=S.Handle;
  571. end;
  572. {$ENDIF}
  573. {$ifdef windows}
  574. FD_Zero(FD);
  575. For S in AnArray do
  576. begin
  577. FD_Set(S.Handle, FD);
  578. if S.Handle>MaxHandle then
  579. MaxHandle:=S.Handle;
  580. end;
  581. {$ENDIF}
  582. end;
  583. function FillArr(FD : TFDSet; Src : TSocketStreamArray) : TSocketStreamArray;
  584. Var
  585. S : TSocketStream;
  586. aLen : Integer;
  587. begin
  588. Result:=nil;
  589. SetLength(Result,Length(Src));
  590. aLen:=0;
  591. For S in Src do
  592. begin
  593. {$IFDEF UNIX}
  594. if fpFD_IsSet(S.Handle, FD)>0 then
  595. {$ENDIF}
  596. {$IFDEF Windows}
  597. if FD_isSet(S.Handle, FD) then
  598. {$ENDIF}
  599. begin
  600. Result[aLen]:=S;
  601. Inc(aLen);
  602. end;
  603. end;
  604. SetLength(Result,aLen);
  605. end;
  606. {$ENDIF} // Unix or windows
  607. begin
  608. Result:=False;
  609. {$if defined(unix) or defined(windows)}
  610. MaxHandle:=0;
  611. TimeV.tv_usec := (aTimeOut mod 1000) * 1000;
  612. TimeV.tv_sec := aTimeOut div 1000;
  613. FillFD(FDR,aRead);
  614. FillFD(FDW,aWrite);
  615. FillFD(FDE,aExceptions);
  616. if MaxHandle=0 then
  617. exit;
  618. {$ifdef unix}
  619. Result := fpSelect(MaxHandle+1, @FDR, @FDW, @FDE, @TimeV) > 0;
  620. {$endif}
  621. {$ifdef windows}
  622. Result := {$IFDEF FPC_DOTTEDUNITS}WinApi.{$ENDIF}Winsock2.Select(MaxHandle+1, @FDR, @FDW, @FDE, @TimeV) > 0;
  623. {$endif}
  624. aRead:=FillArr(FDR,aRead);
  625. aWrite:=FillArr(FDR,aRead);
  626. aExceptions:=FillArr(FDR,aRead);
  627. {$ELSE} // Unix or windows
  628. aRead:=[];
  629. aWrite:=[];
  630. aExceptions:=[];
  631. {$ENDIF}
  632. end;
  633. procedure TSocketStream.Close;
  634. begin
  635. DoOnClose;
  636. if FSocketInitialized then
  637. FHandler.Close; // Ignore the result
  638. FSocketInitialized:=False;
  639. FreeAndNil(FHandler);
  640. CloseSocket(Handle);
  641. FClosed:=True;
  642. end;
  643. procedure TSocketStream.GetSockOptions;
  644. {$ifdef windows}
  645. var
  646. opt: DWord;
  647. olen: tsocklen;
  648. {$endif windows}
  649. {$ifdef unix}
  650. var
  651. time: ttimeval;
  652. olen: tsocklen;
  653. {$endif unix}
  654. begin
  655. {$ifdef windows}
  656. olen:=4;
  657. if fpgetsockopt(Handle, SOL_SOCKET, SO_RCVTIMEO, @opt, @olen) = 0 then
  658. FIOTimeout:=opt;
  659. {$endif windows}
  660. {$ifdef unix}
  661. olen:=sizeof(time);
  662. if fpgetsockopt(Handle, SOL_SOCKET, SO_RCVTIMEO, @time, @olen) = 0 then
  663. FIOTimeout:=(time.tv_sec*1000)+(time.tv_usec div 1000);
  664. {$endif}
  665. end;
  666. procedure TSocketStream.SetConnectTimeout(AValue: Integer);
  667. begin
  668. if FConnectTimeout = AValue then Exit;
  669. FConnectTimeout := AValue;
  670. end;
  671. function TSocketStream.GetLastError: Integer;
  672. begin
  673. Result:=FHandler.LastError;
  674. end;
  675. procedure TSocketStream.SetSocketOptions(Value: TSocketOptions);
  676. begin
  677. FSocketOptions:=Value;
  678. end;
  679. function TSocketStream.Seek(Offset: Longint; Origin: Word): Longint;
  680. begin
  681. Result:=0;
  682. end;
  683. function TSocketStream.Select(aCheck: TSocketStates; TimeOut: Integer): TSocketStates;
  684. begin
  685. Result:=FHandler.Select(aCheck,TimeOut);
  686. end;
  687. function TSocketStream.CanRead(TimeOut: Integer): Boolean;
  688. begin
  689. Result:=FHandler.CanRead(TimeOut);
  690. end;
  691. function TSocketStream.Read(var Buffer; Count: Longint): longint;
  692. begin
  693. Result:=FHandler.Recv(Buffer,Count);
  694. if (Result=0) then
  695. FPeerClosed:=True;
  696. end;
  697. function TSocketStream.Write(const Buffer; Count: Longint): Longint;
  698. begin
  699. Result:=FHandler.Send(Buffer,Count);
  700. end;
  701. function TSocketStream.GetLocalAddress: {$IFDEF FPC_DOTTEDUNITS}System.Net.{$ENDIF}sockets.TSockAddr;
  702. var
  703. len: LongInt;
  704. begin
  705. len := SizeOf({$IFDEF FPC_DOTTEDUNITS}System.Net.{$ENDIF}sockets.TSockAddr);
  706. if fpGetSockName(Handle, @Result, @len) <> 0 then
  707. FillChar(Result, SizeOf(Result), 0);
  708. end;
  709. function TSocketStream.GetRemoteAddress: {$IFDEF FPC_DOTTEDUNITS}System.Net.{$ENDIF}sockets.TSockAddr;
  710. var
  711. len: LongInt;
  712. begin
  713. len := SizeOf({$IFDEF FPC_DOTTEDUNITS}System.Net.{$ENDIF}sockets.TSockAddr);
  714. if fpGetPeerName(Handle, @Result, @len) <> 0 then
  715. FillChar(Result, SizeOf(Result), 0);
  716. end;
  717. procedure TSocketStream.SetIOTimeout(AValue: Integer);
  718. Var
  719. E : Boolean;
  720. {$ifdef windows}
  721. opt: DWord;
  722. {$endif windows}
  723. {$ifdef unix}
  724. time: ttimeval;
  725. {$endif unix}
  726. begin
  727. E:=False;
  728. if FIOTimeout=AValue then Exit;
  729. FIOTimeout:=AValue;
  730. {$ifdef windows}
  731. opt := AValue;
  732. E:=fpsetsockopt(Handle, SOL_SOCKET, SO_RCVTIMEO, @opt, 4)<>0;
  733. if not E then
  734. E:=fpsetsockopt(Handle, SOL_SOCKET, SO_SNDTIMEO, @opt, 4)<>0;
  735. {$endif windows}
  736. {$ifdef unix}
  737. time.tv_sec:=avalue div 1000;
  738. time.tv_usec:=(avalue mod 1000) * 1000;
  739. E:=fpsetsockopt(Handle, SOL_SOCKET, SO_RCVTIMEO, @time, sizeof(time))<>0;
  740. if not E then
  741. E:=fpsetsockopt(Handle, SOL_SOCKET, SO_SNDTIMEO, @time, sizeof(time))<>0;
  742. {$endif}
  743. if E then
  744. Raise ESocketError.Create(seIOTimeout,[AValue]);
  745. end;
  746. procedure TSocketStream.DoOnClose;
  747. begin
  748. If Assigned(FOnClose) then
  749. FOnClose(Self);
  750. end;
  751. { ---------------------------------------------------------------------
  752. TSocketServer
  753. ---------------------------------------------------------------------}
  754. constructor TSocketServer.Create(ASocket: Longint; AHandler: TSocketHandler);
  755. begin
  756. FSocket:=ASocket;
  757. FQueueSize :=5;
  758. FMaxConnections:=-1;
  759. if (AHandler=Nil) then
  760. AHandler:=TSocketHandler.Create;
  761. FHandler:=AHandler;
  762. FConnections:=TThreadList.Create;
  763. end;
  764. destructor TSocketServer.Destroy;
  765. begin
  766. RemoveSelfFromConnections;
  767. FreeAndNil(FConnections);
  768. Close;
  769. FreeAndNil(FHandler);
  770. Inherited;
  771. end;
  772. procedure TSocketServer.Close;
  773. begin
  774. If FSocket<>-1 Then
  775. CloseSocket(FSocket);
  776. FSocket:=-1;
  777. end;
  778. procedure TSocketServer.Abort;
  779. {$if defined(unix) or defined(mswindows) or defined(hasamiga)}
  780. {$else}
  781. var
  782. ASocket: longint;
  783. {$endif}
  784. begin
  785. {$if defined(unix)}
  786. fpShutdown(FSocket,SHUT_RDWR);
  787. {$elseif defined(mswindows) or defined(hasamiga)}
  788. CloseSocket(FSocket);
  789. {$else}
  790. {$WARNING Method Abort is not tested on this platform!}
  791. ASocket:=FSocket;
  792. fpShutdown(ASocket,SHUT_RDWR);
  793. CloseSocket(ASocket);
  794. {$endif}
  795. end;
  796. procedure TSocketServer.RemoveSelfFromConnections;
  797. Var
  798. L : TList;
  799. P: Pointer;
  800. begin
  801. L:=FConnections.LockList;
  802. try
  803. for P in L do
  804. TServerSocketStream(P).FServer:=Nil;
  805. finally
  806. FConnections.UnlockList;
  807. end;
  808. end;
  809. function TSocketServer.RunIdleLoop: Boolean;
  810. // Run Accept idle loop. Return True if there is a new connection waiting
  811. {$if defined(unix) or defined(windows)}
  812. var
  813. FDS: TFDSet;
  814. TimeV: TTimeVal;
  815. {$endif}
  816. begin
  817. Repeat
  818. Result:=False;
  819. {$if defined(unix) or defined(windows)}
  820. TimeV.tv_usec := (AcceptIdleTimeout mod 1000) * 1000;
  821. TimeV.tv_sec := AcceptIdleTimeout div 1000;
  822. {$endif}
  823. {$ifdef unix}
  824. FDS := Default(TFDSet);
  825. fpFD_Zero(FDS);
  826. fpFD_Set(FSocket, FDS);
  827. Result := fpSelect(FSocket + 1, @FDS, @FDS, @FDS, @TimeV) > 0;
  828. {$else}
  829. {$ifdef windows}
  830. FDS := Default(TFDSet);
  831. FD_Zero(FDS);
  832. FD_Set(FSocket, FDS);
  833. Result := {$IFDEF FPC_DOTTEDUNITS}WinApi.{$ENDIF}Winsock2.Select(FSocket + 1, @FDS, @FDS, @FDS, @TimeV) > 0;
  834. {$endif}
  835. {$endif}
  836. If Result then
  837. break;
  838. DoOnIdle;
  839. Until (Not FAccepting);
  840. end;
  841. procedure TSocketServer.Listen;
  842. begin
  843. If Not FBound then
  844. Bind;
  845. If {$IFDEF FPC_DOTTEDUNITS}System.Net.{$ENDIF}Sockets.FpListen(FSocket,FQueueSize)<>0 then
  846. Raise ESocketError.Create(seListenFailed,[FSocket,SocketError]);
  847. end;
  848. function TSocketServer.GetSockopt(ALevel, AOptName: cint; var optval;
  849. var optlen: tsocklen): Boolean;
  850. begin
  851. Result:=fpGetSockOpt(FSocket,ALevel,AOptName,@optval,@optlen)<>-1;
  852. end;
  853. function TSocketServer.SetSockopt(ALevel, AOptName: cint; var optval;
  854. optlen: tsocklen): Boolean;
  855. begin
  856. Result:=fpSetSockOpt(FSocket,ALevel,AOptName,@optval,optlen)<>-1;
  857. end;
  858. function TInetServer.GetConnection: TSocketStream;
  859. var
  860. NewSocket : longint;
  861. begin
  862. Result:=Nil;
  863. NewSocket:=Accept;
  864. if (NewSocket<0) then
  865. if not FAccepting then
  866. exit
  867. else
  868. Raise ESocketError.Create(seAcceptFailed,[Socket,SocketError]);
  869. If FAccepting and DoConnectQuery(NewSocket) Then
  870. Result:=SockToStream(NewSocket)
  871. else
  872. CloseSocket(NewSocket);
  873. end;
  874. function TSocketServer.HandleAcceptError(E: ESocketError): TAcceptErrorAction;
  875. begin
  876. if FAccepting then
  877. Result:=aeaRaise
  878. else
  879. Result:=aeaStop;
  880. if Assigned(FOnAcceptError) then
  881. FOnAcceptError(Self,FSocket,E,Result);
  882. end;
  883. function TSocketServer.GetClientSocketHandler(aSocket : Longint): TSocketHandler;
  884. begin
  885. If Assigned(FOnCreateClientSocketHandler) then
  886. FOnCreateClientSocketHandler(Self,Result)
  887. else
  888. if Assigned(FHandler) then
  889. Result:=TSocketHandlerClass(FHandler.ClassType).Create;
  890. end;
  891. procedure TSocketServer.StartAccepting;
  892. Var
  893. NoConnections : Integer;
  894. Stream : TSocketStream;
  895. begin
  896. FAccepting := True;
  897. NoConnections := 0;
  898. Listen;
  899. Repeat
  900. Repeat
  901. Stream:=Nil;
  902. Try
  903. If (AcceptIdleTimeOut=0) or RunIdleLoop then
  904. Stream:=GetConnection;
  905. if Assigned(Stream) then
  906. if (MaxSimultaneousConnections>0) and (ConnectionCount>=MaxSimultaneousConnections) then
  907. begin
  908. Stream.Close;
  909. DoConnectionDropped(Stream);
  910. FreeAndNil(Stream);
  911. end
  912. else
  913. begin
  914. if Stream is TServerSocketStream then
  915. begin
  916. FConnections.Add(Stream);
  917. TServerSocketStream(Stream).FServer:=Self;
  918. end;
  919. Inc(NoConnections);
  920. DoConnect(Stream);
  921. end;
  922. except
  923. On E : ESocketError do
  924. begin
  925. If E.Code=seAcceptWouldBlock then
  926. DoOnIdle
  927. else
  928. Case HandleAcceptError(E) of
  929. aeaIgnore : ;
  930. aeaStop : FAccepting:=False;
  931. aeaRaise : Raise;
  932. end;
  933. end;
  934. end;
  935. Until (Stream<>Nil) or (Not NonBlocking);
  936. Until Not (FAccepting) or ((FMaxConnections<>-1) and (NoConnections>=FMaxConnections));
  937. end;
  938. procedure TSocketServer.StopAccepting(DoAbort: Boolean = False);
  939. begin
  940. FAccepting:=False;
  941. If DoAbort then
  942. Abort;
  943. end;
  944. procedure TSocketServer.DoOnIdle;
  945. begin
  946. If Assigned(FOnIdle) then
  947. FOnIdle(Self);
  948. end;
  949. function TSocketServer.GetConnectionCount: Integer;
  950. Var
  951. L : TList;
  952. begin
  953. L:=FConnections.LockList;
  954. try
  955. Result:=L.Count;
  956. finally
  957. FConnections.UnlockList;
  958. end;
  959. end;
  960. function TSocketServer.GetReuseAddress: Boolean;
  961. Var
  962. L : cint;
  963. ls : Tsocklen;
  964. begin
  965. L:=0;
  966. ls:=0;
  967. {$IFDEF UNIX}
  968. if not GetSockOpt(SOL_SOCKET, SO_REUSEADDR, L, LS) then
  969. Raise ESocketError.CreateFmt('Failed to get SO_REUSEADDR to %d: %d',[l,socketerror]);
  970. Result:=(L<>0);
  971. {$ELSE}
  972. Result:=True;
  973. {$ENDIF}
  974. end;
  975. function TSocketServer.GetKeepAlive: Boolean;
  976. Var
  977. L : cint;
  978. ls : Tsocklen;
  979. begin
  980. L:=0;
  981. ls:=0;
  982. {$IFDEF UNIX}
  983. if Not GetSockOpt(SOL_SOCKET, SO_KEEPALIVE, L, LS) then
  984. Raise ESocketError.CreateFmt('Failed to get SO_KEEPALIVE: %d',[socketerror]);
  985. Result:=(L<>0);
  986. {$ELSE}
  987. Result:=True;
  988. {$ENDIF}
  989. end;
  990. function TSocketServer.GetLinger: Integer;
  991. Var
  992. L : linger;
  993. ls : tsocklen;
  994. begin
  995. L.l_onoff:=0;
  996. l.l_linger:=0;
  997. if Not GetSockOpt(SOL_SOCKET, SO_LINGER, l, ls) then
  998. Raise ESocketError.CreateFmt('Failed to set linger: %d',[socketerror]);
  999. if l.l_onoff=0 then
  1000. Result:=-1
  1001. else
  1002. Result:=l.l_linger;
  1003. end;
  1004. procedure TSocketServer.DoConnect(ASocket: TSocketStream);
  1005. begin
  1006. If Assigned(FOnConnect) Then
  1007. FOnConnect(Self,ASocket);
  1008. end;
  1009. function TSocketServer.DoConnectQuery(ASocket: longint): Boolean;
  1010. begin
  1011. Result:=True;
  1012. If Assigned(FOnConnectQuery) then
  1013. FOnConnectQuery(Self,ASocket,Result);
  1014. end;
  1015. procedure TSocketServer.SetNonBlocking;
  1016. begin
  1017. {$ifdef Unix}
  1018. fpfcntl(FSocket,F_SETFL,O_NONBLOCK);
  1019. {$endif}
  1020. FNonBlocking:=True;
  1021. end;
  1022. procedure TSocketServer.Foreach(aHandler: TForeachHandler);
  1023. Var
  1024. L : TList;
  1025. P : Pointer;
  1026. aContinue : Boolean;
  1027. begin
  1028. L:=FConnections.LockList;
  1029. try
  1030. aContinue:=True;
  1031. For P in L do
  1032. begin
  1033. aHandler(Self,TSocketStream(P),aContinue);
  1034. if not aContinue then
  1035. break;
  1036. end;
  1037. finally
  1038. FConnections.UnlockList;
  1039. end;
  1040. end;
  1041. procedure TSocketServer.SetLinger(ALinger: Integer);
  1042. Var
  1043. L : linger;
  1044. begin
  1045. L.l_onoff:=Ord(ALinger>0);
  1046. if ALinger<0 then
  1047. l.l_linger:=ALinger
  1048. else
  1049. l.l_linger:=0;
  1050. if Not SetSockOpt(SOL_SOCKET, SO_LINGER, l, SizeOf(L)) then
  1051. Raise ESocketError.CreateFmt('Failed to set linger: %d',[socketerror]);
  1052. end;
  1053. procedure TSocketServer.SocketClosed(aSocket: TSocketStream);
  1054. begin
  1055. FConnections.Remove(aSocket);
  1056. DoDisConnect(aSocket);
  1057. end;
  1058. procedure TSocketServer.DoConnectionDropped(aSocket: TSocketStream);
  1059. begin
  1060. If Assigned(FOnConnectionDropped) then
  1061. FOnConnectionDropped(Self,aSocket);
  1062. end;
  1063. procedure TSocketServer.DoDisconnect(aSocket: TSocketStream);
  1064. begin
  1065. If Assigned(FOnDisconnect) then
  1066. FOnDisconnect(Self,aSocket);
  1067. end;
  1068. procedure TSocketServer.SetReuseAddress(AValue: Boolean);
  1069. Var
  1070. L : cint;
  1071. begin
  1072. L:=Ord(AValue);
  1073. {$IFDEF UNIX}
  1074. if not SetSockOpt(SOL_SOCKET, SO_REUSEADDR , L, SizeOf(L)) then
  1075. Raise ESocketError.CreateFmt('Failed to set SO_REUSEADDR to %d: %d',[l,socketerror]);
  1076. {$ENDIF}
  1077. end;
  1078. procedure TSocketServer.SetKeepAlive(AValue: Boolean);
  1079. Var
  1080. L : cint;
  1081. begin
  1082. L:=Ord(AValue);
  1083. {$IFDEF UNIX}
  1084. if Not SetSockOpt(SOL_SOCKET, SO_KEEPALIVE, L, SizeOf(L)) then
  1085. Raise ESocketError.CreateFmt('Failed to set SO_REUSEADDR to %d: %d',[l,socketerror]);
  1086. {$ENDIF}
  1087. end;
  1088. { ---------------------------------------------------------------------
  1089. TInetServer
  1090. ---------------------------------------------------------------------}
  1091. constructor TInetServer.Create(APort: Word);
  1092. begin
  1093. Create('0.0.0.0', aPort);
  1094. end;
  1095. constructor TInetServer.Create(const aHost: string; const APort: Word;
  1096. AHandler: TSocketHandler);
  1097. Var S : longint;
  1098. begin
  1099. FHost:=aHost;
  1100. FPort:=APort;
  1101. S:={$IFDEF FPC_DOTTEDUNITS}System.Net.{$ENDIF}Sockets.FpSocket(AF_INET,SOCK_STREAM,0);
  1102. If S=-1 Then
  1103. Raise ESocketError.Create(seCreationFailed,[Format('%d',[APort])]);
  1104. Inherited Create(S,AHandler);
  1105. end;
  1106. procedure TInetServer.Bind;
  1107. begin
  1108. Faddr.sin_family := AF_INET;
  1109. Faddr.sin_port := ShortHostToNet(FPort);
  1110. Faddr.sin_addr.s_addr := LongWord(StrToNetAddr(FHost));
  1111. if {$IFDEF FPC_DOTTEDUNITS}System.Net.{$ENDIF}Sockets.fpBind(FSocket, @FAddr, Sizeof(FAddr))<>0 then
  1112. raise ESocketError.Create(seBindFailed, [IntToStr(FPort)]);
  1113. FBound:=True;
  1114. end;
  1115. function TInetServer.SockToStream(ASocket: Longint): TSocketStream;
  1116. Var
  1117. H : TSocketHandler;
  1118. ok : Boolean;
  1119. aClass : TServerSocketStreamClass;
  1120. procedure ShutDownH;
  1121. begin
  1122. H.Shutdown(False);
  1123. FreeAndNil(Result);
  1124. end;
  1125. begin
  1126. H:=GetClientSocketHandler(aSocket);
  1127. aClass:=DefaultServerSocketClass;
  1128. if aClass=Nil then
  1129. aClass:=TServerSocketStream;
  1130. Result:=aClass.Create(ASocket,H);
  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 TNonBlockingSocketStream.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 TNonBlockingSocketStream.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) and Assigned(Handler) 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. if Assigned(FHandler) then
  1400. aErrMsg:=FHandler.GetLastErrorDescription
  1401. else
  1402. aErrMsg:='Error connecting';
  1403. Raise ESocketError.Create(seConnectFailed, [Format('%s:%d',[FHost, FPort]),aErrMsg]);
  1404. end;
  1405. end;
  1406. { ---------------------------------------------------------------------
  1407. TUnixSocket
  1408. ---------------------------------------------------------------------}
  1409. {$ifdef Unix}
  1410. Constructor TUnixSocket.Create(ASocket : Longint);
  1411. begin
  1412. Inherited Create(ASocket);
  1413. end;
  1414. Constructor TUnixSocket.Create(const AFileName : String);
  1415. Var S : Longint;
  1416. begin
  1417. FFileName:=AFileName;
  1418. S:=FpSocket(AF_UNIX,SOCK_STREAM,0);
  1419. DoConnect(S);
  1420. Inherited Create(S);
  1421. end;
  1422. Procedure TUnixSocket.DoConnect(ASocket : longint);
  1423. Var
  1424. UnixAddr : TUnixSockAddr;
  1425. AddrLen : longint;
  1426. begin
  1427. Str2UnixSockAddr(FFilename,UnixAddr,AddrLen);
  1428. If FpConnect(ASocket,@UnixAddr,AddrLen)<>0 then
  1429. Raise ESocketError.Create(seConnectFailed,[FFilename,'']);
  1430. end;
  1431. {$endif}
  1432. end.