void belle_sip_multipart_body_handler_add_part(belle_sip_multipart_body_handler_t *obj, belle_sip_body_handler_t *part){ obj->base.expected_size+=part->expected_size+strlen(obj->boundary) + 4; /* add the separator length to the body length as each part start with a separator. 4 is for "--" and "\r\n" */ if (part->headers != NULL) { /* there is a declared header for this part, add its length to the expected total length */ size_t headerStringBufferSize = DEFAULT_HEADER_STRING_SIZE; size_t offset = 0; belle_sip_list_t *headerList = part->headers; part->headerStringBuffer = (char *)belle_sip_malloc(DEFAULT_HEADER_STRING_SIZE); while (headerList != NULL) { size_t offsetBackup=offset; /* we must backup the offset as it will be messed up by the marshal function in case of failure */ belle_sip_error_code returnCode = belle_sip_object_marshal(headerList->data, part->headerStringBuffer, headerStringBufferSize-5, &offset); /* -5 to leave room for carriage returns */ if (returnCode == BELLE_SIP_BUFFER_OVERFLOW) { /* increase buffer size */ offset=offsetBackup; /* restore the offset, no data were written to the buffer */ headerStringBufferSize+=DEFAULT_HEADER_STRING_SIZE; part->headerStringBuffer = (char *)belle_sip_realloc(part->headerStringBuffer, headerStringBufferSize); } else if (returnCode == BELLE_SIP_OK) { /* add the carriage return chars */ part->headerStringBuffer[offset++]='\r'; part->headerStringBuffer[offset++]='\n'; headerList = belle_sip_list_next(headerList); } } part->headerStringBuffer[offset++]='\r'; part->headerStringBuffer[offset++]='\n'; obj->base.expected_size += offset; part->headerStringBuffer[offset++]='\0'; /* null terminate the buffer in order to be able to get it length later using strlen */ } obj->parts=belle_sip_list_append(obj->parts,belle_sip_object_ref(part)); }
belle_sip_list_t* belle_sip_list_insert_sorted(belle_sip_list_t* list, void *data, int (*compare_func)(const void *, const void*)){ belle_sip_list_t* it,*previt=NULL; belle_sip_list_t* nelem; belle_sip_list_t* ret=list; if (list==NULL) return belle_sip_list_append(list,data); else{ nelem=belle_sip_list_new(data); for(it=list;it!=NULL;it=it->next){ previt=it; if (compare_func(data,it->data)<=0){ nelem->prev=it->prev; nelem->next=it; if (it->prev!=NULL) it->prev->next=nelem; else{ ret=nelem; } it->prev=nelem; return ret; } } previt->next=nelem; nelem->prev=previt; } return ret; }
static void encode_headers(belle_sip_param_pair_t* container, belle_sip_list_t** newlist) { char *escapedName = belle_sip_uri_to_escaped_header(container->name); char *escapedValue = container->value? belle_sip_uri_to_escaped_header(container->value) : NULL; *newlist = belle_sip_list_append(*newlist, belle_sip_param_pair_new(escapedName, escapedValue)); if (escapedName) free(escapedName); if (escapedValue) free(escapedValue); }
int belle_sip_object_data_set( belle_sip_object_t *obj, const char* name, void* data, belle_sip_data_destroy destroy_func ) { int ret = 0; struct _belle_sip_list* list_entry = belle_sip_list_find_custom(obj->data_store, belle_sip_object_data_find, name); struct belle_sip_object_data* entry = (list_entry)? list_entry->data : NULL; if( entry == NULL){ entry = belle_sip_malloc0(sizeof( struct belle_sip_object_data)); obj->data_store = belle_sip_list_append(obj->data_store, entry); } else { // clean previous data if( entry->destroy_func ) entry->destroy_func(entry->data); belle_sip_free(entry->name); ret = 1; } if( entry ){ entry->data = data; entry->name = belle_sip_strdup(name); entry->destroy_func = destroy_func; } else { ret = -1; } return ret; }
static void belle_sip_channel_message_ready(belle_sip_channel_t *obj){ belle_sip_message_t *msg=obj->input_stream.msg; belle_sip_body_handler_t *bh=belle_sip_message_get_body_handler(msg); if (bh) belle_sip_body_handler_end_transfer(bh); if (belle_sip_message_is_response(msg)) belle_sip_channel_learn_public_ip_port(obj,BELLE_SIP_RESPONSE(msg)); obj->incoming_messages=belle_sip_list_append(obj->incoming_messages,msg); belle_sip_channel_input_stream_reset(&obj->input_stream); }
belle_sip_list_t* belle_sip_list_copy(const belle_sip_list_t* list){ belle_sip_list_t* copy=NULL; const belle_sip_list_t* iter; for(iter=list;iter!=NULL;iter=belle_sip_list_next(iter)){ copy=belle_sip_list_append(copy,iter->data); } return copy; }
belle_sip_list_t* belle_sip_list_copy_with_data(const belle_sip_list_t* list, void* (*copyfunc)(void*)){ belle_sip_list_t* copy=NULL; const belle_sip_list_t* iter; for(iter=list;iter!=NULL;iter=belle_sip_list_next(iter)){ copy=belle_sip_list_append(copy,copyfunc(iter->data)); } return copy; }
void sal_set_dns_servers(Sal *sal, const bctbx_list_t *servers){ belle_sip_list_t *l = NULL; /*we have to convert the bctbx_list_t into a belle_sip_list_t first*/ for (; servers != NULL; servers = servers->next){ l = belle_sip_list_append(l, servers->data); } belle_sip_stack_set_dns_servers(sal->stack, l); belle_sip_list_free(l); }
belle_sip_dialog_t *belle_sip_dialog_new(belle_sip_transaction_t *t){ belle_sip_dialog_t *obj; belle_sip_header_from_t *from; const char *from_tag; belle_sip_header_to_t *to; const char *to_tag=NULL; from=belle_sip_message_get_header_by_type(t->request,belle_sip_header_from_t); if (from==NULL){ belle_sip_error("belle_sip_dialog_new(): no from!"); return NULL; } from_tag=belle_sip_header_from_get_tag(from); if (from_tag==NULL){ belle_sip_error("belle_sip_dialog_new(): no from tag!"); return NULL; } if (t->last_response) { to=belle_sip_message_get_header_by_type(t->last_response,belle_sip_header_to_t); if (to==NULL){ belle_sip_error("belle_sip_dialog_new(): no to!"); return NULL; } to_tag=belle_sip_header_to_get_tag(to); } obj=belle_sip_object_new(belle_sip_dialog_t); obj->terminate_on_bye=1; obj->provider=t->provider; if (BELLE_SIP_OBJECT_IS_INSTANCE_OF(t,belle_sip_server_transaction_t)){ obj->remote_tag=belle_sip_strdup(from_tag); obj->local_tag=to_tag?belle_sip_strdup(to_tag):NULL; /*might be null at dialog creation*/ obj->remote_party=(belle_sip_header_address_t*)belle_sip_object_ref(from); obj->is_server=TRUE; }else{ const belle_sip_list_t *predefined_routes=NULL; obj->local_tag=belle_sip_strdup(from_tag); obj->remote_tag=to_tag?belle_sip_strdup(to_tag):NULL; /*might be null at dialog creation*/ obj->local_party=(belle_sip_header_address_t*)belle_sip_object_ref(from); obj->is_server=FALSE; for(predefined_routes=belle_sip_message_get_headers((belle_sip_message_t*)t->request,BELLE_SIP_ROUTE); predefined_routes!=NULL;predefined_routes=predefined_routes->next){ obj->route_set=belle_sip_list_append(obj->route_set,belle_sip_object_ref(predefined_routes->data)); } } belle_sip_message("New %s dialog [%p] , local tag [%s], remote tag [%s]" ,obj->is_server?"server":"client" ,obj ,obj->local_tag?obj->local_tag:"" ,obj->remote_tag?obj->remote_tag:""); set_state(obj,BELLE_SIP_DIALOG_NULL); return obj; }
void belle_sip_listening_point_add_channel(belle_sip_listening_point_t *lp, belle_sip_channel_t *chan){ chan->lp=lp; belle_sip_channel_add_listener(chan,lp->channel_listener); /*add channel listener*/ /*channel is already owned, no ref needed - REVISIT: channel should be initally unowned probably.*/ /* The channel with names must be treated with higher priority by the get_channel() method so queued on front. * This is to prevent the UDP listening point to dispatch incoming messages to channels that were created by inbound connection * where name cannot be determined. When this arrives, there can be 2 channels for the same destination IP and strange problems can occur * where requests are sent through name qualified channel and response received through name unqualified channel. */ if (chan->has_name) lp->channels=belle_sip_list_prepend(lp->channels,chan); else lp->channels=belle_sip_list_append(lp->channels,chan); }
static int belle_sip_dialog_init_as_uas(belle_sip_dialog_t *obj, belle_sip_request_t *req, belle_sip_response_t *resp){ const belle_sip_list_t *elem; belle_sip_header_contact_t *ct=belle_sip_message_get_header_by_type(req,belle_sip_header_contact_t); belle_sip_header_cseq_t *cseq=belle_sip_message_get_header_by_type(req,belle_sip_header_cseq_t); belle_sip_header_to_t *to=belle_sip_message_get_header_by_type(resp,belle_sip_header_to_t); belle_sip_header_via_t *via=belle_sip_message_get_header_by_type(req,belle_sip_header_via_t); belle_sip_uri_t *requri=belle_sip_request_get_uri(req); if (!ct){ belle_sip_error("No contact in request."); return -1; } if (!to){ belle_sip_error("No to in response."); return -1; } if (!cseq){ belle_sip_error("No cseq in request."); return -1; } if (!via){ belle_sip_error("No via in request."); return -1; } if (strcasecmp(belle_sip_header_via_get_protocol(via),"TLS")==0 && belle_sip_uri_is_secure(requri)){ obj->is_secure=TRUE; } /* 12.1.1 *The route set MUST be set to the list of URIs in the Record-Route * header field from the request, taken in order and preserving all URI * parameters. If no Record-Route header field is present in the *request, the route set MUST be set to the empty set. */ obj->route_set=belle_sip_list_free_with_data(obj->route_set,belle_sip_object_unref); for(elem=belle_sip_message_get_headers((belle_sip_message_t*)req,BELLE_SIP_RECORD_ROUTE);elem!=NULL;elem=elem->next){ obj->route_set=belle_sip_list_append(obj->route_set,belle_sip_object_ref(belle_sip_header_route_create( (belle_sip_header_address_t*)elem->data))); } check_route_set(obj->route_set); obj->remote_target=(belle_sip_header_address_t*)belle_sip_object_ref(ct); obj->remote_cseq=belle_sip_header_cseq_get_seq_number(cseq); /*call id already set */ /*remote party already set */ obj->local_party=(belle_sip_header_address_t*)belle_sip_object_ref(to); return 0; }
belle_sip_list_t* belle_sip_list_insert(belle_sip_list_t* list, belle_sip_list_t* before, void *data){ belle_sip_list_t* elem; if (list==NULL || before==NULL) return belle_sip_list_append(list,data); for(elem=list;elem!=NULL;elem=belle_sip_list_next(elem)){ if (elem==before){ if (elem->prev==NULL) return belle_sip_list_prepend(list,data); else{ belle_sip_list_t* nelem=belle_sip_list_new(data); nelem->prev=elem->prev; nelem->next=elem; elem->prev->next=nelem; elem->prev=nelem; } } } return list; }
static int keep_alive_timer_func(void *user_data, unsigned int events) { belle_sip_listening_point_t* lp=(belle_sip_listening_point_t*)user_data; belle_sip_list_t* iterator; belle_sip_channel_t* channel; belle_sip_list_t *to_be_closed=NULL; for (iterator=lp->channels;iterator!=NULL;iterator=iterator->next) { channel=(belle_sip_channel_t*)iterator->data; if (channel->state == BELLE_SIP_CHANNEL_READY && send_keep_alive(channel)==-1) { /*only send keep alive if ready*/ to_be_closed=belle_sip_list_append(to_be_closed,channel); } } for (iterator=to_be_closed;iterator!=NULL;iterator=iterator->next){ channel=(belle_sip_channel_t*)iterator->data; channel_set_state(channel,BELLE_SIP_CHANNEL_ERROR); belle_sip_channel_close(channel); } belle_sip_list_free(to_be_closed); return BELLE_SIP_CONTINUE_WITHOUT_CATCHUP; }
static void channel_on_sending(belle_sip_channel_listener_t *obj, belle_sip_channel_t *chan, belle_sip_message_t *msg){ belle_http_channel_context_t *ctx=BELLE_HTTP_CHANNEL_CONTEXT(obj); ctx->pending_requests=belle_sip_list_append(ctx->pending_requests,belle_sip_object_ref(msg)); }
static void _linphone_xml_rpc_request_add_int_arg(LinphoneXmlRpcRequest *request, int value) { LinphoneXmlRpcArg *arg = belle_sip_malloc0(sizeof(LinphoneXmlRpcArg)); arg->type = LinphoneXmlRpcArgInt; arg->data.i = value; request->arg_list = belle_sip_list_append(request->arg_list, arg); }
static void stream_description_to_sdp ( belle_sdp_session_description_t *session_desc, const SalMediaDescription *md, const SalStreamDescription *stream ) { belle_sdp_mime_parameter_t* mime_param; belle_sdp_media_description_t* media_desc; int j; MSList* pt_it; PayloadType* pt; char buffer[1024]; char* dir=NULL; const char *rtp_addr; const char *rtcp_addr; int rtp_port; int rtcp_port; bool_t different_rtp_and_rtcp_addr; rtp_addr=stream->rtp_addr; rtcp_addr=stream->rtcp_addr; rtp_port=stream->rtp_port; rtcp_port=stream->rtcp_port; media_desc = belle_sdp_media_description_create ( sal_stream_description_get_type_as_string(stream) ,stream->rtp_port ,1 ,sal_media_proto_to_string ( stream->proto ) ,NULL ); if (stream->payloads) { for ( pt_it=stream->payloads; pt_it!=NULL; pt_it=pt_it->next ) { pt= ( PayloadType* ) pt_it->data; mime_param= belle_sdp_mime_parameter_create ( pt->mime_type , payload_type_get_number ( pt ) , pt->clock_rate ,stream->type==SalAudio?1:-1 ); belle_sdp_mime_parameter_set_parameters ( mime_param,pt->recv_fmtp ); if ( stream->ptime>0 ) { belle_sdp_mime_parameter_set_ptime ( mime_param,stream->ptime ); } belle_sdp_media_description_append_values_from_mime_parameter ( media_desc,mime_param ); belle_sip_object_unref ( mime_param ); } } else { /* to comply with SDP we cannot have an empty payload type number list */ /* as it happens only when mline is declined with a zero port, it does not matter to put whatever codec*/ belle_sip_list_t* format = belle_sip_list_append(NULL,0); belle_sdp_media_set_media_formats(belle_sdp_media_description_get_media(media_desc),format); } /*only add a c= line within the stream description if address are differents*/ if (rtp_addr[0]!='\0' && strcmp(rtp_addr,md->addr)!=0){ bool_t inet6; if (strchr(rtp_addr,':')!=NULL){ inet6=TRUE; }else inet6=FALSE; belle_sdp_media_description_set_connection(media_desc,belle_sdp_connection_create("IN", inet6 ? "IP6" : "IP4", rtp_addr)); } if ( stream->bandwidth>0 ) belle_sdp_media_description_set_bandwidth ( media_desc,"AS",stream->bandwidth ); if ( stream->proto == SalProtoRtpSavp ) { /* add crypto lines */ for ( j=0; j<SAL_CRYPTO_ALGO_MAX; j++ ) { switch ( stream->crypto[j].algo ) { case AES_128_SHA1_80: snprintf ( buffer, sizeof ( buffer ), "%d %s inline:%s", stream->crypto[j].tag, "AES_CM_128_HMAC_SHA1_80", stream->crypto[j].master_key ); belle_sdp_media_description_add_attribute ( media_desc,belle_sdp_attribute_create ( "crypto",buffer ) ); break; case AES_128_SHA1_32: snprintf ( buffer, sizeof ( buffer ), "%d %s inline:%s", stream->crypto[j].tag, "AES_CM_128_HMAC_SHA1_32", stream->crypto[j].master_key ); belle_sdp_media_description_add_attribute ( media_desc,belle_sdp_attribute_create ( "crypto",buffer ) ); break; case AES_128_NO_AUTH: ms_warning ( "Unsupported crypto suite: AES_128_NO_AUTH" ); break; case NO_CIPHER_SHA1_80: ms_warning ( "Unsupported crypto suite: NO_CIPHER_SHA1_80" ); break; default: j = SAL_CRYPTO_ALGO_MAX; /* no break */ } } } switch ( stream->dir ) { case SalStreamSendRecv: /*dir="sendrecv";*/ dir=NULL; break; case SalStreamRecvOnly: dir="recvonly"; break; case SalStreamSendOnly: dir="sendonly"; break; case SalStreamInactive: dir="inactive"; break; } if ( dir ) belle_sdp_media_description_add_attribute ( media_desc,belle_sdp_attribute_create ( dir,NULL ) ); if (rtp_port != 0) { different_rtp_and_rtcp_addr = (rtcp_addr[0] != '\0') && (strcmp(rtp_addr, rtcp_addr) != 0); if ((rtcp_port != (rtp_port + 1)) || (different_rtp_and_rtcp_addr == TRUE)) { if (different_rtp_and_rtcp_addr == TRUE) { snprintf(buffer, sizeof(buffer), "%u IN IP4 %s", rtcp_port, rtcp_addr); } else { snprintf(buffer, sizeof(buffer), "%u",rtcp_port); } belle_sdp_media_description_add_attribute(media_desc,belle_sdp_attribute_create ("rtcp",buffer)); } } if (stream->ice_completed == TRUE) { belle_sdp_media_description_add_attribute(media_desc,belle_sdp_attribute_create ("nortpproxy","yes")); } if (stream->ice_mismatch == TRUE) { belle_sdp_media_description_add_attribute(media_desc,belle_sdp_attribute_create ("ice-mismatch",NULL)); } else { if (rtp_port != 0) { if (stream->ice_pwd[0] != '\0') belle_sdp_media_description_add_attribute(media_desc,belle_sdp_attribute_create ("ice-pwd",stream->ice_pwd)); if (stream->ice_ufrag[0] != '\0') belle_sdp_media_description_add_attribute(media_desc,belle_sdp_attribute_create ("ice-ufrag",stream->ice_ufrag)); add_ice_candidates(media_desc,stream); add_ice_remote_candidates(media_desc,stream); } } if (stream->rtcp_xr.enabled == TRUE) { char sastr[1024] = {0}; char mastr[1024] = {0}; size_t saoff = 0; size_t maoff = 0; const belle_sdp_attribute_t *session_attribute = belle_sdp_session_description_get_attribute(session_desc, "rtcp-xr"); belle_sdp_attribute_t *media_attribute; if (session_attribute != NULL) { belle_sip_object_marshal((belle_sip_object_t*)session_attribute, sastr, sizeof(sastr), &saoff); } media_attribute = create_rtcp_xr_attribute(&stream->rtcp_xr); if (media_attribute != NULL) { belle_sip_object_marshal((belle_sip_object_t*)media_attribute, mastr, sizeof(mastr), &maoff); } if (strcmp(sastr, mastr) != 0) { belle_sdp_media_description_add_attribute(media_desc, media_attribute); } else { belle_sip_object_unref((belle_sip_object_t*)media_attribute); } } belle_sdp_session_description_add_media_description(session_desc, media_desc); }
void belle_sip_channel_add_listener(belle_sip_channel_t *obj, belle_sip_channel_listener_t *l){ obj->listeners=belle_sip_list_append(obj->listeners, belle_sip_object_weak_ref(l, (belle_sip_object_destroy_notify_t)channel_remove_listener,obj)); }
static void _linphone_xml_rpc_request_add_string_arg(LinphoneXmlRpcRequest *request, const char *value) { LinphoneXmlRpcArg *arg = belle_sip_malloc0(sizeof(LinphoneXmlRpcArg)); arg->type = LinphoneXmlRpcArgString; arg->data.s = belle_sip_strdup(value); request->arg_list = belle_sip_list_append(request->arg_list, arg); }
static void channel_push_outgoing(belle_sip_channel_t *obj, belle_sip_message_t *msg){ obj->outgoing_messages=belle_sip_list_append(obj->outgoing_messages,msg); }
void belle_sip_body_handler_add_header(belle_sip_body_handler_t *obj, belle_sip_header_t *header) { if (header != NULL) { obj->headers=belle_sip_list_append(obj->headers,belle_sip_object_ref(header)); } }
void belle_sip_dialog_queue_client_transaction(belle_sip_dialog_t *dialog, belle_sip_client_transaction_t *tr){ dialog->queued_ct=belle_sip_list_append(dialog->queued_ct, belle_sip_object_ref(tr)); }
void belle_sip_main_loop_iterate(belle_sip_main_loop_t *ml){ size_t pfd_size = ml->nsources * sizeof(belle_sip_pollfd_t); belle_sip_pollfd_t *pfd=(belle_sip_pollfd_t*)belle_sip_malloc0(pfd_size); int i=0; belle_sip_source_t *s; belle_sip_list_t *elem,*next; uint64_t min_time_ms=(uint64_t)-1; int duration=-1; int ret; uint64_t cur; belle_sip_list_t *to_be_notified=NULL; int can_clean=belle_sip_object_pool_cleanable(ml->pool); /*iterate might not be called by the thread that created the main loop*/ belle_sip_object_pool_t *tmp_pool=NULL; if (!can_clean){ /*Push a temporary pool for the time of the iterate loop*/ tmp_pool=belle_sip_object_pool_push(); } /*Step 1: prepare the pollfd table and get the next timeout value */ for(elem=ml->sources;elem!=NULL;elem=next){ next=elem->next; s=(belle_sip_source_t*)elem->data; if (!s->cancelled){ if (s->fd!=(belle_sip_fd_t)-1){ belle_sip_source_to_poll(s,pfd,i); ++i; } if (s->timeout>=0){ if (min_time_ms>s->expire_ms){ min_time_ms=s->expire_ms; } } } } if (min_time_ms!=(uint64_t)-1 ){ int64_t diff; /* compute the amount of time to wait for shortest timeout*/ cur=belle_sip_time_ms(); diff=min_time_ms-cur; if (diff>0) duration=(int)diff; else duration=0; } /* do the poll */ ret=belle_sip_poll(pfd,i,duration); if (ret==-1){ goto end; } /* Step 2: examine poll results and determine the list of source to be notified */ cur=belle_sip_time_ms(); for(elem=ml->sources;elem!=NULL;elem=elem->next){ unsigned revents=0; s=(belle_sip_source_t*)elem->data; if (!s->cancelled){ if (s->fd!=(belle_sip_fd_t)-1){ if (s->notify_required) { /*for testing purpose to force channel to read*/ revents=BELLE_SIP_EVENT_READ; s->notify_required=0; /*reset*/ } else { revents=belle_sip_source_get_revents(s,pfd); } s->revents=revents; } if (revents!=0 || (s->timeout>=0 && cur>=s->expire_ms)){ to_be_notified=belle_sip_list_append(to_be_notified,belle_sip_object_ref(s)); s->expired=TRUE; if (s->revents==0) s->revents=BELLE_SIP_EVENT_TIMEOUT; } }else to_be_notified=belle_sip_list_append(to_be_notified,belle_sip_object_ref(s)); } /* Step 3: notify those to be notified */ for(elem=to_be_notified;elem!=NULL;){ s=(belle_sip_source_t*)elem->data; next=elem->next; if (!s->cancelled){ char *objdesc=belle_sip_object_to_string((belle_sip_object_t*)s); if (s->timeout>0)/*to avoid too many traces*/ belle_sip_debug("source %s notified revents=%u, timeout=%i",objdesc,revents,s->timeout); belle_sip_free(objdesc); ret=s->notify(s->data,s->revents); if (ret==BELLE_SIP_STOP || s->oneshot){ /*this source needs to be removed*/ belle_sip_main_loop_remove_source(ml,s); }else if (s->revents==BELLE_SIP_EVENT_TIMEOUT){ /*timeout needs to be started again */ s->expire_ms+=s->timeout; s->expired=FALSE; } }else belle_sip_main_loop_remove_source(ml,s); belle_sip_object_unref(s); belle_sip_free(elem); /*free just the element*/ elem=next; } if (can_clean) belle_sip_object_pool_clean(ml->pool); else if (tmp_pool) belle_sip_object_unref(tmp_pool); end: belle_sip_free(pfd); }
static void stream_description_to_sdp ( belle_sdp_session_description_t *session_desc, const SalMediaDescription *md, const SalStreamDescription *stream ) { belle_sdp_mime_parameter_t* mime_param; belle_sdp_media_description_t* media_desc; int j; MSList* pt_it; PayloadType* pt; char buffer[1024]; char* dir=NULL; const char *rtp_addr; const char *rtcp_addr; int rtp_port; int rtcp_port; bool_t different_rtp_and_rtcp_addr; rtp_addr=stream->rtp_addr; rtcp_addr=stream->rtcp_addr; rtp_port=stream->rtp_port; rtcp_port=stream->rtcp_port; media_desc = belle_sdp_media_description_create ( sal_stream_description_get_type_as_string(stream) ,stream->rtp_port ,1 ,sal_media_proto_to_string ( stream->proto ) ,NULL ); if (stream->payloads) { for ( pt_it=stream->payloads; pt_it!=NULL; pt_it=pt_it->next ) { pt= ( PayloadType* ) pt_it->data; mime_param= belle_sdp_mime_parameter_create ( pt->mime_type , payload_type_get_number ( pt ) , pt->clock_rate , pt->channels>0 ? pt->channels : -1 ); belle_sdp_mime_parameter_set_parameters ( mime_param,pt->recv_fmtp ); if ( stream->ptime>0 ) { belle_sdp_mime_parameter_set_ptime ( mime_param,stream->ptime ); } belle_sdp_media_description_append_values_from_mime_parameter ( media_desc,mime_param ); belle_sip_object_unref ( mime_param ); } } else { /* to comply with SDP we cannot have an empty payload type number list */ /* as it happens only when mline is declined with a zero port, it does not matter to put whatever codec*/ belle_sip_list_t* format = belle_sip_list_append(NULL,0); belle_sdp_media_set_media_formats(belle_sdp_media_description_get_media(media_desc),format); } /*only add a c= line within the stream description if address are differents*/ if (rtp_addr[0]!='\0' && strcmp(rtp_addr,md->addr)!=0){ bool_t inet6; belle_sdp_connection_t *connection; if (strchr(rtp_addr,':')!=NULL){ inet6=TRUE; }else inet6=FALSE; connection = belle_sdp_connection_create("IN", inet6 ? "IP6" : "IP4", rtp_addr); if (ms_is_multicast(rtp_addr)) { /*remove session cline in case of multicast*/ belle_sdp_session_description_set_connection(session_desc,NULL); if (inet6 == FALSE) belle_sdp_connection_set_ttl(connection,stream->ttl); } belle_sdp_media_description_set_connection(media_desc,connection); } if ( stream->bandwidth>0 ) belle_sdp_media_description_set_bandwidth ( media_desc,"AS",stream->bandwidth ); if ((stream->proto == SalProtoRtpSavpf) || (stream->proto == SalProtoRtpSavp)) { /* add crypto lines */ for ( j=0; j<SAL_CRYPTO_ALGO_MAX; j++ ) { MSCryptoSuiteNameParams desc; if (ms_crypto_suite_to_name_params(stream->crypto[j].algo,&desc)==0){ if (desc.params) snprintf ( buffer, sizeof ( buffer )-1, "%d %s inline:%s %s", stream->crypto[j].tag, desc.name, stream->crypto[j].master_key,desc.params); else snprintf ( buffer, sizeof ( buffer )-1, "%d %s inline:%s", stream->crypto[j].tag, desc.name, stream->crypto[j].master_key ); belle_sdp_media_description_add_attribute( media_desc,belle_sdp_attribute_create ("crypto", buffer)); }else break; } } /* insert DTLS session attribute if needed */ if ((stream->proto == SalProtoUdpTlsRtpSavpf) || (stream->proto == SalProtoUdpTlsRtpSavp)) { char* ssrc_attribute = ms_strdup_printf("%u cname:%s",htonl(stream->rtp_ssrc),stream->rtcp_cname); if ((stream->dtls_role != SalDtlsRoleInvalid) && (strlen(stream->dtls_fingerprint)>0)) { switch(stream->dtls_role) { case SalDtlsRoleIsClient: belle_sdp_media_description_add_attribute(media_desc, belle_sdp_attribute_create("setup","active")); break; case SalDtlsRoleIsServer: belle_sdp_media_description_add_attribute(media_desc, belle_sdp_attribute_create("setup","passive")); break; case SalDtlsRoleUnset: default: belle_sdp_media_description_add_attribute(media_desc, belle_sdp_attribute_create("setup","actpass")); break; } belle_sdp_media_description_add_attribute(media_desc, belle_sdp_attribute_create("fingerprint",stream->dtls_fingerprint)); } belle_sdp_media_description_add_attribute(media_desc, belle_sdp_attribute_create("ssrc",ssrc_attribute)); /* truc de Jehan a virer? */ ms_free(ssrc_attribute); } switch ( stream->dir ) { case SalStreamSendRecv: /*dir="sendrecv";*/ dir=NULL; break; case SalStreamRecvOnly: dir="recvonly"; break; case SalStreamSendOnly: dir="sendonly"; break; case SalStreamInactive: dir="inactive"; break; } if ( dir ) belle_sdp_media_description_add_attribute ( media_desc,belle_sdp_attribute_create ( dir,NULL ) ); if (rtp_port != 0) { different_rtp_and_rtcp_addr = (rtcp_addr[0] != '\0') && (strcmp(rtp_addr, rtcp_addr) != 0); if ((rtcp_port != (rtp_port + 1)) || (different_rtp_and_rtcp_addr == TRUE)) { if (different_rtp_and_rtcp_addr == TRUE) { snprintf(buffer, sizeof(buffer), "%u IN IP4 %s", rtcp_port, rtcp_addr); } else { snprintf(buffer, sizeof(buffer), "%u",rtcp_port); } belle_sdp_media_description_add_attribute(media_desc,belle_sdp_attribute_create ("rtcp",buffer)); } } if (stream->ice_completed == TRUE) { belle_sdp_media_description_add_attribute(media_desc,belle_sdp_attribute_create ("nortpproxy","yes")); } if (stream->ice_mismatch == TRUE) { belle_sdp_media_description_add_attribute(media_desc,belle_sdp_attribute_create ("ice-mismatch",NULL)); } else { if (rtp_port != 0) { if (stream->ice_pwd[0] != '\0') belle_sdp_media_description_add_attribute(media_desc,belle_sdp_attribute_create ("ice-pwd",stream->ice_pwd)); if (stream->ice_ufrag[0] != '\0') belle_sdp_media_description_add_attribute(media_desc,belle_sdp_attribute_create ("ice-ufrag",stream->ice_ufrag)); add_ice_candidates(media_desc,stream); add_ice_remote_candidates(media_desc,stream); } } if ((rtp_port != 0) && ((stream->proto == SalProtoRtpAvpf) || (stream->proto == SalProtoRtpSavpf))) { add_rtcp_fb_attributes(media_desc, md, stream); } if ((rtp_port != 0) && (stream->rtcp_xr.enabled == TRUE)) { char sastr[1024] = {0}; char mastr[1024] = {0}; size_t saoff = 0; size_t maoff = 0; const belle_sdp_attribute_t *session_attribute = belle_sdp_session_description_get_attribute(session_desc, "rtcp-xr"); belle_sdp_attribute_t *media_attribute; if (session_attribute != NULL) { belle_sip_object_marshal((belle_sip_object_t*)session_attribute, sastr, sizeof(sastr), &saoff); } media_attribute = create_rtcp_xr_attribute(&stream->rtcp_xr); if (media_attribute != NULL) { belle_sip_object_marshal((belle_sip_object_t*)media_attribute, mastr, sizeof(mastr), &maoff); } if (strcmp(sastr, mastr) != 0) { belle_sdp_media_description_add_attribute(media_desc, media_attribute); } else { belle_sip_object_unref((belle_sip_object_t*)media_attribute); } } /* * rfc5576 * 4.1. The "ssrc" Media Attribute * <ssrc-id> is the synchronization source (SSRC) ID of the * source being described, interpreted as a 32-bit unsigned integer in * network byte order and represented in decimal.*/ belle_sdp_session_description_add_media_description(session_desc, media_desc); }