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

来源:互联网 发布:数据挖掘的案例分析 编辑:程序博客网 时间:2024/05/16 12:52

注册增加消息头

在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 line960void 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 exist   headers_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_UPNP   if (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_UPNP   if (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 transaction          notify 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_ENABLED         if (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);   else      obj->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 state       By "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的数据结构;

原创粉丝点击