ssockets.pp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524
  1. {
  2. $Id$
  3. This file is part of the Free Component Library (FCL)
  4. Copyright (c) 1999-2000 by the Free Pascal development team
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. {$MODE objfpc}
  12. unit ssockets;
  13. interface
  14. uses SysUtils, Classes, sockets;
  15. type
  16. TSocketErrorType = (
  17. seHostNotFound,
  18. seCreationFailed,
  19. seBindFailed,
  20. seListenFailed,
  21. seConnectFailed,
  22. seAcceptFailed,
  23. seAcceptWouldBlock);
  24. TSocketOption = (soDebug,soReuseAddr,soKeepAlive,soDontRoute,soBroadcast,
  25. soOOBinline);
  26. TSocketOptions = Set of TSocketOption;
  27. ESocketError = class(Exception)
  28. Code: TSocketErrorType;
  29. constructor Create(ACode: TSocketErrorType; const MsgArgs: array of const);
  30. end;
  31. TSocketStream = class(THandleStream)
  32. Private
  33. FSocketOptions : TSocketOptions;
  34. Procedure GetSockOptions;
  35. Procedure SetSocketOptions(Value : TSocketOptions);
  36. Public
  37. Constructor Create (AHandle : Longint);virtual;
  38. destructor Destroy; override;
  39. function Seek(Offset: Longint; Origin: Word): Longint; override;
  40. Property SocketOptions : TSocketOptions Read FSocketOptions
  41. Write SetSocketOptions;
  42. end;
  43. TConnectEvent = Procedure (Sender : TObject; Data : TSocketStream) Of Object;
  44. TConnectQuery = Procedure (Sender : TObject; ASocket : Longint; Var Allow : Boolean) of Object;
  45. TSocketServer = Class(TObject)
  46. Private
  47. FOnIdle : TNotifyEvent;
  48. FNonBlocking : Boolean;
  49. FSocket : longint;
  50. FListened : Boolean;
  51. FAccepting : Boolean;
  52. FMaxConnections : Longint;
  53. FQueueSize : Longint;
  54. FOnConnect : TConnectEvent;
  55. FOnConnectQuery : TConnectQuery;
  56. Procedure DoOnIdle;
  57. Protected
  58. FSockType : Longint;
  59. FBound : Boolean;
  60. Procedure DoConnect(ASocket : TSocketStream); Virtual;
  61. Function DoConnectQuery(ASocket : longint): Boolean ;Virtual;
  62. Procedure Bind; Virtual; Abstract;
  63. Function Accept: Longint;Virtual;Abstract;
  64. Function SockToStream (ASocket : Longint) : TSocketStream;Virtual;Abstract;
  65. Procedure Close; Virtual;
  66. Public
  67. Constructor Create(ASocket : Longint);
  68. Destructor Destroy; Override;
  69. Procedure Listen;
  70. Procedure StartAccepting;
  71. Procedure StopAccepting;
  72. Procedure SetNonBlocking;
  73. Property Bound : Boolean Read FBound;
  74. Property MaxConnections : longint Read FMaxConnections Write FMaxConnections;
  75. Property QueueSize : Longint Read FQueueSize Write FQueueSize default 5;
  76. Property OnConnect : TConnectEvent Read FOnConnect Write FOnConnect;
  77. Property OnConnectQuery : TConnectQuery Read FOnConnectQuery Write FOnConnectQuery;
  78. Property OnIdle : TNotifyEvent Read FOnIdle Write FOnIdle;
  79. Property NonBlocking : Boolean Read FNonBlocking;
  80. Property Socket : Longint Read FSocket;
  81. Property SockType : Longint Read FSockType;
  82. end;
  83. TInetServer = Class(TSocketServer)
  84. Protected
  85. FAddr : TINetSockAddr;
  86. Function SockToStream (ASocket : Longint) : TSocketStream;Override;
  87. Function Accept : Longint;override;
  88. FPort : Word;
  89. Public
  90. Procedure Bind; Override;
  91. Constructor Create(APort: Word);
  92. Property Port : Word Read FPort;
  93. end;
  94. TUnixServer = Class(TSocketServer)
  95. Private
  96. FUnixAddr : TUnixSockAddr;
  97. FFileName : String;
  98. Protected
  99. Procedure Bind; Override;
  100. Function Accept : Longint;override;
  101. Function SockToStream (ASocket : Longint) : TSocketStream;Override;
  102. Procedure Close; override;
  103. Public
  104. Constructor Create(AFileName : String);
  105. Property FileName : String Read FFileName;
  106. end;
  107. TInetSocket = Class(TSocketStream)
  108. Private
  109. FHost : String;
  110. FPort : Word;
  111. Protected
  112. Procedure DoConnect(ASocket : longint); Virtual;
  113. Public
  114. Constructor Create(ASocket : longint); Override; {$ifndef ver1_0}Overload;{$endif}
  115. Constructor Create(const AHost: String; APort: Word); {$ifndef ver1_0}Overload;{$endif}
  116. Property Host : String Read FHost;
  117. Property Port : Word Read FPort;
  118. end;
  119. TUnixSocket = Class(TSocketStream)
  120. Private
  121. FFileName : String;
  122. Protected
  123. Procedure DoConnect(ASocket : longint); Virtual;
  124. Public
  125. Constructor Create(ASocket : Longint); {$ifndef ver1_0}Overload;{$endif}
  126. Constructor Create(AFileName : String); {$ifndef ver1_0}Overload;{$endif}
  127. Property FileName : String Read FFileName;
  128. end;
  129. Implementation
  130. uses
  131. {$ifdef unix}
  132. {$ifdef ver1_0}
  133. Linux,
  134. {$else}
  135. Unix,
  136. {$endif}
  137. {$endif}
  138. inet
  139. ;
  140. Const
  141. SocketWouldBlock = -2;
  142. { ---------------------------------------------------------------------
  143. ESocketError
  144. ---------------------------------------------------------------------}
  145. resourcestring
  146. strHostNotFound = 'Host name resolution for "%s" failed.';
  147. strSocketCreationFailed = 'Creation of socket failed: %s';
  148. strSocketBindFailed = 'Binding of socket failed: %s';
  149. strSocketListenFailed = 'Listening on port #%d failed: %s';
  150. strSocketConnectFailed = 'Connect to %s failed.';
  151. strSocketAcceptFailed = 'Could not accept a client connection: %s';
  152. strSocketAcceptWouldBlock = 'Accept would block on socket: %d';
  153. constructor ESocketError.Create(ACode: TSocketErrorType; const MsgArgs: array of const);
  154. var
  155. s: String;
  156. begin
  157. Code := ACode;
  158. case ACode of
  159. seHostNotFound : s := strHostNotFound;
  160. seCreationFailed: s := strSocketCreationFailed;
  161. seBindFailed : s := strSocketBindFailed;
  162. seListenFailed : s := strSocketListenFailed;
  163. seConnectFailed : s := strSocketConnectFailed;
  164. seAcceptFailed : s := strSocketAcceptFailed;
  165. seAcceptWouldBLock : S:= strSocketAcceptWouldBlock;
  166. end;
  167. s := Format(s, MsgArgs);
  168. inherited Create(s);
  169. end;
  170. { ---------------------------------------------------------------------
  171. TSocketStream
  172. ---------------------------------------------------------------------}
  173. Constructor TSocketStream.Create (AHandle : Longint);
  174. begin
  175. Inherited Create(AHandle);
  176. GetSockOptions;
  177. end;
  178. destructor TSocketStream.Destroy;
  179. begin
  180. FileClose(Handle);
  181. inherited Destroy;
  182. end;
  183. Procedure TSocketStream.GetSockOptions;
  184. begin
  185. end;
  186. Procedure TSocketStream.SetSocketOptions(Value : TSocketOptions);
  187. begin
  188. end;
  189. Function TSocketStream.Seek(Offset: Longint; Origin: Word): Longint;
  190. begin
  191. Result:=0;
  192. end;
  193. { ---------------------------------------------------------------------
  194. TSocketServer
  195. ---------------------------------------------------------------------}
  196. Constructor TSocketServer.Create(ASocket : Longint);
  197. begin
  198. FSocket:=ASocket;
  199. FQueueSize :=5;
  200. end;
  201. Destructor TSocketServer.Destroy;
  202. begin
  203. Close;
  204. end;
  205. Procedure TSocketServer.Close;
  206. begin
  207. If FSocket<>-1 Then
  208. FileClose(FSocket);
  209. FSocket:=-1;
  210. end;
  211. Procedure TSocketServer.Listen;
  212. begin
  213. If Not FBound then
  214. Bind;
  215. If Not Sockets.Listen(FSocket,FQueueSize) then
  216. Raise ESocketError.Create(seListenFailed,[FSocket]);
  217. end;
  218. Procedure TSocketServer.StartAccepting;
  219. Var
  220. NoConnections,
  221. NewSocket : longint;
  222. Stream : TSocketStream;
  223. begin
  224. Listen;
  225. Repeat
  226. Repeat
  227. Try
  228. NewSocket:=Accept;
  229. If NewSocket>=0 then
  230. begin
  231. Inc (NoConnections);
  232. If DoConnectQuery(NewSocket) Then
  233. begin
  234. Stream:=SockToStream(NewSocket);
  235. DoConnect(Stream);
  236. end
  237. end
  238. except
  239. On E : ESocketError do
  240. If E.Code=seAcceptWouldBlock then
  241. begin
  242. DoOnIdle;
  243. NewSocket:=-1;
  244. end;
  245. else
  246. Raise;
  247. end;
  248. Until (NewSocket>=0) or (Not NonBlocking);
  249. Until Not (FAccepting) or ((FMaxConnections<>-1) and (NoConnections>=FMaxConnections));
  250. end;
  251. Procedure TSocketServer.StopAccepting;
  252. begin
  253. FAccepting:=False;
  254. end;
  255. Procedure TSocketServer.DoOnIdle;
  256. begin
  257. If Assigned(FOnIdle) then
  258. FOnIdle(Self);
  259. end;
  260. Procedure TSocketServer.DoConnect(ASocket : TSocketStream);
  261. begin
  262. If Assigned(FOnConnect) Then
  263. FOnConnect(Self,ASocket);
  264. end;
  265. Function TSocketServer.DoConnectQuery(ASocket : Longint) : Boolean;
  266. begin
  267. Result:=True;
  268. If Assigned(FOnConnectQuery) then
  269. FOnConnectQuery(Self,ASocket,Result);
  270. end;
  271. Procedure TSocketServer.SetNonBlocking;
  272. begin
  273. fcntl(FSocket,F_SETFL,OPEN_NONBLOCK);
  274. FNonBlocking:=True;
  275. end;
  276. { ---------------------------------------------------------------------
  277. TInetServer
  278. ---------------------------------------------------------------------}
  279. Constructor TInetServer.Create(APort: Word);
  280. Var S : longint;
  281. begin
  282. FPort:=APort;
  283. S:=Sockets.Socket(AF_INET,SOCK_STREAM,0);
  284. If S=-1 Then
  285. Raise ESocketError.Create(seCreationFailed,[Format('%d',[APort])]);
  286. Inherited Create(S);
  287. end;
  288. Procedure TInetServer.Bind;
  289. begin
  290. Faddr.family := AF_INET;
  291. Faddr.port := ShortHostToNet(FPort);
  292. Faddr.addr := 0;
  293. if not Sockets.Bind(FSocket, FAddr, Sizeof(FAddr)) then
  294. raise ESocketError.Create(seBindFailed, [IntToStr(FPort)]);
  295. FBound:=True;
  296. end;
  297. Function TInetServer.SockToStream (ASocket : Longint) : TSocketStream;
  298. begin
  299. Result:=TInetSocket.Create(ASocket);
  300. (Result as TInetSocket).FHost:='';
  301. (Result as TInetSocket).FPort:=FPort;
  302. end;
  303. Function TInetServer.Accept : Longint;
  304. Var l : longint;
  305. begin
  306. L:=SizeOf(FAddr);
  307. Result:=Sockets.Accept(Socket,Faddr,L);
  308. If Result<0 then
  309. If SocketError=Sys_EWOULDBLOCK then
  310. Raise ESocketError.Create(seAcceptWouldBlock,[socket])
  311. else
  312. Raise ESocketError.Create(seAcceptFailed,[socket]);
  313. end;
  314. { ---------------------------------------------------------------------
  315. TUnixServer
  316. ---------------------------------------------------------------------}
  317. Constructor TUnixServer.Create(AFileName : String);
  318. Var S : Longint;
  319. begin
  320. FFileName:=AFileName;
  321. S:=Sockets.Socket(AF_UNIX,SOCK_STREAM,0);
  322. If S=-1 then
  323. Raise ESocketError.Create(seCreationFailed,[AFileName])
  324. else
  325. Inherited Create(S);
  326. end;
  327. Procedure TUnixServer.Close;
  328. begin
  329. Inherited Close;
  330. DeleteFile(FFileName);
  331. FFileName:='';
  332. end;
  333. Procedure TUnixServer.Bind;
  334. var
  335. AddrLen : longint;
  336. begin
  337. Str2UnixSockAddr(FFilename,FUnixAddr,AddrLen);
  338. If Not Sockets.Bind(Socket,FUnixAddr,AddrLen) then
  339. Raise ESocketError.Create(seBindFailed,[FFileName]);
  340. FBound:=True;
  341. end;
  342. Function TUnixServer.Accept : Longint;
  343. Var L : longint;
  344. begin
  345. L:=Length(FFileName);
  346. Result:=Sockets.Accept(Socket,FUnixAddr,L);
  347. If Result<0 then
  348. If SocketError=Sys_EWOULDBLOCK then
  349. Raise ESocketError.Create(seAcceptWouldBlock,[socket])
  350. else
  351. Raise ESocketError.Create(seAcceptFailed,[socket]);
  352. end;
  353. Function TUnixServer.SockToStream (ASocket : Longint) : TSocketStream;
  354. begin
  355. Result:=TUnixSocket.Create(ASocket);
  356. (Result as TUnixSocket).FFileName:=FFileName;
  357. end;
  358. { ---------------------------------------------------------------------
  359. TInetSocket
  360. ---------------------------------------------------------------------}
  361. Constructor TInetSocket.Create(ASocket : Longint);
  362. begin
  363. Inherited Create(ASocket);
  364. end;
  365. Constructor TInetSocket.Create(const AHost: String; APort: Word);
  366. Var
  367. S : Longint;
  368. begin
  369. FHost:=AHost;
  370. FPort:=APort;
  371. S:=Socket(AF_INET,SOCK_STREAM,0);
  372. DoConnect(S);
  373. Inherited Create(S);
  374. end;
  375. Procedure TInetSocket.DoConnect(ASocket : Longint);
  376. Var
  377. TheHost: THost;
  378. addr: TInetSockAddr;
  379. begin
  380. TheHost.NameLookup(FHost);
  381. if TheHost.LastError <> 0 then
  382. raise ESocketError.Create(seHostNotFound, [FHost]);
  383. addr.family := AF_INET;
  384. addr.port := ShortHostToNet(FPort);
  385. addr.addr := HostToNet(LongInt(TheHost.IPAddress));
  386. If not Sockets.Connect(ASocket, addr, sizeof(addr)) then
  387. raise ESocketError.Create(seConnectFailed, [Format('%s:%d',[FHost, FPort])]);
  388. end;
  389. { ---------------------------------------------------------------------
  390. TUnixSocket
  391. ---------------------------------------------------------------------}
  392. Constructor TUnixSocket.Create(ASocket : Longint);
  393. begin
  394. Inherited Create(ASocket);
  395. end;
  396. Constructor TUnixSocket.Create(AFileName : String);
  397. Var S : Longint;
  398. begin
  399. FFileName:=AFileName;
  400. S:=Socket(AF_UNIX,SOCK_STREAM,0);
  401. DoConnect(S);
  402. Inherited Create(S);
  403. end;
  404. Procedure TUnixSocket.DoConnect(ASocket : longint);
  405. Var
  406. UnixAddr : TUnixSockAddr;
  407. AddrLen : longint;
  408. begin
  409. Str2UnixSockAddr(FFilename,UnixAddr,AddrLen);
  410. If Not Connect(ASocket,UnixAddr,AddrLen) then
  411. Raise ESocketError.Create(seConnectFailed,[FFilename]);
  412. end;
  413. end.
  414. {
  415. $Log$
  416. Revision 1.12 2002-09-07 15:15:25 peter
  417. * old logs removed and tabs fixed
  418. Revision 1.11 2002/05/31 11:31:46 marco
  419. * 1.0.x Renamefest for FCL. Fixed some oddities in 1.1 too
  420. }