注册增加消息头

在saveNewAccount()中;

添加自定义消息头

LinphoneProxyConfig prxCfg = lc.createProxyConfig(identityAddr.asString(), proxyAddr.asStringUriOnly(), route, tempEnabled);
prxCfg.setCustomHeader("key","hello key");
prxCfg.setCustomHeader("key2","hello key2");

setCustomHeader(); 在linphonecore_jni.cc line5195

JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneProxyConfigImpl_setCustomHeader(JNIEnv *env, jobject thiz, jlong prt, jstring jname, jstring jvalue) {const char *name = GetStringUTFChars(env, jname);const char *value = GetStringUTFChars(env, jvalue);linphone_proxy_config_set_custom_header((LinphoneProxyConfig*) prt, name, value);ReleaseStringUTFChars(env, jname, name);ReleaseStringUTFChars(env, jvalue, value);
}

linphone_proxy_config_set_custom_header(cfg,name,value);在proxy.c line960

void linphone_proxy_config_set_custom_header(LinphoneProxyConfig *cfg, const char *header_name, const char *header_value){cfg->sent_headers=sal_custom_header_append(cfg->sent_headers, header_name, header_value);cfg->register_changed = TRUE;
}

sal_custom_header_append();在sal_impl.c line970

SalCustomHeader *sal_custom_header_append(SalCustomHeader *ch, const char *name, const char *value){belle_sip_message_t *msg=(belle_sip_message_t*)ch;belle_sip_header_t *h;if (msg==NULL){msg=(belle_sip_message_t*)belle_sip_request_new();belle_sip_object_ref(msg);}h=belle_sip_header_create(name,value);if (h==NULL){belle_sip_error("Fail to parse custom header.");return (SalCustomHeader*)msg;}belle_sip_message_add_header(msg,h);return (SalCustomHeader*)msg;
}

其中包含belle_sip_header_create(name,value) 在belle_sip_headers_impl.c line110
和belle_sip_message_add_header(msg,h)在message.c line 178

belle_sip_header_t* belle_sip_header_create(const char* name, const char* value) {return belle_header_create(name,value,PROTO_SIP);
}

belle_header_create(name,value,PROTO_SIP) belle_sip_header_impl.c line 88

static belle_sip_header_t* belle_header_create(const char* name,const char* value,int protocol) {size_t i;belle_sip_header_t* ret;size_t elements =sizeof(header_table)/sizeof(struct header_name_func_pair);if (!name || name[0]=='\0') {belle_sip_error("Cannot create header without name");return NULL;}for(i=0;i<elements;i++) {if ((header_table[i].protocol & protocol) && strcasecmp(header_table[i].name,name)==0) {char* raw = belle_sip_strdup_printf("%s:%s",name,value);ret=header_table[i].func(raw);belle_sip_free(raw);return ret;}}/*not a known header*/return BELLE_SIP_HEADER(belle_sip_header_extension_create(name,value));
}

其中 header_table[]是一个定义好的数组,形式如下:

static struct header_name_func_pair  header_table[] = {{PROTO_SIP,         "m",                     (header_parse_func)belle_sip_header_contact_parse},{PROTO_SIP,         BELLE_SIP_CONTACT,          (header_parse_func)belle_sip_header_contact_parse},{PROTO_SIP,         "f",                     (header_parse_func)belle_sip_header_from_parse}
......
}

通过for循环,检查传入的protocol和name是否与table中预定义的一致,如果一致,将name与value组合,作为入参调用table中的function,获取最终的header;如果name不在table定义的范围内,调用belle_sip_header_extension_create()来构建header;

belle_sip_header_extension_create(); belle_sip_headers_impl.c line 1122;

belle_sip_header_extension_t* belle_sip_header_extension_create (const char* name,const char* value) {belle_sip_header_extension_t* ext = belle_sip_header_extension_new();belle_sip_header_set_name(BELLE_SIP_HEADER(ext),name);belle_sip_header_extension_set_value(ext,value);return ext;
}

至此 自定义头的belle_sip_header_t* 的结构体构建好了
回到sal_custom_header_append函数中,第二部执行add_header;

belle_sip_message_add_header 在message.c line 178

void belle_sip_message_add_header(belle_sip_message_t *message,belle_sip_header_t* header) {char* header_string=belle_sip_object_to_string(header);belle_sip_message("belle_sip_message_add_header [%s]",header_string);headers_container_t *headers_container=get_or_create_container(message,belle_sip_header_get_name(header));headers_container->header_list=belle_sip_list_append(headers_container->header_list,belle_sip_object_ref(header));
}

其中的get_or_create_container(message,xxxx) line 163

headers_container_t * get_or_create_container(belle_sip_message_t *message, const char *header_name){// first check if already existheaders_container_t* headers_container = belle_sip_headers_container_get(message,header_name);if (headers_container == NULL) {headers_container = belle_sip_message_headers_container_new(header_name);message->header_list=belle_sip_list_append(message->header_list,headers_container);}return headers_container;
}

message有一个header_list的属性,可能以name作为键值,来存贮每一对header;
headner_container可能是这个header_list的容器;
这个函数主要从message中获取name键值的container返回;
然后在belle_sip_message_add_header中追加新的header;

回到sal_custom_header_append()内;message中加入了新的header,并返回message;
回到linphone_proxy_config_set_custom_header()内,获得的message被设置到cfg->sent_headers;

至此自定义消息头的添加结束。但是并没有真正发送sip消息给服务器;

**

注册账号
**

在java的用户注册操作如下:

lc.addProxyConfig(prxCfg);
lc.addAuthInfo(authInfo);

先看第一个lc.addProxyConfig();

jni的接口如下,在linphonecore_jni.cc line1782

extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_addProxyConfig( JNIEnv*  env,jobject  thiz,jobject jproxyCfg,jlong lc,jlong pc) {LinphoneProxyConfig* proxy = (LinphoneProxyConfig*)pc;return (jint)linphone_core_add_proxy_config((LinphoneCore*)lc,proxy);
}

真实实现在linphone_core_add_proxy_config(lc,proxy)中 proxy.c line965

int linphone_core_add_proxy_config(LinphoneCore *lc, LinphoneProxyConfig *cfg){if (!linphone_proxy_config_check(lc,cfg)) {return -1;}if (bctbx_list_find(lc->sip_conf.proxies,cfg)!=NULL){ms_warning("ProxyConfig already entered, ignored.");return 0;}lc->sip_conf.proxies=bctbx_list_append(lc->sip_conf.proxies,(void *)linphone_proxy_config_ref(cfg));linphone_proxy_config_apply(cfg,lc);return 0;
}

此处做的工作不多,只是将传入的cfg追加到lc->sip_conf.proxies列表中存储起来;
然后通过linphone_proxy_config_apply(cfg,lc)存储起来;

linphone_proxy_config_apply(cfg,lc) proxy.c line386

void linphone_proxy_config_apply(LinphoneProxyConfig *cfg,LinphoneCore *lc){cfg->lc=lc;linphone_proxy_config_done(cfg);
}

先将新的lc关联到cfg,然后进行config的保存

linphone_proxy_config_done(cfg) proxy.c line765

