]> code.delx.au - pulseaudio/blob - polyp/polyplib-context.c
daemon auto spawn
[pulseaudio] / polyp / polyplib-context.c
1 /* $Id$ */
2
3 /***
4 This file is part of polypaudio.
5
6 polypaudio is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published
8 by the Free Software Foundation; either version 2 of the License,
9 or (at your option) any later version.
10
11 polypaudio is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with polypaudio; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19 USA.
20 ***/
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <stdio.h>
27 #include <assert.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <sys/types.h>
31 #include <sys/socket.h>
32 #include <netdb.h>
33 #include <unistd.h>
34 #include <sys/stat.h>
35 #include <errno.h>
36 #include <sys/wait.h>
37
38 #include "polyplib-internal.h"
39 #include "polyplib-context.h"
40 #include "native-common.h"
41 #include "pdispatch.h"
42 #include "pstream.h"
43 #include "dynarray.h"
44 #include "socket-client.h"
45 #include "pstream-util.h"
46 #include "authkey.h"
47 #include "util.h"
48 #include "xmalloc.h"
49
50 static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = {
51 [PA_COMMAND_REQUEST] = { pa_command_request },
52 [PA_COMMAND_PLAYBACK_STREAM_KILLED] = { pa_command_stream_killed },
53 [PA_COMMAND_RECORD_STREAM_KILLED] = { pa_command_stream_killed },
54 [PA_COMMAND_SUBSCRIBE_EVENT] = { pa_command_subscribe_event },
55 };
56
57 struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name) {
58 struct pa_context *c;
59 assert(mainloop && name);
60
61 c = pa_xmalloc(sizeof(struct pa_context));
62 c->ref = 1;
63 c->name = pa_xstrdup(name);
64 c->mainloop = mainloop;
65 c->client = NULL;
66 c->pstream = NULL;
67 c->pdispatch = NULL;
68 c->playback_streams = pa_dynarray_new();
69 c->record_streams = pa_dynarray_new();
70 assert(c->playback_streams && c->record_streams);
71
72 PA_LLIST_HEAD_INIT(struct pa_stream, c->streams);
73 PA_LLIST_HEAD_INIT(struct pa_operation, c->operations);
74
75 c->error = PA_ERROR_OK;
76 c->state = PA_CONTEXT_UNCONNECTED;
77 c->ctag = 0;
78
79 c->state_callback = NULL;
80 c->state_userdata = NULL;
81
82 c->subscribe_callback = NULL;
83 c->subscribe_userdata = NULL;
84
85 c->memblock_stat = pa_memblock_stat_new();
86
87 pa_check_for_sigpipe();
88 return c;
89 }
90
91 static void context_free(struct pa_context *c) {
92 assert(c);
93
94 while (c->operations)
95 pa_operation_cancel(c->operations);
96
97 while (c->streams)
98 pa_stream_set_state(c->streams, PA_STREAM_TERMINATED);
99
100 if (c->client)
101 pa_socket_client_unref(c->client);
102 if (c->pdispatch)
103 pa_pdispatch_unref(c->pdispatch);
104 if (c->pstream) {
105 pa_pstream_close(c->pstream);
106 pa_pstream_unref(c->pstream);
107 }
108
109 if (c->record_streams)
110 pa_dynarray_free(c->record_streams, NULL, NULL);
111 if (c->playback_streams)
112 pa_dynarray_free(c->playback_streams, NULL, NULL);
113
114 pa_memblock_stat_unref(c->memblock_stat);
115
116 pa_xfree(c->name);
117 pa_xfree(c);
118 }
119
120 struct pa_context* pa_context_ref(struct pa_context *c) {
121 assert(c && c->ref >= 1);
122 c->ref++;
123 return c;
124 }
125
126 void pa_context_unref(struct pa_context *c) {
127 assert(c && c->ref >= 1);
128
129 if ((--(c->ref)) == 0)
130 context_free(c);
131 }
132
133 void pa_context_set_state(struct pa_context *c, enum pa_context_state st) {
134 assert(c);
135
136 if (c->state == st)
137 return;
138
139 pa_context_ref(c);
140
141 if (st == PA_CONTEXT_FAILED || st == PA_CONTEXT_TERMINATED) {
142 struct pa_stream *s;
143
144 s = c->streams ? pa_stream_ref(c->streams) : NULL;
145 while (s) {
146 struct pa_stream *n = s->next ? pa_stream_ref(s->next) : NULL;
147 pa_stream_set_state(s, st == PA_CONTEXT_FAILED ? PA_STREAM_FAILED : PA_STREAM_TERMINATED);
148 pa_stream_unref(s);
149 s = n;
150 }
151
152 if (c->pdispatch)
153 pa_pdispatch_unref(c->pdispatch);
154 c->pdispatch = NULL;
155
156 if (c->pstream) {
157 pa_pstream_close(c->pstream);
158 pa_pstream_unref(c->pstream);
159 }
160 c->pstream = NULL;
161
162 if (c->client)
163 pa_socket_client_unref(c->client);
164 c->client = NULL;
165 }
166
167 c->state = st;
168 if (c->state_callback)
169 c->state_callback(c, c->state_userdata);
170
171 pa_context_unref(c);
172 }
173
174 void pa_context_fail(struct pa_context *c, int error) {
175 assert(c);
176 c->error = error;
177 pa_context_set_state(c, PA_CONTEXT_FAILED);
178 }
179
180 static void pstream_die_callback(struct pa_pstream *p, void *userdata) {
181 struct pa_context *c = userdata;
182 assert(p && c);
183 pa_context_fail(c, PA_ERROR_CONNECTIONTERMINATED);
184 }
185
186 static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *packet, void *userdata) {
187 struct pa_context *c = userdata;
188 assert(p && packet && c);
189
190 pa_context_ref(c);
191
192 if (pa_pdispatch_run(c->pdispatch, packet, c) < 0) {
193 fprintf(stderr, "polyp.c: invalid packet.\n");
194 pa_context_fail(c, PA_ERROR_PROTOCOL);
195 }
196
197 pa_context_unref(c);
198 }
199
200 static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, uint32_t delta, const struct pa_memchunk *chunk, void *userdata) {
201 struct pa_context *c = userdata;
202 struct pa_stream *s;
203 assert(p && chunk && c && chunk->memblock && chunk->memblock->data);
204
205 pa_context_ref(c);
206
207 if ((s = pa_dynarray_get(c->record_streams, channel))) {
208 if (s->read_callback)
209 s->read_callback(s, (uint8_t*) chunk->memblock->data + chunk->index, chunk->length, s->read_userdata);
210 }
211
212 pa_context_unref(c);
213 }
214
215 int pa_context_handle_error(struct pa_context *c, uint32_t command, struct pa_tagstruct *t) {
216 assert(c && t);
217
218 if (command == PA_COMMAND_ERROR) {
219 if (pa_tagstruct_getu32(t, &c->error) < 0) {
220 pa_context_fail(c, PA_ERROR_PROTOCOL);
221 return -1;
222
223 }
224 } else if (command == PA_COMMAND_TIMEOUT)
225 c->error = PA_ERROR_TIMEOUT;
226 else {
227 pa_context_fail(c, PA_ERROR_PROTOCOL);
228 return -1;
229 }
230
231 return 0;
232 }
233
234 static void setup_complete_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
235 struct pa_context *c = userdata;
236 assert(pd && c && (c->state == PA_CONTEXT_AUTHORIZING || c->state == PA_CONTEXT_SETTING_NAME));
237
238 pa_context_ref(c);
239
240 if (command != PA_COMMAND_REPLY) {
241
242 if (pa_context_handle_error(c, command, t) < 0)
243 pa_context_fail(c, PA_ERROR_PROTOCOL);
244
245 pa_context_fail(c, c->error);
246 goto finish;
247 }
248
249 switch(c->state) {
250 case PA_CONTEXT_AUTHORIZING: {
251 struct pa_tagstruct *t;
252 t = pa_tagstruct_new(NULL, 0);
253 assert(t);
254 pa_tagstruct_putu32(t, PA_COMMAND_SET_NAME);
255 pa_tagstruct_putu32(t, tag = c->ctag++);
256 pa_tagstruct_puts(t, c->name);
257 pa_pstream_send_tagstruct(c->pstream, t);
258 pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c);
259
260 pa_context_set_state(c, PA_CONTEXT_SETTING_NAME);
261 break;
262 }
263
264 case PA_CONTEXT_SETTING_NAME :
265 pa_context_set_state(c, PA_CONTEXT_READY);
266 break;
267
268 default:
269 assert(0);
270 }
271
272 finish:
273 pa_context_unref(c);
274 }
275
276 static void setup_context(struct pa_context *c, struct pa_iochannel *io) {
277 struct pa_tagstruct *t;
278 uint32_t tag;
279 assert(c && io);
280
281 pa_context_ref(c);
282
283 assert(!c->pstream);
284 c->pstream = pa_pstream_new(c->mainloop, io, c->memblock_stat);
285 assert(c->pstream);
286
287 pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c);
288 pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c);
289 pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c);
290
291 assert(!c->pdispatch);
292 c->pdispatch = pa_pdispatch_new(c->mainloop, command_table, PA_COMMAND_MAX);
293 assert(c->pdispatch);
294
295 if (pa_authkey_load_from_home(PA_NATIVE_COOKIE_FILE, c->auth_cookie, sizeof(c->auth_cookie)) < 0) {
296 pa_context_fail(c, PA_ERROR_AUTHKEY);
297 goto finish;
298 }
299
300 t = pa_tagstruct_new(NULL, 0);
301 assert(t);
302 pa_tagstruct_putu32(t, PA_COMMAND_AUTH);
303 pa_tagstruct_putu32(t, tag = c->ctag++);
304 pa_tagstruct_put_arbitrary(t, c->auth_cookie, sizeof(c->auth_cookie));
305 pa_pstream_send_tagstruct(c->pstream, t);
306 pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c);
307
308 pa_context_set_state(c, PA_CONTEXT_AUTHORIZING);
309
310 finish:
311
312 pa_context_unref(c);
313 }
314
315 static void on_connection(struct pa_socket_client *client, struct pa_iochannel*io, void *userdata) {
316 struct pa_context *c = userdata;
317 assert(client && c && c->state == PA_CONTEXT_CONNECTING);
318
319 pa_context_ref(c);
320
321 pa_socket_client_unref(client);
322 c->client = NULL;
323
324 if (!io) {
325 pa_context_fail(c, PA_ERROR_CONNECTIONREFUSED);
326 goto finish;
327 }
328
329 setup_context(c, io);
330
331 finish:
332 pa_context_unref(c);
333 }
334
335 static struct sockaddr *resolve_server(const char *server, size_t *len) {
336 struct sockaddr *sa;
337 struct addrinfo hints, *result = NULL;
338 char *port;
339 assert(server && len);
340
341 if ((port = strrchr(server, ':')))
342 port++;
343 if (!port)
344 port = DEFAULT_PORT;
345
346 memset(&hints, 0, sizeof(hints));
347 hints.ai_family = PF_UNSPEC;
348 hints.ai_socktype = SOCK_STREAM;
349 hints.ai_protocol = 0;
350
351 if (getaddrinfo(server, port, &hints, &result) != 0)
352 return NULL;
353 assert(result);
354
355 sa = pa_xmalloc(*len = result->ai_addrlen);
356 memcpy(sa, result->ai_addr, *len);
357
358 freeaddrinfo(result);
359
360 return sa;
361 }
362
363 int pa_context_connect(struct pa_context *c, const char *server) {
364 int r = -1;
365 assert(c && c->ref >= 1 && c->state == PA_CONTEXT_UNCONNECTED);
366
367 pa_context_ref(c);
368
369 if (!server)
370 if (!(server = getenv(ENV_DEFAULT_SERVER)))
371 server = DEFAULT_SERVER;
372
373 assert(!c->client);
374
375 if (*server == '/') {
376 if (!(c->client = pa_socket_client_new_unix(c->mainloop, server))) {
377 pa_context_fail(c, PA_ERROR_CONNECTIONREFUSED);
378 goto finish;
379 }
380 } else {
381 struct sockaddr* sa;
382 size_t sa_len;
383
384 if (!(sa = resolve_server(server, &sa_len))) {
385 pa_context_fail(c, PA_ERROR_INVALIDSERVER);
386 goto finish;
387 }
388
389 c->client = pa_socket_client_new_sockaddr(c->mainloop, sa, sa_len);
390 pa_xfree(sa);
391
392 if (!c->client) {
393 pa_context_fail(c, PA_ERROR_CONNECTIONREFUSED);
394 goto finish;
395 }
396 }
397
398 pa_socket_client_set_callback(c->client, on_connection, c);
399 pa_context_set_state(c, PA_CONTEXT_CONNECTING);
400
401 r = 0;
402
403 finish:
404 pa_context_unref(c);
405
406 return r;
407 }
408
409 void pa_context_disconnect(struct pa_context *c) {
410 assert(c);
411 pa_context_set_state(c, PA_CONTEXT_TERMINATED);
412 }
413
414 enum pa_context_state pa_context_get_state(struct pa_context *c) {
415 assert(c && c->ref >= 1);
416 return c->state;
417 }
418
419 int pa_context_errno(struct pa_context *c) {
420 assert(c && c->ref >= 1);
421 return c->error;
422 }
423
424 void pa_context_set_state_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata) {
425 assert(c && c->ref >= 1);
426 c->state_callback = cb;
427 c->state_userdata = userdata;
428 }
429
430 int pa_context_is_pending(struct pa_context *c) {
431 assert(c && c->ref >= 1);
432
433 if (c->state != PA_CONTEXT_READY)
434 return 0;
435
436 assert(c->pstream && c->pdispatch);
437 return pa_pstream_is_pending(c->pstream) || pa_pdispatch_is_pending(c->pdispatch);
438 }
439
440 static void set_dispatch_callbacks(struct pa_operation *o);
441
442 static void pdispatch_drain_callback(struct pa_pdispatch*pd, void *userdata) {
443 set_dispatch_callbacks(userdata);
444 }
445
446 static void pstream_drain_callback(struct pa_pstream *s, void *userdata) {
447 set_dispatch_callbacks(userdata);
448 }
449
450 static void set_dispatch_callbacks(struct pa_operation *o) {
451 int done = 1;
452 assert(o && o->context && o->context->ref >= 1 && o->ref >= 1 && o->context->state == PA_CONTEXT_READY);
453
454 pa_pstream_set_drain_callback(o->context->pstream, NULL, NULL);
455 pa_pdispatch_set_drain_callback(o->context->pdispatch, NULL, NULL);
456
457 if (pa_pdispatch_is_pending(o->context->pdispatch)) {
458 pa_pdispatch_set_drain_callback(o->context->pdispatch, pdispatch_drain_callback, o);
459 done = 0;
460 }
461
462 if (pa_pstream_is_pending(o->context->pstream)) {
463 pa_pstream_set_drain_callback(o->context->pstream, pstream_drain_callback, o);
464 done = 0;
465 }
466
467 if (!done)
468 pa_operation_ref(o);
469 else {
470 if (o->callback) {
471 void (*cb)(struct pa_context *c, void *userdata);
472 cb = (void (*)(struct pa_context*, void*)) o->callback;
473 cb(o->context, o->userdata);
474 }
475
476 pa_operation_done(o);
477 }
478
479 pa_operation_unref(o);
480 }
481
482 struct pa_operation* pa_context_drain(struct pa_context *c, void (*cb) (struct pa_context*c, void *userdata), void *userdata) {
483 struct pa_operation *o;
484 assert(c && c->ref >= 1);
485
486 if (c->state != PA_CONTEXT_READY)
487 return NULL;
488
489 if (!pa_context_is_pending(c))
490 return NULL;
491
492 o = pa_operation_new(c, NULL);
493 assert(o);
494 o->callback = cb;
495 o->userdata = userdata;
496
497 set_dispatch_callbacks(pa_operation_ref(o));
498
499 return o;
500 }
501
502 void pa_context_exit_daemon(struct pa_context *c) {
503 struct pa_tagstruct *t;
504 assert(c && c->ref >= 1);
505
506 t = pa_tagstruct_new(NULL, 0);
507 assert(t);
508 pa_tagstruct_putu32(t, PA_COMMAND_EXIT);
509 pa_tagstruct_putu32(t, c->ctag++);
510 pa_pstream_send_tagstruct(c->pstream, t);
511 }
512
513 void pa_context_simple_ack_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
514 struct pa_operation *o = userdata;
515 int success = 1;
516 assert(pd && o && o->context && o->ref >= 1);
517
518 if (command != PA_COMMAND_REPLY) {
519 if (pa_context_handle_error(o->context, command, t) < 0)
520 goto finish;
521
522 success = 0;
523 } else if (!pa_tagstruct_eof(t)) {
524 pa_context_fail(o->context, PA_ERROR_PROTOCOL);
525 goto finish;
526 }
527
528 if (o->callback) {
529 void (*cb)(struct pa_context *c, int success, void *userdata) = o->callback;
530 cb(o->context, success, o->userdata);
531 }
532
533 finish:
534 pa_operation_done(o);
535 pa_operation_unref(o);
536 }
537
538 struct pa_operation* pa_context_send_simple_command(struct pa_context *c, uint32_t command, void (*internal_callback)(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata), void (*cb)(), void *userdata) {
539 struct pa_tagstruct *t;
540 struct pa_operation *o;
541 uint32_t tag;
542 assert(c && cb);
543
544 o = pa_operation_new(c, NULL);
545 o->callback = cb;
546 o->userdata = userdata;
547
548 t = pa_tagstruct_new(NULL, 0);
549 pa_tagstruct_putu32(t, command);
550 pa_tagstruct_putu32(t, tag = c->ctag++);
551 pa_pstream_send_tagstruct(c->pstream, t);
552 pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, internal_callback, o);
553
554 return pa_operation_ref(o);
555 }
556
557 const char* pa_get_library_version(void) {
558 return PACKAGE_VERSION;
559 }
560
561 static int is_running(void) {
562 struct stat st;
563
564 if (DEFAULT_SERVER[0] != '/')
565 return 1;
566
567 if (stat(DEFAULT_SERVER, &st) < 0)
568 return 0;
569
570 return 1;
571 }
572
573 int pa_context_connect_spawn(struct pa_context *c, void (*atfork)(void)) {
574 pid_t pid;
575 int status;
576 int fds[2] = { -1, -1} ;
577 struct pa_iochannel *io;
578
579 if (getenv(ENV_DEFAULT_SERVER) || is_running())
580 return pa_context_connect(c, NULL);
581
582 if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) {
583 fprintf(stderr, __FILE__": socketpair() failed: %s\n", strerror(errno));
584 pa_context_fail(c, PA_ERROR_INTERNAL);
585 goto fail;
586 }
587
588 if ((pid = fork()) < 0) {
589 fprintf(stderr, __FILE__": fork() failed: %s\n", strerror(errno));
590 pa_context_fail(c, PA_ERROR_INTERNAL);
591 goto fail;
592 } else if (!pid) {
593 char t[64];
594 char *p;
595 /* Child */
596
597 close(fds[0]);
598
599 if (atfork)
600 atfork();
601
602 if (!(p = getenv(ENV_DEFAULT_BINARY)))
603 p = POLYPAUDIO_BINARY;
604
605 snprintf(t, sizeof(t), "-Lmodule-native-protocol-fd fd=%i", fds[1]);
606 execl(p, p, "-r", "-D", t, NULL);
607
608 exit(1);
609 }
610
611 /* Parent */
612 if (waitpid(pid, &status, 0) < 0) {
613 fprintf(stderr, __FILE__": waitpid() failed: %s\n", strerror(errno));
614 pa_context_fail(c, PA_ERROR_INTERNAL);
615 goto fail;
616 } else if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
617 pa_context_fail(c, PA_ERROR_CONNECTIONREFUSED);
618 goto fail;
619 }
620
621 close(fds[1]);
622
623 io = pa_iochannel_new(c->mainloop, fds[0], fds[0]);
624 setup_context(c, io);
625 return 0;
626
627 fail:
628 if (fds[0] != -1)
629 close(fds[0]);
630 if (fds[1] != -1)
631 close(fds[1]);
632
633 return -1;
634 }