ssockets.pp 13 KB

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