/* -bps and -burst arguments are in bytes. */ #include #include #include #include #include #include extern const char *__progname; static int bps; static int burst; static int allowance; static struct timeval allowt; static struct timeval napto; static int firstbytes; static int firstnap; static int verbose; static void handleargs(int ac, char **av) { int skip; int errs; skip = 0; errs = 0; for (ac--,av++;ac;ac--,av++) { if (skip > 0) { skip --; continue; } if (**av != '-') { fprintf(stderr,"%s: unrecognized argument `%s'\n",__progname,*av); errs ++; continue; } if (0) { needarg:; fprintf(stderr,"%s: %s needs a following argument\n",__progname,*av); errs ++; continue; } #define WANTARG() do { if (++skip >= ac) goto needarg; } while (0) if (!strcmp(*av,"-bps")) { WANTARG(); bps = atoi(av[skip]); continue; } if (!strcmp(*av,"-burst")) { WANTARG(); burst = atoi(av[skip]); continue; } if (!strcmp(*av,"-first")) { WANTARG(); firstbytes = atoi(av[skip]); WANTARG(); firstnap = atof(av[skip]) * 1000000; continue; } if (!strcmp(*av,"-v")) { verbose = 1; continue; } #undef WANTARG fprintf(stderr,"%s: unrecognized option `%s'\n",__progname,*av); errs ++; } if (bps < 1) { fprintf(stderr,"%s: must give -bps with a value > 0\n",__progname); errs ++; } if (errs) exit(1); } static void tv_addus(struct timeval *tv, int us) { tv->tv_sec += us / 1000000; tv->tv_usec += us % 1000000; if (tv->tv_usec >= 1000000) { tv->tv_usec -= 1000000; tv->tv_sec ++; } } static void nap(int us) { struct timeval tv; tv_addus(&napto,us); while (1) { gettimeofday(&tv,0); if ( (tv.tv_sec > napto.tv_sec) || ( (tv.tv_sec == napto.tv_sec) && (tv.tv_usec >= napto.tv_usec) ) ) return; if (tv.tv_usec <= napto.tv_usec) { tv.tv_sec = napto.tv_sec - tv.tv_sec; tv.tv_usec = napto.tv_usec - tv.tv_usec; } else { tv.tv_sec = napto.tv_sec - tv.tv_sec - 1; tv.tv_usec = napto.tv_usec + 1000000 - tv.tv_usec; } select(1,0,0,0,&tv); } } static void adjust_allowance(void) { struct timeval now; unsigned long int deltaus; int nb; gettimeofday(&now,0); if ( (now.tv_sec < allowt.tv_sec) || ( (now.tv_sec == allowt.tv_sec) && (now.tv_usec <= allowt.tv_usec) ) ) { if (verbose) fprintf(stderr,"adjust: %lu.%06lu < %lu.%06lu\n", (unsigned long int)now.tv_sec,(unsigned long int)now.tv_usec, (unsigned long int)allowt.tv_sec,(unsigned long int)allowt.tv_usec); return; } if (verbose) fprintf(stderr,"adjust: allowt %lu.%06lu now %lu.%06lu", (unsigned long int)allowt.tv_sec,(unsigned long int)allowt.tv_usec, (unsigned long int)now.tv_sec,(unsigned long int)now.tv_usec); deltaus = ((now.tv_sec - allowt.tv_sec) * 1000000) + now.tv_usec - allowt.tv_usec; if (verbose) fprintf(stderr," deltaus %lu",deltaus); nb = (bps * deltaus) / 1000000; if (verbose) fprintf(stderr," nb %d",nb); deltaus = (nb * 1000000) / bps; if (verbose) fprintf(stderr," deltaus %lu\n",deltaus); tv_addus(&allowt,deltaus); allowance += nb; } static void copy_allowed(void) { char buf[8192]; int nb; if (burst && (allowance < burst)) return; while (allowance > 0) { nb = allowance; if (nb > sizeof(buf)) nb = sizeof(buf); nb = read(0,&buf[0],nb); if (nb < 0) { fprintf(stderr,"%s: read error: %s\n",__progname,strerror(errno)); exit(1); } if (nb == 0) exit(0); write(1,&buf[0],nb); allowance -= nb; if (verbose) fprintf(stderr,"copy %d\n",nb); } } int main(int, char **); int main(int ac, char **av) { handleargs(ac,av); allowance = 0; gettimeofday(&napto,0); if (firstbytes) { allowance += firstbytes; copy_allowed(); } if (firstnap) nap(firstnap); gettimeofday(&allowt,0); while (1) { nap(10000); adjust_allowance(); copy_allowed(); } }