2 Unix SMB/CIFS implementation.
4 low level WINS replication client code
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 3 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, see <http://www.gnu.org/licenses/>.
23 #include "lib/events/events.h"
24 #include "../lib/util/dlinklist.h"
25 #include "lib/socket/socket.h"
26 #include "libcli/wrepl/winsrepl.h"
27 #include "librpc/gen_ndr/ndr_winsrepl.h"
28 #include "lib/stream/packet.h"
29 #include "libcli/composite/composite.h"
30 #include "system/network.h"
31 #include "lib/socket/netif.h"
32 #include "param/param.h"
33 #include "lib/util/tevent_ntstatus.h"
35 static struct wrepl_request
*wrepl_request_finished(struct wrepl_request
*req
, NTSTATUS status
);
38 mark all pending requests as dead - called when a socket error happens
40 static void wrepl_socket_dead(struct wrepl_socket
*wrepl_socket
, NTSTATUS status
)
42 wrepl_socket
->dead
= true;
44 if (wrepl_socket
->packet
) {
45 packet_recv_disable(wrepl_socket
->packet
);
46 packet_set_fde(wrepl_socket
->packet
, NULL
);
47 packet_set_socket(wrepl_socket
->packet
, NULL
);
50 if (wrepl_socket
->event
.fde
) {
51 talloc_free(wrepl_socket
->event
.fde
);
52 wrepl_socket
->event
.fde
= NULL
;
55 if (wrepl_socket
->sock
) {
56 talloc_free(wrepl_socket
->sock
);
57 wrepl_socket
->sock
= NULL
;
60 if (NT_STATUS_EQUAL(NT_STATUS_UNSUCCESSFUL
, status
)) {
61 status
= NT_STATUS_UNEXPECTED_NETWORK_ERROR
;
63 while (wrepl_socket
->recv_queue
) {
64 struct wrepl_request
*req
= wrepl_socket
->recv_queue
;
65 DLIST_REMOVE(wrepl_socket
->recv_queue
, req
);
66 wrepl_request_finished(req
, status
);
69 talloc_set_destructor(wrepl_socket
, NULL
);
70 if (wrepl_socket
->free_skipped
) {
71 talloc_free(wrepl_socket
);
75 static void wrepl_request_timeout_handler(struct tevent_context
*ev
, struct tevent_timer
*te
,
76 struct timeval t
, void *ptr
)
78 struct wrepl_request
*req
= talloc_get_type(ptr
, struct wrepl_request
);
79 wrepl_socket_dead(req
->wrepl_socket
, NT_STATUS_IO_TIMEOUT
);
85 static NTSTATUS
wrepl_finish_recv(void *private_data
, DATA_BLOB packet_blob_in
)
87 struct wrepl_socket
*wrepl_socket
= talloc_get_type(private_data
, struct wrepl_socket
);
88 struct wrepl_request
*req
= wrepl_socket
->recv_queue
;
90 enum ndr_err_code ndr_err
;
93 DEBUG(1,("Received unexpected WINS packet of length %u!\n",
94 (unsigned)packet_blob_in
.length
));
95 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
98 req
->packet
= talloc(req
, struct wrepl_packet
);
99 NT_STATUS_HAVE_NO_MEMORY(req
->packet
);
101 blob
.data
= packet_blob_in
.data
+ 4;
102 blob
.length
= packet_blob_in
.length
- 4;
104 /* we have a full request - parse it */
105 ndr_err
= ndr_pull_struct_blob(&blob
, req
->packet
, wrepl_socket
->iconv_convenience
, req
->packet
,
106 (ndr_pull_flags_fn_t
)ndr_pull_wrepl_packet
);
107 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
108 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
109 wrepl_request_finished(req
, status
);
114 DEBUG(10,("Received WINS packet of length %u\n",
115 (unsigned)packet_blob_in
.length
));
116 NDR_PRINT_DEBUG(wrepl_packet
, req
->packet
);
119 wrepl_request_finished(req
, NT_STATUS_OK
);
124 handler for winrepl events
126 static void wrepl_handler(struct tevent_context
*ev
, struct tevent_fd
*fde
,
127 uint16_t flags
, void *private_data
)
129 struct wrepl_socket
*wrepl_socket
= talloc_get_type(private_data
,
130 struct wrepl_socket
);
131 if (flags
& EVENT_FD_READ
) {
132 packet_recv(wrepl_socket
->packet
);
135 if (flags
& EVENT_FD_WRITE
) {
136 packet_queue_run(wrepl_socket
->packet
);
140 static void wrepl_error(void *private_data
, NTSTATUS status
)
142 struct wrepl_socket
*wrepl_socket
= talloc_get_type(private_data
,
143 struct wrepl_socket
);
144 wrepl_socket_dead(wrepl_socket
, status
);
149 destroy a wrepl_socket destructor
151 static int wrepl_socket_destructor(struct wrepl_socket
*sock
)
154 sock
->free_skipped
= true;
157 wrepl_socket_dead(sock
, NT_STATUS_LOCAL_DISCONNECT
);
162 initialise a wrepl_socket. The event_ctx is optional, if provided then
163 operations will use that event context
165 struct wrepl_socket
*wrepl_socket_init(TALLOC_CTX
*mem_ctx
,
166 struct tevent_context
*event_ctx
,
167 struct smb_iconv_convenience
*iconv_convenience
)
169 struct wrepl_socket
*wrepl_socket
;
172 wrepl_socket
= talloc_zero(mem_ctx
, struct wrepl_socket
);
173 if (!wrepl_socket
) return NULL
;
175 wrepl_socket
->event
.ctx
= event_ctx
;
176 if (!wrepl_socket
->event
.ctx
) goto failed
;
178 wrepl_socket
->iconv_convenience
= iconv_convenience
;
180 status
= socket_create("ip", SOCKET_TYPE_STREAM
, &wrepl_socket
->sock
, 0);
181 if (!NT_STATUS_IS_OK(status
)) goto failed
;
183 talloc_steal(wrepl_socket
, wrepl_socket
->sock
);
185 wrepl_socket
->request_timeout
= WREPL_SOCKET_REQUEST_TIMEOUT
;
187 talloc_set_destructor(wrepl_socket
, wrepl_socket_destructor
);
192 talloc_free(wrepl_socket
);
197 initialise a wrepl_socket from an already existing connection
199 struct wrepl_socket
*wrepl_socket_merge(TALLOC_CTX
*mem_ctx
,
200 struct tevent_context
*event_ctx
,
201 struct socket_context
*sock
,
202 struct packet_context
*pack
)
204 struct wrepl_socket
*wrepl_socket
;
206 wrepl_socket
= talloc_zero(mem_ctx
, struct wrepl_socket
);
207 if (wrepl_socket
== NULL
) goto failed
;
209 wrepl_socket
->event
.ctx
= event_ctx
;
210 if (wrepl_socket
->event
.ctx
== NULL
) goto failed
;
212 wrepl_socket
->sock
= sock
;
213 talloc_steal(wrepl_socket
, wrepl_socket
->sock
);
216 wrepl_socket
->request_timeout
= WREPL_SOCKET_REQUEST_TIMEOUT
;
218 wrepl_socket
->event
.fde
= event_add_fd(wrepl_socket
->event
.ctx
, wrepl_socket
,
219 socket_get_fd(wrepl_socket
->sock
),
221 wrepl_handler
, wrepl_socket
);
222 if (wrepl_socket
->event
.fde
== NULL
) {
226 wrepl_socket
->packet
= pack
;
227 talloc_steal(wrepl_socket
, wrepl_socket
->packet
);
228 packet_set_private(wrepl_socket
->packet
, wrepl_socket
);
229 packet_set_socket(wrepl_socket
->packet
, wrepl_socket
->sock
);
230 packet_set_callback(wrepl_socket
->packet
, wrepl_finish_recv
);
231 packet_set_full_request(wrepl_socket
->packet
, packet_full_request_u32
);
232 packet_set_error_handler(wrepl_socket
->packet
, wrepl_error
);
233 packet_set_event_context(wrepl_socket
->packet
, wrepl_socket
->event
.ctx
);
234 packet_set_fde(wrepl_socket
->packet
, wrepl_socket
->event
.fde
);
235 packet_set_serialise(wrepl_socket
->packet
);
237 talloc_set_destructor(wrepl_socket
, wrepl_socket_destructor
);
242 talloc_free(wrepl_socket
);
247 destroy a wrepl_request
249 static int wrepl_request_destructor(struct wrepl_request
*req
)
251 if (req
->state
== WREPL_REQUEST_RECV
) {
252 DLIST_REMOVE(req
->wrepl_socket
->recv_queue
, req
);
254 req
->state
= WREPL_REQUEST_ERROR
;
259 wait for a request to complete
261 static NTSTATUS
wrepl_request_wait(struct wrepl_request
*req
)
263 NT_STATUS_HAVE_NO_MEMORY(req
);
264 while (req
->state
< WREPL_REQUEST_DONE
) {
265 event_loop_once(req
->wrepl_socket
->event
.ctx
);
270 struct wrepl_connect_state
{
271 struct composite_context
*result
;
272 struct wrepl_socket
*wrepl_socket
;
273 struct composite_context
*creq
;
277 handler for winrepl connection completion
279 static void wrepl_connect_handler(struct composite_context
*creq
)
281 struct wrepl_connect_state
*state
= talloc_get_type(creq
->async
.private_data
,
282 struct wrepl_connect_state
);
283 struct wrepl_socket
*wrepl_socket
= state
->wrepl_socket
;
284 struct composite_context
*result
= state
->result
;
286 result
->status
= socket_connect_recv(state
->creq
);
287 if (!composite_is_ok(result
)) return;
289 wrepl_socket
->event
.fde
= event_add_fd(wrepl_socket
->event
.ctx
, wrepl_socket
,
290 socket_get_fd(wrepl_socket
->sock
),
292 wrepl_handler
, wrepl_socket
);
293 if (composite_nomem(wrepl_socket
->event
.fde
, result
)) return;
295 /* setup the stream -> packet parser */
296 wrepl_socket
->packet
= packet_init(wrepl_socket
);
297 if (composite_nomem(wrepl_socket
->packet
, result
)) return;
298 packet_set_private(wrepl_socket
->packet
, wrepl_socket
);
299 packet_set_socket(wrepl_socket
->packet
, wrepl_socket
->sock
);
300 packet_set_callback(wrepl_socket
->packet
, wrepl_finish_recv
);
301 packet_set_full_request(wrepl_socket
->packet
, packet_full_request_u32
);
302 packet_set_error_handler(wrepl_socket
->packet
, wrepl_error
);
303 packet_set_event_context(wrepl_socket
->packet
, wrepl_socket
->event
.ctx
);
304 packet_set_fde(wrepl_socket
->packet
, wrepl_socket
->event
.fde
);
305 packet_set_serialise(wrepl_socket
->packet
);
307 composite_done(result
);
310 const char *wrepl_best_ip(struct loadparm_context
*lp_ctx
, const char *peer_ip
)
312 struct interface
*ifaces
;
313 load_interfaces(lp_ctx
, lp_interfaces(lp_ctx
), &ifaces
);
314 return iface_best_ip(ifaces
, peer_ip
);
319 connect a wrepl_socket to a WINS server
321 struct composite_context
*wrepl_connect_send(struct wrepl_socket
*wrepl_socket
,
322 const char *our_ip
, const char *peer_ip
)
324 struct composite_context
*result
;
325 struct wrepl_connect_state
*state
;
326 struct socket_address
*peer
, *us
;
328 result
= talloc_zero(wrepl_socket
, struct composite_context
);
329 if (!result
) return NULL
;
331 result
->state
= COMPOSITE_STATE_IN_PROGRESS
;
332 result
->event_ctx
= wrepl_socket
->event
.ctx
;
334 state
= talloc_zero(result
, struct wrepl_connect_state
);
335 if (composite_nomem(state
, result
)) return result
;
336 result
->private_data
= state
;
337 state
->result
= result
;
338 state
->wrepl_socket
= wrepl_socket
;
340 us
= socket_address_from_strings(state
, wrepl_socket
->sock
->backend_name
,
342 if (composite_nomem(us
, result
)) return result
;
344 peer
= socket_address_from_strings(state
, wrepl_socket
->sock
->backend_name
,
345 peer_ip
, WINS_REPLICATION_PORT
);
346 if (composite_nomem(peer
, result
)) return result
;
348 state
->creq
= socket_connect_send(wrepl_socket
->sock
, us
, peer
,
349 0, wrepl_socket
->event
.ctx
);
350 composite_continue(result
, state
->creq
, wrepl_connect_handler
, state
);
355 connect a wrepl_socket to a WINS server - recv side
357 NTSTATUS
wrepl_connect_recv(struct composite_context
*result
)
359 struct wrepl_connect_state
*state
= talloc_get_type(result
->private_data
,
360 struct wrepl_connect_state
);
361 struct wrepl_socket
*wrepl_socket
= state
->wrepl_socket
;
362 NTSTATUS status
= composite_wait(result
);
364 if (!NT_STATUS_IS_OK(status
)) {
365 wrepl_socket_dead(wrepl_socket
, status
);
373 connect a wrepl_socket to a WINS server - sync API
375 NTSTATUS
wrepl_connect(struct wrepl_socket
*wrepl_socket
,
376 const char *our_ip
, const char *peer_ip
)
378 struct composite_context
*c_req
= wrepl_connect_send(wrepl_socket
, our_ip
, peer_ip
);
379 return wrepl_connect_recv(c_req
);
383 callback from wrepl_request_trigger()
385 static void wrepl_request_trigger_handler(struct tevent_context
*ev
, struct tevent_timer
*te
,
386 struct timeval t
, void *ptr
)
388 struct wrepl_request
*req
= talloc_get_type(ptr
, struct wrepl_request
);
395 trigger an immediate event on a wrepl_request
396 the return value should only be used in wrepl_request_send()
397 this is the only place where req->trigger is true
399 static struct wrepl_request
*wrepl_request_finished(struct wrepl_request
*req
, NTSTATUS status
)
401 struct tevent_timer
*te
;
403 if (req
->state
== WREPL_REQUEST_RECV
) {
404 DLIST_REMOVE(req
->wrepl_socket
->recv_queue
, req
);
407 if (!NT_STATUS_IS_OK(status
)) {
408 req
->state
= WREPL_REQUEST_ERROR
;
410 req
->state
= WREPL_REQUEST_DONE
;
413 req
->status
= status
;
416 req
->trigger
= false;
417 /* a zero timeout means immediate */
418 te
= event_add_timed(req
->wrepl_socket
->event
.ctx
,
420 wrepl_request_trigger_handler
, req
);
434 struct wrepl_send_ctrl_state
{
435 struct wrepl_send_ctrl ctrl
;
436 struct wrepl_request
*req
;
437 struct wrepl_socket
*wrepl_sock
;
440 static int wrepl_send_ctrl_destructor(struct wrepl_send_ctrl_state
*s
)
442 struct wrepl_request
*req
= s
->wrepl_sock
->recv_queue
;
444 /* check if the request is still in WREPL_STATE_RECV,
445 * we need this here because the caller has may called
446 * talloc_free(req) and wrepl_send_ctrl_state isn't
447 * a talloc child of the request, so our s->req pointer
450 for (; req
; req
= req
->next
) {
451 if (req
== s
->req
) break;
455 /* here, we need to make sure the async request handler is called
456 * later in the next event_loop and now now
459 wrepl_request_finished(req
, NT_STATUS_OK
);
461 if (s
->ctrl
.disconnect_after_send
) {
462 wrepl_socket_dead(s
->wrepl_sock
, NT_STATUS_LOCAL_DISCONNECT
);
469 send a generic wins replication request
471 struct wrepl_request
*wrepl_request_send(struct wrepl_socket
*wrepl_socket
,
472 struct wrepl_packet
*packet
,
473 struct wrepl_send_ctrl
*ctrl
)
475 struct wrepl_request
*req
;
476 struct wrepl_wrap wrap
;
479 enum ndr_err_code ndr_err
;
481 req
= talloc_zero(wrepl_socket
, struct wrepl_request
);
482 if (!req
) return NULL
;
483 req
->wrepl_socket
= wrepl_socket
;
484 req
->state
= WREPL_REQUEST_RECV
;
487 DLIST_ADD_END(wrepl_socket
->recv_queue
, req
, struct wrepl_request
*);
488 talloc_set_destructor(req
, wrepl_request_destructor
);
490 if (wrepl_socket
->dead
) {
491 return wrepl_request_finished(req
, NT_STATUS_INVALID_CONNECTION
);
494 wrap
.packet
= *packet
;
495 ndr_err
= ndr_push_struct_blob(&blob
, req
, wrepl_socket
->iconv_convenience
, &wrap
,
496 (ndr_push_flags_fn_t
)ndr_push_wrepl_wrap
);
497 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
498 status
= ndr_map_error2ntstatus(ndr_err
);
499 return wrepl_request_finished(req
, status
);
503 DEBUG(10,("Sending WINS packet of length %u\n",
504 (unsigned)blob
.length
));
505 NDR_PRINT_DEBUG(wrepl_packet
, &wrap
.packet
);
508 if (wrepl_socket
->request_timeout
> 0) {
509 req
->te
= event_add_timed(wrepl_socket
->event
.ctx
, req
,
510 timeval_current_ofs(wrepl_socket
->request_timeout
, 0),
511 wrepl_request_timeout_handler
, req
);
512 if (!req
->te
) return wrepl_request_finished(req
, NT_STATUS_NO_MEMORY
);
515 if (ctrl
&& (ctrl
->send_only
|| ctrl
->disconnect_after_send
)) {
516 struct wrepl_send_ctrl_state
*s
= talloc(blob
.data
, struct wrepl_send_ctrl_state
);
517 if (!s
) return wrepl_request_finished(req
, NT_STATUS_NO_MEMORY
);
520 s
->wrepl_sock
= wrepl_socket
;
521 talloc_set_destructor(s
, wrepl_send_ctrl_destructor
);
524 status
= packet_send(wrepl_socket
->packet
, blob
);
525 if (!NT_STATUS_IS_OK(status
)) {
526 return wrepl_request_finished(req
, status
);
529 req
->trigger
= false;
534 receive a generic WINS replication reply
536 NTSTATUS
wrepl_request_recv(struct wrepl_request
*req
,
538 struct wrepl_packet
**packet
)
540 NTSTATUS status
= wrepl_request_wait(req
);
541 if (NT_STATUS_IS_OK(status
) && packet
) {
542 *packet
= talloc_steal(mem_ctx
, req
->packet
);
549 a full WINS replication request/response
551 NTSTATUS
wrepl_request(struct wrepl_socket
*wrepl_socket
,
553 struct wrepl_packet
*req_packet
,
554 struct wrepl_packet
**reply_packet
)
556 struct wrepl_request
*req
= wrepl_request_send(wrepl_socket
, req_packet
, NULL
);
557 return wrepl_request_recv(req
, mem_ctx
, reply_packet
);
562 setup an association - send
564 struct wrepl_request
*wrepl_associate_send(struct wrepl_socket
*wrepl_socket
,
565 struct wrepl_associate
*io
)
567 struct wrepl_packet
*packet
;
568 struct wrepl_request
*req
;
570 packet
= talloc_zero(wrepl_socket
, struct wrepl_packet
);
571 if (packet
== NULL
) return NULL
;
573 packet
->opcode
= WREPL_OPCODE_BITS
;
574 packet
->mess_type
= WREPL_START_ASSOCIATION
;
575 packet
->message
.start
.minor_version
= 2;
576 packet
->message
.start
.major_version
= 5;
579 * nt4 uses 41 bytes for the start_association call
580 * so do it the same and as we don't know th emeanings of this bytes
581 * we just send zeros and nt4, w2k and w2k3 seems to be happy with this
583 * if we don't do this nt4 uses an old version of the wins replication protocol
584 * and that would break nt4 <-> samba replication
586 packet
->padding
= data_blob_talloc(packet
, NULL
, 21);
587 if (packet
->padding
.data
== NULL
) {
591 memset(packet
->padding
.data
, 0, packet
->padding
.length
);
593 req
= wrepl_request_send(wrepl_socket
, packet
, NULL
);
601 setup an association - recv
603 NTSTATUS
wrepl_associate_recv(struct wrepl_request
*req
,
604 struct wrepl_associate
*io
)
606 struct wrepl_packet
*packet
=NULL
;
608 status
= wrepl_request_recv(req
, req
->wrepl_socket
, &packet
);
609 NT_STATUS_NOT_OK_RETURN(status
);
610 if (packet
->mess_type
!= WREPL_START_ASSOCIATION_REPLY
) {
611 status
= NT_STATUS_UNEXPECTED_NETWORK_ERROR
;
613 if (NT_STATUS_IS_OK(status
)) {
614 io
->out
.assoc_ctx
= packet
->message
.start_reply
.assoc_ctx
;
615 io
->out
.major_version
= packet
->message
.start_reply
.major_version
;
622 setup an association - sync api
624 NTSTATUS
wrepl_associate(struct wrepl_socket
*wrepl_socket
,
625 struct wrepl_associate
*io
)
627 struct wrepl_request
*req
= wrepl_associate_send(wrepl_socket
, io
);
628 return wrepl_associate_recv(req
, io
);
633 stop an association - send
635 struct wrepl_request
*wrepl_associate_stop_send(struct wrepl_socket
*wrepl_socket
,
636 struct wrepl_associate_stop
*io
)
638 struct wrepl_packet
*packet
;
639 struct wrepl_request
*req
;
640 struct wrepl_send_ctrl ctrl
;
642 packet
= talloc_zero(wrepl_socket
, struct wrepl_packet
);
643 if (packet
== NULL
) return NULL
;
645 packet
->opcode
= WREPL_OPCODE_BITS
;
646 packet
->assoc_ctx
= io
->in
.assoc_ctx
;
647 packet
->mess_type
= WREPL_STOP_ASSOCIATION
;
648 packet
->message
.stop
.reason
= io
->in
.reason
;
651 if (io
->in
.reason
== 0) {
652 ctrl
.send_only
= true;
653 ctrl
.disconnect_after_send
= true;
656 req
= wrepl_request_send(wrepl_socket
, packet
, &ctrl
);
664 stop an association - recv
666 NTSTATUS
wrepl_associate_stop_recv(struct wrepl_request
*req
,
667 struct wrepl_associate_stop
*io
)
669 struct wrepl_packet
*packet
=NULL
;
671 status
= wrepl_request_recv(req
, req
->wrepl_socket
, &packet
);
672 NT_STATUS_NOT_OK_RETURN(status
);
678 setup an association - sync api
680 NTSTATUS
wrepl_associate_stop(struct wrepl_socket
*wrepl_socket
,
681 struct wrepl_associate_stop
*io
)
683 struct wrepl_request
*req
= wrepl_associate_stop_send(wrepl_socket
, io
);
684 return wrepl_associate_stop_recv(req
, io
);
687 struct wrepl_pull_table_state
{
688 struct wrepl_packet packet
;
689 uint32_t num_partners
;
690 struct wrepl_wins_owner
*partners
;
693 static void wrepl_pull_table_done(struct wrepl_request
*subreq
);
695 struct tevent_req
*wrepl_pull_table_send(TALLOC_CTX
*mem_ctx
,
696 struct tevent_context
*ev
,
697 struct wrepl_socket
*wrepl_socket
,
698 const struct wrepl_pull_table
*io
)
700 struct tevent_req
*req
;
701 struct wrepl_pull_table_state
*state
;
702 struct wrepl_request
*subreq
;
704 if (wrepl_socket
->event
.ctx
!= ev
) {
705 /* TODO: remove wrepl_socket->event.ctx !!! */
706 smb_panic("wrepl_pull_table_send event context mismatch!");
710 req
= tevent_req_create(mem_ctx
, &state
,
711 struct wrepl_pull_table_state
);
716 state
->packet
.opcode
= WREPL_OPCODE_BITS
;
717 state
->packet
.assoc_ctx
= io
->in
.assoc_ctx
;
718 state
->packet
.mess_type
= WREPL_REPLICATION
;
719 state
->packet
.message
.replication
.command
= WREPL_REPL_TABLE_QUERY
;
721 subreq
= wrepl_request_send(wrepl_socket
, &state
->packet
, NULL
);
722 if (tevent_req_nomem(subreq
, req
)) {
723 return tevent_req_post(req
, ev
);
725 subreq
->async
.fn
= wrepl_pull_table_done
;
726 subreq
->async
.private_data
= req
;
731 static void wrepl_pull_table_done(struct wrepl_request
*subreq
)
733 struct tevent_req
*req
= talloc_get_type_abort(subreq
->async
.private_data
,
735 struct wrepl_pull_table_state
*state
= tevent_req_data(req
,
736 struct wrepl_pull_table_state
);
738 struct wrepl_packet
*packet
;
739 struct wrepl_table
*table
;
741 status
= wrepl_request_recv(subreq
, state
, &packet
);
742 if (!NT_STATUS_IS_OK(status
)) {
743 tevent_req_nterror(req
, status
);
747 if (packet
->mess_type
!= WREPL_REPLICATION
) {
748 tevent_req_nterror(req
, NT_STATUS_NETWORK_ACCESS_DENIED
);
752 if (packet
->message
.replication
.command
!= WREPL_REPL_TABLE_REPLY
) {
753 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
757 table
= &packet
->message
.replication
.info
.table
;
759 state
->num_partners
= table
->partner_count
;
760 state
->partners
= talloc_move(state
, &table
->partners
);
762 tevent_req_done(req
);
766 fetch the partner tables - recv
768 NTSTATUS
wrepl_pull_table_recv(struct tevent_req
*req
,
770 struct wrepl_pull_table
*io
)
772 struct wrepl_pull_table_state
*state
= tevent_req_data(req
,
773 struct wrepl_pull_table_state
);
776 if (tevent_req_is_nterror(req
, &status
)) {
777 tevent_req_received(req
);
781 io
->out
.num_partners
= state
->num_partners
;
782 io
->out
.partners
= talloc_move(mem_ctx
, &state
->partners
);
784 tevent_req_received(req
);
789 fetch the partner table - sync api
791 NTSTATUS
wrepl_pull_table(struct wrepl_socket
*wrepl_socket
,
793 struct wrepl_pull_table
*io
)
795 struct tevent_req
*subreq
;
799 subreq
= wrepl_pull_table_send(mem_ctx
, wrepl_socket
->event
.ctx
,
801 NT_STATUS_HAVE_NO_MEMORY(subreq
);
803 ok
= tevent_req_poll(subreq
, wrepl_socket
->event
.ctx
);
806 return NT_STATUS_INTERNAL_ERROR
;
809 status
= wrepl_pull_table_recv(subreq
, mem_ctx
, io
);
811 NT_STATUS_NOT_OK_RETURN(status
);
817 struct wrepl_pull_names_state
{
819 const struct wrepl_pull_names
*io
;
821 struct wrepl_packet packet
;
823 struct wrepl_name
*names
;
826 static void wrepl_pull_names_done(struct wrepl_request
*subreq
);
828 struct tevent_req
*wrepl_pull_names_send(TALLOC_CTX
*mem_ctx
,
829 struct tevent_context
*ev
,
830 struct wrepl_socket
*wrepl_socket
,
831 const struct wrepl_pull_names
*io
)
833 struct tevent_req
*req
;
834 struct wrepl_pull_names_state
*state
;
835 struct wrepl_request
*subreq
;
837 if (wrepl_socket
->event
.ctx
!= ev
) {
838 /* TODO: remove wrepl_socket->event.ctx !!! */
839 smb_panic("wrepl_pull_names_send event context mismatch!");
843 req
= tevent_req_create(mem_ctx
, &state
,
844 struct wrepl_pull_names_state
);
848 state
->caller
.io
= io
;
850 state
->packet
.opcode
= WREPL_OPCODE_BITS
;
851 state
->packet
.assoc_ctx
= io
->in
.assoc_ctx
;
852 state
->packet
.mess_type
= WREPL_REPLICATION
;
853 state
->packet
.message
.replication
.command
= WREPL_REPL_SEND_REQUEST
;
854 state
->packet
.message
.replication
.info
.owner
= io
->in
.partner
;
856 subreq
= wrepl_request_send(wrepl_socket
, &state
->packet
, NULL
);
857 if (tevent_req_nomem(subreq
, req
)) {
858 return tevent_req_post(req
, ev
);
860 subreq
->async
.fn
= wrepl_pull_names_done
;
861 subreq
->async
.private_data
= req
;
866 static void wrepl_pull_names_done(struct wrepl_request
*subreq
)
868 struct tevent_req
*req
= talloc_get_type_abort(subreq
->async
.private_data
,
870 struct wrepl_pull_names_state
*state
= tevent_req_data(req
,
871 struct wrepl_pull_names_state
);
873 struct wrepl_packet
*packet
;
876 status
= wrepl_request_recv(subreq
, state
, &packet
);
877 if (!NT_STATUS_IS_OK(status
)) {
878 tevent_req_nterror(req
, status
);
882 if (packet
->mess_type
!= WREPL_REPLICATION
) {
883 tevent_req_nterror(req
, NT_STATUS_NETWORK_ACCESS_DENIED
);
887 if (packet
->message
.replication
.command
!= WREPL_REPL_SEND_REPLY
) {
888 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
892 state
->num_names
= packet
->message
.replication
.info
.reply
.num_names
;
894 state
->names
= talloc_array(state
, struct wrepl_name
, state
->num_names
);
895 if (tevent_req_nomem(state
->names
, req
)) {
899 /* convert the list of names and addresses to a sane format */
900 for (i
=0; i
< state
->num_names
; i
++) {
901 struct wrepl_wins_name
*wname
= &packet
->message
.replication
.info
.reply
.names
[i
];
902 struct wrepl_name
*name
= &state
->names
[i
];
904 name
->name
= *wname
->name
;
905 talloc_steal(state
->names
, wname
->name
);
906 name
->type
= WREPL_NAME_TYPE(wname
->flags
);
907 name
->state
= WREPL_NAME_STATE(wname
->flags
);
908 name
->node
= WREPL_NAME_NODE(wname
->flags
);
909 name
->is_static
= WREPL_NAME_IS_STATIC(wname
->flags
);
910 name
->raw_flags
= wname
->flags
;
911 name
->version_id
= wname
->id
;
912 name
->owner
= talloc_strdup(state
->names
,
913 state
->caller
.io
->in
.partner
.address
);
914 if (tevent_req_nomem(name
->owner
, req
)) {
918 /* trying to save 1 or 2 bytes on the wire isn't a good idea */
919 if (wname
->flags
& 2) {
922 name
->num_addresses
= wname
->addresses
.addresses
.num_ips
;
923 name
->addresses
= talloc_array(state
->names
,
924 struct wrepl_address
,
925 name
->num_addresses
);
926 if (tevent_req_nomem(name
->addresses
, req
)) {
930 for (j
=0;j
<name
->num_addresses
;j
++) {
931 name
->addresses
[j
].owner
=
932 talloc_move(name
->addresses
,
933 &wname
->addresses
.addresses
.ips
[j
].owner
);
934 name
->addresses
[j
].address
=
935 talloc_move(name
->addresses
,
936 &wname
->addresses
.addresses
.ips
[j
].ip
);
939 name
->num_addresses
= 1;
940 name
->addresses
= talloc_array(state
->names
,
941 struct wrepl_address
,
942 name
->num_addresses
);
943 if (tevent_req_nomem(name
->addresses
, req
)) {
947 name
->addresses
[0].owner
= talloc_strdup(name
->addresses
, name
->owner
);
948 if (tevent_req_nomem(name
->addresses
[0].owner
, req
)) {
951 name
->addresses
[0].address
= talloc_move(name
->addresses
,
952 &wname
->addresses
.ip
);
956 tevent_req_done(req
);
960 fetch the names for a WINS partner - recv
962 NTSTATUS
wrepl_pull_names_recv(struct tevent_req
*req
,
964 struct wrepl_pull_names
*io
)
966 struct wrepl_pull_names_state
*state
= tevent_req_data(req
,
967 struct wrepl_pull_names_state
);
970 if (tevent_req_is_nterror(req
, &status
)) {
971 tevent_req_received(req
);
975 io
->out
.num_names
= state
->num_names
;
976 io
->out
.names
= talloc_move(mem_ctx
, &state
->names
);
978 tevent_req_received(req
);
985 fetch the names for a WINS partner - sync api
987 NTSTATUS
wrepl_pull_names(struct wrepl_socket
*wrepl_socket
,
989 struct wrepl_pull_names
*io
)
991 struct tevent_req
*subreq
;
995 subreq
= wrepl_pull_names_send(mem_ctx
, wrepl_socket
->event
.ctx
,
997 NT_STATUS_HAVE_NO_MEMORY(subreq
);
999 ok
= tevent_req_poll(subreq
, wrepl_socket
->event
.ctx
);
1001 TALLOC_FREE(subreq
);
1002 return NT_STATUS_INTERNAL_ERROR
;
1005 status
= wrepl_pull_names_recv(subreq
, mem_ctx
, io
);
1006 TALLOC_FREE(subreq
);
1007 NT_STATUS_NOT_OK_RETURN(status
);
1009 return NT_STATUS_OK
;