Featured image of post libresbc实现原理

libresbc实现原理

介绍

上一章我们介绍了libresbc的部署方式以及使用webui查看配置页面, 本章我们介绍一下libresbc原理。

架构

libresbc的架构图如下:

libresbc 架构图

  • webui: 这块是源码中的webui目录下的golang程序, 用于查看和配置libresbc的参数。

  • main.py: 在源码中的liberator/main.pylibresbc的主程序, 具有一下功能:

    • 监听http请求, 把配置参数保存到redis中。
    • 启动freeswitch进程, 建立ESL 连接, 用于接收freeswitch的事件。
    • 发布/订阅redis事件, 接收到事件之后,通知freeswitch进行相应的操作。
    • 接收redis的cdr事件, 然后写文件或者发送到第三方的http server
  • nftables: 这个是防火墙,用于设置黑白名单拦截,如果libresbc是容器部署的,那么nftables不起作用。

  • freeswitch: 这里的freeswitch用作sip server管理,可以设置sip profile,gateway等。

  • kamailio: 只有在页面设置了Connections->Access Service, 才会启动kamailio进程, kamailio使用的是kami功能。 kamailio没配置媒体代理,所以只能转sip协议, 不能转rtp协议。

另外, liberator目录下的*.j2.*文件,会被替换成对应的配置文件。

配置解析

