861c7340a62480087ae83332ad541e7ce9484777
[lttng-ust.git] / liblttng-ust-jul / org / lttng / ust / jul / LTTngTCPSessiondClient.java
1 /*
2 * Copyright (C) 2013 - David Goulet <dgoulet@efficios.com>
3 *
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.
7 *
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
11 * for more details.
12 *
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
16 */
17
18 package org.lttng.ust.jul;
19
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;
32 import java.net.*;
33 import java.lang.management.ManagementFactory;
34 import java.util.logging.Logger;
35
36 class USTRegisterMsg {
37 public static int pid;
38 }
39
40 public class LTTngTCPSessiondClient {
41 /* Command header from the session deamon. */
42 private LTTngSessiondCmd2_4.sessiond_hdr headerCmd =
43 new LTTngSessiondCmd2_4.sessiond_hdr();
44
45 private final String sessiondHost;
46 private Socket sessiondSock;
47 private boolean quit = false;
48
49 private DataInputStream inFromSessiond;
50 private DataOutputStream outToSessiond;
51
52 private LTTngLogHandler handler;
53
54 private Semaphore registerSem;
55
56 private static final String rootPortFile = "/var/run/lttng/jul.port";
57 private static final String userPortFile = "/.lttng/jul.port";
58
59 /* Indicate if we've already release the semaphore. */
60 private boolean sem_posted = false;
61
62 public LTTngTCPSessiondClient(String host, Semaphore sem) {
63 this.sessiondHost = host;
64 this.registerSem = sem;
65 }
66
67 /*
68 * Try to release the registerSem if it's not already done.
69 */
70 private void tryReleaseSem()
71 {
72 /* Release semaphore so we unblock the agent. */
73 if (!this.sem_posted) {
74 this.registerSem.release();
75 this.sem_posted = true;
76 }
77 }
78
79 /*
80 * Cleanup Agent state.
81 */
82 private void cleanupState() {
83 if (this.handler != null) {
84 this.handler.clear();
85 }
86 }
87
88 public void init(LTTngLogHandler handler) throws InterruptedException {
89 this.handler = handler;
90
91 for (;;) {
92 if (this.quit) {
93 break;
94 }
95
96 /* Cleanup Agent state before trying to connect or reconnect. */
97 cleanupState();
98
99 try {
100
101 /*
102 * Connect to the session daemon before anything else.
103 */
104 connectToSessiond();
105
106 /*
107 * Register to the session daemon as the Java component of the
108 * UST application.
109 */
110 registerToSessiond();
111
112 /*
113 * Block on socket receive and wait for command from the
114 * session daemon. This will return if and only if there is a
115 * fatal error or the socket closes.
116 */
117 handleSessiondCmd();
118 } catch (UnknownHostException uhe) {
119 tryReleaseSem();
120 System.out.println(uhe);
121 } catch (IOException ioe) {
122 tryReleaseSem();
123 Thread.sleep(3000);
124 } catch (Exception e) {
125 tryReleaseSem();
126 e.printStackTrace();
127 }
128 }
129 }
130
131 public void destroy() {
132 this.quit = true;
133
134 try {
135 if (this.sessiondSock != null) {
136 this.sessiondSock.close();
137 }
138 } catch (Exception e) {
139 e.printStackTrace();
140 }
141 }
142
143 /*
144 * Receive header data from the session daemon using the LTTng command
145 * static buffer of the right size.
146 */
147 private void recvHeader() throws Exception {
148 int read_len;
149 byte data[] = new byte[this.headerCmd.SIZE];
150
151 read_len = this.inFromSessiond.read(data, 0, data.length);
152 if (read_len != data.length) {
153 throw new IOException();
154 }
155 this.headerCmd.populate(data);
156 }
157
158 /*
159 * Receive payload from the session daemon. This MUST be done after a
160 * recvHeader() so the header value of a command are known.
161 *
162 * The caller SHOULD use isPayload() before which returns true if a payload
163 * is expected after the header.
164 */
165 private byte[] recvPayload() throws Exception {
166 byte payload[] = new byte[(int) this.headerCmd.data_size];
167
168 /* Failsafe check so we don't waste our time reading 0 bytes. */
169 if (payload.length == 0) {
170 return null;
171 }
172
173 this.inFromSessiond.read(payload, 0, payload.length);
174 return payload;
175 }
176
177 /*
178 * Handle session command from the session daemon.
179 */
180 private void handleSessiondCmd() throws Exception {
181 int ret_code;
182 byte data[] = null;
183
184 while (true) {
185 /* Get header from session daemon. */
186 recvHeader();
187
188 if (headerCmd.data_size > 0) {
189 data = recvPayload();
190 }
191
192 switch (headerCmd.cmd) {
193 case CMD_REG_DONE:
194 {
195 /*
196 * Release semaphore so meaning registration is done and we
197 * can proceed to continue tracing.
198 */
199 tryReleaseSem();
200 /*
201 * We don't send any reply to the registration done command.
202 * This just marks the end of the initial session setup.
203 */
204 continue;
205 }
206 case CMD_LIST:
207 {
208 LTTngSessiondCmd2_4.sessiond_list_logger listLoggerCmd =
209 new LTTngSessiondCmd2_4.sessiond_list_logger();
210 listLoggerCmd.execute(this.handler);
211 data = listLoggerCmd.getBytes();
212 break;
213 }
214 case CMD_ENABLE:
215 {
216 LTTngEvent event;
217 LTTngSessiondCmd2_4.sessiond_enable_handler enableCmd =
218 new LTTngSessiondCmd2_4.sessiond_enable_handler();
219 if (data == null) {
220 enableCmd.code = LTTngSessiondCmd2_4.lttng_jul_ret_code.CODE_INVALID_CMD;
221 break;
222 }
223 enableCmd.populate(data);
224 enableCmd.execute(this.handler);
225 data = enableCmd.getBytes();
226 break;
227 }
228 case CMD_DISABLE:
229 {
230 LTTngSessiondCmd2_4.sessiond_disable_handler disableCmd =
231 new LTTngSessiondCmd2_4.sessiond_disable_handler();
232 if (data == null) {
233 disableCmd.code = LTTngSessiondCmd2_4.lttng_jul_ret_code.CODE_INVALID_CMD;
234 break;
235 }
236 disableCmd.populate(data);
237 disableCmd.execute(this.handler);
238 data = disableCmd.getBytes();
239 break;
240 }
241 default:
242 {
243 data = new byte[4];
244 ByteBuffer buf = ByteBuffer.wrap(data);
245 buf.order(ByteOrder.BIG_ENDIAN);
246 LTTngSessiondCmd2_4.lttng_jul_ret_code code =
247 LTTngSessiondCmd2_4.lttng_jul_ret_code.CODE_INVALID_CMD;
248 buf.putInt(code.getCode());
249 break;
250 }
251 }
252
253 /* Send payload to session daemon. */
254 this.outToSessiond.write(data, 0, data.length);
255 this.outToSessiond.flush();
256 }
257 }
258
259 private String getHomePath() {
260 return System.getProperty("user.home");
261 }
262
263 /**
264 * Read port number from file created by the session daemon.
265 *
266 * @return port value if found else 0.
267 */
268 private int getPortFromFile(String path) throws IOException {
269 int port;
270 BufferedReader br;
271
272 try {
273 br = new BufferedReader(new FileReader(path));
274 String line = br.readLine();
275 port = Integer.parseInt(line, 10);
276 if (port < 0 || port > 65535) {
277 /* Invalid value. Ignore. */
278 port = 0;
279 }
280 br.close();
281 } catch (FileNotFoundException e) {
282 /* No port available. */
283 port = 0;
284 }
285
286 return port;
287 }
288
289 private void connectToSessiond() throws Exception {
290 int port;
291
292 if (this.handler.is_root == 1) {
293 port = getPortFromFile(rootPortFile);
294 if (port == 0) {
295 /* No session daemon available. Stop and retry later. */
296 throw new IOException();
297 }
298 } else {
299 port = getPortFromFile(getHomePath() + userPortFile);
300 if (port == 0) {
301 /* No session daemon available. Stop and retry later. */
302 throw new IOException();
303 }
304 }
305
306 this.sessiondSock = new Socket(this.sessiondHost, port);
307 this.inFromSessiond = new DataInputStream(
308 sessiondSock.getInputStream());
309 this.outToSessiond = new DataOutputStream(
310 sessiondSock.getOutputStream());
311 }
312
313 private void registerToSessiond() throws Exception {
314 byte data[] = new byte[4];
315 ByteBuffer buf = ByteBuffer.wrap(data);
316 String pid = ManagementFactory.getRuntimeMXBean().getName().split("@")[0];
317
318 buf.putInt(Integer.parseInt(pid));
319 this.outToSessiond.write(data, 0, data.length);
320 this.outToSessiond.flush();
321 }
322 }
This page took 0.038936 seconds and 3 git commands to generate.