├── src ├── misc │ ├── deps-exe │ │ ├── skabus-dyntee │ │ ├── skabus-dyntee-client │ │ └── skabus-dynteed │ ├── skabus-dyntee-client.c │ ├── skabus-dyntee.c │ └── skabus-dynteed.c ├── pub │ ├── deps-exe │ │ ├── skabus-pub-daemon │ │ └── skabus-pubd │ └── skabus-pub-daemon.c ├── rpc │ ├── deps-exe │ │ ├── skabus-rpc-client │ │ ├── skabus-rpc-daemon │ │ ├── skabus-rpcc │ │ ├── skabus-rpccctl │ │ └── skabus-rpcd │ ├── skabus-rpcc.h │ ├── PROTOCOL │ ├── skabus-rpccctl.h │ ├── skabus_rpcd_interface.c │ ├── skabus-rpc-client.c │ ├── skabus_rpccctl.c │ ├── skabus-rpcd.h │ ├── skabus-rpccctl.c │ ├── skabus-rpc-daemon.c │ ├── skabus_rpcd_client.c │ └── skabus_rpcd_query.c ├── libskabus │ ├── skabus_rpc_zero.c │ ├── skabus_rpc_qinfo_zero.c │ ├── skabus_rpc_rinfo_zero.c │ ├── skabus_rpc_interface_zero.c │ ├── skabus_rpc_rcancel_ignore.c │ ├── skabus-pub-internal.h │ ├── skabus_rpc_r_notimpl.c │ ├── skabus_pub_message_getnfds.c │ ├── skabus_rpc_qlist.c │ ├── skabus_rpc_send_async.c │ ├── skabus_rpc_send.c │ ├── skabus_rpc_sendpm_async.c │ ├── skabus_rpc_sendpm.c │ ├── skabus_rpc_sendv_async.c │ ├── skabus_rpc_sendv.c │ ├── skabus_rpc_sendvpm_async.c │ ├── skabus_pub_subunsub.c │ ├── skabus_rpc_sendvpm.c │ ├── skabus_rpc_reply.c │ ├── skabus_pub_register.c │ ├── skabus_rpc_cancel.c │ ├── skabus_rpc_replyv.c │ ├── skabus_pub_list.c │ ├── skabus_pub_start.c │ ├── skabus_rpc_start.c │ ├── skabus_rpc_qlist_ack.c │ ├── skabus_pub_start_async.c │ ├── skabus_rpc_start_async.c │ ├── skabus_rpc_end.c │ ├── skabus_rpc_interface_unregister.c │ ├── skabus_rpc_interface_register_cb.c │ ├── skabus_rpc_idstr.c │ ├── skabus_pub_send.c │ ├── skabus_pub_sendpm.c │ ├── skabus_pub_send_cb.c │ ├── skabus_pub_sendv.c │ ├── skabus_pub_sendvpm.c │ ├── skabus_rpc_rinfo_pack.c │ ├── skabus_rpc_rinfo_unpack.c │ ├── skabus_pub_end.c │ ├── skabus_rpc_interface_register.c │ ├── skabus_pub_send_async.c │ ├── skabus_pub_subunsub_async.c │ ├── skabus_rpc_sendvq.c │ ├── skabus_rpc_sendq.c │ ├── skabus_rpc_get.c │ ├── skabus_rpc_reply_async.c │ ├── skabus_pub_sendv_async.c │ ├── skabus_rpc_replyv_async.c │ ├── skabus_rpc_cancel_async.c │ ├── skabus_rpc_release.c │ ├── skabus_pub_message_get.c │ ├── skabus_pub_sendpm_async.c │ ├── skabus_pub_register_async.c │ ├── skabus_pub_sendvpm_async.c │ ├── skabus_rpc_interface_unregister_async.c │ ├── skabus-rpc-internal.h │ ├── skabus_rpc_idstr_async.c │ ├── skabus_pub_list_async.c │ ├── skabus_rpc_interface_register_async.c │ ├── skabus_rpc_sendq_async.c │ ├── skabus_rpc_sendvq_async.c │ ├── skabus_rpc_send_cb.c │ ├── deps-lib │ │ └── skabus │ ├── skabus_pub_update.c │ └── skabus_rpc_update.c └── include │ └── skabus │ ├── skabus.h │ └── pub.h ├── package ├── configure-snippets │ ├── configure_case_lines │ ├── configure_expand_dirs │ ├── configure_init_vars │ ├── configure_extra_checks │ ├── configure_generate_configh │ ├── configure_generate_make │ ├── configure_help_install │ ├── configure_help_options │ ├── configure_help_dependencies │ └── configure_slashpackage_other ├── info ├── deps-build ├── modes └── targets.mak ├── AUTHORS ├── NEWS ├── .gitignore ├── CONTRIBUTING ├── README.solaris ├── patch-for-solaris ├── tools ├── run-test.sh ├── gen-configure.el ├── install.sh ├── gen-dotpc.sh └── gen-deps.sh ├── README ├── COPYING ├── doc ├── upgrade.html ├── skabus-dyntee-client.html ├── index.html ├── libskabus │ └── index.html ├── skabus-dyntee.html ├── skabus-dynteed.html ├── skabus-rpc-daemon.html └── skabus-rpcd.html ├── DCO ├── INSTALL └── Makefile /src/misc/deps-exe/skabus-dyntee: -------------------------------------------------------------------------------- 1 | -lskarnet 2 | -------------------------------------------------------------------------------- /src/pub/deps-exe/skabus-pub-daemon: -------------------------------------------------------------------------------- 1 | -lskarnet 2 | -------------------------------------------------------------------------------- /src/rpc/deps-exe/skabus-rpc-client: -------------------------------------------------------------------------------- 1 | -lskarnet 2 | -------------------------------------------------------------------------------- /src/rpc/deps-exe/skabus-rpc-daemon: -------------------------------------------------------------------------------- 1 | -lskarnet 2 | -------------------------------------------------------------------------------- /package/configure-snippets/configure_case_lines: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /package/configure-snippets/configure_expand_dirs: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /package/configure-snippets/configure_init_vars: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /package/configure-snippets/configure_extra_checks: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /package/configure-snippets/configure_generate_configh: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /package/configure-snippets/configure_generate_make: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /package/configure-snippets/configure_help_install: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /package/configure-snippets/configure_help_options: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /package/configure-snippets/configure_help_dependencies: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /package/configure-snippets/configure_slashpackage_other: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/misc/deps-exe/skabus-dyntee-client: -------------------------------------------------------------------------------- 1 | -lskarnet 2 | ${SOCKET_LIB} 3 | -------------------------------------------------------------------------------- /src/misc/deps-exe/skabus-dynteed: -------------------------------------------------------------------------------- 1 | -ls6 2 | -lskarnet 3 | ${SOCKET_LIB} 4 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Main author: 2 | Laurent Bercot 3 | 4 | -------------------------------------------------------------------------------- /src/pub/deps-exe/skabus-pubd: -------------------------------------------------------------------------------- 1 | -ls6 2 | -lskarnet 3 | ${SOCKET_LIB} 4 | ${TAINNOW_LIB} 5 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- 1 | Changelog for skabus 2 | 3 | In 0.0.1.0 4 | ---------- 5 | 6 | - Initial release. 7 | -------------------------------------------------------------------------------- /src/rpc/deps-exe/skabus-rpcc: -------------------------------------------------------------------------------- 1 | ${LIBSKABUS} 2 | -lskarnet 3 | ${SOCKET_LIB} 4 | ${SYSCLOCK_LIB} 5 | -------------------------------------------------------------------------------- /package/info: -------------------------------------------------------------------------------- 1 | package=skabus 2 | version=0.0.1.0 3 | category=admin 4 | package_macro_name=SKABUS 5 | -------------------------------------------------------------------------------- /src/rpc/deps-exe/skabus-rpccctl: -------------------------------------------------------------------------------- 1 | skabus_rpccctl.o 2 | -lskarnet 3 | ${SOCKET_LIB} 4 | ${SYSCLOCK_LIB} 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /*.pc 2 | *.o 3 | *.lo 4 | /*.a.xyzzy 5 | /*.so.xyzzy 6 | /config.mak 7 | /src/include/skabus/config.h 8 | /skabus-* 9 | -------------------------------------------------------------------------------- /src/libskabus/skabus_rpc_zero.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | 5 | skabus_rpc_t const skabus_rpc_zero = SKABUS_RPC_ZERO ; 6 | -------------------------------------------------------------------------------- /src/libskabus/skabus_rpc_qinfo_zero.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | 5 | skabus_rpc_qinfo_t const skabus_rpc_qinfo_zero = SKABUS_RPC_QINFO_ZERO ; 6 | -------------------------------------------------------------------------------- /src/libskabus/skabus_rpc_rinfo_zero.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | 5 | skabus_rpc_rinfo_t const skabus_rpc_rinfo_zero = SKABUS_RPC_RINFO_ZERO ; 6 | -------------------------------------------------------------------------------- /package/deps-build: -------------------------------------------------------------------------------- 1 | true true /package/prog/skalibs 2.14.4.0 libskarnet 2 | true false /package/admin/execline 2.9.7.0 libexecline 3 | true false /package/admin/s6 2.13.2.0 libs6 4 | -------------------------------------------------------------------------------- /src/rpc/deps-exe/skabus-rpcd: -------------------------------------------------------------------------------- 1 | skabus_rpcd_client.o 2 | skabus_rpcd_interface.o 3 | skabus_rpcd_query.o 4 | ${LIBSKABUS} 5 | -ls6 6 | -lskarnet 7 | ${SOCKET_LIB} 8 | ${SYSCLOCK_LIB} 9 | -------------------------------------------------------------------------------- /src/libskabus/skabus_rpc_interface_zero.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | 5 | skabus_rpc_interface_t const skabus_rpc_interface_zero = SKABUS_RPC_INTERFACE_ZERO ; 6 | -------------------------------------------------------------------------------- /package/modes: -------------------------------------------------------------------------------- 1 | skabus-dyntee 0755 2 | skabus-dynteed 0755 3 | skabus-dyntee-client 0755 4 | skabus-pub-daemon 0755 5 | skabus-pubd 0755 6 | skabus-rpc-daemon 0755 7 | skabus-rpcd 0755 8 | skabus-rpc-client 0755 9 | skabus-rpcc 0755 10 | skabus-rpccctl 0755 11 | -------------------------------------------------------------------------------- /src/libskabus/skabus_rpc_rcancel_ignore.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | 5 | int skabus_rpc_rcancel_ignore (uint64_t serial, char reason, void *data) 6 | { 7 | (void)serial ; 8 | (void)reason ; 9 | (void)data ; 10 | return 1 ; 11 | } 12 | -------------------------------------------------------------------------------- /src/include/skabus/skabus.h: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #ifndef SKABUS_H 4 | #define SKABUS_H 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | #include 11 | #include 12 | 13 | #ifdef __cplusplus 14 | } 15 | #endif 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /src/libskabus/skabus-pub-internal.h: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #ifndef SKABUS_PUB_INTERNAL_H 4 | #define SKABUS_PUB_INTERNAL_H 5 | 6 | #include 7 | 8 | #define SKABUS_HEAD_MAX 64 9 | 10 | extern unixmessage_handler_func skabus_pub_send_cb ; 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /CONTRIBUTING: -------------------------------------------------------------------------------- 1 | Please add a Signed-Off-By: line at the end of your commit, 2 | which certifies that you have the right and authority to pass 3 | it on as an open-source patch, as explicited in the Developer's 4 | Certificate of Origin available in this project's DCO file, 5 | or at https://developercertificate.org/ 6 | -------------------------------------------------------------------------------- /package/targets.mak: -------------------------------------------------------------------------------- 1 | BIN_TARGETS := \ 2 | skabus-dyntee \ 3 | skabus-dynteed \ 4 | skabus-dyntee-client \ 5 | skabus-pub-daemon \ 6 | skabus-pubd \ 7 | skabus-rpc-daemon \ 8 | skabus-rpcd \ 9 | skabus-rpc-client 10 | 11 | LIBEXEC_TARGETS := 12 | 13 | LIB_DEFS := SKABUS=skabus 14 | SKABUS_DESCRIPTION := The skabus client library. 15 | -------------------------------------------------------------------------------- /src/libskabus/skabus_rpc_r_notimpl.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | 5 | #include 6 | 7 | int skabus_rpc_r_notimpl (skabus_rpc_t *a, skabus_rpc_rinfo_t const *info, unixmessage const *m, void *data) 8 | { 9 | (void)m ; 10 | (void)data ; 11 | return skabus_rpc_reply(a, info->serial, ENOSYS, "", 0, 0, 0) ; 12 | } 13 | -------------------------------------------------------------------------------- /src/libskabus/skabus_pub_message_getnfds.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | 5 | #include 6 | 7 | int skabus_pub_message_getnfds (skabus_pub_t const *a) 8 | { 9 | return genalloc_len(skabus_pub_cltinfo_t, &a->info) <= a->head ? -1 : 10 | (int)genalloc_s(skabus_pub_cltinfo_t, &a->info)[a->head].nfds ; 11 | } 12 | -------------------------------------------------------------------------------- /src/libskabus/skabus_rpc_qlist.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | size_t skabus_rpc_qlist (skabus_rpc_t *a, uint64_t **list) 9 | { 10 | uint64_t n = genalloc_len(uint64_t, &a->qlist) ; 11 | if (n) *list = genalloc_s(uint64_t, &a->qlist) ; 12 | return n ; 13 | } 14 | -------------------------------------------------------------------------------- /src/libskabus/skabus_rpc_send_async.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | #include "skabus-rpc-internal.h" 5 | 6 | int skabus_rpc_send_withfds_async (skabus_rpc_t *a, char const *ifname, char const *s, size_t len, int const *fds, unsigned int nfds, unsigned char const *bits, tain const *limit, skabus_rpc_send_result_t *r) 7 | { 8 | return skabus_rpc_sendq_withfds_async(a, 0, 0, ifname, s, len, fds, nfds, bits, limit, r) ; 9 | } 10 | -------------------------------------------------------------------------------- /src/libskabus/skabus_rpc_send.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | #include "skabus-rpc-internal.h" 5 | 6 | uint64_t skabus_rpc_send_withfds (skabus_rpc_t *a, char const *ifname, char const *s, size_t len, int const *fds, unsigned int nfds, unsigned char const *bits, tain const *limit, tain const *deadline, tain *stamp) 7 | { 8 | return skabus_rpc_sendq_withfds(a, 0, 0, ifname, s, len, fds, nfds, bits, limit, deadline, stamp) ; 9 | } 10 | -------------------------------------------------------------------------------- /src/libskabus/skabus_rpc_sendpm_async.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | #include "skabus-rpc-internal.h" 5 | 6 | int skabus_rpc_sendpm_withfds_async (skabus_rpc_t *a, char const *cname, char const *s, size_t len, int const *fds, unsigned int nfds, unsigned char const *bits, tain const *limit, skabus_rpc_send_result_t *r) 7 | { 8 | return skabus_rpc_sendq_withfds_async(a, "\xff", 1, cname, s, len, fds, nfds, bits, limit, r) ; 9 | } 10 | -------------------------------------------------------------------------------- /src/libskabus/skabus_rpc_sendpm.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | #include "skabus-rpc-internal.h" 5 | 6 | uint64_t skabus_rpc_sendpm_withfds (skabus_rpc_t *a, char const *cname, char const *s, size_t len, int const *fds, unsigned int nfds, unsigned char const *bits, tain const *limit, tain const *deadline, tain *stamp) 7 | { 8 | return skabus_rpc_sendq_withfds(a, "\xff", 1, cname, s, len, fds, nfds, bits, limit, deadline, stamp) ; 9 | } 10 | -------------------------------------------------------------------------------- /src/libskabus/skabus_rpc_sendv_async.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | #include "skabus-rpc-internal.h" 5 | 6 | int skabus_rpc_sendv_withfds_async (skabus_rpc_t *a, char const *ifname, struct iovec const *v, unsigned int vlen, int const *fds, unsigned int nfds, unsigned char const *bits, tain const *limit, skabus_rpc_send_result_t *r) 7 | { 8 | return skabus_rpc_sendvq_withfds_async(a, 0, 0, ifname, v, vlen, fds, nfds, bits, limit, r) ; 9 | } 10 | -------------------------------------------------------------------------------- /src/libskabus/skabus_rpc_sendv.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | #include "skabus-rpc-internal.h" 5 | 6 | uint64_t skabus_rpc_sendv_withfds (skabus_rpc_t *a, char const *ifname, struct iovec const *v, unsigned int vlen, int const *fds, unsigned int nfds, unsigned char const *bits, tain const *limit, tain const *deadline, tain *stamp) 7 | { 8 | return skabus_rpc_sendvq_withfds(a, 0, 0, ifname, v, vlen, fds, nfds, bits, limit, deadline, stamp) ; 9 | } 10 | -------------------------------------------------------------------------------- /src/libskabus/skabus_rpc_sendvpm_async.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | #include "skabus-rpc-internal.h" 5 | 6 | int skabus_rpc_sendvpm_withfds_async (skabus_rpc_t *a, char const *cname, struct iovec const *v, unsigned int vlen, int const *fds, unsigned int nfds, unsigned char const *bits, tain const *limit, skabus_rpc_send_result_t *r) 7 | { 8 | return skabus_rpc_sendvq_withfds_async(a, "\xff", 1, cname, v, vlen, fds, nfds, bits, limit, r) ; 9 | } 10 | -------------------------------------------------------------------------------- /README.solaris: -------------------------------------------------------------------------------- 1 | 2 | This package assumes the existence of a POSIX shell in /bin/sh. 3 | On Solaris, /bin/sh is not POSIX. Most versions of Solaris provide 4 | a POSIX shell in /usr/xpg4/bin/sh. 5 | 6 | To compile this package on Solaris, you will need to run 7 | 8 | ./patch-for-solaris 9 | 10 | before you run ./configure. This script will change the #! invocation 11 | of the configure script and various tools so that a POSIX shell is used 12 | for the compilation process. 13 | -------------------------------------------------------------------------------- /src/libskabus/skabus_pub_subunsub.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | 9 | int skabus_pub_subunsub (skabus_pub_t *a, char what, char const *id, tain const *deadline, tain *stamp) 10 | { 11 | unsigned char r ; 12 | if (!skabus_pub_subunsub_async(a, what, id, &r)) return 0 ; 13 | if (!skaclient_syncify(&a->connection, deadline, stamp)) return 0 ; 14 | return r ? (errno = r, 0) : 1 ; 15 | } 16 | -------------------------------------------------------------------------------- /src/libskabus/skabus_rpc_sendvpm.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | #include "skabus-rpc-internal.h" 5 | 6 | uint64_t skabus_rpc_sendvpm_withfds (skabus_rpc_t *a, char const *cname, struct iovec const *v, unsigned int vlen, int const *fds, unsigned int nfds, unsigned char const *bits, tain const *limit, tain const *deadline, tain *stamp) 7 | { 8 | return skabus_rpc_sendvq_withfds(a, "\xff", 1, cname, v, vlen, fds, nfds, bits, limit, deadline, stamp) ; 9 | } 10 | -------------------------------------------------------------------------------- /src/libskabus/skabus_rpc_reply.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | 5 | #include 6 | 7 | int skabus_rpc_reply_withfds (skabus_rpc_t *a, uint64_t serial, char result, char const *s, size_t len, int const *fds, unsigned int nfds, unsigned char const *bits, tain const *deadline, tain *stamp) 8 | { 9 | return skabus_rpc_reply_withfds_async(a, serial, result, s, len, fds, nfds, bits) 10 | && skaclient_timed_aflush(&a->connection, deadline, stamp) ; 11 | } 12 | -------------------------------------------------------------------------------- /src/libskabus/skabus_pub_register.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | 9 | int skabus_pub_register (skabus_pub_t *a, char const *id, char const *sre, char const *wre, tain const *deadline, tain *stamp) 10 | { 11 | unsigned char r ; 12 | if (!skabus_pub_register_async(a, id, sre, wre, &r)) return 0 ; 13 | if (!skaclient_syncify(&a->connection, deadline, stamp)) return 0 ; 14 | return r ? (errno = r, 0) : 1 ; 15 | } 16 | -------------------------------------------------------------------------------- /src/libskabus/skabus_rpc_cancel.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | int skabus_rpc_cancel (skabus_rpc_t *a, uint64_t serial, tain const *deadline, tain *stamp) 11 | { 12 | unsigned char r ; 13 | if (!skabus_rpc_cancel_async(a, serial, &r)) return 0 ; 14 | if (!skaclient_syncify(&a->connection, deadline, stamp)) return 0 ; 15 | if (r) return (errno = r, 0) ; 16 | return 1 ; 17 | } 18 | -------------------------------------------------------------------------------- /src/libskabus/skabus_rpc_replyv.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | #include 5 | 6 | int skabus_rpc_replyv_withfds (skabus_rpc_t *a, uint64_t serial, char result, struct iovec const *v, unsigned int vlen, int const *fds, unsigned int nfds, unsigned char const *bits, tain const *deadline, tain *stamp) 7 | { 8 | return skabus_rpc_replyv_withfds_async(a, serial, result, v, vlen, fds, nfds, bits) 9 | && skaclient_timed_aflush(&a->connection, deadline, stamp) ; 10 | } 11 | -------------------------------------------------------------------------------- /src/libskabus/skabus_pub_list.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | 9 | int skabus_pub_list (skabus_pub_t *a, stralloc *sa, diuint32 *n, tain const *deadline, tain *stamp) 10 | { 11 | skabus_pub_list_result_t r ; 12 | if (!skabus_pub_list_async(a, sa, &r)) return 0 ; 13 | if (!skaclient_syncify(&a->connection, deadline, stamp)) return 0 ; 14 | if (r.err) return (errno = r.err, 0) ; 15 | *n = r.n ; 16 | return 1 ; 17 | } 18 | -------------------------------------------------------------------------------- /src/libskabus/skabus_pub_start.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | 5 | #include 6 | 7 | int skabus_pub_start (skabus_pub_t *a, char const *path, tain const *deadline, tain *stamp) 8 | { 9 | return skaclient_start_b( 10 | &a->connection, 11 | &a->buffers, 12 | path, 13 | SKACLIENT_OPTION_ASYNC_ACCEPT_FDS, 14 | SKABUS_PUB_BANNER1, 15 | SKABUS_PUB_BANNER1_LEN, 16 | SKABUS_PUB_BANNER2, 17 | SKABUS_PUB_BANNER2_LEN, 18 | deadline, 19 | stamp) ; 20 | } 21 | -------------------------------------------------------------------------------- /src/libskabus/skabus_rpc_start.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | 5 | #include 6 | 7 | int skabus_rpc_start (skabus_rpc_t *a, char const *path, tain const *deadline, tain *stamp) 8 | { 9 | return skaclient_start_b( 10 | &a->connection, 11 | &a->buffers, 12 | path, 13 | SKACLIENT_OPTION_ASYNC_ACCEPT_FDS, 14 | SKABUS_RPC_BANNER1, 15 | SKABUS_RPC_BANNER1_LEN, 16 | SKABUS_RPC_BANNER2, 17 | SKABUS_RPC_BANNER2_LEN, 18 | deadline, 19 | stamp) ; 20 | } 21 | -------------------------------------------------------------------------------- /src/libskabus/skabus_rpc_qlist_ack.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | void skabus_rpc_qlist_ack (skabus_rpc_t *a, size_t n) 11 | { 12 | uint64_t len = genalloc_len(uint64_t, &a->qlist) ; 13 | uint64_t *p = genalloc_s(uint64_t, &a->qlist) ; 14 | if (n > len) n = len ; 15 | memmove(p, p + n * sizeof(uint64_t), (len - n) * sizeof(uint64_t)) ; 16 | genalloc_setlen(uint64_t, &a->qlist, len - n) ; 17 | } 18 | -------------------------------------------------------------------------------- /src/libskabus/skabus_pub_start_async.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | 5 | #include 6 | 7 | int skabus_pub_start_async (skabus_pub_t *a, char const *path, skabus_pub_start_result_t *data) 8 | { 9 | return skaclient_start_async_b( 10 | &a->connection, 11 | &a->buffers, 12 | path, 13 | SKACLIENT_OPTION_ASYNC_ACCEPT_FDS, 14 | SKABUS_PUB_BANNER1, 15 | SKABUS_PUB_BANNER1_LEN, 16 | SKABUS_PUB_BANNER2, 17 | SKABUS_PUB_BANNER2_LEN, 18 | &data->skaclient_cbdata) ; 19 | } 20 | -------------------------------------------------------------------------------- /src/libskabus/skabus_rpc_start_async.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | 5 | #include 6 | 7 | int skabus_rpc_start_async (skabus_rpc_t *a, char const *path, skabus_rpc_start_result_t *data) 8 | { 9 | return skaclient_start_async_b( 10 | &a->connection, 11 | &a->buffers, 12 | path, 13 | SKACLIENT_OPTION_ASYNC_ACCEPT_FDS, 14 | SKABUS_RPC_BANNER1, 15 | SKABUS_RPC_BANNER1_LEN, 16 | SKABUS_RPC_BANNER2, 17 | SKABUS_RPC_BANNER2_LEN, 18 | &data->skaclient_cbdata) ; 19 | } 20 | -------------------------------------------------------------------------------- /src/libskabus/skabus_rpc_end.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | void skabus_rpc_end (skabus_rpc_t *a) 14 | { 15 | skaclient_end(&a->connection) ; 16 | genalloc_free(uint64_t, &a->qlist) ; 17 | avltree_free(&a->qmap) ; 18 | gensetdyn_free(&a->q) ; 19 | gensetdyn_free(&a->r) ; 20 | a->pmid = (uint32_t)-1 ; 21 | } 22 | -------------------------------------------------------------------------------- /src/libskabus/skabus_rpc_interface_unregister.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | int skabus_rpc_interface_unregister (skabus_rpc_t *a, uint32_t ifid, tain const *deadline, tain *stamp) 11 | { 12 | skabus_rpc_interface_result_t r ; 13 | if (!skabus_rpc_interface_unregister_async(a, ifid, &r)) return 0 ; 14 | if (!skaclient_syncify(&a->connection, deadline, stamp)) return 0 ; 15 | if (r.err) return (errno = r.err, 0) ; 16 | return 1 ; 17 | } 18 | -------------------------------------------------------------------------------- /src/libskabus/skabus_rpc_interface_register_cb.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include "skabus-rpc-internal.h" 11 | 12 | int skabus_rpc_interface_register_cb (unixmessage const *m, void *p) 13 | { 14 | skabus_rpc_interface_result_t *r = p ; 15 | if (m->len != 1 || m->nfds) return (errno = EPROTO, 0) ; 16 | r->err = m->s[0] ; 17 | if (r->err) gensetdyn_delete(r->r, r->ifid) ; 18 | return 1 ; 19 | } 20 | -------------------------------------------------------------------------------- /src/libskabus/skabus_rpc_idstr.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | int skabus_rpc_idstr (skabus_rpc_t *a, char const *idstr, skabus_rpc_interface_t const *ifbody, char const *re, tain const *deadline, tain *stamp) 11 | { 12 | skabus_rpc_interface_result_t r ; 13 | if (!skabus_rpc_idstr_async(a, idstr, ifbody, re, &r)) return 0 ; 14 | if (!skaclient_syncify(&a->connection, deadline, stamp)) return 0 ; 15 | return r.err ? (errno = r.err, 0) : 1 ; 16 | } 17 | -------------------------------------------------------------------------------- /src/libskabus/skabus_pub_send.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | 9 | 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 const *deadline, tain *stamp) 10 | { 11 | skabus_pub_send_result_t r ; 12 | if (!skabus_pub_send_withfds_async(a, s, len, fds, nfds, bits, &r)) return 0 ; 13 | if (!skaclient_syncify(&a->connection, deadline, stamp)) return 0 ; 14 | return r.err ? (errno = r.err, 0) : r.u ; 15 | } 16 | -------------------------------------------------------------------------------- /patch-for-solaris: -------------------------------------------------------------------------------- 1 | #!/usr/xpg4/bin/sh -e 2 | 3 | patchit () { 4 | echo '#!/usr/xpg4/bin/sh' > $1.tmp 5 | tail -n +2 $1 >> $1.tmp 6 | mv -f $1.tmp $1 7 | chmod 755 $1 8 | } 9 | 10 | # Solaris doesn't understand POSIX.1-2008 either. 11 | sed -e 's/XOPEN_SOURCE=700/XOPEN_SOURCE=600/' < configure > configure.tmp 12 | mv -f configure.tmp configure 13 | 14 | patchit ./configure 15 | patchit ./tools/install.sh 16 | patchit ./tools/gen-deps.sh 17 | 18 | echo 'SHELL := /usr/xpg4/bin/sh' > Makefile.tmp 19 | echo >> Makefile.tmp 20 | cat Makefile >> Makefile.tmp 21 | mv -f Makefile.tmp Makefile 22 | -------------------------------------------------------------------------------- /src/libskabus/skabus_pub_sendpm.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | 9 | 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 const *deadline, tain *stamp) 10 | { 11 | skabus_pub_send_result_t r ; 12 | if (!skabus_pub_sendpm_withfds_async(a, id, s, len, fds, nfds, bits, &r)) return 0 ; 13 | if (!skaclient_syncify(&a->connection, deadline, stamp)) return 0 ; 14 | return r.err ? (errno = r.err, 0) : r.u ; 15 | } 16 | -------------------------------------------------------------------------------- /src/libskabus/skabus_pub_send_cb.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | int skabus_pub_send_cb (unixmessage const *m, void *p) 12 | { 13 | skabus_pub_send_result_t *r = p ; 14 | if (!m->len || m->nfds) return (errno = EPROTO, 0) ; 15 | if (m->s[0]) 16 | { 17 | r->u = 0 ; 18 | r->err = m->s[0] ; 19 | return 1 ; 20 | } 21 | if (m->len != 9) return (errno = EPROTO, 0) ; 22 | uint64_unpack_big(m->s + 1, &r->u) ; 23 | r->err = 0 ; 24 | return 1 ; 25 | } 26 | -------------------------------------------------------------------------------- /src/libskabus/skabus_pub_sendv.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | 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 const *deadline, tain *stamp) 11 | { 12 | skabus_pub_send_result_t r ; 13 | if (!skabus_pub_sendv_withfds_async(a, v, vlen, fds, nfds, bits, &r)) return 0 ; 14 | if (!skaclient_syncify(&a->connection, deadline, stamp)) return 0 ; 15 | return r.err ? (errno = r.err, 0) : r.u ; 16 | } 17 | -------------------------------------------------------------------------------- /src/libskabus/skabus_pub_sendvpm.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | 9 | 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 const *deadline, tain *stamp) 10 | { 11 | skabus_pub_send_result_t r ; 12 | if (!skabus_pub_sendvpm_withfds_async(a, idstr, v, vlen, fds, nfds, bits, &r)) return 0 ; 13 | if (!skaclient_syncify(&a->connection, deadline, stamp)) return 0 ; 14 | return r.err ? (errno = r.err, 0) : r.u ; 15 | } 16 | -------------------------------------------------------------------------------- /src/libskabus/skabus_rpc_rinfo_pack.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | void skabus_rpc_rinfo_pack (char *s, skabus_rpc_rinfo_t const *ri) 13 | { 14 | uint64_pack_big(s, ri->serial) ; s += 8 ; 15 | tain_pack(s, &ri->limit) ; s += TAIN_PACK ; 16 | tain_pack(s, &ri->timestamp) ; s += TAIN_PACK ; 17 | uid_pack_big(s, ri->uid) ; s += UID_PACK ; 18 | gid_pack_big(s, ri->gid) ; s += GID_PACK ; 19 | memcpy(s, ri->idstr, SKABUS_RPC_IDSTR_SIZE + 1) ; 20 | } 21 | -------------------------------------------------------------------------------- /tools/run-test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | prog="$1" 4 | 5 | if test -x "./src/tests/${prog}.wrapper" ; then 6 | cmd="./src/tests/${prog}.wrapper $prog" 7 | else 8 | cmd="./$prog" 9 | fi 10 | 11 | if test -r "./src/tests/${prog}.expected" ; then 12 | cp -f "./src/tests/${prog}.expected" "./${prog}.expected" 13 | elif test -x "./src/tests/${prog}.baseline" ; then 14 | "./src/tests/${prog}.baseline" > "./${prog}.expected" 15 | else 16 | echo "run-test.sh: fatal: missing baseline for $prog" 1>&2 ; exit 100 17 | fi 18 | 19 | $cmd | diff "./${prog}.expected" - 20 | 21 | rm -f "./${prog}.expected" 22 | echo "run-test.sh: info: $prog: pass" 1>&2 23 | -------------------------------------------------------------------------------- /src/libskabus/skabus_rpc_rinfo_unpack.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | void skabus_rpc_rinfo_unpack (char const *s, skabus_rpc_rinfo_t *ri) 13 | { 14 | uint64_unpack_big(s, &ri->serial) ; s += 8 ; 15 | tain_unpack(s, &ri->limit) ; s += TAIN_PACK ; 16 | tain_unpack(s, &ri->timestamp) ; s += TAIN_PACK ; 17 | uid_unpack_big(s, &ri->uid) ; s += UID_PACK ; 18 | gid_unpack_big(s, &ri->gid) ; s += GID_PACK ; 19 | memcpy(ri->idstr, s, SKABUS_RPC_IDSTR_SIZE + 1) ; 20 | } 21 | -------------------------------------------------------------------------------- /src/rpc/skabus-rpcc.h: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #ifndef SKABUS_RPCC_H 4 | #define SKABUS_RPCC_H 5 | 6 | #include 7 | 8 | #define SKABUS_RPCC_BUFSIZE 4095 9 | #define SKABUS_RPCC_MAX 256 10 | #define SKABUS_RPCC_INTERFACES_MAX 64 11 | #define SKABUS_RPCC_QUERIES_MAX 1024 12 | 13 | #define X() strerr_dief1x(101, "unexpected error - please submit a bug-report.") 14 | #define dietoomanyinterfaces() strerr_dief1x(100, "too many interface definitions") 15 | #define dieemptyifname() strerr_dief1x(100, "an interface name may not be empty") 16 | #define dieemptyifprog() strerr_dief1x(100, "an interface program may not be empty") 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /src/libskabus/skabus_pub_end.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | static void skabus_pub_cltinfo_free (skabus_pub_cltinfo_t *p) 11 | { 12 | fd_close(p->fd) ; 13 | if (p->nfds) 14 | { 15 | for (size_t i = 0 ; i < p->nfds ; i++) fd_close(p->fds[i]) ; 16 | alloc_free(p->fds) ; 17 | } 18 | } 19 | 20 | void skabus_pub_end (skabus_pub_t *a) 21 | { 22 | skaclient_end(&a->connection) ; 23 | genalloc_deepfree(skabus_pub_cltinfo_t, &a->info, &skabus_pub_cltinfo_free) ; 24 | a->head = 0 ; 25 | } 26 | -------------------------------------------------------------------------------- /src/libskabus/skabus_rpc_interface_register.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | int skabus_rpc_interface_register (skabus_rpc_t *a, uint32_t *ifid, char const *ifname, skabus_rpc_interface_t const *ifbody, char const *re, tain const *deadline, tain *stamp) 11 | { 12 | skabus_rpc_interface_result_t r ; 13 | if (!skabus_rpc_interface_register_async(a, ifname, ifbody, re, &r)) return 0 ; 14 | if (!skaclient_syncify(&a->connection, deadline, stamp)) return 0 ; 15 | if (r.err) return (errno = r.err, 0) ; 16 | *ifid = r.ifid ; 17 | return 1 ; 18 | } 19 | -------------------------------------------------------------------------------- /src/libskabus/skabus_pub_send_async.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | #include "skabus-pub-internal.h" 10 | 11 | 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) 12 | { 13 | struct iovec v[2] = { { .iov_base = "!", .iov_len = 1 }, { .iov_base = (char *)s, .iov_len = len } } ; 14 | unixmessagev m = { .v = v, .vlen = 2, .fds = (int *)fds, .nfds = nfds } ; 15 | return skaclient_putmsgv_and_close(&a->connection, &m, bits, &skabus_pub_send_cb, result) ; 16 | } 17 | -------------------------------------------------------------------------------- /src/libskabus/skabus_pub_subunsub_async.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include 10 | 11 | int skabus_pub_subunsub_async (skabus_pub_t *a, char what, char const *id, unsigned char *err) 12 | { 13 | size_t idlen = strlen(id) ; 14 | char pack[2] = { what, (unsigned char)idlen } ; 15 | struct iovec v[2] = 16 | { 17 | { .iov_base = pack, .iov_len = 2 }, 18 | { .iov_base = (char *)id, .iov_len = idlen+1 } 19 | } ; 20 | if (idlen > SKABUS_PUB_IDSTR_SIZE) return (errno = ERANGE, 0) ; 21 | return skaclient_putv(&a->connection, v, 2, &skaclient_default_cb, err) ; 22 | } 23 | -------------------------------------------------------------------------------- /src/libskabus/skabus_rpc_sendvq.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | 5 | #include 6 | #include "skabus-rpc-internal.h" 7 | 8 | uint64_t skabus_rpc_sendvq_withfds (skabus_rpc_t *a, char const *prefix, size_t plen, char const *ifname, struct iovec const *v, unsigned int vlen, int const *fds, unsigned int nfds, unsigned char const *bits, tain const *limit, tain const *deadline, tain *stamp) 9 | { 10 | skabus_rpc_send_result_t r ; 11 | if (!skabus_rpc_sendvq_withfds_async(a, prefix, plen, ifname, v, vlen, fds, nfds, bits, limit, &r)) return 0 ; 12 | if (!skaclient_syncify(&a->connection, deadline, stamp)) return 0 ; 13 | return r.err ? (errno = r.err, 0) : r.u ; 14 | } 15 | -------------------------------------------------------------------------------- /src/libskabus/skabus_rpc_sendq.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | #include "skabus-rpc-internal.h" 9 | 10 | uint64_t skabus_rpc_sendq_withfds (skabus_rpc_t *a, char const *prefix, size_t plen, char const *ifname, char const *s, size_t len, int const *fds, unsigned int nfds, unsigned char const *bits, tain const *limit, tain const *deadline, tain *stamp) 11 | { 12 | skabus_rpc_send_result_t r ; 13 | if (!skabus_rpc_sendq_withfds_async(a, prefix, plen, ifname, s, len, fds, nfds, bits, limit, &r)) return 0 ; 14 | if (!skaclient_syncify(&a->connection, deadline, stamp)) return 0 ; 15 | return r.err ? (errno = r.err, 0) : r.u ; 16 | } 17 | -------------------------------------------------------------------------------- /src/libskabus/skabus_rpc_get.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | int skabus_rpc_get (skabus_rpc_t *a, uint64_t serial, int *result, unixmessage *m) 13 | { 14 | uint32_t id ; 15 | skabus_rpc_qinfo_t *p ; 16 | if (!avltree_search(&a->qmap, &serial, &id)) 17 | { 18 | if (errno == ESRCH) errno = EINVAL ; 19 | return -1 ; 20 | } 21 | p = GENSETDYN_P(skabus_rpc_qinfo_t, &a->q, id) ; 22 | if (p->status) 23 | return error_isagain(p->status) ? 0 : (errno = p->status, -1) ; 24 | *result = (int)(unsigned char)p->result ; 25 | *m = p->message ; 26 | return 1 ; 27 | } 28 | -------------------------------------------------------------------------------- /src/libskabus/skabus_rpc_reply_async.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | int skabus_rpc_reply_withfds_async (skabus_rpc_t *a, uint64_t serial, char result, char const *s, size_t len, int const *fds, unsigned int nfds, unsigned char const *bits) 12 | { 13 | char pack[10] = "R" ; 14 | struct iovec v[2] = { { .iov_base = pack, .iov_len = 10 }, { .iov_base = (char *)s, .iov_len = len } } ; 15 | unixmessagev m = { .v = v, .vlen = 2, .fds = (int *)fds, .nfds = nfds } ; 16 | uint64_pack_big(pack+1, serial) ; 17 | pack[9] = result ; 18 | return skaclient_aputv_and_close(&a->connection, &m, bits) ; 19 | } 20 | -------------------------------------------------------------------------------- /src/libskabus/skabus_pub_sendv_async.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | #include "skabus-pub-internal.h" 10 | 11 | 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) 12 | { 13 | struct iovec vv[vlen+1] ; 14 | unixmessagev m = { .v = vv, .vlen = vlen+1, .fds = (int *)fds, .nfds = nfds } ; 15 | vv[0].iov_base = "!" ; vv[0].iov_len = 1 ; 16 | for (unsigned int i = 0 ; i < vlen ; i++) vv[1+i] = v[i] ; 17 | return skaclient_putmsgv_and_close(&a->connection, &m, bits, &skabus_pub_send_cb, result) ; 18 | } 19 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | skabus - a simpler Unix bus 2 | --------------------------- 3 | 4 | skabus is a suite of programs related to 1-to-many, 5 | many-to-1 or many-to-many interprocess communication on Unix. 6 | Ultimately, it will be a full implementation of a Unix bus, 7 | aiming for simplicity and maintainability. 8 | 9 | For now, it is very much a work in progress, and it feels like 10 | a random collection of tools, even if it's not random. 11 | 12 | See http://skarnet.org/software/skabus/ for details. 13 | 14 | 15 | * Installation 16 | ------------ 17 | 18 | See the INSTALL file. 19 | 20 | 21 | * Contact information 22 | ------------------- 23 | 24 | Laurent Bercot 25 | 26 | Please use the mailing-list for 27 | questions about skabus. 28 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017-2025 Laurent Bercot 2 | 3 | Permission to use, copy, modify, and distribute this software for any 4 | purpose with or without fee is hereby granted, provided that the above 5 | copyright notice and this permission notice appear in all copies. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | -------------------------------------------------------------------------------- /src/libskabus/skabus_rpc_replyv_async.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | int skabus_rpc_replyv_withfds_async (skabus_rpc_t *a, uint64_t serial, char result, struct iovec const *v, unsigned int vlen, int const *fds, unsigned int nfds, unsigned char const *bits) 10 | { 11 | char pack[10] = "R" ; 12 | struct iovec vv[vlen + 1] ; 13 | unixmessagev m = { .v = vv, .vlen = vlen+1, .fds = (int *)fds, .nfds = nfds } ; 14 | vv[0].iov_base = pack ; vv[0].iov_len = 10 ; 15 | for (unsigned int i = 0 ; i < vlen ; i++) vv[1+i] = v[i] ; 16 | uint64_pack_big(pack+1, serial) ; 17 | pack[9] = result ; 18 | return skaclient_aputv_and_close(&a->connection, &m, bits) ; 19 | } 20 | -------------------------------------------------------------------------------- /doc/upgrade.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | skabus: how to upgrade 7 | 8 | 9 | 10 | 11 | 12 | 13 |

14 | skabus
15 | Software
16 | skarnet.org 17 |

18 | 19 |

What has changed in skabus

20 | 21 |

in 0.0.1.0

22 | 23 |
    24 |
  • Initial release.
  • 25 |
26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/libskabus/skabus_rpc_cancel_async.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | int skabus_rpc_cancel_async (skabus_rpc_t *a, uint64_t serial, unsigned char *err) 14 | { 15 | uint32_t id ; 16 | skabus_rpc_qinfo_t *p ; 17 | char pack[9] = "C" ; 18 | if (!avltree_search(&a->qmap, &serial, &id)) return 0 ; 19 | p = GENSETDYN_P(skabus_rpc_qinfo_t, &a->q, id) ; 20 | if (p->status != EAGAIN) return (errno = EINVAL, 0) ; 21 | uint64_pack_big(pack+1, serial) ; 22 | if (!skaclient_put(&a->connection, pack, 9, &skaclient_default_cb, err)) return 0 ; 23 | p->status = EINVAL ; 24 | avltree_delete(&a->qmap, &serial) ; 25 | gensetdyn_delete(&a->q, id) ; 26 | return 1 ; 27 | } 28 | -------------------------------------------------------------------------------- /src/libskabus/skabus_rpc_release.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | int skabus_rpc_release (skabus_rpc_t *a, uint64_t serial) 14 | { 15 | uint32_t id ; 16 | skabus_rpc_qinfo_t *p ; 17 | if (!avltree_search(&a->qmap, &serial, &id)) 18 | { 19 | if (errno == ESRCH) errno = EINVAL ; 20 | return 0 ; 21 | } 22 | p = GENSETDYN_P(skabus_rpc_qinfo_t, &a->q, id) ; 23 | if (p->status) return (errno = p->status, 0) ; 24 | alloc_free(p->message.s) ; 25 | alloc_free(p->message.fds) ; 26 | /* fds are purposefully left open for the client. */ 27 | p->status = EINVAL ; 28 | avltree_delete(&a->qmap, &serial) ; 29 | gensetdyn_delete(&a->q, id) ; 30 | return 1 ; 31 | } 32 | -------------------------------------------------------------------------------- /src/libskabus/skabus_pub_message_get.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | #include "skabus-pub-internal.h" 10 | 11 | size_t skabus_pub_message_get (skabus_pub_t *a, skabus_pub_msginfo_t *info, int *fd, int *fds) 12 | { 13 | size_t n = genalloc_len(skabus_pub_cltinfo_t, &a->info) ; 14 | skabus_pub_cltinfo_t *p = genalloc_s(skabus_pub_cltinfo_t, &a->info) + a->head ; 15 | if (!n) return 0 ; 16 | *info = p->msginfo ; 17 | *fd = p->fd ; 18 | if (p->nfds) 19 | { 20 | for (size_t i = 0 ; i < p->nfds ; i++) fds[i] = p->fds[i] ; 21 | alloc_free(p->fds) ; 22 | } 23 | 24 | if (++a->head == n || a->head > SKABUS_HEAD_MAX) 25 | { 26 | n -= a->head ; 27 | memmove(a->info.s, a->info.s + a->head * sizeof(skabus_pub_cltinfo_t), n * sizeof(skabus_pub_cltinfo_t)) ; 28 | genalloc_setlen(skabus_pub_cltinfo_t, &a->info, n) ; 29 | a->head = 0 ; 30 | } 31 | return 1 + n - a->head ; 32 | } 33 | -------------------------------------------------------------------------------- /src/libskabus/skabus_pub_sendpm_async.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | #include 11 | #include "skabus-pub-internal.h" 12 | 13 | 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) 14 | { 15 | size_t idlen = strlen(idstr) ; 16 | char tmp[2] = "+" ; 17 | struct iovec v[3] = 18 | { 19 | { .iov_base = tmp, .iov_len = 2 }, 20 | { .iov_base = (char *)idstr, .iov_len = idlen+1 }, 21 | { .iov_base = (char *)s, .iov_len = len } 22 | } ; 23 | unixmessagev m = { .v = v, .vlen = 3, .fds = (int *)fds, .nfds = nfds } ; 24 | if (idlen > SKABUS_PUB_IDSTR_SIZE) return (errno = ERANGE, 0) ; 25 | tmp[1] = (unsigned char)idlen ; 26 | return skaclient_putmsgv_and_close(&a->connection, &m, bits, &skabus_pub_send_cb, result) ; 27 | } 28 | -------------------------------------------------------------------------------- /src/libskabus/skabus_pub_register_async.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | int skabus_pub_register_async (skabus_pub_t *a, char const *id, char const *sre, char const *wre, unsigned char *err) 13 | { 14 | size_t idlen = strlen(id) ; 15 | size_t srelen = strlen(sre) ; 16 | size_t wrelen = strlen(wre) ; 17 | char pack[10] = "R" ; 18 | struct iovec v[4] = 19 | { 20 | { .iov_base = pack, .iov_len = 10 }, 21 | { .iov_base = (char *)id, .iov_len = idlen+1 }, 22 | { .iov_base = (char *)sre, .iov_len = srelen+1 }, 23 | { .iov_base = (char *)wre, .iov_len = wrelen+1 } 24 | } ; 25 | if (idlen > SKABUS_PUB_IDSTR_SIZE) return (errno = ERANGE, 0) ; 26 | pack[1] = (unsigned char)idlen ; 27 | uint32_pack_big(pack+2, srelen) ; 28 | uint32_pack_big(pack+6, wrelen) ; 29 | return skaclient_putv(&a->connection, v, 4, &skaclient_default_cb, err) ; 30 | } 31 | -------------------------------------------------------------------------------- /tools/gen-configure.el: -------------------------------------------------------------------------------- 1 | #!/command/execlineb -S0 2 | 3 | # For dev use only. Don't run this, it overwrites your configure. 4 | 5 | # The quoting interactions in sed and sh make it impossible to get 6 | # such a simple thing done. It's amazing how bad traditional Unix is. 7 | 8 | backtick -E TEMPLATE { redirfd -r 0 tools/configure.template s6-cat } 9 | s6-envdir -Lf package/configure-snippets 10 | multisubstitute 11 | { 12 | importas -uS configure_help_install 13 | importas -uS configure_help_dependencies 14 | importas -uS configure_help_options 15 | importas -uS configure_init_vars 16 | importas -uS configure_case_lines 17 | importas -uS configure_expand_dirs 18 | importas -uS configure_slashpackage_other 19 | importas -uS configure_extra_checks 20 | importas -uS configure_generate_make 21 | importas -uS configure_generate_configh 22 | } 23 | 24 | if 25 | { 26 | redirfd -w 1 configure.new 27 | if { heredoc 0 ${TEMPLATE} s6-cat } 28 | s6-echo 29 | } 30 | 31 | if { s6-chmod 0755 configure.new } 32 | s6-rename configure.new configure 33 | -------------------------------------------------------------------------------- /src/libskabus/skabus_pub_sendvpm_async.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | #include 11 | #include "skabus-pub-internal.h" 12 | 13 | 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) 14 | { 15 | size_t idlen = strlen(idstr) ; 16 | char tmp[2] = "+" ; 17 | struct iovec vv[vlen + 2] ; 18 | unixmessagev m = { .v = vv, .vlen = vlen + 2, .fds = (int *)fds, .nfds = nfds } ; 19 | if (idlen > SKABUS_PUB_IDSTR_SIZE) return (errno = ERANGE, 0) ; 20 | tmp[1] = (unsigned char)idlen ; 21 | vv[0].iov_base = tmp ; vv[0].iov_len = 2 ; 22 | vv[1].iov_base = (char *)idstr ; vv[1].iov_len = idlen+1 ; 23 | for (unsigned int i = 0 ; i < vlen ; i++) vv[2+i] = v[i] ; 24 | return skaclient_putmsgv_and_close(&a->connection, &m, bits, &skabus_pub_send_cb, result) ; 25 | } 26 | -------------------------------------------------------------------------------- /src/misc/skabus-dyntee-client.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define USAGE "skabus-dyntee-client path prog..." 10 | #define dieusage() strerr_dieusage(100, USAGE) 11 | 12 | int main (int argc, char const *const *argv) 13 | { 14 | int fd ; 15 | PROG = "skabus-dyntee-client" ; 16 | { 17 | subgetopt l = SUBGETOPT_ZERO ; 18 | for (;;) 19 | { 20 | int opt = subgetopt_r(argc, argv, "", &l) ; 21 | if (opt == -1) break ; 22 | switch (opt) 23 | { 24 | default : dieusage() ; 25 | } 26 | } 27 | argc -= l.ind ; argv += l.ind ; 28 | if (argc < 2) dieusage() ; 29 | } 30 | 31 | fd = ipc_stream_b() ; 32 | if (fd < 0) strerr_diefu1sys(111, "create socket") ; 33 | if (!ipc_connect(fd, argv[0])) strerr_diefu2sys(111, "connect to ", argv[0]) ; 34 | fd_shutdown(fd, 1) ; 35 | if (fd_move(0, fd) < 0) strerr_diefu1sys(111, "move socket fd to stdin") ; 36 | xexec(argv+1) ; 37 | } 38 | -------------------------------------------------------------------------------- /src/libskabus/skabus_rpc_interface_unregister_async.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | static int skabus_rpc_interface_unregister_cb (unixmessage const *m, void *p) 15 | { 16 | skabus_rpc_interface_result_t *r = p ; 17 | if (m->len != 1 || m->nfds) return (errno = EPROTO, 0) ; 18 | r->err = m->s[0] ; 19 | return r->err ? 1 : gensetdyn_delete(r->r, r->ifid) ; 20 | } 21 | 22 | int skabus_rpc_interface_unregister_async (skabus_rpc_t *a, uint32_t ifid, skabus_rpc_interface_result_t *result) 23 | { 24 | char *name = GENSETDYN_P(skabus_rpc_ifnode_t, &a->r, ifid)->name ; 25 | size_t n = strlen(name) ; 26 | char pack[2] = { 'i', (unsigned char)n } ; 27 | struct iovec v[2] = { { .iov_base = pack, .iov_len = 2 }, { .iov_base = name, .iov_len = n+1 } } ; 28 | result->r = &a->r ; 29 | result->ifid = ifid ; 30 | return skaclient_putv(&a->connection, v, 2, &skabus_rpc_interface_unregister_cb, result) ; 31 | } 32 | -------------------------------------------------------------------------------- /src/libskabus/skabus-rpc-internal.h: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #ifndef SKABUS_RPC_INTERNAL_H 4 | #define SKABUS_RPC_INTERNAL_H 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | extern int skabus_rpc_sendq_withfds_async (skabus_rpc_t *, char const *, size_t, char const *, char const *, size_t, int const *, unsigned int, unsigned char const *, tain const *, skabus_rpc_send_result_t *) ; 13 | extern uint64_t skabus_rpc_sendq_withfds (skabus_rpc_t *, char const *, size_t, char const *, char const *, size_t, int const *, unsigned int, unsigned char const *, tain const *, tain const *, tain *) ; 14 | extern int skabus_rpc_sendvq_withfds_async (skabus_rpc_t *, char const *, size_t, char const *, struct iovec const *, unsigned int, int const *, unsigned int, unsigned char const *, tain const *, skabus_rpc_send_result_t *) ; 15 | extern uint64_t skabus_rpc_sendvq_withfds (skabus_rpc_t *, char const *, size_t, char const *, struct iovec const *, unsigned int, int const *, unsigned int, unsigned char const *, tain const *, tain const *, tain *) ; 16 | 17 | extern unixmessage_handler_func skabus_rpc_send_cb ; 18 | extern unixmessage_handler_func skabus_rpc_interface_register_cb ; 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /src/libskabus/skabus_rpc_idstr_async.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include "skabus-rpc-internal.h" 13 | 14 | int skabus_rpc_idstr_async (skabus_rpc_t *a, char const *idstr, skabus_rpc_interface_t const *ifbody, char const *re, skabus_rpc_interface_result_t *result) 15 | { 16 | size_t idlen = strlen(idstr) ; 17 | size_t relen = strlen(re) ; 18 | skabus_rpc_ifnode_t *ifnode ; 19 | char pack[10] = "S" ; 20 | struct iovec v[3] = { { .iov_base = pack, .iov_len = 10 }, { .iov_base = (char *)idstr, .iov_len = idlen+1 }, { .iov_base = (char *)re, .iov_len = relen+1 } } ; 21 | if (idlen > SKABUS_RPC_IDSTR_SIZE) return (errno = ENAMETOOLONG, 0) ; 22 | if (relen > SKABUS_RPC_RE_MAXLEN) return (errno = ENAMETOOLONG, 0) ; 23 | if (!gensetdyn_new(&a->r, &a->pmid)) return 0 ; 24 | result->ifid = a->pmid ; 25 | result->r = &a->r ; 26 | ifnode = GENSETDYN_P(skabus_rpc_ifnode_t, &a->r, a->pmid) ; 27 | ifnode->name[0] = 0 ; 28 | ifnode->body = *ifbody ; 29 | uint32_pack_big(pack+1, a->pmid) ; 30 | pack[5] = (unsigned char)idlen ; 31 | uint32_pack_big(pack+6, relen) ; 32 | return skaclient_putv(&a->connection, v, 3, &skabus_rpc_interface_register_cb, result) ; 33 | } 34 | -------------------------------------------------------------------------------- /tools/install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | usage() { 4 | echo "usage: $0 [ -D ] [ -l ] [ -m mode ] [ -O owner:group ] src dst" 1>&2 5 | exit 1 6 | } 7 | 8 | mkdirp=false 9 | symlink=false 10 | mode=0755 11 | og= 12 | 13 | while getopts Dlm:O: name ; do 14 | case "$name" in 15 | D) mkdirp=true ;; 16 | l) symlink=true ;; 17 | m) mode=$OPTARG ;; 18 | O) og=$OPTARG ;; 19 | ?) usage ;; 20 | esac 21 | done 22 | shift $(($OPTIND - 1)) 23 | 24 | test "$#" -eq 2 || usage 25 | src=$1 26 | dst=$2 27 | tmp="$dst.tmp.$$" 28 | 29 | case "$dst" in 30 | */) echo "$0: $dst ends in /" 1>&2 ; exit 1 ;; 31 | esac 32 | 33 | set -C 34 | set -e 35 | 36 | if $mkdirp ; then 37 | umask 022 38 | case "$2" in 39 | */*) mkdir -p "${dst%/*}" ;; 40 | esac 41 | fi 42 | 43 | trap 'rm -f "$tmp"' EXIT INT QUIT TERM HUP 44 | 45 | umask 077 46 | 47 | if $symlink ; then 48 | ln -s "$src" "$tmp" 49 | else 50 | cat < "$1" > "$tmp" 51 | if test -n "$og" ; then 52 | chown -- "$og" "$tmp" 53 | fi 54 | chmod -- "$mode" "$tmp" 55 | fi 56 | 57 | mv -f "$tmp" "$dst" 58 | if test -d "$dst" ; then 59 | rm -f "$dst/$(basename $tmp)" 60 | if $symlink ; then 61 | mkdir "$tmp" 62 | ln -s "$src" "$tmp/$(basename $dst)" 63 | mv -f "$tmp/$(basename $dst)" "${dst%/*}" 64 | rmdir "$tmp" 65 | else 66 | echo "$0: $dst is a directory" 1>&2 67 | exit 1 68 | fi 69 | fi 70 | -------------------------------------------------------------------------------- /src/libskabus/skabus_pub_list_async.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | static int skabus_pub_list_cb (unixmessage const *m, void *p) 15 | { 16 | skabus_pub_list_result_t *r = p ; 17 | uint32_t n ; 18 | size_t w = 9, len = m->len - 9 ; 19 | if (m->len < 9 || m->nfds) goto errproto ; 20 | r->err = m->s[0] ; 21 | if (r->err) return 1 ; 22 | uint32_unpack_big(m->s + 1, &n) ; 23 | if (n > 0x7fffffffu || m->len < 9 + (n<<1)) goto errproto ; 24 | if (!stralloc_readyplus(r->sa, m->len - 9 - n)) goto errproto ; 25 | r->n.left = n ; 26 | uint32_unpack_big(m->s + 5, &n) ; r->n.right = n ; 27 | for (uint32_t i = 0 ; i < r->n.left ; i++) 28 | { 29 | size_t thislen ; 30 | if (len < 2) goto errproto ; 31 | thislen = m->s[w++] + 1 ; len-- ; 32 | if ((thislen > len) || m->s[w + thislen]) goto errproto ; 33 | stralloc_catb(r->sa, m->s + w, thislen) ; 34 | w += thislen ; len -= thislen ; 35 | } 36 | return 1 ; 37 | errproto: 38 | return (errno = EPROTO, 0) ; 39 | } 40 | 41 | int skabus_pub_list_async (skabus_pub_t *a, stralloc *sa, skabus_pub_list_result_t *result) 42 | { 43 | result->sa = sa ; 44 | return skaclient_put(&a->connection, "L", 1, &skabus_pub_list_cb, result) ; 45 | } 46 | -------------------------------------------------------------------------------- /src/libskabus/skabus_rpc_interface_register_async.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include "skabus-rpc-internal.h" 14 | 15 | int skabus_rpc_interface_register_async (skabus_rpc_t *a, char const *ifname, skabus_rpc_interface_t const *ifbody, char const *re, skabus_rpc_interface_result_t *result) 16 | { 17 | size_t ifnamelen = strlen(ifname) ; 18 | size_t relen = strlen(re) ; 19 | skabus_rpc_ifnode_t *ifnode ; 20 | char pack[10] = "I" ; 21 | struct iovec v[3] = { { .iov_base = pack, .iov_len = 10 }, { .iov_base = (char *)ifname, .iov_len = ifnamelen + 1 }, { .iov_base = (char *)re, .iov_len = relen + 1 } } ; 22 | if (ifnamelen > SKABUS_RPC_INTERFACE_MAXLEN) return (errno = ENAMETOOLONG, 0) ; 23 | if (relen > SKABUS_RPC_RE_MAXLEN) return (errno = ENAMETOOLONG, 0) ; 24 | if (!gensetdyn_new(&a->r, &result->ifid)) return 0 ; 25 | result->r = &a->r ; 26 | ifnode = GENSETDYN_P(skabus_rpc_ifnode_t, &a->r, result->ifid) ; 27 | memcpy(ifnode->name, ifname, ifnamelen + 1) ; 28 | ifnode->body = *ifbody ; 29 | uint32_pack_big(pack+1, result->ifid) ; 30 | pack[5] = (unsigned char)ifnamelen ; 31 | uint32_pack_big(pack+6, relen) ; 32 | return skaclient_putv(&a->connection, v, 3, &skabus_rpc_interface_register_cb, result) ; 33 | } 34 | -------------------------------------------------------------------------------- /DCO: -------------------------------------------------------------------------------- 1 | Developer Certificate of Origin 2 | Version 1.1 3 | 4 | Copyright (C) 2004, 2006 The Linux Foundation and its contributors. 5 | 1 Letterman Drive 6 | Suite D4700 7 | San Francisco, CA, 94129 8 | 9 | Everyone is permitted to copy and distribute verbatim copies of this 10 | license document, but changing it is not allowed. 11 | 12 | 13 | Developer's Certificate of Origin 1.1 14 | 15 | By making a contribution to this project, I certify that: 16 | 17 | (a) The contribution was created in whole or in part by me and I 18 | have the right to submit it under the open source license 19 | indicated in the file; or 20 | 21 | (b) The contribution is based upon previous work that, to the best 22 | of my knowledge, is covered under an appropriate open source 23 | license and I have the right under that license to submit that 24 | work with modifications, whether created in whole or in part 25 | by me, under the same open source license (unless I am 26 | permitted to submit under a different license), as indicated 27 | in the file; or 28 | 29 | (c) The contribution was provided directly to me by some other 30 | person who certified (a), (b) or (c) and I have not modified 31 | it. 32 | 33 | (d) I understand and agree that this project and the contribution 34 | are public and that a record of the contribution (including all 35 | personal information I submit with it, including my sign-off) is 36 | maintained indefinitely and may be redistributed consistent with 37 | this project or the open source license(s) involved. 38 | -------------------------------------------------------------------------------- /src/libskabus/skabus_rpc_sendq_async.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include "skabus-rpc-internal.h" 14 | 15 | int skabus_rpc_sendq_withfds_async (skabus_rpc_t *a, char const *prefix, size_t plen, char const *ifname, char const *s, size_t len, int const *fds, unsigned int nfds, unsigned char const *bits, tain const *limit, skabus_rpc_send_result_t *r) 16 | { 17 | size_t iflen = strlen(ifname) ; 18 | char pack[2 + TAIN_PACK] = "Q" ; 19 | struct iovec v[4] = { { .iov_base = pack, .iov_len = 2 + TAIN_PACK }, { .iov_base = (char *)prefix, .iov_len = plen }, { .iov_base = (char *)ifname, .iov_len = iflen + 1 }, { .iov_base = (char *)s, .iov_len = len } } ; 20 | unixmessagev m = { .v = v, .vlen = 4, .fds = (int *)fds, .nfds = nfds } ; 21 | iflen += plen ; 22 | if (iflen > SKABUS_RPC_INTERFACE_MAXLEN) return (errno = ENAMETOOLONG, 0) ; 23 | if (!gensetdyn_new(&a->q, &r->i)) return 0 ; 24 | r->a = a ; 25 | if (limit) tain_pack(pack + 1, limit) ; else memset(pack + 1, 0, TAIN_PACK) ; 26 | pack[1 + TAIN_PACK] = (unsigned char)iflen ; 27 | if (!skaclient_putmsgv_and_close(&a->connection, &m, bits, &skabus_rpc_send_cb, r)) 28 | { 29 | int e = errno ; 30 | gensetdyn_delete(&a->q, r->i) ; 31 | errno = e ; 32 | return 0 ; 33 | } 34 | GENSETDYN_P(skabus_rpc_qinfo_t, &a->q, r->i)->status = EINPROGRESS ; 35 | return 1 ; 36 | } 37 | -------------------------------------------------------------------------------- /src/libskabus/skabus_rpc_sendvq_async.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include "skabus-rpc-internal.h" 14 | 15 | int skabus_rpc_sendvq_withfds_async (skabus_rpc_t *a, char const *prefix, size_t plen, char const *ifname, struct iovec const *v, unsigned int vlen, int const *fds, unsigned int nfds, unsigned char const *bits, tain const *limit, skabus_rpc_send_result_t *r) 16 | { 17 | size_t iflen = strlen(ifname) ; 18 | char pack[2 + TAIN_PACK] = "Q" ; 19 | struct iovec vv[vlen + 3] ; 20 | unixmessagev m = { .v = vv, .vlen = vlen + 3, .fds = (int *)fds, .nfds = nfds } ; 21 | iflen += plen ; 22 | if (iflen > SKABUS_RPC_INTERFACE_MAXLEN) return (errno = ENAMETOOLONG, 0) ; 23 | if (!gensetdyn_new(&a->q, &r->i)) return 0 ; 24 | vv[0].iov_base = pack ; vv[0].iov_len = 2 + TAIN_PACK ; 25 | vv[1].iov_base = (char *)prefix ; vv[1].iov_len = plen ; 26 | vv[2].iov_base = (char *)ifname ; vv[2].iov_len = iflen + 1 ; 27 | for (unsigned int i = 0 ; i < vlen ; i++) vv[3 + i] = v[i] ; 28 | r->a = a ; 29 | if (limit) tain_pack(pack + 1, limit) ; else memset(pack + 1, 0, TAIN_PACK) ; 30 | pack[1 + TAIN_PACK] = (unsigned char)iflen ; 31 | if (!skaclient_putmsgv_and_close(&a->connection, &m, bits, &skabus_rpc_send_cb, r)) 32 | { 33 | int e = errno ; 34 | gensetdyn_delete(&a->q, r->i) ; 35 | errno = e ; 36 | return 0 ; 37 | } 38 | GENSETDYN_P(skabus_rpc_qinfo_t, &a->q, r->i)->status = EINPROGRESS ; 39 | return 1 ; 40 | } 41 | -------------------------------------------------------------------------------- /src/rpc/PROTOCOL: -------------------------------------------------------------------------------- 1 | Protocol between a client - using skabus_rpc_*() - and skabus-rpcd. 2 | 3 | Registering (1st connection) (client -> server) 4 | 5 | 'S' : 1 6 | pmid : 4 7 | idlen : 1 8 | relen : 4 9 | idstr : idlen 10 | '\0' : 1 11 | re : relen 12 | '\0' : 1 13 | 14 | Sending a query (qclient -> server) 15 | 16 | 'Q' : 1 17 | deadline : TAIN_PACK (12) 18 | contains sec(8), nano(4) 19 | iflen : 1 20 | ifname : iflen 21 | '\0' : 1 22 | msg : msglen 23 | A PM is the same as a query, except the ifname starts with a 0xff char 24 | and contains an idstr instead of an ifname. 25 | 26 | Sending a query (server -> rclient) 27 | 28 | 'Q' : 1 29 | ifid : 4 30 | rinfo: SKABUS_RPC_RINFO_PACK 31 | contains serial(8), deadline(12), timestamp(12), uid(sizeof(uid_t)), gid(sizeof(gid_t)), idstr(SKABUS_RPC_IDSTR_SIZE), '\0'(1) 32 | msg : msglen 33 | 34 | Sending a reply (rclient -> server) 35 | 36 | 'R' : 1 37 | serial : 8 38 | result : 1 39 | msg : msglen 40 | 41 | 42 | Sending a reply (server -> qclient) 43 | 44 | 'R' : 1 45 | serial : 8 46 | status : 1. If not '\0', the rest is ignored. 47 | result : 1 48 | msg : msglen 49 | 50 | 51 | Cancelling a query (qclient -> server) 52 | 53 | 'C' : 1 54 | serial : 8 55 | 56 | 57 | Cancelling a query (server -> rclient) 58 | 59 | 'C' : 1 60 | ifid : 4 61 | serial : 8 62 | reason : 1 63 | 64 | 65 | Registering an interface (client -> server) 66 | 67 | 'I' : 1 68 | ifid : 4 69 | iflen : 1 70 | relen : 4 71 | ifname : iflen 72 | '\0' : 1 73 | re : relen 74 | '\0' : 1 75 | 76 | 77 | Unregistering an interface (client -> server) 78 | 79 | 'i' : 1 80 | iflen : 1 81 | ifname : iflen 82 | '\0' : 1 83 | -------------------------------------------------------------------------------- /src/libskabus/skabus_rpc_send_cb.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | #include "skabus-rpc-internal.h" 15 | 16 | static int autocancel_cb (unixmessage const *m, void *p) 17 | { 18 | (void)m ; 19 | (void)p ; 20 | return 1 ; 21 | } 22 | 23 | int skabus_rpc_send_cb (unixmessage const *m, void *p) 24 | { 25 | skabus_rpc_send_result_t *r = p ; 26 | skabus_rpc_qinfo_t *info = GENSETDYN_P(skabus_rpc_qinfo_t, &r->a->q, r->i) ; 27 | if (!m->len) return (errno = EPROTO, 0) ; 28 | if (m->s[0]) 29 | { 30 | r->err = m->s[0] ; 31 | r->u = 0 ; 32 | info->status = EINVAL ; 33 | gensetdyn_delete(&r->a->q, r->i) ; 34 | return 1 ; 35 | } 36 | if (m->len != 9) return (errno = EPROTO, 0) ; 37 | uint64_unpack_big(m->s+1, &info->serial) ; 38 | if (!avltree_insert(&r->a->qmap, r->i)) 39 | { 40 | /* the client can't store the info but the server is performing the query, 41 | so we try to send a stealthy cancel */ 42 | char what = 'C' ; 43 | struct iovec v[2] = { { .iov_base = &what, .iov_len = 1 }, { .iov_base = m->s + 1, .iov_len = 8 } } ; 44 | r->err = errno ; 45 | r->u = 0 ; 46 | info->status = EINVAL ; 47 | gensetdyn_delete(&r->a->q, r->i) ; 48 | if (skaclient_putv(&r->a->connection, v, 2, &autocancel_cb, 0)) 49 | skaclient_flush(&r->a->connection) ; 50 | return 1 ; 51 | } 52 | r->u = info->serial ; 53 | info->status = EBUSY ; 54 | return 1 ; 55 | } 56 | -------------------------------------------------------------------------------- /src/rpc/skabus-rpccctl.h: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #ifndef SKABUS_RPCCCTL_H 4 | #define SKABUS_RPCCCTL_H 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | typedef struct skabus_rpcc_s skabus_rpcc_t, *skabus_rpcc_t_ref ; 12 | struct skabus_rpcc_s 13 | { 14 | textmessage_sender out ; 15 | textmessage_receiver in ; 16 | } ; 17 | #define SKABUS_RPCC_ZERO { .in = TEXTMESSAGE_RECEIVER_ZERO, .out = TEXTMESSAGE_SENDER_ZERO } 18 | 19 | extern int skabus_rpcc_start (skabus_rpcc_t *, char const *, tain const *, tain *) ; 20 | #define skabus_rpcc_start_g(a, name, deadline) skabus_rpcc_start(a, name, (deadline), &STAMP) 21 | 22 | extern void skabus_rpcc_end (skabus_rpcc_t *) ; 23 | 24 | extern int skabus_rpcc_interface_register (skabus_rpcc_t *, char const *, char const *, char const *, tain const *, tain *) ; 25 | #define skabus_rpcc_interface_register_g(a, ifname, ifprog, re, deadline) skabus_rpcc_interface_register(a, ifname, ifprog, re, (deadline), &STAMP) 26 | 27 | extern int skabus_rpcc_interface_unregister (skabus_rpcc_t *, char const *, tain const *, tain *) ; 28 | #define skabus_rpcc_interface_unregister_g(a, ifname, deadline) skabus_rpcc_interface_unregister(a, ifname, (deadline), &STAMP) 29 | 30 | extern int skabus_rpcc_query (skabus_rpcc_t *, stralloc *, char const *, char const *, uint32_t, tain const *, tain *) ; 31 | #define skabus_rpcc_query_g(a, reply, ifname, query, timeout, deadline) skabus_rpcc_query(a, reply, ifname, query, timeout, (deadline), &STAMP) 32 | 33 | extern int skabus_rpcc_quit (skabus_rpcc_t *, tain const *, tain *) ; 34 | #define skabus_rpcc_quit_g(a, deadline) skabus_rpcc_quit(a, (deadline), &STAMP) 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /src/libskabus/deps-lib/skabus: -------------------------------------------------------------------------------- 1 | skabus_pub_end.o 2 | skabus_pub_list.o 3 | skabus_pub_list_async.o 4 | skabus_pub_message_get.o 5 | skabus_pub_message_getnfds.o 6 | skabus_pub_register.o 7 | skabus_pub_register_async.o 8 | skabus_pub_send.o 9 | skabus_pub_send_async.o 10 | skabus_pub_send_cb.o 11 | skabus_pub_sendpm.o 12 | skabus_pub_sendpm_async.o 13 | skabus_pub_sendv.o 14 | skabus_pub_sendv_async.o 15 | skabus_pub_sendvpm.o 16 | skabus_pub_sendvpm_async.o 17 | skabus_pub_start.o 18 | skabus_pub_start_async.o 19 | skabus_pub_subunsub.o 20 | skabus_pub_subunsub_async.o 21 | skabus_pub_update.o 22 | skabus_rpc_cancel.o 23 | skabus_rpc_cancel_async.o 24 | skabus_rpc_end.o 25 | skabus_rpc_get.o 26 | skabus_rpc_idstr.o 27 | skabus_rpc_idstr_async.o 28 | skabus_rpc_interface_register.o 29 | skabus_rpc_interface_register_async.o 30 | skabus_rpc_interface_register_cb.o 31 | skabus_rpc_interface_unregister.o 32 | skabus_rpc_interface_unregister_async.o 33 | skabus_rpc_interface_zero.o 34 | skabus_rpc_qinfo_zero.o 35 | skabus_rpc_qlist.o 36 | skabus_rpc_qlist_ack.o 37 | skabus_rpc_r_notimpl.o 38 | skabus_rpc_rcancel_ignore.o 39 | skabus_rpc_release.o 40 | skabus_rpc_reply.o 41 | skabus_rpc_reply_async.o 42 | skabus_rpc_replyv.o 43 | skabus_rpc_replyv_async.o 44 | skabus_rpc_rinfo_pack.o 45 | skabus_rpc_rinfo_unpack.o 46 | skabus_rpc_rinfo_zero.o 47 | skabus_rpc_send.o 48 | skabus_rpc_send_async.o 49 | skabus_rpc_send_cb.o 50 | skabus_rpc_sendpm.o 51 | skabus_rpc_sendpm_async.o 52 | skabus_rpc_sendq.o 53 | skabus_rpc_sendq_async.o 54 | skabus_rpc_sendv.o 55 | skabus_rpc_sendv_async.o 56 | skabus_rpc_sendvpm.o 57 | skabus_rpc_sendvpm_async.o 58 | skabus_rpc_sendvq.o 59 | skabus_rpc_sendvq_async.o 60 | skabus_rpc_start.o 61 | skabus_rpc_start_async.o 62 | skabus_rpc_update.o 63 | skabus_rpc_zero.o 64 | -lskarnet 65 | -------------------------------------------------------------------------------- /src/libskabus/skabus_pub_update.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | static int handler (unixmessage const *m, void *x) 18 | { 19 | skabus_pub_t *a = (skabus_pub_t *)x ; 20 | size_t n = genalloc_len(skabus_pub_cltinfo_t, &a->info) ; 21 | char const *s = m->s ; 22 | size_t len = m->len ; 23 | skabus_pub_cltinfo_t *p ; 24 | uint8_t idlen ; 25 | if (len < 11 + TAIN_PACK || !m->nfds) goto errproto ; 26 | if (!genalloc_readyplus(skabus_pub_cltinfo_t, &a->info, 1)) goto err ; 27 | p = genalloc_s(skabus_pub_cltinfo_t, &a->info) + n ; 28 | p->fd = m->fds[0] ; 29 | p->nfds = m->nfds - 1 ; 30 | if (p->nfds > 1) 31 | { 32 | p->fds = alloc(p->nfds * sizeof(int)) ; 33 | if (!p->fds) goto err ; 34 | for (size_t i = 0 ; i < p->nfds ; i++) p->fds[i] = m->fds[1 + i] ; 35 | } 36 | else p->fds = 0 ; 37 | uint64_unpack_big(s, &p->msginfo.serial) ; s += 8 ; len -= 8 ; 38 | tain_unpack(s, &p->msginfo.timestamp) ; s += TAIN_PACK ; len -= TAIN_PACK ; 39 | p->msginfo.flags = *s++ ; len-- ; 40 | idlen = *s++ ; len-- ; 41 | if (len != (size_t)idlen + 1 || s[idlen] || idlen > SKABUS_PUB_IDSTR_SIZE) goto errprotof ; 42 | memcpy(p->msginfo.sender, s, len) ; 43 | genalloc_setlen(skabus_pub_cltinfo_t, &a->info, n+1) ; 44 | return 1 ; 45 | 46 | errprotof: 47 | alloc_free(p->fds) ; 48 | errproto: 49 | errno = EPROTO ; 50 | err: 51 | unixmessage_drop(m) ; 52 | return 0 ; 53 | } 54 | 55 | int skabus_pub_update (skabus_pub_t *a) 56 | { 57 | return skaclient_update(&a->connection, &handler, a) ; 58 | } 59 | -------------------------------------------------------------------------------- /doc/skabus-dyntee-client.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | skabus: the skabus-dyntee-client program 7 | 8 | 9 | 10 | 11 | 12 | 13 |