int linphone_proxy_config_done(LinphoneProxyConfig *cfg)
{LinphoneProxyConfigAddressComparisonResult res;if (!linphone_proxy_config_check(cfg->lc,cfg))return -1;/*check if server address has changed*/res = linphone_proxy_config_is_server_config_changed(cfg);if (res != LinphoneProxyConfigAddressEqual) {/* server config has changed, need to unregister from previous first*/if (cfg->op) {if (res == LinphoneProxyConfigAddressDifferent) {_linphone_proxy_config_unregister(cfg);}sal_op_set_user_pointer(cfg->op,NULL); /*we don't want to receive status for this un register*/sal_op_unref(cfg->op); /*but we keep refresher to handle authentication if needed*/cfg->op=NULL;}if (cfg->long_term_event) {if (res == LinphoneProxyConfigAddressDifferent) {_linphone_proxy_config_unpublish(cfg);}}cfg->commit = TRUE;}if (cfg->register_changed){cfg->commit = TRUE;cfg->register_changed = FALSE;}if (cfg->commit){linphone_proxy_config_pause_register(cfg);}if (linphone_proxy_config_compute_publish_params_hash(cfg)) {ms_message("Publish params have changed on proxy config [%p]",cfg);if (cfg->long_term_event) {if (cfg->publish) {const char * sip_etag = linphone_event_get_custom_header(cfg->long_term_event, "SIP-ETag");if (sip_etag) {if (cfg->sip_etag) ms_free(cfg->sip_etag);cfg->sip_etag = ms_strdup(sip_etag);}}/*publish is terminated*/linphone_event_terminate(cfg->long_term_event);linphone_event_unref(cfg->long_term_event);cfg->long_term_event = NULL;}if (cfg->publish) cfg->send_publish=TRUE;} else {ms_message("Publish params have not changed on proxy config [%p]",cfg);}linphone_proxy_config_write_all_to_config_file(cfg->lc);return 0;
}

首先检查cfg中的服务器地址是否发生了变化;
如果变化了,将之前存储的cfg删除掉;如果首次登陆的话,基本跳过中间的环节;

linphone_proxy_config_write_all_to_config_file(cfg->lc); proxy.c line86

void linphone_proxy_config_write_all_to_config_file(LinphoneCore *lc){bctbx_list_t *elem;int i;if (!linphone_core_ready(lc)) return;for(elem=lc->sip_conf.proxies,i=0;elem!=NULL;elem=bctbx_list_next(elem),i++){LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)elem->data;linphone_proxy_config_write_to_config_file(lc->config,cfg,i);}/*to ensure removed configs are erased:*/linphone_proxy_config_write_to_config_file(lc->config,NULL,i);lp_config_set_int(lc->config,"sip","default_proxy",linphone_core_get_default_proxy_config_index(lc));
}

首先遍历lc->sip_config.proxies,里面从存储了刚刚add进来的cfg,并逐个写入本地文件中;
for循环执行完以后,追加写入一个null。主要为了保证将原来删除掉的config擦除;

linphone_proxy_config_write_to_config_file(lc->config,cfg,i) proxy.c line1059

void linphone_proxy_config_write_to_config_file(LpConfig *config, LinphoneProxyConfig *cfg, int index)
{char key[50];ms_message("linphone_proxy_config_write_to_config_file");sprintf(key,"proxy_%i",index);lp_config_clean_section(config,key);if (cfg==NULL){return;}if (cfg->type!=NULL){lp_config_set_string(config,key,"type",cfg->type);}if (cfg->reg_proxy!=NULL){lp_config_set_string(config,key,"reg_proxy",cfg->reg_proxy);}if (cfg->reg_route!=NULL){lp_config_set_string(config,key,"reg_route",cfg->reg_route);}if (cfg->reg_identity!=NULL){lp_config_set_string(config,key,"reg_identity",cfg->reg_identity);}if (cfg->realm!=NULL){lp_config_set_string(config,key,"realm",cfg->realm);}if (cfg->contact_params!=NULL){lp_config_set_string(config,key,"contact_parameters",cfg->contact_params);}if (cfg->contact_uri_params!=NULL){lp_config_set_string(config,key,"contact_uri_parameters",cfg->contact_uri_params);}if (cfg->quality_reporting_collector!=NULL){lp_config_set_string(config,key,"quality_reporting_collector",cfg->quality_reporting_collector);}lp_config_set_int(config,key,"quality_reporting_enabled",cfg->quality_reporting_enabled);lp_config_set_int(config,key,"quality_reporting_interval",cfg->quality_reporting_interval);lp_config_set_int(config,key,"reg_expires",cfg->expires);lp_config_set_int(config,key,"reg_sendregister",cfg->reg_sendregister);lp_config_set_int(config,key,"publish",cfg->publish);lp_config_set_int(config, key, "avpf", cfg->avpf_mode);lp_config_set_int(config, key, "avpf_rr_interval", cfg->avpf_rr_interval);lp_config_set_int(config,key,"dial_escape_plus",cfg->dial_escape_plus);lp_config_set_string(config,key,"dial_prefix",cfg->dial_prefix);lp_config_set_int(config,key,"privacy",cfg->privacy);if (cfg->refkey) lp_config_set_string(config,key,"refkey",cfg->refkey);lp_config_set_int(config, key, "publish_expires", cfg->publish_expires);if (cfg->nat_policy != NULL) {lp_config_set_string(config, key, "nat_policy_ref", cfg->nat_policy->ref);linphone_nat_policy_save_to_config(cfg->nat_policy);}
}

这个函数主要是检查cfg中的各种属性,并保存对应的值;保存通过lp_config_set_string(xx)执行;

lp_config_set_string(config,key,”name”,”value”) 在lpconfig.c line643;

void lp_config_set_string(LpConfig *lpconfig,const char *section, const char *key, const char *value){LpItem *item;LpSection *sec=lp_config_find_section(lpconfig,section);if (sec!=NULL){item=lp_section_find_item(sec,key);if (item!=NULL){if (value!=NULL && value[0] != '\0')lp_item_set_value(item,value);else lp_section_remove_item(sec,item);}else{if (value!=NULL && value[0] != '\0')lp_section_add_item(sec,lp_item_new(key,value));}}else if (value!=NULL && value[0] != '\0'){sec=lp_section_new(section);lp_config_add_section(lpconfig,sec);lp_section_add_item(sec,lp_item_new(key,value));}lpconfig->modified++;
}

每个属性值以LPSection的形式存储,name为传入的section;section中列表形式存储了LPItem数据,每个LpItem以key为name;
这个函数的主要操作就是从config中找出对应的section,如果没有就new一个,然后从section中找出key对应的item,然后设置新值;
大概数据结构 lc->config->section->item;

至此lc.addProxyConfig(prxCfg);的操作结束;

**

然后再看lc.addAuthInfo(authInfo);
**

jni接口在linphonecore_jni.cc中 line 1836

extern "C" void Java_org_linphone_core_LinphoneCoreImpl_addAuthInfo(JNIEnv* env,jobject  thiz,jlong lc,jlong pc) {linphone_core_add_auth_info((LinphoneCore*)lc,(LinphoneAuthInfo*)pc);
}

真实实现在linphone_core_add_auth_info(lc,pc) authentication.c line397

