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