123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524 |
- {
- $Id$
- This file is part of the Free Component Library (FCL)
- Copyright (c) 1999-2000 by the Free Pascal development team
- See the file COPYING.FPC, included in this distribution,
- for details about the copyright.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- **********************************************************************}
- {$MODE objfpc}
- unit ssockets;
- interface
- uses SysUtils, Classes, sockets;
- type
- TSocketErrorType = (
- seHostNotFound,
- seCreationFailed,
- seBindFailed,
- seListenFailed,
- seConnectFailed,
- seAcceptFailed,
- seAcceptWouldBlock);
- TSocketOption = (soDebug,soReuseAddr,soKeepAlive,soDontRoute,soBroadcast,
- soOOBinline);
- TSocketOptions = Set of TSocketOption;
- ESocketError = class(Exception)
- Code: TSocketErrorType;
- constructor Create(ACode: TSocketErrorType; const MsgArgs: array of const);
- end;
- TSocketStream = class(THandleStream)
- Private
- FSocketOptions : TSocketOptions;
- Procedure GetSockOptions;
- Procedure SetSocketOptions(Value : TSocketOptions);
- Public
- Constructor Create (AHandle : Longint);virtual;
- destructor Destroy; override;
- function Seek(Offset: Longint; Origin: Word): Longint; override;
- Property SocketOptions : TSocketOptions Read FSocketOptions
- Write SetSocketOptions;
- end;
- TConnectEvent = Procedure (Sender : TObject; Data : TSocketStream) Of Object;
- TConnectQuery = Procedure (Sender : TObject; ASocket : Longint; Var Allow : Boolean) of Object;
- TSocketServer = Class(TObject)
- Private
- FOnIdle : TNotifyEvent;
- FNonBlocking : Boolean;
- FSocket : longint;
- FListened : Boolean;
- FAccepting : Boolean;
- FMaxConnections : Longint;
- FQueueSize : Longint;
- FOnConnect : TConnectEvent;
- FOnConnectQuery : TConnectQuery;
- Procedure DoOnIdle;
- Protected
- FSockType : Longint;
- FBound : Boolean;
- Procedure DoConnect(ASocket : TSocketStream); Virtual;
- Function DoConnectQuery(ASocket : longint): Boolean ;Virtual;
- Procedure Bind; Virtual; Abstract;
- Function Accept: Longint;Virtual;Abstract;
- Function SockToStream (ASocket : Longint) : TSocketStream;Virtual;Abstract;
- Procedure Close; Virtual;
- Public
- Constructor Create(ASocket : Longint);
- Destructor Destroy; Override;
- Procedure Listen;
- Procedure StartAccepting;
- Procedure StopAccepting;
- Procedure SetNonBlocking;
- Property Bound : Boolean Read FBound;
- Property MaxConnections : longint Read FMaxConnections Write FMaxConnections;
- Property QueueSize : Longint Read FQueueSize Write FQueueSize default 5;
- Property OnConnect : TConnectEvent Read FOnConnect Write FOnConnect;
- Property OnConnectQuery : TConnectQuery Read FOnConnectQuery Write FOnConnectQuery;
- Property OnIdle : TNotifyEvent Read FOnIdle Write FOnIdle;
- Property NonBlocking : Boolean Read FNonBlocking;
- Property Socket : Longint Read FSocket;
- Property SockType : Longint Read FSockType;
- end;
- TInetServer = Class(TSocketServer)
- Protected
- FAddr : TINetSockAddr;
- Function SockToStream (ASocket : Longint) : TSocketStream;Override;
- Function Accept : Longint;override;
- FPort : Word;
- Public
- Procedure Bind; Override;
- Constructor Create(APort: Word);
- Property Port : Word Read FPort;
- end;
- TUnixServer = Class(TSocketServer)
- Private
- FUnixAddr : TUnixSockAddr;
- FFileName : String;
- Protected
- Procedure Bind; Override;
- Function Accept : Longint;override;
- Function SockToStream (ASocket : Longint) : TSocketStream;Override;
- Procedure Close; override;
- Public
- Constructor Create(AFileName : String);
- Property FileName : String Read FFileName;
- end;
- TInetSocket = Class(TSocketStream)
- Private
- FHost : String;
- FPort : Word;
- Protected
- Procedure DoConnect(ASocket : longint); Virtual;
- Public
- Constructor Create(ASocket : longint); Override; {$ifndef ver1_0}Overload;{$endif}
- Constructor Create(const AHost: String; APort: Word); {$ifndef ver1_0}Overload;{$endif}
- Property Host : String Read FHost;
- Property Port : Word Read FPort;
- end;
- TUnixSocket = Class(TSocketStream)
- Private
- FFileName : String;
- Protected
- Procedure DoConnect(ASocket : longint); Virtual;
- Public
- Constructor Create(ASocket : Longint); {$ifndef ver1_0}Overload;{$endif}
- Constructor Create(AFileName : String); {$ifndef ver1_0}Overload;{$endif}
- Property FileName : String Read FFileName;
- end;
- Implementation
- uses
- {$ifdef unix}
- {$ifdef ver1_0}
- Linux,
- {$else}
- Unix,
- {$endif}
- {$endif}
- inet
- ;
- Const
- SocketWouldBlock = -2;
- { ---------------------------------------------------------------------
- ESocketError
- ---------------------------------------------------------------------}
- resourcestring
- strHostNotFound = 'Host name resolution for "%s" failed.';
- strSocketCreationFailed = 'Creation of socket failed: %s';
- strSocketBindFailed = 'Binding of socket failed: %s';
- strSocketListenFailed = 'Listening on port #%d failed: %s';
- strSocketConnectFailed = 'Connect to %s failed.';
- strSocketAcceptFailed = 'Could not accept a client connection: %s';
- strSocketAcceptWouldBlock = 'Accept would block on socket: %d';
- constructor ESocketError.Create(ACode: TSocketErrorType; const MsgArgs: array of const);
- var
- s: String;
- begin
- Code := ACode;
- case ACode of
- seHostNotFound : s := strHostNotFound;
- seCreationFailed: s := strSocketCreationFailed;
- seBindFailed : s := strSocketBindFailed;
- seListenFailed : s := strSocketListenFailed;
- seConnectFailed : s := strSocketConnectFailed;
- seAcceptFailed : s := strSocketAcceptFailed;
- seAcceptWouldBLock : S:= strSocketAcceptWouldBlock;
- end;
- s := Format(s, MsgArgs);
- inherited Create(s);
- end;
- { ---------------------------------------------------------------------
- TSocketStream
- ---------------------------------------------------------------------}
- Constructor TSocketStream.Create (AHandle : Longint);
- begin
- Inherited Create(AHandle);
- GetSockOptions;
- end;
- destructor TSocketStream.Destroy;
- begin
- FileClose(Handle);
- inherited Destroy;
- end;
- Procedure TSocketStream.GetSockOptions;
- begin
- end;
- Procedure TSocketStream.SetSocketOptions(Value : TSocketOptions);
- begin
- end;
- Function TSocketStream.Seek(Offset: Longint; Origin: Word): Longint;
- begin
- Result:=0;
- end;
- { ---------------------------------------------------------------------
- TSocketServer
- ---------------------------------------------------------------------}
- Constructor TSocketServer.Create(ASocket : Longint);
- begin
- FSocket:=ASocket;
- FQueueSize :=5;
- end;
- Destructor TSocketServer.Destroy;
- begin
- Close;
- end;
- Procedure TSocketServer.Close;
- begin
- If FSocket<>-1 Then
- FileClose(FSocket);
- FSocket:=-1;
- end;
- Procedure TSocketServer.Listen;
- begin
- If Not FBound then
- Bind;
- If Not Sockets.Listen(FSocket,FQueueSize) then
- Raise ESocketError.Create(seListenFailed,[FSocket]);
- end;
- Procedure TSocketServer.StartAccepting;
- Var
- NoConnections,
- NewSocket : longint;
- Stream : TSocketStream;
- begin
- Listen;
- Repeat
- Repeat
- Try
- NewSocket:=Accept;
- If NewSocket>=0 then
- begin
- Inc (NoConnections);
- If DoConnectQuery(NewSocket) Then
- begin
- Stream:=SockToStream(NewSocket);
- DoConnect(Stream);
- end
- end
- except
- On E : ESocketError do
- If E.Code=seAcceptWouldBlock then
- begin
- DoOnIdle;
- NewSocket:=-1;
- end;
- else
- Raise;
- end;
- Until (NewSocket>=0) or (Not NonBlocking);
- Until Not (FAccepting) or ((FMaxConnections<>-1) and (NoConnections>=FMaxConnections));
- end;
- Procedure TSocketServer.StopAccepting;
- begin
- FAccepting:=False;
- end;
- Procedure TSocketServer.DoOnIdle;
- begin
- If Assigned(FOnIdle) then
- FOnIdle(Self);
- end;
- Procedure TSocketServer.DoConnect(ASocket : TSocketStream);
- begin
- If Assigned(FOnConnect) Then
- FOnConnect(Self,ASocket);
- end;
- Function TSocketServer.DoConnectQuery(ASocket : Longint) : Boolean;
- begin
- Result:=True;
- If Assigned(FOnConnectQuery) then
- FOnConnectQuery(Self,ASocket,Result);
- end;
- Procedure TSocketServer.SetNonBlocking;
- begin
- fcntl(FSocket,F_SETFL,OPEN_NONBLOCK);
- FNonBlocking:=True;
- end;
- { ---------------------------------------------------------------------
- TInetServer
- ---------------------------------------------------------------------}
- Constructor TInetServer.Create(APort: Word);
- Var S : longint;
- begin
- FPort:=APort;
- S:=Sockets.Socket(AF_INET,SOCK_STREAM,0);
- If S=-1 Then
- Raise ESocketError.Create(seCreationFailed,[Format('%d',[APort])]);
- Inherited Create(S);
- end;
- Procedure TInetServer.Bind;
- begin
- Faddr.family := AF_INET;
- Faddr.port := ShortHostToNet(FPort);
- Faddr.addr := 0;
- if not Sockets.Bind(FSocket, FAddr, Sizeof(FAddr)) then
- raise ESocketError.Create(seBindFailed, [IntToStr(FPort)]);
- FBound:=True;
- end;
- Function TInetServer.SockToStream (ASocket : Longint) : TSocketStream;
- begin
- Result:=TInetSocket.Create(ASocket);
- (Result as TInetSocket).FHost:='';
- (Result as TInetSocket).FPort:=FPort;
- end;
- Function TInetServer.Accept : Longint;
- Var l : longint;
- begin
- L:=SizeOf(FAddr);
- Result:=Sockets.Accept(Socket,Faddr,L);
- If Result<0 then
- If SocketError=Sys_EWOULDBLOCK then
- Raise ESocketError.Create(seAcceptWouldBlock,[socket])
- else
- Raise ESocketError.Create(seAcceptFailed,[socket]);
- end;
- { ---------------------------------------------------------------------
- TUnixServer
- ---------------------------------------------------------------------}
- Constructor TUnixServer.Create(AFileName : String);
- Var S : Longint;
- begin
- FFileName:=AFileName;
- S:=Sockets.Socket(AF_UNIX,SOCK_STREAM,0);
- If S=-1 then
- Raise ESocketError.Create(seCreationFailed,[AFileName])
- else
- Inherited Create(S);
- end;
- Procedure TUnixServer.Close;
- begin
- Inherited Close;
- DeleteFile(FFileName);
- FFileName:='';
- end;
- Procedure TUnixServer.Bind;
- var
- AddrLen : longint;
- begin
- Str2UnixSockAddr(FFilename,FUnixAddr,AddrLen);
- If Not Sockets.Bind(Socket,FUnixAddr,AddrLen) then
- Raise ESocketError.Create(seBindFailed,[FFileName]);
- FBound:=True;
- end;
- Function TUnixServer.Accept : Longint;
- Var L : longint;
- begin
- L:=Length(FFileName);
- Result:=Sockets.Accept(Socket,FUnixAddr,L);
- If Result<0 then
- If SocketError=Sys_EWOULDBLOCK then
- Raise ESocketError.Create(seAcceptWouldBlock,[socket])
- else
- Raise ESocketError.Create(seAcceptFailed,[socket]);
- end;
- Function TUnixServer.SockToStream (ASocket : Longint) : TSocketStream;
- begin
- Result:=TUnixSocket.Create(ASocket);
- (Result as TUnixSocket).FFileName:=FFileName;
- end;
- { ---------------------------------------------------------------------
- TInetSocket
- ---------------------------------------------------------------------}
- Constructor TInetSocket.Create(ASocket : Longint);
- begin
- Inherited Create(ASocket);
- end;
- Constructor TInetSocket.Create(const AHost: String; APort: Word);
- Var
- S : Longint;
- begin
- FHost:=AHost;
- FPort:=APort;
- S:=Socket(AF_INET,SOCK_STREAM,0);
- DoConnect(S);
- Inherited Create(S);
- end;
- Procedure TInetSocket.DoConnect(ASocket : Longint);
- Var
- TheHost: THost;
- addr: TInetSockAddr;
- begin
- TheHost.NameLookup(FHost);
- if TheHost.LastError <> 0 then
- raise ESocketError.Create(seHostNotFound, [FHost]);
- addr.family := AF_INET;
- addr.port := ShortHostToNet(FPort);
- addr.addr := HostToNet(LongInt(TheHost.IPAddress));
- If not Sockets.Connect(ASocket, addr, sizeof(addr)) then
- raise ESocketError.Create(seConnectFailed, [Format('%s:%d',[FHost, FPort])]);
- end;
- { ---------------------------------------------------------------------
- TUnixSocket
- ---------------------------------------------------------------------}
- Constructor TUnixSocket.Create(ASocket : Longint);
- begin
- Inherited Create(ASocket);
- end;
- Constructor TUnixSocket.Create(AFileName : String);
- Var S : Longint;
- begin
- FFileName:=AFileName;
- S:=Socket(AF_UNIX,SOCK_STREAM,0);
- DoConnect(S);
- Inherited Create(S);
- end;
- Procedure TUnixSocket.DoConnect(ASocket : longint);
- Var
- UnixAddr : TUnixSockAddr;
- AddrLen : longint;
- begin
- Str2UnixSockAddr(FFilename,UnixAddr,AddrLen);
- If Not Connect(ASocket,UnixAddr,AddrLen) then
- Raise ESocketError.Create(seConnectFailed,[FFilename]);
- end;
- end.
- {
- $Log$
- Revision 1.12 2002-09-07 15:15:25 peter
- * old logs removed and tabs fixed
- Revision 1.11 2002/05/31 11:31:46 marco
- * 1.0.x Renamefest for FCL. Fixed some oddities in 1.1 too
- }
|