installer: ../Makefile.inc is included via bsd.init.mk, no need to repeat.
[dragonfly.git] / bin / cpdup / hclink.c
blobd8868116150fd3473fa46581d015991effb1d35b
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 #if USE_PTHREADS
14 static void * hcc_reader_thread(void *arg);
15 #endif
16 static struct HCHead *hcc_read_command(struct HostConf *hc, hctransaction_t trans);
17 static void hcc_start_reply(hctransaction_t trans, struct HCHead *rhead);
19 int
20 hcc_connect(struct HostConf *hc)
22 int fdin[2];
23 int fdout[2];
24 const char *av[16];
26 if (hc == NULL || hc->host == NULL)
27 return(0);
29 if (pipe(fdin) < 0)
30 return(-1);
31 if (pipe(fdout) < 0) {
32 close(fdin[0]);
33 close(fdin[1]);
34 return(-1);
36 if ((hc->pid = fork()) == 0) {
38 * Child process
40 int n;
42 dup2(fdin[1], 1);
43 close(fdin[0]);
44 close(fdin[1]);
45 dup2(fdout[0], 0);
46 close(fdout[0]);
47 close(fdout[1]);
49 n = 0;
50 av[n++] = "ssh";
51 if (CompressOpt)
52 av[n++] = "-C";
53 av[n++] = "-T";
54 av[n++] = hc->host;
55 av[n++] = "cpdup";
56 av[n++] = "-S";
57 av[n++] = NULL;
59 execv("/usr/bin/ssh", (void *)av);
60 _exit(1);
61 } else if (hc->pid < 0) {
62 return(-1);
63 } else {
65 * Parent process. Do the initial handshake to make sure we are
66 * actually talking to a cpdup slave.
68 close(fdin[1]);
69 hc->fdin = fdin[0];
70 close(fdout[0]);
71 hc->fdout = fdout[1];
72 #if USE_PTHREADS
73 pthread_create(&hc->reader_thread, NULL, hcc_reader_thread, hc);
74 #endif
75 return(0);
79 static int
80 rc_badop(hctransaction_t trans __unused, struct HCHead *head)
82 head->error = EOPNOTSUPP;
83 return(0);
86 int
87 hcc_slave(int fdin, int fdout, struct HCDesc *descs, int count)
89 struct HostConf hcslave;
90 struct HCHead *head;
91 struct HCHead *whead;
92 struct HCTransaction trans;
93 int (*dispatch[256])(hctransaction_t, struct HCHead *);
94 int aligned_bytes;
95 int i;
96 int r;
98 bzero(&hcslave, sizeof(hcslave));
99 bzero(&trans, sizeof(trans));
100 for (i = 0; i < count; ++i) {
101 struct HCDesc *desc = &descs[i];
102 assert(desc->cmd >= 0 && desc->cmd < 256);
103 dispatch[desc->cmd] = desc->func;
105 for (i = 0; i < 256; ++i) {
106 if (dispatch[i] == NULL)
107 dispatch[i] = rc_badop;
109 hcslave.fdin = fdin;
110 hcslave.fdout = fdout;
111 trans.hc = &hcslave;
113 #if USE_PTHREADS
114 pthread_mutex_unlock(&MasterMutex);
115 #endif
117 * Process commands on fdin and write out results on fdout
119 for (;;) {
121 * Get the command
123 head = hcc_read_command(trans.hc, &trans);
124 if (head == NULL)
125 break;
128 * Start the reply and dispatch, then process the return code.
130 head->error = 0;
131 hcc_start_reply(&trans, head);
133 r = dispatch[head->cmd & 255](&trans, head);
135 switch(r) {
136 case -2:
137 head->error = EINVAL;
138 break;
139 case -1:
140 head->error = errno;
141 break;
142 case 0:
143 break;
144 default:
145 assert(0);
146 break;
150 * Write out the reply
152 whead = (void *)trans.wbuf;
153 whead->bytes = trans.windex;
154 whead->error = head->error;
155 aligned_bytes = HCC_ALIGN(trans.windex);
156 #ifdef DEBUG
157 hcc_debug_dump(whead);
158 #endif
159 if (write(hcslave.fdout, whead, aligned_bytes) != aligned_bytes)
160 break;
162 return(0);
165 #if USE_PTHREADS
167 * This thread collects responses from the link. It is run without
168 * the MasterMutex.
170 static void *
171 hcc_reader_thread(void *arg)
173 struct HostConf *hc = arg;
174 struct HCHead *rhead;
175 hctransaction_t scan;
176 int i;
178 pthread_detach(pthread_self());
179 while (hcc_read_command(hc, NULL) != NULL)
181 hc->reader_thread = NULL;
184 * Clean up any threads stuck waiting for a reply.
186 pthread_mutex_lock(&MasterMutex);
187 for (i = 0; i < HCTHASH_SIZE; ++i) {
188 pthread_mutex_lock(&hc->hct_mutex[i]);
189 for (scan = hc->hct_hash[i]; scan; scan = scan->next) {
190 if (scan->state == HCT_SENT) {
191 scan->state = HCT_REPLIED;
192 rhead = (void *)scan->rbuf;
193 rhead->error = ENOTCONN;
194 if (scan->waiting)
195 pthread_cond_signal(&scan->cond);
198 pthread_mutex_unlock(&hc->hct_mutex[i]);
200 pthread_mutex_unlock(&MasterMutex);
201 return(NULL);
204 #endif
207 * This reads a command from fdin, fixes up the byte ordering, and returns
208 * a pointer to HCHead.
210 * The MasterMutex may or may not be held. When threaded this command
211 * is serialized by a reader thread.
213 static
214 struct HCHead *
215 hcc_read_command(struct HostConf *hc, hctransaction_t trans)
217 hctransaction_t fill;
218 struct HCHead tmp;
219 int aligned_bytes;
220 int n;
221 int r;
223 n = 0;
224 while (n < (int)sizeof(struct HCHead)) {
225 r = read(hc->fdin, (char *)&tmp + n, sizeof(struct HCHead) - n);
226 if (r <= 0)
227 goto fail;
228 n += r;
231 assert(tmp.bytes >= (int)sizeof(tmp) && tmp.bytes < 65536);
232 assert(tmp.magic == HCMAGIC);
234 if (trans) {
235 fill = trans;
236 } else {
237 #if USE_PTHREADS
238 pthread_mutex_lock(&hc->hct_mutex[tmp.id & HCTHASH_MASK]);
239 for (fill = hc->hct_hash[tmp.id & HCTHASH_MASK];
240 fill;
241 fill = fill->next)
243 if (fill->state == HCT_SENT && fill->id == tmp.id)
244 break;
246 pthread_mutex_unlock(&hc->hct_mutex[tmp.id & HCTHASH_MASK]);
247 if (fill == NULL)
248 #endif
250 fprintf(stderr,
251 "cpdup hlink protocol error with %s (%04x %04x)\n",
252 hc->host, trans->id, tmp.id);
253 exit(1);
257 bcopy(&tmp, fill->rbuf, n);
258 aligned_bytes = HCC_ALIGN(tmp.bytes);
260 while (n < aligned_bytes) {
261 r = read(hc->fdin, fill->rbuf + n, aligned_bytes - n);
262 if (r <= 0)
263 goto fail;
264 n += r;
266 #ifdef DEBUG
267 hcc_debug_dump(head);
268 #endif
269 #if USE_PTHREADS
270 pthread_mutex_lock(&hc->hct_mutex[fill->id & HCTHASH_MASK]);
271 #endif
272 fill->state = HCT_REPLIED;
273 #if USE_PTHREADS
274 if (fill->waiting)
275 pthread_cond_signal(&fill->cond);
276 pthread_mutex_unlock(&hc->hct_mutex[fill->id & HCTHASH_MASK]);
277 #endif
278 return((void *)fill->rbuf);
279 fail:
280 return(NULL);
283 #if USE_PTHREADS
285 static
286 hctransaction_t
287 hcc_get_trans(struct HostConf *hc)
289 hctransaction_t trans;
290 hctransaction_t scan;
291 pthread_t tid = pthread_self();
292 int i;
294 i = ((intptr_t)tid >> 7) & HCTHASH_MASK;
296 pthread_mutex_lock(&hc->hct_mutex[i]);
297 for (trans = hc->hct_hash[i]; trans; trans = trans->next) {
298 if (trans->tid == tid)
299 break;
301 if (trans == NULL) {
302 trans = malloc(sizeof(*trans));
303 bzero(trans, sizeof(*trans));
304 trans->tid = tid;
305 trans->id = i;
306 pthread_cond_init(&trans->cond, NULL);
307 do {
308 for (scan = hc->hct_hash[i]; scan; scan = scan->next) {
309 if (scan->id == trans->id) {
310 trans->id += HCTHASH_SIZE;
311 break;
314 } while (scan != NULL);
316 trans->next = hc->hct_hash[i];
317 hc->hct_hash[i] = trans;
319 pthread_mutex_unlock(&hc->hct_mutex[i]);
320 return(trans);
323 void
324 hcc_free_trans(struct HostConf *hc)
326 hctransaction_t trans;
327 hctransaction_t *transp;
328 pthread_t tid = pthread_self();
329 int i;
331 i = ((intptr_t)tid >> 7) & HCTHASH_MASK;
333 pthread_mutex_lock(&hc->hct_mutex[i]);
334 for (transp = &hc->hct_hash[i]; *transp; transp = &trans->next) {
335 trans = *transp;
336 if (trans->tid == tid) {
337 *transp = trans->next;
338 pthread_cond_destroy(&trans->cond);
339 free(trans);
340 break;
343 pthread_mutex_unlock(&hc->hct_mutex[i]);
346 #else
348 static
349 hctransaction_t
350 hcc_get_trans(struct HostConf *hc)
352 return(&hc->trans);
355 void
356 hcc_free_trans(struct HostConf *hc __unused)
358 /* nop */
361 #endif
364 * Initialize for a new command
366 hctransaction_t
367 hcc_start_command(struct HostConf *hc, int16_t cmd)
369 struct HCHead *whead;
370 hctransaction_t trans;
372 trans = hcc_get_trans(hc);
374 whead = (void *)trans->wbuf;
375 whead->magic = HCMAGIC;
376 whead->bytes = 0;
377 whead->cmd = cmd;
378 whead->id = trans->id;
379 whead->error = 0;
381 trans->windex = sizeof(*whead);
382 trans->hc = hc;
383 trans->state = HCT_IDLE;
385 return(trans);
388 static void
389 hcc_start_reply(hctransaction_t trans, struct HCHead *rhead)
391 struct HCHead *whead = (void *)trans->wbuf;
393 whead->magic = HCMAGIC;
394 whead->bytes = 0;
395 whead->cmd = rhead->cmd | HCF_REPLY;
396 whead->id = rhead->id;
397 whead->error = 0;
399 trans->windex = sizeof(*whead);
403 * Finish constructing a command, transmit it, and await the reply.
404 * Return the HCHead of the reply.
406 struct HCHead *
407 hcc_finish_command(hctransaction_t trans)
409 struct HostConf *hc;
410 struct HCHead *whead;
411 struct HCHead *rhead;
412 int aligned_bytes;
413 int16_t wcmd;
415 hc = trans->hc;
416 whead = (void *)trans->wbuf;
417 whead->bytes = trans->windex;
418 aligned_bytes = HCC_ALIGN(trans->windex);
420 trans->state = HCT_SENT;
422 if (write(hc->fdout, whead, aligned_bytes) != aligned_bytes) {
423 #ifdef __error
424 *__error = EIO;
425 #else
426 errno = EIO;
427 #endif
428 if (whead->cmd < 0x0010)
429 return(NULL);
430 fprintf(stderr, "cpdup lost connection to %s\n", hc->host);
431 exit(1);
434 wcmd = whead->cmd;
437 * whead is invalid when we call hcc_read_command() because
438 * we may switch to another thread.
440 #if USE_PTHREADS
441 pthread_mutex_unlock(&MasterMutex);
442 while (trans->state != HCT_REPLIED && hc->reader_thread) {
443 pthread_mutex_t *mtxp = &hc->hct_mutex[trans->id & HCTHASH_MASK];
444 pthread_mutex_lock(mtxp);
445 trans->waiting = 1;
446 if (trans->state != HCT_REPLIED && hc->reader_thread)
447 pthread_cond_wait(&trans->cond, mtxp);
448 trans->waiting = 0;
449 pthread_mutex_unlock(mtxp);
451 pthread_mutex_lock(&MasterMutex);
452 rhead = (void *)trans->rbuf;
453 #else
454 rhead = hcc_read_command(hc, trans);
455 #endif
456 if (trans->state != HCT_REPLIED || rhead->id != trans->id) {
457 #ifdef __error
458 *__error = EIO;
459 #else
460 errno = EIO;
461 #endif
462 if (wcmd < 0x0010)
463 return(NULL);
464 fprintf(stderr, "cpdup lost connection to %s\n", hc->host);
465 exit(1);
467 trans->state = HCT_DONE;
469 if (rhead->error) {
470 #ifdef __error
471 *__error = rhead->error;
472 #else
473 errno = rhead->error;
474 #endif
476 return (rhead);
479 void
480 hcc_leaf_string(hctransaction_t trans, int16_t leafid, const char *str)
482 struct HCLeaf *item;
483 int bytes = strlen(str) + 1;
485 item = (void *)(trans->wbuf + trans->windex);
486 assert(trans->windex + sizeof(*item) + bytes < 65536);
487 item->leafid = leafid;
488 item->reserved = 0;
489 item->bytes = sizeof(*item) + bytes;
490 bcopy(str, item + 1, bytes);
491 trans->windex = HCC_ALIGN(trans->windex + item->bytes);
494 void
495 hcc_leaf_data(hctransaction_t trans, int16_t leafid, const void *ptr, int bytes)
497 struct HCLeaf *item;
499 item = (void *)(trans->wbuf + trans->windex);
500 assert(trans->windex + sizeof(*item) + bytes < 65536);
501 item->leafid = leafid;
502 item->reserved = 0;
503 item->bytes = sizeof(*item) + bytes;
504 bcopy(ptr, item + 1, bytes);
505 trans->windex = HCC_ALIGN(trans->windex + item->bytes);
508 void
509 hcc_leaf_int32(hctransaction_t trans, int16_t leafid, int32_t value)
511 struct HCLeaf *item;
513 item = (void *)(trans->wbuf + trans->windex);
514 assert(trans->windex + sizeof(*item) + sizeof(value) < 65536);
515 item->leafid = leafid;
516 item->reserved = 0;
517 item->bytes = sizeof(*item) + sizeof(value);
518 *(int32_t *)(item + 1) = value;
519 trans->windex = HCC_ALIGN(trans->windex + item->bytes);
522 void
523 hcc_leaf_int64(hctransaction_t trans, int16_t leafid, int64_t value)
525 struct HCLeaf *item;
527 item = (void *)(trans->wbuf + trans->windex);
528 assert(trans->windex + sizeof(*item) + sizeof(value) < 65536);
529 item->leafid = leafid;
530 item->reserved = 0;
531 item->bytes = sizeof(*item) + sizeof(value);
532 *(int64_t *)(item + 1) = value;
533 trans->windex = HCC_ALIGN(trans->windex + item->bytes);
537 hcc_alloc_descriptor(struct HostConf *hc, void *ptr, int type)
539 struct HCHostDesc *hd;
540 struct HCHostDesc *hnew;
542 hnew = malloc(sizeof(struct HCHostDesc));
543 hnew->type = type;
544 hnew->data = ptr;
546 if ((hd = hc->hostdescs) != NULL) {
547 hnew->desc = hd->desc + 1;
548 } else {
549 hnew->desc = 1;
551 hnew->next = hd;
552 hc->hostdescs = hnew;
553 return(hnew->desc);
556 void *
557 hcc_get_descriptor(struct HostConf *hc, int desc, int type)
559 struct HCHostDesc *hd;
561 for (hd = hc->hostdescs; hd; hd = hd->next) {
562 if (hd->desc == desc && hd->type == type)
563 return(hd->data);
565 return(NULL);
568 void
569 hcc_set_descriptor(struct HostConf *hc, int desc, void *ptr, int type)
571 struct HCHostDesc *hd;
572 struct HCHostDesc **hdp;
574 for (hdp = &hc->hostdescs; (hd = *hdp) != NULL; hdp = &hd->next) {
575 if (hd->desc == desc) {
576 if (ptr) {
577 hd->data = ptr;
578 hd->type = type;
579 } else {
580 *hdp = hd->next;
581 free(hd);
583 return;
586 if (ptr) {
587 hd = malloc(sizeof(*hd));
588 hd->desc = desc;
589 hd->type = type;
590 hd->data = ptr;
591 hd->next = hc->hostdescs;
592 hc->hostdescs = hd;
596 struct HCLeaf *
597 hcc_firstitem(struct HCHead *head)
599 struct HCLeaf *item;
600 int offset;
602 offset = sizeof(*head);
603 if (offset == head->bytes)
604 return(NULL);
605 assert(head->bytes >= offset + (int)sizeof(*item));
606 item = (void *)(head + 1);
607 assert(head->bytes >= offset + item->bytes);
608 assert(item->bytes >= (int)sizeof(*item) && item->bytes < 65536 - offset);
609 return (item);
612 struct HCLeaf *
613 hcc_nextitem(struct HCHead *head, struct HCLeaf *item)
615 int offset;
617 item = (void *)((char *)item + HCC_ALIGN(item->bytes));
618 offset = (char *)item - (char *)head;
619 if (offset == head->bytes)
620 return(NULL);
621 assert(head->bytes >= offset + (int)sizeof(*item));
622 assert(head->bytes >= offset + item->bytes);
623 assert(item->bytes >= (int)sizeof(*item) && item->bytes < 65536 - offset);
624 return (item);
627 #ifdef DEBUG
629 void
630 hcc_debug_dump(struct HCHead *head)
632 struct HCLeaf *item;
633 int aligned_bytes = HCC_ALIGN(head->bytes);
635 fprintf(stderr, "DUMP %04x (%d)", (u_int16_t)head->cmd, aligned_bytes);
636 if (head->cmd & HCF_REPLY)
637 fprintf(stderr, " error %d", head->error);
638 fprintf(stderr, "\n");
639 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
640 fprintf(stderr, " ITEM %04x DATA ", item->leafid);
641 switch(item->leafid & LCF_TYPEMASK) {
642 case LCF_INT32:
643 fprintf(stderr, "int32 %d\n", *(int32_t *)(item + 1));
644 break;
645 case LCF_INT64:
646 fprintf(stderr, "int64 %lld\n", *(int64_t *)(item + 1));
647 break;
648 case LCF_STRING:
649 fprintf(stderr, "\"%s\"\n", (char *)(item + 1));
650 break;
651 case LCF_BINARY:
652 fprintf(stderr, "(binary)\n");
653 break;
654 default:
655 printf("?\n");
660 #endif