1 -module (lwes_channel
).
3 -behaviour (gen_server
).
5 -include_lib ("lwes.hrl").
6 -include ("lwes_internal.hrl").
9 -export ([ start_link
/1,
17 %% gen_server callbacks
26 -record (state
, {socket
, channel
, type
, callback
, sent
= 0, received
= 0}).
27 -record (callback
, {function, format
, state
}).
29 %%====================================================================
31 %%====================================================================
32 start_link (Channel
) ->
33 gen_server:start_link (?MODULE
, [Channel
], []).
35 open (Type
, {Ip
, Port
, TTL
, Recbuf
}) ->
36 Channel
= #lwes_channel
{
39 is_multicast
= is_multicast (Ip
),
45 { ok
, _Pid
} = lwes_channel_manager:open_channel (Channel
),
47 open (Type
, {Ip
, Port
, TTL
}) ->
48 Channel
= #lwes_channel
{
51 is_multicast
= is_multicast (Ip
),
56 { ok
, _Pid
} = lwes_channel_manager:open_channel (Channel
),
58 open (Type
, {Ip
, Port
}) ->
59 Channel
= #lwes_channel
{
62 is_multicast
= is_multicast (Ip
),
66 { ok
, _Pid
} = lwes_channel_manager:open_channel (Channel
),
69 register_callback (Channel
, CallbackFunction
, EventType
, CallbackState
) ->
70 find_and_call ( Channel
,
71 { register, CallbackFunction
, EventType
, CallbackState
}).
73 send_to (Channel
, Msg
) ->
74 find_and_call (Channel
, { send
, Msg
}).
77 find_and_cast (Channel
, stop
).
80 find_and_call (Channel
, stats
).
82 %%====================================================================
83 %% gen_server callbacks
84 %%====================================================================
85 init ([ Channel
= #lwes_channel
{
88 is_multicast
= IsMulticast
,
95 case {Type
, IsMulticast
} of
98 [ { reuseaddr
, true
},
100 { multicast_ttl
, TTL
},
101 { multicast_loop
, false
},
102 { add_membership
, {Ip
, {0,0,0,0}}},
109 [ { recbuf
, Recbuf
},
118 [ { recbuf
, Recbuf
},
119 { multicast_ttl
, TTL
},
124 [ { recbuf
, Recbuf
},
129 lwes_channel_manager:register_channel (Channel
, self()),
130 { ok
, #state
{ socket
= Socket
,
136 handle_call ({ register, Function
, Format
, Accum
},
139 channel
= #lwes_channel
{type
= listener
}
143 State#state
{ callback
= #callback
{ function = Function
,
147 handle_call ({ send
, Packet
},
151 channel
= #lwes_channel
{ ip
= Ip
, port
= Port
},
155 gen_udp:send (Socket
, Ip
, Port
, Packet
),
156 State#state
{ sent
= Sent
+ 1 }
164 { reply
, {Sent
, Received
}, State
};
166 handle_call (Request
, From
, State
) ->
167 error_logger:warning_msg ("unrecognized call ~p from ~p~n",[Request
, From
]),
168 { reply
, ok
, State
}.
170 handle_cast (stop
, State
) ->
171 {stop
, normal
, State
};
172 handle_cast (Request
, State
) ->
173 error_logger:warning_msg ("unrecognized cast ~p~n",[Request
]),
176 % skip if we don't have a handler
177 handle_info ( {udp
, _
, _
, _
, _
},
180 callback
= undefined
,
183 { noreply
, State#state
{ received
= Received
+ 1 } };
185 handle_info ( Packet
= {udp
, _
, _
, _
, _
},
188 callback
= #callback
{ function = Function
,
196 _
-> lwes_event:from_udp_packet (Packet
, Format
)
198 NewCbState
= Function (Event
, CbState
),
200 State#state
{ callback
= #callback
{ function = Function
,
202 state
= NewCbState
},
203 received
= Received
+ 1
207 handle_info ( Request
, State
) ->
208 error_logger:warning_msg ("unrecognized info ~p~n",[Request
]),
211 terminate (_Reason
, #state
{socket
= Socket
, channel
= Channel
}) ->
212 gen_udp:close (Socket
),
213 lwes_channel_manager:unregister_channel (Channel
).
215 code_change (_OldVsn
, State
, _Extra
) ->
218 %%====================================================================
219 %% Internal functions
220 %%====================================================================
221 is_multicast ({N1
, _
, _
, _
}) when N1
>= 224, N1
=< 239 ->
229 [ {raw
, 1, 15, <<1:32/native
>>} ];
230 {unix
, OS
} when OS
=:= darwin
;
234 [ {raw
, 16#ffff
, 16#
0200, <<1:32/native
>>} ];
238 find_and_call (Channel
, Msg
) ->
239 case lwes_channel_manager:find_channel (Channel
) of
243 gen_server:call ( Pid
, Msg
)
246 find_and_cast (Channel
, Msg
) ->
247 case lwes_channel_manager:find_channel (Channel
) of
251 gen_server:cast ( Pid
, Msg
)
254 %%====================================================================
256 %%====================================================================
258 -include_lib ("eunit/include/eunit.hrl").