mirror of
https://github.com/asterisk/asterisk.git
synced 2025-10-22 20:56:39 +00:00
chan_iax2 has an extremely large function, socket_process(), to handle incoming
frames. The function, before this commit, was roughly 1400 lines long. So, I am working on breaking this up into functions so that the code is easier to follow and debug. Also, I will be committing these changes in chunks as I do them to ease tracking down any potentially introduced problems. Break out roughly 150 lines from socket_process() and introduce a new function, socket_process_meta() which handles the parsing of an incoming meta frame. Also, restructure some of this code a bit to reduce the deep nesting that was in this code. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@48360 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
@@ -1087,10 +1087,6 @@ static struct chan_iax2_pvt *new_iax(struct sockaddr_in *sin, int lockpeer, cons
|
||||
}
|
||||
|
||||
tmp->prefs = prefs;
|
||||
tmp->callno = 0;
|
||||
tmp->peercallno = 0;
|
||||
tmp->transfercallno = 0;
|
||||
tmp->bridgecallno = 0;
|
||||
tmp->pingid = -1;
|
||||
tmp->lagid = -1;
|
||||
tmp->autoid = -1;
|
||||
@@ -6280,36 +6276,156 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int socket_process_meta(int packet_len, struct ast_iax2_meta_hdr *meta, struct sockaddr_in *sin, int sockfd,
|
||||
struct iax_frame *fr)
|
||||
{
|
||||
unsigned char metatype;
|
||||
struct ast_iax2_meta_trunk_mini *mtm;
|
||||
struct ast_iax2_meta_trunk_hdr *mth;
|
||||
struct ast_iax2_meta_trunk_entry *mte;
|
||||
struct iax2_trunk_peer *tpeer;
|
||||
unsigned int ts;
|
||||
void *ptr;
|
||||
struct timeval rxtrunktime;
|
||||
struct ast_frame f = { 0, };
|
||||
|
||||
if (packet_len < sizeof(*meta)) {
|
||||
ast_log(LOG_WARNING, "Rejecting packet from '%s.%d' that is flagged as a meta frame but is too short\n",
|
||||
ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (meta->metacmd != IAX_META_TRUNK)
|
||||
return 1;
|
||||
|
||||
if (packet_len < (sizeof(*meta) + sizeof(*mth))) {
|
||||
ast_log(LOG_WARNING, "midget meta trunk packet received (%d of %zd min)\n", packet_len,
|
||||
sizeof(*meta) + sizeof(*mth));
|
||||
return 1;
|
||||
}
|
||||
mth = (struct ast_iax2_meta_trunk_hdr *)(meta->data);
|
||||
ts = ntohl(mth->ts);
|
||||
metatype = meta->cmddata;
|
||||
packet_len -= (sizeof(*meta) + sizeof(*mth));
|
||||
ptr = mth->data;
|
||||
tpeer = find_tpeer(sin, sockfd);
|
||||
if (!tpeer) {
|
||||
ast_log(LOG_WARNING, "Unable to accept trunked packet from '%s:%d': No matching peer\n",
|
||||
ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
|
||||
return 1;
|
||||
}
|
||||
tpeer->trunkact = ast_tvnow();
|
||||
if (!ts || ast_tvzero(tpeer->rxtrunktime))
|
||||
tpeer->rxtrunktime = tpeer->trunkact;
|
||||
rxtrunktime = tpeer->rxtrunktime;
|
||||
ast_mutex_unlock(&tpeer->lock);
|
||||
while (packet_len >= sizeof(*mte)) {
|
||||
/* Process channels */
|
||||
unsigned short callno, trunked_ts, len;
|
||||
|
||||
if (metatype == IAX_META_TRUNK_MINI) {
|
||||
mtm = (struct ast_iax2_meta_trunk_mini *) ptr;
|
||||
ptr += sizeof(*mtm);
|
||||
packet_len -= sizeof(*mtm);
|
||||
len = ntohs(mtm->len);
|
||||
callno = ntohs(mtm->mini.callno);
|
||||
trunked_ts = ntohs(mtm->mini.ts);
|
||||
} else if (metatype == IAX_META_TRUNK_SUPERMINI) {
|
||||
mte = (struct ast_iax2_meta_trunk_entry *)ptr;
|
||||
ptr += sizeof(*mte);
|
||||
packet_len -= sizeof(*mte);
|
||||
len = ntohs(mte->len);
|
||||
callno = ntohs(mte->callno);
|
||||
trunked_ts = 0;
|
||||
} else {
|
||||
ast_log(LOG_WARNING, "Unknown meta trunk cmd from '%s:%d': dropping\n", ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
|
||||
break;
|
||||
}
|
||||
/* Stop if we don't have enough data */
|
||||
if (len > packet_len)
|
||||
break;
|
||||
fr->callno = find_callno(callno & ~IAX_FLAG_FULL, 0, sin, NEW_PREVENT, 1, sockfd);
|
||||
if (!fr->callno)
|
||||
continue;
|
||||
|
||||
ast_mutex_lock(&iaxsl[fr->callno]);
|
||||
|
||||
/* If it's a valid call, deliver the contents. If not, we
|
||||
drop it, since we don't have a scallno to use for an INVAL */
|
||||
/* Process as a mini frame */
|
||||
f.frametype = AST_FRAME_VOICE;
|
||||
if (!iaxs[fr->callno]) {
|
||||
/* drop it */
|
||||
} else if (iaxs[fr->callno]->voiceformat == 0) {
|
||||
ast_log(LOG_WARNING, "Received trunked frame before first full voice frame\n ");
|
||||
iax2_vnak(fr->callno);
|
||||
} else {
|
||||
f.subclass = iaxs[fr->callno]->voiceformat;
|
||||
f.datalen = len;
|
||||
if (f.datalen >= 0) {
|
||||
if (f.datalen)
|
||||
f.data = ptr;
|
||||
else
|
||||
f.data = NULL;
|
||||
if (trunked_ts)
|
||||
fr->ts = (iaxs[fr->callno]->last & 0xFFFF0000L) | (trunked_ts & 0xffff);
|
||||
else
|
||||
fr->ts = fix_peerts(&rxtrunktime, fr->callno, ts);
|
||||
/* Don't pass any packets until we're started */
|
||||
if (ast_test_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED)) {
|
||||
struct iax_frame *duped_fr;
|
||||
|
||||
/* Common things */
|
||||
f.src = "IAX2";
|
||||
f.mallocd = 0;
|
||||
f.offset = 0;
|
||||
if (f.datalen && (f.frametype == AST_FRAME_VOICE))
|
||||
f.samples = ast_codec_get_samples(&f);
|
||||
else
|
||||
f.samples = 0;
|
||||
fr->outoforder = 0;
|
||||
iax_frame_wrap(fr, &f);
|
||||
duped_fr = iaxfrdup2(fr);
|
||||
if (duped_fr)
|
||||
schedule_delivery(duped_fr, 1, 1, &fr->ts);
|
||||
if (iaxs[fr->callno]->last < fr->ts)
|
||||
iaxs[fr->callno]->last = fr->ts;
|
||||
}
|
||||
} else {
|
||||
ast_log(LOG_WARNING, "Datalen < 0?\n");
|
||||
}
|
||||
}
|
||||
ast_mutex_unlock(&iaxsl[fr->callno]);
|
||||
ptr += len;
|
||||
packet_len -= len;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int socket_process(struct iax2_thread *thread)
|
||||
{
|
||||
struct sockaddr_in sin;
|
||||
int res;
|
||||
int updatehistory=1;
|
||||
int new = NEW_PREVENT;
|
||||
void *ptr;
|
||||
int dcallno = 0;
|
||||
struct ast_iax2_full_hdr *fh = (struct ast_iax2_full_hdr *)thread->buf;
|
||||
struct ast_iax2_mini_hdr *mh = (struct ast_iax2_mini_hdr *)thread->buf;
|
||||
struct ast_iax2_meta_hdr *meta = (struct ast_iax2_meta_hdr *)thread->buf;
|
||||
struct ast_iax2_video_hdr *vh = (struct ast_iax2_video_hdr *)thread->buf;
|
||||
struct ast_iax2_meta_trunk_hdr *mth;
|
||||
struct ast_iax2_meta_trunk_entry *mte;
|
||||
struct ast_iax2_meta_trunk_mini *mtm;
|
||||
struct iax_frame *fr;
|
||||
struct iax_frame *cur;
|
||||
struct ast_frame f;
|
||||
struct ast_channel *c;
|
||||
struct iax2_dpcache *dp;
|
||||
struct iax2_peer *peer;
|
||||
struct iax2_trunk_peer *tpeer;
|
||||
struct timeval rxtrunktime;
|
||||
struct iax_ies ies;
|
||||
struct iax_ie_data ied0, ied1;
|
||||
int format;
|
||||
int fd;
|
||||
int exists;
|
||||
int minivid = 0;
|
||||
unsigned int ts;
|
||||
char empty[32]=""; /* Safety measure */
|
||||
struct iax_frame *duped_fr;
|
||||
char host_pref_buf[128];
|
||||
@@ -6339,123 +6455,8 @@ static int socket_process(struct iax2_thread *thread)
|
||||
/* This is a video frame, get call number */
|
||||
fr->callno = find_callno(ntohs(vh->callno) & ~0x8000, dcallno, &sin, new, 1, fd);
|
||||
minivid = 1;
|
||||
} else if ((meta->zeros == 0) && !(ntohs(meta->metacmd) & 0x8000)) {
|
||||
unsigned char metatype;
|
||||
|
||||
if (res < sizeof(*meta)) {
|
||||
ast_log(LOG_WARNING, "Rejecting packet from '%s.%d' that is flagged as a meta frame but is too short\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* This is a meta header */
|
||||
switch(meta->metacmd) {
|
||||
case IAX_META_TRUNK:
|
||||
if (res < (sizeof(*meta) + sizeof(*mth))) {
|
||||
ast_log(LOG_WARNING, "midget meta trunk packet received (%d of %zd min)\n", res,
|
||||
sizeof(*meta) + sizeof(*mth));
|
||||
return 1;
|
||||
}
|
||||
mth = (struct ast_iax2_meta_trunk_hdr *)(meta->data);
|
||||
ts = ntohl(mth->ts);
|
||||
metatype = meta->cmddata;
|
||||
res -= (sizeof(*meta) + sizeof(*mth));
|
||||
ptr = mth->data;
|
||||
tpeer = find_tpeer(&sin, fd);
|
||||
if (!tpeer) {
|
||||
ast_log(LOG_WARNING, "Unable to accept trunked packet from '%s:%d': No matching peer\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
|
||||
return 1;
|
||||
}
|
||||
tpeer->trunkact = ast_tvnow();
|
||||
if (!ts || ast_tvzero(tpeer->rxtrunktime))
|
||||
tpeer->rxtrunktime = tpeer->trunkact;
|
||||
rxtrunktime = tpeer->rxtrunktime;
|
||||
ast_mutex_unlock(&tpeer->lock);
|
||||
while(res >= sizeof(*mte)) {
|
||||
/* Process channels */
|
||||
unsigned short callno, trunked_ts, len;
|
||||
|
||||
if (metatype == IAX_META_TRUNK_MINI) {
|
||||
mtm = (struct ast_iax2_meta_trunk_mini *)ptr;
|
||||
ptr += sizeof(*mtm);
|
||||
res -= sizeof(*mtm);
|
||||
len = ntohs(mtm->len);
|
||||
callno = ntohs(mtm->mini.callno);
|
||||
trunked_ts = ntohs(mtm->mini.ts);
|
||||
} else if (metatype == IAX_META_TRUNK_SUPERMINI) {
|
||||
mte = (struct ast_iax2_meta_trunk_entry *)ptr;
|
||||
ptr += sizeof(*mte);
|
||||
res -= sizeof(*mte);
|
||||
len = ntohs(mte->len);
|
||||
callno = ntohs(mte->callno);
|
||||
trunked_ts = 0;
|
||||
} else {
|
||||
ast_log(LOG_WARNING, "Unknown meta trunk cmd from '%s:%d': dropping\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
|
||||
break;
|
||||
}
|
||||
/* Stop if we don't have enough data */
|
||||
if (len > res)
|
||||
break;
|
||||
fr->callno = find_callno(callno & ~IAX_FLAG_FULL, 0, &sin, NEW_PREVENT, 1, fd);
|
||||
if (fr->callno) {
|
||||
ast_mutex_lock(&iaxsl[fr->callno]);
|
||||
/* If it's a valid call, deliver the contents. If not, we
|
||||
drop it, since we don't have a scallno to use for an INVAL */
|
||||
/* Process as a mini frame */
|
||||
f.frametype = AST_FRAME_VOICE;
|
||||
if (iaxs[fr->callno]) {
|
||||
if (iaxs[fr->callno]->voiceformat > 0) {
|
||||
f.subclass = iaxs[fr->callno]->voiceformat;
|
||||
f.datalen = len;
|
||||
if (f.datalen >= 0) {
|
||||
if (f.datalen)
|
||||
f.data = ptr;
|
||||
else
|
||||
f.data = NULL;
|
||||
if(trunked_ts) {
|
||||
fr->ts = (iaxs[fr->callno]->last & 0xFFFF0000L) | (trunked_ts & 0xffff);
|
||||
} else
|
||||
fr->ts = fix_peerts(&rxtrunktime, fr->callno, ts);
|
||||
/* Don't pass any packets until we're started */
|
||||
if (ast_test_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED)) {
|
||||
/* Common things */
|
||||
f.src = "IAX2";
|
||||
f.mallocd = 0;
|
||||
f.offset = 0;
|
||||
if (f.datalen && (f.frametype == AST_FRAME_VOICE))
|
||||
f.samples = ast_codec_get_samples(&f);
|
||||
else
|
||||
f.samples = 0;
|
||||
fr->outoforder = 0;
|
||||
iax_frame_wrap(fr, &f);
|
||||
duped_fr = iaxfrdup2(fr);
|
||||
if (duped_fr) {
|
||||
schedule_delivery(duped_fr, updatehistory, 1, &fr->ts);
|
||||
}
|
||||
if (iaxs[fr->callno]->last < fr->ts) {
|
||||
iaxs[fr->callno]->last = fr->ts;
|
||||
#if 1
|
||||
if (option_debug && iaxdebug)
|
||||
ast_log(LOG_DEBUG, "For call=%d, set last=%d\n", fr->callno, fr->ts);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ast_log(LOG_WARNING, "Datalen < 0?\n");
|
||||
}
|
||||
} else {
|
||||
ast_log(LOG_WARNING, "Received trunked frame before first full voice frame\n ");
|
||||
iax2_vnak(fr->callno);
|
||||
}
|
||||
}
|
||||
ast_mutex_unlock(&iaxsl[fr->callno]);
|
||||
}
|
||||
ptr += len;
|
||||
res -= len;
|
||||
}
|
||||
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
} else if ((meta->zeros == 0) && !(ntohs(meta->metacmd) & 0x8000))
|
||||
return socket_process_meta(res, meta, &sin, fd, fr);
|
||||
|
||||
#ifdef DEBUG_SUPPORT
|
||||
if (iaxdebug && (res >= sizeof(*fh)))
|
||||
|
||||
Reference in New Issue
Block a user