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
4
world/net/spyc/active.c
Normal file
4
world/net/spyc/active.c
Normal file
|
@ -0,0 +1,4 @@
|
|||
// $Id: active.c,v 1.1 2008/01/30 17:06:48 lynx Exp $ // vim:syntax=lpc
|
||||
#include "psyc.h"
|
||||
#include "../psyc/active.c"
|
||||
|
493
world/net/spyc/circuit.c
Normal file
493
world/net/spyc/circuit.c
Normal file
|
@ -0,0 +1,493 @@
|
|||
// vim:foldmethod=marker:syntax=lpc:noexpandtab
|
||||
// $Id: circuit.c,v 1.33 2008/03/29 16:00:02 fippo Exp $
|
||||
|
||||
#include "psyc.h"
|
||||
#include <net.h>
|
||||
#include <url.h>
|
||||
#include <tls.h>
|
||||
#include <text.h>
|
||||
|
||||
inherit NET_PATH "trust";
|
||||
inherit NET_PATH "spyc/parse";
|
||||
virtual inherit NET_PATH "output";
|
||||
|
||||
volatile string peerhost;
|
||||
volatile string peeraddr;
|
||||
volatile string peerip;
|
||||
volatile int peerport;
|
||||
|
||||
volatile string netloc;
|
||||
|
||||
#ifndef NEW_RENDER
|
||||
# define NEW_RENDER
|
||||
#endif
|
||||
#include "edit.i"
|
||||
|
||||
// this is completely anti-psyc. it should take mcs as arguments
|
||||
// and look up the actual message from textdb.. FIXME
|
||||
#define CIRCUITERROR(reason) { debug_message("PSYC CIRCUIT ERROR: " reason); \
|
||||
croak("_error_circuit", "circuit error: " \
|
||||
reason); \
|
||||
return 0; \
|
||||
}
|
||||
|
||||
mapping instate;
|
||||
mapping outstate;
|
||||
|
||||
mapping legal_senders;
|
||||
|
||||
|
||||
volatile int flags = 0;
|
||||
|
||||
void circuit_msg(string mc, mapping vars, string data); // prototype
|
||||
varargs int msg(string source, string mc, string data,
|
||||
mapping vars, int showingLog, mixed target); // prototype
|
||||
protected void quit(); // prototype
|
||||
void runQ();
|
||||
|
||||
int isServer() { return 0; }
|
||||
|
||||
void feed(string data) {
|
||||
input_to(#'feed, INPUT_IGNORE_BANG);
|
||||
::feed(data);
|
||||
}
|
||||
|
||||
// yes, this is a funny implementation of croak
|
||||
// it does not use msg(). Yes, that is intended
|
||||
varargs mixed croak(string mc, string data, vamapping vars, vamixed source) {
|
||||
binary_message(sprintf("\n%s\n%s\n|\n", mc, data));
|
||||
remove_interactive(ME);
|
||||
destruct(ME);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// gets called during socket logon
|
||||
int logon(int success) {
|
||||
sAuthHosts(([ ])); // reset authhosts
|
||||
legal_senders = ([ ]);
|
||||
instate = ([ "_INTERNAL_origin" : ME]);
|
||||
outstate = ([ ]);
|
||||
#ifdef __TLS__
|
||||
mixed cert;
|
||||
if (tls_available() && tls_query_connection_state(ME) == 1 && mappingp(cert = tls_certificate(ME, 0))) {
|
||||
mixed m, t;
|
||||
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
|
||||
|
||||
peerip = query_ip_number(ME) || "127.0.0.1";
|
||||
|
||||
enable_binary(ME);
|
||||
input_to(#'feed, INPUT_IGNORE_BANG);
|
||||
|
||||
call_out(#'quit, 90);
|
||||
flags = TCP_PENDING_TIMEOUT;
|
||||
|
||||
parser_init();
|
||||
|
||||
// FIXME
|
||||
unless(isServer()) {
|
||||
emit("|\n"); // initial greeting
|
||||
msg(0, "_request_features", 0);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int disconnected(string remaining) {
|
||||
// i love to copy+paste source codes! thx for NOT sharing.. grrr
|
||||
#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
|
||||
}
|
||||
|
||||
// respond to the first empty packet
|
||||
first_response() {
|
||||
emit("|\n");
|
||||
}
|
||||
|
||||
// processes routing header variable assignments
|
||||
// basic version does no state
|
||||
mapping process_header(mixed varops) {
|
||||
mapping vars = ([ ]);
|
||||
foreach(mixed vop : varops) {
|
||||
string vname = vop[0];
|
||||
switch(vop[1]) {
|
||||
case C_GLYPH_MODIFIER_ASSIGN:
|
||||
instate[vname] = vop[2];
|
||||
// fall thru
|
||||
case C_GLYPH_MODIFIER_SET:
|
||||
vars[vname] = vop[2];
|
||||
break;
|
||||
case C_GLYPH_MODIFIER_AUGMENT:
|
||||
case C_GLYPH_MODIFIER_DIMINISH:
|
||||
case C_GLYPH_MODIFIER_QUERY:
|
||||
CIRCUITERROR("header modifier with glyph other than ':', this is not implemented")
|
||||
break;
|
||||
default:
|
||||
CIRCUITERROR("header modifier with unknown glyph")
|
||||
break;
|
||||
}
|
||||
// FIXME: not every legal varname is a mmp varname
|
||||
// look at shared_memory("routing")
|
||||
if (!legal_keyword(vname) || abbrev("_INTERNAL", vname)) {
|
||||
CIRCUITERROR("illegal varname in header")
|
||||
}
|
||||
}
|
||||
return vars;
|
||||
}
|
||||
|
||||
// handling of packets received
|
||||
void done(mixed header_vars, mixed varops, mixed method, mixed body) {
|
||||
string vname;
|
||||
mixed vop; // value operation
|
||||
mapping vars;
|
||||
string t;
|
||||
|
||||
// check that method is a valid keyword
|
||||
if (method && !legal_keyword(method)) {
|
||||
CIRCUITERROR("non legal method");
|
||||
}
|
||||
// copy() + occasional double modifier ops should be more
|
||||
// efficient than merge at every packet --lynX
|
||||
// no one cares about "efficiency" here. please proof your
|
||||
// bold statements with benchmarks anyway
|
||||
vars = header_vars + instate;
|
||||
|
||||
// FIXME: this can happen earlier, e.g. in parse.c after
|
||||
// process_header
|
||||
// check _source/_context
|
||||
// this check can be skipped if _source and _context are empty
|
||||
if ((t = vars["_context"] || vars["_source"])) {
|
||||
array(mixed) u;
|
||||
unless (u = parse_uniform(t)) {
|
||||
CIRCUITERROR("logical source is not an uniform\n")
|
||||
}
|
||||
unless (qAuthenticated(NAMEPREP(u[UHost]))) {
|
||||
CIRCUITERROR("non-authenticated host\n")
|
||||
}
|
||||
}
|
||||
// check that _target is hosted by us
|
||||
// this check can be skipped if _target is not set
|
||||
if ((t = vars["_target"])) {
|
||||
array(mixed) u;
|
||||
unless (u = parse_uniform(t)) {
|
||||
CIRCUITERROR("target is not an uniform\n")
|
||||
}
|
||||
// FIXME relaying support here?
|
||||
if (!(is_localhost(u[UHost])) || u[UHost] == "localhost") {
|
||||
CIRCUITERROR("target is not configured on this server\n")
|
||||
}
|
||||
}
|
||||
// FIXME: i dont like this block... maybe we decode each variable
|
||||
// when setting it?
|
||||
// that would also fit with 0 as varname deletion
|
||||
// below
|
||||
foreach(vop : varops) {
|
||||
vname = vop[0];
|
||||
// TODO unpack _amount
|
||||
// TODO unpack _time
|
||||
if (abbrev("_list", vname)) {
|
||||
mixed plist = list_parse(vop[2]);
|
||||
if (plist == -1) {
|
||||
CIRCUITERROR("could not parse list");
|
||||
}
|
||||
vop[2] = plist;
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME deliver packet
|
||||
// this should be a separate function
|
||||
PT(("vars is %O\n", vars))
|
||||
PT(("method %O\nbody %O\n", method, body))
|
||||
PT(("packet done\n"))
|
||||
// delivery rules as usual, but
|
||||
if (vars["_context"]) {
|
||||
mixed context;
|
||||
mixed context_state;
|
||||
mixed source, target;
|
||||
|
||||
if (vars["_source"]) {
|
||||
P0(("invalid _context %O with _source %O\n",
|
||||
context, vars["_source"]))
|
||||
CIRCUITERROR("invalid usage of context with _source");
|
||||
}
|
||||
|
||||
context = find_context(vars["_context"]);
|
||||
if (!objectp(context)) {
|
||||
P0(("context %O not found?!\n", vars["_context"]))
|
||||
return;
|
||||
}
|
||||
context_state = context->get_state();
|
||||
|
||||
// apply varops to context state
|
||||
foreach(vop : varops) {
|
||||
vname = vop[0];
|
||||
if (!legal_keyword(vname) || abbrev("_INTERNAL", vname)) {
|
||||
CIRCUITERROR("illegal varname in psyc")
|
||||
}
|
||||
|
||||
switch(vop[1]) { // the glyph
|
||||
case C_GLYPH_MODIFIER_SET:
|
||||
vars[vname] = vop[2];
|
||||
break;
|
||||
case C_GLYPH_MODIFIER_ASSIGN:
|
||||
vars[vname] = context_state[vname] = vop[2];
|
||||
break;
|
||||
case C_GLYPH_MODIFIER_AUGMENT:
|
||||
if (!abbrev("_list", vname)) {
|
||||
CIRCUITERROR("psyc modifier + with non-list arg")
|
||||
}
|
||||
// FIXME: duplicates?
|
||||
context_state[vname] += vop[2];
|
||||
PT(("current state is %O, augment %O\n", context_state[vname], vop[2]))
|
||||
break;
|
||||
case C_GLYPH_MODIFIER_DIMINISH:
|
||||
if (!abbrev("_list", vname)) {
|
||||
CIRCUITERROR("psyc modifier + with non-list arg")
|
||||
}
|
||||
PT(("current state is %O, diminish %O\n", context_state[vname], vop[2]))
|
||||
foreach(mixed item : vop[2])
|
||||
context_state[vname] -= ({ item });
|
||||
PT(("after dim: %O\n", context_state[vname]))
|
||||
break;
|
||||
case C_GLYPH_MODIFIER_QUERY:
|
||||
CIRCUITERROR("psyc modifier ? not implemented")
|
||||
break;
|
||||
}
|
||||
}
|
||||
vars = vars + context_state;
|
||||
// FIXME: is it legal to do this if this has _target?
|
||||
// there should be no mods then anyway
|
||||
context->commit_state(context_state);
|
||||
|
||||
|
||||
if (vars["_target"]) {
|
||||
// FIXME: delivery copycat from below
|
||||
// beware: source is set to 0 here as it may not be present
|
||||
target = find_psyc_object(parse_uniform(vars["_target"]));
|
||||
PT(("target is %O\n", target))
|
||||
// FIXME: net/entity can not yet deal with 0 method
|
||||
//
|
||||
if (objectp(context)) {
|
||||
context->msg(0, method || "", body, vars, 0, target);
|
||||
} else {
|
||||
// FIXME: proper croak back to sender here
|
||||
P0(("context %O for unicast to %O not found???\n", target))
|
||||
}
|
||||
} else {
|
||||
if (vars["_source_relay"]) {
|
||||
mixed localrelay;
|
||||
if ((localrelay = psyc_object(vars["_source_relay"]))) {
|
||||
P0(("local relay %O\n", localrelay))
|
||||
vars["_source_relay"] = localrelay;
|
||||
} else { // NORMALIZE UNIFORM
|
||||
vars["_source_relay"] = lower_case(vars["_source_relay"]);
|
||||
}
|
||||
}
|
||||
if (objectp(context)) {
|
||||
// do we need more local object detection here?
|
||||
context -> castmsg(source, method || "", body, vars);
|
||||
} else {
|
||||
// empty contexts are not bad currently
|
||||
// in the current implementation it only means that no one
|
||||
// interested in that context is online right now
|
||||
// FIXME: lines above are about the old stuff where we did
|
||||
// not have context state
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!vars["_target"] && !vars["_source"]) {
|
||||
circuit_msg(method, vars, body);
|
||||
} else {
|
||||
string source;
|
||||
mixed target;
|
||||
if (!vars["_source"]) {
|
||||
// FIXME: where to set netloc in active
|
||||
if (!netloc) { // set in sender after _request_features
|
||||
// FIXME: this is wrong
|
||||
CIRCUITERROR("Did you forget to request circuit features?");
|
||||
}
|
||||
source = netloc;
|
||||
} else {
|
||||
// FIXME: a macro NORMALIZE_UNIFORM that may do lower_case please
|
||||
// not a simple lower_case
|
||||
source = lower_case(vars["_source"]);
|
||||
}
|
||||
// source was checked either via x509 or dns before
|
||||
// so it is 'safe' to do this
|
||||
register_target(source);
|
||||
|
||||
|
||||
// deliver FIXME same code above
|
||||
if (!vars["_target"]) {
|
||||
target = find_object(NET_PATH "root");
|
||||
} else {
|
||||
target = find_psyc_object(parse_uniform(vars["_target"]));
|
||||
}
|
||||
PT(("target is %O\n", target))
|
||||
// FIXME: net/entity can not yet deal with 0 method
|
||||
if (objectp(target))
|
||||
target->msg(source, method || "", body, vars);
|
||||
else {
|
||||
// FIXME: proper croak back to sender here
|
||||
P0(("target %O not found???\n", target))
|
||||
}
|
||||
}
|
||||
}
|
||||
::done(header_vars, varops, method, body);
|
||||
}
|
||||
|
||||
// request sender authentication and/or target acknowledgement
|
||||
// from the remote side
|
||||
void sender_verification(array(string) sourcehosts, array(string) targethosts)
|
||||
{
|
||||
// FIXME: wrong variables here
|
||||
mapping vars = ([ "_list_sources_hosts" : sourcehosts,
|
||||
"_list_targets_hosts" : targethosts,
|
||||
"_tag" : RANDHEXSTRING ]);
|
||||
// assumption: we have already resolved all targethosts and
|
||||
// they point to the remote ip
|
||||
foreach(string ho : targethosts) {
|
||||
sAuthenticated(ho);
|
||||
}
|
||||
|
||||
msg(0, "_request_verification", 0, vars);
|
||||
}
|
||||
|
||||
// receives a msg from the remote side
|
||||
// note: this is circuit-messaging
|
||||
void circuit_msg(string mc, mapping vars, string data) {
|
||||
switch(mc) {
|
||||
case "_request_verification":
|
||||
if (tls_query_connection_state(ME) == 0) {
|
||||
array(string) targethosts = ({ });
|
||||
foreach(string ho : vars["_list_targets_hosts"]) {
|
||||
if (is_localhost(ho)) {
|
||||
targethosts += ({ ho });
|
||||
}
|
||||
}
|
||||
if (sizeof(vars["_list_sources_hosts"]) == 1) {
|
||||
// doing multiple resolutions in parallel is more complicated
|
||||
string ho = vars["_list_sources_hosts"][0];
|
||||
if (qAuthenticated(ho)) {
|
||||
P0(("warning: trying to reverify authenticated host %O",ho))
|
||||
} else {
|
||||
dns_resolve(ho, (:
|
||||
// FIXME: psyc/parse::deliver is much better here
|
||||
mixed rv = (["_list_targets_accepted_hosts":targethosts]);
|
||||
|
||||
if (vars["_tag"]) rv["_tag_reply"] = vars["_tag"];
|
||||
if ($1 == peerip) {
|
||||
sAuthenticated(NAMEPREP(ho));
|
||||
rv["_list_sources_verified_hosts"] = ({ ho });
|
||||
} else {
|
||||
rv["_list_sources_rejected_hosts"] = ({ ho });
|
||||
}
|
||||
msg(0, "_notice_verification", 0, rv);
|
||||
return;
|
||||
:));
|
||||
}
|
||||
} else {
|
||||
// FIXME!!!!
|
||||
CIRCUITERROR("sorry, no more than one element in _list_sources_hosts currently");
|
||||
}
|
||||
// keep tag if present!!!
|
||||
// resolve all of _list_sources_hosts
|
||||
// look at _list_targets_hosts and determine localhostiness
|
||||
} else {
|
||||
CIRCUITERROR("_request_verification is not allowed on TLS circuits.");
|
||||
// _request_verification is not allowed on tls circuits
|
||||
}
|
||||
break;
|
||||
case "_notice_features":
|
||||
// FIXME: watch for _list_using_modules
|
||||
if (flags & TCP_PENDING_TIMEOUT) {
|
||||
P0(("removing call out\n"))
|
||||
remove_call_out(#'quit);
|
||||
flags -= TCP_PENDING_TIMEOUT;
|
||||
}
|
||||
sTextPath();
|
||||
if (tls_query_connection_state(ME) == 0) {
|
||||
// start hostname verification
|
||||
// rather: look at Q and look for the hostnames we need
|
||||
sender_verification(({ SERVER_HOST }), ({ peerhost }));
|
||||
} else {
|
||||
if (function_exists("runQ")) {
|
||||
runQ();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "_notice_verification":
|
||||
P0(("_notice verification with %O\n", vars))
|
||||
if (function_exists("runQ")) {
|
||||
runQ();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
P0(("%O got circuit_msg %O, not implemented\n", ME, mc))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// delivers a message to the remote side
|
||||
varargs int msg(string source, string mc, string data,
|
||||
mapping vars, int showingLog, mixed target) {
|
||||
|
||||
string buf = "";
|
||||
|
||||
unless(vars) vars = ([ ]);
|
||||
buf = psyc_render(source, mc, data, vars, showingLog, target);
|
||||
#ifdef _flag_log_sockets_PSYC
|
||||
log_file("RAW_PSYC", "» %O\n%s\n", ME, buf);
|
||||
#endif
|
||||
return emit(buf);
|
||||
}
|
4
world/net/spyc/common.c
Normal file
4
world/net/spyc/common.c
Normal file
|
@ -0,0 +1,4 @@
|
|||
// $Id: common.c,v 1.1 2008/01/30 17:06:48 lynx Exp $ // vim:syntax=lpc
|
||||
#include "psyc.h"
|
||||
#include "../psyc/common.c"
|
||||
|
4
world/net/spyc/edit.i
Normal file
4
world/net/spyc/edit.i
Normal file
|
@ -0,0 +1,4 @@
|
|||
// vim:foldmethod=marker:syntax=lpc:noexpandtab
|
||||
// $Id: edit.i,v 1.8 2008/02/19 16:28:41 lynx Exp $
|
||||
|
||||
#include "../psyc/edit.i"
|
4
world/net/spyc/library.i
Normal file
4
world/net/spyc/library.i
Normal file
|
@ -0,0 +1,4 @@
|
|||
// $Id: library.i,v 1.1 2008/02/07 09:33:46 fippo Exp $ // vim:syntax=lpc
|
||||
#include "psyc.h"
|
||||
#include "../psyc/library.i"
|
||||
|
398
world/net/spyc/parse.c
Normal file
398
world/net/spyc/parse.c
Normal file
|
@ -0,0 +1,398 @@
|
|||
// vim:foldmethod=marker:syntax=lpc:noexpandtab
|
||||
// $Id: parse.c,v 1.24 2008/03/29 16:00:02 fippo Exp $
|
||||
//
|
||||
#include "psyc.h"
|
||||
#include <net.h>
|
||||
#include <input_to.h>
|
||||
|
||||
private string buffer;
|
||||
private string body_buffer;
|
||||
int state;
|
||||
int body_len;
|
||||
int may_parse_more;
|
||||
|
||||
// tempoary used to hold assigment lists vname -> ({ glyph, state, vvalue })
|
||||
array(mixed) tvars;
|
||||
mapping hvars;
|
||||
|
||||
// this is completely anti-psyc. it should take mcs as arguments
|
||||
// and look up the actual message from textdb.. FIXME
|
||||
#define PARSEERROR(reason) { debug_message("PSYC PARSE ERROR: " reason "\n"); \
|
||||
croak("_error_syntax_broken", "Failed parsing: " \
|
||||
reason); \
|
||||
return 0; \
|
||||
}
|
||||
|
||||
|
||||
#define DELIM S_GLYPH_PACKET_DELIMITER "\n"
|
||||
#define C_LINEFEED '\n'
|
||||
#define MVAR_GLYPH 0
|
||||
#define MVAR_STATE 1
|
||||
#define MVAR_VALUE 2
|
||||
|
||||
|
||||
step(); // prototype
|
||||
|
||||
// reset parser state
|
||||
void parser_reset() {
|
||||
if (state != PSYCPARSE_STATE_BLOCKED)
|
||||
state = PSYCPARSE_STATE_HEADER;
|
||||
body_len = 0;
|
||||
body_buffer = 0;
|
||||
may_parse_more = 1;
|
||||
tvars = ({ });
|
||||
hvars = ([ ]);
|
||||
}
|
||||
|
||||
// initialize the parser
|
||||
void parser_init() {
|
||||
buffer = "";
|
||||
parser_reset();
|
||||
state = PSYCPARSE_STATE_GREET; // AFTER reset
|
||||
}
|
||||
|
||||
// it is sometimes useful to stop parsing
|
||||
void interrupt_parse() {
|
||||
state = PSYCPARSE_STATE_BLOCKED;
|
||||
}
|
||||
|
||||
// and resume after some blocking operation is done
|
||||
void resume_parse() {
|
||||
state = PSYCPARSE_STATE_HEADER;
|
||||
}
|
||||
|
||||
// input data to the buffer
|
||||
void feed(string data) {
|
||||
# ifdef _flag_log_sockets_PSYC
|
||||
log_file("RAW_PSYC", "» %O\n%s\n", ME, data);
|
||||
# endif
|
||||
buffer += data;
|
||||
|
||||
do {
|
||||
may_parse_more = 0;
|
||||
step();
|
||||
} while (may_parse_more);
|
||||
}
|
||||
|
||||
|
||||
// overload this as needed
|
||||
varargs mixed croak(string mc, string data, vamapping vars, vamixed source) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// called when a complete packet has arrived
|
||||
void done(mixed header_vars, mixed varops, mixed method, mixed body) {
|
||||
parser_reset();
|
||||
}
|
||||
|
||||
// processes routing header variable assignments
|
||||
// basic version does no state
|
||||
mapping process_header(mixed varops) {
|
||||
mapping vars = ([ ]);
|
||||
// apply mmp state
|
||||
foreach(mixed vop : varops) {
|
||||
string vname = vop[0];
|
||||
switch(vop[1]) {
|
||||
case C_GLYPH_MODIFIER_SET:
|
||||
vars[vname] = vop[2];
|
||||
break;
|
||||
case C_GLYPH_MODIFIER_AUGMENT:
|
||||
case C_GLYPH_MODIFIER_DIMINISH:
|
||||
case C_GLYPH_MODIFIER_QUERY:
|
||||
case C_GLYPH_MODIFIER_ASSIGN:
|
||||
PARSEERROR("header modifier with glyph other than ':', this is not implemented")
|
||||
break;
|
||||
default:
|
||||
PARSEERROR("header modifier with unknown glyph")
|
||||
break;
|
||||
}
|
||||
// FIXME: not every legal varname is a mmp varname
|
||||
// look at shared_memory("routing")
|
||||
if (!legal_keyword(vname) || abbrev("_INTERNAL", vname)) {
|
||||
PARSEERROR("illegal varname in header")
|
||||
}
|
||||
}
|
||||
return vars;
|
||||
}
|
||||
|
||||
// parse the header part of the packet
|
||||
// i.e. that is all mmp modifiers
|
||||
// switch to content buffering mode afterwards
|
||||
void parse_header() {
|
||||
if (!strlen(buffer)) return;
|
||||
if (buffer[0] == C_GLYPH_PACKET_DELIMITER) {
|
||||
if (strlen(buffer) < 2)
|
||||
return;
|
||||
if (buffer[1] == C_LINEFEED) {
|
||||
buffer = buffer[2..];
|
||||
hvars = process_header(tvars);
|
||||
tvars = ({ });
|
||||
done(hvars, tvars, 0, 0);
|
||||
} else {
|
||||
// this one is sth like |whatever
|
||||
// actually this should be noglyph i think
|
||||
PARSEERROR("strange thing")
|
||||
}
|
||||
} else if (buffer[0] == C_LINEFEED) {
|
||||
// state transition from parsing header to buffering body
|
||||
buffer = buffer[1..];
|
||||
hvars = process_header(tvars);
|
||||
tvars = ({ });
|
||||
// FIXME: validate source/context here
|
||||
state = PSYCPARSE_STATE_CONTENT;
|
||||
if (hvars["_length"])
|
||||
body_len = to_int(hvars["_length"][MVAR_VALUE]);
|
||||
step();
|
||||
} else { // parse mmp-header
|
||||
int fit;
|
||||
int glyph;
|
||||
string vname, vvalue;
|
||||
switch(buffer[0]) {
|
||||
case C_GLYPH_MODIFIER_SET:
|
||||
case C_GLYPH_MODIFIER_ASSIGN:
|
||||
case C_GLYPH_MODIFIER_AUGMENT:
|
||||
case C_GLYPH_MODIFIER_DIMINISH:
|
||||
case C_GLYPH_MODIFIER_QUERY:
|
||||
glyph = buffer[0];
|
||||
buffer = buffer[1..];
|
||||
break;
|
||||
default:
|
||||
PARSEERROR("noglyph")
|
||||
}
|
||||
fit = sscanf(buffer, "%.1s%t", vname);
|
||||
if (fit != 1) {
|
||||
PARSEERROR("vname")
|
||||
}
|
||||
buffer = buffer[strlen(vname)..];
|
||||
switch(buffer[0]) {
|
||||
case '\t':
|
||||
fit = sscanf(buffer, "\t%s\n%.0s", vvalue, buffer);
|
||||
if (fit != 2) {
|
||||
PARSEERROR("simple-arg")
|
||||
}
|
||||
break;
|
||||
case '\n': // deletion
|
||||
// this is currently implemented as "vvalue is 0" internally
|
||||
// and must handled in done() when merging
|
||||
buffer = buffer[1..];
|
||||
break;
|
||||
default:
|
||||
PARSEERROR("arg")
|
||||
}
|
||||
tvars += ({ ({ vname, glyph, vvalue }) });
|
||||
step();
|
||||
}
|
||||
}
|
||||
|
||||
// parse all psyc-modifiers
|
||||
// this differes from the mmp modifiers in the sense that
|
||||
// a) packet is known to be complete here
|
||||
// b) psyc modifiers may have binary args
|
||||
void parse_psyc() {
|
||||
while(1) { // slurp in all psyc-modifiers
|
||||
int fit, len;
|
||||
int glyph;
|
||||
string vname, vvalue;
|
||||
switch(body_buffer[0]) {
|
||||
case C_GLYPH_MODIFIER_SET:
|
||||
case C_GLYPH_MODIFIER_ASSIGN:
|
||||
case C_GLYPH_MODIFIER_AUGMENT:
|
||||
case C_GLYPH_MODIFIER_DIMINISH:
|
||||
case C_GLYPH_MODIFIER_QUERY:
|
||||
glyph = body_buffer[0];
|
||||
body_buffer = body_buffer[1..];
|
||||
break;
|
||||
default:
|
||||
// this is the method
|
||||
return;
|
||||
}
|
||||
fit = sscanf(body_buffer, "%.1s%t", vname);
|
||||
if (fit != 1) {
|
||||
PARSEERROR("vname")
|
||||
}
|
||||
body_buffer = body_buffer[strlen(vname)..];
|
||||
switch(body_buffer[0]) {
|
||||
case ' ':
|
||||
fit = sscanf(body_buffer, " %d\t%.0s", len, body_buffer);
|
||||
if (fit != 2) {
|
||||
PARSEERROR("binary-arg length")
|
||||
}
|
||||
if (len < 0) {
|
||||
PARSEERROR("negative binary length")
|
||||
}
|
||||
if (strlen(body_buffer) < len) {
|
||||
PARSEERROR("not enough to read binary arg, may not happen")
|
||||
}
|
||||
vvalue = body_buffer[..len-1];
|
||||
body_buffer = body_buffer[len..];
|
||||
if (body_buffer[0] != C_LINEFEED) {
|
||||
PARSEERROR("binary terminal")
|
||||
}
|
||||
body_buffer = body_buffer[1..];
|
||||
break;
|
||||
case '\t':
|
||||
fit = sscanf(body_buffer, "\t%s\n%.0s", vvalue, body_buffer);
|
||||
if (fit != 2) {
|
||||
PARSEERROR("simple-arg")
|
||||
}
|
||||
break;
|
||||
case '\n':
|
||||
switch(glyph) {
|
||||
case C_GLYPH_MODIFIER_ASSIGN:
|
||||
// delete this context's state
|
||||
PARSEERROR("tbd")
|
||||
// unfortunately the routing hasn't been processed at
|
||||
// this moment yet, so we don't know whose context this
|
||||
// is and if it is legitimate. we first have to fix the
|
||||
// processing of the routing layer before we can implement
|
||||
// anything of this
|
||||
continue;
|
||||
case C_GLYPH_MODIFIER_SET:
|
||||
// remember to temporarily ignore state
|
||||
PARSEERROR("tbd")
|
||||
continue;
|
||||
case C_GLYPH_MODIFIER_QUERY:
|
||||
// mark that the next reply packet should
|
||||
// contain a state sync
|
||||
PARSEERROR("tbd")
|
||||
continue;
|
||||
default:
|
||||
PARSEERROR("undefined operation")
|
||||
}
|
||||
return;
|
||||
default:
|
||||
PARSEERROR("arg")
|
||||
}
|
||||
tvars += ({ ({ vname, glyph, vvalue }) });
|
||||
}
|
||||
}
|
||||
|
||||
// parse completed content
|
||||
void parse_content() {
|
||||
int fit;
|
||||
string method, body;
|
||||
|
||||
parse_psyc();
|
||||
// ASSERT strlen(buffer)
|
||||
if (body_buffer[0] == C_LINEFEED) {
|
||||
PARSEERROR("empty method")
|
||||
}
|
||||
|
||||
// FIXME: i am not sure if this is correct...
|
||||
if (body_buffer == S_GLYPH_PACKET_DELIMITER) {
|
||||
P0(("encountered packet delimiter in packet body? how's that?\n"))
|
||||
done(hvars, tvars, 0, 0);
|
||||
return;
|
||||
}
|
||||
fit = sscanf(body_buffer, "%.1s\n%.0s", method, body_buffer);
|
||||
if (fit != 2 || !legal_keyword(method)) {
|
||||
croak("_error_illegal_method",
|
||||
"That's not a valid method name.");
|
||||
return; // NOTREACHED
|
||||
}
|
||||
|
||||
// mhmm... why does body_buffer still contain the newline?
|
||||
// because the newline is by definition not part of the body!
|
||||
if (strlen(body_buffer)) body = body_buffer[..<2];
|
||||
done(hvars, tvars, method, body);
|
||||
}
|
||||
|
||||
// buffer content until complete
|
||||
// then parse it
|
||||
// note: you could overload this, if you just want to route
|
||||
// the packet
|
||||
void buffer_content() {
|
||||
int t;
|
||||
if (body_len && strlen(buffer) >= body_len + 3) {
|
||||
// make sure that the packet is properly terminated
|
||||
if (buffer[body_len..body_len+2] != "\n" DELIM) {
|
||||
PARSEERROR("binary packet delimiter")
|
||||
}
|
||||
body_buffer = buffer[..body_len];
|
||||
buffer = buffer[body_len+3..];
|
||||
parse_content();
|
||||
} else if ((t = strstr(buffer, "\n" DELIM)) != -1) {
|
||||
body_buffer = buffer[..t];
|
||||
buffer = buffer[t+3..];
|
||||
parse_content();
|
||||
} else {
|
||||
}
|
||||
}
|
||||
|
||||
// respond to the first empty packet
|
||||
void first_response() {
|
||||
P0(("parser::first_response called. overload this!"))
|
||||
}
|
||||
|
||||
// parser stepping function
|
||||
void step() {
|
||||
if (!strlen(buffer))
|
||||
return;
|
||||
switch(state) {
|
||||
case PSYCPARSE_STATE_HEADER:
|
||||
parse_header();
|
||||
break;
|
||||
case PSYCPARSE_STATE_CONTENT:
|
||||
buffer_content();
|
||||
break;
|
||||
case PSYCPARSE_STATE_BLOCKED:
|
||||
// someone requested to stop parsing - e.g. _request_features circuit
|
||||
// message
|
||||
break;
|
||||
case PSYCPARSE_STATE_GREET: // wait for greeting
|
||||
if (strlen(buffer) < 2)
|
||||
return;
|
||||
if (buffer[0..1] == DELIM) {
|
||||
state = PSYCPARSE_STATE_HEADER;
|
||||
buffer = buffer[2..];
|
||||
first_response();
|
||||
step();
|
||||
} else {
|
||||
croak("_error_syntax_initialization",
|
||||
"The protocol begins with a pipe and a line feed.");
|
||||
}
|
||||
break;
|
||||
default: // uhm... if we ever get here this is the programmers fault
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME should be in a standalone module
|
||||
//#define PARSEERROR(args) debug_message(sprintf("LIST PARSE ERROR: " args));
|
||||
#define LISTSEP '|'
|
||||
#define LISTPARSE_FAIL -1
|
||||
#define LISTMODE_PLAIN 0
|
||||
#define LISTMODE_BINARY 1
|
||||
// list parsing function - val is assumed to be stripped of the final LF
|
||||
mixed list_parse(string val) {
|
||||
mixed *lv = ({ });
|
||||
if (val[0] == LISTSEP)
|
||||
return explode(val[1..], "|");
|
||||
while(strlen(val)) {
|
||||
int fit, len;
|
||||
fit = sscanf(val, "%d %s", len, val);
|
||||
if (fit != 2) {
|
||||
// invalid binary fit
|
||||
return LISTPARSE_FAIL;
|
||||
}
|
||||
if (len < 0 || len > strlen(val)) {
|
||||
// invalid binary length
|
||||
return LISTPARSE_FAIL;
|
||||
}
|
||||
if (len != strlen(val) && val[len] != LISTSEP) {
|
||||
// listsep not found after binary
|
||||
return LISTPARSE_FAIL;
|
||||
}
|
||||
lv += ({ val[..len-1] });
|
||||
val = val[len+1..];
|
||||
}
|
||||
return lv;
|
||||
}
|
||||
|
||||
#ifdef SELFTESTS
|
||||
test() {
|
||||
list_parse("|psyc://example.symlynX.com/~jim|psyc://example.org/~judy");
|
||||
list_parse("5\tabcde|4\tabcd");
|
||||
}
|
||||
#endif
|
33
world/net/spyc/psyc.h
Normal file
33
world/net/spyc/psyc.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
/* this is the development directory for
|
||||
* psyc 1.0.
|
||||
*
|
||||
* the entire net/speck directory has to go
|
||||
* when net/psyc stops being 0.9 and starts
|
||||
* being 1.0.
|
||||
*
|
||||
* please try to make changes by #ifdef SPYC
|
||||
* where possible, only do a plugin replacement
|
||||
* of parse.i
|
||||
*
|
||||
* why do we need this directory? let me explain:
|
||||
* if old and new psyc are to co-exist, we need
|
||||
* differing path names for objects to assign
|
||||
* to the differing ports. even if we merge the
|
||||
* parsers and make them coexist by detecting the
|
||||
* first incoming byte, then we still need a way
|
||||
* to distinguish outgoing PSYC and SPYC.
|
||||
* also, merging the two parsers is not likely or
|
||||
* useful - they are so totally different in
|
||||
* structure - but we can exec the proper ones
|
||||
* from psyclpc or internally, after looking at
|
||||
* the first byte.
|
||||
*/
|
||||
|
||||
#define SPYC
|
||||
|
||||
#define PSYCPARSE_STATE_HEADER 0
|
||||
#define PSYCPARSE_STATE_CONTENT 1
|
||||
#define PSYCPARSE_STATE_BLOCKED 2
|
||||
#define PSYCPARSE_STATE_GREET 3
|
||||
|
||||
#include <psyc.h>
|
171
world/net/spyc/server.c
Normal file
171
world/net/spyc/server.c
Normal file
|
@ -0,0 +1,171 @@
|
|||
// vim:foldmethod=marker:syntax=lpc:noexpandtab
|
||||
// $Id: server.c,v 1.14 2008/03/11 13:42:27 lynx Exp $
|
||||
//
|
||||
// the thing that answers on port 4404 of psyced.
|
||||
|
||||
#include "psyc.h"
|
||||
#include <net.h>
|
||||
#include <services.h>
|
||||
#define NO_INHERIT
|
||||
#include <server.h>
|
||||
|
||||
// receiving variant
|
||||
inherit NET_PATH "spyc/circuit";
|
||||
|
||||
// keep a list of objects to ->disconnected() when the driver tells us
|
||||
volatile array(object) disconnect_notifies;
|
||||
|
||||
void 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; }
|
||||
|
||||
load(ho, po) {
|
||||
D0 ( if (peerport)
|
||||
PP(("%O loaded twice for %O and %O\n", ME, peerport, po)); )
|
||||
peerport = po;
|
||||
// P3(("loaded server on %O\n", peerport))
|
||||
return ME;
|
||||
}
|
||||
|
||||
protected quit() { QUIT }
|
||||
|
||||
// self-destruct when the TCP link gets lost
|
||||
disconnected(remaining) {
|
||||
int rc;
|
||||
|
||||
P2(( "%O got disconnected.\n", ME))
|
||||
// emulate disconnect() for net/psyc/user
|
||||
if (disconnect_notifies) {
|
||||
foreach (object t : disconnect_notifies)
|
||||
if (t) t->disconnected();
|
||||
}
|
||||
rc = ::disconnected(remaining);
|
||||
destruct(ME);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void resolved(mixed host, mixed tag) {
|
||||
PT(("resolved %O to %O\n", peerip, host))
|
||||
string numericpeeraddr;
|
||||
mixed uni, psycip;
|
||||
|
||||
unless (stringp(host)) {
|
||||
#if 1 //ndef 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
|
||||
// we could instead lower the trust value for this
|
||||
// host so that it can no longer send messages in
|
||||
// a federated way, but still link into an identity
|
||||
// as a client....... TODO.. like this?
|
||||
if (trustworthy < 6) trustworthy = 1;
|
||||
host = peerip;
|
||||
# else
|
||||
croak("_error_invalid_hostname",
|
||||
"Your IP address points to a hostname which doesn't point back to the IP.\n"
|
||||
"You could be trying to spoof you're in somebody else's domain.\n"
|
||||
"We can't let you do that, sorry.");
|
||||
return;
|
||||
# endif
|
||||
}
|
||||
else if (host == -1) host = peerip;
|
||||
else {
|
||||
P0(("resolved(%O) in %O. but that's impossible.\n",
|
||||
host, ME))
|
||||
croak("_failure_invalid_hostname",
|
||||
"Resolving your IP address triggered an internal error.");
|
||||
return;
|
||||
}
|
||||
#else
|
||||
// we sent them to 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
|
||||
if (trustworthy < 6) {
|
||||
if (trustworthy = legal_domain(host, peerport, "psyc", 0)) {
|
||||
if (trustworthy < 3) trustworthy = 0;
|
||||
}
|
||||
else {
|
||||
croak("_error", "Sei nicht so ein Mauerbluemchen");
|
||||
return;
|
||||
}
|
||||
}
|
||||
// the resolver does not register automatically, so here we go
|
||||
register_host(peerip, host);
|
||||
register_host(host);
|
||||
// register_target( "psyc://"+peeraddr );
|
||||
numericpeeraddr = peeraddr;
|
||||
peeraddr = peerhost = host;
|
||||
// peerport has either positive or negative value
|
||||
if (peerport && peerport != PSYC_SERVICE) peeraddr += ":"+peerport;
|
||||
netloc = "psyc://"+peeraddr+"/";
|
||||
register_target( netloc );
|
||||
#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))
|
||||
if (flags & TCP_PENDING_TIMEOUT) {
|
||||
P0(("removing call out\n"))
|
||||
remove_call_out(#'quit);
|
||||
flags -= TCP_PENDING_TIMEOUT;
|
||||
}
|
||||
resume_parse();
|
||||
sTextPath();
|
||||
|
||||
// FIXME: determine response to greeting
|
||||
// instead of this dummy
|
||||
msg(0, "_notice_features", 0, tag ? ([ "_tag_reply" : tag ]) : 0);
|
||||
}
|
||||
|
||||
|
||||
void circuit_msg(string mc, mapping vars, string data) {
|
||||
switch(mc) {
|
||||
case "_request_features": // only servers handle _request_features
|
||||
interrupt_parse();
|
||||
dns_rresolve(peerip, #'resolved, vars && vars["_tag"]);
|
||||
break;
|
||||
default:
|
||||
return ::circuit_msg(mc, vars, data);
|
||||
}
|
||||
}
|
193
world/net/spyc/udp.c
Normal file
193
world/net/spyc/udp.c
Normal file
|
@ -0,0 +1,193 @@
|
|||
// vim:foldmethod=marker:syntax=lpc:noexpandtab
|
||||
// $Id: udp.c,v 1.3 2008/02/19 16:28:41 lynx Exp $
|
||||
|
||||
#include "psyc.h"
|
||||
#include <net.h>
|
||||
#include <url.h>
|
||||
#include <text.h>
|
||||
|
||||
inherit NET_PATH "spyc/parse";
|
||||
|
||||
#define CIRCUITERROR(reason) { debug_message("PSYC CIRCUIT ERROR: " reason); \
|
||||
croak("_error_circuit", "circuit error: " \
|
||||
reason); \
|
||||
return; \
|
||||
}
|
||||
|
||||
string netloc;
|
||||
|
||||
parseUDP2(host, ip, port, msg); // prototype
|
||||
|
||||
object load() { return ME; } // avoid a find_object call in obj/master
|
||||
|
||||
parseUDP(ip, port, msg) {
|
||||
dns_rresolve(ip, #'parseUDP2, ip, port, msg);
|
||||
}
|
||||
|
||||
// respond to the first packet - or don't do it
|
||||
first_response() { }
|
||||
|
||||
parseUDP2(host, ip, port, msg) {
|
||||
// this is an atomic operation. It is never interrupted by another
|
||||
// call to parseUDP2. Or at least it is not designed to be.
|
||||
unless(stringp(host))
|
||||
host = ip; // FIXME: we reject tcp from hosts with invalid pointers
|
||||
// but not udp???
|
||||
netloc = "psyc://" + host + ":" + to_string(-port) + "/";
|
||||
P0(("parseUDP2 from %O == %O port %O\n", host, ip, port))
|
||||
parser_init();
|
||||
feed(msg);
|
||||
}
|
||||
|
||||
void done(mixed varops, mixed method, mixed body) {
|
||||
string vname;
|
||||
mixed vop; // value operation
|
||||
mapping vars = ([ ]); // udp is stateless
|
||||
string t;
|
||||
|
||||
// FIXME: ideally, those unpacks would happen after the checks
|
||||
// that get a packet rejected
|
||||
// FIXME: this allows binary lists in mmp
|
||||
foreach(vname, vop : varops) {
|
||||
// TODO unpack _amount
|
||||
// TODO unpack _time
|
||||
if (abbrev("_list", vname)) {
|
||||
mixed plist = list_parse(vop[2]);
|
||||
if (plist == -1) {
|
||||
CIRCUITERROR("could not parse list");
|
||||
}
|
||||
vop[2] = plist;
|
||||
}
|
||||
}
|
||||
// apply mmp state
|
||||
foreach(vname, vop : varops) {
|
||||
if (vop[1] == 1) // vname was encountered in psyc part
|
||||
continue;
|
||||
switch(vop[0]) {
|
||||
case C_GLYPH_MODIFIER_SET:
|
||||
vars[vname] = vop[2];
|
||||
break;
|
||||
case C_GLYPH_MODIFIER_ASSIGN:
|
||||
case C_GLYPH_MODIFIER_AUGMENT:
|
||||
case C_GLYPH_MODIFIER_DIMINISH:
|
||||
case C_GLYPH_MODIFIER_QUERY:
|
||||
CIRCUITERROR("stateful operation in udp mode")
|
||||
break;
|
||||
}
|
||||
// FIXME: not every legal varname is a mmp varname
|
||||
// look at shared_memory("routing")
|
||||
if (!legal_keyword(vname) || abbrev("_INTERNAL", vname)) {
|
||||
CIRCUITERROR("illegal varname in header")
|
||||
}
|
||||
}
|
||||
|
||||
// check _source/_context
|
||||
// this check can be skipped if _source and _context are empty
|
||||
if ((t = vars["_context"] || vars["_source"])) {
|
||||
array(mixed) u;
|
||||
unless (u = parse_uniform(t)) {
|
||||
CIRCUITERROR("logical source is not an uniform\n")
|
||||
}
|
||||
}
|
||||
// check that _target is hosted by us
|
||||
// this check can be skipped if _target is empty
|
||||
if ((t = vars["_target"])) {
|
||||
array(mixed) u;
|
||||
unless (u = parse_uniform(t)) {
|
||||
CIRCUITERROR("target is not an uniform\n")
|
||||
}
|
||||
// FIXME relaying support here?
|
||||
unless (is_localhost(u[UHost])) {
|
||||
CIRCUITERROR("target is not configured on this server\n")
|
||||
}
|
||||
}
|
||||
foreach(vname, vop : varops) {
|
||||
if (vop[1] == 0) // vname was encountered in mmp header
|
||||
continue;
|
||||
|
||||
switch(vop[0]) { // the glyph
|
||||
case C_GLYPH_MODIFIER_SET:
|
||||
vars[vname] = vop[2];
|
||||
break;
|
||||
case C_GLYPH_MODIFIER_ASSIGN:
|
||||
case C_GLYPH_MODIFIER_AUGMENT:
|
||||
case C_GLYPH_MODIFIER_DIMINISH:
|
||||
case C_GLYPH_MODIFIER_QUERY:
|
||||
CIRCUITERROR("stateful operation in udp mode")
|
||||
break;
|
||||
}
|
||||
if (!legal_keyword(vname) || abbrev("_INTERNAL", vname)) {
|
||||
CIRCUITERROR("illegal varname in psyc")
|
||||
}
|
||||
}
|
||||
PT(("vars is %O\n", vars))
|
||||
PT(("method %O\nbody %O\n", method, body))
|
||||
PT(("packet done\n"))
|
||||
// delivery rules as usual, but
|
||||
if (vars["_context"]) {
|
||||
mixed context;
|
||||
mixed source, target;
|
||||
|
||||
if (vars["_source"] && vars["_target"]) {
|
||||
P0(("invalid _context %O with _source %O, _target %O\n",
|
||||
context, vars["_source"], vars["_target"]))
|
||||
CIRCUITERROR("invalid usage of context with _source and _target");
|
||||
} else if (vars["_source"]) {
|
||||
P0(("invalid _context %O with _source %O and empty _target\n",
|
||||
context, vars["_source"]))
|
||||
CIRCUITERROR("invalid usage of context with _source");
|
||||
} else if (vars["_target"]) {
|
||||
// as we don't have psyc e2e state yet...
|
||||
P0(("unicast from context %O to target %O not implemented yet\n",
|
||||
context, vars["_target"]))
|
||||
CIRCUITERROR("unicast from context to single member not implemented yet");
|
||||
} else {
|
||||
if (vars["_source_relay"]) {
|
||||
mixed localrelay;
|
||||
if ((localrelay = psyc_object(vars["_source_relay"]))) {
|
||||
P0(("local relay %O\n", localrelay))
|
||||
vars["_source_relay"] = localrelay;
|
||||
} else { // NORMALIZE UNIFORM
|
||||
vars["_source_relay"] = lower_case(vars["_source_relay"]);
|
||||
}
|
||||
}
|
||||
context = find_context(vars["_context"]);
|
||||
if (objectp(context)) {
|
||||
// FIXME: we need lots of local object detection here
|
||||
context -> castmsg(source, method || "", body, vars);
|
||||
} else {
|
||||
// empty contexts are not bad currently
|
||||
// in the current implementation it only means that no one
|
||||
// interested in that context is online right now
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!vars["_target"] && !vars["_source"]) {
|
||||
CIRCUITERROR("circuit_msg over udp?");
|
||||
} else {
|
||||
string source;
|
||||
mixed target;
|
||||
if (!vars["_source"]) {
|
||||
source = netloc;
|
||||
} else {
|
||||
// FIXME: a macro NORMALIZE_UNIFORM that may do lower_case please
|
||||
// not a simple lower_case
|
||||
source = lower_case(vars["_source"]);
|
||||
}
|
||||
|
||||
// FIXME
|
||||
if (!vars["_target"])
|
||||
return;
|
||||
// deliver
|
||||
target = find_psyc_object(parse_uniform(vars["_target"]));
|
||||
PT(("target is %O\n", target))
|
||||
// FIXME: net/entity can not yet deal with 0 method
|
||||
if (objectp(target))
|
||||
target->msg(source, method || "", body, vars);
|
||||
else {
|
||||
P0(("target %O not found???\n", target))
|
||||
}
|
||||
}
|
||||
}
|
||||
::done(varops, method, body);
|
||||
}
|
4
world/net/spyc/user.c
Normal file
4
world/net/spyc/user.c
Normal file
|
@ -0,0 +1,4 @@
|
|||
// $Id: user.c,v 1.1 2008/01/30 17:06:48 lynx Exp $ // vim:syntax=lpc
|
||||
#include "psyc.h"
|
||||
#include "../psyc/user.c"
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue