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/+/440?usp=email to review the following change. Change subject: Using the same wait function for both TCP and UDP ...................................................................... Using the same wait function for both TCP and UDP FORWARD: added a new function to collect UDP flags. MTCP: the mtcp structure has been modified to carry around those flags. The second wait function (in UDP case) has been removed. MULTI: properly remove TCP instances by checking the multi_instance protocol instead of the global one. TLS: set the tls_option xmit_hold bool value to true only in case of TCP child instance to avoid checking the global protocol value. INIT: initialize the c->c2.event_set in the inherit_context_top() by default and not only in case of UDP since we could have multiple different sockets. Change-Id: I81ec69d12abc9a661875c93c7f1bd97e525df55f Signed-off-by: Gianmarco De Gregori <gianma...@mandelbit.com> --- M src/openvpn/forward.c M src/openvpn/forward.h M src/openvpn/init.c M src/openvpn/mtcp.c M src/openvpn/mtcp.h M src/openvpn/mudp.c M src/openvpn/multi.c M src/openvpn/options.c M src/openvpn/options.h 9 files changed, 177 insertions(+), 244 deletions(-) git pull ssh://gerrit.openvpn.net:29418/openvpn refs/changes/40/440/1 diff --git a/src/openvpn/forward.c b/src/openvpn/forward.c index 63a684b..ee18f8b 100644 --- a/src/openvpn/forward.c +++ b/src/openvpn/forward.c @@ -2053,48 +2053,20 @@ */ void -io_wait_dowork_udp(struct context *c, struct multi_tcp *mtcp, const unsigned int flags) +get_io_flags_dowork_udp(struct context *c, struct multi_tcp *mtcp, const unsigned int flags) { unsigned int socket = 0; unsigned int tuntap = 0; - struct event_set_return esr[4]; - - /* These shifts all depend on EVENT_READ and EVENT_WRITE */ - static uintptr_t socket_shift = 0; /* depends on SOCKET_READ and SOCKET_WRITE */ - static uintptr_t tun_shift = 2; /* depends on TUN_READ and TUN_WRITE */ - static uintptr_t err_shift = 4; /* depends on ES_ERROR */ -#ifdef ENABLE_MANAGEMENT - static uintptr_t management_shift = 6; /* depends on MANAGEMENT_READ and MANAGEMENT_WRITE */ -#endif -#ifdef ENABLE_ASYNC_PUSH - static int file_shift = FILE_SHIFT; -#endif -#if defined(TARGET_LINUX) || defined(TARGET_FREEBSD) - static int dco_shift = DCO_SHIFT; /* Event from DCO linux kernel module */ -#endif - int i; + static uintptr_t err_shift = 4; /* - * Decide what kind of events we want to wait for. - */ - /*c->c2.event_set = mtcp->es; */ - /*event_reset(mtcp->es); */ - /*event_reset(c->c2.event_set); */ - - /* - * On win32 we use the keyboard or an event object as a source - * of asynchronous signals. + * Calculate the flags based on the provided 'flags' argument. */ if (flags & IOW_WAIT_SIGNAL) { wait_signal(mtcp->es, (void *)err_shift); } - /* - * If outgoing data (for TCP/UDP port) pending, wait for ready-to-send - * status from TCP/UDP port. Otherwise, wait for incoming data on - * TUN/TAP device. - */ if (flags & IOW_TO_LINK) { if (flags & IOW_SHAPER) @@ -2180,117 +2152,68 @@ /* * Configure event wait based on socket, tuntap flags. */ - for (i = 0; i < c->c1.link_sockets_num; i++) + for (int i = 0; i < c->c1.link_sockets_num; i++) { - socket_set(c->c2.link_sockets[i], mtcp->es, socket, - &c->c2.link_sockets[i]->ev_arg, NULL); - } - tun_set(c->c1.tuntap, c->c2.event_set, tuntap, (void *)tun_shift, NULL); -#if defined(TARGET_LINUX) || defined(TARGET_FREEBSD) - if (socket & EVENT_READ && c->c2.did_open_tun) - { - dco_event_set(&c->c1.tuntap->dco, mtcp->es, (void *)&dco_shift); - } -#endif - -#ifdef ENABLE_MANAGEMENT - if (management) - { - management_socket_set(management, mtcp->es, (void *)management_shift, NULL); - } -#endif - -#ifdef ENABLE_ASYNC_PUSH - /* arm inotify watcher */ - if (c->options.mode == MODE_SERVER) - { - event_ctl(mtcp->es, c->c2.inotify_fd, EVENT_READ, (void *)&file_shift); - } -#endif - - /* - * Possible scenarios: - * (1) tcp/udp port has data available to read - * (2) tcp/udp port is ready to accept more data to write - * (3) tun dev has data available to read - * (4) tun dev is ready to accept more data to write - * (5) we received a signal (handler sets signal_received) - * (6) timeout (tv) expired - */ - - mtcp->event_set_status = ES_ERROR; - - if (!c->sig->signal_received) - { - if (!(flags & IOW_CHECK_RESIDUAL) || !sockets_read_residual(c)) + if (proto_is_dgram(c->c2.link_sockets[i]->info.proto)) { - int status; - -#ifdef ENABLE_DEBUG - if (check_debug_level(D_EVENT_WAIT)) - { - show_wait_status(c); - } -#endif - - /* - * Wait for something to happen. - */ - status = event_wait(mtcp->es, &c->c2.timeval, esr, SIZE(esr)); - - check_status(status, "event_wait", NULL, NULL); - - if (status > 0) - { - /*printf("\nstatus: %d\n", status); */ - int i; - mtcp->event_set_status = 0; - for (i = 0; i < status; ++i) - { - const struct event_set_return *e = &esr[i]; - uintptr_t shift; - - if (e->arg >= MULTI_N) - { - struct event_arg *ev_arg = (struct event_arg *)e->arg; - if (ev_arg->type != EVENT_ARG_LINK_SOCKET) - { - mtcp->event_set_status = ES_ERROR; - msg(D_LINK_ERRORS, - "io_work: non socket event delivered"); - return; - } - - shift = socket_shift; - /* mark socket so that the multi code knows where we - * have pending i/o */ - ev_arg->pending = true; - } - else - { - shift = (uintptr_t)e->arg; - } - - mtcp->event_set_status |= ((e->rwflags & 3) << shift); - } - } - else if (status == 0) - { - mtcp->event_set_status = ES_TIMEOUT; - } + socket_set(c->c2.link_sockets[i], mtcp->es, socket, + &c->c2.link_sockets[i]->ev_arg, NULL); } } + mtcp->udp_flags = socket | tuntap; +} - /* 'now' should always be a reasonably up-to-date timestamp */ - update_time(); - - /* set signal_received if a signal was received */ - if (mtcp->event_set_status & ES_ERROR) +void +get_io_flags_udp(struct context *c, struct multi_tcp *mtcp, const unsigned int flags) +{ + mtcp->udp_flags = ES_ERROR; + if (c->c2.fast_io && (flags & (IOW_TO_TUN | IOW_TO_LINK | IOW_MBUF))) { - get_signal(&c->sig->signal_received); + /* fast path -- only for TUN/TAP/UDP writes */ + unsigned int ret = 0; + if (flags & IOW_TO_TUN) + { + ret |= TUN_WRITE; + } + if (flags & (IOW_TO_LINK | IOW_MBUF)) + { + ret |= SOCKET_WRITE; + } + mtcp->udp_flags = ret; } - - dmsg(D_EVENT_WAIT, "I/O WAIT status=0x%04x", mtcp->event_set_status); + else + { +#ifdef _WIN32 + bool skip_iowait = flags & IOW_TO_TUN; + if (flags & IOW_READ_TUN) + { + /* + * don't read from tun if we have pending write to link, + * since every tun read overwrites to_link buffer filled + * by previous tun read + */ + skip_iowait = !(flags & IOW_TO_LINK); + } + if (tuntap_is_wintun(c->c1.tuntap) && skip_iowait) + { + unsigned int ret = 0; + if (flags & IOW_TO_TUN) + { + ret |= TUN_WRITE; + } + if (flags & IOW_READ_TUN) + { + ret |= TUN_READ; + } + mtcp->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); + } + } } void @@ -2308,10 +2231,10 @@ static uintptr_t management_shift = 6; /* depends on MANAGEMENT_READ and MANAGEMENT_WRITE */ #endif #ifdef ENABLE_ASYNC_PUSH - static int file_shift = FILE_SHIFT; + static uintptr_t file_shift = FILE_SHIFT; #endif #if defined(TARGET_LINUX) || defined(TARGET_FREEBSD) - static int dco_shift = DCO_SHIFT; /* Event from DCO linux kernel module */ + static uintptr_t dco_shift = DCO_SHIFT; /* Event from DCO linux kernel module */ #endif int i; @@ -2428,7 +2351,7 @@ #if defined(TARGET_LINUX) || defined(TARGET_FREEBSD) if (socket & EVENT_READ && c->c2.did_open_tun) { - dco_event_set(&c->c1.tuntap->dco, c->c2.event_set, (void *)&dco_shift); + dco_event_set(&c->c1.tuntap->dco, c->c2.event_set, (void *)dco_shift); } #endif @@ -2443,7 +2366,7 @@ /* arm inotify watcher */ if (c->options.mode == MODE_SERVER) { - event_ctl(c->c2.event_set, c->c2.inotify_fd, EVENT_READ, (void *)&file_shift); + event_ctl(c->c2.event_set, c->c2.inotify_fd, EVENT_READ, (void *)file_shift); } #endif diff --git a/src/openvpn/forward.h b/src/openvpn/forward.h index cb184a8..39ac975 100644 --- a/src/openvpn/forward.h +++ b/src/openvpn/forward.h @@ -69,7 +69,9 @@ extern counter_type link_write_bytes_global; -void io_wait_dowork_udp(struct context *c, struct multi_tcp *mtcp, const unsigned int flags); +void get_io_flags_dowork_udp(struct context *c, struct multi_tcp *mtcp, const unsigned int flags); + +void get_io_flags_udp(struct context *c, struct multi_tcp *mtcp, const unsigned int flags); void io_wait_dowork(struct context *c, const unsigned int flags); @@ -366,58 +368,6 @@ return flags; } -static inline void -io_wait_udp(struct context *c, struct multi_tcp *mtcp, const unsigned int flags) -{ - if (c->c2.fast_io && (flags & (IOW_TO_TUN|IOW_TO_LINK|IOW_MBUF))) - { - /* fast path -- only for TUN/TAP/UDP writes */ - unsigned int ret = 0; - if (flags & IOW_TO_TUN) - { - ret |= TUN_WRITE; - } - if (flags & (IOW_TO_LINK|IOW_MBUF)) - { - ret |= SOCKET_WRITE; - } - mtcp->event_set_status = ret; - } - else - { -#ifdef _WIN32 - bool skip_iowait = flags & IOW_TO_TUN; - if (flags & IOW_READ_TUN) - { - /* - * don't read from tun if we have pending write to link, - * since every tun read overwrites to_link buffer filled - * by previous tun read - */ - skip_iowait = !(flags & IOW_TO_LINK); - } - if (tuntap_is_wintun(c->c1.tuntap) && skip_iowait) - { - unsigned int ret = 0; - if (flags & IOW_TO_TUN) - { - ret |= TUN_WRITE; - } - if (flags & IOW_READ_TUN) - { - ret |= TUN_READ; - } - mtcp->event_set_status = ret; - } - else -#endif /* ifdef _WIN32 */ - { - /* slow path */ - io_wait_dowork_udp(c, mtcp, flags); - } - } -} - /* * This is the core I/O wait function, used for all I/O waits except * for TCP in server mode. diff --git a/src/openvpn/init.c b/src/openvpn/init.c index 762793a..2b88551 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -230,7 +230,7 @@ if (streq(p[1], "HTTP")) { struct http_proxy_options *ho; - if (ce->proto != PROTO_TCP && ce->proto != PROTO_TCP_CLIENT) + if (ce->proto != PROTO_TCP && c->mode != CM_CHILD_TCP) { msg(M_WARN, "HTTP proxy support only works for TCP based connections"); return false; @@ -607,7 +607,10 @@ ce_defined = false; } + int proto = c->options.ce.proto; c->options.ce = *ce; + c->options.ce.proto = proto; + #ifdef ENABLE_MANAGEMENT if (ce_defined && management && management_query_remote_enabled(management)) { @@ -2628,7 +2631,7 @@ if (found & OPT_P_EXPLICIT_NOTIFY) { - if (!proto_is_udp(c->options.ce.proto) && c->options.ce.explicit_exit_notification) + if (!proto_is_udp(c->c2.link_sockets[0]->info.proto) && c->options.ce.explicit_exit_notification) { msg(D_PUSH, "OPTIONS IMPORT: --explicit-exit-notify can only be used with --proto udp"); c->options.ce.explicit_exit_notification = 0; @@ -2788,14 +2791,21 @@ int sec = 2; int backoff = 0; - switch (c->options.ce.proto) + switch (c->mode) { - case PROTO_TCP_SERVER: - sec = 1; + case CM_TOP: + if (has_udp_in_local_list(&c->options)) + { + sec = c->options.ce.connect_retry_seconds; + } + else + { + sec = 1; + } break; - case PROTO_UDP: - case PROTO_TCP_CLIENT: + case CM_CHILD_UDP: + case CM_CHILD_TCP: sec = c->options.ce.connect_retry_seconds; break; } @@ -2813,7 +2823,7 @@ } /* Slow down reconnection after 5 retries per remote -- for TCP client or UDP tls-client only */ - if (c->options.ce.proto == PROTO_TCP_CLIENT + if (c->mode == CM_CHILD_TCP || (c->options.ce.proto == PROTO_UDP && c->options.tls_client)) { backoff = (c->options.unsuccessful_attempts / c->options.connection_list->len) - 4; @@ -3293,7 +3303,21 @@ to.server = options->tls_server; to.replay_window = options->replay_window; to.replay_time = options->replay_time; - to.tcp_mode = link_socket_proto_connection_oriented(options->ce.proto); + + if (c->options.ce.local_list->len > 1) + { + for (int i = 0; i < c->options.ce.local_list->len; i++) + { + if (proto_is_dgram(c->options.ce.local_list->array[i]->proto)) + { + to.tcp_mode = false; + } + } + } + else + { + to.tcp_mode = link_socket_proto_connection_oriented(c->options.ce.local_list->array[0]->proto); + } to.config_ciphername = c->options.ciphername; to.config_ncp_ciphers = c->options.ncp_ciphers; to.transition_window = options->transition_window; @@ -3338,7 +3362,7 @@ /* should we not xmit any packets until we get an initial * response from client? */ - if (to.server && options->ce.proto == PROTO_TCP_SERVER) + if (to.server && c->mode == CM_CHILD_TCP) { to.xmit_hold = true; } @@ -4257,20 +4281,13 @@ #ifdef _WIN32 msg(M_INFO, "NOTE: --fast-io is disabled since we are running on Windows"); #else - if (!proto_is_udp(c->options.ce.proto)) + if (c->options.shaper) { - msg(M_INFO, "NOTE: --fast-io is disabled since we are not using UDP"); + msg(M_INFO, "NOTE: --fast-io is disabled since we are using --shaper"); } else { - if (c->options.shaper) - { - msg(M_INFO, "NOTE: --fast-io is disabled since we are using --shaper"); - } - else - { - c->c2.fast_io = true; - } + c->c2.fast_io = true; } #endif } @@ -4967,6 +4984,7 @@ /* options */ dest->options = src->options; + dest->options.ce.proto = ls->info.proto; options_detach(&dest->options); dest->c2.event_set = src->c2.event_set; @@ -5065,10 +5083,7 @@ dest->c2.es_owned = false; dest->c2.event_set = NULL; - if (proto_is_dgram(src->options.ce.proto)) - { - do_event_set_init(dest, false); - } + do_event_set_init(dest, false); #ifdef USE_COMP dest->c2.comp_context = NULL; diff --git a/src/openvpn/mtcp.c b/src/openvpn/mtcp.c index ba0905e..128a375 100644 --- a/src/openvpn/mtcp.c +++ b/src/openvpn/mtcp.c @@ -680,11 +680,11 @@ 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); - struct multi_tcp *mtcp = m->mtcp; - const unsigned int status = mtcp->event_set_status; int i; for (i = 0; i < mtcp->n_esr; ++i) @@ -725,9 +725,10 @@ msg(D_MULTI_ERRORS, "MULTI: mtcp_proc_io: null socket"); break; } - socket_reset_listen_persistent(ev_arg->u.ls); + 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) { @@ -737,7 +738,23 @@ } else { - if (status & SOCKET_READ) + 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)) @@ -750,12 +767,12 @@ while (true) { multi_get_timeout(m, &m->top.c2.timeval); - io_wait_udp(&m->top, m->mtcp, p2mp_iow_flags(m)); + 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->event_set_status == ES_TIMEOUT) + if (m->mtcp->udp_flags == ES_TIMEOUT) { multi_process_timeout(m, MPP_PRE_SELECT | MPP_CLOSE_ON_SIGNAL); } diff --git a/src/openvpn/mtcp.h b/src/openvpn/mtcp.h index b2fdb6e..d55bdfd 100644 --- a/src/openvpn/mtcp.h +++ b/src/openvpn/mtcp.h @@ -55,7 +55,7 @@ int n_esr; int maxevents; unsigned int tun_rwflags; - unsigned int event_set_status; + unsigned int udp_flags; #ifdef ENABLE_MANAGEMENT unsigned int management_persist_flags; #endif diff --git a/src/openvpn/mudp.c b/src/openvpn/mudp.c index 4979751..8945a55 100644 --- a/src/openvpn/mudp.c +++ b/src/openvpn/mudp.c @@ -198,7 +198,6 @@ if (mroute_extract_openvpn_sockaddr(&real, &m->top.c2.from.dest, true) && m->top.c2.buf.len > 0) { - /*real.proto = ls->info.proto; */ struct hash_element *he; const uint32_t hv = hash_value(hash, &real); struct hash_bucket *bucket = hash_bucket(hash, hv); @@ -380,9 +379,7 @@ void multi_process_io_udp(struct multi_context *m) { - const unsigned int status = m->mtcp->event_set_status; - /*p2mp_iow_flags(m); */ - /*m->top.c2.event_set_status; */ + unsigned int status = m->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); diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c index 5098581..108a5a8 100644 --- a/src/openvpn/multi.c +++ b/src/openvpn/multi.c @@ -607,6 +607,7 @@ ASSERT(!mi->halt); mi->halt = true; + bool is_dgram = proto_is_dgram(mi->context.c2.link_sockets[0]->info.proto); dmsg(D_MULTI_DEBUG, "MULTI: multi_close_instance called"); @@ -665,7 +666,7 @@ mi->did_iroutes = false; } - if (m->mtcp && !proto_is_dgram(m->top.options.ce.proto)) + if (!is_dgram) { multi_tcp_dereference_instance(m->mtcp, mi); } @@ -3406,6 +3407,7 @@ perf_push(PERF_PROC_IN_LINK); lsi = get_link_socket_info(c); + /*lsi = &ls->info; */ orig_buf = c->c2.buf.data; if (process_incoming_link_part1(c, lsi, floated)) { @@ -3856,7 +3858,7 @@ while ((he = hash_iterator_next(&hi))) { struct multi_instance *mi = (struct multi_instance *) he->value; - if (!mi->halt) + if (!mi->halt && proto_is_dgram(mi->context.options.ce.proto)) { send_control_channel_string(&mi->context, next_server ? "RESTART,[N]" : "RESTART", D_PUSH); multi_schedule_context_wakeup(m, mi); @@ -3894,13 +3896,15 @@ status_close(so); return false; } - else if (proto_is_dgram(m->top.options.ce.proto) - && is_exit_restart(m->top.sig->signal_received) - && (m->deferred_shutdown_signal.signal_received == 0) - && m->top.options.ce.explicit_exit_notification != 0) + else if (has_udp_in_local_list(&m->top.options)) { - multi_push_restart_schedule_exit(m, m->top.options.ce.explicit_exit_notification == 2); - return false; + if (is_exit_restart(m->top.sig->signal_received) + && (m->deferred_shutdown_signal.signal_received == 0) + && m->top.options.ce.explicit_exit_notification != 0) + { + multi_push_restart_schedule_exit(m, m->top.options.ce.explicit_exit_notification == 2); + return false; + } } return true; } @@ -4198,10 +4202,10 @@ multi_tcp_process_io(multi); MULTI_CHECK_SIG(multi); } - /*else if (status == 0) - * { - * multi_tcp_action(multi, NULL, TA_TIMEOUT, false); - * }*/ + else if (status == 0) + { + multi_tcp_action(multi, NULL, TA_TIMEOUT, false); + } perf_pop(); } diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 9e800bb..553bc26 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -987,10 +987,13 @@ const struct connection_entry *e, const int i) { - setenv_str_i(es, "proto", proto2ascii(e->proto, e->af, false), i); - /* expected to befor single socket contexts only */ - setenv_str_i(es, "local", e->local_list->array[0]->local, i); - setenv_str_i(es, "local_port", e->local_list->array[0]->port, i); + for (int j = 0; j < e->local_list->len; j++) + { + setenv_str_i(es, "proto", proto2ascii(e->local_list->array[j]->proto, e->af, false), i); + /* expected to befor single socket contexts only */ + setenv_str_i(es, "local", e->local_list->array[j]->local, i); + setenv_str_i(es, "local_port", e->local_list->array[j]->port, i); + } setenv_str_i(es, "remote", e->remote, i); setenv_str_i(es, "remote_port", e->remote_port, i); @@ -2455,7 +2458,7 @@ { struct local_entry *le = ce->local_list->array[i]; - if (proto_is_net(ce->proto) + if (proto_is_net(le->proto) && string_defined_equal(le->local, ce->remote) && string_defined_equal(le->port, ce->remote_port)) { @@ -3781,6 +3784,12 @@ options_postprocess_mutate_ce(o, o->connection_list->array[i]); } + if (!has_udp_in_local_list(o)) + { + o->fast_io = false; + msg(M_INFO, "NOTE: --fast-io is disabled while using multi-socket"); + } + if (o->ce.local_list) { for (i = 0; i < o->ce.local_list->len; i++) @@ -9629,3 +9638,19 @@ err: gc_free(&gc); } + +bool +has_udp_in_local_list(const struct options *options) +{ + if (options->ce.local_list) + { + for (int i = 0; i < options->ce.local_list->len; i++) + { + if (proto_is_dgram(options->ce.local_list->array[i]->proto)) + { + return true; + } + } + } + return false; +} diff --git a/src/openvpn/options.h b/src/openvpn/options.h index cba0333..59035f8 100644 --- a/src/openvpn/options.h +++ b/src/openvpn/options.h @@ -913,6 +913,8 @@ bool key_is_external(const struct options *options); +bool has_udp_in_local_list(const struct options *options); + /** * Returns whether the current configuration has dco enabled. */ -- To view, visit http://gerrit.openvpn.net/c/openvpn/+/440?usp=email To unsubscribe, or for help writing mail filters, visit http://gerrit.openvpn.net/settings Gerrit-Project: openvpn Gerrit-Branch: master Gerrit-Change-Id: I81ec69d12abc9a661875c93c7f1bd97e525df55f Gerrit-Change-Number: 440 Gerrit-PatchSet: 1 Gerrit-Owner: ordex <a...@unstable.cc> Gerrit-Reviewer: flichtenheld <fr...@lichtenheld.com> Gerrit-Reviewer: plaisthos <arne-open...@rfc2549.org> Gerrit-CC: openvpn-devel <openvpn-devel@lists.sourceforge.net> Gerrit-Attention: plaisthos <arne-open...@rfc2549.org> Gerrit-Attention: flichtenheld <fr...@lichtenheld.com> Gerrit-MessageType: newchange
_______________________________________________ Openvpn-devel mailing list Openvpn-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/openvpn-devel