📄 wrepl_apply_records.c
字号:
struct r_do_challenge_state); bool old_is_subset = false; bool new_is_subset = false; bool found = false; uint32_t i,j; uint32_t num_rec_addrs; status = irpc_call_recv(ireq); DEBUG(4,("r_do_challenge_handler: %s: %s\n", nbt_name_string(state, &state->replica.name), nt_errstr(status))); if (NT_STATUS_EQUAL(NT_STATUS_IO_TIMEOUT, status) || NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_NOT_FOUND, status)) { r_do_replace(state->partner, state, state->rec, &state->owner, &state->replica); talloc_free(state); return; } for (i=0; i < state->replica.num_addresses; i++) { found = false; new_is_subset = true; for (j=0; j < state->r.out.num_addrs; j++) { if (strcmp(state->replica.addresses[i].address, state->r.out.addrs[j].addr) == 0) { found = true; break; } } if (found) continue; new_is_subset = false; break; } if (!new_is_subset) { r_not_replace(state->partner, state, state->rec, &state->owner, &state->replica); talloc_free(state); return; } num_rec_addrs = winsdb_addr_list_length(state->rec->addresses); for (i=0; i < num_rec_addrs; i++) { found = false; old_is_subset = true; for (j=0; j < state->r.out.num_addrs; j++) { if (strcmp(state->rec->addresses[i]->address, state->r.out.addrs[j].addr) == 0) { found = true; break; } } if (found) continue; old_is_subset = false; break; } if (!old_is_subset) { status = r_do_late_release_demand(state); /* * only free state on error, because we pass it down, * and r_do_late_release_demand() will free it */ if (!NT_STATUS_IS_OK(status)) { talloc_free(state); } return; } r_do_mhomed_merge(state->partner, state, state->rec, &state->owner, &state->replica); talloc_free(state);}static NTSTATUS r_do_challenge(struct wreplsrv_partner *partner, TALLOC_CTX *mem_ctx, struct winsdb_record *rec, struct wrepl_wins_owner *owner, struct wrepl_name *replica){ struct irpc_request *ireq; struct r_do_challenge_state *state; struct server_id *nbt_servers; const char **addrs; uint32_t i; DEBUG(4,("challenge record %s\n", nbt_name_string(mem_ctx, &replica->name))); state = talloc_zero(mem_ctx, struct r_do_challenge_state); NT_STATUS_HAVE_NO_MEMORY(state); state->msg_ctx = partner->service->task->msg_ctx; state->partner = partner; state->rec = talloc_steal(state, rec); state->owner = *owner; state->replica = *replica; /* some stuff to have valid memory pointers in the async complete function */ state->replica.name = *state->rec->name; talloc_steal(state, replica->owner); talloc_steal(state, replica->addresses); nbt_servers = irpc_servers_byname(state->msg_ctx, state, "nbt_server"); if ((nbt_servers == NULL) || (nbt_servers[0].id == 0)) { return NT_STATUS_INTERNAL_ERROR; } state->r.in.name = *rec->name; state->r.in.num_addrs = winsdb_addr_list_length(rec->addresses); state->r.in.addrs = talloc_array(state, struct nbtd_proxy_wins_addr, state->r.in.num_addrs); NT_STATUS_HAVE_NO_MEMORY(state->r.in.addrs); /* TODO: fix pidl to handle inline ipv4address arrays */ addrs = winsdb_addr_string_list(state->r.in.addrs, rec->addresses); NT_STATUS_HAVE_NO_MEMORY(addrs); for (i=0; i < state->r.in.num_addrs; i++) { state->r.in.addrs[i].addr = addrs[i]; } ireq = IRPC_CALL_SEND(state->msg_ctx, nbt_servers[0], irpc, NBTD_PROXY_WINS_CHALLENGE, &state->r, state); NT_STATUS_HAVE_NO_MEMORY(ireq); ireq->async.fn = r_do_challenge_handler; ireq->async.private = state; talloc_steal(partner, state); return NT_STATUS_OK;}struct r_do_release_demand_state { struct messaging_context *msg_ctx; struct nbtd_proxy_wins_release_demand r;};static void r_do_release_demand_handler(struct irpc_request *ireq){ NTSTATUS status; struct r_do_release_demand_state *state = talloc_get_type(ireq->async.private, struct r_do_release_demand_state); status = irpc_call_recv(ireq); /* don't care about the result */ talloc_free(state);}static NTSTATUS r_do_release_demand(struct wreplsrv_partner *partner, TALLOC_CTX *mem_ctx, struct winsdb_record *rec, struct wrepl_wins_owner *owner, struct wrepl_name *replica){ NTSTATUS status; struct irpc_request *ireq; struct server_id *nbt_servers; const char **addrs; struct winsdb_addr **addresses; struct r_do_release_demand_state *state; uint32_t i; /* * we need to get a reference to the old addresses, * as we need to send a release demand to them after replacing the record * and r_do_replace() will modify rec->addresses */ addresses = rec->addresses; status = r_do_replace(partner, mem_ctx, rec, owner, replica); NT_STATUS_NOT_OK_RETURN(status); DEBUG(4,("release demand record %s\n", nbt_name_string(mem_ctx, &replica->name))); state = talloc_zero(mem_ctx, struct r_do_release_demand_state); NT_STATUS_HAVE_NO_MEMORY(state); state->msg_ctx = partner->service->task->msg_ctx; nbt_servers = irpc_servers_byname(state->msg_ctx, state, "nbt_server"); if ((nbt_servers == NULL) || (nbt_servers[0].id == 0)) { return NT_STATUS_INTERNAL_ERROR; } state->r.in.name = *rec->name; state->r.in.num_addrs = winsdb_addr_list_length(addresses); state->r.in.addrs = talloc_array(state, struct nbtd_proxy_wins_addr, state->r.in.num_addrs); NT_STATUS_HAVE_NO_MEMORY(state->r.in.addrs); /* TODO: fix pidl to handle inline ipv4address arrays */ addrs = winsdb_addr_string_list(state->r.in.addrs, addresses); NT_STATUS_HAVE_NO_MEMORY(addrs); for (i=0; i < state->r.in.num_addrs; i++) { state->r.in.addrs[i].addr = addrs[i]; } ireq = IRPC_CALL_SEND(state->msg_ctx, nbt_servers[0], irpc, NBTD_PROXY_WINS_RELEASE_DEMAND, &state->r, state); NT_STATUS_HAVE_NO_MEMORY(ireq); ireq->async.fn = r_do_release_demand_handler; ireq->async.private = state; talloc_steal(partner, state); return NT_STATUS_OK;}/*SGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4 vs. B:A_3_4 => NOT REPLACESGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4 vs. B:NULL => NOT REPLACESGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4_X_3_4 vs. B:A_3_4 => NOT REPLACESGROUP,ACTIVE vs. SGROUP,ACTIVE A:B_3_4 vs. B:A_3_4 => REPLACESGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4 vs. B:A_3_4_OWNER_B => REPLACESGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4_OWNER_B vs. B:A_3_4 => REPLACESGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4 vs. B:B_3_4 => C:A_3_4_B_3_4 => SGROUP_MERGESGROUP,ACTIVE vs. SGROUP,ACTIVE A:B_3_4_X_3_4 vs. B:A_3_4 => B:A_3_4_X_3_4 => SGROUP_MERGESGROUP,ACTIVE vs. SGROUP,ACTIVE A:X_3_4 vs. B:A_3_4 => C:A_3_4_X_3_4 => SGROUP_MERGESGROUP,ACTIVE vs. SGROUP,ACTIVE A:A_3_4_X_3_4 vs. B:A_3_4_OWNER_B => B:A_3_4_OWNER_B_X_3_4 => SGROUP_MERGESGROUP,ACTIVE vs. SGROUP,ACTIVE A:B_3_4_X_3_4 vs. B:B_3_4_X_1_2 => C:B_3_4_X_1_2_3_4 => SGROUP_MERGESGROUP,ACTIVE vs. SGROUP,ACTIVE A:B_3_4_X_3_4 vs. B:NULL => B:X_3_4 => SGROUP_MERGETest Replica vs. owned active: SGROUP vs. SGROUP tests_SA_SA_DI_U<1c> => SGROUP_MERGE_SA_SA_SI_U<1c> => SGROUP_MERGE_SA_SA_SP_U<1c> => SGROUP_MERGE_SA_SA_SB_U<1c> => SGROUP_MERGE*/static NTSTATUS r_do_sgroup_merge(struct wreplsrv_partner *partner, TALLOC_CTX *mem_ctx, struct winsdb_record *rec, struct wrepl_wins_owner *owner, struct wrepl_name *replica){ struct winsdb_record *merge; uint32_t modify_flags = 0; uint32_t i,j; uint8_t ret; size_t len; bool changed_old_addrs = false; bool become_owner = true; merge = talloc(mem_ctx, struct winsdb_record); NT_STATUS_HAVE_NO_MEMORY(merge); merge->name = &replica->name; merge->type = replica->type; merge->state = replica->state; merge->node = replica->node; merge->is_static = replica->is_static; merge->expire_time = time(NULL) + partner->service->config.verify_interval; merge->version = replica->version_id; merge->wins_owner = replica->owner; merge->addresses = winsdb_addr_list_make(merge); NT_STATUS_HAVE_NO_MEMORY(merge->addresses); merge->registered_by = NULL; len = winsdb_addr_list_length(rec->addresses); for (i=0; i < len; i++) { bool found = false; for (j=0; j < replica->num_addresses; j++) { if (strcmp(rec->addresses[i]->address, replica->addresses[j].address) != 0) { continue; } found = true; if (strcmp(rec->addresses[i]->wins_owner, replica->addresses[j].owner) != 0) { changed_old_addrs = true; break; } break; } /* * if the address isn't in the replica and is owned by replicas owner, * it won't be added to the merged record */ if (!found && strcmp(rec->addresses[i]->wins_owner, owner->address) == 0) { changed_old_addrs = true; continue; } /* * add the address to the merge result, with the old owner and expire_time, * the owner and expire_time will be overwritten later if the address is * in the replica too */ merge->addresses = winsdb_addr_list_add(partner->service->wins_db, merge, merge->addresses, rec->addresses[i]->address, rec->addresses[i]->wins_owner, rec->addresses[i]->expire_time, false); NT_STATUS_HAVE_NO_MEMORY(merge->addresses); } for (i=0; i < replica->num_addresses; i++) { merge->addresses = winsdb_addr_list_add(partner->service->wins_db, merge, merge->addresses, replica->addresses[i].address, replica->addresses[i].owner, merge->expire_time, false); NT_STATUS_HAVE_NO_MEMORY(merge->addresses); } /* we the old addresses change changed we don't become the owner */ if (changed_old_addrs) { become_owner = false; } /* if we're the owner of the old record, we'll be the owner of the new one too */ if (strcmp(rec->wins_owner, partner->service->wins_db->local_owner)==0) { become_owner = true; } /* * if the result has no addresses we take the ownership */ len = winsdb_addr_list_length(merge->addresses); if (len == 0) { become_owner = true; } /* * if addresses of the old record will be changed the replica owner * will be owner of the merge result, otherwise we take the ownership */ if (become_owner) { modify_flags = WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP; } ret = winsdb_modify(partner->service->wins_db, merge, modify_flags); if (ret != NBT_RCODE_OK) { DEBUG(0,("Failed to modify sgroup merge record %s: %u\n", nbt_name_string(mem_ctx, &replica->name), ret)); return NT_STATUS_FOOBAR; } DEBUG(4,("sgroup merge record %s\n", nbt_name_string(mem_ctx, &replica->name))); return NT_STATUS_OK;}static NTSTATUS wreplsrv_apply_one_record(struct wreplsrv_partner *partner, TALLOC_CTX *mem_ctx, struct wrepl_wins_owner *owner, struct wrepl_name *replica){ NTSTATUS status; struct winsdb_record *rec = NULL; enum _R_ACTION action = R_INVALID; bool same_owner = false; bool replica_vs_replica = false; bool local_vs_replica = false; status = winsdb_lookup(partner->service->wins_db, &replica->name, mem_ctx, &rec); if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_NOT_FOUND, status)) { return r_do_add(partner, mem_ctx, owner, replica); } NT_STATUS_NOT_OK_RETURN(status); if (strcmp(rec->wins_owner, partner->service->wins_db->local_owner)==0) { local_vs_replica = true; } else if (strcmp(rec->wins_owner, owner->address)==0) { same_owner = true; } else { replica_vs_replica = true; } if (rec->is_static && !same_owner) { action = R_NOT_REPLACE; /* * if we own the local record, then propagate it back to * the other wins servers. * to prevent ping-pong with other servers, we don't do this * if the replica is static too. * * It seems that w2k3 doesn't do this, but I thing that's a bug * and doing propagation helps to have consistent data on all servers */ if (local_vs_replica && !replica->is_static) { action = R_DO_PROPAGATE; } } else if (replica->is_static && !rec->is_static && !same_owner) { action = R_DO_REPLACE; } else if (same_owner) { action = replace_same_owner(rec, replica); } else if (replica_vs_replica) { switch (rec->type) { case WREPL_TYPE_UNIQUE: action = replace_unique_replica_vs_X_replica(rec, replica); break; case WREPL_TYPE_GROUP: action = replace_group_replica_vs_X_replica(rec, replica); break; case WREPL_TYPE_SGROUP: action = replace_sgroup_replica_vs_X_replica(rec, replica); break; case WREPL_TYPE_MHOMED: action = replace_mhomed_replica_vs_X_replica(rec, replica); break; } } else if (local_vs_replica) { switch (rec->type) { case WREPL_TYPE_UNIQUE: action = replace_unique_owned_vs_X_replica(rec, replica); break; case WREPL_TYPE_GROUP: action = replace_group_owned_vs_X_replica(rec, replica); break; case WREPL_TYPE_SGROUP: action = replace_sgroup_owned_vs_X_replica(rec, replica); break; case WREPL_TYPE_MHOMED: action = replace_mhomed_owned_vs_X_replica(rec, replica); break; } } DEBUG(4,("apply record %s: %s\n", nbt_name_string(mem_ctx, &replica->name), _R_ACTION_enum_string(action))); switch (action) { case R_INVALID: break; case R_DO_REPLACE: return r_do_replace(partner, mem_ctx, rec, owner, replica); case R_NOT_REPLACE: return r_not_replace(partner, mem_ctx, rec, owner, replica); case R_DO_PROPAGATE: return r_do_propagate(partner, mem_ctx, rec, owner, replica); case R_DO_CHALLENGE: return r_do_challenge(partner, mem_ctx, rec, owner, replica); case R_DO_RELEASE_DEMAND: return r_do_release_demand(partner, mem_ctx, rec, owner, replica); case R_DO_SGROUP_MERGE: return r_do_sgroup_merge(partner, mem_ctx, rec, owner, replica); } return NT_STATUS_INTERNAL_ERROR;}NTSTATUS wreplsrv_apply_records(struct wreplsrv_partner *partner, struct wrepl_wins_owner *owner, uint32_t num_names, struct wrepl_name *names){ NTSTATUS status; uint32_t i; DEBUG(4,("apply records count[%u]:owner[%s]:min[%llu]:max[%llu]:partner[%s]\n", num_names, owner->address, (long long)owner->min_version, (long long)owner->max_version, partner->address)); for (i=0; i < num_names; i++) { TALLOC_CTX *tmp_mem = talloc_new(partner); NT_STATUS_HAVE_NO_MEMORY(tmp_mem); status = wreplsrv_apply_one_record(partner, tmp_mem, owner, &names[i]); talloc_free(tmp_mem); NT_STATUS_NOT_OK_RETURN(status); } status = wreplsrv_add_table(partner->service, partner->service, &partner->service->table, owner->address, owner->max_version); NT_STATUS_NOT_OK_RETURN(status); return NT_STATUS_OK;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -