ssockets.pp 26 KB

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