Commit Diff


commit - ecd6b12a1f94fa609c3f7484f12d4cc8bc5a46f1
commit + cfe57149140baac9bfd1f900a6e6e425e41b6900
blob - e12a0cfb06988605fc631ae39271ed44a52e41d2
blob + ca4a7aa15578c1b5edae7540faa824038de59c42
--- Makefile
+++ Makefile
@@ -4,11 +4,14 @@ VERSION =	0.4
 PROG =		lstun
 DISTNAME =	${PROG}-${VERSION}
 
-HEADERS =	log.h
+HEADERS =	log.h \
+		lstun.h
 
 SOURCES =	compats.c \
 		log.c \
 		lstun.c \
+		splice.c \
+		splice_bev.c \
 		tests.c
 
 OBJS =		${SOURCES:.c=.o}
blob - aa7a9534a58d2c80e103a87a08936d9cfc8eca26
blob + 0adf97437ca6d672a99314a848d308eae7039d08
--- configure
+++ configure
@@ -275,6 +275,7 @@ HAVE_LIBEVENT2=0		# may not be checked
 HAVE_PLEDGE=
 HAVE_PROGRAM_INVOCATION_SHORT_NAME=
 HAVE_PR_SET_NAME=
+HAVE_SO_SPLICE=
 HAVE_STRLCAT=
 HAVE_STRLCPY=
 HAVE_STRTONUM=
@@ -445,6 +446,7 @@ runtest lib_socket	LIB_SOCKET "" "" "-lsocket -lnsl" |
 runtest pledge		PLEDGE				  || true
 runtest program_invocation_short_name	PROGRAM_INVOCATION_SHORT_NAME || true
 runtest PR_SET_NAME	PR_SET_NAME			  || true
+runtest SO_SPLICE	SO_SPLICE			  || true
 runtest static		STATIC "" "-static"		  || true
 runtest strlcat		STRLCAT				  || true
 runtest strlcpy		STRLCPY				  || true
@@ -559,6 +561,7 @@ cat <<EOF
 #define HAVE_PLEDGE ${HAVE_PLEDGE}
 #define HAVE_PROGRAM_INVOCATION_SHORT_NAME ${HAVE_PROGRAM_INVOCATION_SHORT_NAME}
 #define HAVE_PR_SET_NAME ${HAVE_PR_SET_NAME}
+#define HAVE_SO_SPLICE ${HAVE_SO_SPLICE}
 #define HAVE_STRLCAT ${HAVE_STRLCAT}
 #define HAVE_STRLCPY ${HAVE_STRLCPY}
 #define HAVE_STRTONUM ${HAVE_STRTONUM}
blob - 50e49b42d189dc64abe213706e0286c48e7ec44e
blob + f90988dfb32aaa18e6e06ab124a5d6ac0f10c5a0
--- lstun.c
+++ lstun.c
@@ -34,6 +34,7 @@
 #include <unistd.h>
 
 #include "log.h"
+#include "lstun.h"
 
 #define MAXSOCK 32
 #define BACKOFF 1
@@ -66,16 +67,6 @@ pid_t		 ssh_pid = -1;
 
 int		 conn;
 
-struct conn {
-	int			 ntentative;
-	struct timeval		 retry;
-	struct event		 waitev;
-	int			 source;
-	struct bufferevent	*sourcebev;
-	int			 to;
-	struct bufferevent	*tobev;
-};
-
 static void
 sig_handler(int sig, short event, void *data)
 {
@@ -121,6 +112,17 @@ spawn_ssh(void)
 }
 
 static void
+killing_time(int fd, short event, void *data)
+{
+	if (ssh_pid == -1)
+		return;
+
+	log_debug("timeout expired, killing ssh (%d)", ssh_pid);
+	kill(ssh_pid, SIGTERM);
+	ssh_pid = -1;
+}
+
+void
 conn_free(struct conn *c)
 {
 	if (c->sourcebev != NULL)
@@ -136,50 +138,7 @@ conn_free(struct conn *c)
 		close(c->to);
 
 	free(c);
-}
 
