Skip to content
Snippets Groups Projects
iax2-parser.c 37.1 KiB
Newer Older
  • Learn to ignore specific revisions
  • 		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);
    
    						outputf(tmp);
    
    			if (!var2) {
    
    				snprintf(tmp, sizeof(tmp), "Assigned (%p)%s to (%p)%s\n", var->name, var->name, var->value, var->value);
    
    				outputf(tmp);
    
    				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;
    }
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    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);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	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;
    
    	fr->af.delivery.tv_sec = 0;
    	fr->af.delivery.tv_usec = 0;
    
    	fr->af.len = f->len;
    
    		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;
    		}
    
    #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 */
    
    			ast_swapcopy_samples(fr->af.data.ptr, f->data.ptr, copy_len / 2);
    
    			memcpy(fr->af.data.ptr, f->data.ptr, copy_len);
    
    struct iax_frame *iax_frame_new(int direction, int datalen, unsigned int cacheable)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    
    
    #if !defined(LOW_MEMORY)
    
    	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))) {
    
    			fr->afdatalen = datalen;
    		}
    		fr->cacheable = 1;
    	} else
    #endif
    	{
    		if (!(fr = ast_calloc(1, sizeof(*fr) + datalen))) {
    
    			return NULL;
    
    		fr->afdatalen = datalen;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	}
    
    
    	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);
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return fr;
    }
    
    
    void iax_frame_free(struct iax_frame *fr)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    
    #if !defined(LOW_MEMORY)
    
    	struct iax_frames *iax_frames = NULL;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	/* Note: does not remove from scheduler! */
    	if (fr->direction == DIRECTION_INGRESS)
    
    		ast_atomic_fetchadd_int(&iframes, -1);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	else if (fr->direction == DIRECTION_OUTGRESS)
    
    		ast_atomic_fetchadd_int(&oframes, -1);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	else {
    		errorf("Attempt to double free frame detected\n");
    		return;
    	}
    
    	ast_atomic_fetchadd_int(&frames, -1);
    
    #if !defined(LOW_MEMORY)
    
    	if (!fr->cacheable || !(iax_frames = ast_threadstorage_get(&frame_cache, sizeof(*iax_frames)))) {
    
    	if (iax_frames->size < FRAME_CACHE_MAX_SIZE) {
    		fr->direction = 0;
    
    		/* 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;
    	}
    
    #if !defined(LOW_MEMORY)
    
    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);
    
    Mark Spencer's avatar
    Mark Spencer committed
    int iax_get_frames(void) { return frames; }
    int iax_get_iframes(void) { return iframes; }
    int iax_get_oframes(void) { return oframes; }