2 Unix SMB/CIFS implementation.
3 handle unexpected packets
4 Copyright (C) Andrew Tridgell 2000
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "lib/async_req/async_sock.h"
24 static struct tdb_wrap
*tdbd
= NULL
;
26 /* the key type used in the unexpected packet database */
27 struct unexpected_key
{
28 enum packet_type packet_type
;
33 struct pending_unexpected
{
34 struct pending_unexpected
*prev
, *next
;
35 enum packet_type packet_type
;
40 static struct pending_unexpected
*pu_list
;
42 /****************************************************************************
43 This function is called when nmbd has received an unexpected packet.
44 It checks against the list of outstanding packet transaction id's
45 to see if it should be stored in the unexpected.tdb.
46 **************************************************************************/
48 static struct pending_unexpected
*find_unexpected_packet(struct packet_struct
*p
)
50 struct pending_unexpected
*pu
;
56 for (pu
= pu_list
; pu
; pu
= pu
->next
) {
57 if (pu
->packet_type
== p
->packet_type
) {
58 int id
= (p
->packet_type
== DGRAM_PACKET
) ?
59 p
->packet
.dgram
.header
.dgm_id
:
60 p
->packet
.nmb
.header
.name_trn_id
;
62 DEBUG(10,("find_unexpected_packet: found packet "
63 "with id = %d\n", pu
->id
));
73 /****************************************************************************
74 This function is called when nmbd has been given a packet to send out.
75 It stores a list of outstanding packet transaction id's and the timeout
76 when they should be removed.
77 **************************************************************************/
79 bool store_outstanding_send_packet(struct packet_struct
*p
)
81 struct pending_unexpected
*pu
= NULL
;
87 pu
= find_unexpected_packet(p
);
89 /* This is a resend, and we haven't received a
90 reply yet ! Ignore it. */
94 pu
= SMB_MALLOC_P(struct pending_unexpected
);
100 pu
->packet_type
= p
->packet_type
;
101 pu
->id
= (p
->packet_type
== DGRAM_PACKET
) ?
102 p
->packet
.dgram
.header
.dgm_id
:
103 p
->packet
.nmb
.header
.name_trn_id
;
104 pu
->timeout
= time(NULL
) + 15;
106 DLIST_ADD_END(pu_list
, pu
, struct pending_unexpected
*);
108 DEBUG(10,("store_outstanding_unexpected_packet: storing packet "
109 "with id = %d\n", pu
->id
));
114 /****************************************************************************
115 Return true if this is a reply to a packet we were requested to send.
116 **************************************************************************/
118 bool is_requested_send_packet(struct packet_struct
*p
)
120 return (find_unexpected_packet(p
) != NULL
);
123 /****************************************************************************
124 This function is called when nmbd has received an unexpected packet.
125 It checks against the list of outstanding packet transaction id's
126 to see if it should be stored in the unexpected.tdb. Don't store if
128 **************************************************************************/
130 static bool should_store_unexpected_packet(struct packet_struct
*p
)
132 struct pending_unexpected
*pu
= find_unexpected_packet(p
);
138 /* Remove the outstanding entry. */
139 DLIST_REMOVE(pu_list
, pu
);
144 /****************************************************************************
145 All unexpected packets are passed in here, to be stored in a unexpected
146 packet database. This allows nmblookup and other tools to receive packets
147 erroneously sent to the wrong port by broken MS systems.
148 **************************************************************************/
150 void unexpected_packet(struct packet_struct
*p
)
154 struct unexpected_key key
;
159 if (!should_store_unexpected_packet(p
)) {
160 DEBUG(10,("Not storing unexpected packet\n"));
164 DEBUG(10,("unexpected_packet: storing packet\n"));
167 tdbd
= tdb_wrap_open(NULL
, lock_path("unexpected.tdb"), 0,
168 TDB_CLEAR_IF_FIRST
|TDB_DEFAULT
|TDB_INCOMPATIBLE_HASH
,
169 O_RDWR
| O_CREAT
, 0644);
171 DEBUG(0,("Failed to open unexpected.tdb\n"));
176 memset(buf
,'\0',sizeof(buf
));
178 /* Encode the ip addr and port. */
179 enc_ip
= ntohl(p
->ip
.s_addr
);
181 SSVAL(buf
,4,p
->port
);
183 len
= build_packet(&buf
[6], sizeof(buf
)-6, p
) + 6;
185 ZERO_STRUCT(key
); /* needed for potential alignment */
187 key
.packet_type
= p
->packet_type
;
188 key
.timestamp
= p
->timestamp
;
191 kbuf
.dptr
= (uint8_t *)&key
;
192 kbuf
.dsize
= sizeof(key
);
193 dbuf
.dptr
= (uint8_t *)buf
;
196 tdb_store(tdbd
->tdb
, kbuf
, dbuf
, TDB_REPLACE
);
202 /****************************************************************************
203 Delete the record if it is too old.
204 **************************************************************************/
206 static int traverse_fn(TDB_CONTEXT
*ttdb
, TDB_DATA kbuf
, TDB_DATA dbuf
, void *state
)
208 struct unexpected_key key
;
210 if (kbuf
.dsize
!= sizeof(key
)) {
211 tdb_delete(ttdb
, kbuf
);
214 memcpy(&key
, kbuf
.dptr
, sizeof(key
));
216 if (lastt
- key
.timestamp
> NMBD_UNEXPECTED_TIMEOUT
) {
217 tdb_delete(ttdb
, kbuf
);
224 /****************************************************************************
225 Delete all old unexpected packets.
226 **************************************************************************/
228 void clear_unexpected(time_t t
)
230 struct pending_unexpected
*pu
, *pu_next
;
232 for (pu
= pu_list
; pu
; pu
= pu_next
) {
234 if (pu
->timeout
< t
) {
235 DLIST_REMOVE(pu_list
, pu
);
242 if ((lastt
!= 0) && (t
< lastt
+ NMBD_UNEXPECTED_TIMEOUT
))
247 tdb_traverse(tdbd
->tdb
, traverse_fn
, NULL
);
250 struct receive_unexpected_state
{
251 struct packet_struct
*matched_packet
;
253 enum packet_type match_type
;
254 const char *match_name
;
257 /****************************************************************************
258 tdb traversal fn to find a matching 137 packet.
259 **************************************************************************/
261 static int traverse_match(TDB_CONTEXT
*ttdb
, TDB_DATA kbuf
, TDB_DATA dbuf
,
264 struct receive_unexpected_state
*state
=
265 (struct receive_unexpected_state
*)private_data
;
266 struct unexpected_key key
;
270 struct packet_struct
*p
;
272 if (kbuf
.dsize
!= sizeof(key
)) {
276 memcpy(&key
, kbuf
.dptr
, sizeof(key
));
278 if (key
.packet_type
!= state
->match_type
) return 0;
280 if (dbuf
.dsize
< 6) {
284 /* Decode the ip addr and port. */
285 enc_ip
= IVAL(dbuf
.dptr
,0);
286 ip
.s_addr
= htonl(enc_ip
);
287 port
= SVAL(dbuf
.dptr
,4);
289 p
= parse_packet((char *)&dbuf
.dptr
[6],
297 if ((state
->match_type
== NMB_PACKET
&&
298 p
->packet
.nmb
.header
.name_trn_id
== state
->match_id
) ||
299 (state
->match_type
== DGRAM_PACKET
&&
300 match_mailslot_name(p
, state
->match_name
) &&
301 p
->packet
.dgram
.header
.dgm_id
== state
->match_id
)) {
302 state
->matched_packet
= p
;
303 tdb_delete(ttdb
, kbuf
);
312 /****************************************************************************
313 Check for a particular packet in the unexpected packet queue.
314 **************************************************************************/
316 struct packet_struct
*receive_unexpected(enum packet_type packet_type
, int id
,
317 const char *mailslot_name
)
319 struct tdb_wrap
*tdb2
;
320 struct receive_unexpected_state state
;
322 tdb2
= tdb_wrap_open(talloc_tos(), lock_path("unexpected.tdb"), 0, 0,
324 if (!tdb2
) return NULL
;
326 state
.matched_packet
= NULL
;
328 state
.match_type
= packet_type
;
329 state
.match_name
= mailslot_name
;
331 tdb_traverse(tdb2
->tdb
, traverse_match
, &state
);
335 return state
.matched_packet
;
338 static const char *nmbd_socket_dir(void)
340 return lp_parm_const_string(-1, "nmbd", "socket dir", "/tmp/.nmbd");
343 struct nb_packet_query
{
344 enum packet_type type
;
345 size_t mailslot_namelen
;
349 struct nb_packet_client
;
351 struct nb_packet_server
{
352 struct tevent_context
*ev
;
356 struct nb_packet_client
*clients
;
359 struct nb_packet_client
{
360 struct nb_packet_client
*prev
, *next
;
361 struct nb_packet_server
*server
;
363 enum packet_type type
;
368 struct tevent_req
*read_req
;
369 struct tevent_queue
*out_queue
;
372 static int nb_packet_server_destructor(struct nb_packet_server
*s
);
373 static void nb_packet_server_listener(struct tevent_context
*ev
,
374 struct tevent_fd
*fde
,
378 NTSTATUS
nb_packet_server_create(TALLOC_CTX
*mem_ctx
,
379 struct tevent_context
*ev
,
381 struct nb_packet_server
**presult
)
383 struct nb_packet_server
*result
;
384 struct tevent_fd
*fde
;
387 result
= TALLOC_ZERO_P(mem_ctx
, struct nb_packet_server
);
388 if (result
== NULL
) {
389 status
= NT_STATUS_NO_MEMORY
;
393 result
->max_clients
= max_clients
;
395 result
->listen_sock
= create_pipe_sock(
396 nmbd_socket_dir(), "unexpected", 0755);
397 if (result
->listen_sock
== -1) {
398 status
= map_nt_error_from_unix(errno
);
401 talloc_set_destructor(result
, nb_packet_server_destructor
);
403 fde
= tevent_add_fd(ev
, result
, result
->listen_sock
, TEVENT_FD_READ
,
404 nb_packet_server_listener
, result
);
406 status
= NT_STATUS_NO_MEMORY
;
417 static int nb_packet_server_destructor(struct nb_packet_server
*s
)
419 if (s
->listen_sock
!= -1) {
420 close(s
->listen_sock
);
426 static int nb_packet_client_destructor(struct nb_packet_client
*c
);
427 static ssize_t
nb_packet_client_more(uint8_t *buf
, size_t buflen
,
429 static void nb_packet_got_query(struct tevent_req
*req
);
430 static void nb_packet_client_read_done(struct tevent_req
*req
);
432 static void nb_packet_server_listener(struct tevent_context
*ev
,
433 struct tevent_fd
*fde
,
437 struct nb_packet_server
*server
= talloc_get_type_abort(
438 private_data
, struct nb_packet_server
);
439 struct nb_packet_client
*client
;
440 struct tevent_req
*req
;
441 struct sockaddr_un sunaddr
;
445 len
= sizeof(sunaddr
);
447 sock
= accept(server
->listen_sock
, (struct sockaddr
*)(void *)&sunaddr
,
452 DEBUG(6,("accepted socket %d\n", sock
));
454 client
= TALLOC_ZERO_P(server
, struct nb_packet_client
);
455 if (client
== NULL
) {
456 DEBUG(10, ("talloc failed\n"));
461 client
->server
= server
;
462 talloc_set_destructor(client
, nb_packet_client_destructor
);
464 client
->out_queue
= tevent_queue_create(
465 client
, "unexpected packet output");
466 if (client
->out_queue
== NULL
) {
467 DEBUG(10, ("tevent_queue_create failed\n"));
472 req
= read_packet_send(client
, ev
, client
->sock
,
473 sizeof(struct nb_packet_query
),
474 nb_packet_client_more
, NULL
);
476 DEBUG(10, ("read_packet_send failed\n"));
480 tevent_req_set_callback(req
, nb_packet_got_query
, client
);
482 DLIST_ADD(server
->clients
, client
);
483 server
->num_clients
+= 1;
485 if (server
->num_clients
> server
->max_clients
) {
486 DEBUG(10, ("Too many clients, dropping oldest\n"));
489 * no TALLOC_FREE here, don't mess with the list structs
491 talloc_free(server
->clients
->prev
);
495 static ssize_t
nb_packet_client_more(uint8_t *buf
, size_t buflen
,
498 struct nb_packet_query q
;
499 if (buflen
> sizeof(struct nb_packet_query
)) {
502 /* Take care of alignment */
503 memcpy(&q
, buf
, sizeof(q
));
504 if (q
.mailslot_namelen
> 1024) {
505 DEBUG(10, ("Got invalid mailslot namelen %d\n",
506 (int)q
.mailslot_namelen
));
509 return q
.mailslot_namelen
;
512 static int nb_packet_client_destructor(struct nb_packet_client
*c
)
518 DLIST_REMOVE(c
->server
->clients
, c
);
519 c
->server
->num_clients
-= 1;
523 static void nb_packet_got_query(struct tevent_req
*req
)
525 struct nb_packet_client
*client
= tevent_req_callback_data(
526 req
, struct nb_packet_client
);
527 struct nb_packet_query q
;
529 ssize_t nread
, nwritten
;
533 nread
= read_packet_recv(req
, talloc_tos(), &buf
, &err
);
535 if (nread
< sizeof(struct nb_packet_query
)) {
536 DEBUG(10, ("read_packet_recv returned %d (%s)\n",
538 (nread
== -1) ? strerror(err
) : "wrong length"));
543 /* Take care of alignment */
544 memcpy(&q
, buf
, sizeof(q
));
546 if (nread
!= sizeof(struct nb_packet_query
) + q
.mailslot_namelen
) {
547 DEBUG(10, ("nb_packet_got_query: Invalid mailslot namelength\n"));
552 client
->trn_id
= q
.trn_id
;
553 client
->type
= q
.type
;
554 if (q
.mailslot_namelen
> 0) {
555 client
->mailslot_name
= talloc_strndup(
556 client
, (char *)buf
+ sizeof(q
),
558 if (client
->mailslot_name
== NULL
) {
565 * Yes, this is a blocking write of 1 byte into a unix
566 * domain socket that has never been written to. Highly
567 * unlikely that this actually blocks.
570 nwritten
= sys_write(client
->sock
, &c
, sizeof(c
));
571 if (nwritten
!= sizeof(c
)) {
572 DEBUG(10, ("Could not write success indicator to client: %s\n",
578 client
->read_req
= read_packet_send(client
, client
->server
->ev
,
579 client
->sock
, 1, NULL
, NULL
);
580 if (client
->read_req
== NULL
) {
581 DEBUG(10, ("Could not activate reader for client exit "
586 tevent_req_set_callback(client
->read_req
, nb_packet_client_read_done
,
590 static void nb_packet_client_read_done(struct tevent_req
*req
)
592 struct nb_packet_client
*client
= tevent_req_callback_data(
593 req
, struct nb_packet_client
);
598 nread
= read_packet_recv(req
, talloc_tos(), &buf
, &err
);
601 DEBUG(10, ("Protocol error, received data on write-only "
602 "unexpected socket: 0x%2.2x\n", (*buf
)));
607 static void nb_packet_client_send(struct nb_packet_client
*client
,
608 struct packet_struct
*p
);
610 void nb_packet_dispatch(struct nb_packet_server
*server
,
611 struct packet_struct
*p
)
613 struct nb_packet_client
*c
;
616 switch (p
->packet_type
) {
618 trn_id
= p
->packet
.nmb
.header
.name_trn_id
;
621 trn_id
= p
->packet
.dgram
.header
.dgm_id
;
624 DEBUG(10, ("Got invalid packet type %d\n",
625 (int)p
->packet_type
));
628 for (c
= server
->clients
; c
!= NULL
; c
= c
->next
) {
630 if (c
->type
!= p
->packet_type
) {
631 DEBUG(10, ("client expects packet %d, got %d\n",
632 c
->type
, p
->packet_type
));
636 if (p
->packet_type
== NMB_PACKET
) {
638 * See if the client specified transaction
639 * ID. Filter if it did.
641 if ((c
->trn_id
!= -1) &&
642 (c
->trn_id
!= trn_id
)) {
643 DEBUG(10, ("client expects trn %d, got %d\n",
649 * See if the client specified a mailslot
650 * name. Filter if it did.
652 if ((c
->mailslot_name
!= NULL
) &&
653 !match_mailslot_name(p
, c
->mailslot_name
)) {
657 nb_packet_client_send(c
, p
);
661 struct nb_packet_client_header
{
663 enum packet_type type
;
669 struct nb_packet_client_state
{
670 struct nb_packet_client
*client
;
672 struct nb_packet_client_header hdr
;
676 static void nb_packet_client_send_done(struct tevent_req
*req
);
678 static void nb_packet_client_send(struct nb_packet_client
*client
,
679 struct packet_struct
*p
)
681 struct nb_packet_client_state
*state
;
682 struct tevent_req
*req
;
684 if (tevent_queue_length(client
->out_queue
) > 10) {
686 * Skip clients that don't listen anyway, some form of DoS
692 state
= TALLOC_ZERO_P(client
, struct nb_packet_client_state
);
694 DEBUG(10, ("talloc failed\n"));
698 state
->client
= client
;
700 state
->hdr
.ip
= p
->ip
;
701 state
->hdr
.port
= p
->port
;
702 state
->hdr
.timestamp
= p
->timestamp
;
703 state
->hdr
.type
= p
->packet_type
;
704 state
->hdr
.len
= build_packet(state
->buf
, sizeof(state
->buf
), p
);
706 state
->iov
[0].iov_base
= &state
->hdr
;
707 state
->iov
[0].iov_len
= sizeof(state
->hdr
);
708 state
->iov
[1].iov_base
= state
->buf
;
709 state
->iov
[1].iov_len
= state
->hdr
.len
;
711 TALLOC_FREE(client
->read_req
);
713 req
= writev_send(client
, client
->server
->ev
, client
->out_queue
,
714 client
->sock
, true, state
->iov
, 2);
716 DEBUG(10, ("writev_send failed\n"));
719 tevent_req_set_callback(req
, nb_packet_client_send_done
, state
);
722 static void nb_packet_client_send_done(struct tevent_req
*req
)
724 struct nb_packet_client_state
*state
= tevent_req_callback_data(
725 req
, struct nb_packet_client_state
);
726 struct nb_packet_client
*client
= state
->client
;
730 nwritten
= writev_recv(req
, &err
);
735 if (nwritten
== -1) {
736 DEBUG(10, ("writev failed: %s\n", strerror(err
)));
740 if (tevent_queue_length(client
->out_queue
) == 0) {
741 client
->read_req
= read_packet_send(client
, client
->server
->ev
,
744 if (client
->read_req
== NULL
) {
745 DEBUG(10, ("Could not activate reader for client exit "
750 tevent_req_set_callback(client
->read_req
,
751 nb_packet_client_read_done
,
756 struct nb_packet_reader
{
760 struct nb_packet_reader_state
{
761 struct tevent_context
*ev
;
762 struct sockaddr_un addr
;
763 struct nb_packet_query query
;
764 const char *mailslot_name
;
767 struct nb_packet_reader
*reader
;
770 static int nb_packet_reader_destructor(struct nb_packet_reader
*r
);
771 static void nb_packet_reader_connected(struct tevent_req
*subreq
);
772 static void nb_packet_reader_sent_query(struct tevent_req
*subreq
);
773 static void nb_packet_reader_got_ack(struct tevent_req
*subreq
);
775 struct tevent_req
*nb_packet_reader_send(TALLOC_CTX
*mem_ctx
,
776 struct tevent_context
*ev
,
777 enum packet_type type
,
779 const char *mailslot_name
)
781 struct tevent_req
*req
, *subreq
;
782 struct nb_packet_reader_state
*state
;
785 req
= tevent_req_create(mem_ctx
, &state
,
786 struct nb_packet_reader_state
);
791 state
->query
.trn_id
= trn_id
;
792 state
->query
.type
= type
;
793 state
->mailslot_name
= mailslot_name
;
795 if (mailslot_name
!= NULL
) {
796 state
->query
.mailslot_namelen
= strlen(mailslot_name
);
799 state
->reader
= TALLOC_ZERO_P(state
, struct nb_packet_reader
);
800 if (tevent_req_nomem(state
->reader
, req
)) {
801 return tevent_req_post(req
, ev
);
804 path
= talloc_asprintf(talloc_tos(), "%s/%s", nmbd_socket_dir(),
806 if (tevent_req_nomem(path
, req
)) {
807 return tevent_req_post(req
, ev
);
809 state
->addr
.sun_family
= AF_UNIX
;
810 strlcpy(state
->addr
.sun_path
, path
, sizeof(state
->addr
.sun_path
));
813 state
->reader
->sock
= socket(AF_UNIX
, SOCK_STREAM
, 0);
814 if (state
->reader
->sock
== -1) {
815 tevent_req_nterror(req
, map_nt_error_from_unix(errno
));
816 return tevent_req_post(req
, ev
);
818 talloc_set_destructor(state
->reader
, nb_packet_reader_destructor
);
820 subreq
= async_connect_send(state
, ev
, state
->reader
->sock
,
821 (struct sockaddr
*)(void *)&state
->addr
,
822 sizeof(state
->addr
));
823 if (tevent_req_nomem(subreq
, req
)) {
824 return tevent_req_post(req
, ev
);
826 tevent_req_set_callback(subreq
, nb_packet_reader_connected
, req
);
830 static int nb_packet_reader_destructor(struct nb_packet_reader
*r
)
839 static void nb_packet_reader_connected(struct tevent_req
*subreq
)
841 struct tevent_req
*req
= tevent_req_callback_data(
842 subreq
, struct tevent_req
);
843 struct nb_packet_reader_state
*state
= tevent_req_data(
844 req
, struct nb_packet_reader_state
);
848 res
= async_connect_recv(subreq
, &err
);
851 DEBUG(10, ("async_connect failed: %s\n", strerror(err
)));
852 tevent_req_nterror(req
, map_nt_error_from_unix(err
));
856 state
->iov
[0].iov_base
= &state
->query
;
857 state
->iov
[0].iov_len
= sizeof(state
->query
);
859 if (state
->mailslot_name
!= NULL
) {
861 state
->iov
[1].iov_base
= discard_const_p(
862 char, state
->mailslot_name
);
863 state
->iov
[1].iov_len
= state
->query
.mailslot_namelen
;
866 subreq
= writev_send(state
, state
->ev
, NULL
, state
->reader
->sock
,
867 true, state
->iov
, num_iovecs
);
868 if (tevent_req_nomem(subreq
, req
)) {
871 tevent_req_set_callback(subreq
, nb_packet_reader_sent_query
, req
);
874 static void nb_packet_reader_sent_query(struct tevent_req
*subreq
)
876 struct tevent_req
*req
= tevent_req_callback_data(
877 subreq
, struct tevent_req
);
878 struct nb_packet_reader_state
*state
= tevent_req_data(
879 req
, struct nb_packet_reader_state
);
883 written
= writev_recv(subreq
, &err
);
886 tevent_req_nterror(req
, map_nt_error_from_unix(err
));
889 if (written
!= sizeof(state
->query
) + state
->query
.mailslot_namelen
) {
890 tevent_req_nterror(req
, NT_STATUS_UNEXPECTED_IO_ERROR
);
893 subreq
= read_packet_send(state
, state
->ev
, state
->reader
->sock
,
894 sizeof(state
->c
), NULL
, NULL
);
895 if (tevent_req_nomem(subreq
, req
)) {
898 tevent_req_set_callback(subreq
, nb_packet_reader_got_ack
, req
);
901 static void nb_packet_reader_got_ack(struct tevent_req
*subreq
)
903 struct tevent_req
*req
= tevent_req_callback_data(
904 subreq
, struct tevent_req
);
905 struct nb_packet_reader_state
*state
= tevent_req_data(
906 req
, struct nb_packet_reader_state
);
911 nread
= read_packet_recv(subreq
, state
, &buf
, &err
);
914 DEBUG(10, ("read_packet_recv returned %s\n",
916 tevent_req_nterror(req
, map_nt_error_from_unix(err
));
919 if (nread
!= sizeof(state
->c
)) {
920 DEBUG(10, ("read = %d, expected %d\n", (int)nread
,
921 (int)sizeof(state
->c
)));
922 tevent_req_nterror(req
, NT_STATUS_UNEXPECTED_IO_ERROR
);
925 tevent_req_done(req
);
928 NTSTATUS
nb_packet_reader_recv(struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
,
929 struct nb_packet_reader
**preader
)
931 struct nb_packet_reader_state
*state
= tevent_req_data(
932 req
, struct nb_packet_reader_state
);
935 if (tevent_req_is_nterror(req
, &status
)) {
938 *preader
= talloc_move(mem_ctx
, &state
->reader
);
942 struct nb_packet_read_state
{
943 struct nb_packet_client_header hdr
;
948 static ssize_t
nb_packet_read_more(uint8_t *buf
, size_t buflen
, void *p
);
949 static void nb_packet_read_done(struct tevent_req
*subreq
);
951 struct tevent_req
*nb_packet_read_send(TALLOC_CTX
*mem_ctx
,
952 struct tevent_context
*ev
,
953 struct nb_packet_reader
*reader
)
955 struct tevent_req
*req
, *subreq
;
956 struct nb_packet_read_state
*state
;
958 req
= tevent_req_create(mem_ctx
, &state
, struct nb_packet_read_state
);
962 subreq
= read_packet_send(state
, ev
, reader
->sock
,
963 sizeof(struct nb_packet_client_header
),
964 nb_packet_read_more
, state
);
965 if (tevent_req_nomem(subreq
, req
)) {
966 return tevent_req_post(req
, ev
);
968 tevent_req_set_callback(subreq
, nb_packet_read_done
, req
);
972 static ssize_t
nb_packet_read_more(uint8_t *buf
, size_t buflen
, void *p
)
974 struct nb_packet_read_state
*state
= talloc_get_type_abort(
975 p
, struct nb_packet_read_state
);
977 if (buflen
> sizeof(struct nb_packet_client_header
)) {
983 memcpy(&state
->hdr
, buf
, sizeof(struct nb_packet_client_header
));
984 return state
->hdr
.len
;
987 static void nb_packet_read_done(struct tevent_req
*subreq
)
989 struct tevent_req
*req
= tevent_req_callback_data(
990 subreq
, struct tevent_req
);
991 struct nb_packet_read_state
*state
= tevent_req_data(
992 req
, struct nb_packet_read_state
);
996 nread
= read_packet_recv(subreq
, state
, &state
->buf
, &err
);
998 tevent_req_nterror(req
, map_nt_error_from_unix(err
));
1001 state
->buflen
= nread
;
1002 tevent_req_done(req
);
1005 NTSTATUS
nb_packet_read_recv(struct tevent_req
*req
,
1006 struct packet_struct
**ppacket
)
1008 struct nb_packet_read_state
*state
= tevent_req_data(
1009 req
, struct nb_packet_read_state
);
1010 struct nb_packet_client_header hdr
;
1011 struct packet_struct
*packet
;
1014 if (tevent_req_is_nterror(req
, &status
)) {
1018 memcpy(&hdr
, state
->buf
, sizeof(hdr
));
1020 packet
= parse_packet(
1021 (char *)state
->buf
+ sizeof(struct nb_packet_client_header
),
1022 state
->buflen
- sizeof(struct nb_packet_client_header
),
1023 state
->hdr
.type
, state
->hdr
.ip
, state
->hdr
.port
);
1024 if (packet
== NULL
) {
1025 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
1028 return NT_STATUS_OK
;