Author: rjung Date: Sun Feb 8 14:28:10 2015 New Revision: 1658173 URL: http://svn.apache.org/r1658173 Log: BZ 57536: AJP: Allow to configure connection source address. This should only be used on multi-homed hosts. The feature is experimental.
Modified: tomcat/jk/trunk/native/common/jk_ajp12_worker.c tomcat/jk/trunk/native/common/jk_ajp_common.c tomcat/jk/trunk/native/common/jk_ajp_common.h tomcat/jk/trunk/native/common/jk_connect.c tomcat/jk/trunk/native/common/jk_connect.h tomcat/jk/trunk/native/common/jk_status.c tomcat/jk/trunk/native/common/jk_util.c tomcat/jk/trunk/native/common/jk_util.h tomcat/jk/trunk/xdocs/miscellaneous/changelog.xml tomcat/jk/trunk/xdocs/reference/workers.xml Modified: tomcat/jk/trunk/native/common/jk_ajp12_worker.c URL: http://svn.apache.org/viewvc/tomcat/jk/trunk/native/common/jk_ajp12_worker.c?rev=1658173&r1=1658172&r2=1658173&view=diff ============================================================================== --- tomcat/jk/trunk/native/common/jk_ajp12_worker.c (original) +++ tomcat/jk/trunk/native/common/jk_ajp12_worker.c Sun Feb 8 14:28:10 2015 @@ -41,6 +41,7 @@ struct ajp12_worker { jk_sockaddr_t worker_inet_addr; + jk_sockaddr_t worker_source_inet_addr; unsigned connect_retry_attempts; char *name; jk_worker_t worker; @@ -127,6 +128,9 @@ static int JK_METHOD service(jk_endpoint attempt++) { p->sd = jk_open_socket(&p->worker->worker_inet_addr, + p->worker->worker_source_inet_addr.ipaddr_ptr != NULL ? + &p->worker->worker_source_inet_addr : + NULL, JK_FALSE, 0, 0, 0, l); jk_log(l, JK_LOG_DEBUG, "In jk_endpoint_t::service, sd = %d", @@ -187,19 +191,34 @@ static int JK_METHOD validate(jk_worker_ p->name, AJP_DEF_HOST); + const char *source = jk_get_worker_host(props, + p->name, + ""); + jk_log(l, JK_LOG_DEBUG, - "In jk_worker_t::validate for worker %s contact is %s:%d", + "In jk_worker_t::validate for worker %s target is %s:%d", p->name, host, port); if (host) { - if (jk_resolve(host, port, &p->worker_inet_addr, we->pool, JK_FALSE, l)) { - return JK_TRUE; + if (!jk_resolve(host, port, &p->worker_inet_addr, we->pool, JK_FALSE, l)) { + jk_log(l, JK_LOG_ERROR, + "In jk_worker_t::validate, host '%s:%d' resolve failed", + host, port); + return JK_FALSE; } + } else { jk_log(l, JK_LOG_ERROR, - "In jk_worker_t::validate, resolve failed"); + "In jk_worker_t::validate, Error no host name given"); + return JK_FALSE; + } + if (source && *source) { + if (!jk_resolve(source, 0, &p->worker_source_inet_addr, we->pool, JK_FALSE, l)) { + p->worker_source_inet_addr.ipaddr_ptr = NULL; + jk_log(l, JK_LOG_WARNING, + "In jk_worker_t::validate, source addr '%s' resolve failed - ignored", + source); + } } - jk_log(l, JK_LOG_ERROR, "In jk_worker_t::validate, Error %s %d", - host, port); } else { jk_log(l, JK_LOG_ERROR, Modified: tomcat/jk/trunk/native/common/jk_ajp_common.c URL: http://svn.apache.org/viewvc/tomcat/jk/trunk/native/common/jk_ajp_common.c?rev=1658173&r1=1658172&r2=1658173&view=diff ============================================================================== --- tomcat/jk/trunk/native/common/jk_ajp_common.c (original) +++ tomcat/jk/trunk/native/common/jk_ajp_common.c Sun Feb 8 14:28:10 2015 @@ -1040,6 +1040,9 @@ int ajp_connect_to_endpoint(ajp_endpoint ae->last_errno = 0; ae->sd = jk_open_socket(&ae->worker->worker_inet_addr, + ae->worker->worker_source_inet_addr.ipaddr_ptr != NULL ? + &ae->worker->worker_source_inet_addr : + NULL, ae->worker->keepalive, ae->worker->socket_timeout, ae->worker->socket_connect_timeout, @@ -2830,12 +2833,18 @@ int ajp_validate(jk_worker_t *pThis, } strncpy(p->host, tmp, JK_SHM_STR_SIZ); p->prefer_ipv6 = jk_get_worker_prefer_ipv6(props, p->name, JK_FALSE); + tmp = jk_get_worker_source(props, p->name, ""); + if (jk_check_attribute_length("source address", tmp, l) == JK_FALSE) { + JK_TRACE_EXIT(l); + return JK_FALSE; + } + strncpy(p->source, tmp, JK_SHM_STR_SIZ); if (p->s->h.sequence == 0) { /* Initial setup. */ if (JK_IS_DEBUG_LEVEL(l)) jk_log(l, JK_LOG_DEBUG, - "worker %s contact is '%s:%d'", + "worker %s target is '%s:%d'", p->name, p->host, p->port); if (p->port > 0) { if (!jk_resolve(p->host, p->port, &p->worker_inet_addr, @@ -2850,6 +2859,15 @@ int ajp_validate(jk_worker_t *pThis, p->name); } } + if (p->source && *p->source) { + if (!jk_resolve(p->source, 0, &p->worker_source_inet_addr, + we->pool, p->prefer_ipv6, l)) { + p->worker_source_inet_addr.ipaddr_ptr = NULL; + jk_log(l, JK_LOG_WARNING, + "worker %s can't resolve source address '%s'", + p->name, p->source); + } + } p->addr_sequence = 0; p->s->addr_sequence = 0; p->s->last_maintain_time = time(NULL); Modified: tomcat/jk/trunk/native/common/jk_ajp_common.h URL: http://svn.apache.org/viewvc/tomcat/jk/trunk/native/common/jk_ajp_common.h?rev=1658173&r1=1658172&r2=1658173&view=diff ============================================================================== --- tomcat/jk/trunk/native/common/jk_ajp_common.h (original) +++ tomcat/jk/trunk/native/common/jk_ajp_common.h Sun Feb 8 14:28:10 2015 @@ -299,9 +299,11 @@ struct ajp_worker JK_CRIT_SEC cs; jk_sockaddr_t worker_inet_addr; /* Contains host and port */ + jk_sockaddr_t worker_source_inet_addr; /* Contains source ip */ unsigned connect_retry_attempts; char host[JK_SHM_STR_SIZ]; int port; + char source[JK_SHM_STR_SIZ]; int addr_sequence; /* Whether the address is resolved */ int maintain_time; int prefer_ipv6; Modified: tomcat/jk/trunk/native/common/jk_connect.c URL: http://svn.apache.org/viewvc/tomcat/jk/trunk/native/common/jk_connect.c?rev=1658173&r1=1658172&r2=1658173&view=diff ============================================================================== --- tomcat/jk/trunk/native/common/jk_connect.c (original) +++ tomcat/jk/trunk/native/common/jk_connect.c Sun Feb 8 14:28:10 2015 @@ -163,6 +163,7 @@ static int sononblock(jk_sock_t sd) /** Non-blocking socket connect * @param sd socket to connect * @param addr address to connect to + * @param source optional source address * @param timeout connect timeout in seconds * (<=0: no timeout=blocking) * @param l logger @@ -171,12 +172,22 @@ static int sononblock(jk_sock_t sd) * during blocking connect * 0: success */ -static int nb_connect(jk_sock_t sd, jk_sockaddr_t *addr, int timeout, jk_logger_t *l) +static int nb_connect(jk_sock_t sd, jk_sockaddr_t *addr, jk_sockaddr_t *source, + int timeout, jk_logger_t *l) { int rc; + char buf[64]; JK_TRACE_ENTER(l); + if (source != NULL) { + if (bind(sd, (const struct sockaddr *)&source->sa.sin, source->salen)) { + JK_GET_SOCKET_ERRNO(); + jk_log(l, JK_LOG_ERROR, + "error during source bind on socket %d [%s] (errno=%d)", + sd, jk_dump_hinfo(source, buf, sizeof(buf)), errno); + } + } if (timeout <= 0) { rc = connect(sd, (const struct sockaddr *)&addr->sa.sin, addr->salen); JK_TRACE_EXIT(l); @@ -237,18 +248,29 @@ static int nb_connect(jk_sock_t sd, jk_s /** Non-blocking socket connect * @param sd socket to connect * @param addr address to connect to + * @param source optional source address * @param timeout connect timeout in seconds * (<=0: no timeout=blocking) * @param l logger * @return -1: some kind of error occured * 0: success */ -static int nb_connect(jk_sock_t sd, jk_sockaddr_t *addr, int timeout, jk_logger_t *l) +static int nb_connect(jk_sock_t sd, jk_sockaddr_t *addr, jk_sockaddr_t *source, + int timeout, jk_logger_t *l) { int rc = 0; + char buf[64]; JK_TRACE_ENTER(l); + if (source != NULL) { + if (bind(sd, (const struct sockaddr *)&source->sa.sin, source->salen)) { + JK_GET_SOCKET_ERRNO(); + jk_log(l, JK_LOG_ERROR, + "error during source bind on socket %d [%s] (errno=%d)", + sd, jk_dump_hinfo(source, buf, sizeof(buf)), errno); + } + } if (timeout > 0) { if (sononblock(sd)) { JK_TRACE_EXIT(l); @@ -301,17 +323,28 @@ static int nb_connect(jk_sock_t sd, jk_s /** Non-blocking socket connect * @param sd socket to connect * @param addr address to connect to + * @param source optional source address * @param timeout connect timeout in seconds (ignored!) * @param l logger * @return -1: some kind of error occured * 0: success */ -static int nb_connect(jk_sock_t sd, jk_sockaddr_t *addr, int timeout, jk_logger_t *l) +static int nb_connect(jk_sock_t sd, jk_sockaddr_t *addr, jk_sockaddr_t *source, + int timeout, jk_logger_t *l) { int rc; + char buf[64]; JK_TRACE_ENTER(l); + if (source != NULL) { + if (bind(sd, (const struct sockaddr *)&source->sa.sin, source->salen)) { + JK_GET_SOCKET_ERRNO(); + jk_log(l, JK_LOG_ERROR, + "error during source bind on socket %d [%s] (errno=%d)", + sd, jk_dump_hinfo(source, buf, sizeof(buf)), errno); + } + } rc = connect(sd, (const struct sockaddr *)&addr->sa.sin, addr->salen); JK_TRACE_EXIT(l); return rc; @@ -580,7 +613,8 @@ int jk_resolve(const char *host, int por * created socket: success * @remark Cares about errno */ -jk_sock_t jk_open_socket(jk_sockaddr_t *addr, int keepalive, +jk_sock_t jk_open_socket(jk_sockaddr_t *addr, jk_sockaddr_t *source, + int keepalive, int timeout, int connect_timeout, int sock_buf, jk_logger_t *l) { @@ -767,11 +801,11 @@ jk_sock_t jk_open_socket(jk_sockaddr_t * jk_dump_hinfo(addr, buf, sizeof(buf))); /* Need more infos for BSD 4.4 and Unix 98 defines, for now only -iSeries when Unix98 is required at compil time */ +iSeries when Unix98 is required at compile time */ #if (_XOPEN_SOURCE >= 520) && defined(AS400) ((struct sockaddr *)addr)->sa.sin.sa_len = sizeof(struct sockaddr_in); #endif - ret = nb_connect(sd, addr, connect_timeout, l); + ret = nb_connect(sd, addr, source, connect_timeout, l); #if defined(WIN32) || (defined(NETWARE) && defined(__NOVELL_LIBC__)) if (JK_IS_SOCKET_ERROR(ret)) { JK_GET_SOCKET_ERRNO(); Modified: tomcat/jk/trunk/native/common/jk_connect.h URL: http://svn.apache.org/viewvc/tomcat/jk/trunk/native/common/jk_connect.h?rev=1658173&r1=1658172&r2=1658173&view=diff ============================================================================== --- tomcat/jk/trunk/native/common/jk_connect.h (original) +++ tomcat/jk/trunk/native/common/jk_connect.h Sun Feb 8 14:28:10 2015 @@ -43,7 +43,8 @@ void jk_clone_sockaddr(jk_sockaddr_t *ou int jk_resolve(const char *host, int port, jk_sockaddr_t *rc, void *pool, int prefer_ipv6, jk_logger_t *l); -jk_sock_t jk_open_socket(jk_sockaddr_t *addr, int keepalive, +jk_sock_t jk_open_socket(jk_sockaddr_t *addr, jk_sockaddr_t *source, + int keepalive, int timeout, int connect_timeout, int sock_buf, jk_logger_t *l); Modified: tomcat/jk/trunk/native/common/jk_status.c URL: http://svn.apache.org/viewvc/tomcat/jk/trunk/native/common/jk_status.c?rev=1658173&r1=1658172&r2=1658173&view=diff ============================================================================== --- tomcat/jk/trunk/native/common/jk_status.c (original) +++ tomcat/jk/trunk/native/common/jk_status.c Sun Feb 8 14:28:10 2015 @@ -155,6 +155,7 @@ #define JK_STATUS_ARG_AJP_TEXT_HOST_STR "Hostname" #define JK_STATUS_ARG_AJP_TEXT_PORT "Port" #define JK_STATUS_ARG_AJP_TEXT_ADDR_STR "Address:Port" +#define JK_STATUS_ARG_AJP_TEXT_SOURCE_STR "Source" #define JK_STATUS_ARG_AJP_HEAD_CACHE_TO "Connection<br/>Pool Timeout" #define JK_STATUS_ARG_AJP_HEAD_PING_TO "Ping<br/>Timeout" @@ -170,6 +171,7 @@ #define JK_STATUS_ARG_AJP_HEAD_HOST_STR "Hostname" #define JK_STATUS_ARG_AJP_HEAD_PORT "Port" #define JK_STATUS_ARG_AJP_HEAD_ADDR_STR "Address:Port" +#define JK_STATUS_ARG_AJP_HEAD_SOURCE_STR "Source" #define JK_STATUS_CMD_UNKNOWN (0) #define JK_STATUS_CMD_LIST (1) @@ -274,6 +276,7 @@ "<th>Type</th>" \ "<th>" JK_STATUS_ARG_AJP_HEAD_HOST_STR "</th>" \ "<th>" JK_STATUS_ARG_AJP_HEAD_ADDR_STR "</th>" \ + "<th>" JK_STATUS_ARG_AJP_HEAD_SOURCE_STR "</th>" \ "<th>" JK_STATUS_ARG_AJP_HEAD_CACHE_TO "</th>" \ "<th>" JK_STATUS_ARG_AJP_HEAD_CONNECT_TO "</th>" \ "<th>" JK_STATUS_ARG_AJP_HEAD_PREPOST_TO "</th>" \ @@ -287,6 +290,7 @@ "<td>%s</td>" \ "<td>%s</td>" \ "<td>%s</td>" \ + "<td>%s</td>" \ "<td>%d</td>" \ "<td>%d</td>" \ "<td>%d</td>" \ @@ -379,6 +383,7 @@ "<th>Name</th><th>Type</th>" \ "<th>" JK_STATUS_ARG_AJP_HEAD_HOST_STR "</th>" \ "<th>" JK_STATUS_ARG_AJP_HEAD_ADDR_STR "</th>" \ + "<th>" JK_STATUS_ARG_AJP_HEAD_SOURCE_STR "</th>" \ "<th>" JK_STATUS_ARG_AJP_HEAD_CACHE_TO "</th>" \ "<th>" JK_STATUS_ARG_AJP_HEAD_CONNECT_TO "</th>" \ "<th>" JK_STATUS_ARG_AJP_HEAD_PREPOST_TO "</th>" \ @@ -393,6 +398,7 @@ "<td>%s</td>" \ "<td>%s</td>" \ "<td>%s</td>" \ + "<td>%s</td>" \ "<td>%d</td>" \ "<td>%d</td>" \ "<td>%d</td>" \ @@ -1799,6 +1805,7 @@ static void display_worker_ajp_conf_deta status_worker_type(type), aw->host, dump_ajp_addr(aw, buf, sizeof(buf)), + aw->source && *aw->source ? aw->source : "undefined", aw->cache_timeout, aw->connect_timeout, aw->prepost_timeout, @@ -1812,6 +1819,7 @@ static void display_worker_ajp_conf_deta status_worker_type(type), aw->host, dump_ajp_addr(aw, buf, sizeof(buf)), + aw->source && *aw->source ? aw->source : "undefined", aw->cache_timeout, aw->connect_timeout, aw->prepost_timeout, @@ -1960,6 +1968,7 @@ static void display_worker_ajp_details(j jk_print_xml_att_string(s, l, off+2, "host", aw->host); jk_print_xml_att_int(s, l, off+2, "port", aw->port); jk_print_xml_att_string(s, l, off+2, "address", dump_ajp_addr(aw, buf, sizeof(buf))); + jk_print_xml_att_string(s, l, off+2, "source", aw->source && *aw->source ? aw->source : "undefined"); jk_print_xml_att_int(s, l, off+2, "connection_pool_timeout", aw->cache_timeout); jk_print_xml_att_int(s, l, off+2, "ping_timeout", aw->ping_timeout); jk_print_xml_att_int(s, l, off+2, "connect_timeout", aw->connect_timeout); @@ -2029,6 +2038,7 @@ static void display_worker_ajp_details(j jk_printf(s, l, " host=%s", aw->host); jk_printf(s, l, " port=%d", aw->port); jk_printf(s, l, " address=%s", dump_ajp_addr(aw, buf, sizeof(buf))); + jk_printf(s, l, " source=%s", aw->source && *aw->source ? aw->source : "undefined"); jk_printf(s, l, " connection_pool_timeout=%d", aw->cache_timeout); jk_printf(s, l, " ping_timeout=%d", aw->ping_timeout); jk_printf(s, l, " connect_timeout=%d", aw->connect_timeout); @@ -2095,6 +2105,7 @@ static void display_worker_ajp_details(j jk_print_prop_att_string(s, l, w, ajp_name, "host", aw->host); jk_print_prop_att_int(s, l, w, ajp_name, "port", aw->port); jk_print_prop_att_string(s, l, w, ajp_name, "address", dump_ajp_addr(aw, buf, sizeof(buf))); + jk_print_prop_att_string(s, l, w, ajp_name, "source", aw->source && *aw->source ? aw->source : "undefined"); jk_print_prop_att_int(s, l, w, ajp_name, "connection_pool_timeout", aw->cache_timeout); jk_print_prop_att_int(s, l, w, ajp_name, "ping_timeout", aw->ping_timeout); jk_print_prop_att_int(s, l, w, ajp_name, "connect_timeout", aw->connect_timeout); Modified: tomcat/jk/trunk/native/common/jk_util.c URL: http://svn.apache.org/viewvc/tomcat/jk/trunk/native/common/jk_util.c?rev=1658173&r1=1658172&r2=1658173&view=diff ============================================================================== --- tomcat/jk/trunk/native/common/jk_util.c (original) +++ tomcat/jk/trunk/native/common/jk_util.c Sun Feb 8 14:28:10 2015 @@ -45,6 +45,7 @@ #define NATIVE_LIB_OF_WORKER "native_lib" #define REFERENCE_OF_WORKER "reference" #define HOST_OF_WORKER "host" +#define SOURCE_OF_WORKER "source" #define PORT_OF_WORKER "port" #define TYPE_OF_WORKER "type" #define CACHE_OF_WORKER_DEPRECATED "cachesize" @@ -183,6 +184,7 @@ static const char *unique_properties[] = SECRET_OF_WORKER, REFERENCE_OF_WORKER, HOST_OF_WORKER, + SOURCE_OF_WORKER, PORT_OF_WORKER, TYPE_OF_WORKER, CACHE_OF_WORKER_DEPRECATED, @@ -279,6 +281,7 @@ static const char *supported_properties[ NATIVE_LIB_OF_WORKER, REFERENCE_OF_WORKER, HOST_OF_WORKER, + SOURCE_OF_WORKER, PORT_OF_WORKER, TYPE_OF_WORKER, CACHE_OF_WORKER_DEPRECATED, @@ -906,6 +909,19 @@ const char *jk_get_worker_host(jk_map_t return jk_map_get_string(m, buf, def); } + +const char *jk_get_worker_source(jk_map_t *m, const char *wname, const char *def) +{ + char buf[PARAM_BUFFER_SIZE]; + + if (!m || !wname) { + return NULL; + } + + MAKE_WORKER_PARAM(SOURCE_OF_WORKER); + + return jk_map_get_string(m, buf, def); +} int jk_get_worker_port(jk_map_t *m, const char *wname, int def) { Modified: tomcat/jk/trunk/native/common/jk_util.h URL: http://svn.apache.org/viewvc/tomcat/jk/trunk/native/common/jk_util.h?rev=1658173&r1=1658172&r2=1658173&view=diff ============================================================================== --- tomcat/jk/trunk/native/common/jk_util.h (original) +++ tomcat/jk/trunk/native/common/jk_util.h Sun Feb 8 14:28:10 2015 @@ -63,6 +63,8 @@ int jk_check_attribute_length(const char const char *jk_get_worker_host(jk_map_t *m, const char *wname, const char *def); +const char *jk_get_worker_source(jk_map_t *m, const char *wname, const char *def); + const char *jk_get_worker_type(jk_map_t *m, const char *wname); int jk_get_worker_port(jk_map_t *m, const char *wname, int def); Modified: tomcat/jk/trunk/xdocs/miscellaneous/changelog.xml URL: http://svn.apache.org/viewvc/tomcat/jk/trunk/xdocs/miscellaneous/changelog.xml?rev=1658173&r1=1658172&r2=1658173&view=diff ============================================================================== --- tomcat/jk/trunk/xdocs/miscellaneous/changelog.xml (original) +++ tomcat/jk/trunk/xdocs/miscellaneous/changelog.xml Sun Feb 8 14:28:10 2015 @@ -210,6 +210,11 @@ "no usable connection found, will create a new one". Tone done from info log level to debug for the common case. (rjung) </fix> + <add> + <bug>57536</bug>: AJP: Allow to configure connection source address. + This should only be used on multi-homed hosts. The feature is + experimental. (rjung) + </add> </changelog> </subsection> </section> Modified: tomcat/jk/trunk/xdocs/reference/workers.xml URL: http://svn.apache.org/viewvc/tomcat/jk/trunk/xdocs/reference/workers.xml?rev=1658173&r1=1658172&r2=1658173&view=diff ============================================================================== --- tomcat/jk/trunk/xdocs/reference/workers.xml (original) +++ tomcat/jk/trunk/xdocs/reference/workers.xml Sun Feb 8 14:28:10 2015 @@ -253,6 +253,14 @@ The default value depends on the worker <b>8009</b>, while for ajp14 type of worker that value is <b>8011</b>. </directive> +<directive name="source" default="" required="false"> +Name or IP address used for the connection source (outgoing address). +It should only be used on multi-homed hosts. +<p> +This feature is experimental and has been added in <b>jk 1.2.41</b>. +</p> +</directive> + <directive name="socket_timeout" default="0" required="false"> Socket timeout in seconds used for the communication channel between JK and remote host. If the remote host does not respond inside the timeout specified, JK will generate an error, --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org