青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

posts - 8, comments - 12, trackbacks - 0, articles - 0
  C++博客 :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

(轉(zhuǎn))asterisk核心框架

Posted on 2009-09-03 16:12 eyesmart 閱讀(2600) 評(píng)論(1)  編輯 收藏 引用 所屬分類(lèi): VoIP

Asterisk是一個(gè)開(kāi)源的pbx系統(tǒng),在公開(kāi)的資料中,很難找到asterisk內(nèi)核系統(tǒng)的詳細(xì)描述。因此,很有必要寫(xiě)一篇內(nèi)核框架的描述文檔,作為內(nèi)部培訓(xùn)文檔,相互學(xué)習(xí)提高。

本文主要從三個(gè)層面來(lái)描述asterisk內(nèi)核,即asterisk內(nèi)核模塊、內(nèi)核啟動(dòng)過(guò)程、基本呼叫流程。

一、asterisk內(nèi)核模塊

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

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

1.內(nèi)核模塊

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

l  pbx.c

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

struct ast_app是一個(gè)關(guān)鍵數(shù)據(jù)結(jié)構(gòu),它定義了注冊(cè)builtin applications的結(jié)構(gòu)。

load_pbx函數(shù)用來(lái)注冊(cè)builtin applications和一些命令行CLI命令(每個(gè)模塊都有些CLI命令)。該函數(shù)在系統(tǒng)啟動(dòng)時(shí)被調(diào)用。

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

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

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

l         Channel.c:

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

struct ast_channel_tech結(jié)構(gòu)體是所有channel都要用到的關(guān)鍵結(jié)構(gòu)體,它定義channel操作的一系列回調(diào)函數(shù)指針,如call、 hangup、answer等。每個(gè)channel模塊都會(huì)定義ast_channel_tech的實(shí)體,并將各自的回調(diào)函數(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ù)分別實(shí)現(xiàn)ast_channel_tech中的call、hangup、answer等回調(diào)函數(shù)的調(diào)用。

struct ast_channel結(jié)構(gòu)體定義了channel的上下文參數(shù),它是每個(gè)參與呼叫的channel必不可少的,都會(huì)調(diào)用ast_channel_alloc來(lái)申請(qǐng)ast_channel。

l io.c

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

3)應(yīng)用調(diào)用模塊(Application Launcher):

在pbx.c中定義了一系列的應(yīng)用調(diào)用接口。

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

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

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

Translate.c:

struct ast_translator:編碼轉(zhuǎn)換描述結(jié)構(gòu)體,它定義了編碼轉(zhuǎn)換的名稱(chēng)、回調(diào)函數(shù)、運(yùn)行時(shí)選項(xiàng)。

struct ast_trans_pvt:編碼轉(zhuǎn)換上下文描述結(jié)構(gòu)體。

ast_register_translator:編碼轉(zhuǎn)換注冊(cè)接口函數(shù),供各編碼模塊調(diào)用,注冊(cè)struct ast_translator類(lèi)型的結(jié)構(gòu)體變量。

ast_unregister_translator:編碼轉(zhuǎn)換注銷(xiāo)函數(shù)

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

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

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

該模塊主要是Module.h。

Module.h中定義了struct ast_module_info結(jié)構(gòu),用來(lái)保存各模塊的注冊(cè)、注銷(xiāo)回調(diào)函數(shù),以及模塊描述信息。

load_module、unload_module,每個(gè)應(yīng)用模塊的注冊(cè)、注銷(xiāo)函數(shù),由各個(gè)模塊自行定義為static函數(shù)。

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

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

Cdr.c:

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

ast_cdr_engine_init:CDR模塊初始化,注冊(cè)cdr status、加載cdr.conf、啟動(dòng)CDR線(xiàn)程。

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

2.外圍可加載模塊:

1)Applications

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

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

unload_module函數(shù)調(diào)用ast_unregister_application函數(shù),注銷(xiāo)application命令。

