summaryrefslogtreecommitdiff
path: root/src/libskabus
diff options
context:
space:
mode:
authorLaurent Bercot <ska-skaware@skarnet.org>2020-01-10 10:35:55 +0000
committerLaurent Bercot <ska-skaware@skarnet.org>2020-01-10 10:35:55 +0000
commit9dafc75bb51c0f350330277a2e96b04f5a1c73b3 (patch)
treed00d225400b981648d362e4c3bb56b46c0608b7c /src/libskabus
parent4a14a6b86a4a3c5ab8bc36e4c417a6783dfab463 (diff)
downloadskabus-9dafc75bb51c0f350330277a2e96b04f5a1c73b3.tar.xz
Add pub library and daemon
Diffstat (limited to 'src/libskabus')
-rw-r--r--src/libskabus/deps-lib/skabus23
-rw-r--r--src/libskabus/skabus-pub-internal.h12
-rw-r--r--src/libskabus/skabus_pub_end.c25
-rw-r--r--src/libskabus/skabus_pub_list.c17
-rw-r--r--src/libskabus/skabus_pub_list_async.c45
-rw-r--r--src/libskabus/skabus_pub_message_get.c32
-rw-r--r--src/libskabus/skabus_pub_message_getnfds.c11
-rw-r--r--src/libskabus/skabus_pub_register.c15
-rw-r--r--src/libskabus/skabus_pub_register_async.c30
-rw-r--r--src/libskabus/skabus_pub_send.c15
-rw-r--r--src/libskabus/skabus_pub_send_async.c16
-rw-r--r--src/libskabus/skabus_pub_send_cb.c25
-rw-r--r--src/libskabus/skabus_pub_sendpm.c15
-rw-r--r--src/libskabus/skabus_pub_sendpm_async.c27
-rw-r--r--src/libskabus/skabus_pub_sendv.c16
-rw-r--r--src/libskabus/skabus_pub_sendv_async.c18
-rw-r--r--src/libskabus/skabus_pub_sendvpm.c15
-rw-r--r--src/libskabus/skabus_pub_sendvpm_async.c25
-rw-r--r--src/libskabus/skabus_pub_start.c20
-rw-r--r--src/libskabus/skabus_pub_start_async.c19
-rw-r--r--src/libskabus/skabus_pub_subunsub.c15
-rw-r--r--src/libskabus/skabus_pub_subunsub_async.c22
-rw-r--r--src/libskabus/skabus_pub_update.c58
23 files changed, 515 insertions, 1 deletions
diff --git a/src/libskabus/deps-lib/skabus b/src/libskabus/deps-lib/skabus
index 21582c7..a7a8369 100644
--- a/src/libskabus/deps-lib/skabus
+++ b/src/libskabus/deps-lib/skabus
@@ -1,3 +1,24 @@
+skabus_pub_end.o
+skabus_pub_list.o
+skabus_pub_list_async.o
+skabus_pub_message_get.o
+skabus_pub_message_getnfds.o
+skabus_pub_register.o
+skabus_pub_register_async.o
+skabus_pub_send.o
+skabus_pub_send_async.o
+skabus_pub_send_cb.o
+skabus_pub_sendpm.o
+skabus_pub_sendpm_async.o
+skabus_pub_sendv.o
+skabus_pub_sendv_async.o
+skabus_pub_sendvpm.o
+skabus_pub_sendvpm_async.o
+skabus_pub_start.o
+skabus_pub_start_async.o
+skabus_pub_subunsub.o
+skabus_pub_subunsub_async.o
+skabus_pub_update.o
skabus_rpc_cancel.o
skabus_rpc_cancel_async.o
skabus_rpc_end.o
@@ -17,8 +38,8 @@ skabus_rpc_r_notimpl.o
skabus_rpc_rcancel_ignore.o
skabus_rpc_release.o
skabus_rpc_reply.o
-skabus_rpc_replyv.o
skabus_rpc_reply_async.o
+skabus_rpc_replyv.o
skabus_rpc_replyv_async.o
skabus_rpc_rinfo_pack.o
skabus_rpc_rinfo_unpack.o
diff --git a/src/libskabus/skabus-pub-internal.h b/src/libskabus/skabus-pub-internal.h
new file mode 100644
index 0000000..efe8bb9
--- /dev/null
+++ b/src/libskabus/skabus-pub-internal.h
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+#ifndef SKABUS_PUB_INTERNAL_H
+#define SKABUS_PUB_INTERNAL_H
+
+#include <skalibs/unixmessage.h>
+
+#define SKABUS_HEAD_MAX 64
+
+extern unixmessage_handler_func_t skabus_pub_send_cb ;
+
+#endif
diff --git a/src/libskabus/skabus_pub_end.c b/src/libskabus/skabus_pub_end.c
new file mode 100644
index 0000000..579e83e
--- /dev/null
+++ b/src/libskabus/skabus_pub_end.c
@@ -0,0 +1,25 @@
+/* ISC license. */
+
+#include <skalibs/alloc.h>
+#include <skalibs/djbunix.h>
+#include <skalibs/genalloc.h>
+#include <skalibs/skaclient.h>
+
+#include <skabus/pub.h>
+
+static void skabus_pub_cltinfo_free (skabus_pub_cltinfo_t *p)
+{
+ fd_close(p->fd) ;
+ if (p->nfds)
+ {
+ for (size_t i = 0 ; i < p->nfds ; i++) fd_close(p->fds[i]) ;
+ alloc_free(p->fds) ;
+ }
+}
+
+void skabus_pub_end (skabus_pub_t *a)
+{
+ skaclient_end(&a->connection) ;
+ genalloc_deepfree(skabus_pub_cltinfo_t, &a->info, &skabus_pub_cltinfo_free) ;
+ a->head = 0 ;
+}
diff --git a/src/libskabus/skabus_pub_list.c b/src/libskabus/skabus_pub_list.c
new file mode 100644
index 0000000..4b8ceeb
--- /dev/null
+++ b/src/libskabus/skabus_pub_list.c
@@ -0,0 +1,17 @@
+/* ISC license. */
+
+#include <errno.h>
+
+#include <skalibs/skaclient.h>
+
+#include <skabus/pub.h>
+
+int skabus_pub_list (skabus_pub_t *a, stralloc *sa, diuint32 *n, tain_t const *deadline, tain_t *stamp)
+{
+ skabus_pub_list_result_t r ;
+ if (!skabus_pub_list_async(a, sa, &r)) return 0 ;
+ if (!skaclient_syncify(&a->connection, deadline, stamp)) return 0 ;
+ if (r.err) return (errno = r.err, 0) ;
+ *n = r.n ;
+ return 1 ;
+}
diff --git a/src/libskabus/skabus_pub_list_async.c b/src/libskabus/skabus_pub_list_async.c
new file mode 100644
index 0000000..48797b5
--- /dev/null
+++ b/src/libskabus/skabus_pub_list_async.c
@@ -0,0 +1,45 @@
+/* ISC license. */
+
+#include <stdint.h>
+#include <errno.h>
+
+#include <skalibs/posixishard.h>
+#include <skalibs/uint32.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/unixmessage.h>
+#include <skalibs/skaclient.h>
+
+#include <skabus/pub.h>
+
+static int skabus_pub_list_cb (unixmessage_t const *m, void *p)
+{
+ skabus_pub_list_result_t *r = p ;
+ uint32_t n ;
+ size_t w = 9, len = m->len - 9 ;
+ if (m->len < 9 || m->nfds) goto errproto ;
+ r->err = m->s[0] ;
+ if (r->err) return 1 ;
+ uint32_unpack_big(m->s + 1, &n) ;
+ if (n > 0x7fffffffu || m->len < 9 + (n<<1)) goto errproto ;
+ if (!stralloc_readyplus(r->sa, m->len - 9 - n)) goto errproto ;
+ r->n.left = n ;
+ uint32_unpack_big(m->s + 5, &n) ; r->n.right = n ;
+ for (uint32_t i = 0 ; i < r->n.left ; i++)
+ {
+ size_t thislen ;
+ if (len < 2) goto errproto ;
+ thislen = m->s[w++] + 1 ; len-- ;
+ if ((thislen > len) || m->s[w + thislen]) goto errproto ;
+ stralloc_catb(r->sa, m->s + w, thislen) ;
+ w += thislen ; len -= thislen ;
+ }
+ return 1 ;
+ errproto:
+ return (errno = EPROTO, 0) ;
+}
+
+int skabus_pub_list_async (skabus_pub_t *a, stralloc *sa, skabus_pub_list_result_t *result)
+{
+ result->sa = sa ;
+ return skaclient_put(&a->connection, "L", 1, &skabus_pub_list_cb, result) ;
+}
diff --git a/src/libskabus/skabus_pub_message_get.c b/src/libskabus/skabus_pub_message_get.c
new file mode 100644
index 0000000..aabefaa
--- /dev/null
+++ b/src/libskabus/skabus_pub_message_get.c
@@ -0,0 +1,32 @@
+/* ISC license. */
+
+#include <string.h>
+
+#include <skalibs/alloc.h>
+#include <skalibs/genalloc.h>
+
+#include <skabus/pub.h>
+#include "skabus-pub-internal.h"
+
+size_t skabus_pub_message_get (skabus_pub_t *a, skabus_pub_msginfo_t *info, int *fd, int *fds)
+{
+ size_t n = genalloc_len(skabus_pub_cltinfo_t, &a->info) ;
+ skabus_pub_cltinfo_t *p = genalloc_s(skabus_pub_cltinfo_t, &a->info) + a->head ;
+ if (!n) return 0 ;
+ *info = p->msginfo ;
+ *fd = p->fd ;
+ if (p->nfds)
+ {
+ for (size_t i = 0 ; i < p->nfds ; i++) fds[i] = p->fds[i] ;
+ alloc_free(p->fds) ;
+ }
+
+ if (++a->head == n || a->head > SKABUS_HEAD_MAX)
+ {
+ n -= a->head ;
+ memmove(a->info.s, a->info.s + a->head * sizeof(skabus_pub_cltinfo_t), n * sizeof(skabus_pub_cltinfo_t)) ;
+ genalloc_setlen(skabus_pub_cltinfo_t, &a->info, n) ;
+ a->head = 0 ;
+ }
+ return 1 + n - a->head ;
+}
diff --git a/src/libskabus/skabus_pub_message_getnfds.c b/src/libskabus/skabus_pub_message_getnfds.c
new file mode 100644
index 0000000..828a42d
--- /dev/null
+++ b/src/libskabus/skabus_pub_message_getnfds.c
@@ -0,0 +1,11 @@
+/* ISC license. */
+
+#include <skalibs/genalloc.h>
+
+#include <skabus/pub.h>
+
+int skabus_pub_message_getnfds (skabus_pub_t const *a)
+{
+ return genalloc_len(skabus_pub_cltinfo_t, &a->info) <= a->head ? -1 :
+ (int)genalloc_s(skabus_pub_cltinfo_t, &a->info)[a->head].nfds ;
+}
diff --git a/src/libskabus/skabus_pub_register.c b/src/libskabus/skabus_pub_register.c
new file mode 100644
index 0000000..30a08a3
--- /dev/null
+++ b/src/libskabus/skabus_pub_register.c
@@ -0,0 +1,15 @@
+/* ISC license. */
+
+#include <errno.h>
+
+#include <skalibs/skaclient.h>
+
+#include <skabus/pub.h>
+
+int skabus_pub_register (skabus_pub_t *a, char const *id, char const *sre, char const *wre, tain_t const *deadline, tain_t *stamp)
+{
+ unsigned char r ;
+ if (!skabus_pub_register_async(a, id, sre, wre, &r)) return 0 ;
+ if (!skaclient_syncify(&a->connection, deadline, stamp)) return 0 ;
+ return r ? (errno = r, 0) : 1 ;
+}
diff --git a/src/libskabus/skabus_pub_register_async.c b/src/libskabus/skabus_pub_register_async.c
new file mode 100644
index 0000000..2736bcc
--- /dev/null
+++ b/src/libskabus/skabus_pub_register_async.c
@@ -0,0 +1,30 @@
+/* ISC license. */
+
+#include <string.h>
+#include <errno.h>
+#include <sys/uio.h>
+
+#include <skalibs/uint32.h>
+#include <skalibs/skaclient.h>
+
+#include <skabus/pub.h>
+
+int skabus_pub_register_async (skabus_pub_t *a, char const *id, char const *sre, char const *wre, unsigned char *err)
+{
+ size_t idlen = strlen(id) ;
+ size_t srelen = strlen(sre) ;
+ size_t wrelen = strlen(wre) ;
+ char pack[10] = "R" ;
+ struct iovec v[4] =
+ {
+ { .iov_base = pack, .iov_len = 10 },
+ { .iov_base = (char *)id, .iov_len = idlen+1 },
+ { .iov_base = (char *)sre, .iov_len = srelen+1 },
+ { .iov_base = (char *)wre, .iov_len = wrelen+1 }
+ } ;
+ if (idlen > SKABUS_PUB_IDSTR_SIZE) return (errno = ERANGE, 0) ;
+ pack[1] = (unsigned char)idlen ;
+ uint32_pack_big(pack+2, srelen) ;
+ uint32_pack_big(pack+6, wrelen) ;
+ return skaclient_putv(&a->connection, v, 4, &skaclient_default_cb, err) ;
+}
diff --git a/src/libskabus/skabus_pub_send.c b/src/libskabus/skabus_pub_send.c
new file mode 100644
index 0000000..f41ede3
--- /dev/null
+++ b/src/libskabus/skabus_pub_send.c
@@ -0,0 +1,15 @@
+/* ISC license. */
+
+#include <errno.h>
+
+#include <skalibs/skaclient.h>
+
+#include <skabus/pub.h>
+
+uint64_t skabus_pub_send_withfds (skabus_pub_t *a, char const *s, size_t len, int const *fds, unsigned int nfds, unsigned char const *bits, tain_t const *deadline, tain_t *stamp)
+{
+ skabus_pub_send_result_t r ;
+ if (!skabus_pub_send_withfds_async(a, s, len, fds, nfds, bits, &r)) return 0 ;
+ if (!skaclient_syncify(&a->connection, deadline, stamp)) return 0 ;
+ return r.err ? (errno = r.err, 0) : r.u ;
+}
diff --git a/src/libskabus/skabus_pub_send_async.c b/src/libskabus/skabus_pub_send_async.c
new file mode 100644
index 0000000..1a2bb58
--- /dev/null
+++ b/src/libskabus/skabus_pub_send_async.c
@@ -0,0 +1,16 @@
+/* ISC license. */
+
+#include <sys/uio.h>
+
+#include <skalibs/unixmessage.h>
+#include <skalibs/skaclient.h>
+
+#include <skabus/pub.h>
+#include "skabus-pub-internal.h"
+
+int skabus_pub_send_withfds_async (skabus_pub_t *a, char const *s, size_t len, int const *fds, unsigned int nfds, unsigned char const *bits, skabus_pub_send_result_t *result)
+{
+ struct iovec v[2] = { { .iov_base = "!", .iov_len = 1 }, { .iov_base = (char *)s, .iov_len = len } } ;
+ unixmessage_v_t m = { .v = v, .vlen = 2, .fds = (int *)fds, .nfds = nfds } ;
+ return skaclient_putmsgv_and_close(&a->connection, &m, bits, &skabus_pub_send_cb, result) ;
+}
diff --git a/src/libskabus/skabus_pub_send_cb.c b/src/libskabus/skabus_pub_send_cb.c
new file mode 100644
index 0000000..e95ab6c
--- /dev/null
+++ b/src/libskabus/skabus_pub_send_cb.c
@@ -0,0 +1,25 @@
+/* ISC license. */
+
+#include <errno.h>
+
+#include <skalibs/posixishard.h>
+#include <skalibs/uint64.h>
+#include <skalibs/unixmessage.h>
+
+#include <skabus/pub.h>
+
+int skabus_pub_send_cb (unixmessage_t const *m, void *p)
+{
+ skabus_pub_send_result_t *r = p ;
+ if (!m->len || m->nfds) return (errno = EPROTO, 0) ;
+ if (m->s[0])
+ {
+ r->u = 0 ;
+ r->err = m->s[0] ;
+ return 1 ;
+ }
+ if (m->len != 9) return (errno = EPROTO, 0) ;
+ uint64_unpack_big(m->s + 1, &r->u) ;
+ r->err = 0 ;
+ return 1 ;
+}
diff --git a/src/libskabus/skabus_pub_sendpm.c b/src/libskabus/skabus_pub_sendpm.c
new file mode 100644
index 0000000..073633a
--- /dev/null
+++ b/src/libskabus/skabus_pub_sendpm.c
@@ -0,0 +1,15 @@
+/* ISC license. */
+
+#include <errno.h>
+
+#include <skalibs/skaclient.h>
+
+#include <skabus/pub.h>
+
+uint64_t skabus_pub_sendpm_withfds (skabus_pub_t *a, char const *id, char const *s, size_t len, int const *fds, unsigned int nfds, unsigned char const *bits, tain_t const *deadline, tain_t *stamp)
+{
+ skabus_pub_send_result_t r ;
+ if (!skabus_pub_sendpm_withfds_async(a, id, s, len, fds, nfds, bits, &r)) return 0 ;
+ if (!skaclient_syncify(&a->connection, deadline, stamp)) return 0 ;
+ return r.err ? (errno = r.err, 0) : r.u ;
+}
diff --git a/src/libskabus/skabus_pub_sendpm_async.c b/src/libskabus/skabus_pub_sendpm_async.c
new file mode 100644
index 0000000..d43b01f
--- /dev/null
+++ b/src/libskabus/skabus_pub_sendpm_async.c
@@ -0,0 +1,27 @@
+/* ISC license. */
+
+#include <string.h>
+#include <sys/uio.h>
+#include <errno.h>
+
+#include <skalibs/unixmessage.h>
+#include <skalibs/skaclient.h>
+
+#include <skabus/pub.h>
+#include "skabus-pub-internal.h"
+
+int skabus_pub_sendpm_withfds_async (skabus_pub_t *a, char const *idstr, char const *s, size_t len, int const *fds, unsigned int nfds, unsigned char const *bits, skabus_pub_send_result_t *result)
+{
+ size_t idlen = strlen(idstr) ;
+ char tmp[2] = "+" ;
+ struct iovec v[3] =
+ {
+ { .iov_base = tmp, .iov_len = 2 },
+ { .iov_base = (char *)idstr, .iov_len = idlen+1 },
+ { .iov_base = (char *)s, .iov_len = len }
+ } ;
+ unixmessage_v_t m = { .v = v, .vlen = 3, .fds = (int *)fds, .nfds = nfds } ;
+ if (idlen > SKABUS_PUB_IDSTR_SIZE) return (errno = ERANGE, 0) ;
+ tmp[1] = (unsigned char)idlen ;
+ return skaclient_putmsgv_and_close(&a->connection, &m, bits, &skabus_pub_send_cb, result) ;
+}
diff --git a/src/libskabus/skabus_pub_sendv.c b/src/libskabus/skabus_pub_sendv.c
new file mode 100644
index 0000000..ff1c743
--- /dev/null
+++ b/src/libskabus/skabus_pub_sendv.c
@@ -0,0 +1,16 @@
+/* ISC license. */
+
+#include <errno.h>
+
+#include <skalibs/uint64.h>
+#include <skalibs/skaclient.h>
+
+#include <skabus/pub.h>
+
+uint64_t skabus_pub_sendv_withfds (skabus_pub_t *a, struct iovec const *v, unsigned int vlen, int const *fds, unsigned int nfds, unsigned char const *bits, tain_t const *deadline, tain_t *stamp)
+{
+ skabus_pub_send_result_t r ;
+ if (!skabus_pub_sendv_withfds_async(a, v, vlen, fds, nfds, bits, &r)) return 0 ;
+ if (!skaclient_syncify(&a->connection, deadline, stamp)) return 0 ;
+ return r.err ? (errno = r.err, 0) : r.u ;
+}
diff --git a/src/libskabus/skabus_pub_sendv_async.c b/src/libskabus/skabus_pub_sendv_async.c
new file mode 100644
index 0000000..54ce94e
--- /dev/null
+++ b/src/libskabus/skabus_pub_sendv_async.c
@@ -0,0 +1,18 @@
+/* ISC license. */
+
+#include <sys/uio.h>
+
+#include <skalibs/unixmessage.h>
+#include <skalibs/skaclient.h>
+
+#include <skabus/pub.h>
+#include "skabus-pub-internal.h"
+
+int skabus_pub_sendv_withfds_async (skabus_pub_t *a, struct iovec const *v, unsigned int vlen, int const *fds, unsigned int nfds, unsigned char const *bits, skabus_pub_send_result_t *result)
+{
+ struct iovec vv[vlen+1] ;
+ unixmessage_v_t m = { .v = vv, .vlen = vlen+1, .fds = (int *)fds, .nfds = nfds } ;
+ vv[0].iov_base = "!" ; vv[0].iov_len = 1 ;
+ for (unsigned int i = 0 ; i < vlen ; i++) vv[1+i] = v[i] ;
+ return skaclient_putmsgv_and_close(&a->connection, &m, bits, &skabus_pub_send_cb, result) ;
+}
diff --git a/src/libskabus/skabus_pub_sendvpm.c b/src/libskabus/skabus_pub_sendvpm.c
new file mode 100644
index 0000000..a898bbc
--- /dev/null
+++ b/src/libskabus/skabus_pub_sendvpm.c
@@ -0,0 +1,15 @@
+/* ISC license. */
+
+#include <errno.h>
+
+#include <skalibs/skaclient.h>
+
+#include <skabus/pub.h>
+
+uint64_t skabus_pub_sendvpm_withfds (skabus_pub_t *a, char const *idstr, struct iovec const *v, unsigned int vlen, int const *fds, unsigned int nfds, unsigned char const *bits, tain_t const *deadline, tain_t *stamp)
+{
+ skabus_pub_send_result_t r ;
+ if (!skabus_pub_sendvpm_withfds_async(a, idstr, v, vlen, fds, nfds, bits, &r)) return 0 ;
+ if (!skaclient_syncify(&a->connection, deadline, stamp)) return 0 ;
+ return r.err ? (errno = r.err, 0) : r.u ;
+}
diff --git a/src/libskabus/skabus_pub_sendvpm_async.c b/src/libskabus/skabus_pub_sendvpm_async.c
new file mode 100644
index 0000000..b1bab4d
--- /dev/null
+++ b/src/libskabus/skabus_pub_sendvpm_async.c
@@ -0,0 +1,25 @@
+/* ISC license. */
+
+#include <string.h>
+#include <sys/uio.h>
+#include <errno.h>
+
+#include <skalibs/unixmessage.h>
+#include <skalibs/skaclient.h>
+
+#include <skabus/pub.h>
+#include "skabus-pub-internal.h"
+
+int skabus_pub_sendvpm_withfds_async (skabus_pub_t *a, char const *idstr, struct iovec const *v, unsigned int vlen, int const *fds, unsigned int nfds, unsigned char const *bits, skabus_pub_send_result_t *result)
+{
+ size_t idlen = strlen(idstr) ;
+ char tmp[2] = "+" ;
+ struct iovec vv[vlen + 2] ;
+ unixmessage_v_t m = { .v = vv, .vlen = vlen + 2, .fds = (int *)fds, .nfds = nfds } ;
+ if (idlen > SKABUS_PUB_IDSTR_SIZE) return (errno = ERANGE, 0) ;
+ tmp[1] = (unsigned char)idlen ;
+ vv[0].iov_base = tmp ; vv[0].iov_len = 2 ;
+ vv[1].iov_base = (char *)idstr ; vv[1].iov_len = idlen+1 ;
+ for (unsigned int i = 0 ; i < vlen ; i++) vv[2+i] = v[i] ;
+ return skaclient_putmsgv_and_close(&a->connection, &m, bits, &skabus_pub_send_cb, result) ;
+}
diff --git a/src/libskabus/skabus_pub_start.c b/src/libskabus/skabus_pub_start.c
new file mode 100644
index 0000000..d72b0f7
--- /dev/null
+++ b/src/libskabus/skabus_pub_start.c
@@ -0,0 +1,20 @@
+/* ISC license. */
+
+#include <skalibs/skaclient.h>
+
+#include <skabus/pub.h>
+
+int skabus_pub_start (skabus_pub_t *a, char const *path, tain_t const *deadline, tain_t *stamp)
+{
+ return skaclient_start_b(
+ &a->connection,
+ &a->buffers,
+ path,
+ SKACLIENT_OPTION_ASYNC_ACCEPT_FDS,
+ SKABUS_PUB_BANNER1,
+ SKABUS_PUB_BANNER1_LEN,
+ SKABUS_PUB_BANNER2,
+ SKABUS_PUB_BANNER2_LEN,
+ deadline,
+ stamp) ;
+}
diff --git a/src/libskabus/skabus_pub_start_async.c b/src/libskabus/skabus_pub_start_async.c
new file mode 100644
index 0000000..3a82f41
--- /dev/null
+++ b/src/libskabus/skabus_pub_start_async.c
@@ -0,0 +1,19 @@
+/* ISC license. */
+
+#include <skalibs/skaclient.h>
+
+#include <skabus/pub.h>
+
+int skabus_pub_start_async (skabus_pub_t *a, char const *path, skabus_pub_start_result_t *data)
+{
+ return skaclient_start_async_b(
+ &a->connection,
+ &a->buffers,
+ path,
+ SKACLIENT_OPTION_ASYNC_ACCEPT_FDS,
+ SKABUS_PUB_BANNER1,
+ SKABUS_PUB_BANNER1_LEN,
+ SKABUS_PUB_BANNER2,
+ SKABUS_PUB_BANNER2_LEN,
+ &data->skaclient_cbdata) ;
+}
diff --git a/src/libskabus/skabus_pub_subunsub.c b/src/libskabus/skabus_pub_subunsub.c
new file mode 100644
index 0000000..29e61f1
--- /dev/null
+++ b/src/libskabus/skabus_pub_subunsub.c
@@ -0,0 +1,15 @@
+/* ISC license. */
+
+#include <errno.h>
+
+#include <skalibs/skaclient.h>
+
+#include <skabus/pub.h>
+
+int skabus_pub_subunsub (skabus_pub_t *a, char what, char const *id, tain_t const *deadline, tain_t *stamp)
+{
+ unsigned char r ;
+ if (!skabus_pub_subunsub_async(a, what, id, &r)) return 0 ;
+ if (!skaclient_syncify(&a->connection, deadline, stamp)) return 0 ;
+ return r ? (errno = r, 0) : 1 ;
+}
diff --git a/src/libskabus/skabus_pub_subunsub_async.c b/src/libskabus/skabus_pub_subunsub_async.c
new file mode 100644
index 0000000..d41ed98
--- /dev/null
+++ b/src/libskabus/skabus_pub_subunsub_async.c
@@ -0,0 +1,22 @@
+/* ISC license. */
+
+#include <string.h>
+#include <sys/uio.h>
+#include <errno.h>
+
+#include <skalibs/skaclient.h>
+
+#include <skabus/pub.h>
+
+int skabus_pub_subunsub_async (skabus_pub_t *a, char what, char const *id, unsigned char *err)
+{
+ size_t idlen = strlen(id) ;
+ char pack[2] = { what, (unsigned char)idlen } ;
+ struct iovec v[2] =
+ {
+ { .iov_base = pack, .iov_len = 2 },
+ { .iov_base = (char *)id, .iov_len = idlen+1 }
+ } ;
+ if (idlen > SKABUS_PUB_IDSTR_SIZE) return (errno = ERANGE, 0) ;
+ return skaclient_putv(&a->connection, v, 2, &skaclient_default_cb, err) ;
+}
diff --git a/src/libskabus/skabus_pub_update.c b/src/libskabus/skabus_pub_update.c
new file mode 100644
index 0000000..46e699c
--- /dev/null
+++ b/src/libskabus/skabus_pub_update.c
@@ -0,0 +1,58 @@
+/* ISC license. */
+
+#include <string.h>
+#include <stdint.h>
+#include <errno.h>
+
+#include <skalibs/posixishard.h>
+#include <skalibs/uint64.h>
+#include <skalibs/tai.h>
+#include <skalibs/alloc.h>
+#include <skalibs/genalloc.h>
+#include <skalibs/unixmessage.h>
+#include <skalibs/skaclient.h>
+
+#include <skabus/pub.h>
+
+static int handler (unixmessage_t const *m, void *x)
+{
+ skabus_pub_t *a = (skabus_pub_t *)x ;
+ size_t n = genalloc_len(skabus_pub_cltinfo_t, &a->info) ;
+ char const *s = m->s ;
+ size_t len = m->len ;
+ skabus_pub_cltinfo_t *p ;
+ uint8_t idlen ;
+ if (len < 11 + TAIN_PACK || !m->nfds) goto errproto ;
+ if (!genalloc_readyplus(skabus_pub_cltinfo_t, &a->info, 1)) goto err ;
+ p = genalloc_s(skabus_pub_cltinfo_t, &a->info) + n ;
+ p->fd = m->fds[0] ;
+ p->nfds = m->nfds - 1 ;
+ if (p->nfds > 1)
+ {
+ p->fds = alloc(p->nfds * sizeof(int)) ;
+ if (!p->fds) goto err ;
+ for (size_t i = 0 ; i < p->nfds ; i++) p->fds[i] = m->fds[1 + i] ;
+ }
+ else p->fds = 0 ;
+ uint64_unpack_big(s, &p->msginfo.serial) ; s += 8 ; len -= 8 ;
+ tain_unpack(s, &p->msginfo.timestamp) ; s += TAIN_PACK ; len -= TAIN_PACK ;
+ p->msginfo.flags = *s++ ; len-- ;
+ idlen = *s++ ; len-- ;
+ if (len != (size_t)idlen + 1 || s[idlen] || idlen > SKABUS_PUB_IDSTR_SIZE) goto errprotof ;
+ memcpy(p->msginfo.sender, s, len) ;
+ genalloc_setlen(skabus_pub_cltinfo_t, &a->info, n+1) ;
+ return 1 ;
+
+ errprotof:
+ alloc_free(p->fds) ;
+ errproto:
+ errno = EPROTO ;
+ err:
+ unixmessage_drop(m) ;
+ return 0 ;
+}
+
+int skabus_pub_update (skabus_pub_t *a)
+{
+ return skaclient_update(&a->connection, &handler, a) ;
+}