查看源代码 内部形式及其编码

此版本的堆栈符合

  • Megaco/H.248 版本 1 (RFC3525),根据实施者指南版本 10-13 更新。
  • Megaco/H.248 版本 2,由 draft-ietf-megaco-h248v2-04 定义,根据实施者指南版本 10-13 更新。
  • Megaco/H.248 版本 3,由 ITU H.248.1 (09/2005) 定义。

消息的内部形式

我们对二进制和文本编码使用相同的内部形式。我们的 Megaco/H.248 消息的内部形式深受 ASN.1 编码器/解码器使用的内部格式的影响。

  • “SEQUENCE OF”表示为列表。
  • “CHOICE”表示为大小为 2 的带标签的元组。
  • “SEQUENCE”表示为记录,在“megaco/include/megaco_message_v1.hrl”中定义。
  • “OPTIONAL”表示为记录中的普通字段,默认值为 'asn1_NOVALUE',表示该字段没有值。
  • “OCTET STRING”表示为无符号整数列表。
  • “ENUMERATED”表示为单个原子。
  • “BIT STRING”表示为原子列表。
  • “BOOLEAN”表示为原子 'true' 或 'false'。
  • “INTEGER”表示为整数。
  • “IA5String”表示为整数列表,其中每个整数是相应字符的 ASCII 值。
  • “NULL”表示为原子 'NULL'。

为了完全理解内部形式,您必须获取 Megaco/H.248 协议的 ASN.1 规范,并应用上述规则。请参阅 Erlang/OTP 中 ASN.1 编译器的文档,以了解更多有关 ASN.1 和相应内部形式之间映射的语义的详细信息。

请注意,“TerminationId”记录未在内部形式中使用。它已被 megaco_term_id 记录(在“megaco/include/megaco.hrl”中定义)取代。

不同的编码

Megaco/H.248 标准定义了纯文本编码和二进制编码 (ASN.1 BER),我们已经实现了两者的编码器和解码器。实际上,我们提供了五个不同的编码/解码模块。

在文本编码中,实现者可以选择使用短关键字和长关键字的混合。也可以添加空格以提高可读性。我们使用术语“紧凑”表示使用最短可能关键字且没有可选空格的文本消息,使用术语“美观”表示使用长关键字和缩进样式(如 Megaco/H.248 规范中的文本示例)的格式良好的文本格式。

下面是一个文本消息的示例,以感受美观版本和紧凑版本文本消息之间的差异。首先是美观的、缩进良好的版本,带有长关键字

   MEGACO/1 [124.124.124.222]
   Transaction = 9998 {
           Context = - {
                   ServiceChange = ROOT {
                           Services {
                                   Method = Restart,
                                   ServiceChangeAddress = 55555,
                                   Profile = ResGW/1,
                                   Reason = "901 Cold Boot"
                           }
                   }
           }
   }

然后是不带缩进且带有短关键字的紧凑版本


   !/1 [124.124.124.222]
   T=9998{C=-{SC=ROOT{SV{MT=RS,AD=55555,PF=ResGW/1,RE="901 Cold Boot"}}}}

以及程序员对同一消息的看法。首先构造 ActionRequest 记录列表,然后使用 API 中的一个发送函数发送该列表

  Prof = #'ServiceChangeProfile'{profileName = "resgw", version = 1},
  Parm = #'ServiceChangeParm'{serviceChangeMethod  = restart,
                              serviceChangeAddress = {portNumber, 55555},
                              serviceChangeReason  = "901 Cold Boot",
                              serviceChangeProfile = Prof},
  Req = #'ServiceChangeRequest'{terminationID = [?megaco_root_termination_id],
                                serviceChangeParms = Parm},
  Actions = [#'ActionRequest'{contextId = ?megaco_null_context_id,
                              commandRequests = {serviceChangeReq, Req}}],
  megaco:call(ConnHandle, Actions, Config).

最后是整个内部形式的打印输出

  {'MegacoMessage',
   asn1_NOVALUE,
   {'Message',
    1,
    {ip4Address,{'IP4Address', [124,124,124,222], asn1_NOVALUE}},
    {transactions,
     [
      {transactionRequest,
       {'TransactionRequest',
         9998,
         [{'ActionRequest',
           0,
           asn1_NOVALUE,
           asn1_NOVALUE,
           [
            {'CommandRequest',
             {serviceChangeReq,
              {'ServiceChangeRequest',
               [
                {megaco_term_id, false, ["root"]}],
                {'ServiceChangeParm',
                 restart,
                 {portNumber, 55555},
                 asn1_NOVALUE,
                 {'ServiceChangeProfile', "resgw", version = 1},
                 "901 MG Cold Boot",
                 asn1_NOVALUE,
                 asn1_NOVALUE,
                 asn1_NOVALUE
                }
              }
             },
             asn1_NOVALUE,
             asn1_NOVALUE
            }
           ]
          }
         ]
       }
      }
     ]
    }
   }
  }

