mirror of
https://gitlab.isc.org/isc-projects/bind9
synced 2025-09-02 23:55:27 +00:00
checkpoint. listen and read works, now.
This commit is contained in:
@@ -40,18 +40,75 @@ my_shutdown(isc_task_t task, isc_event_t event)
|
|||||||
return (ISC_TRUE);
|
return (ISC_TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static isc_boolean_t
|
||||||
|
my_recv(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("Socket %s (sock %p, base %p, length %d, n %d, result %d)\n",
|
||||||
|
(char *)(event->arg), sock,
|
||||||
|
dev->region.base, dev->region.length,
|
||||||
|
dev->n, dev->result);
|
||||||
|
|
||||||
|
if (dev->result != ISC_R_SUCCESS) {
|
||||||
|
isc_socket_detach(&sock);
|
||||||
|
|
||||||
|
isc_event_free(&event);
|
||||||
|
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
isc_socket_recv(sock, &dev->region, ISC_FALSE,
|
||||||
|
task, my_recv, 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)
|
||||||
{
|
{
|
||||||
char *name = event->arg;
|
char *name = event->arg;
|
||||||
|
isc_socket_newconnev_t dev;
|
||||||
|
isc_region_t region;
|
||||||
|
|
||||||
printf("newcon %s (%p)\n", name, task);
|
dev = (isc_socket_newconnev_t)event;
|
||||||
|
|
||||||
|
printf("newcon %s (task %p, oldsock %p, newsock %p, result %d)\n",
|
||||||
|
name, task, event->sender, dev->newsocket, dev->result);
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
|
|
||||||
|
if (dev->result == ISC_R_SUCCESS) {
|
||||||
|
/*
|
||||||
|
* queue another listen on this socket
|
||||||
|
*/
|
||||||
|
isc_socket_accept(event->sender, task, my_listen, event->arg);
|
||||||
|
|
||||||
|
region = isc_mem_get(event->mctx, sizeof(*region));
|
||||||
|
INSIST(region != NULL);
|
||||||
|
|
||||||
|
region->base = isc_mem_get(event->mctx, 21);
|
||||||
|
region->length = 20;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* queue up a read on this socket
|
||||||
|
*/
|
||||||
|
isc_socket_recv(dev->newsocket, region, ISC_FALSE,
|
||||||
|
task, my_recv, event->arg);
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* Do something useful here
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
isc_event_free(&event);
|
isc_event_free(&event);
|
||||||
|
|
||||||
tasks_done++;
|
return 0;
|
||||||
|
|
||||||
return (ISC_TRUE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@@ -95,7 +152,9 @@ main(int argc, char *argv[])
|
|||||||
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, t1, my_listen,
|
INSIST(isc_socket_listen(so1, 0) == ISC_R_SUCCESS);
|
||||||
|
|
||||||
|
INSIST(isc_socket_accept(so1, t1, my_listen,
|
||||||
"so1") == ISC_R_SUCCESS);
|
"so1") == ISC_R_SUCCESS);
|
||||||
|
|
||||||
so2 = NULL;
|
so2 = NULL;
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
/* $Id: socket.h,v 1.3 1998/11/10 01:56:44 explorer Exp $ */
|
/* $Id: socket.h,v 1.4 1998/11/10 11:37:54 explorer Exp $ */
|
||||||
|
|
||||||
#ifndef ISC_SOCKET_H
|
#ifndef ISC_SOCKET_H
|
||||||
#define ISC_SOCKET_H 1
|
#define ISC_SOCKET_H 1
|
||||||
@@ -85,6 +85,7 @@ typedef struct isc_socketevent {
|
|||||||
typedef struct isc_socket_newconev {
|
typedef struct isc_socket_newconev {
|
||||||
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_socket_newconnev_t;
|
} *isc_socket_newconnev_t;
|
||||||
|
|
||||||
#define ISC_SOCKEVENT_ANYEVENT (0)
|
#define ISC_SOCKEVENT_ANYEVENT (0)
|
||||||
@@ -253,8 +254,7 @@ isc_socket_bind(isc_socket_t socket, struct isc_sockaddr *addressp,
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
isc_result_t
|
isc_result_t
|
||||||
isc_socket_listen(isc_socket_t socket, int backlog,
|
isc_socket_listen(isc_socket_t socket, int backlog);
|
||||||
isc_task_t task, isc_taskaction_t action, void *arg);
|
|
||||||
/*
|
/*
|
||||||
* Listen on 'socket'. Every time a new connection request arrives,
|
* Listen on 'socket'. Every time a new connection request arrives,
|
||||||
* a NEWCONN event with action 'action' and arg 'arg' will be posted
|
* a NEWCONN event with action 'action' and arg 'arg' will be posted
|
||||||
@@ -278,61 +278,24 @@ isc_socket_listen(isc_socket_t socket, int backlog,
|
|||||||
* Unexpected error
|
* Unexpected error
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void
|
|
||||||
isc_socket_hold(isc_socket_t socket);
|
|
||||||
/*
|
|
||||||
* Put a TCP listener socket on hold. No NEWCONN events will be posted
|
|
||||||
*
|
|
||||||
* Notes:
|
|
||||||
*
|
|
||||||
* While 'on hold', new connection requests will be queued or dropped
|
|
||||||
* by the operating system.
|
|
||||||
*
|
|
||||||
* Requires:
|
|
||||||
*
|
|
||||||
* 'socket' is a valid TCP socket
|
|
||||||
*
|
|
||||||
* Some task is listening on the socket.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
void
|
|
||||||
isc_socket_unhold(isc_socket_t socket);
|
|
||||||
/*
|
|
||||||
* Restore normal NEWCONN event posting.
|
|
||||||
*
|
|
||||||
* Requires:
|
|
||||||
*
|
|
||||||
* 'socket' is a valid TCP socket
|
|
||||||
*
|
|
||||||
* Some task is listening on the socket.
|
|
||||||
*
|
|
||||||
* 'socket' is holding.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
isc_result_t
|
isc_result_t
|
||||||
isc_socket_accept(isc_socket_t s1, isc_socket_t *s2p);
|
isc_socket_accept(isc_socket_t socket,
|
||||||
|
isc_task_t task, isc_taskaction_t action, void *arg);
|
||||||
/*
|
/*
|
||||||
* Accept a connection from 's1', creating a new socket for the connection
|
* Queue accept event.
|
||||||
* and attaching '*s2p' to it.
|
|
||||||
*
|
*
|
||||||
* Requires:
|
* REQUIRES:
|
||||||
|
* 'socket' is a valid TCP socket that isc_socket_listen() has been
|
||||||
|
* called on
|
||||||
*
|
*
|
||||||
* 'socket' is a valid TCP socket.
|
* 'task' is a valid task
|
||||||
*
|
*
|
||||||
* s2p is a valid pointer, and *s2p == NULL;
|
* 'action' is a valid action
|
||||||
*
|
*
|
||||||
* Ensures:
|
* RETURNS:
|
||||||
*
|
* ISC_R_SUCCESS
|
||||||
* *s2p is attached to the newly created socket.
|
* ISC_R_NOMEMORY
|
||||||
*
|
* ISC_R_UNEXPECTED
|
||||||
* Returns:
|
|
||||||
*
|
|
||||||
* Success
|
|
||||||
* No memory
|
|
||||||
* No pending connection requests
|
|
||||||
* Unexpected error
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
isc_result_t
|
isc_result_t
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
/* $Id: socket.c,v 1.4 1998/11/10 01:56:43 explorer Exp $ */
|
/* $Id: socket.c,v 1.5 1998/11/10 11:37:53 explorer Exp $ */
|
||||||
|
|
||||||
#include "attribute.h"
|
#include "attribute.h"
|
||||||
|
|
||||||
@@ -70,6 +70,7 @@ typedef struct isc_socket_ncintev {
|
|||||||
isc_task_t task;
|
isc_task_t task;
|
||||||
isc_socket_newconnev_t done; /* the done event */
|
isc_socket_newconnev_t done; /* the done event */
|
||||||
isc_socket_t sock; /* the socket we will pass or destroy */
|
isc_socket_t sock; /* the socket we will pass or destroy */
|
||||||
|
LINK(struct isc_socket_ncintev) link;
|
||||||
} *isc_socket_ncintev_t;
|
} *isc_socket_ncintev_t;
|
||||||
|
|
||||||
#define SOCKET_MAGIC 0x494f696fU /* IOio */
|
#define SOCKET_MAGIC 0x494f696fU /* IOio */
|
||||||
@@ -85,6 +86,7 @@ struct isc_socket {
|
|||||||
int fd;
|
int fd;
|
||||||
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;
|
||||||
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 */
|
||||||
@@ -118,9 +120,9 @@ struct isc_socketmgr {
|
|||||||
#define SELECT_POKE_SHUTDOWN (-1)
|
#define SELECT_POKE_SHUTDOWN (-1)
|
||||||
#define SELECT_POKE_NOTHING (-2)
|
#define SELECT_POKE_NOTHING (-2)
|
||||||
|
|
||||||
static void send_done_event(isc_socket_t, isc_socket_intev_t *,
|
static void send_rwdone_event(isc_socket_t, isc_socket_intev_t *,
|
||||||
isc_socketevent_t *, isc_result_t);
|
isc_socketevent_t *, isc_result_t);
|
||||||
static void done_event_destroy(isc_event_t);
|
static void rwdone_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 *);
|
||||||
@@ -196,7 +198,30 @@ make_nonblock(int fd)
|
|||||||
* Handle freeing a done event when needed.
|
* Handle freeing a done event when needed.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
done_event_destroy(isc_event_t ev)
|
rwdone_event_destroy(isc_event_t ev)
|
||||||
|
{
|
||||||
|
isc_socket_t sock = ev->sender;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* detach from the socket. We would have already detached from the
|
||||||
|
* task when we actually queue this event up.
|
||||||
|
*/
|
||||||
|
LOCK(&sock->lock);
|
||||||
|
|
||||||
|
REQUIRE(sock->references > 0);
|
||||||
|
sock->references--;
|
||||||
|
XTRACE(("rwdone_event_destroy: sock %p, ref cnt == %d\n",
|
||||||
|
sock, sock->references));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* XXX need to free socket on cnt = 0 here
|
||||||
|
*/
|
||||||
|
|
||||||
|
UNLOCK(&sock->lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ncdone_event_destroy(isc_event_t ev)
|
||||||
{
|
{
|
||||||
isc_socket_t sock = ev->sender;
|
isc_socket_t sock = ev->sender;
|
||||||
|
|
||||||
@@ -255,6 +280,7 @@ allocate_socket(isc_socketmgr_t manager, isc_sockettype_t type,
|
|||||||
*/
|
*/
|
||||||
INIT_LIST(sock->read_list);
|
INIT_LIST(sock->read_list);
|
||||||
INIT_LIST(sock->write_list);
|
INIT_LIST(sock->write_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;
|
||||||
|
|
||||||
@@ -293,6 +319,7 @@ free_socket(isc_socket_t *socketp)
|
|||||||
REQUIRE(!sock->pending_write);
|
REQUIRE(!sock->pending_write);
|
||||||
REQUIRE(EMPTY(sock->read_list));
|
REQUIRE(EMPTY(sock->read_list));
|
||||||
REQUIRE(EMPTY(sock->write_list));
|
REQUIRE(EMPTY(sock->write_list));
|
||||||
|
REQUIRE(EMPTY(sock->listen_list));
|
||||||
|
|
||||||
sock->magic = 0;
|
sock->magic = 0;
|
||||||
|
|
||||||
@@ -453,7 +480,10 @@ dispatch_read(isc_socket_t sock)
|
|||||||
|
|
||||||
sock->pending_read = ISC_TRUE;
|
sock->pending_read = ISC_TRUE;
|
||||||
|
|
||||||
isc_task_send(iev->task, &ev);
|
XTRACE(("dispatch_read: posted event %p to task %p\n",
|
||||||
|
ev, iev->task));
|
||||||
|
|
||||||
|
INSIST(isc_task_send(iev->task, &ev) == ISC_R_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -471,6 +501,22 @@ dispatch_write(isc_socket_t sock)
|
|||||||
isc_task_send(iev->task, &ev);
|
isc_task_send(iev->task, &ev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
dispatch_listen(isc_socket_t sock)
|
||||||
|
{
|
||||||
|
isc_socket_ncintev_t iev;
|
||||||
|
isc_event_t ev;
|
||||||
|
|
||||||
|
iev = HEAD(sock->listen_list);
|
||||||
|
ev = (isc_event_t)iev;
|
||||||
|
|
||||||
|
INSIST(!sock->pending_read);
|
||||||
|
|
||||||
|
sock->pending_read = ISC_TRUE;
|
||||||
|
|
||||||
|
isc_task_send(iev->task, &ev);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 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
|
||||||
@@ -479,7 +525,7 @@ dispatch_write(isc_socket_t sock)
|
|||||||
* Caller must have the socket locked.
|
* Caller must have the socket locked.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
send_done_event(isc_socket_t sock, isc_socket_intev_t *iev,
|
send_rwdone_event(isc_socket_t sock, isc_socket_intev_t *iev,
|
||||||
isc_socketevent_t *dev, isc_result_t resultcode)
|
isc_socketevent_t *dev, isc_result_t resultcode)
|
||||||
{
|
{
|
||||||
REQUIRE(!EMPTY(sock->read_list));
|
REQUIRE(!EMPTY(sock->read_list));
|
||||||
@@ -495,6 +541,27 @@ send_done_event(isc_socket_t sock, isc_socket_intev_t *iev,
|
|||||||
isc_event_free((isc_event_t *)iev);
|
isc_event_free((isc_event_t *)iev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
send_ncdone_event(isc_socket_t sock, isc_socket_ncintev_t *iev,
|
||||||
|
isc_socket_newconnev_t *dev, isc_result_t resultcode)
|
||||||
|
{
|
||||||
|
REQUIRE(!EMPTY(sock->listen_list));
|
||||||
|
REQUIRE(iev != NULL);
|
||||||
|
REQUIRE(*iev != NULL);
|
||||||
|
REQUIRE(dev != NULL);
|
||||||
|
REQUIRE(*dev != NULL);
|
||||||
|
|
||||||
|
DEQUEUE(sock->listen_list, *iev, link);
|
||||||
|
(*dev)->result = resultcode;
|
||||||
|
isc_task_send((*iev)->task, (isc_event_t *)dev);
|
||||||
|
(*iev)->done = NULL;
|
||||||
|
|
||||||
|
if ((*iev)->sock)
|
||||||
|
free_socket(&(*iev)->sock);
|
||||||
|
|
||||||
|
isc_event_free((isc_event_t *)iev);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Call accept() on a socket, to get the new file descriptor. The listen
|
* Call accept() on a socket, to get the new file descriptor. The listen
|
||||||
* socket is used as a prototype to create a new isc_socket_t. The new
|
* socket is used as a prototype to create a new isc_socket_t. The new
|
||||||
@@ -506,7 +573,6 @@ static isc_boolean_t
|
|||||||
internal_accept(isc_task_t task, isc_event_t ev)
|
internal_accept(isc_task_t task, isc_event_t ev)
|
||||||
{
|
{
|
||||||
isc_socket_t sock;
|
isc_socket_t sock;
|
||||||
isc_socket_t nsock = NULL;
|
|
||||||
isc_socket_newconnev_t dev;
|
isc_socket_newconnev_t dev;
|
||||||
isc_socket_ncintev_t iev;
|
isc_socket_ncintev_t iev;
|
||||||
struct sockaddr addr;
|
struct sockaddr addr;
|
||||||
@@ -517,15 +583,29 @@ internal_accept(isc_task_t task, isc_event_t ev)
|
|||||||
iev = (isc_socket_ncintev_t)ev;
|
iev = (isc_socket_ncintev_t)ev;
|
||||||
|
|
||||||
LOCK(&sock->lock);
|
LOCK(&sock->lock);
|
||||||
XTRACE(("internal_accept called, locked sock %p\n", sock));
|
XTRACE(("internal_accept called, locked parent sock %p\n", sock));
|
||||||
|
|
||||||
REQUIRE(sock->pending_read);
|
REQUIRE(sock->pending_read);
|
||||||
REQUIRE(sock->listener);
|
REQUIRE(sock->listener);
|
||||||
REQUIRE(!EMPTY(sock->read_list));
|
REQUIRE(!EMPTY(sock->listen_list));
|
||||||
REQUIRE(iev->task == task);
|
REQUIRE(iev->task == task);
|
||||||
|
|
||||||
sock->pending_read = ISC_FALSE;
|
sock->pending_read = ISC_FALSE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Has this event been canceled?
|
||||||
|
*/
|
||||||
|
if (iev->canceled) {
|
||||||
|
DEQUEUE(sock->listen_list, iev, link);
|
||||||
|
isc_event_free((isc_event_t *)iev);
|
||||||
|
if (!EMPTY(sock->listen_list))
|
||||||
|
select_poke(sock->manager, sock->fd);
|
||||||
|
|
||||||
|
UNLOCK(&sock->lock);
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 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
|
* EWOULDBLOCK, simply poke the watcher to watch this socket
|
||||||
@@ -534,6 +614,7 @@ internal_accept(isc_task_t task, isc_event_t ev)
|
|||||||
fd = accept(sock->fd, &addr, &addrlen);
|
fd = accept(sock->fd, &addr, &addrlen);
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
if (errno == EWOULDBLOCK) {
|
if (errno == EWOULDBLOCK) {
|
||||||
|
XTRACE(("internal_accept: ewouldblock\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);
|
||||||
@@ -546,6 +627,8 @@ internal_accept(isc_task_t task, isc_event_t ev)
|
|||||||
* changed, thanks to broken OSs trying to overload what
|
* changed, thanks to broken OSs trying to overload what
|
||||||
* accept does.
|
* accept does.
|
||||||
*/
|
*/
|
||||||
|
XTRACE(("internal_accept: accept returned %s\n",
|
||||||
|
strerror(errno)));
|
||||||
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);
|
||||||
@@ -558,11 +641,25 @@ internal_accept(isc_task_t task, isc_event_t ev)
|
|||||||
* were preallocated for us.
|
* were preallocated for us.
|
||||||
*/
|
*/
|
||||||
dev = iev->done;
|
dev = iev->done;
|
||||||
nsock = iev->sock;
|
iev->done = NULL;
|
||||||
|
|
||||||
nsock->fd = fd;
|
dev->newsocket->fd = fd;
|
||||||
|
|
||||||
dev->newsocket = nsock;
|
XTRACE(("internal_accept: newsock %p, fd %d\n",
|
||||||
|
dev->newsocket, fd));
|
||||||
|
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
LOCK(&sock->manager->lock);
|
||||||
|
sock->manager->fds[fd] = dev->newsocket;
|
||||||
|
UNLOCK(&sock->manager->lock);
|
||||||
|
|
||||||
|
send_ncdone_event(sock, &iev, &dev, ISC_R_SUCCESS);
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
@@ -585,6 +682,8 @@ internal_read(isc_task_t task, isc_event_t ev)
|
|||||||
INSIST(sock->pending_read == ISC_TRUE);
|
INSIST(sock->pending_read == ISC_TRUE);
|
||||||
sock->pending_read = ISC_FALSE;
|
sock->pending_read = ISC_FALSE;
|
||||||
|
|
||||||
|
XTRACE(("internal_read: sock %p, fd %d\n", sock, sock->fd));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Pull the first entry off the list, and look at it. If it is
|
* Pull the first entry off the list, and look at it. If it is
|
||||||
* NULL, or not ours, something bad happened.
|
* NULL, or not ours, something bad happened.
|
||||||
@@ -604,11 +703,9 @@ internal_read(isc_task_t task, isc_event_t ev)
|
|||||||
dev = iev->done_ev;
|
dev = iev->done_ev;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If dev is null here, there is no done event. This means
|
* check for canceled I/O
|
||||||
* someone other than us canceled our pending I/O.
|
|
||||||
* Just ignore this case.
|
|
||||||
*/
|
*/
|
||||||
if (dev == NULL) {
|
if (iev->canceled) {
|
||||||
DEQUEUE(sock->read_list, iev, link);
|
DEQUEUE(sock->read_list, iev, link);
|
||||||
isc_event_free((isc_event_t *)&iev);
|
isc_event_free((isc_event_t *)&iev);
|
||||||
continue;
|
continue;
|
||||||
@@ -619,7 +716,7 @@ internal_read(isc_task_t task, isc_event_t ev)
|
|||||||
* continue the loop.
|
* continue the loop.
|
||||||
*/
|
*/
|
||||||
if (dev->common.type == ISC_SOCKEVENT_RECVMARK) {
|
if (dev->common.type == ISC_SOCKEVENT_RECVMARK) {
|
||||||
send_done_event(sock, &iev, &dev, ISC_R_SUCCESS);
|
send_rwdone_event(sock, &iev, &dev, ISC_R_SUCCESS);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -628,7 +725,9 @@ internal_read(isc_task_t task, isc_event_t ev)
|
|||||||
* we can.
|
* we can.
|
||||||
*/
|
*/
|
||||||
read_count = dev->region.length - dev->n;
|
read_count = dev->region.length - dev->n;
|
||||||
cc = recv(sock->fd, dev->region.base + dev->n, read_count, 0);
|
cc = read(sock->fd, dev->region.base + dev->n, read_count);
|
||||||
|
|
||||||
|
XTRACE(("internal_read: read(%d) %d\n", sock->fd, cc));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* check for error or block condition
|
* check for error or block condition
|
||||||
@@ -649,8 +748,8 @@ internal_read(isc_task_t task, isc_event_t ev)
|
|||||||
*/
|
*/
|
||||||
if (cc == 0) {
|
if (cc == 0) {
|
||||||
do {
|
do {
|
||||||
send_done_event(sock, &iev, &dev,
|
send_rwdone_event(sock, &iev, &dev,
|
||||||
ISC_R_EOF);
|
ISC_R_EOF);
|
||||||
iev = HEAD(sock->read_list);
|
iev = HEAD(sock->read_list);
|
||||||
} while (iev != NULL);
|
} while (iev != NULL);
|
||||||
|
|
||||||
@@ -670,8 +769,8 @@ internal_read(isc_task_t task, isc_event_t ev)
|
|||||||
* the loop.
|
* the loop.
|
||||||
*/
|
*/
|
||||||
if (iev->partial) {
|
if (iev->partial) {
|
||||||
send_done_event(sock, &iev, &dev,
|
send_rwdone_event(sock, &iev, &dev,
|
||||||
ISC_R_SUCCESS);
|
ISC_R_SUCCESS);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -686,8 +785,10 @@ internal_read(isc_task_t task, isc_event_t ev)
|
|||||||
* Exactly what we wanted to read. We're done with this
|
* Exactly what we wanted to read. We're done with this
|
||||||
* entry. Post its completion event.
|
* entry. Post its completion event.
|
||||||
*/
|
*/
|
||||||
if ((size_t)cc == read_count)
|
if ((size_t)cc == read_count) {
|
||||||
send_done_event(sock, &iev, &dev, ISC_R_SUCCESS);
|
dev->n += read_count;
|
||||||
|
send_rwdone_event(sock, &iev, &dev, ISC_R_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
} while (!EMPTY(sock->read_list));
|
} while (!EMPTY(sock->read_list));
|
||||||
|
|
||||||
@@ -722,6 +823,7 @@ watcher(void *uap)
|
|||||||
isc_boolean_t unlock_sock;
|
isc_boolean_t unlock_sock;
|
||||||
int i;
|
int i;
|
||||||
isc_socket_intev_t iev;
|
isc_socket_intev_t iev;
|
||||||
|
isc_socket_ncintev_t nciev;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get the control fd here. This will never change.
|
* Get the control fd here. This will never change.
|
||||||
@@ -797,7 +899,9 @@ watcher(void *uap)
|
|||||||
* Otherwise, set it.
|
* Otherwise, set it.
|
||||||
*/
|
*/
|
||||||
iev = HEAD(sock->read_list);
|
iev = HEAD(sock->read_list);
|
||||||
if (iev == NULL || sock->pending_read) {
|
nciev = HEAD(sock->listen_list);
|
||||||
|
if ((iev == NULL && nciev == NULL)
|
||||||
|
|| sock->pending_read) {
|
||||||
FD_CLR(sock->fd,
|
FD_CLR(sock->fd,
|
||||||
&manager->read_fds);
|
&manager->read_fds);
|
||||||
XTRACE(("watch cleared r\n"));
|
XTRACE(("watch cleared r\n"));
|
||||||
@@ -836,7 +940,10 @@ watcher(void *uap)
|
|||||||
i, manager->fds[i]));
|
i, manager->fds[i]));
|
||||||
unlock_sock = ISC_TRUE;
|
unlock_sock = ISC_TRUE;
|
||||||
LOCK(&sock->lock);
|
LOCK(&sock->lock);
|
||||||
dispatch_read(sock);
|
if (sock->listener)
|
||||||
|
dispatch_listen(sock);
|
||||||
|
else
|
||||||
|
dispatch_read(sock);
|
||||||
FD_CLR(i, &manager->read_fds);
|
FD_CLR(i, &manager->read_fds);
|
||||||
}
|
}
|
||||||
if (FD_ISSET(i, &writefds)) {
|
if (FD_ISSET(i, &writefds)) {
|
||||||
@@ -981,7 +1088,7 @@ isc_socket_recv(isc_socket_t sock, isc_region_t region,
|
|||||||
isc_socketevent_t ev;
|
isc_socketevent_t ev;
|
||||||
isc_socket_intev_t iev;
|
isc_socket_intev_t iev;
|
||||||
isc_socketmgr_t manager;
|
isc_socketmgr_t manager;
|
||||||
isc_task_t ntask;
|
isc_task_t ntask = NULL;
|
||||||
|
|
||||||
manager = sock->manager;
|
manager = sock->manager;
|
||||||
|
|
||||||
@@ -1017,9 +1124,10 @@ 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 = done_event_destroy;
|
ev->common.destroy = rwdone_event_destroy;
|
||||||
|
|
||||||
ev->region = *region;
|
ev->region = *region;
|
||||||
|
ev->n = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the read queue is empty, try to do the I/O right now.
|
* If the read queue is empty, try to do the I/O right now.
|
||||||
@@ -1060,6 +1168,9 @@ isc_socket_recv(isc_socket_t sock, isc_region_t region,
|
|||||||
ENQUEUE(sock->read_list, iev, link);
|
ENQUEUE(sock->read_list, iev, link);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
XTRACE(("isc_socket_recv: posted ievent %p, dev %p, task %p\n",
|
||||||
|
iev, iev->done_ev, task));
|
||||||
|
|
||||||
UNLOCK(&sock->lock);
|
UNLOCK(&sock->lock);
|
||||||
|
|
||||||
return (ISC_R_SUCCESS);
|
return (ISC_R_SUCCESS);
|
||||||
@@ -1110,31 +1221,15 @@ isc_socket_bind(isc_socket_t sock, struct isc_sockaddr *sockaddr,
|
|||||||
* as well keep things simple rather than having to track them.
|
* as well keep things simple rather than having to track them.
|
||||||
*/
|
*/
|
||||||
isc_result_t
|
isc_result_t
|
||||||
isc_socket_listen(isc_socket_t sock, int backlog, isc_task_t task,
|
isc_socket_listen(isc_socket_t sock, int backlog)
|
||||||
isc_taskaction_t action, void *arg)
|
|
||||||
{
|
{
|
||||||
isc_socket_intev_t iev;
|
REQUIRE(VALID_SOCKET(sock));
|
||||||
isc_task_t ntask = NULL;
|
REQUIRE(backlog >= 0);
|
||||||
isc_socketmgr_t manager;
|
|
||||||
|
|
||||||
manager = sock->manager;
|
|
||||||
|
|
||||||
iev = (isc_socket_intev_t)isc_event_allocate(manager->mctx,
|
|
||||||
sock,
|
|
||||||
ISC_SOCKEVENT_INTCONN,
|
|
||||||
internal_accept,
|
|
||||||
sock,
|
|
||||||
sizeof(*iev));
|
|
||||||
if (iev == NULL)
|
|
||||||
return (ISC_R_NOMEMORY);
|
|
||||||
|
|
||||||
INIT_LINK(iev, link);
|
|
||||||
|
|
||||||
LOCK(&sock->lock);
|
LOCK(&sock->lock);
|
||||||
|
|
||||||
if (sock->type != isc_socket_tcp) {
|
if (sock->type != isc_socket_tcp) {
|
||||||
UNLOCK(&sock->lock);
|
UNLOCK(&sock->lock);
|
||||||
isc_event_free((isc_event_t *)&iev);
|
|
||||||
UNEXPECTED_ERROR(__FILE__, __LINE__,
|
UNEXPECTED_ERROR(__FILE__, __LINE__,
|
||||||
"Socket is not isc_socket_tcp");
|
"Socket is not isc_socket_tcp");
|
||||||
return (ISC_R_UNEXPECTED);
|
return (ISC_R_UNEXPECTED);
|
||||||
@@ -1142,7 +1237,6 @@ isc_socket_listen(isc_socket_t sock, int backlog, isc_task_t task,
|
|||||||
|
|
||||||
if (sock->listener) {
|
if (sock->listener) {
|
||||||
UNLOCK(&sock->lock);
|
UNLOCK(&sock->lock);
|
||||||
isc_event_free((isc_event_t *)&iev);
|
|
||||||
UNEXPECTED_ERROR(__FILE__, __LINE__,
|
UNEXPECTED_ERROR(__FILE__, __LINE__,
|
||||||
"Socket already listener");
|
"Socket already listener");
|
||||||
return (ISC_R_UNEXPECTED);
|
return (ISC_R_UNEXPECTED);
|
||||||
@@ -1150,35 +1244,95 @@ isc_socket_listen(isc_socket_t sock, int backlog, isc_task_t task,
|
|||||||
|
|
||||||
if (listen(sock->fd, backlog) < 0) {
|
if (listen(sock->fd, backlog) < 0) {
|
||||||
UNLOCK(&sock->lock);
|
UNLOCK(&sock->lock);
|
||||||
isc_event_free((isc_event_t *)&iev);
|
|
||||||
UNEXPECTED_ERROR(__FILE__, __LINE__, "listen: %s",
|
UNEXPECTED_ERROR(__FILE__, __LINE__, "listen: %s",
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
|
|
||||||
return (ISC_R_UNEXPECTED);
|
return (ISC_R_UNEXPECTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sock->listener = ISC_TRUE;
|
||||||
|
UNLOCK(&sock->lock);
|
||||||
|
|
||||||
|
return (ISC_R_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
isc_result_t
|
||||||
|
isc_socket_accept(isc_socket_t sock,
|
||||||
|
isc_task_t task, isc_taskaction_t action, void *arg)
|
||||||
|
{
|
||||||
|
isc_socket_ncintev_t iev;
|
||||||
|
isc_socket_newconnev_t dev;
|
||||||
|
isc_task_t ntask = NULL;
|
||||||
|
isc_socketmgr_t manager;
|
||||||
|
isc_socket_t nsock;
|
||||||
|
isc_result_t ret;
|
||||||
|
|
||||||
|
XENTER("isc_socket_accept");
|
||||||
|
REQUIRE(VALID_SOCKET(sock));
|
||||||
|
manager = sock->manager;
|
||||||
|
REQUIRE(VALID_MANAGER(manager));
|
||||||
|
|
||||||
|
LOCK(&sock->lock);
|
||||||
|
|
||||||
|
REQUIRE(sock->listener);
|
||||||
|
|
||||||
|
iev = (isc_socket_ncintev_t)isc_event_allocate(manager->mctx,
|
||||||
|
sock,
|
||||||
|
ISC_SOCKEVENT_INTCONN,
|
||||||
|
internal_accept,
|
||||||
|
sock,
|
||||||
|
sizeof(*iev));
|
||||||
|
if (iev == NULL) {
|
||||||
|
UNLOCK(&sock->lock);
|
||||||
|
return (ISC_R_NOMEMORY);
|
||||||
|
}
|
||||||
|
|
||||||
|
dev = (isc_socket_newconnev_t)isc_event_allocate(manager->mctx,
|
||||||
|
sock,
|
||||||
|
ISC_SOCKEVENT_NEWCONN,
|
||||||
|
action,
|
||||||
|
arg,
|
||||||
|
sizeof (*dev));
|
||||||
|
if (dev == NULL) {
|
||||||
|
UNLOCK(&sock->lock);
|
||||||
|
isc_event_free((isc_event_t *)&iev);
|
||||||
|
return (ISC_R_NOMEMORY);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ret = allocate_socket(manager, sock->type, &nsock);
|
||||||
|
if (ret != ISC_R_SUCCESS) {
|
||||||
|
UNLOCK(&sock->lock);
|
||||||
|
isc_event_free((isc_event_t *)&iev);
|
||||||
|
isc_event_free((isc_event_t *)&dev);
|
||||||
|
return (ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
INIT_LINK(iev, link);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Attach to socket and to task
|
* Attach to socket and to task
|
||||||
*/
|
*/
|
||||||
isc_task_attach(task, &ntask);
|
isc_task_attach(task, &ntask);
|
||||||
sock->references++;
|
sock->references++;
|
||||||
|
|
||||||
sock->listener = ISC_TRUE;
|
sock->listener = ISC_TRUE;
|
||||||
|
|
||||||
iev->task = ntask;
|
iev->task = ntask;
|
||||||
iev->done_ev = NULL;
|
iev->done = dev;
|
||||||
iev->partial = ISC_FALSE; /* state doesn't really matter */
|
iev->canceled = ISC_FALSE;
|
||||||
iev->action = action;
|
dev->common.destroy = ncdone_event_destroy;
|
||||||
iev->arg = arg;
|
dev->newsocket = nsock;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* poke watcher here. We still have the socket locked, so there
|
* poke watcher here. We still have the socket locked, so there
|
||||||
* is no race condition. We will keep the lock for such a short
|
* 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.
|
* bit of time waking it up now or later won't matter all that much.
|
||||||
*/
|
*/
|
||||||
if (EMPTY(sock->read_list))
|
if (EMPTY(sock->listen_list))
|
||||||
select_poke(manager, sock->fd);
|
select_poke(manager, sock->fd);
|
||||||
|
|
||||||
ENQUEUE(sock->read_list, iev, link);
|
ENQUEUE(sock->listen_list, iev, link);
|
||||||
|
|
||||||
UNLOCK(&sock->lock);
|
UNLOCK(&sock->lock);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user