diff options
Diffstat (limited to 'lib/tsocket')
-rw-r--r-- | lib/tsocket/config.mk | 5 | ||||
-rw-r--r-- | lib/tsocket/tsocket.c | 145 | ||||
-rw-r--r-- | lib/tsocket/tsocket.h | 115 | ||||
-rw-r--r-- | lib/tsocket/tsocket_bsd.c | 687 | ||||
-rw-r--r-- | lib/tsocket/tsocket_connect.c | 122 | ||||
-rw-r--r-- | lib/tsocket/tsocket_helpers.c | 121 | ||||
-rw-r--r-- | lib/tsocket/tsocket_internal.h | 91 | ||||
-rw-r--r-- | lib/tsocket/tsocket_readv.c | 222 | ||||
-rw-r--r-- | lib/tsocket/tsocket_writev.c | 316 |
9 files changed, 17 insertions, 1807 deletions
diff --git a/lib/tsocket/config.mk b/lib/tsocket/config.mk index 2e05f544c9..016663ffea 100644 --- a/lib/tsocket/config.mk +++ b/lib/tsocket/config.mk @@ -4,10 +4,7 @@ PRIVATE_DEPENDENCIES = LIBTALLOC LIBTEVENT LIBREPLACE_NETWORK LIBTSOCKET_OBJ_FILES = $(addprefix ../lib/tsocket/, \ tsocket.o \ tsocket_helpers.o \ - tsocket_bsd.o \ - tsocket_connect.o \ - tsocket_writev.o \ - tsocket_readv.o) + tsocket_bsd.o) PUBLIC_HEADERS += $(addprefix ../lib/tsocket/, \ tsocket.h\ diff --git a/lib/tsocket/tsocket.c b/lib/tsocket/tsocket.c index 076c6474a0..8e97997d85 100644 --- a/lib/tsocket/tsocket.c +++ b/lib/tsocket/tsocket.c @@ -26,142 +26,6 @@ #include "tsocket.h" #include "tsocket_internal.h" -static int tsocket_context_destructor(struct tsocket_context *sock) -{ - tsocket_disconnect(sock); - return 0; -} - -struct tsocket_context *_tsocket_context_create(TALLOC_CTX *mem_ctx, - const struct tsocket_context_ops *ops, - void *pstate, - size_t psize, - const char *type, - const char *location) -{ - void **ppstate = (void **)pstate; - struct tsocket_context *sock; - - sock = talloc_zero(mem_ctx, struct tsocket_context); - if (!sock) { - return NULL; - } - sock->ops = ops; - sock->location = location; - sock->private_data = talloc_size(sock, psize); - if (!sock->private_data) { - talloc_free(sock); - return NULL; - } - talloc_set_name_const(sock->private_data, type); - - talloc_set_destructor(sock, tsocket_context_destructor); - - *ppstate = sock->private_data; - return sock; -} - -int tsocket_set_event_context(struct tsocket_context *sock, - struct tevent_context *ev) -{ - return sock->ops->set_event_context(sock, ev); -} - -int tsocket_set_readable_handler(struct tsocket_context *sock, - tsocket_event_handler_t handler, - void *private_data) -{ - return sock->ops->set_read_handler(sock, handler, private_data); -} - -int tsocket_set_writeable_handler(struct tsocket_context *sock, - tsocket_event_handler_t handler, - void *private_data) -{ - return sock->ops->set_write_handler(sock, handler, private_data); -} - -int tsocket_connect(struct tsocket_context *sock, - const struct tsocket_address *remote_addr) -{ - return sock->ops->connect_to(sock, remote_addr); -} - -int tsocket_listen(struct tsocket_context *sock, - int queue_size) -{ - return sock->ops->listen_on(sock, queue_size); -} - -int _tsocket_accept(struct tsocket_context *sock, - TALLOC_CTX *mem_ctx, - struct tsocket_context **new_sock, - const char *location) -{ - return sock->ops->accept_new(sock, mem_ctx, new_sock, location); -} - -ssize_t tsocket_pending(struct tsocket_context *sock) -{ - return sock->ops->pending_data(sock); -} - -int tsocket_readv(struct tsocket_context *sock, - const struct iovec *vector, size_t count) -{ - return sock->ops->readv_data(sock, vector, count); -} - -int tsocket_writev(struct tsocket_context *sock, - const struct iovec *vector, size_t count) -{ - return sock->ops->writev_data(sock, vector, count); -} - -int tsocket_get_status(const struct tsocket_context *sock) -{ - return sock->ops->get_status(sock); -} - -int _tsocket_get_local_address(const struct tsocket_context *sock, - TALLOC_CTX *mem_ctx, - struct tsocket_address **local_addr, - const char *location) -{ - return sock->ops->get_local_address(sock, mem_ctx, - local_addr, location); -} - -int _tsocket_get_remote_address(const struct tsocket_context *sock, - TALLOC_CTX *mem_ctx, - struct tsocket_address **remote_addr, - const char *location) -{ - return sock->ops->get_remote_address(sock, mem_ctx, - remote_addr, location); -} - -int tsocket_get_option(const struct tsocket_context *sock, - const char *option, - TALLOC_CTX *mem_ctx, - char **value) -{ - return sock->ops->get_option(sock, option, mem_ctx, value); -} - -int tsocket_set_option(const struct tsocket_context *sock, - const char *option, - bool force, - const char *value) -{ - return sock->ops->set_option(sock, option, force, value); -} - -void tsocket_disconnect(struct tsocket_context *sock) -{ - sock->ops->disconnect(sock); -} - struct tsocket_address *_tsocket_address_create(TALLOC_CTX *mem_ctx, const struct tsocket_address_ops *ops, void *pstate, @@ -205,15 +69,6 @@ struct tsocket_address *_tsocket_address_copy(const struct tsocket_address *addr return addr->ops->copy(addr, mem_ctx, location); } -int _tsocket_address_create_socket(const struct tsocket_address *addr, - enum tsocket_type type, - TALLOC_CTX *mem_ctx, - struct tsocket_context **sock, - const char *location) -{ - return addr->ops->create_socket(addr, type, mem_ctx, sock, location); -} - struct tdgram_context { const char *location; const struct tdgram_context_ops *ops; diff --git a/lib/tsocket/tsocket.h b/lib/tsocket/tsocket.h index 8f69490012..84e74afa89 100644 --- a/lib/tsocket/tsocket.h +++ b/lib/tsocket/tsocket.h @@ -27,72 +27,13 @@ #include <talloc.h> #include <tevent.h> -struct tsocket_context; struct tsocket_address; struct tdgram_context; struct iovec; -enum tsocket_type { - TSOCKET_TYPE_STREAM = 1, - TSOCKET_TYPE_MESSAGE -}; - -typedef void (*tsocket_event_handler_t)(struct tsocket_context *, void *); -int tsocket_set_event_context(struct tsocket_context *sock, - struct tevent_context *ev); -int tsocket_set_readable_handler(struct tsocket_context *sock, - tsocket_event_handler_t handler, - void *private_data); -int tsocket_set_writeable_handler(struct tsocket_context *sock, - tsocket_event_handler_t handler, - void *private_data); - -int tsocket_connect(struct tsocket_context *sock, - const struct tsocket_address *remote_addr); - -int tsocket_listen(struct tsocket_context *sock, - int queue_size); - -int _tsocket_accept(struct tsocket_context *sock, - TALLOC_CTX *mem_ctx, - struct tsocket_context **new_sock, - const char *location); -#define tsocket_accept(sock, mem_ctx, new_sock) \ - _tsocket_accept(sock, mem_ctx, new_sock, __location__) - -ssize_t tsocket_pending(struct tsocket_context *sock); - -int tsocket_readv(struct tsocket_context *sock, - const struct iovec *vector, size_t count); -int tsocket_writev(struct tsocket_context *sock, - const struct iovec *vector, size_t count); - -int tsocket_get_status(const struct tsocket_context *sock); - -int _tsocket_get_local_address(const struct tsocket_context *sock, - TALLOC_CTX *mem_ctx, - struct tsocket_address **local_addr, - const char *location); -#define tsocket_get_local_address(sock, mem_ctx, local_addr) \ - _tsocket_get_local_address(sock, mem_ctx, local_addr, __location__) -int _tsocket_get_remote_address(const struct tsocket_context *sock, - TALLOC_CTX *mem_ctx, - struct tsocket_address **remote_addr, - const char *location); -#define tsocket_get_remote_address(sock, mem_ctx, remote_addr) \ - _tsocket_get_remote_address(sock, mem_ctx, remote_addr, __location__) - -int tsocket_get_option(const struct tsocket_context *sock, - const char *option, - TALLOC_CTX *mem_ctx, - char **value); -int tsocket_set_option(const struct tsocket_context *sock, - const char *option, - bool force, - const char *value); - -void tsocket_disconnect(struct tsocket_context *sock); - +/* + * tsocket_address related functions + */ char *tsocket_address_string(const struct tsocket_address *addr, TALLOC_CTX *mem_ctx); @@ -103,15 +44,6 @@ struct tsocket_address *_tsocket_address_copy(const struct tsocket_address *addr #define tsocket_address_copy(addr, mem_ctx) \ _tsocket_address_copy(addr, mem_ctx, __location__) -int _tsocket_address_create_socket(const struct tsocket_address *addr, - enum tsocket_type type, - TALLOC_CTX *mem_ctx, - struct tsocket_context **sock, - const char *location); -#define tsocket_address_create_socket(addr, type, mem_ctx, sock) \ - _tsocket_address_create_socket(addr, type, mem_ctx, sock,\ - __location__) - /* * tdgram_context related functions */ @@ -170,14 +102,6 @@ int _tsocket_address_unix_from_path(TALLOC_CTX *mem_ctx, char *tsocket_address_unix_path(const struct tsocket_address *addr, TALLOC_CTX *mem_ctx); -int _tsocket_context_bsd_wrap_existing(TALLOC_CTX *mem_ctx, - int fd, bool close_on_disconnect, - struct tsocket_context **_sock, - const char *location); -#define tsocket_context_bsd_wrap_existing(mem_ctx, fd, cod, _sock) \ - _tsocket_context_bsd_wrap_existing(mem_ctx, fd, cod, _sock, \ - __location__) - int _tdgram_inet_udp_socket(const struct tsocket_address *local, const struct tsocket_address *remote, TALLOC_CTX *mem_ctx, @@ -195,39 +119,6 @@ int _tdgram_unix_dgram_socket(const struct tsocket_address *local, _tdgram_unix_dgram_socket(local, remote, mem_ctx, dgram, __location__) /* - * Async helpers - */ - -struct tevent_req *tsocket_connect_send(struct tsocket_context *sock, - TALLOC_CTX *mem_ctx, - const struct tsocket_address *dst); -int tsocket_connect_recv(struct tevent_req *req, int *perrno); - -struct tevent_req *tsocket_writev_send(struct tsocket_context *sock, - TALLOC_CTX *mem_ctx, - const struct iovec *vector, - size_t count); -int tsocket_writev_recv(struct tevent_req *req, int *perrno); - -struct tevent_req *tsocket_writev_queue_send(TALLOC_CTX *mem_ctx, - struct tsocket_context *sock, - struct tevent_queue *queue, - const struct iovec *vector, - size_t count); -int tsocket_writev_queue_recv(struct tevent_req *req, int *perrno); - -typedef int (*tsocket_readv_next_iovec_t)(struct tsocket_context *sock, - void *private_data, - TALLOC_CTX *mem_ctx, - struct iovec **vector, - size_t *count); -struct tevent_req *tsocket_readv_send(struct tsocket_context *sock, - TALLOC_CTX *mem_ctx, - tsocket_readv_next_iovec_t next_iovec_fn, - void *private_data); -int tsocket_readv_recv(struct tevent_req *req, int *perrno); - -/* * Queue helpers */ diff --git a/lib/tsocket/tsocket_bsd.c b/lib/tsocket/tsocket_bsd.c index 29097bd987..e260b1fa25 100644 --- a/lib/tsocket/tsocket_bsd.c +++ b/lib/tsocket/tsocket_bsd.c @@ -24,7 +24,6 @@ #include "replace.h" #include "system/filesys.h" #include "system/network.h" -#include "system/filesys.h" #include "tsocket.h" #include "tsocket_internal.h" @@ -186,22 +185,9 @@ static ssize_t tsocket_bsd_pending(int fd) return -1; } -static const struct tsocket_context_ops tsocket_context_bsd_ops; static const struct tsocket_address_ops tsocket_address_bsd_ops; -static int tsocket_context_bsd_set_option(const struct tsocket_context *sock, - const char *option, - bool force, - const char *value); - -struct tsocket_context_bsd { - bool close_on_disconnect; - int fd; - struct tevent_fd *fde; -}; - struct tsocket_address_bsd { - bool broadcast; union { struct sockaddr sa; struct sockaddr_in in; @@ -443,19 +429,6 @@ int tsocket_address_inet_set_port(struct tsocket_address *addr, return 0; } -void tsocket_address_inet_set_broadcast(struct tsocket_address *addr, - bool broadcast) -{ - struct tsocket_address_bsd *bsda = talloc_get_type(addr->private_data, - struct tsocket_address_bsd); - - if (!bsda) { - return; - } - - bsda->broadcast = broadcast; -} - int _tsocket_address_unix_from_path(TALLOC_CTX *mem_ctx, const char *path, struct tsocket_address **_addr, @@ -565,654 +538,13 @@ static struct tsocket_address *tsocket_address_bsd_copy(const struct tsocket_add return NULL; } - tsocket_address_inet_set_broadcast(copy, bsda->broadcast); return copy; } -int _tsocket_context_bsd_wrap_existing(TALLOC_CTX *mem_ctx, - int fd, bool close_on_disconnect, - struct tsocket_context **_sock, - const char *location) -{ - struct tsocket_context *sock; - struct tsocket_context_bsd *bsds; - - sock = tsocket_context_create(mem_ctx, - &tsocket_context_bsd_ops, - &bsds, - struct tsocket_context_bsd, - location); - if (!sock) { - return -1; - } - - bsds->close_on_disconnect = close_on_disconnect; - bsds->fd = fd; - bsds->fde = NULL; - - *_sock = sock; - return 0; -} - -static int tsocket_address_bsd_create_socket(const struct tsocket_address *addr, - enum tsocket_type type, - TALLOC_CTX *mem_ctx, - struct tsocket_context **_sock, - const char *location) -{ - struct tsocket_address_bsd *bsda = talloc_get_type(addr->private_data, - struct tsocket_address_bsd); - struct tsocket_context *sock; - int bsd_type; - int fd; - int ret; - bool do_bind = false; - bool do_reuseaddr = false; - - switch (type) { - case TSOCKET_TYPE_STREAM: - if (bsda->broadcast) { - errno = EINVAL; - return -1; - } - bsd_type = SOCK_STREAM; - break; - default: - errno = EPROTONOSUPPORT; - return -1; - } - - switch (bsda->u.sa.sa_family) { - case AF_UNIX: - if (bsda->broadcast) { - errno = EINVAL; - return -1; - } - if (bsda->u.un.sun_path[0] != 0) { - do_bind = true; - } - break; - case AF_INET: - if (bsda->u.in.sin_port != 0) { - do_reuseaddr = true; - do_bind = true; - } - if (bsda->u.in.sin_addr.s_addr == INADDR_ANY) { - do_bind = true; - } - break; -#ifdef HAVE_IPV6 - case AF_INET6: - if (bsda->u.in6.sin6_port != 0) { - do_reuseaddr = true; - do_bind = true; - } - if (memcmp(&in6addr_any, - &bsda->u.in6.sin6_addr, - sizeof(in6addr_any)) != 0) { - do_bind = true; - } - break; -#endif - default: - errno = EINVAL; - return -1; - } - - fd = socket(bsda->u.sa.sa_family, bsd_type, 0); - if (fd < 0) { - return fd; - } - - fd = tsocket_common_prepare_fd(fd, true); - if (fd < 0) { - return fd; - } - - ret = _tsocket_context_bsd_wrap_existing(mem_ctx, fd, true, - &sock, location); - if (ret != 0) { - int saved_errno = errno; - close(fd); - errno = saved_errno; - return ret; - } - - if (bsda->broadcast) { - ret = tsocket_context_bsd_set_option(sock, "SO_BROADCAST", true, "1"); - if (ret != 0) { - int saved_errno = errno; - talloc_free(sock); - errno = saved_errno; - return ret; - } - } - - if (do_reuseaddr) { - ret = tsocket_context_bsd_set_option(sock, "SO_REUSEADDR", true, "1"); - if (ret != 0) { - int saved_errno = errno; - talloc_free(sock); - errno = saved_errno; - return ret; - } - } - - if (do_bind) { - ret = bind(fd, &bsda->u.sa, sizeof(bsda->u.ss)); - if (ret != 0) { - int saved_errno = errno; - talloc_free(sock); - errno = saved_errno; - return ret; - } - } - - *_sock = sock; - return 0; -} - static const struct tsocket_address_ops tsocket_address_bsd_ops = { .name = "bsd", .string = tsocket_address_bsd_string, .copy = tsocket_address_bsd_copy, - .create_socket = tsocket_address_bsd_create_socket -}; - -static void tsocket_context_bsd_fde_handler(struct tevent_context *ev, - struct tevent_fd *fde, - uint16_t flags, - void *private_data) -{ - struct tsocket_context *sock = talloc_get_type(private_data, - struct tsocket_context); - - if (flags & TEVENT_FD_WRITE) { - sock->event.write_handler(sock, sock->event.write_private); - return; - } - if (flags & TEVENT_FD_READ) { - sock->event.read_handler(sock, sock->event.read_private); - return; - } -} - -static int tsocket_context_bsd_set_event_context(struct tsocket_context *sock, - struct tevent_context *ev) -{ - struct tsocket_context_bsd *bsds = talloc_get_type(sock->private_data, - struct tsocket_context_bsd); - - talloc_free(bsds->fde); - bsds->fde = NULL; - ZERO_STRUCT(sock->event); - - if (!ev) { - return 0; - } - - bsds->fde = tevent_add_fd(ev, bsds, - bsds->fd, - 0, - tsocket_context_bsd_fde_handler, - sock); - if (!bsds->fde) { - if (errno == 0) { - errno = ENOMEM; - } - return -1; - } - - sock->event.ctx = ev; - - return 0; -} - -static int tsocket_context_bsd_set_read_handler(struct tsocket_context *sock, - tsocket_event_handler_t handler, - void *private_data) -{ - struct tsocket_context_bsd *bsds = talloc_get_type(sock->private_data, - struct tsocket_context_bsd); - - if (sock->event.read_handler && !handler) { - TEVENT_FD_NOT_READABLE(bsds->fde); - } else if (!sock->event.read_handler && handler) { - TEVENT_FD_READABLE(bsds->fde); - } - - sock->event.read_handler = handler; - sock->event.read_private = private_data; - - return 0; -} - -static int tsocket_context_bsd_set_write_handler(struct tsocket_context *sock, - tsocket_event_handler_t handler, - void *private_data) -{ - struct tsocket_context_bsd *bsds = talloc_get_type(sock->private_data, - struct tsocket_context_bsd); - - if (sock->event.write_handler && !handler) { - TEVENT_FD_NOT_WRITEABLE(bsds->fde); - } else if (!sock->event.write_handler && handler) { - TEVENT_FD_WRITEABLE(bsds->fde); - } - - sock->event.write_handler = handler; - sock->event.write_private = private_data; - - return 0; -} - -static int tsocket_context_bsd_connect_to(struct tsocket_context *sock, - const struct tsocket_address *remote) -{ - struct tsocket_context_bsd *bsds = talloc_get_type(sock->private_data, - struct tsocket_context_bsd); - struct tsocket_address_bsd *bsda = talloc_get_type(remote->private_data, - struct tsocket_address_bsd); - int ret; - - ret = connect(bsds->fd, &bsda->u.sa, - sizeof(bsda->u.ss)); - - return ret; -} - -static int tsocket_context_bsd_listen_on(struct tsocket_context *sock, - int queue_size) -{ - struct tsocket_context_bsd *bsds = talloc_get_type(sock->private_data, - struct tsocket_context_bsd); - int ret; - - ret = listen(bsds->fd, queue_size); - - return ret; -} - -static int tsocket_context_bsd_accept_new(struct tsocket_context *sock, - TALLOC_CTX *mem_ctx, - struct tsocket_context **_new_sock, - const char *location) -{ - struct tsocket_context_bsd *bsds = talloc_get_type(sock->private_data, - struct tsocket_context_bsd); - int new_fd; - struct tsocket_context *new_sock; - struct tsocket_context_bsd *new_bsds; - struct sockaddr_storage ss; - void *p = &ss; - socklen_t ss_len = sizeof(ss); - - new_fd = accept(bsds->fd, (struct sockaddr *)p, &ss_len); - if (new_fd < 0) { - return new_fd; - } - - new_fd = tsocket_common_prepare_fd(new_fd, true); - if (new_fd < 0) { - return new_fd; - } - - new_sock = tsocket_context_create(mem_ctx, - &tsocket_context_bsd_ops, - &new_bsds, - struct tsocket_context_bsd, - location); - if (!new_sock) { - int saved_errno = errno; - close(new_fd); - errno = saved_errno; - return -1; - } - - new_bsds->close_on_disconnect = true; - new_bsds->fd = new_fd; - new_bsds->fde = NULL; - - *_new_sock = new_sock; - return 0; -} - -static ssize_t tsocket_context_bsd_pending_data(struct tsocket_context *sock) -{ - struct tsocket_context_bsd *bsds = talloc_get_type(sock->private_data, - struct tsocket_context_bsd); - int ret; - int value = 0; - - ret = ioctl(bsds->fd, FIONREAD, &value); - if (ret == -1) { - return ret; - } - - if (ret == 0) { - if (value == 0) { - int error=0; - socklen_t len = sizeof(error); - /* - * if no data is available check if the socket - * is in error state. For dgram sockets - * it's the way to return ICMP error messages - * of connected sockets to the caller. - */ - ret = getsockopt(bsds->fd, SOL_SOCKET, SO_ERROR, - &error, &len); - if (ret == -1) { - return ret; - } - if (error != 0) { - errno = error; - return -1; - } - } - return value; - } - - /* this should not be reached */ - errno = EIO; - return -1; -} - -static int tsocket_context_bsd_readv_data(struct tsocket_context *sock, - const struct iovec *vector, - size_t count) -{ - struct tsocket_context_bsd *bsds = talloc_get_type(sock->private_data, - struct tsocket_context_bsd); - int ret; - - ret = readv(bsds->fd, vector, count); - - return ret; -} - -static int tsocket_context_bsd_writev_data(struct tsocket_context *sock, - const struct iovec *vector, - size_t count) -{ - struct tsocket_context_bsd *bsds = talloc_get_type(sock->private_data, - struct tsocket_context_bsd); - int ret; - - ret = writev(bsds->fd, vector, count); - - return ret; -} - -static int tsocket_context_bsd_get_status(const struct tsocket_context *sock) -{ - struct tsocket_context_bsd *bsds = talloc_get_type(sock->private_data, - struct tsocket_context_bsd); - int ret; - int error=0; - socklen_t len = sizeof(error); - - if (bsds->fd == -1) { - errno = EPIPE; - return -1; - } - - ret = getsockopt(bsds->fd, SOL_SOCKET, SO_ERROR, &error, &len); - if (ret == -1) { - return ret; - } - if (error != 0) { - errno = error; - return -1; - } - - return 0; -} - -static int tsocket_context_bsd_get_local_address(const struct tsocket_context *sock, - TALLOC_CTX *mem_ctx, - struct tsocket_address **_addr, - const char *location) -{ - struct tsocket_context_bsd *bsds = talloc_get_type(sock->private_data, - struct tsocket_context_bsd); - struct tsocket_address *addr; - struct tsocket_address_bsd *bsda; - ssize_t ret; - socklen_t sa_len; - - addr = tsocket_address_create(mem_ctx, - &tsocket_address_bsd_ops, - &bsda, - struct tsocket_address_bsd, - location); - if (!addr) { - return -1; - } - - ZERO_STRUCTP(bsda); - - sa_len = sizeof(bsda->u.ss); - ret = getsockname(bsds->fd, &bsda->u.sa, &sa_len); - if (ret < 0) { - int saved_errno = errno; - talloc_free(addr); - errno = saved_errno; - return ret; - } - - *_addr = addr; - return 0; -} - -static int tsocket_context_bsd_get_remote_address(const struct tsocket_context *sock, - TALLOC_CTX *mem_ctx, - struct tsocket_address **_addr, - const char *location) -{ - struct tsocket_context_bsd *bsds = talloc_get_type(sock->private_data, - struct tsocket_context_bsd); - struct tsocket_address *addr; - struct tsocket_address_bsd *bsda; - ssize_t ret; - socklen_t sa_len; - - addr = tsocket_address_create(mem_ctx, - &tsocket_address_bsd_ops, - &bsda, - struct tsocket_address_bsd, - location); - if (!addr) { - return -1; - } - - ZERO_STRUCTP(bsda); - - sa_len = sizeof(bsda->u.ss); - ret = getpeername(bsds->fd, &bsda->u.sa, &sa_len); - if (ret < 0) { - int saved_errno = errno; - talloc_free(addr); - errno = saved_errno; - return ret; - } - - *_addr = addr; - return 0; -} - -static const struct tsocket_context_bsd_option { - const char *name; - int level; - int optnum; - int optval; -} tsocket_context_bsd_options[] = { -#define TSOCKET_OPTION(_level, _optnum, _optval) { \ - .name = #_optnum, \ - .level = _level, \ - .optnum = _optnum, \ - .optval = _optval \ -} - TSOCKET_OPTION(SOL_SOCKET, SO_REUSEADDR, 0), - TSOCKET_OPTION(SOL_SOCKET, SO_BROADCAST, 0) -}; - -static int tsocket_context_bsd_get_option(const struct tsocket_context *sock, - const char *option, - TALLOC_CTX *mem_ctx, - char **_value) -{ - struct tsocket_context_bsd *bsds = talloc_get_type(sock->private_data, - struct tsocket_context_bsd); - const struct tsocket_context_bsd_option *opt = NULL; - uint32_t i; - int optval; - socklen_t optval_len = sizeof(optval); - char *value; - int ret; - - for (i=0; i < ARRAY_SIZE(tsocket_context_bsd_options); i++) { - if (strcmp(option, tsocket_context_bsd_options[i].name) != 0) { - continue; - } - - opt = &tsocket_context_bsd_options[i]; - break; - } - - if (!opt) { - goto nosys; - } - - ret = getsockopt(bsds->fd, opt->level, opt->optnum, - (void *)&optval, &optval_len); - if (ret != 0) { - return ret; - } - - if (optval_len != sizeof(optval)) { - value = NULL; - } if (opt->optval != 0) { - if (optval == opt->optval) { - value = talloc_strdup(mem_ctx, "1"); - } else { - value = talloc_strdup(mem_ctx, "0"); - } - if (!value) { - goto nomem; - } - } else { - value = talloc_asprintf(mem_ctx, "%d", optval); - if (!value) { - goto nomem; - } - } - - *_value = value; - return 0; - - nomem: - errno = ENOMEM; - return -1; - nosys: - errno = ENOSYS; - return -1; -} - -static int tsocket_context_bsd_set_option(const struct tsocket_context *sock, - const char *option, - bool force, - const char *value) -{ - struct tsocket_context_bsd *bsds = talloc_get_type(sock->private_data, - struct tsocket_context_bsd); - const struct tsocket_context_bsd_option *opt = NULL; - uint32_t i; - int optval; - int ret; - - for (i=0; i < ARRAY_SIZE(tsocket_context_bsd_options); i++) { - if (strcmp(option, tsocket_context_bsd_options[i].name) != 0) { - continue; - } - - opt = &tsocket_context_bsd_options[i]; - break; - } - - if (!opt) { - goto nosys; - } - - if (value) { - if (opt->optval != 0) { - errno = EINVAL; - return -1; - } - - optval = atoi(value); - } else { - optval = opt->optval; - } - - ret = setsockopt(bsds->fd, opt->level, opt->optnum, - (const void *)&optval, sizeof(optval)); - if (ret != 0) { - if (!force) { - errno = 0; - return 0; - } - return ret; - } - - return 0; - - nosys: - if (!force) { - return 0; - } - - errno = ENOSYS; - return -1; -} - -static void tsocket_context_bsd_disconnect(struct tsocket_context *sock) -{ - struct tsocket_context_bsd *bsds = talloc_get_type(sock->private_data, - struct tsocket_context_bsd); - - tsocket_context_bsd_set_event_context(sock, NULL); - - if (bsds->fd != -1) { - if (bsds->close_on_disconnect) { - close(bsds->fd); - } - bsds->fd = -1; - } -} - -static const struct tsocket_context_ops tsocket_context_bsd_ops = { - .name = "bsd", - - .set_event_context = tsocket_context_bsd_set_event_context, - .set_read_handler = tsocket_context_bsd_set_read_handler, - .set_write_handler = tsocket_context_bsd_set_write_handler, - - .connect_to = tsocket_context_bsd_connect_to, - .listen_on = tsocket_context_bsd_listen_on, - .accept_new = tsocket_context_bsd_accept_new, - - .pending_data = tsocket_context_bsd_pending_data, - .readv_data = tsocket_context_bsd_readv_data, - .writev_data = tsocket_context_bsd_writev_data, - - .get_status = tsocket_context_bsd_get_status, - .get_local_address = tsocket_context_bsd_get_local_address, - .get_remote_address = tsocket_context_bsd_get_remote_address, - - .get_option = tsocket_context_bsd_get_option, - .set_option = tsocket_context_bsd_set_option, - - .disconnect = tsocket_context_bsd_disconnect }; struct tdgram_bsd { @@ -1482,7 +814,7 @@ static void tdgram_bsd_recvfrom_handler(void *private_data) sa_len = sizeof(bsda->u.ss); ret = recvfrom(bsds->fd, state->buf, state->len, 0, sa, &sa_len); - err = tsocket_error_from_errno(ret, errno, &retry); + err = tsocket_bsd_error_from_errno(ret, errno, &retry); if (retry) { /* retry later */ return; @@ -1630,7 +962,7 @@ static void tdgram_bsd_sendto_handler(void *private_data) } ret = sendto(bsds->fd, state->buf, state->len, 0, sa, sa_len); - err = tsocket_error_from_errno(ret, errno, &retry); + err = tsocket_bsd_error_from_errno(ret, errno, &retry); if (retry) { /* retry later */ return; @@ -1692,7 +1024,7 @@ static struct tevent_req *tdgram_bsd_disconnect_send(TALLOC_CTX *mem_ctx, ret = close(bsds->fd); bsds->fd = -1; - err = tsocket_error_from_errno(ret, errno, &dummy); + err = tsocket_bsd_error_from_errno(ret, errno, &dummy); if (tevent_req_error(req, err)) { goto post; } @@ -1739,6 +1071,7 @@ static int tdgram_bsd_destructor(struct tdgram_bsd *bsds) static int tdgram_bsd_dgram_socket(const struct tsocket_address *local, const struct tsocket_address *remote, + bool broadcast, TALLOC_CTX *mem_ctx, struct tdgram_context **_dgram, const char *location) @@ -1761,6 +1094,10 @@ static int tdgram_bsd_dgram_socket(const struct tsocket_address *local, switch (lbsda->u.sa.sa_family) { case AF_UNIX: + if (broadcast) { + errno = EINVAL; + return -1; + } if (lbsda->u.un.sun_path[0] != 0) { do_reuseaddr = true; do_bind = true; @@ -1818,7 +1155,7 @@ static int tdgram_bsd_dgram_socket(const struct tsocket_address *local, bsds->fd = fd; talloc_set_destructor(bsds, tdgram_bsd_destructor); - if (lbsda->broadcast) { + if (broadcast) { int val = 1; ret = setsockopt(fd, SOL_SOCKET, SO_BROADCAST, @@ -1891,7 +1228,8 @@ int _tdgram_inet_udp_socket(const struct tsocket_address *local, return -1; } - ret = tdgram_bsd_dgram_socket(local, remote, mem_ctx, dgram, location); + ret = tdgram_bsd_dgram_socket(local, remote, false, + mem_ctx, dgram, location); return ret; } @@ -1915,7 +1253,8 @@ int _tdgram_unix_dgram_socket(const struct tsocket_address *local, return -1; } - ret = tdgram_bsd_dgram_socket(local, remote, mem_ctx, dgram, location); + ret = tdgram_bsd_dgram_socket(local, remote, false, + mem_ctx, dgram, location); return ret; } diff --git a/lib/tsocket/tsocket_connect.c b/lib/tsocket/tsocket_connect.c deleted file mode 100644 index 7a9d4b8381..0000000000 --- a/lib/tsocket/tsocket_connect.c +++ /dev/null @@ -1,122 +0,0 @@ -/* - Unix SMB/CIFS implementation. - - Copyright (C) Stefan Metzmacher 2009 - - ** NOTE! The following LGPL license applies to the tevent - ** library. This does NOT imply that all of Samba is released - ** under the LGPL - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, see <http://www.gnu.org/licenses/>. -*/ - -#include "replace.h" -#include "system/network.h" -#include "tsocket.h" -#include "tsocket_internal.h" - -struct tsocket_connect_state { - /* this structs are owned by the caller */ - struct { - struct tsocket_context *sock; - const struct tsocket_address *dst; - } caller; -}; - -static void tsocket_connect_handler(struct tsocket_context *sock, - void *private_data); - -struct tevent_req *tsocket_connect_send(struct tsocket_context *sock, - TALLOC_CTX *mem_ctx, - const struct tsocket_address *dst) -{ - struct tevent_req *req; - struct tsocket_connect_state *state; - int ret; - int err; - bool retry; - bool dummy; - - req = tevent_req_create(mem_ctx, &state, - struct tsocket_connect_state); - if (!req) { - return NULL; - } - - state->caller.sock = sock; - state->caller.dst = dst; - - ret = tsocket_connect(state->caller.sock, - state->caller.dst); - err = tsocket_error_from_errno(ret, errno, &retry); - if (retry) { - /* retry later */ - goto async; - } - if (tevent_req_error(req, err)) { - goto post; - } - - tevent_req_done(req); - goto post; - - async: - ret = tsocket_set_readable_handler(state->caller.sock, - tsocket_connect_handler, - req); - err = tsocket_error_from_errno(ret, errno, &dummy); - if (tevent_req_error(req, err)) { - goto post; - } - - return req; - - post: - return tevent_req_post(req, sock->event.ctx); -} - -static void tsocket_connect_handler(struct tsocket_context *sock, - void *private_data) -{ - struct tevent_req *req = talloc_get_type(private_data, - struct tevent_req); - struct tsocket_connect_state *state = tevent_req_data(req, - struct tsocket_connect_state); - int ret; - int err; - bool retry; - - ret = tsocket_get_status(state->caller.sock); - err = tsocket_error_from_errno(ret, errno, &retry); - if (retry) { - /* retry later */ - return; - } - if (tevent_req_error(req, err)) { - return; - } - - tevent_req_done(req); -} - -int tsocket_connect_recv(struct tevent_req *req, int *perrno) -{ - int ret; - - ret = tsocket_simple_int_recv(req, perrno); - - tevent_req_received(req); - return ret; -} - diff --git a/lib/tsocket/tsocket_helpers.c b/lib/tsocket/tsocket_helpers.c index b2edf43d97..303be2de11 100644 --- a/lib/tsocket/tsocket_helpers.c +++ b/lib/tsocket/tsocket_helpers.c @@ -27,49 +27,6 @@ #include "tsocket.h" #include "tsocket_internal.h" -int tsocket_error_from_errno(int ret, - int sys_errno, - bool *retry) -{ - *retry = false; - - if (ret >= 0) { - return 0; - } - - if (ret != -1) { - return EIO; - } - - if (sys_errno == 0) { - return EIO; - } - - if (sys_errno == EINTR) { - *retry = true; - return sys_errno; - } - - if (sys_errno == EINPROGRESS) { - *retry = true; - return sys_errno; - } - - if (sys_errno == EAGAIN) { - *retry = true; - return sys_errno; - } - -#ifdef EWOULDBLOCK - if (sys_errno == EWOULDBLOCK) { - *retry = true; - return sys_errno; - } -#endif - - return sys_errno; -} - int tsocket_simple_int_recv(struct tevent_req *req, int *perrno) { enum tevent_req_state state; @@ -97,81 +54,3 @@ int tsocket_simple_int_recv(struct tevent_req *req, int *perrno) *perrno = EIO; return -1; } - -int tsocket_common_prepare_fd(int fd, bool high_fd) -{ - int i; - int sys_errno = 0; - int fds[3]; - int num_fds = 0; - - int result, flags; - - if (fd == -1) { - return -1; - } - - /* first make a fd >= 3 */ - if (high_fd) { - while (fd < 3) { - fds[num_fds++] = fd; - fd = dup(fd); - if (fd == -1) { - sys_errno = errno; - break; - } - } - for (i=0; i<num_fds; i++) { - close(fds[i]); - } - if (fd == -1) { - errno = sys_errno; - return fd; - } - } - - /* fd should be nonblocking. */ - -#ifdef O_NONBLOCK -#define FLAG_TO_SET O_NONBLOCK -#else -#ifdef SYSV -#define FLAG_TO_SET O_NDELAY -#else /* BSD */ -#define FLAG_TO_SET FNDELAY -#endif -#endif - - if ((flags = fcntl(fd, F_GETFL)) == -1) { - goto fail; - } - - flags |= FLAG_TO_SET; - if (fcntl(fd, F_SETFL, flags) == -1) { - goto fail; - } - -#undef FLAG_TO_SET - - /* fd should be closed on exec() */ -#ifdef FD_CLOEXEC - result = flags = fcntl(fd, F_GETFD, 0); - if (flags >= 0) { - flags |= FD_CLOEXEC; - result = fcntl(fd, F_SETFD, flags); - } - if (result < 0) { - goto fail; - } -#endif - return fd; - - fail: - if (fd != -1) { - sys_errno = errno; - close(fd); - errno = sys_errno; - } - return -1; -} - diff --git a/lib/tsocket/tsocket_internal.h b/lib/tsocket/tsocket_internal.h index 893394405f..a03dc9bde0 100644 --- a/lib/tsocket/tsocket_internal.h +++ b/lib/tsocket/tsocket_internal.h @@ -24,89 +24,6 @@ #ifndef _TSOCKET_INTERNAL_H #define _TSOCKET_INTERNAL_H -struct tsocket_context_ops { - const char *name; - - /* event handling */ - int (*set_event_context)(struct tsocket_context *sock, - struct tevent_context *ev); - int (*set_read_handler)(struct tsocket_context *sock, - tsocket_event_handler_t handler, - void *private_data); - int (*set_write_handler)(struct tsocket_context *sock, - tsocket_event_handler_t handler, - void *private_data); - - /* client ops */ - int (*connect_to)(struct tsocket_context *sock, - const struct tsocket_address *remote_addr); - - /* server ops */ - int (*listen_on)(struct tsocket_context *sock, - int queue_size); - int (*accept_new)(struct tsocket_context *sock, - TALLOC_CTX *mem_ctx, - struct tsocket_context **new_sock, - const char *location); - - /* general ops */ - ssize_t (*pending_data)(struct tsocket_context *sock); - - int (*readv_data)(struct tsocket_context *sock, - const struct iovec *vector, size_t count); - int (*writev_data)(struct tsocket_context *sock, - const struct iovec *vector, size_t count); - - /* info */ - int (*get_status)(const struct tsocket_context *sock); - int (*get_local_address)(const struct tsocket_context *sock, - TALLOC_CTX *mem_ctx, - struct tsocket_address **local_addr, - const char *location); - int (*get_remote_address)(const struct tsocket_context *sock, - TALLOC_CTX *mem_ctx, - struct tsocket_address **remote_addr, - const char *location); - - /* options */ - int (*get_option)(const struct tsocket_context *sock, - const char *option, - TALLOC_CTX *mem_ctx, - char **value); - int (*set_option)(const struct tsocket_context *sock, - const char *option, - bool force, - const char *value); - - /* close/disconnect */ - void (*disconnect)(struct tsocket_context *sock); -}; - -struct tsocket_context { - const char *location; - const struct tsocket_context_ops *ops; - - void *private_data; - - struct { - struct tevent_context *ctx; - void *read_private; - tsocket_event_handler_t read_handler; - void *write_private; - tsocket_event_handler_t write_handler; - } event; -}; - -struct tsocket_context *_tsocket_context_create(TALLOC_CTX *mem_ctx, - const struct tsocket_context_ops *ops, - void *pstate, - size_t psize, - const char *type, - const char *location); -#define tsocket_context_create(mem_ctx, ops, state, type, location) \ - _tsocket_context_create(mem_ctx, ops, state, sizeof(type), \ - #type, location) - struct tsocket_address_ops { const char *name; @@ -116,12 +33,6 @@ struct tsocket_address_ops { struct tsocket_address *(*copy)(const struct tsocket_address *addr, TALLOC_CTX *mem_ctx, const char *location); - - int (*create_socket)(const struct tsocket_address *addr, - enum tsocket_type, - TALLOC_CTX *mem_ctx, - struct tsocket_context **sock, - const char *location); }; struct tsocket_address { @@ -182,9 +93,7 @@ void *_tdgram_context_data(struct tdgram_context *dgram); #define tdgram_context_data(_req, _type) \ talloc_get_type_abort(_tdgram_context_data(_req), _type) -int tsocket_error_from_errno(int ret, int sys_errno, bool *retry); int tsocket_simple_int_recv(struct tevent_req *req, int *perrno); -int tsocket_common_prepare_fd(int fd, bool high_fd); #endif /* _TSOCKET_H */ diff --git a/lib/tsocket/tsocket_readv.c b/lib/tsocket/tsocket_readv.c deleted file mode 100644 index 2c8483ec7e..0000000000 --- a/lib/tsocket/tsocket_readv.c +++ /dev/null @@ -1,222 +0,0 @@ -/* - Unix SMB/CIFS implementation. - - Copyright (C) Stefan Metzmacher 2009 - - ** NOTE! The following LGPL license applies to the tevent - ** library. This does NOT imply that all of Samba is released - ** under the LGPL - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, see <http://www.gnu.org/licenses/>. -*/ - -#include "replace.h" -#include "system/network.h" -#include "tsocket.h" -#include "tsocket_internal.h" - -struct tsocket_readv_state { - /* this structs are owned by the caller */ - struct { - struct tsocket_context *sock; - tsocket_readv_next_iovec_t next_iovec_fn; - void *private_data; - } caller; - - /* - * Each call to the callback resets iov and count - * the callback allocated the iov as child of our state, - * that means we are allowed to modify and free it. - * - * we should call the callback every time we filled the given - * vector and ask for a new vector. We return if the callback - * ask for 0 bytes. - */ - struct iovec *iov; - size_t count; - - /* - * the total number of bytes we read, - * the return value of the _recv function - */ - int total_read; -}; - -static int tsocket_readv_state_destructor(struct tsocket_readv_state *state) -{ - if (state->caller.sock) { - tsocket_set_readable_handler(state->caller.sock, NULL, NULL); - } - ZERO_STRUCT(state->caller); - - return 0; -} - -static bool tsocket_readv_ask_for_next_vector(struct tevent_req *req, - struct tsocket_readv_state *state) -{ - int ret; - int err; - bool dummy; - size_t to_read = 0; - size_t i; - - talloc_free(state->iov); - state->iov = NULL; - state->count = 0; - - ret = state->caller.next_iovec_fn(state->caller.sock, - state->caller.private_data, - state, &state->iov, &state->count); - err = tsocket_error_from_errno(ret, errno, &dummy); - if (tevent_req_error(req, err)) { - return false; - } - - for (i=0; i < state->count; i++) { - size_t tmp = to_read; - tmp += state->iov[i].iov_len; - - if (tmp < to_read) { - tevent_req_error(req, EMSGSIZE); - return false; - } - - to_read = tmp; - } - - if (to_read == 0) { - tevent_req_done(req); - return false; - } - - if (state->total_read + to_read < state->total_read) { - tevent_req_error(req, EMSGSIZE); - return false; - } - - return true; -} - -static void tsocket_readv_handler(struct tsocket_context *sock, - void *private_data); - -struct tevent_req *tsocket_readv_send(struct tsocket_context *sock, - TALLOC_CTX *mem_ctx, - tsocket_readv_next_iovec_t next_iovec_fn, - void *private_data) -{ - struct tevent_req *req; - struct tsocket_readv_state *state; - int ret; - int err; - bool dummy; - - req = tevent_req_create(mem_ctx, &state, - struct tsocket_readv_state); - if (!req) { - return NULL; - } - - state->caller.sock = sock; - state->caller.next_iovec_fn = next_iovec_fn; - state->caller.private_data = private_data; - - state->iov = NULL; - state->count = 0; - state->total_read = 0; - - if (!tsocket_readv_ask_for_next_vector(req, state)) { - goto post; - } - - talloc_set_destructor(state, tsocket_readv_state_destructor); - - ret = tsocket_set_readable_handler(sock, - tsocket_readv_handler, - req); - err = tsocket_error_from_errno(ret, errno, &dummy); - if (tevent_req_error(req, err)) { - goto post; - } - - return req; - - post: - return tevent_req_post(req, sock->event.ctx); -} - -static void tsocket_readv_handler(struct tsocket_context *sock, - void *private_data) -{ - struct tevent_req *req = talloc_get_type(private_data, - struct tevent_req); - struct tsocket_readv_state *state = tevent_req_data(req, - struct tsocket_readv_state); - ssize_t ret; - int err; - bool retry; - - ret = tsocket_readv(state->caller.sock, - state->iov, - state->count); - err = tsocket_error_from_errno(ret, errno, &retry); - if (retry) { - /* retry later */ - return; - } - if (tevent_req_error(req, err)) { - return; - } - - state->total_read += ret; - - while (ret > 0) { - if (ret < state->iov[0].iov_len) { - uint8_t *base; - base = (uint8_t *)state->iov[0].iov_base; - base += ret; - state->iov[0].iov_base = base; - state->iov[0].iov_len -= ret; - break; - } - ret -= state->iov[0].iov_len; - state->iov += 1; - state->count -= 1; - } - - if (state->count) { - /* we have more to read */ - return; - } - - /* ask the callback for a new vector we should fill */ - tsocket_readv_ask_for_next_vector(req, state); -} - -int tsocket_readv_recv(struct tevent_req *req, int *perrno) -{ - struct tsocket_readv_state *state = tevent_req_data(req, - struct tsocket_readv_state); - int ret; - - ret = tsocket_simple_int_recv(req, perrno); - if (ret == 0) { - ret = state->total_read; - } - - tevent_req_received(req); - return ret; -} - diff --git a/lib/tsocket/tsocket_writev.c b/lib/tsocket/tsocket_writev.c deleted file mode 100644 index 8c5cd40385..0000000000 --- a/lib/tsocket/tsocket_writev.c +++ /dev/null @@ -1,316 +0,0 @@ -/* - Unix SMB/CIFS implementation. - - Copyright (C) Stefan Metzmacher 2009 - - ** NOTE! The following LGPL license applies to the tevent - ** library. This does NOT imply that all of Samba is released - ** under the LGPL - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, see <http://www.gnu.org/licenses/>. -*/ - -#include "replace.h" -#include "system/network.h" -#include "tsocket.h" -#include "tsocket_internal.h" - -struct tsocket_writev_state { - /* this structs are owned by the caller */ - struct { - struct tsocket_context *sock; - const struct iovec *vector; - size_t count; - } caller; - - struct iovec *iov; - size_t count; - int total_written; -}; - -static int tsocket_writev_state_destructor(struct tsocket_writev_state *state) -{ - if (state->caller.sock) { - tsocket_set_writeable_handler(state->caller.sock, NULL, NULL); - } - ZERO_STRUCT(state->caller); - - return 0; -} - -static void tsocket_writev_handler(struct tsocket_context *sock, - void *private_data); - -struct tevent_req *tsocket_writev_send(struct tsocket_context *sock, - TALLOC_CTX *mem_ctx, - const struct iovec *vector, - size_t count) -{ - struct tevent_req *req; - struct tsocket_writev_state *state; - int ret; - int err; - bool dummy; - int to_write = 0; - size_t i; - - req = tevent_req_create(mem_ctx, &state, - struct tsocket_writev_state); - if (!req) { - return NULL; - } - - state->caller.sock = sock; - state->caller.vector = vector; - state->caller.count = count; - - state->iov = NULL; - state->count = count; - state->total_written = 0; - - state->iov = talloc_array(state, struct iovec, count); - if (tevent_req_nomem(state->iov, req)) { - goto post; - } - memcpy(state->iov, vector, sizeof(struct iovec) * count); - - for (i=0; i < count; i++) { - int tmp = to_write; - - tmp += state->iov[i].iov_len; - - if (tmp < to_write) { - tevent_req_error(req, EMSGSIZE); - goto post; - } - - to_write = tmp; - } - - if (to_write == 0) { - tevent_req_done(req); - goto post; - } - - /* - * this is a fast path, not waiting for the - * socket to become explicit writeable gains - * about 10%-20% performance in benchmark tests. - */ - tsocket_writev_handler(sock, req); - if (!tevent_req_is_in_progress(req)) { - goto post; - } - - talloc_set_destructor(state, tsocket_writev_state_destructor); - - ret = tsocket_set_writeable_handler(sock, - tsocket_writev_handler, - req); - err = tsocket_error_from_errno(ret, errno, &dummy); - if (tevent_req_error(req, err)) { - goto post; - } - - return req; - - post: - return tevent_req_post(req, sock->event.ctx); -} - -static void tsocket_writev_handler(struct tsocket_context *sock, - void *private_data) -{ - struct tevent_req *req = talloc_get_type(private_data, - struct tevent_req); - struct tsocket_writev_state *state = tevent_req_data(req, - struct tsocket_writev_state); - int ret; - int err; - bool retry; - - ret = tsocket_writev(state->caller.sock, - state->iov, - state->count); - err = tsocket_error_from_errno(ret, errno, &retry); - if (retry) { - /* retry later */ - return; - } - if (tevent_req_error(req, err)) { - return; - } - - state->total_written += ret; - - /* - * we have not written everything yet, so we need to truncate - * the already written bytes from our iov copy - */ - while (ret > 0) { - if (ret < state->iov[0].iov_len) { - uint8_t *base; - base = (uint8_t *)state->iov[0].iov_base; - base += ret; - state->iov[0].iov_base = base; - state->iov[0].iov_len -= ret; - break; - } - ret -= state->iov[0].iov_len; - state->iov += 1; - state->count -= 1; - } - - if (state->count > 0) { - /* more to write */ - return; - } - - tevent_req_done(req); -} - -int tsocket_writev_recv(struct tevent_req *req, int *perrno) -{ - struct tsocket_writev_state *state = tevent_req_data(req, - struct tsocket_writev_state); - int ret; - - ret = tsocket_simple_int_recv(req, perrno); - if (ret == 0) { - ret = state->total_written; - } - - tevent_req_received(req); - return ret; -} - -struct tsocket_writev_queue_state { - /* this structs are owned by the caller */ - struct { - struct tsocket_context *sock; - const struct iovec *vector; - size_t count; - } caller; - int ret; -}; - -static void tsocket_writev_queue_trigger(struct tevent_req *req, - void *private_data); -static void tsocket_writev_queue_done(struct tevent_req *subreq); - -/** - * @brief Queue a dgram blob for sending through the socket - * @param[in] mem_ctx The memory context for the result - * @param[in] sock The socket to send data through - * @param[in] queue The existing send queue - * @param[in] vector The iovec vector so write - * @param[in] count The size of the vector - * @retval The async request handle - * - * This function queues a blob for sending to destination through an existing - * dgram socket. The async callback is triggered when the whole blob is - * delivered to the underlying system socket. - * - * The caller needs to make sure that all non-scalar input parameters hang - * arround for the whole lifetime of the request. - */ -struct tevent_req *tsocket_writev_queue_send(TALLOC_CTX *mem_ctx, - struct tsocket_context *sock, - struct tevent_queue *queue, - const struct iovec *vector, - size_t count) -{ - struct tevent_req *req; - struct tsocket_writev_queue_state *state; - bool ok; - - req = tevent_req_create(mem_ctx, &state, - struct tsocket_writev_queue_state); - if (!req) { - return NULL; - } - - state->caller.sock = sock; - state->caller.vector = vector; - state->caller.count = count; - state->ret = -1; - - ok = tevent_queue_add(queue, - sock->event.ctx, - req, - tsocket_writev_queue_trigger, - NULL); - if (!ok) { - tevent_req_nomem(NULL, req); - goto post; - } - - return req; - - post: - return tevent_req_post(req, sock->event.ctx); -} - -static void tsocket_writev_queue_trigger(struct tevent_req *req, - void *private_data) -{ - struct tsocket_writev_queue_state *state = tevent_req_data(req, - struct tsocket_writev_queue_state); - struct tevent_req *subreq; - - subreq = tsocket_writev_send(state->caller.sock, - state, - state->caller.vector, - state->caller.count); - if (tevent_req_nomem(subreq, req)) { - return; - } - tevent_req_set_callback(subreq, tsocket_writev_queue_done ,req); -} - -static void tsocket_writev_queue_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data(subreq, - struct tevent_req); - struct tsocket_writev_queue_state *state = tevent_req_data(req, - struct tsocket_writev_queue_state); - int ret; - int sys_errno; - - ret = tsocket_writev_recv(subreq, &sys_errno); - talloc_free(subreq); - if (ret == -1) { - tevent_req_error(req, sys_errno); - return; - } - state->ret = ret; - - tevent_req_done(req); -} - -int tsocket_writev_queue_recv(struct tevent_req *req, int *perrno) -{ - struct tsocket_writev_queue_state *state = tevent_req_data(req, - struct tsocket_writev_queue_state); - int ret; - - ret = tsocket_simple_int_recv(req, perrno); - if (ret == 0) { - ret = state->ret; - } - - tevent_req_received(req); - return ret; -} - |