r13116: make sure we don't add more than 25 addresses to a record,
authorStefan Metzmacher <metze@samba.org>
Tue, 24 Jan 2006 19:14:08 +0000 (19:14 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 18:51:27 +0000 (13:51 -0500)
and don't return more than 25 in a name query reply

we now also order the addresses from the newest owned address
to the oldest replica address

metze
(This used to be commit 602ec0f1c66e6cb9e958e0e7cc10d3294737378a)

source4/nbt_server/wins/winsdb.c
source4/nbt_server/wins/winsserver.c
source4/wrepl_server/wrepl_apply_records.c

index 625d4e68dcbdb116f69ccef8762f052be85b8b6c..f294705e55d5c6bdb312958d56d8c52917a63f6f 100644 (file)
@@ -353,11 +353,134 @@ struct winsdb_addr **winsdb_addr_list_make(TALLOC_CTX *mem_ctx)
        return addresses;
 }
 
-struct winsdb_addr **winsdb_addr_list_add(struct winsdb_addr **addresses, const char *address,
-                                         const char *wins_owner, time_t expire_time)
+static int winsdb_addr_sort_list (struct winsdb_addr **p1, struct winsdb_addr **p2, void *opaque)
 {
-       size_t len = winsdb_addr_list_length(addresses);
+       struct winsdb_addr *a1 = talloc_get_type(*p1, struct winsdb_addr);
+       struct winsdb_addr *a2 = talloc_get_type(*p2, struct winsdb_addr);
+       struct winsdb_handle *h= talloc_get_type(opaque, struct winsdb_handle);
+       BOOL a1_owned = False;
+       BOOL a2_owned = False;
+
+       /*
+        * first the owned addresses with the newest to the oldest address
+        * then the replica addresses with the newest to the oldest address
+        */
+       if (a2->expire_time != a1->expire_time) {
+               return a2->expire_time - a1->expire_time;
+       }
+
+       if (strcmp(a2->wins_owner, h->local_owner) == 0) {
+               a2_owned = True;
+       }
+
+       if (strcmp(a1->wins_owner, h->local_owner) == 0) {
+               a1_owned = True;
+       }
 
+       return a2_owned - a1_owned;
+}
+
+struct winsdb_addr **winsdb_addr_list_add(struct winsdb_handle *h, const struct winsdb_record *rec,
+                                         struct winsdb_addr **addresses, const char *address,
+                                         const char *wins_owner, time_t expire_time,
+                                         BOOL is_name_registration)
+{
+       struct winsdb_addr *old_addr = NULL;
+       size_t len = 0;
+       size_t i;
+       BOOL found_old_replica = False;
+
+       /*
+        * count the addresses and maybe
+        * find an old entry for the new address
+        */
+       for (i=0; addresses[i]; i++) {
+               if (old_addr) continue;
+               if (strcmp(addresses[i]->address, address) == 0) {
+                       old_addr = addresses[i];
+               }
+       }
+       len = i;
+
+       /*
+        * the address is already there
+        * and we can replace it
+        */
+       if (old_addr) {
+               goto remove_old_addr;
+       }
+
+       /*
+        * if we don't have 25 addresses already,
+        * we can just add the new address
+        */
+       if (len < 25) {
+               goto add_new_addr;
+       }
+
+       /*
+        * if we haven't found the address,
+        * and we have already have 25 addresses
+        * if so then we need to do the following:
+        * - if it isn't a name registration, then just ignore the new address
+        * - if it is a name registration, then first search for 
+        *   the oldest replica and if there's no replica address
+        *   search the oldest owned address
+        */
+       if (!is_name_registration) {
+               return addresses;
+       }
+
+       /*
+        * find the oldest replica address, if there's no replica
+        * record at all, find the oldest owned address
+        */
+       for (i=0; addresses[i]; i++) {
+               BOOL cur_is_replica = False;
+               /* find out if the current address is a replica */
+               if (strcmp(addresses[i]->wins_owner, h->local_owner) != 0) {
+                       cur_is_replica = True;
+               }
+
+               /*
+                * if we already found a replica address and the current address
+                * is not a replica, then skip it
+                */
+               if (found_old_replica && !cur_is_replica) continue;
+
+               /*
+                * if we found the first replica address, reset the address
+                * that would be replaced
+                */
+               if (!found_old_replica && cur_is_replica) {
+                       found_old_replica = True;
+                       old_addr = addresses[i];
+                       continue;
+               }
+
+               /*
+                * if the first address isn't a replica, just start with 
+                * the first one
+                */
+               if (!old_addr) {
+                       old_addr = addresses[i];
+                       continue;
+               }
+
+               /*
+                * see if we find an older address
+                */
+               if (addresses[i]->expire_time < old_addr->expire_time) {
+                       old_addr = addresses[i];
+                       continue;
+               }
+       }
+
+remove_old_addr:
+       winsdb_addr_list_remove(addresses, old_addr->address);
+       len --;
+
+add_new_addr:
        addresses = talloc_realloc(addresses, addresses, struct winsdb_addr *, len + 2);
        if (!addresses) return NULL;
 
@@ -383,6 +506,8 @@ struct winsdb_addr **winsdb_addr_list_add(struct winsdb_addr **addresses, const
 
        addresses[len+1] = NULL;
 
+       ldb_qsort(addresses, len+1 , sizeof(addresses[0]), h, (ldb_qsort_cmp_fn_t)winsdb_addr_sort_list);
+
        return addresses;
 }
 
@@ -395,7 +520,7 @@ void winsdb_addr_list_remove(struct winsdb_addr **addresses, const char *address
                        break;
                }
        }
