~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source4/wrepl_server/wrepl_out_push.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
#include "nbt_server/wins/winsdb.h"
 
27
 
 
28
static void wreplsrv_out_partner_push(struct wreplsrv_partner *partner, bool propagate);
 
29
 
 
30
static void wreplsrv_push_handler_creq(struct composite_context *creq)
 
31
{
 
32
        struct wreplsrv_partner *partner = talloc_get_type(creq->async.private_data, struct wreplsrv_partner);
 
33
        struct wreplsrv_push_notify_io *old_notify_io;
 
34
 
 
35
        partner->push.last_status = wreplsrv_push_notify_recv(partner->push.creq);
 
36
        partner->push.creq = NULL;
 
37
 
 
38
        old_notify_io = partner->push.notify_io;
 
39
        partner->push.notify_io = NULL;
 
40
 
 
41
        if (NT_STATUS_IS_OK(partner->push.last_status)) {
 
42
                partner->push.error_count = 0;
 
43
                DEBUG(2,("wreplsrv_push_notify(%s): %s\n",
 
44
                         partner->address, nt_errstr(partner->push.last_status)));
 
45
                goto done;
 
46
        }
 
47
 
 
48
        partner->push.error_count++;
 
49
 
 
50
        if (partner->push.error_count > 1) {
 
51
                DEBUG(1,("wreplsrv_push_notify(%s): %s: error_count: %u: giving up\n",
 
52
                         partner->address, nt_errstr(partner->push.last_status),
 
53
                         partner->push.error_count));
 
54
                goto done;
 
55
        }
 
56
 
 
57
        DEBUG(1,("wreplsrv_push_notify(%s): %s: error_count: %u: retry\n",
 
58
                 partner->address, nt_errstr(partner->push.last_status),
 
59
                 partner->push.error_count));
 
60
        wreplsrv_out_partner_push(partner, old_notify_io->in.propagate);
 
61
done:
 
62
        talloc_free(old_notify_io);
 
63
}
 
64
 
 
65
static void wreplsrv_out_partner_push(struct wreplsrv_partner *partner, bool propagate)
 
66
{
 
67
        /* a push for this partner is currently in progress, so we're done */
 
68
        if (partner->push.creq) return;
 
69
 
 
70
        /* now prepare the push notify */
 
71
        partner->push.notify_io = talloc(partner, struct wreplsrv_push_notify_io);
 
72
        if (!partner->push.notify_io) {
 
73
                goto nomem;
 
74
        }
 
75
 
 
76
        partner->push.notify_io->in.partner     = partner;
 
77
        partner->push.notify_io->in.inform      = partner->push.use_inform;
 
78
        partner->push.notify_io->in.propagate   = propagate;
 
79
        partner->push.creq = wreplsrv_push_notify_send(partner->push.notify_io, partner->push.notify_io);
 
80
        if (!partner->push.creq) {
 
81
                DEBUG(1,("wreplsrv_push_notify_send(%s) failed nomem?\n",
 
82
                         partner->address));
 
83
                goto nomem;
 
84
        }
 
85
 
 
86
        partner->push.creq->async.fn            = wreplsrv_push_handler_creq;
 
87
        partner->push.creq->async.private_data  = partner;
 
88
 
 
89
        return;
 
90
nomem:
 
91
        talloc_free(partner->push.notify_io);
 
92
        partner->push.notify_io = NULL;
 
93
        DEBUG(1,("wreplsrv_out_partner_push(%s,%u) failed nomem? (ignoring)\n",
 
94
                 partner->address, propagate));
 
95
        return;
 
96
}
 
97
 
 
98
static uint32_t wreplsrv_calc_change_count(struct wreplsrv_partner *partner, uint64_t maxVersionID)
 
99
{
 
100
        uint64_t tmp_diff = UINT32_MAX;
 
101
 
 
102
        /* catch an overflow */
 
103
        if (partner->push.maxVersionID > maxVersionID) {
 
104
                goto done;
 
105
        }
 
106
 
 
107
        tmp_diff = maxVersionID - partner->push.maxVersionID;
 
108
 
 
109
        if (tmp_diff > UINT32_MAX) {
 
110
                tmp_diff = UINT32_MAX;
 
111
                goto done;
 
112
        }
 
113
 
 
114
done:
 
115
        partner->push.maxVersionID = maxVersionID;
 
116
        return (uint32_t)(tmp_diff & UINT32_MAX);
 
117
}
 
118
 
 
119
NTSTATUS wreplsrv_out_push_run(struct wreplsrv_service *service)
 
120
{
 
121
        struct wreplsrv_partner *partner;
 
122
        uint64_t seqnumber;
 
123
        uint32_t change_count;
 
124
 
 
125
        seqnumber = winsdb_get_maxVersion(service->wins_db);
 
126
 
 
127
        for (partner = service->partners; partner; partner = partner->next) {
 
128
                /* if it's not a push partner, go to the next partner */
 
129
                if (!(partner->type & WINSREPL_PARTNER_PUSH)) continue;
 
130
 
 
131
                /* if push notifies are disabled for this partner, go to the next partner */
 
132
                if (partner->push.change_count == 0) continue;
 
133
 
 
134
                /* get the actual change count for the partner */
 
135
                change_count = wreplsrv_calc_change_count(partner, seqnumber);
 
136
 
 
137
                /* if the configured change count isn't reached, go to the next partner */
 
138
                if (change_count < partner->push.change_count) continue;
 
139
 
 
140
                wreplsrv_out_partner_push(partner, false);
 
141
        }
 
142
 
 
143
        return NT_STATUS_OK;
 
144
}