From e551f43b4b690d92cbf00a510e6c79a497d91464 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Thu, 1 Jan 2009 18:16:42 +0100 Subject: Remove two pointless globals --- source3/lib/ldb/tools/ldbadd.c | 13 ++++++------- source3/lib/ldb/tools/ldbmodify.c | 12 ++++++------ 2 files changed, 12 insertions(+), 13 deletions(-) (limited to 'source3/lib') diff --git a/source3/lib/ldb/tools/ldbadd.c b/source3/lib/ldb/tools/ldbadd.c index 4dde2a1ef5..155395e065 100644 --- a/source3/lib/ldb/tools/ldbadd.c +++ b/source3/lib/ldb/tools/ldbadd.c @@ -35,8 +35,6 @@ #include "ldb/include/includes.h" #include "ldb/tools/cmdline.h" -static int failures; - static void usage(void) { printf("Usage: ldbadd \n"); @@ -53,7 +51,8 @@ static void usage(void) /* add records from an opened file */ -static int process_file(struct ldb_context *ldb, FILE *f, int *count) +static int process_file(struct ldb_context *ldb, FILE *f, int *count, + int *failures) { struct ldb_ldif *ldif; int ret = LDB_SUCCESS; @@ -71,7 +70,7 @@ static int process_file(struct ldb_context *ldb, FILE *f, int *count) if (ret != LDB_SUCCESS) { fprintf(stderr, "ERR: \"%s\" on DN %s\n", ldb_errstring(ldb), ldb_dn_linearize(ldb, ldif->msg->dn)); - failures++; + (*failures)++; } else { (*count)++; } @@ -86,7 +85,7 @@ static int process_file(struct ldb_context *ldb, FILE *f, int *count) int main(int argc, const char **argv) { struct ldb_context *ldb; - int i, ret=0, count=0; + int i, ret=0, count=0, failures=0; struct ldb_cmdline *options; ldb_global_init(); @@ -96,7 +95,7 @@ int main(int argc, const char **argv) options = ldb_cmdline_process(ldb, argc, argv, usage); if (options->argc == 0) { - ret = process_file(ldb, stdin, &count); + ret = process_file(ldb, stdin, &count, &failures); } else { for (i=0;iargc;i++) { const char *fname = options->argv[i]; @@ -106,7 +105,7 @@ int main(int argc, const char **argv) perror(fname); exit(1); } - ret = process_file(ldb, f, &count); + ret = process_file(ldb, f, &count, &failures); fclose(f); } } diff --git a/source3/lib/ldb/tools/ldbmodify.c b/source3/lib/ldb/tools/ldbmodify.c index 368b4cf996..f12387a8f6 100644 --- a/source3/lib/ldb/tools/ldbmodify.c +++ b/source3/lib/ldb/tools/ldbmodify.c @@ -35,8 +35,6 @@ #include "ldb/include/includes.h" #include "ldb/tools/cmdline.h" -static int failures; - static void usage(void) { printf("Usage: ldbmodify \n"); @@ -52,7 +50,8 @@ static void usage(void) /* process modifies for one file */ -static int process_file(struct ldb_context *ldb, FILE *f, int *count) +static int process_file(struct ldb_context *ldb, FILE *f, int *count, + int *failures) { struct ldb_ldif *ldif; int ret = LDB_SUCCESS; @@ -73,7 +72,7 @@ static int process_file(struct ldb_context *ldb, FILE *f, int *count) if (ret != LDB_SUCCESS) { fprintf(stderr, "ERR: \"%s\" on DN %s\n", ldb_errstring(ldb), ldb_dn_linearize(ldb, ldif->msg->dn)); - failures++; + (*failures)++; } else { (*count)++; } @@ -87,6 +86,7 @@ int main(int argc, const char **argv) { struct ldb_context *ldb; int count=0; + int failures=0; int i, ret=LDB_SUCCESS; struct ldb_cmdline *options; @@ -97,7 +97,7 @@ int main(int argc, const char **argv) options = ldb_cmdline_process(ldb, argc, argv, usage); if (options->argc == 0) { - ret = process_file(ldb, stdin, &count); + ret = process_file(ldb, stdin, &count, &failures); } else { for (i=0;iargc;i++) { const char *fname = options->argv[i]; @@ -107,7 +107,7 @@ int main(int argc, const char **argv) perror(fname); exit(1); } - ret = process_file(ldb, f, &count); + ret = process_file(ldb, f, &count, &failures); } } -- cgit From 7458111ea4cf33b2a093e5edfb3b42ebfdc330c5 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Thu, 1 Jan 2009 22:05:03 +0100 Subject: Fix bug 5913. Never seen this to be a problem, but it doesn't hurt either :-) --- source3/lib/ldb/include/ldb.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source3/lib') diff --git a/source3/lib/ldb/include/ldb.h b/source3/lib/ldb/include/ldb.h index 0a745742d9..3891c1c6a3 100644 --- a/source3/lib/ldb/include/ldb.h +++ b/source3/lib/ldb/include/ldb.h @@ -991,7 +991,7 @@ int ldb_search(struct ldb_context *ldb, const struct ldb_dn *base, enum ldb_scope scope, const char *expression, - const char * const *attrs, struct ldb_result **res); + const char * const *attrs, struct ldb_result **_res); /* * a useful search function where you can easily define the expression and -- cgit From aed8c7bfcfb3c860758d39d476ca87ef9eda2b6d Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Sat, 20 Dec 2008 10:44:29 +0100 Subject: packet.h API: The callback is now responsible to talloc_free() "buf" --- source3/lib/ctdbd_conn.c | 49 +++++++++++++++++++++++++++--------------------- source3/lib/packet.c | 32 +++++++++++++++++-------------- 2 files changed, 46 insertions(+), 35 deletions(-) (limited to 'source3/lib') diff --git a/source3/lib/ctdbd_conn.c b/source3/lib/ctdbd_conn.c index 8d97606b85..75a513312e 100644 --- a/source3/lib/ctdbd_conn.c +++ b/source3/lib/ctdbd_conn.c @@ -155,17 +155,17 @@ static NTSTATUS ctdbd_connect(TALLOC_CTX *mem_ctx, * Do we have a complete ctdb packet in the queue? */ -static bool ctdb_req_complete(const DATA_BLOB *data, +static bool ctdb_req_complete(const uint8_t *buf, size_t available, size_t *length, void *private_data) { uint32 msglen; - if (data->length < sizeof(msglen)) { + if (available < sizeof(msglen)) { return False; } - msglen = *((uint32 *)data->data); + msglen = *((uint32 *)buf); DEBUG(10, ("msglen = %d\n", msglen)); @@ -176,12 +176,12 @@ static bool ctdb_req_complete(const DATA_BLOB *data, cluster_fatal("ctdbd protocol error\n"); } - if (data->length >= msglen) { - *length = msglen; - return True; + if (available < msglen) { + return false; } - return False; + *length = msglen; + return true; } /* @@ -220,16 +220,13 @@ struct req_pull_state { * Pull a ctdb request out of the incoming packet queue */ -static NTSTATUS ctdb_req_pull(const DATA_BLOB *data, +static NTSTATUS ctdb_req_pull(uint8_t *buf, size_t length, void *private_data) { struct req_pull_state *state = (struct req_pull_state *)private_data; - state->req = data_blob_talloc(state->mem_ctx, data->data, - data->length); - if (state->req.data == NULL) { - return NT_STATUS_NO_MEMORY; - } + state->req.data = talloc_move(state->mem_ctx, &buf); + state->req.length = length; return NT_STATUS_OK; } @@ -497,7 +494,7 @@ NTSTATUS ctdbd_messaging_connection(TALLOC_CTX *mem_ctx, /* * Packet handler to receive and handle a ctdb message */ -static NTSTATUS ctdb_handle_message(const DATA_BLOB *data, +static NTSTATUS ctdb_handle_message(uint8_t *buf, size_t length, void *private_data) { struct ctdbd_connection *conn = talloc_get_type_abort( @@ -505,11 +502,12 @@ static NTSTATUS ctdb_handle_message(const DATA_BLOB *data, struct ctdb_req_message *msg; struct messaging_rec *msg_rec; - msg = (struct ctdb_req_message *)data->data; + msg = (struct ctdb_req_message *)buf; if (msg->hdr.operation != CTDB_REQ_MESSAGE) { DEBUG(0, ("Received async msg of type %u, discarding\n", msg->hdr.operation)); + TALLOC_FREE(buf); return NT_STATUS_INVALID_PARAMETER; } @@ -519,6 +517,7 @@ static NTSTATUS ctdb_handle_message(const DATA_BLOB *data, DEBUG(10, ("received CTDB_SRVID_RELEASE_IP\n")); conn->release_ip_handler((const char *)msg->data, conn->release_ip_priv); + TALLOC_FREE(buf); return NT_STATUS_OK; } @@ -540,6 +539,8 @@ static NTSTATUS ctdb_handle_message(const DATA_BLOB *data, */ message_send_all(conn->msg_ctx, MSG_SMB_UNLOCK, NULL, 0, NULL); + TALLOC_FREE(buf); + return NT_STATUS_OK; } @@ -548,17 +549,20 @@ static NTSTATUS ctdb_handle_message(const DATA_BLOB *data, if (msg->srvid != sys_getpid() && msg->srvid != MSG_SRVID_SAMBA) { DEBUG(0,("Got unexpected message with srvid=%llu\n", (unsigned long long)msg->srvid)); + TALLOC_FREE(buf); return NT_STATUS_OK; } - if (!(msg_rec = ctdb_pull_messaging_rec(NULL, data->length, msg))) { + if (!(msg_rec = ctdb_pull_messaging_rec(NULL, length, msg))) { DEBUG(10, ("ctdb_pull_messaging_rec failed\n")); + TALLOC_FREE(buf); return NT_STATUS_NO_MEMORY; } messaging_dispatch_rec(conn->msg_ctx, msg_rec); TALLOC_FREE(msg_rec); + TALLOC_FREE(buf); return NT_STATUS_OK; } @@ -1025,7 +1029,7 @@ struct ctdbd_traverse_state { * Handle a traverse record coming in on the ctdbd connection */ -static NTSTATUS ctdb_traverse_handler(const DATA_BLOB *blob, +static NTSTATUS ctdb_traverse_handler(uint8_t *buf, size_t length, void *private_data) { struct ctdbd_traverse_state *state = @@ -1035,11 +1039,11 @@ static NTSTATUS ctdb_traverse_handler(const DATA_BLOB *blob, struct ctdb_rec_data *d; TDB_DATA key, data; - m = (struct ctdb_req_message *)blob->data; + m = (struct ctdb_req_message *)buf; - if (blob->length < sizeof(*m) || m->hdr.length != blob->length) { - DEBUG(0, ("Got invalid message of length %d\n", - (int)blob->length)); + if (length < sizeof(*m) || m->hdr.length != length) { + DEBUG(0, ("Got invalid message of length %d\n", (int)length)); + TALLOC_FREE(buf); return NT_STATUS_UNEXPECTED_IO_ERROR; } @@ -1047,6 +1051,7 @@ static NTSTATUS ctdb_traverse_handler(const DATA_BLOB *blob, if (m->datalen < sizeof(uint32_t) || m->datalen != d->length) { DEBUG(0, ("Got invalid traverse data of length %d\n", (int)m->datalen)); + TALLOC_FREE(buf); return NT_STATUS_UNEXPECTED_IO_ERROR; } @@ -1063,6 +1068,7 @@ static NTSTATUS ctdb_traverse_handler(const DATA_BLOB *blob, if (data.dsize < sizeof(struct ctdb_ltdb_header)) { DEBUG(0, ("Got invalid ltdb header length %d\n", (int)data.dsize)); + TALLOC_FREE(buf); return NT_STATUS_UNEXPECTED_IO_ERROR; } data.dsize -= sizeof(struct ctdb_ltdb_header); @@ -1072,6 +1078,7 @@ static NTSTATUS ctdb_traverse_handler(const DATA_BLOB *blob, state->fn(key, data, state->private_data); } + TALLOC_FREE(buf); return NT_STATUS_OK; } diff --git a/source3/lib/packet.c b/source3/lib/packet.c index e4cab6ba87..72de30e8ca 100644 --- a/source3/lib/packet.c +++ b/source3/lib/packet.c @@ -120,33 +120,37 @@ NTSTATUS packet_fd_read_sync(struct packet_context *ctx) } bool packet_handler(struct packet_context *ctx, - bool (*full_req)(const DATA_BLOB *data, + bool (*full_req)(const uint8_t *buf, + size_t available, size_t *length, - void *private_data), - NTSTATUS (*callback)(const DATA_BLOB *data, - void *private_data), - void *private_data, - NTSTATUS *status) + void *priv), + NTSTATUS (*callback)(uint8_t *buf, size_t length, + void *priv), + void *priv, NTSTATUS *status) { size_t length; - DATA_BLOB data; + uint8_t *buf; - if (!full_req(&ctx->in, &length, private_data)) { + if (!full_req(ctx->in.data, ctx->in.length, &length, priv)) { return False; } - SMB_ASSERT(length <= ctx->in.length); + if (length > ctx->in.length) { + *status = NT_STATUS_INTERNAL_ERROR; + return true; + } - data = data_blob(ctx->in.data, length); + buf = (uint8_t *)TALLOC_MEMDUP(ctx, ctx->in.data, length); + if (buf == NULL) { + *status = NT_STATUS_NO_MEMORY; + return true; + } memmove(ctx->in.data, ctx->in.data + length, ctx->in.length - length); ctx->in.length -= length; - *status = callback(&data, private_data); - - data_blob_free(&data); - + *status = callback(buf, length, priv); return True; } -- cgit From b4e1eb4345ab0be00e31d09cf0753597ef0af44a Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Sat, 20 Dec 2008 10:51:54 +0100 Subject: Optimize for the common case that packet.c received exactly one full packet --- source3/lib/packet.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) (limited to 'source3/lib') diff --git a/source3/lib/packet.c b/source3/lib/packet.c index 72de30e8ca..ef28bf9f62 100644 --- a/source3/lib/packet.c +++ b/source3/lib/packet.c @@ -140,15 +140,21 @@ bool packet_handler(struct packet_context *ctx, return true; } - buf = (uint8_t *)TALLOC_MEMDUP(ctx, ctx->in.data, length); - if (buf == NULL) { - *status = NT_STATUS_NO_MEMORY; - return true; - } + if (length == ctx->in.length) { + buf = ctx->in.data; + ctx->in.data = NULL; + ctx->in.length = 0; + } else { + buf = (uint8_t *)TALLOC_MEMDUP(ctx, ctx->in.data, length); + if (buf == NULL) { + *status = NT_STATUS_NO_MEMORY; + return true; + } - memmove(ctx->in.data, ctx->in.data + length, - ctx->in.length - length); - ctx->in.length -= length; + memmove(ctx->in.data, ctx->in.data + length, + ctx->in.length - length); + ctx->in.length -= length; + } *status = callback(buf, length, priv); return True; -- cgit From 980aa0d464b5e95c777539cdd7a289b5407f1912 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Sat, 27 Dec 2008 17:20:25 +0100 Subject: Replace some SMB_ASSERTs with NT_STATUS_INTERNAL_ERROR --- source3/lib/async_sock.c | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) (limited to 'source3/lib') diff --git a/source3/lib/async_sock.c b/source3/lib/async_sock.c index 225cc7b195..3e9d6f7904 100644 --- a/source3/lib/async_sock.c +++ b/source3/lib/async_sock.c @@ -236,7 +236,10 @@ static void async_send_callback(struct event_context *ev, req->private_data, struct async_syscall_state); struct param_send *p = &state->param.param_send; - SMB_ASSERT(state->syscall_type == ASYNC_SYSCALL_SEND); + if (state->syscall_type != ASYNC_SYSCALL_SEND) { + async_req_error(req, NT_STATUS_INTERNAL_ERROR); + return; + } state->result.result_ssize_t = send(p->fd, p->buffer, p->length, p->flags); @@ -300,7 +303,10 @@ static void async_sendall_callback(struct event_context *ev, req->private_data, struct async_syscall_state); struct param_sendall *p = &state->param.param_sendall; - SMB_ASSERT(state->syscall_type == ASYNC_SYSCALL_SENDALL); + if (state->syscall_type != ASYNC_SYSCALL_SENDALL) { + async_req_error(req, NT_STATUS_INTERNAL_ERROR); + return; + } state->result.result_ssize_t = send(p->fd, (char *)p->buffer + p->sent, p->length - p->sent, p->flags); @@ -317,7 +323,10 @@ static void async_sendall_callback(struct event_context *ev, } p->sent += state->result.result_ssize_t; - SMB_ASSERT(p->sent <= p->length); + if (p->sent > p->length) { + async_req_error(req, NT_STATUS_INTERNAL_ERROR); + return; + } if (p->sent == p->length) { TALLOC_FREE(state->fde); @@ -385,7 +394,10 @@ static void async_recv_callback(struct event_context *ev, req->private_data, struct async_syscall_state); struct param_recv *p = &state->param.param_recv; - SMB_ASSERT(state->syscall_type == ASYNC_SYSCALL_RECV); + if (state->syscall_type != ASYNC_SYSCALL_RECV) { + async_req_error(req, NT_STATUS_INTERNAL_ERROR); + return; + } state->result.result_ssize_t = recv(p->fd, p->buffer, p->length, p->flags); @@ -450,7 +462,10 @@ static void async_recvall_callback(struct event_context *ev, req->private_data, struct async_syscall_state); struct param_recvall *p = &state->param.param_recvall; - SMB_ASSERT(state->syscall_type == ASYNC_SYSCALL_RECVALL); + if (state->syscall_type != ASYNC_SYSCALL_RECVALL) { + async_req_error(req, NT_STATUS_INTERNAL_ERROR); + return; + } state->result.result_ssize_t = recv(p->fd, (char *)p->buffer + p->received, @@ -468,7 +483,10 @@ static void async_recvall_callback(struct event_context *ev, } p->received += state->result.result_ssize_t; - SMB_ASSERT(p->received <= p->length); + if (p->received > p->length) { + async_req_error(req, NT_STATUS_INTERNAL_ERROR); + return; + } if (p->received == p->length) { TALLOC_FREE(state->fde); @@ -535,7 +553,10 @@ static void async_connect_callback(struct event_context *ev, req->private_data, struct async_syscall_state); struct param_connect *p = &state->param.param_connect; - SMB_ASSERT(state->syscall_type == ASYNC_SYSCALL_CONNECT); + if (state->syscall_type != ASYNC_SYSCALL_CONNECT) { + async_req_error(req, NT_STATUS_INTERNAL_ERROR); + return; + } TALLOC_FREE(state->fde); -- cgit From 27abf6731ed472580157a0447e858e11f6f63f3b Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Sat, 3 Jan 2009 10:34:59 +0100 Subject: struct async_req doesn't really need to carry an event_context --- source3/lib/async_req.c | 9 ++++----- source3/lib/async_sock.c | 10 ++++++---- 2 files changed, 10 insertions(+), 9 deletions(-) (limited to 'source3/lib') diff --git a/source3/lib/async_req.c b/source3/lib/async_req.c index 159666f15c..8c9b2e6b47 100644 --- a/source3/lib/async_req.c +++ b/source3/lib/async_req.c @@ -49,7 +49,7 @@ char *async_req_print(TALLOC_CTX *mem_ctx, struct async_req *req) * The new async request will be initialized in state ASYNC_REQ_IN_PROGRESS */ -struct async_req *async_req_new(TALLOC_CTX *mem_ctx, struct event_context *ev) +struct async_req *async_req_new(TALLOC_CTX *mem_ctx) { struct async_req *result; @@ -58,7 +58,6 @@ struct async_req *async_req_new(TALLOC_CTX *mem_ctx, struct event_context *ev) return NULL; } result->state = ASYNC_REQ_IN_PROGRESS; - result->event_ctx = ev; result->print = async_req_print; return result; } @@ -135,12 +134,12 @@ static void async_trigger(struct event_context *ev, struct timed_event *te, * conventions, independent of whether the request was actually deferred. */ -bool async_post_status(struct async_req *req, NTSTATUS status) +bool async_post_status(struct async_req *req, struct event_context *ev, + NTSTATUS status) { req->status = status; - if (event_add_timed(req->event_ctx, req, timeval_zero(), - "async_trigger", + if (event_add_timed(ev, req, timeval_zero(), "async_trigger", async_trigger, req) == NULL) { return false; } diff --git a/source3/lib/async_sock.c b/source3/lib/async_sock.c index 3e9d6f7904..cb545854dd 100644 --- a/source3/lib/async_sock.c +++ b/source3/lib/async_sock.c @@ -106,7 +106,7 @@ static struct async_req *async_syscall_new(TALLOC_CTX *mem_ctx, struct async_req *result; struct async_syscall_state *state; - result = async_req_new(mem_ctx, ev); + result = async_req_new(mem_ctx); if (result == NULL) { return NULL; } @@ -628,7 +628,8 @@ struct async_req *async_connect(TALLOC_CTX *mem_ctx, struct event_context *ev, p->old_sockflags = sys_fcntl_long(fd, F_GETFL, 0); if (p->old_sockflags == -1) { - if (async_post_status(result, map_nt_error_from_unix(errno))) { + if (async_post_status(result, ev, + map_nt_error_from_unix(errno))) { return result; } TALLOC_FREE(result); @@ -641,7 +642,7 @@ struct async_req *async_connect(TALLOC_CTX *mem_ctx, struct event_context *ev, if (state->result.result_int == 0) { state->sys_errno = 0; - if (async_post_status(result, NT_STATUS_OK)) { + if (async_post_status(result, ev, NT_STATUS_OK)) { return result; } sys_fcntl_long(fd, F_SETFL, p->old_sockflags); @@ -664,7 +665,8 @@ struct async_req *async_connect(TALLOC_CTX *mem_ctx, struct event_context *ev, state->sys_errno = errno; - if (async_post_status(result, map_nt_error_from_unix(errno))) { + if (async_post_status(result, ev, + map_nt_error_from_unix(errno))) { return result; } sys_fcntl_long(fd, F_SETFL, p->old_sockflags); -- cgit From b6138bf4f22e7a093d35e2f23992595acae55068 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Sat, 27 Dec 2008 18:42:45 +0100 Subject: Fix retval of async_syscall_result_int --- source3/lib/async_sock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source3/lib') diff --git a/source3/lib/async_sock.c b/source3/lib/async_sock.c index cb545854dd..107d1402fc 100644 --- a/source3/lib/async_sock.c +++ b/source3/lib/async_sock.c @@ -209,7 +209,7 @@ size_t async_syscall_result_size_t(struct async_req *req, int *perrno) * @retval The return value from the asynchronously called syscall */ -ssize_t async_syscall_result_int(struct async_req *req, int *perrno) +int async_syscall_result_int(struct async_req *req, int *perrno) { struct async_syscall_state *state = talloc_get_type_abort( req->private_data, struct async_syscall_state); -- cgit From fafb9ecc613914ee49bfdb4c1eb249fcbbcf25f7 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Sat, 3 Jan 2009 18:16:08 +0100 Subject: open_socket_out is always used with SOCK_STREAM, remove argument "type" --- source3/lib/util_sock.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) (limited to 'source3/lib') diff --git a/source3/lib/util_sock.c b/source3/lib/util_sock.c index d23758ad6a..a8c3b3031d 100644 --- a/source3/lib/util_sock.c +++ b/source3/lib/util_sock.c @@ -952,10 +952,8 @@ int open_socket_in(int type, Create an outgoing socket. timeout is in milliseconds. **************************************************************************/ -int open_socket_out(int type, - const struct sockaddr_storage *pss, - uint16_t port, - int timeout) +int open_socket_out(const struct sockaddr_storage *pss, uint16_t port, + int timeout) { char addr[INET6_ADDRSTRLEN]; struct sockaddr_storage sock_out = *pss; @@ -964,16 +962,12 @@ int open_socket_out(int type, int increment = 10; /* create a socket to write to */ - res = socket(pss->ss_family, type, 0); + res = socket(pss->ss_family, SOCK_STREAM, 0); if (res == -1) { DEBUG(0,("socket error (%s)\n", strerror(errno))); return -1; } - if (type != SOCK_STREAM) { - return res; - } - #if defined(HAVE_IPV6) if (pss->ss_family == AF_INET6) { struct sockaddr_in6 *psa6 = (struct sockaddr_in6 *)&sock_out; -- cgit From ebacce2efe6dbb27a9e7962597da8ef783473f6a Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Sat, 3 Jan 2009 19:10:57 +0100 Subject: Add async timeout helpers --- source3/lib/async_req.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) (limited to 'source3/lib') diff --git a/source3/lib/async_req.c b/source3/lib/async_req.c index 8c9b2e6b47..0653ff62a7 100644 --- a/source3/lib/async_req.c +++ b/source3/lib/async_req.c @@ -194,3 +194,45 @@ NTSTATUS async_req_simple_recv(struct async_req *req) } return NT_STATUS_OK; } + +static void async_req_timedout(struct event_context *ev, + struct timed_event *te, + const struct timeval *now, + void *priv) +{ + struct async_req *req = talloc_get_type_abort( + priv, struct async_req); + TALLOC_FREE(te); + async_req_error(req, NT_STATUS_IO_TIMEOUT); +} + +bool async_req_set_timeout(struct async_req *req, struct event_context *ev, + struct timeval to) +{ + return (event_add_timed(ev, req, + timeval_current_ofs(to.tv_sec, to.tv_usec), + "async_req_timedout", async_req_timedout, req) + != NULL); +} + +struct async_req *async_wait_send(TALLOC_CTX *mem_ctx, + struct event_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; +} + +NTSTATUS async_wait_recv(struct async_req *req) +{ + return NT_STATUS_OK; +} -- cgit From 611f0d7ee607bad65b7a40ba2f0195ba987f1cab Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Sun, 4 Jan 2009 11:28:40 +0100 Subject: Add an async queueing mechanism --- source3/lib/async_req.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) (limited to 'source3/lib') diff --git a/source3/lib/async_req.c b/source3/lib/async_req.c index 0653ff62a7..ac06df65a3 100644 --- a/source3/lib/async_req.c +++ b/source3/lib/async_req.c @@ -236,3 +236,81 @@ NTSTATUS async_wait_recv(struct async_req *req) { return NT_STATUS_OK; } + +struct async_queue_entry { + struct async_queue_entry *prev, *next; + struct async_req_queue *queue; + struct async_req *req; + void (*trigger)(struct async_req *req); +}; + +struct async_req_queue { + struct async_queue_entry *queue; +}; + +struct async_req_queue *async_req_queue_init(TALLOC_CTX *mem_ctx) +{ + return TALLOC_ZERO_P(mem_ctx, struct async_req_queue); +} + +static int async_queue_entry_destructor(struct async_queue_entry *e) +{ + struct async_req_queue *queue = e->queue; + + DLIST_REMOVE(queue->queue, e); + + if (queue->queue != NULL) { + queue->queue->trigger(queue->queue->req); + } + + return 0; +} + +static void async_req_immediate_trigger(struct event_context *ev, + struct timed_event *te, + const struct timeval *now, + void *priv) +{ + struct async_queue_entry *e = talloc_get_type_abort( + priv, struct async_queue_entry); + + TALLOC_FREE(te); + e->trigger(e->req); +} + +bool async_req_enqueue(struct async_req_queue *queue, struct event_context *ev, + struct async_req *req, + void (*trigger)(struct async_req *req)) +{ + struct async_queue_entry *e; + bool busy; + + busy = (queue->queue != NULL); + + e = talloc(req, struct async_queue_entry); + if (e == NULL) { + return false; + } + + e->req = req; + e->trigger = trigger; + e->queue = queue; + + DLIST_ADD_END(queue->queue, e, struct async_queue_entry *); + talloc_set_destructor(e, async_queue_entry_destructor); + + if (!busy) { + struct timed_event *te; + + te = event_add_timed(ev, e, timeval_zero(), + "async_req_immediate_trigger", + async_req_immediate_trigger, + e); + if (te == NULL) { + TALLOC_FREE(e); + return false; + } + } + + return true; +} -- cgit From 34e8945cb5d0568e511708779d2c33cc59ed54e1 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Sat, 3 Jan 2009 19:23:13 +0100 Subject: Actually do a non-blocking connect.... :-) --- source3/lib/async_sock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source3/lib') diff --git a/source3/lib/async_sock.c b/source3/lib/async_sock.c index 107d1402fc..f755f7ac58 100644 --- a/source3/lib/async_sock.c +++ b/source3/lib/async_sock.c @@ -636,7 +636,7 @@ struct async_req *async_connect(TALLOC_CTX *mem_ctx, struct event_context *ev, return NULL; } - set_blocking(fd, true); + set_blocking(fd, false); state->result.result_int = connect(fd, address, address_len); -- cgit From c6c33d840ba90686fcdc81b49b5e256270b97f29 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Sun, 4 Jan 2009 00:26:49 +0100 Subject: Convert async_connect to "normal" style --- source3/lib/async_sock.c | 214 +++++++++++++++++++++++++---------------------- 1 file changed, 113 insertions(+), 101 deletions(-) (limited to 'source3/lib') diff --git a/source3/lib/async_sock.c b/source3/lib/async_sock.c index f755f7ac58..bb89a1353a 100644 --- a/source3/lib/async_sock.c +++ b/source3/lib/async_sock.c @@ -535,63 +535,16 @@ NTSTATUS recvall_recv(struct async_req *req) return async_req_simple_recv(req); } -/** - * fde event handler for connect(2) - * @param[in] ev The event context that sent us here - * @param[in] fde The file descriptor event associated with the connect - * @param[in] flags Indicate read/writeability of the socket - * @param[in] priv private data, "struct async_req *" in this case - */ - -static void async_connect_callback(struct event_context *ev, - struct fd_event *fde, uint16_t flags, - void *priv) -{ - struct async_req *req = talloc_get_type_abort( - priv, struct async_req); - struct async_syscall_state *state = talloc_get_type_abort( - req->private_data, struct async_syscall_state); - struct param_connect *p = &state->param.param_connect; - - if (state->syscall_type != ASYNC_SYSCALL_CONNECT) { - async_req_error(req, NT_STATUS_INTERNAL_ERROR); - return; - } - - TALLOC_FREE(state->fde); - - /* - * Stevens, Network Programming says that if there's a - * successful connect, the socket is only writable. Upon an - * error, it's both readable and writable. - */ - if ((flags & (EVENT_FD_READ|EVENT_FD_WRITE)) - == (EVENT_FD_READ|EVENT_FD_WRITE)) { - int sockerr; - socklen_t err_len = sizeof(sockerr); - - if (getsockopt(p->fd, SOL_SOCKET, SO_ERROR, - (void *)&sockerr, &err_len) == 0) { - errno = sockerr; - } - - state->sys_errno = errno; - - DEBUG(10, ("connect returned %s\n", strerror(errno))); - - sys_fcntl_long(p->fd, F_SETFL, p->old_sockflags); - - async_req_error(req, map_nt_error_from_unix(state->sys_errno)); - return; - } - - sys_fcntl_long(p->fd, F_SETFL, p->old_sockflags); - - state->result.result_int = 0; - state->sys_errno = 0; +struct async_connect_state { + int fd; + int result; + int sys_errno; + long old_sockflags; +}; - async_req_done(req); -} +static void async_connect_connected(struct event_context *ev, + struct fd_event *fde, uint16_t flags, + void *priv); /** * @brief async version of connect(2) @@ -606,48 +559,46 @@ static void async_connect_callback(struct event_context *ev, * connect in an async state. This will be reset when the request is finished. */ -struct async_req *async_connect(TALLOC_CTX *mem_ctx, struct event_context *ev, - int fd, const struct sockaddr *address, - socklen_t address_len) +struct async_req *async_connect_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, + int fd, const struct sockaddr *address, + socklen_t address_len) { struct async_req *result; - struct async_syscall_state *state; - struct param_connect *p; + struct async_connect_state *state; + struct fd_event *fde; + NTSTATUS status; - result = async_syscall_new(mem_ctx, ev, ASYNC_SYSCALL_CONNECT, &state); + result = async_req_new(mem_ctx); if (result == NULL) { return NULL; } - p = &state->param.param_connect; + state = talloc(result, struct async_connect_state); + if (state == NULL) { + goto fail; + } + result->private_data = state; /** * We have to set the socket to nonblocking for async connect(2). Keep * the old sockflags around. */ - p->old_sockflags = sys_fcntl_long(fd, F_GETFL, 0); + state->fd = fd; + state->sys_errno = 0; - if (p->old_sockflags == -1) { - if (async_post_status(result, ev, - map_nt_error_from_unix(errno))) { - return result; - } - TALLOC_FREE(result); - return NULL; + state->old_sockflags = sys_fcntl_long(fd, F_GETFL, 0); + if (state->old_sockflags == -1) { + goto post_errno; } set_blocking(fd, false); - state->result.result_int = connect(fd, address, address_len); - - if (state->result.result_int == 0) { + state->result = connect(fd, address, address_len); + if (state->result == 0) { state->sys_errno = 0; - if (async_post_status(result, ev, NT_STATUS_OK)) { - return result; - } - sys_fcntl_long(fd, F_SETFL, p->old_sockflags); - TALLOC_FREE(result); - return NULL; + status = NT_STATUS_OK; + goto post_status; } /** @@ -662,32 +613,93 @@ struct async_req *async_connect(TALLOC_CTX *mem_ctx, struct event_context *ev, errno == EISCONN || #endif errno == EAGAIN || errno == EINTR)) { + goto post_errno; + } - state->sys_errno = errno; - - if (async_post_status(result, ev, - map_nt_error_from_unix(errno))) { - return result; - } - sys_fcntl_long(fd, F_SETFL, p->old_sockflags); - TALLOC_FREE(result); - return NULL; + fde = event_add_fd(ev, state, fd, EVENT_FD_READ | EVENT_FD_WRITE, + async_connect_connected, result); + if (fde == NULL) { + status = NT_STATUS_NO_MEMORY; + goto post_status; } + return result; - state->fde = event_add_fd(ev, state, fd, - EVENT_FD_READ | EVENT_FD_WRITE, - async_connect_callback, result); - if (state->fde == NULL) { - sys_fcntl_long(fd, F_SETFL, p->old_sockflags); - TALLOC_FREE(result); - return NULL; + post_errno: + state->sys_errno = errno; + status = map_nt_error_from_unix(state->sys_errno); + post_status: + sys_fcntl_long(fd, F_SETFL, state->old_sockflags); + if (!async_post_status(result, ev, status)) { + goto fail; } - result->private_data = state; + return result; + fail: + TALLOC_FREE(result); + return NULL; +} - state->param.param_connect.fd = fd; - state->param.param_connect.address = address; - state->param.param_connect.address_len = address_len; +/** + * fde event handler for connect(2) + * @param[in] ev The event context that sent us here + * @param[in] fde The file descriptor event associated with the connect + * @param[in] flags Indicate read/writeability of the socket + * @param[in] priv private data, "struct async_req *" in this case + */ - return result; +static void async_connect_connected(struct event_context *ev, + struct fd_event *fde, uint16_t flags, + void *priv) +{ + struct async_req *req = talloc_get_type_abort( + priv, struct async_req); + struct async_connect_state *state = talloc_get_type_abort( + req->private_data, struct async_connect_state); + + TALLOC_FREE(fde); + + /* + * Stevens, Network Programming says that if there's a + * successful connect, the socket is only writable. Upon an + * error, it's both readable and writable. + */ + if ((flags & (EVENT_FD_READ|EVENT_FD_WRITE)) + == (EVENT_FD_READ|EVENT_FD_WRITE)) { + int sockerr; + socklen_t err_len = sizeof(sockerr); + + if (getsockopt(state->fd, SOL_SOCKET, SO_ERROR, + (void *)&sockerr, &err_len) == 0) { + errno = sockerr; + } + + state->sys_errno = errno; + + DEBUG(10, ("connect returned %s\n", strerror(errno))); + + sys_fcntl_long(state->fd, F_SETFL, state->old_sockflags); + async_req_error(req, map_nt_error_from_unix(state->sys_errno)); + return; + } + + state->sys_errno = 0; + async_req_done(req); } +NTSTATUS async_connect_recv(struct async_req *req, int *perrno) +{ + struct async_connect_state *state = talloc_get_type_abort( + req->private_data, struct async_connect_state); + NTSTATUS status; + + sys_fcntl_long(state->fd, F_SETFL, state->old_sockflags); + + *perrno = state->sys_errno; + + if (async_req_is_error(req, &status)) { + return status; + } + if (state->sys_errno == 0) { + return NT_STATUS_OK; + } + return map_nt_error_from_unix(state->sys_errno); +} -- cgit From d933362cb7fdd93fef860feeac1d86b180e29a59 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Sun, 28 Dec 2008 14:47:40 +0100 Subject: Move winbindd/winbindd_reqtrans.c to lib/wb_reqtrans.c --- source3/lib/wb_reqtrans.c | 685 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 685 insertions(+) create mode 100644 source3/lib/wb_reqtrans.c (limited to 'source3/lib') diff --git a/source3/lib/wb_reqtrans.c b/source3/lib/wb_reqtrans.c new file mode 100644 index 0000000000..faf1666705 --- /dev/null +++ b/source3/lib/wb_reqtrans.c @@ -0,0 +1,685 @@ +/* + Unix SMB/CIFS implementation. + + Async transfer of winbindd_request and _response structs + + Copyright (C) Volker Lendecke 2008 + + 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 . +*/ + +#include "includes.h" +#include "winbindd/winbindd.h" + +#undef DBGC_CLASS +#define DBGC_CLASS DBGC_WINBIND + +struct req_read_state { + struct winbindd_request *wb_req; + struct event_context *ev; + size_t max_extra_data; + int fd; +}; + +static void wb_req_read_len(struct async_req *subreq); +static void wb_req_read_main(struct async_req *subreq); +static void wb_req_read_extra(struct async_req *subreq); + +struct async_req *wb_req_read_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, + int fd, size_t max_extra_data) +{ + struct async_req *result, *subreq; + struct req_read_state *state; + + result = async_req_new(mem_ctx); + if (result == NULL) { + return NULL; + } + + state = talloc(result, struct req_read_state); + if (state == NULL) { + goto nomem; + } + result->private_data = state; + + state->fd = fd; + state->ev = ev; + state->max_extra_data = max_extra_data; + state->wb_req = talloc(state, struct winbindd_request); + if (state->wb_req == NULL) { + goto nomem; + } + + subreq = recvall_send(state, ev, state->fd, &(state->wb_req->length), + sizeof(state->wb_req->length), 0); + if (subreq == NULL) { + goto nomem; + } + + subreq->async.fn = wb_req_read_len; + subreq->async.priv = result; + return result; + + nomem: + TALLOC_FREE(result); + return NULL; +} + +static void wb_req_read_len(struct async_req *subreq) +{ + struct async_req *req = talloc_get_type_abort( + subreq->async.priv, struct async_req); + struct req_read_state *state = talloc_get_type_abort( + req->private_data, struct req_read_state); + NTSTATUS status; + + status = recvall_recv(subreq); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + async_req_error(req, status); + return; + } + + if (state->wb_req->length != sizeof(struct winbindd_request)) { + DEBUG(0, ("wb_req_read_len: Invalid request size received: " + "%d (expected %d)\n", (int)state->wb_req->length, + (int)sizeof(struct winbindd_request))); + async_req_error(req, NT_STATUS_INVALID_BUFFER_SIZE); + return; + } + + subreq = recvall_send( + req, state->ev, state->fd, (uint32 *)(state->wb_req)+1, + sizeof(struct winbindd_request) - sizeof(uint32), 0); + if (async_req_nomem(subreq, req)) { + return; + } + + subreq->async.fn = wb_req_read_main; + subreq->async.priv = req; +} + +static void wb_req_read_main(struct async_req *subreq) +{ + struct async_req *req = talloc_get_type_abort( + subreq->async.priv, struct async_req); + struct req_read_state *state = talloc_get_type_abort( + req->private_data, struct req_read_state); + NTSTATUS status; + + status = recvall_recv(subreq); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + async_req_error(req, status); + return; + } + + if ((state->max_extra_data != 0) + && (state->wb_req->extra_len > state->max_extra_data)) { + DEBUG(3, ("Got request with %d bytes extra data on " + "unprivileged socket\n", + (int)state->wb_req->extra_len)); + async_req_error(req, NT_STATUS_INVALID_BUFFER_SIZE); + return; + } + + if (state->wb_req->extra_len == 0) { + async_req_done(req); + return; + } + + state->wb_req->extra_data.data = TALLOC_ARRAY( + state->wb_req, char, state->wb_req->extra_len + 1); + if (async_req_nomem(state->wb_req->extra_data.data, req)) { + return; + } + + state->wb_req->extra_data.data[state->wb_req->extra_len] = 0; + + subreq = recvall_send( + req, state->ev, state->fd, state->wb_req->extra_data.data, + state->wb_req->extra_len, 0); + if (async_req_nomem(subreq, req)) { + return; + } + + subreq->async.fn = wb_req_read_extra; + subreq->async.priv = req; +} + +static void wb_req_read_extra(struct async_req *subreq) +{ + struct async_req *req = talloc_get_type_abort( + subreq->async.priv, struct async_req); + NTSTATUS status; + + status = recvall_recv(subreq); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + async_req_error(req, status); + return; + } + async_req_done(req); +} + + +NTSTATUS wb_req_read_recv(struct async_req *req, TALLOC_CTX *mem_ctx, + struct winbindd_request **preq) +{ + struct req_read_state *state = talloc_get_type_abort( + req->private_data, struct req_read_state); + NTSTATUS status; + + if (async_req_is_error(req, &status)) { + return status; + } + *preq = talloc_move(mem_ctx, &state->wb_req); + return NT_STATUS_OK; +} + +struct req_write_state { + struct winbindd_request *wb_req; + struct event_context *ev; + int fd; +}; + +static void wb_req_write_main(struct async_req *subreq); +static void wb_req_write_extra(struct async_req *subreq); + +struct async_req *wb_req_write_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, int fd, + struct winbindd_request *wb_req) +{ + struct async_req *result, *subreq; + struct req_write_state *state; + + result = async_req_new(mem_ctx); + if (result == NULL) { + return NULL; + } + + state = talloc(result, struct req_write_state); + if (state == NULL) { + goto nomem; + } + result->private_data = state; + + state->fd = fd; + state->ev = ev; + state->wb_req = wb_req; + + subreq = sendall_send(state, state->ev, state->fd, state->wb_req, + sizeof(struct winbindd_request), 0); + if (subreq == NULL) { + goto nomem; + } + + subreq->async.fn = wb_req_write_main; + subreq->async.priv = result; + return result; + + nomem: + TALLOC_FREE(result); + return NULL; +} + +static void wb_req_write_main(struct async_req *subreq) +{ + struct async_req *req = talloc_get_type_abort( + subreq->async.priv, struct async_req); + struct req_write_state *state = talloc_get_type_abort( + req->private_data, struct req_write_state); + NTSTATUS status; + + status = sendall_recv(subreq); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + async_req_error(req, status); + return; + } + + if (state->wb_req->extra_len == 0) { + async_req_done(req); + return; + } + + subreq = sendall_send(state, state->ev, state->fd, + state->wb_req->extra_data.data, + state->wb_req->extra_len, 0); + if (async_req_nomem(subreq, req)) { + return; + } + + subreq->async.fn = wb_req_write_extra; + subreq->async.priv = req; +} + +static void wb_req_write_extra(struct async_req *subreq) +{ + struct async_req *req = talloc_get_type_abort( + subreq->async.priv, struct async_req); + NTSTATUS status; + + status = sendall_recv(subreq); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + async_req_error(req, status); + return; + } + + async_req_done(req); +} + +NTSTATUS wb_req_write_recv(struct async_req *req) +{ + return async_req_simple_recv(req); +} + +struct resp_read_state { + struct winbindd_response *wb_resp; + struct event_context *ev; + size_t max_extra_data; + int fd; +}; + +static void wb_resp_read_len(struct async_req *subreq); +static void wb_resp_read_main(struct async_req *subreq); +static void wb_resp_read_extra(struct async_req *subreq); + +struct async_req *wb_resp_read_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, int fd) +{ + struct async_req *result, *subreq; + struct resp_read_state *state; + + result = async_req_new(mem_ctx); + if (result == NULL) { + return NULL; + } + + state = talloc(result, struct resp_read_state); + if (state == NULL) { + goto nomem; + } + result->private_data = state; + + state->fd = fd; + state->ev = ev; + state->wb_resp = talloc(state, struct winbindd_response); + if (state->wb_resp == NULL) { + goto nomem; + } + + subreq = recvall_send(state, ev, state->fd, &(state->wb_resp->length), + sizeof(state->wb_resp->length), 0); + if (subreq == NULL) { + goto nomem; + } + + subreq->async.fn = wb_resp_read_len; + subreq->async.priv = result; + return result; + + nomem: + TALLOC_FREE(result); + return NULL; +} + +static void wb_resp_read_len(struct async_req *subreq) +{ + struct async_req *req = talloc_get_type_abort( + subreq->async.priv, struct async_req); + struct resp_read_state *state = talloc_get_type_abort( + req->private_data, struct resp_read_state); + NTSTATUS status; + + status = recvall_recv(subreq); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + async_req_error(req, status); + return; + } + + if (state->wb_resp->length < sizeof(struct winbindd_response)) { + DEBUG(0, ("wb_resp_read_len: Invalid response size received: " + "%d (expected at least%d)\n", + (int)state->wb_resp->length, + (int)sizeof(struct winbindd_response))); + async_req_error(req, NT_STATUS_INVALID_BUFFER_SIZE); + return; + } + + subreq = recvall_send( + req, state->ev, state->fd, (uint32 *)(state->wb_resp)+1, + sizeof(struct winbindd_response) - sizeof(uint32), 0); + if (async_req_nomem(subreq, req)) { + return; + } + + subreq->async.fn = wb_resp_read_main; + subreq->async.priv = req; +} + +static void wb_resp_read_main(struct async_req *subreq) +{ + struct async_req *req = talloc_get_type_abort( + subreq->async.priv, struct async_req); + struct resp_read_state *state = talloc_get_type_abort( + req->private_data, struct resp_read_state); + NTSTATUS status; + size_t extra_len; + + status = recvall_recv(subreq); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + async_req_error(req, status); + return; + } + + extra_len = state->wb_resp->length - sizeof(struct winbindd_response); + if (extra_len == 0) { + async_req_done(req); + return; + } + + state->wb_resp->extra_data.data = TALLOC_ARRAY( + state->wb_resp, char, extra_len+1); + if (async_req_nomem(state->wb_resp->extra_data.data, req)) { + return; + } + ((char *)state->wb_resp->extra_data.data)[extra_len] = 0; + + subreq = recvall_send( + req, state->ev, state->fd, state->wb_resp->extra_data.data, + extra_len, 0); + if (async_req_nomem(subreq, req)) { + return; + } + + subreq->async.fn = wb_resp_read_extra; + subreq->async.priv = req; +} + +static void wb_resp_read_extra(struct async_req *subreq) +{ + struct async_req *req = talloc_get_type_abort( + subreq->async.priv, struct async_req); + NTSTATUS status; + + status = recvall_recv(subreq); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + async_req_error(req, status); + return; + } + async_req_done(req); +} + + +NTSTATUS wb_resp_read_recv(struct async_req *req, TALLOC_CTX *mem_ctx, + struct winbindd_response **presp) +{ + struct resp_read_state *state = talloc_get_type_abort( + req->private_data, struct resp_read_state); + NTSTATUS status; + + if (async_req_is_error(req, &status)) { + return status; + } + *presp = talloc_move(mem_ctx, &state->wb_resp); + return NT_STATUS_OK; +} + +struct resp_write_state { + struct winbindd_response *wb_resp; + struct event_context *ev; + int fd; +}; + +static void wb_resp_write_main(struct async_req *subreq); +static void wb_resp_write_extra(struct async_req *subreq); + +struct async_req *wb_resp_write_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, int fd, + struct winbindd_response *wb_resp) +{ + struct async_req *result, *subreq; + struct resp_write_state *state; + + result = async_req_new(mem_ctx); + if (result == NULL) { + return NULL; + } + + state = talloc(result, struct resp_write_state); + if (state == NULL) { + goto nomem; + } + result->private_data = state; + + state->fd = fd; + state->ev = ev; + state->wb_resp = wb_resp; + + subreq = sendall_send(state, state->ev, state->fd, state->wb_resp, + sizeof(struct winbindd_response), 0); + if (subreq == NULL) { + goto nomem; + } + + subreq->async.fn = wb_resp_write_main; + subreq->async.priv = result; + return result; + + nomem: + TALLOC_FREE(result); + return NULL; +} + +static void wb_resp_write_main(struct async_req *subreq) +{ + struct async_req *req = talloc_get_type_abort( + subreq->async.priv, struct async_req); + struct resp_write_state *state = talloc_get_type_abort( + req->private_data, struct resp_write_state); + NTSTATUS status; + + status = sendall_recv(subreq); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + async_req_error(req, status); + return; + } + + if (state->wb_resp->length == sizeof(struct winbindd_response)) { + async_req_done(req); + return; + } + + subreq = sendall_send( + state, state->ev, state->fd, + state->wb_resp->extra_data.data, + state->wb_resp->length - sizeof(struct winbindd_response), 0); + if (async_req_nomem(subreq, req)) { + return; + } + + subreq->async.fn = wb_resp_write_extra; + subreq->async.priv = req; +} + +static void wb_resp_write_extra(struct async_req *subreq) +{ + struct async_req *req = talloc_get_type_abort( + subreq->async.priv, struct async_req); + NTSTATUS status; + + status = sendall_recv(subreq); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + async_req_error(req, status); + return; + } + + async_req_done(req); +} + +NTSTATUS wb_resp_write_recv(struct async_req *req) +{ + return async_req_simple_recv(req); +} + +struct wb_trans_state { + struct event_context *ev; + struct timed_event *te; + int fd; + struct winbindd_response *wb_resp; + size_t reply_max_extra_data; +}; + +static void wb_trans_timeout(struct event_context *ev, struct timed_event *te, + const struct timeval *now, void *priv); +static void wb_trans_sent(struct async_req *req); +static void wb_trans_received(struct async_req *req); + +struct async_req *wb_trans_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, + int fd, + struct winbindd_request *wb_req, + struct timeval timeout, + size_t reply_max_extra_data) +{ + struct async_req *result, *subreq; + struct wb_trans_state *state; + + result = async_req_new(mem_ctx); + if (result == NULL) { + return NULL; + } + + state = talloc(result, struct wb_trans_state); + if (state == NULL) { + goto nomem; + } + result->private_data = state; + + state->ev = ev; + state->fd = fd; + state->reply_max_extra_data = reply_max_extra_data; + + state->te = event_add_timed( + ev, state, + timeval_current_ofs(timeout.tv_sec, timeout.tv_usec), + "wb_trans_timeout", wb_trans_timeout, result); + if (state->te == NULL) { + goto nomem; + } + + subreq = wb_req_write_send(state, state->ev, state->fd, wb_req); + if (subreq == NULL) { + goto nomem; + } + subreq->async.fn = wb_trans_sent; + subreq->async.priv = result; + + return result; + + nomem: + TALLOC_FREE(result); + return NULL; +} + +static void wb_trans_timeout(struct event_context *ev, struct timed_event *te, + const struct timeval *now, void *priv) +{ + struct async_req *req = talloc_get_type_abort( + priv, struct async_req); + struct wb_trans_state *state = talloc_get_type_abort( + req->private_data, struct wb_trans_state); + + TALLOC_FREE(state->te); + async_req_error(req, NT_STATUS_IO_TIMEOUT); +} + +static void wb_trans_sent(struct async_req *subreq) +{ + struct async_req *req = talloc_get_type_abort( + subreq->async.priv, struct async_req); + struct wb_trans_state *state = talloc_get_type_abort( + req->private_data, struct wb_trans_state); + NTSTATUS status; + + status = wb_req_write_recv(subreq); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + async_req_error(req, status); + return; + } + + subreq = wb_resp_read_send(state, state->ev, state->fd); + if (async_req_nomem(subreq, req)) { + return; + } + + subreq->async.fn = wb_trans_received; + subreq->async.priv = req; +}; + +static void wb_trans_received(struct async_req *subreq) +{ + struct async_req *req = talloc_get_type_abort( + subreq->async.priv, struct async_req); + struct wb_trans_state *state = talloc_get_type_abort( + req->private_data, struct wb_trans_state); + NTSTATUS status; + + TALLOC_FREE(state->te); + + status = wb_resp_read_recv(subreq, state, &state->wb_resp); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + async_req_error(req, status); + return; + } + + async_req_done(req); +} + +NTSTATUS wb_trans_recv(struct async_req *req, TALLOC_CTX *mem_ctx, + struct winbindd_response **presp) +{ + struct wb_trans_state *state = talloc_get_type_abort( + req->private_data, struct wb_trans_state); + NTSTATUS status; + + if (async_req_is_error(req, &status)) { + return status; + } + *presp = talloc_move(mem_ctx, &state->wb_resp); + return NT_STATUS_OK; +} + +struct wb_trans_queue_state { + struct wb_trans_queue_state *prev, *next; + struct wb_trans_queue *queue; + struct winbindd_request *req; +}; + +struct wb_trans_queue { + int fd; + struct timeval timeout; + size_t max_resp_extra_data; + struct wb_trans_queue_state *queued_requests; +}; -- cgit From 8c1691d2139e49d6fb47a6d85400a1b7b91ffd67 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Sun, 28 Dec 2008 14:49:22 +0100 Subject: Remove wb_trans_send/recv --- source3/lib/wb_reqtrans.c | 143 ---------------------------------------------- 1 file changed, 143 deletions(-) (limited to 'source3/lib') diff --git a/source3/lib/wb_reqtrans.c b/source3/lib/wb_reqtrans.c index faf1666705..1f5f181aa1 100644 --- a/source3/lib/wb_reqtrans.c +++ b/source3/lib/wb_reqtrans.c @@ -540,146 +540,3 @@ NTSTATUS wb_resp_write_recv(struct async_req *req) { return async_req_simple_recv(req); } - -struct wb_trans_state { - struct event_context *ev; - struct timed_event *te; - int fd; - struct winbindd_response *wb_resp; - size_t reply_max_extra_data; -}; - -static void wb_trans_timeout(struct event_context *ev, struct timed_event *te, - const struct timeval *now, void *priv); -static void wb_trans_sent(struct async_req *req); -static void wb_trans_received(struct async_req *req); - -struct async_req *wb_trans_send(TALLOC_CTX *mem_ctx, - struct event_context *ev, - int fd, - struct winbindd_request *wb_req, - struct timeval timeout, - size_t reply_max_extra_data) -{ - struct async_req *result, *subreq; - struct wb_trans_state *state; - - result = async_req_new(mem_ctx); - if (result == NULL) { - return NULL; - } - - state = talloc(result, struct wb_trans_state); - if (state == NULL) { - goto nomem; - } - result->private_data = state; - - state->ev = ev; - state->fd = fd; - state->reply_max_extra_data = reply_max_extra_data; - - state->te = event_add_timed( - ev, state, - timeval_current_ofs(timeout.tv_sec, timeout.tv_usec), - "wb_trans_timeout", wb_trans_timeout, result); - if (state->te == NULL) { - goto nomem; - } - - subreq = wb_req_write_send(state, state->ev, state->fd, wb_req); - if (subreq == NULL) { - goto nomem; - } - subreq->async.fn = wb_trans_sent; - subreq->async.priv = result; - - return result; - - nomem: - TALLOC_FREE(result); - return NULL; -} - -static void wb_trans_timeout(struct event_context *ev, struct timed_event *te, - const struct timeval *now, void *priv) -{ - struct async_req *req = talloc_get_type_abort( - priv, struct async_req); - struct wb_trans_state *state = talloc_get_type_abort( - req->private_data, struct wb_trans_state); - - TALLOC_FREE(state->te); - async_req_error(req, NT_STATUS_IO_TIMEOUT); -} - -static void wb_trans_sent(struct async_req *subreq) -{ - struct async_req *req = talloc_get_type_abort( - subreq->async.priv, struct async_req); - struct wb_trans_state *state = talloc_get_type_abort( - req->private_data, struct wb_trans_state); - NTSTATUS status; - - status = wb_req_write_recv(subreq); - TALLOC_FREE(subreq); - if (!NT_STATUS_IS_OK(status)) { - async_req_error(req, status); - return; - } - - subreq = wb_resp_read_send(state, state->ev, state->fd); - if (async_req_nomem(subreq, req)) { - return; - } - - subreq->async.fn = wb_trans_received; - subreq->async.priv = req; -}; - -static void wb_trans_received(struct async_req *subreq) -{ - struct async_req *req = talloc_get_type_abort( - subreq->async.priv, struct async_req); - struct wb_trans_state *state = talloc_get_type_abort( - req->private_data, struct wb_trans_state); - NTSTATUS status; - - TALLOC_FREE(state->te); - - status = wb_resp_read_recv(subreq, state, &state->wb_resp); - TALLOC_FREE(subreq); - if (!NT_STATUS_IS_OK(status)) { - async_req_error(req, status); - return; - } - - async_req_done(req); -} - -NTSTATUS wb_trans_recv(struct async_req *req, TALLOC_CTX *mem_ctx, - struct winbindd_response **presp) -{ - struct wb_trans_state *state = talloc_get_type_abort( - req->private_data, struct wb_trans_state); - NTSTATUS status; - - if (async_req_is_error(req, &status)) { - return status; - } - *presp = talloc_move(mem_ctx, &state->wb_resp); - return NT_STATUS_OK; -} - -struct wb_trans_queue_state { - struct wb_trans_queue_state *prev, *next; - struct wb_trans_queue *queue; - struct winbindd_request *req; -}; - -struct wb_trans_queue { - int fd; - struct timeval timeout; - size_t max_resp_extra_data; - struct wb_trans_queue_state *queued_requests; -}; -- cgit From 4df681abf497c24e8abf3df1137023389bfed709 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Sat, 27 Dec 2008 18:43:03 +0100 Subject: async libwbclient infrastructure --- source3/lib/wbclient.c | 774 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 774 insertions(+) create mode 100644 source3/lib/wbclient.c (limited to 'source3/lib') diff --git a/source3/lib/wbclient.c b/source3/lib/wbclient.c new file mode 100644 index 0000000000..d58c934c07 --- /dev/null +++ b/source3/lib/wbclient.c @@ -0,0 +1,774 @@ +/* + Unix SMB/CIFS implementation. + Infrastructure for async winbind requests + Copyright (C) Volker Lendecke 2008 + + 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 . +*/ + +#include "includes.h" +#include "winbindd/winbindd.h" +#include "winbindd/winbindd_proto.h" + +static int make_nonstd_fd(int fd) +{ + int i; + int sys_errno = 0; + int fds[3]; + int num_fds = 0; + + if (fd == -1) { + return -1; + } + while (fd < 3) { + fds[num_fds++] = fd; + fd = dup(fd); + if (fd == -1) { + sys_errno = errno; + break; + } + } + for (i=0; i= 0) { + flags |= FD_CLOEXEC; + result = fcntl( new_fd, F_SETFD, flags ); + } + if (result < 0) { + goto fail; + } +#endif + return new_fd; + + fail: + if (new_fd != -1) { + int sys_errno = errno; + close(new_fd); + errno = sys_errno; + } + return -1; +} + +static bool winbind_closed_fd(int fd) +{ + struct timeval tv; + fd_set r_fds; + + if (fd == -1) { + return true; + } + + FD_ZERO(&r_fds); + FD_SET(fd, &r_fds); + ZERO_STRUCT(tv); + + if ((select(fd+1, &r_fds, NULL, NULL, &tv) == -1) + || FD_ISSET(fd, &r_fds)) { + return true; + } + + return false; +} + +struct wb_context { + struct async_req_queue *queue; + int fd; + bool is_priv; +}; + +struct wb_context *wb_context_init(TALLOC_CTX *mem_ctx) +{ + struct wb_context *result; + + result = talloc(mem_ctx, struct wb_context); + if (result == NULL) { + return NULL; + } + result->queue = async_req_queue_init(result); + if (result->queue == NULL) { + TALLOC_FREE(result); + return NULL; + } + result->fd = -1; + return result; +} + +static struct async_req *wb_connect_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct wb_context *wb_ctx, + const char *dir) +{ + struct async_req *req; + struct sockaddr_un sunaddr; + struct stat st; + char *path = NULL; + NTSTATUS status; + + if (wb_ctx->fd != -1) { + close(wb_ctx->fd); + wb_ctx->fd = -1; + } + + /* Check permissions on unix socket directory */ + + if (lstat(dir, &st) == -1) { + status = NT_STATUS_OBJECT_NAME_NOT_FOUND; + goto post_status; + } + + if (!S_ISDIR(st.st_mode) || + (st.st_uid != 0 && st.st_uid != geteuid())) { + status = NT_STATUS_OBJECT_NAME_NOT_FOUND; + goto post_status; + } + + /* Connect to socket */ + + path = talloc_asprintf(talloc_tos(), "%s/%s", dir, + WINBINDD_SOCKET_NAME); + if (path == NULL) { + goto nomem; + } + + sunaddr.sun_family = AF_UNIX; + strlcpy(sunaddr.sun_path, path, sizeof(sunaddr.sun_path)); + TALLOC_FREE(path); + + /* If socket file doesn't exist, don't bother trying to connect + with retry. This is an attempt to make the system usable when + the winbindd daemon is not running. */ + + if ((lstat(sunaddr.sun_path, &st) == -1) + || !S_ISSOCK(st.st_mode) + || (st.st_uid != 0 && st.st_uid != geteuid())) { + status = NT_STATUS_OBJECT_NAME_NOT_FOUND; + goto post_status; + } + + wb_ctx->fd = make_safe_fd(socket(AF_UNIX, SOCK_STREAM, 0)); + if (wb_ctx->fd == -1) { + status = map_nt_error_from_unix(errno); + goto post_status; + } + + req = async_connect_send(mem_ctx, ev, wb_ctx->fd, + (struct sockaddr *)&sunaddr, + sizeof(sunaddr)); + if (req == NULL) { + goto nomem; + } + if (!async_req_set_timeout(req, ev, timeval_set(30, 0))) { + TALLOC_FREE(req); + goto nomem; + } + + return req; + + nomem: + status = NT_STATUS_NO_MEMORY; + post_status: + req = async_req_new(mem_ctx); + if (req == NULL) { + return NULL; + } + if (async_post_status(req, ev, status)) { + return req; + } + TALLOC_FREE(req); + return NULL; +} + +static NTSTATUS wb_connect_recv(struct async_req *req) +{ + int dummy; + + return async_connect_recv(req, &dummy); +} + +static struct winbindd_request *winbindd_request_copy( + TALLOC_CTX *mem_ctx, + const struct winbindd_request *req) +{ + struct winbindd_request *result; + + result = (struct winbindd_request *)TALLOC_MEMDUP( + mem_ctx, req, sizeof(struct winbindd_request)); + if (result == NULL) { + return NULL; + } + + if (result->extra_len == 0) { + return result; + } + + result->extra_data.data = (char *)TALLOC_MEMDUP( + result, result->extra_data.data, result->extra_len); + if (result->extra_data.data == NULL) { + TALLOC_FREE(result); + return NULL; + } + return result; +} + +struct wb_int_trans_state { + struct event_context *ev; + int fd; + struct winbindd_request *wb_req; + struct winbindd_response *wb_resp; +}; + +static void wb_int_trans_write_done(struct async_req *subreq); +static void wb_int_trans_read_done(struct async_req *subreq); + +static struct async_req *wb_int_trans_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, int fd, + struct winbindd_request *wb_req) +{ + struct async_req *result; + struct async_req *subreq; + struct wb_int_trans_state *state; + + result = async_req_new(mem_ctx); + if (result == NULL) { + return NULL; + } + state = talloc(result, struct wb_int_trans_state); + if (state == NULL) { + goto fail; + } + result->private_data = state; + + if (winbind_closed_fd(fd)) { + if (!async_post_status(result, ev, + NT_STATUS_PIPE_DISCONNECTED)) { + goto fail; + } + return result; + } + + state->ev = ev; + state->fd = fd; + state->wb_req = wb_req; + + state->wb_req->length = sizeof(struct winbindd_request); + state->wb_req->pid = getpid(); + + subreq = wb_req_write_send(state, state->ev, state->fd, state->wb_req); + if (subreq == NULL) { + goto fail; + } + subreq->async.fn = wb_int_trans_write_done; + subreq->async.priv = result; + + return result; + + fail: + TALLOC_FREE(result); + return NULL; +} + +static void wb_int_trans_write_done(struct async_req *subreq) +{ + struct async_req *req = talloc_get_type_abort( + subreq->async.priv, struct async_req); + struct wb_int_trans_state *state = talloc_get_type_abort( + req->private_data, struct wb_int_trans_state); + NTSTATUS status; + + status = wb_req_write_recv(subreq); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + async_req_error(req, status); + return; + } + + subreq = wb_resp_read_send(state, state->ev, state->fd); + if (subreq == NULL) { + async_req_error(req, NT_STATUS_NO_MEMORY); + } + subreq->async.fn = wb_int_trans_read_done; + subreq->async.priv = req; +} + +static void wb_int_trans_read_done(struct async_req *subreq) +{ + struct async_req *req = talloc_get_type_abort( + subreq->async.priv, struct async_req); + struct wb_int_trans_state *state = talloc_get_type_abort( + req->private_data, struct wb_int_trans_state); + NTSTATUS status; + + status = wb_resp_read_recv(subreq, state, &state->wb_resp); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + async_req_error(req, status); + return; + } + + async_req_done(req); +} + +static NTSTATUS wb_int_trans_recv(struct async_req *req, + TALLOC_CTX *mem_ctx, + struct winbindd_response **presponse) +{ + struct wb_int_trans_state *state = talloc_get_type_abort( + req->private_data, struct wb_int_trans_state); + NTSTATUS status; + + if (async_req_is_error(req, &status)) { + return status; + } + + *presponse = talloc_move(mem_ctx, &state->wb_resp); + return NT_STATUS_OK; +} + +static const char *winbindd_socket_dir(void) +{ +#ifdef SOCKET_WRAPPER + const char *env_dir; + + env_dir = getenv(WINBINDD_SOCKET_DIR_ENVVAR); + if (env_dir) { + return env_dir; + } +#endif + + return WINBINDD_SOCKET_DIR; +} + +struct wb_open_pipe_state { + struct wb_context *wb_ctx; + struct event_context *ev; + bool need_priv; + struct winbindd_request wb_req; +}; + +static void wb_open_pipe_connect_nonpriv_done(struct async_req *subreq); +static void wb_open_pipe_ping_done(struct async_req *subreq); +static void wb_open_pipe_getpriv_done(struct async_req *subreq); +static void wb_open_pipe_connect_priv_done(struct async_req *subreq); + +static struct async_req *wb_open_pipe_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct wb_context *wb_ctx, + bool need_priv) +{ + struct async_req *result; + struct async_req *subreq; + struct wb_open_pipe_state *state; + + result = async_req_new(mem_ctx); + if (result == NULL) { + return NULL; + } + state = talloc(result, struct wb_open_pipe_state); + if (state == NULL) { + goto fail; + } + result->private_data = state; + + state->wb_ctx = wb_ctx; + state->ev = ev; + state->need_priv = need_priv; + + if (wb_ctx->fd != -1) { + close(wb_ctx->fd); + wb_ctx->fd = -1; + } + + subreq = wb_connect_send(state, ev, wb_ctx, winbindd_socket_dir()); + if (subreq == NULL) { + goto fail; + } + + subreq->async.fn = wb_open_pipe_connect_nonpriv_done; + subreq->async.priv = result; + return result; + + fail: + TALLOC_FREE(result); + return NULL; +} + +static void wb_open_pipe_connect_nonpriv_done(struct async_req *subreq) +{ + struct async_req *req = talloc_get_type_abort( + subreq->async.priv, struct async_req); + struct wb_open_pipe_state *state = talloc_get_type_abort( + req->private_data, struct wb_open_pipe_state); + NTSTATUS status; + + status = wb_connect_recv(subreq); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + state->wb_ctx->is_priv = true; + async_req_error(req, status); + return; + } + + ZERO_STRUCT(state->wb_req); + state->wb_req.cmd = WINBINDD_INTERFACE_VERSION; + + subreq = wb_int_trans_send(state, state->ev, state->wb_ctx->fd, + &state->wb_req); + if (async_req_nomem(subreq, req)) { + return; + } + + subreq->async.fn = wb_open_pipe_ping_done; + subreq->async.priv = req; +} + +static void wb_open_pipe_ping_done(struct async_req *subreq) +{ + struct async_req *req = talloc_get_type_abort( + subreq->async.priv, struct async_req); + struct wb_open_pipe_state *state = talloc_get_type_abort( + req->private_data, struct wb_open_pipe_state); + struct winbindd_response *wb_resp; + NTSTATUS status; + + status = wb_int_trans_recv(subreq, state, &wb_resp); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + async_req_error(req, status); + return; + } + + if (!state->need_priv) { + async_req_done(req); + return; + } + + state->wb_req.cmd = WINBINDD_PRIV_PIPE_DIR; + + subreq = wb_int_trans_send(state, state->ev, state->wb_ctx->fd, + &state->wb_req); + if (async_req_nomem(subreq, req)) { + return; + } + + subreq->async.fn = wb_open_pipe_getpriv_done; + subreq->async.priv = req; +} + +static void wb_open_pipe_getpriv_done(struct async_req *subreq) +{ + struct async_req *req = talloc_get_type_abort( + subreq->async.priv, struct async_req); + struct wb_open_pipe_state *state = talloc_get_type_abort( + req->private_data, struct wb_open_pipe_state); + struct winbindd_response *wb_resp = NULL; + NTSTATUS status; + + status = wb_int_trans_recv(subreq, state, &wb_resp); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + async_req_error(req, status); + return; + } + + close(state->wb_ctx->fd); + state->wb_ctx->fd = -1; + + subreq = wb_connect_send(state, state->ev, state->wb_ctx, + (char *)wb_resp->extra_data.data); + TALLOC_FREE(wb_resp); + if (async_req_nomem(subreq, req)) { + return; + } + + subreq->async.fn = wb_open_pipe_connect_priv_done; + subreq->async.priv = req; +} + +static void wb_open_pipe_connect_priv_done(struct async_req *subreq) +{ + struct async_req *req = talloc_get_type_abort( + subreq->async.priv, struct async_req); + struct wb_open_pipe_state *state = talloc_get_type_abort( + req->private_data, struct wb_open_pipe_state); + NTSTATUS status; + + status = wb_connect_recv(subreq); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + async_req_error(req, status); + return; + } + state->wb_ctx->is_priv = true; + async_req_done(req); +} + +static NTSTATUS wb_open_pipe_recv(struct async_req *req) +{ + return async_req_simple_recv(req); +} + +struct wb_trans_state { + struct wb_trans_state *prev, *next; + struct wb_context *wb_ctx; + struct event_context *ev; + struct winbindd_request *wb_req; + struct winbindd_response *wb_resp; + int num_retries; + bool need_priv; +}; + +static void wb_trans_connect_done(struct async_req *subreq); +static void wb_trans_done(struct async_req *subreq); +static void wb_trans_retry_wait_done(struct async_req *subreq); + +static void wb_trigger_trans(struct async_req *req) +{ + struct wb_trans_state *state = talloc_get_type_abort( + req->private_data, struct wb_trans_state); + struct async_req *subreq; + + if ((state->wb_ctx->fd == -1) + || (state->need_priv && !state->wb_ctx->is_priv)) { + + subreq = wb_open_pipe_send(state, state->ev, state->wb_ctx, + state->need_priv); + if (async_req_nomem(subreq, req)) { + return; + } + subreq->async.fn = wb_trans_connect_done; + subreq->async.priv = req; + return; + } + + subreq = wb_int_trans_send(state, state->ev, state->wb_ctx->fd, + state->wb_req); + if (async_req_nomem(subreq, req)) { + return; + } + subreq->async.fn = wb_trans_done; + subreq->async.priv = req; +} + +struct async_req *wb_trans_send(TALLOC_CTX *mem_ctx, struct event_context *ev, + struct wb_context *wb_ctx, bool need_priv, + const struct winbindd_request *wb_req) +{ + struct async_req *result; + struct wb_trans_state *state; + + result = async_req_new(mem_ctx); + if (result == NULL) { + return NULL; + } + state = talloc(result, struct wb_trans_state); + if (state == NULL) { + goto fail; + } + result->private_data = state; + + state->wb_ctx = wb_ctx; + state->ev = ev; + state->wb_req = winbindd_request_copy(state, wb_req); + if (state->wb_req == NULL) { + goto fail; + } + state->num_retries = 10; + state->need_priv = need_priv; + + if (!async_req_enqueue(wb_ctx->queue, ev, result, wb_trigger_trans)) { + goto fail; + } + return result; + + fail: + TALLOC_FREE(result); + return NULL; +} + +static bool wb_trans_retry(struct async_req *req, + struct wb_trans_state *state, + NTSTATUS status) +{ + struct async_req *subreq; + + if (NT_STATUS_IS_OK(status)) { + return false; + } + + if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) + || NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) { + /* + * Winbind not around or we can't connect to the pipe. Fail + * immediately. + */ + async_req_error(req, status); + return true; + } + + state->num_retries -= 1; + if (state->num_retries == 0) { + async_req_error(req, status); + return true; + } + + /* + * The transfer as such failed, retry after one second + */ + + if (state->wb_ctx->fd != -1) { + close(state->wb_ctx->fd); + state->wb_ctx->fd = -1; + } + + subreq = async_wait_send(state, state->ev, timeval_set(1, 0)); + if (async_req_nomem(subreq, req)) { + return true; + } + + subreq->async.fn = wb_trans_retry_wait_done; + subreq->async.priv = req; + return true; +} + +static void wb_trans_retry_wait_done(struct async_req *subreq) +{ + struct async_req *req = talloc_get_type_abort( + subreq->async.priv, struct async_req); + struct wb_trans_state *state = talloc_get_type_abort( + req->private_data, struct wb_trans_state); + NTSTATUS status; + + status = async_wait_recv(subreq); + TALLOC_FREE(subreq); + if (!NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) { + async_req_error(req, status); + return; + } + + subreq = wb_open_pipe_send(state, state->ev, state->wb_ctx, + state->need_priv); + if (async_req_nomem(subreq, req)) { + return; + } + subreq->async.fn = wb_trans_connect_done; + subreq->async.priv = req; +} + +static void wb_trans_connect_done(struct async_req *subreq) +{ + struct async_req *req = talloc_get_type_abort( + subreq->async.priv, struct async_req); + struct wb_trans_state *state = talloc_get_type_abort( + req->private_data, struct wb_trans_state); + NTSTATUS status; + + status = wb_open_pipe_recv(subreq); + TALLOC_FREE(subreq); + + if (wb_trans_retry(req, state, status)) { + return; + } + + subreq = wb_int_trans_send(state, state->ev, state->wb_ctx->fd, + state->wb_req); + if (async_req_nomem(subreq, req)) { + return; + } + + subreq->async.fn = wb_trans_done; + subreq->async.priv = req; +} + +static void wb_trans_done(struct async_req *subreq) +{ + struct async_req *req = talloc_get_type_abort( + subreq->async.priv, struct async_req); + struct wb_trans_state *state = talloc_get_type_abort( + req->private_data, struct wb_trans_state); + NTSTATUS status; + + status = wb_int_trans_recv(subreq, state, &state->wb_resp); + TALLOC_FREE(subreq); + + if (wb_trans_retry(req, state, status)) { + return; + } + + async_req_done(req); +} + +NTSTATUS wb_trans_recv(struct async_req *req, TALLOC_CTX *mem_ctx, + struct winbindd_response **presponse) +{ + struct wb_trans_state *state = talloc_get_type_abort( + req->private_data, struct wb_trans_state); + NTSTATUS status; + + if (async_req_is_error(req, &status)) { + return status; + } + + *presponse = talloc_move(mem_ctx, &state->wb_resp); + return NT_STATUS_OK; +} -- cgit From 19b783cce9edf7b616cd1a9d9dcb78a02791d89e Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Sat, 3 Jan 2009 19:50:05 +0100 Subject: Async wrapper for open_socket_out_send/recv --- source3/lib/util_sock.c | 224 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 168 insertions(+), 56 deletions(-) (limited to 'source3/lib') diff --git a/source3/lib/util_sock.c b/source3/lib/util_sock.c index a8c3b3031d..3356318c88 100644 --- a/source3/lib/util_sock.c +++ b/source3/lib/util_sock.c @@ -948,96 +948,208 @@ int open_socket_in(int type, return( res ); } +struct open_socket_out_state { + int fd; + struct event_context *ev; + struct sockaddr_storage ss; + socklen_t salen; + uint16_t port; + int wait_nsec; +}; + +static void open_socket_out_connected(struct async_req *subreq); + +static int open_socket_out_state_destructor(struct open_socket_out_state *s) +{ + if (s->fd != -1) { + close(s->fd); + } + return 0; +} + /**************************************************************************** Create an outgoing socket. timeout is in milliseconds. **************************************************************************/ -int open_socket_out(const struct sockaddr_storage *pss, uint16_t port, - int timeout) +struct async_req *open_socket_out_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, + const struct sockaddr_storage *pss, + uint16_t port, + int timeout) { char addr[INET6_ADDRSTRLEN]; - struct sockaddr_storage sock_out = *pss; - int res,ret; - int connect_loop = 10; - int increment = 10; + struct async_req *result, *subreq; + struct open_socket_out_state *state; + NTSTATUS status; - /* create a socket to write to */ - res = socket(pss->ss_family, SOCK_STREAM, 0); - if (res == -1) { - DEBUG(0,("socket error (%s)\n", strerror(errno))); - return -1; + result = async_req_new(mem_ctx); + if (result == NULL) { + return NULL; + } + state = talloc(result, struct open_socket_out_state); + if (state == NULL) { + goto fail; + } + result->private_data = state; + + state->ev = ev; + state->ss = *pss; + state->port = port; + state->wait_nsec = 10000; + state->salen = -1; + + state->fd = socket(state->ss.ss_family, SOCK_STREAM, 0); + if (state->fd == -1) { + status = map_nt_error_from_unix(errno); + goto post_status; + } + talloc_set_destructor(state, open_socket_out_state_destructor); + + if (!async_req_set_timeout(result, ev, timeval_set(0, timeout*1000))) { + goto fail; } #if defined(HAVE_IPV6) if (pss->ss_family == AF_INET6) { - struct sockaddr_in6 *psa6 = (struct sockaddr_in6 *)&sock_out; + struct sockaddr_in6 *psa6; + psa6 = (struct sockaddr_in6 *)&state->ss; psa6->sin6_port = htons(port); - if (psa6->sin6_scope_id == 0 && - IN6_IS_ADDR_LINKLOCAL(&psa6->sin6_addr)) { - setup_linklocal_scope_id((struct sockaddr *)&sock_out); + if (psa6->sin6_scope_id == 0 + && IN6_IS_ADDR_LINKLOCAL(&psa6->sin6_addr)) { + setup_linklocal_scope_id( + (struct sockaddr *)&(state->ss)); } + state->salen = sizeof(struct sockaddr_in6); } #endif if (pss->ss_family == AF_INET) { - struct sockaddr_in *psa = (struct sockaddr_in *)&sock_out; + struct sockaddr_in *psa; + psa = (struct sockaddr_in *)&state->ss; psa->sin_port = htons(port); + state->salen = sizeof(struct sockaddr_in); } - /* set it non-blocking */ - set_blocking(res,false); + print_sockaddr(addr, sizeof(addr), &state->ss); + DEBUG(3,("Connecting to %s at port %u\n", addr, (unsigned int)port)); - print_sockaddr(addr, sizeof(addr), &sock_out); - DEBUG(3,("Connecting to %s at port %u\n", - addr, - (unsigned int)port)); + subreq = async_connect_send(state, state->ev, state->fd, + (struct sockaddr *)&state->ss, + state->salen); + if ((subreq == NULL) + || !async_req_set_timeout(subreq, state->ev, + timeval_set(0, state->wait_nsec))) { + status = NT_STATUS_NO_MEMORY; + goto post_status; + } + subreq->async.fn = open_socket_out_connected; + subreq->async.priv = result; + return result; - /* and connect it to the destination */ - connect_again: + post_status: + if (!async_post_status(result, ev, status)) { + goto fail; + } + return result; + fail: + TALLOC_FREE(result); + return NULL; +} - ret = sys_connect(res, (struct sockaddr *)&sock_out); +static void open_socket_out_connected(struct async_req *subreq) +{ + struct async_req *req = talloc_get_type_abort( + subreq->async.priv, struct async_req); + struct open_socket_out_state *state = talloc_get_type_abort( + req->private_data, struct open_socket_out_state); + NTSTATUS status; + int sys_errno; - /* Some systems return EAGAIN when they mean EINPROGRESS */ - if (ret < 0 && (errno == EINPROGRESS || errno == EALREADY || - errno == EAGAIN) && (connect_loop < timeout) ) { - smb_msleep(connect_loop); - timeout -= connect_loop; - connect_loop += increment; - if (increment < 250) { - /* After 8 rounds we end up at a max of 255 msec */ - increment *= 1.5; - } - goto connect_again; + status = async_connect_recv(subreq, &sys_errno); + TALLOC_FREE(subreq); + if (NT_STATUS_IS_OK(status)) { + async_req_done(req); + return; } - if (ret < 0 && (errno == EINPROGRESS || errno == EALREADY || - errno == EAGAIN)) { - DEBUG(1,("timeout connecting to %s:%u\n", - addr, - (unsigned int)port)); - close(res); - return -1; + if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) + || (sys_errno == EINPROGRESS) + || (sys_errno == EALREADY) + || (sys_errno == EAGAIN)) { + + /* + * retry + */ + + if (state->wait_nsec < 250000) { + state->wait_nsec *= 1.5; + } + + subreq = async_connect_send(state, state->ev, state->fd, + (struct sockaddr *)&state->ss, + state->salen); + if (async_req_nomem(subreq, req)) { + return; + } + if (!async_req_set_timeout(subreq, state->ev, + timeval_set(0, state->wait_nsec))) { + async_req_error(req, NT_STATUS_NO_MEMORY); + return; + } + subreq->async.fn = open_socket_out_connected; + subreq->async.priv = req; + return; } #ifdef EISCONN - if (ret < 0 && errno == EISCONN) { - errno = 0; - ret = 0; + if (sys_errno == EISCONN) { + async_req_done(req); + return; } #endif - if (ret < 0) { - DEBUG(2,("error connecting to %s:%d (%s)\n", - addr, - (unsigned int)port, - strerror(errno))); - close(res); - return -1; + /* real error */ + async_req_error(req, map_nt_error_from_unix(sys_errno)); +} + +NTSTATUS open_socket_out_recv(struct async_req *req, int *pfd) +{ + struct open_socket_out_state *state = talloc_get_type_abort( + req->private_data, struct open_socket_out_state); + NTSTATUS status; + + if (async_req_is_error(req, &status)) { + return status; } + *pfd = state->fd; + state->fd = -1; + return NT_STATUS_OK; +} - /* set it blocking again */ - set_blocking(res,true); +NTSTATUS open_socket_out(const struct sockaddr_storage *pss, uint16_t port, + int timeout, int *pfd) +{ + TALLOC_CTX *frame = talloc_stackframe(); + struct event_context *ev; + struct async_req *req; + NTSTATUS status = NT_STATUS_NO_MEMORY; - return res; + ev = event_context_init(frame); + if (ev == NULL) { + goto fail; + } + + req = open_socket_out_send(frame, ev, pss, port, timeout); + if (req == NULL) { + goto fail; + } + while (req->state < ASYNC_REQ_DONE) { + event_loop_once(ev); + } + + status = open_socket_out_recv(req, pfd); + fail: + TALLOC_FREE(frame); + return status; } /******************************************************************* -- cgit From 0cc63c64166d2e26b7a7ffc0e78ea6041de35f53 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Sun, 4 Jan 2009 01:45:06 +0100 Subject: Add open_socket_out_defer_send/recv --- source3/lib/util_sock.c | 111 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) (limited to 'source3/lib') diff --git a/source3/lib/util_sock.c b/source3/lib/util_sock.c index 3356318c88..518bb78f65 100644 --- a/source3/lib/util_sock.c +++ b/source3/lib/util_sock.c @@ -1152,6 +1152,117 @@ NTSTATUS open_socket_out(const struct sockaddr_storage *pss, uint16_t port, return status; } +struct open_socket_out_defer_state { + struct event_context *ev; + struct sockaddr_storage ss; + uint16_t port; + int timeout; + int fd; +}; + +static void open_socket_out_defer_waited(struct async_req *subreq); +static void open_socket_out_defer_connected(struct async_req *subreq); + +struct async_req *open_socket_out_defer_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct timeval wait_time, + const struct sockaddr_storage *pss, + uint16_t port, + int timeout) +{ + struct async_req *result, *subreq; + struct open_socket_out_defer_state *state; + NTSTATUS status; + + result = async_req_new(mem_ctx); + if (result == NULL) { + return NULL; + } + state = talloc(result, struct open_socket_out_defer_state); + if (state == NULL) { + goto fail; + } + result->private_data = state; + + state->ev = ev; + state->ss = *pss; + state->port = port; + state->timeout = timeout; + + subreq = async_wait_send(state, ev, wait_time); + if (subreq == NULL) { + status = NT_STATUS_NO_MEMORY; + goto post_status; + } + subreq->async.fn = open_socket_out_defer_waited; + subreq->async.priv = result; + return result; + + post_status: + if (!async_post_status(result, ev, status)) { + goto fail; + } + return result; + fail: + TALLOC_FREE(result); + return NULL; +} + +static void open_socket_out_defer_waited(struct async_req *subreq) +{ + struct async_req *req = talloc_get_type_abort( + subreq->async.priv, struct async_req); + struct open_socket_out_defer_state *state = talloc_get_type_abort( + req->private_data, struct open_socket_out_defer_state); + NTSTATUS status; + + status = async_wait_recv(subreq); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + async_req_error(req, status); + return; + } + + subreq = open_socket_out_send(state, state->ev, &state->ss, + state->port, state->timeout); + if (async_req_nomem(subreq, req)) { + return; + } + subreq->async.fn = open_socket_out_defer_connected; + subreq->async.priv = req; +} + +static void open_socket_out_defer_connected(struct async_req *subreq) +{ + struct async_req *req = talloc_get_type_abort( + subreq->async.priv, struct async_req); + struct open_socket_out_defer_state *state = talloc_get_type_abort( + req->private_data, struct open_socket_out_defer_state); + NTSTATUS status; + + status = open_socket_out_recv(subreq, &state->fd); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + async_req_error(req, status); + return; + } + async_req_done(req); +} + +NTSTATUS open_socket_out_defer_recv(struct async_req *req, int *pfd) +{ + struct open_socket_out_defer_state *state = talloc_get_type_abort( + req->private_data, struct open_socket_out_defer_state); + NTSTATUS status; + + if (async_req_is_error(req, &status)) { + return status; + } + *pfd = state->fd; + state->fd = -1; + return NT_STATUS_OK; +} + /******************************************************************* Create an outgoing TCP socket to the first addr that connects. -- cgit From fe56659442bd5ad7298720b830c26f595189ed2e Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Sun, 4 Jan 2009 18:03:23 +0100 Subject: Remove a duplicated comment --- source3/lib/util_sock.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'source3/lib') diff --git a/source3/lib/util_sock.c b/source3/lib/util_sock.c index 518bb78f65..e913b35d60 100644 --- a/source3/lib/util_sock.c +++ b/source3/lib/util_sock.c @@ -707,10 +707,6 @@ ssize_t write_data_iov(int fd, const struct iovec *orig_iov, int iovcnt) Write data to a fd. ****************************************************************************/ -/**************************************************************************** - Write data to a fd. -****************************************************************************/ - ssize_t write_data(int fd, const char *buffer, size_t N) { ssize_t ret; -- cgit