1*24ea1dbfSLutz Donnerhacke /* 2*24ea1dbfSLutz Donnerhacke * SPDX-License-Identifier: BSD-3-Clause 3*24ea1dbfSLutz Donnerhacke * 4*24ea1dbfSLutz Donnerhacke * Copyright 2021 Lutz Donnerhacke 5*24ea1dbfSLutz Donnerhacke * 6*24ea1dbfSLutz Donnerhacke * Redistribution and use in source and binary forms, with or without 7*24ea1dbfSLutz Donnerhacke * modification, are permitted provided that the following conditions 8*24ea1dbfSLutz Donnerhacke * are met: 9*24ea1dbfSLutz Donnerhacke * 10*24ea1dbfSLutz Donnerhacke * 1. Redistributions of source code must retain the above copyright 11*24ea1dbfSLutz Donnerhacke * notice, this list of conditions and the following disclaimer. 12*24ea1dbfSLutz Donnerhacke * 2. Redistributions in binary form must reproduce the above 13*24ea1dbfSLutz Donnerhacke * copyright notice, this list of conditions and the following 14*24ea1dbfSLutz Donnerhacke * disclaimer in the documentation and/or other materials provided 15*24ea1dbfSLutz Donnerhacke * with the distribution. 16*24ea1dbfSLutz Donnerhacke * 3. Neither the name of the copyright holder nor the names of its 17*24ea1dbfSLutz Donnerhacke * contributors may be used to endorse or promote products derived 18*24ea1dbfSLutz Donnerhacke * from this software without specific prior written permission. 19*24ea1dbfSLutz Donnerhacke * 20*24ea1dbfSLutz Donnerhacke * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 21*24ea1dbfSLutz Donnerhacke * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 22*24ea1dbfSLutz Donnerhacke * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 23*24ea1dbfSLutz Donnerhacke * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24*24ea1dbfSLutz Donnerhacke * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS 25*24ea1dbfSLutz Donnerhacke * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 26*24ea1dbfSLutz Donnerhacke * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 27*24ea1dbfSLutz Donnerhacke * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28*24ea1dbfSLutz Donnerhacke * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 29*24ea1dbfSLutz Donnerhacke * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 30*24ea1dbfSLutz Donnerhacke * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 31*24ea1dbfSLutz Donnerhacke * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32*24ea1dbfSLutz Donnerhacke * SUCH DAMAGE. 33*24ea1dbfSLutz Donnerhacke */ 34*24ea1dbfSLutz Donnerhacke #include <atf-c.h> 35*24ea1dbfSLutz Donnerhacke #include <errno.h> 36*24ea1dbfSLutz Donnerhacke #include <stdlib.h> 37*24ea1dbfSLutz Donnerhacke #include <stdio.h> 38*24ea1dbfSLutz Donnerhacke #include <string.h> 39*24ea1dbfSLutz Donnerhacke 40*24ea1dbfSLutz Donnerhacke #include <sys/select.h> 41*24ea1dbfSLutz Donnerhacke #include <sys/queue.h> 42*24ea1dbfSLutz Donnerhacke 43*24ea1dbfSLutz Donnerhacke #include "util.h" 44*24ea1dbfSLutz Donnerhacke 45*24ea1dbfSLutz Donnerhacke 46*24ea1dbfSLutz Donnerhacke static int cs = -1, ds = -1; 47*24ea1dbfSLutz Donnerhacke static ng_error_t error_handling = FAIL; 48*24ea1dbfSLutz Donnerhacke 49*24ea1dbfSLutz Donnerhacke #define CHECK(r, x) do { \ 50*24ea1dbfSLutz Donnerhacke if (error_handling == FAIL) \ 51*24ea1dbfSLutz Donnerhacke ATF_REQUIRE(x); \ 52*24ea1dbfSLutz Donnerhacke else if(!(x)) \ 53*24ea1dbfSLutz Donnerhacke return r; \ 54*24ea1dbfSLutz Donnerhacke } while(0) 55*24ea1dbfSLutz Donnerhacke 56*24ea1dbfSLutz Donnerhacke struct data_handler { 57*24ea1dbfSLutz Donnerhacke char const *hook; 58*24ea1dbfSLutz Donnerhacke ng_data_handler_t handler; 59*24ea1dbfSLutz Donnerhacke SLIST_ENTRY(data_handler) next; 60*24ea1dbfSLutz Donnerhacke }; 61*24ea1dbfSLutz Donnerhacke static SLIST_HEAD(, data_handler) data_head = SLIST_HEAD_INITIALIZER(data_head); 62*24ea1dbfSLutz Donnerhacke 63*24ea1dbfSLutz Donnerhacke static void handle_data(void *ctx); 64*24ea1dbfSLutz Donnerhacke static void handle_msg(void); 65*24ea1dbfSLutz Donnerhacke 66*24ea1dbfSLutz Donnerhacke void 67*24ea1dbfSLutz Donnerhacke ng_connect(char const *path1, char const *hook1, 68*24ea1dbfSLutz Donnerhacke char const *path2, char const *hook2) 69*24ea1dbfSLutz Donnerhacke { 70*24ea1dbfSLutz Donnerhacke struct ngm_connect c; 71*24ea1dbfSLutz Donnerhacke 72*24ea1dbfSLutz Donnerhacke strncpy(c.ourhook, hook1, sizeof(c.ourhook)); 73*24ea1dbfSLutz Donnerhacke strncpy(c.peerhook, hook2, sizeof(c.peerhook)); 74*24ea1dbfSLutz Donnerhacke strncpy(c.path, path2, sizeof(c.path)); 75*24ea1dbfSLutz Donnerhacke 76*24ea1dbfSLutz Donnerhacke CHECK(, -1 != NgSendMsg(cs, path1, 77*24ea1dbfSLutz Donnerhacke NGM_GENERIC_COOKIE, NGM_CONNECT, 78*24ea1dbfSLutz Donnerhacke &c, sizeof(c))); 79*24ea1dbfSLutz Donnerhacke } 80*24ea1dbfSLutz Donnerhacke 81*24ea1dbfSLutz Donnerhacke void 82*24ea1dbfSLutz Donnerhacke ng_mkpeer(char const *path1, char const *hook1, 83*24ea1dbfSLutz Donnerhacke char const *type, char const *hook2) 84*24ea1dbfSLutz Donnerhacke { 85*24ea1dbfSLutz Donnerhacke struct ngm_mkpeer p; 86*24ea1dbfSLutz Donnerhacke 87*24ea1dbfSLutz Donnerhacke strncpy(p.ourhook, hook1, sizeof(p.ourhook)); 88*24ea1dbfSLutz Donnerhacke strncpy(p.peerhook, hook2, sizeof(p.peerhook)); 89*24ea1dbfSLutz Donnerhacke strncpy(p.type, type, sizeof(p.type)); 90*24ea1dbfSLutz Donnerhacke 91*24ea1dbfSLutz Donnerhacke CHECK(, -1 != NgSendMsg(cs, path1, 92*24ea1dbfSLutz Donnerhacke NGM_GENERIC_COOKIE, NGM_MKPEER, 93*24ea1dbfSLutz Donnerhacke &p, sizeof(p))); 94*24ea1dbfSLutz Donnerhacke } 95*24ea1dbfSLutz Donnerhacke 96*24ea1dbfSLutz Donnerhacke void 97*24ea1dbfSLutz Donnerhacke ng_rmhook(char const *path, char const *hook) 98*24ea1dbfSLutz Donnerhacke { 99*24ea1dbfSLutz Donnerhacke struct ngm_rmhook h; 100*24ea1dbfSLutz Donnerhacke 101*24ea1dbfSLutz Donnerhacke strncpy(h.ourhook, hook, sizeof(h.ourhook)); 102*24ea1dbfSLutz Donnerhacke 103*24ea1dbfSLutz Donnerhacke CHECK(, -1 != NgSendMsg(cs, path, 104*24ea1dbfSLutz Donnerhacke NGM_GENERIC_COOKIE, NGM_RMHOOK, 105*24ea1dbfSLutz Donnerhacke &h, sizeof(h))); 106*24ea1dbfSLutz Donnerhacke } 107*24ea1dbfSLutz Donnerhacke 108*24ea1dbfSLutz Donnerhacke void 109*24ea1dbfSLutz Donnerhacke ng_name(char const *path, char const *name) 110*24ea1dbfSLutz Donnerhacke { 111*24ea1dbfSLutz Donnerhacke struct ngm_name n; 112*24ea1dbfSLutz Donnerhacke 113*24ea1dbfSLutz Donnerhacke strncpy(n.name, name, sizeof(n.name)); 114*24ea1dbfSLutz Donnerhacke 115*24ea1dbfSLutz Donnerhacke CHECK(, -1 != NgSendMsg(cs, path, 116*24ea1dbfSLutz Donnerhacke NGM_GENERIC_COOKIE, NGM_NAME, 117*24ea1dbfSLutz Donnerhacke &n, sizeof(n))); 118*24ea1dbfSLutz Donnerhacke } 119*24ea1dbfSLutz Donnerhacke 120*24ea1dbfSLutz Donnerhacke void 121*24ea1dbfSLutz Donnerhacke ng_shutdown(char const *path) 122*24ea1dbfSLutz Donnerhacke { 123*24ea1dbfSLutz Donnerhacke CHECK(, -1 != NgSendMsg(cs, path, 124*24ea1dbfSLutz Donnerhacke NGM_GENERIC_COOKIE, NGM_SHUTDOWN, 125*24ea1dbfSLutz Donnerhacke NULL, 0)); 126*24ea1dbfSLutz Donnerhacke } 127*24ea1dbfSLutz Donnerhacke 128*24ea1dbfSLutz Donnerhacke void 129*24ea1dbfSLutz Donnerhacke ng_register_data(char const *hook, ng_data_handler_t proc) 130*24ea1dbfSLutz Donnerhacke { 131*24ea1dbfSLutz Donnerhacke struct data_handler *p; 132*24ea1dbfSLutz Donnerhacke 133*24ea1dbfSLutz Donnerhacke ATF_REQUIRE(NULL != (p = calloc(1, sizeof(struct data_handler)))); 134*24ea1dbfSLutz Donnerhacke ATF_REQUIRE(NULL != (p->hook = strdup(hook))); 135*24ea1dbfSLutz Donnerhacke ATF_REQUIRE(NULL != (p->handler = proc)); 136*24ea1dbfSLutz Donnerhacke SLIST_INSERT_HEAD(&data_head, p, next); 137*24ea1dbfSLutz Donnerhacke } 138*24ea1dbfSLutz Donnerhacke 139*24ea1dbfSLutz Donnerhacke void 140*24ea1dbfSLutz Donnerhacke ng_send_data(char const *hook, 141*24ea1dbfSLutz Donnerhacke void const *data, size_t len) 142*24ea1dbfSLutz Donnerhacke { 143*24ea1dbfSLutz Donnerhacke CHECK(, -1 != NgSendData(ds, hook, data, len)); 144*24ea1dbfSLutz Donnerhacke } 145*24ea1dbfSLutz Donnerhacke 146*24ea1dbfSLutz Donnerhacke static void 147*24ea1dbfSLutz Donnerhacke handle_msg(void) { 148*24ea1dbfSLutz Donnerhacke struct ng_mesg *m; 149*24ea1dbfSLutz Donnerhacke char path[NG_PATHSIZ]; 150*24ea1dbfSLutz Donnerhacke 151*24ea1dbfSLutz Donnerhacke ATF_REQUIRE(-1 != NgAllocRecvMsg(cs, &m, path)); 152*24ea1dbfSLutz Donnerhacke 153*24ea1dbfSLutz Donnerhacke printf("Got message from %s\n", path); 154*24ea1dbfSLutz Donnerhacke free(m); 155*24ea1dbfSLutz Donnerhacke } 156*24ea1dbfSLutz Donnerhacke 157*24ea1dbfSLutz Donnerhacke static void 158*24ea1dbfSLutz Donnerhacke handle_data(void *ctx) { 159*24ea1dbfSLutz Donnerhacke char hook[NG_HOOKSIZ]; 160*24ea1dbfSLutz Donnerhacke struct data_handler *hnd; 161*24ea1dbfSLutz Donnerhacke u_char *data; 162*24ea1dbfSLutz Donnerhacke int len; 163*24ea1dbfSLutz Donnerhacke 164*24ea1dbfSLutz Donnerhacke ATF_REQUIRE(0 < (len = NgAllocRecvData(ds, &data, hook))); 165*24ea1dbfSLutz Donnerhacke SLIST_FOREACH(hnd, &data_head, next) 166*24ea1dbfSLutz Donnerhacke if (0 == strcmp(hnd->hook, hook)) 167*24ea1dbfSLutz Donnerhacke break; 168*24ea1dbfSLutz Donnerhacke 169*24ea1dbfSLutz Donnerhacke if (hnd != NULL) 170*24ea1dbfSLutz Donnerhacke (*(hnd->handler))(data, len, ctx); 171*24ea1dbfSLutz Donnerhacke 172*24ea1dbfSLutz Donnerhacke free(data); 173*24ea1dbfSLutz Donnerhacke } 174*24ea1dbfSLutz Donnerhacke 175*24ea1dbfSLutz Donnerhacke int 176*24ea1dbfSLutz Donnerhacke ng_handle_event(unsigned int ms, void *context) 177*24ea1dbfSLutz Donnerhacke { 178*24ea1dbfSLutz Donnerhacke fd_set fds; 179*24ea1dbfSLutz Donnerhacke int maxfd = (ds < cs) ? cs : ds; 180*24ea1dbfSLutz Donnerhacke struct timeval timeout = { 0, ms * 1000lu }; 181*24ea1dbfSLutz Donnerhacke 182*24ea1dbfSLutz Donnerhacke FD_ZERO(&fds); 183*24ea1dbfSLutz Donnerhacke FD_SET(cs, &fds); 184*24ea1dbfSLutz Donnerhacke FD_SET(ds, &fds); 185*24ea1dbfSLutz Donnerhacke retry: 186*24ea1dbfSLutz Donnerhacke switch (select(maxfd+1, &fds, NULL, NULL, &timeout)) { 187*24ea1dbfSLutz Donnerhacke case -1: 188*24ea1dbfSLutz Donnerhacke ATF_REQUIRE_ERRNO(EINTR, 1); 189*24ea1dbfSLutz Donnerhacke goto retry; 190*24ea1dbfSLutz Donnerhacke case 0: /* timeout */ 191*24ea1dbfSLutz Donnerhacke return 0; 192*24ea1dbfSLutz Donnerhacke default: /* something to do */ 193*24ea1dbfSLutz Donnerhacke if (FD_ISSET(cs, &fds)) 194*24ea1dbfSLutz Donnerhacke handle_msg(); 195*24ea1dbfSLutz Donnerhacke if (FD_ISSET(ds, &fds)) 196*24ea1dbfSLutz Donnerhacke handle_data(context); 197*24ea1dbfSLutz Donnerhacke return 1; 198*24ea1dbfSLutz Donnerhacke } 199*24ea1dbfSLutz Donnerhacke } 200*24ea1dbfSLutz Donnerhacke 201*24ea1dbfSLutz Donnerhacke void 202*24ea1dbfSLutz Donnerhacke ng_handle_events(unsigned int ms, void *context) 203*24ea1dbfSLutz Donnerhacke { 204*24ea1dbfSLutz Donnerhacke while(ng_handle_event(ms, context)) 205*24ea1dbfSLutz Donnerhacke ; 206*24ea1dbfSLutz Donnerhacke } 207*24ea1dbfSLutz Donnerhacke 208*24ea1dbfSLutz Donnerhacke int 209*24ea1dbfSLutz Donnerhacke ng_send_msg(char const *path, char const *msg) 210*24ea1dbfSLutz Donnerhacke { 211*24ea1dbfSLutz Donnerhacke int res; 212*24ea1dbfSLutz Donnerhacke 213*24ea1dbfSLutz Donnerhacke CHECK(-1, -1 != (res = NgSendAsciiMsg(cs, path, "%s", msg))); 214*24ea1dbfSLutz Donnerhacke return (res); 215*24ea1dbfSLutz Donnerhacke } 216*24ea1dbfSLutz Donnerhacke 217*24ea1dbfSLutz Donnerhacke ng_error_t 218*24ea1dbfSLutz Donnerhacke ng_errors(ng_error_t n) 219*24ea1dbfSLutz Donnerhacke { 220*24ea1dbfSLutz Donnerhacke ng_error_t o = error_handling; 221*24ea1dbfSLutz Donnerhacke 222*24ea1dbfSLutz Donnerhacke error_handling = n; 223*24ea1dbfSLutz Donnerhacke return (o); 224*24ea1dbfSLutz Donnerhacke } 225*24ea1dbfSLutz Donnerhacke 226*24ea1dbfSLutz Donnerhacke void 227*24ea1dbfSLutz Donnerhacke ng_init(void) { 228*24ea1dbfSLutz Donnerhacke if (cs >= 0) /* prevent reinit */ 229*24ea1dbfSLutz Donnerhacke return; 230*24ea1dbfSLutz Donnerhacke 231*24ea1dbfSLutz Donnerhacke ATF_REQUIRE(0 == NgMkSockNode(NULL, &cs, &ds)); 232*24ea1dbfSLutz Donnerhacke NgSetDebug(3); 233*24ea1dbfSLutz Donnerhacke } 234