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 $
13 static void hcc_start_reply(hctransaction_t trans, struct HCHead *rhead);
14 static int hcc_finish_reply(hctransaction_t trans, struct HCHead *head);
17 hcc_connect(struct HostConf *hc, int readonly)
23 if (hc == NULL || hc->host == NULL)
28 if (pipe(fdout) < 0) {
33 if ((hc->pid = fork()) == 0) {
50 for (m = 0; m < ssh_argc; m++)
51 av[n++] = ssh_argv[m];
55 av[n++] = (readonly ? "-RS" : "-S");
58 execv("/usr/bin/ssh", (void *)av);
60 } else if (hc->pid < 0) {
64 * Parent process. Do the initial handshake to make sure we are
65 * actually talking to a cpdup slave.
76 rc_badop(hctransaction_t trans __unused, struct HCHead *head)
78 head->error = EOPNOTSUPP;
83 hcc_slave(int fdin, int fdout, struct HCDesc *descs, int count)
85 struct HostConf hcslave;
87 struct HCTransaction trans;
88 int (*dispatch[256])(hctransaction_t, struct HCHead *);
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;
105 hcslave.fdout = fdout;
109 * Process commands on fdin and write out results on fdout
115 head = hcc_read_command(trans.hc, &trans);
120 * Start the reply and dispatch, then process the return code.
123 hcc_start_reply(&trans, head);
125 r = dispatch[head->cmd & 255](&trans, head);
129 head->error = EINVAL;
141 if (!hcc_finish_reply(&trans, head))
148 * This reads a command from fdin, fixes up the byte ordering, and returns
149 * a pointer to HCHead.
152 hcc_read_command(struct HostConf *hc, hctransaction_t trans)
154 hctransaction_t fill;
162 while (n < (int)sizeof(struct HCHead)) {
163 r = read(hc->fdin, (char *)&tmp + n, sizeof(struct HCHead) - n);
169 if (tmp.magic == HCMAGIC)
172 tmp.magic = hc_bswap32(tmp.magic);
173 if (tmp.magic != HCMAGIC)
174 fatal("magic mismatch with %s (%04x)", hc->host, tmp.id);
176 tmp.bytes = hc_bswap32(tmp.bytes);
177 tmp.cmd = hc_bswap16(tmp.cmd);
178 tmp.id = hc_bswap16(tmp.id);
179 tmp.error = hc_bswap32(tmp.error);
182 assert(tmp.bytes >= (int)sizeof(tmp) && tmp.bytes < HC_BUFSIZE);
185 fatal("cpdup hlink protocol error with %s (%04x)", hc->host, tmp.id);
187 fill->swap = need_swap;
188 bcopy(&tmp, fill->rbuf, n);
189 aligned_bytes = HCC_ALIGN(tmp.bytes);
191 while (n < aligned_bytes) {
192 r = read(hc->fdin, fill->rbuf + n, aligned_bytes - n);
198 hcc_debug_dump(trans, head);
200 fill->state = HCT_REPLIED;
201 return((void *)fill->rbuf);
207 * Initialize for a new command
210 hcc_start_command(struct HostConf *hc, int16_t cmd)
212 struct HCHead *whead;
213 hctransaction_t trans;
217 whead = (void *)trans->wbuf;
218 whead->magic = HCMAGIC;
221 whead->id = trans->id;
224 trans->windex = sizeof(*whead);
226 trans->state = HCT_IDLE;
232 hcc_start_reply(hctransaction_t trans, struct HCHead *rhead)
234 struct HCHead *whead = (void *)trans->wbuf;
236 whead->magic = HCMAGIC;
238 whead->cmd = rhead->cmd | HCF_REPLY;
239 whead->id = rhead->id;
242 trans->windex = sizeof(*whead);
246 * Finish constructing a command, transmit it, and await the reply.
247 * Return the HCHead of the reply.
250 hcc_finish_command(hctransaction_t trans)
253 struct HCHead *whead;
254 struct HCHead *rhead;
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) {
272 if (whead->cmd < 0x0010)
274 fatal("cpdup lost connection to %s", hc->host);
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) {
292 fatal("cpdup lost connection to %s", hc->host);
294 trans->state = HCT_DONE;
298 *__error = rhead->error;
300 errno = rhead->error;
307 hcc_finish_reply(hctransaction_t trans, struct HCHead *head)
309 struct HCHead *whead;
312 whead = (void *)trans->wbuf;
313 whead->bytes = trans->windex;
314 whead->error = head->error;
315 aligned_bytes = HCC_ALIGN(trans->windex);
317 hcc_debug_dump(trans, whead);
319 return (write(trans->hc->fdout, whead, aligned_bytes) == aligned_bytes);
323 hcc_leaf_string(hctransaction_t trans, int16_t leafid, const char *str)
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;
332 item->bytes = sizeof(*item) + bytes;
333 bcopy(str, item + 1, bytes);
334 trans->windex = HCC_ALIGN(trans->windex + item->bytes);
338 hcc_leaf_data(hctransaction_t trans, int16_t leafid, const void *ptr, int bytes)
342 item = (void *)(trans->wbuf + trans->windex);
343 assert(trans->windex + sizeof(*item) + bytes < HC_BUFSIZE);
344 item->leafid = leafid;
346 item->bytes = sizeof(*item) + bytes;
347 bcopy(ptr, item + 1, bytes);
348 trans->windex = HCC_ALIGN(trans->windex + item->bytes);
352 hcc_leaf_int32(hctransaction_t trans, int16_t leafid, int32_t value)
356 item = (void *)(trans->wbuf + trans->windex);
357 assert(trans->windex + sizeof(*item) + sizeof(value) < HC_BUFSIZE);
358 item->leafid = leafid;
360 item->bytes = sizeof(*item) + sizeof(value);
361 *(int32_t *)(item + 1) = value;
362 trans->windex = HCC_ALIGN(trans->windex + item->bytes);
366 hcc_leaf_int64(hctransaction_t trans, int16_t leafid, int64_t value)
370 item = (void *)(trans->wbuf + trans->windex);
371 assert(trans->windex + sizeof(*item) + sizeof(value) < HC_BUFSIZE);
372 item->leafid = leafid;
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))
397 hcc_start_reply(trans, head);
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));
412 if ((hd = hc->hostdescs) != NULL) {
413 hnew->desc = hd->desc + 1;
415 /* start at 2 because 1 has a special meaning in hc_open() */
419 hc->hostdescs = hnew;
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)
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) {
454 hd = malloc(sizeof(*hd));
458 hd->next = hc->hostdescs;
464 hcc_nextitem(hctransaction_t trans, struct HCHead *head, struct HCLeaf *item)
469 item = (void *)(head + 1);
471 item = (void *)((char *)item + HCC_ALIGN(item->bytes));
472 offset = (char *)item - (char *)head;
473 if (offset == head->bytes)
479 item->leafid = hc_bswap16(item->leafid);
480 item->bytes = hc_bswap32(item->bytes);
481 switch (item->leafid & LCF_TYPEMASK) {
483 i32ptr = (void *)(item + 1);
484 *i32ptr = hc_bswap32(*i32ptr);
487 i64ptr = (void *)(item + 1);
488 *i64ptr = hc_bswap64(*i64ptr);
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);
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))
507 head = hcc_read_command(hc, trans);
508 if (trans->state != HCT_REPLIED || head->id != trans->id)
511 trans->windex = (char *)item - (char *)head;
516 hcc_currentchaineditem(struct HostConf *hc, struct HCHead *head)
518 hctransaction_t trans = &hc->trans;
520 if (trans->windex == 0)
523 return ((void *) ((char *)head + trans->windex));
529 hcc_debug_dump(hctransaction_t trans, struct HCHead *head)
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) {
542 fprintf(stderr, "int32 %d\n", HCC_INT32(item));
545 fprintf(stderr, "int64 %lld\n", HCC_INT64(item));
548 fprintf(stderr, "\"%s\"\n", HCC_STRING(item));
551 fprintf(stderr, "(binary)\n");