Fix PGSQL voicemail issues (bug #625) and fix reload races in iax2
[asterisk/asterisk.git] / channels / chan_iax2.c
index d3194ea..30336bf 100755 (executable)
@@ -181,6 +181,7 @@ struct iax2_user {
        int amaflags;
        int hascallerid;
        int delme;
+       int temponly;
        int capability;
        int trunk;
        char callerid[AST_MAX_EXTENSION];
@@ -216,6 +217,7 @@ struct iax2_peer {
        int expirey;                                    /* How soon to expire */
        int capability;                                 /* Capability */
        int delme;                                              /* I need to be deleted */
+       int temponly;                                   /* I'm only a temp */
        int trunk;                                              /* Treat as an IAX trunking */
        struct timeval txtrunktime;             /* Transmit trunktime */
        struct timeval rxtrunktime;             /* Receive trunktime */
@@ -1596,7 +1598,7 @@ static struct iax2_peer *mysql_peer(char *peer)
        } else {
                strncpy(p->name, peer, sizeof(p->name) - 1);
                p->dynamic = 1;
-               p->delme = 1;
+               p->temponly = 1;
                p->expire = -1;
                p->capability = iax2_capability;
                p->authmethods = IAX_AUTH_MD5 | IAX_AUTH_PLAINTEXT;
@@ -1652,7 +1654,7 @@ static struct iax2_user *mysql_user(char *user)
                p = NULL;
        } else {
                strncpy(p->name, user, sizeof(p->name) - 1);
-               p->delme = 1;
+               p->temponly = 1;
                p->capability = iax2_capability;
                p->authmethods = IAX_AUTH_MD5 | IAX_AUTH_PLAINTEXT;
        }
@@ -1711,7 +1713,7 @@ static int create_addr(struct sockaddr_in *sin, int *capability, int *sendani, i
                        if (notransfer)
                                *notransfer=p->notransfer;
                } else {
-                       if (p->delme)
+                       if (p->temponly)
                                free(p);
                        p = NULL;
                }
@@ -1728,7 +1730,7 @@ static int create_addr(struct sockaddr_in *sin, int *capability, int *sendani, i
                }
        } else if (!p)
                return -1;
-       if (p->delme)
+       if (p->temponly)
                free(p);
        return 0;
 }
