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