libuv/oio-unix.c

553 lines
12 KiB
C
Raw Normal View History

2011-04-07 09:02:54 +00:00
#include "oio.h"
2011-03-23 12:56:06 +00:00
2011-03-31 04:36:52 +00:00
#include <stdio.h> /* printf */
2011-03-28 10:26:00 +00:00
#include <stdlib.h>
#include <errno.h>
#include <assert.h>
2011-03-28 10:54:18 +00:00
#include <string.h> /* strnlen */
2011-03-29 23:40:27 +00:00
#include <unistd.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
2011-03-23 12:56:06 +00:00
2011-04-01 06:31:53 +00:00
#ifndef strnlen
2011-04-01 05:42:29 +00:00
size_t strnlen (register const char* s, size_t maxlen) {
register const char *e;
size_t n;
for (e = s, n = 0; *e && n < maxlen; e++, n++);
return n;
}
2011-04-01 06:31:53 +00:00
#endif /* strnlen */
2011-04-01 05:42:29 +00:00
2011-03-23 12:56:06 +00:00
2011-04-07 09:02:54 +00:00
void oio_tcp_io(EV_P_ ev_io* watcher, int revents);
void oio_tcp_connect(oio_handle* handle, oio_req* req);
int oio_tcp_open(oio_handle*, int fd);
int oio_close_error(oio_handle* handle, oio_err err);
2011-03-23 12:56:06 +00:00
2011-03-28 10:17:52 +00:00
2011-04-07 09:02:54 +00:00
static oio_err oio_err_new(oio_handle* handle, int e) {
2011-04-10 21:59:41 +00:00
handle->err = e;
2011-03-28 10:54:18 +00:00
return e;
2011-03-23 12:56:06 +00:00
}
2011-04-07 09:02:54 +00:00
oio_err oio_err_last(oio_handle *handle) {
2011-04-10 21:59:41 +00:00
return handle->err;
2011-03-29 17:08:45 +00:00
}
2011-03-23 12:56:06 +00:00
2011-04-07 09:02:54 +00:00
struct sockaddr_in oio_ip4_addr(char *ip, int port) {
2011-03-28 10:17:52 +00:00
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = inet_addr(ip);
return addr;
}
2011-04-07 09:02:54 +00:00
int oio_close(oio_handle* handle) {
return oio_close_error(handle, 0);
2011-03-28 10:54:18 +00:00
}
2011-04-07 09:02:54 +00:00
void oio_init() {
2011-03-29 17:08:45 +00:00
ev_default_loop(0);
}
2011-04-07 09:02:54 +00:00
int oio_run() {
2011-03-29 17:08:45 +00:00
ev_run(EV_DEFAULT_ 0);
2011-03-28 10:54:18 +00:00
}
2011-04-14 18:19:36 +00:00
int oio_tcp_handle_init(oio_handle *handle, oio_close_cb close_cb, void* data) {
return -1;
}
/* Remove me */
2011-04-07 09:02:54 +00:00
oio_handle* oio_tcp_handle_new(oio_close_cb close_cb, void* data) {
oio_handle *handle = calloc(sizeof(oio_handle), 1);
2011-03-31 04:36:52 +00:00
if (!handle) {
2011-04-07 09:02:54 +00:00
oio_err_new(NULL, ENOMEM);
2011-03-31 04:36:52 +00:00
return NULL;
}
2011-04-07 09:02:54 +00:00
handle->type = OIO_TCP;
2011-03-28 08:55:29 +00:00
handle->close_cb = close_cb;
handle->data = data;
2011-03-23 12:56:06 +00:00
2011-03-31 04:36:52 +00:00
int fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd < 0) {
2011-04-07 09:02:54 +00:00
oio_err_new(handle, errno);
2011-03-31 04:36:52 +00:00
free(handle);
return NULL;
}
2011-03-30 02:53:29 +00:00
2011-04-07 09:02:54 +00:00
if (oio_tcp_open(handle, fd)) {
2011-03-31 04:36:52 +00:00
close(fd);
free(handle);
return NULL;
}
2011-03-23 23:31:29 +00:00
2011-03-28 10:17:52 +00:00
return handle;
2011-03-23 12:56:06 +00:00
}
2011-03-29 17:08:45 +00:00
2011-04-07 09:02:54 +00:00
int oio_bind(oio_handle* handle, struct sockaddr* addr) {
2011-03-28 08:55:29 +00:00
int addrsize;
2011-03-29 17:08:45 +00:00
int domain;
2011-03-31 04:36:52 +00:00
int r;
2011-04-10 21:59:41 +00:00
assert(handle->fd >= 0);
2011-03-27 21:50:51 +00:00
2011-03-28 08:55:29 +00:00
if (addr->sa_family == AF_INET) {
2011-03-28 10:17:52 +00:00
addrsize = sizeof(struct sockaddr_in);
2011-03-29 17:08:45 +00:00
domain = AF_INET;
2011-03-28 08:55:29 +00:00
} else if (addr->sa_family == AF_INET6) {
2011-03-28 10:17:52 +00:00
addrsize = sizeof(struct sockaddr_in6);
2011-03-29 17:08:45 +00:00
domain = AF_INET6;
2011-03-28 08:55:29 +00:00
} else {
assert(0);
2011-03-28 10:17:52 +00:00
return -1;
2011-03-23 12:56:06 +00:00
}
2011-04-10 21:59:41 +00:00
r = bind(handle->fd, addr, addrsize);
2011-03-27 21:50:51 +00:00
2011-04-07 09:02:54 +00:00
return oio_err_new(handle, r);
2011-03-29 17:08:45 +00:00
}
2011-04-07 09:02:54 +00:00
int oio_tcp_init_fd(int fd) {
2011-03-30 02:53:29 +00:00
int r;
int yes = 1;
r = fcntl(fd, F_SETFL, O_NONBLOCK);
assert(r == 0);
r = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
assert(r == 0);
return 0;
}
2011-04-07 09:02:54 +00:00
int oio_tcp_open(oio_handle* handle, int fd) {
2011-03-30 02:53:29 +00:00
/* Set non-blocking, etc */
2011-04-07 09:02:54 +00:00
oio_tcp_init_fd(fd);
2011-03-30 02:53:29 +00:00
2011-04-10 21:59:41 +00:00
handle->fd = fd;
2011-03-31 04:36:52 +00:00
2011-04-10 21:59:41 +00:00
ngx_queue_init(&handle->read_reqs);
2011-03-31 04:36:52 +00:00
2011-04-10 21:59:41 +00:00
ev_io_init(&handle->read_watcher, oio_tcp_io, fd, EV_READ);
ev_io_init(&handle->write_watcher, oio_tcp_io, fd, EV_WRITE);
2011-03-31 04:36:52 +00:00
2011-04-10 21:59:41 +00:00
handle->read_watcher.data = handle;
handle->write_watcher.data = handle;
2011-03-31 04:36:52 +00:00
return 0;
2011-03-29 17:08:45 +00:00
}
2011-04-07 09:02:54 +00:00
void oio_server_io(EV_P_ ev_io* watcher, int revents) {
oio_handle* handle = watcher->data;
2011-03-29 17:08:45 +00:00
assert(revents == EV_READ);
while (1) {
struct sockaddr addr;
socklen_t addrlen;
2011-04-10 21:59:41 +00:00
int fd = accept(handle->fd, &addr, &addrlen);
2011-03-29 17:08:45 +00:00
if (fd < 0) {
if (errno == EAGAIN) {
2011-03-29 23:40:27 +00:00
return; /* No problem. */
2011-03-29 17:08:45 +00:00
} else if (errno == EMFILE) {
2011-03-29 23:40:27 +00:00
/* TODO special trick. unlock reserved socket, accept, close. */
2011-03-29 17:08:45 +00:00
return;
} else {
2011-04-07 09:02:54 +00:00
oio_close_error(handle, oio_err_new(handle, errno));
2011-03-29 17:08:45 +00:00
}
2011-03-30 02:53:29 +00:00
2011-03-29 17:08:45 +00:00
} else {
2011-03-30 02:53:29 +00:00
if (!handle->accept_cb) {
close(fd);
} else {
2011-04-07 09:02:54 +00:00
oio_handle* new_client = oio_tcp_handle_new(NULL, NULL);
2011-03-29 17:08:45 +00:00
if (!new_client) {
2011-03-31 04:36:52 +00:00
/* Ignore error for now */
} else {
2011-04-07 09:02:54 +00:00
if (oio_tcp_open(new_client, fd)) {
2011-03-31 04:36:52 +00:00
/* Ignore error for now */
} else {
2011-04-10 21:59:41 +00:00
ev_io_start(EV_DEFAULT_ &handle->read_watcher);
handle->accept_cb(handle);
2011-03-31 04:36:52 +00:00
}
2011-03-29 17:08:45 +00:00
}
}
}
}
2011-03-28 08:55:29 +00:00
}
2011-03-23 12:56:06 +00:00
2011-03-27 21:50:51 +00:00
2011-04-07 09:02:54 +00:00
int oio_listen(oio_handle* handle, int backlog, oio_accept_cb cb) {
2011-04-10 21:59:41 +00:00
assert(handle->fd >= 0);
2011-03-29 17:08:45 +00:00
2011-04-10 21:59:41 +00:00
int r = listen(handle->fd, backlog);
2011-03-29 17:08:45 +00:00
if (r < 0) {
2011-04-07 09:02:54 +00:00
return oio_err_new(handle, errno);
2011-03-29 17:08:45 +00:00
}
2011-03-28 08:55:29 +00:00
handle->accept_cb = cb;
2011-04-10 21:59:41 +00:00
ev_io_init(&handle->read_watcher, oio_server_io, handle->fd, EV_READ);
ev_io_start(EV_DEFAULT_ &handle->read_watcher);
handle->read_watcher.data = handle;
2011-03-29 17:08:45 +00:00
return 0;
2011-03-23 12:56:06 +00:00
}
2011-04-14 18:19:36 +00:00
int oio_tcp_handle_accept(oio_handle* server, oio_handle* client,
oio_close_cb close_cb, void* data) {
;
}
2011-04-07 09:02:54 +00:00
int oio_close_error(oio_handle* handle, oio_err err) {
2011-04-10 21:59:41 +00:00
ev_io_stop(EV_DEFAULT_ &handle->read_watcher);
close(handle->fd);
handle->fd = -1;
2011-03-23 23:31:29 +00:00
2011-03-28 08:55:29 +00:00
if (handle->close_cb) {
2011-03-28 10:17:52 +00:00
handle->close_cb(handle, err);
2011-03-24 03:40:55 +00:00
}
2011-03-28 10:54:18 +00:00
return err;
2011-03-23 23:31:29 +00:00
}
2011-04-07 09:02:54 +00:00
oio_req* oio_read_reqs_head(oio_handle* handle) {
2011-04-10 21:59:41 +00:00
ngx_queue_t* q = ngx_queue_head(&(handle->read_reqs));
2011-03-31 04:36:52 +00:00
if (!q) {
return NULL;
}
2011-04-10 21:59:41 +00:00
oio_req* req = ngx_queue_data(q, struct oio_req_s, read_reqs);
assert(req);
2011-03-31 04:36:52 +00:00
return req;
}
2011-04-07 09:02:54 +00:00
int oio_read_reqs_empty(oio_handle* handle) {
2011-04-10 21:59:41 +00:00
return ngx_queue_empty(&(handle->read_reqs));
2011-03-31 04:36:52 +00:00
}
2011-04-07 09:02:54 +00:00
void oio__read(oio_handle* handle) {
2011-04-10 21:59:41 +00:00
assert(handle->fd >= 0);
2011-03-31 04:36:52 +00:00
/* Get the request at the head of the read_reqs queue. */
2011-04-07 09:02:54 +00:00
oio_req* req = oio_read_reqs_head(handle);
2011-03-31 04:36:52 +00:00
if (!req) {
2011-04-10 21:59:41 +00:00
ev_io_stop(EV_DEFAULT_ &(handle->read_watcher));
2011-03-31 04:36:52 +00:00
return;
}
2011-04-07 09:02:54 +00:00
/* Cast to iovec. We had to have our own oio_buf instead of iovec
2011-03-31 04:36:52 +00:00
* because Windows's WSABUF is not an iovec.
*/
2011-04-10 21:59:41 +00:00
struct iovec* iov = (struct iovec*) req->read_bufs;
int iovcnt = req->read_bufcnt;
2011-03-31 04:36:52 +00:00
assert(iov);
assert(iovcnt > 0);
/* Now do the actual read. */
2011-04-10 21:59:41 +00:00
ssize_t nread = readv(handle->fd, iov, iovcnt);
2011-03-31 04:36:52 +00:00
2011-04-07 09:02:54 +00:00
oio_read_cb cb = req->cb;
2011-03-31 04:36:52 +00:00
if (nread < 0) {
if (errno == EAGAIN) {
/* Just wait for the next one. */
2011-04-10 21:59:41 +00:00
assert(ev_is_active(&(handle->read_watcher)));
2011-03-31 04:36:52 +00:00
} else {
2011-04-07 09:02:54 +00:00
oio_err err = oio_err_new(handle, errno);
2011-03-31 04:36:52 +00:00
if (cb) {
2011-03-31 16:02:07 +00:00
cb(req, 0);
2011-03-31 04:36:52 +00:00
}
2011-04-07 09:02:54 +00:00
oio_close_error(handle, errno);
2011-03-31 04:36:52 +00:00
}
} else {
/* Successful read */
2011-04-10 21:59:41 +00:00
/* First pop the req off handle->read_reqs */
ngx_queue_remove(&(req->read_reqs));
2011-03-31 04:36:52 +00:00
2011-04-10 21:59:41 +00:00
/* Must free req if local. Also must free req->read_bufs. */
free(req->read_bufs);
req->read_bufs = NULL;
if (req->local) {
2011-03-31 04:36:52 +00:00
free(req);
}
/* NOTE: call callback AFTER freeing the request data. */
if (cb) {
2011-03-31 16:02:07 +00:00
cb(req, nread);
2011-03-31 04:36:52 +00:00
}
2011-04-07 09:02:54 +00:00
if (oio_read_reqs_empty(handle)) {
2011-04-10 21:59:41 +00:00
ev_io_stop(EV_DEFAULT_ &(handle->read_watcher));
2011-03-31 04:36:52 +00:00
}
}
}
2011-04-07 09:02:54 +00:00
void oio_tcp_io(EV_P_ ev_io* watcher, int revents) {
oio_handle* handle = watcher->data;
2011-03-23 12:56:06 +00:00
2011-04-10 21:59:41 +00:00
assert(handle->fd >= 0);
2011-03-31 04:36:52 +00:00
2011-04-10 21:59:41 +00:00
if (handle->connect_req) {
oio_tcp_connect(handle, handle->connect_req);
2011-03-28 08:55:29 +00:00
} else {
2011-03-31 04:36:52 +00:00
if (revents & EV_READ) {
2011-04-07 09:02:54 +00:00
oio__read(handle);
2011-03-31 04:36:52 +00:00
}
2011-03-23 12:56:06 +00:00
2011-03-31 04:36:52 +00:00
if (revents & EV_WRITE) {
assert(0 && "Queued writes are not supported");
}
}
2011-03-24 03:40:55 +00:00
}
2011-03-28 08:55:29 +00:00
/**
* We get called here from directly following a call to connect(2).
* In order to determine if we've errored out or succeeded must call
* getsockopt.
*/
2011-04-07 09:02:54 +00:00
void oio_tcp_connect(oio_handle* handle, oio_req* req) {
2011-04-10 21:59:41 +00:00
assert(handle->fd >= 0);
2011-03-28 08:55:29 +00:00
assert(req);
2011-03-24 08:50:23 +00:00
2011-03-28 08:55:29 +00:00
int error;
2011-03-28 10:17:52 +00:00
int errorsize = sizeof(int);
2011-04-10 21:59:41 +00:00
getsockopt(handle->fd, SOL_SOCKET, SO_ERROR, &error, &errorsize);
2011-03-24 08:50:23 +00:00
2011-03-28 08:55:29 +00:00
if (!error) {
2011-04-10 21:59:41 +00:00
ev_io_init(&handle->write_watcher, oio_tcp_io, handle->fd, EV_WRITE);
ev_set_cb(&handle->read_watcher, oio_tcp_io);
2011-03-24 08:50:23 +00:00
2011-03-28 08:55:29 +00:00
/* Successful connection */
2011-04-07 09:02:54 +00:00
oio_connect_cb connect_cb = req->cb;
2011-03-28 08:55:29 +00:00
if (connect_cb) {
2011-04-10 21:59:41 +00:00
if (req->local) {
2011-04-07 09:02:54 +00:00
connect_cb(NULL, oio_err_new(handle, 0));
2011-03-24 08:50:23 +00:00
} else {
2011-04-07 09:02:54 +00:00
connect_cb(req, oio_err_new(handle, 0));
2011-03-24 08:50:23 +00:00
}
}
2011-03-28 08:55:29 +00:00
/* Free up connect_req if we own it. */
2011-04-10 21:59:41 +00:00
if (req->local) {
2011-03-28 08:55:29 +00:00
free(req);
}
2011-03-23 12:56:06 +00:00
2011-03-28 08:55:29 +00:00
req = NULL;
2011-03-23 12:56:06 +00:00
2011-03-28 08:55:29 +00:00
} else if (error == EINPROGRESS) {
/* Still connecting. */
return;
2011-03-23 12:56:06 +00:00
2011-03-23 23:31:29 +00:00
} else {
2011-04-07 09:02:54 +00:00
oio_err err = oio_err_new(handle, error);
2011-03-29 17:08:45 +00:00
2011-04-10 21:59:41 +00:00
if (req->connect_cb) {
req->connect_cb(req, err);
2011-03-24 03:40:55 +00:00
}
2011-03-24 08:50:23 +00:00
2011-04-07 09:02:54 +00:00
oio_close_error(handle, err);
2011-03-24 03:40:55 +00:00
}
2011-03-23 23:31:29 +00:00
}
2011-03-23 12:56:06 +00:00
2011-04-07 09:02:54 +00:00
oio_req* oio_req_maybe_alloc(oio_handle* handle, oio_req* in_req) {
2011-03-28 10:17:52 +00:00
if (in_req) {
2011-04-10 21:59:41 +00:00
ngx_queue_init(&(in_req->read_reqs));
2011-03-28 10:17:52 +00:00
in_req->handle = handle;
2011-04-10 21:59:41 +00:00
in_req->local = 0;
2011-03-28 10:17:52 +00:00
return in_req;
} else {
2011-04-07 09:02:54 +00:00
oio_req *req = malloc(sizeof(oio_req));
2011-04-10 21:59:41 +00:00
oio_req_init(req, NULL, NULL);
2011-03-28 10:17:52 +00:00
req->handle = handle;
2011-04-10 21:59:41 +00:00
ngx_queue_init(&(req->read_reqs));
req->local = 1;
2011-03-28 10:17:52 +00:00
return req;
}
}
2011-04-10 21:59:41 +00:00
int oio_connect(oio_req *req_in, struct sockaddr* addr) {
oio_handle* handle = req_in->handle;
if (handle->connect_req) {
2011-04-07 09:02:54 +00:00
return oio_err_new(handle, EALREADY);
2011-03-24 08:50:23 +00:00
}
2011-04-07 09:02:54 +00:00
if (handle->type != OIO_TCP) {
return oio_err_new(handle, ENOTSOCK);
2011-03-24 08:50:23 +00:00
}
2011-04-07 09:02:54 +00:00
oio_req *req = oio_req_maybe_alloc(handle, req_in);
2011-03-28 08:55:29 +00:00
if (!req) {
2011-04-07 09:02:54 +00:00
return oio_err_new(handle, ENOMEM);
2011-03-24 08:50:23 +00:00
}
2011-04-10 21:59:41 +00:00
handle->connect_req = req;
2011-03-24 08:50:23 +00:00
2011-03-28 08:55:29 +00:00
int addrsize;
2011-03-24 08:50:23 +00:00
2011-03-28 08:55:29 +00:00
if (addr->sa_family == AF_INET) {
2011-03-28 10:17:52 +00:00
addrsize = sizeof(struct sockaddr_in);
2011-04-10 21:59:41 +00:00
handle->fd = socket(AF_INET, SOCK_STREAM, 0);
2011-03-28 08:55:29 +00:00
} else if (addr->sa_family == AF_INET6) {
2011-03-28 10:17:52 +00:00
addrsize = sizeof(struct sockaddr_in6);
2011-04-10 21:59:41 +00:00
handle->fd = socket(AF_INET6, SOCK_STREAM, 0);
2011-03-28 08:55:29 +00:00
} else {
assert(0);
2011-03-28 10:17:52 +00:00
return -1;
2011-03-27 21:50:51 +00:00
}
2011-03-24 08:50:23 +00:00
2011-03-28 08:55:29 +00:00
/* socket(2) failed */
2011-04-10 21:59:41 +00:00
if (handle->fd < 0) {
2011-04-07 09:02:54 +00:00
return oio_err_new(handle, errno);
2011-03-28 08:55:29 +00:00
}
2011-03-24 08:50:23 +00:00
2011-04-10 21:59:41 +00:00
int r = connect(handle->fd, addr, addrsize);
2011-03-27 21:50:51 +00:00
2011-04-10 21:59:41 +00:00
ev_io_init(&(handle->read_watcher), oio_tcp_io, handle->fd, EV_READ);
ev_io_init(&(handle->write_watcher), oio_tcp_io, handle->fd, EV_WRITE);
ev_io_start(EV_DEFAULT_ &(handle->read_watcher));
2011-03-27 21:50:51 +00:00
2011-04-07 09:02:54 +00:00
return oio_err_new(handle, r);
2011-03-27 21:50:51 +00:00
}
2011-03-31 04:36:52 +00:00
2011-04-10 21:59:41 +00:00
int oio_write(oio_req *req, oio_buf* bufs, int bufcnt) {
oio_handle* handle = req->handle;
assert(handle->fd >= 0);
2011-03-30 02:53:29 +00:00
ssize_t r;
2011-04-10 21:59:41 +00:00
r = writev(handle->fd, (struct iovec*)bufs, bufcnt);
2011-03-30 02:53:29 +00:00
if (r < 0) {
2011-04-07 09:02:54 +00:00
return oio_err_new(handle, r);
2011-03-30 02:53:29 +00:00
} else {
2011-03-31 04:36:52 +00:00
if (req && req->cb) {
2011-04-07 09:02:54 +00:00
oio_write_cb cb = req->cb;
2011-03-31 16:02:07 +00:00
cb(req);
2011-03-31 04:36:52 +00:00
}
2011-03-30 02:53:29 +00:00
return 0;
}
2011-03-28 10:54:18 +00:00
}
2011-04-10 21:59:41 +00:00
int oio_write2(oio_req* req, const char* msg) {
2011-03-28 10:54:18 +00:00
size_t len = strnlen(msg, 1024 * 1024);
2011-04-07 09:02:54 +00:00
oio_buf b;
2011-03-28 10:54:18 +00:00
b.base = (char*)msg;
b.len = len;
2011-04-10 21:59:41 +00:00
return oio_write(req, &b, 1);
2011-03-28 10:54:18 +00:00
}
2011-04-10 21:59:41 +00:00
int oio_read(oio_req *req_in, oio_buf* bufs, int bufcnt) {
oio_handle* handle = req_in->handle;
2011-03-31 04:36:52 +00:00
ssize_t nread = -1;
errno = EAGAIN;
2011-04-07 09:02:54 +00:00
oio_read_cb cb = req_in->cb;
2011-03-29 17:08:45 +00:00
2011-04-10 21:59:41 +00:00
assert(handle->fd >= 0);
2011-03-29 17:08:45 +00:00
2011-04-10 21:59:41 +00:00
if (ngx_queue_empty(&handle->read_reqs)) {
2011-03-31 04:36:52 +00:00
/* Attempt to read immediately. */
2011-04-10 21:59:41 +00:00
ssize_t nread = readv(handle->fd, (struct iovec*) bufs, bufcnt);
2011-03-31 04:36:52 +00:00
}
2011-03-29 17:08:45 +00:00
2011-03-31 04:36:52 +00:00
if (nread < 0 && errno != EAGAIN) {
/* Real error. */
2011-04-07 09:02:54 +00:00
oio_err err = oio_err_new(handle, errno);
2011-03-29 17:08:45 +00:00
2011-03-31 04:36:52 +00:00
if (cb) {
2011-03-31 16:02:07 +00:00
cb(req_in, nread);
2011-03-31 04:36:52 +00:00
}
2011-03-29 17:08:45 +00:00
2011-03-31 04:36:52 +00:00
return err;
}
2011-03-29 17:08:45 +00:00
2011-03-31 04:36:52 +00:00
if (nread >= 0) {
/* Successful read. */
if (cb) {
2011-03-31 16:02:07 +00:00
cb(req_in, nread);
2011-03-31 04:36:52 +00:00
}
return 0;
}
2011-03-29 17:08:45 +00:00
2011-03-31 04:36:52 +00:00
/* Either we never read anything, or we got EAGAIN. */
2011-04-10 21:59:41 +00:00
assert(!ngx_queue_empty(&handle->read_reqs) ||
2011-03-31 04:36:52 +00:00
(nread < 0 && errno == EAGAIN));
/* Two possible states:
* - EAGAIN, meaning the socket is not wriable currently. We must wait for
2011-04-10 21:59:41 +00:00
* it to become readable with the handle->read_watcher.
2011-03-31 04:36:52 +00:00
* - The read_reqs queue already has reads. Meaning: the user has issued
2011-04-07 09:02:54 +00:00
* many oio_reads calls some of which are still waiting for the socket to
2011-03-31 04:36:52 +00:00
* become readable.
2011-04-10 21:59:41 +00:00
* In the meantime we append the request to handle->read_reqs
2011-03-31 04:36:52 +00:00
*/
2011-04-07 09:02:54 +00:00
oio_req* req = oio_req_maybe_alloc(handle, req_in);
2011-03-31 04:36:52 +00:00
if (!req) {
2011-04-07 09:02:54 +00:00
return oio_err_new(handle, ENOMEM);
2011-03-31 04:36:52 +00:00
}
2011-03-29 17:08:45 +00:00
2011-04-07 09:02:54 +00:00
/* Copy the bufs data over into our oio_req struct. This is so the user can
* free the oio_buf array. The actual data inside the oio_bufs is however
2011-03-31 04:36:52 +00:00
* owned by the user and cannot be deallocated until the read completes.
*/
2011-04-10 21:59:41 +00:00
req->read_bufs = malloc(sizeof(oio_buf) * bufcnt);
memcpy(req->read_bufs, bufs, bufcnt * sizeof(oio_buf));
req->read_bufcnt = bufcnt;
2011-03-29 17:08:45 +00:00
2011-03-31 04:36:52 +00:00
/* Append the request to read_reqs. */
2011-04-10 21:59:41 +00:00
ngx_queue_insert_tail(&(handle->read_reqs), &(req->read_reqs));
2011-03-29 17:08:45 +00:00
2011-04-10 21:59:41 +00:00
ev_io_start(EV_DEFAULT_ &handle->read_watcher);
2011-03-29 17:08:45 +00:00
2011-04-07 09:02:54 +00:00
return oio_err_new(handle, EINPROGRESS);
2011-03-28 10:54:18 +00:00
}
2011-04-07 09:02:54 +00:00
void oio_free(oio_handle* handle) {
2011-03-28 10:54:18 +00:00
free(handle);
2011-03-29 23:40:27 +00:00
/* lists? */
2011-03-28 10:54:18 +00:00
return;
}
2011-03-31 16:02:07 +00:00
2011-04-10 21:59:41 +00:00
void oio_req_init(oio_req* req, oio_handle* handle, void* cb) {
2011-04-07 09:02:54 +00:00
req->type = OIO_UNKNOWN_REQ;
2011-03-31 16:02:07 +00:00
req->cb = cb;
2011-04-10 21:59:41 +00:00
req->handle = handle;
ngx_queue_init(&(req->read_reqs));
2011-03-31 16:02:07 +00:00
}