Mod lua/Serving Configuration

From FreeSWITCH Wiki
Jump to: navigation, search

Contents

Serving Configuration with mod_lua

mod_lua allows you to replace request for configuration data from a lookup in the static XML to your script.

  • You can bind a script to the XML req, like you do with URL in mod_xml_curl.
  • When something looks up sections in the XML registry, it calls your script.
  • Your script does any db lookups or whatever it needs, and it returns the XML string.
  • Note: When you edit lua.conf.xml, giving the reloadxml command from the FreeSWITCH console is not sufficient to get FreeSWITCH™ to recognize the "xml-handler-script" parameters. You have to restart FreeSWITCH™.
  • Some examples for the "xml-handler-bindings" parameter: "dialplan" "directory" "configuration" "dialplan|directory|configuration"
  • The script is passed an XML_REQUEST object which has section, tag_name, key_name, and key_value (see mod_xml_curl). For some configuration requests, for directory requests, and for diaplan requests, an event object is also passed in the variable 'params'.
  • Whatever you put in XML_STRING will be returned to freeswitch once the script is finished.

The file conf/autoload_configs/lua.conf.xml is used in the default FreeSWITCH™ setup.

Here is a minimum configuration file, it will fetch a dialplan from Lua script. (Example dialplan)

<configuration name="lua.conf" description="LUA Configuration">
  <settings>
    <param name="xml-handler-script" value="dp.lua"/>
    <param name="xml-handler-bindings" value="dialplan"/>
  </settings>
</configuration>

You can access the XML_REQUEST object in lua with the variables XML_REQUEST["section"], XML_REQUEST["tag_name"], XML_REQUEST["key_name"], and XML_REQUEST["key_value"]

Example:

 freeswitch.consoleLog("notice", "SECTION " .. XML_REQUEST["section"] .. "\n")


module configuration

If mod_lua is loaded during initial startup, then modules loaded after initial starup may have their configuration served by the bound script whenever they request configuration, which for many modules is on loading.

<configuration name="lua.conf" description="LUA Configuration">
  <settings>
    <param name="xml-handler-script" value="configuration.lua"/>
    <param name="xml-handler-bindings" value="configuration"/>
  </settings>
</configuration>

Then when the module is started, XML_REQUEST will have:

  • key_value = 'iax.conf'|'event_socket.conf'|sofia.conf'|...
  • key_name = 'name'
  • section = 'configuration'
  • tag_name = 'configuration'


'params' event object
acl.conf no N/A
event_socket.conf no N/A
post_load_switch.conf no N/A
sofia.conf yes
Event-Name: REQUEST_PARAMS
Core-UUID: 0f8afb73-2183-a1e2-2316-71053c746130
FreeSWITCH-Hostname: hostname
FreeSWITCH-IPv4: 192.168.1.12
FreeSWITCH-IPv6: %3A%3A1
Event-Date-Local: 2010-08-06%2014%3A04%3A38
Event-Date-GMT: Fri,%2006%20Aug%202010%2018%3A04%3A38%20GMT
Event-Date-Timestamp: 1281117878629975
Event-Calling-File: sofia.c
Event-Calling-Function: config_sofia
Event-Calling-Line-Number: 2637
switch.conf no N/A
syslog.conf no N/A

directory

initial startup

During initial startup/reading profiles, the directory is read for gateways and aliasing domains.

Then when the module is started, XML_REQUEST will have:

  • key_value = ''
  • key_name = ''
  • section = 'directory'
  • tag_name = ''

And params will have an event object.

The directory is read once for each profile in the sofia configuration

Note that the variables are the empty string, not nil.

params event headers

external profile
Event-Name: REQUEST_PARAMS
Core-UUID: <uuid>
FreeSWITCH-Hostname: hostname
FreeSWITCH-IPv4: 192.168.1.11
FreeSWITCH-IPv6: %3A%3A1
Event-Date-Local: 2010-08-06%2014%3A04%3A40
Event-Date-GMT: Fri,%2006%20Aug%202010%2018%3A04%3A40%20GMT
Event-Date-Timestamp: 1281117880813532
Event-Calling-File: sofia.c
Event-Calling-Function: config_sofia
Event-Calling-Line-Number: 3481
purpose: gateways
profile: external
the important bits
purpose: gateways
profile: external

and maybe these:

FreeSWITCH-Hostname: hostname
FreeSWITCH-IPv4: 192.168.1.11
internal profile
Event-Name: REQUEST_PARAMS
Core-UUID: <uuid>
FreeSWITCH-Hostname: hostname
FreeSWITCH-IPv4: 192.168.1.11
FreeSWITCH-IPv6: %3A%3A1
Event-Date-Local: 2010-08-06%2014%3A04%3A41
Event-Date-GMT: Fri,%2006%20Aug%202010%2018%3A04%3A41%20GMT
Event-Date-Timestamp: 1281117881174514
Event-Calling-File: sofia.c
Event-Calling-Function: config_sofia
Event-Calling-Line-Number: 3481
purpose: gateways
profile: internal
the important bits
purpose: gateways
profile: internal

and maybe these:

FreeSWITCH-Hostname: hostname
FreeSWITCH-IPv4: 192.168.1.11

network lists

Also during initial startup the network lists are read from the directory, however at this point the XML_REQUEST has:

  • key_value = <name-of-domain> (e.g. 192.168.1.11)
  • key_name = 'name'
  • section = 'directory'
  • tag_name = 'domain'
Event-Name: GENERAL
Core-UUID: <uuid>
FreeSWITCH-Hostname: hostname
FreeSWITCH-IPv4: 192.168.1.11
FreeSWITCH-IPv6: %3A%3A1
Event-Date-Local: 2010-08-06%2014%3A04%3A46
Event-Date-GMT: Fri,%2006%20Aug%202010%2018%3A04%3A46%20GMT
Event-Date-Timestamp: 1281117886025842
Event-Calling-File: switch_core.c
Event-Calling-Function: switch_load_network_lists
Event-Calling-Line-Number: 1040
domain: 192.168.1.11
purpose: network-list
the important bits
domain: 192.168.1.11
purpose: network-list

and maybe these:

FreeSWITCH-Hostname: hostname
FreeSWITCH-IPv4: 192.168.1.11

when looking for a user

When looking for a user, FreeSWITCH™ looks for the user in a particular domain.

XML_REQUEST will have:

  • key_value = '<name-of-domain>'
  • key_name = 'name'
  • section = 'directory'
  • tag_name = 'domain'

and 'params' will have an event object


when registering (REGISTER)

Event-Name: REQUEST_PARAMS
Core-UUID: <uuid>
FreeSWITCH-Hostname: hostname
FreeSWITCH-IPv4: 192.168.1.11
FreeSWITCH-IPv6: %3A%3A1
Event-Date-Local: 2010-08-06%2014%3A04%3A43
Event-Date-GMT: Fri,%2006%20Aug%202010%2018%3A04%3A43%20GMT
Event-Date-Timestamp: 1281117883173795
Event-Calling-File: sofia_reg.c
Event-Calling-Function: sofia_reg_parse_auth
Event-Calling-Line-Number: 1797
action: sip_auth
sip_profile: internal
sip_user_agent: IP-Phone-V3.2.49T5.13%20-%20G729
sip_auth_username: 1000
sip_auth_realm: 192.168.1.11
sip_auth_nonce: <auth_nonce_uuid>
sip_auth_uri: sip%3A192.168.1.11
sip_contact_user: 1000
sip_contact_host: 192.168.88.202
sip_to_user: 1000
sip_to_host: 192.168.1.11
sip_to_port: 5060
sip_from_user: 1000
sip_from_host: 192.168.1.11
sip_from_port: 5060
sip_request_host: 192.168.1.11
sip_auth_qop: auth
sip_auth_cnonce: 829326
sip_auth_nc: 00000001
sip_auth_response: <auth_response - md5sum?>
sip_auth_method: REGISTER
key: id
user: 1000
domain: 192.168.1.11
ip: 192.168.88.202
the important bits
key: id
user: 1000
domain: 192.168.1.11

and maybe these:

action: sip_auth
sip_profile: internal
FreeSWITCH-Hostname: hostname
FreeSWITCH-IPv4: 192.168.1.11
ip: 192.168.88.202

when calling (INVITE)

