2 /* -}{----------------------------------------------------------------------- */
7 /* -}{----------------------------------------------------------------------- */
9 #define TMPBUFSIZE 4096
10 static char tmpbuf[TMPBUFSIZE];
11 static k_hashtable* own_resources;
13 /* -}{----------------------------------------------------------------------- */
15 extern void run_tests(void);
17 extern char* make_cache_path(char* uri);
18 extern void look_in_file_cache(ni_event* evq);
19 extern void save_in_file_cache(ni_resource* res);
21 extern void init_uri2chan(void);
22 extern char* get_host_for(char* uri);
23 extern char* get_channel_for(char* host);
24 extern char* use_ping_info(k_hashtable*, k_channel*);
25 extern void use_from_info(k_hashtable*, k_channel*);
26 extern void ping_tunnels(void);
27 extern void send_ping(k_channel* chan, char* firstline, char* to);
29 /* -}{----------------------------------------------------------------------- */
31 static int handles_resource(char* name);
32 static void sync_resource(ni_resource* res);
33 int connection_writable(k_channel* chan, int bufpos, int len);
34 int connection_readable(k_channel* chan, int bufpos, int len);
35 static int recv_next_event( k_channel* chan);
36 static void recv_request( k_channel* chan, char* header);
37 static void recv_response( k_channel* chan, char* header);
38 static void got_mmap(char*, char*, char*, int, k_stat, void*);
39 static void set_read_buffer(k_channel*, char*, size_t, ni_event*);
40 static int recv_entity( k_channel* chan, int bufpos, int eof);
41 static int expecting_response(char* pub, ni_event* evt, k_channel*);
42 static void do_request( ni_event* evq);
43 void ensure_self_sub(ni_event* evq);
44 static void ping_resource_subs(void* arg, char* key, void* val);
45 static void ping_sub(ni_resource* res, k_hashtable* sub);
46 static ni_resource* own_resource(char* uri);
47 static void send_request(ni_event* evq);
48 static void send_response(ni_event* evt);
49 static k_channel* ensure_chan(char* chanm);
51 /* -}{----------------------------------------------------------------------- */
53 EXPORT int np_module_loaded(void)
55 ni_register_driver("np", handles_resource, sync_resource);
57 if(strstr(k_version, "test")){
63 own_resources=k_hashtable_new("Own Resources", 0);
65 k_log_out("NP Driver initialised");
70 EXPORT void np_module_tick(void)
75 k_hashtable_apply(own_resources, ping_resource_subs, 0);
82 EXPORT int np_module_event(void* data)
85 if(!k_hashtable_get(evt->ent_head, "Status:")){
94 /* -}{----------------------------------------------------------------------- */
96 int handles_resource(char* name)
101 void sync_resource(ni_resource* res)
103 save_in_file_cache(res);
106 /* -}{----------------------------------------------------------------------- */
108 int connection_readable(k_channel* chan, int bufpos, int len)
110 if(0) k_log_out("connection_readable %s %p %d %d %p",
111 chan->name, chan, bufpos, len, chan->context);
118 ni_event* evt=chan->context;
120 int n=recv_next_event(chan);
125 int n=recv_entity(chan, bufpos, eof);
132 if(eof && chan->context){
133 ni_event* evt=chan->context;
135 ni_event_delete(evt);
142 int connection_writable(k_channel* chan, int bufpos, int len)
144 if(0) k_log_out("connection_writable %p %d %d %p",
145 chan, bufpos, len, chan->context);
146 //if(len>20000) exit(1);
151 send_ping(chan, "PING ni/0.5", 0);
155 if(eof && chan->context){
156 ni_event* evt=chan->context;
158 ni_event_delete(evt);
165 /* -}{---- Receiving -------------------------------------------------------- */
167 int recv_next_event(k_channel* chan)
169 char* header=k_channel_chop_div(chan, CRLF CRLF);
170 if(!header) return -1;
171 int n=strlen(header)+strlen(CRLF CRLF);
173 if(!strncmp(header, "GET", 3) ||
174 !strncmp(header, "SUB", 3) ||
175 !strncmp(header, "UNSUB",5) ||
176 !strncmp(header, "HEAD", 4) ||
177 !strncmp(header, "PING", 4) ){
179 recv_request(chan, header);
182 if(!strncmp(header, "ni/", 4) ){
184 recv_response(chan, header);
188 k_log_err("Failed reading request or response - closing connection");
189 k_channel_close(chan);
193 void recv_request(k_channel* chan, char* header)
196 evq=ni_get_request_headers(header);
198 k_log_err("Failed reading request headers - closing connection");
199 k_channel_close(chan);
202 if(!k_hashtable_isn(evq->evt_head, "Protocol:", "ni/", 4)){
203 ni_event_delete(evq);
204 k_log_err("Failed reading request not ni - closing connection");
205 k_channel_close(chan);
209 k_hashtable* ent_head=evq->ent_head;
210 int ping=k_hashtable_is(ent_head, "Method:", "PING");
212 if(!evq->uri && !ping){
213 evq->uri=k_strdup(chan->name);
214 k_hashtable_put_dup(ent_head, "URI:", chan->name);
217 ni_event_show(evq, "ni Protocol Request");
219 if(k_hashtable_isi(evq->evt_head, "Connection:", "Keep-Alive")){
221 if(k_hashtable_isn(ent_head, "Sub-To:", "./test", 6)){
226 char* from=use_ping_info(ent_head, chan);
227 if(from) send_ping(chan, "ni/0.5 270 PING", from);
228 ni_event_delete(evq);
231 //use_from_info(ent_head, chan);
233 ni_event* evp=ni_event_new(evq->uri, 0, k_hashtable_dup(ent_head), 0);
235 ni_event_delete(evq);
237 k_event_post("ni", evp);
240 void recv_response(k_channel* chan, char* header)
242 ni_event* evt=ni_get_response_headers(header);
244 k_log_err("recv_response: headers failed but doing nothing!");
248 k_hashtable* ent_head=evt->ent_head;
250 if(!expecting_response(pub, evt, chan)) return;
252 ni_event_show(evt, "Response");
254 int head=k_hashtable_is( ent_head, "Status:", "260");
255 int nmod=k_hashtable_is( ent_head, "Status:", "304");
256 int ping=k_hashtable_is( ent_head, "Status:", "270");
257 int cl =k_hashtable_get_int(ent_head, "Content-Length:");
258 int entity=!(head || nmod || ping || cl==0);
261 use_ping_info(ent_head, chan);
262 ni_event_delete(evt);
265 use_from_info(ent_head, chan);
268 k_hashtable_set(ent_head, "Status:", "260");
269 k_hashtable_set(ent_head, "Status-Text:", "Headers Only");
271 k_event_post("ni", evt);
275 k_hashtable* eh=k_hashtable_new("nHeaders/recv_response", 1);
276 char* from =k_hashtable_get(ent_head, "From:");
277 char* contlen =k_hashtable_get(ent_head, "Content-Length:");
278 char* cux =k_hashtable_get(ent_head, "CUX:");
279 k_hashtable_set(eh, "Status:", "206");
280 k_hashtable_set(eh, "Status-Text:", "Partial Content");
281 k_hashtable_put_dup(eh, "From:", from);
282 k_hashtable_put_dup(eh, "Content-Length:", contlen);
283 k_hashtable_put_dup(eh, "CUX:", cux);
284 ni_event* evc=ni_event_new(pub, 0, eh, 0);
287 int constant=k_hashtable_is(ent_head, "CUX:", "C");
289 char* path=make_cache_path(pub); if(!path) return;
290 k_file_read(".", path, USE_MMAP, cl, got_mmap, chan);
293 char* data=k_malloc(cl);
294 set_read_buffer(chan, data, cl, evc);
299 void got_mmap(char* basedir,
307 k_channel* chan=context;
308 ni_event* evt=chan->context;
309 if(!evt){ k_log_err("got_mmap: evt=0"); return; }
310 if(!data || !usedmmap){ k_log_err("got_mmap: mmap failed"); return; }
312 size_t cl=k_hashtable_get_int(evt->ent_head, "Content-Length:");
313 set_read_buffer(chan, data, cl, evt);
316 void set_read_buffer(k_channel* chan, char* data, size_t cl, ni_event* evt)
319 int r=k_channel_setbuf(chan, data, cl);
320 if(0) k_log_out("k_channel_setbuf %d", r);
321 if(r==BUFFER_ALREADY_SET){
322 k_log_err("oops! k_channel_setbuf BUFFER_ALREADY_SET");
325 if(r==BUFFER_FILLED){
326 k_hashtable_set(evt->ent_head, "Status:", "200");
327 k_hashtable_set(evt->ent_head, "Status-Text:", "OK");
329 k_event_post("ni", evt);
333 int recv_entity(k_channel* chan, int bufpos, int eof)
335 ni_event* evt=chan->context;
336 k_hashtable* ent_head=evt->ent_head;
338 char* cls=k_hashtable_get( ent_head, "Content-Length:");
339 int cl =k_hashtable_get_int(ent_head, "Content-Length:");
341 if(!cls && !eof) return -1;
344 int eofcontlen=eof && (!cls || bufpos < cl);
347 char* clg=k_strdup(cls);
348 k_hashtable_put(ent_head, "Content-Length-Given:", clg);
352 char b[32]; snprintf(b, 32, "%d", cl);
353 k_hashtable_put_dup(ent_head, "Content-Length:", b);
358 ni_event* evp=ni_event_dup(evt);
359 snprintf(tmpbuf, TMPBUFSIZE, "0-%d", bufpos);
360 char* cr=k_strdup(tmpbuf);
361 k_hashtable_put(evp->ent_head, "Content-Range:", cr);
362 k_event_post("ni", evp);
367 static char dummy_empty_entity[0];
368 if(!k_channel_getbuf(chan)){
369 int cn=k_hashtable_is(ent_head, "CUX:", "C");
370 if(cl) evt->entity=k_channel_chop_len(chan, cl);
371 else evt->entity=cn? dummy_empty_entity: k_malloc(1);
375 k_hashtable_set(ent_head, "Status:", "200");
376 k_hashtable_set(ent_head, "Status-Text:", "OK");
379 k_event_post("ni", evt);
384 int expecting_response(char* pub, ni_event* evt, k_channel* chan)
387 k_log_err("unwanted response: %s", pub);
388 ni_event_delete(evt);
389 k_channel_close(chan);
395 /* -}{---- Sending ---------------------------------------------------------- */
397 void do_request(ni_event* evq)
399 k_hashtable* sub=evq->ent_head;
400 int tc=k_hashtable_isi(sub, "Sub-Type:", "Cache");
401 int to=k_hashtable_isi(sub, "Sub-Type:", "Original");
404 char* ims=k_hashtable_get(sub, "If-Modified-Since:");
405 if(ims) ensure_self_sub(evq);
406 else look_in_file_cache(evq);
414 void ensure_self_sub(ni_event* evq)
416 k_hashtable* sub=evq->ent_head;
417 char* pub=k_hashtable_get(sub, "Sub-To:");
419 ni_resource* res=own_resource(pub);
420 k_hashtable* enh=res->ent_head;
421 k_hashtable* selfsub=k_hashtable_get(enh, "Sub-To:");
422 if(selfsub && !k_hashtable_is(selfsub, "Status-Cache:", "OK")){
423 k_log_err("cancel selfsub as new one needed");
426 k_hashtable* ss=k_hashtable_dup(sub);
427 k_hashtable_remove( ss, "From:");
428 k_hashtable_put_dup(ss, "URI:", pub);
429 k_hashtable_set( ss, "Sub-Type:", "Original");
430 k_hashtable_put_dup(ss, "Via:", get_host_for(pub));
431 if(k_hashtable_get( ss, "If-Modified-Since:")){
432 char* lm=k_hashtable_get(enh, "Last-Modified:");
433 if(!res->entity) lm=0;
434 k_hashtable_set(ss, "If-Modified-Since:", lm? lm: "0");
436 ni_event* evs=ni_event_new(0, 0, ss, 0);
437 k_event_post("ni", evs);
439 ni_event_delete(evq);
442 void ping_resource_subs(void* arg, char* key, void* val)
444 ni_resource* res=val;
445 k_hashtable* pubcache=k_hashtable_get(res->ent_head, "Pub-Cache:");
446 if(!pubcache || !k_hashtable_get(pubcache, "Method:")) return;
447 k_hashtable* subs=k_hashtable_get(res->ent_head, "Sub-To:");
449 for(sub=subs; sub; sub=sub->next){
450 if(!k_hashtable_is(sub, "Status-Cache:", "OK")){
451 if(!k_hashtable_get(sub, "Status:")){
455 int ts=k_hashtable_get_int(sub, "Timestamp:");
456 if(0) k_log_out("check dried-up request: %d", ts);
462 void ping_sub(ni_resource* res, k_hashtable* sub)
464 ni_resource_show(res, "ping_resource_subs");
466 k_hashtable* ss=k_hashtable_dup(sub);
468 char* subto=k_hashtable_extract(ss, "URI:");
469 k_hashtable_put_dup(ss, "URI:", res->uri);
470 k_hashtable_put( ss, "Sub-To:", subto);
471 k_hashtable_set( ss, "Sub-Type:", "Original");
472 k_hashtable_put_dup(ss, "Via:", get_host_for(res->uri));
474 ni_event* evs=ni_event_new(0, 0, ss, 0);
475 k_event_post("ni", evs);
478 ni_resource* own_resource(char* uri)
480 ni_resource* res=k_hashtable_get(own_resources, uri);
482 res=ni_resource_get(uri);
483 k_hashtable_set(own_resources, uri, res);
488 void send_request(ni_event* evt)
490 k_hashtable* eh=evt->ent_head;
491 char* method=k_strdup(k_hashtable_get(eh, "Method:"));
492 char* to =k_strdup(k_hashtable_get(eh, "Sub-To:"));
493 char* via =k_strdup(k_hashtable_get(eh, "Via:"));
495 char* chanm=get_channel_for(via);
496 if(!chanm) goto free_and_return;
498 k_channel* chan=ensure_chan(chanm);
499 if(!chan) goto free_and_return;
501 ni_fix_ni_headers(eh, 0);
502 ni_request(evt, to, method, chan);
505 k_free(method); k_free(to); k_free(via);
506 ni_event_delete(evt);
509 void send_response(ni_event* evt)
511 ni_event_show(evt, "send_response");
513 k_hashtable* eh=evt->ent_head;
515 k_hashtable* sub=k_hashtable_get(eh, "Pub-To:");
516 char* uri =k_hashtable_get(sub, "URI:");
517 char* from =k_hashtable_get(sub, "From:");
518 char* method =k_hashtable_get(sub, "Method:");
519 int methead =k_hashtable_is( sub, "Method:", "HEAD");
521 char* to=from? from: uri;
523 char* host=from? from: get_host_for(uri);
524 char* chanm=get_channel_for(host);
526 if(0) k_log_out("no ni protocol channel %s", to);
527 ni_event_delete(evt);
531 k_channel* chan=ensure_chan(chanm);
533 if(0) k_log_out("no ni protocol channel %s", to);
534 ni_event_delete(evt);
538 k_hashtable_extract(eh, "Pub-To:");
540 char* protocol="ni/0.5";
542 ni_fix_ni_headers(eh, methead);
543 ni_response(evt, to, method, protocol, 0, chan);
545 k_hashtable_delete(sub);
547 ni_event_delete(evt);
550 k_channel* ensure_chan(char* chanm)
552 k_channel* chan=k_channel_get_name(chanm);
554 k_log_err("Cannot find current channel for %s", chanm);
555 k_channel_connect_name(chanm, connection_readable,
556 connection_writable);
561 /* -}{----------------------------------------------------------------------- */