1 |
|
%%------------------------------------------------------------------------- |
2 |
|
%% Copyright (c) 2020-2022 EMQ Technologies Co., Ltd. All Rights Reserved. |
3 |
|
%% |
4 |
|
%% Licensed under the Apache License, Version 2.0 (the "License"); |
5 |
|
%% you may not use this file except in compliance with the License. |
6 |
|
%% You may obtain a copy of the License at |
7 |
|
%% |
8 |
|
%% http://www.apache.org/licenses/LICENSE-2.0 |
9 |
|
%% |
10 |
|
%% Unless required by applicable law or agreed to in writing, software |
11 |
|
%% distributed under the License is distributed on an "AS IS" BASIS, |
12 |
|
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 |
|
%% See the License for the specific language governing permissions and |
14 |
|
%% limitations under the License. |
15 |
|
%%------------------------------------------------------------------------- |
16 |
|
|
17 |
|
%% @doc low-level API for send any type of standard |
18 |
|
%% MQTT-SN packet, always used with <i>emqttsn_udp</i> |
19 |
|
%% |
20 |
|
%% Caution: If you want to use this module, please |
21 |
|
%% stop the client from emqttsn if there is any! |
22 |
|
%% |
23 |
|
%% @see emqttsn_udp |
24 |
|
%% @see emqttsn_udp:init_port/0 |
25 |
|
-module(emqttsn_send). |
26 |
|
|
27 |
|
%% @headerfile "emqttsn.hrl" |
28 |
|
|
29 |
|
-include_lib("stdlib/include/assert.hrl"). |
30 |
|
|
31 |
|
-include("emqttsn.hrl"). |
32 |
|
|
33 |
|
%% API |
34 |
|
-export([send_connect/6, send_willtopic/5, send_willmsg/3, send_register/4, send_regack/5, |
35 |
|
send_subscribe/7, send_unsubscribe/5, send_publish/9, send_puback/5, send_pubrel/3, |
36 |
|
send_pubrec/3, send_pubcomp/3, send_pub_any/7, send_gwinfo/7, send_disconnect/2, |
37 |
|
send_asleep/3, send_awake/3, send_pingreq/2, send_pingresp/2, broadcast_searchgw/4]). |
38 |
|
|
39 |
|
%% @doc Send a MQTT-SN Connect packet |
40 |
|
%% |
41 |
|
%% @param Config the client object |
42 |
|
%% @param Socket the socket object |
43 |
|
%% @param Will whether need will message for connect |
44 |
|
%% @param CleanSession whether clean session for client |
45 |
|
%% @param Duration interval of keep alive timer |
46 |
|
%% @param ClientId unique name of client |
47 |
|
%% |
48 |
|
%% @returns ok | {error, not_owner | inet:posix()} |
49 |
|
%% @end |
50 |
|
-spec send_connect(config(), |
51 |
|
inet:socket(), |
52 |
|
boolean(), |
53 |
|
boolean(), |
54 |
|
non_neg_integer(), |
55 |
|
string()) -> |
56 |
|
ok | {error, term()}. |
57 |
|
send_connect(Config, Socket, Will, CleanSession, Duration, ClientId) -> |
58 |
48 |
Packet = ?CONNECT_PACKET(Will, CleanSession, Duration, ClientId), |
59 |
48 |
Bin = emqttsn_frame:serialize(Packet, Config), |
60 |
48 |
emqttsn_udp:send(Socket, Bin). |
61 |
|
|
62 |
|
%% @doc Send a MQTT-SN WillTopic packet |
63 |
|
%% |
64 |
|
%% @param Config the client object |
65 |
|
%% @param Socket the socket object |
66 |
|
%% @param Qos the qos level of will |
67 |
|
%% @param Retain whether the message is retain |
68 |
|
%% @param WillTopic the data of will topic |
69 |
|
%% |
70 |
|
%% @returns ok | {error, not_owner | inet:posix()} |
71 |
|
%% @end |
72 |
|
-spec send_willtopic(config(), inet:socket(), qos(), boolean(), string()) -> |
73 |
|
ok | {error, term()}. |
74 |
|
send_willtopic(Config, Socket, Qos, Retain, WillTopic) -> |
75 |
1 |
Packet = ?WILLTOPIC_PACKET(Qos, Retain, WillTopic), |
76 |
1 |
Bin = emqttsn_frame:serialize(Packet, Config), |
77 |
1 |
emqttsn_udp:send(Socket, Bin). |
78 |
|
|
79 |
|
%% @doc Send a MQTT-SN WillMsg packet |
80 |
|
%% |
81 |
|
%% @param Config the client object |
82 |
|
%% @param Socket the socket object |
83 |
|
%% @param WillMsg the data of will message |
84 |
|
%% |
85 |
|
%% @returns ok | {error, not_owner | inet:posix()} |
86 |
|
%% @end |
87 |
|
-spec send_willmsg(config(), inet:socket(), string()) -> ok | {error, term()}. |
88 |
|
send_willmsg(Config, Socket, WillMsg) -> |
89 |
1 |
Packet = ?WILLMSG_PACKET(WillMsg), |
90 |
1 |
Bin = emqttsn_frame:serialize(Packet, Config), |
91 |
1 |
emqttsn_udp:send(Socket, Bin). |
92 |
|
|
93 |
|
%% @doc Send a MQTT-SN WillMsg packet |
94 |
|
%% |
95 |
|
%% @param Config the client object |
96 |
|
%% @param Socket the socket object |
97 |
|
%% @param TopicName topic name to be registered |
98 |
|
%% @param PacketId the id of packet |
99 |
|
%% |
100 |
|
%% @returns ok | {error, not_owner | inet:posix()} |
101 |
|
%% @end |
102 |
|
-spec send_register(config(), inet:socket(), string(), packet_id()) -> |
103 |
|
ok | {error, term()}. |
104 |
|
send_register(Config, Socket, TopicName, PacketId) -> |
105 |
12 |
Packet = ?REGISTER_PACKET(PacketId, TopicName), |
106 |
12 |
Bin = emqttsn_frame:serialize(Packet, Config), |
107 |
12 |
emqttsn_udp:send(Socket, Bin). |
108 |
|
|
109 |
|
%% @doc Send a MQTT-SN RegAck packet |
110 |
|
%% |
111 |
|
%% @param Config the client object |
112 |
|
%% @param Socket the socket object |
113 |
|
%% @param TopicId topic id of packet |
114 |
|
%% @param ReturnCode return code of request |
115 |
|
%% @param PacketId the id of packet |
116 |
|
%% |
117 |
|
%% @returns ok | {error, not_owner | inet:posix()} |
118 |
|
%% @end |
119 |
|
-spec send_regack(config(), inet:socket(), topic_id(), return_code(), packet_id()) -> |
120 |
|
ok | {error, term()}. |
121 |
|
send_regack(Config, Socket, TopicId, ReturnCode, PacketId) -> |
122 |
:-( |
Packet = ?REGACK_PACKET(TopicId, PacketId, ReturnCode), |
123 |
:-( |
Bin = emqttsn_frame:serialize(Packet, Config), |
124 |
:-( |
emqttsn_udp:send(Socket, Bin). |
125 |
|
|
126 |
|
%% @doc Send a MQTT-SN Subscribe packet |
127 |
|
%% |
128 |
|
%% @param Config the client object |
129 |
|
%% @param Socket the socket object |
130 |
|
%% @param Dup whether it is a duplicated packet |
131 |
|
%% @param TopicIdType data type of TopicIdOrName param |
132 |
|
%% @param TopicIdOrName topic id or name to be sent(decided by TopicIdType) |
133 |
|
%% @param MaxQos max Qos level can be handled of subscribed request |
134 |
|
%% @param PacketId the id of packet |
135 |
|
%% |
136 |
|
%% @returns ok | {error, not_owner | inet:posix()} |
137 |
|
%% @end |
138 |
|
-spec send_subscribe(config(), |
139 |
|
inet:socket(), |
140 |
|
boolean(), |
141 |
|
topic_id_type(), |
142 |
|
topic_id_or_name(), |
143 |
|
qos(), |
144 |
|
packet_id()) -> |
145 |
|
ok | {error, term()}. |
146 |
|
send_subscribe(Config, Socket, Dup, TopicIdType, TopicIdOrName, MaxQos, PacketId) -> |
147 |
14 |
Packet = |
148 |
|
case TopicIdType of |
149 |
|
?SHORT_TOPIC_NAME -> |
150 |
12 |
?SUBSCRIBE_PACKET(Dup, PacketId, TopicIdOrName, MaxQos); |
151 |
|
_ -> |
152 |
2 |
?SUBSCRIBE_PACKET(Dup, TopicIdType, PacketId, TopicIdOrName, MaxQos) |
153 |
|
end, |
154 |
14 |
Bin = emqttsn_frame:serialize(Packet, Config), |
155 |
14 |
emqttsn_udp:send(Socket, Bin). |
156 |
|
|
157 |
|
%% @doc Send a MQTT-SN Unsubscribe packet |
158 |
|
%% |
159 |
|
%% @param Config the client object |
160 |
|
%% @param Socket the socket object |
161 |
|
%% @param TopicIdType data type of TopicIdOrName param |
162 |
|
%% @param TopicIdOrName topic id or name to be sent(decided by TopicIdType) |
163 |
|
%% @param PacketId the id of packet |
164 |
|
%% |
165 |
|
%% @returns ok | {error, not_owner | inet:posix()} |
166 |
|
%% @end |
167 |
|
-spec send_unsubscribe(config(), |
168 |
|
inet:socket(), |
169 |
|
topic_id_type(), |
170 |
|
topic_id_or_name(), |
171 |
|
packet_id()) -> |
172 |
|
ok | {error, term()}. |
173 |
|
send_unsubscribe(Config, Socket, TopicIdType, TopicIdOrName, PacketId) -> |
174 |
7 |
Packet = |
175 |
|
case TopicIdType of |
176 |
|
?SHORT_TOPIC_NAME -> |
177 |
7 |
?UNSUBSCRIBE_PACKET(PacketId, TopicIdOrName); |
178 |
|
_ -> |
179 |
:-( |
?UNSUBSCRIBE_PACKET(TopicIdOrName, PacketId, TopicIdOrName) |
180 |
|
end, |
181 |
7 |
Bin = emqttsn_frame:serialize(Packet, Config), |
182 |
7 |
emqttsn_udp:send(Socket, Bin). |
183 |
|
|
184 |
|
%% @doc Send a MQTT-SN Publish packet |
185 |
|
%% |
186 |
|
%% @param Config the client object |
187 |
|
%% @param Socket the socket object |
188 |
|
%% @param Qos the qos level of publish |
189 |
|
%% @param Dup whether it is a duplicated packet |
190 |
|
%% @param Retain whether the message is retain |
191 |
|
%% @param TopicIdType data type of TopicIdOrName param |
192 |
|
%% @param TopicIdOrName topic id or name to be sent(decided by TopicIdType) |
193 |
|
%% @param Message message data of publish request |
194 |
|
%% @param PacketId the id of packet |
195 |
|
%% |
196 |
|
%% @returns ok | {error, not_owner | inet:posix()} |
197 |
|
%% @end |
198 |
|
-spec send_publish(config(), |
199 |
|
inet:socket(), |
200 |
|
qos(), |
201 |
|
boolean(), |
202 |
|
boolean(), |
203 |
|
topic_id_type(), |
204 |
|
topic_id_or_name(), |
205 |
|
string(), |
206 |
|
packet_id()) -> |
207 |
|
ok | {error, term()}. |
208 |
|
send_publish(Config, |
209 |
|
Socket, |
210 |
|
Qos, |
211 |
|
Dup, |
212 |
|
Retain, |
213 |
|
TopicIdType, |
214 |
|
TopicIdOrName, |
215 |
|
Message, |
216 |
|
PacketId) -> |
217 |
13 |
?assert(TopicIdType == ?SHORT_TOPIC_NAME orelse TopicIdType == ?PRE_DEF_TOPIC_ID), |
218 |
13 |
Packet = |
219 |
|
case Qos of |
220 |
|
?QOS_0 -> |
221 |
4 |
?PUBLISH_PACKET(Dup, Retain, TopicIdType, TopicIdOrName, Message); |
222 |
|
_ -> |
223 |
9 |
?PUBLISH_PACKET(Dup, Qos, Retain, TopicIdType, TopicIdOrName, PacketId, Message) |
224 |
|
end, |
225 |
13 |
Bin = emqttsn_frame:serialize(Packet, Config), |
226 |
13 |
emqttsn_udp:send(Socket, Bin). |
227 |
|
|
228 |
|
%% @doc Send a MQTT-SN PubAck packet |
229 |
|
%% |
230 |
|
%% @param Config the client object |
231 |
|
%% @param Socket the socket object |
232 |
|
%% @param TopicId topic id of packet |
233 |
|
%% @param ReturnCode return code of request |
234 |
|
%% @param PacketId the id of packet |
235 |
|
%% |
236 |
|
%% @returns ok | {error, not_owner | inet:posix()} |
237 |
|
%% @end |
238 |
|
-spec send_puback(config(), inet:socket(), topic_id(), return_code(), packet_id()) -> |
239 |
|
ok | {error, term()}. |
240 |
|
send_puback(Config, Socket, TopicId, ReturnCode, PacketId) -> |
241 |
:-( |
Packet = ?PUBACK_PACKET(TopicId, PacketId, ReturnCode), |
242 |
:-( |
Bin = emqttsn_frame:serialize(Packet, Config), |
243 |
:-( |
emqttsn_udp:send(Socket, Bin). |
244 |
|
|
245 |
|
%% @doc Send a MQTT-SN PubRel packet |
246 |
|
%% |
247 |
|
%% @param Config the client object |
248 |
|
%% @param Socket the socket object |
249 |
|
%% @param PacketId the id of packet |
250 |
|
%% |
251 |
|
%% @returns ok | {error, not_owner | inet:posix()} |
252 |
|
%% @end |
253 |
|
-spec send_pubrel(config(), inet:socket(), packet_id()) -> ok | {error, term()}. |
254 |
|
send_pubrel(Config, Socket, PacketId) -> |
255 |
1 |
Packet = ?PUBREL_PACKET(PacketId), |
256 |
1 |
Bin = emqttsn_frame:serialize(Packet, Config), |
257 |
1 |
emqttsn_udp:send(Socket, Bin). |
258 |
|
|
259 |
|
%% @doc Send a MQTT-SN PubRec packet |
260 |
|
%% |
261 |
|
%% @param Config the client object |
262 |
|
%% @param Socket the socket object |
263 |
|
%% @param PacketId the id of packet |
264 |
|
%% |
265 |
|
%% @returns ok | {error, not_owner | inet:posix()} |
266 |
|
%% @end |
267 |
|
-spec send_pubrec(config(), inet:socket(), packet_id()) -> ok | {error, term()}. |
268 |
|
send_pubrec(Config, Socket, PacketId) -> |
269 |
:-( |
Packet = ?PUBREC_PACKET(PacketId), |
270 |
:-( |
Bin = emqttsn_frame:serialize(Packet, Config), |
271 |
:-( |
emqttsn_udp:send(Socket, Bin). |
272 |
|
|
273 |
|
%% @doc Send a MQTT-SN PubComp packet |
274 |
|
%% |
275 |
|
%% @param Config the client object |
276 |
|
%% @param Socket the socket object |
277 |
|
%% @param PacketId the id of packet |
278 |
|
%% |
279 |
|
%% @returns ok | {error, not_owner | inet:posix()} |
280 |
|
%% @end |
281 |
|
-spec send_pubcomp(config(), inet:socket(), packet_id()) -> ok | {error, term()}. |
282 |
|
send_pubcomp(Config, Socket, PacketId) -> |
283 |
:-( |
Packet = ?PUBCOMP_PACKET(PacketId), |
284 |
:-( |
Bin = emqttsn_frame:serialize(Packet, Config), |
285 |
:-( |
emqttsn_udp:send(Socket, Bin). |
286 |
|
|
287 |
|
%% @doc Send a MQTT-SN publish packet to any gateway(at Qos -1) |
288 |
|
%% |
289 |
|
%% @param Config the client object |
290 |
|
%% @param Socket the socket object(not need to connect) |
291 |
|
%% @param Host host of target gateway |
292 |
|
%% @param Port port of target gateway |
293 |
|
%% @param TopicIdType data type of TopicIdOrName param |
294 |
|
%% @param TopicIdOrName topic id or name to be sent(decided by TopicIdType) |
295 |
|
%% @param Message message data of publish request |
296 |
|
%% @returns ok | {error, not_owner | inet:posix()} |
297 |
|
%% @end |
298 |
|
-spec send_pub_any(config(), |
299 |
|
inet:socket(), |
300 |
|
host(), |
301 |
|
inet:port_number(), |
302 |
|
topic_id_type(), |
303 |
|
topic_id_or_name(), |
304 |
|
string()) -> |
305 |
|
ok | {error, term()}. |
306 |
|
send_pub_any(Config, Socket, Host, Port, TopicIdType, TopicIdOrName, Message) -> |
307 |
1 |
?assert(TopicIdType == ?SHORT_TOPIC_NAME orelse TopicIdType == ?PRE_DEF_TOPIC_ID), |
308 |
1 |
Packet = ?PUBLISH_PACKET(TopicIdType, TopicIdOrName, Message), |
309 |
1 |
Bin = emqttsn_frame:serialize(Packet, Config), |
310 |
1 |
emqttsn_udp:send_anywhere(Socket, Bin, Host, Port). |
311 |
|
|
312 |
|
%% @doc Send a MQTT-SN GwInfo packet to any client |
313 |
|
%% |
314 |
|
%% @param Config the client object |
315 |
|
%% @param Socket the socket object |
316 |
|
%% @param Host host of target client |
317 |
|
%% @param Port port of target client |
318 |
|
%% @param _Radius the radius for transmission packet(not implement) |
319 |
|
%% @param GateWayId the id of responsed gateway |
320 |
|
%% @param GateWayAdd the host of responsed gateway(without port) |
321 |
|
%% |
322 |
|
%% @returns ok | {error, not_owner | inet:posix()} |
323 |
|
%% @end |
324 |
|
-spec send_gwinfo(config(), |
325 |
|
inet:socket(), |
326 |
|
host(), |
327 |
|
inet:port_number(), |
328 |
|
pos_integer(), |
329 |
|
gw_id(), |
330 |
|
host()) -> |
331 |
|
ok | {error, term()}. |
332 |
|
send_gwinfo(Config, Socket, Host, Port, _Radius, GateWayId, GateWayAdd) -> |
333 |
:-( |
Packet = ?GWINFO_PACKET(GateWayId, GateWayAdd), |
334 |
:-( |
Bin = emqttsn_frame:serialize(Packet, Config), |
335 |
:-( |
emqttsn_udp:send_anywhere(Socket, Bin, Host, Port). |
336 |
|
|
337 |
|
%% @doc Send a MQTT-SN Disconnect packet |
338 |
|
%% |
339 |
|
%% @param Config the client object |
340 |
|
%% @param Socket the socket object |
341 |
|
%% |
342 |
|
%% @returns ok | {error, not_owner | inet:posix()} |
343 |
|
%% @end |
344 |
|
-spec send_disconnect(config(), inet:socket()) -> ok | {error, term()}. |
345 |
|
send_disconnect(Config, Socket) -> |
346 |
25 |
Packet = ?DISCONNECT_PACKET(), |
347 |
25 |
Bin = emqttsn_frame:serialize(Packet, Config), |
348 |
25 |
emqttsn_udp:send(Socket, Bin). |
349 |
|
|
350 |
|
%% @doc Send a MQTT-SN asleep Disconnect packet |
351 |
|
%% |
352 |
|
%% @param Config the client object |
353 |
|
%% @param Socket the socket object |
354 |
|
%% @param Interval sleep interval(ms) |
355 |
|
%% |
356 |
|
%% @returns ok | {error, not_owner | inet:posix()} |
357 |
|
%% @end |
358 |
|
-spec send_asleep(config(), inet:socket(), non_neg_integer()) -> ok | {error, term()}. |
359 |
|
send_asleep(Config, Socket, Interval) -> |
360 |
1 |
Packet = ?DISCONNECT_PACKET(Interval), |
361 |
1 |
Bin = emqttsn_frame:serialize(Packet, Config), |
362 |
1 |
emqttsn_udp:send(Socket, Bin). |
363 |
|
|
364 |
|
%% @doc Send a MQTT-SN awake PingReq packet |
365 |
|
%% |
366 |
|
%% @param Config the client object |
367 |
|
%% @param Socket the socket object |
368 |
|
%% @param ClientId unique name of client |
369 |
|
%% |
370 |
|
%% @returns ok | {error, not_owner | inet:posix()} |
371 |
|
%% @end |
372 |
|
-spec send_awake(config(), inet:socket(), string()) -> ok | {error, term()}. |
373 |
|
send_awake(Config, Socket, ClientId) -> |
374 |
1 |
Packet = ?PINGREQ_PACKET(ClientId), |
375 |
1 |
Bin = emqttsn_frame:serialize(Packet, Config), |
376 |
1 |
emqttsn_udp:send(Socket, Bin). |
377 |
|
|
378 |
|
%% @doc Send a MQTT-SN PingReq packet |
379 |
|
%% |
380 |
|
%% @param Config the client object |
381 |
|
%% @param Socket the socket object |
382 |
|
%% |
383 |
|
%% @returns ok | {error, not_owner | inet:posix()} |
384 |
|
%% @end |
385 |
|
-spec send_pingreq(config(), inet:socket()) -> ok | {error, term()}. |
386 |
|
send_pingreq(Config, Socket) -> |
387 |
1 |
Packet = ?PINGREQ_PACKET(), |
388 |
1 |
Bin = emqttsn_frame:serialize(Packet, Config), |
389 |
1 |
emqttsn_udp:send(Socket, Bin). |
390 |
|
|
391 |
|
%% @doc Send a MQTT-SN PingResp packet |
392 |
|
%% |
393 |
|
%% @param Config the client object |
394 |
|
%% @param Socket the socket object |
395 |
|
%% |
396 |
|
%% @returns ok | {error, not_owner | inet:posix()} |
397 |
|
%% @end |
398 |
|
-spec send_pingresp(config(), inet:socket()) -> ok | {error, term()}. |
399 |
|
send_pingresp(Config, Socket) -> |
400 |
:-( |
Packet = ?PINGRESP_PACKET(), |
401 |
:-( |
Bin = emqttsn_frame:serialize(Packet, Config), |
402 |
:-( |
emqttsn_udp:send(Socket, Bin). |
403 |
|
|
404 |
|
%% @doc Boardcast a MQTT-SN SearchGw packet |
405 |
|
%% |
406 |
|
%% @param Config the client object |
407 |
|
%% @param Socket the socket object |
408 |
|
%% @param RemotePort the port to broadcast |
409 |
|
%% @param Radius the radius for transmission packet |
410 |
|
%% |
411 |
|
%% @returns ok | {error, not_owner | inet:posix()} |
412 |
|
%% @end |
413 |
|
-spec broadcast_searchgw(config(), |
414 |
|
inet:socket(), |
415 |
|
inet:port_number(), |
416 |
|
non_neg_integer()) -> |
417 |
|
ok | {error, term()}. |
418 |
|
broadcast_searchgw(Config, Socket, RemotePort, Radius) -> |
419 |
54 |
Packet = ?SEARCHGW_PACKET(Radius), |
420 |
54 |
Bin = emqttsn_frame:serialize(Packet, Config), |
421 |
54 |
emqttsn_udp:broadcast(Socket, Bin, RemotePort). |