void linphone_core_add_auth_info(LinphoneCore *lc, const LinphoneAuthInfo *info){ms_message("");LinphoneAuthInfo *ai;bctbx_list_t *elem;bctbx_list_t *l;int restarted_op_count=0;bool_t updating=FALSE;if (info->ha1==NULL && info->passwd==NULL){ms_warning("linphone_core_add_auth_info(): info supplied with empty password or ha1.");}/* find if we are attempting to modify an existing auth info */ai=(LinphoneAuthInfo*)linphone_core_find_auth_info(lc,info->realm,info->username,info->domain);if (ai!=NULL && ai->domain && info->domain && strcmp(ai->domain, info->domain)==0){lc->auth_info=bctbx_list_remove(lc->auth_info,ai);linphone_auth_info_destroy(ai);updating=TRUE;}lc->auth_info=bctbx_list_append(lc->auth_info,linphone_auth_info_clone(info));/* retry pending authentication operations */for(l=elem=sal_get_pending_auths(lc->sal);elem!=NULL;elem=elem->next){SalOp *op=(SalOp*)elem->data;LinphoneAuthInfo *ai;const SalAuthInfo *req_sai=sal_op_get_auth_requested(op);ai=(LinphoneAuthInfo*)_linphone_core_find_auth_info(lc,req_sai->realm,req_sai->username,req_sai->domain, FALSE);if (ai){SalAuthInfo sai;bctbx_list_t* proxy;sai.username=ai->username;sai.userid=ai->userid;sai.realm=ai->realm;sai.password=ai->passwd;sai.ha1=ai->ha1;if (ai->tls_cert && ai->tls_key) {sal_certificates_chain_parse(&sai, ai->tls_cert, SAL_CERTIFICATE_RAW_FORMAT_PEM);sal_signing_key_parse(&sai, ai->tls_key, "");} else if (ai->tls_cert_path && ai->tls_key_path) {sal_certificates_chain_parse_file(&sai, ai->tls_cert_path, SAL_CERTIFICATE_RAW_FORMAT_PEM);sal_signing_key_parse_file(&sai, ai->tls_key_path, "");}/*proxy case*/for (proxy=(bctbx_list_t*)linphone_core_get_proxy_config_list(lc);proxy!=NULL;proxy=proxy->next) {if (proxy->data == sal_op_get_user_pointer(op)) {linphone_proxy_config_set_state((LinphoneProxyConfig*)(proxy->data),LinphoneRegistrationProgress,"Authentication...");break;}}sal_op_authenticate(op,&sai);restarted_op_count++;}}if (l){ms_message("linphone_core_add_auth_info(): restarted [%i] operation(s) after %s auth info for\n""\tusername: [%s]\n""\trealm [%s]\n""\tdomain [%s]\n",restarted_op_count,updating ? "updating" : "adding",info->username ? info->username : "",info->realm ? info->realm : "",info->domain ? info->domain : "");}bctbx_list_free(l);write_auth_infos(lc);
}

首先会检查这个账号是否已经存在;在linphone_core_find_auth_info()中,在line359
如果存在这个账号的信息,先删除,linphone_auth_info_destroy();
然后将当期传入的账号信息添加到lc中
lc->auth_info = bctbx_list_append(lc->auth_info,linphone_auth_info_clone(info));
接下来的for首次登陆的时候没有执行,暂时没看;
最后调用write_auth_infos(lc)进行保存

writh_auth_infos();在authentication.c line377

static void write_auth_infos(LinphoneCore *lc){bctbx_list_t *elem;int i;if (!linphone_core_ready(lc)) return;if (!lc->sip_conf.save_auth_info) return;for(elem=lc->auth_info,i=0;elem!=NULL;elem=bctbx_list_next(elem),i++){LinphoneAuthInfo *ai=(LinphoneAuthInfo*)(elem->data);linphone_auth_info_write_config(lc->config,ai,i);}linphone_auth_info_write_config(lc->config,NULL,i); /* mark the end */
}

这里的操作与cfg的保存比较类似,遍历lc->auth_info,将每个LinphoneAuthInfo对象写入本地
linphone_auth_info_write_config(lc->config,ai,i) 在line 198

void linphone_auth_info_write_config(LpConfig *config, LinphoneAuthInfo *obj, int pos) {ms_message("linphone_auth_info_write_config");char key[50];bool_t store_ha1_passwd = lp_config_get_int(config, "sip", "store_ha1_passwd", 1);sprintf(key, "auth_info_%i", pos);lp_config_clean_section(config, key);if (obj == NULL || lp_config_get_int(config, "sip", "store_auth_info", 1) == 0) {return;}if (!obj->ha1 && obj->realm && obj->passwd && (obj->username || obj->userid) && store_ha1_passwd) {/*compute ha1 to avoid storing clear text password*/obj->ha1 = ms_malloc(33);sal_auth_compute_ha1(obj->userid ? obj->userid : obj->username, obj->realm, obj->passwd, obj->ha1);}if (obj->username != NULL) {lp_config_set_string(config, key, "username", obj->username);}if (obj->userid != NULL) {lp_config_set_string(config, key, "userid", obj->userid);}if (obj->ha1 != NULL) {lp_config_set_string(config, key, "ha1", obj->ha1);}if (obj->passwd != NULL) {if (store_ha1_passwd && obj->ha1) {/*if we have our ha1 and store_ha1_passwd set to TRUE, then drop the clear text password for security*/linphone_auth_info_set_passwd(obj, NULL);} else {/*we store clear text password only if store_ha1_passwd is FALSE AND we have an ha1 to store. Otherwise, passwd would simply be removed, which might bring major auth issue*/lp_config_set_string(config, key, "passwd", obj->passwd);}}if (obj->realm != NULL) {lp_config_set_string(config, key, "realm", obj->realm);}if (obj->domain != NULL) {lp_config_set_string(config, key, "domain", obj->domain);}if (obj->tls_cert_path != NULL) {lp_config_set_string(config, key, "client_cert_chain", obj->tls_cert_path);}if (obj->tls_key_path != NULL) {lp_config_set_string(config, key, "client_cert_key", obj->tls_key_path);}
}

至此待登陆的账号信息就保存好了,具体的登录操作是通过lc.iterate()主循环实现的;

真实的注册登录过程

linphonoe_core_iterate(lc) linphonecore.c line 2753

void linphone_core_iterate(LinphoneCore *lc){......sal_iterate(lc->sal);if (lc->msevq) ms_event_queue_pump(lc->msevq);if (lc->auto_net_state_mon) monitor_network_state(lc, current_real_time);proxy_update(lc);
/...
}

这是linphone的核心功能,在这个循环内,主要进行的操作有,接收sip消息、处理定时器、处理proxy的注册状态变化、认证重连;
关于登录的处理是通过proxy_update(lc)实现的

proxy_update(lc) 在linphonecore.c line2654

static void proxy_update(LinphoneCore *lc){//ms_message("proxy_update");bctbx_list_t *elem,*next;bctbx_list_for_each(lc->sip_conf.proxies,(void (*)(void*))&linphone_proxy_config_update);for(elem=lc->sip_conf.deleted_proxies;elem!=NULL;elem=next){LinphoneProxyConfig* cfg = (LinphoneProxyConfig*)elem->data;next=elem->next;if (ms_time(NULL) - cfg->deletion_date > 32) {lc->sip_conf.deleted_proxies =bctbx_list_erase_link(lc->sip_conf.deleted_proxies,elem);ms_message("Proxy config for [%s] is definitely removed from core.",linphone_proxy_config_get_addr(cfg));_linphone_proxy_config_release_ops(cfg);linphone_proxy_config_unref(cfg);}}
}

函数内通过bctbx_list_for_each(lc->sip_conf.proxies,(xxxx)&linphone_proxy_config_update)
来调用linphone_proxy_config_update检查lc->sip_conf.poxies中的每个config;

linphone_proxy_config_update(LinphoneProxyConfig *cfg); proxy.c line1241

