2 Unix SMB/CIFS mplementation.
4 helper layer for breaking up streams into discrete requests
6 Copyright (C) Andrew Tridgell 2005
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 2 of the License, or
11 (at your option) any later version.
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.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 #include "lib/util/dlinklist.h"
26 #include "lib/events/events.h"
27 #include "lib/socket/socket.h"
28 #include "lib/stream/packet.h"
29 #include "libcli/raw/smb.h"
31 struct packet_context
{
32 packet_callback_fn_t callback
;
33 packet_full_request_fn_t full_request
;
34 packet_error_handler_fn_t error_handler
;
37 uint32_t initial_read
;
38 struct socket_context
*sock
;
39 struct event_context
*ev
;
49 BOOL destructor_called
;
52 struct send_element
*next
, *prev
;
55 packet_send_callback_fn_t send_callback
;
56 void *send_callback_private
;
61 a destructor used when we are processing packets to prevent freeing of this
62 context while it is being used
64 static int packet_destructor(struct packet_context
*pc
)
67 pc
->destructor_called
= True
;
68 /* now we refuse the talloc_free() request. The free will
69 happen again in the packet_recv() code */
78 initialise a packet receiver
80 _PUBLIC_
struct packet_context
*packet_init(TALLOC_CTX
*mem_ctx
)
82 struct packet_context
*pc
= talloc_zero(mem_ctx
, struct packet_context
);
84 talloc_set_destructor(pc
, packet_destructor
);
91 set the request callback, called when a full request is ready
93 _PUBLIC_
void packet_set_callback(struct packet_context
*pc
, packet_callback_fn_t callback
)
95 pc
->callback
= callback
;
101 _PUBLIC_
void packet_set_error_handler(struct packet_context
*pc
, packet_error_handler_fn_t handler
)
103 pc
->error_handler
= handler
;
107 set the private pointer passed to the callback functions
109 _PUBLIC_
void packet_set_private(struct packet_context
*pc
, void *private)
111 pc
->private = private;
115 set the full request callback. Should return as follows:
116 NT_STATUS_OK == blob is a full request.
117 STATUS_MORE_ENTRIES == blob is not complete yet
118 any error == blob is not a valid
120 _PUBLIC_
void packet_set_full_request(struct packet_context
*pc
, packet_full_request_fn_t callback
)
122 pc
->full_request
= callback
;
126 set a socket context to use. You must set a socket_context
128 _PUBLIC_
void packet_set_socket(struct packet_context
*pc
, struct socket_context
*sock
)
134 set an event context. If this is set then the code will ensure that
135 packets arrive with separate events, by creating a immediate event
136 for any secondary packets when more than one packet is read at one
137 time on a socket. This can matter for code that relies on not
138 getting more than one packet per event
140 _PUBLIC_
void packet_set_event_context(struct packet_context
*pc
, struct event_context
*ev
)
146 tell the packet layer the fde for the socket
148 _PUBLIC_
void packet_set_fde(struct packet_context
*pc
, struct fd_event
*fde
)
154 tell the packet layer to serialise requests, so we don't process two
155 requests at once on one connection. You must have set the
156 event_context and fde
158 _PUBLIC_
void packet_set_serialise(struct packet_context
*pc
)
160 pc
->serialise
= True
;
164 tell the packet layer how much to read when starting a new packet
165 this ensures it doesn't overread
167 _PUBLIC_
void packet_set_initial_read(struct packet_context
*pc
, uint32_t initial_read
)
169 pc
->initial_read
= initial_read
;
173 tell the packet system not to steal/free blobs given to packet_send()
175 _PUBLIC_
void packet_set_nofree(struct packet_context
*pc
)
182 tell the caller we have an error
184 static void packet_error(struct packet_context
*pc
, NTSTATUS status
)
187 if (pc
->error_handler
) {
188 pc
->error_handler(pc
->private, status
);
191 /* default error handler is to free the callers private pointer */
192 if (!NT_STATUS_EQUAL(status
, NT_STATUS_END_OF_FILE
)) {
193 DEBUG(0,("packet_error on %s - %s\n",
194 talloc_get_name(pc
->private), nt_errstr(status
)));
196 talloc_free(pc
->private);
202 tell the caller we have EOF
204 static void packet_eof(struct packet_context
*pc
)
206 packet_error(pc
, NT_STATUS_END_OF_FILE
);
211 used to put packets on event boundaries
213 static void packet_next_event(struct event_context
*ev
, struct timed_event
*te
,
214 struct timeval t
, void *private)
216 struct packet_context
*pc
= talloc_get_type(private, struct packet_context
);
217 if (pc
->num_read
!= 0 && pc
->packet_size
!= 0 &&
218 pc
->packet_size
<= pc
->num_read
) {
225 call this when the socket becomes readable to kick off the whole
226 stream parsing process
228 _PUBLIC_
void packet_recv(struct packet_context
*pc
)
235 if (pc
->processing
) {
236 EVENT_FD_NOT_READABLE(pc
->fde
);
241 if (pc
->recv_disable
) {
242 EVENT_FD_NOT_READABLE(pc
->fde
);
246 if (pc
->packet_size
!= 0 && pc
->num_read
>= pc
->packet_size
) {
250 if (pc
->packet_size
!= 0) {
251 /* we've already worked out how long this next packet is, so skip the
252 socket_pending() call */
253 npending
= pc
->packet_size
- pc
->num_read
;
254 } else if (pc
->initial_read
!= 0) {
255 npending
= pc
->initial_read
- pc
->num_read
;
258 status
= socket_pending(pc
->sock
, &npending
);
260 status
= NT_STATUS_CONNECTION_DISCONNECTED
;
262 if (!NT_STATUS_IS_OK(status
)) {
263 packet_error(pc
, status
);
273 if (npending
+ pc
->num_read
< npending
) {
274 packet_error(pc
, NT_STATUS_INVALID_PARAMETER
);
278 if (npending
+ pc
->num_read
< pc
->num_read
) {
279 packet_error(pc
, NT_STATUS_INVALID_PARAMETER
);
283 /* possibly expand the partial packet buffer */
284 if (npending
+ pc
->num_read
> pc
->partial
.length
) {
285 status
= data_blob_realloc(pc
, &pc
->partial
, npending
+pc
->num_read
);
286 if (!NT_STATUS_IS_OK(status
)) {
287 packet_error(pc
, status
);
292 if (pc
->partial
.length
< pc
->num_read
+ npending
) {
293 packet_error(pc
, NT_STATUS_INVALID_PARAMETER
);
297 if ((uint8_t *)pc
->partial
.data
+ pc
->num_read
< (uint8_t *)pc
->partial
.data
) {
298 packet_error(pc
, NT_STATUS_INVALID_PARAMETER
);
301 if ((uint8_t *)pc
->partial
.data
+ pc
->num_read
+ npending
< (uint8_t *)pc
->partial
.data
) {
302 packet_error(pc
, NT_STATUS_INVALID_PARAMETER
);
306 status
= socket_recv(pc
->sock
, pc
->partial
.data
+ pc
->num_read
,
309 if (NT_STATUS_IS_ERR(status
)) {
310 packet_error(pc
, status
);
313 if (!NT_STATUS_IS_OK(status
)) {
322 pc
->num_read
+= nread
;
325 if (pc
->partial
.length
!= pc
->num_read
) {
326 status
= data_blob_realloc(pc
, &pc
->partial
, pc
->num_read
);
327 if (!NT_STATUS_IS_OK(status
)) {
328 packet_error(pc
, status
);
333 /* see if its a full request */
335 blob
.length
= pc
->num_read
;
336 status
= pc
->full_request(pc
->private, blob
, &pc
->packet_size
);
337 if (NT_STATUS_IS_ERR(status
)) {
338 packet_error(pc
, status
);
341 if (!NT_STATUS_IS_OK(status
)) {
345 if (pc
->packet_size
> pc
->num_read
) {
346 /* the caller made an error */
347 DEBUG(0,("Invalid packet_size %lu greater than num_read %lu\n",
348 (long)pc
->packet_size
, (long)pc
->num_read
));
349 packet_error(pc
, NT_STATUS_INVALID_PARAMETER
);
353 /* it is a full request - give it to the caller */
355 blob
.length
= pc
->num_read
;
357 if (pc
->packet_size
< pc
->num_read
) {
358 pc
->partial
= data_blob_talloc(pc
, blob
.data
+ pc
->packet_size
,
359 pc
->num_read
- pc
->packet_size
);
360 if (pc
->partial
.data
== NULL
) {
361 packet_error(pc
, NT_STATUS_NO_MEMORY
);
364 /* Trunate the blob sent to the caller to only the packet length */
365 status
= data_blob_realloc(pc
, &blob
, pc
->packet_size
);
366 if (!NT_STATUS_IS_OK(status
)) {
367 packet_error(pc
, status
);
371 pc
->partial
= data_blob(NULL
, 0);
373 pc
->num_read
-= pc
->packet_size
;
382 status
= pc
->callback(pc
->private, blob
);
386 if (pc
->destructor_called
) {
391 if (pc
->processing
) {
392 if (pc
->processing
> 1) {
393 EVENT_FD_READABLE(pc
->fde
);
398 if (!NT_STATUS_IS_OK(status
)) {
399 packet_error(pc
, status
);
403 /* Have we consumed the whole buffer yet? */
404 if (pc
->partial
.length
== 0) {
408 /* we got multiple packets in one tcp read */
409 if (pc
->ev
== NULL
) {
414 blob
.length
= pc
->num_read
;
416 status
= pc
->full_request(pc
->private, blob
, &pc
->packet_size
);
417 if (NT_STATUS_IS_ERR(status
)) {
418 packet_error(pc
, status
);
422 if (!NT_STATUS_IS_OK(status
)) {
426 event_add_timed(pc
->ev
, pc
, timeval_zero(), packet_next_event
, pc
);
431 temporarily disable receiving
433 _PUBLIC_
void packet_recv_disable(struct packet_context
*pc
)
435 EVENT_FD_NOT_READABLE(pc
->fde
);
436 pc
->recv_disable
= True
;
442 _PUBLIC_
void packet_recv_enable(struct packet_context
*pc
)
444 EVENT_FD_READABLE(pc
->fde
);
445 pc
->recv_disable
= False
;
446 if (pc
->num_read
!= 0 && pc
->packet_size
>= pc
->num_read
) {
447 event_add_timed(pc
->ev
, pc
, timeval_zero(), packet_next_event
, pc
);
452 trigger a run of the send queue
454 _PUBLIC_
void packet_queue_run(struct packet_context
*pc
)
456 while (pc
->send_queue
) {
457 struct send_element
*el
= pc
->send_queue
;
460 DATA_BLOB blob
= data_blob_const(el
->blob
.data
+ el
->nsent
,
461 el
->blob
.length
- el
->nsent
);
463 status
= socket_send(pc
->sock
, &blob
, &nwritten
);
465 if (NT_STATUS_IS_ERR(status
)) {
466 packet_error(pc
, status
);
469 if (!NT_STATUS_IS_OK(status
)) {
472 el
->nsent
+= nwritten
;
473 if (el
->nsent
== el
->blob
.length
) {
474 DLIST_REMOVE(pc
->send_queue
, el
);
475 if (el
->send_callback
) {
476 el
->send_callback(el
->send_callback_private
);
482 /* we're out of requests to send, so don't wait for write
484 EVENT_FD_NOT_WRITEABLE(pc
->fde
);
488 put a packet in the send queue. When the packet is actually sent,
491 Useful for operations that must occour after sending a message, such
492 as the switch to SASL encryption after as sucessful LDAP bind relpy.
494 _PUBLIC_ NTSTATUS
packet_send_callback(struct packet_context
*pc
, DATA_BLOB blob
,
495 packet_send_callback_fn_t send_callback
,
498 struct send_element
*el
;
499 el
= talloc(pc
, struct send_element
);
500 NT_STATUS_HAVE_NO_MEMORY(el
);
502 DLIST_ADD_END(pc
->send_queue
, el
, struct send_element
*);
505 el
->send_callback
= send_callback
;
506 el
->send_callback_private
= private;
508 /* if we aren't going to free the packet then we must reference it
509 to ensure it doesn't disappear before going out */
511 if (!talloc_reference(el
, blob
.data
)) {
512 return NT_STATUS_NO_MEMORY
;
515 talloc_steal(el
, blob
.data
);
518 if (private && !talloc_reference(el
, private)) {
519 return NT_STATUS_NO_MEMORY
;
522 EVENT_FD_WRITEABLE(pc
->fde
);
528 put a packet in the send queue
530 _PUBLIC_ NTSTATUS
packet_send(struct packet_context
*pc
, DATA_BLOB blob
)
532 return packet_send_callback(pc
, blob
, NULL
, NULL
);
537 a full request checker for NBT formatted packets (first 3 bytes are length)
539 _PUBLIC_ NTSTATUS
packet_full_request_nbt(void *private, DATA_BLOB blob
, size_t *size
)
541 if (blob
.length
< 4) {
542 return STATUS_MORE_ENTRIES
;
544 *size
= 4 + smb_len(blob
.data
);
545 if (*size
> blob
.length
) {
546 return STATUS_MORE_ENTRIES
;
553 work out if a packet is complete for protocols that use a 32 bit network byte
556 _PUBLIC_ NTSTATUS
packet_full_request_u32(void *private, DATA_BLOB blob
, size_t *size
)
558 if (blob
.length
< 4) {
559 return STATUS_MORE_ENTRIES
;
561 *size
= 4 + RIVAL(blob
.data
, 0);
562 if (*size
> blob
.length
) {
563 return STATUS_MORE_ENTRIES
;