summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/tsocket/config.mk2
-rw-r--r--lib/tsocket/tsocket.c409
-rw-r--r--lib/tsocket/tsocket.h88
-rw-r--r--lib/tsocket/tsocket_bsd.c943
-rw-r--r--lib/tsocket/tsocket_internal.h49
-rw-r--r--lib/tsocket/tsocket_recvfrom.c164
-rw-r--r--lib/tsocket/tsocket_sendto.c271
-rw-r--r--libcli/cldap/cldap.c83
-rw-r--r--libcli/util/ntstatus.h4
-rw-r--r--source3/lib/charcnv.c25
-rw-r--r--source3/modules/onefs_open.c37
-rw-r--r--source3/passdb/pdb_tdb.c60
-rw-r--r--source3/rpc_server/srv_lsa_nt.c8
-rw-r--r--source3/rpc_server/srv_spoolss_nt.c243
-rw-r--r--source4/libcli/util/nterr.c2
-rw-r--r--source4/torture/raw/lock.c4
-rw-r--r--source4/torture/raw/lockbench.c20
-rw-r--r--source4/torture/raw/oplock.c176
-rw-r--r--source4/torture/raw/streams.c21
-rw-r--r--source4/torture/smb2/lock.c10
20 files changed, 1946 insertions, 673 deletions
diff --git a/lib/tsocket/config.mk b/lib/tsocket/config.mk
index c35f0afd6f..2e05f544c9 100644
--- a/lib/tsocket/config.mk
+++ b/lib/tsocket/config.mk
@@ -5,8 +5,6 @@ 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)
diff --git a/lib/tsocket/tsocket.c b/lib/tsocket/tsocket.c
index 1a12e691a9..076c6474a0 100644
--- a/lib/tsocket/tsocket.c
+++ b/lib/tsocket/tsocket.c
@@ -118,21 +118,6 @@ int tsocket_writev(struct tsocket_context *sock,
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);
@@ -229,3 +214,397 @@ int _tsocket_address_create_socket(const struct tsocket_address *addr,
return addr->ops->create_socket(addr, type, mem_ctx, sock, location);
}
+struct tdgram_context {
+ const char *location;
+ const struct tdgram_context_ops *ops;
+ void *private_data;
+};
+
+struct tdgram_context *_tdgram_context_create(TALLOC_CTX *mem_ctx,
+ const struct tdgram_context_ops *ops,
+ void *pstate,
+ size_t psize,
+ const char *type,
+ const char *location)
+{
+ struct tdgram_context *dgram;
+ void **ppstate = (void **)pstate;
+ void *state;
+
+ dgram = talloc(mem_ctx, struct tdgram_context);
+ if (dgram == NULL) {
+ return NULL;
+ }
+ dgram->location = location;
+ dgram->ops = ops;
+
+ state = talloc_size(dgram, psize);
+ if (state == NULL) {
+ talloc_free(dgram);
+ return NULL;
+ }
+ talloc_set_name_const(state, type);
+
+ dgram->private_data = state;
+
+ *ppstate = state;
+ return dgram;
+}
+
+void *_tdgram_context_data(struct tdgram_context *dgram)
+{
+ return dgram->private_data;
+}
+
+struct tdgram_recvfrom_state {
+ const struct tdgram_context_ops *ops;
+ uint8_t *buf;
+ size_t len;
+ struct tsocket_address *src;
+};
+
+static void tdgram_recvfrom_done(struct tevent_req *subreq);
+
+struct tevent_req *tdgram_recvfrom_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tdgram_context *dgram)
+{
+ struct tevent_req *req;
+ struct tdgram_recvfrom_state *state;
+ struct tevent_req *subreq;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct tdgram_recvfrom_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ state->ops = dgram->ops;
+
+ subreq = state->ops->recvfrom_send(state, ev, dgram);
+ if (tevent_req_nomem(subreq, req)) {
+ goto post;
+ }
+ tevent_req_set_callback(subreq, tdgram_recvfrom_done, req);
+
+ return req;
+
+ post:
+ tevent_req_post(req, ev);
+ return req;
+}
+
+static void tdgram_recvfrom_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct tdgram_recvfrom_state *state = tevent_req_data(req,
+ struct tdgram_recvfrom_state);
+ ssize_t ret;
+ int sys_errno;
+
+ ret = state->ops->recvfrom_recv(subreq, &sys_errno, state,
+ &state->buf, &state->src);
+ if (ret == -1) {
+ tevent_req_error(req, sys_errno);
+ return;
+ }
+
+ state->len = ret;
+
+ tevent_req_done(req);
+}
+
+ssize_t tdgram_recvfrom_recv(struct tevent_req *req,
+ int *perrno,
+ TALLOC_CTX *mem_ctx,
+ uint8_t **buf,
+ struct tsocket_address **src)
+{
+ struct tdgram_recvfrom_state *state = tevent_req_data(req,
+ struct tdgram_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;
+}
+
+struct tdgram_sendto_state {
+ const struct tdgram_context_ops *ops;
+ ssize_t ret;
+};
+
+static void tdgram_sendto_done(struct tevent_req *subreq);
+
+struct tevent_req *tdgram_sendto_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tdgram_context *dgram,
+ const uint8_t *buf, size_t len,
+ const struct tsocket_address *dst)
+{
+ struct tevent_req *req;
+ struct tdgram_sendto_state *state;
+ struct tevent_req *subreq;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct tdgram_sendto_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ state->ops = dgram->ops;
+ state->ret = -1;
+
+ subreq = state->ops->sendto_send(state, ev, dgram,
+ buf, len, dst);
+ if (tevent_req_nomem(subreq, req)) {
+ goto post;
+ }
+ tevent_req_set_callback(subreq, tdgram_sendto_done, req);
+
+ return req;
+
+ post:
+ tevent_req_post(req, ev);
+ return req;
+}
+
+static void tdgram_sendto_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct tdgram_sendto_state *state = tevent_req_data(req,
+ struct tdgram_sendto_state);
+ ssize_t ret;
+ int sys_errno;
+
+ ret = state->ops->sendto_recv(subreq, &sys_errno);
+ if (ret == -1) {
+ tevent_req_error(req, sys_errno);
+ return;
+ }
+
+ state->ret = ret;
+
+ tevent_req_done(req);
+}
+
+ssize_t tdgram_sendto_recv(struct tevent_req *req,
+ int *perrno)
+{
+ struct tdgram_sendto_state *state = tevent_req_data(req,
+ struct tdgram_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 tdgram_disconnect_state {
+ const struct tdgram_context_ops *ops;
+};
+
+static void tdgram_disconnect_done(struct tevent_req *subreq);
+
+struct tevent_req *tdgram_disconnect_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tdgram_context *dgram)
+{
+ struct tevent_req *req;
+ struct tdgram_disconnect_state *state;
+ struct tevent_req *subreq;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct tdgram_disconnect_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ state->ops = dgram->ops;
+
+ subreq = state->ops->disconnect_send(state, ev, dgram);
+ if (tevent_req_nomem(subreq, req)) {
+ goto post;
+ }
+ tevent_req_set_callback(subreq, tdgram_disconnect_done, req);
+
+ return req;
+
+ post:
+ tevent_req_post(req, ev);
+ return req;
+}
+
+static void tdgram_disconnect_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct tdgram_disconnect_state *state = tevent_req_data(req,
+ struct tdgram_disconnect_state);
+ int ret;
+ int sys_errno;
+
+ ret = state->ops->disconnect_recv(subreq, &sys_errno);
+ if (ret == -1) {
+ tevent_req_error(req, sys_errno);
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+int tdgram_disconnect_recv(struct tevent_req *req,
+ int *perrno)
+{
+ int ret;
+
+ ret = tsocket_simple_int_recv(req, perrno);
+
+ tevent_req_received(req);
+ return ret;
+}
+
+struct tdgram_sendto_queue_state {
+ /* this structs are owned by the caller */
+ struct {
+ struct tevent_context *ev;
+ struct tdgram_context *dgram;
+ const uint8_t *buf;
+ size_t len;
+ const struct tsocket_address *dst;
+ } caller;
+ ssize_t ret;
+};
+
+static void tdgram_sendto_queue_trigger(struct tevent_req *req,
+ void *private_data);
+static void tdgram_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] ev The event context the operation should work on
+ * @param[in] dgram The tdgram_context 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 *tdgram_sendto_queue_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tdgram_context *dgram,
+ struct tevent_queue *queue,
+ const uint8_t *buf,
+ size_t len,
+ struct tsocket_address *dst)
+{
+ struct tevent_req *req;
+ struct tdgram_sendto_queue_state *state;
+ bool ok;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct tdgram_sendto_queue_state);
+ if (!req) {
+ return NULL;
+ }
+
+ state->caller.ev = ev;
+ state->caller.dgram = dgram;
+ state->caller.buf = buf;
+ state->caller.len = len;
+ state->caller.dst = dst;
+ state->ret = -1;
+
+ ok = tevent_queue_add(queue,
+ ev,
+ req,
+ tdgram_sendto_queue_trigger,
+ NULL);
+ if (!ok) {
+ tevent_req_nomem(NULL, req);
+ goto post;
+ }
+
+ return req;
+
+ post:
+ tevent_req_post(req, ev);
+ return req;
+}
+
+static void tdgram_sendto_queue_trigger(struct tevent_req *req,
+ void *private_data)
+{
+ struct tdgram_sendto_queue_state *state = tevent_req_data(req,
+ struct tdgram_sendto_queue_state);
+ struct tevent_req *subreq;
+
+ subreq = tdgram_sendto_send(state,
+ state->caller.ev,
+ state->caller.dgram,
+ state->caller.buf,
+ state->caller.len,
+ state->caller.dst);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, tdgram_sendto_queue_done, req);
+}
+
+static void tdgram_sendto_queue_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct tdgram_sendto_queue_state *state = tevent_req_data(req,
+ struct tdgram_sendto_queue_state);
+ ssize_t ret;
+ int sys_errno;
+
+ ret = tdgram_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 tdgram_sendto_queue_recv(struct tevent_req *req, int *perrno)
+{
+ struct tdgram_sendto_queue_state *state = tevent_req_data(req,
+ struct tdgram_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.h b/lib/tsocket/tsocket.h
index 9bcfb5cb7e..8f69490012 100644
--- a/lib/tsocket/tsocket.h
+++ b/lib/tsocket/tsocket.h
@@ -29,11 +29,11 @@
struct tsocket_context;
struct tsocket_address;
+struct tdgram_context;
struct iovec;
enum tsocket_type {
TSOCKET_TYPE_STREAM = 1,
- TSOCKET_TYPE_DGRAM,
TSOCKET_TYPE_MESSAGE
};
@@ -67,14 +67,6 @@ int tsocket_readv(struct tsocket_context *sock,
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,
@@ -121,6 +113,32 @@ int _tsocket_address_create_socket(const struct tsocket_address *addr,
__location__)
/*
+ * tdgram_context related functions
+ */
+struct tevent_req *tdgram_recvfrom_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tdgram_context *dgram);
+ssize_t tdgram_recvfrom_recv(struct tevent_req *req,
+ int *perrno,
+ TALLOC_CTX *mem_ctx,
+ uint8_t **buf,
+ struct tsocket_address **src);
+
+struct tevent_req *tdgram_sendto_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tdgram_context *dgram,
+ const uint8_t *buf, size_t len,
+ const struct tsocket_address *dst);
+ssize_t tdgram_sendto_recv(struct tevent_req *req,
+ int *perrno);
+
+struct tevent_req *tdgram_disconnect_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tdgram_context *dgram);
+int tdgram_disconnect_recv(struct tevent_req *req,
+ int *perrno);
+
+/*
* BSD sockets: inet, inet6 and unix
*/
@@ -160,32 +178,25 @@ int _tsocket_context_bsd_wrap_existing(TALLOC_CTX *mem_ctx,
_tsocket_context_bsd_wrap_existing(mem_ctx, fd, cod, _sock, \
__location__)
-/*
- * Async helpers
- */
+int _tdgram_inet_udp_socket(const struct tsocket_address *local,
+ const struct tsocket_address *remote,
+ TALLOC_CTX *mem_ctx,
+ struct tdgram_context **dgram,
+ const char *location);
+#define tdgram_inet_udp_socket(local, remote, mem_ctx, dgram) \
+ _tdgram_inet_udp_socket(local, remote, mem_ctx, dgram, __location__)
-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,
+int _tdgram_unix_dgram_socket(const struct tsocket_address *local,
+ const struct tsocket_address *remote,
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 tdgram_context **dgram,
+ const char *location);
+#define tdgram_unix_dgram_socket(local, remote, mem_ctx, dgram) \
+ _tdgram_unix_dgram_socket(local, remote, mem_ctx, dgram, __location__)
-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);
+/*
+ * Async helpers
+ */
struct tevent_req *tsocket_connect_send(struct tsocket_context *sock,
TALLOC_CTX *mem_ctx,
@@ -216,5 +227,18 @@ struct tevent_req *tsocket_readv_send(struct tsocket_context *sock,
void *private_data);
int tsocket_readv_recv(struct tevent_req *req, int *perrno);
+/*
+ * Queue helpers
+ */
+
+struct tevent_req *tdgram_sendto_queue_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tdgram_context *dgram,
+ struct tevent_queue *queue,
+ const uint8_t *buf,
+ size_t len,
+ struct tsocket_address *dst);
+ssize_t tdgram_sendto_queue_recv(struct tevent_req *req, int *perrno);
+
#endif /* _TSOCKET_H */
diff --git a/lib/tsocket/tsocket_bsd.c b/lib/tsocket/tsocket_bsd.c
index 8254f5d9d3..4ccaff46e3 100644
--- a/lib/tsocket/tsocket_bsd.c
+++ b/lib/tsocket/tsocket_bsd.c
@@ -24,9 +24,168 @@
#include "replace.h"
#include "system/filesys.h"
#include "system/network.h"
+#include "system/filesys.h"
#include "tsocket.h"
#include "tsocket_internal.h"
+static int tsocket_bsd_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;
+}
+
+static int tsocket_bsd_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;
+}
+
+static ssize_t tsocket_bsd_pending(int fd)
+{
+ int ret;
+ int value = 0;
+
+ ret = ioctl(fd, FIONREAD, &value);
+ if (ret == -1) {
+ return ret;
+ }
+
+ if (ret == 0) {
+ if (value == 0) {
+ int error=0;
+ socklen_t len = sizeof(error);
+ /*
+ * if no data is available check if the socket
+ * is in error state. For dgram sockets
+ * it's the way to return ICMP error messages
+ * of connected sockets to the caller.
+ */
+ ret = getsockopt(fd, SOL_SOCKET, SO_ERROR,
+ &error, &len);
+ if (ret == -1) {
+ return ret;
+ }
+ if (error != 0) {
+ errno = error;
+ return -1;
+ }
+ }
+ return value;
+ }
+
+ /* this should not be reached */
+ errno = EIO;
+ return -1;
+}
+
static const struct tsocket_context_ops tsocket_context_bsd_ops;
static const struct tsocket_address_ops tsocket_address_bsd_ops;
@@ -456,9 +615,6 @@ static int tsocket_address_bsd_create_socket(const struct tsocket_address *addr,
}
bsd_type = SOCK_STREAM;
break;
- case TSOCKET_TYPE_DGRAM:
- bsd_type = SOCK_DGRAM;
- break;
default:
errno = EPROTONOSUPPORT;
return -1;
@@ -785,73 +941,6 @@ static int tsocket_context_bsd_writev_data(struct tsocket_context *sock,
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,
@@ -1113,8 +1202,6 @@ static const struct tsocket_context_ops tsocket_context_bsd_ops = {
.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,
@@ -1125,3 +1212,715 @@ static const struct tsocket_context_ops tsocket_context_bsd_ops = {
.disconnect = tsocket_context_bsd_disconnect
};
+
+struct tdgram_bsd {
+ int fd;
+
+ void *event_ptr;
+ struct tevent_fd *fde;
+
+ void *readable_private;
+ void (*readable_handler)(void *private_data);
+ void *writeable_private;
+ void (*writeable_handler)(void *private_data);
+
+ struct tevent_req *read_req;
+ struct tevent_req *write_req;
+};
+
+static void tdgram_bsd_fde_handler(struct tevent_context *ev,
+ struct tevent_fd *fde,
+ uint16_t flags,
+ void *private_data)
+{
+ struct tdgram_bsd *bsds = talloc_get_type_abort(private_data,
+ struct tdgram_bsd);
+
+ if (flags & TEVENT_FD_WRITE) {
+ bsds->writeable_handler(bsds->writeable_private);
+ return;
+ }
+ if (flags & TEVENT_FD_READ) {
+ if (!bsds->readable_handler) {
+ TEVENT_FD_NOT_READABLE(bsds->fde);
+ return;
+ }
+ bsds->readable_handler(bsds->readable_private);
+ return;
+ }
+}
+
+static int tdgram_bsd_set_readable_handler(struct tdgram_bsd *bsds,
+ struct tevent_context *ev,
+ void (*handler)(void *private_data),
+ void *private_data)
+{
+ if (ev == NULL) {
+ if (handler) {
+ errno = EINVAL;
+ return -1;
+ }
+ if (!bsds->readable_handler) {
+ return 0;
+ }
+ bsds->readable_handler = NULL;
+ bsds->readable_private = NULL;
+
+ return 0;
+ }
+
+ /* read and write must use the same tevent_context */
+ if (bsds->event_ptr != ev) {
+ if (bsds->readable_handler || bsds->writeable_handler) {
+ errno = EINVAL;
+ return -1;
+ }
+ bsds->event_ptr = NULL;
+ TALLOC_FREE(bsds->fde);
+ }
+
+ if (bsds->fde == NULL) {
+ bsds->fde = tevent_add_fd(ev, bsds,
+ bsds->fd, TEVENT_FD_READ,
+ tdgram_bsd_fde_handler,
+ bsds);
+ if (!bsds->fde) {
+ return -1;
+ }
+
+ /* cache the event context we're running on */
+ bsds->event_ptr = ev;
+ } else if (!bsds->readable_handler) {
+ TEVENT_FD_READABLE(bsds->fde);
+ }
+
+ bsds->readable_handler = handler;
+ bsds->readable_private = private_data;
+
+ return 0;
+}
+
+static int tdgram_bsd_set_writeable_handler(struct tdgram_bsd *bsds,
+ struct tevent_context *ev,
+ void (*handler)(void *private_data),
+ void *private_data)
+{
+ if (ev == NULL) {
+ if (handler) {
+ errno = EINVAL;
+ return -1;
+ }
+ if (!bsds->writeable_handler) {
+ return 0;
+ }
+ bsds->writeable_handler = NULL;
+ bsds->writeable_private = NULL;
+ TEVENT_FD_NOT_WRITEABLE(bsds->fde);
+
+ return 0;
+ }
+
+ /* read and write must use the same tevent_context */
+ if (bsds->event_ptr != ev) {
+ if (bsds->readable_handler || bsds->writeable_handler) {
+ errno = EINVAL;
+ return -1;
+ }
+ bsds->event_ptr = NULL;
+ TALLOC_FREE(bsds->fde);
+ }
+
+ if (bsds->fde == NULL) {
+ bsds->fde = tevent_add_fd(ev, bsds,
+ bsds->fd, TEVENT_FD_WRITE,
+ tdgram_bsd_fde_handler,
+ bsds);
+ if (!bsds->fde) {
+ return -1;
+ }
+
+ /* cache the event context we're running on */
+ bsds->event_ptr = ev;
+ } else if (!bsds->writeable_handler) {
+ TEVENT_FD_WRITEABLE(bsds->fde);
+ }
+
+ bsds->writeable_handler = handler;
+ bsds->writeable_private = private_data;
+
+ return 0;
+}
+
+struct tdgram_bsd_recvfrom_state {
+ struct tdgram_context *dgram;
+
+ uint8_t *buf;
+ size_t len;
+ struct tsocket_address *src;
+};
+
+static int tdgram_bsd_recvfrom_destructor(struct tdgram_bsd_recvfrom_state *state)
+{
+ struct tdgram_bsd *bsds = tdgram_context_data(state->dgram,
+ struct tdgram_bsd);
+
+ bsds->read_req = NULL;
+ tdgram_bsd_set_readable_handler(bsds, NULL, NULL, NULL);
+
+ return 0;
+}
+
+static void tdgram_bsd_recvfrom_handler(void *private_data);
+
+static struct tevent_req *tdgram_bsd_recvfrom_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tdgram_context *dgram)
+{
+ struct tevent_req *req;
+ struct tdgram_bsd_recvfrom_state *state;
+ struct tdgram_bsd *bsds = tdgram_context_data(dgram, struct tdgram_bsd);
+ int ret;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct tdgram_bsd_recvfrom_state);
+ if (!req) {
+ return NULL;
+ }
+
+ state->dgram = dgram;
+ state->buf = NULL;
+ state->len = 0;
+ state->src = NULL;
+
+ if (bsds->read_req) {
+ tevent_req_error(req, EBUSY);
+ goto post;
+ }
+ bsds->read_req = req;
+
+ talloc_set_destructor(state, tdgram_bsd_recvfrom_destructor);
+
+ if (bsds->fd == -1) {
+ tevent_req_error(req, ENOTCONN);
+ goto post;
+ }
+
+ /*
+ * this is a fast path, not waiting for the
+ * socket to become explicit readable gains
+ * about 10%-20% performance in benchmark tests.
+ */
+ tdgram_bsd_recvfrom_handler(req);
+ if (!tevent_req_is_in_progress(req)) {
+ goto post;
+ }
+
+ ret = tdgram_bsd_set_readable_handler(bsds, ev,
+ tdgram_bsd_recvfrom_handler,
+ req);
+ if (ret == -1) {
+ tevent_req_error(req, errno);
+ goto post;
+ }
+
+ return req;
+
+ post:
+ tevent_req_post(req, ev);
+ return req;
+}
+
+static void tdgram_bsd_recvfrom_handler(void *private_data)
+{
+ struct tevent_req *req = talloc_get_type_abort(private_data,
+ struct tevent_req);
+ struct tdgram_bsd_recvfrom_state *state = tevent_req_data(req,
+ struct tdgram_bsd_recvfrom_state);
+ struct tdgram_context *dgram = state->dgram;
+ struct tdgram_bsd *bsds = tdgram_context_data(dgram, struct tdgram_bsd);
+ struct tsocket_address_bsd *bsda;
+ ssize_t ret;
+ struct sockaddr *sa = NULL;
+ socklen_t sa_len = 0;
+ int err;
+ bool retry;
+
+ ret = tsocket_bsd_pending(bsds->fd);
+ if (ret == 0) {
+ /* retry later */
+ return;
+ }
+ err = tsocket_bsd_error_from_errno(ret, errno, &retry);
+ if (retry) {
+ /* retry later */
+ return;
+ }
+ if (tevent_req_error(req, err)) {
+ return;
+ }
+
+ state->buf = talloc_array(state, uint8_t, ret);
+ if (tevent_req_nomem(state->buf, req)) {
+ return;
+ }
+ state->len = ret;
+
+ state->src = tsocket_address_create(state,
+ &tsocket_address_bsd_ops,
+ &bsda,
+ struct tsocket_address_bsd,
+ __location__ "bsd_recvfrom");
+ if (tevent_req_nomem(state->src, req)) {
+ return;
+ }
+
+ ZERO_STRUCTP(bsda);
+
+ sa = &bsda->u.sa;
+ sa_len = sizeof(bsda->u.ss);
+
+ ret = recvfrom(bsds->fd, state->buf, state->len, 0, sa, &sa_len);
+ err = tsocket_error_from_errno(ret, errno, &retry);
+ if (retry) {
+ /* retry later */
+ return;
+ }
+ if (tevent_req_error(req, err)) {
+ return;
+ }
+
+ if (ret != state->len) {
+ tevent_req_error(req, EIO);
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+static ssize_t tdgram_bsd_recvfrom_recv(struct tevent_req *req,
+ int *perrno,
+ TALLOC_CTX *mem_ctx,
+ uint8_t **buf,
+ struct tsocket_address **src)
+{
+ struct tdgram_bsd_recvfrom_state *state = tevent_req_data(req,
+ struct tdgram_bsd_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;
+}
+
+struct tdgram_bsd_sendto_state {
+ struct tdgram_context *dgram;
+
+ const uint8_t *buf;
+ size_t len;
+ const struct tsocket_address *dst;
+
+ ssize_t ret;
+};
+
+static int tdgram_bsd_sendto_destructor(struct tdgram_bsd_sendto_state *state)
+{
+ struct tdgram_bsd *bsds = tdgram_context_data(state->dgram,
+ struct tdgram_bsd);
+
+ bsds->write_req = NULL;
+ tdgram_bsd_set_writeable_handler(bsds, NULL, NULL, NULL);
+ return 0;
+}
+
+static void tdgram_bsd_sendto_handler(void *private_data);
+
+static struct tevent_req *tdgram_bsd_sendto_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tdgram_context *dgram,
+ const uint8_t *buf,
+ size_t len,
+ const struct tsocket_address *dst)
+{
+ struct tevent_req *req;
+ struct tdgram_bsd_sendto_state *state;
+ struct tdgram_bsd *bsds = tdgram_context_data(dgram, struct tdgram_bsd);
+ int ret;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct tdgram_bsd_sendto_state);
+ if (!req) {
+ return NULL;
+ }
+
+ state->dgram = dgram;
+ state->buf = buf;
+ state->len = len;
+ state->dst = dst;
+ state->ret = -1;
+
+ if (bsds->write_req) {
+ tevent_req_error(req, EBUSY);
+ goto post;
+ }
+ bsds->write_req = req;
+
+ talloc_set_destructor(state, tdgram_bsd_sendto_destructor);
+
+ if (bsds->fd == -1) {
+ tevent_req_error(req, ENOTCONN);
+ goto post;
+ }
+
+ /*
+ * this is a fast path, not waiting for the
+ * socket to become explicit writeable gains
+ * about 10%-20% performance in benchmark tests.
+ */
+ tdgram_bsd_sendto_handler(req);
+ if (!tevent_req_is_in_progress(req)) {
+ goto post;
+ }
+
+ ret = tdgram_bsd_set_writeable_handler(bsds, ev,
+ tdgram_bsd_sendto_handler,
+ req);
+ if (ret == -1) {
+ tevent_req_error(req, errno);
+ goto post;
+ }
+
+ return req;
+
+ post:
+ tevent_req_post(req, ev);
+ return req;
+}
+
+static void tdgram_bsd_sendto_handler(void *private_data)
+{
+ struct tevent_req *req = talloc_get_type_abort(private_data,
+ struct tevent_req);
+ struct tdgram_bsd_sendto_state *state = tevent_req_data(req,
+ struct tdgram_bsd_sendto_state);
+ struct tdgram_context *dgram = state->dgram;
+ struct tdgram_bsd *bsds = tdgram_context_data(dgram, struct tdgram_bsd);
+ struct sockaddr *sa = NULL;
+ socklen_t sa_len = 0;
+ ssize_t ret;
+ int err;
+ bool retry;
+
+ if (state->dst) {
+ struct tsocket_address_bsd *bsda =
+ talloc_get_type(state->dst->private_data,
+ struct tsocket_address_bsd);
+
+ sa = &bsda->u.sa;
+ sa_len = sizeof(bsda->u.ss);
+ }
+
+ ret = sendto(bsds->fd, state->buf, state->len, 0, sa, sa_len);
+ err = tsocket_error_from_errno(ret, errno, &retry);
+ if (retry) {
+ /* retry later */
+ return;
+ }
+ if (tevent_req_error(req, err)) {
+ return;
+ }
+
+ state->ret = ret;
+
+ tevent_req_done(req);
+}
+
+static ssize_t tdgram_bsd_sendto_recv(struct tevent_req *req, int *perrno)
+{
+ struct tdgram_bsd_sendto_state *state = tevent_req_data(req,
+ struct tdgram_bsd_sendto_state);
+ ssize_t ret;
+
+ ret = tsocket_simple_int_recv(req, perrno);
+ if (ret == 0) {
+ ret = state->ret;
+ }
+
+ tevent_req_received(req);
+ return ret;
+}
+
+struct tdgram_bsd_disconnect_state {
+ int ret;
+};
+
+static struct tevent_req *tdgram_bsd_disconnect_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tdgram_context *dgram)
+{
+ struct tdgram_bsd *bsds = tdgram_context_data(dgram, struct tdgram_bsd);
+ struct tevent_req *req;
+ struct tdgram_bsd_disconnect_state *state;
+ int ret;
+ int err;
+ bool dummy;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct tdgram_bsd_disconnect_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->ret = -1;
+
+ if (bsds->read_req || bsds->write_req) {
+ tevent_req_error(req, EBUSY);
+ goto post;
+ }
+
+ if (bsds->fd == -1) {
+ tevent_req_error(req, ENOTCONN);
+ goto post;
+ }
+
+ state->ret = close(bsds->fd);
+ bsds->fd = -1;
+ err = tsocket_error_from_errno(ret, errno, &dummy);
+ if (tevent_req_error(req, err)) {
+ goto post;
+ }
+
+ tevent_req_done(req);
+post:
+ tevent_req_post(req, ev);
+ return req;
+}
+
+static int tdgram_bsd_disconnect_recv(struct tevent_req *req,
+ int *perrno)
+{
+ struct tdgram_bsd_disconnect_state *state = tevent_req_data(req,
+ struct tdgram_bsd_disconnect_state);
+ int ret;
+
+ ret = tsocket_simple_int_recv(req, perrno);
+ if (ret == 0) {
+ ret = state->ret;
+ }
+
+ tevent_req_received(req);
+ return ret;
+}
+
+static const struct tdgram_context_ops tdgram_bsd_ops = {
+ .name = "bsd",
+
+ .recvfrom_send = tdgram_bsd_recvfrom_send,
+ .recvfrom_recv = tdgram_bsd_recvfrom_recv,
+
+ .sendto_send = tdgram_bsd_sendto_send,
+ .sendto_recv = tdgram_bsd_sendto_recv,
+
+ .disconnect_send = tdgram_bsd_disconnect_send,
+ .disconnect_recv = tdgram_bsd_disconnect_recv,
+};
+
+static int tdgram_bsd_destructor(struct tdgram_bsd *bsds)
+{
+ TALLOC_FREE(bsds->fde);
+ if (bsds->fd != -1) {
+ close(bsds->fd);
+ bsds->fd = -1;
+ }
+ return 0;
+}
+
+static int tdgram_bsd_dgram_socket(const struct tsocket_address *local,
+ const struct tsocket_address *remote,
+ TALLOC_CTX *mem_ctx,
+ struct tdgram_context **_dgram,
+ const char *location)
+{
+ struct tsocket_address_bsd *lbsda =
+ talloc_get_type_abort(local->private_data,
+ struct tsocket_address_bsd);
+ struct tsocket_address_bsd *rbsda = NULL;
+ struct tdgram_context *dgram;
+ struct tdgram_bsd *bsds;
+ int fd;
+ int ret;
+ bool do_bind = false;
+ bool do_reuseaddr = false;
+
+ if (remote) {
+ rbsda = talloc_get_type_abort(remote->private_data,
+ struct tsocket_address_bsd);
+ }
+
+ switch (lbsda->u.sa.sa_family) {
+ case AF_UNIX:
+ if (lbsda->u.un.sun_path[0] != 0) {
+ do_reuseaddr = true;
+ do_bind = true;
+ }
+ break;
+ case AF_INET:
+ if (lbsda->u.in.sin_port != 0) {
+ do_reuseaddr = true;
+ do_bind = true;
+ }
+ if (lbsda->u.in.sin_addr.s_addr == INADDR_ANY) {
+ do_bind = true;
+ }
+ break;
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ if (lbsda->u.in6.sin6_port != 0) {
+ do_reuseaddr = true;
+ do_bind = true;
+ }
+ if (memcmp(&in6addr_any,
+ &lbsda->u.in6.sin6_addr,
+ sizeof(in6addr_any)) != 0) {
+ do_bind = true;
+ }
+ break;
+#endif
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+
+ fd = socket(lbsda->u.sa.sa_family, SOCK_DGRAM, 0);
+ if (fd < 0) {
+ return fd;
+ }
+
+ fd = tsocket_bsd_common_prepare_fd(fd, true);
+ if (fd < 0) {
+ return fd;
+ }
+
+ dgram = tdgram_context_create(mem_ctx,
+ &tdgram_bsd_ops,
+ &bsds,
+ struct tdgram_bsd,
+ location);
+ if (!dgram) {
+ int saved_errno = errno;
+ close(fd);
+ errno = saved_errno;
+ return -1;
+ }
+ ZERO_STRUCTP(bsds);
+ bsds->fd = fd;
+ talloc_set_destructor(bsds, tdgram_bsd_destructor);
+
+ if (lbsda->broadcast) {
+ int val = 1;
+
+ ret = setsockopt(fd, SOL_SOCKET, SO_BROADCAST,
+ (const void *)&val, sizeof(val));
+ if (ret == -1) {
+ int saved_errno = errno;
+ talloc_free(dgram);
+ errno = saved_errno;
+ return ret;
+ }
+ }
+
+ if (do_reuseaddr) {
+ int val = 1;
+
+ ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
+ (const void *)&val, sizeof(val));
+ if (ret == -1) {
+ int saved_errno = errno;
+ talloc_free(dgram);
+ errno = saved_errno;
+ return ret;
+ }
+ }
+
+ if (do_bind) {
+ ret = bind(fd, &lbsda->u.sa, sizeof(lbsda->u.ss));
+ if (ret == -1) {
+ int saved_errno = errno;
+ talloc_free(dgram);
+ errno = saved_errno;
+ return ret;
+ }
+ }
+
+ if (rbsda) {
+ ret = connect(fd, &rbsda->u.sa, sizeof(rbsda->u.ss));
+ if (ret == -1) {
+ int saved_errno = errno;
+ talloc_free(dgram);
+ errno = saved_errno;
+ return ret;
+ }
+ }
+
+ *_dgram = dgram;
+ return 0;
+}
+
+int _tdgram_inet_udp_socket(const struct tsocket_address *local,
+ const struct tsocket_address *remote,
+ TALLOC_CTX *mem_ctx,
+ struct tdgram_context **dgram,
+ const char *location)
+{
+ struct tsocket_address_bsd *lbsda =
+ talloc_get_type_abort(local->private_data,
+ struct tsocket_address_bsd);
+ int ret;
+
+ switch (lbsda->u.sa.sa_family) {
+ case AF_INET:
+ break;
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ break;
+#endif
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+
+ ret = tdgram_bsd_dgram_socket(local, remote, mem_ctx, dgram, location);
+
+ return ret;
+}
+
+int _tdgram_unix_dgram_socket(const struct tsocket_address *local,
+ const struct tsocket_address *remote,
+ TALLOC_CTX *mem_ctx,
+ struct tdgram_context **dgram,
+ const char *location)
+{
+ struct tsocket_address_bsd *lbsda =
+ talloc_get_type_abort(local->private_data,
+ struct tsocket_address_bsd);
+ int ret;
+
+ switch (lbsda->u.sa.sa_family) {
+ case AF_UNIX:
+ break;
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+
+ ret = tdgram_bsd_dgram_socket(local, remote, mem_ctx, dgram, location);
+
+ return ret;
+}
+
diff --git a/lib/tsocket/tsocket_internal.h b/lib/tsocket/tsocket_internal.h
index e4a4908f3e..893394405f 100644
--- a/lib/tsocket/tsocket_internal.h
+++ b/lib/tsocket/tsocket_internal.h
@@ -57,14 +57,6 @@ struct tsocket_context_ops {
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,
@@ -149,6 +141,47 @@ struct tsocket_address *_tsocket_address_create(TALLOC_CTX *mem_ctx,
_tsocket_address_create(mem_ctx, ops, state, sizeof(type), \
#type, location)
+struct tdgram_context_ops {
+ const char *name;
+
+ struct tevent_req *(*recvfrom_send)(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tdgram_context *dgram);
+ ssize_t (*recvfrom_recv)(struct tevent_req *req,
+ int *perrno,
+ TALLOC_CTX *mem_ctx,
+ uint8_t **buf,
+ struct tsocket_address **src);
+
+ struct tevent_req *(*sendto_send)(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tdgram_context *dgram,
+ const uint8_t *buf, size_t len,
+ const struct tsocket_address *dst);
+ ssize_t (*sendto_recv)(struct tevent_req *req,
+ int *perrno);
+
+ struct tevent_req *(*disconnect_send)(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct tdgram_context *dgram);
+ int (*disconnect_recv)(struct tevent_req *req,
+ int *perrno);
+};
+
+struct tdgram_context *_tdgram_context_create(TALLOC_CTX *mem_ctx,
+ const struct tdgram_context_ops *ops,
+ void *pstate,
+ size_t psize,
+ const char *type,
+ const char *location);
+#define tdgram_context_create(mem_ctx, ops, state, type, location) \
+ _tdgram_context_create(mem_ctx, ops, state, sizeof(type), \
+ #type, location)
+
+void *_tdgram_context_data(struct tdgram_context *dgram);
+#define tdgram_context_data(_req, _type) \
+ talloc_get_type_abort(_tdgram_context_data(_req), _type)
+
int tsocket_error_from_errno(int ret, int sys_errno, bool *retry);
int tsocket_simple_int_recv(struct tevent_req *req, int *perrno);
int tsocket_common_prepare_fd(int fd, bool high_fd);
diff --git a/lib/tsocket/tsocket_recvfrom.c b/lib/tsocket/tsocket_recvfrom.c
deleted file mode 100644
index 467738cfc2..0000000000
--- a/lib/tsocket/tsocket_recvfrom.c
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- Unix SMB/CIFS implementation.
-
- Copyright (C) Stefan Metzmacher 2009
-
- ** NOTE! The following LGPL license applies to the tevent
- ** library. This does NOT imply that all of Samba is released
- ** under the LGPL
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 3 of the License, or (at your option) any later version.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with this library; if not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include "replace.h"
-#include "system/network.h"
-#include "tsocket.h"
-#include "tsocket_internal.h"
-
-struct tsocket_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
deleted file mode 100644
index 9c0a76bf16..0000000000
--- a/lib/tsocket/tsocket_sendto.c
+++ /dev/null
@@ -1,271 +0,0 @@
-/*
- Unix SMB/CIFS implementation.
-
- Copyright (C) Stefan Metzmacher 2009
-
- ** NOTE! The following LGPL license applies to the tevent
- ** library. This does NOT imply that all of Samba is released
- ** under the LGPL
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 3 of the License, or (at your option) any later version.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with this library; if not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include "replace.h"
-#include "system/network.h"
-#include "tsocket.h"
-#include "tsocket_internal.h"
-
-struct tsocket_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/libcli/cldap/cldap.c b/libcli/cldap/cldap.c
index d3fb0bb1e9..8a0c2eec5e 100644
--- a/libcli/cldap/cldap.c
+++ b/libcli/cldap/cldap.c
@@ -51,7 +51,7 @@
*/
struct cldap_socket {
/* the low level socket */
- struct tsocket_context *sock;
+ struct tdgram_context *sock;
/*
* Are we in connected mode, which means
@@ -120,8 +120,6 @@ struct cldap_search_state {
static int cldap_socket_destructor(struct cldap_socket *c)
{
- tsocket_disconnect(c->sock);
-
while (c->searches.list) {
struct cldap_search_state *s = c->searches.list;
DLIST_REMOVE(c->searches.list, s);
@@ -146,7 +144,7 @@ static bool cldap_recvfrom_setup(struct cldap_socket *c)
return true;
}
- c->recv_subreq = tsocket_recvfrom_send(c->sock, c);
+ c->recv_subreq = tdgram_recvfrom_send(c, c->event.ctx, c->sock);
if (!c->recv_subreq) {
return false;
}
@@ -186,11 +184,11 @@ static void cldap_recvfrom_done(struct tevent_req *subreq)
goto nomem;
}
- ret = tsocket_recvfrom_recv(subreq,
- &in->recv_errno,
- in,
- &in->buf,
- &in->src);
+ ret = tdgram_recvfrom_recv(subreq,
+ &in->recv_errno,
+ in,
+ &in->buf,
+ &in->src);
talloc_free(subreq);
subreq = NULL;
if (ret >= 0) {
@@ -337,23 +335,15 @@ NTSTATUS cldap_socket_init(TALLOC_CTX *mem_ctx,
goto nomem;
}
- ret = tsocket_address_create_socket(local_addr,
- TSOCKET_TYPE_DGRAM,
- c, &c->sock);
+ ret = tdgram_inet_udp_socket(local_addr, remote_addr,
+ c, &c->sock);
if (ret != 0) {
status = map_nt_error_from_unix(errno);
goto nterror;
}
talloc_free(any);
- tsocket_set_event_context(c->sock, c->event.ctx);
-
if (remote_addr) {
- ret = tsocket_connect(c->sock, remote_addr);
- if (ret != 0) {
- status = map_nt_error_from_unix(errno);
- goto nterror;
- }
c->connected = true;
}
@@ -408,7 +398,7 @@ struct cldap_reply_state {
DATA_BLOB blob;
};
-static void cldap_reply_state_destroy(struct tevent_req *req);
+static void cldap_reply_state_destroy(struct tevent_req *subreq);
/*
queue a cldap reply for send
@@ -419,7 +409,7 @@ NTSTATUS cldap_reply_send(struct cldap_socket *cldap, struct cldap_reply *io)
struct ldap_message *msg;
DATA_BLOB blob1, blob2;
NTSTATUS status;
- struct tevent_req *req;
+ struct tevent_req *subreq;
if (cldap->connected) {
return NT_STATUS_PIPE_CONNECTED;
@@ -476,17 +466,18 @@ NTSTATUS cldap_reply_send(struct cldap_socket *cldap, struct cldap_reply *io)
data_blob_free(&blob1);
data_blob_free(&blob2);
- req = tsocket_sendto_queue_send(state,
- cldap->sock,
- cldap->send_queue,
- state->blob.data,
- state->blob.length,
- state->dest);
- if (!req) {
+ subreq = tdgram_sendto_queue_send(state,
+ cldap->event.ctx,
+ cldap->sock,
+ cldap->send_queue,
+ state->blob.data,
+ state->blob.length,
+ state->dest);
+ if (!subreq) {
goto nomem;
}
/* the callback will just free the state, as we don't need a result */
- tevent_req_set_callback(req, cldap_reply_state_destroy, state);
+ tevent_req_set_callback(subreq, cldap_reply_state_destroy, state);
return NT_STATUS_OK;
@@ -497,13 +488,13 @@ failed:
return status;
}
-static void cldap_reply_state_destroy(struct tevent_req *req)
+static void cldap_reply_state_destroy(struct tevent_req *subreq)
{
- struct cldap_reply_state *state = tevent_req_callback_data(req,
+ struct cldap_reply_state *state = tevent_req_callback_data(subreq,
struct cldap_reply_state);
/* we don't want to know the result here, we just free the state */
- talloc_free(req);
+ talloc_free(subreq);
talloc_free(state);
}
@@ -630,12 +621,13 @@ struct tevent_req *cldap_search_send(TALLOC_CTX *mem_ctx,
goto post;
}
- subreq = tsocket_sendto_queue_send(state,
- state->caller.cldap->sock,
- state->caller.cldap->send_queue,
- state->request.blob.data,
- state->request.blob.length,
- state->request.dest);
+ subreq = tdgram_sendto_queue_send(state,
+ state->caller.cldap->event.ctx,
+ state->caller.cldap->sock,
+ state->caller.cldap->send_queue,
+ state->request.blob.data,
+ state->request.blob.length,
+ state->request.dest);
if (tevent_req_nomem(subreq, req)) {
goto post;
}
@@ -659,7 +651,7 @@ static void cldap_search_state_queue_done(struct tevent_req *subreq)
int sys_errno = 0;
struct timeval next;
- ret = tsocket_sendto_queue_recv(subreq, &sys_errno);
+ ret = tdgram_sendto_queue_recv(subreq, &sys_errno);
talloc_free(subreq);
if (ret == -1) {
NTSTATUS status;
@@ -708,12 +700,13 @@ static void cldap_search_state_wakeup_done(struct tevent_req *subreq)
return;
}
- subreq = tsocket_sendto_queue_send(state,
- state->caller.cldap->sock,
- state->caller.cldap->send_queue,
- state->request.blob.data,
- state->request.blob.length,
- state->request.dest);
+ subreq = tdgram_sendto_queue_send(state,
+ state->caller.cldap->event.ctx,
+ state->caller.cldap->sock,
+ state->caller.cldap->send_queue,
+ state->request.blob.data,
+ state->request.blob.length,
+ state->request.dest);
if (tevent_req_nomem(subreq, req)) {
return;
}
diff --git a/libcli/util/ntstatus.h b/libcli/util/ntstatus.h
index 1608e2874f..a97ef5337e 100644
--- a/libcli/util/ntstatus.h
+++ b/libcli/util/ntstatus.h
@@ -60,8 +60,8 @@ typedef uint32_t NTSTATUS;
#define ERROR_INSUFFICIENT_BUFFER NT_STATUS(0x007a)
#define ERROR_INVALID_DATATYPE NT_STATUS(0x070c)
-/* XXX Win7 Status code: Name unknown. */
-#define NT_STATUS_WIN7_INVALID_RANGE NT_STATUS(0xC0000000 | 0x01a1)
+/* Win7 status codes. */
+#define NT_STATUS_INVALID_LOCK_RANGE NT_STATUS(0xC0000000 | 0x01a1)
/* Win32 Error codes extracted using a loop in smbclient then printing a
netmon sniff to a file. */
diff --git a/source3/lib/charcnv.c b/source3/lib/charcnv.c
index c3b345142f..03b32c13d4 100644
--- a/source3/lib/charcnv.c
+++ b/source3/lib/charcnv.c
@@ -242,7 +242,7 @@ static size_t convert_string_internal(charset_t from, charset_t to,
DEBUG(3,("convert_string_internal: Conversion error: %s(%s)\n",reason,inbuf));
if (allow_bad_conv)
goto use_as_is;
- break;
+ return (size_t)-1;
case E2BIG:
reason="No more room";
if (!conv_silent) {
@@ -263,11 +263,12 @@ static size_t convert_string_internal(charset_t from, charset_t to,
DEBUG(3,("convert_string_internal: Conversion error: %s(%s)\n",reason,inbuf));
if (allow_bad_conv)
goto use_as_is;
- break;
+
+ return (size_t)-1;
default:
if (!conv_silent)
DEBUG(0,("convert_string_internal: Conversion error: %s(%s)\n",reason,inbuf));
- break;
+ return (size_t)-1;
}
/* smb_panic(reason); */
}
@@ -412,7 +413,11 @@ size_t convert_string(charset_t from, charset_t to,
#ifdef BROKEN_UNICODE_COMPOSE_CHARACTERS
goto general_case;
#else
- return retval + convert_string_internal(from, to, p, slen, q, dlen, allow_bad_conv);
+ size_t ret = convert_string_internal(from, to, p, slen, q, dlen, allow_bad_conv);
+ if (ret == (size_t)-1) {
+ return ret;
+ }
+ return retval + ret;
#endif
}
}
@@ -448,7 +453,11 @@ size_t convert_string(charset_t from, charset_t to,
#ifdef BROKEN_UNICODE_COMPOSE_CHARACTERS
goto general_case;
#else
- return retval + convert_string_internal(from, to, p, slen, q, dlen, allow_bad_conv);
+ size_t ret = convert_string_internal(from, to, p, slen, q, dlen, allow_bad_conv);
+ if (ret == (size_t)-1) {
+ return ret;
+ }
+ return retval + ret;
#endif
}
}
@@ -484,7 +493,11 @@ size_t convert_string(charset_t from, charset_t to,
#ifdef BROKEN_UNICODE_COMPOSE_CHARACTERS
goto general_case;
#else
- return retval + convert_string_internal(from, to, p, slen, q, dlen, allow_bad_conv);
+ size_t ret = convert_string_internal(from, to, p, slen, q, dlen, allow_bad_conv);
+ if (ret == (size_t)-1) {
+ return ret;
+ }
+ return retval + ret;
#endif
}
}
diff --git a/source3/modules/onefs_open.c b/source3/modules/onefs_open.c
index d628443ef9..f315b34c8b 100644
--- a/source3/modules/onefs_open.c
+++ b/source3/modules/onefs_open.c
@@ -199,23 +199,6 @@ static NTSTATUS onefs_open_file(files_struct *fsp,
if ((conn->fs_capabilities & FILE_NAMED_STREAMS) && stream != NULL) {
SMB_ASSERT(fsp->base_fsp);
- /*
- * We have never seen an oplock taken on a stream, and our
- * current implementation doesn't support it. If a request is
- * seen, log a loud error message and ignore the requested
- * oplock.
- */
- if ((oplock_request & ~SAMBA_PRIVATE_OPLOCK_MASK) !=
- NO_OPLOCK) {
- DEBUG(0, ("Oplock(%d) being requested on a stream! "
- "Ignoring oplock request: base=%s, "
- "stream=%s\n",
- oplock_request & ~SAMBA_PRIVATE_OPLOCK_MASK,
- base, stream));
- /* Recover by requesting NO_OPLOCK instead. */
- oplock_request &= SAMBA_PRIVATE_OPLOCK_MASK;
- }
-
DEBUG(10,("Opening a stream: base=%s(%d), stream=%s\n",
base, fsp->base_fsp->fh->fd, stream));
@@ -522,10 +505,7 @@ NTSTATUS onefs_open_file_ntcreate(connection_struct *conn,
*
* 1. Open the base file of a stream: Always done stat-only
*
- * 2. Open the stream: Oplocks are disallowed on streams, so an
- * oplock will never be contended.
- *
- * 3. open_file_fchmod(), which is called from 3 places:
+ * 2. open_file_fchmod(), which is called from 3 places:
* A. try_chown: Posix acls only. Never called on onefs.
* B. set_ea_dos_attributes: Can't be called from onefs, because
* SMB_VFS_SETXATTR return ENOSYS.
@@ -1773,6 +1753,21 @@ static NTSTATUS onefs_create_file_unixpath(connection_struct *conn,
"failed: %s\n", base, nt_errstr(status)));
goto fail;
}
+
+ /*
+ * Testing against windows xp/2003/vista shows that oplocks
+ * can actually be requested and granted on streams (see the
+ * RAW-OPLOCK-STREAM1 smbtorture test).
+ */
+ if ((oplock_request & ~SAMBA_PRIVATE_OPLOCK_MASK) !=
+ NO_OPLOCK) {
+ DEBUG(5, ("Oplock(%d) being requested on a stream! "
+ "Ignoring oplock request: fname=%s\n",
+ oplock_request & ~SAMBA_PRIVATE_OPLOCK_MASK,
+ fname));
+ /* Request NO_OPLOCK instead. */
+ oplock_request &= SAMBA_PRIVATE_OPLOCK_MASK;
+ }
}
/* Covert generic bits in the security descriptor. */
diff --git a/source3/passdb/pdb_tdb.c b/source3/passdb/pdb_tdb.c
index 6c49eb1dc2..dd6e678c99 100644
--- a/source3/passdb/pdb_tdb.c
+++ b/source3/passdb/pdb_tdb.c
@@ -817,12 +817,17 @@ static bool tdb_update_ridrec_only( struct samu* newpwd, int flag )
static bool tdb_update_sam(struct pdb_methods *my_methods, struct samu* newpwd,
int flag)
{
- if (!pdb_get_user_rid(newpwd)) {
+ uint32_t oldrid;
+ uint32_t newrid;
+
+ if (!(newrid = pdb_get_user_rid(newpwd))) {
DEBUG(0,("tdb_update_sam: struct samu (%s) with no RID!\n",
pdb_get_username(newpwd)));
return False;
}
+ oldrid = newrid;
+
/* open the database */
if ( !tdbsam_open( tdbsam_filename ) ) {
@@ -835,11 +840,60 @@ static bool tdb_update_sam(struct pdb_methods *my_methods, struct samu* newpwd,
return false;
}
- if (!tdb_update_samacct_only(newpwd, flag)
- || !tdb_update_ridrec_only(newpwd, flag)) {
+ /* If we are updating, we may be changing this users RID. Retrieve the old RID
+ so we can check. */
+
+ if (flag == TDB_MODIFY) {
+ struct samu *account = samu_new(talloc_tos());
+ if (account == NULL) {
+ DEBUG(0,("tdb_update_sam: samu_new() failed\n"));
+ goto cancel;
+ }
+ if (!NT_STATUS_IS_OK(tdbsam_getsampwnam(my_methods, account, pdb_get_username(newpwd)))) {
+ DEBUG(0,("tdb_update_sam: tdbsam_getsampwnam() for %s failed\n",
+ pdb_get_username(newpwd)));
+ TALLOC_FREE(account);
+ goto cancel;
+ }
+ if (!(oldrid = pdb_get_user_rid(account))) {
+ DEBUG(0,("tdb_update_sam: pdb_get_user_rid() failed\n"));
+ TALLOC_FREE(account);
+ goto cancel;
+ }
+ TALLOC_FREE(account);
+ }
+
+ /* Update the new samu entry. */
+ if (!tdb_update_samacct_only(newpwd, flag)) {
goto cancel;
}
+ /* Now take care of the case where the RID changed. We need
+ * to delete the old RID key and add the new. */
+
+ if (flag == TDB_MODIFY && newrid != oldrid) {
+ fstring keystr;
+
+ /* Delete old RID key */
+ DEBUG(10, ("tdb_update_sam: Deleting key for RID %u\n", oldrid));
+ slprintf(keystr, sizeof(keystr) - 1, "%s%.8x", RIDPREFIX, oldrid);
+ if (!NT_STATUS_IS_OK(dbwrap_delete_bystring(db_sam, keystr))) {
+ DEBUG(0, ("tdb_update_sam: Can't delete %s\n", keystr));
+ goto cancel;
+ }
+ /* Insert new RID key */
+ DEBUG(10, ("tdb_update_sam: Inserting key for RID %u\n", newrid));
+ if (!tdb_update_ridrec_only(newpwd, TDB_INSERT)) {
+ goto cancel;
+ }
+ } else {
+ DEBUG(10, ("tdb_update_sam: %s key for RID %u\n",
+ flag == TDB_MODIFY ? "Updating" : "Inserting", newrid));
+ if (!tdb_update_ridrec_only(newpwd, flag)) {
+ goto cancel;
+ }
+ }
+
if (db_sam->transaction_commit(db_sam) != 0) {
DEBUG(0, ("Could not commit transaction\n"));
return false;
diff --git a/source3/rpc_server/srv_lsa_nt.c b/source3/rpc_server/srv_lsa_nt.c
index 5fdcaf2d4a..0ce2b40f65 100644
--- a/source3/rpc_server/srv_lsa_nt.c
+++ b/source3/rpc_server/srv_lsa_nt.c
@@ -648,14 +648,14 @@ NTSTATUS _lsa_QueryInfoPolicy(pipes_struct *p,
* only a BDC is a backup controller
* of the domain, it controls.
*/
- info->role.role = 2;
+ info->role.role = LSA_ROLE_BACKUP;
break;
default:
/*
* any other role is a primary
* of the domain, it controls.
*/
- info->role.role = 3;
+ info->role.role = LSA_ROLE_PRIMARY;
break;
}
break;
@@ -1434,14 +1434,14 @@ NTSTATUS _lsa_EnumAccounts(pipes_struct *p,
sids = TALLOC_ZERO_ARRAY(p->mem_ctx, struct lsa_SidPtr,
num_entries - *r->in.resume_handle);
if (!sids) {
- SAFE_FREE(sid_list);
+ talloc_free(sid_list);
return NT_STATUS_NO_MEMORY;
}
for (i = *r->in.resume_handle, j = 0; i < num_entries; i++, j++) {
sids[j].sid = sid_dup_talloc(p->mem_ctx, &sid_list[i]);
if (!sids[j].sid) {
- SAFE_FREE(sid_list);
+ talloc_free(sid_list);
return NT_STATUS_NO_MEMORY;
}
}
diff --git a/source3/rpc_server/srv_spoolss_nt.c b/source3/rpc_server/srv_spoolss_nt.c
index 15c137a88c..7bb0571042 100644
--- a/source3/rpc_server/srv_spoolss_nt.c
+++ b/source3/rpc_server/srv_spoolss_nt.c
@@ -4890,6 +4890,174 @@ static WERROR fill_printer_driver_info6(TALLOC_CTX *mem_ctx,
}
/********************************************************************
+ ********************************************************************/
+
+static WERROR fill_spoolss_DriverFileInfo(TALLOC_CTX *mem_ctx,
+ struct spoolss_DriverFileInfo *r,
+ const char *cservername,
+ const char *file_name,
+ enum spoolss_DriverFileType file_type,
+ uint32_t file_version)
+{
+ r->file_name = talloc_asprintf(mem_ctx, "\\\\%s%s",
+ cservername, file_name);
+ W_ERROR_HAVE_NO_MEMORY(r->file_name);
+ r->file_type = file_type;
+ r->file_version = file_version;
+
+ return WERR_OK;
+}
+
+/********************************************************************
+ ********************************************************************/
+
+static WERROR spoolss_DriverFileInfo_from_driver(TALLOC_CTX *mem_ctx,
+ const NT_PRINTER_DRIVER_INFO_LEVEL *driver,
+ const char *cservername,
+ struct spoolss_DriverFileInfo **info_p,
+ uint32_t *count_p)
+{
+ struct spoolss_DriverFileInfo *info = NULL;
+ uint32_t count = 0;
+ WERROR result;
+ uint32_t i;
+
+ *info_p = NULL;
+ *count_p = 0;
+
+ if (strlen(driver->info_3->driverpath)) {
+ info = TALLOC_REALLOC_ARRAY(mem_ctx, info,
+ struct spoolss_DriverFileInfo,
+ count + 1);
+ W_ERROR_HAVE_NO_MEMORY(info);
+ result = fill_spoolss_DriverFileInfo(info,
+ &info[count],
+ cservername,
+ driver->info_3->driverpath,
+ SPOOLSS_DRIVER_FILE_TYPE_RENDERING,
+ 0);
+ W_ERROR_NOT_OK_RETURN(result);
+ count++;
+ }
+
+ if (strlen(driver->info_3->configfile)) {
+ info = TALLOC_REALLOC_ARRAY(mem_ctx, info,
+ struct spoolss_DriverFileInfo,
+ count + 1);
+ W_ERROR_HAVE_NO_MEMORY(info);
+ result = fill_spoolss_DriverFileInfo(info,
+ &info[count],
+ cservername,
+ driver->info_3->configfile,
+ SPOOLSS_DRIVER_FILE_TYPE_CONFIGURATION,
+ 0);
+ W_ERROR_NOT_OK_RETURN(result);
+ count++;
+ }
+
+ if (strlen(driver->info_3->datafile)) {
+ info = TALLOC_REALLOC_ARRAY(mem_ctx, info,
+ struct spoolss_DriverFileInfo,
+ count + 1);
+ W_ERROR_HAVE_NO_MEMORY(info);
+ result = fill_spoolss_DriverFileInfo(info,
+ &info[count],
+ cservername,
+ driver->info_3->datafile,
+ SPOOLSS_DRIVER_FILE_TYPE_DATA,
+ 0);
+ W_ERROR_NOT_OK_RETURN(result);
+ count++;
+ }
+
+ if (strlen(driver->info_3->helpfile)) {
+ info = TALLOC_REALLOC_ARRAY(mem_ctx, info,
+ struct spoolss_DriverFileInfo,
+ count + 1);
+ W_ERROR_HAVE_NO_MEMORY(info);
+ result = fill_spoolss_DriverFileInfo(info,
+ &info[count],
+ cservername,
+ driver->info_3->helpfile,
+ SPOOLSS_DRIVER_FILE_TYPE_HELP,
+ 0);
+ W_ERROR_NOT_OK_RETURN(result);
+ count++;
+ }
+
+ for (i=0; driver->info_3->dependentfiles[i][0] != '\0'; i++) {
+ info = TALLOC_REALLOC_ARRAY(mem_ctx, info,
+ struct spoolss_DriverFileInfo,
+ count + 1);
+ W_ERROR_HAVE_NO_MEMORY(info);
+ result = fill_spoolss_DriverFileInfo(info,
+ &info[count],
+ cservername,
+ driver->info_3->dependentfiles[i],
+ SPOOLSS_DRIVER_FILE_TYPE_OTHER,
+ 0);
+ W_ERROR_NOT_OK_RETURN(result);
+ count++;
+ }
+
+ *info_p = info;
+ *count_p = count;
+
+ return WERR_OK;
+}
+
+/********************************************************************
+ * fill a spoolss_DriverInfo101 sttruct
+ ********************************************************************/
+
+static WERROR fill_printer_driver_info101(TALLOC_CTX *mem_ctx,
+ struct spoolss_DriverInfo101 *r,
+ const NT_PRINTER_DRIVER_INFO_LEVEL *driver,
+ const char *servername)
+{
+ const char *cservername = canon_servername(servername);
+ WERROR result;
+
+ r->version = driver->info_3->cversion;
+
+ r->driver_name = talloc_strdup(mem_ctx, driver->info_3->name);
+ W_ERROR_HAVE_NO_MEMORY(r->driver_name);
+ r->architecture = talloc_strdup(mem_ctx, driver->info_3->environment);
+ W_ERROR_HAVE_NO_MEMORY(r->architecture);
+
+ result = spoolss_DriverFileInfo_from_driver(mem_ctx, driver,
+ cservername,
+ &r->file_info,
+ &r->file_count);
+ if (!W_ERROR_IS_OK(result)) {
+ return result;
+ }
+
+ r->monitor_name = talloc_strdup(mem_ctx, driver->info_3->monitorname);
+ W_ERROR_HAVE_NO_MEMORY(r->monitor_name);
+
+ r->default_datatype = talloc_strdup(mem_ctx, driver->info_3->defaultdatatype);
+ W_ERROR_HAVE_NO_MEMORY(r->default_datatype);
+
+ r->previous_names = string_array_from_driver_info(mem_ctx,
+ NULL,
+ cservername);
+ r->driver_date = 0;
+ r->driver_version = 0;
+
+ r->manufacturer_name = talloc_strdup(mem_ctx, "");
+ W_ERROR_HAVE_NO_MEMORY(r->manufacturer_name);
+ r->manufacturer_url = talloc_strdup(mem_ctx, "");
+ W_ERROR_HAVE_NO_MEMORY(r->manufacturer_url);
+ r->hardware_id = talloc_strdup(mem_ctx, "");
+ W_ERROR_HAVE_NO_MEMORY(r->hardware_id);
+ r->provider = talloc_strdup(mem_ctx, "");
+ W_ERROR_HAVE_NO_MEMORY(r->provider);
+
+ return WERR_OK;
+}
+
+/********************************************************************
* construct_printer_driver_info_1
********************************************************************/
@@ -5077,6 +5245,69 @@ static WERROR construct_printer_driver_info_6(TALLOC_CTX *mem_ctx,
return status;
}
+/********************************************************************
+ * construct_printer_info_101
+ * fill a printer_info_101 struct
+ ********************************************************************/
+
+static WERROR construct_printer_driver_info_101(TALLOC_CTX *mem_ctx,
+ struct spoolss_DriverInfo101 *r,
+ int snum,
+ const char *servername,
+ const char *architecture,
+ uint32_t version)
+{
+ NT_PRINTER_INFO_LEVEL *printer = NULL;
+ NT_PRINTER_DRIVER_INFO_LEVEL driver;
+ WERROR result;
+
+ ZERO_STRUCT(driver);
+
+ result = get_a_printer(NULL, &printer, 2, lp_const_servicename(snum));
+
+ DEBUG(8,("construct_printer_driver_info_101: status: %s\n",
+ win_errstr(result)));
+
+ if (!W_ERROR_IS_OK(result)) {
+ return WERR_INVALID_PRINTER_NAME;
+ }
+
+ result = get_a_printer_driver(&driver, 3, printer->info_2->drivername,
+ architecture, version);
+
+ DEBUG(8,("construct_printer_driver_info_101: status: %s\n",
+ win_errstr(result)));
+
+ if (!W_ERROR_IS_OK(result)) {
+ /*
+ * Is this a W2k client ?
+ */
+
+ if (version < 3) {
+ free_a_printer(&printer, 2);
+ return WERR_UNKNOWN_PRINTER_DRIVER;
+ }
+
+ /* Yes - try again with a WinNT driver. */
+ version = 2;
+ result = get_a_printer_driver(&driver, 3, printer->info_2->drivername,
+ architecture, version);
+ DEBUG(8,("construct_printer_driver_info_6: status: %s\n",
+ win_errstr(result)));
+ if (!W_ERROR_IS_OK(result)) {
+ free_a_printer(&printer, 2);
+ return WERR_UNKNOWN_PRINTER_DRIVER;
+ }
+ }
+
+ result = fill_printer_driver_info101(mem_ctx, r, &driver, servername);
+
+ free_a_printer(&printer, 2);
+ free_a_printer_driver(driver, 3);
+
+ return result;
+}
+
/****************************************************************
_spoolss_GetPrinterDriver2
****************************************************************/
@@ -5146,13 +5377,15 @@ WERROR _spoolss_GetPrinterDriver2(pipes_struct *p,
r->in.architecture,
r->in.client_major_version);
break;
- default:
-#if 0 /* JERRY */
case 101:
- /* apparently this call is the equivalent of
- EnumPrinterDataEx() for the DsDriver key */
+ result = construct_printer_driver_info_101(p->mem_ctx,
+ &r->out.info->info101,
+ snum,
+ servername,
+ r->in.architecture,
+ r->in.client_major_version);
break;
-#endif
+ default:
result = WERR_UNKNOWN_LEVEL;
break;
}
diff --git a/source4/libcli/util/nterr.c b/source4/libcli/util/nterr.c
index 7f544b5922..c196433710 100644
--- a/source4/libcli/util/nterr.c
+++ b/source4/libcli/util/nterr.c
@@ -549,7 +549,7 @@ static const nt_err_code_struct nt_errs[] =
{ "NT_STATUS_OBJECTID_NOT_FOUND", NT_STATUS_OBJECTID_NOT_FOUND },
{ "NT_STATUS_DOWNGRADE_DETECTED", NT_STATUS_DOWNGRADE_DETECTED },
{ "NT_STATUS_DS_BUSY", NT_STATUS_DS_BUSY },
- { "XXX_INVALID_RANGE", NT_STATUS_WIN7_INVALID_RANGE },
+ { "NT_STATUS_INVALID_LOCK_RANGE", NT_STATUS_INVALID_LOCK_RANGE },
{ "STATUS_MORE_ENTRIES", STATUS_MORE_ENTRIES },
{ "STATUS_SOME_UNMAPPED", STATUS_SOME_UNMAPPED },
{ "STATUS_NOTIFY_CLEANUP", STATUS_NOTIFY_CLEANUP },
diff --git a/source4/torture/raw/lock.c b/source4/torture/raw/lock.c
index 72a03e1623..7e3ac29809 100644
--- a/source4/torture/raw/lock.c
+++ b/source4/torture/raw/lock.c
@@ -364,7 +364,7 @@ static bool test_lockx(struct torture_context *tctx, struct smbcli_state *cli)
lock[0].count = 2;
status = smb_raw_lock(cli->tree, &io);
if (TARGET_IS_WIN7(tctx))
- CHECK_STATUS(status, NT_STATUS_WIN7_INVALID_RANGE);
+ CHECK_STATUS(status, NT_STATUS_INVALID_LOCK_RANGE);
else
CHECK_STATUS(status, NT_STATUS_OK);
lock[0].pid--;
@@ -376,7 +376,7 @@ static bool test_lockx(struct torture_context *tctx, struct smbcli_state *cli)
/* XXX This is very strange - Win7 gives us an invalid range when we
* unlock the range even though the range is locked! Win7 bug? */
if (TARGET_IS_WIN7(tctx))
- CHECK_STATUS(status, NT_STATUS_WIN7_INVALID_RANGE);
+ CHECK_STATUS(status, NT_STATUS_INVALID_LOCK_RANGE);
else {
CHECK_STATUS(status, NT_STATUS_OK);
status = smb_raw_lock(cli->tree, &io);
diff --git a/source4/torture/raw/lockbench.c b/source4/torture/raw/lockbench.c
index d20175a018..c7f99aeb3c 100644
--- a/source4/torture/raw/lockbench.c
+++ b/source4/torture/raw/lockbench.c
@@ -317,13 +317,15 @@ bool torture_bench_lock(struct torture_context *torture)
{
bool ret = true;
TALLOC_CTX *mem_ctx = talloc_new(torture);
- int i;
+ int i, j;
int timelimit = torture_setting_int(torture, "timelimit", 10);
struct timeval tv;
struct benchlock_state *state;
int total = 0, minops=0;
struct smbcli_state *cli;
bool progress;
+ off_t offset;
+ int initial_locks = torture_setting_int(torture, "initial_locks", 0);
progress = torture_setting_bool(torture, "progress", true);
@@ -371,6 +373,21 @@ bool torture_bench_lock(struct torture_context *torture)
goto failed;
}
+ /* Optionally, lock initial_locks for each proc beforehand. */
+ if (i == 0 && initial_locks > 0) {
+ printf("Initializing %d locks on each proc.\n",
+ initial_locks);
+ }
+
+ for (j = 0; j < initial_locks; j++) {
+ offset = (0xFFFFFED8LLU * (i+2)) + j;
+ if (!NT_STATUS_IS_OK(smbcli_lock64(state[i].tree,
+ state[i].fnum, offset, 1, 0, WRITE_LOCK))) {
+ printf("Failed initializing, lock=%d\n", j);
+ goto failed;
+ }
+ }
+
state[i].stage = LOCK_INITIAL;
lock_send(&state[i]);
}
@@ -413,6 +430,7 @@ bool torture_bench_lock(struct torture_context *torture)
return ret;
failed:
+ smbcli_deltree(state[0].tree, BASEDIR);
talloc_free(mem_ctx);
return false;
}
diff --git a/source4/torture/raw/oplock.c b/source4/torture/raw/oplock.c
index 0aeded8664..3493a552c3 100644
--- a/source4/torture/raw/oplock.c
+++ b/source4/torture/raw/oplock.c
@@ -2855,6 +2855,181 @@ done:
return ret;
}
+/* Test how oplocks work on streams. */
+static bool test_raw_oplock_stream1(struct torture_context *tctx,
+ struct smbcli_state *cli1,
+ struct smbcli_state *cli2)
+{
+ NTSTATUS status;
+ union smb_open io;
+ const char *fname_base = BASEDIR "\\test_stream1.txt";
+ const char *stream = "Stream One:$DATA";
+ const char *fname_stream, *fname_default_stream;
+ const char *default_stream = "::$DATA";
+ bool ret = true;
+ int fnum = -1;
+ int i;
+ int stream_fnum = -1;
+ uint32_t batch_req = NTCREATEX_FLAGS_REQUEST_OPLOCK |
+ NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK | NTCREATEX_FLAGS_EXTENDED;
+ uint32_t exclusive_req = NTCREATEX_FLAGS_REQUEST_OPLOCK |
+ NTCREATEX_FLAGS_EXTENDED;
+
+ /* Only passes against windows at the moment. */
+ if (torture_setting_bool(tctx, "samba3", false) ||
+ torture_setting_bool(tctx, "samba4", false)) {
+ torture_skip(tctx, "STREAM1 disabled against samba3+4\n");
+ }
+
+ fname_stream = talloc_asprintf(tctx, "%s:%s", fname_base, stream);
+ fname_default_stream = talloc_asprintf(tctx, "%s%s", fname_base,
+ default_stream);
+
+ if (!torture_setup_dir(cli1, BASEDIR)) {
+ return false;
+ }
+ smbcli_unlink(cli1->tree, fname_base);
+
+ smbcli_oplock_handler(cli2->transport, oplock_handler_ack_to_given, cli2->tree);
+ smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_given, cli1->tree);
+
+ /* Setup generic open parameters. */
+ io.generic.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.root_fid = 0;
+ io.ntcreatex.in.access_mask = (SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA|
+ SEC_FILE_APPEND_DATA|SEC_STD_READ_CONTROL);
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+ io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+ io.ntcreatex.in.security_flags = 0;
+
+ /* Create the file with a stream */
+ io.ntcreatex.in.fname = fname_stream;
+ io.ntcreatex.in.flags = 0;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+ status = smb_raw_open(cli1->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ smbcli_close(cli1->tree, io.ntcreatex.out.file.fnum);
+
+ /* Change the disposition to open now that the file has been created. */
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+
+ /* Try some permutations of taking oplocks on streams. */
+#define NSTREAM_OPLOCK_RESULTS 8
+ struct {
+ const char *fname;
+ bool open_base_file;
+ uint32_t oplock_req;
+ uint32_t oplock_granted;
+ } stream_oplock_results[NSTREAM_OPLOCK_RESULTS] = {
+ /* Request oplock on stream without the base file open. */
+ {fname_stream, false, batch_req, NO_OPLOCK_RETURN},
+ {fname_default_stream, false, batch_req, NO_OPLOCK_RETURN},
+ {fname_stream, false, exclusive_req, EXCLUSIVE_OPLOCK_RETURN},
+ {fname_default_stream, false, exclusive_req, EXCLUSIVE_OPLOCK_RETURN},
+
+ /* Request oplock on stream with the base file open. */
+ {fname_stream, true, batch_req, NO_OPLOCK_RETURN},
+ {fname_default_stream, true, batch_req, NO_OPLOCK_RETURN},
+ {fname_stream, true, exclusive_req, EXCLUSIVE_OPLOCK_RETURN},
+ {fname_default_stream, true, exclusive_req, LEVEL_II_OPLOCK_RETURN},
+
+ };
+
+ for (i = 0; i < NSTREAM_OPLOCK_RESULTS; i++) {
+ const char *fname = stream_oplock_results[i].fname;
+ bool open_base_file = stream_oplock_results[i].open_base_file;
+ uint32_t oplock_req = stream_oplock_results[i].oplock_req;
+ uint32_t oplock_granted =
+ stream_oplock_results[i].oplock_granted;
+ int base_fnum = -1;
+
+ if (open_base_file) {
+ torture_comment(tctx, "Opening base file: %s with "
+ "%d\n", fname_base, oplock_req);
+ io.ntcreatex.in.fname = fname_base;
+ io.ntcreatex.in.flags = batch_req;
+ status = smb_raw_open(cli2->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ CHECK_VAL(io.ntcreatex.out.oplock_level,
+ BATCH_OPLOCK_RETURN);
+ base_fnum = io.ntcreatex.out.file.fnum;
+ }
+
+ torture_comment(tctx, "%d: Opening stream: %s with %d\n", i,
+ fname, oplock_req);
+ io.ntcreatex.in.fname = fname;
+ io.ntcreatex.in.flags = oplock_req;
+
+ /* Do the open with the desired oplock on the stream. */
+ status = smb_raw_open(cli1->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ CHECK_VAL(io.ntcreatex.out.oplock_level, oplock_granted);
+ smbcli_close(cli1->tree, io.ntcreatex.out.file.fnum);
+
+ /* Cleanup the base file if it was opened. */
+ if (base_fnum != -1) {
+ smbcli_close(cli2->tree, base_fnum);
+ }
+ }
+
+ /* Open the stream with an exclusive oplock. */
+ torture_comment(tctx, "Opening stream: %s with %d\n",
+ fname_stream, exclusive_req);
+ io.ntcreatex.in.fname = fname_stream;
+ io.ntcreatex.in.flags = exclusive_req;
+ status = smb_raw_open(cli1->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ CHECK_VAL(io.ntcreatex.out.oplock_level, EXCLUSIVE_OPLOCK_RETURN);
+ stream_fnum = io.ntcreatex.out.file.fnum;
+
+ /* Open the base file and see if it contends. */
+ ZERO_STRUCT(break_info);
+ torture_comment(tctx, "Opening base file: %s with "
+ "%d\n", fname_base, batch_req);
+ io.ntcreatex.in.fname = fname_base;
+ io.ntcreatex.in.flags = batch_req;
+ status = smb_raw_open(cli2->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ CHECK_VAL(io.ntcreatex.out.oplock_level,
+ BATCH_OPLOCK_RETURN);
+ smbcli_close(cli2->tree, io.ntcreatex.out.file.fnum);
+
+ CHECK_VAL(break_info.count, 0);
+ CHECK_VAL(break_info.failures, 0);
+
+ /* Open the stream again to see if it contends. */
+ ZERO_STRUCT(break_info);
+ torture_comment(tctx, "Opening stream again: %s with "
+ "%d\n", fname_base, batch_req);
+ io.ntcreatex.in.fname = fname_stream;
+ io.ntcreatex.in.flags = exclusive_req;
+ status = smb_raw_open(cli2->tree, tctx, &io);
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ CHECK_VAL(io.ntcreatex.out.oplock_level,
+ LEVEL_II_OPLOCK_RETURN);
+ smbcli_close(cli2->tree, io.ntcreatex.out.file.fnum);
+
+ CHECK_VAL(break_info.count, 1);
+ CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
+ CHECK_VAL(break_info.failures, 0);
+
+ /* Close the stream. */
+ if (stream_fnum != -1) {
+ smbcli_close(cli1->tree, stream_fnum);
+ }
+
+ done:
+ smbcli_close(cli1->tree, fnum);
+ smb_raw_exit(cli1->session);
+ smb_raw_exit(cli2->session);
+ smbcli_deltree(cli1->tree, BASEDIR);
+ return ret;
+}
+
/*
basic testing of oplocks
*/
@@ -2893,6 +3068,7 @@ struct torture_suite *torture_raw_oplock(TALLOC_CTX *mem_ctx)
torture_suite_add_2smb_test(suite, "BATCH23", test_raw_oplock_batch23);
torture_suite_add_2smb_test(suite, "BATCH24", test_raw_oplock_batch24);
torture_suite_add_2smb_test(suite, "BATCH25", test_raw_oplock_batch25);
+ torture_suite_add_2smb_test(suite, "STREAM1", test_raw_oplock_stream1);
return suite;
}
diff --git a/source4/torture/raw/streams.c b/source4/torture/raw/streams.c
index d0d21ccc06..818eb402dd 100644
--- a/source4/torture/raw/streams.c
+++ b/source4/torture/raw/streams.c
@@ -1309,7 +1309,6 @@ static bool test_stream_rename2(struct torture_context *tctx,
static bool create_file_with_stream(struct torture_context *tctx,
struct smbcli_state *cli,
TALLOC_CTX *mem_ctx,
- const char *base_fname,
const char *stream)
{
NTSTATUS status;
@@ -1359,8 +1358,7 @@ static bool test_stream_create_disposition(struct torture_context *tctx,
stream_list[0] = talloc_asprintf(mem_ctx, ":%s", stream);
stream_list[1] = default_stream_name;
- if (!create_file_with_stream(tctx, cli, mem_ctx, fname,
- fname_stream)) {
+ if (!create_file_with_stream(tctx, cli, mem_ctx, fname_stream)) {
goto done;
}
@@ -1407,8 +1405,7 @@ static bool test_stream_create_disposition(struct torture_context *tctx,
*/
printf("(%s) Checking ntcreatex disp: overwrite_if\n", __location__);
smbcli_unlink(cli->tree, fname);
- if (!create_file_with_stream(tctx, cli, mem_ctx, fname,
- fname_stream)) {
+ if (!create_file_with_stream(tctx, cli, mem_ctx, fname_stream)) {
goto done;
}
@@ -1425,8 +1422,7 @@ static bool test_stream_create_disposition(struct torture_context *tctx,
*/
printf("(%s) Checking ntcreatex disp: supersede\n", __location__);
smbcli_unlink(cli->tree, fname);
- if (!create_file_with_stream(tctx, cli, mem_ctx, fname,
- fname_stream)) {
+ if (!create_file_with_stream(tctx, cli, mem_ctx, fname_stream)) {
goto done;
}
@@ -1444,8 +1440,7 @@ static bool test_stream_create_disposition(struct torture_context *tctx,
printf("(%s) Checking ntcreatex disp: overwrite_if on stream\n",
__location__);
smbcli_unlink(cli->tree, fname);
- if (!create_file_with_stream(tctx, cli, mem_ctx, fname,
- fname_stream)) {
+ if (!create_file_with_stream(tctx, cli, mem_ctx, fname_stream)) {
goto done;
}
@@ -1463,8 +1458,7 @@ static bool test_stream_create_disposition(struct torture_context *tctx,
*/
printf("(%s) Checking openx disp: overwrite_if\n", __location__);
smbcli_unlink(cli->tree, fname);
- if (!create_file_with_stream(tctx, cli, mem_ctx, fname,
- fname_stream)) {
+ if (!create_file_with_stream(tctx, cli, mem_ctx, fname_stream)) {
goto done;
}
@@ -1517,7 +1511,7 @@ static bool test_stream_large_streaminfo(struct torture_context *tctx,
for (i = 0; i < 10000; i++) {
fname_stream = talloc_asprintf(mem_ctx, "%s:%s%d", fname,
lstream_name, i);
- ret = create_file_with_stream(tctx, cli, mem_ctx, fname,
+ ret = create_file_with_stream(tctx, cli, mem_ctx,
fname_stream);
if (!ret) {
goto done;
@@ -1556,8 +1550,7 @@ static bool test_stream_attributes(struct torture_context *tctx,
fname_stream = talloc_asprintf(mem_ctx, "%s:%s", fname, stream);
/* Create a file with a stream with attribute FILE_ATTRIBUTE_ARCHIVE. */
- ret = create_file_with_stream(tctx, cli, mem_ctx, fname,
- fname_stream);
+ ret = create_file_with_stream(tctx, cli, mem_ctx, fname_stream);
if (!ret) {
goto done;
}
diff --git a/source4/torture/smb2/lock.c b/source4/torture/smb2/lock.c
index 5f0293c681..844309efd4 100644
--- a/source4/torture/smb2/lock.c
+++ b/source4/torture/smb2/lock.c
@@ -101,7 +101,7 @@ static bool test_valid_request(struct torture_context *torture, struct smb2_tree
el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE|SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
status = smb2_lock(tree, &lck);
if (TARGET_IS_WIN7(torture)) {
- CHECK_STATUS(status, NT_STATUS_WIN7_INVALID_RANGE);
+ CHECK_STATUS(status, NT_STATUS_INVALID_LOCK_RANGE);
} else {
CHECK_STATUS(status, NT_STATUS_OK);
}
@@ -110,7 +110,7 @@ static bool test_valid_request(struct torture_context *torture, struct smb2_tree
lck.in.reserved = 0x123ab2;
status = smb2_lock(tree, &lck);
if (TARGET_IS_WIN7(torture)) {
- CHECK_STATUS(status, NT_STATUS_WIN7_INVALID_RANGE);
+ CHECK_STATUS(status, NT_STATUS_INVALID_LOCK_RANGE);
} else {
CHECK_STATUS(status, NT_STATUS_OK);
}
@@ -118,7 +118,7 @@ static bool test_valid_request(struct torture_context *torture, struct smb2_tree
lck.in.reserved = 0x123ab3;
status = smb2_lock(tree, &lck);
if (TARGET_IS_WIN7(torture)) {
- CHECK_STATUS(status, NT_STATUS_WIN7_INVALID_RANGE);
+ CHECK_STATUS(status, NT_STATUS_INVALID_LOCK_RANGE);
} else if (TARGET_IS_WINDOWS(torture)) {
CHECK_STATUS(status, NT_STATUS_OK);
} else {
@@ -129,7 +129,7 @@ static bool test_valid_request(struct torture_context *torture, struct smb2_tree
lck.in.reserved = 0x123ab4;
status = smb2_lock(tree, &lck);
if (TARGET_IS_WIN7(torture)) {
- CHECK_STATUS(status, NT_STATUS_WIN7_INVALID_RANGE);
+ CHECK_STATUS(status, NT_STATUS_INVALID_LOCK_RANGE);
} else {
CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
}
@@ -137,7 +137,7 @@ static bool test_valid_request(struct torture_context *torture, struct smb2_tree
lck.in.reserved = 0x123ab5;
status = smb2_lock(tree, &lck);
if (TARGET_IS_WIN7(torture)) {
- CHECK_STATUS(status, NT_STATUS_WIN7_INVALID_RANGE);
+ CHECK_STATUS(status, NT_STATUS_INVALID_LOCK_RANGE);
} else if (TARGET_IS_WINDOWS(torture)) {
CHECK_STATUS(status, NT_STATUS_OK);
} else {