]> granicus.if.org Git - libevent/commitdiff
bufferevent: move conn_address out from http into bufferevent
authorAzat Khuzhin <a3at.mail@gmail.com>
Sat, 15 Nov 2014 18:46:11 +0000 (21:46 +0300)
committerAzat Khuzhin <a3at.mail@gmail.com>
Tue, 18 Aug 2015 17:06:52 +0000 (20:06 +0300)
In http the only case when when we could store it is when we already
connected, *but* if we are doing request using domain name, then we need
to do request to nameserver to get IP address, and this is handled by
bufferevent.
So when we have IP address (from nameserver) and don't have connection
to this IP address, we could already cache it to avoid extra DNS
requests (since UDP is slow), and we can't do this from http layer, only
from bufferevent.

bufferevent-internal.h
bufferevent_sock.c
http-internal.h
http.c
include/event2/http.h

index ad3dcfc9ebd465fe658ec8bc63696cad55f855c4..ac32384c5e2f3be1a0d492a56681fb6da85a6457 100644 (file)
@@ -205,6 +205,15 @@ struct bufferevent_private {
 
        /** Rate-limiting information for this bufferevent */
        struct bufferevent_rate_limit *rate_limiting;
+
+       /* Saved conn_addr, to extract IP address from it.
+        *
+        * Because some servers may reset/close connection without waiting clients,
+        * in that case we can't extract IP address even in close_cb.
+        * So we need to save it, just after we connected to remote server, or
+        * after resolving (to avoid extra dns requests during retrying, since UDP
+        * is slow) */
+       struct sockaddr_storage *conn_address;
 };
 
 /** Possible operations for a control callback. */
@@ -392,6 +401,9 @@ int bufferevent_generic_adj_timeouts_(struct bufferevent *bev);
 
 enum bufferevent_options bufferevent_get_options_(struct bufferevent *bev);
 
+const struct sockaddr*
+bufferevent_socket_get_conn_address_(struct bufferevent *bev);
+
 /** Internal use: We have just successfully read data into an inbuf, so
  * reset the read timeout (if any). */
 #define BEV_RESET_GENERIC_READ_TIMEOUT(bev)                            \
