commit 2dc2b22c1505c67c815a6d601fc3c001602edbb8
| author | 斟酌 鵬兄 <tgckpg@gmail.com> |
| date | 2026-05-28T22:16:25Z |
| subject | Break datagram_route.c into multiple files |
commit 2dc2b22c1505c67c815a6d601fc3c001602edbb8
Author: 斟酌 鵬兄 <tgckpg@gmail.com>
Date: 2026-05-28T22:16:25Z
Break datagram_route.c into multiple files
---
src/{compat_socket.h => compat.h} | 27 +-
src/compat_file.h | 25 --
src/datagram_builtin.c | 111 ++++++
src/datagram_builtin.h | 8 +
src/datagram_client.c | 305 +++++++++++++++
src/datagram_client.h | 37 ++
src/datagram_listener.c | 380 ++++++++++++++++++
src/datagram_listener.h | 9 +
src/datagram_route.c | 795 +-------------------------------------
src/datagram_route.h | 3 +-
src/klog.c | 12 +-
src/proxy_proto_v2.c | 2 +-
src/route.h | 2 +
src/stream_listener.c | 2 +-
src/stream_route.c | 2 +-
src/stream_route.h | 2 +-
16 files changed, 888 insertions(+), 834 deletions(-)
diff --git a/src/compat_socket.h b/src/compat.h
similarity index 56%
rename from src/compat_socket.h
rename to src/compat.h
index abea3a4..573cd16 100644
--- a/src/compat_socket.h
+++ b/src/compat.h
@@ -1,5 +1,5 @@
-#ifndef COMPAT_SOCKET_H
-#define COMPAT_SOCKET_H
+#ifndef COMPAT_H
+#define COMPAT_H
#ifdef _WIN32
@@ -9,10 +9,14 @@
#include <winsock2.h>
#include <ws2tcpip.h>
+#include <process.h>
+#include <direct.h>
+#include <errno.h>
#else
#include <errno.h>
+#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
@@ -31,4 +35,23 @@ static inline int socket_err_is_retriable(int err)
#endif
}
+static inline int compat_getpid(void)
+{
+#ifdef _WIN32
+ return _getpid();
+#else
+ return (int)getpid();
+#endif
+}
+
+static inline int compat_mkdir(const char *path, int mode)
+{
+#ifdef _WIN32
+ (void)mode;
+ return _mkdir(path);
+#else
+ return mkdir(path, mode);
+#endif
+}
+
#endif
diff --git a/src/compat_file.h b/src/compat_file.h
deleted file mode 100644
index 68087ae..0000000
--- a/src/compat_file.h
+++ /dev/null
@@ -1,25 +0,0 @@
-#ifndef COMPAT_FILE_H
-#define COMPAT_FILE_H
-
-#ifdef _WIN32
-#include <direct.h>
-#include <errno.h>
-
-static inline int compat_mkdir(const char *path, int mode)
-{
- (void)mode;
- return _mkdir(path);
-}
-
-#else
-#include <sys/stat.h>
-#include <sys/types.h>
-
-static inline int compat_mkdir(const char *path, mode_t mode)
-{
- return mkdir(path, mode);
-}
-
-#endif
-
-#endif
diff --git a/src/datagram_builtin.c b/src/datagram_builtin.c
new file mode 100644
index 0000000..5390e46
--- /dev/null
+++ b/src/datagram_builtin.c
@@ -0,0 +1,111 @@
+#include <stdio.h>
+#include <string.h>
+
+#include "route.h"
+#include "x_builtins.h"
+#include "datagram_builtin.h"
+
+static const char *datagram_client_addr_string(
+ const struct datagram_client *c,
+ char *buf,
+ size_t buf_len
+) {
+ void *addr;
+ uint16_t port;
+
+ if (c == NULL || buf == NULL || buf_len == 0) {
+ return NULL;
+ }
+
+ switch (c->client_addr.ss_family) {
+ case AF_INET: {
+ const struct sockaddr_in *sin =
+ (const struct sockaddr_in *)&c->client_addr;
+
+ addr = (void *)&sin->sin_addr;
+ port = ntohs(sin->sin_port);
+
+ if (inet_ntop(AF_INET, addr, buf, buf_len) == NULL) {
+ return NULL;
+ }
+
+ break;
+ }
+
+ case AF_INET6: {
+ const struct sockaddr_in6 *sin6 =
+ (const struct sockaddr_in6 *)&c->client_addr;
+
+ addr = (void *)&sin6->sin6_addr;
+ port = ntohs(sin6->sin6_port);
+
+ if (inet_ntop(AF_INET6, addr, buf, buf_len) == NULL) {
+ return NULL;
+ }
+
+ break;
+ }
+
+ default:
+ if (snprintf(buf, buf_len, "unknown") < 0) {
+ return NULL;
+ }
+ return buf;
+ }
+
+ if (snprintf(buf + strlen(buf), buf_len - strlen(buf), ":%u", port) < 0) {
+ return NULL;
+ }
+
+ return buf;
+}
+
+int start_datagram_builtin(struct datagram_client *c)
+{
+ struct x_builtin_request req;
+ struct x_builtin_response res;
+ char client_addr[128];
+ int rc;
+
+ if (c == NULL || c->ctx == NULL || c->ctx->route == NULL) {
+ return -EINVAL;
+ }
+
+ memset(&req, 0, sizeof(req));
+
+ req.builtin = c->ctx->route->upstream.builtin;
+ req.client_addr = datagram_client_addr_string(c, client_addr, sizeof(client_addr));
+
+ rc = x_builtin_handle(&req, &res);
+ if (rc < 0) {
+ return rc;
+ }
+
+ switch (res.action) {
+ case X_BUILTIN_ACTION_CLOSE:
+ if (res.data_len == 0) {
+ return 0;
+ }
+
+ if (sendto(
+ c->ctx->listen_fd,
+ res.data,
+ res.data_len,
+ 0,
+ (const struct sockaddr *)&c->client_addr,
+ c->client_addr_len) < 0) {
+ return -EVUTIL_SOCKET_ERROR();
+ }
+
+ return 0;
+
+ case X_BUILTIN_ACTION_DISCARD:
+ return 0;
+
+ case X_BUILTIN_ACTION_HANG:
+ return 0;
+
+ default:
+ return -EINVAL;
+ }
+}
diff --git a/src/datagram_builtin.h b/src/datagram_builtin.h
new file mode 100644
index 0000000..723b4d4
--- /dev/null
+++ b/src/datagram_builtin.h
@@ -0,0 +1,8 @@
+#ifndef DATAGRAM_BUILTIN_H
+#define DATAGRAM_BUILTIN_H
+
+#include "datagram_client.h"
+
+int start_datagram_builtin(struct datagram_client *c);
+
+#endif
diff --git a/src/datagram_client.c b/src/datagram_client.c
new file mode 100644
index 0000000..011301b
--- /dev/null
+++ b/src/datagram_client.c
@@ -0,0 +1,305 @@
+#include <event2/event.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include "compat.h"
+
+#include "klog.h"
+#include "env.h"
+#include "route.h"
+#include "datagram_client.h"
+
+void free_datagram_client(struct datagram_client *c)
+{
+ if (c == NULL) {
+ return;
+ }
+
+ if (c->ev != NULL) {
+ event_free(c->ev);
+ }
+
+ if (c->fd >= 0) {
+ evutil_closesocket(c->fd);
+ }
+
+ if (c->unix_local_path[0] != '\0') {
+ unlink(c->unix_local_path);
+ }
+
+ free(c);
+}
+
+static int sockaddr_equal(
+ const struct sockaddr_storage *a,
+ socklen_t a_len,
+ const struct sockaddr_storage *b,
+ socklen_t b_len
+) {
+ if (a_len != b_len) {
+ return 0;
+ }
+
+ if (a->ss_family != b->ss_family) {
+ return 0;
+ }
+
+ return memcmp(a, b, (size_t)a_len) == 0;
+}
+
+void cleanup_idle_datagram_clients(struct datagram_route_ctx *ctx)
+{
+ time_t now = time(NULL);
+ struct datagram_client **pp = &ctx->clients;
+
+ while (*pp != NULL) {
+ struct datagram_client *c = *pp;
+
+ if (now - c->last_seen <= ctx->route->opts.idle_timeout_sec) {
+ pp = &c->next;
+ continue;
+ }
+
+ *pp = c->next;
+ c->next = NULL;
+
+ LOG_INFO("udp client expired",
+ "client_family", _LOGV(c->client_addr.ss_family),
+ "client_len", _LOGV(c->client_addr_len)
+ );
+
+ free_datagram_client(c);
+ }
+}
+
+struct datagram_client *find_datagram_client(
+ struct datagram_route_ctx *ctx,
+ const struct sockaddr_storage *addr,
+ socklen_t addr_len
+) {
+ for (struct datagram_client *c = ctx->clients; c != NULL; c = c->next) {
+ if (sockaddr_equal(&c->client_addr, c->client_addr_len, addr, addr_len)) {
+ return c;
+ }
+ }
+
+ return NULL;
+}
+
+static int connect_datagram_upstream(struct datagram_client *c, const struct endpoint *upstream)
+{
+ if (upstream == NULL) {
+ return -EINVAL;
+ }
+
+ switch (upstream->kind) {
+
+ case ENDPOINT_INET: {
+ struct sockaddr_in upstream_addr;
+
+ memset(&upstream_addr, 0, sizeof(upstream_addr));
+ upstream_addr.sin_family = AF_INET;
+ upstream_addr.sin_port = htons(upstream->port);
+
+ if (inet_pton(AF_INET, upstream->host, &upstream_addr.sin_addr) != 1) {
+ return -EINVAL;
+ }
+
+ c->fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (c->fd < 0) {
+ return -EVUTIL_SOCKET_ERROR();
+ }
+
+ if (connect(
+ c->fd,
+ (const struct sockaddr *)&upstream_addr,
+ sizeof(upstream_addr)
+ ) < 0) {
+ return -EVUTIL_SOCKET_ERROR();
+ }
+
+ return 0;
+ }
+
+ case ENDPOINT_UNIX_DGRAM:
+#ifdef _WIN32
+ return -ENOTSUP;
+#else
+ {
+ struct sockaddr_un local_addr;
+ struct sockaddr_un upstream_addr;
+
+ if (upstream->path[0] == '\0') {
+ return -EINVAL;
+ }
+
+ if (strlen(upstream->path) >= sizeof(upstream_addr.sun_path)) {
+ return -ENAMETOOLONG;
+ }
+
+ c->fd = socket(AF_UNIX, SOCK_DGRAM, 0);
+ if (c->fd < 0) {
+ return -EVUTIL_SOCKET_ERROR();
+ }
+
+ memset(&local_addr, 0, sizeof(local_addr));
+ local_addr.sun_family = AF_UNIX;
+
+ // UNIX_DGRAM sock for reply
+ const char *runtime_dir = tinyproxy_runtime_dir();
+
+ int n = snprintf(
+ c->unix_local_path,
+ sizeof(c->unix_local_path),
+ "%s/udp-%ld-%p.sock",
+ runtime_dir,
+ (long)getpid(),
+ (void *)c
+ );
+
+ if (n < 0 || (size_t)n >= sizeof(c->unix_local_path)) {
+ return -ENAMETOOLONG;
+ }
+
+ if (strlen(c->unix_local_path) >= sizeof(local_addr.sun_path)) {
+ return -ENAMETOOLONG;
+ }
+
+ unlink(c->unix_local_path);
+ strcpy(local_addr.sun_path, c->unix_local_path);
+
+ if (bind(
+ c->fd,
+ (const struct sockaddr *)&local_addr,
+ sizeof(local_addr)
+ ) < 0) {
+ return -EVUTIL_SOCKET_ERROR();
+ }
+
+ memset(&upstream_addr, 0, sizeof(upstream_addr));
+ upstream_addr.sun_family = AF_UNIX;
+ strcpy(upstream_addr.sun_path, upstream->path);
+
+ if (connect(
+ c->fd,
+ (const struct sockaddr *)&upstream_addr,
+ sizeof(upstream_addr)
+ ) < 0) {
+ return -EVUTIL_SOCKET_ERROR();
+ }
+
+ return 0;
+ }
+#endif
+
+ default:
+ return -ENOTSUP;
+ }
+}
+
+static void upstream_read_cb(evutil_socket_t fd, short events, void *arg)
+{
+ (void)events;
+
+ struct datagram_client *c = arg;
+ struct datagram_route_ctx *ctx = c->ctx;
+
+ unsigned char buf[UDP_MAX_PACKET];
+
+ for (;;) {
+ ssize_t n = recv(fd, (char *)buf, sizeof(buf), 0);
+ if (n < 0) {
+ int err = EVUTIL_SOCKET_ERROR();
+
+ if (socket_err_is_retriable(err)) {
+ return;
+ }
+
+ LOG_ERROR("udp recvfrom failed",
+ "err", _LOGV(evutil_socket_error_to_string(err))
+ );
+ return;
+ }
+
+ if (n == 0) {
+ return;
+ }
+
+ ssize_t sent = sendto(
+ ctx->listen_fd,
+ (const char *)buf,
+ (size_t)n,
+ 0,
+ (const struct sockaddr *)&c->client_addr,
+ c->client_addr_len
+ );
+
+ if (sent < 0) {
+ int err = EVUTIL_SOCKET_ERROR();
+
+ LOG_ERROR("udp send to client failed",
+ "err", _LOGV(evutil_socket_error_to_string(err))
+ );
+ return;
+ }
+ }
+}
+
+struct datagram_client *create_datagram_client(
+ struct datagram_route_ctx *ctx,
+ const struct sockaddr_storage *client_addr,
+ socklen_t client_addr_len
+) {
+ const struct route *r = ctx->route;
+
+ struct datagram_client *c = calloc(1, sizeof(*c));
+ if (c == NULL) {
+ return NULL;
+ }
+
+ c->ctx = ctx;
+ c->fd = -1;
+ c->client_addr = *client_addr;
+ c->client_addr_len = client_addr_len;
+ c->last_seen = time(NULL);
+
+ int rc = connect_datagram_upstream(c, &r->upstream);
+ if (rc < 0) {
+ LOG_ERROR("udp upstream connect failed",
+ "upstream", _LOGV_ENDPOINT(&r->upstream),
+ "err", _LOGV(evutil_socket_error_to_string(-rc))
+ );
+ free_datagram_client(c);
+ return NULL;
+ }
+
+ if (evutil_make_socket_nonblocking(c->fd) < 0) {
+ LOG_ERROR("evutil_make_socket_nonblocking failed");
+ free_datagram_client(c);
+ return NULL;
+ }
+
+ c->ev = event_new(ctx->base, c->fd, EV_READ | EV_PERSIST, upstream_read_cb, c);
+ if (c->ev == NULL) {
+ LOG_ERROR("event_new failed for udp upstream");
+ free_datagram_client(c);
+ return NULL;
+ }
+
+ if (event_add(c->ev, NULL) < 0) {
+ LOG_ERROR("event_add failed for udp upstream");
+ free_datagram_client(c);
+ return NULL;
+ }
+
+ c->next = ctx->clients;
+ ctx->clients = c;
+
+ LOG_INFO("udp client created",
+ "client_family", _LOGV(c->client_addr.ss_family),
+ "client_len", _LOGV(c->client_addr_len)
+ );
+
+ return c;
+}
+
diff --git a/src/datagram_client.h b/src/datagram_client.h
new file mode 100644
index 0000000..7a6b1f4
--- /dev/null
+++ b/src/datagram_client.h
@@ -0,0 +1,37 @@
+#ifndef DATAGRAM_CLIENT_H
+#define DATAGRAM_CLIENT_H
+
+#include "datagram_route.h"
+
+struct datagram_client {
+ struct datagram_route_ctx *ctx;
+
+ evutil_socket_t fd;
+ struct event *ev;
+
+ char unix_local_path[108];
+
+ struct sockaddr_storage client_addr;
+ socklen_t client_addr_len;
+
+ time_t last_seen;
+
+ struct datagram_client *next;
+};
+
+void cleanup_idle_datagram_clients(struct datagram_route_ctx *ctx);
+void free_datagram_client(struct datagram_client *c);
+
+struct datagram_client *create_datagram_client(
+ struct datagram_route_ctx *ctx,
+ const struct sockaddr_storage *client_addr,
+ socklen_t client_addr_len
+);
+
+struct datagram_client *find_datagram_client(
+ struct datagram_route_ctx *ctx,
+ const struct sockaddr_storage *addr,
+ socklen_t addr_len
+);
+
+#endif
diff --git a/src/datagram_listener.c b/src/datagram_listener.c
new file mode 100644
index 0000000..c8c0d8b
--- /dev/null
+++ b/src/datagram_listener.c
@@ -0,0 +1,380 @@
+#include <event2/event.h>
+
+#include <string.h>
+
+#include "klog.h"
+#include "route.h"
+#include "datagram_listener.h"
+#include "datagram_client.h"
+#include "datagram_builtin.h"
+#include "proxy_proto_v2.h"
+
+static int send_datagram_payload_to_upstream(
+ struct datagram_client *c,
+ const unsigned char *payload,
+ size_t payload_len
+) {
+ struct datagram_route_ctx *ctx = c->ctx;
+ const struct route *r = ctx->route;
+
+ if (!r->opts.proxy_v2) {
+ ssize_t sent = send(c->fd, (const char *)payload, payload_len, 0);
+ if (sent < 0) {
+ return -EVUTIL_SOCKET_ERROR();
+ }
+
+ return 0;
+ }
+
+ if (c->client_addr.ss_family != AF_INET ||
+ ctx->local_addr.ss_family != AF_INET) {
+ LOG_ERROR("PROXY v2 UDP currently only supports IPv4",
+ "client_family", _LOGV(c->client_addr.ss_family),
+ "local_family", _LOGV(ctx->local_addr.ss_family)
+ );
+ return -EAFNOSUPPORT;
+ }
+
+ unsigned char hdr[256];
+ size_t hdr_len = 0;
+
+ int rc = proxy_v2_build(
+ hdr,
+ sizeof(hdr),
+ (const struct sockaddr *)&c->client_addr,
+ c->client_addr_len,
+ (const struct sockaddr *)&ctx->local_addr,
+ ctx->local_addr_len,
+ SOCK_DGRAM,
+ &hdr_len
+ );
+ if (rc != 0) {
+ return rc;
+ }
+
+ if (hdr_len + payload_len > UDP_MAX_PACKET) {
+ return -EMSGSIZE;
+ }
+
+ unsigned char out[UDP_MAX_PACKET];
+
+ memcpy(out, hdr, hdr_len);
+ memcpy(out + hdr_len, payload, payload_len);
+
+ ssize_t sent = send(c->fd, (const char *)out, hdr_len + payload_len, 0);
+ if (sent < 0) {
+ return -EVUTIL_SOCKET_ERROR();
+ }
+
+ return 0;
+}
+
+static void listen_read_cb(evutil_socket_t fd, short events, void *arg)
+{
+ (void)events;
+
+ struct datagram_route_ctx *ctx = arg;
+
+ cleanup_idle_datagram_clients(ctx);
+
+ for (;;) {
+ unsigned char buf[UDP_MAX_PACKET];
+
+ struct sockaddr_storage client_addr;
+ socklen_t client_addr_len = sizeof(client_addr);
+
+ memset(&client_addr, 0, sizeof(client_addr));
+
+ ssize_t n = recvfrom(
+ fd,
+ (char *)buf,
+ sizeof(buf),
+ 0,
+ (struct sockaddr *)&client_addr,
+ &client_addr_len
+ );
+
+ if (n < 0) {
+ int err = EVUTIL_SOCKET_ERROR();
+
+ if (socket_err_is_retriable(err)) {
+ return;
+ }
+
+ LOG_ERROR("udp listen recv failed",
+ "err", _LOGV(evutil_socket_error_to_string(err))
+ );
+ return;
+ }
+
+ if (n == 0) {
+ continue;
+ }
+
+ if (ctx->route->upstream.kind == ENDPOINT_BUILTIN) {
+ struct datagram_client tmp;
+
+ memset(&tmp, 0, sizeof(tmp));
+ tmp.ctx = ctx;
+ tmp.fd = -1;
+ tmp.client_addr = client_addr;
+ tmp.client_addr_len = client_addr_len;
+ tmp.last_seen = time(NULL);
+
+ int rc = start_datagram_builtin(&tmp);
+ if (rc < 0) {
+ LOG_ERROR("udp builtin failed",
+ "err", _LOGV(evutil_socket_error_to_string(-rc))
+ );
+ return;
+ }
+
+ continue;
+ }
+
+ struct datagram_client *c = find_datagram_client(ctx, &client_addr, client_addr_len);
+ if (c == NULL) {
+ c = create_datagram_client(ctx, &client_addr, client_addr_len);
+ if (c == NULL) {
+ return;
+ }
+ }
+
+ c->last_seen = time(NULL);
+
+ int rc = send_datagram_payload_to_upstream(c, buf, (size_t)n);
+ if (rc < 0) {
+ LOG_ERROR("udp send to upstream failed",
+ "err", _LOGV(evutil_socket_error_to_string(-rc))
+ );
+ return;
+ }
+ }
+}
+
+#ifndef _WIN32
+static int bind_unix_datagram_listener(struct datagram_route_ctx *ctx)
+{
+ const struct route *r = ctx->route;
+ const char *path = r->listen.path;
+ struct sockaddr_un listen_addr;
+
+ if (path[0] == '\0') {
+ LOG_ERROR("empty unix datagram listen path",
+ "line", _LOGV(r->line_no),
+ "listen", _LOGV_ENDPOINT(&r->listen));
+ return -EINVAL;
+ }
+
+ if (strlen(path) >= sizeof(listen_addr.sun_path)) {
+ LOG_ERROR("unix datagram listen path too long",
+ "line", _LOGV(r->line_no),
+ "path", _LOGV(path));
+ return -ENAMETOOLONG;
+ }
+
+ memset(&listen_addr, 0, sizeof(listen_addr));
+ listen_addr.sun_family = AF_UNIX;
+ memcpy(listen_addr.sun_path, path, strlen(path) + 1);
+
+ if (unlink(path) < 0 && errno != ENOENT) {
+ LOG_ERROR("failed to remove existing unix datagram listener socket",
+ "line", _LOGV(r->line_no),
+ "path", _LOGV(path),
+ "err", _LOGV(strerror(errno)));
+ return -errno;
+ }
+
+ ctx->listen_fd = socket(AF_UNIX, SOCK_DGRAM, 0);
+ if (ctx->listen_fd < 0) {
+ int err = errno;
+
+ LOG_ERROR("unix datagram listen socket failed",
+ "line", _LOGV(r->line_no),
+ "path", _LOGV(path),
+ "err", _LOGV(strerror(err)));
+ return -err;
+ }
+
+ evutil_make_socket_closeonexec(ctx->listen_fd);
+
+ if (evutil_make_socket_nonblocking(ctx->listen_fd) < 0) {
+ int err = errno;
+
+ LOG_ERROR("evutil_make_socket_nonblocking failed for unix datagram listener",
+ "line", _LOGV(r->line_no),
+ "path", _LOGV(path),
+ "err", _LOGV(strerror(err)));
+ return err ? -err : -EINVAL;
+ }
+
+ if (bind(
+ ctx->listen_fd,
+ (const struct sockaddr *)&listen_addr,
+ sizeof(listen_addr)
+ ) < 0) {
+ int err = errno;
+
+ LOG_ERROR("unix datagram bind failed",
+ "line", _LOGV(r->line_no),
+ "path", _LOGV(path),
+ "err", _LOGV(strerror(err)));
+ return -err;
+ }
+
+ ctx->local_addr_len = sizeof(ctx->local_addr);
+ memset(&ctx->local_addr, 0, sizeof(ctx->local_addr));
+
+ if (getsockname(
+ ctx->listen_fd,
+ (struct sockaddr *)&ctx->local_addr,
+ &ctx->local_addr_len
+ ) < 0) {
+ int err = errno;
+
+ LOG_ERROR("unix datagram getsockname failed",
+ "line", _LOGV(r->line_no),
+ "path", _LOGV(path),
+ "err", _LOGV(strerror(err)));
+ return err ? -err : -EINVAL;
+ }
+
+ ctx->listen_ev = event_new(
+ ctx->base,
+ ctx->listen_fd,
+ EV_READ | EV_PERSIST,
+ listen_read_cb,
+ ctx
+ );
+ if (ctx->listen_ev == NULL) {
+ LOG_ERROR("event_new failed for unix datagram listener",
+ "line", _LOGV(r->line_no),
+ "path", _LOGV(path));
+ return -ENOMEM;
+ }
+
+ if (event_add(ctx->listen_ev, NULL) < 0) {
+ LOG_ERROR("event_add failed for unix datagram listener",
+ "line", _LOGV(r->line_no),
+ "path", _LOGV(path));
+ return -EINVAL;
+ }
+
+ return 0;
+}
+#else
+static int bind_unix_datagram_listener(struct datagram_route_ctx *ctx)
+{
+ (void)ctx;
+ return -ENOTSUP;
+}
+#endif
+
+static int bind_udp_datagram_listener(struct datagram_route_ctx *ctx)
+{
+ const struct route *r = ctx->route;
+ struct sockaddr_in listen_addr;
+ int one = 1;
+
+ memset(&listen_addr, 0, sizeof(listen_addr));
+
+ listen_addr.sin_family = AF_INET;
+ listen_addr.sin_port = htons(r->listen.port);
+
+ if (inet_pton(AF_INET, r->listen.host, &listen_addr.sin_addr) != 1) {
+ LOG_ERROR("invalid udp listen address",
+ "listen", _LOGV_ENDPOINT(&r->listen)
+ );
+ return -EINVAL;
+ }
+
+ ctx->listen_fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (ctx->listen_fd < 0) {
+ int err = EVUTIL_SOCKET_ERROR();
+
+ LOG_ERROR("udp listen socket failed",
+ "err", _LOGV(evutil_socket_error_to_string(err))
+ );
+ return -err;
+ }
+
+ evutil_make_socket_closeonexec(ctx->listen_fd);
+
+ if (evutil_make_socket_nonblocking(ctx->listen_fd) < 0) {
+ LOG_ERROR("evutil_make_socket_nonblocking failed");
+ return -EINVAL;
+ }
+
+ setsockopt(
+ ctx->listen_fd,
+ SOL_SOCKET,
+ SO_REUSEADDR,
+ (const char *)&one,
+ sizeof(one)
+ );
+
+ if (bind(
+ ctx->listen_fd,
+ (const struct sockaddr *)&listen_addr,
+ sizeof(listen_addr)
+ ) < 0) {
+ int err = EVUTIL_SOCKET_ERROR();
+
+ LOG_ERROR("udp bind failed",
+ "err", _LOGV(evutil_socket_error_to_string(err))
+ );
+ return -EADDRINUSE;
+ }
+
+ ctx->local_addr_len = sizeof(ctx->local_addr);
+ memset(&ctx->local_addr, 0, sizeof(ctx->local_addr));
+
+ if (getsockname(
+ ctx->listen_fd,
+ (struct sockaddr *)&ctx->local_addr,
+ &ctx->local_addr_len
+ ) < 0) {
+ int err = EVUTIL_SOCKET_ERROR();
+
+ LOG_ERROR("udp getsockname failed",
+ "err", _LOGV(evutil_socket_error_to_string(err))
+ );
+ return -EINVAL;
+ }
+
+ ctx->listen_ev = event_new(
+ ctx->base,
+ ctx->listen_fd,
+ EV_READ | EV_PERSIST,
+ listen_read_cb,
+ ctx
+ );
+ if (ctx->listen_ev == NULL) {
+ LOG_ERROR("event_new failed for udp listener");
+ return -ENOMEM;
+ }
+
+ if (event_add(ctx->listen_ev, NULL) < 0) {
+ LOG_ERROR("event_add failed for udp listener");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int bind_datagram_listener(struct datagram_route_ctx *ctx)
+{
+ switch (ctx->route->listen.kind) {
+ case ENDPOINT_INET:
+ return bind_udp_datagram_listener(ctx);
+
+ case ENDPOINT_UNIX_DGRAM:
+ return bind_unix_datagram_listener(ctx);
+
+ default:
+ LOG_ERROR("datagram listen protocol not implemented yet",
+ "line", _LOGV(ctx->route->line_no),
+ "listen", _LOGV_ENDPOINT(&ctx->route->listen));
+ return -ENOTSUP;
+ }
+}
diff --git a/src/datagram_listener.h b/src/datagram_listener.h
new file mode 100644
index 0000000..ac876b8
--- /dev/null
+++ b/src/datagram_listener.h
@@ -0,0 +1,9 @@
+#ifndef DATAGRAM_LISTENER_H
+#define DATAGRAM_LISTENER_H
+
+#include "datagram_route.h"
+
+int bind_datagram_listener(struct datagram_route_ctx *ctx);
+void close_datagram_listener(struct datagram_route_ctx *ctx);
+
+#endif
diff --git a/src/datagram_route.c b/src/datagram_route.c
index d715fc9..26204fb 100644
--- a/src/datagram_route.c
+++ b/src/datagram_route.c
@@ -6,580 +6,16 @@
#include <stdlib.h>
#include <string.h>
#include <time.h>
-#include <sys/stat.h>
#include "klog.h"
#include "env.h"
#include "file_conf.h"
-#include "compat_socket.h"
-#include "compat_file.h"
#include "proxy_proto_v2.h"
#include "worker.h"
#include "route.h"
#include "datagram_route.h"
-#include "x_builtins.h"
-
-#define UDP_MAX_PACKET 65535
-
-struct datagram_route_ctx;
-
-struct datagram_client {
- struct datagram_route_ctx *ctx;
-
- evutil_socket_t fd;
- struct event *ev;
-
- char unix_local_path[108];
-
- struct sockaddr_storage client_addr;
- socklen_t client_addr_len;
-
- time_t last_seen;
-
- struct datagram_client *next;
-};
-
-static int sockaddr_equal(
- const struct sockaddr_storage *a,
- socklen_t a_len,
- const struct sockaddr_storage *b,
- socklen_t b_len
-) {
- if (a_len != b_len) {
- return 0;
- }
-
- if (a->ss_family != b->ss_family) {
- return 0;
- }
-
- return memcmp(a, b, (size_t)a_len) == 0;
-}
-
-static void free_datagram_client(struct datagram_client *c)
-{
- if (c == NULL) {
- return;
- }
-
- if (c->ev != NULL) {
- event_free(c->ev);
- }
-
- if (c->fd >= 0) {
- evutil_closesocket(c->fd);
- }
-
- if (c->unix_local_path[0] != '\0') {
- unlink(c->unix_local_path);
- }
-
- free(c);
-}
-
-static void cleanup_idle_datagram_clients(struct datagram_route_ctx *ctx)
-{
- time_t now = time(NULL);
- struct datagram_client **pp = &ctx->clients;
-
- while (*pp != NULL) {
- struct datagram_client *c = *pp;
-
- if (now - c->last_seen <= ctx->route->opts.idle_timeout_sec) {
- pp = &c->next;
- continue;
- }
-
- *pp = c->next;
- c->next = NULL;
-
- LOG_INFO("udp client expired",
- "client_family", _LOGV(c->client_addr.ss_family),
- "client_len", _LOGV(c->client_addr_len)
- );
-
- free_datagram_client(c);
- }
-}
-
-static struct datagram_client *find_datagram_client(
- struct datagram_route_ctx *ctx,
- const struct sockaddr_storage *addr,
- socklen_t addr_len
-) {
- for (struct datagram_client *c = ctx->clients; c != NULL; c = c->next) {
- if (sockaddr_equal(&c->client_addr, c->client_addr_len, addr, addr_len)) {
- return c;
- }
- }
-
- return NULL;
-}
-
-static void upstream_read_cb(evutil_socket_t fd, short events, void *arg)
-{
- (void)events;
-
- struct datagram_client *c = arg;
- struct datagram_route_ctx *ctx = c->ctx;
-
- unsigned char buf[UDP_MAX_PACKET];
-
- for (;;) {
- ssize_t n = recv(fd, (char *)buf, sizeof(buf), 0);
- if (n < 0) {
- int err = EVUTIL_SOCKET_ERROR();
-
- if (socket_err_is_retriable(err)) {
- return;
- }
-
- LOG_ERROR("udp recvfrom failed",
- "err", _LOGV(evutil_socket_error_to_string(err))
- );
- return;
- }
-
- if (n == 0) {
- return;
- }
-
- ssize_t sent = sendto(
- ctx->listen_fd,
- (const char *)buf,
- (size_t)n,
- 0,
- (const struct sockaddr *)&c->client_addr,
- c->client_addr_len
- );
-
- if (sent < 0) {
- int err = EVUTIL_SOCKET_ERROR();
-
- LOG_ERROR("udp send to client failed",
- "err", _LOGV(evutil_socket_error_to_string(err))
- );
- return;
- }
- }
-}
-
-static const char *datagram_client_addr_string(
- const struct datagram_client *c,
- char *buf,
- size_t buf_len
-) {
- void *addr;
- uint16_t port;
-
- if (c == NULL || buf == NULL || buf_len == 0) {
- return NULL;
- }
-
- switch (c->client_addr.ss_family) {
- case AF_INET: {
- const struct sockaddr_in *sin =
- (const struct sockaddr_in *)&c->client_addr;
-
- addr = (void *)&sin->sin_addr;
- port = ntohs(sin->sin_port);
-
- if (inet_ntop(AF_INET, addr, buf, buf_len) == NULL) {
- return NULL;
- }
-
- break;
- }
-
- case AF_INET6: {
- const struct sockaddr_in6 *sin6 =
- (const struct sockaddr_in6 *)&c->client_addr;
-
- addr = (void *)&sin6->sin6_addr;
- port = ntohs(sin6->sin6_port);
-
- if (inet_ntop(AF_INET6, addr, buf, buf_len) == NULL) {
- return NULL;
- }
-
- break;
- }
-
- default:
- if (snprintf(buf, buf_len, "unknown") < 0) {
- return NULL;
- }
- return buf;
- }
-
- if (snprintf(buf + strlen(buf), buf_len - strlen(buf), ":%u", port) < 0) {
- return NULL;
- }
-
- return buf;
-}
-
-static int start_datagram_builtin(struct datagram_client *c)
-{
- struct x_builtin_request req;
- struct x_builtin_response res;
- char client_addr[128];
- int rc;
-
- if (c == NULL || c->ctx == NULL || c->ctx->route == NULL) {
- return -EINVAL;
- }
-
- memset(&req, 0, sizeof(req));
-
- req.builtin = c->ctx->route->upstream.builtin;
- req.client_addr = datagram_client_addr_string(c, client_addr, sizeof(client_addr));
-
- rc = x_builtin_handle(&req, &res);
- if (rc < 0) {
- return rc;
- }
-
- switch (res.action) {
- case X_BUILTIN_ACTION_CLOSE:
- if (res.data_len == 0) {
- return 0;
- }
-
- if (sendto(
- c->ctx->listen_fd,
- res.data,
- res.data_len,
- 0,
- (const struct sockaddr *)&c->client_addr,
- c->client_addr_len) < 0) {
- return -EVUTIL_SOCKET_ERROR();
- }
-
- return 0;
-
- case X_BUILTIN_ACTION_DISCARD:
- return 0;
-
- case X_BUILTIN_ACTION_HANG:
- return 0;
-
- default:
- return -EINVAL;
- }
-}
-
-static int connect_datagram_upstream(struct datagram_client *c, const struct endpoint *upstream)
-{
- if (upstream == NULL) {
- return -EINVAL;
- }
-
- switch (upstream->kind) {
-
- case ENDPOINT_INET: {
- struct sockaddr_in upstream_addr;
-
- memset(&upstream_addr, 0, sizeof(upstream_addr));
- upstream_addr.sin_family = AF_INET;
- upstream_addr.sin_port = htons(upstream->port);
-
- if (inet_pton(AF_INET, upstream->host, &upstream_addr.sin_addr) != 1) {
- return -EINVAL;
- }
-
- c->fd = socket(AF_INET, SOCK_DGRAM, 0);
- if (c->fd < 0) {
- return -EVUTIL_SOCKET_ERROR();
- }
-
- if (connect(
- c->fd,
- (const struct sockaddr *)&upstream_addr,
- sizeof(upstream_addr)
- ) < 0) {
- return -EVUTIL_SOCKET_ERROR();
- }
-
- return 0;
- }
-
- case ENDPOINT_UNIX_DGRAM:
-#ifdef _WIN32
- return -ENOTSUP;
-#else
- {
- struct sockaddr_un local_addr;
- struct sockaddr_un upstream_addr;
-
- if (upstream->path[0] == '\0') {
- return -EINVAL;
- }
-
- if (strlen(upstream->path) >= sizeof(upstream_addr.sun_path)) {
- return -ENAMETOOLONG;
- }
-
- c->fd = socket(AF_UNIX, SOCK_DGRAM, 0);
- if (c->fd < 0) {
- return -EVUTIL_SOCKET_ERROR();
- }
-
- memset(&local_addr, 0, sizeof(local_addr));
- local_addr.sun_family = AF_UNIX;
-
- // UNIX_DGRAM sock for reply
- const char *runtime_dir = tinyproxy_runtime_dir();
-
- int n = snprintf(
- c->unix_local_path,
- sizeof(c->unix_local_path),
- "%s/udp-%ld-%p.sock",
- runtime_dir,
- (long)getpid(),
- (void *)c
- );
-
- if (n < 0 || (size_t)n >= sizeof(c->unix_local_path)) {
- return -ENAMETOOLONG;
- }
-
- if (strlen(c->unix_local_path) >= sizeof(local_addr.sun_path)) {
- return -ENAMETOOLONG;
- }
-
- unlink(c->unix_local_path);
- strcpy(local_addr.sun_path, c->unix_local_path);
-
- if (bind(
- c->fd,
- (const struct sockaddr *)&local_addr,
- sizeof(local_addr)
- ) < 0) {
- return -EVUTIL_SOCKET_ERROR();
- }
-
- memset(&upstream_addr, 0, sizeof(upstream_addr));
- upstream_addr.sun_family = AF_UNIX;
- strcpy(upstream_addr.sun_path, upstream->path);
-
- if (connect(
- c->fd,
- (const struct sockaddr *)&upstream_addr,
- sizeof(upstream_addr)
- ) < 0) {
- return -EVUTIL_SOCKET_ERROR();
- }
-
- return 0;
- }
-#endif
-
- default:
- return -ENOTSUP;
- }
-}
-
-static struct datagram_client *create_datagram_client(
- struct datagram_route_ctx *ctx,
- const struct sockaddr_storage *client_addr,
- socklen_t client_addr_len
-) {
- const struct route *r = ctx->route;
-
- struct datagram_client *c = calloc(1, sizeof(*c));
- if (c == NULL) {
- return NULL;
- }
-
- c->ctx = ctx;
- c->fd = -1;
- c->client_addr = *client_addr;
- c->client_addr_len = client_addr_len;
- c->last_seen = time(NULL);
-
- int rc = connect_datagram_upstream(c, &r->upstream);
- if (rc < 0) {
- LOG_ERROR("udp upstream connect failed",
- "upstream", _LOGV_ENDPOINT(&r->upstream),
- "err", _LOGV(evutil_socket_error_to_string(-rc))
- );
- free_datagram_client(c);
- return NULL;
- }
-
- if (evutil_make_socket_nonblocking(c->fd) < 0) {
- LOG_ERROR("evutil_make_socket_nonblocking failed");
- free_datagram_client(c);
- return NULL;
- }
-
- c->ev = event_new(ctx->base, c->fd, EV_READ | EV_PERSIST, upstream_read_cb, c);
- if (c->ev == NULL) {
- LOG_ERROR("event_new failed for udp upstream");
- free_datagram_client(c);
- return NULL;
- }
-
- if (event_add(c->ev, NULL) < 0) {
- LOG_ERROR("event_add failed for udp upstream");
- free_datagram_client(c);
- return NULL;
- }
-
- c->next = ctx->clients;
- ctx->clients = c;
-
- LOG_INFO("udp client created",
- "client_family", _LOGV(c->client_addr.ss_family),
- "client_len", _LOGV(c->client_addr_len)
- );
-
- return c;
-}
-
-static int send_datagram_payload_to_upstream(
- struct datagram_client *c,
- const unsigned char *payload,
- size_t payload_len
-) {
- struct datagram_route_ctx *ctx = c->ctx;
- const struct route *r = ctx->route;
-
- if (!r->opts.proxy_v2) {
- ssize_t sent = send(c->fd, (const char *)payload, payload_len, 0);
- if (sent < 0) {
- return -EVUTIL_SOCKET_ERROR();
- }
-
- return 0;
- }
-
- if (c->client_addr.ss_family != AF_INET ||
- ctx->local_addr.ss_family != AF_INET) {
- LOG_ERROR("PROXY v2 UDP currently only supports IPv4",
- "client_family", _LOGV(c->client_addr.ss_family),
- "local_family", _LOGV(ctx->local_addr.ss_family)
- );
- return -EAFNOSUPPORT;
- }
-
- unsigned char hdr[256];
- size_t hdr_len = 0;
-
- int rc = proxy_v2_build(
- hdr,
- sizeof(hdr),
- (const struct sockaddr *)&c->client_addr,
- c->client_addr_len,
- (const struct sockaddr *)&ctx->local_addr,
- ctx->local_addr_len,
- SOCK_DGRAM,
- &hdr_len
- );
- if (rc != 0) {
- return rc;
- }
-
- if (hdr_len + payload_len > UDP_MAX_PACKET) {
- return -EMSGSIZE;
- }
-
- unsigned char out[UDP_MAX_PACKET];
-
- memcpy(out, hdr, hdr_len);
- memcpy(out + hdr_len, payload, payload_len);
-
- ssize_t sent = send(c->fd, (const char *)out, hdr_len + payload_len, 0);
- if (sent < 0) {
- return -EVUTIL_SOCKET_ERROR();
- }
-
- return 0;
-}
-
-static void listen_read_cb(evutil_socket_t fd, short events, void *arg)
-{
- (void)events;
-
- struct datagram_route_ctx *ctx = arg;
-
- cleanup_idle_datagram_clients(ctx);
-
- for (;;) {
- unsigned char buf[UDP_MAX_PACKET];
-
- struct sockaddr_storage client_addr;
- socklen_t client_addr_len = sizeof(client_addr);
-
- memset(&client_addr, 0, sizeof(client_addr));
-
- ssize_t n = recvfrom(
- fd,
- (char *)buf,
- sizeof(buf),
- 0,
- (struct sockaddr *)&client_addr,
- &client_addr_len
- );
-
- if (n < 0) {
- int err = EVUTIL_SOCKET_ERROR();
-
- if (socket_err_is_retriable(err)) {
- return;
- }
-
- LOG_ERROR("udp listen recv failed",
- "err", _LOGV(evutil_socket_error_to_string(err))
- );
- return;
- }
-
- if (n == 0) {
- continue;
- }
-
- if (ctx->route->upstream.kind == ENDPOINT_BUILTIN) {
- struct datagram_client tmp;
-
- memset(&tmp, 0, sizeof(tmp));
- tmp.ctx = ctx;
- tmp.fd = -1;
- tmp.client_addr = client_addr;
- tmp.client_addr_len = client_addr_len;
- tmp.last_seen = time(NULL);
-
- int rc = start_datagram_builtin(&tmp);
- if (rc < 0) {
- LOG_ERROR("udp builtin failed",
- "err", _LOGV(evutil_socket_error_to_string(-rc))
- );
- return;
- }
-
- continue;
- }
-
- struct datagram_client *c = find_datagram_client(ctx, &client_addr, client_addr_len);
- if (c == NULL) {
- c = create_datagram_client(ctx, &client_addr, client_addr_len);
- if (c == NULL) {
- return;
- }
- }
-
- c->last_seen = time(NULL);
-
- int rc = send_datagram_payload_to_upstream(c, buf, (size_t)n);
- if (rc < 0) {
- LOG_ERROR("udp send to upstream failed",
- "err", _LOGV(evutil_socket_error_to_string(-rc))
- );
- return;
- }
- }
-}
+#include "datagram_listener.h"
+#include "datagram_client.h"
static int prepare_datagram_route(struct datagram_route_ctx *ctx)
{
@@ -600,233 +36,6 @@ static int prepare_datagram_route(struct datagram_route_ctx *ctx)
return 0;
}
-#ifndef _WIN32
-static int bind_unix_datagram_listener(struct datagram_route_ctx *ctx)
-{
- const struct route *r = ctx->route;
- const char *path = r->listen.path;
- struct sockaddr_un listen_addr;
-
- if (path[0] == '\0') {
- LOG_ERROR("empty unix datagram listen path",
- "line", _LOGV(r->line_no),
- "listen", _LOGV_ENDPOINT(&r->listen));
- return -EINVAL;
- }
-
- if (strlen(path) >= sizeof(listen_addr.sun_path)) {
- LOG_ERROR("unix datagram listen path too long",
- "line", _LOGV(r->line_no),
- "path", _LOGV(path));
- return -ENAMETOOLONG;
- }
-
- memset(&listen_addr, 0, sizeof(listen_addr));
- listen_addr.sun_family = AF_UNIX;
- memcpy(listen_addr.sun_path, path, strlen(path) + 1);
-
- if (unlink(path) < 0 && errno != ENOENT) {
- LOG_ERROR("failed to remove existing unix datagram listener socket",
- "line", _LOGV(r->line_no),
- "path", _LOGV(path),
- "err", _LOGV(strerror(errno)));
- return -errno;
- }
-
- ctx->listen_fd = socket(AF_UNIX, SOCK_DGRAM, 0);
- if (ctx->listen_fd < 0) {
- int err = errno;
-
- LOG_ERROR("unix datagram listen socket failed",
- "line", _LOGV(r->line_no),
- "path", _LOGV(path),
- "err", _LOGV(strerror(err)));
- return -err;
- }
-
- evutil_make_socket_closeonexec(ctx->listen_fd);
-
- if (evutil_make_socket_nonblocking(ctx->listen_fd) < 0) {
- int err = errno;
-
- LOG_ERROR("evutil_make_socket_nonblocking failed for unix datagram listener",
- "line", _LOGV(r->line_no),
- "path", _LOGV(path),
- "err", _LOGV(strerror(err)));
- return err ? -err : -EINVAL;
- }
-
- if (bind(
- ctx->listen_fd,
- (const struct sockaddr *)&listen_addr,
- sizeof(listen_addr)
- ) < 0) {
- int err = errno;
-
- LOG_ERROR("unix datagram bind failed",
- "line", _LOGV(r->line_no),
- "path", _LOGV(path),
- "err", _LOGV(strerror(err)));
- return -err;
- }
-
- ctx->local_addr_len = sizeof(ctx->local_addr);
- memset(&ctx->local_addr, 0, sizeof(ctx->local_addr));
-
- if (getsockname(
- ctx->listen_fd,
- (struct sockaddr *)&ctx->local_addr,
- &ctx->local_addr_len
- ) < 0) {
- int err = errno;
-
- LOG_ERROR("unix datagram getsockname failed",
- "line", _LOGV(r->line_no),
- "path", _LOGV(path),
- "err", _LOGV(strerror(err)));
- return err ? -err : -EINVAL;
- }
-
- ctx->listen_ev = event_new(
- ctx->base,
- ctx->listen_fd,
- EV_READ | EV_PERSIST,
- listen_read_cb,
- ctx
- );
- if (ctx->listen_ev == NULL) {
- LOG_ERROR("event_new failed for unix datagram listener",
- "line", _LOGV(r->line_no),
- "path", _LOGV(path));
- return -ENOMEM;
- }
-
- if (event_add(ctx->listen_ev, NULL) < 0) {
- LOG_ERROR("event_add failed for unix datagram listener",
- "line", _LOGV(r->line_no),
- "path", _LOGV(path));
- return -EINVAL;
- }
-
- return 0;
-}
-#else
-static int bind_unix_datagram_listener(struct datagram_route_ctx *ctx)
-{
- (void)ctx;
- return -ENOTSUP;
-}
-#endif
-
-static int bind_udp_datagram_listener(struct datagram_route_ctx *ctx)
-{
- const struct route *r = ctx->route;
- struct sockaddr_in listen_addr;
- int one = 1;
-
- memset(&listen_addr, 0, sizeof(listen_addr));
-
- listen_addr.sin_family = AF_INET;
- listen_addr.sin_port = htons(r->listen.port);
-
- if (inet_pton(AF_INET, r->listen.host, &listen_addr.sin_addr) != 1) {
- LOG_ERROR("invalid udp listen address",
- "listen", _LOGV_ENDPOINT(&r->listen)
- );
- return -EINVAL;
- }
-
- ctx->listen_fd = socket(AF_INET, SOCK_DGRAM, 0);
- if (ctx->listen_fd < 0) {
- int err = EVUTIL_SOCKET_ERROR();
-
- LOG_ERROR("udp listen socket failed",
- "err", _LOGV(evutil_socket_error_to_string(err))
- );
- return -err;
- }
-
- evutil_make_socket_closeonexec(ctx->listen_fd);
-
- if (evutil_make_socket_nonblocking(ctx->listen_fd) < 0) {
- LOG_ERROR("evutil_make_socket_nonblocking failed");
- return -EINVAL;
- }
-
- setsockopt(
- ctx->listen_fd,
- SOL_SOCKET,
- SO_REUSEADDR,
- (const char *)&one,
- sizeof(one)
- );
-
- if (bind(
- ctx->listen_fd,
- (const struct sockaddr *)&listen_addr,
- sizeof(listen_addr)
- ) < 0) {
- int err = EVUTIL_SOCKET_ERROR();
-
- LOG_ERROR("udp bind failed",
- "err", _LOGV(evutil_socket_error_to_string(err))
- );
- return -EADDRINUSE;
- }
-
- ctx->local_addr_len = sizeof(ctx->local_addr);
- memset(&ctx->local_addr, 0, sizeof(ctx->local_addr));
-
- if (getsockname(
- ctx->listen_fd,
- (struct sockaddr *)&ctx->local_addr,
- &ctx->local_addr_len
- ) < 0) {
- int err = EVUTIL_SOCKET_ERROR();
-
- LOG_ERROR("udp getsockname failed",
- "err", _LOGV(evutil_socket_error_to_string(err))
- );
- return -EINVAL;
- }
-
- ctx->listen_ev = event_new(
- ctx->base,
- ctx->listen_fd,
- EV_READ | EV_PERSIST,
- listen_read_cb,
- ctx
- );
- if (ctx->listen_ev == NULL) {
- LOG_ERROR("event_new failed for udp listener");
- return -ENOMEM;
- }
-
- if (event_add(ctx->listen_ev, NULL) < 0) {
- LOG_ERROR("event_add failed for udp listener");
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int bind_datagram_listener(struct datagram_route_ctx *ctx)
-{
- switch (ctx->route->listen.kind) {
- case ENDPOINT_INET:
- return bind_udp_datagram_listener(ctx);
-
- case ENDPOINT_UNIX_DGRAM:
- return bind_unix_datagram_listener(ctx);
-
- default:
- LOG_ERROR("datagram listen protocol not implemented yet",
- "line", _LOGV(ctx->route->line_no),
- "listen", _LOGV_ENDPOINT(&ctx->route->listen));
- return -ENOTSUP;
- }
-}
-
int start_datagram_route(
struct worker *w,
const struct route *r,
diff --git a/src/datagram_route.h b/src/datagram_route.h
index 97ba6da..9b56c4d 100644
--- a/src/datagram_route.h
+++ b/src/datagram_route.h
@@ -2,7 +2,8 @@
#define DATAGRAM_ROUTE_H
#include <event2/util.h>
-#include "compat_socket.h"
+
+#include "compat.h"
struct event;
struct event_base;
diff --git a/src/klog.c b/src/klog.c
index 36b07b8..c053c03 100644
--- a/src/klog.c
+++ b/src/klog.c
@@ -1,16 +1,10 @@
-#include "klog.h"
-
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
-#include <unistd.h>
-
-#ifdef _WIN32
#include <time.h>
-#else
-#include <time.h>
-#endif
+#include "compat.h"
+#include "klog.h"
#include "route.h"
static int localtime_compat(const time_t *t, struct tm *out)
@@ -119,7 +113,7 @@ void log_at(char sev, const char *file, int line, const char *msg, ...)
sev,
tbuf,
ts.tv_nsec / 1000,
- (long)getpid(),
+ (long)compat_getpid(),
file,
line);
diff --git a/src/proxy_proto_v2.c b/src/proxy_proto_v2.c
index 864e544..e584239 100644
--- a/src/proxy_proto_v2.c
+++ b/src/proxy_proto_v2.c
@@ -1,8 +1,8 @@
#include <errno.h>
#include <stdint.h>
#include <string.h>
+#include "compat.h"
-#include "compat_socket.h"
#include "proxy_proto_v2.h"
static void put_u16(unsigned char *p, uint16_t v)
diff --git a/src/route.h b/src/route.h
index 76b9d0f..12f8d6e 100644
--- a/src/route.h
+++ b/src/route.h
@@ -14,6 +14,8 @@
#define BEV_READ_HIGH_WATER (256 * 1024)
#define BEV_WRITE_RESUME_WATER (128 * 1024)
+#define UDP_MAX_PACKET 65535
+
struct route_options {
bool proxy_v2;
bool keep_alive;
diff --git a/src/stream_listener.c b/src/stream_listener.c
index 00969bf..f6d9b05 100644
--- a/src/stream_listener.c
+++ b/src/stream_listener.c
@@ -1,10 +1,10 @@
#include <event2/listener.h>
#include <string.h>
+#include "compat.h"
#include "klog.h"
#include "route.h"
-#include "compat_socket.h"
#include "stream_listener.h"
#include "stream_conn.h"
diff --git a/src/stream_route.c b/src/stream_route.c
index 87610de..1147540 100644
--- a/src/stream_route.c
+++ b/src/stream_route.c
@@ -1,12 +1,12 @@
#include <stdlib.h>
#include <string.h>
+#include "compat.h"
#include "klog.h"
#include "stream_route.h"
#include "worker.h"
#include "route.h"
#include "stream_listener.h"
-#include "compat_file.h"
int start_stream_route(struct worker *w, const struct route *r,
struct stream_route_ctx *ctx)
diff --git a/src/stream_route.h b/src/stream_route.h
index 44d88a6..d25407b 100644
--- a/src/stream_route.h
+++ b/src/stream_route.h
@@ -5,7 +5,7 @@
#include <event2/bufferevent.h>
#include <event2/util.h>
-#include "compat_socket.h"
+#include "compat.h"
struct worker;
struct route;