From 0c7f0405e36c45c88139189dd4c720aa0c4903f5 Mon Sep 17 00:00:00 2001 From: Azat Khuzhin Date: Tue, 1 Oct 2013 19:12:13 +0400 Subject: [PATCH] http: implement new evhttp_connection_get_addr() api. Basically tcp final handshake looks like this: (C - client, S - server) ACK[C] - FIN/ACK[S] - FIN/ACK[S] - ACK [C] However there are servers, that didn't close connection like this, while it is still _considered_ as valid, and using libevent http layer we can do requests to such servers. Modified handshake: (C - client, S - server) ACK[C] - RST/ACK[S] - RST/ACK[S] And in this case we can't extract IP address from socket, because it is already closed, and getpeername() will return: "transport endpoint is not connected". So we need to store address that we are connecting to, after we know it, and that is what this patch do. I have reproduced it, however it have some extra packages. (I will try to fix it) https://github.com/azat/nfq-examples/blob/master/nfqnl_rst_fin.c --- http-internal.h | 7 +++++++ http.c | 18 ++++++++++++++++++ include/event2/http.h | 9 +++++++++ 3 files changed, 34 insertions(+) diff --git a/http-internal.h b/http-internal.h index d25753bb..82dd402a 100644 --- a/http-internal.h +++ b/http-internal.h @@ -99,6 +99,13 @@ struct evhttp_connection { struct event_base *base; struct evdns_base *dns_base; + + /* 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 5600e2fc..e8672b77 100644 --- a/http.c +++ b/http.c @@ -1168,6 +1168,9 @@ 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); } @@ -1404,6 +1407,7 @@ 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); @@ -1454,6 +1458,14 @@ 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, @@ -2348,6 +2360,12 @@ evhttp_connection_get_peer(struct evhttp_connection *evcon, *port = evcon->port; } +const struct sockaddr* +evhttp_connection_get_addr(struct evhttp_connection *evcon) +{ + return (struct sockaddr *)evcon->conn_address; +} + int evhttp_connection_connect_(struct evhttp_connection *evcon) { diff --git a/include/event2/http.h b/include/event2/http.h index cf44941d..956d9d6c 100644 --- a/include/event2/http.h +++ b/include/event2/http.h @@ -614,6 +614,15 @@ void evhttp_connection_set_closecb(struct evhttp_connection *evcon, 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(). + * + * @return NULL if getpeername() return non success, + * or connection is not connected, + * otherwise it return pointer to struct sockaddr_storage */ +const struct sockaddr* +evhttp_connection_get_addr(struct evhttp_connection *evcon); + /** Make an HTTP request over the specified connection. -- 2.40.0