The srbchannel is enabled if protocol version >= 30 and SHM is available. There is also a module parameter srbchannel=false that can be used for disabling the srbchannel. The setup is done in these steps: 1) Server receives authentication (like today) 2) Server sends enable_srbchannel to client 3) Server sends memblock to client 4) Client receives enable_srbchannel 5) Client receives memblock 6) Client sends enable_srbchannel back to server 7) Client switches over 8) Server receives enable_srbchannel and switches over Signed-off-by: David Henningsson <david.henningsson at canonical.com> --- src/modules/module-protocol-stub.c | 6 ++- src/pulsecore/protocol-native.c | 75 ++++++++++++++++++++++++++++++++++++++ src/pulsecore/protocol-native.h | 1 + 3 files changed, 81 insertions(+), 1 deletion(-) diff --git a/src/modules/module-protocol-stub.c b/src/modules/module-protocol-stub.c index 3218a01..118351e 100644 --- a/src/modules/module-protocol-stub.c +++ b/src/modules/module-protocol-stub.c @@ -120,14 +120,17 @@ # endif # if defined(HAVE_CREDS) && !defined(USE_TCP_SOCKETS) -# define MODULE_ARGUMENTS MODULE_ARGUMENTS_COMMON "auth-group", "auth-group-enable", +# define MODULE_ARGUMENTS MODULE_ARGUMENTS_COMMON "auth-group", "auth-group-enable", "srbchannel", # define AUTH_USAGE "auth-group=<system group to allow access> auth-group-enable=<enable auth by UNIX group?> " +# define SRB_USAGE "srbchannel=<enable shared ringbuffer communication channel?> " # elif defined(USE_TCP_SOCKETS) # define MODULE_ARGUMENTS MODULE_ARGUMENTS_COMMON "auth-ip-acl", # define AUTH_USAGE "auth-ip-acl=<IP address ACL to allow access> " +# define SRB_USAGE # else # define MODULE_ARGUMENTS MODULE_ARGUMENTS_COMMON # define AUTH_USAGE +# define SRB_USAGE # endif PA_MODULE_DESCRIPTION("Native protocol "SOCKET_DESCRIPTION); @@ -135,6 +138,7 @@ "auth-cookie=<path to cookie file> " "auth-cookie-enabled=<enable cookie authentication?> " AUTH_USAGE + SRB_USAGE SOCKET_USAGE); #elif defined(USE_PROTOCOL_ESOUND) # include <pulsecore/protocol-esound.h> diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index 7262944..589013b 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -181,6 +181,7 @@ struct pa_native_connection { uint32_t rrobin_index; pa_subscription *subscription; pa_time_event *auth_timeout_event; + pa_srbchannel *srpending; }; #define PA_NATIVE_CONNECTION(o) (pa_native_connection_cast(o)) @@ -294,6 +295,7 @@ static void command_extension(pa_pdispatch *pd, uint32_t command, uint32_t tag, static void command_set_card_profile(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); static void command_set_sink_or_source_port(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); static void command_set_port_latency_offset(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_enable_srbchannel(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = { [PA_COMMAND_ERROR] = NULL, @@ -397,6 +399,8 @@ static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = { [PA_COMMAND_SET_PORT_LATENCY_OFFSET] = command_set_port_latency_offset, + [PA_COMMAND_ENABLE_SRBCHANNEL] = command_enable_srbchannel, + [PA_COMMAND_EXTENSION] = command_extension }; @@ -1327,6 +1331,9 @@ static void native_connection_unlink(pa_native_connection *c) { if (c->options) pa_native_options_unref(c->options); + if (c->srpending) + pa_srbchannel_free(c->srpending); + while ((r = pa_idxset_first(c->record_streams, NULL))) record_stream_unlink(r); @@ -2578,6 +2585,65 @@ static void command_exit(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_ta pa_pstream_send_simple_ack(c->pstream, tag); /* nonsense */ } +static void setup_srbchannel(pa_native_connection *c) { + pa_srbchannel_template srt; + pa_srbchannel *sr; + pa_memchunk mc; + pa_tagstruct *t; + int fdlist[2]; + + if (!c->options->srbchannel) { + pa_log_debug("Disabling srbchannel, reason: Disabled by module parameter"); + return; + } + + if (c->version < 30) { + pa_log_debug("Disabling srbchannel, reason: Protocol too old"); + return; + } + + if (!pa_pstream_get_shm(c->pstream)) { + pa_log_debug("Disabling srbchannel, reason: No SHM support"); + return; + } + + if (!c->protocol->core->rw_mempool) { + pa_log_debug("Disabling srbchannel, reason: No rw memory pool"); + return; + } + + pa_log_debug("Enabling srbchannel..."); + sr = pa_srbchannel_new(c->protocol->core->mainloop, c->protocol->core->rw_mempool); + pa_srbchannel_export(sr, &srt); + + /* Send enable command to client */ + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_ENABLE_SRBCHANNEL); + pa_tagstruct_putu32(t, (size_t) sr); /* tag */ + fdlist[0] = srt.readfd; + fdlist[1] = srt.writefd; + pa_pstream_send_tagstruct_with_fds(c->pstream, t, 2, fdlist); + + /* Send ringbuffer memblock to client */ + mc.memblock = srt.memblock; + mc.index = 0; + mc.length = pa_memblock_get_length(srt.memblock); + pa_pstream_send_memblock(c->pstream, 0, 0, 0, &mc); + + c->srpending = sr; +} + +static void command_enable_srbchannel(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); + + if (tag != (uint32_t) (size_t) c->srpending) + protocol_error(c); + + pa_log_debug("Client enabled srbchannel."); + pa_pstream_set_srbchannel(c->pstream, c->srpending); + c->srpending = NULL; +} + static void command_auth(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); const void*cookie; @@ -2709,6 +2775,8 @@ static void command_auth(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_ta #else pa_pstream_send_tagstruct(c->pstream, reply); #endif + + setup_srbchannel(c); } static void command_set_client_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { @@ -5017,6 +5085,7 @@ void pa_native_protocol_connect(pa_native_protocol *p, pa_iochannel *io, pa_nati c->protocol = p; c->options = pa_native_options_ref(o); c->authorized = false; + c->srpending = NULL; if (o->auth_anonymous) { pa_log_info("Client authenticated anonymously."); @@ -5247,6 +5316,12 @@ int pa_native_options_parse(pa_native_options *o, pa_core *c, pa_modargs *ma) { pa_assert(PA_REFCNT_VALUE(o) >= 1); pa_assert(ma); + o->srbchannel = true; + if (pa_modargs_get_value_boolean(ma, "srbchannel", &o->srbchannel) < 0) { + pa_log("srbchannel= expects a boolean argument."); + return -1; + } + if (pa_modargs_get_value_boolean(ma, "auth-anonymous", &o->auth_anonymous) < 0) { pa_log("auth-anonymous= expects a boolean argument."); return -1; diff --git a/src/pulsecore/protocol-native.h b/src/pulsecore/protocol-native.h index 30b99f9..df30d44 100644 --- a/src/pulsecore/protocol-native.h +++ b/src/pulsecore/protocol-native.h @@ -44,6 +44,7 @@ typedef struct pa_native_options { pa_module *module; bool auth_anonymous; + bool srbchannel; char *auth_group; pa_ip_acl *auth_ip_acl; pa_auth_cookie *auth_cookie; -- 1.9.1