git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@5147 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
Anthony Minessale 2007-05-11 15:01:23 +00:00
parent ebb56a9eba
commit 8c918602d9
1 changed files with 148 additions and 74 deletions

View File

@ -40,16 +40,12 @@ void gettimeofday(struct timeval *tv, void /*struct timezone*/ *tz);
#else #else
#define _BSD_SOURCE 1
#include <netdb.h> #include <netdb.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <sys/time.h> #include <sys/time.h>
#include <stdlib.h> #include <stdlib.h>
#ifdef __GNUC__
#ifndef __USE_SVID
#define __USE_SVID
#endif
#endif
#include <string.h> #include <string.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdio.h> #include <stdio.h>
@ -60,7 +56,7 @@ void gettimeofday(struct timeval *tv, void /*struct timezone*/ *tz);
#include <netinet/in.h> #include <netinet/in.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <time.h> #include <time.h>
#endif #endif
#include "iax2.h" #include "iax2.h"
@ -70,7 +66,7 @@ void gettimeofday(struct timeval *tv, void /*struct timezone*/ *tz);
#ifdef NEWJB #ifdef NEWJB
#include "jitterbuf.h" #include "jitterbuf.h"
#endif #endif
#include "iax-mutex.h"
/* /*
work around jitter-buffer shrinking in asterisk: work around jitter-buffer shrinking in asterisk:
channels/chan_iax2.c:schedule_delivery() shrinks jitter buffer by 2. channels/chan_iax2.c:schedule_delivery() shrinks jitter buffer by 2.
@ -330,6 +326,8 @@ struct iax_sched {
struct iax_sched *next; struct iax_sched *next;
}; };
static mutex_t *sched_mutex = NULL;
static mutex_t *session_mutex = NULL;
static struct iax_sched *schedq = NULL; static struct iax_sched *schedq = NULL;
static struct iax_session *sessions = NULL; static struct iax_session *sessions = NULL;
static int callnums = 1; static int callnums = 1;
@ -412,6 +410,7 @@ static int iax_sched_add(struct iax_event *event, struct iax_frame *frame, sched
sched->func = func; sched->func = func;
sched->arg = arg; sched->arg = arg;
/* Put it in the list, in order */ /* Put it in the list, in order */
iax_mutex_lock(sched_mutex);
cur = schedq; cur = schedq;
while(cur && cur->when <= sched->when) { while(cur && cur->when <= sched->when) {
prev = cur; prev = cur;
@ -423,6 +422,7 @@ static int iax_sched_add(struct iax_event *event, struct iax_frame *frame, sched
} else { } else {
schedq = sched; schedq = sched;
} }
iax_mutex_unlock(sched_mutex);
return 0; return 0;
} else { } else {
DEBU(G "Out of memory!\n"); DEBU(G "Out of memory!\n");
@ -433,7 +433,9 @@ static int iax_sched_add(struct iax_event *event, struct iax_frame *frame, sched
static int iax_sched_del(struct iax_event *event, struct iax_frame *frame, sched_func func, void *arg, int all) static int iax_sched_del(struct iax_event *event, struct iax_frame *frame, sched_func func, void *arg, int all)
{ {
struct iax_sched *cur, *tmp, *prev = NULL; struct iax_sched *cur, *tmp, *prev = NULL;
int ret = 0;
iax_mutex_lock(sched_mutex);
cur = schedq; cur = schedq;
while (cur) { while (cur) {
if (cur->event == event && cur->frame == frame && cur->func == func && cur->arg == arg) { if (cur->event == event && cur->frame == frame && cur->func == func && cur->arg == arg) {
@ -444,13 +446,18 @@ static int iax_sched_del(struct iax_event *event, struct iax_frame *frame, sched
tmp = cur; tmp = cur;
cur = cur->next; cur = cur->next;
free(tmp); free(tmp);
if (!all) if (!all) {
return -1; ret = -1;
goto done;
}
} else { } else {
prev = cur; prev = cur;
cur = cur->next; cur = cur->next;
} }
} }
done:
iax_mutex_unlock(sched_mutex);
return 0; return 0;
} }
@ -458,24 +465,31 @@ static int iax_sched_del(struct iax_event *event, struct iax_frame *frame, sched
time_in_ms_t iax_time_to_next_event(void) time_in_ms_t iax_time_to_next_event(void)
{ {
struct iax_sched *cur = schedq; struct iax_sched *cur = NULL;
time_in_ms_t minimum = 999999999; time_in_ms_t minimum = 999999999;
/* If there are no pending events, we don't need to timeout */ iax_mutex_lock(sched_mutex);
if (!cur) cur = schedq;
return -1;
/* If there are no pending events, we don't need to timeout */
if (!cur) {
iax_mutex_unlock(sched_mutex);
return -1;
}
while(cur) { while(cur) {
if (cur->when < minimum) { if (cur->when < minimum) {
minimum = cur->when; minimum = cur->when;
} }
cur = cur->next; cur = cur->next;
} }
iax_mutex_unlock(sched_mutex);
if (minimum <= 0) { if (minimum <= 0) {
return -1; return -1;
} }
return minimum - current_time_in_ms(); return minimum - current_time_in_ms();
} }
@ -497,7 +511,7 @@ struct iax_session *iax_session_new(void)
callnums = 1; callnums = 1;
s->peercallno = 0; s->peercallno = 0;
s->transferpeer = 0; /* for attended transfer */ s->transferpeer = 0; /* for attended transfer */
s->next = sessions;
s->sendto = iax_sendto; s->sendto = iax_sendto;
s->pingid = -1; s->pingid = -1;
#ifdef NEWJB #ifdef NEWJB
@ -510,7 +524,10 @@ struct iax_session *iax_session_new(void)
jb_setconf(s->jb, &jbconf); jb_setconf(s->jb, &jbconf);
} }
#endif #endif
iax_mutex_lock(session_mutex);
s->next = sessions;
sessions = s; sessions = s;
iax_mutex_unlock(session_mutex);
} }
return s; return s;
} }
@ -518,12 +535,19 @@ struct iax_session *iax_session_new(void)
static int iax_session_valid(struct iax_session *session) static int iax_session_valid(struct iax_session *session)
{ {
/* Return -1 on a valid iax session pointer, 0 on a failure */ /* Return -1 on a valid iax session pointer, 0 on a failure */
struct iax_session *cur = sessions; struct iax_session *cur;
iax_mutex_lock(session_mutex);
cur = sessions;
while(cur) { while(cur) {
if (session == cur) if (session == cur) {
iax_mutex_unlock(session_mutex);
return -1; return -1;
}
cur = cur->next; cur = cur->next;
} }
iax_mutex_unlock(session_mutex);
return 0; return 0;
} }
@ -865,26 +889,29 @@ void iax_set_networking(sendto_t st, recvfrom_t rf)
int __iax_shutdown(void) int __iax_shutdown(void)
{ {
struct iax_sched *sp, *fp;
/* Hangup Calls */ /* Hangup Calls */
if (sessions) { if (sessions) {
struct iax_session *sp = NULL, *fp = NULL; struct iax_session *sp = NULL, *fp = NULL;
iax_mutex_lock(session_mutex);
for(sp = sessions; sp ;) { for(sp = sessions; sp ;) {
iax_hangup(sp, "System Shutdown"); iax_hangup(sp, "System Shutdown");
fp = sp; fp = sp;
sp = sp->next; sp = sp->next;
destroy_session(fp); destroy_session(fp);
} }
iax_mutex_unlock(session_mutex);
} }
/* Clear Scheduler */ /* Clear Scheduler */
if(schedq) { iax_mutex_lock(sched_mutex);
struct iax_sched *sp, *fp; for(sp = schedq; sp ;) {
for(sp = schedq; sp ;) { fp = sp;
fp = sp; sp = sp->next;
sp = sp->next; free(fp);
free(fp);
}
} }
iax_mutex_unlock(sched_mutex);
if (netfd > -1) { if (netfd > -1) {
shutdown(netfd, 2); shutdown(netfd, 2);
@ -893,6 +920,9 @@ int __iax_shutdown(void)
time_end(); time_end();
iax_mutex_destroy(sched_mutex);
iax_mutex_destroy(session_mutex);
return 0; return 0;
} }
@ -910,6 +940,9 @@ int iax_init(char *ip, int preferredportno)
init_time(); init_time();
iax_mutex_create(&sched_mutex);
iax_mutex_create(&session_mutex);
if(iax_recvfrom == (recvfrom_t) recvfrom) { if(iax_recvfrom == (recvfrom_t) recvfrom) {
if (netfd > -1) { if (netfd > -1) {
/* Sokay, just don't do anything */ /* Sokay, just don't do anything */
@ -1229,12 +1262,14 @@ static void stop_transfer(struct iax_session *session)
{ {
struct iax_sched *sch; struct iax_sched *sch;
iax_mutex_lock(sched_mutex);
sch = schedq; sch = schedq;
while(sch) { while(sch) {
if (sch->frame && (sch->frame->session == session)) if (sch->frame && (sch->frame->session == session))
sch->frame->retries = -1; sch->frame->retries = -1;
sch = sch->next; sch = sch->next;
} }
iax_mutex_unlock(sched_mutex);
} /* stop_transfer */ } /* stop_transfer */
static void complete_transfer(struct iax_session *session, int peercallno, int xfr2peer, int preserveSeq) static void complete_transfer(struct iax_session *session, int peercallno, int xfr2peer, int preserveSeq)
@ -1356,14 +1391,18 @@ static int iax_finish_transfer(struct iax_session *s, short new_peer)
static struct iax_session *iax_find_session2(short callno) static struct iax_session *iax_find_session2(short callno)
{ {
struct iax_session *cur = sessions; struct iax_session *cur;
iax_mutex_lock(session_mutex);
cur = sessions;
while(cur) { while(cur) {
if (callno == cur->callno && callno != 0) { if (callno == cur->callno && callno != 0) {
iax_mutex_unlock(session_mutex);
return cur; return cur;
} }
cur = cur->next; cur = cur->next;
} }
iax_mutex_unlock(session_mutex);
return NULL; return NULL;
} }
@ -1431,6 +1470,8 @@ static void destroy_session(struct iax_session *session)
struct iax_session *cur, *prev=NULL; struct iax_session *cur, *prev=NULL;
struct iax_sched *curs, *prevs=NULL, *nexts=NULL; struct iax_sched *curs, *prevs=NULL, *nexts=NULL;
int loop_cnt=0; int loop_cnt=0;
iax_mutex_lock(sched_mutex);
curs = schedq; curs = schedq;
while(curs) { while(curs) {
nexts = curs->next; nexts = curs->next;
@ -1451,7 +1492,9 @@ static void destroy_session(struct iax_session *session)
curs = nexts; curs = nexts;
loop_cnt++; loop_cnt++;
} }
iax_mutex_unlock(sched_mutex);
cur = sessions; cur = sessions;
while(cur) { while(cur) {
if (cur == session) { if (cur == session) {
@ -2081,9 +2124,13 @@ static struct iax_session *iax_find_session(struct sockaddr_in *sin,
short dcallno, short dcallno,
int makenew) int makenew)
{ {
struct iax_session *cur = sessions; struct iax_session *cur;
iax_mutex_lock(session_mutex);
cur = sessions;
while(cur) { while(cur) {
if (forward_match(sin, callno, dcallno, cur)) { if (forward_match(sin, callno, dcallno, cur)) {
iax_mutex_unlock(session_mutex);
return cur; return cur;
} }
cur = cur->next; cur = cur->next;
@ -2092,11 +2139,14 @@ static struct iax_session *iax_find_session(struct sockaddr_in *sin,
cur = sessions; cur = sessions;
while(cur) { while(cur) {
if (reverse_match(sin, callno, cur)) { if (reverse_match(sin, callno, cur)) {
iax_mutex_unlock(session_mutex);
return cur; return cur;
} }
cur = cur->next; cur = cur->next;
} }
iax_mutex_unlock(session_mutex);
if (makenew && !dcallno) { if (makenew && !dcallno) {
cur = iax_session_new(); cur = iax_session_new();
cur->peercallno = callno; cur->peercallno = callno;
@ -2108,6 +2158,7 @@ static struct iax_session *iax_find_session(struct sockaddr_in *sin,
} else { } else {
DEBU(G "No session, peer = %d, us = %d\n", callno, dcallno); DEBU(G "No session, peer = %d, us = %d\n", callno, dcallno);
} }
return cur; return cur;
} }
@ -2428,6 +2479,7 @@ static struct iax_event *iax_header_to_event(struct iax_session *session,
for (x=session->rseqno; x != fh->iseqno; x++) { for (x=session->rseqno; x != fh->iseqno; x++) {
/* Ack the packet with the given timestamp */ /* Ack the packet with the given timestamp */
DEBU(G "Cancelling transmission of packet %d\n", x); DEBU(G "Cancelling transmission of packet %d\n", x);
iax_mutex_lock(sched_mutex);
sch = schedq; sch = schedq;
while(sch) { while(sch) {
if (sch->frame && (sch->frame->session == session) && if (sch->frame && (sch->frame->session == session) &&
@ -2435,6 +2487,7 @@ static struct iax_event *iax_header_to_event(struct iax_session *session,
sch->frame->retries = -1; sch->frame->retries = -1;
sch = sch->next; sch = sch->next;
} }
iax_mutex_unlock(sched_mutex);
} }
/* Note how much we've received acknowledgement for */ /* Note how much we've received acknowledgement for */
session->rseqno = fh->iseqno; session->rseqno = fh->iseqno;
@ -2846,15 +2899,17 @@ static struct iax_event *iax_miniheader_to_event(struct iax_session *session,
void iax_destroy(struct iax_session *session) void iax_destroy(struct iax_session *session)
{ {
iax_mutex_lock(session_mutex);
destroy_session(session); destroy_session(session);
iax_mutex_unlock(session_mutex);
} }
static struct iax_event *iax_net_read(void) static struct iax_event *iax_net_read(void)
{ {
unsigned char buf[65536]; unsigned char buf[65536];
int res; int res, sinlen;
struct sockaddr_in sin; struct sockaddr_in sin;
unsigned int sinlen;
sinlen = sizeof(sin); sinlen = sizeof(sin);
res = iax_recvfrom(netfd, buf, sizeof(buf), 0, (struct sockaddr *) &sin, &sinlen); res = iax_recvfrom(netfd, buf, sizeof(buf), 0, (struct sockaddr *) &sin, &sinlen);
@ -2894,6 +2949,7 @@ static struct iax_session *iax_txcnt_session(struct ast_iax2_full_hdr *fh, int d
if (!ies.transferid) { if (!ies.transferid) {
return NULL; /* TXCNT without proper IAX_IE_TRANSFERID */ return NULL; /* TXCNT without proper IAX_IE_TRANSFERID */
} }
iax_mutex_lock(session_mutex);
for( cur=sessions; cur; cur=cur->next ) { for( cur=sessions; cur; cur=cur->next ) {
if ((cur->transferring) && (cur->transferid == ies.transferid) && if ((cur->transferring) && (cur->transferid == ies.transferid) &&
(cur->callno == dcallno) && (cur->transfercallno == callno)) { (cur->callno == dcallno) && (cur->transfercallno == callno)) {
@ -2906,6 +2962,7 @@ static struct iax_session *iax_txcnt_session(struct ast_iax2_full_hdr *fh, int d
break; break;
} }
} }
iax_mutex_unlock(session_mutex);
return cur; return cur;
} }
@ -2958,6 +3015,7 @@ struct iax_event *iax_net_process(unsigned char *buf, int len, struct sockaddr_i
static struct iax_sched *iax_get_sched(time_in_ms_t time_in_ms) static struct iax_sched *iax_get_sched(time_in_ms_t time_in_ms)
{ {
struct iax_sched *cur, *prev=NULL; struct iax_sched *cur, *prev=NULL;
iax_mutex_lock(sched_mutex);
cur = schedq; cur = schedq;
/* Check the event schedule first. */ /* Check the event schedule first. */
while(cur) { while(cur) {
@ -2968,10 +3026,12 @@ static struct iax_sched *iax_get_sched(time_in_ms_t time_in_ms)
} else { } else {
schedq = cur->next; schedq = cur->next;
} }
iax_mutex_unlock(sched_mutex);
return cur; return cur;
} }
cur = cur->next; cur = cur->next;
} }
iax_mutex_unlock(sched_mutex);
return NULL; return NULL;
} }
@ -3005,8 +3065,11 @@ struct iax_event *iax_get_event(int blocking)
if (frame->retries < 0) { if (frame->retries < 0) {
/* It's been acked. No need to send it. Destroy the old /* It's been acked. No need to send it. Destroy the old
frame. If final, destroy the session. */ frame. If final, destroy the session. */
if (frame->final) if (frame->final) {
iax_mutex_lock(session_mutex);
destroy_session(frame->session); destroy_session(frame->session);
iax_mutex_unlock(session_mutex);
}
if (frame->data) if (frame->data)
free(frame->data); free(frame->data);
free(frame); free(frame);
@ -3023,7 +3086,9 @@ struct iax_event *iax_get_event(int blocking)
/* We haven't been able to get an ACK on this packet. If a /* We haven't been able to get an ACK on this packet. If a
final frame, destroy the session, otherwise, pass up timeout */ final frame, destroy the session, otherwise, pass up timeout */
if (frame->final) { if (frame->final) {
iax_mutex_lock(session_mutex);
destroy_session(frame->session); destroy_session(frame->session);
iax_mutex_unlock(session_mutex);
if (frame->data) if (frame->data)
free(frame->data); free(frame->data);
free(frame); free(frame);
@ -3070,54 +3135,59 @@ struct iax_event *iax_get_event(int blocking)
{ {
struct iax_session *cur; struct iax_session *cur;
jb_frame frame; jb_frame frame;
iax_mutex_lock(session_mutex);
for(cur=sessions; cur; cur=cur->next) { for(cur=sessions; cur; cur=cur->next) {
int ret; int ret;
time_in_ms_t now; time_in_ms_t now;
time_in_ms_t next; time_in_ms_t next;
now = time_in_ms - cur->rxcore; now = time_in_ms - cur->rxcore;
if(now > (next = jb_next(cur->jb))) { if(now > (next = jb_next(cur->jb))) {
/* FIXME don't hardcode interpolation frame length in jb_get */ /* FIXME don't hardcode interpolation frame length in jb_get */
ret = jb_get(cur->jb,&frame,now,20); ret = jb_get(cur->jb,&frame,now,20);
switch(ret) { switch(ret) {
case JB_OK: case JB_OK:
// if(frame.type == JB_TYPE_VOICE && next + 20 != jb_next(cur->jb)) fprintf(stderr, "NEXT %ld is not %ld+20!\n", jb_next(cur->jb), next); // if(frame.type == JB_TYPE_VOICE && next + 20 != jb_next(cur->jb)) fprintf(stderr, "NEXT %ld is not %ld+20!\n", jb_next(cur->jb), next);
event = frame.data; event = frame.data;
event = handle_event(event); event = handle_event(event);
if (event) { if (event) {
return event; iax_mutex_unlock(session_mutex);
} return event;
break; }
case JB_INTERP: break;
// if(next + 20 != jb_next(cur->jb)) fprintf(stderr, "NEXT %ld is not %ld+20!\n", jb_next(cur->jb), next); case JB_INTERP:
/* create an interpolation frame */ // if(next + 20 != jb_next(cur->jb)) fprintf(stderr, "NEXT %ld is not %ld+20!\n", jb_next(cur->jb), next);
//fprintf(stderr, "Making Interpolation frame\n"); /* create an interpolation frame */
event = (struct iax_event *)malloc(sizeof(struct iax_event)); //fprintf(stderr, "Making Interpolation frame\n");
if (event) { event = (struct iax_event *)malloc(sizeof(struct iax_event));
event->etype = IAX_EVENT_VOICE; if (event) {
event->subclass = cur->voiceformat; event->etype = IAX_EVENT_VOICE;
event->ts = now; /* XXX: ??? applications probably ignore this anyway */ event->subclass = cur->voiceformat;
event->session = cur; event->ts = now; /* XXX: ??? applications probably ignore this anyway */
event->datalen = 0; event->session = cur;
event = handle_event(event); event->datalen = 0;
if(event) event = handle_event(event);
return event; if(event) {
} iax_mutex_unlock(session_mutex);
break; return event;
case JB_DROP: }
// if(next != jb_next(cur->jb)) fprintf(stderr, "NEXT %ld is not next %ld!\n", jb_next(cur->jb), next); }
iax_event_free(frame.data); break;
break; case JB_DROP:
case JB_NOFRAME: // if(next != jb_next(cur->jb)) fprintf(stderr, "NEXT %ld is not next %ld!\n", jb_next(cur->jb), next);
case JB_EMPTY: iax_event_free(frame.data);
/* do nothing */ break;
break; case JB_NOFRAME:
default: case JB_EMPTY:
/* shouldn't happen */ /* do nothing */
break; break;
} default:
} /* shouldn't happen */
break;
}
}
} }
iax_mutex_unlock(session_mutex);
} }
#endif #endif
@ -3169,8 +3239,10 @@ char *iax_event_get_apparent_ip(struct iax_event *event)
void iax_session_destroy(struct iax_session **session) void iax_session_destroy(struct iax_session **session)
{ {
iax_mutex_lock(session_mutex);
destroy_session(*session); destroy_session(*session);
*session = NULL; *session = NULL;
iax_mutex_unlock(session_mutex);
} }
void iax_event_free(struct iax_event *event) void iax_event_free(struct iax_event *event)
@ -3185,7 +3257,9 @@ void iax_event_free(struct iax_event *event)
case IAX_EVENT_HANGUP: case IAX_EVENT_HANGUP:
/* Destroy this session -- it's no longer valid */ /* Destroy this session -- it's no longer valid */
if (event->session) { /* maybe the user did it already */ if (event->session) { /* maybe the user did it already */
iax_mutex_lock(session_mutex);
destroy_session(event->session); destroy_session(event->session);
iax_mutex_unlock(session_mutex);
} }
break; break;
} }