5 * (c) 2023 Straylight/Edgeware
8 /*----- Licensing notice --------------------------------------------------*
10 * This file is part of the mLib utilities library.
12 * mLib is free software: you can redistribute it and/or modify it under
13 * the terms of the GNU Library General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or (at
15 * your option) any later version.
17 * mLib is distributed in the hope that it will be useful, but WITHOUT
18 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
20 * License for more details.
22 * You should have received a copy of the GNU Library General Public
23 * License along with mLib. If not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
28 /*----- Header files ------------------------------------------------------*/
36 #include <sys/types.h>
45 /*----- Data structures ---------------------------------------------------*/
51 #define TVRF_BROKEN 1u
54 struct tvec_remotectx {
59 struct remote_output {
60 struct tvec_output _o;
64 /*----- Basic I/O ---------------------------------------------------------*/
66 static int PRINTF_LIKE(3, 4)
67 ioerr(struct tvec_state *tv, struct tvec_remote *r, const char *msg, ...)
73 tvec_write(tv, msg, &ap);
78 static int send_all(struct tvec_state *tv, struct tvec_remote *r,
79 const unsigned char *p, size_t sz)
84 n = write(r->outfd, p, sz);
88 return (ioerr(tv, r, "failed to send: %s",
89 n ? strerror(errno) : "empty write"));
94 #define RCVF_ALLOWEOF 1u
95 static int recv_all(struct tvec_state *tv, struct tvec_remote *r,
96 unsigned char *p, size_t sz, unsigned f)
103 n = read(r->infd, p, sz);
105 { p += n; sz -= n; ff |= f_any; }
106 else if (!n && (f&RCVF_ALLOWEOF) && !(ff&f_any))
109 return (ioerr(tv, r, "failed to receive: %s",
110 n ? strerror(errno) : "unexpected end-of-file"));
117 int tvec_send(struct tvec_state *tv, struct tvec_remote *r)
119 kludge64 k; unsigned char lenbuf[8];
120 const char *p; size_t sz;
122 if (r->f&TVRF_BROKEN) return (-1);
123 if (BBAD(&r->bout.b))
124 return (ioerr(tv, r, "failed to build output packet buffer");
126 p = BBASE(r->bout.b); sz = BLEN(&r->bout.b);
127 ASSIGN64(k, sz); STORE64_L_(lenbuf, k);
128 if (send_all(tv, r, lenbuf, sizeof(lenbuf))) return (-1);
129 if (send_all(tv, r, p, sz)) return (-1);
134 int tvec_recv(struct tvec_state *tv, struct tvec_remote *r, buf *b_out)
136 kludge64 k, szmax; unsigned char lenbuf[8];
141 if (r->f&TVRF_BROKEN) return (-1);
142 ASSIGN64(k, (size_t)-1);
143 rc = recv_all(tv, r, lenbuf, sizeof(lenbuf), RCVF_ALLOWEOF);
145 LOAD64_L_(k, lenbuf);
146 if (CMP64(k, >, szmax))
147 return (ioerr(tv, r, "packet size 0x%08lx%08lx out of range",
148 (unsigned long)HI64(k), (unsigned long)LO64(k)));
150 sz = GET64(size_t, k); buf_reset(&r->bin); p = buf_get(&r->bin.b, sz);
151 if (!p) return (ioerr(tv, r, "failed to allocate receive buffer"));
152 if (recv_all(tv, r, p, sz, 0)) return (-1);
153 buf_init(b_out, p, sz); return (0);
156 /*----- Data formatting primitives ----------------------------------------*/
159 /*----- Packet types ------------------------------------------------------*/
161 #define TVPK_ERROR 0x0001 /* msg: string */
162 #define TVPK_NOTICE 0x0002 /* msg: string */
163 #define TVPK_STATUS 0x0003 /* st: char */
165 #define TVPK_BGROUP 0x0101 /* name: string */
166 #define TVPK_TEST 0x0102 /* in: regs */
167 #define TVPK_EGROUP 0x0103 /* --- */
169 #define TVPK_SKIPGRP 0x0201 /* excuse: string */
170 #define TVPK_SKIP 0x0202 /* excuse: string */
171 #define TVPK_FAIL 0x0203 /* detail: string */
172 #define TVPK_MISMATCH 0x0204 /* in, out: regs */
173 #define TVPK_BBENCH 0x0205 /* in: regs */
174 #define TVPK_EBENCH 0x0206 /* flags: u16; n: u64; t, cy: float */
176 /*----- The output driver -------------------------------------------------*/
178 #define SENDPK(ro, pk) \
179 if ((ro)->r.f&TVRF_BROKEN) /* do nothing */; else \
181 { buf_reset(&(ro)->r.bout); \
182 buf_putu16l(&(ro)->r.bout.b, (pk)); }) \
184 { tvec_send(&ro->_o.tv, &ro->r); })
186 static int sendstr(struct tvec_output *o, unsigned pk,
187 const char *p, va_list *ap)
189 struct remote_output *ro = (struct remote_output *)o;
191 SENDPK(ro, pk) buf_vputstrf16l(&ro->r.bout.b, msg, ap);
192 return (ro->r.f&TVRF_BROKEN ? -1 : 0);
195 static void report(struct tvec_output *o, unsigned pk, const char *what,
196 const char *msg, va_list *ap)
198 if (sendstr(o, pk, msg, ap)) {
199 fprintf(stderr, "%s %s: ", QUIS, what);
200 vfprintf(stderr, msg, *ap);
205 static void remote_error(struct tvec_output *o, const char *msg, va_list *ap)
206 { report(o, TVPK_ERROR, "ERROR", msg, ap); }
208 static void remote_notice(struct tvec_output *o,
209 const char *msg, va_list *ap)
210 { report(o, TVPK_NOTICE, "notice", msg, ap); }
212 static void remote_setstatus(struct tvec_ouptut *o, int st)
214 struct remote_output *ro = (struct remote_output *)o;
215 SENDPK(ro, TVPK_STATUS) buf_putbyte(&ro->r.bout.b, st);
218 static void remote_skipgroup(struct tvec_output *o,
219 const char *excuse, va_list *ap)
220 { sendstr(o, TVPK_SKIPGRP, excuse, ap); }
222 static void remote_skip(struct tvec_output *o,
223 const char *excuse, va_list *ap)
224 { sendstr(o, TVPK_SKIP, excuse, ap); }
226 static void remote_fail(struct tvec_output *o,
227 const char *detail, va_list *ap)
228 { sendstr(o, TVPK_FAIL, detail, ap); }
230 static void remote_mismatch(struct tvec_output *o)
232 struct remote_output *ro = (struct remote_output *)o;
233 struct tvec_state *rv = ro->_o.tv;
235 SENDPK(ro, TVPK_MISMATCH) {
236 tvec_serialize(tv, &ro->r.bout.b, tv->in, tv->nreg, tv->regsz);
237 tvec_serialize(tv, &ro->r.bout.b, tv->out, tv->nrout, tv->regsz);
241 static void remote_bbench(struct tvec_output *o)
243 struct remote_output *ro = (struct remote_output *)o;
244 struct tvec_state *rv = ro->_o.tv;
246 SENDPK(ro, TVPK_BBENCH)
247 tvec_serialize(tv, &ro->r.bout.b, tv->in, tv->nreg, tv->regsz);
250 static void remote_ebench(struct tvec_output *o,
251 const struct bench_timing *t)
253 struct remote_output *ro = (struct remote_output *)o;
256 SENDPK(ro, TVPK_EBENCH) {
257 buf_putu16l(&ro->r.bout.b, t->f);
258 ASSIGN64(k, t->n); buf_putk64l(&ro->r.bout.b, k);
259 if (t->f&BTF_TIMEOK) buf_putf64l(&ro->r.bout.b, t->t);
260 if (t->f&BTF_CYOK) buf_putf64l(&ro->r.bout.b, t->cy);
264 static void remote_write(struct tvec_output *o, const char *p, size_t sz)
265 { assert(!"remote_write"); }
266 static void remote_bsession(struct tvec_output *o)
267 { assert(!"remote_bsession"); }
268 static int remote_esession(struct tvec_output *o)
269 { assert(!"remote_esession"); return (-1); }
270 static void remote_bgroup(struct tvec_output *o)
271 { assert(!"remote_bgroup"); }
272 static void remote_btest(struct tvec_output *o)
273 { assert(!"remote_btest"); }
274 static void remote_egroup(struct tvec_output *o, unsigned outcome)
275 { assert(!"remote_egroup"); }
276 static void remote_etest(struct tvec_output *o, unsigned outcome)
277 { assert(!"remote_etest"); }
279 static void remote_destroy(struct tvec_output *o)
283 static const struct tvec_outops remote_ops = {
284 remote_error, remote_notice, remote_setstatus, remote_write,
285 remote_bsession, remote_esession,
286 remote_bgroup, remote_egroup, remote_skip,
287 remote_btest, remote_skip, remote_fail, remote_mismatch, remote_etest,
288 remote_bbench, remote_ebench,
291 /*----- Main code ---------------------------------------------------------*/
295 /*----- That's all, folks -------------------------------------------------*/