summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorJelmer Vernooij <jelmer@samba.org>2009-03-20 01:30:36 +0100
committerJelmer Vernooij <jelmer@samba.org>2009-03-20 01:30:36 +0100
commit5fe2b28f45289dc5578cdd536600f0d30a14d820 (patch)
tree4bdf36d0d4d8bdddcb3d618b4b01839370ed57c3 /lib
parentec9aeeab00584f4d3dfe9afb83dc1a77b8463b81 (diff)
parent3a4638db0351368d3b148bf547546f28fa0b1479 (diff)
downloadsamba-5fe2b28f45289dc5578cdd536600f0d30a14d820.tar.gz
samba-5fe2b28f45289dc5578cdd536600f0d30a14d820.tar.bz2
samba-5fe2b28f45289dc5578cdd536600f0d30a14d820.zip
Merge branch 'master' of git://git.samba.org/samba into minschema
Diffstat (limited to 'lib')
-rw-r--r--lib/async_req/async_req.c42
-rw-r--r--lib/async_req/async_req.h9
-rw-r--r--lib/async_req/async_sock.c64
-rw-r--r--lib/async_req/async_sock.h3
-rw-r--r--lib/replace/libreplace_network.m418
-rw-r--r--lib/replace/system/network.h4
-rw-r--r--lib/smbconf/smbconf.c24
-rw-r--r--lib/socket_wrapper/socket_wrapper.c748
-rw-r--r--lib/socket_wrapper/socket_wrapper.h12
-rw-r--r--lib/talloc/configure.ac2
-rw-r--r--lib/talloc/talloc.c57
-rw-r--r--lib/talloc/talloc.h7
-rw-r--r--lib/tdr/TODO1
-rw-r--r--lib/tdr/config.mk9
-rw-r--r--lib/tdr/tdr.c397
-rw-r--r--lib/tdr/tdr.h67
-rw-r--r--lib/tdr/testsuite.c185
-rw-r--r--lib/tevent/configure.ac2
-rw-r--r--lib/tevent/libtevent.m43
-rw-r--r--lib/tevent/tevent.c259
-rw-r--r--lib/tevent/tevent.h192
-rw-r--r--lib/tevent/tevent_epoll.c64
-rw-r--r--lib/tevent/tevent_immediate.c139
-rw-r--r--lib/tevent/tevent_internal.h152
-rw-r--r--lib/tevent/tevent_queue.c99
-rw-r--r--lib/tevent/tevent_req.c125
-rw-r--r--lib/tevent/tevent_select.c62
-rw-r--r--lib/tevent/tevent_standard.c71
-rw-r--r--lib/tsocket/config.mk17
-rw-r--r--lib/tsocket/tsocket.c231
-rw-r--r--lib/tsocket/tsocket.h220
-rw-r--r--lib/tsocket/tsocket_bsd.c1126
-rw-r--r--lib/tsocket/tsocket_connect.c122
-rw-r--r--lib/tsocket/tsocket_guide.txt503
-rw-r--r--lib/tsocket/tsocket_helpers.c177
-rw-r--r--lib/tsocket/tsocket_internal.h157
-rw-r--r--lib/tsocket/tsocket_readv.c222
-rw-r--r--lib/tsocket/tsocket_recvfrom.c164
-rw-r--r--lib/tsocket/tsocket_sendto.c271
-rw-r--r--lib/tsocket/tsocket_writev.c316
-rw-r--r--lib/util/charset/charcnv.c6
-rw-r--r--lib/util/charset/charset.h6
-rw-r--r--lib/util/charset/iconv.c29
-rw-r--r--lib/util/charset/util_unistr.c2
-rw-r--r--lib/util/config.mk9
-rw-r--r--lib/util/fault.m41
-rw-r--r--lib/util/util.c15
-rw-r--r--lib/util/util.h7
48 files changed, 5747 insertions, 671 deletions
diff --git a/lib/async_req/async_req.c b/lib/async_req/async_req.c
index 054c9f97cc..4dfe809738 100644
--- a/lib/async_req/async_req.c
+++ b/lib/async_req/async_req.c
@@ -194,48 +194,6 @@ bool async_req_is_error(struct async_req *req, enum async_req_state *state,
return true;
}
-static void async_req_timedout(struct tevent_context *ev,
- struct tevent_timer *te,
- struct timeval now,
- void *priv)
-{
- struct async_req *req = talloc_get_type_abort(priv, struct async_req);
- TALLOC_FREE(te);
- async_req_finish(req, ASYNC_REQ_TIMED_OUT);
-}
-
-bool async_req_set_timeout(struct async_req *req, struct tevent_context *ev,
- struct timeval to)
-{
- return (tevent_add_timer(
- ev, req,
- tevent_timeval_current_ofs(to.tv_sec, to.tv_usec),
- async_req_timedout, req)
- != NULL);
-}
-
-struct async_req *async_wait_send(TALLOC_CTX *mem_ctx,
- struct tevent_context *ev,
- struct timeval to)
-{
- struct async_req *result;
-
- result = async_req_new(mem_ctx);
- if (result == NULL) {
- return result;
- }
- if (!async_req_set_timeout(result, ev, to)) {
- TALLOC_FREE(result);
- return NULL;
- }
- return result;
-}
-
-bool async_wait_recv(struct async_req *req)
-{
- return true;
-}
-
struct async_queue_entry {
struct async_queue_entry *prev, *next;
struct async_req_queue *queue;
diff --git a/lib/async_req/async_req.h b/lib/async_req/async_req.h
index fc849880cd..fdec1b708e 100644
--- a/lib/async_req/async_req.h
+++ b/lib/async_req/async_req.h
@@ -139,15 +139,6 @@ bool async_post_error(struct async_req *req, struct tevent_context *ev,
bool async_req_is_error(struct async_req *req, enum async_req_state *state,
uint64_t *error);
-bool async_req_set_timeout(struct async_req *req, struct tevent_context *ev,
- struct timeval to);
-
-struct async_req *async_wait_send(TALLOC_CTX *mem_ctx,
- struct tevent_context *ev,
- struct timeval to);
-
-bool async_wait_recv(struct async_req *req);
-
struct async_req_queue;
struct async_req_queue *async_req_queue_init(TALLOC_CTX *mem_ctx);
diff --git a/lib/async_req/async_sock.c b/lib/async_req/async_sock.c
index 1f48697f26..77df406044 100644
--- a/lib/async_req/async_sock.c
+++ b/lib/async_req/async_sock.c
@@ -123,8 +123,8 @@ static void async_send_handler(struct tevent_context *ev,
{
struct tevent_req *req = talloc_get_type_abort(
private_data, struct tevent_req);
- struct async_send_state *state = talloc_get_type_abort(
- req->private_state, struct async_send_state);
+ struct async_send_state *state =
+ tevent_req_data(req, struct async_send_state);
state->sent = send(state->fd, state->buf, state->len, state->flags);
if (state->sent == -1) {
@@ -136,8 +136,8 @@ static void async_send_handler(struct tevent_context *ev,
ssize_t async_send_recv(struct tevent_req *req, int *perrno)
{
- struct async_send_state *state = talloc_get_type_abort(
- req->private_state, struct async_send_state);
+ struct async_send_state *state =
+ tevent_req_data(req, struct async_send_state);
if (tevent_req_is_unix_error(req, perrno)) {
return -1;
@@ -189,8 +189,8 @@ static void async_recv_handler(struct tevent_context *ev,
{
struct tevent_req *req = talloc_get_type_abort(
private_data, struct tevent_req);
- struct async_recv_state *state = talloc_get_type_abort(
- req->private_state, struct async_recv_state);
+ struct async_recv_state *state =
+ tevent_req_data(req, struct async_recv_state);
state->received = recv(state->fd, state->buf, state->len,
state->flags);
@@ -203,8 +203,8 @@ static void async_recv_handler(struct tevent_context *ev,
ssize_t async_recv_recv(struct tevent_req *req, int *perrno)
{
- struct async_recv_state *state = talloc_get_type_abort(
- req->private_state, struct async_recv_state);
+ struct async_recv_state *state =
+ tevent_req_data(req, struct async_recv_state);
if (tevent_req_is_unix_error(req, perrno)) {
return -1;
@@ -317,8 +317,8 @@ static void async_connect_connected(struct tevent_context *ev,
{
struct tevent_req *req = talloc_get_type_abort(
priv, struct tevent_req);
- struct async_connect_state *state = talloc_get_type_abort(
- req->private_state, struct async_connect_state);
+ struct async_connect_state *state =
+ tevent_req_data(req, struct async_connect_state);
TALLOC_FREE(fde);
@@ -352,8 +352,8 @@ static void async_connect_connected(struct tevent_context *ev,
int async_connect_recv(struct tevent_req *req, int *perrno)
{
- struct async_connect_state *state = talloc_get_type_abort(
- req->private_state, struct async_connect_state);
+ struct async_connect_state *state =
+ tevent_req_data(req, struct async_connect_state);
int err;
fcntl(state->fd, F_SETFL, state->old_sockflags);
@@ -379,15 +379,16 @@ struct writev_state {
size_t total_size;
};
+static void writev_trigger(struct tevent_req *req, void *private_data);
static void writev_handler(struct tevent_context *ev, struct tevent_fd *fde,
uint16_t flags, void *private_data);
struct tevent_req *writev_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
- int fd, struct iovec *iov, int count)
+ struct tevent_queue *queue, int fd,
+ struct iovec *iov, int count)
{
struct tevent_req *result;
struct writev_state *state;
- struct tevent_fd *fde;
result = tevent_req_create(mem_ctx, &state, struct writev_state);
if (result == NULL) {
@@ -403,25 +404,34 @@ struct tevent_req *writev_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
goto fail;
}
- fde = tevent_add_fd(ev, state, fd, TEVENT_FD_WRITE, writev_handler,
- result);
- if (fde == NULL) {
+ if (!tevent_queue_add(queue, ev, result, writev_trigger, NULL)) {
goto fail;
}
return result;
-
fail:
TALLOC_FREE(result);
return NULL;
}
+static void writev_trigger(struct tevent_req *req, void *private_data)
+{
+ struct writev_state *state = tevent_req_data(req, struct writev_state);
+ struct tevent_fd *fde;
+
+ fde = tevent_add_fd(state->ev, state, state->fd, TEVENT_FD_WRITE,
+ writev_handler, req);
+ if (fde == NULL) {
+ tevent_req_error(req, ENOMEM);
+ }
+}
+
static void writev_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 writev_state *state = talloc_get_type_abort(
- req->private_state, struct writev_state);
+ struct writev_state *state =
+ tevent_req_data(req, struct writev_state);
size_t to_write, written;
int i;
@@ -459,7 +469,7 @@ static void writev_handler(struct tevent_context *ev, struct tevent_fd *fde,
state->iov[0].iov_len -= written;
break;
}
- written = state->iov[0].iov_len;
+ written -= state->iov[0].iov_len;
state->iov += 1;
state->count -= 1;
}
@@ -467,8 +477,8 @@ static void writev_handler(struct tevent_context *ev, struct tevent_fd *fde,
ssize_t writev_recv(struct tevent_req *req, int *perrno)
{
- struct writev_state *state = talloc_get_type_abort(
- req->private_state, struct writev_state);
+ struct writev_state *state =
+ tevent_req_data(req, struct writev_state);
if (tevent_req_is_unix_error(req, perrno)) {
return -1;
@@ -531,8 +541,8 @@ static void read_packet_handler(struct tevent_context *ev,
{
struct tevent_req *req = talloc_get_type_abort(
private_data, struct tevent_req);
- struct read_packet_state *state = talloc_get_type_abort(
- req->private_state, struct read_packet_state);
+ struct read_packet_state *state =
+ tevent_req_data(req, struct read_packet_state);
size_t total = talloc_get_size(state->buf);
ssize_t nread, more;
uint8_t *tmp;
@@ -584,8 +594,8 @@ static void read_packet_handler(struct tevent_context *ev,
ssize_t read_packet_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
uint8_t **pbuf, int *perrno)
{
- struct read_packet_state *state = talloc_get_type_abort(
- req->private_state, struct read_packet_state);
+ struct read_packet_state *state =
+ tevent_req_data(req, struct read_packet_state);
if (tevent_req_is_unix_error(req, perrno)) {
return -1;
diff --git a/lib/async_req/async_sock.h b/lib/async_req/async_sock.h
index e001709d27..c5d9400eb6 100644
--- a/lib/async_req/async_sock.h
+++ b/lib/async_req/async_sock.h
@@ -43,7 +43,8 @@ struct tevent_req *async_connect_send(TALLOC_CTX *mem_ctx,
int async_connect_recv(struct tevent_req *req, int *perrno);
struct tevent_req *writev_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
- int fd, struct iovec *iov, int count);
+ struct tevent_queue *queue, int fd,
+ struct iovec *iov, int count);
ssize_t writev_recv(struct tevent_req *req, int *perrno);
struct tevent_req *read_packet_send(TALLOC_CTX *mem_ctx,
diff --git a/lib/replace/libreplace_network.m4 b/lib/replace/libreplace_network.m4
index 78fb1abaf0..3bac72d136 100644
--- a/lib/replace/libreplace_network.m4
+++ b/lib/replace/libreplace_network.m4
@@ -8,14 +8,18 @@ LIBREPLACE_NETWORK_LIBS=""
AC_CHECK_HEADERS(sys/socket.h netinet/in.h netdb.h arpa/inet.h)
AC_CHECK_HEADERS(netinet/in_systm.h)
-AC_CHECK_HEADERS([netinet/ip.h], [], [],[#ifdef HAVE_NETINET_IN_H
-#include <netinet/in.h>
-#endif
-#ifdef HAVE_NETINET_IN_SYSTM_H
-#include <netinet/in_systm.h>
-#endif])
+AC_CHECK_HEADERS([netinet/ip.h], [], [],[
+ #include <sys/types.h>
+ #ifdef HAVE_NETINET_IN_H
+ #include <netinet/in.h>
+ #endif
+ #ifdef HAVE_NETINET_IN_SYSTM_H
+ #include <netinet/in_systm.h>
+ #endif
+])
AC_CHECK_HEADERS(netinet/tcp.h netinet/in_ip.h)
AC_CHECK_HEADERS(sys/sockio.h sys/un.h)
+AC_CHECK_HEADERS(sys/uio.h)
dnl we need to check that net/if.h really can be used, to cope with hpux
dnl where including it always fails
@@ -241,7 +245,7 @@ AC_CHECK_MEMBERS([struct sockaddr.sa_len],
dnl test for getifaddrs and freeifaddrs
AC_CACHE_CHECK([for getifaddrs and freeifaddrs],libreplace_cv_HAVE_GETIFADDRS,[
-AC_TRY_COMPILE([
+AC_TRY_LINK([
#include <sys/types.h>
#if STDC_HEADERS
#include <stdlib.h>
diff --git a/lib/replace/system/network.h b/lib/replace/system/network.h
index f135d175d4..6add99c0db 100644
--- a/lib/replace/system/network.h
+++ b/lib/replace/system/network.h
@@ -83,6 +83,10 @@
#include <sys/ioctl.h>
#endif
+#ifdef HAVE_SYS_UIO_H
+#include <sys/uio.h>
+#endif
+
#ifdef HAVE_STROPTS_H
#include <stropts.h>
#endif
diff --git a/lib/smbconf/smbconf.c b/lib/smbconf/smbconf.c
index f25ccae0d4..80fe9aac37 100644
--- a/lib/smbconf/smbconf.c
+++ b/lib/smbconf/smbconf.c
@@ -226,10 +226,6 @@ WERROR smbconf_set_parameter(struct smbconf_ctx *ctx,
const char *param,
const char *valstr)
{
- if (!smbconf_share_exists(ctx, service)) {
- return WERR_NO_SUCH_SERVICE;
- }
-
return ctx->ops->set_parameter(ctx, service, param, valstr);
}
@@ -265,10 +261,6 @@ WERROR smbconf_get_parameter(struct smbconf_ctx *ctx,
return WERR_INVALID_PARAM;
}
- if (!smbconf_share_exists(ctx, service)) {
- return WERR_NO_SUCH_SERVICE;
- }
-
return ctx->ops->get_parameter(ctx, mem_ctx, service, param, valstr);
}
@@ -299,10 +291,6 @@ WERROR smbconf_get_global_parameter(struct smbconf_ctx *ctx,
WERROR smbconf_delete_parameter(struct smbconf_ctx *ctx,
const char *service, const char *param)
{
- if (!smbconf_share_exists(ctx, service)) {
- return WERR_NO_SUCH_SERVICE;
- }
-
return ctx->ops->delete_parameter(ctx, service, param);
}
@@ -329,10 +317,6 @@ WERROR smbconf_get_includes(struct smbconf_ctx *ctx,
const char *service,
uint32_t *num_includes, char ***includes)
{
- if (!smbconf_share_exists(ctx, service)) {
- return WERR_NO_SUCH_SERVICE;
- }
-
return ctx->ops->get_includes(ctx, mem_ctx, service, num_includes,
includes);
}
@@ -356,10 +340,6 @@ WERROR smbconf_set_includes(struct smbconf_ctx *ctx,
const char *service,
uint32_t num_includes, const char **includes)
{
- if (!smbconf_share_exists(ctx, service)) {
- return WERR_NO_SUCH_SERVICE;
- }
-
return ctx->ops->set_includes(ctx, service, num_includes, includes);
}
@@ -381,10 +361,6 @@ WERROR smbconf_set_global_includes(struct smbconf_ctx *ctx,
WERROR smbconf_delete_includes(struct smbconf_ctx *ctx, const char *service)
{
- if (!smbconf_share_exists(ctx, service)) {
- return WERR_NO_SUCH_SERVICE;
- }
-
return ctx->ops->delete_includes(ctx, service);
}
diff --git a/lib/socket_wrapper/socket_wrapper.c b/lib/socket_wrapper/socket_wrapper.c
index 1e3927705b..44082e78a1 100644
--- a/lib/socket_wrapper/socket_wrapper.c
+++ b/lib/socket_wrapper/socket_wrapper.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) Jelmer Vernooij 2005,2008 <jelmer@samba.org>
- * Copyright (C) Stefan Metzmacher 2006 <metze@samba.org>
+ * Copyright (C) Stefan Metzmacher 2006-2009 <metze@samba.org>
*
* All rights reserved.
*
@@ -121,6 +121,8 @@
#define real_ioctl ioctl
#define real_recv recv
#define real_send send
+#define real_readv readv
+#define real_writev writev
#define real_socket socket
#define real_close close
#endif
@@ -145,7 +147,29 @@
#define MAX_WRAPPED_INTERFACES 16
-#define SW_IPV6_ADDRESS 1
+#ifdef HAVE_IPV6
+/*
+ * FD00::5357:5FXX
+ */
+static const struct in6_addr *swrap_ipv6(void)
+{
+ static struct in6_addr v;
+ static int initialized;
+ int ret;
+
+ if (initialized) {
+ return &v;
+ }
+ initialized = 1;
+
+ ret = inet_pton(AF_INET6, "FD00::5357:5F00", &v);
+ if (ret <= 0) {
+ abort();
+ }
+
+ return &v;
+}
+#endif
static struct sockaddr *sockaddr_dup(const void *data, socklen_t len)
{
@@ -193,6 +217,7 @@ struct socket_info
int bound;
int bcast;
int is_server;
+ int connected;
char *path;
char *tmp_path;
@@ -295,7 +320,8 @@ static int convert_un_in(const struct sockaddr_un *un, struct sockaddr *in, sock
memset(in2, 0, sizeof(*in2));
in2->sin6_family = AF_INET6;
- in2->sin6_addr.s6_addr[0] = SW_IPV6_ADDRESS;
+ in2->sin6_addr = *swrap_ipv6();
+ in2->sin6_addr.s6_addr[15] = iface;
in2->sin6_port = htons(prt);
*len = sizeof(*in2);
@@ -367,6 +393,7 @@ static int convert_in_un_remote(struct socket_info *si, const struct sockaddr *i
case AF_INET6: {
const struct sockaddr_in6 *in =
(const struct sockaddr_in6 *)inaddr;
+ struct in6_addr cmp;
switch (si->type) {
case SOCK_STREAM:
@@ -380,8 +407,16 @@ static int convert_in_un_remote(struct socket_info *si, const struct sockaddr *i
/* XXX no multicast/broadcast */
prt = ntohs(in->sin6_port);
- iface = SW_IPV6_ADDRESS;
-
+
+ cmp = in->sin6_addr;
+ cmp.s6_addr[15] = 0;
+ if (IN6_ARE_ADDR_EQUAL(swrap_ipv6(), &cmp)) {
+ iface = in->sin6_addr.s6_addr[15];
+ } else {
+ errno = ENETUNREACH;
+ return -1;
+ }
+
break;
}
#endif
@@ -474,6 +509,7 @@ static int convert_in_un_alloc(struct socket_info *si, const struct sockaddr *in
case AF_INET6: {
const struct sockaddr_in6 *in =
(const struct sockaddr_in6 *)inaddr;
+ struct in6_addr cmp;
switch (si->type) {
case SOCK_STREAM:
@@ -487,13 +523,23 @@ static int convert_in_un_alloc(struct socket_info *si, const struct sockaddr *in
/* XXX no multicast/broadcast */
prt = ntohs(in->sin6_port);
- iface = SW_IPV6_ADDRESS;
-
+
+ cmp = in->sin6_addr;
+ cmp.s6_addr[15] = 0;
+ if (IN6_IS_ADDR_UNSPECIFIED(&in->sin6_addr)) {
+ iface = socket_wrapper_default_iface();
+ } else if (IN6_ARE_ADDR_EQUAL(swrap_ipv6(), &cmp)) {
+ iface = in->sin6_addr.s6_addr[15];
+ } else {
+ errno = EADDRNOTAVAIL;
+ return -1;
+ }
+
break;
}
#endif
default:
- errno = ENETUNREACH;
+ errno = EADDRNOTAVAIL;
return -1;
}
@@ -636,69 +682,93 @@ struct swrap_file_hdr {
};
#define SWRAP_FILE_HDR_SIZE 24
-struct swrap_packet {
+struct swrap_packet_frame {
+ uint32_t seconds;
+ uint32_t micro_seconds;
+ uint32_t recorded_length;
+ uint32_t full_length;
+};
+#define SWRAP_PACKET_FRAME_SIZE 16
+
+union swrap_packet_ip {
+ struct {
+ uint8_t ver_hdrlen;
+ uint8_t tos;
+ uint16_t packet_length;
+ uint16_t identification;
+ uint8_t flags;
+ uint8_t fragment;
+ uint8_t ttl;
+ uint8_t protocol;
+ uint16_t hdr_checksum;
+ uint32_t src_addr;
+ uint32_t dest_addr;
+ } v4;
+#define SWRAP_PACKET_IP_V4_SIZE 20
struct {
- uint32_t seconds;
- uint32_t micro_seconds;
- uint32_t recorded_length;
- uint32_t full_length;
- } frame;
-#define SWRAP_PACKET__FRAME_SIZE 16
+ uint8_t ver_prio;
+ uint8_t flow_label_high;
+ uint16_t flow_label_low;
+ uint16_t payload_length;
+ uint8_t next_header;
+ uint8_t hop_limit;
+ uint8_t src_addr[16];
+ uint8_t dest_addr[16];
+ } v6;
+#define SWRAP_PACKET_IP_V6_SIZE 40
+};
+#define SWRAP_PACKET_IP_SIZE 40
+union swrap_packet_payload {
+ struct {
+ uint16_t source_port;
+ uint16_t dest_port;
+ uint32_t seq_num;
+ uint32_t ack_num;
+ uint8_t hdr_length;
+ uint8_t control;
+ uint16_t window;
+ uint16_t checksum;
+ uint16_t urg;
+ } tcp;
+#define SWRAP_PACKET_PAYLOAD_TCP_SIZE 20
+ struct {
+ uint16_t source_port;
+ uint16_t dest_port;
+ uint16_t length;
+ uint16_t checksum;
+ } udp;
+#define SWRAP_PACKET_PAYLOAD_UDP_SIZE 8
struct {
- struct {
- uint8_t ver_hdrlen;
- uint8_t tos;
- uint16_t packet_length;
- uint16_t identification;
- uint8_t flags;
- uint8_t fragment;
- uint8_t ttl;
- uint8_t protocol;
- uint16_t hdr_checksum;
- uint32_t src_addr;
- uint32_t dest_addr;
- } hdr;
-#define SWRAP_PACKET__IP_HDR_SIZE 20
-
- union {
- struct {
- uint16_t source_port;
- uint16_t dest_port;
- uint32_t seq_num;
- uint32_t ack_num;
- uint8_t hdr_length;
- uint8_t control;
- uint16_t window;
- uint16_t checksum;
- uint16_t urg;
- } tcp;
-#define SWRAP_PACKET__IP_P_TCP_SIZE 20
- struct {
- uint16_t source_port;
- uint16_t dest_port;
- uint16_t length;
- uint16_t checksum;
- } udp;
-#define SWRAP_PACKET__IP_P_UDP_SIZE 8
- struct {
- uint8_t type;
- uint8_t code;
- uint16_t checksum;
- uint32_t unused;
- } icmp;
-#define SWRAP_PACKET__IP_P_ICMP_SIZE 8
- } p;
- } ip;
+ uint8_t type;
+ uint8_t code;
+ uint16_t checksum;
+ uint32_t unused;
+ } icmp4;
+#define SWRAP_PACKET_PAYLOAD_ICMP4_SIZE 8
+ struct {
+ uint8_t type;
+ uint8_t code;
+ uint16_t checksum;
+ uint32_t unused;
+ } icmp6;
+#define SWRAP_PACKET_PAYLOAD_ICMP6_SIZE 8
};
-#define SWRAP_PACKET_SIZE 56
+#define SWRAP_PACKET_PAYLOAD_SIZE 20
+
+#define SWRAP_PACKET_MIN_ALLOC \
+ (SWRAP_PACKET_FRAME_SIZE + \
+ SWRAP_PACKET_IP_SIZE + \
+ SWRAP_PACKET_PAYLOAD_SIZE)
static const char *socket_wrapper_pcap_file(void)
{
static int initialized = 0;
static const char *s = NULL;
- static const struct swrap_file_hdr h = { 0, };
- static const struct swrap_packet p = { { 0, }, { { 0, }, { { 0, } } } };
+ static const struct swrap_file_hdr h;
+ static const struct swrap_packet_frame f;
+ static const union swrap_packet_ip i;
+ static const union swrap_packet_payload p;
if (initialized == 1) {
return s;
@@ -715,22 +785,31 @@ static const char *socket_wrapper_pcap_file(void)
if (sizeof(h) != SWRAP_FILE_HDR_SIZE) {
return NULL;
}
- if (sizeof(p) != SWRAP_PACKET_SIZE) {
+ if (sizeof(f) != SWRAP_PACKET_FRAME_SIZE) {
+ return NULL;
+ }
+ if (sizeof(i) != SWRAP_PACKET_IP_SIZE) {
return NULL;
}
- if (sizeof(p.frame) != SWRAP_PACKET__FRAME_SIZE) {
+ if (sizeof(i.v4) != SWRAP_PACKET_IP_V4_SIZE) {
return NULL;
}
- if (sizeof(p.ip.hdr) != SWRAP_PACKET__IP_HDR_SIZE) {
+ if (sizeof(i.v6) != SWRAP_PACKET_IP_V6_SIZE) {
return NULL;
}
- if (sizeof(p.ip.p.tcp) != SWRAP_PACKET__IP_P_TCP_SIZE) {
+ if (sizeof(p) != SWRAP_PACKET_PAYLOAD_SIZE) {
return NULL;
}
- if (sizeof(p.ip.p.udp) != SWRAP_PACKET__IP_P_UDP_SIZE) {
+ if (sizeof(p.tcp) != SWRAP_PACKET_PAYLOAD_TCP_SIZE) {
return NULL;
}
- if (sizeof(p.ip.p.icmp) != SWRAP_PACKET__IP_P_ICMP_SIZE) {
+ if (sizeof(p.udp) != SWRAP_PACKET_PAYLOAD_UDP_SIZE) {
+ return NULL;
+ }
+ if (sizeof(p.icmp4) != SWRAP_PACKET_PAYLOAD_ICMP4_SIZE) {
+ return NULL;
+ }
+ if (sizeof(p.icmp6) != SWRAP_PACKET_PAYLOAD_ICMP6_SIZE) {
return NULL;
}
@@ -744,41 +823,72 @@ static const char *socket_wrapper_pcap_file(void)
return s;
}
-static struct swrap_packet *swrap_packet_init(struct timeval *tval,
- const struct sockaddr_in *src_addr,
- const struct sockaddr_in *dest_addr,
- int socket_type,
- const unsigned char *payload,
- size_t payload_len,
- unsigned long tcp_seqno,
- unsigned long tcp_ack,
- unsigned char tcp_ctl,
- int unreachable,
- size_t *_packet_len)
+static uint8_t *swrap_packet_init(struct timeval *tval,
+ const struct sockaddr *src,
+ const struct sockaddr *dest,
+ int socket_type,
+ const uint8_t *payload,
+ size_t payload_len,
+ unsigned long tcp_seqno,
+ unsigned long tcp_ack,
+ unsigned char tcp_ctl,
+ int unreachable,
+ size_t *_packet_len)
{
- struct swrap_packet *ret;
- struct swrap_packet *packet;
+ uint8_t *base;
+ uint8_t *buf;
+ struct swrap_packet_frame *frame;
+ union swrap_packet_ip *ip;
+ union swrap_packet_payload *pay;
size_t packet_len;
size_t alloc_len;
- size_t nonwire_len = sizeof(packet->frame);
+ size_t nonwire_len = sizeof(*frame);
size_t wire_hdr_len = 0;
size_t wire_len = 0;
+ size_t ip_hdr_len = 0;
size_t icmp_hdr_len = 0;
size_t icmp_truncate_len = 0;
- unsigned char protocol = 0, icmp_protocol = 0;
- unsigned short src_port = src_addr->sin_port;
- unsigned short dest_port = dest_addr->sin_port;
+ uint8_t protocol = 0, icmp_protocol = 0;
+ const struct sockaddr_in *src_in = NULL;
+ const struct sockaddr_in *dest_in = NULL;
+#ifdef HAVE_IPV6
+ const struct sockaddr_in6 *src_in6 = NULL;
+ const struct sockaddr_in6 *dest_in6 = NULL;
+#endif
+ uint16_t src_port;
+ uint16_t dest_port;
+
+ switch (src->sa_family) {
+ case AF_INET:
+ src_in = (const struct sockaddr_in *)src;
+ dest_in = (const struct sockaddr_in *)dest;
+ src_port = src_in->sin_port;
+ dest_port = dest_in->sin_port;
+ ip_hdr_len = sizeof(ip->v4);
+ break;
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ src_in6 = (const struct sockaddr_in6 *)src;
+ dest_in6 = (const struct sockaddr_in6 *)dest;
+ src_port = src_in6->sin6_port;
+ dest_port = dest_in6->sin6_port;
+ ip_hdr_len = sizeof(ip->v6);
+ break;
+#endif
+ default:
+ return NULL;
+ }
switch (socket_type) {
case SOCK_STREAM:
protocol = 0x06; /* TCP */
- wire_hdr_len = sizeof(packet->ip.hdr) + sizeof(packet->ip.p.tcp);
+ wire_hdr_len = ip_hdr_len + sizeof(pay->tcp);
wire_len = wire_hdr_len + payload_len;
break;
case SOCK_DGRAM:
protocol = 0x11; /* UDP */
- wire_hdr_len = sizeof(packet->ip.hdr) + sizeof(packet->ip.p.udp);
+ wire_hdr_len = ip_hdr_len + sizeof(pay->udp);
wire_len = wire_hdr_len + payload_len;
break;
@@ -788,98 +898,160 @@ static struct swrap_packet *swrap_packet_init(struct timeval *tval,
if (unreachable) {
icmp_protocol = protocol;
- protocol = 0x01; /* ICMP */
+ switch (src->sa_family) {
+ case AF_INET:
+ protocol = 0x01; /* ICMPv4 */
+ icmp_hdr_len = ip_hdr_len + sizeof(pay->icmp4);
+ break;
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ protocol = 0x3A; /* ICMPv6 */
+ icmp_hdr_len = ip_hdr_len + sizeof(pay->icmp6);
+ break;
+#endif
+ }
if (wire_len > 64 ) {
icmp_truncate_len = wire_len - 64;
}
- icmp_hdr_len = sizeof(packet->ip.hdr) + sizeof(packet->ip.p.icmp);
wire_hdr_len += icmp_hdr_len;
wire_len += icmp_hdr_len;
}
packet_len = nonwire_len + wire_len;
alloc_len = packet_len;
- if (alloc_len < sizeof(struct swrap_packet)) {
- alloc_len = sizeof(struct swrap_packet);
- }
- ret = (struct swrap_packet *)malloc(alloc_len);
- if (!ret) return NULL;
-
- packet = ret;
-
- packet->frame.seconds = tval->tv_sec;
- packet->frame.micro_seconds = tval->tv_usec;
- packet->frame.recorded_length = wire_len - icmp_truncate_len;
- packet->frame.full_length = wire_len - icmp_truncate_len;
-
- packet->ip.hdr.ver_hdrlen = 0x45; /* version 4 and 5 * 32 bit words */
- packet->ip.hdr.tos = 0x00;
- packet->ip.hdr.packet_length = htons(wire_len - icmp_truncate_len);
- packet->ip.hdr.identification = htons(0xFFFF);
- packet->ip.hdr.flags = 0x40; /* BIT 1 set - means don't fraqment */
- packet->ip.hdr.fragment = htons(0x0000);
- packet->ip.hdr.ttl = 0xFF;
- packet->ip.hdr.protocol = protocol;
- packet->ip.hdr.hdr_checksum = htons(0x0000);
- packet->ip.hdr.src_addr = src_addr->sin_addr.s_addr;
- packet->ip.hdr.dest_addr = dest_addr->sin_addr.s_addr;
+ if (alloc_len < SWRAP_PACKET_MIN_ALLOC) {
+ alloc_len = SWRAP_PACKET_MIN_ALLOC;
+ }
+
+ base = (uint8_t *)malloc(alloc_len);
+ if (!base) return NULL;
+
+ buf = base;
+
+ frame = (struct swrap_packet_frame *)buf;
+ frame->seconds = tval->tv_sec;
+ frame->micro_seconds = tval->tv_usec;
+ frame->recorded_length = wire_len - icmp_truncate_len;
+ frame->full_length = wire_len - icmp_truncate_len;
+ buf += SWRAP_PACKET_FRAME_SIZE;
+
+ ip = (union swrap_packet_ip *)buf;
+ switch (src->sa_family) {
+ case AF_INET:
+ ip->v4.ver_hdrlen = 0x45; /* version 4 and 5 * 32 bit words */
+ ip->v4.tos = 0x00;
+ ip->v4.packet_length = htons(wire_len - icmp_truncate_len);
+ ip->v4.identification = htons(0xFFFF);
+ ip->v4.flags = 0x40; /* BIT 1 set - means don't fraqment */
+ ip->v4.fragment = htons(0x0000);
+ ip->v4.ttl = 0xFF;
+ ip->v4.protocol = protocol;
+ ip->v4.hdr_checksum = htons(0x0000);
+ ip->v4.src_addr = src_in->sin_addr.s_addr;
+ ip->v4.dest_addr = dest_in->sin_addr.s_addr;
+ buf += SWRAP_PACKET_IP_V4_SIZE;
+ break;
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ ip->v6.ver_prio = 0x60; /* version 4 and 5 * 32 bit words */
+ ip->v6.flow_label_high = 0x00;
+ ip->v6.flow_label_low = 0x0000;
+ ip->v6.payload_length = htons(wire_len - icmp_truncate_len);//TODO
+ ip->v6.next_header = protocol;
+ memcpy(ip->v6.src_addr, src_in6->sin6_addr.s6_addr, 16);
+ memcpy(ip->v6.dest_addr, dest_in6->sin6_addr.s6_addr, 16);
+ buf += SWRAP_PACKET_IP_V6_SIZE;
+ break;
+#endif
+ }
if (unreachable) {
- packet->ip.p.icmp.type = 0x03; /* destination unreachable */
- packet->ip.p.icmp.code = 0x01; /* host unreachable */
- packet->ip.p.icmp.checksum = htons(0x0000);
- packet->ip.p.icmp.unused = htonl(0x00000000);
-
- /* set the ip header in the ICMP payload */
- packet = (struct swrap_packet *)(((unsigned char *)ret) + icmp_hdr_len);
- packet->ip.hdr.ver_hdrlen = 0x45; /* version 4 and 5 * 32 bit words */
- packet->ip.hdr.tos = 0x00;
- packet->ip.hdr.packet_length = htons(wire_len - icmp_hdr_len);
- packet->ip.hdr.identification = htons(0xFFFF);
- packet->ip.hdr.flags = 0x40; /* BIT 1 set - means don't fraqment */
- packet->ip.hdr.fragment = htons(0x0000);
- packet->ip.hdr.ttl = 0xFF;
- packet->ip.hdr.protocol = icmp_protocol;
- packet->ip.hdr.hdr_checksum = htons(0x0000);
- packet->ip.hdr.src_addr = dest_addr->sin_addr.s_addr;
- packet->ip.hdr.dest_addr = src_addr->sin_addr.s_addr;
-
- src_port = dest_addr->sin_port;
- dest_port = src_addr->sin_port;
+ pay = (union swrap_packet_payload *)buf;
+ switch (src->sa_family) {
+ case AF_INET:
+ pay->icmp4.type = 0x03; /* destination unreachable */
+ pay->icmp4.code = 0x01; /* host unreachable */
+ pay->icmp4.checksum = htons(0x0000);
+ pay->icmp4.unused = htonl(0x00000000);
+ buf += SWRAP_PACKET_PAYLOAD_ICMP4_SIZE;
+
+ /* set the ip header in the ICMP payload */
+ ip = (union swrap_packet_ip *)buf;
+ ip->v4.ver_hdrlen = 0x45; /* version 4 and 5 * 32 bit words */
+ ip->v4.tos = 0x00;
+ ip->v4.packet_length = htons(wire_len - icmp_hdr_len);
+ ip->v4.identification = htons(0xFFFF);
+ ip->v4.flags = 0x40; /* BIT 1 set - means don't fraqment */
+ ip->v4.fragment = htons(0x0000);
+ ip->v4.ttl = 0xFF;
+ ip->v4.protocol = icmp_protocol;
+ ip->v4.hdr_checksum = htons(0x0000);
+ ip->v4.src_addr = dest_in->sin_addr.s_addr;
+ ip->v4.dest_addr = src_in->sin_addr.s_addr;
+ buf += SWRAP_PACKET_IP_V4_SIZE;
+
+ src_port = dest_in->sin_port;
+ dest_port = src_in->sin_port;
+ break;
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ pay->icmp6.type = 0x01; /* destination unreachable */
+ pay->icmp6.code = 0x03; /* address unreachable */
+ pay->icmp6.checksum = htons(0x0000);
+ pay->icmp6.unused = htonl(0x00000000);
+ buf += SWRAP_PACKET_PAYLOAD_ICMP6_SIZE;
+
+ /* set the ip header in the ICMP payload */
+ ip = (union swrap_packet_ip *)buf;
+ ip->v6.ver_prio = 0x60; /* version 4 and 5 * 32 bit words */
+ ip->v6.flow_label_high = 0x00;
+ ip->v6.flow_label_low = 0x0000;
+ ip->v6.payload_length = htons(wire_len - icmp_truncate_len);//TODO
+ ip->v6.next_header = protocol;
+ memcpy(ip->v6.src_addr, dest_in6->sin6_addr.s6_addr, 16);
+ memcpy(ip->v6.dest_addr, src_in6->sin6_addr.s6_addr, 16);
+ buf += SWRAP_PACKET_IP_V6_SIZE;
+
+ src_port = dest_in6->sin6_port;
+ dest_port = src_in6->sin6_port;
+ break;
+#endif
+ }
}
+ pay = (union swrap_packet_payload *)buf;
+
switch (socket_type) {
case SOCK_STREAM:
- packet->ip.p.tcp.source_port = src_port;
- packet->ip.p.tcp.dest_port = dest_port;
- packet->ip.p.tcp.seq_num = htonl(tcp_seqno);
- packet->ip.p.tcp.ack_num = htonl(tcp_ack);
- packet->ip.p.tcp.hdr_length = 0x50; /* 5 * 32 bit words */
- packet->ip.p.tcp.control = tcp_ctl;
- packet->ip.p.tcp.window = htons(0x7FFF);
- packet->ip.p.tcp.checksum = htons(0x0000);
- packet->ip.p.tcp.urg = htons(0x0000);
+ pay->tcp.source_port = src_port;
+ pay->tcp.dest_port = dest_port;
+ pay->tcp.seq_num = htonl(tcp_seqno);
+ pay->tcp.ack_num = htonl(tcp_ack);
+ pay->tcp.hdr_length = 0x50; /* 5 * 32 bit words */
+ pay->tcp.control = tcp_ctl;
+ pay->tcp.window = htons(0x7FFF);
+ pay->tcp.checksum = htons(0x0000);
+ pay->tcp.urg = htons(0x0000);
+ buf += SWRAP_PACKET_PAYLOAD_TCP_SIZE;
break;
case SOCK_DGRAM:
- packet->ip.p.udp.source_port = src_addr->sin_port;
- packet->ip.p.udp.dest_port = dest_addr->sin_port;
- packet->ip.p.udp.length = htons(8 + payload_len);
- packet->ip.p.udp.checksum = htons(0x0000);
+ pay->udp.source_port = src_port;
+ pay->udp.dest_port = dest_port;
+ pay->udp.length = htons(8 + payload_len);
+ pay->udp.checksum = htons(0x0000);
+ buf += SWRAP_PACKET_PAYLOAD_UDP_SIZE;
break;
}
if (payload && payload_len > 0) {
- unsigned char *p = (unsigned char *)ret;
- p += nonwire_len;
- p += wire_hdr_len;
- memcpy(p, payload, payload_len);
+ memcpy(buf, payload, payload_len);
}
*_packet_len = packet_len - icmp_truncate_len;
- return ret;
+ return base;
}
static int swrap_get_pcap_fd(const char *fname)
@@ -911,14 +1083,14 @@ static int swrap_get_pcap_fd(const char *fname)
return fd;
}
-static struct swrap_packet *swrap_marshall_packet(struct socket_info *si,
- const struct sockaddr *addr,
- enum swrap_packet_type type,
- const void *buf, size_t len,
- size_t *packet_len)
+static uint8_t *swrap_marshall_packet(struct socket_info *si,
+ const struct sockaddr *addr,
+ enum swrap_packet_type type,
+ const void *buf, size_t len,
+ size_t *packet_len)
{
- const struct sockaddr_in *src_addr;
- const struct sockaddr_in *dest_addr;
+ const struct sockaddr *src_addr;
+ const struct sockaddr *dest_addr;
unsigned long tcp_seqno = 0;
unsigned long tcp_ack = 0;
unsigned char tcp_ctl = 0;
@@ -929,6 +1101,8 @@ static struct swrap_packet *swrap_marshall_packet(struct socket_info *si,
switch (si->family) {
case AF_INET:
break;
+ case AF_INET6:
+ break;
default:
return NULL;
}
@@ -937,8 +1111,8 @@ static struct swrap_packet *swrap_marshall_packet(struct socket_info *si,
case SWRAP_CONNECT_SEND:
if (si->type != SOCK_STREAM) return NULL;
- src_addr = (const struct sockaddr_in *)si->myname;
- dest_addr = (const struct sockaddr_in *)addr;
+ src_addr = si->myname;
+ dest_addr = addr;
tcp_seqno = si->io.pck_snd;
tcp_ack = si->io.pck_rcv;
@@ -951,8 +1125,8 @@ static struct swrap_packet *swrap_marshall_packet(struct socket_info *si,
case SWRAP_CONNECT_RECV:
if (si->type != SOCK_STREAM) return NULL;
- dest_addr = (const struct sockaddr_in *)si->myname;
- src_addr = (const struct sockaddr_in *)addr;
+ dest_addr = si->myname;
+ src_addr = addr;
tcp_seqno = si->io.pck_rcv;
tcp_ack = si->io.pck_snd;
@@ -965,8 +1139,8 @@ static struct swrap_packet *swrap_marshall_packet(struct socket_info *si,
case SWRAP_CONNECT_UNREACH:
if (si->type != SOCK_STREAM) return NULL;
- dest_addr = (const struct sockaddr_in *)si->myname;
- src_addr = (const struct sockaddr_in *)addr;
+ dest_addr = si->myname;
+ src_addr = addr;
/* Unreachable: resend the data of SWRAP_CONNECT_SEND */
tcp_seqno = si->io.pck_snd - 1;
@@ -979,8 +1153,8 @@ static struct swrap_packet *swrap_marshall_packet(struct socket_info *si,
case SWRAP_CONNECT_ACK:
if (si->type != SOCK_STREAM) return NULL;
- src_addr = (const struct sockaddr_in *)si->myname;
- dest_addr = (const struct sockaddr_in *)addr;
+ src_addr = si->myname;
+ dest_addr = addr;
tcp_seqno = si->io.pck_snd;
tcp_ack = si->io.pck_rcv;
@@ -991,8 +1165,8 @@ static struct swrap_packet *swrap_marshall_packet(struct socket_info *si,
case SWRAP_ACCEPT_SEND:
if (si->type != SOCK_STREAM) return NULL;
- dest_addr = (const struct sockaddr_in *)si->myname;
- src_addr = (const struct sockaddr_in *)addr;
+ dest_addr = si->myname;
+ src_addr = addr;
tcp_seqno = si->io.pck_rcv;
tcp_ack = si->io.pck_snd;
@@ -1005,8 +1179,8 @@ static struct swrap_packet *swrap_marshall_packet(struct socket_info *si,
case SWRAP_ACCEPT_RECV:
if (si->type != SOCK_STREAM) return NULL;
- src_addr = (const struct sockaddr_in *)si->myname;
- dest_addr = (const struct sockaddr_in *)addr;
+ src_addr = si->myname;
+ dest_addr = addr;
tcp_seqno = si->io.pck_snd;
tcp_ack = si->io.pck_rcv;
@@ -1019,8 +1193,8 @@ static struct swrap_packet *swrap_marshall_packet(struct socket_info *si,
case SWRAP_ACCEPT_ACK:
if (si->type != SOCK_STREAM) return NULL;
- dest_addr = (const struct sockaddr_in *)si->myname;
- src_addr = (const struct sockaddr_in *)addr;
+ dest_addr = si->myname;
+ src_addr = addr;
tcp_seqno = si->io.pck_rcv;
tcp_ack = si->io.pck_snd;
@@ -1029,8 +1203,8 @@ static struct swrap_packet *swrap_marshall_packet(struct socket_info *si,
break;
case SWRAP_SEND:
- src_addr = (const struct sockaddr_in *)si->myname;
- dest_addr = (const struct sockaddr_in *)si->peername;
+ src_addr = si->myname;
+ dest_addr = si->peername;
tcp_seqno = si->io.pck_snd;
tcp_ack = si->io.pck_rcv;
@@ -1041,8 +1215,8 @@ static struct swrap_packet *swrap_marshall_packet(struct socket_info *si,
break;
case SWRAP_SEND_RST:
- dest_addr = (const struct sockaddr_in *)si->myname;
- src_addr = (const struct sockaddr_in *)si->peername;
+ dest_addr = si->myname;
+ src_addr = si->peername;
if (si->type == SOCK_DGRAM) {
return swrap_marshall_packet(si, si->peername,
@@ -1057,8 +1231,8 @@ static struct swrap_packet *swrap_marshall_packet(struct socket_info *si,
break;
case SWRAP_PENDING_RST:
- dest_addr = (const struct sockaddr_in *)si->myname;
- src_addr = (const struct sockaddr_in *)si->peername;
+ dest_addr = si->myname;
+ src_addr = si->peername;
if (si->type == SOCK_DGRAM) {
return NULL;
@@ -1071,8 +1245,8 @@ static struct swrap_packet *swrap_marshall_packet(struct socket_info *si,
break;
case SWRAP_RECV:
- dest_addr = (const struct sockaddr_in *)si->myname;
- src_addr = (const struct sockaddr_in *)si->peername;
+ dest_addr = si->myname;
+ src_addr = si->peername;
tcp_seqno = si->io.pck_rcv;
tcp_ack = si->io.pck_snd;
@@ -1083,8 +1257,8 @@ static struct swrap_packet *swrap_marshall_packet(struct socket_info *si,
break;
case SWRAP_RECV_RST:
- dest_addr = (const struct sockaddr_in *)si->myname;
- src_addr = (const struct sockaddr_in *)si->peername;
+ dest_addr = si->myname;
+ src_addr = si->peername;
if (si->type == SOCK_DGRAM) {
return NULL;
@@ -1097,24 +1271,24 @@ static struct swrap_packet *swrap_marshall_packet(struct socket_info *si,
break;
case SWRAP_SENDTO:
- src_addr = (const struct sockaddr_in *)si->myname;
- dest_addr = (const struct sockaddr_in *)addr;
+ src_addr = si->myname;
+ dest_addr = addr;
si->io.pck_snd += len;
break;
case SWRAP_SENDTO_UNREACH:
- dest_addr = (const struct sockaddr_in *)si->myname;
- src_addr = (const struct sockaddr_in *)addr;
+ dest_addr = si->myname;
+ src_addr = addr;
unreachable = 1;
break;
case SWRAP_RECVFROM:
- dest_addr = (const struct sockaddr_in *)si->myname;
- src_addr = (const struct sockaddr_in *)addr;
+ dest_addr = si->myname;
+ src_addr = addr;
si->io.pck_rcv += len;
@@ -1123,8 +1297,8 @@ static struct swrap_packet *swrap_marshall_packet(struct socket_info *si,
case SWRAP_CLOSE_SEND:
if (si->type != SOCK_STREAM) return NULL;
- src_addr = (const struct sockaddr_in *)si->myname;
- dest_addr = (const struct sockaddr_in *)si->peername;
+ src_addr = si->myname;
+ dest_addr = si->peername;
tcp_seqno = si->io.pck_snd;
tcp_ack = si->io.pck_rcv;
@@ -1137,8 +1311,8 @@ static struct swrap_packet *swrap_marshall_packet(struct socket_info *si,
case SWRAP_CLOSE_RECV:
if (si->type != SOCK_STREAM) return NULL;
- dest_addr = (const struct sockaddr_in *)si->myname;
- src_addr = (const struct sockaddr_in *)si->peername;
+ dest_addr = si->myname;
+ src_addr = si->peername;
tcp_seqno = si->io.pck_rcv;
tcp_ack = si->io.pck_snd;
@@ -1151,8 +1325,8 @@ static struct swrap_packet *swrap_marshall_packet(struct socket_info *si,
case SWRAP_CLOSE_ACK:
if (si->type != SOCK_STREAM) return NULL;
- src_addr = (const struct sockaddr_in *)si->myname;
- dest_addr = (const struct sockaddr_in *)si->peername;
+ src_addr = si->myname;
+ dest_addr = si->peername;
tcp_seqno = si->io.pck_snd;
tcp_ack = si->io.pck_rcv;
@@ -1166,18 +1340,18 @@ static struct swrap_packet *swrap_marshall_packet(struct socket_info *si,
swrapGetTimeOfDay(&tv);
return swrap_packet_init(&tv, src_addr, dest_addr, si->type,
- (const unsigned char *)buf, len,
- tcp_seqno, tcp_ack, tcp_ctl, unreachable,
- packet_len);
+ (const uint8_t *)buf, len,
+ tcp_seqno, tcp_ack, tcp_ctl, unreachable,
+ packet_len);
}
-static void swrap_dump_packet(struct socket_info *si,
- const struct sockaddr *addr,
- enum swrap_packet_type type,
- const void *buf, size_t len)
+static void swrap_dump_packet(struct socket_info *si,
+ const struct sockaddr *addr,
+ enum swrap_packet_type type,
+ const void *buf, size_t len)
{
const char *file_name;
- struct swrap_packet *packet;
+ uint8_t *packet;
size_t packet_len = 0;
int fd;
@@ -1329,6 +1503,7 @@ _PUBLIC_ int swrap_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
child_si->protocol = parent_si->protocol;
child_si->bound = 1;
child_si->is_server = 1;
+ child_si->connected = 1;
child_si->peername_len = len;
child_si->peername = sockaddr_dup(my_addr, len);
@@ -1376,8 +1551,10 @@ static int autobind_start;
/* using sendto() or connect() on an unbound socket would give the
recipient no way to reply, as unlike UDP and TCP, a unix domain
socket can't auto-assign emphemeral port numbers, so we need to
- assign it here */
-static int swrap_auto_bind(struct socket_info *si)
+ assign it here.
+ Note: this might change the family from ipv6 to ipv4
+*/
+static int swrap_auto_bind(struct socket_info *si, int family)
{
struct sockaddr_un un_addr;
int i;
@@ -1395,7 +1572,7 @@ static int swrap_auto_bind(struct socket_info *si)
un_addr.sun_family = AF_UNIX;
- switch (si->family) {
+ switch (family) {
case AF_INET: {
struct sockaddr_in in;
@@ -1424,6 +1601,11 @@ static int swrap_auto_bind(struct socket_info *si)
case AF_INET6: {
struct sockaddr_in6 in6;
+ if (si->family != family) {
+ errno = ENETUNREACH;
+ return -1;
+ }
+
switch (si->type) {
case SOCK_STREAM:
type = SOCKET_TYPE_CHAR_TCP_V6;
@@ -1432,13 +1614,14 @@ static int swrap_auto_bind(struct socket_info *si)
type = SOCKET_TYPE_CHAR_UDP_V6;
break;
default:
- errno = ESOCKTNOSUPPORT;
- return -1;
+ errno = ESOCKTNOSUPPORT;
+ return -1;
}
memset(&in6, 0, sizeof(in6));
in6.sin6_family = AF_INET6;
- in6.sin6_addr.s6_addr[0] = SW_IPV6_ADDRESS;
+ in6.sin6_addr = *swrap_ipv6();
+ in6.sin6_addr.s6_addr[15] = socket_wrapper_default_iface();
si->myname_len = sizeof(in6);
si->myname = sockaddr_dup(&in6, si->myname_len);
break;
@@ -1473,6 +1656,7 @@ static int swrap_auto_bind(struct socket_info *si)
return -1;
}
+ si->family = family;
set_port(si->family, port, si->myname);
return 0;
@@ -1490,7 +1674,7 @@ _PUBLIC_ int swrap_connect(int s, const struct sockaddr *serv_addr, socklen_t ad
}
if (si->bound == 0) {
- ret = swrap_auto_bind(si);
+ ret = swrap_auto_bind(si, serv_addr->sa_family);
if (ret == -1) return -1;
}
@@ -1515,6 +1699,7 @@ _PUBLIC_ int swrap_connect(int s, const struct sockaddr *serv_addr, socklen_t ad
if (ret == 0) {
si->peername_len = addrlen;
si->peername = sockaddr_dup(serv_addr, addrlen);
+ si->connected = 1;
swrap_dump_packet(si, serv_addr, SWRAP_CONNECT_RECV, NULL, 0);
swrap_dump_packet(si, serv_addr, SWRAP_CONNECT_ACK, NULL, 0);
@@ -1644,11 +1829,18 @@ _PUBLIC_ ssize_t swrap_recvfrom(int s, void *buf, size_t len, int flags, struct
socklen_t un_addrlen = sizeof(un_addr);
int ret;
struct socket_info *si = find_socket_info(s);
+ struct sockaddr_storage ss;
+ socklen_t ss_len = sizeof(ss);
if (!si) {
return real_recvfrom(s, buf, len, flags, from, fromlen);
}
+ if (!from) {
+ from = (struct sockaddr *)&ss;
+ fromlen = &ss_len;
+ }
+
len = MIN(len, 1500);
/* irix 6.4 forgets to null terminate the sun_path string :-( */
@@ -1679,6 +1871,16 @@ _PUBLIC_ ssize_t swrap_sendto(int s, const void *buf, size_t len, int flags, con
return real_sendto(s, buf, len, flags, to, tolen);
}
+ if (si->connected) {
+ if (to) {
+ errno = EISCONN;
+ return -1;
+ }
+
+ to = si->peername;
+ tolen = si->peername_len;
+ }
+
len = MIN(len, 1500);
switch (si->type) {
@@ -1687,7 +1889,7 @@ _PUBLIC_ ssize_t swrap_sendto(int s, const void *buf, size_t len, int flags, con
break;
case SOCK_DGRAM:
if (si->bound == 0) {
- ret = swrap_auto_bind(si);
+ ret = swrap_auto_bind(si, si->family);
if (ret == -1) return -1;
}
@@ -1781,7 +1983,7 @@ _PUBLIC_ ssize_t swrap_recv(int s, void *buf, size_t len, int flags)
swrap_dump_packet(si, NULL, SWRAP_RECV_RST, NULL, 0);
} else if (ret == 0) { /* END OF FILE */
swrap_dump_packet(si, NULL, SWRAP_RECV_RST, NULL, 0);
- } else {
+ } else if (ret > 0) {
swrap_dump_packet(si, NULL, SWRAP_RECV, buf, ret);
}
@@ -1812,6 +2014,128 @@ _PUBLIC_ ssize_t swrap_send(int s, const void *buf, size_t len, int flags)
return ret;
}
+int swrap_readv(int s, const struct iovec *vector, size_t count)
+{
+ int ret;
+ struct socket_info *si = find_socket_info(s);
+ struct iovec v;
+
+ if (!si) {
+ return real_readv(s, vector, count);
+ }
+
+ /* we read 1500 bytes as maximum */
+ if (count > 0) {
+ size_t i, len = 0;
+
+ for (i=0; i < count; i++) {
+ size_t nlen;
+ nlen = len + vector[i].iov_len;
+ if (nlen > 1500) {
+ break;
+ }
+ }
+ count = i;
+ if (count == 0) {
+ v = vector[0];
+ v.iov_len = MIN(v.iov_len, 1500);
+ vector = &v;
+ count = 1;
+ }
+ }
+
+ ret = real_readv(s, vector, count);
+ if (ret == -1 && errno != EAGAIN && errno != ENOBUFS) {
+ swrap_dump_packet(si, NULL, SWRAP_RECV_RST, NULL, 0);
+ } else if (ret == 0) { /* END OF FILE */
+ swrap_dump_packet(si, NULL, SWRAP_RECV_RST, NULL, 0);
+ } else if (ret > 0) {
+ uint8_t *buf;
+ off_t ofs = 0;
+ size_t i;
+
+ /* we capture it as one single packet */
+ buf = (uint8_t *)malloc(ret);
+ if (!buf) {
+ /* we just not capture the packet */
+ errno = 0;
+ return ret;
+ }
+
+ for (i=0; i < count; i++) {
+ memcpy(buf + ofs,
+ vector[i].iov_base,
+ vector[i].iov_len);
+ ofs += vector[i].iov_len;
+ }
+
+ swrap_dump_packet(si, NULL, SWRAP_RECV, buf, ret);
+ free(buf);
+ }
+
+ return ret;
+}
+
+int swrap_writev(int s, const struct iovec *vector, size_t count)
+{
+ int ret;
+ struct socket_info *si = find_socket_info(s);
+ struct iovec v;
+
+ if (!si) {
+ return real_writev(s, vector, count);
+ }
+
+ /* we write 1500 bytes as maximum */
+ if (count > 0) {
+ size_t i, len = 0;
+
+ for (i=0; i < count; i++) {
+ size_t nlen;
+ nlen = len + vector[i].iov_len;
+ if (nlen > 1500) {
+ break;
+ }
+ }
+ count = i;
+ if (count == 0) {
+ v = vector[0];
+ v.iov_len = MIN(v.iov_len, 1500);
+ vector = &v;
+ count = 1;
+ }
+ }
+
+ ret = real_writev(s, vector, count);
+ if (ret == -1) {
+ swrap_dump_packet(si, NULL, SWRAP_SEND_RST, NULL, 0);
+ } else {
+ uint8_t *buf;
+ off_t ofs = 0;
+ size_t i;
+
+ /* we capture it as one single packet */
+ buf = (uint8_t *)malloc(ret);
+ if (!buf) {
+ /* we just not capture the packet */
+ errno = 0;
+ return ret;
+ }
+
+ for (i=0; i < count; i++) {
+ memcpy(buf + ofs,
+ vector[i].iov_base,
+ vector[i].iov_len);
+ ofs += vector[i].iov_len;
+ }
+
+ swrap_dump_packet(si, NULL, SWRAP_SEND, buf, ret);
+ free(buf);
+ }
+
+ return ret;
+}
+
_PUBLIC_ int swrap_close(int fd)
{
struct socket_info *si = find_socket_info(fd);
diff --git a/lib/socket_wrapper/socket_wrapper.h b/lib/socket_wrapper/socket_wrapper.h
index cc8b937608..b2d44769ff 100644
--- a/lib/socket_wrapper/socket_wrapper.h
+++ b/lib/socket_wrapper/socket_wrapper.h
@@ -52,6 +52,8 @@ ssize_t swrap_sendto(int s, const void *buf, size_t len, int flags, const struct
int swrap_ioctl(int s, int req, void *ptr);
ssize_t swrap_recv(int s, void *buf, size_t len, int flags);
ssize_t swrap_send(int s, const void *buf, size_t len, int flags);
+int swrap_readv(int s, const struct iovec *vector, size_t count);
+int swrap_writev(int s, const struct iovec *vector, size_t count);
int swrap_close(int);
#ifdef SOCKET_WRAPPER_REPLACE
@@ -121,6 +123,16 @@ int swrap_close(int);
#endif
#define send(s,buf,len,flags) swrap_send(s,buf,len,flags)
+#ifdef readv
+#undef readv
+#endif
+#define readv(s, vector, count) swrap_readv(s,vector, count)
+
+#ifdef writev
+#undef writev
+#endif
+#define writev(s, vector, count) swrap_writev(s,vector, count)
+
#ifdef socket
#undef socket
#endif
diff --git a/lib/talloc/configure.ac b/lib/talloc/configure.ac
index d2538f9222..00e8242d4e 100644
--- a/lib/talloc/configure.ac
+++ b/lib/talloc/configure.ac
@@ -1,5 +1,5 @@
AC_PREREQ(2.50)
-AC_INIT(talloc, 1.2.0)
+AC_INIT(talloc, 1.3.0)
AC_CONFIG_SRCDIR([talloc.c])
AC_SUBST(datarootdir)
AC_CONFIG_HEADER(config.h)
diff --git a/lib/talloc/talloc.c b/lib/talloc/talloc.c
index 1f7e52439f..60a48ad811 100644
--- a/lib/talloc/talloc.c
+++ b/lib/talloc/talloc.c
@@ -138,14 +138,30 @@ struct talloc_chunk {
#define TC_HDR_SIZE ((sizeof(struct talloc_chunk)+15)&~15)
#define TC_PTR_FROM_CHUNK(tc) ((void *)(TC_HDR_SIZE + (char*)tc))
+static void (*talloc_abort_fn)(const char *reason);
+
+void talloc_set_abort_fn(void (*abort_fn)(const char *reason))
+{
+ talloc_abort_fn = abort_fn;
+}
+
+static void talloc_abort(const char *reason)
+{
+ if (!talloc_abort_fn) {
+ TALLOC_ABORT(reason);
+ }
+
+ talloc_abort_fn(reason);
+}
+
static void talloc_abort_double_free(void)
{
- TALLOC_ABORT("Bad talloc magic value - double free");
+ talloc_abort("Bad talloc magic value - double free");
}
static void talloc_abort_unknown_value(void)
{
- TALLOC_ABORT("Bad talloc magic value - unknown value");
+ talloc_abort("Bad talloc magic value - unknown value");
}
/* panic if we get a bad magic value */
@@ -564,7 +580,7 @@ static inline int _talloc_free(void *ptr)
pool_object_count = talloc_pool_objectcount(pool);
if (*pool_object_count == 0) {
- TALLOC_ABORT("Pool object count zero!");
+ talloc_abort("Pool object count zero!");
}
*pool_object_count -= 1;
@@ -806,6 +822,41 @@ void *talloc_check_name(const void *ptr, const char *name)
return NULL;
}
+static void talloc_abort_type_missmatch(const char *location,
+ const char *name,
+ const char *expected)
+{
+ const char *reason;
+
+ reason = talloc_asprintf(NULL,
+ "%s: Type mismatch: name[%s] expected[%s]",
+ location,
+ name?name:"NULL",
+ expected);
+ if (!reason) {
+ reason = "Type mismatch";
+ }
+
+ talloc_abort(reason);
+}
+
+void *_talloc_get_type_abort(const void *ptr, const char *name, const char *location)
+{
+ const char *pname;
+
+ if (unlikely(ptr == NULL)) {
+ talloc_abort_type_missmatch(location, NULL, name);
+ return NULL;
+ }
+
+ pname = talloc_get_name(ptr);
+ if (likely(pname == name || strcmp(pname, name) == 0)) {
+ return discard_const_p(void, ptr);
+ }
+
+ talloc_abort_type_missmatch(location, pname, name);
+ return NULL;
+}
/*
this is for compatibility with older versions of talloc
diff --git a/lib/talloc/talloc.h b/lib/talloc/talloc.h
index 5431971655..5c8d5c5fe2 100644
--- a/lib/talloc/talloc.h
+++ b/lib/talloc/talloc.h
@@ -94,6 +94,7 @@ typedef void TALLOC_CTX;
#define talloc_array(ctx, type, count) (type *)_talloc_array(ctx, sizeof(type), count, #type)
#define talloc_array_size(ctx, size, count) _talloc_array(ctx, size, count, __location__)
#define talloc_array_ptrtype(ctx, ptr, count) (_TALLOC_TYPEOF(ptr))talloc_array_size(ctx, sizeof(*(ptr)), count)
+#define talloc_array_length(ctx) ((ctx) ? talloc_get_size(ctx)/sizeof(*ctx) : 0)
#define talloc_realloc(ctx, p, type, count) (type *)_talloc_realloc_array(ctx, p, sizeof(type), count, #type)
#define talloc_realloc_size(ctx, ptr, size) _talloc_realloc(ctx, ptr, size, __location__)
@@ -102,6 +103,7 @@ typedef void TALLOC_CTX;
#define talloc_set_type(ptr, type) talloc_set_name_const(ptr, #type)
#define talloc_get_type(ptr, type) (type *)talloc_check_name(ptr, #type)
+#define talloc_get_type_abort(ptr, type) (type *)_talloc_get_type_abort(ptr, #type, __location__)
#define talloc_find_parent_bytype(ptr, type) (type *)talloc_find_parent_byname(ptr, #type)
@@ -114,6 +116,8 @@ typedef void TALLOC_CTX;
#define talloc_append_string(c, s, a) (s?talloc_strdup_append(s,a):talloc_strdup(c, a))
#endif
+#define TALLOC_FREE(ctx) do { talloc_free(ctx); ctx=NULL; } while(0)
+
/* The following definitions come from talloc.c */
void *_talloc(const void *context, size_t size);
void *talloc_pool(const void *context, size_t size);
@@ -129,6 +133,7 @@ void *talloc_named(const void *context, size_t size,
void *talloc_named_const(const void *context, size_t size, const char *name);
const char *talloc_get_name(const void *ptr);
void *talloc_check_name(const void *ptr, const char *name);
+void *_talloc_get_type_abort(const void *ptr, const char *name, const char *location);
void *talloc_parent(const void *ptr);
const char *talloc_parent_name(const void *ptr);
void *talloc_init(const char *fmt, ...) PRINTF_ATTRIBUTE(1,2);
@@ -180,4 +185,6 @@ char *talloc_asprintf(const void *t, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3)
char *talloc_asprintf_append(char *s, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3);
char *talloc_asprintf_append_buffer(char *s, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3);
+void talloc_set_abort_fn(void (*abort_fn)(const char *reason));
+
#endif
diff --git a/lib/tdr/TODO b/lib/tdr/TODO
new file mode 100644
index 0000000000..5093afd438
--- /dev/null
+++ b/lib/tdr/TODO
@@ -0,0 +1 @@
+- Support read/write (to fd) as well as push/pull (to DATA_BLOB)
diff --git a/lib/tdr/config.mk b/lib/tdr/config.mk
new file mode 100644
index 0000000000..07506ec647
--- /dev/null
+++ b/lib/tdr/config.mk
@@ -0,0 +1,9 @@
+[SUBSYSTEM::TDR]
+CFLAGS = -Ilib/tdr
+PUBLIC_DEPENDENCIES = LIBTALLOC LIBSAMBA-UTIL
+
+TDR_OBJ_FILES = $(libtdrsrcdir)/tdr.o
+
+$(eval $(call proto_header_template,$(libtdrsrcdir)/tdr_proto.h,$(TDR_OBJ_FILES:.o=.c)))
+
+PUBLIC_HEADERS += $(libtdrsrcdir)/tdr.h
diff --git a/lib/tdr/tdr.c b/lib/tdr/tdr.c
new file mode 100644
index 0000000000..293436ed5e
--- /dev/null
+++ b/lib/tdr/tdr.c
@@ -0,0 +1,397 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ TDR (Trivial Data Representation) helper functions
+ Based loosely on ndr.c by Andrew Tridgell.
+
+ Copyright (C) Jelmer Vernooij 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "system/filesys.h"
+#include "system/network.h"
+#include "lib/tdr/tdr.h"
+
+#define TDR_BASE_MARSHALL_SIZE 1024
+
+#define TDR_PUSH_NEED_BYTES(tdr, n) TDR_CHECK(tdr_push_expand(tdr, tdr->data.length+(n)))
+
+#define TDR_PULL_NEED_BYTES(tdr, n) do { \
+ if ((n) > tdr->data.length || tdr->offset + (n) > tdr->data.length) { \
+ return NT_STATUS_BUFFER_TOO_SMALL; \
+ } \
+} while(0)
+
+#define TDR_BE(tdr) ((tdr)->flags & TDR_BIG_ENDIAN)
+
+#define TDR_CVAL(tdr, ofs) CVAL(tdr->data.data,ofs)
+#define TDR_SVAL(tdr, ofs) (TDR_BE(tdr)?RSVAL(tdr->data.data,ofs):SVAL(tdr->data.data,ofs))
+#define TDR_IVAL(tdr, ofs) (TDR_BE(tdr)?RIVAL(tdr->data.data,ofs):IVAL(tdr->data.data,ofs))
+#define TDR_SCVAL(tdr, ofs, v) SCVAL(tdr->data.data,ofs,v)
+#define TDR_SSVAL(tdr, ofs, v) do { if (TDR_BE(tdr)) { RSSVAL(tdr->data.data,ofs,v); } else SSVAL(tdr->data.data,ofs,v); } while (0)
+#define TDR_SIVAL(tdr, ofs, v) do { if (TDR_BE(tdr)) { RSIVAL(tdr->data.data,ofs,v); } else SIVAL(tdr->data.data,ofs,v); } while (0)
+
+/**
+ expand the available space in the buffer to 'size'
+*/
+NTSTATUS tdr_push_expand(struct tdr_push *tdr, uint32_t size)
+{
+ if (talloc_get_size(tdr->data.data) >= size) {
+ return NT_STATUS_OK;
+ }
+
+ tdr->data.data = talloc_realloc(tdr, tdr->data.data, uint8_t, tdr->data.length + TDR_BASE_MARSHALL_SIZE);
+
+ if (tdr->data.data == NULL)
+ return NT_STATUS_NO_MEMORY;
+
+ return NT_STATUS_OK;
+}
+
+
+NTSTATUS tdr_pull_uint8(struct tdr_pull *tdr, TALLOC_CTX *ctx, uint8_t *v)
+{
+ TDR_PULL_NEED_BYTES(tdr, 1);
+ *v = TDR_CVAL(tdr, tdr->offset);
+ tdr->offset += 1;
+ return NT_STATUS_OK;
+}
+
+NTSTATUS tdr_push_uint8(struct tdr_push *tdr, const uint8_t *v)
+{
+ TDR_PUSH_NEED_BYTES(tdr, 1);
+ TDR_SCVAL(tdr, tdr->data.length, *v);
+ tdr->data.length += 1;
+ return NT_STATUS_OK;
+}
+
+NTSTATUS tdr_print_uint8(struct tdr_print *tdr, const char *name, uint8_t *v)
+{
+ tdr->print(tdr, "%-25s: 0x%02x (%u)", name, *v, *v);
+ return NT_STATUS_OK;
+}
+
+NTSTATUS tdr_pull_uint16(struct tdr_pull *tdr, TALLOC_CTX *ctx, uint16_t *v)
+{
+ TDR_PULL_NEED_BYTES(tdr, 2);
+ *v = TDR_SVAL(tdr, tdr->offset);
+ tdr->offset += 2;
+ return NT_STATUS_OK;
+}
+
+NTSTATUS tdr_push_uint16(struct tdr_push *tdr, const uint16_t *v)
+{
+ TDR_PUSH_NEED_BYTES(tdr, 2);
+ TDR_SSVAL(tdr, tdr->data.length, *v);
+ tdr->data.length += 2;
+ return NT_STATUS_OK;
+}
+
+NTSTATUS tdr_print_uint16(struct tdr_print *tdr, const char *name, uint16_t *v)
+{
+ tdr->print(tdr, "%-25s: 0x%02x (%u)", name, *v, *v);
+ return NT_STATUS_OK;
+}
+
+NTSTATUS tdr_pull_uint32(struct tdr_pull *tdr, TALLOC_CTX *ctx, uint32_t *v)
+{
+ TDR_PULL_NEED_BYTES(tdr, 4);
+ *v = TDR_IVAL(tdr, tdr->offset);
+ tdr->offset += 4;
+ return NT_STATUS_OK;
+}
+
+NTSTATUS tdr_push_uint32(struct tdr_push *tdr, const uint32_t *v)
+{
+ TDR_PUSH_NEED_BYTES(tdr, 4);
+ TDR_SIVAL(tdr, tdr->data.length, *v);
+ tdr->data.length += 4;
+ return NT_STATUS_OK;
+}
+
+NTSTATUS tdr_print_uint32(struct tdr_print *tdr, const char *name, uint32_t *v)
+{
+ tdr->print(tdr, "%-25s: 0x%02x (%u)", name, *v, *v);
+ return NT_STATUS_OK;
+}
+
+NTSTATUS tdr_pull_charset(struct tdr_pull *tdr, TALLOC_CTX *ctx, const char **v, uint32_t length, uint32_t el_size, charset_t chset)
+{
+ size_t ret;
+
+ if (length == -1) {
+ switch (chset) {
+ case CH_DOS:
+ length = ascii_len_n((const char*)tdr->data.data+tdr->offset, tdr->data.length-tdr->offset);
+ break;
+ case CH_UTF16:
+ length = utf16_len_n(tdr->data.data+tdr->offset, tdr->data.length-tdr->offset);
+ break;
+
+ default:
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ }
+
+ if (length == 0) {
+ *v = talloc_strdup(ctx, "");
+ return NT_STATUS_OK;
+ }
+
+ TDR_PULL_NEED_BYTES(tdr, el_size*length);
+
+ if (!convert_string_talloc_convenience(ctx, tdr->iconv_convenience, chset, CH_UNIX, tdr->data.data+tdr->offset, el_size*length, discard_const_p(void *, v), &ret, false)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ tdr->offset += length * el_size;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS tdr_push_charset(struct tdr_push *tdr, const char **v, uint32_t length, uint32_t el_size, charset_t chset)
+{
+ size_t ret, required;
+
+ if (length == -1) {
+ length = strlen(*v) + 1; /* Extra element for null character */
+ }
+
+ required = el_size * length;
+ TDR_PUSH_NEED_BYTES(tdr, required);
+
+ if (!convert_string_convenience(tdr->iconv_convenience, CH_UNIX, chset, *v, strlen(*v), tdr->data.data+tdr->data.length, required, &ret, false)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /* Make sure the remaining part of the string is filled with zeroes */
+ if (ret < required) {
+ memset(tdr->data.data+tdr->data.length+ret, 0, required-ret);
+ }
+
+ tdr->data.length += required;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS tdr_print_charset(struct tdr_print *tdr, const char *name, const char **v, uint32_t length, uint32_t el_size, charset_t chset)
+{
+ tdr->print(tdr, "%-25s: %s", name, *v);
+ return NT_STATUS_OK;
+}
+
+/**
+ parse a hyper
+*/
+NTSTATUS tdr_pull_hyper(struct tdr_pull *tdr, TALLOC_CTX *ctx, uint64_t *v)
+{
+ TDR_PULL_NEED_BYTES(tdr, 8);
+ *v = TDR_IVAL(tdr, tdr->offset);
+ *v |= (uint64_t)(TDR_IVAL(tdr, tdr->offset+4)) << 32;
+ tdr->offset += 8;
+ return NT_STATUS_OK;
+}
+
+/**
+ push a hyper
+*/
+NTSTATUS tdr_push_hyper(struct tdr_push *tdr, uint64_t *v)
+{
+ TDR_PUSH_NEED_BYTES(tdr, 8);
+ TDR_SIVAL(tdr, tdr->data.length, ((*v) & 0xFFFFFFFF));
+ TDR_SIVAL(tdr, tdr->data.length+4, ((*v)>>32));
+ tdr->data.length += 8;
+ return NT_STATUS_OK;
+}
+
+/**
+ push a NTTIME
+*/
+NTSTATUS tdr_push_NTTIME(struct tdr_push *tdr, NTTIME *t)
+{
+ TDR_CHECK(tdr_push_hyper(tdr, t));
+ return NT_STATUS_OK;
+}
+
+/**
+ pull a NTTIME
+*/
+NTSTATUS tdr_pull_NTTIME(struct tdr_pull *tdr, TALLOC_CTX *ctx, NTTIME *t)
+{
+ TDR_CHECK(tdr_pull_hyper(tdr, ctx, t));
+ return NT_STATUS_OK;
+}
+
+/**
+ push a time_t
+*/
+NTSTATUS tdr_push_time_t(struct tdr_push *tdr, time_t *t)
+{
+ return tdr_push_uint32(tdr, (uint32_t *)t);
+}
+
+/**
+ pull a time_t
+*/
+NTSTATUS tdr_pull_time_t(struct tdr_pull *tdr, TALLOC_CTX *ctx, time_t *t)
+{
+ uint32_t tt;
+ TDR_CHECK(tdr_pull_uint32(tdr, ctx, &tt));
+ *t = tt;
+ return NT_STATUS_OK;
+}
+
+NTSTATUS tdr_print_time_t(struct tdr_print *tdr, const char *name, time_t *t)
+{
+ if (*t == (time_t)-1 || *t == 0) {
+ tdr->print(tdr, "%-25s: (time_t)%d", name, (int)*t);
+ } else {
+ tdr->print(tdr, "%-25s: %s", name, timestring(tdr, *t));
+ }
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS tdr_print_NTTIME(struct tdr_print *tdr, const char *name, NTTIME *t)
+{
+ tdr->print(tdr, "%-25s: %s", name, nt_time_string(tdr, *t));
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS tdr_print_DATA_BLOB(struct tdr_print *tdr, const char *name, DATA_BLOB *r)
+{
+ tdr->print(tdr, "%-25s: DATA_BLOB length=%u", name, r->length);
+ if (r->length) {
+ dump_data(10, r->data, r->length);
+ }
+
+ return NT_STATUS_OK;
+}
+
+#define TDR_ALIGN(l,n) (((l) & ((n)-1)) == 0?0:((n)-((l)&((n)-1))))
+
+/*
+ push a DATA_BLOB onto the wire.
+*/
+NTSTATUS tdr_push_DATA_BLOB(struct tdr_push *tdr, DATA_BLOB *blob)
+{
+ if (tdr->flags & TDR_ALIGN2) {
+ blob->length = TDR_ALIGN(tdr->data.length, 2);
+ } else if (tdr->flags & TDR_ALIGN4) {
+ blob->length = TDR_ALIGN(tdr->data.length, 4);
+ } else if (tdr->flags & TDR_ALIGN8) {
+ blob->length = TDR_ALIGN(tdr->data.length, 8);
+ }
+
+ TDR_PUSH_NEED_BYTES(tdr, blob->length);
+
+ memcpy(tdr->data.data+tdr->data.length, blob->data, blob->length);
+ return NT_STATUS_OK;
+}
+
+/*
+ pull a DATA_BLOB from the wire.
+*/
+NTSTATUS tdr_pull_DATA_BLOB(struct tdr_pull *tdr, TALLOC_CTX *ctx, DATA_BLOB *blob)
+{
+ uint32_t length;
+
+ if (tdr->flags & TDR_ALIGN2) {
+ length = TDR_ALIGN(tdr->offset, 2);
+ } else if (tdr->flags & TDR_ALIGN4) {
+ length = TDR_ALIGN(tdr->offset, 4);
+ } else if (tdr->flags & TDR_ALIGN8) {
+ length = TDR_ALIGN(tdr->offset, 8);
+ } else if (tdr->flags & TDR_REMAINING) {
+ length = tdr->data.length - tdr->offset;
+ } else {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (tdr->data.length - tdr->offset < length) {
+ length = tdr->data.length - tdr->offset;
+ }
+
+ TDR_PULL_NEED_BYTES(tdr, length);
+
+ *blob = data_blob_talloc(tdr, tdr->data.data+tdr->offset, length);
+ tdr->offset += length;
+ return NT_STATUS_OK;
+}
+
+struct tdr_push *tdr_push_init(TALLOC_CTX *mem_ctx, struct smb_iconv_convenience *ic)
+{
+ struct tdr_push *push = talloc_zero(mem_ctx, struct tdr_push);
+
+ if (push == NULL)
+ return NULL;
+
+ push->iconv_convenience = talloc_reference(push, ic);
+
+ return push;
+}
+
+struct tdr_pull *tdr_pull_init(TALLOC_CTX *mem_ctx, struct smb_iconv_convenience *ic)
+{
+ struct tdr_pull *pull = talloc_zero(mem_ctx, struct tdr_pull);
+
+ if (pull == NULL)
+ return NULL;
+
+ pull->iconv_convenience = talloc_reference(pull, ic);
+
+ return pull;
+}
+
+NTSTATUS tdr_push_to_fd(int fd, struct smb_iconv_convenience *iconv_convenience, tdr_push_fn_t push_fn, const void *p)
+{
+ struct tdr_push *push = tdr_push_init(NULL, iconv_convenience);
+
+ if (push == NULL)
+ return NT_STATUS_NO_MEMORY;
+
+ if (NT_STATUS_IS_ERR(push_fn(push, p))) {
+ DEBUG(1, ("Error pushing data\n"));
+ talloc_free(push);
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ if (write(fd, push->data.data, push->data.length) < push->data.length) {
+ DEBUG(1, ("Error writing all data\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ talloc_free(push);
+
+ return NT_STATUS_OK;
+}
+
+void tdr_print_debug_helper(struct tdr_print *tdr, const char *format, ...) _PRINTF_ATTRIBUTE(2,3)
+{
+ va_list ap;
+ char *s = NULL;
+ int i;
+
+ va_start(ap, format);
+ vasprintf(&s, format, ap);
+ va_end(ap);
+
+ for (i=0;i<tdr->level;i++) { DEBUG(0,(" ")); }
+
+ DEBUG(0,("%s\n", s));
+ free(s);
+}
diff --git a/lib/tdr/tdr.h b/lib/tdr/tdr.h
new file mode 100644
index 0000000000..c983cd35c1
--- /dev/null
+++ b/lib/tdr/tdr.h
@@ -0,0 +1,67 @@
+/*
+ Unix SMB/CIFS implementation.
+ TDR definitions
+ Copyright (C) Jelmer Vernooij 2005
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __TDR_H__
+#define __TDR_H__
+
+#include <talloc.h>
+#include "../lib/util/charset/charset.h"
+
+#define TDR_BIG_ENDIAN 0x01
+#define TDR_ALIGN2 0x02
+#define TDR_ALIGN4 0x04
+#define TDR_ALIGN8 0x08
+#define TDR_REMAINING 0x10
+
+struct tdr_pull {
+ DATA_BLOB data;
+ uint32_t offset;
+ int flags;
+ struct smb_iconv_convenience *iconv_convenience;
+};
+
+struct tdr_push {
+ DATA_BLOB data;
+ int flags;
+ struct smb_iconv_convenience *iconv_convenience;
+};
+
+struct tdr_print {
+ int level;
+ void (*print)(struct tdr_print *, const char *, ...);
+ int flags;
+};
+
+#define TDR_CHECK(call) do { NTSTATUS _status; \
+ _status = call; \
+ if (!NT_STATUS_IS_OK(_status)) \
+ return _status; \
+ } while (0)
+
+#define TDR_ALLOC(ctx, s, n) do { \
+ (s) = talloc_array_size(ctx, sizeof(*(s)), n); \
+ if ((n) && !(s)) return NT_STATUS_NO_MEMORY; \
+ } while (0)
+
+typedef NTSTATUS (*tdr_push_fn_t) (struct tdr_push *, const void *);
+typedef NTSTATUS (*tdr_pull_fn_t) (struct tdr_pull *, TALLOC_CTX *, void *);
+
+#include "lib/tdr/tdr_proto.h"
+
+#endif /* __TDR_H__ */
diff --git a/lib/tdr/testsuite.c b/lib/tdr/testsuite.c
new file mode 100644
index 0000000000..36bb164a9a
--- /dev/null
+++ b/lib/tdr/testsuite.c
@@ -0,0 +1,185 @@
+/*
+ Unix SMB/CIFS implementation.
+ test suite for basic tdr functions
+
+ Copyright (C) Jelmer Vernooij 2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "torture/torture.h"
+#include "lib/tdr/tdr.h"
+
+static bool test_push_uint8(struct torture_context *tctx)
+{
+ uint8_t v = 4;
+ struct tdr_push *tdr = tdr_push_init(tctx, global_iconv_convenience);
+
+ torture_assert_ntstatus_ok(tctx, tdr_push_uint8(tdr, &v), "push failed");
+ torture_assert_int_equal(tctx, tdr->data.length, 1, "length incorrect");
+ torture_assert_int_equal(tctx, tdr->data.data[0], 4, "data incorrect");
+ return true;
+}
+
+static bool test_pull_uint8(struct torture_context *tctx)
+{
+ uint8_t d = 2;
+ uint8_t l;
+ struct tdr_pull *tdr = tdr_pull_init(tctx, global_iconv_convenience);
+ tdr->data.data = &d;
+ tdr->data.length = 1;
+ tdr->offset = 0;
+ tdr->flags = 0;
+ torture_assert_ntstatus_ok(tctx, tdr_pull_uint8(tdr, tctx, &l),
+ "pull failed");
+ torture_assert_int_equal(tctx, 1, tdr->offset,
+ "offset invalid");
+ return true;
+}
+
+static bool test_push_uint16(struct torture_context *tctx)
+{
+ uint16_t v = 0xF32;
+ struct tdr_push *tdr = tdr_push_init(tctx, global_iconv_convenience);
+
+ torture_assert_ntstatus_ok(tctx, tdr_push_uint16(tdr, &v), "push failed");
+ torture_assert_int_equal(tctx, tdr->data.length, 2, "length incorrect");
+ torture_assert_int_equal(tctx, tdr->data.data[0], 0x32, "data incorrect");
+ torture_assert_int_equal(tctx, tdr->data.data[1], 0x0F, "data incorrect");
+ return true;
+}
+
+static bool test_pull_uint16(struct torture_context *tctx)
+{
+ uint8_t d[2] = { 782 & 0xFF, (782 & 0xFF00) / 0x100 };
+ uint16_t l;
+ struct tdr_pull *tdr = tdr_pull_init(tctx, global_iconv_convenience);
+ tdr->data.data = d;
+ tdr->data.length = 2;
+ tdr->offset = 0;
+ tdr->flags = 0;
+ torture_assert_ntstatus_ok(tctx, tdr_pull_uint16(tdr, tctx, &l),
+ "pull failed");
+ torture_assert_int_equal(tctx, 2, tdr->offset, "offset invalid");
+ torture_assert_int_equal(tctx, 782, l, "right int read");
+ return true;
+}
+
+static bool test_push_uint32(struct torture_context *tctx)
+{
+ uint32_t v = 0x100F32;
+ struct tdr_push *tdr = tdr_push_init(tctx, global_iconv_convenience);
+
+ torture_assert_ntstatus_ok(tctx, tdr_push_uint32(tdr, &v), "push failed");
+ torture_assert_int_equal(tctx, tdr->data.length, 4, "length incorrect");
+ torture_assert_int_equal(tctx, tdr->data.data[0], 0x32, "data incorrect");
+ torture_assert_int_equal(tctx, tdr->data.data[1], 0x0F, "data incorrect");
+ torture_assert_int_equal(tctx, tdr->data.data[2], 0x10, "data incorrect");
+ torture_assert_int_equal(tctx, tdr->data.data[3], 0x00, "data incorrect");
+ return true;
+}
+
+static bool test_pull_uint32(struct torture_context *tctx)
+{
+ uint8_t d[4] = { 782 & 0xFF, (782 & 0xFF00) / 0x100, 0, 0 };
+ uint32_t l;
+ struct tdr_pull *tdr = tdr_pull_init(tctx, global_iconv_convenience);
+ tdr->data.data = d;
+ tdr->data.length = 4;
+ tdr->offset = 0;
+ tdr->flags = 0;
+ torture_assert_ntstatus_ok(tctx, tdr_pull_uint32(tdr, tctx, &l),
+ "pull failed");
+ torture_assert_int_equal(tctx, 4, tdr->offset, "offset invalid");
+ torture_assert_int_equal(tctx, 782, l, "right int read");
+ return true;
+}
+
+static bool test_pull_charset(struct torture_context *tctx)
+{
+ struct tdr_pull *tdr = tdr_pull_init(tctx, global_iconv_convenience);
+ const char *l = NULL;
+ tdr->data.data = (uint8_t *)talloc_strdup(tctx, "bla");
+ tdr->data.length = 4;
+ tdr->offset = 0;
+ tdr->flags = 0;
+ torture_assert_ntstatus_ok(tctx, tdr_pull_charset(tdr, tctx, &l, -1, 1, CH_DOS),
+ "pull failed");
+ torture_assert_int_equal(tctx, 4, tdr->offset, "offset invalid");
+ torture_assert_str_equal(tctx, "bla", l, "right int read");
+
+ tdr->offset = 0;
+ torture_assert_ntstatus_ok(tctx, tdr_pull_charset(tdr, tctx, &l, 2, 1, CH_UNIX),
+ "pull failed");
+ torture_assert_int_equal(tctx, 2, tdr->offset, "offset invalid");
+ torture_assert_str_equal(tctx, "bl", l, "right int read");
+
+ return true;
+}
+
+static bool test_pull_charset_empty(struct torture_context *tctx)
+{
+ struct tdr_pull *tdr = tdr_pull_init(tctx, global_iconv_convenience);
+ const char *l = NULL;
+ tdr->data.data = (uint8_t *)talloc_strdup(tctx, "bla");
+ tdr->data.length = 4;
+ tdr->offset = 0;
+ tdr->flags = 0;
+ torture_assert_ntstatus_ok(tctx, tdr_pull_charset(tdr, tctx, &l, 0, 1, CH_DOS),
+ "pull failed");
+ torture_assert_int_equal(tctx, 0, tdr->offset, "offset invalid");
+ torture_assert_str_equal(tctx, "", l, "right string read");
+
+ return true;
+}
+
+
+
+static bool test_push_charset(struct torture_context *tctx)
+{
+ const char *l = "bloe";
+ struct tdr_push *tdr = tdr_push_init(tctx, global_iconv_convenience);
+ torture_assert_ntstatus_ok(tctx, tdr_push_charset(tdr, &l, 4, 1, CH_UTF8),
+ "push failed");
+ torture_assert_int_equal(tctx, 4, tdr->data.length, "offset invalid");
+ torture_assert(tctx, strcmp("bloe", (const char *)tdr->data.data) == 0, "right string push");
+
+ torture_assert_ntstatus_ok(tctx, tdr_push_charset(tdr, &l, -1, 1, CH_UTF8),
+ "push failed");
+ torture_assert_int_equal(tctx, 9, tdr->data.length, "offset invalid");
+ torture_assert_str_equal(tctx, "bloe", (const char *)tdr->data.data+4, "right string read");
+
+ return true;
+}
+
+struct torture_suite *torture_local_tdr(TALLOC_CTX *mem_ctx)
+{
+ struct torture_suite *suite = torture_suite_create(mem_ctx, "TDR");
+
+ torture_suite_add_simple_test(suite, "pull_uint8", test_pull_uint8);
+ torture_suite_add_simple_test(suite, "push_uint8", test_push_uint8);
+
+ torture_suite_add_simple_test(suite, "pull_uint16", test_pull_uint16);
+ torture_suite_add_simple_test(suite, "push_uint16", test_push_uint16);
+
+ torture_suite_add_simple_test(suite, "pull_uint32", test_pull_uint32);
+ torture_suite_add_simple_test(suite, "push_uint32", test_push_uint32);
+
+ torture_suite_add_simple_test(suite, "pull_charset", test_pull_charset);
+ torture_suite_add_simple_test(suite, "pull_charset", test_pull_charset_empty);
+ torture_suite_add_simple_test(suite, "push_charset", test_push_charset);
+
+ return suite;
+}
diff --git a/lib/tevent/configure.ac b/lib/tevent/configure.ac
index 4333461110..171a4088ba 100644
--- a/lib/tevent/configure.ac
+++ b/lib/tevent/configure.ac
@@ -1,5 +1,5 @@
AC_PREREQ(2.50)
-AC_INIT(tevent, 0.9.3)
+AC_INIT(tevent, 0.9.5)
AC_CONFIG_SRCDIR([tevent.c])
AC_CONFIG_HEADER(config.h)
diff --git a/lib/tevent/libtevent.m4 b/lib/tevent/libtevent.m4
index c316823a71..20730b17d6 100644
--- a/lib/tevent/libtevent.m4
+++ b/lib/tevent/libtevent.m4
@@ -26,7 +26,8 @@ AC_SUBST(TEVENT_LIBS)
TEVENT_CFLAGS="-I$teventdir"
-TEVENT_OBJ="tevent.o tevent_fd.o tevent_timed.o tevent_signal.o tevent_debug.o tevent_util.o"
+TEVENT_OBJ="tevent.o tevent_debug.o tevent_util.o"
+TEVENT_OBJ="$TEVENT_OBJ tevent_fd.o tevent_timed.o tevent_immediate.o tevent_signal.o"
TEVENT_OBJ="$TEVENT_OBJ tevent_req.o tevent_wakeup.o tevent_queue.o"
TEVENT_OBJ="$TEVENT_OBJ tevent_standard.o tevent_select.o"
diff --git a/lib/tevent/tevent.c b/lib/tevent/tevent.c
index fc8252960a..0c02e46f3c 100644
--- a/lib/tevent/tevent.c
+++ b/lib/tevent/tevent.c
@@ -59,6 +59,7 @@
*/
#include "replace.h"
#include "system/filesys.h"
+#define TEVENT_DEPRECATED 1
#include "tevent.h"
#include "tevent_internal.h"
#include "tevent_util.h"
@@ -142,6 +143,7 @@ int tevent_common_context_destructor(struct tevent_context *ev)
{
struct tevent_fd *fd, *fn;
struct tevent_timer *te, *tn;
+ struct tevent_immediate *ie, *in;
struct tevent_signal *se, *sn;
if (ev->pipe_fde) {
@@ -161,6 +163,13 @@ int tevent_common_context_destructor(struct tevent_context *ev)
DLIST_REMOVE(ev->timer_events, te);
}
+ for (ie = ev->immediate_events; ie; ie = in) {
+ in = ie->next;
+ ie->event_ctx = NULL;
+ ie->cancel_fn = NULL;
+ DLIST_REMOVE(ev->immediate_events, ie);
+ }
+
for (se = ev->signal_events; se; se = sn) {
sn = se->next;
se->event_ctx = NULL;
@@ -305,6 +314,33 @@ void tevent_fd_set_flags(struct tevent_fd *fde, uint16_t flags)
fde->event_ctx->ops->set_fd_flags(fde, flags);
}
+bool tevent_signal_support(struct tevent_context *ev)
+{
+ if (ev->ops->add_signal) {
+ return true;
+ }
+ return false;
+}
+
+static void (*tevent_abort_fn)(const char *reason);
+
+void tevent_set_abort_fn(void (*abort_fn)(const char *reason))
+{
+ tevent_abort_fn = abort_fn;
+}
+
+static void tevent_abort(struct tevent_context *ev, const char *reason)
+{
+ tevent_debug(ev, TEVENT_DEBUG_FATAL,
+ "abort: %s\n", reason);
+
+ if (!tevent_abort_fn) {
+ abort();
+ }
+
+ tevent_abort_fn(reason);
+}
+
/*
add a timer event
return NULL on failure
@@ -322,6 +358,47 @@ struct tevent_timer *_tevent_add_timer(struct tevent_context *ev,
}
/*
+ allocate an immediate event
+ return NULL on failure (memory allocation error)
+*/
+struct tevent_immediate *_tevent_create_immediate(TALLOC_CTX *mem_ctx,
+ const char *location)
+{
+ struct tevent_immediate *im;
+
+ im = talloc(mem_ctx, struct tevent_immediate);
+ if (im == NULL) return NULL;
+
+ im->prev = NULL;
+ im->next = NULL;
+ im->event_ctx = NULL;
+ im->create_location = location;
+ im->handler = NULL;
+ im->private_data = NULL;
+ im->handler_name = NULL;
+ im->schedule_location = NULL;
+ im->cancel_fn = NULL;
+ im->additional_data = NULL;
+
+ return im;
+}
+
+/*
+ schedule an immediate event
+ return NULL on failure
+*/
+void _tevent_schedule_immediate(struct tevent_immediate *im,
+ struct tevent_context *ev,
+ tevent_immediate_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location)
+{
+ ev->ops->schedule_immediate(im, ev, handler, private_data,
+ handler_name, location);
+}
+
+/*
add a signal event
sa_flags are flags to sigaction(2)
@@ -341,18 +418,192 @@ struct tevent_signal *_tevent_add_signal(struct tevent_context *ev,
handler_name, location);
}
+void tevent_loop_allow_nesting(struct tevent_context *ev)
+{
+ ev->nesting.allowed = true;
+}
+
+void tevent_loop_set_nesting_hook(struct tevent_context *ev,
+ tevent_nesting_hook hook,
+ void *private_data)
+{
+ if (ev->nesting.hook_fn &&
+ (ev->nesting.hook_fn != hook ||
+ ev->nesting.hook_private != private_data)) {
+ /* the way the nesting hook code is currently written
+ we cannot support two different nesting hooks at the
+ same time. */
+ tevent_abort(ev, "tevent: Violation of nesting hook rules\n");
+ }
+ ev->nesting.hook_fn = hook;
+ ev->nesting.hook_private = private_data;
+}
+
+static void tevent_abort_nesting(struct tevent_context *ev, const char *location)
+{
+ const char *reason;
+
+ reason = talloc_asprintf(NULL, "tevent_loop_once() nesting at %s",
+ location);
+ if (!reason) {
+ reason = "tevent_loop_once() nesting";
+ }
+
+ tevent_abort(ev, reason);
+}
+
/*
do a single event loop using the events defined in ev
*/
-int tevent_loop_once(struct tevent_context *ev)
+int _tevent_loop_once(struct tevent_context *ev, const char *location)
+{
+ int ret;
+ void *nesting_stack_ptr = NULL;
+
+ ev->nesting.level++;
+
+ if (ev->nesting.level > 1) {
+ if (!ev->nesting.allowed) {
+ tevent_abort_nesting(ev, location);
+ errno = ELOOP;
+ return -1;
+ }
+ }
+ if (ev->nesting.level > 0) {
+ if (ev->nesting.hook_fn) {
+ int ret2;
+ ret2 = ev->nesting.hook_fn(ev,
+ ev->nesting.hook_private,
+ ev->nesting.level,
+ true,
+ (void *)&nesting_stack_ptr,
+ location);
+ if (ret2 != 0) {
+ ret = ret2;
+ goto done;
+ }
+ }
+ }
+
+ ret = ev->ops->loop_once(ev, location);
+
+ if (ev->nesting.level > 0) {
+ if (ev->nesting.hook_fn) {
+ int ret2;
+ ret2 = ev->nesting.hook_fn(ev,
+ ev->nesting.hook_private,
+ ev->nesting.level,
+ false,
+ (void *)&nesting_stack_ptr,
+ location);
+ if (ret2 != 0) {
+ ret = ret2;
+ goto done;
+ }
+ }
+ }
+
+done:
+ ev->nesting.level--;
+ return ret;
+}
+
+/*
+ this is a performance optimization for the samba4 nested event loop problems
+*/
+int _tevent_loop_until(struct tevent_context *ev,
+ bool (*finished)(void *private_data),
+ void *private_data,
+ const char *location)
+{
+ int ret = 0;
+ void *nesting_stack_ptr = NULL;
+
+ ev->nesting.level++;
+
+ if (ev->nesting.level > 1) {
+ if (!ev->nesting.allowed) {
+ tevent_abort_nesting(ev, location);
+ errno = ELOOP;
+ return -1;
+ }
+ }
+ if (ev->nesting.level > 0) {
+ if (ev->nesting.hook_fn) {
+ int ret2;
+ ret2 = ev->nesting.hook_fn(ev,
+ ev->nesting.hook_private,
+ ev->nesting.level,
+ true,
+ (void *)&nesting_stack_ptr,
+ location);
+ if (ret2 != 0) {
+ ret = ret2;
+ goto done;
+ }
+ }
+ }
+
+ while (!finished(private_data)) {
+ ret = ev->ops->loop_once(ev, location);
+ if (ret != 0) {
+ break;
+ }
+ }
+
+ if (ev->nesting.level > 0) {
+ if (ev->nesting.hook_fn) {
+ int ret2;
+ ret2 = ev->nesting.hook_fn(ev,
+ ev->nesting.hook_private,
+ ev->nesting.level,
+ false,
+ (void *)&nesting_stack_ptr,
+ location);
+ if (ret2 != 0) {
+ ret = ret2;
+ goto done;
+ }
+ }
+ }
+
+done:
+ ev->nesting.level--;
+ return ret;
+}
+
+/*
+ return on failure or (with 0) if all fd events are removed
+*/
+int tevent_common_loop_wait(struct tevent_context *ev,
+ const char *location)
{
- return ev->ops->loop_once(ev);
+ /*
+ * loop as long as we have events pending
+ */
+ while (ev->fd_events ||
+ ev->timer_events ||
+ ev->immediate_events ||
+ ev->signal_events) {
+ int ret;
+ ret = _tevent_loop_once(ev, location);
+ if (ret != 0) {
+ tevent_debug(ev, TEVENT_DEBUG_FATAL,
+ "_tevent_loop_once() failed: %d - %s\n",
+ ret, strerror(errno));
+ return ret;
+ }
+ }
+
+ tevent_debug(ev, TEVENT_DEBUG_WARNING,
+ "tevent_common_loop_wait() out of events\n");
+ return 0;
}
/*
return on failure or (with 0) if all fd events are removed
*/
-int tevent_loop_wait(struct tevent_context *ev)
+int _tevent_loop_wait(struct tevent_context *ev, const char *location)
{
- return ev->ops->loop_wait(ev);
+ return ev->ops->loop_wait(ev, location);
}
diff --git a/lib/tevent/tevent.h b/lib/tevent/tevent.h
index 8c119ffb8e..6c5df6321a 100644
--- a/lib/tevent/tevent.h
+++ b/lib/tevent/tevent.h
@@ -37,6 +37,7 @@ struct tevent_context;
struct tevent_ops;
struct tevent_fd;
struct tevent_timer;
+struct tevent_immediate;
struct tevent_signal;
/* event handler types */
@@ -52,6 +53,9 @@ typedef void (*tevent_timer_handler_t)(struct tevent_context *ev,
struct tevent_timer *te,
struct timeval current_time,
void *private_data);
+typedef void (*tevent_immediate_handler_t)(struct tevent_context *ctx,
+ struct tevent_immediate *im,
+ void *private_data);
typedef void (*tevent_signal_handler_t)(struct tevent_context *ev,
struct tevent_signal *se,
int signum,
@@ -87,6 +91,21 @@ struct tevent_timer *_tevent_add_timer(struct tevent_context *ev,
_tevent_add_timer(ev, mem_ctx, next_event, handler, private_data, \
#handler, __location__)
+struct tevent_immediate *_tevent_create_immediate(TALLOC_CTX *mem_ctx,
+ const char *location);
+#define tevent_create_immediate(mem_ctx) \
+ _tevent_create_immediate(mem_ctx, __location__)
+
+void _tevent_schedule_immediate(struct tevent_immediate *im,
+ struct tevent_context *ctx,
+ tevent_immediate_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location);
+#define tevent_schedule_immediate(im, ctx, handler, private_data) \
+ _tevent_schedule_immediate(im, ctx, handler, private_data, \
+ #handler, __location__);
+
struct tevent_signal *_tevent_add_signal(struct tevent_context *ev,
TALLOC_CTX *mem_ctx,
int signum,
@@ -99,8 +118,13 @@ struct tevent_signal *_tevent_add_signal(struct tevent_context *ev,
_tevent_add_signal(ev, mem_ctx, signum, sa_flags, handler, private_data, \
#handler, __location__)
-int tevent_loop_once(struct tevent_context *ev);
-int tevent_loop_wait(struct tevent_context *ev);
+int _tevent_loop_once(struct tevent_context *ev, const char *location);
+#define tevent_loop_once(ev) \
+ _tevent_loop_once(ev, __location__) \
+
+int _tevent_loop_wait(struct tevent_context *ev, const char *location);
+#define tevent_loop_wait(ev) \
+ _tevent_loop_wait(ev, __location__) \
void tevent_fd_set_close_fn(struct tevent_fd *fde,
tevent_fd_close_fn_t close_fn);
@@ -108,6 +132,10 @@ void tevent_fd_set_auto_close(struct tevent_fd *fde);
uint16_t tevent_fd_get_flags(struct tevent_fd *fde);
void tevent_fd_set_flags(struct tevent_fd *fde, uint16_t flags);
+bool tevent_signal_support(struct tevent_context *ev);
+
+void tevent_set_abort_fn(void (*abort_fn)(const char *reason));
+
/* bits for file descriptor event flags */
#define TEVENT_FD_READ 1
#define TEVENT_FD_WRITE 2
@@ -165,7 +193,11 @@ enum tevent_req_state {
/**
* No memory in between
*/
- TEVENT_REQ_NO_MEMORY
+ TEVENT_REQ_NO_MEMORY,
+ /**
+ * the request is already received by the caller
+ */
+ TEVENT_REQ_RECEIVED
};
/**
@@ -183,98 +215,24 @@ enum tevent_req_state {
* finished. This can happen while the completion function is called.
*/
-struct tevent_req {
- /**
- * @brief What to do on completion
- *
- * This is used for the user of an async request, fn is called when
- * the request completes, either successfully or with an error.
- */
- struct {
- /**
- * @brief Completion function
- * Completion function, to be filled by the API user
- */
- void (*fn)(struct tevent_req *);
- /**
- * @brief Private data for the completion function
- */
- void *private_data;
- } async;
+struct tevent_req;
- /**
- * @brief Private state pointer for the actual implementation
- *
- * The implementation doing the work for the async request needs a
- * current state like for example a fd event. The user of an async
- * request should not touch this.
- */
- void *private_state;
+typedef void (*tevent_req_fn)(struct tevent_req *);
- /**
- * @brief A function to overwrite the default print function
- *
- * The implementation doing the work may want to imeplement a
- * custom function to print the text representation of the async
- * request.
- */
- char *(*private_print)(struct tevent_req *req, TALLOC_CTX *mem_ctx);
+void tevent_req_set_callback(struct tevent_req *req, tevent_req_fn fn, void *pvt);
+void *_tevent_req_callback_data(struct tevent_req *req);
+void *_tevent_req_data(struct tevent_req *req);
- /**
- * @brief Internal state of the request
- *
- * Callers should only access this via functions and never directly.
- */
- struct {
- /**
- * @brief The talloc type of the private_state pointer
- *
- * This is filled by the tevent_req_create() macro.
- *
- * This for debugging only.
- */
- const char *private_type;
-
- /**
- * @brief The location where the request was created
- *
- * This uses the __location__ macro via the tevent_req_create()
- * macro.
- *
- * This for debugging only.
- */
- const char *location;
-
- /**
- * @brief The external state - will be queried by the caller
- *
- * While the async request is being processed, state will remain in
- * TEVENT_REQ_IN_PROGRESS. A request is finished if
- * req->state>=TEVENT_REQ_DONE.
- */
- enum tevent_req_state state;
-
- /**
- * @brief status code when finished
- *
- * This status can be queried in the async completion function. It
- * will be set to 0 when everything went fine.
- */
- uint64_t error;
-
- /**
- * @brief the timer event if tevent_req_post was used
- *
- */
- struct tevent_timer *trigger;
-
- /**
- * @brief the timer event if tevent_req_set_timeout was used
- *
- */
- struct tevent_timer *timer;
- } internal;
-};
+#define tevent_req_callback_data(_req, _type) \
+ talloc_get_type_abort(_tevent_req_callback_data(_req), _type)
+#define tevent_req_callback_data_void(_req) \
+ _tevent_req_callback_data(_req)
+#define tevent_req_data(_req, _type) \
+ talloc_get_type_abort(_tevent_req_data(_req), _type)
+
+typedef char *(*tevent_req_print_fn)(struct tevent_req *, TALLOC_CTX *);
+
+void tevent_req_set_print_fn(struct tevent_req *req, tevent_req_print_fn fn);
char *tevent_req_default_print(struct tevent_req *req, TALLOC_CTX *mem_ctx);
@@ -294,13 +252,22 @@ bool tevent_req_set_endtime(struct tevent_req *req,
struct tevent_context *ev,
struct timeval endtime);
-void tevent_req_done(struct tevent_req *req);
+void _tevent_req_done(struct tevent_req *req,
+ const char *location);
+#define tevent_req_done(req) \
+ _tevent_req_done(req, __location__)
-bool tevent_req_error(struct tevent_req *req,
- uint64_t error);
+bool _tevent_req_error(struct tevent_req *req,
+ uint64_t error,
+ const char *location);
+#define tevent_req_error(req, error) \
+ _tevent_req_error(req, error, __location__)
-bool tevent_req_nomem(const void *p,
- struct tevent_req *req);
+bool _tevent_req_nomem(const void *p,
+ struct tevent_req *req,
+ const char *location);
+#define tevent_req_nomem(p, req) \
+ _tevent_req_nomem(p, req, __location__)
struct tevent_req *tevent_req_post(struct tevent_req *req,
struct tevent_context *ev);
@@ -314,6 +281,8 @@ bool tevent_req_is_error(struct tevent_req *req,
enum tevent_req_state *state,
uint64_t *error);
+void tevent_req_received(struct tevent_req *req);
+
struct tevent_req *tevent_wakeup_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct timeval wakeup_time);
@@ -354,12 +323,37 @@ bool tevent_queue_add(struct tevent_queue *queue,
struct tevent_req *req,
tevent_queue_trigger_fn_t trigger,
void *private_data);
-bool tevent_queue_start(struct tevent_queue *queue,
- struct tevent_context *ev);
+void tevent_queue_start(struct tevent_queue *queue);
void tevent_queue_stop(struct tevent_queue *queue);
size_t tevent_queue_length(struct tevent_queue *queue);
+typedef int (*tevent_nesting_hook)(struct tevent_context *ev,
+ void *private_data,
+ uint32_t level,
+ bool begin,
+ void *stack_ptr,
+ const char *location);
+#ifdef TEVENT_DEPRECATED
+#ifndef _DEPRECATED_
+#if (__GNUC__ >= 3) && (__GNUC_MINOR__ >= 1 )
+#define _DEPRECATED_ __attribute__ ((deprecated))
+#else
+#define _DEPRECATED_
+#endif
+#endif
+void tevent_loop_allow_nesting(struct tevent_context *ev) _DEPRECATED_;
+void tevent_loop_set_nesting_hook(struct tevent_context *ev,
+ tevent_nesting_hook hook,
+ void *private_data) _DEPRECATED_;
+int _tevent_loop_until(struct tevent_context *ev,
+ bool (*finished)(void *private_data),
+ void *private_data,
+ const char *location) _DEPRECATED_;
+#define tevent_loop_until(ev, finished, private_data) \
+ _tevent_loop_until(ev, finished, private_data, __location__)
+#endif
+
#ifdef TEVENT_COMPAT_DEFINES
#define event_context tevent_context
diff --git a/lib/tevent/tevent_epoll.c b/lib/tevent/tevent_epoll.c
index 0494f55060..7c7f389d5b 100644
--- a/lib/tevent/tevent_epoll.c
+++ b/lib/tevent/tevent_epoll.c
@@ -35,14 +35,6 @@ struct epoll_event_context {
/* a pointer back to the generic event_context */
struct tevent_context *ev;
- /* this is changed by the destructors for the fd event
- type. It is used to detect event destruction by event
- handlers, which means the code that is calling the event
- handler needs to assume that the linked list is no longer
- valid
- */
- uint32_t destruction_count;
-
/* when using epoll this is the handle from epoll_create */
int epoll_fd;
@@ -242,9 +234,8 @@ static void epoll_change_event(struct epoll_event_context *epoll_ev, struct teve
static int epoll_event_loop(struct epoll_event_context *epoll_ev, struct timeval *tvalp)
{
int ret, i;
-#define MAXEVENTS 32
+#define MAXEVENTS 1
struct epoll_event events[MAXEVENTS];
- uint32_t destruction_count = ++epoll_ev->destruction_count;
int timeout = -1;
if (epoll_ev->epoll_fd == -1) return -1;
@@ -305,9 +296,7 @@ static int epoll_event_loop(struct epoll_event_context *epoll_ev, struct timeval
if (events[i].events & EPOLLOUT) flags |= TEVENT_FD_WRITE;
if (flags) {
fde->handler(epoll_ev->ev, fde, flags, fde->private_data);
- if (destruction_count != epoll_ev->destruction_count) {
- break;
- }
+ break;
}
}
@@ -351,8 +340,6 @@ static int epoll_event_fd_destructor(struct tevent_fd *fde)
epoll_check_reopen(epoll_ev);
- epoll_ev->destruction_count++;
-
epoll_del_event(epoll_ev, fde);
}
@@ -411,12 +398,22 @@ static void epoll_event_set_fd_flags(struct tevent_fd *fde, uint16_t flags)
/*
do a single event loop using the events defined in ev
*/
-static int epoll_event_loop_once(struct tevent_context *ev)
+static int epoll_event_loop_once(struct tevent_context *ev, const char *location)
{
struct epoll_event_context *epoll_ev = talloc_get_type(ev->additional_data,
struct epoll_event_context);
struct timeval tval;
+ if (ev->signal_events &&
+ tevent_common_check_signal(ev)) {
+ return 0;
+ }
+
+ if (ev->immediate_events &&
+ tevent_common_loop_immediate(ev)) {
+ return 0;
+ }
+
tval = tevent_common_loop_timer_delay(ev);
if (tevent_timeval_is_zero(&tval)) {
return 0;
@@ -427,32 +424,17 @@ static int epoll_event_loop_once(struct tevent_context *ev)
return epoll_event_loop(epoll_ev, &tval);
}
-/*
- return on failure or (with 0) if all fd events are removed
-*/
-static int epoll_event_loop_wait(struct tevent_context *ev)
-{
- struct epoll_event_context *epoll_ev = talloc_get_type(ev->additional_data,
- struct epoll_event_context);
- while (epoll_ev->ev->fd_events) {
- if (epoll_event_loop_once(ev) != 0) {
- break;
- }
- }
-
- return 0;
-}
-
static const struct tevent_ops epoll_event_ops = {
- .context_init = epoll_event_context_init,
- .add_fd = epoll_event_add_fd,
- .set_fd_close_fn= tevent_common_fd_set_close_fn,
- .get_fd_flags = tevent_common_fd_get_flags,
- .set_fd_flags = epoll_event_set_fd_flags,
- .add_timer = tevent_common_add_timer,
- .add_signal = tevent_common_add_signal,
- .loop_once = epoll_event_loop_once,
- .loop_wait = epoll_event_loop_wait,
+ .context_init = epoll_event_context_init,
+ .add_fd = epoll_event_add_fd,
+ .set_fd_close_fn = tevent_common_fd_set_close_fn,
+ .get_fd_flags = tevent_common_fd_get_flags,
+ .set_fd_flags = epoll_event_set_fd_flags,
+ .add_timer = tevent_common_add_timer,
+ .schedule_immediate = tevent_common_schedule_immediate,
+ .add_signal = tevent_common_add_signal,
+ .loop_once = epoll_event_loop_once,
+ .loop_wait = tevent_common_loop_wait,
};
bool tevent_epoll_init(void)
diff --git a/lib/tevent/tevent_immediate.c b/lib/tevent/tevent_immediate.c
new file mode 100644
index 0000000000..1ac293e175
--- /dev/null
+++ b/lib/tevent/tevent_immediate.c
@@ -0,0 +1,139 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ common events code for immediate events
+
+ 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 "tevent.h"
+#include "tevent_internal.h"
+#include "tevent_util.h"
+
+static void tevent_common_immediate_cancel(struct tevent_immediate *im)
+{
+ if (!im->event_ctx) {
+ return;
+ }
+
+ tevent_debug(im->event_ctx, TEVENT_DEBUG_TRACE,
+ "Cancel immediate event %p \"%s\"\n",
+ im, im->handler_name);
+
+ /* let the backend free im->additional_data */
+ if (im->cancel_fn) {
+ im->cancel_fn(im);
+ }
+
+ DLIST_REMOVE(im->event_ctx->immediate_events, im);
+ im->event_ctx = NULL;
+ im->handler = NULL;
+ im->private_data = NULL;
+ im->handler_name = NULL;
+ im->schedule_location = NULL;
+ im->cancel_fn = NULL;
+ im->additional_data = NULL;
+
+ talloc_set_destructor(im, NULL);
+}
+
+/*
+ destroy an immediate event
+*/
+static int tevent_common_immediate_destructor(struct tevent_immediate *im)
+{
+ tevent_common_immediate_cancel(im);
+ return 0;
+}
+
+/*
+ * schedule an immediate event on
+ */
+void tevent_common_schedule_immediate(struct tevent_immediate *im,
+ struct tevent_context *ev,
+ tevent_immediate_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location)
+{
+ tevent_common_immediate_cancel(im);
+
+ if (!handler) {
+ return;
+ }
+
+ im->event_ctx = ev;
+ im->handler = handler;
+ im->private_data = private_data;
+ im->handler_name = handler_name;
+ im->schedule_location = location;
+ im->cancel_fn = NULL;
+ im->additional_data = NULL;
+
+ DLIST_ADD_END(ev->immediate_events, im, struct tevent_immediate *);
+ talloc_set_destructor(im, tevent_common_immediate_destructor);
+
+ tevent_debug(ev, TEVENT_DEBUG_TRACE,
+ "Schedule immediate event \"%s\": %p\n",
+ handler_name, im);
+}
+
+/*
+ trigger the first immediate event and return true
+ if no event was triggered return false
+*/
+bool tevent_common_loop_immediate(struct tevent_context *ev)
+{
+ struct tevent_immediate *im = ev->immediate_events;
+ tevent_immediate_handler_t handler;
+ void *private_data;
+
+ if (!im) {
+ return false;
+ }
+
+ tevent_debug(ev, TEVENT_DEBUG_TRACE,
+ "Run immediate event \"%s\": %p\n",
+ im->handler_name, im);
+
+ /*
+ * remember the handler and then clear the event
+ * the handler might reschedule the event
+ */
+ handler = im->handler;
+ private_data = im->private_data;
+
+ DLIST_REMOVE(im->event_ctx->immediate_events, im);
+ im->event_ctx = NULL;
+ im->handler = NULL;
+ im->private_data = NULL;
+ im->handler_name = NULL;
+ im->schedule_location = NULL;
+ im->cancel_fn = NULL;
+ im->additional_data = NULL;
+
+ talloc_set_destructor(im, NULL);
+
+ handler(ev, im, private_data);
+
+ return true;
+}
+
diff --git a/lib/tevent/tevent_internal.h b/lib/tevent/tevent_internal.h
index 758bdb4628..eebf767067 100644
--- a/lib/tevent/tevent_internal.h
+++ b/lib/tevent/tevent_internal.h
@@ -25,6 +25,109 @@
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
+struct tevent_req {
+ /**
+ * @brief What to do on completion
+ *
+ * This is used for the user of an async request, fn is called when
+ * the request completes, either successfully or with an error.
+ */
+ struct {
+ /**
+ * @brief Completion function
+ * Completion function, to be filled by the API user
+ */
+ tevent_req_fn fn;
+ /**
+ * @brief Private data for the completion function
+ */
+ void *private_data;
+ } async;
+
+ /**
+ * @brief Private state pointer for the actual implementation
+ *
+ * The implementation doing the work for the async request needs to
+ * keep around current data like for example a fd event. The user of
+ * an async request should not touch this.
+ */
+ void *data;
+
+ /**
+ * @brief A function to overwrite the default print function
+ *
+ * The implementation doing the work may want to implement a
+ * custom function to print the text representation of the async
+ * request.
+ */
+ tevent_req_print_fn private_print;
+
+ /**
+ * @brief Internal state of the request
+ *
+ * Callers should only access this via functions and never directly.
+ */
+ struct {
+ /**
+ * @brief The talloc type of the data pointer
+ *
+ * This is filled by the tevent_req_create() macro.
+ *
+ * This for debugging only.
+ */
+ const char *private_type;
+
+ /**
+ * @brief The location where the request was created
+ *
+ * This uses the __location__ macro via the tevent_req_create()
+ * macro.
+ *
+ * This for debugging only.
+ */
+ const char *create_location;
+
+ /**
+ * @brief The location where the request was finished
+ *
+ * This uses the __location__ macro via the tevent_req_done(),
+ * tevent_req_error() or tevent_req_nomem() macro.
+ *
+ * This for debugging only.
+ */
+ const char *finish_location;
+
+ /**
+ * @brief The external state - will be queried by the caller
+ *
+ * While the async request is being processed, state will remain in
+ * TEVENT_REQ_IN_PROGRESS. A request is finished if
+ * req->state>=TEVENT_REQ_DONE.
+ */
+ enum tevent_req_state state;
+
+ /**
+ * @brief status code when finished
+ *
+ * This status can be queried in the async completion function. It
+ * will be set to 0 when everything went fine.
+ */
+ uint64_t error;
+
+ /**
+ * @brief the immediate event used by tevent_req_post
+ *
+ */
+ struct tevent_immediate *trigger;
+
+ /**
+ * @brief the timer event if tevent_req_set_timeout was used
+ *
+ */
+ struct tevent_timer *timer;
+ } internal;
+};
+
struct tevent_ops {
/* conntext init */
int (*context_init)(struct tevent_context *ev);
@@ -50,6 +153,15 @@ struct tevent_ops {
void *private_data,
const char *handler_name,
const char *location);
+
+ /* immediate event functions */
+ void (*schedule_immediate)(struct tevent_immediate *im,
+ struct tevent_context *ev,
+ tevent_immediate_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location);
+
/* signal functions */
struct tevent_signal *(*add_signal)(struct tevent_context *ev,
TALLOC_CTX *mem_ctx,
@@ -60,8 +172,8 @@ struct tevent_ops {
const char *location);
/* loop functions */
- int (*loop_once)(struct tevent_context *ev);
- int (*loop_wait)(struct tevent_context *ev);
+ int (*loop_once)(struct tevent_context *ev, const char *location);
+ int (*loop_wait)(struct tevent_context *ev, const char *location);
};
struct tevent_fd {
@@ -95,6 +207,21 @@ struct tevent_timer {
void *additional_data;
};
+struct tevent_immediate {
+ struct tevent_immediate *prev, *next;
+ struct tevent_context *event_ctx;
+ tevent_immediate_handler_t handler;
+ /* this is private for the specific handler */
+ void *private_data;
+ /* this is for debugging only! */
+ const char *handler_name;
+ const char *create_location;
+ const char *schedule_location;
+ /* this is private for the events_ops implementation */
+ void (*cancel_fn)(struct tevent_immediate *im);
+ void *additional_data;
+};
+
struct tevent_signal {
struct tevent_signal *prev, *next;
struct tevent_context *event_ctx;
@@ -129,6 +256,9 @@ struct tevent_context {
/* list of timed events - used by common code */
struct tevent_timer *timer_events;
+ /* list of immediate events - used by common code */
+ struct tevent_immediate *immediate_events;
+
/* list of signal events - used by common code */
struct tevent_signal *signal_events;
@@ -140,12 +270,22 @@ struct tevent_context {
/* debugging operations */
struct tevent_debug_ops debug_ops;
+
+ /* info about the nesting status */
+ struct {
+ bool allowed;
+ uint32_t level;
+ tevent_nesting_hook hook_fn;
+ void *hook_private;
+ } nesting;
};
bool tevent_register_backend(const char *name, const struct tevent_ops *ops);
int tevent_common_context_destructor(struct tevent_context *ev);
+int tevent_common_loop_wait(struct tevent_context *ev,
+ const char *location);
int tevent_common_fd_destructor(struct tevent_fd *fde);
struct tevent_fd *tevent_common_add_fd(struct tevent_context *ev,
@@ -170,6 +310,14 @@ struct tevent_timer *tevent_common_add_timer(struct tevent_context *ev,
const char *location);
struct timeval tevent_common_loop_timer_delay(struct tevent_context *);
+void tevent_common_schedule_immediate(struct tevent_immediate *im,
+ struct tevent_context *ev,
+ tevent_immediate_handler_t handler,
+ void *private_data,
+ const char *handler_name,
+ const char *location);
+bool tevent_common_loop_immediate(struct tevent_context *ev);
+
struct tevent_signal *tevent_common_add_signal(struct tevent_context *ev,
TALLOC_CTX *mem_ctx,
int signum,
diff --git a/lib/tevent/tevent_queue.c b/lib/tevent/tevent_queue.c
index 6c8fbe4f95..3715c35e4f 100644
--- a/lib/tevent/tevent_queue.c
+++ b/lib/tevent/tevent_queue.c
@@ -34,6 +34,7 @@ struct tevent_queue_entry {
bool triggered;
struct tevent_req *req;
+ struct tevent_context *ev;
tevent_queue_trigger_fn_t trigger;
void *private_data;
@@ -44,12 +45,16 @@ struct tevent_queue {
const char *location;
bool running;
- struct tevent_timer *timer;
+ struct tevent_immediate *immediate;
size_t length;
struct tevent_queue_entry *list;
};
+static void tevent_queue_immediate_trigger(struct tevent_context *ev,
+ struct tevent_immediate *im,
+ void *private_data);
+
static int tevent_queue_entry_destructor(struct tevent_queue_entry *e)
{
struct tevent_queue *q = e->queue;
@@ -61,14 +66,23 @@ static int tevent_queue_entry_destructor(struct tevent_queue_entry *e)
DLIST_REMOVE(q->list, e);
q->length--;
- if (e->triggered &&
- q->running &&
- q->list) {
- q->list->triggered = true;
- q->list->trigger(q->list->req,
- q->list->private_data);
+ if (!q->running) {
+ return 0;
+ }
+
+ if (!q->list) {
+ return 0;
+ }
+
+ if (q->list->triggered) {
+ return 0;
}
+ tevent_schedule_immediate(q->immediate,
+ q->list->ev,
+ tevent_queue_immediate_trigger,
+ q);
+
return 0;
}
@@ -100,6 +114,11 @@ struct tevent_queue *_tevent_queue_create(TALLOC_CTX *mem_ctx,
talloc_free(queue);
return NULL;
}
+ queue->immediate = tevent_create_immediate(queue);
+ if (!queue->immediate) {
+ talloc_free(queue);
+ return NULL;
+ }
queue->location = location;
@@ -110,16 +129,16 @@ struct tevent_queue *_tevent_queue_create(TALLOC_CTX *mem_ctx,
return queue;
}
-static void tevent_queue_timer_start(struct tevent_context *ev,
- struct tevent_timer *te,
- struct timeval now,
- void *private_data)
+static void tevent_queue_immediate_trigger(struct tevent_context *ev,
+ struct tevent_immediate *im,
+ void *private_data)
{
struct tevent_queue *q = talloc_get_type(private_data,
struct tevent_queue);
- talloc_free(te);
- q->timer = NULL;
+ if (!q->running) {
+ return;
+ }
q->list->triggered = true;
q->list->trigger(q->list->req, q->list->private_data);
@@ -140,56 +159,56 @@ bool tevent_queue_add(struct tevent_queue *queue,
e->queue = queue;
e->req = req;
+ e->ev = ev;
e->trigger = trigger;
e->private_data = private_data;
- if (queue->running &&
- !queue->timer &&
- !queue->list) {
- queue->timer = tevent_add_timer(ev, queue, tevent_timeval_zero(),
- tevent_queue_timer_start,
- queue);
- if (!queue->timer) {
- talloc_free(e);
- return false;
- }
- }
-
DLIST_ADD_END(queue->list, e, struct tevent_queue_entry *);
queue->length++;
talloc_set_destructor(e, tevent_queue_entry_destructor);
+ if (!queue->running) {
+ return true;
+ }
+
+ if (queue->list->triggered) {
+ return true;
+ }
+
+ tevent_schedule_immediate(queue->immediate,
+ queue->list->ev,
+ tevent_queue_immediate_trigger,
+ queue);
+
return true;
}
-bool tevent_queue_start(struct tevent_queue *queue,
- struct tevent_context *ev)
+void tevent_queue_start(struct tevent_queue *queue)
{
if (queue->running) {
/* already started */
- return true;
+ return;
}
- if (!queue->timer &&
- queue->list) {
- queue->timer = tevent_add_timer(ev, queue, tevent_timeval_zero(),
- tevent_queue_timer_start,
- queue);
- if (!queue->timer) {
- return false;
- }
+ queue->running = true;
+
+ if (!queue->list) {
+ return;
}
- queue->running = true;
+ if (queue->list->triggered) {
+ return;
+ }
- return true;
+ tevent_schedule_immediate(queue->immediate,
+ queue->list->ev,
+ tevent_queue_immediate_trigger,
+ queue);
}
void tevent_queue_stop(struct tevent_queue *queue)
{
queue->running = false;
- talloc_free(queue->timer);
- queue->timer = NULL;
}
size_t tevent_queue_length(struct tevent_queue *queue)
diff --git a/lib/tevent/tevent_req.c b/lib/tevent/tevent_req.c
index e243c7de5d..380a6388e2 100644
--- a/lib/tevent/tevent_req.c
+++ b/lib/tevent/tevent_req.c
@@ -43,12 +43,12 @@ char *tevent_req_default_print(struct tevent_req *req, TALLOC_CTX *mem_ctx)
return talloc_asprintf(mem_ctx,
"tevent_req[%p/%s]: state[%d] error[%lld (0x%llX)] "
" state[%s (%p)] timer[%p]",
- req, req->internal.location,
+ req, req->internal.create_location,
req->internal.state,
(unsigned long long)req->internal.error,
(unsigned long long)req->internal.error,
- talloc_get_name(req->private_state),
- req->private_state,
+ talloc_get_name(req->data),
+ req->data,
req->internal.timer
);
}
@@ -81,39 +81,48 @@ char *tevent_req_print(TALLOC_CTX *mem_ctx, struct tevent_req *req)
*/
struct tevent_req *_tevent_req_create(TALLOC_CTX *mem_ctx,
- void *pstate,
- size_t state_size,
+ void *pdata,
+ size_t data_size,
const char *type,
const char *location)
{
struct tevent_req *req;
- void **ppstate = (void **)pstate;
- void *state;
+ void **ppdata = (void **)pdata;
+ void *data;
req = talloc_zero(mem_ctx, struct tevent_req);
if (req == NULL) {
return NULL;
}
req->internal.private_type = type;
- req->internal.location = location;
+ req->internal.create_location = location;
+ req->internal.finish_location = NULL;
req->internal.state = TEVENT_REQ_IN_PROGRESS;
+ req->internal.trigger = tevent_create_immediate(req);
+ if (!req->internal.trigger) {
+ talloc_free(req);
+ return NULL;
+ }
- state = talloc_size(req, state_size);
- if (state == NULL) {
+ data = talloc_size(req, data_size);
+ if (data == NULL) {
talloc_free(req);
return NULL;
}
- talloc_set_name_const(state, type);
+ talloc_set_name_const(data, type);
- req->private_state = state;
+ req->data = data;
- *ppstate = state;
+ *ppdata = data;
return req;
}
-static void tevent_req_finish(struct tevent_req *req, enum tevent_req_state state)
+static void tevent_req_finish(struct tevent_req *req,
+ enum tevent_req_state state,
+ const char *location)
{
req->internal.state = state;
+ req->internal.finish_location = location;
if (req->async.fn != NULL) {
req->async.fn(req);
}
@@ -128,9 +137,10 @@ static void tevent_req_finish(struct tevent_req *req, enum tevent_req_state stat
* function.
*/
-void tevent_req_done(struct tevent_req *req)
+void _tevent_req_done(struct tevent_req *req,
+ const char *location)
{
- tevent_req_finish(req, TEVENT_REQ_DONE);
+ tevent_req_finish(req, TEVENT_REQ_DONE, location);
}
/**
@@ -161,14 +171,16 @@ void tevent_req_done(struct tevent_req *req)
* \endcode
*/
-bool tevent_req_error(struct tevent_req *req, uint64_t error)
+bool _tevent_req_error(struct tevent_req *req,
+ uint64_t error,
+ const char *location)
{
if (error == 0) {
return false;
}
req->internal.error = error;
- tevent_req_finish(req, TEVENT_REQ_USER_ERROR);
+ tevent_req_finish(req, TEVENT_REQ_USER_ERROR, location);
return true;
}
@@ -189,42 +201,39 @@ bool tevent_req_error(struct tevent_req *req, uint64_t error)
* \endcode
*/
-bool tevent_req_nomem(const void *p, struct tevent_req *req)
+bool _tevent_req_nomem(const void *p,
+ struct tevent_req *req,
+ const char *location)
{
if (p != NULL) {
return false;
}
- tevent_req_finish(req, TEVENT_REQ_NO_MEMORY);
+ tevent_req_finish(req, TEVENT_REQ_NO_MEMORY, location);
return true;
}
/**
- * @brief Timed event callback
+ * @brief Immediate event callback
* @param[in] ev Event context
- * @param[in] te The timed event
- * @param[in] now zero time
+ * @param[in] im The immediate event
* @param[in] priv The async request to be finished
*/
static void tevent_req_trigger(struct tevent_context *ev,
- struct tevent_timer *te,
- struct timeval zero,
+ struct tevent_immediate *im,
void *private_data)
{
struct tevent_req *req = talloc_get_type(private_data,
struct tevent_req);
- talloc_free(req->internal.trigger);
- req->internal.trigger = NULL;
-
- tevent_req_finish(req, req->internal.state);
+ tevent_req_finish(req, req->internal.state,
+ req->internal.finish_location);
}
/**
* @brief Finish a request before the caller had the change to set the callback
* @param[in] req The finished request
* @param[in] ev The tevent_context for the timed event
- * @retval On success req will be returned,
- * on failure req will be destroyed
+ * @retval req will be returned
*
* An implementation of an async request might find that it can either finish
* the request without waiting for an external event, or it can't even start
@@ -237,13 +246,8 @@ static void tevent_req_trigger(struct tevent_context *ev,
struct tevent_req *tevent_req_post(struct tevent_req *req,
struct tevent_context *ev)
{
- req->internal.trigger = tevent_add_timer(ev, req, tevent_timeval_zero(),
- tevent_req_trigger, req);
- if (!req->internal.trigger) {
- talloc_free(req);
- return NULL;
- }
-
+ tevent_schedule_immediate(req->internal.trigger,
+ ev, tevent_req_trigger, req);
return req;
}
@@ -256,6 +260,24 @@ bool tevent_req_is_in_progress(struct tevent_req *req)
return false;
}
+/**
+ * @brief This function destroys the attached private data
+ * @param[in] req The finished request
+ *
+ * This function can be called as last action of a _recv()
+ * function, it destroys the data attached to the tevent_req.
+ */
+void tevent_req_received(struct tevent_req *req)
+{
+ TALLOC_FREE(req->data);
+ req->private_print = NULL;
+
+ TALLOC_FREE(req->internal.trigger);
+ TALLOC_FREE(req->internal.timer);
+
+ req->internal.state = TEVENT_REQ_RECEIVED;
+}
+
bool tevent_req_poll(struct tevent_req *req,
struct tevent_context *ev)
{
@@ -292,17 +314,16 @@ static void tevent_req_timedout(struct tevent_context *ev,
struct tevent_req *req = talloc_get_type(private_data,
struct tevent_req);
- talloc_free(req->internal.timer);
- req->internal.timer = NULL;
+ TALLOC_FREE(req->internal.timer);
- tevent_req_finish(req, TEVENT_REQ_TIMED_OUT);
+ tevent_req_finish(req, TEVENT_REQ_TIMED_OUT, __FUNCTION__);
}
bool tevent_req_set_endtime(struct tevent_req *req,
struct tevent_context *ev,
struct timeval endtime)
{
- talloc_free(req->internal.timer);
+ TALLOC_FREE(req->internal.timer);
req->internal.timer = tevent_add_timer(ev, req, endtime,
tevent_req_timedout,
@@ -314,3 +335,23 @@ bool tevent_req_set_endtime(struct tevent_req *req,
return true;
}
+void tevent_req_set_callback(struct tevent_req *req, tevent_req_fn fn, void *pvt)
+{
+ req->async.fn = fn;
+ req->async.private_data = pvt;
+}
+
+void *_tevent_req_callback_data(struct tevent_req *req)
+{
+ return req->async.private_data;
+}
+
+void *_tevent_req_data(struct tevent_req *req)
+{
+ return req->data;
+}
+
+void tevent_req_set_print_fn(struct tevent_req *req, tevent_req_print_fn fn)
+{
+ req->private_print = fn;
+}
diff --git a/lib/tevent/tevent_select.c b/lib/tevent/tevent_select.c
index 32678f0a15..d97418991a 100644
--- a/lib/tevent/tevent_select.c
+++ b/lib/tevent/tevent_select.c
@@ -38,10 +38,6 @@ struct select_event_context {
/* information for exiting from the event loop */
int exit_code;
-
- /* this is incremented when the loop over events causes something which
- could change the events yet to be processed */
- uint32_t destruction_count;
};
/*
@@ -95,8 +91,6 @@ static int select_event_fd_destructor(struct tevent_fd *fde)
if (select_ev->maxfd == fde->fd) {
select_ev->maxfd = EVENT_INVALID_MAXFD;
}
-
- select_ev->destruction_count++;
}
return tevent_common_fd_destructor(fde);
@@ -138,7 +132,6 @@ static int select_event_loop_select(struct select_event_context *select_ev, stru
fd_set r_fds, w_fds;
struct tevent_fd *fde;
int selrtn;
- uint32_t destruction_count = ++select_ev->destruction_count;
/* we maybe need to recalculate the maxfd */
if (select_ev->maxfd == EVENT_INVALID_MAXFD) {
@@ -200,61 +193,52 @@ static int select_event_loop_select(struct select_event_context *select_ev, stru
if (FD_ISSET(fde->fd, &w_fds)) flags |= TEVENT_FD_WRITE;
if (flags) {
fde->handler(select_ev->ev, fde, flags, fde->private_data);
- if (destruction_count != select_ev->destruction_count) {
- break;
- }
+ break;
}
}
}
return 0;
-}
+}
/*
do a single event loop using the events defined in ev
*/
-static int select_event_loop_once(struct tevent_context *ev)
+static int select_event_loop_once(struct tevent_context *ev, const char *location)
{
struct select_event_context *select_ev = talloc_get_type(ev->additional_data,
struct select_event_context);
struct timeval tval;
- tval = tevent_common_loop_timer_delay(ev);
- if (tevent_timeval_is_zero(&tval)) {
+ if (ev->signal_events &&
+ tevent_common_check_signal(ev)) {
return 0;
}
- return select_event_loop_select(select_ev, &tval);
-}
-
-/*
- return on failure or (with 0) if all fd events are removed
-*/
-static int select_event_loop_wait(struct tevent_context *ev)
-{
- struct select_event_context *select_ev = talloc_get_type(ev->additional_data,
- struct select_event_context);
- select_ev->exit_code = 0;
+ if (ev->immediate_events &&
+ tevent_common_loop_immediate(ev)) {
+ return 0;
+ }
- while (ev->fd_events && select_ev->exit_code == 0) {
- if (select_event_loop_once(ev) != 0) {
- break;
- }
+ tval = tevent_common_loop_timer_delay(ev);
+ if (tevent_timeval_is_zero(&tval)) {
+ return 0;
}
- return select_ev->exit_code;
+ return select_event_loop_select(select_ev, &tval);
}
static const struct tevent_ops select_event_ops = {
- .context_init = select_event_context_init,
- .add_fd = select_event_add_fd,
- .set_fd_close_fn= tevent_common_fd_set_close_fn,
- .get_fd_flags = tevent_common_fd_get_flags,
- .set_fd_flags = tevent_common_fd_set_flags,
- .add_timer = tevent_common_add_timer,
- .add_signal = tevent_common_add_signal,
- .loop_once = select_event_loop_once,
- .loop_wait = select_event_loop_wait,
+ .context_init = select_event_context_init,
+ .add_fd = select_event_add_fd,
+ .set_fd_close_fn = tevent_common_fd_set_close_fn,
+ .get_fd_flags = tevent_common_fd_get_flags,
+ .set_fd_flags = tevent_common_fd_set_flags,
+ .add_timer = tevent_common_add_timer,
+ .schedule_immediate = tevent_common_schedule_immediate,
+ .add_signal = tevent_common_add_signal,
+ .loop_once = select_event_loop_once,
+ .loop_wait = tevent_common_loop_wait,
};
bool tevent_select_init(void)
diff --git a/lib/tevent/tevent_standard.c b/lib/tevent/tevent_standard.c
index bbd5c5d785..c3f8b36e84 100644
--- a/lib/tevent/tevent_standard.c
+++ b/lib/tevent/tevent_standard.c
@@ -48,14 +48,6 @@ struct std_event_context {
/* information for exiting from the event loop */
int exit_code;
- /* this is changed by the destructors for the fd event
- type. It is used to detect event destruction by event
- handlers, which means the code that is calling the event
- handler needs to assume that the linked list is no longer
- valid
- */
- uint32_t destruction_count;
-
/* when using epoll this is the handle from epoll_create */
int epoll_fd;
@@ -253,9 +245,8 @@ static void epoll_change_event(struct std_event_context *std_ev, struct tevent_f
static int epoll_event_loop(struct std_event_context *std_ev, struct timeval *tvalp)
{
int ret, i;
-#define MAXEVENTS 8
+#define MAXEVENTS 1
struct epoll_event events[MAXEVENTS];
- uint32_t destruction_count = ++std_ev->destruction_count;
int timeout = -1;
if (std_ev->epoll_fd == -1) return -1;
@@ -316,9 +307,7 @@ static int epoll_event_loop(struct std_event_context *std_ev, struct timeval *tv
if (events[i].events & EPOLLOUT) flags |= TEVENT_FD_WRITE;
if (flags) {
fde->handler(std_ev->ev, fde, flags, fde->private_data);
- if (destruction_count != std_ev->destruction_count) {
- break;
- }
+ break;
}
}
@@ -390,8 +379,6 @@ static int std_event_fd_destructor(struct tevent_fd *fde)
std_ev->maxfd = EVENT_INVALID_MAXFD;
}
- std_ev->destruction_count++;
-
epoll_del_event(std_ev, fde);
}
@@ -459,7 +446,6 @@ static int std_event_loop_select(struct std_event_context *std_ev, struct timeva
fd_set r_fds, w_fds;
struct tevent_fd *fde;
int selrtn;
- uint32_t destruction_count = ++std_ev->destruction_count;
/* we maybe need to recalculate the maxfd */
if (std_ev->maxfd == EVENT_INVALID_MAXFD) {
@@ -521,9 +507,7 @@ static int std_event_loop_select(struct std_event_context *std_ev, struct timeva
if (FD_ISSET(fde->fd, &w_fds)) flags |= TEVENT_FD_WRITE;
if (flags) {
fde->handler(std_ev->ev, fde, flags, fde->private_data);
- if (destruction_count != std_ev->destruction_count) {
- break;
- }
+ break;
}
}
}
@@ -534,12 +518,22 @@ static int std_event_loop_select(struct std_event_context *std_ev, struct timeva
/*
do a single event loop using the events defined in ev
*/
-static int std_event_loop_once(struct tevent_context *ev)
+static int std_event_loop_once(struct tevent_context *ev, const char *location)
{
struct std_event_context *std_ev = talloc_get_type(ev->additional_data,
struct std_event_context);
struct timeval tval;
+ if (ev->signal_events &&
+ tevent_common_check_signal(ev)) {
+ return 0;
+ }
+
+ if (ev->immediate_events &&
+ tevent_common_loop_immediate(ev)) {
+ return 0;
+ }
+
tval = tevent_common_loop_timer_delay(ev);
if (tevent_timeval_is_zero(&tval)) {
return 0;
@@ -554,34 +548,17 @@ static int std_event_loop_once(struct tevent_context *ev)
return std_event_loop_select(std_ev, &tval);
}
-/*
- return on failure or (with 0) if all fd events are removed
-*/
-static int std_event_loop_wait(struct tevent_context *ev)
-{
- struct std_event_context *std_ev = talloc_get_type(ev->additional_data,
- struct std_event_context);
- std_ev->exit_code = 0;
-
- while (ev->fd_events && std_ev->exit_code == 0) {
- if (std_event_loop_once(ev) != 0) {
- break;
- }
- }
-
- return std_ev->exit_code;
-}
-
static const struct tevent_ops std_event_ops = {
- .context_init = std_event_context_init,
- .add_fd = std_event_add_fd,
- .set_fd_close_fn= tevent_common_fd_set_close_fn,
- .get_fd_flags = tevent_common_fd_get_flags,
- .set_fd_flags = std_event_set_fd_flags,
- .add_timer = tevent_common_add_timer,
- .add_signal = tevent_common_add_signal,
- .loop_once = std_event_loop_once,
- .loop_wait = std_event_loop_wait,
+ .context_init = std_event_context_init,
+ .add_fd = std_event_add_fd,
+ .set_fd_close_fn = tevent_common_fd_set_close_fn,
+ .get_fd_flags = tevent_common_fd_get_flags,
+ .set_fd_flags = std_event_set_fd_flags,
+ .add_timer = tevent_common_add_timer,
+ .schedule_immediate = tevent_common_schedule_immediate,
+ .add_signal = tevent_common_add_signal,
+ .loop_once = std_event_loop_once,
+ .loop_wait = tevent_common_loop_wait,
};
diff --git a/lib/tsocket/config.mk b/lib/tsocket/config.mk
new file mode 100644
index 0000000000..c35f0afd6f
--- /dev/null
+++ b/lib/tsocket/config.mk
@@ -0,0 +1,17 @@
+[SUBSYSTEM::LIBTSOCKET]
+PRIVATE_DEPENDENCIES = LIBTALLOC LIBTEVENT LIBREPLACE_NETWORK
+
+LIBTSOCKET_OBJ_FILES = $(addprefix ../lib/tsocket/, \
+ tsocket.o \
+ tsocket_helpers.o \
+ tsocket_bsd.o \
+ tsocket_recvfrom.o \
+ tsocket_sendto.o \
+ tsocket_connect.o \
+ tsocket_writev.o \
+ tsocket_readv.o)
+
+PUBLIC_HEADERS += $(addprefix ../lib/tsocket/, \
+ tsocket.h\
+ tsocket_internal.h)
+
diff --git a/lib/tsocket/tsocket.c b/lib/tsocket/tsocket.c
new file mode 100644
index 0000000000..1a12e691a9
--- /dev/null
+++ b/lib/tsocket/tsocket.c
@@ -0,0 +1,231 @@
+/*
+ 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"
+
+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);
+}
+
+ssize_t tsocket_recvfrom(struct tsocket_context *sock,
+ uint8_t *data, size_t len,
+ TALLOC_CTX *addr_ctx,
+ struct tsocket_address **src_addr)
+{
+ return sock->ops->recvfrom_data(sock, data, len, addr_ctx, src_addr);
+}
+
+ssize_t tsocket_sendto(struct tsocket_context *sock,
+ const uint8_t *data, size_t len,
+ const struct tsocket_address *dest_addr)
+{
+ return sock->ops->sendto_data(sock, data, len, dest_addr);
+}
+
+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,
+ size_t psize,
+ const char *type,
+ const char *location)
+{
+ void **ppstate = (void **)pstate;
+ struct tsocket_address *addr;
+
+ addr = talloc_zero(mem_ctx, struct tsocket_address);
+ if (!addr) {
+ return NULL;
+ }
+ addr->ops = ops;
+ addr->location = location;
+ addr->private_data = talloc_size(addr, psize);
+ if (!addr->private_data) {
+ talloc_free(addr);
+ return NULL;
+ }
+ talloc_set_name_const(addr->private_data, type);
+
+ *ppstate = addr->private_data;
+ return addr;
+}
+
+char *tsocket_address_string(const struct tsocket_address *addr,
+ TALLOC_CTX *mem_ctx)
+{
+ if (!addr) {
+ return talloc_strdup(mem_ctx, "NULL");
+ }
+ return addr->ops->string(addr, mem_ctx);
+}
+
+struct tsocket_address *_tsocket_address_copy(const struct tsocket_address *addr,
+ TALLOC_CTX *mem_ctx,
+ const char *location)
+{
+ 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);
+}
+
diff --git a/lib/tsocket/tsocket.h b/lib/tsocket/tsocket.h
new file mode 100644
index 0000000000..9bcfb5cb7e
--- /dev/null
+++ b/lib/tsocket/tsocket.h
@@ -0,0 +1,220 @@
+/*
+ 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/>.
+*/
+
+#ifndef _TSOCKET_H
+#define _TSOCKET_H
+
+#include <talloc.h>
+#include <tevent.h>
+
+struct tsocket_context;
+struct tsocket_address;
+struct iovec;
+
+enum tsocket_type {
+ TSOCKET_TYPE_STREAM = 1,
+ TSOCKET_TYPE_DGRAM,
+ 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);
+
+ssize_t tsocket_recvfrom(struct tsocket_context *sock,
+ uint8_t *data, size_t len,
+ TALLOC_CTX *addr_ctx,
+ struct tsocket_address **src_addr);
+ssize_t tsocket_sendto(struct tsocket_context *sock,
+ const uint8_t *data, size_t len,
+ const struct tsocket_address *dest_addr);
+
+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);
+
+char *tsocket_address_string(const struct tsocket_address *addr,
+ TALLOC_CTX *mem_ctx);
+
+struct tsocket_address *_tsocket_address_copy(const struct tsocket_address *addr,
+ TALLOC_CTX *mem_ctx,
+ const char *location);
+
+#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__)
+
+/*
+ * BSD sockets: inet, inet6 and unix
+ */
+
+int _tsocket_address_inet_from_strings(TALLOC_CTX *mem_ctx,
+ const char *fam,
+ const char *addr,
+ uint16_t port,
+ struct tsocket_address **_addr,
+ const char *location);
+#define tsocket_address_inet_from_strings(mem_ctx, fam, addr, port, _addr) \
+ _tsocket_address_inet_from_strings(mem_ctx, fam, addr, port, _addr, \
+ __location__)
+
+char *tsocket_address_inet_addr_string(const struct tsocket_address *addr,
+ TALLOC_CTX *mem_ctx);
+uint16_t tsocket_address_inet_port(const struct tsocket_address *addr);
+int tsocket_address_inet_set_port(struct tsocket_address *addr,
+ uint16_t port);
+void tsocket_address_inet_set_broadcast(struct tsocket_address *addr,
+ bool broadcast);
+
+int _tsocket_address_unix_from_path(TALLOC_CTX *mem_ctx,
+ const char *path,
+ struct tsocket_address **_addr,
+ const char *location);
+#define tsocket_address_unix_from_path(mem_ctx, path, _addr) \
+ _tsocket_address_unix_from_path(mem_ctx, path, _addr, \
+ __location__)
+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__)
+
+/*
+ * Async helpers
+ */
+
+struct tevent_req *tsocket_recvfrom_send(struct tsocket_context *sock,
+ TALLOC_CTX *mem_ctx);
+ssize_t tsocket_recvfrom_recv(struct tevent_req *req,
+ int *perrno,
+ TALLOC_CTX *mem_ctx,
+ uint8_t **buf,
+ struct tsocket_address **src);
+
+struct tevent_req *tsocket_sendto_send(struct tsocket_context *sock,
+ TALLOC_CTX *mem_ctx,
+ const uint8_t *buf,
+ size_t len,
+ const struct tsocket_address *dst);
+ssize_t tsocket_sendto_recv(struct tevent_req *req, int *perrno);
+
+struct tevent_req *tsocket_sendto_queue_send(TALLOC_CTX *mem_ctx,
+ struct tsocket_context *sock,
+ struct tevent_queue *queue,
+ const uint8_t *buf,
+ size_t len,
+ struct tsocket_address *dst);
+ssize_t tsocket_sendto_queue_recv(struct tevent_req *req, int *perrno);
+
+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);
+
+#endif /* _TSOCKET_H */
+
diff --git a/lib/tsocket/tsocket_bsd.c b/lib/tsocket/tsocket_bsd.c
new file mode 100644
index 0000000000..2811882fed
--- /dev/null
+++ b/lib/tsocket/tsocket_bsd.c
@@ -0,0 +1,1126 @@
+/*
+ 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"
+
+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 sin;
+#ifdef HAVE_IPV6
+ struct sockaddr_in6 sin6;
+#endif
+ struct sockaddr_un sun;
+ struct sockaddr_storage ss;
+ } 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)
+{
+ struct tsocket_address *addr;
+ struct tsocket_address_bsd *bsda;
+
+ switch (sa->sa_family) {
+ case AF_UNIX:
+ if (sa_len < sizeof(struct sockaddr_un)) {
+ errno = EINVAL;
+ return -1;
+ }
+ break;
+ case AF_INET:
+ if (sa_len < sizeof(struct sockaddr_in)) {
+ errno = EINVAL;
+ return -1;
+ }
+ break;
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ if (sa_len < sizeof(struct sockaddr_in6)) {
+ errno = EINVAL;
+ return -1;
+ }
+ break;
+#endif
+ default:
+ errno = EAFNOSUPPORT;
+ return -1;
+ }
+
+ if (sa_len > sizeof(struct sockaddr_storage)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ addr = tsocket_address_create(mem_ctx,
+ &tsocket_address_bsd_ops,
+ &bsda,
+ struct tsocket_address_bsd,
+ location);
+ if (!addr) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ ZERO_STRUCTP(bsda);
+
+ memcpy(&bsda->u.ss, sa, sa_len);
+
+ *_addr = addr;
+ return 0;
+}
+
+int _tsocket_address_inet_from_strings(TALLOC_CTX *mem_ctx,
+ const char *fam,
+ const char *addr,
+ uint16_t port,
+ struct tsocket_address **_addr,
+ const char *location)
+{
+ struct addrinfo hints;
+ struct addrinfo *result = NULL;
+ char port_str[6];
+ int ret;
+
+ ZERO_STRUCT(hints);
+ /*
+ * we use SOCKET_STREAM here to get just one result
+ * back from getaddrinfo().
+ */
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV;
+
+ if (strcasecmp(fam, "ip") == 0) {
+ hints.ai_family = AF_UNSPEC;
+ if (!addr) {
+#ifdef HAVE_IPV6
+ addr = "::";
+#else
+ addr = "0.0.0.0";
+#endif
+ }
+ } else if (strcasecmp(fam, "ipv4") == 0) {
+ hints.ai_family = AF_INET;
+ if (!addr) {
+ addr = "0.0.0.0";
+ }
+#ifdef HAVE_IPV6
+ } else if (strcasecmp(fam, "ipv6") == 0) {
+ hints.ai_family = AF_INET6;
+ if (!addr) {
+ addr = "::";
+ }
+#endif
+ } else {
+ errno = EAFNOSUPPORT;
+ return -1;
+ }
+
+ snprintf(port_str, sizeof(port_str) - 1, "%u", port);
+
+ ret = getaddrinfo(addr, port_str, &hints, &result);
+ if (ret != 0) {
+ switch (ret) {
+ case EAI_FAIL:
+ errno = EINVAL;
+ break;
+ }
+ ret = -1;
+ goto done;
+ }
+
+ if (result->ai_socktype != SOCK_STREAM) {
+ errno = EINVAL;
+ ret = -1;
+ goto done;
+ }
+
+ ret = _tsocket_address_bsd_from_sockaddr(mem_ctx,
+ result->ai_addr,
+ result->ai_addrlen,
+ _addr,
+ location);
+
+done:
+ if (result) {
+ freeaddrinfo(result);
+ }
+ return ret;
+}
+
+char *tsocket_address_inet_addr_string(const struct tsocket_address *addr,
+ TALLOC_CTX *mem_ctx)
+{
+ struct tsocket_address_bsd *bsda = talloc_get_type(addr->private_data,
+ struct tsocket_address_bsd);
+ char addr_str[INET6_ADDRSTRLEN+1];
+ const char *str;
+
+ if (!bsda) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ switch (bsda->u.sa.sa_family) {
+ case AF_INET:
+ str = inet_ntop(bsda->u.sin.sin_family,
+ &bsda->u.sin.sin_addr,
+ addr_str, sizeof(addr_str));
+ break;
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ str = inet_ntop(bsda->u.sin6.sin6_family,
+ &bsda->u.sin6.sin6_addr,
+ addr_str, sizeof(addr_str));
+ break;
+#endif
+ default:
+ errno = EINVAL;
+ return NULL;
+ }
+
+ if (!str) {
+ return NULL;
+ }
+
+ return talloc_strdup(mem_ctx, str);
+}
+
+uint16_t tsocket_address_inet_port(const struct tsocket_address *addr)
+{
+ struct tsocket_address_bsd *bsda = talloc_get_type(addr->private_data,
+ struct tsocket_address_bsd);
+ uint16_t port = 0;
+
+ if (!bsda) {
+ errno = EINVAL;
+ return 0;
+ }
+
+ switch (bsda->u.sa.sa_family) {
+ case AF_INET:
+ port = ntohs(bsda->u.sin.sin_port);
+ break;
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ port = ntohs(bsda->u.sin6.sin6_port);
+ break;
+#endif
+ default:
+ errno = EINVAL;
+ return 0;
+ }
+
+ return port;
+}
+
+int tsocket_address_inet_set_port(struct tsocket_address *addr,
+ uint16_t port)
+{
+ struct tsocket_address_bsd *bsda = talloc_get_type(addr->private_data,
+ struct tsocket_address_bsd);
+
+ if (!bsda) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ switch (bsda->u.sa.sa_family) {
+ case AF_INET:
+ bsda->u.sin.sin_port = htons(port);
+ break;
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ bsda->u.sin6.sin6_port = htons(port);
+ break;
+#endif
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+
+ 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,
+ const char *location)
+{
+ struct sockaddr_un sun;
+ void *p = &sun;
+ int ret;
+
+ if (!path) {
+ path = "";
+ }
+
+ ZERO_STRUCT(sun);
+ sun.sun_family = AF_UNIX;
+ strncpy(sun.sun_path, path, sizeof(sun.sun_path));
+
+ ret = _tsocket_address_bsd_from_sockaddr(mem_ctx,
+ (struct sockaddr *)p,
+ sizeof(sun),
+ _addr,
+ location);
+
+ return ret;
+}
+
+char *tsocket_address_unix_path(const struct tsocket_address *addr,
+ TALLOC_CTX *mem_ctx)
+{
+ struct tsocket_address_bsd *bsda = talloc_get_type(addr->private_data,
+ struct tsocket_address_bsd);
+ const char *str;
+
+ if (!bsda) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ switch (bsda->u.sa.sa_family) {
+ case AF_UNIX:
+ str = bsda->u.sun.sun_path;
+ break;
+ default:
+ errno = EINVAL;
+ return NULL;
+ }
+
+ return talloc_strdup(mem_ctx, str);
+}
+
+static char *tsocket_address_bsd_string(const struct tsocket_address *addr,
+ TALLOC_CTX *mem_ctx)
+{
+ struct tsocket_address_bsd *bsda = talloc_get_type(addr->private_data,
+ struct tsocket_address_bsd);
+ char *str;
+ char *addr_str;
+ const char *prefix = NULL;
+ uint16_t port;
+
+ switch (bsda->u.sa.sa_family) {
+ case AF_UNIX:
+ return talloc_asprintf(mem_ctx, "unix:%s",
+ bsda->u.sun.sun_path);
+ case AF_INET:
+ prefix = "ipv4";
+ break;
+ case AF_INET6:
+ prefix = "ipv6";
+ break;
+ default:
+ errno = EINVAL;
+ return NULL;
+ }
+
+ addr_str = tsocket_address_inet_addr_string(addr, mem_ctx);
+ if (!addr_str) {
+ return NULL;
+ }
+
+ port = tsocket_address_inet_port(addr);
+
+ str = talloc_asprintf(mem_ctx, "%s:%s:%u",
+ prefix, addr_str, port);
+ talloc_free(addr_str);
+
+ return str;
+}
+
+static struct tsocket_address *tsocket_address_bsd_copy(const struct tsocket_address *addr,
+ TALLOC_CTX *mem_ctx,
+ const char *location)
+{
+ struct tsocket_address_bsd *bsda = talloc_get_type(addr->private_data,
+ struct tsocket_address_bsd);
+ struct tsocket_address *copy;
+ int ret;
+
+ ret = _tsocket_address_bsd_from_sockaddr(mem_ctx,
+ &bsda->u.sa,
+ sizeof(bsda->u.ss),
+ &copy,
+ location);
+ if (ret != 0) {
+ 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;
+ case TSOCKET_TYPE_DGRAM:
+ bsd_type = SOCK_DGRAM;
+ 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.sun.sun_path[0] != 0) {
+ do_bind = true;
+ }
+ break;
+ case AF_INET:
+ if (bsda->u.sin.sin_port != 0) {
+ do_reuseaddr = true;
+ do_bind = true;
+ }
+ if (bsda->u.sin.sin_addr.s_addr == INADDR_ANY) {
+ do_bind = true;
+ }
+ break;
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ if (bsda->u.sin6.sin6_port != 0) {
+ do_reuseaddr = true;
+ do_bind = true;
+ }
+ if (memcmp(&in6addr_any,
+ &bsda->u.sin6.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 ssize_t tsocket_context_bsd_recvfrom_data(struct tsocket_context *sock,
+ uint8_t *data, size_t len,
+ TALLOC_CTX *addr_ctx,
+ struct tsocket_address **remote)
+{
+ struct tsocket_context_bsd *bsds = talloc_get_type(sock->private_data,
+ struct tsocket_context_bsd);
+ struct tsocket_address *addr = NULL;
+ struct tsocket_address_bsd *bsda;
+ ssize_t ret;
+ struct sockaddr *sa = NULL;
+ socklen_t sa_len = 0;
+
+ if (remote) {
+ addr = tsocket_address_create(addr_ctx,
+ &tsocket_address_bsd_ops,
+ &bsda,
+ struct tsocket_address_bsd,
+ __location__ "recvfrom");
+ if (!addr) {
+ return -1;
+ }
+
+ ZERO_STRUCTP(bsda);
+
+ sa = &bsda->u.sa;
+ sa_len = sizeof(bsda->u.ss);
+ }
+
+ ret = recvfrom(bsds->fd, data, len, 0, sa, &sa_len);
+ if (ret < 0) {
+ int saved_errno = errno;
+ talloc_free(addr);
+ errno = saved_errno;
+ return ret;
+ }
+
+ if (remote) {
+ *remote = addr;
+ }
+ return ret;
+}
+
+static ssize_t tsocket_context_bsd_sendto_data(struct tsocket_context *sock,
+ const uint8_t *data, size_t len,
+ const struct tsocket_address *remote)
+{
+ struct tsocket_context_bsd *bsds = talloc_get_type(sock->private_data,
+ struct tsocket_context_bsd);
+ struct sockaddr *sa = NULL;
+ socklen_t sa_len = 0;
+ ssize_t ret;
+
+ if (remote) {
+ struct tsocket_address_bsd *bsda =
+ talloc_get_type(remote->private_data,
+ struct tsocket_address_bsd);
+
+ sa = &bsda->u.sa;
+ sa_len = sizeof(bsda->u.ss);
+ }
+
+ ret = sendto(bsds->fd, data, len, 0, sa, sa_len);
+
+ 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,
+ .recvfrom_data = tsocket_context_bsd_recvfrom_data,
+ .sendto_data = tsocket_context_bsd_sendto_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
+};
diff --git a/lib/tsocket/tsocket_connect.c b/lib/tsocket/tsocket_connect.c
new file mode 100644
index 0000000000..7a9d4b8381
--- /dev/null
+++ b/lib/tsocket/tsocket_connect.c
@@ -0,0 +1,122 @@
+/*
+ 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_guide.txt b/lib/tsocket/tsocket_guide.txt
new file mode 100644
index 0000000000..a02fa373fa
--- /dev/null
+++ b/lib/tsocket/tsocket_guide.txt
@@ -0,0 +1,503 @@
+
+Basic design of the tsocket abstraction
+=======================================
+
+The tsocket layer is designed to match more or less
+the bsd socket layer, but it hides the filedescriptor
+within a opaque 'tsocket_context' structure to make virtual
+sockets possible. The virtual sockets can be encrypted tunnels
+(like TLS, SASL or GSSAPI) or named pipes over smb.
+
+The tsocket layer is a bit like an abstract class, which defines
+common methods to work with sockets in a non blocking fashion.
+
+The whole library is based on the talloc(3) and 'tevent' libraries.
+
+The 'tsocket_address' structure is the 2nd abstracted class
+which represends the address of a socket endpoint.
+
+Each different type of socket has its own constructor.
+
+Typically the constructor for a tsocket_context is attached to
+the tsocket_address of the source endpoint. That means
+the tsocket_address_create_socket() function takes the
+tsocket_address of the local endpoint and creates a tsocket_context
+for the communication.
+
+For some usecases it's possible to wrap an existing socket into a
+tsocket_context, e.g. to wrap an existing pipe(2) into
+tsocket_context, so that you can use the same functions to
+communicate over the pipe.
+
+The tsocket_address abstraction
+===============================
+
+The tsocket_address represents an socket endpoint genericly.
+As it's like an abstract class it has no specific constructor.
+The specific constructors are descripted later sections.
+
+There's a function get the string representation of the
+endpoint for debugging. Callers should not try to parse
+the string! The should use additional methods of the specific
+tsocket_address implemention to get more details.
+
+ char *tsocket_address_string(const struct tsocket_address *addr,
+ TALLOC_CTX *mem_ctx);
+
+There's a function to create a copy of the tsocket_address.
+This is useful when before doing modifications to a socket
+via additional methods of the specific tsocket_address implementation.
+
+ struct tsocket_address *tsocket_address_copy(const struct tsocket_address *addr,
+ TALLOC_CTX *mem_ctx);
+
+There's a function to create a tsocket_context based on the given local
+socket endpoint. The return value is 0 on success and -1 on failure
+with errno holding the specific error. Specific details are descripted in later
+sections. Note not all specific implementation have to implement all socket
+types.
+
+ enum tsocket_type {
+ TSOCKET_TYPE_STREAM = 1,
+ TSOCKET_TYPE_DGRAM,
+ TSOCKET_TYPE_MESSAGE
+ };
+
+ int tsocket_address_create_socket(const struct tsocket_address *addr,
+ enum tsocket_type type,
+ TALLOC_CTX *mem_ctx,
+ struct tsocket_context **sock);
+
+The tsocket_context abstraction
+===============================
+
+The tsocket_context is like an abstract class and represents
+a socket similar to bsd style sockets. The methods are more
+or less equal to the bsd socket api, while the filedescriptor
+is replaced by tsocket_context and sockaddr, socklen_t pairs
+are replaced by tsocket_address. The 'bind' operation happens
+in the specific constructor as the constructor is typically based
+on tsocket_address of local socket endpoint.
+
+All operations are by design non blocking and can return error
+values like EAGAIN, EINPROGRESS, EWOULDBLOCK or EINTR which
+indicate that the caller should retry the operation later.
+Also read the "The glue to tevent" section.
+
+The socket can of types:
+ - TSOCKET_TYPE_STREAM is the equivalent to SOCK_STREAM in the bsd socket api.
+ - TSOCKET_TYPE_DGRAM is the equivalent to SOCK_DGRAM in the bsd socket api.
+ - TSOCKET_TYPE_MESSAGE operates on a connected socket and is therefore
+ like TSOCKET_TYPE_STREAM, but the consumer needs to first read all
+ data of a message, which was generated by one message 'write' on the sender,
+ before the consumer gets data of the next message. This matches a bit
+ like message mode pipes on windows. The concept is to transfer ordered
+ messages between to endpoints.
+
+There's a function to connect to a remote endpoint. The behavior
+and error codes match the connect(2) function of the bsd socket api.
+Maybe the specific tsocket_context implementation speficied some
+further details.
+
+ int tsocket_connect(struct tsocket_context *sock,
+ const struct tsocket_address *remote_addr);
+
+There's a function to listen for incoming connections. The behavior
+and error codes match the listen(2) function of the bsd socket api.
+Maybe the specific tsocket_context implementation speficied some
+further details.
+
+ int tsocket_listen(struct tsocket_context *sock,
+ int queue_size);
+
+There's a function to accept incoming connections. The behavior
+and error codes match the accept(2) function of the bsd socket api.
+Maybe the specific tsocket_context implementation speficied some
+further details.
+
+ int tsocket_accept(struct tsocket_context *sock,
+ TALLOC_CTX *mem_ctx,
+ struct tsocket_context **new_sock);
+
+There's a function to ask how many bytes are in input buffer
+of the connection. For sockets of type TSOCKET_TYPE_DGRAM or
+TSOCKET_TYPE_MESSAGE the size of the next available dgram/message
+is returned. A return value of -1 indicates a socket error
+and errno will hold the specific error code. If no data
+is available 0 is returned, but retry error codes like
+EINTR can also be returned.
+
+ ssize_t tsocket_pending(struct tsocket_context *sock);
+
+There's a function to read data from the socket. The behavior
+and error codes match the readv(3) function, also take a look
+at the recv(2) function of the bsd socket api.
+Maybe the specific tsocket_context implementation speficied some
+further details.
+
+ int tsocket_readv(struct tsocket_context *sock,
+ const struct iovec *vector, size_t count);
+
+There's a function to write data from the socket. The behavior
+and error codes match the writev(3) function, also take a look
+at the send(2) function of the bsd socket api.
+Maybe the specific tsocket_context implementation speficied some
+further details.
+
+ int tsocket_writev(struct tsocket_context *sock,
+ const struct iovec *vector, size_t count);
+
+There's a function to read a datagram from a remote endpoint.
+The behavior and error codes match the recvfrom(2) function of
+the bsd socket api. As TSOCKET_TYPE_DGRAM sockets can also be
+used in connected mode src_addr can be NULL, if the caller don't
+want to get the source address. Maybe the specific tsocket_context
+implementation speficied some further details.
+
+ ssize_t tsocket_recvfrom(struct tsocket_context *sock,
+ uint8_t *data, size_t len,
+ TALLOC_CTX *addr_ctx,
+ struct tsocket_address **src_addr);
+
+There's a function to send a datagram to a remote endpoint the socket.
+The behavior and error codes match the recvfrom(2) function of the
+bsd socket api. As TSOCKET_TYPE_DGRAM sockets can also be used in
+connected mode dest_addr must be NULL in connected mode and a valid
+tsocket_address otherwise. Maybe the specific tsocket_context
+implementation speficied some further details.
+
+ ssize_t tsocket_sendto(struct tsocket_context *sock,
+ const uint8_t *data, size_t len,
+ const struct tsocket_address *dest_addr);
+
+There's a function to get the current status of the socket.
+The behavior and error codes match the getsockopt(2) function
+of the bsd socket api, with SOL_SOCKET and SO_ERROR as arguments.
+Maybe the specific tsocket_context implementation speficied some
+further details.
+
+ int tsocket_get_status(const struct tsocket_context *sock);
+
+There's a function to get tsocket_address of the local endpoint.
+The behavior and error codes match the getsockname(2) function
+of the bsd socket api. Maybe the specific tsocket_context
+implementation speficied some further details.
+
+ int tsocket_get_local_address(const struct tsocket_context *sock,
+ TALLOC_CTX *mem_ctx,
+ struct tsocket_address **local_addr);
+
+There's a function to get tsocket_address of the remote endpoint
+of a connected socket. The behavior and error codes match the
+getpeername(2) function of the bsd socket api. Maybe the specific
+tsocket_context implementation speficied some further details.
+
+ int tsocket_get_remote_address(const struct tsocket_context *sock,
+ TALLOC_CTX *mem_ctx,
+ struct tsocket_address **remote_addr,
+ const char *location);
+
+There's a function to ask for specific options of the socket.
+The behavior and error codes match the getsockopt(2) function
+of the bsd socket api. The option and value are represented as string
+values, where the 'value' parameter can be NULL is the caller don't want to
+get the value. The supported options and values are up to the specific
+tsocket_context implementation.
+
+ int tsocket_get_option(const struct tsocket_context *sock,
+ const char *option,
+ TALLOC_CTX *mem_ctx,
+ char **value);
+
+There's a function to set specific options of the socket.
+The behavior and error codes match the setsockopt(2) function
+of the bsd socket api. The option and value are represented as string
+values, where the 'value' parameter can be NULL. The supported options
+and values are up to the specific tsocket_context implementation.
+The 'force' parameter specifies whether an error should be returned
+for unsupported options.
+
+ int tsocket_set_option(const struct tsocket_context *sock,
+ const char *option,
+ bool force,
+ const char *value);
+
+There's a function to disconnect the socket. The behavior
+and error codes match the close(2) function of the bsd socket api.
+Maybe the specific tsocket_context implementation speficied some
+further details.
+
+ void tsocket_disconnect(struct tsocket_context *sock);
+
+The glue to tevent
+==================
+
+As the tsocket library is based on the tevent library,
+there need to be functions to let the caller register
+callback functions, which are triggered when the socket
+is writeable or readable. Typically one would use
+tevent fd events, but in order to hide the filedescriptor
+the tsocket_context abstraction has their own functions.
+
+There's a function to set the currently active tevent_context
+for the socket. It's important there's only one tevent_context
+actively used with the socket. A second call will cancel
+all low level events made on the old tevent_context, it will
+also resets the send and recv handlers to NULL. If the caller
+sets attaches a new event context to the socket, the callback
+function also need to be registered again. It's important
+that the caller keeps the given tevent_context in memory
+and actively calls tsocket_set_event_context(sock, NULL)
+before calling talloc_free(event_context).
+The function returns 0 on success and -1 together with an errno
+on failure.
+
+ int tsocket_set_event_context(struct tsocket_context *sock,
+ struct tevent_context *ev);
+
+There's a function to register a callback function which is called
+when the socket is readable. If the caller don't want to get notified
+anymore the function should be called with NULL as handler.
+The function returns 0 on success and -1 together with an errno
+on failure.
+
+ typedef void (*tsocket_event_handler_t)(struct tsocket_context *, void *);
+ int tsocket_set_readable_handler(struct tsocket_context *sock,
+ tsocket_event_handler_t handler,
+ void *private_data);
+
+There's a function to register a callback function which is called
+when the socket is writeable. If the caller don't want to get notified
+anymore the function should be called with NULL as handler.
+The function returns 0 on success and -1 together with an errno
+on failure.
+
+ typedef void (*tsocket_event_handler_t)(struct tsocket_context *, void *);
+ int tsocket_set_writeable_handler(struct tsocket_context *sock,
+ tsocket_event_handler_t handler,
+ void *private_data);
+
+Note: if the socket is readable and writeable, only the writeable
+ handler is called, this avoids deadlocks at the application level.
+
+Async helper functions
+======================
+
+To make the life easier for the callers, there're 'tevent_req' based
+helper functions for non-blocking io-operations. For each of this functions
+to work the caller must attach the tevent_context to the tsocket_context
+with tsocket_set_event_context(). Please remember that attching a new
+tevent_context will reset the event state of the socket and should only
+be done, when there's no async request is pending on the socket!
+
+The detailed calling conventions for 'tevent_req' based programming
+will be explained in the 'tevent' documentation.
+
+To receive the next availabe datagram from socket there's a wrapper
+for tsocket_recvfrom(). The caller virtually sends its desire to receive
+the next available datagram by calling the tsocket_recvfrom_send() function
+and attaches a callback function to the returned tevent_req via tevent_req_set_callback().
+The callback function is called when a datagram is available or an error has happened.
+The callback function needs to get the result by calling
+tsocket_recvfrom_recv(). The return value of tsocket_recvfrom_recv()
+matches the return value from tsocket_recvfrom(). A possible errno is delivered
+via the perrno parameter instead of the global errno variable. The datagram
+buffer and optional the source tsocket_address of the datagram are returned as talloc
+childs of the mem_ctx passed to tsocket_recvfrom_recv().
+It's important that the caller garanties that there's only one async
+read request on the socket at a time.
+
+ struct tevent_req *tsocket_recvfrom_send(struct tsocket_context *sock,
+ TALLOC_CTX *mem_ctx);
+ ssize_t tsocket_recvfrom_recv(struct tevent_req *req,
+ int *perrno,
+ TALLOC_CTX *mem_ctx,
+ uint8_t **buf,
+ struct tsocket_address **src);
+
+To send a datagram there's a wrapper for tsocket_sendto().
+The caller calls tsocket_sendto_send() instead of tsocket_sendto()
+which returns a tevent_req allocated on the given TALLOC_CTX.
+The caller attaches a callback function to the returned tevent_req via
+tevent_req_set_callback(). The callback function is called when a datagram was
+deliviered into the socket or an error has happened.
+The callback function needs to get the result by calling
+tsocket_sendto_recv(). The return value of tsocket_sendto_recv()
+matches the return value from tsocket_sendto(). A possible errno is delivered
+via the perrno parameter instead of the global errno variable.
+Normal callers should not use this function directly, they should use
+tsocket_sendto_queue_send/recv() instead.
+
+ struct tevent_req *tsocket_sendto_send(struct tsocket_context *sock,
+ TALLOC_CTX *mem_ctx,
+ const uint8_t *buf,
+ size_t len,
+ const struct tsocket_address *dst);
+ ssize_t tsocket_sendto_recv(struct tevent_req *req, int *perrno);
+
+As only one async tsocket_sendto() call should happen at a time,
+there's a 'tevent_queue' is used to serialize the sendto requests.
+
+ struct tevent_req *tsocket_sendto_queue_send(TALLOC_CTX *mem_ctx,
+ struct tsocket_context *sock,
+ struct tevent_queue *queue,
+ const uint8_t *buf,
+ size_t len,
+ struct tsocket_address *dst);
+ ssize_t tsocket_sendto_queue_recv(struct tevent_req *req, int *perrno);
+
+Ther's an async helper for tsocket_connect(), which should be used
+to connect TSOCKET_TYPE_STREAM based sockets.
+The caller virtually sends its desire to connect to the destination
+tsocket_address by calling tsocket_connect_send() and gets back a tevent_req.
+The caller sets a callback function via tevent_req_set_callback().
+The callback function is called if the tsocket is connected or an error has happened.
+The callback function needs to get the result by calling
+tsocket_connect_recv(). The return value of tsocket_connect_recv()
+matches the return value from tsocket_connect()/tsocket_get_status().
+A possible errno is delivered via the perrno parameter instead of the global
+errno variable.
+
+ 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);
+
+To send an 'iovec' there's a wrapper for tsocket_writev().
+The caller calls tsocket_writev_send() instead of tsocket_writev()
+which returns a tevent_req allocated on the given TALLOC_CTX.
+The caller attaches a callback function to the returned tevent_req via
+tevent_req_set_callback(). The callback function is called when the whole iovec
+was deliviered into the socket or an error has happened.
+The callback function needs to get the result by calling
+tsocket_writev_recv(). The return value of tsocket_writev_recv()
+matches the return value from tsocket_writev(). A possible errno is delivered
+via the perrno parameter instead of the global errno variable.
+Normal callers should not use this function directly, they should use
+tsocket_writev_queue_send/recv() instead.
+
+ 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);
+
+As only one async tsocket_writev() call should happen at a time,
+there's a 'tevent_queue' is used to serialize the writev requests.
+
+ 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);
+
+For TSOCKET_TYPE_STREAM sockets, it's typically desired to split the stream
+into PDUs. That's why the helper function for tsocket_readv() is a bit
+different compared to the other helper functions. The general rule
+is still to get a tevent_req, set a callback which gets called when the
+operation is done. The callback function needs to get the result by
+calling tsocket_readv_recv(). The 'next_iovec' callback function
+makes the difference to the other helper function.
+The tsocket_writev_send/recv() logic asks the caller via the
+next_iovec_fn for an iovec array, which will be filled completely
+with bytes from the socket, then the next_iovec_fn is called for
+the next iovec array to fill, untill the next_iovec_fn returns an empty
+iovec array. That next_iovec_fn should allocate the array as child of the
+passed mem_ctx, while the buffers the array referr to belong to the caller.
+The tsocket_writev_send/recv() engine will modify and free the given array!
+The basic idea is that the caller allocates and maintains the real buffers.
+The next_iovec_fn should report error by returning -1 and setting errno to
+the specific error code. The engine will pass the error to the caller
+via tsocket_readv_recv().
+
+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);
+
+Wrapper for BSD style sockets
+=============================
+
+Support for BSD style sockets of AF_INET, AF_INET6 and AF_UNIX
+are part of the main tsocket library.
+
+To wrap an existing fd into a tsocket_context the function
+tsocket_context_bsd_wrap_existing() can be used.
+The caller needs to make sure the fd is marked as non-blocking!
+Normaly the tsocket_disconnect() function would close the fd,
+but the caller can influence this behavior based on the close_on_disconnect
+parameter. The caller should also make sure that the socket is only
+accessed via the tsocket_context wrapper after the call to
+tsocket_context_bsd_wrap_existing().
+
+ int tsocket_context_bsd_wrap_existing(TALLOC_CTX *mem_ctx,
+ int fd, bool close_on_disconnect,
+ struct tsocket_context **_sock);
+
+To create a tsocket_address for an inet address you need to use
+the tsocket_address_inet_from_strings() function. It takes the family
+as parameter which can be "ipv4", "ipv6" or "ip", where "ip" autodetects
+"ipv4" or "ipv6", based on the given address string. Depending on the
+operating system, "ipv6" may not be supported. Note: NULL as address
+is mapped to "0.0.0.0" or "::" based on the given family.
+The address parameter only accepts valid ipv4 or ipv6 address strings
+and no names! The caller need to resolve names before using this function.
+
+ int tsocket_address_inet_from_strings(TALLOC_CTX *mem_ctx,
+ const char *family,
+ const char *address,
+ uint16_t port,
+ struct tsocket_address **addr);
+
+To get the address of the inet tsocket_address as string the
+tsocket_address_inet_addr_string() function should be used.
+The caller should not try to parse the tsocket_address_string() output!
+
+ char *tsocket_address_inet_addr_string(const struct tsocket_address *addr,
+ TALLOC_CTX *mem_ctx);
+
+To get the port number of the inet tsocket_address the
+tsocket_address_inet_port() function should be used.
+The caller should not try to parse the tsocket_address_string() output!
+
+ uint16_t tsocket_address_inet_port(const struct tsocket_address *addr);
+
+To alter the port number of an inet tsocket_address the
+tsocket_address_inet_set_port() function can be used.
+This is usefull if the caller gets the address from
+tsocket_address_copy(), tsocket_context_remote_address() or
+tsocket_context_remote_address() instead of tsocket_address_inet_from_strings().
+
+ int tsocket_address_inet_set_port(struct tsocket_address *addr,
+ uint16_t port);
+
+If the caller wants to create a broadcast socket, with the SO_BROADCAST
+socket option, the broadcast option needs to be set with the
+tsocket_address_inet_set_broadcast() function before calling
+tsocket_address_create_socket().
+
+ void tsocket_address_inet_set_broadcast(struct tsocket_address *addr,
+ bool broadcast);
+
+To create a tsocket_address for AF_UNIX style sockets the
+tsocket_address_unix_from_path() should be used.
+NULL as path is handled like "".
+
+ int tsocket_address_unix_from_path(TALLOC_CTX *mem_ctx,
+ const char *path,
+ struct tsocket_address **addr);
+
+To get the unix path of an existing unix tsocket_address
+the tsocket_address_unix_path() should be used.
+The caller should not try to parse the tsocket_address_string() output!
+
+ char *tsocket_address_unix_path(const struct tsocket_address *addr,
+ TALLOC_CTX *mem_ctx);
+
diff --git a/lib/tsocket/tsocket_helpers.c b/lib/tsocket/tsocket_helpers.c
new file mode 100644
index 0000000000..b2edf43d97
--- /dev/null
+++ b/lib/tsocket/tsocket_helpers.c
@@ -0,0 +1,177 @@
+/*
+ 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 "system/filesys.h"
+#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;
+ uint64_t error;
+
+ if (!tevent_req_is_error(req, &state, &error)) {
+ return 0;
+ }
+
+ switch (state) {
+ case TEVENT_REQ_NO_MEMORY:
+ *perrno = ENOMEM;
+ return -1;
+ case TEVENT_REQ_TIMED_OUT:
+ *perrno = ETIMEDOUT;
+ return -1;
+ case TEVENT_REQ_USER_ERROR:
+ *perrno = (int)error;
+ return -1;
+ default:
+ *perrno = EIO;
+ return -1;
+ }
+
+ *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
new file mode 100644
index 0000000000..e4a4908f3e
--- /dev/null
+++ b/lib/tsocket/tsocket_internal.h
@@ -0,0 +1,157 @@
+/*
+ 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/>.
+*/
+
+#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);
+
+ ssize_t (*recvfrom_data)(struct tsocket_context *sock,
+ uint8_t *data, size_t len,
+ TALLOC_CTX *addr_ctx,
+ struct tsocket_address **remote_addr);
+ ssize_t (*sendto_data)(struct tsocket_context *sock,
+ const uint8_t *data, size_t len,
+ const struct tsocket_address *remote_addr);
+
+ /* 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;
+
+ char *(*string)(const struct tsocket_address *addr,
+ TALLOC_CTX *mem_ctx);
+
+ 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 {
+ const char *location;
+ const struct tsocket_address_ops *ops;
+
+ void *private_data;
+};
+
+struct tsocket_address *_tsocket_address_create(TALLOC_CTX *mem_ctx,
+ const struct tsocket_address_ops *ops,
+ void *pstate,
+ size_t psize,
+ const char *type,
+ const char *location);
+#define tsocket_address_create(mem_ctx, ops, state, type, location) \
+ _tsocket_address_create(mem_ctx, ops, state, sizeof(type), \
+ #type, location)
+
+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
new file mode 100644
index 0000000000..2c8483ec7e
--- /dev/null
+++ b/lib/tsocket/tsocket_readv.c
@@ -0,0 +1,222 @@
+/*
+ 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_recvfrom.c b/lib/tsocket/tsocket_recvfrom.c
new file mode 100644
index 0000000000..467738cfc2
--- /dev/null
+++ b/lib/tsocket/tsocket_recvfrom.c
@@ -0,0 +1,164 @@
+/*
+ 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_recvfrom_state {
+ /* this structs are owned by the caller */
+ struct {
+ struct tsocket_context *sock;
+ } caller;
+
+ uint8_t *buf;
+ size_t len;
+ struct tsocket_address *src;
+};
+
+static int tsocket_recvfrom_state_destructor(struct tsocket_recvfrom_state *state)
+{
+ if (state->caller.sock) {
+ tsocket_set_readable_handler(state->caller.sock, NULL, NULL);
+ }
+ ZERO_STRUCT(state->caller);
+
+ return 0;
+}
+
+static void tsocket_recvfrom_handler(struct tsocket_context *sock,
+ void *private_data);
+
+struct tevent_req *tsocket_recvfrom_send(struct tsocket_context *sock,
+ TALLOC_CTX *mem_ctx)
+{
+ struct tevent_req *req;
+ struct tsocket_recvfrom_state *state;
+ int ret;
+ int err;
+ bool dummy;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct tsocket_recvfrom_state);
+ if (!req) {
+ return NULL;
+ }
+
+ state->caller.sock = sock;
+ state->buf = NULL;
+ state->len = 0;
+ state->src = NULL;
+
+ talloc_set_destructor(state, tsocket_recvfrom_state_destructor);
+
+ ret = tsocket_set_readable_handler(sock,
+ tsocket_recvfrom_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_recvfrom_handler(struct tsocket_context *sock,
+ void *private_data)
+{
+ struct tevent_req *req = talloc_get_type(private_data,
+ struct tevent_req);
+ struct tsocket_recvfrom_state *state = tevent_req_data(req,
+ struct tsocket_recvfrom_state);
+ ssize_t ret;
+ int err;
+ bool retry;
+
+ ret = tsocket_pending(state->caller.sock);
+ if (ret == 0) {
+ /* retry later */
+ return;
+ }
+ err = tsocket_error_from_errno(ret, errno, &retry);
+ if (retry) {
+ /* retry later */
+ return;
+ }
+ if (tevent_req_error(req, err)) {
+ return;
+ }
+
+ state->buf = talloc_array(state, uint8_t, ret);
+ if (tevent_req_nomem(state->buf, req)) {
+ return;
+ }
+ state->len = ret;
+
+ ret = tsocket_recvfrom(state->caller.sock,
+ state->buf,
+ state->len,
+ state,
+ &state->src);
+ err = tsocket_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);
+}
+
+ssize_t tsocket_recvfrom_recv(struct tevent_req *req,
+ int *perrno,
+ TALLOC_CTX *mem_ctx,
+ uint8_t **buf,
+ struct tsocket_address **src)
+{
+ struct tsocket_recvfrom_state *state = tevent_req_data(req,
+ struct tsocket_recvfrom_state);
+ ssize_t 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);
+ }
+ }
+
+ tevent_req_received(req);
+ return ret;
+}
+
diff --git a/lib/tsocket/tsocket_sendto.c b/lib/tsocket/tsocket_sendto.c
new file mode 100644
index 0000000000..9c0a76bf16
--- /dev/null
+++ b/lib/tsocket/tsocket_sendto.c
@@ -0,0 +1,271 @@
+/*
+ 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_sendto_state {
+ /* this structs are owned by the caller */
+ struct {
+ struct tsocket_context *sock;
+ const uint8_t *buf;
+ size_t len;
+ const struct tsocket_address *dst;
+ } caller;
+
+ ssize_t ret;
+};
+
+static int tsocket_sendto_state_destructor(struct tsocket_sendto_state *state)
+{
+ if (state->caller.sock) {
+ tsocket_set_writeable_handler(state->caller.sock, NULL, NULL);
+ }
+ ZERO_STRUCT(state->caller);
+
+ return 0;
+}
+
+static void tsocket_sendto_handler(struct tsocket_context *sock,
+ void *private_data);
+
+struct tevent_req *tsocket_sendto_send(struct tsocket_context *sock,
+ TALLOC_CTX *mem_ctx,
+ const uint8_t *buf,
+ size_t len,
+ const struct tsocket_address *dst)
+{
+ struct tevent_req *req;
+ struct tsocket_sendto_state *state;
+ int ret;
+ int err;
+ bool dummy;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct tsocket_sendto_state);
+ if (!req) {
+ return NULL;
+ }
+
+ state->caller.sock = sock;
+ state->caller.buf = buf;
+ state->caller.len = len;
+ state->caller.dst = dst;
+ state->ret = -1;
+
+ /*
+ * this is a fast path, not waiting for the
+ * socket to become explicit writeable gains
+ * about 10%-20% performance in benchmark tests.
+ */
+ tsocket_sendto_handler(sock, req);
+ if (!tevent_req_is_in_progress(req)) {
+ goto post;
+ }
+
+ talloc_set_destructor(state, tsocket_sendto_state_destructor);
+
+ ret = tsocket_set_writeable_handler(sock,
+ tsocket_sendto_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_sendto_handler(struct tsocket_context *sock,
+ void *private_data)
+{
+ struct tevent_req *req = talloc_get_type(private_data,
+ struct tevent_req);
+ struct tsocket_sendto_state *state = tevent_req_data(req,
+ struct tsocket_sendto_state);
+ ssize_t ret;
+ int err;
+ bool retry;
+
+ ret = tsocket_sendto(state->caller.sock,
+ state->caller.buf,
+ state->caller.len,
+ state->caller.dst);
+ err = tsocket_error_from_errno(ret, errno, &retry);
+ if (retry) {
+ /* retry later */
+ return;
+ }
+ if (tevent_req_error(req, err)) {
+ return;
+ }
+
+ state->ret = ret;
+
+ tevent_req_done(req);
+}
+
+ssize_t tsocket_sendto_recv(struct tevent_req *req, int *perrno)
+{
+ struct tsocket_sendto_state *state = tevent_req_data(req,
+ struct tsocket_sendto_state);
+ ssize_t ret;
+
+ ret = tsocket_simple_int_recv(req, perrno);
+ if (ret == 0) {
+ ret = state->ret;
+ }
+
+ tevent_req_received(req);
+ return ret;
+}
+
+struct tsocket_sendto_queue_state {
+ /* this structs are owned by the caller */
+ struct {
+ struct tsocket_context *sock;
+ const uint8_t *buf;
+ size_t len;
+ const struct tsocket_address *dst;
+ } caller;
+ ssize_t ret;
+};
+
+static void tsocket_sendto_queue_trigger(struct tevent_req *req,
+ void *private_data);
+static void tsocket_sendto_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 the message buffer
+ * @param[in] queue The existing dgram queue
+ * @param[in] buf The message buffer
+ * @param[in] len The message length
+ * @param[in] dst The destination socket address
+ * @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_sendto_queue_send(TALLOC_CTX *mem_ctx,
+ struct tsocket_context *sock,
+ struct tevent_queue *queue,
+ const uint8_t *buf,
+ size_t len,
+ struct tsocket_address *dst)
+{
+ struct tevent_req *req;
+ struct tsocket_sendto_queue_state *state;
+ bool ok;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct tsocket_sendto_queue_state);
+ if (!req) {
+ return NULL;
+ }
+
+ state->caller.sock = sock;
+ state->caller.buf = buf;
+ state->caller.len = len;
+ state->caller.dst = dst;
+ state->ret = -1;
+
+ ok = tevent_queue_add(queue,
+ sock->event.ctx,
+ req,
+ tsocket_sendto_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_sendto_queue_trigger(struct tevent_req *req,
+ void *private_data)
+{
+ struct tsocket_sendto_queue_state *state = tevent_req_data(req,
+ struct tsocket_sendto_queue_state);
+ struct tevent_req *subreq;
+
+ subreq = tsocket_sendto_send(state->caller.sock,
+ state,
+ state->caller.buf,
+ state->caller.len,
+ state->caller.dst);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, tsocket_sendto_queue_done ,req);
+}
+
+static void tsocket_sendto_queue_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct tsocket_sendto_queue_state *state = tevent_req_data(req,
+ struct tsocket_sendto_queue_state);
+ ssize_t ret;
+ int sys_errno;
+
+ ret = tsocket_sendto_recv(subreq, &sys_errno);
+ talloc_free(subreq);
+ if (ret == -1) {
+ tevent_req_error(req, sys_errno);
+ return;
+ }
+ state->ret = ret;
+
+ tevent_req_done(req);
+}
+
+ssize_t tsocket_sendto_queue_recv(struct tevent_req *req, int *perrno)
+{
+ struct tsocket_sendto_queue_state *state = tevent_req_data(req,
+ struct tsocket_sendto_queue_state);
+ ssize_t ret;
+
+ ret = tsocket_simple_int_recv(req, perrno);
+ if (ret == 0) {
+ ret = state->ret;
+ }
+
+ tevent_req_received(req);
+ return ret;
+}
+
diff --git a/lib/tsocket/tsocket_writev.c b/lib/tsocket/tsocket_writev.c
new file mode 100644
index 0000000000..8c5cd40385
--- /dev/null
+++ b/lib/tsocket/tsocket_writev.c
@@ -0,0 +1,316 @@
+/*
+ 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;
+}
+
diff --git a/lib/util/charset/charcnv.c b/lib/util/charset/charcnv.c
index 258730ec82..94d47a9f7f 100644
--- a/lib/util/charset/charcnv.c
+++ b/lib/util/charset/charcnv.c
@@ -169,9 +169,10 @@ static smb_iconv_t get_conv_handle(struct smb_iconv_convenience *ic,
_PUBLIC_ ssize_t iconv_talloc(TALLOC_CTX *ctx,
smb_iconv_t cd,
void const *src, size_t srclen,
- void **dest)
+ void *dst)
{
size_t i_len, o_len, destlen;
+ void **dest = (void **)dst;
size_t retval;
const char *inbuf = (const char *)src;
char *outbuf, *ob;
@@ -314,9 +315,10 @@ _PUBLIC_ bool convert_string_talloc_convenience(TALLOC_CTX *ctx,
struct smb_iconv_convenience *ic,
charset_t from, charset_t to,
void const *src, size_t srclen,
- void **dest, size_t *converted_size,
+ void *dst, size_t *converted_size,
bool allow_badcharcnv)
{
+ void **dest = (void **)dst;
smb_iconv_t descriptor;
ssize_t ret;
diff --git a/lib/util/charset/charset.h b/lib/util/charset/charset.h
index 655bae7bcd..37c5acafaf 100644
--- a/lib/util/charset/charset.h
+++ b/lib/util/charset/charset.h
@@ -136,7 +136,7 @@ ssize_t pull_string(char *dest, const void *src, size_t dest_len, size_t src_len
bool convert_string_talloc(TALLOC_CTX *ctx,
charset_t from, charset_t to,
void const *src, size_t srclen,
- void **dest, size_t *converted_size,
+ void *dest, size_t *converted_size,
bool allow_badcharcnv);
size_t convert_string(charset_t from, charset_t to,
@@ -146,7 +146,7 @@ size_t convert_string(charset_t from, charset_t to,
ssize_t iconv_talloc(TALLOC_CTX *mem_ctx,
smb_iconv_t cd,
void const *src, size_t srclen,
- void **dest);
+ void *dest);
extern struct smb_iconv_convenience *global_iconv_convenience;
@@ -176,7 +176,7 @@ bool convert_string_talloc_convenience(TALLOC_CTX *ctx,
struct smb_iconv_convenience *ic,
charset_t from, charset_t to,
void const *src, size_t srclen,
- void **dest, size_t *converted_size, bool allow_badcharcnv);
+ void *dest, size_t *converted_size, bool allow_badcharcnv);
/* iconv */
smb_iconv_t smb_iconv_open(const char *tocode, const char *fromcode);
int smb_iconv_close(smb_iconv_t cd);
diff --git a/lib/util/charset/iconv.c b/lib/util/charset/iconv.c
index 98284ce9bd..9825e4be01 100644
--- a/lib/util/charset/iconv.c
+++ b/lib/util/charset/iconv.c
@@ -50,6 +50,7 @@
static size_t ascii_pull (void *,const char **, size_t *, char **, size_t *);
static size_t ascii_push (void *,const char **, size_t *, char **, size_t *);
+static size_t latin1_push (void *,const char **, size_t *, char **, size_t *);
static size_t utf8_pull (void *,const char **, size_t *, char **, size_t *);
static size_t utf8_push (void *,const char **, size_t *, char **, size_t *);
static size_t utf16_munged_pull(void *,const char **, size_t *, char **, size_t *);
@@ -73,6 +74,8 @@ static const struct charset_functions builtin_functions[] = {
{"UTF16_MUNGED", utf16_munged_pull, iconv_copy},
{"ASCII", ascii_pull, ascii_push},
+ {"646", ascii_pull, ascii_push},
+ {"ISO-8859-1", ascii_pull, latin1_push},
{"UCS2-HEX", ucs2hex_pull, ucs2hex_push}
};
@@ -341,6 +344,32 @@ static size_t ascii_push(void *cd, const char **inbuf, size_t *inbytesleft,
return ir_count;
}
+static size_t latin1_push(void *cd, const char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft)
+{
+ int ir_count=0;
+
+ while (*inbytesleft >= 2 && *outbytesleft >= 1) {
+ (*outbuf)[0] = (*inbuf)[0];
+ if ((*inbuf)[1]) ir_count++;
+ (*inbytesleft) -= 2;
+ (*outbytesleft) -= 1;
+ (*inbuf) += 2;
+ (*outbuf) += 1;
+ }
+
+ if (*inbytesleft == 1) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (*inbytesleft > 1) {
+ errno = E2BIG;
+ return -1;
+ }
+
+ return ir_count;
+}
static size_t ucs2hex_pull(void *cd, const char **inbuf, size_t *inbytesleft,
char **outbuf, size_t *outbytesleft)
diff --git a/lib/util/charset/util_unistr.c b/lib/util/charset/util_unistr.c
index ec88e784d0..ea2bfeab9f 100644
--- a/lib/util/charset/util_unistr.c
+++ b/lib/util/charset/util_unistr.c
@@ -978,7 +978,7 @@ _PUBLIC_ size_t convert_string(charset_t from, charset_t to,
_PUBLIC_ bool convert_string_talloc(TALLOC_CTX *ctx,
charset_t from, charset_t to,
void const *src, size_t srclen,
- void **dest, size_t *converted_size,
+ void *dest, size_t *converted_size,
bool allow_badcharcnv)
{
return convert_string_talloc_convenience(ctx, get_iconv_convenience(),
diff --git a/lib/util/config.mk b/lib/util/config.mk
index 14bdb2a277..7835fed911 100644
--- a/lib/util/config.mk
+++ b/lib/util/config.mk
@@ -5,7 +5,7 @@ PUBLIC_DEPENDENCIES = \
CHARSET EXECINFO
LIBSAMBA-UTIL_OBJ_FILES = $(addprefix $(libutilsrcdir)/, \
- xfile.o \
+ xfile.o \
debug.o \
fault.o \
signal.o \
@@ -68,6 +68,13 @@ PUBLIC_DEPENDENCIES = LIBTDB
UTIL_TDB_OBJ_FILES = $(libutilsrcdir)/util_tdb.o
+[SUBSYSTEM::UTIL_TEVENT]
+PUBLIC_DEPENDENCIES = LIBTEVENT
+
+UTIL_TEVENT_OBJ_FILES = $(addprefix $(libutilsrcdir)/, \
+ tevent_unix.o \
+ tevent_ntstatus.o)
+
[SUBSYSTEM::UTIL_LDB]
PUBLIC_DEPENDENCIES = LIBLDB
diff --git a/lib/util/fault.m4 b/lib/util/fault.m4
index da077af31d..bac553a158 100644
--- a/lib/util/fault.m4
+++ b/lib/util/fault.m4
@@ -8,6 +8,7 @@ if test x"$ac_cv_header_execinfo_h" = x"yes" -a x"$ac_cv_func_ext_backtrace" = x
EXECINFO_CFLAGS="$CFLAGS"
EXECINFO_CPPFLAGS="$CPPFLAGS"
EXECINFO_LDFLAGS="$LDFLAGS"
+ LIB_REMOVE_USR_LIB(EXECINFO_LDFLAGS)
else
SMB_ENABLE(EXECINFO,NO)
fi
diff --git a/lib/util/util.c b/lib/util/util.c
index 1f31f55e8b..0148bdb00d 100644
--- a/lib/util/util.c
+++ b/lib/util/util.c
@@ -541,21 +541,6 @@ void *malloc_array(size_t el_size, unsigned int count)
return realloc_array(NULL, el_size, count, false);
}
-_PUBLIC_ void *talloc_check_name_abort(const void *ptr, const char *name)
-{
- void *result;
-
- result = talloc_check_name(ptr, name);
- if (result != NULL)
- return result;
-
- DEBUG(0, ("Talloc type mismatch, expected %s, got %s\n",
- name, talloc_get_name(ptr)));
- smb_panic("talloc type mismatch");
- /* Keep the compiler happy */
- return NULL;
-}
-
/**
Trim the specified elements off the front and back of a string.
**/
diff --git a/lib/util/util.h b/lib/util/util.h
index 1f6e3b193b..defef127d9 100644
--- a/lib/util/util.h
+++ b/lib/util/util.h
@@ -767,13 +767,6 @@ bool pm_process( const char *fileName,
bool (*pfunc)(const char *, const char *, void *),
void *userdata);
-/**
- * Add-on to talloc_get_type
- */
-_PUBLIC_ void *talloc_check_name_abort(const void *ptr, const char *name);
-#define talloc_get_type_abort(ptr, type) \
- (type *)talloc_check_name_abort(ptr, #type)
-
bool unmap_file(void *start, size_t size);
void print_asc(int level, const uint8_t *buf,int len);