2
0
mirror of https://gitlab.isc.org/isc-projects/dhcp synced 2025-08-30 05:47:45 +00:00

- Make the connect system call asynchronous.

- Add a new call that takes a list of addresses of arbitrary types,
  rather than just IPv4 addresses.
- Allow caller to also specify a local address to which to bind before
  connecting.
This commit is contained in:
Ted Lemon 2000-05-01 23:50:16 +00:00
parent df9ff0a119
commit fc24e951a2

View File

@ -49,11 +49,55 @@ isc_result_t omapi_connect (omapi_object_t *c,
unsigned port) unsigned port)
{ {
struct hostent *he; struct hostent *he;
int hix; unsigned i, hix;
omapi_addr_list_t *addrs = (omapi_addr_list_t *)0;
struct in_addr foo;
isc_result_t status;
if (!inet_aton (server_name, &foo)) {
/* If we didn't get a numeric address, try for a domain
name. It's okay for this call to block. */
he = gethostbyname (server_name);
if (!he)
return ISC_R_HOSTUNKNOWN;
for (i = 0; he -> h_addr_list [i]; i++)
;
if (i == 0)
return ISC_R_HOSTUNKNOWN;
hix = i;
if (!omapi_addr_list_new (&addrs, hix, MDL))
return ISC_R_NOMEMORY;
for (i = 0; i < hix; i++) {
addrs -> addresses [i].addrtype = he -> h_addrtype;
addrs -> addresses [i].addrlen = he -> h_length;
memcpy (addrs -> addresses [i].address,
he -> h_addr_list [i],
(unsigned)he -> h_length);
addrs -> addresses [i].port = port;
}
} else {
if (!omapi_addr_list_new (&addrs, 1, MDL))
return ISC_R_NOMEMORY;
addrs -> addresses [0].addrtype = AF_INET;
addrs -> addresses [0].addrlen = sizeof foo;
memcpy (addrs -> addresses [0].address, &foo, sizeof foo);
addrs -> addresses [0].port = port;
hix = 1;
}
status = omapi_connect_list (c, addrs, (omapi_addr_t *)0);
omapi_addr_list_dereference (&addrs, MDL);
return status;
}
isc_result_t omapi_connect_list (omapi_object_t *c,
omapi_addr_list_t *remote_addrs,
omapi_addr_t *local_addr)
{
isc_result_t status; isc_result_t status;
omapi_connection_object_t *obj; omapi_connection_object_t *obj;
int flag; int flag;
SOCKLEN_T sl; struct sockaddr_in local_sin;
obj = (omapi_connection_object_t *)dmalloc (sizeof *obj, MDL); obj = (omapi_connection_object_t *)dmalloc (sizeof *obj, MDL);
if (!obj) if (!obj)
@ -75,34 +119,6 @@ isc_result_t omapi_connect (omapi_object_t *c,
return status; return status;
} }
/* Set up all the constants in the address... */
obj -> remote_addr.sin_port = htons (port);
/* First try for a numeric address, since that's easier to check. */
if (!inet_aton (server_name, &obj -> remote_addr.sin_addr)) {
/* If we didn't get a numeric address, try for a domain
name. It's okay for this call to block. */
he = gethostbyname (server_name);
if (!he) {
omapi_object_dereference ((omapi_object_t **)&obj,
MDL);
return ISC_R_HOSTUNKNOWN;
}
hix = 1;
memcpy (&obj -> remote_addr.sin_addr,
he -> h_addr_list [0],
sizeof obj -> remote_addr.sin_addr);
} else
he = (struct hostent *)0;
#if defined (HAVE_SA_LEN)
obj -> remote_addr.sin_len =
sizeof (struct sockaddr_in);
#endif
obj -> remote_addr.sin_family = AF_INET;
memset (&(obj -> remote_addr.sin_zero), 0,
sizeof obj -> remote_addr.sin_zero);
/* Create a socket on which to communicate. */ /* Create a socket on which to communicate. */
obj -> socket = obj -> socket =
socket (PF_INET, SOCK_STREAM, IPPROTO_TCP); socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
@ -113,6 +129,38 @@ isc_result_t omapi_connect (omapi_object_t *c,
return ISC_R_UNEXPECTED; return ISC_R_UNEXPECTED;
} }
/* Set up the local address, if any. */
if (local_addr) {
/* Only do TCPv4 so far. */
if (local_addr -> addrtype != AF_INET) {
omapi_object_dereference ((omapi_object_t **)&obj,
MDL);
return ISC_R_INVALIDARG;
}
local_sin.sin_port = htons (local_addr -> port);
memcpy (&local_sin.sin_addr,
local_addr -> address,
local_addr -> addrlen);
#if defined (HAVE_SA_LEN)
local_sin.sin_len = sizeof local_addr;
#endif
local_sin.sin_family = AF_INET;
memset (&local_sin.sin_zero, 0, sizeof local_sin.sin_zero);
if (bind (obj -> socket, (struct sockaddr *)&local_sin,
sizeof local_sin) < 0) {
omapi_object_dereference ((omapi_object_t **)&obj,
MDL);
if (errno == EADDRINUSE)
return ISC_R_ADDRINUSE;
if (errno == EADDRNOTAVAIL)
return ISC_R_ADDRNOTAVAIL;
if (errno == EACCES)
return ISC_R_NOPERM;
return ISC_R_UNEXPECTED;
}
}
#if defined (HAVE_SETFD) #if defined (HAVE_SETFD)
if (fcntl (obj -> socket, F_SETFD, 1) < 0) { if (fcntl (obj -> socket, F_SETFD, 1) < 0) {
close (obj -> socket); close (obj -> socket);
@ -129,53 +177,34 @@ isc_result_t omapi_connect (omapi_object_t *c,
return ISC_R_UNEXPECTED; return ISC_R_UNEXPECTED;
} }
/* Try to connect to the one IP address we were given, or any of /* Set the SO_USELOOPBACK flag (this should not fail). */
the IP addresses listed in the host's A RR. */ flag = 1;
while (connect (obj -> socket, if (setsockopt (obj -> socket, SOL_SOCKET, SO_USELOOPBACK,
((struct sockaddr *) (char *)&flag, sizeof flag) < 0) {
&obj -> remote_addr), omapi_object_dereference ((omapi_object_t **)&obj, MDL);
sizeof obj -> remote_addr)) { return ISC_R_UNEXPECTED;
if (!he || !he -> h_addr_list [hix]) {
omapi_object_dereference ((omapi_object_t **)&obj,
MDL);
if (errno == ECONNREFUSED)
return ISC_R_CONNREFUSED;
if (errno == ENETUNREACH)
return ISC_R_NETUNREACH;
return ISC_R_UNEXPECTED;
}
memcpy (&obj -> remote_addr.sin_addr,
he -> h_addr_list [hix++],
sizeof obj -> remote_addr.sin_addr);
} }
obj -> state = omapi_connection_connected; /* Set the file to nonblocking mode. */
/* I don't know why this would fail, so I'm tempted not to test
the return value. */
sl = sizeof (obj -> local_addr);
if (getsockname (obj -> socket,
((struct sockaddr *)
&obj -> local_addr), &sl) < 0) {
}
if (fcntl (obj -> socket, F_SETFL, O_NONBLOCK) < 0) { if (fcntl (obj -> socket, F_SETFL, O_NONBLOCK) < 0) {
omapi_object_dereference ((omapi_object_t **)&obj, MDL); omapi_object_dereference ((omapi_object_t **)&obj, MDL);
return ISC_R_UNEXPECTED; return ISC_R_UNEXPECTED;
} }
status = omapi_register_io_object ((omapi_object_t *)obj, /* Store the address list on the object. */
omapi_connection_readfd, omapi_addr_list_reference (&obj -> connect_list, remote_addrs, MDL);
omapi_connection_writefd, obj -> cptr = 0;
omapi_connection_reader,
omapi_connection_writer,
omapi_connection_reaper);
if (status != ISC_R_SUCCESS) {
omapi_object_dereference ((omapi_object_t **)&obj, MDL);
return status;
}
return ISC_R_SUCCESS; status = (omapi_register_io_object
((omapi_object_t *)obj,
0, omapi_connection_writefd,
0, omapi_connection_connect,
omapi_connection_reaper));
obj -> state = omapi_connection_unconnected;
omapi_connection_connect ((omapi_object_t *)obj);
omapi_object_dereference ((omapi_object_t **)&obj, MDL);
return status;
} }
/* Disconnect a connection object from the remote end. If force is nonzero, /* Disconnect a connection object from the remote end. If force is nonzero,
@ -263,12 +292,102 @@ int omapi_connection_writefd (omapi_object_t *h)
if (h -> type != omapi_type_connection) if (h -> type != omapi_type_connection)
return -1; return -1;
c = (omapi_connection_object_t *)h; c = (omapi_connection_object_t *)h;
if (c -> state == omapi_connection_connecting)
return c -> socket;
if (c -> out_bytes) if (c -> out_bytes)
return c -> socket; return c -> socket;
else else
return -1; return -1;
} }
isc_result_t omapi_connection_connect (omapi_object_t *h)
{
int error;
omapi_connection_object_t *c;
SOCKLEN_T sl;
isc_result_t status;
if (h -> type != omapi_type_connection)
return ISC_R_INVALIDARG;
c = (omapi_connection_object_t *)h;
if (c -> state == omapi_connection_connecting) {
sl = sizeof error;
if (getsockopt (c -> socket, SOL_SOCKET, SO_ERROR,
&error, &sl) < 0) {
omapi_disconnect (h, 1);
return ISC_R_SUCCESS;
}
if (!errno)
c -> state = omapi_connection_connected;
}
if (c -> state == omapi_connection_connecting ||
c -> state == omapi_connection_unconnected) {
if (c -> cptr >= c -> connect_list -> count) {
omapi_disconnect (h, 1);
return ISC_R_SUCCESS;
}
if (c -> connect_list -> addresses [c -> cptr].addrtype !=
AF_INET) {
omapi_disconnect (h, 1);
return ISC_R_SUCCESS;
}
memcpy (&c -> remote_addr.sin_addr,
&c -> connect_list -> addresses [c -> cptr].address,
sizeof c -> remote_addr.sin_addr);
c -> remote_addr.sin_family = AF_INET;
c -> remote_addr.sin_port =
htons (c -> connect_list -> addresses [c -> cptr].port);
#if defined (HAVE_SA_LEN)
c -> remote_addr.sin_len = sizeof c -> remote_addr;
#endif
memset (&c -> remote_addr.sin_zero, 0,
sizeof c -> remote_addr.sin_zero);
++c -> cptr;
if (connect (c -> socket,
(struct sockaddr *)&c -> remote_addr,
sizeof c -> remote_addr) < 0) {
if (errno != EINPROGRESS) {
omapi_disconnect (h, 1);
return ISC_R_UNEXPECTED;
}
c -> state = omapi_connection_connecting;
return ISC_R_SUCCESS;
}
c -> state = omapi_connection_connected;
}
/* I don't know why this would fail, so I'm tempted not to test
the return value. */
sl = sizeof (c -> local_addr);
if (getsockname (c -> socket,
(struct sockaddr *)&c -> local_addr, &sl) < 0) {
}
/* Disconnect from I/O object, if any. */
if (h -> outer)
omapi_object_dereference (&h -> outer, MDL);
status = omapi_register_io_object (h,
omapi_connection_readfd,
omapi_connection_writefd,
omapi_connection_reader,
omapi_connection_writer,
omapi_connection_reaper);
if (status != ISC_R_SUCCESS) {
omapi_disconnect (h, 1);
return status;
}
omapi_signal_in (h, "connect");
omapi_addr_list_dereference (&c -> connect_list, MDL);
return ISC_R_SUCCESS;
}
/* Reaper function for connection - if the connection is completely closed, /* Reaper function for connection - if the connection is completely closed,
reap it. If it's in the disconnecting state, there were bytes left reap it. If it's in the disconnecting state, there were bytes left
to write when the user closed it, so if there are now no bytes left to to write when the user closed it, so if there are now no bytes left to
@ -329,6 +448,8 @@ isc_result_t omapi_connection_destroy (omapi_object_t *h,
omapi_disconnect (h, 1); omapi_disconnect (h, 1);
if (c -> listener) if (c -> listener)
omapi_object_dereference (&c -> listener, file, line); omapi_object_dereference (&c -> listener, file, line);
if (c -> connect_list)
omapi_addr_list_dereference (&c -> connect_list, file, line);
return ISC_R_SUCCESS; return ISC_R_SUCCESS;
} }