/*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2022 Bjoern A. Zeeb * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include static void getaddrport(const char *a, const char *p, struct sockaddr_in *sin) { const char *errstr; long long l; int rc; if (sin->sin_family != AF_INET) errx(EX_SOFTWARE, "Only AF_INET supported currently\n"); rc = inet_pton(sin->sin_family, a, &sin->sin_addr); switch (rc) { case 1: break; case 0: errx(EX_DATAERR, "IPv4 address '%s' not parseable\n", a); /* NOT REACHED */ case -1: err(EX_OSERR, "inet_pton failed\n"); /* NOT REACHED */ default: errx(EX_SOFTWARE, "inet_pton returned %d\n", rc); /* NOT REACHED */ } errstr = NULL; l = strtonum(p, 1, 65535, &errstr); if (l == 0 && errstr != NULL) err(EX_USAGE, "strtonum returned '%s'\n", errstr); sin->sin_port = htons((in_port_t)l); } int main(int argc, char *argv[]) { struct sockaddr_in laddr4, faddr4; int rc, s, sopt; if (argc != 3 && argc != 5) errx(EX_USAGE, "usage: %s [ ]\n", argv[0]); memset(&laddr4, 0, sizeof(laddr4)); laddr4.sin_len = sizeof(laddr4); laddr4.sin_family = AF_INET; memset(&faddr4, 0, sizeof(faddr4)); faddr4.sin_len = sizeof(faddr4); faddr4.sin_family = AF_INET; getaddrport(argv[1], argv[2], &laddr4); if (argc == 5) getaddrport(argv[3], argv[4], &faddr4); s = socket(PF_INET, SOCK_STREAM, 0); if (s == -1) err(EX_UNAVAILABLE, "socket\n"); sopt = 1; rc = setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &sopt, sizeof(sopt)); if (rc == -1) err(EX_UNAVAILABLE, "setsockopt\n"); rc = bind(s, (const struct sockaddr *)&laddr4, sizeof(laddr4)); if (rc == -1) err(EX_UNAVAILABLE, "bind\n"); if (argc == 3) { rc = listen(s, 1000); if (rc == -1) err(EX_UNAVAILABLE, "listen\n"); printf("%s pid %d listening on [%s %u]\n", argv[0], getpid(), inet_ntoa(laddr4.sin_addr), ntohs(laddr4.sin_port)); do { socklen_t flen; flen = sizeof(faddr4); rc = accept(s, (struct sockaddr *)&faddr4, &flen); if (rc == -1) err(EX_UNAVAILABLE, "accept\n"); if (flen == sizeof(faddr4)) printf("%s pid %d accepted [%s %u]\n", argv[0], getpid(), inet_ntoa(faddr4.sin_addr), ntohs(faddr4.sin_port)); else { printf("%s pid %d accepted connection\n", argv[0], getpid()); rc = -1; } } while (rc != -1); } if (argc == 5) { rc = connect(s, (const struct sockaddr *)&faddr4, sizeof(faddr4)); if (rc == -1) err(EX_UNAVAILABLE, "connect\n"); } printf("%s pid %d [%s %u] sleeping 60.\n", argv[0], getpid(), argv[1], ntohs(laddr4.sin_port)); sleep(60); printf("%s pid %d done.\n", argv[0], getpid()); close(s); return (0); }