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 $
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
)
23 if (hc
== NULL
|| hc
->host
== NULL
)
28 if (pipe(fdout
) < 0) {
33 if ((hc
->pid
= fork()) == 0) {
56 execv("/usr/bin/ssh", (void *)av
);
58 } else if (hc
->pid
< 0) {
62 * Parent process. Do the initial handshake to make sure we are
63 * actually talking to a cpdup slave.
74 rc_badop(hctransaction_t trans __unused
, struct HCHead
*head
)
76 head
->error
= EOPNOTSUPP
;
81 hcc_slave(int fdin
, int fdout
, struct HCDesc
*descs
, int count
)
83 struct HostConf hcslave
;
86 struct HCTransaction trans
;
87 int (*dispatch
[256])(hctransaction_t
, struct HCHead
*);
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
;
104 hcslave
.fdout
= fdout
;
108 * Process commands on fdin and write out results on fdout
114 head
= hcc_read_command(&trans
, 1);
119 * Start the reply and dispatch, then process the return code.
122 hcc_start_reply(&trans
, head
);
124 r
= dispatch
[head
->cmd
& 255](&trans
, head
);
128 head
->error
= EINVAL
;
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
);
148 hcc_debug_dump(whead
);
150 if (write(hcslave
.fdout
, whead
, aligned_bytes
) != aligned_bytes
)
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
164 hcc_read_command(hctransaction_t trans
, int anypkt
)
166 struct HostConf
*hc
= trans
->hc
;
167 hctransaction_t fill
;
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
);
183 while (trans
->state
!= HCT_REPLIED
) {
185 while (n
< (int)sizeof(struct HCHead
)) {
186 r
= read(hc
->fdin
, (char *)&tmp
+ n
, sizeof(struct HCHead
) - n
);
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) {
197 for (fill
= trans
->hc
->hct_hash
[tmp
.id
& HCTHASH_MASK
];
201 if (fill
->state
== HCT_SENT
&& fill
->id
== tmp
.id
)
208 "cpdup hlink protocol error with %s (%04x %04x)\n",
209 trans
->hc
->host
, trans
->id
, tmp
.id
);
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
);
226 hcc_debug_dump(head
);
228 fill
->state
= HCT_REPLIED
;
230 trans
->state
= HCT_DONE
;
232 pthread_mutex_unlock(&hc
->read_mutex
);
233 pthread_mutex_lock(&MasterMutex
);
235 return((void *)trans
->rbuf
);
238 pthread_mutex_unlock(&hc
->read_mutex
);
239 pthread_mutex_lock(&MasterMutex
);
248 hcc_get_trans(struct HostConf
*hc
)
250 hctransaction_t trans
;
251 hctransaction_t scan
;
252 pthread_t tid
= pthread_self();
255 i
= ((intptr_t)tid
>> 7) & HCTHASH_MASK
;
257 for (trans
= hc
->hct_hash
[i
]; trans
; trans
= trans
->next
) {
258 if (trans
->tid
== tid
)
262 trans
= malloc(sizeof(*trans
));
263 bzero(trans
, sizeof(*trans
));
267 for (scan
= hc
->hct_hash
[i
]; scan
; scan
= scan
->next
) {
268 if (scan
->id
== trans
->id
) {
269 trans
->id
+= HCTHASH_SIZE
;
273 } while (scan
!= NULL
);
275 trans
->next
= hc
->hct_hash
[i
];
276 hc
->hct_hash
[i
] = trans
;
282 hcc_free_trans(struct HostConf
*hc
)
284 hctransaction_t trans
;
285 hctransaction_t
*transp
;
286 pthread_t tid
= pthread_self();
289 i
= ((intptr_t)tid
>> 7) & HCTHASH_MASK
;
291 for (transp
= &hc
->hct_hash
[i
]; *transp
; transp
= &trans
->next
) {
293 if (trans
->tid
== tid
) {
294 *transp
= trans
->next
;
305 hcc_get_trans(struct HostConf
*hc
)
312 hcc_free_trans(struct HostConf
*hc
)
320 * Initialize for a new command
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
;
334 whead
->id
= trans
->id
;
337 trans
->windex
= sizeof(*whead
);
339 trans
->state
= HCT_IDLE
;
345 hcc_start_reply(hctransaction_t trans
, struct HCHead
*rhead
)
347 struct HCHead
*whead
= (void *)trans
->wbuf
;
349 whead
->magic
= HCMAGIC
;
351 whead
->cmd
= rhead
->cmd
| HCF_REPLY
;
352 whead
->id
= rhead
->id
;
355 trans
->windex
= sizeof(*whead
);
359 * Finish constructing a command, transmit it, and await the reply.
360 * Return the HCHead of the reply.
363 hcc_finish_command(hctransaction_t trans
)
365 struct HCHead
*whead
;
366 struct HCHead
*rhead
;
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
) {
382 if (whead
->cmd
< 0x0010)
384 fprintf(stderr
, "cpdup lost connection to %s\n", trans
->hc
->host
);
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
) {
402 fprintf(stderr
, "cpdup lost connection to %s\n", trans
->hc
->host
);
408 *__error
= rhead
->error
;
410 errno
= rhead
->error
;
417 hcc_leaf_string(hctransaction_t trans
, int16_t leafid
, const char *str
)
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
;
426 item
->bytes
= sizeof(*item
) + bytes
;
427 bcopy(str
, item
+ 1, bytes
);
428 trans
->windex
= HCC_ALIGN(trans
->windex
+ item
->bytes
);
432 hcc_leaf_data(hctransaction_t trans
, int16_t leafid
, const void *ptr
, int bytes
)
436 item
= (void *)(trans
->wbuf
+ trans
->windex
);
437 assert(trans
->windex
+ sizeof(*item
) + bytes
< 65536);
438 item
->leafid
= leafid
;
440 item
->bytes
= sizeof(*item
) + bytes
;
441 bcopy(ptr
, item
+ 1, bytes
);
442 trans
->windex
= HCC_ALIGN(trans
->windex
+ item
->bytes
);
446 hcc_leaf_int32(hctransaction_t trans
, int16_t leafid
, int32_t value
)
450 item
= (void *)(trans
->wbuf
+ trans
->windex
);
451 assert(trans
->windex
+ sizeof(*item
) + sizeof(value
) < 65536);
452 item
->leafid
= leafid
;
454 item
->bytes
= sizeof(*item
) + sizeof(value
);
455 *(int32_t *)(item
+ 1) = value
;
456 trans
->windex
= HCC_ALIGN(trans
->windex
+ item
->bytes
);
460 hcc_leaf_int64(hctransaction_t trans
, int16_t leafid
, int64_t value
)
464 item
= (void *)(trans
->wbuf
+ trans
->windex
);
465 assert(trans
->windex
+ sizeof(*item
) + sizeof(value
) < 65536);
466 item
->leafid
= leafid
;
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
));
483 if ((hd
= hc
->hostdescs
) != NULL
) {
484 hnew
->desc
= hd
->desc
+ 1;
489 hc
->hostdescs
= hnew
;
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
)
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
) {
524 hd
= malloc(sizeof(*hd
));
528 hd
->next
= hc
->hostdescs
;
534 hcc_firstitem(struct HCHead
*head
)
539 offset
= sizeof(*head
);
540 if (offset
== head
->bytes
)
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
);
550 hcc_nextitem(struct HCHead
*head
, struct HCLeaf
*item
)
554 item
= (void *)((char *)item
+ HCC_ALIGN(item
->bytes
));
555 offset
= (char *)item
- (char *)head
;
556 if (offset
== head
->bytes
)
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
);
567 hcc_debug_dump(struct HCHead
*head
)
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
) {
580 fprintf(stderr
, "int32 %d\n", *(int32_t *)(item
+ 1));
583 fprintf(stderr
, "int64 %lld\n", *(int64_t *)(item
+ 1));
586 fprintf(stderr
, "\"%s\"\n", (char *)(item
+ 1));
589 fprintf(stderr
, "(binary)\n");