ssockets.pp 12 KB

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