2 Unix SMB/CIFS implementation.
4 low level WINS replication client code
6 Copyright (C) Andrew Tridgell 2005
7 Copyright (C) Stefan Metzmacher 2005-2010
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "lib/events/events.h"
25 #include "../lib/util/dlinklist.h"
26 #include "libcli/wrepl/winsrepl.h"
27 #include "librpc/gen_ndr/ndr_winsrepl.h"
28 #include "lib/stream/packet.h"
29 #include "system/network.h"
30 #include "lib/socket/netif.h"
31 #include "param/param.h"
32 #include "lib/util/tevent_ntstatus.h"
33 #include "lib/tsocket/tsocket.h"
34 #include "libcli/util/tstream.h"
37 main context structure for the wins replication client library
41 struct tevent_context *ctx;
44 /* the default timeout for requests, 0 means no timeout */
45 #define WREPL_SOCKET_REQUEST_TIMEOUT (60)
46 uint32_t request_timeout;
48 struct tevent_queue *request_queue;
50 struct tstream_context *stream;
53 bool wrepl_socket_is_connected(struct wrepl_socket *wrepl_sock)
59 if (!wrepl_sock->stream) {
67 initialise a wrepl_socket. The event_ctx is optional, if provided then
68 operations will use that event context
70 struct wrepl_socket *wrepl_socket_init(TALLOC_CTX *mem_ctx,
71 struct tevent_context *event_ctx)
73 struct wrepl_socket *wrepl_socket;
75 wrepl_socket = talloc_zero(mem_ctx, struct wrepl_socket);
80 wrepl_socket->event.ctx = event_ctx;
81 if (!wrepl_socket->event.ctx) {
85 wrepl_socket->request_queue = tevent_queue_create(wrepl_socket,
86 "wrepl request queue");
87 if (wrepl_socket->request_queue == NULL) {
91 wrepl_socket->request_timeout = WREPL_SOCKET_REQUEST_TIMEOUT;
96 talloc_free(wrepl_socket);
101 initialise a wrepl_socket from an already existing connection
103 NTSTATUS wrepl_socket_donate_stream(struct wrepl_socket *wrepl_socket,
104 struct tstream_context **stream)
106 if (wrepl_socket->stream) {
107 return NT_STATUS_CONNECTION_ACTIVE;
110 wrepl_socket->stream = talloc_move(wrepl_socket, stream);
115 initialise a wrepl_socket from an already existing connection
117 NTSTATUS wrepl_socket_split_stream(struct wrepl_socket *wrepl_socket,
119 struct tstream_context **stream)
123 if (!wrepl_socket->stream) {
124 return NT_STATUS_CONNECTION_INVALID;
127 num_requests = tevent_queue_length(wrepl_socket->request_queue);
128 if (num_requests > 0) {
129 return NT_STATUS_CONNECTION_IN_USE;
132 *stream = talloc_move(wrepl_socket, &wrepl_socket->stream);
136 const char *wrepl_best_ip(struct loadparm_context *lp_ctx, const char *peer_ip)
138 struct interface *ifaces;
139 load_interfaces(lp_ctx, lp_interfaces(lp_ctx), &ifaces);
140 return iface_best_ip(ifaces, peer_ip);
143 struct wrepl_connect_state {
145 struct wrepl_socket *wrepl_socket;
146 struct tevent_context *ev;
148 struct tsocket_address *local_address;
149 struct tsocket_address *remote_address;
150 struct tstream_context *stream;
153 static void wrepl_connect_trigger(struct tevent_req *req,
156 struct tevent_req *wrepl_connect_send(TALLOC_CTX *mem_ctx,
157 struct tevent_context *ev,
158 struct wrepl_socket *wrepl_socket,
159 const char *our_ip, const char *peer_ip)
161 struct tevent_req *req;
162 struct wrepl_connect_state *state;
166 req = tevent_req_create(mem_ctx, &state,
167 struct wrepl_connect_state);
172 state->caller.wrepl_socket = wrepl_socket;
173 state->caller.ev = ev;
175 if (wrepl_socket->stream) {
176 tevent_req_nterror(req, NT_STATUS_CONNECTION_ACTIVE);
177 return tevent_req_post(req, ev);
180 ret = tsocket_address_inet_from_strings(state, "ipv4",
182 &state->local_address);
184 NTSTATUS status = map_nt_error_from_unix(errno);
185 tevent_req_nterror(req, status);
186 return tevent_req_post(req, ev);
189 ret = tsocket_address_inet_from_strings(state, "ipv4",
190 peer_ip, WINS_REPLICATION_PORT,
191 &state->remote_address);
193 NTSTATUS status = map_nt_error_from_unix(errno);
194 tevent_req_nterror(req, status);
195 return tevent_req_post(req, ev);
198 ok = tevent_queue_add(wrepl_socket->request_queue,
201 wrepl_connect_trigger,
204 tevent_req_nomem(NULL, req);
205 return tevent_req_post(req, ev);
208 if (wrepl_socket->request_timeout > 0) {
209 struct timeval endtime;
210 endtime = tevent_timeval_current_ofs(wrepl_socket->request_timeout, 0);
211 ok = tevent_req_set_endtime(req, ev, endtime);
213 return tevent_req_post(req, ev);
220 static void wrepl_connect_done(struct tevent_req *subreq);
222 static void wrepl_connect_trigger(struct tevent_req *req,
225 struct wrepl_connect_state *state = tevent_req_data(req,
226 struct wrepl_connect_state);
227 struct tevent_req *subreq;
229 subreq = tstream_inet_tcp_connect_send(state,
231 state->local_address,
232 state->remote_address);
233 if (tevent_req_nomem(subreq, req)) {
236 tevent_req_set_callback(subreq, wrepl_connect_done, req);
241 static void wrepl_connect_done(struct tevent_req *subreq)
243 struct tevent_req *req = tevent_req_callback_data(subreq,
245 struct wrepl_connect_state *state = tevent_req_data(req,
246 struct wrepl_connect_state);
250 ret = tstream_inet_tcp_connect_recv(subreq, &sys_errno,
251 state, &state->stream);
253 NTSTATUS status = map_nt_error_from_unix(sys_errno);
254 tevent_req_nterror(req, status);
258 tevent_req_done(req);
262 connect a wrepl_socket to a WINS server - recv side
264 NTSTATUS wrepl_connect_recv(struct tevent_req *req)
266 struct wrepl_connect_state *state = tevent_req_data(req,
267 struct wrepl_connect_state);
268 struct wrepl_socket *wrepl_socket = state->caller.wrepl_socket;
271 if (tevent_req_is_nterror(req, &status)) {
272 tevent_req_received(req);
276 wrepl_socket->stream = talloc_move(wrepl_socket, &state->stream);
278 tevent_req_received(req);
283 connect a wrepl_socket to a WINS server - sync API
285 NTSTATUS wrepl_connect(struct wrepl_socket *wrepl_socket,
286 const char *our_ip, const char *peer_ip)
288 struct tevent_req *subreq;
292 subreq = wrepl_connect_send(wrepl_socket, wrepl_socket->event.ctx,
293 wrepl_socket, our_ip, peer_ip);
294 NT_STATUS_HAVE_NO_MEMORY(subreq);
296 ok = tevent_req_poll(subreq, wrepl_socket->event.ctx);
299 return NT_STATUS_INTERNAL_ERROR;
302 status = wrepl_connect_recv(subreq);
304 NT_STATUS_NOT_OK_RETURN(status);
309 struct wrepl_request_state {
311 struct wrepl_socket *wrepl_socket;
312 struct tevent_context *ev;
314 struct wrepl_send_ctrl ctrl;
316 struct wrepl_wrap wrap;
323 struct wrepl_packet *packet;
327 static void wrepl_request_trigger(struct tevent_req *req,
330 struct tevent_req *wrepl_request_send(TALLOC_CTX *mem_ctx,
331 struct tevent_context *ev,
332 struct wrepl_socket *wrepl_socket,
333 const struct wrepl_packet *packet,
334 const struct wrepl_send_ctrl *ctrl)
336 struct tevent_req *req;
337 struct wrepl_request_state *state;
339 enum ndr_err_code ndr_err;
342 if (wrepl_socket->event.ctx != ev) {
343 /* TODO: remove wrepl_socket->event.ctx !!! */
344 smb_panic("wrepl_associate_stop_send event context mismatch!");
348 req = tevent_req_create(mem_ctx, &state,
349 struct wrepl_request_state);
354 state->caller.wrepl_socket = wrepl_socket;
355 state->caller.ev = ev;
361 if (wrepl_socket->stream == NULL) {
362 tevent_req_nterror(req, NT_STATUS_INVALID_CONNECTION);
363 return tevent_req_post(req, ev);
366 state->req.wrap.packet = *packet;
367 ndr_err = ndr_push_struct_blob(&state->req.blob, state,
369 (ndr_push_flags_fn_t)ndr_push_wrepl_wrap);
370 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
371 status = ndr_map_error2ntstatus(ndr_err);
372 tevent_req_nterror(req, status);
373 return tevent_req_post(req, ev);
376 state->req.iov.iov_base = state->req.blob.data;
377 state->req.iov.iov_len = state->req.blob.length;
379 ok = tevent_queue_add(wrepl_socket->request_queue,
382 wrepl_request_trigger,
385 tevent_req_nomem(NULL, req);
386 return tevent_req_post(req, ev);
389 if (wrepl_socket->request_timeout > 0) {
390 struct timeval endtime;
391 endtime = tevent_timeval_current_ofs(wrepl_socket->request_timeout, 0);
392 ok = tevent_req_set_endtime(req, ev, endtime);
394 return tevent_req_post(req, ev);
401 static void wrepl_request_writev_done(struct tevent_req *subreq);
403 static void wrepl_request_trigger(struct tevent_req *req,
406 struct wrepl_request_state *state = tevent_req_data(req,
407 struct wrepl_request_state);
408 struct tevent_req *subreq;
410 if (state->caller.wrepl_socket->stream == NULL) {
411 tevent_req_nterror(req, NT_STATUS_INVALID_CONNECTION);
416 DEBUG(10,("Sending WINS packet of length %u\n",
417 (unsigned)state->req.blob.length));
418 NDR_PRINT_DEBUG(wrepl_packet, &state->req.wrap.packet);
421 subreq = tstream_writev_send(state,
423 state->caller.wrepl_socket->stream,
425 if (tevent_req_nomem(subreq, req)) {
428 tevent_req_set_callback(subreq, wrepl_request_writev_done, req);
431 static void wrepl_request_disconnect_done(struct tevent_req *subreq);
432 static void wrepl_request_read_pdu_done(struct tevent_req *subreq);
434 static void wrepl_request_writev_done(struct tevent_req *subreq)
436 struct tevent_req *req = tevent_req_callback_data(subreq,
438 struct wrepl_request_state *state = tevent_req_data(req,
439 struct wrepl_request_state);
443 ret = tstream_writev_recv(subreq, &sys_errno);
446 NTSTATUS status = map_nt_error_from_unix(sys_errno);
447 TALLOC_FREE(state->caller.wrepl_socket->stream);
448 tevent_req_nterror(req, status);
452 if (state->caller.wrepl_socket->stream == NULL) {
453 tevent_req_nterror(req, NT_STATUS_INVALID_CONNECTION);
457 if (state->ctrl.disconnect_after_send) {
458 subreq = tstream_disconnect_send(state,
460 state->caller.wrepl_socket->stream);
461 if (tevent_req_nomem(subreq, req)) {
464 tevent_req_set_callback(subreq, wrepl_request_disconnect_done, req);
468 if (state->ctrl.send_only) {
469 tevent_req_done(req);
473 subreq = tstream_read_pdu_blob_send(state,
475 state->caller.wrepl_socket->stream,
476 4, /* initial_read_size */
477 packet_full_request_u32,
479 if (tevent_req_nomem(subreq, req)) {
482 tevent_req_set_callback(subreq, wrepl_request_read_pdu_done, req);
485 static void wrepl_request_disconnect_done(struct tevent_req *subreq)
487 struct tevent_req *req = tevent_req_callback_data(subreq,
489 struct wrepl_request_state *state = tevent_req_data(req,
490 struct wrepl_request_state);
494 ret = tstream_disconnect_recv(subreq, &sys_errno);
497 NTSTATUS status = map_nt_error_from_unix(sys_errno);
498 TALLOC_FREE(state->caller.wrepl_socket->stream);
499 tevent_req_nterror(req, status);
503 DEBUG(10,("WINS connection disconnected\n"));
504 TALLOC_FREE(state->caller.wrepl_socket->stream);
506 tevent_req_done(req);
509 static void wrepl_request_read_pdu_done(struct tevent_req *subreq)
511 struct tevent_req *req = tevent_req_callback_data(subreq,
513 struct wrepl_request_state *state = tevent_req_data(req,
514 struct wrepl_request_state);
517 enum ndr_err_code ndr_err;
519 status = tstream_read_pdu_blob_recv(subreq, state, &state->rep.blob);
520 if (!NT_STATUS_IS_OK(status)) {
521 TALLOC_FREE(state->caller.wrepl_socket->stream);
522 tevent_req_nterror(req, status);
526 state->rep.packet = talloc(state, struct wrepl_packet);
527 if (tevent_req_nomem(state->rep.packet, req)) {
531 blob.data = state->rep.blob.data + 4;
532 blob.length = state->rep.blob.length - 4;
534 /* we have a full request - parse it */
535 ndr_err = ndr_pull_struct_blob(&blob,
538 (ndr_pull_flags_fn_t)ndr_pull_wrepl_packet);
539 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
540 status = ndr_map_error2ntstatus(ndr_err);
541 tevent_req_nterror(req, status);
546 DEBUG(10,("Received WINS packet of length %u\n",
547 (unsigned)state->rep.blob.length));
548 NDR_PRINT_DEBUG(wrepl_packet, state->rep.packet);
551 tevent_req_done(req);
554 NTSTATUS wrepl_request_recv(struct tevent_req *req,
556 struct wrepl_packet **packet)
558 struct wrepl_request_state *state = tevent_req_data(req,
559 struct wrepl_request_state);
562 if (tevent_req_is_nterror(req, &status)) {
563 TALLOC_FREE(state->caller.wrepl_socket->stream);
564 tevent_req_received(req);
569 *packet = talloc_move(mem_ctx, &state->rep.packet);
572 tevent_req_received(req);
577 a full WINS replication request/response
579 NTSTATUS wrepl_request(struct wrepl_socket *wrepl_socket,
581 const struct wrepl_packet *req_packet,
582 struct wrepl_packet **reply_packet)
584 struct tevent_req *subreq;
588 subreq = wrepl_request_send(mem_ctx, wrepl_socket->event.ctx,
589 wrepl_socket, req_packet, NULL);
590 NT_STATUS_HAVE_NO_MEMORY(subreq);
592 ok = tevent_req_poll(subreq, wrepl_socket->event.ctx);
595 return NT_STATUS_INTERNAL_ERROR;
598 status = wrepl_request_recv(subreq, mem_ctx, reply_packet);
600 NT_STATUS_NOT_OK_RETURN(status);
606 struct wrepl_associate_state {
607 struct wrepl_packet packet;
609 uint16_t major_version;
612 static void wrepl_associate_done(struct tevent_req *subreq);
614 struct tevent_req *wrepl_associate_send(TALLOC_CTX *mem_ctx,
615 struct tevent_context *ev,
616 struct wrepl_socket *wrepl_socket,
617 const struct wrepl_associate *io)
619 struct tevent_req *req;
620 struct wrepl_associate_state *state;
621 struct tevent_req *subreq;
623 if (wrepl_socket->event.ctx != ev) {
624 /* TODO: remove wrepl_socket->event.ctx !!! */
625 smb_panic("wrepl_associate_send event context mismatch!");
629 req = tevent_req_create(mem_ctx, &state,
630 struct wrepl_associate_state);
635 state->packet.opcode = WREPL_OPCODE_BITS;
636 state->packet.mess_type = WREPL_START_ASSOCIATION;
637 state->packet.message.start.minor_version = 2;
638 state->packet.message.start.major_version = 5;
641 * nt4 uses 41 bytes for the start_association call
642 * so do it the same and as we don't know th emeanings of this bytes
643 * we just send zeros and nt4, w2k and w2k3 seems to be happy with this
645 * if we don't do this nt4 uses an old version of the wins replication protocol
646 * and that would break nt4 <-> samba replication
648 state->packet.padding = data_blob_talloc(state, NULL, 21);
649 if (tevent_req_nomem(state->packet.padding.data, req)) {
650 return tevent_req_post(req, ev);
652 memset(state->packet.padding.data, 0, state->packet.padding.length);
654 subreq = wrepl_request_send(state, ev, wrepl_socket, &state->packet, NULL);
655 if (tevent_req_nomem(subreq, req)) {
656 return tevent_req_post(req, ev);
658 tevent_req_set_callback(subreq, wrepl_associate_done, req);
663 static void wrepl_associate_done(struct tevent_req *subreq)
665 struct tevent_req *req = tevent_req_callback_data(subreq,
667 struct wrepl_associate_state *state = tevent_req_data(req,
668 struct wrepl_associate_state);
670 struct wrepl_packet *packet;
672 status = wrepl_request_recv(subreq, state, &packet);
674 if (!NT_STATUS_IS_OK(status)) {
675 tevent_req_nterror(req, status);
679 if (packet->mess_type != WREPL_START_ASSOCIATION_REPLY) {
680 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
684 state->assoc_ctx = packet->message.start_reply.assoc_ctx;
685 state->major_version = packet->message.start_reply.major_version;
687 tevent_req_done(req);
691 setup an association - recv
693 NTSTATUS wrepl_associate_recv(struct tevent_req *req,
694 struct wrepl_associate *io)
696 struct wrepl_associate_state *state = tevent_req_data(req,
697 struct wrepl_associate_state);
700 if (tevent_req_is_nterror(req, &status)) {
701 tevent_req_received(req);
705 io->out.assoc_ctx = state->assoc_ctx;
706 io->out.major_version = state->major_version;
708 tevent_req_received(req);
713 setup an association - sync api
715 NTSTATUS wrepl_associate(struct wrepl_socket *wrepl_socket,
716 struct wrepl_associate *io)
718 struct tevent_req *subreq;
722 subreq = wrepl_associate_send(wrepl_socket, wrepl_socket->event.ctx,
724 NT_STATUS_HAVE_NO_MEMORY(subreq);
726 ok = tevent_req_poll(subreq, wrepl_socket->event.ctx);
729 return NT_STATUS_INTERNAL_ERROR;
732 status = wrepl_associate_recv(subreq, io);
734 NT_STATUS_NOT_OK_RETURN(status);
739 struct wrepl_associate_stop_state {
740 struct wrepl_packet packet;
741 struct wrepl_send_ctrl ctrl;
744 static void wrepl_associate_stop_done(struct tevent_req *subreq);
746 struct tevent_req *wrepl_associate_stop_send(TALLOC_CTX *mem_ctx,
747 struct tevent_context *ev,
748 struct wrepl_socket *wrepl_socket,
749 const struct wrepl_associate_stop *io)
751 struct tevent_req *req;
752 struct wrepl_associate_stop_state *state;
753 struct tevent_req *subreq;
755 if (wrepl_socket->event.ctx != ev) {
756 /* TODO: remove wrepl_socket->event.ctx !!! */
757 smb_panic("wrepl_associate_stop_send event context mismatch!");
761 req = tevent_req_create(mem_ctx, &state,
762 struct wrepl_associate_stop_state);
767 state->packet.opcode = WREPL_OPCODE_BITS;
768 state->packet.assoc_ctx = io->in.assoc_ctx;
769 state->packet.mess_type = WREPL_STOP_ASSOCIATION;
770 state->packet.message.stop.reason = io->in.reason;
772 if (io->in.reason == 0) {
773 state->ctrl.send_only = true;
774 state->ctrl.disconnect_after_send = true;
777 subreq = wrepl_request_send(state, ev, wrepl_socket, &state->packet, &state->ctrl);
778 if (tevent_req_nomem(subreq, req)) {
779 return tevent_req_post(req, ev);
781 tevent_req_set_callback(subreq, wrepl_associate_stop_done, req);
786 static void wrepl_associate_stop_done(struct tevent_req *subreq)
788 struct tevent_req *req = tevent_req_callback_data(subreq,
790 struct wrepl_associate_stop_state *state = tevent_req_data(req,
791 struct wrepl_associate_stop_state);
794 /* currently we don't care about a possible response */
795 status = wrepl_request_recv(subreq, state, NULL);
797 if (!NT_STATUS_IS_OK(status)) {
798 tevent_req_nterror(req, status);
802 tevent_req_done(req);
806 stop an association - recv
808 NTSTATUS wrepl_associate_stop_recv(struct tevent_req *req,
809 struct wrepl_associate_stop *io)
813 if (tevent_req_is_nterror(req, &status)) {
814 tevent_req_received(req);
818 tevent_req_received(req);
823 setup an association - sync api
825 NTSTATUS wrepl_associate_stop(struct wrepl_socket *wrepl_socket,
826 struct wrepl_associate_stop *io)
828 struct tevent_req *subreq;
832 subreq = wrepl_associate_stop_send(wrepl_socket, wrepl_socket->event.ctx,
834 NT_STATUS_HAVE_NO_MEMORY(subreq);
836 ok = tevent_req_poll(subreq, wrepl_socket->event.ctx);
839 return NT_STATUS_INTERNAL_ERROR;
842 status = wrepl_associate_stop_recv(subreq, io);
844 NT_STATUS_NOT_OK_RETURN(status);
849 struct wrepl_pull_table_state {
850 struct wrepl_packet packet;
851 uint32_t num_partners;
852 struct wrepl_wins_owner *partners;
855 static void wrepl_pull_table_done(struct tevent_req *subreq);
857 struct tevent_req *wrepl_pull_table_send(TALLOC_CTX *mem_ctx,
858 struct tevent_context *ev,
859 struct wrepl_socket *wrepl_socket,
860 const struct wrepl_pull_table *io)
862 struct tevent_req *req;
863 struct wrepl_pull_table_state *state;
864 struct tevent_req *subreq;
866 if (wrepl_socket->event.ctx != ev) {
867 /* TODO: remove wrepl_socket->event.ctx !!! */
868 smb_panic("wrepl_pull_table_send event context mismatch!");
872 req = tevent_req_create(mem_ctx, &state,
873 struct wrepl_pull_table_state);
878 state->packet.opcode = WREPL_OPCODE_BITS;
879 state->packet.assoc_ctx = io->in.assoc_ctx;
880 state->packet.mess_type = WREPL_REPLICATION;
881 state->packet.message.replication.command = WREPL_REPL_TABLE_QUERY;
883 subreq = wrepl_request_send(state, ev, wrepl_socket, &state->packet, NULL);
884 if (tevent_req_nomem(subreq, req)) {
885 return tevent_req_post(req, ev);
887 tevent_req_set_callback(subreq, wrepl_pull_table_done, req);
892 static void wrepl_pull_table_done(struct tevent_req *subreq)
894 struct tevent_req *req = tevent_req_callback_data(subreq,
896 struct wrepl_pull_table_state *state = tevent_req_data(req,
897 struct wrepl_pull_table_state);
899 struct wrepl_packet *packet;
900 struct wrepl_table *table;
902 status = wrepl_request_recv(subreq, state, &packet);
904 if (!NT_STATUS_IS_OK(status)) {
905 tevent_req_nterror(req, status);
909 if (packet->mess_type != WREPL_REPLICATION) {
910 tevent_req_nterror(req, NT_STATUS_NETWORK_ACCESS_DENIED);
914 if (packet->message.replication.command != WREPL_REPL_TABLE_REPLY) {
915 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
919 table = &packet->message.replication.info.table;
921 state->num_partners = table->partner_count;
922 state->partners = talloc_move(state, &table->partners);
924 tevent_req_done(req);
928 fetch the partner tables - recv
930 NTSTATUS wrepl_pull_table_recv(struct tevent_req *req,
932 struct wrepl_pull_table *io)
934 struct wrepl_pull_table_state *state = tevent_req_data(req,
935 struct wrepl_pull_table_state);
938 if (tevent_req_is_nterror(req, &status)) {
939 tevent_req_received(req);
943 io->out.num_partners = state->num_partners;
944 io->out.partners = talloc_move(mem_ctx, &state->partners);
946 tevent_req_received(req);
951 fetch the partner table - sync api
953 NTSTATUS wrepl_pull_table(struct wrepl_socket *wrepl_socket,
955 struct wrepl_pull_table *io)
957 struct tevent_req *subreq;
961 subreq = wrepl_pull_table_send(mem_ctx, wrepl_socket->event.ctx,
963 NT_STATUS_HAVE_NO_MEMORY(subreq);
965 ok = tevent_req_poll(subreq, wrepl_socket->event.ctx);
968 return NT_STATUS_INTERNAL_ERROR;
971 status = wrepl_pull_table_recv(subreq, mem_ctx, io);
973 NT_STATUS_NOT_OK_RETURN(status);
979 struct wrepl_pull_names_state {
981 const struct wrepl_pull_names *io;
983 struct wrepl_packet packet;
985 struct wrepl_name *names;
988 static void wrepl_pull_names_done(struct tevent_req *subreq);
990 struct tevent_req *wrepl_pull_names_send(TALLOC_CTX *mem_ctx,
991 struct tevent_context *ev,
992 struct wrepl_socket *wrepl_socket,
993 const struct wrepl_pull_names *io)
995 struct tevent_req *req;
996 struct wrepl_pull_names_state *state;
997 struct tevent_req *subreq;
999 if (wrepl_socket->event.ctx != ev) {
1000 /* TODO: remove wrepl_socket->event.ctx !!! */
1001 smb_panic("wrepl_pull_names_send event context mismatch!");
1005 req = tevent_req_create(mem_ctx, &state,
1006 struct wrepl_pull_names_state);
1010 state->caller.io = io;
1012 state->packet.opcode = WREPL_OPCODE_BITS;
1013 state->packet.assoc_ctx = io->in.assoc_ctx;
1014 state->packet.mess_type = WREPL_REPLICATION;
1015 state->packet.message.replication.command = WREPL_REPL_SEND_REQUEST;
1016 state->packet.message.replication.info.owner = io->in.partner;
1018 subreq = wrepl_request_send(state, ev, wrepl_socket, &state->packet, NULL);
1019 if (tevent_req_nomem(subreq, req)) {
1020 return tevent_req_post(req, ev);
1022 tevent_req_set_callback(subreq, wrepl_pull_names_done, req);
1027 static void wrepl_pull_names_done(struct tevent_req *subreq)
1029 struct tevent_req *req = tevent_req_callback_data(subreq,
1031 struct wrepl_pull_names_state *state = tevent_req_data(req,
1032 struct wrepl_pull_names_state);
1034 struct wrepl_packet *packet;
1037 status = wrepl_request_recv(subreq, state, &packet);
1038 TALLOC_FREE(subreq);
1039 if (!NT_STATUS_IS_OK(status)) {
1040 tevent_req_nterror(req, status);
1044 if (packet->mess_type != WREPL_REPLICATION) {
1045 tevent_req_nterror(req, NT_STATUS_NETWORK_ACCESS_DENIED);
1049 if (packet->message.replication.command != WREPL_REPL_SEND_REPLY) {
1050 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
1054 state->num_names = packet->message.replication.info.reply.num_names;
1056 state->names = talloc_array(state, struct wrepl_name, state->num_names);
1057 if (tevent_req_nomem(state->names, req)) {
1061 /* convert the list of names and addresses to a sane format */
1062 for (i=0; i < state->num_names; i++) {
1063 struct wrepl_wins_name *wname = &packet->message.replication.info.reply.names[i];
1064 struct wrepl_name *name = &state->names[i];
1066 name->name = *wname->name;
1067 talloc_steal(state->names, wname->name);
1068 name->type = WREPL_NAME_TYPE(wname->flags);
1069 name->state = WREPL_NAME_STATE(wname->flags);
1070 name->node = WREPL_NAME_NODE(wname->flags);
1071 name->is_static = WREPL_NAME_IS_STATIC(wname->flags);
1072 name->raw_flags = wname->flags;
1073 name->version_id= wname->id;
1074 name->owner = talloc_strdup(state->names,
1075 state->caller.io->in.partner.address);
1076 if (tevent_req_nomem(name->owner, req)) {
1080 /* trying to save 1 or 2 bytes on the wire isn't a good idea */
1081 if (wname->flags & 2) {
1084 name->num_addresses = wname->addresses.addresses.num_ips;
1085 name->addresses = talloc_array(state->names,
1086 struct wrepl_address,
1087 name->num_addresses);
1088 if (tevent_req_nomem(name->addresses, req)) {
1092 for (j=0;j<name->num_addresses;j++) {
1093 name->addresses[j].owner =
1094 talloc_move(name->addresses,
1095 &wname->addresses.addresses.ips[j].owner);
1096 name->addresses[j].address =
1097 talloc_move(name->addresses,
1098 &wname->addresses.addresses.ips[j].ip);
1101 name->num_addresses = 1;
1102 name->addresses = talloc_array(state->names,
1103 struct wrepl_address,
1104 name->num_addresses);
1105 if (tevent_req_nomem(name->addresses, req)) {
1109 name->addresses[0].owner = talloc_strdup(name->addresses, name->owner);
1110 if (tevent_req_nomem(name->addresses[0].owner, req)) {
1113 name->addresses[0].address = talloc_move(name->addresses,
1114 &wname->addresses.ip);
1118 tevent_req_done(req);
1122 fetch the names for a WINS partner - recv
1124 NTSTATUS wrepl_pull_names_recv(struct tevent_req *req,
1125 TALLOC_CTX *mem_ctx,
1126 struct wrepl_pull_names *io)
1128 struct wrepl_pull_names_state *state = tevent_req_data(req,
1129 struct wrepl_pull_names_state);
1132 if (tevent_req_is_nterror(req, &status)) {
1133 tevent_req_received(req);
1137 io->out.num_names = state->num_names;
1138 io->out.names = talloc_move(mem_ctx, &state->names);
1140 tevent_req_received(req);
1141 return NT_STATUS_OK;
1147 fetch the names for a WINS partner - sync api
1149 NTSTATUS wrepl_pull_names(struct wrepl_socket *wrepl_socket,
1150 TALLOC_CTX *mem_ctx,
1151 struct wrepl_pull_names *io)
1153 struct tevent_req *subreq;
1157 subreq = wrepl_pull_names_send(mem_ctx, wrepl_socket->event.ctx,
1159 NT_STATUS_HAVE_NO_MEMORY(subreq);
1161 ok = tevent_req_poll(subreq, wrepl_socket->event.ctx);
1163 TALLOC_FREE(subreq);
1164 return NT_STATUS_INTERNAL_ERROR;
1167 status = wrepl_pull_names_recv(subreq, mem_ctx, io);
1168 TALLOC_FREE(subreq);
1169 NT_STATUS_NOT_OK_RETURN(status);
1171 return NT_STATUS_OK;