/**@ingroup tmedia_codec_group * Initialize a Codec * @param self The codec to initialize. Could be any type of codec (e.g. @ref tmedia_codec_audio_t or @ref tmedia_codec_video_t). * @param type * @param name the name of the codec. e.g. "G.711u" or "G.711a" etc used in the sdp. * @param desc full description. * @param format the format. e.g. "0" for G.711.u or "8" for G.711a or "*" for MSRP. * @retval Zero if succeed and non-zero error code otherwise. */ int tmedia_codec_init(tmedia_codec_t* self, tmedia_type_t type, const char* name, const char* desc, const char* format) { if(!self || tsk_strnullORempty(name)){ TSK_DEBUG_ERROR("Invalid parameter"); return -1; } self->type = type; tsk_strupdate(&self->name, name); tsk_strupdate(&self->desc,desc); tsk_strupdate(&self->format, format); if(!self->bandwidth_max_upload) self->bandwidth_max_upload = (type == tmedia_video ? tmedia_defaults_get_bandwidth_video_upload_max() : INT_MAX); // INT_MAX or <=0 means undefined if(!self->bandwidth_max_download) self->bandwidth_max_download = (type == tmedia_video ? tmedia_defaults_get_bandwidth_video_download_max() : INT_MAX); // INT_MAX or <=0 means undefined if(!self->in.rate) self->in.rate = self->plugin->rate; if(!self->out.rate) self->out.rate = self->plugin->rate; if(type & tmedia_audio){ tmedia_codec_audio_t* audio = TMEDIA_CODEC_AUDIO(self); if(!audio->in.ptime) audio->in.ptime = (self->plugin->audio.ptime ? self->plugin->audio.ptime : tmedia_defaults_get_audio_ptime()); if(!audio->out.ptime) audio->out.ptime = (self->plugin->audio.ptime ? self->plugin->audio.ptime : tmedia_defaults_get_audio_ptime()); if(!audio->in.channels) audio->in.channels = self->plugin->audio.channels; if(!audio->out.channels) audio->out.channels = self->plugin->audio.channels; if(!audio->in.timestamp_multiplier) audio->in.timestamp_multiplier = tmedia_codec_audio_get_timestamp_multiplier(self->id, self->in.rate); if(!audio->out.timestamp_multiplier) audio->out.timestamp_multiplier = tmedia_codec_audio_get_timestamp_multiplier(self->id, self->out.rate); } // Video flipping: For backward compatibility we have to initialize the default values // according to the CFLAGS: 'FLIP_ENCODED_PICT' and 'FLIP_DECODED_PICT'. At any time you // can update thse values (e.g. when the device switch from landscape to portrait) using video_session->set(); else if(type & tmedia_video){ tmedia_codec_video_t* video = TMEDIA_CODEC_VIDEO(self); #if FLIP_ENCODED_PICT video->out.flip = tsk_true; #endif #if FLIP_DECODED_PICT video->in.flip = tsk_true; #endif if(!video->in.fps) video->in.fps = self->plugin->video.fps ? self->plugin->video.fps : tmedia_defaults_get_video_fps(); if(!video->out.fps) video->out.fps = self->plugin->video.fps ? self->plugin->video.fps : tmedia_defaults_get_video_fps(); if(video->in.chroma == tmedia_chroma_none) video->in.chroma = tmedia_chroma_yuv420p; if(video->out.chroma == tmedia_chroma_none) video->out.chroma = tmedia_chroma_yuv420p; if(0){ // @deprecated if(!video->in.width) video->in.width = video->out.width = self->plugin->video.width; if(!video->in.height) video->in.height = video->out.height = self->plugin->video.height; } else{ int ret; unsigned width, height; video->pref_size = tmedia_defaults_get_pref_video_size(); if((ret = tmedia_video_get_size(video->pref_size, &width, &height)) != 0){ width = self->plugin->video.width; height = self->plugin->video.height; } if(!video->in.width) video->in.width = video->out.width = width; if(!video->in.height) video->in.height = video->out.height = height; } } return 0; }
/** * Registers a new AUID. If the AUID already exist (case-insensitive comparison on the id), * then it will be updated with the new supplied values. * @param auids The destination list. * @param id The id of the new AUID to add (e.g. xcap-caps). * @param mime_type The MIME-Type of the new AUID to add (e.g. application/xcap-caps+xml). * @param ns The Namespace of the new AUID to add (e.g. urn:ietf:params:xml:ns:xcap-caps). * @param document_name The name of the new AUID to add (e.g. index). * @param is_global Indicates whether the AUID scope is global or not (user). * @retval Zero if succeed and non-zero error code otherwise. */ int txcap_auid_register(txcap_auids_L_t* auids, const char* id, const char* mime_type, const char* ns, const char* document_name, tsk_bool_t is_global) { const tsk_list_item_t* item; int ret = -1; if(!auids || !id){ return -1; } if((item = tsk_list_find_item_by_pred(auids, pred_find_auid_by_id, id))){ tsk_strupdate(&((txcap_auid_t*)item->data)->mime_type, mime_type); tsk_strupdate(&((txcap_auid_t*)item->data)->ns, ns); tsk_strupdate(&((txcap_auid_t*)item->data)->document_name, document_name); ((txcap_auid_t*)item->data)->global = is_global; ret = 0; } else{ txcap_auid_t* auid; if((auid = txcap_auid_create(tauid_dummy, id, mime_type, ns, document_name, is_global))){ tsk_list_push_back_data(auids, (void**)&auid); ret = 0; }else{ ret = -2; } } return ret; }
static int init_neg_types(tdav_session_msrp_t* msrp, const tsdp_header_M_t* m) { const tsdp_header_A_t* A; if((A = tsdp_header_M_findA(m, "accept-types"))){ char* atype = strtok((char*)A->value, " "); const char* default_atype = atype; while(atype){ if(tsk_striequals(atype, "message/CPIM")){ tsk_strupdate(&msrp->neg_accept_type, atype); if((A = tsdp_header_M_findA(m, "accept-wrapped-types"))){ char* awtype = strtok((char*)A->value, " "); tsk_strupdate(&msrp->neg_accept_w_type, awtype); // first } break; } atype = strtok(tsk_null, " "); } if(!msrp->neg_accept_type){ tsk_strupdate(&msrp->neg_accept_type, default_atype); } return 0; } return -1; }
int tnet_ice_candidate_process_stun_response(tnet_ice_candidate_t* self, const tnet_stun_pkt_resp_t* response, tnet_fd_t fd) { int ret = 0; if (!self || !response) { TSK_DEBUG_ERROR("Inavlid parameter"); return -1; } //if(!(_tnet_ice_candidate_stun_transac_id_equals(response->transac_id, self->stun.transac_id))){ // TSK_DEBUG_ERROR("Transaction id mismatch"); // return -2; //} if (TNET_STUN_PKT_RESP_IS_ERROR(response)) { uint16_t u_code; if ((ret = tnet_stun_pkt_get_errorcode(response, &u_code))) { return ret; } if (u_code == kStunErrCodeUnauthorized || u_code == kStunErrCodeStaleNonce) { const tnet_stun_attr_vdata_t* pc_attr; if (u_code == kStunErrCodeUnauthorized) { // Make sure this is not an authentication failure (#2 401) // Do not send another req to avoid endless messages if ((tnet_stun_pkt_attr_exists(response, tnet_stun_attr_type_message_integrity))) { // already has a MESSAGE-INTEGRITY? TSK_DEBUG_ERROR("TURN authentication failed"); return -3; } } if ((ret = tnet_stun_pkt_attr_find_first(response, tnet_stun_attr_type_nonce, (const tnet_stun_attr_t**)&pc_attr)) == 0 && pc_attr) { tsk_strupdate(&self->stun.nonce, (const char*)pc_attr->p_data_ptr); } if ((ret = tnet_stun_pkt_attr_find_first(response, tnet_stun_attr_type_realm, (const tnet_stun_attr_t**)&pc_attr)) == 0 && pc_attr) { tsk_strupdate(&self->stun.realm, (const char*)pc_attr->p_data_ptr); } return 0; } else { TSK_DEBUG_ERROR("STUN error: %hu", u_code); return -4; } } else if (TNET_STUN_PKT_RESP_IS_SUCCESS(response)) { const tnet_stun_attr_address_t* pc_attr_addr; if (((ret = tnet_stun_pkt_attr_find_first(response, tnet_stun_attr_type_xor_mapped_address, (const tnet_stun_attr_t**)&pc_attr_addr)) == 0 && pc_attr_addr) || ((ret = tnet_stun_pkt_attr_find_first(response, tnet_stun_attr_type_mapped_address, (const tnet_stun_attr_t**)&pc_attr_addr)) == 0 && pc_attr_addr)) { tnet_ip_t ip; if ((ret = tnet_stun_utils_inet_ntop((pc_attr_addr->e_family == tnet_stun_address_family_ipv6), &pc_attr_addr->address, &ip))) { return ret; } tsk_strupdate(&self->stun.srflx_addr, ip); self->stun.srflx_port = pc_attr_addr->u_port; } } return ret; }
int tsip_challenge_set_cred(tsip_challenge_t *self, const char* username, const char* ha1_hexstr) { if(!self || tsk_strlen(ha1_hexstr) != (TSK_MD5_DIGEST_SIZE << 1)){ TSK_DEBUG_ERROR("Invalid parameter"); return -1; } tsk_strupdate(&self->username, username); tsk_strupdate(&self->ha1_hexstr, ha1_hexstr); return 0; }
int tnet_ice_candidate_set_credential(tnet_ice_candidate_t* self, const char* ufrag, const char* pwd) { if(!self){ TSK_DEBUG_ERROR("Invalid parameter"); return -1; } tsk_strupdate(&self->ufrag, ufrag); tsk_strupdate(&self->pwd, pwd); return 0; }
int tnet_ice_candidate_process_stun_response(tnet_ice_candidate_t* self, const tnet_stun_response_t* response, tnet_fd_t fd) { int ret = 0; if(!self || !response){ TSK_DEBUG_ERROR("Inavlid parameter"); return -1; } //if(!(_tnet_ice_candidate_stun_transac_id_equals(response->transaction_id, self->stun.transac_id))){ // TSK_DEBUG_ERROR("Transaction id mismatch"); // return -2; //} if(TNET_STUN_RESPONSE_IS_ERROR(response)){ short code = tnet_stun_message_get_errorcode(response); const char* realm = tnet_stun_message_get_realm(response); const char* nonce = tnet_stun_message_get_nonce(response); if(code == 401 && realm && nonce){ if(!self->stun.nonce){ /* First time we get a nonce */ tsk_strupdate(&self->stun.nonce, nonce); tsk_strupdate(&self->stun.realm, realm); return 0; } else{ TSK_DEBUG_ERROR("Authentication failed"); return -3; } } else{ TSK_DEBUG_ERROR("STUN error: %hi", code); return -4; } } else if(TNET_STUN_RESPONSE_IS_SUCCESS(response)){ const tnet_stun_attribute_t *attribute; if((attribute = tnet_stun_message_get_attribute(response, stun_xor_mapped_address))){ const tnet_stun_attribute_xmapped_addr_t *xmaddr = (const tnet_stun_attribute_xmapped_addr_t *)attribute; tnet_ice_utils_stun_address_tostring(xmaddr->xaddress, xmaddr->family, &self->stun.srflx_addr); self->stun.srflx_port = xmaddr->xport; } else if((attribute = tnet_stun_message_get_attribute(response, stun_mapped_address))){ const tnet_stun_attribute_mapped_addr_t *maddr = (const tnet_stun_attribute_mapped_addr_t *)attribute; ret = tnet_ice_utils_stun_address_tostring(maddr->address, maddr->family, &self->stun.srflx_addr); self->stun.srflx_port = maddr->port; } } return ret; }
/**@ingroup tnet_nat_group * Gets the server reflexive address associated to this STUN2 binding. * * * @param [in,out] p_self The NAT context. * @param id The id of the STUN2 binding conetxt (obtained using @ref tnet_nat_stun_bind) holding the server-reflexive address. * @param [in,out] pp_ip The reflexive IP address. It is up the the caller to free the returned string * @param [in,out] pu_port The reflexive port. * * @return Zero if succeed and non zero error code otherwise. **/ int tnet_nat_stun_get_reflexive_address(const struct tnet_nat_ctx_s* p_self, tnet_stun_binding_id_t id, char** pp_ip, tnet_port_t *pu_port) { const tsk_list_item_t* item; if (!p_self) { TSK_DEBUG_ERROR("Invalid parameter"); return -1; } if (!pp_ip && !pu_port) { return 0; } if ((item = tsk_list_find_item_by_pred(p_self->stun_bindings, __pred_find_stun_binding, &id)) && item->data) { const tnet_stun_binding_t *pc_bind = (const tnet_stun_binding_t *)item->data; const struct tnet_stun_attr_address_s *pc_addr = pc_bind->p_xmaddr ? pc_bind->p_xmaddr : pc_bind->p_maddr; if (pc_addr) { tnet_ip_t ip; int ret; if ((ret = tnet_stun_utils_inet_ntop((pc_addr->e_family == tnet_stun_address_family_ipv6), &pc_addr->address, &ip))) { return ret; } if (pp_ip) { tsk_strupdate(pp_ip, ip); } if (pu_port) { *pu_port = pc_addr->u_port; } return 0; } } return -2; }
/**@ingroup tmedia_codec_group * Initialize a Codec * @param self The codec to initialize. Could be any type of codec (e.g. @ref tmedia_codec_audio_t or @ref tmedia_codec_video_t). * @param type * @param name the name of the codec. e.g. "G.711u" or "G.711a" etc used in the sdp. * @param desc full description. * @param format the format. e.g. "0" for G.711.u or "8" for G.711a or "*" for MSRP. * @retval Zero if succeed and non-zero error code otherwise. */ int tmedia_codec_init(tmedia_codec_t* self, tmedia_type_t type, const char* name, const char* desc, const char* format) { if(!self || tsk_strnullORempty(name)){ TSK_DEBUG_ERROR("Invalid parameter"); return -1; } self->type = type; tsk_strupdate(&self->name, name); tsk_strupdate(&self->desc,desc); tsk_strupdate(&self->format, format); // Video flipping: For backward compatibility we have to initialize the default values // according to the CFLAGS: 'FLIP_ENCODED_PICT' and 'FLIP_DECODED_PICT'. At any time you // can update thse values (e.g. when the device switch from landscape to portrait) using video_session->set(); if(type & tmedia_video){ tmedia_codec_video_t* video = TMEDIA_CODEC_VIDEO(self); #if FLIP_ENCODED_PICT video->out.flip = tsk_true; #endif #if FLIP_DECODED_PICT video->in.flip = tsk_true; #endif if(!video->in.fps) video->in.fps = video->out.fps = self->plugin->video.fps; if(video->in.chroma == tmedia_chroma_none) video->in.chroma = tmedia_chroma_yuv420p; if(video->out.chroma == tmedia_chroma_none) video->out.chroma = tmedia_chroma_yuv420p; if(0){ // @deprecated if(!video->in.width) video->in.width = video->out.width = self->plugin->video.width; if(!video->in.height) video->in.height = video->out.height = self->plugin->video.height; } else{ int ret; unsigned width, height; video->pref_size = tmedia_defaults_get_pref_video_size(); if((ret = tmedia_video_get_size(video->pref_size, &width, &height)) != 0){ width = self->plugin->video.width; height = self->plugin->video.height; } if(!video->in.width) video->in.width = video->out.width = width; if(!video->in.height) video->in.height = video->out.height = height; } } return 0; }
/**@ingroup tipsec_xp_group */ int tipsec_set_local(tipsec_context_t* ctx, const char* addr_local, const char* addr_remote, tipsec_port_t port_uc, tipsec_port_t port_us) { tipsec_context_xp_t* ctx_xp = TIPSEC_CONTEXT_XP(ctx); int ret = -1; if(!ctx_xp){ ret = -1; goto bail; } if(!addr_local || !port_uc || !port_us){ ret = -2; goto bail; } if(!TIPSEC_CONTEXT(ctx_xp)->initialized){ TSK_DEBUG_ERROR("IPSec engine not initialized."); ret = -3; goto bail; } if(TIPSEC_CONTEXT(ctx_xp)->state != state_initial){ TSK_DEBUG_ERROR("IPSec context is in the wrong state."); ret = -4; goto bail; } /* Set local/remote IPv6 addresses*/ tsk_strupdate((char**)&TIPSEC_CONTEXT(ctx_xp)->addr_local, addr_local); tsk_strupdate((char**)&TIPSEC_CONTEXT(ctx_xp)->addr_remote, addr_remote); /* Set ports */ TIPSEC_CONTEXT(ctx_xp)->port_uc = port_uc; TIPSEC_CONTEXT(ctx_xp)->port_us = port_us; /* Set SPIs */ TIPSEC_CONTEXT(ctx_xp)->spi_uc = (rand() ^ rand()); TIPSEC_CONTEXT(ctx_xp)->spi_us = (rand() ^ rand()); TIPSEC_CONTEXT(ctx_xp)->state = state_inbound; ret = 0; bail: return ret; }
int tsip_transac_init(tsip_transac_t *self, tsip_transac_type_t type, int32_t cseq_value, const char* cseq_method, const char* callid, struct tsip_transac_dst_s* dst, tsk_fsm_state_id curr, tsk_fsm_state_id term) { if(self && !self->initialized){ self->type = type; self->cseq_value = cseq_value; tsk_strupdate(&self->cseq_method, cseq_method); tsk_strupdate(&self->callid, callid); self->dst = tsk_object_ref(dst); /* FSM */ self->fsm = tsk_fsm_create(curr, term); self->initialized = tsk_true; return 0; } return -1; }
int tnet_transport_prepare(tnet_transport_t *transport) { int ret = -1; transport_context_t *context; if (!transport || !transport->context) { TSK_DEBUG_ERROR("Invalid parameter."); return -1; } else { context = transport->context; } if (transport->prepared) { TSK_DEBUG_ERROR("Transport already prepared."); return -2; } /* Prepare master */ if (!transport->master) { if ((transport->master = tnet_socket_create(transport->local_host, transport->req_local_port, transport->type))) { tsk_strupdate(&transport->local_ip, transport->master->ip); transport->bind_local_port = transport->master->port; } else { TSK_DEBUG_ERROR("Failed to create master socket"); return -3; } } /* Start listening */ if (TNET_SOCKET_TYPE_IS_STREAM(transport->master->type)) { if ((ret = tnet_sockfd_listen(transport->master->fd, WSA_MAXIMUM_WAIT_EVENTS))) { TNET_PRINT_LAST_ERROR("listen have failed."); goto bail; } } /* Add the master socket to the context. */ // don't take ownership: will be closed by the dctor() when refCount==0 // otherwise will be closed twice: dctor() and removeSocket() if ((ret = addSocket(transport->master->fd, transport->master->type, transport, tsk_false, tsk_false, tsk_null))) { TSK_DEBUG_ERROR("Failed to add master socket"); goto bail; } /* set events on master socket */ if ((ret = WSAEventSelect(transport->master->fd, context->events[context->count - 1], FD_ALL_EVENTS) == SOCKET_ERROR)) { TNET_PRINT_LAST_ERROR("WSAEventSelect have failed."); goto bail; } transport->prepared = tsk_true; bail: return ret; }
/**@ingroup tnet_nat_group * * Sets the address of the STUN/TURN server. * * @param [in,out] p_self The NAT context. * @param [in,out] pc_server_address The address of server. * * @return Zero if succeed and non zero error code otherwise. **/ int tnet_nat_set_server_address(struct tnet_nat_ctx_s* p_self, const char* pc_server_address) { if (!p_self) { TSK_DEBUG_ERROR("Invalid parameter"); return -1; } tsk_strupdate(&(p_self->server_address), pc_server_address); return 0; }
int tsip_challenge_update(tsip_challenge_t *self, const char* scheme, const char* realm, const char* nonce, const char* opaque, const char* algorithm, const char* qop) { if(self){ int noncechanged = !tsk_striequals(self->nonce, nonce); tsk_strupdate(&self->scheme, scheme); tsk_strupdate(&self->realm, realm); tsk_strupdate(&self->nonce, nonce); tsk_strupdate(&self->opaque, opaque); tsk_strupdate(&self->algorithm, algorithm); if(qop){ self->qop = tsk_strcontains(qop, tsk_strlen(qop), "auth-int") ? "auth-int" : (tsk_strcontains(qop, tsk_strlen(qop), "auth") ? "auth" : tsk_null); } if(noncechanged && self->qop){ tsip_challenge_reset_cnonce(self); } return 0; } return -1; }
/**@ingroup txcap_stack_group * Creates new XCAP stack. * @param callback Poiner to the callback function to call when new messages come to the transport layer. * Can be set to Null if you don't want to be alerted. * @param xui user's id as per RFC 4825 subclause 4. Also used to fill @b "X-3GPP-Intended-Identity" header. * This paramter is mandatory and must not be null. If for any reason you'd like to update the user's id, then use @ref TXCAP_STACK_SET_XUI(). * @param password user's password used to authenticate to the XDMS. * This parameter is not mandatory. If for any reason you'd like to update the password, then use @ref TXCAP_STACK_SET_PASSWORD(). * @param xcap_root xcap-root URI as per RFC 4825 subclause 6.1, used to build all request-uris. * This parameter is not mandatory and must be a valid HTPP/HTTPS URL. * @param ... User configuration. You must use @a TXCAP_STACK_SET_*() macros to set these options. * The list of options must always end with @ref TXCAP_STACK_SET_NULL() even if these is no option to pass to the stack. * @retval A Pointer to the newly created stack if succeed and @a Null otherwise. * A stack is a well-defined object. * * @code int test_stack_callback(const thttp_event_t *httpevent); txcap_stack_handle_t* stack = txcap_stack_create(test_stack_callback, "sip:[email protected]", "mysecret", "http://doubango.org:8080/services", // stack-level options TXCAP_STACK_SET_OPTION(TXCAP_STACK_OPTION_TIMEOUT, "6000"), // stack-level headers TXCAP_STACK_SET_HEADER("Connection", "Keep-Alive"), TXCAP_STACK_SET_HEADER("User-Agent", "XDM-client/OMA1.1"), TXCAP_STACK_SET_HEADER("X-3GPP-Intended-Identity", XUI), TXCAP_STACK_SET_NULL()); * @endcode * * @sa @ref txcap_stack_set */ txcap_stack_handle_t* txcap_stack_create(thttp_stack_callback_f callback, const char* xui, const char* password, const char* xcap_root, ...) { txcap_stack_t* ret = tsk_null; if(!xui || !xcap_root){ TSK_DEBUG_ERROR("Both xui and xcap_root are mandatory and should be non-null"); goto bail; } /* check url validity */ if(!thttp_url_isvalid(xcap_root)){ TSK_DEBUG_ERROR("%s is not a valid HTTP/HTTPS url", xcap_root); goto bail; } if(!(ret = tsk_object_new(txcap_stack_def_t, callback, xui, password, xcap_root))){ TSK_DEBUG_FATAL("Failed to create the XCAP stack"); goto bail; } else{ /* set parameters */ va_list ap; va_start(ap, xcap_root); __txcap_stack_set(ret, &ap); va_end(ap); /* credendials */ tsk_strupdate(&ret->xui, xui); tsk_strupdate(&ret->password, password); if(ret->http_session){ thttp_session_set(ret->http_session, THTTP_SESSION_SET_CRED(ret->xui, ret->password), THTTP_SESSION_SET_NULL()); } } bail: return ret; }
int update_param(const char* pname, const char* pvalue) { if(ctx->params && pname){ const tsk_param_t* param; if((param = tsk_params_get_param_by_name(ctx->params, pname))){ tsk_strupdate(&TSK_PARAM(param)->value, pvalue); return 0; } else{ TSK_DEBUG_INFO("[%s] parameter does not exist", pname); } } else{ TSK_DEBUG_ERROR("Invalid parameter"); } return -1; }
/**@ingroup tsk_params_group * Adds a parameter to the list of parameters. If the parameter already exist(case-insensitive), then it's value will be updated. * @param self The destination list. * @param name The name of the parameter to add. * @param value The value of the parameter to add. * @retval Zero if succeed and -1 otherwise. */ int tsk_params_add_param(tsk_params_L_t **self, const char* name, const char* value) { tsk_param_t *param; if(!self || !name) { TSK_DEBUG_ERROR("Invalid parameter"); return -1; } if(!*self){ *self = tsk_list_create(); } if((param = (tsk_param_t*)tsk_params_get_param_by_name(*self, name))){ tsk_strupdate(¶m->value, value); /* Already exist ==> update the value. */ } else{ param = tsk_param_create(name, value); tsk_list_push_back_data(*self, (void**)¶m); } return 0; }
/** * Starts the client transaction. * * @param [in,out] self The client transaction to start. * @param [in,out] request The SIP/IMS request to send. * * @return Zero if succeed and non-zero error code otherwise. **/ int tsip_transac_nict_start(tsip_transac_nict_t *self, const tsip_request_t* request) { int ret = -1; if(self && request && !TSIP_TRANSAC(self)->running){ /* Add branch to the new client transaction * - CANCEL will have the same Via and Contact headers as the request it cancel * - Transac will use request branch if exit (e.g. when request received over websocket) */ if((request->firstVia && !tsk_strnullORempty(request->firstVia->branch))){ tsk_strupdate(&TSIP_TRANSAC(self)->branch, (request->firstVia ? request->firstVia->branch : "doubango")); } else if((TSIP_TRANSAC(self)->branch = tsk_strdup(TSIP_TRANSAC_MAGIC_COOKIE))){ tsk_istr_t branch; tsk_strrandom(&branch); tsk_strcat_2(&(TSIP_TRANSAC(self)->branch), "-%s", branch); } TSIP_TRANSAC(self)->running = tsk_true; self->request = tsk_object_ref((void*)request); ret = tsip_transac_fsm_act(TSIP_TRANSAC(self), _fsm_action_send, tsk_null); } return ret; }
/** internal fuction used to config a SIP action */ int _tsip_action_set(tsip_action_handle_t* self, va_list* app) { tsip_action_param_type_t curr; tsip_action_t* action = self; if(!action){ /* Nothing to do */ return 0; } while((curr = va_arg(*app, tsip_action_param_type_t)) != aptype_null){ switch(curr){ case aptype_header: { /* (const char*)NAME_STR, (const char*)VALUE_STR */ const char* name = va_arg(*app, const char *); const char* value = va_arg(*app, const char *); tsk_params_add_param(&action->headers, name, value); break; } case aptype_config: { /* (const tsip_action_handle_t*)ACTION_CONFIG_HANDLE */ const tsip_action_t* handle = va_arg(*app, const tsip_action_handle_t *); if(handle && handle->type == tsip_atype_config){ /* Copy headers */ if(!TSK_LIST_IS_EMPTY(handle->headers)){ tsk_list_pushback_list(action->headers, handle->headers); } /* Copy payload */ if(handle->payload && handle->payload->data && handle->payload->size){ TSK_OBJECT_SAFE_FREE(action->payload); action->payload = tsk_buffer_create(handle->payload->data, handle->payload->size); } /* Copy resp line */ action->line_resp.code = handle->line_resp.code; tsk_strupdate(&action->line_resp.phrase, handle->line_resp.phrase); /* Copy media params */ if(!TSK_LIST_IS_EMPTY(handle->media.params)){ if(!action->media.params){ action->media.params = tmedia_params_create(); } tsk_list_pushback_list(action->media.params, handle->media.params); } } else if(handle){ /* Only invalid type should cause error */ TSK_DEBUG_ERROR("Invalid action configuration handle."); return -2; } break; } case aptype_payload: { /* (const void*)PAY_PTR, (tsk_size_t)PAY_SIZE */ const void* payload = va_arg(*app, const void *); tsk_size_t size = va_arg(*app, tsk_size_t); if(payload && size){ TSK_OBJECT_SAFE_FREE(action->payload); action->payload = tsk_buffer_create(payload, size); } break; } case aptype_resp_line: { /* (int32_t)CODE_INT, (const char*)PHRASE_STR */ int32_t code = va_arg(*app, int32_t); const char* phrase = va_arg(*app, const void *); action->line_resp.code = (short)code; tsk_strupdate(&action->line_resp.phrase, phrase); break; } case aptype_media: { /* ... */ tmedia_params_L_t* params; if((params = tmedia_params_create_2(app))){ if(action->media.params){ tsk_list_pushback_list(action->media.params, params); } else{ action->media.params = tsk_object_ref(params); } TSK_OBJECT_SAFE_FREE(params); } break; } default: { /* va_list will be unsafe ==> exit */ TSK_DEBUG_ERROR("NOT SUPPORTED."); return -3; } } /* switch */ } /* while */ return 0; }
int tnet_transport_tls_set_certs(tnet_transport_handle_t *handle, const char* ca, const char* pbk, const char* pvk, tsk_bool_t verify) { tnet_transport_t *transport = handle; static const char* ssl_password = tsk_null; if(!transport){ TSK_DEBUG_ERROR("Invalid parameter"); return -1; } tsk_strupdate(&transport->tls.ca, ca); tsk_strupdate(&transport->tls.pvk, pvk); tsk_strupdate(&transport->tls.pbk, pbk); transport->tls.verify = verify; #if HAVE_OPENSSL { int32_t i, ret; SSL_CTX* contexts[3] = { tsk_null }; /* init DTLS/TLS contexts */ if((ret = _tnet_transport_ssl_init(transport))){ return ret; } if(transport->tls.enabled){ contexts[0] = transport->tls.ctx_client; contexts[1] = transport->tls.ctx_server; } if(transport->dtls.enabled){ contexts[2] = transport->dtls.ctx; /* Reset fingerprints */ memset(transport->dtls.fingerprints, 0, sizeof(transport->dtls.fingerprints)); } for(i = 0; i < sizeof(contexts)/sizeof(contexts[0]); ++i){ if(!contexts[i]){ continue; } SSL_CTX_set_verify(contexts[i], transport->tls.verify ? (SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT) : SSL_VERIFY_NONE, tsk_null); if(!tsk_strnullORempty(transport->tls.pbk) || !tsk_strnullORempty(transport->tls.pvk) || !tsk_strnullORempty(transport->tls.ca)){ /* Sets Public key (cert) */ if(!tsk_strnullORempty(transport->tls.pbk) && (ret = SSL_CTX_use_certificate_file(contexts[i], transport->tls.pbk, SSL_FILETYPE_PEM)) != 1) { TSK_DEBUG_ERROR("SSL_CTX_use_certificate_file failed [%d,%s]", ret, ERR_error_string(ERR_get_error(), tsk_null)); return -3; } /*Sets the password of the private key*/ if(!tsk_strnullORempty(ssl_password)){ SSL_CTX_set_default_passwd_cb_userdata(contexts[i], (void*)ssl_password); } /* Sets Private key (cert) */ if (!tsk_strnullORempty(transport->tls.pvk) && (ret = SSL_CTX_use_PrivateKey_file(contexts[i], transport->tls.pvk, SSL_FILETYPE_PEM)) != 1) { TSK_DEBUG_ERROR("SSL_CTX_use_PrivateKey_file failed [%d,%s]", ret, ERR_error_string(ERR_get_error(), tsk_null)); return -4; } /* Checks private key */ if(!tsk_strnullORempty(transport->tls.pvk) && SSL_CTX_check_private_key(contexts[i]) == 0) { TSK_DEBUG_ERROR("SSL_CTX_check_private_key failed [%d,%s]", ret, ERR_error_string(ERR_get_error(), tsk_null)); return -5; } /* Sets trusted CAs and CA file */ if(!tsk_strnullORempty(transport->tls.ca) && (ret = SSL_CTX_load_verify_locations(contexts[i], transport->tls.ca, /*tlsdir_cas*/tsk_null)) != 1) { TSK_DEBUG_ERROR("SSL_CTX_load_verify_locations failed [%d, %s]", ret, ERR_error_string(ERR_get_error(), tsk_null)); return -5; } } } } #endif /* HAVE_OPENSSL */ return 0; }
// @param str e.g. "1 1 udp 1 192.168.196.1 57806 typ host name video_rtcp network_name {0C0137CC-DB78-46B6-9B6C-7E097FFA79FE} username StFEVThMK2DHThkv password qkhKUDr4WqKRwZTo generation 0" tnet_ice_candidate_t* tnet_ice_candidate_parse(const char* str) { char *v, *copy; int32_t k; tnet_ice_candidate_t* candidate; if(tsk_strnullORempty(str)){ TSK_DEBUG_ERROR("Invalid parameter"); return tsk_null; } if(!(candidate = tsk_object_new(&tnet_ice_candidate_def_s))){ TSK_DEBUG_ERROR("Failed to create candidate"); return tsk_null; } k = 0; copy = tsk_strdup(str); v = strtok(copy, " "); while(v){ switch(k){ case 0: { memcpy(candidate->foundation, v, TSK_MIN(tsk_strlen(v), sizeof(candidate->foundation))); break; } case 1: { candidate->comp_id = atoi(v); break; } case 2: { candidate->transport_str = tsk_strdup(v); break; } case 3: { candidate->priority = atoi(v); break; } case 4: { memcpy(candidate->connection_addr, v, TSK_MIN(tsk_strlen(v), sizeof(candidate->connection_addr))); break; } case 5: { tnet_family_t family; candidate->port = atoi(v); family = tnet_get_family(candidate->connection_addr, candidate->port); candidate->transport_e = _tnet_ice_candidate_get_transport_type((family == AF_INET6), candidate->transport_str); break; } case 6: { v = strtok(tsk_null, " "); tsk_strupdate(&candidate->cand_type_str, v); candidate->type_e = _tnet_ice_candtype_get_transport_type(v); break; } default: { const char* name = v; const char* value = (v = strtok(tsk_null, " ")); tsk_param_t* param = tsk_param_create(name, value); if(param){ tsk_list_push_back_data(candidate->extension_att_list, (void**)¶m); } break; } } ++k; v = strtok(tsk_null, " "); } if(k < 6){ TSK_DEBUG_ERROR("Failed to parse: %s", str); TSK_OBJECT_SAFE_FREE(candidate); } TSK_FREE(copy); return candidate; }
/* Started -> (oINVITE) -> Outgoing */ int c0000_Started_2_Outgoing_X_oINVITE(va_list *app) { int ret; tsip_dialog_invite_t *self; const tsip_action_t* action; self = va_arg(*app, tsip_dialog_invite_t *); va_arg(*app, const tsip_message_t *); action = va_arg(*app, const tsip_action_t *); /* This is the first FSM transaction when you try to make an audio/video/msrp call */ if(!self->msession_mgr){ int32_t transport_idx = TSIP_DIALOG_GET_STACK(self)->network.transport_idx_default; self->msession_mgr = tmedia_session_mgr_create(action ? action->media.type : tmedia_all, TSIP_DIALOG_GET_STACK(self)->network.local_ip[transport_idx], TNET_SOCKET_TYPE_IS_IPV6(TSIP_DIALOG_GET_STACK(self)->network.proxy_cscf_type[transport_idx]), tsk_true); if(TSIP_DIALOG_GET_STACK(self)->natt.ctx){ ret = tmedia_session_mgr_set_natt_ctx(self->msession_mgr, TSIP_DIALOG_GET_STACK(self)->natt.ctx, TSIP_DIALOG_GET_STACK(self)->network.aor.ip[transport_idx]); } ret = tmedia_session_mgr_set_ice_ctx(self->msession_mgr, self->ice.ctx_audio, self->ice.ctx_video); ret = tsip_dialog_invite_msession_configure(self); } /* We are the client */ self->is_client = tsk_true; /* Whether it's a client dialog for call transfer */ self->is_transf = (TSIP_DIALOG_GET_SS(self)->id_parent != TSIP_SSESSION_INVALID_ID); /* Get Media type from the action */ TSIP_DIALOG_GET_SS(self)->media.type = action->media.type; /* Appy media params received from the user */ if(!TSK_LIST_IS_EMPTY(action->media.params)){ tmedia_session_mgr_set_3(self->msession_mgr, action->media.params); } /* RFC 4028 - 7.1. Generating an Initial Session Refresh Request A UAC MAY include a Session-Expires header field in an initial session refresh request if it wants a session timer applied to the session. The value of this header field indicates the session interval desired by the UAC. If a Min-SE header is included in the initial session refresh request, the value of the Session-Expires MUST be greater than or equal to the value in Min-SE. The UAC MAY include the refresher parameter with value 'uac' if it wants to perform the refreshes. However, it is RECOMMENDED that the parameter be omitted so that it can be selected by the negotiation mechanisms described below. */ if(TSIP_DIALOG_GET_SS(self)->media.timers.timeout){ self->stimers.timer.timeout = TSIP_DIALOG_GET_SS(self)->media.timers.timeout; tsk_strupdate(&self->stimers.refresher, TSIP_DIALOG_GET_SS(self)->media.timers.refresher); self->stimers.is_refresher = tsk_striequals(self->stimers.refresher, "uac"); self->supported.timer = tsk_true; } /* QoS * One Voice Profile - 5.4.1 SIP Precondition Considerations * The UE shall use the Supported header, and not the Require header, to indicate the support of precondition in * accordance with Section 5.1.3.1 of 3GPP TS 24.229. */ self->qos.type = TSIP_DIALOG_GET_SS(self)->media.qos.type; self->qos.strength = TSIP_DIALOG_GET_SS(self)->media.qos.strength; tmedia_session_mgr_set_qos(self->msession_mgr, self->qos.type, self->qos.strength); self->supported.precondition = (self->qos.strength == tmedia_qos_strength_optional); self->required.precondition = (self->qos.strength == tmedia_qos_strength_mandatory); /* send the request */ ret = send_INVITE(self, tsk_false); /* alert the user */ TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_connecting, "Dialog connecting"); return ret; }
int tdav_session_msrp_set_ro(tmedia_session_t* self, const tsdp_header_M_t* m) { tdav_session_msrp_t* msrp; const tsdp_header_A_t* A; tsk_bool_t answer; TSK_DEBUG_INFO("tdav_session_msrp_set_ro"); if(!self || !m){ TSK_DEBUG_ERROR("Invalid parameter"); return -1; } msrp = (tdav_session_msrp_t*)self; // answer or initial offer? answer = (self->M.lo != tsk_null); /* update remote offer */ TSK_OBJECT_SAFE_FREE(self->M.ro); self->M.ro = tsk_object_ref((void*)m); if(self->M.lo){ if((match_offer(msrp, m))){ } else{ TSK_DEBUG_ERROR("MSRP offer doesn't match"); return -1; } /* QoS */ if(self->qos){ tmedia_qos_tline_t* ro_tline; if(self->M.ro && (ro_tline = tmedia_qos_tline_from_sdp(self->M.ro))){ tmedia_qos_tline_set_ro(self->qos, ro_tline); TSK_OBJECT_SAFE_FREE(ro_tline); } } } /* To-Path */ if((A = tsdp_header_M_findA(m, "path"))){ tmsrp_uri_t* uri; if((uri = tmsrp_uri_parse(A->value, tsk_strlen(A->value)))){ TSK_OBJECT_SAFE_FREE(msrp->config->To_Path); msrp->config->To_Path = tmsrp_header_To_Path_create(uri); TSK_OBJECT_SAFE_FREE(uri); } } // OMA-TS-SIMPLE_IM-V1_0-20080903-C - 5.8.1 Negotiate direction of the MSRP connection setup if((A = tsdp_header_M_findA(m, "setup"))){ tdav_msrp_setup_t setup = setup_from_string(A->value); switch(setup){ case msrp_setup_actpass: case msrp_setup_passive: msrp->setup = msrp_setup_active; break; case msrp_setup_active: msrp->setup = msrp_setup_passive; break; } } /* Neg parameters */ init_neg_types(msrp, m); /* [OMA-TS-SIMPLE_IM-V1_0-20100322-C] - 5.8.2 Support of Application Level Gateway */ /* get connection associated to this media line * If the connnection is global, then the manager will call tdav_session_audio_set() */ if(m->C && m->C->addr && !msrp->remote_ip){ tsk_strupdate(&msrp->remote_ip, m->C->addr); msrp->useIPv6 = tsk_striequals(m->C->addrtype, "IP6"); } /* set remote port */ msrp->remote_port = m->port; return 0; }
int tnet_transport_prepare(tnet_transport_t *transport) { int ret = -1; transport_context_t *context; tnet_fd_t pipes[2]; TSK_DEBUG_INFO("tnet_transport_prepare()"); if(!transport || !transport->context) { TSK_DEBUG_ERROR("Invalid parameter."); return -1; } else { context = transport->context; } if(transport->prepared) { TSK_DEBUG_ERROR("Transport already prepared."); return -2; } /* Prepare master */ if(!transport->master) { if((transport->master = tnet_socket_create(transport->local_host, transport->req_local_port, transport->type))) { tsk_strupdate(&transport->local_ip, transport->master->ip); transport->bind_local_port = transport->master->port; } else { TSK_DEBUG_ERROR("Failed to create master socket"); return -3; } } /* Start listening */ if(TNET_SOCKET_TYPE_IS_STREAM(transport->master->type)) { if((ret = tnet_sockfd_listen(transport->master->fd, TNET_MAX_FDS))) { TNET_PRINT_LAST_ERROR("listen have failed."); goto bail; } } /* Create and add pipes to the fd_set */ if((ret = pipe(pipes))) { TNET_PRINT_LAST_ERROR("Failed to create new pipes."); goto bail; } /* set both R and W sides */ context->pipeR = pipes[0]; context->pipeW = pipes[1]; /* add R side */ TSK_DEBUG_INFO("pipeR fd=%d, pipeW=%d", context->pipeR, context->pipeW); if((ret = addSocket(context->pipeR, transport->master->type, transport, tsk_true, tsk_false, tsk_null))) { goto bail; } /* Add the master socket to the context. */ TSK_DEBUG_INFO("master fd=%d", transport->master->fd); // don't take ownership: will be closed by the dctor() when refCount==0 // otherwise will be closed twice: dctor() and removeSocket() if((ret = addSocket(transport->master->fd, transport->master->type, transport, tsk_false, tsk_false, tsk_null))) { TSK_DEBUG_ERROR("Failed to add master socket"); goto bail; } transport->prepared = tsk_true; bail: return ret; }
/** Internal function used to set options. */ int __txcap_stack_set(txcap_stack_t* self, va_list *app) { txcap_stack_param_type_t curr; tsk_bool_t cred_updated = tsk_false; if(!self || !self->http_session){ return -1; } while((curr = va_arg(*app, txcap_stack_param_type_t)) != xcapp_null){ switch(curr){ case xcapp_option: { /* (txcap_stack_option_t)ID_ENUM, (const char*)VALUE_STR */ txcap_stack_option_t ID_ENUM = va_arg(*app, txcap_stack_option_t); const char* VALUE_STR = va_arg(*app, const char*); switch(ID_ENUM){ case TXCAP_STACK_OPTION_ROOT: { tsk_strupdate(&self->xcap_root, VALUE_STR); break; } /* PASSWORD and XUI are not used as options in the HTTP/HTTPS stack */ case TXCAP_STACK_OPTION_PASSWORD: { tsk_strupdate(&self->password, VALUE_STR); cred_updated = tsk_true; break; } case TXCAP_STACK_OPTION_XUI: { tsk_strupdate(&self->xui, VALUE_STR); cred_updated = tsk_true; break; } case TXCAP_STACK_OPTION_LOCAL_IP: { thttp_stack_set(self->http_stack, THTTP_STACK_SET_LOCAL_IP(VALUE_STR), THTTP_STACK_SET_NULL()); break; } case TXCAP_STACK_OPTION_LOCAL_PORT: { int port = atoi(VALUE_STR); thttp_stack_set(self->http_stack, THTTP_STACK_SET_LOCAL_PORT(port), THTTP_STACK_SET_NULL()); break; } default: { /* HTTP Options: MUST be changed to valid HTTP option enum */ switch(ID_ENUM){ case TXCAP_STACK_OPTION_TIMEOUT: tsk_options_add_option(&((thttp_session_t*)self->http_session)->options, THTTP_SESSION_OPTION_TIMEOUT, VALUE_STR); break; case TXCAP_STACK_OPTION_TTL: tsk_options_add_option(&((thttp_session_t*)self->http_session)->options, THTTP_SESSION_OPTION_TTL, VALUE_STR); break; default: TSK_DEBUG_WARN("%d is an invalid XCAP option", ID_ENUM); break; } break; } } break; } case xcapp_header: { /* (const char*)NAME_STR, (const char*)VALUE_STR */ const char* NAME_STR = va_arg(*app, const char*); const char* VALUE_STR = va_arg(*app, const char*); if(VALUE_STR == (const char*)-1){ tsk_params_remove_param(((thttp_session_t*)self->http_session)->headers, NAME_STR); } else{ tsk_params_add_param(&((thttp_session_t*)self->http_session)->headers, NAME_STR, VALUE_STR); } break; } case xcapp_userdata: { /* (const void*)CTX_PTR */ const void* CTX_PTR = va_arg(*app, const void*); ((thttp_session_t*)self->http_session)->userdata = CTX_PTR; break; } case xcapp_auid: { /* (const char*)ID_STR, (const char*)MIME_TYPE_STR, (const char*)NS_STR, (const char*)DOC_NAME_STR, (tsk_bool_t)IS_GLOBAL_BOOL */ const char* ID_STR = va_arg(*app, const char*); const char* MIME_TYPE_STR = va_arg(*app, const char*); const char* NS_STR = va_arg(*app, const char*); const char* DOC_NAME_STR = va_arg(*app, const char*); tsk_bool_t IS_GLOBAL_BOOL = va_arg(*app, tsk_bool_t); if(txcap_auid_register(self->auids, ID_STR, MIME_TYPE_STR, NS_STR, DOC_NAME_STR, IS_GLOBAL_BOOL)){ // do nothing } break; } default: { TSK_DEBUG_ERROR("NOT SUPPORTED."); goto bail; } } /* switch */ } /* while */ if(cred_updated && self->http_session){ /* credentials */ thttp_session_set(self->http_session, THTTP_SESSION_SET_CRED(self->xui, self->password), THTTP_SESSION_SET_NULL()); } return 0; bail: return -2; }
int tnet_transport_prepare(tnet_transport_t *transport) { int ret = -1; transport_context_t *context; tnet_fd_t pipes[2]; if(!transport || !transport->context){ TSK_DEBUG_ERROR("Invalid parameter."); return -1; } else{ context = transport->context; } if(transport->prepared){ TSK_DEBUG_ERROR("Transport already prepared."); return -2; } /* Prepare master */ if(!transport->master){ if((transport->master = tnet_socket_create(transport->local_host, transport->req_local_port, transport->type))){ tsk_strupdate(&transport->local_ip, transport->master->ip); transport->bind_local_port = transport->master->port; } else{ TSK_DEBUG_ERROR("Failed to create master socket"); return -3; } } /* set events */ context->events = TNET_POLLIN | TNET_POLLNVAL | TNET_POLLERR; if(TNET_SOCKET_TYPE_IS_STREAM(transport->master->type)){ context->events |= TNET_POLLOUT // emulate WinSock2 FD_CONNECT event //#if !defined(ANDROID) // | TNET_POLLHUP /* FIXME: always present */ //#endif ; } /* Start listening */ if(TNET_SOCKET_TYPE_IS_STREAM(transport->master->type)){ if((ret = tnet_sockfd_listen(transport->master->fd, TNET_MAX_FDS))){ TNET_PRINT_LAST_ERROR("listen have failed."); goto bail; } } /* Create and add pipes to the fd_set */ if((ret = pipe(pipes))){ TNET_PRINT_LAST_ERROR("Failed to create new pipes."); goto bail; } /* set both R and W sides */ context->pipeR = pipes[0]; context->pipeW = pipes[1]; /* add R side */ TSK_DEBUG_INFO("pipeR fd=%d", context->pipeR); if((ret = addSocket(context->pipeR, transport->master->type, transport, tsk_true, tsk_false))){ goto bail; } /* Add the master socket to the context. */ TSK_DEBUG_INFO("master fd=%d", transport->master->fd); // don't take ownership: will be closed by the dctor() // otherwise will be closed twice: dctor() and removeSocket() if((ret = addSocket(transport->master->fd, transport->master->type, transport, tsk_false, tsk_false))){ TSK_DEBUG_ERROR("Failed to add master socket"); goto bail; } transport->prepared = tsk_true; bail: return ret; }
int tdav_session_msrp_set(tmedia_session_t* self, const tmedia_param_t* param) { int ret = 0; tdav_session_msrp_t* msrp; if(!self){ TSK_DEBUG_ERROR("Invalid parameter"); return -1; } TSK_DEBUG_INFO("tdav_session_msrp_set"); msrp = (tdav_session_msrp_t*)self; if(param->value_type == tmedia_pvt_pchar){ if(tsk_striequals(param->key, "remote-ip")){ // only if no ip associated to the "m=" line if(param->value && !msrp->remote_ip){ msrp->remote_ip = tsk_strdup(param->value); } } else if(tsk_striequals(param->key, "local-ip")){ tsk_strupdate(&msrp->local_ip, param->value); } else if(tsk_striequals(param->key, "local-ipver")){ msrp->useIPv6 = tsk_striequals(param->value, "ipv6"); } else if(tsk_striequals(param->key, "accept-types")){ tsk_strupdate(&msrp->accept_types, param->value); } else if(tsk_striequals(param->key, "accept-wrapped-types")){ tsk_strupdate(&msrp->accept_w_types, param->value); } /* Configuration */ else if(tsk_striequals(param->key, "Failure-Report")){ msrp->config->Failure_Report = tsk_striequals(param->value, "yes"); } else if(tsk_striequals(param->key, "Success-Report")){ msrp->config->Success_Report = tsk_striequals(param->value, "yes"); } /* File Transfer */ else if(tsk_striequals(param->key, "file-path") && !tsk_strnullORempty((const char*)param->value)){ tsk_strupdate(&msrp->file.path, param->value); } else if(tsk_striequals(param->key, "file-selector")){ tsk_strupdate(&msrp->file.selector, param->value); } else if(tsk_striequals(param->key, "file-disposition")){ tsk_strupdate(&msrp->file.disposition, param->value); } else if(tsk_striequals(param->key, "file-date")){ tsk_strupdate(&msrp->file.date, param->value); } else if(tsk_striequals(param->key, "file-icon")){ tsk_strupdate(&msrp->file.icon, param->value); } else if(tsk_striequals(param->key, "file-transfer-id")){ tsk_strupdate(&msrp->file.transfer_id, param->value); } } else if(param->value_type == tmedia_pvt_pobject){ if(tsk_striequals(param->key, "natt-ctx")){ TSK_OBJECT_SAFE_FREE(msrp->natt_ctx); msrp->natt_ctx = tsk_object_ref(param->value); } } else if(param->value_type == tmedia_pvt_int64 || param->value_type == tmedia_pvt_int32){ if(tsk_striequals(param->key, "chunck-duration")){ msrp->chunck_duration = TSK_TO_UINT32((uint8_t*)param->value); if(msrp->sender){ msrp->sender->chunck_duration = msrp->chunck_duration; } } } return ret; }