Permalink
Browse files

Enhances the handle_proxy so it can handle multi-IP sources nicely.

The proxy handler will try to use the different IPs returned by the
DNS in case some of them is not reachable.

git-svn-id: svn://cherokee-project.com/cherokee/trunk@6882 5dc97367-97f1-0310-9951-d761b3857238
  • Loading branch information...
1 parent d5dc944 commit d2e7b9541655c69dcf797ae235e6e76b9f82c930 @alobbs alobbs committed Oct 6, 2011
Showing with 149 additions and 41 deletions.
  1. +1 −1 cherokee/access.c
  2. +17 −1 cherokee/handler_proxy.c
  3. +73 −23 cherokee/proxy_hosts.c
  4. +9 −5 cherokee/proxy_hosts.h
  5. +28 −6 cherokee/resolv_cache.c
  6. +19 −3 cherokee/socket.c
  7. +1 −1 cherokee/socket.h
  8. +1 −1 cherokee/source.c
View
2 cherokee/access.c
@@ -342,7 +342,7 @@ cherokee_access_add_domain (cherokee_access_t *entry, char *domain)
while (addr != NULL) {
ret = cherokee_ntop (addr->ai_family, addr->ai_addr, ip, sizeof(ip));
if (unlikely(ret!=ret_ok)) return ret;
-
+
TRACE (ENTRIES, "Access: domain '%s' -> IP: %s\n", domain, ip);
ret = cherokee_access_add_ip (entry, (char *)ip);
if (unlikely(ret!=ret_ok)) return ret;
View
18 cherokee/handler_proxy.c
@@ -933,6 +933,14 @@ cherokee_handler_proxy_init (cherokee_handler_proxy_t *hdl)
hdl->init_phase = proxy_init_preconnect;
TRACE(ENTRIES, "Entering phase '%s'\n", "preconnect");
+ /* Get the addrinfo object */
+ if (hdl->pconn->addr_info_ref == NULL) {
+ ret = cherokee_handler_proxy_conn_get_addrinfo (hdl->pconn, hdl->src_ref);
+ if (ret != ret_ok) {
+ return ret_error;
+ }
+ }
+
case proxy_init_preconnect:
/* Configure if respinned
*/
@@ -959,7 +967,7 @@ cherokee_handler_proxy_init (cherokee_handler_proxy_t *hdl)
if (! cherokee_socket_configured (&hdl->pconn->socket))
{
- ret = cherokee_proxy_util_init_socket (&hdl->pconn->socket, hdl->src_ref);
+ ret = cherokee_handler_proxy_conn_init_socket (hdl->pconn, hdl->src_ref);
if (ret != ret_ok) {
hdl->pconn->keepalive_in = false;
conn->error_code = http_bad_gateway;
@@ -985,6 +993,14 @@ cherokee_handler_proxy_init (cherokee_handler_proxy_t *hdl)
case ret_eagain:
return ret_eagain;
case ret_deny:
+ /* Multiple IPs on a single source */
+ if (hdl->pconn->addr_current < hdl->pconn->addr_total) {
+ hdl->pconn->addr_current += 1;
+ cherokee_socket_close (&hdl->pconn->socket);
+ cherokee_socket_clean (&hdl->pconn->socket);
+ goto reconnect;
+ }
+
if (hdl->respinned) {
cherokee_balancer_report_fail (props->balancer, conn, hdl->src_ref);
conn->error_code = http_bad_gateway;
View
96 cherokee/proxy_hosts.c
@@ -176,7 +176,13 @@ cherokee_handler_proxy_poll_get (cherokee_handler_proxy_poll_t *poll,
if (ret != ret_ok)
goto error;
- ret = cherokee_proxy_util_init_socket (&n->socket, src);
+ ret = cherokee_handler_proxy_conn_get_addrinfo (n, src);
+ if (ret != ret_ok) {
+ cherokee_handler_proxy_conn_free (n);
+ goto error;
+ }
+
+ ret = cherokee_handler_proxy_conn_init_socket (n, src);
if (ret != ret_ok) {
cherokee_handler_proxy_conn_free (n);
goto error;
@@ -266,6 +272,9 @@ cherokee_handler_proxy_conn_new (cherokee_handler_proxy_conn_t **pconn)
n->size_in = 0;
n->sent_out = 0;
n->enc = pconn_enc_none;
+ n->addr_total = 0;
+ n->addr_current = 0;
+ n->addr_info_ref = NULL;
*pconn = n;
return ret_ok;
@@ -432,50 +441,91 @@ cherokee_handler_proxy_conn_recv_headers (cherokee_handler_proxy_conn_t *pconn,
*/
ret_t
-cherokee_proxy_util_init_socket (cherokee_socket_t *socket,
- cherokee_source_t *src)
+cherokee_handler_proxy_conn_init_socket (cherokee_handler_proxy_conn_t *pconn,
+ cherokee_source_t *src)
{
- ret_t ret;
- cherokee_resolv_cache_t *resolv;
- const struct addrinfo *addr_info = NULL;
+ ret_t ret;
+ cherokee_socket_t *socket = &pconn->socket;
TRACE (ENTRIES, "Initializing proxy %s\n", "socket");
- /* Resolve the hostname of the target server */
- ret = cherokee_resolv_cache_get_default (&resolv);
- if (unlikely (ret != ret_ok)) {
- return ret_error;
- }
-
- ret = cherokee_resolv_cache_get_addrinfo (resolv, &src->host, &addr_info);
- if ((ret != ret_ok) || (addr_info == NULL)) {
- return ret_error;
- }
-
/* Ensure that no fd leak happens */
cherokee_socket_close (socket);
/* Create the socket descriptor */
- ret = cherokee_socket_create_fd (socket, addr_info->ai_family);
+ ret = cherokee_socket_create_fd (socket, pconn->addr_info_ref->ai_family);
if (unlikely (ret != ret_ok)) {
return ret_error;
}
/* Update the new socket */
- SOCKET_SIN_PORT(socket) = htons (src->port);
-
- ret = cherokee_socket_update_from_addrinfo (socket, addr_info);
+ ret = cherokee_socket_update_from_addrinfo (socket, pconn->addr_info_ref, pconn->addr_current);
if (unlikely (ret != ret_ok)) {
return ret_error;
}
- TRACE (ENTRIES, "Proxy socket Initialized: %s, target: %s\n",
- SOCKET_AF(socket) == AF_INET6 ? "IPv6": "IPv4", src->host.buf);
+ SOCKET_SIN_PORT(socket) = htons (src->port);
/* Set a few properties */
cherokee_fd_set_closexec (socket->socket);
cherokee_fd_set_nonblocking (socket->socket, true);
cherokee_fd_set_nodelay (socket->socket, true);
+ /* Trace */
+#ifdef TRACE_ENABLED
+ if (cherokee_trace_is_tracing()) {
+ cuint_t ip_num;
+ struct addrinfo *ai;
+ char buf[50];
+
+ ai = pconn->addr_info_ref;
+ ip_num = pconn->addr_current;
+
+ while (ip_num--) {
+ ai = ai->ai_next;
+ }
+
+ ret = cherokee_ntop (pconn->addr_info_ref->ai_family, ai->ai_addr, buf, 50);
+ if (ret == ret_ok) {
+ TRACE (ENTRIES, "Proxy socket Initialized: %s, target: %s, IP: %s\n",
+ SOCKET_AF(socket) == AF_INET6 ? "IPv6": "IPv4", src->host.buf, buf);
+ }
+ }
+#endif
+
+ return ret_ok;
+}
+
+
+ret_t
+cherokee_handler_proxy_conn_get_addrinfo (cherokee_handler_proxy_conn_t *pconn,
+ cherokee_source_t *src)
+{
+ ret_t ret;
+ struct addrinfo *ai;
+ cherokee_resolv_cache_t *resolv;
+
+ /* Resolve the hostname of the target server
+ */
+ ret = cherokee_resolv_cache_get_default (&resolv);
+ if (unlikely (ret != ret_ok)) {
+ return ret_error;
+ }
+
+ ret = cherokee_resolv_cache_get_addrinfo (resolv, &src->host, &pconn->addr_info_ref);
+ if ((ret != ret_ok) || (pconn->addr_info_ref == NULL)) {
+ return ret_error;
+ }
+
+ /* Count the number of IPs
+ */
+ if (pconn->addr_total == 0) {
+ ai = pconn->addr_info_ref;
+ while (ai != NULL) {
+ pconn->addr_total += 1;
+ ai = ai->ai_next;
+ }
+ }
+
return ret_ok;
}
View
14 cherokee/proxy_hosts.h
@@ -57,6 +57,11 @@ typedef struct {
cherokee_socket_t socket;
cherokee_handler_proxy_poll_t *poll_ref;
+ /* Name resolution */
+ const struct addrinfo *addr_info_ref;
+ cuint_t addr_total;
+ cuint_t addr_current;
+
/* In */
cherokee_handler_proxy_enc_t enc;
cherokee_buffer_t header_in_raw;
@@ -107,11 +112,10 @@ ret_t cherokee_handler_proxy_conn_send (cherokee_handler_proxy_conn_t *
ret_t cherokee_handler_proxy_conn_recv_headers (cherokee_handler_proxy_conn_t *pconn,
cherokee_buffer_t *body,
cherokee_boolean_t flexible);
-
-/* Utils
- */
-ret_t cherokee_proxy_util_init_socket (cherokee_socket_t *socket,
- cherokee_source_t *src);
+ret_t cherokee_handler_proxy_conn_get_addrinfo (cherokee_handler_proxy_conn_t *pconn,
+ cherokee_source_t *src);
+ret_t cherokee_handler_proxy_conn_init_socket (cherokee_handler_proxy_conn_t *pconn,
+ cherokee_source_t *src);
#endif /* CHEROKEE_HANDLER_PROXY_HOSTS_H */
View
34 cherokee/resolv_cache.c
@@ -45,6 +45,7 @@
typedef struct {
struct addrinfo *addr;
cherokee_buffer_t ip_str;
+ cherokee_buffer_t ip_str_all;
} cherokee_resolv_cache_entry_t;
struct cherokee_resolv_cache {
@@ -64,6 +65,7 @@ entry_new (cherokee_resolv_cache_entry_t **entry)
n->addr = NULL;
cherokee_buffer_init (&n->ip_str);
+ cherokee_buffer_init (&n->ip_str_all);
*entry = n;
return ret_ok;
@@ -80,6 +82,7 @@ entry_free (void *entry)
}
cherokee_buffer_mrproper (&e->ip_str);
+ cherokee_buffer_mrproper (&e->ip_str_all);
free(entry);
}
@@ -88,9 +91,10 @@ static ret_t
entry_fill_up (cherokee_resolv_cache_entry_t *entry,
cherokee_buffer_t *domain)
{
- ret_t ret;
- char tmp[46]; // Max IPv6 length is 45
- time_t eagain_at = 0;
+ ret_t ret;
+ char tmp[46]; // Max IPv6 length is 45
+ struct addrinfo *addr;
+ time_t eagain_at = 0;
while (true) {
ret = cherokee_gethostbyname (domain->buf, &entry->addr);
@@ -126,6 +130,24 @@ entry_fill_up (cherokee_resolv_cache_entry_t *entry,
}
cherokee_buffer_add (&entry->ip_str, tmp, strlen(tmp));
+
+ /* Render the text representation (all the IPs)
+ */
+ cherokee_buffer_add_buffer (&entry->ip_str_all, &entry->ip_str);
+
+ addr = entry->addr;
+ while (addr != NULL) {
+ ret = cherokee_ntop (entry->addr->ai_family, addr->ai_addr, tmp, sizeof(tmp));
+ if (ret != ret_ok) {
+ return ret_error;
+ }
+
+ cherokee_buffer_add_char (&entry->ip_str_all, ',');
+ cherokee_buffer_add (&entry->ip_str_all, tmp, strlen(tmp));
+
+ addr = addr->ai_next;
+ }
+
return ret_ok;
}
@@ -246,9 +268,9 @@ cherokee_resolv_cache_get_ipstr (cherokee_resolv_cache_t *resolv,
if (ret != ret_ok) {
return ret;
}
- TRACE (ENTRIES, "Resolve '%s': added succesfuly as '%s'.\n", domain->buf, entry->ip_str.buf);
+ TRACE (ENTRIES, "Resolve '%s': added succesfuly as '%s'.\n", domain->buf, entry->ip_str_all.buf);
} else {
- TRACE (ENTRIES, "Resolve '%s': hit.\n", domain->buf);
+ TRACE (ENTRIES, "Resolve '%s': hit: %s\n", domain->buf, entry->ip_str_all.buf);
}
/* Return the ip string
@@ -279,7 +301,7 @@ cherokee_resolv_cache_get_host (cherokee_resolv_cache_t *resolv,
/* Copy it to the socket object
*/
- ret = cherokee_socket_update_from_addrinfo (sock, addr);
+ ret = cherokee_socket_update_from_addrinfo (sock, addr, 0);
if (ret != ret_ok) {
return ret;
}
View
22 cherokee/socket.c
@@ -367,20 +367,36 @@ cherokee_socket_set_sockaddr (cherokee_socket_t *socket, int fd, cherokee_sockad
ret_t
cherokee_socket_update_from_addrinfo (cherokee_socket_t *socket,
- const struct addrinfo *addr)
+ const struct addrinfo *addr,
+ cuint_t num)
{
+ struct addrinfo *ai;
+
if (unlikely (addr == NULL))
return ret_error;
+ /* Find the right address
+ */
+ ai = addr;
+ while (num > 0) {
+ num -= 1;
+ ai = ai->ai_next;
+ if (ai == NULL) {
+ return ret_not_found;
+ }
+ }
+
+ /* Copy the information
+ */
SOCKET_AF(socket) = addr->ai_family;
socket->client_addr_len = addr->ai_addrlen;
switch (addr->ai_family) {
case AF_INET:
- memcpy (&SOCKET_SIN_ADDR(socket), &((struct sockaddr_in *) addr->ai_addr)->sin_addr, sizeof(struct in_addr));
+ memcpy (&SOCKET_SIN_ADDR(socket), &((struct sockaddr_in *) ai->ai_addr)->sin_addr, sizeof(struct in_addr));
break;
case AF_INET6:
- memcpy (&SOCKET_SIN6_ADDR(socket), &((struct sockaddr_in6 *) addr->ai_addr)->sin6_addr, sizeof(struct in6_addr));
+ memcpy (&SOCKET_SIN6_ADDR(socket), &((struct sockaddr_in6 *) ai->ai_addr)->sin6_addr, sizeof(struct in6_addr));
break;
default:
SHOULDNT_HAPPEN;
View
2 cherokee/socket.h
@@ -150,6 +150,6 @@ ret_t cherokee_socket_writev (cherokee_socket_t *socket, const struct iovec *vec
/* Extra
*/
ret_t cherokee_socket_set_sockaddr (cherokee_socket_t *socket, int fd, cherokee_sockaddr_t *sa);
-ret_t cherokee_socket_update_from_addrinfo (cherokee_socket_t *socket, const struct addrinfo *addr_info);
+ret_t cherokee_socket_update_from_addrinfo (cherokee_socket_t *socket, const struct addrinfo *addr_info, cuint_t num);
#endif /* CHEROKEE_SOCKET_H */
View
2 cherokee/source.c
@@ -119,7 +119,7 @@ cherokee_source_connect (cherokee_source_t *src, cherokee_socket_t *sock)
/* Update the new socket */
SOCKET_ADDR_IPv4(sock)->sin_port = htons(src->port);
- ret = cherokee_socket_update_from_addrinfo (sock, addr_info);
+ ret = cherokee_socket_update_from_addrinfo (sock, addr_info, 0);
if (unlikely (ret != ret_ok)) {
return ret_error;
}

0 comments on commit d2e7b95

Please sign in to comment.