mirror of
https://github.com/cuberite/libevent.git
synced 2025-09-18 08:49:57 -04:00
support setting local address on an evhttp_connection
svn:r416
This commit is contained in:
parent
23866b7657
commit
98f9616bf4
@ -2,4 +2,5 @@ Changes in current version:
|
|||||||
o allow \r or \n individually to separate HTTP headers instead of the standard "\r\n"; from Charles Kerr.
|
o allow \r or \n individually to separate HTTP headers instead of the standard "\r\n"; from Charles Kerr.
|
||||||
o demote most http warnings to debug messages
|
o demote most http warnings to debug messages
|
||||||
o Fix Solaris compilation; from Magne Mahre
|
o Fix Solaris compilation; from Magne Mahre
|
||||||
o Add a "Date" header to HTTP responses, as required by HTTP 1.1.
|
o Add a "Date" header to HTTP responses, as required by HTTP 1.1.
|
||||||
|
o Support specifying the local address of an evhttp_connection using set_local_address
|
||||||
|
4
evhttp.h
4
evhttp.h
@ -196,6 +196,10 @@ struct evhttp_connection *evhttp_connection_new(
|
|||||||
/* Frees an http connection */
|
/* Frees an http connection */
|
||||||
void evhttp_connection_free(struct evhttp_connection *evcon);
|
void evhttp_connection_free(struct evhttp_connection *evcon);
|
||||||
|
|
||||||
|
/* sets the ip address from which http connections are made */
|
||||||
|
void evhttp_connection_set_local_address(struct evhttp_connection *evcon,
|
||||||
|
const char *address);
|
||||||
|
|
||||||
/* Sets the timeout for events related to this connection */
|
/* Sets the timeout for events related to this connection */
|
||||||
void evhttp_connection_set_timeout(struct evhttp_connection *evcon,
|
void evhttp_connection_set_timeout(struct evhttp_connection *evcon,
|
||||||
int timeout_in_secs);
|
int timeout_in_secs);
|
||||||
|
@ -39,7 +39,7 @@ struct event_base;
|
|||||||
|
|
||||||
struct evhttp_connection {
|
struct evhttp_connection {
|
||||||
/* we use tailq only if they were created for an http server */
|
/* we use tailq only if they were created for an http server */
|
||||||
TAILQ_ENTRY(evhttp_connection) next;
|
TAILQ_ENTRY(evhttp_connection) (next);
|
||||||
|
|
||||||
int fd;
|
int fd;
|
||||||
struct event ev;
|
struct event ev;
|
||||||
@ -47,7 +47,9 @@ struct evhttp_connection {
|
|||||||
struct evbuffer *input_buffer;
|
struct evbuffer *input_buffer;
|
||||||
struct evbuffer *output_buffer;
|
struct evbuffer *output_buffer;
|
||||||
|
|
||||||
char *address;
|
char *bind_address; /* address to use for binding the src */
|
||||||
|
|
||||||
|
char *address; /* address to connect to */
|
||||||
u_short port;
|
u_short port;
|
||||||
|
|
||||||
int flags;
|
int flags;
|
||||||
@ -66,7 +68,7 @@ struct evhttp_connection {
|
|||||||
|
|
||||||
TAILQ_HEAD(evcon_requestq, evhttp_request) requests;
|
TAILQ_HEAD(evcon_requestq, evhttp_request) requests;
|
||||||
|
|
||||||
void (*cb)(struct evhttp_connection *, void *);
|
void (*cb)(struct evhttp_connection *, void *);
|
||||||
void *cb_arg;
|
void *cb_arg;
|
||||||
|
|
||||||
void (*closecb)(struct evhttp_connection *, void *);
|
void (*closecb)(struct evhttp_connection *, void *);
|
||||||
|
172
http.c
172
http.c
@ -139,8 +139,9 @@ event_make_socket_nonblocking(int fd)
|
|||||||
|
|
||||||
extern int debug;
|
extern int debug;
|
||||||
|
|
||||||
static int make_socket_ai(int should_bind, struct addrinfo *);
|
static int socket_connect(int fd, const char *address, unsigned short port);
|
||||||
static int make_socket(int should_bind, const char *, u_short);
|
static int bind_socket_ai(struct addrinfo *);
|
||||||
|
static int bind_socket(const char *, u_short);
|
||||||
static void name_from_addr(struct sockaddr *, socklen_t, char **, char **);
|
static void name_from_addr(struct sockaddr *, socklen_t, char **, char **);
|
||||||
static int evhttp_associate_new_request_with_connection(
|
static int evhttp_associate_new_request_with_connection(
|
||||||
struct evhttp_connection *evcon);
|
struct evhttp_connection *evcon);
|
||||||
@ -823,6 +824,9 @@ evhttp_connection_free(struct evhttp_connection *evcon)
|
|||||||
if (evcon->fd != -1)
|
if (evcon->fd != -1)
|
||||||
close(evcon->fd);
|
close(evcon->fd);
|
||||||
|
|
||||||
|
if (evcon->bind_address != NULL)
|
||||||
|
free(evcon->bind_address);
|
||||||
|
|
||||||
if (evcon->address != NULL)
|
if (evcon->address != NULL)
|
||||||
free(evcon->address);
|
free(evcon->address);
|
||||||
|
|
||||||
@ -835,6 +839,18 @@ evhttp_connection_free(struct evhttp_connection *evcon)
|
|||||||
free(evcon);
|
free(evcon);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
evhttp_connection_set_local_address(struct evhttp_connection *evcon,
|
||||||
|
const char *address)
|
||||||
|
{
|
||||||
|
assert(evcon->state == EVCON_DISCONNECTED);
|
||||||
|
if (evcon->bind_address)
|
||||||
|
free(evcon->bind_address);
|
||||||
|
if ((evcon->bind_address = strdup(address)) == NULL)
|
||||||
|
event_err(1, "%s: strdup", __func__);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
evhttp_request_dispatch(struct evhttp_connection* evcon)
|
evhttp_request_dispatch(struct evhttp_connection* evcon)
|
||||||
{
|
{
|
||||||
@ -1479,11 +1495,15 @@ evhttp_connection_connect(struct evhttp_connection *evcon)
|
|||||||
assert(!(evcon->flags & EVHTTP_CON_INCOMING));
|
assert(!(evcon->flags & EVHTTP_CON_INCOMING));
|
||||||
evcon->flags |= EVHTTP_CON_OUTGOING;
|
evcon->flags |= EVHTTP_CON_OUTGOING;
|
||||||
|
|
||||||
/* Do async connection to HTTP server */
|
evcon->fd = bind_socket(evcon->bind_address, 0);
|
||||||
if ((evcon->fd = make_socket(
|
if (evcon->fd == -1) {
|
||||||
0, evcon->address, evcon->port)) == -1) {
|
event_debug(("%s: failed to bind to \"%s\"",
|
||||||
event_debug(("%s: failed to connect to \"%s:%d\"",
|
__func__, bind_address));
|
||||||
__func__, evcon->address, evcon->port));
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (socket_connect(evcon->fd, evcon->address, evcon->port) == -1) {
|
||||||
|
close(evcon->fd); evcon->fd = -1;
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1940,7 +1960,7 @@ evhttp_bind_socket(struct evhttp *http, const char *address, u_short port)
|
|||||||
struct event *ev = &http->bind_ev;
|
struct event *ev = &http->bind_ev;
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
if ((fd = make_socket(1, address, port)) == -1)
|
if ((fd = bind_socket(address, port)) == -1)
|
||||||
return (-1);
|
return (-1);
|
||||||
|
|
||||||
if (listen(fd, 10) == -1) {
|
if (listen(fd, 10) == -1) {
|
||||||
@ -2313,7 +2333,7 @@ name_from_addr(struct sockaddr *sa, socklen_t salen,
|
|||||||
/* Either connect or bind */
|
/* Either connect or bind */
|
||||||
|
|
||||||
static int
|
static int
|
||||||
make_socket_ai(int should_bind, struct addrinfo *ai)
|
bind_socket_ai(struct addrinfo *ai)
|
||||||
{
|
{
|
||||||
struct linger linger;
|
struct linger linger;
|
||||||
int fd, on = 1, r;
|
int fd, on = 1, r;
|
||||||
@ -2342,11 +2362,87 @@ make_socket_ai(int should_bind, struct addrinfo *ai)
|
|||||||
linger.l_linger = 5;
|
linger.l_linger = 5;
|
||||||
setsockopt(fd, SOL_SOCKET, SO_LINGER, (void *)&linger, sizeof(linger));
|
setsockopt(fd, SOL_SOCKET, SO_LINGER, (void *)&linger, sizeof(linger));
|
||||||
|
|
||||||
if (should_bind)
|
r = bind(fd, ai->ai_addr, ai->ai_addrlen);
|
||||||
r = bind(fd, ai->ai_addr, ai->ai_addrlen);
|
if (r == -1)
|
||||||
else
|
goto out;
|
||||||
r = connect(fd, ai->ai_addr, ai->ai_addrlen);
|
|
||||||
if (r == -1) {
|
return (fd);
|
||||||
|
|
||||||
|
out:
|
||||||
|
serrno = errno;
|
||||||
|
close(fd);
|
||||||
|
errno = serrno;
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct addrinfo *
|
||||||
|
make_addrinfo(const char *address, u_short port)
|
||||||
|
{
|
||||||
|
struct addrinfo ai[2], *aitop = NULL;
|
||||||
|
|
||||||
|
#ifdef HAVE_GETADDRINFO
|
||||||
|
char strport[NI_MAXSERV];
|
||||||
|
int ai_result;
|
||||||
|
|
||||||
|
memset(&ai[0], 0, sizeof (ai[0]));
|
||||||
|
ai[0].ai_family = AF_INET;
|
||||||
|
ai[0].ai_socktype = SOCK_STREAM;
|
||||||
|
ai[0].ai_flags = AI_PASSIVE; /* turn NULL host name into INADDR_ANY */
|
||||||
|
snprintf(strport, sizeof (strport), "%d", port);
|
||||||
|
if ((ai_result = getaddrinfo(address, strport, &ai[0], &aitop)) != 0) {
|
||||||
|
if ( ai_result == EAI_SYSTEM )
|
||||||
|
event_warn("getaddrinfo");
|
||||||
|
else
|
||||||
|
event_warnx("getaddrinfo: %s", gai_strerror(ai_result));
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static int cur;
|
||||||
|
if (++cur == 2) cur = 0; /* allow calling this function twice */
|
||||||
|
|
||||||
|
if (fake_getaddrinfo(address, &ai[cur]) < 0) {
|
||||||
|
event_warn("fake_getaddrinfo");
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
aitop = &ai[cur];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return (aitop);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
bind_socket(const char *address, u_short port)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
struct addrinfo *aitop = make_addrinfo(address, port);
|
||||||
|
|
||||||
|
if (aitop == NULL)
|
||||||
|
return (-1);
|
||||||
|
|
||||||
|
fd = bind_socket_ai(aitop);
|
||||||
|
|
||||||
|
#ifdef HAVE_GETADDRINFO
|
||||||
|
freeaddrinfo(aitop);
|
||||||
|
#else
|
||||||
|
fake_freeaddrinfo(aitop);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return (fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
socket_connect(int fd, const char *address, unsigned short port)
|
||||||
|
{
|
||||||
|
struct addrinfo *ai = make_addrinfo(address, port);
|
||||||
|
int res = -1;
|
||||||
|
|
||||||
|
if (ai == NULL) {
|
||||||
|
event_debug(("%s: make_addrinfo: \"%s:%d\"",
|
||||||
|
__func__, evcon->address, evcon->port));
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (connect(fd, ai->ai_addr, ai->ai_addrlen) == -1) {
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
int tmp_error = WSAGetLastError();
|
int tmp_error = WSAGetLastError();
|
||||||
if (tmp_error != WSAEWOULDBLOCK && tmp_error != WSAEINVAL &&
|
if (tmp_error != WSAEWOULDBLOCK && tmp_error != WSAEINVAL &&
|
||||||
@ -2360,51 +2456,15 @@ make_socket_ai(int should_bind, struct addrinfo *ai)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
return (fd);
|
/* everything is fine */
|
||||||
|
res = 0;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
serrno = errno;
|
|
||||||
close(fd);
|
|
||||||
errno = serrno;
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
make_socket(int should_bind, const char *address, u_short port)
|
|
||||||
{
|
|
||||||
int fd;
|
|
||||||
struct addrinfo ai, *aitop = NULL;
|
|
||||||
#ifdef HAVE_GETADDRINFO
|
#ifdef HAVE_GETADDRINFO
|
||||||
char strport[NI_MAXSERV];
|
freeaddrinfo(ai);
|
||||||
int ai_result;
|
|
||||||
|
|
||||||
memset(&ai, 0, sizeof (ai));
|
|
||||||
ai.ai_family = AF_INET;
|
|
||||||
ai.ai_socktype = SOCK_STREAM;
|
|
||||||
ai.ai_flags = should_bind ? AI_PASSIVE : 0;
|
|
||||||
snprintf(strport, sizeof (strport), "%d", port);
|
|
||||||
if ((ai_result = getaddrinfo(address, strport, &ai, &aitop)) != 0) {
|
|
||||||
if ( ai_result == EAI_SYSTEM )
|
|
||||||
event_warn("getaddrinfo");
|
|
||||||
else
|
|
||||||
event_warnx("getaddrinfo: %s", gai_strerror(ai_result));
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
#else
|
#else
|
||||||
if (fake_getaddrinfo(address, &ai) < 0) {
|
fake_freeaddrinfo(ai);
|
||||||
event_warn("fake_getaddrinfo");
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
aitop = &ai;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
fd = make_socket_ai(should_bind, aitop);
|
return (res);
|
||||||
|
|
||||||
#ifdef HAVE_GETADDRINFO
|
|
||||||
freeaddrinfo(aitop);
|
|
||||||
#else
|
|
||||||
fake_freeaddrinfo(aitop);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return (fd);
|
|
||||||
}
|
}
|
||||||
|
@ -393,6 +393,9 @@ http_dispatcher_test(void)
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* also bind to local host */
|
||||||
|
evhttp_connection_set_local_address(evcon, "127.0.0.1");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* At this point, we want to schedule an HTTP GET request
|
* At this point, we want to schedule an HTTP GET request
|
||||||
* server using our make request method.
|
* server using our make request method.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user