-static void
-killing_time(int fd, short event, void *data)
-{
-	if (ssh_pid == -1)
-		return;
-
-	log_debug("timeout expired, killing ssh (%d)", ssh_pid);
-	kill(ssh_pid, SIGTERM);
-	ssh_pid = -1;
-}
-
-static void
-nopcb(struct bufferevent *bev, void *d)
-{
-	return;
-}
-
-static void
-sreadcb(struct bufferevent *bev, void *d)
-{
-	struct conn *c = d;
-
-	bufferevent_write_buffer(c->tobev, EVBUFFER_INPUT(bev));
-}
-
-static void
-treadcb(struct bufferevent *bev, void *d)
-{
-	struct conn *c = d;
-
-	bufferevent_write_buffer(c->sourcebev, EVBUFFER_INPUT(bev));
-}
-
-static void
-errcb(struct bufferevent *bev, short event, void *d)
-{
-	struct conn *c = d;
-
-	log_info("closing connection (event=%x)", event);
-
-	conn_free(c);
-
 	if (--conn == 0) {
 		log_debug("scheduling ssh termination (%llds)",
 		    (long long)timeout.tv_sec);
@@ -264,16 +223,8 @@ try_to_connect(int fd, short event, void *d)
 
 	log_info("connected!");
 
-	c->sourcebev = bufferevent_new(c->source, sreadcb, nopcb, errcb, c);
-	c->tobev = bufferevent_new(c->to, treadcb, nopcb, errcb, c);
-	if (c->sourcebev == NULL || c->tobev == NULL) {
-		log_warn("bufferevent_new");
+	if (conn_splice(c) == -1)
 		conn_free(c);
-		return;
-	}
-
-	bufferevent_enable(c->sourcebev, EV_READ|EV_WRITE);
-	bufferevent_enable(c->tobev, EV_READ|EV_WRITE);
 }
 
 static void
blob - 3ac5d07899463dd2f7686bdb4d644b9b756021fd
blob + 4a4aeb61dc59fbbf52851f5fad6d3a12dc91ab45
--- tests.c
+++ tests.c
@@ -99,6 +99,22 @@ main(void)
 	return 0;
 }
 #endif /* TEST_PR_SET_NAME */
+#if TEST_SO_SPLICE
+#include <sys/socket.h>
+
+int
+main(void)
+{
+	int src = 0, dst = 1;
+
+	/*
+	 * invalid usage, i'm only interested in checking if it
+	 * compiles
+	 */
+	setsockopt(src, SOL_SOCKET, SO_SPLICE, &dst, sizeof(int));
+	return 0;
+}
+#endif /* TEST_SO_SPLICE */
 #if TEST_STATIC
 int
 main(void)
blob - /dev/null
blob + c57c79c233526cdcfb89e7f7761c0b94b4b75dad (mode 644)
--- /dev/null
+++ lstun.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2022 Omar Polo <op@omarpolo.com>
+ *
+ * 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.
+ */
+
+struct conn {
+	int			 ntentative;
+	struct timeval		 retry;
+	struct event		 waitev;
+	int			 source;
+	struct bufferevent	*sourcebev;
+	int			 to;
+	struct bufferevent	*tobev;
+};
+
+int		conn_splice(struct conn *);
+void		conn_free(struct conn *);
blob - /dev/null
blob + ad33ac746ebe2a3cb533e1c25e26f9742c81277f (mode 644)
--- /dev/null
+++ splice.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2022 Omar Polo <op@omarpolo.com>
+ *
+ * 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 "config.h"
+
+#if HAVE_SO_SPLICE
+
+#include <sys/socket.h>
+
+#include "log.h"
+#include "lstun.h"
+
+static void
+splice_done(int fd, short ev, void *data)
+{
+	struct conn *c = data;
+
+	log_info("closing connection (event=%x)", ev);
+	conn_free(c);
+}
+
+int
+conn_splice(struct conn *c)
+{
+	if (setsockopt(c->source, SOL_SOCKET, SO_SPLICE, &c->to, sizeof(int))
+	    == -1)
+		return -1;
+	if (setsockopt(c->to, SOL_SOCKET, SO_SPLICE, &c->source, sizeof(int))
+	    == -1)
+		return -1;
+
+	event_once(c->source, EV_READ, splice_done, c, NULL);
+	return 0;
+}
+
+#endif	/* HAVE_SO_SPLICE */
blob - /dev/null
blob + 63498c504deb7aaca4573c0a1afcf27dfd0c093b (mode 644)
--- /dev/null
+++ splice_bev.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2022 Omar Polo <op@omarpolo.com>
+ *
+ * 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 "config.h"
+
+#if !HAVE_SO_SPLICE
+
+#include <sys/socket.h>
+
+#include "log.h"
+#include "lstun.h"
+
+static void
+nopcb(struct bufferevent *bev, void *d)
+{
+	return;
+}
+
+static void
+sreadcb(struct bufferevent *bev, void *d)
+{
+	struct conn *c = d;
+
+	bufferevent_write_buffer(c->tobev, EVBUFFER_INPUT(bev));
+}
+
+static void
+treadcb(struct bufferevent *bev, void *d)
+{
+	struct conn *c = d;
+
+	bufferevent_write_buffer(c->sourcebev, EVBUFFER_INPUT(bev));
+}
+
+static void
+errcb(struct bufferevent *bev, short event, void *d)
+{
+	struct conn *c = d;
+
+	log_info("closing connection (event=%x)", event);
+	conn_free(c);
+}
+
+int
+conn_splice(struct conn *c)
+{
+	c->sourcebev = bufferevent_new(c->source, sreadcb, nopcb, errcb, c);
+	c->tobev = bufferevent_new(c->to, treadcb, nopcb, errcb, c);
+
+	if (c->sourcebev == NULL || c->tobev == NULL) {
+		log_warn("bufferevent_new");
+		return -1;
+	}
+
+	bufferevent_enable(c->sourcebev, EV_READ|EV_WRITE);
+	bufferevent_enable(c->tobev, EV_READ|EV_WRITE);
+	return 0;
+}
+
+#endif	/* !HAVE_SO_SPLICE */