Newer
Older
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
case IAX_IE_CALLINGPRES:
if (len == 1)
ies->calling_pres = data[2];
else {
snprintf(tmp, (int)sizeof(tmp), "Expected single byte callingpres, but was %d long\n", len);
errorf(tmp);
}
break;
case IAX_IE_CALLINGTON:
if (len == 1)
ies->calling_ton = data[2];
else {
snprintf(tmp, (int)sizeof(tmp), "Expected single byte callington, but was %d long\n", len);
errorf(tmp);
}
break;
case IAX_IE_CALLINGTNS:
if (len != (int)sizeof(unsigned short)) {
snprintf(tmp, (int)sizeof(tmp), "Expecting callingtns to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
errorf(tmp);
} else
ies->calling_tns = ntohs(get_unaligned_uint16(data + 2));
case IAX_IE_RR_JITTER:
if (len != (int)sizeof(unsigned int)) {
snprintf(tmp, (int)sizeof(tmp), "Expected jitter rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
errorf(tmp);
} else {
ies->rr_jitter = ntohl(get_unaligned_uint32(data + 2));
}
break;
case IAX_IE_RR_LOSS:
if (len != (int)sizeof(unsigned int)) {
snprintf(tmp, (int)sizeof(tmp), "Expected loss rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
errorf(tmp);
} else {
ies->rr_loss = ntohl(get_unaligned_uint32(data + 2));
}
break;
case IAX_IE_RR_PKTS:
if (len != (int)sizeof(unsigned int)) {
snprintf(tmp, (int)sizeof(tmp), "Expected packets rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
errorf(tmp);
} else {
ies->rr_pkts = ntohl(get_unaligned_uint32(data + 2));
}
break;
case IAX_IE_RR_DELAY:
if (len != (int)sizeof(unsigned short)) {
snprintf(tmp, (int)sizeof(tmp), "Expected loss rr to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
errorf(tmp);
} else {
ies->rr_delay = ntohs(get_unaligned_uint16(data + 2));
}
break;
case IAX_IE_RR_DROPPED:
if (len != (int)sizeof(unsigned int)) {
snprintf(tmp, (int)sizeof(tmp), "Expected packets rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
errorf(tmp);
} else {
ies->rr_dropped = ntohl(get_unaligned_uint32(data + 2));
}
break;
case IAX_IE_RR_OOO:
if (len != (int)sizeof(unsigned int)) {
snprintf(tmp, (int)sizeof(tmp), "Expected packets rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
errorf(tmp);
} else {
ies->rr_ooo = ntohl(get_unaligned_uint32(data + 2));
case IAX_IE_VARIABLE:
ast_copy_string(tmp, (char *)data + 2, len + 1);
tmp2 = strchr(tmp, '=');
if (tmp2)
*tmp2++ = '\0';
else
tmp2 = "";
{
struct ast_str *str = ast_str_create(16);
/* Existing variable or new variable? */
for (var2 = ies->vars, prev = NULL; var2; prev = var2, var2 = var2->next) {
if (strcmp(tmp, var2->name) == 0) {
ast_str_set(&str, 0, "%s%s", var2->value, tmp2);
var = ast_variable_new(tmp, ast_str_buffer(str), var2->file);
var->next = var2->next;
if (prev) {
prev->next = var;
} else {
ies->vars = var;
}
snprintf(tmp, sizeof(tmp), "Assigned (%p)%s to (%p)%s\n", var->name, var->name, var->value, var->value);
ast_free(var2);
break;
}
ast_free(str);
Steve Murphy
committed
var = ast_variable_new(tmp, tmp2, "");
snprintf(tmp, sizeof(tmp), "Assigned (%p)%s to (%p)%s\n", var->name, var->name, var->value, var->value);
var->next = ies->vars;
ies->vars = var;
}
break;
case IAX_IE_OSPTOKEN:
if ((count = data[2]) < IAX_MAX_OSPBLOCK_NUM) {
ies->osptokenblock[count] = (char *)data + 2 + 1;
ies->ospblocklength[count] = len - 1;
} else {
snprintf(tmp, (int)sizeof(tmp), "Expected OSP token block index to be 0~%d but was %d\n", IAX_MAX_OSPBLOCK_NUM - 1, count);
errorf(tmp);
}
break;
case IAX_IE_CALLTOKEN:
if (len) {
ies->calltokendata = (unsigned char *) data + 2;
}
ies->calltoken = 1;
break;
snprintf(tmp, (int)sizeof(tmp), "Ignoring unknown information element '%s' (%d) of length %d\n", iax_ie2str(ie), ie, len);
}
/* Overwrite information element with 0, to null terminate previous portion */
data[0] = 0;
datalen -= (len + 2);
data += (len + 2);
}
/* Null-terminate last field */
*data = '\0';
if (datalen) {
errorf("Invalid information element contents, strange boundary\n");
return -1;
}
return 0;
}
void iax_frame_wrap(struct iax_frame *fr, struct ast_frame *f)
{
fr->af.frametype = f->frametype;
ast_format_copy(&fr->af.subclass.format, &f->subclass.format);
fr->af.mallocd = 0; /* Our frame is static relative to the container */
fr->af.datalen = f->datalen;
fr->af.samples = f->samples;
fr->af.offset = AST_FRIENDLY_OFFSET;
fr->af.src = f->src;
Mark Spencer
committed
fr->af.delivery.tv_sec = 0;
fr->af.delivery.tv_usec = 0;
Michiel van Baak
committed
fr->af.data.ptr = fr->afdata;
Kevin P. Fleming
committed
if (fr->af.datalen) {
size_t copy_len = fr->af.datalen;
if (copy_len > fr->afdatalen) {
ast_log(LOG_ERROR, "Losing frame data because destination buffer size '%d' bytes not big enough for '%d' bytes in the frame\n",
(int) fr->afdatalen, (int) fr->af.datalen);
copy_len = fr->afdatalen;
}
Kevin P. Fleming
committed
#if __BYTE_ORDER == __LITTLE_ENDIAN
/* We need to byte-swap slinear samples from network byte order */
if ((fr->af.frametype == AST_FRAME_VOICE) && (fr->af.subclass.format.id == AST_FORMAT_SLINEAR)) {
/* 2 bytes / sample for SLINEAR */
Michiel van Baak
committed
ast_swapcopy_samples(fr->af.data.ptr, f->data.ptr, copy_len / 2);
Kevin P. Fleming
committed
} else
#endif
Michiel van Baak
committed
memcpy(fr->af.data.ptr, f->data.ptr, copy_len);
Kevin P. Fleming
committed
}
struct iax_frame *iax_frame_new(int direction, int datalen, unsigned int cacheable)
struct iax_frame *fr;
if (cacheable) {
struct iax_frames *iax_frames;
struct iax_frame *smallest;
/* Attempt to get a frame from this thread's cache */
if ((iax_frames = ast_threadstorage_get(&frame_cache, sizeof(*iax_frames)))) {
smallest = AST_LIST_FIRST(&iax_frames->list);
AST_LIST_TRAVERSE_SAFE_BEGIN(&iax_frames->list, fr, list) {
if (fr->afdatalen >= datalen) {
size_t afdatalen = fr->afdatalen;
AST_LIST_REMOVE_CURRENT(list);
iax_frames->size--;
memset(fr, 0, sizeof(*fr));
fr->afdatalen = afdatalen;
break;
} else if (smallest->afdatalen > fr->afdatalen) {
smallest = fr;
}
AST_LIST_TRAVERSE_SAFE_END;
if (!fr) {
if (iax_frames->size >= FRAME_CACHE_MAX_SIZE && smallest) {
/* Make useless cache into something more useful */
AST_LIST_REMOVE(&iax_frames->list, smallest, list);
iax_frames->size--;
ast_free(smallest);
}
if (!(fr = ast_calloc_cache(1, sizeof(*fr) + datalen))) {
return NULL;
}
fr->afdatalen = datalen;
}
} else {
if (!(fr = ast_calloc_cache(1, sizeof(*fr) + datalen))) {
Tilghman Lesher
committed
return NULL;
}
fr->afdatalen = datalen;
}
fr->cacheable = 1;
} else
#endif
{
if (!(fr = ast_calloc(1, sizeof(*fr) + datalen))) {
fr->direction = direction;
fr->retrans = -1;
if (fr->direction == DIRECTION_INGRESS)
ast_atomic_fetchadd_int(&iframes, 1);
else
ast_atomic_fetchadd_int(&oframes, 1);
ast_atomic_fetchadd_int(&frames, 1);
void iax_frame_free(struct iax_frame *fr)
struct iax_frames *iax_frames = NULL;
/* Note: does not remove from scheduler! */
if (fr->direction == DIRECTION_INGRESS)
ast_atomic_fetchadd_int(&iframes, -1);
ast_atomic_fetchadd_int(&oframes, -1);
else {
errorf("Attempt to double free frame detected\n");
return;
}
ast_atomic_fetchadd_int(&frames, -1);
if (!fr->cacheable || !(iax_frames = ast_threadstorage_get(&frame_cache, sizeof(*iax_frames)))) {
Tilghman Lesher
committed
ast_free(fr);
if (iax_frames->size < FRAME_CACHE_MAX_SIZE) {
fr->direction = 0;
Tilghman Lesher
committed
/* Pseudo-sort: keep smaller frames at the top of the list. This should
* increase the chance that we pick the smallest applicable frame for use. */
if (AST_LIST_FIRST(&iax_frames->list) && AST_LIST_FIRST(&iax_frames->list)->afdatalen < fr->afdatalen) {
AST_LIST_INSERT_TAIL(&iax_frames->list, fr, list);
} else {
AST_LIST_INSERT_HEAD(&iax_frames->list, fr, list);
}
iax_frames->size++;
return;
}
static void frame_cache_cleanup(void *data)
{
struct iax_frames *framelist = data;
struct iax_frame *current;
while ((current = AST_LIST_REMOVE_HEAD(&framelist->list, list)))
ast_free(current);
ast_free(framelist);
int iax_get_frames(void) { return frames; }
int iax_get_iframes(void) { return iframes; }
int iax_get_oframes(void) { return oframes; }