dhcpcd: update README.DRAGONFLY
[dragonfly.git] / bin / cpdup / hclink.c
blob46198841baf8f9c91feb3f0ee1e1505599a852d2
1 /*
2 * HCLINK.C
4 * This module implements a simple remote control protocol
6 * $DragonFly: src/bin/cpdup/hclink.c,v 1.10 2008/05/24 17:21:36 dillon Exp $
7 */
9 #include "cpdup.h"
10 #include "hclink.h"
11 #include "hcproto.h"
13 static void hcc_start_reply(hctransaction_t trans, struct HCHead *rhead);
14 static int hcc_finish_reply(hctransaction_t trans, struct HCHead *head);
16 int
17 hcc_connect(struct HostConf *hc, int readonly)
19 int fdin[2];
20 int fdout[2];
21 const char *av[32];
23 if (hc == NULL || hc->host == NULL)
24 return(0);
26 if (pipe(fdin) < 0)
27 return(-1);
28 if (pipe(fdout) < 0) {
29 close(fdin[0]);
30 close(fdin[1]);
31 return(-1);
33 if ((hc->pid = fork()) == 0) {
35 * Child process
37 int n, m;
39 dup2(fdin[1], 1);
40 close(fdin[0]);
41 close(fdin[1]);
42 dup2(fdout[0], 0);
43 close(fdout[0]);
44 close(fdout[1]);
46 n = 0;
47 av[n++] = "ssh";
48 if (CompressOpt)
49 av[n++] = "-C";
50 for (m = 0; m < ssh_argc; m++)
51 av[n++] = ssh_argv[m];
52 av[n++] = "-T";
53 av[n++] = hc->host;
54 av[n++] = "cpdup";
55 av[n++] = (readonly ? "-RS" : "-S");
56 av[n++] = NULL;
58 execv("/usr/bin/ssh", (void *)av);
59 _exit(1);
60 } else if (hc->pid < 0) {
61 return(-1);
62 } else {
64 * Parent process. Do the initial handshake to make sure we are
65 * actually talking to a cpdup slave.
67 close(fdin[1]);
68 hc->fdin = fdin[0];
69 close(fdout[0]);
70 hc->fdout = fdout[1];
71 return(0);
75 static int
76 rc_badop(hctransaction_t trans __unused, struct HCHead *head)
78 head->error = EOPNOTSUPP;
79 return(0);
82 int
83 hcc_slave(int fdin, int fdout, struct HCDesc *descs, int count)
85 struct HostConf hcslave;
86 struct HCHead *head;
87 struct HCTransaction trans;
88 int (*dispatch[256])(hctransaction_t, struct HCHead *);
89 int i;
90 int r;
92 bzero(&hcslave, sizeof(hcslave));
93 bzero(&trans, sizeof(trans));
94 bzero(dispatch, sizeof(dispatch));
95 for (i = 0; i < count; ++i) {
96 struct HCDesc *desc = &descs[i];
97 assert(desc->cmd >= 0 && desc->cmd < 256);
98 dispatch[desc->cmd] = desc->func;
100 for (i = 0; i < 256; ++i) {
101 if (dispatch[i] == NULL)
102 dispatch[i] = rc_badop;
104 hcslave.fdin = fdin;
105 hcslave.fdout = fdout;
106 trans.hc = &hcslave;
109 * Process commands on fdin and write out results on fdout
111 for (;;) {
113 * Get the command
115 head = hcc_read_command(trans.hc, &trans);
116 if (head == NULL)
117 break;
120 * Start the reply and dispatch, then process the return code.
122 head->error = 0;
123 hcc_start_reply(&trans, head);
125 r = dispatch[head->cmd & 255](&trans, head);
127 switch(r) {
128 case -2:
129 head->error = EINVAL;
130 break;
131 case -1:
132 head->error = errno;
133 break;
134 case 0:
135 break;
136 default:
137 assert(0);
138 break;
141 if (!hcc_finish_reply(&trans, head))
142 break;
144 return(0);
148 * This reads a command from fdin, fixes up the byte ordering, and returns
149 * a pointer to HCHead.
151 struct HCHead *
152 hcc_read_command(struct HostConf *hc, hctransaction_t trans)
154 struct HCHead tmp;
155 int aligned_bytes;
156 int need_swap;
157 int n;
158 int r;
160 if (trans == NULL)
161 fatal("cpdup hlink protocol error with %s", hc->host);
163 n = 0;
164 while (n < (int)sizeof(struct HCHead)) {
165 r = read(hc->fdin, (char *)&tmp + n, sizeof(struct HCHead) - n);
166 if (r <= 0)
167 goto fail;
168 n += r;
171 if (tmp.magic == HCMAGIC) {
172 need_swap = 0;
173 } else {
174 tmp.magic = hc_bswap32(tmp.magic);
175 if (tmp.magic != HCMAGIC)
176 fatal("magic mismatch with %s (%04x)", hc->host, tmp.id);
177 need_swap = 1;
178 tmp.bytes = hc_bswap32(tmp.bytes);
179 tmp.cmd = hc_bswap16(tmp.cmd);
180 tmp.id = hc_bswap16(tmp.id);
181 tmp.error = hc_bswap32(tmp.error);
184 assert(tmp.bytes >= (int)sizeof(tmp) && tmp.bytes < HC_BUFSIZE);
186 trans->swap = need_swap;
187 bcopy(&tmp, trans->rbuf, n);
188 aligned_bytes = HCC_ALIGN(tmp.bytes);
190 while (n < aligned_bytes) {
191 r = read(hc->fdin, trans->rbuf + n, aligned_bytes - n);
192 if (r <= 0)
193 goto fail;
194 n += r;
196 #ifdef DEBUG
197 hcc_debug_dump(trans, head);
198 #endif
199 trans->state = HCT_REPLIED;
200 return((void *)trans->rbuf);
201 fail:
202 trans->state = HCT_FAIL;
203 return(NULL);
207 * Initialize for a new command
209 hctransaction_t
210 hcc_start_command(struct HostConf *hc, int16_t cmd)
212 struct HCHead *whead;
213 hctransaction_t trans;
215 trans = &hc->trans;
217 whead = (void *)trans->wbuf;
218 whead->magic = HCMAGIC;
219 whead->bytes = 0;
220 whead->cmd = cmd;
221 whead->id = trans->id;
222 whead->error = 0;
224 trans->windex = sizeof(*whead);
225 trans->hc = hc;
226 trans->state = HCT_IDLE;
228 return(trans);
231 static void
232 hcc_start_reply(hctransaction_t trans, struct HCHead *rhead)
234 struct HCHead *whead = (void *)trans->wbuf;
236 whead->magic = HCMAGIC;
237 whead->bytes = 0;
238 whead->cmd = rhead->cmd | HCF_REPLY;
239 whead->id = rhead->id;
240 whead->error = 0;
242 trans->windex = sizeof(*whead);
246 * Finish constructing a command, transmit it, and await the reply.
247 * Return the HCHead of the reply.
249 struct HCHead *
250 hcc_finish_command(hctransaction_t trans)
252 struct HostConf *hc;
253 struct HCHead *whead;
254 struct HCHead *rhead;
255 int aligned_bytes;
256 int16_t wcmd;
258 hc = trans->hc;
259 whead = (void *)trans->wbuf;
260 whead->bytes = trans->windex;
261 aligned_bytes = HCC_ALIGN(trans->windex);
262 trans->windex = 0; /* initialize for hcc_nextchaineditem() */
264 trans->state = HCT_SENT;
266 if (write(hc->fdout, whead, aligned_bytes) != aligned_bytes) {
267 #ifdef __error
268 *__error = EIO;
269 #else
270 errno = EIO;
271 #endif
272 if (whead->cmd < 0x0010)
273 return(NULL);
274 fatal("cpdup lost connection to %s", hc->host);
277 wcmd = whead->cmd;
280 * whead is invalid when we call hcc_read_command() because
281 * we may switch to another thread.
283 rhead = hcc_read_command(hc, trans);
284 if (trans->state != HCT_REPLIED || rhead->id != trans->id) {
285 #ifdef __error
286 *__error = EIO;
287 #else
288 errno = EIO;
289 #endif
290 if (wcmd < 0x0010)
291 return(NULL);
292 fatal("cpdup lost connection to %s", hc->host);
294 trans->state = HCT_DONE;
296 if (rhead->error) {
297 #ifdef __error
298 *__error = rhead->error;
299 #else
300 errno = rhead->error;
301 #endif
303 return (rhead);
307 hcc_finish_reply(hctransaction_t trans, struct HCHead *head)
309 struct HCHead *whead;
310 int aligned_bytes;
312 whead = (void *)trans->wbuf;
313 whead->bytes = trans->windex;
314 whead->error = head->error;
315 aligned_bytes = HCC_ALIGN(trans->windex);
316 #ifdef DEBUG
317 hcc_debug_dump(trans, whead);
318 #endif
319 return (write(trans->hc->fdout, whead, aligned_bytes) == aligned_bytes);
322 void
323 hcc_leaf_string(hctransaction_t trans, int16_t leafid, const char *str)
325 struct HCLeaf *item;
326 int bytes = strlen(str) + 1;
328 item = (void *)(trans->wbuf + trans->windex);
329 assert(trans->windex + sizeof(*item) + bytes < HC_BUFSIZE);
330 item->leafid = leafid;
331 item->reserved = 0;
332 item->bytes = sizeof(*item) + bytes;
333 bcopy(str, item + 1, bytes);
334 trans->windex = HCC_ALIGN(trans->windex + item->bytes);
337 void
338 hcc_leaf_data(hctransaction_t trans, int16_t leafid, const void *ptr, int bytes)
340 struct HCLeaf *item;
342 item = (void *)(trans->wbuf + trans->windex);
343 assert(trans->windex + sizeof(*item) + bytes < HC_BUFSIZE);
344 item->leafid = leafid;
345 item->reserved = 0;
346 item->bytes = sizeof(*item) + bytes;
347 bcopy(ptr, item + 1, bytes);
348 trans->windex = HCC_ALIGN(trans->windex + item->bytes);
351 void
352 hcc_leaf_int32(hctransaction_t trans, int16_t leafid, int32_t value)
354 struct HCLeaf *item;
356 item = (void *)(trans->wbuf + trans->windex);
357 assert(trans->windex + sizeof(*item) + sizeof(value) < HC_BUFSIZE);
358 item->leafid = leafid;
359 item->reserved = 0;
360 item->bytes = sizeof(*item) + sizeof(value);
361 *(int32_t *)(item + 1) = value;
362 trans->windex = HCC_ALIGN(trans->windex + item->bytes);
365 void
366 hcc_leaf_int64(hctransaction_t trans, int16_t leafid, int64_t value)
368 struct HCLeaf *item;
370 item = (void *)(trans->wbuf + trans->windex);
371 assert(trans->windex + sizeof(*item) + sizeof(value) < HC_BUFSIZE);
372 item->leafid = leafid;
373 item->reserved = 0;
374 item->bytes = sizeof(*item) + sizeof(value);
375 *(int64_t *)(item + 1) = value;
376 trans->windex = HCC_ALIGN(trans->windex + item->bytes);
380 * Check if there's enough space left in the write buffer for <n>
381 * leaves with a total of <size> data bytes.
382 * If not, the current packet will be sent with the HCF_CONTINUE flag,
383 * then the transaction is initialized for another reply packet.
385 * Returns success status (boolean).
388 hcc_check_space(hctransaction_t trans, struct HCHead *head, int n, int size)
390 size = HCC_ALIGN(size) + n * sizeof(struct HCLeaf);
391 if (size >= HC_BUFSIZE - trans->windex) {
392 struct HCHead *whead = (void *)trans->wbuf;
394 whead->cmd |= HCF_CONTINUE;
395 if (!hcc_finish_reply(trans, head))
396 return (0);
397 hcc_start_reply(trans, head);
399 return (1);
402 intptr_t
403 hcc_alloc_descriptor(struct HostConf *hc, void *ptr, int type)
405 struct HCHostDesc *hd;
406 struct HCHostDesc *hnew;
408 hnew = malloc(sizeof(struct HCHostDesc));
409 hnew->type = type;
410 hnew->data = ptr;
412 if ((hd = hc->hostdescs) != NULL) {
413 hnew->desc = hd->desc + 1;
414 } else {
415 /* start at 2 because 1 has a special meaning in hc_open() */
416 hnew->desc = 2;
418 hnew->next = hd;
419 hc->hostdescs = hnew;
420 return(hnew->desc);
423 void *
424 hcc_get_descriptor(struct HostConf *hc, intptr_t desc, int type)
426 struct HCHostDesc *hd;
428 for (hd = hc->hostdescs; hd; hd = hd->next) {
429 if (hd->desc == desc && hd->type == type)
430 return(hd->data);
432 return(NULL);
435 void
436 hcc_set_descriptor(struct HostConf *hc, intptr_t desc, void *ptr, int type)
438 struct HCHostDesc *hd;
439 struct HCHostDesc **hdp;
441 for (hdp = &hc->hostdescs; (hd = *hdp) != NULL; hdp = &hd->next) {
442 if (hd->desc == desc) {
443 if (ptr) {
444 hd->data = ptr;
445 hd->type = type;
446 } else {
447 *hdp = hd->next;
448 free(hd);
450 return;
453 if (ptr) {
454 hd = malloc(sizeof(*hd));
455 hd->desc = desc;
456 hd->type = type;
457 hd->data = ptr;
458 hd->next = hc->hostdescs;
459 hc->hostdescs = hd;
463 struct HCLeaf *
464 hcc_nextitem(hctransaction_t trans, struct HCHead *head, struct HCLeaf *item)
466 int offset;
468 if (item == NULL)
469 item = (void *)(head + 1);
470 else
471 item = (void *)((char *)item + HCC_ALIGN(item->bytes));
472 offset = (char *)item - (char *)head;
473 if (offset == head->bytes)
474 return(NULL);
475 if (trans->swap) {
476 int64_t *i64ptr;
477 int32_t *i32ptr;
479 item->leafid = hc_bswap16(item->leafid);
480 item->bytes = hc_bswap32(item->bytes);
481 switch (item->leafid & LCF_TYPEMASK) {
482 case LCF_INT32:
483 i32ptr = (void *)(item + 1);
484 *i32ptr = hc_bswap32(*i32ptr);
485 break;
486 case LCF_INT64:
487 i64ptr = (void *)(item + 1);
488 *i64ptr = hc_bswap64(*i64ptr);
489 break;
492 assert(head->bytes >= offset + (int)sizeof(*item));
493 assert(head->bytes >= offset + item->bytes);
494 assert(item->bytes >= (int)sizeof(*item) && item->bytes < HC_BUFSIZE);
495 return (item);
498 struct HCLeaf *
499 hcc_nextchaineditem(struct HostConf *hc, struct HCHead *head)
501 hctransaction_t trans = &hc->trans;
502 struct HCLeaf *item = hcc_currentchaineditem(hc, head);
504 while ((item = hcc_nextitem(trans, head, item)) == NULL) {
505 if (!(head->cmd & HCF_CONTINUE))
506 return (NULL);
507 head = hcc_read_command(hc, trans);
508 if (trans->state != HCT_REPLIED || head->id != trans->id)
509 return (NULL);
511 trans->windex = (char *)item - (char *)head;
512 return (item);
515 struct HCLeaf *
516 hcc_currentchaineditem(struct HostConf *hc, struct HCHead *head)
518 hctransaction_t trans = &hc->trans;
520 if (trans->windex == 0)
521 return (NULL);
522 else
523 return ((void *) ((char *)head + trans->windex));
526 #ifdef DEBUG
528 void
529 hcc_debug_dump(hctransaction_t trans, struct HCHead *head)
531 struct HCLeaf *item;
532 int aligned_bytes = HCC_ALIGN(head->bytes);
534 fprintf(stderr, "DUMP %04x (%d)", (uint16_t)head->cmd, aligned_bytes);
535 if (head->cmd & HCF_REPLY)
536 fprintf(stderr, " error %d", head->error);
537 fprintf(stderr, "\n");
538 FOR_EACH_ITEM(item, trans, head) {
539 fprintf(stderr, " ITEM %04x DATA ", item->leafid);
540 switch(item->leafid & LCF_TYPEMASK) {
541 case LCF_INT32:
542 fprintf(stderr, "int32 %d\n", HCC_INT32(item));
543 break;
544 case LCF_INT64:
545 fprintf(stderr, "int64 %lld\n", HCC_INT64(item));
546 break;
547 case LCF_STRING:
548 fprintf(stderr, "\"%s\"\n", HCC_STRING(item));
549 break;
550 case LCF_BINARY:
551 fprintf(stderr, "(binary)\n");
552 break;
553 default:
554 printf("?\n");
559 #endif