Commit a21e2e7f authored by Michael Graff's avatar Michael Graff
Browse files

connect works; snapshot

parent 9df01daa
......@@ -14,13 +14,19 @@
#include <isc/socket.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
isc_memctx_t mctx = NULL;
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
my_callback(isc_task_t task, isc_event_t event)
{
......@@ -45,6 +51,59 @@ my_shutdown(isc_task_t task, isc_event_t event)
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;
struct isc_region region;
char buf[1024];
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);
printf("\tFrom: %s port %d\n", inet_ntoa(dev->address.type.sin.sin_addr),
ntohs(dev->address.type.sin.sin_port));
if (dev->result != ISC_R_SUCCESS) {
isc_socket_detach(&sock);
isc_event_free(&event);
return (0);
}
/*
* Echo the data back
*/
if (strcmp(event->arg, "so2")) {
region = dev->region;
region.base[20] = 0;
snprintf(buf, sizeof buf, "Received: %s\r\n", region.base);
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_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,
task, my_recv, event->arg);
isc_event_free(&event);
return (0);
}
static isc_boolean_t
my_send(isc_task_t task, isc_event_t event)
{
......@@ -65,46 +124,60 @@ my_send(isc_task_t task, isc_event_t event)
return (0);
}
static isc_boolean_t
my_recv(isc_task_t task, isc_event_t event)
my_http_get(isc_task_t task, isc_event_t event)
{
isc_socket_t sock;
isc_socketevent_t dev;
struct isc_region region;
char buf[1024];
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,
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);
printf("\tFrom: %s port %d\n", inet_ntoa(dev->address.type.sin.sin_addr),
ntohs(dev->address.type.sin.sin_port));
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);
}
/*
* Echo the data back
* Send a GET string, and set up to receive (and just display)
* the result.
*/
region = dev->region;
region.base[20] = 0;
snprintf(buf, sizeof buf, "Received: %s\r\n", region.base);
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_send, event->arg);
isc_socket_recv(sock, &dev->region, ISC_FALSE,
task, my_recv, event->arg);
isc_socket_send(sock, &region, task, my_http_get, event->arg);
isc_event_free(&event);
......@@ -186,18 +259,40 @@ main(int argc, char *argv[])
socketmgr = NULL;
INSIST(isc_socketmgr_create(mctx, &socketmgr) == ISC_R_SUCCESS);
/*
* open up a listener socket
*/
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,
&so1) == ISC_R_SUCCESS);
INSIST(isc_socket_bind(so1, &sockaddr, addrlen) == 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,
"so1") == ISC_R_SUCCESS);
/*
* open up a socket that will connect to www.flame.org, port 80.
* Why not. :)
*/
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,
&so2) == ISC_R_SUCCESS);
INSIST(isc_socket_connect(so2, &sockaddr, addrlen, t1, my_connect,
"so2") == ISC_R_SUCCESS);
sleep(2);
......
/* $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
#define ISC_SOCKET_H 1
......@@ -82,7 +82,7 @@ typedef struct isc_socketevent {
unsigned int addrlength; /* length of address */
} *isc_socketevent_t;
typedef struct isc_socket_newconev {
typedef struct isc_socket_newconnev {
struct isc_event common;
isc_socket_t newsocket;
isc_result_t result; /* OK, EOF, whatever else */
......@@ -90,11 +90,16 @@ typedef struct isc_socket_newconev {
unsigned int addrlength; /* length of address */
} *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_RECVDONE (ISC_EVENTCLASS_SOCKET + 1)
#define ISC_SOCKEVENT_SENDDONE (ISC_EVENTCLASS_SOCKET + 2)
#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_SENDMARK (ISC_EVENTCLASS_SOCKET + 6)
......@@ -306,7 +311,7 @@ isc_socket_connect(isc_socket_t socket, struct isc_sockaddr *addressp,
void *arg);
/*
* 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'.
*
* Requires:
......
/* $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"
......@@ -70,9 +70,17 @@ typedef struct isc_socket_ncintev {
LINK(struct isc_socket_ncintev) link;
} *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 VALID_SOCKET(t) ((t) != NULL && \
(t)->magic == SOCKET_MAGIC)
#define VALID_SOCKET(t) ((t) != NULL \
&& (t)->magic == SOCKET_MAGIC)
struct isc_socket {
/* Not locked. */
unsigned int magic;
......@@ -84,12 +92,15 @@ struct isc_socket {
LIST(struct isc_socket_intev) read_list;
LIST(struct isc_socket_intev) write_list;
LIST(struct isc_socket_ncintev) listen_list;
isc_socket_connintev_t connect_ev;
isc_boolean_t pending_read;
isc_boolean_t pending_write;
isc_boolean_t listener; /* listener socket */
isc_boolean_t connecting;
isc_sockettype_t type;
isc_socket_intev_t riev;
isc_socket_intev_t wiev;
isc_socket_connintev_t ciev;
struct isc_sockaddr address;
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);
static void send_senddone_event(isc_socket_t, isc_socket_intev_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 isc_result_t allocate_socket(isc_socketmgr_t, isc_sockettype_t,
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
......@@ -158,18 +173,18 @@ select_readmsg(isc_socketmgr_t mgr)
cc = read(mgr->pipe_fds[0], &msg, sizeof(int));
if (cc < 0) {
if (errno == EWOULDBLOCK)
return SELECT_POKE_NOTHING;
if (errno == EAGAIN)
return (SELECT_POKE_NOTHING);
UNEXPECTED_ERROR(__FILE__, __LINE__,
"read() failed during watcher poke: %s",
strerror(errno));
return SELECT_POKE_NOTHING; /* XXX */
return (SELECT_POKE_NOTHING);
}
INSIST(cc == sizeof(int));
return msg;
return (msg);
}
/*
......@@ -199,7 +214,7 @@ make_nonblock(int fd)
* Handle freeing a done event when needed.
*/
static void
rwdone_event_destroy(isc_event_t ev)
done_event_destroy(isc_event_t ev)
{
isc_socket_t sock = ev->sender;
isc_boolean_t kill_socket = ISC_FALSE;
......@@ -212,7 +227,7 @@ rwdone_event_destroy(isc_event_t ev)
REQUIRE(sock->references > 0);
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));
if (sock->references == 0)
......@@ -223,27 +238,6 @@ rwdone_event_destroy(isc_event_t ev)
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.
*
......@@ -300,6 +294,8 @@ allocate_socket(isc_socketmgr_t manager, isc_sockettype_t type,
INIT_LIST(sock->listen_list);
sock->pending_read = ISC_FALSE;
sock->pending_write = ISC_FALSE;
sock->listener = ISC_FALSE;
sock->connecting = ISC_FALSE;
/*
* initialize the lock
......@@ -374,9 +370,6 @@ isc_socket_create(isc_socketmgr_t manager, isc_sockettype_t type,
if (ret != ISC_R_SUCCESS)
return (ret);
/*
* Create the associated socket XXX
*/
switch (type) {
case isc_socket_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);
}
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
* 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
* EWOULDBLOCK, simply poke the watcher to watch this socket
* EAGAIN, simply poke the watcher to watch this socket
* again.
*/
addrlen = sizeof(addr);
fd = accept(sock->fd, &addr, &addrlen);
if (fd < 0) {
if (errno == EWOULDBLOCK) {
XTRACE(("internal_accept: ewouldblock\n"));
if (errno == EAGAIN) {
XTRACE(("internal_accept: EAGAIN\n"));
sock->pending_read = ISC_FALSE;
select_poke(sock->manager, sock->fd);
UNLOCK(&sock->lock);
......@@ -791,7 +796,7 @@ internal_read(isc_task_t task, isc_event_t ev)
* check for error or block condition
*/
if (cc < 0) {
if (cc == EWOULDBLOCK)
if (errno == EAGAIN)
goto poke;
UNEXPECTED_ERROR(__FILE__, __LINE__,
"internal read: %s",
......@@ -935,7 +940,7 @@ internal_write(isc_task_t task, isc_event_t ev)
* check for error or block condition
*/
if (cc < 0) {
if (cc == EWOULDBLOCK)
if (errno == EAGAIN)
goto poke;
UNEXPECTED_ERROR(__FILE__, __LINE__,
"internal_write: %s",
......@@ -1104,7 +1109,9 @@ watcher(void *uap)
}
iev = HEAD(sock->write_list);
if (iev == NULL || sock->pending_write) {
if ((iev == NULL
|| sock->pending_write)
&& !sock->connecting) {
FD_CLR(sock->fd,
&manager->write_fds);
XTRACE(("watch cleared w\n"));
......@@ -1145,7 +1152,10 @@ watcher(void *uap)
unlock_sock = ISC_TRUE;
LOCK(&sock->lock);
}
dispatch_write(sock);
if (sock->connecting)
dispatch_connect(sock);
else
dispatch_write(sock);
FD_CLR(i, &manager->write_fds);
}
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);
UNEXPECTED_ERROR(__FILE__, __LINE__,
"pipe() failed: %s",
strerror(errno)); /* XXX */
strerror(errno));
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
*/
ev->common.destroy = rwdone_event_destroy;
ev->common.destroy = done_event_destroy;
ev->region = *region;
ev->n = 0;
......@@ -1347,7 +1357,7 @@ isc_socket_recv(isc_socket_t sock, isc_region_t region,
}
if (cc < 0) {
if (cc == EWOULDBLOCK)
if (errno == EAGAIN)
goto queue;
UNEXPECTED_ERROR(__FILE__, __LINE__,
"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
*/
ev->common.destroy = rwdone_event_destroy;
ev->common.destroy = done_event_destroy;
ev->region = *region;
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)
cc = send(sock->fd, ev->region.base,
ev->region.length, 0);
else
cc = -1; /* XXX */
else {
UNEXPECTED_ERROR(__FILE__, __LINE__,
"isc_socket_send: unknown socket type");
return (ISC_R_UNEXPECTED);
}
if (cc < 0) {
if (cc == EWOULDBLOCK)
if (errno == EAGAIN)
goto queue;
UNEXPECTED_ERROR(__FILE__, __LINE__,
"isc_socket_send: %s",
strerror(errno));
INSIST(cc >= 0);
return (ISC_R_UNEXPECTED);
}
if (cc == 0) {
......@@ -1653,6 +1667,9 @@ isc_socket_listen(isc_socket_t sock, int backlog)
return (ISC_R_SUCCESS);
}
/*
* This should try to do agressive accept()
*/
isc_result_t
isc_socket_accept(isc_socket_t sock,
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->done = dev;
iev->canceled = ISC_FALSE;
dev->common.destroy = ncdone_event_destroy;
dev->common.destroy = done_event_destroy;
dev->newsocket = nsock;
/*
......@@ -1735,3 +1752,207 @@ isc_socket_accept(isc_socket_t sock,
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);