Linphone-android 登錄過程增加自定義消息頭流程分析

註冊增加消息頭

在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 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的數據結構;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章