ssockets.pp 31 KB

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