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 struct HCHead *hcc_read_command(struct HostConf *hc, hctransaction_t trans);
14 static void hcc_start_reply(hctransaction_t trans, struct HCHead *rhead);
17 hcc_connect(struct HostConf *hc)
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];
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;
88 struct HCTransaction trans;
89 int (*dispatch[256])(hctransaction_t, struct HCHead *);
94 bzero(&hcslave, sizeof(hcslave));
95 bzero(&trans, sizeof(trans));
96 bzero(dispatch, sizeof(dispatch));
97 for (i = 0; i < count; ++i) {
98 struct HCDesc *desc = &descs[i];
99 assert(desc->cmd >= 0 && desc->cmd < 256);
100 dispatch[desc->cmd] = desc->func;
102 for (i = 0; i < 256; ++i) {
103 if (dispatch[i] == NULL)
104 dispatch[i] = rc_badop;
107 hcslave.fdout = fdout;
111 * Process commands on fdin and write out results on fdout
117 head = hcc_read_command(trans.hc, &trans);
122 * Start the reply and dispatch, then process the return code.
125 hcc_start_reply(&trans, head);
127 r = dispatch[head->cmd & 255](&trans, head);
131 head->error = EINVAL;
144 * Write out the reply
146 whead = (void *)trans.wbuf;
147 whead->bytes = trans.windex;
148 whead->error = head->error;
149 aligned_bytes = HCC_ALIGN(trans.windex);
151 hcc_debug_dump(whead);
153 if (write(hcslave.fdout, whead, aligned_bytes) != aligned_bytes)
160 * This reads a command from fdin, fixes up the byte ordering, and returns
161 * a pointer to HCHead.
163 * The MasterMutex may or may not be held. When threaded this command
164 * is serialized by a reader thread.
168 hcc_read_command(struct HostConf *hc, hctransaction_t trans)
170 hctransaction_t fill;
177 while (n < (int)sizeof(struct HCHead)) {
178 r = read(hc->fdin, (char *)&tmp + n, sizeof(struct HCHead) - n);
184 assert(tmp.bytes >= (int)sizeof(tmp) && tmp.bytes < 65536);
185 assert(tmp.magic == HCMAGIC);
190 fprintf(stderr, "cpdup hlink protocol error with %s (%04x)\n",
195 bcopy(&tmp, fill->rbuf, n);
196 aligned_bytes = HCC_ALIGN(tmp.bytes);
198 while (n < aligned_bytes) {
199 r = read(hc->fdin, fill->rbuf + n, aligned_bytes - n);
205 hcc_debug_dump(head);
207 fill->state = HCT_REPLIED;
208 return((void *)fill->rbuf);
215 hcc_get_trans(struct HostConf *hc)
221 hcc_free_trans(struct HostConf *hc __unused)
227 * Initialize for a new command
230 hcc_start_command(struct HostConf *hc, int16_t cmd)
232 struct HCHead *whead;
233 hctransaction_t trans;
235 trans = hcc_get_trans(hc);
237 whead = (void *)trans->wbuf;
238 whead->magic = HCMAGIC;
241 whead->id = trans->id;
244 trans->windex = sizeof(*whead);
246 trans->state = HCT_IDLE;
252 hcc_start_reply(hctransaction_t trans, struct HCHead *rhead)
254 struct HCHead *whead = (void *)trans->wbuf;
256 whead->magic = HCMAGIC;
258 whead->cmd = rhead->cmd | HCF_REPLY;
259 whead->id = rhead->id;
262 trans->windex = sizeof(*whead);
266 * Finish constructing a command, transmit it, and await the reply.
267 * Return the HCHead of the reply.
270 hcc_finish_command(hctransaction_t trans)
273 struct HCHead *whead;
274 struct HCHead *rhead;
279 whead = (void *)trans->wbuf;
280 whead->bytes = trans->windex;
281 aligned_bytes = HCC_ALIGN(trans->windex);
283 trans->state = HCT_SENT;
285 if (write(hc->fdout, whead, aligned_bytes) != aligned_bytes) {
291 if (whead->cmd < 0x0010)
293 fprintf(stderr, "cpdup lost connection to %s\n", hc->host);
300 * whead is invalid when we call hcc_read_command() because
301 * we may switch to another thread.
303 rhead = hcc_read_command(hc, trans);
304 if (trans->state != HCT_REPLIED || rhead->id != trans->id) {
312 fprintf(stderr, "cpdup lost connection to %s\n", hc->host);
315 trans->state = HCT_DONE;
319 *__error = rhead->error;
321 errno = rhead->error;
328 hcc_leaf_string(hctransaction_t trans, int16_t leafid, const char *str)
331 int bytes = strlen(str) + 1;
333 item = (void *)(trans->wbuf + trans->windex);
334 assert(trans->windex + sizeof(*item) + bytes < 65536);
335 item->leafid = leafid;
337 item->bytes = sizeof(*item) + bytes;
338 bcopy(str, item + 1, bytes);
339 trans->windex = HCC_ALIGN(trans->windex + item->bytes);
343 hcc_leaf_data(hctransaction_t trans, int16_t leafid, const void *ptr, int bytes)
347 item = (void *)(trans->wbuf + trans->windex);
348 assert(trans->windex + sizeof(*item) + bytes < 65536);
349 item->leafid = leafid;
351 item->bytes = sizeof(*item) + bytes;
352 bcopy(ptr, item + 1, bytes);
353 trans->windex = HCC_ALIGN(trans->windex + item->bytes);
357 hcc_leaf_int32(hctransaction_t trans, int16_t leafid, int32_t value)
361 item = (void *)(trans->wbuf + trans->windex);
362 assert(trans->windex + sizeof(*item) + sizeof(value) < 65536);
363 item->leafid = leafid;
365 item->bytes = sizeof(*item) + sizeof(value);
366 *(int32_t *)(item + 1) = value;
367 trans->windex = HCC_ALIGN(trans->windex + item->bytes);
371 hcc_leaf_int64(hctransaction_t trans, int16_t leafid, int64_t value)
375 item = (void *)(trans->wbuf + trans->windex);
376 assert(trans->windex + sizeof(*item) + sizeof(value) < 65536);
377 item->leafid = leafid;
379 item->bytes = sizeof(*item) + sizeof(value);
380 *(int64_t *)(item + 1) = value;
381 trans->windex = HCC_ALIGN(trans->windex + item->bytes);
385 hcc_alloc_descriptor(struct HostConf *hc, void *ptr, int type)
387 struct HCHostDesc *hd;
388 struct HCHostDesc *hnew;
390 hnew = malloc(sizeof(struct HCHostDesc));
394 if ((hd = hc->hostdescs) != NULL) {
395 hnew->desc = hd->desc + 1;
400 hc->hostdescs = hnew;
405 hcc_get_descriptor(struct HostConf *hc, int desc, int type)
407 struct HCHostDesc *hd;
409 for (hd = hc->hostdescs; hd; hd = hd->next) {
410 if (hd->desc == desc && hd->type == type)
417 hcc_set_descriptor(struct HostConf *hc, int desc, void *ptr, int type)
419 struct HCHostDesc *hd;
420 struct HCHostDesc **hdp;
422 for (hdp = &hc->hostdescs; (hd = *hdp) != NULL; hdp = &hd->next) {
423 if (hd->desc == desc) {
435 hd = malloc(sizeof(*hd));
439 hd->next = hc->hostdescs;
445 hcc_firstitem(struct HCHead *head)
450 offset = sizeof(*head);
451 if (offset == head->bytes)
453 assert(head->bytes >= offset + (int)sizeof(*item));
454 item = (void *)(head + 1);
455 assert(head->bytes >= offset + item->bytes);
456 assert(item->bytes >= (int)sizeof(*item) && item->bytes < 65536 - offset);
461 hcc_nextitem(struct HCHead *head, struct HCLeaf *item)
465 item = (void *)((char *)item + HCC_ALIGN(item->bytes));
466 offset = (char *)item - (char *)head;
467 if (offset == head->bytes)
469 assert(head->bytes >= offset + (int)sizeof(*item));
470 assert(head->bytes >= offset + item->bytes);
471 assert(item->bytes >= (int)sizeof(*item) && item->bytes < 65536 - offset);
478 hcc_debug_dump(struct HCHead *head)
481 int aligned_bytes = HCC_ALIGN(head->bytes);
483 fprintf(stderr, "DUMP %04x (%d)", (u_int16_t)head->cmd, aligned_bytes);
484 if (head->cmd & HCF_REPLY)
485 fprintf(stderr, " error %d", head->error);
486 fprintf(stderr, "\n");
487 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
488 fprintf(stderr, " ITEM %04x DATA ", item->leafid);
489 switch(item->leafid & LCF_TYPEMASK) {
491 fprintf(stderr, "int32 %d\n", *(int32_t *)(item + 1));
494 fprintf(stderr, "int64 %lld\n", *(int64_t *)(item + 1));
497 fprintf(stderr, "\"%s\"\n", (char *)(item + 1));
500 fprintf(stderr, "(binary)\n");