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