static void
sockaddr_set_data (struct sockaddr *sa, const ip_address *ip, int port)
{
- switch (ip->type)
+ switch (ip->family)
{
- case IPV4_ADDRESS:
+ case AF_INET:
{
struct sockaddr_in *sin = (struct sockaddr_in *)sa;
xzero (*sin);
sin->sin_family = AF_INET;
sin->sin_port = htons (port);
- sin->sin_addr = ADDRESS_IPV4_IN_ADDR (ip);
+ sin->sin_addr = ip->data.d4;
break;
}
#ifdef ENABLE_IPV6
- case IPV6_ADDRESS:
+ case AF_INET6:
{
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
xzero (*sin6);
sin6->sin6_family = AF_INET6;
sin6->sin6_port = htons (port);
- sin6->sin6_addr = ADDRESS_IPV6_IN6_ADDR (ip);
+ sin6->sin6_addr = ip->data.d6;
#ifdef HAVE_SOCKADDR_IN6_SCOPE_ID
- sin6->sin6_scope_id = ADDRESS_IPV6_SCOPE (ip);
+ sin6->sin6_scope_id = ip->ipv6_scope;
#endif
break;
}
struct sockaddr_in *sin = (struct sockaddr_in *)sa;
if (ip)
{
- ip->type = IPV4_ADDRESS;
- ADDRESS_IPV4_IN_ADDR (ip) = sin->sin_addr;
+ ip->family = AF_INET;
+ ip->data.d4 = sin->sin_addr;
}
if (port)
*port = ntohs (sin->sin_port);
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
if (ip)
{
- ip->type = IPV6_ADDRESS;
- ADDRESS_IPV6_IN6_ADDR (ip) = sin6->sin6_addr;
+ ip->family = AF_INET6;
+ ip->data.d6 = sin6->sin6_addr;
#ifdef HAVE_SOCKADDR_IN6_SCOPE_ID
- ADDRESS_IPV6_SCOPE (ip) = sin6->sin6_scope_id;
+ ip->ipv6_scope = sin6->sin6_scope_id;
#endif
}
if (port)
bind_local (const ip_address *bind_address, int *port)
{
int sock;
- int family = AF_INET;
struct sockaddr_storage ss;
struct sockaddr *sa = (struct sockaddr *)&ss;
void *setopt_ptr = (void *)&setopt_val;
socklen_t setopt_size = sizeof (setopt_val);
-#ifdef ENABLE_IPV6
- if (bind_address->type == IPV6_ADDRESS)
- family = AF_INET6;
-#endif
-
- sock = socket (family, SOCK_STREAM, 0);
+ sock = socket (bind_address->family, SOCK_STREAM, 0);
if (sock < 0)
return -1;
if (ret < 0)
return false;
+ ip->family = sockaddr->sa_family;
switch (sockaddr->sa_family)
{
#ifdef ENABLE_IPV6
case AF_INET6:
{
struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)&storage;
- ip->type = IPV6_ADDRESS;
- ADDRESS_IPV6_IN6_ADDR (ip) = sa6->sin6_addr;
+ ip->data.d6 = sa6->sin6_addr;
#ifdef HAVE_SOCKADDR_IN6_SCOPE_ID
- ADDRESS_IPV6_SCOPE (ip) = sa6->sin6_scope_id;
+ ip->ipv6_scope = sa6->sin6_scope_id;
#endif
DEBUGP (("conaddr is: %s\n", print_address (ip)));
return true;
case AF_INET:
{
struct sockaddr_in *sa = (struct sockaddr_in *)&storage;
- ip->type = IPV4_ADDRESS;
- ADDRESS_IPV4_IN_ADDR (ip) = sa->sin_addr;
+ ip->data.d4 = sa->sin_addr;
DEBUGP (("conaddr is: %s\n", print_address (ip)));
return true;
}
return result;
}
+/* Return true iff the connection to the remote site established
+ through SOCK is still open.
+
+ Specifically, this function returns true if SOCK is not ready for
+ reading. This is because, when the connection closes, the socket
+ is ready for reading because EOF is about to be delivered. A side
+ effect of this method is that sockets that have pending data are
+ considered non-open. This is actually a good thing for callers of
+ this function, where such pending data can only be unwanted
+ leftover from a previous request. */
+
bool
test_socket_open (int sock)
{
to.tv_sec = 0;
to.tv_usec = 1;
- /* If we get a timeout, then that means still connected */
if (select (sock + 1, &check_set, NULL, NULL, &to) == 0)
- {
- /* Connection is valid (not EOF), so continue */
- return true;
- }
+ /* We got a timeout, it means we're still connected. */
+ return true;
else
+ /* Read now would not wait, it means we have either pending data
+ or EOF/error. */
return false;
}
\f
or SSL_read or whatever is necessary. */
static struct hash_table *transport_map;
-static int transport_map_modified_tick;
+static unsigned int transport_map_modified_tick;
struct transport_info {
- fd_reader_t reader;
- fd_writer_t writer;
- fd_poller_t poller;
- fd_peeker_t peeker;
- fd_closer_t closer;
+ struct transport_implementation *imp;
void *ctx;
};
call getpeername, etc. */
void
-fd_register_transport (int fd, fd_reader_t reader, fd_writer_t writer,
- fd_poller_t poller, fd_peeker_t peeker,
- fd_closer_t closer, void *ctx)
+fd_register_transport (int fd, struct transport_implementation *imp, void *ctx)
{
struct transport_info *info;
assert (fd >= 0);
info = xnew (struct transport_info);
- info->reader = reader;
- info->writer = writer;
- info->poller = poller;
- info->peeker = peeker;
- info->closer = closer;
+ info->imp = imp;
info->ctx = ctx;
if (!transport_map)
transport_map = hash_table_new (0, NULL, NULL);
#define LAZY_RETRIEVE_INFO(info) do { \
static struct transport_info *last_info; \
- static int last_fd = -1, last_tick; \
+ static int last_fd = -1; \
+ static unsigned int last_tick; \
if (!transport_map) \
info = NULL; \
else if (last_fd == fd && last_tick == transport_map_modified_tick) \
if (timeout)
{
int test;
- if (info && info->poller)
- test = info->poller (fd, timeout, wf, info->ctx);
+ if (info && info->imp->poller)
+ test = info->imp->poller (fd, timeout, wf, info->ctx);
else
test = sock_poll (fd, timeout, wf);
if (test == 0)
LAZY_RETRIEVE_INFO (info);
if (!poll_internal (fd, info, WAIT_FOR_READ, timeout))
return -1;
- if (info && info->reader)
- return info->reader (fd, buf, bufsize, info->ctx);
+ if (info && info->imp->reader)
+ return info->imp->reader (fd, buf, bufsize, info->ctx);
else
return sock_read (fd, buf, bufsize);
}
LAZY_RETRIEVE_INFO (info);
if (!poll_internal (fd, info, WAIT_FOR_READ, timeout))
return -1;
- if (info && info->peeker)
- return info->peeker (fd, buf, bufsize, info->ctx);
+ if (info && info->imp->peeker)
+ return info->imp->peeker (fd, buf, bufsize, info->ctx);
else
return sock_peek (fd, buf, bufsize);
}
{
if (!poll_internal (fd, info, WAIT_FOR_WRITE, timeout))
return -1;
- if (info && info->writer)
- res = info->writer (fd, buf, bufsize, info->ctx);
+ if (info && info->imp->writer)
+ res = info->imp->writer (fd, buf, bufsize, info->ctx);
else
res = sock_write (fd, buf, bufsize);
if (res <= 0)
return res;
}
+/* Report the most recent error(s) on FD. This should only be called
+ after fd_* functions, such as fd_read and fd_write, and only if
+ they return a negative result. For errors coming from other calls
+ such as setsockopt or fopen, strerror should continue to be
+ used.
+
+ If the transport doesn't support error messages or doesn't supply
+ one, strerror(errno) is returned. The returned error message
+ should not be used after fd_close has been called. */
+
+const char *
+fd_errstr (int fd)
+{
+ /* Don't bother with LAZY_RETRIEVE_INFO, as this will only be called
+ in case of error, never in a tight loop. */
+ struct transport_info *info = NULL;
+ if (transport_map)
+ info = hash_table_get (transport_map, (void *) fd);
+
+ if (info && info->imp->errstr)
+ {
+ const char *err = info->imp->errstr (fd, info->ctx);
+ if (err)
+ return err;
+ /* else, fall through and print the system error. */
+ }
+ return strerror (errno);
+}
+
/* Close the file descriptor FD. */
void
if (transport_map)
info = hash_table_get (transport_map, (void *) fd);
- if (info && info->closer)
- info->closer (fd, info->ctx);
+ if (info && info->imp->closer)
+ info->imp->closer (fd, info->ctx);
else
sock_close (fd);