From b55923a8d33a1c4ed2f892a0da36c9c679e7d828 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 7 Nov 2004 20:48:46 +0000 Subject: * Look for M4 in configure.ac * Share auth cookies in module-tunnel.c, module-x11-publish.c and native-protocol.c * disable TCP_NODELAY * publish auth cookie in module-x11-publish git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@274 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/Makefile.am | 16 +++++---- polyp/authkey-prop.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++ polyp/authkey-prop.h | 39 +++++++++++++++++++++ polyp/authkey.c | 6 ++-- polyp/module-match.c | 2 +- polyp/module-tunnel.c | 43 ++++++++++++++++++++--- polyp/module-x11-publish.c | 46 ++++++++++++++++++++++-- polyp/module.c | 2 ++ polyp/native-common.h | 2 ++ polyp/protocol-native.c | 43 +++++++++++++++++++---- polyp/socket-util.c | 2 ++ polyp/util.c | 17 +++++++++ polyp/util.h | 2 ++ 13 files changed, 284 insertions(+), 23 deletions(-) create mode 100644 polyp/authkey-prop.c create mode 100644 polyp/authkey-prop.h (limited to 'polyp') diff --git a/polyp/Makefile.am b/polyp/Makefile.am index 1ed1b28f..b0b863e5 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -84,6 +84,7 @@ modlib_LTLIBRARIES= \ libpstream-util.la \ libpdispatch.la \ libauthkey.la \ + libauthkey-prop.la \ libprotocol-simple.la \ libprotocol-esound.la \ libprotocol-native.la \ @@ -199,7 +200,7 @@ polypaudio_CFLAGS = $(AM_CFLAGS) $(LIBSAMPLERATE_CFLAGS) $(LIBSNDFILE_CFLAGS) polypaudio_INCLUDES = $(INCLTDL) polypaudio_LDADD = $(AM_LDADD) $(LIBLTDL) $(LIBSAMPLERATE_LIBS) $(LIBSNDFILE_LIBS) $(CAP_LIBS) polypaudio_LDFLAGS= -export-dynamic -dlopen force -#-static $(foreach f,$(modlib_LTLIBRARIES),-dlpreopen $(f)) +# -static $(foreach f,$(modlib_LTLIBRARIES),-dlpreopen $(f)) libprotocol_simple_la_SOURCES = protocol-simple.c protocol-simple.h libprotocol_simple_la_LDFLAGS = -avoid-version @@ -249,7 +250,7 @@ libprotocol_cli_la_LIBADD = $(AM_LIBADD) libsocket-server.la libiochannel.la lib libprotocol_native_la_SOURCES = protocol-native.c protocol-native.h native-common.h libprotocol_native_la_LDFLAGS = -avoid-version -libprotocol_native_la_LIBADD = $(AM_LIBADD) libsocket-server.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la +libprotocol_native_la_LIBADD = $(AM_LIBADD) libsocket-server.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la libauthkey-prop.la libtagstruct_la_SOURCES = tagstruct.c tagstruct.h libtagstruct_la_LDFLAGS = -avoid-version @@ -261,6 +262,9 @@ libprotocol_esound_la_LIBADD = $(AM_LIBADD) libsocket-server.la libiochannel.la libauthkey_la_SOURCES = authkey.c authkey.h libauthkey_la_LDFLAGS = -avoid-version +libauthkey_prop_la_SOURCES = authkey-prop.c authkey-prop.h +libauthkey_prop_la_LDFLAGS = -avoid-version + libsocket_util_la_SOURCES = socket-util.c socket-util.h libsocket_util_la_LDFLAGS = -avoid-version @@ -348,11 +352,11 @@ module_match_la_LIBADD = $(AM_LIBADD) module_tunnel_sink_la_SOURCES = module-tunnel.c module_tunnel_sink_la_CFLAGS = -DTUNNEL_SINK=1 $(AM_CFLAGS) module_tunnel_sink_la_LDFLAGS = -module -avoid-version -module_tunnel_sink_la_LIBADD = $(AM_LIBADD) libsocket-client.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la +module_tunnel_sink_la_LIBADD = $(AM_LIBADD) libsocket-client.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la libauthkey-prop.la libsocket-util.la libiochannel.la module_tunnel_source_la_SOURCES = module-tunnel.c module_tunnel_source_la_LDFLAGS = -module -avoid-version -module_tunnel_source_la_LIBADD = $(AM_LIBADD) libsocket-client.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la +module_tunnel_source_la_LIBADD = $(AM_LIBADD) libsocket-client.la libpstream.la libpstream-util.la libpdispatch.la libtagstruct.la libauthkey.la libauthkey-prop.la libsocket-util.la libiochannel.la module_esound_compat_spawnfd_la_SOURCES = module-esound-compat-spawnfd.c module_esound_compat_spawnfd_la_LDFLAGS = -module -avoid-version @@ -477,7 +481,7 @@ module_x11_bell_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA module_x11_publish_la_SOURCES = module-x11-publish.c module_x11_publish_la_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS) module_x11_publish_la_LDFLAGS = -module -avoid-version -module_x11_publish_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIB) libx11wrap.la +module_x11_publish_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIB) libx11wrap.la libauthkey.la libauthkey-prop.la endif @@ -645,4 +649,4 @@ install-exec-hook: chmod u+s $(DESTDIR)$(bindir)/polypaudio $(SYMDEF_FILES): module-defs.h.m4 - m4 -Dfname="$@" $< > $@ + $(M4) -Dfname="$@" $< > $@ diff --git a/polyp/authkey-prop.c b/polyp/authkey-prop.c new file mode 100644 index 00000000..13227955 --- /dev/null +++ b/polyp/authkey-prop.c @@ -0,0 +1,87 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include +#include + +#include "xmalloc.h" +#include "authkey-prop.h" +#include "props.h" +#include "log.h" + +struct authkey_data { + int ref; + size_t length; +}; + +int pa_authkey_prop_get(struct pa_core *c, const char *name, void *data, size_t len) { + struct authkey_data *a; + assert(c && name && data && len > 0); + + if (!(a = pa_property_get(c, name))) + return -1; + + assert(a->length == len); + memcpy(data, a+1, len); + return 0; +} + +int pa_authkey_prop_put(struct pa_core *c, const char *name, const void *data, size_t len) { + struct authkey_data *a; + assert(c && name); + + if (pa_property_get(c, name)) + return -1; + + a = pa_xmalloc(sizeof(struct authkey_data) + len); + a->ref = 1; + a->length = len; + memcpy(a+1, data, len); + + pa_property_set(c, name, a); + + return 0; +} + +void pa_authkey_prop_ref(struct pa_core *c, const char *name) { + struct authkey_data *a; + assert(c && name); + + a = pa_property_get(c, name); + assert(a && a->ref >= 1); + + a->ref++; +} + +void pa_authkey_prop_unref(struct pa_core *c, const char *name) { + struct authkey_data *a; + assert(c && name); + + a = pa_property_get(c, name); + assert(a && a->ref >= 1); + + if (!(--a->ref)) { + pa_property_remove(c, name); + pa_xfree(a); + } +} + + diff --git a/polyp/authkey-prop.h b/polyp/authkey-prop.h new file mode 100644 index 00000000..d9ba5122 --- /dev/null +++ b/polyp/authkey-prop.h @@ -0,0 +1,39 @@ +#ifndef fooauthkeyprophfoo +#define fooauthkeyprophfoo + +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#include "core.h" + +/* Return the data of the specified authorization key property. Doesn't alter the refernce count of the key */ +int pa_authkey_prop_get(struct pa_core *c, const char *name, void *data, size_t len); + +/* Store data in the specified authorization key property. The initial reference count is set to 1 */ +int pa_authkey_prop_put(struct pa_core *c, const char *name, const void *data, size_t len); + +/* Increase the reference count of the specified authorization key */ +void pa_authkey_prop_ref(struct pa_core *c, const char *name); + +/* Decrease the reference count of the specified authorization key */ +void pa_authkey_prop_unref(struct pa_core *c, const char *name); + +#endif diff --git a/polyp/authkey.c b/polyp/authkey.c index d3cb382b..773484e9 100644 --- a/polyp/authkey.c +++ b/polyp/authkey.c @@ -145,17 +145,17 @@ int pa_authkey_load(const char *path, void *data, size_t length) { } int pa_authkey_load_from_home(const char *fn, void *data, size_t length) { - char *home; char path[PATH_MAX]; const char *p; assert(fn && data && length); if (fn[0] != '/') { - if (!(home = getenv("HOME"))) + char homedir[PATH_MAX]; + if (!pa_get_home_dir(homedir, sizeof(homedir))) return -2; - snprintf(path, sizeof(path), "%s/%s", home, fn); + snprintf(path, sizeof(path), "%s/%s", homedir, fn); p = path; } else p = fn; diff --git a/polyp/module-match.c b/polyp/module-match.c index 176c338f..0398cede 100644 --- a/polyp/module-match.c +++ b/polyp/module-match.c @@ -53,7 +53,7 @@ PA_MODULE_VERSION(PACKAGE_VERSION) #endif #define DEFAULT_MATCH_TABLE_FILE DEFAULT_CONFIG_DIR"/match.table" -#define DEFAULT_MATCH_TABLE_FILE_USER ".polypaudio/.match.table" +#define DEFAULT_MATCH_TABLE_FILE_USER ".polypaudio/match.table" static const char* const valid_modargs[] = { "table", diff --git a/polyp/module-tunnel.c b/polyp/module-tunnel.c index 2e22258a..c899929f 100644 --- a/polyp/module-tunnel.c +++ b/polyp/module-tunnel.c @@ -45,6 +45,7 @@ #include "authkey.h" #include "socket-client.h" #include "socket-util.h" +#include "authkey-prop.h" #ifdef TUNNEL_SINK #include "module-tunnel-sink-symdef.h" @@ -129,10 +130,13 @@ struct userdata { pa_usec_t host_latency; struct pa_time_event *time_event; -}; + int auth_cookie_in_property; +}; static void close_stuff(struct userdata *u) { + assert(u); + if (u->pstream) { pa_pstream_close(u->pstream); pa_pstream_unref(u->pstream); @@ -532,6 +536,32 @@ static void timeout_callback(struct pa_mainloop_api *m, struct pa_time_event*e, m->time_restart(e, &ntv); } +static int load_key(struct userdata *u, const char*fn) { + assert(u); + + u->auth_cookie_in_property = 0; + + if (!fn && pa_authkey_prop_get(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME, u->auth_cookie, sizeof(u->auth_cookie)) >= 0) { + pa_log(__FILE__": using already loaded auth cookie.\n"); + pa_authkey_prop_ref(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME); + u->auth_cookie_in_property = 1; + return 0; + } + + if (!fn) + fn = PA_NATIVE_COOKIE_FILE; + + if (pa_authkey_load_from_home(fn, u->auth_cookie, sizeof(u->auth_cookie)) < 0) + return -1; + + pa_log(__FILE__": loading cookie from disk.\n"); + + if (pa_authkey_prop_put(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME, u->auth_cookie, sizeof(u->auth_cookie)) >= 0) + u->auth_cookie_in_property = 1; + + return 0; +} + int pa__init(struct pa_core *c, struct pa_module*m) { struct pa_modargs *ma = NULL; struct userdata *u = NULL; @@ -563,11 +593,11 @@ int pa__init(struct pa_core *c, struct pa_module*m) { u->ctag = 1; u->device_index = u->channel = PA_INVALID_INDEX; u->host_latency = 0; - - if (pa_authkey_load_from_home(pa_modargs_get_value(ma, "cookie", PA_NATIVE_COOKIE_FILE), u->auth_cookie, sizeof(u->auth_cookie)) < 0) { - pa_log(__FILE__": failed to load cookie.\n"); + u->auth_cookie_in_property = 0; + u->time_event = NULL; + + if (load_key(u, pa_modargs_get_value(ma, "cookie", NULL)) < 0) goto fail; - } if (!(u->server_name = pa_xstrdup(pa_modargs_get_value(ma, "server", NULL)))) { pa_log(__FILE__": no server specified.\n"); @@ -650,6 +680,9 @@ void pa__done(struct pa_core *c, struct pa_module*m) { close_stuff(u); + if (u->auth_cookie_in_property) + pa_authkey_prop_unref(c, PA_NATIVE_COOKIE_PROPERTY_NAME); + #ifdef TUNNEL_SINK pa_xfree(u->sink_name); #else diff --git a/polyp/module-x11-publish.c b/polyp/module-x11-publish.c index fd4df4ad..a488f6d5 100644 --- a/polyp/module-x11-publish.c +++ b/polyp/module-x11-publish.c @@ -41,8 +41,10 @@ #include "log.h" #include "x11wrap.h" #include "util.h" - +#include "native-common.h" #include "module-x11-publish-symdef.h" +#include "authkey-prop.h" +#include "authkey.h" PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_DESCRIPTION("X11 Credential Publisher") @@ -53,6 +55,7 @@ static const char* const valid_modargs[] = { "display", "sink", "source", + "cookie", NULL }; @@ -61,6 +64,8 @@ struct userdata { struct pa_x11_wrapper *x11_wrapper; Display *display; char *id; + uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH]; + int auth_cookie_in_property; }; static void set_x11_prop(Display *d, const char *name, const char *data) { @@ -91,11 +96,38 @@ static char* get_x11_prop(Display *d, const char *name, char *p, size_t l) { return p; } +static int load_key(struct userdata *u, const char*fn) { + assert(u); + + u->auth_cookie_in_property = 0; + + if (!fn && pa_authkey_prop_get(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME, u->auth_cookie, sizeof(u->auth_cookie)) >= 0) { + pa_log(__FILE__": using already loaded auth cookie.\n"); + pa_authkey_prop_ref(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME); + u->auth_cookie_in_property = 1; + return 0; + } + + if (!fn) + fn = PA_NATIVE_COOKIE_FILE; + + if (pa_authkey_load_from_home(fn, u->auth_cookie, sizeof(u->auth_cookie)) < 0) + return -1; + + pa_log(__FILE__": loading cookie from disk.\n"); + + if (pa_authkey_prop_put(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME, u->auth_cookie, sizeof(u->auth_cookie)) >= 0) + u->auth_cookie_in_property = 1; + + return 0; +} + int pa__init(struct pa_core *c, struct pa_module*m) { struct userdata *u; struct pa_modargs *ma = NULL; char hn[256], un[128]; - const char *t; + char hx[PA_NATIVE_COOKIE_LENGTH*2+1]; + const char *t; if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { pa_log(__FILE__": failed to parse module arguments\n"); @@ -105,6 +137,10 @@ int pa__init(struct pa_core *c, struct pa_module*m) { m->userdata = u = pa_xmalloc(sizeof(struct userdata)); u->core = c; u->id = NULL; + u->auth_cookie_in_property = 0; + + if (load_key(u, pa_modargs_get_value(ma, "cookie", NULL)) < 0) + goto fail; if (!(u->x11_wrapper = pa_x11_wrapper_get(c, pa_modargs_get_value(ma, "display", NULL)))) goto fail; @@ -124,6 +160,8 @@ int pa__init(struct pa_core *c, struct pa_module*m) { if ((t = pa_modargs_get_value(ma, "sink", NULL))) set_x11_prop(u->display, "POLYP_SINK", t); + + set_x11_prop(u->display, "POLYP_COOKIE", pa_hexstr(u->auth_cookie, sizeof(u->auth_cookie), hx, sizeof(hx))); pa_modargs_free(ma); return 0; @@ -154,6 +192,7 @@ void pa__done(struct pa_core *c, struct pa_module*m) { del_x11_prop(u->display, "POLYP_SERVER"); del_x11_prop(u->display, "POLYP_SINK"); del_x11_prop(u->display, "POLYP_SOURCE"); + del_x11_prop(u->display, "POLYP_COOKIE"); XSync(u->display, False); } } @@ -161,6 +200,9 @@ void pa__done(struct pa_core *c, struct pa_module*m) { if (u->x11_wrapper) pa_x11_wrapper_unref(u->x11_wrapper); + if (u->auth_cookie_in_property) + pa_authkey_prop_unref(c, PA_NATIVE_COOKIE_PROPERTY_NAME); + pa_xfree(u->id); pa_xfree(u); } diff --git a/polyp/module.c b/polyp/module.c index 3fb42d87..9ecdfe29 100644 --- a/polyp/module.c +++ b/polyp/module.c @@ -135,6 +135,8 @@ static void pa_module_free(struct pa_module *m) { if (m->core->disallow_module_loading) return; + pa_log(__FILE__": Unloading \"%s\" (index: #%u).\n", m->name, m->index); + m->done(m->core, m); lt_dlclose(m->dl); diff --git a/polyp/native-common.h b/polyp/native-common.h index 33ecdc76..fbee74c9 100644 --- a/polyp/native-common.h +++ b/polyp/native-common.h @@ -98,6 +98,8 @@ enum { #define PA_NATIVE_DEFAULT_PORT 4713 +#define PA_NATIVE_COOKIE_PROPERTY_NAME "protocol-native-cookie" + PA_C_DECL_END #endif diff --git a/polyp/protocol-native.c b/polyp/protocol-native.c index 6f3f82be..fade2a2f 100644 --- a/polyp/protocol-native.c +++ b/polyp/protocol-native.c @@ -46,6 +46,7 @@ #include "subscribe.h" #include "log.h" #include "autoload.h" +#include "authkey-prop.h" struct connection; struct pa_protocol_native; @@ -106,6 +107,7 @@ struct pa_protocol_native { struct pa_socket_server *server; struct pa_idxset *connections; uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH]; + int auth_cookie_in_property; }; static int sink_input_peek_cb(struct pa_sink_input *i, struct pa_memchunk *chunk); @@ -2008,6 +2010,32 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo /*** module entry points ***/ +static int load_key(struct pa_protocol_native*p, const char*fn) { + assert(p); + + p->auth_cookie_in_property = 0; + + if (!fn && pa_authkey_prop_get(p->core, PA_NATIVE_COOKIE_PROPERTY_NAME, p->auth_cookie, sizeof(p->auth_cookie)) >= 0) { + pa_log(__FILE__": using already loaded auth cookie.\n"); + pa_authkey_prop_ref(p->core, PA_NATIVE_COOKIE_PROPERTY_NAME); + p->auth_cookie_in_property = 1; + return 0; + } + + if (!fn) + fn = PA_NATIVE_COOKIE_FILE; + + if (pa_authkey_load_from_home(fn, p->auth_cookie, sizeof(p->auth_cookie)) < 0) + return -1; + + pa_log(__FILE__": loading cookie from disk.\n"); + + if (pa_authkey_prop_put(p->core, PA_NATIVE_COOKIE_PROPERTY_NAME, p->auth_cookie, sizeof(p->auth_cookie)) >= 0) + p->auth_cookie_in_property = 1; + + return 0; +} + static struct pa_protocol_native* protocol_new_internal(struct pa_core *c, struct pa_module *m, struct pa_modargs *ma) { struct pa_protocol_native *p; int public = 0; @@ -2019,16 +2047,16 @@ static struct pa_protocol_native* protocol_new_internal(struct pa_core *c, struc } p = pa_xmalloc(sizeof(struct pa_protocol_native)); + p->core = c; + p->module = m; + p->public = public; + p->server = NULL; - if (pa_authkey_load_from_home(pa_modargs_get_value(ma, "cookie", PA_NATIVE_COOKIE_FILE), p->auth_cookie, sizeof(p->auth_cookie)) < 0) { + if (load_key(p, pa_modargs_get_value(ma, "cookie", NULL)) < 0) { pa_xfree(p); return NULL; } - p->module = m; - p->public = public; - p->server = NULL; - p->core = c; p->connections = pa_idxset_new(NULL, NULL); assert(p->connections); @@ -2057,7 +2085,10 @@ void pa_protocol_native_free(struct pa_protocol_native *p) { if (p->server) pa_socket_server_unref(p->server); - + + if (p->auth_cookie_in_property) + pa_authkey_prop_unref(p->core, PA_NATIVE_COOKIE_PROPERTY_NAME); + pa_xfree(p); } diff --git a/polyp/socket-util.c b/polyp/socket-util.c index 4e1eb6ab..96ea2c60 100644 --- a/polyp/socket-util.c +++ b/polyp/socket-util.c @@ -114,6 +114,7 @@ int pa_socket_tcp_low_delay(int fd) { ret = pa_socket_low_delay(fd); on = 1; +/* #if defined(SOL_TCP) || defined(IPPROTO_TCP) #if defined(SOL_TCP) if (setsockopt(fd, SOL_TCP, TCP_NODELAY, &on, sizeof(on)) < 0) @@ -122,6 +123,7 @@ int pa_socket_tcp_low_delay(int fd) { #endif ret = -1; #endif +*/ #if defined(IPTOS_LOWDELAY) && defined(IP_TOS) && (defined(SOL_IP) || \ defined(IPPROTO_IP)) diff --git a/polyp/util.c b/polyp/util.c index 6e97bae4..97b3a26b 100644 --- a/polyp/util.c +++ b/polyp/util.c @@ -715,3 +715,20 @@ FILE *pa_open_config_file(const char *global, const char *local, const char *env return fopen(global, "r"); } +/* Format the specified data as a hexademical string */ +char *pa_hexstr(const uint8_t* d, size_t dlength, char *s, size_t slength) { + size_t i = 0, j = 0; + const char hex[] = "0123456789abcdef"; + assert(d && s && slength > 0); + + while (i < dlength && j+3 <= slength) { + s[j++] = hex[*d >> 4]; + s[j++] = hex[*d & 0xF]; + + d++; + i++; + } + + s[j < slength ? j : slength] = 0; + return s; +} diff --git a/polyp/util.h b/polyp/util.h index 0299148e..2b7e6bbe 100644 --- a/polyp/util.h +++ b/polyp/util.h @@ -81,4 +81,6 @@ int pa_unlock_lockfile(int fd); FILE *pa_open_config_file(const char *env, const char *global, const char *local, char **result); +char *pa_hexstr(const uint8_t* d, size_t dlength, char *s, size_t slength); + #endif -- cgit