aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--NEWS5
-rw-r--r--doc/index.html4
-rw-r--r--doc/license.html2
-rw-r--r--doc/upgrade.html6
-rw-r--r--package/deps.mak14
-rw-r--r--package/info2
-rw-r--r--src/include/skalibs/sassclient.h44
-rw-r--r--src/include/skalibs/sassserver.h29
-rw-r--r--src/include/skalibs/unixonacid.h2
-rw-r--r--src/libunixonacid/sassclient-internal.h22
-rw-r--r--src/libunixonacid/sassclient_ack.c24
-rw-r--r--src/libunixonacid/sassclient_cancel.c39
-rw-r--r--src/libunixonacid/sassclient_cancel_internal.c21
-rw-r--r--src/libunixonacid/sassclient_end.c20
-rw-r--r--src/libunixonacid/sassclient_send.c11
-rw-r--r--src/libunixonacid/sassclient_sendv.c63
-rw-r--r--src/libunixonacid/sassclient_start.c36
-rw-r--r--src/libunixonacid/sassclient_update.c58
-rw-r--r--src/libunixonacid/sassserver.c234
19 files changed, 628 insertions, 8 deletions
diff --git a/NEWS b/NEWS
index 5d896ae..882321d 100644
--- a/NEWS
+++ b/NEWS
@@ -1,9 +1,12 @@
Changelog for skalibs.
-In 2.14.5.2
+In 2.14.6.0
-----------
- Bugfixes.
+ - New functions: sassclient.h and sassserver.h, in libunixonacid.
+The goal is to factor the client-side and server-side code for
+asynchronous helpers such as s6-ftrigrd, skadnsd, and more.
In 2.14.5.1
diff --git a/doc/index.html b/doc/index.html
index 1501eda..8c90840 100644
--- a/doc/index.html
+++ b/doc/index.html
@@ -60,8 +60,8 @@ with a standard C development environment </li>
<h3> Download </h3>
<ul>
- <li> The current released version of skalibs is <a href="skalibs-2.14.5.2.tar.gz">2.14.5.2</a>.
-You can access its checksum <a href="skalibs-2.14.5.2.tar.gz.sha256">here</a>. </li>
+ <li> The current released version of skalibs is <a href="skalibs-2.14.6.0.tar.gz">2.14.6.0</a>.
+You can access its checksum <a href="skalibs-2.14.6.0.tar.gz.sha256">here</a>. </li>
<li> Alternatively, you can checkout a copy of the
<a href="//git.skarnet.org/cgi-bin/cgit.cgi/skalibs/">skalibs
git repository</a>:
diff --git a/doc/license.html b/doc/license.html
index 232c470..43f7138 100644
--- a/doc/license.html
+++ b/doc/license.html
@@ -74,7 +74,7 @@ color, or different text font. </li>
<p>
<em>I am aware that the previous restrictions sound completely
ridiculous while the official skalibs documentation is incomplete.
-As of 2.14.5.2, I'm not going to enforce those restrictions, but if you're
+As of 2.14.6.0, I'm not going to enforce those restrictions, but if you're
going to provide documentation for skalibs, don't keep it to yourself,
please send it to me instead. :-) </em>
</p>
diff --git a/doc/upgrade.html b/doc/upgrade.html
index ea83c7e..d9c8ee1 100644
--- a/doc/upgrade.html
+++ b/doc/upgrade.html
@@ -16,10 +16,12 @@
<a href="//skarnet.org/">skarnet.org</a>
</p>
-<h2> in 2.14.5.2 </h2>
+<h2> in 2.14.6.0 </h2>
<ul>
- <li> No functional changes. </li>
+ <li> New family of functions: sassclient and sassserver, working on top
+of textclient, to factor code for asynchronous helpers like s6-ftrigrd
+or skadnsd. </li> </li>
</ul>
<h2> in 2.14.5.1 </h2>
diff --git a/package/deps.mak b/package/deps.mak
index f10cd10..ef71687 100644
--- a/package/deps.mak
+++ b/package/deps.mak
@@ -40,6 +40,8 @@ src/include/skalibs/posixishard.h: src/include/skalibs/gccattributes.h src/inclu
src/include/skalibs/posixplz.h: src/include/skalibs/functypes.h src/include/skalibs/gccattributes.h
src/include/skalibs/prog.h: src/include/skalibs/types.h
src/include/skalibs/random.h: src/include/skalibs/functypes.h src/include/skalibs/stralloc.h
+src/include/skalibs/sassclient.h: src/include/skalibs/genqdyn.h src/include/skalibs/gensetdyn.h src/include/skalibs/tai.h src/include/skalibs/textclient.h
+src/include/skalibs/sassserver.h: src/include/skalibs/iopause.h src/include/skalibs/tai.h
src/include/skalibs/setgroups.h: src/include/skalibs/sysdeps.h
src/include/skalibs/sha512.h: src/include/skalibs/uint64.h
src/include/skalibs/sig.h: src/include/skalibs/gccattributes.h
@@ -60,7 +62,7 @@ src/include/skalibs/unix-timed.h: src/include/skalibs/bufalloc.h src/include/ska
src/include/skalibs/unix-transactional.h: src/include/skalibs/direntry.h src/include/skalibs/gccattributes.h src/include/skalibs/stralloc.h
src/include/skalibs/unixconnection.h: src/include/skalibs/unixmessage.h
src/include/skalibs/unixmessage.h: src/include/skalibs/buffer.h src/include/skalibs/cbuffer.h src/include/skalibs/gccattributes.h src/include/skalibs/genalloc.h src/include/skalibs/stralloc.h src/include/skalibs/tai.h
-src/include/skalibs/unixonacid.h: src/include/skalibs/ancil.h src/include/skalibs/kolbak.h src/include/skalibs/skaclient.h src/include/skalibs/textclient.h src/include/skalibs/textmessage.h src/include/skalibs/unix-timed.h src/include/skalibs/unix-transactional.h src/include/skalibs/unixconnection.h src/include/skalibs/unixmessage.h
+src/include/skalibs/unixonacid.h: src/include/skalibs/ancil.h src/include/skalibs/kolbak.h src/include/skalibs/sassclient.h src/include/skalibs/sassserver.h src/include/skalibs/skaclient.h src/include/skalibs/textclient.h src/include/skalibs/textmessage.h src/include/skalibs/unix-timed.h src/include/skalibs/unix-transactional.h src/include/skalibs/unixconnection.h src/include/skalibs/unixmessage.h
src/libdatastruct/avlnode-internal.h: src/include/skalibs/avlnode.h
src/libdatastruct/genqdyn-internal.h: src/include/skalibs/genqdyn.h
src/libenvexec/envdir-internal.h: src/include/skalibs/stralloc.h
@@ -73,6 +75,7 @@ src/libstddjb/cdbmake-internal.h: src/include/skalibs/cdbmake.h
src/libstddjb/djbtime-internal.h: src/include/skalibs/uint64.h
src/libstddjb/fmtscan-internal.h: src/include/skalibs/fmtscan.h src/include/skalibs/uint64.h
src/libunixonacid/at-internal.h: src/include/skalibs/functypes.h
+src/libunixonacid/sassclient-internal.h: src/include/skalibs/sassclient.h src/include/skalibs/tai.h
src/libunixonacid/skaclient-internal.h: src/include/skalibs/kolbak.h src/include/skalibs/skaclient.h src/include/skalibs/unixmessage.h
src/libdatastruct/avlnode_delete.o src/libdatastruct/avlnode_delete.lo: src/libdatastruct/avlnode_delete.c src/libdatastruct/avlnode-internal.h src/include/skalibs/avlnode.h
src/libdatastruct/avlnode_doublerotate.o src/libdatastruct/avlnode_doublerotate.lo: src/libdatastruct/avlnode_doublerotate.c src/libdatastruct/avlnode-internal.h src/include/skalibs/avlnode.h
@@ -810,6 +813,15 @@ src/libunixonacid/openreadnclose_at.o src/libunixonacid/openreadnclose_at.lo: sr
src/libunixonacid/openslurpclose_at.o src/libunixonacid/openslurpclose_at.lo: src/libunixonacid/openslurpclose_at.c src/include/skalibs/djbunix.h src/include/skalibs/unix-transactional.h
src/libunixonacid/openwritenclose_at.o src/libunixonacid/openwritenclose_at.lo: src/libunixonacid/openwritenclose_at.c src/include/skalibs/allreadwrite.h src/include/skalibs/djbunix.h src/include/skalibs/unix-transactional.h
src/libunixonacid/openwritevnclose_at.o src/libunixonacid/openwritevnclose_at.lo: src/libunixonacid/openwritevnclose_at.c src/include/skalibs/allreadwrite.h src/include/skalibs/djbunix.h src/include/skalibs/siovec.h src/include/skalibs/unix-transactional.h
+src/libunixonacid/sassclient_ack.o src/libunixonacid/sassclient_ack.lo: src/libunixonacid/sassclient_ack.c src/include/skalibs/genqdyn.h src/include/skalibs/sassclient.h src/include/skalibs/uint32.h
+src/libunixonacid/sassclient_cancel.o src/libunixonacid/sassclient_cancel.lo: src/libunixonacid/sassclient_cancel.c src/include/skalibs/gensetdyn.h src/libunixonacid/sassclient-internal.h src/include/skalibs/sassclient.h src/include/skalibs/tai.h src/include/skalibs/textclient.h src/include/skalibs/uint32.h
+src/libunixonacid/sassclient_cancel_internal.o src/libunixonacid/sassclient_cancel_internal.lo: src/libunixonacid/sassclient_cancel_internal.c src/libunixonacid/sassclient-internal.h src/include/skalibs/textclient.h src/include/skalibs/uint32.h
+src/libunixonacid/sassclient_end.o src/libunixonacid/sassclient_end.lo: src/libunixonacid/sassclient_end.c src/include/skalibs/genqdyn.h src/include/skalibs/gensetdyn.h src/include/skalibs/sassclient.h src/include/skalibs/textclient.h
+src/libunixonacid/sassclient_send.o src/libunixonacid/sassclient_send.lo: src/libunixonacid/sassclient_send.c src/include/skalibs/sassclient.h
+src/libunixonacid/sassclient_sendv.o src/libunixonacid/sassclient_sendv.lo: src/libunixonacid/sassclient_sendv.c src/include/skalibs/gensetdyn.h src/libunixonacid/sassclient-internal.h src/include/skalibs/sassclient.h src/include/skalibs/siovec.h src/include/skalibs/tai.h src/include/skalibs/textclient.h src/include/skalibs/uint32.h
+src/libunixonacid/sassclient_start.o src/libunixonacid/sassclient_start.lo: src/libunixonacid/sassclient_start.c src/include/skalibs/genqdyn.h src/include/skalibs/gensetdyn.h src/include/skalibs/posixplz.h src/libunixonacid/sassclient-internal.h src/include/skalibs/sassclient.h src/include/skalibs/textclient.h
+src/libunixonacid/sassclient_update.o src/libunixonacid/sassclient_update.lo: src/libunixonacid/sassclient_update.c src/include/skalibs/genqdyn.h src/include/skalibs/gensetdyn.h src/include/skalibs/posixishard.h src/libunixonacid/sassclient-internal.h src/include/skalibs/sassclient.h src/include/skalibs/textclient.h src/include/skalibs/uint32.h
+src/libunixonacid/sassserver.o src/libunixonacid/sassserver.lo: src/libunixonacid/sassserver.c src/include/skalibs/avltree.h src/include/skalibs/error.h src/include/skalibs/gensetdyn.h src/include/skalibs/iopause.h src/include/skalibs/sassserver.h src/include/skalibs/strerr.h src/include/skalibs/tai.h src/include/skalibs/textclient.h src/include/skalibs/textmessage.h src/include/skalibs/uint32.h
src/libunixonacid/skaclient_default_cb.o src/libunixonacid/skaclient_default_cb.lo: src/libunixonacid/skaclient_default_cb.c src/include/skalibs/posixishard.h src/include/skalibs/skaclient.h src/include/skalibs/unixmessage.h
src/libunixonacid/skaclient_end.o src/libunixonacid/skaclient_end.lo: src/libunixonacid/skaclient_end.c src/include/skalibs/djbunix.h src/include/skalibs/skaclient.h src/include/skalibs/unixmessage.h
src/libunixonacid/skaclient_init.o src/libunixonacid/skaclient_init.lo: src/libunixonacid/skaclient_init.c src/libunixonacid/skaclient-internal.h src/include/skalibs/skaclient.h src/include/skalibs/unixmessage.h
diff --git a/package/info b/package/info
index bf25046..b986cde 100644
--- a/package/info
+++ b/package/info
@@ -1,4 +1,4 @@
package=skalibs
-version=2.14.5.2
+version=2.14.6.0
category=prog
package_macro_name=SKALIBS
diff --git a/src/include/skalibs/sassclient.h b/src/include/skalibs/sassclient.h
new file mode 100644
index 0000000..b932414
--- /dev/null
+++ b/src/include/skalibs/sassclient.h
@@ -0,0 +1,44 @@
+/* ISC license. */
+
+#ifndef SKALIBS_SASSCLIENT_H
+#define SKALIBS_SASSCLIENT_H
+
+#include <pthread.h>
+
+#include <skalibs/tai.h>
+#include <skalibs/textclient.h>
+#include <skalibs/gensetdyn.h>
+#include <skalibs/genqdyn.h>
+
+typedef struct sassclient_s sassclient, *sassclient_ref ;
+struct sassclient_s
+{
+ textclient connection ;
+ gensetdyn store ; /* sassclient_data */
+ genqdyn results ; /* char id[4] + char status[4] */
+ pthread_mutex_t connection_mutex ;
+ pthread_mutex_t results_mutex ;
+} ;
+#define SASSCLIENT_ZERO { .connection = TEXTCLIENT_ZERO, .store = GENSETDYN_ZERO, .results = GENQDYN_ZERO }
+
+typedef int sassclient_cb_func (char const *, size_t, void *) ;
+typedef sassclient_cb_func *sassclient_cb_func_ref ;
+
+extern int sassclient_start (sassclient *, char const *const *, char const *, char const *, tain const *, tain *) ;
+#define sassclient_start_g(a, argv, banner1, banner2, deadline) sassclient_start(a, argv, banner1, banner2, (deadline), &STAMP)
+extern void sassclient_end (sassclient *) ;
+
+#define sassclient_fd(a) textclient_fd(&(a)->connection)
+extern int sassclient_update (sassclient *) ;
+extern int sassclient_ack (sassclient *, uint32_t *, int *) ;
+
+extern int sassclient_send (sassclient *, uint32_t *, uint32_t, uint32_t, char const *, size_t, sassclient_cb_func_ref, void *, tain const *, tain *) ;
+#define sassclient_send_g(a, id, timeout, opcode, s, len, cb, data, deadline) sassclient_send(a, id, timeout, opcode, s, len, cb, data, (deadline), &STAMP)
+
+extern int sassclient_sendv (sassclient *, uint32_t *, uint32_t, uint32_t, struct iovec const *, unsigned int, sassclient_cb_func_ref, void *, tain const *, tain *) ;
+#define sassclient_sendv_g(a, id, timeout, opcode, v, n, cb, data, deadline) sassclient_sendv(a, id, timeout, opcode, v, n, cb, data, (deadline), &STAMP)
+
+extern int sassclient_cancel (sassclient *, uint32_t, tain const *, tain *) ;
+#define sassclient_cancel_g(a, id, deadline) sassclient_cancel(a, id, (deadline), &STAMP)
+
+#endif
diff --git a/src/include/skalibs/sassserver.h b/src/include/skalibs/sassserver.h
new file mode 100644
index 0000000..fcd1286
--- /dev/null
+++ b/src/include/skalibs/sassserver.h
@@ -0,0 +1,29 @@
+/* ISC license. */
+
+#ifndef SKALIBS_SASSSERVER_H
+#define SKALIBS_SASSSERVER_H
+
+#include <sys/uio.h>
+#include <stdint.h>
+
+#include <skalibs/tai.h>
+#include <skalibs/iopause.h>
+
+typedef void *sassserver_send_func (uint32_t, uint32_t, char const *, size_t) ;
+typedef sassserver_send_func *sassserver_send_func_ref ;
+
+typedef void sassserver_cancel_func (void *) ;
+typedef sassserver_cancel_func *sassserver_cancel_func_ref ;
+
+extern void sassserver_init (char const *, char const *, sassserver_send_func_ref, sassserver_cancel_func_ref, tain const *, tain *stamp) ;
+#define sassserver_init_g(banner1, banner2, deadline) sassserver_init(banner1, banner2, (deadline), &STAMP)
+extern unsigned int sassserver_prepare_iopause (iopause_fd *, tain *) ;
+extern void sassserver_timeout (void) ;
+extern int sassserver_event (iopause_fd const *) ;
+extern void *sassserver_data (uint32_t) ;
+
+extern void sassserver_async_failure (uint32_t, int) ;
+extern void sassserver_async_success (uint32_t, char const *, size_t) ;
+extern void sassserver_async_successv (uint32_t, struct iovec const *, unsigned int) ;
+
+#endif
diff --git a/src/include/skalibs/unixonacid.h b/src/include/skalibs/unixonacid.h
index d9f952c..1cba96a 100644
--- a/src/include/skalibs/unixonacid.h
+++ b/src/include/skalibs/unixonacid.h
@@ -12,5 +12,7 @@
#include <skalibs/unixconnection.h>
#include <skalibs/kolbak.h>
#include <skalibs/skaclient.h>
+#include <skalibs/sassclient.h>
+#include <skalibs/sassserver.h>
#endif
diff --git a/src/libunixonacid/sassclient-internal.h b/src/libunixonacid/sassclient-internal.h
new file mode 100644
index 0000000..5ddf0f4
--- /dev/null
+++ b/src/libunixonacid/sassclient-internal.h
@@ -0,0 +1,22 @@
+/* ISC license. */
+
+#ifndef SKALIBS_SASSCLIENT_INTERNAL_H
+#define SKALIBS_SASSCLIENT_INTERNAL_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <skalibs/tai.h>
+#include <skalibs/sassclient.h>
+
+typedef struct sassclient_data_s sassclient_data, *sassclient_data_ref ;
+struct sassclient_data_s
+{
+ void *data ;
+ sassclient_cb_func_ref cb ;
+} ;
+
+extern int sassclient_cancel_internal (sassclient *, uint32_t, tain const *, tain *) ;
+#define asyncnss_cancel_internal_g(a, id, deadline) sassclient_cancel_internal(a, id, (deadline), &STAMP)
+
+#endif
diff --git a/src/libunixonacid/sassclient_ack.c b/src/libunixonacid/sassclient_ack.c
new file mode 100644
index 0000000..4fd765f
--- /dev/null
+++ b/src/libunixonacid/sassclient_ack.c
@@ -0,0 +1,24 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <pthread.h>
+
+#include <skalibs/uint32.h>
+#include <skalibs/genqdyn.h>
+#include <skalibs/sassclient.h>
+
+int sassclient_ack (sassclient *a, uint32_t *id, int *status)
+{
+ uint32_t x ;
+ char const *s ;
+ int e = pthread_mutex_lock(&a->results_mutex) ;
+ if (e) return (errno = e, -1) ;
+ if (!genqdyn_n(&a->results)) { pthread_mutex_unlock(&a->results_mutex) ; return 0 ; }
+ s = GENQDYN_PEEK(char const, &a->results) ;
+ uint32_unpack_big(s, id) ;
+ uint32_unpack_big(s + 4, &x) ;
+ genqdyn_pop(&a->results) ;
+ pthread_mutex_unlock(&a->results_mutex) ;
+ *status = x ;
+ return 1 ;
+}
diff --git a/src/libunixonacid/sassclient_cancel.c b/src/libunixonacid/sassclient_cancel.c
new file mode 100644
index 0000000..bc4273e
--- /dev/null
+++ b/src/libunixonacid/sassclient_cancel.c
@@ -0,0 +1,39 @@
+/* ISC license. */
+
+#include <stdint.h>
+#include <errno.h>
+#include <time.h>
+#include <pthread.h>
+
+#include <skalibs/uint32.h>
+#include <skalibs/tai.h>
+#include <skalibs/textclient.h>
+#include <skalibs/gensetdyn.h>
+#include <skalibs/sassclient.h>
+#include "sassclient-internal.h"
+
+int sassclient_cancel (sassclient *a, uint32_t id, tain const *deadline, tain *stamp)
+{
+ int e ;
+
+ {
+ struct timespec ts ;
+ tain diff ;
+ tain_sub(&diff, deadline, stamp) ;
+ if (!timespec_from_tain_relative(&ts, &diff)) return 0 ;
+ e = pthread_mutex_timedlock(&a->connection_mutex, &ts) ;
+// e = pthread_mutex_clocklock(&a->connection_mutex, CLOCK_MONOTONIC, &ts) ;
+ if (e) return (errno = e, 0) ;
+ }
+
+ e = sassclient_cancel_internal(a, id, deadline, stamp) ;
+ if (e) goto err ;
+ gensetdyn_delete(&a->store, id) ;
+ pthread_mutex_unlock(&a->connection_mutex) ;
+ return 1 ;
+
+ err:
+ pthread_mutex_unlock(&a->connection_mutex) ;
+ errno = e ;
+ return 0 ;
+}
diff --git a/src/libunixonacid/sassclient_cancel_internal.c b/src/libunixonacid/sassclient_cancel_internal.c
new file mode 100644
index 0000000..d9fbd5d
--- /dev/null
+++ b/src/libunixonacid/sassclient_cancel_internal.c
@@ -0,0 +1,21 @@
+/* ISC license. */
+
+#include <sys/uio.h>
+#include <stdint.h>
+#include <errno.h>
+
+#include <skalibs/uint32.h>
+#include <skalibs/textclient.h>
+
+#include "sassclient-internal.h"
+
+int asyncnss_cancel_internal (sassclient *a, uint32_t id, tain const *deadline, tain *stamp)
+{
+ struct iovec answer ;
+ char pack[5] = "-" ;
+
+ uint32_pack_big(pack + 1, id) ;
+ if (!textclient_exchange(&a->connection, pack, 5, &answer, deadline, stamp)) return errno ;
+ if (answer.iov_len != 1) return EPROTO ;
+ return *(uint8_t *)answer.iov_base ;
+}
diff --git a/src/libunixonacid/sassclient_end.c b/src/libunixonacid/sassclient_end.c
new file mode 100644
index 0000000..3e8b106
--- /dev/null
+++ b/src/libunixonacid/sassclient_end.c
@@ -0,0 +1,20 @@
+/* ISC license. */
+
+#include <pthread.h>
+
+#include <skalibs/textclient.h>
+#include <skalibs/gensetdyn.h>
+#include <skalibs/genqdyn.h>
+#include <skalibs/sassclient.h>
+
+void sassclient_end (sassclient *a)
+{
+ static sassclient const zero = SASSCLIENT_ZERO ;
+ if (textclient_fd(&a->connection) == -1) return ;
+ textclient_end(&a->connection) ;
+ gensetdyn_free(&a->store) ;
+ genqdyn_free(&a->results) ;
+ pthread_mutex_destroy(&a->connection_mutex) ;
+ pthread_mutex_destroy(&a->results_mutex) ;
+ *a = zero ;
+}
diff --git a/src/libunixonacid/sassclient_send.c b/src/libunixonacid/sassclient_send.c
new file mode 100644
index 0000000..9ede61a
--- /dev/null
+++ b/src/libunixonacid/sassclient_send.c
@@ -0,0 +1,11 @@
+/* ISC license. */
+
+#include <sys/uio.h>
+
+#include <skalibs/sassclient.h>
+
+int sassclient_send (sassclient *a, uint32_t *id, uint32_t timeout, uint32_t opcode, char const *s, size_t len, sassclient_cb_func_ref cb, void *data, tain const *deadline, tain *stamp)
+{
+ struct iovec v = { .iov_base = (char *)s, .iov_len = len } ;
+ return sassclient_sendv(a, id, timeout, opcode, &v, 1, cb, data, deadline, stamp) ;
+}
diff --git a/src/libunixonacid/sassclient_sendv.c b/src/libunixonacid/sassclient_sendv.c
new file mode 100644
index 0000000..ef38679
--- /dev/null
+++ b/src/libunixonacid/sassclient_sendv.c
@@ -0,0 +1,63 @@
+/* ISC license. */
+
+#include <sys/uio.h>
+#include <stdint.h>
+#include <errno.h>
+#include <time.h>
+#include <limits.h>
+#include <pthread.h>
+
+#include <skalibs/uint32.h>
+#include <skalibs/tai.h>
+#include <skalibs/siovec.h>
+#include <skalibs/gensetdyn.h>
+#include <skalibs/textclient.h>
+#include <skalibs/sassclient.h>
+#include "sassclient-internal.h"
+
+int sassclient_sendv (sassclient *a, uint32_t *cid, uint32_t timeout, uint32_t opcode, struct iovec const *vv, unsigned int n, sassclient_cb_func_ref cb, void *data, tain const *deadline, tain *stamp)
+{
+ size_t len = siovec_len(vv, n) ;
+ uint32_t id ;
+ int e ;
+ struct iovec answer ;
+ sassclient_data *p ;
+ char pack[17] = "+" ;
+ struct iovec v[1 + n] ;
+ if (len + 11 > UINT32_MAX) return (errno = ENAMETOOLONG, 0) ;
+
+ {
+ struct timespec ts ;
+ tain diff ;
+ tain_sub(&diff, deadline, stamp) ;
+ if (!timespec_from_tain_relative(&ts, &diff)) return 0 ;
+ e = pthread_mutex_timedlock(&a->connection_mutex, &ts) ;
+// e = pthread_mutex_clocklock(&a->connection_mutex, CLOCK_MONOTONIC, &ts) ;
+ if (e) return (errno = e, 0) ;
+ }
+
+ if (!gensetdyn_new(&a->store, &id)) goto err ;
+ v[0].iov_base = pack ;
+ v[0].iov_len = 17 ;
+ for (unsigned int i = 0 ; i < n ; i++) v[i+1] = vv[i] ;
+ uint32_pack_big(pack + 1, id) ;
+ uint32_pack_big(pack + 5, timeout) ;
+ uint32_pack_big(pack + 9, opcode) ;
+ uint32_pack_big(pack + 13, len) ;
+ if (!textclient_exchangev(&a->connection, v, 1 + n, &answer, deadline, stamp)) { e = errno ; goto err0 ; }
+ if (answer.iov_len == 1) { e = *(unsigned char *)answer.iov_base ; goto err0 ; }
+ if (answer.iov_len != 5 || *(unsigned char *)answer.iov_base) { e = EPROTO ; goto err0 ; }
+ p = GENSETDYN_P(sassclient_data, &a->store, id) ;
+ p->cb = cb ;
+ p->data = data ;
+ pthread_mutex_unlock(&a->connection_mutex) ;
+ *cid = id ;
+ return 1 ;
+
+ err0:
+ gensetdyn_delete(&a->store, id) ;
+ errno = e ;
+ err:
+ pthread_mutex_unlock(&a->connection_mutex) ;
+ return 0 ;
+}
diff --git a/src/libunixonacid/sassclient_start.c b/src/libunixonacid/sassclient_start.c
new file mode 100644
index 0000000..73ad732
--- /dev/null
+++ b/src/libunixonacid/sassclient_start.c
@@ -0,0 +1,36 @@
+/* ISC license. */
+
+#include <string.h>
+#include <errno.h>
+#include <pthread.h>
+
+#include <skalibs/posixplz.h>
+#include <skalibs/textclient.h>
+#include <skalibs/gensetdyn.h>
+#include <skalibs/genqdyn.h>
+#include <skalibs/sassclient.h>
+#include "sassclient-internal.h"
+
+int sassclient_start (sassclient *a, char const *const *argv, char const *banner1, char const *banner2, tain const *deadline, tain *stamp)
+{
+ int e ;
+ if (sassclient_fd(a) >= 0) return (errno = EBUSY, 0) ;
+ e = pthread_mutex_init(&a->connection_mutex, 0) ;
+ if (e) goto err ;
+ e = pthread_mutex_init(&a->results_mutex, 0) ;
+ if (e) goto err0 ;
+ if (!textclient_startf(&a->connection, argv, (char const *const *)environ, TEXTCLIENT_OPTION_WAITPID, banner1, strlen(banner1), banner2, strlen(banner2), deadline, stamp))
+ goto err1 ;
+ gensetdyn_init(&a->store, sizeof(sassclient_data), 8, 3, 8) ;
+ genqdyn_init(&a->results, 8, 1, 10) ;
+ return 1 ;
+
+ err1:
+ e = errno ;
+ pthread_mutex_destroy(&a->results_mutex) ;
+ err0:
+ pthread_mutex_destroy(&a->connection_mutex) ;
+ err:
+ errno = e ;
+ return 0 ;
+}
diff --git a/src/libunixonacid/sassclient_update.c b/src/libunixonacid/sassclient_update.c
new file mode 100644
index 0000000..01a0427
--- /dev/null
+++ b/src/libunixonacid/sassclient_update.c
@@ -0,0 +1,58 @@
+/* ISC license. */
+
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <pthread.h>
+
+#include <skalibs/uint32.h>
+#include <skalibs/textclient.h>
+#include <skalibs/gensetdyn.h>
+#include <skalibs/genqdyn.h>
+#include <skalibs/sassclient.h>
+#include "sassclient-internal.h"
+
+#include <skalibs/posixishard.h>
+
+static int sassclient_msghandler (struct iovec const *v, void *aux)
+{
+ sassclient *a = aux ;
+ char const *s = v->iov_base ;
+ int e ;
+ sassclient_data *p ;
+ uint32_t id ;
+ char res[8] ;
+ if (v->iov_len < 8) return (errno = EPROTO, 0) ;
+ uint32_unpack_big(s, &id) ;
+ memcpy(res, s, 4) ; s += 4 ;
+ p = GENSETDYN_P(sassclient_data, &a->store, id) ;
+ if (memcmp(s, "\0\0\0", 4))
+ {
+ if (v->iov_len != 8) return (errno = EPROTO, 0) ;
+ memcpy(res + 4, s, 4) ;
+ }
+ else
+ {
+ e = (*p->cb)(s + 8, v->iov_len - 8, p->data) ;
+ uint32_pack_big(res + 4, e) ;
+ }
+ e = pthread_mutex_lock(&a->results_mutex) ;
+ if (e) return (errno = e, 0) ;
+ if (!genqdyn_push(&a->results, res))
+ {
+ pthread_mutex_unlock(&a->results_mutex) ;
+ return 0 ;
+ }
+ pthread_mutex_unlock(&a->results_mutex) ;
+ if (!gensetdyn_delete(&a->store, id)) return 0 ;
+ return 1 ;
+}
+
+int sassclient_update (sassclient *a)
+{
+ int e = pthread_mutex_lock(&a->connection_mutex) ;
+ if (e) return (errno = e, -1) ;
+ e = textclient_update(&a->connection, &sassclient_msghandler, a) ;
+ pthread_mutex_unlock(&a->connection_mutex) ;
+ return e < 0 ? -1 : !!e ;
+}
diff --git a/src/libunixonacid/sassserver.c b/src/libunixonacid/sassserver.c
new file mode 100644
index 0000000..7ca3ad7
--- /dev/null
+++ b/src/libunixonacid/sassserver.c
@@ -0,0 +1,234 @@
+/* ISC license. */
+
+#include <sys/uio.h>
+#include <string.h>
+#include <stdint.h>
+#include <errno.h>
+
+#include <skalibs/uint32.h>
+#include <skalibs/error.h>
+#include <skalibs/strerr.h>
+#include <skalibs/tai.h>
+#include <skalibs/iopause.h>
+#include <skalibs/gensetdyn.h>
+#include <skalibs/avltree.h>
+#include <skalibs/textmessage.h>
+#include <skalibs/textclient.h>
+#include <skalibs/sassserver.h>
+
+typedef struct sassserver_query_s sassserver_query, sassserver_query_ref ;
+struct sassserver_query_s
+{
+ uint32_t id ;
+ tain deadline ;
+ void *data ;
+} ;
+
+static sassserver_send_func_ref sassserver_sendf ;
+static sassserver_cancel_func_ref sassserver_cancelf ;
+
+static gensetdyn sassserver_queries = GENSETDYN_INIT(sassserver_query, 8, 3, 8) ;
+#define SASSSERVER_QUERY(i) GENSETDYN_P(sassserver_query, &sassserver_queries, (i))
+
+void *sassserver_data (uint32_t handle)
+{
+ return SASSSERVER_QUERY(handle)->data ;
+}
+
+static void *sassserver_deadline_dtok (uint32_t d, void *aux)
+{
+ return &GENSETDYN_P(sassserver_query, (gensetdyn *)aux, d)->deadline ;
+}
+
+static int sassserver_deadline_cmp (void const *a, void const *b, void *aux)
+{
+ tain const *aa = a ;
+ tain const *bb = b ;
+ (void)aux ;
+ return tain_less(aa, bb) ? -1 : tain_less(bb, aa) ;
+}
+
+static avltree sassserver_by_deadline = AVLTREE_INIT(8, 3, 8, &sassserver_deadline_dtok, &sassserver_deadline_cmp, &sassserver_queries) ;
+
+static void *sassserver_id_dtok (uint32_t d, void *aux)
+{
+ return &GENSETDYN_P(sassserver_query, (gensetdyn *)aux, d)->id ;
+}
+
+static int sassserver_id_cmp (void const *a, void const *b, void *aux)
+{
+ uint32_t const *aa = a ;
+ uint32_t const *bb = b ;
+ (void)aux ;
+ return *aa < *bb ? -1 : *aa > *bb ;
+}
+
+static avltree sassserver_by_id = AVLTREE_INIT(8, 3, 8, &sassserver_id_dtok, &sassserver_id_cmp, &sassserver_queries) ;
+
+static void sassserver_sync_answer (int e)
+{
+ char pack[4] ;
+ uint32_pack_big(pack, (uint32_t)e) ;
+ if (!textmessage_put(textmessage_sender_1, pack, 4))
+ strerr_diefu1sys(111, "textmessage_put") ;
+}
+
+static void sassserver_remove (uint32_t handle)
+{
+ sassserver_query *p = SASSSERVER_QUERY(handle) ;
+ avltree_delete(&sassserver_by_deadline, &p->deadline) ;
+ avltree_delete(&sassserver_by_id, &p->id) ;
+ gensetdyn_delete(&sassserver_queries, handle) ;
+}
+
+void sassserver_async_failure (uint32_t handle, int e)
+{
+ sassserver_query *p = SASSSERVER_QUERY(handle) ;
+ char pack[8] ;
+ uint32_pack_big(pack, p->id) ;
+ uint32_pack_big(pack + 4, (uint32_t)e) ;
+ if (!textmessage_put(textmessage_sender_x, pack, 8))
+ strerr_diefu1sys(111, "textmessage_put") ;
+ sassserver_remove(handle) ;
+}
+
+void sassserver_async_successv (uint32_t handle, struct iovec const *v, unsigned int n)
+{
+ sassserver_query *p = SASSSERVER_QUERY(handle) ;
+ char pack[8] = "\0\0\0\0\0\0\0" ;
+ struct iovec vv[n+1] ;
+ vv[0].iov_base = pack ; vv[0].iov_len = 8 ;
+ for (unsigned int i = 0 ; i < n ; i++) vv[i+1] = v[i] ;
+ uint32_pack_big(pack, p->id) ;
+ if (!textmessage_putv(textmessage_sender_x, vv, n+1))
+ strerr_diefu1sys(111, "textmessage_putv") ;
+ sassserver_remove(handle) ;
+}
+
+void sassserver_async_success (uint32_t handle, char const *s, size_t len)
+{
+ struct iovec v = { .iov_base = (char *)s, .iov_len = len } ;
+ sassserver_async_successv(handle, &v, 1) ;
+}
+
+static inline void sassserver_uniquify (tain *deadline)
+{
+ static tain const nanosec = { .sec = TAI_ZERO, .nano = 1 } ;
+ uint32_t dummy ;
+ while (avltree_search(&sassserver_by_deadline, deadline, &dummy))
+ tain_add(deadline, deadline, &nanosec) ;
+}
+
+static int sassserver_parse_protocol (struct iovec const *v, void *aux)
+{
+ char const *s = v->iov_base ;
+ size_t vlen = v->iov_len ;
+ (void)aux ;
+ if (vlen-- < 5) strerr_dief1x(100, "invalid client request") ;
+ switch (*s++)
+ {
+ case '-' : /* cancel */
+ {
+ uint32_t handle, id ;
+ if (vlen != 4) strerr_dief1x(100, "invalid client request") ;
+ uint32_unpack_big(s, &id) ;
+ if (!avltree_search(&sassserver_by_id, &id, &handle)) sassserver_sync_answer(EINVAL) ;
+ (*sassserver_cancelf)(SASSSERVER_QUERY(handle)->data) ;
+ sassserver_remove(handle) ;
+ sassserver_sync_answer(0) ;
+ break ;
+ }
+ case '+' : /* send */
+ {
+ sassserver_query *p ;
+ uint32_t handle ;
+ uint32_t timeout ;
+ uint32_t opcode ;
+ uint32_t len ;
+ if (vlen < 16) strerr_dief1x(100, "invalid client request") ;
+ if (!gensetdyn_new(&sassserver_queries, &handle)) strerr_diefu1sys(111, "gensetdyn_new") ;
+ p = SASSSERVER_QUERY(handle) ;
+ uint32_unpack_big(s, &p->id) ; s += 4 ; vlen -= 4 ;
+ uint32_unpack_big(s, &timeout) ; s += 4 ; vlen -= 4 ;
+ uint32_unpack_big(s, &opcode) ; s += 4 ; vlen -= 4 ;
+ uint32_unpack_big(s, &len) ; s += 4 ; vlen -= 4 ;
+ if (len != vlen) strerr_dief1x(100, "invalid client request") ;
+ if (timeout)
+ {
+ if (!tain_from_millisecs(&p->deadline, timeout)) strerr_dief1x(100, "invalid client request") ;
+ tain_add_g(&p->deadline, &p->deadline) ;
+ }
+ else tain_add_g(&p->deadline, &tain_infinite_relative) ;
+ sassserver_uniquify(&p->deadline) ;
+ if (!avltree_insert(&sassserver_by_deadline, handle)) strerr_diefu1sys(111, "avltree_insert") ;
+ if (!avltree_insert(&sassserver_by_id, handle)) strerr_diefu1sys(111, "avltree_insert") ;
+ p->data = (*sassserver_sendf)(handle, opcode, s, len) ;
+ if (!p->data)
+ {
+ int e = errno ;
+ sassserver_remove(handle) ;
+ sassserver_sync_answer(e) ;
+ }
+ else sassserver_sync_answer(0) ;
+ break ;
+ }
+ default : strerr_dief1x(100, "invalid client request") ;
+ }
+ return 1 ;
+}
+
+void sassserver_init (char const *banner1, char const *banner2, sassserver_send_func_ref sendf, sassserver_cancel_func_ref cancelf, tain const *deadline, tain *stamp)
+{
+ if (!textclient_server_01x_init(banner1, strlen(banner1), banner2, strlen(banner2), deadline, stamp))
+ strerr_diefu1sys(111, "sync with client") ;
+ sassserver_sendf = sendf ;
+ sassserver_cancelf = cancelf ;
+}
+
+unsigned int sassserver_prepare_iopause (iopause_fd *x, tain *deadline)
+{
+ uint32_t i ;
+ if (avltree_min(&sassserver_by_deadline, &i)) tain_earliest1(deadline, &SASSSERVER_QUERY(i)->deadline) ;
+ x[0].fd = 0 ;
+ x[0].events = IOPAUSE_READ ;
+ x[1].fd = 1 ;
+ x[1].events = textmessage_sender_isempty(textmessage_sender_1) ? 0 : IOPAUSE_WRITE ;
+ x[2].fd = textmessage_sender_fd(textmessage_sender_x) ;
+ x[2].events = textmessage_sender_isempty(textmessage_sender_x) ? 0 : IOPAUSE_WRITE ;
+ return 3 ;
+}
+
+void sassserver_timeout (void)
+{
+ uint32_t i ;
+ while (avltree_min(&sassserver_by_deadline, &i))
+ {
+ sassserver_query *p = SASSSERVER_QUERY(i) ;
+ if (tain_future(&p->deadline)) break ;
+ avltree_delete(&sassserver_by_deadline, &p->deadline) ;
+ avltree_delete(&sassserver_by_id, &p->id) ;
+ (*sassserver_cancelf)(p->data) ;
+ sassserver_async_failure(p->id, ETIMEDOUT) ;
+ gensetdyn_delete(&sassserver_queries, i) ;
+ }
+}
+
+int sassserver_event (iopause_fd const *x)
+{
+ if (x[1].revents & IOPAUSE_WRITE)
+ if (!textmessage_sender_flush(textmessage_sender_1) && !error_isagain(errno))
+ strerr_diefu1sys(111, "flush stdout") ;
+ if (x[2].revents & IOPAUSE_WRITE)
+ if (!textmessage_sender_flush(textmessage_sender_x) && !error_isagain(errno))
+ strerr_diefu1sys(111, "flush asyncout") ;
+
+ if (!textmessage_receiver_isempty(textmessage_receiver_0) || x[0].revents & IOPAUSE_READ)
+ {
+ if (textmessage_handle(textmessage_receiver_0, &sassserver_parse_protocol, 0) == -1)
+ {
+ if (errno != EPIPE) strerr_diefu1sys(111, "read messages from client") ;
+ return 1 ;
+ }
+ }
+ return 0 ;
+}