From 8752e38c05779b6ff72bb0bf49940ef6afe55184 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 9 Nov 2005 08:11:50 +0000 Subject: r11595: added a helper layer to parse streams into individual packets. This is something that Andrew Bartlett has been asking for for a while, and when I started having to re-invent this packet parsing code yet again for SMB2 I decided it was time to do it generically you use it by providing a "is this a full packet yet?" helper function to the packet_*() functions, which then handle all the logic of partial packet buffering. This also goes to great lengths to operate efficiently, minimising the number of recv system calls. (This used to be commit e6c47b954a6f09c53ea419800ce873295fcd0be9) --- source4/lib/stream/packet.c | 312 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 312 insertions(+) create mode 100644 source4/lib/stream/packet.c (limited to 'source4/lib/stream/packet.c') diff --git a/source4/lib/stream/packet.c b/source4/lib/stream/packet.c new file mode 100644 index 0000000000..971135ff9b --- /dev/null +++ b/source4/lib/stream/packet.c @@ -0,0 +1,312 @@ +/* + Unix SMB/CIFS mplementation. + + helper layer for breaking up streams into discrete requests + + Copyright (C) Andrew Tridgell 2005 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 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, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include "includes.h" +#include "dlinklist.h" +#include "lib/events/events.h" +#include "lib/socket/socket.h" +#include "lib/tls/tls.h" +#include "lib/stream/packet.h" + + +struct packet_context { + packet_callback_fn_t callback; + packet_full_request_fn_t full_request; + packet_error_handler_fn_t error_handler; + DATA_BLOB partial; + uint32_t initial_read_size; + uint32_t num_read; + struct tls_context *tls; + struct socket_context *sock; + struct event_context *ev; + size_t packet_size; + void *private; +}; + +/* + initialise a packet receiver +*/ +struct packet_context *packet_init(TALLOC_CTX *mem_ctx) +{ + return talloc_zero(mem_ctx, struct packet_context); +} + + +/* + set the request callback, called when a full request is ready +*/ +void packet_set_callback(struct packet_context *pc, packet_callback_fn_t callback) +{ + pc->callback = callback; +} + +/* + set the error handler +*/ +void packet_set_error_handler(struct packet_context *pc, packet_error_handler_fn_t handler) +{ + pc->error_handler = handler; +} + +/* + set the private pointer passed to the callback functions +*/ +void packet_set_private(struct packet_context *pc, void *private) +{ + pc->private = private; +} + +/* + set the full request callback. Should return as follows: + NT_STATUS_OK == blob is a full request. + STATUS_MORE_ENTRIES == blob is not complete yet + any error == blob is not a valid +*/ +void packet_set_full_request(struct packet_context *pc, packet_full_request_fn_t callback) +{ + pc->full_request = callback; +} + +/* + set a tls context to use. You must either set a tls_context or a socket_context +*/ +void packet_set_tls(struct packet_context *pc, struct tls_context *tls) +{ + pc->tls = tls; +} + +/* + set a socket context to use. You must either set a tls_context or a socket_context +*/ +void packet_set_socket(struct packet_context *pc, struct socket_context *sock) +{ + pc->sock = sock; +} + +/* + set an event context. If this is set then the code will ensure that + packets arrive with separate events, by creating a immediate event + for any secondary packets when more than one packet is read at one + time on a socket. This can matter for code that relies on not + getting more than one packet per event +*/ +void packet_set_event_context(struct packet_context *pc, struct event_context *ev) +{ + pc->ev = ev; +} + + +/* + tell the caller we have an error +*/ +static void packet_error(struct packet_context *pc, NTSTATUS status) +{ + pc->tls = NULL; + pc->sock = NULL; + if (pc->error_handler) { + pc->error_handler(pc->private, status); + return; + } + /* default error handler is to free the callers private pointer */ + if (!NT_STATUS_EQUAL(status, NT_STATUS_END_OF_FILE)) { + DEBUG(0,("packet_error on %s - %s\n", + talloc_get_name(pc->private), nt_errstr(status))); + } + talloc_free(pc->private); + return; +} + + +/* + tell the caller we have EOF +*/ +static void packet_eof(struct packet_context *pc) +{ + packet_error(pc, NT_STATUS_END_OF_FILE); +} + + +/* + used to put packets on event boundaries +*/ +static void packet_next_event(struct event_context *ev, struct timed_event *te, + struct timeval t, void *private) +{ + struct packet_context *pc = talloc_get_type(private, struct packet_context); + packet_recv(pc); +} + +/* + call this when the socket becomes readable to kick off the whole + stream parsing process +*/ +void packet_recv(struct packet_context *pc) +{ + size_t npending; + NTSTATUS status; + size_t nread; + DATA_BLOB blob; + + if (pc->packet_size != 0 && pc->num_read >= pc->packet_size) { + goto next_partial; + } + + if (pc->packet_size != 0) { + /* we've already worked out how long this next packet is, so skip the + socket_pending() call */ + npending = pc->packet_size - pc->num_read; + } else { + if (pc->tls) { + status = tls_socket_pending(pc->tls, &npending); + } else if (pc->sock) { + status = socket_pending(pc->sock, &npending); + } else { + status = NT_STATUS_CONNECTION_DISCONNECTED; + } + if (!NT_STATUS_IS_OK(status)) { + packet_error(pc, status); + return; + } + } + + if (npending == 0) { + packet_eof(pc); + return; + } + + /* possibly expand the partial packet buffer */ + if (npending + pc->num_read > pc->partial.length) { + status = data_blob_realloc(pc, &pc->partial, npending+pc->num_read); + if (!NT_STATUS_IS_OK(status)) { + packet_error(pc, status); + return; + } + } + + if (pc->tls) { + status = tls_socket_recv(pc->tls, pc->partial.data + pc->num_read, + npending, &nread); + } else { + status = socket_recv(pc->sock, pc->partial.data + pc->num_read, + npending, &nread, 0); + } + if (NT_STATUS_IS_ERR(status)) { + packet_error(pc, status); + return; + } + if (!NT_STATUS_IS_OK(status)) { + return; + } + + if (nread == 0) { + packet_eof(pc); + return; + } + + pc->num_read += nread; + + /* see if its a full request */ +next_partial: + blob = pc->partial; + blob.length = pc->num_read; + status = pc->full_request(pc->private, blob, &pc->packet_size); + if (NT_STATUS_IS_ERR(status)) { + packet_error(pc, status); + return; + } + if (!NT_STATUS_IS_OK(status)) { + return; + } + + if (pc->packet_size > pc->num_read) { + /* the caller made an error */ + DEBUG(0,("Invalid packet_size %u greater than num_read %u\n", + pc->packet_size, pc->num_read)); + packet_error(pc, NT_STATUS_INVALID_PARAMETER); + return; + } + + /* it is a full request - give it to the caller */ + blob = pc->partial; + + if (pc->packet_size < pc->num_read) { + pc->partial = data_blob_talloc(pc, blob.data + pc->packet_size, + pc->num_read - pc->packet_size); + if (pc->partial.data == NULL) { + packet_error(pc, NT_STATUS_NO_MEMORY); + return; + } + data_blob_realloc(pc, &blob, pc->packet_size); + } else { + pc->partial = data_blob(NULL, 0); + } + pc->num_read -= pc->packet_size; + pc->packet_size = 0; + + status = pc->callback(pc->private, blob); + if (!NT_STATUS_IS_OK(status)) { + packet_error(pc, status); + return; + } + + if (pc->partial.length == 0) { + return; + } + + /* we got multiple packets in one tcp read */ + if (pc->ev == NULL) { + goto next_partial; + } + + blob = pc->partial; + blob.length = pc->num_read; + + status = pc->full_request(pc->private, blob, &pc->packet_size); + if (NT_STATUS_IS_ERR(status)) { + packet_error(pc, status); + return; + } + + if (!NT_STATUS_IS_OK(status)) { + return; + } + + event_add_timed(pc->ev, pc, timeval_zero(), packet_next_event, pc); +} + + + +/* + a full request checker for NBT formatted packets (first 3 bytes are length) +*/ +NTSTATUS packet_full_request_nbt(void *private, DATA_BLOB blob, size_t *packet_size) +{ + if (blob.length < 4) { + return STATUS_MORE_ENTRIES; + } + *packet_size = 4 + smb_len(blob.data); + if (*packet_size > blob.length) { + return STATUS_MORE_ENTRIES; + } + return NT_STATUS_OK; +} -- cgit From a3fcb93df1571da51a0f525141c3010e7f2dcae6 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 9 Nov 2005 10:50:39 +0000 Subject: r11602: added packet_set_serialise() to allow the generic packet layer to handle optional request serialisation (this is something that is commonly needed on stream connections) (This used to be commit d860eb795693d8c292eec2a639ece4793d28dc38) --- source4/lib/stream/packet.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'source4/lib/stream/packet.c') diff --git a/source4/lib/stream/packet.c b/source4/lib/stream/packet.c index 971135ff9b..50687d18fa 100644 --- a/source4/lib/stream/packet.c +++ b/source4/lib/stream/packet.c @@ -41,6 +41,9 @@ struct packet_context { struct event_context *ev; size_t packet_size; void *private; + struct fd_event *fde; + BOOL serialise; + BOOL processing; }; /* @@ -115,6 +118,16 @@ void packet_set_event_context(struct packet_context *pc, struct event_context *e pc->ev = ev; } +/* + tell the packet layer to serialise requests, so we don't process two requests at once on + one connection. You must have set the event_context +*/ +void packet_set_serialise(struct packet_context *pc, struct fd_event *fde) +{ + pc->serialise = True; + pc->fde = fde; +} + /* tell the caller we have an error @@ -167,6 +180,10 @@ void packet_recv(struct packet_context *pc) size_t nread; DATA_BLOB blob; + if (pc->processing) { + return; + } + if (pc->packet_size != 0 && pc->num_read >= pc->packet_size) { goto next_partial; } @@ -262,8 +279,19 @@ next_partial: } pc->num_read -= pc->packet_size; pc->packet_size = 0; + + if (pc->serialise) { + EVENT_FD_NOT_READABLE(pc->fde); + pc->processing = True; + } status = pc->callback(pc->private, blob); + + if (pc->serialise) { + EVENT_FD_READABLE(pc->fde); + pc->processing = False; + } + if (!NT_STATUS_IS_OK(status)) { packet_error(pc, status); return; -- cgit From fc5a11829d7a10f61b03e09a4880b540deb38a74 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 9 Nov 2005 13:33:53 +0000 Subject: r11605: added handling of the send queue to the generic packet handling code (This used to be commit f98d499b2ef93cf2d060acafbc424754add322a8) --- source4/lib/stream/packet.c | 63 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) (limited to 'source4/lib/stream/packet.c') diff --git a/source4/lib/stream/packet.c b/source4/lib/stream/packet.c index 50687d18fa..3a7a938249 100644 --- a/source4/lib/stream/packet.c +++ b/source4/lib/stream/packet.c @@ -44,6 +44,12 @@ struct packet_context { struct fd_event *fde; BOOL serialise; BOOL processing; + + struct send_element { + struct send_element *next, *prev; + DATA_BLOB blob; + size_t nsent; + } *send_queue; }; /* @@ -323,6 +329,61 @@ next_partial: } +/* + trigger a run of the send queue +*/ +void packet_queue_run(struct packet_context *pc) +{ + while (pc->send_queue) { + struct send_element *el = pc->send_queue; + NTSTATUS status; + size_t nwritten; + DATA_BLOB blob = data_blob_const(el->blob.data + el->nsent, + el->blob.length - el->nsent); + + if (pc->tls) { + status = tls_socket_send(pc->tls, &blob, &nwritten); + } else { + status = socket_send(pc->sock, &blob, &nwritten, 0); + } + if (NT_STATUS_IS_ERR(status)) { + packet_error(pc, NT_STATUS_NET_WRITE_FAULT); + return; + } + if (!NT_STATUS_IS_OK(status)) { + return; + } + el->nsent += nwritten; + if (el->nsent == el->blob.length) { + DLIST_REMOVE(pc->send_queue, el); + talloc_free(el); + } + } + + /* we're out of requests to send, so don't wait for write + events any more */ + EVENT_FD_NOT_WRITEABLE(pc->fde); +} + +/* + put a packet in the send queue +*/ +NTSTATUS packet_send(struct packet_context *pc, DATA_BLOB blob) +{ + struct send_element *el; + el = talloc(pc, struct send_element); + NT_STATUS_HAVE_NO_MEMORY(el); + + DLIST_ADD_END(pc->send_queue, el, struct send_element *); + el->blob = blob; + el->nsent = 0; + talloc_steal(el, blob.data); + + EVENT_FD_WRITEABLE(pc->fde); + + return NT_STATUS_OK; +} + /* a full request checker for NBT formatted packets (first 3 bytes are length) @@ -338,3 +399,5 @@ NTSTATUS packet_full_request_nbt(void *private, DATA_BLOB blob, size_t *packet_s } return NT_STATUS_OK; } + + -- cgit From a9d0bf80459a574ac261a635ee9f68caf0e5f3b0 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Thu, 10 Nov 2005 00:25:57 +0000 Subject: r11618: added a generic '32 bit length prefix' full packet helper to the packet code (This used to be commit b4dbe55105cc2807a17d7e5bf8db9756cc526a3b) --- source4/lib/stream/packet.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) (limited to 'source4/lib/stream/packet.c') diff --git a/source4/lib/stream/packet.c b/source4/lib/stream/packet.c index 3a7a938249..f367368def 100644 --- a/source4/lib/stream/packet.c +++ b/source4/lib/stream/packet.c @@ -388,16 +388,31 @@ NTSTATUS packet_send(struct packet_context *pc, DATA_BLOB blob) /* a full request checker for NBT formatted packets (first 3 bytes are length) */ -NTSTATUS packet_full_request_nbt(void *private, DATA_BLOB blob, size_t *packet_size) +NTSTATUS packet_full_request_nbt(void *private, DATA_BLOB blob, size_t *size) { if (blob.length < 4) { return STATUS_MORE_ENTRIES; } - *packet_size = 4 + smb_len(blob.data); - if (*packet_size > blob.length) { + *size = 4 + smb_len(blob.data); + if (*size > blob.length) { return STATUS_MORE_ENTRIES; } return NT_STATUS_OK; } +/* + work out if a packet is complete for protocols that use a 32 bit network byte + order length +*/ +NTSTATUS packet_full_request_u32(void *private, DATA_BLOB blob, size_t *size) +{ + if (blob.length < 4) { + return STATUS_MORE_ENTRIES; + } + *size = 4 + RIVAL(blob.data, 0); + if (*size > blob.length) { + return STATUS_MORE_ENTRIES; + } + return NT_STATUS_OK; +} -- cgit From 79b3a3afb51947437edbf6804a18a99526e3e281 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Thu, 10 Nov 2005 04:26:00 +0000 Subject: r11627: give the caller much more control over the stream to packet process, allowing it to specify the initial read size (thus preventing over-reading) and to stop the recv process when needed. This is used by the dcerpc socket code, which relies on not getting packets when it isn't ready for them (This used to be commit f869fd674ec4b148dc9a264e94d19ce79d35131d) --- source4/lib/stream/packet.c | 45 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) (limited to 'source4/lib/stream/packet.c') diff --git a/source4/lib/stream/packet.c b/source4/lib/stream/packet.c index f367368def..7aed43a943 100644 --- a/source4/lib/stream/packet.c +++ b/source4/lib/stream/packet.c @@ -36,6 +36,7 @@ struct packet_context { DATA_BLOB partial; uint32_t initial_read_size; uint32_t num_read; + uint32_t initial_read; struct tls_context *tls; struct socket_context *sock; struct event_context *ev; @@ -44,6 +45,7 @@ struct packet_context { struct fd_event *fde; BOOL serialise; BOOL processing; + BOOL recv_disable; struct send_element { struct send_element *next, *prev; @@ -134,6 +136,15 @@ void packet_set_serialise(struct packet_context *pc, struct fd_event *fde) pc->fde = fde; } +/* + tell the packet layer how much to read when starting a new packet + this ensures it doesn't overread +*/ +void packet_set_initial_read(struct packet_context *pc, uint32_t initial_read) +{ + pc->initial_read = initial_read; +} + /* tell the caller we have an error @@ -172,7 +183,9 @@ static void packet_next_event(struct event_context *ev, struct timed_event *te, struct timeval t, void *private) { struct packet_context *pc = talloc_get_type(private, struct packet_context); - packet_recv(pc); + if (pc->num_read != 0 && pc->packet_size >= pc->num_read) { + packet_recv(pc); + } } /* @@ -190,6 +203,11 @@ void packet_recv(struct packet_context *pc) return; } + if (pc->recv_disable) { + EVENT_FD_NOT_READABLE(pc->fde); + return; + } + if (pc->packet_size != 0 && pc->num_read >= pc->packet_size) { goto next_partial; } @@ -198,6 +216,8 @@ void packet_recv(struct packet_context *pc) /* we've already worked out how long this next packet is, so skip the socket_pending() call */ npending = pc->packet_size - pc->num_read; + } else if (pc->initial_read != 0) { + npending = pc->initial_read - pc->num_read; } else { if (pc->tls) { status = tls_socket_pending(pc->tls, &npending); @@ -306,7 +326,7 @@ next_partial: if (pc->partial.length == 0) { return; } - + /* we got multiple packets in one tcp read */ if (pc->ev == NULL) { goto next_partial; @@ -329,6 +349,27 @@ next_partial: } +/* + temporarily disable receiving +*/ +void packet_recv_disable(struct packet_context *pc) +{ + EVENT_FD_NOT_READABLE(pc->fde); + pc->recv_disable = True; +} + +/* + re-enable receiving +*/ +void packet_recv_enable(struct packet_context *pc) +{ + EVENT_FD_READABLE(pc->fde); + pc->recv_disable = False; + if (pc->num_read != 0 && pc->packet_size >= pc->num_read) { + event_add_timed(pc->ev, pc, timeval_zero(), packet_next_event, pc); + } +} + /* trigger a run of the send queue */ -- cgit From 78422169b29d84bfebd8df705b00432d627d202d Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Thu, 10 Nov 2005 04:49:02 +0000 Subject: r11629: fixed a bug found with the socket:testnonblock code. With randomised under-reads we could end up supplying a buffer to the client that has an incorrect length (This used to be commit 9c95015b9cccc10a5ba1facd4b48c0fff34e9588) --- source4/lib/stream/packet.c | 1 + 1 file changed, 1 insertion(+) (limited to 'source4/lib/stream/packet.c') diff --git a/source4/lib/stream/packet.c b/source4/lib/stream/packet.c index 7aed43a943..76b796d4b5 100644 --- a/source4/lib/stream/packet.c +++ b/source4/lib/stream/packet.c @@ -291,6 +291,7 @@ next_partial: /* it is a full request - give it to the caller */ blob = pc->partial; + blob.length = pc->num_read; if (pc->packet_size < pc->num_read) { pc->partial = data_blob_talloc(pc, blob.data + pc->packet_size, -- cgit From 1aa141dbd56e4845cdaddf0c424212a317b78dcf Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Thu, 10 Nov 2005 05:12:28 +0000 Subject: r11630: another fix for over-reading in the packet code. This time get the sign of the comparison right :-) (This used to be commit 7e40077aa793e29b5770aae2e07e964239e8249b) --- source4/lib/stream/packet.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'source4/lib/stream/packet.c') diff --git a/source4/lib/stream/packet.c b/source4/lib/stream/packet.c index 76b796d4b5..7a453add53 100644 --- a/source4/lib/stream/packet.c +++ b/source4/lib/stream/packet.c @@ -34,7 +34,6 @@ struct packet_context { packet_full_request_fn_t full_request; packet_error_handler_fn_t error_handler; DATA_BLOB partial; - uint32_t initial_read_size; uint32_t num_read; uint32_t initial_read; struct tls_context *tls; @@ -183,7 +182,8 @@ static void packet_next_event(struct event_context *ev, struct timed_event *te, struct timeval t, void *private) { struct packet_context *pc = talloc_get_type(private, struct packet_context); - if (pc->num_read != 0 && pc->packet_size >= pc->num_read) { + if (pc->num_read != 0 && pc->packet_size != 0 && + pc->packet_size <= pc->num_read) { packet_recv(pc); } } @@ -196,7 +196,7 @@ void packet_recv(struct packet_context *pc) { size_t npending; NTSTATUS status; - size_t nread; + size_t nread = 0; DATA_BLOB blob; if (pc->processing) { @@ -268,8 +268,16 @@ void packet_recv(struct packet_context *pc) pc->num_read += nread; - /* see if its a full request */ next_partial: + if (pc->partial.length != pc->num_read) { + status = data_blob_realloc(pc, &pc->partial, pc->num_read); + if (!NT_STATUS_IS_OK(status)) { + packet_error(pc, status); + return; + } + } + + /* see if its a full request */ blob = pc->partial; blob.length = pc->num_read; status = pc->full_request(pc->private, blob, &pc->packet_size); -- cgit From 872b821fca36bf543f2c3baf1296f25d1cb7e5a7 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Thu, 10 Nov 2005 11:10:40 +0000 Subject: r11636: a bit neater solution to the nt_cancel problem (This used to be commit ba7864b07eebecd4d4eb2ce515412a49964ae179) --- source4/lib/stream/packet.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) (limited to 'source4/lib/stream/packet.c') diff --git a/source4/lib/stream/packet.c b/source4/lib/stream/packet.c index 7a453add53..a272b28c0c 100644 --- a/source4/lib/stream/packet.c +++ b/source4/lib/stream/packet.c @@ -45,6 +45,7 @@ struct packet_context { BOOL serialise; BOOL processing; BOOL recv_disable; + BOOL nofree; struct send_element { struct send_element *next, *prev; @@ -144,6 +145,14 @@ void packet_set_initial_read(struct packet_context *pc, uint32_t initial_read) pc->initial_read = initial_read; } +/* + tell the packet system not to steal/free blobs given to packet_send() +*/ +void packet_set_nofree(struct packet_context *pc) +{ + pc->nofree = True; +} + /* tell the caller we have an error @@ -427,7 +436,14 @@ NTSTATUS packet_send(struct packet_context *pc, DATA_BLOB blob) DLIST_ADD_END(pc->send_queue, el, struct send_element *); el->blob = blob; el->nsent = 0; - talloc_steal(el, blob.data); + + /* if we aren't going to free the packet then we must reference it + to ensure it doesn't disappear before going out */ + if (pc->nofree) { + talloc_reference(el, blob.data); + } else { + talloc_steal(el, blob.data); + } EVENT_FD_WRITEABLE(pc->fde); -- cgit From f0c7fca7807431a73e389e10a25e756afefd2afe Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 10 Nov 2005 13:52:07 +0000 Subject: r11642: add some error checks metze (This used to be commit 9d6406d8daeff0a9bde72ce7749d18fa61324e8a) --- source4/lib/stream/packet.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'source4/lib/stream/packet.c') diff --git a/source4/lib/stream/packet.c b/source4/lib/stream/packet.c index a272b28c0c..14933ff963 100644 --- a/source4/lib/stream/packet.c +++ b/source4/lib/stream/packet.c @@ -317,7 +317,11 @@ next_partial: packet_error(pc, NT_STATUS_NO_MEMORY); return; } - data_blob_realloc(pc, &blob, pc->packet_size); + status = data_blob_realloc(pc, &blob, pc->packet_size); + if (!NT_STATUS_IS_OK(status)) { + packet_error(pc, status); + return; + } } else { pc->partial = data_blob(NULL, 0); } @@ -440,7 +444,9 @@ NTSTATUS packet_send(struct packet_context *pc, DATA_BLOB blob) /* if we aren't going to free the packet then we must reference it to ensure it doesn't disappear before going out */ if (pc->nofree) { - talloc_reference(el, blob.data); + if (!talloc_reference(el, blob.data)) { + return NT_STATUS_NO_MEMORY; + } } else { talloc_steal(el, blob.data); } -- cgit From 763d862fee5c8d73088e93da0c5a2857eb77afc3 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 14 Nov 2005 02:45:28 +0000 Subject: r11712: avoid changing the fde flags unless really needed (This used to be commit 48e6424b0cce38f7d8f212d1e891ff8bbd5fec34) --- source4/lib/stream/packet.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'source4/lib/stream/packet.c') diff --git a/source4/lib/stream/packet.c b/source4/lib/stream/packet.c index 14933ff963..23db44ef02 100644 --- a/source4/lib/stream/packet.c +++ b/source4/lib/stream/packet.c @@ -43,7 +43,7 @@ struct packet_context { void *private; struct fd_event *fde; BOOL serialise; - BOOL processing; + int processing; BOOL recv_disable; BOOL nofree; @@ -209,6 +209,8 @@ void packet_recv(struct packet_context *pc) DATA_BLOB blob; if (pc->processing) { + EVENT_FD_NOT_READABLE(pc->fde); + pc->processing++; return; } @@ -329,15 +331,16 @@ next_partial: pc->packet_size = 0; if (pc->serialise) { - EVENT_FD_NOT_READABLE(pc->fde); - pc->processing = True; + pc->processing = 1; } status = pc->callback(pc->private, blob); - if (pc->serialise) { - EVENT_FD_READABLE(pc->fde); - pc->processing = False; + if (pc->processing) { + if (pc->processing > 1) { + EVENT_FD_READABLE(pc->fde); + } + pc->processing = 0; } if (!NT_STATUS_IS_OK(status)) { -- cgit From 614950aed35353854019db5cccec5b3154643ca3 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 14 Nov 2005 03:45:57 +0000 Subject: r11713: separate out the setting of the fde in the packet context from the enabling of packet serialisation (This used to be commit 6a47cd65a8b588f9ddd375c57caaba08281e7cbb) --- source4/lib/stream/packet.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'source4/lib/stream/packet.c') diff --git a/source4/lib/stream/packet.c b/source4/lib/stream/packet.c index 23db44ef02..45ca1feb45 100644 --- a/source4/lib/stream/packet.c +++ b/source4/lib/stream/packet.c @@ -127,15 +127,23 @@ void packet_set_event_context(struct packet_context *pc, struct event_context *e } /* - tell the packet layer to serialise requests, so we don't process two requests at once on - one connection. You must have set the event_context + tell the packet layer the fde for the socket */ -void packet_set_serialise(struct packet_context *pc, struct fd_event *fde) +void packet_set_fde(struct packet_context *pc, struct fd_event *fde) { - pc->serialise = True; pc->fde = fde; } +/* + tell the packet layer to serialise requests, so we don't process two + requests at once on one connection. You must have set the + event_context and fde +*/ +void packet_set_serialise(struct packet_context *pc) +{ + pc->serialise = True; +} + /* tell the packet layer how much to read when starting a new packet this ensures it doesn't overread -- cgit From 69c531b75c2aa969fe3e028b92ea5817be574575 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 23 Nov 2005 00:30:58 +0000 Subject: r11870: fixed the problem volker reported with the RPX-XPLOGIN test. The problem was caused by a callback destroying the packet processing context while that context was being used in packet_recv() This is the first time we have used the ability of talloc destructors to 'refuse' a free request. It works well in this case as it makes the composite API simpler to use for other code, and isolates the complexity of having callbacks destroying the packet context to the packet.c code. (This used to be commit b1b2d86541a376f1ef33fae897f750005c386ebe) --- source4/lib/stream/packet.c | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) (limited to 'source4/lib/stream/packet.c') diff --git a/source4/lib/stream/packet.c b/source4/lib/stream/packet.c index 45ca1feb45..54cf662e2e 100644 --- a/source4/lib/stream/packet.c +++ b/source4/lib/stream/packet.c @@ -47,6 +47,9 @@ struct packet_context { BOOL recv_disable; BOOL nofree; + BOOL busy; + BOOL destructor_called; + struct send_element { struct send_element *next, *prev; DATA_BLOB blob; @@ -54,12 +57,35 @@ struct packet_context { } *send_queue; }; +/* + a destructor used when we are processing packets to prevent freeing of this + context while it is being used +*/ +static int packet_destructor(void *p) +{ + struct packet_context *pc = talloc_get_type(p, struct packet_context); + + if (pc->busy) { + pc->destructor_called = True; + /* now we refuse the talloc_free() request. The free will + happen again in the packet_recv() code */ + return -1; + } + + return 0; +} + + /* initialise a packet receiver */ struct packet_context *packet_init(TALLOC_CTX *mem_ctx) { - return talloc_zero(mem_ctx, struct packet_context); + struct packet_context *pc = talloc_zero(mem_ctx, struct packet_context); + if (pc != NULL) { + talloc_set_destructor(pc, packet_destructor); + } + return pc; } @@ -205,6 +231,7 @@ static void packet_next_event(struct event_context *ev, struct timed_event *te, } } + /* call this when the socket becomes readable to kick off the whole stream parsing process @@ -342,8 +369,17 @@ next_partial: pc->processing = 1; } + pc->busy = True; + status = pc->callback(pc->private, blob); + pc->busy = False; + + if (pc->destructor_called) { + talloc_free(pc); + return; + } + if (pc->processing) { if (pc->processing > 1) { EVENT_FD_READABLE(pc->fde); -- cgit From 03d301ead5f702872b8cb948b8cd01b0fa0db5f7 Mon Sep 17 00:00:00 2001 From: Tim Potter Date: Wed, 30 Nov 2005 02:08:15 +0000 Subject: r11967: Fix more 64-bit warnings. (This used to be commit 9c4436a124f874ae240feaf590141d48c33a635f) --- source4/lib/stream/packet.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'source4/lib/stream/packet.c') diff --git a/source4/lib/stream/packet.c b/source4/lib/stream/packet.c index 54cf662e2e..d8ce332de6 100644 --- a/source4/lib/stream/packet.c +++ b/source4/lib/stream/packet.c @@ -337,8 +337,8 @@ next_partial: if (pc->packet_size > pc->num_read) { /* the caller made an error */ - DEBUG(0,("Invalid packet_size %u greater than num_read %u\n", - pc->packet_size, pc->num_read)); + DEBUG(0,("Invalid packet_size %lu greater than num_read %lu\n", + (long)pc->packet_size, (long)pc->num_read)); packet_error(pc, NT_STATUS_INVALID_PARAMETER); return; } -- cgit From 78c50015bb8bd5a1d831a6e7ec796b3367c73145 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Tue, 3 Jan 2006 15:40:05 +0000 Subject: r12694: Move some headers to the directory of the subsystem they belong to. (This used to be commit c722f665c90103f3ed57621c460e32ad33e7a8a3) --- source4/lib/stream/packet.c | 1 + 1 file changed, 1 insertion(+) (limited to 'source4/lib/stream/packet.c') diff --git a/source4/lib/stream/packet.c b/source4/lib/stream/packet.c index d8ce332de6..2c053009dd 100644 --- a/source4/lib/stream/packet.c +++ b/source4/lib/stream/packet.c @@ -22,6 +22,7 @@ */ #include "includes.h" +#include "smb.h" #include "dlinklist.h" #include "lib/events/events.h" #include "lib/socket/socket.h" -- cgit From 556f6c4346d9dccd6dcc431d65508a9ede5fef09 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 7 Mar 2006 16:50:07 +0000 Subject: r13962: make functions public metze (This used to be commit fd84583ab4a3afc484f220d1475b1e61b3f2fbc6) --- source4/lib/stream/packet.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) (limited to 'source4/lib/stream/packet.c') diff --git a/source4/lib/stream/packet.c b/source4/lib/stream/packet.c index 2c053009dd..987193c7d7 100644 --- a/source4/lib/stream/packet.c +++ b/source4/lib/stream/packet.c @@ -80,7 +80,7 @@ static int packet_destructor(void *p) /* initialise a packet receiver */ -struct packet_context *packet_init(TALLOC_CTX *mem_ctx) +_PUBLIC_ struct packet_context *packet_init(TALLOC_CTX *mem_ctx) { struct packet_context *pc = talloc_zero(mem_ctx, struct packet_context); if (pc != NULL) { @@ -93,7 +93,7 @@ struct packet_context *packet_init(TALLOC_CTX *mem_ctx) /* set the request callback, called when a full request is ready */ -void packet_set_callback(struct packet_context *pc, packet_callback_fn_t callback) +_PUBLIC_ void packet_set_callback(struct packet_context *pc, packet_callback_fn_t callback) { pc->callback = callback; } @@ -101,7 +101,7 @@ void packet_set_callback(struct packet_context *pc, packet_callback_fn_t callbac /* set the error handler */ -void packet_set_error_handler(struct packet_context *pc, packet_error_handler_fn_t handler) +_PUBLIC_ void packet_set_error_handler(struct packet_context *pc, packet_error_handler_fn_t handler) { pc->error_handler = handler; } @@ -109,7 +109,7 @@ void packet_set_error_handler(struct packet_context *pc, packet_error_handler_fn /* set the private pointer passed to the callback functions */ -void packet_set_private(struct packet_context *pc, void *private) +_PUBLIC_ void packet_set_private(struct packet_context *pc, void *private) { pc->private = private; } @@ -120,7 +120,7 @@ void packet_set_private(struct packet_context *pc, void *private) STATUS_MORE_ENTRIES == blob is not complete yet any error == blob is not a valid */ -void packet_set_full_request(struct packet_context *pc, packet_full_request_fn_t callback) +_PUBLIC_ void packet_set_full_request(struct packet_context *pc, packet_full_request_fn_t callback) { pc->full_request = callback; } @@ -128,7 +128,7 @@ void packet_set_full_request(struct packet_context *pc, packet_full_request_fn_t /* set a tls context to use. You must either set a tls_context or a socket_context */ -void packet_set_tls(struct packet_context *pc, struct tls_context *tls) +_PUBLIC_ void packet_set_tls(struct packet_context *pc, struct tls_context *tls) { pc->tls = tls; } @@ -136,7 +136,7 @@ void packet_set_tls(struct packet_context *pc, struct tls_context *tls) /* set a socket context to use. You must either set a tls_context or a socket_context */ -void packet_set_socket(struct packet_context *pc, struct socket_context *sock) +_PUBLIC_ void packet_set_socket(struct packet_context *pc, struct socket_context *sock) { pc->sock = sock; } @@ -148,7 +148,7 @@ void packet_set_socket(struct packet_context *pc, struct socket_context *sock) time on a socket. This can matter for code that relies on not getting more than one packet per event */ -void packet_set_event_context(struct packet_context *pc, struct event_context *ev) +_PUBLIC_ void packet_set_event_context(struct packet_context *pc, struct event_context *ev) { pc->ev = ev; } @@ -156,7 +156,7 @@ void packet_set_event_context(struct packet_context *pc, struct event_context *e /* tell the packet layer the fde for the socket */ -void packet_set_fde(struct packet_context *pc, struct fd_event *fde) +_PUBLIC_ void packet_set_fde(struct packet_context *pc, struct fd_event *fde) { pc->fde = fde; } @@ -166,7 +166,7 @@ void packet_set_fde(struct packet_context *pc, struct fd_event *fde) requests at once on one connection. You must have set the event_context and fde */ -void packet_set_serialise(struct packet_context *pc) +_PUBLIC_ void packet_set_serialise(struct packet_context *pc) { pc->serialise = True; } @@ -175,7 +175,7 @@ void packet_set_serialise(struct packet_context *pc) tell the packet layer how much to read when starting a new packet this ensures it doesn't overread */ -void packet_set_initial_read(struct packet_context *pc, uint32_t initial_read) +_PUBLIC_ void packet_set_initial_read(struct packet_context *pc, uint32_t initial_read) { pc->initial_read = initial_read; } @@ -183,7 +183,7 @@ void packet_set_initial_read(struct packet_context *pc, uint32_t initial_read) /* tell the packet system not to steal/free blobs given to packet_send() */ -void packet_set_nofree(struct packet_context *pc) +_PUBLIC_ void packet_set_nofree(struct packet_context *pc) { pc->nofree = True; } @@ -237,7 +237,7 @@ static void packet_next_event(struct event_context *ev, struct timed_event *te, call this when the socket becomes readable to kick off the whole stream parsing process */ -void packet_recv(struct packet_context *pc) +_PUBLIC_ void packet_recv(struct packet_context *pc) { size_t npending; NTSTATUS status; @@ -422,7 +422,7 @@ next_partial: /* temporarily disable receiving */ -void packet_recv_disable(struct packet_context *pc) +_PUBLIC_ void packet_recv_disable(struct packet_context *pc) { EVENT_FD_NOT_READABLE(pc->fde); pc->recv_disable = True; @@ -431,7 +431,7 @@ void packet_recv_disable(struct packet_context *pc) /* re-enable receiving */ -void packet_recv_enable(struct packet_context *pc) +_PUBLIC_ void packet_recv_enable(struct packet_context *pc) { EVENT_FD_READABLE(pc->fde); pc->recv_disable = False; @@ -443,7 +443,7 @@ void packet_recv_enable(struct packet_context *pc) /* trigger a run of the send queue */ -void packet_queue_run(struct packet_context *pc) +_PUBLIC_ void packet_queue_run(struct packet_context *pc) { while (pc->send_queue) { struct send_element *el = pc->send_queue; @@ -479,7 +479,7 @@ void packet_queue_run(struct packet_context *pc) /* put a packet in the send queue */ -NTSTATUS packet_send(struct packet_context *pc, DATA_BLOB blob) +_PUBLIC_ NTSTATUS packet_send(struct packet_context *pc, DATA_BLOB blob) { struct send_element *el; el = talloc(pc, struct send_element); @@ -508,7 +508,7 @@ NTSTATUS packet_send(struct packet_context *pc, DATA_BLOB blob) /* a full request checker for NBT formatted packets (first 3 bytes are length) */ -NTSTATUS packet_full_request_nbt(void *private, DATA_BLOB blob, size_t *size) +_PUBLIC_ NTSTATUS packet_full_request_nbt(void *private, DATA_BLOB blob, size_t *size) { if (blob.length < 4) { return STATUS_MORE_ENTRIES; @@ -525,7 +525,7 @@ NTSTATUS packet_full_request_nbt(void *private, DATA_BLOB blob, size_t *size) work out if a packet is complete for protocols that use a 32 bit network byte order length */ -NTSTATUS packet_full_request_u32(void *private, DATA_BLOB blob, size_t *size) +_PUBLIC_ NTSTATUS packet_full_request_u32(void *private, DATA_BLOB blob, size_t *size) { if (blob.length < 4) { return STATUS_MORE_ENTRIES; -- cgit From c2cc10c7869221c7f43cbbb151feb4c4db173cb9 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Sun, 30 Apr 2006 05:58:31 +0000 Subject: r15356: Remove unused 'flags' argument from socket_send() and friends. This is in preperation for making TLS a socket library. Andrew Bartlett (This used to be commit a312812b92f5ac7e6bd2c4af725dbbbc900d4452) --- source4/lib/stream/packet.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'source4/lib/stream/packet.c') diff --git a/source4/lib/stream/packet.c b/source4/lib/stream/packet.c index 987193c7d7..613400226b 100644 --- a/source4/lib/stream/packet.c +++ b/source4/lib/stream/packet.c @@ -298,7 +298,7 @@ _PUBLIC_ void packet_recv(struct packet_context *pc) npending, &nread); } else { status = socket_recv(pc->sock, pc->partial.data + pc->num_read, - npending, &nread, 0); + npending, &nread); } if (NT_STATUS_IS_ERR(status)) { packet_error(pc, status); @@ -455,7 +455,7 @@ _PUBLIC_ void packet_queue_run(struct packet_context *pc) if (pc->tls) { status = tls_socket_send(pc->tls, &blob, &nwritten); } else { - status = socket_send(pc->sock, &blob, &nwritten, 0); + status = socket_send(pc->sock, &blob, &nwritten); } if (NT_STATUS_IS_ERR(status)) { packet_error(pc, NT_STATUS_NET_WRITE_FAULT); -- cgit From 742c110cd67f4995639822981e8bfcb1f652f2c4 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Tue, 2 May 2006 20:15:47 +0000 Subject: r15400: Move the TLS code behind the socket interface. This reduces caller complexity, because the TLS code is now called just like any other socket. (A new socket context is returned by the tls_init_server and tls_init_client routines). When TLS is not available, the original socket is returned. Andrew Bartlett (This used to be commit 09b2f30dfa7a640f5187b4933204e9680be61497) --- source4/lib/stream/packet.c | 34 +++++++--------------------------- 1 file changed, 7 insertions(+), 27 deletions(-) (limited to 'source4/lib/stream/packet.c') diff --git a/source4/lib/stream/packet.c b/source4/lib/stream/packet.c index 613400226b..1da7f5706b 100644 --- a/source4/lib/stream/packet.c +++ b/source4/lib/stream/packet.c @@ -26,7 +26,6 @@ #include "dlinklist.h" #include "lib/events/events.h" #include "lib/socket/socket.h" -#include "lib/tls/tls.h" #include "lib/stream/packet.h" @@ -37,7 +36,6 @@ struct packet_context { DATA_BLOB partial; uint32_t num_read; uint32_t initial_read; - struct tls_context *tls; struct socket_context *sock; struct event_context *ev; size_t packet_size; @@ -126,15 +124,7 @@ _PUBLIC_ void packet_set_full_request(struct packet_context *pc, packet_full_req } /* - set a tls context to use. You must either set a tls_context or a socket_context -*/ -_PUBLIC_ void packet_set_tls(struct packet_context *pc, struct tls_context *tls) -{ - pc->tls = tls; -} - -/* - set a socket context to use. You must either set a tls_context or a socket_context + set a socket context to use. You must set a socket_context */ _PUBLIC_ void packet_set_socket(struct packet_context *pc, struct socket_context *sock) { @@ -194,7 +184,6 @@ _PUBLIC_ void packet_set_nofree(struct packet_context *pc) */ static void packet_error(struct packet_context *pc, NTSTATUS status) { - pc->tls = NULL; pc->sock = NULL; if (pc->error_handler) { pc->error_handler(pc->private, status); @@ -266,9 +255,7 @@ _PUBLIC_ void packet_recv(struct packet_context *pc) } else if (pc->initial_read != 0) { npending = pc->initial_read - pc->num_read; } else { - if (pc->tls) { - status = tls_socket_pending(pc->tls, &npending); - } else if (pc->sock) { + if (pc->sock) { status = socket_pending(pc->sock, &npending); } else { status = NT_STATUS_CONNECTION_DISCONNECTED; @@ -293,13 +280,9 @@ _PUBLIC_ void packet_recv(struct packet_context *pc) } } - if (pc->tls) { - status = tls_socket_recv(pc->tls, pc->partial.data + pc->num_read, - npending, &nread); - } else { - status = socket_recv(pc->sock, pc->partial.data + pc->num_read, - npending, &nread); - } + status = socket_recv(pc->sock, pc->partial.data + pc->num_read, + npending, &nread); + if (NT_STATUS_IS_ERR(status)) { packet_error(pc, status); return; @@ -452,11 +435,8 @@ _PUBLIC_ void packet_queue_run(struct packet_context *pc) DATA_BLOB blob = data_blob_const(el->blob.data + el->nsent, el->blob.length - el->nsent); - if (pc->tls) { - status = tls_socket_send(pc->tls, &blob, &nwritten); - } else { - status = socket_send(pc->sock, &blob, &nwritten); - } + status = socket_send(pc->sock, &blob, &nwritten); + if (NT_STATUS_IS_ERR(status)) { packet_error(pc, NT_STATUS_NET_WRITE_FAULT); return; -- cgit From 971d30bb201f5c3faff5f575d26882eb79f7955a Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 24 May 2006 07:34:11 +0000 Subject: r15854: more talloc_set_destructor() typesafe fixes (This used to be commit 61c6100617589ac6df4f527877241464cacbf8b3) --- source4/lib/stream/packet.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'source4/lib/stream/packet.c') diff --git a/source4/lib/stream/packet.c b/source4/lib/stream/packet.c index 1da7f5706b..e06f4985ef 100644 --- a/source4/lib/stream/packet.c +++ b/source4/lib/stream/packet.c @@ -60,10 +60,8 @@ struct packet_context { a destructor used when we are processing packets to prevent freeing of this context while it is being used */ -static int packet_destructor(void *p) +static int packet_destructor(struct packet_context *pc) { - struct packet_context *pc = talloc_get_type(p, struct packet_context); - if (pc->busy) { pc->destructor_called = True; /* now we refuse the talloc_free() request. The free will -- cgit From ba07fa43d0b0090f5e686d8c1822468049f52416 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Sun, 23 Jul 2006 02:50:08 +0000 Subject: r17197: This patch moves the encryption of bulk data on SASL negotiated security contexts from the application layer into the socket layer. This improves a number of correctness aspects, as we now allow LDAP packets to cross multiple SASL packets. It should also make it much easier to write async LDAP tests from windows clients, as they use SASL by default. It is also vital to allowing OpenLDAP clients to use GSSAPI against Samba4, as it negotiates a rather small SASL buffer size. This patch mirrors the earlier work done to move TLS into the socket layer. Unusual in this pstch is the extra read callback argument I take. As SASL is a layer on top of a socket, it is entirely possible for the SASL layer to drain a socket dry, but for the caller not to have read all the decrypted data. This would leave the system without an event to restart the read (as the socket is dry). As such, I re-invoke the read handler from a timed callback, which should trigger on the next running of the event loop. I believe that the TLS code does require a similar callback. In trying to understand why this is required, imagine a SASL-encrypted LDAP packet in the following formation: +-----------------+---------------------+ | SASL Packet #1 | SASL Packet #2 | ----------------------------------------+ | LDAP Packet #1 | LDAP Packet #2 | ----------------------------------------+ In the old code, this was illegal, but it is perfectly standard SASL-encrypted LDAP. Without the callback, we would read and process the first LDAP packet, and the SASL code would have read the second SASL packet (to decrypt enough data for the LDAP packet), and no data would remain on the socket. Without data on the socket, read events stop. That is why I add timed events, until the SASL buffer is drained. Another approach would be to add a hack to the event system, to have it pretend there remained data to read off the network (but that is ugly). In improving the code, to handle more real-world cases, I've been able to remove almost all the special-cases in the testnonblock code. The only special case is that we must use a deterministic partial packet when calling send, rather than a random length. (1 + n/2). This is needed because of the way the SASL and TLS code works, and the 'resend on failure' requirements. Andrew Bartlett (This used to be commit 5d7c9c12cb2b39673172a357092b80cd814850b0) --- source4/lib/stream/packet.c | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) (limited to 'source4/lib/stream/packet.c') diff --git a/source4/lib/stream/packet.c b/source4/lib/stream/packet.c index e06f4985ef..2759c75214 100644 --- a/source4/lib/stream/packet.c +++ b/source4/lib/stream/packet.c @@ -28,7 +28,6 @@ #include "lib/socket/socket.h" #include "lib/stream/packet.h" - struct packet_context { packet_callback_fn_t callback; packet_full_request_fn_t full_request; @@ -53,6 +52,8 @@ struct packet_context { struct send_element *next, *prev; DATA_BLOB blob; size_t nsent; + packet_send_callback_fn_t send_callback; + void *send_callback_private; } *send_queue; }; @@ -374,6 +375,7 @@ next_partial: return; } + /* Have we consumed the whole buffer yet? */ if (pc->partial.length == 0) { return; } @@ -436,7 +438,7 @@ _PUBLIC_ void packet_queue_run(struct packet_context *pc) status = socket_send(pc->sock, &blob, &nwritten); if (NT_STATUS_IS_ERR(status)) { - packet_error(pc, NT_STATUS_NET_WRITE_FAULT); + packet_error(pc, status); return; } if (!NT_STATUS_IS_OK(status)) { @@ -445,6 +447,9 @@ _PUBLIC_ void packet_queue_run(struct packet_context *pc) el->nsent += nwritten; if (el->nsent == el->blob.length) { DLIST_REMOVE(pc->send_queue, el); + if (el->send_callback) { + el->send_callback(el->send_callback_private); + } talloc_free(el); } } @@ -455,9 +460,15 @@ _PUBLIC_ void packet_queue_run(struct packet_context *pc) } /* - put a packet in the send queue + put a packet in the send queue. When the packet is actually sent, + call send_callback. + + Useful for operations that must occour after sending a message, such + as the switch to SASL encryption after as sucessful LDAP bind relpy. */ -_PUBLIC_ NTSTATUS packet_send(struct packet_context *pc, DATA_BLOB blob) +_PUBLIC_ NTSTATUS packet_send_callback(struct packet_context *pc, DATA_BLOB blob, + packet_send_callback_fn_t send_callback, + void *private) { struct send_element *el; el = talloc(pc, struct send_element); @@ -466,6 +477,8 @@ _PUBLIC_ NTSTATUS packet_send(struct packet_context *pc, DATA_BLOB blob) DLIST_ADD_END(pc->send_queue, el, struct send_element *); el->blob = blob; el->nsent = 0; + el->send_callback = send_callback; + el->send_callback_private = private; /* if we aren't going to free the packet then we must reference it to ensure it doesn't disappear before going out */ @@ -477,11 +490,23 @@ _PUBLIC_ NTSTATUS packet_send(struct packet_context *pc, DATA_BLOB blob) talloc_steal(el, blob.data); } + if (private && !talloc_reference(el, private)) { + return NT_STATUS_NO_MEMORY; + } + EVENT_FD_WRITEABLE(pc->fde); return NT_STATUS_OK; } +/* + put a packet in the send queue +*/ +_PUBLIC_ NTSTATUS packet_send(struct packet_context *pc, DATA_BLOB blob) +{ + return packet_send_callback(pc, blob, NULL, NULL); +} + /* a full request checker for NBT formatted packets (first 3 bytes are length) -- cgit From 9d6f2767179fad2f9a067c67c09afddb6304e4eb Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Tue, 25 Jul 2006 00:57:27 +0000 Subject: r17222: Change the function prototypes for the GENSEc and TLS socket creation routines to return an NTSTATUS. This should help track down errors. Use a bit of talloc_steal and talloc_unlink to get the real socket to be a child of the GENSEC or TLS socket. Always return a new socket, even for the 'pass-though' case. Andrew Bartlett (This used to be commit 003e2ab93c87267ba28cd67bd85975bad62a8ea2) --- source4/lib/stream/packet.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'source4/lib/stream/packet.c') diff --git a/source4/lib/stream/packet.c b/source4/lib/stream/packet.c index 2759c75214..0d14435486 100644 --- a/source4/lib/stream/packet.c +++ b/source4/lib/stream/packet.c @@ -270,6 +270,16 @@ _PUBLIC_ void packet_recv(struct packet_context *pc) return; } + if (npending + pc->num_read < npending) { + packet_error(pc, NT_STATUS_INVALID_PARAMETER); + return; + } + + if (npending + pc->num_read < pc->num_read) { + packet_error(pc, NT_STATUS_INVALID_PARAMETER); + return; + } + /* possibly expand the partial packet buffer */ if (npending + pc->num_read > pc->partial.length) { status = data_blob_realloc(pc, &pc->partial, npending+pc->num_read); @@ -279,6 +289,20 @@ _PUBLIC_ void packet_recv(struct packet_context *pc) } } + if (pc->partial.length < pc->num_read + npending) { + packet_error(pc, NT_STATUS_INVALID_PARAMETER); + return; + } + + if ((uint8_t *)pc->partial.data + pc->num_read < (uint8_t *)pc->partial.data) { + packet_error(pc, NT_STATUS_INVALID_PARAMETER); + return; + } + if ((uint8_t *)pc->partial.data + pc->num_read + npending < (uint8_t *)pc->partial.data) { + packet_error(pc, NT_STATUS_INVALID_PARAMETER); + return; + } + status = socket_recv(pc->sock, pc->partial.data + pc->num_read, npending, &nread); @@ -337,6 +361,7 @@ next_partial: packet_error(pc, NT_STATUS_NO_MEMORY); return; } + /* Trunate the blob sent to the caller to only the packet length */ status = data_blob_realloc(pc, &blob, pc->packet_size); if (!NT_STATUS_IS_OK(status)) { packet_error(pc, status); -- cgit From 0329d755a7611ba3897fc1ee9bdce410cc33d7f8 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Wed, 30 Aug 2006 11:29:34 +0000 Subject: r17930: Merge noinclude branch: * Move dlinklist.h, smb.h to subsystem-specific directories * Clean up ads.h and move what is left of it to dsdb/ (only place where it's used) (This used to be commit f7afa1cb77f3cfa7020b57de12e6003db7cfcc42) --- source4/lib/stream/packet.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'source4/lib/stream/packet.c') diff --git a/source4/lib/stream/packet.c b/source4/lib/stream/packet.c index 0d14435486..2c472641cc 100644 --- a/source4/lib/stream/packet.c +++ b/source4/lib/stream/packet.c @@ -22,11 +22,11 @@ */ #include "includes.h" -#include "smb.h" -#include "dlinklist.h" +#include "lib/util/dlinklist.h" #include "lib/events/events.h" #include "lib/socket/socket.h" #include "lib/stream/packet.h" +#include "libcli/raw/smb.h" struct packet_context { packet_callback_fn_t callback; -- cgit From 0479a2f1cbae51fcd8dbdc3c148c808421fb4d25 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Tue, 10 Jul 2007 02:07:03 +0000 Subject: r23792: convert Samba4 to GPLv3 There are still a few tidyups of old FSF addresses to come (in both s3 and s4). More commits soon. (This used to be commit fcf38a38ac691abd0fa51b89dc951a08e89fdafa) --- source4/lib/stream/packet.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'source4/lib/stream/packet.c') diff --git a/source4/lib/stream/packet.c b/source4/lib/stream/packet.c index 2c472641cc..3f4fcb1ef7 100644 --- a/source4/lib/stream/packet.c +++ b/source4/lib/stream/packet.c @@ -7,7 +7,7 @@ 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 2 of the License, or + 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, @@ -16,8 +16,7 @@ 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, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + along with this program. If not, see . */ -- cgit From 0b91f3916430d0271eab867675d44c5439de40c2 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Wed, 29 Aug 2007 13:07:03 +0000 Subject: r24780: More work allowing libutil to be used by external users. (This used to be commit 31993cf67b816a184a4a4e92ef8ca2532c797190) --- source4/lib/stream/packet.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) (limited to 'source4/lib/stream/packet.c') diff --git a/source4/lib/stream/packet.c b/source4/lib/stream/packet.c index 3f4fcb1ef7..e6cfae7bd6 100644 --- a/source4/lib/stream/packet.c +++ b/source4/lib/stream/packet.c @@ -281,9 +281,8 @@ _PUBLIC_ void packet_recv(struct packet_context *pc) /* possibly expand the partial packet buffer */ if (npending + pc->num_read > pc->partial.length) { - status = data_blob_realloc(pc, &pc->partial, npending+pc->num_read); - if (!NT_STATUS_IS_OK(status)) { - packet_error(pc, status); + if (!data_blob_realloc(pc, &pc->partial, npending+pc->num_read)) { + packet_error(pc, NT_STATUS_NO_MEMORY); return; } } @@ -322,9 +321,8 @@ _PUBLIC_ void packet_recv(struct packet_context *pc) next_partial: if (pc->partial.length != pc->num_read) { - status = data_blob_realloc(pc, &pc->partial, pc->num_read); - if (!NT_STATUS_IS_OK(status)) { - packet_error(pc, status); + if (!data_blob_realloc(pc, &pc->partial, pc->num_read)) { + packet_error(pc, NT_STATUS_NO_MEMORY); return; } } @@ -361,9 +359,8 @@ next_partial: return; } /* Trunate the blob sent to the caller to only the packet length */ - status = data_blob_realloc(pc, &blob, pc->packet_size); - if (!NT_STATUS_IS_OK(status)) { - packet_error(pc, status); + if (!data_blob_realloc(pc, &blob, pc->packet_size)) { + packet_error(pc, NT_STATUS_NO_MEMORY); return; } } else { -- cgit From 719a4ae0d32ab9ba817fd01f2b8f4cba220a8c60 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Fri, 5 Oct 2007 18:03:01 +0000 Subject: r25522: Convert to standard bool types. (This used to be commit 5e814287ba475e12f8cc934fdd09b199dcdfdb86) --- source4/lib/stream/packet.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'source4/lib/stream/packet.c') diff --git a/source4/lib/stream/packet.c b/source4/lib/stream/packet.c index e6cfae7bd6..51021c1fc6 100644 --- a/source4/lib/stream/packet.c +++ b/source4/lib/stream/packet.c @@ -39,13 +39,13 @@ struct packet_context { size_t packet_size; void *private; struct fd_event *fde; - BOOL serialise; + bool serialise; int processing; - BOOL recv_disable; - BOOL nofree; + bool recv_disable; + bool nofree; - BOOL busy; - BOOL destructor_called; + bool busy; + bool destructor_called; struct send_element { struct send_element *next, *prev; @@ -63,7 +63,7 @@ struct packet_context { static int packet_destructor(struct packet_context *pc) { if (pc->busy) { - pc->destructor_called = True; + pc->destructor_called = true; /* now we refuse the talloc_free() request. The free will happen again in the packet_recv() code */ return -1; @@ -156,7 +156,7 @@ _PUBLIC_ void packet_set_fde(struct packet_context *pc, struct fd_event *fde) */ _PUBLIC_ void packet_set_serialise(struct packet_context *pc) { - pc->serialise = True; + pc->serialise = true; } /* @@ -173,7 +173,7 @@ _PUBLIC_ void packet_set_initial_read(struct packet_context *pc, uint32_t initia */ _PUBLIC_ void packet_set_nofree(struct packet_context *pc) { - pc->nofree = True; + pc->nofree = true; } @@ -373,11 +373,11 @@ next_partial: pc->processing = 1; } - pc->busy = True; + pc->busy = true; status = pc->callback(pc->private, blob); - pc->busy = False; + pc->busy = false; if (pc->destructor_called) { talloc_free(pc); @@ -429,7 +429,7 @@ next_partial: _PUBLIC_ void packet_recv_disable(struct packet_context *pc) { EVENT_FD_NOT_READABLE(pc->fde); - pc->recv_disable = True; + pc->recv_disable = true; } /* @@ -438,7 +438,7 @@ _PUBLIC_ void packet_recv_disable(struct packet_context *pc) _PUBLIC_ void packet_recv_enable(struct packet_context *pc) { EVENT_FD_READABLE(pc->fde); - pc->recv_disable = False; + pc->recv_disable = false; if (pc->num_read != 0 && pc->packet_size >= pc->num_read) { event_add_timed(pc->ev, pc, timeval_zero(), packet_next_event, pc); } -- cgit From 8350a230939dbb734a6c4b9ffa665421f8f05821 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 7 Jul 2008 18:55:59 +0200 Subject: packet: make it possible to free the packet_context from the send_callback metze (cherry picked from commit 20795c4a0d5f75561561470231de1a2fad2906ff) (This used to be commit 5d5b4e4ab23e1c630dfde2b9f296681e3979c4e0) --- source4/lib/stream/packet.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'source4/lib/stream/packet.c') diff --git a/source4/lib/stream/packet.c b/source4/lib/stream/packet.c index 51021c1fc6..92fa0e5a54 100644 --- a/source4/lib/stream/packet.c +++ b/source4/lib/stream/packet.c @@ -469,7 +469,13 @@ _PUBLIC_ void packet_queue_run(struct packet_context *pc) if (el->nsent == el->blob.length) { DLIST_REMOVE(pc->send_queue, el); if (el->send_callback) { + pc->busy = true; el->send_callback(el->send_callback_private); + pc->busy = false; + if (pc->destructor_called) { + talloc_free(pc); + return; + } } talloc_free(el); } -- cgit