@@ -3049,7 +3051,7 @@ static int register_verify(int callno, struct sockaddr_in *sin, struct iax_ies *
        if (!p->dynamic) {
                if (authdebug)
                        ast_log(LOG_NOTICE, "Peer '%s' is not dynamic (from %s)\n", peer, inet_ntoa(sin->sin_addr));
-               if (p->delme)
+               if (p->temponly)
                        free(p);
                return -1;
        }
@@ -3057,7 +3059,7 @@ static int register_verify(int callno, struct sockaddr_in *sin, struct iax_ies *
        if (!ast_apply_ha(p->ha, sin)) {
                if (authdebug)
                        ast_log(LOG_NOTICE, "Host %s denied access to register peer '%s'\n", inet_ntoa(sin->sin_addr), p->name);
-               if (p->delme)
+               if (p->temponly)
                        free(p);
                return -1;
        }
@@ -3083,14 +3085,14 @@ static int register_verify(int callno, struct sockaddr_in *sin, struct iax_ies *
                        if (!keyn) {
                                if (authdebug)
                                        ast_log(LOG_NOTICE, "Host %s failed RSA authentication with inkeys '%s'\n", peer, p->inkeys);
-                               if (p->delme)
+                               if (p->temponly)
                                        free(p);
                                return -1;
                        }
                } else {
                        if (authdebug)
                                ast_log(LOG_NOTICE, "Host '%s' trying to do RSA authentication, but we have no inkeys\n", peer);
-                       if (p->delme)
+                       if (p->temponly)
                                free(p);
                        return -1;
                }
@@ -3099,7 +3101,7 @@ static int register_verify(int callno, struct sockaddr_in *sin, struct iax_ies *
                if (strcmp(secret, p->secret)) {
                        if (authdebug)
                                ast_log(LOG_NOTICE, "Host %s did not provide proper plaintext password for '%s'\n", inet_ntoa(sin->sin_addr), p->name);
-                       if (p->delme)
+                       if (p->temponly)
                                free(p);
                        return -1;
                } else
@@ -3116,7 +3118,7 @@ static int register_verify(int callno, struct sockaddr_in *sin, struct iax_ies *
                if (strcasecmp(requeststr, md5secret)) {
                        if (authdebug)
                                ast_log(LOG_NOTICE, "Host %s failed MD5 authentication for '%s' (%s != %s)\n", inet_ntoa(sin->sin_addr), p->name, requeststr, md5secret);
-                       if (p->delme)
+                       if (p->temponly)
                                free(p);
                        return -1;
                } else
@@ -3124,7 +3126,7 @@ static int register_verify(int callno, struct sockaddr_in *sin, struct iax_ies *
        } else if (strlen(md5secret) || strlen(secret)) {
                if (authdebug)
                        ast_log(LOG_NOTICE, "Inappropriate authentication received\n");
-               if (p->delme)
+               if (p->temponly)
                        free(p);
                return -1;
        }
@@ -3132,7 +3134,7 @@ static int register_verify(int callno, struct sockaddr_in *sin, struct iax_ies *
        /* Choose lowest expirey number */
        if (expire && (expire < iaxs[callno]->expirey)) 
                iaxs[callno]->expirey = expire;
-       if (p->delme)
+       if (p->temponly)
                free(p);
        return 0;
        
@@ -3564,7 +3566,7 @@ static int update_registry(char *name, struct sockaddr_in *sin, int callno)
 #endif 
        if (p) {
 #ifdef MYSQL_FRIENDS
-               if (p->delme)
+               if (p->temponly)
                        mysql_update_peer(name, sin);
 #endif
                if (inaddrcmp(&p->addr, sin)) {
@@ -3596,7 +3598,7 @@ static int update_registry(char *name, struct sockaddr_in *sin, int callno)
                }
                if (p->hascallerid)
                        iax_ie_append_str(&ied, IAX_IE_CALLING_NAME, p->callerid);
-               if (p->delme)
+               if (p->temponly)
                        free(p);
                return send_command_final(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_REGACK, 0, ied.buf, ied.pos, -1);;
        }
@@ -3628,7 +3630,7 @@ static int registry_authrequest(char *name, int callno)
                        iax_ie_append_str(&ied, IAX_IE_CHALLENGE, iaxs[callno]->challenge);
                }
                iax_ie_append_str(&ied, IAX_IE_USERNAME, name);
-               if (p->delme)
+               if (p->temponly)
                        free(p);
                return send_command(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_REGAUTH, 0, ied.buf, ied.pos, -1);;
        } 
@@ -5219,10 +5221,36 @@ static struct iax2_peer *build_peer(char *name, struct ast_variable *v)
 
 static struct iax2_user *build_user(char *name, struct ast_variable *v)
 {
-       struct iax2_user *user;
+       struct iax2_user *prev, *user;
        struct iax2_context *con, *conl = NULL;
        int format;
-       user = (struct iax2_user *)malloc(sizeof(struct iax2_user));
+       int found;
+       
+       prev = NULL;
+       ast_mutex_lock(&userl.lock);
+       user = userl.users;
+       while(user) {
+               if (!strcasecmp(user->name, name)) {    
+                       break;
+               }
+               prev = user;
+               user = user->next;
+       }
+       if (user) {
+               found++;
+               /* Already in the list, remove it and it will be added back (or FREE'd) */
+               if (prev) {
+                       prev->next = user->next;
+               } else {
+                       userl.users = user->next;
+               }
+               ast_mutex_unlock(&userl.lock);
+       } else {
+               ast_mutex_unlock(&userl.lock);
+               user = malloc(sizeof(struct iax2_user));
+               memset(user, 0, sizeof(struct iax2_user));
+       }
+       
        if (user) {
                memset(user, 0, sizeof(struct iax2_user));
                user->capability = iax2_capability;
@@ -5282,39 +5310,34 @@ static struct iax2_user *build_user(char *name, struct ast_variable *v)
                        //      ast_log(LOG_WARNING, "Ignoring %s\n", v->name);
                        v = v->next;
                }
-       }
-       if (!user->authmethods) {
-               if (strlen(user->secret)) {
-                       user->authmethods = IAX_AUTH_MD5 | IAX_AUTH_PLAINTEXT;
-                       if (strlen(user->inkeys))
-                               user->authmethods |= IAX_AUTH_RSA;
-               } else if (strlen(user->inkeys)) {
-                       user->authmethods = IAX_AUTH_RSA;
-               } else {
-                       user->authmethods = IAX_AUTH_MD5 | IAX_AUTH_PLAINTEXT;
+               if (!user->authmethods) {
+                       if (strlen(user->secret)) {
+                               user->authmethods = IAX_AUTH_MD5 | IAX_AUTH_PLAINTEXT;
+                               if (strlen(user->inkeys))
+                                       user->authmethods |= IAX_AUTH_RSA;
+                       } else if (strlen(user->inkeys)) {
+                               user->authmethods = IAX_AUTH_RSA;
+                       } else {
+                               user->authmethods = IAX_AUTH_MD5 | IAX_AUTH_PLAINTEXT;
+                       }
                }
+               user->delme = 0;
        }
        return user;
 }
 
-
-static void delete_users(void){
-       struct iax2_user *user, *userlast;
+static void delete_users(void)
+{
+       struct iax2_user *user;
        struct iax2_peer *peer;
        struct iax2_registry *reg, *regl;
 
-       /* Delete all users */
        ast_mutex_lock(&userl.lock);
        for (user=userl.users;user;) {
-               ast_free_ha(user->ha);
-               free_context(user->contexts);
-               userlast = user;
-               user=user->next;
-               free(userlast);
+               user->delme = 1;
+               user = user->next;
        }
-       userl.users=NULL;
        ast_mutex_unlock(&userl.lock);
-
        for (reg = registrations;reg;) {
                regl = reg;
                reg = reg->next;
@@ -5332,6 +5355,28 @@ static void delete_users(void){
        ast_mutex_unlock(&peerl.lock);
 }
 
+static void prune_users(void)
+{
+       struct iax2_user *user, *usernext, *userlast = NULL;
+       ast_mutex_lock(&userl.lock);
+       for (user=userl.users;user;) {
+               usernext = user->next;
+               if (user->delme) {
+                       ast_free_ha(user->ha);
+                       free_context(user->contexts);
+                       user=user->next;
+                       free(user);
+                       if (userlast)
+                               userlast->next = usernext;
+                       else
+                               userl.users = usernext;
+               } else
+                       userlast = user;
+               user = usernext;
+       }
+       ast_mutex_unlock(&userl.lock);
+}
+
 static void prune_peers(void){
        /* Prune peers who still are supposed to be deleted */
        struct iax2_peer *peer, *peerlast, *peernext;
@@ -5563,6 +5608,7 @@ static int reload_config(void)
        delete_users();
        set_config(config,&dead_sin);
        prune_peers();
+       prune_users();
        for (reg = registrations; reg; reg = reg->next)
                iax2_do_register(reg);
        /* Qualify hosts, too */