#include <network.h> #include <save.h> #include <daemons.h> string my_name = "*yatmim"; string my_password = "CROATOAN"; string *ok_ips = ({}); int irn_enabled = 1; int irn_maxtry = 32; int convert_channel = 0; mapping routers = ([ "*i4" : ([ "ip" : "204.209.44.3", "port" : 8080, "password" : "STENDEC" ]), ]); static mapping chan_conv = ([ //"*i4" : ([ "dead_test" : "test" ]) ]); mapping irn_connections = ([]); mapping irn_sockets = ([]); void eventSetup(); static void write_data(int fd, mixed data); static varargs void SendList(mixed data, int fd, string type); varargs void SendWholeList(int fd,string type); static void begin_socket_handoff(int i); static int GoodPeer(int fd, mixed data){ string ip = explode(socket_address(fd)," ")[0]; trr("IRN: hit GoodPeer","yellow"); if(member_array(ip,ok_ips) == -1){ //trr("irn: bad ip"); return 0; } if(member_array(data[2], keys(routers)) == -1){ //trr("IRN: unknown peer"); return 0; } if(data[4] != my_name){ //trr("IRN: they don't know my name. I am "+my_name+". They think I am: "+identify(data[4])); return 0; } if(data[6]["client_password"] != routers[data[2]]["password"]){ //trr("IRN: wrong client password"); return 0; } if(data[6]["server_password"] != my_password){ //trr("IRN: wrong server password"); return 0; } irn_connections[data[2]]["fd"] = fd; trr("IRN: returning 1!","yellow"); return 1; } static int ValidatePeer(int fd, mixed data){ string ip = explode(socket_address(fd)," ")[0]; //trr("IRN: hit ValidatePeer","green"); if(member_array(ip,ok_ips) == -1){ //trr("IRN: bad ip"); return 0; } if(!irn_connections[data[2]]){ //trr("IRN: no such connection."); return 0; } if(member_array(data[2], keys(routers)) == -1){ //trr("IRN: unknown peer"); return 0; } foreach(mixed key, mixed val in routers){ if(routers[key]["ip"] == ip && irn_connections[key]["fd"] != -1 && irn_connections[key]["fd"] != fd ){ //trr("IRN: wrong fd I got "+fd+" but expected "+ irn_connections[key]["fd"]); return 0; } } //trr("returning 1!","green"); return 1; } static string id_mud(int fd){ string *ret = ({}); foreach(mixed element in keys(irn_connections)){ if(irn_connections[element]["fd"] == fd) ret += ({ element }); } return implode(ret,", "); } void irn_clear(){ foreach(mixed key, mixed val in irn_connections){ this_object()->close_connection(irn_connections[key]["fd"]); } foreach(mixed key, mixed val in irn_sockets){ this_object()->close_connection(key); } irn_connections = ([]); irn_sockets = ([]); foreach(string key, mixed val in routers){ if(key == my_name){ map_delete(routers, key); continue; } ok_ips += ({ routers[key]["ip"] }); if(!irn_connections[key]){ irn_connections[key] = (["blocking" : 1, "type": MUD, "fd": -1, "data" : 0 ]); } } save_object(SAVE_ROUTER); } varargs void irn_setup(int clear){ if(!irn_enabled) return; if(clear){ foreach(mixed key, mixed val in irn_connections){ this_object()->close_connection(irn_connections[key]["fd"]); } foreach(mixed key, mixed val in irn_sockets){ this_object()->close_connection(key); } irn_connections = ([]); irn_sockets = ([]); } foreach(string key, mixed val in routers){ if(key == my_name){ map_delete(routers, key); continue; } ok_ips += ({ routers[key]["ip"] }); if(!irn_connections[key]){ irn_connections[key] = (["blocking" : 1, "type": MUD, "fd": -1, "data" : 0 ]); } else { trr("sockstat on "+key+": "+identify(socket_status(irn_connections[key]["fd"])),"white"); if(socket_status(irn_connections[key]["fd"]) && socket_status(irn_connections[key]["fd"])[1] == "CLOSED") irn_connections[key]["fd"] = -1; trr("sock staus on "+key+": "+irn_connections[key]["fd"],"white"); } } foreach(string name in keys(routers)){ int tmp_fd, sockstat; if(irn_connections[name]["fd"] != -1) continue; tmp_fd = socket_create(MUD, "irn_read_callback","irn_close_callback"); if(tmp_fd < 0){ trr("irn: Couldn't create socket. errorcode: "+socket_error(tmp_fd)); return; } sockstat = socket_bind(tmp_fd, 0); //trr("socket_bind: "+sockstat); if(sockstat < 0){ trr("irn: Couldn't bind socket. errorcode: "+socket_error(sockstat)); return; } irn_connections[name]["fd"] = tmp_fd; irn_sockets[tmp_fd] = (["name" : name]); sockstat = socket_connect(irn_connections[name]["fd"], routers[name]["ip"]+" "+ routers[name]["port"], "irn_read_callback", "irn_write_callback"); //trr("socket_connect: "+sockstat); if(sockstat < 0){ trr("irn: Couldn't connect to "+name+", errorcode: "+socket_error(sockstat)); this_object()->close_connection(irn_connections[name]["fd"]); irn_connections[name]["fd"] = -1; } this_object()->Report(); begin_socket_handoff(tmp_fd); call_out( "eventSendStartup", 5, tmp_fd); } } varargs void eventSendStartup(int fd){ mixed *targets = ({}); //trr("irn: hit eventSendStartup","yellow"); if(!irn_enabled) return; //trr("irn: hit eventSendStartup","green"); if(!fd) targets = keys(irn_connections); else if(irn_sockets[fd]["name"]) targets = ({ irn_sockets[fd]["name"] }); else targets = keys(irn_connections); if(!sizeof(targets)){ call_out( "irn_setup", 5, 1 ); return; } this_object()->Report(); foreach(mixed element in targets){ trr("irn: sending statup to "+element+" on fd "+irn_connections[element]["fd"]); write_data(irn_connections[element]["fd"], ({ "irn-startup-req", 5, my_name, "foo", element, "bar", ([ "client_password" : my_password, "server_password" : routers[element]["password"] ]) }) ); } } static void irn_write_callback(int fd){ //trr("hit irn_write_callback for fd"+fd); } static void irn_close_callback(int fd){ if(!irn_enabled) return; irn_connections[id_mud(fd)]["fd"] = -1; map_delete(irn_sockets, fd); trr("I'm wanting to close "+id_mud(fd)+" on fd"+fd+" now."); call_out( "eventSendStartup", 5); } static void irn_read_callback(int fd, mixed data){ int i; string tmp=""; mapping MudList = ([]); if(!irn_enabled) return; if(this_object()->query_mudinfo()) MudList = this_object()->query_mudinfo(); else MudList = ([ "wt" : "f" ]); //trr("irn: hit irn_read_callback for fd"+fd+", "+id_mud(fd)); if(!data || !sizeof(data)){ //trr("irn: no data"); } else { if(bufferp(data)){ //trr("data buffer: "+identify(read_buffer(data))); for(i=0;i<sizeof(data);i++){ tmp += sprintf("%c",data[i]); } } else { //trr("data: "+identify(data)); } } //trr("tmp: "+tmp); //trr("mudinfo keys: "+identify(keys(MudList))); switch(data[0]){ case "irn-startup-req" : trr("IRN got a startup request on fd"+fd); if(!GoodPeer(fd, data)) return; trr("IRN startup from "+data[2]+" accepted."); irn_connections[data[2]]["fd"] = fd; //trr("irn_connections[\""+data[2]+"\"][\"fd\"]: "+irn_connections[data[2]]["fd"]); irn_sockets[fd] = ([ "name" : data[2] ]); //SendList(MudList, fd); SendWholeList(fd); trr(data[2]+" has joined IRN on socket "+fd); return; case "irn-mudlist-altered" : trr("irn: received irn-mudlist-altered"); if(!ValidatePeer(fd, data)) { trr("irn: peer failed validation."); //this_object()->close_connection(fd); //if(irn_sockets[fd]) map_delete(irn_sockets, fd); //if(irn_connections[data[2]]) map_delete(irn_connections, data[2]); return; } //trr("got new delta. sending to router."); this_object()->ReceiveList(data[7],"mudlist"); break; case "irn-mudlist-delta" : trr("irn: got mudlist delta"); if(!ValidatePeer(fd, data)) { trr("irn: peer failed validation."); //this_object()->close_connection(fd); //if(irn_sockets[fd]) map_delete(irn_sockets, fd); //if(irn_connections[data[2]]) map_delete(irn_connections, data[2]); return; } //trr("irn: got new delta. sending to router."); this_object()->ReceiveList(data[7],"mudlist"); break; case "irn-chanlist-altered" : trr("irn: received irn-chanlist-altered"); if(!ValidatePeer(fd, data)) { trr("irn: peer failed validation."); //this_object()->close_connection(fd); //if(irn_sockets[fd]) map_delete(irn_sockets, fd); //if(irn_connections[data[2]]) map_delete(irn_connections, data[2]); return; } //trr("got new delta. sending to router."); this_object()->ReceiveList(data[7],"chanlist"); break; case "irn-chanlist-delta" : trr("irn: got chanlist delta"); if(!ValidatePeer(fd, data)) { trr("irn: peer failed validation."); //this_object()->close_connection(fd); //if(irn_sockets[fd]) map_delete(irn_sockets, fd); //if(irn_connections[data[2]]) map_delete(irn_connections, data[2]); return; } //trr("irn: got new delta. sending to router."); this_object()->ReceiveList(data[7],"chanlist"); break; case "irn-data" : if(!ValidatePeer(fd, data)) { trr("irn-data: peer on fd"+fd+" failed validation."); //this_object()->close_connection(fd); //if(irn_sockets[fd]) map_delete(irn_sockets, fd); //if(irn_connections[data[2]]) map_delete(irn_connections, data[2]); return; } //trr("irn: got new data, type: "+data[0]+". sending to router."); if(convert_channel && !strsrch(data[6][0],"chan") && strsrch(data[6][0],"chan-user")){ if(chan_conv[irn_sockets[fd]["name"]]){ foreach(string key, string val in chan_conv[irn_sockets[fd]["name"]]){ //trr("data[6][6]: "+data[6][6]); data[6][6] = replace_string(data[6][6],key,val); } } } this_object()->read_callback(data[6][2],data[6]); break; default : if(!ValidatePeer(fd, data)) { //this_object()->close_connection(fd); //if(irn_sockets[fd]) map_delete(irn_sockets, fd); //if(irn_connections[data[2]]) map_delete(irn_connections, data[2]); return; } //trr("irn: got i3 data, type: "+data[1][0]+". sending to router."); this_object()->read_callback(data[6][2],data[6]); return; } } static varargs void SendList(mixed data, int fd, string type){ int *targets = ({}); mixed *outbound = ({}); mapping tmp = ([]); if(!type || !sizeof(type)) type = "irn-mudlist-delta"; if(type == "mudlist") type = "irn-mudlist-delta"; if(type == "chanlist") type = "irn-chanlist-delta"; //trr("list type: "+type); //trr("irn: trying to send list","white"); if(!irn_enabled) return; if(!mapp(data)){ //trr("irn: Tried to send a non-map. guilty stack: "+get_stack(),"cyan"); return; } //trr("1"); tmp = data; if(mapp(tmp)){ foreach(mixed key, mixed val in tmp){ if(!mapp(val)){ //trr("irn: Non mapping val. Key: "+key+". stack: "+get_stack(),"yellow"); //trr("irn: guilty stack: "+get_stack(),"cyan"); } } } //trr("2"); if(!fd) targets = keys(irn_sockets); else targets = ({ fd }); foreach(int router in targets){ //trr("3"); if(type == "irn-chanlist-delta"){ //print_long_string(find_player("cratylus"),"I'm trying to send this: "+identify(data)+" to "+router); //continue; } write_data(router, ({ type, 5, my_name, 0, irn_sockets[router]["name"], 0, time(), data }) ); } } varargs void SendWholeList(int fd, string type){ mapping tmp = ([]); if(!type || !sizeof(type)) type = "mudlist"; if(!irn_enabled) return; if(!fd) fd = 0; //trr("SendWholeList type: "+type); switch(type){ case "mudlist" : tmp = this_object()->query_mudinfo(); break; case "chanlist" : tmp = this_object()->query_chaninfo(); break; default : trr("irn SendWholeList error: bad type "+type); return; } foreach(mixed key, mixed val in tmp){ //trr("irn: Sending "+key,"white"); if(type == "mudlist") if(mapp(val)) SendList( ([ key : val ]), fd, type ); if(type == "chanlist"){ foreach(mixed key2, mixed val2 in val){ SendList( ([ key : ([ key2 : val2 ]) ]), fd, type ); } } } } static void SendMessage(mixed data){ //trr("irn: received SendMessage call","blue"); if(!irn_enabled) return; foreach(int router in keys(irn_sockets)){ if(convert_channel && !strsrch(data[0],"chan") && strsrch(data[0],"chan-user")){ if(member_array(irn_sockets[router]["name"], keys(chan_conv)) != -1){ foreach(string key, string val in chan_conv[irn_sockets[router]["name"]]){ //trr("data[6]: "+data[6]); data[6] = replace_string(data[6],val,key); //trr("data: "+identify(data)); } } } write_data(router, ({ "irn-data", 5, my_name, 0, "*", 0, data }) ); } } string Report(){ string ret = "IRN: connections: "; foreach(mixed key, mixed val in irn_connections){ if(!key) continue; ret += key+":"+irn_connections[key]["fd"]+" "; } ret += "\n"; ret += "IRN: sockets: "; foreach(mixed key, mixed val in irn_sockets){ int sstat = -1; string statmess = "DISCONNECTED"; if(irn_connections[val["name"]]){ sstat = irn_connections[val["name"]]["fd"]; if(sstat > 0 && socket_status(key)) statmess = socket_status(key)[1]; ret += key +":"+val["name"]+":"+statmess+" "; } ret += "\n"; } trr("irn: irn_connections: "+identify(irn_connections),"green"); trr("irn: irn_sockets: "+identify(irn_sockets),"cyan"); foreach(mixed element in keys(irn_sockets)){ trr("socket_status("+element+"): "+identify(socket_status(element)),"green"); } return ret; } static void begin_socket_handoff(int fd){ object rsock = find_object(RSOCKET_D); if(!irn_enabled) return; if(!rsock) rsock = load_object(RSOCKET_D); if(!rsock){ trr("IRN: Socket handoff failed. Couldn't load RSOCKET_D"); return; } socket_release(fd, rsock, "complete_socket_handoff"); }