- Make Multilink work this time
authorkkalev <kkalev>
Mon, 28 Jul 2003 13:17:38 +0000 (13:17 +0000)
committerkkalev <kkalev>
Mon, 28 Jul 2003 13:17:38 +0000 (13:17 +0000)
- Instead of locking file operations, lock transactions. That means we only keep
  one big transaction lock instead of per file locks (mutexes).

src/modules/rlm_ippool/rlm_ippool.c

index 1fe29df..109b54a 100644 (file)
  * - Fail if we don't find nas port information
  * Oct 2002, Kostas Kalevras <kkalev@noc.ntua.gr>
  * - Do a memset(0) on the key.nas before doing searches. Nusty bug
+ * Jul 2003, Kostas Kalevras <kkalev@noc.ntua.gr>
+ * - Make Multilink work this time
+ * - Instead of locking file operations, lock transactions. That means we only keep
+ *   one big transaction lock instead of per file locks (mutexes).
  */
 
 #include "config.h"
@@ -87,8 +91,7 @@ typedef struct rlm_ippool_t {
        int override;
        GDBM_FILE gdbm;
        GDBM_FILE ip;
-       pthread_mutex_t session_mutex;
-       pthread_mutex_t ip_mutex;
+       pthread_mutex_t op_mutex;
 } rlm_ippool_t;
 
 typedef struct ippool_info {
@@ -262,8 +265,7 @@ static int ippool_instantiate(CONF_SECTION *conf, void **instance)
        pool_name = cf_section_name2(conf);
        if (pool_name != NULL)
                data->name = strdup(pool_name);
-       pthread_mutex_init(&data->session_mutex, NULL);
-       pthread_mutex_init(&data->ip_mutex, NULL);
+       pthread_mutex_init(&data->op_mutex, NULL);
 
        *instance = data;
        
@@ -318,6 +320,7 @@ static int ippool_accounting(void *instance, REQUEST *request)
                        break;
                default:
                        /* We don't care about any other accounting packet */
+                       DEBUG("rlm_ippool: This is not an Accounting-Stop. Return NOOP.");
 
                        return RLM_MODULE_NOOP;
        }
@@ -329,9 +332,8 @@ static int ippool_accounting(void *instance, REQUEST *request)
        key_datum.dptr = (char *) &key;
        key_datum.dsize = sizeof(ippool_key);
 
-       pthread_mutex_lock(&data->session_mutex);
+       pthread_mutex_lock(&data->op_mutex);
        data_datum = gdbm_fetch(data->gdbm, key_datum);
-       pthread_mutex_unlock(&data->session_mutex);
        if (data_datum.dptr != NULL){
 
                /*
@@ -345,12 +347,11 @@ static int ippool_accounting(void *instance, REQUEST *request)
                data_datum.dptr = (char *) &entry;
                data_datum.dsize = sizeof(ippool_info);
 
-               pthread_mutex_lock(&data->session_mutex);
                rcode = gdbm_store(data->gdbm, key_datum, data_datum, GDBM_REPLACE);
-               pthread_mutex_unlock(&data->session_mutex);
                if (rcode < 0) {
                        radlog(L_ERR, "rlm_ippool: Failed storing data to %s: %s",
                                        data->session_db, gdbm_strerror(gdbm_errno));
+                       pthread_mutex_unlock(&data->op_mutex);
                        return RLM_MODULE_FAIL;
                }
 
@@ -359,9 +360,7 @@ static int ippool_accounting(void *instance, REQUEST *request)
                 */
                key_datum.dptr = (char *) &entry.ipaddr;
                key_datum.dsize = sizeof(uint32_t);
-               pthread_mutex_lock(&data->ip_mutex);
                data_datum = gdbm_fetch(data->ip, key_datum);
-               pthread_mutex_unlock(&data->ip_mutex);
                if (data_datum.dptr != NULL){
                        memcpy(&num, data_datum.dptr, sizeof(int));
                        free(data_datum.dptr);
@@ -370,12 +369,11 @@ static int ippool_accounting(void *instance, REQUEST *request)
                                DEBUG("rlm_ippool: num: %d",num);
                                data_datum.dptr = (char *) &num;
                                data_datum.dsize = sizeof(int);
-                               pthread_mutex_lock(&data->ip_mutex);
                                rcode = gdbm_store(data->ip, key_datum, data_datum, GDBM_REPLACE);
-                               pthread_mutex_unlock(&data->ip_mutex);
                                if (rcode < 0) {
                                        radlog(L_ERR, "rlm_ippool: Failed storing data to %s: %s",
                                                        data->ip_index, gdbm_strerror(gdbm_errno));
+                                       pthread_mutex_unlock(&data->op_mutex);
                                        return RLM_MODULE_FAIL;
                                }
                        }
@@ -384,6 +382,8 @@ static int ippool_accounting(void *instance, REQUEST *request)
        else
                DEBUG("rlm_ippool: Entry not found");
 
+       pthread_mutex_unlock(&data->op_mutex);
+
        return RLM_MODULE_OK;
 }
 
