commit e2d0048f2369f01eefe5cee4973845e4765740f8 Author: anlicheng <244108715@qq.com> Date: Mon May 12 11:54:24 2025 +0800 init project diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..acfddff --- /dev/null +++ b/.gitignore @@ -0,0 +1,20 @@ +.rebar3 +_* +.eunit +*.o +*.beam +*.plt +*.swp +*.swo +.erlang.cookie +ebin +log +erl_crash.dump +.rebar +logs +_build +.idea +*.iml +rebar3.crashdump +*~ +config/sys.config diff --git a/API.md b/API.md new file mode 100644 index 0000000..02f65d1 --- /dev/null +++ b/API.md @@ -0,0 +1,188 @@ +# SDLAN API交互文档 + +## 检测客户端版本 + +```text +url: /api/upgrade +method: post +params: + client_id: string + version: int + channel: string // 客户端的渠道信息 +return: + {"result": { + "upgrade_type": 0, // 升级类型,0: 不升级,1: 普通升级,2: 强制升级 + "upgrade_prompt": "升级提升语" + "upgrade_address": "升级提升语" + }} + + {"error": {"code": 1, "message": "错误描述"}} + +``` + +## SDL主动请求的接口 + +### 1. 获取全部的可用网络信息 +```text +url: /api/get_all_networks +method: get +return: + + {"result": [8, 9, 10]} + + {"error": {"code": 1, "message": "错误描述"}} + +``` + +### 2. 获取单个网络信息 +```text +url: /api/get_network?id=:id +method: get +return: + {"result": + { + + "id": 1, + "name": "网络1", + "ipaddr": "192.168.0.1/24", + "owner_id": 1234, + "disabled_clients": ["client_id_xyz", "client_id_xyz1"] + } + } + + {"error": {"code": 1, "message": "错误描述"}} + +``` + +### 3.token校验 +```text +url: /api/auth_token +method: post +params: + client_id: string + token: string, + version: int // 当前客户端版本 +return: + + {"result": + { + "network_id": 8, + "upgrade_type": 0, // 升级类型,0: 不升级,1: 普通升级,2: 强制升级 + "upgrade_prompt": "升级提升语" + "upgrade_address": "升级提升语" + } + } + + {"error": {"code": 1, "message": "错误描述"}} + code = 1, Token does not exists + code = 2, Client Connection Disable +``` + +### 4.设置节点的状态 +```text +url: /api/set_node_status +method: post +params: + client_id: string + network_id: int, + ip_addr: string, + status: 0 | 1, // 0: 离线,1, 在线 +return: + + {"result": "success"} +``` + +### 5. 节点流量汇报(每分钟汇报一次,单位为字节数) +```text +url: /api/flow_report +method: post +params: + client_id: string + network_id: int, + forward_num: int, + p2p_num: int, + inbound_num: int +return: + + {"result": "success"} +``` + +## 管理平台请求SDLAN + +### 网络管理接口 + +#### 1. 创建新网络 +```text +url: /network/create +method: post +params: + id: int +return: + + {"result": "success"} + {"error": {"code": 1, "message": "错误描述"}} + +``` + +#### 2. 更新网络信息 +```text +url: /network/reload +method: post +params: + id: int +return: + + {"result": "success"} + {"error": {"code": 1, "message": "错误描述"}} + +``` + +#### 3. 删除网络 +```text +url: /network/delete +method: post +params: + id: int +return: + + {"result": "success"} + {"error": {"code": 1, "message": "错误描述"}} + +``` + +### 客户端节点管理 + +#### 1. 禁用节点 + +```text +url: /node/disable +method: post +params: + network_id: int + client_id: int + +return: + + {"result": "success"} + {"error": {"code": 1, "message": "错误描述"}} + +``` + +#### 2. 迁移到新网络 + +```text +url: /node/move +method: post +params: + client_id: int + to_network_id: int + timeout: int + +return: + + {"result": "success"} + {"error": {"code": 1, "message": "错误描述"}} + +``` + + diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..8ed2215 --- /dev/null +++ b/LICENSE @@ -0,0 +1,191 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + Copyright 2024, anlicheng <244108715@qq.com>. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/Protocol.md b/Protocol.md new file mode 100644 index 0000000..c0f969f --- /dev/null +++ b/Protocol.md @@ -0,0 +1,347 @@ +# 协议说明 + +## AES加密算法说明(不同网络下的AesKey的值不一样, 服务器端网络启动的时候采用的随机生成的方式) + +```text +算法: AES256 +aesKey: 长度为32个字节 +iv: 长度为aesKey的前16个字节 +blockMode: cbc +padding: pkcs7Padding +``` +## 1. 客户端与云端的交互同时使用了TCP和UDP协议 + +### 1.1 TCP协议基础说明 +```text +协议格式: <> + +Len: tcp数据流采用2个字节长度作为分包协议, Len的长度为后面的二进制的字节数 +PacketId: 4字节用来标识包ID,用来对应请求和响应; 对于不需要返回值的命令,PacketId的值必须是0 +PacketType: 1字节命令编码,具体参考后面的说明 +ProtobufData: 所用的message采用protobuf协议进行编码和解码 +``` +### 1.2 UDP协议基础说明 + +```text +协议格式: <> + +PacketType: 1字节命令编码,具体参考后面的说明 +ProtobufData: 所用的message采用protobuf协议进行编码和解码 +``` + +## 2. protobuf消息 + 参考文档`message.proto`里面的定义 + +## 3. PacketType编码说明 + +### 3.1 一级编码 +```text +enum CommandType: UInt8 { + // 为了建立完整的请求和响应的对应关系,部分请求没有数据返回时;服务器端返回空数据 + case empty = 0x00 + + case registerSuper = 0x01 + case registerSuperAck = 0x02 + case registerSuperNak = 0x04 + + case unregisterSuper = 0x05 + + case queryInfo = 0x06 + case peerInfo = 0x07 + + // TCP连接需要心跳机制来保持,客户端需要定时向服务器端发送心跳包 + case ping = 0x08 + case pong = 0x09 + + // 事件类型, 服务器端主动推送到客户端的事件;客户端在收到Event后,不需要向服务端发送Ack + case event = 0x10 + + // 推送命令消息, 服务器端主动推送到客户端的命令; 需要返回值(管理后台的部分操作需要反馈信息) + case command = 0x11 + case commandAck = 0x12 + + // 流量统计, 客户端统计的端上的流量信息;定期上报即可;服务器端收到后没有返回值 + case flowTracer = 0x15 + + // 客户端之间相互打洞 + case register = 0x20 + case registerAck = 0x21 + + // 客户端通过UDP周期性上报自己的Nat信息;需要依靠该方式保持客户端在Nat的洞不会被Nat设备关闭 + case stunRequest = 0x30 + case stunReply = 0x31 + + // 客户端通过UDP请求判断自己的Nat类型,并且在stunRequest请求中上报 + case stunProbe = 0x32 + case stunProbeReply = 0x33 + + // 数据类型 + case data = 0xFF +} +``` +### 3.2 二级编码(Event和Command指令存在二级编码) + 二级编码占用1个字节长度,紧跟在一级编码的后面,即: <> + +```text +Event编码 + + enum SDLEventType: UInt8 { + // 有新的ip加入到当前网络 + case knownIp = 0x01 + // ip地址离开当前网络 + case dropIp = 0x02 + // ip地址对应的nat信息发生了编码,需要重新打洞 + case natChanged = 0x03 + // 需要发送打洞请求 + case sendRegister = 0x04 + // 网络关闭 + case networkShutdown = 0xFF + } + +Command编码 + + enum SDLCommandType: UInt8 { + // 网络地址改变,当node被move的时候网络会发生改变 + case changeNetwork = 0x01 + } +``` + +## 4. 交互说明 + +### 4.1 基于公共类型定义 +```text + +message SDLV4Info { + uint32 port = 1; + bytes v4 = 2; + uint32 nat_type = 3; +} + +// ipv6信息,目前未支持!! +message SDLV6Info { + uint32 port = 1; + bytes v6 = 2; +} + +// 设备网络地址信息 +message SDLDevAddr { + uint32 network_id = 1; + uint32 net_addr = 2; + uint32 net_bit_len = 3; +} + +``` + +### 5. TCP交互 + +### 5.1 客户端建立到服务端后,需要先发送RegisterSuper消息 + 由于时基于tcp长连接方式,因此理论上一个连接上只需要请求一次;服务器端会绑定相关信息 +```text +请求: + +message SDLRegisterSuper { + uint32 version = 1; + string installed_channel = 2; + string client_id = 3; + SDLDevAddr dev_addr = 4; + string pub_key = 5; + string token = 6; +} + +响应: + +// 服务器验证通过后返回 +message SDLRegisterSuperAck { + SDLDevAddr dev_addr = 1; + bytes aes_key = 2; + bytes known_ips = 3; + uint32 upgrade_type = 4; + optional string upgrade_prompt = 5; + optional string upgrade_address = 6; +} + +// 服务验证失败返回 +message SDLRegisterSuperNak { + uint32 error_code = 1; + string error_message = 2; +} + +``` + +### 5.2 查询ip对应的PeerInfo +```text +请求: + message SDLQueryInfo { + uint32 dst_ip = 1; + } + +响应: + 成功: + + // 目前未支持ipv6,因此SDLV6Info的值为空 + message SDLPeerInfo { + SDLV4Info v4_info = 1; + optional SDLV6Info v6_info = 2; + } + + 失败: + 返回empty: <> +``` + +### 5.3 客户端主动发起Ping + 服务器端无返回, 服务器在15秒内没有收到任何ping包;会关闭掉当前的tcp连接 +```text +请求: + <<0:32, 0x08>> +``` + +### 5.4 主动上报当前节点的流量信息 + 服务器端无返回, 请求是的packetId值必须是: 0 +```text +请求: + message SDLFlows { + // 服务器转发流量 + uint32 forward_num = 1; + // p2p直接流量 + uint32 p2p_num = 2; + // 接收的流量 + uint32 inbound_num = 3; + } + +``` + +### 5.5 命令下发 +```text + 消息格式: <> +``` + +### 5.6 命令回复 + 注意Ack里面的PacketId的值必须和下发命令时的PacketId值一致 +```text + 消息格式: <> +``` + +### 5.7 Event下发 + 客户端在收到Event后,不需要回复Ack信息 +```text + 消息格式: <> +``` + +### 5.8 Unregister取消注册 + 无返回,服务器端收到后会关闭掉当前连接 +```text +请求: + <<0:32, 0x05>> +``` + +## 6. UDP交互 + +### 6.1 StunRequest请求(10s发送一次) +```text +请求: + message SDLStunRequest { + uint32 cookie = 1; + string client_id = 2; + uint32 network_id = 3; + uint32 ip = 4; + uint32 nat_type = 5; + } + +响应: + message SDLStunReply { + uint32 cookie = 1; + } +``` + +### 6.2 StunProbe请求 + +```text +请求: + message SDLStunProbe { + uint32 cookie = 1; + uint32 attr = 2; + } + +响应: + message SDLStunProbeReply { + uint32 cookie = 1; + uint32 port = 2; + uint32 ip = 3; + } + +Attr值的说明: + enum SDLProbeAttr: UInt8 { + // 正常响应 + case none = 0 + // 服务器在收到消息,用相同IP地址,但是Port不相同的Socket响应 + case port = 1 + // 服务器在收到消息,同时改变IP地址和Port的Socket响应 + case peer = 2 + } + +Nat类型说明: + enum NatType: UInt8, Encodable { + case blocked = 0 // 网络不通 + case noNat = 1 // 当前设备在公网IP下 + case fullCone = 2 // 完全对称型Nat + case portRestricted = 3 // 端口限制型 + case coneRestricted = 4 // Ip限制型 + case symmetric = 5 // 完全对称型 + } +Nat类型的判断逻辑 + func getNatType() async -> NatType { + let addressArray = config.stunProbeSocketAddressArray + // step1: ip1:port1 <---- ip1:port1 + guard let natAddress1 = await getNatAddress(remoteAddress: addressArray[0][0], attr: .none) else { + return .blocked + } + + // 网络没有在nat下 + if natAddress1 == self.udpHole?.localAddress { + return .noNat + } + + // step2: ip2:port2 <---- ip2:port2 + guard let natAddress2 = await getNatAddress(remoteAddress: addressArray[1][1], attr: .none) else { + return .blocked + } + + // 如果natAddress2 的IP地址与上次回来的IP是不一样的,它就是对称型NAT; 这次的包也一定能发成功并收到 + // 如果ip地址变了,这说明{dstIp, dstPort, srcIp, srcPort}, 其中有一个变了;则用新的ip地址 + NSLog("nat_address1: \(natAddress1), nat_address2: \(natAddress2)") + if let ipAddress1 = natAddress1.ipAddress, let ipAddress2 = natAddress2.ipAddress, ipAddress1 != ipAddress2 { + return .symmetric + } + + // step3: ip1:port1 <---- ip2:port2 (ip地址和port都变的情况) + // 如果能收到的,说明是完全锥形 说明是IP地址限制锥型NAT,如果不能收到说明是端口限制锥型。 + if let natAddress3 = await getNatAddress(remoteAddress: addressArray[0][0], attr: .peer) { + NSLog("nat_address1: \(natAddress1), nat_address2: \(natAddress2), nat_address3: \(natAddress3)") + return .fullCone + } + + // step3: ip1:port1 <---- ip1:port2 (port改变情况) + // 如果能收到的说明是IP地址限制锥型NAT,如果不能收到说明是端口限制锥型。 + if let natAddress4 = await getNatAddress(remoteAddress: addressArray[0][0], attr: .port) { + NSLog("nat_address1: \(natAddress1), nat_address2: \(natAddress2), nat_address4: \(natAddress4)") + return .coneRestricted + } else { + return .portRestricted + } + } +``` + +### 6.3 StunData请求 +```text +消息体: 其中只有data字段里面的数据使用了aes加密 + +message SDLData { + uint32 network_id = 1; + uint32 src_ip = 2; + uint32 dst_ip = 3; + bool is_p2p = 4; + uint32 ttl = 5; + bytes data = 6; +} + +``` \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..daa468b --- /dev/null +++ b/README.md @@ -0,0 +1,13 @@ +sdlan +===== + +An OTP application + +## proto文件的编译 + 目录: /usr/local/code/tmp/gpb + bin/protoc-erl -I . -rename msg_name:snake_case -strbin sdlan_pb.proto + +Build +----- + + $ rebar3 compile diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000..124224d --- /dev/null +++ b/TODO.md @@ -0,0 +1,3 @@ +# 需要完善的事情 + +## 后端网络需要增加一个aes_key,采用AES256加密算法,key的长度为32个字符 \ No newline at end of file diff --git a/apps/sdlan/include/sdlan.hrl b/apps/sdlan/include/sdlan.hrl new file mode 100644 index 0000000..0f2e6c5 --- /dev/null +++ b/apps/sdlan/include/sdlan.hrl @@ -0,0 +1,83 @@ +%%%------------------------------------------------------------------- +%%% @author anlicheng +%%% @copyright (C) 2024, +%%% @doc +%%% +%%% @end +%%% Created : 09. 3月 2024 14:53 +%%%------------------------------------------------------------------- +-author("anlicheng"). + +%% 定义version +-define(VERSION_1, 1). + +-define(DEFAULT_PASS, <<"`encrypt!`">>). + +-define(PACKET_EMPTY, 16#00). +-define(PACKET_REGISTER_SUPER, 16#01). +-define(PACKET_REGISTER_SUPER_ACK, 16#02). +-define(PACKET_REGISTER_SUPER_ACKNOWLEDGE, 16#03). +-define(PACKET_REGISTER_SUPER_NAK, 16#04). +-define(PACKET_UNREGISTER, 16#05). + +%% 信息查询 +-define(PACKET_QUERY_INFO, 16#06). +-define(PACKET_PEER_INFO, 16#07). + +%% 心跳机制 +-define(PACKET_PING, 16#08). +-define(PACKET_PONG, 16#09). + +%% 推送的事件信息, 不需要返回值 +-define(PACKET_EVENT, 16#10). + +%% 定义事件信息 +-define(PACKET_EVENT_KNOWN_IP, 16#01). +-define(PACKET_EVENT_DROP_IP, 16#02). +-define(PACKET_EVENT_NAT_CHANGED, 16#03). +-define(PACKET_EVENT_SEND_REGISTER, 16#04). + +%% 网络关闭 +-define(PACKET_EVENT_NETWORK_SHUTDOWN, 16#FF). + +%% 推送命令信息, 需要等待返回值 +-define(PACKET_COMMAND, 16#11). +-define(PACKET_COMMAND_ACK, 16#12). + +%% 网络发生变化 +-define(PACKET_COMMAND_CHANGE_NETWORK, 16#01). +-define(PACKET_COMMAND_UPGRADE, 16#02). + +%% 网络流量统计 +-define(PACKET_FLOW_TRACER, 16#15). + +-define(PACKET_REGISTER, 16#20). +-define(PACKET_REGISTER_ACK, 16#21). + +%% stun相关的请求 + +%% 请求 +-define(PACKET_STUN_REQUEST, 16#30). +%% 响应 +-define(PACKET_STUN_REPLY, 16#31). + +%% stun网络类型检测 +%% 请求 +-define(PACKET_STUN_PROBE, 16#32). +%% 响应 +-define(PACKET_STUN_PROBE_REPLY, 16#33). +%% stun消息转发 +-define(PACKET_STUN_PROBE_RELAY, 16#3a). + +%% stun请求的attr +-define(STUN_ATTR_CHANGE_NONE, 0). +-define(STUN_ATTR_CHANGE_PORT, 1). +-define(STUN_ATTR_CHANGE_PEER, 2). + +%% 数据转发 +-define(PACKET_STUN_DATA, 16#FF). + +-record(id_generator, { + tab :: atom(), + increment_id = 0 :: integer() +}). \ No newline at end of file diff --git a/apps/sdlan/include/sdlan_pb.hrl b/apps/sdlan/include/sdlan_pb.hrl new file mode 100644 index 0000000..d7c149a --- /dev/null +++ b/apps/sdlan/include/sdlan_pb.hrl @@ -0,0 +1,210 @@ +%% -*- coding: utf-8 -*- +%% Automatically generated, do not edit +%% Generated by gpb_compile version 4.21.1 + +-ifndef(sdlan_pb). +-define(sdlan_pb, true). + +-define(sdlan_pb_gpb_version, "4.21.1"). + + +-ifndef('SDLV_4_INFO_PB_H'). +-define('SDLV_4_INFO_PB_H', true). +-record(sdl_v4_info, + {port = 0 :: non_neg_integer() | undefined, % = 1, optional, 32 bits + v4 = <<>> :: iodata() | undefined, % = 2, optional + nat_type = 0 :: non_neg_integer() | undefined % = 3, optional, 32 bits + }). +-endif. + +-ifndef('SDLV_6_INFO_PB_H'). +-define('SDLV_6_INFO_PB_H', true). +-record(sdl_v6_info, + {port = 0 :: non_neg_integer() | undefined, % = 1, optional, 32 bits + v6 = <<>> :: iodata() | undefined % = 2, optional + }). +-endif. + +-ifndef('SDL_DEV_ADDR_PB_H'). +-define('SDL_DEV_ADDR_PB_H', true). +-record(sdl_dev_addr, + {network_id = 0 :: non_neg_integer() | undefined, % = 1, optional, 32 bits + mac = <<>> :: iodata() | undefined, % = 2, optional + net_addr = 0 :: non_neg_integer() | undefined, % = 3, optional, 32 bits + net_bit_len = 0 :: non_neg_integer() | undefined % = 4, optional, 32 bits + }). +-endif. + +-ifndef('SDL_EMPTY_PB_H'). +-define('SDL_EMPTY_PB_H', true). +-record(sdl_empty, + { + }). +-endif. + +-ifndef('SDL_REGISTER_SUPER_PB_H'). +-define('SDL_REGISTER_SUPER_PB_H', true). +-record(sdl_register_super, + {version = 0 :: non_neg_integer() | undefined, % = 1, optional, 32 bits + installed_channel = <<>> :: unicode:chardata() | undefined, % = 2, optional + client_id = <<>> :: unicode:chardata() | undefined, % = 3, optional + dev_addr = undefined :: sdlan_pb:sdl_dev_addr() | undefined, % = 4, optional + pub_key = <<>> :: unicode:chardata() | undefined, % = 5, optional + token = <<>> :: unicode:chardata() | undefined % = 6, optional + }). +-endif. + +-ifndef('SDL_REGISTER_SUPER_ACK_PB_H'). +-define('SDL_REGISTER_SUPER_ACK_PB_H', true). +-record(sdl_register_super_ack, + {dev_addr = undefined :: sdlan_pb:sdl_dev_addr() | undefined, % = 1, optional + aes_key = <<>> :: iodata() | undefined, % = 2, optional + upgrade_type = 0 :: non_neg_integer() | undefined, % = 3, optional, 32 bits + upgrade_prompt :: unicode:chardata() | undefined, % = 4, optional + upgrade_address :: unicode:chardata() | undefined % = 5, optional + }). +-endif. + +-ifndef('SDL_REGISTER_SUPER_NAK_PB_H'). +-define('SDL_REGISTER_SUPER_NAK_PB_H', true). +-record(sdl_register_super_nak, + {error_code = 0 :: non_neg_integer() | undefined, % = 1, optional, 32 bits + error_message = <<>> :: unicode:chardata() | undefined % = 2, optional + }). +-endif. + +-ifndef('SDL_QUERY_INFO_PB_H'). +-define('SDL_QUERY_INFO_PB_H', true). +-record(sdl_query_info, + {dst_mac = <<>> :: iodata() | undefined % = 1, optional + }). +-endif. + +-ifndef('SDL_PEER_INFO_PB_H'). +-define('SDL_PEER_INFO_PB_H', true). +-record(sdl_peer_info, + {dst_mac = <<>> :: iodata() | undefined, % = 1, optional + v4_info = undefined :: sdlan_pb:sdl_v4_info() | undefined, % = 2, optional + v6_info :: sdlan_pb:sdl_v6_info() | undefined % = 3, optional + }). +-endif. + +-ifndef('SDL_NAT_CHANGED_EVENT_PB_H'). +-define('SDL_NAT_CHANGED_EVENT_PB_H', true). +-record(sdl_nat_changed_event, + {mac = <<>> :: iodata() | undefined, % = 1, optional + ip = 0 :: non_neg_integer() | undefined % = 2, optional, 32 bits + }). +-endif. + +-ifndef('SDL_SEND_REGISTER_EVENT_PB_H'). +-define('SDL_SEND_REGISTER_EVENT_PB_H', true). +-record(sdl_send_register_event, + {dst_mac = <<>> :: iodata() | undefined, % = 1, optional + nat_ip = 0 :: non_neg_integer() | undefined, % = 2, optional, 32 bits + nat_port = 0 :: non_neg_integer() | undefined, % = 3, optional, 32 bits + nat_type = 0 :: non_neg_integer() | undefined, % = 4, optional, 32 bits + v6_info :: sdlan_pb:sdl_v6_info() | undefined % = 5, optional + }). +-endif. + +-ifndef('SDL_NETWORK_SHUTDOWN_EVENT_PB_H'). +-define('SDL_NETWORK_SHUTDOWN_EVENT_PB_H', true). +-record(sdl_network_shutdown_event, + {message = <<>> :: unicode:chardata() | undefined % = 1, optional + }). +-endif. + +-ifndef('SDL_CHANGE_NETWORK_COMMAND_PB_H'). +-define('SDL_CHANGE_NETWORK_COMMAND_PB_H', true). +-record(sdl_change_network_command, + {dev_addr = undefined :: sdlan_pb:sdl_dev_addr() | undefined, % = 1, optional + aes_key = <<>> :: iodata() | undefined % = 2, optional + }). +-endif. + +-ifndef('SDL_COMMAND_ACK_PB_H'). +-define('SDL_COMMAND_ACK_PB_H', true). +-record(sdl_command_ack, + {status = false :: boolean() | 0 | 1 | undefined, % = 1, optional + message :: unicode:chardata() | undefined % = 2, optional + }). +-endif. + +-ifndef('SDL_FLOWS_PB_H'). +-define('SDL_FLOWS_PB_H', true). +-record(sdl_flows, + {forward_num = 0 :: non_neg_integer() | undefined, % = 1, optional, 32 bits + p2p_num = 0 :: non_neg_integer() | undefined, % = 2, optional, 32 bits + inbound_num = 0 :: non_neg_integer() | undefined % = 3, optional, 32 bits + }). +-endif. + +-ifndef('SDL_STUN_REQUEST_PB_H'). +-define('SDL_STUN_REQUEST_PB_H', true). +-record(sdl_stun_request, + {cookie = 0 :: non_neg_integer() | undefined, % = 1, optional, 32 bits + client_id = <<>> :: unicode:chardata() | undefined, % = 2, optional + network_id = 0 :: non_neg_integer() | undefined, % = 3, optional, 32 bits + mac = <<>> :: iodata() | undefined, % = 4, optional + ip = 0 :: non_neg_integer() | undefined, % = 5, optional, 32 bits + nat_type = 0 :: non_neg_integer() | undefined, % = 6, optional, 32 bits + v6_info :: sdlan_pb:sdl_v6_info() | undefined % = 7, optional + }). +-endif. + +-ifndef('SDL_STUN_REPLY_PB_H'). +-define('SDL_STUN_REPLY_PB_H', true). +-record(sdl_stun_reply, + {cookie = 0 :: non_neg_integer() | undefined % = 1, optional, 32 bits + }). +-endif. + +-ifndef('SDL_DATA_PB_H'). +-define('SDL_DATA_PB_H', true). +-record(sdl_data, + {network_id = 0 :: non_neg_integer() | undefined, % = 1, optional, 32 bits + src_mac = <<>> :: iodata() | undefined, % = 2, optional + dst_mac = <<>> :: iodata() | undefined, % = 3, optional + is_p2p = false :: boolean() | 0 | 1 | undefined, % = 4, optional + ttl = 0 :: non_neg_integer() | undefined, % = 5, optional, 32 bits + data = <<>> :: iodata() | undefined % = 6, optional + }). +-endif. + +-ifndef('SDL_REGISTER_PB_H'). +-define('SDL_REGISTER_PB_H', true). +-record(sdl_register, + {network_id = 0 :: non_neg_integer() | undefined, % = 1, optional, 32 bits + src_mac = <<>> :: iodata() | undefined, % = 2, optional + dst_mac = <<>> :: iodata() | undefined % = 3, optional + }). +-endif. + +-ifndef('SDL_REGISTER_ACK_PB_H'). +-define('SDL_REGISTER_ACK_PB_H', true). +-record(sdl_register_ack, + {network_id = 0 :: non_neg_integer() | undefined, % = 1, optional, 32 bits + src_mac = <<>> :: iodata() | undefined, % = 2, optional + dst_mac = <<>> :: iodata() | undefined % = 3, optional + }). +-endif. + +-ifndef('SDL_STUN_PROBE_PB_H'). +-define('SDL_STUN_PROBE_PB_H', true). +-record(sdl_stun_probe, + {cookie = 0 :: non_neg_integer() | undefined, % = 1, optional, 32 bits + attr = 0 :: non_neg_integer() | undefined % = 2, optional, 32 bits + }). +-endif. + +-ifndef('SDL_STUN_PROBE_REPLY_PB_H'). +-define('SDL_STUN_PROBE_REPLY_PB_H', true). +-record(sdl_stun_probe_reply, + {cookie = 0 :: non_neg_integer() | undefined, % = 1, optional, 32 bits + port = 0 :: non_neg_integer() | undefined, % = 2, optional, 32 bits + ip = 0 :: non_neg_integer() | undefined % = 3, optional, 32 bits + }). +-endif. + +-endif. diff --git a/apps/sdlan/include/sdlan_tables.hrl b/apps/sdlan/include/sdlan_tables.hrl new file mode 100644 index 0000000..355670f --- /dev/null +++ b/apps/sdlan/include/sdlan_tables.hrl @@ -0,0 +1,18 @@ +%%%------------------------------------------------------------------- +%%% @author anlicheng +%%% @copyright (C) 2025, +%%% @doc +%%% +%%% @end +%%% Created : 20. 1月 2025 21:35 +%%%------------------------------------------------------------------- +-author("anlicheng"). + +%% ip的使用信息 +-record(client, { + client_id :: binary(), + mac :: binary(), + ip :: integer(), + %% 当前状态 + status = normal :: normal | disabled +}). \ No newline at end of file diff --git a/apps/sdlan/src/http_handler/api_handler.erl b/apps/sdlan/src/http_handler/api_handler.erl new file mode 100644 index 0000000..5c89df2 --- /dev/null +++ b/apps/sdlan/src/http_handler/api_handler.erl @@ -0,0 +1,34 @@ +%%%------------------------------------------------------------------- +%%% @author licheng5 +%%% @copyright (C) 2020, +%%% @doc +%%% +%%% @end +%%% Created : 26. 4月 2020 3:36 下午 +%%%------------------------------------------------------------------- +-module(api_handler). +-author("licheng5"). + +%% API +-export([handle_request/4]). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% helper methods +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% 重新加载对应的主机信息 +handle_request("POST", "/test/auth_token", _, PostParams) -> + lager:debug("[test_handler] get post params: ~p", [PostParams]), + [Id | _] = network_bo:get_all_networks(), + Data = #{ + <<"network_id">> => Id + }, + {ok, 200, sdlan_util:json_data(Data)}; + +handle_request(_, Path, _, _) -> + Path1 = list_to_binary(Path), + {ok, 200, sdlan_util:json_error(-1, <<"url: ", Path1/binary, " not found">>)}. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% helper methods +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \ No newline at end of file diff --git a/apps/sdlan/src/http_handler/file_handler.erl b/apps/sdlan/src/http_handler/file_handler.erl new file mode 100644 index 0000000..838e385 --- /dev/null +++ b/apps/sdlan/src/http_handler/file_handler.erl @@ -0,0 +1,24 @@ +%%%------------------------------------------------------------------- +%%% @author anlicheng +%%% @copyright (C) 2024, +%%% @doc +%%% +%%% @end +%%% Created : 09. 4月 2024 14:28 +%%%------------------------------------------------------------------- +-module(file_handler). +-author("anlicheng"). + +%% API +-export([init/2]). + +init(Req, State) -> + %% 拼接得到文件的真实路径 + FullPath = "/tmp/files/test.dmg", + %% 使用cowboy_req:reply函数返回文件内容 + {ok, Content} = file:read_file(FullPath), + Req1 = cowboy_req:reply(200, #{ + <<"Content-Type">> => <<"application/octet-stream">> + }, Content, Req), + + {ok, Req1, State}. \ No newline at end of file diff --git a/apps/sdlan/src/http_handler/http_protocol.erl b/apps/sdlan/src/http_handler/http_protocol.erl new file mode 100644 index 0000000..2de5748 --- /dev/null +++ b/apps/sdlan/src/http_handler/http_protocol.erl @@ -0,0 +1,86 @@ +%%%------------------------------------------------------------------- +%%% @author licheng5 +%%% @copyright (C) 2020, +%%% @doc +%%% +%%% @end +%%% Created : 26. 4月 2020 3:36 下午 +%%%------------------------------------------------------------------- +-module(http_protocol). +-author("licheng5"). + +%% API +-export([init/2]). + +init(Req0, Opts = [Mod|_]) -> + Method = binary_to_list(cowboy_req:method(Req0)), + Path = binary_to_list(cowboy_req:path(Req0)), + GetParams0 = cowboy_req:parse_qs(Req0), + GetParams = maps:from_list(GetParams0), + {ok, PostParams, Req1} = parse_body(Req0), + + try Mod:handle_request(Method, Path, GetParams, PostParams) of + {ok, StatusCode, Resp} -> + %lager:debug("[http_protocol] request path: ~p, get_params: ~p, post_params: ~p, response: ~ts", + % [Path, GetParams, PostParams, Resp]), + AcceptEncoding = cowboy_req:header(<<"accept-encoding">>, Req1, <<>>), + Req2 = case iolist_size(Resp) >= 1024 andalso supported_gzip(AcceptEncoding) of + true -> + Resp1 = zlib:gzip(Resp), + cowboy_req:reply(StatusCode, #{ + <<"Content-Type">> => <<"application/json;charset=utf-8">>, + <<"Content-Encoding">> => <<"gzip">> + }, Resp1, Req1); + false -> + cowboy_req:reply(StatusCode, #{ + <<"Content-Type">> => <<"application/json;charset=utf-8">> + }, Resp, Req1) + end, + {ok, Req2, Opts} + catch + throw:Error -> + Req2 = cowboy_req:reply(404, #{ + <<"Content-Type">> => <<"application/json;charset=utf-8">> + }, Error, Req1), + {ok, Req2, Opts}; + _:Error:Stack -> + lager:warning("[http_handler] get error: ~p, stack: ~p", [Error, Stack]), + Req2 = cowboy_req:reply(500, #{ + <<"Content-Type">> => <<"text/html;charset=utf-8">> + }, <<"Internal Server Error">>, Req1), + {ok, Req2, Opts} + end. + +%% 判断是否支持gzip +supported_gzip(AcceptEncoding) when is_binary(AcceptEncoding) -> + binary:match(AcceptEncoding, <<"gzip">>) =/= nomatch. + +parse_body(Req0) -> + ContentType = cowboy_req:header(<<"content-type">>, Req0), + case ContentType of + <<"application/json", _/binary>> -> + {ok, Body, Req1} = read_body(Req0), + case Body /= <<>> of + true -> + {ok, catch jiffy:decode(Body, [return_maps]), Req1}; + false -> + {ok, #{}, Req1} + end; + <<"application/x-www-form-urlencoded">> -> + {ok, PostParams0, Req1} = cowboy_req:read_urlencoded_body(Req0), + PostParams = maps:from_list(PostParams0), + {ok, PostParams, Req1}; + _ -> + {ok, #{}, Req0} + end. + +%% 读取请求体 +read_body(Req) -> + read_body(Req, <<>>). +read_body(Req, AccData) -> + case cowboy_req:read_body(Req) of + {ok, Data, Req1} -> + {ok, <>, Req1}; + {more, Data, Req1} -> + read_body(Req1, <>) + end. \ No newline at end of file diff --git a/apps/sdlan/src/http_handler/network_handler.erl b/apps/sdlan/src/http_handler/network_handler.erl new file mode 100644 index 0000000..ded897b --- /dev/null +++ b/apps/sdlan/src/http_handler/network_handler.erl @@ -0,0 +1,61 @@ +%%%------------------------------------------------------------------- +%%% @author anlicheng +%%% @copyright (C) 2024, +%%% @doc +%%% +%%% @end +%%% Created : 09. 4月 2024 14:28 +%%%------------------------------------------------------------------- +-module(network_handler). +-author("anlicheng"). + +%% API +-export([handle_request/4]). + +handle_request("POST", "/network/create", _, #{<<"id">> := NetworkId}) when NetworkId > 0 -> + case sdlan_network_sup:ensured_network_started(NetworkId) of + {ok, Pid} when is_pid(Pid) -> + {ok, 200, sdlan_util:json_data(<<"success">>)}; + {error, Reason} -> + lager:debug("[network_handler] create network: ~p, get error: ~p", [NetworkId, Reason]), + {ok, 200, sdlan_util:json_error(-1, <<"error">>)} + end; + +handle_request("POST", "/network/reload", _, #{<<"id">> := NetworkId}) when NetworkId > 0 -> + case sdlan_network:get_pid(NetworkId) of + undefined -> + case sdlan_network_sup:start_network(NetworkId) of + {ok, Pid} when is_pid(Pid) -> + sdlan_network_sup:reallocate_bind_width(), + {ok, 200, sdlan_util:json_data(<<"success">>)}; + {error, Reason} -> + lager:debug("[network_handler] start network: ~p, get error: ~p", [NetworkId, Reason]), + {ok, 200, sdlan_util:json_error(-1, <<"error">>)} + end; + NetworkPid when is_pid(NetworkPid) -> + case sdlan_network:reload(NetworkPid) of + ok -> + {ok, 200, sdlan_util:json_data(<<"success">>)}; + {error, Reason} -> + lager:debug("[network_handler] reload network: ~p, get error: ~p", [NetworkId, Reason]), + {ok, 200, sdlan_util:json_error(-1, <<"error">>)} + end + end; + +handle_request("POST", "/network/delete", _, #{<<"id">> := NetworkId}) when NetworkId > 0 -> + case sdlan_network:get_pid(NetworkId) of + undefined -> + {ok, 200, sdlan_util:json_data(<<"success">>)}; + NetworkPid when is_pid(NetworkPid) -> + case sdlan_network_sup:delete_network(NetworkId) of + ok -> + {ok, 200, sdlan_util:json_data(<<"success">>)}; + {error, Reason} -> + lager:debug("[network_handler] delete network: ~p, get error: ~p", [NetworkId, Reason]), + {ok, 200, sdlan_util:json_error(-1, <<"error">>)} + end + end; + +handle_request(_, Path, _, _) -> + Path1 = list_to_binary(Path), + {ok, 200, sdlan_util:json_error(-1, <<"url: ", Path1/binary, " not found">>)}. \ No newline at end of file diff --git a/apps/sdlan/src/http_handler/node_handler.erl b/apps/sdlan/src/http_handler/node_handler.erl new file mode 100644 index 0000000..9a68acb --- /dev/null +++ b/apps/sdlan/src/http_handler/node_handler.erl @@ -0,0 +1,72 @@ +%%%------------------------------------------------------------------- +%%% @author anlicheng +%%% @copyright (C) 2024, +%%% @doc +%%% +%%% @end +%%% Created : 09. 4月 2024 14:28 +%%%------------------------------------------------------------------- +-module(node_handler). +-author("anlicheng"). +-include("sdlan.hrl"). +-include("sdlan_pb.hrl"). +-include("sdlan_tables.hrl"). + +%% API +-export([handle_request/4]). + +handle_request("POST", "/node/list", _, #{<<"network_id">> := NetworkId}) when NetworkId > 0 -> + Pid = sdlan_network:get_pid(NetworkId), + UsedMap = sdlan_network:get_used_map(Pid), + + Clients = client_model:get_clients(NetworkId), + ClientInfos = lists:map(fun(#client{client_id = ClientId, mac = Mac, ip = Ip, status = Status}) -> + Info = #{ + <<"client_id">> => ClientId, + <<"mac">> => Mac, + <<"ip">> => sdlan_ipaddr:int_to_ipv4(Ip), + <<"status">> => atom_to_binary(Status) + }, + maps:merge(Info, maps:get(Mac, UsedMap, #{})) + end, Clients), + + {ok, 200, sdlan_util:json_data(ClientInfos)}; + +handle_request("POST", "/node/disable", _, #{<<"network_id">> := NetworkId, <<"client_id">> := ClientId}) when NetworkId > 0 -> + case sdlan_network:get_pid(NetworkId) of + undefined -> + {ok, 200, sdlan_util:json_error(-1, <<"network not found">>)}; + Pid -> + sdlan_network:disable_client(Pid, ClientId), + {ok, 200, sdlan_util:json_data(<<"success">>)} + end; + +handle_request("POST", "/node/move", _, #{<<"client_id">> := ClientId, <<"from_network_id">> := FromNetworkId, <<"to_network_id">> := ToNetworkId, <<"timeout">> := Timeout}) -> + case {sdlan_network:get_pid(FromNetworkId), sdlan_network:get_pid(ToNetworkId)} of + {FromPid, ToPid} when is_pid(FromPid), is_pid(ToPid) -> + case sdlan_network:dropout_client(FromPid, ClientId) of + {ok, ChannelPid} -> + Ref = sdlan_channel:move_network(ChannelPid, self(), ToPid), + receive + {command_reply, Ref, {error, Reason}} -> + lager:warning("[node_handler] client_id: ~p, move network from: ~p, to: ~p, get error: ~p", [ClientId, FromPid, ToPid, Reason]), + {ok, 200, sdlan_util:json_error(-1, <<"move failed">>)}; + {command_reply, Ref, #sdl_command_ack{status = true}} -> + {ok, 200, sdlan_util:json_data(<<"success">>)}; + {command_reply, Ref, #sdl_command_ack{status = false, message = ErrorMsg}} when is_binary(ErrorMsg) -> + {ok, 200, sdlan_util:json_error(-1, <<"move failed: ", ErrorMsg/binary>>)} + after Timeout * 1000 -> + {ok, 200, sdlan_util:json_error(-1, <<"move timeout">>)} + end; + error -> + {ok, 200, sdlan_util:json_error(-1, <<"dropout from from_network error">>)} + end; + {FromPid, undefined} when is_pid(FromPid) -> + {ok, 200, sdlan_util:json_error(-1, <<"to_network not found">>)}; + {undefined, ToPid} when is_pid(ToPid) -> + {ok, 200, sdlan_util:json_error(-1, <<"from_network not found">>)} + end; + +handle_request(_, Path, _, _) -> + Path1 = list_to_binary(Path), + {ok, 200, sdlan_util:json_error(-1, <<"url: ", Path1/binary, " not found">>)}. \ No newline at end of file diff --git a/apps/sdlan/src/http_handler/test_handler.erl b/apps/sdlan/src/http_handler/test_handler.erl new file mode 100644 index 0000000..b03d977 --- /dev/null +++ b/apps/sdlan/src/http_handler/test_handler.erl @@ -0,0 +1,77 @@ +%%%------------------------------------------------------------------- +%%% @author licheng5 +%%% @copyright (C) 2020, +%%% @doc +%%% +%%% @end +%%% Created : 26. 4月 2020 3:36 下午 +%%%------------------------------------------------------------------- +-module(test_handler). +-author("licheng5"). + +%% API +-export([handle_request/4]). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% helper methods +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% 重新加载对应的主机信息 +handle_request("POST", "/test/auth_token", _, PostParams) -> + lager:debug("[test_handler] get post params: ~p", [PostParams]), + Data = #{ + <<"network_id">> => 8, + <<"upgrade_type">> => 0, + <<"upgrade_prompt">> => <<"simple upgrade">>, + <<"upgrade_address">> => <<"upgrade_address">> + }, + {ok, 200, sdlan_util:json_data(Data)}; + +handle_request("POST", "/test/upgrade", _, PostParams) -> + lager:debug("[test_handler] get post params: ~p", [PostParams]), + Data = #{ + <<"upgrade_type">> => 1, + <<"upgrade_prompt">> => <<"prompt需要升级"/utf8>>, + <<"upgrade_address">> => <<"macappstore://apps.apple.com/app/id836500024">> + }, + {ok, 200, sdlan_util:json_data(Data)}; + +handle_request("GET", "/test/get_all_networks", _, _) -> + {ok, 200, sdlan_util:json_data([8, 9, 10])}; + +handle_request("GET", "/test/get_network", #{<<"id">> := Id0}, _) -> + Id = binary_to_integer(Id0), + Networks = #{ + 8 => #{ + <<"id">> => 8, + <<"name">> => <<"test1">>, + <<"ipaddr">> => <<"10.211.179.0/24">>, + <<"owner_id">> => 1234, + <<"disabled_clients">> => [] + }, + 9 => #{ + <<"id">> => 9, + <<"name">> => <<"test2">>, + <<"ipaddr">> => <<"10.211.180.0/24">>, + <<"owner_id">> => 1234, + <<"disabled_clients">> => [] + }, + 10 => #{ + <<"id">> => 10, + <<"name">> => <<"test3">>, + <<"ipaddr">> => <<"10.211.181.0/24">>, + <<"owner_id">> => 1234, + <<"disabled_clients">> => [] + } + }, + Network = maps:get(Id, Networks), + + {ok, 200, sdlan_util:json_data(Network)}; + +handle_request(_, Path, _, _) -> + Path1 = list_to_binary(Path), + {ok, 200, sdlan_util:json_error(-1, <<"url: ", Path1/binary, " not found">>)}. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% helper methods +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \ No newline at end of file diff --git a/apps/sdlan/src/mnesia/client_model.erl b/apps/sdlan/src/mnesia/client_model.erl new file mode 100644 index 0000000..08fc660 --- /dev/null +++ b/apps/sdlan/src/mnesia/client_model.erl @@ -0,0 +1,134 @@ +%%%------------------------------------------------------------------- +%%% @author aresei +%%% @copyright (C) 2023, +%%% @doc +%%% +%%% @end +%%% Created : 04. 7月 2023 12:31 +%%%------------------------------------------------------------------- +-module(client_model). +-author("aresei"). +-include("sdlan_tables.hrl"). +-include_lib("stdlib/include/qlc.hrl"). + +%% API +-export([create_table/1, get_table_name/1]). +-export([get_clients/1, delete_clients/1, delete_client/2, disable_client/2, alloc_ip/5]). +-export([debug/1]). + +create_table(Tab) when is_atom(Tab) -> + mnesia:create_table(Tab, [ + {attributes, record_info(fields, client)}, + {record_name, client}, + {disc_copies, [node()]}, + {type, set} + ]). + +-spec get_table_name(NetworkId :: integer()) -> TableName :: atom(). +get_table_name(NetworkId) when is_integer(NetworkId) -> + list_to_atom("client_" ++ integer_to_list(NetworkId)). + +-spec get_clients(NetworkId :: integer()) -> [Client :: #client{}]. +get_clients(NetworkId) when is_integer(NetworkId) -> + Tab = get_table_name(NetworkId), + case mnesia:transaction(fun() -> mnesia:foldl(fun(R, Acc0) -> [R|Acc0] end, [], Tab) end) of + {'atomic', Items} -> + lists:reverse(Items); + {'aborted', _} -> + [] + end. + +-spec delete_clients(NetworkId :: integer()) -> ok | {error, Reason :: any()}. +delete_clients(NetworkId) when is_integer(NetworkId) -> + Tab = get_table_name(NetworkId), + case mnesia:transaction(fun() -> mnesia:clear_table(Tab) end) of + {'atomic', ok} -> + ok; + {'aborted', Reason} -> + {error, Reason} + end. + +-spec delete_client(NetworkId :: integer(), ClientId :: binary()) -> ok | {error, Reason :: any()}. +delete_client(NetworkId, ClientId) when is_integer(NetworkId), is_binary(ClientId) -> + Tab = get_table_name(NetworkId), + case mnesia:transaction(fun() -> mnesia:delete(Tab, ClientId, write) end) of + {'atomic', ok} -> + ok; + {'aborted', Reason} -> + {error, Reason} + end. + +-spec disable_client(NetworkId :: integer(), ClientId :: binary()) -> ok | {error, Reason :: any()}. +disable_client(NetworkId, ClientId) when is_integer(NetworkId), is_binary(ClientId) -> + Tab = get_table_name(NetworkId), + Fun = fun() -> + case mnesia:read(Tab, ClientId, read) of + [] -> + ok; + [Client] -> + mnesia:write(client, Client#client{status = disabled}, write) + end + end, + + case mnesia:transaction(Fun) of + {'atomic', ok} -> + ok; + {'aborted', Reason} -> + {error, Reason} + end. + +%% 分配ip地址的时候,以mac地址为唯一基准 +-spec alloc_ip(NetworkId :: integer(), Ips :: list(), ClientId :: binary(), Mac :: binary(), NetAddr0 :: integer()) -> + {ok, Ip :: integer()} | {error, Reason :: any()}. +alloc_ip(NetworkId, Ips, ClientId, Mac, NetAddr0) when is_binary(ClientId), is_integer(NetAddr0), is_binary(Mac) -> + case mnesia:transaction(fun() -> alloc_ip0(NetworkId, Ips, ClientId, Mac, NetAddr0) end) of + {'atomic', Res} -> + {ok, Res}; + {'aborted', Reason} -> + {error, Reason} + end. +alloc_ip0(NetworkId, Ips, ClientId, Mac, NetAddr0) -> + Tab = get_table_name(NetworkId), + + case mnesia:read(Tab, ClientId) of + [Client=#client{ip = Ip, status = normal}] -> + ok = mnesia:write(client, Client#client{mac = Mac}, write), + Ip; + [#client{status = disabled}] -> + mnesia:abort(client_disabled); + [] -> + UsedIps = mnesia:foldl(fun(#client{ip = Ip0}, Acc) -> [Ip0|Acc] end, [], Tab), + case lists:member(NetAddr0, Ips) andalso not lists:member(NetAddr0, UsedIps) of + true -> + %% 如果ip没有被占用,则分配給当前请求 + Client = #client{client_id = ClientId, mac = Mac, ip = NetAddr0}, + ok = mnesia:write(client, Client, write), + NetAddr0; + false -> + case Ips -- UsedIps of + [] -> + mnesia:abort(no_ip); + [Ip|_] -> + Client = #client{client_id = ClientId, mac = Mac, ip = Ip, status = normal}, + ok = mnesia:write(client, Client, write), + Ip + end + end + end. + +%%%=================================================================== +%%% helper functions +%%%=================================================================== + +debug(NetworkId) when is_integer(NetworkId) -> + Tab = get_table_name(NetworkId), + F = fun() -> + Q = qlc:q([E || E <- mnesia:table(Tab)]), + qlc:e(Q) + end, + case mnesia:transaction(F) of + {'atomic', Records} -> + lists:foreach(fun(C) -> lager:debug("client: ~p", [C]) end, Records); + {'aborted', Reason} -> + lager:warning("read clients get error: ~p", [Reason]) + end. \ No newline at end of file diff --git a/apps/sdlan/src/mnesia/mnesia_id_generator.erl b/apps/sdlan/src/mnesia/mnesia_id_generator.erl new file mode 100644 index 0000000..cab8586 --- /dev/null +++ b/apps/sdlan/src/mnesia/mnesia_id_generator.erl @@ -0,0 +1,26 @@ +%%%------------------------------------------------------------------- +%%% @author aresei +%%% @copyright (C) 2023, +%%% @doc +%%% +%%% @end +%%% Created : 04. 7月 2023 12:31 +%%%------------------------------------------------------------------- +-module(mnesia_id_generator). +-author("aresei"). +-include("sdlan.hrl"). + +%% API +-export([next_id/1, create_table/0]). + +create_table() -> + %% id生成器 + mnesia:create_table(id_generator, [ + {attributes, record_info(fields, id_generator)}, + {record_name, id_generator}, + {disc_copies, [node()]}, + {type, ordered_set} + ]). + +next_id(Tab) when is_atom(Tab) -> + mnesia:dirty_update_counter(id_generator, Tab, 1). \ No newline at end of file diff --git a/apps/sdlan/src/mnesia/mnesia_manager.erl b/apps/sdlan/src/mnesia/mnesia_manager.erl new file mode 100644 index 0000000..55e18bd --- /dev/null +++ b/apps/sdlan/src/mnesia/mnesia_manager.erl @@ -0,0 +1,43 @@ +%%%------------------------------------------------------------------- +%%% @author anlicheng +%%% @copyright (C) 2024, +%%% @doc +%%% TODO 数据库暂时不启用 +%%% @end +%%% Created : 28. 3月 2024 11:01 +%%%------------------------------------------------------------------- +-module(mnesia_manager). +-author("anlicheng"). +-include("sdlan.hrl"). + +%% API +-export([init_database/0, join/1, copy_database/1]). + +init_database() -> + %% 清理掉以前的schema + mnesia:stop(), + mnesia:delete_schema([node()]), + + %% 创建schema + ok = mnesia:create_schema([node()]), + ok = mnesia:start(), + ok. + +%% 加入集群 +join(MasterNode) when is_atom(MasterNode) -> + net_kernel:connect_node(MasterNode). + +%% 初始化slave数据库 +copy_database(MasterNode) when is_atom(MasterNode) -> + %% 清理旧的schema + mnesia:stop(), + mnesia:delete_schema([node()]), + %% 重新启动数据库 + mnesia:start(), + + rpc:call(MasterNode, mnesia, change_config, [extra_db_nodes, [node()]]), + mnesia:change_table_copy_type(schema, node(), disc_copies), + + %% 增加表的分区复制 + % mnesia:add_table_copy(client, node(), ram_copies), + ok. \ No newline at end of file diff --git a/apps/sdlan/src/model/network_bo.erl b/apps/sdlan/src/model/network_bo.erl new file mode 100644 index 0000000..c1160f6 --- /dev/null +++ b/apps/sdlan/src/model/network_bo.erl @@ -0,0 +1,29 @@ +%%%------------------------------------------------------------------- +%%% @author aresei +%%% @copyright (C) 2023, +%%% @doc +%%% +%%% @end +%%% Created : 16. 5月 2023 12:48 +%%%------------------------------------------------------------------- +-module(network_bo). +-author("aresei"). +-include("sdlan.hrl"). + +-define(POOL_NAME, mysql_sdlan). + +%% API +-export([get_all_networks/0, get_network_by_id/1]). + +-spec get_all_networks() -> Networks :: [integer()]. +get_all_networks() -> + case mysql_pool:get_all(?POOL_NAME, <<"SELECT id FROM network">>) of + {ok, Networks} -> + lists:map(fun(#{<<"id">> := Id}) -> Id end, Networks); + {error, _} -> + [] + end. + +-spec get_network_by_id(Id :: integer()) -> undefined | {ok, NetworkInfo :: map()}. +get_network_by_id(Id) when is_integer(Id) -> + mysql_pool:get_row(?POOL_NAME, <<"SELECT * FROM network WHERE id = ? LIMIT 1">>, [Id]). \ No newline at end of file diff --git a/apps/sdlan/src/mysql/mysql_pool.erl b/apps/sdlan/src/mysql/mysql_pool.erl new file mode 100644 index 0000000..cbceac5 --- /dev/null +++ b/apps/sdlan/src/mysql/mysql_pool.erl @@ -0,0 +1,48 @@ +%%%------------------------------------------------------------------- +%%% @author aresei +%%% @copyright (C) 2018, +%%% @doc +%%% +%%% @end +%%% Created : 29. 九月 2018 17:01 +%%%------------------------------------------------------------------- +-module(mysql_pool). +-author("aresei"). + +%% API +-export([get_row/2, get_row/3, get_all/2, get_all/3]). +-export([update/4, update_by/2, update_by/3, insert/4]). + +%% 从数据库中查找一行记录 +-spec get_row(Pool :: atom(), Sql::binary()) -> {ok, Record::map()} | undefined. +get_row(Pool, Sql) when is_atom(Pool), is_binary(Sql) -> + poolboy:transaction(Pool, fun(ConnPid) -> mysql_provider:get_row(ConnPid, Sql) end). + +-spec get_row(Pool :: atom(), Sql::binary(), Params::list()) -> {ok, Record::map()} | undefined. +get_row(Pool, Sql, Params) when is_atom(Pool), is_binary(Sql), is_list(Params) -> + poolboy:transaction(Pool, fun(ConnPid) -> mysql_provider:get_row(ConnPid, Sql, Params) end). + +-spec get_all(Pool :: atom(), Sql::binary()) -> {ok, Rows::list()} | {error, Reason :: any()}. +get_all(Pool, Sql) when is_atom(Pool), is_binary(Sql) -> + poolboy:transaction(Pool, fun(ConnPid) -> mysql_provider:get_all(ConnPid, Sql) end). + +-spec get_all(Pool :: atom(), Sql::binary(), Params::list()) -> {ok, Rows::list()} | {error, Reason::any()}. +get_all(Pool, Sql, Params) when is_atom(Pool), is_binary(Sql), is_list(Params) -> + poolboy:transaction(Pool, fun(ConnPid) -> mysql_provider:get_all(ConnPid, Sql, Params) end). + +-spec insert(Pool :: atom(), Table :: binary(), Fields :: map() | list(), boolean()) -> + ok | {ok, InsertId :: integer()} | {error, Reason :: any()}. +insert(Pool, Table, Fields, FetchInsertId) when is_atom(Pool), is_binary(Table), is_list(Fields); is_map(Fields), is_boolean(FetchInsertId) -> + poolboy:transaction(Pool, fun(ConnPid) -> mysql_provider:insert(ConnPid, Table, Fields, FetchInsertId) end). + +-spec update_by(Pool :: atom(), UpdateSql :: binary()) -> {ok, AffectedRows :: integer()} | {error, Reason :: any()}. +update_by(Pool, UpdateSql) when is_atom(Pool), is_binary(UpdateSql) -> + poolboy:transaction(Pool, fun(ConnPid) -> mysql_provider:update_by(ConnPid, UpdateSql) end). + +-spec update_by(Pool :: atom(), UpdateSql :: binary(), Params :: list()) -> {ok, AffectedRows :: integer()} | {error, Reason :: any()}. +update_by(Pool, UpdateSql, Params) when is_atom(Pool), is_binary(UpdateSql) -> + poolboy:transaction(Pool, fun(ConnPid) -> mysql_provider:update_by(ConnPid, UpdateSql, Params) end). + +-spec update(Pool :: atom(), Table :: binary(), Fields :: map(), WhereFields :: map()) -> {ok, AffectedRows::integer()} | {error, Reason::any()}. +update(Pool, Table, Fields, WhereFields) when is_atom(Pool), is_binary(Table), is_map(Fields), is_map(WhereFields) -> + poolboy:transaction(Pool, fun(ConnPid) -> mysql_provider:update(ConnPid, Table, Fields, WhereFields) end). \ No newline at end of file diff --git a/apps/sdlan/src/mysql/mysql_provider.erl b/apps/sdlan/src/mysql/mysql_provider.erl new file mode 100644 index 0000000..7415f9d --- /dev/null +++ b/apps/sdlan/src/mysql/mysql_provider.erl @@ -0,0 +1,144 @@ +%%%------------------------------------------------------------------- +%%% @author aresei +%%% @copyright (C) 2018, +%%% @doc +%%% +%%% @end +%%% Created : 29. 九月 2018 17:01 +%%%------------------------------------------------------------------- +-module(mysql_provider). +-author("aresei"). + +%% API +-export([get_row/2, get_row/3, get_all/2, get_all/3]). +-export([update/4, update_by/2, update_by/3, insert/4]). + +%% 从数据库中查找一行记录 +-spec get_row(ConnPid :: pid(), Sql::binary()) -> {ok, Record::map()} | undefined. +get_row(ConnPid, Sql) when is_pid(ConnPid), is_binary(Sql) -> + lager:debug("[mysql_client] get_row sql is: ~p", [Sql]), + case mysql:query(ConnPid, Sql) of + {ok, Names, [Row | _]} -> + {ok, maps:from_list(lists:zip(Names, Row))}; + {ok, _, []} -> + undefined; + Error -> + lager:warning("[mysql_client] get error: ~p", [Error]), + undefined + end. + +-spec get_row(ConnPid :: pid(), Sql::binary(), Params::list()) -> {ok, Record::map()} | undefined. +get_row(ConnPid, Sql, Params) when is_pid(ConnPid), is_binary(Sql), is_list(Params) -> + lager:debug("[mysql_client] get_row sql is: ~p, params: ~p", [Sql, Params]), + case mysql:query(ConnPid, Sql, Params) of + {ok, Names, [Row | _]} -> + {ok, maps:from_list(lists:zip(Names, Row))}; + {ok, _, []} -> + undefined; + Error -> + lager:warning("[mysql_client] get error: ~p", [Error]), + undefined + end. + +-spec get_all(ConnPid :: pid(), Sql::binary()) -> {ok, Rows::list()} | {error, Reason :: any()}. +get_all(ConnPid, Sql) when is_pid(ConnPid), is_binary(Sql) -> + lager:debug("[mysql_client] get_all sql is: ~p", [Sql]), + case mysql:query(ConnPid, Sql) of + {ok, Names, Rows} -> + {ok, lists:map(fun(Row) -> maps:from_list(lists:zip(Names, Row)) end, Rows)}; + {error, Reason} -> + lager:warning("[mysql_client] get error: ~p", [Reason]), + {error, Reason} + end. + +-spec get_all(ConnPid :: pid(), Sql::binary(), Params::list()) -> {ok, Rows::list()} | {error, Reason::any()}. +get_all(ConnPid, Sql, Params) when is_pid(ConnPid), is_binary(Sql), is_list(Params) -> + lager:debug("[mysql_client] get_all sql is: ~p, params: ~p", [Sql, Params]), + case mysql:query(ConnPid, Sql, Params) of + {ok, Names, Rows} -> + {ok, lists:map(fun(Row) -> maps:from_list(lists:zip(Names, Row)) end, Rows)}; + {error, Reason} -> + lager:warning("[mysql_client] get error: ~p", [Reason]), + {error, Reason} + end. + +-spec insert(ConnPid :: pid(), Table :: binary(), Fields :: map() | list(), boolean()) -> + ok | {ok, InsertId :: integer()} | {error, Reason :: any()}. +insert(ConnPid, Table, Fields, FetchInsertId) when is_pid(ConnPid), is_binary(Table), is_map(Fields), is_boolean(FetchInsertId) -> + insert(ConnPid, Table, maps:to_list(Fields), FetchInsertId); +insert(ConnPid, Table, Fields, FetchInsertId) when is_pid(ConnPid), is_binary(Table), is_list(Fields), is_boolean(FetchInsertId) -> + {Keys, Values} = kvs(Fields), + + FieldSql = iolist_to_binary(lists:join(<<", ">>, Keys)), + Placeholders = lists:duplicate(length(Keys), <<"?">>), + ValuesPlaceholder = iolist_to_binary(lists:join(<<", ">>, Placeholders)), + + Sql = <<"INSERT INTO ", Table/binary, "(", FieldSql/binary, ") VALUES(", ValuesPlaceholder/binary, ")">>, + lager:debug("[mysql_client] insert sql is: ~p, params: ~p", [Sql, Values]), + case mysql:query(ConnPid, Sql, Values) of + ok -> + case FetchInsertId of + true -> + InsertId = mysql:insert_id(ConnPid), + {ok, InsertId}; + false -> + ok + end; + Error -> + Error + end. + +-spec update_by(ConnPid :: pid(), UpdateSql :: binary()) -> {ok, AffectedRows :: integer()} | {error, Reason :: any()}. +update_by(ConnPid, UpdateSql) when is_pid(ConnPid), is_binary(UpdateSql) -> + lager:debug("[mysql_client] updateBySql sql: ~p", [UpdateSql]), + case mysql:query(ConnPid, UpdateSql) of + ok -> + AffectedRows = mysql:affected_rows(ConnPid), + {ok, AffectedRows}; + Error -> + Error + end. + +-spec update_by(ConnPid :: pid(), UpdateSql :: binary(), Params :: list()) -> {ok, AffectedRows :: integer()} | {error, Reason :: any()}. +update_by(ConnPid, UpdateSql, Params) when is_pid(ConnPid), is_binary(UpdateSql) -> + lager:debug("[mysql_client] updateBySql sql: ~p, params: ~p", [UpdateSql, Params]), + case mysql:query(ConnPid, UpdateSql, Params) of + ok -> + AffectedRows = mysql:affected_rows(ConnPid), + {ok, AffectedRows}; + Error -> + Error + end. + +-spec update(ConnPid :: pid(), Sql :: binary(), Fields :: map(), WhereFields :: map()) -> + {ok, AffectedRows::integer()} | {error, Reason::any()}. +update(ConnPid, Table, Fields, WhereFields) when is_pid(ConnPid), is_binary(Table), is_map(Fields), is_map(WhereFields) -> + %% 拼接set + {SetKeys, SetVals} = kvs(Fields), + SetKeys1 = lists:map(fun(K) when is_binary(K) -> <<"`", K/binary, "` = ?">> end, SetKeys), + SetSql = iolist_to_binary(lists:join(<<", ">>, SetKeys1)), + + %% 拼接where + {WhereKeys, WhereVals} = kvs(WhereFields), + WhereKeys1 = lists:map(fun(K) when is_binary(K) -> <<"`", K/binary, "` = ?">> end, WhereKeys), + WhereSql = iolist_to_binary(lists:join(<<" AND ">>, WhereKeys1)), + + Params = SetVals ++ WhereVals, + + Sql = <<"UPDATE ", Table/binary, " SET ", SetSql/binary, " WHERE ", WhereSql/binary>>, + lager:debug("[mysql_client] update sql is: ~p, params: ~p", [Sql, Params]), + case mysql:query(ConnPid, Sql, Params) of + ok -> + AffectedRows = mysql:affected_rows(ConnPid), + {ok, AffectedRows}; + Error -> + lager:error("[mysql_client] update sql: ~p, params: ~p, get a error: ~p", [Sql, Params, Error]), + Error + end. + +-spec kvs(Fields :: map() | list()) -> {Keys :: list(), Values :: list()}. +kvs(Fields) when is_map(Fields) -> + kvs(maps:to_list(Fields)); +kvs(Fields) when is_list(Fields) -> + {Keys0, Values0} = lists:foldl(fun({K, V}, {Acc0, Acc1}) -> {[K|Acc0], [V|Acc1]} end, {[], []}, Fields), + {lists:reverse(Keys0), lists:reverse(Values0)}. \ No newline at end of file diff --git a/apps/sdlan/src/sdlan.app.src b/apps/sdlan/src/sdlan.app.src new file mode 100644 index 0000000..bbe1acf --- /dev/null +++ b/apps/sdlan/src/sdlan.app.src @@ -0,0 +1,31 @@ +{application, sdlan, + [{description, "An OTP application"}, + {vsn, "0.1.0"}, + {registered, []}, + {mod, {sdlan_app, []}}, + {applications, + [ + sync, + lager, + cowboy, + ranch, + poolboy, + mysql, + esockd, + jiffy, + hackney, + gpb, + throttle, + parse_trans, + mnesia, + erts, + kernel, + crypto, + stdlib + ]}, + {env,[]}, + {modules, []}, + + {licenses, ["Apache-2.0"]}, + {links, []} + ]}. diff --git a/apps/sdlan/src/sdlan_api.erl b/apps/sdlan/src/sdlan_api.erl new file mode 100644 index 0000000..5628a76 --- /dev/null +++ b/apps/sdlan/src/sdlan_api.erl @@ -0,0 +1,170 @@ +%%%------------------------------------------------------------------- +%%% @author anlicheng +%%% @copyright (C) 2024, +%%% @doc +%%% +%%% @end +%%% Created : 27. 3月 2024 16:17 +%%%------------------------------------------------------------------- +-module(sdlan_api). +-author("anlicheng"). + +-define(API_TOKEN, <<"wv6fGyBhl*7@AsD9">>). + +%% API +-export([get_all_networks/0, get_network/1]). +-export([auth_token/3, node_online/3, node_offline/2, flow_report/5, network_forward_report/2]). + +-spec get_all_networks() -> {ok, [NetworkId :: integer()]} | {error, Reason :: any()}. +get_all_networks() -> + case catch do_get("get_all_networks", []) of + {ok, Resp} -> + case catch jiffy:decode(Resp, [return_maps]) of + #{<<"result">> := Networks} -> + {ok, Networks}; + #{<<"error">> := #{<<"code">> := Code, <<"message">> := Message}} -> + {error, {Code, Message}}; + _ -> + {error, <<"invalid json">>} + end; + Error -> + Error + end. + +-spec get_network(Id :: integer()) -> {ok, Network :: map()} | {error, Reason :: any()}. +get_network(Id) when is_integer(Id) -> + case catch do_get("get_network", [{<<"id">>, integer_to_binary(Id)}]) of + {ok, Resp} -> + case catch jiffy:decode(Resp, [return_maps]) of + #{<<"result">> := Network} -> + {ok, Network}; + #{<<"error">> := #{<<"code">> := Code, <<"message">> := Message}} -> + {error, {Code, Message}}; + _ -> + {error, <<"invalid json">>} + end; + Error -> + Error + end. + +-spec auth_token(ClientId :: binary(), Token :: binary(), Version :: integer()) -> {ok, Resp :: map()} | {error, Reason :: any()}. +auth_token(ClientId, Token, Version) when is_binary(ClientId), is_binary(Token), is_integer(Version) -> + case catch do_post("auth_token", #{<<"client_id">> => ClientId, <<"token">> => Token, <<"version">> => Version}) of + {ok, Resp} -> + case catch jiffy:decode(Resp, [return_maps]) of + Result when is_map(Result) -> + {ok, Result}; + {error, Reason} -> + {error, Reason} + end; + Error -> + Error + end. + +-spec node_online(ClientId :: binary(), NetworkId :: integer(), IpAddr :: binary()) -> {ok, Resp :: map()} | {error, Reason :: any()}. +node_online(ClientId, NetworkId, IpAddr) when is_binary(ClientId), is_integer(NetworkId), is_binary(IpAddr) -> + case catch do_post("set_node_status", #{<<"client_id">> => ClientId, <<"network_id">> => NetworkId, <<"ip_addr">> => IpAddr, <<"status">> => 1}) of + {ok, Resp} -> + {ok, catch jiffy:decode(Resp, [return_maps])}; + Error -> + Error + end. + +-spec node_offline(ClientId :: binary(), NetworkId :: integer()) -> {ok, Resp :: map()} | {error, Reason :: any()}. +node_offline(ClientId, NetworkId) when is_binary(ClientId), is_integer(NetworkId) -> + case catch do_post("set_node_status", #{<<"client_id">> => ClientId, <<"network_id">> => NetworkId, <<"status">> => 0}) of + {ok, Resp} -> + {ok, catch jiffy:decode(Resp, [return_maps])}; + Error -> + Error + end. + +-spec flow_report(ClientId :: binary(), NetworkId :: integer(), ForwardNum :: integer(), P2PNum :: integer(), InboundNum :: integer()) -> + {ok, Resp :: map()} | {error, Reason :: any()}. +flow_report(ClientId, NetworkId, ForwardNum, P2PNum, InboundNum) + when is_binary(ClientId), is_integer(NetworkId), is_integer(ForwardNum), is_integer(P2PNum), is_integer(InboundNum) -> + Params = #{ + <<"client_id">> => ClientId, + <<"network_id">> => NetworkId, + <<"forward_num">> => ForwardNum, + <<"p2p_num">> => P2PNum, + <<"inbound_num">> => InboundNum + }, + case catch do_post("client_flow_report", Params) of + {ok, Resp} -> + {ok, catch jiffy:decode(Resp, [return_maps])}; + Error -> + Error + end. + +-spec network_forward_report(NetworkId :: integer(), ForwardNum :: integer()) -> + {ok, Resp :: map()} | {error, Reason :: any()}. +network_forward_report(NetworkId, ForwardNum) when is_integer(NetworkId), is_integer(ForwardNum) -> + Params = #{ + <<"network_id">> => NetworkId, + <<"forward_num">> => ForwardNum + }, + case catch do_post("network_forward_report", Params) of + {ok, Resp} -> + {ok, catch jiffy:decode(Resp, [return_maps])}; + Error -> + Error + end. + +-spec do_get(Uri :: string(), Params :: [{K :: binary(), V :: binary()}]) -> {ok, Response :: binary()} | {error, Reason :: any()}. +do_get(Uri, Params) when is_list(Uri), is_list(Params) -> + Token = sdlan_util:md5(<>), + {ok, Url0} = application:get_env(sdlan, api_url), + + Headers = [ + {<<"content-type">>, <<"application/json">>}, + {<<"token">>, Token} + ], + + QS0 = uri_string:compose_query(Params), + QS = iolist_to_binary(QS0), + + Url = Url0 ++ Uri ++ "?" ++ binary_to_list(QS), + case catch hackney:request(get, Url, Headers, <<>>, [{pool, false}]) of + {ok, 200, _, ClientRef} -> + {ok, RespBody} = hackney:body(ClientRef), + hackney:close(ClientRef), + {ok, RespBody}; + {ok, HttpCode, _, ClientRef} -> + {ok, RespBody} = hackney:body(ClientRef), + hackney:close(ClientRef), + {error, {HttpCode, RespBody}}; + {error, Reason} -> + {error, Reason} + end. + +-spec do_post(Uri :: string(), Params :: list() | map()) -> {ok, Resp :: binary()} | {error, Reason :: any()}. +do_post(Uri, Params) when is_list(Uri), is_map(Params); is_list(Params) -> + Token = sdlan_util:md5(<>), + {ok, Url0} = application:get_env(sdlan, api_url), + + Headers = [ + {<<"content-type">>, <<"application/json">>}, + {<<"token">>, Token} + ], + + Body = iolist_to_binary(jiffy:encode(Params, [force_utf8])), + Url = Url0 ++ Uri, + + case catch hackney:request(post, Url, Headers, Body, [{pool, false}]) of + {ok, 200, _, ClientRef} -> + {ok, RespBody} = hackney:body(ClientRef), + hackney:close(ClientRef), + {ok, RespBody}; + {ok, HttpCode, _, ClientRef} -> + {ok, RespBody} = hackney:body(ClientRef), + hackney:close(ClientRef), + {error, {HttpCode, RespBody}}; + {ok, HttpCode, _} -> + {error, {HttpCode, <<"empty response">>}}; + {ok, ClientRef} -> + hackney:close(ClientRef), + {error, <<"empty response">>}; + {error, Reason} -> + {error, Reason} + end. \ No newline at end of file diff --git a/apps/sdlan/src/sdlan_app.erl b/apps/sdlan/src/sdlan_app.erl new file mode 100644 index 0000000..c5f4400 --- /dev/null +++ b/apps/sdlan/src/sdlan_app.erl @@ -0,0 +1,78 @@ +%%%------------------------------------------------------------------- +%% @doc sdlan public API +%% @end +%%%------------------------------------------------------------------- + +-module(sdlan_app). + +-behaviour(application). + +-export([start/2, stop/1]). + +start(_StartType, _StartArgs) -> + io:setopts([{encoding, unicode}]), + %% 启动mnesia数据库 + mnesia:start(), + %% 加速内存的回收 + erlang:system_flag(fullsweep_after, 16), + start_http_server(), + start_tcp_server(), + sdlan_sup:start_link(). + +stop(_State) -> + ok. + +%% internal functions + +%% 启动http服务 +start_http_server() -> + {ok, Props} = application:get_env(sdlan, http_server), + Acceptors = proplists:get_value(acceptors, Props, 50), + MaxConnections = proplists:get_value(max_connections, Props, 10240), + Backlog = proplists:get_value(backlog, Props, 1024), + Port = proplists:get_value(port, Props), + + Dispatcher = cowboy_router:compile([ + {'_', [ + {"/file/[...]", file_handler, []}, + {"/api/[...]", http_protocol, [api_handler]}, + {"/network/[...]", http_protocol, [network_handler]}, + {"/node/[...]", http_protocol, [node_handler]}, + {"/test/[...]", http_protocol, [test_handler]} + ]} + ]), + + TransOpts = [ + {port, Port}, + {num_acceptors, Acceptors}, + {backlog, Backlog}, + {max_connections, MaxConnections} + ], + + {ok, Pid} = cowboy:start_clear(http_listener, TransOpts, #{env => #{dispatch => Dispatcher}}), + + lager:debug("[iot_app] the http server start at: ~p, pid is: ~p", [Port, Pid]). + +%% 启动tcp服务 +start_tcp_server() -> + {ok, Props} = application:get_env(sdlan, tcp_server), + Acceptors = proplists:get_value(acceptors, Props, 50), + MaxConnections = proplists:get_value(max_connections, Props, 10240), + Backlog = proplists:get_value(backlog, Props, 1024), + Port = proplists:get_value(port, Props), + + TransOpts = [ + {tcp_options, [ + binary, + {reuseaddr, true}, + {active, false}, + {packet, 2}, + {nodelay, false}, + {backlog, Backlog} + ]}, + {acceptors, Acceptors}, + {max_connections, MaxConnections} + ], + {ok, _} = esockd:open('sdlan/tcp_server', Port, TransOpts, {sdlan_channel, start_link, []}), + + lager:debug("[sdlan_app] the tcp server start at: ~p", [Port]). \ No newline at end of file diff --git a/apps/sdlan/src/sdlan_channel.erl b/apps/sdlan/src/sdlan_channel.erl new file mode 100644 index 0000000..5ce73e0 --- /dev/null +++ b/apps/sdlan/src/sdlan_channel.erl @@ -0,0 +1,366 @@ +%%%------------------------------------------------------------------- +%%% @author licheng5 +%%% @copyright (C) 2020, +%%% @doc +%%% +%%% @end +%%% Created : 10. 12月 2020 上午11:17 +%%%------------------------------------------------------------------- +-module(sdlan_channel). +-author("licheng5"). +-behaviour(gen_server). + +-include("sdlan.hrl"). +-include("sdlan_pb.hrl"). + +%% 心跳包监测机制 +-define(PING_TICKER, 15000). + +%% 注册失败的的错误码 + +%% token不存在 +-define(NAK_INVALID_TOKEN, 1). +%% 节点被禁用 +-define(NAK_NODE_DISABLE, 2). +%% 没有IP地址可以用 +-define(NAK_NO_IP, 3). +%% 网络错误 +-define(NAK_NETWORK_FAULT, 4). +%% 内部错误 +-define(NAK_INTERNAL_FAULT, 5). + +%% 升级策略 +-define(UPGRADE_NONE, 0). +-define(UPGRADE_NORMAL, 1). +-define(UPGRADE_FORCE, 2). + +%% API +-export([start_link/2]). +-export([publish_command/4, send_event/3, stop/2, move_network/3]). + +-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). + +-record(state, { + transport, + socket, + + client_id :: undefined | binary(), + pub_key :: undefined | binary(), + token :: undefined | binary(), + + %% 分配的ip地址 + assign_ip :: undefined | integer(), + %% 网络相关信息id + network_pid :: undefined | pid(), + %% mac地址 + mac :: undefined | binary(), + + %% 标记是否已经注册 + is_registered = false, + + %% 记录ping的次数 + ping_counter = 0, + + %% 发送消息对应的id + packet_id = 1 :: integer(), + %% 请求响应的对应关系 + inflight = #{} +}). + +%% 向通道中写入消息 +-spec publish_command(Pid :: pid(), ReceiverPid :: pid(), CommandType :: integer(), Msg :: binary()) -> Ref :: reference(). +publish_command(Pid, ReceiverPid, CommandType, Msg) when is_pid(Pid), is_pid(ReceiverPid), is_integer(CommandType), is_binary(Msg) -> + Ref = make_ref(), + Pid ! {publish_command, ReceiverPid, Ref, CommandType, Msg}, + Ref. + +%% 网络迁移是一种特殊的指令信息,需要单独处理 +-spec move_network(Pid :: pid(), ReceiverPid :: pid(), NetworkPid :: pid()) -> Ref :: reference(). +move_network(Pid, ReceiverPid, NetworkPid) when is_pid(Pid), is_pid(ReceiverPid), is_pid(NetworkPid) -> + Ref = make_ref(), + Pid ! {move_network, ReceiverPid, Ref, NetworkPid}, + Ref. + +%% 向通道中写入消息 +-spec send_event(Pid :: pid(), EventType :: integer(), Event :: binary()) -> no_return(). +send_event(Pid, EventType, Event) when is_pid(Pid), is_integer(EventType), is_binary(Event) -> + Pid ! {send_event, EventType, Event}. + +%% 关闭方法 +-spec stop(Pid :: pid(), Reason :: any()) -> no_return(). +stop(undefined, _Reason) -> + ok; +stop(Pid, Reason) when is_pid(Pid) -> + Pid ! {stop, Reason}. + +%%-------------------------------------------------------------------- +%% esockd callback +%%-------------------------------------------------------------------- + +start_link(Transport, Sock) -> + {ok, proc_lib:spawn_link(?MODULE, init, [[Transport, Sock]])}. + +init([Transport, Sock]) -> + lager:debug("[sdlan_channel] get a new connection: ~p", [Sock]), + case Transport:wait(Sock) of + {ok, NewSock} -> + Transport:setopts(Sock, [{active, true}]), + erlang:start_timer(?PING_TICKER, self(), ping_ticker), + gen_server:enter_loop(?MODULE, [], #state{transport = Transport, socket = NewSock}); + {error, Reason} -> + {stop, Reason} + end. + +handle_call(_Request, _From, State) -> + {reply, ok, State}. + +handle_cast(_Msg, State) -> + {noreply, State}. + +handle_info({tcp, Sock, <>}, State=#state{transport = Transport, socket = Sock}) -> + #sdl_register_super{version = Version, client_id = ClientId, dev_addr = #sdl_dev_addr{net_addr = NetAddr0, mac = Mac}, token = Token, pub_key = PubKey} = sdlan_pb:decode_msg(Body, sdl_register_super), + + %% 参数检查 + lager:debug("[sdlan_channel] client_id: ~p, assert0: ~p, assert1: ~p, assert2: ~p", [ClientId, Mac =/= <<>>, PubKey =/= <<>>, ClientId =/= <<>>]), + true = (Mac =/= <<>> andalso PubKey =/= <<>> andalso ClientId =/= <<>>), + %% Mac地址不能是广播地址 + true = not (sdlan_util:is_multicast_mac(Mac) orelse sdlan_util:is_broadcast_mac(Mac)), + + case sdlan_api:auth_token(ClientId, Token, Version) of + {ok, #{<<"result">> := #{<<"network_id">> := NetworkId, <<"upgrade_type">> := UpgradeType, <<"upgrade_prompt">> := UpgradePrompt, <<"upgrade_address">> := UpgradeAddress}}} when is_integer(NetworkId) -> + lager:debug("[sdlan_channel] client_id: ~p, mac: ~p, token: ~p, version: ~p, registerd, alloc network_id: ~p", [ClientId, sdlan_util:format_mac(Mac), Token, Version, NetworkId]), + %% 建立到network的对应关系 + case sdlan_network:get_pid(NetworkId) of + NetworkPid when is_pid(NetworkPid) -> + case sdlan_network:assign_ip_addr(NetworkPid, self(), ClientId, Mac, NetAddr0) of + {ok, NetAddr, NetBitLen, AesKey} -> + RsaPubKey = sdlan_cipher:rsa_pem_decode(PubKey), + EncodedAesKey = rsa_encode(AesKey, RsaPubKey), + + RegisterSuperAck = sdlan_pb:encode_msg(#sdl_register_super_ack { + dev_addr = #sdl_dev_addr{ + network_id = NetworkId, + net_addr = NetAddr, + mac = Mac, + net_bit_len = NetBitLen + }, + aes_key = EncodedAesKey, + upgrade_type = UpgradeType, + upgrade_prompt = UpgradePrompt, + upgrade_address = UpgradeAddress + }), + + %% 发送确认信息 + Reply = <>, + Transport:send(Sock, Reply), + lager:debug("[sdlan_channel] client_id: ~p, mac: ~p, alloc ip: ~p, register will send ack", + [ClientId, sdlan_util:format_mac(Mac), sdlan_ipaddr:int_to_ipv4(NetAddr)]), + + %% 设置节点的在线状态 + Result = sdlan_api:node_online(ClientId, NetworkId, sdlan_ipaddr:int_to_ipv4(NetAddr)), + lager:debug("[sdlan_channel] client_id: ~p, set none online, result is: ~p", [ClientId, Result]), + case UpgradeType =:= ?UPGRADE_FORCE of + true -> + lager:warning("[sdlan_channel] client_id: ~p, need upgrade force!", [ClientId]), + {stop, normal, State}; + false -> + {noreply, State#state{client_id = ClientId, mac = Mac, assign_ip = NetAddr, network_pid = NetworkPid, pub_key = PubKey, is_registered = true}} + end; + {error, no_ip} -> + lager:debug("[sdlan_channel] client_id: ~p, token: ~p, register get error: no_ip", [ClientId, Token]), + Transport:send(Sock, register_nak_reply(PacketId, ?NAK_NO_IP, <<"No Ip address">>)), + {stop, normal, State}; + {error, client_disabled} -> + lager:debug("[sdlan_channel] client_id: ~p, token: ~p, register get error: client_disabled", [ClientId, Token]), + Transport:send(Sock, register_nak_reply(PacketId, ?NAK_NODE_DISABLE, <<"Client Connection Disable">>)), + {stop, normal, State} + end; + undefined -> + lager:debug("[sdlan_channel] client_id: ~p, token: ~p, register get error: network not found", [ClientId, Token]), + Transport:send(Sock, register_nak_reply(PacketId, ?NAK_INTERNAL_FAULT, <<"Internal Error">>)), + + {stop, normal, State} + end; + {ok, #{<<"error">> := #{<<"code">> := 1, <<"message">> := Message}}} -> + lager:debug("[sdlan_channel] client_id: ~p, token: ~p, register get error: ~p, error_code: 1", [ClientId, Token, Message]), + Transport:send(Sock, register_nak_reply(PacketId, ?NAK_INVALID_TOKEN, Message)), + {stop, normal, State}; + + {ok, #{<<"error">> := #{<<"code">> := 2, <<"message">> := Message}}} -> + lager:debug("[sdlan_channel] client_id: ~p, token: ~p, register get error: ~p, error_code: 2", [ClientId, Token, Message]), + Transport:send(Sock, register_nak_reply(PacketId, ?NAK_NODE_DISABLE, Message)), + {stop, normal, State}; + + {error, Reason} -> + lager:debug("[sdlan_channel] client_id: ~p, token: ~p, register get error: ~p", [ClientId, Token, Reason]), + Transport:send(Sock, register_nak_reply(PacketId, ?NAK_NETWORK_FAULT, <<"Network Error">>)), + {stop, normal, State} + end; + +handle_info({tcp, Sock, <>}, State = #state{transport = Transport, socket = Sock, network_pid = NetworkPid, mac = SrcMac, is_registered = true}) when is_pid(NetworkPid) -> + #sdl_query_info{dst_mac = DstMac} = sdlan_pb:decode_msg(Body, sdl_query_info), + case sdlan_network:peer_info(NetworkPid, SrcMac, DstMac) of + error -> + lager:debug("[sdlan_channel] query_info src_mac is: ~p, dst_mac: ~p, nat_peer not found", + [sdlan_util:format_mac(SrcMac), sdlan_util:format_mac(DstMac)]), + + Transport:send(Sock, <>), + {noreply, State}; + {ok, {NatPeer = {{Ip0, Ip1, Ip2, Ip3}, NatPort}, NatType}, V6Info} -> + lager:debug("[sdlan_channel] query_info src_mac is: ~p, dst_mac: ~p, nat_peer: ~p", + [sdlan_util:format_mac(SrcMac), sdlan_util:format_mac(DstMac), NatPeer]), + + PeerInfo = sdlan_pb:encode_msg(#sdl_peer_info{ + dst_mac = DstMac, + v4_info = #sdl_v4_info { + port = NatPort, + v4 = <>, + nat_type = NatType + }, + v6_info = V6Info + }), + Transport:send(Sock, <>), + {noreply, State} + end; + +handle_info({tcp, _Sock, <<0:32, ?PACKET_PING>>}, State = #state{transport = Transport, socket = Sock, client_id = ClientId, ping_counter = PingCounter}) -> + lager:debug("[sdlan_channel] client_id: ~p, get ping", [ClientId]), + Transport:send(Sock, <<0:32, ?PACKET_PONG>>), + {noreply, State#state{ping_counter = PingCounter + 1}}; + +handle_info({timeout, _, ping_ticker}, State = #state{client_id = ClientId, ping_counter = PingCounter}) -> + %% 等待下一次的心跳检测 + erlang:start_timer(?PING_TICKER, self(), ping_ticker), + case PingCounter > 0 of + true -> + {noreply, State#state{ping_counter = 0}}; + false -> + lager:debug("[sdlan_channel] client_id: ~p, ping losted", [ClientId]), + {stop, normal, State#state{ping_counter = 0}} + end; + +%% 重新加入网络 +handle_info({move_network, ReceiverPid, Ref, NetworkPid}, + State = #state{transport = Transport, socket = Sock, client_id = ClientId, mac = Mac, pub_key = PubKey, packet_id = PacketId, inflight = Inflight, is_registered = true}) -> + + %% 建立到network的对应关系 + case sdlan_network:assign_ip_addr(NetworkPid, self(), ClientId, Mac, 0) of + {ok, NetAddr, NetBitLen, AesKey} -> + RsaPubKey = sdlan_cipher:rsa_pem_decode(PubKey), + EncodedAesKey = rsa_encode(AesKey, RsaPubKey), + + {ok, NetworkId} = sdlan_network:get_network_id(NetworkPid), + %% 发送确认信息 + ChangeNetworkCommand = sdlan_pb:encode_msg(#sdl_change_network_command { + dev_addr = #sdl_dev_addr { + network_id = NetworkId, + net_addr = NetAddr, + net_bit_len = NetBitLen + }, + aes_key = EncodedAesKey + }), + Command = <>, + Transport:send(Sock, Command), + + %% 设置节点的在线状态 + sdlan_api:node_online(ClientId, NetworkId, sdlan_ipaddr:int_to_ipv4(NetAddr)), + + lager:debug("[sdlan_channel] client_id: ~p, move_network will send command: ~p", [ClientId, Command]), + {noreply, State#state{packet_id = PacketId + 1, assign_ip = NetAddr, network_pid = NetworkPid, inflight = maps:put(PacketId, {ReceiverPid, Ref}, Inflight)}}; + {error, Reason} -> + lager:debug("[sdlan_channel] client_id: ~p, move_network get error: ~p", [ClientId, Reason]), + Transport:send(Sock, register_nak_reply(0, ?NAK_NO_IP, <<"No Ip address">>)), + ReceiverPid ! {command_reply, Ref, {error, <<"assign_ip error, no ip free">>}}, + {noreply, State} + end; + +%% 发送指令信息 +handle_info({send_event, EventType, Event}, State = #state{transport = Transport, socket = Sock, client_id = ClientId, is_registered = true}) -> + lager:debug("[sdlan_channel] client_id: ~p, will send eventType: ~p, event: ~p", [ClientId, EventType, Event]), + Transport:send(Sock, <<0:32, ?PACKET_EVENT, EventType, Event/binary>>), + {noreply, State}; + +%% 网络流量统计 +handle_info({tcp, _Sock, <<0:32, ?PACKET_FLOW_TRACER, Body/binary>>}, State = #state{client_id = ClientId, network_pid = NetworkPid, is_registered = true}) when is_pid(NetworkPid) -> + #sdl_flows{forward_num = ForwardNum, p2p_num = P2PNum, inbound_num = InboundNum} = sdlan_pb:decode_msg(Body, sdl_flows), + {ok, NetworkId} = sdlan_network:get_network_id(NetworkPid), + ReportResult = sdlan_api:flow_report(ClientId, NetworkId, ForwardNum, P2PNum, InboundNum), + lager:debug("[sdlan_channel] flow_tracer, forward: ~p, p2p: ~p, inbound: ~p, result: ~p", [ClientId, ForwardNum, P2PNum, InboundNum, ReportResult]), + {noreply, State}; + +%% 取消注册 +handle_info({tcp, _Sock, <<0:32, ?PACKET_UNREGISTER>>}, State = #state{client_id = ClientId, network_pid = NetworkPid, is_registered = true}) when is_pid(NetworkPid) -> + lager:warning("[sdlan_channel] unregister client_id: ~p", [ClientId]), + % sdlan_network:unregister(NetworkPid, ClientId), + {stop, normal, State}; + +%% 发送指令信息 +handle_info({publish_command, ReceiverPid, Ref, CommandType, Msg}, State = #state{transport = Transport, socket = Sock, client_id = ClientId, packet_id = PacketId, inflight = Inflight, is_registered = true}) -> + lager:warning("[sdlan_channel] client_id: ~p, will publish: ~p, message: ~p", [ClientId, CommandType, Msg]), + Transport:send(Sock, <>), + {noreply, State#state{packet_id = PacketId + 1, inflight = maps:put(PacketId, {ReceiverPid, Ref}, Inflight)}}; + +%% 主机端的消息响应 +handle_info({tcp, _Sock, <>}, State = #state{client_id = ClientId, inflight = Inflight}) when PacketId > 0 -> + CommandAck = #sdl_command_ack{} = sdlan_pb:decode_msg(Body, sdl_command_ack), + + lager:debug("[sdlan_channel] client_id: ~p, get publish response message: ~p, packet_id: ~p", [ClientId, CommandAck, PacketId]), + case maps:take(PacketId, Inflight) of + error -> + lager:warning("[sdlan_channel] get unknown publish response message: ~p, packet_id: ~p", [CommandAck, PacketId]), + {ok, State}; + {{ReceiverPid, Ref}, NInflight} -> + case is_pid(ReceiverPid) andalso is_process_alive(ReceiverPid) of + true -> + ReceiverPid ! {command_reply, Ref, CommandAck}; + false -> + lager:warning("[sdlan_channel] get publish response message: ~p, packet_id: ~p, but receiver_pid is deaded", [CommandAck, PacketId]) + end, + {noreply, State#state{inflight = NInflight}} + end; + +handle_info({tcp_error, Sock, Reason}, State = #state{socket = Sock, client_id = ClientId}) -> + lager:notice("[sdlan_channel] client_id: ~p, tcp_error: ~p", [ClientId, Reason]), + {stop, normal, State}; + +handle_info({tcp_closed, Sock}, State = #state{socket = Sock, client_id = ClientId}) -> + lager:notice("[sdlan_channel] client_id: ~p, tcp_closed", [ClientId]), + {stop, normal, State}; + +%% 关闭当前通道 +handle_info({stop, Reason}, State) -> + {stop, Reason, State}; + +handle_info(Info, State) -> + lager:warning("[sdlan_channel] get a unknown message: ~p, channel will closed", [Info]), + {noreply, State}. + +terminate(Reason, #state{client_id = ClientId, network_pid = NetworkPid}) -> + case ClientId /= undefined andalso is_pid(NetworkPid) of + true -> + {ok, NetworkId} = sdlan_network:get_network_id(NetworkPid), + Result = sdlan_api:node_offline(ClientId, NetworkId), + lager:debug("[sdlan_channel] client_id: ~p, set none offline, result is: ~p", [ClientId, Result]); + false -> + ok + end, + lager:warning("[sdlan_channel] client_id: ~p, stop with reason: ~p", [ClientId, Reason]), + ok. + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% helper methods +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +-spec register_nak_reply(PacketId :: integer(), ErrorCode :: integer(), ErrorMsg :: binary()) -> binary(). +register_nak_reply(PacketId, ErrorCode, ErrorMsg) when is_integer(PacketId), is_integer(ErrorCode), is_binary(ErrorMsg) -> + RegisterNakReply = sdlan_pb:encode_msg(#sdl_register_super_nak { + error_code = ErrorCode, + error_message = ErrorMsg + }), + <>. + +rsa_encode(PlainText, RsaPubKey) when is_binary(PlainText) -> + iolist_to_binary(sdlan_cipher:rsa_encrypt(PlainText, RsaPubKey)). \ No newline at end of file diff --git a/apps/sdlan/src/sdlan_cipher.erl b/apps/sdlan/src/sdlan_cipher.erl new file mode 100644 index 0000000..8c22c41 --- /dev/null +++ b/apps/sdlan/src/sdlan_cipher.erl @@ -0,0 +1,43 @@ +%%%------------------------------------------------------------------- +%%% @author anlicheng +%%% @copyright (C) 2024, +%%% @doc +%%% +%%% @end +%%% Created : 11. 3月 2024 11:07 +%%%------------------------------------------------------------------- +-module(sdlan_cipher). +-author("anlicheng"). + +%% API +-export([rsa_encrypt/2, rsa_pem_decode/1]). +-export([aes_encrypt/3, aes_decrypt/3]). +-export([test/0]). + +test() -> + Key = <<"abcdabcdabcdabcd">>, + X = aes_encrypt(Key, Key, <<"hello world">>), + lager:debug("x is: ~p, raw: ~p", [X, aes_decrypt(Key, Key, X)]), + + + ok. + +-spec rsa_pem_decode(PubKey :: binary()) -> public_key:rsa_public_key(). +rsa_pem_decode(PubKey) when is_binary(PubKey) -> + [PubPem] = public_key:pem_decode(PubKey), + public_key:pem_entry_decode(PubPem). + +%% 加密数据 +-spec rsa_encrypt(binary(), public_key:rsa_public_key()) -> binary(). +rsa_encrypt(BinData, PublicKey) when is_binary(BinData) -> + public_key:encrypt_public(BinData, PublicKey, [{rsa_padding, rsa_pkcs1_padding}]). + +%% 基于aes的加密算法 +-spec aes_encrypt(binary(), binary(), binary()) -> binary(). +aes_encrypt(Key, IVec, PlainText) when is_binary(Key), is_binary(IVec), is_binary(PlainText) -> + crypto:crypto_one_time(aes_128_ofb, Key, IVec, PlainText, [{encrypt, true}, {padding, pkcs_padding}]). + +%% 基于aes的解密算法 +-spec aes_decrypt(binary(), binary(), binary()) -> binary(). +aes_decrypt(Key, IVec, CipherText) when is_binary(Key), is_binary(IVec), is_binary(CipherText) -> + crypto:crypto_one_time(aes_128_ofb, Key, IVec, CipherText, [{encrypt, false}, {padding, pkcs_padding}]). \ No newline at end of file diff --git a/apps/sdlan/src/sdlan_ipaddr.erl b/apps/sdlan/src/sdlan_ipaddr.erl new file mode 100644 index 0000000..019f54d --- /dev/null +++ b/apps/sdlan/src/sdlan_ipaddr.erl @@ -0,0 +1,55 @@ +%%%------------------------------------------------------------------- +%%% @author anlicheng +%%% @copyright (C) 2024, +%%% @doc +%%% +%%% @end +%%% Created : 27. 3月 2024 17:43 +%%%------------------------------------------------------------------- +-module(sdlan_ipaddr). +-author("anlicheng"). + +%% API +-export([ipv4_to_int/1, int_to_ipv4/1, ips/2, format_ip/1]). +-export([ipv6_bytes_to_binary/1]). + +format_ip(Ip) when is_integer(Ip) -> + int_to_ipv4(Ip); +format_ip(Ip) -> + Ip. + +-spec ipv4_to_int(Ip :: integer() | binary() | inet:ip4_address()) -> integer(). +ipv4_to_int(Ip) when is_integer(Ip) -> + Ip; +ipv4_to_int({Ip0, Ip1, Ip2, Ip3}) -> + <> = <>, + Ip; +ipv4_to_int(Ip) when is_binary(Ip) -> + Parts0 = binary:split(Ip, <<".">>, [global]), + Parts = lists:map(fun binary_to_integer/1, Parts0), + <> = iolist_to_binary(Parts), + IpInt. + +-spec int_to_ipv4(Ip :: integer()) -> binary(). +int_to_ipv4(Ip) when is_integer(Ip) -> + <> = <>, + <<(integer_to_binary(Ip0))/binary, $., (integer_to_binary(Ip1))/binary, $., (integer_to_binary(Ip2))/binary, $., (integer_to_binary(Ip3))/binary>>. + +-spec ips(NetAddr :: binary(), MaskLen :: integer()) -> [Ip :: integer()]. +ips(NetAddr, MaskLen) when is_binary(NetAddr), is_integer(MaskLen) -> + Mask = 16#FFFFFFFF bsr MaskLen, + Net0 = ipv4_to_int(NetAddr), + %% 防止网络地址给得不对,比如: "192.168.1.101", + L = 32 - MaskLen, + Net = (Net0 bsr L) bsl L, + lists:map(fun(V) -> Net + V end, lists:seq(1, Mask - 1)). + +-spec ipv6_bytes_to_binary(Bytes :: binary()) -> Bin :: binary(). +ipv6_bytes_to_binary(<>) -> + Segments = [integer_to_list(X, 16) || X <- [A, B, C, D, E, F, G, H]], + % 填充每个段以确保是4位 + Padded = [string:pad(S, 4, leading, $0) || S <- Segments], + % 合并成IPv6地址格式,这里没有处理最简化形式的缩写 + iolist_to_binary(lists:flatten(string:join(Padded, ":"))); +ipv6_bytes_to_binary(_) -> + <<"">>. diff --git a/apps/sdlan/src/sdlan_network.erl b/apps/sdlan/src/sdlan_network.erl new file mode 100644 index 0000000..9fbdde4 --- /dev/null +++ b/apps/sdlan/src/sdlan_network.erl @@ -0,0 +1,586 @@ +%%%------------------------------------------------------------------- +%%% @author anlicheng +%%% @copyright (C) 2024, +%%% @doc +%%% +%%% @end +%%% Created : 27. 3月 2024 15:13 +%%%------------------------------------------------------------------- +-module(sdlan_network). +-author("anlicheng"). +-include("sdlan.hrl"). +-include("sdlan_pb.hrl"). +-include("sdlan_tables.hrl"). + +-behaviour(gen_server). + +-define(FLOW_REPORT_INTERVAL, 60 * 1000). + +%% broadcast, "FF-FF-FF-FF-FF-FF" +-define(BROADCAST_MAC, <<16#FF,16#FF,16#FF,16#FF,16#FF,16#FF>>). + +%% API +-export([start_link/2]). +-export([get_name/1, get_pid/1, assign_ip_addr/5, peer_info/3, unregister/3, debug_info/1, get_network_id/1, get_used_map/1]). +-export([forward/5, update_hole/6, disable_client/2, get_channel/2, dropout_client/2, reload/1]). +-export([test_event/1]). + +%% gen_server callbacks +-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). + +-record(hole, { + peer :: {Ip :: inet:ip4_address(), Port :: integer()}, + nat_type :: integer() +}). + +%% ip的使用信息 +-record(host, { + client_id :: binary(), + mac :: binary(), + ip :: integer(), + channel_pid :: undefined | pid(), + monitor_ref :: undefined | reference(), + hole :: undefined | #hole{}, + %% 记录ip和ip_v6的映射关系, #{ip_addr :: integer() => {}} + v6_info :: undefined | #sdl_v6_info{} +}). + +-record(state, { + network_id :: integer(), + name :: binary(), + ipaddr :: binary(), + mask_len :: integer(), + owner_id :: integer(), + + %% 设置网络带宽 + throttle_key :: atom(), + + %% 转发流量统计 + forward_bytes = 0, + + %% 同一个网络下公用的密钥, 采用AES-256加密算法;随机生成 + aes_key :: binary(), + + %% ip分配器 + %% 记录当前网络下的全部ip地址 + ips = [] :: [Ip :: integer()], + + %% 记录已经使用了的ip, #{mac :: integer() => Host :: #host{}} + used_map = #{} +}). + +%%%=================================================================== +%%% API +%%%=================================================================== + +%% -- MARK: 测试函数 +test_event(Pid) -> + gen_server:cast(Pid, test_event). + +-spec get_pid(Id :: integer()) -> undefined | pid(). +get_pid(Id) when is_integer(Id) -> + whereis(get_name(Id)). + +-spec get_name(Id :: integer()) -> atom(). +get_name(Id) when is_integer(Id) -> + list_to_atom("sdlan_network:" ++ integer_to_list(Id)). + +-spec reload(Pid :: pid()) -> ok | {error, Reason :: any()}. +reload(Pid) when is_pid(Pid) -> + gen_server:call(Pid, reload). + +-spec assign_ip_addr(Pid :: pid(), ChannelPid :: pid(), ClientId :: binary(), Mac :: binary(), NetAddr :: integer()) -> + {ok, NetAddr :: integer(), MaskLen :: integer(), AesKey :: binary()} | {error, Reason :: any()}. +assign_ip_addr(Pid, ChannelPid, ClientId, Mac, NetAddr) when is_pid(Pid), is_pid(ChannelPid), is_binary(ClientId), is_binary(Mac), is_integer(NetAddr) -> + gen_server:call(Pid, {assign_ip_addr, ChannelPid, ClientId, Mac, NetAddr}). + +-spec get_network_id(Pid :: pid()) -> {ok, NetworkId :: integer()}. +get_network_id(Pid) when is_pid(Pid) -> + gen_server:call(Pid, get_network_id). + +-spec unregister(Pid :: pid(), ClientId :: binary(), Mac :: binary()) -> no_return(). +unregister(Pid, ClientId, Mac) when is_pid(Pid), is_binary(ClientId), is_binary(Mac) -> + gen_server:cast(Pid, {unregister, ClientId, Mac}). + +-spec peer_info(Pid :: pid(), SrcMac :: binary(), DstMac :: binary()) -> + error | {ok, {NatPeer :: {Ip :: inet:ip4_address(), Port :: integer()}, NatType :: integer()}, V6Info :: undefined | #sdl_v6_info{}}. +peer_info(Pid, SrcMac, DstMac) when is_pid(Pid), is_binary(SrcMac), is_binary(DstMac) -> + gen_server:call(Pid, {peer_info, SrcMac, DstMac}). + +-spec forward(pid(), Sock :: any(), SrcMac :: binary(), DstMac :: binary(), Packet :: binary()) -> no_return(). +forward(Pid, Sock, SrcMac, DstMac, Packet) when is_pid(Pid), is_binary(SrcMac), is_binary(DstMac), is_binary(Packet) -> + gen_server:cast(Pid, {forward, Sock, SrcMac, DstMac, Packet}). + +%% 更新ip地址对应的nat关系 +-spec update_hole(Pid :: pid(), ClientId :: binary(), Mac :: binary(), Peer :: tuple(), NatType :: integer(), V6Info :: undefined | #sdl_v6_info{}) -> no_return(). +update_hole(Pid, ClientId, Mac, Peer, NatType, V6Info) when is_pid(Pid), is_binary(ClientId), is_binary(Mac), is_integer(NatType) -> + gen_server:cast(Pid, {update_hole, ClientId, Mac, Peer, NatType, V6Info}). + +-spec disable_client(Pid :: pid(), ClientId :: binary()) -> ok | error. +disable_client(Pid, ClientId) when is_pid(Pid), is_binary(ClientId) -> + gen_server:call(Pid, {disable_client, ClientId}). + +-spec get_channel(Pid :: pid(), ClientId :: binary()) -> error | {ok, ChannelPid :: pid()}. +get_channel(Pid, ClientId) when is_pid(Pid), is_binary(ClientId) -> + gen_server:call(Pid, {get_channel, ClientId}). + +%% 剔除client_id,channel不关闭; channel会被重新绑定到其他的network里面 +-spec dropout_client(Pid :: pid(), ClientId :: binary()) -> {ok, ChannelPid :: pid()} | error. +dropout_client(Pid, ClientId) when is_pid(Pid), is_binary(ClientId) -> + gen_server:call(Pid, {dropout_client, ClientId}). + +-spec debug_info(Pid :: pid()) -> map(). +debug_info(Pid) when is_pid(Pid) -> + gen_server:call(Pid, debug_info). + +-spec get_used_map(Pid :: pid()) -> map(). +get_used_map(Pid) when is_pid(Pid) -> + gen_server:call(Pid, get_used_map); +get_used_map(undefined) -> + #{}. + +%% @doc Spawns the server and registers the local name (unique) +-spec(start_link(Name :: atom(), Id :: integer()) -> + {ok, Pid :: pid()} | ignore | {error, Reason :: term()}). +start_link(Name, Id) when is_atom(Name), is_integer(Id) -> + gen_server:start_link({local, Name}, ?MODULE, [Id], []). + +%%%=================================================================== +%%% gen_server callbacks +%%%=================================================================== + +%% @private +%% @doc Initializes the server +-spec(init(Args :: term()) -> + {ok, State :: #state{}} | {ok, State :: #state{}, timeout() | hibernate} | + {stop, Reason :: term()} | ignore). +init([Id]) when is_integer(Id) -> + erlang:process_flag(trap_exit, true), + case sdlan_api:get_network(Id) of + {ok, #{<<"ipaddr">> := Null}} when Null == <<"null">>; Null == <<"NULL">> -> + ignore; + {ok, #{<<"id">> := Id, <<"name">> := Name, <<"ipaddr">> := IpAddr0, <<"owner_id">> := OwnerId}} -> + {IpAddr, MaskLen} = parse_ipaddr(IpAddr0), + Ips = sdlan_ipaddr:ips(IpAddr, MaskLen), + AesKey = sdlan_util:rand_byte(32), + %% 限流key + ThrottleKey = list_to_atom("network_throttle:" ++ integer_to_list(Id)), + %% 绑定到资源协调器 + sdlan_network_coordinator:attach(self(), ThrottleKey), + + %% 每分钟汇报一次转发的流量 + erlang:start_timer(?FLOW_REPORT_INTERVAL, self(), flow_report_ticker), + + %% 创建数据库表 + create_mnesia_table(Id), + + lager:debug("[sdlan_network] network: ~p, ips: ~p", [Id, lists:map(fun sdlan_ipaddr:int_to_ipv4/1, Ips)]), + + {ok, #state{network_id = Id, name = Name, ipaddr = IpAddr, owner_id = OwnerId, mask_len = MaskLen, ips = Ips, aes_key = AesKey, throttle_key = ThrottleKey}}; + {error, Reason} -> + lager:warning("[sdlan_network] load network: ~p, get error: ~p", [Id, Reason]), + ignore + end. + +%% @private +%% @doc Handling call messages +-spec(handle_call(Request :: term(), From :: {pid(), Tag :: term()}, + State :: #state{}) -> + {reply, Reply :: term(), NewState :: #state{}} | + {reply, Reply :: term(), NewState :: #state{}, timeout() | hibernate} | + {noreply, NewState :: #state{}} | + {noreply, NewState :: #state{}, timeout() | hibernate} | + {stop, Reason :: term(), Reply :: term(), NewState :: #state{}} | + {stop, Reason :: term(), NewState :: #state{}}). +%% 重新加载网络信息 +handle_call(reload, _From, State = #state{network_id = Id, ipaddr = OldIpAddr, mask_len = OldMarkLen, used_map = UsedMap}) -> + case sdlan_api:get_network(Id) of + {ok, #{<<"name">> := Name, <<"ipaddr">> := IpAddr0, <<"owner_id">> := OwnerId}} -> + {IpAddr, MaskLen} = parse_ipaddr(IpAddr0), + case OldIpAddr =:= IpAddr andalso OldMarkLen =:= MaskLen of + true -> + {reply, ok, State#state{name = Name, owner_id = OwnerId}}; + false -> + lager:debug("[sdlan_networkd] network_id: ~p, reload will close all channels", [Id]), + Ips = sdlan_ipaddr:ips(IpAddr, MaskLen), + %% 整个网络下的设备都需要重新连接 + maps:foreach(fun(_, #host{channel_pid = ChannelPid, monitor_ref = MRef}) -> + is_reference(MRef) andalso demonitor(MRef), + is_process_alive(ChannelPid) andalso sdlan_channel:stop(ChannelPid, normal) + end, UsedMap), + %% 清理掉数据库中的数据 + ok = client_model:delete_clients(Id), + + {reply, ok, State#state{name = Name, ipaddr = IpAddr, + owner_id = OwnerId, mask_len = MaskLen, ips = Ips, used_map = maps:new()}} + end; + {error, Reason} -> + lager:warning("[sdlan_network] reload network: ~p, get error: ~p", [Id, Reason]), + {reply, {error, Reason}, State} + end; + +%% 给客户端分配ip地址 +handle_call({assign_ip_addr, ChannelPid, ClientId, Mac, NetAddr0}, _From, + State = #state{network_id = NetworkId, ips = Ips, used_map = UsedMap, mask_len = MaskLen, aes_key = AesKey}) -> + + %% 分配ip地址的时候,以mac地址为唯一基准 + case client_model:alloc_ip(NetworkId, Ips, ClientId, Mac, NetAddr0) of + {ok, Ip} -> + %% 关闭之前的channel + maybe_close_channel(maps:get(Mac, UsedMap, undefined)), + + %% 建立到新的channel之间的关系 + MRef = monitor(process, ChannelPid), + NUsedMap = maps:put(Mac, #host{client_id = ClientId, mac = Mac, ip = Ip, channel_pid = ChannelPid, monitor_ref = MRef}, UsedMap), + + {reply, {ok, Ip, MaskLen, AesKey}, State#state{used_map = NUsedMap}}; + {error, Reason} -> + {reply, {error, Reason}, State} + end; + +handle_call(get_used_map, _From, State = #state{used_map = UsedMap}) -> + UsedInfos = maps:map(fun(_, #host{hole = Hole, v6_info = V6Info}) -> + HoleMap = case Hole of + #hole{peer = {NatIp, NatPort}} -> + #{ + <<"nat_ip">> => sdlan_ipaddr:int_to_ipv4(sdlan_ipaddr:ipv4_to_int(NatIp)), + <<"nat_port">> => NatPort + }; + _ -> + #{} + end, + + V6Map = case V6Info of + #sdl_v6_info{v6 = IpV6, port = Port} -> + #{ + <<"v6_ip">> => sdlan_ipaddr:ipv6_bytes_to_binary(IpV6), + <<"v6_port">> => Port + }; + _ -> + #{} + end, + #{<<"hole">> => HoleMap, <<"v6_info">> => V6Map} + end, UsedMap), + + {reply, {ok, UsedInfos}, State}; + +%% client设置为禁止状态,不允许重连 +handle_call({disable_client, ClientId}, _From, State = #state{network_id = NetworkId, used_map = UsedMap}) -> + case lists:search(fun({_, #host{client_id = ClientId0}}) -> ClientId =:= ClientId0 end, maps:to_list(UsedMap)) of + {value, {Mac, #host{channel_pid = ChannelPid, monitor_ref = MRef}}} -> + is_reference(MRef) andalso demonitor(MRef), + sdlan_channel:stop(ChannelPid, disable), + NUsedMap = maps:remove(Mac, UsedMap), + %% 将客户端设置为禁止状态 + client_model:disable_client(NetworkId, ClientId), + + {reply, ok, State#state{used_map = NUsedMap}}; + false -> + {reply, error, State} + end; + +handle_call({get_channel, ClientId}, _From, State = #state{used_map = UsedMap}) -> + case lists:search(fun({_, #host{client_id = ClientId0}}) -> ClientId =:= ClientId0 end, maps:to_list(UsedMap)) of + {value, {_Ip, #host{channel_pid = ChannelPid}}} -> + {reply, {ok, ChannelPid}, State}; + false -> + {reply, error, State} + end; + +%% 区别在于是否关闭掉channel, 这里是在网络迁移中的功能; drop的时候需要从当前网络中移除 +handle_call({dropout_client, ClientId}, _From, State = #state{network_id = NetworkId, used_map = UsedMap}) -> + case lists:search(fun({_, #host{client_id = ClientId0}}) -> ClientId =:= ClientId0 end, maps:to_list(UsedMap)) of + {value, {Mac, #host{channel_pid = ChannelPid, monitor_ref = MRef}}} -> + is_reference(MRef) andalso demonitor(MRef), + NUsedMap = maps:remove(Mac, UsedMap), + %% 从数据库删除 + client_model:delete_client(NetworkId, ClientId), + + {reply, {ok, ChannelPid}, State#state{used_map = NUsedMap}}; + false -> + {reply, error, State} + end; + +handle_call(get_network_id, _From, State = #state{network_id = NetworkId}) -> + {reply, {ok, NetworkId}, State}; + +%% 网络存在的nat_peer信息 +handle_call({peer_info, SrcMac, DstMac}, _From, State = #state{used_map = UsedMap}) -> + case maps:find(DstMac, UsedMap) of + {ok, #host{channel_pid = DstChannelPid, hole = #hole{peer = DstNatPeer, nat_type = DstNatType}, v6_info = DstV6Info}} -> + %% 让目标服务器发送sendRegister事件(2024-06-25 新增,提高打洞的成功率) + case maps:get(SrcMac, UsedMap, undefined) of + #host{hole = #hole{peer = {SrcNatIp, SrcNatPort}, nat_type = NatType}, v6_info = SrcV6Info} -> + Event = sdlan_pb:encode_msg(#sdl_send_register_event { + dst_mac = SrcMac, + nat_ip = sdlan_ipaddr:ipv4_to_int(SrcNatIp), + nat_type = NatType, + nat_port = SrcNatPort, + v6_info = SrcV6Info + }), + sdlan_channel:send_event(DstChannelPid, ?PACKET_EVENT_SEND_REGISTER, Event); + _ -> + ok + end, + {reply, {ok, {DstNatPeer, DstNatType}, DstV6Info}, State}; + _ -> + {reply, error, State} + end; + +handle_call(debug_info, _From, State = #state{network_id = NetworkId, ipaddr = IpAddr, mask_len = MaskLen, owner_id = OwnerId, ips = Ips, used_map = UsedMap}) -> + Reply = #{ + <<"network_id">> => NetworkId, + <<"ipaddr">> => IpAddr, + <<"mask_len">> => MaskLen, + <<"owner_id">> => OwnerId, + <<"ips">> => lists:map(fun sdlan_ipaddr:int_to_ipv4/1, Ips), + <<"used_ips">> => lists:map(fun({_, Host}) -> format_host(Host) end, maps:to_list(UsedMap)) + }, + {reply, Reply, State}. + +%% @private +%% @doc Handling cast messages +-spec(handle_cast(Request :: term(), State :: #state{}) -> + {noreply, NewState :: #state{}} | + {noreply, NewState :: #state{}, timeout() | hibernate} | + {stop, Reason :: term(), NewState :: #state{}}). +%% 网络数据转发, mac地址单播 +handle_cast({forward, Sock, SrcMac, DstMac, Packet}, State = #state{network_id = NetworkId, used_map = UsedMap, throttle_key = ThrottleKey, forward_bytes = ForwardBytes}) + when is_map_key(SrcMac, UsedMap), is_map_key(DstMac, UsedMap) -> + + PacketBytes = byte_size(Packet), + case maps:find(DstMac, UsedMap) of + {ok, #host{hole = #hole{peer = Peer = {Ip, Port}}}} -> + case throttle:check(sdlan_network, ThrottleKey) of + {ok, _RestCount, _LeftToReset} -> + %% client和stun之间必须有心跳机制保持nat映射可用,并且通过服务转发的udp包肯定可以到达对端的nat + lager:debug("[sdlan_network] forward data networkd_id: ~p, src_mac: ~p, dst_mac: ~p, hole: ~p", + [NetworkId, sdlan_util:format_mac(SrcMac), sdlan_util:format_mac(DstMac), Peer]), + + gen_udp:send(Sock, Ip, Port, Packet), + {noreply, State#state{forward_bytes = ForwardBytes + PacketBytes}}; + {limit_exceeded, 0, _LeftToReset} -> + %% 尝试获取其他网络是否有让渡的资源 + case sdlan_network_coordinator:checkout() of + ok -> + lager:debug("[sdlan_network] use release forward data networkd_id: ~p, src_mac: ~p, dst_mac: ~p, hole: ~p", + [NetworkId, sdlan_util:format_mac(SrcMac), sdlan_util:format_mac(DstMac), Peer]), + + gen_udp:send(Sock, Ip, Port, Packet), + {noreply, State#state{forward_bytes = ForwardBytes + PacketBytes}}; + error -> + lager:notice("[sdlan_network] networkd_id: ~p, src_mac: ~p, dst_mac: ~p, rate limited, discard", + [NetworkId, sdlan_util:format_mac(SrcMac), sdlan_util:format_mac(DstMac)]), + {noreply, State} + end + end; + {ok, _} -> + lager:debug("[sdlan_network] networkd_id: ~p, src_mac: ~p, dst_mac: ~p, hole not found", + [NetworkId, sdlan_util:format_mac(SrcMac), sdlan_util:format_mac(DstMac)]), + {noreply, State}; + error -> + lager:debug("[sdlan_network] networkd_id: ~p, src_mac: ~p, dst_mac: ~p not found", + [NetworkId, sdlan_util:format_mac(SrcMac), sdlan_util:format_mac(DstMac)]), + {noreply, State} + end; + +%% 网络数据转发, ip广播或组播, 不限流 +handle_cast({forward, Sock, SrcMac, DstMac, Packet}, State = #state{network_id = NetworkId, used_map = UsedMap, forward_bytes = ForwardBytes}) + when is_map_key(SrcMac, UsedMap) -> + %% 广播地址和组播地址,需要转发到整个网络 + case sdlan_util:is_broadcast_mac(DstMac) orelse sdlan_util:is_multicast_mac(DstMac) of + true -> + PacketBytes = byte_size(Packet), + %% 消息广播 + maps:foreach(fun(Mac, #host{hole = Hole}) -> + case {Mac =/= SrcMac, Hole} of + {true, #hole{peer = {NatIp, NatPort}}} -> + lager:debug("[sdlan_network] call me here"), + gen_udp:send(Sock, NatIp, NatPort, Packet); + _ -> + ok + end + end, UsedMap), + + %% client和stun之间必须有心跳机制保持nat映射可用,并且通过服务转发的udp包肯定可以到达对端的nat + lager:debug("[sdlan_network] broadcast data networkd_id: ~p, src_mac: ~p, dst_mac: ~p", + [NetworkId, sdlan_util:format_mac(SrcMac), sdlan_util:format_mac(DstMac)]), + + {noreply, State#state{forward_bytes = ForwardBytes + PacketBytes}}; + false -> + lager:debug("[sdlan_network] networkd_id: ~p, src_mac: ~p, dst_mac: ~p, forward discard 1", + [NetworkId, sdlan_util:format_mac(SrcMac), sdlan_util:format_mac(DstMac)]), + {noreply, State} + end; + +handle_cast({forward, _Sock, SrcMac, DstMac, _Packet}, State = #state{network_id = NetworkId}) -> + lager:debug("[sdlan_network] networkd_id: ~p, src_mac: ~p, dst_mac: ~p, forward discard 2", + [NetworkId, sdlan_util:format_mac(SrcMac), sdlan_util:format_mac(DstMac)]), + {noreply, State}; + +%% 删除ip的占用并关闭channel +handle_cast({unregister, _ClientId, Mac}, State = #state{network_id = NetworkId, used_map = UsedMap}) -> + lager:debug("[sdlan_network] networkd_id: ~p, unregister Mac: ~p", [NetworkId, Mac]), + case maps:take(Mac, UsedMap) of + error -> + {noreply, State}; + {#host{channel_pid = ChannelPid, monitor_ref = MRef}, NUsedMap} -> + is_reference(MRef) andalso demonitor(MRef), + sdlan_channel:stop(ChannelPid, normal), + {noreply, State#state{used_map = NUsedMap}} + end; + +%% 需要判断,client是属于当前网络的 +handle_cast({update_hole, _ClientId, Mac, Peer, NatType, V6Info}, State = #state{used_map = UsedMap}) -> + case maps:find(Mac, UsedMap) of + {ok, Host0 = #host{hole = OldHole, ip = Ip}} -> + case OldHole =:= undefined orelse (OldHole#hole.peer =/= Peer orelse OldHole#hole.nat_type =/= NatType) of + true -> + NatChangedEvent = sdlan_pb:encode_msg(#sdl_nat_changed_event { + mac = Mac, + ip = Ip + }), + broadcast(?PACKET_EVENT_NAT_CHANGED, NatChangedEvent, Mac, UsedMap); + false -> + ok + end, + Host = Host0#host{hole = #hole{peer = Peer, nat_type = NatType}, v6_info = V6Info}, + + {noreply, State#state{used_map = maps:put(Mac, Host, UsedMap)}}; + error -> + {noreply, State} + end. + +%% @private +%% @doc Handling all non call/cast messages +-spec(handle_info(Info :: timeout() | term(), State :: #state{}) -> + {noreply, NewState :: #state{}} | + {noreply, NewState :: #state{}, timeout() | hibernate} | + {stop, Reason :: term(), NewState :: #state{}}). +handle_info({timeout, _, flow_report_ticker}, State = #state{network_id = NetworkId, forward_bytes = ForwardBytes}) -> + erlang:start_timer(?FLOW_REPORT_INTERVAL, self(), flow_report_ticker), + catch sdlan_api:network_forward_report(NetworkId, ForwardBytes), + {noreply, State#state{forward_bytes = 0}}; + +handle_info({'EXIT', _Pid, shutdown}, State = #state{network_id = NetworkId, used_map = UsedMap}) -> + lager:warning("[sdlan_network] network: ~p, get shutdown message", [NetworkId]), + broadcast_shutdown(UsedMap), + {stop, shutdown, State}; +%% Channel进程退出, hole里面的数据也需要清理 +handle_info({'DOWN', _MRef, process, ChannelPid, Reason}, State = #state{network_id = NetworkId, used_map = UsedMap}) -> + lager:notice("[sdlan_network] network_id: ~p, channel_pid: ~p, close with reason: ~p", [NetworkId, ChannelPid, Reason]), + NUsedMap = maps:filter(fun(_, #host{channel_pid = ChannelPid0}) -> ChannelPid =/= ChannelPid0 end, UsedMap), + {noreply, State#state{used_map = NUsedMap}}. + +%% @private +%% @doc This function is called by a gen_server when it is about to +%% terminate. It should be the opposite of Module:init/1 and do any +%% necessary cleaning up. When it returns, the gen_server terminates +%% with Reason. The return value is ignored. +-spec(terminate(Reason :: (normal | shutdown | {shutdown, term()} | term()), + State :: #state{}) -> term()). +terminate(Reason, #state{network_id = NetworkId, used_map = UsedMap}) -> + lager:debug("[sdlan_network] network: ~p, will terminate with reason: ~p", [NetworkId, Reason]), + broadcast_shutdown(UsedMap), + ok. + +%% @private +%% @doc Convert process state when code is changed +-spec(code_change(OldVsn :: term() | {down, term()}, State :: #state{}, + Extra :: term()) -> + {ok, NewState :: #state{}} | {error, Reason :: term()}). +code_change(_OldVsn, State = #state{}, _Extra) -> + {ok, State}. + +%%%=================================================================== +%%% Internal functions +%%%=================================================================== + +%% 创建数据库表 +-spec create_mnesia_table(NetworkId :: integer()) -> no_return(). +create_mnesia_table(NetworkId) when is_integer(NetworkId) -> + Tab = client_model:get_table_name(NetworkId), + Tables = mnesia:system_info(tables), + case lists:member(Tab, Tables) of + true -> + ok; + false -> + Res = client_model:create_table(Tab), + lager:debug("[sdlan_network] create table result: ~p", [Res]) + end. + +-spec maybe_close_channel(undefined | #host{}) -> no_return(). +maybe_close_channel(#host{channel_pid = ChannelPid0, monitor_ref = MRef0}) -> + case is_pid(ChannelPid0) andalso is_process_alive(ChannelPid0) of + true -> + is_reference(MRef0) andalso demonitor(MRef0), + sdlan_channel:stop(ChannelPid0, channel_rebind); + false -> + ok + end; +maybe_close_channel(_) -> + ok. + +-spec broadcast(EventType :: integer(), Event :: binary(), ExcludeMac :: binary(), UsedMap :: map()) -> no_return(). +broadcast(EventType, Event, ExcludeMac, UsedMap) when is_map(UsedMap), is_binary(ExcludeMac), is_integer(EventType), is_binary(Event) -> + maps:foreach(fun(Mac, #host{channel_pid = ChannelPid}) -> + case is_process_alive(ChannelPid) andalso ExcludeMac /= Mac of + true -> + sdlan_channel:send_event(ChannelPid, EventType, Event); + false -> + ok + end + end, UsedMap). + +broadcast_shutdown(UsedMap) when is_map(UsedMap) -> + maps:foreach(fun(_, #host{channel_pid = ChannelPid}) -> + case is_process_alive(ChannelPid) of + true -> + NetworkShutdownEvent = sdlan_pb:encode_msg(#sdl_network_shutdown_event { + message = <<"Network shutdown">> + }), + sdlan_channel:send_event(ChannelPid, ?PACKET_EVENT_NETWORK_SHUTDOWN, NetworkShutdownEvent), + sdlan_channel:stop(ChannelPid, normal); + false -> + ok + end + end, UsedMap). + +%% 解析IpAddr: <<"192.168.172/24">> +-spec parse_ipaddr(IpAddr0 :: binary()) -> {IpAddr :: binary(), MaskLen :: integer()}. +parse_ipaddr(IpAddr0) when is_binary(IpAddr0) -> + case binary:split(IpAddr0, <<"/">>) of + [IpAddr, MaskLen] -> + MaskLen1 = binary_to_integer(MaskLen), + {IpAddr, MaskLen1}; + _ -> + {IpAddr0, 24} + end. + +-spec format_host(Host :: #host{}) -> map(). +format_host(#host{client_id = ClientId, mac = Mac, ip = Ip, hole = Hole, v6_info = V6Info}) -> + HoleMap = case Hole of + undefined -> + #{}; + #hole{peer = {NatIp, NatPort}, nat_type = NatType} -> + #{ + nat_ip => NatIp, + nat_port => NatPort, + nat_type => NatType + } + end, + + V6InfoMap = case V6Info of + undefined -> + #{}; + #sdl_v6_info{v6 = V6, port = V6Port} -> + #{v6 => V6, port => V6Port} + end, + + #{ + client_id => ClientId, + mac => sdlan_util:format_mac(Mac), + ip => sdlan_ipaddr:int_to_ipv4(Ip), + hole_map => HoleMap, + v6_info => V6InfoMap + }. diff --git a/apps/sdlan/src/sdlan_network_coordinator.erl b/apps/sdlan/src/sdlan_network_coordinator.erl new file mode 100644 index 0000000..1223195 --- /dev/null +++ b/apps/sdlan/src/sdlan_network_coordinator.erl @@ -0,0 +1,133 @@ +%%%------------------------------------------------------------------- +%%% @author anlicheng +%%% @copyright (C) 2024, +%%% @doc +%%% 资源协调器,用来充分利用网络资源 +%%% @end +%%% Created : 04. 6月 2024 10:55 +%%%------------------------------------------------------------------- +-module(sdlan_network_coordinator). +-author("anlicheng"). + +-behaviour(gen_server). + +%% API +-export([start_link/0]). +-export([checkout/0, attach/2]). + +%% gen_server callbacks +-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). + +-define(SERVER, ?MODULE). + +-record(state, { + release_count = 0, + network_map = #{} %% {NetworkPid => ThrottleKey :: atom()} +}). + +%%%=================================================================== +%%% API +%%%=================================================================== + +-spec attach(NetworkPid :: pid(), ThrottleKey :: atom()) -> no_return(). +attach(NetworkPid, ThrottleKey) when is_pid(NetworkPid), is_atom(ThrottleKey) -> + gen_server:cast(?SERVER, {attach, NetworkPid, ThrottleKey}). + +-spec checkout() -> ok | error. +checkout() -> + gen_server:call(?SERVER, checkout). + +%% @doc Spawns the server and registers the local name (unique) +-spec(start_link() -> + {ok, Pid :: pid()} | ignore | {error, Reason :: term()}). +start_link() -> + gen_server:start_link({local, ?SERVER}, ?MODULE, [], []). + +%%%=================================================================== +%%% gen_server callbacks +%%%=================================================================== + +%% @private +%% @doc Initializes the server +-spec(init(Args :: term()) -> + {ok, State :: #state{}} | {ok, State :: #state{}, timeout() | hibernate} | + {stop, Reason :: term()} | ignore). +init([]) -> + %% 让渡资源定时器 + erlang:start_timer(100, self(), release_ticker), + {ok, #state{release_count = 0}}. + +%% @private +%% @doc Handling call messages +-spec(handle_call(Request :: term(), From :: {pid(), Tag :: term()}, + State :: #state{}) -> + {reply, Reply :: term(), NewState :: #state{}} | + {reply, Reply :: term(), NewState :: #state{}, timeout() | hibernate} | + {noreply, NewState :: #state{}} | + {noreply, NewState :: #state{}, timeout() | hibernate} | + {stop, Reason :: term(), Reply :: term(), NewState :: #state{}} | + {stop, Reason :: term(), NewState :: #state{}}). +handle_call(checkout, _From, State = #state{release_count = Count}) -> + case Count > 0 of + true -> + {reply, ok, State#state{release_count = Count - 1}}; + false -> + {reply, error, State} + end. + +%% @private +%% @doc Handling cast messages +-spec(handle_cast(Request :: term(), State :: #state{}) -> + {noreply, NewState :: #state{}} | + {noreply, NewState :: #state{}, timeout() | hibernate} | + {stop, Reason :: term(), NewState :: #state{}}). +handle_cast({attach, NetworkPid, ThrottleKey}, State = #state{network_map = NetworkMap}) -> + monitor(process, NetworkPid), + {noreply, State#state{network_map = maps:put(NetworkPid, ThrottleKey, NetworkMap)}}. + +%% @private +%% @doc Handling all non call/cast messages +-spec(handle_info(Info :: timeout() | term(), State :: #state{}) -> + {noreply, NewState :: #state{}} | + {noreply, NewState :: #state{}, timeout() | hibernate} | + {stop, Reason :: term(), NewState :: #state{}}). +handle_info({timeout, _, release_ticker}, State = #state{network_map = ChannelMap}) -> + %% 让渡资源定时器 + erlang:start_timer(100, self(), release_ticker), + AccReleaseCount = lists:foldl(fun(ThrottleKey, Acc) -> + case throttle:peek(sdlan_network, ThrottleKey) of + {ok, RestCount, LeftToReset} -> + {ok, NetworkBindWidth} = application:get_env(sdlan, network_bind_width), + NeedCount = erlang:ceil(NetworkBindWidth / 1000 * LeftToReset), + Acc + max(0, RestCount - NeedCount); + {limit_exceeded, 0, _} -> + Acc + end + end, 0, maps:keys(ChannelMap)), + % lager:debug("[sdlan_network_coordinator] can release count is: ~p", [AccReleaseCount]), + {noreply, State#state{release_count = AccReleaseCount}}; +handle_info({'DOWN', _, process, NetworkPid, Reason}, State = #state{network_map = NetworkMap}) -> + lager:debug("[sdlan_network_coordinator] network_pid close with reason: ~p", [Reason]), + {noreply, State#state{network_map = maps:remove(NetworkPid, NetworkMap)}}. + +%% @private +%% @doc This function is called by a gen_server when it is about to +%% terminate. It should be the opposite of Module:init/1 and do any +%% necessary cleaning up. When it returns, the gen_server terminates +%% with Reason. The return value is ignored. +-spec(terminate(Reason :: (normal | shutdown | {shutdown, term()} | term()), + State :: #state{}) -> term()). +terminate(_Reason, _State = #state{}) -> + ok. + +%% @private +%% @doc Convert process state when code is changed +-spec(code_change(OldVsn :: term() | {down, term()}, State :: #state{}, + Extra :: term()) -> + {ok, NewState :: #state{}} | {error, Reason :: term()}). +code_change(_OldVsn, State = #state{}, _Extra) -> + {ok, State}. + +%%%=================================================================== +%%% Internal functions +%%%=================================================================== diff --git a/apps/sdlan/src/sdlan_network_sup.erl b/apps/sdlan/src/sdlan_network_sup.erl new file mode 100644 index 0000000..5a39378 --- /dev/null +++ b/apps/sdlan/src/sdlan_network_sup.erl @@ -0,0 +1,117 @@ +%%%------------------------------------------------------------------- +%%% @author anlicheng +%%% @copyright (C) 2024, +%%% @doc +%%% +%%% @end +%%% Created : 27. 3月 2024 15:12 +%%%------------------------------------------------------------------- +-module(sdlan_network_sup). +-author("anlicheng"). + +-behaviour(supervisor). + +%% API +-export([start_link/0]). +-export([ensured_network_started/1, delete_network/1, get_all_networks/0, start_network/1, reallocate_bind_width/0]). + +%% Supervisor callbacks +-export([init/1]). + +-define(SERVER, ?MODULE). + +%%%=================================================================== +%%% API functions +%%%=================================================================== + +%% @doc Starts the supervisor +-spec(start_link() -> {ok, Pid :: pid()} | ignore | {error, Reason :: term()}). +start_link() -> + supervisor:start_link({local, ?SERVER}, ?MODULE, []). + +%%%=================================================================== +%%% Supervisor callbacks +%%%=================================================================== + +%% @private +%% @doc Whenever a supervisor is started using supervisor:start_link/[2,3], +%% this function is called by the new process to find out about +%% restart strategy, maximum restart frequency and child +%% specifications. +init([]) -> + SupFlags = #{strategy => one_for_one, intensity => 1000, period => 3600}, + {ok, NetworkIds} = sdlan_api:get_all_networks(), + Specs = lists:map(fun child_spec/1, NetworkIds), + + set_network_bind(length(Specs)), + + {ok, {SupFlags, Specs}}. + +%%%=================================================================== +%%% Internal functions +%%%=================================================================== + +-spec ensured_network_started(Id :: integer()) -> {ok, Pid :: pid()} | {error, Reason :: any()}. +ensured_network_started(Id) when is_integer(Id) -> + case sdlan_network:get_pid(Id) of + undefined -> + case supervisor:start_child(?MODULE, child_spec(Id)) of + {ok, Pid} when is_pid(Pid) -> + {ok, Pid}; + {error, {'already_started', Pid}} when is_pid(Pid) -> + {ok, Pid}; + {error, Error} -> + {error, Error} + end; + Pid when is_pid(Pid) -> + {ok, Pid} + end. + +-spec start_network(Id :: integer()) -> {ok, Pid :: pid()} | {error, Reason :: any()}. +start_network(Id) when is_integer(Id) -> + case supervisor:start_child(?MODULE, child_spec(Id)) of + {ok, Pid} when is_pid(Pid) -> + {ok, Pid}; + {error, {'already_started', Pid}} when is_pid(Pid) -> + {ok, Pid}; + {error, Error} -> + {error, Error} + end. + +-spec get_all_networks() -> [pid()]. +get_all_networks() -> + lists:map(fun({_Id, ChildPid, _Type, _Modules}) -> ChildPid end, supervisor:which_children(?MODULE)). + +%% 重新分配网络带宽 +-spec reallocate_bind_width() -> no_return(). +reallocate_bind_width() -> + ChildPids = lists:map(fun({_Id, ChildPid, _Type, _Modules}) -> ChildPid end, supervisor:which_children(?MODULE)), + set_network_bind(length(ChildPids)). + +-spec delete_network(NetworkId :: integer()) -> ok | {error, Reason :: any()}. +delete_network(NetworkId) when is_integer(NetworkId) -> + ChildId = sdlan_network:get_name(NetworkId), + case supervisor:terminate_child(?MODULE, ChildId) of + ok -> + supervisor:delete_child(?MODULE, ChildId); + Error -> + Error + end. + +-spec child_spec(Id :: integer()) -> map(). +child_spec(Id) when is_integer(Id) -> + Name = sdlan_network:get_name(Id), + #{ + id => Name, + start => {sdlan_network, start_link, [Name, Id]}, + restart => permanent, + shutdown => 2000, + type => worker, + modules => ['sdlan_network'] + }. + +set_network_bind(Count) when is_integer(Count) -> + {ok, BindWidth} = application:get_env(sdlan, band_width), + NetworkBindWidth = BindWidth div Count, + application:set_env(sdlan, network_bind_width, NetworkBindWidth), + throttle:setup(sdlan_network, NetworkBindWidth, per_second). \ No newline at end of file diff --git a/apps/sdlan/src/sdlan_pb.erl b/apps/sdlan/src/sdlan_pb.erl new file mode 100644 index 0000000..f3ddf96 --- /dev/null +++ b/apps/sdlan/src/sdlan_pb.erl @@ -0,0 +1,3733 @@ +%% -*- coding: utf-8 -*- +%% % this file is @generated +%% @private +%% Automatically generated, do not edit +%% Generated by gpb_compile version 4.21.1 +%% Version source: git +-module(sdlan_pb). + +-export([encode_msg/1, encode_msg/2, encode_msg/3]). +-export([decode_msg/2, decode_msg/3]). +-export([merge_msgs/2, merge_msgs/3, merge_msgs/4]). +-export([verify_msg/1, verify_msg/2, verify_msg/3]). +-export([get_msg_defs/0]). +-export([get_msg_names/0]). +-export([get_group_names/0]). +-export([get_msg_or_group_names/0]). +-export([get_enum_names/0]). +-export([find_msg_def/1, fetch_msg_def/1]). +-export([find_enum_def/1, fetch_enum_def/1]). +-export([enum_symbol_by_value/2, enum_value_by_symbol/2]). +-export([get_service_names/0]). +-export([get_service_def/1]). +-export([get_rpc_names/1]). +-export([find_rpc_def/2, fetch_rpc_def/2]). +-export([fqbin_to_service_name/1]). +-export([service_name_to_fqbin/1]). +-export([fqbins_to_service_and_rpc_name/2]). +-export([service_and_rpc_name_to_fqbins/2]). +-export([fqbin_to_msg_name/1]). +-export([msg_name_to_fqbin/1]). +-export([fqbin_to_enum_name/1]). +-export([enum_name_to_fqbin/1]). +-export([get_package_name/0]). +-export([uses_packages/0]). +-export([source_basename/0]). +-export([get_all_source_basenames/0]). +-export([get_all_proto_names/0]). +-export([get_msg_containment/1]). +-export([get_pkg_containment/1]). +-export([get_service_containment/1]). +-export([get_rpc_containment/1]). +-export([get_enum_containment/1]). +-export([get_proto_by_msg_name_as_fqbin/1]). +-export([get_proto_by_service_name_as_fqbin/1]). +-export([get_proto_by_enum_name_as_fqbin/1]). +-export([get_protos_by_pkg_name_as_fqbin/1]). +-export([gpb_version_as_string/0, gpb_version_as_list/0]). +-export([gpb_version_source/0]). + +-include("sdlan_pb.hrl"). +-include_lib("gpb/include/gpb.hrl"). + +%% enumerated types + +-export_type([]). + +%% message types +-type sdl_v4_info() :: #sdl_v4_info{}. + +-type sdl_v6_info() :: #sdl_v6_info{}. + +-type sdl_dev_addr() :: #sdl_dev_addr{}. + +-type sdl_empty() :: #sdl_empty{}. + +-type sdl_register_super() :: #sdl_register_super{}. + +-type sdl_register_super_ack() :: #sdl_register_super_ack{}. + +-type sdl_register_super_nak() :: #sdl_register_super_nak{}. + +-type sdl_query_info() :: #sdl_query_info{}. + +-type sdl_peer_info() :: #sdl_peer_info{}. + +-type sdl_nat_changed_event() :: #sdl_nat_changed_event{}. + +-type sdl_send_register_event() :: #sdl_send_register_event{}. + +-type sdl_network_shutdown_event() :: #sdl_network_shutdown_event{}. + +-type sdl_change_network_command() :: #sdl_change_network_command{}. + +-type sdl_command_ack() :: #sdl_command_ack{}. + +-type sdl_flows() :: #sdl_flows{}. + +-type sdl_stun_request() :: #sdl_stun_request{}. + +-type sdl_stun_reply() :: #sdl_stun_reply{}. + +-type sdl_data() :: #sdl_data{}. + +-type sdl_register() :: #sdl_register{}. + +-type sdl_register_ack() :: #sdl_register_ack{}. + +-type sdl_stun_probe() :: #sdl_stun_probe{}. + +-type sdl_stun_probe_reply() :: #sdl_stun_probe_reply{}. + +-export_type(['sdl_v4_info'/0, 'sdl_v6_info'/0, 'sdl_dev_addr'/0, 'sdl_empty'/0, 'sdl_register_super'/0, 'sdl_register_super_ack'/0, 'sdl_register_super_nak'/0, 'sdl_query_info'/0, 'sdl_peer_info'/0, 'sdl_nat_changed_event'/0, 'sdl_send_register_event'/0, 'sdl_network_shutdown_event'/0, 'sdl_change_network_command'/0, 'sdl_command_ack'/0, 'sdl_flows'/0, 'sdl_stun_request'/0, 'sdl_stun_reply'/0, 'sdl_data'/0, 'sdl_register'/0, 'sdl_register_ack'/0, 'sdl_stun_probe'/0, 'sdl_stun_probe_reply'/0]). +-type '$msg_name'() :: sdl_v4_info | sdl_v6_info | sdl_dev_addr | sdl_empty | sdl_register_super | sdl_register_super_ack | sdl_register_super_nak | sdl_query_info | sdl_peer_info | sdl_nat_changed_event | sdl_send_register_event | sdl_network_shutdown_event | sdl_change_network_command | sdl_command_ack | sdl_flows | sdl_stun_request | sdl_stun_reply | sdl_data | sdl_register | sdl_register_ack | sdl_stun_probe | sdl_stun_probe_reply. +-type '$msg'() :: sdl_v4_info() | sdl_v6_info() | sdl_dev_addr() | sdl_empty() | sdl_register_super() | sdl_register_super_ack() | sdl_register_super_nak() | sdl_query_info() | sdl_peer_info() | sdl_nat_changed_event() | sdl_send_register_event() | sdl_network_shutdown_event() | sdl_change_network_command() | sdl_command_ack() | sdl_flows() | sdl_stun_request() | sdl_stun_reply() | sdl_data() | sdl_register() | sdl_register_ack() | sdl_stun_probe() | sdl_stun_probe_reply(). +-export_type(['$msg_name'/0, '$msg'/0]). + +-if(?OTP_RELEASE >= 24). +-dialyzer({no_underspecs, encode_msg/1}). +-endif. +-spec encode_msg('$msg'()) -> binary(). +encode_msg(Msg) when tuple_size(Msg) >= 1 -> encode_msg(Msg, element(1, Msg), []). + +-if(?OTP_RELEASE >= 24). +-dialyzer({no_underspecs, encode_msg/2}). +-endif. +-spec encode_msg('$msg'(), '$msg_name'() | list()) -> binary(). +encode_msg(Msg, MsgName) when is_atom(MsgName) -> encode_msg(Msg, MsgName, []); +encode_msg(Msg, Opts) when tuple_size(Msg) >= 1, is_list(Opts) -> encode_msg(Msg, element(1, Msg), Opts). + +-if(?OTP_RELEASE >= 24). +-dialyzer({no_underspecs, encode_msg/3}). +-endif. +-spec encode_msg('$msg'(), '$msg_name'(), list()) -> binary(). +encode_msg(Msg, MsgName, Opts) -> + case proplists:get_bool(verify, Opts) of + true -> verify_msg(Msg, MsgName, Opts); + false -> ok + end, + TrUserData = proplists:get_value(user_data, Opts), + case MsgName of + sdl_v4_info -> encode_msg_sdl_v4_info(id(Msg, TrUserData), TrUserData); + sdl_v6_info -> encode_msg_sdl_v6_info(id(Msg, TrUserData), TrUserData); + sdl_dev_addr -> encode_msg_sdl_dev_addr(id(Msg, TrUserData), TrUserData); + sdl_empty -> encode_msg_sdl_empty(id(Msg, TrUserData), TrUserData); + sdl_register_super -> encode_msg_sdl_register_super(id(Msg, TrUserData), TrUserData); + sdl_register_super_ack -> encode_msg_sdl_register_super_ack(id(Msg, TrUserData), TrUserData); + sdl_register_super_nak -> encode_msg_sdl_register_super_nak(id(Msg, TrUserData), TrUserData); + sdl_query_info -> encode_msg_sdl_query_info(id(Msg, TrUserData), TrUserData); + sdl_peer_info -> encode_msg_sdl_peer_info(id(Msg, TrUserData), TrUserData); + sdl_nat_changed_event -> encode_msg_sdl_nat_changed_event(id(Msg, TrUserData), TrUserData); + sdl_send_register_event -> encode_msg_sdl_send_register_event(id(Msg, TrUserData), TrUserData); + sdl_network_shutdown_event -> encode_msg_sdl_network_shutdown_event(id(Msg, TrUserData), TrUserData); + sdl_change_network_command -> encode_msg_sdl_change_network_command(id(Msg, TrUserData), TrUserData); + sdl_command_ack -> encode_msg_sdl_command_ack(id(Msg, TrUserData), TrUserData); + sdl_flows -> encode_msg_sdl_flows(id(Msg, TrUserData), TrUserData); + sdl_stun_request -> encode_msg_sdl_stun_request(id(Msg, TrUserData), TrUserData); + sdl_stun_reply -> encode_msg_sdl_stun_reply(id(Msg, TrUserData), TrUserData); + sdl_data -> encode_msg_sdl_data(id(Msg, TrUserData), TrUserData); + sdl_register -> encode_msg_sdl_register(id(Msg, TrUserData), TrUserData); + sdl_register_ack -> encode_msg_sdl_register_ack(id(Msg, TrUserData), TrUserData); + sdl_stun_probe -> encode_msg_sdl_stun_probe(id(Msg, TrUserData), TrUserData); + sdl_stun_probe_reply -> encode_msg_sdl_stun_probe_reply(id(Msg, TrUserData), TrUserData) + end. + + +encode_msg_sdl_v4_info(Msg, TrUserData) -> encode_msg_sdl_v4_info(Msg, <<>>, TrUserData). + + +encode_msg_sdl_v4_info(#sdl_v4_info{port = F1, v4 = F2, nat_type = F3}, Bin, TrUserData) -> + B1 = if F1 == undefined -> Bin; + true -> + begin + TrF1 = id(F1, TrUserData), + if TrF1 =:= 0 -> Bin; + true -> e_varint(TrF1, <>, TrUserData) + end + end + end, + B2 = if F2 == undefined -> B1; + true -> + begin + TrF2 = id(F2, TrUserData), + case iolist_size(TrF2) of + 0 -> B1; + _ -> e_type_bytes(TrF2, <>, TrUserData) + end + end + end, + if F3 == undefined -> B2; + true -> + begin + TrF3 = id(F3, TrUserData), + if TrF3 =:= 0 -> B2; + true -> e_varint(TrF3, <>, TrUserData) + end + end + end. + +encode_msg_sdl_v6_info(Msg, TrUserData) -> encode_msg_sdl_v6_info(Msg, <<>>, TrUserData). + + +encode_msg_sdl_v6_info(#sdl_v6_info{port = F1, v6 = F2}, Bin, TrUserData) -> + B1 = if F1 == undefined -> Bin; + true -> + begin + TrF1 = id(F1, TrUserData), + if TrF1 =:= 0 -> Bin; + true -> e_varint(TrF1, <>, TrUserData) + end + end + end, + if F2 == undefined -> B1; + true -> + begin + TrF2 = id(F2, TrUserData), + case iolist_size(TrF2) of + 0 -> B1; + _ -> e_type_bytes(TrF2, <>, TrUserData) + end + end + end. + +encode_msg_sdl_dev_addr(Msg, TrUserData) -> encode_msg_sdl_dev_addr(Msg, <<>>, TrUserData). + + +encode_msg_sdl_dev_addr(#sdl_dev_addr{network_id = F1, mac = F2, net_addr = F3, net_bit_len = F4}, Bin, TrUserData) -> + B1 = if F1 == undefined -> Bin; + true -> + begin + TrF1 = id(F1, TrUserData), + if TrF1 =:= 0 -> Bin; + true -> e_varint(TrF1, <>, TrUserData) + end + end + end, + B2 = if F2 == undefined -> B1; + true -> + begin + TrF2 = id(F2, TrUserData), + case iolist_size(TrF2) of + 0 -> B1; + _ -> e_type_bytes(TrF2, <>, TrUserData) + end + end + end, + B3 = if F3 == undefined -> B2; + true -> + begin + TrF3 = id(F3, TrUserData), + if TrF3 =:= 0 -> B2; + true -> e_varint(TrF3, <>, TrUserData) + end + end + end, + if F4 == undefined -> B3; + true -> + begin + TrF4 = id(F4, TrUserData), + if TrF4 =:= 0 -> B3; + true -> e_varint(TrF4, <>, TrUserData) + end + end + end. + +encode_msg_sdl_empty(_Msg, _TrUserData) -> <<>>. + +encode_msg_sdl_register_super(Msg, TrUserData) -> encode_msg_sdl_register_super(Msg, <<>>, TrUserData). + + +encode_msg_sdl_register_super(#sdl_register_super{version = F1, installed_channel = F2, client_id = F3, dev_addr = F4, pub_key = F5, token = F6}, Bin, TrUserData) -> + B1 = if F1 == undefined -> Bin; + true -> + begin + TrF1 = id(F1, TrUserData), + if TrF1 =:= 0 -> Bin; + true -> e_varint(TrF1, <>, TrUserData) + end + end + end, + B2 = if F2 == undefined -> B1; + true -> + begin + TrF2 = id(F2, TrUserData), + case is_empty_string(TrF2) of + true -> B1; + false -> e_type_string(TrF2, <>, TrUserData) + end + end + end, + B3 = if F3 == undefined -> B2; + true -> + begin + TrF3 = id(F3, TrUserData), + case is_empty_string(TrF3) of + true -> B2; + false -> e_type_string(TrF3, <>, TrUserData) + end + end + end, + B4 = if F4 == undefined -> B3; + true -> + begin + TrF4 = id(F4, TrUserData), + if TrF4 =:= undefined -> B3; + true -> e_mfield_sdl_register_super_dev_addr(TrF4, <>, TrUserData) + end + end + end, + B5 = if F5 == undefined -> B4; + true -> + begin + TrF5 = id(F5, TrUserData), + case is_empty_string(TrF5) of + true -> B4; + false -> e_type_string(TrF5, <>, TrUserData) + end + end + end, + if F6 == undefined -> B5; + true -> + begin + TrF6 = id(F6, TrUserData), + case is_empty_string(TrF6) of + true -> B5; + false -> e_type_string(TrF6, <>, TrUserData) + end + end + end. + +encode_msg_sdl_register_super_ack(Msg, TrUserData) -> encode_msg_sdl_register_super_ack(Msg, <<>>, TrUserData). + + +encode_msg_sdl_register_super_ack(#sdl_register_super_ack{dev_addr = F1, aes_key = F2, upgrade_type = F3, upgrade_prompt = F4, upgrade_address = F5}, Bin, TrUserData) -> + B1 = if F1 == undefined -> Bin; + true -> + begin + TrF1 = id(F1, TrUserData), + if TrF1 =:= undefined -> Bin; + true -> e_mfield_sdl_register_super_ack_dev_addr(TrF1, <>, TrUserData) + end + end + end, + B2 = if F2 == undefined -> B1; + true -> + begin + TrF2 = id(F2, TrUserData), + case iolist_size(TrF2) of + 0 -> B1; + _ -> e_type_bytes(TrF2, <>, TrUserData) + end + end + end, + B3 = if F3 == undefined -> B2; + true -> + begin + TrF3 = id(F3, TrUserData), + if TrF3 =:= 0 -> B2; + true -> e_varint(TrF3, <>, TrUserData) + end + end + end, + B4 = if F4 == undefined -> B3; + true -> begin TrF4 = id(F4, TrUserData), e_type_string(TrF4, <>, TrUserData) end + end, + if F5 == undefined -> B4; + true -> begin TrF5 = id(F5, TrUserData), e_type_string(TrF5, <>, TrUserData) end + end. + +encode_msg_sdl_register_super_nak(Msg, TrUserData) -> encode_msg_sdl_register_super_nak(Msg, <<>>, TrUserData). + + +encode_msg_sdl_register_super_nak(#sdl_register_super_nak{error_code = F1, error_message = F2}, Bin, TrUserData) -> + B1 = if F1 == undefined -> Bin; + true -> + begin + TrF1 = id(F1, TrUserData), + if TrF1 =:= 0 -> Bin; + true -> e_varint(TrF1, <>, TrUserData) + end + end + end, + if F2 == undefined -> B1; + true -> + begin + TrF2 = id(F2, TrUserData), + case is_empty_string(TrF2) of + true -> B1; + false -> e_type_string(TrF2, <>, TrUserData) + end + end + end. + +encode_msg_sdl_query_info(Msg, TrUserData) -> encode_msg_sdl_query_info(Msg, <<>>, TrUserData). + + +encode_msg_sdl_query_info(#sdl_query_info{dst_mac = F1}, Bin, TrUserData) -> + if F1 == undefined -> Bin; + true -> + begin + TrF1 = id(F1, TrUserData), + case iolist_size(TrF1) of + 0 -> Bin; + _ -> e_type_bytes(TrF1, <>, TrUserData) + end + end + end. + +encode_msg_sdl_peer_info(Msg, TrUserData) -> encode_msg_sdl_peer_info(Msg, <<>>, TrUserData). + + +encode_msg_sdl_peer_info(#sdl_peer_info{dst_mac = F1, v4_info = F2, v6_info = F3}, Bin, TrUserData) -> + B1 = if F1 == undefined -> Bin; + true -> + begin + TrF1 = id(F1, TrUserData), + case iolist_size(TrF1) of + 0 -> Bin; + _ -> e_type_bytes(TrF1, <>, TrUserData) + end + end + end, + B2 = if F2 == undefined -> B1; + true -> + begin + TrF2 = id(F2, TrUserData), + if TrF2 =:= undefined -> B1; + true -> e_mfield_sdl_peer_info_v4_info(TrF2, <>, TrUserData) + end + end + end, + if F3 == undefined -> B2; + true -> begin TrF3 = id(F3, TrUserData), e_mfield_sdl_peer_info_v6_info(TrF3, <>, TrUserData) end + end. + +encode_msg_sdl_nat_changed_event(Msg, TrUserData) -> encode_msg_sdl_nat_changed_event(Msg, <<>>, TrUserData). + + +encode_msg_sdl_nat_changed_event(#sdl_nat_changed_event{mac = F1, ip = F2}, Bin, TrUserData) -> + B1 = if F1 == undefined -> Bin; + true -> + begin + TrF1 = id(F1, TrUserData), + case iolist_size(TrF1) of + 0 -> Bin; + _ -> e_type_bytes(TrF1, <>, TrUserData) + end + end + end, + if F2 == undefined -> B1; + true -> + begin + TrF2 = id(F2, TrUserData), + if TrF2 =:= 0 -> B1; + true -> e_varint(TrF2, <>, TrUserData) + end + end + end. + +encode_msg_sdl_send_register_event(Msg, TrUserData) -> encode_msg_sdl_send_register_event(Msg, <<>>, TrUserData). + + +encode_msg_sdl_send_register_event(#sdl_send_register_event{dst_mac = F1, nat_ip = F2, nat_port = F3, nat_type = F4, v6_info = F5}, Bin, TrUserData) -> + B1 = if F1 == undefined -> Bin; + true -> + begin + TrF1 = id(F1, TrUserData), + case iolist_size(TrF1) of + 0 -> Bin; + _ -> e_type_bytes(TrF1, <>, TrUserData) + end + end + end, + B2 = if F2 == undefined -> B1; + true -> + begin + TrF2 = id(F2, TrUserData), + if TrF2 =:= 0 -> B1; + true -> e_varint(TrF2, <>, TrUserData) + end + end + end, + B3 = if F3 == undefined -> B2; + true -> + begin + TrF3 = id(F3, TrUserData), + if TrF3 =:= 0 -> B2; + true -> e_varint(TrF3, <>, TrUserData) + end + end + end, + B4 = if F4 == undefined -> B3; + true -> + begin + TrF4 = id(F4, TrUserData), + if TrF4 =:= 0 -> B3; + true -> e_varint(TrF4, <>, TrUserData) + end + end + end, + if F5 == undefined -> B4; + true -> begin TrF5 = id(F5, TrUserData), e_mfield_sdl_send_register_event_v6_info(TrF5, <>, TrUserData) end + end. + +encode_msg_sdl_network_shutdown_event(Msg, TrUserData) -> encode_msg_sdl_network_shutdown_event(Msg, <<>>, TrUserData). + + +encode_msg_sdl_network_shutdown_event(#sdl_network_shutdown_event{message = F1}, Bin, TrUserData) -> + if F1 == undefined -> Bin; + true -> + begin + TrF1 = id(F1, TrUserData), + case is_empty_string(TrF1) of + true -> Bin; + false -> e_type_string(TrF1, <>, TrUserData) + end + end + end. + +encode_msg_sdl_change_network_command(Msg, TrUserData) -> encode_msg_sdl_change_network_command(Msg, <<>>, TrUserData). + + +encode_msg_sdl_change_network_command(#sdl_change_network_command{dev_addr = F1, aes_key = F2}, Bin, TrUserData) -> + B1 = if F1 == undefined -> Bin; + true -> + begin + TrF1 = id(F1, TrUserData), + if TrF1 =:= undefined -> Bin; + true -> e_mfield_sdl_change_network_command_dev_addr(TrF1, <>, TrUserData) + end + end + end, + if F2 == undefined -> B1; + true -> + begin + TrF2 = id(F2, TrUserData), + case iolist_size(TrF2) of + 0 -> B1; + _ -> e_type_bytes(TrF2, <>, TrUserData) + end + end + end. + +encode_msg_sdl_command_ack(Msg, TrUserData) -> encode_msg_sdl_command_ack(Msg, <<>>, TrUserData). + + +encode_msg_sdl_command_ack(#sdl_command_ack{status = F1, message = F2}, Bin, TrUserData) -> + B1 = if F1 == undefined -> Bin; + true -> + begin + TrF1 = id(F1, TrUserData), + if TrF1 =:= false -> Bin; + true -> e_type_bool(TrF1, <>, TrUserData) + end + end + end, + if F2 == undefined -> B1; + true -> begin TrF2 = id(F2, TrUserData), e_type_string(TrF2, <>, TrUserData) end + end. + +encode_msg_sdl_flows(Msg, TrUserData) -> encode_msg_sdl_flows(Msg, <<>>, TrUserData). + + +encode_msg_sdl_flows(#sdl_flows{forward_num = F1, p2p_num = F2, inbound_num = F3}, Bin, TrUserData) -> + B1 = if F1 == undefined -> Bin; + true -> + begin + TrF1 = id(F1, TrUserData), + if TrF1 =:= 0 -> Bin; + true -> e_varint(TrF1, <>, TrUserData) + end + end + end, + B2 = if F2 == undefined -> B1; + true -> + begin + TrF2 = id(F2, TrUserData), + if TrF2 =:= 0 -> B1; + true -> e_varint(TrF2, <>, TrUserData) + end + end + end, + if F3 == undefined -> B2; + true -> + begin + TrF3 = id(F3, TrUserData), + if TrF3 =:= 0 -> B2; + true -> e_varint(TrF3, <>, TrUserData) + end + end + end. + +encode_msg_sdl_stun_request(Msg, TrUserData) -> encode_msg_sdl_stun_request(Msg, <<>>, TrUserData). + + +encode_msg_sdl_stun_request(#sdl_stun_request{cookie = F1, client_id = F2, network_id = F3, mac = F4, ip = F5, nat_type = F6, v6_info = F7}, Bin, TrUserData) -> + B1 = if F1 == undefined -> Bin; + true -> + begin + TrF1 = id(F1, TrUserData), + if TrF1 =:= 0 -> Bin; + true -> e_varint(TrF1, <>, TrUserData) + end + end + end, + B2 = if F2 == undefined -> B1; + true -> + begin + TrF2 = id(F2, TrUserData), + case is_empty_string(TrF2) of + true -> B1; + false -> e_type_string(TrF2, <>, TrUserData) + end + end + end, + B3 = if F3 == undefined -> B2; + true -> + begin + TrF3 = id(F3, TrUserData), + if TrF3 =:= 0 -> B2; + true -> e_varint(TrF3, <>, TrUserData) + end + end + end, + B4 = if F4 == undefined -> B3; + true -> + begin + TrF4 = id(F4, TrUserData), + case iolist_size(TrF4) of + 0 -> B3; + _ -> e_type_bytes(TrF4, <>, TrUserData) + end + end + end, + B5 = if F5 == undefined -> B4; + true -> + begin + TrF5 = id(F5, TrUserData), + if TrF5 =:= 0 -> B4; + true -> e_varint(TrF5, <>, TrUserData) + end + end + end, + B6 = if F6 == undefined -> B5; + true -> + begin + TrF6 = id(F6, TrUserData), + if TrF6 =:= 0 -> B5; + true -> e_varint(TrF6, <>, TrUserData) + end + end + end, + if F7 == undefined -> B6; + true -> begin TrF7 = id(F7, TrUserData), e_mfield_sdl_stun_request_v6_info(TrF7, <>, TrUserData) end + end. + +encode_msg_sdl_stun_reply(Msg, TrUserData) -> encode_msg_sdl_stun_reply(Msg, <<>>, TrUserData). + + +encode_msg_sdl_stun_reply(#sdl_stun_reply{cookie = F1}, Bin, TrUserData) -> + if F1 == undefined -> Bin; + true -> + begin + TrF1 = id(F1, TrUserData), + if TrF1 =:= 0 -> Bin; + true -> e_varint(TrF1, <>, TrUserData) + end + end + end. + +encode_msg_sdl_data(Msg, TrUserData) -> encode_msg_sdl_data(Msg, <<>>, TrUserData). + + +encode_msg_sdl_data(#sdl_data{network_id = F1, src_mac = F2, dst_mac = F3, is_p2p = F4, ttl = F5, data = F6}, Bin, TrUserData) -> + B1 = if F1 == undefined -> Bin; + true -> + begin + TrF1 = id(F1, TrUserData), + if TrF1 =:= 0 -> Bin; + true -> e_varint(TrF1, <>, TrUserData) + end + end + end, + B2 = if F2 == undefined -> B1; + true -> + begin + TrF2 = id(F2, TrUserData), + case iolist_size(TrF2) of + 0 -> B1; + _ -> e_type_bytes(TrF2, <>, TrUserData) + end + end + end, + B3 = if F3 == undefined -> B2; + true -> + begin + TrF3 = id(F3, TrUserData), + case iolist_size(TrF3) of + 0 -> B2; + _ -> e_type_bytes(TrF3, <>, TrUserData) + end + end + end, + B4 = if F4 == undefined -> B3; + true -> + begin + TrF4 = id(F4, TrUserData), + if TrF4 =:= false -> B3; + true -> e_type_bool(TrF4, <>, TrUserData) + end + end + end, + B5 = if F5 == undefined -> B4; + true -> + begin + TrF5 = id(F5, TrUserData), + if TrF5 =:= 0 -> B4; + true -> e_varint(TrF5, <>, TrUserData) + end + end + end, + if F6 == undefined -> B5; + true -> + begin + TrF6 = id(F6, TrUserData), + case iolist_size(TrF6) of + 0 -> B5; + _ -> e_type_bytes(TrF6, <>, TrUserData) + end + end + end. + +encode_msg_sdl_register(Msg, TrUserData) -> encode_msg_sdl_register(Msg, <<>>, TrUserData). + + +encode_msg_sdl_register(#sdl_register{network_id = F1, src_mac = F2, dst_mac = F3}, Bin, TrUserData) -> + B1 = if F1 == undefined -> Bin; + true -> + begin + TrF1 = id(F1, TrUserData), + if TrF1 =:= 0 -> Bin; + true -> e_varint(TrF1, <>, TrUserData) + end + end + end, + B2 = if F2 == undefined -> B1; + true -> + begin + TrF2 = id(F2, TrUserData), + case iolist_size(TrF2) of + 0 -> B1; + _ -> e_type_bytes(TrF2, <>, TrUserData) + end + end + end, + if F3 == undefined -> B2; + true -> + begin + TrF3 = id(F3, TrUserData), + case iolist_size(TrF3) of + 0 -> B2; + _ -> e_type_bytes(TrF3, <>, TrUserData) + end + end + end. + +encode_msg_sdl_register_ack(Msg, TrUserData) -> encode_msg_sdl_register_ack(Msg, <<>>, TrUserData). + + +encode_msg_sdl_register_ack(#sdl_register_ack{network_id = F1, src_mac = F2, dst_mac = F3}, Bin, TrUserData) -> + B1 = if F1 == undefined -> Bin; + true -> + begin + TrF1 = id(F1, TrUserData), + if TrF1 =:= 0 -> Bin; + true -> e_varint(TrF1, <>, TrUserData) + end + end + end, + B2 = if F2 == undefined -> B1; + true -> + begin + TrF2 = id(F2, TrUserData), + case iolist_size(TrF2) of + 0 -> B1; + _ -> e_type_bytes(TrF2, <>, TrUserData) + end + end + end, + if F3 == undefined -> B2; + true -> + begin + TrF3 = id(F3, TrUserData), + case iolist_size(TrF3) of + 0 -> B2; + _ -> e_type_bytes(TrF3, <>, TrUserData) + end + end + end. + +encode_msg_sdl_stun_probe(Msg, TrUserData) -> encode_msg_sdl_stun_probe(Msg, <<>>, TrUserData). + + +encode_msg_sdl_stun_probe(#sdl_stun_probe{cookie = F1, attr = F2}, Bin, TrUserData) -> + B1 = if F1 == undefined -> Bin; + true -> + begin + TrF1 = id(F1, TrUserData), + if TrF1 =:= 0 -> Bin; + true -> e_varint(TrF1, <>, TrUserData) + end + end + end, + if F2 == undefined -> B1; + true -> + begin + TrF2 = id(F2, TrUserData), + if TrF2 =:= 0 -> B1; + true -> e_varint(TrF2, <>, TrUserData) + end + end + end. + +encode_msg_sdl_stun_probe_reply(Msg, TrUserData) -> encode_msg_sdl_stun_probe_reply(Msg, <<>>, TrUserData). + + +encode_msg_sdl_stun_probe_reply(#sdl_stun_probe_reply{cookie = F1, port = F2, ip = F3}, Bin, TrUserData) -> + B1 = if F1 == undefined -> Bin; + true -> + begin + TrF1 = id(F1, TrUserData), + if TrF1 =:= 0 -> Bin; + true -> e_varint(TrF1, <>, TrUserData) + end + end + end, + B2 = if F2 == undefined -> B1; + true -> + begin + TrF2 = id(F2, TrUserData), + if TrF2 =:= 0 -> B1; + true -> e_varint(TrF2, <>, TrUserData) + end + end + end, + if F3 == undefined -> B2; + true -> + begin + TrF3 = id(F3, TrUserData), + if TrF3 =:= 0 -> B2; + true -> e_varint(TrF3, <>, TrUserData) + end + end + end. + +e_mfield_sdl_register_super_dev_addr(Msg, Bin, TrUserData) -> + SubBin = encode_msg_sdl_dev_addr(Msg, <<>>, TrUserData), + Bin2 = e_varint(byte_size(SubBin), Bin), + <>. + +e_mfield_sdl_register_super_ack_dev_addr(Msg, Bin, TrUserData) -> + SubBin = encode_msg_sdl_dev_addr(Msg, <<>>, TrUserData), + Bin2 = e_varint(byte_size(SubBin), Bin), + <>. + +e_mfield_sdl_peer_info_v4_info(Msg, Bin, TrUserData) -> + SubBin = encode_msg_sdl_v4_info(Msg, <<>>, TrUserData), + Bin2 = e_varint(byte_size(SubBin), Bin), + <>. + +e_mfield_sdl_peer_info_v6_info(Msg, Bin, TrUserData) -> + SubBin = encode_msg_sdl_v6_info(Msg, <<>>, TrUserData), + Bin2 = e_varint(byte_size(SubBin), Bin), + <>. + +e_mfield_sdl_send_register_event_v6_info(Msg, Bin, TrUserData) -> + SubBin = encode_msg_sdl_v6_info(Msg, <<>>, TrUserData), + Bin2 = e_varint(byte_size(SubBin), Bin), + <>. + +e_mfield_sdl_change_network_command_dev_addr(Msg, Bin, TrUserData) -> + SubBin = encode_msg_sdl_dev_addr(Msg, <<>>, TrUserData), + Bin2 = e_varint(byte_size(SubBin), Bin), + <>. + +e_mfield_sdl_stun_request_v6_info(Msg, Bin, TrUserData) -> + SubBin = encode_msg_sdl_v6_info(Msg, <<>>, TrUserData), + Bin2 = e_varint(byte_size(SubBin), Bin), + <>. + +-compile({nowarn_unused_function,e_type_sint/3}). +e_type_sint(Value, Bin, _TrUserData) when Value >= 0 -> e_varint(Value * 2, Bin); +e_type_sint(Value, Bin, _TrUserData) -> e_varint(Value * -2 - 1, Bin). + +-compile({nowarn_unused_function,e_type_int32/3}). +e_type_int32(Value, Bin, _TrUserData) when 0 =< Value, Value =< 127 -> <>; +e_type_int32(Value, Bin, _TrUserData) -> + <> = <>, + e_varint(N, Bin). + +-compile({nowarn_unused_function,e_type_int64/3}). +e_type_int64(Value, Bin, _TrUserData) when 0 =< Value, Value =< 127 -> <>; +e_type_int64(Value, Bin, _TrUserData) -> + <> = <>, + e_varint(N, Bin). + +-compile({nowarn_unused_function,e_type_bool/3}). +e_type_bool(true, Bin, _TrUserData) -> <>; +e_type_bool(false, Bin, _TrUserData) -> <>; +e_type_bool(1, Bin, _TrUserData) -> <>; +e_type_bool(0, Bin, _TrUserData) -> <>. + +-compile({nowarn_unused_function,e_type_string/3}). +e_type_string(S, Bin, _TrUserData) -> + Utf8 = unicode:characters_to_binary(S), + Bin2 = e_varint(byte_size(Utf8), Bin), + <>. + +-compile({nowarn_unused_function,e_type_bytes/3}). +e_type_bytes(Bytes, Bin, _TrUserData) when is_binary(Bytes) -> + Bin2 = e_varint(byte_size(Bytes), Bin), + <>; +e_type_bytes(Bytes, Bin, _TrUserData) when is_list(Bytes) -> + BytesBin = iolist_to_binary(Bytes), + Bin2 = e_varint(byte_size(BytesBin), Bin), + <>. + +-compile({nowarn_unused_function,e_type_fixed32/3}). +e_type_fixed32(Value, Bin, _TrUserData) -> <>. + +-compile({nowarn_unused_function,e_type_sfixed32/3}). +e_type_sfixed32(Value, Bin, _TrUserData) -> <>. + +-compile({nowarn_unused_function,e_type_fixed64/3}). +e_type_fixed64(Value, Bin, _TrUserData) -> <>. + +-compile({nowarn_unused_function,e_type_sfixed64/3}). +e_type_sfixed64(Value, Bin, _TrUserData) -> <>. + +-compile({nowarn_unused_function,e_type_float/3}). +e_type_float(V, Bin, _) when is_number(V) -> <>; +e_type_float(infinity, Bin, _) -> <>; +e_type_float('-infinity', Bin, _) -> <>; +e_type_float(nan, Bin, _) -> <>. + +-compile({nowarn_unused_function,e_type_double/3}). +e_type_double(V, Bin, _) when is_number(V) -> <>; +e_type_double(infinity, Bin, _) -> <>; +e_type_double('-infinity', Bin, _) -> <>; +e_type_double(nan, Bin, _) -> <>. + +-compile({nowarn_unused_function,e_unknown_elems/2}). +e_unknown_elems([Elem | Rest], Bin) -> + BinR = case Elem of + {varint, FNum, N} -> + BinF = e_varint(FNum bsl 3, Bin), + e_varint(N, BinF); + {length_delimited, FNum, Data} -> + BinF = e_varint(FNum bsl 3 bor 2, Bin), + BinL = e_varint(byte_size(Data), BinF), + <>; + {group, FNum, GroupFields} -> + Bin1 = e_varint(FNum bsl 3 bor 3, Bin), + Bin2 = e_unknown_elems(GroupFields, Bin1), + e_varint(FNum bsl 3 bor 4, Bin2); + {fixed32, FNum, V} -> + BinF = e_varint(FNum bsl 3 bor 5, Bin), + <>; + {fixed64, FNum, V} -> + BinF = e_varint(FNum bsl 3 bor 1, Bin), + <> + end, + e_unknown_elems(Rest, BinR); +e_unknown_elems([], Bin) -> Bin. + +-compile({nowarn_unused_function,e_varint/3}). +e_varint(N, Bin, _TrUserData) -> e_varint(N, Bin). + +-compile({nowarn_unused_function,e_varint/2}). +e_varint(N, Bin) when N =< 127 -> <>; +e_varint(N, Bin) -> + Bin2 = <>, + e_varint(N bsr 7, Bin2). + +is_empty_string("") -> true; +is_empty_string(<<>>) -> true; +is_empty_string(L) when is_list(L) -> not string_has_chars(L); +is_empty_string(B) when is_binary(B) -> false. + +string_has_chars([C | _]) when is_integer(C) -> true; +string_has_chars([H | T]) -> + case string_has_chars(H) of + true -> true; + false -> string_has_chars(T) + end; +string_has_chars(B) when is_binary(B), byte_size(B) =/= 0 -> true; +string_has_chars(C) when is_integer(C) -> true; +string_has_chars(<<>>) -> false; +string_has_chars([]) -> false. + + +decode_msg(Bin, MsgName) when is_binary(Bin) -> decode_msg(Bin, MsgName, []). + +decode_msg(Bin, MsgName, Opts) when is_binary(Bin) -> + TrUserData = proplists:get_value(user_data, Opts), + decode_msg_1_catch(Bin, MsgName, TrUserData). + +-ifdef('OTP_RELEASE'). +decode_msg_1_catch(Bin, MsgName, TrUserData) -> + try decode_msg_2_doit(MsgName, Bin, TrUserData) + catch + error:{gpb_error,_}=Reason:StackTrace -> + erlang:raise(error, Reason, StackTrace); + Class:Reason:StackTrace -> error({gpb_error,{decoding_failure, {Bin, MsgName, {Class, Reason, StackTrace}}}}) + end. +-else. +decode_msg_1_catch(Bin, MsgName, TrUserData) -> + try decode_msg_2_doit(MsgName, Bin, TrUserData) + catch + error:{gpb_error,_}=Reason -> + erlang:raise(error, Reason, + erlang:get_stacktrace()); + Class:Reason -> + StackTrace = erlang:get_stacktrace(), + error({gpb_error,{decoding_failure, {Bin, MsgName, {Class, Reason, StackTrace}}}}) + end. +-endif. + +decode_msg_2_doit(sdl_v4_info, Bin, TrUserData) -> id(decode_msg_sdl_v4_info(Bin, TrUserData), TrUserData); +decode_msg_2_doit(sdl_v6_info, Bin, TrUserData) -> id(decode_msg_sdl_v6_info(Bin, TrUserData), TrUserData); +decode_msg_2_doit(sdl_dev_addr, Bin, TrUserData) -> id(decode_msg_sdl_dev_addr(Bin, TrUserData), TrUserData); +decode_msg_2_doit(sdl_empty, Bin, TrUserData) -> id(decode_msg_sdl_empty(Bin, TrUserData), TrUserData); +decode_msg_2_doit(sdl_register_super, Bin, TrUserData) -> id(decode_msg_sdl_register_super(Bin, TrUserData), TrUserData); +decode_msg_2_doit(sdl_register_super_ack, Bin, TrUserData) -> id(decode_msg_sdl_register_super_ack(Bin, TrUserData), TrUserData); +decode_msg_2_doit(sdl_register_super_nak, Bin, TrUserData) -> id(decode_msg_sdl_register_super_nak(Bin, TrUserData), TrUserData); +decode_msg_2_doit(sdl_query_info, Bin, TrUserData) -> id(decode_msg_sdl_query_info(Bin, TrUserData), TrUserData); +decode_msg_2_doit(sdl_peer_info, Bin, TrUserData) -> id(decode_msg_sdl_peer_info(Bin, TrUserData), TrUserData); +decode_msg_2_doit(sdl_nat_changed_event, Bin, TrUserData) -> id(decode_msg_sdl_nat_changed_event(Bin, TrUserData), TrUserData); +decode_msg_2_doit(sdl_send_register_event, Bin, TrUserData) -> id(decode_msg_sdl_send_register_event(Bin, TrUserData), TrUserData); +decode_msg_2_doit(sdl_network_shutdown_event, Bin, TrUserData) -> id(decode_msg_sdl_network_shutdown_event(Bin, TrUserData), TrUserData); +decode_msg_2_doit(sdl_change_network_command, Bin, TrUserData) -> id(decode_msg_sdl_change_network_command(Bin, TrUserData), TrUserData); +decode_msg_2_doit(sdl_command_ack, Bin, TrUserData) -> id(decode_msg_sdl_command_ack(Bin, TrUserData), TrUserData); +decode_msg_2_doit(sdl_flows, Bin, TrUserData) -> id(decode_msg_sdl_flows(Bin, TrUserData), TrUserData); +decode_msg_2_doit(sdl_stun_request, Bin, TrUserData) -> id(decode_msg_sdl_stun_request(Bin, TrUserData), TrUserData); +decode_msg_2_doit(sdl_stun_reply, Bin, TrUserData) -> id(decode_msg_sdl_stun_reply(Bin, TrUserData), TrUserData); +decode_msg_2_doit(sdl_data, Bin, TrUserData) -> id(decode_msg_sdl_data(Bin, TrUserData), TrUserData); +decode_msg_2_doit(sdl_register, Bin, TrUserData) -> id(decode_msg_sdl_register(Bin, TrUserData), TrUserData); +decode_msg_2_doit(sdl_register_ack, Bin, TrUserData) -> id(decode_msg_sdl_register_ack(Bin, TrUserData), TrUserData); +decode_msg_2_doit(sdl_stun_probe, Bin, TrUserData) -> id(decode_msg_sdl_stun_probe(Bin, TrUserData), TrUserData); +decode_msg_2_doit(sdl_stun_probe_reply, Bin, TrUserData) -> id(decode_msg_sdl_stun_probe_reply(Bin, TrUserData), TrUserData). + + + +decode_msg_sdl_v4_info(Bin, TrUserData) -> dfp_read_field_def_sdl_v4_info(Bin, 0, 0, 0, id(0, TrUserData), id(<<>>, TrUserData), id(0, TrUserData), TrUserData). + +dfp_read_field_def_sdl_v4_info(<<8, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> d_field_sdl_v4_info_port(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData); +dfp_read_field_def_sdl_v4_info(<<18, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> d_field_sdl_v4_info_v4(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData); +dfp_read_field_def_sdl_v4_info(<<24, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> d_field_sdl_v4_info_nat_type(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData); +dfp_read_field_def_sdl_v4_info(<<>>, 0, 0, _, F@_1, F@_2, F@_3, _) -> #sdl_v4_info{port = F@_1, v4 = F@_2, nat_type = F@_3}; +dfp_read_field_def_sdl_v4_info(Other, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> dg_read_field_def_sdl_v4_info(Other, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData). + +dg_read_field_def_sdl_v4_info(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, TrUserData) when N < 32 - 7 -> dg_read_field_def_sdl_v4_info(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, TrUserData); +dg_read_field_def_sdl_v4_info(<<0:1, X:7, Rest/binary>>, N, Acc, _, F@_1, F@_2, F@_3, TrUserData) -> + Key = X bsl N + Acc, + case Key of + 8 -> d_field_sdl_v4_info_port(Rest, 0, 0, 0, F@_1, F@_2, F@_3, TrUserData); + 18 -> d_field_sdl_v4_info_v4(Rest, 0, 0, 0, F@_1, F@_2, F@_3, TrUserData); + 24 -> d_field_sdl_v4_info_nat_type(Rest, 0, 0, 0, F@_1, F@_2, F@_3, TrUserData); + _ -> + case Key band 7 of + 0 -> skip_varint_sdl_v4_info(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, TrUserData); + 1 -> skip_64_sdl_v4_info(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, TrUserData); + 2 -> skip_length_delimited_sdl_v4_info(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, TrUserData); + 3 -> skip_group_sdl_v4_info(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, TrUserData); + 5 -> skip_32_sdl_v4_info(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, TrUserData) + end + end; +dg_read_field_def_sdl_v4_info(<<>>, 0, 0, _, F@_1, F@_2, F@_3, _) -> #sdl_v4_info{port = F@_1, v4 = F@_2, nat_type = F@_3}. + +d_field_sdl_v4_info_port(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, TrUserData) when N < 57 -> d_field_sdl_v4_info_port(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, TrUserData); +d_field_sdl_v4_info_port(<<0:1, X:7, Rest/binary>>, N, Acc, F, _, F@_2, F@_3, TrUserData) -> + {NewFValue, RestF} = {id((X bsl N + Acc) band 4294967295, TrUserData), Rest}, + dfp_read_field_def_sdl_v4_info(RestF, 0, 0, F, NewFValue, F@_2, F@_3, TrUserData). + +d_field_sdl_v4_info_v4(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, TrUserData) when N < 57 -> d_field_sdl_v4_info_v4(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, TrUserData); +d_field_sdl_v4_info_v4(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, _, F@_3, TrUserData) -> + {NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, Bytes2 = binary:copy(Bytes), {id(Bytes2, TrUserData), Rest2} end, + dfp_read_field_def_sdl_v4_info(RestF, 0, 0, F, F@_1, NewFValue, F@_3, TrUserData). + +d_field_sdl_v4_info_nat_type(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, TrUserData) when N < 57 -> d_field_sdl_v4_info_nat_type(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, TrUserData); +d_field_sdl_v4_info_nat_type(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, _, TrUserData) -> + {NewFValue, RestF} = {id((X bsl N + Acc) band 4294967295, TrUserData), Rest}, + dfp_read_field_def_sdl_v4_info(RestF, 0, 0, F, F@_1, F@_2, NewFValue, TrUserData). + +skip_varint_sdl_v4_info(<<1:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> skip_varint_sdl_v4_info(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData); +skip_varint_sdl_v4_info(<<0:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> dfp_read_field_def_sdl_v4_info(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData). + +skip_length_delimited_sdl_v4_info(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, TrUserData) when N < 57 -> skip_length_delimited_sdl_v4_info(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, TrUserData); +skip_length_delimited_sdl_v4_info(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, TrUserData) -> + Length = X bsl N + Acc, + <<_:Length/binary, Rest2/binary>> = Rest, + dfp_read_field_def_sdl_v4_info(Rest2, 0, 0, F, F@_1, F@_2, F@_3, TrUserData). + +skip_group_sdl_v4_info(Bin, _, Z2, FNum, F@_1, F@_2, F@_3, TrUserData) -> + {_, Rest} = read_group(Bin, FNum), + dfp_read_field_def_sdl_v4_info(Rest, 0, Z2, FNum, F@_1, F@_2, F@_3, TrUserData). + +skip_32_sdl_v4_info(<<_:32, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> dfp_read_field_def_sdl_v4_info(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData). + +skip_64_sdl_v4_info(<<_:64, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> dfp_read_field_def_sdl_v4_info(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData). + +decode_msg_sdl_v6_info(Bin, TrUserData) -> dfp_read_field_def_sdl_v6_info(Bin, 0, 0, 0, id(0, TrUserData), id(<<>>, TrUserData), TrUserData). + +dfp_read_field_def_sdl_v6_info(<<8, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> d_field_sdl_v6_info_port(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData); +dfp_read_field_def_sdl_v6_info(<<18, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> d_field_sdl_v6_info_v6(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData); +dfp_read_field_def_sdl_v6_info(<<>>, 0, 0, _, F@_1, F@_2, _) -> #sdl_v6_info{port = F@_1, v6 = F@_2}; +dfp_read_field_def_sdl_v6_info(Other, Z1, Z2, F, F@_1, F@_2, TrUserData) -> dg_read_field_def_sdl_v6_info(Other, Z1, Z2, F, F@_1, F@_2, TrUserData). + +dg_read_field_def_sdl_v6_info(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, TrUserData) when N < 32 - 7 -> dg_read_field_def_sdl_v6_info(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, TrUserData); +dg_read_field_def_sdl_v6_info(<<0:1, X:7, Rest/binary>>, N, Acc, _, F@_1, F@_2, TrUserData) -> + Key = X bsl N + Acc, + case Key of + 8 -> d_field_sdl_v6_info_port(Rest, 0, 0, 0, F@_1, F@_2, TrUserData); + 18 -> d_field_sdl_v6_info_v6(Rest, 0, 0, 0, F@_1, F@_2, TrUserData); + _ -> + case Key band 7 of + 0 -> skip_varint_sdl_v6_info(Rest, 0, 0, Key bsr 3, F@_1, F@_2, TrUserData); + 1 -> skip_64_sdl_v6_info(Rest, 0, 0, Key bsr 3, F@_1, F@_2, TrUserData); + 2 -> skip_length_delimited_sdl_v6_info(Rest, 0, 0, Key bsr 3, F@_1, F@_2, TrUserData); + 3 -> skip_group_sdl_v6_info(Rest, 0, 0, Key bsr 3, F@_1, F@_2, TrUserData); + 5 -> skip_32_sdl_v6_info(Rest, 0, 0, Key bsr 3, F@_1, F@_2, TrUserData) + end + end; +dg_read_field_def_sdl_v6_info(<<>>, 0, 0, _, F@_1, F@_2, _) -> #sdl_v6_info{port = F@_1, v6 = F@_2}. + +d_field_sdl_v6_info_port(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, TrUserData) when N < 57 -> d_field_sdl_v6_info_port(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, TrUserData); +d_field_sdl_v6_info_port(<<0:1, X:7, Rest/binary>>, N, Acc, F, _, F@_2, TrUserData) -> + {NewFValue, RestF} = {id((X bsl N + Acc) band 4294967295, TrUserData), Rest}, + dfp_read_field_def_sdl_v6_info(RestF, 0, 0, F, NewFValue, F@_2, TrUserData). + +d_field_sdl_v6_info_v6(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, TrUserData) when N < 57 -> d_field_sdl_v6_info_v6(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, TrUserData); +d_field_sdl_v6_info_v6(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, _, TrUserData) -> + {NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, Bytes2 = binary:copy(Bytes), {id(Bytes2, TrUserData), Rest2} end, + dfp_read_field_def_sdl_v6_info(RestF, 0, 0, F, F@_1, NewFValue, TrUserData). + +skip_varint_sdl_v6_info(<<1:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> skip_varint_sdl_v6_info(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData); +skip_varint_sdl_v6_info(<<0:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> dfp_read_field_def_sdl_v6_info(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData). + +skip_length_delimited_sdl_v6_info(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, TrUserData) when N < 57 -> skip_length_delimited_sdl_v6_info(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, TrUserData); +skip_length_delimited_sdl_v6_info(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, TrUserData) -> + Length = X bsl N + Acc, + <<_:Length/binary, Rest2/binary>> = Rest, + dfp_read_field_def_sdl_v6_info(Rest2, 0, 0, F, F@_1, F@_2, TrUserData). + +skip_group_sdl_v6_info(Bin, _, Z2, FNum, F@_1, F@_2, TrUserData) -> + {_, Rest} = read_group(Bin, FNum), + dfp_read_field_def_sdl_v6_info(Rest, 0, Z2, FNum, F@_1, F@_2, TrUserData). + +skip_32_sdl_v6_info(<<_:32, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> dfp_read_field_def_sdl_v6_info(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData). + +skip_64_sdl_v6_info(<<_:64, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> dfp_read_field_def_sdl_v6_info(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData). + +decode_msg_sdl_dev_addr(Bin, TrUserData) -> dfp_read_field_def_sdl_dev_addr(Bin, 0, 0, 0, id(0, TrUserData), id(<<>>, TrUserData), id(0, TrUserData), id(0, TrUserData), TrUserData). + +dfp_read_field_def_sdl_dev_addr(<<8, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, TrUserData) -> d_field_sdl_dev_addr_network_id(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, TrUserData); +dfp_read_field_def_sdl_dev_addr(<<18, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, TrUserData) -> d_field_sdl_dev_addr_mac(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, TrUserData); +dfp_read_field_def_sdl_dev_addr(<<24, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, TrUserData) -> d_field_sdl_dev_addr_net_addr(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, TrUserData); +dfp_read_field_def_sdl_dev_addr(<<32, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, TrUserData) -> d_field_sdl_dev_addr_net_bit_len(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, TrUserData); +dfp_read_field_def_sdl_dev_addr(<<>>, 0, 0, _, F@_1, F@_2, F@_3, F@_4, _) -> #sdl_dev_addr{network_id = F@_1, mac = F@_2, net_addr = F@_3, net_bit_len = F@_4}; +dfp_read_field_def_sdl_dev_addr(Other, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, TrUserData) -> dg_read_field_def_sdl_dev_addr(Other, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, TrUserData). + +dg_read_field_def_sdl_dev_addr(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, TrUserData) when N < 32 - 7 -> dg_read_field_def_sdl_dev_addr(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, TrUserData); +dg_read_field_def_sdl_dev_addr(<<0:1, X:7, Rest/binary>>, N, Acc, _, F@_1, F@_2, F@_3, F@_4, TrUserData) -> + Key = X bsl N + Acc, + case Key of + 8 -> d_field_sdl_dev_addr_network_id(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, TrUserData); + 18 -> d_field_sdl_dev_addr_mac(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, TrUserData); + 24 -> d_field_sdl_dev_addr_net_addr(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, TrUserData); + 32 -> d_field_sdl_dev_addr_net_bit_len(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, TrUserData); + _ -> + case Key band 7 of + 0 -> skip_varint_sdl_dev_addr(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, F@_4, TrUserData); + 1 -> skip_64_sdl_dev_addr(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, F@_4, TrUserData); + 2 -> skip_length_delimited_sdl_dev_addr(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, F@_4, TrUserData); + 3 -> skip_group_sdl_dev_addr(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, F@_4, TrUserData); + 5 -> skip_32_sdl_dev_addr(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, F@_4, TrUserData) + end + end; +dg_read_field_def_sdl_dev_addr(<<>>, 0, 0, _, F@_1, F@_2, F@_3, F@_4, _) -> #sdl_dev_addr{network_id = F@_1, mac = F@_2, net_addr = F@_3, net_bit_len = F@_4}. + +d_field_sdl_dev_addr_network_id(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, TrUserData) when N < 57 -> d_field_sdl_dev_addr_network_id(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, TrUserData); +d_field_sdl_dev_addr_network_id(<<0:1, X:7, Rest/binary>>, N, Acc, F, _, F@_2, F@_3, F@_4, TrUserData) -> + {NewFValue, RestF} = {id((X bsl N + Acc) band 4294967295, TrUserData), Rest}, + dfp_read_field_def_sdl_dev_addr(RestF, 0, 0, F, NewFValue, F@_2, F@_3, F@_4, TrUserData). + +d_field_sdl_dev_addr_mac(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, TrUserData) when N < 57 -> d_field_sdl_dev_addr_mac(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, TrUserData); +d_field_sdl_dev_addr_mac(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, _, F@_3, F@_4, TrUserData) -> + {NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, Bytes2 = binary:copy(Bytes), {id(Bytes2, TrUserData), Rest2} end, + dfp_read_field_def_sdl_dev_addr(RestF, 0, 0, F, F@_1, NewFValue, F@_3, F@_4, TrUserData). + +d_field_sdl_dev_addr_net_addr(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, TrUserData) when N < 57 -> d_field_sdl_dev_addr_net_addr(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, TrUserData); +d_field_sdl_dev_addr_net_addr(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, _, F@_4, TrUserData) -> + {NewFValue, RestF} = {id((X bsl N + Acc) band 4294967295, TrUserData), Rest}, + dfp_read_field_def_sdl_dev_addr(RestF, 0, 0, F, F@_1, F@_2, NewFValue, F@_4, TrUserData). + +d_field_sdl_dev_addr_net_bit_len(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, TrUserData) when N < 57 -> d_field_sdl_dev_addr_net_bit_len(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, TrUserData); +d_field_sdl_dev_addr_net_bit_len(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, _, TrUserData) -> + {NewFValue, RestF} = {id((X bsl N + Acc) band 4294967295, TrUserData), Rest}, + dfp_read_field_def_sdl_dev_addr(RestF, 0, 0, F, F@_1, F@_2, F@_3, NewFValue, TrUserData). + +skip_varint_sdl_dev_addr(<<1:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, TrUserData) -> skip_varint_sdl_dev_addr(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, TrUserData); +skip_varint_sdl_dev_addr(<<0:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, TrUserData) -> dfp_read_field_def_sdl_dev_addr(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, TrUserData). + +skip_length_delimited_sdl_dev_addr(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, TrUserData) when N < 57 -> skip_length_delimited_sdl_dev_addr(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, TrUserData); +skip_length_delimited_sdl_dev_addr(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, TrUserData) -> + Length = X bsl N + Acc, + <<_:Length/binary, Rest2/binary>> = Rest, + dfp_read_field_def_sdl_dev_addr(Rest2, 0, 0, F, F@_1, F@_2, F@_3, F@_4, TrUserData). + +skip_group_sdl_dev_addr(Bin, _, Z2, FNum, F@_1, F@_2, F@_3, F@_4, TrUserData) -> + {_, Rest} = read_group(Bin, FNum), + dfp_read_field_def_sdl_dev_addr(Rest, 0, Z2, FNum, F@_1, F@_2, F@_3, F@_4, TrUserData). + +skip_32_sdl_dev_addr(<<_:32, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, TrUserData) -> dfp_read_field_def_sdl_dev_addr(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, TrUserData). + +skip_64_sdl_dev_addr(<<_:64, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, TrUserData) -> dfp_read_field_def_sdl_dev_addr(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, TrUserData). + +decode_msg_sdl_empty(Bin, TrUserData) -> dfp_read_field_def_sdl_empty(Bin, 0, 0, 0, TrUserData). + +dfp_read_field_def_sdl_empty(<<>>, 0, 0, _, _) -> #sdl_empty{}; +dfp_read_field_def_sdl_empty(Other, Z1, Z2, F, TrUserData) -> dg_read_field_def_sdl_empty(Other, Z1, Z2, F, TrUserData). + +dg_read_field_def_sdl_empty(<<1:1, X:7, Rest/binary>>, N, Acc, F, TrUserData) when N < 32 - 7 -> dg_read_field_def_sdl_empty(Rest, N + 7, X bsl N + Acc, F, TrUserData); +dg_read_field_def_sdl_empty(<<0:1, X:7, Rest/binary>>, N, Acc, _, TrUserData) -> + Key = X bsl N + Acc, + case Key band 7 of + 0 -> skip_varint_sdl_empty(Rest, 0, 0, Key bsr 3, TrUserData); + 1 -> skip_64_sdl_empty(Rest, 0, 0, Key bsr 3, TrUserData); + 2 -> skip_length_delimited_sdl_empty(Rest, 0, 0, Key bsr 3, TrUserData); + 3 -> skip_group_sdl_empty(Rest, 0, 0, Key bsr 3, TrUserData); + 5 -> skip_32_sdl_empty(Rest, 0, 0, Key bsr 3, TrUserData) + end; +dg_read_field_def_sdl_empty(<<>>, 0, 0, _, _) -> #sdl_empty{}. + +skip_varint_sdl_empty(<<1:1, _:7, Rest/binary>>, Z1, Z2, F, TrUserData) -> skip_varint_sdl_empty(Rest, Z1, Z2, F, TrUserData); +skip_varint_sdl_empty(<<0:1, _:7, Rest/binary>>, Z1, Z2, F, TrUserData) -> dfp_read_field_def_sdl_empty(Rest, Z1, Z2, F, TrUserData). + +skip_length_delimited_sdl_empty(<<1:1, X:7, Rest/binary>>, N, Acc, F, TrUserData) when N < 57 -> skip_length_delimited_sdl_empty(Rest, N + 7, X bsl N + Acc, F, TrUserData); +skip_length_delimited_sdl_empty(<<0:1, X:7, Rest/binary>>, N, Acc, F, TrUserData) -> + Length = X bsl N + Acc, + <<_:Length/binary, Rest2/binary>> = Rest, + dfp_read_field_def_sdl_empty(Rest2, 0, 0, F, TrUserData). + +skip_group_sdl_empty(Bin, _, Z2, FNum, TrUserData) -> + {_, Rest} = read_group(Bin, FNum), + dfp_read_field_def_sdl_empty(Rest, 0, Z2, FNum, TrUserData). + +skip_32_sdl_empty(<<_:32, Rest/binary>>, Z1, Z2, F, TrUserData) -> dfp_read_field_def_sdl_empty(Rest, Z1, Z2, F, TrUserData). + +skip_64_sdl_empty(<<_:64, Rest/binary>>, Z1, Z2, F, TrUserData) -> dfp_read_field_def_sdl_empty(Rest, Z1, Z2, F, TrUserData). + +decode_msg_sdl_register_super(Bin, TrUserData) -> dfp_read_field_def_sdl_register_super(Bin, 0, 0, 0, id(0, TrUserData), id(<<>>, TrUserData), id(<<>>, TrUserData), id(undefined, TrUserData), id(<<>>, TrUserData), id(<<>>, TrUserData), TrUserData). + +dfp_read_field_def_sdl_register_super(<<8, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData) -> d_field_sdl_register_super_version(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData); +dfp_read_field_def_sdl_register_super(<<18, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData) -> d_field_sdl_register_super_installed_channel(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData); +dfp_read_field_def_sdl_register_super(<<26, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData) -> d_field_sdl_register_super_client_id(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData); +dfp_read_field_def_sdl_register_super(<<34, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData) -> d_field_sdl_register_super_dev_addr(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData); +dfp_read_field_def_sdl_register_super(<<42, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData) -> d_field_sdl_register_super_pub_key(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData); +dfp_read_field_def_sdl_register_super(<<50, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData) -> d_field_sdl_register_super_token(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData); +dfp_read_field_def_sdl_register_super(<<>>, 0, 0, _, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, _) -> #sdl_register_super{version = F@_1, installed_channel = F@_2, client_id = F@_3, dev_addr = F@_4, pub_key = F@_5, token = F@_6}; +dfp_read_field_def_sdl_register_super(Other, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData) -> dg_read_field_def_sdl_register_super(Other, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData). + +dg_read_field_def_sdl_register_super(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData) when N < 32 - 7 -> + dg_read_field_def_sdl_register_super(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData); +dg_read_field_def_sdl_register_super(<<0:1, X:7, Rest/binary>>, N, Acc, _, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData) -> + Key = X bsl N + Acc, + case Key of + 8 -> d_field_sdl_register_super_version(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData); + 18 -> d_field_sdl_register_super_installed_channel(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData); + 26 -> d_field_sdl_register_super_client_id(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData); + 34 -> d_field_sdl_register_super_dev_addr(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData); + 42 -> d_field_sdl_register_super_pub_key(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData); + 50 -> d_field_sdl_register_super_token(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData); + _ -> + case Key band 7 of + 0 -> skip_varint_sdl_register_super(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData); + 1 -> skip_64_sdl_register_super(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData); + 2 -> skip_length_delimited_sdl_register_super(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData); + 3 -> skip_group_sdl_register_super(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData); + 5 -> skip_32_sdl_register_super(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData) + end + end; +dg_read_field_def_sdl_register_super(<<>>, 0, 0, _, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, _) -> #sdl_register_super{version = F@_1, installed_channel = F@_2, client_id = F@_3, dev_addr = F@_4, pub_key = F@_5, token = F@_6}. + +d_field_sdl_register_super_version(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData) when N < 57 -> d_field_sdl_register_super_version(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData); +d_field_sdl_register_super_version(<<0:1, X:7, Rest/binary>>, N, Acc, F, _, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData) -> + {NewFValue, RestF} = {id((X bsl N + Acc) band 4294967295, TrUserData), Rest}, + dfp_read_field_def_sdl_register_super(RestF, 0, 0, F, NewFValue, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData). + +d_field_sdl_register_super_installed_channel(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData) when N < 57 -> + d_field_sdl_register_super_installed_channel(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData); +d_field_sdl_register_super_installed_channel(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, _, F@_3, F@_4, F@_5, F@_6, TrUserData) -> + {NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, Bytes2 = binary:copy(Bytes), {id(Bytes2, TrUserData), Rest2} end, + dfp_read_field_def_sdl_register_super(RestF, 0, 0, F, F@_1, NewFValue, F@_3, F@_4, F@_5, F@_6, TrUserData). + +d_field_sdl_register_super_client_id(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData) when N < 57 -> + d_field_sdl_register_super_client_id(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData); +d_field_sdl_register_super_client_id(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, _, F@_4, F@_5, F@_6, TrUserData) -> + {NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, Bytes2 = binary:copy(Bytes), {id(Bytes2, TrUserData), Rest2} end, + dfp_read_field_def_sdl_register_super(RestF, 0, 0, F, F@_1, F@_2, NewFValue, F@_4, F@_5, F@_6, TrUserData). + +d_field_sdl_register_super_dev_addr(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData) when N < 57 -> + d_field_sdl_register_super_dev_addr(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData); +d_field_sdl_register_super_dev_addr(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, Prev, F@_5, F@_6, TrUserData) -> + {NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, {id(decode_msg_sdl_dev_addr(Bs, TrUserData), TrUserData), Rest2} end, + dfp_read_field_def_sdl_register_super(RestF, + 0, + 0, + F, + F@_1, + F@_2, + F@_3, + if Prev == undefined -> NewFValue; + true -> merge_msg_sdl_dev_addr(Prev, NewFValue, TrUserData) + end, + F@_5, + F@_6, + TrUserData). + +d_field_sdl_register_super_pub_key(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData) when N < 57 -> d_field_sdl_register_super_pub_key(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData); +d_field_sdl_register_super_pub_key(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, _, F@_6, TrUserData) -> + {NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, Bytes2 = binary:copy(Bytes), {id(Bytes2, TrUserData), Rest2} end, + dfp_read_field_def_sdl_register_super(RestF, 0, 0, F, F@_1, F@_2, F@_3, F@_4, NewFValue, F@_6, TrUserData). + +d_field_sdl_register_super_token(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData) when N < 57 -> d_field_sdl_register_super_token(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData); +d_field_sdl_register_super_token(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, _, TrUserData) -> + {NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, Bytes2 = binary:copy(Bytes), {id(Bytes2, TrUserData), Rest2} end, + dfp_read_field_def_sdl_register_super(RestF, 0, 0, F, F@_1, F@_2, F@_3, F@_4, F@_5, NewFValue, TrUserData). + +skip_varint_sdl_register_super(<<1:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData) -> skip_varint_sdl_register_super(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData); +skip_varint_sdl_register_super(<<0:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData) -> dfp_read_field_def_sdl_register_super(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData). + +skip_length_delimited_sdl_register_super(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData) when N < 57 -> + skip_length_delimited_sdl_register_super(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData); +skip_length_delimited_sdl_register_super(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData) -> + Length = X bsl N + Acc, + <<_:Length/binary, Rest2/binary>> = Rest, + dfp_read_field_def_sdl_register_super(Rest2, 0, 0, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData). + +skip_group_sdl_register_super(Bin, _, Z2, FNum, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData) -> + {_, Rest} = read_group(Bin, FNum), + dfp_read_field_def_sdl_register_super(Rest, 0, Z2, FNum, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData). + +skip_32_sdl_register_super(<<_:32, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData) -> dfp_read_field_def_sdl_register_super(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData). + +skip_64_sdl_register_super(<<_:64, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData) -> dfp_read_field_def_sdl_register_super(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData). + +decode_msg_sdl_register_super_ack(Bin, TrUserData) -> dfp_read_field_def_sdl_register_super_ack(Bin, 0, 0, 0, id(undefined, TrUserData), id(<<>>, TrUserData), id(0, TrUserData), id(undefined, TrUserData), id(undefined, TrUserData), TrUserData). + +dfp_read_field_def_sdl_register_super_ack(<<10, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) -> d_field_sdl_register_super_ack_dev_addr(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); +dfp_read_field_def_sdl_register_super_ack(<<18, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) -> d_field_sdl_register_super_ack_aes_key(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); +dfp_read_field_def_sdl_register_super_ack(<<24, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) -> d_field_sdl_register_super_ack_upgrade_type(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); +dfp_read_field_def_sdl_register_super_ack(<<34, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) -> d_field_sdl_register_super_ack_upgrade_prompt(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); +dfp_read_field_def_sdl_register_super_ack(<<42, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) -> d_field_sdl_register_super_ack_upgrade_address(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); +dfp_read_field_def_sdl_register_super_ack(<<>>, 0, 0, _, F@_1, F@_2, F@_3, F@_4, F@_5, _) -> #sdl_register_super_ack{dev_addr = F@_1, aes_key = F@_2, upgrade_type = F@_3, upgrade_prompt = F@_4, upgrade_address = F@_5}; +dfp_read_field_def_sdl_register_super_ack(Other, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) -> dg_read_field_def_sdl_register_super_ack(Other, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData). + +dg_read_field_def_sdl_register_super_ack(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) when N < 32 - 7 -> + dg_read_field_def_sdl_register_super_ack(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); +dg_read_field_def_sdl_register_super_ack(<<0:1, X:7, Rest/binary>>, N, Acc, _, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) -> + Key = X bsl N + Acc, + case Key of + 10 -> d_field_sdl_register_super_ack_dev_addr(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); + 18 -> d_field_sdl_register_super_ack_aes_key(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); + 24 -> d_field_sdl_register_super_ack_upgrade_type(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); + 34 -> d_field_sdl_register_super_ack_upgrade_prompt(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); + 42 -> d_field_sdl_register_super_ack_upgrade_address(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); + _ -> + case Key band 7 of + 0 -> skip_varint_sdl_register_super_ack(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); + 1 -> skip_64_sdl_register_super_ack(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); + 2 -> skip_length_delimited_sdl_register_super_ack(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); + 3 -> skip_group_sdl_register_super_ack(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); + 5 -> skip_32_sdl_register_super_ack(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) + end + end; +dg_read_field_def_sdl_register_super_ack(<<>>, 0, 0, _, F@_1, F@_2, F@_3, F@_4, F@_5, _) -> #sdl_register_super_ack{dev_addr = F@_1, aes_key = F@_2, upgrade_type = F@_3, upgrade_prompt = F@_4, upgrade_address = F@_5}. + +d_field_sdl_register_super_ack_dev_addr(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) when N < 57 -> d_field_sdl_register_super_ack_dev_addr(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); +d_field_sdl_register_super_ack_dev_addr(<<0:1, X:7, Rest/binary>>, N, Acc, F, Prev, F@_2, F@_3, F@_4, F@_5, TrUserData) -> + {NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, {id(decode_msg_sdl_dev_addr(Bs, TrUserData), TrUserData), Rest2} end, + dfp_read_field_def_sdl_register_super_ack(RestF, + 0, + 0, + F, + if Prev == undefined -> NewFValue; + true -> merge_msg_sdl_dev_addr(Prev, NewFValue, TrUserData) + end, + F@_2, + F@_3, + F@_4, + F@_5, + TrUserData). + +d_field_sdl_register_super_ack_aes_key(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) when N < 57 -> d_field_sdl_register_super_ack_aes_key(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); +d_field_sdl_register_super_ack_aes_key(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, _, F@_3, F@_4, F@_5, TrUserData) -> + {NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, Bytes2 = binary:copy(Bytes), {id(Bytes2, TrUserData), Rest2} end, + dfp_read_field_def_sdl_register_super_ack(RestF, 0, 0, F, F@_1, NewFValue, F@_3, F@_4, F@_5, TrUserData). + +d_field_sdl_register_super_ack_upgrade_type(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) when N < 57 -> + d_field_sdl_register_super_ack_upgrade_type(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); +d_field_sdl_register_super_ack_upgrade_type(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, _, F@_4, F@_5, TrUserData) -> + {NewFValue, RestF} = {id((X bsl N + Acc) band 4294967295, TrUserData), Rest}, + dfp_read_field_def_sdl_register_super_ack(RestF, 0, 0, F, F@_1, F@_2, NewFValue, F@_4, F@_5, TrUserData). + +d_field_sdl_register_super_ack_upgrade_prompt(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) when N < 57 -> + d_field_sdl_register_super_ack_upgrade_prompt(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); +d_field_sdl_register_super_ack_upgrade_prompt(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, _, F@_5, TrUserData) -> + {NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, Bytes2 = binary:copy(Bytes), {id(Bytes2, TrUserData), Rest2} end, + dfp_read_field_def_sdl_register_super_ack(RestF, 0, 0, F, F@_1, F@_2, F@_3, NewFValue, F@_5, TrUserData). + +d_field_sdl_register_super_ack_upgrade_address(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) when N < 57 -> + d_field_sdl_register_super_ack_upgrade_address(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); +d_field_sdl_register_super_ack_upgrade_address(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, _, TrUserData) -> + {NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, Bytes2 = binary:copy(Bytes), {id(Bytes2, TrUserData), Rest2} end, + dfp_read_field_def_sdl_register_super_ack(RestF, 0, 0, F, F@_1, F@_2, F@_3, F@_4, NewFValue, TrUserData). + +skip_varint_sdl_register_super_ack(<<1:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) -> skip_varint_sdl_register_super_ack(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); +skip_varint_sdl_register_super_ack(<<0:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) -> dfp_read_field_def_sdl_register_super_ack(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData). + +skip_length_delimited_sdl_register_super_ack(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) when N < 57 -> + skip_length_delimited_sdl_register_super_ack(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); +skip_length_delimited_sdl_register_super_ack(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) -> + Length = X bsl N + Acc, + <<_:Length/binary, Rest2/binary>> = Rest, + dfp_read_field_def_sdl_register_super_ack(Rest2, 0, 0, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData). + +skip_group_sdl_register_super_ack(Bin, _, Z2, FNum, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) -> + {_, Rest} = read_group(Bin, FNum), + dfp_read_field_def_sdl_register_super_ack(Rest, 0, Z2, FNum, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData). + +skip_32_sdl_register_super_ack(<<_:32, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) -> dfp_read_field_def_sdl_register_super_ack(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData). + +skip_64_sdl_register_super_ack(<<_:64, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) -> dfp_read_field_def_sdl_register_super_ack(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData). + +decode_msg_sdl_register_super_nak(Bin, TrUserData) -> dfp_read_field_def_sdl_register_super_nak(Bin, 0, 0, 0, id(0, TrUserData), id(<<>>, TrUserData), TrUserData). + +dfp_read_field_def_sdl_register_super_nak(<<8, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> d_field_sdl_register_super_nak_error_code(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData); +dfp_read_field_def_sdl_register_super_nak(<<18, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> d_field_sdl_register_super_nak_error_message(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData); +dfp_read_field_def_sdl_register_super_nak(<<>>, 0, 0, _, F@_1, F@_2, _) -> #sdl_register_super_nak{error_code = F@_1, error_message = F@_2}; +dfp_read_field_def_sdl_register_super_nak(Other, Z1, Z2, F, F@_1, F@_2, TrUserData) -> dg_read_field_def_sdl_register_super_nak(Other, Z1, Z2, F, F@_1, F@_2, TrUserData). + +dg_read_field_def_sdl_register_super_nak(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, TrUserData) when N < 32 - 7 -> dg_read_field_def_sdl_register_super_nak(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, TrUserData); +dg_read_field_def_sdl_register_super_nak(<<0:1, X:7, Rest/binary>>, N, Acc, _, F@_1, F@_2, TrUserData) -> + Key = X bsl N + Acc, + case Key of + 8 -> d_field_sdl_register_super_nak_error_code(Rest, 0, 0, 0, F@_1, F@_2, TrUserData); + 18 -> d_field_sdl_register_super_nak_error_message(Rest, 0, 0, 0, F@_1, F@_2, TrUserData); + _ -> + case Key band 7 of + 0 -> skip_varint_sdl_register_super_nak(Rest, 0, 0, Key bsr 3, F@_1, F@_2, TrUserData); + 1 -> skip_64_sdl_register_super_nak(Rest, 0, 0, Key bsr 3, F@_1, F@_2, TrUserData); + 2 -> skip_length_delimited_sdl_register_super_nak(Rest, 0, 0, Key bsr 3, F@_1, F@_2, TrUserData); + 3 -> skip_group_sdl_register_super_nak(Rest, 0, 0, Key bsr 3, F@_1, F@_2, TrUserData); + 5 -> skip_32_sdl_register_super_nak(Rest, 0, 0, Key bsr 3, F@_1, F@_2, TrUserData) + end + end; +dg_read_field_def_sdl_register_super_nak(<<>>, 0, 0, _, F@_1, F@_2, _) -> #sdl_register_super_nak{error_code = F@_1, error_message = F@_2}. + +d_field_sdl_register_super_nak_error_code(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, TrUserData) when N < 57 -> d_field_sdl_register_super_nak_error_code(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, TrUserData); +d_field_sdl_register_super_nak_error_code(<<0:1, X:7, Rest/binary>>, N, Acc, F, _, F@_2, TrUserData) -> + {NewFValue, RestF} = {id((X bsl N + Acc) band 4294967295, TrUserData), Rest}, + dfp_read_field_def_sdl_register_super_nak(RestF, 0, 0, F, NewFValue, F@_2, TrUserData). + +d_field_sdl_register_super_nak_error_message(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, TrUserData) when N < 57 -> d_field_sdl_register_super_nak_error_message(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, TrUserData); +d_field_sdl_register_super_nak_error_message(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, _, TrUserData) -> + {NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, Bytes2 = binary:copy(Bytes), {id(Bytes2, TrUserData), Rest2} end, + dfp_read_field_def_sdl_register_super_nak(RestF, 0, 0, F, F@_1, NewFValue, TrUserData). + +skip_varint_sdl_register_super_nak(<<1:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> skip_varint_sdl_register_super_nak(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData); +skip_varint_sdl_register_super_nak(<<0:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> dfp_read_field_def_sdl_register_super_nak(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData). + +skip_length_delimited_sdl_register_super_nak(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, TrUserData) when N < 57 -> skip_length_delimited_sdl_register_super_nak(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, TrUserData); +skip_length_delimited_sdl_register_super_nak(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, TrUserData) -> + Length = X bsl N + Acc, + <<_:Length/binary, Rest2/binary>> = Rest, + dfp_read_field_def_sdl_register_super_nak(Rest2, 0, 0, F, F@_1, F@_2, TrUserData). + +skip_group_sdl_register_super_nak(Bin, _, Z2, FNum, F@_1, F@_2, TrUserData) -> + {_, Rest} = read_group(Bin, FNum), + dfp_read_field_def_sdl_register_super_nak(Rest, 0, Z2, FNum, F@_1, F@_2, TrUserData). + +skip_32_sdl_register_super_nak(<<_:32, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> dfp_read_field_def_sdl_register_super_nak(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData). + +skip_64_sdl_register_super_nak(<<_:64, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> dfp_read_field_def_sdl_register_super_nak(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData). + +decode_msg_sdl_query_info(Bin, TrUserData) -> dfp_read_field_def_sdl_query_info(Bin, 0, 0, 0, id(<<>>, TrUserData), TrUserData). + +dfp_read_field_def_sdl_query_info(<<10, Rest/binary>>, Z1, Z2, F, F@_1, TrUserData) -> d_field_sdl_query_info_dst_mac(Rest, Z1, Z2, F, F@_1, TrUserData); +dfp_read_field_def_sdl_query_info(<<>>, 0, 0, _, F@_1, _) -> #sdl_query_info{dst_mac = F@_1}; +dfp_read_field_def_sdl_query_info(Other, Z1, Z2, F, F@_1, TrUserData) -> dg_read_field_def_sdl_query_info(Other, Z1, Z2, F, F@_1, TrUserData). + +dg_read_field_def_sdl_query_info(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, TrUserData) when N < 32 - 7 -> dg_read_field_def_sdl_query_info(Rest, N + 7, X bsl N + Acc, F, F@_1, TrUserData); +dg_read_field_def_sdl_query_info(<<0:1, X:7, Rest/binary>>, N, Acc, _, F@_1, TrUserData) -> + Key = X bsl N + Acc, + case Key of + 10 -> d_field_sdl_query_info_dst_mac(Rest, 0, 0, 0, F@_1, TrUserData); + _ -> + case Key band 7 of + 0 -> skip_varint_sdl_query_info(Rest, 0, 0, Key bsr 3, F@_1, TrUserData); + 1 -> skip_64_sdl_query_info(Rest, 0, 0, Key bsr 3, F@_1, TrUserData); + 2 -> skip_length_delimited_sdl_query_info(Rest, 0, 0, Key bsr 3, F@_1, TrUserData); + 3 -> skip_group_sdl_query_info(Rest, 0, 0, Key bsr 3, F@_1, TrUserData); + 5 -> skip_32_sdl_query_info(Rest, 0, 0, Key bsr 3, F@_1, TrUserData) + end + end; +dg_read_field_def_sdl_query_info(<<>>, 0, 0, _, F@_1, _) -> #sdl_query_info{dst_mac = F@_1}. + +d_field_sdl_query_info_dst_mac(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, TrUserData) when N < 57 -> d_field_sdl_query_info_dst_mac(Rest, N + 7, X bsl N + Acc, F, F@_1, TrUserData); +d_field_sdl_query_info_dst_mac(<<0:1, X:7, Rest/binary>>, N, Acc, F, _, TrUserData) -> + {NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, Bytes2 = binary:copy(Bytes), {id(Bytes2, TrUserData), Rest2} end, + dfp_read_field_def_sdl_query_info(RestF, 0, 0, F, NewFValue, TrUserData). + +skip_varint_sdl_query_info(<<1:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, TrUserData) -> skip_varint_sdl_query_info(Rest, Z1, Z2, F, F@_1, TrUserData); +skip_varint_sdl_query_info(<<0:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, TrUserData) -> dfp_read_field_def_sdl_query_info(Rest, Z1, Z2, F, F@_1, TrUserData). + +skip_length_delimited_sdl_query_info(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, TrUserData) when N < 57 -> skip_length_delimited_sdl_query_info(Rest, N + 7, X bsl N + Acc, F, F@_1, TrUserData); +skip_length_delimited_sdl_query_info(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, TrUserData) -> + Length = X bsl N + Acc, + <<_:Length/binary, Rest2/binary>> = Rest, + dfp_read_field_def_sdl_query_info(Rest2, 0, 0, F, F@_1, TrUserData). + +skip_group_sdl_query_info(Bin, _, Z2, FNum, F@_1, TrUserData) -> + {_, Rest} = read_group(Bin, FNum), + dfp_read_field_def_sdl_query_info(Rest, 0, Z2, FNum, F@_1, TrUserData). + +skip_32_sdl_query_info(<<_:32, Rest/binary>>, Z1, Z2, F, F@_1, TrUserData) -> dfp_read_field_def_sdl_query_info(Rest, Z1, Z2, F, F@_1, TrUserData). + +skip_64_sdl_query_info(<<_:64, Rest/binary>>, Z1, Z2, F, F@_1, TrUserData) -> dfp_read_field_def_sdl_query_info(Rest, Z1, Z2, F, F@_1, TrUserData). + +decode_msg_sdl_peer_info(Bin, TrUserData) -> dfp_read_field_def_sdl_peer_info(Bin, 0, 0, 0, id(<<>>, TrUserData), id(undefined, TrUserData), id(undefined, TrUserData), TrUserData). + +dfp_read_field_def_sdl_peer_info(<<10, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> d_field_sdl_peer_info_dst_mac(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData); +dfp_read_field_def_sdl_peer_info(<<18, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> d_field_sdl_peer_info_v4_info(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData); +dfp_read_field_def_sdl_peer_info(<<26, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> d_field_sdl_peer_info_v6_info(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData); +dfp_read_field_def_sdl_peer_info(<<>>, 0, 0, _, F@_1, F@_2, F@_3, _) -> #sdl_peer_info{dst_mac = F@_1, v4_info = F@_2, v6_info = F@_3}; +dfp_read_field_def_sdl_peer_info(Other, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> dg_read_field_def_sdl_peer_info(Other, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData). + +dg_read_field_def_sdl_peer_info(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, TrUserData) when N < 32 - 7 -> dg_read_field_def_sdl_peer_info(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, TrUserData); +dg_read_field_def_sdl_peer_info(<<0:1, X:7, Rest/binary>>, N, Acc, _, F@_1, F@_2, F@_3, TrUserData) -> + Key = X bsl N + Acc, + case Key of + 10 -> d_field_sdl_peer_info_dst_mac(Rest, 0, 0, 0, F@_1, F@_2, F@_3, TrUserData); + 18 -> d_field_sdl_peer_info_v4_info(Rest, 0, 0, 0, F@_1, F@_2, F@_3, TrUserData); + 26 -> d_field_sdl_peer_info_v6_info(Rest, 0, 0, 0, F@_1, F@_2, F@_3, TrUserData); + _ -> + case Key band 7 of + 0 -> skip_varint_sdl_peer_info(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, TrUserData); + 1 -> skip_64_sdl_peer_info(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, TrUserData); + 2 -> skip_length_delimited_sdl_peer_info(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, TrUserData); + 3 -> skip_group_sdl_peer_info(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, TrUserData); + 5 -> skip_32_sdl_peer_info(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, TrUserData) + end + end; +dg_read_field_def_sdl_peer_info(<<>>, 0, 0, _, F@_1, F@_2, F@_3, _) -> #sdl_peer_info{dst_mac = F@_1, v4_info = F@_2, v6_info = F@_3}. + +d_field_sdl_peer_info_dst_mac(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, TrUserData) when N < 57 -> d_field_sdl_peer_info_dst_mac(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, TrUserData); +d_field_sdl_peer_info_dst_mac(<<0:1, X:7, Rest/binary>>, N, Acc, F, _, F@_2, F@_3, TrUserData) -> + {NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, Bytes2 = binary:copy(Bytes), {id(Bytes2, TrUserData), Rest2} end, + dfp_read_field_def_sdl_peer_info(RestF, 0, 0, F, NewFValue, F@_2, F@_3, TrUserData). + +d_field_sdl_peer_info_v4_info(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, TrUserData) when N < 57 -> d_field_sdl_peer_info_v4_info(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, TrUserData); +d_field_sdl_peer_info_v4_info(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, Prev, F@_3, TrUserData) -> + {NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, {id(decode_msg_sdl_v4_info(Bs, TrUserData), TrUserData), Rest2} end, + dfp_read_field_def_sdl_peer_info(RestF, + 0, + 0, + F, + F@_1, + if Prev == undefined -> NewFValue; + true -> merge_msg_sdl_v4_info(Prev, NewFValue, TrUserData) + end, + F@_3, + TrUserData). + +d_field_sdl_peer_info_v6_info(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, TrUserData) when N < 57 -> d_field_sdl_peer_info_v6_info(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, TrUserData); +d_field_sdl_peer_info_v6_info(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, Prev, TrUserData) -> + {NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, {id(decode_msg_sdl_v6_info(Bs, TrUserData), TrUserData), Rest2} end, + dfp_read_field_def_sdl_peer_info(RestF, + 0, + 0, + F, + F@_1, + F@_2, + if Prev == undefined -> NewFValue; + true -> merge_msg_sdl_v6_info(Prev, NewFValue, TrUserData) + end, + TrUserData). + +skip_varint_sdl_peer_info(<<1:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> skip_varint_sdl_peer_info(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData); +skip_varint_sdl_peer_info(<<0:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> dfp_read_field_def_sdl_peer_info(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData). + +skip_length_delimited_sdl_peer_info(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, TrUserData) when N < 57 -> skip_length_delimited_sdl_peer_info(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, TrUserData); +skip_length_delimited_sdl_peer_info(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, TrUserData) -> + Length = X bsl N + Acc, + <<_:Length/binary, Rest2/binary>> = Rest, + dfp_read_field_def_sdl_peer_info(Rest2, 0, 0, F, F@_1, F@_2, F@_3, TrUserData). + +skip_group_sdl_peer_info(Bin, _, Z2, FNum, F@_1, F@_2, F@_3, TrUserData) -> + {_, Rest} = read_group(Bin, FNum), + dfp_read_field_def_sdl_peer_info(Rest, 0, Z2, FNum, F@_1, F@_2, F@_3, TrUserData). + +skip_32_sdl_peer_info(<<_:32, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> dfp_read_field_def_sdl_peer_info(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData). + +skip_64_sdl_peer_info(<<_:64, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> dfp_read_field_def_sdl_peer_info(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData). + +decode_msg_sdl_nat_changed_event(Bin, TrUserData) -> dfp_read_field_def_sdl_nat_changed_event(Bin, 0, 0, 0, id(<<>>, TrUserData), id(0, TrUserData), TrUserData). + +dfp_read_field_def_sdl_nat_changed_event(<<10, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> d_field_sdl_nat_changed_event_mac(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData); +dfp_read_field_def_sdl_nat_changed_event(<<16, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> d_field_sdl_nat_changed_event_ip(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData); +dfp_read_field_def_sdl_nat_changed_event(<<>>, 0, 0, _, F@_1, F@_2, _) -> #sdl_nat_changed_event{mac = F@_1, ip = F@_2}; +dfp_read_field_def_sdl_nat_changed_event(Other, Z1, Z2, F, F@_1, F@_2, TrUserData) -> dg_read_field_def_sdl_nat_changed_event(Other, Z1, Z2, F, F@_1, F@_2, TrUserData). + +dg_read_field_def_sdl_nat_changed_event(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, TrUserData) when N < 32 - 7 -> dg_read_field_def_sdl_nat_changed_event(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, TrUserData); +dg_read_field_def_sdl_nat_changed_event(<<0:1, X:7, Rest/binary>>, N, Acc, _, F@_1, F@_2, TrUserData) -> + Key = X bsl N + Acc, + case Key of + 10 -> d_field_sdl_nat_changed_event_mac(Rest, 0, 0, 0, F@_1, F@_2, TrUserData); + 16 -> d_field_sdl_nat_changed_event_ip(Rest, 0, 0, 0, F@_1, F@_2, TrUserData); + _ -> + case Key band 7 of + 0 -> skip_varint_sdl_nat_changed_event(Rest, 0, 0, Key bsr 3, F@_1, F@_2, TrUserData); + 1 -> skip_64_sdl_nat_changed_event(Rest, 0, 0, Key bsr 3, F@_1, F@_2, TrUserData); + 2 -> skip_length_delimited_sdl_nat_changed_event(Rest, 0, 0, Key bsr 3, F@_1, F@_2, TrUserData); + 3 -> skip_group_sdl_nat_changed_event(Rest, 0, 0, Key bsr 3, F@_1, F@_2, TrUserData); + 5 -> skip_32_sdl_nat_changed_event(Rest, 0, 0, Key bsr 3, F@_1, F@_2, TrUserData) + end + end; +dg_read_field_def_sdl_nat_changed_event(<<>>, 0, 0, _, F@_1, F@_2, _) -> #sdl_nat_changed_event{mac = F@_1, ip = F@_2}. + +d_field_sdl_nat_changed_event_mac(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, TrUserData) when N < 57 -> d_field_sdl_nat_changed_event_mac(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, TrUserData); +d_field_sdl_nat_changed_event_mac(<<0:1, X:7, Rest/binary>>, N, Acc, F, _, F@_2, TrUserData) -> + {NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, Bytes2 = binary:copy(Bytes), {id(Bytes2, TrUserData), Rest2} end, + dfp_read_field_def_sdl_nat_changed_event(RestF, 0, 0, F, NewFValue, F@_2, TrUserData). + +d_field_sdl_nat_changed_event_ip(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, TrUserData) when N < 57 -> d_field_sdl_nat_changed_event_ip(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, TrUserData); +d_field_sdl_nat_changed_event_ip(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, _, TrUserData) -> + {NewFValue, RestF} = {id((X bsl N + Acc) band 4294967295, TrUserData), Rest}, + dfp_read_field_def_sdl_nat_changed_event(RestF, 0, 0, F, F@_1, NewFValue, TrUserData). + +skip_varint_sdl_nat_changed_event(<<1:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> skip_varint_sdl_nat_changed_event(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData); +skip_varint_sdl_nat_changed_event(<<0:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> dfp_read_field_def_sdl_nat_changed_event(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData). + +skip_length_delimited_sdl_nat_changed_event(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, TrUserData) when N < 57 -> skip_length_delimited_sdl_nat_changed_event(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, TrUserData); +skip_length_delimited_sdl_nat_changed_event(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, TrUserData) -> + Length = X bsl N + Acc, + <<_:Length/binary, Rest2/binary>> = Rest, + dfp_read_field_def_sdl_nat_changed_event(Rest2, 0, 0, F, F@_1, F@_2, TrUserData). + +skip_group_sdl_nat_changed_event(Bin, _, Z2, FNum, F@_1, F@_2, TrUserData) -> + {_, Rest} = read_group(Bin, FNum), + dfp_read_field_def_sdl_nat_changed_event(Rest, 0, Z2, FNum, F@_1, F@_2, TrUserData). + +skip_32_sdl_nat_changed_event(<<_:32, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> dfp_read_field_def_sdl_nat_changed_event(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData). + +skip_64_sdl_nat_changed_event(<<_:64, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> dfp_read_field_def_sdl_nat_changed_event(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData). + +decode_msg_sdl_send_register_event(Bin, TrUserData) -> dfp_read_field_def_sdl_send_register_event(Bin, 0, 0, 0, id(<<>>, TrUserData), id(0, TrUserData), id(0, TrUserData), id(0, TrUserData), id(undefined, TrUserData), TrUserData). + +dfp_read_field_def_sdl_send_register_event(<<10, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) -> d_field_sdl_send_register_event_dst_mac(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); +dfp_read_field_def_sdl_send_register_event(<<16, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) -> d_field_sdl_send_register_event_nat_ip(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); +dfp_read_field_def_sdl_send_register_event(<<24, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) -> d_field_sdl_send_register_event_nat_port(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); +dfp_read_field_def_sdl_send_register_event(<<32, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) -> d_field_sdl_send_register_event_nat_type(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); +dfp_read_field_def_sdl_send_register_event(<<42, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) -> d_field_sdl_send_register_event_v6_info(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); +dfp_read_field_def_sdl_send_register_event(<<>>, 0, 0, _, F@_1, F@_2, F@_3, F@_4, F@_5, _) -> #sdl_send_register_event{dst_mac = F@_1, nat_ip = F@_2, nat_port = F@_3, nat_type = F@_4, v6_info = F@_5}; +dfp_read_field_def_sdl_send_register_event(Other, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) -> dg_read_field_def_sdl_send_register_event(Other, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData). + +dg_read_field_def_sdl_send_register_event(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) when N < 32 - 7 -> + dg_read_field_def_sdl_send_register_event(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); +dg_read_field_def_sdl_send_register_event(<<0:1, X:7, Rest/binary>>, N, Acc, _, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) -> + Key = X bsl N + Acc, + case Key of + 10 -> d_field_sdl_send_register_event_dst_mac(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); + 16 -> d_field_sdl_send_register_event_nat_ip(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); + 24 -> d_field_sdl_send_register_event_nat_port(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); + 32 -> d_field_sdl_send_register_event_nat_type(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); + 42 -> d_field_sdl_send_register_event_v6_info(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); + _ -> + case Key band 7 of + 0 -> skip_varint_sdl_send_register_event(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); + 1 -> skip_64_sdl_send_register_event(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); + 2 -> skip_length_delimited_sdl_send_register_event(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); + 3 -> skip_group_sdl_send_register_event(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); + 5 -> skip_32_sdl_send_register_event(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) + end + end; +dg_read_field_def_sdl_send_register_event(<<>>, 0, 0, _, F@_1, F@_2, F@_3, F@_4, F@_5, _) -> #sdl_send_register_event{dst_mac = F@_1, nat_ip = F@_2, nat_port = F@_3, nat_type = F@_4, v6_info = F@_5}. + +d_field_sdl_send_register_event_dst_mac(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) when N < 57 -> d_field_sdl_send_register_event_dst_mac(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); +d_field_sdl_send_register_event_dst_mac(<<0:1, X:7, Rest/binary>>, N, Acc, F, _, F@_2, F@_3, F@_4, F@_5, TrUserData) -> + {NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, Bytes2 = binary:copy(Bytes), {id(Bytes2, TrUserData), Rest2} end, + dfp_read_field_def_sdl_send_register_event(RestF, 0, 0, F, NewFValue, F@_2, F@_3, F@_4, F@_5, TrUserData). + +d_field_sdl_send_register_event_nat_ip(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) when N < 57 -> d_field_sdl_send_register_event_nat_ip(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); +d_field_sdl_send_register_event_nat_ip(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, _, F@_3, F@_4, F@_5, TrUserData) -> + {NewFValue, RestF} = {id((X bsl N + Acc) band 4294967295, TrUserData), Rest}, + dfp_read_field_def_sdl_send_register_event(RestF, 0, 0, F, F@_1, NewFValue, F@_3, F@_4, F@_5, TrUserData). + +d_field_sdl_send_register_event_nat_port(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) when N < 57 -> d_field_sdl_send_register_event_nat_port(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); +d_field_sdl_send_register_event_nat_port(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, _, F@_4, F@_5, TrUserData) -> + {NewFValue, RestF} = {id((X bsl N + Acc) band 4294967295, TrUserData), Rest}, + dfp_read_field_def_sdl_send_register_event(RestF, 0, 0, F, F@_1, F@_2, NewFValue, F@_4, F@_5, TrUserData). + +d_field_sdl_send_register_event_nat_type(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) when N < 57 -> d_field_sdl_send_register_event_nat_type(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); +d_field_sdl_send_register_event_nat_type(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, _, F@_5, TrUserData) -> + {NewFValue, RestF} = {id((X bsl N + Acc) band 4294967295, TrUserData), Rest}, + dfp_read_field_def_sdl_send_register_event(RestF, 0, 0, F, F@_1, F@_2, F@_3, NewFValue, F@_5, TrUserData). + +d_field_sdl_send_register_event_v6_info(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) when N < 57 -> d_field_sdl_send_register_event_v6_info(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); +d_field_sdl_send_register_event_v6_info(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, Prev, TrUserData) -> + {NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, {id(decode_msg_sdl_v6_info(Bs, TrUserData), TrUserData), Rest2} end, + dfp_read_field_def_sdl_send_register_event(RestF, + 0, + 0, + F, + F@_1, + F@_2, + F@_3, + F@_4, + if Prev == undefined -> NewFValue; + true -> merge_msg_sdl_v6_info(Prev, NewFValue, TrUserData) + end, + TrUserData). + +skip_varint_sdl_send_register_event(<<1:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) -> skip_varint_sdl_send_register_event(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); +skip_varint_sdl_send_register_event(<<0:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) -> dfp_read_field_def_sdl_send_register_event(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData). + +skip_length_delimited_sdl_send_register_event(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) when N < 57 -> + skip_length_delimited_sdl_send_register_event(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData); +skip_length_delimited_sdl_send_register_event(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) -> + Length = X bsl N + Acc, + <<_:Length/binary, Rest2/binary>> = Rest, + dfp_read_field_def_sdl_send_register_event(Rest2, 0, 0, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData). + +skip_group_sdl_send_register_event(Bin, _, Z2, FNum, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) -> + {_, Rest} = read_group(Bin, FNum), + dfp_read_field_def_sdl_send_register_event(Rest, 0, Z2, FNum, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData). + +skip_32_sdl_send_register_event(<<_:32, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) -> dfp_read_field_def_sdl_send_register_event(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData). + +skip_64_sdl_send_register_event(<<_:64, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData) -> dfp_read_field_def_sdl_send_register_event(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, TrUserData). + +decode_msg_sdl_network_shutdown_event(Bin, TrUserData) -> dfp_read_field_def_sdl_network_shutdown_event(Bin, 0, 0, 0, id(<<>>, TrUserData), TrUserData). + +dfp_read_field_def_sdl_network_shutdown_event(<<10, Rest/binary>>, Z1, Z2, F, F@_1, TrUserData) -> d_field_sdl_network_shutdown_event_message(Rest, Z1, Z2, F, F@_1, TrUserData); +dfp_read_field_def_sdl_network_shutdown_event(<<>>, 0, 0, _, F@_1, _) -> #sdl_network_shutdown_event{message = F@_1}; +dfp_read_field_def_sdl_network_shutdown_event(Other, Z1, Z2, F, F@_1, TrUserData) -> dg_read_field_def_sdl_network_shutdown_event(Other, Z1, Z2, F, F@_1, TrUserData). + +dg_read_field_def_sdl_network_shutdown_event(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, TrUserData) when N < 32 - 7 -> dg_read_field_def_sdl_network_shutdown_event(Rest, N + 7, X bsl N + Acc, F, F@_1, TrUserData); +dg_read_field_def_sdl_network_shutdown_event(<<0:1, X:7, Rest/binary>>, N, Acc, _, F@_1, TrUserData) -> + Key = X bsl N + Acc, + case Key of + 10 -> d_field_sdl_network_shutdown_event_message(Rest, 0, 0, 0, F@_1, TrUserData); + _ -> + case Key band 7 of + 0 -> skip_varint_sdl_network_shutdown_event(Rest, 0, 0, Key bsr 3, F@_1, TrUserData); + 1 -> skip_64_sdl_network_shutdown_event(Rest, 0, 0, Key bsr 3, F@_1, TrUserData); + 2 -> skip_length_delimited_sdl_network_shutdown_event(Rest, 0, 0, Key bsr 3, F@_1, TrUserData); + 3 -> skip_group_sdl_network_shutdown_event(Rest, 0, 0, Key bsr 3, F@_1, TrUserData); + 5 -> skip_32_sdl_network_shutdown_event(Rest, 0, 0, Key bsr 3, F@_1, TrUserData) + end + end; +dg_read_field_def_sdl_network_shutdown_event(<<>>, 0, 0, _, F@_1, _) -> #sdl_network_shutdown_event{message = F@_1}. + +d_field_sdl_network_shutdown_event_message(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, TrUserData) when N < 57 -> d_field_sdl_network_shutdown_event_message(Rest, N + 7, X bsl N + Acc, F, F@_1, TrUserData); +d_field_sdl_network_shutdown_event_message(<<0:1, X:7, Rest/binary>>, N, Acc, F, _, TrUserData) -> + {NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, Bytes2 = binary:copy(Bytes), {id(Bytes2, TrUserData), Rest2} end, + dfp_read_field_def_sdl_network_shutdown_event(RestF, 0, 0, F, NewFValue, TrUserData). + +skip_varint_sdl_network_shutdown_event(<<1:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, TrUserData) -> skip_varint_sdl_network_shutdown_event(Rest, Z1, Z2, F, F@_1, TrUserData); +skip_varint_sdl_network_shutdown_event(<<0:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, TrUserData) -> dfp_read_field_def_sdl_network_shutdown_event(Rest, Z1, Z2, F, F@_1, TrUserData). + +skip_length_delimited_sdl_network_shutdown_event(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, TrUserData) when N < 57 -> skip_length_delimited_sdl_network_shutdown_event(Rest, N + 7, X bsl N + Acc, F, F@_1, TrUserData); +skip_length_delimited_sdl_network_shutdown_event(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, TrUserData) -> + Length = X bsl N + Acc, + <<_:Length/binary, Rest2/binary>> = Rest, + dfp_read_field_def_sdl_network_shutdown_event(Rest2, 0, 0, F, F@_1, TrUserData). + +skip_group_sdl_network_shutdown_event(Bin, _, Z2, FNum, F@_1, TrUserData) -> + {_, Rest} = read_group(Bin, FNum), + dfp_read_field_def_sdl_network_shutdown_event(Rest, 0, Z2, FNum, F@_1, TrUserData). + +skip_32_sdl_network_shutdown_event(<<_:32, Rest/binary>>, Z1, Z2, F, F@_1, TrUserData) -> dfp_read_field_def_sdl_network_shutdown_event(Rest, Z1, Z2, F, F@_1, TrUserData). + +skip_64_sdl_network_shutdown_event(<<_:64, Rest/binary>>, Z1, Z2, F, F@_1, TrUserData) -> dfp_read_field_def_sdl_network_shutdown_event(Rest, Z1, Z2, F, F@_1, TrUserData). + +decode_msg_sdl_change_network_command(Bin, TrUserData) -> dfp_read_field_def_sdl_change_network_command(Bin, 0, 0, 0, id(undefined, TrUserData), id(<<>>, TrUserData), TrUserData). + +dfp_read_field_def_sdl_change_network_command(<<10, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> d_field_sdl_change_network_command_dev_addr(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData); +dfp_read_field_def_sdl_change_network_command(<<18, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> d_field_sdl_change_network_command_aes_key(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData); +dfp_read_field_def_sdl_change_network_command(<<>>, 0, 0, _, F@_1, F@_2, _) -> #sdl_change_network_command{dev_addr = F@_1, aes_key = F@_2}; +dfp_read_field_def_sdl_change_network_command(Other, Z1, Z2, F, F@_1, F@_2, TrUserData) -> dg_read_field_def_sdl_change_network_command(Other, Z1, Z2, F, F@_1, F@_2, TrUserData). + +dg_read_field_def_sdl_change_network_command(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, TrUserData) when N < 32 - 7 -> dg_read_field_def_sdl_change_network_command(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, TrUserData); +dg_read_field_def_sdl_change_network_command(<<0:1, X:7, Rest/binary>>, N, Acc, _, F@_1, F@_2, TrUserData) -> + Key = X bsl N + Acc, + case Key of + 10 -> d_field_sdl_change_network_command_dev_addr(Rest, 0, 0, 0, F@_1, F@_2, TrUserData); + 18 -> d_field_sdl_change_network_command_aes_key(Rest, 0, 0, 0, F@_1, F@_2, TrUserData); + _ -> + case Key band 7 of + 0 -> skip_varint_sdl_change_network_command(Rest, 0, 0, Key bsr 3, F@_1, F@_2, TrUserData); + 1 -> skip_64_sdl_change_network_command(Rest, 0, 0, Key bsr 3, F@_1, F@_2, TrUserData); + 2 -> skip_length_delimited_sdl_change_network_command(Rest, 0, 0, Key bsr 3, F@_1, F@_2, TrUserData); + 3 -> skip_group_sdl_change_network_command(Rest, 0, 0, Key bsr 3, F@_1, F@_2, TrUserData); + 5 -> skip_32_sdl_change_network_command(Rest, 0, 0, Key bsr 3, F@_1, F@_2, TrUserData) + end + end; +dg_read_field_def_sdl_change_network_command(<<>>, 0, 0, _, F@_1, F@_2, _) -> #sdl_change_network_command{dev_addr = F@_1, aes_key = F@_2}. + +d_field_sdl_change_network_command_dev_addr(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, TrUserData) when N < 57 -> d_field_sdl_change_network_command_dev_addr(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, TrUserData); +d_field_sdl_change_network_command_dev_addr(<<0:1, X:7, Rest/binary>>, N, Acc, F, Prev, F@_2, TrUserData) -> + {NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, {id(decode_msg_sdl_dev_addr(Bs, TrUserData), TrUserData), Rest2} end, + dfp_read_field_def_sdl_change_network_command(RestF, + 0, + 0, + F, + if Prev == undefined -> NewFValue; + true -> merge_msg_sdl_dev_addr(Prev, NewFValue, TrUserData) + end, + F@_2, + TrUserData). + +d_field_sdl_change_network_command_aes_key(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, TrUserData) when N < 57 -> d_field_sdl_change_network_command_aes_key(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, TrUserData); +d_field_sdl_change_network_command_aes_key(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, _, TrUserData) -> + {NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, Bytes2 = binary:copy(Bytes), {id(Bytes2, TrUserData), Rest2} end, + dfp_read_field_def_sdl_change_network_command(RestF, 0, 0, F, F@_1, NewFValue, TrUserData). + +skip_varint_sdl_change_network_command(<<1:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> skip_varint_sdl_change_network_command(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData); +skip_varint_sdl_change_network_command(<<0:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> dfp_read_field_def_sdl_change_network_command(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData). + +skip_length_delimited_sdl_change_network_command(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, TrUserData) when N < 57 -> skip_length_delimited_sdl_change_network_command(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, TrUserData); +skip_length_delimited_sdl_change_network_command(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, TrUserData) -> + Length = X bsl N + Acc, + <<_:Length/binary, Rest2/binary>> = Rest, + dfp_read_field_def_sdl_change_network_command(Rest2, 0, 0, F, F@_1, F@_2, TrUserData). + +skip_group_sdl_change_network_command(Bin, _, Z2, FNum, F@_1, F@_2, TrUserData) -> + {_, Rest} = read_group(Bin, FNum), + dfp_read_field_def_sdl_change_network_command(Rest, 0, Z2, FNum, F@_1, F@_2, TrUserData). + +skip_32_sdl_change_network_command(<<_:32, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> dfp_read_field_def_sdl_change_network_command(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData). + +skip_64_sdl_change_network_command(<<_:64, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> dfp_read_field_def_sdl_change_network_command(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData). + +decode_msg_sdl_command_ack(Bin, TrUserData) -> dfp_read_field_def_sdl_command_ack(Bin, 0, 0, 0, id(false, TrUserData), id(undefined, TrUserData), TrUserData). + +dfp_read_field_def_sdl_command_ack(<<8, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> d_field_sdl_command_ack_status(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData); +dfp_read_field_def_sdl_command_ack(<<18, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> d_field_sdl_command_ack_message(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData); +dfp_read_field_def_sdl_command_ack(<<>>, 0, 0, _, F@_1, F@_2, _) -> #sdl_command_ack{status = F@_1, message = F@_2}; +dfp_read_field_def_sdl_command_ack(Other, Z1, Z2, F, F@_1, F@_2, TrUserData) -> dg_read_field_def_sdl_command_ack(Other, Z1, Z2, F, F@_1, F@_2, TrUserData). + +dg_read_field_def_sdl_command_ack(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, TrUserData) when N < 32 - 7 -> dg_read_field_def_sdl_command_ack(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, TrUserData); +dg_read_field_def_sdl_command_ack(<<0:1, X:7, Rest/binary>>, N, Acc, _, F@_1, F@_2, TrUserData) -> + Key = X bsl N + Acc, + case Key of + 8 -> d_field_sdl_command_ack_status(Rest, 0, 0, 0, F@_1, F@_2, TrUserData); + 18 -> d_field_sdl_command_ack_message(Rest, 0, 0, 0, F@_1, F@_2, TrUserData); + _ -> + case Key band 7 of + 0 -> skip_varint_sdl_command_ack(Rest, 0, 0, Key bsr 3, F@_1, F@_2, TrUserData); + 1 -> skip_64_sdl_command_ack(Rest, 0, 0, Key bsr 3, F@_1, F@_2, TrUserData); + 2 -> skip_length_delimited_sdl_command_ack(Rest, 0, 0, Key bsr 3, F@_1, F@_2, TrUserData); + 3 -> skip_group_sdl_command_ack(Rest, 0, 0, Key bsr 3, F@_1, F@_2, TrUserData); + 5 -> skip_32_sdl_command_ack(Rest, 0, 0, Key bsr 3, F@_1, F@_2, TrUserData) + end + end; +dg_read_field_def_sdl_command_ack(<<>>, 0, 0, _, F@_1, F@_2, _) -> #sdl_command_ack{status = F@_1, message = F@_2}. + +d_field_sdl_command_ack_status(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, TrUserData) when N < 57 -> d_field_sdl_command_ack_status(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, TrUserData); +d_field_sdl_command_ack_status(<<0:1, X:7, Rest/binary>>, N, Acc, F, _, F@_2, TrUserData) -> + {NewFValue, RestF} = {id(X bsl N + Acc =/= 0, TrUserData), Rest}, + dfp_read_field_def_sdl_command_ack(RestF, 0, 0, F, NewFValue, F@_2, TrUserData). + +d_field_sdl_command_ack_message(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, TrUserData) when N < 57 -> d_field_sdl_command_ack_message(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, TrUserData); +d_field_sdl_command_ack_message(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, _, TrUserData) -> + {NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, Bytes2 = binary:copy(Bytes), {id(Bytes2, TrUserData), Rest2} end, + dfp_read_field_def_sdl_command_ack(RestF, 0, 0, F, F@_1, NewFValue, TrUserData). + +skip_varint_sdl_command_ack(<<1:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> skip_varint_sdl_command_ack(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData); +skip_varint_sdl_command_ack(<<0:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> dfp_read_field_def_sdl_command_ack(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData). + +skip_length_delimited_sdl_command_ack(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, TrUserData) when N < 57 -> skip_length_delimited_sdl_command_ack(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, TrUserData); +skip_length_delimited_sdl_command_ack(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, TrUserData) -> + Length = X bsl N + Acc, + <<_:Length/binary, Rest2/binary>> = Rest, + dfp_read_field_def_sdl_command_ack(Rest2, 0, 0, F, F@_1, F@_2, TrUserData). + +skip_group_sdl_command_ack(Bin, _, Z2, FNum, F@_1, F@_2, TrUserData) -> + {_, Rest} = read_group(Bin, FNum), + dfp_read_field_def_sdl_command_ack(Rest, 0, Z2, FNum, F@_1, F@_2, TrUserData). + +skip_32_sdl_command_ack(<<_:32, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> dfp_read_field_def_sdl_command_ack(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData). + +skip_64_sdl_command_ack(<<_:64, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> dfp_read_field_def_sdl_command_ack(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData). + +decode_msg_sdl_flows(Bin, TrUserData) -> dfp_read_field_def_sdl_flows(Bin, 0, 0, 0, id(0, TrUserData), id(0, TrUserData), id(0, TrUserData), TrUserData). + +dfp_read_field_def_sdl_flows(<<8, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> d_field_sdl_flows_forward_num(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData); +dfp_read_field_def_sdl_flows(<<16, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> d_field_sdl_flows_p2p_num(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData); +dfp_read_field_def_sdl_flows(<<24, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> d_field_sdl_flows_inbound_num(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData); +dfp_read_field_def_sdl_flows(<<>>, 0, 0, _, F@_1, F@_2, F@_3, _) -> #sdl_flows{forward_num = F@_1, p2p_num = F@_2, inbound_num = F@_3}; +dfp_read_field_def_sdl_flows(Other, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> dg_read_field_def_sdl_flows(Other, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData). + +dg_read_field_def_sdl_flows(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, TrUserData) when N < 32 - 7 -> dg_read_field_def_sdl_flows(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, TrUserData); +dg_read_field_def_sdl_flows(<<0:1, X:7, Rest/binary>>, N, Acc, _, F@_1, F@_2, F@_3, TrUserData) -> + Key = X bsl N + Acc, + case Key of + 8 -> d_field_sdl_flows_forward_num(Rest, 0, 0, 0, F@_1, F@_2, F@_3, TrUserData); + 16 -> d_field_sdl_flows_p2p_num(Rest, 0, 0, 0, F@_1, F@_2, F@_3, TrUserData); + 24 -> d_field_sdl_flows_inbound_num(Rest, 0, 0, 0, F@_1, F@_2, F@_3, TrUserData); + _ -> + case Key band 7 of + 0 -> skip_varint_sdl_flows(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, TrUserData); + 1 -> skip_64_sdl_flows(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, TrUserData); + 2 -> skip_length_delimited_sdl_flows(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, TrUserData); + 3 -> skip_group_sdl_flows(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, TrUserData); + 5 -> skip_32_sdl_flows(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, TrUserData) + end + end; +dg_read_field_def_sdl_flows(<<>>, 0, 0, _, F@_1, F@_2, F@_3, _) -> #sdl_flows{forward_num = F@_1, p2p_num = F@_2, inbound_num = F@_3}. + +d_field_sdl_flows_forward_num(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, TrUserData) when N < 57 -> d_field_sdl_flows_forward_num(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, TrUserData); +d_field_sdl_flows_forward_num(<<0:1, X:7, Rest/binary>>, N, Acc, F, _, F@_2, F@_3, TrUserData) -> + {NewFValue, RestF} = {id((X bsl N + Acc) band 4294967295, TrUserData), Rest}, + dfp_read_field_def_sdl_flows(RestF, 0, 0, F, NewFValue, F@_2, F@_3, TrUserData). + +d_field_sdl_flows_p2p_num(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, TrUserData) when N < 57 -> d_field_sdl_flows_p2p_num(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, TrUserData); +d_field_sdl_flows_p2p_num(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, _, F@_3, TrUserData) -> + {NewFValue, RestF} = {id((X bsl N + Acc) band 4294967295, TrUserData), Rest}, + dfp_read_field_def_sdl_flows(RestF, 0, 0, F, F@_1, NewFValue, F@_3, TrUserData). + +d_field_sdl_flows_inbound_num(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, TrUserData) when N < 57 -> d_field_sdl_flows_inbound_num(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, TrUserData); +d_field_sdl_flows_inbound_num(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, _, TrUserData) -> + {NewFValue, RestF} = {id((X bsl N + Acc) band 4294967295, TrUserData), Rest}, + dfp_read_field_def_sdl_flows(RestF, 0, 0, F, F@_1, F@_2, NewFValue, TrUserData). + +skip_varint_sdl_flows(<<1:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> skip_varint_sdl_flows(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData); +skip_varint_sdl_flows(<<0:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> dfp_read_field_def_sdl_flows(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData). + +skip_length_delimited_sdl_flows(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, TrUserData) when N < 57 -> skip_length_delimited_sdl_flows(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, TrUserData); +skip_length_delimited_sdl_flows(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, TrUserData) -> + Length = X bsl N + Acc, + <<_:Length/binary, Rest2/binary>> = Rest, + dfp_read_field_def_sdl_flows(Rest2, 0, 0, F, F@_1, F@_2, F@_3, TrUserData). + +skip_group_sdl_flows(Bin, _, Z2, FNum, F@_1, F@_2, F@_3, TrUserData) -> + {_, Rest} = read_group(Bin, FNum), + dfp_read_field_def_sdl_flows(Rest, 0, Z2, FNum, F@_1, F@_2, F@_3, TrUserData). + +skip_32_sdl_flows(<<_:32, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> dfp_read_field_def_sdl_flows(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData). + +skip_64_sdl_flows(<<_:64, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> dfp_read_field_def_sdl_flows(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData). + +decode_msg_sdl_stun_request(Bin, TrUserData) -> + dfp_read_field_def_sdl_stun_request(Bin, 0, 0, 0, id(0, TrUserData), id(<<>>, TrUserData), id(0, TrUserData), id(<<>>, TrUserData), id(0, TrUserData), id(0, TrUserData), id(undefined, TrUserData), TrUserData). + +dfp_read_field_def_sdl_stun_request(<<8, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) -> d_field_sdl_stun_request_cookie(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData); +dfp_read_field_def_sdl_stun_request(<<18, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) -> d_field_sdl_stun_request_client_id(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData); +dfp_read_field_def_sdl_stun_request(<<24, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) -> d_field_sdl_stun_request_network_id(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData); +dfp_read_field_def_sdl_stun_request(<<34, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) -> d_field_sdl_stun_request_mac(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData); +dfp_read_field_def_sdl_stun_request(<<40, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) -> d_field_sdl_stun_request_ip(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData); +dfp_read_field_def_sdl_stun_request(<<48, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) -> d_field_sdl_stun_request_nat_type(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData); +dfp_read_field_def_sdl_stun_request(<<58, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) -> d_field_sdl_stun_request_v6_info(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData); +dfp_read_field_def_sdl_stun_request(<<>>, 0, 0, _, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, _) -> #sdl_stun_request{cookie = F@_1, client_id = F@_2, network_id = F@_3, mac = F@_4, ip = F@_5, nat_type = F@_6, v6_info = F@_7}; +dfp_read_field_def_sdl_stun_request(Other, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) -> dg_read_field_def_sdl_stun_request(Other, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData). + +dg_read_field_def_sdl_stun_request(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) when N < 32 - 7 -> + dg_read_field_def_sdl_stun_request(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData); +dg_read_field_def_sdl_stun_request(<<0:1, X:7, Rest/binary>>, N, Acc, _, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) -> + Key = X bsl N + Acc, + case Key of + 8 -> d_field_sdl_stun_request_cookie(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData); + 18 -> d_field_sdl_stun_request_client_id(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData); + 24 -> d_field_sdl_stun_request_network_id(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData); + 34 -> d_field_sdl_stun_request_mac(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData); + 40 -> d_field_sdl_stun_request_ip(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData); + 48 -> d_field_sdl_stun_request_nat_type(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData); + 58 -> d_field_sdl_stun_request_v6_info(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData); + _ -> + case Key band 7 of + 0 -> skip_varint_sdl_stun_request(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData); + 1 -> skip_64_sdl_stun_request(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData); + 2 -> skip_length_delimited_sdl_stun_request(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData); + 3 -> skip_group_sdl_stun_request(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData); + 5 -> skip_32_sdl_stun_request(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) + end + end; +dg_read_field_def_sdl_stun_request(<<>>, 0, 0, _, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, _) -> #sdl_stun_request{cookie = F@_1, client_id = F@_2, network_id = F@_3, mac = F@_4, ip = F@_5, nat_type = F@_6, v6_info = F@_7}. + +d_field_sdl_stun_request_cookie(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) when N < 57 -> + d_field_sdl_stun_request_cookie(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData); +d_field_sdl_stun_request_cookie(<<0:1, X:7, Rest/binary>>, N, Acc, F, _, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) -> + {NewFValue, RestF} = {id((X bsl N + Acc) band 4294967295, TrUserData), Rest}, + dfp_read_field_def_sdl_stun_request(RestF, 0, 0, F, NewFValue, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData). + +d_field_sdl_stun_request_client_id(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) when N < 57 -> + d_field_sdl_stun_request_client_id(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData); +d_field_sdl_stun_request_client_id(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, _, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) -> + {NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, Bytes2 = binary:copy(Bytes), {id(Bytes2, TrUserData), Rest2} end, + dfp_read_field_def_sdl_stun_request(RestF, 0, 0, F, F@_1, NewFValue, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData). + +d_field_sdl_stun_request_network_id(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) when N < 57 -> + d_field_sdl_stun_request_network_id(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData); +d_field_sdl_stun_request_network_id(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, _, F@_4, F@_5, F@_6, F@_7, TrUserData) -> + {NewFValue, RestF} = {id((X bsl N + Acc) band 4294967295, TrUserData), Rest}, + dfp_read_field_def_sdl_stun_request(RestF, 0, 0, F, F@_1, F@_2, NewFValue, F@_4, F@_5, F@_6, F@_7, TrUserData). + +d_field_sdl_stun_request_mac(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) when N < 57 -> d_field_sdl_stun_request_mac(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData); +d_field_sdl_stun_request_mac(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, _, F@_5, F@_6, F@_7, TrUserData) -> + {NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, Bytes2 = binary:copy(Bytes), {id(Bytes2, TrUserData), Rest2} end, + dfp_read_field_def_sdl_stun_request(RestF, 0, 0, F, F@_1, F@_2, F@_3, NewFValue, F@_5, F@_6, F@_7, TrUserData). + +d_field_sdl_stun_request_ip(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) when N < 57 -> d_field_sdl_stun_request_ip(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData); +d_field_sdl_stun_request_ip(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, _, F@_6, F@_7, TrUserData) -> + {NewFValue, RestF} = {id((X bsl N + Acc) band 4294967295, TrUserData), Rest}, + dfp_read_field_def_sdl_stun_request(RestF, 0, 0, F, F@_1, F@_2, F@_3, F@_4, NewFValue, F@_6, F@_7, TrUserData). + +d_field_sdl_stun_request_nat_type(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) when N < 57 -> + d_field_sdl_stun_request_nat_type(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData); +d_field_sdl_stun_request_nat_type(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, _, F@_7, TrUserData) -> + {NewFValue, RestF} = {id((X bsl N + Acc) band 4294967295, TrUserData), Rest}, + dfp_read_field_def_sdl_stun_request(RestF, 0, 0, F, F@_1, F@_2, F@_3, F@_4, F@_5, NewFValue, F@_7, TrUserData). + +d_field_sdl_stun_request_v6_info(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) when N < 57 -> + d_field_sdl_stun_request_v6_info(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData); +d_field_sdl_stun_request_v6_info(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, Prev, TrUserData) -> + {NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, {id(decode_msg_sdl_v6_info(Bs, TrUserData), TrUserData), Rest2} end, + dfp_read_field_def_sdl_stun_request(RestF, + 0, + 0, + F, + F@_1, + F@_2, + F@_3, + F@_4, + F@_5, + F@_6, + if Prev == undefined -> NewFValue; + true -> merge_msg_sdl_v6_info(Prev, NewFValue, TrUserData) + end, + TrUserData). + +skip_varint_sdl_stun_request(<<1:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) -> skip_varint_sdl_stun_request(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData); +skip_varint_sdl_stun_request(<<0:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) -> dfp_read_field_def_sdl_stun_request(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData). + +skip_length_delimited_sdl_stun_request(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) when N < 57 -> + skip_length_delimited_sdl_stun_request(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData); +skip_length_delimited_sdl_stun_request(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) -> + Length = X bsl N + Acc, + <<_:Length/binary, Rest2/binary>> = Rest, + dfp_read_field_def_sdl_stun_request(Rest2, 0, 0, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData). + +skip_group_sdl_stun_request(Bin, _, Z2, FNum, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) -> + {_, Rest} = read_group(Bin, FNum), + dfp_read_field_def_sdl_stun_request(Rest, 0, Z2, FNum, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData). + +skip_32_sdl_stun_request(<<_:32, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) -> dfp_read_field_def_sdl_stun_request(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData). + +skip_64_sdl_stun_request(<<_:64, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData) -> dfp_read_field_def_sdl_stun_request(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, F@_7, TrUserData). + +decode_msg_sdl_stun_reply(Bin, TrUserData) -> dfp_read_field_def_sdl_stun_reply(Bin, 0, 0, 0, id(0, TrUserData), TrUserData). + +dfp_read_field_def_sdl_stun_reply(<<8, Rest/binary>>, Z1, Z2, F, F@_1, TrUserData) -> d_field_sdl_stun_reply_cookie(Rest, Z1, Z2, F, F@_1, TrUserData); +dfp_read_field_def_sdl_stun_reply(<<>>, 0, 0, _, F@_1, _) -> #sdl_stun_reply{cookie = F@_1}; +dfp_read_field_def_sdl_stun_reply(Other, Z1, Z2, F, F@_1, TrUserData) -> dg_read_field_def_sdl_stun_reply(Other, Z1, Z2, F, F@_1, TrUserData). + +dg_read_field_def_sdl_stun_reply(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, TrUserData) when N < 32 - 7 -> dg_read_field_def_sdl_stun_reply(Rest, N + 7, X bsl N + Acc, F, F@_1, TrUserData); +dg_read_field_def_sdl_stun_reply(<<0:1, X:7, Rest/binary>>, N, Acc, _, F@_1, TrUserData) -> + Key = X bsl N + Acc, + case Key of + 8 -> d_field_sdl_stun_reply_cookie(Rest, 0, 0, 0, F@_1, TrUserData); + _ -> + case Key band 7 of + 0 -> skip_varint_sdl_stun_reply(Rest, 0, 0, Key bsr 3, F@_1, TrUserData); + 1 -> skip_64_sdl_stun_reply(Rest, 0, 0, Key bsr 3, F@_1, TrUserData); + 2 -> skip_length_delimited_sdl_stun_reply(Rest, 0, 0, Key bsr 3, F@_1, TrUserData); + 3 -> skip_group_sdl_stun_reply(Rest, 0, 0, Key bsr 3, F@_1, TrUserData); + 5 -> skip_32_sdl_stun_reply(Rest, 0, 0, Key bsr 3, F@_1, TrUserData) + end + end; +dg_read_field_def_sdl_stun_reply(<<>>, 0, 0, _, F@_1, _) -> #sdl_stun_reply{cookie = F@_1}. + +d_field_sdl_stun_reply_cookie(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, TrUserData) when N < 57 -> d_field_sdl_stun_reply_cookie(Rest, N + 7, X bsl N + Acc, F, F@_1, TrUserData); +d_field_sdl_stun_reply_cookie(<<0:1, X:7, Rest/binary>>, N, Acc, F, _, TrUserData) -> + {NewFValue, RestF} = {id((X bsl N + Acc) band 4294967295, TrUserData), Rest}, + dfp_read_field_def_sdl_stun_reply(RestF, 0, 0, F, NewFValue, TrUserData). + +skip_varint_sdl_stun_reply(<<1:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, TrUserData) -> skip_varint_sdl_stun_reply(Rest, Z1, Z2, F, F@_1, TrUserData); +skip_varint_sdl_stun_reply(<<0:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, TrUserData) -> dfp_read_field_def_sdl_stun_reply(Rest, Z1, Z2, F, F@_1, TrUserData). + +skip_length_delimited_sdl_stun_reply(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, TrUserData) when N < 57 -> skip_length_delimited_sdl_stun_reply(Rest, N + 7, X bsl N + Acc, F, F@_1, TrUserData); +skip_length_delimited_sdl_stun_reply(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, TrUserData) -> + Length = X bsl N + Acc, + <<_:Length/binary, Rest2/binary>> = Rest, + dfp_read_field_def_sdl_stun_reply(Rest2, 0, 0, F, F@_1, TrUserData). + +skip_group_sdl_stun_reply(Bin, _, Z2, FNum, F@_1, TrUserData) -> + {_, Rest} = read_group(Bin, FNum), + dfp_read_field_def_sdl_stun_reply(Rest, 0, Z2, FNum, F@_1, TrUserData). + +skip_32_sdl_stun_reply(<<_:32, Rest/binary>>, Z1, Z2, F, F@_1, TrUserData) -> dfp_read_field_def_sdl_stun_reply(Rest, Z1, Z2, F, F@_1, TrUserData). + +skip_64_sdl_stun_reply(<<_:64, Rest/binary>>, Z1, Z2, F, F@_1, TrUserData) -> dfp_read_field_def_sdl_stun_reply(Rest, Z1, Z2, F, F@_1, TrUserData). + +decode_msg_sdl_data(Bin, TrUserData) -> dfp_read_field_def_sdl_data(Bin, 0, 0, 0, id(0, TrUserData), id(<<>>, TrUserData), id(<<>>, TrUserData), id(false, TrUserData), id(0, TrUserData), id(<<>>, TrUserData), TrUserData). + +dfp_read_field_def_sdl_data(<<8, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData) -> d_field_sdl_data_network_id(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData); +dfp_read_field_def_sdl_data(<<18, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData) -> d_field_sdl_data_src_mac(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData); +dfp_read_field_def_sdl_data(<<26, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData) -> d_field_sdl_data_dst_mac(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData); +dfp_read_field_def_sdl_data(<<32, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData) -> d_field_sdl_data_is_p2p(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData); +dfp_read_field_def_sdl_data(<<40, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData) -> d_field_sdl_data_ttl(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData); +dfp_read_field_def_sdl_data(<<50, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData) -> d_field_sdl_data_data(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData); +dfp_read_field_def_sdl_data(<<>>, 0, 0, _, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, _) -> #sdl_data{network_id = F@_1, src_mac = F@_2, dst_mac = F@_3, is_p2p = F@_4, ttl = F@_5, data = F@_6}; +dfp_read_field_def_sdl_data(Other, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData) -> dg_read_field_def_sdl_data(Other, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData). + +dg_read_field_def_sdl_data(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData) when N < 32 - 7 -> dg_read_field_def_sdl_data(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData); +dg_read_field_def_sdl_data(<<0:1, X:7, Rest/binary>>, N, Acc, _, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData) -> + Key = X bsl N + Acc, + case Key of + 8 -> d_field_sdl_data_network_id(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData); + 18 -> d_field_sdl_data_src_mac(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData); + 26 -> d_field_sdl_data_dst_mac(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData); + 32 -> d_field_sdl_data_is_p2p(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData); + 40 -> d_field_sdl_data_ttl(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData); + 50 -> d_field_sdl_data_data(Rest, 0, 0, 0, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData); + _ -> + case Key band 7 of + 0 -> skip_varint_sdl_data(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData); + 1 -> skip_64_sdl_data(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData); + 2 -> skip_length_delimited_sdl_data(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData); + 3 -> skip_group_sdl_data(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData); + 5 -> skip_32_sdl_data(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData) + end + end; +dg_read_field_def_sdl_data(<<>>, 0, 0, _, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, _) -> #sdl_data{network_id = F@_1, src_mac = F@_2, dst_mac = F@_3, is_p2p = F@_4, ttl = F@_5, data = F@_6}. + +d_field_sdl_data_network_id(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData) when N < 57 -> d_field_sdl_data_network_id(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData); +d_field_sdl_data_network_id(<<0:1, X:7, Rest/binary>>, N, Acc, F, _, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData) -> + {NewFValue, RestF} = {id((X bsl N + Acc) band 4294967295, TrUserData), Rest}, + dfp_read_field_def_sdl_data(RestF, 0, 0, F, NewFValue, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData). + +d_field_sdl_data_src_mac(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData) when N < 57 -> d_field_sdl_data_src_mac(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData); +d_field_sdl_data_src_mac(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, _, F@_3, F@_4, F@_5, F@_6, TrUserData) -> + {NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, Bytes2 = binary:copy(Bytes), {id(Bytes2, TrUserData), Rest2} end, + dfp_read_field_def_sdl_data(RestF, 0, 0, F, F@_1, NewFValue, F@_3, F@_4, F@_5, F@_6, TrUserData). + +d_field_sdl_data_dst_mac(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData) when N < 57 -> d_field_sdl_data_dst_mac(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData); +d_field_sdl_data_dst_mac(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, _, F@_4, F@_5, F@_6, TrUserData) -> + {NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, Bytes2 = binary:copy(Bytes), {id(Bytes2, TrUserData), Rest2} end, + dfp_read_field_def_sdl_data(RestF, 0, 0, F, F@_1, F@_2, NewFValue, F@_4, F@_5, F@_6, TrUserData). + +d_field_sdl_data_is_p2p(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData) when N < 57 -> d_field_sdl_data_is_p2p(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData); +d_field_sdl_data_is_p2p(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, _, F@_5, F@_6, TrUserData) -> + {NewFValue, RestF} = {id(X bsl N + Acc =/= 0, TrUserData), Rest}, + dfp_read_field_def_sdl_data(RestF, 0, 0, F, F@_1, F@_2, F@_3, NewFValue, F@_5, F@_6, TrUserData). + +d_field_sdl_data_ttl(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData) when N < 57 -> d_field_sdl_data_ttl(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData); +d_field_sdl_data_ttl(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, _, F@_6, TrUserData) -> + {NewFValue, RestF} = {id((X bsl N + Acc) band 4294967295, TrUserData), Rest}, + dfp_read_field_def_sdl_data(RestF, 0, 0, F, F@_1, F@_2, F@_3, F@_4, NewFValue, F@_6, TrUserData). + +d_field_sdl_data_data(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData) when N < 57 -> d_field_sdl_data_data(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData); +d_field_sdl_data_data(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, _, TrUserData) -> + {NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, Bytes2 = binary:copy(Bytes), {id(Bytes2, TrUserData), Rest2} end, + dfp_read_field_def_sdl_data(RestF, 0, 0, F, F@_1, F@_2, F@_3, F@_4, F@_5, NewFValue, TrUserData). + +skip_varint_sdl_data(<<1:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData) -> skip_varint_sdl_data(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData); +skip_varint_sdl_data(<<0:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData) -> dfp_read_field_def_sdl_data(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData). + +skip_length_delimited_sdl_data(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData) when N < 57 -> skip_length_delimited_sdl_data(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData); +skip_length_delimited_sdl_data(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData) -> + Length = X bsl N + Acc, + <<_:Length/binary, Rest2/binary>> = Rest, + dfp_read_field_def_sdl_data(Rest2, 0, 0, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData). + +skip_group_sdl_data(Bin, _, Z2, FNum, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData) -> + {_, Rest} = read_group(Bin, FNum), + dfp_read_field_def_sdl_data(Rest, 0, Z2, FNum, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData). + +skip_32_sdl_data(<<_:32, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData) -> dfp_read_field_def_sdl_data(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData). + +skip_64_sdl_data(<<_:64, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData) -> dfp_read_field_def_sdl_data(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, F@_4, F@_5, F@_6, TrUserData). + +decode_msg_sdl_register(Bin, TrUserData) -> dfp_read_field_def_sdl_register(Bin, 0, 0, 0, id(0, TrUserData), id(<<>>, TrUserData), id(<<>>, TrUserData), TrUserData). + +dfp_read_field_def_sdl_register(<<8, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> d_field_sdl_register_network_id(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData); +dfp_read_field_def_sdl_register(<<18, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> d_field_sdl_register_src_mac(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData); +dfp_read_field_def_sdl_register(<<26, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> d_field_sdl_register_dst_mac(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData); +dfp_read_field_def_sdl_register(<<>>, 0, 0, _, F@_1, F@_2, F@_3, _) -> #sdl_register{network_id = F@_1, src_mac = F@_2, dst_mac = F@_3}; +dfp_read_field_def_sdl_register(Other, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> dg_read_field_def_sdl_register(Other, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData). + +dg_read_field_def_sdl_register(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, TrUserData) when N < 32 - 7 -> dg_read_field_def_sdl_register(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, TrUserData); +dg_read_field_def_sdl_register(<<0:1, X:7, Rest/binary>>, N, Acc, _, F@_1, F@_2, F@_3, TrUserData) -> + Key = X bsl N + Acc, + case Key of + 8 -> d_field_sdl_register_network_id(Rest, 0, 0, 0, F@_1, F@_2, F@_3, TrUserData); + 18 -> d_field_sdl_register_src_mac(Rest, 0, 0, 0, F@_1, F@_2, F@_3, TrUserData); + 26 -> d_field_sdl_register_dst_mac(Rest, 0, 0, 0, F@_1, F@_2, F@_3, TrUserData); + _ -> + case Key band 7 of + 0 -> skip_varint_sdl_register(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, TrUserData); + 1 -> skip_64_sdl_register(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, TrUserData); + 2 -> skip_length_delimited_sdl_register(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, TrUserData); + 3 -> skip_group_sdl_register(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, TrUserData); + 5 -> skip_32_sdl_register(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, TrUserData) + end + end; +dg_read_field_def_sdl_register(<<>>, 0, 0, _, F@_1, F@_2, F@_3, _) -> #sdl_register{network_id = F@_1, src_mac = F@_2, dst_mac = F@_3}. + +d_field_sdl_register_network_id(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, TrUserData) when N < 57 -> d_field_sdl_register_network_id(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, TrUserData); +d_field_sdl_register_network_id(<<0:1, X:7, Rest/binary>>, N, Acc, F, _, F@_2, F@_3, TrUserData) -> + {NewFValue, RestF} = {id((X bsl N + Acc) band 4294967295, TrUserData), Rest}, + dfp_read_field_def_sdl_register(RestF, 0, 0, F, NewFValue, F@_2, F@_3, TrUserData). + +d_field_sdl_register_src_mac(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, TrUserData) when N < 57 -> d_field_sdl_register_src_mac(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, TrUserData); +d_field_sdl_register_src_mac(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, _, F@_3, TrUserData) -> + {NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, Bytes2 = binary:copy(Bytes), {id(Bytes2, TrUserData), Rest2} end, + dfp_read_field_def_sdl_register(RestF, 0, 0, F, F@_1, NewFValue, F@_3, TrUserData). + +d_field_sdl_register_dst_mac(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, TrUserData) when N < 57 -> d_field_sdl_register_dst_mac(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, TrUserData); +d_field_sdl_register_dst_mac(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, _, TrUserData) -> + {NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, Bytes2 = binary:copy(Bytes), {id(Bytes2, TrUserData), Rest2} end, + dfp_read_field_def_sdl_register(RestF, 0, 0, F, F@_1, F@_2, NewFValue, TrUserData). + +skip_varint_sdl_register(<<1:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> skip_varint_sdl_register(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData); +skip_varint_sdl_register(<<0:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> dfp_read_field_def_sdl_register(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData). + +skip_length_delimited_sdl_register(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, TrUserData) when N < 57 -> skip_length_delimited_sdl_register(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, TrUserData); +skip_length_delimited_sdl_register(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, TrUserData) -> + Length = X bsl N + Acc, + <<_:Length/binary, Rest2/binary>> = Rest, + dfp_read_field_def_sdl_register(Rest2, 0, 0, F, F@_1, F@_2, F@_3, TrUserData). + +skip_group_sdl_register(Bin, _, Z2, FNum, F@_1, F@_2, F@_3, TrUserData) -> + {_, Rest} = read_group(Bin, FNum), + dfp_read_field_def_sdl_register(Rest, 0, Z2, FNum, F@_1, F@_2, F@_3, TrUserData). + +skip_32_sdl_register(<<_:32, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> dfp_read_field_def_sdl_register(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData). + +skip_64_sdl_register(<<_:64, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> dfp_read_field_def_sdl_register(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData). + +decode_msg_sdl_register_ack(Bin, TrUserData) -> dfp_read_field_def_sdl_register_ack(Bin, 0, 0, 0, id(0, TrUserData), id(<<>>, TrUserData), id(<<>>, TrUserData), TrUserData). + +dfp_read_field_def_sdl_register_ack(<<8, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> d_field_sdl_register_ack_network_id(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData); +dfp_read_field_def_sdl_register_ack(<<18, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> d_field_sdl_register_ack_src_mac(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData); +dfp_read_field_def_sdl_register_ack(<<26, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> d_field_sdl_register_ack_dst_mac(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData); +dfp_read_field_def_sdl_register_ack(<<>>, 0, 0, _, F@_1, F@_2, F@_3, _) -> #sdl_register_ack{network_id = F@_1, src_mac = F@_2, dst_mac = F@_3}; +dfp_read_field_def_sdl_register_ack(Other, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> dg_read_field_def_sdl_register_ack(Other, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData). + +dg_read_field_def_sdl_register_ack(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, TrUserData) when N < 32 - 7 -> dg_read_field_def_sdl_register_ack(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, TrUserData); +dg_read_field_def_sdl_register_ack(<<0:1, X:7, Rest/binary>>, N, Acc, _, F@_1, F@_2, F@_3, TrUserData) -> + Key = X bsl N + Acc, + case Key of + 8 -> d_field_sdl_register_ack_network_id(Rest, 0, 0, 0, F@_1, F@_2, F@_3, TrUserData); + 18 -> d_field_sdl_register_ack_src_mac(Rest, 0, 0, 0, F@_1, F@_2, F@_3, TrUserData); + 26 -> d_field_sdl_register_ack_dst_mac(Rest, 0, 0, 0, F@_1, F@_2, F@_3, TrUserData); + _ -> + case Key band 7 of + 0 -> skip_varint_sdl_register_ack(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, TrUserData); + 1 -> skip_64_sdl_register_ack(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, TrUserData); + 2 -> skip_length_delimited_sdl_register_ack(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, TrUserData); + 3 -> skip_group_sdl_register_ack(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, TrUserData); + 5 -> skip_32_sdl_register_ack(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, TrUserData) + end + end; +dg_read_field_def_sdl_register_ack(<<>>, 0, 0, _, F@_1, F@_2, F@_3, _) -> #sdl_register_ack{network_id = F@_1, src_mac = F@_2, dst_mac = F@_3}. + +d_field_sdl_register_ack_network_id(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, TrUserData) when N < 57 -> d_field_sdl_register_ack_network_id(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, TrUserData); +d_field_sdl_register_ack_network_id(<<0:1, X:7, Rest/binary>>, N, Acc, F, _, F@_2, F@_3, TrUserData) -> + {NewFValue, RestF} = {id((X bsl N + Acc) band 4294967295, TrUserData), Rest}, + dfp_read_field_def_sdl_register_ack(RestF, 0, 0, F, NewFValue, F@_2, F@_3, TrUserData). + +d_field_sdl_register_ack_src_mac(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, TrUserData) when N < 57 -> d_field_sdl_register_ack_src_mac(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, TrUserData); +d_field_sdl_register_ack_src_mac(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, _, F@_3, TrUserData) -> + {NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, Bytes2 = binary:copy(Bytes), {id(Bytes2, TrUserData), Rest2} end, + dfp_read_field_def_sdl_register_ack(RestF, 0, 0, F, F@_1, NewFValue, F@_3, TrUserData). + +d_field_sdl_register_ack_dst_mac(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, TrUserData) when N < 57 -> d_field_sdl_register_ack_dst_mac(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, TrUserData); +d_field_sdl_register_ack_dst_mac(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, _, TrUserData) -> + {NewFValue, RestF} = begin Len = X bsl N + Acc, <> = Rest, Bytes2 = binary:copy(Bytes), {id(Bytes2, TrUserData), Rest2} end, + dfp_read_field_def_sdl_register_ack(RestF, 0, 0, F, F@_1, F@_2, NewFValue, TrUserData). + +skip_varint_sdl_register_ack(<<1:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> skip_varint_sdl_register_ack(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData); +skip_varint_sdl_register_ack(<<0:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> dfp_read_field_def_sdl_register_ack(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData). + +skip_length_delimited_sdl_register_ack(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, TrUserData) when N < 57 -> skip_length_delimited_sdl_register_ack(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, TrUserData); +skip_length_delimited_sdl_register_ack(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, TrUserData) -> + Length = X bsl N + Acc, + <<_:Length/binary, Rest2/binary>> = Rest, + dfp_read_field_def_sdl_register_ack(Rest2, 0, 0, F, F@_1, F@_2, F@_3, TrUserData). + +skip_group_sdl_register_ack(Bin, _, Z2, FNum, F@_1, F@_2, F@_3, TrUserData) -> + {_, Rest} = read_group(Bin, FNum), + dfp_read_field_def_sdl_register_ack(Rest, 0, Z2, FNum, F@_1, F@_2, F@_3, TrUserData). + +skip_32_sdl_register_ack(<<_:32, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> dfp_read_field_def_sdl_register_ack(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData). + +skip_64_sdl_register_ack(<<_:64, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> dfp_read_field_def_sdl_register_ack(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData). + +decode_msg_sdl_stun_probe(Bin, TrUserData) -> dfp_read_field_def_sdl_stun_probe(Bin, 0, 0, 0, id(0, TrUserData), id(0, TrUserData), TrUserData). + +dfp_read_field_def_sdl_stun_probe(<<8, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> d_field_sdl_stun_probe_cookie(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData); +dfp_read_field_def_sdl_stun_probe(<<16, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> d_field_sdl_stun_probe_attr(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData); +dfp_read_field_def_sdl_stun_probe(<<>>, 0, 0, _, F@_1, F@_2, _) -> #sdl_stun_probe{cookie = F@_1, attr = F@_2}; +dfp_read_field_def_sdl_stun_probe(Other, Z1, Z2, F, F@_1, F@_2, TrUserData) -> dg_read_field_def_sdl_stun_probe(Other, Z1, Z2, F, F@_1, F@_2, TrUserData). + +dg_read_field_def_sdl_stun_probe(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, TrUserData) when N < 32 - 7 -> dg_read_field_def_sdl_stun_probe(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, TrUserData); +dg_read_field_def_sdl_stun_probe(<<0:1, X:7, Rest/binary>>, N, Acc, _, F@_1, F@_2, TrUserData) -> + Key = X bsl N + Acc, + case Key of + 8 -> d_field_sdl_stun_probe_cookie(Rest, 0, 0, 0, F@_1, F@_2, TrUserData); + 16 -> d_field_sdl_stun_probe_attr(Rest, 0, 0, 0, F@_1, F@_2, TrUserData); + _ -> + case Key band 7 of + 0 -> skip_varint_sdl_stun_probe(Rest, 0, 0, Key bsr 3, F@_1, F@_2, TrUserData); + 1 -> skip_64_sdl_stun_probe(Rest, 0, 0, Key bsr 3, F@_1, F@_2, TrUserData); + 2 -> skip_length_delimited_sdl_stun_probe(Rest, 0, 0, Key bsr 3, F@_1, F@_2, TrUserData); + 3 -> skip_group_sdl_stun_probe(Rest, 0, 0, Key bsr 3, F@_1, F@_2, TrUserData); + 5 -> skip_32_sdl_stun_probe(Rest, 0, 0, Key bsr 3, F@_1, F@_2, TrUserData) + end + end; +dg_read_field_def_sdl_stun_probe(<<>>, 0, 0, _, F@_1, F@_2, _) -> #sdl_stun_probe{cookie = F@_1, attr = F@_2}. + +d_field_sdl_stun_probe_cookie(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, TrUserData) when N < 57 -> d_field_sdl_stun_probe_cookie(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, TrUserData); +d_field_sdl_stun_probe_cookie(<<0:1, X:7, Rest/binary>>, N, Acc, F, _, F@_2, TrUserData) -> + {NewFValue, RestF} = {id((X bsl N + Acc) band 4294967295, TrUserData), Rest}, + dfp_read_field_def_sdl_stun_probe(RestF, 0, 0, F, NewFValue, F@_2, TrUserData). + +d_field_sdl_stun_probe_attr(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, TrUserData) when N < 57 -> d_field_sdl_stun_probe_attr(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, TrUserData); +d_field_sdl_stun_probe_attr(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, _, TrUserData) -> + {NewFValue, RestF} = {id((X bsl N + Acc) band 4294967295, TrUserData), Rest}, + dfp_read_field_def_sdl_stun_probe(RestF, 0, 0, F, F@_1, NewFValue, TrUserData). + +skip_varint_sdl_stun_probe(<<1:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> skip_varint_sdl_stun_probe(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData); +skip_varint_sdl_stun_probe(<<0:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> dfp_read_field_def_sdl_stun_probe(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData). + +skip_length_delimited_sdl_stun_probe(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, TrUserData) when N < 57 -> skip_length_delimited_sdl_stun_probe(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, TrUserData); +skip_length_delimited_sdl_stun_probe(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, TrUserData) -> + Length = X bsl N + Acc, + <<_:Length/binary, Rest2/binary>> = Rest, + dfp_read_field_def_sdl_stun_probe(Rest2, 0, 0, F, F@_1, F@_2, TrUserData). + +skip_group_sdl_stun_probe(Bin, _, Z2, FNum, F@_1, F@_2, TrUserData) -> + {_, Rest} = read_group(Bin, FNum), + dfp_read_field_def_sdl_stun_probe(Rest, 0, Z2, FNum, F@_1, F@_2, TrUserData). + +skip_32_sdl_stun_probe(<<_:32, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> dfp_read_field_def_sdl_stun_probe(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData). + +skip_64_sdl_stun_probe(<<_:64, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, TrUserData) -> dfp_read_field_def_sdl_stun_probe(Rest, Z1, Z2, F, F@_1, F@_2, TrUserData). + +decode_msg_sdl_stun_probe_reply(Bin, TrUserData) -> dfp_read_field_def_sdl_stun_probe_reply(Bin, 0, 0, 0, id(0, TrUserData), id(0, TrUserData), id(0, TrUserData), TrUserData). + +dfp_read_field_def_sdl_stun_probe_reply(<<8, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> d_field_sdl_stun_probe_reply_cookie(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData); +dfp_read_field_def_sdl_stun_probe_reply(<<16, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> d_field_sdl_stun_probe_reply_port(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData); +dfp_read_field_def_sdl_stun_probe_reply(<<24, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> d_field_sdl_stun_probe_reply_ip(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData); +dfp_read_field_def_sdl_stun_probe_reply(<<>>, 0, 0, _, F@_1, F@_2, F@_3, _) -> #sdl_stun_probe_reply{cookie = F@_1, port = F@_2, ip = F@_3}; +dfp_read_field_def_sdl_stun_probe_reply(Other, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> dg_read_field_def_sdl_stun_probe_reply(Other, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData). + +dg_read_field_def_sdl_stun_probe_reply(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, TrUserData) when N < 32 - 7 -> dg_read_field_def_sdl_stun_probe_reply(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, TrUserData); +dg_read_field_def_sdl_stun_probe_reply(<<0:1, X:7, Rest/binary>>, N, Acc, _, F@_1, F@_2, F@_3, TrUserData) -> + Key = X bsl N + Acc, + case Key of + 8 -> d_field_sdl_stun_probe_reply_cookie(Rest, 0, 0, 0, F@_1, F@_2, F@_3, TrUserData); + 16 -> d_field_sdl_stun_probe_reply_port(Rest, 0, 0, 0, F@_1, F@_2, F@_3, TrUserData); + 24 -> d_field_sdl_stun_probe_reply_ip(Rest, 0, 0, 0, F@_1, F@_2, F@_3, TrUserData); + _ -> + case Key band 7 of + 0 -> skip_varint_sdl_stun_probe_reply(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, TrUserData); + 1 -> skip_64_sdl_stun_probe_reply(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, TrUserData); + 2 -> skip_length_delimited_sdl_stun_probe_reply(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, TrUserData); + 3 -> skip_group_sdl_stun_probe_reply(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, TrUserData); + 5 -> skip_32_sdl_stun_probe_reply(Rest, 0, 0, Key bsr 3, F@_1, F@_2, F@_3, TrUserData) + end + end; +dg_read_field_def_sdl_stun_probe_reply(<<>>, 0, 0, _, F@_1, F@_2, F@_3, _) -> #sdl_stun_probe_reply{cookie = F@_1, port = F@_2, ip = F@_3}. + +d_field_sdl_stun_probe_reply_cookie(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, TrUserData) when N < 57 -> d_field_sdl_stun_probe_reply_cookie(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, TrUserData); +d_field_sdl_stun_probe_reply_cookie(<<0:1, X:7, Rest/binary>>, N, Acc, F, _, F@_2, F@_3, TrUserData) -> + {NewFValue, RestF} = {id((X bsl N + Acc) band 4294967295, TrUserData), Rest}, + dfp_read_field_def_sdl_stun_probe_reply(RestF, 0, 0, F, NewFValue, F@_2, F@_3, TrUserData). + +d_field_sdl_stun_probe_reply_port(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, TrUserData) when N < 57 -> d_field_sdl_stun_probe_reply_port(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, TrUserData); +d_field_sdl_stun_probe_reply_port(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, _, F@_3, TrUserData) -> + {NewFValue, RestF} = {id((X bsl N + Acc) band 4294967295, TrUserData), Rest}, + dfp_read_field_def_sdl_stun_probe_reply(RestF, 0, 0, F, F@_1, NewFValue, F@_3, TrUserData). + +d_field_sdl_stun_probe_reply_ip(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, TrUserData) when N < 57 -> d_field_sdl_stun_probe_reply_ip(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, TrUserData); +d_field_sdl_stun_probe_reply_ip(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, _, TrUserData) -> + {NewFValue, RestF} = {id((X bsl N + Acc) band 4294967295, TrUserData), Rest}, + dfp_read_field_def_sdl_stun_probe_reply(RestF, 0, 0, F, F@_1, F@_2, NewFValue, TrUserData). + +skip_varint_sdl_stun_probe_reply(<<1:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> skip_varint_sdl_stun_probe_reply(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData); +skip_varint_sdl_stun_probe_reply(<<0:1, _:7, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> dfp_read_field_def_sdl_stun_probe_reply(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData). + +skip_length_delimited_sdl_stun_probe_reply(<<1:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, TrUserData) when N < 57 -> skip_length_delimited_sdl_stun_probe_reply(Rest, N + 7, X bsl N + Acc, F, F@_1, F@_2, F@_3, TrUserData); +skip_length_delimited_sdl_stun_probe_reply(<<0:1, X:7, Rest/binary>>, N, Acc, F, F@_1, F@_2, F@_3, TrUserData) -> + Length = X bsl N + Acc, + <<_:Length/binary, Rest2/binary>> = Rest, + dfp_read_field_def_sdl_stun_probe_reply(Rest2, 0, 0, F, F@_1, F@_2, F@_3, TrUserData). + +skip_group_sdl_stun_probe_reply(Bin, _, Z2, FNum, F@_1, F@_2, F@_3, TrUserData) -> + {_, Rest} = read_group(Bin, FNum), + dfp_read_field_def_sdl_stun_probe_reply(Rest, 0, Z2, FNum, F@_1, F@_2, F@_3, TrUserData). + +skip_32_sdl_stun_probe_reply(<<_:32, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> dfp_read_field_def_sdl_stun_probe_reply(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData). + +skip_64_sdl_stun_probe_reply(<<_:64, Rest/binary>>, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData) -> dfp_read_field_def_sdl_stun_probe_reply(Rest, Z1, Z2, F, F@_1, F@_2, F@_3, TrUserData). + +read_group(Bin, FieldNum) -> + {NumBytes, EndTagLen} = read_gr_b(Bin, 0, 0, 0, 0, FieldNum), + <> = Bin, + {Group, Rest}. + +%% Like skipping over fields, but record the total length, +%% Each field is <(FieldNum bsl 3) bor FieldType> ++ +%% Record the length because varints may be non-optimally encoded. +%% +%% Groups can be nested, but assume the same FieldNum cannot be nested +%% because group field numbers are shared with the rest of the fields +%% numbers. Thus we can search just for an group-end with the same +%% field number. +%% +%% (The only time the same group field number could occur would +%% be in a nested sub message, but then it would be inside a +%% length-delimited entry, which we skip-read by length.) +read_gr_b(<<1:1, X:7, Tl/binary>>, N, Acc, NumBytes, TagLen, FieldNum) + when N < (32-7) -> + read_gr_b(Tl, N+7, X bsl N + Acc, NumBytes, TagLen+1, FieldNum); +read_gr_b(<<0:1, X:7, Tl/binary>>, N, Acc, NumBytes, TagLen, + FieldNum) -> + Key = X bsl N + Acc, + TagLen1 = TagLen + 1, + case {Key bsr 3, Key band 7} of + {FieldNum, 4} -> % 4 = group_end + {NumBytes, TagLen1}; + {_, 0} -> % 0 = varint + read_gr_vi(Tl, 0, NumBytes + TagLen1, FieldNum); + {_, 1} -> % 1 = bits64 + <<_:64, Tl2/binary>> = Tl, + read_gr_b(Tl2, 0, 0, NumBytes + TagLen1 + 8, 0, FieldNum); + {_, 2} -> % 2 = length_delimited + read_gr_ld(Tl, 0, 0, NumBytes + TagLen1, FieldNum); + {_, 3} -> % 3 = group_start + read_gr_b(Tl, 0, 0, NumBytes + TagLen1, 0, FieldNum); + {_, 4} -> % 4 = group_end + read_gr_b(Tl, 0, 0, NumBytes + TagLen1, 0, FieldNum); + {_, 5} -> % 5 = bits32 + <<_:32, Tl2/binary>> = Tl, + read_gr_b(Tl2, 0, 0, NumBytes + TagLen1 + 4, 0, FieldNum) + end. + +read_gr_vi(<<1:1, _:7, Tl/binary>>, N, NumBytes, FieldNum) + when N < (64-7) -> + read_gr_vi(Tl, N+7, NumBytes+1, FieldNum); +read_gr_vi(<<0:1, _:7, Tl/binary>>, _, NumBytes, FieldNum) -> + read_gr_b(Tl, 0, 0, NumBytes+1, 0, FieldNum). + +read_gr_ld(<<1:1, X:7, Tl/binary>>, N, Acc, NumBytes, FieldNum) + when N < (64-7) -> + read_gr_ld(Tl, N+7, X bsl N + Acc, NumBytes+1, FieldNum); +read_gr_ld(<<0:1, X:7, Tl/binary>>, N, Acc, NumBytes, FieldNum) -> + Len = X bsl N + Acc, + NumBytes1 = NumBytes + 1, + <<_:Len/binary, Tl2/binary>> = Tl, + read_gr_b(Tl2, 0, 0, NumBytes1 + Len, 0, FieldNum). + +merge_msgs(Prev, New) when element(1, Prev) =:= element(1, New) -> merge_msgs(Prev, New, element(1, Prev), []). + +merge_msgs(Prev, New, MsgName) when is_atom(MsgName) -> merge_msgs(Prev, New, MsgName, []); +merge_msgs(Prev, New, Opts) when element(1, Prev) =:= element(1, New), is_list(Opts) -> merge_msgs(Prev, New, element(1, Prev), Opts). + +merge_msgs(Prev, New, MsgName, Opts) -> + TrUserData = proplists:get_value(user_data, Opts), + case MsgName of + sdl_v4_info -> merge_msg_sdl_v4_info(Prev, New, TrUserData); + sdl_v6_info -> merge_msg_sdl_v6_info(Prev, New, TrUserData); + sdl_dev_addr -> merge_msg_sdl_dev_addr(Prev, New, TrUserData); + sdl_empty -> merge_msg_sdl_empty(Prev, New, TrUserData); + sdl_register_super -> merge_msg_sdl_register_super(Prev, New, TrUserData); + sdl_register_super_ack -> merge_msg_sdl_register_super_ack(Prev, New, TrUserData); + sdl_register_super_nak -> merge_msg_sdl_register_super_nak(Prev, New, TrUserData); + sdl_query_info -> merge_msg_sdl_query_info(Prev, New, TrUserData); + sdl_peer_info -> merge_msg_sdl_peer_info(Prev, New, TrUserData); + sdl_nat_changed_event -> merge_msg_sdl_nat_changed_event(Prev, New, TrUserData); + sdl_send_register_event -> merge_msg_sdl_send_register_event(Prev, New, TrUserData); + sdl_network_shutdown_event -> merge_msg_sdl_network_shutdown_event(Prev, New, TrUserData); + sdl_change_network_command -> merge_msg_sdl_change_network_command(Prev, New, TrUserData); + sdl_command_ack -> merge_msg_sdl_command_ack(Prev, New, TrUserData); + sdl_flows -> merge_msg_sdl_flows(Prev, New, TrUserData); + sdl_stun_request -> merge_msg_sdl_stun_request(Prev, New, TrUserData); + sdl_stun_reply -> merge_msg_sdl_stun_reply(Prev, New, TrUserData); + sdl_data -> merge_msg_sdl_data(Prev, New, TrUserData); + sdl_register -> merge_msg_sdl_register(Prev, New, TrUserData); + sdl_register_ack -> merge_msg_sdl_register_ack(Prev, New, TrUserData); + sdl_stun_probe -> merge_msg_sdl_stun_probe(Prev, New, TrUserData); + sdl_stun_probe_reply -> merge_msg_sdl_stun_probe_reply(Prev, New, TrUserData) + end. + +-compile({nowarn_unused_function,merge_msg_sdl_v4_info/3}). +merge_msg_sdl_v4_info(#sdl_v4_info{port = PFport, v4 = PFv4, nat_type = PFnat_type}, #sdl_v4_info{port = NFport, v4 = NFv4, nat_type = NFnat_type}, _) -> + #sdl_v4_info{port = + if NFport =:= undefined -> PFport; + true -> NFport + end, + v4 = + if NFv4 =:= undefined -> PFv4; + true -> NFv4 + end, + nat_type = + if NFnat_type =:= undefined -> PFnat_type; + true -> NFnat_type + end}. + +-compile({nowarn_unused_function,merge_msg_sdl_v6_info/3}). +merge_msg_sdl_v6_info(#sdl_v6_info{port = PFport, v6 = PFv6}, #sdl_v6_info{port = NFport, v6 = NFv6}, _) -> + #sdl_v6_info{port = + if NFport =:= undefined -> PFport; + true -> NFport + end, + v6 = + if NFv6 =:= undefined -> PFv6; + true -> NFv6 + end}. + +-compile({nowarn_unused_function,merge_msg_sdl_dev_addr/3}). +merge_msg_sdl_dev_addr(#sdl_dev_addr{network_id = PFnetwork_id, mac = PFmac, net_addr = PFnet_addr, net_bit_len = PFnet_bit_len}, #sdl_dev_addr{network_id = NFnetwork_id, mac = NFmac, net_addr = NFnet_addr, net_bit_len = NFnet_bit_len}, _) -> + #sdl_dev_addr{network_id = + if NFnetwork_id =:= undefined -> PFnetwork_id; + true -> NFnetwork_id + end, + mac = + if NFmac =:= undefined -> PFmac; + true -> NFmac + end, + net_addr = + if NFnet_addr =:= undefined -> PFnet_addr; + true -> NFnet_addr + end, + net_bit_len = + if NFnet_bit_len =:= undefined -> PFnet_bit_len; + true -> NFnet_bit_len + end}. + +-compile({nowarn_unused_function,merge_msg_sdl_empty/3}). +merge_msg_sdl_empty(_Prev, New, _TrUserData) -> New. + +-compile({nowarn_unused_function,merge_msg_sdl_register_super/3}). +merge_msg_sdl_register_super(#sdl_register_super{version = PFversion, installed_channel = PFinstalled_channel, client_id = PFclient_id, dev_addr = PFdev_addr, pub_key = PFpub_key, token = PFtoken}, + #sdl_register_super{version = NFversion, installed_channel = NFinstalled_channel, client_id = NFclient_id, dev_addr = NFdev_addr, pub_key = NFpub_key, token = NFtoken}, TrUserData) -> + #sdl_register_super{version = + if NFversion =:= undefined -> PFversion; + true -> NFversion + end, + installed_channel = + if NFinstalled_channel =:= undefined -> PFinstalled_channel; + true -> NFinstalled_channel + end, + client_id = + if NFclient_id =:= undefined -> PFclient_id; + true -> NFclient_id + end, + dev_addr = + if PFdev_addr /= undefined, NFdev_addr /= undefined -> merge_msg_sdl_dev_addr(PFdev_addr, NFdev_addr, TrUserData); + PFdev_addr == undefined -> NFdev_addr; + NFdev_addr == undefined -> PFdev_addr + end, + pub_key = + if NFpub_key =:= undefined -> PFpub_key; + true -> NFpub_key + end, + token = + if NFtoken =:= undefined -> PFtoken; + true -> NFtoken + end}. + +-compile({nowarn_unused_function,merge_msg_sdl_register_super_ack/3}). +merge_msg_sdl_register_super_ack(#sdl_register_super_ack{dev_addr = PFdev_addr, aes_key = PFaes_key, upgrade_type = PFupgrade_type, upgrade_prompt = PFupgrade_prompt, upgrade_address = PFupgrade_address}, + #sdl_register_super_ack{dev_addr = NFdev_addr, aes_key = NFaes_key, upgrade_type = NFupgrade_type, upgrade_prompt = NFupgrade_prompt, upgrade_address = NFupgrade_address}, TrUserData) -> + #sdl_register_super_ack{dev_addr = + if PFdev_addr /= undefined, NFdev_addr /= undefined -> merge_msg_sdl_dev_addr(PFdev_addr, NFdev_addr, TrUserData); + PFdev_addr == undefined -> NFdev_addr; + NFdev_addr == undefined -> PFdev_addr + end, + aes_key = + if NFaes_key =:= undefined -> PFaes_key; + true -> NFaes_key + end, + upgrade_type = + if NFupgrade_type =:= undefined -> PFupgrade_type; + true -> NFupgrade_type + end, + upgrade_prompt = + if NFupgrade_prompt =:= undefined -> PFupgrade_prompt; + true -> NFupgrade_prompt + end, + upgrade_address = + if NFupgrade_address =:= undefined -> PFupgrade_address; + true -> NFupgrade_address + end}. + +-compile({nowarn_unused_function,merge_msg_sdl_register_super_nak/3}). +merge_msg_sdl_register_super_nak(#sdl_register_super_nak{error_code = PFerror_code, error_message = PFerror_message}, #sdl_register_super_nak{error_code = NFerror_code, error_message = NFerror_message}, _) -> + #sdl_register_super_nak{error_code = + if NFerror_code =:= undefined -> PFerror_code; + true -> NFerror_code + end, + error_message = + if NFerror_message =:= undefined -> PFerror_message; + true -> NFerror_message + end}. + +-compile({nowarn_unused_function,merge_msg_sdl_query_info/3}). +merge_msg_sdl_query_info(#sdl_query_info{dst_mac = PFdst_mac}, #sdl_query_info{dst_mac = NFdst_mac}, _) -> + #sdl_query_info{dst_mac = + if NFdst_mac =:= undefined -> PFdst_mac; + true -> NFdst_mac + end}. + +-compile({nowarn_unused_function,merge_msg_sdl_peer_info/3}). +merge_msg_sdl_peer_info(#sdl_peer_info{dst_mac = PFdst_mac, v4_info = PFv4_info, v6_info = PFv6_info}, #sdl_peer_info{dst_mac = NFdst_mac, v4_info = NFv4_info, v6_info = NFv6_info}, TrUserData) -> + #sdl_peer_info{dst_mac = + if NFdst_mac =:= undefined -> PFdst_mac; + true -> NFdst_mac + end, + v4_info = + if PFv4_info /= undefined, NFv4_info /= undefined -> merge_msg_sdl_v4_info(PFv4_info, NFv4_info, TrUserData); + PFv4_info == undefined -> NFv4_info; + NFv4_info == undefined -> PFv4_info + end, + v6_info = + if PFv6_info /= undefined, NFv6_info /= undefined -> merge_msg_sdl_v6_info(PFv6_info, NFv6_info, TrUserData); + PFv6_info == undefined -> NFv6_info; + NFv6_info == undefined -> PFv6_info + end}. + +-compile({nowarn_unused_function,merge_msg_sdl_nat_changed_event/3}). +merge_msg_sdl_nat_changed_event(#sdl_nat_changed_event{mac = PFmac, ip = PFip}, #sdl_nat_changed_event{mac = NFmac, ip = NFip}, _) -> + #sdl_nat_changed_event{mac = + if NFmac =:= undefined -> PFmac; + true -> NFmac + end, + ip = + if NFip =:= undefined -> PFip; + true -> NFip + end}. + +-compile({nowarn_unused_function,merge_msg_sdl_send_register_event/3}). +merge_msg_sdl_send_register_event(#sdl_send_register_event{dst_mac = PFdst_mac, nat_ip = PFnat_ip, nat_port = PFnat_port, nat_type = PFnat_type, v6_info = PFv6_info}, + #sdl_send_register_event{dst_mac = NFdst_mac, nat_ip = NFnat_ip, nat_port = NFnat_port, nat_type = NFnat_type, v6_info = NFv6_info}, TrUserData) -> + #sdl_send_register_event{dst_mac = + if NFdst_mac =:= undefined -> PFdst_mac; + true -> NFdst_mac + end, + nat_ip = + if NFnat_ip =:= undefined -> PFnat_ip; + true -> NFnat_ip + end, + nat_port = + if NFnat_port =:= undefined -> PFnat_port; + true -> NFnat_port + end, + nat_type = + if NFnat_type =:= undefined -> PFnat_type; + true -> NFnat_type + end, + v6_info = + if PFv6_info /= undefined, NFv6_info /= undefined -> merge_msg_sdl_v6_info(PFv6_info, NFv6_info, TrUserData); + PFv6_info == undefined -> NFv6_info; + NFv6_info == undefined -> PFv6_info + end}. + +-compile({nowarn_unused_function,merge_msg_sdl_network_shutdown_event/3}). +merge_msg_sdl_network_shutdown_event(#sdl_network_shutdown_event{message = PFmessage}, #sdl_network_shutdown_event{message = NFmessage}, _) -> + #sdl_network_shutdown_event{message = + if NFmessage =:= undefined -> PFmessage; + true -> NFmessage + end}. + +-compile({nowarn_unused_function,merge_msg_sdl_change_network_command/3}). +merge_msg_sdl_change_network_command(#sdl_change_network_command{dev_addr = PFdev_addr, aes_key = PFaes_key}, #sdl_change_network_command{dev_addr = NFdev_addr, aes_key = NFaes_key}, TrUserData) -> + #sdl_change_network_command{dev_addr = + if PFdev_addr /= undefined, NFdev_addr /= undefined -> merge_msg_sdl_dev_addr(PFdev_addr, NFdev_addr, TrUserData); + PFdev_addr == undefined -> NFdev_addr; + NFdev_addr == undefined -> PFdev_addr + end, + aes_key = + if NFaes_key =:= undefined -> PFaes_key; + true -> NFaes_key + end}. + +-compile({nowarn_unused_function,merge_msg_sdl_command_ack/3}). +merge_msg_sdl_command_ack(#sdl_command_ack{status = PFstatus, message = PFmessage}, #sdl_command_ack{status = NFstatus, message = NFmessage}, _) -> + #sdl_command_ack{status = + if NFstatus =:= undefined -> PFstatus; + true -> NFstatus + end, + message = + if NFmessage =:= undefined -> PFmessage; + true -> NFmessage + end}. + +-compile({nowarn_unused_function,merge_msg_sdl_flows/3}). +merge_msg_sdl_flows(#sdl_flows{forward_num = PFforward_num, p2p_num = PFp2p_num, inbound_num = PFinbound_num}, #sdl_flows{forward_num = NFforward_num, p2p_num = NFp2p_num, inbound_num = NFinbound_num}, _) -> + #sdl_flows{forward_num = + if NFforward_num =:= undefined -> PFforward_num; + true -> NFforward_num + end, + p2p_num = + if NFp2p_num =:= undefined -> PFp2p_num; + true -> NFp2p_num + end, + inbound_num = + if NFinbound_num =:= undefined -> PFinbound_num; + true -> NFinbound_num + end}. + +-compile({nowarn_unused_function,merge_msg_sdl_stun_request/3}). +merge_msg_sdl_stun_request(#sdl_stun_request{cookie = PFcookie, client_id = PFclient_id, network_id = PFnetwork_id, mac = PFmac, ip = PFip, nat_type = PFnat_type, v6_info = PFv6_info}, + #sdl_stun_request{cookie = NFcookie, client_id = NFclient_id, network_id = NFnetwork_id, mac = NFmac, ip = NFip, nat_type = NFnat_type, v6_info = NFv6_info}, TrUserData) -> + #sdl_stun_request{cookie = + if NFcookie =:= undefined -> PFcookie; + true -> NFcookie + end, + client_id = + if NFclient_id =:= undefined -> PFclient_id; + true -> NFclient_id + end, + network_id = + if NFnetwork_id =:= undefined -> PFnetwork_id; + true -> NFnetwork_id + end, + mac = + if NFmac =:= undefined -> PFmac; + true -> NFmac + end, + ip = + if NFip =:= undefined -> PFip; + true -> NFip + end, + nat_type = + if NFnat_type =:= undefined -> PFnat_type; + true -> NFnat_type + end, + v6_info = + if PFv6_info /= undefined, NFv6_info /= undefined -> merge_msg_sdl_v6_info(PFv6_info, NFv6_info, TrUserData); + PFv6_info == undefined -> NFv6_info; + NFv6_info == undefined -> PFv6_info + end}. + +-compile({nowarn_unused_function,merge_msg_sdl_stun_reply/3}). +merge_msg_sdl_stun_reply(#sdl_stun_reply{cookie = PFcookie}, #sdl_stun_reply{cookie = NFcookie}, _) -> + #sdl_stun_reply{cookie = + if NFcookie =:= undefined -> PFcookie; + true -> NFcookie + end}. + +-compile({nowarn_unused_function,merge_msg_sdl_data/3}). +merge_msg_sdl_data(#sdl_data{network_id = PFnetwork_id, src_mac = PFsrc_mac, dst_mac = PFdst_mac, is_p2p = PFis_p2p, ttl = PFttl, data = PFdata}, + #sdl_data{network_id = NFnetwork_id, src_mac = NFsrc_mac, dst_mac = NFdst_mac, is_p2p = NFis_p2p, ttl = NFttl, data = NFdata}, _) -> + #sdl_data{network_id = + if NFnetwork_id =:= undefined -> PFnetwork_id; + true -> NFnetwork_id + end, + src_mac = + if NFsrc_mac =:= undefined -> PFsrc_mac; + true -> NFsrc_mac + end, + dst_mac = + if NFdst_mac =:= undefined -> PFdst_mac; + true -> NFdst_mac + end, + is_p2p = + if NFis_p2p =:= undefined -> PFis_p2p; + true -> NFis_p2p + end, + ttl = + if NFttl =:= undefined -> PFttl; + true -> NFttl + end, + data = + if NFdata =:= undefined -> PFdata; + true -> NFdata + end}. + +-compile({nowarn_unused_function,merge_msg_sdl_register/3}). +merge_msg_sdl_register(#sdl_register{network_id = PFnetwork_id, src_mac = PFsrc_mac, dst_mac = PFdst_mac}, #sdl_register{network_id = NFnetwork_id, src_mac = NFsrc_mac, dst_mac = NFdst_mac}, _) -> + #sdl_register{network_id = + if NFnetwork_id =:= undefined -> PFnetwork_id; + true -> NFnetwork_id + end, + src_mac = + if NFsrc_mac =:= undefined -> PFsrc_mac; + true -> NFsrc_mac + end, + dst_mac = + if NFdst_mac =:= undefined -> PFdst_mac; + true -> NFdst_mac + end}. + +-compile({nowarn_unused_function,merge_msg_sdl_register_ack/3}). +merge_msg_sdl_register_ack(#sdl_register_ack{network_id = PFnetwork_id, src_mac = PFsrc_mac, dst_mac = PFdst_mac}, #sdl_register_ack{network_id = NFnetwork_id, src_mac = NFsrc_mac, dst_mac = NFdst_mac}, _) -> + #sdl_register_ack{network_id = + if NFnetwork_id =:= undefined -> PFnetwork_id; + true -> NFnetwork_id + end, + src_mac = + if NFsrc_mac =:= undefined -> PFsrc_mac; + true -> NFsrc_mac + end, + dst_mac = + if NFdst_mac =:= undefined -> PFdst_mac; + true -> NFdst_mac + end}. + +-compile({nowarn_unused_function,merge_msg_sdl_stun_probe/3}). +merge_msg_sdl_stun_probe(#sdl_stun_probe{cookie = PFcookie, attr = PFattr}, #sdl_stun_probe{cookie = NFcookie, attr = NFattr}, _) -> + #sdl_stun_probe{cookie = + if NFcookie =:= undefined -> PFcookie; + true -> NFcookie + end, + attr = + if NFattr =:= undefined -> PFattr; + true -> NFattr + end}. + +-compile({nowarn_unused_function,merge_msg_sdl_stun_probe_reply/3}). +merge_msg_sdl_stun_probe_reply(#sdl_stun_probe_reply{cookie = PFcookie, port = PFport, ip = PFip}, #sdl_stun_probe_reply{cookie = NFcookie, port = NFport, ip = NFip}, _) -> + #sdl_stun_probe_reply{cookie = + if NFcookie =:= undefined -> PFcookie; + true -> NFcookie + end, + port = + if NFport =:= undefined -> PFport; + true -> NFport + end, + ip = + if NFip =:= undefined -> PFip; + true -> NFip + end}. + + +verify_msg(Msg) when tuple_size(Msg) >= 1 -> verify_msg(Msg, element(1, Msg), []); +verify_msg(X) -> mk_type_error(not_a_known_message, X, []). + +verify_msg(Msg, MsgName) when is_atom(MsgName) -> verify_msg(Msg, MsgName, []); +verify_msg(Msg, Opts) when tuple_size(Msg) >= 1 -> verify_msg(Msg, element(1, Msg), Opts); +verify_msg(X, _Opts) -> mk_type_error(not_a_known_message, X, []). + +verify_msg(Msg, MsgName, Opts) -> + TrUserData = proplists:get_value(user_data, Opts), + case MsgName of + sdl_v4_info -> v_msg_sdl_v4_info(Msg, [MsgName], TrUserData); + sdl_v6_info -> v_msg_sdl_v6_info(Msg, [MsgName], TrUserData); + sdl_dev_addr -> v_msg_sdl_dev_addr(Msg, [MsgName], TrUserData); + sdl_empty -> v_msg_sdl_empty(Msg, [MsgName], TrUserData); + sdl_register_super -> v_msg_sdl_register_super(Msg, [MsgName], TrUserData); + sdl_register_super_ack -> v_msg_sdl_register_super_ack(Msg, [MsgName], TrUserData); + sdl_register_super_nak -> v_msg_sdl_register_super_nak(Msg, [MsgName], TrUserData); + sdl_query_info -> v_msg_sdl_query_info(Msg, [MsgName], TrUserData); + sdl_peer_info -> v_msg_sdl_peer_info(Msg, [MsgName], TrUserData); + sdl_nat_changed_event -> v_msg_sdl_nat_changed_event(Msg, [MsgName], TrUserData); + sdl_send_register_event -> v_msg_sdl_send_register_event(Msg, [MsgName], TrUserData); + sdl_network_shutdown_event -> v_msg_sdl_network_shutdown_event(Msg, [MsgName], TrUserData); + sdl_change_network_command -> v_msg_sdl_change_network_command(Msg, [MsgName], TrUserData); + sdl_command_ack -> v_msg_sdl_command_ack(Msg, [MsgName], TrUserData); + sdl_flows -> v_msg_sdl_flows(Msg, [MsgName], TrUserData); + sdl_stun_request -> v_msg_sdl_stun_request(Msg, [MsgName], TrUserData); + sdl_stun_reply -> v_msg_sdl_stun_reply(Msg, [MsgName], TrUserData); + sdl_data -> v_msg_sdl_data(Msg, [MsgName], TrUserData); + sdl_register -> v_msg_sdl_register(Msg, [MsgName], TrUserData); + sdl_register_ack -> v_msg_sdl_register_ack(Msg, [MsgName], TrUserData); + sdl_stun_probe -> v_msg_sdl_stun_probe(Msg, [MsgName], TrUserData); + sdl_stun_probe_reply -> v_msg_sdl_stun_probe_reply(Msg, [MsgName], TrUserData); + _ -> mk_type_error(not_a_known_message, Msg, []) + end. + + +-compile({nowarn_unused_function,v_submsg_sdl_v4_info/3}). +-dialyzer({nowarn_function,v_submsg_sdl_v4_info/3}). +v_submsg_sdl_v4_info(Msg, Path, TrUserData) -> v_msg_sdl_v4_info(Msg, Path, TrUserData). + +-compile({nowarn_unused_function,v_msg_sdl_v4_info/3}). +-dialyzer({nowarn_function,v_msg_sdl_v4_info/3}). +v_msg_sdl_v4_info(#sdl_v4_info{port = F1, v4 = F2, nat_type = F3}, Path, TrUserData) -> + if F1 == undefined -> ok; + true -> v_type_uint32(F1, [port | Path], TrUserData) + end, + if F2 == undefined -> ok; + true -> v_type_bytes(F2, [v4 | Path], TrUserData) + end, + if F3 == undefined -> ok; + true -> v_type_uint32(F3, [nat_type | Path], TrUserData) + end, + ok; +v_msg_sdl_v4_info(X, Path, _TrUserData) -> mk_type_error({expected_msg, sdl_v4_info}, X, Path). + +-compile({nowarn_unused_function,v_submsg_sdl_v6_info/3}). +-dialyzer({nowarn_function,v_submsg_sdl_v6_info/3}). +v_submsg_sdl_v6_info(Msg, Path, TrUserData) -> v_msg_sdl_v6_info(Msg, Path, TrUserData). + +-compile({nowarn_unused_function,v_msg_sdl_v6_info/3}). +-dialyzer({nowarn_function,v_msg_sdl_v6_info/3}). +v_msg_sdl_v6_info(#sdl_v6_info{port = F1, v6 = F2}, Path, TrUserData) -> + if F1 == undefined -> ok; + true -> v_type_uint32(F1, [port | Path], TrUserData) + end, + if F2 == undefined -> ok; + true -> v_type_bytes(F2, [v6 | Path], TrUserData) + end, + ok; +v_msg_sdl_v6_info(X, Path, _TrUserData) -> mk_type_error({expected_msg, sdl_v6_info}, X, Path). + +-compile({nowarn_unused_function,v_submsg_sdl_dev_addr/3}). +-dialyzer({nowarn_function,v_submsg_sdl_dev_addr/3}). +v_submsg_sdl_dev_addr(Msg, Path, TrUserData) -> v_msg_sdl_dev_addr(Msg, Path, TrUserData). + +-compile({nowarn_unused_function,v_msg_sdl_dev_addr/3}). +-dialyzer({nowarn_function,v_msg_sdl_dev_addr/3}). +v_msg_sdl_dev_addr(#sdl_dev_addr{network_id = F1, mac = F2, net_addr = F3, net_bit_len = F4}, Path, TrUserData) -> + if F1 == undefined -> ok; + true -> v_type_uint32(F1, [network_id | Path], TrUserData) + end, + if F2 == undefined -> ok; + true -> v_type_bytes(F2, [mac | Path], TrUserData) + end, + if F3 == undefined -> ok; + true -> v_type_uint32(F3, [net_addr | Path], TrUserData) + end, + if F4 == undefined -> ok; + true -> v_type_uint32(F4, [net_bit_len | Path], TrUserData) + end, + ok; +v_msg_sdl_dev_addr(X, Path, _TrUserData) -> mk_type_error({expected_msg, sdl_dev_addr}, X, Path). + +-compile({nowarn_unused_function,v_msg_sdl_empty/3}). +-dialyzer({nowarn_function,v_msg_sdl_empty/3}). +v_msg_sdl_empty(#sdl_empty{}, _Path, _) -> ok; +v_msg_sdl_empty(X, Path, _TrUserData) -> mk_type_error({expected_msg, sdl_empty}, X, Path). + +-compile({nowarn_unused_function,v_msg_sdl_register_super/3}). +-dialyzer({nowarn_function,v_msg_sdl_register_super/3}). +v_msg_sdl_register_super(#sdl_register_super{version = F1, installed_channel = F2, client_id = F3, dev_addr = F4, pub_key = F5, token = F6}, Path, TrUserData) -> + if F1 == undefined -> ok; + true -> v_type_uint32(F1, [version | Path], TrUserData) + end, + if F2 == undefined -> ok; + true -> v_type_string(F2, [installed_channel | Path], TrUserData) + end, + if F3 == undefined -> ok; + true -> v_type_string(F3, [client_id | Path], TrUserData) + end, + if F4 == undefined -> ok; + true -> v_submsg_sdl_dev_addr(F4, [dev_addr | Path], TrUserData) + end, + if F5 == undefined -> ok; + true -> v_type_string(F5, [pub_key | Path], TrUserData) + end, + if F6 == undefined -> ok; + true -> v_type_string(F6, [token | Path], TrUserData) + end, + ok; +v_msg_sdl_register_super(X, Path, _TrUserData) -> mk_type_error({expected_msg, sdl_register_super}, X, Path). + +-compile({nowarn_unused_function,v_msg_sdl_register_super_ack/3}). +-dialyzer({nowarn_function,v_msg_sdl_register_super_ack/3}). +v_msg_sdl_register_super_ack(#sdl_register_super_ack{dev_addr = F1, aes_key = F2, upgrade_type = F3, upgrade_prompt = F4, upgrade_address = F5}, Path, TrUserData) -> + if F1 == undefined -> ok; + true -> v_submsg_sdl_dev_addr(F1, [dev_addr | Path], TrUserData) + end, + if F2 == undefined -> ok; + true -> v_type_bytes(F2, [aes_key | Path], TrUserData) + end, + if F3 == undefined -> ok; + true -> v_type_uint32(F3, [upgrade_type | Path], TrUserData) + end, + if F4 == undefined -> ok; + true -> v_type_string(F4, [upgrade_prompt | Path], TrUserData) + end, + if F5 == undefined -> ok; + true -> v_type_string(F5, [upgrade_address | Path], TrUserData) + end, + ok; +v_msg_sdl_register_super_ack(X, Path, _TrUserData) -> mk_type_error({expected_msg, sdl_register_super_ack}, X, Path). + +-compile({nowarn_unused_function,v_msg_sdl_register_super_nak/3}). +-dialyzer({nowarn_function,v_msg_sdl_register_super_nak/3}). +v_msg_sdl_register_super_nak(#sdl_register_super_nak{error_code = F1, error_message = F2}, Path, TrUserData) -> + if F1 == undefined -> ok; + true -> v_type_uint32(F1, [error_code | Path], TrUserData) + end, + if F2 == undefined -> ok; + true -> v_type_string(F2, [error_message | Path], TrUserData) + end, + ok; +v_msg_sdl_register_super_nak(X, Path, _TrUserData) -> mk_type_error({expected_msg, sdl_register_super_nak}, X, Path). + +-compile({nowarn_unused_function,v_msg_sdl_query_info/3}). +-dialyzer({nowarn_function,v_msg_sdl_query_info/3}). +v_msg_sdl_query_info(#sdl_query_info{dst_mac = F1}, Path, TrUserData) -> + if F1 == undefined -> ok; + true -> v_type_bytes(F1, [dst_mac | Path], TrUserData) + end, + ok; +v_msg_sdl_query_info(X, Path, _TrUserData) -> mk_type_error({expected_msg, sdl_query_info}, X, Path). + +-compile({nowarn_unused_function,v_msg_sdl_peer_info/3}). +-dialyzer({nowarn_function,v_msg_sdl_peer_info/3}). +v_msg_sdl_peer_info(#sdl_peer_info{dst_mac = F1, v4_info = F2, v6_info = F3}, Path, TrUserData) -> + if F1 == undefined -> ok; + true -> v_type_bytes(F1, [dst_mac | Path], TrUserData) + end, + if F2 == undefined -> ok; + true -> v_submsg_sdl_v4_info(F2, [v4_info | Path], TrUserData) + end, + if F3 == undefined -> ok; + true -> v_submsg_sdl_v6_info(F3, [v6_info | Path], TrUserData) + end, + ok; +v_msg_sdl_peer_info(X, Path, _TrUserData) -> mk_type_error({expected_msg, sdl_peer_info}, X, Path). + +-compile({nowarn_unused_function,v_msg_sdl_nat_changed_event/3}). +-dialyzer({nowarn_function,v_msg_sdl_nat_changed_event/3}). +v_msg_sdl_nat_changed_event(#sdl_nat_changed_event{mac = F1, ip = F2}, Path, TrUserData) -> + if F1 == undefined -> ok; + true -> v_type_bytes(F1, [mac | Path], TrUserData) + end, + if F2 == undefined -> ok; + true -> v_type_uint32(F2, [ip | Path], TrUserData) + end, + ok; +v_msg_sdl_nat_changed_event(X, Path, _TrUserData) -> mk_type_error({expected_msg, sdl_nat_changed_event}, X, Path). + +-compile({nowarn_unused_function,v_msg_sdl_send_register_event/3}). +-dialyzer({nowarn_function,v_msg_sdl_send_register_event/3}). +v_msg_sdl_send_register_event(#sdl_send_register_event{dst_mac = F1, nat_ip = F2, nat_port = F3, nat_type = F4, v6_info = F5}, Path, TrUserData) -> + if F1 == undefined -> ok; + true -> v_type_bytes(F1, [dst_mac | Path], TrUserData) + end, + if F2 == undefined -> ok; + true -> v_type_uint32(F2, [nat_ip | Path], TrUserData) + end, + if F3 == undefined -> ok; + true -> v_type_uint32(F3, [nat_port | Path], TrUserData) + end, + if F4 == undefined -> ok; + true -> v_type_uint32(F4, [nat_type | Path], TrUserData) + end, + if F5 == undefined -> ok; + true -> v_submsg_sdl_v6_info(F5, [v6_info | Path], TrUserData) + end, + ok; +v_msg_sdl_send_register_event(X, Path, _TrUserData) -> mk_type_error({expected_msg, sdl_send_register_event}, X, Path). + +-compile({nowarn_unused_function,v_msg_sdl_network_shutdown_event/3}). +-dialyzer({nowarn_function,v_msg_sdl_network_shutdown_event/3}). +v_msg_sdl_network_shutdown_event(#sdl_network_shutdown_event{message = F1}, Path, TrUserData) -> + if F1 == undefined -> ok; + true -> v_type_string(F1, [message | Path], TrUserData) + end, + ok; +v_msg_sdl_network_shutdown_event(X, Path, _TrUserData) -> mk_type_error({expected_msg, sdl_network_shutdown_event}, X, Path). + +-compile({nowarn_unused_function,v_msg_sdl_change_network_command/3}). +-dialyzer({nowarn_function,v_msg_sdl_change_network_command/3}). +v_msg_sdl_change_network_command(#sdl_change_network_command{dev_addr = F1, aes_key = F2}, Path, TrUserData) -> + if F1 == undefined -> ok; + true -> v_submsg_sdl_dev_addr(F1, [dev_addr | Path], TrUserData) + end, + if F2 == undefined -> ok; + true -> v_type_bytes(F2, [aes_key | Path], TrUserData) + end, + ok; +v_msg_sdl_change_network_command(X, Path, _TrUserData) -> mk_type_error({expected_msg, sdl_change_network_command}, X, Path). + +-compile({nowarn_unused_function,v_msg_sdl_command_ack/3}). +-dialyzer({nowarn_function,v_msg_sdl_command_ack/3}). +v_msg_sdl_command_ack(#sdl_command_ack{status = F1, message = F2}, Path, TrUserData) -> + if F1 == undefined -> ok; + true -> v_type_bool(F1, [status | Path], TrUserData) + end, + if F2 == undefined -> ok; + true -> v_type_string(F2, [message | Path], TrUserData) + end, + ok; +v_msg_sdl_command_ack(X, Path, _TrUserData) -> mk_type_error({expected_msg, sdl_command_ack}, X, Path). + +-compile({nowarn_unused_function,v_msg_sdl_flows/3}). +-dialyzer({nowarn_function,v_msg_sdl_flows/3}). +v_msg_sdl_flows(#sdl_flows{forward_num = F1, p2p_num = F2, inbound_num = F3}, Path, TrUserData) -> + if F1 == undefined -> ok; + true -> v_type_uint32(F1, [forward_num | Path], TrUserData) + end, + if F2 == undefined -> ok; + true -> v_type_uint32(F2, [p2p_num | Path], TrUserData) + end, + if F3 == undefined -> ok; + true -> v_type_uint32(F3, [inbound_num | Path], TrUserData) + end, + ok; +v_msg_sdl_flows(X, Path, _TrUserData) -> mk_type_error({expected_msg, sdl_flows}, X, Path). + +-compile({nowarn_unused_function,v_msg_sdl_stun_request/3}). +-dialyzer({nowarn_function,v_msg_sdl_stun_request/3}). +v_msg_sdl_stun_request(#sdl_stun_request{cookie = F1, client_id = F2, network_id = F3, mac = F4, ip = F5, nat_type = F6, v6_info = F7}, Path, TrUserData) -> + if F1 == undefined -> ok; + true -> v_type_uint32(F1, [cookie | Path], TrUserData) + end, + if F2 == undefined -> ok; + true -> v_type_string(F2, [client_id | Path], TrUserData) + end, + if F3 == undefined -> ok; + true -> v_type_uint32(F3, [network_id | Path], TrUserData) + end, + if F4 == undefined -> ok; + true -> v_type_bytes(F4, [mac | Path], TrUserData) + end, + if F5 == undefined -> ok; + true -> v_type_uint32(F5, [ip | Path], TrUserData) + end, + if F6 == undefined -> ok; + true -> v_type_uint32(F6, [nat_type | Path], TrUserData) + end, + if F7 == undefined -> ok; + true -> v_submsg_sdl_v6_info(F7, [v6_info | Path], TrUserData) + end, + ok; +v_msg_sdl_stun_request(X, Path, _TrUserData) -> mk_type_error({expected_msg, sdl_stun_request}, X, Path). + +-compile({nowarn_unused_function,v_msg_sdl_stun_reply/3}). +-dialyzer({nowarn_function,v_msg_sdl_stun_reply/3}). +v_msg_sdl_stun_reply(#sdl_stun_reply{cookie = F1}, Path, TrUserData) -> + if F1 == undefined -> ok; + true -> v_type_uint32(F1, [cookie | Path], TrUserData) + end, + ok; +v_msg_sdl_stun_reply(X, Path, _TrUserData) -> mk_type_error({expected_msg, sdl_stun_reply}, X, Path). + +-compile({nowarn_unused_function,v_msg_sdl_data/3}). +-dialyzer({nowarn_function,v_msg_sdl_data/3}). +v_msg_sdl_data(#sdl_data{network_id = F1, src_mac = F2, dst_mac = F3, is_p2p = F4, ttl = F5, data = F6}, Path, TrUserData) -> + if F1 == undefined -> ok; + true -> v_type_uint32(F1, [network_id | Path], TrUserData) + end, + if F2 == undefined -> ok; + true -> v_type_bytes(F2, [src_mac | Path], TrUserData) + end, + if F3 == undefined -> ok; + true -> v_type_bytes(F3, [dst_mac | Path], TrUserData) + end, + if F4 == undefined -> ok; + true -> v_type_bool(F4, [is_p2p | Path], TrUserData) + end, + if F5 == undefined -> ok; + true -> v_type_uint32(F5, [ttl | Path], TrUserData) + end, + if F6 == undefined -> ok; + true -> v_type_bytes(F6, [data | Path], TrUserData) + end, + ok; +v_msg_sdl_data(X, Path, _TrUserData) -> mk_type_error({expected_msg, sdl_data}, X, Path). + +-compile({nowarn_unused_function,v_msg_sdl_register/3}). +-dialyzer({nowarn_function,v_msg_sdl_register/3}). +v_msg_sdl_register(#sdl_register{network_id = F1, src_mac = F2, dst_mac = F3}, Path, TrUserData) -> + if F1 == undefined -> ok; + true -> v_type_uint32(F1, [network_id | Path], TrUserData) + end, + if F2 == undefined -> ok; + true -> v_type_bytes(F2, [src_mac | Path], TrUserData) + end, + if F3 == undefined -> ok; + true -> v_type_bytes(F3, [dst_mac | Path], TrUserData) + end, + ok; +v_msg_sdl_register(X, Path, _TrUserData) -> mk_type_error({expected_msg, sdl_register}, X, Path). + +-compile({nowarn_unused_function,v_msg_sdl_register_ack/3}). +-dialyzer({nowarn_function,v_msg_sdl_register_ack/3}). +v_msg_sdl_register_ack(#sdl_register_ack{network_id = F1, src_mac = F2, dst_mac = F3}, Path, TrUserData) -> + if F1 == undefined -> ok; + true -> v_type_uint32(F1, [network_id | Path], TrUserData) + end, + if F2 == undefined -> ok; + true -> v_type_bytes(F2, [src_mac | Path], TrUserData) + end, + if F3 == undefined -> ok; + true -> v_type_bytes(F3, [dst_mac | Path], TrUserData) + end, + ok; +v_msg_sdl_register_ack(X, Path, _TrUserData) -> mk_type_error({expected_msg, sdl_register_ack}, X, Path). + +-compile({nowarn_unused_function,v_msg_sdl_stun_probe/3}). +-dialyzer({nowarn_function,v_msg_sdl_stun_probe/3}). +v_msg_sdl_stun_probe(#sdl_stun_probe{cookie = F1, attr = F2}, Path, TrUserData) -> + if F1 == undefined -> ok; + true -> v_type_uint32(F1, [cookie | Path], TrUserData) + end, + if F2 == undefined -> ok; + true -> v_type_uint32(F2, [attr | Path], TrUserData) + end, + ok; +v_msg_sdl_stun_probe(X, Path, _TrUserData) -> mk_type_error({expected_msg, sdl_stun_probe}, X, Path). + +-compile({nowarn_unused_function,v_msg_sdl_stun_probe_reply/3}). +-dialyzer({nowarn_function,v_msg_sdl_stun_probe_reply/3}). +v_msg_sdl_stun_probe_reply(#sdl_stun_probe_reply{cookie = F1, port = F2, ip = F3}, Path, TrUserData) -> + if F1 == undefined -> ok; + true -> v_type_uint32(F1, [cookie | Path], TrUserData) + end, + if F2 == undefined -> ok; + true -> v_type_uint32(F2, [port | Path], TrUserData) + end, + if F3 == undefined -> ok; + true -> v_type_uint32(F3, [ip | Path], TrUserData) + end, + ok; +v_msg_sdl_stun_probe_reply(X, Path, _TrUserData) -> mk_type_error({expected_msg, sdl_stun_probe_reply}, X, Path). + +-compile({nowarn_unused_function,v_type_uint32/3}). +-dialyzer({nowarn_function,v_type_uint32/3}). +v_type_uint32(N, _Path, _TrUserData) when is_integer(N), 0 =< N, N =< 4294967295 -> ok; +v_type_uint32(N, Path, _TrUserData) when is_integer(N) -> mk_type_error({value_out_of_range, uint32, unsigned, 32}, N, Path); +v_type_uint32(X, Path, _TrUserData) -> mk_type_error({bad_integer, uint32, unsigned, 32}, X, Path). + +-compile({nowarn_unused_function,v_type_bool/3}). +-dialyzer({nowarn_function,v_type_bool/3}). +v_type_bool(false, _Path, _TrUserData) -> ok; +v_type_bool(true, _Path, _TrUserData) -> ok; +v_type_bool(0, _Path, _TrUserData) -> ok; +v_type_bool(1, _Path, _TrUserData) -> ok; +v_type_bool(X, Path, _TrUserData) -> mk_type_error(bad_boolean_value, X, Path). + +-compile({nowarn_unused_function,v_type_string/3}). +-dialyzer({nowarn_function,v_type_string/3}). +v_type_string(S, Path, _TrUserData) when is_list(S); is_binary(S) -> + try unicode:characters_to_binary(S) of + B when is_binary(B) -> ok; + {error, _, _} -> mk_type_error(bad_unicode_string, S, Path) + catch + error:badarg -> mk_type_error(bad_unicode_string, S, Path) + end; +v_type_string(X, Path, _TrUserData) -> mk_type_error(bad_unicode_string, X, Path). + +-compile({nowarn_unused_function,v_type_bytes/3}). +-dialyzer({nowarn_function,v_type_bytes/3}). +v_type_bytes(B, _Path, _TrUserData) when is_binary(B) -> ok; +v_type_bytes(B, _Path, _TrUserData) when is_list(B) -> ok; +v_type_bytes(X, Path, _TrUserData) -> mk_type_error(bad_binary_value, X, Path). + +-compile({nowarn_unused_function,mk_type_error/3}). +-spec mk_type_error(_, _, list()) -> no_return(). +mk_type_error(Error, ValueSeen, Path) -> + Path2 = prettify_path(Path), + erlang:error({gpb_type_error, {Error, [{value, ValueSeen}, {path, Path2}]}}). + + +-compile({nowarn_unused_function,prettify_path/1}). +-dialyzer({nowarn_function,prettify_path/1}). +prettify_path([]) -> top_level; +prettify_path(PathR) -> lists:append(lists:join(".", lists:map(fun atom_to_list/1, lists:reverse(PathR)))). + + +-compile({nowarn_unused_function,id/2}). +-compile({inline,id/2}). +id(X, _TrUserData) -> X. + +-compile({nowarn_unused_function,v_ok/3}). +-compile({inline,v_ok/3}). +v_ok(_Value, _Path, _TrUserData) -> ok. + +-compile({nowarn_unused_function,m_overwrite/3}). +-compile({inline,m_overwrite/3}). +m_overwrite(_Prev, New, _TrUserData) -> New. + +-compile({nowarn_unused_function,cons/3}). +-compile({inline,cons/3}). +cons(Elem, Acc, _TrUserData) -> [Elem | Acc]. + +-compile({nowarn_unused_function,lists_reverse/2}). +-compile({inline,lists_reverse/2}). +'lists_reverse'(L, _TrUserData) -> lists:reverse(L). +-compile({nowarn_unused_function,'erlang_++'/3}). +-compile({inline,'erlang_++'/3}). +'erlang_++'(A, B, _TrUserData) -> A ++ B. + + +get_msg_defs() -> + [{{msg, sdl_v4_info}, + [#field{name = port, fnum = 1, rnum = 2, type = uint32, occurrence = defaulty, opts = []}, + #field{name = v4, fnum = 2, rnum = 3, type = bytes, occurrence = defaulty, opts = []}, + #field{name = nat_type, fnum = 3, rnum = 4, type = uint32, occurrence = defaulty, opts = []}]}, + {{msg, sdl_v6_info}, [#field{name = port, fnum = 1, rnum = 2, type = uint32, occurrence = defaulty, opts = []}, #field{name = v6, fnum = 2, rnum = 3, type = bytes, occurrence = defaulty, opts = []}]}, + {{msg, sdl_dev_addr}, + [#field{name = network_id, fnum = 1, rnum = 2, type = uint32, occurrence = defaulty, opts = []}, + #field{name = mac, fnum = 2, rnum = 3, type = bytes, occurrence = defaulty, opts = []}, + #field{name = net_addr, fnum = 3, rnum = 4, type = uint32, occurrence = defaulty, opts = []}, + #field{name = net_bit_len, fnum = 4, rnum = 5, type = uint32, occurrence = defaulty, opts = []}]}, + {{msg, sdl_empty}, []}, + {{msg, sdl_register_super}, + [#field{name = version, fnum = 1, rnum = 2, type = uint32, occurrence = defaulty, opts = []}, + #field{name = installed_channel, fnum = 2, rnum = 3, type = string, occurrence = defaulty, opts = []}, + #field{name = client_id, fnum = 3, rnum = 4, type = string, occurrence = defaulty, opts = []}, + #field{name = dev_addr, fnum = 4, rnum = 5, type = {msg, sdl_dev_addr}, occurrence = defaulty, opts = []}, + #field{name = pub_key, fnum = 5, rnum = 6, type = string, occurrence = defaulty, opts = []}, + #field{name = token, fnum = 6, rnum = 7, type = string, occurrence = defaulty, opts = []}]}, + {{msg, sdl_register_super_ack}, + [#field{name = dev_addr, fnum = 1, rnum = 2, type = {msg, sdl_dev_addr}, occurrence = defaulty, opts = []}, + #field{name = aes_key, fnum = 2, rnum = 3, type = bytes, occurrence = defaulty, opts = []}, + #field{name = upgrade_type, fnum = 3, rnum = 4, type = uint32, occurrence = defaulty, opts = []}, + #field{name = upgrade_prompt, fnum = 4, rnum = 5, type = string, occurrence = optional, opts = []}, + #field{name = upgrade_address, fnum = 5, rnum = 6, type = string, occurrence = optional, opts = []}]}, + {{msg, sdl_register_super_nak}, [#field{name = error_code, fnum = 1, rnum = 2, type = uint32, occurrence = defaulty, opts = []}, #field{name = error_message, fnum = 2, rnum = 3, type = string, occurrence = defaulty, opts = []}]}, + {{msg, sdl_query_info}, [#field{name = dst_mac, fnum = 1, rnum = 2, type = bytes, occurrence = defaulty, opts = []}]}, + {{msg, sdl_peer_info}, + [#field{name = dst_mac, fnum = 1, rnum = 2, type = bytes, occurrence = defaulty, opts = []}, + #field{name = v4_info, fnum = 2, rnum = 3, type = {msg, sdl_v4_info}, occurrence = defaulty, opts = []}, + #field{name = v6_info, fnum = 3, rnum = 4, type = {msg, sdl_v6_info}, occurrence = optional, opts = []}]}, + {{msg, sdl_nat_changed_event}, [#field{name = mac, fnum = 1, rnum = 2, type = bytes, occurrence = defaulty, opts = []}, #field{name = ip, fnum = 2, rnum = 3, type = uint32, occurrence = defaulty, opts = []}]}, + {{msg, sdl_send_register_event}, + [#field{name = dst_mac, fnum = 1, rnum = 2, type = bytes, occurrence = defaulty, opts = []}, + #field{name = nat_ip, fnum = 2, rnum = 3, type = uint32, occurrence = defaulty, opts = []}, + #field{name = nat_port, fnum = 3, rnum = 4, type = uint32, occurrence = defaulty, opts = []}, + #field{name = nat_type, fnum = 4, rnum = 5, type = uint32, occurrence = defaulty, opts = []}, + #field{name = v6_info, fnum = 5, rnum = 6, type = {msg, sdl_v6_info}, occurrence = optional, opts = []}]}, + {{msg, sdl_network_shutdown_event}, [#field{name = message, fnum = 1, rnum = 2, type = string, occurrence = defaulty, opts = []}]}, + {{msg, sdl_change_network_command}, [#field{name = dev_addr, fnum = 1, rnum = 2, type = {msg, sdl_dev_addr}, occurrence = defaulty, opts = []}, #field{name = aes_key, fnum = 2, rnum = 3, type = bytes, occurrence = defaulty, opts = []}]}, + {{msg, sdl_command_ack}, [#field{name = status, fnum = 1, rnum = 2, type = bool, occurrence = defaulty, opts = []}, #field{name = message, fnum = 2, rnum = 3, type = string, occurrence = optional, opts = []}]}, + {{msg, sdl_flows}, + [#field{name = forward_num, fnum = 1, rnum = 2, type = uint32, occurrence = defaulty, opts = []}, + #field{name = p2p_num, fnum = 2, rnum = 3, type = uint32, occurrence = defaulty, opts = []}, + #field{name = inbound_num, fnum = 3, rnum = 4, type = uint32, occurrence = defaulty, opts = []}]}, + {{msg, sdl_stun_request}, + [#field{name = cookie, fnum = 1, rnum = 2, type = uint32, occurrence = defaulty, opts = []}, + #field{name = client_id, fnum = 2, rnum = 3, type = string, occurrence = defaulty, opts = []}, + #field{name = network_id, fnum = 3, rnum = 4, type = uint32, occurrence = defaulty, opts = []}, + #field{name = mac, fnum = 4, rnum = 5, type = bytes, occurrence = defaulty, opts = []}, + #field{name = ip, fnum = 5, rnum = 6, type = uint32, occurrence = defaulty, opts = []}, + #field{name = nat_type, fnum = 6, rnum = 7, type = uint32, occurrence = defaulty, opts = []}, + #field{name = v6_info, fnum = 7, rnum = 8, type = {msg, sdl_v6_info}, occurrence = optional, opts = []}]}, + {{msg, sdl_stun_reply}, [#field{name = cookie, fnum = 1, rnum = 2, type = uint32, occurrence = defaulty, opts = []}]}, + {{msg, sdl_data}, + [#field{name = network_id, fnum = 1, rnum = 2, type = uint32, occurrence = defaulty, opts = []}, + #field{name = src_mac, fnum = 2, rnum = 3, type = bytes, occurrence = defaulty, opts = []}, + #field{name = dst_mac, fnum = 3, rnum = 4, type = bytes, occurrence = defaulty, opts = []}, + #field{name = is_p2p, fnum = 4, rnum = 5, type = bool, occurrence = defaulty, opts = []}, + #field{name = ttl, fnum = 5, rnum = 6, type = uint32, occurrence = defaulty, opts = []}, + #field{name = data, fnum = 6, rnum = 7, type = bytes, occurrence = defaulty, opts = []}]}, + {{msg, sdl_register}, + [#field{name = network_id, fnum = 1, rnum = 2, type = uint32, occurrence = defaulty, opts = []}, + #field{name = src_mac, fnum = 2, rnum = 3, type = bytes, occurrence = defaulty, opts = []}, + #field{name = dst_mac, fnum = 3, rnum = 4, type = bytes, occurrence = defaulty, opts = []}]}, + {{msg, sdl_register_ack}, + [#field{name = network_id, fnum = 1, rnum = 2, type = uint32, occurrence = defaulty, opts = []}, + #field{name = src_mac, fnum = 2, rnum = 3, type = bytes, occurrence = defaulty, opts = []}, + #field{name = dst_mac, fnum = 3, rnum = 4, type = bytes, occurrence = defaulty, opts = []}]}, + {{msg, sdl_stun_probe}, [#field{name = cookie, fnum = 1, rnum = 2, type = uint32, occurrence = defaulty, opts = []}, #field{name = attr, fnum = 2, rnum = 3, type = uint32, occurrence = defaulty, opts = []}]}, + {{msg, sdl_stun_probe_reply}, + [#field{name = cookie, fnum = 1, rnum = 2, type = uint32, occurrence = defaulty, opts = []}, + #field{name = port, fnum = 2, rnum = 3, type = uint32, occurrence = defaulty, opts = []}, + #field{name = ip, fnum = 3, rnum = 4, type = uint32, occurrence = defaulty, opts = []}]}]. + + +get_msg_names() -> + [sdl_v4_info, + sdl_v6_info, + sdl_dev_addr, + sdl_empty, + sdl_register_super, + sdl_register_super_ack, + sdl_register_super_nak, + sdl_query_info, + sdl_peer_info, + sdl_nat_changed_event, + sdl_send_register_event, + sdl_network_shutdown_event, + sdl_change_network_command, + sdl_command_ack, + sdl_flows, + sdl_stun_request, + sdl_stun_reply, + sdl_data, + sdl_register, + sdl_register_ack, + sdl_stun_probe, + sdl_stun_probe_reply]. + + +get_group_names() -> []. + + +get_msg_or_group_names() -> + [sdl_v4_info, + sdl_v6_info, + sdl_dev_addr, + sdl_empty, + sdl_register_super, + sdl_register_super_ack, + sdl_register_super_nak, + sdl_query_info, + sdl_peer_info, + sdl_nat_changed_event, + sdl_send_register_event, + sdl_network_shutdown_event, + sdl_change_network_command, + sdl_command_ack, + sdl_flows, + sdl_stun_request, + sdl_stun_reply, + sdl_data, + sdl_register, + sdl_register_ack, + sdl_stun_probe, + sdl_stun_probe_reply]. + + +get_enum_names() -> []. + + +fetch_msg_def(MsgName) -> + case find_msg_def(MsgName) of + Fs when is_list(Fs) -> Fs; + error -> erlang:error({no_such_msg, MsgName}) + end. + + +-spec fetch_enum_def(_) -> no_return(). +fetch_enum_def(EnumName) -> erlang:error({no_such_enum, EnumName}). + + +find_msg_def(sdl_v4_info) -> + [#field{name = port, fnum = 1, rnum = 2, type = uint32, occurrence = defaulty, opts = []}, + #field{name = v4, fnum = 2, rnum = 3, type = bytes, occurrence = defaulty, opts = []}, + #field{name = nat_type, fnum = 3, rnum = 4, type = uint32, occurrence = defaulty, opts = []}]; +find_msg_def(sdl_v6_info) -> [#field{name = port, fnum = 1, rnum = 2, type = uint32, occurrence = defaulty, opts = []}, #field{name = v6, fnum = 2, rnum = 3, type = bytes, occurrence = defaulty, opts = []}]; +find_msg_def(sdl_dev_addr) -> + [#field{name = network_id, fnum = 1, rnum = 2, type = uint32, occurrence = defaulty, opts = []}, + #field{name = mac, fnum = 2, rnum = 3, type = bytes, occurrence = defaulty, opts = []}, + #field{name = net_addr, fnum = 3, rnum = 4, type = uint32, occurrence = defaulty, opts = []}, + #field{name = net_bit_len, fnum = 4, rnum = 5, type = uint32, occurrence = defaulty, opts = []}]; +find_msg_def(sdl_empty) -> []; +find_msg_def(sdl_register_super) -> + [#field{name = version, fnum = 1, rnum = 2, type = uint32, occurrence = defaulty, opts = []}, + #field{name = installed_channel, fnum = 2, rnum = 3, type = string, occurrence = defaulty, opts = []}, + #field{name = client_id, fnum = 3, rnum = 4, type = string, occurrence = defaulty, opts = []}, + #field{name = dev_addr, fnum = 4, rnum = 5, type = {msg, sdl_dev_addr}, occurrence = defaulty, opts = []}, + #field{name = pub_key, fnum = 5, rnum = 6, type = string, occurrence = defaulty, opts = []}, + #field{name = token, fnum = 6, rnum = 7, type = string, occurrence = defaulty, opts = []}]; +find_msg_def(sdl_register_super_ack) -> + [#field{name = dev_addr, fnum = 1, rnum = 2, type = {msg, sdl_dev_addr}, occurrence = defaulty, opts = []}, + #field{name = aes_key, fnum = 2, rnum = 3, type = bytes, occurrence = defaulty, opts = []}, + #field{name = upgrade_type, fnum = 3, rnum = 4, type = uint32, occurrence = defaulty, opts = []}, + #field{name = upgrade_prompt, fnum = 4, rnum = 5, type = string, occurrence = optional, opts = []}, + #field{name = upgrade_address, fnum = 5, rnum = 6, type = string, occurrence = optional, opts = []}]; +find_msg_def(sdl_register_super_nak) -> [#field{name = error_code, fnum = 1, rnum = 2, type = uint32, occurrence = defaulty, opts = []}, #field{name = error_message, fnum = 2, rnum = 3, type = string, occurrence = defaulty, opts = []}]; +find_msg_def(sdl_query_info) -> [#field{name = dst_mac, fnum = 1, rnum = 2, type = bytes, occurrence = defaulty, opts = []}]; +find_msg_def(sdl_peer_info) -> + [#field{name = dst_mac, fnum = 1, rnum = 2, type = bytes, occurrence = defaulty, opts = []}, + #field{name = v4_info, fnum = 2, rnum = 3, type = {msg, sdl_v4_info}, occurrence = defaulty, opts = []}, + #field{name = v6_info, fnum = 3, rnum = 4, type = {msg, sdl_v6_info}, occurrence = optional, opts = []}]; +find_msg_def(sdl_nat_changed_event) -> [#field{name = mac, fnum = 1, rnum = 2, type = bytes, occurrence = defaulty, opts = []}, #field{name = ip, fnum = 2, rnum = 3, type = uint32, occurrence = defaulty, opts = []}]; +find_msg_def(sdl_send_register_event) -> + [#field{name = dst_mac, fnum = 1, rnum = 2, type = bytes, occurrence = defaulty, opts = []}, + #field{name = nat_ip, fnum = 2, rnum = 3, type = uint32, occurrence = defaulty, opts = []}, + #field{name = nat_port, fnum = 3, rnum = 4, type = uint32, occurrence = defaulty, opts = []}, + #field{name = nat_type, fnum = 4, rnum = 5, type = uint32, occurrence = defaulty, opts = []}, + #field{name = v6_info, fnum = 5, rnum = 6, type = {msg, sdl_v6_info}, occurrence = optional, opts = []}]; +find_msg_def(sdl_network_shutdown_event) -> [#field{name = message, fnum = 1, rnum = 2, type = string, occurrence = defaulty, opts = []}]; +find_msg_def(sdl_change_network_command) -> [#field{name = dev_addr, fnum = 1, rnum = 2, type = {msg, sdl_dev_addr}, occurrence = defaulty, opts = []}, #field{name = aes_key, fnum = 2, rnum = 3, type = bytes, occurrence = defaulty, opts = []}]; +find_msg_def(sdl_command_ack) -> [#field{name = status, fnum = 1, rnum = 2, type = bool, occurrence = defaulty, opts = []}, #field{name = message, fnum = 2, rnum = 3, type = string, occurrence = optional, opts = []}]; +find_msg_def(sdl_flows) -> + [#field{name = forward_num, fnum = 1, rnum = 2, type = uint32, occurrence = defaulty, opts = []}, + #field{name = p2p_num, fnum = 2, rnum = 3, type = uint32, occurrence = defaulty, opts = []}, + #field{name = inbound_num, fnum = 3, rnum = 4, type = uint32, occurrence = defaulty, opts = []}]; +find_msg_def(sdl_stun_request) -> + [#field{name = cookie, fnum = 1, rnum = 2, type = uint32, occurrence = defaulty, opts = []}, + #field{name = client_id, fnum = 2, rnum = 3, type = string, occurrence = defaulty, opts = []}, + #field{name = network_id, fnum = 3, rnum = 4, type = uint32, occurrence = defaulty, opts = []}, + #field{name = mac, fnum = 4, rnum = 5, type = bytes, occurrence = defaulty, opts = []}, + #field{name = ip, fnum = 5, rnum = 6, type = uint32, occurrence = defaulty, opts = []}, + #field{name = nat_type, fnum = 6, rnum = 7, type = uint32, occurrence = defaulty, opts = []}, + #field{name = v6_info, fnum = 7, rnum = 8, type = {msg, sdl_v6_info}, occurrence = optional, opts = []}]; +find_msg_def(sdl_stun_reply) -> [#field{name = cookie, fnum = 1, rnum = 2, type = uint32, occurrence = defaulty, opts = []}]; +find_msg_def(sdl_data) -> + [#field{name = network_id, fnum = 1, rnum = 2, type = uint32, occurrence = defaulty, opts = []}, + #field{name = src_mac, fnum = 2, rnum = 3, type = bytes, occurrence = defaulty, opts = []}, + #field{name = dst_mac, fnum = 3, rnum = 4, type = bytes, occurrence = defaulty, opts = []}, + #field{name = is_p2p, fnum = 4, rnum = 5, type = bool, occurrence = defaulty, opts = []}, + #field{name = ttl, fnum = 5, rnum = 6, type = uint32, occurrence = defaulty, opts = []}, + #field{name = data, fnum = 6, rnum = 7, type = bytes, occurrence = defaulty, opts = []}]; +find_msg_def(sdl_register) -> + [#field{name = network_id, fnum = 1, rnum = 2, type = uint32, occurrence = defaulty, opts = []}, + #field{name = src_mac, fnum = 2, rnum = 3, type = bytes, occurrence = defaulty, opts = []}, + #field{name = dst_mac, fnum = 3, rnum = 4, type = bytes, occurrence = defaulty, opts = []}]; +find_msg_def(sdl_register_ack) -> + [#field{name = network_id, fnum = 1, rnum = 2, type = uint32, occurrence = defaulty, opts = []}, + #field{name = src_mac, fnum = 2, rnum = 3, type = bytes, occurrence = defaulty, opts = []}, + #field{name = dst_mac, fnum = 3, rnum = 4, type = bytes, occurrence = defaulty, opts = []}]; +find_msg_def(sdl_stun_probe) -> [#field{name = cookie, fnum = 1, rnum = 2, type = uint32, occurrence = defaulty, opts = []}, #field{name = attr, fnum = 2, rnum = 3, type = uint32, occurrence = defaulty, opts = []}]; +find_msg_def(sdl_stun_probe_reply) -> + [#field{name = cookie, fnum = 1, rnum = 2, type = uint32, occurrence = defaulty, opts = []}, + #field{name = port, fnum = 2, rnum = 3, type = uint32, occurrence = defaulty, opts = []}, + #field{name = ip, fnum = 3, rnum = 4, type = uint32, occurrence = defaulty, opts = []}]; +find_msg_def(_) -> error. + + +find_enum_def(_) -> error. + + +-spec enum_symbol_by_value(_, _) -> no_return(). +enum_symbol_by_value(E, V) -> erlang:error({no_enum_defs, E, V}). + + +-spec enum_value_by_symbol(_, _) -> no_return(). +enum_value_by_symbol(E, V) -> erlang:error({no_enum_defs, E, V}). + + + +get_service_names() -> []. + + +get_service_def(_) -> error. + + +get_rpc_names(_) -> error. + + +find_rpc_def(_, _) -> error. + + + +-spec fetch_rpc_def(_, _) -> no_return(). +fetch_rpc_def(ServiceName, RpcName) -> erlang:error({no_such_rpc, ServiceName, RpcName}). + + +%% Convert a a fully qualified (ie with package name) service name +%% as a binary to a service name as an atom. +-spec fqbin_to_service_name(_) -> no_return(). +fqbin_to_service_name(X) -> error({gpb_error, {badservice, X}}). + + +%% Convert a service name as an atom to a fully qualified +%% (ie with package name) name as a binary. +-spec service_name_to_fqbin(_) -> no_return(). +service_name_to_fqbin(X) -> error({gpb_error, {badservice, X}}). + + +%% Convert a a fully qualified (ie with package name) service name +%% and an rpc name, both as binaries to a service name and an rpc +%% name, as atoms. +-spec fqbins_to_service_and_rpc_name(_, _) -> no_return(). +fqbins_to_service_and_rpc_name(S, R) -> error({gpb_error, {badservice_or_rpc, {S, R}}}). + + +%% Convert a service name and an rpc name, both as atoms, +%% to a fully qualified (ie with package name) service name and +%% an rpc name as binaries. +-spec service_and_rpc_name_to_fqbins(_, _) -> no_return(). +service_and_rpc_name_to_fqbins(S, R) -> error({gpb_error, {badservice_or_rpc, {S, R}}}). + + +fqbin_to_msg_name(<<"SDLV4Info">>) -> sdl_v4_info; +fqbin_to_msg_name(<<"SDLV6Info">>) -> sdl_v6_info; +fqbin_to_msg_name(<<"SDLDevAddr">>) -> sdl_dev_addr; +fqbin_to_msg_name(<<"SDLEmpty">>) -> sdl_empty; +fqbin_to_msg_name(<<"SDLRegisterSuper">>) -> sdl_register_super; +fqbin_to_msg_name(<<"SDLRegisterSuperAck">>) -> sdl_register_super_ack; +fqbin_to_msg_name(<<"SDLRegisterSuperNak">>) -> sdl_register_super_nak; +fqbin_to_msg_name(<<"SDLQueryInfo">>) -> sdl_query_info; +fqbin_to_msg_name(<<"SDLPeerInfo">>) -> sdl_peer_info; +fqbin_to_msg_name(<<"SDLNatChangedEvent">>) -> sdl_nat_changed_event; +fqbin_to_msg_name(<<"SDLSendRegisterEvent">>) -> sdl_send_register_event; +fqbin_to_msg_name(<<"SDLNetworkShutdownEvent">>) -> sdl_network_shutdown_event; +fqbin_to_msg_name(<<"SDLChangeNetworkCommand">>) -> sdl_change_network_command; +fqbin_to_msg_name(<<"SDLCommandAck">>) -> sdl_command_ack; +fqbin_to_msg_name(<<"SDLFlows">>) -> sdl_flows; +fqbin_to_msg_name(<<"SDLStunRequest">>) -> sdl_stun_request; +fqbin_to_msg_name(<<"SDLStunReply">>) -> sdl_stun_reply; +fqbin_to_msg_name(<<"SDLData">>) -> sdl_data; +fqbin_to_msg_name(<<"SDLRegister">>) -> sdl_register; +fqbin_to_msg_name(<<"SDLRegisterAck">>) -> sdl_register_ack; +fqbin_to_msg_name(<<"SDLStunProbe">>) -> sdl_stun_probe; +fqbin_to_msg_name(<<"SDLStunProbeReply">>) -> sdl_stun_probe_reply; +fqbin_to_msg_name(E) -> error({gpb_error, {badmsg, E}}). + + +msg_name_to_fqbin(sdl_v4_info) -> <<"SDLV4Info">>; +msg_name_to_fqbin(sdl_v6_info) -> <<"SDLV6Info">>; +msg_name_to_fqbin(sdl_dev_addr) -> <<"SDLDevAddr">>; +msg_name_to_fqbin(sdl_empty) -> <<"SDLEmpty">>; +msg_name_to_fqbin(sdl_register_super) -> <<"SDLRegisterSuper">>; +msg_name_to_fqbin(sdl_register_super_ack) -> <<"SDLRegisterSuperAck">>; +msg_name_to_fqbin(sdl_register_super_nak) -> <<"SDLRegisterSuperNak">>; +msg_name_to_fqbin(sdl_query_info) -> <<"SDLQueryInfo">>; +msg_name_to_fqbin(sdl_peer_info) -> <<"SDLPeerInfo">>; +msg_name_to_fqbin(sdl_nat_changed_event) -> <<"SDLNatChangedEvent">>; +msg_name_to_fqbin(sdl_send_register_event) -> <<"SDLSendRegisterEvent">>; +msg_name_to_fqbin(sdl_network_shutdown_event) -> <<"SDLNetworkShutdownEvent">>; +msg_name_to_fqbin(sdl_change_network_command) -> <<"SDLChangeNetworkCommand">>; +msg_name_to_fqbin(sdl_command_ack) -> <<"SDLCommandAck">>; +msg_name_to_fqbin(sdl_flows) -> <<"SDLFlows">>; +msg_name_to_fqbin(sdl_stun_request) -> <<"SDLStunRequest">>; +msg_name_to_fqbin(sdl_stun_reply) -> <<"SDLStunReply">>; +msg_name_to_fqbin(sdl_data) -> <<"SDLData">>; +msg_name_to_fqbin(sdl_register) -> <<"SDLRegister">>; +msg_name_to_fqbin(sdl_register_ack) -> <<"SDLRegisterAck">>; +msg_name_to_fqbin(sdl_stun_probe) -> <<"SDLStunProbe">>; +msg_name_to_fqbin(sdl_stun_probe_reply) -> <<"SDLStunProbeReply">>; +msg_name_to_fqbin(E) -> error({gpb_error, {badmsg, E}}). + + +-spec fqbin_to_enum_name(_) -> no_return(). +fqbin_to_enum_name(E) -> error({gpb_error, {badenum, E}}). + + +-spec enum_name_to_fqbin(_) -> no_return(). +enum_name_to_fqbin(E) -> error({gpb_error, {badenum, E}}). + + +get_package_name() -> undefined. + + +%% Whether or not the message names +%% are prepended with package name or not. +uses_packages() -> false. + + +source_basename() -> "sdlan_pb.proto". + + +%% Retrieve all proto file names, also imported ones. +%% The order is top-down. The first element is always the main +%% source file. The files are returned with extension, +%% see get_all_proto_names/0 for a version that returns +%% the basenames sans extension +get_all_source_basenames() -> ["sdlan_pb.proto"]. + + +%% Retrieve all proto file names, also imported ones. +%% The order is top-down. The first element is always the main +%% source file. The files are returned sans .proto extension, +%% to make it easier to use them with the various get_xyz_containment +%% functions. +get_all_proto_names() -> ["sdlan_pb"]. + + +get_msg_containment("sdlan_pb") -> + [sdl_change_network_command, + sdl_command_ack, + sdl_data, + sdl_dev_addr, + sdl_empty, + sdl_flows, + sdl_nat_changed_event, + sdl_network_shutdown_event, + sdl_peer_info, + sdl_query_info, + sdl_register, + sdl_register_ack, + sdl_register_super, + sdl_register_super_ack, + sdl_register_super_nak, + sdl_send_register_event, + sdl_stun_probe, + sdl_stun_probe_reply, + sdl_stun_reply, + sdl_stun_request, + sdl_v4_info, + sdl_v6_info]; +get_msg_containment(P) -> error({gpb_error, {badproto, P}}). + + +get_pkg_containment("sdlan_pb") -> undefined; +get_pkg_containment(P) -> error({gpb_error, {badproto, P}}). + + +get_service_containment("sdlan_pb") -> []; +get_service_containment(P) -> error({gpb_error, {badproto, P}}). + + +get_rpc_containment("sdlan_pb") -> []; +get_rpc_containment(P) -> error({gpb_error, {badproto, P}}). + + +get_enum_containment("sdlan_pb") -> []; +get_enum_containment(P) -> error({gpb_error, {badproto, P}}). + + +get_proto_by_msg_name_as_fqbin(<<"SDLData">>) -> "sdlan_pb"; +get_proto_by_msg_name_as_fqbin(<<"SDLRegisterSuper">>) -> "sdlan_pb"; +get_proto_by_msg_name_as_fqbin(<<"SDLRegister">>) -> "sdlan_pb"; +get_proto_by_msg_name_as_fqbin(<<"SDLDevAddr">>) -> "sdlan_pb"; +get_proto_by_msg_name_as_fqbin(<<"SDLFlows">>) -> "sdlan_pb"; +get_proto_by_msg_name_as_fqbin(<<"SDLStunRequest">>) -> "sdlan_pb"; +get_proto_by_msg_name_as_fqbin(<<"SDLSendRegisterEvent">>) -> "sdlan_pb"; +get_proto_by_msg_name_as_fqbin(<<"SDLNetworkShutdownEvent">>) -> "sdlan_pb"; +get_proto_by_msg_name_as_fqbin(<<"SDLNatChangedEvent">>) -> "sdlan_pb"; +get_proto_by_msg_name_as_fqbin(<<"SDLChangeNetworkCommand">>) -> "sdlan_pb"; +get_proto_by_msg_name_as_fqbin(<<"SDLStunProbe">>) -> "sdlan_pb"; +get_proto_by_msg_name_as_fqbin(<<"SDLStunReply">>) -> "sdlan_pb"; +get_proto_by_msg_name_as_fqbin(<<"SDLStunProbeReply">>) -> "sdlan_pb"; +get_proto_by_msg_name_as_fqbin(<<"SDLEmpty">>) -> "sdlan_pb"; +get_proto_by_msg_name_as_fqbin(<<"SDLRegisterSuperNak">>) -> "sdlan_pb"; +get_proto_by_msg_name_as_fqbin(<<"SDLRegisterSuperAck">>) -> "sdlan_pb"; +get_proto_by_msg_name_as_fqbin(<<"SDLRegisterAck">>) -> "sdlan_pb"; +get_proto_by_msg_name_as_fqbin(<<"SDLCommandAck">>) -> "sdlan_pb"; +get_proto_by_msg_name_as_fqbin(<<"SDLV6Info">>) -> "sdlan_pb"; +get_proto_by_msg_name_as_fqbin(<<"SDLV4Info">>) -> "sdlan_pb"; +get_proto_by_msg_name_as_fqbin(<<"SDLQueryInfo">>) -> "sdlan_pb"; +get_proto_by_msg_name_as_fqbin(<<"SDLPeerInfo">>) -> "sdlan_pb"; +get_proto_by_msg_name_as_fqbin(E) -> error({gpb_error, {badmsg, E}}). + + +-spec get_proto_by_service_name_as_fqbin(_) -> no_return(). +get_proto_by_service_name_as_fqbin(E) -> error({gpb_error, {badservice, E}}). + + +-spec get_proto_by_enum_name_as_fqbin(_) -> no_return(). +get_proto_by_enum_name_as_fqbin(E) -> error({gpb_error, {badenum, E}}). + + +-spec get_protos_by_pkg_name_as_fqbin(_) -> no_return(). +get_protos_by_pkg_name_as_fqbin(E) -> error({gpb_error, {badpkg, E}}). + + + +gpb_version_as_string() -> + "4.21.1". + +gpb_version_as_list() -> + [4,21,1]. + +gpb_version_source() -> + "git". diff --git a/apps/sdlan/src/sdlan_stun.erl b/apps/sdlan/src/sdlan_stun.erl new file mode 100644 index 0000000..16cc9ee --- /dev/null +++ b/apps/sdlan/src/sdlan_stun.erl @@ -0,0 +1,197 @@ +%%%------------------------------------------------------------------- +%%% @author anlicheng +%%% @copyright (C) 2024, +%%% @doc +%%% +%%% @end +%%% Created : 09. 4月 2024 17:37 +%%%------------------------------------------------------------------- +-module(sdlan_stun). +-author("anlicheng"). +-include("sdlan.hrl"). +-include("sdlan_pb.hrl"). + +-behaviour(gen_server). + +%% API +-export([start_link/2]). +-export([get_name/1]). + +%% gen_server callbacks +-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). + +-define(SERVER, ?MODULE). + +-record(state, { + socket, + stun_assist +}). + +%%%=================================================================== +%%% API +%%%=================================================================== + +-spec get_name(Id :: integer()) -> atom(). +get_name(Id) when is_integer(Id) -> + list_to_atom("sdlan_stun:" ++ integer_to_list(Id)). + +%% @doc Spawns the server and registers the local name (unique) +-spec(start_link(Name :: atom(), Port :: integer()) -> + {ok, Pid :: pid()} | ignore | {error, Reason :: term()}). +start_link(Name, Port) when is_atom(Name), is_integer(Port) -> + gen_server:start_link({local, Name}, ?MODULE, [Port], []). + +%%%=================================================================== +%%% gen_server callbacks +%%%=================================================================== + +%% @private +%% @doc Initializes the server +-spec(init(Args :: term()) -> + {ok, State :: #state{}} | {ok, State :: #state{}, timeout() | hibernate} | + {stop, Reason :: term()} | ignore). +init([Port]) -> + %% 需要提高进程的调度优先级 + erlang:process_flag(priority, max), + + {ok, Socket} = gen_udp:open(Port, [binary, {active, true}, {recbuf, 5 * 1024 * 1024}, {sndbuf, 5 * 1024 * 1024}]), + inet_udp:controlling_process(Socket, self()), + lager:debug("[sdlan_stun] start at port: ~p", [Port]), + + case application:get_env(sdlan, stun_assist) of + undefined -> + {ok, #state{socket = Socket, stun_assist = undefined}}; + {ok, StunAssist} -> + {ok, #state{socket = Socket, stun_assist = StunAssist}} + end. + +%% @private +%% @doc Handling call messages +-spec(handle_call(Request :: term(), From :: {pid(), Tag :: term()}, + State :: #state{}) -> + {reply, Reply :: term(), NewState :: #state{}} | + {reply, Reply :: term(), NewState :: #state{}, timeout() | hibernate} | + {noreply, NewState :: #state{}} | + {noreply, NewState :: #state{}, timeout() | hibernate} | + {stop, Reason :: term(), Reply :: term(), NewState :: #state{}} | + {stop, Reason :: term(), NewState :: #state{}}). +handle_call(_Request, _From, State = #state{}) -> + {reply, ok, State}. + +%% @private +%% @doc Handling cast messages +-spec(handle_cast(Request :: term(), State :: #state{}) -> + {noreply, NewState :: #state{}} | + {noreply, NewState :: #state{}, timeout() | hibernate} | + {stop, Reason :: term(), NewState :: #state{}}). + +%% 当前node下的转发,基于进程间的通讯 +handle_cast({stun_relay, Ip, Port, Reply}, State = #state{socket = Sock}) -> + ok = gen_udp:send(Sock, Ip, Port, Reply), + {noreply, State}. + +%% @private +%% @doc Handling all non call/cast messages +-spec(handle_info(Info :: timeout() | term(), State :: #state{}) -> + {noreply, NewState :: #state{}} | + {noreply, NewState :: #state{}, timeout() | hibernate} | + {stop, Reason :: term(), NewState :: #state{}}). + +handle_info({udp, Sock, Ip, Port, <>}, State = #state{socket = Sock}) -> + #sdl_stun_request{cookie = Cookie, client_id = ClientId, network_id = NetworkId, mac = Mac, nat_type = NatType, v6_info = V6Info} = sdlan_pb:decode_msg(Body, sdl_stun_request), + %% 告知网络当前的ip对应的nat的映射关系 + + case sdlan_network:get_pid(NetworkId) of + undefined -> + lager:debug("call me here stun request 11: ~p", [NetworkId]), + {noreply, State}; + NetworkPid when is_pid(NetworkPid) -> + sdlan_network:update_hole(NetworkPid, ClientId, Mac, {Ip, Port}, NatType, V6Info), + StunReply = sdlan_pb:encode_msg(#sdl_stun_reply{ + cookie = Cookie + }), + ok = gen_udp:send(Sock, Ip, Port, <>), + lager:debug("call me here stun request 12"), + {noreply, State} + end; + +%% 网络nat类型的探测机制, 需要借助其他服务一起才能实现 +%% 辅助节点没有assist的配置,不支持attr = 2的探测 +handle_info({udp, Sock, Ip = {Ip0, Ip1, Ip2, Ip3}, Port, <>}, State = #state{socket = Sock, stun_assist = StunAssist}) -> + #sdl_stun_probe{cookie = Cookie, attr = Attr} = sdlan_pb:decode_msg(Body, sdl_stun_probe), + lager:debug("[sdlan_stun] get stun_probe request, att: ~p", [Attr]), + + ProbeReply = sdlan_pb:encode_msg(#sdl_stun_probe_reply { + cookie = Cookie, + port = Port, + ip = int_ip(Ip) + }), + Packet = <>, + + case Attr of + ?STUN_ATTR_CHANGE_NONE -> + ok = gen_udp:send(Sock, Ip, Port, Packet); + ?STUN_ATTR_CHANGE_PORT -> + gen_server:cast('sdlan_stun:1:2', {stun_relay, Ip, Port, Packet}); + ?STUN_ATTR_CHANGE_PEER -> + case StunAssist of + {AssistIp, AssistPort} -> + gen_udp:send(Sock, AssistIp, AssistPort, <>); + undefined -> + ok + end + end, + {noreply, State}; + +%% 转发消息, 跨服务器的stun_reply的转发通过socket来转发 +handle_info({udp, Sock, _, _, <>}, State = #state{socket = Sock}) -> + lager:debug("[sdlan_stun] get stun_probe_replay request, reply: ~p", [Reply]), + gen_udp:send(Sock, {Ip0, Ip1, Ip2, Ip3}, Port, Reply), + {noreply, State}; + +handle_info({udp, _, _Ip, _Port, <>}, State = #state{socket = Sock}) -> + Data = #sdl_data{network_id = NetworkId, src_mac = SrcMac, dst_mac = DstMac, ttl = TTL} = sdlan_pb:decode_msg(Body, sdl_data), + + lager:debug("[sdlan_stun] stun data, src_mac: ~p, dst_mac: ~p", [sdlan_util:format_mac(SrcMac), sdlan_util:format_mac(DstMac)]), + + %% 重新打包数据ttl需要减1 + case sdlan_network:get_pid(NetworkId) of + NetworkPid when is_pid(NetworkPid) -> + NData = sdlan_pb:encode_msg(Data#sdl_data{ttl = TTL - 1, is_p2p = false}), + sdlan_network:forward(NetworkPid, Sock, SrcMac, DstMac, <>); + _ -> + ok + end, + + {noreply, State}; + +handle_info(Info, State) -> + lager:error("[sdlan_stun] get a unknown message: ~p, channel will closed", [Info]), + {noreply, State}. + +%% @private +%% @doc This function is called by a gen_server when it is about to +%% terminate. It should be the opposite of Module:init/1 and do any +%% necessary cleaning up. When it returns, the gen_server terminates +%% with Reason. The return value is ignored. +-spec(terminate(Reason :: (normal | shutdown | {shutdown, term()} | term()), + State :: #state{}) -> term()). +terminate(_Reason, _State = #state{}) -> + ok. + +%% @private +%% @doc Convert process state when code is changed +-spec(code_change(OldVsn :: term() | {down, term()}, State :: #state{}, + Extra :: term()) -> + {ok, NewState :: #state{}} | {error, Reason :: term()}). +code_change(_OldVsn, State = #state{}, _Extra) -> + {ok, State}. + +%%%=================================================================== +%%% Internal functions +%%%=================================================================== + +-spec int_ip(tuple()) -> integer(). +int_ip({Ip0, Ip1, Ip2, Ip3}) -> + <> = <>, + Ip. \ No newline at end of file diff --git a/apps/sdlan/src/sdlan_sup.erl b/apps/sdlan/src/sdlan_sup.erl new file mode 100644 index 0000000..fad7687 --- /dev/null +++ b/apps/sdlan/src/sdlan_sup.erl @@ -0,0 +1,71 @@ +%%%------------------------------------------------------------------- +%% @doc sdlan top level supervisor. +%% @end +%%%------------------------------------------------------------------- + +-module(sdlan_sup). + +-behaviour(supervisor). + +-export([start_link/0]). + +-export([init/1]). + +-define(SERVER, ?MODULE). + +start_link() -> + supervisor:start_link({local, ?SERVER}, ?MODULE, []). + +%% sup_flags() = #{strategy => strategy(), % optional +%% intensity => non_neg_integer(), % optional +%% period => pos_integer()} % optional +%% child_spec() = #{id => child_id(), % mandatory +%% start => mfargs(), % mandatory +%% restart => restart(), % optional +%% shutdown => shutdown(), % optional +%% type => worker(), % optional +%% modules => modules()} % optional +init([]) -> + SupFlags = #{strategy => one_for_one, intensity => 1000, period => 3600}, + + Specs = [ + #{ + id => sdlan_network_coordinator, + start => {sdlan_network_coordinator, start_link, []}, + restart => permanent, + shutdown => 2000, + type => worker, + modules => ['sdlan_network_coordinator'] + }, + #{ + id => sdlan_network_sup, + start => {sdlan_network_sup, start_link, []}, + restart => permanent, + shutdown => 2000, + type => supervisor, + modules => ['sdlan_network_sup'] + } + ], + + {ok, {SupFlags, pools() ++ Specs ++ stun_specs()}}. + +%% internal functions + +pools() -> + {ok, Pools} = application:get_env(sdlan, pools), + lists:map(fun({Name, PoolArgs, WorkerArgs}) -> + poolboy:child_spec(Name, [{name, {local, Name}}|PoolArgs], WorkerArgs) + end, Pools). + +stun_specs() -> + {ok, StunServers} = application:get_env(sdlan, stun_servers), + lists:map(fun({Name, Port}) -> + #{ + id => Name, + start => {sdlan_stun, start_link, [Name, Port]}, + restart => permanent, + shutdown => 2000, + type => worker, + modules => ['sdlan_stun'] + } + end, StunServers). \ No newline at end of file diff --git a/apps/sdlan/src/sdlan_test.erl b/apps/sdlan/src/sdlan_test.erl new file mode 100644 index 0000000..1bd30d5 --- /dev/null +++ b/apps/sdlan/src/sdlan_test.erl @@ -0,0 +1,18 @@ +%%%------------------------------------------------------------------- +%%% @author anlicheng +%%% @copyright (C) 2024, +%%% @doc +%%% +%%% @end +%%% Created : 09. 3月 2024 15:25 +%%%------------------------------------------------------------------- +-module(sdlan_test). +-author("anlicheng"). + +%% API +-export([test/1]). + +test(X) when X band 1 == 0 -> + ok; +test(_) -> + error. diff --git a/apps/sdlan/src/sdlan_util.erl b/apps/sdlan/src/sdlan_util.erl new file mode 100644 index 0000000..874c3d9 --- /dev/null +++ b/apps/sdlan/src/sdlan_util.erl @@ -0,0 +1,74 @@ +%%%------------------------------------------------------------------- +%%% @author anlicheng +%%% @copyright (C) 2024, +%%% @doc +%%% +%%% @end +%%% Created : 11. 3月 2024 11:10 +%%%------------------------------------------------------------------- +-module(sdlan_util). +-author("anlicheng"). + +%% API +-export([rand_byte/1, md5/1, format_mac/1, assert_call/2]). +-export([json_data/1, json_error/2]). +-export([is_broadcast_mac/1, is_multicast_mac/1]). + +-spec format_mac(Mac :: binary()) -> binary(). +format_mac(Mac) when is_binary(Mac) -> + Hex = fun + (N) when N < 10 -> + $0 + N; + (N) -> + $a + (N - 10) + end, + Y = [[Hex(X0), Hex(X1)] || <> <= Mac], + list_to_binary(lists:flatten(lists:join(":", Y))). + +%% 生成随机字节 +rand_byte(Num) when is_integer(Num), Num > 0 -> + rand_byte0(Num, <<>>). +rand_byte0(0, Acc) -> + Acc; +rand_byte0(Num, Acc) -> + Byte = ceil(rand:uniform() * 255), + rand_byte0(Num - 1, <>). + +%% md5哈希算法 +-spec md5(string() | binary()) -> string(). +md5(Str) when is_binary(Str) -> + md5(binary_to_list(Str)); +md5(Str) when is_list(Str) -> + Hash = binary_to_list(erlang:md5(Str)), + lists:flatten([hex(I) || I <- Hash]). + +hex(I) when I > 16#f -> + [hex0((I band 16#f0) bsr 4), hex0(I band 16#0f)]; +hex(I) -> + [$0, hex0(I)]. +hex0(10) -> $a; +hex0(11) -> $b; +hex0(12) -> $c; +hex0(13) -> $d; +hex0(14) -> $e; +hex0(15) -> $f; +hex0(I) -> $0 + I. + +json_data(Data) -> + jiffy:encode(#{<<"result">> => Data}, [force_utf8]). + +json_error(ErrCode, ErrMessage) when is_integer(ErrCode), is_binary(ErrMessage) -> + jiffy:encode(#{<<"error">> => #{<<"code">> => ErrCode, <<"message">> => ErrMessage}}, [force_utf8]). + +assert_call(true, F) -> + F(); +assert_call(false, _) -> + ok. + +-spec is_broadcast_mac(Mac :: binary()) -> boolean(). +is_broadcast_mac(Mac) when is_binary(Mac) -> + Mac =:= <<16#FF,16#FF,16#FF,16#FF,16#FF,16#FF>>. + +-spec is_multicast_mac(Mac :: binary()) -> boolean(). +is_multicast_mac(Mac) when is_binary(Mac) -> + binary:part(Mac, 0, 3) =:= <<16#01,16#00,16#5E>>. \ No newline at end of file diff --git a/apps/sdlan/src/test/sdlan_tcp_client.erl b/apps/sdlan/src/test/sdlan_tcp_client.erl new file mode 100644 index 0000000..cae3213 --- /dev/null +++ b/apps/sdlan/src/test/sdlan_tcp_client.erl @@ -0,0 +1,101 @@ +%%%------------------------------------------------------------------- +%%% @author anlicheng +%%% @copyright (C) 2024, +%%% @doc +%%% +%%% @end +%%% Created : 29. 3月 2024 14:32 +%%%------------------------------------------------------------------- +-module(sdlan_tcp_client). +-author("anlicheng"). + +-behaviour(gen_server). + +%% API +-export([start_link/0]). + +%% gen_server callbacks +-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). + +-define(SERVER, ?MODULE). + +-record(state, { + socket +}). + +%%%=================================================================== +%%% API +%%%=================================================================== + +%% @doc Spawns the server and registers the local name (unique) +-spec(start_link() -> + {ok, Pid :: pid()} | ignore | {error, Reason :: term()}). +start_link() -> + gen_server:start_link({local, ?SERVER}, ?MODULE, [], []). + +%%%=================================================================== +%%% gen_server callbacks +%%%=================================================================== + +%% @private +%% @doc Initializes the server +-spec(init(Args :: term()) -> + {ok, State :: #state{}} | {ok, State :: #state{}, timeout() | hibernate} | + {stop, Reason :: term()} | ignore). +init([]) -> + {ok, Socket} = gen_tcp:connect("localhost", 18083, [binary, {packet, 2}, {active, true}]), + ok = gen_tcp:send(Socket, <<"hello world">>), + {ok, #state{socket = Socket}}. + +%% @private +%% @doc Handling call messages +-spec(handle_call(Request :: term(), From :: {pid(), Tag :: term()}, + State :: #state{}) -> + {reply, Reply :: term(), NewState :: #state{}} | + {reply, Reply :: term(), NewState :: #state{}, timeout() | hibernate} | + {noreply, NewState :: #state{}} | + {noreply, NewState :: #state{}, timeout() | hibernate} | + {stop, Reason :: term(), Reply :: term(), NewState :: #state{}} | + {stop, Reason :: term(), NewState :: #state{}}). +handle_call(_Request, _From, State = #state{}) -> + {reply, ok, State}. + +%% @private +%% @doc Handling cast messages +-spec(handle_cast(Request :: term(), State :: #state{}) -> + {noreply, NewState :: #state{}} | + {noreply, NewState :: #state{}, timeout() | hibernate} | + {stop, Reason :: term(), NewState :: #state{}}). +handle_cast(_Request, State = #state{}) -> + {noreply, State}. + +%% @private +%% @doc Handling all non call/cast messages +-spec(handle_info(Info :: timeout() | term(), State :: #state{}) -> + {noreply, NewState :: #state{}} | + {noreply, NewState :: #state{}, timeout() | hibernate} | + {stop, Reason :: term(), NewState :: #state{}}). +handle_info(_Info, State = #state{}) -> + {noreply, State}. + +%% @private +%% @doc This function is called by a gen_server when it is about to +%% terminate. It should be the opposite of Module:init/1 and do any +%% necessary cleaning up. When it returns, the gen_server terminates +%% with Reason. The return value is ignored. +-spec(terminate(Reason :: (normal | shutdown | {shutdown, term()} | term()), + State :: #state{}) -> term()). +terminate(_Reason, _State = #state{}) -> + ok. + +%% @private +%% @doc Convert process state when code is changed +-spec(code_change(OldVsn :: term() | {down, term()}, State :: #state{}, + Extra :: term()) -> + {ok, NewState :: #state{}} | {error, Reason :: term()}). +code_change(_OldVsn, State = #state{}, _Extra) -> + {ok, State}. + +%%%=================================================================== +%%% Internal functions +%%%=================================================================== diff --git a/apps/sdlan/src/test/sdlan_udp_downloader.erl b/apps/sdlan/src/test/sdlan_udp_downloader.erl new file mode 100644 index 0000000..9177b5b --- /dev/null +++ b/apps/sdlan/src/test/sdlan_udp_downloader.erl @@ -0,0 +1,110 @@ +%%%------------------------------------------------------------------- +%%% @author anlicheng +%%% @copyright (C) 2024, +%%% @doc +%%% +%%% @end +%%% Created : 17. 4月 2024 10:35 +%%%------------------------------------------------------------------- +-module(sdlan_udp_downloader). +-author("anlicheng"). + +-behaviour(gen_server). + +%% API +-export([start_link/0]). + +%% gen_server callbacks +-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, + code_change/3]). + +-define(SERVER, ?MODULE). + +-record(state, { + socket +}). + +%%%=================================================================== +%%% API +%%%=================================================================== + +%% @doc Spawns the server and registers the local name (unique) +-spec(start_link() -> + {ok, Pid :: pid()} | ignore | {error, Reason :: term()}). +start_link() -> + gen_server:start_link({local, ?SERVER}, ?MODULE, [], []). + +%%%=================================================================== +%%% gen_server callbacks +%%%=================================================================== + +%% @private +%% @doc Initializes the server +-spec(init(Args :: term()) -> + {ok, State :: #state{}} | {ok, State :: #state{}, timeout() | hibernate} | + {stop, Reason :: term()} | ignore). +init([]) -> + {ok, Socket} = gen_udp:open(22222, [binary]), + {ok, #state{socket = Socket}}. + +%% @private +%% @doc Handling call messages +-spec(handle_call(Request :: term(), From :: {pid(), Tag :: term()}, + State :: #state{}) -> + {reply, Reply :: term(), NewState :: #state{}} | + {reply, Reply :: term(), NewState :: #state{}, timeout() | hibernate} | + {noreply, NewState :: #state{}} | + {noreply, NewState :: #state{}, timeout() | hibernate} | + {stop, Reason :: term(), Reply :: term(), NewState :: #state{}} | + {stop, Reason :: term(), NewState :: #state{}}). +handle_call(_Request, _From, State) -> + {reply, ok, State}. + +%% @private +%% @doc Handling cast messages +-spec(handle_cast(Request :: term(), State :: #state{}) -> + {noreply, NewState :: #state{}} | + {noreply, NewState :: #state{}, timeout() | hibernate} | + {stop, Reason :: term(), NewState :: #state{}}). +handle_cast(_Info, State) -> + {noreply, State}. + +%% @private +%% @doc Handling all non call/cast messages +-spec(handle_info(Info :: timeout() | term(), State :: #state{}) -> + {noreply, NewState :: #state{}} | + {noreply, NewState :: #state{}, timeout() | hibernate} | + {stop, Reason :: term(), NewState :: #state{}}). +handle_info({udp, Sock, Ip, Port, <<1>>}, State = #state{socket = Sock}) -> + {ok, Content} = file:read_file("/tmp/files/test.dmg"), + send_file_content(Sock, Ip, Port, 1200, Content), + {noreply, State#state{}}. + +%% @private +%% @doc This function is called by a gen_server when it is about to +%% terminate. It should be the opposite of Module:init/1 and do any +%% necessary cleaning up. When it returns, the gen_server terminates +%% with Reason. The return value is ignored. +-spec(terminate(Reason :: (normal | shutdown | {shutdown, term()} | term()), + State :: #state{}) -> term()). +terminate(_Reason, _State = #state{}) -> + ok. + +%% @private +%% @doc Convert process state when code is changed +-spec(code_change(OldVsn :: term() | {down, term()}, State :: #state{}, + Extra :: term()) -> + {ok, NewState :: #state{}} | {error, Reason :: term()}). +code_change(_OldVsn, State = #state{}, _Extra) -> + {ok, State}. + +%%%=================================================================== +%%% Internal functions +%%%=================================================================== + +send_file_content(Sock, Ip, Port, Size, Content) when byte_size(Content) =< Size -> + gen_udp:send(Sock, Ip, Port, Content); +send_file_content(Sock, Ip, Port, Size, Content) -> + <> = Content, + gen_udp:send(Sock, Ip, Port, Part), + send_file_content(Sock, Ip, Port, Size, Rest). diff --git a/apps/sdlan/src/test/sdlan_udp_wget.erl b/apps/sdlan/src/test/sdlan_udp_wget.erl new file mode 100644 index 0000000..cee81bd --- /dev/null +++ b/apps/sdlan/src/test/sdlan_udp_wget.erl @@ -0,0 +1,114 @@ +%%%------------------------------------------------------------------- +%%% @author anlicheng +%%% @copyright (C) 2024, +%%% @doc +%%% +%%% @end +%%% Created : 17. 4月 2024 10:35 +%%%------------------------------------------------------------------- +-module(sdlan_udp_wget). +-author("anlicheng"). + +-behaviour(gen_server). + +%% API +-export([start_link/0]). +-export([wget/0]). + +%% gen_server callbacks +-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). + +-define(SERVER, ?MODULE). + +-record(state, { + socket, + bytes = 0 +}). + +%%%=================================================================== +%%% API +%%%=================================================================== +wget() -> + gen_server:call(?MODULE, wget). + +%% @doc Spawns the server and registers the local name (unique) +-spec(start_link() -> + {ok, Pid :: pid()} | ignore | {error, Reason :: term()}). +start_link() -> + gen_server:start_link({local, ?SERVER}, ?MODULE, [], []). + +%%%=================================================================== +%%% gen_server callbacks +%%%=================================================================== + +%% @private +%% @doc Initializes the server +-spec(init(Args :: term()) -> + {ok, State :: #state{}} | {ok, State :: #state{}, timeout() | hibernate} | + {stop, Reason :: term()} | ignore). +init([]) -> + {ok, Socket} = gen_udp:open(0, [binary, {active, true}]), + inet_udp:controlling_process(Socket, self()), + + erlang:start_timer(5000, self(), qps_ticker), + + {ok, #state{socket = Socket}}. + +%% @private +%% @doc Handling call messages +-spec(handle_call(Request :: term(), From :: {pid(), Tag :: term()}, + State :: #state{}) -> + {reply, Reply :: term(), NewState :: #state{}} | + {reply, Reply :: term(), NewState :: #state{}, timeout() | hibernate} | + {noreply, NewState :: #state{}} | + {noreply, NewState :: #state{}, timeout() | hibernate} | + {stop, Reason :: term(), Reply :: term(), NewState :: #state{}} | + {stop, Reason :: term(), NewState :: #state{}}). +handle_call(wget, _From, State=#state{socket = Socket}) -> + gen_udp:send(Socket, "127.0.0.1", 22222, <<1>>), + {reply, ok, State}. + +%% @private +%% @doc Handling cast messages +-spec(handle_cast(Request :: term(), State :: #state{}) -> + {noreply, NewState :: #state{}} | + {noreply, NewState :: #state{}, timeout() | hibernate} | + {stop, Reason :: term(), NewState :: #state{}}). +handle_cast(_Info, State) -> + {noreply, State}. + +%% @private +%% @doc Handling all non call/cast messages +-spec(handle_info(Info :: timeout() | term(), State :: #state{}) -> + {noreply, NewState :: #state{}} | + {noreply, NewState :: #state{}, timeout() | hibernate} | + {stop, Reason :: term(), NewState :: #state{}}). +handle_info({udp, Sock, _Ip, _Port, Data}, State = #state{socket = Sock, bytes = Bytes}) -> + {noreply, State#state{bytes = Bytes + byte_size(Data)}}; +handle_info({timeout, _, qps_ticker}, State = #state{bytes = Bytes}) -> + lager:debug("[sdlan_udp_wget] qps is: ~p(M)", [Bytes / 1024 / 1024]), + erlang:start_timer(5000, self(), qps_ticker), + {noreply, State#state{bytes = 0}}. + + +%% @private +%% @doc This function is called by a gen_server when it is about to +%% terminate. It should be the opposite of Module:init/1 and do any +%% necessary cleaning up. When it returns, the gen_server terminates +%% with Reason. The return value is ignored. +-spec(terminate(Reason :: (normal | shutdown | {shutdown, term()} | term()), + State :: #state{}) -> term()). +terminate(_Reason, _State = #state{}) -> + ok. + +%% @private +%% @doc Convert process state when code is changed +-spec(code_change(OldVsn :: term() | {down, term()}, State :: #state{}, + Extra :: term()) -> + {ok, NewState :: #state{}} | {error, Reason :: term()}). +code_change(_OldVsn, State = #state{}, _Extra) -> + {ok, State}. + +%%%=================================================================== +%%% Internal functions +%%%=================================================================== diff --git a/apps/sdlan/src/test/stun_client.erl b/apps/sdlan/src/test/stun_client.erl new file mode 100644 index 0000000..9ee47bd --- /dev/null +++ b/apps/sdlan/src/test/stun_client.erl @@ -0,0 +1,208 @@ +%%%------------------------------------------------------------------- +%%% @author anlicheng +%%% @copyright (C) 2024, +%%% @doc +%%% +%%% @end +%%% Created : 08. 4月 2024 10:37 +%%%------------------------------------------------------------------- +-module(stun_client). +-author("anlicheng"). +-include("sdlan_pb.hrl"). + +-behaviour(gen_server). + +%% API +-export([start_link/0]). +-export([register/1, debug_info/1]). + +%% gen_server callbacks +-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, + code_change/3]). + +-define(SERVER, ?MODULE). +%% 请求 +-define(STUN_REGISTER, 3). +%% 响应 +-define(STUN_REGISTER_ACK, 4). + +-define(STUN_DATA, 5). + +-record(state, { + socket, + tun_socket, + client_id :: binary(), + network_id, + net_addr, + mask_len, + aes_key, + cookie = 1, + + sessions = #{} +}). + +%%%=================================================================== +%%% API +%%%=================================================================== + +register(Pid) when is_pid(Pid) -> + gen_server:call(Pid, register). + +debug_info(Pid) -> + gen_server:call(Pid, debug_info). + +%% @doc Spawns the server and registers the local name (unique) +-spec(start_link() -> + {ok, Pid :: pid()} | ignore | {error, Reason :: term()}). +start_link() -> + gen_server:start_link(?MODULE, [], []). + +%%%=================================================================== +%%% gen_server callbacks +%%%=================================================================== + +%% @private +%% @doc Initializes the server +-spec(init(Args :: term()) -> + {ok, State :: #state{}} | {ok, State :: #state{}, timeout() | hibernate} | + {stop, Reason :: term()} | ignore). +init([]) -> + {ok, Socket} = gen_tcp:connect("localhost", 18083, [binary, {packet, 2}, {active, true}]), + inet_tcp:controlling_process(Socket, self()), + {ok, TunSocket} = gen_udp:open(12345, [binary, {active, true}]), + + {ok, #state{socket = Socket, tun_socket = TunSocket, client_id = <<"22222222222222222222222222222222">>}}. + +%% @private +%% @doc Handling call messages +-spec(handle_call(Request :: term(), From :: {pid(), Tag :: term()}, + State :: #state{}) -> + {reply, Reply :: term(), NewState :: #state{}} | + {reply, Reply :: term(), NewState :: #state{}, timeout() | hibernate} | + {noreply, NewState :: #state{}} | + {noreply, NewState :: #state{}, timeout() | hibernate} | + {stop, Reason :: term(), Reply :: term(), NewState :: #state{}} | + {stop, Reason :: term(), NewState :: #state{}}). +handle_call(debug_info, _From, State) -> + {reply, {ok, State}, State}; + +handle_call(register, _From, State = #state{socket = Socket, client_id = ClientId}) -> + Req = #{ + <<"version">> => 1, + <<"client_id">> => ClientId, + <<"dev_addr">> => #{ + <<"net_addr">> => 0, + <<"net_bit_len">> => 0 + }, + <<"token">> => <<"1234567890">> + }, + + Register = #sdl_register_super { + version = 1, + installed_channel = <<"macos">>, + client_id = ClientId, + dev_addr = #sdl_dev_addr { + network_id = 0, + mac = <<11, 12, 13, 14, 15, 16>>, + net_addr = 0, + net_bit_len = 0 + }, + pub_key = <<>>, + token = <<"1234567890">> + }, + + lager:debug("register is: ~p", [Register]), + + Packet = jiffy:encode(Req, [force_utf8]), + ok = gen_tcp:send(Socket, <<1:32, 101, Packet/binary>>), + + {reply, ok, State}. + +%% @private +%% @doc Handling cast messages +-spec(handle_cast(Request :: term(), State :: #state{}) -> + {noreply, NewState :: #state{}} | + {noreply, NewState :: #state{}, timeout() | hibernate} | + {stop, Reason :: term(), NewState :: #state{}}). +handle_cast(_Request, State = #state{}) -> + {noreply, State}. + +%% @private +%% @doc Handling all non call/cast messages +-spec(handle_info(Info :: timeout() | term(), State :: #state{}) -> + {noreply, NewState :: #state{}} | + {noreply, NewState :: #state{}, timeout() | hibernate} | + {stop, Reason :: term(), NewState :: #state{}}). +handle_info({tcp, Socket, <<1:32, 5, Data/binary>>}, State = #state{socket = Socket, tun_socket = TunSocket, client_id = ClientId, cookie = Cookie}) -> + Response = jiffy:decode(Data, [return_maps]), + #{ + <<"dev_addr">> := #{ + <<"network_id">> := NetworkId, + <<"net_addr">> := NetAddr, + <<"net_bit_len">> := NetBitLen + }, + <<"aes_key">> := AesKey, + <<"lifetime">> := Lifetime + } = Response, + + lager:debug("[stun_client] get a register super response: ~p, alloc ip addr: ~p", [Response, sdlan_ipaddr:int_to_ipv4(NetAddr)]), + + %% 开始注册自己的tun信息 + gen_udp:send(TunSocket, "localhost", 1265, <<1, Cookie:32, ClientId/binary, NetworkId:32, NetAddr:32>>), + + {noreply, State#state{network_id = NetworkId, net_addr = NetAddr, mask_len = NetBitLen, aes_key = AesKey, cookie = Cookie + 1}}; + +handle_info({udp, _, _, _, <<2, Cookie:32, Family, Port:16, Ip0, Ip1, Ip2, Ip3>>}, State = #state{}) -> + lager:debug("[stun_client] tun register ack, cookie: ~p, ack: ~p", [Cookie, {Family, Port, {Ip0, Ip1, Ip2, Ip3}}]), + {noreply, State}; + +handle_info({udp, _, Ip, Port, <>}, State = #state{tun_socket = TunSocket, sessions = Sessions}) -> + Packet = <>, + lager:debug("[stun_client] will send stun reply: ~p, peer: ~p", [Packet, {Ip, Port}]), + ok = gen_udp:send(TunSocket, Ip, Port, Packet), + + NSessions = maps:put(SrcIp, {Ip, Port}, Sessions), + {noreply, State#state{sessions = NSessions}}; + +handle_info({udp, _, Ip, Port, <>}, State = #state{sessions = Sessions}) -> + lager:debug("[stun_client] stun_data: network_id: ~p, src: ~p, dst: ~p, register_ack!!!", [NetworkId, SrcIp, DstIp]), + NSessions = maps:put(SrcIp, {Ip, Port}, Sessions), + {noreply, State#state{sessions = NSessions}}; + +handle_info({udp, _, _Ip0, _Port0, <>}, State = #state{tun_socket = TunSocket, sessions = Sessions}) -> + lager:debug("[stun_client] stun_data: network_id: ~p, src: ~p, dst: ~p, data!!!", [NetworkId, SrcIp, DstIp]), + case maps:is_key(SrcIp, Sessions) of + true -> + {Ip, Port} = maps:get(SrcIp, Sessions), + ok = gen_udp:send(TunSocket, Ip, Port, <>), + lager:debug("[stun_client] stun_data: network_id: ~p, src: ~p, dst: ~p, reply data!!!", [NetworkId, SrcIp, DstIp]); + false -> + lager:debug("[stun_client] stun_data: network_id: ~p, src: ~p, dst: ~p, no session", [NetworkId, SrcIp, DstIp]) + end, + {noreply, State}; + +handle_info(Info, State = #state{}) -> + lager:debug("[stun_client] get info: ~p", [Info]), + {noreply, State}. + +%% @private +%% @doc This function is called by a gen_server when it is about to +%% terminate. It should be the opposite of Module:init/1 and do any +%% necessary cleaning up. When it returns, the gen_server terminates +%% with Reason. The return value is ignored. +-spec(terminate(Reason :: (normal | shutdown | {shutdown, term()} | term()), + State :: #state{}) -> term()). +terminate(_Reason, _State = #state{}) -> + ok. + +%% @private +%% @doc Convert process state when code is changed +-spec(code_change(OldVsn :: term() | {down, term()}, State :: #state{}, + Extra :: term()) -> + {ok, NewState :: #state{}} | {error, Reason :: term()}). +code_change(_OldVsn, State = #state{}, _Extra) -> + {ok, State}. + +%%%=================================================================== +%%% Internal functions +%%%=================================================================== diff --git a/config/sys-dev.config b/config/sys-dev.config new file mode 100644 index 0000000..e29ade5 --- /dev/null +++ b/config/sys-dev.config @@ -0,0 +1,86 @@ +[ + {sdlan, [ + + {http_server, [ + {port, 18082}, + {acceptors, 500}, + {max_connections, 10240}, + {backlog, 10240} + ]}, + + {tcp_server, [ + {port, 18083}, + {acceptors, 500}, + {max_connections, 10240}, + {backlog, 10240} + ]}, + + %% 网络带宽, 单位为: kb + {band_width, 2048}, + + {stun_servers, [{'sdlan_stun:1:1', 1265}, {'sdlan_stun:1:2', 1266}]}, + {stun_assist, {{47,98,178,3}, 1266}}, + + % {stun_servers, [{'sdlan_stun:2:1', 1265}, {'sdlan_stun:2:2', 1266}]}, + + {pools, [ + %% mysql连接池配置 + {mysql_sdlan, + [{size, 10}, {max_overflow, 20}, {worker_module, mysql}], + [ + {host, {39, 98, 184, 67}}, + {port, 3306}, + {user, "sdlanuser"}, + {connect_mode, lazy}, + {keep_alive, true}, + {password, "sdlan@J1c8WGu"}, + {database, "sdlan"}, + {queries, [<<"set names utf8">>]} + ] + } + ]}, + + {api_url, "http://127.0.0.1:18082/test/"} + + ]}, + + {throttle, [ + {driver, throttle_ets}, + {access_context, sync_transaction} + ]}, + + %% 系统日志配置,系统日志为lager, 支持日志按日期自动分割 + {lager, [ + {colored, true}, + %% Whether to write a crash log, and where. Undefined means no crash logger. + {crash_log, "trade_hub.crash.log"}, + %% Maximum size in bytes of events in the crash log - defaults to 65536 + {crash_log_msg_size, 65536}, + %% Maximum size of the crash log in bytes, before its rotated, set + %% to 0 to disable rotation - default is 0 + {crash_log_size, 10485760}, + %% What time to rotate the crash log - default is no time + %% rotation. See the README for a description of this format. + {crash_log_date, "$D0"}, + %% Number of rotated crash logs to keep, 0 means keep only the + %% current one - default is 0 + {crash_log_count, 5}, + %% Whether to redirect error_logger messages into lager - defaults to true + {error_logger_redirect, true}, + + %% How big the gen_event mailbox can get before it is switched into sync mode + {async_threshold, 20}, + %% Switch back to async mode, when gen_event mailbox size decrease from `async_threshold' + %% to async_threshold - async_threshold_window + {async_threshold_window, 5}, + + {handlers, [ + %% debug | info | warning | error, 日志级别 + {lager_console_backend, debug}, + {lager_file_backend, [{file, "debug.log"}, {level, debug}, {size, 314572800}]}, + {lager_file_backend, [{file, "notice.log"}, {level, notice}, {size, 314572800}]}, + {lager_file_backend, [{file, "error.log"}, {level, error}, {size, 314572800}]}, + {lager_file_backend, [{file, "info.log"}, {level, info}, {size, 314572800}]} + ]} + ]} +]. diff --git a/config/sys-prod.config b/config/sys-prod.config new file mode 100644 index 0000000..8ee0dab --- /dev/null +++ b/config/sys-prod.config @@ -0,0 +1,86 @@ +[ + {sdlan, [ + + {http_server, [ + {port, 18082}, + {acceptors, 500}, + {max_connections, 10240}, + {backlog, 10240} + ]}, + + {tcp_server, [ + {port, 18083}, + {acceptors, 500}, + {max_connections, 10240}, + {backlog, 10240} + ]}, + + %% 网络带宽, 单位为: kb + {band_width, 2048}, + + {stun_servers, [{'sdlan_stun:1:1', 1265}, {'sdlan_stun:1:2', 1266}]}, + {stun_assist, {{47,98,178,3}, 1266}}, + + % {stun_servers, [{'sdlan_stun:2:1', 1265}, {'sdlan_stun:2:2', 1266}]}, + + {pools, [ + %% mysql连接池配置 + {mysql_sdlan, + [{size, 10}, {max_overflow, 20}, {worker_module, mysql}], + [ + {host, {39, 98, 184, 67}}, + {port, 3306}, + {user, "sdlanuser"}, + {connect_mode, lazy}, + {keep_alive, true}, + {password, "sdlan@J1c8WGu"}, + {database, "sdlan"}, + {queries, [<<"set names utf8">>]} + ] + } + ]}, + + {api_url, "http://39.98.184.67:8200/api/"} + + ]}, + + {throttle, [ + {driver, throttle_ets}, + {access_context, sync_transaction} + ]}, + + %% 系统日志配置,系统日志为lager, 支持日志按日期自动分割 + {lager, [ + {colored, true}, + %% Whether to write a crash log, and where. Undefined means no crash logger. + {crash_log, "trade_hub.crash.log"}, + %% Maximum size in bytes of events in the crash log - defaults to 65536 + {crash_log_msg_size, 65536}, + %% Maximum size of the crash log in bytes, before its rotated, set + %% to 0 to disable rotation - default is 0 + {crash_log_size, 10485760}, + %% What time to rotate the crash log - default is no time + %% rotation. See the README for a description of this format. + {crash_log_date, "$D0"}, + %% Number of rotated crash logs to keep, 0 means keep only the + %% current one - default is 0 + {crash_log_count, 5}, + %% Whether to redirect error_logger messages into lager - defaults to true + {error_logger_redirect, true}, + + %% How big the gen_event mailbox can get before it is switched into sync mode + {async_threshold, 20}, + %% Switch back to async mode, when gen_event mailbox size decrease from `async_threshold' + %% to async_threshold - async_threshold_window + {async_threshold_window, 5}, + + {handlers, [ + %% debug | info | warning | error, 日志级别 + {lager_console_backend, debug}, + {lager_file_backend, [{file, "debug.log"}, {level, debug}, {size, 314572800}]}, + {lager_file_backend, [{file, "notice.log"}, {level, notice}, {size, 314572800}]}, + {lager_file_backend, [{file, "error.log"}, {level, error}, {size, 314572800}]}, + {lager_file_backend, [{file, "info.log"}, {level, info}, {size, 314572800}]} + ]} + ]} +]. diff --git a/config/vm.args b/config/vm.args new file mode 100644 index 0000000..737fd3b --- /dev/null +++ b/config/vm.args @@ -0,0 +1,6 @@ +-sname sdlan + +-setcookie sdlan_cookie + ++K true ++A30 diff --git a/message.proto b/message.proto new file mode 100644 index 0000000..ddc66e6 --- /dev/null +++ b/message.proto @@ -0,0 +1,152 @@ +syntax = "proto3"; + +// 基础公共类型定义 + +message SDLV4Info { + uint32 port = 1; + bytes v4 = 2; + uint32 nat_type = 3; +} + +message SDLV6Info { + uint32 port = 1; + bytes v6 = 2; +} + +// 设备网络地址信息 +message SDLDevAddr { + uint32 network_id = 1; + bytes mac = 2; + uint32 net_addr = 3; + uint32 net_bit_len = 4; +} + +// tcp通讯消息 +message SDLEmpty { + +} + +message SDLRegisterSuper { + uint32 version = 1; + string installed_channel = 2; + string client_id = 3; + SDLDevAddr dev_addr = 4; + string pub_key = 5; + string token = 6; +} + +message SDLRegisterSuperAck { + SDLDevAddr dev_addr = 1; + bytes aes_key = 2; + uint32 upgrade_type = 3; + optional string upgrade_prompt = 4; + optional string upgrade_address = 5; +} + +message SDLRegisterSuperNak { + uint32 error_code = 1; + string error_message = 2; +} + +// 网络地址查询 + +message SDLQueryInfo { + bytes dst_mac = 1; +} + +message SDLPeerInfo { + bytes dst_mac = 1; + SDLV4Info v4_info = 2; + optional SDLV6Info v6_info = 3; +} + +// 事件定义 + +message SDLNatChangedEvent { + bytes mac = 1; + uint32 ip = 2; +} + +message SDLSendRegisterEvent { + bytes dst_mac = 1; + uint32 nat_ip = 2; + uint32 nat_port = 3; + uint32 nat_type = 4; + optional SDLV6Info v6_info = 5; +} + +message SDLNetworkShutdownEvent { + string message = 1; +} + +// 命令定义 + +message SDLChangeNetworkCommand { + SDLDevAddr dev_addr = 1; + bytes aes_key = 2; +} + +message SDLCommandAck { + // status = true, 表示成功;status = false 表示失败,message是失败原因描述 + bool status = 1; + optional string message = 2; +} + +message SDLFlows { + // 服务器转发流量 + uint32 forward_num = 1; + // p2p直接流量 + uint32 p2p_num = 2; + // 接收的流量 + uint32 inbound_num = 3; +} + +// UDP通讯消息 + +message SDLStunRequest { + uint32 cookie = 1; + string client_id = 2; + uint32 network_id = 3; + bytes mac = 4; + uint32 ip = 5; + uint32 nat_type = 6; + optional SDLV6Info v6_info = 7; +} + +message SDLStunReply { + uint32 cookie = 1; +} + +message SDLData { + uint32 network_id = 1; + bytes src_mac = 2; + bytes dst_mac = 3; + bool is_p2p = 4; + uint32 ttl = 5; + bytes data = 6; +} + +message SDLRegister { + uint32 network_id = 1; + bytes src_mac = 2; + bytes dst_mac = 3; +} + +message SDLRegisterAck { + uint32 network_id = 1; + bytes src_mac = 2; + bytes dst_mac = 3; +} + +// 网络类型探测 + +message SDLStunProbe { + uint32 cookie = 1; + uint32 attr = 2; +} + +message SDLStunProbeReply { + uint32 cookie = 1; + uint32 port = 2; + uint32 ip = 3; +} \ No newline at end of file diff --git a/rebar.config b/rebar.config new file mode 100644 index 0000000..3c9e869 --- /dev/null +++ b/rebar.config @@ -0,0 +1,48 @@ +{erl_opts, [debug_info]}. +{deps, [ + {poolboy, ".*", {git, "https://github.com/devinus/poolboy.git", {tag, "1.5.1"}}}, + {hackney, ".*", {git, "https://github.com/benoitc/hackney.git", {tag, "1.16.0"}}}, + {sync, ".*", {git, "https://github.com/rustyio/sync.git", {branch, "master"}}}, + {esockd, ".*", {git, "https://github.com/emqx/esockd.git", {tag, "v5.7.3"}}}, + {jiffy, ".*", {git, "https://github.com/davisp/jiffy.git", {tag, "1.1.1"}}}, + {cowboy, ".*", {git, "https://github.com/ninenines/cowboy.git", {tag, "2.12.0"}}}, + {mysql, ".*", {git, "https://github.com/mysql-otp/mysql-otp", {tag, "1.8.0"}}}, + {gpb, ".*", {git, "https://github.com/tomas-abrahamsson/gpb.git", {tag, "4.21.1"}}}, + {throttle, ".*", {git, "https://github.com/lambdaclass/throttle.git", {tag, "0.3.0"}}}, + {parse_trans, ".*", {git, "https://github.com/uwiger/parse_trans", {tag, "3.0.0"}}}, + {lager, ".*", {git,"https://github.com/erlang-lager/lager.git", {tag, "3.9.2"}}} +]}. + +{relx, [{release, {sdlan, "0.1.0"}, + [sdlan, + sasl]}, + + {mode, dev}, + + %% automatically picked up if the files + %% exist but can be set manually, which + %% is required if the names aren't exactly + %% sys.config and vm.args + {sys_config, "./config/sys.config"}, + {vm_args, "./config/vm.args"} + + %% the .src form of the configuration files do + %% not require setting RELX_REPLACE_OS_VARS + %% {sys_config_src, "./config/sys.config.src"}, + %% {vm_args_src, "./config/vm.args.src"} +]}. + +{profiles, [{prod, [{relx, + [%% prod is the default mode when prod + %% profile is used, so does not have + %% to be explicitly included like this + {mode, prod} + + %% use minimal mode to exclude ERTS + %% {mode, minimal} + ] + }]}]}. + +{erl_opts, [{parse_transform,lager_transform}]}. + +{rebar_packages_cdn, "https://hexpm.upyun.com"}. \ No newline at end of file diff --git a/rebar.lock b/rebar.lock new file mode 100644 index 0000000..7566f8a --- /dev/null +++ b/rebar.lock @@ -0,0 +1,81 @@ +{"1.2.0", +[{<<"certifi">>,{pkg,<<"certifi">>,<<"2.5.2">>},1}, + {<<"cowboy">>, + {git,"https://github.com/ninenines/cowboy.git", + {ref,"3ea8395eb8f53a57acb5d3c00b99c70296e7cdbd"}}, + 0}, + {<<"cowlib">>, + {git,"https://github.com/ninenines/cowlib", + {ref,"1eb7f4293a652adcfe43b1835d22c58d8def839f"}}, + 1}, + {<<"esockd">>, + {git,"https://github.com/emqx/esockd.git", + {ref,"d9ce4024cc42a65e9a05001997031e743442f955"}}, + 0}, + {<<"fs">>,{pkg,<<"fs">>,<<"6.1.1">>},1}, + {<<"goldrush">>,{pkg,<<"goldrush">>,<<"0.1.9">>},1}, + {<<"gpb">>, + {git,"https://github.com/tomas-abrahamsson/gpb.git", + {ref,"a53bc4909b3dc5a78b996263d92db38fed9d4782"}}, + 0}, + {<<"hackney">>, + {git,"https://github.com/benoitc/hackney.git", + {ref,"f3e9292db22c807e73f57a8422402d6b423ddf5f"}}, + 0}, + {<<"idna">>,{pkg,<<"idna">>,<<"6.0.1">>},1}, + {<<"jiffy">>, + {git,"https://github.com/davisp/jiffy.git", + {ref,"9ea1b35b6e60ba21dfd4adbd18e7916a831fd7d4"}}, + 0}, + {<<"lager">>, + {git,"https://github.com/erlang-lager/lager.git", + {ref,"459a3b2cdd9eadd29e5a7ce5c43932f5ccd6eb88"}}, + 0}, + {<<"metrics">>,{pkg,<<"metrics">>,<<"1.0.1">>},1}, + {<<"mimerl">>,{pkg,<<"mimerl">>,<<"1.2.0">>},1}, + {<<"mysql">>, + {git,"https://github.com/mysql-otp/mysql-otp", + {ref,"caf5ff96c677a8fe0ce6f4082bc036c8fd27dd62"}}, + 0}, + {<<"parse_trans">>, + {git,"https://github.com/uwiger/parse_trans", + {ref,"6f3645afb43c7c57d61b54ef59aecab288ce1013"}}, + 0}, + {<<"poolboy">>, + {git,"https://github.com/devinus/poolboy.git", + {ref,"3bb48a893ff5598f7c73731ac17545206d259fac"}}, + 0}, + {<<"ranch">>, + {git,"https://github.com/ninenines/ranch", + {ref,"a692f44567034dacf5efcaa24a24183788594eb7"}}, + 1}, + {<<"ssl_verify_fun">>,{pkg,<<"ssl_verify_fun">>,<<"1.1.6">>},1}, + {<<"sync">>, + {git,"https://github.com/rustyio/sync.git", + {ref,"7dc303ed4ce8d26db82e171dbbd7c41067852c65"}}, + 0}, + {<<"throttle">>, + {git,"https://github.com/lambdaclass/throttle.git", + {ref,"4f5fb17c9d4a86ba016e7011648ae5dfe539ac01"}}, + 0}, + {<<"unicode_util_compat">>,{pkg,<<"unicode_util_compat">>,<<"0.5.0">>},2}]}. +[ +{pkg_hash,[ + {<<"certifi">>, <<"B7CFEAE9D2ED395695DD8201C57A2D019C0C43ECAF8B8BCB9320B40D6662F340">>}, + {<<"fs">>, <<"9D147B944D60CFA48A349F12D06C8EE71128F610C90870BDF9A6773206452ED0">>}, + {<<"goldrush">>, <<"F06E5D5F1277DA5C413E84D5A2924174182FB108DABB39D5EC548B27424CD106">>}, + {<<"idna">>, <<"1D038FB2E7668CE41FBF681D2C45902E52B3CB9E9C77B55334353B222C2EE50C">>}, + {<<"metrics">>, <<"25F094DEA2CDA98213CECC3AEFF09E940299D950904393B2A29D191C346A8486">>}, + {<<"mimerl">>, <<"67E2D3F571088D5CFD3E550C383094B47159F3EEE8FFA08E64106CDF5E981BE3">>}, + {<<"ssl_verify_fun">>, <<"CF344F5692C82D2CD7554F5EC8FD961548D4FD09E7D22F5B62482E5AEAEBD4B0">>}, + {<<"unicode_util_compat">>, <<"8516502659002CEC19E244EBD90D312183064BE95025A319A6C7E89F4BCCD65B">>}]}, +{pkg_hash_ext,[ + {<<"certifi">>, <<"3B3B5F36493004AC3455966991EAF6E768CE9884693D9968055AEEEB1E575040">>}, + {<<"fs">>, <<"EF94E95FFE79916860649FED80AC62B04C322B0BB70F5128144C026B4D171F8B">>}, + {<<"goldrush">>, <<"99CB4128CFFCB3227581E5D4D803D5413FA643F4EB96523F77D9E6937D994CEB">>}, + {<<"idna">>, <<"A02C8A1C4FD601215BB0B0324C8A6986749F807CE35F25449EC9E69758708122">>}, + {<<"metrics">>, <<"69B09ADDDC4F74A40716AE54D140F93BEB0FB8978D8636EADED0C31B6F099F16">>}, + {<<"mimerl">>, <<"F278585650AA581986264638EBF698F8BB19DF297F66AD91B18910DFC6E19323">>}, + {<<"ssl_verify_fun">>, <<"BDB0D2471F453C88FF3908E7686F86F9BE327D065CC1EC16FA4540197EA04680">>}, + {<<"unicode_util_compat">>, <<"D48D002E15F5CC105A696CF2F1BBB3FC72B4B770A184D8420C8DB20DA2674B38">>}]} +]. diff --git a/run b/run new file mode 100755 index 0000000..0b7fbc6 --- /dev/null +++ b/run @@ -0,0 +1,6 @@ +#! /bin/sh + +rebar3 compile && rebar3 release + +_build/default/rel/sdlan/bin/sdlan console + diff --git a/shell b/shell new file mode 100755 index 0000000..5111757 --- /dev/null +++ b/shell @@ -0,0 +1,4 @@ +#! /bin/sh + +./_build/default/rel/sdlan/bin/sdlan remote + diff --git a/tap.md b/tap.md new file mode 100644 index 0000000..3a4c44e --- /dev/null +++ b/tap.md @@ -0,0 +1,58 @@ +# Tap修改的点 + +## 数据结构的改变 + +### 1. 设备网络地址信息 +```text +message SDLDevAddr { + uint32 network_id = 1; + uint32 net_addr = 2; + uint32 net_bit_len = 3; + // 增加mac地址信息,6个字节的bytes + bytes mac = 4; +} +``` + +### 2. QueryInfo的请求和响应的修改 + +```text +message SDLQueryInfo { + // 改为基于mac地址查询 + bytes dst_mac = 1; +} + +message SDLPeerInfo { + bytes dst_mac = 1; + SDLV4Info v4_info = 2; + optional SDLV6Info v6_info = 3; +} +``` + +### 3. Data数据消息体 + +```text +message SDLData { + uint32 network_id = 1; + bytes src_mac = 2; + bytes dst_mac = 3; + bool is_p2p = 4; + uint32 ttl = 5; + bytes data = 6; +} +``` + +### 4. +```text +message SDLRegister { + uint32 network_id = 1; + uint32 src_ip = 2; + uint32 dst_ip = 3; +} + +message SDLRegisterAck { + uint32 network_id = 1; + uint32 src_ip = 2; + uint32 dst_ip = 3; +} + +``` \ No newline at end of file