X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ian/git?p=chiark-utils.git;a=blobdiff_plain;f=cprogs%2Frcopy-repeatedly.c;fp=cprogs%2Frcopy-repeatedly.c;h=68aedcfe85fc33dcd45fc491d4c450a9bbf65c25;hp=86cd3170388c2d9a66d32b7925616411a8a38874;hb=76d935083795438ff360cb1d13543b215da94d2a;hpb=e07e49f983756cbeb25ac4ac813e18defdca0de6 diff --git a/cprogs/rcopy-repeatedly.c b/cprogs/rcopy-repeatedly.c index 86cd317..68aedcf 100644 --- a/cprogs/rcopy-repeatedly.c +++ b/cprogs/rcopy-repeatedly.c @@ -7,15 +7,18 @@ * server sends banner * - "#rcopy-repeatedly#\n" * - length of declaration, as 4 hex digits, zero prefixed, - * and a space [5 bytes]. In this protocol version this + * and a newline [5 bytes]. In this protocol version this * will be "0002" but client _must_ parse it. * server sends declaration * - one of "u " or "d" [1 byte] * - optionally, some more ascii text, reserved for future use - * must be ignored by client (but not sent by server) + * must be ignored by declaree (but not sent by declarer) * - a newline [1 byte] * client sends - * - 0x01 go + * - 0x02 START + * n 2 bytes big endian declaration length + * ... client's declaration (ascii text, including newline) + 8 see above * then for each update * sender sends one of * - 0x03 destination file should be deleted @@ -24,7 +27,7 @@ * - 0x04 complete new destination file follows, 64-bit length * l 8 bytes big endian length * ... l bytes data - * receiver must then reply with 0x01 GO + * receiver must then reply with 0x01 ACK */ #define _GNU_SOURCE @@ -46,7 +49,8 @@ #include "myopt.h" -#define REPLMSG_GO 0x01 +#define REPLMSG_ACK 0x01 +#define REPLMSG_START 0x02 #define REPLMSG_RM 0x03 #define REPLMSG_FILE64 0x04 @@ -68,6 +72,7 @@ static int server_upcopy=-1; /* -1 means not yet known; 0 means download */ /* `up' means towards the client, * since we regard the subprocess as `down' */ +static int udchar; static double stream_allow_secsperbyte= 1/1e6; /* for initial transfer */ static char mainbuf[65536]; /* must be at least 2^16 */ @@ -143,6 +148,13 @@ static void sendbyte(int c) { die_badsend(); } +static void mfreadcommsi(void *buf, int l, const char *what) { + int r= fread(buf,1,l,commsi); if (r!=l) die_badrecv(what); +} +static void mfwritecommso(const void *buf, int l) { + int r= fwrite(buf,1,l,commso); if (r!=l) die_badsend(); +} + static void mpipe(int p[2]) { if (pipe(p)) diee("could not create pipe"); } static void mdup2(int fd, int fd2) { if (dup2(fd,fd2)!=fd2) diee("could not dup2(%d,%d)",fd,fd2); @@ -256,6 +268,24 @@ static void copydie_commso(FILE *f, const char *what) { die_badsend(); } +static int generate_declaration(void) { + /* returns length; declaration is left in mainbuf */ + char *p= mainbuf; + *p++= udchar; + *p++= '\n'; + return p - mainbuf; +} + +static void read_declaration(int decllen) { + assert(decllen <= sizeof(mainbuf)); + if (decllen<2) die_protocol("declaration too short"); + mfreadcommsi(mainbuf,decllen,"declaration"); + if (mainbuf[decllen-1] != '\n') + die_protocol("declaration missing final newline"); + if (mainbuf[0] != udchar) + die_protocol("declaration incorrect direction indicator"); +} + static void receiver(const char *filename) { FILE *newfile; char *tmpfilename; @@ -296,7 +326,7 @@ static void receiver(const char *filename) { if (!newfile) diee("could not create temporary receiving file `%s'", tmpfilename); uint8_t lbuf[8]; - r= fread(lbuf,1,8,commsi); if (r!=8) die_badrecv("FILE64 l"); + mfreadcommsi(lbuf,8,"FILE64 l"); uint64_t l= (lbuf[0] << 28 << 28) | @@ -318,7 +348,7 @@ static void receiver(const char *filename) { diee("could not install new version of destination file `%s'", filename); - sendbyte(REPLMSG_GO); + sendbyte(REPLMSG_ACK); break; default: @@ -391,8 +421,8 @@ static void sender(const char *filename) { }; bandlimit_sendstart(); - - r= fwrite(hbuf,1,9,commso); if (r!=9) die_badsend(); + + mfwritecommso(hbuf,9); copyfile(f, copydie_inputfile,filename, commso, copydie_commso,0, @@ -401,7 +431,7 @@ static void sender(const char *filename) { send_flush(); c= fgetc(commsi); if (c==EOF) die_badrecv("ack"); - if (c!=REPLMSG_GO) die_protocol("got %#02x instead of GO",c); + if (c!=REPLMSG_ACK) die_protocol("got %#02x instead of ACK",c); bandlimit_sendend(stab.st_size, &interval_usec); @@ -410,15 +440,6 @@ static void sender(const char *filename) { } } -void usagemessage(void) { - puts("usage: rcopy-repeatedly [] \n" - " may be or [@]:\n" - " exactly one of each of the two forms must be provided\n" - " a file is taken as remote if it has a : before the first /\n" - "options\n" - " --help\n"); -} - typedef struct { const char *userhost, *path; } FileSpecification; @@ -460,27 +481,67 @@ static void of_server_int(const struct cmdinfo *ci, const char *val) { *(int*)ci->parg= of__server_int(ci,val); } +void usagemessage(void) { + printf( + "usage: rcopy-repeatedly [] \n" + " may be or [@]:\n" + " exactly one of each of the two forms must be provided\n" + " a file is taken as remote if it has a : before the first /\n" + "general options:\n" + " --help\n" + " --quiet | -q\n" + "options for bandwidth (and cpu time) control:\n" + " --max-bandwidth-percent-mean (default %d)\n" + " --max-bandwidth-percent-burst (default %d)\n" + " --tx-block-size (default/max %d)\n" + " --min-interval-usec (default %d)\n" + "options for finding programs:\n" + " --rcopy-repeatedly (default: rcopy-repeatedly)\n" + " --rsh-program (default: $RCOPY_REPEATEDLY_RSH or $RSYNC_RSH or ssh)\n" + "options passed to server side via ssh:\n" + " --receiver --sender, bandwidth control options\n", + (int)(max_bw_prop_mean*100), (int)(max_bw_prop_burst*100), + (int)sizeof(mainbuf), min_interval_usec); +} + static const struct cmdinfo cmdinfos[]= { { "help", .call= of_help }, { "max-bandwidth-percent-mean", 0,1,.call=of_bw,.parg=&max_bw_prop_mean }, { "max-bandwidth-percent-burst",0,1,.call=of_bw,.parg=&max_bw_prop_burst }, - { "tx-block-size", 0,1,.call=of_server_int, .parg=&txblocksz }, - { "min-interval-usec", 0,1,.call=of_server_int, .parg=&min_interval_usec }, - { "rcopy-repeatedly", 0,1, .sassignto=&rcopy_repeatedly_program }, - { "ssh-program", 0,1, .sassignto=&rsh_program }, - { "receiver", .iassignto=&server_upcopy, .arg=0 }, - { "sender", .iassignto=&server_upcopy, .arg=1 }, + { "tx-block-size",0, 1,.call=of_server_int, .parg=&txblocksz }, + { "min-interval-usec",0, 1,.call=of_server_int, .parg=&min_interval_usec }, + { "rcopy-repeatedly",0, 1, .sassignto=&rcopy_repeatedly_program }, + { "rsh-program",0, 1, .sassignto=&rsh_program }, + { "quiet",'q', .iassignto= &verbose, .arg=0 }, + { "receiver", .iassignto= &server_upcopy, .arg=0 }, + { "sender", .iassignto= &server_upcopy, .arg=1 }, { 0 } }; static void server(const char *filename) { - int c; + int c, l; + char buf[2]; + + udchar= server_upcopy?'u':'d'; + commsi= stdin; commso= stdout; - fprintf(commso, "%s0002 %c\n", banner, server_upcopy?'u':'d'); + l= generate_declaration(); + fprintf(commso, "%s%04x\n", banner, l); + mfwritecommso(mainbuf, l); send_flush(); - c= fgetc(commsi); if (c==EOF) die_badrecv("initial go"); - if (c!=REPLMSG_GO) die_protocol("initial go message was %#02x instead",c); + + c= fgetc(commsi); + if (c==EOF) { + if (feof(commsi)) exit(14); + assert(ferror(commsi)); die_badrecv("initial START message"); + } + if (c!=REPLMSG_START) die_protocol("initial START was %#02x instead",c); + + mfreadcommsi(buf,2,"START l"); + l= (buf[0] << 8) | buf[1]; + + read_declaration(l); if (server_upcopy) sender(filename); @@ -491,12 +552,21 @@ static void server(const char *filename) { static void client(void) { int uppipe[2], downpipe[2], r; pid_t child; + FileSpecification *remotespec; + const char *remotemode; mpipe(uppipe); mpipe(downpipe); - FileSpecification *remotespec= srcspec.userhost ? &srcspec : &dstspec; - const char *remotemode= srcspec.userhost ? "--sender" : "--receiver"; + if (srcspec.userhost) { + udchar= 'u'; + remotespec= &srcspec; + remotemode= "--sender"; + } else { + udchar= 'd'; + remotespec= &dstspec; + remotemode= "--receiver"; + } sargs= xrealloc(sargs, sizeof(*sargs) * (7 + nsargs)); memmove(sargs+5, sargs, sizeof(*sargs) * nsargs); @@ -532,7 +602,7 @@ static void client(void) { if (r!=sizeof(banbuf)-1 || memcmp(banbuf,banner,sizeof(banner)-1) || - banbuf[sizeof(banner)-1 + 4] != ' ') { + banbuf[sizeof(banner)-1 + 4] != '\n') { const char **sap; int count=0; for (count=0, sap=sargs; *sap; sap++) count+= strlen(*sap)+1; @@ -555,19 +625,16 @@ static void client(void) { banbuf[sizeof(banbuf)-1]= 0; char *ep; long decllen= strtoul(banbuf + sizeof(banner)-1, &ep, 16); - if (ep!=banbuf + sizeof(banner)-1 + 4 || *ep!=' ') - die_protocol("declaration length syntax error (`%s')",ep); - assert(decllen <= sizeof(mainbuf)); - if (decllen<2) die_protocol("declaration too short"); + if (ep != banbuf + sizeof(banner)-1 + 4) + die_protocol("declaration length syntax error"); - r= fread(mainbuf,1,decllen,commsi); - if (r!=decllen) die_badrecv("declaration"); - if (mainbuf[decllen-1] != '\n') - die_protocol("declaration missing final newline"); - if (mainbuf[0] != (remotespec==&srcspec ? 'u' : 'd')) - die_protocol("declaration incorrect direction indicator"); + read_declaration(decllen); - sendbyte(REPLMSG_GO); + int l= generate_declaration(); + sendbyte(REPLMSG_START); + sendbyte((l >> 8) & 0x0ff); + sendbyte( l & 0x0ff); + mfwritecommso(mainbuf,l); if (remotespec==&srcspec) receiver(dstspec.path);