Fix: Relayd and sessiond version check
[lttng-tools.git] / src / common / relayd / relayd.c
1 /*
2 * Copyright (C) 2012 - David Goulet <dgoulet@efficios.com>
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License, version 2 only, as
6 * published by the Free Software Foundation.
7 *
8 * This program 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 General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License along with
14 * this program; if not, write to the Free Software Foundation, Inc., 51
15 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16 */
17
18 #define _GNU_SOURCE
19 #include <assert.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <sys/stat.h>
24 #include <inttypes.h>
25
26 #include <common/common.h>
27 #include <common/defaults.h>
28 #include <common/sessiond-comm/relayd.h>
29
30 #include "relayd.h"
31
32 /*
33 * Send command. Fill up the header and append the data.
34 */
35 static int send_command(struct lttcomm_sock *sock,
36 enum lttcomm_sessiond_command cmd, void *data, size_t size,
37 int flags)
38 {
39 int ret;
40 struct lttcomm_relayd_hdr header;
41 char *buf;
42 uint64_t buf_size = sizeof(header);
43
44 if (data) {
45 buf_size += size;
46 }
47
48 buf = zmalloc(buf_size);
49 if (buf == NULL) {
50 PERROR("zmalloc relayd send command buf");
51 ret = -1;
52 goto alloc_error;
53 }
54
55 header.cmd = htobe32(cmd);
56 header.data_size = htobe64(size);
57
58 /* Zeroed for now since not used. */
59 header.cmd_version = 0;
60 header.circuit_id = 0;
61
62 /* Prepare buffer to send. */
63 memcpy(buf, &header, sizeof(header));
64 if (data) {
65 memcpy(buf + sizeof(header), data, size);
66 }
67
68 ret = sock->ops->sendmsg(sock, buf, buf_size, flags);
69 if (ret < 0) {
70 ret = -errno;
71 goto error;
72 }
73
74 DBG3("Relayd sending command %d of size %" PRIu64, cmd, buf_size);
75
76 error:
77 free(buf);
78 alloc_error:
79 return ret;
80 }
81
82 /*
83 * Receive reply data on socket. This MUST be call after send_command or else
84 * could result in unexpected behavior(s).
85 */
86 static int recv_reply(struct lttcomm_sock *sock, void *data, size_t size)
87 {
88 int ret;
89
90 DBG3("Relayd waiting for reply of size %ld", size);
91
92 ret = sock->ops->recvmsg(sock, data, size, 0);
93 if (ret < 0) {
94 ret = -errno;
95 goto error;
96 }
97
98 error:
99 return ret;
100 }
101
102 /*
103 * Add stream on the relayd and assign stream handle to the stream_id argument.
104 *
105 * On success return 0 else return ret_code negative value.
106 */
107 int relayd_add_stream(struct lttcomm_sock *sock, const char *channel_name,
108 const char *pathname, uint64_t *stream_id)
109 {
110 int ret;
111 struct lttcomm_relayd_add_stream msg;
112 struct lttcomm_relayd_status_stream reply;
113
114 /* Code flow error. Safety net. */
115 assert(sock);
116 assert(channel_name);
117 assert(pathname);
118
119 DBG("Relayd adding stream for channel name %s", channel_name);
120
121 strncpy(msg.channel_name, channel_name, sizeof(msg.channel_name));
122 strncpy(msg.pathname, pathname, sizeof(msg.pathname));
123
124 /* Send command */
125 ret = send_command(sock, RELAYD_ADD_STREAM, (void *) &msg, sizeof(msg), 0);
126 if (ret < 0) {
127 goto error;
128 }
129
130 /* Waiting for reply */
131 ret = recv_reply(sock, (void *) &reply, sizeof(reply));
132 if (ret < 0) {
133 goto error;
134 }
135
136 /* Back to host bytes order. */
137 reply.handle = be64toh(reply.handle);
138 reply.ret_code = be32toh(reply.ret_code);
139
140 /* Return session id or negative ret code. */
141 if (reply.ret_code != LTTNG_OK) {
142 ret = -reply.ret_code;
143 ERR("Relayd add stream replied error %d", ret);
144 } else {
145 /* Success */
146 ret = 0;
147 *stream_id = reply.handle;
148 }
149
150 DBG("Relayd stream added successfully with handle %" PRIu64,
151 reply.handle);
152
153 error:
154 return ret;
155 }
156
157 /*
158 * Check version numbers on the relayd.
159 *
160 * Return 0 if compatible else negative value.
161 */
162 int relayd_version_check(struct lttcomm_sock *sock, uint32_t major,
163 uint32_t minor)
164 {
165 int ret;
166 struct lttcomm_relayd_version msg;
167
168 /* Code flow error. Safety net. */
169 assert(sock);
170
171 DBG("Relayd version check for major.minor %u.%u", major, minor);
172
173 /* Prepare network byte order before transmission. */
174 msg.major = htobe32(major);
175 msg.minor = htobe32(minor);
176
177 /* Send command */
178 ret = send_command(sock, RELAYD_VERSION, (void *) &msg, sizeof(msg), 0);
179 if (ret < 0) {
180 goto error;
181 }
182
183 /* Recevie response */
184 ret = recv_reply(sock, (void *) &msg, sizeof(msg));
185 if (ret < 0) {
186 goto error;
187 }
188
189 /* Set back to host bytes order */
190 msg.major = be32toh(msg.major);
191 msg.minor = be32toh(msg.minor);
192
193 /*
194 * Only validate the major version. If the other side is higher,
195 * communication is not possible. Only major version equal can talk to each
196 * other. If the minor version differs, the lowest version is used by both
197 * sides.
198 *
199 * For now, before 2.1.0 stable release, we don't have to check the minor
200 * because this new mechanism with the relayd will only be available with
201 * 2.1 and NOT 2.0.x.
202 */
203 if (msg.major == major) {
204 /* Compatible */
205 ret = 0;
206 DBG2("Relayd version is compatible");
207 goto error;
208 }
209
210 /*
211 * After 2.1.0 release, for the 2.2 release, at this point will have to
212 * check the minor version in order for the session daemon to know which
213 * structure to use to communicate with the relayd. If the relayd's minor
214 * version is higher, it will adapt to our version so we can continue to
215 * use the latest relayd communication data structure.
216 */
217
218 /* Version number not compatible */
219 DBG2("Relayd version is NOT compatible. Relayd version %u != %u (us)",
220 msg.major, major);
221 ret = -1;
222
223 error:
224 return ret;
225 }
226
227 /*
228 * Add stream on the relayd and assign stream handle to the stream_id argument.
229 *
230 * On success return 0 else return ret_code negative value.
231 */
232 int relayd_send_metadata(struct lttcomm_sock *sock, size_t len)
233 {
234 int ret;
235
236 /* Code flow error. Safety net. */
237 assert(sock);
238
239 DBG("Relayd sending metadata of size %zu", len);
240
241 /* Send command */
242 ret = send_command(sock, RELAYD_SEND_METADATA, NULL, len, 0);
243 if (ret < 0) {
244 goto error;
245 }
246
247 DBG2("Relayd metadata added successfully");
248
249 /*
250 * After that call, the metadata data MUST be sent to the relayd so the
251 * receive size on the other end matches the len of the metadata packet
252 * header. This is why we don't wait for a reply here.
253 */
254
255 error:
256 return ret;
257 }
258
259 /*
260 * Connect to relay daemon with an allocated lttcomm_sock.
261 */
262 int relayd_connect(struct lttcomm_sock *sock)
263 {
264 /* Code flow error. Safety net. */
265 assert(sock);
266
267 DBG3("Relayd connect ...");
268
269 return sock->ops->connect(sock);
270 }
271
272 /*
273 * Close relayd socket with an allocated lttcomm_sock.
274 */
275 int relayd_close(struct lttcomm_sock *sock)
276 {
277 /* Code flow error. Safety net. */
278 assert(sock);
279
280 DBG3("Relayd closing socket %d", sock->fd);
281
282 return sock->ops->close(sock);
283 }
284
285 /*
286 * Send data header structure to the relayd.
287 */
288 int relayd_send_data_hdr(struct lttcomm_sock *sock,
289 struct lttcomm_relayd_data_hdr *hdr, size_t size)
290 {
291 int ret;
292
293 /* Code flow error. Safety net. */
294 assert(sock);
295 assert(hdr);
296
297 DBG3("Relayd sending data header of size %ld", size);
298
299 /* Again, safety net */
300 if (size == 0) {
301 size = sizeof(struct lttcomm_relayd_data_hdr);
302 }
303
304 /* Only send data header. */
305 ret = sock->ops->sendmsg(sock, hdr, size, 0);
306 if (ret < 0) {
307 ret = -errno;
308 goto error;
309 }
310
311 /*
312 * The data MUST be sent right after that command for the receive on the
313 * other end to match the size in the header.
314 */
315
316 error:
317 return ret;
318 }
319
320 /*
321 * Send close stream command to the relayd.
322 */
323 int relayd_send_close_stream(struct lttcomm_sock *sock, uint64_t stream_id,
324 uint64_t last_net_seq_num)
325 {
326 int ret;
327 struct lttcomm_relayd_close_stream msg;
328 struct lttcomm_relayd_generic_reply reply;
329
330 /* Code flow error. Safety net. */
331 assert(sock);
332
333 DBG("Relayd closing stream id %" PRIu64, stream_id);
334
335 msg.stream_id = htobe64(stream_id);
336 msg.last_net_seq_num = htobe64(last_net_seq_num);
337
338 /* Send command */
339 ret = send_command(sock, RELAYD_CLOSE_STREAM, (void *) &msg, sizeof(msg), 0);
340 if (ret < 0) {
341 goto error;
342 }
343
344 /* Recevie response */
345 ret = recv_reply(sock, (void *) &reply, sizeof(reply));
346 if (ret < 0) {
347 goto error;
348 }
349
350 reply.ret_code = be32toh(reply.ret_code);
351
352 /* Return session id or negative ret code. */
353 if (reply.ret_code != LTTNG_OK) {
354 ret = -reply.ret_code;
355 ERR("Relayd close stream replied error %d", ret);
356 } else {
357 /* Success */
358 ret = 0;
359 }
360
361 DBG("Relayd close stream id %" PRIu64 " successfully", stream_id);
362
363 error:
364 return ret;
365 }
366
367 /*
368 * Check for data availability for a given stream id.
369 *
370 * Return 0 if NOT pending, 1 if so and a negative value on error.
371 */
372 int relayd_data_pending(struct lttcomm_sock *sock, uint64_t stream_id,
373 uint64_t last_net_seq_num)
374 {
375 int ret;
376 struct lttcomm_relayd_data_pending msg;
377 struct lttcomm_relayd_generic_reply reply;
378
379 /* Code flow error. Safety net. */
380 assert(sock);
381
382 DBG("Relayd data pending for stream id %" PRIu64, stream_id);
383
384 msg.stream_id = htobe64(stream_id);
385 msg.last_net_seq_num = htobe64(last_net_seq_num);
386
387 /* Send command */
388 ret = send_command(sock, RELAYD_DATA_PENDING, (void *) &msg,
389 sizeof(msg), 0);
390 if (ret < 0) {
391 goto error;
392 }
393
394 /* Recevie response */
395 ret = recv_reply(sock, (void *) &reply, sizeof(reply));
396 if (ret < 0) {
397 goto error;
398 }
399
400 reply.ret_code = be32toh(reply.ret_code);
401
402 /* Return session id or negative ret code. */
403 if (reply.ret_code >= LTTNG_OK) {
404 ret = -reply.ret_code;
405 ERR("Relayd data pending replied error %d", ret);
406 }
407
408 /* At this point, the ret code is either 1 or 0 */
409 ret = reply.ret_code;
410
411 DBG("Relayd data is %s pending for stream id %" PRIu64,
412 ret == 1 ? "NOT" : "", stream_id);
413
414 error:
415 return ret;
416 }
417
418 /*
419 * Check on the relayd side for a quiescent state on the control socket.
420 */
421 int relayd_quiescent_control(struct lttcomm_sock *sock)
422 {
423 int ret;
424 struct lttcomm_relayd_generic_reply reply;
425
426 /* Code flow error. Safety net. */
427 assert(sock);
428
429 DBG("Relayd checking quiescent control state");
430
431 /* Send command */
432 ret = send_command(sock, RELAYD_QUIESCENT_CONTROL, NULL, 0, 0);
433 if (ret < 0) {
434 goto error;
435 }
436
437 /* Recevie response */
438 ret = recv_reply(sock, (void *) &reply, sizeof(reply));
439 if (ret < 0) {
440 goto error;
441 }
442
443 reply.ret_code = be32toh(reply.ret_code);
444
445 /* Return session id or negative ret code. */
446 if (reply.ret_code != LTTNG_OK) {
447 ret = -reply.ret_code;
448 ERR("Relayd quiescent control replied error %d", ret);
449 goto error;
450 }
451
452 /* Control socket is quiescent */
453 return 0;
454
455 error:
456 return ret;
457 }
This page took 0.038347 seconds and 4 git commands to generate.