Update chan_iax2 to use linkedlists.h for users and peers. Modify the way get_from_jb and expire_registry works to get rid of certain crash scenarios. Finally - change the way expire_registry works when realtime autoclear is enabled to be a bit more efficient.

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@24422 65c4cc65-6c06-0410-ace0-fbb531ad65f3
1.4
Joshua Colp 19 years ago
parent 7cc4511fa2
commit b82b277790

@ -308,8 +308,8 @@ struct iax2_user {
struct ast_codec_pref prefs;
struct ast_ha *ha;
struct iax2_context *contexts;
struct iax2_user *next;
struct ast_variable *vars;
AST_LIST_ENTRY(iax2_user) entry;
};
struct iax2_peer {
@ -357,7 +357,7 @@ struct iax2_peer {
int smoothing; /*!< Sample over how many units to determine historic ms */
struct ast_ha *ha;
struct iax2_peer *next;
AST_LIST_ENTRY(iax2_peer) entry;
};
#define IAX2_TRUNK_PREFACE (sizeof(struct iax_frame) + sizeof(struct ast_iax2_meta_hdr) + sizeof(struct ast_iax2_meta_trunk_hdr))
@ -628,15 +628,9 @@ static struct ast_iax2_queue {
ast_mutex_t lock;
} iaxq;
static struct ast_user_list {
struct iax2_user *users;
ast_mutex_t lock;
} userl;
static AST_LIST_HEAD_STATIC(users, iax2_user);
static struct ast_peer_list {
struct iax2_peer *peers;
ast_mutex_t lock;
} peerl;
static AST_LIST_HEAD_STATIC(peers, iax2_peer);
static struct ast_firmware_list {
struct iax_firmware *wares;
@ -1009,14 +1003,18 @@ static int uncompress_subclass(unsigned char csub)
static struct iax2_peer *find_peer(const char *name, int realtime)
{
struct iax2_peer *peer;
ast_mutex_lock(&peerl.lock);
for(peer = peerl.peers; peer; peer = peer->next) {
struct iax2_peer *peer = NULL;
/* Grab peer from linked list */
AST_LIST_LOCK(&peers);
AST_LIST_TRAVERSE(&peers, peer, entry) {
if (!strcasecmp(peer->name, name)) {
break;
}
}
ast_mutex_unlock(&peerl.lock);
AST_LIST_UNLOCK(&peers);
/* Now go for realtime if applicable */
if(!peer && realtime)
peer = realtime_peer(name, NULL);
return peer;
@ -1024,23 +1022,21 @@ static struct iax2_peer *find_peer(const char *name, int realtime)
static int iax2_getpeername(struct sockaddr_in sin, char *host, int len, int lockpeer)
{
struct iax2_peer *peer;
struct iax2_peer *peer = NULL;
int res = 0;
if (lockpeer)
ast_mutex_lock(&peerl.lock);
peer = peerl.peers;
while (peer) {
AST_LIST_LOCK(&peers);
AST_LIST_TRAVERSE(&peers, peer, entry) {
if ((peer->addr.sin_addr.s_addr == sin.sin_addr.s_addr) &&
(peer->addr.sin_port == sin.sin_port)) {
ast_copy_string(host, peer->name, len);
res = 1;
break;
(peer->addr.sin_port == sin.sin_port)) {
ast_copy_string(host, peer->name, len);
res = 1;
break;
}
peer = peer->next;
}
if (lockpeer)
ast_mutex_unlock(&peerl.lock);
AST_LIST_UNLOCK(&peers);
if (!peer) {
peer = realtime_peer(NULL, &sin);
if (peer) {
@ -2134,20 +2130,20 @@ static int iax2_show_peer(int fd, int argc, char *argv[])
static char *complete_iax2_show_peer(const char *line, const char *word, int pos, int state)
{
int which = 0;
struct iax2_peer *p;
struct iax2_peer *p = NULL;
char *res = NULL;
int wordlen = strlen(word);
/* 0 - iax2; 1 - show; 2 - peer; 3 - <peername> */
if (pos == 3) {
ast_mutex_lock(&peerl.lock);
for (p = peerl.peers ; p ; p = p->next) {
AST_LIST_LOCK(&peers);
AST_LIST_TRAVERSE(&peers, p, entry) {
if (!strncasecmp(p->name, word, wordlen) && ++which > state) {
res = ast_strdup(p->name);
break;
}
}
ast_mutex_unlock(&peerl.lock);
AST_LIST_UNLOCK(&peers);
}
return res;
@ -2304,66 +2300,75 @@ static void unwrap_timestamp(struct iax_frame *fr)
#ifdef NEWJB
static int get_from_jb(void *p);
static void update_jbsched(struct chan_iax2_pvt *pvt) {
int when;
when = ast_tvdiff_ms(ast_tvnow(), pvt->rxcore);
/* fprintf(stderr, "now = %d, next=%d\n", when, jb_next(pvt->jb)); */
when = jb_next(pvt->jb) - when;
/* fprintf(stderr, "when = %d\n", when); */
if(pvt->jbid > -1) ast_sched_del(sched, pvt->jbid);
if(when <= 0) {
/* XXX should really just empty until when > 0.. */
when = 1;
}
pvt->jbid = ast_sched_add(sched, when, get_from_jb, (void *)pvt);
/* Signal scheduler thread */
signal_condition(&sched_lock, &sched_cond);
static void update_jbsched(struct chan_iax2_pvt *pvt)
{
int when;
when = ast_tvdiff_ms(ast_tvnow(), pvt->rxcore);
/* fprintf(stderr, "now = %d, next=%d\n", when, jb_next(pvt->jb)); */
when = jb_next(pvt->jb) - when;
/* fprintf(stderr, "when = %d\n", when); */
if(pvt->jbid > -1) ast_sched_del(sched, pvt->jbid);
if(when <= 0) {
/* XXX should really just empty until when > 0.. */
when = 1;
}
pvt->jbid = ast_sched_add(sched, when, get_from_jb, CALLNO_TO_PTR(pvt->callno));
/* Signal scheduler thread */
signal_condition(&sched_lock, &sched_cond);
}
static void __get_from_jb(void *p)
{
/* make sure pvt is valid! */
struct chan_iax2_pvt *pvt = p;
struct iax_frame *fr;
jb_frame frame;
int ret;
long now;
long next;
struct timeval tv;
ast_mutex_lock(&iaxsl[pvt->callno]);
/* fprintf(stderr, "get_from_jb called\n"); */
pvt->jbid = -1;
gettimeofday(&tv,NULL);
/* round up a millisecond since ast_sched_runq does; */
/* prevents us from spinning while waiting for our now */
/* to catch up with runq's now */
tv.tv_usec += 1000;
now = ast_tvdiff_ms(tv, pvt->rxcore);
int callno = PTR_TO_CALLNO(p);
struct chan_iax2_pvt *pvt = iaxs[callno];
struct iax_frame *fr;
jb_frame frame;
int ret;
long now;
long next;
struct timeval tv;
/* Make sure we have a valid private structure before going on */
ast_mutex_lock(&iaxsl[callno]);
pvt = iaxs[callno];
if (!pvt) {
/* No go! */
ast_mutex_unlock(&iaxsl[callno]);
return;
}
if(now >= (next = jb_next(pvt->jb))) {
/* fprintf(stderr, "get_from_jb called\n"); */
pvt->jbid = -1;
gettimeofday(&tv,NULL);
/* round up a millisecond since ast_sched_runq does; */
/* prevents us from spinning while waiting for our now */
/* to catch up with runq's now */
tv.tv_usec += 1000;
now = ast_tvdiff_ms(tv, pvt->rxcore);
if(now >= (next = jb_next(pvt->jb))) {
ret = jb_get(pvt->jb,&frame,now,ast_codec_interp_len(pvt->voiceformat));
switch(ret) {
case JB_OK:
/*if(frame.type == JB_TYPE_VOICE && next + 20 != jb_next(pvt->jb)) fprintf(stderr, "NEXT %ld is not %ld+20!\n", jb_next(pvt->jb), next); */
fr = frame.data;
__do_deliver(fr);
break;
break;
case JB_INTERP:
{
{
struct ast_frame af;
/*if(next + 20 != jb_next(pvt->jb)) fprintf(stderr, "NEXT %ld is not %ld+20!\n", jb_next(pvt->jb), next); */
/* create an interpolation frame */
/*fprintf(stderr, "Making Interpolation frame\n"); */
af.frametype = AST_FRAME_VOICE;
@ -2375,28 +2380,28 @@ static void __get_from_jb(void *p)
af.data = NULL;
af.delivery = ast_tvadd(pvt->rxcore, ast_samp2tv(next, 1000));
af.offset=AST_FRIENDLY_OFFSET;
/* queue the frame: For consistency, we would call __do_deliver here, but __do_deliver wants an iax_frame,
* which we'd need to malloc, and then it would free it. That seems like a drag */
if (iaxs[pvt->callno] && !ast_test_flag(iaxs[pvt->callno], IAX_ALREADYGONE))
iax2_queue_frame(pvt->callno, &af);
}
break;
if (!ast_test_flag(iaxs[callno], IAX_ALREADYGONE))
iax2_queue_frame(callno, &af);
}
break;
case JB_DROP:
/*if(next != jb_next(pvt->jb)) fprintf(stderr, "NEXT %ld is not next %ld!\n", jb_next(pvt->jb), next); */
iax2_frame_free(frame.data);
break;
break;
case JB_NOFRAME:
case JB_EMPTY:
/* do nothing */
break;
break;
default:
/* shouldn't happen */
break;
break;
}
}
update_jbsched(pvt);
ast_mutex_unlock(&iaxsl[pvt->callno]);
}
update_jbsched(pvt);
ast_mutex_unlock(&iaxsl[callno]);
}
static int get_from_jb(void *data)
@ -2803,10 +2808,9 @@ static struct iax2_peer *realtime_peer(const char *peername, struct sockaddr_in
ast_sched_del(sched, peer->expire);
peer->expire = ast_sched_add(sched, (global_rtautoclear) * 1000, expire_registry, peer);
}
ast_mutex_lock(&peerl.lock);
peer->next = peerl.peers;
peerl.peers = peer;
ast_mutex_unlock(&peerl.lock);
AST_LIST_LOCK(&peers);
AST_LIST_INSERT_HEAD(&peers, peer, entry);
AST_LIST_UNLOCK(&peers);
if (ast_test_flag(peer, IAX_DYNAMIC))
reg_source_db(peer);
} else {
@ -2861,10 +2865,9 @@ static struct iax2_user *realtime_user(const char *username)
if (ast_test_flag((&globalflags), IAX_RTCACHEFRIENDS)) {
ast_set_flag(user, IAX_RTCACHEFRIENDS);
ast_mutex_lock(&userl.lock);
user->next = userl.users;
userl.users = user;
ast_mutex_unlock(&userl.lock);
AST_LIST_LOCK(&users);
AST_LIST_INSERT_HEAD(&users, user, entry);
AST_LIST_UNLOCK(&users);
} else {
ast_set_flag(user, IAX_TEMPONLY);
}
@ -3520,19 +3523,19 @@ static int iax2_write(struct ast_channel *c, struct ast_frame *f);
static int iax2_getpeertrunk(struct sockaddr_in sin)
{
struct iax2_peer *peer;
struct iax2_peer *peer = NULL;
int res = 0;
ast_mutex_lock(&peerl.lock);
peer = peerl.peers;
while(peer) {
AST_LIST_LOCK(&peers);
AST_LIST_TRAVERSE(&peers, peer, entry) {
if ((peer->addr.sin_addr.s_addr == sin.sin_addr.s_addr) &&
(peer->addr.sin_port == sin.sin_port)) {
res = ast_test_flag(peer, IAX_TRUNK);
break;
(peer->addr.sin_port == sin.sin_port)) {
res = ast_test_flag(peer, IAX_TRUNK);
break;
}
peer = peer->next;
}
ast_mutex_unlock(&peerl.lock);
AST_LIST_UNLOCK(&peers);
return res;
}
@ -4270,7 +4273,7 @@ static int iax2_show_users(int fd, int argc, char *argv[])
#define FORMAT "%-15.15s %-20.20s %-15.15s %-15.15s %-5.5s %-5.10s\n"
#define FORMAT2 "%-15.15s %-20.20s %-15.15d %-15.15s %-5.5s %-5.10s\n"
struct iax2_user *user;
struct iax2_user *user = NULL;
char auth[90];
char *pstr = "";
@ -4288,32 +4291,32 @@ static int iax2_show_users(int fd, int argc, char *argv[])
return RESULT_SHOWUSAGE;
}
ast_mutex_lock(&userl.lock);
ast_cli(fd, FORMAT, "Username", "Secret", "Authen", "Def.Context", "A/C","Codec Pref");
for(user=userl.users;user;user=user->next) {
AST_LIST_LOCK(&users);
AST_LIST_TRAVERSE(&users, user, entry) {
if (havepattern && regexec(&regexbuf, user->name, 0, NULL, 0))
continue;
if (!ast_strlen_zero(user->secret)) {
ast_copy_string(auth,user->secret,sizeof(auth));
} else if (!ast_strlen_zero(user->inkeys)) {
snprintf(auth, sizeof(auth), "Key: %-15.15s ", user->inkeys);
} else
ast_copy_string(auth, "-no secret-", sizeof(auth));
if(ast_test_flag(user,IAX_CODEC_NOCAP))
pstr = "REQ Only";
else if(ast_test_flag(user,IAX_CODEC_NOPREFS))
pstr = "Disabled";
else
pstr = ast_test_flag(user,IAX_CODEC_USER_FIRST) ? "Caller" : "Host";
ast_cli(fd, FORMAT2, user->name, auth, user->authmethods,
user->contexts ? user->contexts->context : context,
user->ha ? "Yes" : "No", pstr);
user->contexts ? user->contexts->context : context,
user->ha ? "Yes" : "No", pstr);
}
ast_mutex_unlock(&userl.lock);
AST_LIST_UNLOCK(&users);
if (havepattern)
regfree(&regexbuf);
@ -4335,7 +4338,7 @@ static int __iax2_show_peers(int manager, int fd, struct mansession *s, int argc
#define FORMAT2 "%-15.15s %-15.15s %s %-15.15s %-8s %s %-10s%s"
#define FORMAT "%-15.15s %-15.15s %s %-15.15s %-5d%s %s %-10s%s"
struct iax2_peer *peer;
struct iax2_peer *peer = NULL;
char name[256];
char iabuf[INET_ADDRSTRLEN];
int registeredonly=0;
@ -4374,12 +4377,14 @@ static int __iax2_show_peers(int manager, int fd, struct mansession *s, int argc
return RESULT_SHOWUSAGE;
}
ast_mutex_lock(&peerl.lock);
if (s)
astman_append(s, FORMAT2, "Name/Username", "Host", " ", "Mask", "Port", " ", "Status", term);
else
ast_cli(fd, FORMAT2, "Name/Username", "Host", " ", "Mask", "Port", " ", "Status", term);
for (peer = peerl.peers;peer;peer = peer->next) {
AST_LIST_LOCK(&peers);
AST_LIST_TRAVERSE(&peers, peer, entry) {
char nm[20];
char status[20];
char srch[2000];
@ -4404,31 +4409,31 @@ static int __iax2_show_peers(int manager, int fd, struct mansession *s, int argc
unmonitored_peers++;
ast_copy_string(nm, ast_inet_ntoa(iabuf, sizeof(iabuf), peer->mask), sizeof(nm));
snprintf(srch, sizeof(srch), FORMAT, name,
peer->addr.sin_addr.s_addr ? ast_inet_ntoa(iabuf, sizeof(iabuf), peer->addr.sin_addr) : "(Unspecified)",
ast_test_flag(peer, IAX_DYNAMIC) ? "(D)" : "(S)",
nm,
ntohs(peer->addr.sin_port), ast_test_flag(peer, IAX_TRUNK) ? "(T)" : " ",
peer->encmethods ? "(E)" : " ", status, term);
peer->addr.sin_addr.s_addr ? ast_inet_ntoa(iabuf, sizeof(iabuf), peer->addr.sin_addr) : "(Unspecified)",
ast_test_flag(peer, IAX_DYNAMIC) ? "(D)" : "(S)",
nm,
ntohs(peer->addr.sin_port), ast_test_flag(peer, IAX_TRUNK) ? "(T)" : " ",
peer->encmethods ? "(E)" : " ", status, term);
if (s)
astman_append(s, FORMAT, name,
peer->addr.sin_addr.s_addr ? ast_inet_ntoa(iabuf, sizeof(iabuf), peer->addr.sin_addr) : "(Unspecified)",
ast_test_flag(peer, IAX_DYNAMIC) ? "(D)" : "(S)",
nm,
ntohs(peer->addr.sin_port), ast_test_flag(peer, IAX_TRUNK) ? "(T)" : " ",
peer->encmethods ? "(E)" : " ", status, term);
peer->addr.sin_addr.s_addr ? ast_inet_ntoa(iabuf, sizeof(iabuf), peer->addr.sin_addr) : "(Unspecified)",
ast_test_flag(peer, IAX_DYNAMIC) ? "(D)" : "(S)",
nm,
ntohs(peer->addr.sin_port), ast_test_flag(peer, IAX_TRUNK) ? "(T)" : " ",
peer->encmethods ? "(E)" : " ", status, term);
else
ast_cli(fd, FORMAT, name,
peer->addr.sin_addr.s_addr ? ast_inet_ntoa(iabuf, sizeof(iabuf), peer->addr.sin_addr) : "(Unspecified)",
ast_test_flag(peer, IAX_DYNAMIC) ? "(D)" : "(S)",
nm,
ntohs(peer->addr.sin_port), ast_test_flag(peer, IAX_TRUNK) ? "(T)" : " ",
peer->encmethods ? "(E)" : " ", status, term);
peer->addr.sin_addr.s_addr ? ast_inet_ntoa(iabuf, sizeof(iabuf), peer->addr.sin_addr) : "(Unspecified)",
ast_test_flag(peer, IAX_DYNAMIC) ? "(D)" : "(S)",
nm,
ntohs(peer->addr.sin_port), ast_test_flag(peer, IAX_TRUNK) ? "(T)" : " ",
peer->encmethods ? "(E)" : " ", status, term);
total_peers++;
}
ast_mutex_unlock(&peerl.lock);
AST_LIST_UNLOCK(&peers);
if (s)
astman_append(s,"%d iax2 peers [%d online, %d offline, %d unmonitored]%s", total_peers, online_peers, offline_peers, unmonitored_peers, term);
@ -4578,13 +4583,14 @@ static int iax2_show_registry(int fd, int argc, char *argv[])
{
#define FORMAT2 "%-20.20s %-10.10s %-20.20s %8.8s %s\n"
#define FORMAT "%-20.20s %-10.10s %-20.20s %8d %s\n"
struct iax2_registry *reg;
struct iax2_registry *reg = NULL;
char host[80];
char perceived[80];
char iabuf[INET_ADDRSTRLEN];
if (argc != 3)
return RESULT_SHOWUSAGE;
ast_mutex_lock(&peerl.lock);
AST_LIST_LOCK(&peers);
ast_cli(fd, FORMAT2, "Host", "Username", "Perceived", "Refresh", "State");
for (reg = registrations;reg;reg = reg->next) {
snprintf(host, sizeof(host), "%s:%d", ast_inet_ntoa(iabuf, sizeof(iabuf), reg->addr.sin_addr), ntohs(reg->addr.sin_port));
@ -4595,7 +4601,7 @@ static int iax2_show_registry(int fd, int argc, char *argv[])
ast_cli(fd, FORMAT, host,
reg->username, perceived, reg->refresh, regstate2str(reg->regstate));
}
ast_mutex_unlock(&peerl.lock);
AST_LIST_UNLOCK(&peers);
return RESULT_SUCCESS;
#undef FORMAT
#undef FORMAT2
@ -4959,7 +4965,7 @@ static int check_access(int callno, struct sockaddr_in *sin, struct iax_ies *ies
/* Start pessimistic */
int res = -1;
int version = 2;
struct iax2_user *user, *best = NULL;
struct iax2_user *user = NULL, *best = NULL;
int bestscore = 0;
int gotcapability=0;
char iabuf[INET_ADDRSTRLEN];
@ -5014,10 +5020,9 @@ static int check_access(int callno, struct sockaddr_in *sin, struct iax_ies *ies
ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr), version);
return res;
}
ast_mutex_lock(&userl.lock);
/* Search the userlist for a compatible entry, and fill in the rest */
user = userl.users;
while(user) {
AST_LIST_LOCK(&users);
AST_LIST_TRAVERSE(&users, user, entry) {
if ((ast_strlen_zero(iaxs[callno]->username) || /* No username specified */
!strcmp(iaxs[callno]->username, user->name)) /* Or this username specified */
&& ast_apply_ha(user->ha, sin) /* Access is permitted from this IP */
@ -5058,9 +5063,8 @@ static int check_access(int callno, struct sockaddr_in *sin, struct iax_ies *ies
}
}
}
user = user->next;
}
ast_mutex_unlock(&userl.lock);
AST_LIST_UNLOCK(&users);
user = best;
if (!user && !ast_strlen_zero(iaxs[callno]->username)) {
user = realtime_user(iaxs[callno]->username);
@ -5473,7 +5477,7 @@ static int authenticate(char *challenge, char *secret, char *keyn, int authmetho
static int authenticate_reply(struct chan_iax2_pvt *p, struct sockaddr_in *sin, struct iax_ies *ies, char *override, char *okey)
{
struct iax2_peer *peer;
struct iax2_peer *peer = NULL;
/* Start pessimistic */
int res = -1;
int authmethods = 0;
@ -5497,23 +5501,21 @@ static int authenticate_reply(struct chan_iax2_pvt *p, struct sockaddr_in *sin,
/* Normal password authentication */
res = authenticate(p->challenge, override, okey, authmethods, &ied, sin, &p->ecx, &p->dcx);
} else {
ast_mutex_lock(&peerl.lock);
peer = peerl.peers;
while(peer) {
AST_LIST_LOCK(&peers);
AST_LIST_TRAVERSE(&peers, peer, entry) {
if ((ast_strlen_zero(p->peer) || !strcmp(p->peer, peer->name))
/* No peer specified at our end, or this is the peer */
&& (ast_strlen_zero(peer->username) || (!strcmp(peer->username, p->username)))
/* No username specified in peer rule, or this is the right username */
&& (!peer->addr.sin_addr.s_addr || ((sin->sin_addr.s_addr & peer->mask.s_addr) == (peer->addr.sin_addr.s_addr & peer->mask.s_addr)))
/* No specified host, or this is our host */
) {
/* No peer specified at our end, or this is the peer */
&& (ast_strlen_zero(peer->username) || (!strcmp(peer->username, p->username)))
/* No username specified in peer rule, or this is the right username */
&& (!peer->addr.sin_addr.s_addr || ((sin->sin_addr.s_addr & peer->mask.s_addr) == (peer->addr.sin_addr.s_addr & peer->mask.s_addr)))
/* No specified host, or this is our host */
) {
res = authenticate(p->challenge, peer->secret, peer->outkey, authmethods, &ied, sin, &p->ecx, &p->dcx);
if (!res)
break;
}
peer = peer->next;
}
ast_mutex_unlock(&peerl.lock);
AST_LIST_UNLOCK(&peers);
if (!peer) {
/* We checked our list and didn't find one. It's unlikely, but possible,
that we're trying to authenticate *to* a realtime peer */
@ -5830,7 +5832,25 @@ static void prune_peers(void);
static void __expire_registry(void *data)
{
struct iax2_peer *p = data;
char *name = data;
struct iax2_peer *p = NULL;
/* Go through and grab this peer... and if it needs to be removed... then do it */
AST_LIST_LOCK(&peers);
AST_LIST_TRAVERSE_SAFE_BEGIN(&peers, p, entry) {
if (!strcasecmp(p->name, name)) {
/* If we are set to auto clear then remove ourselves */
if (ast_test_flag(p, IAX_RTAUTOCLEAR))
AST_LIST_REMOVE_CURRENT(&peers, entry);
break;
}
}
AST_LIST_TRAVERSE_SAFE_END
AST_LIST_UNLOCK(&peers);
/* Peer is already gone for whatever reason */
if (!p)
return;
ast_log(LOG_DEBUG, "Expiring registration for peer '%s'\n", p->name);
manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "Peer: IAX2/%s\r\nPeerStatus: Unregistered\r\nCause: Expired\r\n", p->name);
@ -5846,8 +5866,8 @@ static void __expire_registry(void *data)
iax2_regfunk(p->name, 0);
if (ast_test_flag(p, IAX_RTAUTOCLEAR)) {
ast_set_flag(p, IAX_DELME);
prune_peers();
/* We are already gone from the list, so we can just destroy ourselves */
destroy_peer(p);
}
}
@ -5893,7 +5913,7 @@ static void reg_source_db(struct iax2_peer *p)
if (p->expire > -1)
ast_sched_del(sched, p->expire);
ast_device_state_changed("IAX2/%s", p->name); /* Activate notification */
p->expire = ast_sched_add(sched, (p->expiry + 10) * 1000, expire_registry, (void *)p);
p->expire = ast_sched_add(sched, (p->expiry + 10) * 1000, expire_registry, (void *)p->name);
if (iax2_regfunk)
iax2_regfunk(p->name, 1);
register_peer_exten(p, 1);
@ -5971,7 +5991,7 @@ static int update_registry(char *name, struct sockaddr_in *sin, int callno, char
p->expiry = refresh;
}
if (p->expiry && sin->sin_addr.s_addr)
p->expire = ast_sched_add(sched, (p->expiry + 10) * 1000, expire_registry, (void *)p);
p->expire = ast_sched_add(sched, (p->expiry + 10) * 1000, expire_registry, (void *)p->name);
iax_ie_append_str(&ied, IAX_IE_USERNAME, p->name);
iax_ie_append_int(&ied, IAX_IE_DATETIME, iax2_datetime(p->zonetag));
if (sin->sin_addr.s_addr) {
@ -6289,7 +6309,6 @@ static int timing_read(int *id, int fd, short events, void *cbdata)
res = read(fd, buf, sizeof(buf));
if (res < 1) {
ast_log(LOG_WARNING, "Unable to read from timing fd\n");
ast_mutex_unlock(&peerl.lock);
return 1;
}
}
@ -6553,7 +6572,7 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
thread->iofd = fd;
thread->iores = recvfrom(fd, thread->buf, sizeof(thread->buf), 0,(struct sockaddr *) &thread->iosin, &len);
if (thread->iores < 0) {
if (errno != ECONNREFUSED)
if (errno != ECONNREFUSED && errno != EAGAIN)
ast_log(LOG_WARNING, "Error: %s\n", strerror(errno));
handle_error();
AST_LIST_LOCK(&idle_list);
@ -8554,21 +8573,17 @@ static int peer_set_srcaddr(struct iax2_peer *peer, const char *srcaddr)
/*! \brief Create peer structure based on configuration */
static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, int temponly)
{
struct iax2_peer *peer;
struct iax2_peer *prev;
struct iax2_peer *peer = NULL;
struct ast_ha *oldha = NULL;
int maskfound=0;
int found=0;
prev = NULL;
ast_mutex_lock(&peerl.lock);
AST_LIST_LOCK(&peers);
if (!temponly) {
peer = peerl.peers;
while(peer) {
AST_LIST_TRAVERSE(&peers, peer, entry) {
if (!strcmp(peer->name, name)) {
break;
}
prev = peer;
peer = peer->next;
}
} else
peer = NULL;
@ -8576,15 +8591,10 @@ static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, in
found++;
oldha = peer->ha;
peer->ha = NULL;
/* Already in the list, remove it and it will be added back (or FREE'd) */
if (prev) {
prev->next = peer->next;
} else {
peerl.peers = peer->next;
}
ast_mutex_unlock(&peerl.lock);
AST_LIST_REMOVE(&peers, peer, entry);
AST_LIST_UNLOCK(&peers);
} else {
ast_mutex_unlock(&peerl.lock);
AST_LIST_UNLOCK(&peers);
if ((peer = ast_calloc(1, sizeof(*peer)))) {
peer->expire = -1;
peer->pokeexpire = -1;
@ -8744,7 +8754,7 @@ static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, in
/*! \brief Create in-memory user structure from configuration */
static struct iax2_user *build_user(const char *name, struct ast_variable *v, int temponly)
{
struct iax2_user *prev, *user;
struct iax2_user *user = NULL;
struct iax2_context *con, *conl = NULL;
struct ast_ha *oldha = NULL;
struct iax2_context *oldcon = NULL;
@ -8752,16 +8762,12 @@ static struct iax2_user *build_user(const char *name, struct ast_variable *v, in
char *varname = NULL, *varval = NULL;
struct ast_variable *tmpvar = NULL;
prev = NULL;
ast_mutex_lock(&userl.lock);
AST_LIST_LOCK(&users);
if (!temponly) {
user = userl.users;
while(user) {
AST_LIST_TRAVERSE(&users, user, entry) {
if (!strcmp(user->name, name)) {
break;
}
prev = user;
user = user->next;
}
} else
user = NULL;
@ -8772,14 +8778,10 @@ static struct iax2_user *build_user(const char *name, struct ast_variable *v, in
user->ha = NULL;
user->contexts = NULL;
/* 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);
AST_LIST_REMOVE(&users, user, entry);
AST_LIST_UNLOCK(&users);
} else {
ast_mutex_unlock(&userl.lock);
AST_LIST_UNLOCK(&users);
/* This is going to memset'd to 0 in the next block */
user = ast_malloc(sizeof(*user));
}
@ -8894,16 +8896,15 @@ static struct iax2_user *build_user(const char *name, struct ast_variable *v, in
static void delete_users(void)
{
struct iax2_user *user;
struct iax2_peer *peer;
struct iax2_user *user = NULL;
struct iax2_peer *peer = NULL;
struct iax2_registry *reg, *regl;
ast_mutex_lock(&userl.lock);
for (user=userl.users;user;) {
AST_LIST_LOCK(&users);
AST_LIST_TRAVERSE(&users, user, entry)
ast_set_flag(user, IAX_DELME);
user = user->next;
}
ast_mutex_unlock(&userl.lock);
AST_LIST_UNLOCK(&users);
for (reg = registrations;reg;) {
regl = reg;
reg = reg->next;
@ -8922,13 +8923,12 @@ static void delete_users(void)
free(regl);
}
registrations = NULL;
ast_mutex_lock(&peerl.lock);
for (peer=peerl.peers;peer;) {
/* Assume all will be deleted, and we'll find out for sure later */
AST_LIST_LOCK(&peers);
AST_LIST_TRAVERSE(&peers, peer, entry)
ast_set_flag(peer, IAX_DELME);
peer = peer->next;
}
ast_mutex_unlock(&peerl.lock);
AST_LIST_UNLOCK(&peers);
}
static void destroy_user(struct iax2_user *user)
@ -8944,21 +8944,18 @@ static void destroy_user(struct iax2_user *user)
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;
struct iax2_user *user = NULL;
AST_LIST_LOCK(&users);
AST_LIST_TRAVERSE_SAFE_BEGIN(&users, user, entry) {
if (ast_test_flag(user, IAX_DELME)) {
destroy_user(user);
if (userlast)
userlast->next = usernext;
else
userl.users = usernext;
} else
userlast = user;
user = usernext;
AST_LIST_REMOVE_CURRENT(&users, entry);
}
}
ast_mutex_unlock(&userl.lock);
AST_LIST_TRAVERSE_SAFE_END
AST_LIST_UNLOCK(&users);
}
static void destroy_peer(struct iax2_peer *peer)
@ -8987,22 +8984,17 @@ static void destroy_peer(struct iax2_peer *peer)
static void prune_peers(void){
/* Prune peers who still are supposed to be deleted */
struct iax2_peer *peer, *peerlast, *peernext;
ast_mutex_lock(&peerl.lock);
peerlast = NULL;
for (peer=peerl.peers;peer;) {
peernext = peer->next;
struct iax2_peer *peer = NULL;
AST_LIST_LOCK(&peers);
AST_LIST_TRAVERSE_SAFE_BEGIN(&peers, peer, entry) {
if (ast_test_flag(peer, IAX_DELME)) {
destroy_peer(peer);
if (peerlast)
peerlast->next = peernext;
else
peerl.peers = peernext;
} else
peerlast = peer;
peer=peernext;
AST_LIST_REMOVE_CURRENT(&peers, entry);
}
}
ast_mutex_unlock(&peerl.lock);
AST_LIST_TRAVERSE_SAFE_END
AST_LIST_UNLOCK(&peers);
}
static void set_timing(void)
@ -9274,19 +9266,17 @@ static int set_config(char *config_file, int reload)
if (!strcasecmp(utype, "user") || !strcasecmp(utype, "friend")) {
user = build_user(cat, ast_variable_browse(cfg, cat), 0);
if (user) {
ast_mutex_lock(&userl.lock);
user->next = userl.users;
userl.users = user;
ast_mutex_unlock(&userl.lock);
AST_LIST_LOCK(&users);
AST_LIST_INSERT_HEAD(&users, user, entry);
AST_LIST_UNLOCK(&users);
}
}
if (!strcasecmp(utype, "peer") || !strcasecmp(utype, "friend")) {
peer = build_peer(cat, ast_variable_browse(cfg, cat), 0);
if (peer) {
ast_mutex_lock(&peerl.lock);
peer->next = peerl.peers;
peerl.peers = peer;
ast_mutex_unlock(&peerl.lock);
AST_LIST_LOCK(&peers);
AST_LIST_INSERT_HEAD(&peers, peer, entry);
AST_LIST_UNLOCK(&peers);
if (ast_test_flag(peer, IAX_DYNAMIC))
reg_source_db(peer);
}
@ -9307,7 +9297,8 @@ static int reload_config(void)
{
char *config = "iax.conf";
struct iax2_registry *reg;
struct iax2_peer *peer;
struct iax2_peer *peer = NULL;
ast_copy_string(accountcode, "", sizeof(accountcode));
ast_copy_string(language, "", sizeof(language));
amaflags = 0;
@ -9322,12 +9313,13 @@ static int reload_config(void)
for (reg = registrations; reg; reg = reg->next)
iax2_do_register(reg);
/* Qualify hosts, too */
ast_mutex_lock(&peerl.lock);
for (peer = peerl.peers; peer; peer = peer->next)
AST_LIST_LOCK(&peers);
AST_LIST_TRAVERSE(&peers, peer, entry)
iax2_poke_peer(peer, 0);
ast_mutex_unlock(&peerl.lock);
AST_LIST_UNLOCK(&peers);
reload_firmware();
iax_provision_reload();
return 0;
}
@ -10035,8 +10027,6 @@ static int __unload_module(void)
static int unload_module(void *mod)
{
ast_mutex_destroy(&iaxq.lock);
ast_mutex_destroy(&userl.lock);
ast_mutex_destroy(&peerl.lock);
ast_mutex_destroy(&waresl.lock);
ast_custom_function_unregister(&iaxpeer_function);
return __unload_module();
@ -10049,8 +10039,8 @@ static int load_module(void *mod)
char *config = "iax.conf";
int res = 0;
int x;
struct iax2_registry *reg;
struct iax2_peer *peer;
struct iax2_registry *reg = NULL;
struct iax2_peer *peer = NULL;
ast_custom_function_register(&iaxpeer_function);
@ -10091,8 +10081,6 @@ static int load_module(void *mod)
ast_netsock_init(netsock);
ast_mutex_init(&iaxq.lock);
ast_mutex_init(&userl.lock);
ast_mutex_init(&peerl.lock);
ast_mutex_init(&waresl.lock);
ast_cli_register_multiple(iax2_cli, sizeof(iax2_cli) / sizeof(iax2_cli[0]));
@ -10124,13 +10112,13 @@ static int load_module(void *mod)
for (reg = registrations; reg; reg = reg->next)
iax2_do_register(reg);
ast_mutex_lock(&peerl.lock);
for (peer = peerl.peers; peer; peer = peer->next) {
AST_LIST_LOCK(&peers);
AST_LIST_TRAVERSE(&peers, peer, entry) {
if (peer->sockfd < 0)
peer->sockfd = defaultsockfd;
iax2_poke_peer(peer, 0);
}
ast_mutex_unlock(&peerl.lock);
AST_LIST_UNLOCK(&peers);
reload_firmware();
iax_provision_reload();
return res;

Loading…
Cancel
Save