ssockets.pp 31 KB

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