每個(gè)application模塊都會(huì)使用AST_MODULE_INFO_STANDARD宏來(lái)登記模塊信息__mod_info。 AST_MODULE_INFO_STANDARD將load_module和unload_module注冊(cè)為回調(diào)函數(shù),供module load/unload/reload調(diào)用。

2)Channel

以chan_開(kāi)始的模塊,如chan_sip.c、chan_h323.c、chan_mgcp.c 、chan_iax2.c、 chan_zap.c等,對(duì)應(yīng)代碼保存在channels目錄中。

channel注冊(cè)、注銷(xiāo)過(guò)程和application基本類(lèi)似。由于每個(gè)channel需要和外部交互,都會(huì)在load_module中啟用do_monitor線(xiàn)程來(lái)偵聽(tīng)外部tcp/udp端口,接收外部消息。

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

3)Functions

以Fun_開(kāi)始的模塊,例如Fun_db.c、func_moh.c、func_cdr.c等,對(duì)應(yīng)代碼保存在funcs目錄中。

Function注冊(cè)、注銷(xiāo)過(guò)程也和application類(lèi)似。

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

二、asterisk啟動(dòng)過(guò)程

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

   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[]),以便程序重啟時(shí)使用*/
  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,設(shè)置AST_OPT_FLAG_NO_FORK和AST_OPT_FLAG_REMOTE標(biāo)志位*/
  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 /*得到當(dāng)前主機(jī)名,在啟動(dòng)時(shí)打印出來(lái)*/
  62 
  63        if (gethostname(hostname, sizeof(hostname)-1))
  64 
  65               ast_copy_string(hostname, "<Unknown>"sizeof(hostname));
  66 
  67 /*獲取當(dāng)前的進(jìn)程標(biāo)識(shí)*/
  68 
  69        ast_mainpid = getpid();
  70 
  71 /*建立mu-law和a-law轉(zhuǎn)換表*/
  72 
  73        ast_ulaw_init();
  74 
  75        ast_alaw_init();
  76 
  77 /*為FFT逆變換(傅立葉逆變換)做一些初始化,用于在zaptel里進(jìn)行callerid的DTMF檢測(cè)*/
  78 
  79        callerid_init();
  80 
  81 /*初始化內(nèi)置命令的_full_cmd字符串,并注冊(cè)常用命令,ast_builtins_init() -> ast_cli_register_multiple() -> ast_cli_register() -> __ast_cli_register() */
  82 
  83        ast_builtins_init();
  84 
  85 /*初始化base64轉(zhuǎn)換*/
  86 
  87        ast_utils_init();
  88 
  89 /* tty/tdd初始化*/
  90 
  91        tdd_init();
  92 
  93 /*設(shè)置用戶(hù)歷史命令的保存路徑*/
  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分支處理。有幾個(gè)v,verbose級(jí)別就增加幾*/
 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并且沒(méi)有-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 /*如果沒(méi)有開(kāi)調(diào)試則簡(jiǎn)單打印Booting */
 286 
 287        if (ast_opt_console && !option_verbose)
 288 
 289               ast_verbose("[ Booting\n");
 290 
 291 /*顯示控制臺(tái)時(shí),不論是本地還是遠(yuǎn)程,都不能使用-F參數(shù),否則無(wú)效*/
 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 /*如果啟動(dòng)加了-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 /*修改用戶(hù)和組權(quán)限*/
 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(),默認(rèn)是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 /*注冊(cè)命令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 /*設(shè)置和檢查本地或遠(yuǎn)程終端的連接*/
 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 /*測(cè)試線(xiàn)程安全,避免出現(xiàn)死鎖*/
 644 
 645        if (test_for_thread_safety())
 646 
 647               ast_verbose("Warning! Asterisk is not thread safe.\n");
 648 
 649 /*創(chuàng)建用于和控制臺(tái)交互的服務(wù)器端socket接口*/
 650 
 651        ast_makesocket();
 652 
 653 /*加入信號(hào)集,設(shè)置掩碼,以及注冊(cè)信號(hào)的相應(yīng)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è)置種子并初始化隨機(jī)數(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 /*注冊(cè)threadstorage show allocations和threadstorage show summary這兩個(gè)命令*/
 760 
 761        threadstorage_init();
 762 
 763        astobj2_init();
 764 
 765        ast_autoservice_init();
 766 
 767 /*加載配置文件/etc/asterisk/modules.conf中標(biāo)記為preload的模塊,再去掉標(biāo)記為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服務(wù)器*/
 788 
 789        ast_http_init();
 790 
 791 /*注冊(cè)兩個(gè)命令core show channeltypes和core show channeltype */
 792 
 793        ast_channels_init();
 794 
 795 /*注冊(cè)管理命令*/
 796 
 797        if (init_manager()) {
 798 
 799               printf(term_quit());
 800 
 801               exit(1);
 802 
 803        }
 804 
 805 /*用來(lái)創(chuàng)建一個(gè)調(diào)度上下文以及注冊(cè)相應(yīng)的命令,然后用do_reload來(lái)讀取配置文件cdr.conf和創(chuàng)建后臺(tái)線(xiàn)程do_cdr */
 806 
 807        if (ast_cdr_engine_init()) {
 808 
 809               printf(term_quit());
 810 
 811               exit(1);
 812 
 813        }
 814 
 815 /*用來(lái)創(chuàng)建一個(gè)后臺(tái)線(xiàn)程輪巡設(shè)備的狀態(tài),如果發(fā)生變化則及時(shí)通告*/
 816 
 817        if (ast_device_state_engine_init()) {
 818 
 819               printf(term_quit());
 820 
 821               exit(1);
 822 
 823        }
 824 
 825 /*注冊(cè)rtp,rtcp,stun相關(guān)的CLI命令,然后調(diào)用ast_rtp_reload()讀取配置文件rtp.conf,設(shè)置相關(guān)參數(shù)*/
 826 
 827        ast_rtp_init();
 828 
 829 /*注冊(cè)u(píng)dptl相關(guān)的CLI命令,然后調(diào)用ast_udptl_reload()讀取配置文件udptl.conf,設(shè)置相關(guān)參數(shù)*/
 830 
 831        ast_udptl_init();
 832 
 833 /*注冊(cè)core show image formats */
 834 
 835        if (ast_image_init()) {
 836 
 837               printf(term_quit());
 838 
 839               exit(1);
 840 
 841        }
 842 
 843 /*注冊(cè)core show file formats */
 844 
 845        if (ast_file_init()) {
 846 
 847               printf(term_quit());
 848 
 849               exit(1);
 850 
 851        }
 852 
 853 /*注冊(cè)dialplan相關(guān)的CLI命令,然后調(diào)用ast_register_application來(lái)注冊(cè)所有的app */
 854 
 855        if (load_pbx()) {
 856 
 857               printf(term_quit());
 858 
 859               exit(1);
 860 
 861        }
 862 
 863 /*注冊(cè)與codec相關(guān)的CLI命令*/
 864 
 865        if (init_framer()) {
 866 
 867               printf(term_quit());
 868 
 869               exit(1);
 870 
 871        }
 872 
 873 /*注冊(cè)與database相關(guān)的CLI命令,然后再注冊(cè)兩個(gè)管理命令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)加載所有其它需要加載的動(dòng)態(tài)鏈接庫(kù)*/
 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 /*注冊(cè)asterisk相關(guān)的命令,比如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)建線(xiàn)程,輪詢(xún)上面創(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 /*接收和處理控制臺(tái)命令*/
 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基本呼叫流程

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

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

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

