blob: 7608d8fc3d4621af14be46f03d48c9e4804b6980 [file] [log] [blame]
MG Mud User88f12472016-06-24 23:31:02 +02001/*
2 * Mudlibseite des iplookup systems, mit dem aus numerischen IP Adressen
3 * der Hostname und der Ort, an dem sich der Rechner befinden berechnet wird.
4 * Ergebnisse werden gecachet.
5 *
6 * (c)2010 rumata @ morgengrauen
7 */
8
9#pragma strict_types,save_types
10#pragma no_clone,no_shadow
11
12// Format der ipmap:
13// Key: numerische ip als string (ohne fuehrende nullen)
14// Data:
15// [ip,0] Hostname, der vom externen Server geliefert wurde.
16// [ip,1] Locationinformation, die vom externen Server kommt.
17// dieser sollte den Ort, oder falls es nicht besser geht, das Land
18// im Klartext liefern.
19// [ip,2] Zeitstempel, bei dessen erreichen der Wert geloescht werden
20// soll.
21// [ip,3] Status der Anfrage
22
23private mapping ipmap;
24#define IPMAP_HOST 0
25#define IPMAP_CITY 1
26#define IPMAP_EXPIRE 2
27#define IPMAP_STATUS 3
28
29// externer server, der der lokationdaten berechnet
30#define IPLOOKUP_HOST "127.0.0.1"
31#define IPLOOKUP_PORT 8711
32#define IPLOOKUP_SAVE "/p/daemon/save/iplookup"
33
34// moegliche statuswerte (platz zum zaehlen der anfragen gelassen)
35#define STATUS_QUERYING 1
36#define STATUS_AUTHORITATIVE 128
37
38// so lange werden die daten im cache gehalten
39#define CACHE_TIME 86400 /* 1 day */
40
41// Ab dieser Groesse betrache ich den cache als "gross genug",
42// um einen cache update in etappen zu rechtfertigen.
43#define LARGE_CACHE_LIMIT 2000
44
45// so lange sind wir bereit auf die antwort einer anfrage beim server zu warten
46#define QUERY_TIME 60 /* 1 min */
47
48#include <config.h>
49#if MUDNAME == "MorgenGrauen"
50#define LOG(x) log_file("rumata/iplookup.log",strftime("%Y-%m-%d %H:%M:%S: ")+(x)+"\n")
51#else
52#define LOG(x)
53#endif
54
55// PROTOTYPES
56
57public void create();
58public void reset();
59static int active_entry( string key, mixed* data );
60static void expire_cache_small();
61static void expire_cache_large( string* keys );
62public void update( string udp_reply );
63
64// IMPLEMENTATION
65
66public void create() {
67 seteuid(getuid());
68 restore_object( IPLOOKUP_SAVE );
69
70 if( !mappingp(ipmap) || widthof(ipmap)!=4 ) {
71 ipmap = m_allocate( 0, 4 );
72 LOG("restore failed, creating new ipmap");
73 } else {
74 LOG(sprintf("created (%d entries)",sizeof(ipmap)));
75 }
76}
77
78public void reset() {
79 if( sizeof(ipmap) < LARGE_CACHE_LIMIT ) {
80 expire_cache_small();
81 } else {
82 LOG(sprintf("reset %d ->",sizeof(ipmap)));
83 expire_cache_large( m_indices(ipmap) );
84 }
85 set_next_reset(10800);
86}
87
88static int active_entry( string key, mixed* data ) {
89 return time() < data[IPMAP_EXPIRE];
90}
91
92// Den cache auf einfache weise aufraeumen.
93static void expire_cache_small() {
94 int s = sizeof(ipmap);
95 ipmap = filter( ipmap, #'active_entry );
96 save_object( IPLOOKUP_SAVE );
97 LOG(sprintf("reset (%d -> %d)",s,sizeof(ipmap)));
98}
99
100// Kompliziertere routine, die den cache etappenweise abarbeitet.
101static void expire_cache_large( string* keys ) {
102 if( !pointerp(keys) ) return;
103 int next=0;
104 foreach( string key: keys ) {
105 if( get_eval_cost() < 100000 ) break;
106 if( ipmap[key,IPMAP_EXPIRE] < time() ) {
107 m_delete( ipmap, key );
108 }
109 next++;
110 }
111 LOG(sprintf("checking %d of %d",next,sizeof(keys)));
112 if( next<sizeof(keys) ) {
113 call_out( #'expire_cache_large, 6, keys[next..] );
114 } else {
115 save_object( IPLOOKUP_SAVE );
116 LOG(sprintf("reset -> %d (done)",sizeof(ipmap)));
117 }
118}
119
120#define SEARCHING "<auf der Suche...>"
121
122/* Erzeugt einen temporaeren Eintrag, der fuer eine Suche steht.
123 * Wenn die Antwort kommt, wird der Eintrag mit den entgueltigen
124 * Daten ueberschrieben.
125 */
126static void make_request( string ipnum ) {
127 send_udp( IPLOOKUP_HOST, IPLOOKUP_PORT, ipnum );
128 ipmap += ([ ipnum : ipnum ; SEARCHING ;
129 time()+QUERY_TIME ; STATUS_QUERYING
130 ]);
131}
132
133/* Liefert zu einer gegebenen ipnum den Ort.
134 * diese Funktion wird von simul_efun aufgerufen.
135 * @param ipnum eine numerische ip-adresse oder ein interactive
136 * @return den Ort (oder das Land) in dem sich die ip-adresse
137 * laut externem Server befindet.
138 */
139public string country( mixed ipnum ) {
140 string host,city;
141 int expire,state;
142
143 if( objectp(ipnum) ) {
144 ipnum = query_ip_number(ipnum);
145 }
146 if( !stringp(ipnum) ) {
147 return "<undefined>";
148 }
149 if( !m_contains( &host, &city, &expire, &state, ipmap, ipnum ) ) {
150 make_request( ipnum );
151 return SEARCHING;
152 }
153
154 return city;
155}
156
157/* Liefert zu einer gegebenen ipnum den Hostnamen.
158 * diese Funktion wird von simul_efun aufgerufen.
159 * @param ipnum eine numerische ip-adresse oder ein interactive
160 * @return den Hostnamen der zu der angegebenen ip-adresse gehoert.
161 * wenn der hostname nicht bekannt ist, wird die ipadresse zurueckgegeben.
162 */
163public string host( mixed ipnum ) {
164 string host,city;
165 int expire,state;
166
167 if( objectp(ipnum) ) {
168 ipnum = query_ip_number(ipnum);
169 }
170 if( !stringp(ipnum) ) {
171 return "<undefined>";
172 }
173 if( !m_contains( &host, &city, &expire, &state, ipmap, ipnum ) ) {
174 make_request( ipnum );
175 return ipnum;
176 }
177
178 return host;
179}
180
181/* wird vom master aufgerufen, wenn eine antwort vom externen
182 * iplookup dienst eintrudelt.
183 */
184public void update( string udp_reply ) {
185 string* reply;
186 if( previous_object()!=master() ) return;
187 reply = explode(udp_reply,"\n");
188 if( sizeof(reply)<4 ) return;
189
190 if( reply[3] == "<unknown>" ) reply[3] = reply[1];
191 if( reply[2] == "<unknown>" ) reply[2] = "irgendwoher";
192 ipmap += ([ reply[1] : reply[3] ; reply[2] ; time()+CACHE_TIME ;
193 STATUS_AUTHORITATIVE ]);
194 //save_object( IPLOOKUP_SAVE );
195}
196
197int remove(int silent) {
198 save_object( IPLOOKUP_SAVE );
199 destruct(this_object());
200 return 1;
201}
202
203// DEBUGGING CODE
204
205#if 0
206public void dump( string key, mixed* data ) {
207 printf( "%s: %s (%s) s=%d bis %d\n", key, data[0], data[1],
208 data[3], data[2] );
209}
210
211public void load(string s) {
212 restore_object(s);
213 if( !mappingp(ipmap) || widthof(ipmap)!=4 ) {
214 ipmap = m_allocate( 0, 4 );
215 LOG("restore failed, creating new ipmap");
216 } else {
217 LOG(sprintf("created (%d entries)",sizeof(ipmap)));
218 }
219}
220
221public void debug() {
222 map( ipmap, #'dump );
223 printf( "= %d Eintraege\n", sizeof(ipmap) );
224}
225#endif