debugserverintf.pp 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388
  1. {
  2. $Id$
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 2003 by the Free Pascal development team
  5. Interface for debug server.
  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. {$mode objfpc}
  13. {$h+}
  14. unit debugserverintf;
  15. Interface
  16. Uses
  17. msgintf,linux,classes,sockets,sysutils;
  18. Const
  19. MsgTypes : Array[-1..3] of string =
  20. ('Disconnect','Information','Warning','Error','Identify');
  21. Type
  22. Thandle = Longint; // Abstraction for easier porting.
  23. TClient = Class(TObject)
  24. Handle : THandle;
  25. Peer : ShortString;
  26. Data : Pointer;
  27. end;
  28. TDebugEvent = Record
  29. Client : TClient;
  30. LogCode : Integer;
  31. TimeStamp : TDateTime;
  32. Event : String;
  33. end;
  34. Var
  35. FClients : TList;
  36. Accepting : Boolean;
  37. Quit : Boolean;
  38. DebugLogCallback : Procedure (Const Event : TDebugEvent);
  39. DebugObjLogCallBack : Procedure (Const Event : TDebugEvent) of Object;
  40. CloseConnectionCallBack : Procedure (Client : TClient);
  41. CloseObjConnectionCallBack : Procedure (Client : TClient) of Object;
  42. Procedure OpenDebugServer;
  43. Procedure CloseDebugServer;
  44. Function ClientFromHandle (AHandle : THandle) : TClient;
  45. Procedure ReadMessage(Handle : THandle);
  46. Procedure ReadMessageEvent(Handle : THandle; Var Event : TDebugEvent);
  47. Function CheckNewConnection : TClient;
  48. procedure CloseConnection(Client : TClient);
  49. Procedure CloseClientHandle(Handle : THandle);
  50. ResourceString
  51. SClientLog = 'Client log %d';
  52. SEvent = 'Event';
  53. SMessage = 'Message';
  54. SStopAccepting = 'Stop accepting new connections';
  55. SStartAccepting = 'Start accepting new connections';
  56. SErrSocketFailed = 'Creation of socket failed: %s';
  57. SErrBindFailed = 'Binding of socket failed: %s';
  58. SErrListenFailed = 'Listening on port #%d failed: %s';
  59. SErrAcceptFailed = 'Could not accept a client connection: %d';
  60. SClosingConnection = 'Closing connection.';
  61. SErrFailedToSetSignalHandler = 'Failed to set signal handler.';
  62. SPeerAt = 'Peer at %d';
  63. Implementation
  64. Function ClientFromHandle (AHandle : THandle) : TClient;
  65. Var
  66. I : Longint;
  67. begin
  68. Result:=Nil;
  69. I:=0;
  70. With FClients do
  71. While (I<Count) and (Result=Nil) do
  72. Begin
  73. If TClient(Items[i]).Handle=AHandle then
  74. Result:=TClient(Items[i]);
  75. Inc(I);
  76. end;
  77. end;
  78. { ---------------------------------------------------------------------
  79. Communications handling: Unix Socket setup
  80. ---------------------------------------------------------------------}
  81. Var
  82. FSocket : Integer;
  83. Procedure SetupUnixSocket;
  84. var
  85. Flags,AddrLen : Integer;
  86. FUnixAddr : TUnixSockAddr;
  87. FFileName : String;
  88. Quit : Boolean;
  89. begin
  90. FFileName:=DebugSocket;
  91. FSocket:=Socket(AF_UNIX,SOCK_STREAM,0);
  92. If FSocket<0 Then
  93. Raise Exception.Create(SErrSocketFailed);
  94. Flags:=FCntl(FSOCket,F_GETFL);
  95. Flags:=Flags or Open_NONBLOCK;
  96. FCntl(FSocket,F_SETFL,Flags);
  97. Str2UnixSockAddr(FFilename,FUnixAddr,AddrLen);
  98. If Not Bind(FSocket,FUnixAddr,AddrLen) then
  99. Raise Exception.CreateFmt(SErrBindFailed,[FFileName]);
  100. If Not (Listen(FSocket,5)) then
  101. Raise Exception.CreateFmt(SErrListenFailed,[FSocket]);
  102. FClients:=TList.Create;
  103. Accepting:=True;
  104. end;
  105. Procedure DestroyUnixSocket;
  106. Var
  107. C : TClient;
  108. begin
  109. If Assigned(FClients) then
  110. begin
  111. With FClients do
  112. While Count>0 do
  113. begin
  114. C:=TClient(Items[Count-1]);
  115. FileClose(C.Handle);
  116. C.Free;
  117. Delete(Count-1);
  118. end;
  119. FileClose(FSocket);
  120. DeleteFile(DebugSocket);
  121. end;
  122. end;
  123. { ---------------------------------------------------------------------
  124. Communications handling: Inet Socket setup
  125. ---------------------------------------------------------------------}
  126. Procedure SetupInetSocket(Aport : Word);
  127. var
  128. Flags,AddrLen : Integer;
  129. FInetAddr : TInetSockAddr;
  130. FFileName : String;
  131. Quit : Boolean;
  132. begin
  133. FSocket:=Socket(AF_INET,SOCK_STREAM,0);
  134. If FSocket<0 Then
  135. Raise Exception.Create(SErrSocketFailed);
  136. Flags:=FCntl(FSocket,F_GETFL);
  137. Flags:=Flags or Open_NONBLOCK;
  138. FCntl(FSocket,F_SETFL,Flags);
  139. FInetAddr.Family := AF_INET;
  140. Writeln('Using port : ',APort);
  141. FInetAddr.Port := Swap(APort);
  142. FInetAddr.Addr := 0;
  143. If Not Bind(FSocket,FInetAddr,SizeOf(FInetAddr)) then
  144. Raise Exception.CreateFmt(SErrBindFailed,[FFileName]);
  145. If Not (Listen(FSocket,5)) then
  146. Raise Exception.CreateFmt(SErrListenFailed,[FSocket]);
  147. end;
  148. Procedure DestroyInetSocket;
  149. Var
  150. C : TClient;
  151. begin
  152. If Assigned(FClients) then
  153. begin
  154. With FClients do
  155. While Count>0 do
  156. begin
  157. C:=TClient(Items[Count-1]);
  158. FileClose(C.Handle);
  159. C.Free;
  160. Delete(Count-1);
  161. end;
  162. FileClose(FSocket);
  163. end;
  164. end;
  165. { ---------------------------------------------------------------------
  166. Communications handling: Public interface
  167. ---------------------------------------------------------------------}
  168. Procedure OpenDebugServer;
  169. begin
  170. Case DebugConnection of
  171. dcUnix : SetupUnixSocket;
  172. dcInet : SetupInetSocket(DebugPort);
  173. end;
  174. FClients:=TList.Create;
  175. Accepting:=True;
  176. end;
  177. Procedure CloseDebugServer;
  178. begin
  179. Accepting:=False;
  180. Case DebugConnection of
  181. dcUnix : DestroyUnixSocket;
  182. dcInet : DestroyInetSocket;
  183. end;
  184. FClients.Free;
  185. FClients:=Nil;
  186. end;
  187. { ---------------------------------------------------------------------
  188. Communications handling: Connection handling
  189. ---------------------------------------------------------------------}
  190. Function GetNewConnection : THandle;
  191. Var
  192. ClientAddr: TUnixSockAddr;
  193. L : Integer;
  194. begin
  195. If Accepting then
  196. begin
  197. L:=SizeOf(ClientAddr);
  198. Result:=Accept(FSocket,ClientAddr,L);
  199. If (Result<0) Then
  200. if (Errno<>SYS_EWOULDBLOCK) then
  201. Raise Exception.CreateFmt(SErrAcceptFailed,[FSocket])
  202. else
  203. Result:=-1
  204. {$ifdef debug}
  205. else
  206. Writeln('New connection detected at ',Result)
  207. {$endif debug}
  208. end
  209. else
  210. Result:=-1;
  211. end;
  212. Function CheckNewConnection : TClient;
  213. Var
  214. NC : THandle;
  215. begin
  216. NC:=GetNewConnection;
  217. If (NC=-1) then
  218. Result:=Nil
  219. else
  220. begin
  221. Result:=TClient.Create;
  222. Result.Handle:=NC;
  223. {$ifdef debug}
  224. Writeln('Added new client', nc, ' at : ',FClients.Add(Result));
  225. {$else}
  226. FClients.Add(Result);
  227. {$endif debug}
  228. end;
  229. end;
  230. Procedure CloseClientHandle(Handle : THandle);
  231. begin
  232. ShutDown(Handle,2);
  233. FileClose(Handle);
  234. end;
  235. Procedure CloseConnection(Client : TClient);
  236. Var
  237. I : longint;
  238. C : TClient;
  239. begin
  240. If Assigned(Client) then
  241. begin
  242. If Assigned(CloseConnectionCallBack) then
  243. CloseConnectionCallBack(Client);
  244. If Assigned(CloseObjConnectionCallBack) then
  245. CloseObjConnectionCallBack(Client);
  246. CloseClientHandle(Client.Handle);
  247. FClients.Remove(Client);
  248. Client.Free;
  249. end;
  250. end;
  251. { ---------------------------------------------------------------------
  252. Message handling
  253. ---------------------------------------------------------------------}
  254. Function MsgToEvent(AHandle: THandle; ALogCode : Integer; ATimeStamp : TDateTime; AEvent : String) : TDebugEvent;
  255. begin
  256. With Result do
  257. begin
  258. Client:=ClientFromHandle(AHandle);
  259. If (Client<>Nil) then
  260. begin
  261. If (ALogCode=lctIdentify) then
  262. Client.Peer:=AEvent;
  263. end;
  264. LogCode:=ALogCode;
  265. TimeStamp:=ATimeStamp;
  266. Event:=AEvent;
  267. end;
  268. end;
  269. Procedure LogEvent(Event : TDebugEvent);
  270. begin
  271. if Assigned(DebugLogCallback) then
  272. DebugLogCallBack(Event);
  273. If Assigned(DebugObjLogCallBack) then
  274. DebugObjLogCallBack(Event);
  275. end;
  276. Procedure ReadMessageEvent(Handle : THandle; Var Event : TDebugEvent);
  277. Var
  278. FDebugMessage : TDebugMessage;
  279. msgSize : Integer;
  280. begin
  281. Try
  282. With FDebugMessage do
  283. begin
  284. // Select reports read ready when closed, so check for this.
  285. If (FileRead(Handle,msgType,SizeOf(Integer))=0) or (MsgType=-1) then
  286. begin
  287. event:=MsgToEvent(Handle,lctStop,Now,SClosingConnection);
  288. If Assigned(Event.Client) then
  289. CloseConnection(Event.Client)
  290. else
  291. CloseClientHandle(Handle);
  292. end
  293. else
  294. begin
  295. FileRead(Handle,msgTimeStamp,sizeof(TDateTime));
  296. FileRead(Handle,MsgSize,SizeOf(Integer));
  297. SetLength(Msg,MsgSize);
  298. FileRead(Handle,Msg[1],MsgSize);
  299. Event:=MsgToEvent(Handle,msgType,msgTimeStamp,Msg);
  300. end
  301. end;
  302. except
  303. On E : Exception do
  304. Event:=MsgToEvent(Handle,lctError,Now,E.Message);
  305. end;
  306. end;
  307. Procedure ReadMessage(Handle : THandle);
  308. Var
  309. Event : TDebugEvent;
  310. begin
  311. ReadMessageEvent(Handle,Event);
  312. LogEvent(Event);
  313. end;
  314. end.
  315. {
  316. $Log$
  317. Revision 1.1 2003-01-02 14:44:29 michael
  318. + Initial implementation
  319. }