Packages
grizzly
0.17.6
9.1.4
9.1.2
9.1.1
9.1.0
9.0.0
8.15.3
8.15.2
8.15.1
8.15.0
8.14.0
8.13.0
8.12.0
8.11.3
8.11.2
8.11.1
8.11.0
8.10.0
8.9.0
8.8.1
8.8.0
8.7.1
8.7.0
8.6.12
8.6.11
8.6.10
8.6.9
8.6.8
8.6.7
retired
8.6.6
8.6.5
8.6.4
8.6.3
8.6.2
8.6.1
8.6.0
8.5.3
8.5.2
8.5.1
8.5.0
8.4.0
8.3.0
8.2.3
8.2.2
8.2.1
8.2.0
8.1.0
8.0.1
8.0.0
7.4.3
7.4.2
7.4.1
7.4.0
7.3.0
7.2.0
7.1.4
7.1.3
7.1.2
7.1.1
7.1.0
7.0.4
7.0.3
7.0.2
7.0.1
7.0.0
6.8.8
6.8.7
6.8.6
6.8.5
6.8.4
6.8.3
6.8.2
6.8.1
6.8.0
6.7.1
6.7.0
6.6.1
6.6.0
6.5.1
6.5.0
6.4.0
6.3.0
6.2.0
6.1.1
6.1.0
6.0.1
6.0.0
5.4.1
5.4.0
5.3.0
5.2.8
5.2.7
5.2.6
5.2.5
5.2.4
5.2.3
5.2.2
5.2.1
5.2.0
5.1.2
5.1.1
5.1.0
5.0.2
5.0.1
5.0.0
4.0.1
4.0.0
3.0.0
2.1.0
2.0.0
1.0.1
1.0.0
0.22.7
0.22.6
0.22.5
0.22.4
0.22.3
0.22.2
0.22.1
0.22.0
0.21.1
0.21.0
0.20.2
0.20.1
0.20.0
0.19.1
0.19.0
0.18.3
0.18.2
0.18.1
0.18.0
0.17.7
0.17.6
0.17.5
0.17.4
0.17.3
0.17.2
0.17.1
0.17.0
0.16.2
0.16.1
0.16.0
0.15.11
0.15.10
0.15.9
0.15.8
0.15.7
0.15.6
0.15.5
0.15.4
0.15.3
0.15.2
0.15.1
0.15.0
0.14.8
0.14.7
0.14.6
0.14.5
0.14.4
0.14.3
0.14.2
0.14.1
0.14.0
0.13.0
0.12.3
0.12.2
0.12.1
0.12.0
0.11.0
0.10.3
0.10.2
0.10.1
0.10.0
0.9.0
0.9.0-rc.4
0.9.0-rc.3
0.9.0-rc.2
0.9.0-rc.1
0.9.0-rc.0
0.8.8
0.8.7
0.8.6
0.8.5
0.8.4
0.8.3
0.8.2
0.8.1
0.8.0
0.7.0
0.6.6
0.6.5
0.6.4
0.6.3
0.6.2
0.6.1
0.6.0
0.5.0
0.4.3
0.4.2
Elixir Z-Wave library
Current section
Files
Jump to
Current section
Files
lib/grizzly/unsolicited_server/socket.ex
defmodule Grizzly.UnsolicitedServer.Socket do
@moduledoc false
use GenServer
require Logger
alias Grizzly.{Report, SeqNumber, Transport, ZWave, ZIPGateway}
alias Grizzly.ZWave.Command
alias Grizzly.ZWave.Commands.ZIPPacket
alias Grizzly.UnsolicitedServer.{Messages, SocketSupervisor, ResponseHandler}
@spec child_spec(Transport.t()) :: map()
def child_spec(transport) do
%{
id: __MODULE__,
start: {__MODULE__, :start_link, [transport]},
restart: :temporary
}
end
@spec start_link(Transport.t()) :: GenServer.on_start()
def start_link(listening_transport) do
GenServer.start_link(__MODULE__, listening_transport)
end
@impl GenServer
def init(transport) do
{:ok, transport, {:continue, :accept}}
end
@impl GenServer
def handle_continue(:accept, listening_transport) do
with {:ok, accept_transport} <- Transport.accept(listening_transport),
{:ok, _sock} <- Transport.handshake(accept_transport) do
# Start a new listen socket to replace this one as this one is now not
# open for more traffic now
{:ok, _} = SocketSupervisor.start_socket(listening_transport)
else
other ->
Logger.warn(
"grizzly: Failed to start socket. Got this on SSL handshake: #{inspect(other)}"
)
end
{:noreply, listening_transport}
end
@impl GenServer
def handle_info({:ssl_closed, _} = message, transport) do
Logger.error("[CLOSED]: #{inspect(message)}")
{:stop, :normal, transport}
end
def handle_info({:grizzly, :binary_response, _does_not_matter}, transport) do
{:noreply, transport}
end
def handle_info(response, transport) do
{:ok, transport_response} = Transport.parse_response(transport, response)
case ResponseHandler.handle_response(transport_response) do
[] ->
:ok
actions ->
Enum.each(actions, &run_response_action(transport_response, &1))
end
{:noreply, transport}
end
defp run_response_action(response, {:send, command}) do
%Transport.Response{ip_address: ip_address, command: zippacket} = response
# We have to perverse the header extensions to ensure command encapsulation
# is correct when sending the response back to the Z-Wave PAN.
header_extensions = Command.param!(zippacket, :header_extensions)
node_id = ZIPGateway.node_id_from_ip(ip_address)
_ = send_ack_response(node_id, zippacket)
{:ok, zip_packet} =
ZIPPacket.with_zwave_command(command, SeqNumber.get_and_inc(),
flag: :ack_request,
header_extensions: header_extensions
)
binary = ZWave.to_binary(zip_packet)
Grizzly.send_binary(node_id, binary)
end
defp run_response_action(response, {:notify, command}) do
:ok = Messages.broadcast(response.ip_address, command)
end
defp run_response_action(response, {:forward_to_controller, command}) do
case Grizzly.send_command(:gateway, command.name, command.params) do
{:ok, report} ->
handle_grizzly_report(report, response)
error ->
error
end
end
defp handle_grizzly_report(%Report{type: :ack_response}, response) do
%Transport.Response{ip_address: ip_address} = response
zip_packet = ZIPPacket.make_ack_response(SeqNumber.get_and_inc())
binary = ZWave.to_binary(zip_packet)
node_id = ZIPGateway.node_id_from_ip(ip_address)
Grizzly.send_binary(node_id, binary)
end
defp handle_grizzly_report(%Report{type: :command, command: command}, response) do
%Transport.Response{ip_address: ip_address} = response
{:ok, zip_packet} = ZIPPacket.with_zwave_command(command, SeqNumber.get_and_inc(), flag: nil)
binary = ZWave.to_binary(zip_packet)
node_id = ZIPGateway.node_id_from_ip(ip_address)
Grizzly.send_binary(node_id, binary)
end
defp send_ack_response(node_id, zippacket) do
header_extensions = Command.param!(zippacket, :header_extensions)
seq = Command.param!(zippacket, :seq_number)
ack_bin =
seq
|> ZIPPacket.make_ack_response(header_extensions: header_extensions)
|> ZWave.to_binary()
Grizzly.send_binary(node_id, ack_bin)
end
end