From b4867481f4aa80af1904654a23370c30bba8dcd1 Mon Sep 17 00:00:00 2001 From: "psyc://psyced.org/~lynX" <@> Date: Wed, 19 Jan 2011 22:19:34 +0100 Subject: [PATCH] unlink detection rewrite - please test this --- world/net/person.c | 44 ++++++++++++++++++++++++++-------------- world/net/psyc/circuit.c | 4 +++- world/net/psyc/server.c | 10 ++++----- world/net/psyc/user.c | 20 +++++++++++------- world/net/spyc/circuit.c | 7 ++++++- world/net/spyc/server.c | 4 ++-- world/net/user.c | 17 +++++++++++----- 7 files changed, 70 insertions(+), 36 deletions(-) diff --git a/world/net/person.c b/world/net/person.c index 09c9e5c..3df6643 100644 --- a/world/net/person.c +++ b/world/net/person.c @@ -525,6 +525,15 @@ static linkSet(service, location, source) { v("locations")[service] = ([ location ]); } register_location(location, ME); + // let me know if you lose the connection to my link! + object circuit = find_target_handler(location); + if (objectp(circuit)) { + P3(("linkSet: registering disc notify for %O from %O.\n", + location, circuit)) + circuit -> register_link(ME); + } + // probably should go to the user instead + else P1(("Warning for %O: Location %O will ghost.\n", MYNICK, location)) if (service) sendmsg(source, "_notice_link_service", 0, ([ "_service" : service, "_location" : location, @@ -551,22 +560,24 @@ static linkSet(service, location, source) { } P2(("locations after linkSet: %O\n", v("locations"))) } -static linkDel(service, source, variant) { +linkDel(service, source, variant) { P3(("linkDel(%O, %O, %O) called in %O!\n", service, source, variant, ME)) string mc = "_notice_unlink"; service = service || 0; unless (member(v("locations"), service)) { - P3(("linkDel(%O, %O) called in %O: no such candidate!\n", + P4(("linkDel(%O, %O) called in %O: no such candidate!\n", service, source, ME)); return 0; } int n = 0; foreach(string candidate : v("locations")[service]) { + P4(("linkDel(%O, %O) in %O: unlinking %O ? handler = %O\n", + service, source, ME, candidate, find_target_handler(candidate))); if ((objectp(source) && find_target_handler(candidate) != source) || (source && !objectp(source) && candidate != source)) continue; - P2(("linkDel(%O, %O) called in %O: unlinking %O.\n", + P2(("linkDel(%O, %O) in %O: unlinking %O.\n", service, source, ME, candidate)); // sLocation? register_location(candidate, 0); @@ -1049,7 +1060,6 @@ case "_set_password": if (checkPassword(vars["_password"], vars["_method"], nonce, vars)) #endif { - string scheme; mixed *u; // TODO? add support for integer _service means multiple @@ -1084,8 +1094,11 @@ case "_set_password": return display; } #endif - scheme = v("scheme"); -#if 1 +#if 0 +// no new link should throw out interactives or other links! +// this must be from the days when we had no disconnect notification +// so it would remove ghosts of itself.. +// his should be unnecessary by now! --lynX 2011 // in other cases this is done by // morph. this may not be the very best // solution, but until person/user is rewritten @@ -1108,13 +1121,13 @@ case "_set_password": // allows two psyc clients to be logged in // concurrently and is very suspicious if (query_once_interactive(ME) - || (scheme && scheme != "psyc")) { + || (v("scheme") && v("scheme") != "psyc")) { // temporary fix for initially created psyc // users. (they dont have a scheme) object o; save(); if (interactive(ME)) { - linkDel(); + // linkDel(); doesn't make sense here remove_interactive(ME); } o = named_clone(PSYC_PATH "user", MYNICK); @@ -1172,7 +1185,7 @@ case "_set_password": // language support for clients.. // done in w() instead. vars["_INTERNAL_origin"]->sTextPath(v("layout"), - v("language"), scheme); + v("language"), v("scheme")); #endif // yeah right.. //unless (interactive()) vSet("host", source); @@ -2637,13 +2650,14 @@ quit(immediate, variant) { int rc; P3(("person:QUIT(%O,%O) in %O\n", immediate,variant, ME)) - // keeping services running while logging out should be possible.. but - // we currently don't do that -- now we do - linkDel(0, previous_object()); -#if 0 +#if 1 + // keeping services running while logging out should be possible.. + // will this unlink all main clients? should it? + linkDel(0); // 0, previous_object()); <- this can be ME and will fail +#else if (sizeof(v("locations"))) { // this should only trigger at first pass linkCleanUp(); -#if 1 //def PARANOID +# if 1 //def PARANOID if (sizeof(v("locations"))) { P1(("%O * Hey, linkCleanUp left us with %O\n", ME, v("locations"))) @@ -2651,7 +2665,7 @@ quit(immediate, variant) { // breaks when we do vSet("locations", ([])); } -#endif +# endif } #endif if (immediate == 1 || (immediate && find_call_out(#'quit) != -1)) { //' diff --git a/world/net/psyc/circuit.c b/world/net/psyc/circuit.c index 6a2fb62..23ec73c 100644 --- a/world/net/psyc/circuit.c +++ b/world/net/psyc/circuit.c @@ -474,9 +474,11 @@ int disconnected(string remaining) { #endif // wow.. a sincerely expected disconnect! if (flags & TCP_PENDING_DISCONNECT) return 1; -#ifndef _flag_disable_report_failure_network_circuit_disconnect +#ifdef _flag_enable_report_failure_network_circuit_disconnect monitor_report("_failure_network_circuit_disconnect", object_name(ME) +" · lost PSYC circuit"); +#else + P1(("%O disconnected unexpectedly\n", ME)) #endif return 0; // unexpected } diff --git a/world/net/psyc/server.c b/world/net/psyc/server.c index bc72b7f..b5c8b69 100644 --- a/world/net/psyc/server.c +++ b/world/net/psyc/server.c @@ -19,7 +19,8 @@ inherit PSYC_PATH "circuit"; // keep a list of objects to ->disconnected() when the driver tells us volatile array(object) disconnect_notifies; -void do_notify_on_disconnect(object user) { +void register_link(object user) { + P4(("disconnect_notifies for %O in %O\n", user, ME)) unless(disconnect_notifies) disconnect_notifies = ({ }); disconnect_notifies += ({ user }); @@ -54,11 +55,10 @@ protected quit() { QUIT } // self-destruct when the TCP link gets lost disconnected(remaining) { - P2(( "%O got disconnected.\n", ME)) // emulate disconnected() for net/psyc/user - if (disconnect_notifies) { - foreach (object t : disconnect_notifies) - if (t) t->disconnected(); + if (disconnect_notifies) foreach (object t : disconnect_notifies) { + P3(( "%O disconnecting %O\n", ME, t)) + if (t) t->link_disconnected(); } ::disconnected(remaining); QUIT // returns unexpected.. TODO diff --git a/world/net/psyc/user.c b/world/net/psyc/user.c index e0b3005..bbc6732 100644 --- a/world/net/psyc/user.c +++ b/world/net/psyc/user.c @@ -1,6 +1,7 @@ // $Id: user.c,v 1.15 2008/12/09 19:27:32 lynx Exp $ // vim:syntax=lpc // -// handler for PSYC clients +// should be a dummy user object since all user objects +// must be able to handle PSYC clients #include "common.h" #include @@ -12,14 +13,19 @@ logon() { #ifdef NO_EXTERNAL_LOGINS return destruct(ME); #endif +#if 0 // psyc users dont have their own socket, so the driver // does not call disconnected() for them - this enables the // psyc socket to do that - if (this_interactive()) this_interactive()->do_notify_on_disconnect(ME); +// basically a good idea, but the wrong place to do this. since we +// want to be notified about any of n possible psyc clients we need +// to do this in linkSet(). --lynX + if (this_interactive()) this_interactive()->register_link(ME); // connection that is creating us, died while we got here. // rare, but does indeed happen sometimes. else return destruct(ME); - +// i presume the else case is better handled by disconnected() --lynX +#endif // no lang support here either vSet("scheme", "psyc"); return ::logon(); @@ -27,10 +33,10 @@ logon() { // errors only, it says pr(mc, fmt, a,b,c,d,e,f,g,h) { -#if 1 //def PRO_PATH - if (abbrev("_message",mc)) return; - if (v("location")) - sendmsg(v("location"), mc+"_print", sprintf(fmt, a,b,c,d,e,f,g,h) ); +#if 1 //ndef DEVELOPMENT + //if (abbrev("_message",mc)) return; + foreach (string location : v("locations")[0]) + sendmsg(location, mc+"_print", sprintf(fmt, a,b,c,d,e,f,g,h) ); #else // checkVar() still calls pr() .... grmlblmblm TODO raise_error("pr() called\n"); diff --git a/world/net/spyc/circuit.c b/world/net/spyc/circuit.c index 3eaff45..55aaa12 100644 --- a/world/net/spyc/circuit.c +++ b/world/net/spyc/circuit.c @@ -183,9 +183,14 @@ int disconnected(string remaining) { #endif // wow.. a sincerely expected disconnect! if (flags & TCP_PENDING_DISCONNECT) return 1; +#ifdef _flag_enable_report_failure_network_circuit_disconnect monitor_report("_failure_network_circuit_disconnect", object_name(ME) +" · lost PSYC circuit"); - return 0; // unexpected +#else + P1(("%O disconnected unexpectedly\n", ME)) +#endif + return 0; // unexpected + } // respond to the first empty packet diff --git a/world/net/spyc/server.c b/world/net/spyc/server.c index 05bbb4a..89bd439 100644 --- a/world/net/spyc/server.c +++ b/world/net/spyc/server.c @@ -15,7 +15,7 @@ inherit NET_PATH "spyc/circuit"; // keep a list of objects to ->disconnected() when the driver tells us volatile array(object) disconnect_notifies; -void do_notify_on_disconnect(object user) { +void register_link(object user) { unless(disconnect_notifies) disconnect_notifies = ({ }); disconnect_notifies += ({ user }); @@ -54,7 +54,7 @@ disconnected(remaining) { // emulate disconnect() for net/psyc/user if (disconnect_notifies) { foreach (object t : disconnect_notifies) - if (t) t->disconnected(); + if (t) t->link_disconnected(); } rc = ::disconnected(remaining); destruct(ME); diff --git a/world/net/user.c b/world/net/user.c index dcabe18..26127cd 100644 --- a/world/net/user.c +++ b/world/net/user.c @@ -1760,16 +1760,23 @@ quit(immediate, variant) { return ::quit(immediate, variant); } +link_disconnected() { + P3(("link_disconnected in %O from %O\nlocations: %O\n", ME, previous_object(), v("locations"))) + linkDel(0, previous_object()); + // if there are any catch-all connections left don't quit, + // just delete link + if (member(v("locations"), 0) && sizeof(v("locations")[0])) return; + // unless we have a legacy client, let's get outta here + unless (interactive(ME)) disconnected(); +} + // driver calls us here to tell us we lost the connection // if you don't like this default behaviour, override it // // we also call this manually from _request_unlink_disconnect disconnected(remainder) { - P2(("disconnected(%O) called in %O\nlocations: %O\n", remainder, ME, v("locations"))) - // if there are any catch-all connections left don't quit, just delete link - if (member(v("locations"), 0) && sizeof(v("locations")[0]) > 1) - return linkDel(0, previous_object()); - + P2(("disconnected(%O) in %O from %O\n", + remainder, ME, previous_object())) // user did not detach his client properly. we'll make a wild guess // at how many messages he may have missed - enough to make the user // check the lastlog if that's not enough.