2773b1a0a4fc7c299a95e3a6897a993c5eefbb60
[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_path(const char *path, const char *msg, char **reply, int signalpid)
52 {
53 int fd;
54 int result;
55 struct sockaddr_un addr;
56
57 result = fd = socket(PF_UNIX, SOCK_STREAM, 0);
58 if(result == -1) {
59 PERROR("socket");
60 return -1;
61 }
62
63 addr.sun_family = AF_UNIX;
64
65 result = snprintf(addr.sun_path, UNIX_PATH_MAX, "%s", path);
66 if(result >= UNIX_PATH_MAX) {
67 ERR("string overflow allocating socket name");
68 return -1;
69 }
70
71 if(signalpid >= 0)
72 signal_process(signalpid);
73
74 result = connect(fd, (struct sockaddr *)&addr, sizeof(addr));
75 if(result == -1) {
76 PERROR("connect");
77 return -1;
78 }
79
80 result = send(fd, msg, strlen(msg), 0);
81 if(result == -1) {
82 PERROR("send");
83 return -1;
84 }
85
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) {
92 PERROR("recvfrom");
93 return -1;
94 }
95
96 (*reply)[result] = '\0';
97
98 return 0;
99 }
100
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
107 int 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
125 int 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
139 send_message_path(path, msg, NULL, -1);
140 free(msg);
141
142 return 0;
143 }
144
145 static int recv_message_fd(int fd, char **msg, struct ustcomm_source *src)
146 {
147 int result;
148
149 *msg = (char *) malloc(MSG_MAX+1);
150
151 result = recv(fd, *msg, MSG_MAX, 0);
152 if(result == -1) {
153 PERROR("recvfrom");
154 return -1;
155 }
156
157 (*msg)[result] = '\0';
158
159 DBG("ustcomm_app_recv_message: result is %d, message is %s", result, (*msg));
160
161 return 0;
162 }
163
164 int ustcomm_ustd_recv_message(struct ustcomm_ustd *ustd, char **msg, struct ustcomm_source *src)
165 {
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
246 free_fds_return:
247 free(fds);
248 return retval;
249 }
250
251 int ustcomm_app_recv_message(struct ustcomm_app *app, char **msg, struct ustcomm_source *src)
252 {
253 return ustcomm_ustd_recv_message((struct ustcomm_ustd *)app, msg, src);
254 }
255
256 static int init_named_socket(char *name, char **path_out)
257 {
258 int result;
259 int fd;
260
261 struct sockaddr_un addr;
262
263 result = fd = socket(PF_UNIX, SOCK_STREAM, 0);
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
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
285 result = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
286 if(result == -1) {
287 PERROR("bind");
288 goto close_sock;
289 }
290
291 result = listen(fd, 1);
292 if(result == -1) {
293 PERROR("listen");
294 goto close_sock;
295 }
296
297 if(path_out) {
298 *path_out = "";
299 *path_out = strdupa(addr.sun_path);
300 }
301
302 return fd;
303
304 close_sock:
305 close(fd);
306
307 return -1;
308 }
309
310 int 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
321 handle->listen_fd = init_named_socket(name, &(handle->socketpath));
322 if(handle->listen_fd < 0) {
323 ERR("error initializing named socket");
324 goto free_name;
325 }
326 free(name);
327
328 INIT_LIST_HEAD(&handle->connections);
329
330 return 0;
331
332 free_name:
333 free(name);
334 return -1;
335 }
336
337 int ustcomm_init_ustd(struct ustcomm_ustd *handle)
338 {
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
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 }
353 free(name);
354
355 INIT_LIST_HEAD(&handle->connections);
356
357 return 0;
358
359 free_name:
360 free(name);
361 return -1;
362 }
363
364 static char *find_tok(char *str)
365 {
366 while(*str == ' ') {
367 str++;
368
369 if(*str == 0)
370 return NULL;
371 }
372
373 return str;
374 }
375
376 static 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
388 int 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
417 char *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
443 asprintf(&retval, "%.*s", (int)(end-start), start);
444
445 return retval;
446 }
447
This page took 0.0703 seconds and 4 git commands to generate.