1
0
Fork 0
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:
PSYC 2009-01-26 20:21:29 +01:00
commit 4e601cf1c7
509 changed files with 77963 additions and 0 deletions

42
world/net/psyc/LICENSE Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load diff

56
world/net/psyc/relay.c Normal file
View 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

View 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
View 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
View 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
View 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; }