void linphone_proxy_config_update(LinphoneProxyConfig *cfg){//ms_message("linphone_proxy_config_update");LinphoneCore *lc=cfg->lc;if (cfg->commit){ms_message("update cfg->commit = true");if (cfg->type && cfg->ssctx==NULL){linphone_proxy_config_activate_sip_setup(cfg);}if (can_register(cfg)){linphone_proxy_config_register(cfg);cfg->commit=FALSE;}}if (cfg->send_publish && (cfg->state==LinphoneRegistrationOk || cfg->state==LinphoneRegistrationCleared)){linphone_proxy_config_send_publish(cfg,lc->presence_model);cfg->send_publish=FALSE;}
}

在之前addProxyConfig的时候,cfg->commit为true;然后判断can_register(cfg),

can_register(cfg) proxy.c line1224

static bool_t can_register(LinphoneProxyConfig *cfg){LinphoneCore *lc=cfg->lc;
#ifdef BUILD_UPNPif (linphone_core_get_firewall_policy(lc)==LinphonePolicyUseUpnp){if(lc->sip_conf.register_only_when_upnp_is_ok &&(lc->upnp == NULL || !linphone_upnp_context_is_ready_for_register(lc->upnp))) {return FALSE;}}
#endif //BUILD_UPNPif (lc->sip_conf.register_only_when_network_is_up){return lc->sip_network_reachable;}return TRUE;
}

检查防火墙是否可用啥的,然后执行注册

linphone_proxy_config_register(cfg) proxy.c line462

static void linphone_proxy_config_register(LinphoneProxyConfig *cfg){ms_message("linphone_proxy_config_register");if (cfg->reg_sendregister){LinphoneAddress* proxy=linphone_address_new(cfg->reg_proxy);char* proxy_string;char * from = linphone_address_as_string(cfg->identity_address);LinphoneAddress *contact;ms_message("LinphoneProxyConfig [%p] about to register (LinphoneCore version: %s)  from =[ %s ]" ,cfg,linphone_core_get_version() , from);proxy_string=linphone_address_as_string_uri_only(proxy);linphone_address_destroy(proxy);if (cfg->op)sal_op_release(cfg->op);cfg->op=sal_op_new(cfg->lc->sal);linphone_configure_op(cfg->lc, cfg->op, cfg->identity_address, cfg->sent_headers, FALSE);if ((contact=guess_contact_for_register(cfg))) {sal_op_set_contact_address(cfg->op,contact);linphone_address_destroy(contact);}sal_op_set_user_pointer(cfg->op,cfg);if (sal_register(cfg->op,proxy_string, cfg->reg_identity, cfg->expires, cfg->pending_contact)==0) {if (cfg->pending_contact) {linphone_address_unref(cfg->pending_contact);cfg->pending_contact=NULL;}linphone_proxy_config_set_state(cfg,LinphoneRegistrationProgress,"Registration in progress");} else {linphone_proxy_config_set_state(cfg,LinphoneRegistrationFailed,"Registration failed");}ms_free(proxy_string);ms_free(from);} else {/* unregister if registered*/if (cfg->state == LinphoneRegistrationProgress) {linphone_proxy_config_set_state(cfg,LinphoneRegistrationCleared,"Registration cleared");}_linphone_proxy_config_unregister(cfg);}
}

先将cfg原来的op删除,然后执行linphone_configure_op(xxx);

linphone_configure_op(cfg->lc,cfg->op,cfg->identity_address,cfg->sent_headers,false); linphonecore.c line3283

void linphone_configure_op(LinphoneCore *lc, SalOp *op, const LinphoneAddress *dest, SalCustomHeader *headers, bool_t with_contact){bctbx_list_t *routes=NULL;LinphoneProxyConfig *proxy=linphone_core_lookup_known_proxy(lc,dest);const char *identity;if (proxy){identity=linphone_proxy_config_get_identity(proxy);if (linphone_proxy_config_get_privacy(proxy)!=LinphonePrivacyDefault) {sal_op_set_privacy(op,linphone_proxy_config_get_privacy(proxy));}}else identity=linphone_core_get_primary_contact(lc);/*sending out of calls*/if (proxy){routes=make_routes_for_proxy(proxy,dest);linphone_transfer_routes_to_op(routes,op);}sal_op_set_to_address(op,dest);sal_op_set_from(op,identity);sal_op_set_sent_custom_header(op,headers);sal_op_set_realm(op,linphone_proxy_config_get_realm(proxy));if (with_contact && proxy && proxy->op){const SalAddress *contact;if ((contact=sal_op_get_contact_address(proxy->op))){SalTransport tport=sal_address_get_transport((SalAddress*)contact);SalAddress *new_contact=sal_address_clone(contact);sal_address_clean(new_contact); /* clean out contact_params that come from proxy config*/sal_address_set_transport(new_contact,tport);sal_op_set_contact_address(op,new_contact);sal_address_destroy(new_contact);}}sal_op_cnx_ip_to_0000_if_sendonly_enable(op,lp_config_get_default_int(lc->config,"sip","cnx_ip_to_0000_if_sendonly_enabled",0)); /*also set in linphone_call_new_incoming*/
}

这个接口主要是讲op原有的属性清除,然后设置为新的属性
sal_op_set_to_address(op,dest); 给op设置目标地址
sal_op_set_from(op,identity); 给op设置本地地址
sal_op_set_sent_custom_header(op,headers); 给op设置sip消息头
sal_op_set_realm(op,linphone_proxy_config_get_realm(proxy)); 给op设置realm;

sal_op_set_sent_custom_header(op,headers); sal_op_impl.c line700;

void sal_op_set_sent_custom_header(SalOp *op, SalCustomHeader* ch){SalOpBase *b=(SalOpBase *)op;if (b->sent_custom_headers){sal_custom_header_free(b->sent_custom_headers);b->sent_custom_headers=NULL;}if (ch) belle_sip_object_ref((belle_sip_message_t*)ch);b->sent_custom_headers=ch;
}

先删除op原来的的sent_custom_headers,然后重新设置为ch;
回到linphone_proxy_config_register中,继续执行sal_register();

sal_register(); sal_op_registration.c line78

int sal_register(SalOp *op, const char *proxy, const char *from, int expires,SalAddress* old_contact){belle_sip_message("sal_register %s" ,from);belle_sip_request_t *req;belle_sip_uri_t* req_uri;belle_sip_header_t* accept_header;if (op->refresher){belle_sip_refresher_stop(op->refresher);belle_sip_object_unref(op->refresher);op->refresher=NULL;}op->type=SalOpRegister;sal_op_set_from(op,from);sal_op_set_to(op,from);sal_op_set_route(op,proxy);req = sal_op_build_request(op,"REGISTER");req_uri = belle_sip_request_get_uri(req);belle_sip_uri_set_user(req_uri,NULL); /*remove userinfo if any*/if (op->base.root->use_dates){time_t curtime=time(NULL);belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(belle_sip_header_date_create_from_time(&curtime)));}accept_header = belle_sip_header_create("Accept", "application/sdp, text/plain, application/vnd.gsma.rcs-ft-http+xml");belle_sip_message_add_header(BELLE_SIP_MESSAGE(req), accept_header);belle_sip_message_set_header(BELLE_SIP_MESSAGE(req),(belle_sip_header_t*)sal_op_create_contact(op));belle_sip_list_t* new_list = belle_sip_message_get_all_headers(BELLE_SIP_MESSAGE(req));belle_sip_list_t* iterator = new_list;for (;iterator!=NULL;iterator=iterator->next) {belle_sip_header_t* header=(belle_sip_header_t*)iterator->data;char* header_string=belle_sip_object_to_string(header);belle_sip_message("header = %s",header_string);}if (old_contact) {belle_sip_header_contact_t *contact=belle_sip_header_contact_create((const belle_sip_header_address_t *)old_contact);if (contact) {char * tmp;belle_sip_header_contact_set_expires(contact,0); /*remove old aor*/belle_sip_message_add_header(BELLE_SIP_MESSAGE(req), BELLE_SIP_HEADER(contact));tmp = belle_sip_object_to_string(contact);ms_message("Clearing contact [%s] for op [%p]",tmp,op);ms_free(tmp);} else {ms_error("Cannot add old contact header to op [%p]",op);}}return sal_op_send_and_create_refresher(op,req,expires,register_refresher_listener);
}

