xref: /dflybsd-src/bin/cpdup/hclink.c (revision 8bf5b238b6869b07d32313f388d8d715ae7c284d)
14d858d58SMatthew Dillon /*
24d858d58SMatthew Dillon  * HCLINK.C
34d858d58SMatthew Dillon  *
44d858d58SMatthew Dillon  * This module implements a simple remote control protocol
54d858d58SMatthew Dillon  *
6713d03c0SMatthew Dillon  * $DragonFly: src/bin/cpdup/hclink.c,v 1.10 2008/05/24 17:21:36 dillon Exp $
74d858d58SMatthew Dillon  */
84d858d58SMatthew Dillon 
9a2dc574cSMatthew Dillon #include "cpdup.h"
104d858d58SMatthew Dillon #include "hclink.h"
114d858d58SMatthew Dillon #include "hcproto.h"
124d858d58SMatthew Dillon 
13a2dc574cSMatthew Dillon static void hcc_start_reply(hctransaction_t trans, struct HCHead *rhead);
14c0538630SMatthew Dillon static int hcc_finish_reply(hctransaction_t trans, struct HCHead *head);
154d858d58SMatthew Dillon 
164d858d58SMatthew Dillon int
hcc_connect(struct HostConf * hc,int readonly)17c0538630SMatthew Dillon hcc_connect(struct HostConf *hc, int readonly)
184d858d58SMatthew Dillon {
194d858d58SMatthew Dillon     int fdin[2];
204d858d58SMatthew Dillon     int fdout[2];
218f0e7bc1SMatthew Dillon     const char *av[32];
224d858d58SMatthew Dillon 
234d858d58SMatthew Dillon     if (hc == NULL || hc->host == NULL)
244d858d58SMatthew Dillon 	return(0);
254d858d58SMatthew Dillon 
264d858d58SMatthew Dillon     if (pipe(fdin) < 0)
274d858d58SMatthew Dillon 	return(-1);
284d858d58SMatthew Dillon     if (pipe(fdout) < 0) {
294d858d58SMatthew Dillon 	close(fdin[0]);
304d858d58SMatthew Dillon 	close(fdin[1]);
314d858d58SMatthew Dillon 	return(-1);
324d858d58SMatthew Dillon     }
334d858d58SMatthew Dillon     if ((hc->pid = fork()) == 0) {
344d858d58SMatthew Dillon 	/*
354d858d58SMatthew Dillon 	 * Child process
364d858d58SMatthew Dillon 	 */
378f0e7bc1SMatthew Dillon 	int n, m;
3844dd1628SMatthew Dillon 
394d858d58SMatthew Dillon 	dup2(fdin[1], 1);
404d858d58SMatthew Dillon 	close(fdin[0]);
414d858d58SMatthew Dillon 	close(fdin[1]);
424d858d58SMatthew Dillon 	dup2(fdout[0], 0);
434d858d58SMatthew Dillon 	close(fdout[0]);
444d858d58SMatthew Dillon 	close(fdout[1]);
4544dd1628SMatthew Dillon 
4644dd1628SMatthew Dillon 	n = 0;
4744dd1628SMatthew Dillon 	av[n++] = "ssh";
4844dd1628SMatthew Dillon 	if (CompressOpt)
4944dd1628SMatthew Dillon 	    av[n++] = "-C";
508f0e7bc1SMatthew Dillon 	for (m = 0; m < ssh_argc; m++)
518f0e7bc1SMatthew Dillon 	    av[n++] = ssh_argv[m];
5244dd1628SMatthew Dillon 	av[n++] = "-T";
5344dd1628SMatthew Dillon 	av[n++] = hc->host;
5444dd1628SMatthew Dillon 	av[n++] = "cpdup";
55c0538630SMatthew Dillon 	av[n++] = (readonly ? "-RS" : "-S");
5644dd1628SMatthew Dillon 	av[n++] = NULL;
5744dd1628SMatthew Dillon 
5844dd1628SMatthew Dillon 	execv("/usr/bin/ssh", (void *)av);
594d858d58SMatthew Dillon 	_exit(1);
604d858d58SMatthew Dillon     } else if (hc->pid < 0) {
614d858d58SMatthew Dillon 	return(-1);
624d858d58SMatthew Dillon     } else {
634d858d58SMatthew Dillon 	/*
644d858d58SMatthew Dillon 	 * Parent process.  Do the initial handshake to make sure we are
654d858d58SMatthew Dillon 	 * actually talking to a cpdup slave.
664d858d58SMatthew Dillon 	 */
674d858d58SMatthew Dillon 	close(fdin[1]);
684d858d58SMatthew Dillon 	hc->fdin = fdin[0];
694d858d58SMatthew Dillon 	close(fdout[0]);
704d858d58SMatthew Dillon 	hc->fdout = fdout[1];
714d858d58SMatthew Dillon 	return(0);
724d858d58SMatthew Dillon     }
734d858d58SMatthew Dillon }
744d858d58SMatthew Dillon 
754d858d58SMatthew Dillon static int
rc_badop(hctransaction_t trans __unused,struct HCHead * head)76a2dc574cSMatthew Dillon rc_badop(hctransaction_t trans __unused, struct HCHead *head)
774d858d58SMatthew Dillon {
784d858d58SMatthew Dillon     head->error = EOPNOTSUPP;
794d858d58SMatthew Dillon     return(0);
804d858d58SMatthew Dillon }
814d858d58SMatthew Dillon 
824d858d58SMatthew Dillon int
hcc_slave(int fdin,int fdout,struct HCDesc * descs,int count)834d858d58SMatthew Dillon hcc_slave(int fdin, int fdout, struct HCDesc *descs, int count)
844d858d58SMatthew Dillon {
854d858d58SMatthew Dillon     struct HostConf hcslave;
864d858d58SMatthew Dillon     struct HCHead *head;
87a2dc574cSMatthew Dillon     struct HCTransaction trans;
88a2dc574cSMatthew Dillon     int (*dispatch[256])(hctransaction_t, struct HCHead *);
894d858d58SMatthew Dillon     int i;
904d858d58SMatthew Dillon     int r;
914d858d58SMatthew Dillon 
924d858d58SMatthew Dillon     bzero(&hcslave, sizeof(hcslave));
93a2dc574cSMatthew Dillon     bzero(&trans, sizeof(trans));
94293141b7SMatthew Dillon     bzero(dispatch, sizeof(dispatch));
954d858d58SMatthew Dillon     for (i = 0; i < count; ++i) {
964d858d58SMatthew Dillon 	struct HCDesc *desc = &descs[i];
974d858d58SMatthew Dillon 	assert(desc->cmd >= 0 && desc->cmd < 256);
984d858d58SMatthew Dillon 	dispatch[desc->cmd] = desc->func;
994d858d58SMatthew Dillon     }
1004d858d58SMatthew Dillon     for (i = 0; i < 256; ++i) {
1014d858d58SMatthew Dillon 	if (dispatch[i] == NULL)
1024d858d58SMatthew Dillon 	    dispatch[i] = rc_badop;
1034d858d58SMatthew Dillon     }
1044d858d58SMatthew Dillon     hcslave.fdin = fdin;
1054d858d58SMatthew Dillon     hcslave.fdout = fdout;
106a2dc574cSMatthew Dillon     trans.hc = &hcslave;
1074d858d58SMatthew Dillon 
1084d858d58SMatthew Dillon     /*
1094d858d58SMatthew Dillon      * Process commands on fdin and write out results on fdout
1104d858d58SMatthew Dillon      */
1114d858d58SMatthew Dillon     for (;;) {
1124d858d58SMatthew Dillon 	/*
1134d858d58SMatthew Dillon 	 * Get the command
1144d858d58SMatthew Dillon 	 */
11507424787SMatthew Dillon 	head = hcc_read_command(trans.hc, &trans);
1164d858d58SMatthew Dillon 	if (head == NULL)
1174d858d58SMatthew Dillon 	    break;
1184d858d58SMatthew Dillon 
1194d858d58SMatthew Dillon 	/*
1204d858d58SMatthew Dillon 	 * Start the reply and dispatch, then process the return code.
1214d858d58SMatthew Dillon 	 */
1224d858d58SMatthew Dillon 	head->error = 0;
123a2dc574cSMatthew Dillon 	hcc_start_reply(&trans, head);
124a2dc574cSMatthew Dillon 
125a2dc574cSMatthew Dillon 	r = dispatch[head->cmd & 255](&trans, head);
126a2dc574cSMatthew Dillon 
1274d858d58SMatthew Dillon 	switch(r) {
1284d858d58SMatthew Dillon 	case -2:
1294d858d58SMatthew Dillon 		head->error = EINVAL;
1304d858d58SMatthew Dillon 		break;
1314d858d58SMatthew Dillon 	case -1:
1324d858d58SMatthew Dillon 		head->error = errno;
1334d858d58SMatthew Dillon 		break;
1344d858d58SMatthew Dillon 	case 0:
1354d858d58SMatthew Dillon 		break;
1364d858d58SMatthew Dillon 	default:
1374d858d58SMatthew Dillon 		assert(0);
1384d858d58SMatthew Dillon 		break;
1394d858d58SMatthew Dillon 	}
1404d858d58SMatthew Dillon 
141c0538630SMatthew Dillon 	if (!hcc_finish_reply(&trans, head))
1424d858d58SMatthew Dillon 	    break;
1434d858d58SMatthew Dillon     }
1444d858d58SMatthew Dillon     return(0);
1454d858d58SMatthew Dillon }
1464d858d58SMatthew Dillon 
1474d858d58SMatthew Dillon /*
1484d858d58SMatthew Dillon  * This reads a command from fdin, fixes up the byte ordering, and returns
1494d858d58SMatthew Dillon  * a pointer to HCHead.
1504d858d58SMatthew Dillon  */
1514d858d58SMatthew Dillon struct HCHead *
hcc_read_command(struct HostConf * hc,hctransaction_t trans)15207424787SMatthew Dillon hcc_read_command(struct HostConf *hc, hctransaction_t trans)
1534d858d58SMatthew Dillon {
154a2dc574cSMatthew Dillon     struct HCHead tmp;
1554d858d58SMatthew Dillon     int aligned_bytes;
156c0538630SMatthew Dillon     int need_swap;
1574d858d58SMatthew Dillon     int n;
1584d858d58SMatthew Dillon     int r;
1594d858d58SMatthew Dillon 
160*8bf5b238SMatthew Dillon     if (trans == NULL)
161*8bf5b238SMatthew Dillon 	fatal("cpdup hlink protocol error with %s", hc->host);
162*8bf5b238SMatthew Dillon 
1634d858d58SMatthew Dillon     n = 0;
1644d858d58SMatthew Dillon     while (n < (int)sizeof(struct HCHead)) {
165a2dc574cSMatthew Dillon 	r = read(hc->fdin, (char *)&tmp + n, sizeof(struct HCHead) - n);
1664d858d58SMatthew Dillon 	if (r <= 0)
167a2dc574cSMatthew Dillon 	    goto fail;
1684d858d58SMatthew Dillon 	n += r;
1694d858d58SMatthew Dillon     }
170a2dc574cSMatthew Dillon 
171*8bf5b238SMatthew Dillon     if (tmp.magic == HCMAGIC) {
172c0538630SMatthew Dillon 	need_swap = 0;
173*8bf5b238SMatthew Dillon     } else {
174c0538630SMatthew Dillon 	tmp.magic = hc_bswap32(tmp.magic);
175c0538630SMatthew Dillon 	if (tmp.magic != HCMAGIC)
176c0538630SMatthew Dillon 	    fatal("magic mismatch with %s (%04x)", hc->host, tmp.id);
177c0538630SMatthew Dillon 	need_swap = 1;
178c0538630SMatthew Dillon 	tmp.bytes = hc_bswap32(tmp.bytes);
179c0538630SMatthew Dillon 	tmp.cmd   = hc_bswap16(tmp.cmd);
180c0538630SMatthew Dillon 	tmp.id    = hc_bswap16(tmp.id);
181c0538630SMatthew Dillon 	tmp.error = hc_bswap32(tmp.error);
182a2dc574cSMatthew Dillon     }
183a2dc574cSMatthew Dillon 
184c0538630SMatthew Dillon     assert(tmp.bytes >= (int)sizeof(tmp) && tmp.bytes < HC_BUFSIZE);
185c0538630SMatthew Dillon 
186*8bf5b238SMatthew Dillon     trans->swap = need_swap;
187*8bf5b238SMatthew Dillon     bcopy(&tmp, trans->rbuf, n);
188a2dc574cSMatthew Dillon     aligned_bytes = HCC_ALIGN(tmp.bytes);
189a2dc574cSMatthew Dillon 
1904d858d58SMatthew Dillon     while (n < aligned_bytes) {
191*8bf5b238SMatthew Dillon 	r = read(hc->fdin, trans->rbuf + n, aligned_bytes - n);
1924d858d58SMatthew Dillon 	if (r <= 0)
193a2dc574cSMatthew Dillon 	    goto fail;
1944d858d58SMatthew Dillon 	n += r;
1954d858d58SMatthew Dillon     }
1964d858d58SMatthew Dillon #ifdef DEBUG
197c0538630SMatthew Dillon     hcc_debug_dump(trans, head);
1984d858d58SMatthew Dillon #endif
199*8bf5b238SMatthew Dillon     trans->state = HCT_REPLIED;
200*8bf5b238SMatthew Dillon     return((void *)trans->rbuf);
201a2dc574cSMatthew Dillon fail:
202*8bf5b238SMatthew Dillon     trans->state = HCT_FAIL;
203a2dc574cSMatthew Dillon     return(NULL);
204a2dc574cSMatthew Dillon }
205a2dc574cSMatthew Dillon 
2064d858d58SMatthew Dillon /*
2074d858d58SMatthew Dillon  * Initialize for a new command
2084d858d58SMatthew Dillon  */
209a2dc574cSMatthew Dillon hctransaction_t
hcc_start_command(struct HostConf * hc,int16_t cmd)2104d858d58SMatthew Dillon hcc_start_command(struct HostConf *hc, int16_t cmd)
2114d858d58SMatthew Dillon {
212a2dc574cSMatthew Dillon     struct HCHead *whead;
213a2dc574cSMatthew Dillon     hctransaction_t trans;
2144d858d58SMatthew Dillon 
215c0538630SMatthew Dillon     trans = &hc->trans;
216a2dc574cSMatthew Dillon 
217a2dc574cSMatthew Dillon     whead = (void *)trans->wbuf;
2184d858d58SMatthew Dillon     whead->magic = HCMAGIC;
2194d858d58SMatthew Dillon     whead->bytes = 0;
2204d858d58SMatthew Dillon     whead->cmd = cmd;
221a2dc574cSMatthew Dillon     whead->id = trans->id;
2224d858d58SMatthew Dillon     whead->error = 0;
223a2dc574cSMatthew Dillon 
224a2dc574cSMatthew Dillon     trans->windex = sizeof(*whead);
225a2dc574cSMatthew Dillon     trans->hc = hc;
226a2dc574cSMatthew Dillon     trans->state = HCT_IDLE;
227a2dc574cSMatthew Dillon 
228a2dc574cSMatthew Dillon     return(trans);
229a2dc574cSMatthew Dillon }
230a2dc574cSMatthew Dillon 
231a2dc574cSMatthew Dillon static void
hcc_start_reply(hctransaction_t trans,struct HCHead * rhead)232a2dc574cSMatthew Dillon hcc_start_reply(hctransaction_t trans, struct HCHead *rhead)
233a2dc574cSMatthew Dillon {
234a2dc574cSMatthew Dillon     struct HCHead *whead = (void *)trans->wbuf;
235a2dc574cSMatthew Dillon 
236a2dc574cSMatthew Dillon     whead->magic = HCMAGIC;
237a2dc574cSMatthew Dillon     whead->bytes = 0;
238a2dc574cSMatthew Dillon     whead->cmd = rhead->cmd | HCF_REPLY;
239a2dc574cSMatthew Dillon     whead->id = rhead->id;
240a2dc574cSMatthew Dillon     whead->error = 0;
241a2dc574cSMatthew Dillon 
242a2dc574cSMatthew Dillon     trans->windex = sizeof(*whead);
2434d858d58SMatthew Dillon }
2444d858d58SMatthew Dillon 
2454d858d58SMatthew Dillon /*
2464d858d58SMatthew Dillon  * Finish constructing a command, transmit it, and await the reply.
2474d858d58SMatthew Dillon  * Return the HCHead of the reply.
2484d858d58SMatthew Dillon  */
2494d858d58SMatthew Dillon struct HCHead *
hcc_finish_command(hctransaction_t trans)250a2dc574cSMatthew Dillon hcc_finish_command(hctransaction_t trans)
2514d858d58SMatthew Dillon {
252713d03c0SMatthew Dillon     struct HostConf *hc;
2534d858d58SMatthew Dillon     struct HCHead *whead;
2544d858d58SMatthew Dillon     struct HCHead *rhead;
2554d858d58SMatthew Dillon     int aligned_bytes;
256a2dc574cSMatthew Dillon     int16_t wcmd;
2574d858d58SMatthew Dillon 
258713d03c0SMatthew Dillon     hc = trans->hc;
259a2dc574cSMatthew Dillon     whead = (void *)trans->wbuf;
260a2dc574cSMatthew Dillon     whead->bytes = trans->windex;
261a2dc574cSMatthew Dillon     aligned_bytes = HCC_ALIGN(trans->windex);
262c0538630SMatthew Dillon     trans->windex = 0;	/* initialize for hcc_nextchaineditem() */
263a2dc574cSMatthew Dillon 
264a2dc574cSMatthew Dillon     trans->state = HCT_SENT;
265a2dc574cSMatthew Dillon 
266713d03c0SMatthew Dillon     if (write(hc->fdout, whead, aligned_bytes) != aligned_bytes) {
2674d858d58SMatthew Dillon #ifdef __error
2684d858d58SMatthew Dillon 	*__error = EIO;
2694d858d58SMatthew Dillon #else
2704d858d58SMatthew Dillon 	errno = EIO;
2714d858d58SMatthew Dillon #endif
272d8bce52dSMatthew Dillon 	if (whead->cmd < 0x0010)
2734d858d58SMatthew Dillon 	    return(NULL);
274c0538630SMatthew Dillon 	fatal("cpdup lost connection to %s", hc->host);
2754d858d58SMatthew Dillon     }
276a2dc574cSMatthew Dillon 
277a2dc574cSMatthew Dillon     wcmd = whead->cmd;
278a2dc574cSMatthew Dillon 
279a2dc574cSMatthew Dillon     /*
280a2dc574cSMatthew Dillon      * whead is invalid when we call hcc_read_command() because
281a2dc574cSMatthew Dillon      * we may switch to another thread.
282a2dc574cSMatthew Dillon      */
283713d03c0SMatthew Dillon     rhead = hcc_read_command(hc, trans);
28407424787SMatthew Dillon     if (trans->state != HCT_REPLIED || rhead->id != trans->id) {
2854d858d58SMatthew Dillon #ifdef __error
2864d858d58SMatthew Dillon 	*__error = EIO;
2874d858d58SMatthew Dillon #else
2884d858d58SMatthew Dillon 	errno = EIO;
2894d858d58SMatthew Dillon #endif
290a2dc574cSMatthew Dillon 	if (wcmd < 0x0010)
2914d858d58SMatthew Dillon 		return(NULL);
292c0538630SMatthew Dillon 	fatal("cpdup lost connection to %s", hc->host);
2934d858d58SMatthew Dillon     }
29407424787SMatthew Dillon     trans->state = HCT_DONE;
295a2dc574cSMatthew Dillon 
2964d858d58SMatthew Dillon     if (rhead->error) {
2974d858d58SMatthew Dillon #ifdef __error
2984d858d58SMatthew Dillon 	*__error = rhead->error;
2994d858d58SMatthew Dillon #else
3004d858d58SMatthew Dillon 	errno = rhead->error;
3014d858d58SMatthew Dillon #endif
3024d858d58SMatthew Dillon     }
3034d858d58SMatthew Dillon     return (rhead);
3044d858d58SMatthew Dillon }
3054d858d58SMatthew Dillon 
306c0538630SMatthew Dillon int
hcc_finish_reply(hctransaction_t trans,struct HCHead * head)307c0538630SMatthew Dillon hcc_finish_reply(hctransaction_t trans, struct HCHead *head)
308c0538630SMatthew Dillon {
309c0538630SMatthew Dillon     struct HCHead *whead;
310c0538630SMatthew Dillon     int aligned_bytes;
311c0538630SMatthew Dillon 
312c0538630SMatthew Dillon     whead = (void *)trans->wbuf;
313c0538630SMatthew Dillon     whead->bytes = trans->windex;
314c0538630SMatthew Dillon     whead->error = head->error;
315c0538630SMatthew Dillon     aligned_bytes = HCC_ALIGN(trans->windex);
316c0538630SMatthew Dillon #ifdef DEBUG
317c0538630SMatthew Dillon     hcc_debug_dump(trans, whead);
318c0538630SMatthew Dillon #endif
319c0538630SMatthew Dillon     return (write(trans->hc->fdout, whead, aligned_bytes) == aligned_bytes);
320c0538630SMatthew Dillon }
321c0538630SMatthew Dillon 
3224d858d58SMatthew Dillon void
hcc_leaf_string(hctransaction_t trans,int16_t leafid,const char * str)323a2dc574cSMatthew Dillon hcc_leaf_string(hctransaction_t trans, int16_t leafid, const char *str)
3244d858d58SMatthew Dillon {
3254d858d58SMatthew Dillon     struct HCLeaf *item;
3264d858d58SMatthew Dillon     int bytes = strlen(str) + 1;
3274d858d58SMatthew Dillon 
328a2dc574cSMatthew Dillon     item = (void *)(trans->wbuf + trans->windex);
329c0538630SMatthew Dillon     assert(trans->windex + sizeof(*item) + bytes < HC_BUFSIZE);
3304d858d58SMatthew Dillon     item->leafid = leafid;
3314d858d58SMatthew Dillon     item->reserved = 0;
3324d858d58SMatthew Dillon     item->bytes = sizeof(*item) + bytes;
3334d858d58SMatthew Dillon     bcopy(str, item + 1, bytes);
334a2dc574cSMatthew Dillon     trans->windex = HCC_ALIGN(trans->windex + item->bytes);
3354d858d58SMatthew Dillon }
3364d858d58SMatthew Dillon 
3374d858d58SMatthew Dillon void
hcc_leaf_data(hctransaction_t trans,int16_t leafid,const void * ptr,int bytes)338a2dc574cSMatthew Dillon hcc_leaf_data(hctransaction_t trans, int16_t leafid, const void *ptr, int bytes)
3394d858d58SMatthew Dillon {
3404d858d58SMatthew Dillon     struct HCLeaf *item;
3414d858d58SMatthew Dillon 
342a2dc574cSMatthew Dillon     item = (void *)(trans->wbuf + trans->windex);
343c0538630SMatthew Dillon     assert(trans->windex + sizeof(*item) + bytes < HC_BUFSIZE);
3444d858d58SMatthew Dillon     item->leafid = leafid;
3454d858d58SMatthew Dillon     item->reserved = 0;
3464d858d58SMatthew Dillon     item->bytes = sizeof(*item) + bytes;
3474d858d58SMatthew Dillon     bcopy(ptr, item + 1, bytes);
348a2dc574cSMatthew Dillon     trans->windex = HCC_ALIGN(trans->windex + item->bytes);
3494d858d58SMatthew Dillon }
3504d858d58SMatthew Dillon 
3514d858d58SMatthew Dillon void
hcc_leaf_int32(hctransaction_t trans,int16_t leafid,int32_t value)352a2dc574cSMatthew Dillon hcc_leaf_int32(hctransaction_t trans, int16_t leafid, int32_t value)
3534d858d58SMatthew Dillon {
3544d858d58SMatthew Dillon     struct HCLeaf *item;
3554d858d58SMatthew Dillon 
356a2dc574cSMatthew Dillon     item = (void *)(trans->wbuf + trans->windex);
357c0538630SMatthew Dillon     assert(trans->windex + sizeof(*item) + sizeof(value) < HC_BUFSIZE);
3584d858d58SMatthew Dillon     item->leafid = leafid;
3594d858d58SMatthew Dillon     item->reserved = 0;
3604d858d58SMatthew Dillon     item->bytes = sizeof(*item) + sizeof(value);
3614d858d58SMatthew Dillon     *(int32_t *)(item + 1) = value;
362a2dc574cSMatthew Dillon     trans->windex = HCC_ALIGN(trans->windex + item->bytes);
3634d858d58SMatthew Dillon }
3644d858d58SMatthew Dillon 
3654d858d58SMatthew Dillon void
hcc_leaf_int64(hctransaction_t trans,int16_t leafid,int64_t value)366a2dc574cSMatthew Dillon hcc_leaf_int64(hctransaction_t trans, int16_t leafid, int64_t value)
3674d858d58SMatthew Dillon {
3684d858d58SMatthew Dillon     struct HCLeaf *item;
3694d858d58SMatthew Dillon 
370a2dc574cSMatthew Dillon     item = (void *)(trans->wbuf + trans->windex);
371c0538630SMatthew Dillon     assert(trans->windex + sizeof(*item) + sizeof(value) < HC_BUFSIZE);
3724d858d58SMatthew Dillon     item->leafid = leafid;
3734d858d58SMatthew Dillon     item->reserved = 0;
3744d858d58SMatthew Dillon     item->bytes = sizeof(*item) + sizeof(value);
3754d858d58SMatthew Dillon     *(int64_t *)(item + 1) = value;
376a2dc574cSMatthew Dillon     trans->windex = HCC_ALIGN(trans->windex + item->bytes);
3774d858d58SMatthew Dillon }
3784d858d58SMatthew Dillon 
379c0538630SMatthew Dillon /*
380c0538630SMatthew Dillon  * Check if there's enough space left in the write buffer for <n>
381c0538630SMatthew Dillon  * leaves with a total of <size> data bytes.
382c0538630SMatthew Dillon  * If not, the current packet will be sent with the HCF_CONTINUE flag,
383c0538630SMatthew Dillon  * then the transaction is initialized for another reply packet.
384c0538630SMatthew Dillon  *
385c0538630SMatthew Dillon  * Returns success status (boolean).
386c0538630SMatthew Dillon  */
3874d858d58SMatthew Dillon int
hcc_check_space(hctransaction_t trans,struct HCHead * head,int n,int size)388c0538630SMatthew Dillon hcc_check_space(hctransaction_t trans, struct HCHead *head, int n, int size)
389c0538630SMatthew Dillon {
390c0538630SMatthew Dillon     size = HCC_ALIGN(size) + n * sizeof(struct HCLeaf);
391704cef52SPeter Avalos     if (size >= HC_BUFSIZE - trans->windex) {
392c0538630SMatthew Dillon 	struct HCHead *whead = (void *)trans->wbuf;
393c0538630SMatthew Dillon 
394c0538630SMatthew Dillon 	whead->cmd |= HCF_CONTINUE;
395c0538630SMatthew Dillon 	if (!hcc_finish_reply(trans, head))
396c0538630SMatthew Dillon 	    return (0);
397c0538630SMatthew Dillon 	hcc_start_reply(trans, head);
398c0538630SMatthew Dillon     }
399c0538630SMatthew Dillon     return (1);
400c0538630SMatthew Dillon }
401c0538630SMatthew Dillon 
402c0538630SMatthew Dillon intptr_t
hcc_alloc_descriptor(struct HostConf * hc,void * ptr,int type)4034d858d58SMatthew Dillon hcc_alloc_descriptor(struct HostConf *hc, void *ptr, int type)
4044d858d58SMatthew Dillon {
4054d858d58SMatthew Dillon     struct HCHostDesc *hd;
4064d858d58SMatthew Dillon     struct HCHostDesc *hnew;
4074d858d58SMatthew Dillon 
4084d858d58SMatthew Dillon     hnew = malloc(sizeof(struct HCHostDesc));
4094d858d58SMatthew Dillon     hnew->type = type;
4104d858d58SMatthew Dillon     hnew->data = ptr;
4114d858d58SMatthew Dillon 
4124d858d58SMatthew Dillon     if ((hd = hc->hostdescs) != NULL) {
4134d858d58SMatthew Dillon 	hnew->desc = hd->desc + 1;
4144d858d58SMatthew Dillon     } else {
415c0538630SMatthew Dillon 	/* start at 2 because 1 has a special meaning in hc_open() */
416c0538630SMatthew Dillon 	hnew->desc = 2;
4174d858d58SMatthew Dillon     }
4184d858d58SMatthew Dillon     hnew->next = hd;
4194d858d58SMatthew Dillon     hc->hostdescs = hnew;
4204d858d58SMatthew Dillon     return(hnew->desc);
4214d858d58SMatthew Dillon }
4224d858d58SMatthew Dillon 
4234d858d58SMatthew Dillon void *
hcc_get_descriptor(struct HostConf * hc,intptr_t desc,int type)424c0538630SMatthew Dillon hcc_get_descriptor(struct HostConf *hc, intptr_t desc, int type)
4254d858d58SMatthew Dillon {
4264d858d58SMatthew Dillon     struct HCHostDesc *hd;
4274d858d58SMatthew Dillon 
4284d858d58SMatthew Dillon     for (hd = hc->hostdescs; hd; hd = hd->next) {
4294d858d58SMatthew Dillon 	if (hd->desc == desc && hd->type == type)
4304d858d58SMatthew Dillon 	    return(hd->data);
4314d858d58SMatthew Dillon     }
4324d858d58SMatthew Dillon     return(NULL);
4334d858d58SMatthew Dillon }
4344d858d58SMatthew Dillon 
4354d858d58SMatthew Dillon void
hcc_set_descriptor(struct HostConf * hc,intptr_t desc,void * ptr,int type)436c0538630SMatthew Dillon hcc_set_descriptor(struct HostConf *hc, intptr_t desc, void *ptr, int type)
4374d858d58SMatthew Dillon {
4384d858d58SMatthew Dillon     struct HCHostDesc *hd;
43971de6efcSMatthew Dillon     struct HCHostDesc **hdp;
4404d858d58SMatthew Dillon 
44171de6efcSMatthew Dillon     for (hdp = &hc->hostdescs; (hd = *hdp) != NULL; hdp = &hd->next) {
4424d858d58SMatthew Dillon 	if (hd->desc == desc) {
44371de6efcSMatthew Dillon 	    if (ptr) {
4444d858d58SMatthew Dillon 		hd->data = ptr;
4454d858d58SMatthew Dillon 		hd->type = type;
44671de6efcSMatthew Dillon 	    } else {
44771de6efcSMatthew Dillon 		*hdp = hd->next;
44871de6efcSMatthew Dillon 		free(hd);
44971de6efcSMatthew Dillon 	    }
4504d858d58SMatthew Dillon 	    return;
4514d858d58SMatthew Dillon 	}
4524d858d58SMatthew Dillon     }
45371de6efcSMatthew Dillon     if (ptr) {
4544d858d58SMatthew Dillon 	hd = malloc(sizeof(*hd));
4554d858d58SMatthew Dillon 	hd->desc = desc;
4564d858d58SMatthew Dillon 	hd->type = type;
4574d858d58SMatthew Dillon 	hd->data = ptr;
4584d858d58SMatthew Dillon 	hd->next = hc->hostdescs;
4594d858d58SMatthew Dillon 	hc->hostdescs = hd;
4604d858d58SMatthew Dillon     }
46171de6efcSMatthew Dillon }
4624d858d58SMatthew Dillon 
4634d858d58SMatthew Dillon struct HCLeaf *
hcc_nextitem(hctransaction_t trans,struct HCHead * head,struct HCLeaf * item)464c0538630SMatthew Dillon hcc_nextitem(hctransaction_t trans, struct HCHead *head, struct HCLeaf *item)
4654d858d58SMatthew Dillon {
4664d858d58SMatthew Dillon     int offset;
4674d858d58SMatthew Dillon 
468c0538630SMatthew Dillon     if (item == NULL)
4694d858d58SMatthew Dillon 	item = (void *)(head + 1);
470c0538630SMatthew Dillon     else
4714d858d58SMatthew Dillon 	item = (void *)((char *)item + HCC_ALIGN(item->bytes));
4724d858d58SMatthew Dillon     offset = (char *)item - (char *)head;
4734d858d58SMatthew Dillon     if (offset == head->bytes)
4744d858d58SMatthew Dillon 	return(NULL);
475c0538630SMatthew Dillon     if (trans->swap) {
476c0538630SMatthew Dillon 	int64_t *i64ptr;
477c0538630SMatthew Dillon 	int32_t *i32ptr;
478c0538630SMatthew Dillon 
479c0538630SMatthew Dillon 	item->leafid = hc_bswap16(item->leafid);
480c0538630SMatthew Dillon 	item->bytes  = hc_bswap32(item->bytes);
481c0538630SMatthew Dillon 	switch (item->leafid & LCF_TYPEMASK) {
482c0538630SMatthew Dillon 	    case LCF_INT32:
483c0538630SMatthew Dillon 		i32ptr = (void *)(item + 1);
484c0538630SMatthew Dillon 		*i32ptr = hc_bswap32(*i32ptr);
485c0538630SMatthew Dillon 		break;
486c0538630SMatthew Dillon 	    case LCF_INT64:
487c0538630SMatthew Dillon 		i64ptr = (void *)(item + 1);
488c0538630SMatthew Dillon 		*i64ptr = hc_bswap64(*i64ptr);
489c0538630SMatthew Dillon 		break;
490c0538630SMatthew Dillon 	}
491c0538630SMatthew Dillon     }
4924d858d58SMatthew Dillon     assert(head->bytes >= offset + (int)sizeof(*item));
4934d858d58SMatthew Dillon     assert(head->bytes >= offset + item->bytes);
494c0538630SMatthew Dillon     assert(item->bytes >= (int)sizeof(*item) && item->bytes < HC_BUFSIZE);
4954d858d58SMatthew Dillon     return (item);
4964d858d58SMatthew Dillon }
4974d858d58SMatthew Dillon 
498c0538630SMatthew Dillon struct HCLeaf *
hcc_nextchaineditem(struct HostConf * hc,struct HCHead * head)499c0538630SMatthew Dillon hcc_nextchaineditem(struct HostConf *hc, struct HCHead *head)
500c0538630SMatthew Dillon {
501c0538630SMatthew Dillon     hctransaction_t trans = &hc->trans;
502c0538630SMatthew Dillon     struct HCLeaf *item = hcc_currentchaineditem(hc, head);
503c0538630SMatthew Dillon 
504c0538630SMatthew Dillon     while ((item = hcc_nextitem(trans, head, item)) == NULL) {
505c0538630SMatthew Dillon 	if (!(head->cmd & HCF_CONTINUE))
506c0538630SMatthew Dillon 	    return (NULL);
507c0538630SMatthew Dillon 	head = hcc_read_command(hc, trans);
508c0538630SMatthew Dillon 	if (trans->state != HCT_REPLIED || head->id != trans->id)
509c0538630SMatthew Dillon 	    return (NULL);
510c0538630SMatthew Dillon     }
511c0538630SMatthew Dillon     trans->windex = (char *)item - (char *)head;
512c0538630SMatthew Dillon     return (item);
513c0538630SMatthew Dillon }
514c0538630SMatthew Dillon 
515c0538630SMatthew Dillon struct HCLeaf *
hcc_currentchaineditem(struct HostConf * hc,struct HCHead * head)516c0538630SMatthew Dillon hcc_currentchaineditem(struct HostConf *hc, struct HCHead *head)
517c0538630SMatthew Dillon {
518c0538630SMatthew Dillon     hctransaction_t trans = &hc->trans;
519c0538630SMatthew Dillon 
520c0538630SMatthew Dillon     if (trans->windex == 0)
521c0538630SMatthew Dillon 	return (NULL);
522c0538630SMatthew Dillon     else
523c0538630SMatthew Dillon 	return ((void *) ((char *)head + trans->windex));
524c0538630SMatthew Dillon }
525c0538630SMatthew Dillon 
5264d858d58SMatthew Dillon #ifdef DEBUG
5274d858d58SMatthew Dillon 
5284d858d58SMatthew Dillon void
hcc_debug_dump(hctransaction_t trans,struct HCHead * head)529c0538630SMatthew Dillon hcc_debug_dump(hctransaction_t trans, struct HCHead *head)
5304d858d58SMatthew Dillon {
5314d858d58SMatthew Dillon     struct HCLeaf *item;
5324d858d58SMatthew Dillon     int aligned_bytes = HCC_ALIGN(head->bytes);
5334d858d58SMatthew Dillon 
534c0538630SMatthew Dillon     fprintf(stderr, "DUMP %04x (%d)", (uint16_t)head->cmd, aligned_bytes);
5354d858d58SMatthew Dillon     if (head->cmd & HCF_REPLY)
5364d858d58SMatthew Dillon 	fprintf(stderr, " error %d", head->error);
5374d858d58SMatthew Dillon     fprintf(stderr, "\n");
538c0538630SMatthew Dillon     FOR_EACH_ITEM(item, trans, head) {
5394d858d58SMatthew Dillon 	fprintf(stderr, "    ITEM %04x DATA ", item->leafid);
5404d858d58SMatthew Dillon 	switch(item->leafid & LCF_TYPEMASK) {
5414d858d58SMatthew Dillon 	case LCF_INT32:
542c0538630SMatthew Dillon 	    fprintf(stderr, "int32 %d\n", HCC_INT32(item));
5434d858d58SMatthew Dillon 	    break;
5444d858d58SMatthew Dillon 	case LCF_INT64:
545c0538630SMatthew Dillon 	    fprintf(stderr, "int64 %lld\n", HCC_INT64(item));
5464d858d58SMatthew Dillon 	    break;
5474d858d58SMatthew Dillon 	case LCF_STRING:
548c0538630SMatthew Dillon 	    fprintf(stderr, "\"%s\"\n", HCC_STRING(item));
5494d858d58SMatthew Dillon 	    break;
5504d858d58SMatthew Dillon 	case LCF_BINARY:
5514d858d58SMatthew Dillon 	    fprintf(stderr, "(binary)\n");
5524d858d58SMatthew Dillon 	    break;
5534d858d58SMatthew Dillon 	default:
5544d858d58SMatthew Dillon 	    printf("?\n");
5554d858d58SMatthew Dillon 	}
5564d858d58SMatthew Dillon     }
5574d858d58SMatthew Dillon }
5584d858d58SMatthew Dillon 
5594d858d58SMatthew Dillon #endif
560