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 void hcc_start_reply(hctransaction_t trans
, struct HCHead
*rhead
);
14 static int hcc_finish_reply(hctransaction_t trans
, struct HCHead
*head
);
17 hcc_connect(struct HostConf
*hc
, int readonly
)
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
];
55 av
[n
++] = (readonly
? "-RS" : "-S");
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
;
87 struct HCTransaction trans
;
88 int (*dispatch
[256])(hctransaction_t
, struct HCHead
*);
92 bzero(&hcslave
, sizeof(hcslave
));
93 bzero(&trans
, sizeof(trans
));
94 bzero(dispatch
, sizeof(dispatch
));
95 for (i
= 0; i
< count
; ++i
) {
96 struct HCDesc
*desc
= &descs
[i
];
97 assert(desc
->cmd
>= 0 && desc
->cmd
< 256);
98 dispatch
[desc
->cmd
] = desc
->func
;
100 for (i
= 0; i
< 256; ++i
) {
101 if (dispatch
[i
] == NULL
)
102 dispatch
[i
] = rc_badop
;
105 hcslave
.fdout
= fdout
;
109 * Process commands on fdin and write out results on fdout
115 head
= hcc_read_command(trans
.hc
, &trans
);
120 * Start the reply and dispatch, then process the return code.
123 hcc_start_reply(&trans
, head
);
125 r
= dispatch
[head
->cmd
& 255](&trans
, head
);
129 head
->error
= EINVAL
;
141 if (!hcc_finish_reply(&trans
, head
))
148 * This reads a command from fdin, fixes up the byte ordering, and returns
149 * a pointer to HCHead.
152 hcc_read_command(struct HostConf
*hc
, hctransaction_t trans
)
154 hctransaction_t fill
;
162 while (n
< (int)sizeof(struct HCHead
)) {
163 r
= read(hc
->fdin
, (char *)&tmp
+ n
, sizeof(struct HCHead
) - n
);
169 if (tmp
.magic
== HCMAGIC
)
172 tmp
.magic
= hc_bswap32(tmp
.magic
);
173 if (tmp
.magic
!= HCMAGIC
)
174 fatal("magic mismatch with %s (%04x)", hc
->host
, tmp
.id
);
176 tmp
.bytes
= hc_bswap32(tmp
.bytes
);
177 tmp
.cmd
= hc_bswap16(tmp
.cmd
);
178 tmp
.id
= hc_bswap16(tmp
.id
);
179 tmp
.error
= hc_bswap32(tmp
.error
);
182 assert(tmp
.bytes
>= (int)sizeof(tmp
) && tmp
.bytes
< HC_BUFSIZE
);
185 fatal("cpdup hlink protocol error with %s (%04x)", hc
->host
, tmp
.id
);
187 fill
->swap
= need_swap
;
188 bcopy(&tmp
, fill
->rbuf
, n
);
189 aligned_bytes
= HCC_ALIGN(tmp
.bytes
);
191 while (n
< aligned_bytes
) {
192 r
= read(hc
->fdin
, fill
->rbuf
+ n
, aligned_bytes
- n
);
198 hcc_debug_dump(trans
, head
);
200 fill
->state
= HCT_REPLIED
;
201 return((void *)fill
->rbuf
);
207 * Initialize for a new command
210 hcc_start_command(struct HostConf
*hc
, int16_t cmd
)
212 struct HCHead
*whead
;
213 hctransaction_t trans
;
217 whead
= (void *)trans
->wbuf
;
218 whead
->magic
= HCMAGIC
;
221 whead
->id
= trans
->id
;
224 trans
->windex
= sizeof(*whead
);
226 trans
->state
= HCT_IDLE
;
232 hcc_start_reply(hctransaction_t trans
, struct HCHead
*rhead
)
234 struct HCHead
*whead
= (void *)trans
->wbuf
;
236 whead
->magic
= HCMAGIC
;
238 whead
->cmd
= rhead
->cmd
| HCF_REPLY
;
239 whead
->id
= rhead
->id
;
242 trans
->windex
= sizeof(*whead
);
246 * Finish constructing a command, transmit it, and await the reply.
247 * Return the HCHead of the reply.
250 hcc_finish_command(hctransaction_t trans
)
253 struct HCHead
*whead
;
254 struct HCHead
*rhead
;
259 whead
= (void *)trans
->wbuf
;
260 whead
->bytes
= trans
->windex
;
261 aligned_bytes
= HCC_ALIGN(trans
->windex
);
262 trans
->windex
= 0; /* initialize for hcc_nextchaineditem() */
264 trans
->state
= HCT_SENT
;
266 if (write(hc
->fdout
, whead
, aligned_bytes
) != aligned_bytes
) {
272 if (whead
->cmd
< 0x0010)
274 fatal("cpdup lost connection to %s", hc
->host
);
280 * whead is invalid when we call hcc_read_command() because
281 * we may switch to another thread.
283 rhead
= hcc_read_command(hc
, trans
);
284 if (trans
->state
!= HCT_REPLIED
|| rhead
->id
!= trans
->id
) {
292 fatal("cpdup lost connection to %s", hc
->host
);
294 trans
->state
= HCT_DONE
;
298 *__error
= rhead
->error
;
300 errno
= rhead
->error
;
307 hcc_finish_reply(hctransaction_t trans
, struct HCHead
*head
)
309 struct HCHead
*whead
;
312 whead
= (void *)trans
->wbuf
;
313 whead
->bytes
= trans
->windex
;
314 whead
->error
= head
->error
;
315 aligned_bytes
= HCC_ALIGN(trans
->windex
);
317 hcc_debug_dump(trans
, whead
);
319 return (write(trans
->hc
->fdout
, whead
, aligned_bytes
) == aligned_bytes
);
323 hcc_leaf_string(hctransaction_t trans
, int16_t leafid
, const char *str
)
326 int bytes
= strlen(str
) + 1;
328 item
= (void *)(trans
->wbuf
+ trans
->windex
);
329 assert(trans
->windex
+ sizeof(*item
) + bytes
< HC_BUFSIZE
);
330 item
->leafid
= leafid
;
332 item
->bytes
= sizeof(*item
) + bytes
;
333 bcopy(str
, item
+ 1, bytes
);
334 trans
->windex
= HCC_ALIGN(trans
->windex
+ item
->bytes
);
338 hcc_leaf_data(hctransaction_t trans
, int16_t leafid
, const void *ptr
, int bytes
)
342 item
= (void *)(trans
->wbuf
+ trans
->windex
);
343 assert(trans
->windex
+ sizeof(*item
) + bytes
< HC_BUFSIZE
);
344 item
->leafid
= leafid
;
346 item
->bytes
= sizeof(*item
) + bytes
;
347 bcopy(ptr
, item
+ 1, bytes
);
348 trans
->windex
= HCC_ALIGN(trans
->windex
+ item
->bytes
);
352 hcc_leaf_int32(hctransaction_t trans
, int16_t leafid
, int32_t value
)
356 item
= (void *)(trans
->wbuf
+ trans
->windex
);
357 assert(trans
->windex
+ sizeof(*item
) + sizeof(value
) < HC_BUFSIZE
);
358 item
->leafid
= leafid
;
360 item
->bytes
= sizeof(*item
) + sizeof(value
);
361 *(int32_t *)(item
+ 1) = value
;
362 trans
->windex
= HCC_ALIGN(trans
->windex
+ item
->bytes
);
366 hcc_leaf_int64(hctransaction_t trans
, int16_t leafid
, int64_t value
)
370 item
= (void *)(trans
->wbuf
+ trans
->windex
);
371 assert(trans
->windex
+ sizeof(*item
) + sizeof(value
) < HC_BUFSIZE
);
372 item
->leafid
= leafid
;
374 item
->bytes
= sizeof(*item
) + sizeof(value
);
375 *(int64_t *)(item
+ 1) = value
;
376 trans
->windex
= HCC_ALIGN(trans
->windex
+ item
->bytes
);
380 * Check if there's enough space left in the write buffer for <n>
381 * leaves with a total of <size> data bytes.
382 * If not, the current packet will be sent with the HCF_CONTINUE flag,
383 * then the transaction is initialized for another reply packet.
385 * Returns success status (boolean).
388 hcc_check_space(hctransaction_t trans
, struct HCHead
*head
, int n
, int size
)
390 size
= HCC_ALIGN(size
) + n
* sizeof(struct HCLeaf
);
391 if (size
>= HC_BUFSIZE
- trans
->windex
) {
392 struct HCHead
*whead
= (void *)trans
->wbuf
;
394 whead
->cmd
|= HCF_CONTINUE
;
395 if (!hcc_finish_reply(trans
, head
))
397 hcc_start_reply(trans
, head
);
403 hcc_alloc_descriptor(struct HostConf
*hc
, void *ptr
, int type
)
405 struct HCHostDesc
*hd
;
406 struct HCHostDesc
*hnew
;
408 hnew
= malloc(sizeof(struct HCHostDesc
));
412 if ((hd
= hc
->hostdescs
) != NULL
) {
413 hnew
->desc
= hd
->desc
+ 1;
415 /* start at 2 because 1 has a special meaning in hc_open() */
419 hc
->hostdescs
= hnew
;
424 hcc_get_descriptor(struct HostConf
*hc
, intptr_t desc
, int type
)
426 struct HCHostDesc
*hd
;
428 for (hd
= hc
->hostdescs
; hd
; hd
= hd
->next
) {
429 if (hd
->desc
== desc
&& hd
->type
== type
)
436 hcc_set_descriptor(struct HostConf
*hc
, intptr_t desc
, void *ptr
, int type
)
438 struct HCHostDesc
*hd
;
439 struct HCHostDesc
**hdp
;
441 for (hdp
= &hc
->hostdescs
; (hd
= *hdp
) != NULL
; hdp
= &hd
->next
) {
442 if (hd
->desc
== desc
) {
454 hd
= malloc(sizeof(*hd
));
458 hd
->next
= hc
->hostdescs
;
464 hcc_nextitem(hctransaction_t trans
, struct HCHead
*head
, struct HCLeaf
*item
)
469 item
= (void *)(head
+ 1);
471 item
= (void *)((char *)item
+ HCC_ALIGN(item
->bytes
));
472 offset
= (char *)item
- (char *)head
;
473 if (offset
== head
->bytes
)
479 item
->leafid
= hc_bswap16(item
->leafid
);
480 item
->bytes
= hc_bswap32(item
->bytes
);
481 switch (item
->leafid
& LCF_TYPEMASK
) {
483 i32ptr
= (void *)(item
+ 1);
484 *i32ptr
= hc_bswap32(*i32ptr
);
487 i64ptr
= (void *)(item
+ 1);
488 *i64ptr
= hc_bswap64(*i64ptr
);
492 assert(head
->bytes
>= offset
+ (int)sizeof(*item
));
493 assert(head
->bytes
>= offset
+ item
->bytes
);
494 assert(item
->bytes
>= (int)sizeof(*item
) && item
->bytes
< HC_BUFSIZE
);
499 hcc_nextchaineditem(struct HostConf
*hc
, struct HCHead
*head
)
501 hctransaction_t trans
= &hc
->trans
;
502 struct HCLeaf
*item
= hcc_currentchaineditem(hc
, head
);
504 while ((item
= hcc_nextitem(trans
, head
, item
)) == NULL
) {
505 if (!(head
->cmd
& HCF_CONTINUE
))
507 head
= hcc_read_command(hc
, trans
);
508 if (trans
->state
!= HCT_REPLIED
|| head
->id
!= trans
->id
)
511 trans
->windex
= (char *)item
- (char *)head
;
516 hcc_currentchaineditem(struct HostConf
*hc
, struct HCHead
*head
)
518 hctransaction_t trans
= &hc
->trans
;
520 if (trans
->windex
== 0)
523 return ((void *) ((char *)head
+ trans
->windex
));
529 hcc_debug_dump(hctransaction_t trans
, struct HCHead
*head
)
532 int aligned_bytes
= HCC_ALIGN(head
->bytes
);
534 fprintf(stderr
, "DUMP %04x (%d)", (uint16_t)head
->cmd
, aligned_bytes
);
535 if (head
->cmd
& HCF_REPLY
)
536 fprintf(stderr
, " error %d", head
->error
);
537 fprintf(stderr
, "\n");
538 FOR_EACH_ITEM(item
, trans
, head
) {
539 fprintf(stderr
, " ITEM %04x DATA ", item
->leafid
);
540 switch(item
->leafid
& LCF_TYPEMASK
) {
542 fprintf(stderr
, "int32 %d\n", HCC_INT32(item
));
545 fprintf(stderr
, "int64 %lld\n", HCC_INT64(item
));
548 fprintf(stderr
, "\"%s\"\n", HCC_STRING(item
));
551 fprintf(stderr
, "(binary)\n");