首先构建sdp的request,sal_op_build_request(op,”REGISTER”);

sal_op_build_request() sal_op_impl.c line155;
这个函数主要是构建request的基本信息;
然后继续在request填充cantact信息;
最后返回 sal_op_send_and_create_refresher();

sal_op_send_and_create_refresher(); sal_op_impl.c line 663

int sal_op_send_and_create_refresher(SalOp* op,belle_sip_request_t* req, int expires,belle_sip_refresher_listener_t listener ) {if (sal_op_send_request_with_expires(op,req,expires)==0) {if (op->refresher) {belle_sip_refresher_stop(op->refresher);belle_sip_object_unref(op->refresher);}if ((op->refresher = belle_sip_client_transaction_create_refresher(op->pending_client_trans))) {/*since refresher acquires the transaction, we should remove our context from the transaction, because we won't be notified* that it is terminated anymore.*/sal_op_unref(op);/*loose the reference that was given to the transaction when creating it*//* Note that the refresher will replace our data with belle_sip_transaction_set_application_data().Something in the design is not very good here, it makes things complicated to the belle-sip user.Possible ideas to improve things: refresher shall not use belle_sip_transaction_set_application_data() internally, refresher should let the first transactionnotify the user as a normal transaction*/belle_sip_refresher_set_listener(op->refresher,listener,op);belle_sip_refresher_set_retry_after(op->refresher,op->base.root->refresher_retry_after);belle_sip_refresher_set_realm(op->refresher,op->base.realm);belle_sip_refresher_enable_manual_mode(op->refresher,op->manual_refresher);return 0;} else {return -1;}}return -1;
}

第一步 执行sal_op_send_request_with_expires();
sal_op_send_request_with_expires(), sal_op_impl.c line263

int sal_op_send_request_with_expires(SalOp* op, belle_sip_request_t* request,int expires) {belle_sip_message("sal_op_send_request_with_expires");belle_sip_header_expires_t* expires_header=(belle_sip_header_expires_t*)belle_sip_message_get_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_EXPIRES);if (!expires_header && expires>=0) {belle_sip_message_add_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(expires_header=belle_sip_header_expires_new()));}if (expires_header) belle_sip_header_expires_set_expires(expires_header,expires);return sal_op_send_request(op,request);
}

继续在request中增加expires的头字段,然后返回sal_op_send_request;

sal_op_send_request(); sal_op_impl.c line399

int sal_op_send_request(SalOp* op, belle_sip_request_t* request)  {bool_t need_contact=FALSE;if (request==NULL) {return -1; /*sanity check*/}if (strcmp(belle_sip_request_get_method(request),"INVITE")==0||strcmp(belle_sip_request_get_method(request),"REGISTER")==0||strcmp(belle_sip_request_get_method(request),"SUBSCRIBE")==0||strcmp(belle_sip_request_get_method(request),"OPTIONS")==0||strcmp(belle_sip_request_get_method(request),"REFER")==0) /* Despite contact seems not mandatory, call flow example show a Contact in REFER requests*/need_contact=TRUE;return _sal_op_send_request_with_contact(op, request,need_contact);
}

检查一下request是什么类型的请求,决定need_contact取值,然后返回_sal_op_send_request_with_contact();

_sal_op_send_request_with_contact(); sal_op_impl.c line309

