c4282995194ff550969ee6466d2758bc49a97275
[lttng-tools.git] / src / lib / lttng-ctl / channel.c
1 /*
2 * Copyright (C) 2017 - Jérémie Galarneau <jeremie.galarneau@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 #include <lttng/notification/notification-internal.h>
19 #include <lttng/notification/channel-internal.h>
20 #include <lttng/condition/condition-internal.h>
21 #include <lttng/endpoint.h>
22 #include <common/error.h>
23 #include <common/dynamic-buffer.h>
24 #include <common/utils.h>
25 #include <common/defaults.h>
26 #include <assert.h>
27 #include "lttng-ctl-helper.h"
28
29 struct lttng_notification_channel *lttng_notification_channel_create(
30 struct lttng_endpoint *endpoint)
31 {
32 int fd, ret;
33 bool is_in_tracing_group = false, is_root = false;
34 char *sock_path = NULL;
35 struct lttng_notification_channel *channel = NULL;
36
37 if (!endpoint ||
38 endpoint != lttng_session_daemon_notification_endpoint) {
39 goto end;
40 }
41
42 sock_path = zmalloc(LTTNG_PATH_MAX);
43 if (!sock_path) {
44 goto end;
45 }
46
47 channel = zmalloc(sizeof(struct lttng_notification_channel));
48 if (!channel) {
49 goto end;
50 }
51 channel->socket = -1;
52
53 is_root = (getuid() == 0);
54 if (!is_root) {
55 is_in_tracing_group = lttng_check_tracing_group();
56 }
57
58 if (is_root || is_in_tracing_group) {
59 lttng_ctl_copy_string(sock_path,
60 DEFAULT_GLOBAL_NOTIFICATION_CHANNEL_UNIX_SOCK,
61 LTTNG_PATH_MAX);
62 ret = lttcomm_connect_unix_sock(sock_path);
63 if (ret >= 0) {
64 fd = ret;
65 goto set_fd;
66 }
67 }
68
69 /* Fallback to local session daemon. */
70 ret = snprintf(sock_path, LTTNG_PATH_MAX,
71 DEFAULT_HOME_NOTIFICATION_CHANNEL_UNIX_SOCK,
72 utils_get_home_dir());
73 if (ret < 0 || ret >= LTTNG_PATH_MAX) {
74 goto error;
75 }
76
77 ret = lttcomm_connect_unix_sock(sock_path);
78 if (ret < 0) {
79 goto error;
80 }
81 fd = ret;
82
83 set_fd:
84 channel->socket = fd;
85
86 /* FIXME send creds */
87 end:
88 free(sock_path);
89 return channel;
90 error:
91 lttng_notification_channel_destroy(channel);
92 channel = NULL;
93 goto end;
94 }
95
96 enum lttng_notification_channel_status
97 lttng_notification_channel_get_next_notification(
98 struct lttng_notification_channel *channel,
99 struct lttng_notification **_notification)
100 {
101 ssize_t ret;
102 struct lttng_notification_comm comm;
103 struct lttng_notification *notification = NULL;
104 struct lttng_dynamic_buffer reception_buffer;
105 struct lttng_notification_channel_message msg;
106 enum lttng_notification_channel_status status =
107 LTTNG_NOTIFICATION_CHANNEL_STATUS_OK;
108
109 lttng_dynamic_buffer_init(&reception_buffer);
110
111 if (!channel || !_notification) {
112 status = LTTNG_NOTIFICATION_CHANNEL_STATUS_INVALID;
113 goto end;
114 }
115
116 ret = lttcomm_recv_unix_sock(channel->socket, &msg, sizeof(msg));
117 if (ret <= 0) {
118 status = LTTNG_NOTIFICATION_CHANNEL_STATUS_ERROR;
119 goto end;
120 }
121 if (msg.type != LTTNG_NOTIFICATION_CHANNEL_MESSAGE_TYPE_NOTIFICATION) {
122 status = LTTNG_NOTIFICATION_CHANNEL_STATUS_ERROR;
123 goto end;
124 }
125
126 ret = lttcomm_recv_unix_sock(channel->socket, &comm, sizeof(comm));
127 if (ret < sizeof(comm)) {
128 status = LTTNG_NOTIFICATION_CHANNEL_STATUS_ERROR;
129 goto end;
130 }
131
132 ret = lttng_dynamic_buffer_set_size(&reception_buffer,
133 comm.length + sizeof(comm));
134 if (ret) {
135 status = LTTNG_NOTIFICATION_CHANNEL_STATUS_ERROR;
136 goto end;
137 }
138
139 memcpy(reception_buffer.data, &comm, sizeof(comm));
140 ret = lttcomm_recv_unix_sock(channel->socket,
141 reception_buffer.data + sizeof(comm),
142 comm.length);
143 if (ret < (ssize_t) comm.length) {
144 status = LTTNG_NOTIFICATION_CHANNEL_STATUS_ERROR;
145 goto end;
146 }
147
148 ret = lttng_notification_create_from_buffer(reception_buffer.data,
149 &notification);
150 if (ret != (sizeof(comm) + (ssize_t) comm.length)) {
151 status = LTTNG_NOTIFICATION_CHANNEL_STATUS_ERROR;
152 goto error;
153 }
154 *_notification = notification;
155 end:
156 lttng_dynamic_buffer_reset(&reception_buffer);
157 return status;
158 error:
159 lttng_notification_destroy(notification);
160 goto end;
161 }
162
163 static
164 enum lttng_notification_channel_status send_command(
165 struct lttng_notification_channel *channel,
166 enum lttng_notification_channel_message_type type,
167 struct lttng_condition *condition)
168 {
169 int socket;
170 ssize_t command_size, ret;
171 size_t received = 0;
172 enum lttng_notification_channel_status status =
173 LTTNG_NOTIFICATION_CHANNEL_STATUS_OK;
174 char *command_buffer = NULL;
175 struct lttng_notification_channel_message cmd_message = {
176 .type = type,
177 };
178 struct lttng_notification_channel_message reply_message;
179 struct lttng_notification_channel_command_reply reply;
180
181 if (!channel) {
182 status = LTTNG_NOTIFICATION_CHANNEL_STATUS_INVALID;
183 goto end;
184 }
185
186 socket = channel->socket;
187 if (!lttng_condition_validate(condition)) {
188 status = LTTNG_NOTIFICATION_CHANNEL_STATUS_INVALID;
189 goto end;
190 }
191
192 ret = lttng_condition_serialize(condition, NULL);
193 if (ret < 0) {
194 status = LTTNG_NOTIFICATION_CHANNEL_STATUS_INVALID;
195 goto end;
196 }
197 assert(ret < UINT32_MAX);
198 cmd_message.size = (uint32_t) ret;
199 command_size = ret + sizeof(
200 struct lttng_notification_channel_message);
201 command_buffer = zmalloc(command_size);
202 if (!command_buffer) {
203 goto end;
204 }
205
206 memcpy(command_buffer, &cmd_message, sizeof(cmd_message));
207 ret = lttng_condition_serialize(condition,
208 command_buffer + sizeof(cmd_message));
209 if (ret < 0) {
210 goto end;
211 }
212
213 ret = lttcomm_send_unix_sock(socket, command_buffer, command_size);
214 if (ret < 0) {
215 status = LTTNG_NOTIFICATION_CHANNEL_STATUS_ERROR;
216 goto end;
217 }
218
219 /* Receive command reply header. */
220 do {
221 ret = lttcomm_recv_unix_sock(socket,
222 ((char *) &reply_message) + received,
223 sizeof(reply_message) - received);
224 if (ret <= 0) {
225 status = LTTNG_NOTIFICATION_CHANNEL_STATUS_ERROR;
226 goto end;
227 }
228 received += ret;
229 } while (received < sizeof(reply_message));
230 if (reply_message.type !=
231 LTTNG_NOTIFICATION_CHANNEL_MESSAGE_TYPE_COMMAND_REPLY ||
232 reply_message.size != sizeof(reply)) {
233 status = LTTNG_NOTIFICATION_CHANNEL_STATUS_ERROR;
234 goto end;
235 }
236
237 /* Receive command reply payload. */
238 received = 0;
239 do {
240 ret = lttcomm_recv_unix_sock(socket,
241 ((char *) &reply) + received,
242 sizeof(reply) - received);
243 if (ret <= 0) {
244 status = LTTNG_NOTIFICATION_CHANNEL_STATUS_ERROR;
245 goto end;
246 }
247 received += ret;
248 } while (received < sizeof(reply));
249 status = (enum lttng_notification_channel_status) reply.status;
250 end:
251 free(command_buffer);
252 return status;
253 }
254
255 enum lttng_notification_channel_status lttng_notification_channel_subscribe(
256 struct lttng_notification_channel *channel,
257 struct lttng_condition *condition)
258 {
259 return send_command(channel,
260 LTTNG_NOTIFICATION_CHANNEL_MESSAGE_TYPE_SUBSCRIBE,
261 condition);
262 }
263
264 enum lttng_notification_channel_status lttng_notification_channel_unsubscribe(
265 struct lttng_notification_channel *channel,
266 struct lttng_condition *condition)
267 {
268 return send_command(channel,
269 LTTNG_NOTIFICATION_CHANNEL_MESSAGE_TYPE_UNSUBSCRIBE,
270 condition);
271 }
272
273 void lttng_notification_channel_destroy(
274 struct lttng_notification_channel *channel)
275 {
276 if (!channel) {
277 return;
278 }
279
280 if (channel->socket >= 0) {
281 (void) lttcomm_close_unix_sock(channel->socket);
282 }
283 free(channel);
284 }
285
This page took 0.036157 seconds and 5 git commands to generate.