| /* |
| * Mudlibseite des iplookup systems, mit dem aus numerischen IP Adressen |
| * der Hostname und der Ort, an dem sich der Rechner befinden berechnet wird. |
| * Ergebnisse werden gecachet. |
| * |
| * (c)2010 rumata @ morgengrauen |
| */ |
| |
| #pragma strict_types,save_types |
| #pragma no_clone,no_shadow |
| |
| // Format der ipmap: |
| // Key: numerische ip als string (ohne fuehrende nullen) |
| // Data: |
| // [ip,0] Hostname, der vom externen Server geliefert wurde. |
| // [ip,1] Locationinformation, die vom externen Server kommt. |
| // dieser sollte den Ort, oder falls es nicht besser geht, das Land |
| // im Klartext liefern. |
| // [ip,2] Zeitstempel, bei dessen erreichen der Wert geloescht werden |
| // soll. |
| // [ip,3] Status der Anfrage |
| |
| private mapping ipmap; |
| #define IPMAP_HOST 0 |
| #define IPMAP_CITY 1 |
| #define IPMAP_EXPIRE 2 |
| #define IPMAP_STATUS 3 |
| |
| // externer server, der der lokationdaten berechnet |
| #define IPLOOKUP_HOST "127.0.0.1" |
| #define IPLOOKUP_PORT 8711 |
| #define IPLOOKUP_SAVE "/p/daemon/save/iplookup" |
| |
| // moegliche statuswerte (platz zum zaehlen der anfragen gelassen) |
| #define STATUS_QUERYING 1 |
| #define STATUS_AUTHORITATIVE 128 |
| |
| // so lange werden die daten im cache gehalten |
| #define CACHE_TIME 86400 /* 1 day */ |
| |
| // Ab dieser Groesse betrache ich den cache als "gross genug", |
| // um einen cache update in etappen zu rechtfertigen. |
| #define LARGE_CACHE_LIMIT 2000 |
| |
| // so lange sind wir bereit auf die antwort einer anfrage beim server zu warten |
| #define QUERY_TIME 60 /* 1 min */ |
| |
| #include <config.h> |
| #if MUDNAME == "MorgenGrauen" |
| #define LOG(x) log_file("rumata/iplookup.log",strftime("%Y-%m-%d %H:%M:%S: ")+(x)+"\n") |
| #else |
| #define LOG(x) |
| #endif |
| |
| // PROTOTYPES |
| |
| public void create(); |
| public void reset(); |
| static int active_entry( string key, mixed* data ); |
| static void expire_cache_small(); |
| static void expire_cache_large( string* keys ); |
| public void update( string udp_reply ); |
| |
| // IMPLEMENTATION |
| |
| public void create() { |
| seteuid(getuid()); |
| restore_object( IPLOOKUP_SAVE ); |
| |
| if( !mappingp(ipmap) || widthof(ipmap)!=4 ) { |
| ipmap = m_allocate( 0, 4 ); |
| LOG("restore failed, creating new ipmap"); |
| } else { |
| LOG(sprintf("created (%d entries)",sizeof(ipmap))); |
| } |
| } |
| |
| public void reset() { |
| if( sizeof(ipmap) < LARGE_CACHE_LIMIT ) { |
| expire_cache_small(); |
| } else { |
| LOG(sprintf("reset %d ->",sizeof(ipmap))); |
| expire_cache_large( m_indices(ipmap) ); |
| } |
| set_next_reset(10800); |
| } |
| |
| static int active_entry( string key, mixed* data ) { |
| return time() < data[IPMAP_EXPIRE]; |
| } |
| |
| // Den cache auf einfache weise aufraeumen. |
| static void expire_cache_small() { |
| int s = sizeof(ipmap); |
| ipmap = filter( ipmap, #'active_entry ); |
| save_object( IPLOOKUP_SAVE ); |
| LOG(sprintf("reset (%d -> %d)",s,sizeof(ipmap))); |
| } |
| |
| // Kompliziertere routine, die den cache etappenweise abarbeitet. |
| static void expire_cache_large( string* keys ) { |
| if( !pointerp(keys) ) return; |
| int next=0; |
| foreach( string key: keys ) { |
| if( get_eval_cost() < 100000 ) break; |
| if( ipmap[key,IPMAP_EXPIRE] < time() ) { |
| m_delete( ipmap, key ); |
| } |
| next++; |
| } |
| LOG(sprintf("checking %d of %d",next,sizeof(keys))); |
| if( next<sizeof(keys) ) { |
| call_out( #'expire_cache_large, 6, keys[next..] ); |
| } else { |
| save_object( IPLOOKUP_SAVE ); |
| LOG(sprintf("reset -> %d (done)",sizeof(ipmap))); |
| } |
| } |
| |
| #define SEARCHING "<auf der Suche...>" |
| |
| /* Erzeugt einen temporaeren Eintrag, der fuer eine Suche steht. |
| * Wenn die Antwort kommt, wird der Eintrag mit den entgueltigen |
| * Daten ueberschrieben. |
| */ |
| static void make_request( string ipnum ) { |
| send_udp( IPLOOKUP_HOST, IPLOOKUP_PORT, ipnum ); |
| ipmap += ([ ipnum : ipnum ; SEARCHING ; |
| time()+QUERY_TIME ; STATUS_QUERYING |
| ]); |
| } |
| |
| /* Liefert zu einer gegebenen ipnum den Ort. |
| * diese Funktion wird von simul_efun aufgerufen. |
| * @param ipnum eine numerische ip-adresse oder ein interactive |
| * @return den Ort (oder das Land) in dem sich die ip-adresse |
| * laut externem Server befindet. |
| */ |
| public string country( mixed ipnum ) { |
| string host,city; |
| int expire,state; |
| |
| if( objectp(ipnum) ) { |
| ipnum = query_ip_number(ipnum); |
| } |
| if( !stringp(ipnum) ) { |
| return "<undefined>"; |
| } |
| if( !m_contains( &host, &city, &expire, &state, ipmap, ipnum ) ) { |
| make_request( ipnum ); |
| return SEARCHING; |
| } |
| |
| return city; |
| } |
| |
| /* Liefert zu einer gegebenen ipnum den Hostnamen. |
| * diese Funktion wird von simul_efun aufgerufen. |
| * @param ipnum eine numerische ip-adresse oder ein interactive |
| * @return den Hostnamen der zu der angegebenen ip-adresse gehoert. |
| * wenn der hostname nicht bekannt ist, wird die ipadresse zurueckgegeben. |
| */ |
| public string host( mixed ipnum ) { |
| string host,city; |
| int expire,state; |
| |
| if( objectp(ipnum) ) { |
| ipnum = query_ip_number(ipnum); |
| } |
| if( !stringp(ipnum) ) { |
| return "<undefined>"; |
| } |
| if( !m_contains( &host, &city, &expire, &state, ipmap, ipnum ) ) { |
| make_request( ipnum ); |
| return ipnum; |
| } |
| |
| return host; |
| } |
| |
| /* wird vom master aufgerufen, wenn eine antwort vom externen |
| * iplookup dienst eintrudelt. |
| */ |
| public void update( string udp_reply ) { |
| string* reply; |
| if( previous_object()!=master() ) return; |
| reply = explode(udp_reply,"\n"); |
| if( sizeof(reply)<4 ) return; |
| |
| if( reply[3] == "<unknown>" ) reply[3] = reply[1]; |
| if( reply[2] == "<unknown>" ) reply[2] = "irgendwoher"; |
| ipmap += ([ reply[1] : reply[3] ; reply[2] ; time()+CACHE_TIME ; |
| STATUS_AUTHORITATIVE ]); |
| //save_object( IPLOOKUP_SAVE ); |
| } |
| |
| int remove(int silent) { |
| save_object( IPLOOKUP_SAVE ); |
| destruct(this_object()); |
| return 1; |
| } |
| |
| // DEBUGGING CODE |
| |
| #if 0 |
| public void dump( string key, mixed* data ) { |
| printf( "%s: %s (%s) s=%d bis %d\n", key, data[0], data[1], |
| data[3], data[2] ); |
| } |
| |
| public void load(string s) { |
| restore_object(s); |
| if( !mappingp(ipmap) || widthof(ipmap)!=4 ) { |
| ipmap = m_allocate( 0, 4 ); |
| LOG("restore failed, creating new ipmap"); |
| } else { |
| LOG(sprintf("created (%d entries)",sizeof(ipmap))); |
| } |
| } |
| |
| public void debug() { |
| map( ipmap, #'dump ); |
| printf( "= %d Eintraege\n", sizeof(ipmap) ); |
| } |
| #endif |