// vim:foldmethod=marker:syntax=lpc:noexpandtab // $Id: server.c,v 1.19 2008/12/27 00:42:04 lynx Exp $ // // the thing that answers on port 4404 of psyced. #include "psyc.h" #ifdef LIBPSYC #include #include #define NO_INHERIT #include // receiving variant inherit NET_PATH "spyc/circuit"; // keep a list of objects to ->disconnected() when the driver tells us volatile array(object) disconnect_notifies; void register_link(object user) { unless(disconnect_notifies) disconnect_notifies = ({ }); disconnect_notifies += ({ user }); } // only used by list_sockets() string qName() { switch (sizeof(disconnect_notifies)) { case 0: return 0; case 1: return to_string( disconnect_notifies[0] ); // default: } return to_string( sizeof(disconnect_notifies) ); } //isServer() { return peerport < 0; } int isServer() { return 1; } load(ho, po) { D0 ( if (peerport) PP(("%O loaded twice for %O and %O\n", ME, peerport, po)); ) peerport = po; // P3(("loaded server on %O\n", peerport)) return ME; } protected quit() { QUIT } // self-destruct when the TCP link gets lost disconnected(remaining) { int rc; P2(( "%O got disconnected.\n", ME)) // emulate disconnect() for net/psyc/user if (disconnect_notifies) { foreach (object t : disconnect_notifies) if (t) t->link_disconnected(); } rc = ::disconnected(remaining); destruct(ME); return rc; } // this only gets called from net/psyc.. FIXME void greet() { // should be doing sTextPath(); here ? // should be sharing code with net/psyc and do a proper greeting // three separate packets follow (thus three emits) //emit(S_GLYPH_PACKET_DELIMITER "\n"); /* emit("\ :_source\t"+ SERVER_UNIFORM +"\n\ :_target_peer\tpsyc://"+ peeraddr +"/\n\ \n\ _notice_circuit_established\n" S_GLYPH_PACKET_DELIMITER "\n"); emit("\ :_source\t"+ SERVER_UNIFORM +"\n\ \n\ _status_circuit\n" S_GLYPH_PACKET_DELIMITER "\n"); #ifdef _flag_log_sockets_SPYC log_file("RAW_SPYC", "« %O greeted.\n", ME); #endif */ } static void resolved(mixed host, mixed tag) { PT(("resolved %O to %O\n", peerip, host)) string numericpeeraddr; mixed uni, psycip; unless (stringp(host)) { #if 1 //ndef SYMLYNX if (host == -2) { monitor_report("_warning_invalid_hostname", S("%O: %O has an invalid IN PTR", ME, query_ip_number(ME))); # ifndef STRICT_DNS_POLICY // we could instead lower the trust value for this // host so that it can no longer send messages in // a federated way, but still link into an identity // as a client....... TODO.. like this? if (trustworthy < 6) trustworthy = 1; host = peerip; # else croak("_error_invalid_hostname", "Your IP address points to a hostname which doesn't point back to the IP.\n" "You could be trying to spoof you're in somebody else's domain.\n" "We can't let you do that, sorry."); return; # endif } else if (host == -1) host = peerip; else { P0(("resolved(%O) in %O. but that's impossible.\n", host, ME)) croak("_failure_invalid_hostname", "Resolving your IP address triggered an internal error."); return; } #else // we sent them to the test server, so let it be easy on them host = peerip; #endif } // maybe dns_rresolve should only return lower_case'd strings // then we no longer have to do that everywhere else TODO host = lower_case(host); #ifdef EXTRA_RRESOLVE EXTRA_RRESOLVE(host) #endif if (trustworthy < 6) { if (trustworthy = legal_domain(host, peerport, "psyc", 0)) { if (trustworthy < 3) trustworthy = 0; } else { croak("_error", "Sei nicht so ein Mauerbluemchen"); return; } } // the resolver does not register automatically, so here we go register_host(peerip, host); register_host(host); // register_target( "psyc://"+peeraddr ); numericpeeraddr = peeraddr; peeraddr = peerhost = host; // peerport has either positive or negative value if (peerport && peerport != PSYC_SERVICE) peeraddr += ":"+peerport; netloc = "psyc://"+peeraddr+"/"; register_target( netloc ); #ifndef _flag_disable_module_authentication // OPTIONAL // should this server be connected to a psyc client, then the new // resolved name of the connection may have to be recognized as // location for the person. finally this code should be unnecessary // as you should never want to _link a person before seeing the // _notice_circuit_established. maybe we should even enforce that. // anyway, here's an attempt to cope with such a situation.. maybe // it turns out useful someday (lynX after a quick patch by elrid). // psycip = "psyc://"+numericpeeraddr+"/"; if (uni = lookup_identification(psycip)) { register_location(netloc, uni); // cleanup? are you sure we will never need this again? register_location(psycip, 0); //cleanup } #endif // _flag_disable_module_authentication // PIKE TPD: says psyc://127.0.0.1/ here .. should say // psyc://localhost:-23232/ instead P2(("%O resolves as %O (UNI %O)\n", ME, netloc, uni)) if (flags & TCP_PENDING_TIMEOUT) { P0(("removing call out\n")) remove_call_out(#'quit); flags -= TCP_PENDING_TIMEOUT; } resume_parse(); sTextPath(); greet(); //msg(0, "_notice_features", 0, tag ? ([ "_tag_reply" : tag ]) : 0); } int logon(int nothing) { P2(("%O accepted TCP from %O (%s:%O)\n", ME, query_ip_name(), query_ip_number(), peerport)) // we could set the next_input_to and reply with _failure until // hostname is resolved .. TODO ... no, we need some form // of queuing for the scripts which do not wait.. why? don't we // squeeze received packets thru dns-lambdas anyway? // peerport has either positive or negative value //peeraddr = peerip+":"+peerport; ::logon(0); #if 0 //def EXPERIMENTAL // added this because greet() happens after dns resolution and // some quick clients may not be waiting that long.. then again // if they do, they deserve other treatment sTextPath(); #endif dns_rresolve(peerip, #'resolved); return 1; // success } #endif // LIBPSYC