index fce73b91def0c15180ff9dc9f8cf10969da3f886..ef1b7e435b93060354653752f6c5dc9d694d79dc 100644 (file)
@@ -100,6 +100,37 @@ const struct bufferevent_ops bufferevent_ops_socket = {
 #define be_socket_add(ev, t)                   \
        bufferevent_add_event_((ev), (t))
 
+const struct sockaddr*
+bufferevent_socket_get_conn_address_(struct bufferevent *bev)
+{
+       struct bufferevent_private *bev_p =
+           EVUTIL_UPCAST(bev, struct bufferevent_private, bev);
+
+       return (struct sockaddr *)bev_p->conn_address;
+}
+static void
+bufferevent_socket_set_conn_address_fd(struct bufferevent_private *bev_p, int fd)
+{
+       socklen_t len = sizeof(*bev_p->conn_address);
+
+       if (!bev_p->conn_address) {
+               bev_p->conn_address = mm_malloc(sizeof(*bev_p->conn_address));
+       }
+       if (getpeername(fd, (struct sockaddr *)bev_p->conn_address, &len)) {
+               mm_free(bev_p->conn_address);
+               bev_p->conn_address = NULL;
+       }
+}
+static void
+bufferevent_socket_set_conn_address(struct bufferevent_private *bev_p,
+       struct sockaddr *addr, size_t addrlen)
+{
+       if (!bev_p->conn_address) {
+               bev_p->conn_address = mm_malloc(sizeof(*bev_p->conn_address));
+       }
+       memcpy(bev_p->conn_address, addr, addrlen);
+}
+
 static void
 bufferevent_socket_outbuf_cb(struct evbuffer *buf,
     const struct evbuffer_cb_info *cbinfo,
@@ -239,6 +270,7 @@ bufferevent_writecb(evutil_socket_t fd, short event, void *arg)
                        goto done;
                } else {
                        connected = 1;
+                       bufferevent_socket_set_conn_address_fd(bufev_p, fd);
 #ifdef _WIN32
                        if (BEV_IS_ASYNC(bufev)) {
                                event_del(&bufev->ev_write);
@@ -457,6 +489,7 @@ bufferevent_connect_getaddrinfo_cb(int result, struct evutil_addrinfo *ai,
 
        /* XXX use the other addrinfos? */
        /* XXX use this return value */
+       bufferevent_socket_set_conn_address(bev_p, ai->ai_addr, (int)ai->ai_addrlen);
        r = bufferevent_socket_connect(bev, ai->ai_addr, (int)ai->ai_addrlen);
        (void)r;
        bufferevent_decref_and_unlock_(bev);
@@ -590,6 +623,9 @@ be_socket_destruct(struct bufferevent *bufev)
 
        if ((bufev_p->options & BEV_OPT_CLOSE_ON_FREE) && fd >= 0)
                EVUTIL_CLOSESOCKET(fd);
+
+       mm_free(bufev_p->conn_address);
+       bufev_p->conn_address = NULL;
 }
 
 static int
index a83160c8341b8ae9e348f15526c13356c2581b7a..6e1b21477169e4792e281dc967e0fd9a3d78b287 100644 (file)
@@ -101,13 +101,6 @@ struct evhttp_connection {
        struct event_base *base;
        struct evdns_base *dns_base;
        int ai_family;
-
-       /* Saved conn_addr, to extract IP address from it.
-        *
-        * Because some servers may reset/close connection without waiting clients,
-        * in that case we can't extract IP address even in close_cb.
-        * So we need to save it, just after we connected to remote server. */
-       struct sockaddr_storage *conn_address;
 };
 
 /* A callback for an http server */
diff --git a/http.c b/http.c
index 55242d84ad4df7c2702cf2d02660d53d8148f6e2..ad5e7612a5b1abd49a922a5105a6f96d1a30b501 100644 (file)
--- a/http.c
+++ b/http.c
@@ -1196,9 +1196,6 @@ evhttp_connection_free(struct evhttp_connection *evcon)
        if (evcon->address != NULL)
                mm_free(evcon->address);
 
-       if (evcon->conn_address != NULL)
-               mm_free(evcon->conn_address);
-
        mm_free(evcon);
 }
 
@@ -1452,7 +1449,6 @@ evhttp_connection_cb(struct bufferevent *bufev, short what, void *arg)
        struct evhttp_connection *evcon = arg;
        int error;
        ev_socklen_t errsz = sizeof(error);
-       socklen_t conn_address_len = sizeof(*evcon->conn_address);
 
        if (evcon->fd == -1)
                evcon->fd = bufferevent_getfd(bufev);
@@ -1503,14 +1499,6 @@ evhttp_connection_cb(struct bufferevent *bufev, short what, void *arg)
        evcon->retry_cnt = 0;
        evcon->state = EVCON_IDLE;
 
-       if (!evcon->conn_address) {
-               evcon->conn_address = mm_malloc(sizeof(*evcon->conn_address));
-       }
-       if (getpeername(evcon->fd, (struct sockaddr *)evcon->conn_address, &conn_address_len)) {
-               mm_free(evcon->conn_address);
-               evcon->conn_address = NULL;
-       }
-
        /* reset the bufferevent cbs */
        bufferevent_setcb(evcon->bufev,
            evhttp_read_cb,
@@ -2423,7 +2411,7 @@ evhttp_connection_get_peer(struct evhttp_connection *evcon,
 const struct sockaddr*
 evhttp_connection_get_addr(struct evhttp_connection *evcon)
 {
-       return (struct sockaddr *)evcon->conn_address;
+       return bufferevent_socket_get_conn_address_(evcon->bufev);
 }
 
 int
index 4284d5fc32bc21bffb8cde93c4422930616d0a67..689643ff7b296a946c0dd656b187d4ff7c2de0c0 100644 (file)
@@ -728,7 +728,7 @@ void evhttp_connection_get_peer(struct evhttp_connection *evcon,
     char **address, ev_uint16_t *port);
 
 /** Get the remote address associated with this connection.
- * extracted from getpeername().
+ * extracted from getpeername() OR from nameserver.
  *
  * @return NULL if getpeername() return non success,
  * or connection is not connected,