4 * This module implements a simple remote control protocol
6 * $DragonFly: src/bin/cpdup/hclink.c,v 1.5 2008/04/10 22:09:08 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)
22 if (hc == NULL || hc->host == NULL)
27 if (pipe(fdout) < 0) {
32 if ((hc->pid = fork()) == 0) {
42 execl("/usr/bin/ssh", "ssh", "-T", hc->host, "cpdup", "-S", (char *) NULL);
44 } else if (hc->pid < 0) {
48 * Parent process. Do the initial handshake to make sure we are
49 * actually talking to a cpdup slave.
60 rc_badop(hctransaction_t trans __unused, struct HCHead *head)
62 head->error = EOPNOTSUPP;
67 hcc_slave(int fdin, int fdout, struct HCDesc *descs, int count)
69 struct HostConf hcslave;
72 struct HCTransaction trans;
73 int (*dispatch[256])(hctransaction_t, struct HCHead *);
78 bzero(&hcslave, sizeof(hcslave));
79 bzero(&trans, sizeof(trans));
80 for (i = 0; i < count; ++i) {
81 struct HCDesc *desc = &descs[i];
82 assert(desc->cmd >= 0 && desc->cmd < 256);
83 dispatch[desc->cmd] = desc->func;
85 for (i = 0; i < 256; ++i) {
86 if (dispatch[i] == NULL)
87 dispatch[i] = rc_badop;
90 hcslave.fdout = fdout;
94 * Process commands on fdin and write out results on fdout
100 head = hcc_read_command(&trans, 1);
105 * Start the reply and dispatch, then process the return code.
108 hcc_start_reply(&trans, head);
110 r = dispatch[head->cmd & 255](&trans, head);
114 head->error = EINVAL;
127 * Write out the reply
129 whead = (void *)trans.wbuf;
130 whead->bytes = trans.windex;
131 whead->error = head->error;
132 aligned_bytes = HCC_ALIGN(trans.windex);
134 hcc_debug_dump(whead);
136 if (write(hcslave.fdout, whead, aligned_bytes) != aligned_bytes)
143 * This reads a command from fdin, fixes up the byte ordering, and returns
144 * a pointer to HCHead.
146 * If id is -1 we do not match response id's
150 hcc_read_command(hctransaction_t trans, int anypkt)
152 struct HostConf *hc = trans->hc;
153 hctransaction_t fill;
161 * Shortcut if the reply has already been read in by another thread.
163 if (trans->state == HCT_REPLIED) {
164 return((void *)trans->rbuf);
166 pthread_mutex_unlock(&MasterMutex);
167 pthread_mutex_lock(&hc->read_mutex);
169 while (trans->state != HCT_REPLIED) {
171 while (n < (int)sizeof(struct HCHead)) {
172 r = read(hc->fdin, (char *)&tmp + n, sizeof(struct HCHead) - n);
178 assert(tmp.bytes >= (int)sizeof(tmp) && tmp.bytes < 65536);
179 assert(tmp.magic == HCMAGIC);
181 if (anypkt == 0 && tmp.id != trans->id && trans->hc->version > 0) {
183 for (fill = trans->hc->hct_hash[tmp.id & HCTHASH_MASK];
187 if (fill->state == HCT_SENT && fill->id == tmp.id)
194 "cpdup hlink protocol error with %s (%04x %04x)\n",
195 trans->hc->host, trans->id, tmp.id);
202 bcopy(&tmp, fill->rbuf, n);
203 aligned_bytes = HCC_ALIGN(tmp.bytes);
205 while (n < aligned_bytes) {
206 r = read(hc->fdin, fill->rbuf + n, aligned_bytes - n);
212 hcc_debug_dump(head);
214 fill->state = HCT_REPLIED;
217 pthread_mutex_lock(&MasterMutex);
218 pthread_mutex_unlock(&hc->read_mutex);
220 return((void *)trans->rbuf);
223 pthread_mutex_lock(&MasterMutex);
224 pthread_mutex_unlock(&hc->read_mutex);
233 hcc_get_trans(struct HostConf *hc)
235 hctransaction_t trans;
236 hctransaction_t scan;
237 pthread_t tid = pthread_self();
240 i = ((intptr_t)tid >> 7) & HCTHASH_MASK;
242 for (trans = hc->hct_hash[i]; trans; trans = trans->next) {
243 if (trans->tid == tid)
247 trans = malloc(sizeof(*trans));
248 bzero(trans, sizeof(*trans));
252 for (scan = hc->hct_hash[i]; scan; scan = scan->next) {
253 if (scan->id == trans->id) {
254 trans->id += HCTHASH_SIZE;
258 } while (scan != NULL);
260 trans->next = hc->hct_hash[i];
261 hc->hct_hash[i] = trans;
270 hcc_get_trans(struct HostConf *hc)
278 * Initialize for a new command
281 hcc_start_command(struct HostConf *hc, int16_t cmd)
283 struct HCHead *whead;
284 hctransaction_t trans;
286 trans = hcc_get_trans(hc);
288 whead = (void *)trans->wbuf;
289 whead->magic = HCMAGIC;
292 whead->id = trans->id;
295 trans->windex = sizeof(*whead);
297 trans->state = HCT_IDLE;
303 hcc_start_reply(hctransaction_t trans, struct HCHead *rhead)
305 struct HCHead *whead = (void *)trans->wbuf;
307 whead->magic = HCMAGIC;
309 whead->cmd = rhead->cmd | HCF_REPLY;
310 whead->id = rhead->id;
313 trans->windex = sizeof(*whead);
317 * Finish constructing a command, transmit it, and await the reply.
318 * Return the HCHead of the reply.
321 hcc_finish_command(hctransaction_t trans)
323 struct HCHead *whead;
324 struct HCHead *rhead;
328 whead = (void *)trans->wbuf;
329 whead->bytes = trans->windex;
330 aligned_bytes = HCC_ALIGN(trans->windex);
332 trans->state = HCT_SENT;
334 if (write(trans->hc->fdout, whead, aligned_bytes) != aligned_bytes) {
340 if (whead->cmd < 0x0010)
342 fprintf(stderr, "cpdup lost connection to %s\n", trans->hc->host);
349 * whead is invalid when we call hcc_read_command() because
350 * we may switch to another thread.
352 if ((rhead = hcc_read_command(trans, 0)) == NULL) {
360 fprintf(stderr, "cpdup lost connection to %s\n", trans->hc->host);
366 *__error = rhead->error;
368 errno = rhead->error;
375 hcc_leaf_string(hctransaction_t trans, int16_t leafid, const char *str)
378 int bytes = strlen(str) + 1;
380 item = (void *)(trans->wbuf + trans->windex);
381 assert(trans->windex + sizeof(*item) + bytes < 65536);
382 item->leafid = leafid;
384 item->bytes = sizeof(*item) + bytes;
385 bcopy(str, item + 1, bytes);
386 trans->windex = HCC_ALIGN(trans->windex + item->bytes);
390 hcc_leaf_data(hctransaction_t trans, int16_t leafid, const void *ptr, int bytes)
394 item = (void *)(trans->wbuf + trans->windex);
395 assert(trans->windex + sizeof(*item) + bytes < 65536);
396 item->leafid = leafid;
398 item->bytes = sizeof(*item) + bytes;
399 bcopy(ptr, item + 1, bytes);
400 trans->windex = HCC_ALIGN(trans->windex + item->bytes);
404 hcc_leaf_int32(hctransaction_t trans, int16_t leafid, int32_t value)
408 item = (void *)(trans->wbuf + trans->windex);
409 assert(trans->windex + sizeof(*item) + sizeof(value) < 65536);
410 item->leafid = leafid;
412 item->bytes = sizeof(*item) + sizeof(value);
413 *(int32_t *)(item + 1) = value;
414 trans->windex = HCC_ALIGN(trans->windex + item->bytes);
418 hcc_leaf_int64(hctransaction_t trans, int16_t leafid, int64_t value)
422 item = (void *)(trans->wbuf + trans->windex);
423 assert(trans->windex + sizeof(*item) + sizeof(value) < 65536);
424 item->leafid = leafid;
426 item->bytes = sizeof(*item) + sizeof(value);
427 *(int64_t *)(item + 1) = value;
428 trans->windex = HCC_ALIGN(trans->windex + item->bytes);
432 hcc_alloc_descriptor(struct HostConf *hc, void *ptr, int type)
434 struct HCHostDesc *hd;
435 struct HCHostDesc *hnew;
437 hnew = malloc(sizeof(struct HCHostDesc));
441 if ((hd = hc->hostdescs) != NULL) {
442 hnew->desc = hd->desc + 1;
447 hc->hostdescs = hnew;
452 hcc_get_descriptor(struct HostConf *hc, int desc, int type)
454 struct HCHostDesc *hd;
456 for (hd = hc->hostdescs; hd; hd = hd->next) {
457 if (hd->desc == desc && hd->type == type)
464 hcc_set_descriptor(struct HostConf *hc, int desc, void *ptr, int type)
466 struct HCHostDesc *hd;
467 struct HCHostDesc **hdp;
469 for (hdp = &hc->hostdescs; (hd = *hdp) != NULL; hdp = &hd->next) {
470 if (hd->desc == desc) {
482 hd = malloc(sizeof(*hd));
486 hd->next = hc->hostdescs;
492 hcc_firstitem(struct HCHead *head)
497 offset = sizeof(*head);
498 if (offset == head->bytes)
500 assert(head->bytes >= offset + (int)sizeof(*item));
501 item = (void *)(head + 1);
502 assert(head->bytes >= offset + item->bytes);
503 assert(item->bytes >= (int)sizeof(*item) && item->bytes < 65536 - offset);
508 hcc_nextitem(struct HCHead *head, struct HCLeaf *item)
512 item = (void *)((char *)item + HCC_ALIGN(item->bytes));
513 offset = (char *)item - (char *)head;
514 if (offset == head->bytes)
516 assert(head->bytes >= offset + (int)sizeof(*item));
517 assert(head->bytes >= offset + item->bytes);
518 assert(item->bytes >= (int)sizeof(*item) && item->bytes < 65536 - offset);
525 hcc_debug_dump(struct HCHead *head)
528 int aligned_bytes = HCC_ALIGN(head->bytes);
530 fprintf(stderr, "DUMP %04x (%d)", (u_int16_t)head->cmd, aligned_bytes);
531 if (head->cmd & HCF_REPLY)
532 fprintf(stderr, " error %d", head->error);
533 fprintf(stderr, "\n");
534 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
535 fprintf(stderr, " ITEM %04x DATA ", item->leafid);
536 switch(item->leafid & LCF_TYPEMASK) {
538 fprintf(stderr, "int32 %d\n", *(int32_t *)(item + 1));
541 fprintf(stderr, "int64 %lld\n", *(int64_t *)(item + 1));
544 fprintf(stderr, "\"%s\"\n", (char *)(item + 1));
547 fprintf(stderr, "(binary)\n");