ssockets.pp 12 KB

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