Merge branch 'v4-0-test' of /home/jelmer/samba4 into v4-0-test
[kai/samba.git] / source4 / wrepl_server / wrepl_out_pull.c
1 /* 
2    Unix SMB/CIFS implementation.
3    
4    WINS Replication server
5    
6    Copyright (C) Stefan Metzmacher      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 3 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, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "includes.h"
23 #include "librpc/gen_ndr/winsrepl.h"
24 #include "wrepl_server/wrepl_server.h"
25 #include "libcli/composite/composite.h"
26
27 static void wreplsrv_out_pull_reschedule(struct wreplsrv_partner *partner, uint32_t interval)
28 {
29         NTSTATUS status;
30
31         partner->pull.next_run = timeval_current_ofs(interval, 0);
32         status = wreplsrv_periodic_schedule(partner->service, interval);
33         if (!NT_STATUS_IS_OK(status)) {
34                 DEBUG(0,("wreplsrv_periodic_schedule() failed\n"));
35         }
36 }
37
38 static void wreplsrv_pull_handler_creq(struct composite_context *creq)
39 {
40         struct wreplsrv_partner *partner = talloc_get_type(creq->async.private_data, struct wreplsrv_partner);
41         struct wreplsrv_pull_cycle_io *old_cycle_io;
42         struct wrepl_table inform_in;
43
44         partner->pull.last_status = wreplsrv_pull_cycle_recv(partner->pull.creq);
45         partner->pull.creq = NULL;
46
47         old_cycle_io = partner->pull.cycle_io;
48         partner->pull.cycle_io = NULL;
49
50         if (NT_STATUS_IS_OK(partner->pull.last_status)) {
51                 partner->pull.error_count = 0;
52                 DEBUG(2,("wreplsrv_pull_cycle(%s): %s\n",
53                          partner->address, nt_errstr(partner->pull.last_status)));
54                 goto done;
55         }
56
57         partner->pull.error_count++;
58
59         if (partner->pull.error_count > 1) {
60                 uint32_t retry_interval;
61
62                 retry_interval = partner->pull.error_count * partner->pull.retry_interval;
63                 retry_interval = MIN(retry_interval, partner->pull.interval);
64
65                 DEBUG(1,("wreplsrv_pull_cycle(%s): %s: error_count: %u: reschedule(%u)\n",
66                          partner->address, nt_errstr(partner->pull.last_status),
67                          partner->pull.error_count, retry_interval));
68
69                 wreplsrv_out_pull_reschedule(partner, retry_interval);
70                 goto done;
71         }
72
73         DEBUG(1,("wreplsrv_pull_cycle(%s): %s: error_count:%u retry\n",
74                  partner->address, nt_errstr(partner->pull.last_status),
75                  partner->pull.error_count));
76         inform_in.partner_count = old_cycle_io->in.num_owners;
77         inform_in.partners      = old_cycle_io->in.owners;
78         wreplsrv_out_partner_pull(partner, &inform_in);
79 done:
80         talloc_free(old_cycle_io);
81 }
82
83 void wreplsrv_out_partner_pull(struct wreplsrv_partner *partner, struct wrepl_table *inform_in)
84 {
85         /* there's already a pull in progress, so we're done */
86         if (partner->pull.creq) return;
87
88         partner->pull.cycle_io = talloc(partner, struct wreplsrv_pull_cycle_io);
89         if (!partner->pull.cycle_io) {
90                 goto nomem;
91         }
92
93         partner->pull.cycle_io->in.partner      = partner;
94         partner->pull.cycle_io->in.wreplconn    = NULL;
95         if (inform_in) {
96                 partner->pull.cycle_io->in.num_owners   = inform_in->partner_count;
97                 partner->pull.cycle_io->in.owners       = inform_in->partners;
98                 talloc_steal(partner->pull.cycle_io, inform_in->partners);
99         } else {
100                 partner->pull.cycle_io->in.num_owners   = 0;
101                 partner->pull.cycle_io->in.owners       = NULL;
102         }
103         partner->pull.creq = wreplsrv_pull_cycle_send(partner->pull.cycle_io, partner->pull.cycle_io);
104         if (!partner->pull.creq) {
105                 DEBUG(1,("wreplsrv_pull_cycle_send(%s) failed\n",
106                          partner->address));
107                 goto nomem;
108         }
109
110         partner->pull.creq->async.fn            = wreplsrv_pull_handler_creq;
111         partner->pull.creq->async.private_data  = partner;
112
113         return;
114 nomem:
115         talloc_free(partner->pull.cycle_io);
116         partner->pull.cycle_io = NULL;
117         DEBUG(0,("wreplsrv_out_partner_pull(%s): no memory? (ignoring)\n",
118                 partner->address));
119         return;
120 }
121
122 NTSTATUS wreplsrv_out_pull_run(struct wreplsrv_service *service)
123 {
124         struct wreplsrv_partner *partner;
125
126         for (partner = service->partners; partner; partner = partner->next) {
127                 /* if it's not a pull partner, go to the next partner */
128                 if (!(partner->type & WINSREPL_PARTNER_PULL)) continue;
129
130                 /* if pulling is disabled for the partner, go to the next one */
131                 if (partner->pull.interval == 0) continue;
132
133                 /* if the next timer isn't reached, go to the next partner */
134                 if (!timeval_expired(&partner->pull.next_run)) continue;
135
136                 wreplsrv_out_pull_reschedule(partner, partner->pull.interval);
137
138                 wreplsrv_out_partner_pull(partner, NULL);
139         }
140
141         return NT_STATUS_OK;
142 }