From patchwork Wed Nov 15 13:45:20 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "its_Giaan (Code Review)" X-Patchwork-Id: 3440 Return-Path: Delivered-To: patchwork@openvpn.net Received: by 2002:a05:7300:3c06:b0:f2:62eb:61c1 with SMTP id e6csp2926189dys; Wed, 15 Nov 2023 05:46:06 -0800 (PST) X-Google-Smtp-Source: AGHT+IEpa/0OqUmed2vTZu2odJ3uY0nHrH3f6bpUFGV/7tBJeuhhUylXgt7e3M5NtCxYuZFmd/8d X-Received: by 2002:a17:90a:a592:b0:280:259:435d with SMTP id b18-20020a17090aa59200b002800259435dmr5133016pjq.4.1700055965758; Wed, 15 Nov 2023 05:46:05 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1700055965; cv=none; d=google.com; s=arc-20160816; b=M6xjrLB4jL/r806RRPUJ6NgVquCIPXdXSUe/5MLBgfGrQmiVm6PUJBu4aHY5j8sbuV NQzYO5uW2XwzOStJaM3/ZBUK/6l2OkV98JKswjpbHvPt4FjCRdVff2DAr4kwPJzKVS9d Kd66+dGPwwhRwXmyDnrOnfZkWKOWu25mHy519e/L9orYYDwUiIlytHC5Rp2/55SGXHU9 kkoEdSwODft+B/xhiOrdxJ5y12t0xRdX9iwT6Xxpgv/sqgbaX+vH/FtTF/dmEqU248ps EEM/o60LZk6ithsc+AH9D4/7Ucgx5jT20oC5om0cw69bkBYMB7C2MtdvEsbPoS+xg1Vw P1wQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=errors-to:cc:reply-to:list-subscribe:list-help:list-post :list-archive:list-unsubscribe:list-id:precedence:subject:user-agent :mime-version:message-id:references:auto-submitted:to:date:from :dkim-signature:dkim-signature:dkim-signature; bh=JjkfwduBwc/beNfkOCYbaLAiDWfnE9hj+oGc9NccHOI=; fh=U7wEyxtwz2o5+UdevFSA47vNeG9knhWH0KV//QhD5a0=; b=o3i9OrkUH6oOPLY9CgQxAl5Mg8HJmYNzEmSvNi3DF6yakxbag9F0vai6F57c9cwCQ6 0VouRufojwImIO/VDwH/SnQY1lwOW1LR+je/iIbs8k0ov88CcJVFU31UvmaqUfFiW+sC IYnBuGKuhYvfkhMycqGxaU7X1CFujy51VHlcj3phe5Irmyvz8HlpJJ2U5++P27JbfXtv HICSjD83EGK64R2lmK7nvLAdPHyakUnaGe/gswCEzuYQkpRtHHnWbGiYhkdtgZBnx7Q3 hG4Yxvy79nXGQRLmXYC0dgifrJ6GZGwDLlqYhqJwDAEXs1Be2dRnWqxyMaFQphvZQQns ORIA== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@sourceforge.net header.s=x header.b="XZLc/kSx"; dkim=neutral (body hash did not verify) header.i=@sf.net header.s=x header.b=nFkhYgoa; dkim=neutral (body hash did not verify) header.i=@openvpn.net header.s=google header.b=cWhHg9gS; spf=pass (google.com: domain of openvpn-devel-bounces@lists.sourceforge.net designates 216.105.38.7 as permitted sender) smtp.mailfrom=openvpn-devel-bounces@lists.sourceforge.net; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=openvpn.net Received: from lists.sourceforge.net (lists.sourceforge.net. [216.105.38.7]) by mx.google.com with ESMTPS id g8-20020a17090a7d0800b00280c9b49738si10170471pjl.84.2023.11.15.05.46.05 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Wed, 15 Nov 2023 05:46:05 -0800 (PST) Received-SPF: pass (google.com: domain of openvpn-devel-bounces@lists.sourceforge.net designates 216.105.38.7 as permitted sender) client-ip=216.105.38.7; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@sourceforge.net header.s=x header.b="XZLc/kSx"; dkim=neutral (body hash did not verify) header.i=@sf.net header.s=x header.b=nFkhYgoa; dkim=neutral (body hash did not verify) header.i=@openvpn.net header.s=google header.b=cWhHg9gS; spf=pass (google.com: domain of openvpn-devel-bounces@lists.sourceforge.net designates 216.105.38.7 as permitted sender) smtp.mailfrom=openvpn-devel-bounces@lists.sourceforge.net; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=openvpn.net Received: from [127.0.0.1] (helo=sfs-ml-1.v29.lw.sourceforge.com) by sfs-ml-1.v29.lw.sourceforge.com with esmtp (Exim 4.95) (envelope-from ) id 1r3GD4-0000Rd-Tg; Wed, 15 Nov 2023 13:45:39 +0000 Received: from [172.30.20.202] (helo=mx.sourceforge.net) by sfs-ml-1.v29.lw.sourceforge.com with esmtps (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.95) (envelope-from ) id 1r3GD3-0000RO-BW for openvpn-devel@lists.sourceforge.net; Wed, 15 Nov 2023 13:45:37 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sourceforge.net; s=x; h=Content-Type:Content-Transfer-Encoding:MIME-Version :Message-ID:Reply-To:References:Subject:List-Unsubscribe:List-Id:Cc:To:Date: From:Sender:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To:List-Help: List-Subscribe:List-Post:List-Owner:List-Archive; bh=bfvwV6co66yuqJaEQO2uxUb59BGzxT4zZxLuLG8bFEQ=; b=XZLc/kSxcmXctlrzGlvqItSPp+ Ye2dNVXB7pSNVKI+4yKwFytgEaqmFi9+6oYiFP+DbOwvWRWdusD9WNJNtfUpUiwRx9L5HH6sxSCNe /fVUfoE+V5/8jqKbUO6HImaNKQnu1sXiJAWlzGvf/IazTQotMUiYmSRfxHygNXcC2tJU=; DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sf.net; s=x ; h=Content-Type:Content-Transfer-Encoding:MIME-Version:Message-ID:Reply-To: References:Subject:List-Unsubscribe:List-Id:Cc:To:Date:From:Sender:Content-ID :Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To: Resent-Cc:Resent-Message-ID:In-Reply-To:List-Help:List-Subscribe:List-Post: List-Owner:List-Archive; bh=bfvwV6co66yuqJaEQO2uxUb59BGzxT4zZxLuLG8bFEQ=; b=n FkhYgoa1B3yDnBiDN1pAVs2pKPrbvffAnu+Z6ybA7mjANcFwkMtUp4/pdDxXN67+O4x+GxbU9eQ9s ulyeW/zDgoZZuE99ZmoVTrYPrR3d7bZjYBKluDJnHbzAvEag+aAaejHKpRM9PG6BjH0fBoTQ/8hfL CHROBC67+vdrc4Ts=; Received: from mail-wm1-f50.google.com ([209.85.128.50]) by sfi-mx-2.v28.lw.sourceforge.com with esmtps (TLS1.2:ECDHE-RSA-AES128-GCM-SHA256:128) (Exim 4.95) id 1r3GCu-0000Oa-9j for openvpn-devel@lists.sourceforge.net; Wed, 15 Nov 2023 13:45:33 +0000 Received: by mail-wm1-f50.google.com with SMTP id 5b1f17b1804b1-4084095722aso56094685e9.1 for ; Wed, 15 Nov 2023 05:45:28 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=openvpn.net; s=google; t=1700055922; x=1700660722; darn=lists.sourceforge.net; h=user-agent:content-disposition:content-transfer-encoding :mime-version:message-id:reply-to:references:subject :list-unsubscribe:list-id:auto-submitted:cc:to:date:from:from:to:cc :subject:date:message-id:reply-to; bh=bfvwV6co66yuqJaEQO2uxUb59BGzxT4zZxLuLG8bFEQ=; b=cWhHg9gSzenaOTmiJdPfnYoJAwxab255JWraGMcg3WEh94SqqMH7W6XtRKIkcfSEOT nl6x0sP/eWrhuyZqJWrcgKCNEDBR8TX1DvDztHv1zBDOxSTpFuoQVxJoH3u/UXmaj7eJ IzMeQ1Hid2XrGjEHr1G9nWE0qr9CKg0N/uh6rlcy2lyIbA5bWGdkeghiEJHm5OpCMWkj nueoftrN78oVBZ5ko5R55CwOg0sDznJ/K5UJEOagQa3qzBqrAnEqCKHUGf/EwT8hmTd8 qXgDVbs00jUazLfxC93IMj9h03VDqmIFnxuvw+WA0UeShIp95oFAJuY0ah8wM3C/NgfT d1Fg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1700055922; x=1700660722; h=user-agent:content-disposition:content-transfer-encoding :mime-version:message-id:reply-to:references:subject :list-unsubscribe:list-id:auto-submitted:cc:to:date:from :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=bfvwV6co66yuqJaEQO2uxUb59BGzxT4zZxLuLG8bFEQ=; b=Y7o34M4XfygVkIlvHqINpkX7Ffw1dKeiJ4X69xXyLfsBJypj4OJA3fHSzFFi/4/6wd DI7cEAfQ38Yx6g9xfCQUUsCkap/D/6xZdYU3rH4BownIAVtjPgVWV8k8IpkX0waxwREf m/bECFHKeLiiZ+dN+zo7an3bTSDdc2GWN5Z2Z8/8KzH6lLNO8Vo8Q94hH2sVFbYj6i71 w1FhL7Sl2I2ao2CGf/3koPU1/cz4G6TrSIU44PkvN2OhLuZhwjwrqNiR0bYteNm3MJir XAtVT3zV6TYgoN0Lb0vYVz0oszwj0f6VJrkC4lmBblFJ6Ssq9lG5w/XiIZVtyQwXQy/n BrDA== X-Gm-Message-State: AOJu0YxnJPoGMKRCXj+tuKLJGfe5t7Uchxt28PrylQ3I/9T7BlS34tbb 2nfItm9yHonq/uSYZbY9qszPHA== X-Received: by 2002:a05:600c:46cf:b0:3f5:fff8:d4f3 with SMTP id q15-20020a05600c46cf00b003f5fff8d4f3mr11252419wmo.7.1700055921064; Wed, 15 Nov 2023 05:45:21 -0800 (PST) Received: from gerrit.openvpn.in (ec2-18-159-0-78.eu-central-1.compute.amazonaws.com. [18.159.0.78]) by smtp.gmail.com with ESMTPSA id be14-20020a05600c1e8e00b00401b242e2e6sm20954153wmb.47.2023.11.15.05.45.20 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 15 Nov 2023 05:45:20 -0800 (PST) From: "ordex (Code Review)" X-Google-Original-From: "ordex (Code Review)" X-Gerrit-PatchSet: 1 Date: Wed, 15 Nov 2023 13:45:20 +0000 To: plaisthos , flichtenheld Auto-Submitted: auto-generated X-Gerrit-MessageType: newchange X-Gerrit-Change-Id: Id2d7957f5950115d9baade4c09fd9679b01f749b X-Gerrit-Change-Number: 441 X-Gerrit-Project: openvpn X-Gerrit-ChangeURL: X-Gerrit-Commit: 6dee68038e066da8a06b02b7c437b2147f110dc9 References: Message-ID: MIME-Version: 1.0 User-Agent: Gerrit/3.8.2 X-Spam-Score: -0.2 (/) X-Spam-Report: Spam detection software, running on the system "util-spamd-1.v13.lw.sourceforge.com", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: Attention is currently required from: flichtenheld, plaisthos. Hello plaisthos, flichtenheld, I'd like you to do a code review. Please visit Content analysis details: (-0.2 points, 6.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/, no trust [209.85.128.50 listed in list.dnswl.org] 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record -0.0 RCVD_IN_MSPIKE_H2 RBL: Average reputation (+2) [209.85.128.50 listed in wl.mailspike.net] -0.0 SPF_PASS SPF: sender matches SPF record 0.0 WEIRD_PORT URI: Uses non-standard port number for HTTP 0.0 HTML_MESSAGE BODY: HTML included in message 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain 0.0 T_KAM_HTML_FONT_INVALID Test for Invalidly Named or Formatted Colors in HTML -0.0 T_SCC_BODY_TEXT_LINE No description available. X-Headers-End: 1r3GCu-0000Oa-9j Subject: [Openvpn-devel] [XL] Change in openvpn[master]: multiproto: move generic event handling code in dedicated files X-BeenThere: openvpn-devel@lists.sourceforge.net X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: a@unstable.cc, arne-openvpn@rfc2549.org, openvpn-devel@lists.sourceforge.net, frank@lichtenheld.com Cc: openvpn-devel Errors-To: openvpn-devel-bounces@lists.sourceforge.net X-getmail-retrieved-from-mailbox: Inbox X-GMAIL-THRID: =?utf-8?q?1782637884688552613?= X-GMAIL-MSGID: =?utf-8?q?1782637884688552613?= X-getmail-filter-classifier: gerrit message type newchange Attention is currently required from: flichtenheld, plaisthos. Hello plaisthos, flichtenheld, I'd like you to do a code review. Please visit http://gerrit.openvpn.net/c/openvpn/+/441?usp=email to review the following change. Change subject: multiproto: move generic event handling code in dedicated files ...................................................................... multiproto: move generic event handling code in dedicated files Introduced multi_io.h and multi_io.c files to centralize all codes related to multiple protocols. Renamed the struct mtcp to struct multi_protocol since it encompasses the event_set used by the parent context in server mode. Several methods have also been renamed and moved to fit the multiproto structure: - multi_tcp_init() -> multi_protocol_init(); - multi_tcp_free() -> multi_protocol_free(); - multi_tcp_wait() -> multi_protocol_io_wait(); and so forth. Change-Id: Id2d7957f5950115d9baade4c09fd9679b01f749b Signed-off-by: Gianmarco De Gregori --- M CMakeLists.txt M src/openvpn/Makefile.am M src/openvpn/forward.c M src/openvpn/forward.h M src/openvpn/mtcp.c M src/openvpn/mtcp.h M src/openvpn/mudp.c M src/openvpn/multi.c M src/openvpn/multi.h A src/openvpn/multi_io.c A src/openvpn/multi_io.h 11 files changed, 821 insertions(+), 777 deletions(-) git pull ssh://gerrit.openvpn.net:29418/openvpn refs/changes/41/441/1 diff --git a/CMakeLists.txt b/CMakeLists.txt index d21c9bd..ee27465 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -402,6 +402,8 @@ src/openvpn/mudp.h src/openvpn/multi.c src/openvpn/multi.h + src/openvpn/multi_io.c + src/openvpn/multi_io.h src/openvpn/ntlm.c src/openvpn/ntlm.h src/openvpn/occ.c diff --git a/src/openvpn/Makefile.am b/src/openvpn/Makefile.am index 52deef8..17fcb1b 100644 --- a/src/openvpn/Makefile.am +++ b/src/openvpn/Makefile.am @@ -89,6 +89,7 @@ mtu.c mtu.h \ mudp.c mudp.h \ multi.c multi.h \ + multi_io.c multi_io.h \ networking_freebsd.c \ networking_iproute2.c networking_iproute2.h \ networking_sitnl.c networking_sitnl.h \ diff --git a/src/openvpn/forward.c b/src/openvpn/forward.c index ee18f8b..0e5b611 100644 --- a/src/openvpn/forward.c +++ b/src/openvpn/forward.c @@ -2053,7 +2053,7 @@ */ void -get_io_flags_dowork_udp(struct context *c, struct multi_tcp *mtcp, const unsigned int flags) +get_io_flags_dowork_udp(struct context *c, struct multi_protocol *multi_io, const unsigned int flags) { unsigned int socket = 0; unsigned int tuntap = 0; @@ -2064,7 +2064,7 @@ */ if (flags & IOW_WAIT_SIGNAL) { - wait_signal(mtcp->es, (void *)err_shift); + wait_signal(multi_io->es, (void *)err_shift); } if (flags & IOW_TO_LINK) @@ -2156,17 +2156,17 @@ { if (proto_is_dgram(c->c2.link_sockets[i]->info.proto)) { - socket_set(c->c2.link_sockets[i], mtcp->es, socket, + socket_set(c->c2.link_sockets[i], multi_io->es, socket, &c->c2.link_sockets[i]->ev_arg, NULL); } } - mtcp->udp_flags = socket | tuntap; + multi_io->udp_flags = socket | tuntap; } void -get_io_flags_udp(struct context *c, struct multi_tcp *mtcp, const unsigned int flags) +get_io_flags_udp(struct context *c, struct multi_protocol *multi_io, const unsigned int flags) { - mtcp->udp_flags = ES_ERROR; + multi_io->udp_flags = ES_ERROR; if (c->c2.fast_io && (flags & (IOW_TO_TUN | IOW_TO_LINK | IOW_MBUF))) { /* fast path -- only for TUN/TAP/UDP writes */ @@ -2179,7 +2179,7 @@ { ret |= SOCKET_WRITE; } - mtcp->udp_flags = ret; + multi_io->udp_flags = ret; } else { @@ -2205,13 +2205,13 @@ { ret |= TUN_READ; } - mtcp->udp_flags = ret; + multi_io->udp_flags = ret; } else #endif /* ifdef _WIN32 */ { /* slow path - delegate to io_wait_dowork_udp to calculate flags */ - get_io_flags_dowork_udp(c, mtcp, flags); + get_io_flags_dowork_udp(c, multi_io, flags); } } } diff --git a/src/openvpn/forward.h b/src/openvpn/forward.h index 39ac975..a251d04 100644 --- a/src/openvpn/forward.h +++ b/src/openvpn/forward.h @@ -50,7 +50,7 @@ #include "openvpn.h" #include "occ.h" #include "ping.h" -#include "mtcp.h" +#include "multi_io.h" #define IOW_TO_TUN (1<<0) #define IOW_TO_LINK (1<<1) @@ -65,13 +65,19 @@ #define IOW_READ (IOW_READ_TUN|IOW_READ_LINK) + +/* forward declaration */ +/*struct multi_context; + * struct multi_protocol; + * struct context;*/ + extern counter_type link_read_bytes_global; extern counter_type link_write_bytes_global; -void get_io_flags_dowork_udp(struct context *c, struct multi_tcp *mtcp, const unsigned int flags); +void get_io_flags_dowork_udp(struct context *c, struct multi_protocol *multi_io, const unsigned int flags); -void get_io_flags_udp(struct context *c, struct multi_tcp *mtcp, const unsigned int flags); +void get_io_flags_udp(struct context *c, struct multi_protocol *multi_io, const unsigned int flags); void io_wait_dowork(struct context *c, const unsigned int flags); diff --git a/src/openvpn/mtcp.c b/src/openvpn/mtcp.c index 128a375..4efce35 100644 --- a/src/openvpn/mtcp.c +++ b/src/openvpn/mtcp.c @@ -29,6 +29,8 @@ #include "multi.h" #include "forward.h" +#include "mtcp.h" +#include "multi_io.h" #include "memdbg.h" @@ -36,70 +38,7 @@ #include #endif -/* - * Special tags passed to event.[ch] functions - */ -#define MTCP_SOCKET ((void *)1) -#define MTCP_TUN ((void *)2) -#define MTCP_SIG ((void *)3) /* Only on Windows */ -#define MTCP_MANAGEMENT ((void *)4) -#define MTCP_FILE_CLOSE_WRITE ((void *)5) -#define MTCP_DCO ((void *)6) - -struct ta_iow_flags -{ - unsigned int flags; - unsigned int ret; - unsigned int tun; - unsigned int sock; -}; - -#ifdef ENABLE_DEBUG -static const char * -pract(int action) -{ - switch (action) - { - case TA_UNDEF: - return "TA_UNDEF"; - - case TA_SOCKET_READ: - return "TA_SOCKET_READ"; - - case TA_SOCKET_READ_RESIDUAL: - return "TA_SOCKET_READ_RESIDUAL"; - - case TA_SOCKET_WRITE: - return "TA_SOCKET_WRITE"; - - case TA_SOCKET_WRITE_READY: - return "TA_SOCKET_WRITE_READY"; - - case TA_SOCKET_WRITE_DEFERRED: - return "TA_SOCKET_WRITE_DEFERRED"; - - case TA_TUN_READ: - return "TA_TUN_READ"; - - case TA_TUN_WRITE: - return "TA_TUN_WRITE"; - - case TA_INITIAL: - return "TA_INITIAL"; - - case TA_TIMEOUT: - return "TA_TIMEOUT"; - - case TA_TUN_WRITE_TIMEOUT: - return "TA_TUN_WRITE_TIMEOUT"; - - default: - return "?"; - } -} -#endif /* ENABLE_DEBUG */ - -static struct multi_instance * +struct multi_instance * multi_create_instance_tcp(struct multi_context *m, struct link_socket *ls) { struct gc_arena gc = gc_new(); @@ -180,126 +119,19 @@ mbuf_free(mi->tcp_link_out_deferred); } -struct multi_tcp * -multi_tcp_init(int maxevents, int *maxclients) -{ - struct multi_tcp *mtcp; - const int extra_events = BASE_N_EVENTS; - - ASSERT(maxevents >= 1); - ASSERT(maxclients); - - ALLOC_OBJ_CLEAR(mtcp, struct multi_tcp); - mtcp->maxevents = maxevents + extra_events; - mtcp->es = event_set_init(&mtcp->maxevents, 0); - wait_signal(mtcp->es, MTCP_SIG); - ALLOC_ARRAY(mtcp->esr, struct event_set_return, mtcp->maxevents); - *maxclients = max_int(min_int(mtcp->maxevents - extra_events, *maxclients), 1); - msg(D_MULTI_LOW, "MULTI: TCP INIT maxclients=%d maxevents=%d", *maxclients, mtcp->maxevents); - return mtcp; -} - void -multi_tcp_delete_event(struct multi_tcp *mtcp, event_t event) -{ - if (mtcp && mtcp->es) - { - event_del(mtcp->es, event); - } -} - -void -multi_tcp_free(struct multi_tcp *mtcp) -{ - if (mtcp) - { - event_free(mtcp->es); - free(mtcp->esr); - free(mtcp); - } -} - -void -multi_tcp_dereference_instance(struct multi_tcp *mtcp, struct multi_instance *mi) +multi_tcp_dereference_instance(struct multi_protocol *multi_io, struct multi_instance *mi) { struct link_socket *ls = mi->context.c2.link_sockets[0]; if (ls && mi->socket_set_called) { - event_del(mtcp->es, socket_event_handle(ls)); + event_del(multi_io->es, socket_event_handle(ls)); mi->socket_set_called = false; } - mtcp->n_esr = 0; + multi_io->n_esr = 0; } -static inline void -multi_tcp_set_global_rw_flags(struct multi_context *m, struct multi_instance *mi) -{ - if (mi) - { - mi->socket_set_called = true; - socket_set(mi->context.c2.link_sockets[0], - m->mtcp->es, - mbuf_defined(mi->tcp_link_out_deferred) ? EVENT_WRITE : EVENT_READ, - &mi->ev_arg, - &mi->tcp_rwflags); - } -} - -int -multi_tcp_wait(struct context *c, - struct multi_tcp *mtcp) -{ - int status, i; - unsigned int *persistent = &mtcp->tun_rwflags; - - for (i = 0; i < c->c1.link_sockets_num; i++) - { - socket_set_listen_persistent(c->c2.link_sockets[i], mtcp->es, - &c->c2.link_sockets[i]->ev_arg); - } - -#ifdef _WIN32 - if (tuntap_is_wintun(c->c1.tuntap)) - { - if (!tuntap_ring_empty(c->c1.tuntap)) - { - /* there is data in wintun ring buffer, read it immediately */ - mtcp->esr[0].arg = MTCP_TUN; - mtcp->esr[0].rwflags = EVENT_READ; - mtcp->n_esr = 1; - return 1; - } - persistent = NULL; - } -#endif - tun_set(c->c1.tuntap, mtcp->es, EVENT_READ, MTCP_TUN, persistent); -#if defined(TARGET_LINUX) || defined(TARGET_FREEBSD) - dco_event_set(&c->c1.tuntap->dco, mtcp->es, MTCP_DCO); -#endif - -#ifdef ENABLE_MANAGEMENT - if (management) - { - management_socket_set(management, mtcp->es, MTCP_MANAGEMENT, &mtcp->management_persist_flags); - } -#endif - -#ifdef ENABLE_ASYNC_PUSH - /* arm inotify watcher */ - event_ctl(mtcp->es, c->c2.inotify_fd, EVENT_READ, MTCP_FILE_CLOSE_WRITE); -#endif - - status = event_wait(mtcp->es, &c->c2.timeval, mtcp->esr, mtcp->maxevents); - update_time(); - mtcp->n_esr = 0; - if (status > 0) - { - mtcp->n_esr = status; - } - return status; -} - -static inline struct context * +struct context * multi_tcp_context(struct multi_context *m, struct multi_instance *mi) { if (mi) @@ -312,7 +144,7 @@ } } -static bool +bool multi_tcp_process_outgoing_link_ready(struct multi_context *m, struct multi_instance *mi, const unsigned int mpp_flags) { struct mbuf_item item; @@ -336,7 +168,7 @@ return ret; } -static bool +bool multi_tcp_process_outgoing_link(struct multi_context *m, bool defer, const unsigned int mpp_flags) { struct multi_instance *mi = multi_process_outgoing_link_pre(m); @@ -379,566 +211,3 @@ } return ret; } - -static int -multi_tcp_wait_lite(struct multi_context *m, struct multi_instance *mi, const int action, bool *tun_input_pending) -{ - struct context *c = multi_tcp_context(m, mi); - unsigned int looking_for = 0; - - dmsg(D_MULTI_DEBUG, "MULTI TCP: multi_tcp_wait_lite a=%s mi=" ptr_format, - pract(action), - (ptr_type)mi); - - tv_clear(&c->c2.timeval); /* ZERO-TIMEOUT */ - - switch (action) - { - case TA_TUN_READ: - looking_for = TUN_READ; - tun_input_pending = NULL; - io_wait(c, IOW_READ_TUN); - break; - - case TA_SOCKET_READ: - looking_for = SOCKET_READ; - tun_input_pending = NULL; - io_wait(c, IOW_READ_LINK); - break; - - case TA_TUN_WRITE: - looking_for = TUN_WRITE; - tun_input_pending = NULL; - c->c2.timeval.tv_sec = 1; /* For some reason, the Linux 2.2 TUN/TAP driver hits this timeout */ - perf_push(PERF_PROC_OUT_TUN_MTCP); - io_wait(c, IOW_TO_TUN); - perf_pop(); - break; - - case TA_SOCKET_WRITE: - looking_for = SOCKET_WRITE; - io_wait(c, IOW_TO_LINK|IOW_READ_TUN_FORCE); - break; - - default: - msg(M_FATAL, "MULTI TCP: multi_tcp_wait_lite, unhandled action=%d", action); - } - - if (tun_input_pending && (c->c2.event_set_status & TUN_READ)) - { - *tun_input_pending = true; - } - - if (c->c2.event_set_status & looking_for) - { - return action; - } - else - { - switch (action) - { - /* TCP socket output buffer is full */ - case TA_SOCKET_WRITE: - return TA_SOCKET_WRITE_DEFERRED; - - /* TUN device timed out on accepting write */ - case TA_TUN_WRITE: - return TA_TUN_WRITE_TIMEOUT; - } - - return TA_UNDEF; - } -} - -static struct multi_instance * -multi_tcp_dispatch(struct multi_context *m, struct multi_instance *mi, const int action) -{ - const unsigned int mpp_flags = MPP_PRE_SELECT|MPP_RECORD_TOUCH; - struct multi_instance *touched = mi; - m->mpp_touched = &touched; - - dmsg(D_MULTI_DEBUG, "MULTI TCP: multi_tcp_dispatch a=%s mi=" ptr_format, - pract(action), - (ptr_type)mi); - - switch (action) - { - case TA_TUN_READ: - read_incoming_tun(&m->top); - if (!IS_SIG(&m->top)) - { - multi_process_incoming_tun(m, mpp_flags); - } - break; - - case TA_SOCKET_READ: - case TA_SOCKET_READ_RESIDUAL: - ASSERT(mi); - ASSERT(mi->context.c2.link_sockets); - ASSERT(mi->context.c2.link_sockets[0]); - set_prefix(mi); - read_incoming_link(&mi->context, mi->context.c2.link_sockets[0]); - clear_prefix(); - if (!IS_SIG(&mi->context)) - { - multi_process_incoming_link(m, mi, mpp_flags, - mi->context.c2.link_sockets[0]); - if (!IS_SIG(&mi->context)) - { - stream_buf_read_setup(mi->context.c2.link_sockets[0]); - } - } - break; - - case TA_TIMEOUT: - multi_process_timeout(m, mpp_flags); - break; - - case TA_TUN_WRITE: - multi_process_outgoing_tun(m, mpp_flags); - break; - - case TA_TUN_WRITE_TIMEOUT: - multi_process_drop_outgoing_tun(m, mpp_flags); - break; - - case TA_SOCKET_WRITE_READY: - ASSERT(mi); - multi_tcp_process_outgoing_link_ready(m, mi, mpp_flags); - break; - - case TA_SOCKET_WRITE: - multi_tcp_process_outgoing_link(m, false, mpp_flags); - break; - - case TA_SOCKET_WRITE_DEFERRED: - multi_tcp_process_outgoing_link(m, true, mpp_flags); - break; - - case TA_INITIAL: - ASSERT(mi); - multi_tcp_set_global_rw_flags(m, mi); - multi_process_post(m, mi, mpp_flags); - break; - - default: - msg(M_FATAL, "MULTI TCP: multi_tcp_dispatch, unhandled action=%d", action); - } - - m->mpp_touched = NULL; - return touched; -} - -static int -multi_tcp_post(struct multi_context *m, struct multi_instance *mi, const int action) -{ - struct context *c = multi_tcp_context(m, mi); - int newaction = TA_UNDEF; - -#define MTP_NONE 0 -#define MTP_TUN_OUT (1<<0) -#define MTP_LINK_OUT (1<<1) - unsigned int flags = MTP_NONE; - - if (TUN_OUT(c)) - { - flags |= MTP_TUN_OUT; - } - if (LINK_OUT(c)) - { - flags |= MTP_LINK_OUT; - } - - switch (flags) - { - case MTP_TUN_OUT|MTP_LINK_OUT: - case MTP_TUN_OUT: - newaction = TA_TUN_WRITE; - break; - - case MTP_LINK_OUT: - newaction = TA_SOCKET_WRITE; - break; - - case MTP_NONE: - if (mi && sockets_read_residual(c)) - { - newaction = TA_SOCKET_READ_RESIDUAL; - } - else - { - multi_tcp_set_global_rw_flags(m, mi); - } - break; - - default: - { - struct gc_arena gc = gc_new(); - msg(M_FATAL, "MULTI TCP: multi_tcp_post bad state, mi=%s flags=%d", - multi_instance_string(mi, false, &gc), - flags); - gc_free(&gc); - break; - } - } - - dmsg(D_MULTI_DEBUG, "MULTI TCP: multi_tcp_post %s -> %s", - pract(action), - pract(newaction)); - - return newaction; -} - -void -multi_tcp_action(struct multi_context *m, struct multi_instance *mi, int action, bool poll) -{ - bool tun_input_pending = false; - - do - { - dmsg(D_MULTI_DEBUG, "MULTI TCP: multi_tcp_action a=%s p=%d", - pract(action), - poll); - - /* - * If TA_SOCKET_READ_RESIDUAL, it means we still have pending - * input packets which were read by a prior TCP recv. - * - * Otherwise do a "lite" wait, which means we wait with 0 timeout - * on I/O events only related to the current instance, not - * the big list of events. - * - * On our first pass, poll will be false because we already know - * that input is available, and to call io_wait would be redundant. - */ - if (poll && action != TA_SOCKET_READ_RESIDUAL) - { - const int orig_action = action; - action = multi_tcp_wait_lite(m, mi, action, &tun_input_pending); - if (action == TA_UNDEF) - { - msg(M_FATAL, "MULTI TCP: I/O wait required blocking in multi_tcp_action, action=%d", orig_action); - } - } - - /* - * Dispatch the action - */ - struct multi_instance *touched = multi_tcp_dispatch(m, mi, action); - - /* - * Signal received or TCP connection - * reset by peer? - */ - if (touched && IS_SIG(&touched->context)) - { - if (mi == touched) - { - mi = NULL; - } - multi_close_instance_on_signal(m, touched); - } - - - /* - * If dispatch produced any pending output - * for a particular instance, point to - * that instance. - */ - if (m->pending) - { - mi = m->pending; - } - - /* - * Based on the effects of the action, - * such as generating pending output, - * possibly transition to a new action state. - */ - action = multi_tcp_post(m, mi, action); - - /* - * If we are finished processing the original action, - * check if we have any TUN input. If so, transition - * our action state to processing this input. - */ - if (tun_input_pending && action == TA_UNDEF) - { - action = TA_TUN_READ; - mi = NULL; - tun_input_pending = false; - poll = false; - } - else - { - poll = true; - } - - } while (action != TA_UNDEF); -} - -void -multi_tcp_process_io(struct multi_context *m) -{ - struct multi_tcp *mtcp = m->mtcp; - const unsigned int udp_status = mtcp->udp_flags; - const unsigned int mpp_flags = m->top.c2.fast_io - ? (MPP_CONDITIONAL_PRE_SELECT | MPP_CLOSE_ON_SIGNAL) - : (MPP_PRE_SELECT | MPP_CLOSE_ON_SIGNAL); - int i; - - for (i = 0; i < mtcp->n_esr; ++i) - { - struct event_set_return *e = &mtcp->esr[i]; - struct event_arg *ev_arg = (struct event_arg *)e->arg; - - /* incoming data for instance or listening socket? */ - if (e->arg >= MULTI_N) - { - switch (ev_arg->type) - { - struct multi_instance *mi; - - /* react to event on child instance */ - case EVENT_ARG_MULTI_INSTANCE: - if (!ev_arg->u.mi) - { - msg(D_MULTI_ERRORS, "MULTI: mtcp_proc_io: null minstance"); - break; - } - - mi = ev_arg->u.mi; - if (e->rwflags & EVENT_WRITE) - { - multi_tcp_action(m, mi, TA_SOCKET_WRITE_READY, false); - } - else if (e->rwflags & EVENT_READ) - { - multi_tcp_action(m, mi, TA_SOCKET_READ, false); - } - break; - - /* new incoming TCP client attempting to connect? */ - case EVENT_ARG_LINK_SOCKET: - if (!ev_arg->u.ls) - { - msg(D_MULTI_ERRORS, "MULTI: mtcp_proc_io: null socket"); - break; - } - - if (!proto_is_dgram(ev_arg->u.ls->info.proto)) - { - socket_reset_listen_persistent(ev_arg->u.ls); - mi = multi_create_instance_tcp(m, ev_arg->u.ls); - if (mi) - { - multi_tcp_action(m, mi, TA_INITIAL, false); - } - break; - } - else - { - if (e->arg >= MULTI_N) - { - struct event_arg *ev_arg = (struct event_arg *)e->arg; - if (ev_arg->type != EVENT_ARG_LINK_SOCKET) - { - mtcp->udp_flags = ES_ERROR; - msg(D_LINK_ERRORS, - "io_work: non socket event delivered"); - break; - } - } - else - { - ev_arg->pending = true; - } - - if (udp_status & SOCKET_READ) - { - read_incoming_link(&m->top, ev_arg->u.ls); - if (!IS_SIG(&m->top)) - { - multi_process_incoming_link(m, NULL, mpp_flags, - ev_arg->u.ls); - } - } - - while (true) - { - multi_get_timeout(m, &m->top.c2.timeval); - get_io_flags_udp(&m->top, m->mtcp, p2mp_iow_flags(m)); - MULTI_CHECK_SIG(m); - - multi_process_per_second_timers(m); - - if (m->mtcp->udp_flags == ES_TIMEOUT) - { - multi_process_timeout(m, MPP_PRE_SELECT | MPP_CLOSE_ON_SIGNAL); - } - else - { - multi_process_io_udp(m); - MULTI_CHECK_SIG(m); - break; - } - } - break; - } - } - } - else - { -#ifdef ENABLE_MANAGEMENT - if (e->arg == MTCP_MANAGEMENT) - { - ASSERT(management); - management_io(management); - } - else -#endif - /* incoming data on TUN? */ - if (e->arg == MTCP_TUN) - { - if (e->rwflags & EVENT_WRITE) - { - multi_tcp_action(m, NULL, TA_TUN_WRITE, false); - } - else if (e->rwflags & EVENT_READ) - { - multi_tcp_action(m, NULL, TA_TUN_READ, false); - } - } - /* new incoming TCP client attempting to connect? */ - else if (e->arg == MTCP_SOCKET) - { - struct multi_instance *mi; - ASSERT(m->top.c2.link_sockets[0]); - socket_reset_listen_persistent(m->top.c2.link_sockets[0]); - mi = multi_create_instance_tcp(m, m->top.c2.link_sockets[0]); - if (mi) - { - multi_tcp_action(m, mi, TA_INITIAL, false); - } - } -#if defined(ENABLE_DCO) && (defined(TARGET_LINUX) || defined(TARGET_FREEBSD)) - /* incoming data on DCO? */ - else if (e->arg == MTCP_DCO) - { - multi_process_incoming_dco(m); - } -#endif - /* signal received? */ - else if (e->arg == MTCP_SIG) - { - get_signal(&m->top.sig->signal_received); - } -#ifdef ENABLE_ASYNC_PUSH - else if (e->arg == MTCP_FILE_CLOSE_WRITE) - { - multi_process_file_closed(m, MPP_PRE_SELECT | MPP_RECORD_TOUCH); - } -#endif - } - if (IS_SIG(&m->top)) - { - break; - } - } - mtcp->n_esr = 0; - - /* - * Process queued mbuf packets destined for TCP socket - */ - { - struct multi_instance *mi; - while (!IS_SIG(&m->top) && (mi = mbuf_peek(m->mbuf)) != NULL) - { - multi_tcp_action(m, mi, TA_SOCKET_WRITE, true); - } - } -} - -/* - * Top level event loop for single-threaded operation. - * TCP mode. - */ -void -tunnel_server_tcp(struct context *top) -{ - struct multi_context multi; - int status; - - top->mode = CM_TOP; - context_clear_2(top); - - /* initialize top-tunnel instance */ - init_instance_handle_signals(top, top->es, CC_HARD_USR1_TO_HUP); - if (IS_SIG(top)) - { - return; - } - - /* initialize global multi_context object */ - multi_init(&multi, top); - - /* initialize our cloned top object */ - multi_top_init(&multi, top); - - /* initialize management interface */ - init_management_callback_multi(&multi); - - /* finished with initialization */ - initialization_sequence_completed(top, ISC_SERVER); /* --mode server --proto tcp-server */ - -#ifdef ENABLE_ASYNC_PUSH - multi.top.c2.inotify_fd = inotify_init(); - if (multi.top.c2.inotify_fd < 0) - { - msg(D_MULTI_ERRORS | M_ERRNO, "MULTI: inotify_init error"); - } -#endif - - /* per-packet event loop */ - while (true) - { - perf_push(PERF_EVENT_LOOP); - - /* wait on tun/socket list */ - multi_get_timeout(&multi, &multi.top.c2.timeval); - status = multi_tcp_wait(&multi.top, multi.mtcp); - MULTI_CHECK_SIG(&multi); - - /* check on status of coarse timers */ - multi_process_per_second_timers(&multi); - - /* timeout? */ - if (status > 0) - { - /* process the I/O which triggered select */ - /*multi_tcp_process_io(&multi); */ - MULTI_CHECK_SIG(&multi); - } - else if (status == 0) - { - /*multi_tcp_action(&multi, NULL, TA_TIMEOUT, false); */ - } - - perf_pop(); - } - -#ifdef ENABLE_ASYNC_PUSH - close(top->c2.inotify_fd); -#endif - - /* shut down management interface */ - uninit_management_callback(); - - /* save ifconfig-pool */ - multi_ifconfig_pool_persist(&multi, true); - - /* tear down tunnel instance (unless --persist-tun) */ - multi_uninit(&multi); - multi_top_free(&multi); - close_instance(top); -} diff --git a/src/openvpn/mtcp.h b/src/openvpn/mtcp.h index d55bdfd..b8a0191 100644 --- a/src/openvpn/mtcp.h +++ b/src/openvpn/mtcp.h @@ -63,26 +63,23 @@ struct multi_instance; struct context; +struct multi_protocol; -struct multi_tcp *multi_tcp_init(int maxevents, int *maxclients); - -void multi_tcp_free(struct multi_tcp *mtcp); - -void multi_tcp_dereference_instance(struct multi_tcp *mtcp, struct multi_instance *mi); +void multi_tcp_dereference_instance(struct multi_protocol *multi_io, struct multi_instance *mi); bool multi_tcp_instance_specific_init(struct multi_context *m, struct multi_instance *mi); void multi_tcp_instance_specific_free(struct multi_instance *mi); -int multi_tcp_wait(struct context *c, struct multi_tcp *mtcp); +bool multi_tcp_process_outgoing_link(struct multi_context *m, bool defer, const unsigned int mpp_flags); -void multi_tcp_process_io(struct multi_context *m); +bool multi_tcp_process_outgoing_link_ready(struct multi_context *m, struct multi_instance *mi, const unsigned int mpp_flags); -void multi_tcp_action(struct multi_context *m, struct multi_instance *mi, int action, bool poll); - +struct multi_instance *multi_create_instance_tcp(struct multi_context *m, struct link_socket *ls); void multi_tcp_link_out_deferred(struct multi_context *m, struct multi_instance *mi); +struct context *multi_tcp_context(struct multi_context *m, struct multi_instance *mi); /**************************************************************************/ /** @@ -91,9 +88,6 @@ * * @param top - Top-level context structure. */ -void tunnel_server_tcp(struct context *top); - - -void multi_tcp_delete_event(struct multi_tcp *mtcp, event_t event); +/*void tunnel_server_tcp(struct context *top); */ #endif /* ifndef MTCP_H */ diff --git a/src/openvpn/mudp.c b/src/openvpn/mudp.c index 8945a55..d29f7a5 100644 --- a/src/openvpn/mudp.c +++ b/src/openvpn/mudp.c @@ -379,7 +379,7 @@ void multi_process_io_udp(struct multi_context *m) { - unsigned int status = m->mtcp->udp_flags; + unsigned int status = m->multi_io->udp_flags; const unsigned int mpp_flags = m->top.c2.fast_io ? (MPP_CONDITIONAL_PRE_SELECT | MPP_CLOSE_ON_SIGNAL) : (MPP_PRE_SELECT | MPP_CLOSE_ON_SIGNAL); diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c index 108a5a8..b29134e 100644 --- a/src/openvpn/multi.c +++ b/src/openvpn/multi.c @@ -440,7 +440,7 @@ /* * Initialize multi-socket TCP I/O wait object */ - m->mtcp = multi_tcp_init(t->options.max_clients, &m->max_clients); + m->multi_io = multi_protocol_init(t->options.max_clients, &m->max_clients); m->tcp_queue_limit = t->options.tcp_queue_limit; @@ -668,7 +668,7 @@ if (!is_dgram) { - multi_tcp_dereference_instance(m->mtcp, mi); + multi_tcp_dereference_instance(m->multi_io, mi); } mbuf_dereference_instance(m->mbuf, mi); @@ -746,7 +746,7 @@ initial_rate_limit_free(m->initial_rate_limiter); multi_reap_free(m->reaper); mroute_helper_free(m->route_helper); - multi_tcp_free(m->mtcp); + multi_protocol_free(m->multi_io); } } @@ -3997,9 +3997,9 @@ management_delete_event(void *arg, event_t event) { struct multi_context *m = (struct multi_context *) arg; - if (m->mtcp) + if (m->multi_io) { - multi_tcp_delete_event(m->mtcp, event); + multi_protocol_delete_event(m->multi_io, event); } } @@ -4177,7 +4177,7 @@ ASSERT(mi->context.c2.tls_multi->peer_id < m->max_clients); } - +/* Actual multi protocol event loop in server mode */ void tunnel_server_loop(struct multi_context *multi) { @@ -4189,7 +4189,7 @@ /* wait on tun/socket list */ multi_get_timeout(multi, &multi->top.c2.timeval); - status = multi_tcp_wait(&multi->top, multi->mtcp); + status = multi_protocol_io_wait(&multi->top, multi->multi_io); MULTI_CHECK_SIG(multi); /* check on status of coarse timers */ @@ -4199,18 +4199,25 @@ if (status > 0) { /* process the I/O which triggered select */ - multi_tcp_process_io(multi); + multi_protocol_process_io(multi); MULTI_CHECK_SIG(multi); } else if (status == 0) { - multi_tcp_action(multi, NULL, TA_TIMEOUT, false); + multi_protocol_action(multi, NULL, TA_TIMEOUT, false); } perf_pop(); } } +/**************************************************************************/ +/** + * Main event loop for OpenVPN in server mode. + * @ingroup eventloop + * + * @param top - Top-level context structure. + */ void tunnel_server_init(struct context *top) { diff --git a/src/openvpn/multi.h b/src/openvpn/multi.h index 472c2a3..dd7a29c 100644 --- a/src/openvpn/multi.h +++ b/src/openvpn/multi.h @@ -37,6 +37,7 @@ #include "pool.h" #include "mudp.h" #include "mtcp.h" +#include "multi_io.h" #include "perf.h" #include "vlan.h" #include "reflect_filter.h" @@ -169,8 +170,8 @@ struct mbuf_set *mbuf; /**< Set of buffers for passing data * channel packets between VPN tunnel * instances. */ - struct multi_tcp *mtcp; /**< State specific to OpenVPN using TCP - * as external transport. */ + struct multi_protocol *multi_io; /**< State specific to OpenVPN using both TCP + * and UDP as external transport. */ struct ifconfig_pool *ifconfig_pool; struct frequency_limit *new_connection_limiter; struct initial_packet_rate_limit *initial_rate_limiter; diff --git a/src/openvpn/multi_io.c b/src/openvpn/multi_io.c new file mode 100644 index 0000000..a1ea7fb --- /dev/null +++ b/src/openvpn/multi_io.c @@ -0,0 +1,687 @@ +/* + * OpenVPN -- An application to securely tunnel IP networks + * over a single TCP/UDP port, with support for SSL/TLS-based + * session authentication and key exchange, + * packet encryption, packet authentication, and + * packet compression. + * + * Copyright (C) 2002-2023 OpenVPN Inc + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "syshead.h" + +#include "memdbg.h" + +#include "multi.h" +#include "forward.h" +#include "multi_io.h" + +#ifdef HAVE_SYS_INOTIFY_H +#include +#endif + +/* + * Special tags passed to event.[ch] functions + */ +#define MULTI_IO_SOCKET ((void *)1) +#define MULTI_IO_TUN ((void *)2) +#define MULTI_IO_SIG ((void *)3) /* Only on Windows */ +#define MULTI_IO_MANAGEMENT ((void *)4) +#define MULTI_IO_FILE_CLOSE_WRITE ((void *)5) +#define MULTI_IO_DCO ((void *)6) + +struct ta_iow_flags +{ + unsigned int flags; + unsigned int ret; + unsigned int tun; + unsigned int sock; +}; + +#ifdef ENABLE_DEBUG +static const char * +pract(int action) +{ + switch (action) + { + case TA_UNDEF: + return "TA_UNDEF"; + + case TA_SOCKET_READ: + return "TA_SOCKET_READ"; + + case TA_SOCKET_READ_RESIDUAL: + return "TA_SOCKET_READ_RESIDUAL"; + + case TA_SOCKET_WRITE: + return "TA_SOCKET_WRITE"; + + case TA_SOCKET_WRITE_READY: + return "TA_SOCKET_WRITE_READY"; + + case TA_SOCKET_WRITE_DEFERRED: + return "TA_SOCKET_WRITE_DEFERRED"; + + case TA_TUN_READ: + return "TA_TUN_READ"; + + case TA_TUN_WRITE: + return "TA_TUN_WRITE"; + + case TA_INITIAL: + return "TA_INITIAL"; + + case TA_TIMEOUT: + return "TA_TIMEOUT"; + + case TA_TUN_WRITE_TIMEOUT: + return "TA_TUN_WRITE_TIMEOUT"; + + default: + return "?"; + } +} +#endif /* ENABLE_DEBUG */ + +struct multi_protocol * +multi_protocol_init(int maxevents, int *maxclients) +{ + struct multi_protocol *multi_io; + const int extra_events = BASE_N_EVENTS; + + ASSERT(maxevents >= 1); + ASSERT(maxclients); + + ALLOC_OBJ_CLEAR(multi_io, struct multi_protocol); + multi_io->maxevents = maxevents + extra_events; + multi_io->es = event_set_init(&multi_io->maxevents, 0); + wait_signal(multi_io->es, MULTI_IO_SIG); + ALLOC_ARRAY(multi_io->esr, struct event_set_return, multi_io->maxevents); + *maxclients = max_int(min_int(multi_io->maxevents - extra_events, *maxclients), 1); + msg(D_MULTI_LOW, "MULTI: TCP INIT maxclients=%d maxevents=%d", *maxclients, multi_io->maxevents); + return multi_io; +} + +void +multi_protocol_free(struct multi_protocol *multi_io) +{ + if (multi_io) + { + event_free(multi_io->es); + free(multi_io->esr); + free(multi_io); + } +} + +int +multi_protocol_io_wait(struct context *c, + struct multi_protocol *multi_io) +{ + int status, i; + unsigned int *persistent = &multi_io->tun_rwflags; + + for (i = 0; i < c->c1.link_sockets_num; i++) + { + socket_set_listen_persistent(c->c2.link_sockets[i], multi_io->es, + &c->c2.link_sockets[i]->ev_arg); + } + +#ifdef _WIN32 + if (tuntap_is_wintun(c->c1.tuntap)) + { + if (!tuntap_ring_empty(c->c1.tuntap)) + { + /* there is data in wintun ring buffer, read it immediately */ + multi_io->esr[0].arg = MULTI_IO_TUN; + multi_io->esr[0].rwflags = EVENT_READ; + multi_io->n_esr = 1; + return 1; + } + persistent = NULL; + } +#endif + tun_set(c->c1.tuntap, multi_io->es, EVENT_READ, MULTI_IO_TUN, persistent); +#if defined(TARGET_LINUX) || defined(TARGET_FREEBSD) + dco_event_set(&c->c1.tuntap->dco, multi_io->es, MULTI_IO_DCO); +#endif + +#ifdef ENABLE_MANAGEMENT + if (management) + { + management_socket_set(management, multi_io->es, MULTI_IO_MANAGEMENT, &multi_io->management_persist_flags); + } +#endif + +#ifdef ENABLE_ASYNC_PUSH + /* arm inotify watcher */ + event_ctl(multi_io->es, c->c2.inotify_fd, EVENT_READ, MULTI_IO_FILE_CLOSE_WRITE); +#endif + + status = event_wait(multi_io->es, &c->c2.timeval, multi_io->esr, multi_io->maxevents); + update_time(); + multi_io->n_esr = 0; + if (status > 0) + { + multi_io->n_esr = status; + } + return status; +} + +static int +multi_protocol_wait_lite(struct multi_context *m, struct multi_instance *mi, const int action, bool *tun_input_pending) +{ + struct context *c = multi_tcp_context(m, mi); + unsigned int looking_for = 0; + + dmsg(D_MULTI_DEBUG, "MULTI PROTOCOL: multi_protocol_wait_lite a=%s mi=" ptr_format, + pract(action), + (ptr_type)mi); + + tv_clear(&c->c2.timeval); /* ZERO-TIMEOUT */ + + switch (action) + { + case TA_TUN_READ: + looking_for = TUN_READ; + tun_input_pending = NULL; + io_wait(c, IOW_READ_TUN); + break; + + case TA_SOCKET_READ: + looking_for = SOCKET_READ; + tun_input_pending = NULL; + io_wait(c, IOW_READ_LINK); + break; + + case TA_TUN_WRITE: + looking_for = TUN_WRITE; + tun_input_pending = NULL; + c->c2.timeval.tv_sec = 1; /* For some reason, the Linux 2.2 TUN/TAP driver hits this timeout */ + perf_push(PERF_PROC_OUT_TUN_MTCP); + io_wait(c, IOW_TO_TUN); + perf_pop(); + break; + + case TA_SOCKET_WRITE: + looking_for = SOCKET_WRITE; + io_wait(c, IOW_TO_LINK|IOW_READ_TUN_FORCE); + break; + + default: + msg(M_FATAL, "MULTI PROTOCOL: multi_protocol_wait_lite, unhandled action=%d", action); + } + + if (tun_input_pending && (c->c2.event_set_status & TUN_READ)) + { + *tun_input_pending = true; + } + + if (c->c2.event_set_status & looking_for) + { + return action; + } + else + { + switch (action) + { + /* MULTI PROTOCOL socket output buffer is full */ + case TA_SOCKET_WRITE: + return TA_SOCKET_WRITE_DEFERRED; + + /* TUN device timed out on accepting write */ + case TA_TUN_WRITE: + return TA_TUN_WRITE_TIMEOUT; + } + + return TA_UNDEF; + } +} + +static inline void +multi_protocol_set_global_rw_flags(struct multi_context *m, struct multi_instance *mi) +{ + if (mi) + { + mi->socket_set_called = true; + socket_set(mi->context.c2.link_sockets[0], + m->multi_io->es, + mbuf_defined(mi->tcp_link_out_deferred) ? EVENT_WRITE : EVENT_READ, + &mi->ev_arg, + &mi->tcp_rwflags); + } +} + +static struct multi_instance * +multi_protocol_dispatch(struct multi_context *m, struct multi_instance *mi, const int action) +{ + const unsigned int mpp_flags = MPP_PRE_SELECT|MPP_RECORD_TOUCH; + struct multi_instance *touched = mi; + m->mpp_touched = &touched; + + dmsg(D_MULTI_DEBUG, "MULTI PROTOCOL: multi_protocol_dispatch a=%s mi=" ptr_format, + pract(action), + (ptr_type)mi); + + switch (action) + { + case TA_TUN_READ: + read_incoming_tun(&m->top); + if (!IS_SIG(&m->top)) + { + multi_process_incoming_tun(m, mpp_flags); + } + break; + + case TA_SOCKET_READ: + case TA_SOCKET_READ_RESIDUAL: + ASSERT(mi); + ASSERT(mi->context.c2.link_sockets); + ASSERT(mi->context.c2.link_sockets[0]); + set_prefix(mi); + read_incoming_link(&mi->context, mi->context.c2.link_sockets[0]); + clear_prefix(); + if (!IS_SIG(&mi->context)) + { + multi_process_incoming_link(m, mi, mpp_flags, + mi->context.c2.link_sockets[0]); + if (!IS_SIG(&mi->context)) + { + stream_buf_read_setup(mi->context.c2.link_sockets[0]); + } + } + break; + + case TA_TIMEOUT: + multi_process_timeout(m, mpp_flags); + break; + + case TA_TUN_WRITE: + multi_process_outgoing_tun(m, mpp_flags); + break; + + case TA_TUN_WRITE_TIMEOUT: + multi_process_drop_outgoing_tun(m, mpp_flags); + break; + + case TA_SOCKET_WRITE_READY: + ASSERT(mi); + multi_tcp_process_outgoing_link_ready(m, mi, mpp_flags); + break; + + case TA_SOCKET_WRITE: + multi_tcp_process_outgoing_link(m, false, mpp_flags); + break; + + case TA_SOCKET_WRITE_DEFERRED: + multi_tcp_process_outgoing_link(m, true, mpp_flags); + break; + + case TA_INITIAL: + ASSERT(mi); + multi_protocol_set_global_rw_flags(m, mi); + multi_process_post(m, mi, mpp_flags); + break; + + default: + msg(M_FATAL, "MULTI PROTOCOL: multi_protocol_dispatch, unhandled action=%d", action); + } + + m->mpp_touched = NULL; + return touched; +} + +static int +multi_protocol_post(struct multi_context *m, struct multi_instance *mi, const int action) +{ + struct context *c = multi_tcp_context(m, mi); + int newaction = TA_UNDEF; + +#define MTP_NONE 0 +#define MTP_TUN_OUT (1<<0) +#define MTP_LINK_OUT (1<<1) + unsigned int flags = MTP_NONE; + + if (TUN_OUT(c)) + { + flags |= MTP_TUN_OUT; + } + if (LINK_OUT(c)) + { + flags |= MTP_LINK_OUT; + } + + switch (flags) + { + case MTP_TUN_OUT|MTP_LINK_OUT: + case MTP_TUN_OUT: + newaction = TA_TUN_WRITE; + break; + + case MTP_LINK_OUT: + newaction = TA_SOCKET_WRITE; + break; + + case MTP_NONE: + if (mi && sockets_read_residual(c)) + { + newaction = TA_SOCKET_READ_RESIDUAL; + } + else + { + multi_protocol_set_global_rw_flags(m, mi); + } + break; + + default: + { + struct gc_arena gc = gc_new(); + msg(M_FATAL, "MULTI PROTOCOL: multi_protocol_post bad state, mi=%s flags=%d", + multi_instance_string(mi, false, &gc), + flags); + gc_free(&gc); + break; + } + } + + dmsg(D_MULTI_DEBUG, "MULTI PROTOCOL: multi_protocol_post %s -> %s", + pract(action), + pract(newaction)); + + return newaction; +} + +void +multi_protocol_process_io(struct multi_context *m) +{ + struct multi_protocol *multi_io = m->multi_io; + const unsigned int udp_status = multi_io->udp_flags; + const unsigned int mpp_flags = m->top.c2.fast_io + ? (MPP_CONDITIONAL_PRE_SELECT | MPP_CLOSE_ON_SIGNAL) + : (MPP_PRE_SELECT | MPP_CLOSE_ON_SIGNAL); + int i; + + for (i = 0; i < multi_io->n_esr; ++i) + { + struct event_set_return *e = &multi_io->esr[i]; + struct event_arg *ev_arg = (struct event_arg *)e->arg; + + /* incoming data for instance or listening socket? */ + if (e->arg >= MULTI_N) + { + switch (ev_arg->type) + { + struct multi_instance *mi; + + /* react to event on child instance */ + case EVENT_ARG_MULTI_INSTANCE: + if (!ev_arg->u.mi) + { + msg(D_MULTI_ERRORS, "MULTI PROTOCOL: multi_proto_proc_io: null minstance"); + break; + } + + mi = ev_arg->u.mi; + if (e->rwflags & EVENT_WRITE) + { + multi_protocol_action(m, mi, TA_SOCKET_WRITE_READY, false); + } + else if (e->rwflags & EVENT_READ) + { + multi_protocol_action(m, mi, TA_SOCKET_READ, false); + } + break; + + /* new incoming TCP client attempting to connect? */ + case EVENT_ARG_LINK_SOCKET: + if (!ev_arg->u.ls) + { + msg(D_MULTI_ERRORS, "MULTI PROTOCOL: multi_proto_proc_io: null socket"); + break; + } + + if (!proto_is_dgram(ev_arg->u.ls->info.proto)) + { + socket_reset_listen_persistent(ev_arg->u.ls); + mi = multi_create_instance_tcp(m, ev_arg->u.ls); + if (mi) + { + multi_protocol_action(m, mi, TA_INITIAL, false); + } + break; + } + else + { + if (e->arg >= MULTI_N) + { + struct event_arg *ev_arg = (struct event_arg *)e->arg; + if (ev_arg->type != EVENT_ARG_LINK_SOCKET) + { + multi_io->udp_flags = ES_ERROR; + msg(D_LINK_ERRORS, + "MULTI PROTOCOL: io_work: non socket event delivered"); + break; + } + } + else + { + ev_arg->pending = true; + } + + if (udp_status & SOCKET_READ) + { + read_incoming_link(&m->top, ev_arg->u.ls); + if (!IS_SIG(&m->top)) + { + multi_process_incoming_link(m, NULL, mpp_flags, + ev_arg->u.ls); + } + } + + while (true) + { + multi_get_timeout(m, &m->top.c2.timeval); + get_io_flags_udp(&m->top, m->multi_io, p2mp_iow_flags(m)); + MULTI_CHECK_SIG(m); + + multi_process_per_second_timers(m); + + if (m->multi_io->udp_flags == ES_TIMEOUT) + { + multi_process_timeout(m, MPP_PRE_SELECT | MPP_CLOSE_ON_SIGNAL); + } + else + { + multi_process_io_udp(m); + MULTI_CHECK_SIG(m); + break; + } + } + break; + } + } + } + else + { +#ifdef ENABLE_MANAGEMENT + if (e->arg == MULTI_IO_MANAGEMENT) + { + ASSERT(management); + management_io(management); + } + else +#endif + /* incoming data on TUN? */ + if (e->arg == MULTI_IO_TUN) + { + if (e->rwflags & EVENT_WRITE) + { + multi_protocol_action(m, NULL, TA_TUN_WRITE, false); + } + else if (e->rwflags & EVENT_READ) + { + multi_protocol_action(m, NULL, TA_TUN_READ, false); + } + } + /* new incoming TCP client attempting to connect? */ + else if (e->arg == MULTI_IO_SOCKET) + { + struct multi_instance *mi; + ASSERT(m->top.c2.link_sockets[0]); + socket_reset_listen_persistent(m->top.c2.link_sockets[0]); + mi = multi_create_instance_tcp(m, m->top.c2.link_sockets[0]); + if (mi) + { + multi_protocol_action(m, mi, TA_INITIAL, false); + } + } +#if defined(ENABLE_DCO) && (defined(TARGET_LINUX) || defined(TARGET_FREEBSD)) + /* incoming data on DCO? */ + else if (e->arg == MULTI_IO_DCO) + { + multi_process_incoming_dco(m); + } +#endif + /* signal received? */ + else if (e->arg == MULTI_IO_SIG) + { + get_signal(&m->top.sig->signal_received); + } +#ifdef ENABLE_ASYNC_PUSH + else if (e->arg == MULTI_IO_FILE_CLOSE_WRITE) + { + multi_process_file_closed(m, MPP_PRE_SELECT | MPP_RECORD_TOUCH); + } +#endif + } + if (IS_SIG(&m->top)) + { + break; + } + } + multi_io->n_esr = 0; + + /* + * Process queued mbuf packets destined for TCP socket + */ + { + struct multi_instance *mi; + while (!IS_SIG(&m->top) && (mi = mbuf_peek(m->mbuf)) != NULL) + { + multi_protocol_action(m, mi, TA_SOCKET_WRITE, true); + } + } +} + +void +multi_protocol_action(struct multi_context *m, struct multi_instance *mi, int action, bool poll) +{ + bool tun_input_pending = false; + + do + { + dmsg(D_MULTI_DEBUG, "MULTI PROTOCOL: multi_protocol_action a=%s p=%d", + pract(action), + poll); + + /* + * If TA_SOCKET_READ_RESIDUAL, it means we still have pending + * input packets which were read by a prior recv. + * + * Otherwise do a "lite" wait, which means we wait with 0 timeout + * on I/O events only related to the current instance, not + * the big list of events. + * + * On our first pass, poll will be false because we already know + * that input is available, and to call io_wait would be redundant. + */ + if (poll && action != TA_SOCKET_READ_RESIDUAL) + { + const int orig_action = action; + action = multi_protocol_wait_lite(m, mi, action, &tun_input_pending); + if (action == TA_UNDEF) + { + msg(M_FATAL, "MULTI PROTOCOL: I/O wait required blocking in multi_protocol_action, action=%d", orig_action); + } + } + + /* + * Dispatch the action + */ + struct multi_instance *touched = multi_protocol_dispatch(m, mi, action); + + /* + * Signal received or connection + * reset by peer? + */ + if (touched && IS_SIG(&touched->context)) + { + if (mi == touched) + { + mi = NULL; + } + multi_close_instance_on_signal(m, touched); + } + + + /* + * If dispatch produced any pending output + * for a particular instance, point to + * that instance. + */ + if (m->pending) + { + mi = m->pending; + } + + /* + * Based on the effects of the action, + * such as generating pending output, + * possibly transition to a new action state. + */ + action = multi_protocol_post(m, mi, action); + + /* + * If we are finished processing the original action, + * check if we have any TUN input. If so, transition + * our action state to processing this input. + */ + if (tun_input_pending && action == TA_UNDEF) + { + action = TA_TUN_READ; + mi = NULL; + tun_input_pending = false; + poll = false; + } + else + { + poll = true; + } + + } while (action != TA_UNDEF); +} + +void +multi_protocol_delete_event(struct multi_protocol *multi_io, event_t event) +{ + if (multi_io && multi_io->es) + { + event_del(multi_io->es, event); + } +} diff --git a/src/openvpn/multi_io.h b/src/openvpn/multi_io.h new file mode 100644 index 0000000..bd27f08 --- /dev/null +++ b/src/openvpn/multi_io.h @@ -0,0 +1,77 @@ +/* + * OpenVPN -- An application to securely tunnel IP networks + * over a single TCP/UDP port, with support for SSL/TLS-based + * session authentication and key exchange, + * packet encryption, packet authentication, and + * packet compression. + * + * Copyright (C) 2002-2023 OpenVPN Inc + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +/* + * Multi-protocol specific code for --mode server + */ + +#ifndef MULTI_IO_H +#define MULTI_IO_H + +#include "event.h" + +/* + * I/O processing States + */ + +#define TA_UNDEF 0 +#define TA_SOCKET_READ 1 +#define TA_SOCKET_READ_RESIDUAL 2 +#define TA_SOCKET_WRITE 3 +#define TA_SOCKET_WRITE_READY 4 +#define TA_SOCKET_WRITE_DEFERRED 5 +#define TA_TUN_READ 6 +#define TA_TUN_WRITE 7 +#define TA_INITIAL 8 +#define TA_TIMEOUT 9 +#define TA_TUN_WRITE_TIMEOUT 10 + +/* + * Extra state info needed for Multi-protocol + */ +struct multi_protocol +{ + struct event_set *es; + struct event_set_return *esr; + int n_esr; + int maxevents; + unsigned int tun_rwflags; + unsigned int udp_flags; +#ifdef ENABLE_MANAGEMENT + unsigned int management_persist_flags; +#endif +}; + +struct multi_protocol *multi_protocol_init(int maxevents, int *maxclients); + +void multi_protocol_free(struct multi_protocol *multi_io); + +int multi_protocol_io_wait(struct context *c, struct multi_protocol *multi_io); + +void multi_protocol_process_io(struct multi_context *m); + +void multi_protocol_action(struct multi_context *m, struct multi_instance *mi, int action, bool poll); + +void multi_protocol_delete_event(struct multi_protocol *multi_io, event_t event); + +#endif /* ifndef MULTI_IO_H */