simpleipc.inc 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. {
  2. This file is part of the Free Component library.
  3. Copyright (c) 2005 by Michael Van Canneyt, member of
  4. the Free Pascal development team
  5. Unix implementation of one-way IPC between 2 processes
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. {$ifdef ipcunit}
  13. unit pipesipc;
  14. interface
  15. {$IFDEF FPC_DOTTEDUNITS}
  16. uses System.SysUtils, System.Classes, System.Simpleipc, UnixApi.Base;
  17. {$ELSE FPC_DOTTEDUNITS}
  18. uses sysutils, classes, simpleipc, baseunix;
  19. {$ENDIF FPC_DOTTEDUNITS}
  20. {$else}
  21. {$IFDEF FPC_DOTTEDUNITS}
  22. uses UnixApi.Base;
  23. {$ELSE FPC_DOTTEDUNITS}
  24. uses baseunix;
  25. {$ENDIF FPC_DOTTEDUNITS}
  26. {$endif}
  27. ResourceString
  28. SErrFailedToCreatePipe = 'Failed to create named pipe: %s';
  29. SErrFailedToRemovePipe = 'Failed to remove named pipe: %s';
  30. { ---------------------------------------------------------------------
  31. TPipeClientComm
  32. ---------------------------------------------------------------------}
  33. Type
  34. TPipeClientComm = Class(TIPCClientComm)
  35. Private
  36. FFileName: String;
  37. FStream: TFileStream;
  38. Public
  39. Constructor Create(AOWner : TSimpleIPCClient); override;
  40. Procedure Connect; override;
  41. Procedure Disconnect; override;
  42. Procedure SendMessage(MsgType : TMessageType; AStream : TStream); override;
  43. Function ServerRunning : Boolean; override;
  44. Property FileName : String Read FFileName;
  45. Property Stream : TFileStream Read FStream;
  46. end;
  47. {$ifdef ipcunit}
  48. implementation
  49. {$endif}
  50. constructor TPipeClientComm.Create(AOWner: TSimpleIPCClient);
  51. begin
  52. inherited Create(AOWner);
  53. FFileName:=Owner.ServerID;
  54. If (Owner.ServerInstance<>'') then
  55. FFileName:=FFileName+'-'+Owner.ServerInstance;
  56. if FFileName[1]<>'/' then
  57. FFileName:=GetTempDir(true)+FFileName;
  58. end;
  59. procedure TPipeClientComm.Connect;
  60. begin
  61. If Not ServerRunning then
  62. DoError(SErrServerNotActive,[Owner.ServerID]);
  63. // Use the sharedenynone line to allow more then one client
  64. // communicating with one server at the same time
  65. // see also mantis 15219
  66. FStream:=TFileStream.Create(FFileName,fmOpenWrite+fmShareDenyNone);
  67. // FStream:=TFileStream.Create(FFileName,fmOpenWrite);
  68. end;
  69. procedure TPipeClientComm.Disconnect;
  70. begin
  71. FreeAndNil(FStream);
  72. end;
  73. procedure TPipeClientComm.SendMessage(MsgType : TMessagetype; AStream: TStream);
  74. Var
  75. Hdr : TMsgHeader;
  76. begin
  77. Hdr.Version:=MsgVersion;
  78. Hdr.msgType:=MsgType;
  79. Hdr.MsgLen:=AStream.Size;
  80. FStream.WriteBuffer(hdr,SizeOf(hdr));
  81. FStream.CopyFrom(AStream,0);
  82. end;
  83. function TPipeClientComm.ServerRunning: Boolean;
  84. var
  85. fd: cint;
  86. begin
  87. Result:=FileExists(FFileName);
  88. // it's possible to have a stale file that is not open for reading which will
  89. // cause fpOpen to hang/block later when .Active is set to true while it
  90. // wait's for the pipe to be opened on the other end
  91. if Result then
  92. begin
  93. // O_WRONLY | O_NONBLOCK causes fpOpen to return -1 if the file is not open for reading
  94. // so in fact the 'server' is not running
  95. fd := FpOpen(FFileName, O_WRONLY or O_NONBLOCK);
  96. if fd = -1 then
  97. begin
  98. Result := False;
  99. // delete the named pipe since it's orphaned
  100. FpUnlink(FFileName);
  101. end
  102. else
  103. FpClose(fd);
  104. end;
  105. end;
  106. { ---------------------------------------------------------------------
  107. TPipeServerComm
  108. ---------------------------------------------------------------------}
  109. Type
  110. { TPipeServerComm }
  111. TPipeServerComm = Class(TIPCServerComm)
  112. Private
  113. FFileName: String;
  114. FStream: TFileStream;
  115. Public
  116. Constructor Create(AOWner : TSimpleIPCServer); override;
  117. Procedure StartServer; override;
  118. Procedure StopServer; override;
  119. Function PeekMessage(TimeOut : Integer) : Boolean; override;
  120. Procedure ReadMessage ; override;
  121. Function GetInstanceID : String;override;
  122. Property FileName : String Read FFileName;
  123. Property Stream : TFileStream Read FStream;
  124. end;
  125. constructor TPipeServerComm.Create(AOWner: TSimpleIPCServer);
  126. begin
  127. inherited Create(AOWner);
  128. FFileName:=Owner.ServerID;
  129. If Not Owner.Global then
  130. FFileName:=FFileName+'-'+IntToStr(fpGetPID);
  131. if FFileName[1]<>'/' then
  132. FFileName:=GetTempDir(Owner.Global)+FFileName;
  133. end;
  134. procedure TPipeServerComm.StartServer;
  135. const
  136. PrivateRights = S_IRUSR or S_IWUSR;
  137. GlobalRights = PrivateRights or S_IRGRP or S_IWGRP or S_IROTH or S_IWOTH;
  138. Rights : Array [Boolean] of Integer = (PrivateRights,GlobalRights);
  139. begin
  140. If not FileExists(FFileName) then
  141. If (fpmkFifo(FFileName,438)<>0) then
  142. DoError(SErrFailedToCreatePipe,[FFileName]);
  143. FStream:=TFileStream.Create(FFileName,fmOpenReadWrite+fmShareDenyNone,Rights[Owner.Global]);
  144. end;
  145. procedure TPipeServerComm.StopServer;
  146. begin
  147. FreeAndNil(FStream);
  148. if Not DeleteFile(FFileName) then
  149. DoError(SErrFailedtoRemovePipe,[FFileName]);
  150. end;
  151. function TPipeServerComm.PeekMessage(TimeOut: Integer): Boolean;
  152. Var
  153. FDS : TFDSet;
  154. begin
  155. fpfd_zero(FDS);
  156. fpfd_set(FStream.Handle,FDS);
  157. Result := fpSelect(FStream.Handle+1,@FDS,Nil,Nil,TimeOut)>0;
  158. end;
  159. procedure TPipeServerComm.ReadMessage;
  160. Var
  161. Hdr : TMsgHeader;
  162. begin
  163. FStream.ReadBuffer(Hdr,SizeOf(Hdr));
  164. PushMessage(Hdr,FStream);
  165. end;
  166. function TPipeServerComm.GetInstanceID: String;
  167. begin
  168. Result:=IntToStr(fpGetPID);
  169. end;
  170. { ---------------------------------------------------------------------
  171. Set TSimpleIPCClient / TSimpleIPCServer defaults.
  172. ---------------------------------------------------------------------}
  173. {$ifndef ipcunit}
  174. function TSimpleIPCServer.CommClass: TIPCServerCommClass;
  175. begin
  176. if (DefaultIPCServerClass<>Nil) then
  177. Result:=DefaultIPCServerClass
  178. else
  179. Result:=TPipeServerComm;
  180. end;
  181. function TSimpleIPCClient.CommClass: TIPCClientCommClass;
  182. begin
  183. if (DefaultIPCClientClass<>Nil) then
  184. Result:=DefaultIPCClientClass
  185. else
  186. Result:=TPipeClientComm;
  187. end;
  188. {$else ipcunit}
  189. end.
  190. {$endif}