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