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

34
world/net/d/bounce.c Normal file
View file

@ -0,0 +1,34 @@
// $Id: bounce.c,v 1.6 2005/03/14 13:30:46 lynx Exp $ // vim:syntax=lpc
//
// currently specific to the IRC implementation: recognize when a
// person has several clients kicking each other out automatically.
// yes, IRC client coders do implement things like these.
//
#include <net.h>
volatile mapping bounces = ([ ]);
#ifndef MAX_BOUNCES
# define MAX_BOUNCES 3
#endif
#ifndef BOUNCE_INTERVAL
# define BOUNCE_INTERVAL 60
#endif
reset() {
foreach (string nick : bounces) {
unless (bounces[nick]) m_delete(bounces, nick);
}
}
checkBounce(nick) {
string n = lower_case(nick);
if (bounces[n] < (MAX_BOUNCES + 2)) {
bounces[n]++;
call_out(lambda(({}),
({ #'--,
({ #'[, bounces, n })
})), BOUNCE_INTERVAL);
}
return (bounces[lower_case(nick)] > MAX_BOUNCES);
}

16
world/net/d/echo.c Normal file
View file

@ -0,0 +1,16 @@
// $Id: echo.c,v 1.2 2005/03/14 10:23:26 lynx Exp $ // vim:syntax=lpc
//
// just a test daemon.. load it if you want urls of $echo type to work
// you can (currently) also use /msg echo:whatever locally
// put it into init.ls
create() {
register_service("echo");
}
msg(source, mc, data, mapping vars) {
P1(("%O echoing for %O", ME, source))
sendmsg(source, "_notice_echo"+mc,
"Thanks for the "+data, vars);
}

270
world/net/d/gameserv.c Normal file
View file

@ -0,0 +1,270 @@
// $Id: gameserv.c,v 1.12 2007/09/18 08:37:57 lynx Exp $ // vim:syntax=lpc
//
// game server gateway or something. quite amazing.
// serves also as demonstration on how to use the udp library.
//
#include <net.h>
#if defined(__ERQ_MAX_SEND__) && !defined(MUD)
#include <closures.h>
inherit NET_PATH "udp";
#define P_PING 0
#define P_FRAGS 1
#define P_NAME 2
#define P_DEATHS 3
#define P_TEAM 4
protected mapping servers, alias, ut, ut_player, q3, bf_player;
void create() {
servers = ([ ]);
alias = ([ ]);
q3 = ([ "hostname" : "_name", "mapname" : "_map", "clients" : "_players", "sv_maxclients" : "_maxplayers" ]);
ut = ([ "hostname" : "_name", "mapname" : "_map", "numplayers" : "_players", "maxplayers" : "_maxplayers" ]);
ut_player = ([ "player" : P_NAME, "frags" : P_FRAGS, "ping " : P_PING ]);
bf_player = ([ "player" : P_NAME, "score" : P_FRAGS, ]);
}
/*
GSERV: player_11 => -'-=||=<Dr.ArAgOrN
GSERV: frags_11 => 56
GSERV: ping_11 => 69
GSERV: team_11 => 1
GSERV: mesh_11 => Male Soldier
GSERV: skin_11 => SoldierSkins.Gard
GSERV: face_11 => SoldierSkins.Wraith
*/
public string list_servers() {
reset();
string message = "SERVERS:\n";
foreach(string key : m_indices(servers)) {
// message += " "+key+"\t"+servers[key]+"\n";
message += sprintf("%s\t%s\n",to_string(key),servers[key]["_name"]);
}
message += "\nALIASES:\n";
foreach(string key : m_indices(alias)) {
// message += " "+key+"\t"+alias[key]+"\n";
message += sprintf("%s\t%s\n",key,alias[key]);
}
return message;
}
private closure gen_callback(string id,string type) {
return lambda(({ 'flag, 'data, 'l_port, 'ip, 'r_port }),
({ CL_IF, ({ #'==, 'flag, 1 }),
({ symbol_function("parse_"+type, ME), id, 'data, 'l_port,'ip, 'r_port }),
({ #'return })
})
);
}
parse_bf(string id, string data, int l_port, int ip, int r_port) {
D2(D(data);)
}
parse_q3a(string id, string data, int l_port, int ip, int r_port) {
array(string) temp;
int size;
temp = explode(data, "\n");
string * info = explode(temp[1], "\\");
size = sizeof(info);
for(int i = 1; i < size; i = i + 2) {
servers[id][(q3[info[i]] || info[i])] = info[i+1];
D2(D("GSERV: "+info[i]+" => "+info[i+1]+"\n");)
}
if(temp[0] == "ÿÿÿÿstatusResponse") {
int ping, frags;
string name;
foreach(string player : temp[2..]) {
if(sscanf(player,"%U %U \"%s\"",frags,ping,name) == 3) {
name = regreplace(name,"\\^[0-9]","",1);
D2(D("PLAYER: "+frags+"\t"+ping+"\t"+name+"\n");)
servers[id]["p"] += ({ ({ frags,ping,name }) });
}
}
}
if(servers[id]["_name"])
alias[servers[id]["_name"]] = id;
if(servers[id]["sv_privateClients"])
servers[id]["_maxplayers"] = to_int(servers[id]["_maxplayers"]) - to_int(servers[id]["sv_privateClients"]);
servers[id]["time"] = time();
return 1;
}
parse_ut(string id, string data, int l_port, int ip, int r_port) {
array(string) temp;
int size,num;
string key, value;
temp = explode(data, "\\")[1..];
size = sizeof(temp);
if(temp[size - 2] != "final") {
closure cb = gen_callback(id,"ut");
ticket(cb,l_port,ip,r_port);
}
for(int i = 0; i < size - 2; i = i + 2) {
if(sscanf(temp[i],"%s_%U",key,num) == 2 && ut_player[key]) {
if(sizeof(servers[id]["p"]) - 1 < num) servers[id]["p"][num] = allocate(10);
servers[id]["p"][num][ut_player[key]] = temp[i+1];
} else {
servers[id][(ut[temp[i]] || temp[i])] = temp[i+1];
D2(D("GSERV: "+temp[i]+" => "+temp[i+1]+"\n");)
}
}
if(servers[id]["_name"])
alias[servers[id]["_name"]] = id;
servers[id]["time"] = time();
return 1;
}
public void del_server(string id) {
m_delete(servers, id);
foreach(string key : m_indices(alias)) {
if(alias[key] == id)
m_delete(alias, key);
}
}
public mapping info(string id) {
if(servers[id] || servers[alias[id]]) {
D2(D("wuuusch!\n");)
return servers[id] || servers[alias[id]];
}
return ([]);
}
public mapping* players(string id) {
if(pointerp(servers[id]["p"]))
return servers[id]["p"];
return ({ });
}
public int update_server(string id) {
closure cb;
switch(lower_case(servers[id]["_type"])) {
case "q1":
case "quake1":
cb = gen_callback(id,"q1");
break;
case "qw":
case "quakew":
case "quakeworld":
cb = gen_callback(id,"qw");
break;
case "q2":
case "quake2":
cb = gen_callback(id,"q2");
break;
case "q3":
case "q3a":
case "quake3":
case "quake3arena":
cb = gen_callback(id,"q3a");
ticket(cb,"q3a", servers[id]["_host"], servers[id]["_port"]);
ticket(cb,"q3a", servers[id]["_host"], servers[id]["_port"]);
send("q3a", servers[id]["_host"], servers[id]["_port"],
to_string(({ 255,255,255,255 })) + "getinfo");
send("q3a", servers[id]["_host"], servers[id]["_port"],
to_string(({ 255,255,255,255 })) + "getstatus");
break;
case "unreal":
cb = gen_callback(id,"ut");
ticket(cb,"u", servers[id]["_host"], servers[id]["_port"]);
send("u", servers[id]["_host"], servers[id]["_port"], "\\status\\");
break;
case "ut":
case "unrealtournament":
cb = gen_callback(id,"ut");
ticket(cb,"ut", servers[id]["_host"], servers[id]["_port"] + 1);
send("ut", servers[id]["_host"], servers[id]["_port"] + 1, "\\status\\");
break;
case "ut2003":
case "unrealtournament2003":
cb = gen_callback(id,"ut2003");
ticket(cb,"ut2003", servers[id]["_host"], servers[id]["_port"] + 1);
send("ut2003", servers[id]["_host"], servers[id]["_port"] + 1, "x" + to_string(({ 0,0,0,0 })));
break;
case "bf":
case "bf1942":
cb = gen_callback(id,"bf");
ticket(cb,"bf", servers[id]["_host"], servers[id]["_port"] + 8433);
send("bf", servers[id]["_host"], servers[id]["_port"] + 8433, "\\status\\");
break;
default:
del_server(id);
break;
}
return 1;
}
public varargs int add_server(string type, string r_host, int r_port, string name) {
string id;
reset();
id = to_string(r_host + ":" + r_port);
if(name) alias[name] = id;
if(servers[id]) {
return update_server(id);
}
servers[id] = ([
"_type" : type,
"_host" : r_host,
"_port" : r_port,
"time" : time(),
"p" : ({ }),
]);
return update_server(id);
/* cb = lambda(({ 'flag, 'data, 'l_port, 'ip, 'r_port }),
({ CL_IF, ({ #'==, 'flag, 1 }),
({ symbol_function("parseGS", ME), id, 'data, 'l_port,'ip, 'r_port }),
({ #'return })
})
); */
}
load() {
reset();
register_scheme("gameserv");
return ME;
}
#else
public varargs int add_server(string type, string r_host, int r_port, string name) {
D2(D("You need an erq to use d/gameserv.c\n");)
return 0;
}
public string list_servers() {
D2(D("You need an erq to use d/gameserv.c\n");)
return "";
}
public void del_server(string id) {
D2(D("You need an erq to use d/gameserv.c\n");)
}
public mapping info(string id) {
D2(D("You need an erq to use d/gameserv.c\n");)
return ([ ]);
}
public mapping* players(string id) {
D2(D("You need an erq to use d/gameserv.c\n");)
return ([ ]);
}
public int update_server(string id) {
D2(D("You need an erq to use d/gameserv.c\n");)
return 0;
}
#endif
msg(source, mc, data, mapping vars, showingLog, target) {
D2(D("GAMESPY-D: HERE I AM!\n");)
}

177
world/net/d/hosts.c Normal file
View file

@ -0,0 +1,177 @@
// $Id: hosts.c,v 1.27 2008/03/11 13:42:25 lynx Exp $ // vim:syntax=lpc
//
// keeper of list of offensive hosts
#include <net.h>
#include CONFIG_PATH "hosts.h"
#ifdef legal_host
# undef legal_host
#endif
#ifndef DISABLED_HOSTS
# define DISABLED_HOSTS
#endif
#ifndef ENABLED_HOSTS
# define ENABLED_HOSTS
#endif
#ifdef PSYC_ENABLED_HOSTS
# define PSYC_TRUSTWORTHY_HOSTS PSYC_ENABLED_HOSTS
# define PSYC_PRIVATE
#endif
#define DATA_FILE DATA_PATH "hosts"
#define I_HOST 0
#define I_REASON 1
#define I_NEXT 2
array(string) disabled_hosts = ({ DISABLED_HOSTS });
mixed *disabled_list;
volatile array(string) enabled_hosts = ({ ENABLED_HOSTS });
volatile int loaded = 0;
#ifdef PSYC_TRUSTWORTHY_HOSTS
volatile array(string) psyc_trustworthy_hosts = ({ PSYC_TRUSTWORTHY_HOSTS });
#endif
create() { load(); }
load() {
// P1(("disabled_hosts is %O\n", disabled_hosts))
unless (loaded) {
loaded++;
restore_object(DATA_FILE);
unless (disabled_list) {
mixed *cur = disabled_list = allocate(3);
foreach (string host : disabled_hosts) {
cur = cur[I_NEXT] = allocate(3);
cur[I_HOST] = host;
// easier to read. no info where there is no info.
cur[I_REASON] = ""; // "Old block, no reason given.";
}
disabled_hosts = 0;
}
}
return ME;
}
legal_host(host, port, scheme, udp) {
int i, k, l;
mixed *cur = disabled_list;
if (udp) udp = 3; // UDP is spoofable, see net/psyc/udp.c
l = strlen(host);
P3(("legal_host(%O,%O,%O,%O) called\n", host, port, scheme, udp))
#ifdef PSYC_TRUSTWORTHY_HOSTS
if (scheme == "psyc") {
for (i=sizeof(psyc_trustworthy_hosts)-1; i>=0; i--) {
k = strlen(psyc_trustworthy_hosts[i]) - 1;
P3(("trustworthy_host(%O): %O,%O,%O,%O,%O\n",
host, i, k, l, psyc_trustworthy_hosts[i], host[0..k]))
if (k < l && host[0..k] == psyc_trustworthy_hosts[i])
return 9 - udp;
}
# ifdef PSYC_PRIVATE
return 0;
# endif
}
#endif
while (cur = cur[I_NEXT]) {
k = strlen(cur[I_HOST]) - 1;
P3(("disabled_host(%O): %O,%O,%O,%O,%O\n",
host, cur, k, l, cur[I_HOST], host[0..k]))
#if 1
// #define DIABLED_HOSTS "" blocks everyone.. imho this is not
// expected behaviour
if (k != -1 && k < l && host[0..k] == cur[I_HOST]) return 0;
#else // ungetestet.. wäre aber genauer
if (k < l && host[0..k] == cur[I_HOST]) {
if (host == cur[I_HOST]) return 0;
if (host[k] == '.') return 0;
}
#endif
}
if (enabled_hosts && sizeof(enabled_hosts)) {
for (i=sizeof(enabled_hosts)-1; i>=0; i--) {
k = strlen(enabled_hosts[i]) - 1;
P4(("enabled_host(%O): %O,%O,%O,%O,%O\n",
host, i, k, l, enabled_hosts[i], host[0..k]))
if (k != -1 && k < l && host[0..k] == enabled_hosts[i])
return 7 - udp;
}
// why should activated ENABLED_HOSTS exclude everyone else??
//
// return 0;
}
return 5 - udp;
}
list() {
mapping show = ([ ]);
mixed *cur = disabled_list;
if (enabled_hosts && sizeof(enabled_hosts)) {
previous_object()->pr("_list_hosts_enabled_amount", // _tab
"Access permitted from %d IP nets\n", sizeof(enabled_hosts));
previous_object()->pr("_list_hosts_enabled", // _tab
"Enabled IP nets: %O\n", enabled_hosts);
}
/*
int i;
string l;
for (i=sizeof(disabled_hosts)-1; i>=0; i--) {
if (l) l += ", \""+ disabled_hosts[i] +"\"";
else l = "\""+ disabled_hosts[i] +"\"";
}
unless (l) l = "none.";
*/
while (cur = cur[I_NEXT])
show[cur[I_HOST]] = cur[I_REASON];
previous_object()->pr("_list_hosts_disabled", // _tab
"Blocked IP nets: %O\n", show);
// "Blocked IP nets: %-*#s\n", implode(disabled_hosts, "\n")
#ifdef PSYC_TRUSTWORTHY_HOSTS
previous_object()->pr("_list_hosts_trustworthy_psyc", // _tab
"PSYC-trustworthy nets: %O\n", psyc_trustworthy_hosts);
#endif
}
modify(match, reason) {
int i;
mixed *pre, *cur = disabled_list;
//for (i=sizeof(disabled_hosts)-1; i>=0; i--) {
while ((pre = cur) && cur = cur[I_NEXT]) {
if (cur[I_HOST] == match) {
pre[I_NEXT] = cur[I_NEXT];
#ifdef SAVE_FORMAT
save_object(DATA_FILE, SAVE_FORMAT);
#else
save_object(DATA_FILE);
#endif
log_file("BLOCK", "[%s] %O unblocked by %O\n",
ctime(), match, previous_object());
monitor_report("_notice_block_off",
match+" unblocked by "+
object_name(previous_object()));
return -1;
}
}
unless (reason) return -2;
disabled_list[I_NEXT] = ({ match, reason, disabled_list[I_NEXT] });
#ifdef SAVE_FORMAT
save_object(DATA_FILE, SAVE_FORMAT);
#else
save_object(DATA_FILE);
#endif
log_file("BLOCK", "[%s] %O blocked by %O\n",
ctime(), match, previous_object());
monitor_report("_notice_block_on",
match+" blocked by "+object_name(previous_object()));
return 1;
}

32
world/net/d/mysql.c Normal file
View file

@ -0,0 +1,32 @@
#include <net.h>
/*
* from ldmud's concepts/mysql:
* As mySQL "limits" the number of connections to 100 and as every
* connection to the mySQL-server takes time, you should use
* database serverobjects in your MUD which constantly keep the
* connection to the mySQL-server.
*
* hence we use this instead of letting each object have it's own connection
*/
volatile int handle;
create() {
#if defined(STORAGE_MYSQL)
handle = db_connect(STORAGE_MYSQL_DATABASE, STORAGE_MYSQL_USER, STORAGE_MYSQL_PASSWORD);
#endif
}
mixed query(string q, varargs mixed args) {
// TODO: it might be wise to db_conv_string on each arg to
// avoid sql injections
int res;
mixed row;
mixed *data = ({ });
res = db_exec(handle, sprintf(q, args...));
unless(res) return ({ });
while(row = db_fetch(handle))
data += ({ row });
return data;
}

23
world/net/d/pgsql.c Normal file
View file

@ -0,0 +1,23 @@
#include <net.h>
/*
* using one database connection is sufficient
*
* WARNING
* ONLY USE THIS IF YOUR DRIVER HAS THE SYNC PG PACKAGE
* (otherwise you dont have the pg_connect_sync and pg_query_sync efuns ;-)
*/
create() {
int ret;
#if defined(STORAGE_PGSQL)
ret = pg_connect_sync(STORAGE_PGSQL_CONNECT);
PT(("ret %d\n", ret))
#endif
}
mixed query(string q, varargs mixed args) {
// TODO: it might be wise to db_conv_string on each arg to
// avoid sql injections
return pg_query_sync(sprintf(q, args...));
}

700
world/net/d/psyc.c Normal file
View file

@ -0,0 +1,700 @@
// vim:foldmethod=marker:syntax=lpc:noexpandtab
// this whole file is a mistake... and not in use...
#ifdef FORK // {{{
#include <net.h>
#include <url.h>
#include <services.h>
inherit NET_PATH "state";
inherit NET_PATH "queue2";
#include "../psyc/edit.i"
string psycName() { return ""; }
varargs mixed find_psyc_object(string t, object connection, array(mixed) u) {
string r, svc, user;
object o;
PT((">> t: %O\n", t))
unless (strlen(t) && u = (u || parse_uniform(t))) return 0;
//unless (u[UScheme] && u[UScheme] == "psyc") {
unless (u[UScheme] && strlen(u[UScheme])) {
if (connection)
connection -> w("_failure_unsupported_target_relative",
"No support for relative targets yet.");
return 0;
//QUIT
}
unless (u[UHost] && strlen(u[UHost])) {
if (connection)
connection -> w("_failure_unsupported_notation_location",
"No support for fancy UNLs yet.");
return 0;
//QUIT
}
// TODO: croak if host:port isnt us?
// or implement proxy service?
// do any checking for gateway schemes?
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 (r[<1] == '/') r = r[..<2];
#endif
if (strlen(r)) switch(r[0]) {
case '^':
case '~':
if (user) {
if (connection)
connection -> w("_error_invalid_uniform_user_duplicate",
"Two users in uniform not allowed here.");
// QUIT
return 0;
}
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) {
if (connection)
connection -> w("_failure_unavailable_service",
"No service '[_service]' available here.", ([ "_service" : svc ]) );
return 0;
}
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());
// fall thru
default:
o = find_object(r);
D2( if(!o)
D("OBJECT NOT FOUND: "+ r +"\n"); )
}
else unless (user) return 0;
if (user && !objectp(o)) {
o = summon_person(user);
// o = find_person(user);
// unless(o) o = createUser(user);
}
}
return o;
}
// new psyc-parser to fit the needs ot the new api. operates on _one_ string
// containing _one_ paket (everything after the mc is considered the data)
//
// returns the mc, psyc-data remains in the buffer.
#define ERROR(x) { monitor_report("_error_broken_syntax", x+((connection) ? sprintf(" from %O.", connection) : ".")); return 0; }
//#define ERROR(x) { monitor_report("_error_broken_syntax", x); return 0; }
static string spsyc_parse(string buf, mapping vars, int iscontext, string source,
object connection, object o) {
string mod, var, val, mc, line, lastmod, lastvar;
mixed lastval;
int a = 0, b;
while (a < strlen(buf) && !mc && ((b = strstr(buf, "\n", a)) != -1
|| b = strlen(buf))) {
val = "";
line = buf[a..b-1];
switch(buf[a]) {
case ':':
case '=':
case '+':
case '-':
unless (sscanf(line, "%1.1s%s%t%s", mod, var, val)
|| sscanf(line, "%1.1s%s", mod, var)) {
if (connection)
connection -> w("_error_broken_syntax",
"You are in league with Ratzinger,\
the evil lord or broken psyc.");
// <lynX> runtime error erzeugen!?? wie kommt ihr darauf
// das sei eine gute idee? damit man nen grund hat große
// teure catches zu machen? ich will in meinen logs nur
// runtime fehler von bugs - ist schon schlimm genug das
// schrottige http-zugriffe sowas auslösen, aber logs
// voller fehler von buggy psyc implementationen, nein!
// man sagt der gegenseite dass was faul ist, killt evtl
// die verbindung falls der fehler nicht recoverbar ist,
// reported oder loggt das problem, aber dann is gut!
ERROR(S("PSYC parsing failed in '%s'", line))
}
unless (sizeof(var)) {
if (mod == "-") {
if (connection)
connection -> w("_error_broken_syntax",
"Diminishing of lists is not supported.");
ERROR("PSYC parsing failed (Invalid list diminish)")
} else unless (lastvar) {
if (connection)
connection -> w("_error_broken_syntax",
"Wrong list continuation.");
ERROR("PSYC parsing failed (Invalid list continuation)")
} else unless (lastmod == mod) {
if (connection)
connection -> w("_error_broken_syntax",
"Inconsistent list continuation. Do not mix modifiers.");
ERROR("PSYC parsing failed (Invalid list continuation)")
}
if (pointerp(lastval)) {
lastval += ({ val });
} else {
lastval = ({ lastval, val });
}
a = b+1;
continue;
}
break;
case '\t':
unless (lastvar) {
if (connection)
connection -> w("_error_broken_syntax",
"Continuation without variable.");
ERROR("PSYC parsing failed (Invalid variable continuation)")
}
if (pointerp(lastval))
lastval[<1] += "\n"+line[1..];
else lastval += "\n"+line[1..];
a = b+1;
continue;
case '_':
int i;
for (i = b - a - 1; i>=0; i--) {
unless (line[i] == '_' ||
(line[i] >= 'a' && line[i] <= 'z') ||
(line[i] >= '0' && line[i] <= '9') ||
(line[i] >= 'A' && line[i] <= 'Z')) {
if (connection)
connection -> w("_error_illegal_method",
"[_method] is not a valid method name.",
([ "_method" : line ]));
ERROR("PSYC parsing failed (Invalid method '"
+ line +"')\n")
}
}
mc = line;
switch(mc) {
case "_conversation": // we will soon have to decide its
case "_converse": // final name...
case "_talk":
mc = "_message";
break;
default:
if (abbrev("_conversation", mc)) {
mc[..12] = "_message";
} else if (abbrev("_converse", mc)) {
mc[..8] = "_message";
} else if (abbrev("_talk", mc)) {
mc[..4] = "_message";
}
}
break;
default:
if (connection)
connection -> w("_error_broken_syntax",
"Unsupported modifier '[_modifier]'",
([ "_modifier" : line[0] ]));
ERROR("PSYC parsing failed (Unknown modifier '"
+ line[0] + "')")
}
if (lastmod) switch(lastmod[0]) {
case '=':
if (o)
o -> Assign(source, lastvar, lastval, iscontext);
case ':':
vars[lastvar] = lastval;
break;
case '+':
if (o)
o -> Augment(source, lastvar, lastval, iscontext);
break;
case '-':
if (o)
o -> Diminish(source, lastvar, lastval, iscontext);
break;
}
lastmod = mod;
lastvar = var;
lastval = val;
a = b+1;
}
unless (mc) {
// malformed psyc-packet in buf. get on it!
if (connection)
connection -> w("_error_broken_syntax",
"Received packet without method.");
ERROR("PSYC parsing failed (Method missing)")
}
if (strlen(buf) == b) { // no data. packet ends with mc
buf = "";
} else {
// still data in buf. buf[b] is the last \n before the psyc-data
buf = buf[b+1..];
}
return mc;
}
// not exactly beautiful to have it here, but still more efficient than
// having hordes of if (psycd) checks..
int deliver(mixed ip, string peerip, object connection, string peeraddr,
string host, string data, mapping mvars) {
string psycaddr;
PT(("deliver(%O, %O, %O, %O)\n", ip, host, data, mvars))
mixed o, target = mvars["_target"];
int trustworthy = (member(mvars, "_INTERNAL_trust"))
? to_int(mvars["_INTERNAL_trust"])
: 0;
if (ip == -1) {
monitor_report("_error_something_because_somebody_was_once_again_too_lazy_to_look_up_a_method_which_most_likely_already_exists_in_library_dns_c", S("%O could not resolve %O.",
ME, host));
if (objectp(connection))
connection->w("_error_invalid_host", "Could not resolve [_host].",
([ "_host": host ]));
return 1;
}
if (ip && ip != peerip) {
monitor_report("_warning_rejected_relay_incoming",
"Dropped a packet from "+ peerip +
" trying to relay for "+ host);
P0(("Dropped a packet from "+ peerip +
" trying to relay for "+ host +"\n"+
" in parse:deliver(%O, %O, %O, %O)\n",
ip, host, data, mvars))
if (connection)
connection->w("_error_rejected_relay_incoming",
"You are not allowed to relay for [_host].",
([ "_host": host ]));
return 1;
} else if (psycaddr = mvars["_context"] || mvars["_source"]) {
// schmorp??
if (connection)
// is psycaddr already lc?
register_target(lower_case(psycaddr), connection);
} else psycaddr = "psyc://"+peeraddr;
if (member(mvars, "_source_identification")) {
mixed t = lookup_identification(psycaddr,
mvars["_source_identification"]);
unless (t) {
// the i: is a safety measure in case of a supergau
// that mvars["_source_identification"] could somehow resemble
// some other queue in the system.. not convinced..
// see also two more occurences in this file.
//
string n = "i:"+mvars["_source_identification"]+psycaddr;
unless (qExists(n)) qInit(n, 100, 5);
enqueue(n, ({ ip, peerip, connection, peeraddr, host, data,
mvars }));
return 0;
} else if (t == mvars["_source_identification"]) {
// TODO: increase trustworthy ness
mvars["_source_technical"] = psycaddr;
mvars["_source"] = mvars["_source_identification"];
m_delete(mvars, "_source_identification");
} else {
PT(("someone (%O) claims an identification (%O) though he is "
"already"
" registered as someone else. Will we allow multiple"
" identifications per unl? Should - in theory - be possible"
" and okay. dropping this message.\n",
psycaddr, mvars["_source_identification"]))
return 0;
}
}
{
string state, err, mc;
mixed source, t;
mixed *u;
int iscontext = 0; // if we are in context-state
mapping psycvars = ([ "_INTERNAL_origin" : connection ]);
// this is our new context-routing without target.
// 1 _source
// 2 _target
// 4 _context
switch(
(member(mvars, "_source") ? 1 : 0) |
(member(mvars, "_target") ? 2 : 0) |
(member(mvars, "_context") ? 4 : 0)
) {
case 5:
# if DEBUG > 0
PT(("Received both context(%s) and source(%s) from %O\n",
mvars["_context"], mvars["_source"], psycaddr))
# endif
case 4:
t = mvars["_context"];
state = t;
iscontext = 1;
o = find_context(t);
unless (o) {
// no one is interested / online
// is this an abuse or a feature?
// fippo: feature, context may be 0
// if no one who is normally listening is online
PT(("Dropped messages from %s because there was no\
context slave for %s.\n",
psycaddr, mvars["_context"]))
return 1;
}
break;
case 6: // this is unicast from context to target in the context's
// state
state = mvars["_context"];
iscontext = 1;
case 3:
// "Link to [_source] established.. uses this
// and place/slave too (although improperly)
//m_delete(mvars, "_source");
unless (iscontext) {
source = lower_case(mvars["_source"]);
state = source;
}
case 2:
t = mvars["_target"];
// this is a message from the rootobj but since its target is
// not our rootmsg we need to offer some kind of source.
// TODO: Why not use ME here ??
unless (source)
source = psycaddr;
if (trustworthy > 7) {
P2(("%O relaying permitted for %O to %O via %O\n",
ME, source, t, o))
// We should do mmp-routing here.. but find out before if
// there is any connections registered for that target/host
}
u = parse_uniform(t);
if (u && (u[UResource] == "" || !u[UResource])) {
// rootMSG. that parse_uniform makes me quite unhappy.
// we may check the string t only for the existance of a
// resource since we allready know that it is a valid url.
// TODO
} else unless (o = psyc_object(t) || find_psyc_object(t)) {
PT(("Found no recipent for %O. Dropping message.\n", t))
return 1;
}
break;
case 1:
// this is a message to our rootmsg from someone
source = lower_case(mvars["_source"]);
break;
case 0:
// going to our rootmsg from hell
source = psycaddr;
break;
default:
PT(("Unimplemented routing-scheme (_source, _target and _context are all present)\n"))
return 1;
}
// can this safely move into one of the ifs above? TODO
if (t = mvars["_source_relay"]) {
if (t = psyc_object(t)) {
P2(("local _source_relay %O from %O, cont %O\n",
t, source, mvars["_context"]))
mvars["_source_relay"] = t;
}
}
unless (mc = spsyc_parse(&data, psycvars, iscontext, state,
connection, o)) {
if (connection)
destruct(connection);
return 1;
}
# ifdef PSYC_TCP
P2(("TCP[%s] => %O: %s\n", peeraddr, o || t, mc))
# else
PT(("UDP[%s] => %O: %s\n", peeraddr, o || t, mc))
# endif
# ifndef GOOD_IDEA
// why do we parse for auth mcs here if we already do it
// in common::rootMsg? if this should be here instead,
// you can make these checks a bit more efficient if
// you first ensure that the target of this message is
// the server root. it's also nicer to the users that
// you're not looking at their messages here.. ;)
//
if (mc == "_error_invalid_authentication") {
string n;
unless (member(mvars, "_source") &&
member(psycvars, "_location")) {
PT(("got _error_invalid_authentication without proper"
"vars.\n"))
return 0;
}
n = "i:"+mvars["_source"]+psycvars["_location"];
unless (qExists(n)) {
PT(("got _error_invalid_authentication for something we "
"never requested.\n"))
return 0;
}
sendmsg(psycvars["_location"], "_error_invalid_source_identification",
"Your identification [_location] seems to be bogus. "
"Du kommst hier ned rein!\n",
([ "_location" : mvars["_source"]]));
qDel(n);
return 1;
} else if (mc == "_notice_authentication") {
string n;
unless (member(mvars, "_source") &&
member(psycvars, "_location")) {
PT(("got _notice_authentication without proper"
"vars.\n"))
return 0;
}
n = "i:"+mvars["_source"]+psycvars["_location"];
unless (qExists(n)) {
PT(("got _notice_authentication for something we "
"never requested.\n"))
return 0;
}
register_location(psycvars["_location"], mvars["_source"]);
while (qSize(n))
apply(#'deliver, shift(n));
return 1;
}
# endif
// we could put these mmp-vars into cvars only to avoid this loop
foreach (string key : mvars) {
if (mergeRoutingVar(key))
psycvars[key] = mvars[key];
}
PT(("deliver ending with target: %O and mc: %O\n", o, mc))
if (objectp(o))
o -> msg(source, mc, (data == "" ? 0 : data), psycvars, 0,
source);
else if (connection) {
// per-connection "server root" which actually handles
// connection feature negotiation
connection -> rootMsg(source, mc, data == "" ? 0 : data,
psycvars, source);
}
return 1;
}
}
/*
* wrong order of arguments.. elsaga: how did this ever work!?
int msg(mixed target, string mc, mixed data, mapping vars,
mixed source, mixed target2) {
*/
int msg(mixed source, string mc, mixed data, mapping vars,
mixed showingLog, mixed target) {
string sname;
int port;
string user, host, obj;
string buf, room;
object o;
mixed t;
array(mixed) u = parse_uniform(target);
unless (u[UHost]) {
sendmsg(source, "_failure_unsupported_notation_location",
"PSYC server-independent uniform network "
"identificators not implemented yet.", 0, 0);
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 = psyc_name(source);
// host = lower_case(u[UHostPort]);
// unless (u[URoot]) u[URoot] = "psyc://"+host;
// TODO: no need for vars
unless (mappingp(vars)) vars = ([ ]);
P3(("looking for %O(%O) in %O..\n", target, u[UHostPort], targets))
// if (member(targets, t2 = u[URoot])) {
// t = targets[t2];
// if (t) {
unless (port = u[UPort]) port = PSYC_SERVICE;
else if (port < 0) {
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
return 0;
}
host = lower_case(u[UHost]);
user = u[UUser];
obj = u[UResource];
// was: obj = u[UResource];
// but probably caused the erratic rootMsg() events
//obj = u[UUser] ? "~" + u[UUser] : u[UResource];
//
// if (host == SERVER_HOST) host = "127.0.0.1";
#if 1
//
// at this point i should be able to recognize targets which are my own!
// net/gateway/aim would use that.. TODO
//
// see also legal_domain and legal_host
if (query_udp_port() == port && (host == "127.0.0.1"
|| host == "127.1"
#ifdef __HOST_IP_NUMBER__
|| host == __HOST_IP_NUMBER__
#else
|| host == myIP
#endif
// || host == SERVER_HOST
// || lower_case(host) == myLowerCaseHost
|| host == my_lower_case_host() || host == "localhost")) {
if (stringp(obj)) {
if (obj[<1] == '/') obj = obj[..<2];
if (strlen(obj)) switch(obj[0]) {
case '^':
case '~':
unless(user) user = obj[1..];
break;
case '$':
// no services available yet
// but here's the support for them
obj[0..0] = "/service/";
break;
case '@':
// t[0..0] = PLACE_PATH;
obj = PLACE_PATH + lower_case(obj[1..]);
if (o = find_object(obj)) break;
// should check for legal name instead
// of catch. TODO
catch(obj -> load());
// fall thru
default:
o = find_object(obj);
D2( if(!o) D(S("OBJECT NOT FOUND: %O\n", t)); )
} else unless(user) {
// rootMsg(source, mc,
// buffer == "" ? 0 : buffer, cvars);
return 0;
}
}
// user@ is ignored if /@ or /~ is given..
if (user && !objectp(o)) {
o = summon_person(user); //, PSYC_PATH "user");
//o = find_person(user);
//unless(o) o = createUser(user);
}
// cache the resulting object for the url
register_target(lower_case(target), o);
return sendmsg(o, mc, data, vars, source);
// or deliver directly?
}
#endif
// 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
unless (u[UTransport] == "d" || abbrev("_notice", mc)) {
#endif
dns_resolve(host, (:
object o;
string addr = $1;
string hopo = $2;
string psycaddr = "psyc://"+ addr;
// if ($3 && $3 != PSYC_SERVICE) {
if ($9) {
hopo += ":"+$9;
addr += ":"+$9;
}
unless (o = find_target_handler(psycaddr)) {
o = ("psyc:"+hopo) -> circuit($2, $3, 0, "psyc", 0,
system_queue());
}
register_target($4, o);
register_target("psyc://"+hopo, o);
register_target(psycaddr, o);
P2(("delivering %O(%O) over %O\n", hopo, $1, o))
// 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
:),
host, port, target, sname, mc, data, vars, u[UPort]
);
return 1;
#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
if (objectp(source)) buf = make_psyc(mc, data, vars, source);
else buf = make_psyc(mc, data, vars);
buf = make_mmp(buf, vars);
if (host == "localhost") return send_udp(host, port, buf);
P3(("send_udp %O:%O packet:\n%O", host,port,buf))
dns_resolve(host, (: if ($2 < 0) {
send_udp($1, $2, $3);
}
return; :), port, buf);
return 1;
#endif /* _flag_enable_routing_UDP */
}
object load() {
return ME;
}
int outstate() {
return 1;
}
mapping state() {
return ([]);
}
void create() {
qCreate();
}
#endif // }}}

25
world/net/d/sqlite.c Normal file
View file

@ -0,0 +1,25 @@
#include <net.h>
#ifdef STORAGE_SQLITE
# ifndef SQLITE_DB_PERSON
# define SQLITE_DB_PERSON DATA_PATH "person-sqlite"
# endif
#endif
/*
* TODO: actually, this may need be a wrapper, as every object is only allowed
* a single sqlite db
*/
create() {
#if defined(STORAGE_SQLITE)
sl_open(SQLITE_DB_PERSON);
#endif
}
mixed query(string q, varargs mixed args) {
// TODO: it might be wise to db_conv_string on each arg to
// avoid sql injections
return sl_exec(sprintf(q, args...));
}

481
world/net/d/udp.c Normal file
View file

@ -0,0 +1,481 @@
// $Id: udp.c,v 1.15 2008/03/29 20:05:32 lynx Exp $ // vim:syntax=lpc
//
// interface to the erq (external request daemon) to handle
// multi-protocol UDP, since the driver only has one port
// which we use for native PSYC. okay fippo also uses it for SIP,
// but i'm not sure if that's going to stay that way.
#include <net.h>
#ifdef __ERQ_MAX_SEND__
#include <erq.h>
#include <errno.h>
#include <closures.h>
//#include NET_PATH "queue.c"
inherit NET_PATH "queue";
volatile private mapping udp_ports, alias;
#endif
// port || alias -> data
// port -> alias
public varargs int ticket(closure callback, int localport, string remotehost, int remoteport);
public int send(int localport, string host, int remoteport, string data);
private void sendUDP(int localport);
public varargs mixed listenPort(int port, mixed param, varargs mixed * args);
public int closePort(mixed port);
void process_erq(int port, string type, int * response_data, int len);
public void getRPort(int port);
public varargs mixed listPorts(int m);
private void reset();
#ifdef __ERQ_MAX_SEND__
#define TICKETS_MAX 100 // maximum size of the tickets array
#define TICKETS_PRE 50 // size to allocate
#define QUEUE_MAX 100
#define QUEUE_PRE 50
// sockets states
#define S_WAITING -1
#define S_ERROR 0
#define S_OK 1
#define S_BLOCKED 2
#define S_SENDING 3
#define S_CLOSED 4
// send-queue packet-array
#define P_LOCALPORT 0
#define P_REMOTEHOST 1
#define P_REMOTEPORT 2
#define P_DATA 3
// socket-array
#define STATE 0
#define TICKET 1
#define CALLBACK 2
#define PORT 3
//load() { return ME; }
/*
public void reset(int a) {
if(!mappingp(udp_ports)) udp_ports = ([ ]);
if(!mappingp(alias)) alias = ([ ]);
::reset(a);
}
*/
public varargs mixed listPorts(int m) {
string message, port;
mapping states;
reset();
states = ([ -1 : "S_WAITING", 0 : "S_ERROR", 1 : "S_OK",
2 : "S_BLOCKED", 3 : "S_SENDING", 4 : "S_CLOSED" ]);
if (m) {
mixed value, ports;
ports = ([ ]);
foreach (port, value : udp_ports) {
ports += ([ port : ([ "_port" : port,
"_state" : states[value[STATE]],
"_callback" : to_string(value[CALLBACK])
]) ]);
}
return ports;
}
message = "===================\n\tPORT\tSTATE\tCALLBACK\n";
foreach(port : m_indices(udp_ports)) {
message += "\t"+port+"\t"+states[udp_ports[port][STATE]]+"\t"
+to_string(udp_ports[port][CALLBACK])+"\n";
}
return message;
}
public varargs int ticket(closure callback, mixed localport, string remotehost, int remoteport) {
mixed key;
reset();
unless(udp_ports[to_string(localport)]) {
if(!alias[to_string(localport)]) {
if(stringp(localport)) {
unless (listenPort(0,localport,callback))
return 0;
} else {
unless (listenPort(localport,callback))
return 0;
}
} else {
localport = alias[to_string(localport)];
}
}
localport = to_string(localport);
if(remotehost && sscanf(remotehost,"%~D.%~D.%~D.%~D") != 4) {
closure c = lambda(
({ 'name }),
({
CL_IF, 'name,
({ (#'funcall), #'ticket,
callback, localport, 'name,
remoteport
})
}));
dns_resolve(remotehost, c);
return 1;
}
if(remoteport) {
key = localport + ":" + remotehost + ":" + remoteport;
} else if(remotehost) {
key = localport + ":" + remotehost;
} else {
key = localport;
}
unless(qExists( key )) {
qInit(key, TICKETS_MAX, TICKETS_PRE);
}
enqueue(key, callback);
return 1;
}
public int send(mixed localport, string remotehost, int remoteport, string data) {
unless(udp_ports[to_string(localport)]) {
if(!alias[to_string(localport)]) {
if(stringp(localport)) {
unless (listenPort(0,localport))
return 0;
} else {
unless (listenPort(localport))
return 0;
}
} else {
localport = alias[to_string(localport)];
}
}
localport = to_string(localport);
if(remotehost && sscanf(remotehost,"%~D.%~D.%~D.%~D") != 4) {
closure c = lambda(
({ 'name }),
({
CL_IF, 'name,
({ (#'funcall), #'send,
localport, 'name,
remoteport, data
})
}) );
dns_resolve(remotehost, c);
return 1;
}
if(udp_ports[localport][STATE] != S_BLOCKED) {
if(!enqueue(":" + localport,({
localport,remotehost,remoteport,
to_array(data)[0..strlen(data)-1],
}) )) return 0;
sendUDP(localport);
return 1;
}
return 0;
}
private void sendUDP(mixed localport) {
string packet;
mixed data;
int * ip;
unless(udp_ports[localport]) return 0;
switch(udp_ports[localport][STATE]) {
case S_OK:
if(!qSize( ":" + localport ))
return;
data = shift( ":" + localport );
ip = map(explode(data[P_REMOTEHOST],"."),#'to_int);
packet = udp_ports[localport][TICKET]
+ ip[0..3]
+ ({ data[P_REMOTEPORT] / 256, data[P_REMOTEPORT] & 255 })
+ data[P_DATA];
unless (send_erq(ERQ_SEND, packet,
lambda(({ 'data, 'len }),
({
#'process_erq, localport,
ERQ_SEND, 'data, 'len
})
))) {
P0(("%O failed to ERQ_SEND!\n", ME))
}
udp_ports[localport][STATE] = S_SENDING;
D2(D("============\nOutgoing UDP-packet on port "+localport
+"\nto: "+data[P_REMOTEHOST]
+":"+data[P_REMOTEPORT]+"\n============\n");)
return;
case S_ERROR:
return;
case S_WAITING:
return;
}
}
public void getRPort(int port) {
// first we will try to bind port 3645
// if that fails ++ until it works fine ,)
// then we will send a packet over the new
// unknown port which is still represented by udp_ports[0]
// to our new port 3645+n. Tada! we know our former unknown
// port. Then we just change 0 to x.
//
// and everything put into one large lambda.. .]
// -el
if (send_erq(ERQ_OPEN_UDP,({ port/256, port&255 }),
lambda(({ 'data, 'len }),
({ (#',),
({ (#'=),'data,({ (#'map),'data,#'&,255 }) }),
({ #'switch, ({ CL_INDEX, 'data, 0 }),
({ ERQ_OK }),
({ (#',),
({ #'send,0,"127.0.0.1",port,"PORT" }),
({ (#'=), ({ CL_INDEX, ({ CL_INDEX, udp_ports, port }), TICKET }), ({ CL_L_RANGE, 'data, 1 }) }),
({ (#'=), ({ CL_INDEX, ({ CL_INDEX, udp_ports, port }), STATE }), S_OK }),
}),
(#'break),
({ ERQ_E_UNKNOWN }),
({ CL_IF, ({ #'==,({ CL_INDEX, 'data, 1}), 98 }),
({ #'getRPort, port+1 }),
({ (#'return),0 }),
}),
(#'break),
({ ERQ_STDOUT }),
({ (#',),
({ (#'=),'r_host,({ (#'sprintf),"%d.%d.%d.%d", ({ CL_INDEX, 'data, 1 }), ({ CL_INDEX, 'data, 2 }), ({ CL_INDEX, 'data, 3 }), ({ CL_INDEX, 'data, 4 }) }) }),
({ CL_IF, ({ #'&&, ({ #'==,'r_host,"127.0.0.1" }),({ #'==,({ (#'to_string),({ CL_RANGE,'data,7,11 }) }),"PORT" }), }),
({ (#',),
({ (#'=),'l_port, ({ (#'+), ({ CL_INDEX,'data,6 }),({ (#'*),256,({ CL_INDEX,'data,5 }) }) }) }),
({ #'qRename,":0", ({ (#'+),":",'l_port }) }),
({ (#'=), ({ CL_INDEX, udp_ports, 'l_port }), ({ CL_INDEX, udp_ports, to_string(0) }) }),
({ (#'m_delete), udp_ports, to_string(0) }),
({ #'closePort, port}),
({ (#'=), 'callback, ({ CL_INDEX, ({ CL_INDEX, udp_ports, 'l_port }), CALLBACK }) }),
({ #'closePort, 'l_port }),
({ #'listenPort, 'l_port, 'callback }),
({ (#'funcall), 'callback, 0, 'l_port }),
}),
({ (#'return),0 })
}),
}),
(#'break),
})
}))))
{
qInit(":" + port, QUEUE_MAX, QUEUE_PRE);
udp_ports += ([ port : ({ S_WAITING,0,lambda(({ 'data, 'len }), ({ #'process_erq, port, ERQ_OPEN_UDP, 'data, 'len }) )}) ]);
} else {
P0(("%O failed to ERQ_OPEN_UDP!\n", ME))
return 0;
}
/* switch(data[0]) {
* case ERQ_OK:
* send data to that port over unknown port which is still
* represented by udp_ports[0] callback must be the 0 to x changer!
* break;
* case ERQ_E_UNKNOW:
* if(data[1] == 98) { // 98 == Adress allready in use
* bind port+1
* recall myself
* }
* break;
* case ERQ_STDOUT:
* extract port and make the movement!
* break;
* }
*/
}
public varargs mixed listenPort(int port, mixed param, varargs mixed * args) {
unless (mappingp(udp_ports))
reset();
if(qExists(":" + port) && udp_ports[to_string(port)]) return 0;
if(!port && !param) return 0;
// doesnt make any sence to bind to a
// random port without getting to know
// which it is.
mixed id;
closure callback;
if(!port && stringp(param)) {
while (udp_ports[param]) {
param = to_string(({ random(150)+1,random(150)+1 }));
}
id = param;
if(sizeof(args) && closurep(args[0])) callback = args[0];
} else {
id = to_string(port);
}
if(closurep(param)) callback = param;
D2(D("============\nlistenPort("+(port || id)
+") called!\n============\n");)
closure c = lambda(
({ 'data, 'len }),
({
#'process_erq, id,
ERQ_OPEN_UDP, 'data, 'len
})
);
if (send_erq(ERQ_OPEN_UDP,({ port/256, port&255 }),c)) {
qInit(":" + id, QUEUE_MAX, QUEUE_PRE);
udp_ports += ([ id : ({ S_WAITING,0,callback || 0 }) ]);
if(stringp(param)) return id;
return 1;
} else {
P0(("%O failed to ERQ_OPEN_UDP!\n", ME))
return 0;
}
}
public int closePort(mixed port) {
port = to_string(port);
if(!udp_ports[port] && (!alias[port] && !udp_ports[alias[port]])) return 0;
D2(D("============\nclosePort("+port+") called!\n============\n");)
send_erq(ERQ_KILL,
(udp_ports[port][TICKET] || udp_ports[alias[port]][TICKET])
+ ({0,0,0,0}),
lambda(({ 'data, 'len }),
({ #'process_erq, port,
ERQ_KILL, 'data, 'len })
));
udp_ports -= ([ port ]);
udp_ports -= ([ alias[port] ]);
alias -= ([ port ]);
qDel(":" + port);
}
void process_erq(mixed port, string type, int * response_data, int len) {
response_data = map(response_data,#'&,255);
port = to_string(port);
int remoteport;
string remotehost;
mixed callback;
switch (response_data[0]) {
// BIND and SEND
case ERQ_OK: // port bound || package sent !
switch (type) {
case ERQ_OPEN_UDP:
D2(D("============\nPORT \""+port+"\" bound for ticket: \""+to_string(response_data[1..])+"\"\n============\n");)
udp_ports[port][TICKET] = response_data[1..];
udp_ports[port][STATE] = S_OK;
if(port == "0" && udp_ports[port][CALLBACK]) {
// no alias, cb
getRPort(3654);
} else {
sendUDP( port );
}
break;
case ERQ_SEND:
udp_ports[port][STATE] = S_OK;
sendUDP( port );
break;
case ERQ_KILL:
break;
}
return;
case ERQ_E_UNKNOWN: // unknown error while binding || sending
switch(response_data[1]) {
case EADDRINUSE:
D2(D("Port "+port+" allready in use by someone else!\n");)
default:
D2(D("Unknown error while Binding or Sending!"
+to_string(response_data[1..])+"\n");)
}
return;
// BIND
case ERQ_E_NSLOTS:// The max number of child processes is exhausted.
udp_ports -= ([ port ]);
return;
case ERQ_E_ARGLENGTH: // The port number given does not consist of two bytes
return;
// SEND
case ERQ_E_TICKET: // ticket invalid!
if(!unshift(":" + port )) {
D2(D("PANIC! Mysteriously a UDP-packet got lost in the"
"queue!\n");)
}
if(!to_int(port) || to_string(to_int(port)) != port) {
listenPort(0, port );
} else {
listenPort( to_int(port), udp_ports[port][CALLBACK] || 0);
}
udp_ports -= ([ port ]);
return;
case ERQ_E_INCOMPLETE: // only a part of the message has been sent
return;
case ERQ_E_WOULDBLOCK: // erq allready has a packet in the queue..
if(!unshift( port )) {
D2(D("You are too fast, young Jedi!\n");)
}
return;
case ERQ_E_PIPE: // pipe error. <info>
return;
// INCOMING UDP
case ERQ_STDOUT: // incoming data on udp-port
remotehost = sprintf("%d.%d.%d.%d", response_data[1],
response_data[2], response_data[3],
response_data[4]);
remoteport = response_data[5] * 256 + response_data[6];
string key = qSize(port + ":" + remotehost + ":" + remoteport,
port + ":" + remotehost,
port);
if(key) {
callback = shift( key );
} else {
callback = udp_ports[port][CALLBACK];
}
D2(D("============\nIncoming UDP-packet:\n from: "+port + ":"
+ remotehost + ":" + remoteport +"\nticket: \""+ key
+ "\" callback: "+to_string(callback)+"\n============\n");)
if(closurep(callback))
funcall(callback,1,to_string(response_data[7..]), port,
remotehost, remoteport);
return;
}
}
void create() {
alias = ([ ]);
udp_ports = ([ ]);
}
load() { return ME; }
#else
public varargs int ticket(closure callback, int localport, string remotehost, int remoteport) {
D2(D("You need an erq to use d/udp.c\n");)
return 0;
}
public int send(int localport, string host, int remoteport, string data) {
D2(D("You need an erq to use d/udp.c\n");)
return 0;
}
public varargs mixed listenPort(int port, mixed param) {
D2(D("You need an erq to use d/udp.c\n");)
return 0;
}
public void getRPort(int port) {
D2(D("You need an erq to use d/udp.c\n");)
}
public varargs mixed listPorts(int m) {
D2(D("You need an erq to use d/udp.c\n");)
if (m)
return ([ ]);
return "";
}
load() {
return ME;
}
#endif
void reset() { }