static int _sal_op_send_request_with_contact(SalOp* op, belle_sip_request_t* request, bool_t add_contact) {belle_sip_message("_sal_op_send_request_with_contact");belle_sip_client_transaction_t* client_transaction;belle_sip_provider_t* prov=op->base.root->prov;belle_sip_uri_t* outbound_proxy=NULL;belle_sip_header_contact_t* contact;int result =-1;belle_sip_uri_t *next_hop_uri=NULL;if (add_contact && !belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(request),belle_sip_header_contact_t)) {contact = sal_op_create_contact(op);belle_sip_message_set_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(contact));} /*keep existing*/_sal_op_add_custom_headers(op, (belle_sip_message_t*)request);if (!op->dialog || belle_sip_dialog_get_state(op->dialog) == BELLE_SIP_DIALOG_NULL) {/*don't put route header if  dialog is in confirmed state*/const MSList *elem=sal_op_get_route_addresses(op);const char *transport;const char *method=belle_sip_request_get_method(request);belle_sip_listening_point_t *udplp=belle_sip_provider_get_listening_point(prov,"UDP");if (elem) {outbound_proxy=belle_sip_header_address_get_uri((belle_sip_header_address_t*)elem->data);next_hop_uri=outbound_proxy;}else{next_hop_uri=(belle_sip_uri_t*)belle_sip_object_clone((belle_sip_object_t*)belle_sip_request_get_uri(request));}transport=belle_sip_uri_get_transport_param(next_hop_uri);if (transport==NULL){/*compatibility mode: by default it should be udp as not explicitely set and if no udp listening point is available, then use* the first available transport*/if (!belle_sip_uri_is_secure(next_hop_uri)){if (udplp==NULL){if (belle_sip_provider_get_listening_point(prov,"TCP")!=NULL){transport="tcp";}else if (belle_sip_provider_get_listening_point(prov,"TLS")!=NULL ){transport="tls";}}if (transport){belle_sip_message("Transport is not specified, using %s because UDP is not available.",transport);belle_sip_uri_set_transport_param(next_hop_uri,transport);}}}else{
#ifdef TUNNEL_ENABLEDif (udplp && BELLE_SIP_OBJECT_IS_INSTANCE_OF(udplp,belle_sip_tunnel_listening_point_t)){/* our tunnel mode only supports UDP. Force transport to be set to UDP */belle_sip_uri_set_transport_param(next_hop_uri,"udp");}
#endif}/*because in case of tunnel, transport can be changed*/transport=belle_sip_uri_get_transport_param(next_hop_uri);if ((strcmp(method,"REGISTER")==0 || strcmp(method,"SUBSCRIBE")==0) && transport &&(strcasecmp(transport,"TCP")==0 || strcasecmp(transport,"TLS")==0)){/*RFC 5923: add 'alias' parameter to tell the server that we want it to keep the connection for future requests*/belle_sip_header_via_t *via=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(request),belle_sip_header_via_t);belle_sip_parameters_set_parameter(BELLE_SIP_PARAMETERS(via),"alias",NULL);}}client_transaction = belle_sip_provider_create_client_transaction(prov,request);belle_sip_transaction_set_application_data(BELLE_SIP_TRANSACTION(client_transaction),sal_op_ref(op));if (op->pending_client_trans) belle_sip_object_unref(op->pending_client_trans);op->pending_client_trans=client_transaction; /*update pending inv for being able to cancel*/belle_sip_object_ref(op->pending_client_trans);if (belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(request),belle_sip_header_user_agent_t)==NULL)belle_sip_message_add_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_HEADER(op->base.root->user_agent));if (!belle_sip_message_get_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_AUTHORIZATION)&& !belle_sip_message_get_header(BELLE_SIP_MESSAGE(request),BELLE_SIP_PROXY_AUTHORIZATION)) {/*hmm just in case we already have authentication param in cache*/belle_sip_provider_add_authorization(op->base.root->prov,request,NULL,NULL,NULL,op->base.realm);}result = belle_sip_client_transaction_send_request_to(client_transaction,next_hop_uri/*might be null*/);/*update call id if not set yet for this OP*/if (result == 0 && !op->base.call_id) {op->base.call_id=ms_strdup(belle_sip_header_call_id_get_call_id(BELLE_SIP_HEADER_CALL_ID(belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(request), belle_sip_header_call_id_t))));}return result;}

首先检查add_contact是否true,且当前的request里面没有包含contact数据,如果没有则从op中获取contact信息,并添加到request中;
调用_sal_op_add_custom_headers,添加自定义的消息头字段;
然后设置dialog信息,不知道干嘛的
然后通过prov和request构建一个client_transaction对象;通过belle_sip_transaction_set_application_data()函数,将整个op数据设置到client_transaction->appdata上,同时也将op->pending_client_trans属性设置为client_transaction上;
继续设置request的User-Agent属性;
然后检查request消息头的认证方式是否存在;
所有头信息检查完毕以后,调用belle_sip_client_transaction_send_request_to()发送消息,并获取结果;最终返回结果;

分析其中两个关键函数,设置自定义头消息字段的接口和发送消息的接口
_sal_op_add_custom_headers(); sal_op_impl.c line 296

void _sal_op_add_custom_headers(SalOp *op, belle_sip_message_t *msg){ms_message("_sal_op_add_custom_headers");if (op->base.sent_custom_headers){belle_sip_message_t *ch=(belle_sip_message_t*)op->base.sent_custom_headers;belle_sip_list_t *l=belle_sip_message_get_all_headers(ch);belle_sip_list_t *elem;for(elem=l;elem!=NULL;elem=elem->next){add_headers(op,(belle_sip_header_t*)elem->data,msg);}belle_sip_list_free(l);}
}

从op->base.sent_custom_headers获取所有增加的自定义的消息头列表,然后遍历列表,将没个自定义消息头添加到op中;
add_headers(op,header); sal_op_impl.c line280;

static void add_headers(SalOp *op, belle_sip_header_t *h, belle_sip_message_t *msg){char* header_string=belle_sip_object_to_string(h);ms_message("add_headers  [%s]",header_string);if (BELLE_SIP_OBJECT_IS_INSTANCE_OF(h,belle_sip_header_contact_t)){belle_sip_header_contact_t* newct;/*special case for contact, we want to keep everything from the custom contact but set automatic mode and add our own parameters as well*/sal_op_set_contact_address(op,(SalAddress*)BELLE_SIP_HEADER_ADDRESS(h));newct = sal_op_create_contact(op);belle_sip_message_set_header(BELLE_SIP_MESSAGE(msg),BELLE_SIP_HEADER(newct));return;}/*if a header already exists in the message, replace it*/belle_sip_message_set_header(msg,h);
}

接着分析第二个关键函数:
belle_sip_client_transaction_send_request_to();transaction.c line444

int belle_sip_client_transaction_send_request_to(belle_sip_client_transaction_t *t,belle_sip_uri_t* outbound_proxy) {belle_sip_channel_t *chan; ....chan=belle_sip_provider_get_channel(prov,t->next_hop);if (chan){belle_sip_object_ref(chan);belle_sip_channel_add_listener(chan,BELLE_SIP_CHANNEL_LISTENER(t));t->base.channel=chan;if (belle_sip_channel_get_state(chan)==BELLE_SIP_CHANNEL_INIT){belle_sip_message("belle_sip_client_transaction_send_request(): waiting channel to be ready");belle_sip_channel_prepare(chan);/*the channel will notify us when it is ready*/} else if (belle_sip_channel_get_state(chan)==BELLE_SIP_CHANNEL_READY){/*otherwise we can send immediately*/BELLE_SIP_OBJECT_VPTR(t,belle_sip_client_transaction_t)->send_request(t);}result=0;}else {belle_sip_error("belle_sip_client_transaction_send_request(): no channel available");belle_sip_transaction_terminate(BELLE_SIP_TRANSACTION(t));result=-1;}return result;
}

获取channel对象,然后给channel设置监听器,belle_sip_channel_add_listener(chan, t);
判断channel的状态,如果是INIT状态,先去执行belle_sip_channel_prepare(chan);如果是READY状态,就直接调用client_transaction中的send_request(t)函数指针;

先看一下INIT状态下的;
belle_sip_channel_prepare() channel.c line1347;

void belle_sip_channel_prepare(belle_sip_channel_t *obj){channel_prepare_continue(obj);
}
static void channel_prepare_continue(belle_sip_channel_t *obj){belle_sip_message("channel_prepare_continue");switch(obj->state){case BELLE_SIP_CHANNEL_INIT:channel_begin_send_background_task(obj);belle_sip_channel_resolve(obj);break;case BELLE_SIP_CHANNEL_RES_DONE:belle_sip_channel_connect(obj);break;case BELLE_SIP_CHANNEL_READY:channel_process_queue(obj);break;default:break;}
}

第一步:channel_begin_send_background_task(obj);
第二步:belle_sip_channel_resolve(obj);

static void channel_begin_send_background_task(belle_sip_channel_t *obj){if (obj->bg_task_id==0){obj->bg_task_id=belle_sip_begin_background_task("belle-sip send channel",(void (*)(void*))channel_on_send_background_task_ended, obj);if (obj->bg_task_id) belle_sip_message("channel [%p]: starting send background task with id=[%lx].",obj,obj->bg_task_id);}
}
unsigned long belle_sip_begin_background_task(const char *name, belle_sip_background_task_end_callback_t cb, void *data){return wake_lock_acquire(name);
}

belle_sip_channel_resolve(obj); channel.c line1442

void belle_sip_channel_resolve(belle_sip_channel_t *obj){belle_sip_message("channel [%p]: starting resolution of %s", obj, obj->peer_name);channel_set_state(obj,BELLE_SIP_CHANNEL_RES_IN_PROGRESS);if (belle_sip_stack_dns_srv_enabled(obj->stack) && obj->lp!=NULL)obj->resolver_ctx=belle_sip_stack_resolve(obj->stack, "sip", belle_sip_channel_get_transport_name_lower_case(obj), obj->peer_name, obj->peer_port, obj->ai_family, channel_res_done, obj);elseobj->resolver_ctx=belle_sip_stack_resolve_a(obj->stack, obj->peer_name, obj->peer_port, obj->ai_family, channel_res_done, obj);if (obj->resolver_ctx){belle_sip_object_ref(obj->resolver_ctx);}return ;
}

先将状态设置为 BELLE_SIP_CHANNEL_RES_IN_PROGRESS;然后调用belle_sip_stack_resolve,可能是启动另一个任务,并回调channel_res_done接口;
其中设置状态的接口也很重要,
channel_set_state(),在channel.c line1028;

void channel_set_state(belle_sip_channel_t *obj, belle_sip_channel_state_t state) {belle_sip_message("channel %p: state %s",obj,belle_sip_channel_state_to_string(state));if (state==BELLE_SIP_CHANNEL_ERROR){belle_sip_channel_handle_error(obj);}else{obj->state=state;channel_invoke_state_listener(obj);}
}

发现只要状态不是error,都会调用channel_invoke_state_listener(obj);在line 951

static void channel_invoke_state_listener(belle_sip_channel_t *obj){int close = FALSE;switch(obj->state){case BELLE_SIP_CHANNEL_DISCONNECTED:case BELLE_SIP_CHANNEL_ERROR:/*the background tasks must be released "after" notifying the app of the disconnected or error stateBy "after" it is means not before the main loop iteration that will notify the app.This is the reason why these calls are done here rather than in the channel_set_state() function.*/channel_end_send_background_task(obj);channel_end_recv_background_task(obj);close = TRUE;break;default:break;}/*Channel listeners may drop the last reference of the channel, so protect by ref/unref until we finish.*/belle_sip_object_ref(obj);BELLE_SIP_CHANNEL_INVOKE_STATE_LISTENERS(obj,obj->state);if (close) belle_sip_channel_close(obj);belle_sip_object_unref(obj);
}

在这个函数中 ,通过BELLE_SIP_CHANNEL_INVOKE_STATE_LISTENERS来执行状态回调,真实的回调接口定义在transaction.c中 line96;暂时先不讲
设置完状态以后,再看回调的channel_res_done接口;

channel_res_done()在line1426;

static void channel_res_done(void *data, const char *name, struct addrinfo *ai_list){belle_sip_channel_t *obj=(belle_sip_channel_t*)data;if (obj->resolver_ctx){belle_sip_object_unref(obj->resolver_ctx);obj->resolver_ctx=NULL;}if (ai_list){obj->peer_list=obj->current_peer=ai_list;channel_set_state(obj,BELLE_SIP_CHANNEL_RES_DONE);channel_prepare_continue(obj);}else{belle_sip_error("%s: DNS resolution failed for %s", __FUNCTION__, name);channel_set_state(obj,BELLE_SIP_CHANNEL_ERROR);}
}

将状态设置为BELLE_SIP_CHANNEL_RES_DONE,又一次调用channel_prepare_continue();
根据此时channel的状态,这一次在channel_prepare_continue中进入belle_sip_channel_connect(obj)环节;

belle_sip_channel_connect() 在line1455

void belle_sip_channel_connect(belle_sip_channel_t *obj){char ip[64];int port=obj->peer_port;channel_set_state(obj,BELLE_SIP_CHANNEL_CONNECTING);bctbx_addrinfo_to_ip_address(obj->current_peer,ip,sizeof(ip),&port);/* update peer_port as it may have been overriden by SRV resolution*/if (port!=obj->peer_port){/*the SRV resolution provided a port number that must be used*/obj->srv_overrides_port=TRUE;obj->peer_port=port;}belle_sip_message("Trying to connect to [%s://%s:%i]",belle_sip_channel_get_transport_name(obj),ip,obj->peer_port);if(BELLE_SIP_OBJECT_VPTR(obj,belle_sip_channel_t)->connect(obj,obj->current_peer)) {belle_sip_error("Cannot connect to [%s://%s:%i]",belle_sip_channel_get_transport_name(obj),obj->peer_name,obj->peer_port);channel_set_state(obj,BELLE_SIP_CHANNEL_ERROR);}return;
}

将状态更新为BELLE_SIP_CHANNEL_CONNECTING;
解析出地址和端口号;
调用channel中定义的connect接口:如果用的是UDP协议的,connect指向的函数指针是 udp_channel_connect(x,x);

udp_channel_connect(); 在udp_channel.c line 69;

int udp_channel_connect(belle_sip_channel_t *obj, const struct addrinfo *ai){belle_sip_message("udp_channel_connect");belle_sip_udp_channel_t *chan=(belle_sip_udp_channel_t *)obj;struct sockaddr_storage laddr={0};socklen_t lslen=sizeof(laddr);if (obj->local_ip==NULL){int err = belle_sip_get_src_addr_for(ai->ai_addr,(socklen_t)ai->ai_addrlen,(struct sockaddr*)&laddr,&lslen,obj->local_port);if (err == -BCTBX_ENETUNREACH || err == -BCTBX_EHOSTUNREACH){return -1;}}belle_sip_channel_set_socket(obj, chan->shared_socket, NULL);belle_sip_channel_set_ready(obj, (struct sockaddr*)&laddr, lslen);return 0;
}

首先设置socket,然后调用belle_sip_channel_set_ready();

belle_sip_channel_set_ready() 在channel.c line1401;

void belle_sip_channel_set_ready(belle_sip_channel_t *obj, const struct sockaddr *addr, socklen_t slen){belle_sip_message("belle_sip_channel_set_ready");char name[NI_MAXHOST];char serv[NI_MAXSERV];if (obj->local_ip==NULL){struct sockaddr_storage saddr;socklen_t slen2=sizeof(saddr);int err;bctbx_sockaddr_remove_v4_mapping(addr,(struct sockaddr*) &saddr,&slen2);err=getnameinfo((struct sockaddr*)&saddr,slen2,name,sizeof(name),serv,sizeof(serv),NI_NUMERICHOST|NI_NUMERICSERV);if (err!=0){belle_sip_error("belle_sip_channel_set_ready(): getnameinfo() failed: %s",gai_strerror(err));}else{obj->local_ip=belle_sip_strdup(name);obj->local_port=atoi(serv);belle_sip_message("Channel has local address %s:%s",name,serv);}}channel_set_state(obj,BELLE_SIP_CHANNEL_READY);channel_process_queue(obj);
}

设置channel的本地ip和端口号,然后修改状态为BELLE_SIP_CHANNEL_READY,然后调用channel_process_queue(obj)
在修改状态为READYD时候,channel_set_state中invoke的监听器里会执行下面的操作

case BELLE_SIP_CHANNEL_READY:if (tr_state==BELLE_SIP_TRANSACTION_INIT && BELLE_SIP_OBJECT_IS_INSTANCE_OF(t,belle_sip_client_transaction_t) ){belle_sip_client_transaction_t *ct = (belle_sip_client_transaction_t*) t;BELLE_SIP_OBJECT_VPTR(ct,belle_sip_client_transaction_t)->send_request(ct);}

也就是执行send_request()的函数指针;在使用UDP协议登录的时候,这个send_request()指针指向的是nict.c中的nict_send_request()函数;

static void nict_send_request(belle_sip_nict_t *obj){belle_sip_message("nict_send_request");belle_sip_transaction_t *base=(belle_sip_transaction_t*)obj;const belle_sip_timer_config_t *cfg=belle_sip_transaction_get_timer_config(base);belle_sip_transaction_set_state(base,BELLE_SIP_TRANSACTION_TRYING);obj->timer_F=belle_sip_timeout_source_new((belle_sip_source_func_t)nict_on_timer_F,obj,cfg->T1*64);belle_sip_object_set_name((belle_sip_object_t*)obj->timer_F,"timer_F");belle_sip_transaction_start_timer(base,obj->timer_F);if (!belle_sip_channel_is_reliable(base->channel)){obj->timer_E=belle_sip_timeout_source_new((belle_sip_source_func_t)nict_on_timer_E,obj,cfg->T1);belle_sip_object_set_name((belle_sip_object_t*)obj->timer_E,"timer_E");belle_sip_transaction_start_timer(base,obj->timer_E);}belle_sip_channel_queue_message(base->channel,(belle_sip_message_t*)base->request);
}

先更新transaction的状态,为BELLE_SIP_TRANSACTION_TRYING,然后开启了一个定时器
最后调用belle_sip_channel_queue_message();

belle_sip_channel_queue_message在channel.c line1512;

int belle_sip_channel_queue_message(belle_sip_channel_t *obj, belle_sip_message_t *msg){belle_sip_message("belle_sip_channel_queue_message");if (obj->stack->tx_delay>0){queue_message_delayed(obj,msg);}else queue_message(obj,msg);return 0;
}

其实就是检查一下这个请求是否是延迟发送的;注册的时候不是;

queue_message(), 在line1476

static void queue_message(belle_sip_channel_t *obj, belle_sip_message_t *msg){belle_sip_message("queue_message");belle_sip_object_ref(msg);channel_push_outgoing(obj,msg);if (obj->state==BELLE_SIP_CHANNEL_INIT){belle_sip_channel_prepare(obj);}else if (obj->state==BELLE_SIP_CHANNEL_READY) {channel_process_queue(obj);}
}

第一步: channel_push_outgoing(obj,msg);
第二部:因为此时状态是ready,进入channel_process_queue();

channel_push_outgoing()在line1351;

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);
}

