This commit is contained in:
Ryan Dahl 2011-03-23 20:40:55 -07:00
parent e108022ccc
commit 116bd967d6
4 changed files with 120 additions and 33 deletions

View File

@ -147,6 +147,22 @@ Marc Lehmann has written <a
portable version in libeio</a>.
</dd>
<dt><code>shutdown(2)</code>, graceful close, half-duplex connections</dt>
<dd>
<a
href="http://msdn.microsoft.com/en-us/library/ms738547(v=VS.85).aspx">Graceful
Shutdown, Linger Options, and Socket Closure</a>
<br/>
<a
href="http://msdn.microsoft.com/en-us/library/ms737757(VS.85).aspx"><code>DisconnectEx()</code></a>
</dd>
<dt><code>close(2)</code></dt>
<dd>
<a href="http://msdn.microsoft.com/en-us/library/ms737582(v=VS.85).aspx"><code>closesocket()</code></a>
</dd>
The following are nearly same in Windows overlapped and UNIX
non-blocking sockets. The only difference is that the UNIX variants
@ -351,4 +367,10 @@ Pipes:
<li><a href="http://msdn.microsoft.com/en-us/library/aa365146(v=VS.85).aspx"><code>ConnectNamedPipe</code></a>
</ul>
Also useful:
<a
href="http://msdn.microsoft.com/en-us/library/xw1ew2f8(v=vs.80).aspx">Introduction
to Visual C++ for UNIX Users</a>
</body></html>

51
ol.h
View File

@ -8,6 +8,16 @@
# include "ol_win.h"
#endif
/**
* Error codes are not cross-platform, so we have our own.
*/
typedef enum {
OL_SUCCESS = 0,
OL_EAGAIN = -1,
OL_EPIPE = -2,
OL_EMEM = -3,
} ol_errno;
/**
* Do not make assumptions about the order of the elements in this sturct.
@ -17,10 +27,19 @@
struct ol_buf;
typedef ol_read_cb void(*)(ol_buf *bufs, int bufcnt);
typedef ol_close_cb void(*)(int read, int write);
typedef ol_connect_cb void(*)();
typedef ol_accept_cb void(*)(ol_handle *peer);
typedef enum {
OL_TCP,
OL_TCP6,
OL_NAMED_PIPE,
OL_FILE,
OL_TTY
} ol_handle_type;
typedef ol_read_cb void(*)(ol_handle* h, ol_buf *bufs, int bufcnt);
typedef ol_close_cb void(*)(ol_handle* h, int read, int write, ol_errno err);
typedef ol_connect_cb void(*)(ol_handle* h);
typedef ol_accept_cb void(*)(ol_handle* h, ol_handle *peer);
/**
@ -70,10 +89,10 @@ int ol_bind(ol_handle* h, sockaddr* addr, sockaddr_len len);
size_t ol_buffer_size(ol_handle* h);
int ol_pause(ol_handle* h);
int ol_read_stop(ol_handle* h);
int ol_resume(ol_handle* h);
int ol_read_start(ol_handle* h);
/**
@ -85,6 +104,12 @@ int ol_resume(ol_handle* h);
int ol_get_fd(ol_handle* h);
/**
* Returns the type of the handle.
*/
ol_handle_type ol_get_type(ol_handle* h);
/**
* Send data to h. User responsible for bufs until callback is made.
* Multiple ol_handle_write() calls may be issued before the previous ones
@ -95,17 +120,25 @@ int ol_write(ol_handle* h, ol_buf* bufs, int bufcnt,
/**
* Note: works on both named pipes and TCP handles.
* Works on both named pipes and TCP handles.
*/
int ol_listen(ol_handle* h, int backlog, ol_accept_cb cb);
/**
* Writes EOF or sends a FIN packet.
* Further calls to ol_write() result in OI_EPIPE error. When the send
* buffer is drained and the other side also terminates their writes, the
* handle is finally closed and ol_close_cb() made. There is no need to call
* ol_close() after this.
*/
int ol_end(ol_handle* h);
int ol_graceful_close(ol_handle* h);
/**
* Immediately closes the handle. If there is data in the send buffer
* it will not be sent.
*/
int ol_close(ol_handle* h);
@ -121,7 +154,7 @@ int ol_free(ol_handle* h);
ol_loop* ol_loop_new();
ol_loop* ol_associate(ol_handle* handle);
void ol_associate(ol_loop* loop, ol_handle* handle);
void ol_loop_free(ol_loop* loop);

