Correct comments and minor variable naming and sysctl issues.
[dragonfly.git] / bin / cpdup / hclink.c
blob82ac944aff5c0066a4e56d16a39f154c6fb2be14
1 /*
2 * HCLINK.C
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 $
7 */
9 #include "cpdup.h"
10 #include "hclink.h"
11 #include "hcproto.h"
13 static struct HCHead *hcc_read_command(hctransaction_t trans, int anypkt);
14 static void hcc_start_reply(hctransaction_t trans, struct HCHead *rhead);
16 int
17 hcc_connect(struct HostConf *hc)
19 int fdin[2];
20 int fdout[2];
21 const char *av[16];
23 if (hc == NULL || hc->host == NULL)
24 return(0);
26 if (pipe(fdin) < 0)
27 return(-1);
28 if (pipe(fdout) < 0) {
29 close(fdin[0]);
30 close(fdin[1]);
31 return(-1);
33 if ((hc->pid = fork()) == 0) {
35 * Child process
37 int n;
39 dup2(fdin[1], 1);
40 close(fdin[0]);
41 close(fdin[1]);
42 dup2(fdout[0], 0);
43 close(fdout[0]);
44 close(fdout[1]);
46 n = 0;
47 av[n++] = "ssh";
48 if (CompressOpt)
49 av[n++] = "-C";
50 av[n++] = "-T";
51 av[n++] = hc->host;
52 av[n++] = "cpdup";
53 av[n++] = "-S";
54 av[n++] = NULL;
56 execv("/usr/bin/ssh", (void *)av);
57 _exit(1);
58 } else if (hc->pid < 0) {
59 return(-1);
60 } else {
62 * Parent process. Do the initial handshake to make sure we are
63 * actually talking to a cpdup slave.
65 close(fdin[1]);
66 hc->fdin = fdin[0];
67 close(fdout[0]);
68 hc->fdout = fdout[1];
69 return(0);
73 static int
74 rc_badop(hctransaction_t trans __unused, struct HCHead *head)
76 head->error = EOPNOTSUPP;
77 return(0);
80 int
81 hcc_slave(int fdin, int fdout, struct HCDesc *descs, int count)
83 struct HostConf hcslave;
84 struct HCHead *head;
85 struct HCHead *whead;
86 struct HCTransaction trans;
87 int (*dispatch[256])(hctransaction_t, struct HCHead *);
88 int aligned_bytes;
89 int i;
90 int r;
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;
103 hcslave.fdin = fdin;
104 hcslave.fdout = fdout;
105 trans.hc = &hcslave;
108 * Process commands on fdin and write out results on fdout
110 for (;;) {
112 * Get the command
114 head = hcc_read_command(&trans, 1);
115 if (head == NULL)
116 break;
119 * Start the reply and dispatch, then process the return code.
121 head->error = 0;
122 hcc_start_reply(&trans, head);
124 r = dispatch[head->cmd & 255](&trans, head);
126 switch(r) {
127 case -2:
128 head->error = EINVAL;
129 break;
130 case -1:
131 head->error = errno;
132 break;
133 case 0:
134 break;
135 default:
136 assert(0);
137 break;
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);
147 #ifdef DEBUG
148 hcc_debug_dump(whead);
149 #endif
150 if (write(hcslave.fdout, whead, aligned_bytes) != aligned_bytes)
151 break;
153 return(0);
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
162 static
163 struct HCHead *
164 hcc_read_command(hctransaction_t trans, int anypkt)
166 struct HostConf *hc = trans->hc;
167 hctransaction_t fill;
168 struct HCHead tmp;
169 int aligned_bytes;
170 int n;
171 int r;
173 #if USE_PTHREADS
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);
182 #endif
183 while (trans->state != HCT_REPLIED) {
184 n = 0;
185 while (n < (int)sizeof(struct HCHead)) {
186 r = read(hc->fdin, (char *)&tmp + n, sizeof(struct HCHead) - n);
187 if (r <= 0)
188 goto fail;
189 n += r;
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) {
196 #if USE_PTHREADS
197 for (fill = trans->hc->hct_hash[tmp.id & HCTHASH_MASK];
198 fill;
199 fill = fill->next)
201 if (fill->state == HCT_SENT && fill->id == tmp.id)
202 break;
204 if (fill == NULL)
205 #endif
207 fprintf(stderr,
208 "cpdup hlink protocol error with %s (%04x %04x)\n",
209 trans->hc->host, trans->id, tmp.id);
210 exit(1);
212 } else {
213 fill = trans;
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);
221 if (r <= 0)
222 goto fail;
223 n += r;
225 #ifdef DEBUG
226 hcc_debug_dump(head);
227 #endif
228 fill->state = HCT_REPLIED;
230 trans->state = HCT_DONE;
231 #if USE_PTHREADS
232 pthread_mutex_unlock(&hc->read_mutex);
233 pthread_mutex_lock(&MasterMutex);
234 #endif
235 return((void *)trans->rbuf);
236 fail:
237 #if USE_PTHREADS
238 pthread_mutex_unlock(&hc->read_mutex);
239 pthread_mutex_lock(&MasterMutex);
240 #endif
241 return(NULL);
244 #if USE_PTHREADS
246 static
247 hctransaction_t
248 hcc_get_trans(struct HostConf *hc)
250 hctransaction_t trans;
251 hctransaction_t scan;
252 pthread_t tid = pthread_self();
253 int i;
255 i = ((intptr_t)tid >> 7) & HCTHASH_MASK;
257 for (trans = hc->hct_hash[i]; trans; trans = trans->next) {
258 if (trans->tid == tid)
259 break;
261 if (trans == NULL) {
262 trans = malloc(sizeof(*trans));
263 bzero(trans, sizeof(*trans));
264 trans->tid = tid;
265 trans->id = i;
266 do {
267 for (scan = hc->hct_hash[i]; scan; scan = scan->next) {
268 if (scan->id == trans->id) {
269 trans->id += HCTHASH_SIZE;
270 break;
273 } while (scan != NULL);
275 trans->next = hc->hct_hash[i];
276 hc->hct_hash[i] = trans;
278 return(trans);
281 void
282 hcc_free_trans(struct HostConf *hc)
284 hctransaction_t trans;
285 hctransaction_t *transp;
286 pthread_t tid = pthread_self();
287 int i;
289 i = ((intptr_t)tid >> 7) & HCTHASH_MASK;
291 for (transp = &hc->hct_hash[i]; *transp; transp = &trans->next) {
292 trans = *transp;
293 if (trans->tid == tid) {
294 *transp = trans->next;
295 free(trans);
296 break;
301 #else
303 static
304 hctransaction_t
305 hcc_get_trans(struct HostConf *hc)
307 return(&hc->trans);
310 static
311 void
312 hcc_free_trans(struct HostConf *hc)
314 /* nop */
317 #endif
320 * Initialize for a new command
322 hctransaction_t
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;
332 whead->bytes = 0;
333 whead->cmd = cmd;
334 whead->id = trans->id;
335 whead->error = 0;
337 trans->windex = sizeof(*whead);
338 trans->hc = hc;
339 trans->state = HCT_IDLE;
341 return(trans);
344 static void
345 hcc_start_reply(hctransaction_t trans, struct HCHead *rhead)
347 struct HCHead *whead = (void *)trans->wbuf;
349 whead->magic = HCMAGIC;
350 whead->bytes = 0;
351 whead->cmd = rhead->cmd | HCF_REPLY;
352 whead->id = rhead->id;
353 whead->error = 0;
355 trans->windex = sizeof(*whead);
359 * Finish constructing a command, transmit it, and await the reply.
360 * Return the HCHead of the reply.
362 struct HCHead *
363 hcc_finish_command(hctransaction_t trans)
365 struct HCHead *whead;
366 struct HCHead *rhead;
367 int aligned_bytes;
368 int16_t wcmd;
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) {
377 #ifdef __error
378 *__error = EIO;
379 #else
380 errno = EIO;
381 #endif
382 if (whead->cmd < 0x0010)
383 return(NULL);
384 fprintf(stderr, "cpdup lost connection to %s\n", trans->hc->host);
385 exit(1);
388 wcmd = whead->cmd;
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) {
395 #ifdef __error
396 *__error = EIO;
397 #else
398 errno = EIO;
399 #endif
400 if (wcmd < 0x0010)
401 return(NULL);
402 fprintf(stderr, "cpdup lost connection to %s\n", trans->hc->host);
403 exit(1);
406 if (rhead->error) {
407 #ifdef __error
408 *__error = rhead->error;
409 #else
410 errno = rhead->error;
411 #endif
413 return (rhead);
416 void
417 hcc_leaf_string(hctransaction_t trans, int16_t leafid, const char *str)
419 struct HCLeaf *item;
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;
425 item->reserved = 0;
426 item->bytes = sizeof(*item) + bytes;
427 bcopy(str, item + 1, bytes);
428 trans->windex = HCC_ALIGN(trans->windex + item->bytes);
431 void
432 hcc_leaf_data(hctransaction_t trans, int16_t leafid, const void *ptr, int bytes)
434 struct HCLeaf *item;
436 item = (void *)(trans->wbuf + trans->windex);
437 assert(trans->windex + sizeof(*item) + bytes < 65536);
438 item->leafid = leafid;
439 item->reserved = 0;
440 item->bytes = sizeof(*item) + bytes;
441 bcopy(ptr, item + 1, bytes);
442 trans->windex = HCC_ALIGN(trans->windex + item->bytes);
445 void
446 hcc_leaf_int32(hctransaction_t trans, int16_t leafid, int32_t value)
448 struct HCLeaf *item;
450 item = (void *)(trans->wbuf + trans->windex);
451 assert(trans->windex + sizeof(*item) + sizeof(value) < 65536);
452 item->leafid = leafid;
453 item->reserved = 0;
454 item->bytes = sizeof(*item) + sizeof(value);
455 *(int32_t *)(item + 1) = value;
456 trans->windex = HCC_ALIGN(trans->windex + item->bytes);
459 void
460 hcc_leaf_int64(hctransaction_t trans, int16_t leafid, int64_t value)
462 struct HCLeaf *item;
464 item = (void *)(trans->wbuf + trans->windex);
465 assert(trans->windex + sizeof(*item) + sizeof(value) < 65536);
466 item->leafid = leafid;
467 item->reserved = 0;
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));
480 hnew->type = type;
481 hnew->data = ptr;
483 if ((hd = hc->hostdescs) != NULL) {
484 hnew->desc = hd->desc + 1;
485 } else {
486 hnew->desc = 1;
488 hnew->next = hd;
489 hc->hostdescs = hnew;
490 return(hnew->desc);
493 void *
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)
500 return(hd->data);
502 return(NULL);
505 void
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) {
513 if (ptr) {
514 hd->data = ptr;
515 hd->type = type;
516 } else {
517 *hdp = hd->next;
518 free(hd);
520 return;
523 if (ptr) {
524 hd = malloc(sizeof(*hd));
525 hd->desc = desc;
526 hd->type = type;
527 hd->data = ptr;
528 hd->next = hc->hostdescs;
529 hc->hostdescs = hd;
533 struct HCLeaf *
534 hcc_firstitem(struct HCHead *head)
536 struct HCLeaf *item;
537 int offset;
539 offset = sizeof(*head);
540 if (offset == head->bytes)
541 return(NULL);
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);
546 return (item);
549 struct HCLeaf *
550 hcc_nextitem(struct HCHead *head, struct HCLeaf *item)
552 int offset;
554 item = (void *)((char *)item + HCC_ALIGN(item->bytes));
555 offset = (char *)item - (char *)head;
556 if (offset == head->bytes)
557 return(NULL);
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);
561 return (item);
564 #ifdef DEBUG
566 void
567 hcc_debug_dump(struct HCHead *head)
569 struct HCLeaf *item;
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) {
579 case LCF_INT32:
580 fprintf(stderr, "int32 %d\n", *(int32_t *)(item + 1));
581 break;
582 case LCF_INT64:
583 fprintf(stderr, "int64 %lld\n", *(int64_t *)(item + 1));
584 break;
585 case LCF_STRING:
586 fprintf(stderr, "\"%s\"\n", (char *)(item + 1));
587 break;
588 case LCF_BINARY:
589 fprintf(stderr, "(binary)\n");
590 break;
591 default:
592 printf("?\n");
597 #endif