mirror of
git://git.psyced.org/git/psyced
synced 2024-08-15 03:25:10 +00:00
let the past begone in cvs land. welcome to igit igit!
This commit is contained in:
commit
4e601cf1c7
509 changed files with 77963 additions and 0 deletions
42
world/net/psyc/LICENSE
Normal file
42
world/net/psyc/LICENSE
Normal file
|
@ -0,0 +1,42 @@
|
|||
// $Id: LICENSE,v 1.5 2007/09/24 15:08:22 lynx Exp $ // vim:syntax=lpc
|
||||
|
||||
----------------------------------------------------------------------------------
|
||||
|
||||
The files contained in this directory, that is precisely
|
||||
|
||||
active.c circuit.c common.c edit.i library.i parse.i server.c udp.c and user.c
|
||||
|
||||
and additionally the psyc.h file in ../include
|
||||
|
||||
are freeware according to the so-called MIT-License that follows.
|
||||
I took it from http://www.opensource.org/mit-license.html
|
||||
Thanks to Markus Fleck for the pointer, or was it a reference?
|
||||
|
||||
----------------------------------------------------------------------------------
|
||||
|
||||
Copyright since 1995 by Carlo von Loesch
|
||||
psyc://ve.symlynX.com/~lynX
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify,
|
||||
merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
Software, and to permit persons to whom the Software is furnished
|
||||
to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY
|
||||
OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
||||
LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
|
||||
OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||
IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
----------------------------------------------------------------------------------
|
95
world/net/psyc/active.c
Normal file
95
world/net/psyc/active.c
Normal file
|
@ -0,0 +1,95 @@
|
|||
// vim:foldmethod=marker:syntax=lpc:noexpandtab
|
||||
// $Id: active.c,v 1.40 2008/02/20 14:03:30 fippo Exp $
|
||||
//
|
||||
#include <net.h>
|
||||
#include <services.h>
|
||||
|
||||
inherit PSYC_PATH "circuit";
|
||||
inherit NET_PATH "circuit";
|
||||
|
||||
volatile object super;
|
||||
|
||||
void takeover() {
|
||||
super = previous_object();
|
||||
if (super == ME) /* TODO: prevent elsewhere */ {
|
||||
super = 0;
|
||||
}
|
||||
unless (interactive(ME)) runQ();
|
||||
}
|
||||
|
||||
// we love multiple inheritance.. rock'n'roll!
|
||||
int logon(int failure) {
|
||||
int ret;
|
||||
|
||||
P2(("%O logon kriegt %O, prev: %O\n", ME, failure, previous_object()))
|
||||
ret = NET_PATH "circuit"::logon(failure);
|
||||
if (failure >= 0 && ret > 0) {
|
||||
#if 0 // apparently wrong
|
||||
emit(".\n"); // should we do the greeting?
|
||||
PSYC_PATH "circuit"::logon(failure);
|
||||
|
||||
peeraddr = peerhost = host;
|
||||
if (port && port != PSYC_SERVICE) peeraddr += ":"+port;
|
||||
#else // probably better
|
||||
peeraddr = peerhost = host;
|
||||
peerport = port;
|
||||
if (port && port != PSYC_SERVICE) peeraddr += ":"+port;
|
||||
// circuit::logon now also implies a full greeting
|
||||
// therefore it needs peeraddr, and the emit is redundant
|
||||
PSYC_PATH "circuit"::logon(failure);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int msg(string source, string method, string data,
|
||||
mapping vars, int showingLog, string target) {
|
||||
P3(("active.c:msg(%O, %O, %O) in %O%s\n", source, method, data, ME,
|
||||
(interactive()) ? "(connected)" : "(not connected)"))
|
||||
|
||||
unless (interactive())
|
||||
#ifdef FORK // {{{
|
||||
{
|
||||
if (!member(vars, "_source"))
|
||||
vars["_source"] = UNIFORM(source);
|
||||
unless (super)
|
||||
return enqueue(source, method, data, vars, showingLog, target);
|
||||
return super->msg(source, method, data, vars, showingLog, target);
|
||||
}
|
||||
return ::msg(source, method, data, vars, showingLog, target);
|
||||
#else // }}}
|
||||
{
|
||||
P2(("%O ist nicht interactive\n", ME))
|
||||
if (!member(vars, "_source"))
|
||||
vars["_source"] = UNIFORM(source);
|
||||
// this stuff is causing loops and i don't know how to fix it right now
|
||||
// unless (super)
|
||||
# ifdef SPYC
|
||||
// NOTE: SPYC uses a per-host verification and therefore
|
||||
// may not send certain packets before verification
|
||||
// is done (those packets usually have source and target)
|
||||
// for now, this check works most of the time
|
||||
# endif
|
||||
return enqueue(source, method, data, vars, showingLog, target);
|
||||
// return super->msg(source, method, data, vars, showingLog, target);
|
||||
}
|
||||
return ::msg(source, method, data, vars, showingLog, target);
|
||||
#endif // !FORK
|
||||
}
|
||||
|
||||
#if 0
|
||||
connect(host, port) {
|
||||
if (host) {
|
||||
// funky but who needs this?
|
||||
if (interactive()) {
|
||||
if (ahost == host && aport == port) return -8;
|
||||
else remove_interactive(ME);
|
||||
}
|
||||
...
|
||||
|
||||
P1(("PSYC/TCP %O * net_connect(%O, %O) = %O\n",
|
||||
ME, host, port, rc))
|
||||
return rc;
|
||||
}
|
||||
#endif
|
539
world/net/psyc/circuit.c
Normal file
539
world/net/psyc/circuit.c
Normal file
|
@ -0,0 +1,539 @@
|
|||
// vim:foldmethod=marker:syntax=lpc:noexpandtab
|
||||
// $Id: circuit.c,v 1.189 2008/03/29 20:36:44 lynx Exp $
|
||||
#include <net.h>
|
||||
#include <services.h>
|
||||
#include <person.h>
|
||||
#include <driver.h>
|
||||
#include <url.h>
|
||||
#include <text.h>
|
||||
#include <psyc.h>
|
||||
|
||||
protected void quit(); // prototype
|
||||
|
||||
#ifdef __PIKE__
|
||||
import net.psyc.common;
|
||||
#else
|
||||
// since this doesn't exec() the user object
|
||||
// it needs to do its own network output
|
||||
virtual inherit NET_PATH "output";
|
||||
inherit PSYC_PATH "common";
|
||||
#endif
|
||||
|
||||
// thats also why we do not inherit the generic server!
|
||||
//
|
||||
#ifndef QUIT
|
||||
//define QUIT remove_interactive(ME); return 1;
|
||||
# define QUIT destruct(ME); return 1;
|
||||
#endif
|
||||
|
||||
//volatile mapping namecache = ([]);
|
||||
|
||||
#ifdef FORK
|
||||
volatile mapping _o, memory;
|
||||
// why do we need to do this, el?
|
||||
//psycName() { return ""; }
|
||||
#else
|
||||
//# define MMP_STATE
|
||||
#endif
|
||||
#ifdef MMP_STATE
|
||||
// first steps at making use of TCPs persistence
|
||||
volatile string lastSource;
|
||||
volatile string lastTarget;
|
||||
volatile string lastContext;
|
||||
#endif
|
||||
|
||||
int isServer() { return 0; }
|
||||
|
||||
volatile int flags = 0;
|
||||
|
||||
#define PSYC_TCP
|
||||
// contains PSYC parser
|
||||
#ifdef FORK
|
||||
# include "routerparse.i"
|
||||
#else
|
||||
# include "parse.i"
|
||||
#endif
|
||||
|
||||
int greet() {
|
||||
string usingmods;
|
||||
|
||||
sTextPath();
|
||||
// we should know our port numbers from command line
|
||||
// and with the new ports.h we do.. we just have to use it here..
|
||||
// ehm.. how do we to_string() a dozen numbers efficiently? we don't huh?
|
||||
// we patch ports.h to also provide #define PSYC_PORT_S etc? we let
|
||||
// psyconf generate this string? how do we specify TLS ports? TODO
|
||||
//
|
||||
#define UNDERPROTS USINGPROTS ";PSYC/0.9 UDP IP/4;" \
|
||||
"XMPP-S2S/1;IRC/2;XMPP-C2S/1;Chatlet;Telnet;" \
|
||||
"HTTP/1.0;WAP"
|
||||
#define USINGPROTS "PSYC/0.9 TCP IP/4"
|
||||
|
||||
#ifdef PRO_PATH
|
||||
# if defined(BRAIN) && !defined(SLAVE) && !defined(VOLATILE)
|
||||
// for the time being.. a special case with port numbers
|
||||
# define PROTS "PSYC/0.9:4404 TCP IP/4;PSYC/0.9:4404 UDP IP/4;" \
|
||||
"XMPP-S2S/1:5269;IRC/2:6667;XMPP-C2S/1:5222;Chatlet:2008;Telnet:23;" \
|
||||
"HTTP/1.0:33333;XMLpsyc/0.3:1404;WAP"
|
||||
// and the gateways brain provides..
|
||||
// I would like to change that into old list-syntax again.. or lets implement
|
||||
// this @_var stuff.. this damages my brain
|
||||
# define SCHEMES ":_understand_schemes\taim;icq;irc;efnet;euirc;" \
|
||||
"freenode;quakenet;galaxynetwork;xentonix;klingons\n"
|
||||
# define TSCHEMES "Gateways provided: [_understand_schemes].\n"
|
||||
# else
|
||||
# define SCHEMES ""
|
||||
# define TSCHEMES ""
|
||||
# define PROTS UNDERPROTS ";XMLpsyc/0.3"
|
||||
# endif
|
||||
#else
|
||||
# define SCHEMES ""
|
||||
# define TSCHEMES ""
|
||||
# define PROTS UNDERPROTS
|
||||
#endif
|
||||
|
||||
// we only understand circuit-level (MMP) _state, the one that is so easy
|
||||
// that we can expect any TCP-MMP implementation to provide it, but PSYC
|
||||
// state which needs to be stored per logical source and target still needs
|
||||
// to be implemented. see also http://about.psyc.eu/State
|
||||
//#define UNDERMODS "_state;_context"
|
||||
#define UNDERMODS "_context"
|
||||
usingmods = UNDERMODS;
|
||||
|
||||
#if defined(__MCCP__) && !defined(FORK)
|
||||
# define ZIPMOD ";_compress"
|
||||
if (query_mccp(ME)) usingmods += ZIPMOD;
|
||||
#else
|
||||
# define ZIPMOD
|
||||
#endif
|
||||
#if defined(__TLS__)
|
||||
# define TLSMOD ";_encrypt"
|
||||
if (tls_query_connection_state(ME) > 0) usingmods += TLSMOD;
|
||||
#else
|
||||
# define TLSMOD
|
||||
#endif
|
||||
|
||||
// TODO: if negotiation of _using_characters is implemented, then change this
|
||||
// _available_characters into _understand_characters. same goes for
|
||||
// _available_protocols, although i don't expect anyone to need this.
|
||||
//
|
||||
// the text messages in here are to say hello to clients.
|
||||
// servers will just skip them..
|
||||
//
|
||||
// und eigentlich ist das alles nur eitelkeit, die vielen vars. sagt el. ;)
|
||||
#ifdef FORK // {{{
|
||||
emit(S_GLYPH_PACKET_DELIMITER "\n");
|
||||
emit("\
|
||||
=_source "+ query_server_unl() +"\n\
|
||||
=_target_peer psyc://"+ peeraddr +"/\n\
|
||||
=_available_characters UTF-8\n\
|
||||
=_available_protocols " PROTS "\n\
|
||||
" SCHEMES "\
|
||||
=_understand_modules " UNDERMODS TLSMOD "\n\
|
||||
=_using_characters " SYSTEM_CHARSET "\n\
|
||||
=_using_protocols " USINGPROTS "\n\
|
||||
=_using_modules "+ usingmods +"\n\
|
||||
\n\
|
||||
:_implementation " SERVER_VERSION " " DRIVER_VERSION " " OSTYPE " " MACHTYPE "\n\
|
||||
:_page_description http://www.psyc.eu/\n\
|
||||
_notice_circuit_established\n\
|
||||
Circuit to [_source] running [_implementation] established.\n\
|
||||
Available protocols: [_available_protocols].\n" S_GLYPH_PACKET_DELIMITER "\n");
|
||||
#else // }}}
|
||||
// should we rename _target into _target_raw here? maybe, then again
|
||||
// all subsequent traffic still goes to this target unless the
|
||||
// other side tells us her name
|
||||
emit(S_GLYPH_PACKET_DELIMITER "\n");
|
||||
emit("\
|
||||
:_source "+ query_server_unl() +"\n\
|
||||
:_target_peer psyc://"+ peeraddr +"/\n"
|
||||
"\n\
|
||||
:_implementation "+ SERVER_VERSION +" "+ DRIVER_VERSION +" "+ OSTYPE +" "+ MACHTYPE +"\n\
|
||||
:_page_description http://www.psyc.eu/\n\
|
||||
_notice_circuit_established\n\
|
||||
Hello [_target_peer].\n\
|
||||
Circuit to [_source] running [_implementation] established.\n" S_GLYPH_PACKET_DELIMITER "\n");
|
||||
// ;ISO-8859-1;ISO-8859-15\n
|
||||
emit("\
|
||||
:_source "+ query_server_unl() +"\n\
|
||||
\n\
|
||||
:_available_hashes "
|
||||
#if __EFUN_DEFINED__(sha1)
|
||||
"sha1;"
|
||||
#endif
|
||||
#if __EFUN_DEFINED__(md5)
|
||||
"md5;http-digest;digest-md5"
|
||||
#endif
|
||||
"\n\
|
||||
:_available_characters UTF-8\n\
|
||||
:_available_protocols " PROTS "\n\
|
||||
" SCHEMES "\
|
||||
:_understand_modules " UNDERMODS TLSMOD "\n\
|
||||
:_using_characters " SYSTEM_CHARSET "\n\
|
||||
:_using_protocols " USINGPROTS "\n\
|
||||
:_using_modules "+ usingmods +"\n\
|
||||
_status_circuit\n\
|
||||
" TSCHEMES "\
|
||||
Available protocols: [_available_protocols].\n" S_GLYPH_PACKET_DELIMITER "\n");
|
||||
#endif // !FORK
|
||||
#ifdef _flag_log_sockets_PSYC
|
||||
log_file("RAW_PSYC", "» %O greeted.\n", ME);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
static varargs int block(vastring mc, vastring reason) {
|
||||
// we used to get here at shutdown time because legal_host was
|
||||
// saying no.. but it's better to do it differently..
|
||||
P0(("Circuit blocked TCP PSYC connection from %O in %O (%O).\n",
|
||||
query_ip_number(ME), ME, mc))
|
||||
#ifdef EXPERIMENTAL
|
||||
unless (ME)
|
||||
raise_error("blocked destructed object?\n");
|
||||
unless (interactive(ME))
|
||||
raise_error("blocked non-interactive?\n");
|
||||
#endif
|
||||
write(S_GLYPH_PACKET_DELIMITER "\n\
|
||||
\n\
|
||||
:_source_redirect psyc://ve.symlynX.com\n\
|
||||
_error_illegal_source\n\
|
||||
Sorry, my configuration does not allow me to talk to you.\n\
|
||||
Try the [_source_redirect] server instead!\n" S_GLYPH_PACKET_DELIMITER "\n");
|
||||
QUIT
|
||||
}
|
||||
|
||||
// this logon() is either called in psyc/server, so it has no args
|
||||
// or it is actively called from psyc/active, when no failure has
|
||||
// taken place. thus, the argument is useless.
|
||||
int logon(int neverfails) {
|
||||
#ifdef __TLS__
|
||||
mixed cert;
|
||||
#endif
|
||||
object cur;
|
||||
int isserver;
|
||||
mixed m;
|
||||
string t;
|
||||
|
||||
unless (ME) {
|
||||
// this happens when shutdown has been initiated during
|
||||
// establishment of the circuit. we get the callback,
|
||||
// although we have already been destroyed. unfortunately
|
||||
// we can't even find out which connection it was.
|
||||
P3(("logon(%O) called in destructed object\n", neverfails))
|
||||
return 0;
|
||||
}
|
||||
isserver = isServer();
|
||||
peerip = query_ip_number(ME) || "127.0.0.1";
|
||||
P3(("%O logon from %O\n", ME, peerip))
|
||||
|
||||
// in case of psyc/active this hostCheck has already performed
|
||||
// in net/connect
|
||||
if (isserver &&! hostCheck(peerip, peerport)) {
|
||||
// also gets here when ME is 0
|
||||
return block();
|
||||
}
|
||||
|
||||
#ifdef __TLS__
|
||||
# ifdef EXPERIMENTAL
|
||||
sAuthHosts(([ ])); // reset authhosts
|
||||
if (tls_available() && tls_query_connection_state(ME) == 1 && mappingp(cert = tls_certificate(ME, 0))) {
|
||||
if (cert[0] != 0) {
|
||||
// log error 17 + cert here
|
||||
// and goodbye.
|
||||
P0(("%O encountered a cert verify error %O in %O\n", ME,
|
||||
cert[0], cert))
|
||||
remove_interactive(ME);
|
||||
return 0;
|
||||
}
|
||||
if (m = cert["2.5.29.17:dNSName"]) {
|
||||
// FIXME: this does not yet handle wildcard DNS names
|
||||
P1(("%O believing dNSName %O\n", ME, m))
|
||||
// probably also: register_target?
|
||||
// but be careful never to register_target wildcards
|
||||
if (stringp(m)) sAuthenticated(NAMEPREP(m));
|
||||
else foreach(t : m) sAuthenticated(NAMEPREP(t));
|
||||
}
|
||||
//#ifdef _flag_allow_certificate_name_common // to be switched this year
|
||||
#ifndef _flag_disallow_certificate_name_common
|
||||
// assume that CN is a host
|
||||
// as this is an assumption only, we may NEVER register_target it
|
||||
// note: CN is deprecated for good reasons.
|
||||
else if (t = cert["2.5.4.3"]) {
|
||||
P1(("%O believing CN %O\n", ME, t))
|
||||
sAuthenticated(NAMEPREP(t));
|
||||
}
|
||||
#endif
|
||||
if (m = tls_query_connection_info(ME)) {
|
||||
P2(("%O is using the %O cipher.\n", ME, m[TLS_CIPHER]))
|
||||
// shouldn't our negotiation have ensured we have PFS?
|
||||
if (stringp(t = m[TLS_CIPHER]) &&! abbrev("DHE", t)) {
|
||||
// croak("_warning_circuit_encryption_cipher",
|
||||
// "Your cipher choice does not provide forward secrecy.");
|
||||
monitor_report(
|
||||
"_warning_circuit_encryption_cipher_details",
|
||||
object_name(ME) +" · using "+ t +" cipher");
|
||||
//debug_message(sprintf(
|
||||
// "TLS connection info for %O is %O\n", ME, m));
|
||||
//QUIT // are we ready for *this* !???
|
||||
}
|
||||
}
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
|
||||
cvars = ([]);
|
||||
pvars = ([ "_INTERNAL_origin" : ME ]);
|
||||
|
||||
#if defined(MMP_STATE) && !defined(FORK)
|
||||
lastSource = lastTarget = lastContext = 0;
|
||||
#endif
|
||||
next_input_to(#'startParse);
|
||||
// even active connections want to time out to avoid lockups
|
||||
// but quit() should check if there is a queue to return! TODO
|
||||
call_out(#'quit, 90);
|
||||
flags |= TCP_PENDING_TIMEOUT;
|
||||
// unless(peeraddr) {
|
||||
peeraddr = peerhost = peerip;
|
||||
// peerport value is positive for real listen() ports
|
||||
if (peerport) peeraddr += ":"+peerport;
|
||||
// }
|
||||
#ifdef FORK // {{{
|
||||
// init the out-state. these will be sent by greet()
|
||||
_o = ([
|
||||
"_source" : query_server_unl(),
|
||||
"_target" : "psyc:"+ peeraddr +"/",
|
||||
]);
|
||||
memory = copy(_o);
|
||||
#if 0
|
||||
memory = ([ "_source" : query_server_unl(); 4,
|
||||
"_target" : "psyc:" + peeraddr +"/"; 4,
|
||||
]);
|
||||
#endif
|
||||
#endif // }}}
|
||||
if (cur = find_target_handler( "psyc://"+ peeraddr +"/" )) {
|
||||
unless (cur->isServer()) {
|
||||
cur->takeover();
|
||||
}
|
||||
if (!interactive(cur)) {
|
||||
destruct(cur);
|
||||
}
|
||||
}
|
||||
register_target( "psyc://"+peeraddr+"/" , ME );
|
||||
|
||||
// merge with isserver-if further up? not sure
|
||||
// if order of actions has some side fx..
|
||||
unless (isserver) greet();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef FORK // edit.i is included into the library. should be enough
|
||||
#include "edit.i"
|
||||
|
||||
// called from sendmsg() either by registered target or psyc: scheme
|
||||
//int delivermsg(string target, string mc, string data,
|
||||
varargs int msg(string source, string mc, string data,
|
||||
mapping vars, vaint showingLog, vamixed target) {
|
||||
string buf, context;
|
||||
|
||||
P2(( (tls_query_connection_state() ? "TLS": "TCP") +
|
||||
"[%s] <= %s: %s %O\n", peeraddr || "error",
|
||||
to_string(source), mc || "-", data))
|
||||
// to_string(vars["_source_relay"] || source)
|
||||
buf = "";
|
||||
#ifndef NEW_RENDER
|
||||
ASSERT("mc", mc, "Message from "+source+" w/out mc")
|
||||
if (!stringp(data))
|
||||
data = abbrev("_message", mc)? "": (T(mc, "") || "");
|
||||
else if (data == S_GLYPH_PACKET_DELIMITER || data[0..1] == S_GLYPH_PACKET_DELIMITER "\n"
|
||||
|| strstr(data, "\n" S_GLYPH_PACKET_DELIMITER "\n") != -1) {
|
||||
# if 0 // one day we shall be able to parse that, too
|
||||
vars["_length"] = strlen(data);
|
||||
# else
|
||||
P1(("%O: %O tried to send %O via psyc. censored.\n",
|
||||
previous_object() || ME, vars["_nick"] || vars, data))
|
||||
// data = "*** censored message ***";
|
||||
return 0;
|
||||
# endif
|
||||
}
|
||||
// modular message protocol layer
|
||||
//
|
||||
// this stuff should not be seperate from the one done
|
||||
// for UDP!!! TODO
|
||||
# if 1 //def NOT_EXPERIMENTAL
|
||||
if (context = vars["_INTERNAL_context"]) {
|
||||
P4(("retransmit: %O - deleting source\n", data))
|
||||
unless(vars["_source_relay"])
|
||||
vars["_source_relay"] = source;
|
||||
// public lastlog and history are sent with _context and _target
|
||||
source = 0;
|
||||
}
|
||||
else if (context = vars["_context"]) {
|
||||
P4(("1st transmit: %O - deleting source and target\n", data))
|
||||
// we're not multipeering, so no sources here.
|
||||
unless(vars["_source_relay"])
|
||||
vars["_source_relay"] = source;
|
||||
source = 0;
|
||||
// if (vars["_INTERNAL_context"]) context = 0; // EXPERIMENTAL
|
||||
// else {
|
||||
// at least we get to see when he does that
|
||||
// vars["_INTERNAL_target"] = target;
|
||||
// oh he does it a lot currently
|
||||
P2(("psycrender removing _target %O for %O in %O\n",
|
||||
target, context, ME))
|
||||
// history in fact is a state sync so it
|
||||
// should be sent with _context AND _target TODO
|
||||
target = 0;
|
||||
// }
|
||||
}
|
||||
# else
|
||||
context = vars["_context"];
|
||||
# endif
|
||||
# ifndef PRE_SPEC
|
||||
if (context) {
|
||||
buf+= ":_context\t"+ UNIFORM(context) +"\n";
|
||||
if (source) buf += ":_source_relay\t"+ UNIFORM(source) +"\n";
|
||||
if (target) buf += ":_target_relay\t"+ target +"\n";
|
||||
} else {
|
||||
if (source) buf += ":_source\t"+ UNIFORM(source) +"\n";
|
||||
if (target) buf += ":_target\t"+ target +"\n";
|
||||
}
|
||||
# else
|
||||
// is MMP_STATE a relict of pre-FORK days?
|
||||
# if defined(MMP_STATE)
|
||||
if (source != lastSource) {
|
||||
lastSource = source;
|
||||
buf += "=_source\t"+ UNIFORM(source) +"\n";
|
||||
}
|
||||
if (target != lastTarget) {
|
||||
lastTarget = target;
|
||||
buf += "=_target\t"+ (target || "") +"\n";
|
||||
}
|
||||
if (context != lastContext) {
|
||||
lastContext = context;
|
||||
buf += "=_context\t"+ UNIFORM(context) +"\n";
|
||||
}
|
||||
# else
|
||||
if (source) buf += ":_source\t"+ UNIFORM(source) +"\n";
|
||||
if (target) buf += ":_target\t"+ target +"\n";
|
||||
if (context) buf+= ":_context\t"+ UNIFORM(context) +"\n";
|
||||
if (vars["_source_relay"])
|
||||
buf += "\n:_source_relay\t"+ UNIFORM(vars["_source_relay"]);
|
||||
# endif /* MMP_STATE */
|
||||
# endif /* !PRE_SPEC */
|
||||
#endif /* !NEW_RENDER */
|
||||
buf += psyc_render(source, mc, data, vars, showingLog, target);
|
||||
# ifndef EXPERIMENTAL
|
||||
# if 0
|
||||
// i believe this was an old hack to fix psyctext fmts that
|
||||
// came with an extra newline. since the invention of the
|
||||
// single-file textdb (and the ease of detecting wrong newlines),
|
||||
// this should be of no usefulness anymore ...
|
||||
//
|
||||
if (strlen(data) && char_from_end(data, 1) != '\n')
|
||||
buf += "\n" S_GLYPH_PACKET_DELIMITER "\n";
|
||||
else
|
||||
buf += S_GLYPH_PACKET_DELIMITER "\n";
|
||||
# else
|
||||
buf += "\n" S_GLYPH_PACKET_DELIMITER "\n";
|
||||
# endif
|
||||
# endif
|
||||
# ifdef _flag_log_sockets_PSYC
|
||||
log_file("RAW_PSYC", "» %O\n%s\n", ME, buf);
|
||||
# endif
|
||||
//PT(("» %O\t%s\n", ME, buf))
|
||||
return emit(buf);
|
||||
}
|
||||
#else /* FORK {{{ */
|
||||
|
||||
varargs int msg(string source, string mc, string data,
|
||||
mapping vars, int showingLog, mixed target) {
|
||||
string buf;
|
||||
mapping mvars = copy(vars);
|
||||
|
||||
P2(("TCP[%s] <= %s: %s\n", peeraddr || "error",
|
||||
to_string(source), mc || "-"))
|
||||
// to_string(vars["_source_relay"] || source)
|
||||
|
||||
// <lynX> yet another place where sources are rendered..
|
||||
// but it is no longer compliant to the specs. don't use this.
|
||||
vars["_source"] = UNIFORM(source);
|
||||
unless (member(vars, "_context"))
|
||||
vars["_target"] = UNIFORM(target);
|
||||
|
||||
// do state only if source is an object.
|
||||
if (objectp(source)) buf = make_psyc(mc, data, vars, source);
|
||||
else buf = make_psyc(mc, data, vars);
|
||||
|
||||
#ifdef _flag_log_sockets_PSYC
|
||||
log_file("RAW_PSYC", "» %O\n%s\n", ME, buf);
|
||||
#endif
|
||||
return emit(make_mmp(buf, vars, ME));
|
||||
}
|
||||
|
||||
int send(string data, mapping vars) {
|
||||
#ifdef _flag_log_sockets_PSYC
|
||||
log_file("RAW_PSYC", "» %O send(%O)\n", ME, data);
|
||||
#endif
|
||||
return emit(make_mmp(data, vars, ME));
|
||||
}
|
||||
|
||||
int outstate(string key, string value) {
|
||||
if (member(_o, key)) {
|
||||
m_delete(memory, key);
|
||||
if (_o[key] == value) return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
mapping state() {
|
||||
mapping t = ([]);
|
||||
string key;
|
||||
|
||||
foreach (key : memory)
|
||||
t[key] = "";
|
||||
|
||||
memory = copy(_o);
|
||||
return t;
|
||||
}
|
||||
#endif // FORK }}}
|
||||
|
||||
void reboot(string reason, int restart, int pass) {
|
||||
P3(("reboot(%O, %O, %O) in %O\n", pass, restart, reason, ME))
|
||||
// this gets called in blueprints too, so we have to make sure
|
||||
// we ARE indeed connected somewhere.
|
||||
if (pass == 1 && interactive(ME)) {
|
||||
// same in person.c
|
||||
if (restart)
|
||||
croak("_warning_server_shutdown_temporary",
|
||||
"Server restart: [_reason]", ([ "_reason": reason ]) );
|
||||
else
|
||||
croak("_warning_server_shutdown",
|
||||
"Server shutdown: [_reason]", ([ "_reason": reason ]) );
|
||||
flags |= TCP_PENDING_DISCONNECT;
|
||||
croak("_request_circuit_shutdown",
|
||||
// the text message is to be removed ;)
|
||||
"Please close this socket as you read this.");
|
||||
}
|
||||
}
|
||||
|
||||
// this is used to issue errors to the other side such as
|
||||
// _error_invalid_method_compact. it is good to have!
|
||||
varargs mixed croak(string mc, string data, vamapping vars, vamixed source) {
|
||||
PT(("%O croak(%O, %O ..)\n", ME, mc,data))
|
||||
return msg(0, mc, data, vars || ([]));
|
||||
//return delivermsg(0, mc, data, vars || ([]));
|
||||
}
|
||||
|
||||
int disconnected(string remaining) {
|
||||
#if DEBUG > 0
|
||||
if (remaining && (!stringp(remaining) || strlen(remaining)))
|
||||
PP(("%O ignoring remaining data from socket: %O\n", ME,
|
||||
remaining));
|
||||
#endif
|
||||
// wow.. a sincerely expected disconnect!
|
||||
if (flags & TCP_PENDING_DISCONNECT) return 1;
|
||||
monitor_report("_failure_network_circuit_disconnect",
|
||||
object_name(ME) +" · lost PSYC circuit");
|
||||
return 0; // unexpected
|
||||
}
|
||||
|
328
world/net/psyc/common.c
Normal file
328
world/net/psyc/common.c
Normal file
|
@ -0,0 +1,328 @@
|
|||
// vim:foldmethod=marker:syntax=lpc:noexpandtab
|
||||
// $Id: common.c,v 1.64 2008/02/06 18:13:16 lynx Exp $
|
||||
//
|
||||
// common code for UDP and TCP server
|
||||
|
||||
#include <net.h>
|
||||
#include <url.h>
|
||||
#include <psyc.h>
|
||||
|
||||
#ifdef __MCCP__
|
||||
# include <telnet.h>
|
||||
#endif
|
||||
|
||||
#ifndef __PIKE__
|
||||
#ifdef FORK
|
||||
virtual inherit NET_PATH "state";
|
||||
#endif
|
||||
virtual inherit NET_PATH "trust";
|
||||
#endif
|
||||
|
||||
// protos.
|
||||
varargs mixed croak(string mc, string data, vamapping vars, vamixed source);
|
||||
void connect_failure(string mc, string reason);
|
||||
void runQ();
|
||||
|
||||
// microspect0rs.
|
||||
string qScheme() { return "psyc"; }
|
||||
|
||||
int isServer() { return 0; }
|
||||
|
||||
int greet() { return 0; }
|
||||
|
||||
// rootMsg: handles messages to the psyc server root node
|
||||
// lynX:
|
||||
// i dont want this to be call_other'd, so i decided to inherit it
|
||||
// into all psyc servers
|
||||
// fippo:
|
||||
// maybe we need a more generic root object to be inherited by
|
||||
// all psyc and jabber servers
|
||||
// it's there: net/root - yet it is not suitable for everything in here
|
||||
|
||||
varargs int rootMsg(mixed source, string mc, string data,
|
||||
vamapping vars, vamixed target) {
|
||||
string t;
|
||||
#ifdef SCHWAN
|
||||
mixed *u;
|
||||
#endif
|
||||
//PT((">>> %O::rootMsg(%O, %O, %O, %O, %O)\n", ME, source, mc, data, vars, target))
|
||||
switch(mc) {
|
||||
case "_status_circuit":
|
||||
if (member(vars, "_understand_modules")) {
|
||||
unless (pointerp(vars["_understand_modules"]))
|
||||
vars["_understand_modules"] =
|
||||
explode(vars["_understand_modules"], ";");
|
||||
#ifdef __MCCP__
|
||||
if (member(vars["_understand_modules"], "_compress") != -1) {
|
||||
if(query_mccp(ME) || tls_query_connection_state(ME) > 0) break;
|
||||
#ifdef FORK
|
||||
croak("", "", ([ "+_using_modules" : "_compress" ]));
|
||||
#else
|
||||
croak("", "", ([ "_using_modules" : "_compress" ]));
|
||||
#endif
|
||||
enable_telnet(0);
|
||||
start_mccp_compress(TELOPT_COMPRESS2);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
break;
|
||||
case "_notice_link_established":
|
||||
case "_notice_circuit_established":
|
||||
#if 0
|
||||
// note: module negotation is started by client
|
||||
if (pointerp(vars["_understand_modules"]) && !isServer()) {
|
||||
string module;
|
||||
foreach(module : vars["_understand_modules"]) {
|
||||
#ifdef __MCCP__
|
||||
if (module == "_compress") {
|
||||
croak("_request_compression",
|
||||
"Requesting compression using [_method]",
|
||||
([ "_method" : "zlib" ]),
|
||||
query_server_unl());
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#ifdef __TLS__
|
||||
// sigh... we need tls client functionality for that!
|
||||
if (module == "_encrypt") {
|
||||
croak("_request_circuit_encrypt",
|
||||
"Requesting transport layer security",
|
||||
([ ]), query_server_unl());
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (source == query_server_unl()) {
|
||||
#ifndef __PIKE__ // TPD
|
||||
if (function_exists("connect_failure"))
|
||||
connect_failure("_self",
|
||||
"That sender claims to be me!\n");
|
||||
#endif
|
||||
// It may look tempting to do a register_localhost
|
||||
// here, but since we didn't make a serious attempt
|
||||
// to ensure we are talking to ourselves an outside
|
||||
// host may want to fool us into thinking an address
|
||||
// is us, then inject messages with localhost trust
|
||||
// level. We're not going to do that. For automatic
|
||||
// virtual host detection we need to smarten up still!
|
||||
PT(("SUICIDE %O\n", ME))
|
||||
destruct(ME);
|
||||
return 1;
|
||||
}
|
||||
#ifndef __PIKE__ // TPD
|
||||
if (function_exists("runQ")) {
|
||||
P2(("%s in %O: runQ()\n", mc, ME));
|
||||
runQ();
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
P2(("%s in %O: no runQ to execute\n", mc, ME));
|
||||
}
|
||||
#ifdef SCHWAN
|
||||
if (vars["_source_verbatim"]
|
||||
&& u = parse_uniform(vars["_source_verbatim"])) {
|
||||
if (u[UHost]) {
|
||||
register_host(u[UHost]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
#ifdef EXPERIMENTAL
|
||||
case "_notice_authentication":
|
||||
P0(("rootMsg got a _notice_authentication. never happens since entity.c\n"))
|
||||
register_location(vars["_location"], source, 1);
|
||||
break;
|
||||
case "_error_invalid_authentication":
|
||||
monitor_report(mc, psyctext("Breach: [_source] reports invalid authentication provided by [_location]", vars, data, source));
|
||||
break;
|
||||
#endif
|
||||
#if 0
|
||||
case "_request_session_compression":
|
||||
case "_request_session_compress":
|
||||
#ifdef __MCCP__
|
||||
// dont try to compress an already compressed stream...
|
||||
// and compressing an sslified stream is pretty
|
||||
// meaningless
|
||||
if(query_mccp(ME) || tls_query_connection_state(ME) > 0) break;
|
||||
// reply with a _status_compression and start compression
|
||||
croak("_notice_circuit_compress",
|
||||
"Will restart with compression using [_method]",
|
||||
([ "_method" : vars["_method"] || "zlib" ]),
|
||||
query_server_unl());
|
||||
enable_telnet(0);
|
||||
start_mccp_compress(TELOPT_COMPRESS2);
|
||||
// greet(); // TODO: calling it directly kills pypsyc
|
||||
call_out(#'greet, 1);
|
||||
break;
|
||||
case "_notice_circuit_compress":
|
||||
// TODO: we have to make sure that we had wanted to do
|
||||
// compression to this host
|
||||
//start_mccp_compress(TELOPT_COMPRESS2);
|
||||
P0(("%O is getting compressed from the other side. ouch!\n", ME))
|
||||
#else
|
||||
croak("_error_unavailable_circuit_compress",
|
||||
"Did I really flaunt compression to you?",
|
||||
([ ]), query_server_unl());
|
||||
#endif
|
||||
break;
|
||||
case "_request_circuit_encryption":
|
||||
case "_request_circuit_encrypt":
|
||||
#ifdef __TLS__
|
||||
// answer with either _status_tls and go ahead, we are
|
||||
// server side of the handshake
|
||||
// or reply _error_tls_unavailable
|
||||
int t;
|
||||
if (t = tls_query_connection_state(ME) == 0) {
|
||||
croak("_notice_circuit_encrypt",
|
||||
"Enabling TLS encryption.", ([ ]),
|
||||
query_server_unl());
|
||||
tls_init_connection(ME);
|
||||
// here we could actually need lars style
|
||||
// to call greet when ready()
|
||||
} else if (t > 0) {
|
||||
/* sendmsg(source, "_error_tls_active",
|
||||
"TLS is already active",
|
||||
([ ]), query_server_unl()); */
|
||||
P0(("received %O for %O who already has TLS\n", mc, ME))
|
||||
} else {
|
||||
// negative numbers (current behaviour of ldmud)
|
||||
// should never make it here
|
||||
P0(("negative numbers are impossible here :)\n"))
|
||||
}
|
||||
#else
|
||||
// we can not be advertising it
|
||||
croak("_error_unavailable_circuit_encrypt",
|
||||
"Can not remember telling you I had TLS.",
|
||||
([ ]), query_server_unl());
|
||||
#endif
|
||||
break;
|
||||
case "_notice_circuit_encrypt":
|
||||
#if __EFUN_DEFINED__(tls_init_connection)
|
||||
PT(("is my connection secure %O\n", tls_query_connection_state()))
|
||||
// we just leave the socket to verreck, because closing it
|
||||
// would probably only incite the other side to reconnect
|
||||
tls_init_connection(ME, #'greet);
|
||||
#endif
|
||||
break;
|
||||
#endif
|
||||
case 0: // this is kinda funky!
|
||||
if (member(vars, "_using_modules")) {
|
||||
unless (pointerp(vars["_using_modules"]))
|
||||
vars["_using_modules"] = ({ vars["_using_modules"] });
|
||||
|
||||
#ifdef __TLS__
|
||||
if (member(vars["_using_modules"], "_encrypt") != -1) {
|
||||
if (tls_query_connection_state(ME) == 0) {
|
||||
croak("", "", ([ "_using_modules" : "_encrypt" ]));
|
||||
tls_init_connection(ME);
|
||||
}
|
||||
# ifdef __MCCP__
|
||||
} else
|
||||
# else
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
#ifdef __MCCP__
|
||||
if (member(vars["_using_modules"], "_compress") != -1) {
|
||||
P0(("%O is getting compressed from the other side."
|
||||
"ouch! Closing Connection!\n", ME))
|
||||
croak("_error_compress_unavailable",
|
||||
"I don't want to receive compressed data.");
|
||||
destruct(ME);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// sendmsg(source, "_error_unsupported_method",
|
||||
// "Don't know what to do with '[_method]'.",
|
||||
// ([ "_method" : mc ]), "");
|
||||
P1(("rootMsg(%O,%O,%O,%O,%O)\n", source,mc,data,vars,target))
|
||||
#if 0 //def EXPERIMENTAL
|
||||
// circuit root wasn't successful, let's pass the message
|
||||
// on to the server root entity
|
||||
return sendmsg("/", mc, data, vars, source);
|
||||
#else
|
||||
t = "Circuit got "+ mc;
|
||||
if (target) t += " to "+ target;
|
||||
unless (source) source = vars["_INTERNAL_source"]
|
||||
|| vars["_INTERNAL_origin"];
|
||||
if (source) t += " from "+ to_string(source);
|
||||
monitor_report("_notice_forward"+ mc, psyctext(data ?
|
||||
t+": "+data : t, vars, "", source));
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void internalError() {
|
||||
write("_failure_broken_parser\n.\n\n");
|
||||
#ifndef __PIKE__ // TPD
|
||||
// reicht das schon, oder müssen wir weitere maßnahmen ergreifen?
|
||||
remove_interactive(ME);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef FORK // {{{
|
||||
void Assign(mixed source, string key, mixed value) {
|
||||
}
|
||||
void negotiate(mixed modules) {
|
||||
#ifdef __TLS__
|
||||
unless (pointerp(modules))
|
||||
modules = ({ modules });
|
||||
foreach (string key : modules) {
|
||||
if ("_encrypt" == key) {
|
||||
if (tls_query_connection_state(ME) == 0) {
|
||||
|
||||
croak("", "", "", ([ "+_using_modules" : "_encrypt", "_target" : "" ]));
|
||||
|
||||
tls_init_connection(ME);
|
||||
}
|
||||
return;
|
||||
}
|
||||
#ifdef __MCCP__
|
||||
if ("_compress" == key) {
|
||||
P0(("%O is getting compressed from the other side."
|
||||
"ouch! Closing Connection!\n", ME))
|
||||
croak("_error_compress_unavailable",
|
||||
"I don't want to receive compressed data.");
|
||||
destruct(ME);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void gotiate(mixed modules) {
|
||||
unless (pointerp(modules))
|
||||
modules = ({ modules });
|
||||
foreach (string key : modules) {
|
||||
#ifdef __MCCP__
|
||||
if ("_compress" == key) {
|
||||
if(query_mccp(ME)
|
||||
#ifdef __TLS__
|
||||
|| tls_query_connection_state(ME) > 0
|
||||
#endif
|
||||
) break;
|
||||
croak("", "", "", ([ "+_using_modules" : "_compress" ]));
|
||||
enable_telnet(0);
|
||||
start_mccp_compress(TELOPT_COMPRESS2);
|
||||
}
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void Diminish(mixed source, string key, mixed value) {
|
||||
}
|
||||
void Reset() {
|
||||
|
||||
}
|
||||
|
||||
#endif // FORK }}}
|
334
world/net/psyc/edit.i
Normal file
334
world/net/psyc/edit.i
Normal file
|
@ -0,0 +1,334 @@
|
|||
// vim:foldmethod=marker:syntax=lpc:noexpandtab
|
||||
// $Id: edit.i,v 1.106 2008/04/01 18:27:15 lynx Exp $
|
||||
//
|
||||
// headermaker functions. we should call it render rather than edit.
|
||||
|
||||
volatile mapping isRouting = shared_memory("routing");
|
||||
|
||||
#ifdef FORK
|
||||
// these macros support state modifiers in varnames.. we'll need that later
|
||||
#define isRoutingVar(x) (stringp(x) && strlen(x) > 1 && member(isRouting, (x[0] == '_') ? x : x[1..]))
|
||||
#define mergeRoutingVar(x) (stringp(x) && strlen(x) > 1 && (isRouting[(x[0] == '_') ? x : x[1..]] & PSYC_ROUTING_MERGE)
|
||||
#endif
|
||||
|
||||
volatile string rbuf, ebuf; // pike has no pass-by-reference
|
||||
|
||||
static int build_header(string key, mixed val, mapping vars) {
|
||||
string s, klopp;
|
||||
int routeMe = 0;
|
||||
#ifdef SPYC
|
||||
int needLen = 0;
|
||||
#endif
|
||||
|
||||
unless (stringp(key)) {
|
||||
s = sprintf("%O encountered key %O value %O (rbuf %O ebuf %O)\n",
|
||||
ME, key, val, rbuf, ebuf);
|
||||
log_file("PANIC", s);
|
||||
monitor_report("_failure_invalid_variable_name", s);
|
||||
return -9;
|
||||
}
|
||||
#ifndef FORK
|
||||
routeMe = isRouting[key];
|
||||
# if 1 //def EXPERIMENTAL
|
||||
P3(("isRouting[%O] = %O, render? %O\n",
|
||||
key, routeMe, routeMe & PSYC_ROUTING_RENDER))
|
||||
if ((routeMe &&! (routeMe & PSYC_ROUTING_RENDER))
|
||||
|| abbrev("_INTERNAL", key)) return -1;
|
||||
# else
|
||||
if (routeMe || abbrev("_INTERNAL", key)) return -1;
|
||||
# endif
|
||||
#endif /* ! FORK */
|
||||
P2(("build_header(%O, %O) into %s vars\n", key, val,
|
||||
routeMe ? "routing" : "entity"))
|
||||
if (key[0] == '_') key = ":"+key;
|
||||
if (objectp(val)) klopp = psyc_name(val);
|
||||
else if (stringp(val)) {
|
||||
if (key == "_nick" && (s = vars["_INTERNAL_nick_plain"])) {
|
||||
P1(("%O sending %O instead of %O\n", ME, s, val))
|
||||
klopp = s;
|
||||
} else {
|
||||
// yeah but we haven't implement the other stuff yet
|
||||
// and the parser can handle it
|
||||
#if 0 //def EXPERIMENTAL
|
||||
// according to http://about.psyc.eu/Grammar
|
||||
if (index(val, '\n') >=0)
|
||||
raise_error("Multiline variables no longer permitted.\n");
|
||||
#else
|
||||
// indenting of multiline variables ...
|
||||
// hardly ever happens, that's why indexing first is
|
||||
// more efficient
|
||||
# ifdef SPYC
|
||||
// better even to not look into the variable but we
|
||||
// need to implement types for that, first
|
||||
if (index(val, '\n') >=0) {
|
||||
needLen = 1;
|
||||
}
|
||||
klopp = val;
|
||||
# else
|
||||
if (index(val, '\n') >=0)
|
||||
klopp = replace(val, "\n", "\n\t");
|
||||
else
|
||||
klopp = val;
|
||||
# endif
|
||||
#endif
|
||||
}
|
||||
} else if (intp(val)) {
|
||||
klopp = to_string(val);
|
||||
} else {
|
||||
mixed k,d, sep;
|
||||
|
||||
// using list syntax here without testing for
|
||||
// _list in name.. bad?
|
||||
|
||||
// fippo likes this variant, but it gives + a wrong
|
||||
// meaning (non-persistent!)
|
||||
// also psyc/parse cannot parse this, and shouldnt start
|
||||
//
|
||||
#ifndef SPYC
|
||||
//sep = key[0] == '_' ? "\n+\t" : "\n"+key[0..]+"\t";
|
||||
sep = "\n"+key[0..0]+"\t";
|
||||
//P2(("sep %O, key[0] %O\n", sep, key[0]))
|
||||
#else
|
||||
needLen = 1; // is it always necessary?
|
||||
// no, but it does not hurt much either
|
||||
#endif
|
||||
if (pointerp(val)) {
|
||||
klopp = "";
|
||||
each(d, val) {
|
||||
#ifndef SPYC
|
||||
// good-old "simple" http://about.psyc.eu/List syntax
|
||||
klopp += sep + UNIFORM(d);
|
||||
#else
|
||||
k = objectp(d)? psyc_name(d): to_string(d);
|
||||
klopp += strlen(k) +" "+ k + "|";
|
||||
#endif
|
||||
}
|
||||
#ifdef SPYC
|
||||
klopp = klopp[..<2];
|
||||
#endif
|
||||
}
|
||||
else if (mappingp(val)) {
|
||||
#if 1 //def NOT_EXPERIMENTAL
|
||||
raise_error("Mappings currently not transmittable.\n");
|
||||
#else
|
||||
klopp = "";
|
||||
mapeach(k, d, val) {
|
||||
// inofficial table syntax
|
||||
klopp += sep + UNIFORM(k);
|
||||
if (d) klopp += " " + UNIFORM(d);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
// it could lead to problems if vars is reused since val may
|
||||
// be an array .. pointer ... so we put stuff in klopp instead
|
||||
#ifndef SPYC
|
||||
klopp = strlen(klopp) > 3 ? klopp[3..] : "";
|
||||
// if (sizeof(val) && stringp(val[0])) val = implode(val, " , ");
|
||||
// else return;
|
||||
#endif
|
||||
}
|
||||
#ifndef SPYC
|
||||
if (klopp) klopp = "\n"+ key +"\t"+ klopp;
|
||||
else klopp = "\n"+ key;
|
||||
#else
|
||||
if (klopp) klopp = "\n"+ key +
|
||||
(needLen? (" "+strlen(klopp)+"\t") : "\t") + klopp;
|
||||
else klopp = "\n"+ key +"\t"; // with or without TAB here?
|
||||
#endif
|
||||
#if 1 //def EXPERIMENTAL
|
||||
if (routeMe) rbuf += klopp;
|
||||
else ebuf += klopp;
|
||||
#else
|
||||
ebuf += klopp;
|
||||
#endif
|
||||
P4(("build_header (%O, %O) rbuf %O\n", key, val, rbuf))
|
||||
return 0;
|
||||
}
|
||||
|
||||
static varargs string psyc_render(mixed source, string mc, mixed data,
|
||||
mapping vars, int showingLog, vastring target) {
|
||||
// vaobject obj, vastring target, vaint hascontext)
|
||||
P4(("%O psyc_render %O for %O\n", ME, vars, previous_object()))
|
||||
string t, context;
|
||||
int needLen = 0;
|
||||
|
||||
rbuf = ebuf = "";
|
||||
#ifdef NEW_RENDER
|
||||
ASSERT("mc", mc, "Message from "+ to_string(source) +" w/out mc")
|
||||
#ifdef T // what lynX wants to say here: do we have the textdb
|
||||
if (!stringp(data))
|
||||
data = abbrev("_message", mc)? "": (T(mc, "") || "");
|
||||
#else
|
||||
if (!stringp(data)) data = data? to_string(data): "";
|
||||
#endif
|
||||
else if (data == S_GLYPH_PACKET_DELIMITER ||
|
||||
(data[0] == C_GLYPH_PACKET_DELIMITER && data[1] == '\n')
|
||||
|| strstr(data, "\n" S_GLYPH_PACKET_DELIMITER "\n") != -1) {
|
||||
// this check shouldn't be necessary here: we should check what
|
||||
// people are typing in usercmd
|
||||
# ifdef SPYC
|
||||
needLen++;
|
||||
# else
|
||||
P1(("%O: %O tried to send %O via psyc. censored.\n",
|
||||
previous_object() || ME, vars["_nick"] || vars, data))
|
||||
// data = "*** censored message ***";
|
||||
return 0;
|
||||
# endif
|
||||
}
|
||||
# if 1 //def NOT_EXPERIMENTAL
|
||||
if (context = vars["_INTERNAL_context"]) {
|
||||
P4(("retransmit: %O - deleting source\n", data))
|
||||
unless(vars["_source_relay"])
|
||||
vars["_source_relay"] = source;
|
||||
// public lastlog and history are sent with _context and _target
|
||||
source = 0;
|
||||
}
|
||||
else if (context = vars["_context"]) {
|
||||
P4(("1st transmit: %O - deleting source and target\n", data))
|
||||
// we're not multipeering, so no sources here.
|
||||
unless(vars["_source_relay"])
|
||||
vars["_source_relay"] = source;
|
||||
source = 0;
|
||||
// if (vars["_INTERNAL_context"]) context = 0; // EXPERIMENTAL
|
||||
// else {
|
||||
// at least we get to see when he does that
|
||||
// vars["_INTERNAL_target"] = target;
|
||||
// oh he does it a lot currently
|
||||
P2(("psycrender removing _target %O for %O in %O\n",
|
||||
target, context, ME))
|
||||
// history in fact is a state sync so it
|
||||
// should be sent with _context AND _target TODO
|
||||
target = 0;
|
||||
// }
|
||||
}
|
||||
# else
|
||||
context = vars["_context"];
|
||||
# endif
|
||||
# ifndef PRE_SPEC
|
||||
if (context) {
|
||||
rbuf += "\n:_context\t"+ UNIFORM(context);
|
||||
t = source || vars["_source_relay"];
|
||||
if (t) rbuf += "\n:_source_relay\t"+ UNIFORM(t);
|
||||
// resend of /history transmitted according to spec:
|
||||
if (showingLog && target) rbuf += "\n:_target\t"+ target;
|
||||
// usually the same as context or a different channel of
|
||||
// context or the actual recipient of a multicast
|
||||
// ... not interesting in any case
|
||||
//else if (target) rbuf += "\n:_target_relay\t"+ target;
|
||||
} else {
|
||||
if (source) rbuf += "\n:_source\t"+ UNIFORM(source);
|
||||
if (target) rbuf += "\n:_target\t"+ target;
|
||||
// this is necessary for message forwarding ( /set id )
|
||||
if (t = vars["_source_relay"])
|
||||
rbuf += "\n:_source_relay\t"+ UNIFORM(t);
|
||||
}
|
||||
# else
|
||||
if (source) rbuf += "\n:_source\t"+ UNIFORM(source);
|
||||
if (target) rbuf += "\n:_target\t"+ target;
|
||||
if (context) rbuf+= "\n:_context\t"+ UNIFORM(context);
|
||||
if (t = vars["_source_relay"])
|
||||
rbuf += "\n:_source_relay\t"+ UNIFORM(t);
|
||||
# endif /* PRE_SPEC */
|
||||
#endif /* NEW_RENDER */
|
||||
|
||||
if (mappingp(vars)) {
|
||||
#if 0 //ndef EXPERIMENTAL
|
||||
if (member(vars, "_count"))
|
||||
ebuf += "\n:_count\t" + vars["_count"];
|
||||
#endif
|
||||
#if __EFUN_DEFINED__(walk_mapping)
|
||||
#ifndef FORK // NO STATE
|
||||
// walk_mapping could be rewritten into foreach, but thats work
|
||||
walk_mapping(vars, #'build_header, vars);
|
||||
#else /* FORK {{{ */
|
||||
# if 0 //ndef EXPERIMENTAL
|
||||
// At least the psyced needs _count first to handle that properly
|
||||
m_delete(vars, "_count");
|
||||
# endif
|
||||
foreach (string key, mixed value : vars) {
|
||||
// why does FORK weed out _INTERNAL in two places? ah nevermind
|
||||
if (abbrev("_INTERNAL_", key)) {
|
||||
// equal on a line by itself to mean "clear all state"
|
||||
if (key == "_INTERNAL_state_clear")
|
||||
ebuf = "\n="+ ebuf;
|
||||
continue;
|
||||
}
|
||||
|
||||
// CONTEXT_STATE and ENTITY_STATE here
|
||||
if (!isRoutingVar(key) && (!objectp(obj)
|
||||
|| obj->outstate(target, key, value, hascontext)))
|
||||
build_header(key, value);
|
||||
}
|
||||
if (objectp(obj))
|
||||
walk_mapping(obj->state(target, hascontext), #'build_header);
|
||||
#endif /* FORK }}} */
|
||||
#else // PIKE, MudOS...
|
||||
mixed key, val;
|
||||
|
||||
mapeach(key, val, vars) {
|
||||
build_header(key, val, vars);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
ebuf += "\n"+ mc +"\n"+ data;
|
||||
#if 1 //def EXPERIMENTAL
|
||||
# ifdef SPYC // || MODULE_LENGTH
|
||||
if (needLen || strlen(ebuf) + strlen(rbuf) > 555)
|
||||
return ":_length\t"+ strlen(ebuf) + rbuf +"\n"+
|
||||
ebuf +"\n" S_GLYPH_PACKET_DELIMITER "\n";
|
||||
else
|
||||
# endif
|
||||
if (strlen(rbuf)) return rbuf[1 ..] +"\n"+
|
||||
ebuf +"\n" S_GLYPH_PACKET_DELIMITER "\n";
|
||||
return ebuf +"\n" S_GLYPH_PACKET_DELIMITER "\n";
|
||||
#else
|
||||
return ebuf;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef FORK // {{{
|
||||
|
||||
static varargs string mmp_make_header(mapping vars, object o) {
|
||||
buf = "";
|
||||
foreach (string key, mixed value : vars) {
|
||||
if (abbrev("_INTERNAL_", key)) continue;
|
||||
if (isRoutingVar(key) && (!objectp(o) || o->outstate(key, value)))
|
||||
build_header(key, value);
|
||||
}
|
||||
if (objectp(o))
|
||||
walk_mapping(o->state(), #'build_header);
|
||||
return buf;
|
||||
}
|
||||
|
||||
varargs string make_mmp(string data, mapping vars, object o) {
|
||||
// we could regreplace here and do some funny nntp-like encoding of
|
||||
// leading dots.. but we should simply implement _length instead. one day.
|
||||
if (data == "." || data[0..1] == ".\n" || strstr(data, "\n.\n") != -1) {
|
||||
# if 0 // one day we shall be able to parse that, too
|
||||
vars["_length"] = strlen(data);
|
||||
# else
|
||||
P1(("%O: %O tried to send %O via psyc. censored.\n",
|
||||
previous_object() || ME, vars["_nick"] || vars, data))
|
||||
// this message makes some people feel like they missed out
|
||||
// on something..
|
||||
//data = "*** censored message ***";
|
||||
data = "";
|
||||
# endif
|
||||
}
|
||||
return mmp_make_header(vars, o)
|
||||
+ ((data && "" != data) ? "\n"+data+"\n.\n" : "\n.\n");
|
||||
}
|
||||
|
||||
varargs string make_psyc(string mc, string data, mapping vars, object o) {
|
||||
unless (stringp(data))
|
||||
data = "";
|
||||
return psyc_make_header(vars, o, vars["_target"], member(vars, "_context"))
|
||||
+ ((mc) ? mc +"\n"+data : "");
|
||||
}
|
||||
|
||||
#endif /* FORK }}} */
|
||||
|
||||
// notice for completeness: the PSYC renderer does not convert_charset
|
||||
// from SYSTEM_CHARSET to UTF-8, so to produce correct PSYC you must not
|
||||
// switch to a different SYSTEM_CHARSET, or you have to fix that...
|
||||
|
431
world/net/psyc/library.i
Normal file
431
world/net/psyc/library.i
Normal file
|
@ -0,0 +1,431 @@
|
|||
// vim:foldmethod=marker:syntax=lpc:noexpandtab
|
||||
// $Id: library.i,v 1.170 2008/03/29 20:05:32 lynx Exp $
|
||||
|
||||
#include <psyc.h>
|
||||
// #include "../base64.i"
|
||||
#define QUIT destruct(ME); return 1;
|
||||
|
||||
#if SYSTEM_CHARSET != "UTF-8"
|
||||
# echo "FIXME: PSYC will be not be rendered in UTF-8."
|
||||
#endif
|
||||
|
||||
volatile mapping obj2unl = ([]);
|
||||
volatile mapping unl2obj = ([]);
|
||||
// global location to identification resolver
|
||||
volatile mapping unl2uni = ([]);
|
||||
|
||||
varargs void register_location(mixed unl, vamixed uni, vaint unsafe) {
|
||||
PROTECT("REGISTER_LOCATION")
|
||||
if (uni) {
|
||||
if (unsafe && unl2uni[unl]) {
|
||||
P1(("register_location denied: %O says it is %O, but that is already registered for %O\n", uni, unl, unl2uni[unl]))
|
||||
return;
|
||||
}
|
||||
unl2uni[unl] = uni;
|
||||
}
|
||||
else m_delete(unl2uni, unl);
|
||||
}
|
||||
|
||||
/** finds the _identification for a network source. if it cannot find
|
||||
** the information in the cache, and a second argument is given with
|
||||
** the _identification claimed by the source, that _identification
|
||||
** will be asked for confirmation via PSYC. the result will obviously
|
||||
** be available only at a later time. there is no callback function
|
||||
** to this purpose. this function will ONLY return an identification
|
||||
** when it is effectively different from the provided source.
|
||||
** when a source is its own identification, this returns to avoid
|
||||
** any extra processing. maybe one day we will return 1 if that's
|
||||
** useful in any way, but you can check source == givenUNI yourself.
|
||||
** the reason why the variable is called givenUNI and not identification
|
||||
** is because a client may very well claim to be someone and actually not
|
||||
** be that person. we are not sure about identification before the
|
||||
** _request_authentication has returned.
|
||||
*/
|
||||
// this code is used intensely in FORK mode, whereas in !FORK,
|
||||
// since entity.c, the givenUNI is never passed, thus inactive.
|
||||
// unl2uni is only being used for local users' clients, not remotes
|
||||
//
|
||||
varargs mixed lookup_identification(mixed source, vamixed givenUNI) {
|
||||
PROTECT("LOOKUP_IDENTIFICATION")
|
||||
P2(("lookup_identification %O (%O) in %O\n", source, givenUNI, unl2uni))
|
||||
if (member(unl2uni, source)) return unl2uni[source];
|
||||
// ask a remote uni, but don't wait to complete
|
||||
if (givenUNI && source) {
|
||||
unl2uni[source] = 0; // ensures that we don't get here twice
|
||||
// now and in future always return 0 to avoid extra
|
||||
// processing of
|
||||
if (givenUNI == source) return 0;
|
||||
P1(("%O sending _request_authentication to %O for %O\n",
|
||||
ME, givenUNI, source))
|
||||
#ifndef __PIKE__ // TPD
|
||||
sendmsg(givenUNI, "_request_authentication", 0,
|
||||
([ "_location" : source ]));
|
||||
#endif
|
||||
}
|
||||
// we could look again ;)
|
||||
//if (unl2uni[source]) return unl2uni[source];
|
||||
return 0;
|
||||
}
|
||||
|
||||
varargs string psyc_name(mixed source, vastring localpart) {
|
||||
string s;
|
||||
|
||||
if (s = obj2unl[source]) return s;
|
||||
#if DEBUG > 0
|
||||
if (stringp(source))
|
||||
raise_error("psyc_name called for string "+ source+ "\n");
|
||||
#else
|
||||
if (stringp(source)) return source;
|
||||
#endif
|
||||
#ifdef PARANOID
|
||||
unless (objectp(source)) return 0;
|
||||
#endif
|
||||
unless (s = localpart) {
|
||||
if (s = source->psycName()) {
|
||||
if (abbrev("mailto:", s)) {
|
||||
unl2obj[s] = source;
|
||||
return obj2unl[source] = s;
|
||||
}
|
||||
} else s = file_name(source);
|
||||
}
|
||||
//
|
||||
// since this is an outgoing UNL and we do not do
|
||||
// virtual psyc hosting we should be
|
||||
// allowed to leave out the myUNL here.
|
||||
// since we need to recognize ourselves in _context messages
|
||||
// even if our _source has been repatched, we need to know
|
||||
// all our "canonical" names. so this isn't even enough.
|
||||
// we probably need to our canonical hostname: myUNLCN.
|
||||
//
|
||||
#ifndef __HOST_IP_NUMBER__
|
||||
// if (myUNLIP)
|
||||
#endif
|
||||
// unl2obj[myUNLIP +"/"+ s] = source;
|
||||
// why store it with an ip? nobody uses that anyway!?
|
||||
// is it being used anywhere in the parser? naaah.
|
||||
s = myUNL + s;
|
||||
unl2obj[s] = source;
|
||||
return obj2unl[source] = s;
|
||||
}
|
||||
|
||||
object psyc_object(string uniform) {
|
||||
P3(("psyc_object(%O) in %O\n", uniform, unl2obj))
|
||||
return unl2obj[uniform];
|
||||
}
|
||||
|
||||
#ifndef FORK
|
||||
object find_psyc_object(array(mixed) u) {
|
||||
string t, r, svc, user;
|
||||
object o;
|
||||
|
||||
user = u[UUser];
|
||||
r = u[UResource];
|
||||
if (r && strlen(r)) {
|
||||
#if __EFUN_DEFINED__(trim)
|
||||
# include <sys/strings.h>
|
||||
r = trim(r, TRIM_RIGHT, '/');
|
||||
#else
|
||||
while (char_from_end(r, 1) == '/') r = slice_from_end(r, 0, 2);
|
||||
#endif
|
||||
if (strlen(r)) switch(r[0]) {
|
||||
case '^':
|
||||
case '~':
|
||||
if (user) {
|
||||
// croak("_error_invalid_uniform_user_duplicate",
|
||||
// "Two users in uniform not allowed here.");
|
||||
// QUIT
|
||||
return 0; // TODO!
|
||||
}
|
||||
user = r[1..];
|
||||
break;
|
||||
case '$':
|
||||
// target wird auf serv/args gesetzt
|
||||
// weiss noch nicht ob das gut ist
|
||||
t = r[1..];
|
||||
unless (sscanf(t, "%s/%s", svc, r))
|
||||
svc = t;
|
||||
//P3(("find_service: %O for %O(%O)\n", o, svc, r))
|
||||
if (o = find_service(lower_case(svc)))
|
||||
break;
|
||||
// unless (user) {
|
||||
// croak("_failure_unavailable_service",
|
||||
// "No service '[_service]' available here.", ([ "_service" : svc ]) );
|
||||
// return restart();
|
||||
// }
|
||||
return 0; // TODO!
|
||||
#ifndef __PIKE__
|
||||
case '@':
|
||||
// t[0..0] = PLACE_PATH;
|
||||
r = PLACE_PATH + lower_case(r[1..]);
|
||||
if (o = find_object(r)) break;
|
||||
// should check for legal name instead
|
||||
// of catch. TODO
|
||||
catch(o = r -> load());
|
||||
if (objectp(o)) break;
|
||||
// fall thru
|
||||
#endif
|
||||
default:
|
||||
o = find_object(r);
|
||||
D2( if(!o)
|
||||
D("OBJECT NOT FOUND: "+ r +"\n"); )
|
||||
}
|
||||
}
|
||||
else unless (user) {
|
||||
//return 0; // return SERVER_UNI !?
|
||||
return find_target_handler("/");
|
||||
}
|
||||
if (!objectp(o) && user) {
|
||||
// psyc/parse used to do this here
|
||||
o = summon_person(user); //, PSYC_PATH "user");
|
||||
P2(("%O summoning %O: %O\n", ME, user, o))
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
#ifndef __PIKE__
|
||||
// library transmits udp packets itself
|
||||
#include "edit.i"
|
||||
#endif
|
||||
|
||||
// target is lowercased already
|
||||
int psyc_sendmsg(mixed target, string mc, mixed data, mapping vars,
|
||||
int showingLog, mixed source, array(mixed) u) {
|
||||
string sname, host, buf, room;
|
||||
int port, usesrv = 1;
|
||||
object o;
|
||||
mixed t;
|
||||
|
||||
unless (u[UHost]) {
|
||||
#ifndef __PIKE__ // TPD
|
||||
sendmsg(source, "_failure_unsupported_notation_location",
|
||||
"PSYC server-independent uniform network "
|
||||
"identificators not implemented yet.", 0, 0);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
#if DEBUG > 0
|
||||
unless (stringp(mc)) {
|
||||
P0(("psyc_sendmsg got mc == %O from %O.\n"
|
||||
"probably a mistake when converting a walk_mapping.\n",
|
||||
mc, previous_object()))
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
sname = objectp(source) ? psyc_name(source) : sname;
|
||||
// host = lower_case(u[UHostPort]);
|
||||
// unless (u[URoot]) u[URoot] = "psyc://"+host;
|
||||
|
||||
// TODO: vars should be enforced system-wide
|
||||
unless (mappingp(vars)) vars = ([ ]);
|
||||
#ifndef FORK
|
||||
// seid ihr euch wirklich sicher, dass ihr diese zeile entfernen wollt?
|
||||
vars["_target"] = target;
|
||||
// <lynX> this could help protect against sources who destruct while
|
||||
// the message is in the queue. is it being used or is it okay to do
|
||||
// this operation at enqueing time? in fact the templates who use it
|
||||
// get it from psyctext() which resolves _source as source.. so this
|
||||
// here should not be necessary.. then again we just calculated it
|
||||
// so we don't want it to be calculated again later.. so we should
|
||||
// rather adapt the other spots where it's used rather than here..
|
||||
// after all it's mostly speed improvements.. no big thing.. TODO
|
||||
vars["_source"] = sname;
|
||||
#endif
|
||||
unless (port = u[UPort]) port = u[UTransport] == "s" ?
|
||||
PSYCS_SERVICE : PSYC_SERVICE;
|
||||
else {
|
||||
usesrv = 0;
|
||||
if (port < 0) {
|
||||
P2(("Minusport in %O or %O, _failure to %O || %O\n",
|
||||
target, u[UHost], vars["_context"], source))
|
||||
#ifndef __PIKE__ // TPD
|
||||
sendmsg(vars["_context"] || source,
|
||||
"_failure_network_connect_invalid_port",
|
||||
"No connectable port known for [_source_relay].",
|
||||
([ "_source_relay" : target || u[UHost] ]), ME);
|
||||
// ME shouldn't be necessary! TODO
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
host = lower_case(u[UHost]);
|
||||
if (query_udp_port() == port && is_localhost(host)) {
|
||||
o = find_psyc_object(u);
|
||||
// cache the resulting object for the url
|
||||
if (o) {
|
||||
// currently find_psyc_object returns 0 for the
|
||||
// local root, thus register_target messes up next. ouch.
|
||||
P1(("psyc_sendmsg registering target %O for %O found through %O\n",
|
||||
target, o, u))
|
||||
register_target(target, o);
|
||||
}
|
||||
#ifndef __PIKE__ // TPD
|
||||
return sendmsg(o, mc, data, vars, source);
|
||||
#endif
|
||||
// or deliver directly?
|
||||
}
|
||||
// since the local URoot is in targets and pointing to net/root
|
||||
// we have to get here *after* making sure we are not addressing
|
||||
// a local entity.
|
||||
P3(("looking for %O(%O) in %O..\n", target, u[UHostPort], targets))
|
||||
// if (member(targets, t2 = u[URoot])) {
|
||||
// t = targets[t2];
|
||||
// if (t) {
|
||||
if (t = targets[u[URoot]]) {
|
||||
P2(("%O to be delivered on %O's circuit\n",
|
||||
target, query_ip_name(t) || t ))
|
||||
register_target(target, t);
|
||||
// was delivermsg(
|
||||
return t->msg(sname, mc, data, vars, 0, target);
|
||||
// no more cleansing of targets mapping.. see also net/library.i
|
||||
// } else {
|
||||
// P1(("PSYC/TCP target %O gone!\n", t2))
|
||||
// m_delete( targets, t2 );
|
||||
// }
|
||||
}
|
||||
#ifndef __PIKE__
|
||||
// okay so we have no existing connection..
|
||||
// current rule of thumb to decide whether to open up a tcp
|
||||
// also all localhost traffic should be handled by udp TODO
|
||||
#ifdef _flag_enable_routing_UDP
|
||||
if (u[UTransport] == "c" ||
|
||||
# ifdef _flag_enable_routing_TLS
|
||||
u[UTransport] == "s" ||
|
||||
# endif
|
||||
(!u[UTransport] && !abbrev("_notice", mc)))
|
||||
#else
|
||||
if (!u[UTransport] || u[UTransport] == "c"
|
||||
# ifdef _flag_enable_routing_TLS
|
||||
|| u[UTransport] == "s"
|
||||
# endif
|
||||
)
|
||||
#endif
|
||||
{
|
||||
dns_resolve(host, (:
|
||||
object o;
|
||||
string hopo = $2;
|
||||
string psychopo;
|
||||
string psycippo = "psyc://"+ $1 +"/";
|
||||
|
||||
// if ($3 && $3 != PSYC_SERVICE) {
|
||||
if ($9) {
|
||||
hopo += ":"+$9;
|
||||
psycippo += ":"+$9;
|
||||
}
|
||||
// hope it is correct to have a trailing slash here
|
||||
psychopo = "psyc://"+ hopo +"/";
|
||||
unless (o = find_target_handler(psycippo)) {
|
||||
// we use psyc:host:port as an object name
|
||||
// we can change that if it is confusing
|
||||
#ifdef QUEUE_WITH_SCHEME
|
||||
// this makes it look for psyc:host:port as its queue
|
||||
o = ("psyc:"+hopo) -> circuit($2, $3, u[UTransport],
|
||||
usesrv && "psyc", 0, systemQ, psychopo);
|
||||
#else
|
||||
// this makes it look for host:port as its queue
|
||||
o = ("psyc:"+hopo) -> circuit($2, $3, u[UTransport],
|
||||
usesrv && "psyc", hopo, systemQ, psychopo);
|
||||
#endif
|
||||
// SRV tag "psyc" is actively being checked, but
|
||||
// don't rely on it.. just use it as a fallback if
|
||||
// nothing else is possible, but some clients may
|
||||
// no longer be able to connect to you...
|
||||
}
|
||||
register_target($4, o);
|
||||
register_target(psychopo, o);
|
||||
register_target(psycippo, o);
|
||||
P2(("delivering %O(%O) over %O\n", hopo, $1, o))
|
||||
P3(("targets = %O\n", targets))
|
||||
// psyc/circuit.c will register psyc://IP:PORT at logon()
|
||||
// the last thing missing is a way to register all CNAMEs
|
||||
return o->msg($5, $6, $7, $8, 0, $4);
|
||||
// ip=1 2 3 4 5 6 7 8 9
|
||||
:),
|
||||
#ifdef FORK
|
||||
host, port, target, source, mc, data, vars, u[UPort]
|
||||
#else
|
||||
host, port, target, sname, mc, data, vars, u[UPort]
|
||||
#endif
|
||||
);
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
#ifdef _flag_enable_routing_UDP
|
||||
if (u[UTransport] && u[UTransport] != "d")
|
||||
#endif
|
||||
{
|
||||
P1(("Invalid transport %O in %O, _failure to %O || %O\n",
|
||||
u[UTransport], target, vars["_context"], source))
|
||||
sendmsg(vars["_context"] || source,
|
||||
"_failure_network_connect_invalid_transport",
|
||||
"Unknown transport type '[_transport]' for [_source_relay].",
|
||||
([ "_source_relay" : target || u[UHost],
|
||||
"_transport": u[UTransport] ]), ME);
|
||||
// ME shouldn't be necessary! TODO
|
||||
return 0;
|
||||
}
|
||||
#ifdef _flag_enable_routing_UDP
|
||||
// fall thru to UDP
|
||||
# if DEBUG > 1
|
||||
if (port) {
|
||||
D(S("UDP[%s:%d] <= %O: %s\n", host, port, source, mc));
|
||||
} else {
|
||||
D(S("UDP[%s] <= %O: %s\n", host, source, mc));
|
||||
}
|
||||
# endif
|
||||
#ifndef NEW_RENDER
|
||||
// this produced wrong _length. please discontinue.
|
||||
if (stringp(data) && strlen(data))
|
||||
// why do we take guesses at data here? uncool!
|
||||
data="\n"+data+ (data[strlen(data)-1] == '\n' ?
|
||||
S_GLYPH_PACKET_DELIMITER "\n" :
|
||||
"\n" S_GLYPH_PACKET_DELIMITER "\n");
|
||||
else data="\n" S_GLYPH_PACKET_DELIMITER "\n"; // TODO? look up textdb.
|
||||
|
||||
// look! MMP-conformant support of the _context variable!
|
||||
if (room = vars["_context"]) {
|
||||
// this may have to change into a full psyc: URL
|
||||
if (objectp(room)) room = psyc_name(room);
|
||||
buf = S_GLYPH_PACKET_DELIMITER "\n"
|
||||
# ifdef PRE_SPEC
|
||||
":_source\t"+ sname +"\n"
|
||||
# else
|
||||
":_source_relay\t"+ sname +"\n"
|
||||
# endif
|
||||
+ ":_context\t"+ room +"\n";
|
||||
} else
|
||||
buf = S_GLYPH_PACKET_DELIMITER "\n"
|
||||
":_source\t"+ sname +"\n"
|
||||
":_target\t"+ target +"\n";
|
||||
buf += psyc_render(source, mc, data, vars, showingLog, target);
|
||||
#else
|
||||
buf = psyc_render(source, mc, data, vars, showingLog, target);
|
||||
#endif /* NEW_RENDER */
|
||||
|
||||
if (is_localhost(host)) return send_udp(host, port, buf);
|
||||
PT(("dns_resolve + send_udp %O:%O packet:\n%s", host,port,buf))
|
||||
dns_resolve(host, (: if (stringp($1))
|
||||
send_udp($1, $2, $3);
|
||||
else
|
||||
// if your driver complains about vars being
|
||||
// undefined at this point, you are probably
|
||||
// running an ldmud 3.2 which is not compatible
|
||||
// with psyced. pick a newer major version pls
|
||||
sendmsg(vars["_context"] || source,
|
||||
"_failure_network_send_resolve",
|
||||
"[_source_host] for [_source_relay] does not resolve.",
|
||||
([ "_source_host" : host,
|
||||
"_source_relay" : target||host ]), ME);
|
||||
return; :), port, buf);
|
||||
return 1;
|
||||
#endif /* _flag_enable_routing_UDP */
|
||||
#endif // PIKE
|
||||
}
|
||||
#endif
|
||||
|
||||
/* this breaks /connect ...
|
||||
object createUser(string nick) {
|
||||
PT(("creating " PSYC_PATH "user for "+ nick +"\n"))
|
||||
return named_clone(PSYC_PATH "user", nick);
|
||||
}
|
||||
*/
|
||||
|
17
world/net/psyc/master.c
Normal file
17
world/net/psyc/master.c
Normal file
|
@ -0,0 +1,17 @@
|
|||
// $Id: master.c,v 1.4 2005/03/14 10:23:27 lynx Exp $ // vim:syntax=lpc
|
||||
//
|
||||
#include <net.h>
|
||||
|
||||
#ifdef MASTER_LINK
|
||||
|
||||
inherit PSYC_PATH "active";
|
||||
|
||||
reset() {
|
||||
if (!interactive()) {
|
||||
D("..\n(reconnecting master link)\n");
|
||||
connect(MASTER_LINK);
|
||||
}
|
||||
// return ::reset();
|
||||
}
|
||||
|
||||
#endif
|
1166
world/net/psyc/parse.i
Normal file
1166
world/net/psyc/parse.i
Normal file
File diff suppressed because it is too large
Load diff
56
world/net/psyc/relay.c
Normal file
56
world/net/psyc/relay.c
Normal file
|
@ -0,0 +1,56 @@
|
|||
// $Id: relay.c,v 1.9 2007/09/18 08:37:58 lynx Exp $ // vim:syntax=lpc
|
||||
//
|
||||
// to become a generic gateway to all sorts of services
|
||||
//
|
||||
// dies ist noch auf AIM zugeschnitten.. "aim" und AIM_GATEWAY müssen
|
||||
// einfach nur in konfigurierbare strings rein und schon hat man
|
||||
// einen generischen relay für allerlei zwecke.
|
||||
|
||||
#include <net.h>
|
||||
#include <url.h>
|
||||
//#include <text.h>
|
||||
|
||||
//inherit NET_PATH "gateway/generic";
|
||||
inherit PSYC_PATH "active";
|
||||
|
||||
#ifdef AIM_GATEWAY
|
||||
void create() {
|
||||
array(string) u = URL(AIM_GATEWAY);
|
||||
// for a gateway that only supports tcp, append "c"
|
||||
// #define AIM_GATEWAY "psyc://aim.symlynX.com:49152c"
|
||||
// for a gateway that only supports udp, append "d"
|
||||
// #define AIM_GATEWAY "psyc://aim.symlynX.com:49152d"
|
||||
//
|
||||
// we prefer using udp, but if the gateway cannot handle that
|
||||
// we'll have to open up a tcp connection..
|
||||
//
|
||||
if (u && u[URL_TRANSPORT] == "c") {
|
||||
ahost = u[URL_HOST];
|
||||
aport = u[URL_PORT];
|
||||
register_target(lower_case(AIM_GATEWAY));
|
||||
}
|
||||
else ahost = 0;
|
||||
// joe = "nobody";
|
||||
// sTextPath("default", "en", "aim");
|
||||
register_scheme("aim");
|
||||
}
|
||||
|
||||
msg(source, mc, data, mapping vars, showingLog, target) {
|
||||
if (target && stringp(target) && abbrev("aim:", target)) {
|
||||
vars["_source_relay"] = source;
|
||||
vars["_target_relay"] = target;
|
||||
|
||||
if (interactive(ME))
|
||||
return ::msg(target, mc, data, vars, ME);
|
||||
//delivermsg(target, mc, data, vars, ME);
|
||||
else
|
||||
sendmsg(AIM_GATEWAY, mc, data, vars);
|
||||
} else if (source && stringp(source) && abbrev(AIM_GATEWAY, source)) {
|
||||
target = vars["_target_relay"];
|
||||
source = vars["_source_relay"];
|
||||
m_delete(vars, "_target_relay");
|
||||
m_delete(vars, "_source_relay");
|
||||
sendmsg(target, mc, data, vars, source);
|
||||
}
|
||||
}
|
||||
#endif
|
287
world/net/psyc/routerparse.i
Normal file
287
world/net/psyc/routerparse.i
Normal file
|
@ -0,0 +1,287 @@
|
|||
// vim:foldmethod=marker:syntax=lpc:noexpandtab
|
||||
// $Id: routerparse.i,v 1.15 2008/02/06 12:16:16 lynx Exp $
|
||||
//
|
||||
// THIS FILE IS FORK ONLY, thus currently not in use.
|
||||
//
|
||||
// TODO: both parsers need to croak on incoming _INTERNAL vars!!
|
||||
|
||||
#ifdef FORK // {{{
|
||||
// MMP PARSER - parses the routing header of PSYC, also known as MMP.
|
||||
//
|
||||
// THIS IS THE INNOVATIVE RID'N'SAGE PARSER REWRITE
|
||||
// they wanted to have it completely seperate from the original parse.i
|
||||
// so *keep* it seperate in its own file, routerparse.i!
|
||||
//
|
||||
// unfortunately it handles context counters in a non-universal way.. TODO
|
||||
// also it misses support for _trust
|
||||
|
||||
// this flag should enable forward-checks of dns resolutions..
|
||||
// currently we don't have that, so this flag actually disables
|
||||
// use of unprooven resolved hostnames and reduces everything to
|
||||
// ip numbers.
|
||||
//#define HOST_CHECKS
|
||||
|
||||
#ifndef PSYC_LIST_SIZE_LIMIT
|
||||
# define PSYC_LIST_SIZE_LIMIT 404
|
||||
#endif
|
||||
|
||||
// just the plain ip number of the remote host
|
||||
// ^^ glatte lüge!
|
||||
volatile string peerhost;
|
||||
#if 0 //defined(PSYC_TCP) && __EFUN_DEFINED__(strrstr)
|
||||
volatile string peerdomain;
|
||||
#endif
|
||||
// remote port number
|
||||
volatile int peerport;
|
||||
// unresolved-ip or ip:port
|
||||
volatile string peeraddr;
|
||||
// holds last ip we were connected to
|
||||
volatile string peerip;
|
||||
// how much can we trust the content of this packet?
|
||||
volatile int ctrust;
|
||||
|
||||
volatile closure _deliver;
|
||||
volatile object _psyced;
|
||||
#define PSYCED (_psyced ? _deliver : (_psyced = DAEMON_PATH "psyc" -> load(), _deliver = symbol_function("deliver", _psyced)))
|
||||
|
||||
|
||||
// current variables (":"), permanent variables ("=", "+", "-")
|
||||
//
|
||||
volatile mapping cvars = 0, pvars = ([ "_INTERNAL_origin" : ME ]), nvars = 0;
|
||||
|
||||
//
|
||||
// a distinction between mmp and psyc-vars should be made
|
||||
|
||||
// current method and incoming buffer
|
||||
volatile string buffer;
|
||||
|
||||
// cache of patched remote uniforms
|
||||
volatile mapping patches = ([]);
|
||||
|
||||
// parsing helpers..
|
||||
// MMP
|
||||
volatile string lastvar, lastmod, checkpack, origin_unl;
|
||||
volatile mixed lastvalue;
|
||||
// list parsing helpers..
|
||||
volatile array(mixed) list;
|
||||
volatile mapping hash;
|
||||
volatile int l = 0;
|
||||
//volatile int pongtime; // TODO: FORK is missing the PONG
|
||||
|
||||
# ifndef PSYC_TCP
|
||||
// resolved UNL of remote server (psyc://hostname or psyc://hostname:port)
|
||||
volatile string netloc;
|
||||
# define QUIT return 0;
|
||||
# endif
|
||||
|
||||
// prototype definition for #'getdata
|
||||
getdata(string a);
|
||||
restart();
|
||||
|
||||
#ifdef __LDMUD__
|
||||
# define SCANFIT (sscanf(a, "%1.1s%s%t%s", mod, vname, vvalue) || sscanf(a, "%1.1s%s", mod, vname))
|
||||
#else
|
||||
# define SCANFIT (sscanf(a, "%1s%s%*[ \t]%s", mod, vname, vvalue) || sscanf(a, "%1s%s", mod, vname))
|
||||
#endif
|
||||
|
||||
#define SPLITVAL(val) \
|
||||
unless (sscanf(val, "%s %s", val, vdata)) vdata = 0
|
||||
// sollte es wirklich ein space sein? hmmm.. %t ist sowieso zu grob..
|
||||
|
||||
# ifndef PSYC_TCP
|
||||
# define UDPRETURN(x) return x;
|
||||
# define ERROR(m) UDPRETURN(0)
|
||||
# else
|
||||
# define UDPRETURN(x)
|
||||
# define ERROR(m) { croak("_error_syntax_broken", "Failed in parsing " \
|
||||
"[_modifier], closing connection.", \
|
||||
([ "_modifier" : intp(m) \
|
||||
? to_string(({m})) \
|
||||
: to_string(m) ])); \
|
||||
monitor_report("_error_syntax_broken", \
|
||||
sprintf("MMP parsing failed. closing connection: %O", ME)); \
|
||||
destruct(ME); \
|
||||
}
|
||||
# endif
|
||||
|
||||
# ifdef PSYC_TCP
|
||||
void
|
||||
# else
|
||||
mixed
|
||||
# endif
|
||||
mmp_parse(string a) {
|
||||
string mod, vname, vvalue;
|
||||
|
||||
P3(("MMP>> %O\n", a))
|
||||
|
||||
if (sizeof(a)) switch(a[0]) {
|
||||
case '=':
|
||||
case '+':
|
||||
case '-':
|
||||
# ifndef PSYC_TCP
|
||||
// hier könnten wir jedenfalls nen error ausgeben
|
||||
// udp und state ist keine gute kombination
|
||||
# endif
|
||||
case ':':
|
||||
unless (2 <= sscanf(a, "%1.1s%s%t%s", mod, vname, vvalue)
|
||||
|| 2 == sscanf(a, "%1.1s%s", mod, vname)) {
|
||||
ERROR(a[0]);
|
||||
}
|
||||
if (vvalue == "") vvalue = 0;
|
||||
P3(("G: %O %O %O\n", mod, vname, vvalue))
|
||||
unless (vname) {
|
||||
unless (lastvar && a[0] != '-' && lastmod
|
||||
&& lastmod[0] == a[0]) ERROR(a[0]);
|
||||
if (pointerp(lastvalue)) {
|
||||
lastvalue += ({ vvalue });
|
||||
} else {
|
||||
lastvalue = ({ lastvalue, vvalue });
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
break;
|
||||
case '\t':
|
||||
unless (lastvar) {
|
||||
ERROR(a[0]);
|
||||
}
|
||||
if (pointerp(lastvalue))
|
||||
lastvalue[<1] += "\n"+a[1..];
|
||||
lastvalue += "\n"+a[1..];
|
||||
return;
|
||||
default:
|
||||
ERROR(a[0]);
|
||||
}
|
||||
|
||||
if (lastmod) switch(lastmod[0]) {
|
||||
# ifdef PSYC_TCP
|
||||
case '=':
|
||||
unless (lastvalue) {
|
||||
m_delete(pvars, lastvar);
|
||||
break;
|
||||
}
|
||||
if (lastvar == "_understand_modules") {
|
||||
gotiate(lastvalue);
|
||||
} else if (lastvar == "_use_modules") {
|
||||
negotiate(lastvalue);
|
||||
}
|
||||
pvars[lastvar] = lastvalue;
|
||||
# endif
|
||||
case ':':
|
||||
if (lastvalue)
|
||||
cvars[lastvar] = lastvalue;
|
||||
else
|
||||
m_add(nvars, lastvar);
|
||||
break;
|
||||
# ifdef PSYC_TCP
|
||||
case '+':
|
||||
_augment(pvars, lastvar, lastvalue);
|
||||
if (lastvar == "_understand_modules") {
|
||||
gotiate(lastvalue);
|
||||
} else if (lastvar == "_use_modules") {
|
||||
negotiate(lastvalue);
|
||||
}
|
||||
break;
|
||||
case '-':
|
||||
_diminish(pvars, lastvar, lastvalue);
|
||||
break;
|
||||
# endif
|
||||
}
|
||||
|
||||
|
||||
unless (sizeof(a)) {
|
||||
# ifdef PSYC_TCP
|
||||
next_input_to(#'getdata);
|
||||
# endif
|
||||
// TODO init cvars = copy(pvars)
|
||||
cvars = (pvars + cvars) - nvars;
|
||||
UDPRETURN(2)
|
||||
} else if (a[0] == '.') {
|
||||
# ifdef PSYC_TCP
|
||||
next_input_to(#'mmp_parse);
|
||||
# endif
|
||||
restart();
|
||||
UDPRETURN(1)
|
||||
} else {
|
||||
lastmod = mod;
|
||||
lastvar = vname;
|
||||
lastvalue = vvalue;
|
||||
# ifdef PSYC_TCP
|
||||
next_input_to(#'mmp_parse);
|
||||
# endif
|
||||
UDPRETURN(1)
|
||||
}
|
||||
# ifdef PSYC_TCP
|
||||
if (timeoutPending) remove_call_out(#'quit);
|
||||
# endif
|
||||
}
|
||||
|
||||
getdata(string a) {
|
||||
P4(("GETDATA: %O\n", a));
|
||||
if (a != ".") {
|
||||
if (buffer == "")
|
||||
buffer = a;
|
||||
else
|
||||
buffer += "\n"+a;
|
||||
# ifdef PSYC_TCP
|
||||
next_input_to(#'getdata);
|
||||
# endif
|
||||
} else {
|
||||
array(mixed) u;
|
||||
string t = cvars["_context"] || cvars["_source"];
|
||||
|
||||
# ifdef PSYC_TCP
|
||||
// let's do this before we deliver in case we run into
|
||||
// a runtime error (but it's still better to fix it!)
|
||||
next_input_to(#'mmp_parse);
|
||||
# endif
|
||||
if (!t || trustworthy > 5) {
|
||||
funcall(PSYCED, 0, 0, ME, peeraddr, peerhost,
|
||||
buffer, cvars);
|
||||
} else unless (u = parse_uniform(t)) {
|
||||
P1((">> parse_uniform %O %O\n", t, u))
|
||||
croak("_error_invalid_uniform",
|
||||
"Looks like a malformed URL to me.");
|
||||
QUIT
|
||||
} else dns_resolve(u[UHost], PSYCED, peerip, ME, peeraddr,
|
||||
u[UHost], buffer, cvars);
|
||||
restart();
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
restart() {
|
||||
// delete temporary variables for next msg
|
||||
cvars = ([ "_INTERNAL_trust" : trustworthy ]);
|
||||
nvars = m_allocate(0, 1);
|
||||
lastvalue = lastvar = lastmod = 0;
|
||||
// delete other stuff too
|
||||
buffer = "";
|
||||
ctrust = trustworthy;
|
||||
return 1;
|
||||
}
|
||||
|
||||
# ifdef PSYC_TCP
|
||||
startParse(string a) {
|
||||
if (a == ".") restart();
|
||||
else {
|
||||
croak("_error_syntax_initialization",
|
||||
"The protocol begins with a dot on a line by itself.");
|
||||
QUIT
|
||||
}
|
||||
next_input_to(#'mmp_parse);
|
||||
}
|
||||
# endif
|
||||
|
||||
// also overrides createUser in net/server.c
|
||||
createUser(string nick) {
|
||||
D2(D("creating " PSYC_PATH "user for "+ nick +"\n");)
|
||||
return named_clone(PSYC_PATH "user", nick);
|
||||
}
|
||||
|
||||
qOrigin() { return origin_unl; }
|
||||
|
||||
sOrigin(origin) { P3(("sOrigin(%O) (%O) in %O\n", origin, origin_unl, ME))
|
||||
unless (origin_unl) origin_unl = origin; }
|
||||
|
||||
#endif /* FORK }}} */
|
205
world/net/psyc/server.c
Normal file
205
world/net/psyc/server.c
Normal file
|
@ -0,0 +1,205 @@
|
|||
// $Id: server.c,v 1.98 2008/04/15 19:36:44 lynx Exp $ // vim:syntax=lpc
|
||||
//
|
||||
// the thing that answers on port 4404 of psyced.
|
||||
|
||||
#include <net.h>
|
||||
#include <services.h>
|
||||
#define NO_INHERIT
|
||||
#include <server.h>
|
||||
|
||||
#ifdef __PIKE__
|
||||
inherit net.psyc.circuit;
|
||||
#else
|
||||
// receiving variant
|
||||
inherit PSYC_PATH "circuit";
|
||||
#endif
|
||||
|
||||
// keep a list of objects to ->disconnected() when the driver tells us
|
||||
volatile array(object) disconnect_notifies;
|
||||
|
||||
void do_notify_on_disconnect(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; }
|
||||
|
||||
#ifndef __PIKE__
|
||||
|
||||
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) {
|
||||
P2(( "%O got disconnected.\n", ME))
|
||||
// emulate disconnected() for net/psyc/user
|
||||
if (disconnect_notifies) {
|
||||
foreach (object t : disconnect_notifies)
|
||||
if (t) t->disconnected();
|
||||
}
|
||||
::disconnected(remaining);
|
||||
QUIT // returns unexpected.. TODO
|
||||
}
|
||||
// actually bad considering that a packet may be in dns resolution
|
||||
// and wants to callback deliver in here TODO
|
||||
// saga: jedenfalls müssen wir entweder sofort destructen oder aber alle targets abmelden, die wir je angemeldet haben
|
||||
// lynX: oder die unterscheidung zwischen active und server abschaffen
|
||||
|
||||
static varargs int block(vastring mc, vastring reason) {
|
||||
P0(("Server blocked TCP PSYC connection from %O in %O (%O).\n",
|
||||
query_ip_number(ME), ME, mc))
|
||||
#ifdef BETA
|
||||
# define BETA_REDIR ""
|
||||
# define TEXT_REDIR ""
|
||||
#else
|
||||
# define BETA_REDIR ":_source_redirect\tpsyc://beta.ve.symlynX.com\n"
|
||||
# define TEXT_REDIR "Try the [_source_redirect] server instead!\n"
|
||||
#endif
|
||||
unless(mc) mc = "_error_illegal_source";
|
||||
unless(reason) reason = "";
|
||||
emit(".\n\
|
||||
\n\
|
||||
" BETA_REDIR + mc +"\n\
|
||||
Sorry, my configuration does not allow me to talk to you.\n\
|
||||
"+ reason +"\n\
|
||||
" TEXT_REDIR "\
|
||||
.\n"
|
||||
);
|
||||
QUIT
|
||||
}
|
||||
|
||||
#endif // PIKE
|
||||
|
||||
static void resolved(mixed host) {
|
||||
string netloc, numericpeeraddr;
|
||||
mixed uni, psycip;
|
||||
|
||||
unless (stringp(host)) {
|
||||
#if 1 //ndef BETA
|
||||
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
|
||||
# ifndef __PIKE__
|
||||
// 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;
|
||||
# endif
|
||||
host = peerip;
|
||||
# else
|
||||
block("_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))
|
||||
block("_failure_invalid_hostname",
|
||||
"Resolving your IP address triggered an internal error.");
|
||||
return;
|
||||
}
|
||||
#else
|
||||
// we sent them to beta, so let beta 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
|
||||
#ifndef __PIKE__
|
||||
if (trustworthy < 6) {
|
||||
if (trustworthy = legal_domain(host, peerport, "psyc", 0)) {
|
||||
if (trustworthy < 3) trustworthy = 0;
|
||||
}
|
||||
else {
|
||||
block();
|
||||
return;
|
||||
}
|
||||
}
|
||||
// the resolver does not register automatically, so here we go
|
||||
register_host(peerip, host);
|
||||
register_host(host);
|
||||
#endif // PIKE
|
||||
// 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 );
|
||||
#if 1 // 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
|
||||
// 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))
|
||||
#ifndef NOT_EXPERIMENTAL
|
||||
greet();
|
||||
#endif
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
113
world/net/psyc/udp.c
Normal file
113
world/net/psyc/udp.c
Normal file
|
@ -0,0 +1,113 @@
|
|||
// vim:foldmethod=marker:syntax=lpc:noexpandtab
|
||||
// $Id: udp.c,v 1.32 2008/03/29 20:36:44 lynx Exp $
|
||||
//
|
||||
#include <net.h>
|
||||
#include <person.h>
|
||||
#include <services.h>
|
||||
#include <url.h>
|
||||
#include <psyc.h>
|
||||
|
||||
// SECURITY CONCERN:
|
||||
// originating udp host and port numbers can rather easily be spoofed
|
||||
// and currently many routers/gateways won't bother delivering a packet which
|
||||
// couldn't possibly have come from that direction. UDP may generally
|
||||
// need to be considered not trustworthy, even if it apparently comes
|
||||
// from localhost. okay, hopefully our kernel is smart enough not to
|
||||
// believe an incoming packet to be from localhost. it's his job!
|
||||
|
||||
#ifdef __PIKE__
|
||||
import net.psyc.common;
|
||||
#else
|
||||
inherit PSYC_PATH "common";
|
||||
#endif
|
||||
|
||||
// network location of remote server (hostname or hostname:port)
|
||||
volatile mapping namecache = ([]);
|
||||
// volatile int timeoutPending;
|
||||
|
||||
// TODO? should keep caches of host:port per remote target somewhat like tcp
|
||||
|
||||
#ifdef FORK
|
||||
# include "routerparse.i"
|
||||
#else
|
||||
# include "parse.i"
|
||||
#endif
|
||||
|
||||
object load() { return ME; } // avoid a find_object call in obj/master
|
||||
|
||||
parseUDP2(host, ip, port, msg) {
|
||||
string *m;
|
||||
int i, l
|
||||
#ifdef FORK
|
||||
, parsed
|
||||
#endif
|
||||
;
|
||||
|
||||
unless (stringp(host)) host = ip;
|
||||
|
||||
P3(( "parseUDP(%O,%O): %O\n", ip,port,msg ))
|
||||
|
||||
pvars = ([ ]);
|
||||
|
||||
// this call is a performance killer
|
||||
// should UDP get used heavily.. TODO
|
||||
// needs hash-based host matching, not linear
|
||||
unless (hostCheck(ip, port, 1)) {
|
||||
log_file("PSYCBLOCK", "UDP from "+ip
|
||||
+" ignored » "+msg+" «\n");
|
||||
// netloc = "psyc://"+ip+":"+port;
|
||||
// sendmsg(netloc, "_error_illegal_source",
|
||||
// "Sorry, my configuration does not permit to talk to you.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
//netloc = "psyc://"+ip;
|
||||
peeraddr = peerhost = host;
|
||||
if (port != PSYC_SERVICE) {
|
||||
peerport = port;
|
||||
peeraddr += ":"+port+"d"; // this is a UDP peerport
|
||||
}
|
||||
// else: we presume a UDP 4404 also listens on TCP
|
||||
|
||||
#ifdef PRO_PATH
|
||||
P1(("./psyc/udp.c: restart. why?\n"))
|
||||
restart(); // leading . does that anyway
|
||||
#endif
|
||||
#if 1 //def NOT_EXPERIMENTAL
|
||||
pvars["_INTERNAL_source"] = "psyc://"+peeraddr+"/";
|
||||
#endif
|
||||
// m = regexplode(msg, "\r?\n"); ?
|
||||
m = explode(msg, "\n");
|
||||
|
||||
for (l=0; l<sizeof(m); l++) {
|
||||
// i'd like to know why no-mc has to be an empty string
|
||||
// rather than NULL from now on.
|
||||
// should you find out, pls tell me.. -lynX
|
||||
#ifdef FORK
|
||||
if (parsed == 2) getdata(m[l]);
|
||||
else unless (parsed = mmp_parse(m[l])) {
|
||||
#else
|
||||
if (sizeof(mc)) getdata(m[l]);
|
||||
else unless (parse(m[l])) {
|
||||
#endif
|
||||
log_file("PSYCHACK", "Can't parseUDP(%s): %O in %O\n",
|
||||
peeraddr,m[l],msg );
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
parseUDP(ip, port, msg) {
|
||||
dns_rresolve(ip, #'parseUDP2, ip, port, msg);
|
||||
}
|
||||
|
||||
#if 0
|
||||
// in other words.. this shouldnt get called :)
|
||||
pr(mc, fmt, a,b,c,d,e,f,g,h,i,j,k) {
|
||||
D("PSYC/UDP pr("+mc+", "+S(fmt, a,b,c,d,e,f,g,h,i,j,k)+")\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
// no syntax error messages via udp
|
||||
croak(a,b,c,d,e,f) {}
|
||||
|
35
world/net/psyc/user.c
Normal file
35
world/net/psyc/user.c
Normal file
|
@ -0,0 +1,35 @@
|
|||
// $Id: user.c,v 1.13 2008/03/11 13:42:27 lynx Exp $ // vim:syntax=lpc
|
||||
//
|
||||
// handler for PSYC clients
|
||||
|
||||
#include <net.h>
|
||||
#include <user.h>
|
||||
|
||||
qHasCurrentPlace() { return 0; }
|
||||
|
||||
logon() {
|
||||
#ifdef NO_EXTERNAL_LOGINS
|
||||
return destruct(ME);
|
||||
#endif
|
||||
// psyc users dont have their own socket, so the driver
|
||||
// does not call disconnected() for them - this enables the
|
||||
// psyc socket to do that
|
||||
this_interactive()->do_notify_on_disconnect(ME);
|
||||
// no lang support here either
|
||||
vSet("scheme", "psyc");
|
||||
return ::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) );
|
||||
#else
|
||||
// checkVar() still calls pr() .... grmlblmblm TODO
|
||||
raise_error("pr() called\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
wAction(mc, data, vars, source, variant, nick) { return 0; }
|
Loading…
Add table
Add a link
Reference in a new issue