`
free_bird816
  • 浏览: 206003 次
  • 性别: Icon_minigender_1
  • 来自: 济南
社区版块
存档分类
最新评论

Asterisk内核框架

阅读更多

Asterisk内核框架(转帖)

 

Asterisk是一个开源的pbx系统,在公开的资料中,很难找到asterisk内核系统的详细描述。因此,很有必要写一篇内核框架的描述文档,作为内部培训文档,相互学习提高。

本文主要从三个层面来描述asterisk内核,即asterisk内核模块、内核启动过程、基本呼叫流程。

一、             asterisk内核模块

Asterisk由内部核心和外围动态可加载模块组成。内部核心由以下六个部分组成:PBX交换核心模块(PBX Switching Core)、调度和I/O管理模块(Scheduler and I/O Manager)、应用调用模块(Application Launcher)、编解码转换模块(Codec Translator)、动态模块加载器模块(Dynamic Module Loader)和CDR生成模块(CDR Core)。

外围动态可加载模块包括以App_开始的Applications、以Func_开始的Functions、以Res_开始的Resources、以Chan_开始的channels、以Codec_开始的codec编解码模块等。

1.         内核模块

1)        PBX交换核心模块(PBX Switching Core):

l         pbx.c

pbx.c是asterisk的核心模块,每路呼叫都需要经过它调度。pbx实现了builtin applications,也就是内置的应用,比如最常见的Answer,Hangup, Background,Wait等等。

struct ast_app是一个关键数据结构,它定义了注册builtin applications的结构。

load_pbx函数用来注册builtin applications和一些命令行CLI命令(每个模块都有些CLI命令)。该函数在系统启动时被调用。

pbx_exec是Answer/BackGround/Busy/Goto/GotoIf/Hangup/Set等builtin applications的执行入口函数,它被pbx_extension_helper调用。

ast_pbx_start函数是每路呼叫的起点。

2)        调度和I/O管理模块(Scheduler and I/O Manager):

l         Channel.c:

Channel.c/channel.h定义了channel操作的结构体和接口函数。

struct ast_channel_tech结构体是所有channel都要用到的关键结构体,它定义channel操作的一系列回调函数指针,如call、hangup、answer等。每个channel模块都会定义ast_channel_tech的实体,并将各自的回调函数赋值给它。例如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等函数分别实现ast_channel_tech中的call、hangup、answer等回调函数的调用。

struct ast_channel结构体定义了channel的上下文参数,它是每个参与呼叫的channel必不可少的,都会调用ast_channel_alloc来申请ast_channel。

l         io.c

io.c实现了asterisk跟外部交互时的I/O管理,如chan_sip为了从外部接收SIP信令,调用ast_io_add添加IO接口,并调用ast_io_wait实现外部消息接收。

3)        应用调用模块(Application Launcher):

在pbx.c中定义了一系列的应用调用接口。

applications模块定义了application回调函数并注册后,在pbx.c中通过应用调用接口回调执行。

应用调用接口的关键函数是pbx_extension_helper,它执行dialplan,在cli上打印“Executing ……”,并抛出ami event事件,同时调用pbx_exec执行application回调函数。

4)        编解码转换模块(Codec Translator):

Translate.c:

struct ast_translator:编码转换描述结构体,它定义了编码转换的名称、回调函数、运行时选项。

struct ast_trans_pvt:编码转换上下文描述结构体。

ast_register_translator:编码转换注册接口函数,供各编码模块调用,注册struct ast_translator类型的结构体变量。

ast_unregister_translator:编码转换注销函数

ast_translate:编码转换的执行函数。

codec_gsm.c/codec_...:对应各种编码的编解码执行模块,如g.711alaw/g.711ulaw/gsm等。

5)        动态模块加载器模块(Dynamic Module Loader):

该模块主要是Module.h。

Module.h中定义了struct ast_module_info结构,用来保存各模块的注册、注销回调函数,以及模块描述信息。

load_module、unload_module,每个应用模块的注册、注销函数,由各个模块自行定义为static函数。

AST_MODULE_INFO_STANDARD:注册接口、注销接口、模块描述信息等模块信息的登记接口。它是一个宏定义,动态模块调用它时,首先定义类型为ast_module_info的__mod_info静态结构变量,保存模块信息,并定义__attribute__ ((constructor)) __reg_module和__attribute__ ((destructor)) __unreg_module,在程序启动和退出时调用。

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

Cdr.c:

ast_cdr_register:cdr driver注册,供cdr_mysql等调用,注册话单保存的回调函数。

ast_cdr_engine_init:CDR模块初始化,注册cdr status、加载cdr.conf、启动CDR线程。

ast_cdr_detach:产生话单的接口函数,呼叫结束时被调用。

2.         外围可加载模块:

1)        Applications

以app_开始的模块,如app_dial.c、app_db.c、app_queue.c、app_record.c、app_meetme.c等,代码保存在apps目录中。每个application模块都定义了load_module函数和unload_module函数,分别用来注册和注销application。

load_module函数调用ast_register_application函数,注册application命令,例如app_dial模块注册Dial:res = ast_register_application(app, dial_exec, synopsis, descrip)。

unload_module函数调用ast_unregister_application函数,注销application命令。

每个application模块都会使用AST_MODULE_INFO_STANDARD宏来登记模块信息__mod_info。AST_MODULE_INFO_STANDARD将load_module和unload_module注册为回调函数,供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函数讲解asterisk的启动过程:

int main(int argc, char *argv[])

{

       int c;

       char filename[80] = "";

       char hostname[MAXHOSTNAMELEN] = "";

       char tmp[80];

       char * xarg = NULL;

       int x;

       FILE *f;

       sigset_t sigs;

       int num;

       int isroot = 1;

       char *buf;

       char *runuser = NULL, *rungroup = NULL;

/*保存命令行参数(argv[]->_argv[]),以便程序重启时使用*/

       /* Remember original args for restart */

       if (argc > sizeof(_argv) / sizeof(_argv[0]) - 1) {

              fprintf(stderr, "Truncating argument size to %d\n", (int)(sizeof(_argv) / sizeof(_argv[0])) - 1);

              argc = sizeof(_argv) / sizeof(_argv[0]) - 1;

       }

       for (x=0; x<argc; x++)

              _argv[x] = argv[x];

       _argv[x] = NULL;

       if (geteuid() != 0)

              isroot = 0;

/*命令如果是rasterisk,设置AST_OPT_FLAG_NO_FORK和AST_OPT_FLAG_REMOTE标志位*/

       /* if the progname is rasterisk consider it a remote console */

       if (argv[0] && (strstr(argv[0], "rasterisk")) != NULL) {

              ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE);

       }

/*得到当前主机名,在启动时打印出来*/

       if (gethostname(hostname, sizeof(hostname)-1))

              ast_copy_string(hostname, "<Unknown>", sizeof(hostname));

/*获取当前的进程标识*/

       ast_mainpid = getpid();

/*建立mu-law和a-law转换表*/

       ast_ulaw_init();

       ast_alaw_init();

/*为FFT逆变换(傅立叶逆变换)做一些初始化,用于在zaptel里进行callerid的DTMF检测*/

       callerid_init();

/*初始化内置命令的_full_cmd字符串,并注册常用命令,ast_builtins_init() -> ast_cli_register_multiple() -> ast_cli_register() -> __ast_cli_register() */

       ast_builtins_init();

/*初始化base64转换*/

       ast_utils_init();

/* tty/tdd初始化*/

       tdd_init();

/*设置用户历史命令的保存路径*/

       if (getenv("HOME"))

              snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));

       /* Check for options */

/*检查命令行的输入参数,匹配参数范围是“mtThfFdvVqprRgciInx:U:G:C:L:M:”,不同的参数输入走到不同的case分支处理。有几个v,verbose级别就增加几*/

       while ((c = getopt(argc, argv, "mtThfFdvVqprRgciInx:U:G:C:L:M:")) != -1) {

              switch (c) {

#if HAVE_WORKING_FORK

              case 'F':

                     ast_set_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK);

                     break;

              case 'f':

                     ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);

                     break;

#endif

              case 'd':

                     option_debug++;

                     ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);

                     break;

              case 'c':

                     ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_CONSOLE);

                     break;

              case 'n':

                     ast_set_flag(&ast_options, AST_OPT_FLAG_NO_COLOR);

                     break;

              case 'r':

                     ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE);

                     break;

              case 'R':

                     ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE | AST_OPT_FLAG_RECONNECT);

                     break;

              case 'p':

                     ast_set_flag(&ast_options, AST_OPT_FLAG_HIGH_PRIORITY);

                     break;

              case 'v':

                     option_verbose++;

                     ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);

                     break;

              case 'm':

                     ast_set_flag(&ast_options, AST_OPT_FLAG_MUTE);

                     break;

              case 'M':

                     if ((sscanf(optarg, "%d", &option_maxcalls) != 1) || (option_maxcalls < 0))

                            option_maxcalls = 0;

                     break;

              case 'L':

                     if ((sscanf(optarg, "%lf", &option_maxload) != 1) || (option_maxload < 0.0))

                            option_maxload = 0.0;

                     break;

              case 'q':

                     ast_set_flag(&ast_options, AST_OPT_FLAG_QUIET);

                     break;

              case 't':

                     ast_set_flag(&ast_options, AST_OPT_FLAG_CACHE_RECORD_FILES);

                     break;

              case 'T':

                     ast_set_flag(&ast_options, AST_OPT_FLAG_TIMESTAMP);

                     break;

              case 'x':

                     ast_set_flag(&ast_options, AST_OPT_FLAG_EXEC);

                     xarg = ast_strdupa(optarg);

                     break;

              case 'C':

                     ast_copy_string(ast_config_AST_CONFIG_FILE, optarg, sizeof(ast_config_AST_CONFIG_FILE));

                     ast_set_flag(&ast_options, AST_OPT_FLAG_OVERRIDE_CONFIG);

                     break;

              case 'I':

                     ast_set_flag(&ast_options, AST_OPT_FLAG_INTERNAL_TIMING);

                     break;

              case 'i':

                     ast_set_flag(&ast_options, AST_OPT_FLAG_INIT_KEYS);

                     break;

              case 'g':

                     ast_set_flag(&ast_options, AST_OPT_FLAG_DUMP_CORE);

                     break;

              case 'h':

                     show_cli_help();

                     exit(0);

              case 'V':

                     show_version();

                     exit(0);

              case 'U':

                     runuser = ast_strdupa(optarg);

                     break;

              case 'G':

                     rungroup = ast_strdupa(optarg);

                     break;

              case '?':

                     exit(1);

              }

       }

/*如果用了-c或者-v或者-r并且没有-x cmd参数,则打印欢迎信息*/

       if (ast_opt_console || option_verbose || (ast_opt_remote && !ast_opt_exec)) {

              ast_register_verbose(console_verboser);

              WELCOME_MESSAGE;

       }

/*如果没有开调试则简单打印Booting... */

       if (ast_opt_console && !option_verbose)

              ast_verbose("[ Booting...\n");

/*显示控制台时,不论是本地还是远程,都不能使用-F参数,否则无效*/

       if (ast_opt_always_fork && (ast_opt_remote || ast_opt_console)) {

              ast_log(LOG_WARNING, "'alwaysfork' is not compatible with console or remote console mode; ignored\n");

              ast_clear_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK);

       }

       /* For remote connections, change the name of the remote connection.

        * We do this for the benefit of init scripts (which need to know if/when

        * the main asterisk process has died yet). */

       if (ast_opt_remote) {

              strcpy(argv[0], "rasterisk");

              for (x = 1; x < argc; x++) {

                     argv[x] = argv[0] + 10;

              }

       }

/*读取主配置文件,主配置文件是由make menuselect配置的*/

       if (ast_opt_console && !option_verbose)

              ast_verbose("[ Reading Master Configuration ]\n");

       ast_readconfig();

/*如果启动加了-g,取消core dump文件的大小限制*/

       if (ast_opt_dump_core) {

              struct rlimit l;

              memset(&l, 0, sizeof(l));

              l.rlim_cur = RLIM_INFINITY;

              l.rlim_max = RLIM_INFINITY;

              if (setrlimit(RLIMIT_CORE, &l)) {

                     ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n", strerror(errno));

              }

       }

/*修改用户和组权限*/

       if ((!rungroup) && !ast_strlen_zero(ast_config_AST_RUN_GROUP))

              rungroup = ast_config_AST_RUN_GROUP;

       if ((!runuser) && !ast_strlen_zero(ast_config_AST_RUN_USER))

              runuser = ast_config_AST_RUN_USER;

#ifndef __CYGWIN__

       if (isroot)

              ast_set_priority(ast_opt_high_priority);

       if (isroot && rungroup) {

              struct group *gr;

              gr = getgrnam(rungroup);

              if (!gr) {

                     ast_log(LOG_WARNING, "No such group '%s'!\n", rungroup);

                     exit(1);

              }

              if (setgid(gr->gr_gid)) {

                     ast_log(LOG_WARNING, "Unable to setgid to %d (%s)\n", (int)gr->gr_gid, rungroup);

                     exit(1);

              }

              if (setgroups(0, NULL)) {

                     ast_log(LOG_WARNING, "Unable to drop unneeded groups\n");

                     exit(1);

              }

              if (option_verbose)

                     ast_verbose("Running as group '%s'\n", rungroup);

       }

       if (runuser && !ast_test_flag(&ast_options, AST_OPT_FLAG_REMOTE)) {

#ifdef HAVE_CAP

              int has_cap = 1;

#endif /* HAVE_CAP */

              struct passwd *pw;

              pw = getpwnam(runuser);

              if (!pw) {

                     ast_log(LOG_WARNING, "No such user '%s'!\n", runuser);

                     exit(1);

              }

#ifdef HAVE_CAP

              if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0)) {

                     ast_log(LOG_WARNING, "Unable to keep capabilities.\n");

                     has_cap = 0;

              }

#endif /* HAVE_CAP */

              if (!isroot && pw->pw_uid != geteuid()) {

                     ast_log(LOG_ERROR, "Asterisk started as nonroot, but runuser '%s' requested.\n", runuser);

                     exit(1);

              }

              if (!rungroup) {

                     if (setgid(pw->pw_gid)) {

                            ast_log(LOG_WARNING, "Unable to setgid to %d!\n", (int)pw->pw_gid);

                            exit(1);

                     }

                     if (isroot && initgroups(pw->pw_name, pw->pw_gid)) {

                            ast_log(LOG_WARNING, "Unable to init groups for '%s'\n", runuser);

                            exit(1);

                     }

              }

              if (setuid(pw->pw_uid)) {

                     ast_log(LOG_WARNING, "Unable to setuid to %d (%s)\n", (int)pw->pw_uid, runuser);

                     exit(1);

              }

              if (option_verbose)

                     ast_verbose("Running as user '%s'\n", runuser);

#ifdef HAVE_CAP

              if (has_cap) {

                     cap_t cap;

                     cap = cap_from_text("cap_net_admin=ep");

                     if (cap_set_proc(cap))

                            ast_log(LOG_WARNING, "Unable to install capabilities.\n");

                     if (cap_free(cap))

                            ast_log(LOG_WARNING, "Unable to drop capabilities.\n");

              }

#endif /* HAVE_CAP */

       }

#endif /* __CYGWIN__ */

#ifdef linux

       if (geteuid() && ast_opt_dump_core) {

              if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) < 0) {

                     ast_log(LOG_WARNING, "Unable to set the process for core dumps after changing to a non-root user. %s\n", strerror(errno));

              }   

       }

#endif

/*初始化模拟终端ast_term_init(),默认是VT100*/

       ast_term_init();

       printf(term_end());

       fflush(stdout);

       if (ast_opt_console && !option_verbose)

              ast_verbose("[ Initializing Custom Configuration Options ]\n");

       /* custom config setup */

/*注册命令core show config mappings*/

       register_config_cli();

/*配置文件的映射和绑定*/

       read_config_maps();

       if (ast_opt_console) {

              if (el_hist == NULL || el == NULL)

                     ast_el_initialize();

              if (!ast_strlen_zero(filename))

                     ast_el_read_history(filename);

       }

/*设置和检查本地或远程终端的连接*/

       if (ast_tryconnect()) {

              /* One is already running */

              if (ast_opt_remote) {

                     if (ast_opt_exec) {

                            ast_remotecontrol(xarg);

                            quit_handler(0, 0, 0, 0);

                            exit(0);

                     }

                     printf(term_quit());

                     ast_remotecontrol(NULL);

                     quit_handler(0, 0, 0, 0);

                     exit(0);

              } else {

                     ast_log(LOG_ERROR, "Asterisk already running on %s.  Use 'asterisk -r' to connect.\n", ast_config_AST_SOCKET);

                     printf(term_quit());

                     exit(1);

              }

       } else if (ast_opt_remote || ast_opt_exec) {

              ast_log(LOG_ERROR, "Unable to connect to remote asterisk (does %s exist?)\n", ast_config_AST_SOCKET);

              printf(term_quit());

              exit(1);

       }

       /* Blindly write pid file since we couldn't connect */

       unlink(ast_config_AST_PID);

       f = fopen(ast_config_AST_PID, "w");

       if (f) {

              fprintf(f, "%ld\n", (long)getpid());

              fclose(f);

       } else

              ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", ast_config_AST_PID, strerror(errno));

#if HAVE_WORKING_FORK

       if (ast_opt_always_fork || !ast_opt_no_fork) {

#ifndef HAVE_SBIN_LAUNCHD

              daemon(1, 0);

              ast_mainpid = getpid();

              /* Blindly re-write pid file since we are forking */

              unlink(ast_config_AST_PID);

              f = fopen(ast_config_AST_PID, "w");

              if (f) {

                     fprintf(f, "%ld\n", (long)ast_mainpid);

                     fclose(f);

              } else

                     ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", ast_config_AST_PID, strerror(errno));

#else

              ast_log(LOG_WARNING, "Mac OS X detected.  Use '/sbin/launchd -d' to launch with the nofork option.\n");

#endif

       }

#endif

       /* Test recursive mutex locking. */

/*测试线程安全,避免出现死锁*/

       if (test_for_thread_safety())

              ast_verbose("Warning! Asterisk is not thread safe.\n");

/*创建用于和控制台交互的服务器端socket接口*/

       ast_makesocket();

/*加入信号集,设置掩码,以及注册信号的相应handler */

       sigemptyset(&sigs);

       sigaddset(&sigs, SIGHUP);

       sigaddset(&sigs, SIGTERM);

       sigaddset(&sigs, SIGINT);

       sigaddset(&sigs, SIGPIPE);

       sigaddset(&sigs, SIGWINCH);

       pthread_sigmask(SIG_BLOCK, &sigs, NULL);

       signal(SIGURG, urg_handler);

       signal(SIGINT, __quit_handler);

       signal(SIGTERM, __quit_handler);

       signal(SIGHUP, hup_handler);

       signal(SIGCHLD, child_handler);

       signal(SIGPIPE, SIG_IGN);

       /* ensure that the random number generators are seeded with a different value every time

          Asterisk is started

       */

/*设置种子并初始化随机数发生器*/

       srand((unsigned int) getpid() + (unsigned int) time(NULL));

       initstate((unsigned int) getpid() * 65536 + (unsigned int) time(NULL), randompool, sizeof(randompool));

/*初始化日志模块*/

       if (init_logger()) {

              printf(term_quit());

              exit(1);

       }

#ifdef HAVE_ZAPTEL

       {

              int fd;

              int x = 160;

              fd = open("/dev/zap/timer", O_RDWR);

              if (fd >= 0) {

                     if (ioctl(fd, ZT_TIMERCONFIG, &x)) {

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

                            exit(1);

                     }

                     if ((x = ast_wait_for_input(fd, 300)) < 0) {

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

                            exit(1);

                     }

                     if (!x) {

                            const char zaptel_timer_error[] = {

                                   "Asterisk has detected a problem with your Zaptel configuration and will shutdown for your protection.  You have options:"

                                   "\n\t1. You only have to compile Zaptel support into Asterisk if you need it.  One option is to recompile without Zaptel support."

                                   "\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."

                                   "\n\t3. If you need Zaptel services, you must correctly configure Zaptel."

                            };

                            ast_log(LOG_ERROR, "%s\n", zaptel_timer_error);

                            exit(1);

                     }

                     close(fd);

              }

       }

#endif

/*注册threadstorage show allocations和threadstorage show summary这两个命令*/

       threadstorage_init();

       astobj2_init();

       ast_autoservice_init();

/*加载配置文件/etc/asterisk/modules.conf中标记为preload的模块,再去掉标记为noload的模块*/

       if (load_modules(1)) {

              printf(term_quit());

              exit(1);

       }

/* DNS manager的初始化*/

       if (dnsmgr_init()) {

              printf(term_quit());

              exit(1);

       }

/*配置http服务器*/

       ast_http_init();

/*注册两个命令core show channeltypes和core show channeltype */

       ast_channels_init();

/*注册管理命令*/

       if (init_manager()) {

              printf(term_quit());

              exit(1);

       }

/*用来创建一个调度上下文以及注册相应的命令,然后用do_reload来读取配置文件cdr.conf和创建后台线程do_cdr */

       if (ast_cdr_engine_init()) {

              printf(term_quit());

              exit(1);

       }

/*用来创建一个后台线程轮巡设备的状态,如果发生变化则及时通告*/

       if (ast_device_state_engine_init()) {

              printf(term_quit());

              exit(1);

       }

/*注册rtp,rtcp,stun相关的CLI命令,然后调用ast_rtp_reload()读取配置文件rtp.conf,设置相关参数*/

       ast_rtp_init();

/*注册udptl相关的CLI命令,然后调用ast_udptl_reload()读取配置文件udptl.conf,设置相关参数*/

       ast_udptl_init();

/*注册core show image formats */

       if (ast_image_init()) {

              printf(term_quit());

              exit(1);

       }

/*注册core show file formats */

       if (ast_file_init()) {

              printf(term_quit());

              exit(1);

       }

/*注册dialplan相关的CLI命令,然后调用ast_register_application来注册所有的app */

       if (load_pbx()) {

              printf(term_quit());

              exit(1);

       }

/*注册与codec相关的CLI命令*/

       if (init_framer()) {

              printf(term_quit());

              exit(1);

       }

/*注册与database相关的CLI命令,然后再注册两个管理命令DBGet和DBPut */

       if (astdb_init()) {

              printf(term_quit());

              exit(1);

       }

/*读取配置文件enum.conf,初始化支持ENUM(e164)的子系统*/

       if (ast_enum_init()) {

              printf(term_quit());

              exit(1);

       }

/* load_modules(0)加载所有其它需要加载的动态链接库*/

       if (load_modules(0)) {

              printf(term_quit());

              exit(1);

       }

       dnsmgr_start_refresh();

       /* We might have the option of showing a console, but for now just

          do nothing... */

       if (ast_opt_console && !option_verbose)

              ast_verbose(" ]\n");

       if (option_verbose || ast_opt_console)

              ast_verbose(term_color(tmp, "Asterisk Ready.\n", COLOR_BRWHITE, COLOR_BLACK, sizeof(tmp)));

       if (ast_opt_no_fork)

              consolethread = pthread_self();

/*创建管道*/

       if (pipe(sig_alert_pipe))

              sig_alert_pipe[0] = sig_alert_pipe[1] = -1;

       ast_set_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED);

       pthread_sigmask(SIG_UNBLOCK, &sigs, NULL);

#ifdef __AST_DEBUG_MALLOC

       __ast_mm_init();

#endif   

       time(&ast_startuptime);

/*注册asterisk相关的命令,比如stop,restart,halt等等*/

       ast_cli_register_multiple(cli_asterisk, sizeof(cli_asterisk) / sizeof(struct ast_cli_entry));

       if (ast_opt_console) {

              /* Console stuff now... */

              /* Register our quit function */

              char title[256];

              pthread_attr_t attr;

              pthread_t dont_care;

/*创建线程,轮询上面创建的sig_alert_pipe管道*/

              pthread_attr_init(&attr);

              pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

              ast_pthread_create(&dont_care, &attr, monitor_sig_flags, NULL);

              pthread_attr_destroy(&attr);

              set_icon("Asterisk");

              snprintf(title, sizeof(title), "Asterisk Console on '%s' (pid %ld)", hostname, (long)ast_mainpid);

              set_title(title);

/*接收和处理控制台命令*/

              for (;;) {

                     buf = (char *)el_gets(el, &num);

                     if (!buf && write(1, "", 1) < 0)

                            goto lostterm;

                     if (buf) {

                            if (buf[strlen(buf)-1] == '\n')

                                   buf[strlen(buf)-1] = '\0';

                            consolehandler((char *)buf);

                     } else if (ast_opt_remote && (write(STDOUT_FILENO, "\nUse EXIT or QUIT to exit the asterisk console\n",

                               strlen("\nUse EXIT or QUIT to exit the asterisk console\n")) < 0)) {

                            /* Whoa, stdout disappeared from under us... Make /dev/null's */

                            int fd;

                            fd = open("/dev/null", O_RDWR);

                            if (fd > -1) {

                                   dup2(fd, S

分享到:
评论

相关推荐

    最全Asterisk代码学习笔记

    3. **内核框架**:Asterisk的内核负责处理基本的通话处理和信号处理,包括SIP、IAX2等通信协议的解析和处理。它还包含事件循环机制,用于处理异步事件。 4. **配置文件参数读取**:Asterisk通过读取配置文件(如`...

    Asterisk内核研发笔记

    Asterisk,是当今最流行的开源电话平台,这篇文档详细阐述了其内核的研发,希望对大家有帮助

    Asterisk 简介 Asterisk 架构 Asterisk程序框图

    Asterisk是一款开源的电话交换机软件,它允许用户创建高度自定义的通信系统,包括VoIP(Voice over IP)电话、会议桥、自动呼叫分配(ACD)以及许多其他电信功能。Asterisk的核心设计理念是灵活性和可扩展性,这使得...

    Asterisk 之数据库配置方案 asterisk数据库

    Asterisk 之数据库配置方案 Asterisk 是一个开源的 PBX(Private Branch Exchange)系统,可以实现电话交换和语音网关的功能。在传统的 Asterisk 配置中,配置文件都是存储在文件系统中的,但是随着系统的复杂度和...

    通过asterisk-java操作asterisk

    Asterisk是一个开源的IP电话系统,而Asterisk-java则是一个Java库,它提供了与Asterisk服务器交互的能力。这个库使得开发者可以利用Java语言来控制和编程Asterisk PBX(Private Branch eXchange),执行诸如创建、...

    asterisk学习资料

    资料包含: ...Asterisk核心框架.docx Asterisk核心框架.pdf asterisk目录结构.txt 基于Asterisk的VoIP开发指南--Asterisk_AGI程序编写指南.docx 基于SIP协议的ASTERISK_VOIP服务器研究-综合课程设计.doc

    Asterisk.NET 1.6.3 控制Asterisk

    Asterisk.NET 1.6.3 是一个专门为.NET开发者设计的开源库,它提供了对Asterisk PBX系统的编程接口,使得用户可以方便地在C#、VB.NET或其他.NET支持的语言中控制和扩展Asterisk功能。这个库是基于Asterisk Manager ...

    Asterisk权威指南中文

    Asterisk权威指南中文(第3版) Asterisk权威指南(第3版)第15章自动话务员 Asterisk权威指南(第3版)第02章Asterisk体系结构 Asterisk权威指南(第3版)第05章用户设备配置 Asterisk权威指南(第3版)第06章Dialplan基础 ...

    Asterisk AMI 接口代码

    Asterisk AMI(Asterisk Manager Interface)接口是Asterisk PBX系统提供的一种用于远程管理和监控的强大工具。这个接口允许开发者通过编程方式与Asterisk进行交互,执行诸如控制呼叫、获取状态、监听通话等多种操作...

    asterisk16版本安装包

    Asterisk是一款开源的IP电话系统,用于构建VoIP(Voice over Internet Protocol)通信平台。在本场景中,我们讨论的是Asterisk的16版本安装包,这将引导我们深入理解Asterisk的核心功能、安装流程以及如何进行编译和...

    asterisk info 录音实现方案

    标签“asterisk record”指的是与Asterisk录音相关的配置和功能,它表明文章将围绕如何在Asterisk中设置和实现录音功能。 在提供的部分内容中,提到了几个关键的配置文件和步骤,这些是实现Asterisk录音功能的核心...

    asterisk 参考手册(Asterisk Administrator Guide)

    “AsteriskSecurityFramework”(Asterisk安全框架)部分详细介绍了Asterisk的安全机制,包括安全事件的生成、日志记录等。这对于确保Asterisk系统的安全性和合规性至关重要。 整个手册不仅提供了安装和配置方面的...

    Ubuntu16.0.4环境下的Asterisk安装经验

    这些库包括但不限于Linux内核头文件、构建工具、自动化工具、库文件等。下面是一些基本的依赖库及其安装命令: ```bash sudo apt-get update sudo apt-get install -y linux-headers-$(uname -r) build-essential ...

    Asterisk 中文语音包

    Asterisk是一款开源的IP电话系统,它允许用户创建自己的通信平台,支持VoIP(Voice over IP)服务,包括电话会议、语音邮件和IVR(Interactive Voice Response)等。中文语音包是为Asterisk系统设计的一个关键组件,...

    asterisk 七号信令 模块

    9. `lffifo.c`:低级文件I/O缓冲区的实现,可能用于在内核级别处理SS7数据的输入和输出。 10. `utils.c`:通用工具函数,提供辅助功能,如错误处理、内存管理或数据转换,对其他模块进行支持。 通过这些文件,我们...

    Asterisk一些常用的命令

    Asterisk命令详解 Asterisk是一款开源的电话交换机软件,提供了丰富的命令来管理和控制电话系统。下面是Asterisk的一些常用的命令: 1. amportal 命令 amportal 命令是FreePBX搞的,负责管控Asterisk。amportal ...

    asterisk 视频通讯实现方法

    Asterisk是一款开源的PBX(Private Branch Exchange)软件,专用于实现VoIP(Voice over IP)通信。在本文中,我们将深入探讨如何利用Asterisk实现视频通讯功能。实现Asterisk视频通讯的关键在于配置sip.conf文件...

    Asterisk 中文文档说明

    Asterisk是一款强大的开源通信平台,它被广泛用于构建VoIP(Voice over Internet Protocol)电话系统,SIP(Session Initiation Protocol)服务器以及各种通信应用。这个“Asterisk中文文档说明”涵盖了从基础概念到...

    asterisk AGI应用说明

    ### Asterisk AGI应用详解 #### 一、概述 Asterisk是世界上最流行的开源PBX系统之一,它支持多种通信协议并提供了丰富的功能。在Asterisk中,AGI(Asterisk Gateway Interface)是一种非常重要的接口技术,它允许...

    Asterisk 客户端.rar

    Asterisk是一款开源的IP电话系统,用于构建VoIP网络通信基础设施。它的功能强大,能够支持PBX(Private Branch Exchange)、VoIP网关、呼叫中心和许多其他电信应用。在这个"Asterisk客户端.rar"压缩包中,我们主要...

Global site tag (gtag.js) - Google Analytics