-       if (!addresses[i]) return;
+       if (addresses[i]) talloc_free(addresses[i]);
 
        for (; addresses[i]; i++) {
                addresses[i] = addresses[i+1];
index 5cc3a51a0077e1480a5c5a5aaedb0c04fad8a3bd..7f674299966b37f36e95f5ea4a8edc4d7ad2a092 100644 (file)
@@ -90,10 +90,12 @@ static uint8_t wins_register_new(struct nbt_name_socket *nbtsock,
        rec.addresses           = winsdb_addr_list_make(packet);
        if (rec.addresses == NULL) return NBT_RCODE_SVR;
 
-       rec.addresses     = winsdb_addr_list_add(rec.addresses,
+       rec.addresses     = winsdb_addr_list_add(winssrv->wins_db,
+                                                &rec, rec.addresses,
                                                 address,
                                                 winssrv->wins_db->local_owner,
-                                                rec.expire_time);
+                                                rec.expire_time,
+                                                True);
        if (rec.addresses == NULL) return NBT_RCODE_SVR;
 
        DEBUG(4,("WINS: accepted registration of %s with address %s\n",
@@ -123,8 +125,13 @@ static uint8_t wins_update_ttl(struct nbt_name_socket *nbtsock,
        rec->registered_by = src->addr;
 
        if (winsdb_addr) {
-               winsdb_addr->wins_owner  = winssrv->wins_db->local_owner;
-               winsdb_addr->expire_time = rec->expire_time;
+               rec->addresses = winsdb_addr_list_add(winssrv->wins_db,
+                                                     rec, rec->addresses,
+                                                     winsdb_addr->address,
+                                                     winssrv->wins_db->local_owner,
+                                                     rec->expire_time,
+                                                     True);
+               if (rec->addresses == NULL) return NBT_RCODE_SVR;
        }
 
        if (strcmp(winssrv->wins_db->local_owner, rec->wins_owner) != 0) {
@@ -154,10 +161,12 @@ static uint8_t wins_sgroup_merge(struct nbt_name_socket *nbtsock,
        rec->expire_time   = time(NULL) + ttl;
        rec->registered_by = src->addr;
 
-       rec->addresses     = winsdb_addr_list_add(rec->addresses,
+       rec->addresses     = winsdb_addr_list_add(winssrv->wins_db,
+                                                 rec, rec->addresses,
                                                  address,
                                                  winssrv->wins_db->local_owner,
-                                                 rec->expire_time);
+                                                 rec->expire_time,
+                                                 True);
        if (rec->addresses == NULL) return NBT_RCODE_SVR;
 
        DEBUG(5,("WINS: sgroup merge of %s at %s\n",
@@ -244,18 +253,25 @@ static void wins_wack_allow(struct wack_state *s)
                        break;
                }
                if (found) {
-                       rec->addresses[i]->wins_owner = s->winssrv->wins_db->local_owner;
-                       rec->addresses[i]->expire_time = rec->expire_time;
+                       rec->addresses = winsdb_addr_list_add(s->winssrv->wins_db,
+                                                             rec, rec->addresses,
+                                                             s->reg_address,
+                                                             s->winssrv->wins_db->local_owner,
+                                                             rec->expire_time,
+                                                             True);
+                       if (rec->addresses == NULL) goto failed;
                        continue;
                }
 
                winsdb_addr_list_remove(rec->addresses, rec->addresses[i]->address);
        }
 
-       rec->addresses = winsdb_addr_list_add(rec->addresses,
+       rec->addresses = winsdb_addr_list_add(s->winssrv->wins_db,
+                                             rec, rec->addresses,
                                              s->reg_address,
                                              s->winssrv->wins_db->local_owner,
-                                             rec->expire_time);
+                                             rec->expire_time,
+                                             True);
        if (rec->addresses == NULL) goto failed;
 
        /* if we have more than one address, this becomes implicit a MHOMED record */
@@ -623,16 +639,24 @@ static void nbtd_winsserver_query(struct nbt_name_socket *nbtsock,
        if (addresses_1b && addresses_1b[0]) {
                const char **addresses_1c = addresses;
                uint32_t i;
+               uint32_t num_addrs;
 
                addresses = str_list_add(NULL, addresses_1b[0]);
                if (!addresses) {
                        goto notfound;
                }
                talloc_steal(packet, addresses);
+               num_addrs = 1;
 
                for (i=0; addresses_1c[i]; i++) {
                        if (strcmp(addresses_1b[0], addresses_1c[i]) == 0) continue;
 
+                       /*
+                        * stop when we already have 25 addresses
+                        */
+                       if (num_addrs >= 25) break;
+
+                       num_addrs++;                    
                        addresses = str_list_add(addresses, addresses_1c[i]);
                        if (!addresses) {
                                goto notfound;
@@ -643,7 +667,7 @@ static void nbtd_winsserver_query(struct nbt_name_socket *nbtsock,
        if (rec->type == WREPL_TYPE_SGROUP) {
                nb_flags |= NBT_NM_GROUP;
        } else {
-               nb_flags |= (rec->node <<13);           
+               nb_flags |= (rec->node <<13);
        }
 
 found:
@@ -705,7 +729,7 @@ static void nbtd_winsserver_release(struct nbt_name_socket *nbtsock,
        if (!winsdb_addr_list_check(rec->addresses, src->addr)) {
                int i;
                DEBUG(4,("WINS: silently ignoring attempted name release on %s from %s\n", nbt_name_string(rec, rec->name), src->addr));
-               DEBUGADD(4, ("Registered Addressss: \n"));
+               DEBUGADD(4, ("Registered Addresses: \n"));
                for (i=0; rec->addresses && rec->addresses[i]; i++) {
                        DEBUGADD(4, ("%s\n", rec->addresses[i]->address));
                }
index f41957a210b2c4aec6909c17551ff35f93b8077e..e1b4bcbf39181b937be92ed999bd9e14aa4f035c 100644 (file)
@@ -686,10 +686,12 @@ static NTSTATUS r_do_add(struct wreplsrv_partner *partner,
 
        for (i=0; i < replica->num_addresses; i++) {
                /* TODO: find out if rec->expire_time is correct here */
-               rec->addresses = winsdb_addr_list_add(rec->addresses,
+               rec->addresses = winsdb_addr_list_add(partner->service->wins_db,
+                                                     rec, rec->addresses,
                                                      replica->addresses[i].address,
                                                      replica->addresses[i].owner,
-                                                     rec->expire_time);
+                                                     rec->expire_time,
+                                                     False);
                NT_STATUS_HAVE_NO_MEMORY(rec->addresses);
        }
 
@@ -729,10 +731,12 @@ static NTSTATUS r_do_replace(struct wreplsrv_partner *partner,
 
        for (i=0; i < replica->num_addresses; i++) {
                /* TODO: find out if rec->expire_time is correct here */
-               rec->addresses = winsdb_addr_list_add(rec->addresses,
+               rec->addresses = winsdb_addr_list_add(partner->service->wins_db,
+                                                     rec, rec->addresses,
                                                      replica->addresses[i].address,
                                                      replica->addresses[i].owner,
-                                                     rec->expire_time);
+                                                     rec->expire_time,
+                                                     False);
                NT_STATUS_HAVE_NO_MEMORY(rec->addresses);
        }
 
@@ -829,11 +833,12 @@ static NTSTATUS r_do_mhomed_merge(struct wreplsrv_partner *partner,
        merge->registered_by = NULL;
 
        for (i=0; i < replica->num_addresses; i++) {
-               /* TODO: find out if rec->expire_time is correct here */
-               merge->addresses = winsdb_addr_list_add(merge->addresses,
+               merge->addresses = winsdb_addr_list_add(partner->service->wins_db,
+                                                       merge, merge->addresses,
                                                        replica->addresses[i].address,
                                                        replica->addresses[i].owner,
-                                                       merge->expire_time);
+                                                       merge->expire_time,
+                                                       False);
                NT_STATUS_HAVE_NO_MEMORY(merge->addresses);
        }
 
@@ -849,11 +854,12 @@ static NTSTATUS r_do_mhomed_merge(struct wreplsrv_partner *partner,
                }
                if (found) continue;
 
-               /* TODO: find out if rec->expire_time is correct here */
-               merge->addresses = winsdb_addr_list_add(merge->addresses,
+               merge->addresses = winsdb_addr_list_add(partner->service->wins_db,
+                                                       merge, merge->addresses,
                                                        rec->addresses[i]->address,
                                                        rec->addresses[i]->wins_owner,
-                                                       merge->expire_time);
+                                                       rec->addresses[i]->expire_time,
+                                                       False);
                NT_STATUS_HAVE_NO_MEMORY(merge->addresses);
        }
 
@@ -1198,34 +1204,36 @@ static NTSTATUS r_do_sgroup_merge(struct wreplsrv_partner *partner,
                        break;
                }
 
-               /* if it's also in the replica, it'll added later */
-               if (found) continue;
-
                /* 
                 * if the address isn't in the replica and is owned by replicas owner,
                 * it won't be added to the merged record
                 */
-               if (strcmp(rec->addresses[i]->wins_owner, owner->address) == 0) {
+               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
+                * 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(merge->addresses,
+               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);
+                                                       rec->addresses[i]->expire_time,
+                                                       False);
                NT_STATUS_HAVE_NO_MEMORY(merge->addresses);
        }
 
        for (i=0; i < replica->num_addresses; i++) {
-               /* TODO: find out if rec->expire_time is correct here */
-               merge->addresses = winsdb_addr_list_add(merge->addresses,
+               merge->addresses = winsdb_addr_list_add(partner->service->wins_db,
+                                                       merge, merge->addresses,
                                                        replica->addresses[i].address,
                                                        replica->addresses[i].owner,
-                                                       merge->expire_time);
+                                                       merge->expire_time,
+                                                       False);
                NT_STATUS_HAVE_NO_MEMORY(merge->addresses);
        }