`

Asterisk Kernel analysis 1

 
阅读更多

一、内核初始化。

 

 main入口。Asterisk.c  进入内核。

 

 

对于重启,记录上一次main函数传过来的命令,

 

/* Remember original args for restart */

      if (argc > ARRAY_LEN(_argv) - 1) {

           fprintf(stderr, "Truncating argument size to %d/n", (int)ARRAY_LEN(_argv) - 1);

           argc = ARRAY_LEN(_argv) - 1;

      }

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

           _argv[x] = argv[x];

      _argv[x] = NULL;

 

获取主机名,失败则设置为unknown.

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

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

      ast_mainpid = getpid();

 

初始化各种语音编码,

ast_ulaw_init();

      ast_alaw_init();

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

      callerid_init();

      ast_builtins_init();

      ast_utils_init();

      tdd_init();

ast_tps_init(); // 启动业务处理引擎,1.8新增,

      ast_fd_init();

 

解析启动参数

/* Check for options */

      while ((c = getopt(argc, argv, "mtThfdvVqprRgciInx: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;

 

 

 

注册控制台打印函数,,,

 

ast_readconfig(); //读取主配置文件asterisk.conf并根据配置初始化系统各种参数。

 

这里对asterisk配置文件的读取及解析实现做一下解释。

 

Asterisk配置文件以.conf结尾,当然了,解析文件引擎不考虑文件格式。

 

这里有两个结构,一个为 struct ast_config

 

struct ast_config {

      struct ast_category *root;

      struct ast_category *last;

      struct ast_category *current;

      struct ast_category *last_browse;         /*!< used to cache the last category supplied via category_browse */

      int include_level;

      int max_include_level;

    struct ast_config_include *includes;  /*!< a list of inclusions, which should describe the entire tree */

};

 

此结构读取一个文件,同时文件可以包含另一个文件,按目录保存,这里的目录用【xx】格式表示,

 asterisk.conf文件的[options]目录

;verbose = 3

;debug = 3

;alwaysfork = yes           ; Same as -F at startup.

nofork = yes 

单个目录用结构struct ast_category表示, 每个目录下包含注释,变量,

如上面的;verbose = 3

;debug = 3

即为注释,用struct ast_comment表示,

nofork = yes   

为变量, struct ast_variable 表示,是个名值对。

 

Asterisk配置文件解析过程,

1.调用ast_config_load2(文件名,falgs)读取文件,返回指向ast_config

的指针 cfg

2.调用ast_variable_browse(cfg, "catogery_name"),访问文件的一个目录,如上面的【options】即为一个目录,ast_variable_browse()返回目录下的一个名值对,用结构ast_variable表示,

struct ast_variable *v;

for (v = ast_variable_browse(cfg, "directories"); v; v = v->next)

循环遍历directories目录下面的变量,包含变量名及变量值,即可访问到真实的设置值。(!strcasecmp(v->name, "astctlgroup"))

 

文件解析完毕后调用 ast_category_destroy释放内存。

 

 

接下来 设置fd上限,对于select系统调用,linux上一个进程最多打开1024fd

 

sigaction(SIGCHLD, &child_handler, NULL); 注册 信号处理函数。

 

 

/* custom config setup */

注册控制台命令

register_config_cli();

//读取extconfig.conf文件,映射realtime到具体数据库引擎,表。。。

 

read_config_maps();

此函数内部,解析extconfig.conf文件,解析settings目录,

找数据库引擎,数据库表。

这里,如果你的数据库表为sipfriends则会提示不要用这个表,同时用sipuserssippeers表,替换。

最终调用append_mapping 完成数据库表的映射。映射关系用结构struct ast_config_map 表示,此结构内部保存数据库引擎,数据库表名字等。

 

映射玩之后 接下来调用ast_tryconnect连接远程Asterisk Server.

 

启动子进程或线程处理日历功能,1.8新增。

ast_pthread_create_detached(&dont_care, NULL, canary_thread, NULL);此线程每隔一分钟扫描一次日历文件。

 

/* Kill the canary when we exit */

         ast_register_atexit(canary_exit);

注册退出处理函数。struct ast_atexit 描述了注册信息,所有注册退出回调函数保存到atexits链表中。

struct ast_atexit {

     void (*func)(void);

     AST_RWLIST_ENTRY(ast_atexit) list;

};

static AST_RWLIST_HEAD_STATIC(atexits, ast_atexit);

 

接下来执行

if (ast_event_init()) {

         printf("%s", term_quit());

         exit(1);

     }

初始化asterisk事件引擎。这里事件引擎为新增内容,系统事件包括响铃,接听,等待等等一系列事件,事件包括类型,对应回调等,事件跟业务引擎结合。

 

接下来调用ast_makesocket 启动服务器登陆监听socket,处理远程cli连接。注册远程cli处理回调函数,

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

if (ast_register_verbose(network_verboser)) {

         ast_log(LOG_WARNING, "Unable to register network verboser?/n");

     }

 

绑定后创建线程处理所有客户端连接

ast_pthread_create_background(&lthread, NULL, listener, NULL);,

此线程负责接收所有连接,具体读写则创建线程netconsole处理。

 

/*设置种子并初始化随机数发生器*/
 
        srand((unsigned int) getpid() + (unsigned int) time(NULL));
 
        initstate((unsigned int) getpid() * 65536 + (unsigned int) time(NULL), randompool, sizeof(randompool));
  

if (init_logger()) {        /* Start logging subsystem */

         printf("%s", term_quit());

         exit(1);

     }

 

初始化logger系统。创建线程logger_thread,处理message链表。取出一条消息,调用logger_print_normal 处理此消息,根据消息类型分派给不同函数处理。如控制台,文件,syslog。。。

线程存储初始化,调试时提供线程信息

threadstorage_init();

Asterisk大对象类型初始化,实际上此类型为简化结构的内存分配及回收,通过引用计数来控制内存的回收,分配内存时即指定回调函数,这样不必考虑何时释放内存,同时,大对象的查找等通过hash查找,效率很高。

     astobj2_init();

 

下面函数

ao2_t_alloc(arg1, arg2, arg3)

ao2_t_ref(arg1,arg2,arg3)

ao2_t_container_alloc(arg1,arg2,arg3,arg4)

ao2_t_link(arg1, arg2, arg3)

ao2_t_unlink(arg1, arg2, arg3)

ao2_t_callback(arg1,arg2,arg3,arg4,arg5)

ao2_t_find(arg1,arg2,arg3,arg4)

ao2_t_iterator_next(arg1, arg2)

提供了操作大对象的方式,包括内存分配,引用计数增减,把对象放入哈希表,查找,遍历对象。

同时提供了debug 大对象接口REF_DEBUG。这些函数在sip协议栈及队列实现中都有所体现。

接下来初始化自服务引擎,此引擎的作用是监听channel上的事件,比如坐席接听后,此引擎负责监听双方的按键,根据按键走不通流程。

     ast_autoservice_init();

初始化定时器引擎。。,1.6开始才有,以前都用dahdi提供定时器,如meetme,提供三个实现

res_timing_pthread.so

res_timing_dahdi.so res_timing_timerfd.so (Beginning with Asterisk 1.6.2)

 

ast_timing_init

 

接下来if (ast_ssl_init()) {

         printf("%s", term_quit());

         exit(1);

     }

 

#ifdef AST_XML_DOCS

     /* Load XML documentation. */

     ast_xmldoc_load_documentation();

#endif

初始化sslxml_doc系统。

 

ast_channels_init();初始化channel 内存池,

 

if ((moduleresult = load_modules(1))) {     /* Load modules, pre-load only */

         printf("%s", term_quit());

         exit(moduleresult == -2 ? 2 : 1);

     }

 

加载模块,

int dnsmgr_init(void)//初始化dns管理引擎,创建调度器。

 

ast_http_init();    初始化asterisk http引擎。

if (init_manager()) {

         printf("%s", term_quit());

         exit(1);

     } 

初始化ami引擎,

if (ast_cdr_engine_init()) {

         printf("%s", term_quit());

         exit(1);

     }

Cdr引擎初始化。

 

if (ast_cel_engine_init()) {

         printf("%s", term_quit());

         exit(1);

     }

 

Cel引擎初始化。

if (ast_device_state_engine_init()) {

         printf("%s", term_quit());

         exit(1);

     }

设备状态引擎初始化。

设备有下面状态。

/*! /brief Device state strings for printing */

static const char * const devstatestring[][2] = {

       { /* 0 AST_DEVICE_UNKNOWN */     "Unknown",     "UNKNOWN"     }, /*!< Valid, but unknown state */

       { /* 1 AST_DEVICE_NOT_INUSE */   "Not in use",  "NOT_INUSE"   }, /*!< Not used */

       { /* 2 AST_DEVICE IN USE */      "In use",      "INUSE"       }, /*!< In use */

       { /* 3 AST_DEVICE_BUSY */        "Busy",        "BUSY"        }, /*!< Busy */

       { /* 4 AST_DEVICE_INVALID */     "Invalid",     "INVALID"     }, /*!< Invalid - not known to Asterisk */

       { /* 5 AST_DEVICE_UNAVAILABLE */ "Unavailable", "UNAVAILABLE" }, /*!< Unavailable (not registered) */

       { /* 6 AST_DEVICE_RINGING */     "Ringing",     "RINGING"     }, /*!< Ring, ring, ring */

       { /* 7 AST_DEVICE_RINGINUSE */   "Ring+Inuse",  "RINGINUSE"   }, /*!< Ring and in use */

       { /* 8 AST_DEVICE_ONHOLD */      "On Hold",      "ONHOLD"      }, /*!< On Hold */

};

 

关于设备状态,可以用来做全局排队,

int ast_device_state_engine_init(void)

{

       ast_cond_init(&change_pending, NULL);

       if (ast_pthread_create_background(&change_thread, NULL, do_devstate_changes, NULL) < 0) {

              ast_log(LOG_ERROR, "Unable to start device state change thread./n");

              return -1;

       }

 

       return 0;

}

 

初始化设备状态引擎创建一个线程,do_devstate_changes,此线程扫描设备状态队列,然后调用

do_state_change(current->device); 处理此设备状态,do_state_change 内部,调用_ast_device_state,获取设备的当前状态,获取状态后调用devstate_event(device, state);发射设备状态改变事件。_ast_device_state 内部获取状态有两种方式,一种为通道提供获取设备状态回调函数,另一种为通用状态获取。

 

 

if (load_pbx()) {

              printf("%s", term_quit());

              exit(1);

       }

初始化pbx引擎。注册pbx内嵌函数,如ast_answer,ast_hangup等。

 

/*! /brief Load indications module */

int ast_indications_init(void)

初始化indications引擎,此模块是一些时区,语言类型的初始化。

 

ast_features_init(); features引擎初始化,此模块为

 

int astdb_init(void) 初始化astdb,本地数据库引擎,开启一个线程处理数据库动作。

 

 

if (ast_enum_init()) {          //枚举引擎初始化。

              printf("%s", term_quit());

              exit(1);

       }

 

       if (ast_cc_init()) {   call completetion 模块初始化,1.8新增。

              printf("%s", term_quit());

              exit(1);

       }

 

 

if ((moduleresult = load_modules(0))) {        /* Load modules */

              printf("%s", term_quit());

              exit(moduleresult == -2 ? 2 : 1);

       }

 

加载动态模块,包括sip协议栈,队列,等等一些列可配置模块。

 

 

ast_stun_init(); 初始化 nat穿透模块。

run_startup_commands(); 解析cli.conf,处理启动时执行的命令,同时接受控制台命令。

分享到:
评论

相关推荐

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

    1.Asterisk 是一个开源的 PBX 系统,可以实现电话交换和语音网关的功能。 2. 将配置从配置文件迁移到数据库中可以提高系统的可靠性和可扩展性,并且可以简化配置的管理和维护。 3. Kamailio 是一个 SIP 服务器,...

    Asterisk 简介 Asterisk 架构 Asterisk程序框图

    1. **通道驱动**:负责处理与不同类型的通信设备或网络协议的连接,例如SIP、PSTN(公共交换电话网络)或者模拟电话线。 2. **拨号计划**:定义了如何路由和处理呼叫,可以基于来电号码、时间、目的地等因素进行...

    通过asterisk-java操作asterisk

    1. **登录到Asterisk Manager**:使用Asterisk-java,你可以创建一个`ManagerConnection`对象,输入Asterisk服务器的IP地址、端口号、用户名和密码,然后调用`connect()`方法连接到服务器。一旦连接成功,你就可以...

    Asterisk权威指南中文

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

    Asterisk.NET 1.6.3 控制Asterisk

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

    Asterisk 中文文档说明

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

    Asterisk AMI 接口代码

    1. **呼叫控制**:挂断、接听、转移、录音、播放音频文件等。 2. **状态查询**:获取通道、队列、扩展的状态信息。 3. **事件监听**:订阅并接收Asterisk产生的各种事件,如新呼叫、呼叫状态变化等。 4. **配置管理*...

    asterisk16版本安装包

    1. **Asterisk核心功能**: - **PBX(Private Branch Exchange)**:Asterisk作为一款软交换系统,可以替代传统的PBX设备,实现电话分机间的通话,并与外部网络连接。 - **语音会议**:支持多用户参与的电话会议,...

    asterisk code1

    asterisk code1asterisk code1asterisk code1asterisk code1asterisk code1asterisk code1asterisk code1asterisk code1asterisk code1asterisk code1asterisk code1asterisk code1asterisk code1

    Asterisk 中文语音包

    1. **下载与安装**:首先,你需要从可靠源下载"hiastar_Asterisk中文配音包"。下载完成后,将压缩文件解压到Asterisk系统的适当目录,通常是`/var/lib/asterisk/sounds/cn`或类似路径,具体路径取决于你的Asterisk...

    asterisk info 录音实现方案

    1. features.conf文件配置:通过这个文件可以定义如何使用DTMF信号触发录音的开始和结束。需要配置如startMonitor和stopMonitor这样的命令来响应DTMF信号,从而控制录音。这里的宏(Macro)是自定义的脚本,用于控制...

    asterisk 视频通讯实现方法

    1. `videosupport=yes`:这行代码是开启视频支持的关键,它告诉Asterisk应该处理视频流。 2. `maxcallbitrate=384`:这个参数设定了最大呼叫比特率,单位通常是kbps。这里设置为384kbps,意味着你的视频通话质量将...

    asterisk AGI应用说明

    1. **脚本完整路径**:如果AGI脚本位于Asterisk的默认路径中,可以仅提供文件名。 2. **拨号计划中的EXTEN参数**:这是AGI脚本期望从拨号计划中接收到的参数。 #### 三、AGI脚本与Asterisk的通信 ##### 3.1 发送...

    asterisk 教程

    1. `gcc3.x`:C语言编译器,用于编译Asterisk源码。 2. `bison`:用于解析`extensions.conf`文件中的表达式,它作为`yacc`的替代品,同时也服务于Asterisk的CLI(命令行界面)。 3. `OpenSSL`:提供加密功能,对VoIP...

    20120412_Asterisk录音记录(SQLServer)1

    Asterisk录音记录(SQLServer)1 在Asterisk PBX系统中,录音记录是非常重要的功能,它允许管理员和用户追踪通话记录以便于分析、审计或存档。本篇文章将介绍如何利用SQL Server来存储Asterisk的录音记录,并对其进行...

    asterisk 学习日志

    1. **Asterisk调试与日志记录**: 在学习Asterisk时,使用命令`asterisk -vvvg –cps -C`可以开启更详细的调试模式,这对于排查问题和理解系统运行状态非常有帮助。同时,了解如何阅读和分析日志文件(如`backtrace...

    最全Asterisk代码学习笔记

    1. **Asterisk版本差异**:Asterisk经历了多个版本的迭代,如1.2、1.4、1.8等。每个版本都有其特定的改进和增强,例如性能优化、新特性的引入和对协议的支持。例如,1.4版本引入了更强大的DialPlan和更好的SIP支持。...

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

    ### Ubuntu16.0.4环境下Asterisk安装经验 #### 概述 本文将详细介绍如何在Ubuntu 16.0.4系统上安装Asterisk。Asterisk是一款非常强大的开源PBX(Private Branch Exchange)系统,它可以将普通的计算机变成一个功能...

    Asterisk系统的安装与配置

    1. tar zxvf asterisk-1.8.7.1.tar.gz 2. cd asterisk-1.8.7.1 3. ./configure --build=i386 4. make menuselect 5. make 6. make install 安装完成后,需要安装配置文件模板: 7. make samples 8. make progdocs ...

    Asterisk一些常用的命令

    1. amportal 命令 amportal 命令是FreePBX搞的,负责管控Asterisk。amportal start 启动Asterisk,amportal restart 重启Asterisk,amportal stop 关闭Asterisk。 2. asterisk 命令 asterisk 命令可以启动...

Global site tag (gtag.js) - Google Analytics