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:
@@ -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, ®ion, task, my_send, event->arg);
|
strcpy(region.base, buf); /* strcpy is safe */
|
||||||
|
isc_socket_send(sock, ®ion, 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, ®ion, 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);
|
||||||
|
|
||||||
|
@@ -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:
|
||||||
|
@@ -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);
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user