ssockets.pp 24 KB

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