Copyright (C) Stefan Metzmacher 2009
- ** NOTE! The following LGPL license applies to the tevent
+ ** NOTE! The following LGPL license applies to the tsocket
** library. This does NOT imply that all of Samba is released
** under the LGPL
#include "replace.h"
#include "system/filesys.h"
#include "system/network.h"
-#include "system/filesys.h"
#include "tsocket.h"
#include "tsocket_internal.h"
static ssize_t tsocket_bsd_pending(int fd)
{
- int ret;
+ int ret, error;
int value = 0;
+ socklen_t len;
ret = ioctl(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(fd, SOL_SOCKET, SO_ERROR,
- &error, &len);
- if (ret == -1) {
- return ret;
- }
- if (error != 0) {
- errno = error;
- return -1;
- }
- }
+ if (ret != 0) {
+ /* this should not be reached */
+ errno = EIO;
+ return -1;
+ }
+
+ if (value != 0) {
return value;
}
- /* this should not be reached */
- errno = EIO;
- return -1;
+ error = 0;
+ 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(fd, SOL_SOCKET, SO_ERROR, &error, &len);
+ if (ret == -1) {
+ return ret;
+ }
+ if (error != 0) {
+ errno = error;
+ return -1;
+ }
+ return 0;
}
-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;
} u;
};
-static int _tsocket_address_bsd_from_sockaddr(TALLOC_CTX *mem_ctx,
- struct sockaddr *sa,
- socklen_t sa_len,
- struct tsocket_address **_addr,
- const char *location)
+int _tsocket_address_bsd_from_sockaddr(TALLOC_CTX *mem_ctx,
+ struct sockaddr *sa,
+ size_t sa_socklen,
+ struct tsocket_address **_addr,
+ const char *location)
{
struct tsocket_address *addr;
struct tsocket_address_bsd *bsda;
+ if (sa_socklen < sizeof(sa->sa_family)) {
+ errno = EINVAL;
+ return -1;
+ }
+
switch (sa->sa_family) {
case AF_UNIX:
- if (sa_len < sizeof(struct sockaddr_un)) {
- errno = EINVAL;
- return -1;
+ if (sa_socklen > sizeof(struct sockaddr_un)) {
+ sa_socklen = sizeof(struct sockaddr_un);
}
break;
case AF_INET:
- if (sa_len < sizeof(struct sockaddr_in)) {
+ if (sa_socklen < sizeof(struct sockaddr_in)) {
errno = EINVAL;
return -1;
}
+ sa_socklen = sizeof(struct sockaddr_in);
break;
#ifdef HAVE_IPV6
case AF_INET6:
- if (sa_len < sizeof(struct sockaddr_in6)) {
+ if (sa_socklen < sizeof(struct sockaddr_in6)) {
errno = EINVAL;
return -1;
}
+ sa_socklen = sizeof(struct sockaddr_in6);
break;
#endif
default:
return -1;
}
- if (sa_len > sizeof(struct sockaddr_storage)) {
+ if (sa_socklen > sizeof(struct sockaddr_storage)) {
errno = EINVAL;
return -1;
}
ZERO_STRUCTP(bsda);
- memcpy(&bsda->u.ss, sa, sa_len);
+ memcpy(&bsda->u.ss, sa, sa_socklen);
*_addr = addr;
return 0;
}
+ssize_t tsocket_address_bsd_sockaddr(const struct tsocket_address *addr,
+ struct sockaddr *sa,
+ size_t sa_socklen)
+{
+ struct tsocket_address_bsd *bsda = talloc_get_type(addr->private_data,
+ struct tsocket_address_bsd);
+ ssize_t rlen = 0;
+
+ if (!bsda) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ switch (bsda->u.sa.sa_family) {
+ case AF_UNIX:
+ rlen = sizeof(struct sockaddr_un);
+ break;
+ case AF_INET:
+ rlen = sizeof(struct sockaddr_in);
+ break;
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ rlen = sizeof(struct sockaddr_in6);
+ break;
+#endif
+ default:
+ errno = EAFNOSUPPORT;
+ return -1;
+ }
+
+ if (sa_socklen < rlen) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (sa_socklen > sizeof(struct sockaddr_storage)) {
+ memset(sa, 0, sa_socklen);
+ sa_socklen = sizeof(struct sockaddr_storage);
+ }
+
+ memcpy(sa, &bsda->u.ss, sa_socklen);
+ return rlen;
+}
+
int _tsocket_address_inet_from_strings(TALLOC_CTX *mem_ctx,
const char *fam,
const char *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,
path = "";
}
+ if (strlen(path) > sizeof(un.sun_path)-1) {
+ errno = ENAMETOOLONG;
+ return -1;
+ }
+
ZERO_STRUCT(un);
un.sun_family = AF_UNIX;
- strncpy(un.sun_path, path, sizeof(un.sun_path));
+ strncpy(un.sun_path, path, sizeof(un.sun_path)-1);
ret = _tsocket_address_bsd_from_sockaddr(mem_ctx,
(struct sockaddr *)p,
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;
+static const struct tsocket_address_ops tsocket_address_bsd_ops = {
+ .name = "bsd",
+ .string = tsocket_address_bsd_string,
+ .copy = tsocket_address_bsd_copy,
+};
- sock = tsocket_context_create(mem_ctx,
- &tsocket_context_bsd_ops,
- &bsds,
- struct tsocket_context_bsd,
- location);
- if (!sock) {
- return -1;
- }
+struct tdgram_bsd {
+ int fd;
- bsds->close_on_disconnect = close_on_disconnect;
- bsds->fd = fd;
- bsds->fde = NULL;
+ void *event_ptr;
+ struct tevent_fd *fde;
- *_sock = sock;
- return 0;
-}
+ void *readable_private;
+ void (*readable_handler)(void *private_data);
+ void *writeable_private;
+ void (*writeable_handler)(void *private_data);
+};
-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)
+static void tdgram_bsd_fde_handler(struct tevent_context *ev,
+ struct tevent_fd *fde,
+ uint16_t flags,
+ void *private_data)
{
- 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;
+ struct tdgram_bsd *bsds = talloc_get_type_abort(private_data,
+ struct tdgram_bsd);
- switch (type) {
- case TSOCKET_TYPE_STREAM:
- if (bsda->broadcast) {
- errno = EINVAL;
- return -1;
+ if (flags & TEVENT_FD_WRITE) {
+ bsds->writeable_handler(bsds->writeable_private);
+ return;
+ }
+ if (flags & TEVENT_FD_READ) {
+ if (!bsds->readable_handler) {
+ TEVENT_FD_NOT_READABLE(bsds->fde);
+ return;
}
- bsd_type = SOCK_STREAM;
- break;
- default:
- errno = EPROTONOSUPPORT;
- return -1;
+ bsds->readable_handler(bsds->readable_private);
+ return;
}
+}
- switch (bsda->u.sa.sa_family) {
- case AF_UNIX:
- if (bsda->broadcast) {
+static int tdgram_bsd_set_readable_handler(struct tdgram_bsd *bsds,
+ struct tevent_context *ev,
+ void (*handler)(void *private_data),
+ void *private_data)
+{
+ if (ev == NULL) {
+ if (handler) {
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;
+ if (!bsds->readable_handler) {
+ return 0;
}
- break;
-#endif
- default:
- errno = EINVAL;
- return -1;
- }
+ bsds->readable_handler = NULL;
+ bsds->readable_private = NULL;
- fd = socket(bsda->u.sa.sa_family, bsd_type, 0);
- if (fd < 0) {
- return fd;
+ return 0;
}
- fd = tsocket_common_prepare_fd(fd, true);
- if (fd < 0) {
- return fd;
+ /* read and write must use the same tevent_context */
+ if (bsds->event_ptr != ev) {
+ if (bsds->readable_handler || bsds->writeable_handler) {
+ errno = EINVAL;
+ return -1;
+ }
+ bsds->event_ptr = NULL;
+ TALLOC_FREE(bsds->fde);
}
- 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 (tevent_fd_get_flags(bsds->fde) == 0) {
+ TALLOC_FREE(bsds->fde);
- 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;
+ bsds->fde = tevent_add_fd(ev, bsds,
+ bsds->fd, TEVENT_FD_READ,
+ tdgram_bsd_fde_handler,
+ bsds);
+ if (!bsds->fde) {
+ errno = ENOMEM;
+ return -1;
}
- }
- 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;
- }
+ /* cache the event context we're running on */
+ bsds->event_ptr = ev;
+ } else if (!bsds->readable_handler) {
+ TEVENT_FD_READABLE(bsds->fde);
}
- 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;
- }
- }
+ bsds->readable_handler = handler;
+ bsds->readable_private = private_data;
- *_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,
+static int tdgram_bsd_set_writeable_handler(struct tdgram_bsd *bsds,
+ struct tevent_context *ev,
+ void (*handler)(void *private_data),
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 == NULL) {
+ if (handler) {
+ errno = EINVAL;
+ return -1;
+ }
+ if (!bsds->writeable_handler) {
+ return 0;
+ }
+ bsds->writeable_handler = NULL;
+ bsds->writeable_private = NULL;
+ TEVENT_FD_NOT_WRITEABLE(bsds->fde);
- 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;
+ /* read and write must use the same tevent_context */
+ if (bsds->event_ptr != ev) {
+ if (bsds->readable_handler || bsds->writeable_handler) {
+ errno = EINVAL;
+ return -1;
}
- return -1;
+ bsds->event_ptr = NULL;
+ TALLOC_FREE(bsds->fde);
}
- sock->event.ctx = ev;
-
- return 0;
-}
+ if (tevent_fd_get_flags(bsds->fde) == 0) {
+ TALLOC_FREE(bsds->fde);
-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);
+ bsds->fde = tevent_add_fd(ev, bsds,
+ bsds->fd, TEVENT_FD_WRITE,
+ tdgram_bsd_fde_handler,
+ bsds);
+ if (!bsds->fde) {
+ errno = ENOMEM;
+ return -1;
+ }
- if (sock->event.read_handler && !handler) {
- TEVENT_FD_NOT_READABLE(bsds->fde);
- } else if (!sock->event.read_handler && handler) {
- TEVENT_FD_READABLE(bsds->fde);
+ /* cache the event context we're running on */
+ bsds->event_ptr = ev;
+ } else if (!bsds->writeable_handler) {
+ TEVENT_FD_WRITEABLE(bsds->fde);
}
- sock->event.read_handler = handler;
- sock->event.read_private = private_data;
+ bsds->writeable_handler = handler;
+ bsds->writeable_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);
+struct tdgram_bsd_recvfrom_state {
+ struct tdgram_context *dgram;
- if (sock->event.write_handler && !handler) {
- TEVENT_FD_NOT_WRITEABLE(bsds->fde);
- } else if (!sock->event.write_handler && handler) {
- TEVENT_FD_WRITEABLE(bsds->fde);
- }
+ uint8_t *buf;
+ size_t len;
+ struct tsocket_address *src;
+};
- sock->event.write_handler = handler;
- sock->event.write_private = private_data;
+static int tdgram_bsd_recvfrom_destructor(struct tdgram_bsd_recvfrom_state *state)
+{
+ struct tdgram_bsd *bsds = tdgram_context_data(state->dgram,
+ struct tdgram_bsd);
+
+ tdgram_bsd_set_readable_handler(bsds, NULL, NULL, NULL);
return 0;
}
-static int tsocket_context_bsd_connect_to(struct tsocket_context *sock,
- const struct tsocket_address *remote)
+static void tdgram_bsd_recvfrom_handler(void *private_data);
+
+static struct tevent_req *tdgram_bsd_recvfrom_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tdgram_context *dgram)
{
- 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);
+ struct tevent_req *req;
+ struct tdgram_bsd_recvfrom_state *state;
+ struct tdgram_bsd *bsds = tdgram_context_data(dgram, struct tdgram_bsd);
int ret;
- ret = connect(bsds->fd, &bsda->u.sa,
- sizeof(bsda->u.ss));
+ req = tevent_req_create(mem_ctx, &state,
+ struct tdgram_bsd_recvfrom_state);
+ if (!req) {
+ return NULL;
+ }
- return ret;
-}
+ state->dgram = dgram;
+ state->buf = NULL;
+ state->len = 0;
+ state->src = NULL;
-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;
+ talloc_set_destructor(state, tdgram_bsd_recvfrom_destructor);
- ret = listen(bsds->fd, queue_size);
+ if (bsds->fd == -1) {
+ tevent_req_error(req, ENOTCONN);
+ goto post;
+ }
- return ret;
-}
+ /*
+ * this is a fast path, not waiting for the
+ * socket to become explicit readable gains
+ * about 10%-20% performance in benchmark tests.
+ */
+ tdgram_bsd_recvfrom_handler(req);
+ if (!tevent_req_is_in_progress(req)) {
+ goto post;
+ }
-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;
+ ret = tdgram_bsd_set_readable_handler(bsds, ev,
+ tdgram_bsd_recvfrom_handler,
+ req);
+ if (ret == -1) {
+ tevent_req_error(req, errno);
+ goto post;
}
- new_bsds->close_on_disconnect = true;
- new_bsds->fd = new_fd;
- new_bsds->fde = NULL;
+ return req;
- *_new_sock = new_sock;
- return 0;
+ post:
+ tevent_req_post(req, ev);
+ return req;
}
-static ssize_t tsocket_context_bsd_pending_data(struct tsocket_context *sock)
+static void tdgram_bsd_recvfrom_handler(void *private_data)
{
- struct tsocket_context_bsd *bsds = talloc_get_type(sock->private_data,
- struct tsocket_context_bsd);
- int ret;
- int value = 0;
+ struct tevent_req *req = talloc_get_type_abort(private_data,
+ struct tevent_req);
+ struct tdgram_bsd_recvfrom_state *state = tevent_req_data(req,
+ struct tdgram_bsd_recvfrom_state);
+ struct tdgram_context *dgram = state->dgram;
+ struct tdgram_bsd *bsds = tdgram_context_data(dgram, struct tdgram_bsd);
+ struct tsocket_address_bsd *bsda;
+ ssize_t ret;
+ struct sockaddr *sa = NULL;
+ socklen_t sa_socklen = 0;
+ int err;
+ bool retry;
- ret = ioctl(bsds->fd, FIONREAD, &value);
- if (ret == -1) {
- return ret;
+ ret = tsocket_bsd_pending(bsds->fd);
+ if (ret == 0) {
+ /* retry later */
+ return;
+ }
+ err = tsocket_bsd_error_from_errno(ret, errno, &retry);
+ if (retry) {
+ /* retry later */
+ return;
+ }
+ if (tevent_req_error(req, err)) {
+ return;
}
- 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;
+ state->buf = talloc_array(state, uint8_t, ret);
+ if (tevent_req_nomem(state->buf, req)) {
+ return;
}
+ state->len = ret;
- /* this should not be reached */
- errno = EIO;
- return -1;
+ state->src = tsocket_address_create(state,
+ &tsocket_address_bsd_ops,
+ &bsda,
+ struct tsocket_address_bsd,
+ __location__ "bsd_recvfrom");
+ if (tevent_req_nomem(state->src, req)) {
+ return;
+ }
+
+ ZERO_STRUCTP(bsda);
+
+ sa = &bsda->u.sa;
+ sa_socklen = sizeof(bsda->u.ss);
+ /*
+ * for unix sockets we can't use the size of sockaddr_storage
+ * we would get EINVAL
+ */
+ if (bsda->u.sa.sa_family == AF_UNIX) {
+ sa_socklen = sizeof(bsda->u.un);
+ }
+
+ ret = recvfrom(bsds->fd, state->buf, state->len, 0, sa, &sa_socklen);
+ err = tsocket_bsd_error_from_errno(ret, errno, &retry);
+ if (retry) {
+ /* retry later */
+ return;
+ }
+ if (tevent_req_error(req, err)) {
+ return;
+ }
+
+ if (ret != state->len) {
+ tevent_req_error(req, EIO);
+ return;
+ }
+
+ tevent_req_done(req);
}
-static int tsocket_context_bsd_readv_data(struct tsocket_context *sock,
- const struct iovec *vector,
- size_t count)
+static ssize_t tdgram_bsd_recvfrom_recv(struct tevent_req *req,
+ int *perrno,
+ TALLOC_CTX *mem_ctx,
+ uint8_t **buf,
+ struct tsocket_address **src)
{
- struct tsocket_context_bsd *bsds = talloc_get_type(sock->private_data,
- struct tsocket_context_bsd);
- int ret;
+ struct tdgram_bsd_recvfrom_state *state = tevent_req_data(req,
+ struct tdgram_bsd_recvfrom_state);
+ ssize_t ret;
- ret = readv(bsds->fd, vector, count);
+ ret = tsocket_simple_int_recv(req, perrno);
+ if (ret == 0) {
+ *buf = talloc_move(mem_ctx, &state->buf);
+ ret = state->len;
+ if (src) {
+ *src = talloc_move(mem_ctx, &state->src);
+ }
+ }
+ tevent_req_received(req);
return ret;
}
-static int tsocket_context_bsd_writev_data(struct tsocket_context *sock,
- const struct iovec *vector,
- size_t count)
+struct tdgram_bsd_sendto_state {
+ struct tdgram_context *dgram;
+
+ const uint8_t *buf;
+ size_t len;
+ const struct tsocket_address *dst;
+
+ ssize_t ret;
+};
+
+static int tdgram_bsd_sendto_destructor(struct tdgram_bsd_sendto_state *state)
{
- struct tsocket_context_bsd *bsds = talloc_get_type(sock->private_data,
- struct tsocket_context_bsd);
- int ret;
+ struct tdgram_bsd *bsds = tdgram_context_data(state->dgram,
+ struct tdgram_bsd);
- ret = writev(bsds->fd, vector, count);
+ tdgram_bsd_set_writeable_handler(bsds, NULL, NULL, NULL);
- return ret;
+ return 0;
}
-static int tsocket_context_bsd_get_status(const struct tsocket_context *sock)
+static void tdgram_bsd_sendto_handler(void *private_data);
+
+static struct tevent_req *tdgram_bsd_sendto_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tdgram_context *dgram,
+ const uint8_t *buf,
+ size_t len,
+ const struct tsocket_address *dst)
{
- struct tsocket_context_bsd *bsds = talloc_get_type(sock->private_data,
- struct tsocket_context_bsd);
+ struct tevent_req *req;
+ struct tdgram_bsd_sendto_state *state;
+ struct tdgram_bsd *bsds = tdgram_context_data(dgram, struct tdgram_bsd);
int ret;
- int error=0;
- socklen_t len = sizeof(error);
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct tdgram_bsd_sendto_state);
+ if (!req) {
+ return NULL;
+ }
+
+ state->dgram = dgram;
+ state->buf = buf;
+ state->len = len;
+ state->dst = dst;
+ state->ret = -1;
+
+ talloc_set_destructor(state, tdgram_bsd_sendto_destructor);
if (bsds->fd == -1) {
- errno = EPIPE;
- return -1;
+ tevent_req_error(req, ENOTCONN);
+ goto post;
}
- ret = getsockopt(bsds->fd, SOL_SOCKET, SO_ERROR, &error, &len);
- if (ret == -1) {
- return ret;
+ /*
+ * this is a fast path, not waiting for the
+ * socket to become explicit writeable gains
+ * about 10%-20% performance in benchmark tests.
+ */
+ tdgram_bsd_sendto_handler(req);
+ if (!tevent_req_is_in_progress(req)) {
+ goto post;
}
- if (error != 0) {
- errno = error;
- return -1;
+
+ ret = tdgram_bsd_set_writeable_handler(bsds, ev,
+ tdgram_bsd_sendto_handler,
+ req);
+ if (ret == -1) {
+ tevent_req_error(req, errno);
+ goto post;
}
- return 0;
+ return req;
+
+ post:
+ tevent_req_post(req, ev);
+ return req;
}
-static int tsocket_context_bsd_get_local_address(const struct tsocket_context *sock,
- TALLOC_CTX *mem_ctx,
- struct tsocket_address **_addr,
- const char *location)
+static void tdgram_bsd_sendto_handler(void *private_data)
{
- struct tsocket_context_bsd *bsds = talloc_get_type(sock->private_data,
- struct tsocket_context_bsd);
- struct tsocket_address *addr;
- struct tsocket_address_bsd *bsda;
+ struct tevent_req *req = talloc_get_type_abort(private_data,
+ struct tevent_req);
+ struct tdgram_bsd_sendto_state *state = tevent_req_data(req,
+ struct tdgram_bsd_sendto_state);
+ struct tdgram_context *dgram = state->dgram;
+ struct tdgram_bsd *bsds = tdgram_context_data(dgram, struct tdgram_bsd);
+ struct sockaddr *sa = NULL;
+ socklen_t sa_socklen = 0;
ssize_t ret;
- socklen_t sa_len;
+ int err;
+ bool retry;
- addr = tsocket_address_create(mem_ctx,
- &tsocket_address_bsd_ops,
- &bsda,
- struct tsocket_address_bsd,
- location);
- if (!addr) {
- return -1;
- }
+ if (state->dst) {
+ struct tsocket_address_bsd *bsda =
+ talloc_get_type(state->dst->private_data,
+ struct tsocket_address_bsd);
- ZERO_STRUCTP(bsda);
+ sa = &bsda->u.sa;
+ sa_socklen = sizeof(bsda->u.ss);
+ /*
+ * for unix sockets we can't use the size of sockaddr_storage
+ * we would get EINVAL
+ */
+ if (bsda->u.sa.sa_family == AF_UNIX) {
+ sa_socklen = sizeof(bsda->u.un);
+ }
+ }
- 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;
+ ret = sendto(bsds->fd, state->buf, state->len, 0, sa, sa_socklen);
+ err = tsocket_bsd_error_from_errno(ret, errno, &retry);
+ if (retry) {
+ /* retry later */
+ return;
+ }
+ if (tevent_req_error(req, err)) {
+ return;
}
- *_addr = addr;
- return 0;
+ state->ret = ret;
+
+ tevent_req_done(req);
}
-static int tsocket_context_bsd_get_remote_address(const struct tsocket_context *sock,
- TALLOC_CTX *mem_ctx,
- struct tsocket_address **_addr,
- const char *location)
+static ssize_t tdgram_bsd_sendto_recv(struct tevent_req *req, int *perrno)
{
- struct tsocket_context_bsd *bsds = talloc_get_type(sock->private_data,
- struct tsocket_context_bsd);
- struct tsocket_address *addr;
- struct tsocket_address_bsd *bsda;
+ struct tdgram_bsd_sendto_state *state = tevent_req_data(req,
+ struct tdgram_bsd_sendto_state);
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;
+ ret = tsocket_simple_int_recv(req, perrno);
+ if (ret == 0) {
+ ret = state->ret;
}
- ZERO_STRUCTP(bsda);
+ tevent_req_received(req);
+ return ret;
+}
- 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;
+struct tdgram_bsd_disconnect_state {
+ uint8_t __dummy;
+};
+
+static struct tevent_req *tdgram_bsd_disconnect_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tdgram_context *dgram)
+{
+ struct tdgram_bsd *bsds = tdgram_context_data(dgram, struct tdgram_bsd);
+ struct tevent_req *req;
+ struct tdgram_bsd_disconnect_state *state;
+ int ret;
+ int err;
+ bool dummy;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct tdgram_bsd_disconnect_state);
+ if (req == NULL) {
+ return NULL;
}
- *_addr = addr;
- return 0;
+ if (bsds->fd == -1) {
+ tevent_req_error(req, ENOTCONN);
+ goto post;
+ }
+
+ ret = close(bsds->fd);
+ bsds->fd = -1;
+ err = tsocket_bsd_error_from_errno(ret, errno, &dummy);
+ if (tevent_req_error(req, err)) {
+ goto post;
+ }
+
+ tevent_req_done(req);
+post:
+ tevent_req_post(req, ev);
+ return req;
}
-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 \
+static int tdgram_bsd_disconnect_recv(struct tevent_req *req,
+ int *perrno)
+{
+ int ret;
+
+ ret = tsocket_simple_int_recv(req, perrno);
+
+ tevent_req_received(req);
+ return ret;
}
- TSOCKET_OPTION(SOL_SOCKET, SO_REUSEADDR, 0),
- TSOCKET_OPTION(SOL_SOCKET, SO_BROADCAST, 0)
+
+static const struct tdgram_context_ops tdgram_bsd_ops = {
+ .name = "bsd",
+
+ .recvfrom_send = tdgram_bsd_recvfrom_send,
+ .recvfrom_recv = tdgram_bsd_recvfrom_recv,
+
+ .sendto_send = tdgram_bsd_sendto_send,
+ .sendto_recv = tdgram_bsd_sendto_recv,
+
+ .disconnect_send = tdgram_bsd_disconnect_send,
+ .disconnect_recv = tdgram_bsd_disconnect_recv,
};
-static int tsocket_context_bsd_get_option(const struct tsocket_context *sock,
- const char *option,
- TALLOC_CTX *mem_ctx,
- char **_value)
+static int tdgram_bsd_destructor(struct tdgram_bsd *bsds)
{
- 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;
+ TALLOC_FREE(bsds->fde);
+ if (bsds->fd != -1) {
+ close(bsds->fd);
+ bsds->fd = -1;
+ }
+ return 0;
+}
+
+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)
+{
+ struct tsocket_address_bsd *lbsda =
+ talloc_get_type_abort(local->private_data,
+ struct tsocket_address_bsd);
+ struct tsocket_address_bsd *rbsda = NULL;
+ struct tdgram_context *dgram;
+ struct tdgram_bsd *bsds;
+ int fd;
int ret;
+ bool do_bind = false;
+ bool do_reuseaddr = false;
+ bool do_ipv6only = false;
+ bool is_inet = false;
+ int sa_fam = lbsda->u.sa.sa_family;
+ socklen_t sa_socklen = sizeof(lbsda->u.ss);
- for (i=0; i < ARRAY_SIZE(tsocket_context_bsd_options); i++) {
- if (strcmp(option, tsocket_context_bsd_options[i].name) != 0) {
- continue;
- }
+ if (remote) {
+ rbsda = talloc_get_type_abort(remote->private_data,
+ struct tsocket_address_bsd);
+ }
- opt = &tsocket_context_bsd_options[i];
+ 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;
+ }
+ /*
+ * for unix sockets we can't use the size of sockaddr_storage
+ * we would get EINVAL
+ */
+ sa_socklen = sizeof(lbsda->u.un);
break;
+ case AF_INET:
+ if (lbsda->u.in.sin_port != 0) {
+ do_reuseaddr = true;
+ do_bind = true;
+ }
+ if (lbsda->u.in.sin_addr.s_addr != INADDR_ANY) {
+ do_bind = true;
+ }
+ is_inet = true;
+ sa_socklen = sizeof(rbsda->u.in);
+ break;
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ if (lbsda->u.in6.sin6_port != 0) {
+ do_reuseaddr = true;
+ do_bind = true;
+ }
+ if (memcmp(&in6addr_any,
+ &lbsda->u.in6.sin6_addr,
+ sizeof(in6addr_any)) != 0) {
+ do_bind = true;
+ }
+ is_inet = true;
+ sa_socklen = sizeof(rbsda->u.in6);
+ do_ipv6only = true;
+ break;
+#endif
+ default:
+ errno = EINVAL;
+ return -1;
}
- if (!opt) {
- goto nosys;
+ if (!do_bind && is_inet && rbsda) {
+ sa_fam = rbsda->u.sa.sa_family;
+ switch (sa_fam) {
+ case AF_INET:
+ sa_socklen = sizeof(rbsda->u.in);
+ do_ipv6only = false;
+ break;
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ sa_socklen = sizeof(rbsda->u.in6);
+ do_ipv6only = true;
+ break;
+#endif
+ }
}
- ret = getsockopt(bsds->fd, opt->level, opt->optnum,
- (void *)&optval, &optval_len);
- if (ret != 0) {
- return ret;
+ fd = socket(sa_fam, SOCK_DGRAM, 0);
+ if (fd < 0) {
+ return fd;
}
- 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;
+ fd = tsocket_bsd_common_prepare_fd(fd, true);
+ if (fd < 0) {
+ return fd;
+ }
+
+ dgram = tdgram_context_create(mem_ctx,
+ &tdgram_bsd_ops,
+ &bsds,
+ struct tdgram_bsd,
+ location);
+ if (!dgram) {
+ int saved_errno = errno;
+ close(fd);
+ errno = saved_errno;
+ return -1;
+ }
+ ZERO_STRUCTP(bsds);
+ bsds->fd = fd;
+ talloc_set_destructor(bsds, tdgram_bsd_destructor);
+
+#ifdef HAVE_IPV6
+ if (do_ipv6only) {
+ int val = 1;
+
+ ret = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY,
+ (const void *)&val, sizeof(val));
+ if (ret == -1) {
+ int saved_errno = errno;
+ talloc_free(dgram);
+ errno = saved_errno;
+ return ret;
}
}
+#endif
- *_value = value;
- return 0;
+ if (broadcast) {
+ int val = 1;
- nomem:
- errno = ENOMEM;
- return -1;
- nosys:
- errno = ENOSYS;
- return -1;
-}
+ ret = setsockopt(fd, SOL_SOCKET, SO_BROADCAST,
+ (const void *)&val, sizeof(val));
+ if (ret == -1) {
+ int saved_errno = errno;
+ talloc_free(dgram);
+ errno = saved_errno;
+ return ret;
+ }
+ }
-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;
+ if (do_reuseaddr) {
+ int val = 1;
- for (i=0; i < ARRAY_SIZE(tsocket_context_bsd_options); i++) {
- if (strcmp(option, tsocket_context_bsd_options[i].name) != 0) {
- continue;
+ ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
+ (const void *)&val, sizeof(val));
+ if (ret == -1) {
+ int saved_errno = errno;
+ talloc_free(dgram);
+ errno = saved_errno;
+ return ret;
}
-
- opt = &tsocket_context_bsd_options[i];
- break;
}
- if (!opt) {
- goto nosys;
+ if (do_bind) {
+ ret = bind(fd, &lbsda->u.sa, sa_socklen);
+ if (ret == -1) {
+ int saved_errno = errno;
+ talloc_free(dgram);
+ errno = saved_errno;
+ return ret;
+ }
}
- if (value) {
- if (opt->optval != 0) {
+ if (rbsda) {
+ if (rbsda->u.sa.sa_family != sa_fam) {
+ talloc_free(dgram);
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;
+ ret = connect(fd, &rbsda->u.sa, sa_socklen);
+ if (ret == -1) {
+ int saved_errno = errno;
+ talloc_free(dgram);
+ errno = saved_errno;
+ return ret;
}
- return ret;
}
+ *_dgram = dgram;
return 0;
-
- nosys:
- if (!force) {
- return 0;
- }
-
- errno = ENOSYS;
- return -1;
}
-static void tsocket_context_bsd_disconnect(struct tsocket_context *sock)
+int _tdgram_inet_udp_socket(const struct tsocket_address *local,
+ const struct tsocket_address *remote,
+ TALLOC_CTX *mem_ctx,
+ struct tdgram_context **dgram,
+ const char *location)
{
- struct tsocket_context_bsd *bsds = talloc_get_type(sock->private_data,
- struct tsocket_context_bsd);
-
- tsocket_context_bsd_set_event_context(sock, NULL);
+ struct tsocket_address_bsd *lbsda =
+ talloc_get_type_abort(local->private_data,
+ struct tsocket_address_bsd);
+ int ret;
- if (bsds->fd != -1) {
- if (bsds->close_on_disconnect) {
- close(bsds->fd);
- }
- bsds->fd = -1;
+ switch (lbsda->u.sa.sa_family) {
+ case AF_INET:
+ break;
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ break;
+#endif
+ default:
+ errno = EINVAL;
+ return -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,
+ ret = tdgram_bsd_dgram_socket(local, remote, false,
+ mem_ctx, dgram, location);
- .connect_to = tsocket_context_bsd_connect_to,
- .listen_on = tsocket_context_bsd_listen_on,
- .accept_new = tsocket_context_bsd_accept_new,
+ return ret;
+}
- .pending_data = tsocket_context_bsd_pending_data,
- .readv_data = tsocket_context_bsd_readv_data,
- .writev_data = tsocket_context_bsd_writev_data,
+int _tdgram_unix_socket(const struct tsocket_address *local,
+ const struct tsocket_address *remote,
+ TALLOC_CTX *mem_ctx,
+ struct tdgram_context **dgram,
+ const char *location)
+{
+ struct tsocket_address_bsd *lbsda =
+ talloc_get_type_abort(local->private_data,
+ struct tsocket_address_bsd);
+ int ret;
- .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,
+ switch (lbsda->u.sa.sa_family) {
+ case AF_UNIX:
+ break;
+ default:
+ errno = EINVAL;
+ return -1;
+ }
- .get_option = tsocket_context_bsd_get_option,
- .set_option = tsocket_context_bsd_set_option,
+ ret = tdgram_bsd_dgram_socket(local, remote, false,
+ mem_ctx, dgram, location);
- .disconnect = tsocket_context_bsd_disconnect
-};
+ return ret;
+}
-struct tdgram_bsd {
+struct tstream_bsd {
int fd;
void *event_ptr;
void (*readable_handler)(void *private_data);
void *writeable_private;
void (*writeable_handler)(void *private_data);
-
- struct tevent_req *read_req;
- struct tevent_req *write_req;
};
-static void tdgram_bsd_fde_handler(struct tevent_context *ev,
- struct tevent_fd *fde,
- uint16_t flags,
- void *private_data)
+static void tstream_bsd_fde_handler(struct tevent_context *ev,
+ struct tevent_fd *fde,
+ uint16_t flags,
+ void *private_data)
{
- struct tdgram_bsd *bsds = talloc_get_type_abort(private_data,
- struct tdgram_bsd);
+ struct tstream_bsd *bsds = talloc_get_type_abort(private_data,
+ struct tstream_bsd);
if (flags & TEVENT_FD_WRITE) {
bsds->writeable_handler(bsds->writeable_private);
}
if (flags & TEVENT_FD_READ) {
if (!bsds->readable_handler) {
+ if (bsds->writeable_handler) {
+ bsds->writeable_handler(bsds->writeable_private);
+ return;
+ }
TEVENT_FD_NOT_READABLE(bsds->fde);
return;
}
}
}
-static int tdgram_bsd_set_readable_handler(struct tdgram_bsd *bsds,
- struct tevent_context *ev,
- void (*handler)(void *private_data),
- void *private_data)
+static int tstream_bsd_set_readable_handler(struct tstream_bsd *bsds,
+ struct tevent_context *ev,
+ void (*handler)(void *private_data),
+ void *private_data)
{
if (ev == NULL) {
if (handler) {
TALLOC_FREE(bsds->fde);
}
- if (bsds->fde == NULL) {
+ if (tevent_fd_get_flags(bsds->fde) == 0) {
+ TALLOC_FREE(bsds->fde);
+
bsds->fde = tevent_add_fd(ev, bsds,
bsds->fd, TEVENT_FD_READ,
- tdgram_bsd_fde_handler,
+ tstream_bsd_fde_handler,
bsds);
if (!bsds->fde) {
+ errno = ENOMEM;
return -1;
}
return 0;
}
-static int tdgram_bsd_set_writeable_handler(struct tdgram_bsd *bsds,
- struct tevent_context *ev,
- void (*handler)(void *private_data),
- void *private_data)
+static int tstream_bsd_set_writeable_handler(struct tstream_bsd *bsds,
+ struct tevent_context *ev,
+ void (*handler)(void *private_data),
+ void *private_data)
{
if (ev == NULL) {
if (handler) {
TALLOC_FREE(bsds->fde);
}
- if (bsds->fde == NULL) {
+ if (tevent_fd_get_flags(bsds->fde) == 0) {
+ TALLOC_FREE(bsds->fde);
+
bsds->fde = tevent_add_fd(ev, bsds,
- bsds->fd, TEVENT_FD_WRITE,
- tdgram_bsd_fde_handler,
+ bsds->fd,
+ TEVENT_FD_READ | TEVENT_FD_WRITE,
+ tstream_bsd_fde_handler,
bsds);
if (!bsds->fde) {
+ errno = ENOMEM;
return -1;
}
/* cache the event context we're running on */
bsds->event_ptr = ev;
} else if (!bsds->writeable_handler) {
- TEVENT_FD_WRITEABLE(bsds->fde);
+ uint16_t flags = tevent_fd_get_flags(bsds->fde);
+ flags |= TEVENT_FD_READ | TEVENT_FD_WRITE;
+ tevent_fd_set_flags(bsds->fde, flags);
}
bsds->writeable_handler = handler;
return 0;
}
-struct tdgram_bsd_recvfrom_state {
- struct tdgram_context *dgram;
+static ssize_t tstream_bsd_pending_bytes(struct tstream_context *stream)
+{
+ struct tstream_bsd *bsds = tstream_context_data(stream,
+ struct tstream_bsd);
+ ssize_t ret;
- uint8_t *buf;
- size_t len;
- struct tsocket_address *src;
+ if (bsds->fd == -1) {
+ errno = ENOTCONN;
+ return -1;
+ }
+
+ ret = tsocket_bsd_pending(bsds->fd);
+
+ return ret;
+}
+
+struct tstream_bsd_readv_state {
+ struct tstream_context *stream;
+
+ struct iovec *vector;
+ size_t count;
+
+ int ret;
};
-static int tdgram_bsd_recvfrom_destructor(struct tdgram_bsd_recvfrom_state *state)
+static int tstream_bsd_readv_destructor(struct tstream_bsd_readv_state *state)
{
- struct tdgram_bsd *bsds = tdgram_context_data(state->dgram,
- struct tdgram_bsd);
+ struct tstream_bsd *bsds = tstream_context_data(state->stream,
+ struct tstream_bsd);
- bsds->read_req = NULL;
- tdgram_bsd_set_readable_handler(bsds, NULL, NULL, NULL);
+ tstream_bsd_set_readable_handler(bsds, NULL, NULL, NULL);
return 0;
}
-static void tdgram_bsd_recvfrom_handler(void *private_data);
+static void tstream_bsd_readv_handler(void *private_data);
-static struct tevent_req *tdgram_bsd_recvfrom_send(TALLOC_CTX *mem_ctx,
+static struct tevent_req *tstream_bsd_readv_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
- struct tdgram_context *dgram)
+ struct tstream_context *stream,
+ struct iovec *vector,
+ size_t count)
{
struct tevent_req *req;
- struct tdgram_bsd_recvfrom_state *state;
- struct tdgram_bsd *bsds = tdgram_context_data(dgram, struct tdgram_bsd);
+ struct tstream_bsd_readv_state *state;
+ struct tstream_bsd *bsds = tstream_context_data(stream, struct tstream_bsd);
int ret;
req = tevent_req_create(mem_ctx, &state,
- struct tdgram_bsd_recvfrom_state);
+ struct tstream_bsd_readv_state);
if (!req) {
return NULL;
}
- state->dgram = dgram;
- state->buf = NULL;
- state->len = 0;
- state->src = NULL;
-
- if (bsds->read_req) {
- tevent_req_error(req, EBUSY);
+ state->stream = stream;
+ /* we make a copy of the vector so that we can modify it */
+ state->vector = talloc_array(state, struct iovec, count);
+ if (tevent_req_nomem(state->vector, req)) {
goto post;
}
- bsds->read_req = req;
+ memcpy(state->vector, vector, sizeof(struct iovec)*count);
+ state->count = count;
+ state->ret = 0;
- talloc_set_destructor(state, tdgram_bsd_recvfrom_destructor);
+ talloc_set_destructor(state, tstream_bsd_readv_destructor);
if (bsds->fd == -1) {
tevent_req_error(req, ENOTCONN);
* socket to become explicit readable gains
* about 10%-20% performance in benchmark tests.
*/
- tdgram_bsd_recvfrom_handler(req);
+ tstream_bsd_readv_handler(req);
if (!tevent_req_is_in_progress(req)) {
goto post;
}
- ret = tdgram_bsd_set_readable_handler(bsds, ev,
- tdgram_bsd_recvfrom_handler,
+ ret = tstream_bsd_set_readable_handler(bsds, ev,
+ tstream_bsd_readv_handler,
req);
if (ret == -1) {
tevent_req_error(req, errno);
return req;
}
-static void tdgram_bsd_recvfrom_handler(void *private_data)
+static void tstream_bsd_readv_handler(void *private_data)
{
struct tevent_req *req = talloc_get_type_abort(private_data,
struct tevent_req);
- struct tdgram_bsd_recvfrom_state *state = tevent_req_data(req,
- struct tdgram_bsd_recvfrom_state);
- struct tdgram_context *dgram = state->dgram;
- struct tdgram_bsd *bsds = tdgram_context_data(dgram, struct tdgram_bsd);
- struct tsocket_address_bsd *bsda;
- ssize_t ret;
- struct sockaddr *sa = NULL;
- socklen_t sa_len = 0;
+ struct tstream_bsd_readv_state *state = tevent_req_data(req,
+ struct tstream_bsd_readv_state);
+ struct tstream_context *stream = state->stream;
+ struct tstream_bsd *bsds = tstream_context_data(stream, struct tstream_bsd);
+ int ret;
int err;
bool retry;
- ret = tsocket_bsd_pending(bsds->fd);
+ ret = readv(bsds->fd, state->vector, state->count);
if (ret == 0) {
- /* retry later */
+ /* propagate end of file */
+ tevent_req_error(req, EPIPE);
return;
}
err = tsocket_bsd_error_from_errno(ret, errno, &retry);
return;
}
- state->buf = talloc_array(state, uint8_t, ret);
- if (tevent_req_nomem(state->buf, req)) {
- return;
- }
- state->len = ret;
+ state->ret += ret;
- state->src = tsocket_address_create(state,
- &tsocket_address_bsd_ops,
- &bsda,
- struct tsocket_address_bsd,
- __location__ "bsd_recvfrom");
- if (tevent_req_nomem(state->src, req)) {
- return;
+ while (ret > 0) {
+ if (ret < state->vector[0].iov_len) {
+ uint8_t *base;
+ base = (uint8_t *)state->vector[0].iov_base;
+ base += ret;
+ state->vector[0].iov_base = base;
+ state->vector[0].iov_len -= ret;
+ break;
+ }
+ ret -= state->vector[0].iov_len;
+ state->vector += 1;
+ state->count -= 1;
}
- ZERO_STRUCTP(bsda);
-
- sa = &bsda->u.sa;
- 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);
- if (retry) {
- /* retry later */
- return;
- }
- if (tevent_req_error(req, err)) {
- return;
+ /*
+ * there're maybe some empty vectors at the end
+ * which we need to skip, otherwise we would get
+ * ret == 0 from the readv() call and return EPIPE
+ */
+ while (state->count > 0) {
+ if (state->vector[0].iov_len > 0) {
+ break;
+ }
+ state->vector += 1;
+ state->count -= 1;
}
- if (ret != state->len) {
- tevent_req_error(req, EIO);
+ if (state->count > 0) {
+ /* we have more to read */
return;
}
tevent_req_done(req);
}
-static ssize_t tdgram_bsd_recvfrom_recv(struct tevent_req *req,
- int *perrno,
- TALLOC_CTX *mem_ctx,
- uint8_t **buf,
- struct tsocket_address **src)
+static int tstream_bsd_readv_recv(struct tevent_req *req,
+ int *perrno)
{
- struct tdgram_bsd_recvfrom_state *state = tevent_req_data(req,
- struct tdgram_bsd_recvfrom_state);
- ssize_t ret;
+ struct tstream_bsd_readv_state *state = tevent_req_data(req,
+ struct tstream_bsd_readv_state);
+ int ret;
ret = tsocket_simple_int_recv(req, perrno);
if (ret == 0) {
- *buf = talloc_move(mem_ctx, &state->buf);
- ret = state->len;
- if (src) {
- *src = talloc_move(mem_ctx, &state->src);
- }
+ ret = state->ret;
}
tevent_req_received(req);
return ret;
}
-struct tdgram_bsd_sendto_state {
- struct tdgram_context *dgram;
+struct tstream_bsd_writev_state {
+ struct tstream_context *stream;
- const uint8_t *buf;
- size_t len;
- const struct tsocket_address *dst;
+ struct iovec *vector;
+ size_t count;
- ssize_t ret;
+ int ret;
};
-static int tdgram_bsd_sendto_destructor(struct tdgram_bsd_sendto_state *state)
+static int tstream_bsd_writev_destructor(struct tstream_bsd_writev_state *state)
{
- struct tdgram_bsd *bsds = tdgram_context_data(state->dgram,
- struct tdgram_bsd);
+ struct tstream_bsd *bsds = tstream_context_data(state->stream,
+ struct tstream_bsd);
+
+ tstream_bsd_set_writeable_handler(bsds, NULL, NULL, NULL);
- bsds->write_req = NULL;
- tdgram_bsd_set_writeable_handler(bsds, NULL, NULL, NULL);
return 0;
}
-static void tdgram_bsd_sendto_handler(void *private_data);
+static void tstream_bsd_writev_handler(void *private_data);
-static struct tevent_req *tdgram_bsd_sendto_send(TALLOC_CTX *mem_ctx,
+static struct tevent_req *tstream_bsd_writev_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
- struct tdgram_context *dgram,
- const uint8_t *buf,
- size_t len,
- const struct tsocket_address *dst)
+ struct tstream_context *stream,
+ const struct iovec *vector,
+ size_t count)
{
struct tevent_req *req;
- struct tdgram_bsd_sendto_state *state;
- struct tdgram_bsd *bsds = tdgram_context_data(dgram, struct tdgram_bsd);
+ struct tstream_bsd_writev_state *state;
+ struct tstream_bsd *bsds = tstream_context_data(stream, struct tstream_bsd);
int ret;
req = tevent_req_create(mem_ctx, &state,
- struct tdgram_bsd_sendto_state);
+ struct tstream_bsd_writev_state);
if (!req) {
return NULL;
}
- state->dgram = dgram;
- state->buf = buf;
- state->len = len;
- state->dst = dst;
- state->ret = -1;
-
- if (bsds->write_req) {
- tevent_req_error(req, EBUSY);
+ state->stream = stream;
+ /* we make a copy of the vector so that we can modify it */
+ state->vector = talloc_array(state, struct iovec, count);
+ if (tevent_req_nomem(state->vector, req)) {
goto post;
}
- bsds->write_req = req;
+ memcpy(state->vector, vector, sizeof(struct iovec)*count);
+ state->count = count;
+ state->ret = 0;
- talloc_set_destructor(state, tdgram_bsd_sendto_destructor);
+ talloc_set_destructor(state, tstream_bsd_writev_destructor);
if (bsds->fd == -1) {
tevent_req_error(req, ENOTCONN);
* socket to become explicit writeable gains
* about 10%-20% performance in benchmark tests.
*/
- tdgram_bsd_sendto_handler(req);
+ tstream_bsd_writev_handler(req);
if (!tevent_req_is_in_progress(req)) {
goto post;
}
- ret = tdgram_bsd_set_writeable_handler(bsds, ev,
- tdgram_bsd_sendto_handler,
+ ret = tstream_bsd_set_writeable_handler(bsds, ev,
+ tstream_bsd_writev_handler,
req);
if (ret == -1) {
tevent_req_error(req, errno);
return req;
}
-static void tdgram_bsd_sendto_handler(void *private_data)
+static void tstream_bsd_writev_handler(void *private_data)
{
struct tevent_req *req = talloc_get_type_abort(private_data,
struct tevent_req);
- struct tdgram_bsd_sendto_state *state = tevent_req_data(req,
- struct tdgram_bsd_sendto_state);
- struct tdgram_context *dgram = state->dgram;
- struct tdgram_bsd *bsds = tdgram_context_data(dgram, struct tdgram_bsd);
- struct sockaddr *sa = NULL;
- socklen_t sa_len = 0;
+ struct tstream_bsd_writev_state *state = tevent_req_data(req,
+ struct tstream_bsd_writev_state);
+ struct tstream_context *stream = state->stream;
+ struct tstream_bsd *bsds = tstream_context_data(stream, struct tstream_bsd);
ssize_t ret;
int err;
bool retry;
- if (state->dst) {
- struct tsocket_address_bsd *bsda =
- talloc_get_type(state->dst->private_data,
- struct tsocket_address_bsd);
-
- sa = &bsda->u.sa;
- sa_len = sizeof(bsda->u.ss);
+ ret = writev(bsds->fd, state->vector, state->count);
+ if (ret == 0) {
+ /* propagate end of file */
+ tevent_req_error(req, EPIPE);
+ return;
}
-
- 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;
return;
}
- state->ret = ret;
+ state->ret += ret;
+
+ while (ret > 0) {
+ if (ret < state->vector[0].iov_len) {
+ uint8_t *base;
+ base = (uint8_t *)state->vector[0].iov_base;
+ base += ret;
+ state->vector[0].iov_base = base;
+ state->vector[0].iov_len -= ret;
+ break;
+ }
+ ret -= state->vector[0].iov_len;
+ state->vector += 1;
+ state->count -= 1;
+ }
+
+ /*
+ * there're maybe some empty vectors at the end
+ * which we need to skip, otherwise we would get
+ * ret == 0 from the writev() call and return EPIPE
+ */
+ while (state->count > 0) {
+ if (state->vector[0].iov_len > 0) {
+ break;
+ }
+ state->vector += 1;
+ state->count -= 1;
+ }
+
+ if (state->count > 0) {
+ /* we have more to read */
+ return;
+ }
tevent_req_done(req);
}
-static ssize_t tdgram_bsd_sendto_recv(struct tevent_req *req, int *perrno)
+static int tstream_bsd_writev_recv(struct tevent_req *req, int *perrno)
{
- struct tdgram_bsd_sendto_state *state = tevent_req_data(req,
- struct tdgram_bsd_sendto_state);
- ssize_t ret;
+ struct tstream_bsd_writev_state *state = tevent_req_data(req,
+ struct tstream_bsd_writev_state);
+ int ret;
ret = tsocket_simple_int_recv(req, perrno);
if (ret == 0) {
return ret;
}
-struct tdgram_bsd_disconnect_state {
- uint8_t __dummy;
+struct tstream_bsd_disconnect_state {
+ void *__dummy;
};
-static struct tevent_req *tdgram_bsd_disconnect_send(TALLOC_CTX *mem_ctx,
+static struct tevent_req *tstream_bsd_disconnect_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
- struct tdgram_context *dgram)
+ struct tstream_context *stream)
{
- struct tdgram_bsd *bsds = tdgram_context_data(dgram, struct tdgram_bsd);
+ struct tstream_bsd *bsds = tstream_context_data(stream, struct tstream_bsd);
struct tevent_req *req;
- struct tdgram_bsd_disconnect_state *state;
+ struct tstream_bsd_disconnect_state *state;
int ret;
int err;
bool dummy;
req = tevent_req_create(mem_ctx, &state,
- struct tdgram_bsd_disconnect_state);
+ struct tstream_bsd_disconnect_state);
if (req == NULL) {
return NULL;
}
- if (bsds->read_req || bsds->write_req) {
- tevent_req_error(req, EBUSY);
- goto post;
- }
-
if (bsds->fd == -1) {
tevent_req_error(req, ENOTCONN);
goto post;
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;
}
return req;
}
-static int tdgram_bsd_disconnect_recv(struct tevent_req *req,
+static int tstream_bsd_disconnect_recv(struct tevent_req *req,
int *perrno)
{
int ret;
return ret;
}
-static const struct tdgram_context_ops tdgram_bsd_ops = {
+static const struct tstream_context_ops tstream_bsd_ops = {
.name = "bsd",
- .recvfrom_send = tdgram_bsd_recvfrom_send,
- .recvfrom_recv = tdgram_bsd_recvfrom_recv,
+ .pending_bytes = tstream_bsd_pending_bytes,
- .sendto_send = tdgram_bsd_sendto_send,
- .sendto_recv = tdgram_bsd_sendto_recv,
+ .readv_send = tstream_bsd_readv_send,
+ .readv_recv = tstream_bsd_readv_recv,
- .disconnect_send = tdgram_bsd_disconnect_send,
- .disconnect_recv = tdgram_bsd_disconnect_recv,
+ .writev_send = tstream_bsd_writev_send,
+ .writev_recv = tstream_bsd_writev_recv,
+
+ .disconnect_send = tstream_bsd_disconnect_send,
+ .disconnect_recv = tstream_bsd_disconnect_recv,
};
-static int tdgram_bsd_destructor(struct tdgram_bsd *bsds)
+static int tstream_bsd_destructor(struct tstream_bsd *bsds)
{
TALLOC_FREE(bsds->fde);
if (bsds->fd != -1) {
return 0;
}
-static int tdgram_bsd_dgram_socket(const struct tsocket_address *local,
- const struct tsocket_address *remote,
- TALLOC_CTX *mem_ctx,
- struct tdgram_context **_dgram,
- const char *location)
+int _tstream_bsd_existing_socket(TALLOC_CTX *mem_ctx,
+ int fd,
+ struct tstream_context **_stream,
+ const char *location)
+{
+ struct tstream_context *stream;
+ struct tstream_bsd *bsds;
+
+ stream = tstream_context_create(mem_ctx,
+ &tstream_bsd_ops,
+ &bsds,
+ struct tstream_bsd,
+ location);
+ if (!stream) {
+ return -1;
+ }
+ ZERO_STRUCTP(bsds);
+ bsds->fd = fd;
+ talloc_set_destructor(bsds, tstream_bsd_destructor);
+
+ *_stream = stream;
+ return 0;
+}
+
+struct tstream_bsd_connect_state {
+ int fd;
+ struct tevent_fd *fde;
+ struct tstream_conext *stream;
+};
+
+static int tstream_bsd_connect_destructor(struct tstream_bsd_connect_state *state)
+{
+ TALLOC_FREE(state->fde);
+ if (state->fd != -1) {
+ close(state->fd);
+ state->fd = -1;
+ }
+
+ return 0;
+}
+
+static void tstream_bsd_connect_fde_handler(struct tevent_context *ev,
+ struct tevent_fd *fde,
+ uint16_t flags,
+ void *private_data);
+
+static struct tevent_req * tstream_bsd_connect_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ int sys_errno,
+ const struct tsocket_address *local,
+ const struct tsocket_address *remote)
{
+ struct tevent_req *req;
+ struct tstream_bsd_connect_state *state;
struct tsocket_address_bsd *lbsda =
talloc_get_type_abort(local->private_data,
struct tsocket_address_bsd);
- struct tsocket_address_bsd *rbsda = NULL;
- struct tdgram_context *dgram;
- struct tdgram_bsd *bsds;
- int fd;
+ struct tsocket_address_bsd *rbsda =
+ talloc_get_type_abort(remote->private_data,
+ struct tsocket_address_bsd);
int ret;
+ int err;
+ bool retry;
bool do_bind = false;
bool do_reuseaddr = false;
+ bool do_ipv6only = false;
+ bool is_inet = false;
+ int sa_fam = lbsda->u.sa.sa_family;
+ socklen_t sa_socklen = sizeof(rbsda->u.ss);
- if (remote) {
- rbsda = talloc_get_type_abort(remote->private_data,
- struct tsocket_address_bsd);
+ req = tevent_req_create(mem_ctx, &state,
+ struct tstream_bsd_connect_state);
+ if (!req) {
+ return NULL;
+ }
+ state->fd = -1;
+ state->fde = NULL;
+
+ talloc_set_destructor(state, tstream_bsd_connect_destructor);
+
+ /* give the wrappers a chance to report an error */
+ if (sys_errno != 0) {
+ tevent_req_error(req, sys_errno);
+ goto post;
}
switch (lbsda->u.sa.sa_family) {
do_reuseaddr = true;
do_bind = true;
}
+ /*
+ * for unix sockets we can't use the size of sockaddr_storage
+ * we would get EINVAL
+ */
+ sa_socklen = sizeof(rbsda->u.un);
break;
case AF_INET:
if (lbsda->u.in.sin_port != 0) {
do_reuseaddr = true;
do_bind = true;
}
- if (lbsda->u.in.sin_addr.s_addr == INADDR_ANY) {
+ if (lbsda->u.in.sin_addr.s_addr != INADDR_ANY) {
do_bind = true;
}
+ is_inet = true;
+ sa_socklen = sizeof(rbsda->u.in);
break;
#ifdef HAVE_IPV6
case AF_INET6:
sizeof(in6addr_any)) != 0) {
do_bind = true;
}
+ is_inet = true;
+ sa_socklen = sizeof(rbsda->u.in6);
+ do_ipv6only = true;
break;
#endif
default:
- errno = EINVAL;
- return -1;
+ tevent_req_error(req, EINVAL);
+ goto post;
}
- fd = socket(lbsda->u.sa.sa_family, SOCK_DGRAM, 0);
- if (fd < 0) {
- return fd;
+ if (!do_bind && is_inet) {
+ sa_fam = rbsda->u.sa.sa_family;
+ switch (sa_fam) {
+ case AF_INET:
+ sa_socklen = sizeof(rbsda->u.in);
+ do_ipv6only = false;
+ break;
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ sa_socklen = sizeof(rbsda->u.in6);
+ do_ipv6only = true;
+ break;
+#endif
+ }
}
- fd = tsocket_bsd_common_prepare_fd(fd, true);
- if (fd < 0) {
- return fd;
+ state->fd = socket(sa_fam, SOCK_STREAM, 0);
+ if (state->fd == -1) {
+ tevent_req_error(req, errno);
+ goto post;
}
- dgram = tdgram_context_create(mem_ctx,
- &tdgram_bsd_ops,
- &bsds,
- struct tdgram_bsd,
- location);
- if (!dgram) {
- int saved_errno = errno;
- close(fd);
- errno = saved_errno;
- return -1;
+ state->fd = tsocket_bsd_common_prepare_fd(state->fd, true);
+ if (state->fd == -1) {
+ tevent_req_error(req, errno);
+ goto post;
}
- ZERO_STRUCTP(bsds);
- bsds->fd = fd;
- talloc_set_destructor(bsds, tdgram_bsd_destructor);
- if (lbsda->broadcast) {
+#ifdef HAVE_IPV6
+ if (do_ipv6only) {
int val = 1;
- ret = setsockopt(fd, SOL_SOCKET, SO_BROADCAST,
+ ret = setsockopt(state->fd, IPPROTO_IPV6, IPV6_V6ONLY,
(const void *)&val, sizeof(val));
if (ret == -1) {
- int saved_errno = errno;
- talloc_free(dgram);
- errno = saved_errno;
- return ret;
+ tevent_req_error(req, errno);
+ goto post;
}
}
+#endif
if (do_reuseaddr) {
int val = 1;
- ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
+ ret = setsockopt(state->fd, SOL_SOCKET, SO_REUSEADDR,
(const void *)&val, sizeof(val));
if (ret == -1) {
- int saved_errno = errno;
- talloc_free(dgram);
- errno = saved_errno;
- return ret;
+ tevent_req_error(req, errno);
+ goto post;
}
}
if (do_bind) {
- ret = bind(fd, &lbsda->u.sa, sizeof(lbsda->u.ss));
+ ret = bind(state->fd, &lbsda->u.sa, sa_socklen);
if (ret == -1) {
- int saved_errno = errno;
- talloc_free(dgram);
- errno = saved_errno;
- return ret;
+ tevent_req_error(req, errno);
+ goto post;
}
}
- if (rbsda) {
- ret = connect(fd, &rbsda->u.sa, sizeof(rbsda->u.ss));
+ if (rbsda->u.sa.sa_family != sa_fam) {
+ tevent_req_error(req, EINVAL);
+ goto post;
+ }
+
+ ret = connect(state->fd, &rbsda->u.sa, sa_socklen);
+ err = tsocket_bsd_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:
+ state->fde = tevent_add_fd(ev, state,
+ state->fd,
+ TEVENT_FD_READ | TEVENT_FD_WRITE,
+ tstream_bsd_connect_fde_handler,
+ req);
+ if (tevent_req_nomem(state->fde, req)) {
+ goto post;
+ }
+
+ return req;
+
+ post:
+ tevent_req_post(req, ev);
+ return req;
+}
+
+static void tstream_bsd_connect_fde_handler(struct tevent_context *ev,
+ struct tevent_fd *fde,
+ uint16_t flags,
+ void *private_data)
+{
+ struct tevent_req *req = talloc_get_type_abort(private_data,
+ struct tevent_req);
+ struct tstream_bsd_connect_state *state = tevent_req_data(req,
+ struct tstream_bsd_connect_state);
+ int ret;
+ int error=0;
+ socklen_t len = sizeof(error);
+ int err;
+ bool retry;
+
+ ret = getsockopt(state->fd, SOL_SOCKET, SO_ERROR, &error, &len);
+ if (ret == 0) {
+ if (error != 0) {
+ errno = error;
+ ret = -1;
+ }
+ }
+ err = tsocket_bsd_error_from_errno(ret, errno, &retry);
+ if (retry) {
+ /* retry later */
+ return;
+ }
+ if (tevent_req_error(req, err)) {
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+static int tstream_bsd_connect_recv(struct tevent_req *req,
+ int *perrno,
+ TALLOC_CTX *mem_ctx,
+ struct tstream_context **stream,
+ const char *location)
+{
+ struct tstream_bsd_connect_state *state = tevent_req_data(req,
+ struct tstream_bsd_connect_state);
+ int ret;
+
+ ret = tsocket_simple_int_recv(req, perrno);
+ if (ret == 0) {
+ ret = _tstream_bsd_existing_socket(mem_ctx,
+ state->fd,
+ stream,
+ location);
if (ret == -1) {
- int saved_errno = errno;
- talloc_free(dgram);
- errno = saved_errno;
- return ret;
+ *perrno = errno;
+ goto done;
}
+ TALLOC_FREE(state->fde);
+ state->fd = -1;
}
- *_dgram = dgram;
- return 0;
+done:
+ tevent_req_received(req);
+ return ret;
}
-int _tdgram_inet_udp_socket(const struct tsocket_address *local,
- const struct tsocket_address *remote,
- TALLOC_CTX *mem_ctx,
- struct tdgram_context **dgram,
- const char *location)
+struct tevent_req * tstream_inet_tcp_connect_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ const struct tsocket_address *local,
+ const struct tsocket_address *remote)
{
struct tsocket_address_bsd *lbsda =
talloc_get_type_abort(local->private_data,
struct tsocket_address_bsd);
- int ret;
+ struct tevent_req *req;
+ int sys_errno = 0;
switch (lbsda->u.sa.sa_family) {
case AF_INET:
break;
#endif
default:
- errno = EINVAL;
- return -1;
+ sys_errno = EINVAL;
+ break;
}
- ret = tdgram_bsd_dgram_socket(local, remote, mem_ctx, dgram, location);
+ req = tstream_bsd_connect_send(mem_ctx, ev, sys_errno, local, remote);
- return ret;
+ return req;
+}
+
+int _tstream_inet_tcp_connect_recv(struct tevent_req *req,
+ int *perrno,
+ TALLOC_CTX *mem_ctx,
+ struct tstream_context **stream,
+ const char *location)
+{
+ return tstream_bsd_connect_recv(req, perrno, mem_ctx, stream, location);
}
-int _tdgram_unix_dgram_socket(const struct tsocket_address *local,
- const struct tsocket_address *remote,
- TALLOC_CTX *mem_ctx,
- struct tdgram_context **dgram,
- const char *location)
+struct tevent_req * tstream_unix_connect_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ const struct tsocket_address *local,
+ const struct tsocket_address *remote)
{
struct tsocket_address_bsd *lbsda =
talloc_get_type_abort(local->private_data,
struct tsocket_address_bsd);
- int ret;
+ struct tevent_req *req;
+ int sys_errno = 0;
switch (lbsda->u.sa.sa_family) {
case AF_UNIX:
break;
default:
- errno = EINVAL;
+ sys_errno = EINVAL;
+ break;
+ }
+
+ req = tstream_bsd_connect_send(mem_ctx, ev, sys_errno, local, remote);
+
+ return req;
+}
+
+int _tstream_unix_connect_recv(struct tevent_req *req,
+ int *perrno,
+ TALLOC_CTX *mem_ctx,
+ struct tstream_context **stream,
+ const char *location)
+{
+ return tstream_bsd_connect_recv(req, perrno, mem_ctx, stream, location);
+}
+
+int _tstream_unix_socketpair(TALLOC_CTX *mem_ctx1,
+ struct tstream_context **_stream1,
+ TALLOC_CTX *mem_ctx2,
+ struct tstream_context **_stream2,
+ const char *location)
+{
+ int ret;
+ int fds[2];
+ int fd1;
+ int fd2;
+ struct tstream_context *stream1 = NULL;
+ struct tstream_context *stream2 = NULL;
+
+ ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fds);
+ if (ret == -1) {
+ return -1;
+ }
+ fd1 = fds[0];
+ fd2 = fds[1];
+
+ fd1 = tsocket_bsd_common_prepare_fd(fd1, true);
+ if (fd1 == -1) {
+ int sys_errno = errno;
+ close(fd2);
+ errno = sys_errno;
return -1;
}
- ret = tdgram_bsd_dgram_socket(local, remote, mem_ctx, dgram, location);
+ fd2 = tsocket_bsd_common_prepare_fd(fd2, true);
+ if (fd2 == -1) {
+ int sys_errno = errno;
+ close(fd1);
+ errno = sys_errno;
+ return -1;
+ }
- return ret;
+ ret = _tstream_bsd_existing_socket(mem_ctx1,
+ fd1,
+ &stream1,
+ location);
+ if (ret == -1) {
+ int sys_errno = errno;
+ close(fd1);
+ close(fd2);
+ errno = sys_errno;
+ return -1;
+ }
+
+ ret = _tstream_bsd_existing_socket(mem_ctx2,
+ fd2,
+ &stream2,
+ location);
+ if (ret == -1) {
+ int sys_errno = errno;
+ talloc_free(stream1);
+ close(fd2);
+ errno = sys_errno;
+ return -1;
+ }
+
+ *_stream1 = stream1;
+ *_stream2 = stream2;
+ return 0;
}