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_reomte *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_reomte *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) \
180 { buf_reset(&(ro)->r.bout); \
181 buf_putu16l(&(ro)->r.bout.b, (pk)); }) \
183 { tvec_send(&ro->_o.tv, &ro->r); })
185 static int sendstr(struct tvec_output *o, unsigned pk,
186 const char *p, va_list *ap)
188 struct remote_output *ro = (struct remote_output *)o;
190 if (ro->r.f&TVRF_BROKEN) return (-1);
191 dbuf_reset(&ro->r.bout);
192 buf_putu16l(&ro->r.bout.b, TVPK_ERROR);
193 buf_vputstrf16l(&ro->r.bout.b, msg, ap);
194 return (tvec_send(ro->_o.tv, &ro->r));
197 static void report(struct tvec_output *o, unsigned pk,
198 const char *msg, va_list *ap)
200 if (sendstr(o, pk, msg, ap)) {
201 fprintf(stderr, "%s: ", QUIS);
202 vfprintf(stderr, msg, *ap);
207 static void remote_error(struct tvec_output *o, const char *msg, va_list *ap)
208 { report(o, TVPK_ERROR, msg, ap); }
210 static void remote_notice(struct tvec_output *o,
211 const char *msg, va_list *ap)
212 { report(o, TVPK_NOTICE, msg, ap); }
214 static void remote_setstatus(struct tvec_ouptut *o, int st)
216 struct remote_output *ro = (struct remote_output *)o;
217 SENDPK(ro, TVPK_STATUS) buf_putbyte(&ro->r.bout.b, st);
220 static void remote_skipgroup(struct tvec_output *o,
221 const char *excuse, va_list *ap)
222 { sendstr(o, TVPK_SKIPGRP, excuse, ap); }
224 static void remote_skip(struct tvec_output *o,
225 const char *excuse, va_list *ap)
226 { sendstr(o, TVPK_SKIP, excuse, ap); }
228 static void remote_fail(struct tvec_output *o,
229 const char *detail, va_list *ap)
230 { sendstr(o, TVPK_FAIL, detail, ap); }
232 static void remote_mismatch(struct tvec_output *o)
234 struct remote_output *ro = (struct remote_output *)o;
235 struct tvec_state *rv = ro->_o.tv;
237 SENDPK(ro, TVPK_MISMATCH) {
238 tvec_serialize(tv, &ro->r.bout.b, tv->in, tv->nreg, tv->regsz);
239 tvec_serialize(tv, &ro->r.bout.b, tv->out, tv->nrout, tv->regsz);
243 static void remote_bbench(struct tvec_output *o)
245 struct remote_output *ro = (struct remote_output *)o;
246 struct tvec_state *rv = ro->_o.tv;
248 SENDPK(ro, TVPK_BBENCH)
249 tvec_serialize(tv, &ro->r.bout.b, tv->in, tv->nreg, tv->regsz);
252 static void remote_ebench(struct tvec_output *o,
253 const struct bench_timing *t)
255 struct remote_output *ro = (struct remote_output *)o;
258 SENDPK(ro, TVPK_EBENCH) {
259 buf_putu16l(&ro->r.bout.b, t->f);
260 ASSIGN64(k, t->n); buf_putk64l(&ro->r.bout.b, k);
261 if (t->f&BTF_TIMEOK) buf_putf64l(&ro->r.bout.b, t->t);
262 if (t->f&BTF_CYOK) buf_putf64l(&ro->r.bout.b, t->cy);
266 static void remote_write(struct tvec_output *o, const char *p, size_t sz)
267 { assert(!"remote_write"); }
268 static void remote_bsession(struct tvec_output *o)
269 { assert(!"remote_bsession"); }
270 static int remote_esession(struct tvec_output *o)
271 { assert(!"remote_esession"); return (-1); }
272 static void remote_bgroup(struct tvec_output *o)
273 { assert(!"remote_bgroup"); }
274 static void remote_btest(struct tvec_output *o)
275 { assert(!"remote_btest"); }
276 static void remote_egroup(struct tvec_output *o, unsigned outcome)
277 { assert(!"remote_egroup"); }
278 static void remote_etest(struct tvec_output *o, unsigned outcome)
279 { assert(!"remote_etest"); }
281 static void remote_destroy(struct tvec_output *o)
285 static const struct tvec_outops remote_ops = {
286 remote_error, remote_notice, remote_setstatus, remote_write,
287 remote_bsession, remote_esession,
288 remote_bgroup, remote_egroup, remote_skip,
289 remote_btest, remote_skip, remote_fail, remote_mismatch, remote_etest,
290 remote_bbench, remote_ebench,
293 /*----- Main code ---------------------------------------------------------*/
297 /*----- That's all, folks -------------------------------------------------*/