r12200: - move the the winsreplication client and server code to the packet_context
[metze/samba/wip.git] / source4 / libcli / wrepl / winsrepl.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    low level WINS replication client code
5
6    Copyright (C) Andrew Tridgell 2005
7    
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
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.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "includes.h"
24 #include "lib/events/events.h"
25 #include "dlinklist.h"
26 #include "lib/socket/socket.h"
27 #include "libcli/wrepl/winsrepl.h"
28 #include "lib/stream/packet.h"
29 #include "libcli/composite/composite.h"
30
31 static struct wrepl_request *wrepl_request_finished(struct wrepl_request *req, NTSTATUS status);
32
33 /*
34   mark all pending requests as dead - called when a socket error happens
35 */
36 static void wrepl_socket_dead(struct wrepl_socket *wrepl_socket, NTSTATUS status)
37 {
38         talloc_set_destructor(wrepl_socket, NULL);
39         wrepl_socket->dead = True;
40
41         if (wrepl_socket->event.fde) {
42                 packet_recv_disable(wrepl_socket->packet);
43                 packet_set_fde(wrepl_socket->packet, NULL);
44                 talloc_free(wrepl_socket->event.fde);
45                 wrepl_socket->event.fde = NULL;
46         }
47
48         if (wrepl_socket->sock) {
49                 packet_set_socket(wrepl_socket->packet, NULL);
50                 talloc_free(wrepl_socket->sock);
51                 wrepl_socket->sock = NULL;
52         }
53
54         if (NT_STATUS_EQUAL(NT_STATUS_UNSUCCESSFUL, status)) {
55                 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
56         }
57         while (wrepl_socket->recv_queue) {
58                 struct wrepl_request *req = wrepl_socket->recv_queue;
59                 DLIST_REMOVE(wrepl_socket->recv_queue, req);
60                 wrepl_request_finished(req, status);
61         }
62 }
63
64 static void wrepl_request_timeout_handler(struct event_context *ev, struct timed_event *te,
65                                           struct timeval t, void *ptr)
66 {
67         struct wrepl_request *req = talloc_get_type(ptr, struct wrepl_request);
68         wrepl_socket_dead(req->wrepl_socket, NT_STATUS_IO_TIMEOUT);
69 }
70
71 /*
72   handle recv events 
73 */
74 static NTSTATUS wrepl_finish_recv(void *private, DATA_BLOB packet_blob_in)
75 {
76         struct wrepl_socket *wrepl_socket = talloc_get_type(private, struct wrepl_socket);
77         struct wrepl_request *req = wrepl_socket->recv_queue;
78         DATA_BLOB blob;
79
80         req->packet = talloc(req, struct wrepl_packet);
81         NT_STATUS_HAVE_NO_MEMORY(req->packet);
82
83         blob.data = packet_blob_in.data + 4;
84         blob.length = packet_blob_in.length - 4;
85         
86         /* we have a full request - parse it */
87         req->status = ndr_pull_struct_blob(&blob,
88                                            req->packet, req->packet,
89                                            (ndr_pull_flags_fn_t)ndr_pull_wrepl_packet);
90         if (!NT_STATUS_IS_OK(req->status)) {
91                 wrepl_request_finished(req, req->status);
92                 return NT_STATUS_OK;
93         }
94
95         if (DEBUGLVL(10)) {
96                 DEBUG(10,("Received WINS packet of length %u\n", packet_blob_in.length));
97                 NDR_PRINT_DEBUG(wrepl_packet, req->packet);
98         }
99
100         wrepl_request_finished(req, req->status);
101         return NT_STATUS_OK;
102 }
103
104 /*
105   handler for winrepl events
106 */
107 static void wrepl_handler(struct event_context *ev, struct fd_event *fde, 
108                           uint16_t flags, void *private)
109 {
110         struct wrepl_socket *wrepl_socket = talloc_get_type(private, 
111                                                             struct wrepl_socket);
112         if (flags & EVENT_FD_READ) {
113                 packet_recv(wrepl_socket->packet);
114                 return;
115         }
116         if (flags & EVENT_FD_WRITE) {
117                 packet_queue_run(wrepl_socket->packet);
118         }
119 }
120
121 static void wrepl_error(void *private, NTSTATUS status)
122 {
123         struct wrepl_socket *wrepl_socket = talloc_get_type(private, 
124                                                             struct wrepl_socket);
125         wrepl_socket_dead(wrepl_socket, status);
126 }
127
128
129 /*
130   destroy a wrepl_socket destructor
131 */
132 static int wrepl_socket_destructor(void *ptr)
133 {
134         struct wrepl_socket *sock = talloc_get_type(ptr, struct wrepl_socket);
135         wrepl_socket_dead(sock, NT_STATUS_LOCAL_DISCONNECT);
136         return 0;
137 }
138
139 /*
140   initialise a wrepl_socket. The event_ctx is optional, if provided then
141   operations will use that event context
142 */
143 struct wrepl_socket *wrepl_socket_init(TALLOC_CTX *mem_ctx, 
144                                        struct event_context *event_ctx)
145 {
146         struct wrepl_socket *wrepl_socket;
147         NTSTATUS status;
148
149         wrepl_socket = talloc_zero(mem_ctx, struct wrepl_socket);
150         if (!wrepl_socket) return NULL;
151
152         if (event_ctx == NULL) {
153                 wrepl_socket->event.ctx = event_context_init(wrepl_socket);
154         } else {
155                 wrepl_socket->event.ctx = talloc_reference(wrepl_socket, event_ctx);
156         }
157         if (!wrepl_socket->event.ctx) goto failed;
158
159         status = socket_create("ip", SOCKET_TYPE_STREAM, &wrepl_socket->sock, 0);
160         if (!NT_STATUS_IS_OK(status)) goto failed;
161
162         talloc_steal(wrepl_socket, wrepl_socket->sock);
163
164         wrepl_socket->request_timeout   = WREPL_SOCKET_REQUEST_TIMEOUT;
165
166         talloc_set_destructor(wrepl_socket, wrepl_socket_destructor);
167
168         return wrepl_socket;
169
170 failed:
171         talloc_free(wrepl_socket);
172         return NULL;
173 }
174
175 /*
176   initialise a wrepl_socket from an already existing connection
177 */
178 struct wrepl_socket *wrepl_socket_merge(TALLOC_CTX *mem_ctx, 
179                                         struct event_context *event_ctx,
180                                         struct socket_context *socket,
181                                         struct packet_context *packet)
182 {
183         struct wrepl_socket *wrepl_socket;
184
185         wrepl_socket = talloc_zero(mem_ctx, struct wrepl_socket);
186         if (wrepl_socket == NULL) goto failed;
187
188         wrepl_socket->event.ctx = talloc_reference(wrepl_socket, event_ctx);
189         if (wrepl_socket->event.ctx == NULL) goto failed;
190
191         wrepl_socket->sock = socket;
192         talloc_steal(wrepl_socket, wrepl_socket->sock);
193
194
195         wrepl_socket->request_timeout   = WREPL_SOCKET_REQUEST_TIMEOUT;
196
197         wrepl_socket->event.fde = event_add_fd(wrepl_socket->event.ctx, wrepl_socket,
198                                                socket_get_fd(wrepl_socket->sock), 
199                                                EVENT_FD_READ,
200                                                wrepl_handler, wrepl_socket);
201         if (wrepl_socket->event.fde == NULL) {
202                 goto failed;
203         }
204
205         wrepl_socket->packet = packet;
206         talloc_steal(wrepl_socket, wrepl_socket->packet);
207         packet_set_private(wrepl_socket->packet, wrepl_socket);
208         packet_set_socket(wrepl_socket->packet, wrepl_socket->sock);
209         packet_set_callback(wrepl_socket->packet, wrepl_finish_recv);
210         packet_set_full_request(wrepl_socket->packet, packet_full_request_u32);
211         packet_set_error_handler(wrepl_socket->packet, wrepl_error);
212         packet_set_event_context(wrepl_socket->packet, wrepl_socket->event.ctx);
213         packet_set_fde(wrepl_socket->packet, wrepl_socket->event.fde);
214         packet_set_serialise(wrepl_socket->packet);
215
216         talloc_set_destructor(wrepl_socket, wrepl_socket_destructor);
217         
218         return wrepl_socket;
219
220 failed:
221         talloc_free(wrepl_socket);
222         return NULL;
223 }
224
225 /*
226   destroy a wrepl_request
227 */
228 static int wrepl_request_destructor(void *ptr)
229 {
230         struct wrepl_request *req = talloc_get_type(ptr, struct wrepl_request);
231         if (req->state == WREPL_REQUEST_RECV) {
232                 DLIST_REMOVE(req->wrepl_socket->recv_queue, req);
233         }
234         req->state = WREPL_REQUEST_ERROR;
235         return 0;
236 }
237
238 /*
239   wait for a request to complete
240 */
241 static NTSTATUS wrepl_request_wait(struct wrepl_request *req)
242 {
243         NT_STATUS_HAVE_NO_MEMORY(req);
244         while (req->state < WREPL_REQUEST_DONE) {
245                 event_loop_once(req->wrepl_socket->event.ctx);
246         }
247         return req->status;
248 }
249
250 struct wrepl_connect_state {
251         struct composite_context *result;
252         struct wrepl_socket *wrepl_socket;
253         struct composite_context *creq;
254 };
255
256 /*
257   handler for winrepl connection completion
258 */
259 static void wrepl_connect_handler(struct composite_context *creq)
260 {
261         struct wrepl_connect_state *state = talloc_get_type(creq->async.private_data, 
262                                             struct wrepl_connect_state);
263         struct wrepl_socket *wrepl_socket = state->wrepl_socket;
264         struct composite_context *result = state->result;
265
266         result->status = socket_connect_recv(state->creq);
267         if (!composite_is_ok(result)) return;
268
269         wrepl_socket->event.fde = event_add_fd(wrepl_socket->event.ctx, wrepl_socket, 
270                                                socket_get_fd(wrepl_socket->sock), 
271                                                EVENT_FD_READ,
272                                                wrepl_handler, wrepl_socket);
273         if (composite_nomem(wrepl_socket->event.fde, result)) return;
274
275         /* setup the stream -> packet parser */
276         wrepl_socket->packet = packet_init(wrepl_socket);
277         if (composite_nomem(wrepl_socket->packet, result)) return;
278         packet_set_private(wrepl_socket->packet, wrepl_socket);
279         packet_set_socket(wrepl_socket->packet, wrepl_socket->sock);
280         packet_set_callback(wrepl_socket->packet, wrepl_finish_recv);
281         packet_set_full_request(wrepl_socket->packet, packet_full_request_u32);
282         packet_set_error_handler(wrepl_socket->packet, wrepl_error);
283         packet_set_event_context(wrepl_socket->packet, wrepl_socket->event.ctx);
284         packet_set_fde(wrepl_socket->packet, wrepl_socket->event.fde);
285         packet_set_serialise(wrepl_socket->packet);
286
287         composite_done(result);
288 }
289
290 /*
291   connect a wrepl_socket to a WINS server
292 */
293 struct composite_context *wrepl_connect_send(struct wrepl_socket *wrepl_socket,
294                                              const char *our_ip, const char *peer_ip)
295 {
296         struct composite_context *result;
297         struct wrepl_connect_state *state;
298
299         result = talloc_zero(wrepl_socket, struct composite_context);
300         if (!result) return NULL;
301
302         result->state           = COMPOSITE_STATE_IN_PROGRESS;
303         result->event_ctx       = wrepl_socket->event.ctx;
304
305         state = talloc_zero(result, struct wrepl_connect_state);
306         if (composite_nomem(state, result)) return result;
307         result->private_data    = state;
308         state->result           = result;
309         state->wrepl_socket     = wrepl_socket;
310
311         if (!our_ip) {
312                 our_ip = iface_best_ip(peer_ip);
313         }
314
315         state->creq = socket_connect_send(wrepl_socket->sock, our_ip, 0,
316                                           peer_ip, WINS_REPLICATION_PORT,
317                                           0, wrepl_socket->event.ctx);
318         composite_continue(result, state->creq, wrepl_connect_handler, state);
319         return result;
320 }
321
322 /*
323   connect a wrepl_socket to a WINS server - recv side
324 */
325 NTSTATUS wrepl_connect_recv(struct composite_context *result)
326 {
327         struct wrepl_connect_state *state = talloc_get_type(result->private_data,
328                                             struct wrepl_connect_state);
329         struct wrepl_socket *wrepl_socket = state->wrepl_socket;
330         NTSTATUS status = composite_wait(result);
331
332         if (!NT_STATUS_IS_OK(status)) {
333                 wrepl_socket_dead(wrepl_socket, status);
334         }
335
336         talloc_free(result);
337         return status;
338 }
339
340 /*
341   connect a wrepl_socket to a WINS server - sync API
342 */
343 NTSTATUS wrepl_connect(struct wrepl_socket *wrepl_socket, const char *our_ip, const char *peer_ip)
344 {
345         struct composite_context *c_req = wrepl_connect_send(wrepl_socket, our_ip, peer_ip);
346         return wrepl_connect_recv(c_req);
347 }
348
349 /* 
350    callback from wrepl_request_trigger() 
351 */
352 static void wrepl_request_trigger_handler(struct event_context *ev, struct timed_event *te,
353                                           struct timeval t, void *ptr)
354 {
355         struct wrepl_request *req = talloc_get_type(ptr, struct wrepl_request);
356         if (req->async.fn) {
357                 req->async.fn(req);
358         }
359 }
360
361 /*
362   trigger an immediate event on a wrepl_request
363   the return value should only be used in wrepl_request_send()
364   this is the only place where req->trigger is True
365 */
366 static struct wrepl_request *wrepl_request_finished(struct wrepl_request *req, NTSTATUS status)
367 {
368         struct timed_event *te;
369
370         if (req->state == WREPL_REQUEST_RECV) {
371                 DLIST_REMOVE(req->wrepl_socket->recv_queue, req);
372         }
373
374         if (!NT_STATUS_IS_OK(status)) {
375                 req->state      = WREPL_REQUEST_ERROR;
376         } else {
377                 req->state      = WREPL_REQUEST_DONE;
378         }
379
380         req->status     = status;
381
382         if (req->trigger) {
383                 req->trigger = False;
384                 /* a zero timeout means immediate */
385                 te = event_add_timed(req->wrepl_socket->event.ctx,
386                                      req, timeval_zero(),
387                                      wrepl_request_trigger_handler, req);
388                 if (!te) {
389                         talloc_free(req);
390                         return NULL;
391                 }
392                 return req;
393         }
394
395         if (req->async.fn) {
396                 req->async.fn(req);
397         }
398         return NULL;
399 }
400
401 struct wrepl_send_ctrl_state {
402         struct wrepl_send_ctrl ctrl;
403         struct wrepl_request *req;
404         struct wrepl_socket *wrepl_sock;
405 };
406
407 static int wrepl_send_ctrl_destructor(void *ptr)
408 {
409         struct wrepl_send_ctrl_state *s = talloc_get_type(ptr, struct wrepl_send_ctrl_state);
410         struct wrepl_request *req = s->wrepl_sock->recv_queue;
411
412         /* check if the request is still in WREPL_STATE_RECV,
413          * we need this here because the caller has may called 
414          * talloc_free(req) and wrepl_send_ctrl_state isn't
415          * a talloc child of the request, so our s->req pointer
416          * is maybe invalid!
417          */
418         for (; req; req = req->next) {
419                 if (req == s->req) break;
420         }
421         if (!req) return 0;
422
423         /* here, we need to make sure the async request handler is called
424          * later in the next event_loop and now now
425          */
426         req->trigger = True;
427         wrepl_request_finished(req, NT_STATUS_OK);
428
429         if (s->ctrl.disconnect_after_send) {
430                 wrepl_socket_dead(s->wrepl_sock, NT_STATUS_LOCAL_DISCONNECT);
431         }
432
433         return 0;
434 }
435
436 /*
437   send a generic wins replication request
438 */
439 struct wrepl_request *wrepl_request_send(struct wrepl_socket *wrepl_socket,
440                                          struct wrepl_packet *packet,
441                                          struct wrepl_send_ctrl *ctrl)
442 {
443         struct wrepl_request *req;
444         struct wrepl_wrap wrap;
445         DATA_BLOB blob;
446
447         req = talloc_zero(wrepl_socket, struct wrepl_request);
448         if (!req) return NULL;
449         req->wrepl_socket = wrepl_socket;
450         req->state        = WREPL_REQUEST_RECV;
451         req->trigger      = True;
452
453         DLIST_ADD_END(wrepl_socket->recv_queue, req, struct wrepl_request *);
454         talloc_set_destructor(req, wrepl_request_destructor);
455
456         if (wrepl_socket->dead) {
457                 return wrepl_request_finished(req, NT_STATUS_INVALID_CONNECTION);
458         }
459
460         wrap.packet = *packet;
461         req->status = ndr_push_struct_blob(&blob, req, &wrap,
462                                            (ndr_push_flags_fn_t)ndr_push_wrepl_wrap);
463         if (!NT_STATUS_IS_OK(req->status)) {
464                 return wrepl_request_finished(req, req->status);
465         }
466
467         if (DEBUGLVL(10)) {
468                 DEBUG(10,("Sending WINS packet of length %u\n", blob.length));
469                 NDR_PRINT_DEBUG(wrepl_packet, &wrap.packet);
470         }
471
472         if (wrepl_socket->request_timeout > 0) {
473                 req->te = event_add_timed(wrepl_socket->event.ctx, req, 
474                                           timeval_current_ofs(wrepl_socket->request_timeout, 0), 
475                                           wrepl_request_timeout_handler, req);
476                 if (!req->te) return wrepl_request_finished(req, NT_STATUS_NO_MEMORY);
477         }
478
479         if (ctrl && (ctrl->send_only || ctrl->disconnect_after_send)) {
480                 struct wrepl_send_ctrl_state *s = talloc(blob.data, struct wrepl_send_ctrl_state);
481                 if (!s) return wrepl_request_finished(req, NT_STATUS_NO_MEMORY);
482                 s->ctrl         = *ctrl;
483                 s->req          = req;
484                 s->wrepl_sock   = wrepl_socket;
485                 talloc_set_destructor(s, wrepl_send_ctrl_destructor);
486         }
487
488         req->status = packet_send(wrepl_socket->packet, blob);
489         if (!NT_STATUS_IS_OK(req->status)) {
490                 return wrepl_request_finished(req, req->status);
491         }
492
493         req->trigger = False;
494         return req;
495 }
496
497 /*
498   receive a generic WINS replication reply
499 */
500 NTSTATUS wrepl_request_recv(struct wrepl_request *req,
501                             TALLOC_CTX *mem_ctx,
502                             struct wrepl_packet **packet)
503 {
504         NTSTATUS status = wrepl_request_wait(req);
505         if (NT_STATUS_IS_OK(status)) {
506                 *packet = talloc_steal(mem_ctx, req->packet);
507         }
508         talloc_free(req);
509         return status;
510 }
511
512 /*
513   a full WINS replication request/response
514 */
515 NTSTATUS wrepl_request(struct wrepl_socket *wrepl_socket,
516                        TALLOC_CTX *mem_ctx,
517                        struct wrepl_packet *req_packet,
518                        struct wrepl_packet **reply_packet)
519 {
520         struct wrepl_request *req = wrepl_request_send(wrepl_socket, req_packet, NULL);
521         return wrepl_request_recv(req, mem_ctx, reply_packet);
522 }
523
524
525 /*
526   setup an association - send
527 */
528 struct wrepl_request *wrepl_associate_send(struct wrepl_socket *wrepl_socket,
529                                            struct wrepl_associate *io)
530 {
531         struct wrepl_packet *packet;
532         struct wrepl_request *req;
533
534         packet = talloc_zero(wrepl_socket, struct wrepl_packet);
535         if (packet == NULL) return NULL;
536
537         packet->opcode                      = WREPL_OPCODE_BITS;
538         packet->mess_type                   = WREPL_START_ASSOCIATION;
539         packet->message.start.minor_version = 2;
540         packet->message.start.major_version = 5;
541
542         req = wrepl_request_send(wrepl_socket, packet, NULL);
543
544         talloc_free(packet);
545
546         return req;     
547 }
548
549 /*
550   setup an association - recv
551 */
552 NTSTATUS wrepl_associate_recv(struct wrepl_request *req,
553                               struct wrepl_associate *io)
554 {
555         struct wrepl_packet *packet=NULL;
556         NTSTATUS status;
557         status = wrepl_request_recv(req, req->wrepl_socket, &packet);
558         NT_STATUS_NOT_OK_RETURN(status);
559         if (packet->mess_type != WREPL_START_ASSOCIATION_REPLY) {
560                 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
561         }
562         if (NT_STATUS_IS_OK(status)) {
563                 io->out.assoc_ctx = packet->message.start_reply.assoc_ctx;
564         }
565         talloc_free(packet);
566         return status;
567 }
568
569 /*
570   setup an association - sync api
571 */
572 NTSTATUS wrepl_associate(struct wrepl_socket *wrepl_socket,
573                          struct wrepl_associate *io)
574 {
575         struct wrepl_request *req = wrepl_associate_send(wrepl_socket, io);
576         return wrepl_associate_recv(req, io);
577 }
578
579
580 /*
581   stop an association - send
582 */
583 struct wrepl_request *wrepl_associate_stop_send(struct wrepl_socket *wrepl_socket,
584                                                 struct wrepl_associate_stop *io)
585 {
586         struct wrepl_packet *packet;
587         struct wrepl_request *req;
588         struct wrepl_send_ctrl ctrl;
589
590         packet = talloc_zero(wrepl_socket, struct wrepl_packet);
591         if (packet == NULL) return NULL;
592
593         packet->opcode                  = WREPL_OPCODE_BITS;
594         packet->assoc_ctx               = io->in.assoc_ctx;
595         packet->mess_type               = WREPL_STOP_ASSOCIATION;
596         packet->message.stop.reason     = io->in.reason;
597
598         ZERO_STRUCT(ctrl);
599         if (io->in.reason == 0) {
600                 ctrl.send_only                  = True;
601                 ctrl.disconnect_after_send      = True;
602         }
603
604         req = wrepl_request_send(wrepl_socket, packet, &ctrl);
605
606         talloc_free(packet);
607
608         return req;     
609 }
610
611 /*
612   stop an association - recv
613 */
614 NTSTATUS wrepl_associate_stop_recv(struct wrepl_request *req,
615                                    struct wrepl_associate_stop *io)
616 {
617         struct wrepl_packet *packet=NULL;
618         NTSTATUS status;
619         status = wrepl_request_recv(req, req->wrepl_socket, &packet);
620         NT_STATUS_NOT_OK_RETURN(status);
621         talloc_free(packet);
622         return status;
623 }
624
625 /*
626   setup an association - sync api
627 */
628 NTSTATUS wrepl_associate_stop(struct wrepl_socket *wrepl_socket,
629                               struct wrepl_associate_stop *io)
630 {
631         struct wrepl_request *req = wrepl_associate_stop_send(wrepl_socket, io);
632         return wrepl_associate_stop_recv(req, io);
633 }
634
635 /*
636   fetch the partner tables - send
637 */
638 struct wrepl_request *wrepl_pull_table_send(struct wrepl_socket *wrepl_socket,
639                                             struct wrepl_pull_table *io)
640 {
641         struct wrepl_packet *packet;
642         struct wrepl_request *req;
643
644         packet = talloc_zero(wrepl_socket, struct wrepl_packet);
645         if (packet == NULL) return NULL;
646
647         packet->opcode                      = WREPL_OPCODE_BITS;
648         packet->assoc_ctx                   = io->in.assoc_ctx;
649         packet->mess_type                   = WREPL_REPLICATION;
650         packet->message.replication.command = WREPL_REPL_TABLE_QUERY;
651
652         req = wrepl_request_send(wrepl_socket, packet, NULL);
653
654         talloc_free(packet);
655
656         return req;     
657 }
658
659
660 /*
661   fetch the partner tables - recv
662 */
663 NTSTATUS wrepl_pull_table_recv(struct wrepl_request *req,
664                                TALLOC_CTX *mem_ctx,
665                                struct wrepl_pull_table *io)
666 {
667         struct wrepl_packet *packet=NULL;
668         NTSTATUS status;
669         struct wrepl_table *table;
670         int i;
671
672         status = wrepl_request_recv(req, req->wrepl_socket, &packet);
673         NT_STATUS_NOT_OK_RETURN(status);
674         if (packet->mess_type != WREPL_REPLICATION) {
675                 status = NT_STATUS_NETWORK_ACCESS_DENIED;
676         } else if (packet->message.replication.command != WREPL_REPL_TABLE_REPLY) {
677                 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
678         }
679         if (!NT_STATUS_IS_OK(status)) goto failed;
680
681         table = &packet->message.replication.info.table;
682         io->out.num_partners = table->partner_count;
683         io->out.partners = talloc_steal(mem_ctx, table->partners);
684         for (i=0;i<io->out.num_partners;i++) {
685                 talloc_steal(io->out.partners, io->out.partners[i].address);
686         }
687
688 failed:
689         talloc_free(packet);
690         return status;
691 }
692
693
694 /*
695   fetch the partner table - sync api
696 */
697 NTSTATUS wrepl_pull_table(struct wrepl_socket *wrepl_socket,
698                           TALLOC_CTX *mem_ctx,
699                           struct wrepl_pull_table *io)
700 {
701         struct wrepl_request *req = wrepl_pull_table_send(wrepl_socket, io);
702         return wrepl_pull_table_recv(req, mem_ctx, io);
703 }
704
705
706 /*
707   fetch the names for a WINS partner - send
708 */
709 struct wrepl_request *wrepl_pull_names_send(struct wrepl_socket *wrepl_socket,
710                                             struct wrepl_pull_names *io)
711 {
712         struct wrepl_packet *packet;
713         struct wrepl_request *req;
714
715         packet = talloc_zero(wrepl_socket, struct wrepl_packet);
716         if (packet == NULL) return NULL;
717
718         packet->opcode                         = WREPL_OPCODE_BITS;
719         packet->assoc_ctx                      = io->in.assoc_ctx;
720         packet->mess_type                      = WREPL_REPLICATION;
721         packet->message.replication.command    = WREPL_REPL_SEND_REQUEST;
722         packet->message.replication.info.owner = io->in.partner;
723
724         req = wrepl_request_send(wrepl_socket, packet, NULL);
725
726         talloc_free(packet);
727
728         return req;     
729 }
730
731 /*
732   fetch the names for a WINS partner - recv
733 */
734 NTSTATUS wrepl_pull_names_recv(struct wrepl_request *req,
735                                TALLOC_CTX *mem_ctx,
736                                struct wrepl_pull_names *io)
737 {
738         struct wrepl_packet *packet=NULL;
739         NTSTATUS status;
740         int i;
741
742         status = wrepl_request_recv(req, req->wrepl_socket, &packet);
743         NT_STATUS_NOT_OK_RETURN(status);
744         if (packet->mess_type != WREPL_REPLICATION ||
745             packet->message.replication.command != WREPL_REPL_SEND_REPLY) {
746                 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
747         }
748         if (!NT_STATUS_IS_OK(status)) goto failed;
749
750         io->out.num_names = packet->message.replication.info.reply.num_names;
751
752         io->out.names = talloc_array(packet, struct wrepl_name, io->out.num_names);
753         if (io->out.names == NULL) goto nomem;
754
755         /* convert the list of names and addresses to a sane format */
756         for (i=0;i<io->out.num_names;i++) {
757                 struct wrepl_wins_name *wname = &packet->message.replication.info.reply.names[i];
758                 struct wrepl_name *name = &io->out.names[i];
759
760                 name->name      = *wname->name;
761                 talloc_steal(io->out.names, wname->name);
762                 name->type      = WREPL_NAME_TYPE(wname->flags);
763                 name->state     = WREPL_NAME_STATE(wname->flags);
764                 name->node      = WREPL_NAME_NODE(wname->flags);
765                 name->is_static = WREPL_NAME_IS_STATIC(wname->flags);
766                 name->raw_flags = wname->flags;
767                 name->version_id= wname->id;
768                 name->owner     = talloc_strdup(io->out.names, io->in.partner.address);
769                 if (name->owner == NULL) goto nomem;
770
771                 /* trying to save 1 or 2 bytes on the wire isn't a good idea */
772                 if (wname->flags & 2) {
773                         int j;
774
775                         name->num_addresses = wname->addresses.addresses.num_ips;
776                         name->addresses = talloc_array(io->out.names, 
777                                                        struct wrepl_address, 
778                                                        name->num_addresses);
779                         if (name->addresses == NULL) goto nomem;
780                         for (j=0;j<name->num_addresses;j++) {
781                                 name->addresses[j].owner = 
782                                         talloc_steal(name->addresses, 
783                                                      wname->addresses.addresses.ips[j].owner);
784                                 name->addresses[j].address = 
785                                         talloc_steal(name->addresses, 
786                                                      wname->addresses.addresses.ips[j].ip);
787                         }
788                 } else {
789                         name->num_addresses = 1;
790                         name->addresses = talloc(io->out.names, struct wrepl_address);
791                         if (name->addresses == NULL) goto nomem;
792                         name->addresses[0].owner = talloc_strdup(name->addresses,io->in.partner.address);
793                         if (name->addresses[0].owner == NULL) goto nomem;
794                         name->addresses[0].address = talloc_steal(name->addresses,
795                                                                   wname->addresses.ip);
796                 }
797         }
798
799         talloc_steal(mem_ctx, io->out.names);
800         talloc_free(packet);
801         return NT_STATUS_OK;
802 nomem:
803         status = NT_STATUS_NO_MEMORY;
804 failed:
805         talloc_free(packet);
806         return status;
807 }
808
809
810
811 /*
812   fetch the names for a WINS partner - sync api
813 */
814 NTSTATUS wrepl_pull_names(struct wrepl_socket *wrepl_socket,
815                           TALLOC_CTX *mem_ctx,
816                           struct wrepl_pull_names *io)
817 {
818         struct wrepl_request *req = wrepl_pull_names_send(wrepl_socket, io);
819         return wrepl_pull_names_recv(req, mem_ctx, io);
820 }