提供了以下编码模块

  • megaco_pretty_text_encoder - 将消息编码为美观的文本格式,解码美观文本和紧凑文本。
  • megaco_compact_text_encoder - 将消息编码为紧凑的文本格式,解码美观文本和紧凑文本。
  • megaco_binary_encoder - 编码/解码 ASN.1 BER 消息。此编码器实现最快的 BER 编码器/解码器。推荐的二进制编解码器。
  • megaco_ber_encoder - 编码/解码 ASN.1 BER 消息。
  • megaco_per_encoder - 编码/解码 ASN.1 PER 消息。注意:此格式不包含在 Megaco 标准中。
  • megaco_erl_dist_encoder - 将消息编码为 Erlang 分布格式。它相当冗长,但编码和解码速度非常快。注意:此格式不包含在 Megaco 标准中。

Erlang 分布编码模块的配置

megaco_erl_dist_encoder 模块的 encoding_config 可以是以下之一

  • [] - 将消息编码为标准分布格式。它相当冗长,但编码和解码速度非常快。
  • [megaco_compressed] - 在内部转换后将消息编码为标准分布格式。它不那么冗长,但另一方面,编码和解码的总时间会稍慢(有关更多信息,请参阅性能章节)。
  • [{megaco_compressed, Module}] - 工作方式与 megaco_compressed 配置参数相同,只是用户在此处提供他们自己的压缩模块。此模块必须实现megaco_edist_compress行为。
  • [compressed] - 将消息编码为标准分布格式的压缩形式。它不那么冗长,但另一方面,编码和解码速度会较慢。

文本编码模块的配置

使用文本编码时,实际上有两个不同的配置来控制使用什么软件

  • [] - 空列表表示应使用 Erlang 扫描器。
  • [{flex, port()}] - 解码时使用 flex 扫描器(未针对 SMP 优化)。有关更多信息,请参阅初始配置
  • [{flex, ports()}] - 解码时使用 flex 扫描器(针对 SMP 优化)。有关更多信息,请参阅初始配置

Flex 扫描器是一个 Megaco 扫描器,它被编写为链接驱动程序 (C)。有两种方法可以使其工作

  • 让 Megaco 堆栈启动 flex 扫描器(加载驱动程序)。

    为了实现此目的,必须配置 megaco 堆栈

    • {scanner, flex}(或类似)指令添加到 megaco 应用的 Erlang 系统配置文件中(有关详细信息,请参阅初始配置章节)。
    • 使用 system_info 函数检索编码配置(其中 Item = text_config)。
    • 使用编码配置(encoding_config 字段)更新接收句柄。

    这样做的好处是 Megaco 处理驱动程序和端口的启动、保持和监督。

  • Megaco 客户端(用户)启动 flex 扫描器(加载驱动程序)。

    启动 flex 扫描器时,会创建一个到链接驱动程序的端口。此端口必须由进程拥有。此进程不得终止。如果终止,端口也将终止。因此

    • 创建一个永久进程。确保此进程受到监督(以便如果它终止,将会被注意到)。
    • 让此进程通过调用 megaco_flex_scanner:start/0,1 函数来启动 flex 扫描器。
    • 检索编码配置,并在初始化 megaco_receive_handle 时,相应地设置字段 encoding_config
    • megaco_receive_handle 传递给传输模块。

二进制编码模块的配置

使用二进制编码时,需要指定终止 ID 的结构。

  • [native] - 跳过转换阶段,即解码后的消息不会转换为我们的内部形式。
  • [integer()] - 包含每个级别大小(位数)的列表。示例:[3,8,5,8]
  • integer/0 - 单字节(8 位)级别的数量。注意:这当前转换为之前的配置。示例:3 ([8,8,8])。

处理 megaco 版本

有两种方法可以处理不同的 megaco 编码版本。一种是使用动态版本检测(仅对传入消息有效),另一种是在连接信息中显式设置版本

对于传入消息

  • 动态版本检测

    将 megacoreceive_handle 中的协议版本设置为 dynamic(这是默认值)。
    这适用于那些支持部分解码版本的编解码器,目前是 _text_ 和 ber_bin(megaco_binary_encodermegaco_ber_bin_encoder)。
    这样,解码器将检测使用哪个版本,然后使用正确的解码器。

  • 显式版本

    在 megaco_receive_handle 中显式设置实际的协议版本。
    从版本 1 开始。当执行初始服务更改并且已协商版本 2 时,将传输进程 (control_pid) 的 megaco_receive_handle 升级到版本 2。请参阅megaco_tcpmegaco_udp
    请注意,如果使用 udp,则同一个传输进程可以用于多个连接。这可能会使升级变得不可能。
    对于不支持部分解码版本的编解码器,目前是 megaco_ber_encodermegaco_per_encoderdynamic 将恢复到版本 1。

对于传出消息

  • 更新连接信息 protocol_version。
  • 发送消息时,可以通过在 Options 中添加项 {protocol_version, integer()} 来覆盖协议版本。请参阅 callcast
    请注意,这不会影响堆栈自主发送的消息。它们使用连接信息的 protocol_version。

编码器回调函数

编码器回调接口由 megaco_encoder 行为定义,请参阅 megaco_encoder