diff options
Diffstat (limited to 'lib/net')
-rw-r--r-- | lib/net/manager.ex | 60 | ||||
-rw-r--r-- | lib/net/tcpconn.ex | 9 | ||||
-rw-r--r-- | lib/net/tcpserver.ex | 17 |
3 files changed, 69 insertions, 17 deletions
diff --git a/lib/net/manager.ex b/lib/net/manager.ex new file mode 100644 index 0000000..e5eb12d --- /dev/null +++ b/lib/net/manager.ex @@ -0,0 +1,60 @@ +defmodule SNet.Manager do + use GenServer + + def start_link(my_port) do + GenServer.start_link(__MODULE__, my_port, name: __MODULE__) + end + + def init(my_port) do + state = %{ + peers: %{}, + my_port: my_port + } + {:ok, state} + end + + def handle_cast({:peer_up, pk, pid, addr, ip}, state) do + new_peers = Map.put(state.peers, pk, {pid, addr, ip}) + new_state = %{ state | peers: new_peers } + {:noreply, new_state} + end + + def handle_cast({:peer_down, pk, addr, ip}, state) do + new_peers = Map.put(state.peers, pk, {nil, addr, ip}) + new_state = %{ state | peers: new_peers } + {:noreply, new_state} + end + + def handle_cast({:add_peer, ip, port}, state) do + add_peer(ip, port, state.my_port) + {:noreply, state} + end + + def handle_cast({:try_connect, pk_list}, state) do + for pk <- pk_list do + case state.peers[pk] do + {nil, ip, port} -> add_peer(ip, port) + _ -> nil + end + end + {:noreply, state} + end + + def handle_call({:get_connections, pk_list}, state) do + pid_list = (for pk <- pk_list, Map.has_key?(state.peers, pk), do: state.peers[pk]) + |> Enum.map(fn {pid, _, _} -> pid end) + |> Enum.filter(&(&1 != nil)) + {:ok, pid_list, state} + end + + def add_peer(ip, port) do + GenServer.cast(__MODULE__, {:add_peer, ip, port}) + end + + def add_peer(ip, port, my_port) do + {:ok, client} = :gen_tcp.connect(ip, port, [:binary, packet: 2, active: false]) + {:ok, pid} = DynamicSupervisor.start_child(SNet.ConnSupervisor, {SNet.TCPConn, %{socket: client, my_port: my_port}}) + :ok = :gen_tcp.controlling_process(client, pid) + pid + end +end diff --git a/lib/net/tcpconn.ex b/lib/net/tcpconn.ex index 5d6c912..301e931 100644 --- a/lib/net/tcpconn.ex +++ b/lib/net/tcpconn.ex @@ -25,11 +25,10 @@ defmodule SNet.TCPConn do {:ok, challenge} = Salty.Random.buf 32 # Exchange public keys and challenge - :gen_tcp.send(socket, srv_pkey <> sess_pkey <> challenge) + hello = {srv_pkey, sess_pkey, challenge, state.my_port} + :gen_tcp.send(socket, :erlang.term_to_binary hello) {:ok, pkt} = :gen_tcp.recv(socket, 0) - cli_pkey = binary_part(pkt, 0, Sign.publickeybytes) - cli_sess_pkey = binary_part(pkt, Sign.publickeybytes, Box.publickeybytes) - cli_challenge = binary_part(pkt, Sign.publickeybytes + Box.publickeybytes, 32) + {cli_pkey, cli_sess_pkey, cli_challenge, his_port} = :erlang.binary_to_term(pkt, [:safe]) # Do challenge and check their challenge {:ok, cli_challenge_sign} = Sign.sign_detached(cli_challenge, srv_skey) @@ -54,6 +53,7 @@ defmodule SNet.TCPConn do addr: addr, port: port } + GenServer.cast(SNet.Manager, {:peer_up, self(), cli_pkey, addr, his_port}) Logger.info "New peer: #{print_id state} at #{inspect addr}:#{port}" GenServer.cast(self(), :init_push) @@ -98,6 +98,7 @@ defmodule SNet.TCPConn do def handle_info({:tcp_closed, _socket}, state) do Logger.info "Disconnected: #{print_id state} at #{inspect state.addr}:#{state.port}" + GenServer.cast(SNet.Manager, {:peer_down, state.his_pkey, state.addr, state.port}) exit(:normal) end diff --git a/lib/net/tcpserver.ex b/lib/net/tcpserver.ex index e5ee996..7c758c1 100644 --- a/lib/net/tcpserver.ex +++ b/lib/net/tcpserver.ex @@ -6,7 +6,6 @@ defmodule SNet.TCPServer do Task.start_link(__MODULE__, :accept, [port]) end - @doc """ Starts accepting connections on the given `port`. """ @@ -14,22 +13,14 @@ defmodule SNet.TCPServer do {:ok, socket} = :gen_tcp.listen(port, [:binary, packet: 2, active: false, reuseaddr: true]) Logger.info "Accepting connections on port #{port}" - loop_acceptor(socket) + loop_acceptor(socket, port) end - defp loop_acceptor(socket) do + defp loop_acceptor(socket, my_port) do {:ok, client} = :gen_tcp.accept(socket) - {:ok, pid} = DynamicSupervisor.start_child(SNet.ConnSupervisor, {SNet.TCPConn, %{socket: client}}) + {:ok, pid} = DynamicSupervisor.start_child(SNet.ConnSupervisor, {SNet.TCPConn, %{socket: client, my_port: my_port}}) :ok = :gen_tcp.controlling_process(client, pid) - loop_acceptor(socket) + loop_acceptor(socket, my_port) end - - def add_peer(ip, port) do - {:ok, client} = :gen_tcp.connect(ip, port, [:binary, packet: 2, active: false]) - {:ok, pid} = DynamicSupervisor.start_child(SNet.ConnSupervisor, {SNet.TCPConn, %{socket: client}}) - :ok = :gen_tcp.controlling_process(client, pid) - pid - end - end |