libresbc关于freeswitch的重要配置是liberator/fscfg/xml/freeswitch.xml, 它把freeswitchacl,diaplan,gateway都写到了一个.xml中,这里是完整的配置。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
<?xml version="1.0"?>
<document type="freeswitch/xml">
  <X-PRE-PROCESS cmd="set" data="preprocess_exec=true"/>
  <X-PRE-PROCESS cmd="exec-set" data="fsxmlapi=(echo ${LIBERATOR_CFGAPI_URL:-http://127.0.0.1:8080/cfgapi/fsxml})"/>
  <X-PRE-PROCESS cmd="exec-set" data="nodeid=(echo ${NODEID:-{{NODEID}}})"/>
  <X-PRE-PROCESS cmd="exec-set" data="loglevel=(echo ${LOGLEVEL:-INFO})"/>
  <X-PRE-PROCESS cmd="exec-set" data="eslhost=(echo ${ESLHOST:-{{eslhost}}})"/>
  <X-PRE-PROCESS cmd="exec-set" data="eslport=(echo ${ESLPOST:-{{eslport}}})"/>
  <X-PRE-PROCESS cmd="exec-set" data="eslpassword=(echo ${ESLPASSWORD:-{{eslpassword}}})"/>
  <X-PRE-PROCESS cmd="set" data="hold_music={loops=-1}tone_stream://%(250,0,350);%(250,0,440);%(250,0,530);%(300,0,700);%(400,0,800);%(300,0,900);%(250,0,600);%(160,0,440)"/>
  <X-PRE-PROCESS cmd="set" data="devshm=/dev/shm"/>
  <!-- BEGIN: CONFIGURATION SECTION -->
  <section name="configuration" description="Various Configuration">
    <!-- ACL ACCESS CONTROL LIST -->
    <configuration name="acl.conf" description="Network Lists">
      <network-lists>
        <X-PRE-PROCESS cmd="exec" data="curl -so $${devshm}/acl $${fsxmlapi}/acl"/>
        <X-PRE-PROCESS cmd="include" data="$${devshm}/acl"/>
        <list name="loopback.auto" default="deny">
          <node type="allow" cidr="127.0.0.1/32"/>
          <node type="allow" cidr="::1/128"/>
       </list>
      </network-lists>
    </configuration>
    <!-- CONSOLE LOGGER -->
    <configuration name="console.conf" description="Console Logger">
      <mappings>
        <map name="all" value="console,debug,info,notice,warning,err,crit,alert"/>
      </mappings>
      <settings>
        <param name="colorize" value="false"/>
        <param name="loglevel" value="$${loglevel}"/>
      </settings>
    </configuration>
    <!-- DISTRIBUTOR -->
    <configuration name="distributor.conf" description="Distributor Configuration">
      <lists>
        <X-PRE-PROCESS cmd="exec" data="curl -so $${devshm}/distributor $${fsxmlapi}/distributor"/>
        <X-PRE-PROCESS cmd="include" data="$${devshm}/distributor"/>
      </lists>
    </configuration>
    <!-- EVENT SOCKET -->
    <configuration name="event_socket.conf" description="Socket Client">
      <settings>
        <param name="nat-map" value="false"/>
        <param name="listen-ip" value="$${eslhost}"/>
        <param name="listen-port" value="$${eslport}"/>
        <param name="password" value="$${eslpassword}"/>
      </settings>
    </configuration>
    <!--- LOGFILE -->
    <configuration name="logfile.conf" description="File Logging">
      <settings>
        <param name="rotate-on-hup" value="true"/>
      </settings>
      <profiles>
        <profile name="default">
          <settings>
            <!-- At this length in bytes rotate the log file (0 for never) -->
            <param name="rollover" value="104857600"/>
            	<!-- Maximum number of log files to keep before wrapping -->
              <!-- If this parameter is enabled, the log filenames will not include a date stamp -->
              <param name="maximum-rotate" value="32"/>
            <param name="uuid" value="true" />
          </settings>
          <mappings>
            <map name="all" value="console,info,notice,warning,err,crit,alert"/>
          </mappings>
        </profile>
      </profiles>
    </configuration>
    <!--- AWESOME LUA -->
    <configuration name="lua.conf" description="LUA Configuration">
      <settings>
        <!-- <param name="module-directory" value="/usr/share/lua/5.2/?.lua"/> -->
        <param name="startup-script" value="callng/event.initiation.lua"/>
        <hook event="CHANNEL_CREATE" script="callng/event.capacity.lua"/>
        <hook event="CHANNEL_UUID" script="callng/event.capacity.lua"/>
        <hook event="CHANNEL_DESTROY" script="callng/event.capacity.lua"/>
        <hook event="CHANNEL_HANGUP_COMPLETE" script="callng/event.cdr.lua"/>
        <hook event="STARTUP" script="callng/event.startup.lua"/>
        <hook event="CUSTOM" subclass="sofia::register_failure" script="callng/event.unauth.lua"/>
      </settings>
    </configuration>
    <!--- MODULES -->
    <configuration name="pre_load_modules.conf" description="Modules">
      <modules>
        <load module="mod_pgsql"/>
      </modules>
    </configuration>
    <configuration name="modules.conf" description="Modules">
      <modules>
        <load module="mod_console"/>
        <load module="mod_logfile"/>
        <load module="mod_event_socket"/>
        <load module="mod_bcg729"/>
        <load module="mod_amr"/>
        <load module="mod_amrwb"/>
        <load module="mod_spandsp"/>
        <load module="mod_sndfile"/>
        <load module="mod_tone_stream"/>
        <load module="mod_opus"/>
        <load module="mod_flite"/>
        <load module="mod_lua"/>
        <load module="mod_sofia"/>
        <load module="mod_distributor"/>
        <load module="mod_commands"/>
        <load module="mod_dptools"/>
        <load module="mod_dialplan_xml"/>
      </modules>
    </configuration>
    <!--- CODECS -->
    <configuration name="amr.conf">
      <settings>
        <param name="default-bitrate" value="7"/>
        <param name="volte" value="1"/>
        <param name="adjust-bitrate" value="0"/>
        <param name="force-oa" value="0"/>
      </settings>
    </configuration>
    <configuration name="amrwb.conf">
      <settings>
        <param name="default-bitrate" value="8"/>
        <param name="volte" value="1"/>
        <param name="adjust-bitrate" value="0"/>
        <param name="force-oa" value="0"/>
        <param name="mode-set-overwrite" value="0"/>
      </settings>
    </configuration>
    <configuration name="opus.conf">
      <settings>
        <param name="use-vbr" value="1"/>
        <param name="use-dtx" value="1"/>
        <param name="complexity" value="10"/>
        <param name="packet-loss-percent" value="10"/>
        <param name="keep-fec-enabled" value="1"/>
        <param name="use-jb-lookahead" value="1"/>
        <param name="maxaveragebitrate" value="64000"/>
        <param name="maxplaybackrate" value="48000"/>
        <param name="sprop-maxcapturerate" value="48000"/>
        <param name="adjust-bitrate" value="1"/>
      </settings>
    </configuration>
    <!--- SOFIA SIP -->
    <configuration name="sofia.conf" description="sofia Endpoint">
      <global_settings>
        <param name="log-level" value="0"/>
        <param name="debug-presence" value="0"/>
      </global_settings>
      <profiles>
        <X-PRE-PROCESS cmd="exec" data="curl -so $${devshm}/sipsetting $${fsxmlapi}/sip-setting/$${nodeid}" />
        <X-PRE-PROCESS cmd="include" data="$${devshm}/sipsetting"/>
      </profiles>
    </configuration>
    <!--- SPANDSP  -->
    <configuration name="spandsp.conf" description="FAX application configuration">
    </configuration>
    <!-- FREESWITCH DEFAULT CONFIGURATION -->
    <configuration name="switch.conf" description="Core Configuration">
      <settings>
        <X-PRE-PROCESS cmd="exec" data="curl -so $${devshm}/switch $${fsxmlapi}/switch"/>
        <X-PRE-PROCESS cmd="include" data="$${devshm}/switch"/>
        <param name="switchname" value="$${nodeid}"/>
      </settings>
    </configuration>
  </section>
  <!-- END: CONFIGURATION SECTION -->
  <!-- BEGIN: DIALPLAN SECTION -->
  <section name="dialplan" description="Regex/XML Dialplan">
    <context name="redirected">
      <extension name="any_to_any">
        <condition field="destination_number" expression="^.+$">
          <action application="lua" data="callng/redirection.lua"/>
          <anti-action application="hangup" data="CALL_REJECTED"/>
        </condition>
      </extension>
    </context>
    <context name="carrier">
      <extension name="carrier_to_any">
        <condition regex="all">
          <action application="lua" data="callng/main.lua"/>
          <anti-action application="hangup" data="CALL_REJECTED"/>
          <anti-action application="log" data="WARNING: YOU SHOULD NOT FOUND THIS MESSAGE, SO PLEASE CHECK THE FIREWALL"/>
        </condition>
      </extension>
    </context>
    <context name="core">
      <extension name="core_to_any">
        <condition regex="all">
          <action application="lua" data="callng/main.lua"/>
          <anti-action application="hangup" data="CALL_REJECTED"/>
          <anti-action application="log" data="WARNING: YOU SHOULD NOT FOUND THIS MESSAGE, SO PLEASE CHECK THE FIREWALL"/>
        </condition>
      </extension>
    </context>
    <context name="access">
      <extension name="access_to_any">
        <condition regex="all">
          <!-- <regex field="${acl(${network_addr} ACL)}" expression="true"/> -->
          <action application="lua" data="callng/main.lua"/>
          <anti-action application="hangup" data="CALL_REJECTED"/>
          <anti-action application="log" data="WARNING: YOU SHOULD NOT FOUND THIS MESSAGE, SO PLEASE CHECK THE FIREWALL"/>
        </condition>
      </extension>
    </context>
  </section>
  <!-- END: DIALPLAN SECTION -->
  <!-- BEGIN: DIRECTORY SECTION -->
  <section name="directory" description="User Directory">
    <X-PRE-PROCESS cmd="exec" data="curl -so $${devshm}/directory $${fsxmlapi}/directory"/>
    <X-PRE-PROCESS cmd="include" data="$${devshm}/directory"/>
  </section>
  <!-- END: DIRECTORY SECTION -->
</document>

有几个关键点:

  1. curl -so $${devshm}/acl $${fsxmlapi}/acl

    通过请求main.py, 把获取的配置写入到/dev/shm/acl共享内存的文件中。

  2. <X-PRE-PROCESS cmd="include" data="$${devshm}/acl"/>

    include结合realodxml,可以实现动态更新配置。

  3. <hook event="CHANNEL_CREATE" script="callng/event.capacity.lua"/>

    实现了事件监听的效果。

  4. <param name="startup-script" value="callng/event.initiation.lua"/>

    服务启动就运行脚本。

本博客已稳定运行
发表了74篇文章 · 总计128.75k字
本站总访问量 次 · 您是本站第 位访问者
粤ICP备2025368587号-1| 使用 Hugo 构建
主题 StackJimmy 设计