View File

@ -2,7 +2,7 @@
ol_loop* ol_loop_new() {
ol_loop* loop = malloc(sizeof(ol_loop));
ol_loop* loop = calloc(sizeof(ol_loop), 1);
if (!loop) {
return NULL;
}
@ -16,7 +16,9 @@ ol_loop* ol_loop_new() {
}
ol_loop* ol_associate(ol_handle* handle) {
void ol_associate(ol_loop* loop, ol_handle* handle) {
assert(!handle->loop);
handle->loop = loop;
}
@ -26,7 +28,7 @@ void ol_run(ol_loop *loop) {
ol_handle* ol_tcp_new(int v4, ol_read_cb read_cb, ol_close_cb close_cb) {
ol_handle *handle = malloc(sizeof(ol_handle));
ol_handle *handle = calloc(sizeof(ol_handle), 1);
if (!handle) {
return NULL;
}
@ -34,6 +36,8 @@ ol_handle* ol_tcp_new(int v4, ol_read_cb read_cb, ol_close_cb close_cb) {
handle->read_cb = read_cb;
handle->close_cb = close_cb;
handle->type = v4 ? OL_TCP : OL_TCP6;
int domain = v4 ? AF_INET : AF_INET6;
handle->fd = socket(domain, SOCK_STREAM, 0);
if (fd == -1) {
@ -46,32 +50,42 @@ ol_handle* ol_tcp_new(int v4, ol_read_cb read_cb, ol_close_cb close_cb) {
}
void handle_tcp_io() {
static void tcp_io(EV_P_ ev_io *w, int revents) {
ol_handle* h = (ol_handle*)w->data;
if (h->connecting) {
tcp_check_connect_status(h);
} else {
}
}
int try_connect(ol_handle* h) {
int r = connect(h->fd, h->connect_addr, h->connect_addrlen);
static void tcp_check_connect_status(ol_handle* h) {
assert(h->connecting);
if (r != 0) {
if (errno == EINPROGRESS) {
/* Wait for fd to become writable. */
h->connecting = 1;
ev_io_init(&h->write_watcher, handle_tcp_io, h->fd, EV_WRITE);
ev_io_start(h->loop, &h->write_watcher);
}
return got_error("connect", errno);
int error;
socklen_t len = sizeof(int);
getsockopt(h->fd, SOL_SOCKET, SO_ERROR, &error, &len);
if (error == 0) {
tcp_connected(h);
} else if (errno != EINPROGRESS) {
close(h->fd);
got_error("connect", errno);
}
/* Connected */
/* EINPROGRESS - unlikely. What to do? */
}
static void tcp_connected(ol_handle* h) {
assert(h->connecting);
if (h->connect_cb) {
h->connect_cb(h);
h->connecting = 0;
h->connect_cb = NULL;
}
return 0;
h->connecting = 0;
h->connect_cb = NULL;
}
@ -86,12 +100,27 @@ int ol_connect(ol_handle* h, sockaddr* addr, sockaddr_len addrlen,
h->connect_addrlen = addrlen;
if (buf) {
/* We're allowed to ol_write before the socket becomes connected. */
ol_write(h, buf, 1, bytes_sent, cb);
} else {
h->connect_cb = cb;
}
return try_connect(h);
int r = connect(h->fd, h->connect_addr, h->connect_addrlen);
if (r != 0) {
if (errno == EINPROGRESS) {
/* Wait for fd to become writable. */
h->connecting = 1;
ev_io_init(&h->write_watcher, tcp_io, h->fd, EV_WRITE);
ev_io_start(h->loop, &h->write_watcher);
}
return got_error("connect", errno);
}
/* Connected */
tcp_connected(h);
return 0;
}

View File

@ -1,9 +1,7 @@
/**
* Note can be cast to io_vec.
*/
typedef struct _ol_buf {
typedef struct {
char* buf;
size_t len;
ngx_queue_s write_queue;
@ -11,11 +9,16 @@ typedef struct _ol_buf {
typedef struct _ol_handle {
typedef struct {
int fd;
ol_handle_type type;
ol_read_cb read_cb;
ol_close_cb close_cb;
ol_connect_cb connect_cb;
ev_io read_watcher;
ev_io write_watcher;
ngx_queue_s write_queue;
ngx_queue_s all_handles;