Nick Mathewson added the ARES_OPT_SOCK_STATE_CB option that when set makes

c-ares call a callback on socket state changes. A better way than the
ares_getsock() to get full control over the socket state.
This commit is contained in:
Daniel Stenberg 2006-05-03 06:11:44 +00:00
parent 6ca627ae74
commit dd06c60ada
9 changed files with 79 additions and 11 deletions

View File

@ -1,5 +1,11 @@
Changelog for the c-ares project
* May 3, 2006
- Nick Mathewson added the ARES_OPT_SOCK_STATE_CB option that when set makes
c-ares call a callback on socket state changes. A better way than the
ares_getsock() to get full control over the socket state.
* January 9, 2006
- Alexander Lazic improved the getservbyport_r() configure check.
@ -28,8 +34,8 @@
- Added constants that will be used by ares_getaddrinfo
- Made ares_getnameinfo use the reentrant getservbyport (getservbyport_r) if it is
available to ensure it works properly in a threaded environment.
- Made ares_getnameinfo use the reentrant getservbyport (getservbyport_r) if it
is available to ensure it works properly in a threaded environment.
* September 10

View File

@ -93,6 +93,7 @@ extern "C" {
#define ARES_OPT_SERVERS (1 << 6)
#define ARES_OPT_DOMAINS (1 << 7)
#define ARES_OPT_LOOKUPS (1 << 8)
#define ARES_OPT_SOCK_STATE_CB (1 << 9)
/* Nameinfo flag values */
#define ARES_NI_NOFQDN (1 << 0)
@ -135,6 +136,18 @@ extern "C" {
#define ARES_GETSOCK_WRITABLE(bits,num) (bits & (1 << ((num) + \
ARES_GETSOCK_MAXNUM)))
#ifdef WIN32
typedef void (*ares_sock_state_cb)(void *data,
SOCKET socket,
int readable,
int writable);
#else
typedef void (*ares_sock_state_cb)(void *data,
int socket,
int readable,
int writable);
#endif
struct ares_options {
int flags;
int timeout;
@ -147,6 +160,8 @@ struct ares_options {
char **domains;
int ndomains;
char *lookups;
ares_sock_state_cb sock_state_cb;
void *sock_state_cb_data;
};
struct hostent;

View File

@ -23,7 +23,7 @@
#include "ares.h"
#include "ares_private.h"
void ares__close_sockets(struct server_state *server)
void ares__close_sockets(ares_channel channel, struct server_state *server)
{
struct send_request *sendreq;
@ -46,11 +46,13 @@ void ares__close_sockets(struct server_state *server)
/* Close the TCP and UDP sockets. */
if (server->tcp_socket != ARES_SOCKET_BAD)
{
SOCK_STATE_CALLBACK(channel, server->tcp_socket, 0, 0);
closesocket(server->tcp_socket);
server->tcp_socket = ARES_SOCKET_BAD;
}
if (server->udp_socket != ARES_SOCKET_BAD)
{
SOCK_STATE_CALLBACK(channel, server->udp_socket, 0, 0);
closesocket(server->udp_socket);
server->udp_socket = ARES_SOCKET_BAD;
}

View File

@ -38,6 +38,6 @@ void ares_cancel(ares_channel channel)
if (!(channel->flags & ARES_FLAG_STAYOPEN))
{
for (i = 0; i < channel->nservers; i++)
ares__close_sockets(&channel->servers[i]);
ares__close_sockets(channel, &channel->servers[i]);
}
}

View File

@ -24,7 +24,7 @@ void ares_destroy(ares_channel channel)
struct query *query;
for (i = 0; i < channel->nservers; i++)
ares__close_sockets(&channel->servers[i]);
ares__close_sockets(channel, &channel->servers[i]);
free(channel->servers);
for (i = 0; i < channel->ndomains; i++)
free(channel->domains[i]);

View File

@ -98,6 +98,24 @@ The lookups to perform for host queries.
.I lookups
should be set to a string of the characters "b" or "f", where "b"
indicates a DNS lookup and "f" indicates a lookup in the hosts file.
.TP 18
.B ARES_OPT_SOCK_STATE_CB
.B void (*\fIsock_state_cb\fP)(void *data, int s, int read, int write);
.br
.B void *\fIsock_state_cb_data\fP;
.br
A callback function to be invoked when a socket changes state.
.I s
will be passed the socket whose state has changed;
.I read
will be set to true if the socket should listen for read events, and
.I write
will be set to true if the socket should listen for write events.
The value of
.I sock_state_cb_data
will be passed as the
.I data
argument.
.PP
The
.I flags

View File

@ -113,6 +113,7 @@ int ares_init_options(ares_channel *channelptr, struct ares_options *options,
channel->queries = NULL;
channel->domains = NULL;
channel->sortlist = NULL;
channel->sock_state_cb = NULL;
/* Initialize configuration by each of the four sources, from highest
* precedence to lowest.
@ -192,6 +193,11 @@ static int init_by_options(ares_channel channel, struct ares_options *options,
channel->udp_port = options->udp_port;
if ((optmask & ARES_OPT_TCP_PORT) && channel->tcp_port == -1)
channel->tcp_port = options->tcp_port;
if ((optmask & ARES_OPT_SOCK_STATE_CB) && channel->sock_state_cb == NULL)
{
channel->sock_state_cb = options->sock_state_cb;
channel->sock_state_cb_data = options->sock_state_cb_data;
}
/* Copy the servers, if given. */
if ((optmask & ARES_OPT_SERVERS) && channel->nservers == -1)

View File

@ -176,13 +176,22 @@ struct ares_channeldata {
/* Active queries */
struct query *queries;
ares_sock_state_cb sock_state_cb;
void *sock_state_cb_data;
};
void ares__send_query(ares_channel channel, struct query *query, time_t now);
void ares__close_sockets(struct server_state *server);
void ares__close_sockets(ares_channel channel, struct server_state *server);
int ares__get_hostent(FILE *fp, int family, struct hostent **host);
int ares__read_line(FILE *fp, char **buf, int *bufsize);
#define SOCK_STATE_CALLBACK(c, s, r, w) \
do { \
if ((c)->sock_state_cb) \
(c)->sock_state_cb((c)->sock_state_cb_data, (s), (r), (w)); \
} while (0)
#ifdef CURLDEBUG
/* This is low-level hard-hacking memory leak tracking and similar. Using the
libcurl lowlevel code from within library is ugly and only works when

View File

@ -149,7 +149,10 @@ static void write_tcp_data(ares_channel channel, fd_set *write_fds, time_t now)
wcount -= sendreq->len;
server->qhead = sendreq->next;
if (server->qhead == NULL)
server->qtail = NULL;
{
SOCK_STATE_CALLBACK(channel, server->tcp_socket, 1, 0);
server->qtail = NULL;
}
free(sendreq);
}
else
@ -179,7 +182,10 @@ static void write_tcp_data(ares_channel channel, fd_set *write_fds, time_t now)
{
server->qhead = sendreq->next;
if (server->qhead == NULL)
server->qtail = NULL;
{
SOCK_STATE_CALLBACK(channel, server->tcp_socket, 1, 0);
server->qtail = NULL;
}
free(sendreq);
}
else
@ -380,7 +386,7 @@ static void handle_error(ares_channel channel, int whichserver, time_t now)
struct query *query, *next;
/* Reset communications with this server. */
ares__close_sockets(&channel->servers[whichserver]);
ares__close_sockets(channel, &channel->servers[whichserver]);
/* Tell all queries talking to this server to move on and not try
* this server again.
@ -452,7 +458,10 @@ void ares__send_query(ares_channel channel, struct query *query, time_t now)
if (server->qtail)
server->qtail->next = sendreq;
else
server->qhead = sendreq;
{
SOCK_STATE_CALLBACK(channel, server->tcp_socket, 1, 1);
server->qhead = sendreq;
}
server->qtail = sendreq;
query->timeout = 0;
}
@ -575,6 +584,7 @@ static int open_tcp_socket(ares_channel channel, struct server_state *server)
}
}
SOCK_STATE_CALLBACK(channel, s, 1, 0);
server->tcp_buffer_pos = 0;
server->tcp_socket = s;
return 0;
@ -604,6 +614,8 @@ static int open_udp_socket(ares_channel channel, struct server_state *server)
return -1;
}
SOCK_STATE_CALLBACK(channel, s, 1, 0);
server->udp_socket = s;
return 0;
}
@ -714,7 +726,7 @@ static struct query *end_query (ares_channel channel, struct query *query, int s
if (!channel->queries && !(channel->flags & ARES_FLAG_STAYOPEN))
{
for (i = 0; i < channel->nservers; i++)
ares__close_sockets(&channel->servers[i]);
ares__close_sockets(channel, &channel->servers[i]);
}
return (next);
}