Add ares_set_socket_configure_callback()
This function sets a callback that is invoked after the socket is created, but before the connection is established. This is an ideal time to customize various socket options.
This commit is contained in:
parent
87d641a907
commit
11e37a92ef
|
@ -116,6 +116,7 @@ MANPAGES = ares_cancel.3 \
|
||||||
ares_set_servers_ports.3 \
|
ares_set_servers_ports.3 \
|
||||||
ares_set_servers_ports_csv.3 \
|
ares_set_servers_ports_csv.3 \
|
||||||
ares_set_socket_callback.3 \
|
ares_set_socket_callback.3 \
|
||||||
|
ares_set_socket_configure_callback.3 \
|
||||||
ares_set_sortlist.3 \
|
ares_set_sortlist.3 \
|
||||||
ares_strerror.3 \
|
ares_strerror.3 \
|
||||||
ares_timeout.3 \
|
ares_timeout.3 \
|
||||||
|
@ -167,6 +168,7 @@ HTMLPAGES = ares_cancel.html \
|
||||||
ares_set_servers_ports.html \
|
ares_set_servers_ports.html \
|
||||||
ares_set_servers_ports_csv.html \
|
ares_set_servers_ports_csv.html \
|
||||||
ares_set_socket_callback.html \
|
ares_set_socket_callback.html \
|
||||||
|
ares_set_socket_configure_callback.html \
|
||||||
ares_set_sortlist.html \
|
ares_set_sortlist.html \
|
||||||
ares_strerror.html \
|
ares_strerror.html \
|
||||||
ares_timeout.html \
|
ares_timeout.html \
|
||||||
|
@ -218,6 +220,7 @@ PDFPAGES = ares_cancel.pdf \
|
||||||
ares_set_servers_ports.pdf \
|
ares_set_servers_ports.pdf \
|
||||||
ares_set_servers_ports_csv.pdf \
|
ares_set_servers_ports_csv.pdf \
|
||||||
ares_set_socket_callback.pdf \
|
ares_set_socket_callback.pdf \
|
||||||
|
ares_set_socket_configure_callback.pdf \
|
||||||
ares_set_sortlist.pdf \
|
ares_set_sortlist.pdf \
|
||||||
ares_strerror.pdf \
|
ares_strerror.pdf \
|
||||||
ares_timeout.pdf \
|
ares_timeout.pdf \
|
||||||
|
|
8
ares.h
8
ares.h
|
@ -294,6 +294,10 @@ typedef int (*ares_sock_create_callback)(ares_socket_t socket_fd,
|
||||||
int type,
|
int type,
|
||||||
void *data);
|
void *data);
|
||||||
|
|
||||||
|
typedef int (*ares_sock_config_callback)(ares_socket_t socket_fd,
|
||||||
|
int type,
|
||||||
|
void *data);
|
||||||
|
|
||||||
CARES_EXTERN int ares_library_init(int flags);
|
CARES_EXTERN int ares_library_init(int flags);
|
||||||
|
|
||||||
CARES_EXTERN int ares_library_init_mem(int flags,
|
CARES_EXTERN int ares_library_init_mem(int flags,
|
||||||
|
@ -344,6 +348,10 @@ CARES_EXTERN void ares_set_socket_callback(ares_channel channel,
|
||||||
ares_sock_create_callback callback,
|
ares_sock_create_callback callback,
|
||||||
void *user_data);
|
void *user_data);
|
||||||
|
|
||||||
|
CARES_EXTERN void ares_set_socket_configure_callback(ares_channel channel,
|
||||||
|
ares_sock_config_callback callback,
|
||||||
|
void *user_data);
|
||||||
|
|
||||||
CARES_EXTERN int ares_set_sortlist(ares_channel channel,
|
CARES_EXTERN int ares_set_sortlist(ares_channel channel,
|
||||||
const char *sortstr);
|
const char *sortstr);
|
||||||
|
|
||||||
|
|
12
ares_init.c
12
ares_init.c
|
@ -164,6 +164,8 @@ int ares_init_options(ares_channel *channelptr, struct ares_options *options,
|
||||||
channel->sock_state_cb_data = NULL;
|
channel->sock_state_cb_data = NULL;
|
||||||
channel->sock_create_cb = NULL;
|
channel->sock_create_cb = NULL;
|
||||||
channel->sock_create_cb_data = NULL;
|
channel->sock_create_cb_data = NULL;
|
||||||
|
channel->sock_config_cb = NULL;
|
||||||
|
channel->sock_config_cb_data = NULL;
|
||||||
|
|
||||||
channel->last_server = 0;
|
channel->last_server = 0;
|
||||||
channel->last_timeout_processed = (time_t)now.tv_sec;
|
channel->last_timeout_processed = (time_t)now.tv_sec;
|
||||||
|
@ -291,6 +293,8 @@ int ares_dup(ares_channel *dest, ares_channel src)
|
||||||
/* Now clone the options that ares_save_options() doesn't support. */
|
/* Now clone the options that ares_save_options() doesn't support. */
|
||||||
(*dest)->sock_create_cb = src->sock_create_cb;
|
(*dest)->sock_create_cb = src->sock_create_cb;
|
||||||
(*dest)->sock_create_cb_data = src->sock_create_cb_data;
|
(*dest)->sock_create_cb_data = src->sock_create_cb_data;
|
||||||
|
(*dest)->sock_config_cb = src->sock_config_cb;
|
||||||
|
(*dest)->sock_config_cb_data = src->sock_config_cb_data;
|
||||||
|
|
||||||
strncpy((*dest)->local_dev_name, src->local_dev_name,
|
strncpy((*dest)->local_dev_name, src->local_dev_name,
|
||||||
sizeof(src->local_dev_name));
|
sizeof(src->local_dev_name));
|
||||||
|
@ -2085,6 +2089,14 @@ void ares_set_socket_callback(ares_channel channel,
|
||||||
channel->sock_create_cb_data = data;
|
channel->sock_create_cb_data = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ares_set_socket_configure_callback(ares_channel channel,
|
||||||
|
ares_sock_config_callback cb,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
channel->sock_config_cb = cb;
|
||||||
|
channel->sock_config_cb_data = data;
|
||||||
|
}
|
||||||
|
|
||||||
int ares_set_sortlist(ares_channel channel, const char *sortstr)
|
int ares_set_sortlist(ares_channel channel, const char *sortstr)
|
||||||
{
|
{
|
||||||
int nsort = 0;
|
int nsort = 0;
|
||||||
|
|
|
@ -311,6 +311,9 @@ struct ares_channeldata {
|
||||||
|
|
||||||
ares_sock_create_callback sock_create_cb;
|
ares_sock_create_callback sock_create_cb;
|
||||||
void *sock_create_cb_data;
|
void *sock_create_cb_data;
|
||||||
|
|
||||||
|
ares_sock_config_callback sock_config_cb;
|
||||||
|
void *sock_config_cb_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Memory management functions */
|
/* Memory management functions */
|
||||||
|
|
|
@ -1031,6 +1031,17 @@ static int open_tcp_socket(ares_channel channel, struct server_state *server)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (channel->sock_config_cb)
|
||||||
|
{
|
||||||
|
int err = channel->sock_config_cb(s, SOCK_STREAM,
|
||||||
|
channel->sock_config_cb_data);
|
||||||
|
if (err < 0)
|
||||||
|
{
|
||||||
|
sclose(s);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Connect to the server. */
|
/* Connect to the server. */
|
||||||
if (connect(s, sa, salen) == -1)
|
if (connect(s, sa, salen) == -1)
|
||||||
{
|
{
|
||||||
|
@ -1115,6 +1126,17 @@ static int open_udp_socket(ares_channel channel, struct server_state *server)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (channel->sock_config_cb)
|
||||||
|
{
|
||||||
|
int err = channel->sock_config_cb(s, SOCK_DGRAM,
|
||||||
|
channel->sock_config_cb_data);
|
||||||
|
if (err < 0)
|
||||||
|
{
|
||||||
|
sclose(s);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Connect to the server. */
|
/* Connect to the server. */
|
||||||
if (connect(s, sa, salen) == -1)
|
if (connect(s, sa, salen) == -1)
|
||||||
{
|
{
|
||||||
|
|
|
@ -20,7 +20,7 @@ connected to the remote server. The callback must return ARES_SUCCESS if
|
||||||
things are fine, or use the standard ares error codes to signal errors
|
things are fine, or use the standard ares error codes to signal errors
|
||||||
back. Returned errors will abort the ares operation.
|
back. Returned errors will abort the ares operation.
|
||||||
.SH SEE ALSO
|
.SH SEE ALSO
|
||||||
.BR ares_init_options (3)
|
.BR ares_init_options (3), ares_set_socket_configure_callback (3)
|
||||||
.SH AVAILABILITY
|
.SH AVAILABILITY
|
||||||
ares_set_socket_callback(3) was added in c-ares 1.6.0
|
ares_set_socket_callback(3) was added in c-ares 1.6.0
|
||||||
.SH AUTHOR
|
.SH AUTHOR
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
.\"
|
||||||
|
.TH ARES_SET_SOCKET_CONFIGURE_CALLBACK 3 "6 Feb 2016"
|
||||||
|
.SH NAME
|
||||||
|
ares_set_socket_configure_callback \- Set a socket configuration callback
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.nf
|
||||||
|
.B #include <ares.h>
|
||||||
|
.PP
|
||||||
|
.B typedef int (*ares_sock_config_callback)(ares_socket_t \fIsocket_fd\fP,
|
||||||
|
int \fItype\fP,
|
||||||
|
void *\fIuserdata\fP)
|
||||||
|
.PP
|
||||||
|
.B void ares_set_socket_configure_callback(ares_channel \fIchannel\fP,
|
||||||
|
ares_sock_config_callback \fIcallback\fP,
|
||||||
|
void *\fIuserdata\fP)
|
||||||
|
.PP
|
||||||
|
.B cc file.c -lcares
|
||||||
|
.fi
|
||||||
|
.SH DESCRIPTION
|
||||||
|
.PP
|
||||||
|
This function sets a \fIcallback\fP in the given ares channel handle. This
|
||||||
|
callback function will be invoked after the socket has been created, but
|
||||||
|
before it has been connected to the remote server, which is an ideal time
|
||||||
|
to configure various socket options. The callback must return ARES_SUCCESS
|
||||||
|
if things are fine, or return -1 to signal an error. A returned error will
|
||||||
|
abort the ares operation.
|
||||||
|
.SH SEE ALSO
|
||||||
|
.BR ares_init_options (3), ares_set_socket_callback (3)
|
||||||
|
.SH AVAILABILITY
|
||||||
|
ares_set_socket_configure_callback(3) was added in c-ares 1.11.0
|
||||||
|
.SH AUTHOR
|
||||||
|
Andrew Ayer
|
||||||
|
|
|
@ -153,6 +153,51 @@ TEST_P(MockChannelTest, SockFailCallback) {
|
||||||
EXPECT_EQ(ARES_ECONNREFUSED, result.status_);
|
EXPECT_EQ(ARES_ECONNREFUSED, result.status_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int sock_config_cb_count = 0;
|
||||||
|
static int SocketConfigureCallback(ares_socket_t fd, int type, void *data) {
|
||||||
|
int rc = *(int*)data;
|
||||||
|
if (verbose) std::cerr << "SocketConfigureCallback(" << fd << ") invoked" << std::endl;
|
||||||
|
sock_config_cb_count++;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_P(MockChannelTest, SockConfigureCallback) {
|
||||||
|
DNSPacket rsp;
|
||||||
|
rsp.set_response().set_aa()
|
||||||
|
.add_question(new DNSQuestion("www.google.com", ns_t_a))
|
||||||
|
.add_answer(new DNSARR("www.google.com", 100, {2, 3, 4, 5}));
|
||||||
|
EXPECT_CALL(server_, OnRequest("www.google.com", ns_t_a))
|
||||||
|
.WillOnce(SetReply(&server_, &rsp));
|
||||||
|
|
||||||
|
// Get notified of new sockets
|
||||||
|
int rc = ARES_SUCCESS;
|
||||||
|
ares_set_socket_configure_callback(channel_, SocketConfigureCallback, &rc);
|
||||||
|
|
||||||
|
HostResult result;
|
||||||
|
sock_config_cb_count = 0;
|
||||||
|
ares_gethostbyname(channel_, "www.google.com.", AF_INET, HostCallback, &result);
|
||||||
|
Process();
|
||||||
|
EXPECT_EQ(1, sock_config_cb_count);
|
||||||
|
EXPECT_TRUE(result.done_);
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << result.host_;
|
||||||
|
EXPECT_EQ("{'www.google.com' aliases=[] addrs=[2.3.4.5]}", ss.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_P(MockChannelTest, SockConfigureFailCallback) {
|
||||||
|
// Notification of new sockets gives an error.
|
||||||
|
int rc = -1;
|
||||||
|
ares_set_socket_configure_callback(channel_, SocketConfigureCallback, &rc);
|
||||||
|
|
||||||
|
HostResult result;
|
||||||
|
sock_config_cb_count = 0;
|
||||||
|
ares_gethostbyname(channel_, "www.google.com.", AF_INET, HostCallback, &result);
|
||||||
|
Process();
|
||||||
|
EXPECT_LT(1, sock_config_cb_count);
|
||||||
|
EXPECT_TRUE(result.done_);
|
||||||
|
EXPECT_EQ(ARES_ECONNREFUSED, result.status_);
|
||||||
|
}
|
||||||
|
|
||||||
// TCP only to prevent retries
|
// TCP only to prevent retries
|
||||||
TEST_P(MockTCPChannelTest, MalformedResponse) {
|
TEST_P(MockTCPChannelTest, MalformedResponse) {
|
||||||
std::vector<byte> one = {0x01};
|
std::vector<byte> one = {0x01};
|
||||||
|
|
Loading…
Reference in New Issue