4 * This module implements a simple remote control protocol
6 * $DragonFly: src/bin/cpdup/hclink.c,v 1.8 2008/04/14 05:40:51 dillon Exp $
13 static struct HCHead *hcc_read_command(hctransaction_t trans, int anypkt);
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) {
56 execv("/usr/bin/ssh", (void *)av);
58 } else if (hc->pid < 0) {
62 * Parent process. Do the initial handshake to make sure we are
63 * actually talking to a cpdup slave.
74 rc_badop(hctransaction_t trans __unused, struct HCHead *head)
76 head->error = EOPNOTSUPP;
81 hcc_slave(int fdin, int fdout, struct HCDesc *descs, int count)
83 struct HostConf hcslave;
86 struct HCTransaction trans;
87 int (*dispatch[256])(hctransaction_t, struct HCHead *);
92 bzero(&hcslave, sizeof(hcslave));
93 bzero(&trans, sizeof(trans));
94 for (i = 0; i < count; ++i) {
95 struct HCDesc *desc = &descs[i];
96 assert(desc->cmd >= 0 && desc->cmd < 256);
97 dispatch[desc->cmd] = desc->func;
99 for (i = 0; i < 256; ++i) {
100 if (dispatch[i] == NULL)
101 dispatch[i] = rc_badop;
104 hcslave.fdout = fdout;
108 * Process commands on fdin and write out results on fdout
114 head = hcc_read_command(&trans, 1);
119 * Start the reply and dispatch, then process the return code.
122 hcc_start_reply(&trans, head);
124 r = dispatch[head->cmd & 255](&trans, head);
128 head->error = EINVAL;
141 * Write out the reply
143 whead = (void *)trans.wbuf;
144 whead->bytes = trans.windex;
145 whead->error = head->error;
146 aligned_bytes = HCC_ALIGN(trans.windex);
148 hcc_debug_dump(whead);
150 if (write(hcslave.fdout, whead, aligned_bytes) != aligned_bytes)
157 * This reads a command from fdin, fixes up the byte ordering, and returns
158 * a pointer to HCHead.
160 * If id is -1 we do not match response id's
164 hcc_read_command(hctransaction_t trans, int anypkt)
166 struct HostConf *hc = trans->hc;
167 hctransaction_t fill;
175 * Shortcut if the reply has already been read in by another thread.
177 if (trans->state == HCT_REPLIED) {
178 return((void *)trans->rbuf);
180 pthread_mutex_unlock(&MasterMutex);
181 pthread_mutex_lock(&hc->read_mutex);
183 while (trans->state != HCT_REPLIED) {
185 while (n < (int)sizeof(struct HCHead)) {
186 r = read(hc->fdin, (char *)&tmp + n, sizeof(struct HCHead) - n);
192 assert(tmp.bytes >= (int)sizeof(tmp) && tmp.bytes < 65536);
193 assert(tmp.magic == HCMAGIC);
195 if (anypkt == 0 && tmp.id != trans->id && trans->hc->version > 0) {
197 for (fill = trans->hc->hct_hash[tmp.id & HCTHASH_MASK];
201 if (fill->state == HCT_SENT && fill->id == tmp.id)
208 "cpdup hlink protocol error with %s (%04x %04x)\n",
209 trans->hc->host, trans->id, tmp.id);
216 bcopy(&tmp, fill->rbuf, n);
217 aligned_bytes = HCC_ALIGN(tmp.bytes);
219 while (n < aligned_bytes) {
220 r = read(hc->fdin, fill->rbuf + n, aligned_bytes - n);
226 hcc_debug_dump(head);
228 fill->state = HCT_REPLIED;
230 trans->state = HCT_DONE;
232 pthread_mutex_unlock(&hc->read_mutex);
233 pthread_mutex_lock(&MasterMutex);
235 return((void *)trans->rbuf);
238 pthread_mutex_unlock(&hc->read_mutex);
239 pthread_mutex_lock(&MasterMutex);
248 hcc_get_trans(struct HostConf *hc)
250 hctransaction_t trans;
251 hctransaction_t scan;
252 pthread_t tid = pthread_self();
255 i = ((intptr_t)tid >> 7) & HCTHASH_MASK;
257 for (trans = hc->hct_hash[i]; trans; trans = trans->next) {
258 if (trans->tid == tid)
262 trans = malloc(sizeof(*trans));
263 bzero(trans, sizeof(*trans));
267 for (scan = hc->hct_hash[i]; scan; scan = scan->next) {
268 if (scan->id == trans->id) {
269 trans->id += HCTHASH_SIZE;
273 } while (scan != NULL);
275 trans->next = hc->hct_hash[i];
276 hc->hct_hash[i] = trans;
282 hcc_free_trans(struct HostConf *hc)
284 hctransaction_t trans;
285 hctransaction_t *transp;
286 pthread_t tid = pthread_self();
289 i = ((intptr_t)tid >> 7) & HCTHASH_MASK;
291 for (transp = &hc->hct_hash[i]; *transp; transp = &trans->next) {
293 if (trans->tid == tid) {
294 *transp = trans->next;
305 hcc_get_trans(struct HostConf *hc)
312 hcc_free_trans(struct HostConf *hc)
320 * Initialize for a new command
323 hcc_start_command(struct HostConf *hc, int16_t cmd)
325 struct HCHead *whead;
326 hctransaction_t trans;
328 trans = hcc_get_trans(hc);
330 whead = (void *)trans->wbuf;
331 whead->magic = HCMAGIC;
334 whead->id = trans->id;
337 trans->windex = sizeof(*whead);
339 trans->state = HCT_IDLE;
345 hcc_start_reply(hctransaction_t trans, struct HCHead *rhead)
347 struct HCHead *whead = (void *)trans->wbuf;
349 whead->magic = HCMAGIC;
351 whead->cmd = rhead->cmd | HCF_REPLY;
352 whead->id = rhead->id;
355 trans->windex = sizeof(*whead);
359 * Finish constructing a command, transmit it, and await the reply.
360 * Return the HCHead of the reply.
363 hcc_finish_command(hctransaction_t trans)
365 struct HCHead *whead;
366 struct HCHead *rhead;
370 whead = (void *)trans->wbuf;
371 whead->bytes = trans->windex;
372 aligned_bytes = HCC_ALIGN(trans->windex);
374 trans->state = HCT_SENT;
376 if (write(trans->hc->fdout, whead, aligned_bytes) != aligned_bytes) {
382 if (whead->cmd < 0x0010)
384 fprintf(stderr, "cpdup lost connection to %s\n", trans->hc->host);
391 * whead is invalid when we call hcc_read_command() because
392 * we may switch to another thread.
394 if ((rhead = hcc_read_command(trans, 0)) == NULL) {
402 fprintf(stderr, "cpdup lost connection to %s\n", trans->hc->host);
408 *__error = rhead->error;
410 errno = rhead->error;
417 hcc_leaf_string(hctransaction_t trans, int16_t leafid, const char *str)
420 int bytes = strlen(str) + 1;
422 item = (void *)(trans->wbuf + trans->windex);
423 assert(trans->windex + sizeof(*item) + bytes < 65536);
424 item->leafid = leafid;
426 item->bytes = sizeof(*item) + bytes;
427 bcopy(str, item + 1, bytes);
428 trans->windex = HCC_ALIGN(trans->windex + item->bytes);
432 hcc_leaf_data(hctransaction_t trans, int16_t leafid, const void *ptr, int bytes)
436 item = (void *)(trans->wbuf + trans->windex);
437 assert(trans->windex + sizeof(*item) + bytes < 65536);
438 item->leafid = leafid;
440 item->bytes = sizeof(*item) + bytes;
441 bcopy(ptr, item + 1, bytes);
442 trans->windex = HCC_ALIGN(trans->windex + item->bytes);
446 hcc_leaf_int32(hctransaction_t trans, int16_t leafid, int32_t value)
450 item = (void *)(trans->wbuf + trans->windex);
451 assert(trans->windex + sizeof(*item) + sizeof(value) < 65536);
452 item->leafid = leafid;
454 item->bytes = sizeof(*item) + sizeof(value);
455 *(int32_t *)(item + 1) = value;
456 trans->windex = HCC_ALIGN(trans->windex + item->bytes);
460 hcc_leaf_int64(hctransaction_t trans, int16_t leafid, int64_t value)
464 item = (void *)(trans->wbuf + trans->windex);
465 assert(trans->windex + sizeof(*item) + sizeof(value) < 65536);
466 item->leafid = leafid;
468 item->bytes = sizeof(*item) + sizeof(value);
469 *(int64_t *)(item + 1) = value;
470 trans->windex = HCC_ALIGN(trans->windex + item->bytes);
474 hcc_alloc_descriptor(struct HostConf *hc, void *ptr, int type)
476 struct HCHostDesc *hd;
477 struct HCHostDesc *hnew;
479 hnew = malloc(sizeof(struct HCHostDesc));
483 if ((hd = hc->hostdescs) != NULL) {
484 hnew->desc = hd->desc + 1;
489 hc->hostdescs = hnew;
494 hcc_get_descriptor(struct HostConf *hc, int desc, int type)
496 struct HCHostDesc *hd;
498 for (hd = hc->hostdescs; hd; hd = hd->next) {
499 if (hd->desc == desc && hd->type == type)
506 hcc_set_descriptor(struct HostConf *hc, int desc, void *ptr, int type)
508 struct HCHostDesc *hd;
509 struct HCHostDesc **hdp;
511 for (hdp = &hc->hostdescs; (hd = *hdp) != NULL; hdp = &hd->next) {
512 if (hd->desc == desc) {
524 hd = malloc(sizeof(*hd));
528 hd->next = hc->hostdescs;
534 hcc_firstitem(struct HCHead *head)
539 offset = sizeof(*head);
540 if (offset == head->bytes)
542 assert(head->bytes >= offset + (int)sizeof(*item));
543 item = (void *)(head + 1);
544 assert(head->bytes >= offset + item->bytes);
545 assert(item->bytes >= (int)sizeof(*item) && item->bytes < 65536 - offset);
550 hcc_nextitem(struct HCHead *head, struct HCLeaf *item)
554 item = (void *)((char *)item + HCC_ALIGN(item->bytes));
555 offset = (char *)item - (char *)head;
556 if (offset == head->bytes)
558 assert(head->bytes >= offset + (int)sizeof(*item));
559 assert(head->bytes >= offset + item->bytes);
560 assert(item->bytes >= (int)sizeof(*item) && item->bytes < 65536 - offset);
567 hcc_debug_dump(struct HCHead *head)
570 int aligned_bytes = HCC_ALIGN(head->bytes);
572 fprintf(stderr, "DUMP %04x (%d)", (u_int16_t)head->cmd, aligned_bytes);
573 if (head->cmd & HCF_REPLY)
574 fprintf(stderr, " error %d", head->error);
575 fprintf(stderr, "\n");
576 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
577 fprintf(stderr, " ITEM %04x DATA ", item->leafid);
578 switch(item->leafid & LCF_TYPEMASK) {
580 fprintf(stderr, "int32 %d\n", *(int32_t *)(item + 1));
583 fprintf(stderr, "int64 %lld\n", *(int64_t *)(item + 1));
586 fprintf(stderr, "\"%s\"\n", (char *)(item + 1));
589 fprintf(stderr, "(binary)\n");