summaryrefslogtreecommitdiff
path: root/source4/lib/stream/packet.c
diff options
context:
space:
mode:
authorAndrew Bartlett <abartlet@samba.org>2009-02-18 17:47:43 +1100
committerAndrew Bartlett <abartlet@samba.org>2009-02-18 17:47:43 +1100
commit48ba64010046bece3b54009131f88c851ec82047 (patch)
tree0430d009052247af062a3f0f301f2eab33c4d969 /source4/lib/stream/packet.c
parent6b8b7665bdbf47e70e0d6d904c1234c03321182d (diff)
parentbb7e6f0f51a91e461c18efd392af3e4fc6174c34 (diff)
downloadsamba-48ba64010046bece3b54009131f88c851ec82047.tar.gz
samba-48ba64010046bece3b54009131f88c851ec82047.tar.bz2
samba-48ba64010046bece3b54009131f88c851ec82047.zip
Merge branch 'master' of ssh://git.samba.org/data/git/samba into master-devel
Diffstat (limited to 'source4/lib/stream/packet.c')
-rw-r--r--source4/lib/stream/packet.c38
1 files changed, 37 insertions, 1 deletions
diff --git a/source4/lib/stream/packet.c b/source4/lib/stream/packet.c
index f614e9490a..f5e2b843cd 100644
--- a/source4/lib/stream/packet.c
+++ b/source4/lib/stream/packet.c
@@ -47,6 +47,8 @@ struct packet_context {
bool busy;
bool destructor_called;
+ bool unreliable_select;
+
struct send_element {
struct send_element *next, *prev;
DATA_BLOB blob;
@@ -176,6 +178,21 @@ _PUBLIC_ void packet_set_nofree(struct packet_context *pc)
pc->nofree = true;
}
+/*
+ tell the packet system that select/poll/epoll on the underlying
+ socket may not be a reliable way to determine if data is available
+ for receive. This happens with underlying socket systems such as the
+ one implemented on top of GNUTLS, where there may be data in
+ encryption/compression buffers that could be received by
+ socket_recv(), while there is no data waiting at the real socket
+ level as seen by select/poll/epoll. The GNUTLS library is supposed
+ to cope with this by always leaving some data sitting in the socket
+ buffer, but it does not seem to be reliable.
+ */
+_PUBLIC_ void packet_set_unreliable_select(struct packet_context *pc)
+{
+ pc->unreliable_select = true;
+}
/*
tell the caller we have an error
@@ -230,6 +247,7 @@ _PUBLIC_ void packet_recv(struct packet_context *pc)
NTSTATUS status;
size_t nread = 0;
DATA_BLOB blob;
+ bool recv_retry = false;
if (pc->processing) {
EVENT_FD_NOT_READABLE(pc->fde);
@@ -269,6 +287,8 @@ _PUBLIC_ void packet_recv(struct packet_context *pc)
return;
}
+again:
+
if (npending + pc->num_read < npending) {
packet_error(pc, NT_STATUS_INVALID_PARAMETER);
return;
@@ -308,17 +328,33 @@ _PUBLIC_ void packet_recv(struct packet_context *pc)
packet_error(pc, status);
return;
}
+ if (recv_retry && NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
+ nread = 0;
+ status = NT_STATUS_OK;
+ }
if (!NT_STATUS_IS_OK(status)) {
return;
}
- if (nread == 0) {
+ if (nread == 0 && !recv_retry) {
packet_eof(pc);
return;
}
pc->num_read += nread;
+ if (pc->unreliable_select && nread != 0) {
+ recv_retry = true;
+ status = socket_pending(pc->sock, &npending);
+ if (!NT_STATUS_IS_OK(status)) {
+ packet_error(pc, status);
+ return;
+ }
+ if (npending != 0) {
+ goto again;
+ }
+ }
+
next_partial:
if (pc->partial.length != pc->num_read) {
if (!data_blob_realloc(pc, &pc->partial, pc->num_read)) {