smbd: First watch, then defer
[Samba.git] / source4 / libcli / wrepl / winsrepl.c
blobeab7430e42b6bd29063ad0a7b1c8eb068347f3ab
1 /*
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/>.
23 #include "includes.h"
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
39 struct wrepl_socket {
40 struct {
41 struct tevent_context *ctx;
42 } event;
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)
55 if (!wrepl_sock) {
56 return false;
59 if (!wrepl_sock->stream) {
60 return false;
63 return true;
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);
76 if (!wrepl_socket) {
77 return NULL;
80 wrepl_socket->event.ctx = event_ctx;
81 if (!wrepl_socket->event.ctx) {
82 goto failed;
85 wrepl_socket->request_queue = tevent_queue_create(wrepl_socket,
86 "wrepl request queue");
87 if (wrepl_socket->request_queue == NULL) {
88 goto failed;
91 wrepl_socket->request_timeout = WREPL_SOCKET_REQUEST_TIMEOUT;
93 return wrepl_socket;
95 failed:
96 talloc_free(wrepl_socket);
97 return NULL;
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);
111 return NT_STATUS_OK;
115 initialise a wrepl_socket from an already existing connection
117 NTSTATUS wrepl_socket_split_stream(struct wrepl_socket *wrepl_socket,
118 TALLOC_CTX *mem_ctx,
119 struct tstream_context **stream)
121 size_t num_requests;
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);
133 return NT_STATUS_OK;
136 const char *wrepl_best_ip(struct loadparm_context *lp_ctx, const char *peer_ip)
138 struct interface *ifaces;
139 load_interface_list(lp_ctx, lp_ctx, &ifaces);
140 return iface_list_best_ip(ifaces, peer_ip);
143 struct wrepl_connect_state {
144 struct {
145 struct wrepl_socket *wrepl_socket;
146 struct tevent_context *ev;
147 } caller;
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,
154 void *private_date);
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;
163 int ret;
164 bool ok;
166 req = tevent_req_create(mem_ctx, &state,
167 struct wrepl_connect_state);
168 if (req == NULL) {
169 return NULL;
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",
181 our_ip, 0,
182 &state->local_address);
183 if (ret != 0) {
184 NTSTATUS status = map_nt_error_from_unix_common(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);
192 if (ret != 0) {
193 NTSTATUS status = map_nt_error_from_unix_common(errno);
194 tevent_req_nterror(req, status);
195 return tevent_req_post(req, ev);
198 ok = tevent_queue_add(wrepl_socket->request_queue,
200 req,
201 wrepl_connect_trigger,
202 NULL);
203 if (!ok) {
204 tevent_req_oom(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);
212 if (!ok) {
213 return tevent_req_post(req, ev);
217 return req;
220 static void wrepl_connect_done(struct tevent_req *subreq);
222 static void wrepl_connect_trigger(struct tevent_req *req,
223 void *private_date)
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,
230 state->caller.ev,
231 state->local_address,
232 state->remote_address);
233 if (tevent_req_nomem(subreq, req)) {
234 return;
236 tevent_req_set_callback(subreq, wrepl_connect_done, req);
238 return;
241 static void wrepl_connect_done(struct tevent_req *subreq)
243 struct tevent_req *req = tevent_req_callback_data(subreq,
244 struct tevent_req);
245 struct wrepl_connect_state *state = tevent_req_data(req,
246 struct wrepl_connect_state);
247 int ret;
248 int sys_errno;
250 ret = tstream_inet_tcp_connect_recv(subreq, &sys_errno,
251 state, &state->stream, NULL);
252 if (ret != 0) {
253 NTSTATUS status = map_nt_error_from_unix_common(sys_errno);
254 tevent_req_nterror(req, status);
255 return;
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;
269 NTSTATUS status;
271 if (tevent_req_is_nterror(req, &status)) {
272 tevent_req_received(req);
273 return status;
276 wrepl_socket->stream = talloc_move(wrepl_socket, &state->stream);
278 tevent_req_received(req);
279 return NT_STATUS_OK;
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;
289 bool ok;
290 NTSTATUS status;
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);
297 if (!ok) {
298 TALLOC_FREE(subreq);
299 return NT_STATUS_INTERNAL_ERROR;
302 status = wrepl_connect_recv(subreq);
303 TALLOC_FREE(subreq);
304 NT_STATUS_NOT_OK_RETURN(status);
306 return NT_STATUS_OK;
309 struct wrepl_request_state {
310 struct {
311 struct wrepl_socket *wrepl_socket;
312 struct tevent_context *ev;
313 } caller;
314 struct wrepl_send_ctrl ctrl;
315 struct {
316 struct wrepl_wrap wrap;
317 DATA_BLOB blob;
318 struct iovec iov;
319 } req;
320 bool one_way;
321 struct {
322 DATA_BLOB blob;
323 struct wrepl_packet *packet;
324 } rep;
327 static void wrepl_request_trigger(struct tevent_req *req,
328 void *private_data);
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;
338 NTSTATUS status;
339 enum ndr_err_code ndr_err;
340 bool ok;
342 if (wrepl_socket->event.ctx != ev) {
343 /* TODO: remove wrepl_socket->event.ctx !!! */
344 smb_panic("wrepl_associate_stop_send event context mismatch!");
345 return NULL;
348 req = tevent_req_create(mem_ctx, &state,
349 struct wrepl_request_state);
350 if (req == NULL) {
351 return NULL;
354 state->caller.wrepl_socket = wrepl_socket;
355 state->caller.ev = ev;
357 if (ctrl) {
358 state->ctrl = *ctrl;
361 if (wrepl_socket->stream == NULL) {
362 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
363 return tevent_req_post(req, ev);
366 state->req.wrap.packet = *packet;
367 ndr_err = ndr_push_struct_blob(&state->req.blob, state,
368 &state->req.wrap,
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 = (char *) state->req.blob.data;
377 state->req.iov.iov_len = state->req.blob.length;
379 ok = tevent_queue_add(wrepl_socket->request_queue,
381 req,
382 wrepl_request_trigger,
383 NULL);
384 if (!ok) {
385 tevent_req_oom(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);
393 if (!ok) {
394 return tevent_req_post(req, ev);
398 return req;
401 static void wrepl_request_writev_done(struct tevent_req *subreq);
403 static void wrepl_request_trigger(struct tevent_req *req,
404 void *private_data)
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_CONNECTION_DISCONNECTED);
412 return;
415 if (DEBUGLVL(10)) {
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,
422 state->caller.ev,
423 state->caller.wrepl_socket->stream,
424 &state->req.iov, 1);
425 if (tevent_req_nomem(subreq, req)) {
426 return;
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,
437 struct tevent_req);
438 struct wrepl_request_state *state = tevent_req_data(req,
439 struct wrepl_request_state);
440 int ret;
441 int sys_errno;
443 ret = tstream_writev_recv(subreq, &sys_errno);
444 TALLOC_FREE(subreq);
445 if (ret == -1) {
446 NTSTATUS status = map_nt_error_from_unix_common(sys_errno);
447 TALLOC_FREE(state->caller.wrepl_socket->stream);
448 tevent_req_nterror(req, status);
449 return;
452 if (state->caller.wrepl_socket->stream == NULL) {
453 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
454 return;
457 if (state->ctrl.disconnect_after_send) {
458 subreq = tstream_disconnect_send(state,
459 state->caller.ev,
460 state->caller.wrepl_socket->stream);
461 if (tevent_req_nomem(subreq, req)) {
462 return;
464 tevent_req_set_callback(subreq, wrepl_request_disconnect_done, req);
465 return;
468 if (state->ctrl.send_only) {
469 tevent_req_done(req);
470 return;
473 subreq = tstream_read_pdu_blob_send(state,
474 state->caller.ev,
475 state->caller.wrepl_socket->stream,
476 4, /* initial_read_size */
477 packet_full_request_u32,
478 NULL);
479 if (tevent_req_nomem(subreq, req)) {
480 return;
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,
488 struct tevent_req);
489 struct wrepl_request_state *state = tevent_req_data(req,
490 struct wrepl_request_state);
491 int ret;
492 int sys_errno;
494 ret = tstream_disconnect_recv(subreq, &sys_errno);
495 TALLOC_FREE(subreq);
496 if (ret == -1) {
497 NTSTATUS status = map_nt_error_from_unix_common(sys_errno);
498 TALLOC_FREE(state->caller.wrepl_socket->stream);
499 tevent_req_nterror(req, status);
500 return;
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,
512 struct tevent_req);
513 struct wrepl_request_state *state = tevent_req_data(req,
514 struct wrepl_request_state);
515 NTSTATUS status;
516 DATA_BLOB blob;
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);
523 return;
526 state->rep.packet = talloc(state, struct wrepl_packet);
527 if (tevent_req_nomem(state->rep.packet, req)) {
528 return;
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,
536 state->rep.packet,
537 state->rep.packet,
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);
542 return;
545 if (DEBUGLVL(10)) {
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,
555 TALLOC_CTX *mem_ctx,
556 struct wrepl_packet **packet)
558 struct wrepl_request_state *state = tevent_req_data(req,
559 struct wrepl_request_state);
560 NTSTATUS status;
562 if (tevent_req_is_nterror(req, &status)) {
563 TALLOC_FREE(state->caller.wrepl_socket->stream);
564 tevent_req_received(req);
565 return status;
568 if (packet) {
569 *packet = talloc_move(mem_ctx, &state->rep.packet);
572 tevent_req_received(req);
573 return NT_STATUS_OK;
577 a full WINS replication request/response
579 NTSTATUS wrepl_request(struct wrepl_socket *wrepl_socket,
580 TALLOC_CTX *mem_ctx,
581 const struct wrepl_packet *req_packet,
582 struct wrepl_packet **reply_packet)
584 struct tevent_req *subreq;
585 bool ok;
586 NTSTATUS status;
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);
593 if (!ok) {
594 TALLOC_FREE(subreq);
595 return NT_STATUS_INTERNAL_ERROR;
598 status = wrepl_request_recv(subreq, mem_ctx, reply_packet);
599 TALLOC_FREE(subreq);
600 NT_STATUS_NOT_OK_RETURN(status);
602 return NT_STATUS_OK;
606 struct wrepl_associate_state {
607 struct wrepl_packet packet;
608 uint32_t assoc_ctx;
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!");
626 return NULL;
629 req = tevent_req_create(mem_ctx, &state,
630 struct wrepl_associate_state);
631 if (req == NULL) {
632 return NULL;
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);
660 return req;
663 static void wrepl_associate_done(struct tevent_req *subreq)
665 struct tevent_req *req = tevent_req_callback_data(subreq,
666 struct tevent_req);
667 struct wrepl_associate_state *state = tevent_req_data(req,
668 struct wrepl_associate_state);
669 NTSTATUS status;
670 struct wrepl_packet *packet;
672 status = wrepl_request_recv(subreq, state, &packet);
673 TALLOC_FREE(subreq);
674 if (!NT_STATUS_IS_OK(status)) {
675 tevent_req_nterror(req, status);
676 return;
679 if (packet->mess_type != WREPL_START_ASSOCIATION_REPLY) {
680 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
681 return;
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);
698 NTSTATUS status;
700 if (tevent_req_is_nterror(req, &status)) {
701 tevent_req_received(req);
702 return status;
705 io->out.assoc_ctx = state->assoc_ctx;
706 io->out.major_version = state->major_version;
708 tevent_req_received(req);
709 return NT_STATUS_OK;
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;
719 bool ok;
720 NTSTATUS status;
722 subreq = wrepl_associate_send(wrepl_socket, wrepl_socket->event.ctx,
723 wrepl_socket, io);
724 NT_STATUS_HAVE_NO_MEMORY(subreq);
726 ok = tevent_req_poll(subreq, wrepl_socket->event.ctx);
727 if (!ok) {
728 TALLOC_FREE(subreq);
729 return NT_STATUS_INTERNAL_ERROR;
732 status = wrepl_associate_recv(subreq, io);
733 TALLOC_FREE(subreq);
734 NT_STATUS_NOT_OK_RETURN(status);
736 return NT_STATUS_OK;
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!");
758 return NULL;
761 req = tevent_req_create(mem_ctx, &state,
762 struct wrepl_associate_stop_state);
763 if (req == NULL) {
764 return NULL;
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);
783 return req;
786 static void wrepl_associate_stop_done(struct tevent_req *subreq)
788 struct tevent_req *req = tevent_req_callback_data(subreq,
789 struct tevent_req);
790 struct wrepl_associate_stop_state *state = tevent_req_data(req,
791 struct wrepl_associate_stop_state);
792 NTSTATUS status;
794 /* currently we don't care about a possible response */
795 status = wrepl_request_recv(subreq, state, NULL);
796 TALLOC_FREE(subreq);
797 if (!NT_STATUS_IS_OK(status)) {
798 tevent_req_nterror(req, status);
799 return;
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)
811 NTSTATUS status;
813 if (tevent_req_is_nterror(req, &status)) {
814 tevent_req_received(req);
815 return status;
818 tevent_req_received(req);
819 return NT_STATUS_OK;
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;
829 bool ok;
830 NTSTATUS status;
832 subreq = wrepl_associate_stop_send(wrepl_socket, wrepl_socket->event.ctx,
833 wrepl_socket, io);
834 NT_STATUS_HAVE_NO_MEMORY(subreq);
836 ok = tevent_req_poll(subreq, wrepl_socket->event.ctx);
837 if (!ok) {
838 TALLOC_FREE(subreq);
839 return NT_STATUS_INTERNAL_ERROR;
842 status = wrepl_associate_stop_recv(subreq, io);
843 TALLOC_FREE(subreq);
844 NT_STATUS_NOT_OK_RETURN(status);
846 return NT_STATUS_OK;
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!");
869 return NULL;
872 req = tevent_req_create(mem_ctx, &state,
873 struct wrepl_pull_table_state);
874 if (req == NULL) {
875 return NULL;
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);
889 return req;
892 static void wrepl_pull_table_done(struct tevent_req *subreq)
894 struct tevent_req *req = tevent_req_callback_data(subreq,
895 struct tevent_req);
896 struct wrepl_pull_table_state *state = tevent_req_data(req,
897 struct wrepl_pull_table_state);
898 NTSTATUS status;
899 struct wrepl_packet *packet;
900 struct wrepl_table *table;
902 status = wrepl_request_recv(subreq, state, &packet);
903 TALLOC_FREE(subreq);
904 if (!NT_STATUS_IS_OK(status)) {
905 tevent_req_nterror(req, status);
906 return;
909 if (packet->mess_type != WREPL_REPLICATION) {
910 tevent_req_nterror(req, NT_STATUS_NETWORK_ACCESS_DENIED);
911 return;
914 if (packet->message.replication.command != WREPL_REPL_TABLE_REPLY) {
915 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
916 return;
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,
931 TALLOC_CTX *mem_ctx,
932 struct wrepl_pull_table *io)
934 struct wrepl_pull_table_state *state = tevent_req_data(req,
935 struct wrepl_pull_table_state);
936 NTSTATUS status;
938 if (tevent_req_is_nterror(req, &status)) {
939 tevent_req_received(req);
940 return status;
943 io->out.num_partners = state->num_partners;
944 io->out.partners = talloc_move(mem_ctx, &state->partners);
946 tevent_req_received(req);
947 return NT_STATUS_OK;
951 fetch the partner table - sync api
953 NTSTATUS wrepl_pull_table(struct wrepl_socket *wrepl_socket,
954 TALLOC_CTX *mem_ctx,
955 struct wrepl_pull_table *io)
957 struct tevent_req *subreq;
958 bool ok;
959 NTSTATUS status;
961 subreq = wrepl_pull_table_send(mem_ctx, wrepl_socket->event.ctx,
962 wrepl_socket, io);
963 NT_STATUS_HAVE_NO_MEMORY(subreq);
965 ok = tevent_req_poll(subreq, wrepl_socket->event.ctx);
966 if (!ok) {
967 TALLOC_FREE(subreq);
968 return NT_STATUS_INTERNAL_ERROR;
971 status = wrepl_pull_table_recv(subreq, mem_ctx, io);
972 TALLOC_FREE(subreq);
973 NT_STATUS_NOT_OK_RETURN(status);
975 return NT_STATUS_OK;
979 struct wrepl_pull_names_state {
980 struct {
981 const struct wrepl_pull_names *io;
982 } caller;
983 struct wrepl_packet packet;
984 uint32_t num_names;
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!");
1002 return NULL;
1005 req = tevent_req_create(mem_ctx, &state,
1006 struct wrepl_pull_names_state);
1007 if (req == NULL) {
1008 return NULL;
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);
1024 return req;
1027 static void wrepl_pull_names_done(struct tevent_req *subreq)
1029 struct tevent_req *req = tevent_req_callback_data(subreq,
1030 struct tevent_req);
1031 struct wrepl_pull_names_state *state = tevent_req_data(req,
1032 struct wrepl_pull_names_state);
1033 NTSTATUS status;
1034 struct wrepl_packet *packet;
1035 uint32_t i;
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);
1041 return;
1044 if (packet->mess_type != WREPL_REPLICATION) {
1045 tevent_req_nterror(req, NT_STATUS_NETWORK_ACCESS_DENIED);
1046 return;
1049 if (packet->message.replication.command != WREPL_REPL_SEND_REPLY) {
1050 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
1051 return;
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)) {
1058 return;
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)) {
1077 return;
1080 /* trying to save 1 or 2 bytes on the wire isn't a good idea */
1081 if (wname->flags & 2) {
1082 uint32_t j;
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)) {
1089 return;
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);
1100 } else {
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)) {
1106 return;
1109 name->addresses[0].owner = talloc_strdup(name->addresses, name->owner);
1110 if (tevent_req_nomem(name->addresses[0].owner, req)) {
1111 return;
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);
1130 NTSTATUS status;
1132 if (tevent_req_is_nterror(req, &status)) {
1133 tevent_req_received(req);
1134 return status;
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;
1154 bool ok;
1155 NTSTATUS status;
1157 subreq = wrepl_pull_names_send(mem_ctx, wrepl_socket->event.ctx,
1158 wrepl_socket, io);
1159 NT_STATUS_HAVE_NO_MEMORY(subreq);
1161 ok = tevent_req_poll(subreq, wrepl_socket->event.ctx);
1162 if (!ok) {
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;