Author: bdonlan
Date: 2005-12-09 17:24:04 -0500 (Fri, 09 Dec 2005)
New Revision: 947

Modified:
   trunk/erlang/server/haver_worker.erl
   trunk/erlang/server/schema.hrl
   trunk/erlang/server/server.erl
Log:
ghost support - be sure to remake your schema

Modified: trunk/erlang/server/haver_worker.erl
===================================================================
--- trunk/erlang/server/haver_worker.erl        2005-12-09 21:42:22 UTC (rev 
946)
+++ trunk/erlang/server/haver_worker.erl        2005-12-09 22:24:04 UTC (rev 
947)
@@ -11,6 +11,8 @@
 entry(Parent, Socket) ->
     link(Parent),
     put(socket, Socket),
+    { ok, { Address, RemotePort } } = inet:peername(Socket),
+    put(address, Address),
     receive
         { line, [ "HAVER", Vers | _ ] } ->
             haver_sendline(["HAVER", "localhost", "Erver/0.0"]),
@@ -21,7 +23,7 @@
         Foo -> io:format("haver_entry unknown msg ~p~n", [Foo])
     end.
 
-handle_ident(Uid) ->
+try_ident(Uid) ->
     F = fun() ->
         Q = query
             [ E || E <- table(users), E.name = Uid ]
@@ -29,28 +31,91 @@
         R = mnemosyne:eval(Q),
         io:format("~p~n", [R]),
         case R of
-            [] -> mnesia:write(#users{name = Uid, pid = self()}),
+            [] -> mnesia:write(#users{name = Uid, pid = self(), ip = 
get(address)}),
                   ok;
             _  -> collision
         end
     end,
     R = mnesia:transaction(F),
     case R of
-        { atomic, ok } ->
+        { atomic, ok } -> ok;
+        { atomic, collision } -> collision;
+        V -> exit(V)
+    end.
+
+handle_ident(Uid) ->
+    case try_ident(Uid) of
+        ok ->
             haver_sendline(["HELLO", Uid]),
             put(uid, Uid),
             haver_mainloop();
-        { atomic, collision } ->
+        collision ->
             haver_sendline(["FAIL", "IDENT", "exists.user", Uid]),
+            haver_login()
+    end.
+
+handle_ghost(Uid) ->
+    Myip = get(address),
+    F = fun() ->
+        Q = query [ U || U <- table(users), U.name = Uid ] end,
+        R = mnemosyne:eval(Q),
+        case R of
+            [] -> try_ident;
+            [U] ->
+                Theirip = U#users.ip,
+                case Theirip of
+                    Myip -> U;
+                    _    -> wrongip
+        end end end,
+    R = mnesia:transaction(F),
+    io:format("hg, R=~p, myip=~p~n", [R, Myip]),
+    case R of
+        { atomic, try_ident } ->
+            case try_ident(Uid) of
+                ok ->
+                    haver_sendline(["HELLO", Uid]),
+                    put(uid, Uid),
+                    haver_mainloop();
+                collision ->
+                    haver_sendline(["FAIL", "GHOST", "race", Uid]),
+                    haver_login()
+            end;
+        { atomic, wrongip } ->
+            haver_sendline(["FAIL", "GHOST", "ip.mismatch", Uid]),
             haver_login();
-        Wtf -> io:format("wtf: ~p~n", [Wtf])
+        { atomic, U  } -> perform_ghost(U)
     end.
 
+perform_ghost(U) ->
+    io:format("p_g: U=~p~n", [U]),
+    Uid = U#users.name,
+    Pid = U#users.pid,
+    erlang:monitor(process, U#users.pid),
+    U#users.pid ! { quit, "ghost", ghost },
+    receive
+        {'DOWN', _, _, Pid, _} ->
+             server:reap_child(U#users.pid, ghost),
+             case try_ident(U#users.name) of
+                 collision ->
+                     haver_sendline(["FAIL", "GHOST", "race"]),
+                     haver_login();
+                 ok ->
+                     haver_sendline(["HELLO", Uid]),
+                     put(uid, Uid),
+                     haver_mainloop()
+             end
+    after
+        5000 ->
+            haver_sendline(["FAIL", "GHOST", "timeout", Uid]),
+            haver_login()
+    end.
+
 haver_login() ->
     receive
         { line, [ "IDENT", Uid ] } -> handle_ident(Uid);
+        { line, [ "GHOST", Uid ] } -> handle_ghost(Uid);
         { line, _ } ->
-            haver_sendline(["DIE", "ihateyou"]),
+            haver_sendline(["DIE", "wrong.command"]),
             gen_tcp:close(get(socket)),
             exit(rudepeer);
         M -> exit({unexpected, M})
@@ -237,6 +302,7 @@
             haver_sendline(["BYE", Detail]),
             gen_tcp:close(get(socket)),
             exit({ quit, "bye", Detail});
+        { line, [ "BYE" ] } -> self() ! { line, [ "BYE", "bye" ] }
         { line, [ L | T ] } ->
             io:format("unmatched line: ~p~n", [L|T]),
             haver_sendline(["FAIL", L, "unknown.cmd"]),
@@ -247,6 +313,10 @@
         { privmsg, From, Message } ->
             haver_sendline(["FROM", From | Message]),
             ok;
-        Other -> io:format("unknown msg: ~p~n", Other), exit(Other)
+        { quit, Message, Exitcode } ->
+            haver_sendline(["BYE", Message]),
+            gen_tcp:close(get(socket)),
+            exit(Exitcode);
+        Other -> io:format("unknown msg: ~p~n", [Other]), exit(Other)
         end,
     haver_mainloop().

Modified: trunk/erlang/server/schema.hrl
===================================================================
--- trunk/erlang/server/schema.hrl      2005-12-09 21:42:22 UTC (rev 946)
+++ trunk/erlang/server/schema.hrl      2005-12-09 22:24:04 UTC (rev 947)
@@ -1,4 +1,4 @@
--record(users, {name,
-                pid}).
+% vim: set ft=erlang :
+-record(users, {name, pid, ip}).
 -record(channels, {name, notused}).
 -record(chanjoin, {channel, user}).

Modified: trunk/erlang/server/server.erl
===================================================================
--- trunk/erlang/server/server.erl      2005-12-09 21:42:22 UTC (rev 946)
+++ trunk/erlang/server/server.erl      2005-12-09 22:24:04 UTC (rev 947)
@@ -1,6 +1,6 @@
 -module(server).
 -export([cstart/1, start/1, stop/0, worker/2, setup_schema/0,
-         clear_transients/0]).
+         clear_transients/0, reap_child/2]).
 -import(haver_worker, []).
 -import(haver_protocol, [encode/1, decode/1]).
 -include_lib("mnemosyne/include/mnemosyne.hrl").
@@ -57,10 +57,13 @@
         ok -> { ok, spawn(?MODULE, cstart, [Port]) };
         Err -> { nok, Err }
     end.
-stop() -> haver ! shutdown.
+stop() ->
+    haver ! shutdown.
+    
 
 match_reason({quit, Type, Detail}) -> {Type, Detail};
 match_reason({socket_closed, _}) -> {"closed", ""};
+match_reason(ghost) -> {"ghost", ""};
 match_reason(R) ->
     io:format("Unknown quit-reason: ~p~n", [R]),
     { "error", io_lib:format("~w", [R]) }.


Reply via email to