From 94e5b8aa269c34c3e8486108b3ddfe7d9b0171be Mon Sep 17 00:00:00 2001 From: zfl9 Date: Mon, 17 Apr 2023 20:14:55 +0800 Subject: [PATCH] try fix #122 #123 #124 issues --- dnl.c | 6 ++--- ipset.c | 4 ++-- main.c | 6 +++-- net.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ net.h | 8 +++++++ 5 files changed, 90 insertions(+), 7 deletions(-) diff --git a/dnl.c b/dnl.c index d42ae00..ae3efc6 100644 --- a/dnl.c +++ b/dnl.c @@ -490,7 +490,7 @@ static void do_debug(u32 gfw_addr0, u32 gfw_n, u32 chn_addr0, u32 chn_n) { } } - /* check map2 hash collisions */ + /* check map2 hash collisions */ if (!map_is_null(&s_map2)) { int maxlen = 0; for (u32 idx = 0, n = map_cap(&s_map2); idx < n; ++idx) { @@ -579,8 +579,8 @@ u8 get_name_tag(const char *noalias name, int namelen) { assert(n > 0); u8 name_tag; - for (int i = 0; i < n; ++i) { - if (exists_in_dnl(sub_names[i], sub_namelens[i], &name_tag)) + while (--n >= 0) { + if (exists_in_dnl(sub_names[n], sub_namelens[n], &name_tag)) return name_tag; } diff --git a/ipset.c b/ipset.c index cd7b33a..b6466bd 100644 --- a/ipset.c +++ b/ipset.c @@ -466,7 +466,7 @@ void ipset_init(void) { static inline int send_req(int n_msg) { assert(n_msg > 0); assert(n_msg <= MSG_N); - int n_sent = sendall(sendmmsg, s_sock, s_msgv, n_msg, 0); + int n_sent = sendall(x_sendmmsg, s_sock, s_msgv, n_msg, 0); assert(n_sent != 0); unlikely_if (n_sent != n_msg) log_error("failed to send nlmsg: %d != %d, (%d) %s", n_sent, n_msg, errno, strerror(errno)); @@ -477,7 +477,7 @@ static inline int send_req(int n_msg) { static inline int recv_res(int n_msg, bool err_if_nomsg) { assert(n_msg > 0); assert(n_msg <= MSG_N); - int n_recv = recvmmsg(s_sock, s_msgv, n_msg, MSG_DONTWAIT, NULL); + int n_recv = x_recvmmsg(s_sock, s_msgv, n_msg, MSG_DONTWAIT, NULL); assert(n_recv != 0); if (n_recv < 0) { /* no-msg or error */ if (errno == EAGAIN || errno == EWOULDBLOCK) diff --git a/main.c b/main.c index ad79a21..5f25ac5 100644 --- a/main.c +++ b/main.c @@ -161,7 +161,7 @@ static void handle_local_packet(void) { log_verbose("forward [%s] to %s (%s)", s_name_buf, g_upstream_addrs[i], is_chinadns_idx(i) ? "chinadns" : "trustdns"); - int n_sent = sendmmsg(s_upstream_sockfds[i], msgv, msg_n, 0); + int n_sent = x_sendmmsg(s_upstream_sockfds[i], msgv, msg_n, 0); unlikely_if (n_sent != msg_n) { if (n_sent < 0) log_error("failed to send query to %s: (%d) %s", g_upstream_addrs[i], errno, strerror(errno)); @@ -325,7 +325,7 @@ static void handle_remote_packet(int index) { } static void handle_timeout_event(struct queryctx *context) { - log_warning("upstream reply timeout, unique msgid: %u", (uint)context->unique_msgid); + log_verbose("upstream reply timeout, unique msgid: %u", (uint)context->unique_msgid); free_context(context); } @@ -334,6 +334,8 @@ int main(int argc, char *argv[]) { setvbuf(stdout, NULL, _IOLBF, 256); opt_parse(argc, argv); + net_init(); + log_info("local listen addr: %s#%u", g_bind_ip, (uint)g_bind_port); if (g_upstream_addrs[CHINADNS1_IDX]) log_info("chinadns server#1: %s", g_upstream_addrs[CHINADNS1_IDX]); diff --git a/net.c b/net.c index d1382e2..507f21d 100644 --- a/net.c +++ b/net.c @@ -1,6 +1,7 @@ #define _GNU_SOURCE #include "net.h" #include "log.h" +#include #include #include #include @@ -11,6 +12,78 @@ #define SO_REUSEPORT 15 #endif +int (*x_recvmmsg)(int sockfd, struct mmsghdr *msgvec, unsigned int vlen, int flags, struct timespec *timeout); + +int (*x_sendmmsg)(int sockfd, struct mmsghdr *msgvec, unsigned int vlen, int flags); + +static int my_recvmmsg(int sockfd, struct mmsghdr *msgvec, unsigned int vlen, int flags, struct timespec *timeout) { + unlikely_if (vlen <= 0 || timeout) { + errno = EINVAL; + return -1; + } + + bool wait_for_one = flags & MSG_WAITFORONE; + flags &= ~MSG_WAITFORONE; + + int nrecv = 0; + + for (uint i = 0; i < vlen; ++i) { + ssize_t res = recvmsg(sockfd, &msgvec[i].msg_hdr, flags); + if (res < 0) break; + + msgvec[i].msg_len = res; + ++nrecv; + + if (wait_for_one) + flags |= MSG_DONTWAIT; + } + + return nrecv ?: -1; +} + +static int my_sendmmsg(int sockfd, struct mmsghdr *msgvec, unsigned int vlen, int flags) { + unlikely_if (vlen <= 0) { + errno = EINVAL; + return -1; + } + + int nsent = 0; + + for (uint i = 0; i < vlen; ++i) { + ssize_t res = sendmsg(sockfd, &msgvec[i].msg_hdr, flags); + if (res < 0) break; + + msgvec[i].msg_len = res; + ++nsent; + } + + return nsent ?: -1; +} + +void net_init(void) { + int res = recvmmsg(-1, NULL, 0, 0, NULL); + assert(res == -1); + (void)res; + + if (errno != ENOSYS) { + x_recvmmsg = recvmmsg; + } else { + log_info("recvmmsg not implemented, use recvmsg to simulate"); + x_recvmmsg = my_recvmmsg; + } + + res = sendmmsg(-1, NULL, 0, 0); + assert(res == -1); + (void)res; + + if (errno != ENOSYS) { + x_sendmmsg = sendmmsg; + } else { + log_info("sendmmsg not implemented, use sendmsg to simulate"); + x_sendmmsg = my_sendmmsg; + } +} + /* setsockopt(IPV6_V6ONLY) */ static inline void set_ipv6_only(int sockfd) { unlikely_if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, &(int){1}, sizeof(int))) { diff --git a/net.h b/net.h index 28ca9db..6244b97 100644 --- a/net.h +++ b/net.h @@ -26,6 +26,14 @@ union skaddr { #define skaddr_is_sin6(p) (skaddr_family(p) == AF_INET6) #define skaddr_size(p) (skaddr_is_sin(p) ? sizeof((p)->sin) : sizeof((p)->sin6)) +/* compatible with old kernel (runtime) */ +extern int (*x_recvmmsg)(int sockfd, struct mmsghdr *msgvec, unsigned int vlen, int flags, struct timespec *timeout); + +/* compatible with old kernel (runtime) */ +extern int (*x_sendmmsg)(int sockfd, struct mmsghdr *msgvec, unsigned int vlen, int flags); + +void net_init(void); + void set_reuse_port(int sockfd); int new_udp_socket(int family);