@@ -430,7 +430,7 @@ static int ippool_postauth(void *instance, REQUEST *request)
                if ((vp = pairfind(request->packet->vps, PW_NAS_IDENTIFIER)) != NULL)
                        strncpy(nas, vp->strvalue, MAX_NAS_NAME_SIZE - 1);
                else{
-                       DEBUG("rlm_ippool: Could not find nas information.");
+                       DEBUG("rlm_ippool: Could not find nas information. Return NOOP.");
                        return RLM_MODULE_NOOP;
                }
        }
@@ -448,7 +448,7 @@ static int ippool_postauth(void *instance, REQUEST *request)
        if ((vp = pairfind(request->packet->vps, PW_NAS_PORT)) != NULL)
                port = vp->lvalue;
        else{
-               DEBUG("rlm_ippool: Could not find port information.");
+               DEBUG("rlm_ippool: Could not find nas port information. Return NOOP.");
                return RLM_MODULE_NOOP;
        }
 
@@ -459,9 +459,8 @@ static int ippool_postauth(void *instance, REQUEST *request)
        key_datum.dptr = (char *) &key;
        key_datum.dsize = sizeof(ippool_key);
 
-       pthread_mutex_lock(&data->session_mutex);
+       pthread_mutex_lock(&data->op_mutex);
        data_datum = gdbm_fetch(data->gdbm, key_datum);
-       pthread_mutex_unlock(&data->session_mutex);
        if (data_datum.dptr != NULL){
                /*
                 * If there is a corresponding entry in the database with active=1 it is stale.
@@ -476,21 +475,18 @@ static int ippool_postauth(void *instance, REQUEST *request)
                        data_datum.dptr = (char *) &entry;
                        data_datum.dsize = sizeof(ippool_info);
 
-                       pthread_mutex_lock(&data->session_mutex);
                        rcode = gdbm_store(data->gdbm, key_datum, data_datum, GDBM_REPLACE);
-                       pthread_mutex_unlock(&data->session_mutex);
                        if (rcode < 0) {
                                radlog(L_ERR, "rlm_ippool: Failed storing data to %s: %s",
                                        data->session_db, gdbm_strerror(gdbm_errno));
+                               pthread_mutex_unlock(&data->op_mutex);
                                return RLM_MODULE_FAIL;
                        }
                        /* Decrease allocated count from the ip index */
 
                        key_datum.dptr = (char *) &entry.ipaddr;
                        key_datum.dsize = sizeof(uint32_t);
-                       pthread_mutex_lock(&data->ip_mutex);
                        data_datum = gdbm_fetch(data->ip, key_datum);
-                       pthread_mutex_unlock(&data->ip_mutex);
                        if (data_datum.dptr != NULL){
                                memcpy(&num, data_datum.dptr, sizeof(int));
                                free(data_datum.dptr);
@@ -499,18 +495,20 @@ static int ippool_postauth(void *instance, REQUEST *request)
                                        DEBUG("rlm_ippool: num: %d",num);
                                        data_datum.dptr = (char *) &num;
                                        data_datum.dsize = sizeof(int);
-                                       pthread_mutex_lock(&data->ip_mutex);
                                        rcode = gdbm_store(data->ip, key_datum, data_datum, GDBM_REPLACE);
-                                       pthread_mutex_unlock(&data->ip_mutex);
                                        if (rcode < 0) {
                                                radlog(L_ERR, "rlm_ippool: Failed storing data to %s: %s",
                                                                data->ip_index, gdbm_strerror(gdbm_errno));
+                                               pthread_mutex_unlock(&data->op_mutex);
                                                return RLM_MODULE_FAIL;
                                        }
                                }
                        }
                }
        }
