source: branches/samba-3.5.x/source4/lib/stream/packet.c

Last change on this file was 414, checked in by Herwig Bauernfeind, 15 years ago

Samba 3.5.0: Initial import

File size: 14.1 KB
Line 
1/*
2 Unix SMB/CIFS mplementation.
3
4 helper layer for breaking up streams into discrete requests
5
6 Copyright (C) Andrew Tridgell 2005
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
20
21*/
22
23#include "includes.h"
24#include "../lib/util/dlinklist.h"
25#include "lib/events/events.h"
26#include "lib/socket/socket.h"
27#include "lib/stream/packet.h"
28#include "libcli/raw/smb.h"
29
30struct packet_context {
31 packet_callback_fn_t callback;
32 packet_full_request_fn_t full_request;
33 packet_error_handler_fn_t error_handler;
34 DATA_BLOB partial;
35 uint32_t num_read;
36 uint32_t initial_read;
37 struct socket_context *sock;
38 struct tevent_context *ev;
39 size_t packet_size;
40 void *private_data;
41 struct tevent_fd *fde;
42 bool serialise;
43 int processing;
44 bool recv_disable;
45 bool nofree;
46
47 bool busy;
48 bool destructor_called;
49
50 bool unreliable_select;
51
52 struct send_element {
53 struct send_element *next, *prev;
54 DATA_BLOB blob;
55 size_t nsent;
56 packet_send_callback_fn_t send_callback;
57 void *send_callback_private;
58 } *send_queue;
59};
60
61/*
62 a destructor used when we are processing packets to prevent freeing of this
63 context while it is being used
64*/
65static int packet_destructor(struct packet_context *pc)
66{
67 if (pc->busy) {
68 pc->destructor_called = true;
69 /* now we refuse the talloc_free() request. The free will
70 happen again in the packet_recv() code */
71 return -1;
72 }
73
74 return 0;
75}
76
77
78/*
79 initialise a packet receiver
80*/
81_PUBLIC_ struct packet_context *packet_init(TALLOC_CTX *mem_ctx)
82{
83 struct packet_context *pc = talloc_zero(mem_ctx, struct packet_context);
84 if (pc != NULL) {
85 talloc_set_destructor(pc, packet_destructor);
86 }
87 return pc;
88}
89
90
91/*
92 set the request callback, called when a full request is ready
93*/
94_PUBLIC_ void packet_set_callback(struct packet_context *pc, packet_callback_fn_t callback)
95{
96 pc->callback = callback;
97}
98
99/*
100 set the error handler
101*/
102_PUBLIC_ void packet_set_error_handler(struct packet_context *pc, packet_error_handler_fn_t handler)
103{
104 pc->error_handler = handler;
105}
106
107/*
108 set the private pointer passed to the callback functions
109*/
110_PUBLIC_ void packet_set_private(struct packet_context *pc, void *private_data)
111{
112 pc->private_data = private_data;
113}
114
115/*
116 set the full request callback. Should return as follows:
117 NT_STATUS_OK == blob is a full request.
118 STATUS_MORE_ENTRIES == blob is not complete yet
119 any error == blob is not a valid
120*/
121_PUBLIC_ void packet_set_full_request(struct packet_context *pc, packet_full_request_fn_t callback)
122{
123 pc->full_request = callback;
124}
125
126/*
127 set a socket context to use. You must set a socket_context
128*/
129_PUBLIC_ void packet_set_socket(struct packet_context *pc, struct socket_context *sock)
130{
131 pc->sock = sock;
132}
133
134/*
135 set an event context. If this is set then the code will ensure that
136 packets arrive with separate events, by creating a immediate event
137 for any secondary packets when more than one packet is read at one
138 time on a socket. This can matter for code that relies on not
139 getting more than one packet per event
140*/
141_PUBLIC_ void packet_set_event_context(struct packet_context *pc, struct tevent_context *ev)
142{
143 pc->ev = ev;
144}
145
146/*
147 tell the packet layer the fde for the socket
148*/
149_PUBLIC_ void packet_set_fde(struct packet_context *pc, struct tevent_fd *fde)
150{
151 pc->fde = fde;
152}
153
154/*
155 tell the packet layer to serialise requests, so we don't process two
156 requests at once on one connection. You must have set the
157 event_context and fde
158*/
159_PUBLIC_ void packet_set_serialise(struct packet_context *pc)
160{
161 pc->serialise = true;
162}
163
164/*
165 tell the packet layer how much to read when starting a new packet
166 this ensures it doesn't overread
167*/
168_PUBLIC_ void packet_set_initial_read(struct packet_context *pc, uint32_t initial_read)
169{
170 pc->initial_read = initial_read;
171}
172
173/*
174 tell the packet system not to steal/free blobs given to packet_send()
175*/
176_PUBLIC_ void packet_set_nofree(struct packet_context *pc)
177{
178 pc->nofree = true;
179}
180
181/*
182 tell the packet system that select/poll/epoll on the underlying
183 socket may not be a reliable way to determine if data is available
184 for receive. This happens with underlying socket systems such as the
185 one implemented on top of GNUTLS, where there may be data in
186 encryption/compression buffers that could be received by
187 socket_recv(), while there is no data waiting at the real socket
188 level as seen by select/poll/epoll. The GNUTLS library is supposed
189 to cope with this by always leaving some data sitting in the socket
190 buffer, but it does not seem to be reliable.
191 */
192_PUBLIC_ void packet_set_unreliable_select(struct packet_context *pc)
193{
194 pc->unreliable_select = true;
195}
196
197/*
198 tell the caller we have an error
199*/
200static void packet_error(struct packet_context *pc, NTSTATUS status)
201{
202 pc->sock = NULL;
203 if (pc->error_handler) {
204 pc->error_handler(pc->private_data, status);
205 return;
206 }
207 /* default error handler is to free the callers private pointer */
208 if (!NT_STATUS_EQUAL(status, NT_STATUS_END_OF_FILE)) {
209 DEBUG(0,("packet_error on %s - %s\n",
210 talloc_get_name(pc->private_data), nt_errstr(status)));
211 }
212 talloc_free(pc->private_data);
213 return;
214}
215
216
217/*
218 tell the caller we have EOF
219*/
220static void packet_eof(struct packet_context *pc)
221{
222 packet_error(pc, NT_STATUS_END_OF_FILE);
223}
224
225
226/*
227 used to put packets on event boundaries
228*/
229static void packet_next_event(struct tevent_context *ev, struct tevent_timer *te,
230 struct timeval t, void *private_data)
231{
232 struct packet_context *pc = talloc_get_type(private_data, struct packet_context);
233 if (pc->num_read != 0 && pc->packet_size != 0 &&
234 pc->packet_size <= pc->num_read) {
235 packet_recv(pc);
236 }
237}
238
239
240/*
241 call this when the socket becomes readable to kick off the whole
242 stream parsing process
243*/
244_PUBLIC_ void packet_recv(struct packet_context *pc)
245{
246 size_t npending;
247 NTSTATUS status;
248 size_t nread = 0;
249 DATA_BLOB blob;
250 bool recv_retry = false;
251
252 if (pc->processing) {
253 EVENT_FD_NOT_READABLE(pc->fde);
254 pc->processing++;
255 return;
256 }
257
258 if (pc->recv_disable) {
259 EVENT_FD_NOT_READABLE(pc->fde);
260 return;
261 }
262
263 if (pc->packet_size != 0 && pc->num_read >= pc->packet_size) {
264 goto next_partial;
265 }
266
267 if (pc->packet_size != 0) {
268 /* we've already worked out how long this next packet is, so skip the
269 socket_pending() call */
270 npending = pc->packet_size - pc->num_read;
271 } else if (pc->initial_read != 0) {
272 npending = pc->initial_read - pc->num_read;
273 } else {
274 if (pc->sock) {
275 status = socket_pending(pc->sock, &npending);
276 } else {
277 status = NT_STATUS_CONNECTION_DISCONNECTED;
278 }
279 if (!NT_STATUS_IS_OK(status)) {
280 packet_error(pc, status);
281 return;
282 }
283 }
284
285 if (npending == 0) {
286 packet_eof(pc);
287 return;
288 }
289
290again:
291
292 if (npending + pc->num_read < npending) {
293 packet_error(pc, NT_STATUS_INVALID_PARAMETER);
294 return;
295 }
296
297 if (npending + pc->num_read < pc->num_read) {
298 packet_error(pc, NT_STATUS_INVALID_PARAMETER);
299 return;
300 }
301
302 /* possibly expand the partial packet buffer */
303 if (npending + pc->num_read > pc->partial.length) {
304 if (!data_blob_realloc(pc, &pc->partial, npending+pc->num_read)) {
305 packet_error(pc, NT_STATUS_NO_MEMORY);
306 return;
307 }
308 }
309
310 if (pc->partial.length < pc->num_read + npending) {
311 packet_error(pc, NT_STATUS_INVALID_PARAMETER);
312 return;
313 }
314
315 if ((uint8_t *)pc->partial.data + pc->num_read < (uint8_t *)pc->partial.data) {
316 packet_error(pc, NT_STATUS_INVALID_PARAMETER);
317 return;
318 }
319 if ((uint8_t *)pc->partial.data + pc->num_read + npending < (uint8_t *)pc->partial.data) {
320 packet_error(pc, NT_STATUS_INVALID_PARAMETER);
321 return;
322 }
323
324 status = socket_recv(pc->sock, pc->partial.data + pc->num_read,
325 npending, &nread);
326
327 if (NT_STATUS_IS_ERR(status)) {
328 packet_error(pc, status);
329 return;
330 }
331 if (recv_retry && NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
332 nread = 0;
333 status = NT_STATUS_OK;
334 }
335 if (!NT_STATUS_IS_OK(status)) {
336 return;
337 }
338
339 if (nread == 0 && !recv_retry) {
340 packet_eof(pc);
341 return;
342 }
343
344 pc->num_read += nread;
345
346 if (pc->unreliable_select && nread != 0) {
347 recv_retry = true;
348 status = socket_pending(pc->sock, &npending);
349 if (!NT_STATUS_IS_OK(status)) {
350 packet_error(pc, status);
351 return;
352 }
353 if (npending != 0) {
354 goto again;
355 }
356 }
357
358next_partial:
359 if (pc->partial.length != pc->num_read) {
360 if (!data_blob_realloc(pc, &pc->partial, pc->num_read)) {
361 packet_error(pc, NT_STATUS_NO_MEMORY);
362 return;
363 }
364 }
365
366 /* see if its a full request */
367 blob = pc->partial;
368 blob.length = pc->num_read;
369 status = pc->full_request(pc->private_data, blob, &pc->packet_size);
370 if (NT_STATUS_IS_ERR(status)) {
371 packet_error(pc, status);
372 return;
373 }
374 if (!NT_STATUS_IS_OK(status)) {
375 return;
376 }
377
378 if (pc->packet_size > pc->num_read) {
379 /* the caller made an error */
380 DEBUG(0,("Invalid packet_size %lu greater than num_read %lu\n",
381 (long)pc->packet_size, (long)pc->num_read));
382 packet_error(pc, NT_STATUS_INVALID_PARAMETER);
383 return;
384 }
385
386 /* it is a full request - give it to the caller */
387 blob = pc->partial;
388 blob.length = pc->num_read;
389
390 if (pc->packet_size < pc->num_read) {
391 pc->partial = data_blob_talloc(pc, blob.data + pc->packet_size,
392 pc->num_read - pc->packet_size);
393 if (pc->partial.data == NULL) {
394 packet_error(pc, NT_STATUS_NO_MEMORY);
395 return;
396 }
397 /* Trunate the blob sent to the caller to only the packet length */
398 if (!data_blob_realloc(pc, &blob, pc->packet_size)) {
399 packet_error(pc, NT_STATUS_NO_MEMORY);
400 return;
401 }
402 } else {
403 pc->partial = data_blob(NULL, 0);
404 }
405 pc->num_read -= pc->packet_size;
406 pc->packet_size = 0;
407
408 if (pc->serialise) {
409 pc->processing = 1;
410 }
411
412 pc->busy = true;
413
414 status = pc->callback(pc->private_data, blob);
415
416 pc->busy = false;
417
418 if (pc->destructor_called) {
419 talloc_free(pc);
420 return;
421 }
422
423 if (pc->processing) {
424 if (pc->processing > 1) {
425 EVENT_FD_READABLE(pc->fde);
426 }
427 pc->processing = 0;
428 }
429
430 if (!NT_STATUS_IS_OK(status)) {
431 packet_error(pc, status);
432 return;
433 }
434
435 /* Have we consumed the whole buffer yet? */
436 if (pc->partial.length == 0) {
437 return;
438 }
439
440 /* we got multiple packets in one tcp read */
441 if (pc->ev == NULL) {
442 goto next_partial;
443 }
444
445 blob = pc->partial;
446 blob.length = pc->num_read;
447
448 status = pc->full_request(pc->private_data, blob, &pc->packet_size);
449 if (NT_STATUS_IS_ERR(status)) {
450 packet_error(pc, status);
451 return;
452 }
453
454 if (!NT_STATUS_IS_OK(status)) {
455 return;
456 }
457
458 event_add_timed(pc->ev, pc, timeval_zero(), packet_next_event, pc);
459}
460
461
462/*
463 temporarily disable receiving
464*/
465_PUBLIC_ void packet_recv_disable(struct packet_context *pc)
466{
467 EVENT_FD_NOT_READABLE(pc->fde);
468 pc->recv_disable = true;
469}
470
471/*
472 re-enable receiving
473*/
474_PUBLIC_ void packet_recv_enable(struct packet_context *pc)
475{
476 EVENT_FD_READABLE(pc->fde);
477 pc->recv_disable = false;
478 if (pc->num_read != 0 && pc->packet_size >= pc->num_read) {
479 event_add_timed(pc->ev, pc, timeval_zero(), packet_next_event, pc);
480 }
481}
482
483/*
484 trigger a run of the send queue
485*/
486_PUBLIC_ void packet_queue_run(struct packet_context *pc)
487{
488 while (pc->send_queue) {
489 struct send_element *el = pc->send_queue;
490 NTSTATUS status;
491 size_t nwritten;
492 DATA_BLOB blob = data_blob_const(el->blob.data + el->nsent,
493 el->blob.length - el->nsent);
494
495 status = socket_send(pc->sock, &blob, &nwritten);
496
497 if (NT_STATUS_IS_ERR(status)) {
498 packet_error(pc, status);
499 return;
500 }
501 if (!NT_STATUS_IS_OK(status)) {
502 return;
503 }
504 el->nsent += nwritten;
505 if (el->nsent == el->blob.length) {
506 DLIST_REMOVE(pc->send_queue, el);
507 if (el->send_callback) {
508 pc->busy = true;
509 el->send_callback(el->send_callback_private);
510 pc->busy = false;
511 if (pc->destructor_called) {
512 talloc_free(pc);
513 return;
514 }
515 }
516 talloc_free(el);
517 }
518 }
519
520 /* we're out of requests to send, so don't wait for write
521 events any more */
522 EVENT_FD_NOT_WRITEABLE(pc->fde);
523}
524
525/*
526 put a packet in the send queue. When the packet is actually sent,
527 call send_callback.
528
529 Useful for operations that must occour after sending a message, such
530 as the switch to SASL encryption after as sucessful LDAP bind relpy.
531*/
532_PUBLIC_ NTSTATUS packet_send_callback(struct packet_context *pc, DATA_BLOB blob,
533 packet_send_callback_fn_t send_callback,
534 void *private_data)
535{
536 struct send_element *el;
537 el = talloc(pc, struct send_element);
538 NT_STATUS_HAVE_NO_MEMORY(el);
539
540 DLIST_ADD_END(pc->send_queue, el, struct send_element *);
541 el->blob = blob;
542 el->nsent = 0;
543 el->send_callback = send_callback;
544 el->send_callback_private = private_data;
545
546 /* if we aren't going to free the packet then we must reference it
547 to ensure it doesn't disappear before going out */
548 if (pc->nofree) {
549 if (!talloc_reference(el, blob.data)) {
550 return NT_STATUS_NO_MEMORY;
551 }
552 } else {
553 talloc_steal(el, blob.data);
554 }
555
556 if (private_data && !talloc_reference(el, private_data)) {
557 return NT_STATUS_NO_MEMORY;
558 }
559
560 EVENT_FD_WRITEABLE(pc->fde);
561
562 return NT_STATUS_OK;
563}
564
565/*
566 put a packet in the send queue
567*/
568_PUBLIC_ NTSTATUS packet_send(struct packet_context *pc, DATA_BLOB blob)
569{
570 return packet_send_callback(pc, blob, NULL, NULL);
571}
572
573
574/*
575 a full request checker for NBT formatted packets (first 3 bytes are length)
576*/
577_PUBLIC_ NTSTATUS packet_full_request_nbt(void *private_data, DATA_BLOB blob, size_t *size)
578{
579 if (blob.length < 4) {
580 return STATUS_MORE_ENTRIES;
581 }
582 *size = 4 + smb_len(blob.data);
583 if (*size > blob.length) {
584 return STATUS_MORE_ENTRIES;
585 }
586 return NT_STATUS_OK;
587}
588
589
590/*
591 work out if a packet is complete for protocols that use a 32 bit network byte
592 order length
593*/
594_PUBLIC_ NTSTATUS packet_full_request_u32(void *private_data, DATA_BLOB blob, size_t *size)
595{
596 if (blob.length < 4) {
597 return STATUS_MORE_ENTRIES;
598 }
599 *size = 4 + RIVAL(blob.data, 0);
600 if (*size > blob.length) {
601 return STATUS_MORE_ENTRIES;
602 }
603 return NT_STATUS_OK;
604}
Note: See TracBrowser for help on using the repository browser.