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