14 | skabus
15 | Software
16 | skarnet.org 17 |

18 | 19 |

The skabus-dyntee-client program

20 | 21 |

22 | skabus-dyntee-client is a client for the 23 | skabus-dyntee server. 24 | It connects to a Unix domain socket where a 25 | skabus-dyntee instance is listening, 26 | then executes into a program with the data stream from skabus-dyntee 27 | on its standard input. 28 |

29 | 30 |

Interface

31 | 32 |
33 |      skabus-dyntee-client path prog...
34 | 
35 | 36 |
    37 |
  • skabus-dyntee-client connects to the Unix domain socket at path. 38 | It assumes the other end of the socket is a skabus-dyntee 39 | (or skabus-dynteed, which is the same) instance.
  • 40 |
  • It executes into the prog... command line with the 41 | socket as prog's standard input.
  • 42 |
43 | 44 |

Notes

45 | 46 |
    47 |
  • It is possible for prog to immediately get EOF on its 48 | standard input. This likely means that the server has denied the 49 | connection (skabus-dyntee-client did not run with an authorized uid 50 | or gid). But it could also mean that the stream ended right after 51 | the client connected.
  • 52 |
  • The socket is shut down for writing, so prog can 53 | only read on its stdin; attempts to write will always fail.
  • 54 |
