Merge commit 'origin/master-tx'
[platform/upstream/pulseaudio.git] / src / pulsecore / protocol-http.c
1 /***
2   This file is part of PulseAudio.
3
4   Copyright 2005-2009 Lennart Poettering
5
6   PulseAudio is free software; you can redistribute it and/or modify
7   it under the terms of the GNU Lesser General Public License as published
8   by the Free Software Foundation; either version 2.1 of the License,
9   or (at your option) any later version.
10
11   PulseAudio 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 Lesser General Public License
17   along with PulseAudio; 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 <stdlib.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <errno.h>
30
31 #include <pulse/util.h>
32 #include <pulse/xmalloc.h>
33 #include <pulse/timeval.h>
34
35 #include <pulsecore/ioline.h>
36 #include <pulsecore/thread-mq.h>
37 #include <pulsecore/macro.h>
38 #include <pulsecore/log.h>
39 #include <pulsecore/namereg.h>
40 #include <pulsecore/cli-text.h>
41 #include <pulsecore/shared.h>
42 #include <pulsecore/core-error.h>
43 #include <pulsecore/mime-type.h>
44
45 #include "protocol-http.h"
46
47 /* Don't allow more than this many concurrent connections */
48 #define MAX_CONNECTIONS 10
49
50 #define URL_ROOT "/"
51 #define URL_CSS "/style"
52 #define URL_STATUS "/status"
53 #define URL_LISTEN "/listen"
54 #define URL_LISTEN_SOURCE "/listen/source/"
55
56 #define MIME_HTML "text/html; charset=utf-8"
57 #define MIME_TEXT "text/plain; charset=utf-8"
58 #define MIME_CSS "text/css"
59
60 #define HTML_HEADER(t)                                                  \
61     "<?xml version=\"1.0\"?>\n"                                         \
62     "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n" \
63     "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n"                   \
64     "        <head>\n"                                                  \
65     "                <title>"t"</title>\n"                              \
66     "                <link rel=\"stylesheet\" type=\"text/css\" href=\"style\"/>\n" \
67     "        </head>\n"                                                 \
68     "        <body>\n"
69
70 #define HTML_FOOTER                                                     \
71     "        </body>\n"                                                 \
72     "</html>\n"
73
74 #define RECORD_BUFFER_SECONDS (5)
75 #define DEFAULT_SOURCE_LATENCY (300*PA_USEC_PER_MSEC)
76
77 enum state {
78     STATE_REQUEST_LINE,
79     STATE_MIME_HEADER,
80     STATE_DATA
81 };
82
83 struct connection {
84     pa_http_protocol *protocol;
85     pa_iochannel *io;
86     pa_ioline *line;
87     pa_memblockq *output_memblockq;
88     pa_source_output *source_output;
89     pa_client *client;
90     enum state state;
91     char *url;
92     pa_module *module;
93 };
94
95 struct pa_http_protocol {
96     PA_REFCNT_DECLARE;
97
98     pa_core *core;
99     pa_idxset *connections;
100
101     pa_strlist *servers;
102 };
103
104 enum {
105     SOURCE_OUTPUT_MESSAGE_POST_DATA = PA_SOURCE_OUTPUT_MESSAGE_MAX
106 };
107
108 /* Called from main context */
109 static void connection_unlink(struct connection *c) {
110     pa_assert(c);
111
112     if (c->source_output) {
113         pa_source_output_unlink(c->source_output);
114         c->source_output->userdata = NULL;
115         pa_source_output_unref(c->source_output);
116     }
117
118     if (c->client)
119         pa_client_free(c->client);
120
121     pa_xfree(c->url);
122
123     if (c->line)
124         pa_ioline_unref(c->line);
125
126     if (c->io)
127         pa_iochannel_free(c->io);
128
129     if (c->output_memblockq)
130         pa_memblockq_free(c->output_memblockq);
131
132     pa_idxset_remove_by_data(c->protocol->connections, c, NULL);
133
134     pa_xfree(c);
135 }
136
137 /* Called from main context */
138 static int do_write(struct connection *c) {
139     pa_memchunk chunk;
140     ssize_t r;
141     void *p;
142
143     pa_assert(c);
144
145     if (pa_memblockq_peek(c->output_memblockq, &chunk) < 0)
146         return 0;
147
148     pa_assert(chunk.memblock);
149     pa_assert(chunk.length > 0);
150
151     p = pa_memblock_acquire(chunk.memblock);
152     r = pa_iochannel_write(c->io, (uint8_t*) p+chunk.index, chunk.length);
153     pa_memblock_release(chunk.memblock);
154
155     pa_memblock_unref(chunk.memblock);
156
157     if (r < 0) {
158
159         if (errno == EINTR || errno == EAGAIN)
160             return 0;
161
162         pa_log("write(): %s", pa_cstrerror(errno));
163         return -1;
164     }
165
166     pa_memblockq_drop(c->output_memblockq, (size_t) r);
167
168     return 0;
169 }
170
171 /* Called from main context */
172 static void do_work(struct connection *c) {
173     pa_assert(c);
174
175     if (pa_iochannel_is_hungup(c->io))
176         goto fail;
177
178     if (pa_iochannel_is_writable(c->io))
179         if (do_write(c) < 0)
180             goto fail;
181
182     return;
183
184 fail:
185     connection_unlink(c);
186 }
187
188 /* Called from thread context, except when it is not */
189 static int source_output_process_msg(pa_msgobject *m, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
190     pa_source_output *o = PA_SOURCE_OUTPUT(m);
191     struct connection *c;
192
193     pa_source_output_assert_ref(o);
194
195     if (!(c = o->userdata))
196         return -1;
197
198     switch (code) {
199
200         case SOURCE_OUTPUT_MESSAGE_POST_DATA:
201             /* While this function is usually called from IO thread
202              * context, this specific command is not! */
203             pa_memblockq_push_align(c->output_memblockq, chunk);
204             do_work(c);
205             break;
206
207         default:
208             return pa_source_output_process_msg(m, code, userdata, offset, chunk);
209     }
210
211     return 0;
212 }
213
214 /* Called from thread context */
215 static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) {
216     struct connection *c;
217
218     pa_source_output_assert_ref(o);
219     pa_assert_se(c = o->userdata);
220     pa_assert(chunk);
221
222     pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(o), SOURCE_OUTPUT_MESSAGE_POST_DATA, NULL, 0, chunk, NULL);
223 }
224
225 /* Called from main context */
226 static void source_output_kill_cb(pa_source_output *o) {
227     struct connection*c;
228
229     pa_source_output_assert_ref(o);
230     pa_assert_se(c = o->userdata);
231
232     connection_unlink(c);
233 }
234
235 /* Called from main context */
236 static pa_usec_t source_output_get_latency_cb(pa_source_output *o) {
237     struct connection*c;
238
239     pa_source_output_assert_ref(o);
240     pa_assert_se(c = o->userdata);
241
242     return pa_bytes_to_usec(pa_memblockq_get_length(c->output_memblockq), &c->source_output->sample_spec);
243 }
244
245 /*** client callbacks ***/
246 static void client_kill_cb(pa_client *client) {
247     struct connection*c;
248
249     pa_assert(client);
250     pa_assert_se(c = client->userdata);
251
252     connection_unlink(c);
253 }
254
255 /*** pa_iochannel callbacks ***/
256 static void io_callback(pa_iochannel*io, void *userdata) {
257     struct connection *c = userdata;
258
259     pa_assert(c);
260     pa_assert(io);
261
262     do_work(c);
263 }
264
265 static char *escape_html(const char *t) {
266     pa_strbuf *sb;
267     const char *p, *e;
268
269     sb = pa_strbuf_new();
270
271     for (e = p = t; *p; p++) {
272
273         if (*p == '>' || *p == '<' || *p == '&') {
274
275             if (p > e) {
276                 pa_strbuf_putsn(sb, e, p-e);
277                 e = p + 1;
278             }
279
280             if (*p == '>')
281                 pa_strbuf_puts(sb, "&gt;");
282             else if (*p == '<')
283                 pa_strbuf_puts(sb, "&lt;");
284             else
285                 pa_strbuf_puts(sb, "&amp;");
286         }
287     }
288
289     if (p > e)
290         pa_strbuf_putsn(sb, e, p-e);
291
292     return pa_strbuf_tostring_free(sb);
293 }
294
295 static void http_response(
296         struct connection *c,
297         int code,
298         const char *msg,
299         const char *mime) {
300
301     char *s;
302
303     pa_assert(c);
304     pa_assert(msg);
305     pa_assert(mime);
306
307     s = pa_sprintf_malloc(
308             "HTTP/1.0 %i %s\n"
309             "Connection: close\n"
310             "Content-Type: %s\n"
311             "Cache-Control: no-cache\n"
312             "Expires: 0\n"
313             "Server: "PACKAGE_NAME"/"PACKAGE_VERSION"\n"
314             "\n", code, msg, mime);
315     pa_ioline_puts(c->line, s);
316     pa_xfree(s);
317 }
318
319 static void html_response(
320         struct connection *c,
321         int code,
322         const char *msg,
323         const char *text) {
324
325     char *s;
326     pa_assert(c);
327
328     http_response(c, code, msg, MIME_HTML);
329
330     if (!text)
331         text = msg;
332
333     s = pa_sprintf_malloc(
334             HTML_HEADER("%s")
335             "%s"
336             HTML_FOOTER,
337             text, text);
338
339     pa_ioline_puts(c->line, s);
340     pa_xfree(s);
341
342     pa_ioline_defer_close(c->line);
343 }
344
345 static void html_print_field(pa_ioline *line, const char *left, const char *right) {
346     char *eleft, *eright;
347
348     eleft = escape_html(left);
349     eright = escape_html(right);
350
351     pa_ioline_printf(line,
352                      "<tr><td><b>%s</b></td>"
353                      "<td>%s</td></tr>\n", eleft, eright);
354
355     pa_xfree(eleft);
356     pa_xfree(eright);
357 }
358
359 static void handle_root(struct connection *c) {
360     char *t;
361
362     pa_assert(c);
363
364     http_response(c, 200, "OK", MIME_HTML);
365
366     pa_ioline_puts(c->line,
367                    HTML_HEADER(PACKAGE_NAME" "PACKAGE_VERSION)
368                    "<h1>"PACKAGE_NAME" "PACKAGE_VERSION"</h1>\n"
369                    "<table>\n");
370
371     t = pa_get_user_name_malloc();
372     html_print_field(c->line, "User Name:", t);
373     pa_xfree(t);
374
375     t = pa_get_host_name_malloc();
376     html_print_field(c->line, "Host name:", t);
377     pa_xfree(t);
378
379     t = pa_machine_id();
380     html_print_field(c->line, "Machine ID:", t);
381     pa_xfree(t);
382
383     t = pa_uname_string();
384     html_print_field(c->line, "System:", t);
385     pa_xfree(t);
386
387     t = pa_sprintf_malloc("%lu", (unsigned long) getpid());
388     html_print_field(c->line, "Process ID:", t);
389     pa_xfree(t);
390
391     pa_ioline_puts(c->line,
392                    "</table>\n"
393                    "<p><a href=\"" URL_STATUS "\">Show an extensive server status report</a></p>\n"
394                    "<p><a href=\"" URL_LISTEN "\">Monitor sinks and sources</a></p>\n"
395                    HTML_FOOTER);
396
397     pa_ioline_defer_close(c->line);
398 }
399
400 static void handle_css(struct connection *c) {
401     pa_assert(c);
402
403     http_response(c, 200, "OK", MIME_CSS);
404
405     pa_ioline_puts(c->line,
406                    "body { color: black; background-color: white; }\n"
407                    "a:link, a:visited { color: #900000; }\n"
408                    "div.news-date { font-size: 80%; font-style: italic; }\n"
409                    "pre { background-color: #f0f0f0; padding: 0.4cm; }\n"
410                    ".grey { color: #8f8f8f; font-size: 80%; }"
411                    "table {  margin-left: 1cm; border:1px solid lightgrey; padding: 0.2cm; }\n"
412                    "td { padding-left:10px; padding-right:10px; }\n");
413
414     pa_ioline_defer_close(c->line);
415 }
416
417 static void handle_status(struct connection *c) {
418     char *r;
419
420     pa_assert(c);
421
422     http_response(c, 200, "OK", MIME_TEXT);
423     r = pa_full_status_string(c->protocol->core);
424     pa_ioline_puts(c->line, r);
425     pa_xfree(r);
426
427     pa_ioline_defer_close(c->line);
428 }
429
430 static void handle_listen(struct connection *c) {
431     pa_source *source;
432     pa_sink *sink;
433     uint32_t idx;
434
435     http_response(c, 200, "OK", MIME_HTML);
436
437     pa_ioline_puts(c->line,
438                    HTML_HEADER("Listen")
439                    "<h2>Sinks</h2>\n"
440                    "<p>\n");
441
442     PA_IDXSET_FOREACH(sink, c->protocol->core->sinks, idx) {
443         char *t, *m;
444
445         t = escape_html(pa_strna(pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_DESCRIPTION)));
446         m = pa_sample_spec_to_mime_type_mimefy(&sink->sample_spec, &sink->channel_map);
447
448         pa_ioline_printf(c->line,
449                          "<a href=\"" URL_LISTEN_SOURCE "%s\" title=\"%s\">%s</a><br/>\n",
450                          sink->monitor_source->name, m, t);
451
452         pa_xfree(t);
453         pa_xfree(m);
454     }
455
456     pa_ioline_puts(c->line,
457                    "</p>\n"
458                    "<h2>Sources</h2>\n"
459                    "<p>\n");
460
461     PA_IDXSET_FOREACH(source, c->protocol->core->sources, idx) {
462         char *t, *m;
463
464         if (source->monitor_of)
465             continue;
466
467         t = escape_html(pa_strna(pa_proplist_gets(source->proplist, PA_PROP_DEVICE_DESCRIPTION)));
468         m = pa_sample_spec_to_mime_type_mimefy(&source->sample_spec, &source->channel_map);
469
470         pa_ioline_printf(c->line,
471                          "<a href=\"" URL_LISTEN_SOURCE "%s\" title=\"%s\">%s</a><br/>\n",
472                          source->name, m, t);
473
474         pa_xfree(m);
475         pa_xfree(t);
476
477     }
478
479     pa_ioline_puts(c->line,
480                    "</p>\n"
481                    HTML_FOOTER);
482
483     pa_ioline_defer_close(c->line);
484 }
485
486 static void line_drain_callback(pa_ioline *l, void *userdata) {
487     struct connection *c;
488
489     pa_assert(l);
490     pa_assert_se(c = userdata);
491
492     /* We don't need the line reader anymore, instead we need a real
493      * binary io channel */
494     pa_assert_se(c->io = pa_ioline_detach_iochannel(c->line));
495     pa_iochannel_set_callback(c->io, io_callback, c);
496
497     pa_iochannel_socket_set_sndbuf(c->io, pa_memblockq_get_length(c->output_memblockq));
498
499     pa_ioline_unref(c->line);
500     c->line = NULL;
501 }
502
503 static void handle_listen_prefix(struct connection *c, const char *source_name) {
504     pa_source *source;
505     pa_source_output_new_data data;
506     pa_sample_spec ss;
507     pa_channel_map cm;
508     char *t;
509     size_t l;
510
511     pa_assert(c);
512     pa_assert(source_name);
513
514     pa_assert(c->line);
515     pa_assert(!c->io);
516
517     if (!(source = pa_namereg_get(c->protocol->core, source_name, PA_NAMEREG_SOURCE))) {
518         html_response(c, 404, "Source not found", NULL);
519         return;
520     }
521
522     ss = source->sample_spec;
523     cm = source->channel_map;
524
525     pa_sample_spec_mimefy(&ss, &cm);
526
527     pa_source_output_new_data_init(&data);
528     data.driver = __FILE__;
529     data.module = c->module;
530     data.client = c->client;
531     data.source = source;
532     pa_proplist_update(data.proplist, PA_UPDATE_MERGE, c->client->proplist);
533     pa_source_output_new_data_set_sample_spec(&data, &ss);
534     pa_source_output_new_data_set_channel_map(&data, &cm);
535
536     pa_source_output_new(&c->source_output, c->protocol->core, &data, 0);
537     pa_source_output_new_data_done(&data);
538
539     if (!c->source_output) {
540         html_response(c, 403, "Cannot create source output", NULL);
541         return;
542     }
543
544     c->source_output->parent.process_msg = source_output_process_msg;
545     c->source_output->push = source_output_push_cb;
546     c->source_output->kill = source_output_kill_cb;
547     c->source_output->get_latency = source_output_get_latency_cb;
548     c->source_output->userdata = c;
549
550     pa_source_output_set_requested_latency(c->source_output, DEFAULT_SOURCE_LATENCY);
551
552     l = (size_t) (pa_bytes_per_second(&ss)*RECORD_BUFFER_SECONDS);
553     c->output_memblockq = pa_memblockq_new(
554             0,
555             l,
556             0,
557             pa_frame_size(&ss),
558             1,
559             0,
560             0,
561             NULL);
562
563     pa_source_output_put(c->source_output);
564
565     t = pa_sample_spec_to_mime_type(&ss, &cm);
566     http_response(c, 200, "OK", t);
567     pa_xfree(t);
568
569     pa_ioline_set_callback(c->line, NULL, NULL);
570
571     if (pa_ioline_is_drained(c->line))
572         line_drain_callback(c->line, c);
573     else
574         pa_ioline_set_drain_callback(c->line, line_drain_callback, c);
575 }
576
577 static void handle_url(struct connection *c) {
578     pa_assert(c);
579
580     pa_log_debug("Request for %s", c->url);
581
582     if (pa_streq(c->url, URL_ROOT))
583         handle_root(c);
584     else if (pa_streq(c->url, URL_CSS))
585         handle_css(c);
586     else if (pa_streq(c->url, URL_STATUS))
587         handle_status(c);
588     else if (pa_streq(c->url, URL_LISTEN))
589         handle_listen(c);
590     else if (pa_startswith(c->url, URL_LISTEN_SOURCE))
591         handle_listen_prefix(c, c->url + sizeof(URL_LISTEN_SOURCE)-1);
592     else
593         html_response(c, 404, "Not Found", NULL);
594 }
595
596 static void line_callback(pa_ioline *line, const char *s, void *userdata) {
597     struct connection *c = userdata;
598     pa_assert(line);
599     pa_assert(c);
600
601     if (!s) {
602         /* EOF */
603         connection_unlink(c);
604         return;
605     }
606
607     switch (c->state) {
608         case STATE_REQUEST_LINE: {
609             if (!pa_startswith(s, "GET "))
610                 goto fail;
611
612             s +=4;
613
614             c->url = pa_xstrndup(s, strcspn(s, " \r\n\t?"));
615             c->state = STATE_MIME_HEADER;
616             break;
617         }
618
619         case STATE_MIME_HEADER: {
620
621             /* Ignore MIME headers */
622             if (strcspn(s, " \r\n") != 0)
623                 break;
624
625             /* We're done */
626             c->state = STATE_DATA;
627
628             handle_url(c);
629             break;
630         }
631
632         default:
633             ;
634     }
635
636     return;
637
638 fail:
639     html_response(c, 500, "Internal Server Error", NULL);
640 }
641
642 void pa_http_protocol_connect(pa_http_protocol *p, pa_iochannel *io, pa_module *m) {
643     struct connection *c;
644     pa_client_new_data client_data;
645     char pname[128];
646
647     pa_assert(p);
648     pa_assert(io);
649     pa_assert(m);
650
651     if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) {
652         pa_log("Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS);
653         pa_iochannel_free(io);
654         return;
655     }
656
657     c = pa_xnew0(struct connection, 1);
658     c->protocol = p;
659     c->state = STATE_REQUEST_LINE;
660     c->module = m;
661
662     c->line = pa_ioline_new(io);
663     pa_ioline_set_callback(c->line, line_callback, c);
664
665     pa_client_new_data_init(&client_data);
666     client_data.module = c->module;
667     client_data.driver = __FILE__;
668     pa_iochannel_socket_peer_to_string(io, pname, sizeof(pname));
669     pa_proplist_setf(client_data.proplist, PA_PROP_APPLICATION_NAME, "HTTP client (%s)", pname);
670     pa_proplist_sets(client_data.proplist, "http-protocol.peer", pname);
671     c->client = pa_client_new(p->core, &client_data);
672     pa_client_new_data_done(&client_data);
673
674     if (!c->client)
675         goto fail;
676
677     c->client->kill = client_kill_cb;
678     c->client->userdata = c;
679
680     pa_idxset_put(p->connections, c, NULL);
681
682     return;
683
684 fail:
685     if (c)
686         connection_unlink(c);
687 }
688
689 void pa_http_protocol_disconnect(pa_http_protocol *p, pa_module *m) {
690     struct connection *c;
691     uint32_t idx;
692
693     pa_assert(p);
694     pa_assert(m);
695
696     PA_IDXSET_FOREACH(c, p->connections, idx)
697         if (c->module == m)
698             connection_unlink(c);
699 }
700
701 static pa_http_protocol* http_protocol_new(pa_core *c) {
702     pa_http_protocol *p;
703
704     pa_assert(c);
705
706     p = pa_xnew0(pa_http_protocol, 1);
707     PA_REFCNT_INIT(p);
708     p->core = c;
709     p->connections = pa_idxset_new(NULL, NULL);
710
711     pa_assert_se(pa_shared_set(c, "http-protocol", p) >= 0);
712
713     return p;
714 }
715
716 pa_http_protocol* pa_http_protocol_get(pa_core *c) {
717     pa_http_protocol *p;
718
719     if ((p = pa_shared_get(c, "http-protocol")))
720         return pa_http_protocol_ref(p);
721
722     return http_protocol_new(c);
723 }
724
725 pa_http_protocol* pa_http_protocol_ref(pa_http_protocol *p) {
726     pa_assert(p);
727     pa_assert(PA_REFCNT_VALUE(p) >= 1);
728
729     PA_REFCNT_INC(p);
730
731     return p;
732 }
733
734 void pa_http_protocol_unref(pa_http_protocol *p) {
735     struct connection *c;
736
737     pa_assert(p);
738     pa_assert(PA_REFCNT_VALUE(p) >= 1);
739
740     if (PA_REFCNT_DEC(p) > 0)
741         return;
742
743     while ((c = pa_idxset_first(p->connections, NULL)))
744         connection_unlink(c);
745
746     pa_idxset_free(p->connections, NULL, NULL);
747
748     pa_strlist_free(p->servers);
749
750     pa_assert_se(pa_shared_remove(p->core, "http-protocol") >= 0);
751
752     pa_xfree(p);
753 }
754
755 void pa_http_protocol_add_server_string(pa_http_protocol *p, const char *name) {
756     pa_assert(p);
757     pa_assert(PA_REFCNT_VALUE(p) >= 1);
758     pa_assert(name);
759
760     p->servers = pa_strlist_prepend(p->servers, name);
761 }
762
763 void pa_http_protocol_remove_server_string(pa_http_protocol *p, const char *name) {
764     pa_assert(p);
765     pa_assert(PA_REFCNT_VALUE(p) >= 1);
766     pa_assert(name);
767
768     p->servers = pa_strlist_remove(p->servers, name);
769 }
770
771 pa_strlist *pa_http_protocol_servers(pa_http_protocol *p) {
772     pa_assert(p);
773     pa_assert(PA_REFCNT_VALUE(p) >= 1);
774
775     return p->servers;
776 }