Don't cast the return from calloc()
[openafs.git] / src / libadmin / client / afs_clientAdmin.c
index f2183ce..1e04869 100644 (file)
@@ -9,36 +9,23 @@
 
 #include <afsconfig.h>
 #include <afs/param.h>
+#include <afs/stds.h>
 
-RCSID
-    ("$Header$");
+#include <roken.h>
 
-#include <afs/stds.h>
-#include "afs_clientAdmin.h"
-#include "../adminutil/afs_AdminInternal.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <afs/cellconfig.h>
 #ifdef AFS_NT40_ENV
 #include <afs/afssyscalls.h>
-#include <winsock2.h>
 #include <afs/fs_utils.h>
+#define close(x) closesocket(x)
 #else
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <netdb.h>
 #include <afs/venus.h>
-#include <errno.h>
-#include <strings.h>
-#include <unistd.h>
 #endif
-#include <string.h>
-#include <afs/kautils.h>
 #include <rx/rx.h>
+#include <rx/rxstat.h>
 #include <rx/rx_null.h>
 #include <rx/rxkad.h>
+
+#include <afs/kautils.h>
 #include <afs/dirpath.h>
 #include <afs/afs_AdminErrors.h>
 #include <afs/afs_vosAdmin.h>
@@ -46,6 +33,10 @@ RCSID
 #include <afs/ptserver.h>
 #include <afs/vlserver.h>
 #include <afs/pthread_glock.h>
