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 struct HCHead
*hcc_read_command(struct HostConf
*hc
, hctransaction_t trans
);
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) {
50 for (m
= 0; m
< ssh_argc
; m
++)
51 av
[n
++] = ssh_argv
[m
];
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
;
88 struct HCTransaction trans
;
89 int (*dispatch
[256])(hctransaction_t
, struct HCHead
*);
94 bzero(&hcslave
, sizeof(hcslave
));
95 bzero(&trans
, sizeof(trans
));
96 bzero(dispatch
, sizeof(dispatch
));
97 for (i
= 0; i
< count
; ++i
) {
98 struct HCDesc
*desc
= &descs
[i
];
99 assert(desc
->cmd
>= 0 && desc
->cmd
< 256);
100 dispatch
[desc
->cmd
] = desc
->func
;
102 for (i
= 0; i
< 256; ++i
) {
103 if (dispatch
[i
] == NULL
)
104 dispatch
[i
] = rc_badop
;
107 hcslave
.fdout
= fdout
;
111 * Process commands on fdin and write out results on fdout
117 head
= hcc_read_command(trans
.hc
, &trans
);
122 * Start the reply and dispatch, then process the return code.
125 hcc_start_reply(&trans
, head
);
127 r
= dispatch
[head
->cmd
& 255](&trans
, head
);
131 head
->error
= EINVAL
;
144 * Write out the reply
146 whead
= (void *)trans
.wbuf
;
147 whead
->bytes
= trans
.windex
;
148 whead
->error
= head
->error
;
149 aligned_bytes
= HCC_ALIGN(trans
.windex
);
151 hcc_debug_dump(whead
);
153 if (write(hcslave
.fdout
, whead
, aligned_bytes
) != aligned_bytes
)
160 * This reads a command from fdin, fixes up the byte ordering, and returns
161 * a pointer to HCHead.
163 * The MasterMutex may or may not be held. When threaded this command
164 * is serialized by a reader thread.
168 hcc_read_command(struct HostConf
*hc
, hctransaction_t trans
)
170 hctransaction_t fill
;
177 while (n
< (int)sizeof(struct HCHead
)) {
178 r
= read(hc
->fdin
, (char *)&tmp
+ n
, sizeof(struct HCHead
) - n
);
184 assert(tmp
.bytes
>= (int)sizeof(tmp
) && tmp
.bytes
< 65536);
185 assert(tmp
.magic
== HCMAGIC
);
190 fprintf(stderr
, "cpdup hlink protocol error with %s (%04x)\n",
195 bcopy(&tmp
, fill
->rbuf
, n
);
196 aligned_bytes
= HCC_ALIGN(tmp
.bytes
);
198 while (n
< aligned_bytes
) {
199 r
= read(hc
->fdin
, fill
->rbuf
+ n
, aligned_bytes
- n
);
205 hcc_debug_dump(head
);
207 fill
->state
= HCT_REPLIED
;
208 return((void *)fill
->rbuf
);
215 hcc_get_trans(struct HostConf
*hc
)
221 hcc_free_trans(struct HostConf
*hc __unused
)
227 * Initialize for a new command
230 hcc_start_command(struct HostConf
*hc
, int16_t cmd
)
232 struct HCHead
*whead
;
233 hctransaction_t trans
;
235 trans
= hcc_get_trans(hc
);
237 whead
= (void *)trans
->wbuf
;
238 whead
->magic
= HCMAGIC
;
241 whead
->id
= trans
->id
;
244 trans
->windex
= sizeof(*whead
);
246 trans
->state
= HCT_IDLE
;
252 hcc_start_reply(hctransaction_t trans
, struct HCHead
*rhead
)
254 struct HCHead
*whead
= (void *)trans
->wbuf
;
256 whead
->magic
= HCMAGIC
;
258 whead
->cmd
= rhead
->cmd
| HCF_REPLY
;
259 whead
->id
= rhead
->id
;
262 trans
->windex
= sizeof(*whead
);
266 * Finish constructing a command, transmit it, and await the reply.
267 * Return the HCHead of the reply.
270 hcc_finish_command(hctransaction_t trans
)
273 struct HCHead
*whead
;
274 struct HCHead
*rhead
;
279 whead
= (void *)trans
->wbuf
;
280 whead
->bytes
= trans
->windex
;
281 aligned_bytes
= HCC_ALIGN(trans
->windex
);
283 trans
->state
= HCT_SENT
;
285 if (write(hc
->fdout
, whead
, aligned_bytes
) != aligned_bytes
) {
291 if (whead
->cmd
< 0x0010)
293 fprintf(stderr
, "cpdup lost connection to %s\n", hc
->host
);
300 * whead is invalid when we call hcc_read_command() because
301 * we may switch to another thread.
303 rhead
= hcc_read_command(hc
, trans
);
304 if (trans
->state
!= HCT_REPLIED
|| rhead
->id
!= trans
->id
) {
312 fprintf(stderr
, "cpdup lost connection to %s\n", hc
->host
);
315 trans
->state
= HCT_DONE
;
319 *__error
= rhead
->error
;
321 errno
= rhead
->error
;
328 hcc_leaf_string(hctransaction_t trans
, int16_t leafid
, const char *str
)
331 int bytes
= strlen(str
) + 1;
333 item
= (void *)(trans
->wbuf
+ trans
->windex
);
334 assert(trans
->windex
+ sizeof(*item
) + bytes
< 65536);
335 item
->leafid
= leafid
;
337 item
->bytes
= sizeof(*item
) + bytes
;
338 bcopy(str
, item
+ 1, bytes
);
339 trans
->windex
= HCC_ALIGN(trans
->windex
+ item
->bytes
);
343 hcc_leaf_data(hctransaction_t trans
, int16_t leafid
, const void *ptr
, int bytes
)
347 item
= (void *)(trans
->wbuf
+ trans
->windex
);
348 assert(trans
->windex
+ sizeof(*item
) + bytes
< 65536);
349 item
->leafid
= leafid
;
351 item
->bytes
= sizeof(*item
) + bytes
;
352 bcopy(ptr
, item
+ 1, bytes
);
353 trans
->windex
= HCC_ALIGN(trans
->windex
+ item
->bytes
);
357 hcc_leaf_int32(hctransaction_t trans
, int16_t leafid
, int32_t value
)
361 item
= (void *)(trans
->wbuf
+ trans
->windex
);
362 assert(trans
->windex
+ sizeof(*item
) + sizeof(value
) < 65536);
363 item
->leafid
= leafid
;
365 item
->bytes
= sizeof(*item
) + sizeof(value
);
366 *(int32_t *)(item
+ 1) = value
;
367 trans
->windex
= HCC_ALIGN(trans
->windex
+ item
->bytes
);
371 hcc_leaf_int64(hctransaction_t trans
, int16_t leafid
, int64_t value
)
375 item
= (void *)(trans
->wbuf
+ trans
->windex
);
376 assert(trans
->windex
+ sizeof(*item
) + sizeof(value
) < 65536);
377 item
->leafid
= leafid
;
379 item
->bytes
= sizeof(*item
) + sizeof(value
);
380 *(int64_t *)(item
+ 1) = value
;
381 trans
->windex
= HCC_ALIGN(trans
->windex
+ item
->bytes
);
385 hcc_alloc_descriptor(struct HostConf
*hc
, void *ptr
, int type
)
387 struct HCHostDesc
*hd
;
388 struct HCHostDesc
*hnew
;
390 hnew
= malloc(sizeof(struct HCHostDesc
));
394 if ((hd
= hc
->hostdescs
) != NULL
) {
395 hnew
->desc
= hd
->desc
+ 1;
400 hc
->hostdescs
= hnew
;
405 hcc_get_descriptor(struct HostConf
*hc
, int desc
, int type
)
407 struct HCHostDesc
*hd
;
409 for (hd
= hc
->hostdescs
; hd
; hd
= hd
->next
) {
410 if (hd
->desc
== desc
&& hd
->type
== type
)
417 hcc_set_descriptor(struct HostConf
*hc
, int desc
, void *ptr
, int type
)
419 struct HCHostDesc
*hd
;
420 struct HCHostDesc
**hdp
;
422 for (hdp
= &hc
->hostdescs
; (hd
= *hdp
) != NULL
; hdp
= &hd
->next
) {
423 if (hd
->desc
== desc
) {
435 hd
= malloc(sizeof(*hd
));
439 hd
->next
= hc
->hostdescs
;
445 hcc_firstitem(struct HCHead
*head
)
450 offset
= sizeof(*head
);
451 if (offset
== head
->bytes
)
453 assert(head
->bytes
>= offset
+ (int)sizeof(*item
));
454 item
= (void *)(head
+ 1);
455 assert(head
->bytes
>= offset
+ item
->bytes
);
456 assert(item
->bytes
>= (int)sizeof(*item
) && item
->bytes
< 65536 - offset
);
461 hcc_nextitem(struct HCHead
*head
, struct HCLeaf
*item
)
465 item
= (void *)((char *)item
+ HCC_ALIGN(item
->bytes
));
466 offset
= (char *)item
- (char *)head
;
467 if (offset
== head
->bytes
)
469 assert(head
->bytes
>= offset
+ (int)sizeof(*item
));
470 assert(head
->bytes
>= offset
+ item
->bytes
);
471 assert(item
->bytes
>= (int)sizeof(*item
) && item
->bytes
< 65536 - offset
);
478 hcc_debug_dump(struct HCHead
*head
)
481 int aligned_bytes
= HCC_ALIGN(head
->bytes
);
483 fprintf(stderr
, "DUMP %04x (%d)", (u_int16_t
)head
->cmd
, aligned_bytes
);
484 if (head
->cmd
& HCF_REPLY
)
485 fprintf(stderr
, " error %d", head
->error
);
486 fprintf(stderr
, "\n");
487 for (item
= hcc_firstitem(head
); item
; item
= hcc_nextitem(head
, item
)) {
488 fprintf(stderr
, " ITEM %04x DATA ", item
->leafid
);
489 switch(item
->leafid
& LCF_TYPEMASK
) {
491 fprintf(stderr
, "int32 %d\n", *(int32_t *)(item
+ 1));
494 fprintf(stderr
, "int64 %lld\n", *(int64_t *)(item
+ 1));
497 fprintf(stderr
, "\"%s\"\n", (char *)(item
+ 1));
500 fprintf(stderr
, "(binary)\n");