2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-30 14:07:59 +00:00

connect works; snapshot

This commit is contained in:
Michael Graff
1998-11-26 00:10:33 +00:00
parent 9df01daac3
commit a21e2e7fea
3 changed files with 401 additions and 80 deletions

View File

@@ -14,13 +14,19 @@
#include <isc/socket.h> #include <isc/socket.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <arpa/inet.h> #include <arpa/inet.h>
isc_memctx_t mctx = NULL; isc_memctx_t mctx = NULL;
volatile int tasks_done = 0; volatile int tasks_done = 0;
static isc_boolean_t my_send(isc_task_t task, isc_event_t event);
static isc_boolean_t my_recv(isc_task_t task, isc_event_t event);
static isc_boolean_t static isc_boolean_t
my_callback(isc_task_t task, isc_event_t event) my_callback(isc_task_t task, isc_event_t event)
{ {
@@ -45,26 +51,7 @@ my_shutdown(isc_task_t task, isc_event_t event)
return (ISC_TRUE); return (ISC_TRUE);
} }
static isc_boolean_t
my_send(isc_task_t task, isc_event_t event)
{
isc_socket_t sock;
isc_socketevent_t dev;
sock = event->sender;
dev = (isc_socketevent_t)event;
printf("my_send: %s task %p\n\t(sock %p, base %p, length %d, n %d, result %d)\n",
(char *)(event->arg), task, sock,
dev->region.base, dev->region.length,
dev->n, dev->result);
isc_mem_put(event->mctx, dev->region.base, dev->region.length);
isc_event_free(&event);
return (0);
}
static isc_boolean_t static isc_boolean_t
my_recv(isc_task_t task, isc_event_t event) my_recv(isc_task_t task, isc_event_t event)
{ {
@@ -94,13 +81,19 @@ my_recv(isc_task_t task, isc_event_t event)
/* /*
* Echo the data back * Echo the data back
*/ */
region = dev->region; if (strcmp(event->arg, "so2")) {
region.base[20] = 0; region = dev->region;
snprintf(buf, sizeof buf, "Received: %s\r\n", region.base); region.base[20] = 0;
region.base = isc_mem_get(event->mctx, strlen(buf) + 1); snprintf(buf, sizeof buf, "Received: %s\r\n", region.base);
region.length = strlen(buf) + 1; region.base = isc_mem_get(event->mctx, strlen(buf) + 1);
strcpy(region.base, buf); /* strcpy is safe */ region.length = strlen(buf) + 1;
isc_socket_send(sock, &region, task, my_send, event->arg); strcpy(region.base, buf); /* strcpy is safe */
isc_socket_send(sock, &region, task, my_send, event->arg);
} else {
region = dev->region;
region.base[region.length - 1] = 0;
printf("Received: %s\r\n", region.base);
}
isc_socket_recv(sock, &dev->region, ISC_FALSE, isc_socket_recv(sock, &dev->region, ISC_FALSE,
task, my_recv, event->arg); task, my_recv, event->arg);
@@ -111,6 +104,86 @@ my_recv(isc_task_t task, isc_event_t event)
return (0); return (0);
} }
static isc_boolean_t
my_send(isc_task_t task, isc_event_t event)
{
isc_socket_t sock;
isc_socketevent_t dev;
sock = event->sender;
dev = (isc_socketevent_t)event;
printf("my_send: %s task %p\n\t(sock %p, base %p, length %d, n %d, result %d)\n",
(char *)(event->arg), task, sock,
dev->region.base, dev->region.length,
dev->n, dev->result);
isc_mem_put(event->mctx, dev->region.base, dev->region.length);
isc_event_free(&event);
return (0);
}
static isc_boolean_t
my_http_get(isc_task_t task, isc_event_t event)
{
isc_socket_t sock;
isc_socketevent_t dev;
sock = event->sender;
dev = (isc_socketevent_t)event;
printf("my_http_get: %s task %p\n\t(sock %p, base %p, length %d, n %d, result %d)\n",
(char *)(event->arg), task, sock,
dev->region.base, dev->region.length,
dev->n, dev->result);
isc_socket_recv(sock, &dev->region, ISC_FALSE, task, my_recv,
event->arg);
isc_event_free(&event);
return (0);
}
static isc_boolean_t
my_connect(isc_task_t task, isc_event_t event)
{
isc_socket_t sock;
isc_socket_connev_t dev;
struct isc_region region;
char buf[1024];
sock = event->sender;
dev = (isc_socket_connev_t)event;
printf("%s: Connection result: %d\n", (char *)(event->arg),
dev->result);
if (dev->result != ISC_R_SUCCESS) {
isc_socket_detach(&sock);
isc_event_free(&event);
return (0);
}
/*
* Send a GET string, and set up to receive (and just display)
* the result.
*/
strcpy(buf, "GET / HTTP/1.1\r\nHost: www.flame.org\r\nConnection: Close\r\n\r\n");
region.base = isc_mem_get(event->mctx, strlen(buf) + 1);
region.length = strlen(buf) + 1;
strcpy(region.base, buf); /* strcpy is safe */
isc_socket_send(sock, &region, task, my_http_get, event->arg);
isc_event_free(&event);
return (0);
}
static isc_boolean_t static isc_boolean_t
my_listen(isc_task_t task, isc_event_t event) my_listen(isc_task_t task, isc_event_t event)
{ {
@@ -186,18 +259,40 @@ main(int argc, char *argv[])
socketmgr = NULL; socketmgr = NULL;
INSIST(isc_socketmgr_create(mctx, &socketmgr) == ISC_R_SUCCESS); INSIST(isc_socketmgr_create(mctx, &socketmgr) == ISC_R_SUCCESS);
/*
* open up a listener socket
*/
so1 = NULL; so1 = NULL;
memset(&sockaddr, 0, sizeof(sockaddr));
sockaddr.type.sin.sin_family = AF_INET;
sockaddr.type.sin.sin_port = htons(5544);
addrlen = sizeof(struct sockaddr_in);
INSIST(isc_socket_create(socketmgr, isc_socket_tcp, INSIST(isc_socket_create(socketmgr, isc_socket_tcp,
&so1) == ISC_R_SUCCESS); &so1) == ISC_R_SUCCESS);
INSIST(isc_socket_bind(so1, &sockaddr, addrlen) == ISC_R_SUCCESS); INSIST(isc_socket_bind(so1, &sockaddr, addrlen) == ISC_R_SUCCESS);
INSIST(isc_socket_listen(so1, 0) == ISC_R_SUCCESS); INSIST(isc_socket_listen(so1, 0) == ISC_R_SUCCESS);
/*
* queue up the first accept event
*/
INSIST(isc_socket_accept(so1, t1, my_listen, INSIST(isc_socket_accept(so1, t1, my_listen,
"so1") == ISC_R_SUCCESS); "so1") == ISC_R_SUCCESS);
/*
* open up a socket that will connect to www.flame.org, port 80.
* Why not. :)
*/
so2 = NULL; so2 = NULL;
memset(&sockaddr, 0, sizeof(sockaddr));
sockaddr.type.sin.sin_port = htons(80);
sockaddr.type.sin.sin_family = AF_INET;
INSIST(inet_aton("204.152.184.97", &sockaddr.type.sin.sin_addr) == 1);
addrlen = sizeof(struct sockaddr_in);
INSIST(isc_socket_create(socketmgr, isc_socket_tcp, INSIST(isc_socket_create(socketmgr, isc_socket_tcp,
&so2) == ISC_R_SUCCESS); &so2) == ISC_R_SUCCESS);
INSIST(isc_socket_connect(so2, &sockaddr, addrlen, t1, my_connect,
"so2") == ISC_R_SUCCESS);
sleep(2); sleep(2);

View File

@@ -1,4 +1,4 @@
/* $Id: socket.h,v 1.6 1998/11/15 11:48:21 explorer Exp $ */ /* $Id: socket.h,v 1.7 1998/11/26 00:10:33 explorer Exp $ */
#ifndef ISC_SOCKET_H #ifndef ISC_SOCKET_H
#define ISC_SOCKET_H 1 #define ISC_SOCKET_H 1
@@ -82,7 +82,7 @@ typedef struct isc_socketevent {
unsigned int addrlength; /* length of address */ unsigned int addrlength; /* length of address */
} *isc_socketevent_t; } *isc_socketevent_t;
typedef struct isc_socket_newconev { typedef struct isc_socket_newconnev {
struct isc_event common; struct isc_event common;
isc_socket_t newsocket; isc_socket_t newsocket;
isc_result_t result; /* OK, EOF, whatever else */ isc_result_t result; /* OK, EOF, whatever else */
@@ -90,11 +90,16 @@ typedef struct isc_socket_newconev {
unsigned int addrlength; /* length of address */ unsigned int addrlength; /* length of address */
} *isc_socket_newconnev_t; } *isc_socket_newconnev_t;
typedef struct isc_socket_connev {
struct isc_event common;
isc_result_t result; /* OK, EOF, whatever else */
} *isc_socket_connev_t;
#define ISC_SOCKEVENT_ANYEVENT (0) #define ISC_SOCKEVENT_ANYEVENT (0)
#define ISC_SOCKEVENT_RECVDONE (ISC_EVENTCLASS_SOCKET + 1) #define ISC_SOCKEVENT_RECVDONE (ISC_EVENTCLASS_SOCKET + 1)
#define ISC_SOCKEVENT_SENDDONE (ISC_EVENTCLASS_SOCKET + 2) #define ISC_SOCKEVENT_SENDDONE (ISC_EVENTCLASS_SOCKET + 2)
#define ISC_SOCKEVENT_NEWCONN (ISC_EVENTCLASS_SOCKET + 3) #define ISC_SOCKEVENT_NEWCONN (ISC_EVENTCLASS_SOCKET + 3)
#define ISC_SOCKEVENT_CONNECTED (ISC_EVENTCLASS_SOCKET + 4) #define ISC_SOCKEVENT_CONNECT (ISC_EVENTCLASS_SOCKET + 4)
#define ISC_SOCKEVENT_RECVMARK (ISC_EVENTCLASS_SOCKET + 5) #define ISC_SOCKEVENT_RECVMARK (ISC_EVENTCLASS_SOCKET + 5)
#define ISC_SOCKEVENT_SENDMARK (ISC_EVENTCLASS_SOCKET + 6) #define ISC_SOCKEVENT_SENDMARK (ISC_EVENTCLASS_SOCKET + 6)
@@ -306,7 +311,7 @@ isc_socket_connect(isc_socket_t socket, struct isc_sockaddr *addressp,
void *arg); void *arg);
/* /*
* Connect 'socket' to peer with address *saddr. When the connection * Connect 'socket' to peer with address *saddr. When the connection
* succeeds, or when an error occurs, a CONNECTED event with action 'action' * succeeds, or when an error occurs, a CONNECT event with action 'action'
* and arg 'arg' will be posted to the event queue for 'task'. * and arg 'arg' will be posted to the event queue for 'task'.
* *
* Requires: * Requires:

View File

@@ -1,4 +1,4 @@
/* $Id: socket.c,v 1.9 1998/11/15 11:48:17 explorer Exp $ */ /* $Id: socket.c,v 1.10 1998/11/26 00:10:33 explorer Exp $ */
#include "attribute.h" #include "attribute.h"
@@ -70,9 +70,17 @@ typedef struct isc_socket_ncintev {
LINK(struct isc_socket_ncintev) link; LINK(struct isc_socket_ncintev) link;
} *isc_socket_ncintev_t; } *isc_socket_ncintev_t;
typedef struct isc_socket_connintev {
struct isc_event common;
isc_boolean_t canceled;
isc_task_t task;
isc_socket_connev_t done; /* the done event */
} *isc_socket_connintev_t;
#define SOCKET_MAGIC 0x494f696fU /* IOio */ #define SOCKET_MAGIC 0x494f696fU /* IOio */
#define VALID_SOCKET(t) ((t) != NULL && \ #define VALID_SOCKET(t) ((t) != NULL \
(t)->magic == SOCKET_MAGIC) && (t)->magic == SOCKET_MAGIC)
struct isc_socket { struct isc_socket {
/* Not locked. */ /* Not locked. */
unsigned int magic; unsigned int magic;
@@ -84,12 +92,15 @@ struct isc_socket {
LIST(struct isc_socket_intev) read_list; LIST(struct isc_socket_intev) read_list;
LIST(struct isc_socket_intev) write_list; LIST(struct isc_socket_intev) write_list;
LIST(struct isc_socket_ncintev) listen_list; LIST(struct isc_socket_ncintev) listen_list;
isc_socket_connintev_t connect_ev;
isc_boolean_t pending_read; isc_boolean_t pending_read;
isc_boolean_t pending_write; isc_boolean_t pending_write;
isc_boolean_t listener; /* listener socket */ isc_boolean_t listener; /* listener socket */
isc_boolean_t connecting;
isc_sockettype_t type; isc_sockettype_t type;
isc_socket_intev_t riev; isc_socket_intev_t riev;
isc_socket_intev_t wiev; isc_socket_intev_t wiev;
isc_socket_connintev_t ciev;
struct isc_sockaddr address; struct isc_sockaddr address;
unsigned int addrlength; unsigned int addrlength;
}; };
@@ -122,11 +133,15 @@ static void send_recvdone_event(isc_socket_t, isc_socket_intev_t *,
isc_socketevent_t *, isc_result_t); isc_socketevent_t *, isc_result_t);
static void send_senddone_event(isc_socket_t, isc_socket_intev_t *, static void send_senddone_event(isc_socket_t, isc_socket_intev_t *,
isc_socketevent_t *, isc_result_t); isc_socketevent_t *, isc_result_t);
static void rwdone_event_destroy(isc_event_t); static void done_event_destroy(isc_event_t);
static void free_socket(isc_socket_t *); static void free_socket(isc_socket_t *);
static isc_result_t allocate_socket(isc_socketmgr_t, isc_sockettype_t, static isc_result_t allocate_socket(isc_socketmgr_t, isc_sockettype_t,
isc_socket_t *); isc_socket_t *);
static void destroy(isc_socket_t *); static void destroy(isc_socket_t *);
static isc_boolean_t internal_accept(isc_task_t, isc_event_t);
static isc_boolean_t internal_connect(isc_task_t, isc_event_t);
static isc_boolean_t internal_read(isc_task_t, isc_event_t);
static isc_boolean_t internal_write(isc_task_t, isc_event_t);
/* /*
* poke the select loop when there is something for us to do. Manager must * poke the select loop when there is something for us to do. Manager must
@@ -158,18 +173,18 @@ select_readmsg(isc_socketmgr_t mgr)
cc = read(mgr->pipe_fds[0], &msg, sizeof(int)); cc = read(mgr->pipe_fds[0], &msg, sizeof(int));
if (cc < 0) { if (cc < 0) {
if (errno == EWOULDBLOCK) if (errno == EAGAIN)
return SELECT_POKE_NOTHING; return (SELECT_POKE_NOTHING);
UNEXPECTED_ERROR(__FILE__, __LINE__, UNEXPECTED_ERROR(__FILE__, __LINE__,
"read() failed during watcher poke: %s", "read() failed during watcher poke: %s",
strerror(errno)); strerror(errno));
return SELECT_POKE_NOTHING; /* XXX */ return (SELECT_POKE_NOTHING);
} }
INSIST(cc == sizeof(int)); INSIST(cc == sizeof(int));
return msg; return (msg);
} }
/* /*
@@ -199,7 +214,7 @@ make_nonblock(int fd)
* Handle freeing a done event when needed. * Handle freeing a done event when needed.
*/ */
static void static void
rwdone_event_destroy(isc_event_t ev) done_event_destroy(isc_event_t ev)
{ {
isc_socket_t sock = ev->sender; isc_socket_t sock = ev->sender;
isc_boolean_t kill_socket = ISC_FALSE; isc_boolean_t kill_socket = ISC_FALSE;
@@ -212,7 +227,7 @@ rwdone_event_destroy(isc_event_t ev)
REQUIRE(sock->references > 0); REQUIRE(sock->references > 0);
sock->references--; sock->references--;
XTRACE(("rwdone_event_destroy: sock %p, ref cnt == %d\n", XTRACE(("done_event_destroy: sock %p, ref cnt == %d\n",
sock, sock->references)); sock, sock->references));
if (sock->references == 0) if (sock->references == 0)
@@ -223,27 +238,6 @@ rwdone_event_destroy(isc_event_t ev)
destroy(&sock); destroy(&sock);
} }
static void
ncdone_event_destroy(isc_event_t ev)
{
isc_socket_t sock = ev->sender;
isc_boolean_t kill_socket = ISC_FALSE;
/*
* detach from the socket. We would have already detached from the
* task when we actually queue this event up.
*/
LOCK(&sock->lock);
sock->references--;
if (sock->references == 0)
kill_socket = ISC_TRUE;
UNLOCK(&sock->lock);
if (kill_socket)
destroy(&sock);
}
/* /*
* Kill. * Kill.
* *
@@ -300,6 +294,8 @@ allocate_socket(isc_socketmgr_t manager, isc_sockettype_t type,
INIT_LIST(sock->listen_list); INIT_LIST(sock->listen_list);
sock->pending_read = ISC_FALSE; sock->pending_read = ISC_FALSE;
sock->pending_write = ISC_FALSE; sock->pending_write = ISC_FALSE;
sock->listener = ISC_FALSE;
sock->connecting = ISC_FALSE;
/* /*
* initialize the lock * initialize the lock
@@ -374,9 +370,6 @@ isc_socket_create(isc_socketmgr_t manager, isc_sockettype_t type,
if (ret != ISC_R_SUCCESS) if (ret != ISC_R_SUCCESS)
return (ret); return (ret);
/*
* Create the associated socket XXX
*/
switch (type) { switch (type) {
case isc_socket_udp: case isc_socket_udp:
sock->fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); sock->fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
@@ -538,6 +531,18 @@ dispatch_listen(isc_socket_t sock)
isc_task_send(iev->task, &ev); isc_task_send(iev->task, &ev);
} }
static void
dispatch_connect(isc_socket_t sock)
{
isc_socket_connintev_t iev;
INSIST(sock->connecting);
iev = sock->connect_ev;
isc_task_send(iev->task, (isc_event_t *)&iev);
}
/* /*
* Dequeue an item off the given socket's read queue, set the result code * Dequeue an item off the given socket's read queue, set the result code
* in the done event to the one provided, and send it to the task it was * in the done event to the one provided, and send it to the task it was
@@ -642,14 +647,14 @@ internal_accept(isc_task_t task, isc_event_t ev)
/* /*
* Try to accept the new connection. If the accept fails with * Try to accept the new connection. If the accept fails with
* EWOULDBLOCK, simply poke the watcher to watch this socket * EAGAIN, simply poke the watcher to watch this socket
* again. * again.
*/ */
addrlen = sizeof(addr); addrlen = sizeof(addr);
fd = accept(sock->fd, &addr, &addrlen); fd = accept(sock->fd, &addr, &addrlen);
if (fd < 0) { if (fd < 0) {
if (errno == EWOULDBLOCK) { if (errno == EAGAIN) {
XTRACE(("internal_accept: ewouldblock\n")); XTRACE(("internal_accept: EAGAIN\n"));
sock->pending_read = ISC_FALSE; sock->pending_read = ISC_FALSE;
select_poke(sock->manager, sock->fd); select_poke(sock->manager, sock->fd);
UNLOCK(&sock->lock); UNLOCK(&sock->lock);
@@ -791,7 +796,7 @@ internal_read(isc_task_t task, isc_event_t ev)
* check for error or block condition * check for error or block condition
*/ */
if (cc < 0) { if (cc < 0) {
if (cc == EWOULDBLOCK) if (errno == EAGAIN)
goto poke; goto poke;
UNEXPECTED_ERROR(__FILE__, __LINE__, UNEXPECTED_ERROR(__FILE__, __LINE__,
"internal read: %s", "internal read: %s",
@@ -935,7 +940,7 @@ internal_write(isc_task_t task, isc_event_t ev)
* check for error or block condition * check for error or block condition
*/ */
if (cc < 0) { if (cc < 0) {
if (cc == EWOULDBLOCK) if (errno == EAGAIN)
goto poke; goto poke;
UNEXPECTED_ERROR(__FILE__, __LINE__, UNEXPECTED_ERROR(__FILE__, __LINE__,
"internal_write: %s", "internal_write: %s",
@@ -1104,7 +1109,9 @@ watcher(void *uap)
} }
iev = HEAD(sock->write_list); iev = HEAD(sock->write_list);
if (iev == NULL || sock->pending_write) { if ((iev == NULL
|| sock->pending_write)
&& !sock->connecting) {
FD_CLR(sock->fd, FD_CLR(sock->fd,
&manager->write_fds); &manager->write_fds);
XTRACE(("watch cleared w\n")); XTRACE(("watch cleared w\n"));
@@ -1145,7 +1152,10 @@ watcher(void *uap)
unlock_sock = ISC_TRUE; unlock_sock = ISC_TRUE;
LOCK(&sock->lock); LOCK(&sock->lock);
} }
dispatch_write(sock); if (sock->connecting)
dispatch_connect(sock);
else
dispatch_write(sock);
FD_CLR(i, &manager->write_fds); FD_CLR(i, &manager->write_fds);
} }
if (unlock_sock) if (unlock_sock)
@@ -1196,7 +1206,7 @@ isc_socketmgr_create(isc_memctx_t mctx, isc_socketmgr_t *managerp)
isc_mem_put(mctx, manager, sizeof *manager); isc_mem_put(mctx, manager, sizeof *manager);
UNEXPECTED_ERROR(__FILE__, __LINE__, UNEXPECTED_ERROR(__FILE__, __LINE__,
"pipe() failed: %s", "pipe() failed: %s",
strerror(errno)); /* XXX */ strerror(errno));
return (ISC_R_UNEXPECTED); return (ISC_R_UNEXPECTED);
} }
@@ -1324,7 +1334,7 @@ isc_socket_recv(isc_socket_t sock, isc_region_t region,
/* /*
* Remember that we need to detach on event free * Remember that we need to detach on event free
*/ */
ev->common.destroy = rwdone_event_destroy; ev->common.destroy = done_event_destroy;
ev->region = *region; ev->region = *region;
ev->n = 0; ev->n = 0;
@@ -1347,7 +1357,7 @@ isc_socket_recv(isc_socket_t sock, isc_region_t region,
} }
if (cc < 0) { if (cc < 0) {
if (cc == EWOULDBLOCK) if (errno == EAGAIN)
goto queue; goto queue;
UNEXPECTED_ERROR(__FILE__, __LINE__, UNEXPECTED_ERROR(__FILE__, __LINE__,
"isc_socket_recv: %s", "isc_socket_recv: %s",
@@ -1466,7 +1476,7 @@ isc_socket_sendto(isc_socket_t sock, isc_region_t region,
/* /*
* Remember that we need to detach on event free * Remember that we need to detach on event free
*/ */
ev->common.destroy = rwdone_event_destroy; ev->common.destroy = done_event_destroy;
ev->region = *region; ev->region = *region;
ev->n = 0; ev->n = 0;
@@ -1499,16 +1509,20 @@ isc_socket_sendto(isc_socket_t sock, isc_region_t region,
else if (sock->type == isc_socket_tcp) else if (sock->type == isc_socket_tcp)
cc = send(sock->fd, ev->region.base, cc = send(sock->fd, ev->region.base,
ev->region.length, 0); ev->region.length, 0);
else else {
cc = -1; /* XXX */ UNEXPECTED_ERROR(__FILE__, __LINE__,
"isc_socket_send: unknown socket type");
return (ISC_R_UNEXPECTED);
}
if (cc < 0) { if (cc < 0) {
if (cc == EWOULDBLOCK) if (errno == EAGAIN)
goto queue; goto queue;
UNEXPECTED_ERROR(__FILE__, __LINE__, UNEXPECTED_ERROR(__FILE__, __LINE__,
"isc_socket_send: %s", "isc_socket_send: %s",
strerror(errno)); strerror(errno));
INSIST(cc >= 0); return (ISC_R_UNEXPECTED);
} }
if (cc == 0) { if (cc == 0) {
@@ -1653,6 +1667,9 @@ isc_socket_listen(isc_socket_t sock, int backlog)
return (ISC_R_SUCCESS); return (ISC_R_SUCCESS);
} }
/*
* This should try to do agressive accept()
*/
isc_result_t isc_result_t
isc_socket_accept(isc_socket_t sock, isc_socket_accept(isc_socket_t sock,
isc_task_t task, isc_taskaction_t action, void *arg) isc_task_t task, isc_taskaction_t action, void *arg)
@@ -1718,7 +1735,7 @@ isc_socket_accept(isc_socket_t sock,
iev->task = ntask; iev->task = ntask;
iev->done = dev; iev->done = dev;
iev->canceled = ISC_FALSE; iev->canceled = ISC_FALSE;
dev->common.destroy = ncdone_event_destroy; dev->common.destroy = done_event_destroy;
dev->newsocket = nsock; dev->newsocket = nsock;
/* /*
@@ -1735,3 +1752,207 @@ isc_socket_accept(isc_socket_t sock,
return (ISC_R_SUCCESS); return (ISC_R_SUCCESS);
} }
isc_result_t
isc_socket_connect(isc_socket_t sock, struct isc_sockaddr *addr, int addrlen,
isc_task_t task, isc_taskaction_t action, void *arg)
{
isc_socket_connev_t dev;
isc_task_t ntask = NULL;
isc_socketmgr_t manager;
int cc;
XENTER("isc_socket_connect");
REQUIRE(VALID_SOCKET(sock));
manager = sock->manager;
REQUIRE(VALID_MANAGER(manager));
LOCK(&sock->lock);
REQUIRE(!sock->connecting);
if (sock->ciev == NULL) {
sock->ciev = (isc_socket_connintev_t)isc_event_allocate(manager->mctx,
sock,
ISC_SOCKEVENT_INTCONN,
internal_connect,
sock,
sizeof(*(sock->ciev)));
if (sock->ciev == NULL) {
UNLOCK(&sock->lock);
return (ISC_R_NOMEMORY);
}
}
dev = (isc_socket_connev_t)isc_event_allocate(manager->mctx,
sock,
ISC_SOCKEVENT_CONNECT,
action,
arg,
sizeof (*dev));
if (dev == NULL) {
UNLOCK(&sock->lock);
return (ISC_R_NOMEMORY);
}
/*
* attach to socket
*/
sock->references++;
/*
* Try to do the connect right away, as there can be only one
* outstanding, and it might happen to complete.
*/
sock->address = *addr;
sock->addrlength = addrlen;
cc = connect(sock->fd, (struct sockaddr *)addr, addrlen);
if (cc < 0) {
if (errno == EAGAIN || errno == EINPROGRESS)
goto queue;
/* XXX check for normal errors here */
UNEXPECTED_ERROR(__FILE__, __LINE__,
"%s", strerror(errno));
return (ISC_R_UNEXPECTED);
}
/*
* If connect completed, fire off the done event
*/
if (cc == 0) {
dev->result = ISC_R_SUCCESS;
isc_task_send(task, (isc_event_t *)&dev);
UNLOCK(&sock->lock);
return (ISC_R_SUCCESS);
}
queue:
XTRACE(("queueing connect internal event\n"));
/*
* Attach to to task
*/
isc_task_attach(task, &ntask);
sock->connecting = ISC_TRUE;
sock->ciev->task = ntask;
sock->ciev->done = dev;
sock->ciev->canceled = ISC_FALSE;
dev->common.destroy = done_event_destroy;
/*
* poke watcher here. We still have the socket locked, so there
* is no race condition. We will keep the lock for such a short
* bit of time waking it up now or later won't matter all that much.
*/
if (sock->connect_ev == NULL)
select_poke(manager, sock->fd);
sock->connect_ev = sock->ciev;
sock->ciev = NULL;
UNLOCK(&sock->lock);
return (ISC_R_SUCCESS);
}
/*
* Called when a socket with a pending connect() finishes.
*/
static isc_boolean_t
internal_connect(isc_task_t task, isc_event_t ev)
{
isc_socket_t sock;
isc_socket_connev_t dev;
isc_socket_connintev_t iev;
int cc;
int optlen;
sock = ev->sender;
iev = (isc_socket_connintev_t)ev;
REQUIRE(VALID_SOCKET(sock));
LOCK(&sock->lock);
XTRACE(("internal_connect called, locked parent sock %p\n", sock));
REQUIRE(sock->connecting);
REQUIRE(sock->connect_ev != NULL);
REQUIRE(iev->task == task);
sock->connecting = ISC_FALSE;
/*
* Has this event been canceled?
*/
if (iev->canceled) {
isc_event_free((isc_event_t *)(sock->connect_ev));
UNLOCK(&sock->lock);
return (0);
}
dev = iev->done;
/*
* Get any possible error status here.
*/
optlen = sizeof(cc);
if (getsockopt(sock->fd, SOL_SOCKET, SO_ERROR,
(char *)&cc, &optlen) < 0)
cc = errno;
else
errno = cc;
if (errno != 0) {
/*
* If the error is EAGAIN, just re-select on this
* fd and pretend nothing strange happened.
*/
if (errno == EAGAIN || errno == EINPROGRESS) {
XTRACE(("internal_connect: EAGAIN\n"));
sock->connecting = ISC_TRUE;
select_poke(sock->manager, sock->fd);
UNLOCK(&sock->lock);
return (0);
}
/*
* Translate other errors into ISC_R_* flavors.
*/
switch (errno) {
case ETIMEDOUT:
dev->result = ISC_R_TIMEDOUT;
break;
case ECONNREFUSED:
dev->result = ISC_R_CONNREFUSED;
break;
case ENETUNREACH:
dev->result = ISC_R_NETUNREACH;
break;
default:
dev->result = ISC_R_UNEXPECTED;
UNEXPECTED_ERROR(__FILE__, __LINE__,
"internal_connect: connect() %s",
strerror(errno));
break;
}
}
UNLOCK(&sock->lock);
/*
* It's safe to do this, since the done event's free routine will
* detach from the socket, so sock can't disappear out from under
* us.
*/
isc_task_send(iev->task, (isc_event_t *)&dev);
iev->done = NULL;
return (0);
}