dns-and-server-ref-counts-20040530
[openafs.git] / src / WINNT / afsd / cm_server.c
index 22385cb..77707e1 100644 (file)
@@ -1,23 +1,28 @@
-/* 
- * Copyright (C) 1998, 1989 Transarc Corporation - All rights reserved
- *
- * (C) COPYRIGHT IBM CORPORATION 1987, 1988
- * LICENSED MATERIALS - PROPERTY OF IBM
- *
- *
+/*
+ * Copyright 2000, International Business Machines Corporation and others.
+ * All Rights Reserved.
+ * 
+ * This software has been released under the terms of the IBM Public
+ * License.  For details, see the LICENSE file in the top-level source
+ * directory or online at http://www.openafs.org/dl/license10.html
  */
+
 #include <afs/param.h>
 #include <afs/stds.h>
 
+#ifndef DJGPP
 #include <windows.h>
 #include <winsock2.h>
+#include <nb30.h>
+#else
+#include <sys/socket.h>
+#endif /* !DJGPP */
 #include <stdlib.h>
 #include <malloc.h>
 #include <string.h>
 
 #include <osi.h>
 #include <rx/rx.h>
-#include <nb30.h>
 #include "afsd.h"
 
 osi_rwlock_t cm_serverLock;
@@ -194,17 +199,21 @@ cm_server_t *cm_NewServer(struct sockaddr_in *socketp, int type, cm_cell_t *cell
        osi_assert(socketp->sin_family == AF_INET);
 
        tsp = malloc(sizeof(*tsp));
-        memset(tsp, 0, sizeof(*tsp));
+    memset(tsp, 0, sizeof(*tsp));
        tsp->type = type;
-        tsp->cellp = cellp;
-        tsp->refCount = 1;
-       tsp->allNextp = cm_allServersp;
-        cm_allServersp = tsp;
+    tsp->cellp = cellp;
+    tsp->refCount = 1;
        lock_InitializeMutex(&tsp->mx, "cm_server_t mutex");
        tsp->addr = *socketp;
 
        cm_SetServerPrefs(tsp); 
-        return tsp;
+
+    lock_ObtainWrite(&cm_serverLock); /* get server lock */
+       tsp->allNextp = cm_allServersp;
+    cm_allServersp = tsp;
+    lock_ReleaseWrite(&cm_serverLock); /* release server lock */
+
+    return tsp;
 }
 
 /* find a server based on its properties */
@@ -251,6 +260,8 @@ long cm_ChecksumServerList(cm_serverRef_t *serversp)
        int first = 1;
        cm_serverRef_t *tsrp;
 
+    lock_ObtainWrite(&cm_serverLock);
+
        for (tsrp = serversp; tsrp; tsrp=tsrp->next) {
                if (first)
                        first = 0;
@@ -259,6 +270,7 @@ long cm_ChecksumServerList(cm_serverRef_t *serversp)
                sum ^= (long) tsrp->server;
        }
 
+    lock_ReleaseWrite(&cm_serverLock);
        return sum;
 }
 
@@ -271,11 +283,14 @@ void cm_InsertServerList(cm_serverRef_t** list, cm_serverRef_t* element)
        cm_serverRef_t  *current=*list;
        unsigned short ipRank = element->server->ipRank;
 
+    lock_ObtainWrite(&cm_serverLock);
+
        /* insertion into empty list  or at the beginning of the list */
        if ( !current || (current->server->ipRank > ipRank) )
        {
                element->next = *list;
                *list = element;
+        lock_ReleaseWrite(&cm_serverLock);
                return ;        
        }
        
@@ -287,6 +302,7 @@ void cm_InsertServerList(cm_serverRef_t** list, cm_serverRef_t* element)
        }
        element->next = current->next;
        current->next = element;
+    lock_ReleaseWrite(&cm_serverLock);
 }
 /*
 ** Re-sort the server list with the modified rank
@@ -302,6 +318,7 @@ long cm_ChangeRankServer(cm_serverRef_t** list, cm_server_t*        server)
        if ( (!*current) || !((*current)->next)  )
                return 1;               /* list unchanged: return success */
 
+    lock_ObtainWrite(&cm_serverLock);
        /* if the server is on the list, delete it from list */
        while ( *current )
        {
@@ -313,8 +330,10 @@ long cm_ChangeRankServer(cm_serverRef_t** list, cm_server_t*       server)
                }
                current = & ( (*current)->next);        
        }
-       /* if this volume is not replicated on this server  */
-       if ( !element)
+    lock_ReleaseWrite(&cm_serverLock);
+
+    /* if this volume is not replicated on this server  */
+       if (!element)
                return 1;       /* server is not on list */
 
        /* re-insert deleted element into the list with modified rank*/
@@ -335,6 +354,8 @@ void cm_RandomizeServer(cm_serverRef_t** list)
        if ( !tsrp || ! tsrp->next )
                return ; 
 
+    lock_ObtainWrite(&cm_serverLock);
+
        /* count the number of servers with the lowest rank */
        lowestRank = tsrp->server->ipRank;
        for ( count=1, tsrp=tsrp->next; tsrp; tsrp=tsrp->next)
@@ -346,12 +367,17 @@ void cm_RandomizeServer(cm_serverRef_t** list)
        }       
 
        /* if there is only one server with the lowest rank, we are done */
-       if ( count <= 1 )               
+       if ( count <= 1 ) {
+        lock_ReleaseWrite(&cm_serverLock);
                return ;
+    }
 
        picked = rand() % count;
-       if ( !picked )
+       if ( !picked ) {
+        lock_ReleaseWrite(&cm_serverLock);
                return ;
+    }
+
        tsrp = *list;
        while (--picked >= 0)
        {
@@ -361,4 +387,52 @@ void cm_RandomizeServer(cm_serverRef_t** list)
        lastTsrp->next = tsrp->next;  /* delete random element from list*/
        tsrp->next     = *list; /* insert element at the beginning of list */
        *list          = tsrp;
+    lock_ReleaseWrite(&cm_serverLock);
 }
+
+void cm_FreeServer(cm_server_t* server)
+{
+    lock_ObtainWrite(&cm_serverLock);
+    if (--(server->refCount) == 0)
+    {
+        /* we need to check to ensure that all of the connections
+         * for this server have a 0 refCount; otherwise, they will
+         * not be garbage collected 
+         */
+        cm_GCConnections(&server);  /* connsp */
+
+        lock_FinalizeMutex(&server->mx);
+        if ( cm_allServersp == server )
+            cm_allServersp = server->allNextp;
+        else {
+            cm_server_t *tsp;
+
+            for(tsp = cm_allServersp; tsp->allNextp; tsp=tsp->allNextp) {
+                if ( tsp->allNextp == server ) {
+                    tsp->allNextp = server->allNextp;
+                    break;
+                }
+            }
+        }
+    }
+    lock_ReleaseWrite(&cm_serverLock);
+}
+
+void cm_FreeServerList(cm_serverRef_t** list)
+{
+    cm_serverRef_t  *current = *list;
+    cm_serverRef_t  *next = 0;
+
+    lock_ObtainWrite(&cm_serverLock);
+
+    while (current)
+    {
+        next = current->next;
+        cm_FreeServer(current->server);
+        free(current);
+        current = next;
+    }
+  
+    lock_ReleaseWrite(&cm_serverLock);
+}
+