2 * Copyright (C) 2013 - David Goulet <dgoulet@efficios.com>
4 * This library is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License, version 2.1 only,
6 * as published by the Free Software Foundation.
8 * This library is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this library; if not, write to the Free Software Foundation,
15 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 package org
.lttng
.ust
.jul
;
20 import java
.util
.concurrent
.Semaphore
;
21 import java
.nio
.ByteBuffer
;
22 import java
.nio
.ByteOrder
;
23 import java
.lang
.Integer
;
24 import java
.io
.IOException
;
25 import java
.io
.BufferedOutputStream
;
26 import java
.io
.BufferedReader
;
27 import java
.io
.ByteArrayOutputStream
;
28 import java
.io
.DataOutputStream
;
29 import java
.io
.DataInputStream
;
30 import java
.io
.FileReader
;
31 import java
.io
.FileNotFoundException
;
33 import java
.lang
.management
.ManagementFactory
;
34 import java
.util
.logging
.Logger
;
36 class USTRegisterMsg
{
37 public static int pid
;
40 public class LTTngTCPSessiondClient
{
41 /* Command header from the session deamon. */
42 private LTTngSessiondCmd2_4
.sessiond_hdr headerCmd
=
43 new LTTngSessiondCmd2_4
.sessiond_hdr();
45 private final String sessiondHost
;
46 private Socket sessiondSock
;
47 private boolean quit
= false;
49 private DataInputStream inFromSessiond
;
50 private DataOutputStream outToSessiond
;
52 private LTTngLogHandler handler
;
54 private Semaphore registerSem
;
56 private static final String rootPortFile
= "/var/run/lttng/agent.port";
57 private static final String userPortFile
= "/.lttng/agent.port";
59 * This is taken from the lttng/domain.h file which is mapped to
60 * LTTNG_DOMAIN_JUL value for this agent.
62 private static final int agent_domain
= 3;
64 /* Indicate if we've already release the semaphore. */
65 private boolean sem_posted
= false;
67 public LTTngTCPSessiondClient(String host
, Semaphore sem
) {
68 this.sessiondHost
= host
;
69 this.registerSem
= sem
;
73 * Try to release the registerSem if it's not already done.
75 private void tryReleaseSem()
77 /* Release semaphore so we unblock the agent. */
78 if (!this.sem_posted
) {
79 this.registerSem
.release();
80 this.sem_posted
= true;
85 * Cleanup Agent state.
87 private void cleanupState() {
88 if (this.handler
!= null) {
93 public void init(LTTngLogHandler handler
) throws InterruptedException
{
94 this.handler
= handler
;
101 /* Cleanup Agent state before trying to connect or reconnect. */
107 * Connect to the session daemon before anything else.
112 * Register to the session daemon as the Java component of the
115 registerToSessiond();
118 * Block on socket receive and wait for command from the
119 * session daemon. This will return if and only if there is a
120 * fatal error or the socket closes.
123 } catch (UnknownHostException uhe
) {
125 System
.out
.println(uhe
);
126 } catch (IOException ioe
) {
129 } catch (Exception e
) {
136 public void destroy() {
140 if (this.sessiondSock
!= null) {
141 this.sessiondSock
.close();
143 } catch (Exception e
) {
149 * Receive header data from the session daemon using the LTTng command
150 * static buffer of the right size.
152 private void recvHeader() throws Exception
{
154 byte data
[] = new byte[this.headerCmd
.SIZE
];
156 read_len
= this.inFromSessiond
.read(data
, 0, data
.length
);
157 if (read_len
!= data
.length
) {
158 throw new IOException();
160 this.headerCmd
.populate(data
);
164 * Receive payload from the session daemon. This MUST be done after a
165 * recvHeader() so the header value of a command are known.
167 * The caller SHOULD use isPayload() before which returns true if a payload
168 * is expected after the header.
170 private byte[] recvPayload() throws Exception
{
171 byte payload
[] = new byte[(int) this.headerCmd
.data_size
];
173 /* Failsafe check so we don't waste our time reading 0 bytes. */
174 if (payload
.length
== 0) {
178 this.inFromSessiond
.read(payload
, 0, payload
.length
);
183 * Handle session command from the session daemon.
185 private void handleSessiondCmd() throws Exception
{
190 /* Get header from session daemon. */
193 if (headerCmd
.data_size
> 0) {
194 data
= recvPayload();
197 switch (headerCmd
.cmd
) {
201 * Release semaphore so meaning registration is done and we
202 * can proceed to continue tracing.
206 * We don't send any reply to the registration done command.
207 * This just marks the end of the initial session setup.
213 LTTngSessiondCmd2_4
.sessiond_list_logger listLoggerCmd
=
214 new LTTngSessiondCmd2_4
.sessiond_list_logger();
215 listLoggerCmd
.execute(this.handler
);
216 data
= listLoggerCmd
.getBytes();
222 LTTngSessiondCmd2_4
.sessiond_enable_handler enableCmd
=
223 new LTTngSessiondCmd2_4
.sessiond_enable_handler();
225 enableCmd
.code
= LTTngSessiondCmd2_4
.lttng_jul_ret_code
.CODE_INVALID_CMD
;
228 enableCmd
.populate(data
);
229 enableCmd
.execute(this.handler
);
230 data
= enableCmd
.getBytes();
235 LTTngSessiondCmd2_4
.sessiond_disable_handler disableCmd
=
236 new LTTngSessiondCmd2_4
.sessiond_disable_handler();
238 disableCmd
.code
= LTTngSessiondCmd2_4
.lttng_jul_ret_code
.CODE_INVALID_CMD
;
241 disableCmd
.populate(data
);
242 disableCmd
.execute(this.handler
);
243 data
= disableCmd
.getBytes();
249 ByteBuffer buf
= ByteBuffer
.wrap(data
);
250 buf
.order(ByteOrder
.BIG_ENDIAN
);
251 LTTngSessiondCmd2_4
.lttng_jul_ret_code code
=
252 LTTngSessiondCmd2_4
.lttng_jul_ret_code
.CODE_INVALID_CMD
;
253 buf
.putInt(code
.getCode());
258 /* Send payload to session daemon. */
259 this.outToSessiond
.write(data
, 0, data
.length
);
260 this.outToSessiond
.flush();
264 private String
getHomePath() {
265 return System
.getProperty("user.home");
269 * Read port number from file created by the session daemon.
271 * @return port value if found else 0.
273 private int getPortFromFile(String path
) throws IOException
{
278 br
= new BufferedReader(new FileReader(path
));
279 String line
= br
.readLine();
280 port
= Integer
.parseInt(line
, 10);
281 if (port
< 0 || port
> 65535) {
282 /* Invalid value. Ignore. */
286 } catch (FileNotFoundException e
) {
287 /* No port available. */
294 private void connectToSessiond() throws Exception
{
297 if (this.handler
.is_root
== 1) {
298 port
= getPortFromFile(rootPortFile
);
300 /* No session daemon available. Stop and retry later. */
301 throw new IOException();
304 port
= getPortFromFile(getHomePath() + userPortFile
);
306 /* No session daemon available. Stop and retry later. */
307 throw new IOException();
311 this.sessiondSock
= new Socket(this.sessiondHost
, port
);
312 this.inFromSessiond
= new DataInputStream(
313 sessiondSock
.getInputStream());
314 this.outToSessiond
= new DataOutputStream(
315 sessiondSock
.getOutputStream());
318 private void registerToSessiond() throws Exception
{
319 byte data
[] = new byte[8];
320 ByteBuffer buf
= ByteBuffer
.wrap(data
);
321 String pid
= ManagementFactory
.getRuntimeMXBean().getName().split("@")[0];
323 buf
.putInt(this.agent_domain
);
324 buf
.putInt(Integer
.parseInt(pid
));
325 this.outToSessiond
.write(data
, 0, data
.length
);
326 this.outToSessiond
.flush();