只是将待发送的消息追加的obj->outgoing_messages中;
第二步的函数在line1382

static void channel_process_queue(belle_sip_channel_t *obj){belle_sip_message("channel_process_queue");belle_sip_message_t *msg;belle_sip_object_ref(obj);/* we need to ref ourself because code below may trigger our destruction*/if (obj->out_state!=OUTPUT_STREAM_IDLE)_send_message(obj);while((msg=channel_pop_outgoing(obj))!=NULL && obj->state==BELLE_SIP_CHANNEL_READY && obj->out_state==OUTPUT_STREAM_IDLE) {send_message(obj, msg);belle_sip_object_unref(msg);}if (obj->state == BELLE_SIP_CHANNEL_READY && obj->out_state == OUTPUT_STREAM_IDLE) {channel_end_send_background_task(obj);}belle_sip_object_unref(obj);
}

后面就是最终的消息发送的流程,暂时不深入展开了。

总结:

关于自定义消息头

首先在LinphoneProxyConfig中添加消息头字段时,数据是保存在cfg->sent_headers中的,sent_headers可以转换为belle_sip_message_t 的结构,是一个列表形式的;
可以通过belle_sip_message_get_all_headers()来获取对应的belle_sip_list_t列表,然后通过->next遍历每一个belle_sip_header_t对象

