On Tue, Jan 21, 2020 at 02:44:35AM +0000, Tom Smyth wrote: > Claudio, > Thanks for this, > I compiled it on Openbsd 6.6 (stable) amd64 > > it compiled without error > > the binary seems to run fine but, > ./tbridge -k /dev/tap0 /dev/tap1 > > runs and displays the usage message and gives an errorlevel of 1 > every time use the -k or -t or -s or -p arguments see terminal > conversation below >
Shit, I added a last minute check and as usual introduced a bug. Line 189 change if (ch != 0) to if (mode != 0) -- :wq Claudio /* * Copyright (c) 2020 Claudio Jeker <clau...@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <sys/types.h> #include <sys/event.h> #include <sys/time.h> #include <err.h> #include <errno.h> #include <fcntl.h> #include <poll.h> #include <pthread.h> #include <signal.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> volatile sig_atomic_t quit; static void do_read(int in, int out) { char buf[2048]; ssize_t n, o; n = read(in, buf, sizeof(buf)); if (n == -1) err(1, "read"); o = write(out, buf, n); if (o == -1) err(1, "read"); if (o != n) errx(1, "short write"); } static void do_poll(int fd[2]) { struct pollfd pfd[2]; int n, i; while (quit == 0) { memset(pfd, 0, sizeof(pfd)); pfd[0].fd = fd[0]; pfd[0].events = POLLIN; pfd[1].fd = fd[1]; pfd[1].events = POLLIN; n = poll(pfd, 2, INFTIM); if (n == -1) err(1, "poll"); if (n == 0) errx(1, "poll: timeout"); for (i = 0; i < 2; i++) { if (pfd[i].revents & POLLIN) do_read(fd[i], fd[(i + 1) & 0x1]); else if (pfd[i].revents & (POLLHUP | POLLERR)) errx(1, "fd %d revents %x", i, pfd[i].revents); } } } static void do_select(int fd[2]) { fd_set readfds; int n, i, maxfd = -1; while (quit == 0) { FD_ZERO(&readfds); for (i = 0; i < 2; i++) { if (fd[i] > maxfd) maxfd = fd[i]; FD_SET(fd[i], &readfds); } n = select(maxfd + 1, &readfds, NULL, NULL, NULL); if (n == -1) err(1, "select"); if (n == 0) errx(1, "select: timeout"); for (i = 0; i < 2; i++) { if (FD_ISSET(fd[i], &readfds)) do_read(fd[i], fd[(i + 1) & 0x1]); } } } static void do_kqueue(int fd[2]) { struct kevent kev[2]; int kq, i, n; if ((kq = kqueue()) == -1) err(1, "kqueue"); memset(kev, 0, sizeof(kev)); for (i = 0; i < 2; i++) { EV_SET(&kev[i], fd[i], EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, (void *)(intptr_t)i); } if (kevent(kq, kev, 2, NULL, 0, NULL) == -1) err(1, "kevent register"); while (quit == 0) { n = kevent(kq, NULL, 0, kev, 2, NULL); if (n == -1) err(1, "kevent"); if (n == 0) errx(1, "kevent: timeout"); for (i = 0; i < n; i++) { if (kev[i].flags & EV_ERROR) errc(1, kev[i].data, "kevent EV_ERROR"); if (kev[i].filter == EVFILT_READ) { int r = (int)kev[i].udata; do_read(fd[r], fd[(r + 1) & 0x1]); } } } } static void * run_thread(void *arg) { int *fd = arg; while (quit == 0) do_read(fd[0], fd[1]); return NULL; } static void do_thread(int fd[2]) { pthread_t tid; int ret; ret = pthread_create(&tid, NULL, run_thread, fd); if (ret) { errc(1, ret, "pthread_create"); } while (quit == 0) do_read(fd[1], fd[0]); } static void sighdlr(int sig) { quit = 1; } static __dead void usage(void) { fprintf(stderr, "tbridge -k | -p | -s | -t tapA tapB\n"); exit(1); } int main(int argc, char **argv) { int fd[2]; int ch = 0; int mode = 0; while ((ch = getopt(argc, argv, "kpst")) != -1) { switch (ch) { case 'k': case 'p': case 's': case 't': if (mode != 0) usage(); mode = ch; break; default: usage(); } } argc -= optind; argv += optind; if (argc != 2) usage(); signal(SIGTERM, sighdlr); signal(SIGINT, sighdlr); signal(SIGHUP, sighdlr); fd[0] = open(argv[0], O_RDWR); if (fd[0] == -1) err(1, "open %s", argv[1]); fd[1] = open(argv[1], O_RDWR); if (fd[1] == -1) err(1, "open %s", argv[2]); switch (mode) { case 'k': do_kqueue(fd); break; case 'p': do_poll(fd); break; case 's': do_select(fd); break; case 't': do_thread(fd); break; } exit(0); }