/__w/emqttsn/emqttsn/_build/test/cover/aggregate/emqttsn_udp.html

1 %%-------------------------------------------------------------------------
2 %% Copyright (c) 2021-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 working with socket, can be used
18 %% standalone or with <i>emqttsn_send</i>
19 %%
20 %% @see emqttsn_send
21 -module(emqttsn_udp).
22
23 %% @headerfile "emqttsn.hrl"
24
25 -include("logger.hrl").
26 -include("emqttsn.hrl").
27
28 -include_lib("eunit/include/eunit.hrl").
29
30 -export([init_port/1, init_port/0, connect/3, send/2, send_anywhere/4, broadcast/3,
31 recv/1, recv/2]).
32
33 %% @doc Start a udp socket at given port
34 %%
35 %% @param Port on which to open the socket
36 %%
37 %% @returns ok | {error, system_limit | inet:posix()}
38 %% @end
39 -spec init_port(inet:port_number()) -> {ok, inet:socket()} | {error, term()}.
40 init_port(LocalPort) ->
41 49 case gen_udp:open(LocalPort, [binary, {active, true}, {broadcast, true}]) of
42 {ok, Socket} ->
43 45 {ok, Socket};
44 {error, Reason} when LocalPort =:= 0 ->
45 3 ?LOGP(error, "Open random port failed, reason : ~p", [Reason]),
46 3 {error, Reason};
47 {error, _Reason} when LocalPort =/= 0 ->
48 1 ?LOGP(warning, "Open port ~p failed, turn to random port", [LocalPort]),
49 1 init_port()
50 end.
51
52 %% @doc Start a udp socket at auto pick port
53 %%
54 %% @equiv init_port(0)
55 %%
56 %% @returns ok | {error, system_limit | inet:posix()}
57 %% @end
58 -spec init_port() -> {ok, inet:socket()} | {error, term()}.
59 init_port() ->
60 11 init_port(0).
61
62 %% @doc Connect to gateway
63 %%
64 %% Caution: not really <i>connect</i>,
65 %% only store infomation for udp!
66 %%
67 %% @param Socket the socket object
68 %% @param Host host of gateway to connect
69 %% @param Port port of gateway to connect
70 %%
71 %% @end
72 -spec connect(inet:socket(), host(), inet:port_number()) -> ok | {error, term()}.
73 connect(Socket, Host, Port) ->
74 31 case gen_udp:connect(Socket, Host, Port) of
75 ok ->
76 30 ok;
77 {error, Reason} ->
78 1 {error, Reason}
79 end.
80
81 %% @doc send binary packet to connected gateway
82 %%
83 %% Caution: need to connect first before call it!
84 %%
85 %% @param Socket the socket object
86 %% @param Bin Binary packet send to gateway
87 %%
88 %% @returns ok | {error, not_owner | inet:posix()}
89 %% @end
90 -spec send(inet:socket(), bitstring()) -> ok | {error, term()}.
91 send(Socket, Bin) ->
92 125 gen_udp:send(Socket, Bin).
93
94 %% @doc send binary packet to any host
95 %%
96 %% @param Socket the socket object
97 %% @param Bin Binary packet send to gateway
98 %% @param Host host of target to send packet
99 %% @param RemotePort port of target to send packet
100 %%
101 %% @returns ok | {error, not_owner | inet:posix()}
102 %% @end
103 -spec send_anywhere(inet:socket(), bitstring(), host(), inet:port_number()) ->
104 ok | {error, term()}.
105 send_anywhere(Socket, Bin, Host, RemotePort) ->
106 1 gen_udp:send(Socket, {Host, RemotePort}, Bin).
107
108 %% @doc broadcast binary packet to local network
109 %%
110 %% @param Socket the socket object
111 %% @param Bin Binary packet send to gateway
112 %% @param RemotePort port of target to send packet
113 %%
114 %% @returns ok | {error, not_owner | inet:posix()}
115 %% @end
116 -spec broadcast(inet:socket(), bitstring(), inet:port_number()) -> ok | {error, term()}.
117 broadcast(Socket, Bin, RemotePort) ->
118 56 case gen_udp:send(Socket, '255.255.255.255', RemotePort, Bin) of
119 {error, Reason} ->
120 1 ?LOGP(warning, "boardcast failed at send data:~p", [Reason]),
121 1 {error, Reason};
122 ok ->
123 55 ok
124 end.
125
126 %% @doc recv and parse incoming packet
127 %%
128 %% @param Socket the socket object
129 %% @equiv recv(Socket, 2000)
130 %%
131 %% @returns ok | {error, not_owner | inet:posix()}
132 %% @end
133 -spec recv(inet:socket()) -> {ok, mqttsn_packet()} | udp_receive_timeout.
134 recv(Socket) ->
135 6 recv(Socket, 2000).
136
137 %% @doc recv and parse incoming packet at given timeout
138 %%
139 %% @param Socket the socket object
140 %% @param Timeout the timeout of recv packet
141 %%
142 %% @returns {ok, mqttsn_packet()} | {error, udp_receive_timeout}
143 %% @end
144 -spec recv(inet:socket(), pos_integer()) -> {ok, mqttsn_packet()} | {error, term()}.
145 recv(Socket, Timeout) ->
146 10 receive
147 {udp, Socket, _, _, Bin} ->
148 6 ?LOGP(debug, "receive_response Bin=~p~n", [Bin]),
149 6 case emqttsn_frame:parse(Bin) of
150 {ok, Packet} ->
151 4 {ok, Packet};
152 {error, Reason} ->
153 2 ?LOGP(warning, "parse packet ~p failed: ~p", [Bin, Reason]),
154 2 {error, Reason}
155 end;
156 Other ->
157 2 ?LOGP(warning, "receive_response() Other message: ~p", [{unexpected_data, Other}]),
158 2 {error, unexpected_data}
159 after Timeout ->
160 2 {error, udp_receive_timeout}
161 end.
Line Hits Source