diff options
Diffstat (limited to 'src/openvpn/mtcp.c')
-rw-r--r-- | src/openvpn/mtcp.c | 1153 |
1 files changed, 621 insertions, 532 deletions
diff --git a/src/openvpn/mtcp.c b/src/openvpn/mtcp.c index 78e5ccd..b5471b1 100644 --- a/src/openvpn/mtcp.c +++ b/src/openvpn/mtcp.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -59,619 +59,706 @@ /* * 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_SOCKET ((void *)1) +#define MTCP_TUN ((void *)2) +#define MTCP_SIG ((void *)3) /* Only on Windows */ #ifdef ENABLE_MANAGEMENT -# define MTCP_MANAGEMENT ((void*)4) +#define MTCP_MANAGEMENT ((void *)4) #endif #ifdef ENABLE_ASYNC_PUSH -#define MTCP_FILE_CLOSE_WRITE ((void*)5) +#define MTCP_FILE_CLOSE_WRITE ((void *)5) #endif -#define MTCP_N ((void*)16) /* upper bound on MTCP_x */ +#define MTCP_N ((void *)16) /* upper bound on MTCP_x */ struct ta_iow_flags { - unsigned int flags; - unsigned int ret; - unsigned int tun; - unsigned int sock; + unsigned int flags; + unsigned int ret; + unsigned int tun; + unsigned int sock; }; static const char * -pract (int action) +pract(int action) { - switch (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 "?"; + 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 "?"; } } static struct multi_instance * -multi_create_instance_tcp (struct multi_context *m) +multi_create_instance_tcp(struct multi_context *m) { - struct gc_arena gc = gc_new (); - struct multi_instance *mi = NULL; - struct hash *hash = m->hash; + struct gc_arena gc = gc_new(); + struct multi_instance *mi = NULL; + struct hash *hash = m->hash; - mi = multi_create_instance (m, NULL); - if (mi) + mi = multi_create_instance(m, NULL); + if (mi) { - struct hash_element *he; - const uint32_t hv = hash_value (hash, &mi->real); - struct hash_bucket *bucket = hash_bucket (hash, hv); - - he = hash_lookup_fast (hash, bucket, &mi->real, hv); - - if (he) - { - struct multi_instance *oldmi = (struct multi_instance *) he->value; - msg (D_MULTI_LOW, "MULTI TCP: new incoming client address matches existing client address -- new client takes precedence"); - oldmi->did_real_hash = false; - multi_close_instance (m, oldmi, false); - he->key = &mi->real; - he->value = mi; - } - else - hash_add_fast (hash, bucket, &mi->real, hv, mi); - - mi->did_real_hash = true; + struct hash_element *he; + const uint32_t hv = hash_value(hash, &mi->real); + struct hash_bucket *bucket = hash_bucket(hash, hv); + + he = hash_lookup_fast(hash, bucket, &mi->real, hv); + + if (he) + { + struct multi_instance *oldmi = (struct multi_instance *) he->value; + msg(D_MULTI_LOW, "MULTI TCP: new incoming client address matches existing client address -- new client takes precedence"); + oldmi->did_real_hash = false; + multi_close_instance(m, oldmi, false); + he->key = &mi->real; + he->value = mi; + } + else + { + hash_add_fast(hash, bucket, &mi->real, hv, mi); + } + + mi->did_real_hash = true; } #ifdef ENABLE_DEBUG - if (mi) - dmsg (D_MULTI_DEBUG, "MULTI TCP: instance added: %s", mroute_addr_print (&mi->real, &gc)); - else - dmsg (D_MULTI_DEBUG, "MULTI TCP: new client instance failed"); + if (mi) + { + dmsg(D_MULTI_DEBUG, "MULTI TCP: instance added: %s", mroute_addr_print(&mi->real, &gc)); + } + else + { + dmsg(D_MULTI_DEBUG, "MULTI TCP: new client instance failed"); + } #endif - gc_free (&gc); - ASSERT (!(mi && mi->halt)); - return mi; + gc_free(&gc); + ASSERT(!(mi && mi->halt)); + return mi; } bool -multi_tcp_instance_specific_init (struct multi_context *m, struct multi_instance *mi) +multi_tcp_instance_specific_init(struct multi_context *m, struct multi_instance *mi) { - /* buffer for queued TCP socket output packets */ - mi->tcp_link_out_deferred = mbuf_init (m->top.options.n_bcast_buf); - - ASSERT (mi->context.c2.link_socket); - ASSERT (mi->context.c2.link_socket->info.lsa); - ASSERT (mi->context.c2.link_socket->mode == LS_MODE_TCP_ACCEPT_FROM); - ASSERT (mi->context.c2.link_socket->info.lsa->actual.dest.addr.sa.sa_family == AF_INET - || mi->context.c2.link_socket->info.lsa->actual.dest.addr.sa.sa_family == AF_INET6 - ); - if (!mroute_extract_openvpn_sockaddr (&mi->real, &mi->context.c2.link_socket->info.lsa->actual.dest, true)) + /* buffer for queued TCP socket output packets */ + mi->tcp_link_out_deferred = mbuf_init(m->top.options.n_bcast_buf); + + ASSERT(mi->context.c2.link_socket); + ASSERT(mi->context.c2.link_socket->info.lsa); + ASSERT(mi->context.c2.link_socket->mode == LS_MODE_TCP_ACCEPT_FROM); + ASSERT(mi->context.c2.link_socket->info.lsa->actual.dest.addr.sa.sa_family == AF_INET + || mi->context.c2.link_socket->info.lsa->actual.dest.addr.sa.sa_family == AF_INET6 + ); + if (!mroute_extract_openvpn_sockaddr(&mi->real, &mi->context.c2.link_socket->info.lsa->actual.dest, true)) { - msg (D_MULTI_ERRORS, "MULTI TCP: TCP client address is undefined"); - return false; + msg(D_MULTI_ERRORS, "MULTI TCP: TCP client address is undefined"); + return false; } - return true; + return true; } void -multi_tcp_instance_specific_free (struct multi_instance *mi) +multi_tcp_instance_specific_free(struct multi_instance *mi) { - mbuf_free (mi->tcp_link_out_deferred); + mbuf_free(mi->tcp_link_out_deferred); } struct multi_tcp * -multi_tcp_init (int maxevents, int *maxclients) +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; + 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) +multi_tcp_delete_event(struct multi_tcp *mtcp, event_t event) { - if (mtcp && mtcp->es) - event_del (mtcp->es, event); + if (mtcp && mtcp->es) + { + event_del(mtcp->es, event); + } } void -multi_tcp_free (struct multi_tcp *mtcp) +multi_tcp_free(struct multi_tcp *mtcp) { - if (mtcp) + if (mtcp) { - event_free (mtcp->es); - if (mtcp->esr) - free (mtcp->esr); - free (mtcp); + event_free(mtcp->es); + if (mtcp->esr) + { + free(mtcp->esr); + } + free(mtcp); } } void -multi_tcp_dereference_instance (struct multi_tcp *mtcp, struct multi_instance *mi) +multi_tcp_dereference_instance(struct multi_tcp *mtcp, struct multi_instance *mi) { - struct link_socket *ls = mi->context.c2.link_socket; - if (ls && mi->socket_set_called) - event_del (mtcp->es, socket_event_handle (ls)); - mtcp->n_esr = 0; + struct link_socket *ls = mi->context.c2.link_socket; + if (ls && mi->socket_set_called) + { + event_del(mtcp->es, socket_event_handle(ls)); + } + mtcp->n_esr = 0; } static inline void -multi_tcp_set_global_rw_flags (struct multi_context *m, struct multi_instance *mi) +multi_tcp_set_global_rw_flags(struct multi_context *m, struct multi_instance *mi) { - if (mi) + if (mi) { - mi->socket_set_called = true; - socket_set (mi->context.c2.link_socket, - m->mtcp->es, - mbuf_defined (mi->tcp_link_out_deferred) ? EVENT_WRITE : EVENT_READ, - mi, - &mi->tcp_rwflags); + mi->socket_set_called = true; + socket_set(mi->context.c2.link_socket, + m->mtcp->es, + mbuf_defined(mi->tcp_link_out_deferred) ? EVENT_WRITE : EVENT_READ, + mi, + &mi->tcp_rwflags); } } static inline int -multi_tcp_wait (const struct context *c, - struct multi_tcp *mtcp) +multi_tcp_wait(const struct context *c, + struct multi_tcp *mtcp) { - int status; - socket_set_listen_persistent (c->c2.link_socket, mtcp->es, MTCP_SOCKET); - tun_set (c->c1.tuntap, mtcp->es, EVENT_READ, MTCP_TUN, &mtcp->tun_rwflags); + int status; + socket_set_listen_persistent(c->c2.link_socket, mtcp->es, MTCP_SOCKET); + tun_set(c->c1.tuntap, mtcp->es, EVENT_READ, MTCP_TUN, &mtcp->tun_rwflags); #ifdef ENABLE_MANAGEMENT - if (management) - management_socket_set (management, mtcp->es, MTCP_MANAGEMENT, &mtcp->management_persist_flags); + 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); + /* 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; + 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 * -multi_tcp_context (struct multi_context *m, struct multi_instance *mi) +multi_tcp_context(struct multi_context *m, struct multi_instance *mi) { - if (mi) - return &mi->context; - else - return &m->top; + if (mi) + { + return &mi->context; + } + else + { + return &m->top; + } } static bool -multi_tcp_process_outgoing_link_ready (struct multi_context *m, struct multi_instance *mi, const unsigned int mpp_flags) +multi_tcp_process_outgoing_link_ready(struct multi_context *m, struct multi_instance *mi, const unsigned int mpp_flags) { - struct mbuf_item item; - bool ret = true; - ASSERT (mi); + struct mbuf_item item; + bool ret = true; + ASSERT(mi); - /* extract from queue */ - if (mbuf_extract_item (mi->tcp_link_out_deferred, &item)) /* ciphertext IP packet */ + /* extract from queue */ + if (mbuf_extract_item(mi->tcp_link_out_deferred, &item)) /* ciphertext IP packet */ { - dmsg (D_MULTI_TCP, "MULTI TCP: transmitting previously deferred packet"); - - ASSERT (mi == item.instance); - mi->context.c2.to_link = item.buffer->buf; - ret = multi_process_outgoing_link_dowork (m, mi, mpp_flags); - if (!ret) - mi = NULL; - mbuf_free_buf (item.buffer); + dmsg(D_MULTI_TCP, "MULTI TCP: transmitting previously deferred packet"); + + ASSERT(mi == item.instance); + mi->context.c2.to_link = item.buffer->buf; + ret = multi_process_outgoing_link_dowork(m, mi, mpp_flags); + if (!ret) + { + mi = NULL; + } + mbuf_free_buf(item.buffer); } - return ret; + return ret; } static bool -multi_tcp_process_outgoing_link (struct multi_context *m, bool defer, const unsigned int mpp_flags) +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); - bool ret = true; + struct multi_instance *mi = multi_process_outgoing_link_pre(m); + bool ret = true; - if (mi) + if (mi) { - if (defer || mbuf_defined (mi->tcp_link_out_deferred)) - { - /* save to queue */ - struct buffer *buf = &mi->context.c2.to_link; - if (BLEN (buf) > 0) - { - struct mbuf_buffer *mb = mbuf_alloc_buf (buf); - struct mbuf_item item; - - set_prefix (mi); - dmsg (D_MULTI_TCP, "MULTI TCP: queuing deferred packet"); - item.buffer = mb; - item.instance = mi; - mbuf_add_item (mi->tcp_link_out_deferred, &item); - mbuf_free_buf (mb); - buf_reset (buf); - ret = multi_process_post (m, mi, mpp_flags); - if (!ret) - mi = NULL; - clear_prefix (); - } - } - else - { - ret = multi_process_outgoing_link_dowork (m, mi, mpp_flags); - if (!ret) - mi = NULL; - } + if (defer || mbuf_defined(mi->tcp_link_out_deferred)) + { + /* save to queue */ + struct buffer *buf = &mi->context.c2.to_link; + if (BLEN(buf) > 0) + { + struct mbuf_buffer *mb = mbuf_alloc_buf(buf); + struct mbuf_item item; + + set_prefix(mi); + dmsg(D_MULTI_TCP, "MULTI TCP: queuing deferred packet"); + item.buffer = mb; + item.instance = mi; + mbuf_add_item(mi->tcp_link_out_deferred, &item); + mbuf_free_buf(mb); + buf_reset(buf); + ret = multi_process_post(m, mi, mpp_flags); + if (!ret) + { + mi = NULL; + } + clear_prefix(); + } + } + else + { + ret = multi_process_outgoing_link_dowork(m, mi, mpp_flags); + if (!ret) + { + mi = NULL; + } + } } - return ret; + return ret; } static int -multi_tcp_wait_lite (struct multi_context *m, struct multi_instance *mi, const int action, bool *tun_input_pending) +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; + 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); + 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 */ + tv_clear(&c->c2.timeval); /* ZERO-TIMEOUT */ - switch (action) + 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); + 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 (tun_input_pending && (c->c2.event_set_status & TUN_READ)) + { + *tun_input_pending = true; + } - if (c->c2.event_set_status & looking_for) + if (c->c2.event_set_status & looking_for) { - return action; + return action; } - else + 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; + 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) +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; + 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); + dmsg(D_MULTI_DEBUG, "MULTI TCP: multi_tcp_dispatch a=%s mi=" ptr_format, + pract(action), + (ptr_type)mi); - switch (action) + 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_socket); - set_prefix (mi); - read_incoming_link (&mi->context); - clear_prefix (); - if (!IS_SIG (&mi->context)) - { - multi_process_incoming_link (m, mi, mpp_flags); - if (!IS_SIG (&mi->context)) - stream_buf_read_setup (mi->context.c2.link_socket); - } - 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); + 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_socket); + set_prefix(mi); + read_incoming_link(&mi->context); + clear_prefix(); + if (!IS_SIG(&mi->context)) + { + multi_process_incoming_link(m, mi, mpp_flags); + if (!IS_SIG(&mi->context)) + { + stream_buf_read_setup(mi->context.c2.link_socket); + } + } + 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; + m->mpp_touched = NULL; + return touched; } int -multi_tcp_post (struct multi_context *m, struct multi_instance *mi, const int action) +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; + 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; +#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; + if (TUN_OUT(c)) + { + flags |= MTP_TUN_OUT; + } + if (LINK_OUT(c)) + { + flags |= MTP_LINK_OUT; + } - switch (flags) + 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 && socket_read_residual (c->c2.link_socket)) - 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; - } + 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 && socket_read_residual(c->c2.link_socket)) + { + 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)); + dmsg(D_MULTI_DEBUG, "MULTI TCP: multi_tcp_post %s -> %s", + pract(action), + pract(newaction)); - return newaction; + return newaction; } static void -multi_tcp_action (struct multi_context *m, struct multi_instance *mi, int action, bool poll) +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); + 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); } static void -multi_tcp_process_io (struct multi_context *m) +multi_tcp_process_io(struct multi_context *m) { - struct multi_tcp *mtcp = m->mtcp; - int i; + struct multi_tcp *mtcp = m->mtcp; + int i; - for (i = 0; i < mtcp->n_esr; ++i) + for (i = 0; i < mtcp->n_esr; ++i) { - struct event_set_return *e = &mtcp->esr[i]; - - /* incoming data for instance? */ - if (e->arg >= MTCP_N) - { - struct multi_instance *mi = (struct multi_instance *) e->arg; - if (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); - } - } - else - { + struct event_set_return *e = &mtcp->esr[i]; + + /* incoming data for instance? */ + if (e->arg >= MTCP_N) + { + struct multi_instance *mi = (struct multi_instance *) e->arg; + if (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); + } + } + } + else + { #ifdef ENABLE_MANAGEMENT - if (e->arg == MTCP_MANAGEMENT) - { - ASSERT (management); - management_io (management); - } - else + 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_socket); - socket_reset_listen_persistent (m->top.c2.link_socket); - mi = multi_create_instance_tcp (m); - if (mi) - multi_tcp_action (m, mi, TA_INITIAL, false); - } - /* signal received? */ - else if (e->arg == MTCP_SIG) - { - get_signal (&m->top.sig->signal_received); - } + /* 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_socket); + socket_reset_listen_persistent(m->top.c2.link_socket); + mi = multi_create_instance_tcp(m); + if (mi) + { + multi_tcp_action(m, mi, TA_INITIAL, false); + } + } + /* 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); - } + 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; + } + 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); + } } - 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); - } - } } /* @@ -679,81 +766,83 @@ multi_tcp_process_io (struct multi_context *m) * TCP mode. */ void -tunnel_server_tcp (struct context *top) +tunnel_server_tcp(struct context *top) { - struct multi_context multi; - int status; + struct multi_context multi; + int status; - top->mode = CM_TOP; - context_clear_2 (top); + 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, true, MC_SINGLE_THREADED); + /* initialize top-tunnel instance */ + init_instance_handle_signals(top, top->es, CC_HARD_USR1_TO_HUP); + if (IS_SIG(top)) + { + return; + } - /* initialize our cloned top object */ - multi_top_init (&multi, top); + /* initialize global multi_context object */ + multi_init(&multi, top, true, MC_SINGLE_THREADED); - /* initialize management interface */ - init_management_callback_multi (&multi); + /* initialize our cloned top object */ + multi_top_init(&multi, top); - /* finished with initialization */ - initialization_sequence_completed (top, ISC_SERVER); /* --mode server --proto tcp-server */ + /* 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) + multi.top.c2.inotify_fd = inotify_init(); + if (multi.top.c2.inotify_fd < 0) { - msg (D_MULTI_ERRORS, "MULTI: inotify_init error: %s", strerror(errno)); + msg(D_MULTI_ERRORS, "MULTI: inotify_init error: %s", strerror(errno)); } #endif - /* per-packet event loop */ - while (true) + /* 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 (); + 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); + close(top->c2.inotify_fd); #endif - /* shut down management interface */ - uninit_management_callback_multi (&multi); + /* shut down management interface */ + uninit_management_callback_multi(&multi); - /* save ifconfig-pool */ - multi_ifconfig_pool_persist (&multi, true); + /* 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); + /* tear down tunnel instance (unless --persist-tun) */ + multi_uninit(&multi); + multi_top_free(&multi); + close_instance(top); } -#endif +#endif /* if P2MP_SERVER */ |