+
+       pthread_mutex_unlock(&data->op_mutex);
+
        /*
         * If there is a Framed-IP-Address attribute in the reply, check for override
         */
@@ -527,61 +525,83 @@ static int ippool_postauth(void *instance, REQUEST *request)
 
        /*
         * Walk through the database searching for an active=0 entry.
+        * We search twice. Once to see if we have an active entry with the same callerid
+        * so that MPPP can work ok and then once again to find a free entry.
         */
 
-       pthread_mutex_lock(&data->session_mutex);
-       key_datum = gdbm_firstkey(data->gdbm);
-       while(key_datum.dptr){
-               data_datum = gdbm_fetch(data->gdbm, key_datum);
-               if (data_datum.dptr){
-                       memcpy(&entry,data_datum.dptr, sizeof(ippool_info));
-                       free(data_datum.dptr);  
-                       /*
-                       * If we find an entry for the same caller-id and nas with active=1
-                       * then we use that for multilink (MPPP) to work properly.
-                       */
-                       if (cli != NULL && strcmp(entry.cli,cli) == 0 && entry.active){
-                               memcpy(&key,key_datum.dptr,sizeof(ippool_key));
-                               if (!strcmp(key.nas,nas))
-                                       break;
+       pthread_mutex_lock(&data->op_mutex);
+
+       key_datum.dptr = NULL;
+       if (cli != NULL){       
+               key_datum = gdbm_firstkey(data->gdbm);
+               while(key_datum.dptr){
+                       data_datum = gdbm_fetch(data->gdbm, key_datum);
+                       if (data_datum.dptr){
+                               memcpy(&entry,data_datum.dptr, sizeof(ippool_info));
+                               free(data_datum.dptr);  
+                               /*
+                               * If we find an entry for the same caller-id and nas with active=1
+                               * then we use that for multilink (MPPP) to work properly.
+                               */
+                               if (strcmp(entry.cli,cli) == 0 && entry.active){
+                                       memcpy(&key,key_datum.dptr,sizeof(ippool_key));
+                                       if (!strcmp(key.nas,nas))
+                                               break;
+                               }
                        }
-                       if (entry.active == 0){
-                               datum tmp;              
+                       nextkey = gdbm_nextkey(data->gdbm, key_datum);
+                       free(key_datum.dptr);
+                       key_datum = nextkey;
+               }
+       }
 
-                               tmp.dptr = (char *) &entry.ipaddr;
-                               tmp.dsize = sizeof(uint32_t);
-                               pthread_mutex_lock(&data->ip_mutex);
-                               data_datum = gdbm_fetch(data->ip, tmp);
-                               pthread_mutex_unlock(&data->ip_mutex);
+       if (key_datum.dptr == NULL){
+               key_datum = gdbm_firstkey(data->gdbm);
+               while(key_datum.dptr){
+                       data_datum = gdbm_fetch(data->gdbm, key_datum);
+                       if (data_datum.dptr){
+                               memcpy(&entry,data_datum.dptr, sizeof(ippool_info));
+                               free(data_datum.dptr);  
 
                                /*
-                                * If we find an entry in the ip index and the number is zero (meaning
-                                * that we haven't allocated the same ip address to another nas/port pair)
-                                * or if we don't find an entry then delete the session entry so
-                                * that we can change the key (nas/port)
-                                * Else we don't delete the session entry since we haven't yet deallocated the
-                                * corresponding ip address and we continue our search.
+                                * Find an entry with active == 0
                                 */
+                               if (entry.active == 0){
+                                       datum tmp;              
 
-                               if (data_datum.dptr){
-                                       memcpy(&num,data_datum.dptr, sizeof(int));
-                                       free(data_datum.dptr);
-                                       if (num == 0){
+                                       tmp.dptr = (char *) &entry.ipaddr;
+                                       tmp.dsize = sizeof(uint32_t);
+                                       data_datum = gdbm_fetch(data->ip, tmp);
+       
+                                       /*
+                                        * If we find an entry in the ip index and the number is zero (meaning
+                                        * that we haven't allocated the same ip address to another nas/port pair)
+                                        * or if we don't find an entry then delete the session entry so
+                                        * that we can change the key (nas/port)
+                                        * Else we don't delete the session entry since we haven't yet deallocated the
+                                        * corresponding ip address and we continue our search.
+                                        */
+       
+                                       if (data_datum.dptr){
+                                               memcpy(&num,data_datum.dptr, sizeof(int));
+                                               free(data_datum.dptr);
+                                               if (num == 0){
+                                                       delete = 1;
+                                                       break;
+                                               }
+                                       }
+                                       else{
                                                delete = 1;
                                                break;
                                        }
                                }
-                               else{
-                                       delete = 1;
-                                       break;
-                               }
                        }
+                       nextkey = gdbm_nextkey(data->gdbm, key_datum);
+                       free(key_datum.dptr);
+                       key_datum = nextkey;
                }
-               nextkey = gdbm_nextkey(data->gdbm, key_datum);
-               free(key_datum.dptr);
-               key_datum = nextkey;
        }
-       pthread_mutex_unlock(&data->session_mutex);
+       pthread_mutex_unlock(&data->op_mutex);
        /*
         * If we have found a free entry set active to 1 then add a Framed-IP-Address attribute to
         * the reply
@@ -591,13 +611,12 @@ static int ippool_postauth(void *instance, REQUEST *request)
                data_datum.dptr = (char *) &entry;
                data_datum.dsize = sizeof(ippool_info);
 
+               pthread_mutex_lock(&data->op_mutex);
                if (delete){
                        /*
                         * Delete the entry so that we can change the key
                         */
-                       pthread_mutex_lock(&data->session_mutex);
                        gdbm_delete(data->gdbm, key_datum);
-                       pthread_mutex_unlock(&data->session_mutex);
                }
                free(key_datum.dptr);
                memset(key.nas,0,MAX_NAS_NAME_SIZE);
@@ -607,21 +626,18 @@ static int ippool_postauth(void *instance, REQUEST *request)
                key_datum.dsize = sizeof(ippool_key);
                
                DEBUG2("rlm_ippool: Allocating ip to nas/port: %s/%u",key.nas,key.port);
-               pthread_mutex_lock(&data->session_mutex);
                rcode = gdbm_store(data->gdbm, key_datum, data_datum, GDBM_REPLACE);
-               pthread_mutex_unlock(&data->session_mutex);
                if (rcode < 0) {
                        radlog(L_ERR, "rlm_ippool: Failed storing data to %s: %s",
                                data->session_db, gdbm_strerror(gdbm_errno));
+                               pthread_mutex_unlock(&data->op_mutex);
                        return RLM_MODULE_FAIL;
                }
 
                /* Increase the ip index count */
                key_datum.dptr = (char *) &entry.ipaddr;
                key_datum.dsize = sizeof(uint32_t);     
-               pthread_mutex_lock(&data->ip_mutex);
                data_datum = gdbm_fetch(data->ip, key_datum);
-               pthread_mutex_unlock(&data->ip_mutex);
                if (data_datum.dptr){
                        memcpy(&num,data_datum.dptr,sizeof(int));
                        free(data_datum.dptr);
@@ -630,14 +646,14 @@ static int ippool_postauth(void *instance, REQUEST *request)
                DEBUG("rlm_ippool: num: %d",num);
                data_datum.dptr = (char *) &num;
                data_datum.dsize = sizeof(int);
-               pthread_mutex_lock(&data->ip_mutex);
                rcode = gdbm_store(data->ip, key_datum, data_datum, GDBM_REPLACE);
-               pthread_mutex_unlock(&data->ip_mutex);
                if (rcode < 0) {
                        radlog(L_ERR, "rlm_ippool: Failed storing data to %s: %s",
                                data->ip_index, gdbm_strerror(gdbm_errno));
+                       pthread_mutex_unlock(&data->op_mutex);
                        return RLM_MODULE_FAIL;
                }
+               pthread_mutex_unlock(&data->op_mutex);
                        
 
                DEBUG("rlm_ippool: Allocated ip %s to client on nas %s,port %u",ip_ntoa(str,entry.ipaddr),
@@ -681,8 +697,7 @@ static int ippool_detach(void *instance)
        gdbm_close(data->ip);
        free(data->session_db);
        free(data->ip_index);
-       pthread_mutex_destroy(&data->session_mutex);
-       pthread_mutex_destroy(&data->ip_mutex);
+       pthread_mutex_destroy(&data->op_mutex);
 
        free(instance);
        return 0;