+#include <afs/sys_prototypes.h>
+
+#include "afs_clientAdmin.h"
+#include "../adminutil/afs_AdminInternal.h"
 
 /*
  * AFS client administration functions.
@@ -59,6 +50,8 @@ RCSID
 
 static const unsigned long ADMIN_TICKET_LIFETIME = 24 * 3600;
 
+static const unsigned long SERVER_TTL = 10 * 60;
+
 /*
  * We need a way to track whether or not the client library has been 
  * initialized.  We count on the fact that the other library initialization
@@ -946,6 +939,8 @@ afsclient_CellOpen(const char *cellName, const void *tokenHandle,
        c_handle->begin_magic = BEGIN_MAGIC;
        c_handle->is_valid = 1;
        c_handle->is_null = 0;
+       c_handle->server_list = NULL;
+       c_handle->server_ttl = 0;
        c_handle->end_magic = END_MAGIC;
        *cellHandleP = (void *)c_handle;
     }
@@ -1020,9 +1015,11 @@ afsclient_NullCellOpen(void **cellHandleP, afs_status_p st)
     c_handle->kas_valid = 0;
     c_handle->pts_valid = 0;
     c_handle->vos_valid = 0;
-    c_handle->kas = 0;
-    c_handle->pts = 0;
-    c_handle->vos = 0;
+    c_handle->kas = NULL;
+    c_handle->pts = NULL;
+    c_handle->vos = NULL;
+    c_handle->server_list = NULL;
+    c_handle->server_ttl = 0;
     *cellHandleP = (void *)c_handle;
     rc = 1;
 
@@ -1071,6 +1068,8 @@ afsclient_CellClose(const void *cellHandle, afs_status_p st)
        goto fail_afsclient_CellClose;
     }
 
+    if (c_handle->server_list)
+       free(c_handle->server_list);
     if (c_handle->kas_valid)
        ubik_ClientDestroy(c_handle->kas);
     if (c_handle->pts_valid)
@@ -1228,7 +1227,7 @@ client_ExtractDriveLetter(char *path)
 static int
 Parent(char *directory, char *parentDirectory)
 {
-    register char *tp;
+    char *tp;
     int rc = 0;
 
     strcpy(parentDirectory, directory);
@@ -1358,7 +1357,8 @@ afsclient_MountPointCreate(const void *cellHandle, const char *directory,
      */
 
     if (volCheck == CHECK_VOLUME) {
-       if (!vos_VLDBGet(cellHandle, 0, 0, volumeName, &vldbEntry, &tst)) {
+       if (!vos_VLDBGet(cellHandle, 0, 0, (char *)volumeName, &vldbEntry,
+                        &tst)) {
            goto fail_afsclient_MountPointCreate;
        }
     }
@@ -1490,7 +1490,7 @@ afsclient_ACLEntryAdd(const char *directory, const char *user,
     idata.out_size = 2048;
     idata.in_size = 0;
     idata.in = idata.out = old_acl_string;
-    tst = pioctl(directory, VIOCGETAL, &idata, 1);
+    tst = pioctl((char *)directory, VIOCGETAL, &idata, 1);
 
     if (tst != 0) {
        goto fail_afsclient_ACLEntryAdd;
@@ -1579,7 +1579,7 @@ afsclient_ACLEntryAdd(const char *directory, const char *user,
     idata.out_size = 0;
     idata.in_size = strlen(new_acl_string) + 1;
     idata.in = idata.out = new_acl_string;
-    tst = pioctl(directory, VIOCSETAL, &idata, 1);
+    tst = pioctl((char *) directory, VIOCSETAL, &idata, 1);
 
     if (tst != 0) {
        goto fail_afsclient_ACLEntryAdd;
@@ -1824,8 +1824,9 @@ afsclient_AFSServerGetBegin(const void *cellHandle, void **iterationIdP,
     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
     afs_admin_iterator_p iter =
        (afs_admin_iterator_p) malloc(sizeof(afs_admin_iterator_t));
-    server_get_p serv = (server_get_p) calloc(1, sizeof(server_get_t));
-    const char *cellName;
+    server_get_p serv = calloc(1, sizeof(server_get_t));
+    server_get_p serv_cache = NULL;
+    const char *cellName = NULL;
     void *database_iter;
     util_databaseServerEntry_t database_entry;
     void *fileserver_iter;
@@ -1847,57 +1848,77 @@ afsclient_AFSServerGetBegin(const void *cellHandle, void **iterationIdP,
        goto fail_afsclient_AFSServerGetBegin;
     }
 
-    /*
-     * Retrieve the list of database servers for this cell.
-     */
-
-    if (!afsclient_CellNameGet(cellHandle, &cellName, &tst)) {
-       goto fail_afsclient_AFSServerGetBegin;
+  restart:
+    LOCK_GLOBAL_MUTEX;
+    if (c_handle->server_list != NULL && c_handle->server_ttl < time(NULL)) {
+       serv_cache = c_handle->server_list;
+       c_handle->server_list = NULL;
     }
+    UNLOCK_GLOBAL_MUTEX;
 
-    if (!util_DatabaseServerGetBegin(cellName, &database_iter, &tst)) {
-       goto fail_afsclient_AFSServerGetBegin;
-    }
+    if (c_handle->server_list == NULL) {
+       if (serv_cache == NULL) {
+           serv_cache = (server_get_p) calloc(1, sizeof(server_get_t));
 
-    while (util_DatabaseServerGetNext(database_iter, &database_entry, &tst)) {
-       serv->server[serv->total].serverAddress[0] =
-           database_entry.serverAddress;
-       serv->server[serv->total].serverType = DATABASE_SERVER;
-       serv->total++;
-    }
+           if (serv_cache == NULL) {
+               tst = ADMNOMEM;
+               goto fail_afsclient_AFSServerGetBegin;
+           }
+       }
 
-    if (tst != ADMITERATORDONE) {
-       util_DatabaseServerGetDone(database_iter, 0);
-       goto fail_afsclient_AFSServerGetBegin;
-    }
+       /*
+        * Retrieve the list of database servers for this cell.
+        */
 
-    if (!util_DatabaseServerGetDone(database_iter, &tst)) {
-       goto fail_afsclient_AFSServerGetBegin;
-    }
+       if (!afsclient_CellNameGet(c_handle, &cellName, &tst)) {
+           goto fail_afsclient_AFSServerGetBegin;
+       }
 
-    /*
-     * Retrieve the list of file servers for this cell.
-     */
+       if (!util_DatabaseServerGetBegin(cellName, &database_iter, &tst)) {
+           goto fail_afsclient_AFSServerGetBegin;
+       }
 
-    if (!vos_FileServerGetBegin(cellHandle, 0, &fileserver_iter, &tst)) {
-       goto fail_afsclient_AFSServerGetBegin;
-    }
+       while (util_DatabaseServerGetNext(database_iter, &database_entry, &tst)) {
+           serv->server[serv->total].serverAddress[0] =
+               database_entry.serverAddress;
+           serv->server[serv->total].serverType = DATABASE_SERVER;
+           serv->total++;
+       }
+
+       if (tst != ADMITERATORDONE) {
+           util_DatabaseServerGetDone(database_iter, 0);
+           goto fail_afsclient_AFSServerGetBegin;
+       }
+
+       if (!util_DatabaseServerGetDone(database_iter, &tst)) {
+           goto fail_afsclient_AFSServerGetBegin;
+       }
 
-    while (vos_FileServerGetNext(fileserver_iter, &fileserver_entry, &tst)) {
        /*
-        * See if any of the addresses returned in this fileserver_entry
-        * structure already exist in the list of servers we're building.
-        * If not, create a new record for this server.
+        * Retrieve the list of file servers for this cell.
         */
-       is_dup = 0;
-       for (iserv = 0; iserv < serv->total; iserv++) {
-           for (ientryaddr = 0; ientryaddr < fileserver_entry.count;
-                ientryaddr++) {
-               for (iservaddr = 0; iservaddr < AFS_MAX_SERVER_ADDRESS;
-                    iservaddr++) {
-                   if (serv->server[iserv].serverAddress[iservaddr] ==
-                       fileserver_entry.serverAddress[ientryaddr]) {
-                       is_dup = 1;
+
+       if (!vos_FileServerGetBegin(c_handle, 0, &fileserver_iter, &tst)) {
+           goto fail_afsclient_AFSServerGetBegin;
+       }
+
+       while (vos_FileServerGetNext(fileserver_iter, &fileserver_entry, &tst)) {
+           /*
+            * See if any of the addresses returned in this fileserver_entry
+            * structure already exist in the list of servers we're building.
+            * If not, create a new record for this server.
+            */
+           is_dup = 0;
+           for (iserv = 0; iserv < serv->total; iserv++) {
+               for (ientryaddr = 0; ientryaddr < fileserver_entry.count; ientryaddr++) {
+                   for (iservaddr = 0; iservaddr < AFS_MAX_SERVER_ADDRESS; iservaddr++) {
+                       if (serv->server[iserv].serverAddress[iservaddr] ==
+                            fileserver_entry.serverAddress[ientryaddr]) {
+                           is_dup = 1;
+                           break;
+                       }
+                   }
+                   if (is_dup) {
                        break;
                    }
                }
@@ -1905,72 +1926,80 @@ afsclient_AFSServerGetBegin(const void *cellHandle, void **iterationIdP,
                    break;
                }
            }
+
            if (is_dup) {
-               break;
+               serv->server[iserv].serverType |= FILE_SERVER;
+           } else {
+               iserv = serv->total++;
+               serv->server[iserv].serverType = FILE_SERVER;
            }
-       }
 
-       if (is_dup) {
-           serv->server[iserv].serverType |= FILE_SERVER;
-       } else {
-           iserv = serv->total++;
-           serv->server[iserv].serverType = FILE_SERVER;
-       }
+           /*
+            * Add the addresses from the vldb list to the serv->server[iserv]
+            * record.  Remember that VLDB's list-of-addrs is not guaranteed
+            * to be unique in a particular entry, or to return only one entry
+            * per machine--so when we add addresses, always check for
+            * duplicate entries.
+            */
 
-       /*
-        * Add the addresses from the vldb list to the serv->server[iserv]
-        * record.  Remember that VLDB's list-of-addrs is not guaranteed
-        * to be unique in a particular entry, or to return only one entry
-        * per machine--so when we add addresses, always check for
-        * duplicate entries.
-        */
-
-       for (ientryaddr = 0; ientryaddr < fileserver_entry.count;
-            ientryaddr++) {
-           for (iservaddr = 0; iservaddr < AFS_MAX_SERVER_ADDRESS;
-                iservaddr++) {
-               if (serv->server[iserv].serverAddress[iservaddr] ==
-                   fileserver_entry.serverAddress[ientryaddr]) {
-                   break;
-               }
-           }
-           if (iservaddr == AFS_MAX_SERVER_ADDRESS) {
-               for (iservaddr = 0; iservaddr < AFS_MAX_SERVER_ADDRESS;
-                    iservaddr++) {
-                   if (!serv->server[iserv].serverAddress[iservaddr]) {
-                       serv->server[iserv].serverAddress[iservaddr] =
-                           fileserver_entry.serverAddress[ientryaddr];
+           for (ientryaddr = 0; ientryaddr < fileserver_entry.count; ientryaddr++) {
+               for (iservaddr = 0; iservaddr < AFS_MAX_SERVER_ADDRESS; iservaddr++) {
+                   if (serv->server[iserv].serverAddress[iservaddr] ==
+                        fileserver_entry.serverAddress[ientryaddr]) {
                        break;
                    }
                }
+               if (iservaddr == AFS_MAX_SERVER_ADDRESS) {
+                   for (iservaddr = 0; iservaddr < AFS_MAX_SERVER_ADDRESS;
+                         iservaddr++) {
+                       if (!serv->server[iserv].serverAddress[iservaddr]) {
+                           serv->server[iserv].serverAddress[iservaddr] =
+                               fileserver_entry.serverAddress[ientryaddr];
+                           break;
+                       }
+                   }
+               }
            }
        }
-    }
 
-    if (tst != ADMITERATORDONE) {
-       vos_FileServerGetDone(fileserver_iter, 0);
-       goto fail_afsclient_AFSServerGetBegin;
-    }
+       if (tst != ADMITERATORDONE) {
+           vos_FileServerGetDone(fileserver_iter, 0);
+           goto fail_afsclient_AFSServerGetBegin;
+       }
 
-    if (!vos_FileServerGetDone(fileserver_iter, &tst)) {
-       goto fail_afsclient_AFSServerGetBegin;
-    }
+       if (!vos_FileServerGetDone(fileserver_iter, &tst)) {
+           goto fail_afsclient_AFSServerGetBegin;
+       }
 
-    /*
-     * Iterate over the list and fill in the hostname of each of the servers
-     */
+       /*
+        * Iterate over the list and fill in the hostname of each of the servers
+        */
 
-    LOCK_GLOBAL_MUTEX;
-    for (iserv = 0; iserv < serv->total; iserv++) {
-       int addr = htonl(serv->server[iserv].serverAddress[0]);
-       host = gethostbyaddr((const char *)&addr, sizeof(int), AF_INET);
-       if (host != NULL) {
-           strncpy(serv->server[iserv].serverName, host->h_name,
-                   AFS_MAX_SERVER_NAME_LEN);
-            serv->server[iserv].serverName[AFS_MAX_SERVER_NAME_LEN - 1] = '\0';
+       for (iserv = 0; iserv < serv->total; iserv++) {
+           int addr = htonl(serv->server[iserv].serverAddress[0]);
+           LOCK_GLOBAL_MUTEX;
+           host = gethostbyaddr((const char *)&addr, sizeof(int), AF_INET);
+           if (host != NULL) {
+               strncpy(serv->server[iserv].serverName, host->h_name,
+                        AFS_MAX_SERVER_NAME_LEN);
+               serv->server[iserv].serverName[AFS_MAX_SERVER_NAME_LEN - 1] = '\0';
+           }
+           UNLOCK_GLOBAL_MUTEX;
        }
+    
+       memcpy(serv_cache, serv, sizeof(server_get_t));
+    } else {
+       int race = 0;
+       LOCK_GLOBAL_MUTEX;
+       if (c_handle->server_list == NULL)
+           race = 1;
+       else
+           memcpy(serv, c_handle->server_list, sizeof(server_get_t));
+       UNLOCK_GLOBAL_MUTEX;
+       if (race)
+           goto restart;
     }
-    UNLOCK_GLOBAL_MUTEX;
+
     if (IteratorInit
            (iter, (void *)serv, GetServerRPC, GetServerFromCache, NULL, NULL,
             &tst)) {
@@ -1981,17 +2010,28 @@ afsclient_AFSServerGetBegin(const void *cellHandle, void **iterationIdP,
   fail_afsclient_AFSServerGetBegin:
 
     if (rc == 0) {
-       if (iter != NULL) {
+       if (iter != NULL)
            free(iter);
-       }
-       if (serv != NULL) {
+       if (serv != NULL)
            free(serv);
+       if (serv_cache != NULL)
+           free(serv_cache);
+    } else {
+       if (serv_cache) {
+           LOCK_GLOBAL_MUTEX;
+           /* in case there was a race and we constructed the list twice */
+           if (c_handle->server_list)
+               free(c_handle->server_list);
+
+           c_handle->server_list = serv_cache;
+           c_handle->server_ttl = time(NULL) + SERVER_TTL;
+           UNLOCK_GLOBAL_MUTEX;
        }
     }
 
-    if (st != NULL) {
+    if (st != NULL)
        *st = tst;
-    }
+
     return rc;
 }