下圖是asterisk 的呼叫流程圖:

我們以sip的呼叫過(guò)程為例來(lái)描述,其他channel的呼叫過(guò)程基本類(lèi)似。

Astersik下注冊(cè)的sip用戶(hù)主動(dòng)發(fā)起一個(gè)呼叫的函數(shù)調(diào)用過(guò)程(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

當(dāng)Chan_sip模塊被加載時(shí),會(huì)啟動(dòng)一個(gè)獨(dú)立的監(jiān)聽(tīng)線(xiàn)程do_monitor,不斷偵聽(tīng)sip端口上的外部消息;

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

在handle_request_invite中,首先解析invite消息,對(duì)該sip用戶(hù)的業(yè)務(wù)屬性分析,確認(rèn)被叫可達(dá),然后就調(diào)用sip_new申請(qǐng)channel資源,并調(diào)用ast_pbx_start函數(shù)啟動(dòng)一個(gè)pbx_thread線(xiàn)程來(lái)專(zhuān)門(mén)處理該呼叫。

pbx_thread線(xiàn)程調(diào)用__ast_pbx_run。

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

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

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

當(dāng)其他用戶(hù)呼叫asterisk的sip用戶(hù)時(shí),函數(shù)調(diào)用過(guò)程(outbound)如下: Dial->dial_exec->dial_exec_full->ast_request/ast_call/wait_for_answer/ ast_bridge_call

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

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

然后該呼叫線(xiàn)程會(huì)調(diào)用wait_for_answer等待被叫接通。

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

當(dāng)chan_sip的偵聽(tīng)線(xiàn)程接收到BYE消息,則調(diào)用handle_request_bye找到相應(yīng)的channel,執(zhí)行hangup釋放呼叫。

Feedback

# re: (轉(zhuǎn))asterisk核心框架  回復(fù)  更多評(píng)論   

2023-03-01 09:24 by Dawn
往事如煙~~

只有注冊(cè)用戶(hù)登錄后才能發(fā)表評(píng)論。
網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問(wèn)   Chat2DB   管理


青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            亚洲理伦电影| 欧美精品一卡| 亚洲高清在线播放| 久久午夜色播影院免费高清| 久久精品30| 久久久久国产免费免费| 久久久亚洲国产美女国产盗摄| 久久一区二区三区四区| 另类人畜视频在线| 亚洲黄一区二区| 在线视频欧美日韩精品| 午夜亚洲视频| 欧美1区免费| 国产精品扒开腿做爽爽爽视频| 国产欧美日韩视频一区二区| 在线观看欧美黄色| 一区二区三区四区国产| 欧美一区二区三区四区夜夜大片| 久久伊伊香蕉| 亚洲福利电影| 午夜欧美大尺度福利影院在线看| 久久视频一区二区| 欧美三级电影网| 狠狠色香婷婷久久亚洲精品| 日韩视频二区| 久久久亚洲一区| 亚洲靠逼com| 久久久天天操| 国产精品视频最多的网站| 亚洲欧洲精品一区二区三区不卡| 亚洲欧美日韩综合| 亚洲国产精品久久久久秋霞蜜臀| 亚洲欧美日本在线| 亚洲一区久久久| 国产精品亚洲视频| 亚洲另类自拍| 玖玖综合伊人| 亚洲欧美激情精品一区二区| 欧美二区乱c少妇| 国产伦精品一区二区| 日韩视频在线播放| 麻豆乱码国产一区二区三区| 亚洲欧美经典视频| 欧美视频一区| 亚洲日本中文字幕区 | 亚洲国产精品传媒在线观看| 在线视频欧美一区| 亚洲国产精品成人综合色在线婷婷| 欧美在线播放视频| 国产精品毛片a∨一区二区三区|国| av72成人在线| 欧美国产大片| 久久青青草综合| 黄色av一区| 另类亚洲自拍| 久久精品国产一区二区三| 国产九区一区在线| 午夜精品婷婷| 亚洲欧美综合v| 国产精品多人| 欧美一区二区三区男人的天堂| 一区二区三区欧美激情| 欧美日韩不卡| 亚洲欧美日本国产有色| 中日韩男男gay无套| 欧美午夜剧场| 久久精品人人做人人综合| 亚洲欧美日韩在线一区| 国产欧美精品| 免费成人毛片| 欧美成人一二三| 亚洲精品一区二区三区福利| 亚洲激情午夜| 欧美午夜精品久久久久久久 | 亚洲精品偷拍| 欧美视频中文字幕在线| 性欧美办公室18xxxxhd| 欧美有码在线视频| 亚洲电影激情视频网站| 亚洲国产精品久久久久秋霞影院| 欧美日韩国产精品自在自线| 午夜精品国产| 久久成人资源| 亚洲美女在线观看| 一区二区三区高清不卡| 狠狠久久亚洲欧美| 亚洲日本久久| 国产一区亚洲| 亚洲精品一区在线观看香蕉| 国产九九精品| 久久这里有精品15一区二区三区 | 你懂的网址国产 欧美| 日韩一区二区精品| 先锋影音久久久| 91久久香蕉国产日韩欧美9色| 日韩视频一区二区三区在线播放免费观看 | 久久久精品国产免费观看同学| 久久久人成影片一区二区三区观看| 日韩一级在线观看| 欧美在线1区| 亚洲午夜久久久久久久久电影院| 欧美一级视频免费在线观看| 在线中文字幕不卡| 美女网站久久| 欧美一区1区三区3区公司| 欧美风情在线| 久久伊人精品天天| 欧美三级视频在线播放| 欧美国产视频在线观看| 国产精品视频yy9299一区| 欧美激情欧美激情在线五月| 国产精品你懂的在线| 亚洲国产综合91精品麻豆| 精品不卡视频| 欧美伊人影院| 欧美一区二区免费视频| 欧美精品一区二区久久婷婷| 麻豆免费精品视频| 国产欧美日韩精品在线| 亚洲一区二区欧美| 99re8这里有精品热视频免费 | 一区二区三区国产在线| 亚洲黄色在线看| 久久精品日韩一区二区三区| 欧美在线播放高清精品| 国产精品一区久久| 99香蕉国产精品偷在线观看| 99在线|亚洲一区二区| 欧美高清视频一区二区| 亚洲第一视频| 亚洲全黄一级网站| 男人的天堂亚洲| 亚洲成人在线免费| 亚洲欧美精品| 亚洲自拍三区| 欧美性大战久久久久久久| 亚洲精品无人区| 中文欧美日韩| 欧美午夜精品久久久久久久| 亚洲另类一区二区| 一区二区三区久久| 亚洲免费一区二区| 国产精品国产一区二区| 欧美激情片在线观看| 在线观看欧美一区| 久久久久久成人| 欧美a级片网站| 最新国产乱人伦偷精品免费网站| 久久综合五月天婷婷伊人| 久久久女女女女999久久| 国产女主播一区| 久久精品亚洲精品国产欧美kt∨| 久久香蕉精品| 亚洲日本视频| 欧美日韩免费一区| 亚洲视频综合| 老司机久久99久久精品播放免费| 尤物yw午夜国产精品视频明星| 久久精品卡一| 亚洲欧洲日夜超级视频| 亚洲综合日韩在线| 国产一区二区三区黄视频| 久久久久99精品国产片| 亚洲国产高清一区| 亚洲中午字幕| 国产综合网站| 欧美激情在线| 欧美有码视频| 亚洲韩国一区二区三区| 亚洲淫性视频| 激情小说亚洲一区| 欧美成人精品在线视频| 亚洲一区在线观看免费观看电影高清 | 欧美一级黄色网| 亚洲国产日韩欧美| 国产精品视频免费观看| 欧美1区3d| 欧美在线观看一区二区| 亚洲精品美女久久7777777| 久久精品国产综合精品| 夜夜嗨av色一区二区不卡| 国产精品资源在线观看| 欧美激情精品久久久| 久久精品国产v日韩v亚洲 | 亚洲一级黄色| 欧美国产视频在线观看| 久久电影一区| 亚洲天堂成人在线观看| 亚洲国产一区二区三区在线播| 国产麻豆精品theporn| 欧美日韩综合久久| 欧美激情中文字幕乱码免费| 久久久五月婷婷| 欧美一区二区三区免费看 | 免费中文字幕日韩欧美| 久久国产精品高清| 亚洲欧美日韩爽爽影院| 99精品福利视频| 亚洲国产毛片完整版| 欧美成人伊人久久综合网|