Hi, Here is a patch trying to fix the persistent connection issue. The patch adds a relay_disconnect function. This function allows to only disconnect se_out connection and reallocate output buffer for future use.
The patch also uses this function in relay_match_action for http if it appears destination changed. Feel free to comment. Regards, -- Paul Fariello PGP: 0x672CDD2031AAF49B
? .gitignore ? 0001-Remove-superfluous-http-method-handling-for-request-.patch ? README.md Index: relay.c =================================================================== RCS file: /cvs/src/usr.sbin/relayd/relay.c,v retrieving revision 1.206 diff -u -p -r1.206 relay.c --- relay.c 30 Dec 2015 16:00:57 -0000 1.206 +++ relay.c 4 Aug 2016 19:32:58 -0000 @@ -1646,6 +1646,67 @@ relay_connect(struct rsession *con) } void +relay_disconnect(struct rsession *con, const char *msg) +{ + char ibuf[128], obuf[128], *ptr = NULL; + struct relay *rlay = con->se_relay; + + if ((env->sc_opts & RELAYD_OPT_LOGUPDATE) && msg != NULL) { + bzero(&ibuf, sizeof(ibuf)); + bzero(&obuf, sizeof(obuf)); + (void)print_host(&con->se_in.ss, ibuf, sizeof(ibuf)); + (void)print_host(&con->se_out.ss, obuf, sizeof(obuf)); + if (EVBUFFER_LENGTH(con->se_log) && + evbuffer_add_printf(con->se_log, "\r\n") != -1) + ptr = evbuffer_readline(con->se_log); + log_info("relay %s, " + "session %d (%d active), %s, %s -> %s:%d, " + "%s%s%s", rlay->rl_conf.name, con->se_id, relay_sessions, + con->se_tag != 0 ? tag_id2name(con->se_tag) : "0", ibuf, + obuf, ntohs(con->se_out.port), msg, ptr == NULL ? "" : ",", + ptr == NULL ? "" : ptr); + free(ptr); + } + + if (con->se_out.bev != NULL) { + bufferevent_free(con->se_out.bev); + con->se_out.bev = NULL; + } + if (con->se_out.ssl != NULL) { + /* XXX handle non-blocking shutdown */ + if (SSL_shutdown(con->se_out.ssl) == 0) + SSL_shutdown(con->se_out.ssl); + SSL_free(con->se_out.ssl); + con->se_out.ssl = NULL; + } + if (con->se_out.tlscert != NULL) { + X509_free(con->se_out.tlscert); + con->se_out.tlscert = NULL; + } + if (con->se_out.s != -1) { + close(con->se_out.s); + + /* Some file descriptors are available again. */ + if (evtimer_pending(&rlay->rl_evt, NULL)) { + evtimer_del(&rlay->rl_evt); + event_add(&rlay->rl_ev, NULL); + } + con->se_out.s = -1; + } + + /* Pre-allocate output buffer */ + con->se_out.output = evbuffer_new(); + if (con->se_out.output == NULL) { + relay_close(con, "failed to allocate output buffer"); + return; + } + + con->se_out.state = STATE_INIT; + + free(con->se_out.buf); +} + +void relay_close(struct rsession *con, const char *msg) { char ibuf[128], obuf[128], *ptr = NULL; Index: relay_http.c =================================================================== RCS file: /cvs/src/usr.sbin/relayd/relay_http.c,v retrieving revision 1.57 diff -u -p -r1.57 relay_http.c --- relay_http.c 27 Jul 2016 06:55:44 -0000 1.57 +++ relay_http.c 4 Aug 2016 19:32:58 -0000 @@ -1414,8 +1414,13 @@ relay_match_actions(struct ctl_relay_eve /* * Apply the following options instantly (action per match). */ - if (rule->rule_table != NULL) + if (rule->rule_table != NULL) { + if (con->se_table != rule->rule_table && + cre->dst->state == STATE_CONNECTED) { + relay_disconnect(con, "change destination"); + } con->se_table = rule->rule_table; + } if (rule->rule_tag != 0) con->se_tag = rule->rule_tag == -1 ? 0 : rule->rule_tag; Index: relayd.h =================================================================== RCS file: /cvs/src/usr.sbin/relayd/relayd.h,v retrieving revision 1.224 diff -u -p -r1.224 relayd.h --- relayd.h 27 Jul 2016 06:55:44 -0000 1.224 +++ relayd.h 4 Aug 2016 19:32:58 -0000 @@ -1166,6 +1166,7 @@ int relay_spliceadjust(struct ctl_relay void relay_error(struct bufferevent *, short, void *); int relay_preconnect(struct rsession *); int relay_connect(struct rsession *); +void relay_disconnect(struct rsession *, const char *); void relay_connected(int, short, void *); void relay_bindanyreq(struct rsession *, in_port_t, int); void relay_bindany(int, short, void *);