Index: main.c =================================================================== RCS file: /home/ncvs/projects/csup/main.c,v retrieving revision 1.28 diff -u -r1.28 main.c --- main.c 2 Feb 2006 19:53:13 -0000 1.28 +++ main.c 5 Feb 2006 19:01:43 -0000 @@ -52,6 +52,8 @@ { lprintf(-1, "Usage: %s [options] supfile\n", basename(argv0)); lprintf(-1, " Options:\n"); + lprintf(-1, USAGE_OPTFMT, "-1", "Don't retry automatically on failure" + "(same as \"-r 0\""); lprintf(-1, USAGE_OPTFMT, "-4", "Force usage of IPv4 addresses"); lprintf(-1, USAGE_OPTFMT, "-6", "Force usage of IPv6 addresses"); lprintf(-1, USAGE_OPTFMT, "-b base", @@ -78,12 +80,14 @@ int main(int argc, char *argv[]) { + struct backoff_timer *timer; struct config *config; struct stream *lock; char *argv0, *base, *colldir, *host, *file, *lockfile; uint16_t port; - int family, compress, error, lockfd, lflag, truststatus; - int c; + int family, compress, error, lockfd, lflag, retries, truststatus; + int c, i; + time_t nexttry; error = 0; family = PF_UNSPEC; @@ -92,10 +96,15 @@ truststatus = 0; lflag = 0; lockfd = 0; + nexttry = 0; + retries = 0; argv0 = argv[0]; base = colldir = host = lockfile = NULL; - while ((c = getopt(argc, argv, "46b:c:gh:l:L:p:P:svzZ")) != -1) { + while ((c = getopt(argc, argv, "146b:c:gh:l:L:p:P:r:svzZ")) != -1) { switch (c) { + case '1': + retries = 1; + break; case '4': family = AF_INET; break; @@ -165,6 +174,15 @@ return (1); } break; + case 'r': + errno = 0; + retries = strtol(optarg, NULL, 0); + if (errno == EINVAL) { + lprintf(-1, "Invalid number of retries\n"); + usage(argv0); + return (1); + } + break; case 's': truststatus = 1; break; @@ -199,11 +217,24 @@ lprintf(2, "Parsing supfile \"%s\"\n", file); config = config_init(file, host, base, colldir, compress, truststatus); lprintf(2, "Connecting to %s\n", config->host); - error = proto_connect(config, family, port); - if (error) - return (1); - lprintf(1, "Connected to %s\n", config->host); - proto_init(config); + + timer = btcreate((time_t)300, (time_t)7200, 2.0, 0.1); + for (i = -1; i < retries;) { + error = proto_connect(config, family, port); + if (!error) { + lprintf(1, "Connected to %s\n", config->host); + error = proto_init(config); + if (!error) + break; + } + if (retries) + i++; + if (i < retries) { + nexttry = time(0) + btget(timer); + lprintf(1, "Will retry at %s", ctime(&nexttry)); + btpause(timer); + } + } if (lflag) { unlink(lockfile); flock(lockfd, LOCK_UN); Index: misc.c =================================================================== RCS file: /home/ncvs/projects/csup/misc.c,v retrieving revision 1.22 diff -u -r1.22 misc.c --- misc.c 3 Feb 2006 17:22:34 -0000 1.22 +++ misc.c 5 Feb 2006 19:01:43 -0000 @@ -37,12 +37,23 @@ #include #include #include +#include #include #include "fattr.h" #include "main.h" #include "misc.h" +struct backoff_timer { + time_t min; + time_t max; + time_t interval; + float backoff; + float jitter; +}; + +void btupdate(struct backoff_timer *); + int lprintf(int level, const char *fmt, ...) { @@ -324,4 +335,58 @@ if (*ret == NULL) err(1, "asprintf"); return (rv); +} + +/* + * Creates a backoff timer. + */ +struct backoff_timer * +btcreate(time_t min, time_t max, float backoff, float jitter) +{ + time_t mag; + struct backoff_timer *bt; + bt = malloc(sizeof(struct backoff_timer)); + if (!bt) + err(1, "malloc"); + bt->min = min; + bt->max = max; + bt->backoff = backoff; + bt->jitter = jitter; + bt->interval = min; + mag = (time_t)bt->jitter * bt->interval; + srand(time(0)); + bt->interval = bt->interval + rand()%(mag+1); + return bt; +} + +/* + * Updates backoff timer. + */ +void +btupdate(struct backoff_timer *bt) +{ + time_t cur = bt->interval * (time_t)bt->backoff; + if (bt->max > cur) + bt->interval = bt->max; + else + bt->interval = cur; +} + +/* + * Returns timer + */ +time_t +btget(struct backoff_timer *bt) +{ + return bt->interval; +} + +/* + * Times out for bt->interval seconds. + */ +void +btpause(struct backoff_timer *bt) +{ + sleep(bt->interval); + btupdate(bt); } Index: misc.h =================================================================== RCS file: /home/ncvs/projects/csup/misc.h,v retrieving revision 1.20 diff -u -r1.20 misc.h --- misc.h 3 Feb 2006 16:23:03 -0000 1.20 +++ misc.h 5 Feb 2006 19:01:43 -0000 @@ -73,6 +73,7 @@ /* Minimum size for MD5_File() and MD5_End() buffers. */ #define MD5_DIGEST_SIZE 33 +struct backoff_timer; #define min(a, b) ((a) > (b) ? (b) : (a)) @@ -86,6 +87,9 @@ char *checkoutpath(const char *, const char *); int mkdirhier(char *, mode_t); char *tempname(const char *); +struct backoff_timer* btcreate(time_t, time_t, float, float); +time_t btget(struct backoff_timer *); +void btpause(struct backoff_timer *); void *xmalloc(size_t); void *xrealloc(void *, size_t); char *xstrdup(const char *);