Event-Name: REQUEST_PARAMS
Core-UUID: <uuid>
FreeSWITCH-Hostname: hostname
FreeSWITCH-IPv4: 192.168.1.11
FreeSWITCH-IPv6: %3A%3A1
Event-Date-Local: 2010-08-06%2016%3A28%3A08
Event-Date-GMT: Fri,%2006%20Aug%202010%2020%3A28%3A08%20GMT
Event-Date-Timestamp: 1281126488274011
Event-Calling-File: sofia_reg.c
Event-Calling-Function: sofia_reg_parse_auth
Event-Calling-Line-Number: 1797
action: sip_auth
sip_profile: internal
sip_user_agent: IP-Phone-V3.2.49T5.13%20-%20G729
sip_auth_username: 1001
sip_auth_realm: 192.168.1.11
sip_auth_nonce: 1fe3d1fa-a199-11df-b392-b105e374638e
sip_auth_uri: sip%3A1000%40192.168.1.11
sip_contact_user: 1001
sip_contact_host: 192.168.88.99
sip_to_user: 1000
sip_to_host: 192.168.1.11
sip_to_port: 5060
sip_from_user: 1001
sip_from_host: 192.168.1.11
sip_from_port: 5060
sip_request_user: 1000
sip_request_host: 192.168.1.11
sip_auth_qop: auth
sip_auth_cnonce: 10560d0
sip_auth_nc: 00000001
sip_auth_response: b99d1213022480a2b6c4e14432661821
sip_auth_method: INVITE
key: id
user: 1001
domain: 192.168.1.11
ip: 192.168.88.99
the important bits
key: id
user: 1001
domain: 192.168.1.11

and maybe these:

ip: 192.168.88.99
FreeSWITCH-Hostname: hostname
FreeSWITCH-IPv4: 192.168.1.11
action: sip_auth
sip_profile: internal

when being called (by another extension)

Event-Name: REQUEST_PARAMS
Core-UUID: <uuid>
FreeSWITCH-Hostname: hostname
FreeSWITCH-IPv4: 192.168.1.11
FreeSWITCH-IPv6: %3A%3A1
Event-Date-Local: 2010-08-06%2016%3A28%3A09
Event-Date-GMT: Fri,%2006%20Aug%202010%2020%3A28%3A09%20GMT
Event-Date-Timestamp: 1281126489462522
Event-Calling-File: mod_dptools.c
Event-Calling-Function: user_outgoing_channel
Event-Calling-Line-Number: 2662
as_channel: true
action: user_call
key: id
user: 1000
domain: 192.168.1.11
the important bits
key: id
user: 1000
domain: 192.168.1.11

and maybe these:

FreeSWITCH-Hostname: hostname
FreeSWITCH-IPv4: 192.168.1.11
as_channel: true
Event-Calling-Function: user_outgoing_channel

dialplan

XML

Example dialplan

Lua

In for example a sip profile you can - instead of XML dialplan - use Lua directly to generate a dialplan:

<profile name="phones">
  <!-- ... -->
  <settings>
    <param name="dialplan" value="LUA"/>
    <param name="context" value="dialplan-from-phones.lua"/>
    <!-- ... -->
  </settings>
</profile>

Then create a dialplan in scripts/dialplan-from-phones.lua like this:

-- dialplan-from-phones.lua

ACTIONS = {}

freeswitch.consoleLog("notice", "from your script")

table.insert(ACTIONS, "answer")
table.insert(ACTIONS, {"log", "NOTICE after your script"})

The entire table (array) of actions will be executed after the Lua script has stopped.

This works the same as when the XML dialplan generates a list of actions that is run after it has reached the end.

Note that you must not use media directly from your script (eg session:answer()) like you could if it were called as an IVR script.

Advantage of this method over answering from an IVR script is that during the call itself there will be no Lua script (per session) running - which could add up if you have a few thousand sessions going.

Alternative is to call a Lua script from the XML dialplan that only sets some channel variables that will be picked up by consecutive applications - or you can generate an XML stub as is described in the previous section.

Of course it is also possible to transfer from one dialplan to another.

From Lua to XML:

table.insert(ACTIONS, {"transfer", "123 XML some-context"})

From XML to Lua:

<action application="transfer" data="123 LUA some-dialplan.lua"/>

not found

If your LUA application receives a request and you don't wish to serve dialplan or like to fallback to plain XML dialplan, then you should return the following "not found" result.

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="freeswitch/xml">
  <section name="result">
    <result status="not found" />
  </section>
</document>

If you return an empty response instead of the not found, you may see the following error;

[ERR] switch_xml.c:1534 switch_xml_locate() Error[[error near line 1]: root tag missing]