55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /tools/gen-dotpc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | isunique () { 4 | x=$1 5 | set -- $2 6 | while test "$#" -gt 0 ; do 7 | if test "$x" = "$1" ; then 8 | return 1 9 | fi 10 | shift 11 | done 12 | return 0 13 | } 14 | 15 | uniqit () { 16 | res= 17 | while test "$#" -gt 0 ; do 18 | if isunique "$1" "$res" ; then 19 | res="${res}${res:+ }${1}" 20 | fi 21 | shift 22 | done 23 | printf %s\\n "$res" 24 | } 25 | 26 | filterout () { 27 | res= 28 | filter="$1" 29 | shift 30 | while test "$#" -gt 0 ; do 31 | if isunique "$1" "$filter" ; then 32 | res="${res}${res:+ }${1}" 33 | fi 34 | shift 35 | done 36 | printf %s\\n "$res" 37 | } 38 | 39 | print_requires () { 40 | line= 41 | oldifs="$IFS" 42 | while IFS=" " read condvar usedinlibs pkg ver libs ; do 43 | IFS="$oldifs" 44 | for h ; do 45 | i=lib${h##-l} 46 | for j in $libs ; do 47 | if test "$i" = "$j" ; then 48 | line="${line}${line:+, }${i} >= ${ver}" 49 | fi 50 | done 51 | done 52 | done < package/deps-build 53 | IFS="$oldifs" 54 | echo "Requires: $line" 55 | } 56 | 57 | . package/info 58 | 59 | ilist= 60 | dlist= 61 | slist= 62 | 63 | if test "${includedir}" != /usr/include ; then 64 | ilist="-I${includedir}" 65 | fi 66 | if test -n "${extra_includedirs}" ; then 67 | ilist="${ilist}${ilist:+ }${extra_includedirs}" 68 | fi 69 | ilist=`uniqit ${ilist}` 70 | 71 | if test "${dynlibdir}" != /usr/lib && test "${dynlibdir}" != /lib ; then 72 | dlist="-L${dynlibdir}" 73 | fi 74 | 75 | if test "${libdir}" != /usr/lib && test "${libdir}" != /lib ; then 76 | slist="-L${libdir}" 77 | fi 78 | if test -n "${extra_libdirs}" ; then 79 | slist="${slist}${slist:+ }${extra_libdirs}" 80 | fi 81 | slist="$(filterout "${dlist}" $(uniqit ${slist}))" 82 | 83 | echo "prefix=${prefix}" 84 | echo "includedir=${includedir}" 85 | echo "libdir=${libdir}" 86 | echo "dynlibdir=${dynlibdir}" 87 | echo 88 | echo "Name: lib${library}" 89 | echo "Version: ${version}" 90 | echo "Description: ${description:-The ${library} library.}" 91 | echo "URL: ${url:-https://skarnet.org/software/${package}/}" 92 | if test -n "${extra_libs}" ; then 93 | print_requires ${extra_libs} 94 | fi 95 | if test -n "$ilist" ; then 96 | echo "Cflags: ${ilist}" 97 | fi 98 | echo "Libs: ${dlist}${dlist:+ }-l${library}${ldlibs:+ }${ldlibs}" 99 | if test -n "${extra_libs}" ; then 100 | echo "Libs.private: ${slist}${slist:+ }${extra_libs}" 101 | fi 102 | -------------------------------------------------------------------------------- /tools/gen-deps.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | . package/info 4 | 5 | echo '#' 6 | echo '# This file has been generated by tools/gen-deps.sh' 7 | echo '#' 8 | echo 9 | 10 | internal_libs= 11 | 12 | for dir in src/include/${package} src/* ; do 13 | for file in $(ls -1 $dir | grep -- \\.h$) ; do 14 | { 15 | grep -F -- "#include <${package}/" < ${dir}/$file | cut -d'<' -f2 | cut -d'>' -f1 ; 16 | grep -- '#include ".*\.h"' < ${dir}/$file | cut -d'"' -f2 17 | } | sort -u | { 18 | deps= 19 | while read dep ; do 20 | if echo $dep | grep -q "^${package}/" ; then 21 | deps="$deps src/include/$dep" 22 | elif test -f "${dir}/$dep" ; then 23 | deps="$deps ${dir}/$dep" 24 | else 25 | deps="$deps src/include-local/$dep" 26 | fi 27 | done 28 | if test -n "$deps" ; then 29 | echo "${dir}/${file}:${deps}" 30 | fi 31 | } 32 | done 33 | done 34 | 35 | for dir in src/* ; do 36 | for file in $(ls -1 $dir | grep -- \\.c$) ; do 37 | { 38 | grep -F -- "#include <${package}/" < ${dir}/$file | cut -d'<' -f2 | cut -d'>' -f1 ; 39 | grep -- '#include ".*\.h"' < ${dir}/$file | cut -d'"' -f2 40 | } | sort -u | { 41 | deps=" ${dir}/$file" 42 | while read dep ; do 43 | if echo $dep | grep -q "^${package}/" ; then 44 | deps="$deps src/include/$dep" 45 | elif test -f "${dir}/$dep" ; then 46 | deps="$deps ${dir}/$dep" 47 | else 48 | deps="$deps src/include-local/$dep" 49 | fi 50 | done 51 | o=$(echo $file | sed s/\\.c$/.o/) 52 | lo=$(echo $file | sed s/\\.c$/.lo/) 53 | echo "${dir}/${o} ${dir}/${lo}:${deps}" 54 | } 55 | done 56 | done 57 | echo 58 | 59 | for dir in $(ls -1 src | grep -v ^include) ; do 60 | for file in $(ls -1 src/$dir/deps-lib) ; do 61 | deps= 62 | libs= 63 | while read dep ; do 64 | if echo $dep | grep -q -e '^\${LIB' -e '^-l' -e '^\${.*_LIB}' ; then 65 | libs="$libs $dep" 66 | else 67 | deps="$deps src/$dir/$dep" 68 | fi 69 | done < src/$dir/deps-lib/$file 70 | echo 'ifeq ($(strip $(STATIC_LIBS_ARE_PIC)),)' 71 | echo "lib${file}.a.xyzzy:${deps}" 72 | echo else 73 | echo "lib${file}.a.xyzzy:$(echo ${deps} | sed 's/\.o/.lo/g')" 74 | echo endif 75 | if grep -qE "^LIB_DEFS [+:]= .*=$file" package/targets.mak ; then 76 | echo "lib${file}.pc: EXTRA_LIBS :=${libs}" 77 | echo "lib${file}.so.xyzzy: EXTRA_LIBS :=$libs" 78 | echo "lib${file}.so.xyzzy:$(echo ${deps} | sed 's/\.o/.lo/g')" 79 | echo "lib${file}.dylib.xyzzy: EXTRA_LIBS :=$libs" 80 | echo "lib${file}.dylib.xyzzy:$(echo ${deps} | sed 's/\.o/.lo/g')" 81 | else 82 | internal_libs="$internal_libs lib${file}.a.xyzzy" 83 | fi 84 | done 85 | 86 | for file in $(ls -1 src/$dir/deps-exe) ; do 87 | deps= 88 | libs= 89 | while read dep ; do 90 | if echo $dep | grep -q \\.o$ ; then 91 | dep="src/$dir/$dep" 92 | fi 93 | if echo $dep | grep -qx '\${.*_LIB}' ; then 94 | libs="$libs $dep" 95 | else 96 | deps="$deps $dep" 97 | fi 98 | done < src/$dir/deps-exe/$file 99 | echo "$file: EXTRA_LIBS :=$libs" 100 | echo "$file: src/$dir/$file.o$deps" 101 | done 102 | done 103 | echo "INTERNAL_LIBS :=$internal_libs" 104 | -------------------------------------------------------------------------------- /src/rpc/skabus_rpcd_interface.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include "skabus-rpcd.h" 15 | 16 | static inline void interface_free (interface_t *p) 17 | { 18 | p->name[0] = p->name[1] = 0 ; 19 | gensetdyn_free(&p->queries) ; 20 | } 21 | 22 | static void *if_dtok (uint32_t d, void *x) 23 | { 24 | (void)x ; 25 | return INTERFACE(d)->name ; 26 | } 27 | 28 | static int if_cmp (void const *a, void const *b, void *x) 29 | { 30 | (void)x ; 31 | return strncmp((char const *)a, (char const *)b, SKABUS_RPC_INTERFACE_MAXLEN) ; 32 | } 33 | 34 | gensetdyn interfaces = GENSETDYN_ZERO ; 35 | static avltree ifdict = AVLTREE_INIT(2, 3, 8, &if_dtok, &if_cmp, 0) ; 36 | 37 | static inline void interface_delete (uint32_t i) 38 | { 39 | interface_t *y = INTERFACE(i) ; 40 | if (!avltree_delete(&ifdict, y->name)) 41 | strerr_diefu1sys(111, "avltree_delete in interface_delete") ; 42 | interface_free(y) ; 43 | if (!gensetdyn_delete(&interfaces, i)) 44 | strerr_diefu1sys(111, "gensetdyn_delete in interface_delete") ; 45 | } 46 | 47 | static int query_fail_iter (void *s, void *reason) 48 | { 49 | query_fail(*(uint32_t *)s, *(unsigned char *)reason) ; 50 | return 1 ; 51 | } 52 | 53 | static inline void client_interfacemove (client_t *c, uint32_t from, uint32_t to) 54 | { 55 | uint32_t *ifaces = genalloc_s(uint32_t, &c->interfaces) ; 56 | INTERFACE(ifaces[from])->index = to ; 57 | ifaces[to] = ifaces[from] ; 58 | } 59 | 60 | void interface_remove (uint32_t i) 61 | { 62 | interface_t *y = INTERFACE(i) ; 63 | client_t *c = CLIENT(y->client) ; 64 | uint32_t n = gensetdyn_n(&y->queries) ; 65 | unsigned char reason = ECONNRESET ; 66 | gensetdyn_iter(&y->queries, &query_fail_iter, &reason) ; 67 | n = genalloc_len(uint32_t, &c->interfaces) ; 68 | client_interfacemove(c, n-1, y->index) ; 69 | genalloc_setlen(uint32_t, &c->interfaces, n-1) ; 70 | interface_delete(i) ; 71 | } 72 | 73 | int interface_lookup_by_name (char const *s, uint32_t *d) 74 | { 75 | return avltree_search(&ifdict, s, d) ; 76 | } 77 | 78 | int interface_add (uint32_t *d, char const *name, size_t namelen, uint32_t client, char const *re, uint32_t id) 79 | { 80 | uint32_t yy ; 81 | int e ; 82 | genalloc *g = &CLIENT(client)->interfaces ; 83 | if (!genalloc_readyplus(uint32_t, g, 1)) return 0 ; 84 | if (!gensetdyn_new(&interfaces, &yy)) return 0 ; 85 | { 86 | interface_t *y = INTERFACE(yy) ; 87 | int r = skalibs_regcomp(&y->re, re, REG_EXTENDED | REG_NOSUB) ; 88 | if (r) 89 | { 90 | e = r == REG_ESPACE ? ENOMEM : EINVAL ; 91 | goto err ; 92 | } 93 | memcpy(y->name, name, namelen) ; y->name[namelen] = 0 ; 94 | y->id = id ; 95 | y->client = client ; 96 | y->index = genalloc_len(uint32_t, g) - 1 ; 97 | y->queries = gensetdyn_zero ; 98 | if (!avltree_insert(&ifdict, yy)) 99 | { 100 | e = errno ; 101 | regfree(&y->re) ; 102 | goto err ; 103 | } 104 | } 105 | genalloc_append(uint32_t, g, &yy) ; 106 | *d = yy ; 107 | return 1 ; 108 | 109 | err: 110 | if (!gensetdyn_delete(&interfaces, yy)) 111 | strerr_diefu1sys(111, "gensetdyn_delete in interface_add") ; 112 | errno = e ; 113 | return 0 ; 114 | } 115 | -------------------------------------------------------------------------------- /src/libskabus/skabus_rpc_update.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include 19 | 20 | typedef int localhandler_func (skabus_rpc_t *, unixmessage *) ; 21 | typedef localhandler_func *localhandler_func_ref ; 22 | 23 | static int skabus_rpc_serve (skabus_rpc_t *a, unixmessage *m) 24 | { 25 | skabus_rpc_rinfo_t rinfo ; 26 | uint32_t ifid ; 27 | skabus_rpc_interface_t *p ; 28 | if (m->len < 4 + SKABUS_RPC_RINFO_PACK) return (errno = EPROTO, 0) ; 29 | uint32_unpack_big(m->s, &ifid) ; m->s += 4 ; m->len -= 4 ; 30 | skabus_rpc_rinfo_unpack(m->s, &rinfo) ; 31 | m->s += SKABUS_RPC_RINFO_PACK ; m->len -= SKABUS_RPC_RINFO_PACK ; 32 | p = GENSETDYN_P(skabus_rpc_interface_t, &a->r, ifid) ; 33 | if (!p) return (errno = ESRCH, 0) ; 34 | return (*p->f)(a, &rinfo, m, p->data) ; 35 | } 36 | 37 | static int skabus_rpc_cancelr (skabus_rpc_t *a, unixmessage *m) 38 | { 39 | uint64_t serial ; 40 | uint32_t ifid ; 41 | skabus_rpc_interface_t *p ; 42 | if (m->len != 13 || m->nfds) return (errno = EPROTO, 0) ; 43 | uint32_unpack_big(m->s, &ifid) ; 44 | uint64_unpack_big(m->s+4, &serial) ; 45 | p = GENSETDYN_P(skabus_rpc_interface_t, &a->r, ifid) ; 46 | if (!p) return (errno = ESRCH, 0) ; 47 | return (*p->cancelf)(serial, m->s[12], p->data) ; 48 | } 49 | 50 | static int skabus_rpc_handle_reply (skabus_rpc_t *a, unixmessage *m) 51 | { 52 | skabus_rpc_qinfo_t *p ; 53 | uint64_t serial ; 54 | uint32_t id ; 55 | if (m->len < 9) return (errno = EPROTO, 0) ; 56 | uint64_unpack_big(m->s, &serial) ; 57 | if (!avltree_search(&a->qmap, &serial, &id)) 58 | { 59 | unixmessage_drop(m) ; 60 | return 1 ; 61 | } 62 | p = GENSETDYN_P(skabus_rpc_qinfo_t, &a->q, id) ; 63 | if (!genalloc_readyplus(uint64_t, &a->qlist, 1)) return 0 ; 64 | if (!m->s[8]) 65 | { 66 | if (m->len < 10) return (errno = EPROTO, 0) ; 67 | p->message.s = alloc(m->len - 10) ; 68 | if (!p->message.s) return 0 ; 69 | p->message.fds = (int *)alloc(m->nfds * sizeof(int)) ; 70 | if (!p->message.fds) 71 | { 72 | alloc_free(p->message.s) ; 73 | p->message.s = 0 ; 74 | return 0 ; 75 | } 76 | p->result = m->s[9] ; 77 | p->message.len = m->len - 10 ; 78 | p->message.nfds = m->nfds ; 79 | memcpy(p->message.s, m->s + 10, p->message.len) ; 80 | memcpy(p->message.fds, m->fds, p->message.nfds * sizeof(int)) ; 81 | } 82 | p->status = m->s[8] ; 83 | genalloc_append(uint64_t, &a->qlist, &serial) ; 84 | return 1 ; 85 | } 86 | 87 | static int skabus_rpc_error (skabus_rpc_t *a, unixmessage *m) 88 | { 89 | (void)a ; 90 | (void)m ; 91 | return (errno = EPROTO, 0) ; 92 | } 93 | 94 | static int handler (unixmessage const *m, void *x) 95 | { 96 | skabus_rpc_t *a = x ; 97 | unixmessage mm = { .s = m->s + 1, .len = m->len - 1, .fds = m->fds, .nfds = m->nfds } ; 98 | static localhandler_func_ref const f[4] = 99 | { 100 | &skabus_rpc_serve, 101 | &skabus_rpc_handle_reply, 102 | &skabus_rpc_cancelr, 103 | &skabus_rpc_error 104 | } ; 105 | if (!m->len) 106 | { 107 | unixmessage_drop(m) ; 108 | return (errno = EPROTO, 0) ; 109 | } 110 | if (!(*f[byte_chr("QRC", 3, m->s[0])])(a, &mm)) 111 | { 112 | unixmessage_drop(m) ; 113 | return 0 ; 114 | } 115 | return 1 ; 116 | } 117 | 118 | int skabus_rpc_update (skabus_rpc_t *a) 119 | { 120 | return skaclient_update(&a->connection, &handler, a) ; 121 | } 122 | -------------------------------------------------------------------------------- /src/rpc/skabus-rpc-client.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | #include 11 | #include "skabus-rpcc.h" 12 | 13 | #define USAGE "skabus-rpc-client [ -v verbosity ] [ -d | -D ] [ -1 ] [ -c maxconn ] [ -b backlog ] [ -t timeout ] [ -T lameducktimeout ] [ -C pmprog:sep:flags ] [ -y ifname:ifprog:sep:flags ... ] rpccpath rpcdpath clientname" 14 | #define dieusage() strerr_dieusage(100, USAGE) 15 | 16 | int main (int argc, char const *const *argv) 17 | { 18 | unsigned int verbosity = 1 ; 19 | int flag1 = 0 ; 20 | int flagreuse = 1 ; 21 | unsigned int maxconn = 0 ; 22 | unsigned int backlog = (unsigned int)-1 ; 23 | unsigned int timeout = 0 ; 24 | unsigned int ltimeout = 0 ; 25 | PROG = "skabus-rpc-client" ; 26 | unsigned int ifn = 1 ; 27 | char const *interfaces[SKABUS_RPCC_INTERFACES_MAX] = { 0 } ; 28 | { 29 | subgetopt l = SUBGETOPT_ZERO ; 30 | for (;;) 31 | { 32 | register int opt = subgetopt_r(argc, argv, "Dd1v:c:b:t:T:C:y:", &l) ; 33 | if (opt == -1) break ; 34 | switch (opt) 35 | { 36 | case 'D' : flagreuse = 0 ; break ; 37 | case 'd' : flagreuse = 1 ; break ; 38 | case '1' : flag1 = 1 ; break ; 39 | case 'v' : if (!uint0_scan(l.arg, &verbosity)) dieusage() ; break ; 40 | case 'c' : if (!uint0_scan(l.arg, &maxconn)) dieusage() ; if (!maxconn) maxconn = 1 ; break ; 41 | case 'b' : if (!uint0_scan(l.arg, &backlog)) dieusage() ; break ; 42 | case 't' : if (!uint0_scan(l.arg, &timeout)) dieusage() ; break ; 43 | case 'T' : if (!uint0_scan(l.arg, <imeout)) dieusage() ; break ; 44 | case 'C' : interfaces[0] = l.arg ; break ; 45 | case 'y' : 46 | { 47 | if (ifn >= SKABUS_RPCC_INTERFACES_MAX) dietoomanyinterfaces() ; 48 | if (!l.arg[0]) dieemptyifname() ; 49 | interfaces[ifn++] = l.arg ; 50 | break ; 51 | } 52 | default : dieusage() ; 53 | } 54 | } 55 | argc -= l.ind ; argv += l.ind ; 56 | if (argc < 3) dieusage() ; 57 | } 58 | 59 | { 60 | unsigned int m = 0, pos = 0 ; 61 | char fmt[UINT_FMT * 5] ; 62 | char const *newargv[22 + 2 * ifn] ; 63 | newargv[m++] = S6_EXTBINPREFIX "s6-ipcserver-socketbinder" ; 64 | if (!flagreuse) newargv[m++] = "-D" ; 65 | newargv[m++] = "-a" ; 66 | newargv[m++] = "0700" ; 67 | if (backlog != (unsigned int)-1) 68 | { 69 | newargv[m++] = "-b" ; 70 | newargv[m++] = fmt + pos ; 71 | pos += uint_fmt(fmt + pos, backlog) ; 72 | fmt[pos++] = 0 ; 73 | } 74 | newargv[m++] = "--" ; 75 | newargv[m++] = *argv++ ; 76 | newargv[m++] = SKABUS_BINPREFIX "skabus-rpcc" ; 77 | if (verbosity != 1) 78 | { 79 | newargv[m++] = "-v" ; 80 | newargv[m++] = fmt + pos ; 81 | pos += uint_fmt(fmt + pos, verbosity) ; 82 | fmt[pos++] = 0 ; 83 | } 84 | if (flag1) newargv[m++] = "-1" ; 85 | if (maxconn) 86 | { 87 | newargv[m++] = "-c" ; 88 | newargv[m++] = fmt + pos ; 89 | pos += uint_fmt(fmt + pos, maxconn) ; 90 | fmt[pos++] = 0 ; 91 | } 92 | if (timeout) 93 | { 94 | newargv[m++] = "-t" ; 95 | newargv[m++] = fmt + pos ; 96 | pos += uint_fmt(fmt + pos, timeout) ; 97 | fmt[pos++] = 0 ; 98 | } 99 | if (ltimeout) 100 | { 101 | newargv[m++] = "-T" ; 102 | newargv[m++] = fmt + pos ; 103 | pos += uint_fmt(fmt + pos, timeout) ; 104 | fmt[pos++] = 0 ; 105 | } 106 | if (interfaces[0]) 107 | { 108 | newargv[m++] = "-X" ; 109 | newargv[m++] = interfaces[0] ; 110 | } 111 | for (unsigned int i = 1 ; i < ifn ; i++) 112 | { 113 | newargv[m++] = "-y" ; 114 | newargv[m++] = interfaces[i] ; 115 | } 116 | newargv[m++] = "--" ; 117 | newargv[m++] = *argv++ ; 118 | newargv[m++] = *argv++ ; 119 | newargv[m++] = 0 ; 120 | xexec(newargv) ; 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /src/rpc/skabus_rpccctl.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include 18 | #include "skabus-rpccctl.h" 19 | 20 | int skabus_rpcc_start (skabus_rpcc_t *a, char const *path, tain const *deadline, tain *stamp) 21 | { 22 | int fd = ipc_stream_nb() ; 23 | if (fd < 0) return 0 ; 24 | if (!ipc_timed_connect(fd, path, deadline, stamp)) 25 | { 26 | fd_close(fd) ; 27 | return 0 ; 28 | } 29 | textmessage_sender_init(&a->out, fd) ; 30 | textmessage_receiver_init(&a->in, fd) ; 31 | return 1 ; 32 | } 33 | 34 | void skabus_rpcc_end (skabus_rpcc_t *a) 35 | { 36 | fd_close(textmessage_sender_fd(&a->out)) ; 37 | textmessage_sender_free(&a->out) ; 38 | textmessage_receiver_free(&a->in) ; 39 | } 40 | 41 | int skabus_rpcc_interface_register (skabus_rpcc_t *a, char const *ifname, char const *ifprog, char const *re, tain const *deadline, tain *stamp) 42 | { 43 | size_t ifnamelen, ifproglen, relen ; 44 | char *ifprogfn = realpath(ifprog, 0) ; 45 | if (!ifprogfn) return 0 ; 46 | ifnamelen = strlen(ifname) ; 47 | ifproglen = strlen(ifprogfn) ; 48 | relen = strlen(re) ; 49 | if (ifnamelen > SKABUS_RPC_INTERFACE_MAXLEN || ifproglen > PATH_MAX || relen > SKABUS_RPC_RE_MAXLEN) goto terr ; 50 | { 51 | char buf[9] ; 52 | struct iovec v[5] = 53 | { 54 | { .iov_base = "I", .iov_len = 1 }, 55 | { .iov_base = buf, .iov_len = 9 }, 56 | { .iov_base = ifname, .iov_len = ifnamelen + 1 }, 57 | { .iov_base = ifprogfn, .iov_len = ifproglen + 1 }, 58 | { .iov_base = re, .iov_len = relen + 1 } 59 | } ; 60 | buf[0] = (unsigned char)ifnamelen ; 61 | uint32_pack_big(buf + 1, ifproglen) ; 62 | uint32_pack_big(buf + 5, relen) ; 63 | if (!textmessage_timed_commandv(&a->out, v, 5, deadline, stamp)) goto err ; 64 | } 65 | free(ifprogfn) ; 66 | return 1 ; 67 | 68 | terr: 69 | errno = ENAMETOOLONG ; 70 | err: 71 | free(ifprogfn) ; 72 | return 0 ; 73 | } 74 | 75 | int skabus_rpcc_interface_unregister (skabus_rpcc_t *a, char const *ifname, tain const *deadline, tain *stamp) 76 | { 77 | size_t ifnamelen = strlen(ifname) ; 78 | if (ifnamelen > SKABUS_RPC_INTERFACE_MAXLEN) return (errno = ENAMETOOLONG, 0) ; 79 | { 80 | unsigned char c = ifnamelen ; 81 | struct iovec v[3] = 82 | { 83 | { .iov_base = "i", .iov_len = 1 }, 84 | { .iov_base = &c, .iov_len = 1 }, 85 | { .iov_base = ifname, .iov_len = ifnamelen + 1 } 86 | } ; 87 | if (!textmessage_timed_commandv(&a->out, v, 3, deadline, stamp)) return 0 ; 88 | } 89 | return 1 ; 90 | } 91 | 92 | int skabus_rpcc_query (skabus_rpcc_t *a, stralloc *reply, char const *ifname, char const *query, uint32_t timeout, tain const *deadline, tain *stamp) 93 | { 94 | size_t ifnamelen = strlen(ifname) ; 95 | size_t querylen = strlen(query) ; 96 | if (ifnamelen > SKABUS_RPC_INTERFACE_MAXLEN || querylen > UINT32_MAX) return (errno = ENAMETOOLONG, 0) ; 97 | { 98 | char buf[9] ; 99 | struct iovec v[4] = 100 | { 101 | { .iov_base = "Q", .iov_len = 1 }, 102 | { .iov_base = buf, .iov_len = 59 }, 103 | { .iov_base = ifname, .iov_len = ifnamelen + 1 }, 104 | { .iov_base = query, .iov_len = querylen + 1 }, 105 | } ; 106 | buf[0] = ifnamelen ; 107 | uint32_pack_big(buf + 1, querylen) ; 108 | uint32_pack_big(buf + 5, timeout) ; 109 | if (!textmessage_timed_sendv(&a->out, v, 4)) return 0 ; 110 | } 111 | { 112 | struct iovec v ; 113 | if (!textmessage_timed_receive(&a->in, &v, deadline, stamp)) return 0 ; 114 | if (!v.iov_len) return (errno = EPROTO, 0) ; 115 | if (*(unsigned char *)v.iov_base) return (errno = *(unsigned char)v.iov_base, 0) ; 116 | if (!stralloc_catb(reply, (char *)v.iov_base + 1, v.iov_len - 1)) return 0 ; 117 | } 118 | return 1 ; 119 | } 120 | 121 | int skabus_rpcc_quit (skabus_rpcc_t *a, tain const *deadline, tain *stamp) 122 | { 123 | return textmessage_timed_command(&a->out, ".", 1, deadline, stamp) ; 124 | } 125 | -------------------------------------------------------------------------------- /src/rpc/skabus-rpcd.h: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #ifndef SKABUS_RPCD_H 4 | #define SKABUS_RPCD_H 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #define X() strerr_dief1x(101, "unexpected error - please submit a bug-report.") ; 20 | 21 | 22 | /* 23 | query: queries accepted from client, sent to interface 24 | The list is stored in a gensetdyn. 25 | Looked up by serial for answers or cancels. 26 | */ 27 | 28 | typedef struct query_s query_t, *query_t_ref ; 29 | struct query_s 30 | { 31 | uint64_t serial ; 32 | tain deadline ; 33 | uint32_t client ; 34 | uint32_t clientindex ; 35 | uint32_t interface ; 36 | uint32_t interfaceindex ; 37 | } ; 38 | 39 | #define QUERY_ZERO \ 40 | { \ 41 | .serial = 0, \ 42 | .deadline = TAIN_ZERO, \ 43 | .client = 0, \ 44 | .clientindex = 0, \ 45 | .interface = 0, \ 46 | .interfaceindex = 0 \ 47 | } 48 | 49 | 50 | /* 51 | interfaces: registered R interfaces. 52 | The list is stored in a gensetdyn. 53 | Looked up by name. 54 | */ 55 | 56 | typedef struct interface_s interface_t, *interface_t_ref ; 57 | struct interface_s 58 | { 59 | char name[SKABUS_RPC_INTERFACE_MAXLEN+1] ; 60 | regex_t re ; /* clients who can access that interface */ 61 | uint32_t id ; 62 | uint32_t client ; 63 | uint32_t index ; /* in the owner's interfaces list */ 64 | gensetdyn queries ; /* uint32_t */ 65 | } ; 66 | #define INTERFACE_ZERO { .name = "", .id = 0, .client = 0, .index = 0, .queries = GENSETDYN_ZERO } 67 | 68 | 69 | /* 70 | client: client connections. 71 | The list is stored in a genset. 72 | List browsed at every iopause iteration, so needs a next field. 73 | */ 74 | 75 | typedef struct client_s client_t, *client_t_ref ; 76 | struct client_s 77 | { 78 | uint32_t next ; 79 | uid_t uid ; 80 | gid_t gid ; 81 | tain deadline ; 82 | genalloc interfaces ; /* uint32_t */ 83 | gensetdyn queries ; /* uint32_t */ 84 | unixconnection sync ; 85 | unixconnection async ; 86 | uint32_t xindex[2] ; 87 | regex_t idstr_re ; 88 | regex_t interfaces_re ; 89 | } ; 90 | #define CLIENT_ZERO \ 91 | { \ 92 | .next = 0, \ 93 | .uid = (uid_t)-1, \ 94 | .gid = (gid_t)-1, \ 95 | .deadline = TAIN_ZERO, \ 96 | .interfaces = GENALLOC_ZERO, \ 97 | .queries = GENALLOC_ZERO, \ 98 | .sync = UNIXCONNECTION_ZERO, \ 99 | .async = UNIXCONNECTION_ZERO, \ 100 | .xindex = { 0, 0 }, \ 101 | } 102 | 103 | extern gensetdyn queries ; 104 | #define QUERY(i) GENSETDYN_P(query_t, &queries, (i)) 105 | #define queries_pending() gensetdyn_n(&queries) 106 | 107 | extern gensetdyn interfaces ; 108 | #define INTERFACE(i) GENSETDYN_P(interface_t, &interfaces, (i)) 109 | 110 | extern genset *clients ; 111 | extern unsigned int sentinel ; 112 | #define CLIENT(i) genset_p(client_t, clients, (i)) 113 | #define numconn (genset_n(clients) - 1) 114 | 115 | extern void query_remove (uint32_t) ; 116 | extern void query_fail (uint32_t, unsigned char) ; 117 | extern int query_cancel (uint32_t, unsigned char) ; 118 | extern int query_cancelremove (uint32_t, unsigned char) ; 119 | extern int query_lookup_by_serial (uint64_t, uint32_t *) ; 120 | extern int query_lookup_by_mindeadline (uint32_t *) ; 121 | extern void query_get_mindeadline (tain *) ; 122 | extern int query_add (uint32_t *, tain const *, uint32_t, uint32_t) ; 123 | extern int query_send (uint32_t, unixmessage const *) ; 124 | extern int query_sendpm (uint32_t, unixmessage const *) ; 125 | extern void query_reply (uint32_t, char, unixmessage const *) ; 126 | 127 | extern void interface_remove (uint32_t) ; 128 | extern int interface_lookup_by_name (char const *, uint32_t *) ; 129 | extern int interface_add (uint32_t *, char const *, size_t, uint32_t, char const *, uint32_t) ; 130 | 131 | #define client_isregistered(cc) genalloc_len(uint32_t, &CLIENT(cc)->interfaces) 132 | #define client_idstr(c) (INTERFACE(genalloc_s(uint32_t, &(c)->interfaces)[0])->name + 1) 133 | extern void client_remove (uint32_t, uint32_t) ; 134 | extern void client_add (uint32_t *, regex_t const *, regex_t const *, uid_t, gid_t, int, uint32_t) ; 135 | extern void client_nextdeadline (uint32_t, tain *) ; 136 | extern void client_setdeadline (client_t *) ; 137 | extern int client_prepare_iopause (uint32_t, tain *, iopause_fd *, uint32_t *, int) ; 138 | extern int client_flush (uint32_t, iopause_fd const *) ; 139 | extern int client_read (uint32_t, iopause_fd const *) ; 140 | 141 | extern int parse_protocol_sync (unixmessage const *, void *) ; 142 | extern int parse_protocol_async (unixmessage const *, void *) ; 143 | 144 | extern tain answertto ; 145 | 146 | #endif 147 | -------------------------------------------------------------------------------- /src/rpc/skabus-rpccctl.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "skabus-rpccctl.h" 12 | 13 | #define USAGE "skabus-rpccctl [ -t timeout ] help|interface|interface-remove|query args..." 14 | #define dieusage() strerr_dieusage(100, USAGE) 15 | 16 | static tain deadline ; 17 | static skabus_rpcc_t a = SKABUS_RPCC_ZERO ; 18 | 19 | static void add_interface (char const *rpccpath, char const *ifname, char const *ifprog, char const *re) 20 | { 21 | if (!skabus_rpcc_start_g(&a, rpccpath, &deadline)) 22 | strerr_diefu2sys(111, "start session with skabus-rpcc instance at ", rpccpath) ; 23 | if (!skabus_rpcc_interface_register_g(&a, ifname, ifprog, re, &deadline)) 24 | strerr_diefu6sys(111, "register interface ", ifname, " with body ", ifprog, " and regex ", re) ; 25 | skabus_rpcc_end(&a) ; 26 | } 27 | 28 | static void remove_interface (char const *rpccpath, char const *ifname) 29 | { 30 | if (!skabus_rpcc_start_g(&a, rpccpath, &deadline)) 31 | strerr_diefu2sys(111, "start session with skabus-rpcc instance at ", rpccpath) ; 32 | if (!skabus_rpcc_interface_unregister_g(&a, ifname, &deadline)) 33 | strerr_diefu2sys(111, "unregister interface ", ifname) ; 34 | skabus_rpcc_end(&a) ; 35 | } 36 | 37 | static void query (char const *rpccpath, char const *ifname, char const *query, uint32_t timeout) 38 | { 39 | stralloc sa = STRALLOC_ZERO ; 40 | if (!skabus_rpcc_start_g(&a, rpccpath, &deadline)) 41 | strerr_diefu2sys(111, "start session with skabus-rpcc instance at ", rpccpath) ; 42 | if (!skabus_rpcc_query_g(&a, &sa, ifname, query, timeout, &deadline)) 43 | strerr_diefu2sys(111, "send query to interface ", ifname) ; 44 | skabus_rpcc_end(&a) ; 45 | if (buffer_putflush(buffer_1, sa.s, sa.len) < 0) 46 | strerr_diefu1sys(111, "write to stdout") ; 47 | stralloc_free(&sa) ; 48 | } 49 | 50 | static void quit (char const *rpccpath) 51 | { 52 | if (!skabus_rpcc_start_g(&a, rpccpath, &deadline)) 53 | strerr_diefu2sys(111, "start session with skabus-rpcc instance at ", rpccpath) ; 54 | if (!skabus_rpcc_quit_g(&a, &deadline)) 55 | strerr_diefu1sys(111, "send quit command") ; 56 | skabus_rpcc_end(&a) ; 57 | } 58 | 59 | static inline void print_help (void) 60 | { 61 | static char const *help = 62 | "skabus-rpccctl help\n" 63 | "skabus-rpccctl [ -t timeout ] interface rpccpath interface-name interface-program clientid-regex\n" 64 | "skabus-rpccctl [ -t timeout ] interface-remove rpccpath interface-name\n" 65 | "skabus-rpccctl [ -t timeout ] [ -T limit ] query rpccpath interface-name query\n" 66 | "skabus-rpccctl quit\n" ; 67 | if (buffer_putsflush(buffer_1, help) < 0) 68 | strerr_diefu1sys(111, "write to stdout") ; 69 | } 70 | 71 | static inline unsigned int lookup (char const *const *table, char const *command) 72 | { 73 | unsigned int i = 0 ; 74 | for (; table[i] ; i++) if (!strcmp(command, table[i])) break ; 75 | return i ; 76 | } 77 | 78 | static inline unsigned int parse_command (char const *command) 79 | { 80 | static char const *const command_table[13] = 81 | { 82 | "help", 83 | "interface", 84 | "interface-remove", 85 | "query", 86 | "quit", 87 | 0 88 | } ; 89 | unsigned int i = lookup(command_table, command) ; 90 | if (!command_table[i]) dieusage() ; 91 | return i ; 92 | } 93 | 94 | int main (int argc, char const *const *argv) 95 | { 96 | unsigned int what ; 97 | uint32_t timeout = 0 ; 98 | PROG = "skabus-rpccctl" ; 99 | { 100 | unsigned int t = 0 ; 101 | subgetopt l = SUBGETOPT_ZERO ; 102 | for (;;) 103 | { 104 | int opt = subgetopt_r(argc, argv, "t:T:", &l) ; 105 | if (opt == -1) break ; 106 | switch (opt) 107 | { 108 | case 't' : if (!uint0_scan(l.arg, &t)) dieusage() ; break ; 109 | case 'T' : if (!uint320_scan(l.arg, &timeout)) dieusage() ; break ; 110 | default : dieusage() ; 111 | } 112 | } 113 | argc -= l.ind ; argv += l.ind ; 114 | if (t) tain_from_millisecs(&deadline, t) ; 115 | else deadline = tain_infinite_relative ; 116 | } 117 | 118 | if (!argc) dieusage() ; 119 | 120 | tain_now_set_stopwatch_g() ; 121 | tain_add_g(&deadline, &deadline) ; 122 | 123 | what = parse_command(argv[0]) ; 124 | switch (what) 125 | { 126 | case 0 : 127 | print_help() ; 128 | break ; 129 | case 1 : 130 | if (argc < 5) dieusage() ; 131 | add_interface(argv[2], argv[3], argv[4], argv[5]) ; 132 | break ; 133 | case 2 : 134 | if (argc < 3) dieusage() ; 135 | remove_interface(argv[2], argv[3]) ; 136 | break ; 137 | case 3 : 138 | if (argc < 4) dieusage() ; 139 | query(argv[2], argv[3], argv[4], timeout) ; 140 | break ; 141 | case 4 : 142 | if (argc < 2) dieusage() ; 143 | quit(argv[2]) ; 144 | break ; 145 | default : dieusage() ; 146 | } 147 | return 0 ; 148 | } 149 | -------------------------------------------------------------------------------- /doc/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | skabus - a Unix bus system 7 | 8 | 9 | 10 | 11 | 12 | 13 |

14 | Software
15 | skarnet.org 16 |

17 | 18 |

skabus

19 | 20 |

What is it ?

21 | 22 |

23 | skabus is a suite of programs and libraries for Unix systems 24 | that aim to implement a bus, i.e. a many-to-many interprocess 25 | communication mechanism. 26 |

27 | 28 |

29 | It is very much a work in progress, and won't be complete for a long time. 30 | For now, it looks like a random collection of tools, even though there is 31 | a consistent vision behind them. 32 |

33 | 34 |
35 | 36 | 44 | 45 |

Installation

46 | 47 |

Requirements

48 | 49 |
    50 |
  • A POSIX-compliant system with a standard C development environment
  • 51 |
  • GNU make, version 3.81 or later
  • 52 |
  • skalibs version 53 | 2.14.5.0 or later
  • 54 |
  • execline version 55 | 2.9.8.0 or later
  • 56 |
  • s6 version 57 | 2.13.3.0 or later
  • 58 | 59 |
60 | 61 |

Licensing

62 | 63 |

64 | skabus is free software. It is available under the 65 | ISC license. 66 |

67 | 68 |

Download

69 | 70 |
    71 | 73 |
  • There is no official numbered release version of skabus at the moment.
  • 74 |
  • You can checkout a copy of the 75 | skabus 76 | git repository: 77 |
     git clone git://git.skarnet.org/skabus 
  • 78 |
  • There's also a 79 | GitHub mirror, or a 80 | SourceHut mirror">SourceHut mirror 81 | of the skabus git repository.
  • 82 |
83 | 84 |

Compilation

85 | 86 |
    87 |
  • See the enclosed INSTALL file for installation details.
  • 88 |
89 | 90 |

Upgrade notes

91 | 92 |
    93 |
  • This page lists the differences to be aware of between 94 | the previous versions of skabus and the current one.
  • 95 |
96 | 97 |
98 | 99 |

Reference

100 | 101 |

Commands

102 | 103 |

104 | All these commands exit 111 if they encounter a temporary error or 105 | hardware error, and 106 | 100 if they encounter a permanent error - such as a misuse. Short-lived 107 | commands exit 0 on success. Other exit codes are documented in the 108 | relevant page. 109 |

110 | 111 |

Publication/subscription

112 | 113 | 118 | 119 |

Remote procedure calls

120 | 121 | 125 | 126 |

Libraries

127 | 128 |
    129 |
  • The skabus library interface
  • 130 |
131 | 132 |
133 | 134 | 135 |

Related resources

136 |
137 | 138 |

skabus discussion

139 | 140 |
    141 |
  • skabus is discussed on the 142 | skaware mailing-list.
  • 143 |
144 | 145 |

Similar work

146 | 147 |
    148 |
  • D-Bus is 149 | the most widely used Linux bus. It's also a horrible, inefficient mess.
  • 150 |
  • ubus is 151 | OpenWrt's micro-bus architecture.
  • 152 |
  • Mathias Andree's bus 153 | is a daemonless system for broadcasting messages locally.
  • 154 |
155 | 156 | 157 | 158 | -------------------------------------------------------------------------------- /doc/libskabus/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | skabus: the skabus library interface 7 | 8 | 9 | 10 | 11 | 12 | 13 |

14 | skabus
15 | Software
16 | skarnet.org 17 |

18 | 19 |

The skabus library interface

20 | 21 |

General information

22 | 23 |

24 | libskabus is a collection of C client libraries used 25 | to communicate with the various skabus daemons. 26 |

27 | 28 |

Compiling

29 | 30 |
    31 |
  • Make sure the skabus headers, as well as the skalibs headers, 32 | are visible in your header search path.
  • 33 |
  • Use #include <skabus/skabus.h>
  • 34 |
35 | 36 |

Linking

37 | 38 |
    39 |
  • Make sure the skabus libraries, as well as the skalibs 40 | libraries, are visible in your library search path.
  • 41 |
  • Link against -lskabus and -lskarnet. 42 | If you're using socket functions (which is the case with 43 | skabus_rpc, for instance, add 44 | `cat $sysdeps/socket.lib` to your command line. 45 | If you're using timed functions involving TAI timestamps 46 | (which is also the case with skabus_rpc 47 | for instance), add 48 | `cat $sysdeps/sysclock.lib`. $sysdeps 49 | stands for your skalibs sysdeps directory.
  • 50 |
51 | 52 |

Programming

53 | 54 |

Preamble: synchronous functions

55 | 56 |

57 | The bulk of libskabus functions takes two extra arguments at the 58 | end: deadline and stamp. Their type is 59 | tain_t. This means 60 | they are synchronous function calls, and the extra arguments are there to ensure 61 | those calls do not block forever. 62 |

63 | 64 |

65 | stamp must be first initialized to an 66 | accurate enough approximation of the current time, for instance via skalibs' 67 | tain_now() function; it will then be automatically updated by the 68 | skabus function calls to always contain (an accurate enough approximation 69 | of) the current time. 70 |

71 | 72 |

73 | deadline is an absolute date. The meaning is: if the function has 74 | not returned by deadline, its operation is interrupted, and it 75 | will immediately return with a failure code, and errno 76 | will be set to ETIMEDOUT. 77 |

78 | 79 |

80 | deadline and stamp are used internally to compute a 81 | timeout, because blocking functions such as 82 | poll() 83 | use timeouts. The functions (like most skarnet.org functions) prefer to 84 | take a deadline and a timestamp instead of a timeout, because it's much 85 | easier (for both the application and the library's implementation) to 86 | work with absolute deadlines and update a timestamp regularly than it is 87 | to recompute a bunch of timeouts after every operation that potentially 88 | takes time. 89 |

90 | 91 |

92 | skalibs can keep track of the 93 | timestamp for you, in the global STAMP variable. All libskabus 94 | functions taking a deadline and stamp argument also have a 95 | version with a name ending in _g, that does not take stamp, and 96 | assumes the STAMP variable always contains (an accurate 97 | enough approximation of) the current time. 98 |

99 | 100 |

101 | Those synchronous function calls normally return almost instantly: there should 102 | be no blocking code path between the function call and its return. Nevertheless, 103 | since they involve communication with another process, they are at the whim 104 | of the scheduler, so it's impossible to guarantee that they will never block. 105 | The use of the deadline and stamp arguments 106 | ensures there is a cap on the amount of time they block. 107 |

108 | 109 |

skabus functions

110 | 111 |

112 | The skabus/skabus.h header is actually a 113 | concatenation of other headers: 114 | the libskabus is separated into several modules, each of them with its 115 | own header. 116 |

117 | 118 |
    119 |
  • The skabus/rpc.h header provides 120 | functions to communicate with a 121 | skabus-rpcd server, and help 122 | clients serve RPC calls or perform RPC calls to other registered 123 | clients.
  • 124 |
125 | 126 | 127 | 128 | -------------------------------------------------------------------------------- /src/misc/skabus-dyntee.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | #include 14 | 15 | #include 16 | 17 | #define USAGE "skabus-dyntee [ -d | -D ] [ -1 ] [ -c maxconn ] [ -b backlog ] [ -G gid,gid,... ] [ -g gid ] [ -u uid ] [ -U ] [ -t timeout ] [ -T lameducktimeout ] [ -i rulesdir | -x rulesfile ] socketpath" 18 | #define dieusage() strerr_dieusage(100, USAGE) 19 | 20 | int main (int argc, char const *const *argv) 21 | { 22 | int flag1 = 0 ; 23 | int flagU = 0 ; 24 | int flagreuse = 1 ; 25 | uid_t uid = 0 ; 26 | gid_t gid = 0 ; 27 | gid_t gids[NGROUPS_MAX] ; 28 | size_t gidn = (size_t)-1 ; 29 | unsigned int maxconn = 0 ; 30 | unsigned int backlog = (unsigned int)-1 ; 31 | unsigned int timeout = 0 ; 32 | unsigned int ltimeout = 0 ; 33 | char const *rulesdir = 0 ; 34 | char const *rulesfile = 0 ; 35 | PROG = "skabus-dyntee" ; 36 | { 37 | subgetopt l = SUBGETOPT_ZERO ; 38 | for (;;) 39 | { 40 | register int opt = subgetopt_r(argc, argv, "Dd1Uc:b:u:g:G:t:T:i:x:", &l) ; 41 | if (opt == -1) break ; 42 | switch (opt) 43 | { 44 | case 'D' : flagreuse = 0 ; break ; 45 | case 'd' : flagreuse = 1 ; break ; 46 | case '1' : flag1 = 1 ; break ; 47 | case 'c' : if (!uint0_scan(l.arg, &maxconn)) dieusage() ; if (!maxconn) maxconn = 1 ; break ; 48 | case 'b' : if (!uint0_scan(l.arg, &backlog)) dieusage() ; break ; 49 | case 'u' : if (!uid0_scan(l.arg, &uid)) dieusage() ; break ; 50 | case 'g' : if (!gid0_scan(l.arg, &gid)) dieusage() ; break ; 51 | case 'G' : if (!gid_scanlist(gids, NGROUPS_MAX, l.arg, &gidn) && *l.arg) dieusage() ; break ; 52 | case 'U' : flagU = 1 ; uid = 0 ; gid = 0 ; gidn = (unsigned int)-1 ; break ; 53 | case 't' : if (!uint0_scan(l.arg, &timeout)) dieusage() ; break ; 54 | case 'T' : if (!uint0_scan(l.arg, <imeout)) dieusage() ; break ; 55 | case 'i' : rulesdir = l.arg ; rulesfile = 0 ; break ; 56 | case 'x' : rulesfile = l.arg ; rulesdir = 0 ; break ; 57 | default : dieusage() ; 58 | } 59 | } 60 | argc -= l.ind ; argv += l.ind ; 61 | if (!argc) dieusage() ; 62 | } 63 | 64 | { 65 | size_t pos = 0 ; 66 | unsigned int m = 0 ; 67 | int fdin = dup(0) ; 68 | char const *newargv[31] ; 69 | char fmt[UINT_FMT * 5 + UID_FMT + GID_FMT * (1 + NGROUPS_MAX)] ; 70 | if (fdin < 0) strerr_diefu1sys(111, "dup(0)") ; 71 | if (fdin < 3) strerr_dief1x(100, "invalid standard file descriptors") ; 72 | pos += uint_fmt(fmt + pos, fdin) ; 73 | fmt[pos++] = 0 ; 74 | newargv[m++] = S6_EXTBINPREFIX "s6-ipcserver-socketbinder" ; 75 | if (!flagreuse) newargv[m++] = "-D" ; 76 | if (backlog != (unsigned int)-1) 77 | { 78 | newargv[m++] = "-b" ; 79 | newargv[m++] = fmt + pos ; 80 | pos += uint_fmt(fmt + pos, backlog) ; 81 | fmt[pos++] = 0 ; 82 | } 83 | newargv[m++] = "--" ; 84 | newargv[m++] = argv[0] ; 85 | if (flagU || uid || gid || gidn != (size_t)-1) 86 | { 87 | newargv[m++] = S6_EXTBINPREFIX "s6-applyuidgid" ; 88 | if (flagU) newargv[m++] = "-Uz" ; 89 | if (uid) 90 | { 91 | newargv[m++] = "-u" ; 92 | newargv[m++] = fmt + pos ; 93 | pos += uid_fmt(fmt + pos, uid) ; 94 | fmt[pos++] = 0 ; 95 | } 96 | if (gid) 97 | { 98 | newargv[m++] = "-g" ; 99 | newargv[m++] = fmt + pos ; 100 | pos += gid_fmt(fmt + pos, gid) ; 101 | fmt[pos++] = 0 ; 102 | } 103 | if (gidn != (size_t)-1) 104 | { 105 | newargv[m++] = "-G" ; 106 | newargv[m++] = fmt + pos ; 107 | pos += gid_fmtlist(fmt + pos, gids, gidn) ; 108 | fmt[pos++] = 0 ; 109 | } 110 | newargv[m++] = "--" ; 111 | } 112 | newargv[m++] = EXECLINE_EXTBINPREFIX "fdswap" ; 113 | newargv[m++] = "0" ; 114 | newargv[m++] = fmt ; 115 | newargv[m++] = SKABUS_BINPREFIX "skabus-dynteed" ; 116 | newargv[m++] = "-d" ; 117 | newargv[m++] = fmt ; 118 | if (flag1) newargv[m++] = "-1" ; 119 | if (maxconn) 120 | { 121 | newargv[m++] = "-c" ; 122 | newargv[m++] = fmt + pos ; 123 | pos += uint_fmt(fmt + pos, maxconn) ; 124 | fmt[pos++] = 0 ; 125 | } 126 | if (timeout) 127 | { 128 | newargv[m++] = "-t" ; 129 | newargv[m++] = fmt + pos ; 130 | pos += uint_fmt(fmt + pos, timeout) ; 131 | fmt[pos++] = 0 ; 132 | } 133 | if (ltimeout) 134 | { 135 | newargv[m++] = "-T" ; 136 | newargv[m++] = fmt + pos ; 137 | pos += uint_fmt(fmt + pos, ltimeout) ; 138 | fmt[pos++] = 0 ; 139 | } 140 | if (rulesdir) 141 | { 142 | newargv[m++] = "-i" ; 143 | newargv[m++] = rulesdir ; 144 | } 145 | else if (rulesfile) 146 | { 147 | newargv[m++] = "-x" ; 148 | newargv[m++] = rulesfile ; 149 | } 150 | newargv[m++] = 0 ; 151 | xexec(newargv) ; 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /src/rpc/skabus-rpc-daemon.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | #include 14 | 15 | #define USAGE "skabus-rpc-daemon [ -v verbosity ] [ -d | -D ] [ -1 ] [ -c maxconn ] [ -b backlog ] [ -G gid,gid,... ] [ -g gid ] [ -u uid ] [ -U ] [ -t timeout ] [ -T lameducktimeout ] [ -i rulesdir | -x rulesfile ] [ -S | -s ] [ -J | -j ] path" 16 | #define dieusage() strerr_dieusage(100, USAGE) 17 | 18 | int main (int argc, char const *const *argv) 19 | { 20 | unsigned int verbosity = 1 ; 21 | int flag1 = 0 ; 22 | int flagU = 0 ; 23 | int flagreuse = 1 ; 24 | uid_t uid = 0 ; 25 | gid_t gid = 0 ; 26 | gid_t gids[NGROUPS_MAX] ; 27 | size_t gidn = (size_t)-1 ; 28 | unsigned int maxconn = 0 ; 29 | unsigned int backlog = (unsigned int)-1 ; 30 | int flagpublic = 0 ; 31 | int flagifpublic = 0 ; 32 | unsigned int timeout = 0 ; 33 | unsigned int ltimeout = 0 ; 34 | char const *rulesdir = 0 ; 35 | char const *rulesfile = 0 ; 36 | PROG = "skabus-rpc-daemon" ; 37 | { 38 | subgetopt l = SUBGETOPT_ZERO ; 39 | for (;;) 40 | { 41 | int opt = subgetopt_r(argc, argv, "Dd1USsJjv:c:b:u:g:G:t:T:i:x:", &l) ; 42 | if (opt == -1) break ; 43 | switch (opt) 44 | { 45 | case 'D' : flagreuse = 0 ; break ; 46 | case 'd' : flagreuse = 1 ; break ; 47 | case '1' : flag1 = 1 ; break ; 48 | case 'v' : if (!uint0_scan(l.arg, &verbosity)) dieusage() ; break ; 49 | case 'c' : if (!uint0_scan(l.arg, &maxconn)) dieusage() ; if (!maxconn) maxconn = 1 ; break ; 50 | case 'b' : if (!uint0_scan(l.arg, &backlog)) dieusage() ; break ; 51 | case 'u' : if (!uid0_scan(l.arg, &uid)) dieusage() ; break ; 52 | case 'g' : if (!gid0_scan(l.arg, &gid)) dieusage() ; break ; 53 | case 'G' : if (!gid_scanlist(gids, NGROUPS_MAX, l.arg, &gidn) && *l.arg) dieusage() ; break ; 54 | case 'U' : flagU = 1 ; uid = 0 ; gid = 0 ; gidn = (size_t)-1 ; break ; 55 | case 'S' : flagpublic = 0 ; break ; 56 | case 's' : flagpublic = 1 ; break ; 57 | case 'J' : flagifpublic = 0 ; break ; 58 | case 'j' : flagifpublic = 1 ; break ; 59 | case 't' : if (!uint0_scan(l.arg, &timeout)) dieusage() ; break ; 60 | case 'T' : if (!uint0_scan(l.arg, <imeout)) dieusage() ; break ; 61 | case 'i' : rulesdir = l.arg ; rulesfile = 0 ; break ; 62 | case 'x' : rulesfile = l.arg ; rulesdir = 0 ; break ; 63 | default : dieusage() ; 64 | } 65 | } 66 | argc -= l.ind ; argv += l.ind ; 67 | if (!argc) dieusage() ; 68 | } 69 | 70 | { 71 | unsigned int m = 0, pos = 0 ; 72 | char const *newargv[30] ; 73 | char fmt[UINT_FMT * 6 + UID_FMT + GID_FMT * (1 + NGROUPS_MAX)] ; 74 | newargv[m++] = S6_EXTBINPREFIX "s6-ipcserver-socketbinder" ; 75 | if (!flagreuse) newargv[m++] = "-D" ; 76 | if (backlog != (unsigned int)-1) 77 | { 78 | newargv[m++] = "-b" ; 79 | newargv[m++] = fmt + pos ; 80 | pos += uint_fmt(fmt + pos, backlog) ; 81 | fmt[pos++] = 0 ; 82 | } 83 | newargv[m++] = "--" ; 84 | newargv[m++] = *argv++ ; 85 | if (flagU || uid || gid || gidn != (size_t)-1) 86 | { 87 | newargv[m++] = S6_EXTBINPREFIX "s6-applyuidgid" ; 88 | if (flagU) newargv[m++] = "-Uz" ; 89 | if (uid) 90 | { 91 | newargv[m++] = "-u" ; 92 | newargv[m++] = fmt + pos ; 93 | pos += uid_fmt(fmt + pos, uid) ; 94 | fmt[pos++] = 0 ; 95 | } 96 | if (gid) 97 | { 98 | newargv[m++] = "-g" ; 99 | newargv[m++] = fmt + pos ; 100 | pos += gid_fmt(fmt + pos, gid) ; 101 | fmt[pos++] = 0 ; 102 | } 103 | if (gidn != (size_t)-1) 104 | { 105 | newargv[m++] = "-G" ; 106 | newargv[m++] = fmt + pos ; 107 | pos += gid_fmtlist(fmt + pos, gids, gidn) ; 108 | fmt[pos++] = 0 ; 109 | } 110 | newargv[m++] = "--" ; 111 | } 112 | newargv[m++] = SKABUS_BINPREFIX "skabus-rpcd" ; 113 | if (verbosity != 1) 114 | { 115 | newargv[m++] = "-v" ; 116 | newargv[m++] = fmt + pos ; 117 | pos += uint_fmt(fmt + pos, verbosity) ; 118 | fmt[pos++] = 0 ; 119 | } 120 | if (flag1) newargv[m++] = "-1" ; 121 | if (flagpublic) newargv[m++] = "-s" ; 122 | if (flagifpublic) newargv[m++] = "-j" ; 123 | if (maxconn) 124 | { 125 | newargv[m++] = "-c" ; 126 | newargv[m++] = fmt + pos ; 127 | pos += uint_fmt(fmt + pos, maxconn) ; 128 | fmt[pos++] = 0 ; 129 | } 130 | if (timeout) 131 | { 132 | newargv[m++] = "-t" ; 133 | newargv[m++] = fmt + pos ; 134 | pos += uint_fmt(fmt + pos, timeout) ; 135 | fmt[pos++] = 0 ; 136 | } 137 | if (ltimeout) 138 | { 139 | newargv[m++] = "-T" ; 140 | newargv[m++] = fmt + pos ; 141 | pos += uint_fmt(fmt + pos, timeout) ; 142 | fmt[pos++] = 0 ; 143 | } 144 | if (rulesdir) 145 | { 146 | newargv[m++] = "-i" ; 147 | newargv[m++] = rulesdir ; 148 | } 149 | else if (rulesfile) 150 | { 151 | newargv[m++] = "-x" ; 152 | newargv[m++] = rulesfile ; 153 | } 154 | newargv[m++] = 0 ; 155 | xexec(newargv) ; 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /src/pub/skabus-pub-daemon.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | #include 14 | 15 | #define USAGE "skabus-pub-daemon [ -v verbosity ] [ -d | -D ] [ -1 ] [ -c maxconn ] [ -b backlog ] [ -G gid,gid,... ] [ -g gid ] [ -u uid ] [ -U ] [ -t timeout ] [ -T lameducktimeout ] [ -i rulesdir | -x rulesfile ] [ -S | -s ] [ -k announcere ] path msgfsdir" 16 | #define dieusage() strerr_dieusage(100, USAGE) 17 | 18 | int main (int argc, char const *const *argv) 19 | { 20 | unsigned int verbosity = 1 ; 21 | int flag1 = 0 ; 22 | int flagU = 0 ; 23 | int flagreuse = 1 ; 24 | uid_t uid = 0 ; 25 | gid_t gid = 0 ; 26 | gid_t gids[NGROUPS_MAX] ; 27 | size_t gidn = (size_t)-1 ; 28 | unsigned int maxconn = 0 ; 29 | unsigned int backlog = (unsigned int)-1 ; 30 | int flagpublic = 0 ; 31 | unsigned int timeout = 0 ; 32 | unsigned int ltimeout = 0 ; 33 | char const *rulesdir = 0 ; 34 | char const *rulesfile = 0 ; 35 | char const *announcere = 0 ; 36 | PROG = "skabus-pub-daemon" ; 37 | { 38 | subgetopt l = SUBGETOPT_ZERO ; 39 | for (;;) 40 | { 41 | int opt = subgetopt_r(argc, argv, "Dd1USsv:c:b:u:g:G:t:T:i:x:k:", &l) ; 42 | if (opt == -1) break ; 43 | switch (opt) 44 | { 45 | case 'D' : flagreuse = 0 ; break ; 46 | case 'd' : flagreuse = 1 ; break ; 47 | case '1' : flag1 = 1 ; break ; 48 | case 'v' : if (!uint0_scan(l.arg, &verbosity)) dieusage() ; break ; 49 | case 'c' : if (!uint0_scan(l.arg, &maxconn)) dieusage() ; if (!maxconn) maxconn = 1 ; break ; 50 | case 'b' : if (!uint0_scan(l.arg, &backlog)) dieusage() ; break ; 51 | case 'u' : if (!uid0_scan(l.arg, &uid)) dieusage() ; break ; 52 | case 'g' : if (!gid0_scan(l.arg, &gid)) dieusage() ; break ; 53 | case 'G' : if (!gid_scanlist(gids, NGROUPS_MAX, l.arg, &gidn) && *l.arg) dieusage() ; break ; 54 | case 'U' : flagU = 1 ; uid = 0 ; gid = 0 ; gidn = (size_t)-1 ; break ; 55 | case 'S' : flagpublic = 0 ; break ; 56 | case 's' : flagpublic = 1 ; break ; 57 | case 't' : if (!uint0_scan(l.arg, &timeout)) dieusage() ; break ; 58 | case 'T' : if (!uint0_scan(l.arg, <imeout)) dieusage() ; break ; 59 | case 'i' : rulesdir = l.arg ; rulesfile = 0 ; break ; 60 | case 'x' : rulesfile = l.arg ; rulesdir = 0 ; break ; 61 | case 'k' : announcere = l.arg ; break ; 62 | default : dieusage() ; 63 | } 64 | } 65 | argc -= l.ind ; argv += l.ind ; 66 | if (argc < 2) dieusage() ; 67 | } 68 | 69 | { 70 | unsigned int m = 0, pos = 0 ; 71 | char const *newargv[33] ; 72 | char fmt[UINT_FMT * 4 + UID_FMT + GID_FMT * (1 + NGROUPS_MAX)] ; 73 | newargv[m++] = S6_EXTBINPREFIX "s6-ipcserver-socketbinder" ; 74 | if (!flagreuse) newargv[m++] = "-D" ; 75 | if (backlog != (unsigned int)-1) 76 | { 77 | newargv[m++] = "-b" ; 78 | newargv[m++] = fmt + pos ; 79 | pos += uint_fmt(fmt + pos, backlog) ; 80 | fmt[pos++] = 0 ; 81 | } 82 | newargv[m++] = "--" ; 83 | newargv[m++] = *argv++ ; 84 | if (flagU || uid || gid || gidn != (size_t)-1) 85 | { 86 | newargv[m++] = S6_EXTBINPREFIX "s6-applyuidgid" ; 87 | if (flagU) newargv[m++] = "-Uz" ; 88 | if (uid) 89 | { 90 | newargv[m++] = "-u" ; 91 | newargv[m++] = fmt + pos ; 92 | pos += uid_fmt(fmt + pos, uid) ; 93 | fmt[pos++] = 0 ; 94 | } 95 | if (gid) 96 | { 97 | newargv[m++] = "-g" ; 98 | newargv[m++] = fmt + pos ; 99 | pos += gid_fmt(fmt + pos, gid) ; 100 | fmt[pos++] = 0 ; 101 | } 102 | if (gidn != (unsigned int)-1) 103 | { 104 | newargv[m++] = "-G" ; 105 | newargv[m++] = fmt + pos ; 106 | pos += gid_fmtlist(fmt + pos, gids, gidn) ; 107 | fmt[pos++] = 0 ; 108 | } 109 | newargv[m++] = "--" ; 110 | } 111 | newargv[m++] = SKABUS_BINPREFIX "skabus-pubd" ; 112 | if (verbosity != 1) 113 | { 114 | newargv[m++] = "-v" ; 115 | newargv[m++] = fmt + pos ; 116 | pos += uint_fmt(fmt + pos, verbosity) ; 117 | fmt[pos++] = 0 ; 118 | } 119 | if (flag1) newargv[m++] = "-1" ; 120 | if (flagpublic) newargv[m++] = "-s" ; 121 | if (maxconn) 122 | { 123 | newargv[m++] = "-c" ; 124 | newargv[m++] = fmt + pos ; 125 | pos += uint_fmt(fmt + pos, maxconn) ; 126 | fmt[pos++] = 0 ; 127 | } 128 | if (timeout) 129 | { 130 | newargv[m++] = "-t" ; 131 | newargv[m++] = fmt + pos ; 132 | pos += uint_fmt(fmt + pos, timeout) ; 133 | fmt[pos++] = 0 ; 134 | } 135 | if (ltimeout) 136 | { 137 | newargv[m++] = "-T" ; 138 | newargv[m++] = fmt + pos ; 139 | pos += uint_fmt(fmt + pos, ltimeout) ; 140 | fmt[pos++] = 0 ; 141 | } 142 | if (rulesdir) 143 | { 144 | newargv[m++] = "-i" ; 145 | newargv[m++] = rulesdir ; 146 | } 147 | else if (rulesfile) 148 | { 149 | newargv[m++] = "-x" ; 150 | newargv[m++] = rulesfile ; 151 | } 152 | if (announcere) 153 | { 154 | newargv[m++] = "-k" ; 155 | newargv[m++] = announcere ; 156 | } 157 | newargv[m++] = "--" ; 158 | newargv[m++] = *argv++ ; 159 | newargv[m++] = 0 ; 160 | xexec(newargv) ; 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /doc/skabus-dyntee.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | skabus: the skabus-dyntee program 7 | 8 | 9 | 10 | 11 | 12 | 13 |

14 | skabus
15 | Software
16 | skarnet.org 17 |

18 | 19 |

The skabus-dyntee program

20 | 21 |

22 | skabus-dyntee is a dynamic tee, which is the 23 | simplest publisher daemon possible. 24 | It listens on a Unix domain socket, accepts client connections, and 25 | publishes to its clients everything it reads on its standard 26 | input, as a byte stream. It only writes to clients and never reads 27 | from them. 28 |

29 | 30 |

Interface

31 | 32 |
 33 |      skabus-dyntee [ -1 ] [ -D | -d ] [ -c maxconn ] [ -b backlog ] [ -G gidlist ] [ -g gid ] [ -u uid ] [ -U ] [ -t clienttimeout ] [ -T lameducktimeout ] [ -i rulesdir | -x rulesfile ] path
 34 | 
35 | 36 |
    37 |
  • skabus-dyntee binds to the Unix domain socket at path.
  • 38 |
  • If applicable, it drops root privileges.
  • 39 |
  • It listens to its socket and accepts client connections.
  • 40 |
  • Whenever it has data available on its standard input, it reads 41 | that data and writes it to every client it has. It duplicates its 42 | stdin stream to all its clients, hence the name dynamic tee.
  • 43 |
  • When it reads EOF on its stdin, or when it receives a SIGTERM, 44 | it waits for its clients to read their pending data, then exits 0.
  • 45 |
46 | 47 |

48 | skabus-dyntee is just a wrapper that binds to its socket and 49 | drops privileges before executing into 50 | skabus-dynteed. For details of 51 | the daemon's operation, see the 52 | skabus-dynteed documentation. 53 |

54 | 55 |

Options

56 | 57 |
    58 |
  • -1 : write a newline to stdout, before 59 | closing it, right after binding and listening to the Unix socket. 60 | If stdout is suitably redirected, this can be used by monitoring 61 | programs to check when the server is ready to accept connections.
  • 62 |
  • -d : allow instant rebinding to the same path 63 | even if it has been used not long ago - this is the SO_REUSEADDR flag to 64 | setsockopt() 65 | and is generally used with server programs. This is the default. Note that 66 | path will be deleted if it already exists at program start time.
  • 67 |
  • -D : disallow instant rebinding to the same path.
  • 68 |
  • -c maxconn : accept at most 69 | maxconn concurrent client connections. Default is 40. It is 70 | impossible to set it higher than the value of the SKABUS_DYNTEE_MAX macro, 71 | which is 1000. 72 |
  • -b backlog : set a maximum of 73 | backlog backlog connections on the socket. Extra 74 | connection attempts will rejected by the kernel.
  • 75 |
  • -G gidlist : change skabus-dyntee's 76 | supplementary group list to gidlist after binding the socket. 77 | This is only valid when run as root. gidlist must be a 78 | comma-separated list of numerical group IDs.
  • 79 |
  • -g gid : change skabus-dyntee's groupid 80 | to gid after binding the socket. This is only valid when run 81 | as root.
  • 82 |
  • -u uid : change skabus-dyntee's userid 83 | to uid after binding the socket. This is only valid when run 84 | as root.
  • 85 |
  • -U : change skabus-dyntee's user id, group id and 86 | supplementary group list 87 | according to the values of the UID, GID and GIDLIST environment variables 88 | after binding the socket. This is only valid when run as root. 89 | This can be used with the 90 | s6-envuidgid 91 | program to easily script a service that binds to a privileged socket 92 | then drops its privileges to those of a named non-root account.
  • 93 |
  • -t clienttimeout : disconnect a client 94 | that has not read its data after clienttimeout milliseconds. 95 | By default, clienttimeout is 0, which means infinite.
  • 96 |
  • -T lameducktimeout : after 97 | skabus-dyntee has been told to exit, clients will have 98 | lameducktimeout milliseconds to read their pending data, 99 | after which skabus-dyntee will exit anyway. 100 | By default, lameducktimeout is 0, which means infinite.
  • 101 |
  • -x rulesfile : read access rights 102 | configuration from CDB file rulesfile.
  • 103 |
  • -i rulesdir : read access rights 104 | configuration from the filesystem in directory rulesdir.
  • 105 |
106 | 107 |

Notes

108 | 109 |
    110 |
  • skabus-dyntee does not interpret its options itself. It just 111 | dispatches them to the appropriate program on the command line that 112 | it builds.
  • 113 |
  • From the user's point of view, skabus-dyntee behaves like a 114 | long-lived process, even if the long-lived process itself is called 115 | skabus-dynteed. Every operational detail 116 | of skabus-dynteed applies to skabus-dyntee as well; in particular, 117 | make sure to properly 118 | configure the clients' 119 | access rights.
  • 120 |
121 | 122 | 123 | 124 | -------------------------------------------------------------------------------- /src/rpc/skabus_rpcd_client.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include "skabus-rpcd.h" 20 | 21 | static inline void client_free (client_t *c) 22 | { 23 | if (!genalloc_len(uint32_t, &c->interfaces)) regfree(&c->idstr_re) ; 24 | regfree(&c->interfaces_re) ; 25 | genalloc_free(unsigned int, &c->interfaces) ; 26 | gensetdyn_free(&c->queries) ; 27 | fd_close(unixmessage_sender_fd(&c->sync.out)) ; 28 | unixconnection_free(&c->sync) ; 29 | if (unixmessage_sender_fd(&c->async.out) >= 0) 30 | { 31 | fd_close(unixmessage_sender_fd(&c->async.out)) ; 32 | unixconnection_free(&c->async) ; 33 | } 34 | } 35 | 36 | genset *clients ; 37 | unsigned int sentinel ; 38 | 39 | static inline void client_delete (uint32_t i, uint32_t prev) 40 | { 41 | CLIENT(prev)->next = CLIENT(i)->next ; 42 | client_free(CLIENT(i)) ; 43 | genset_delete(clients, i) ; 44 | } 45 | 46 | static int query_cancelremove_iter (void *s, void *reason) 47 | { 48 | return query_cancelremove(*(uint32_t *)s, *(unsigned char *)reason) ; 49 | } 50 | 51 | void client_remove (uint32_t i, uint32_t prev) 52 | { 53 | client_t *c = CLIENT(i) ; 54 | unsigned char reason = ECONNABORTED ; 55 | if (gensetdyn_iter(&c->queries, &query_cancelremove_iter, &reason) < gensetdyn_n(&c->queries)) 56 | strerr_diefu1sys(111, "query_cancelremove_iter in client_remove") ; 57 | while (genalloc_len(uint32_t, &c->interfaces)) 58 | interface_remove(genalloc_s(uint32_t, &c->interfaces)[genalloc_len(uint32_t, &c->interfaces) - 1]) ; 59 | client_delete(i, prev) ; 60 | } 61 | 62 | void client_setdeadline (client_t *c) 63 | { 64 | tain blah ; 65 | tain_half(&blah, &tain_infinite_relative) ; 66 | tain_add_g(&blah, &blah) ; 67 | if (tain_less(&blah, &c->deadline)) tain_add_g(&c->deadline, &answertto) ; 68 | } 69 | 70 | void client_add (uint32_t *d, regex_t const *idstr_re, regex_t const *interfaces_re, uid_t uid, gid_t gid, int fdsock, uint32_t flags) 71 | { 72 | uint32_t cc = genset_new(clients) ; 73 | client_t *c = CLIENT(cc) ; 74 | c->next = CLIENT(sentinel)->next ; 75 | c->uid = uid ; 76 | c->gid = gid ; 77 | tain_add_g(&c->deadline, &answertto) ; 78 | c->interfaces = genalloc_zero ; 79 | c->queries = gensetdyn_zero ; 80 | c->idstr_re = *idstr_re ; 81 | c->interfaces_re = *interfaces_re ; 82 | unixconnection_init(&c->sync, fdsock, fdsock) ; 83 | unixconnection_init(&c->async, -1, -1) ; 84 | c->async.out.fd = -(int)flags-1 ; 85 | CLIENT(sentinel)->next = cc ; 86 | *d = cc ; 87 | } 88 | 89 | void client_nextdeadline (uint32_t i, tain *deadline) 90 | { 91 | client_t *c = CLIENT(i) ; 92 | if (tain_less(&c->deadline, deadline)) *deadline = c->deadline ; 93 | } 94 | 95 | int client_prepare_iopause (uint32_t cc, tain *deadline, iopause_fd *x, uint32_t *j, int notlameduck) 96 | { 97 | client_t *c = CLIENT(cc) ; 98 | int inflight = 0 ; 99 | uint32_t i = genalloc_len(uint32_t, &c->interfaces) ; 100 | if (tain_less(&c->deadline, deadline)) *deadline = c->deadline ; 101 | if (!unixmessage_sender_isempty(&c->sync.out) | !unixmessage_receiver_isempty(&c->sync.in) || (notlameduck && !unixmessage_receiver_isfull(&c->sync.in))) 102 | { 103 | x[*j].fd = unixmessage_sender_fd(&c->sync.out) ; 104 | x[*j].events = ((!unixmessage_receiver_isempty(&c->sync.in) || (notlameduck && !unixmessage_receiver_isfull(&c->sync.in))) ? IOPAUSE_READ : 0) 105 | | (!unixmessage_sender_isempty(&c->sync.out) ? IOPAUSE_WRITE : 0) ; 106 | c->xindex[0] = (*j)++ ; 107 | } 108 | else c->xindex[0] = 0 ; 109 | while (i--) 110 | { 111 | interface_t *y = INTERFACE(genalloc_s(uint32_t, &c->interfaces)[i]) ; 112 | if (gensetdyn_n(&y->queries)) 113 | { 114 | inflight = 1 ; 115 | break ; 116 | } 117 | } 118 | if (!unixmessage_sender_isempty(&c->async.out) || !unixmessage_receiver_isempty(&c->async.in) || inflight) 119 | { 120 | x[*j].fd = unixmessage_sender_fd(&c->async.out) ; 121 | x[*j].events = (unixmessage_sender_isempty(&c->async.out) ? IOPAUSE_WRITE : 0) 122 | | (!unixmessage_receiver_isempty(&c->async.in) || inflight ? IOPAUSE_READ : 0) ; 123 | c->xindex[1] = (*j)++ ; 124 | } 125 | else c->xindex[1] = 0 ; 126 | return c->xindex[0] || c->xindex[1] ; 127 | } 128 | 129 | int client_flush (uint32_t i, iopause_fd const *x) 130 | { 131 | client_t *c = CLIENT(i) ; 132 | int isflushed = 2 ; 133 | if (c->xindex[0] && (x[c->xindex[0]].revents & IOPAUSE_WRITE)) 134 | { 135 | if (!unixmessage_sender_flush(&c->sync.out)) 136 | if (!error_isagain(errno)) return 0 ; 137 | else isflushed = 0 ; 138 | else isflushed = 1 ; 139 | } 140 | 141 | if (c->xindex[1] && (x[c->xindex[1]].revents & IOPAUSE_WRITE)) 142 | { 143 | if (!unixmessage_sender_flush(&c->async.out)) 144 | if (!error_isagain(errno)) return 0 ; 145 | else isflushed = 0 ; 146 | else isflushed = !!isflushed ; 147 | } 148 | 149 | if (isflushed == 1) tain_add_g(&c->deadline, &tain_infinite_relative) ; 150 | return 1 ; 151 | } 152 | 153 | int client_read (uint32_t cc, iopause_fd const *x) 154 | { 155 | client_t *c = CLIENT(cc) ; 156 | if (!unixmessage_receiver_isempty(&c->sync.in) || (c->xindex[0] && x[c->xindex[0]].revents & IOPAUSE_READ)) 157 | { 158 | if (unixmessage_sender_fd(&c->async.out) < 0) 159 | { 160 | unixmessage m ; 161 | int r = unixmessage_receive(&c->sync.in, &m) ; 162 | if (r < 0) return -1 ; 163 | if (r) 164 | { 165 | uint32_t flags = -(unixmessage_sender_fd(&c->async.out) + 1) ; 166 | if (!skaclient_server_bidi_ack(&m, &c->sync.out, &c->async.out, &c->async.in, c->async.mainbuf, UNIXMESSAGE_BUFSIZE, c->async.auxbuf, UNIXMESSAGE_AUXBUFSIZE, SKABUS_RPC_BANNER1, SKABUS_RPC_BANNER1_LEN, SKABUS_RPC_BANNER2, SKABUS_RPC_BANNER2_LEN)) 167 | { 168 | unixmessage_drop(&m) ; 169 | return -1 ; 170 | } 171 | if (!(flags & 1)) unixmessage_receiver_refuse_fds(&c->sync.in) ; 172 | if (!(flags & 2)) unixmessage_receiver_refuse_fds(&c->async.in) ; 173 | } 174 | } 175 | else 176 | { 177 | int r = unixmessage_handle(&c->sync.in, &parse_protocol_sync, &cc) ; 178 | if (r <= 0) return r ; 179 | } 180 | } 181 | if (!unixmessage_receiver_isempty(&c->async.in) || (c->xindex[1] && x[c->xindex[1]].revents & IOPAUSE_READ)) 182 | { 183 | int r = unixmessage_handle(&c->async.in, &parse_protocol_async, &cc) ; 184 | if (r <= 0) return r ; 185 | } 186 | return 1 ; 187 | } 188 | -------------------------------------------------------------------------------- /doc/skabus-dynteed.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | skabus: the skabus-dynteed program 7 | 8 | 9 | 10 | 11 | 12 | 13 |

14 | skabus
15 | Software
16 | skarnet.org 17 |

18 | 19 |

The skabus-dynteed program

20 | 21 |

22 | skabus-dynteed is the serving part of the 23 | skabus-dyntee program. 24 | It assumes that one of its file descriptors (3 or above) is a 25 | bound, listening, non-blocking domain socket; 26 | it accepts connections from clients connecting to that socket, 27 | and copies its stdin stream to all its clients. 28 |

29 | 30 |

Interface

31 | 32 |
 33 |      skabus-dynteed [ -1 ] [ -c maxconn ] [ -t clienttimeout ] [ -T lameducktimeout ] [ -i rulesdir | -x rulesfile ]
 34 | 
35 | 36 |
    37 |
  • skabus-dynteed accepts connections from clients to an already 38 | bound and listening SOCK_STREAM Unix domain socket, by default on 39 | its file descriptor 3.
  • 40 |
  • It runs until it receives a SIGTERM or until it reads EOF 41 | on its stdin. In that case, it stops accepting new client connections, 42 | and exits 0 when all clients have read their pending data.
  • 43 |
  • Client connections last as long as the client wants to, unless an 44 | error occurs, or unless the server is told to exit - in which cases 45 | skabus-dynteed forcibly disconnects the client.
  • 46 |
  • Clients cannot write anything to skabus-dynteed. They can only 47 | read a stream of bytes on their socket, which is a copy of what 48 | skabus-dynteed reads on its standard input.
  • 49 |
50 | 51 |

Options

52 | 53 |
    54 |
  • -1 : write a newline to stdout, and close stdout, 55 | right before entering the client-accepting loop. 56 | If stdout is suitably redirected, this can be used by monitoring 57 | programs to check when the server is accepting connections. See 58 | this page 59 | for more information on readiness notification.
  • 60 |
  • -c maxconn : accept at most 61 | maxconn concurrent connections. Default is 40. It is 62 | impossible to set it higher than the value of the SKABUS_DYNTEE_MAX macro, 63 | i.e. 1000.
  • 64 |
  • -t clienttimeout : disconnect a client 65 | if it has not read its pending data after clienttimeout milliseconds. 66 | By default, clienttimeout is 0, which means infinite.
  • 67 |
  • -T lameducktimeout : give clients 68 | lameducktimeout milliseconds to read their pending data when 69 | skabus-dynteed is going to exit. 70 | By default, lameducktimeout is 0, which means infinite.
  • 71 |
  • -x rulesfile : read access rights 72 | configuration from 73 | CDB 74 | file rulesfile.
  • 75 |
  • -i rulesdir : read access rights 76 | configuration from the filesystem in directory rulesdir.
  • 77 |
78 | 79 |

Signals

80 | 81 |
    82 |
  • SIGTERM: enter lameduck mode, then exit when all clients have 83 | read their pending data (or lameducktimeout milliseconds have 84 | elapsed).
  • 85 |
  • SIGHUP: reopen rulesfile, if skabus-dynteed has been run 86 | with the -x option. It is not necessary to send skabus-dynteed 87 | a SIGHUP when the -i option is used instead: configuration 88 | changes in the filesystem are automatically picked up.
  • 89 |
90 | 91 | 92 |

Configuration

93 |
94 | 95 |

96 | skabus-dynteed (or its wrapper skabus-dyntee) 97 | can be instructed not to accept every client. This is achieved 98 | via a series of rules, or ruleset, stored in either a 99 | rulesfile in the 100 | CDB format, 101 | and given to skabus-dynteed with the -x option, 102 | or in a rulesdir, i.e. a directory in the filesystem following a 103 | certain format, and given to skabus-dynteed with the -i option. 104 | If neither the -i nor the -x option has been provided, 105 | skabus-dynteed will accept connections from any client. 106 |

107 | 108 |

109 | Rulesets can be converted between the rulesdir and 110 | rulesfile formats with the 111 | s6-accessrules-cdb-from-fs and 112 | s6-accessrules-fs-from-cdb 113 | conversion tools. 114 |

115 | 116 |

Rules format

117 | 118 |

119 | The rules file, or rules directory, follows the 120 | s6 accessrules format for uid and 121 | gid checking. For every connecting client, skabus-dynteed matches the uid 122 | and gid of the client against the provided ruleset, and determines whether 123 | the client is authorized or not to connect. 124 | The right to connect is given if an 125 | allow file is found in one of the subdirectories checked by 126 | s6_accessrules_keycheck_uidgid. 127 | For instance, to allow everyone to connect, touch 128 | rulesdir/uid/default/allow. 129 |

130 | 131 |

132 | If a rulesfile or rulesdir has been provided to 133 | skabus-dynteed, and the client's uid and gid match no rule in the 134 | ruleset, then the connection is denied. 135 |

136 | 137 |

Notes

138 | 139 |
    140 |
  • skabus-dynteed is meant to be execve'd into by a program that gets 141 | the listening socket. That program is normally 142 | s6-ipcserver-socketbinder, 143 | which creates the socket itself; but it can be a different one if the 144 | socket is to be obtained by another means, for instance if it has 145 | been retrieved from a fd-holding daemon.
  • 146 |
  • Clients can plug into the data stream at any time. The data stream 147 | should have a format making it easy for clients to synchronize with it.
  • 148 |
  • The simplest way of connecting to a skabus-dynteed instance and 149 | reading the data stream is via the 150 | skabus-dyntee-client program.
  • 151 |
152 | 153 | 154 | 155 | -------------------------------------------------------------------------------- /doc/skabus-rpc-daemon.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | skabus: the skabus-rpc-daemon program 7 | 8 | 9 | 10 | 11 | 12 | 13 |

14 | skabus
15 | Software
16 | skarnet.org 17 |

18 | 19 |

The skabus-rpc-daemon program

20 | 21 |

22 | skabus-rpc-daemon is a RPC mapper daemon, i.e. a 23 | long-lived program. 24 | It listens on a Unix domain socket, then 25 | accepts client connections. It allows clients to register interfaces 26 | and methods; it transmits queries from a client Q to the appropriate 27 | client R that can handle them; it then transmits the answer back to 28 | client Q. 29 |

30 | 31 |

Interface

32 | 33 |
 34 |      skabus-rpc-daemon [ -1 ] [ -v verbosity ] [ -D | -d ] [ -c maxconn ] [ -b backlog ] [ -G gidlist ] [ -g gid ] [ -u uid ] [ -U ] [ -t clienttimeout ] [ -T lameducktimeout ] [ -i rulesdir | -x rulesfile ] [ -S | -s ] [ -J | -j ] path
 35 | 
36 | 37 |
    38 |
  • skabus-rpc-daemon binds to the Unix domain socket at path.
  • 39 |
  • If applicable, it drops root privileges.
  • 40 |
  • It listens to its socket and accepts client connections.
  • 41 |
  • Clients are handled as described in the 42 | skabus-rpcd page.
  • 43 |
44 | 45 |

46 | skabus-rpc-daemon is just a wrapper that binds to its socket and drops 47 | privileges before executing into 48 | skabus-rpcd. For details of the daemon's 49 | operation, see the skabus-rpcd documentation. 50 |

51 | 52 |

Options

53 | 54 |
    55 |
  • -1 : write a newline to stdout, before 56 | closing it, right after binding and listening to the Unix socket. 57 | If stdout is suitably redirected, this can be used by monitoring 58 | programs to check when the server is ready to accept connections.
  • 59 |
  • -v verbosity : be quiet, normally 60 | verbose, or more verbose, depending on if verbosity is 0, 61 | 1, or more. The default is 1.
  • 62 |
  • -d : allow instant rebinding to the same path 63 | even if it has been used not long ago - this is the SO_REUSEADDR flag to 64 | setsockopt() 65 | and is generally used with server programs. This is the default. Note that 66 | path will be deleted if it already exists at program start time.
  • 67 |
  • -D : disallow instant rebinding to the same path.
  • 68 |
  • -c maxconn : accept at most 69 | maxconn concurrent client connections. Default is 40. It is 70 | impossible to set it higher than the value of the SKABUS_RPC_MAX macro, 71 | which is 1000. Client connections to this server are usually long-lived; 72 | make sure to correctly tune that number to your needs.
  • 73 |
  • -b backlog : set a maximum of 74 | backlog backlog connections on the socket. Extra 75 | connection attempts will rejected by the kernel.
  • 76 |
  • -G gidlist : change skabus-rpc-daemon's 77 | supplementary group list to gidlist after binding the socket. 78 | This is only valid when run as root. gidlist must be a 79 | comma-separated list of numerical group IDs.
  • 80 |
  • -g gid : change skabus-rpc-daemon's groupid 81 | to gid after binding the socket. This is only valid when run 82 | as root.
  • 83 |
  • -u uid : change skabus-rpc-daemon's userid 84 | to uid after binding the socket. This is only valid when run 85 | as root.
  • 86 |
  • -U : change skabus-rpc-daemon's user id, group id and 87 | supplementary group list 88 | according to the values of the UID, GID and GIDLIST environment variables 89 | after binding the socket. This is only valid when run as root. 90 | This can be used with the 91 | s6-envuidgid 92 | program to easily script a service that binds to a privileged socket 93 | then drops its privileges to those of a named non-root account.
  • 94 |
  • -t clienttimeout : disconnect a client 95 | if it's in the middle of an operation and it has not written or read any 96 | data in clienttimeout milliseconds. By default, clienttimeout 97 | is 0, which means infinite.
  • 98 |
  • -T lameducktimeout : give clients 99 | lameducktimeout milliseconds to finish their current operation 100 | before exiting after skabus-rpc-daemon has received a SIGTERM. By default, 101 | lameducktimeout is 0, which means infinite.
  • 102 |
  • -x rulesfile : read access rights 103 | configuration from CDB file rulesfile.
  • 104 |
  • -i rulesdir : read access rights 105 | configuration from the filesystem in directory rulesdir.
  • 106 |
  • -S : paranoid identification mode. Disallows 107 | unspecified clients from registering 108 | under any identifier. This is the default.
  • 109 |
  • -s : free registration. Allows unspecified clients 110 | to register with any identifier.
  • 111 |
  • -J : paranoid interface registration. Disallows 112 | unspecified clients from registering interfaces. This is the default.
  • 113 |
  • -j : free interface registration. Allows unspecified clients 114 | to register any interface name.
  • 115 |
116 | 117 |

Notes

118 | 119 |
    120 |
  • skabus-rpc-daemon does not interpret its options itself. It just 121 | dispatches them to the appropriate program on the command line that 122 | it builds.
  • 123 |
  • From the user's point of view, skabus-rpc-daemon behaves like a 124 | long-lived process, even if the long-lived process itself is called 125 | skabus-rpcd. Every operational detail 126 | of skabus-rpcd applies to skabus-rpc-daemon as well; in particular, 127 | make sure to properly 128 | configure the clients' 129 | access rights.
  • 130 |
  • skabus-rpc-daemon is meant to be used in a s6 run script, as 131 | a supervised local service. It does not fork itself or write to syslog. 132 | However, it can be run under any infrastructure, including other 133 | supervision infrastructures, OpenRC, systemd, or SysV scripts.
  • 134 |
135 | 136 | 137 | 138 | -------------------------------------------------------------------------------- /src/rpc/skabus_rpcd_query.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include "skabus-rpcd.h" 16 | 17 | static void *query_serial_dtok (uint32_t d, void *x) 18 | { 19 | (void)x ; 20 | return &QUERY(d)->serial ; 21 | } 22 | 23 | static void *query_deadline_dtok (uint32_t d, void *x) 24 | { 25 | (void)x ; 26 | return &QUERY(d)->deadline ; 27 | } 28 | 29 | static int query_serial_cmp (void const *a, void const *b, void *x) 30 | { 31 | uint64_t aa = *(uint64_t *)a ; 32 | uint64_t bb = *(uint64_t *)b ; 33 | (void)x ; 34 | return aa < bb ? -1 : aa > bb ; 35 | } 36 | 37 | static int query_deadline_cmp (void const *a, void const *b, void *x) 38 | { 39 | tain const *aa = (tain const *)a ; 40 | tain const *bb = (tain const *)b ; 41 | (void)x ; 42 | return tain_less(aa, bb) ? -1 : tain_less(bb, aa) ; 43 | } 44 | 45 | gensetdyn queries = GENSETDYN_ZERO ; 46 | static avltree qserialdict = AVLTREE_INIT(10, 1, 2, &query_serial_dtok, &query_serial_cmp, 0) ; 47 | static avltree qdeadlinedict = AVLTREE_INIT(10, 1, 2, &query_deadline_dtok, &query_deadline_cmp, 0) ; 48 | 49 | static inline void query_delete (uint32_t i) 50 | { 51 | if (!avltree_delete(&qdeadlinedict, &QUERY(i)->deadline)) 52 | strerr_diefu1sys(111, "avltree_delete qdeadlinedict in query_delete") ; 53 | if (!avltree_delete(&qserialdict, &QUERY(i)->serial)) 54 | strerr_diefu1sys(111, "avltree_delete qserialdict in query_delete") ; 55 | if (!gensetdyn_delete(&queries, i)) 56 | strerr_diefu1sys(111, "gensetdyn_delete in query_delete") ; 57 | } 58 | 59 | void query_remove (uint32_t i) 60 | { 61 | query_t *q = QUERY(i) ; 62 | client_t *c = CLIENT(q->client) ; 63 | interface_t *y = INTERFACE(q->interface) ; 64 | if (!gensetdyn_delete(&c->queries, q->clientindex)) 65 | strerr_diefu1sys(111, "gensetdyn_delete c->queries in query_remove") ; 66 | if (!gensetdyn_delete(&y->queries, q->interfaceindex)) 67 | strerr_diefu1sys(111, "gensetdyn_delete y->queries in query_remove") ; 68 | query_delete(i) ; 69 | } 70 | 71 | void query_fail (uint32_t i, unsigned char status) 72 | { 73 | query_t *q = QUERY(i) ; 74 | client_t *c = CLIENT(q->client) ; 75 | char pack[10] = "Rssssssssr" ; 76 | unixmessage m = { .s = pack, .len = 10, .fds = 0, .nfds = 0 } ; 77 | uint64_pack_big(pack+1, q->serial) ; 78 | pack[9] = status ; 79 | if (!unixmessage_put(&c->async.out, &m)) 80 | strerr_diefu1sys(111, "unixmessage_put in query_fail") ; 81 | query_remove(i) ; 82 | client_setdeadline(c) ; 83 | } 84 | 85 | int query_cancel (uint32_t i, unsigned char reason) 86 | { 87 | query_t *q = QUERY(i) ; 88 | interface_t *y = INTERFACE(q->interface) ; 89 | client_t *c = CLIENT(y->client) ; 90 | char pack[14] = "Ciiiissssssssr" ; 91 | unixmessage m = { .s = pack, .len = 14, .fds = 0, .nfds = 0 } ; 92 | uint32_pack_big(pack+1, y->id) ; 93 | uint64_pack_big(pack+5, q->serial) ; 94 | pack[13] = reason ; 95 | if (!unixmessage_put(&c->async.out, &m)) return 0 ; 96 | client_setdeadline(c) ; 97 | return 1 ; 98 | } 99 | 100 | int query_cancelremove (uint32_t i, unsigned char reason) 101 | { 102 | if (!query_cancel(i, reason)) return 0 ; 103 | query_remove(i) ; 104 | return 1 ; 105 | } 106 | 107 | int query_lookup_by_serial (uint64_t serial, uint32_t *d) 108 | { 109 | return avltree_search(&qserialdict, &serial, d) ; 110 | } 111 | 112 | int query_lookup_by_mindeadline (uint32_t *d) 113 | { 114 | return avltree_min(&qdeadlinedict, d) ; 115 | } 116 | 117 | void query_get_mindeadline (tain *deadline) 118 | { 119 | uint32_t d ; 120 | if (query_lookup_by_mindeadline(&d)) *deadline = QUERY(d)->deadline ; 121 | else tain_add_g(deadline, &tain_infinite_relative) ; 122 | } 123 | 124 | int query_add (uint32_t *d, tain const *deadline, uint32_t client, uint32_t interface) 125 | { 126 | static uint64_t serial = 1 ; 127 | uint32_t qq, cc, yy ; 128 | query_t *q ; 129 | if (!gensetdyn_new(&queries, &qq)) return 0 ; 130 | if (!gensetdyn_new(&CLIENT(client)->queries, &cc)) goto end0 ; 131 | if (!gensetdyn_new(&INTERFACE(interface)->queries, &yy)) goto end1 ; 132 | q = QUERY(qq) ; 133 | q->serial = serial ; 134 | q->deadline = *deadline ; 135 | q->client = client ; 136 | q->clientindex = cc ; 137 | q->interface = interface ; 138 | q->interfaceindex = yy ; 139 | if (!avltree_insert(&qserialdict, qq)) goto end2 ; 140 | for (;;) 141 | { 142 | static tain const nano1 = { .sec = TAI_ZERO, .nano = 1 } ; 143 | uint32_t d ; 144 | if (!avltree_search(&qdeadlinedict, &q->deadline, &d)) break ; 145 | tain_add(&q->deadline, &q->deadline, &nano1) ; 146 | } 147 | if (!avltree_insert(&qdeadlinedict, qq)) goto end3 ; 148 | serial++ ; 149 | *d = qq ; 150 | return 1 ; 151 | 152 | end3: 153 | if (!avltree_delete(&qserialdict, &serial)) 154 | strerr_diefu1sys(111, "avltree_delete in query_add") ; 155 | end2: 156 | if (!gensetdyn_delete(&INTERFACE(interface)->queries, yy)) 157 | strerr_diefu1sys(111, "gensetdyn_delete INTERFACE(interface)->queries in query_add") ; 158 | end1: 159 | if (!gensetdyn_delete(&CLIENT(client)->queries, cc)) 160 | strerr_diefu1sys(111, "gensetdyn_delete CLIENT(client)->queries in query_add") ; 161 | end0: 162 | if (!gensetdyn_delete(&queries, qq)) 163 | strerr_diefu1sys(111, "gensetdyn_delete queries in query_add") ; 164 | return 0 ; 165 | } 166 | 167 | int query_send (uint32_t qq, unixmessage const *m) 168 | { 169 | skabus_rpc_rinfo_t rinfo ; 170 | char pack[4 + SKABUS_RPC_RINFO_PACK] = "Q" ; 171 | struct iovec v[2] = { { .iov_base = pack, .iov_len = 4 + SKABUS_RPC_RINFO_PACK }, { .iov_base = m->s, .iov_len = m->len } } ; 172 | unixmessagev mtosend = { .v = v, .vlen = 2, .fds = m->fds, .nfds = m->nfds } ; 173 | query_t *q = QUERY(qq) ; 174 | interface_t *y = INTERFACE(q->interface) ; 175 | client_t *c = CLIENT(q->client) ; 176 | char const *idstr = client_idstr(c) ; 177 | size_t idstrlen = strlen(idstr) ; 178 | rinfo.serial = q->serial ; 179 | rinfo.limit = q->deadline ; 180 | tain_copynow(&rinfo.timestamp) ; 181 | rinfo.uid = c->uid ; 182 | rinfo.gid = c->gid ; 183 | memcpy(rinfo.idstr, idstr, idstrlen) ; 184 | memset(rinfo.idstr + idstrlen, 0, SKABUS_RPC_IDSTR_SIZE + 1 - idstrlen) ; 185 | uint32_pack_big(pack+1, y->id) ; 186 | skabus_rpc_rinfo_pack(pack + 5, &rinfo) ; 187 | c = CLIENT(y->client) ; 188 | if (!unixmessage_putv_and_close(&c->async.out, &mtosend, unixmessage_bits_closeall)) return 0 ; 189 | client_setdeadline(c) ; 190 | return 1 ; 191 | } 192 | 193 | void query_reply (uint32_t qq, char result, unixmessage const *m) 194 | { 195 | char pack[11] = "R" ; 196 | struct iovec v[2] = { { .iov_base = pack, .iov_len = 11 }, { .iov_base = m->s, .iov_len = m->len } } ; 197 | unixmessagev mtosend = { .v = v, .vlen = 2, .fds = m->fds, .nfds = m->nfds } ; 198 | query_t *q = QUERY(qq) ; 199 | client_t *c = CLIENT(q->client) ; 200 | uint64_pack_big(pack+1, q->serial) ; 201 | pack[9] = 0 ; 202 | pack[10] = result ; 203 | if (!unixmessage_putv_and_close(&c->async.out, &mtosend, unixmessage_bits_closeall)) 204 | strerr_diefu1sys(111, "unixmessage_put in query_reply") ; 205 | client_setdeadline(c) ; 206 | query_remove(qq) ; 207 | } 208 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | Build Instructions 2 | ------------------ 3 | 4 | * Requirements 5 | ------------ 6 | 7 | - A POSIX-compliant C development environment 8 | - GNU make version 3.81 or later 9 | - skalibs version 2.14.5.0 or later: http://skarnet.org/software/skalibs/ 10 | - execline version 2.9.8.0 or later: http://skarnet.org/software/execline/ 11 | - s6 version 2.13.3.0 or later: http://skarnet.org/software/s6/ 12 | 13 | This software will run on any operating system that implements 14 | POSIX.1-2024, available at: 15 | http://pubs.opengroup.org/onlinepubs/9799919799/ 16 | 17 | 18 | * Standard usage 19 | -------------- 20 | 21 | ./configure && make && sudo make install 22 | 23 | will work for most users. 24 | It will install the binaries in /bin and the static libraries in /usr/lib. 25 | 26 | You can strip the binaries and libraries of their extra symbols via 27 | "make strip" before the "make install" phase. It will shave a few bytes 28 | off them. 29 | 30 | 31 | * pkg-config 32 | ---------- 33 | 34 | pkg-config is a tool used by some Linux and BSD distributions, providing 35 | a registry to store policy information about libraries exported by a 36 | software package; that is supposed to make it easier to build software 37 | depending on these libraries, by having a tool to automatically extract 38 | the various flags to pass to the compiler and linker in order to correctly 39 | build against these libraries. 40 | This package supports pkg-config, but you need to explicitly ask for it: 41 | - To use the pkg-config tool to *read* information from the registry and 42 | use it to build *this* package: --with-pkgconfig[=PROG]. This assumes 43 | PROG supports the pkg-config interface (as the popular pkgconf 44 | implementation does). If PROG is not supplied, the PKG_CONFIG environment 45 | variable is used to find the program to use, and if empty/unset, it defaults 46 | to pkg-config. 47 | - To build a .pc file for each library exported by this package, and then 48 | install it to the pkg-config registry, in other words to *write* information 49 | so that other software can use pkg-config to build against this package, 50 | use --enable-pkgconfig. 51 | 52 | pkg-config and slashpackage (see below) configure options can be set 53 | together, but the slashpackage convention provides its own installation 54 | policies that generally make it unnecessary to use pkg-config. You 55 | probably should not mix both. 56 | 57 | 58 | * Customization 59 | ------------- 60 | 61 | You can customize paths via flags given to configure. 62 | See ./configure --help for a list of all available configure options. 63 | 64 | 65 | * Environment variables 66 | --------------------- 67 | 68 | Controlling a build process via environment variables is a big and 69 | dangerous hammer. You should try and pass flags to configure instead; 70 | nevertheless, a few standard environment variables are recognized. 71 | 72 | If the CC environment variable is set, its value will override compiler 73 | detection by configure. The --host=HOST option will still add a HOST- 74 | prefix to the value of CC. 75 | 76 | The values of CFLAGS, CPPFLAGS and LDFLAGS will be appended to flags 77 | auto-detected by configure. To entirely override the flags set by 78 | configure instead, use make variables. 79 | 80 | 81 | * Make variables 82 | -------------- 83 | 84 | You can invoke make with a few variables for more configuration. 85 | 86 | CC, CFLAGS, CPPFLAGS, LDFLAGS, LDLIBS, AR, RANLIB, STRIP, INSTALL and 87 | CROSS_COMPILE can all be overridden on the make command line. This is 88 | an even bigger hammer than running ./configure with environment 89 | variables, so it is advised to only do this when it is the only way of 90 | obtaining the behaviour you want. 91 | 92 | DESTDIR can be given on the "make install" command line in order to 93 | install to a staging directory. 94 | 95 | 96 | * Shared libraries 97 | ---------------- 98 | 99 | Software from skarnet.org is small enough that shared libraries are 100 | generally not worth using. Static linking is simpler and incurs less 101 | runtime overhead and less points of failure: so by default, shared 102 | libraries are not built and binaries are linked against the static 103 | versions of the skarnet.org libraries. Nevertheless, you can: 104 | * build shared libraries: --enable-shared 105 | * link binaries against shared libraries: --disable-allstatic 106 | 107 | 108 | * Static binaries 109 | --------------- 110 | 111 | By default, binaries are linked against static versions of all the 112 | libraries they depend on, except for the libc. You can enforce 113 | linking against the static libc with --enable-static-libc. 114 | 115 | (If you are using a GNU/Linux system, be aware that the GNU libc 116 | behaves badly with static linking and produces huge executables, 117 | which is why it is not the default. Other libcs are better suited 118 | to static linking, for instance musl: http://musl-libc.org/) 119 | 120 | 121 | * Cross-compilation 122 | ----------------- 123 | 124 | skarnet.org packages centralize all the difficulty of 125 | cross-compilation in one place: skalibs. Once you have 126 | cross-compiled skalibs, the rest is easy. 127 | 128 | * Use the --host=HOST option to configure, HOST being the triplet 129 | for your target. 130 | * Make sure your cross-toolchain binaries (i.e. prefixed with HOST-) 131 | are accessible via your PATH environment variable. 132 | * Make sure to use the correct version of skalibs for your target, 133 | and the correct sysdeps directory, making use of the 134 | --with-include, --with-lib, --with-dynlib and --with-sysdeps 135 | options as necessary. 136 | 137 | 138 | * The slashpackage convention 139 | --------------------------- 140 | 141 | The slashpackage convention (http://cr.yp.to/slashpackage.html) 142 | is a package installation scheme that provides a few guarantees 143 | over other conventions such as the FHS, for instance fixed 144 | absolute pathnames. skarnet.org packages support it: use the 145 | --enable-slashpackage option to configure, or 146 | --enable-slashpackage=DIR for a prefixed DIR/package tree. 147 | This option will activate slashpackage support during the build 148 | and set slashpackage-compatible installation directories. 149 | If $package_home is the home of the package, defined as 150 | DIR/package/$category/$package-$version with the variables 151 | read from the package/info file, then: 152 | 153 | --dynlibdir is set to $package_home/library.so 154 | --bindir is set to $package_home/command 155 | --sbindir is also set to $package_home/command (slashpackage 156 | differentiates root-only binaries by their Unix rights, not their 157 | location in the filesystem) 158 | --libexecdir is also set to $package_home/command (slashpackage 159 | does not need a specific directory for internal binaries) 160 | --libdir is set to $package_home/library 161 | --includedir is set to $package_home/include 162 | 163 | --prefix is pretty much ignored when you use --enable-slashpackage. 164 | You should probably not use both --enable-slashpackage and --prefix. 165 | 166 | When using slashpackage, two additional Makefile targets are 167 | available after "make install": 168 | - "make update" changes the default version of the software to the 169 | freshly installed one. (This is useful when you have several installed 170 | versions of the same software, which slashpackage supports.) 171 | - "make -L global-links" adds links from /command and /library.so to the 172 | default version of the binaries and shared libraries. The "-L" option to 173 | make is necessary because targets are symbolic links, and the default make 174 | behaviour is to check the pointed file's timestamp and not the symlink's 175 | timestamp. 176 | 177 | 178 | * Absolute pathnames 179 | ------------------ 180 | 181 | You may want to use fixed absolute pathnames even if you're not 182 | following the slashpackage convention: for instance, the Nix packaging 183 | system prefers calling binaries with immutable paths rather than rely on 184 | PATH resolution. If you are in that case, use the --enable-absolute-paths 185 | option to configure. This will ensure that programs calling binaries from 186 | this package will call them with their full installation path (in bindir) 187 | without relying on a PATH search. 188 | 189 | 190 | * Out-of-tree builds 191 | ------------------ 192 | 193 | skarnet.org packages do not support out-of-tree builds. They 194 | are small, so it does not cost much to duplicate the entire 195 | source tree if parallel builds are needed. 196 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # This Makefile requires GNU make. 3 | # 4 | # Do not make changes here. 5 | # Use the included .mak files. 6 | # 7 | 8 | it: all 9 | 10 | make_need := 3.81 11 | ifeq "" "$(strip $(filter $(make_need), $(firstword $(sort $(make_need) $(MAKE_VERSION)))))" 12 | fail := $(error Your make ($(MAKE_VERSION)) is too old. You need $(make_need) or newer) 13 | endif 14 | 15 | uniq = $(if $1,$(firstword $1) $(call uniq,$(filter-out $(firstword $1),$1))) 16 | 17 | CC = $(error Please use ./configure first) 18 | 19 | STATIC_LIBS := 20 | SHARED_LIBS := 21 | INTERNAL_LIBS := 22 | EXTRA_TARGETS := 23 | PC_TARGETS := 24 | LIB_DEFS := 25 | BIN_SYMLINKS := 26 | TEST_BINS := 27 | 28 | -include config.mak 29 | include package/targets.mak 30 | 31 | define library_definition 32 | LIB$(1) := lib$(2).$(if $(DO_ALLSTATIC),a,$(SHLIB_EXT)).xyzzy 33 | ifdef DO_SHARED 34 | SHARED_LIBS += lib$(2).$(SHLIB_EXT).xyzzy 35 | endif 36 | ifdef DO_STATIC 37 | STATIC_LIBS += lib$(2).a.xyzzy 38 | endif 39 | ifdef DO_PKGCONFIG 40 | PC_TARGETS += lib$(2).pc 41 | endif 42 | 43 | lib$(2).pc: 44 | exec env \ 45 | library="$(2)" \ 46 | includedir="$(includedir)" \ 47 | dynlibdir="$(dynlibdir)" \ 48 | libdir="$(libdir)" \ 49 | extra_includedirs="$(extra_includedirs)" \ 50 | extra_libdirs="$(extra_libdirs)" \ 51 | extra_libs="$$(strip $$(EXTRA_LIBS))" \ 52 | description="$$($(1)_DESCRIPTION)" \ 53 | url="$$($(1)_URL)" \ 54 | ldlibs="$(LDLIBS)" \ 55 | ./tools/gen-dotpc.sh > $$@.tmp 56 | exec mv -f $$@.tmp $$@ 57 | 58 | endef 59 | 60 | define binary_installation_rule 61 | $(DESTDIR)$(1)/$(2): ./$(2) package/modes 62 | exec $(INSTALL) -D -m 600 $$< $$@ 63 | grep -- ^$$(@F) < package/modes | { read name mode owner && \ 64 | if [ x$$$$owner != x ] ; then chown -- $$$$owner $$@ ; fi && \ 65 | chmod $$$$mode $$@ ; } 66 | endef 67 | 68 | define symlink_installation_rule 69 | $(DESTDIR)$(1)/$(2): $(DESTDIR)$(1)/$(SYMLINK_TARGET_$(2)) 70 | exec $(INSTALL) -l $$( $$package-$$version.tar.gz.sha256 && \ 116 | exec rm -rf /tmp/$$package-$$version 117 | 118 | strip: $(ALL_LIBS) $(ALL_BINS) 119 | ifneq ($(strip $(STATIC_LIBS)),) 120 | exec $(STRIP) -x -R .note -R .comment $(STATIC_LIBS) 121 | endif 122 | ifneq ($(strip $(ALL_BINS)$(SHARED_LIBS)),) 123 | exec $(STRIP) -R .note -R .comment $(ALL_BINS) $(SHARED_LIBS) 124 | endif 125 | 126 | install: install-dynlib install-libexec install-bin install-symlinks install-lib install-include install-pkgconfig 127 | install-dynlib: $(SHARED_LIBS:lib%.$(SHLIB_EXT).xyzzy=$(DESTDIR)$(dynlibdir)/lib%.$(SHLIB_EXT)) 128 | install-libexec: $(LIBEXEC_TARGETS:%=$(DESTDIR)$(libexecdir)/%) 129 | install-bin: $(BIN_TARGETS:%=$(DESTDIR)$(bindir)/%) 130 | install-symlinks: $(BIN_SYMLINKS:%=$(DESTDIR)$(bindir)/%) 131 | install-lib: $(STATIC_LIBS:lib%.a.xyzzy=$(DESTDIR)$(libdir)/lib%.a) 132 | install-include: $(ALL_INCLUDES:src/include/$(package)/%.h=$(DESTDIR)$(includedir)/$(package)/%.h) $(EXTRA_INCLUDES:src/include/%.h=$(DESTDIR)$(includedir)/%.h) 133 | install-pkgconfig: $(PC_TARGETS:%=$(DESTDIR)$(pkgconfdir)/%) 134 | 135 | tests: $(TEST_BINS) 136 | 137 | check: tests 138 | @for i in $(TEST_BINS) ; do ./tools/run-test.sh $$i || exit 1 ; done 139 | 140 | ifneq ($(exthome),) 141 | 142 | $(DESTDIR)$(exthome): $(DESTDIR)$(home) 143 | exec $(INSTALL) -l $(notdir $(home)) $(DESTDIR)$(exthome) 144 | 145 | update: $(DESTDIR)$(exthome) 146 | 147 | global-links: $(DESTDIR)$(exthome) $(SHARED_LIBS:lib%.so.xyzzy=$(DESTDIR)$(sproot)/library.so/lib%.so.$(version_M)) $(BIN_TARGETS:%=$(DESTDIR)$(sproot)/command/%) $(BIN_SYMLINKS:%=$(DESTDIR)$(sproot)/command/%) 148 | 149 | $(DESTDIR)$(sproot)/command/%: $(DESTDIR)$(home)/command/% 150 | exec $(INSTALL) -D -l ..$(subst $(sproot),,$(exthome))/command/$( 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | 18 | /* Misc constants */ 19 | 20 | #define SKABUS_PUB_MAX 4000 21 | #define SKABUS_PUB_MAXFDS 4000 22 | #define SKABUS_PUB_BANNER1 "skabus_pub v1.0 (b)\n" 23 | #define SKABUS_PUB_BANNER1_LEN (sizeof SKABUS_PUB_BANNER1 - 1) 24 | #define SKABUS_PUB_BANNER2 "skabus_pub v1.0 (a)\n" 25 | #define SKABUS_PUB_BANNER2_LEN (sizeof SKABUS_PUB_BANNER2 - 1) 26 | #define SKABUS_PUB_IDSTR_SIZE 254 27 | 28 | 29 | /* skabus_pub auxiliary data */ 30 | 31 | typedef struct skabus_pub_msginfo_s skabus_pub_msginfo_t, *skabus_pub_msginfo_t_ref ; 32 | struct skabus_pub_msginfo_s 33 | { 34 | uint64_t serial ; 35 | tain timestamp ; 36 | uint8_t flags ; 37 | char sender[SKABUS_PUB_IDSTR_SIZE + 1] ; 38 | } ; 39 | #define SKABUS_PUB_MSGINFO_ZERO { .serial = 0, .timestamp = TAIN_ZERO, .flags = 0, .sender = "" } 40 | 41 | 42 | /* internal client message storage */ 43 | 44 | typedef struct skabus_pub_cltinfo_s skabus_pub_cltinfo_t, *skabus_pub_cltinfo_t_ref ; 45 | struct skabus_pub_cltinfo_s 46 | { 47 | skabus_pub_msginfo_t msginfo ; 48 | int fd ; 49 | size_t nfds ; 50 | int *fds ; 51 | } ; 52 | #define SKABUS_PUB_CLTINFO_ZERO { .msginfo = SKABUS_PUB_MSGINFO_ZERO, .fd = -1, .nfds = 0, .fds = 0 } 53 | 54 | 55 | /* skabus_pub client connection */ 56 | 57 | typedef struct skabus_pub_s skabus_pub_t, *skabus_pub_t_ref ; 58 | struct skabus_pub_s 59 | { 60 | skaclient connection ; 61 | genalloc info ; /* array of skabus_pub_cltinfo_t */ 62 | size_t head ; 63 | skaclient_buffer buffers ; 64 | } ; 65 | #define SKABUS_PUB_ZERO { .connection = SKACLIENT_ZERO, .info = GENALLOC_ZERO, .head = 0 } 66 | 67 | 68 | /* Starting and ending a session */ 69 | 70 | typedef struct skabus_pub_start_result_s skabus_pub_start_result_t, *skabus_pub_start_result_t_ref ; 71 | struct skabus_pub_start_result_s 72 | { 73 | skaclient_cbdata skaclient_cbdata ; 74 | } ; 75 | 76 | #define skabus_pub_init(a, path, id, sre, wre, deadline, stamp) (skabus_pub_start(a, path, deadline, stamp) && skabus_pub_register(a, id, sre, wre, deadline, stamp)) 77 | #define skabus_pub_init_g(a, path, id, sre, wre, deadline) skabus_pub_init(a, path, id, sre, wre, (deadline), &STAMP) 78 | 79 | extern int skabus_pub_start_async (skabus_pub_t *, char const *, skabus_pub_start_result_t *) ; 80 | extern int skabus_pub_start (skabus_pub_t *, char const *, tain const *, tain *) ; 81 | #define skabus_pub_start_g(a, path, deadline) skabus_pub_start(a, path, (deadline), &STAMP) 82 | 83 | extern int skabus_pub_register_async (skabus_pub_t *, char const *, char const *, char const *, unsigned char *) ; 84 | extern int skabus_pub_register (skabus_pub_t *, char const *, char const *, char const *, tain const *, tain *) ; 85 | #define skabus_pub_register_g(a, id, sre, wre, deadline) skabus_pub_register(a, id, sre, wre, (deadline), &STAMP) 86 | 87 | extern void skabus_pub_end (skabus_pub_t *) ; 88 | 89 | 90 | /* Reading messages */ 91 | 92 | #define skabus_pub_fd(a) skaclient_fd(&(a)->connection) 93 | extern int skabus_pub_update (skabus_pub_t *) ; 94 | extern int skabus_pub_message_getnfds (skabus_pub_t const *) ; 95 | extern size_t skabus_pub_message_get (skabus_pub_t *, skabus_pub_msginfo_t *, int *, int *) ; 96 | 97 | 98 | /* Sending public messages */ 99 | 100 | typedef struct skabus_pub_send_result_s skabus_pub_send_result_t, *skabus_pub_send_result_t_ref ; 101 | struct skabus_pub_send_result_s 102 | { 103 | uint64_t u ; 104 | unsigned char err ; 105 | } ; 106 | 107 | extern int skabus_pub_send_withfds_async (skabus_pub_t *, char const *, size_t, int const *, unsigned int, unsigned char const *, skabus_pub_send_result_t *) ; 108 | #define skabus_pub_send_async(a, s, len, res) skabus_pub_send_withfds_async(a, s, len, 0, 0, unixmessage_bits_closenone, res) 109 | 110 | extern uint64_t skabus_pub_send_withfds (skabus_pub_t *, char const *, size_t, int const *, unsigned int, unsigned char const *, tain const *, tain *) ; 111 | #define skabus_pub_send_withfds_g(a, s, len, fds, nfds, bits, deadline) skabus_pub_send_withfds(a, s, len, fds, nfds, bits, (deadline), &STAMP) 112 | #define skabus_pub_send(a, s, len, deadline, stamp) skabus_pub_send_withfds(a, s, len, 0, 0, unixmessage_bits_closenone, deadline, stamp) 113 | #define skabus_pub_send_g(a, s, len, deadline) skabus_pub_send(a, s, len, (deadline), &STAMP) 114 | 115 | extern int skabus_pub_sendv_withfds_async (skabus_pub_t *, struct iovec const *, unsigned int, int const *, unsigned int, unsigned char const *, skabus_pub_send_result_t *) ; 116 | #define skabus_pub_sendv_async(a, v, vlen, res) skabus_pub_sendv_withfds_async(a, v, vlen, 0, 0, unixmessage_bits_closenone, res) 117 | 118 | extern uint64_t skabus_pub_sendv_withfds (skabus_pub_t *, struct iovec const *, unsigned int, int const *, unsigned int, unsigned char const *, tain const *, tain *) ; 119 | #define skabus_pub_sendv_withfds_g(a, v, vlen, fds, nfds, bits, deadline) skabus_pub_sendv_withfds(a, v, vlen, fds, nfds, bits, (deadline), &STAMP) 120 | #define skabus_pub_sendv(a, v, vlen, deadline, stamp) skabus_pub_sendv_withfds(a, v, vlen, 0, 0, unixmessage_bits_closenone, deadline, stamp) 121 | #define skabus_pub_sendv_g(a, v, vlen, deadline) skabus_pub_sendv(a, v, vlen, (deadline), &STAMP) 122 | 123 | 124 | /* Sending private messages */ 125 | 126 | extern int skabus_pub_sendpm_withfds_async (skabus_pub_t *, char const *, char const *, size_t, int const *, unsigned int, unsigned char const *, skabus_pub_send_result_t *) ; 127 | #define skabus_pub_sendpm_async(a, id, s, len, res) skabus_pub_sendpm_withfds_async(a, id, s, len, 0, 0, unixmessage_bits_closenone, res) 128 | 129 | extern uint64_t skabus_pub_sendpm_withfds (skabus_pub_t *, char const *, char const *, size_t, int const *, unsigned int, unsigned char const *, tain const *, tain *) ; 130 | #define skabus_pub_sendpm_withfds_g(a, id, s, len, fds, nfds, bits, deadline) skabus_pub_sendpm_withfds(a, id, s, len, fds, nfds, bits, (deadline), &STAMP) 131 | #define skabus_pub_sendpm(a, id, s, len, deadline, stamp) skabus_pub_sendpm_withfds(a, id, s, len, 0, 0, unixmessage_bits_closenone, deadline, stamp) 132 | #define skabus_pub_sendpm_g(a, id, s, len, deadline) skabus_pub_sendpm(a, id, s, len, (deadline), &STAMP) 133 | 134 | extern int skabus_pub_sendvpm_withfds_async (skabus_pub_t *, char const *, struct iovec const *, unsigned int, int const *, unsigned int, unsigned char const *, skabus_pub_send_result_t *) ; 135 | #define skabus_pub_sendvpm_async(a, id, v, vlen, res) skabus_pub_sendvpm_withfds_async(a, id, v, vlen, 0, 0, unixmessage_bits_closenone, res) 136 | 137 | extern uint64_t skabus_pub_sendvpm_withfds (skabus_pub_t *, char const *, struct iovec const *, unsigned int, int const *, unsigned int, unsigned char const *, tain const *, tain *) ; 138 | #define skabus_pub_sendvpm_withfds_g(a, id, v, vlen, fds, nfds, bits, deadline) skabus_pub_sendvpm_withfds(a, id, v, vlen, fds, nfds, bits, (deadline), &STAMP) 139 | #define skabus_pub_sendvpm(a, id, v, vlen, deadline, stamp) skabus_pub_sendvpm_withfds(a, id, v, vlen, 0, 0, unixmessage_bits_closenone, deadline, stamp) 140 | #define skabus_pub_sendvpm_g(a, id, v, vlen, deadline) skabus_pub_sendvpm(a, id, v, vlen, (deadline), &STAMP) 141 | 142 | 143 | /* Subscribing to a sender */ 144 | 145 | extern int skabus_pub_subunsub_async (skabus_pub_t *, char, char const *, unsigned char *) ; 146 | #define skabus_pub_subscribe_async(a, id, err) skabus_pub_subunsub_async(a, 'S', id, err) 147 | #define skabus_pub_unsubscribe_async(a, id, err) skabus_pub_subunsub_async(a, 'U', id, err) 148 | extern int skabus_pub_subunsub (skabus_pub_t *, char, char const *, tain const *, tain *) ; 149 | #define skabus_pub_subscribe(a, id, deadline, stamp) skabus_pub_subunsub(a, 'S', id, deadline, stamp) 150 | #define skabus_pub_subscribe_g(a, id, deadline) skabus_pub_subscribe(a, id, (deadline), &STAMP) 151 | #define skabus_pub_unsubscribe(a, id, deadline, stamp) skabus_pub_subunsub(a, 'U', id, deadline, stamp) 152 | #define skabus_pub_unsubscribe_g(a, id, deadline) skabus_pub_unsubscribe(a, id, (deadline), &STAMP) 153 | 154 | 155 | /* Listing all clients */ 156 | 157 | typedef struct skabus_pub_list_result_s skabus_pub_list_result_t, *skabus_pub_list_result_t_ref ; 158 | struct skabus_pub_list_result_s 159 | { 160 | stralloc *sa ; 161 | diuint32 n ; 162 | unsigned char err ; 163 | } ; 164 | 165 | extern int skabus_pub_list_async (skabus_pub_t *, stralloc *, skabus_pub_list_result_t *) ; 166 | extern int skabus_pub_list (skabus_pub_t *, stralloc *, diuint32 *, tain const *, tain *) ; 167 | #define skabus_pub_list_g(a, sa, deadline) skabus_pub_list(a, sa, (deadline), &STAMP) 168 | 169 | #endif 170 | -------------------------------------------------------------------------------- /src/misc/skabus-dynteed.c: -------------------------------------------------------------------------------- 1 | /* ISC license. */ 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include /* shutdown */ 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include 30 | 31 | #define USAGE "skabus-dynteed [ -d fdsocket ] [ -c maxconn ] [ -1 ] [ -t timeout ] [ -T lameducktimeout ] [ -i rulesdir | -x rulesfile ]" 32 | #define dieusage() strerr_dieusage(100, USAGE) ; 33 | #define dienomem() strerr_diefu1sys(111, "stralloc_catb") ; 34 | #define die() strerr_dief1sys(101, "unexpected error") ; 35 | 36 | #define SKABUS_DYNTEE_MAX 1000 37 | 38 | static int cont = 1 ; 39 | static tain lameduckdeadline ; 40 | 41 | static unsigned int rulestype = 0 ; 42 | static char const *rules = 0 ; 43 | static cdb cdbmap = CDB_ZERO ; 44 | 45 | typedef struct client_s client_t, *client_t_ref ; 46 | struct client_s 47 | { 48 | unsigned int xindex ; 49 | tain deadline ; 50 | bufalloc ba ; 51 | } ; 52 | 53 | static void client_free (client_t *c) 54 | { 55 | fd_close(bufalloc_fd(&c->ba)) ; 56 | bufalloc_free(&c->ba) ; 57 | } 58 | 59 | static void handle_signals (void) 60 | { 61 | for (;;) switch (selfpipe_read()) 62 | { 63 | case -1 : strerr_diefu1sys(111, "selfpipe_read()") ; 64 | case 0 : return ; 65 | case SIGTERM : 66 | { 67 | if (cont) 68 | { 69 | cont = 0 ; 70 | tain_add_g(&lameduckdeadline, &lameduckdeadline) ; 71 | } 72 | break ; 73 | } 74 | case SIGHUP : 75 | { 76 | cdb c = CDB_ZERO ; 77 | if (rulestype != 2) break ; 78 | if (!cdb_init(&c, rules)) break ; 79 | cdb_free(&cdbmap) ; 80 | cdbmap = c ; 81 | } 82 | break ; 83 | default : break ; 84 | } 85 | } 86 | 87 | static inline int new_connection (int fd) 88 | { 89 | s6_accessrules_params_t params = S6_ACCESSRULES_PARAMS_ZERO ; 90 | uid_t uid ; 91 | gid_t gid ; 92 | if (!rulestype) return 1 ; 93 | if (getpeereid(fd, &uid, &gid) < 0) 94 | { 95 | strerr_warnwu1sys("getpeereid") ; 96 | return 0 ; 97 | } 98 | if ((rulestype == 1 ? s6_accessrules_uidgid_fs(uid, gid, rules, ¶ms) : s6_accessrules_uidgid_cdb(uid, gid, &cdbmap, ¶ms)) != S6_ACCESSRULES_ALLOW) 99 | return 0 ; 100 | s6_accessrules_params_free(¶ms) ; 101 | return 1 ; 102 | } 103 | 104 | int main (int argc, char const *const *argv, char const *const *envp) 105 | { 106 | tain readtto ; 107 | int flag1 = 0 ; 108 | unsigned int maxconn = 40 ; 109 | unsigned int fdsocket = 3 ; 110 | PROG = "skabus-dynteed" ; 111 | 112 | { 113 | subgetopt l = SUBGETOPT_ZERO ; 114 | unsigned int t = 0, T = 0 ; 115 | for (;;) 116 | { 117 | int opt = subgetopt_r(argc, argv, "d:1c:i:x:t:T:", &l) ; 118 | if (opt == -1) break ; 119 | switch (opt) 120 | { 121 | case 'd' : if (!uint0_scan(l.arg, &fdsocket)) dieusage() ; break ; 122 | case '1' : flag1 = 1 ; break ; 123 | case 'i' : rules = l.arg ; rulestype = 1 ; break ; 124 | case 'x' : rules = l.arg ; rulestype = 2 ; break ; 125 | case 't' : if (!uint0_scan(l.arg, &t)) dieusage() ; break ; 126 | case 'T' : if (!uint0_scan(l.arg, &T)) dieusage() ; break ; 127 | case 'c' : if (!uint0_scan(l.arg, &maxconn)) dieusage() ; break ; 128 | default : dieusage() ; 129 | } 130 | } 131 | argc -= l.ind ; argv += l.ind ; 132 | if (t) tain_from_millisecs(&readtto, t) ; 133 | else readtto = tain_infinite_relative ; 134 | if (T) tain_from_millisecs(&lameduckdeadline, T) ; 135 | else lameduckdeadline = tain_infinite_relative ; 136 | } 137 | if (maxconn > SKABUS_DYNTEE_MAX) maxconn = SKABUS_DYNTEE_MAX ; 138 | if (!maxconn) maxconn = 1 ; 139 | { 140 | struct stat st ; 141 | if (fstat(fdsocket, &st) < 0) strerr_diefu1sys(111, "fstat socket descriptor") ; 142 | if (!S_ISSOCK(st.st_mode)) strerr_dief1x(100, "descriptor is not a socket") ; 143 | } 144 | if (flag1) 145 | { 146 | if (fcntl(1, F_GETFD) < 0) 147 | strerr_dief1sys(100, "called with option -1 but stdout said") ; 148 | } 149 | else close(1) ; 150 | if (ndelay_on(0) < 0) strerr_diefu1sys(111, "set stdin non-blocking") ; 151 | if (selfpipe_init() == -1) strerr_diefu1sys(111, "selfpipe_init") ; 152 | if (!sig_ignore(SIGPIPE)) strerr_diefu1sys(111, "ignore SIGPIPE") ; 153 | { 154 | sigset_t set ; 155 | sigemptyset(&set) ; 156 | sigaddset(&set, SIGTERM) ; 157 | sigaddset(&set, SIGHUP) ; 158 | if (!selfpipe_trapset(&set)) strerr_diefu1sys(111, "trap signals") ; 159 | } 160 | 161 | if (rulestype == 2) 162 | { 163 | if (!cdb_init(&cdbmap, rules)) 164 | strerr_diefu2sys(111, "cdb_init ", rules) ; 165 | } 166 | 167 | { 168 | unsigned int numconn = 0 ; 169 | client_t clients[maxconn] ; 170 | 171 | if (flag1) 172 | { 173 | fd_write(1, "\n", 1) ; 174 | fd_close(1) ; 175 | } 176 | tain_now_set_stopwatch_g() ; 177 | 178 | for (;;) 179 | { 180 | tain deadline ; 181 | int r = 2 ; 182 | iopause_fd x[2 + cont + numconn] ; 183 | x[0].fd = selfpipe_fd() ; 184 | x[0].events = IOPAUSE_READ ; 185 | x[1].fd = fdsocket ; 186 | x[1].events = (cont && (numconn < maxconn)) ? IOPAUSE_READ : 0 ; 187 | if (cont) 188 | { 189 | tain_add_g(&deadline, &tain_infinite_relative) ; 190 | x[2].fd = 0 ; 191 | x[2].events = IOPAUSE_READ ; 192 | r++ ; 193 | } 194 | else deadline = lameduckdeadline ; 195 | for (unsigned int i = 0 ; i < numconn ; i++) if (bufalloc_len(&clients[i].ba)) 196 | { 197 | if (tain_less(&clients[i].deadline, &deadline)) deadline = clients[i].deadline ; 198 | x[r].fd = bufalloc_fd(&clients[i].ba) ; 199 | x[r].events = IOPAUSE_WRITE ; 200 | clients[i].xindex = r++ ; 201 | } 202 | 203 | r = iopause_g(x, r, &deadline) ; 204 | if (r < 0) strerr_diefu1sys(111, "iopause") ; 205 | 206 | if (!r) 207 | { 208 | for (unsigned int i = 0 ; i < numconn ; i++) 209 | { 210 | if (bufalloc_len(&clients[i].ba) && !tain_future(&clients[i].deadline)) 211 | { 212 | client_free(clients + i) ; 213 | clients[i--] = clients[--numconn] ; 214 | } 215 | } 216 | if (!(cont || (numconn && tain_future(&lameduckdeadline)))) break ; 217 | continue ; 218 | } 219 | 220 | if (x[0].revents & IOPAUSE_READ) handle_signals() ; 221 | 222 | for (unsigned int i = 0 ; i < numconn ; i++) if (bufalloc_len(&clients[i].ba)) 223 | { 224 | if (x[clients[i].xindex].revents & (IOPAUSE_WRITE | IOPAUSE_EXCEPT)) 225 | { 226 | if (!bufalloc_flush(&clients[i].ba) && !error_isagain(errno)) 227 | { 228 | client_free(clients + i) ; 229 | clients[i--] = clients[--numconn] ; 230 | } 231 | } 232 | } 233 | 234 | if (cont && x[1].revents & IOPAUSE_READ) 235 | { 236 | int fd = ipc_accept_nb(fdsocket, 0, 0, 0) ; 237 | if (fd < 0) 238 | { 239 | if (!error_isagain(errno)) strerr_diefu1sys(111, "accept") ; 240 | } 241 | else if (!new_connection(fd)) fd_close(fd) ; 242 | else if (shutdown(fd, SHUT_RD) < 0) 243 | { 244 | fd_close(fd) ; 245 | strerr_warnwu1sys("shutdown client connection for reading - aborting it") ; 246 | } 247 | else 248 | { 249 | bufalloc_init(&clients[numconn].ba, &fd_write, fd) ; 250 | tain_copynow(&clients[numconn].deadline) ; 251 | numconn++ ; 252 | } 253 | } 254 | 255 | if (cont && x[2].revents & IOPAUSE_READ) 256 | { 257 | ssize_t r = sanitize_read(buffer_fill(buffer_0)) ; 258 | if (r < 0) 259 | { 260 | fd_close(0) ; 261 | cont = 0 ; 262 | tain_add_g(&lameduckdeadline, &lameduckdeadline) ; 263 | if (errno != EPIPE) strerr_warnwu1sys("read from stdin") ; 264 | } 265 | if (r > 0) 266 | { 267 | struct iovec v[2] ; 268 | buffer_rpeek(buffer_0, v) ; 269 | for (unsigned int i = 0 ; i < numconn ; i++) 270 | { 271 | if (!bufalloc_putv(&clients[i].ba, v, 2)) dienomem() ; 272 | if (!tain_future(&clients[i].deadline)) tain_add_g(&clients[i].deadline, &readtto) ; 273 | } 274 | buffer_rseek(buffer_0, siovec_len(v, 2)) ; 275 | } 276 | } 277 | 278 | if (!cont) 279 | { 280 | for (unsigned int i = 0 ; i < numconn ; i++) 281 | { 282 | if (!bufalloc_len(&clients[i].ba)) 283 | { 284 | client_free(clients + i) ; 285 | clients[i--] = clients[--numconn] ; 286 | } 287 | } 288 | if (!numconn) break ; 289 | } 290 | } 291 | } 292 | return 0 ; 293 | } 294 | -------------------------------------------------------------------------------- /doc/skabus-rpcd.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | skabus: the skabus-rpcd program 7 | 8 | 9 | 10 | 11 | 12 | 13 |

14 | skabus
15 | Software
16 | skarnet.org 17 |

18 | 19 |

The skabus-rpcd program

20 | 21 |

22 | skabus-rpcd is the serving part of the 23 | skabus-rpc-daemon 24 | RPC mapper daemon. 25 | It assumes that its stdin is a bound and listening Unix 26 | domain socket; 27 | it accepts connections from clients connecting to that socket, 28 | and transmits messages between clients. 29 |

30 | 31 |

Overview and terminology

32 | 33 |
    34 |
  • Every program connecting to skabus-rpcd, for instance using the 35 | skabus_rpc library, is called a 36 | client. This is standard Unix client-server terminology.
  • 37 |
  • A client can have two functions: 38 |
      39 |
    • It can implement and register an interface.
    • 40 |
    • It can perform queries to an interface 41 | provided by another client.
    • 42 |
    43 | A client can perform both functions.
  • 44 |
  • skabus-rpcd is the RPC mapper. It accepts interface 45 | registrations, and client queries. It directs queries made to an 46 | interface to the client that implements that interface, and directs 47 | the reply to the client that made the query.
  • 48 |
  • A client making a query is called a qclient. A 49 | client replying to a query is called a rclient. skabus-rpcd 50 | tries to be as transparent and out-of-the-way as possible: all a qclient 51 | is interested in is getting its query to the corresponding rclient, and 52 | getting the reply from said rclient. skabus-rpcd's only job is to get 53 | the queries and replies to the appropriate processes.
  • 54 |
55 | 56 | 57 |

Interface

58 | 59 |
 60 |      skabus-rpcd [ -1 ] [ -v verbosity ] [ -c maxconn ] [ -t clienttimeout ] [ -T lameducktimeout ] [ -i rulesdir | -x rulesfile ] [ -S | -s ] [ -J | -j ]
 61 | 
62 | 63 |
    64 |
  • skabus-rpcd accepts connections from clients to an already 65 | bound and listening SOCK_STREAM Unix domain socket which is its 66 | standard input.
  • 67 |
  • It runs until it receives a SIGTERM, in which case it will 68 | stop accepting new client operations, and exit 0 when the pending 69 | operations have completed.
  • 70 |
  • Client connections last as long as the client wants to, unless an 71 | error occurs, or unless the server is told to exit - in which cases 72 | skabus-rpcd forcibly disconnects the client.
  • 73 |
  • Clients can perform operations by calling the appropriate 74 | functions in the skabus_rpc library.
  • 75 |
76 | 77 |

Operation

78 | 79 |
    80 |
  • A client connects to skabus-rpcd.
  • 81 |
  • A client registers itself to skabus-rpcd, giving it 82 | the identifier it wishes to acquire. This identifier can 83 | be any string, up to SKABUS_RPC_IDSTR_SIZE (254) characters. 84 | Depending on skabus-rpcd's configuration, not every client is 85 | allowed to use any string, see below.
  • 86 |
  • A client may register interfaces. For every 87 | interface it wishes to register, it gives skabus-rpcd an 88 | interface name, which is the name qclients will access 89 | that interface under. It also provides an interface body, 90 | which contains pointers to functions that will be called to serve 91 | queries made to that interface. (The interface body is not sent to 92 | skabus-rpcd: it's only relevant inside the rclient's address space.)
  • 93 |
  • A qclient can send queries to an interface. A query is 94 | just an array of bytes, possibly coupled with an array of file 95 | descriptors (if the qclient is authorized to send file descriptors). 96 | skabus-rpcd routes the query to the rclient that has registered 97 | the interface.
  • 98 |
  • The rclient receives the query, with a little additional 99 | information from skabus-rpcd: a timestamp, the qclient's identifier, 100 | the qclient's credentials. The appropriate callback declared in 101 | the interface body is run, and the reply is sent to 102 | skabus-rpcd, which routes it back to the qclient.
  • 103 |
104 | 105 |

106 | skabus-rpcd only performs low-level operations and message routing. 107 | Client identifiers, interface names and queries are strings or arrays 108 | of bytes - they are not structured. It's up to the client programs 109 | to decide on a structure for the queries, a protocol between qclient 110 | and rclient. 111 |

112 | 113 |

Options

114 | 115 |
    116 |
  • -1 : write a newline to stdout, and close stdout, 117 | right before entering the client-accepting loop. 118 | If stdout is suitably redirected, this can be used by monitoring 119 | programs to check when the server is accepting connections. See 120 | this page 121 | for more information on readiness notification.
  • 122 |
  • -v verbosity : be more or less 123 | verbose. verbosity can be 0 (quiet), 1 (normal), or 2 or more 124 | (verbose).
  • 125 |
  • -c maxconn : accept at most 126 | maxconn concurrent connections. Default is 40. It is 127 | impossible to set it higher than the value of the SKABUS_RPC_MAX macro, 128 | i.e. 1000.
  • 129 |
  • -t clienttimeout : disconnect a client 130 | if it's in the middle of an operation and it has not written or read any 131 | data in clienttimeout milliseconds. By default, clienttimeout 132 | is 0, which means infinite.
  • 133 |
  • -T lameducktimeout : give clients 134 | lameducktimeout milliseconds to finish their current operations 135 | before exiting after receiving a SIGTERM. By default, lameducktimeout 136 | is 0, which means infinite.
  • 137 |
  • -x rulesfile : read access rights 138 | configuration from 139 | CDB 140 | file rulesfile.
  • 141 |
  • -i rulesdir : read access rights 142 | configuration from the filesystem in directory rulesdir.
  • 143 |
  • -S : no open registration. Clients that cannot find 144 | a matching env/SKABUS_RPC_ID_REGEX entry in their accepted 145 | ruleset are forbidden to register themselves. This is the default.
  • 146 |
  • -s : open registration. If the accepted ruleset 147 | for the client does not contain a env/SKABUS_RPC_ID_REGEX entry, 148 | the client is authorized to register itself with any identifier.
  • 149 |
  • -J : no open interface registration. If the accepted 150 | ruleset for the client does not contain a env/SKABUS_RPC_INTERFACES_REGEX entry, 151 | the client will be unable to register interfaces. This is the default.
  • 152 |
  • -j : open interface registration. If the accepted ruleset 153 | for the client does not contain a env/SKABUS_RPC_ID_REGEX entry, 154 | the client is authorized to register interfaces with any name.
  • 155 |
156 | 157 |

Signals

158 | 159 |
    160 |
  • SIGTERM: enter lameduck mode (stop accepting new clients and new 161 | operations), then exit when no more operation is pending.
  • 162 |
  • SIGHUP: reopen rulesfile, if skabus-rpcd has been run 163 | with the -x option. It is not necessary to send skabus-rpcd 164 | a SIGHUP when the -i option is used instead: configuration 165 | changes in the filesystem are automatically picked up.
  • 166 |
167 | 168 | 169 |

Configuration

170 |
171 | 172 |

173 | Before running skabus-rpcd (or its wrapper 174 | skabus-rpc-daemon), it is necessary 175 | to configure it. This is done by a series of rules, or ruleset, 176 | stored in either a rulesfile in the 177 | CDB format, 178 | or in a rulesdir, i.e. a directory in the filesystem following a 179 | certain format. skabus-rpcd will refuse to run if neither the -i 180 | nor the -x option has been provided. 181 |

182 | 183 |

184 | Rulesets can be converted between the rulesdir and 185 | rulesfile formats with the 186 | s6-accessrules-cdb-from-fs and 187 | s6-accessrules-fs-from-cdb 188 | conversion tools. 189 |

190 | 191 |

Rules format

192 | 193 |

194 | The rules file, or rules directory, follows the 195 | s6 accessrules format 196 | for uid and gid checking. For every connecting client, skabus-rpcd matches the uid 197 | and gid of the client against the provided ruleset, and determines what 198 | the client is authorized to do. 199 |

200 | 201 |

202 | By default, no client is allowed to do anything - not even 203 | connect to the server. Even root, the super-user, will be denied 204 | access. That is why 205 | it is essential to create a sensible ruleset prior to running the server 206 | in order to do anything useful. 207 |

208 | 209 |

210 | Here is how to configure a rulesdir for a client running as uid u. 211 | It is also possible to configure rules for clients running under gid 212 | g by replacing uid/u with gid/g 213 | il all the examples below. The default behaviour can be configured under 214 | uid/default. It is also possible to use a rulesfile instead 215 | by writing a rulesdir and converting it to a rulesfile with the 216 | s6-accessrules-cdb-from-fs 217 | program. 218 |

219 | 220 |
    221 |
  • If the uid/u/allow file exists, the client will be 222 | authorized to connect to the server. This is a prerequisite for 223 | doing anything.
  • 224 |
  • The uid/u/env/SKABUS_RPC_ID_REGEX file 225 | should contain a regular expression. The client will be authorized to 226 | register itself using an identifier that matches that regular 227 | expression. If the file does not exist, the default behaviour is 228 | given by the -S or -s option to skabus-rpcd.
  • 229 |
  • The uid/u/env/SKABUS_RPC_INTERFACES_REGEX file 230 | should contain a regular expression. The client will be authorized to 231 | register interfaces with names that match that regular 232 | expression. If the file does not exist, the default behaviour is 233 | given by the -J or -j option to skabus-rpcd.
  • 234 |
  • If the uid/u/env/SKABUS_RPC_QSENDFDS file 235 | exists and is not empty, the client will be allowed to send 236 | queries containing open file descriptors. If the file exists and is 237 | empty, the client will be explicitly denied this right: it will only 238 | be allowed to send purely textual queries.
  • 239 |
  • If the uid/u/env/SKABUS_RPC_RSENDFDS file 240 | exists and is not empty, the client will be allowed to send 241 | replies containing open file descriptors to the queries it gets. 242 | If the file exists and is 243 | empty, the client will be explicitly denied this right: it will only 244 | be allowed to reply with purely textual answers.
  • 245 |
246 | 247 |

Notes

248 | 249 |
    250 |
  • skabus-rpcd is meant to be execve'd into by a program that gets 251 | the listening socket. That program is normally 252 | s6-ipcserver-socketbinder, 253 | which creates the socket itself; but it can be a different one if the 254 | socket is to be obtained by another means, for instance if it has 255 | been retrieved from a fd-holding daemon.
  • 256 |
257 | 258 | 259 | 260 | --------------------------------------------------------------------------------