Commit 11ad647a authored by Pieter Noordhuis's avatar Pieter Noordhuis
Browse files

Return address when connecting with getaddrinfo

It is opaque to the caller which address the handle connects to when the
host is resolved by getaddrinfo. Now, it returns a redis_address type
that encapsulates multiple sockaddr_* structs (sockaddr_storage would be
appropriate here, but it appears not to be portable).
parent 6d3577ef
...@@ -158,7 +158,7 @@ static int redis__finish_connect(redis_handle *h, int fd) { ...@@ -158,7 +158,7 @@ static int redis__finish_connect(redis_handle *h, int fd) {
return REDIS_OK; return REDIS_OK;
} }
int redis_handle_connect_in(redis_handle *h, struct sockaddr_in addr) { int redis_handle_connect_address(redis_handle *h, const redis_address *addr) {
int fd; int fd;
if (h->fd >= 0) { if (h->fd >= 0) {
...@@ -166,8 +166,7 @@ int redis_handle_connect_in(redis_handle *h, struct sockaddr_in addr) { ...@@ -166,8 +166,7 @@ int redis_handle_connect_in(redis_handle *h, struct sockaddr_in addr) {
return REDIS_ESYS; return REDIS_ESYS;
} }
assert(addr.sin_family == AF_INET); fd = redis__handle_connect(addr->sa_family, &addr->sa_addr.addr, addr->sa_addrlen);
fd = redis__handle_connect(AF_INET, (struct sockaddr*)&addr, sizeof(addr));
if (fd == -1) { if (fd == -1) {
return REDIS_ESYS; return REDIS_ESYS;
} }
...@@ -175,44 +174,38 @@ int redis_handle_connect_in(redis_handle *h, struct sockaddr_in addr) { ...@@ -175,44 +174,38 @@ int redis_handle_connect_in(redis_handle *h, struct sockaddr_in addr) {
return redis__finish_connect(h, fd); return redis__finish_connect(h, fd);
} }
int redis_handle_connect_in6(redis_handle *h, struct sockaddr_in6 addr) { int redis_handle_connect_in(redis_handle *h, struct sockaddr_in sa) {
int fd; redis_address address;
if (h->fd >= 0) {
errno = EALREADY;
return REDIS_ESYS;
}
assert(addr.sin6_family == AF_INET6); address.sa_family = AF_INET;
fd = redis__handle_connect(AF_INET6, (struct sockaddr*)&addr, sizeof(addr)); address.sa_addr.in = sa;
if (fd == -1) { address.sa_addrlen = sizeof(sa);
return REDIS_ESYS; return redis_handle_connect_address(h, &address);
}
return redis__finish_connect(h, fd);
} }
int redis_handle_connect_un(redis_handle *h, struct sockaddr_un addr) { int redis_handle_connect_in6(redis_handle *h, struct sockaddr_in6 sa) {
int fd; redis_address address;
if (h->fd >= 0) { address.sa_family = AF_INET6;
errno = EALREADY; address.sa_addr.in6 = sa;
return REDIS_ESYS; address.sa_addrlen = sizeof(sa);
} return redis_handle_connect_address(h, &address);
}
assert(addr.sun_family == AF_LOCAL); int redis_handle_connect_un(redis_handle *h, struct sockaddr_un sa) {
fd = redis__handle_connect(AF_LOCAL, (struct sockaddr*)&addr, sizeof(addr)); redis_address address;
if (fd == -1) {
return REDIS_ESYS;
}
return redis__finish_connect(h, fd); address.sa_family = AF_LOCAL;
address.sa_addr.un = sa;
address.sa_addrlen = sizeof(sa);
return redis_handle_connect_address(h, &address);
} }
int redis_handle_connect_gai(redis_handle *h, int redis_handle_connect_gai(redis_handle *h,
int family, int family,
const char *addr, const char *addr,
int port) { int port,
redis_address *_addr) {
char _port[6]; /* strlen("65535"); */ char _port[6]; /* strlen("65535"); */
struct addrinfo hints, *servinfo, *p; struct addrinfo hints, *servinfo, *p;
int rv, fd; int rv, fd;
...@@ -242,6 +235,14 @@ int redis_handle_connect_gai(redis_handle *h, ...@@ -242,6 +235,14 @@ int redis_handle_connect_gai(redis_handle *h,
goto error; goto error;
} }
/* Pass address we connect to back to caller */
if (_addr != NULL) {
memset(_addr, 0, sizeof(*_addr));
memcpy(&_addr->sa_addr, p->ai_addr, p->ai_addrlen);
_addr->sa_family = p->ai_family;
_addr->sa_addrlen = p->ai_addrlen;
}
freeaddrinfo(servinfo); freeaddrinfo(servinfo);
return redis__finish_connect(h, fd); return redis__finish_connect(h, fd);
} }
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#define REDIS_EEOF -4 #define REDIS_EEOF -4
typedef struct redis_handle_s redis_handle; typedef struct redis_handle_s redis_handle;
typedef struct redis_address_s redis_address;
struct redis_handle_s { struct redis_handle_s {
int fd; int fd;
...@@ -27,16 +28,28 @@ struct redis_handle_s { ...@@ -27,16 +28,28 @@ struct redis_handle_s {
char *rbuf; char *rbuf;
}; };
struct redis_address_s {
int sa_family;
socklen_t sa_addrlen;
union {
struct sockaddr addr;
struct sockaddr_in in;
struct sockaddr_in6 in6;
struct sockaddr_un un;
} sa_addr;
};
int redis_handle_init(redis_handle *h); int redis_handle_init(redis_handle *h);
int redis_handle_close(redis_handle *); int redis_handle_close(redis_handle *);
int redis_handle_destroy(redis_handle *); int redis_handle_destroy(redis_handle *);
int redis_handle_set_timeout(redis_handle *, unsigned long us); int redis_handle_set_timeout(redis_handle *, unsigned long us);
unsigned long redis_handle_get_timeout(redis_handle *h); unsigned long redis_handle_get_timeout(redis_handle *h);
int redis_handle_connect_address(redis_handle *, const redis_address *);
int redis_handle_connect_in(redis_handle *, struct sockaddr_in addr); int redis_handle_connect_in(redis_handle *, struct sockaddr_in addr);
int redis_handle_connect_in6(redis_handle *, struct sockaddr_in6 addr); int redis_handle_connect_in6(redis_handle *, struct sockaddr_in6 addr);
int redis_handle_connect_un(redis_handle *, struct sockaddr_un addr); int redis_handle_connect_un(redis_handle *, struct sockaddr_un addr);
int redis_handle_connect_gai(redis_handle *h, int family, const char *addr, int port); int redis_handle_connect_gai(redis_handle *h, int family, const char *host, int port, redis_address *addr);
int redis_handle_wait_connected(redis_handle *); int redis_handle_wait_connected(redis_handle *);
int redis_handle_wait_readable(redis_handle *); int redis_handle_wait_readable(redis_handle *);
......
...@@ -118,7 +118,7 @@ TEST(connect_gai_unknown_host) { ...@@ -118,7 +118,7 @@ TEST(connect_gai_unknown_host) {
rv = redis_handle_init(&h); rv = redis_handle_init(&h);
assert(rv == REDIS_OK); assert(rv == REDIS_OK);
rv = redis_handle_connect_gai(&h, AF_INET, "idontexist.foo", redis_port()); rv = redis_handle_connect_gai(&h, AF_INET, "idontexist.foo", redis_port(), NULL);
assert_equal_int(rv, REDIS_EGAI); assert_equal_int(rv, REDIS_EGAI);
/* Don't care about the specific error for now. */ /* Don't care about the specific error for now. */
...@@ -132,7 +132,7 @@ TEST(connect_gai_success) { ...@@ -132,7 +132,7 @@ TEST(connect_gai_success) {
rv = redis_handle_init(&h); rv = redis_handle_init(&h);
assert(rv == REDIS_OK); assert(rv == REDIS_OK);
rv = redis_handle_connect_gai(&h, AF_INET, "localhost", redis_port()); rv = redis_handle_connect_gai(&h, AF_INET, "localhost", redis_port(), NULL);
assert_equal_int(rv, REDIS_OK); assert_equal_int(rv, REDIS_OK);
rv = redis_handle_wait_connected(&h); rv = redis_handle_wait_connected(&h);
...@@ -141,6 +141,30 @@ TEST(connect_gai_success) { ...@@ -141,6 +141,30 @@ TEST(connect_gai_success) {
redis_handle_destroy(&h); redis_handle_destroy(&h);
} }
TEST(connect_gai_redis_address) {
redis_handle h;
redis_address address;
int rv;
rv = redis_handle_init(&h);
assert(rv == REDIS_OK);
rv = redis_handle_connect_gai(&h, AF_INET, "localhost", redis_port(), &address);
assert_equal_int(rv, REDIS_OK);
/* Match common fields */
assert(address.sa_family == AF_INET);
assert(address.sa_addrlen == sizeof(struct sockaddr_in));
/* Match sockaddr specific fields */
assert(address.sa_addr.in.sin_len == sizeof(struct sockaddr_in));
assert(address.sa_addr.in.sin_family == AF_INET);
assert(ntohs(address.sa_addr.in.sin_port) == redis_port());
assert(strcmp(inet_ntoa(address.sa_addr.in.sin_addr), "127.0.0.1") == 0);
redis_handle_destroy(&h);
}
redis_handle *setup(void) { redis_handle *setup(void) {
redis_handle *h = malloc(sizeof(*h)); redis_handle *h = malloc(sizeof(*h));
int rv; int rv;
...@@ -149,7 +173,7 @@ redis_handle *setup(void) { ...@@ -149,7 +173,7 @@ redis_handle *setup(void) {
assert(rv == REDIS_OK); assert(rv == REDIS_OK);
rv = redis_handle_set_timeout(h, 10000); rv = redis_handle_set_timeout(h, 10000);
assert_equal_int(rv, REDIS_OK); assert_equal_int(rv, REDIS_OK);
rv = redis_handle_connect_gai(h, AF_INET, "localhost", redis_port()); rv = redis_handle_connect_gai(h, AF_INET, "localhost", redis_port(), NULL);
assert_equal_int(rv, REDIS_OK); assert_equal_int(rv, REDIS_OK);
rv = redis_handle_wait_connected(h); rv = redis_handle_wait_connected(h);
assert_equal_int(rv, REDIS_OK); assert_equal_int(rv, REDIS_OK);
...@@ -242,6 +266,7 @@ int main(void) { ...@@ -242,6 +266,7 @@ int main(void) {
test_connect_timeout(); test_connect_timeout();
test_connect_gai_unknown_host(); test_connect_gai_unknown_host();
test_connect_gai_success(); test_connect_gai_success();
test_connect_gai_redis_address();
test_eof_after_quit(); test_eof_after_quit();
test_read_timeout(); test_read_timeout();
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment