int main(int argc, char **argv) { char buf[BUF_SIZE], dev[IFNAMSIZ]="/dev/net/tun", tapdev[IFNAMSIZ], *progname; int tap, r, tun = IFF_TUN; int c, verbose = 0, interval = 0, keep = 0, keep_count = 0; time_t last_keep; struct timeval tv; struct rlimit rlim; fd_set rfd; while ( (c=getopt(argc,argv,"vi:k:")) != -1 ) { switch (c) { case 'v': verbose++; break; case 'i': interval = atoi(optarg); break; case 'k': keep = atoi(optarg); break; } } if ((progname = strrchr(argv[0], '/')) == NULL) { progname = argv[0]; } else { progname++; } if (keep && !interval) { write_str(STDERR_FILENO, progname); write_cstr(STDERR_FILENO, ": keep alive need interval value.\n"); return 1; } signal(SIGPIPE,signalHandler); if (strcmp("tunio", progname)) tun = IFF_TAP; if (argc>optind) { if (!strncmp(argv[optind],"/dev/",5)) argv[optind] += 5; if (verbose) { write_str(STDERR_FILENO, progname); write_cstr(STDERR_FILENO, ": Forced to "); write_str(STDERR_FILENO,argv[optind]); write_cstr(STDERR_FILENO, "\n"); } strstart(tapdev); strarray(tapdev); strannex(tapdev,argv[optind]); tap = tap_alloc (dev, tapdev, tun); } else { strstart(tapdev); for (r=0 ; r<1000 ; r++) { strarray(tapdev); if (tun == IFF_TUN) { strannex(tapdev, "tun"); } else { strannex(tapdev, "tap"); } strannex_uint(tapdev, r); tap = tap_alloc (dev, tapdev, tun); if (tap > 0) break; // success } } if (tap <= 0) { write_str(STDERR_FILENO, progname); if (tun == IFF_TUN) { write_cstr(STDERR_FILENO, ": Cannot open TUN\n"); } else { write_cstr(STDERR_FILENO, ": Cannot open TAP\n"); } return 1; } gettimeofday(&tv, NULL); last_keep = tv.tv_sec; rlim.rlim_cur = 0; setrlimit(RLIMIT_NOFILE, &rlim); /* ------------ main loop without length ---------- */ for (;;) { FD_ZERO(&rfd); FD_SET(STDIN_FILENO, &rfd); FD_SET(tap, &rfd); tv.tv_sec = 1; tv.tv_usec = 0; r = select(tap+1,&rfd,NULL,NULL,&tv); if(r == -1) { write_str(STDERR_FILENO, progname); write_cstr(STDERR_FILENO, ": select() error.\n"); return errno; } if (interval) { gettimeofday(&tv, NULL); if (verbose && (tv.tv_sec % 10)==0) { write_str(STDERR_FILENO, progname); write_str_uint(STDERR_FILENO, ": keep count: ", keep_count); writeln_str_uint(STDERR_FILENO, ", keep: ", keep); } if (tv.tv_sec >= (last_keep+interval)) { write(STDOUT_FILENO, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20); if (verbose) { write_str(STDERR_FILENO, progname); write_cstr(STDERR_FILENO, ": Sent a keep alive.\n"); } last_keep = tv.tv_sec; } } if (keep) { keep_count++; if (verbose) { write_str(STDERR_FILENO, progname); writeln_str_uint(STDERR_FILENO, ": keep count increased: ", keep_count); } } if (FD_ISSET(STDIN_FILENO,&rfd)) { r = read(STDIN_FILENO, buf, BUF_SIZE); if (r > 0 && keep) { // reset count on read. keep_count = 0; if (verbose) { write_str(STDERR_FILENO, progname); write_cstr(STDERR_FILENO, ": data received, keep count reseted.\n"); } } if (r > 20) { // ignore packet inferior to 21 bytes, keep alive write(tap, buf, r); } else if (r <= 0) { if (verbose) { write_str(STDERR_FILENO, progname); write_cstr(STDERR_FILENO, ": stdin error.\n"); } return 1; } } if (FD_ISSET(tap,&rfd)) { r = read(tap, buf, BUF_SIZE); if (r > 0) { write(STDOUT_FILENO, buf, r); } else if (r <= 0) { if (verbose) { write_str(STDERR_FILENO, progname); write_cstr(STDERR_FILENO, ": stdout error.\n"); } return 2; } } if (keep && keep_count >= keep) { write_str(STDERR_FILENO, progname); writeln_str_uint(STDERR_FILENO, ": Keep count exceeded ", keep_count); kill(getppid(), SIGPIPE); return 0; } } return 0; }
void rbenv_print_usage(char *command) { redirect_stdout_to_stderr(); run("rbenv-help", strarray("--usage", command, NULL)); }