Repository URL to install this package:
Version:
3.0.0 ▾
|
{
This file is part of the Free Component library.
Copyright (c) 2005 by Michael Van Canneyt, member of
the Free Pascal development team
Unix implementation of one-way IPC between 2 processes
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.
**********************************************************************}
{$ifdef ipcunit}
unit pipesipc;
interface
uses sysutils, classes, simpleipc, baseunix;
{$else}
uses baseunix;
{$endif}
{$DEFINE OSNEEDIPCINITDONE}
ResourceString
SErrFailedToCreatePipe = 'Failed to create named pipe: %s';
SErrFailedToRemovePipe = 'Failed to remove named pipe: %s';
{ ---------------------------------------------------------------------
TPipeClientComm
---------------------------------------------------------------------}
Type
TPipeClientComm = Class(TIPCClientComm)
Private
FFileName: String;
FStream: TFileStream;
Public
Constructor Create(AOWner : TSimpleIPCClient); override;
Procedure Connect; override;
Procedure Disconnect; override;
Procedure SendMessage(MsgType : TMessageType; AStream : TStream); override;
Function ServerRunning : Boolean; override;
Property FileName : String Read FFileName;
Property Stream : TFileStream Read FStream;
end;
{$ifdef ipcunit}
implementation
{$endif}
Var
SocketFiles : TStringList;
Procedure IPCInit;
begin
end;
Procedure IPCDone;
Var
I : integer;
begin
if Assigned(SocketFiles) then
try
For I:=0 to SocketFiles.Count-1 do
DeleteFile(SocketFiles[i]);
finally
FreeAndNil(SocketFiles);
end;
end;
Procedure RegisterSocketFile(Const AFileName : String);
begin
If Not Assigned(SocketFiles) then
begin
SocketFiles:=TStringList.Create;
SocketFiles.Sorted:=True;
end;
SocketFiles.Add(AFileName);
end;
Procedure UnRegisterSocketFile(Const AFileName : String);
Var
I : Integer;
begin
If Assigned(SocketFiles) then
begin
I:=SocketFiles.IndexOf(AFileName);
If (I<>-1) then
SocketFiles.Delete(I);
If (SocketFiles.Count=0) then
FreeAndNil(SocketFiles);
end;
end;
constructor TPipeClientComm.Create(AOWner: TSimpleIPCClient);
begin
inherited Create(AOWner);
FFileName:=Owner.ServerID;
If (Owner.ServerInstance<>'') then
FFileName:=FFileName+'-'+Owner.ServerInstance;
if FFileName[1]<>'/' then
FFileName:=GetTempDir(true)+FFileName;
end;
procedure TPipeClientComm.Connect;
begin
If Not ServerRunning then
DoError(SErrServerNotActive,[Owner.ServerID]);
// Use the sharedenynone line to allow more then one client
// communicating with one server at the same time
// see also mantis 15219
FStream:=TFileStream.Create(FFileName,fmOpenWrite+fmShareDenyNone);
// FStream:=TFileStream.Create(FFileName,fmOpenWrite);
end;
procedure TPipeClientComm.Disconnect;
begin
FreeAndNil(FStream);
end;
procedure TPipeClientComm.SendMessage(MsgType : TMessagetype; AStream: TStream);
Var
Hdr : TMsgHeader;
P,L,Count : Integer;
begin
Hdr.Version:=MsgVersion;
Hdr.msgType:=MsgType;
Hdr.MsgLen:=AStream.Size;
FStream.WriteBuffer(hdr,SizeOf(hdr));
FStream.CopyFrom(AStream,0);
end;
function TPipeClientComm.ServerRunning: Boolean;
var
fd: cint;
begin
Result:=FileExists(FFileName);
// it's possible to have a stale file that is not open for reading which will
// cause fpOpen to hang/block later when .Active is set to true while it
// wait's for the pipe to be opened on the other end
if Result then
begin
// O_WRONLY | O_NONBLOCK causes fpOpen to return -1 if the file is not open for reading
// so in fact the 'server' is not running
fd := FpOpen(FFileName, O_WRONLY or O_NONBLOCK);
if fd = -1 then
begin
Result := False;
// delete the named pipe since it's orphaned
FpUnlink(FFileName);
end
else
FpClose(fd);
end;
end;
{ ---------------------------------------------------------------------
TPipeServerComm
---------------------------------------------------------------------}
Type
TPipeServerComm = Class(TIPCServerComm)
Private
FFileName: String;
FStream: TFileStream;
Public
Constructor Create(AOWner : TSimpleIPCServer); override;
Procedure StartServer; override;
Procedure StopServer; override;
Function PeekMessage(TimeOut : Integer) : Boolean; override;
Procedure ReadMessage ; override;
Function GetInstanceID : String;override;
Property FileName : String Read FFileName;
Property Stream : TFileStream Read FStream;
end;
constructor TPipeServerComm.Create(AOWner: TSimpleIPCServer);
begin
inherited Create(AOWner);
FFileName:=Owner.ServerID;
If Not Owner.Global then
FFileName:=FFileName+'-'+IntToStr(fpGetPID);
if FFileName[1]<>'/' then
FFileName:=GetTempDir(Owner.Global)+FFileName;
end;
procedure TPipeServerComm.StartServer;
const
PrivateRights = S_IRUSR or S_IWUSR;
GlobalRights = PrivateRights or S_IRGRP or S_IWGRP or S_IROTH or S_IWOTH;
Rights : Array [Boolean] of Integer = (PrivateRights,GlobalRights);
begin
If not FileExists(FFileName) then
If (fpmkFifo(FFileName,438)<>0) then
DoError(SErrFailedToCreatePipe,[FFileName]);
FStream:=TFileStream.Create(FFileName,fmOpenReadWrite+fmShareDenyNone,Rights[Owner.Global]);
RegisterSocketFile(FFileName);
end;
procedure TPipeServerComm.StopServer;
begin
UnregisterSocketFile(FFileName);
FreeAndNil(FStream);
if Not DeleteFile(FFileName) then
DoError(SErrFailedtoRemovePipe,[FFileName]);
end;
function TPipeServerComm.PeekMessage(TimeOut: Integer): Boolean;
Var
FDS : TFDSet;
begin
fpfd_zero(FDS);
fpfd_set(FStream.Handle,FDS);
Result:=fpSelect(FStream.Handle+1,@FDS,Nil,Nil,TimeOut)>0;
end;
procedure TPipeServerComm.ReadMessage;
Var
L,P,Count : Integer;
Hdr : TMsgHeader;
M : TStream;
begin
FStream.ReadBuffer(Hdr,SizeOf(Hdr));
SetMsgType(Hdr.MsgType);
Count:=Hdr.MsgLen;
M:=MsgData;
if count > 0 then
begin
M.Size:=0;
M.Seek(0,soFrombeginning);
M.CopyFrom(FStream,Count);
end
else
M.Size := 0;
end;
function TPipeServerComm.GetInstanceID: String;
begin
Result:=IntToStr(fpGetPID);
end;
{ ---------------------------------------------------------------------
Set TSimpleIPCClient / TSimpleIPCServer defaults.
---------------------------------------------------------------------}
{$ifndef ipcunit}
Function TSimpleIPCServer.CommClass : TIPCServerCommClass;
begin
if (DefaultIPCServerClass<>Nil) then
Result:=DefaultIPCServerClass
else
Result:=TPipeServerComm;
end;
function TSimpleIPCClient.CommClass: TIPCClientCommClass;
begin
if (DefaultIPCClientClass<>Nil) then
Result:=DefaultIPCClientClass
else
Result:=TPipeClientComm;
end;
{$else ipcunit}
initialization
IPCInit;
Finalization
IPCDone;
end.
{$endif}