153a5a1b3Sopenharmony_ci/*** 253a5a1b3Sopenharmony_ci This file is part of PulseAudio. 353a5a1b3Sopenharmony_ci 453a5a1b3Sopenharmony_ci Copyright 2005-2009 Lennart Poettering 553a5a1b3Sopenharmony_ci 653a5a1b3Sopenharmony_ci PulseAudio is free software; you can redistribute it and/or modify 753a5a1b3Sopenharmony_ci it under the terms of the GNU Lesser General Public License as published 853a5a1b3Sopenharmony_ci by the Free Software Foundation; either version 2.1 of the License, 953a5a1b3Sopenharmony_ci or (at your option) any later version. 1053a5a1b3Sopenharmony_ci 1153a5a1b3Sopenharmony_ci PulseAudio is distributed in the hope that it will be useful, but 1253a5a1b3Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 1353a5a1b3Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1453a5a1b3Sopenharmony_ci General Public License for more details. 1553a5a1b3Sopenharmony_ci 1653a5a1b3Sopenharmony_ci You should have received a copy of the GNU Lesser General Public License 1753a5a1b3Sopenharmony_ci along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. 1853a5a1b3Sopenharmony_ci***/ 1953a5a1b3Sopenharmony_ci 2053a5a1b3Sopenharmony_ci#ifdef HAVE_CONFIG_H 2153a5a1b3Sopenharmony_ci#include <config.h> 2253a5a1b3Sopenharmony_ci#endif 2353a5a1b3Sopenharmony_ci 2453a5a1b3Sopenharmony_ci#include <stdlib.h> 2553a5a1b3Sopenharmony_ci#include <stdio.h> 2653a5a1b3Sopenharmony_ci#include <string.h> 2753a5a1b3Sopenharmony_ci#include <errno.h> 2853a5a1b3Sopenharmony_ci 2953a5a1b3Sopenharmony_ci#include <pulse/util.h> 3053a5a1b3Sopenharmony_ci#include <pulse/xmalloc.h> 3153a5a1b3Sopenharmony_ci#include <pulse/timeval.h> 3253a5a1b3Sopenharmony_ci 3353a5a1b3Sopenharmony_ci#include <pulsecore/core-util.h> 3453a5a1b3Sopenharmony_ci#include <pulsecore/ioline.h> 3553a5a1b3Sopenharmony_ci#include <pulsecore/thread-mq.h> 3653a5a1b3Sopenharmony_ci#include <pulsecore/macro.h> 3753a5a1b3Sopenharmony_ci#include <pulsecore/log.h> 3853a5a1b3Sopenharmony_ci#include <pulsecore/namereg.h> 3953a5a1b3Sopenharmony_ci#include <pulsecore/cli-text.h> 4053a5a1b3Sopenharmony_ci#include <pulsecore/shared.h> 4153a5a1b3Sopenharmony_ci#include <pulsecore/core-error.h> 4253a5a1b3Sopenharmony_ci#include <pulsecore/mime-type.h> 4353a5a1b3Sopenharmony_ci 4453a5a1b3Sopenharmony_ci#include "protocol-http.h" 4553a5a1b3Sopenharmony_ci 4653a5a1b3Sopenharmony_ci/* Don't allow more than this many concurrent connections */ 4753a5a1b3Sopenharmony_ci#define MAX_CONNECTIONS 10 4853a5a1b3Sopenharmony_ci 4953a5a1b3Sopenharmony_ci#define URL_ROOT "/" 5053a5a1b3Sopenharmony_ci#define URL_CSS "/style" 5153a5a1b3Sopenharmony_ci#define URL_STATUS "/status" 5253a5a1b3Sopenharmony_ci#define URL_LISTEN "/listen" 5353a5a1b3Sopenharmony_ci#define URL_LISTEN_SOURCE "/listen/source/" 5453a5a1b3Sopenharmony_ci 5553a5a1b3Sopenharmony_ci#define MIME_HTML "text/html; charset=utf-8" 5653a5a1b3Sopenharmony_ci#define MIME_TEXT "text/plain; charset=utf-8" 5753a5a1b3Sopenharmony_ci#define MIME_CSS "text/css" 5853a5a1b3Sopenharmony_ci 5953a5a1b3Sopenharmony_ci#define HTML_HEADER(t) \ 6053a5a1b3Sopenharmony_ci "<?xml version=\"1.0\"?>\n" \ 6153a5a1b3Sopenharmony_ci "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n" \ 6253a5a1b3Sopenharmony_ci "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n" \ 6353a5a1b3Sopenharmony_ci " <head>\n" \ 6453a5a1b3Sopenharmony_ci " <title>"t"</title>\n" \ 6553a5a1b3Sopenharmony_ci " <link rel=\"stylesheet\" type=\"text/css\" href=\"style\"/>\n" \ 6653a5a1b3Sopenharmony_ci " </head>\n" \ 6753a5a1b3Sopenharmony_ci " <body>\n" 6853a5a1b3Sopenharmony_ci 6953a5a1b3Sopenharmony_ci#define HTML_FOOTER \ 7053a5a1b3Sopenharmony_ci " </body>\n" \ 7153a5a1b3Sopenharmony_ci "</html>\n" 7253a5a1b3Sopenharmony_ci 7353a5a1b3Sopenharmony_ci#define RECORD_BUFFER_SECONDS (5) 7453a5a1b3Sopenharmony_ci#define DEFAULT_SOURCE_LATENCY (300*PA_USEC_PER_MSEC) 7553a5a1b3Sopenharmony_ci 7653a5a1b3Sopenharmony_cienum state { 7753a5a1b3Sopenharmony_ci STATE_REQUEST_LINE, 7853a5a1b3Sopenharmony_ci STATE_MIME_HEADER, 7953a5a1b3Sopenharmony_ci STATE_DATA 8053a5a1b3Sopenharmony_ci}; 8153a5a1b3Sopenharmony_ci 8253a5a1b3Sopenharmony_cienum method { 8353a5a1b3Sopenharmony_ci METHOD_GET, 8453a5a1b3Sopenharmony_ci METHOD_HEAD 8553a5a1b3Sopenharmony_ci}; 8653a5a1b3Sopenharmony_ci 8753a5a1b3Sopenharmony_cistruct connection { 8853a5a1b3Sopenharmony_ci pa_http_protocol *protocol; 8953a5a1b3Sopenharmony_ci pa_iochannel *io; 9053a5a1b3Sopenharmony_ci pa_ioline *line; 9153a5a1b3Sopenharmony_ci pa_memblockq *output_memblockq; 9253a5a1b3Sopenharmony_ci pa_source_output *source_output; 9353a5a1b3Sopenharmony_ci pa_client *client; 9453a5a1b3Sopenharmony_ci enum state state; 9553a5a1b3Sopenharmony_ci char *url; 9653a5a1b3Sopenharmony_ci enum method method; 9753a5a1b3Sopenharmony_ci pa_module *module; 9853a5a1b3Sopenharmony_ci}; 9953a5a1b3Sopenharmony_ci 10053a5a1b3Sopenharmony_cistruct pa_http_protocol { 10153a5a1b3Sopenharmony_ci PA_REFCNT_DECLARE; 10253a5a1b3Sopenharmony_ci 10353a5a1b3Sopenharmony_ci pa_core *core; 10453a5a1b3Sopenharmony_ci pa_idxset *connections; 10553a5a1b3Sopenharmony_ci 10653a5a1b3Sopenharmony_ci pa_strlist *servers; 10753a5a1b3Sopenharmony_ci}; 10853a5a1b3Sopenharmony_ci 10953a5a1b3Sopenharmony_cienum { 11053a5a1b3Sopenharmony_ci SOURCE_OUTPUT_MESSAGE_POST_DATA = PA_SOURCE_OUTPUT_MESSAGE_MAX 11153a5a1b3Sopenharmony_ci}; 11253a5a1b3Sopenharmony_ci 11353a5a1b3Sopenharmony_ci/* Called from main context */ 11453a5a1b3Sopenharmony_cistatic void connection_unlink(struct connection *c) { 11553a5a1b3Sopenharmony_ci pa_assert(c); 11653a5a1b3Sopenharmony_ci 11753a5a1b3Sopenharmony_ci if (c->source_output) { 11853a5a1b3Sopenharmony_ci pa_source_output_unlink(c->source_output); 11953a5a1b3Sopenharmony_ci c->source_output->userdata = NULL; 12053a5a1b3Sopenharmony_ci pa_source_output_unref(c->source_output); 12153a5a1b3Sopenharmony_ci } 12253a5a1b3Sopenharmony_ci 12353a5a1b3Sopenharmony_ci if (c->client) 12453a5a1b3Sopenharmony_ci pa_client_free(c->client); 12553a5a1b3Sopenharmony_ci 12653a5a1b3Sopenharmony_ci pa_xfree(c->url); 12753a5a1b3Sopenharmony_ci 12853a5a1b3Sopenharmony_ci if (c->line) 12953a5a1b3Sopenharmony_ci pa_ioline_unref(c->line); 13053a5a1b3Sopenharmony_ci 13153a5a1b3Sopenharmony_ci if (c->io) 13253a5a1b3Sopenharmony_ci pa_iochannel_free(c->io); 13353a5a1b3Sopenharmony_ci 13453a5a1b3Sopenharmony_ci if (c->output_memblockq) 13553a5a1b3Sopenharmony_ci pa_memblockq_free(c->output_memblockq); 13653a5a1b3Sopenharmony_ci 13753a5a1b3Sopenharmony_ci pa_idxset_remove_by_data(c->protocol->connections, c, NULL); 13853a5a1b3Sopenharmony_ci 13953a5a1b3Sopenharmony_ci pa_xfree(c); 14053a5a1b3Sopenharmony_ci} 14153a5a1b3Sopenharmony_ci 14253a5a1b3Sopenharmony_ci/* Called from main context */ 14353a5a1b3Sopenharmony_cistatic int do_write(struct connection *c) { 14453a5a1b3Sopenharmony_ci pa_memchunk chunk; 14553a5a1b3Sopenharmony_ci ssize_t r; 14653a5a1b3Sopenharmony_ci void *p; 14753a5a1b3Sopenharmony_ci 14853a5a1b3Sopenharmony_ci pa_assert(c); 14953a5a1b3Sopenharmony_ci 15053a5a1b3Sopenharmony_ci if (pa_memblockq_peek(c->output_memblockq, &chunk) < 0) 15153a5a1b3Sopenharmony_ci return 0; 15253a5a1b3Sopenharmony_ci 15353a5a1b3Sopenharmony_ci pa_assert(chunk.memblock); 15453a5a1b3Sopenharmony_ci pa_assert(chunk.length > 0); 15553a5a1b3Sopenharmony_ci 15653a5a1b3Sopenharmony_ci p = pa_memblock_acquire(chunk.memblock); 15753a5a1b3Sopenharmony_ci r = pa_iochannel_write(c->io, (uint8_t*) p+chunk.index, chunk.length); 15853a5a1b3Sopenharmony_ci pa_memblock_release(chunk.memblock); 15953a5a1b3Sopenharmony_ci 16053a5a1b3Sopenharmony_ci pa_memblock_unref(chunk.memblock); 16153a5a1b3Sopenharmony_ci 16253a5a1b3Sopenharmony_ci if (r < 0) { 16353a5a1b3Sopenharmony_ci pa_log("write(): %s", pa_cstrerror(errno)); 16453a5a1b3Sopenharmony_ci return -1; 16553a5a1b3Sopenharmony_ci } 16653a5a1b3Sopenharmony_ci 16753a5a1b3Sopenharmony_ci pa_memblockq_drop(c->output_memblockq, (size_t) r); 16853a5a1b3Sopenharmony_ci 16953a5a1b3Sopenharmony_ci return 1; 17053a5a1b3Sopenharmony_ci} 17153a5a1b3Sopenharmony_ci 17253a5a1b3Sopenharmony_ci/* Called from main context */ 17353a5a1b3Sopenharmony_cistatic void do_work(struct connection *c) { 17453a5a1b3Sopenharmony_ci pa_assert(c); 17553a5a1b3Sopenharmony_ci 17653a5a1b3Sopenharmony_ci if (pa_iochannel_is_hungup(c->io)) 17753a5a1b3Sopenharmony_ci goto fail; 17853a5a1b3Sopenharmony_ci 17953a5a1b3Sopenharmony_ci while (pa_iochannel_is_writable(c->io)) { 18053a5a1b3Sopenharmony_ci int r = do_write(c); 18153a5a1b3Sopenharmony_ci if (r < 0) 18253a5a1b3Sopenharmony_ci goto fail; 18353a5a1b3Sopenharmony_ci if (r == 0) 18453a5a1b3Sopenharmony_ci break; 18553a5a1b3Sopenharmony_ci } 18653a5a1b3Sopenharmony_ci 18753a5a1b3Sopenharmony_ci return; 18853a5a1b3Sopenharmony_ci 18953a5a1b3Sopenharmony_cifail: 19053a5a1b3Sopenharmony_ci connection_unlink(c); 19153a5a1b3Sopenharmony_ci} 19253a5a1b3Sopenharmony_ci 19353a5a1b3Sopenharmony_ci/* Called from thread context, except when it is not */ 19453a5a1b3Sopenharmony_cistatic int source_output_process_msg(pa_msgobject *m, int code, void *userdata, int64_t offset, pa_memchunk *chunk) { 19553a5a1b3Sopenharmony_ci pa_source_output *o = PA_SOURCE_OUTPUT(m); 19653a5a1b3Sopenharmony_ci struct connection *c; 19753a5a1b3Sopenharmony_ci 19853a5a1b3Sopenharmony_ci pa_source_output_assert_ref(o); 19953a5a1b3Sopenharmony_ci 20053a5a1b3Sopenharmony_ci if (!(c = o->userdata)) 20153a5a1b3Sopenharmony_ci return -1; 20253a5a1b3Sopenharmony_ci 20353a5a1b3Sopenharmony_ci switch (code) { 20453a5a1b3Sopenharmony_ci 20553a5a1b3Sopenharmony_ci case SOURCE_OUTPUT_MESSAGE_POST_DATA: 20653a5a1b3Sopenharmony_ci /* While this function is usually called from IO thread 20753a5a1b3Sopenharmony_ci * context, this specific command is not! */ 20853a5a1b3Sopenharmony_ci pa_memblockq_push_align(c->output_memblockq, chunk); 20953a5a1b3Sopenharmony_ci do_work(c); 21053a5a1b3Sopenharmony_ci break; 21153a5a1b3Sopenharmony_ci 21253a5a1b3Sopenharmony_ci default: 21353a5a1b3Sopenharmony_ci return pa_source_output_process_msg(m, code, userdata, offset, chunk); 21453a5a1b3Sopenharmony_ci } 21553a5a1b3Sopenharmony_ci 21653a5a1b3Sopenharmony_ci return 0; 21753a5a1b3Sopenharmony_ci} 21853a5a1b3Sopenharmony_ci 21953a5a1b3Sopenharmony_ci/* Called from thread context */ 22053a5a1b3Sopenharmony_cistatic void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) { 22153a5a1b3Sopenharmony_ci struct connection *c; 22253a5a1b3Sopenharmony_ci 22353a5a1b3Sopenharmony_ci pa_source_output_assert_ref(o); 22453a5a1b3Sopenharmony_ci pa_assert_se(c = o->userdata); 22553a5a1b3Sopenharmony_ci pa_assert(chunk); 22653a5a1b3Sopenharmony_ci 22753a5a1b3Sopenharmony_ci pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(o), SOURCE_OUTPUT_MESSAGE_POST_DATA, NULL, 0, chunk, NULL); 22853a5a1b3Sopenharmony_ci} 22953a5a1b3Sopenharmony_ci 23053a5a1b3Sopenharmony_ci/* Called from main context */ 23153a5a1b3Sopenharmony_cistatic void source_output_kill_cb(pa_source_output *o) { 23253a5a1b3Sopenharmony_ci struct connection*c; 23353a5a1b3Sopenharmony_ci 23453a5a1b3Sopenharmony_ci pa_source_output_assert_ref(o); 23553a5a1b3Sopenharmony_ci pa_assert_se(c = o->userdata); 23653a5a1b3Sopenharmony_ci 23753a5a1b3Sopenharmony_ci connection_unlink(c); 23853a5a1b3Sopenharmony_ci} 23953a5a1b3Sopenharmony_ci 24053a5a1b3Sopenharmony_ci/* Called from main context */ 24153a5a1b3Sopenharmony_cistatic pa_usec_t source_output_get_latency_cb(pa_source_output *o) { 24253a5a1b3Sopenharmony_ci struct connection*c; 24353a5a1b3Sopenharmony_ci 24453a5a1b3Sopenharmony_ci pa_source_output_assert_ref(o); 24553a5a1b3Sopenharmony_ci pa_assert_se(c = o->userdata); 24653a5a1b3Sopenharmony_ci 24753a5a1b3Sopenharmony_ci return pa_bytes_to_usec(pa_memblockq_get_length(c->output_memblockq), &c->source_output->sample_spec); 24853a5a1b3Sopenharmony_ci} 24953a5a1b3Sopenharmony_ci 25053a5a1b3Sopenharmony_ci/*** client callbacks ***/ 25153a5a1b3Sopenharmony_cistatic void client_kill_cb(pa_client *client) { 25253a5a1b3Sopenharmony_ci struct connection*c; 25353a5a1b3Sopenharmony_ci 25453a5a1b3Sopenharmony_ci pa_assert(client); 25553a5a1b3Sopenharmony_ci pa_assert_se(c = client->userdata); 25653a5a1b3Sopenharmony_ci 25753a5a1b3Sopenharmony_ci connection_unlink(c); 25853a5a1b3Sopenharmony_ci} 25953a5a1b3Sopenharmony_ci 26053a5a1b3Sopenharmony_ci/*** pa_iochannel callbacks ***/ 26153a5a1b3Sopenharmony_cistatic void io_callback(pa_iochannel*io, void *userdata) { 26253a5a1b3Sopenharmony_ci struct connection *c = userdata; 26353a5a1b3Sopenharmony_ci 26453a5a1b3Sopenharmony_ci pa_assert(c); 26553a5a1b3Sopenharmony_ci pa_assert(io); 26653a5a1b3Sopenharmony_ci 26753a5a1b3Sopenharmony_ci do_work(c); 26853a5a1b3Sopenharmony_ci} 26953a5a1b3Sopenharmony_ci 27053a5a1b3Sopenharmony_cistatic char *escape_html(const char *t) { 27153a5a1b3Sopenharmony_ci pa_strbuf *sb; 27253a5a1b3Sopenharmony_ci const char *p, *e; 27353a5a1b3Sopenharmony_ci 27453a5a1b3Sopenharmony_ci sb = pa_strbuf_new(); 27553a5a1b3Sopenharmony_ci 27653a5a1b3Sopenharmony_ci for (e = p = t; *p; p++) { 27753a5a1b3Sopenharmony_ci 27853a5a1b3Sopenharmony_ci if (*p == '>' || *p == '<' || *p == '&') { 27953a5a1b3Sopenharmony_ci 28053a5a1b3Sopenharmony_ci if (p > e) { 28153a5a1b3Sopenharmony_ci pa_strbuf_putsn(sb, e, p-e); 28253a5a1b3Sopenharmony_ci e = p + 1; 28353a5a1b3Sopenharmony_ci } 28453a5a1b3Sopenharmony_ci 28553a5a1b3Sopenharmony_ci if (*p == '>') 28653a5a1b3Sopenharmony_ci pa_strbuf_puts(sb, ">"); 28753a5a1b3Sopenharmony_ci else if (*p == '<') 28853a5a1b3Sopenharmony_ci pa_strbuf_puts(sb, "<"); 28953a5a1b3Sopenharmony_ci else 29053a5a1b3Sopenharmony_ci pa_strbuf_puts(sb, "&"); 29153a5a1b3Sopenharmony_ci } 29253a5a1b3Sopenharmony_ci } 29353a5a1b3Sopenharmony_ci 29453a5a1b3Sopenharmony_ci if (p > e) 29553a5a1b3Sopenharmony_ci pa_strbuf_putsn(sb, e, p-e); 29653a5a1b3Sopenharmony_ci 29753a5a1b3Sopenharmony_ci return pa_strbuf_to_string_free(sb); 29853a5a1b3Sopenharmony_ci} 29953a5a1b3Sopenharmony_ci 30053a5a1b3Sopenharmony_cistatic void http_response( 30153a5a1b3Sopenharmony_ci struct connection *c, 30253a5a1b3Sopenharmony_ci int code, 30353a5a1b3Sopenharmony_ci const char *msg, 30453a5a1b3Sopenharmony_ci const char *mime) { 30553a5a1b3Sopenharmony_ci 30653a5a1b3Sopenharmony_ci char *s; 30753a5a1b3Sopenharmony_ci 30853a5a1b3Sopenharmony_ci pa_assert(c); 30953a5a1b3Sopenharmony_ci pa_assert(msg); 31053a5a1b3Sopenharmony_ci pa_assert(mime); 31153a5a1b3Sopenharmony_ci 31253a5a1b3Sopenharmony_ci s = pa_sprintf_malloc( 31353a5a1b3Sopenharmony_ci "HTTP/1.0 %i %s\n" 31453a5a1b3Sopenharmony_ci "Connection: close\n" 31553a5a1b3Sopenharmony_ci "Content-Type: %s\n" 31653a5a1b3Sopenharmony_ci "Cache-Control: no-cache\n" 31753a5a1b3Sopenharmony_ci "Expires: 0\n" 31853a5a1b3Sopenharmony_ci "Server: "PACKAGE_NAME"/"PACKAGE_VERSION"\n" 31953a5a1b3Sopenharmony_ci "\n", code, msg, mime); 32053a5a1b3Sopenharmony_ci pa_ioline_puts(c->line, s); 32153a5a1b3Sopenharmony_ci pa_xfree(s); 32253a5a1b3Sopenharmony_ci} 32353a5a1b3Sopenharmony_ci 32453a5a1b3Sopenharmony_cistatic void html_response( 32553a5a1b3Sopenharmony_ci struct connection *c, 32653a5a1b3Sopenharmony_ci int code, 32753a5a1b3Sopenharmony_ci const char *msg, 32853a5a1b3Sopenharmony_ci const char *text) { 32953a5a1b3Sopenharmony_ci 33053a5a1b3Sopenharmony_ci char *s; 33153a5a1b3Sopenharmony_ci pa_assert(c); 33253a5a1b3Sopenharmony_ci 33353a5a1b3Sopenharmony_ci http_response(c, code, msg, MIME_HTML); 33453a5a1b3Sopenharmony_ci 33553a5a1b3Sopenharmony_ci if (c->method == METHOD_HEAD) { 33653a5a1b3Sopenharmony_ci pa_ioline_defer_close(c->line); 33753a5a1b3Sopenharmony_ci return; 33853a5a1b3Sopenharmony_ci } 33953a5a1b3Sopenharmony_ci 34053a5a1b3Sopenharmony_ci if (!text) 34153a5a1b3Sopenharmony_ci text = msg; 34253a5a1b3Sopenharmony_ci 34353a5a1b3Sopenharmony_ci s = pa_sprintf_malloc( 34453a5a1b3Sopenharmony_ci HTML_HEADER("%s") 34553a5a1b3Sopenharmony_ci "%s" 34653a5a1b3Sopenharmony_ci HTML_FOOTER, 34753a5a1b3Sopenharmony_ci text, text); 34853a5a1b3Sopenharmony_ci 34953a5a1b3Sopenharmony_ci pa_ioline_puts(c->line, s); 35053a5a1b3Sopenharmony_ci pa_xfree(s); 35153a5a1b3Sopenharmony_ci 35253a5a1b3Sopenharmony_ci pa_ioline_defer_close(c->line); 35353a5a1b3Sopenharmony_ci} 35453a5a1b3Sopenharmony_ci 35553a5a1b3Sopenharmony_cistatic void html_print_field(pa_ioline *line, const char *left, const char *right) { 35653a5a1b3Sopenharmony_ci char *eleft, *eright; 35753a5a1b3Sopenharmony_ci 35853a5a1b3Sopenharmony_ci eleft = escape_html(left); 35953a5a1b3Sopenharmony_ci eright = escape_html(right); 36053a5a1b3Sopenharmony_ci 36153a5a1b3Sopenharmony_ci pa_ioline_printf(line, 36253a5a1b3Sopenharmony_ci "<tr><td><b>%s</b></td>" 36353a5a1b3Sopenharmony_ci "<td>%s</td></tr>\n", eleft, eright); 36453a5a1b3Sopenharmony_ci 36553a5a1b3Sopenharmony_ci pa_xfree(eleft); 36653a5a1b3Sopenharmony_ci pa_xfree(eright); 36753a5a1b3Sopenharmony_ci} 36853a5a1b3Sopenharmony_ci 36953a5a1b3Sopenharmony_cistatic void handle_root(struct connection *c) { 37053a5a1b3Sopenharmony_ci char *t; 37153a5a1b3Sopenharmony_ci 37253a5a1b3Sopenharmony_ci pa_assert(c); 37353a5a1b3Sopenharmony_ci 37453a5a1b3Sopenharmony_ci http_response(c, 200, "OK", MIME_HTML); 37553a5a1b3Sopenharmony_ci 37653a5a1b3Sopenharmony_ci if (c->method == METHOD_HEAD) { 37753a5a1b3Sopenharmony_ci pa_ioline_defer_close(c->line); 37853a5a1b3Sopenharmony_ci return; 37953a5a1b3Sopenharmony_ci } 38053a5a1b3Sopenharmony_ci 38153a5a1b3Sopenharmony_ci pa_ioline_puts(c->line, 38253a5a1b3Sopenharmony_ci HTML_HEADER(PACKAGE_NAME" "PACKAGE_VERSION) 38353a5a1b3Sopenharmony_ci "<h1>"PACKAGE_NAME" "PACKAGE_VERSION"</h1>\n" 38453a5a1b3Sopenharmony_ci "<table>\n"); 38553a5a1b3Sopenharmony_ci 38653a5a1b3Sopenharmony_ci t = pa_get_user_name_malloc(); 38753a5a1b3Sopenharmony_ci html_print_field(c->line, "User Name:", t); 38853a5a1b3Sopenharmony_ci pa_xfree(t); 38953a5a1b3Sopenharmony_ci 39053a5a1b3Sopenharmony_ci t = pa_get_host_name_malloc(); 39153a5a1b3Sopenharmony_ci html_print_field(c->line, "Host name:", t); 39253a5a1b3Sopenharmony_ci pa_xfree(t); 39353a5a1b3Sopenharmony_ci 39453a5a1b3Sopenharmony_ci t = pa_machine_id(); 39553a5a1b3Sopenharmony_ci html_print_field(c->line, "Machine ID:", t); 39653a5a1b3Sopenharmony_ci pa_xfree(t); 39753a5a1b3Sopenharmony_ci 39853a5a1b3Sopenharmony_ci t = pa_uname_string(); 39953a5a1b3Sopenharmony_ci html_print_field(c->line, "System:", t); 40053a5a1b3Sopenharmony_ci pa_xfree(t); 40153a5a1b3Sopenharmony_ci 40253a5a1b3Sopenharmony_ci t = pa_sprintf_malloc("%lu", (unsigned long) getpid()); 40353a5a1b3Sopenharmony_ci html_print_field(c->line, "Process ID:", t); 40453a5a1b3Sopenharmony_ci pa_xfree(t); 40553a5a1b3Sopenharmony_ci 40653a5a1b3Sopenharmony_ci pa_ioline_puts(c->line, 40753a5a1b3Sopenharmony_ci "</table>\n" 40853a5a1b3Sopenharmony_ci "<p><a href=\"" URL_STATUS "\">Show an extensive server status report</a></p>\n" 40953a5a1b3Sopenharmony_ci "<p><a href=\"" URL_LISTEN "\">Monitor sinks and sources</a></p>\n" 41053a5a1b3Sopenharmony_ci HTML_FOOTER); 41153a5a1b3Sopenharmony_ci 41253a5a1b3Sopenharmony_ci pa_ioline_defer_close(c->line); 41353a5a1b3Sopenharmony_ci} 41453a5a1b3Sopenharmony_ci 41553a5a1b3Sopenharmony_cistatic void handle_css(struct connection *c) { 41653a5a1b3Sopenharmony_ci pa_assert(c); 41753a5a1b3Sopenharmony_ci 41853a5a1b3Sopenharmony_ci http_response(c, 200, "OK", MIME_CSS); 41953a5a1b3Sopenharmony_ci 42053a5a1b3Sopenharmony_ci if (c->method == METHOD_HEAD) { 42153a5a1b3Sopenharmony_ci pa_ioline_defer_close(c->line); 42253a5a1b3Sopenharmony_ci return; 42353a5a1b3Sopenharmony_ci } 42453a5a1b3Sopenharmony_ci 42553a5a1b3Sopenharmony_ci pa_ioline_puts(c->line, 42653a5a1b3Sopenharmony_ci "body { color: black; background-color: white; }\n" 42753a5a1b3Sopenharmony_ci "a:link, a:visited { color: #900000; }\n" 42853a5a1b3Sopenharmony_ci "div.news-date { font-size: 80%; font-style: italic; }\n" 42953a5a1b3Sopenharmony_ci "pre { background-color: #f0f0f0; padding: 0.4cm; }\n" 43053a5a1b3Sopenharmony_ci ".grey { color: #8f8f8f; font-size: 80%; }" 43153a5a1b3Sopenharmony_ci "table { margin-left: 1cm; border:1px solid lightgrey; padding: 0.2cm; }\n" 43253a5a1b3Sopenharmony_ci "td { padding-left:10px; padding-right:10px; }\n"); 43353a5a1b3Sopenharmony_ci 43453a5a1b3Sopenharmony_ci pa_ioline_defer_close(c->line); 43553a5a1b3Sopenharmony_ci} 43653a5a1b3Sopenharmony_ci 43753a5a1b3Sopenharmony_cistatic void handle_status(struct connection *c) { 43853a5a1b3Sopenharmony_ci char *r; 43953a5a1b3Sopenharmony_ci 44053a5a1b3Sopenharmony_ci pa_assert(c); 44153a5a1b3Sopenharmony_ci 44253a5a1b3Sopenharmony_ci http_response(c, 200, "OK", MIME_TEXT); 44353a5a1b3Sopenharmony_ci 44453a5a1b3Sopenharmony_ci if (c->method == METHOD_HEAD) { 44553a5a1b3Sopenharmony_ci pa_ioline_defer_close(c->line); 44653a5a1b3Sopenharmony_ci return; 44753a5a1b3Sopenharmony_ci } 44853a5a1b3Sopenharmony_ci 44953a5a1b3Sopenharmony_ci r = pa_full_status_string(c->protocol->core); 45053a5a1b3Sopenharmony_ci pa_ioline_puts(c->line, r); 45153a5a1b3Sopenharmony_ci pa_xfree(r); 45253a5a1b3Sopenharmony_ci 45353a5a1b3Sopenharmony_ci pa_ioline_defer_close(c->line); 45453a5a1b3Sopenharmony_ci} 45553a5a1b3Sopenharmony_ci 45653a5a1b3Sopenharmony_cistatic void handle_listen(struct connection *c) { 45753a5a1b3Sopenharmony_ci pa_source *source; 45853a5a1b3Sopenharmony_ci pa_sink *sink; 45953a5a1b3Sopenharmony_ci uint32_t idx; 46053a5a1b3Sopenharmony_ci 46153a5a1b3Sopenharmony_ci http_response(c, 200, "OK", MIME_HTML); 46253a5a1b3Sopenharmony_ci 46353a5a1b3Sopenharmony_ci pa_ioline_puts(c->line, 46453a5a1b3Sopenharmony_ci HTML_HEADER("Listen") 46553a5a1b3Sopenharmony_ci "<h2>Sinks</h2>\n" 46653a5a1b3Sopenharmony_ci "<p>\n"); 46753a5a1b3Sopenharmony_ci 46853a5a1b3Sopenharmony_ci if (c->method == METHOD_HEAD) { 46953a5a1b3Sopenharmony_ci pa_ioline_defer_close(c->line); 47053a5a1b3Sopenharmony_ci return; 47153a5a1b3Sopenharmony_ci } 47253a5a1b3Sopenharmony_ci 47353a5a1b3Sopenharmony_ci PA_IDXSET_FOREACH(sink, c->protocol->core->sinks, idx) { 47453a5a1b3Sopenharmony_ci char *t, *m; 47553a5a1b3Sopenharmony_ci 47653a5a1b3Sopenharmony_ci t = escape_html(pa_strna(pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_DESCRIPTION))); 47753a5a1b3Sopenharmony_ci m = pa_sample_spec_to_mime_type_mimefy(&sink->sample_spec, &sink->channel_map); 47853a5a1b3Sopenharmony_ci 47953a5a1b3Sopenharmony_ci pa_ioline_printf(c->line, 48053a5a1b3Sopenharmony_ci "<a href=\"" URL_LISTEN_SOURCE "%s\" title=\"%s\">%s</a><br/>\n", 48153a5a1b3Sopenharmony_ci sink->monitor_source->name, m, t); 48253a5a1b3Sopenharmony_ci 48353a5a1b3Sopenharmony_ci pa_xfree(t); 48453a5a1b3Sopenharmony_ci pa_xfree(m); 48553a5a1b3Sopenharmony_ci } 48653a5a1b3Sopenharmony_ci 48753a5a1b3Sopenharmony_ci pa_ioline_puts(c->line, 48853a5a1b3Sopenharmony_ci "</p>\n" 48953a5a1b3Sopenharmony_ci "<h2>Sources</h2>\n" 49053a5a1b3Sopenharmony_ci "<p>\n"); 49153a5a1b3Sopenharmony_ci 49253a5a1b3Sopenharmony_ci PA_IDXSET_FOREACH(source, c->protocol->core->sources, idx) { 49353a5a1b3Sopenharmony_ci char *t, *m; 49453a5a1b3Sopenharmony_ci 49553a5a1b3Sopenharmony_ci if (source->monitor_of) 49653a5a1b3Sopenharmony_ci continue; 49753a5a1b3Sopenharmony_ci 49853a5a1b3Sopenharmony_ci t = escape_html(pa_strna(pa_proplist_gets(source->proplist, PA_PROP_DEVICE_DESCRIPTION))); 49953a5a1b3Sopenharmony_ci m = pa_sample_spec_to_mime_type_mimefy(&source->sample_spec, &source->channel_map); 50053a5a1b3Sopenharmony_ci 50153a5a1b3Sopenharmony_ci pa_ioline_printf(c->line, 50253a5a1b3Sopenharmony_ci "<a href=\"" URL_LISTEN_SOURCE "%s\" title=\"%s\">%s</a><br/>\n", 50353a5a1b3Sopenharmony_ci source->name, m, t); 50453a5a1b3Sopenharmony_ci 50553a5a1b3Sopenharmony_ci pa_xfree(m); 50653a5a1b3Sopenharmony_ci pa_xfree(t); 50753a5a1b3Sopenharmony_ci 50853a5a1b3Sopenharmony_ci } 50953a5a1b3Sopenharmony_ci 51053a5a1b3Sopenharmony_ci pa_ioline_puts(c->line, 51153a5a1b3Sopenharmony_ci "</p>\n" 51253a5a1b3Sopenharmony_ci HTML_FOOTER); 51353a5a1b3Sopenharmony_ci 51453a5a1b3Sopenharmony_ci pa_ioline_defer_close(c->line); 51553a5a1b3Sopenharmony_ci} 51653a5a1b3Sopenharmony_ci 51753a5a1b3Sopenharmony_cistatic void line_drain_callback(pa_ioline *l, void *userdata) { 51853a5a1b3Sopenharmony_ci struct connection *c; 51953a5a1b3Sopenharmony_ci 52053a5a1b3Sopenharmony_ci pa_assert(l); 52153a5a1b3Sopenharmony_ci pa_assert_se(c = userdata); 52253a5a1b3Sopenharmony_ci 52353a5a1b3Sopenharmony_ci /* We don't need the line reader anymore, instead we need a real 52453a5a1b3Sopenharmony_ci * binary io channel */ 52553a5a1b3Sopenharmony_ci pa_assert_se(c->io = pa_ioline_detach_iochannel(c->line)); 52653a5a1b3Sopenharmony_ci pa_iochannel_set_callback(c->io, io_callback, c); 52753a5a1b3Sopenharmony_ci 52853a5a1b3Sopenharmony_ci pa_iochannel_socket_set_sndbuf(c->io, pa_memblockq_get_length(c->output_memblockq)); 52953a5a1b3Sopenharmony_ci 53053a5a1b3Sopenharmony_ci pa_ioline_unref(c->line); 53153a5a1b3Sopenharmony_ci c->line = NULL; 53253a5a1b3Sopenharmony_ci} 53353a5a1b3Sopenharmony_ci 53453a5a1b3Sopenharmony_cistatic void handle_listen_prefix(struct connection *c, const char *source_name) { 53553a5a1b3Sopenharmony_ci pa_source *source; 53653a5a1b3Sopenharmony_ci pa_source_output_new_data data; 53753a5a1b3Sopenharmony_ci pa_sample_spec ss; 53853a5a1b3Sopenharmony_ci pa_channel_map cm; 53953a5a1b3Sopenharmony_ci char *t; 54053a5a1b3Sopenharmony_ci size_t l; 54153a5a1b3Sopenharmony_ci 54253a5a1b3Sopenharmony_ci pa_assert(c); 54353a5a1b3Sopenharmony_ci pa_assert(source_name); 54453a5a1b3Sopenharmony_ci 54553a5a1b3Sopenharmony_ci pa_assert(c->line); 54653a5a1b3Sopenharmony_ci pa_assert(!c->io); 54753a5a1b3Sopenharmony_ci 54853a5a1b3Sopenharmony_ci if (!(source = pa_namereg_get(c->protocol->core, source_name, PA_NAMEREG_SOURCE))) { 54953a5a1b3Sopenharmony_ci html_response(c, 404, "Source not found", NULL); 55053a5a1b3Sopenharmony_ci return; 55153a5a1b3Sopenharmony_ci } 55253a5a1b3Sopenharmony_ci 55353a5a1b3Sopenharmony_ci ss = source->sample_spec; 55453a5a1b3Sopenharmony_ci cm = source->channel_map; 55553a5a1b3Sopenharmony_ci 55653a5a1b3Sopenharmony_ci pa_sample_spec_mimefy(&ss, &cm); 55753a5a1b3Sopenharmony_ci 55853a5a1b3Sopenharmony_ci pa_source_output_new_data_init(&data); 55953a5a1b3Sopenharmony_ci data.driver = __FILE__; 56053a5a1b3Sopenharmony_ci data.module = c->module; 56153a5a1b3Sopenharmony_ci data.client = c->client; 56253a5a1b3Sopenharmony_ci pa_source_output_new_data_set_source(&data, source, false, true); 56353a5a1b3Sopenharmony_ci pa_proplist_update(data.proplist, PA_UPDATE_MERGE, c->client->proplist); 56453a5a1b3Sopenharmony_ci pa_source_output_new_data_set_sample_spec(&data, &ss); 56553a5a1b3Sopenharmony_ci pa_source_output_new_data_set_channel_map(&data, &cm); 56653a5a1b3Sopenharmony_ci 56753a5a1b3Sopenharmony_ci pa_source_output_new(&c->source_output, c->protocol->core, &data); 56853a5a1b3Sopenharmony_ci pa_source_output_new_data_done(&data); 56953a5a1b3Sopenharmony_ci 57053a5a1b3Sopenharmony_ci if (!c->source_output) { 57153a5a1b3Sopenharmony_ci html_response(c, 403, "Cannot create source output", NULL); 57253a5a1b3Sopenharmony_ci return; 57353a5a1b3Sopenharmony_ci } 57453a5a1b3Sopenharmony_ci 57553a5a1b3Sopenharmony_ci c->source_output->parent.process_msg = source_output_process_msg; 57653a5a1b3Sopenharmony_ci c->source_output->push = source_output_push_cb; 57753a5a1b3Sopenharmony_ci c->source_output->kill = source_output_kill_cb; 57853a5a1b3Sopenharmony_ci c->source_output->get_latency = source_output_get_latency_cb; 57953a5a1b3Sopenharmony_ci c->source_output->userdata = c; 58053a5a1b3Sopenharmony_ci 58153a5a1b3Sopenharmony_ci pa_source_output_set_requested_latency(c->source_output, DEFAULT_SOURCE_LATENCY); 58253a5a1b3Sopenharmony_ci 58353a5a1b3Sopenharmony_ci l = (size_t) (pa_bytes_per_second(&ss)*RECORD_BUFFER_SECONDS); 58453a5a1b3Sopenharmony_ci c->output_memblockq = pa_memblockq_new( 58553a5a1b3Sopenharmony_ci "http protocol connection output_memblockq", 58653a5a1b3Sopenharmony_ci 0, 58753a5a1b3Sopenharmony_ci l, 58853a5a1b3Sopenharmony_ci 0, 58953a5a1b3Sopenharmony_ci &ss, 59053a5a1b3Sopenharmony_ci 1, 59153a5a1b3Sopenharmony_ci 0, 59253a5a1b3Sopenharmony_ci 0, 59353a5a1b3Sopenharmony_ci NULL); 59453a5a1b3Sopenharmony_ci 59553a5a1b3Sopenharmony_ci pa_source_output_put(c->source_output); 59653a5a1b3Sopenharmony_ci 59753a5a1b3Sopenharmony_ci t = pa_sample_spec_to_mime_type(&ss, &cm); 59853a5a1b3Sopenharmony_ci http_response(c, 200, "OK", t); 59953a5a1b3Sopenharmony_ci pa_xfree(t); 60053a5a1b3Sopenharmony_ci 60153a5a1b3Sopenharmony_ci if (c->method == METHOD_HEAD) { 60253a5a1b3Sopenharmony_ci connection_unlink(c); 60353a5a1b3Sopenharmony_ci return; 60453a5a1b3Sopenharmony_ci } 60553a5a1b3Sopenharmony_ci pa_ioline_set_callback(c->line, NULL, NULL); 60653a5a1b3Sopenharmony_ci 60753a5a1b3Sopenharmony_ci if (pa_ioline_is_drained(c->line)) 60853a5a1b3Sopenharmony_ci line_drain_callback(c->line, c); 60953a5a1b3Sopenharmony_ci else 61053a5a1b3Sopenharmony_ci pa_ioline_set_drain_callback(c->line, line_drain_callback, c); 61153a5a1b3Sopenharmony_ci} 61253a5a1b3Sopenharmony_ci 61353a5a1b3Sopenharmony_cistatic void handle_url(struct connection *c) { 61453a5a1b3Sopenharmony_ci pa_assert(c); 61553a5a1b3Sopenharmony_ci 61653a5a1b3Sopenharmony_ci pa_log_debug("Request for %s", c->url); 61753a5a1b3Sopenharmony_ci 61853a5a1b3Sopenharmony_ci if (pa_streq(c->url, URL_ROOT)) 61953a5a1b3Sopenharmony_ci handle_root(c); 62053a5a1b3Sopenharmony_ci else if (pa_streq(c->url, URL_CSS)) 62153a5a1b3Sopenharmony_ci handle_css(c); 62253a5a1b3Sopenharmony_ci else if (pa_streq(c->url, URL_STATUS)) 62353a5a1b3Sopenharmony_ci handle_status(c); 62453a5a1b3Sopenharmony_ci else if (pa_streq(c->url, URL_LISTEN)) 62553a5a1b3Sopenharmony_ci handle_listen(c); 62653a5a1b3Sopenharmony_ci else if (pa_startswith(c->url, URL_LISTEN_SOURCE)) 62753a5a1b3Sopenharmony_ci handle_listen_prefix(c, c->url + sizeof(URL_LISTEN_SOURCE)-1); 62853a5a1b3Sopenharmony_ci else 62953a5a1b3Sopenharmony_ci html_response(c, 404, "Not Found", NULL); 63053a5a1b3Sopenharmony_ci} 63153a5a1b3Sopenharmony_ci 63253a5a1b3Sopenharmony_cistatic void line_callback(pa_ioline *line, const char *s, void *userdata) { 63353a5a1b3Sopenharmony_ci struct connection *c = userdata; 63453a5a1b3Sopenharmony_ci pa_assert(line); 63553a5a1b3Sopenharmony_ci pa_assert(c); 63653a5a1b3Sopenharmony_ci 63753a5a1b3Sopenharmony_ci if (!s) { 63853a5a1b3Sopenharmony_ci /* EOF */ 63953a5a1b3Sopenharmony_ci connection_unlink(c); 64053a5a1b3Sopenharmony_ci return; 64153a5a1b3Sopenharmony_ci } 64253a5a1b3Sopenharmony_ci 64353a5a1b3Sopenharmony_ci switch (c->state) { 64453a5a1b3Sopenharmony_ci case STATE_REQUEST_LINE: { 64553a5a1b3Sopenharmony_ci if (pa_startswith(s, "GET ")) { 64653a5a1b3Sopenharmony_ci c->method = METHOD_GET; 64753a5a1b3Sopenharmony_ci s +=4; 64853a5a1b3Sopenharmony_ci } else if (pa_startswith(s, "HEAD ")) { 64953a5a1b3Sopenharmony_ci c->method = METHOD_HEAD; 65053a5a1b3Sopenharmony_ci s +=5; 65153a5a1b3Sopenharmony_ci } else { 65253a5a1b3Sopenharmony_ci goto fail; 65353a5a1b3Sopenharmony_ci } 65453a5a1b3Sopenharmony_ci 65553a5a1b3Sopenharmony_ci c->url = pa_xstrndup(s, strcspn(s, " \r\n\t?")); 65653a5a1b3Sopenharmony_ci c->state = STATE_MIME_HEADER; 65753a5a1b3Sopenharmony_ci break; 65853a5a1b3Sopenharmony_ci } 65953a5a1b3Sopenharmony_ci 66053a5a1b3Sopenharmony_ci case STATE_MIME_HEADER: { 66153a5a1b3Sopenharmony_ci 66253a5a1b3Sopenharmony_ci /* Ignore MIME headers */ 66353a5a1b3Sopenharmony_ci if (strcspn(s, " \r\n") != 0) 66453a5a1b3Sopenharmony_ci break; 66553a5a1b3Sopenharmony_ci 66653a5a1b3Sopenharmony_ci /* We're done */ 66753a5a1b3Sopenharmony_ci c->state = STATE_DATA; 66853a5a1b3Sopenharmony_ci 66953a5a1b3Sopenharmony_ci handle_url(c); 67053a5a1b3Sopenharmony_ci break; 67153a5a1b3Sopenharmony_ci } 67253a5a1b3Sopenharmony_ci 67353a5a1b3Sopenharmony_ci default: 67453a5a1b3Sopenharmony_ci ; 67553a5a1b3Sopenharmony_ci } 67653a5a1b3Sopenharmony_ci 67753a5a1b3Sopenharmony_ci return; 67853a5a1b3Sopenharmony_ci 67953a5a1b3Sopenharmony_cifail: 68053a5a1b3Sopenharmony_ci html_response(c, 500, "Internal Server Error", NULL); 68153a5a1b3Sopenharmony_ci} 68253a5a1b3Sopenharmony_ci 68353a5a1b3Sopenharmony_civoid pa_http_protocol_connect(pa_http_protocol *p, pa_iochannel *io, pa_module *m) { 68453a5a1b3Sopenharmony_ci struct connection *c; 68553a5a1b3Sopenharmony_ci pa_client_new_data client_data; 68653a5a1b3Sopenharmony_ci char pname[128]; 68753a5a1b3Sopenharmony_ci 68853a5a1b3Sopenharmony_ci pa_assert(p); 68953a5a1b3Sopenharmony_ci pa_assert(io); 69053a5a1b3Sopenharmony_ci pa_assert(m); 69153a5a1b3Sopenharmony_ci 69253a5a1b3Sopenharmony_ci if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) { 69353a5a1b3Sopenharmony_ci pa_log("Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS); 69453a5a1b3Sopenharmony_ci pa_iochannel_free(io); 69553a5a1b3Sopenharmony_ci return; 69653a5a1b3Sopenharmony_ci } 69753a5a1b3Sopenharmony_ci 69853a5a1b3Sopenharmony_ci c = pa_xnew0(struct connection, 1); 69953a5a1b3Sopenharmony_ci c->protocol = p; 70053a5a1b3Sopenharmony_ci c->state = STATE_REQUEST_LINE; 70153a5a1b3Sopenharmony_ci c->module = m; 70253a5a1b3Sopenharmony_ci 70353a5a1b3Sopenharmony_ci c->line = pa_ioline_new(io); 70453a5a1b3Sopenharmony_ci pa_ioline_set_callback(c->line, line_callback, c); 70553a5a1b3Sopenharmony_ci 70653a5a1b3Sopenharmony_ci pa_client_new_data_init(&client_data); 70753a5a1b3Sopenharmony_ci client_data.module = c->module; 70853a5a1b3Sopenharmony_ci client_data.driver = __FILE__; 70953a5a1b3Sopenharmony_ci pa_iochannel_socket_peer_to_string(io, pname, sizeof(pname)); 71053a5a1b3Sopenharmony_ci pa_proplist_setf(client_data.proplist, PA_PROP_APPLICATION_NAME, "HTTP client (%s)", pname); 71153a5a1b3Sopenharmony_ci pa_proplist_sets(client_data.proplist, "http-protocol.peer", pname); 71253a5a1b3Sopenharmony_ci c->client = pa_client_new(p->core, &client_data); 71353a5a1b3Sopenharmony_ci pa_client_new_data_done(&client_data); 71453a5a1b3Sopenharmony_ci 71553a5a1b3Sopenharmony_ci if (!c->client) 71653a5a1b3Sopenharmony_ci goto fail; 71753a5a1b3Sopenharmony_ci 71853a5a1b3Sopenharmony_ci c->client->kill = client_kill_cb; 71953a5a1b3Sopenharmony_ci c->client->userdata = c; 72053a5a1b3Sopenharmony_ci 72153a5a1b3Sopenharmony_ci pa_idxset_put(p->connections, c, NULL); 72253a5a1b3Sopenharmony_ci 72353a5a1b3Sopenharmony_ci return; 72453a5a1b3Sopenharmony_ci 72553a5a1b3Sopenharmony_cifail: 72653a5a1b3Sopenharmony_ci if (c) 72753a5a1b3Sopenharmony_ci connection_unlink(c); 72853a5a1b3Sopenharmony_ci} 72953a5a1b3Sopenharmony_ci 73053a5a1b3Sopenharmony_civoid pa_http_protocol_disconnect(pa_http_protocol *p, pa_module *m) { 73153a5a1b3Sopenharmony_ci struct connection *c; 73253a5a1b3Sopenharmony_ci uint32_t idx; 73353a5a1b3Sopenharmony_ci 73453a5a1b3Sopenharmony_ci pa_assert(p); 73553a5a1b3Sopenharmony_ci pa_assert(m); 73653a5a1b3Sopenharmony_ci 73753a5a1b3Sopenharmony_ci PA_IDXSET_FOREACH(c, p->connections, idx) 73853a5a1b3Sopenharmony_ci if (c->module == m) 73953a5a1b3Sopenharmony_ci connection_unlink(c); 74053a5a1b3Sopenharmony_ci} 74153a5a1b3Sopenharmony_ci 74253a5a1b3Sopenharmony_cistatic pa_http_protocol* http_protocol_new(pa_core *c) { 74353a5a1b3Sopenharmony_ci pa_http_protocol *p; 74453a5a1b3Sopenharmony_ci 74553a5a1b3Sopenharmony_ci pa_assert(c); 74653a5a1b3Sopenharmony_ci 74753a5a1b3Sopenharmony_ci p = pa_xnew0(pa_http_protocol, 1); 74853a5a1b3Sopenharmony_ci PA_REFCNT_INIT(p); 74953a5a1b3Sopenharmony_ci p->core = c; 75053a5a1b3Sopenharmony_ci p->connections = pa_idxset_new(NULL, NULL); 75153a5a1b3Sopenharmony_ci 75253a5a1b3Sopenharmony_ci pa_assert_se(pa_shared_set(c, "http-protocol", p) >= 0); 75353a5a1b3Sopenharmony_ci 75453a5a1b3Sopenharmony_ci return p; 75553a5a1b3Sopenharmony_ci} 75653a5a1b3Sopenharmony_ci 75753a5a1b3Sopenharmony_cipa_http_protocol* pa_http_protocol_get(pa_core *c) { 75853a5a1b3Sopenharmony_ci pa_http_protocol *p; 75953a5a1b3Sopenharmony_ci 76053a5a1b3Sopenharmony_ci if ((p = pa_shared_get(c, "http-protocol"))) 76153a5a1b3Sopenharmony_ci return pa_http_protocol_ref(p); 76253a5a1b3Sopenharmony_ci 76353a5a1b3Sopenharmony_ci return http_protocol_new(c); 76453a5a1b3Sopenharmony_ci} 76553a5a1b3Sopenharmony_ci 76653a5a1b3Sopenharmony_cipa_http_protocol* pa_http_protocol_ref(pa_http_protocol *p) { 76753a5a1b3Sopenharmony_ci pa_assert(p); 76853a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(p) >= 1); 76953a5a1b3Sopenharmony_ci 77053a5a1b3Sopenharmony_ci PA_REFCNT_INC(p); 77153a5a1b3Sopenharmony_ci 77253a5a1b3Sopenharmony_ci return p; 77353a5a1b3Sopenharmony_ci} 77453a5a1b3Sopenharmony_ci 77553a5a1b3Sopenharmony_civoid pa_http_protocol_unref(pa_http_protocol *p) { 77653a5a1b3Sopenharmony_ci struct connection *c; 77753a5a1b3Sopenharmony_ci 77853a5a1b3Sopenharmony_ci pa_assert(p); 77953a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(p) >= 1); 78053a5a1b3Sopenharmony_ci 78153a5a1b3Sopenharmony_ci if (PA_REFCNT_DEC(p) > 0) 78253a5a1b3Sopenharmony_ci return; 78353a5a1b3Sopenharmony_ci 78453a5a1b3Sopenharmony_ci while ((c = pa_idxset_first(p->connections, NULL))) 78553a5a1b3Sopenharmony_ci connection_unlink(c); 78653a5a1b3Sopenharmony_ci 78753a5a1b3Sopenharmony_ci pa_idxset_free(p->connections, NULL); 78853a5a1b3Sopenharmony_ci 78953a5a1b3Sopenharmony_ci pa_strlist_free(p->servers); 79053a5a1b3Sopenharmony_ci 79153a5a1b3Sopenharmony_ci pa_assert_se(pa_shared_remove(p->core, "http-protocol") >= 0); 79253a5a1b3Sopenharmony_ci 79353a5a1b3Sopenharmony_ci pa_xfree(p); 79453a5a1b3Sopenharmony_ci} 79553a5a1b3Sopenharmony_ci 79653a5a1b3Sopenharmony_civoid pa_http_protocol_add_server_string(pa_http_protocol *p, const char *name) { 79753a5a1b3Sopenharmony_ci pa_assert(p); 79853a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(p) >= 1); 79953a5a1b3Sopenharmony_ci pa_assert(name); 80053a5a1b3Sopenharmony_ci 80153a5a1b3Sopenharmony_ci p->servers = pa_strlist_prepend(p->servers, name); 80253a5a1b3Sopenharmony_ci} 80353a5a1b3Sopenharmony_ci 80453a5a1b3Sopenharmony_civoid pa_http_protocol_remove_server_string(pa_http_protocol *p, const char *name) { 80553a5a1b3Sopenharmony_ci pa_assert(p); 80653a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(p) >= 1); 80753a5a1b3Sopenharmony_ci pa_assert(name); 80853a5a1b3Sopenharmony_ci 80953a5a1b3Sopenharmony_ci p->servers = pa_strlist_remove(p->servers, name); 81053a5a1b3Sopenharmony_ci} 81153a5a1b3Sopenharmony_ci 81253a5a1b3Sopenharmony_cipa_strlist *pa_http_protocol_servers(pa_http_protocol *p) { 81353a5a1b3Sopenharmony_ci pa_assert(p); 81453a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(p) >= 1); 81553a5a1b3Sopenharmony_ci 81653a5a1b3Sopenharmony_ci return p->servers; 81753a5a1b3Sopenharmony_ci} 818