• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            posts - 8, comments - 12, trackbacks - 0, articles - 0
              C++博客 :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

            (轉)asterisk核心框架

            Posted on 2009-09-03 16:12 eyesmart 閱讀(2565) 評論(1)  編輯 收藏 引用 所屬分類: VoIP

            Asterisk是一個開源的pbx系統(tǒng),在公開的資料中,很難找到asterisk內核系統(tǒng)的詳細描述。因此,很有必要寫一篇內核框架的描述文檔,作為內部培訓文檔,相互學習提高。

            本文主要從三個層面來描述asterisk內核,即asterisk內核模塊、內核啟動過程、基本呼叫流程。

            一、asterisk內核模塊

            Asterisk由內部核心和外圍動態(tài)可加載模塊組成。內部核心由以下六個部分組成:PBX交換核心模塊(PBX Switching Core)、調度和I/O管理模塊(Scheduler and I/O Manager)、應用調用模塊(Application Launcher)、編解碼轉換模塊(Codec Translator)、動態(tài)模塊加載器模塊(Dynamic Module Loader)和CDR生成模塊(CDR Core)。

            外圍動態(tài)可加載模塊包括以App_開始的Applications、以Func_開始的Functions、以Res_開始的Resources、以Chan_開始的channels、以Codec_開始的codec編解碼模塊等。

            1.內核模塊

            1) PBX交換核心模塊(PBX Switching Core):

            l  pbx.c

            pbx.c是asterisk的核心模塊,每路呼叫都需要經(jīng)過它調度。pbx實現(xiàn)了builtin applications,也就是內置的應用,比如最常見的Answer,Hangup, Background,Wait等等。

            struct ast_app是一個關鍵數(shù)據(jù)結構,它定義了注冊builtin applications的結構。

            load_pbx函數(shù)用來注冊builtin applications和一些命令行CLI命令(每個模塊都有些CLI命令)。該函數(shù)在系統(tǒng)啟動時被調用。

            pbx_exec是Answer/BackGround/Busy/Goto/GotoIf/Hangup/Set等builtin applications的執(zhí)行入口函數(shù),它被pbx_extension_helper調用。

            ast_pbx_start函數(shù)是每路呼叫的起點。

            2)        調度和I/O管理模塊(Scheduler and I/O Manager):

            l         Channel.c:

            Channel.c/channel.h定義了channel操作的結構體和接口函數(shù)。

            struct ast_channel_tech結構體是所有channel都要用到的關鍵結構體,它定義channel操作的一系列回調函數(shù)指針,如call、 hangup、answer等。每個channel模塊都會定義ast_channel_tech的實體,并將各自的回調函數(shù)賦值給它。例如 chan_sip.c中定義如下:

            /*! \brief Definition of this channel for PBX channel registration */

            static const struct ast_channel_tech sip_tech = {

                   .type = "SIP",

                   .description = "Session Initiation Protocol (SIP)",

                   .capabilities = ((AST_FORMAT_MAX_AUDIO << 1) - 1),

                   .properties = AST_CHAN_TP_WANTSJITTER | AST_CHAN_TP_CREATESJITTER,

                   .requester = sip_request_call,

                   .devicestate = sip_devicestate,

                   .call = sip_call,

                   .hangup = sip_hangup,

                   .answer = sip_answer,

                   .read = sip_read,

                   .write = sip_write,

                   .write_video = sip_write,

                   .indicate = sip_indicate,

                   .transfer = sip_transfer,

                   .fixup = sip_fixup,

                   .send_digit_begin = sip_senddigit_begin,

                   .send_digit_end = sip_senddigit_end,

                   .bridge = ast_rtp_bridge,

                   .send_text = sip_sendtext,

                   .func_channel_read = acf_channel_read,

            };

            ast_call、ast_hangup、ast_answer等函數(shù)分別實現(xiàn)ast_channel_tech中的call、hangup、answer等回調函數(shù)的調用。

            struct ast_channel結構體定義了channel的上下文參數(shù),它是每個參與呼叫的channel必不可少的,都會調用ast_channel_alloc來申請ast_channel。

            l io.c

            io.c實現(xiàn)了asterisk跟外部交互時的I/O管理,如chan_sip為了從外部接收SIP信令,調用ast_io_add添加IO接口,并調用ast_io_wait實現(xiàn)外部消息接收。

            3)應用調用模塊(Application Launcher):

            在pbx.c中定義了一系列的應用調用接口。

            applications模塊定義了application回調函數(shù)并注冊后,在pbx.c中通過應用調用接口回調執(zhí)行。

            應用調用接口的關鍵函數(shù)是pbx_extension_helper,它執(zhí)行dialplan,在cli上打印“Executing ……”,并拋出ami event事件,同時調用pbx_exec執(zhí)行application回調函數(shù)。

            4) 編解碼轉換模塊(Codec Translator):

            Translate.c:

            struct ast_translator:編碼轉換描述結構體,它定義了編碼轉換的名稱、回調函數(shù)、運行時選項。

            struct ast_trans_pvt:編碼轉換上下文描述結構體。

            ast_register_translator:編碼轉換注冊接口函數(shù),供各編碼模塊調用,注冊struct ast_translator類型的結構體變量。

            ast_unregister_translator:編碼轉換注銷函數(shù)

            ast_translate:編碼轉換的執(zhí)行函數(shù)。

            codec_gsm.c/codec_...:對應各種編碼的編解碼執(zhí)行模塊,如g.711alaw/g.711ulaw/gsm等。

            5)動態(tài)模塊加載器模塊(Dynamic Module Loader):

            該模塊主要是Module.h。

            Module.h中定義了struct ast_module_info結構,用來保存各模塊的注冊、注銷回調函數(shù),以及模塊描述信息。

            load_module、unload_module,每個應用模塊的注冊、注銷函數(shù),由各個模塊自行定義為static函數(shù)。

            AST_MODULE_INFO_STANDARD:注冊接口、注銷接口、模塊描述信息等模塊信息的登記接口。它是一個宏定義,動態(tài)模塊調用它時, 首先定義類型為ast_module_info的__mod_info靜態(tài)結構變量,保存模塊信息,并定義__attribute__ ((constructor)) __reg_module和__attribute__ ((destructor)) __unreg_module,在程序啟動和退出時調用。

            6)CDR生成模塊(CDR Core):

            Cdr.c:

            ast_cdr_register:cdr driver注冊,供cdr_mysql等調用,注冊話單保存的回調函數(shù)。

            ast_cdr_engine_init:CDR模塊初始化,注冊cdr status、加載cdr.conf、啟動CDR線程。

            ast_cdr_detach:產(chǎn)生話單的接口函數(shù),呼叫結束時被調用。

            2.外圍可加載模塊:

            1)Applications

            以app_開始的模塊,如app_dial.c、app_db.c、app_queue.c、app_record.c、app_meetme.c 等,代碼保存在apps目錄中。每個application模塊都定義了load_module函數(shù)和unload_module函數(shù),分別用來注冊和注 銷application。

            load_module函數(shù)調用ast_register_application函數(shù),注冊application命令,例如app_dial模 塊注冊Dial:res = ast_register_application(app, dial_exec, synopsis, descrip)。

            unload_module函數(shù)調用ast_unregister_application函數(shù),注銷application命令。

            每個application模塊都會使用AST_MODULE_INFO_STANDARD宏來登記模塊信息__mod_info。 AST_MODULE_INFO_STANDARD將load_module和unload_module注冊為回調函數(shù),供module load/unload/reload調用。

            2)Channel

            以chan_開始的模塊,如chan_sip.c、chan_h323.c、chan_mgcp.c 、chan_iax2.c、 chan_zap.c等,對應代碼保存在channels目錄中。

            channel注冊、注銷過程和application基本類似。由于每個channel需要和外部交互,都會在load_module中啟用do_monitor線程來偵聽外部tcp/udp端口,接收外部消息。

            每個channel也定義了各自的cli命令和Function命令,例如chan_sip定義了sip debug/history/no/notify/prune/ reload/set/show等cli命令和SIP_HEADER、CHECKSIPDOMAIN、SIPPEER、SIPCHANINFO等 Function命令。

            3)Functions

            以Fun_開始的模塊,例如Fun_db.c、func_moh.c、func_cdr.c等,對應代碼保存在funcs目錄中。

            Function注冊、注銷過程也和application類似。

            每個Function模塊也定義了各自的Function命令,例如Fun_db.c就定義了DB、DB_EXISTS、DB_DELETE等Function命令。

            二、asterisk啟動過程

            主要就main函數(shù)講解asterisk的啟動過程:

               1 int main(int argc, char *argv[])
               2 
               3 {
               4 
               5        int c;
               6 
               7        char filename[80= "";
               8 
               9        char hostname[MAXHOSTNAMELEN] = "";
              10 
              11        char tmp[80];
              12 
              13        char * xarg = NULL;
              14 
              15        int x;
              16 
              17        FILE *f;
              18 
              19        sigset_t sigs;
              20 
              21        int num;
              22 
              23        int isroot = 1;
              24 
              25        char *buf;
              26 
              27        char *runuser = NULL, *rungroup = NULL;
              28 
              29 /*保存命令行參數(shù)(argv[]->_argv[]),以便程序重啟時使用*/
              30 
              31        /* Remember original args for restart */
              32 
              33        if (argc > sizeof(_argv) / sizeof(_argv[0]) - 1) {
              34 
              35               fprintf(stderr, "Truncating argument size to %d\n", (int)(sizeof(_argv) / sizeof(_argv[0])) - 1);
              36 
              37               argc = sizeof(_argv) / sizeof(_argv[0]) - 1;
              38 
              39        }
              40 
              41        for (x=0; x<argc; x++)
              42 
              43               _argv[x] = argv[x];
              44 
              45        _argv[x] = NULL;
              46 
              47        if (geteuid() != 0)
              48 
              49               isroot = 0;
              50 
              51 /*命令如果是rasterisk,設置AST_OPT_FLAG_NO_FORK和AST_OPT_FLAG_REMOTE標志位*/
              52 
              53        /* if the progname is rasterisk consider it a remote console */
              54 
              55        if (argv[0&& (strstr(argv[0], "rasterisk")) != NULL) {
              56 
              57               ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE);
              58 
              59        }
              60 
              61 /*得到當前主機名,在啟動時打印出來*/
              62 
              63        if (gethostname(hostname, sizeof(hostname)-1))
              64 
              65               ast_copy_string(hostname, "<Unknown>"sizeof(hostname));
              66 
              67 /*獲取當前的進程標識*/
              68 
              69        ast_mainpid = getpid();
              70 
              71 /*建立mu-law和a-law轉換表*/
              72 
              73        ast_ulaw_init();
              74 
              75        ast_alaw_init();
              76 
              77 /*為FFT逆變換(傅立葉逆變換)做一些初始化,用于在zaptel里進行callerid的DTMF檢測*/
              78 
              79        callerid_init();
              80 
              81 /*初始化內置命令的_full_cmd字符串,并注冊常用命令,ast_builtins_init() -> ast_cli_register_multiple() -> ast_cli_register() -> __ast_cli_register() */
              82 
              83        ast_builtins_init();
              84 
              85 /*初始化base64轉換*/
              86 
              87        ast_utils_init();
              88 
              89 /* tty/tdd初始化*/
              90 
              91        tdd_init();
              92 
              93 /*設置用戶歷史命令的保存路徑*/
              94 
              95        if (getenv("HOME"))
              96 
              97               snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
              98 
              99        /* Check for options */
             100 
             101 /*檢查命令行的輸入?yún)?shù),匹配參數(shù)范圍是“mtThfFdvVqprRgciInx:U:G:C:L:M:”,不同的參數(shù)輸入走到不同的case分支處理。有幾個v,verbose級別就增加幾*/
             102 
             103        while ((c = getopt(argc, argv, "mtThfFdvVqprRgciInx:U:G:C:L:M:")) != -1) {
             104 
             105               switch (c) {
             106 
             107 #if HAVE_WORKING_FORK
             108 
             109               case 'F':
             110 
             111                      ast_set_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK);
             112 
             113                      break;
             114 
             115               case 'f':
             116 
             117                      ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
             118 
             119                      break;
             120 
             121 #endif
             122 
             123               case 'd':
             124 
             125                      option_debug++;
             126 
             127                      ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
             128 
             129                      break;
             130 
             131               case 'c':
             132 
             133                      ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_CONSOLE);
             134 
             135                      break;
             136 
             137               case 'n':
             138 
             139                      ast_set_flag(&ast_options, AST_OPT_FLAG_NO_COLOR);
             140 
             141                      break;
             142 
             143               case 'r':
             144 
             145                      ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE);
             146 
             147                      break;
             148 
             149               case 'R':
             150 
             151                      ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE | AST_OPT_FLAG_RECONNECT);
             152 
             153                      break;
             154 
             155               case 'p':
             156 
             157                      ast_set_flag(&ast_options, AST_OPT_FLAG_HIGH_PRIORITY);
             158 
             159                      break;
             160 
             161               case 'v':
             162 
             163                      option_verbose++;
             164 
             165                      ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
             166 
             167                      break;
             168 
             169               case 'm':
             170 
             171                      ast_set_flag(&ast_options, AST_OPT_FLAG_MUTE);
             172 
             173                      break;
             174 
             175               case 'M':
             176 
             177                      if ((sscanf(optarg, "%d"&option_maxcalls) != 1|| (option_maxcalls < 0))
             178 
             179                             option_maxcalls = 0;
             180 
             181                      break;
             182 
             183               case 'L':
             184 
             185                      if ((sscanf(optarg, "%lf"&option_maxload) != 1|| (option_maxload < 0.0))
             186 
             187                             option_maxload = 0.0;
             188 
             189                      break;
             190 
             191               case 'q':
             192 
             193                      ast_set_flag(&ast_options, AST_OPT_FLAG_QUIET);
             194 
             195                      break;
             196 
             197               case 't':
             198 
             199                      ast_set_flag(&ast_options, AST_OPT_FLAG_CACHE_RECORD_FILES);
             200 
             201                      break;
             202 
             203               case 'T':
             204 
             205                      ast_set_flag(&ast_options, AST_OPT_FLAG_TIMESTAMP);
             206 
             207                      break;
             208 
             209               case 'x':
             210 
             211                      ast_set_flag(&ast_options, AST_OPT_FLAG_EXEC);
             212 
             213                      xarg = ast_strdupa(optarg);
             214 
             215                      break;
             216 
             217               case 'C':
             218 
             219                      ast_copy_string(ast_config_AST_CONFIG_FILE, optarg, sizeof(ast_config_AST_CONFIG_FILE));
             220 
             221                      ast_set_flag(&ast_options, AST_OPT_FLAG_OVERRIDE_CONFIG);
             222 
             223                      break;
             224 
             225               case 'I':
             226 
             227                      ast_set_flag(&ast_options, AST_OPT_FLAG_INTERNAL_TIMING);
             228 
             229                      break;
             230 
             231               case 'i':
             232 
             233                      ast_set_flag(&ast_options, AST_OPT_FLAG_INIT_KEYS);
             234 
             235                      break;
             236 
             237               case 'g':
             238 
             239                      ast_set_flag(&ast_options, AST_OPT_FLAG_DUMP_CORE);
             240 
             241                      break;
             242 
             243               case 'h':
             244 
             245                      show_cli_help();
             246 
             247                      exit(0);
             248 
             249               case 'V':
             250 
             251                      show_version();
             252 
             253                      exit(0);
             254 
             255               case 'U':
             256 
             257                      runuser = ast_strdupa(optarg);
             258 
             259                      break;
             260 
             261               case 'G':
             262 
             263                      rungroup = ast_strdupa(optarg);
             264 
             265                      break;
             266 
             267               case '?':
             268 
             269                      exit(1);
             270 
             271               }
             272 
             273        }
             274 
             275 /*如果用了-c或者-v或者-r并且沒有-x cmd參數(shù),則打印歡迎信息*/
             276 
             277        if (ast_opt_console || option_verbose || (ast_opt_remote && !ast_opt_exec)) {
             278 
             279               ast_register_verbose(console_verboser);
             280 
             281               WELCOME_MESSAGE;
             282 
             283        }
             284 
             285 /*如果沒有開調試則簡單打印Booting */
             286 
             287        if (ast_opt_console && !option_verbose)
             288 
             289               ast_verbose("[ Booting\n");
             290 
             291 /*顯示控制臺時,不論是本地還是遠程,都不能使用-F參數(shù),否則無效*/
             292 
             293        if (ast_opt_always_fork && (ast_opt_remote || ast_opt_console)) {
             294 
             295               ast_log(LOG_WARNING, "'alwaysfork' is not compatible with console or remote console mode; ignored\n");
             296 
             297               ast_clear_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK);
             298 
             299        }
             300 
             301        /* For remote connections, change the name of the remote connection.
             302 
             303         * We do this for the benefit of init scripts (which need to know if/when
             304 
             305         * the main asterisk process has died yet). */
             306 
             307        if (ast_opt_remote) {
             308 
             309               strcpy(argv[0], "rasterisk");
             310 
             311               for (x = 1; x < argc; x++) {
             312 
             313                      argv[x] = argv[0+ 10;
             314 
             315               }
             316 
             317        }
             318 
             319 /*讀取主配置文件,主配置文件是由make menuselect配置的*/
             320 
             321        if (ast_opt_console && !option_verbose)
             322 
             323               ast_verbose("[ Reading Master Configuration ]\n");
             324 
             325        ast_readconfig();
             326 
             327 /*如果啟動加了-g,取消core dump文件的大小限制*/
             328 
             329        if (ast_opt_dump_core) {
             330 
             331               struct rlimit l;
             332 
             333               memset(&l, 0sizeof(l));
             334 
             335               l.rlim_cur = RLIM_INFINITY;
             336 
             337               l.rlim_max = RLIM_INFINITY;
             338 
             339               if (setrlimit(RLIMIT_CORE, &l)) {
             340 
             341                      ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n", strerror(errno));
             342 
             343               }
             344 
             345        }
             346 
             347 /*修改用戶和組權限*/
             348 
             349        if ((!rungroup) && !ast_strlen_zero(ast_config_AST_RUN_GROUP))
             350 
             351               rungroup = ast_config_AST_RUN_GROUP;
             352 
             353        if ((!runuser) && !ast_strlen_zero(ast_config_AST_RUN_USER))
             354 
             355               runuser = ast_config_AST_RUN_USER;
             356 
             357 #ifndef __CYGWIN__
             358 
             359        if (isroot)
             360 
             361               ast_set_priority(ast_opt_high_priority);
             362 
             363        if (isroot && rungroup) {
             364 
             365               struct group *gr;
             366 
             367               gr = getgrnam(rungroup);
             368 
             369               if (!gr) {
             370 
             371                      ast_log(LOG_WARNING, "No such group '%s'!\n", rungroup);
             372 
             373                      exit(1);
             374 
             375               }
             376 
             377               if (setgid(gr->gr_gid)) {
             378 
             379                      ast_log(LOG_WARNING, "Unable to setgid to %d (%s)\n", (int)gr->gr_gid, rungroup);
             380 
             381                      exit(1);
             382 
             383               }
             384 
             385               if (setgroups(0, NULL)) {
             386 
             387                      ast_log(LOG_WARNING, "Unable to drop unneeded groups\n");
             388 
             389                      exit(1);
             390 
             391               }
             392 
             393               if (option_verbose)
             394 
             395                      ast_verbose("Running as group '%s'\n", rungroup);
             396 
             397        }
             398 
             399        if (runuser && !ast_test_flag(&ast_options, AST_OPT_FLAG_REMOTE)) {
             400 
             401 #ifdef HAVE_CAP
             402 
             403               int has_cap = 1;
             404 
             405 #endif /* HAVE_CAP */
             406 
             407               struct passwd *pw;
             408 
             409               pw = getpwnam(runuser);
             410 
             411               if (!pw) {
             412 
             413                      ast_log(LOG_WARNING, "No such user '%s'!\n", runuser);
             414 
             415                      exit(1);
             416 
             417               }
             418 
             419 #ifdef HAVE_CAP
             420 
             421               if (prctl(PR_SET_KEEPCAPS, 1000)) {
             422 
             423                      ast_log(LOG_WARNING, "Unable to keep capabilities.\n");
             424 
             425                      has_cap = 0;
             426 
             427               }
             428 
             429 #endif /* HAVE_CAP */
             430 
             431               if (!isroot && pw->pw_uid != geteuid()) {
             432 
             433                      ast_log(LOG_ERROR, "Asterisk started as nonroot, but runuser '%s' requested.\n", runuser);
             434 
             435                      exit(1);
             436 
             437               }
             438 
             439               if (!rungroup) {
             440 
             441                      if (setgid(pw->pw_gid)) {
             442 
             443                             ast_log(LOG_WARNING, "Unable to setgid to %d!\n", (int)pw->pw_gid);
             444 
             445                             exit(1);
             446 
             447                      }
             448 
             449                      if (isroot && initgroups(pw->pw_name, pw->pw_gid)) {
             450 
             451                             ast_log(LOG_WARNING, "Unable to init groups for '%s'\n", runuser);
             452 
             453                             exit(1);
             454 
             455                      }
             456 
             457               }
             458 
             459               if (setuid(pw->pw_uid)) {
             460 
             461                      ast_log(LOG_WARNING, "Unable to setuid to %d (%s)\n", (int)pw->pw_uid, runuser);
             462 
             463                      exit(1);
             464 
             465               }
             466 
             467               if (option_verbose)
             468 
             469                      ast_verbose("Running as user '%s'\n", runuser);
             470 
             471 #ifdef HAVE_CAP
             472 
             473               if (has_cap) {
             474 
             475                      cap_t cap;
             476 
             477                      cap = cap_from_text("cap_net_admin=ep");
             478 
             479                      if (cap_set_proc(cap))
             480 
             481                             ast_log(LOG_WARNING, "Unable to install capabilities.\n");
             482 
             483                      if (cap_free(cap))
             484 
             485                             ast_log(LOG_WARNING, "Unable to drop capabilities.\n");
             486 
             487               }
             488 
             489 #endif /* HAVE_CAP */
             490 
             491        }
             492 
             493 #endif /* __CYGWIN__ */
             494 
             495 #ifdef linux
             496 
             497        if (geteuid() && ast_opt_dump_core) {
             498 
             499               if (prctl(PR_SET_DUMPABLE, 1000< 0) {
             500 
             501                      ast_log(LOG_WARNING, "Unable to set the process for core dumps after changing to a non-root user. %s\n", strerror(errno));
             502 
             503               }   
             504 
             505        }
             506 
             507 #endif
             508 
             509 /*初始化模擬終端ast_term_init(),默認是VT100*/
             510 
             511        ast_term_init();
             512 
             513        printf(term_end());
             514 
             515        fflush(stdout);
             516 
             517        if (ast_opt_console && !option_verbose)
             518 
             519               ast_verbose("[ Initializing Custom Configuration Options ]\n");
             520 
             521        /* custom config setup */
             522 
             523 /*注冊命令core show config mappings*/
             524 
             525        register_config_cli();
             526 
             527 /*配置文件的映射和綁定*/
             528 
             529        read_config_maps();
             530 
             531        if (ast_opt_console) {
             532 
             533               if (el_hist == NULL || el == NULL)
             534 
             535                      ast_el_initialize();
             536 
             537               if (!ast_strlen_zero(filename))
             538 
             539                      ast_el_read_history(filename);
             540 
             541        }
             542 
             543 /*設置和檢查本地或遠程終端的連接*/
             544 
             545        if (ast_tryconnect()) {
             546 
             547               /* One is already running */
             548 
             549               if (ast_opt_remote) {
             550 
             551                      if (ast_opt_exec) {
             552 
             553                             ast_remotecontrol(xarg);
             554 
             555                             quit_handler(0000);
             556 
             557                             exit(0);
             558 
             559                      }
             560 
             561                      printf(term_quit());
             562 
             563                      ast_remotecontrol(NULL);
             564 
             565                      quit_handler(0000);
             566 
             567                      exit(0);
             568 
             569               } else {
             570 
             571                      ast_log(LOG_ERROR, "Asterisk already running on %s.  Use 'asterisk -r' to connect.\n", ast_config_AST_SOCKET);
             572 
             573                      printf(term_quit());
             574 
             575                      exit(1);
             576 
             577               }
             578 
             579        } else if (ast_opt_remote || ast_opt_exec) {
             580 
             581               ast_log(LOG_ERROR, "Unable to connect to remote asterisk (does %s exist?)\n", ast_config_AST_SOCKET);
             582 
             583               printf(term_quit());
             584 
             585               exit(1);
             586 
             587        }
             588 
             589        /* Blindly write pid file since we couldn't connect */
             590 
             591        unlink(ast_config_AST_PID);
             592 
             593        f = fopen(ast_config_AST_PID, "w");
             594 
             595        if (f) {
             596 
             597               fprintf(f, "%ld\n", (long)getpid());
             598 
             599               fclose(f);
             600 
             601        } else
             602 
             603               ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", ast_config_AST_PID, strerror(errno));
             604 
             605 #if HAVE_WORKING_FORK
             606 
             607        if (ast_opt_always_fork || !ast_opt_no_fork) {
             608 
             609 #ifndef HAVE_SBIN_LAUNCHD
             610 
             611               daemon(10);
             612 
             613               ast_mainpid = getpid();
             614 
             615               /* Blindly re-write pid file since we are forking */
             616 
             617               unlink(ast_config_AST_PID);
             618 
             619               f = fopen(ast_config_AST_PID, "w");
             620 
             621               if (f) {
             622 
             623                      fprintf(f, "%ld\n", (long)ast_mainpid);
             624 
             625                      fclose(f);
             626 
             627               } else
             628 
             629                      ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", ast_config_AST_PID, strerror(errno));
             630 
             631 #else
             632 
             633               ast_log(LOG_WARNING, "Mac OS X detected.  Use '/sbin/launchd -d' to launch with the nofork option.\n");
             634 
             635 #endif
             636 
             637        }
             638 
             639 #endif
             640 
             641        /* Test recursive mutex locking. */
             642 
             643 /*測試線程安全,避免出現(xiàn)死鎖*/
             644 
             645        if (test_for_thread_safety())
             646 
             647               ast_verbose("Warning! Asterisk is not thread safe.\n");
             648 
             649 /*創(chuàng)建用于和控制臺交互的服務器端socket接口*/
             650 
             651        ast_makesocket();
             652 
             653 /*加入信號集,設置掩碼,以及注冊信號的相應handler */
             654 
             655        sigemptyset(&sigs);
             656 
             657        sigaddset(&sigs, SIGHUP);
             658 
             659        sigaddset(&sigs, SIGTERM);
             660 
             661        sigaddset(&sigs, SIGINT);
             662 
             663        sigaddset(&sigs, SIGPIPE);
             664 
             665        sigaddset(&sigs, SIGWINCH);
             666 
             667        pthread_sigmask(SIG_BLOCK, &sigs, NULL);
             668 
             669        signal(SIGURG, urg_handler);
             670 
             671        signal(SIGINT, __quit_handler);
             672 
             673        signal(SIGTERM, __quit_handler);
             674 
             675        signal(SIGHUP, hup_handler);
             676 
             677        signal(SIGCHLD, child_handler);
             678 
             679        signal(SIGPIPE, SIG_IGN);
             680 
             681        /* ensure that the random number generators are seeded with a different value every time
             682 
             683           Asterisk is started
             684 
             685        */
             686 
             687 /*設置種子并初始化隨機數(shù)發(fā)生器*/
             688 
             689        srand((unsigned int) getpid() + (unsigned int) time(NULL));
             690 
             691        initstate((unsigned int) getpid() * 65536 + (unsigned int) time(NULL), randompool, sizeof(randompool));
             692 
             693 /*初始化日志模塊*/
             694 
             695        if (init_logger()) {
             696 
             697               printf(term_quit());
             698 
             699               exit(1);
             700 
             701        }
             702 
             703 #ifdef HAVE_ZAPTEL
             704 
             705        {
             706 
             707               int fd;
             708 
             709               int x = 160;
             710 
             711               fd = open("/dev/zap/timer", O_RDWR);
             712 
             713               if (fd >= 0) {
             714 
             715                      if (ioctl(fd, ZT_TIMERCONFIG, &x)) {
             716 
             717                             ast_log(LOG_ERROR, "You have Zaptel built and drivers loaded, but the Zaptel timer test failed to set ZT_TIMERCONFIG to %d.\n", x);
             718 
             719                             exit(1);
             720 
             721                      }
             722 
             723                      if ((x = ast_wait_for_input(fd, 300)) < 0) {
             724 
             725                             ast_log(LOG_ERROR, "You have Zaptel built and drivers loaded, but the Zaptel timer could not be polled during the Zaptel timer test.\n");
             726 
             727                             exit(1);
             728 
             729                      }
             730 
             731                      if (!x) {
             732 
             733                             const char zaptel_timer_error[] = {
             734 
             735                                    "Asterisk has detected a problem with your Zaptel configuration and will shutdown for your protection.  You have options:"
             736 
             737                                    "\n\t1. You only have to compile Zaptel support into Asterisk if you need it.  One option is to recompile without Zaptel support."
             738 
             739                                    "\n\t2. You only have to load Zaptel drivers if you want to take advantage of Zaptel services.  One option is to unload zaptel modules if you don't need them."
             740 
             741                                    "\n\t3. If you need Zaptel services, you must correctly configure Zaptel."
             742 
             743                             };
             744 
             745                             ast_log(LOG_ERROR, "%s\n", zaptel_timer_error);
             746 
             747                             exit(1);
             748 
             749                      }
             750 
             751                      close(fd);
             752 
             753               }
             754 
             755        }
             756 
             757 #endif
             758 
             759 /*注冊threadstorage show allocations和threadstorage show summary這兩個命令*/
             760 
             761        threadstorage_init();
             762 
             763        astobj2_init();
             764 
             765        ast_autoservice_init();
             766 
             767 /*加載配置文件/etc/asterisk/modules.conf中標記為preload的模塊,再去掉標記為noload的模塊*/
             768 
             769        if (load_modules(1)) {
             770 
             771               printf(term_quit());
             772 
             773               exit(1);
             774 
             775        }
             776 
             777 /* DNS manager的初始化*/
             778 
             779        if (dnsmgr_init()) {
             780 
             781               printf(term_quit());
             782 
             783               exit(1);
             784 
             785        }
             786 
             787 /*配置http服務器*/
             788 
             789        ast_http_init();
             790 
             791 /*注冊兩個命令core show channeltypes和core show channeltype */
             792 
             793        ast_channels_init();
             794 
             795 /*注冊管理命令*/
             796 
             797        if (init_manager()) {
             798 
             799               printf(term_quit());
             800 
             801               exit(1);
             802 
             803        }
             804 
             805 /*用來創(chuàng)建一個調度上下文以及注冊相應的命令,然后用do_reload來讀取配置文件cdr.conf和創(chuàng)建后臺線程do_cdr */
             806 
             807        if (ast_cdr_engine_init()) {
             808 
             809               printf(term_quit());
             810 
             811               exit(1);
             812 
             813        }
             814 
             815 /*用來創(chuàng)建一個后臺線程輪巡設備的狀態(tài),如果發(fā)生變化則及時通告*/
             816 
             817        if (ast_device_state_engine_init()) {
             818 
             819               printf(term_quit());
             820 
             821               exit(1);
             822 
             823        }
             824 
             825 /*注冊rtp,rtcp,stun相關的CLI命令,然后調用ast_rtp_reload()讀取配置文件rtp.conf,設置相關參數(shù)*/
             826 
             827        ast_rtp_init();
             828 
             829 /*注冊udptl相關的CLI命令,然后調用ast_udptl_reload()讀取配置文件udptl.conf,設置相關參數(shù)*/
             830 
             831        ast_udptl_init();
             832 
             833 /*注冊core show image formats */
             834 
             835        if (ast_image_init()) {
             836 
             837               printf(term_quit());
             838 
             839               exit(1);
             840 
             841        }
             842 
             843 /*注冊core show file formats */
             844 
             845        if (ast_file_init()) {
             846 
             847               printf(term_quit());
             848 
             849               exit(1);
             850 
             851        }
             852 
             853 /*注冊dialplan相關的CLI命令,然后調用ast_register_application來注冊所有的app */
             854 
             855        if (load_pbx()) {
             856 
             857               printf(term_quit());
             858 
             859               exit(1);
             860 
             861        }
             862 
             863 /*注冊與codec相關的CLI命令*/
             864 
             865        if (init_framer()) {
             866 
             867               printf(term_quit());
             868 
             869               exit(1);
             870 
             871        }
             872 
             873 /*注冊與database相關的CLI命令,然后再注冊兩個管理命令DBGet和DBPut */
             874 
             875        if (astdb_init()) {
             876 
             877               printf(term_quit());
             878 
             879               exit(1);
             880 
             881        }
             882 
             883 /*讀取配置文件enum.conf,初始化支持ENUM(e164)的子系統(tǒng)*/
             884 
             885        if (ast_enum_init()) {
             886 
             887               printf(term_quit());
             888 
             889               exit(1);
             890 
             891        }
             892 
             893 /* load_modules(0)加載所有其它需要加載的動態(tài)鏈接庫*/
             894 
             895        if (load_modules(0)) {
             896 
             897               printf(term_quit());
             898 
             899               exit(1);
             900 
             901        }
             902 
             903        dnsmgr_start_refresh();
             904 
             905        /* We might have the option of showing a console, but for now just
             906 
             907           do nothing */
             908 
             909        if (ast_opt_console && !option_verbose)
             910 
             911               ast_verbose(" ]\n");
             912 
             913        if (option_verbose || ast_opt_console)
             914 
             915               ast_verbose(term_color(tmp, "Asterisk Ready.\n", COLOR_BRWHITE, COLOR_BLACK, sizeof(tmp)));
             916 
             917        if (ast_opt_no_fork)
             918 
             919               consolethread = pthread_self();
             920 
             921 /*創(chuàng)建管道*/
             922 
             923        if (pipe(sig_alert_pipe))
             924 
             925               sig_alert_pipe[0= sig_alert_pipe[1= -1;
             926 
             927        ast_set_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED);
             928 
             929        pthread_sigmask(SIG_UNBLOCK, &sigs, NULL);
             930 
             931 #ifdef __AST_DEBUG_MALLOC
             932 
             933        __ast_mm_init();
             934 
             935 #endif   
             936 
             937        time(&ast_startuptime);
             938 
             939 /*注冊asterisk相關的命令,比如stop,restart,halt等等*/
             940 
             941        ast_cli_register_multiple(cli_asterisk, sizeof(cli_asterisk) / sizeof(struct ast_cli_entry));
             942 
             943        if (ast_opt_console) {
             944 
             945               /* Console stuff now */
             946 
             947               /* Register our quit function */
             948 
             949               char title[256];
             950 
             951               pthread_attr_t attr;
             952 
             953               pthread_t dont_care;
             954 
             955 /*創(chuàng)建線程,輪詢上面創(chuàng)建的sig_alert_pipe管道*/
             956 
             957               pthread_attr_init(&attr);
             958 
             959               pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
             960 
             961               ast_pthread_create(&dont_care, &attr, monitor_sig_flags, NULL);
             962 
             963               pthread_attr_destroy(&attr);
             964 
             965               set_icon("Asterisk");
             966 
             967               snprintf(title, sizeof(title), "Asterisk Console on '%s' (pid %ld)", hostname, (long)ast_mainpid);
             968 
             969               set_title(title);
             970 
             971 /*接收和處理控制臺命令*/
             972 
             973               for (;;) {
             974 
             975                      buf = (char *)el_gets(el, &num);
             976 
             977                      if (!buf && write(1""1< 0)
             978 
             979                             goto lostterm;
             980 
             981                      if (buf) {
             982 
             983                             if (buf[strlen(buf)-1== '\n')
             984 
             985                                    buf[strlen(buf)-1= '\0';
             986 
             987                             consolehandler((char *)buf);
             988 
             989                      } else if (ast_opt_remote && (write(STDOUT_FILENO, "\nUse EXIT or QUIT to exit the asterisk console\n",
             990 
             991                                strlen("\nUse EXIT or QUIT to exit the asterisk console\n")) < 0)) {
             992 
             993                             /* Whoa, stdout disappeared from under us Make /dev/null's */
             994 
             995                             int fd;
             996 
             997                             fd = open("/dev/null", O_RDWR);
             998 
             999                             if (fd > -1) {
            1000 
            1001                                    dup2(fd, STDOUT_FILENO);
            1002 
            1003                                    dup2(fd, STDIN_FILENO);
            1004 
            1005                             } else
            1006 
            1007                                    ast_log(LOG_WARNING, "Failed to open /dev/null to recover from dead console. Bad things will happen!\n");
            1008 
            1009                             break;
            1010 
            1011                      }
            1012 
            1013               }
            1014 
            1015        }
            1016 
            1017        monitor_sig_flags(NULL);
            1018 
            1019 lostterm:
            1020 
            1021        return 0;
            1022 
            1023 }

            三、asterisk基本呼叫流程

            從內核的角度去分析問題時,弄清楚呼叫流程是非常關鍵的,只有理清了呼叫流程,才能從流程的各個環(huán)節(jié)細節(jié)中分析出問題所在。

            Asterisk所有功能都是基于函數(shù)調用的模式,呼叫流程也不例外。因此如何從一團亂麻似的內核函數(shù)調用中理出函數(shù)調用執(zhí)行路線,是解讀呼叫流程的關鍵。

            所有呼叫都跟astersisk的channel有關。這路通話都包含一個incoming連接和一個outbound連接。每個電話都是通過對應 的channel程序建立起來的,比如Chan_sip,Chan_zap,Chan_iax2等等。每一類的channel,都擁有自己私有的 channel數(shù)據(jù)結構,例如chan_sip的struct sip_pvt結構,這些私有的結構從屬于一個通用的Asterisk通道數(shù)據(jù)結構中,具體定義在channel.h的struct ast_channe中。

            下圖是asterisk 的呼叫流程圖:

            我們以sip的呼叫過程為例來描述,其他channel的呼叫過程基本類似。

            Astersik下注冊的sip用戶主動發(fā)起一個呼叫的函數(shù)調用過程(incoming)如下:

            do_monitor->sipsock_read->handle_request->handle_request_invite->sip_new/ast_pbx_start->pbx_thread->__ast_pbx_run

            -> ast_spawn_extension ->pbx_extension_helper->pbx_exec->執(zhí)行dialplan

            當Chan_sip模塊被加載時,會啟動一個獨立的監(jiān)聽線程do_monitor,不斷偵聽sip端口上的外部消息;

            當sip用戶撥叫被叫號碼后,chan_sip的do_monitor調用sipsock_read函數(shù),在sip端口收到invite消息,然后就調用handle_request和handle_request_invite進行處理。

            在handle_request_invite中,首先解析invite消息,對該sip用戶的業(yè)務屬性分析,確認被叫可達,然后就調用sip_new申請channel資源,并調用ast_pbx_start函數(shù)啟動一個pbx_thread線程來專門處理該呼叫。

            pbx_thread線程調用__ast_pbx_run。

            __ast_pbx_run是一個銜接dialplan和內核的關鍵函數(shù),它首先調用ast_exists_extension函數(shù),根據(jù)分機號碼 的context屬性,匹配到對應的dialplan;然后進入一個for死循環(huán),逐條執(zhí)行dialplan對應的context中的語句。

            pbx_extension_helper函數(shù)調用pbx_extension_helper,在pbx_extension_helper中調用 pbx_find_extension找到對應的context后,通過verbose打印dialplan執(zhí)行語句“Executing ……”,同時調用pbx_exec執(zhí)行該dialplan。執(zhí)行到dial語句呼叫被叫。

            在等待被叫接通的過程中,完成媒體協(xié)商過程,向主叫發(fā)送180、200OK消息接通呼叫。

            當其他用戶呼叫asterisk的sip用戶時,函數(shù)調用過程(outbound)如下: Dial->dial_exec->dial_exec_full->ast_request/ast_call/wait_for_answer/ ast_bridge_call

            呼叫執(zhí)行到dial時,pbx_exec調用application dial的接口函數(shù)dial_exec,dial_exec調用dial_exec_full。

            在dial_exec_full中,首先調用ast_request,在ast_request調用chan_sip對應的回調函數(shù) sip_request_call為該被叫sip用戶申請channel資源。然后調用ast_call,在ast_call中調用chan_sip對應 的回調函數(shù)sip_call向被叫發(fā)送INVITE消息,呼叫被叫SIP用戶。

            然后該呼叫線程會調用wait_for_answer等待被叫接通。

            在呼叫接通后,也即wait_for_answer函數(shù)返回,在dial_exec_full中調用ast_bridge_call橋接媒體,這樣呼叫就正式接通了。

            當chan_sip的偵聽線程接收到BYE消息,則調用handle_request_bye找到相應的channel,執(zhí)行hangup釋放呼叫。

            Feedback

            # re: (轉)asterisk核心框架  回復  更多評論   

            2023-03-01 09:24 by Dawn
            往事如煙~~
            久久综合香蕉国产蜜臀AV| av午夜福利一片免费看久久| 天天做夜夜做久久做狠狠| 久久露脸国产精品| 久久久久久精品无码人妻| 久久久久亚洲AV片无码下载蜜桃| 精品无码久久久久久尤物| 国产精品免费久久久久电影网| 久久人人爽人爽人人爽av| 囯产精品久久久久久久久蜜桃| 国产精品久久久久9999高清| 久久精品国产一区二区三区| 影音先锋女人AV鲁色资源网久久| 777米奇久久最新地址| 欧美亚洲日本久久精品| 亚洲国产一成人久久精品| 欧美久久综合性欧美| 久久久久久免费视频| 国产一级做a爰片久久毛片| 怡红院日本一道日本久久| 18禁黄久久久AAA片| 曰曰摸天天摸人人看久久久| 久久婷婷五月综合97色直播| 久久免费小视频| 伊人久久综合成人网| 久久国产精品一区| 99国产欧美久久久精品蜜芽 | 三级韩国一区久久二区综合| 久久精品国产网红主播| 久久久久99这里有精品10| 国产精品九九久久免费视频 | av国内精品久久久久影院| 久久香蕉国产线看观看猫咪?v| 久久精品国产亚洲av日韩| 久久综合久久综合亚洲| 国产叼嘿久久精品久久| 久久久久久夜精品精品免费啦| 色综合久久夜色精品国产| 国内精品久久久久国产盗摄| 国产成人久久精品区一区二区| 一本一本久久A久久综合精品|