mirror of
https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
synced 2025-11-01 22:58:47 -04:00
protocol-http: substantial modernizations
This commit is contained in:
parent
d8710711fb
commit
0b2d96d6c0
1 changed files with 394 additions and 103 deletions
|
|
@ -42,20 +42,39 @@
|
|||
/* Don't allow more than this many concurrent connections */
|
||||
#define MAX_CONNECTIONS 10
|
||||
|
||||
#define internal_server_error(c) http_message((c), 500, "Internal Server Error", NULL)
|
||||
|
||||
#define URL_ROOT "/"
|
||||
#define URL_CSS "/style"
|
||||
#define URL_STATUS "/status"
|
||||
#define URL_LISTEN "/listen"
|
||||
#define URL_LISTEN_PREFIX "/listen/"
|
||||
|
||||
#define MIME_HTML "text/html; charset=utf-8"
|
||||
#define MIME_TEXT "text/plain; charset=utf-8"
|
||||
#define MIME_CSS "text/css"
|
||||
|
||||
#define HTML_HEADER(t) \
|
||||
"<?xml version=\"1.0\"?>\n" \
|
||||
"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n" \
|
||||
"<html xmlns=\"http://www.w3.org/1999/xhtml\">\n" \
|
||||
" <head>\n" \
|
||||
" <title>"t"</title>\n" \
|
||||
" <link rel=\"stylesheet\" type=\"text/css\" href=\"style\"/>\n" \
|
||||
" </head>\n" \
|
||||
" <body>\n"
|
||||
|
||||
#define HTML_FOOTER \
|
||||
" </body>\n" \
|
||||
"</html>\n"
|
||||
enum state {
|
||||
STATE_REQUEST_LINE,
|
||||
STATE_MIME_HEADER,
|
||||
STATE_DATA
|
||||
};
|
||||
|
||||
struct connection {
|
||||
pa_http_protocol *protocol;
|
||||
pa_ioline *line;
|
||||
enum {
|
||||
REQUEST_LINE,
|
||||
MIME_HEADER,
|
||||
DATA
|
||||
} state;
|
||||
enum state state;
|
||||
char *url;
|
||||
pa_module *module;
|
||||
};
|
||||
|
|
@ -67,45 +86,242 @@ struct pa_http_protocol {
|
|||
pa_idxset *connections;
|
||||
};
|
||||
|
||||
static void http_response(struct connection *c, int code, const char *msg, const char *mime) {
|
||||
char s[256];
|
||||
|
||||
static pa_bool_t is_mime_sample_spec(const pa_sample_spec *ss, const pa_channel_map *cm) {
|
||||
|
||||
pa_assert(pa_channel_map_compatible(cm, ss));
|
||||
|
||||
switch (ss->format) {
|
||||
case PA_SAMPLE_S16BE:
|
||||
case PA_SAMPLE_S24BE:
|
||||
case PA_SAMPLE_U8:
|
||||
|
||||
if (ss->rate != 8000 &&
|
||||
ss->rate != 11025 &&
|
||||
ss->rate != 16000 &&
|
||||
ss->rate != 22050 &&
|
||||
ss->rate != 24000 &&
|
||||
ss->rate != 32000 &&
|
||||
ss->rate != 44100 &&
|
||||
ss->rate != 48000)
|
||||
return FALSE;
|
||||
|
||||
if (ss->channels != 1 &&
|
||||
ss->channels != 2)
|
||||
return FALSE;
|
||||
|
||||
if ((cm->channels == 1 && cm->map[0] != PA_CHANNEL_POSITION_MONO) ||
|
||||
(cm->channels == 2 && (cm->map[0] != PA_CHANNEL_POSITION_LEFT || cm->map[1] != PA_CHANNEL_POSITION_RIGHT)))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
|
||||
case PA_SAMPLE_ULAW:
|
||||
|
||||
if (ss->rate != 8000)
|
||||
return FALSE;
|
||||
|
||||
if (ss->channels != 1)
|
||||
return FALSE;
|
||||
|
||||
if (cm->map[0] != PA_CHANNEL_POSITION_MONO)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static void mimefy_sample_spec(pa_sample_spec *ss, pa_channel_map *cm) {
|
||||
|
||||
pa_assert(pa_channel_map_compatible(cm, ss));
|
||||
|
||||
/* Turns the sample type passed in into the next 'better' one that
|
||||
* can be encoded for HTTP. If there is no 'better' one we pick
|
||||
* the 'best' one that is 'worse'. */
|
||||
|
||||
if (ss->channels > 2)
|
||||
ss->channels = 2;
|
||||
|
||||
if (ss->rate > 44100)
|
||||
ss->rate = 48000;
|
||||
else if (ss->rate > 32000)
|
||||
ss->rate = 44100;
|
||||
else if (ss->rate > 24000)
|
||||
ss->rate = 32000;
|
||||
else if (ss->rate > 22050)
|
||||
ss->rate = 24000;
|
||||
else if (ss->rate > 16000)
|
||||
ss->rate = 22050;
|
||||
else if (ss->rate > 11025)
|
||||
ss->rate = 16000;
|
||||
else if (ss->rate > 8000)
|
||||
ss->rate = 11025;
|
||||
else
|
||||
ss->rate = 8000;
|
||||
|
||||
switch (ss->format) {
|
||||
case PA_SAMPLE_S24BE:
|
||||
case PA_SAMPLE_S24LE:
|
||||
case PA_SAMPLE_S24_32LE:
|
||||
case PA_SAMPLE_S24_32BE:
|
||||
case PA_SAMPLE_S32LE:
|
||||
case PA_SAMPLE_S32BE:
|
||||
case PA_SAMPLE_FLOAT32LE:
|
||||
case PA_SAMPLE_FLOAT32BE:
|
||||
ss->format = PA_SAMPLE_S24BE;
|
||||
break;
|
||||
|
||||
case PA_SAMPLE_S16BE:
|
||||
case PA_SAMPLE_S16LE:
|
||||
ss->format = PA_SAMPLE_S16BE;
|
||||
break;
|
||||
|
||||
case PA_SAMPLE_ULAW:
|
||||
case PA_SAMPLE_ALAW:
|
||||
|
||||
if (ss->rate == 8000 && ss->channels == 1)
|
||||
ss->format = PA_SAMPLE_ULAW;
|
||||
else
|
||||
ss->format = PA_SAMPLE_S16BE;
|
||||
break;
|
||||
|
||||
case PA_SAMPLE_U8:
|
||||
ss->format = PA_SAMPLE_U8;
|
||||
break;
|
||||
|
||||
case PA_SAMPLE_MAX:
|
||||
case PA_SAMPLE_INVALID:
|
||||
pa_assert_not_reached();
|
||||
}
|
||||
|
||||
pa_channel_map_init_auto(cm, ss->channels, PA_CHANNEL_MAP_DEFAULT);
|
||||
|
||||
pa_assert(is_mime_sample_spec(ss, cm));
|
||||
}
|
||||
|
||||
static char *sample_spec_to_mime_type(const pa_sample_spec *ss, const pa_channel_map *cm) {
|
||||
pa_assert(pa_channel_map_compatible(cm, ss));
|
||||
|
||||
if (!is_mime_sample_spec(ss, cm))
|
||||
return NULL;
|
||||
|
||||
switch (ss->format) {
|
||||
|
||||
case PA_SAMPLE_S16BE:
|
||||
case PA_SAMPLE_S24BE:
|
||||
case PA_SAMPLE_U8:
|
||||
return pa_sprintf_malloc("audio/%s; rate=%u; channels=%u",
|
||||
ss->format == PA_SAMPLE_S16BE ? "L16" :
|
||||
(ss->format == PA_SAMPLE_S24BE ? "L24" : "L8"),
|
||||
ss->rate, ss->channels);
|
||||
|
||||
case PA_SAMPLE_ULAW:
|
||||
return pa_xstrdup("audio/basic");
|
||||
|
||||
default:
|
||||
pa_assert_not_reached();
|
||||
}
|
||||
|
||||
pa_assert(pa_sample_spec_valid(ss));
|
||||
}
|
||||
|
||||
static char *mimefy_and_stringify_sample_spec(const pa_sample_spec *_ss, const pa_channel_map *_cm) {
|
||||
pa_sample_spec ss = *_ss;
|
||||
pa_channel_map cm = *_cm;
|
||||
|
||||
mimefy_sample_spec(&ss, &cm);
|
||||
|
||||
return sample_spec_to_mime_type(&ss, &cm);
|
||||
}
|
||||
|
||||
static char *escape_html(const char *t) {
|
||||
pa_strbuf *sb;
|
||||
const char *p, *e;
|
||||
|
||||
sb = pa_strbuf_new();
|
||||
|
||||
for (e = p = t; *p; p++) {
|
||||
|
||||
if (*p == '>' || *p == '<' || *p == '&') {
|
||||
|
||||
if (p > e) {
|
||||
pa_strbuf_putsn(sb, e, p-e);
|
||||
e = p + 1;
|
||||
}
|
||||
|
||||
if (*p == '>')
|
||||
pa_strbuf_puts(sb, ">");
|
||||
else if (*p == '<')
|
||||
pa_strbuf_puts(sb, "<");
|
||||
else
|
||||
pa_strbuf_puts(sb, "&");
|
||||
}
|
||||
}
|
||||
|
||||
if (p > e)
|
||||
pa_strbuf_putsn(sb, e, p-e);
|
||||
|
||||
return pa_strbuf_tostring_free(sb);
|
||||
}
|
||||
|
||||
static void http_response(
|
||||
struct connection *c,
|
||||
int code,
|
||||
const char *msg,
|
||||
const char *mime) {
|
||||
|
||||
char *s;
|
||||
|
||||
pa_assert(c);
|
||||
pa_assert(msg);
|
||||
pa_assert(mime);
|
||||
|
||||
pa_snprintf(s, sizeof(s),
|
||||
"HTTP/1.0 %i %s\n"
|
||||
"Connection: close\n"
|
||||
"Content-Type: %s\n"
|
||||
"Cache-Control: no-cache\n"
|
||||
"Expires: 0\n"
|
||||
"Server: "PACKAGE_NAME"/"PACKAGE_VERSION"\n"
|
||||
"\n", code, msg, mime);
|
||||
|
||||
s = pa_sprintf_malloc(
|
||||
"HTTP/1.0 %i %s\n"
|
||||
"Connection: close\n"
|
||||
"Content-Type: %s\n"
|
||||
"Cache-Control: no-cache\n"
|
||||
"Expires: 0\n"
|
||||
"Server: "PACKAGE_NAME"/"PACKAGE_VERSION"\n"
|
||||
"\n", code, msg, mime);
|
||||
pa_ioline_puts(c->line, s);
|
||||
pa_xfree(s);
|
||||
}
|
||||
|
||||
static void http_message(struct connection *c, int code, const char *msg, const char *text) {
|
||||
char s[256];
|
||||
static void html_response(
|
||||
struct connection *c,
|
||||
int code,
|
||||
const char *msg,
|
||||
const char *text) {
|
||||
|
||||
char *s;
|
||||
pa_assert(c);
|
||||
|
||||
http_response(c, code, msg, "text/html");
|
||||
http_response(c, code, msg, MIME_HTML);
|
||||
|
||||
if (!text)
|
||||
text = msg;
|
||||
|
||||
pa_snprintf(s, sizeof(s),
|
||||
"<?xml version=\"1.0\"?>\n"
|
||||
"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n"
|
||||
"<html xmlns=\"http://www.w3.org/1999/xhtml\"><head><title>%s</title></head>\n"
|
||||
"<body>%s</body></html>\n",
|
||||
text, text);
|
||||
s = pa_sprintf_malloc(
|
||||
HTML_HEADER("%s")
|
||||
"%s"
|
||||
HTML_FOOTER,
|
||||
text, text);
|
||||
|
||||
pa_ioline_puts(c->line, s);
|
||||
pa_xfree(s);
|
||||
|
||||
pa_ioline_defer_close(c->line);
|
||||
}
|
||||
|
||||
static void internal_server_error(struct connection *c) {
|
||||
pa_assert(c);
|
||||
|
||||
html_response(c, 500, "Internal Server Error", NULL);
|
||||
}
|
||||
|
||||
static void connection_unlink(struct connection *c) {
|
||||
pa_assert(c);
|
||||
|
|
@ -113,12 +329,153 @@ static void connection_unlink(struct connection *c) {
|
|||
if (c->url)
|
||||
pa_xfree(c->url);
|
||||
|
||||
if (c->line)
|
||||
pa_ioline_unref(c->line);
|
||||
|
||||
pa_idxset_remove_by_data(c->protocol->connections, c, NULL);
|
||||
|
||||
pa_ioline_unref(c->line);
|
||||
pa_xfree(c);
|
||||
}
|
||||
|
||||
static void html_print_field(pa_ioline *line, const char *left, const char *right) {
|
||||
char *eleft, *eright;
|
||||
|
||||
eleft = escape_html(left);
|
||||
eright = escape_html(right);
|
||||
|
||||
pa_ioline_printf(line,
|
||||
"<tr><td><b>%s</b></td>"
|
||||
"<td>%s</td></tr>\n", eleft, eright);
|
||||
|
||||
pa_xfree(eleft);
|
||||
pa_xfree(eright);
|
||||
}
|
||||
|
||||
static void handle_url(struct connection *c) {
|
||||
pa_assert(c);
|
||||
|
||||
pa_log_debug("Request for %s", c->url);
|
||||
|
||||
if (pa_streq(c->url, URL_ROOT)) {
|
||||
char *t;
|
||||
|
||||
http_response(c, 200, "OK", MIME_HTML);
|
||||
|
||||
pa_ioline_puts(c->line,
|
||||
HTML_HEADER(PACKAGE_NAME" "PACKAGE_VERSION)
|
||||
"<h1>"PACKAGE_NAME" "PACKAGE_VERSION"</h1>\n"
|
||||
"<table>\n");
|
||||
|
||||
t = pa_get_user_name_malloc();
|
||||
html_print_field(c->line, "User Name:", t);
|
||||
pa_xfree(t);
|
||||
|
||||
t = pa_get_host_name_malloc();
|
||||
html_print_field(c->line, "Host name:", t);
|
||||
pa_xfree(t);
|
||||
|
||||
t = pa_machine_id();
|
||||
html_print_field(c->line, "Machine ID:", t);
|
||||
pa_xfree(t);
|
||||
|
||||
t = pa_uname_string();
|
||||
html_print_field(c->line, "System:", t);
|
||||
pa_xfree(t);
|
||||
|
||||
t = pa_sprintf_malloc("%lu", (unsigned long) getpid());
|
||||
html_print_field(c->line, "Process ID:", t);
|
||||
pa_xfree(t);
|
||||
|
||||
pa_ioline_puts(c->line,
|
||||
"</table>\n"
|
||||
"<p><a href=\"/status\">Show an extensive server status report</a></p>\n"
|
||||
"<p><a href=\"/listen\">Monitor sinks and sources</a></p>\n"
|
||||
HTML_FOOTER);
|
||||
|
||||
pa_ioline_defer_close(c->line);
|
||||
|
||||
} else if (pa_streq(c->url, URL_CSS)) {
|
||||
http_response(c, 200, "OK", MIME_CSS);
|
||||
|
||||
pa_ioline_puts(c->line,
|
||||
"body { color: black; background-color: white; }\n"
|
||||
"a:link, a:visited { color: #900000; }\n"
|
||||
"div.news-date { font-size: 80%; font-style: italic; }\n"
|
||||
"pre { background-color: #f0f0f0; padding: 0.4cm; }\n"
|
||||
".grey { color: #8f8f8f; font-size: 80%; }"
|
||||
"table { margin-left: 1cm; border:1px solid lightgrey; padding: 0.2cm; }\n"
|
||||
"td { padding-left:10px; padding-right:10px; }\n");
|
||||
|
||||
pa_ioline_defer_close(c->line);
|
||||
|
||||
} else if (pa_streq(c->url, URL_STATUS)) {
|
||||
char *r;
|
||||
|
||||
http_response(c, 200, "OK", MIME_TEXT);
|
||||
r = pa_full_status_string(c->protocol->core);
|
||||
pa_ioline_puts(c->line, r);
|
||||
pa_xfree(r);
|
||||
|
||||
pa_ioline_defer_close(c->line);
|
||||
|
||||
} else if (pa_streq(c->url, URL_LISTEN)) {
|
||||
pa_source *source;
|
||||
pa_sink *sink;
|
||||
uint32_t idx;
|
||||
|
||||
http_response(c, 200, "OK", MIME_HTML);
|
||||
|
||||
pa_ioline_puts(c->line,
|
||||
HTML_HEADER("Listen")
|
||||
"<h2>Sinks</h2>\n"
|
||||
"<p>\n");
|
||||
|
||||
PA_IDXSET_FOREACH(sink, c->protocol->core->sinks, idx) {
|
||||
char *t, *m;
|
||||
|
||||
t = escape_html(pa_strna(pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_DESCRIPTION)));
|
||||
m = mimefy_and_stringify_sample_spec(&sink->sample_spec, &sink->channel_map);
|
||||
|
||||
pa_ioline_printf(c->line,
|
||||
"<a href=\"/listen/%s\" title=\"%s\">%s</a><br/>\n",
|
||||
sink->monitor_source->name, m, t);
|
||||
|
||||
pa_xfree(t);
|
||||
pa_xfree(m);
|
||||
}
|
||||
|
||||
pa_ioline_puts(c->line,
|
||||
"</p>\n"
|
||||
"<h2>Sources</h2>\n"
|
||||
"<p>\n");
|
||||
|
||||
PA_IDXSET_FOREACH(source, c->protocol->core->sources, idx) {
|
||||
char *t, *m;
|
||||
|
||||
if (source->monitor_of)
|
||||
continue;
|
||||
|
||||
t = escape_html(pa_strna(pa_proplist_gets(source->proplist, PA_PROP_DEVICE_DESCRIPTION)));
|
||||
m = mimefy_and_stringify_sample_spec(&source->sample_spec, &source->channel_map);
|
||||
|
||||
pa_ioline_printf(c->line,
|
||||
"<a href=\"/listen/%s\" title=\"%s\">%s</a><br/>\n",
|
||||
source->name, m, t);
|
||||
|
||||
pa_xfree(m);
|
||||
pa_xfree(t);
|
||||
|
||||
}
|
||||
|
||||
pa_ioline_puts(c->line,
|
||||
"</p>\n"
|
||||
HTML_FOOTER);
|
||||
|
||||
pa_ioline_defer_close(c->line);
|
||||
} else
|
||||
html_response(c, 404, "Not Found", NULL);
|
||||
}
|
||||
|
||||
static void line_callback(pa_ioline *line, const char *s, void *userdata) {
|
||||
struct connection *c = userdata;
|
||||
pa_assert(line);
|
||||
|
|
@ -131,93 +488,27 @@ static void line_callback(pa_ioline *line, const char *s, void *userdata) {
|
|||
}
|
||||
|
||||
switch (c->state) {
|
||||
case REQUEST_LINE: {
|
||||
if (memcmp(s, "GET ", 4))
|
||||
case STATE_REQUEST_LINE: {
|
||||
if (!pa_startswith(s, "GET "))
|
||||
goto fail;
|
||||
|
||||
s +=4;
|
||||
|
||||
c->url = pa_xstrndup(s, strcspn(s, " \r\n\t?"));
|
||||
c->state = MIME_HEADER;
|
||||
c->state = STATE_MIME_HEADER;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
case MIME_HEADER: {
|
||||
case STATE_MIME_HEADER: {
|
||||
|
||||
/* Ignore MIME headers */
|
||||
if (strcspn(s, " \r\n") != 0)
|
||||
break;
|
||||
|
||||
/* We're done */
|
||||
c->state = DATA;
|
||||
|
||||
pa_log_info("request for %s", c->url);
|
||||
|
||||
if (!strcmp(c->url, URL_ROOT)) {
|
||||
char txt[256];
|
||||
pa_sink *def_sink;
|
||||
pa_source *def_source;
|
||||
http_response(c, 200, "OK", "text/html");
|
||||
|
||||
pa_ioline_puts(c->line,
|
||||
"<?xml version=\"1.0\"?>\n"
|
||||
"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n"
|
||||
"<html xmlns=\"http://www.w3.org/1999/xhtml\"><title>"PACKAGE_NAME" "PACKAGE_VERSION"</title>\n"
|
||||
"<link rel=\"stylesheet\" type=\"text/css\" href=\"style\"/></head><body>\n");
|
||||
|
||||
pa_ioline_puts(c->line,
|
||||
"<h1>"PACKAGE_NAME" "PACKAGE_VERSION"</h1>\n"
|
||||
"<table>");
|
||||
|
||||
#define PRINTF_FIELD(a,b) pa_ioline_printf(c->line, "<tr><td><b>%s</b></td><td>%s</td></tr>\n",(a),(b))
|
||||
|
||||
PRINTF_FIELD("User Name:", pa_get_user_name(txt, sizeof(txt)));
|
||||
PRINTF_FIELD("Host name:", pa_get_host_name(txt, sizeof(txt)));
|
||||
PRINTF_FIELD("Default Sample Specification:", pa_sample_spec_snprint(txt, sizeof(txt), &c->protocol->core->default_sample_spec));
|
||||
|
||||
def_sink = pa_namereg_get_default_sink(c->protocol->core);
|
||||
def_source = pa_namereg_get_default_source(c->protocol->core);
|
||||
|
||||
PRINTF_FIELD("Default Sink:", def_sink ? def_sink->name : "n/a");
|
||||
PRINTF_FIELD("Default Source:", def_source ? def_source->name : "n/a");
|
||||
|
||||
pa_ioline_puts(c->line, "</table>");
|
||||
|
||||
pa_ioline_puts(c->line, "<p><a href=\"/status\">Click here</a> for an extensive server status report.</p>");
|
||||
|
||||
pa_ioline_puts(c->line, "</body></html>\n");
|
||||
|
||||
pa_ioline_defer_close(c->line);
|
||||
} else if (!strcmp(c->url, URL_CSS)) {
|
||||
http_response(c, 200, "OK", "text/css");
|
||||
|
||||
pa_ioline_puts(c->line,
|
||||
"body { color: black; background-color: white; margin: 0.5cm; }\n"
|
||||
"a:link, a:visited { color: #900000; }\n"
|
||||
"p { margin-left: 0.5cm; margin-right: 0.5cm; }\n"
|
||||
"h1 { color: #00009F; }\n"
|
||||
"h2 { color: #00009F; }\n"
|
||||
"ul { margin-left: .5cm; }\n"
|
||||
"ol { margin-left: .5cm; }\n"
|
||||
"pre { margin-left: .5cm; background-color: #f0f0f0; padding: 0.4cm;}\n"
|
||||
".grey { color: #afafaf; }\n"
|
||||
"table { margin-left: 1cm; border:1px solid lightgrey; padding: 0.2cm; }\n"
|
||||
"td { padding-left:10px; padding-right:10px; }\n");
|
||||
|
||||
pa_ioline_defer_close(c->line);
|
||||
} else if (!strcmp(c->url, URL_STATUS)) {
|
||||
char *r;
|
||||
|
||||
http_response(c, 200, "OK", "text/plain");
|
||||
r = pa_full_status_string(c->protocol->core);
|
||||
pa_ioline_puts(c->line, r);
|
||||
pa_xfree(r);
|
||||
|
||||
pa_ioline_defer_close(c->line);
|
||||
} else
|
||||
http_message(c, 404, "Not Found", NULL);
|
||||
c->state = STATE_DATA;
|
||||
|
||||
handle_url(c);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -247,7 +538,7 @@ void pa_http_protocol_connect(pa_http_protocol *p, pa_iochannel *io, pa_module *
|
|||
c = pa_xnew(struct connection, 1);
|
||||
c->protocol = p;
|
||||
c->line = pa_ioline_new(io);
|
||||
c->state = REQUEST_LINE;
|
||||
c->state = STATE_REQUEST_LINE;
|
||||
c->url = NULL;
|
||||
c->module = m;
|
||||
|
||||
|
|
@ -258,12 +549,12 @@ void pa_http_protocol_connect(pa_http_protocol *p, pa_iochannel *io, pa_module *
|
|||
|
||||
void pa_http_protocol_disconnect(pa_http_protocol *p, pa_module *m) {
|
||||
struct connection *c;
|
||||
void *state = NULL;
|
||||
uint32_t idx;
|
||||
|
||||
pa_assert(p);
|
||||
pa_assert(m);
|
||||
|
||||
while ((c = pa_idxset_iterate(p->connections, &state, NULL)))
|
||||
PA_IDXSET_FOREACH(c, p->connections, idx)
|
||||
if (c->module == m)
|
||||
connection_unlink(c);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue