summaryrefslogtreecommitdiff
path: root/bufferevent_sock.c
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2009-11-03 20:40:48 +0000
committerNick Mathewson <nickm@torproject.org>2009-11-03 20:40:48 +0000
commit0b9eb1bffbd5af7d1dc6987f1a859e5f1e8c25e8 (patch)
tree5c41f0537d17c4bec064a8733c2093fef50624ed /bufferevent_sock.c
parentfcc7668c008ce25d47834019c3d081819851c32d (diff)
downloadlibevent-0b9eb1bffbd5af7d1dc6987f1a859e5f1e8c25e8.tar.gz
Add a bufferevent function to resolve a name then connect to it.
This function, bufferevent_socket_connect_hostname() can either use evdns to do the resolve, or use a new function (evutil_resolve) that uses getaddrinfo or gethostbyname, like http.c does now. This function is meant to eventually replace the hostname resolution mess in http.c. svn:r1496
Diffstat (limited to 'bufferevent_sock.c')
-rw-r--r--bufferevent_sock.c73
1 files changed, 73 insertions, 0 deletions
diff --git a/bufferevent_sock.c b/bufferevent_sock.c
index 2cfef385..11dd10d3 100644
--- a/bufferevent_sock.c
+++ b/bufferevent_sock.c
@@ -54,6 +54,12 @@
#ifdef _EVENT_HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
+#ifdef _EVENT_HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef _EVENT_HAVE_NETINET_IN6_H
+#include <netinet/in6.h>
+#endif
#include "event2/util.h"
#include "event2/bufferevent.h"
@@ -352,6 +358,73 @@ done:
return result;
}
+static int (*_bufferevent_socket_connect_hostname_evdns_fn)(
+ struct bufferevent *, struct evdns_base *, int,
+ const char *, int) = NULL;
+
+void _bufferevent_set_socket_connect_hostname_evdns_fn(
+ int (*fn)(struct bufferevent *, struct evdns_base *, int,
+ const char *, int))
+{
+ if (!_bufferevent_socket_connect_hostname_evdns_fn)
+ _bufferevent_socket_connect_hostname_evdns_fn = fn;
+}
+
+int
+bufferevent_socket_connect_hostname(struct bufferevent *bev,
+ struct evdns_base *evdns_base, int family, const char *hostname, int port)
+{
+ struct sockaddr_storage ss;
+ ev_socklen_t socklen = sizeof(ss);
+ int socklen_int = sizeof(ss);
+
+ if (family != AF_INET && family != AF_INET6 && family != AF_UNSPEC)
+ return -1;
+ if (port < 1 || port > 65535)
+ return -1;
+
+ memset(&ss, 0, sizeof(ss));
+ if (!evutil_parse_sockaddr_port(hostname, (struct sockaddr*)&ss,
+ &socklen_int)) {
+ socklen = socklen_int;
+ if (ss.ss_family == AF_INET) {
+ struct sockaddr_in *sin = (struct sockaddr_in*)&ss;
+ if (family == AF_INET6)
+ return -1;
+ if (sin->sin_port)
+ return -1;
+ sin->sin_port = htons(port);
+ } else if (ss.ss_family == AF_INET6) {
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&ss;
+ if (family == AF_INET)
+ return -1;
+ if (sin6->sin6_port)
+ return -1;
+ sin6->sin6_port = htons(port);
+ }
+ return bufferevent_socket_connect(bev, (struct sockaddr*)&ss,
+ socklen);
+ }
+
+ if (evdns_base) {
+ EVUTIL_ASSERT(_bufferevent_socket_connect_hostname_evdns_fn);
+ return _bufferevent_socket_connect_hostname_evdns_fn(
+ bev, evdns_base, family, hostname, port);
+ }
+
+ memset(&ss, 0, sizeof(ss));
+
+ if (evutil_resolve(family, hostname, (struct sockaddr*)&ss,
+ &socklen, port)<0) {
+ _bufferevent_incref_and_lock(bev);
+ _bufferevent_run_eventcb(bev, BEV_EVENT_ERROR);
+ _bufferevent_decref_and_unlock(bev);
+ return -1;
+ }
+
+ return bufferevent_socket_connect(bev, (struct sockaddr*)&ss, socklen);
+}
+
/*
* Create a new buffered event object.
*