ust: change communication socket for STREAM
[ust.git] / libustcomm / ustcomm.c
CommitLineData
d0b5f2b9 1#define _GNU_SOURCE
f9e5ce61
PMF
2#include <sys/types.h>
3#include <signal.h>
4#include <errno.h>
5#include <sys/socket.h>
6#include <sys/un.h>
d0b5f2b9 7#include <unistd.h>
aca1ad90 8#include <poll.h>
f9e5ce61
PMF
9
10#include <stdio.h>
11#include <stdlib.h>
d0b5f2b9 12#include <string.h>
b0540e11 13#include <execinfo.h>
d0b5f2b9
PMF
14
15#include "ustcomm.h"
16#include "localerr.h"
f9e5ce61
PMF
17
18#define UNIX_PATH_MAX 108
19#define SOCK_DIR "/tmp/socks"
20#define UST_SIGNAL SIGIO
21
d0b5f2b9
PMF
22#define MSG_MAX 1000
23
aca1ad90
PMF
24/* FIXME: ustcomm blocks on message sending, which might be problematic in
25 * some cases. Fix the poll() usage so sends are buffered until they don't
26 * block.
27 */
28
3847c3ba
PMF
29//static void bt(void)
30//{
31// void *buffer[100];
32// int result;
33//
34// result = backtrace(&buffer, 100);
35// backtrace_symbols_fd(buffer, result, STDERR_FILENO);
36//}
b0540e11 37
f9e5ce61
PMF
38static void signal_process(pid_t pid)
39{
40 int result;
41
42 result = kill(pid, UST_SIGNAL);
43 if(result == -1) {
b0540e11 44 PERROR("kill");
f9e5ce61
PMF
45 return;
46 }
47
48 sleep(1);
49}
50
b0540e11 51int send_message_path(const char *path, const char *msg, char **reply, int signalpid)
f9e5ce61
PMF
52{
53 int fd;
54 int result;
55 struct sockaddr_un addr;
f9e5ce61 56
aca1ad90 57 result = fd = socket(PF_UNIX, SOCK_STREAM, 0);
f9e5ce61 58 if(result == -1) {
b0540e11 59 PERROR("socket");
d0b5f2b9 60 return -1;
f9e5ce61
PMF
61 }
62
63 addr.sun_family = AF_UNIX;
64
b0540e11 65 result = snprintf(addr.sun_path, UNIX_PATH_MAX, "%s", path);
f9e5ce61 66 if(result >= UNIX_PATH_MAX) {
b0540e11 67 ERR("string overflow allocating socket name");
d0b5f2b9 68 return -1;
f9e5ce61
PMF
69 }
70
b0540e11
PMF
71 if(signalpid >= 0)
72 signal_process(signalpid);
f9e5ce61 73
aca1ad90 74 result = connect(fd, (struct sockaddr *)&addr, sizeof(addr));
f9e5ce61 75 if(result == -1) {
aca1ad90
PMF
76 PERROR("connect");
77 return -1;
78 }
79
80 result = send(fd, msg, strlen(msg), 0);
81 if(result == -1) {
82 PERROR("send");
d0b5f2b9 83 return -1;
f9e5ce61
PMF
84 }
85
d0b5f2b9
PMF
86 if(!reply)
87 return 0;
88
89 *reply = (char *) malloc(MSG_MAX+1);
90 result = recvfrom(fd, *reply, MSG_MAX, 0, NULL, NULL);
91 if(result == -1) {
b0540e11 92 PERROR("recvfrom");
d0b5f2b9
PMF
93 return -1;
94 }
95
96 (*reply)[result] = '\0';
f9e5ce61
PMF
97
98 return 0;
99}
100
b0540e11
PMF
101/* pid: the pid of the trace process that must receive the msg
102 msg: pointer to a null-terminated message to send
103 reply: location where to put the null-terminated string of the reply;
104 it must be free'd after usage
105 */
106
107int send_message(pid_t pid, const char *msg, char **reply)
108{
109 int result;
110 char path[UNIX_PATH_MAX];
111
112 result = snprintf(path, UNIX_PATH_MAX, "%s/%d", SOCK_DIR, pid);
113 if(result >= UNIX_PATH_MAX) {
114 fprintf(stderr, "string overflow allocating socket name");
115 return -1;
116 }
117
118 send_message_path(path, msg, reply, pid);
119
120 return 0;
121}
122
123/* Called by an app to ask the consumer daemon to connect to it. */
124
125int ustcomm_request_consumer(pid_t pid, const char *channel)
126{
127 char path[UNIX_PATH_MAX];
128 int result;
129 char *msg;
130
131 result = snprintf(path, UNIX_PATH_MAX, "%s/ustd", SOCK_DIR);
132 if(result >= UNIX_PATH_MAX) {
133 fprintf(stderr, "string overflow allocating socket name");
134 return -1;
135 }
136
137 asprintf(&msg, "collect %d %s", pid, channel);
138
3847c3ba 139 send_message_path(path, msg, NULL, -1);
b0540e11
PMF
140 free(msg);
141
142 return 0;
143}
144
b02e31e5 145static int recv_message_fd(int fd, char **msg, struct ustcomm_source *src)
d0b5f2b9 146{
d0b5f2b9 147 int result;
d0b5f2b9
PMF
148
149 *msg = (char *) malloc(MSG_MAX+1);
b02e31e5 150
aca1ad90 151 result = recv(fd, *msg, MSG_MAX, 0);
d0b5f2b9
PMF
152 if(result == -1) {
153 PERROR("recvfrom");
154 return -1;
155 }
b0540e11 156
d0b5f2b9 157 (*msg)[result] = '\0';
b0540e11
PMF
158
159 DBG("ustcomm_app_recv_message: result is %d, message is %s", result, (*msg));
160
d0b5f2b9
PMF
161 return 0;
162}
163
b02e31e5 164int ustcomm_ustd_recv_message(struct ustcomm_ustd *ustd, char **msg, struct ustcomm_source *src)
b0540e11 165{
aca1ad90
PMF
166 struct pollfd *fds;
167 struct ustcomm_connection *conn;
168 int result;
169 int retval;
170
171 for(;;) {
172 int idx = 0;
173 int n_fds = 1;
174
175 list_for_each_entry(conn, &ustd->connections, list) {
176 n_fds++;
177 }
178
179 fds = (struct pollfd *) malloc(n_fds * sizeof(struct pollfd));
180 if(fds == NULL) {
181 ERR("malloc returned NULL");
182 return -1;
183 }
184
185 /* special idx 0 is for listening socket */
186 fds[idx].fd = ustd->listen_fd;
187 fds[idx].events = POLLIN;
188 idx++;
189
190 list_for_each_entry(conn, &ustd->connections, list) {
191 fds[idx].fd = conn->fd;
192 fds[idx].events = POLLIN;
193 idx++;
194 }
195
196 result = poll(fds, n_fds, -1);
197 if(result == -1) {
198 PERROR("poll");
199 return -1;
200 }
201
202 if(fds[0].revents) {
203 struct ustcomm_connection *newconn;
204 int newfd;
205
206 result = newfd = accept(ustd->listen_fd, NULL, NULL);
207 if(result == -1) {
208 PERROR("accept");
209 return -1;
210 }
211
212 newconn = (struct ustcomm_connection *) malloc(sizeof(struct ustcomm_connection));
213 if(newconn == NULL) {
214 ERR("malloc returned NULL");
215 return -1;
216 }
217
218 newconn->fd = newfd;
219
220 list_add(&newconn->list, &ustd->connections);
221 }
222
223 for(idx=1; idx<n_fds; idx++) {
224 if(fds[idx].revents) {
225 retval = recv_message_fd(fds[idx].fd, msg, src);
226 if(**msg == 0) {
227 /* connection finished */
228 close(fds[idx].fd);
229
230 list_for_each_entry(conn, &ustd->connections, list) {
231 if(conn->fd == fds[idx].fd) {
232 list_del(&conn->list);
233 break;
234 }
235 }
236 }
237 else {
238 goto free_fds_return;
239 }
240 }
241 }
242
243 free(fds);
244 }
245
246free_fds_return:
247 free(fds);
248 return retval;
b0540e11
PMF
249}
250
b02e31e5 251int ustcomm_app_recv_message(struct ustcomm_app *app, char **msg, struct ustcomm_source *src)
b0540e11 252{
aca1ad90 253 return ustcomm_ustd_recv_message((struct ustcomm_ustd *)app, msg, src);
b0540e11
PMF
254}
255
d0b5f2b9
PMF
256static int init_named_socket(char *name, char **path_out)
257{
258 int result;
259 int fd;
260
261 struct sockaddr_un addr;
262
aca1ad90 263 result = fd = socket(PF_UNIX, SOCK_STREAM, 0);
d0b5f2b9
PMF
264 if(result == -1) {
265 PERROR("socket");
266 return -1;
267 }
268
269 addr.sun_family = AF_UNIX;
270
271 strncpy(addr.sun_path, name, UNIX_PATH_MAX);
272 addr.sun_path[UNIX_PATH_MAX-1] = '\0';
273
aca1ad90
PMF
274 result = access(name, F_OK);
275 if(result == 0) {
276 /* file exists */
277 result = unlink(name);
278 if(result == -1) {
279 PERROR("unlink of socket file");
280 goto close_sock;
281 }
282 WARN("socket already exists; overwriting");
283 }
284
d0b5f2b9
PMF
285 result = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
286 if(result == -1) {
287 PERROR("bind");
288 goto close_sock;
289 }
290
aca1ad90
PMF
291 result = listen(fd, 1);
292 if(result == -1) {
293 PERROR("listen");
294 goto close_sock;
295 }
296
b0540e11
PMF
297 if(path_out) {
298 *path_out = "";
d0b5f2b9 299 *path_out = strdupa(addr.sun_path);
b0540e11 300 }
d0b5f2b9
PMF
301
302 return fd;
303
304 close_sock:
305 close(fd);
306
307 return -1;
308}
309
310int ustcomm_init_app(pid_t pid, struct ustcomm_app *handle)
311{
312 int result;
313 char *name;
314
315 result = asprintf(&name, "%s/%d", SOCK_DIR, (int)pid);
316 if(result >= UNIX_PATH_MAX) {
317 ERR("string overflow allocating socket name");
318 return -1;
319 }
320
aca1ad90
PMF
321 handle->listen_fd = init_named_socket(name, &(handle->socketpath));
322 if(handle->listen_fd < 0) {
323 ERR("error initializing named socket");
d0b5f2b9
PMF
324 goto free_name;
325 }
326 free(name);
327
aca1ad90
PMF
328 INIT_LIST_HEAD(&handle->connections);
329
d0b5f2b9
PMF
330 return 0;
331
332free_name:
333 free(name);
334 return -1;
335}
336
337int ustcomm_init_ustd(struct ustcomm_ustd *handle)
338{
3847c3ba
PMF
339 int result;
340 char *name;
341
342 result = asprintf(&name, "%s/%s", SOCK_DIR, "ustd");
343 if(result >= UNIX_PATH_MAX) {
344 ERR("string overflow allocating socket name");
345 return -1;
346 }
347
aca1ad90
PMF
348 handle->listen_fd = init_named_socket(name, &handle->socketpath);
349 if(handle->listen_fd < 0) {
350 ERR("error initializing named socket");
351 goto free_name;
352 }
3847c3ba 353 free(name);
d0b5f2b9 354
aca1ad90
PMF
355 INIT_LIST_HEAD(&handle->connections);
356
d0b5f2b9 357 return 0;
aca1ad90
PMF
358
359free_name:
360 free(name);
361 return -1;
d0b5f2b9 362}
b02e31e5 363
aca1ad90 364static char *find_tok(char *str)
b02e31e5
PMF
365{
366 while(*str == ' ') {
367 str++;
368
369 if(*str == 0)
370 return NULL;
371 }
372
373 return str;
374}
375
376static char *find_sep(char *str)
377{
378 while(*str != ' ') {
379 str++;
380
381 if(*str == 0)
382 break;
383 }
384
385 return str;
386}
387
388int nth_token_is(char *str, char *token, int tok_no)
389{
390 int i;
391 char *start;
392 char *end;
393
394 for(i=0; i<=tok_no; i++) {
395 str = find_tok(str);
396 if(str == NULL)
397 return -1;
398
399 start = str;
400
401 str = find_sep(str);
402 if(str == NULL)
403 return -1;
404
405 end = str;
406 }
407
408 if(end-start != strlen(token))
409 return 0;
410
411 if(strncmp(start, token, end-start))
412 return 0;
413
414 return 1;
415}
416
417char *nth_token(char *str, int tok_no)
418{
419 static char *retval = NULL;
420 int i;
421 char *start;
422 char *end;
423
424 for(i=0; i<=tok_no; i++) {
425 str = find_tok(str);
426 if(str == NULL)
427 return NULL;
428
429 start = str;
430
431 str = find_sep(str);
432 if(str == NULL)
433 return NULL;
434
435 end = str;
436 }
437
438 if(retval) {
439 free(retval);
440 retval = NULL;
441 }
442
aca1ad90 443 asprintf(&retval, "%.*s", (int)(end-start), start);
b02e31e5
PMF
444
445 return retval;
446}
447
This page took 0.040739 seconds and 4 git commands to generate.