if(cfg->sent_headers){belle_sip_message_t *ch=(belle_sip_message_t*)cfg->sent_headers;belle_sip_list_t *l=belle_sip_message_get_all_headers(ch);belle_sip_list_t *elem;for(elem=l;elem!=NULL;elem=elem->next){belle_sip_header_t* head = (belle_sip_header_t*)elem->data;char* header_string=belle_sip_object_to_string(head);       ms_message("cfg header  [%s]",header_string);}
}

真正发送的时候,自定义的消息头保存在lc的op中,lc->op->base.sent_custom_headers,也是一个belle_sip_message_t的数据结构;
————————————————

下一篇:Linphone android去电增加自定义SIP消息头的流程分析_今人不见古时月,今月曾经照古人的博客-CSDN博客

转载于:https://blog.csdn.net/yfloctar/article/details/73180050

Linphone-android 登录过程增加自定义消息头流程分析相关推荐

  1. Android 源码 Camera2 预览流程分析四

    <Android 源码 Camera2 预览流程分析二>中进行了流启动,这是调用 QCamera3Channel start() 方法实现的,对应于 HAL_PIXEL_FORMAT_YC ...

  2. android 开机向导加载过程,开机向导启动流程分析

    开机向导启动流程 首先来看Android启动流程: 1.Bootloader(系统启动加载器,将Linux加载到RAM): 2.Kernel 3.init进程 4.Zygote(Zygote进程是整个 ...

  3. android打电话 接电话 挂电话流程分析

    android打电话过程: 1.TwelveKeyDialer.java,onKeyDown()->dialButtonPressed() 2.OutgoingCallBroadcaster.j ...

  4. Android 9.0 开关机动画流程分析

    Android开机动画流程的启动主要是在Surfaseflinger里面完成的,具体代码如下: /frameworks/native/services/surfaceflinger/StartProp ...

  5. Android系统开机到Launcher启动流程分析

    本文基于Android10.0的源码. 由于google团队在对framework层代码进行大量重构,所以代码变动还是挺大的. 常见基础问题: SystemServer系统服务进程是如何创建的?Lau ...

  6. 全志 android 编译,全志A20启动代码流程分析 ——Android

    现在的CPU都固化了内部 ROM,内部 ROM中有一般都有一段程序,一般有如下几个功能: 1,初始化,部分外设,如USB,SDCARD 2,初始化DDR(内存)和NandFlash 3,加载boot( ...

  7. 全志android 编译,全志A20启动代码流程分析 ——Android

    现在的CPU都固化了内部 ROM,内部 ROM中有一般都有一段程序,一般有如下几个功能: 1,初始化,部分外设,如USB,SDCARD 2,初始化DDR(内存)和NandFlash 3,加载boot( ...

  8. Android 7.0 挂断电话流程分析

    1.图形显示 挂断电话分为本地挂断和远程对方挂断 2.本地挂断 1).点击按钮 先看按键的监听事件 CallCardFragment.java 中有对按钮的监听事件 @Overridepublic v ...

  9. Android Tel 拨打电话及来电流程分析

    打电话流程 接下来分析一下打电话的流程.输入电话号码的流程这里忽略.输入电话号码之后会点击拨打图标.之后就会走拨打电话的流程了.这部分是在packages/apps/Dialer/src/com/an ...

最新文章

  1. php技术会议总结,【技术产品】总结PHP编程20大效率要点
  2. WxCountUp - 数字滚动(微信小程序插件)
  3. 14个最常见的Kafka面试题及答案【转】
  4. 阿里巴巴的五大平台野心,让“连接”论成为过去式
  5. 聚焦视频文本检索:一文概览视频文本检索任务最新研究进展
  6. 如何在Android Studio里关掉instant run
  7. 【JavaScript】查漏补缺 —数组中filter()方法
  8. 2022-03-21 转载办公室之常用职位(英汉)
  9. 下一个最大2的幂 判断是否是2的幂
  10. Python实战——为人脸照片添加口罩
  11. C语言编译出现首值缪,TP312C-C语言程序设计 武马群.pdf
  12. 基于荔枝派Lichee Nano(全志f1c100s)的u-boot移植(一)
  13. MSP MCU I2C入门指南
  14. unity商店的Standard Assets自带人物移动插件的bug修改
  15. oracle12c 开启em,Oracle12C的EM无法访问怎么办?
  16. java基础知识【第12期】-- 集合之Set
  17. Java实现手机登录功能
  18. E - Eddy的难题
  19. 源码解析-偏向锁撤销流程解读
  20. M洞察|“MOBA”还是“MMO”?2023上半年热门手游大盘点来了,拯救你的游戏荒

热门文章

  1. 长安福特全新蒙迪欧混动版正式申报,搭载1.5T发动机和比亚迪电池
  2. 期权询价+报价+下单系统解决方案
  3. NestJS初步学习,创建新用户
  4. 《大营救》将登陆央视 高曙光李佳璇领衔主演
  5. 直线回归和相关------(一)回归和相关的概念与直线回归(含最小二乘推导)
  6. 复杂度 O、Θ、Ω、o、ω,别再傻傻分不清了!
  7. 童士豪:VC都在想什么?
  8. DirectX 12 3D游戏开发实战(第一章向量)
  9. 苹果开发完整的苹果证书与描述文件创建流程
  10. 共创云端新业态,AppCan移动云大会即将召开