defmodule CaaS do use GenServer def start_link(args) do # GenServer.start_link(__MODULE__, :init, [socket]) pid = spawn(__MODULE__, :init, [args]) {:ok, pid} end def init(args = %{password: _}) do socket = receive do {:pass_socket, socket} -> socket end :inet.setopts(socket, packet: 4) auth = "auth:" <> args.password case :gen_tcp.recv(socket, 0) do {:ok, ^auth} -> :gen_tcp.send(socket,"auth ok\r\n") worker(socket, []) {:ok, unk} -> :gen_tcp.send(socket, "auth error\r\n") :gen_tcp.close(socket) end end def worker(socket, context) do {:ok, data} = :gen_tcp.recv(socket, 0) IO.puts("received #{inspect(data)}") context = try do {res, context} = Code.eval_string(data, context) # IO.inspect(context) :gen_tcp.send(socket, inspect(res)) IO.inspect(res) context catch a, b -> IO.puts("error #{inspect(a)} #{inspect(b)}") IO.puts("#{inspect(__STACKTRACE__)}") :gen_tcp.send(socket, "error\r\n#{inspect(b)}") context end __MODULE__.worker(socket, context) end end defmodule CaaS.Acceptor do use GenServer def start_link(%{port: port} = args) do GenServer.start_link(__MODULE__, args, []) end def init(%{port: port, password: password} = args) do params = %{ password: password } IO.puts("caas listen on port #{port}") {:ok, listenSocket} = :gen_tcp.listen(port, [ {:ip, {0, 0, 0, 0}}, {:active, false}, {:reuseaddr, true}, {:nodelay, true}, :binary ]) {:ok, _} = :prim_inet.async_accept(listenSocket, -1) {:ok, %{listen_socket: listenSocket, clients: [], params: params}} end def handle_info( {:inet_async, listenSocket, _, {:ok, clientSocket}}, state = %{params: %{} = params} ) do :prim_inet.async_accept(listenSocket, -1) {:ok, pid} = CaaS.start_link(params) :inet_db.register_socket(clientSocket, :inet_tcp) :gen_tcp.controlling_process(clientSocket, pid) send(pid, {:pass_socket, clientSocket}) Process.monitor(pid) {:noreply, %{state | clients: [pid | state.clients]}} end def handle_info({:inet_async, _listenSocket, _, error}, state) do IO.puts( "#{inspect(__MODULE__)}: Error in inet_async accept, shutting down. #{inspect(error)}" ) {:stop, error, state} end def handle_info(_, state) do {:noreply, state} end def handle_call(:get_clients, _from, state) do {:reply, state.clients, state} end end