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);
}

Reply via email to