linux: LIBRARIES=-L/usr/local/lib -lnsl -ldl -lm -lX11 -lEGL -lGLESv2
linux: linux-all
-linux-all: cilux mod-ni.so mod-np.so mod-mid.so mod-testni.so install-lin
+linux-all: cilux mod-on.so mod-op.so mod-mid.so mod-teston.so install-lin
# ---------------------------------------------------------------------------- #
@echo -n " Linux (Built " >> src/platform/linux/version.h
@date | tr '\012' ')' >> src/platform/linux/version.h
@echo "\";" >> src/platform/linux/version.h
- @echo "static char* cilux_ciux=\"np\";" >> src/platform/linux/version.h
+ @echo "static char* cilux_ciux=\"op\";" >> src/platform/linux/version.h
cilux: version-lin src/platform/linux/cilux.c src/platform/linux/kernelplat.h src/platform/linux/kernelplat.c src/platform/kernelapi.c src/include/kernelapi.h src/platform/linux/platform.h
(cd src/platform/linux; $(CC) $(CCOPTIONS) -c cilux.c -o cilux.o $(COMPILEOPTIONS) $(INCLUDES))
$(STRIP) cilux
@echo '--------------------'
-mod-ni.so: src/ni/ni.c src/ni/headers.c src/include/ni.h src/include/kernelapi.h src/platform/linux/platform.h
- (cd src/ni; $(CC) $(CCOPTIONS) -c headers.c -o headers.o $(COMPILEOPTIONS) $(INCLUDES))
- (cd src/ni; $(CC) $(CCOPTIONS) -c ni.c -o ni.o $(COMPILEOPTIONS) $(INCLUDES))
- $(CCLIB),mod-ni.so -o mod-ni.so src/ni/headers.o src/ni/ni.o
- $(STRIP) mod-ni.so
+mod-on.so: src/on/notification.c src/on/headers.c src/include/notification.h src/include/kernelapi.h src/platform/linux/platform.h
+ (cd src/on; $(CC) $(CCOPTIONS) -c headers.c -o headers.o $(COMPILEOPTIONS) $(INCLUDES))
+ (cd src/on; $(CC) $(CCOPTIONS) -c notification.c -o notification.o $(COMPILEOPTIONS) $(INCLUDES))
+ $(CCLIB),mod-on.so -o mod-on.so src/on/headers.o src/on/notification.o
+ $(STRIP) mod-on.so
@echo '--------------------'
-mod-np.so: src/drivers/np/np.c src/drivers/np/uri2chan.c src/include/kernelapi.h src/platform/linux/platform.h
- (cd src/drivers/np; $(CC) $(CCOPTIONS) -c np.c -o np.o $(COMPILEOPTIONS) $(INCLUDES))
- (cd src/drivers/np; $(CC) $(CCOPTIONS) -c uri2chan.c -o uri2chan.o $(COMPILEOPTIONS) $(INCLUDES))
- (cd src/drivers/np; $(CC) $(CCOPTIONS) -c cache.c -o cache.o $(COMPILEOPTIONS) $(INCLUDES))
- $(CCLIB),mod-np.so -o mod-np.so src/drivers/np/np.o src/drivers/np/uri2chan.o src/drivers/np/cache.o
- $(STRIP) mod-np.so
+mod-op.so: src/drivers/op/protocol.c src/drivers/op/uri2chan.c src/include/kernelapi.h src/platform/linux/platform.h
+ (cd src/drivers/op; $(CC) $(CCOPTIONS) -c protocol.c -o protocol.o $(COMPILEOPTIONS) $(INCLUDES))
+ (cd src/drivers/op; $(CC) $(CCOPTIONS) -c uri2chan.c -o uri2chan.o $(COMPILEOPTIONS) $(INCLUDES))
+ (cd src/drivers/op; $(CC) $(CCOPTIONS) -c cache.c -o cache.o $(COMPILEOPTIONS) $(INCLUDES))
+ $(CCLIB),mod-op.so -o mod-op.so src/drivers/op/protocol.o src/drivers/op/uri2chan.o src/drivers/op/cache.o
+ $(STRIP) mod-op.so
@echo '--------------------'
-mod-mid.so: src/drivers/nt/mid/mid.c src/include/kernelapi.h src/platform/linux/platform.h
- (cd src/drivers/nt/mid; $(CC) $(CCOPTIONS) -c mid.c -o mid.o $(COMPILEOPTIONS) $(INCLUDES))
- $(CCLIB),mod-mid.so -o mod-mid.so src/drivers/nt/mid/mid.o
+mod-mid.so: src/drivers/ot/mid/mid.c src/include/kernelapi.h src/platform/linux/platform.h
+ (cd src/drivers/ot/mid; $(CC) $(CCOPTIONS) -c mid.c -o mid.o $(COMPILEOPTIONS) $(INCLUDES))
+ $(CCLIB),mod-mid.so -o mod-mid.so src/drivers/ot/mid/mid.o
$(STRIP) mod-mid.so
@echo '--------------------'
-mod-testni.so: src/drivers/nt/test/testni.c src/include/kernelapi.h src/platform/linux/platform.h
- (cd src/drivers/nt/test; $(CC) $(CCOPTIONS) -c testni.c -o testni.o $(COMPILEOPTIONS) $(INCLUDES))
- $(CCLIB),mod-testni.so -o mod-testni.so src/drivers/nt/test/testni.o
- $(STRIP) mod-testni.so
+mod-teston.so: src/drivers/ot/test/teston.c src/include/kernelapi.h src/platform/linux/platform.h
+ (cd src/drivers/ot/test; $(CC) $(CCOPTIONS) -c teston.c -o teston.o $(COMPILEOPTIONS) $(INCLUDES))
+ $(CCLIB),mod-teston.so -o mod-teston.so src/drivers/ot/test/teston.o
+ $(STRIP) mod-teston.so
@echo '--------------------'
install-lin:
mv cilux /usr/local/bin
- mv mod-ni.so mod-np.so /usr/local/lib
+ mv mod-on.so mod-op.so /usr/local/lib
mkdir -p modules/mid
mv mod-mid.so modules/mid
- mkdir -p modules/testni
- mv mod-testni.so modules/testni
+ mkdir -p modules/teston
+ mv mod-teston.so modules/teston
@echo '--------------------'
# ---------------------------------------------------------------------------- #
+++ /dev/null
-
-/* -}{----------------------------------------------------------------------- */
-
-#include <kernelapi.h>
-#include <ni.h>
-
-/* -}{----------------------------------------------------------------------- */
-
-extern void ensure_self_sub(ni_event* evq);
-
-/* -}{----------------------------------------------------------------------- */
-
-#define TMPBUFSIZE 4096
-static char tmpbuf[TMPBUFSIZE];
-
-/* -}{----------------------------------------------------------------------- */
-
-static void cache_read(char*, char*, char*, int, k_stat, void*);
-static void entity_written(char*, char*, char*, int, k_stat, void*);
-static void write_headers(char* path, ni_resource* res);
-static void headers_written(char*, char*, char*, int, k_stat, void*);
-
-
-/* -}{----------------------------------------------------------------------- */
-
-char* make_cache_path(char* uri)
-{
- char* path;
- size_t l=strlen(uri);
- if(l>100){ k_log_out("URI too long to save: %s", uri); return 0; }
- if(*(uri+l-1)!='/'){
- path=k_strdup(uri);
- }
- else{
- path=k_malloc(l+1+10);
- sprintf(path, "%sindex.html", uri);
- }
- return path;
-}
-
-void look_in_file_cache(ni_event* evq)
-{
- k_hashtable* sub=evq->ent_head;
- char* uri=k_hashtable_get(sub, "Sub-To:");
- size_t l=strlen(uri);
-
- if(l>100){ ensure_self_sub(evq); return; }
-
- char hdr[128];
- if(*(uri+l-1)!='/') sprintf(hdr, "%s.hdr", uri);
- else sprintf(hdr, "%sindex.html.hdr", uri);
-
- if(strstr(hdr, "..")){ ensure_self_sub(evq); return; }
- if(strchr(hdr, '?' )){ ensure_self_sub(evq); return; }
-
- char* c=strchr(hdr, ':');
- char* e=strchr(hdr, '/');
- if(c && c< e) *c='-';
-
- k_file_read(".", k_strdup(hdr), USE_MALL, 0, cache_read, evq);
-}
-
-void save_in_file_cache(ni_resource* res)
-{
- char* uri =res->uri;
- char* path =make_cache_path(uri); if(!path) return;
- k_hashtable* ent_head=res->ent_head;
- void* data =res->entity;
- int partial =k_hashtable_is( ent_head, "Status:", "206");
- size_t size =k_hashtable_get_int(ent_head, "Content-Length:");
- char* conrange=k_hashtable_get( ent_head, "Content-Range:");
- int constant=k_hashtable_is( ent_head, "CUX:", "C");
-
- if(!data){
- write_headers(path, res);
- }
- else
- if(constant){
- int ok=k_file_sync(data, size);
- if(!ok){
- k_log_err("Failed to write (sync mmap): %s", uri);
- k_free(path);
- return;
- }
- write_headers(path, res);
- }
- else{
- if(partial){
- k_log_out("save_in_file_cache partial %s", conrange);
- if(!conrange || strncmp(conrange, "0-", 2)){
- k_log_err("not saving partial");
- k_free(path);
- return;
- }
- size=atoi(conrange+2);
- }
- k_log_out("save_in_file_cache updateable: %d bytes", size);
- k_file_write(".", path, data, size, entity_written, res);
- }
-}
-
-/* -}{----------------------------------------------------------------------- */
-
-void entity_written(char* basedir,
- char* path,
- char* data,
- int usedmmap,
- k_stat kstat,
- void* context)
-{
- if(data) k_log_out("File cache entity written: %s", path);
- else{
- k_log_err("Failed to write entity: %s", path);
- k_free(path);
- return;
- }
- ni_resource* res=context;
- write_headers(path, res);
-}
-
-void write_headers(char* path, ni_resource* res)
-{
- snprintf(tmpbuf, TMPBUFSIZE, "%s.hdr", path);
- k_free(path); path=k_strdup(tmpbuf);
- k_hashtable_snprintf(res->ent_head, tmpbuf, TMPBUFSIZE);
- k_file_write(".", path, tmpbuf, strlen(tmpbuf), headers_written, 0);
-}
-
-void headers_written(char* basedir,
- char* path,
- char* data,
- int usedmmap,
- k_stat kstat,
- void* context)
-{
- if(data) k_log_out("File cache headers written: %s", path);
- else k_log_err("Failed to write headers: %s", path);
- k_free(path);
-}
-
-void cache_read(char* basedir,
- char* path,
- char* data,
- int usedmmap,
- k_stat kstat,
- void* context)
-{
- if(!data) k_log_out("no cache of %s", path);
- else k_log_out("file cache read: %d %s", kstat.size, path);
- char* e=strstr(path, ".hdr");
- if(e){
- ni_event* evq=context;
- if(!data){ k_free(path); ensure_self_sub(evq); return; }
-
- char* header=data;
- *(header+kstat.size-2)=0;
- k_hashtable* ent_head=k_hashtable_new("nHeaders/cache_read", 1);
- k_hashtable_put(ent_head, "", header);
- if(!ni_get_headers(header, 0, ent_head)){
- k_hashtable_delete(ent_head);
- k_free(path);
- ensure_self_sub(evq);
- return;
- }
- ni_event_delete(evq);
- *e=0;
- ni_event* evt=ni_event_new(0, 0, ent_head, 0);
- int constant=k_hashtable_is(ent_head, "CUX:", "C");
- size_t m=constant? USE_MMAP: USE_MALL;
- k_file_read(".", path, m, 0, cache_read, evt);
- return;
- }
- ni_event* evt=context;
- k_free(path);
- evt->entity=data;
- ni_event_show(evt, "File Cache Found:");
- k_event_post("ni", evt);
-}
-
-/* -}{----------------------------------------------------------------------- */
-
-
+++ /dev/null
-
-/* -}{----------------------------------------------------------------------- */
-
-#include <kernelapi.h>
-#include <ni.h>
-
-/* -}{----------------------------------------------------------------------- */
-
-#define TMPBUFSIZE 4096
-static char tmpbuf[TMPBUFSIZE];
-static k_hashtable* own_resources;
-
-/* -}{----------------------------------------------------------------------- */
-
-extern void run_tests(void);
-
-extern char* make_cache_path(char* uri);
-extern void look_in_file_cache(ni_event* evq);
-extern void save_in_file_cache(ni_resource* res);
-
-extern void init_uri2chan(void);
-extern char* get_host_for(char* uri);
-extern char* get_channel_for(char* host);
-extern char* use_ping_info(k_hashtable*, k_channel*);
-extern void use_from_info(k_hashtable*, k_channel*);
-extern void ping_tunnels(void);
-extern void send_ping(k_channel* chan, char* firstline, char* to);
-
-/* -}{----------------------------------------------------------------------- */
-
-static int handles_resource(char* name);
-static void sync_resource(ni_resource* res);
- int connection_writable(k_channel* chan, int bufpos, int len);
- int connection_readable(k_channel* chan, int bufpos, int len);
-static int recv_next_event( k_channel* chan);
-static void recv_request( k_channel* chan, char* header);
-static void recv_response( k_channel* chan, char* header);
-static void got_mmap(char*, char*, char*, int, k_stat, void*);
-static void set_read_buffer(k_channel*, char*, size_t, ni_event*);
-static int recv_entity( k_channel* chan, int bufpos, int eof);
-static int expecting_response(char* pub, ni_event* evt, k_channel*);
-static void do_request( ni_event* evq);
- void ensure_self_sub(ni_event* evq);
-static void ping_resource_subs(void* arg, char* key, void* val);
-static void ping_sub(ni_resource* res, k_hashtable* sub);
-static ni_resource* own_resource(char* uri);
-static void send_request(ni_event* evq);
-static void send_response(ni_event* evt);
-static k_channel* ensure_chan(char* chanm);
-
-/* -}{----------------------------------------------------------------------- */
-
-EXPORT int np_module_loaded(void)
-{
- ni_register_driver("np", handles_resource, sync_resource);
-
- if(strstr(k_version, "test")){
- //run_tests();
- }
-
- init_uri2chan();
-
- own_resources=k_hashtable_new("Own Resources", 0);
-
- k_log_out("NP Driver initialised");
-
- return 0;
-}
-
-EXPORT void np_module_tick(void)
-{
- static long tix;
- tix++;
- if(!(tix % 1000)){
- k_hashtable_apply(own_resources, ping_resource_subs, 0);
- }
- if(!(tix % 3000)){
- ping_tunnels();
- }
-}
-
-EXPORT int np_module_event(void* data)
-{
- ni_event* evt=data;
- if(!k_hashtable_get(evt->ent_head, "Status:")){
- do_request(evt);
- }
- else{
- send_response(evt);
- }
- return 0;
-}
-
-/* -}{----------------------------------------------------------------------- */
-
-int handles_resource(char* name)
-{
- return 0;
-}
-
-void sync_resource(ni_resource* res)
-{
- save_in_file_cache(res);
-}
-
-/* -}{----------------------------------------------------------------------- */
-
-int connection_readable(k_channel* chan, int bufpos, int len)
-{
- if(0) k_log_out("connection_readable %s %p %d %d %p",
- chan->name, chan, bufpos, len, chan->context);
- int sof=(len== 0);
- int eof=(len== -1);
-
- if(sof) return 0;
-
- do{
- ni_event* evt=chan->context;
- if(!evt){
- int n=recv_next_event(chan);
- if(n<0) break;
- bufpos-=n;
- }
- else{
- int n=recv_entity(chan, bufpos, eof);
- if(n<0) break;
- bufpos-=n;
- }
-
- } while(1);
-
- if(eof && chan->context){
- ni_event* evt=chan->context;
- evt->entity=0;
- ni_event_delete(evt);
- chan->context=0;
- }
-
- return 0;
-}
-
-int connection_writable(k_channel* chan, int bufpos, int len)
-{
- if(0) k_log_out("connection_writable %p %d %d %p",
- chan, bufpos, len, chan->context);
-//if(len>20000) exit(1);
- int sof=(len== 0);
- int eof=(len== -1);
-
- if(sof){
- send_ping(chan, "PING ni/0.5", 0);
- return 0;
- }
-
- if(eof && chan->context){
- ni_event* evt=chan->context;
- evt->entity=0;
- ni_event_delete(evt);
- chan->context=0;
- }
-
- return 0;
-}
-
-/* -}{---- Receiving -------------------------------------------------------- */
-
-int recv_next_event(k_channel* chan)
-{
- char* header=k_channel_chop_div(chan, CRLF CRLF);
- if(!header) return -1;
- int n=strlen(header)+strlen(CRLF CRLF);
-
- if(!strncmp(header, "GET", 3) ||
- !strncmp(header, "SUB", 3) ||
- !strncmp(header, "UNSUB",5) ||
- !strncmp(header, "HEAD", 4) ||
- !strncmp(header, "PING", 4) ){
-
- recv_request(chan, header);
- return n;
- }
- if(!strncmp(header, "ni/", 4) ){
-
- recv_response(chan, header);
- return n;
- }
- k_free(header);
- k_log_err("Failed reading request or response - closing connection");
- k_channel_close(chan);
- return n;
-}
-
-void recv_request(k_channel* chan, char* header)
-{
- ni_event* evq;
- evq=ni_get_request_headers(header);
- if(!evq){
- k_log_err("Failed reading request headers - closing connection");
- k_channel_close(chan);
- return;
- }
- if(!k_hashtable_isn(evq->evt_head, "Protocol:", "ni/", 4)){
- ni_event_delete(evq);
- k_log_err("Failed reading request not ni - closing connection");
- k_channel_close(chan);
- return;
- }
-
- k_hashtable* ent_head=evq->ent_head;
- int ping=k_hashtable_is(ent_head, "Method:", "PING");
-
- if(!evq->uri && !ping){
- evq->uri=k_strdup(chan->name);
- k_hashtable_put_dup(ent_head, "URI:", chan->name);
- }
-
- ni_event_show(evq, "ni Protocol Request");
-
- if(k_hashtable_isi(evq->evt_head, "Connection:", "Keep-Alive")){
- chan->linger=1;
- if(k_hashtable_isn(ent_head, "Sub-To:", "./test", 6)){
- chan->linger=0;
- }
- }
- if(ping){
- char* from=use_ping_info(ent_head, chan);
- if(from) send_ping(chan, "ni/0.5 270 PING", from);
- ni_event_delete(evq);
- return;
- }
- //use_from_info(ent_head, chan);
-
- ni_event* evp=ni_event_new(evq->uri, 0, k_hashtable_dup(ent_head), 0);
-
- ni_event_delete(evq);
-
- k_event_post("ni", evp);
-}
-
-void recv_response(k_channel* chan, char* header)
-{
- ni_event* evt=ni_get_response_headers(header);
- if(!evt){
- k_log_err("recv_response: headers failed but doing nothing!");
- return;
- }
- char* pub= evt->uri;
- k_hashtable* ent_head=evt->ent_head;
-
- if(!expecting_response(pub, evt, chan)) return;
-
- ni_event_show(evt, "Response");
-
- int head=k_hashtable_is( ent_head, "Status:", "260");
- int nmod=k_hashtable_is( ent_head, "Status:", "304");
- int ping=k_hashtable_is( ent_head, "Status:", "270");
- int cl =k_hashtable_get_int(ent_head, "Content-Length:");
- int entity=!(head || nmod || ping || cl==0);
-
- if(ping){
- use_ping_info(ent_head, chan);
- ni_event_delete(evt);
- return;
- }
- use_from_info(ent_head, chan);
-
- if(entity){
- k_hashtable_set(ent_head, "Status:", "260");
- k_hashtable_set(ent_head, "Status-Text:", "Headers Only");
- }
- k_event_post("ni", evt);
-
- if(entity){
-
- k_hashtable* eh=k_hashtable_new("nHeaders/recv_response", 1);
- char* from =k_hashtable_get(ent_head, "From:");
- char* contlen =k_hashtable_get(ent_head, "Content-Length:");
- char* cux =k_hashtable_get(ent_head, "CUX:");
- k_hashtable_set(eh, "Status:", "206");
- k_hashtable_set(eh, "Status-Text:", "Partial Content");
- k_hashtable_put_dup(eh, "From:", from);
- k_hashtable_put_dup(eh, "Content-Length:", contlen);
- k_hashtable_put_dup(eh, "CUX:", cux);
- ni_event* evc=ni_event_new(pub, 0, eh, 0);
- chan->context=evc;
-
- int constant=k_hashtable_is(ent_head, "CUX:", "C");
- if(constant){
- char* path=make_cache_path(pub); if(!path) return;
- k_file_read(".", path, USE_MMAP, cl, got_mmap, chan);
- }
- else{
- char* data=k_malloc(cl);
- set_read_buffer(chan, data, cl, evc);
- }
- }
-}
-
-void got_mmap(char* basedir,
- char* path,
- char* data,
- int usedmmap,
- k_stat kstat,
- void* context){
-
- k_free(path);
- k_channel* chan=context;
- ni_event* evt=chan->context;
- if(!evt){ k_log_err("got_mmap: evt=0"); return; }
- if(!data || !usedmmap){ k_log_err("got_mmap: mmap failed"); return; }
-
- size_t cl=k_hashtable_get_int(evt->ent_head, "Content-Length:");
- set_read_buffer(chan, data, cl, evt);
-}
-
-void set_read_buffer(k_channel* chan, char* data, size_t cl, ni_event* evt)
-{
- evt->entity=data;
- int r=k_channel_setbuf(chan, data, cl);
- if(0) k_log_out("k_channel_setbuf %d", r);
- if(r==BUFFER_ALREADY_SET){
- k_log_err("oops! k_channel_setbuf BUFFER_ALREADY_SET");
- return;
- }
- if(r==BUFFER_FILLED){
- k_hashtable_set(evt->ent_head, "Status:", "200");
- k_hashtable_set(evt->ent_head, "Status-Text:", "OK");
- chan->context=0;
- k_event_post("ni", evt);
- }
-}
-
-int recv_entity(k_channel* chan, int bufpos, int eof)
-{
- ni_event* evt=chan->context;
- k_hashtable* ent_head=evt->ent_head;
-
- char* cls=k_hashtable_get( ent_head, "Content-Length:");
- int cl =k_hashtable_get_int(ent_head, "Content-Length:");
-
- if(!cls && !eof) return -1;
-
- int partial=0;
- int eofcontlen=eof && (!cls || bufpos < cl);
- if(eofcontlen){
- if(cls){
- char* clg=k_strdup(cls);
- k_hashtable_put(ent_head, "Content-Length-Given:", clg);
- partial=1;
- }
- cl=bufpos;
- char b[32]; snprintf(b, 32, "%d", cl);
- k_hashtable_put_dup(ent_head, "Content-Length:", b);
- }
-
- if(bufpos < cl){
- if(bufpos){
- ni_event* evp=ni_event_dup(evt);
- snprintf(tmpbuf, TMPBUFSIZE, "0-%d", bufpos);
- char* cr=k_strdup(tmpbuf);
- k_hashtable_put(evp->ent_head, "Content-Range:", cr);
- k_event_post("ni", evp);
- }
- return -1;
- }
-
- static char dummy_empty_entity[0];
- if(!k_channel_getbuf(chan)){
- int cn=k_hashtable_is(ent_head, "CUX:", "C");
- if(cl) evt->entity=k_channel_chop_len(chan, cl);
- else evt->entity=cn? dummy_empty_entity: k_malloc(1);
- }
-
- if(!partial){
- k_hashtable_set(ent_head, "Status:", "200");
- k_hashtable_set(ent_head, "Status-Text:", "OK");
- }
- chan->context=0;
- k_event_post("ni", evt);
-
- return cl;
-}
-
-int expecting_response(char* pub, ni_event* evt, k_channel* chan)
-{
- if(pub && 0){
- k_log_err("unwanted response: %s", pub);
- ni_event_delete(evt);
- k_channel_close(chan);
- return 0;
- }
- return 1;
-}
-
-/* -}{---- Sending ---------------------------------------------------------- */
-
-void do_request(ni_event* evq)
-{
- k_hashtable* sub=evq->ent_head;
- int tc=k_hashtable_isi(sub, "Sub-Type:", "Cache");
- int to=k_hashtable_isi(sub, "Sub-Type:", "Original");
-
- if(tc){
- char* ims=k_hashtable_get(sub, "If-Modified-Since:");
- if(ims) ensure_self_sub(evq);
- else look_in_file_cache(evq);
- }
- else
- if(to){
- send_request(evq);
- }
-}
-
-void ensure_self_sub(ni_event* evq)
-{
- k_hashtable* sub=evq->ent_head;
- char* pub=k_hashtable_get(sub, "Sub-To:");
-
- ni_resource* res=own_resource(pub);
- k_hashtable* enh=res->ent_head;
- k_hashtable* selfsub=k_hashtable_get(enh, "Sub-To:");
- if(selfsub && !k_hashtable_is(selfsub, "Status-Cache:", "OK")){
- k_log_err("cancel selfsub as new one needed");
- }
-
- k_hashtable* ss=k_hashtable_dup(sub);
- k_hashtable_remove( ss, "From:");
- k_hashtable_put_dup(ss, "URI:", pub);
- k_hashtable_set( ss, "Sub-Type:", "Original");
- k_hashtable_put_dup(ss, "Via:", get_host_for(pub));
- if(k_hashtable_get( ss, "If-Modified-Since:")){
- char* lm=k_hashtable_get(enh, "Last-Modified:");
- if(!res->entity) lm=0;
- k_hashtable_set(ss, "If-Modified-Since:", lm? lm: "0");
- }
- ni_event* evs=ni_event_new(0, 0, ss, 0);
- k_event_post("ni", evs);
-
- ni_event_delete(evq);
-}
-
-void ping_resource_subs(void* arg, char* key, void* val)
-{
- ni_resource* res=val;
- k_hashtable* pubcache=k_hashtable_get(res->ent_head, "Pub-Cache:");
- if(!pubcache || !k_hashtable_get(pubcache, "Method:")) return;
- k_hashtable* subs=k_hashtable_get(res->ent_head, "Sub-To:");
- k_hashtable* sub;
- for(sub=subs; sub; sub=sub->next){
- if(!k_hashtable_is(sub, "Status-Cache:", "OK")){
- if(!k_hashtable_get(sub, "Status:")){
- ping_sub(res, sub);
- }
- else{
- int ts=k_hashtable_get_int(sub, "Timestamp:");
- if(0) k_log_out("check dried-up request: %d", ts);
- }
- }
- }
-}
-
-void ping_sub(ni_resource* res, k_hashtable* sub)
-{
- ni_resource_show(res, "ping_resource_subs");
-
- k_hashtable* ss=k_hashtable_dup(sub);
-
- char* subto=k_hashtable_extract(ss, "URI:");
- k_hashtable_put_dup(ss, "URI:", res->uri);
- k_hashtable_put( ss, "Sub-To:", subto);
- k_hashtable_set( ss, "Sub-Type:", "Original");
- k_hashtable_put_dup(ss, "Via:", get_host_for(res->uri));
-
- ni_event* evs=ni_event_new(0, 0, ss, 0);
- k_event_post("ni", evs);
-}
-
-ni_resource* own_resource(char* uri)
-{
- ni_resource* res=k_hashtable_get(own_resources, uri);
- if(!res){
- res=ni_resource_get(uri);
- k_hashtable_set(own_resources, uri, res);
- }
- return res;
-}
-
-void send_request(ni_event* evt)
-{
- k_hashtable* eh=evt->ent_head;
- char* method=k_strdup(k_hashtable_get(eh, "Method:"));
- char* to =k_strdup(k_hashtable_get(eh, "Sub-To:"));
- char* via =k_strdup(k_hashtable_get(eh, "Via:"));
-
- char* chanm=get_channel_for(via);
- if(!chanm) goto free_and_return;
-
- k_channel* chan=ensure_chan(chanm);
- if(!chan) goto free_and_return;
-
- ni_fix_ni_headers(eh, 0);
- ni_request(evt, to, method, chan);
-
- free_and_return:
- k_free(method); k_free(to); k_free(via);
- ni_event_delete(evt);
-}
-
-void send_response(ni_event* evt)
-{
- ni_event_show(evt, "send_response");
-
- k_hashtable* eh=evt->ent_head;
-
- k_hashtable* sub=k_hashtable_get(eh, "Pub-To:");
- char* uri =k_hashtable_get(sub, "URI:");
- char* from =k_hashtable_get(sub, "From:");
- char* method =k_hashtable_get(sub, "Method:");
- int methead =k_hashtable_is( sub, "Method:", "HEAD");
-
- char* to=from? from: uri;
-
- char* host=from? from: get_host_for(uri);
- char* chanm=get_channel_for(host);
- if(!chanm){
- if(0) k_log_out("no ni protocol channel %s", to);
- ni_event_delete(evt);
- return;
- }
-
- k_channel* chan=ensure_chan(chanm);
- if(!chan){
- if(0) k_log_out("no ni protocol channel %s", to);
- ni_event_delete(evt);
- return;
- }
-
- k_hashtable_extract(eh, "Pub-To:");
-
- char* protocol="ni/0.5";
-
- ni_fix_ni_headers(eh, methead);
- ni_response(evt, to, method, protocol, 0, chan);
-
- k_hashtable_delete(sub);
- evt->entity=0;
- ni_event_delete(evt);
-}
-
-k_channel* ensure_chan(char* chanm)
-{
- k_channel* chan=k_channel_get_name(chanm);
- if(!chan){
- k_log_err("Cannot find current channel for %s", chanm);
- k_channel_connect_name(chanm, connection_readable,
- connection_writable);
- }
- return chan;
-}
-
-/* -}{----------------------------------------------------------------------- */
-
+++ /dev/null
-
-/* -}{----------------------------------------------------------------------- */
-
-#include <kernelapi.h>
-#include <ni.h>
-
-/* -}{----------------------------------------------------------------------- */
-
-extern int connection_writable(k_channel* chan, int bufpos, int len);
-extern int connection_readable(k_channel* chan, int bufpos, int len);
-
-/* -}{----------------------------------------------------------------------- */
-
-#define TMPBUFSIZE 4096
-static char tmpbuf[TMPBUFSIZE];
-static int is_np;
-static char* nexus_channel;
-static k_hashtable* chans_for_host;
-
-/* -}{----------------------------------------------------------------------- */
-
-static void nexus_file_read(char*, char*, char*, int, k_stat, void*);
-static void write_nexus(char* hostname);
-static void nexus_file_written(char*, char*, char*, int, k_stat, void*);
-static int root_nexus(void);
-static void listen_http(void);
-static void listen_nexus(void);
-static void connect_to_nexus(void);
-static void ping_this(void* arg, char* key, void* val);
-static char* generate_new_hostname(k_hashtable* ent_head, k_channel* chan);
-static void set_channel_for(char* host, char* chanm);
-static void show_np(void);
-static void show_list(void* arg, char* key, void* val);
-
-/* -}{----------------------------------------------------------------------- */
-
-void init_uri2chan(void)
-{
- chans_for_host =k_hashtable_new("Channels for Host", 0);
-
- k_file_read(".", "nexus.txt", USE_MALL, 0, nexus_file_read, 0);
-
- is_np=!strcmp(k_ciux, "np");
- if(is_np) listen_nexus();
- if(root_nexus()){
- k_log_out("root nexus - but listening on http");
- listen_http();
- }
- else{
- k_log_out("connecting to nexus %s", nexus_channel);
- connect_to_nexus();
- }
-}
-
-char* get_host_for(char* uri)
-{
- if(0) k_log_out("get_host_for %s", uri);
- char* host=0;
- if(0) k_log_out("host for %s=%s", uri, host);
- return host;
-}
-
-char* get_channel_for(char* host)
-{
- if(0) k_log_out("get_channel_for %s", host);
- char* chanm=k_hashtable_get(chans_for_host, host);
- if(!chanm){
- }
- if(0) k_log_out("channel for %s=%s", host, chanm);
- return chanm;
-}
-
-char* use_ping_info(k_hashtable* ent_head, k_channel* chan)
-{
- char* from=k_hashtable_get(ent_head, "From:");
- char* to =k_hashtable_get(ent_head, "To:");
-
- if(!from) return 0;
- if(!strcmp(from, "-")) from=generate_new_hostname(ent_head, chan);
- if(!from) return 0;
- if(!ni_hostname() && to) write_nexus(to);
-
- set_channel_for(from, chan->name);
-
- if(0) k_log_out("%s PING %s", chan->name, from);
- if(0) show_np();
-
- return from;
-}
-
-void use_from_info(k_hashtable* ent_head, k_channel* chan)
-{
- char* from=k_hashtable_get(ent_head, "From:");
-
- if(!from) return;
-
- set_channel_for(from, chan->name);
-
- if(0) show_np();
-}
-
-void ping_tunnels(void)
-{
- k_hashtable* channelspinged=k_hashtable_new("channelspinged", 0);
- k_hashtable_apply(chans_for_host, ping_this, channelspinged);
- k_hashtable_delete(channelspinged);
-}
-
-void send_ping(k_channel* chan, char* firstline, char* to)
-{
- char* from=ni_hostname();
- if(!from) from="-";
-
- int ln=0;
- int bufsize=TMPBUFSIZE;
-
- ln+=snprintf(tmpbuf+ln, bufsize-ln, "%s" CRLF, firstline);
- if(ln>=bufsize) return;
- ln+=snprintf(tmpbuf+ln, bufsize-ln, "From: %s" CRLF, from);
- if(ln>=bufsize) return;
- if(to){
- ln+=snprintf(tmpbuf+ln, bufsize-ln, "To: %s" CRLF, to);
- if(ln>=bufsize) return;
- }
- ln+=snprintf(tmpbuf+ln, bufsize-ln, "Server: %s" CRLF, k_version);
- if(ln>=bufsize) return;
- ln+=snprintf(tmpbuf+ln, bufsize-ln, "Channels: %s" CRLF, "-");
- if(ln>=bufsize) return;
- ln+=snprintf(tmpbuf+ln, bufsize-ln, CRLF);
- if(ln>=bufsize) return;
-
- char* head=k_strdup(tmpbuf);
- k_channel_send(chan, head, ln, FREE_ON_SENT);
-}
-
-/* -}{----------------------------------------------------------------------- */
-
-void nexus_file_read(char* basedir,
- char* filepath,
- char* data,
- int usedmmap,
- k_stat kstat,
- void* context)
-{
- int L=0;
- if(data) data[kstat.size-1]=0;
- else data=k_strdup("");
- k_hashtable* nex=k_hashtable_new("nexus", 1);
- if(!ni_get_headers(data, nex, 0)){
- k_log_err("Corrupt nexus.txt file");
- k_hashtable_delete(nex);
- k_free(data);
- data=k_strdup("");
- nex=k_hashtable_new("nexus", 1);
- ni_get_headers(data, nex, 0);
- }
-
- char* hostname;
- nexus_channel=k_hashtable_get_dup(nex, "Nexus-Channel:");
- hostname =k_hashtable_get( nex, "Hostname:");
-
- if(hostname) ni_hostname_set(hostname);
-
- if(L) if(nexus_channel) k_log_out("Nexus-Channel: %s", nexus_channel);
- if(L) if(hostname) k_log_out("Hostname: %s", hostname);
-
- k_hashtable_delete(nex);
- k_free(data);
-}
-
-void write_nexus(char* hostname)
-{
- ni_hostname_set(hostname);
-
- snprintf(tmpbuf, TMPBUFSIZE, "Nexus-Channel: %s\r\n"
- "Hostname: %s\r\n", nexus_channel,
- hostname);
-
- k_file_write(".", "nexus.txt", tmpbuf, strlen(tmpbuf),
- nexus_file_written, 0);
-}
-
-void nexus_file_written(char* basedir,
- char* filepath,
- char* data,
- int usedmmap,
- k_stat kstat,
- void* context)
-{
- if(!data) k_fatal("Failed to write nexus.txt");
- else k_log_out("New nexus.txt written:\n%s", data);
-}
-
-int root_nexus(void)
-{
- char* hostname=ni_hostname();
- if(!hostname || strchr(hostname, '-')) return 0;
- return 1;
-}
-
-void listen_http(void)
-{
- char* chanm="|nip-server|-|8081|-|";
- k_channel_connect_name(chanm, connection_readable,
- connection_writable);
-}
-
-void listen_nexus(void)
-{
- char* chanm="|nip-server|-|7747|-|";
- k_channel_connect_name(chanm, connection_readable,
- connection_writable);
-}
-
-void connect_to_nexus(void)
-{
- if(nexus_channel){
- k_channel_connect_name(nexus_channel, connection_readable,
- connection_writable);
- }
- else k_log_out("discovery of nexus not implemented yet!");
-}
-
-void ping_this(void* arg, char* key, void* val)
-{
- k_hashtable* channelspinged=arg;
- char* chanm=val;
-
- if(strncmp(chanm, "nip-client", 11) ) return;
- if(k_hashtable_get(channelspinged, chanm)) return;
- k_hashtable_set(channelspinged, chanm, chanm);
-
- k_channel* chan=k_channel_get_name(chanm);
- //k_log_out("ping_this: host %s channel %s got=%p", key, chanm, chan);
-
- if(!chan) k_channel_connect_name(chanm, connection_readable,
- connection_writable);
-
- int pingtodeath=0;
- if(chan && pingtodeath) send_ping(chan, "PING ni/0.5", 0);
-}
-
-char* generate_new_hostname(k_hashtable* ent_head, k_channel* chan)
-{
- if(!ni_hostname()) return 0;
- unsigned long a=chan->clientip.s_addr;
- #define IPQUAD(a) \
- ((unsigned char *)&a)[0], \
- ((unsigned char *)&a)[1], \
- ((unsigned char *)&a)[2], \
- ((unsigned char *)&a)[3]
- snprintf(tmpbuf, TMPBUFSIZE, "%s-%02x%02x%02x%02x.%d",
- ni_hostname(), IPQUAD(a), 7747);
- if(0) k_log_out("generated new hostname: %s\n", tmpbuf);
- return k_strdup(tmpbuf);
-}
-
-/* -}{----------------------------------------------------------------------- */
-
-void set_channel_for(char* host, char* chanm)
-{
- k_hashtable_put_dup(chans_for_host, host, chanm);
-}
-
-void show_np(void)
-{
- k_log_out("-------- channel for host ---------------");
- k_hashtable_apply(chans_for_host, show_list, 0);
- k_channel_show_all();
-}
-
-void show_list(void* arg, char* key, void* val)
-{
- char* chanm=val;
- k_log_out("%s %s", key, chanm);
-}
-
-void generate_random(void)
-{
- time_t t=time(0);
- short r;
- k_random_bytes((char*)&r, sizeof(r));
- unsigned char r1=(t >>24) & 255;
- unsigned char r2=(t >>16) & 255;
- unsigned char r3=(t >> 8) & 255;
- unsigned char r4=(t ) & 255;
- unsigned char r5=(r >> 8) & 255;
- unsigned char r6=(r ) & 255;
- snprintf(tmpbuf, TMPBUFSIZE, "%02x-%02x-%02x-%02x-%02x-%02x",
- r1, r2, r3, r4, r5, r6);
-}
-
-/* -}{----------------------------------------------------------------------- */
-
+++ /dev/null
-
-/* -------------------------------------------------------------------------- */
-
-#include <kernelapi.h>
-#include <ni.h>
-
-/* -------------------------------------------------------------------------- */
-
-#define WINDOW_WIDTH 640
-#define WINDOW_HEIGHT 480
-
-#define POS_ARRAY 0
-#define NORMAL_ARRAY 1
-#define TEXCOORD_ARRAY 2
-
-#define TEX_SIZE 128
-
-/* -------------------------------------------------------------------------- */
-
-static GLfloat xco= 0;
-static GLfloat yco= 1;
-static GLfloat zco= -35;
-static GLfloat view_rotx=0.0, view_roty=0.0, view_rotz=0.0;
-static int shift=0;
-
-GLuint program;
-GLuint texture;
-GLuint vbo;
-unsigned int numberOfVertices;
-unsigned int posStep;
-unsigned int normStep;
-unsigned int tcStep;
-unsigned int stride;
-float angle=0.0;
-float viewAngle = 0.0;
-
-/* -------------------------------------------------------------------------- */
-
-static int handles_resource(char* name);
-static void sync_resource(ni_resource* res);
-static void init_gl(void);
-static void reshape(int width, int height);
-static void draw(void);
-static void key(unsigned char k, int down);
-
-static int useTheProgram();
-static int setUpTnL();
-static int drawStuff(int width, int height);
-
-/* -------------------------------------------------------------------------- */
-
-EXPORT int mid_module_loaded(void)
-{
- ni_register_driver("mid", handles_resource, sync_resource);
-
- init_gl();
-
- k_gl_register_reshape(reshape);
- k_gl_register_draw(draw);
- k_gl_register_key(key);
-
- k_log_out("MID Driver initialised");
-
- return 1;
-}
-
-EXPORT int mid_module_event(void* data)
-{
- k_log_out("MID got event: %p", data);
- ni_event* evt=data;
- ni_event_delete(evt);
- return 1;
-}
-
-EXPORT int mid_module_tick(void)
-{
- if(!drawStuff(WINDOW_WIDTH, WINDOW_HEIGHT)) k_gl_end();
- return 1;
-}
-
-/* -------------------------------------------------------------------------- */
-
-int handles_resource(char* name)
-{
- return 0;
-}
-
-void sync_resource(ni_resource* res)
-{
-}
-
-/* -------------------------------------------------------------------------- */
-
-void init_gl(void)
-{
- if(!useTheProgram()) k_gl_end();
- if(!setUpTnL()) k_gl_end();
-}
-
-void reshape(int width, int height)
-{
-}
-
-void draw(void)
-{
- if(!drawStuff(WINDOW_WIDTH, WINDOW_HEIGHT)) k_gl_end();
-}
-
-#define SHIFT 0
-void key(unsigned char k, int down)
-{
- if(k == 113) viewAngle += 0.1;
- if(k == 114) viewAngle -= 0.1;
-
- if(k==SHIFT && down){ shift=1; return; }
- if(k==SHIFT && !down){ shift=0; return; }
- if(!down) return;
-
- if(shift) k-=('a'-'A');
-
- float speed=0.25;
- switch (k) {
- case 'H':
- xco-=speed*(float)sin((view_roty-90)*3.14/180);
- zco+=speed*(float)cos((view_roty-90)*3.14/180);
- if(xco< -35) xco= -35;
- if(xco> 35) xco= 35;
- if(zco< -35) zco= -35;
- if(zco> 35) zco= 35;
- break;
- case 'L':
- xco+=speed*(float)sin((view_roty-90)*3.14/180);
- zco-=speed*(float)cos((view_roty-90)*3.14/180);
- if(xco< -35) xco= -35;
- if(xco> 35) xco= 35;
- if(zco< -35) zco= -35;
- if(zco> 35) zco= 35;
- break;
- case 'i':
- xco-=speed*(float)sin(view_roty*3.14/180);
- zco+=speed*(float)cos(view_roty*3.14/180);
- if(xco< -35) xco= -35;
- if(xco> 35) xco= 35;
- if(zco< -35) zco= -35;
- if(zco> 35) zco= 35;
- break;
- case 'o':
- xco+=speed*(float)sin(view_roty*3.14/180);
- zco-=speed*(float)cos(view_roty*3.14/180);
- if(xco< -35) xco= -35;
- if(xco> 35) xco= 35;
- if(zco< -35) zco= -35;
- if(zco> 35) zco= 35;
- break;
- case 'j':
- yco-=speed;
- if(yco< 0.2) yco= 0.2;
- break;
- case 'k':
- yco+=speed;
- break;
- case 'l':
- view_roty += speed*20;
- break;
- case 'h':
- view_roty -= speed*20;
- break;
- case 'J':
- view_rotx += 2.0;
- break;
- case 'K':
- view_rotx -= 2.0;
- break;
- case 'z':
- view_rotz += 2.0;
- break;
- case 'Z':
- view_rotz -= 2.0;
- break;
- default:
- return;
- }
- draw();
-}
-
-/* ------------------------------------------------------------- */
-
-GLuint isShaderError(GLuint thing)
-{
- GLint isShader = glIsShader(thing);
-
- GLint ok;
- if(isShader){
- glGetShaderiv(thing, GL_COMPILE_STATUS, &ok);
- }else{
- glGetProgramiv(thing, GL_LINK_STATUS, &ok);
- }
- if(ok) return 0;
-
- GLint infoLen=0;
- if(isShader){
- glGetShaderiv(thing, GL_INFO_LOG_LENGTH, &infoLen);
- }else{
- glGetProgramiv(thing, GL_INFO_LOG_LENGTH, &infoLen);
- }
- if(infoLen){
- char* infoLog = malloc(sizeof(char)*infoLen);
- if(isShader){
- glGetShaderInfoLog(thing, infoLen, NULL, infoLog);
- }else{
- glGetProgramInfoLog(thing, infoLen, NULL, infoLog);
- }
- printf("%s: %s\n", isShader? "Shader compile": "Program link", infoLog);
- free(infoLog);
- }
- return 1;
-}
-
-char* file2string(const char *path)
-{
- FILE *fd;
- long len, r;
- char *str;
-
- if(!(fd=fopen(path, "r"))) {
- fprintf(stderr, "Can't open file '%s' for reading\n", path);
- return NULL;
- }
-
- fseek(fd, 0, SEEK_END);
- len = ftell(fd);
- fseek(fd, 0, SEEK_SET);
-
- if(!(str=malloc(len*sizeof(char)))) {
- fprintf(stderr, "Can't malloc space for '%s'\n", path);
- return NULL;
- }
-
- r = fread(str, sizeof(char), len, fd);
-
- str[r-1] = '\0';
-
- fclose(fd);
-
- return str;
-}
-
-/* ------------------------------------------------------------- */
-
-int useTheProgram()
-{
- const char *vsSource = file2string("tnl.vert");
- const char *fsSource = file2string("tnl.frag");
-
- GLuint vs = glCreateShader(GL_VERTEX_SHADER);
- glShaderSource(vs, 1, &vsSource, NULL);
- glCompileShader(vs);
- if(isShaderError(vs)) return 0;
-
- GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
- glShaderSource(fs, 1, &fsSource, NULL);
- glCompileShader(fs);
- if(isShaderError(fs)) return 0;
-
- free((void*)vsSource);
- free((void*)fsSource);
-
- program = glCreateProgram();
- glAttachShader(program, vs);
- glAttachShader(program, fs);
-
- glBindAttribLocation(program, POS_ARRAY, "vertPos");
- glBindAttribLocation(program, NORMAL_ARRAY, "vertNormal");
- /* vertNormal and vertTexCoord don't need to be bound here.. ? */
- glBindAttribLocation(program, TEXCOORD_ARRAY, "vertTexCoord");
-
- glLinkProgram(program);
- if(isShaderError(program)) return 0;
-
- glUseProgram(program);
-
- glUniform3f(glGetUniformLocation(program, "frameLightDirection"), 1.0, 0.0, 1.0);
- glUniform1i(glGetUniformLocation(program, "texture"), 0); /* 0 ?? */
-
- return 1;
-}
-
-int setUpTnL()
-{
- glClearColor(1.0f, 1.0f, 0.0f, 0.0f);
-
- glGenTextures(1, &texture);
- glBindTexture(GL_TEXTURE_2D, texture);
-
- GLuint* td = malloc(sizeof(GLuint)*TEX_SIZE*TEX_SIZE);
- int i,j;
- for(i=0; i<TEX_SIZE; i++)
- for(j=0; j<TEX_SIZE; j++) {
- GLuint col = (255L<<24) + ((255L-j*2)<<16) + ((255L-i)<<8) + (255L-i*2);
- if ( ((i*j)/8) % 2 ) col = (GLuint) (255L<<24) + (255L<<16) + (0L<<8) + (255L);
- td[j*TEX_SIZE+i] = col;
- }
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, TEX_SIZE, TEX_SIZE, 0, GL_RGBA, GL_UNSIGNED_BYTE, td);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
- free(td);
-
- GLfloat trivertices[] = {
- -0.4f,-0.4f,0.4f, // Pos
- 0.0f,0.0f,1.0f, // Normal
- 0.0f,0.0f, // TexCoord
-
- 0.4f,-0.0f,0.0f, // Pos
- 0.0f,0.0f,1.0f, // Normal
- 1.0f,0.0f, // TexCoord
-
- 0.0f,0.4f,0.4f, // Pos
- 0.5f,0.5f,0.5f, // Normal
- 0.5f,1.0f, // TexCoord
-
- 0.4f,0.0f,0.4f, // Pos
- 0.5f,0.5f,0.5f, // Normal
- 0.5f,0.0f, // TexCoord
-
- 0.4f,0.4f,0.4f, // Pos
- 0.0f,0.0f,1.0f, // Normal
- 0.0f,0.0f, // TexCoord
-
- };
-
- numberOfVertices = 4;
- posStep = 3 * sizeof(GLfloat);
- normStep = 3 * sizeof(GLfloat);
- tcStep = 2 * sizeof(GLfloat);
- stride = posStep + normStep + tcStep;
-
- glGenBuffers(1, &vbo);
- glBindBuffer(GL_ARRAY_BUFFER, vbo);
- glBufferData(GL_ARRAY_BUFFER, numberOfVertices * stride, trivertices, GL_STATIC_DRAW);
- glBindBuffer(GL_ARRAY_BUFFER, 0);
-
- return 1;
-}
-
-int drawStuff(int width, int height)
-{
- glViewport(0, 0, width, height);
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-
- float TransRotScaleVerticeMatrix[] = {
- cos(angle), 0, sin(angle), 0,
- 0, 1, 0, 0,
- -sin(angle), 0, cos(angle), 0,
- 0, 0, 0, 1
- };
-
- float ModelViewProjectionMatrix[] = {
- cos(viewAngle), 0, sin(viewAngle), 0,
- 0, 1, 0, 0,
- -sin(viewAngle), 0, cos(viewAngle), 0,
- 0, 0, 0, 1
- };
-
- float TransRotScaleNormalMatrix[] = {
- cos(angle), 0, sin(angle),
- 0, 1, 0,
- -sin(angle), 0, cos(angle)
- };
-
- glUniformMatrix4fv(glGetUniformLocation(program, "frameTRSV"), 1, GL_FALSE, TransRotScaleVerticeMatrix);
- glUniformMatrix4fv(glGetUniformLocation(program, "frameMVP"), 1, GL_FALSE, ModelViewProjectionMatrix);
- glUniformMatrix3fv(glGetUniformLocation(program, "frameTRSN"), 1, GL_FALSE, TransRotScaleNormalMatrix);
-
-
- glBindBuffer(GL_ARRAY_BUFFER, vbo);
-
- glEnableVertexAttribArray(POS_ARRAY);
- glVertexAttribPointer(POS_ARRAY, 3, GL_FLOAT, GL_FALSE, stride, 0);
-
- glEnableVertexAttribArray(NORMAL_ARRAY);
- glVertexAttribPointer(NORMAL_ARRAY, 3, GL_FLOAT, GL_FALSE, stride, (void*)posStep );
-
- glEnableVertexAttribArray(TEXCOORD_ARRAY);
- glVertexAttribPointer(TEXCOORD_ARRAY, 2, GL_FLOAT, GL_FALSE, stride, (void*)(posStep + normStep) );
-
- glDrawArrays(GL_TRIANGLE_STRIP, 0, numberOfVertices);
-
- glBindBuffer(GL_ARRAY_BUFFER, 0);
-
- k_gl_swap_buffers();
-
- angle += .007f;
-
- return 1;
-}
-
-void deleteStuff(){
- glDeleteTextures(1, &texture);
- glDeleteBuffers(1, &vbo);
- glDeleteProgram(program);
-/* glDeleteShader();
- glDeleteShader();*/
-}
-
-/* ------------------------------------------------------------- */
-
-
-
+++ /dev/null
-
-/* -------------------------------------------------------------------------- */
-
-#include <kernelapi.h>
-#include <ni.h>
-
-/* -------------------------------------------------------------------------- */
-
-static int handles_resource(char* name);
-static void sync_resource(ni_resource* res);
-
-static void start_tests(void);
-static void running_tests(ni_event* evt);
-
-static void test_state(n_object* o, char* os, char* uid, char* cont);
-
-/* -------------------------------------------------------------------------- */
-
-EXPORT int testni_module_loaded(void)
-{
- ni_register_driver("testni", handles_resource, sync_resource);
-
- k_log_out("Test NI Driver initialised");
-
- start_tests();
-
- return 1;
-}
-
-EXPORT int testni_module_event(void* data)
-{
- ni_event* evt=data;
-
- running_tests(evt);
-
- ni_event_delete(evt);
- return 1;
-}
-
-EXPORT int testni_module_tick(void)
-{
- return 1;
-}
-
-/* -------------------------------------------------------------------------- */
-
-int handles_resource(char* name)
-{
- return 1;
-}
-
-void sync_resource(ni_resource* res)
-{
-}
-
-/* -------------------------------------------------------------------------- */
-
-/*
- - object.create .update .commit .rollback (auto inc version #?)
- - object.see - may return empty so wait for ..
- - seestate(object) - state asked for /or/ object is subscribing
- */
-void start_tests(void)
-{
- k_log_out("Creating o11111");
-
- char* o11111s = "UID: 11111-4141a\n"
- "\n"
- "This: is one content\n";
-
- n_object* o11111 = n_object_new(o11111s);
-
- test_state(o11111, o11111s, "11111-4141a", "is one content");
-
- k_log_out("Committing o11111");
-
- n_commit(o11111);
-
- k_log_out("Creating o22222");
-
- char* o22222s = "UID: 22222-ef990\n"
- "\n"
- "This: is two content\n";
-
- n_object* o22222 = n_object_new(o22222s);
-
- test_state(o22222, o22222s, "22222-ef990", "is two content");
-
- n_object* o2 = n_see(o11111, "22222-ef990");
-
- k_assert(!o2, "Object 2 has not been committed yet, but Object 1 can see it:\n%s\n", n_to_string(o2));
-
- n_commit(o22222);
-
- o2 = n_see(o11111, "22222-ef990");
-
- k_assert(o2!=0, "Object 2 has been committed, but can't be seen by Object 1");
-
- test_state(o2, o22222s, "22222-ef990", "is two content");
-
- n_object* o3 = n_see(o22222, "33333-18bbc");
-
- k_assert(!o3, "Object 3 has not been created yet, but Object 2 can see it:\n%s", n_to_string(o3));
-}
-
-void running_tests(ni_event* evt)
-{
- char* o33333s =
- "UID: 33333-18bbc\n"
- "\n"
- "This: is three content\n";
-
- n_object* o33333 = n_object_new(o33333s);
-
- n_commit(o33333);
-
-}
-
-/* -------------------------------------------------------------------------- */
-
-void test_state(n_object* o, char* os, char* uid, char* cont)
-{
- char* c;
-
- k_log_out("Checking %s", uid);
-
- c=n_to_string(o);
- k_assert(c && !strcmp(c, os), "To-string was\n%s", c? c: "null");
-
- c=n_uid(o);
- k_assert(c && !strcmp(c, uid), "UID was %s in n_uid", c? c: "null");
-
- c=n_header(o, "UID");
- k_assert(c && !strcmp(c, uid), "UID was %s in n_header", c? c: "null");
-
- c=k_hashtable_get(n_headers(o), "UID");
- k_assert(c && !strcmp(c, uid), "UID was %s in hash get", c? c: "null");
-
- c=k_hashtable_get(n_content(o), "This");
- k_assert(c && !strcmp(c, cont), "Content was %s", c? c: "null");
-
- c=n_to_string(o);
- k_assert(c && !strcmp(c, os), "To-string was\n%s", c? c: "null");
-}
-
-/* -------------------------------------------------------------------------- */
-
-
-
--- /dev/null
+
+/* -}{----------------------------------------------------------------------- */
+
+#include <kernelapi.h>
+#include <notification.h>
+
+/* -}{----------------------------------------------------------------------- */
+
+extern void ensure_self_sub(ni_event* evq);
+
+/* -}{----------------------------------------------------------------------- */
+
+#define TMPBUFSIZE 4096
+static char tmpbuf[TMPBUFSIZE];
+
+/* -}{----------------------------------------------------------------------- */
+
+static void cache_read(char*, char*, char*, int, k_stat, void*);
+static void entity_written(char*, char*, char*, int, k_stat, void*);
+static void write_headers(char* path, ni_resource* res);
+static void headers_written(char*, char*, char*, int, k_stat, void*);
+
+
+/* -}{----------------------------------------------------------------------- */
+
+char* make_cache_path(char* uri)
+{
+ char* path;
+ size_t l=strlen(uri);
+ if(l>100){ k_log_out("URI too long to save: %s", uri); return 0; }
+ if(*(uri+l-1)!='/'){
+ path=k_strdup(uri);
+ }
+ else{
+ path=k_malloc(l+1+10);
+ sprintf(path, "%sindex.html", uri);
+ }
+ return path;
+}
+
+void look_in_file_cache(ni_event* evq)
+{
+ k_hashtable* sub=evq->ent_head;
+ char* uri=k_hashtable_get(sub, "Sub-To:");
+ size_t l=strlen(uri);
+
+ if(l>100){ ensure_self_sub(evq); return; }
+
+ char hdr[128];
+ if(*(uri+l-1)!='/') sprintf(hdr, "%s.hdr", uri);
+ else sprintf(hdr, "%sindex.html.hdr", uri);
+
+ if(strstr(hdr, "..")){ ensure_self_sub(evq); return; }
+ if(strchr(hdr, '?' )){ ensure_self_sub(evq); return; }
+
+ char* c=strchr(hdr, ':');
+ char* e=strchr(hdr, '/');
+ if(c && c< e) *c='-';
+
+ k_file_read(".", k_strdup(hdr), USE_MALL, 0, cache_read, evq);
+}
+
+void save_in_file_cache(ni_resource* res)
+{
+ char* uri =res->uri;
+ char* path =make_cache_path(uri); if(!path) return;
+ k_hashtable* ent_head=res->ent_head;
+ void* data =res->entity;
+ int partial =k_hashtable_is( ent_head, "Status:", "206");
+ size_t size =k_hashtable_get_int(ent_head, "Content-Length:");
+ char* conrange=k_hashtable_get( ent_head, "Content-Range:");
+ int constant=k_hashtable_is( ent_head, "CUX:", "C");
+
+ if(!data){
+ write_headers(path, res);
+ }
+ else
+ if(constant){
+ int ok=k_file_sync(data, size);
+ if(!ok){
+ k_log_err("Failed to write (sync mmap): %s", uri);
+ k_free(path);
+ return;
+ }
+ write_headers(path, res);
+ }
+ else{
+ if(partial){
+ k_log_out("save_in_file_cache partial %s", conrange);
+ if(!conrange || strncmp(conrange, "0-", 2)){
+ k_log_err("not saving partial");
+ k_free(path);
+ return;
+ }
+ size=atoi(conrange+2);
+ }
+ k_log_out("save_in_file_cache updateable: %d bytes", size);
+ k_file_write(".", path, data, size, entity_written, res);
+ }
+}
+
+/* -}{----------------------------------------------------------------------- */
+
+void entity_written(char* basedir,
+ char* path,
+ char* data,
+ int usedmmap,
+ k_stat kstat,
+ void* context)
+{
+ if(data) k_log_out("File cache entity written: %s", path);
+ else{
+ k_log_err("Failed to write entity: %s", path);
+ k_free(path);
+ return;
+ }
+ ni_resource* res=context;
+ write_headers(path, res);
+}
+
+void write_headers(char* path, ni_resource* res)
+{
+ snprintf(tmpbuf, TMPBUFSIZE, "%s.hdr", path);
+ k_free(path); path=k_strdup(tmpbuf);
+ k_hashtable_snprintf(res->ent_head, tmpbuf, TMPBUFSIZE);
+ k_file_write(".", path, tmpbuf, strlen(tmpbuf), headers_written, 0);
+}
+
+void headers_written(char* basedir,
+ char* path,
+ char* data,
+ int usedmmap,
+ k_stat kstat,
+ void* context)
+{
+ if(data) k_log_out("File cache headers written: %s", path);
+ else k_log_err("Failed to write headers: %s", path);
+ k_free(path);
+}
+
+void cache_read(char* basedir,
+ char* path,
+ char* data,
+ int usedmmap,
+ k_stat kstat,
+ void* context)
+{
+ if(!data) k_log_out("no cache of %s", path);
+ else k_log_out("file cache read: %d %s", kstat.size, path);
+ char* e=strstr(path, ".hdr");
+ if(e){
+ ni_event* evq=context;
+ if(!data){ k_free(path); ensure_self_sub(evq); return; }
+
+ char* header=data;
+ *(header+kstat.size-2)=0;
+ k_hashtable* ent_head=k_hashtable_new("nHeaders/cache_read", 1);
+ k_hashtable_put(ent_head, "", header);
+ if(!ni_get_headers(header, 0, ent_head)){
+ k_hashtable_delete(ent_head);
+ k_free(path);
+ ensure_self_sub(evq);
+ return;
+ }
+ ni_event_delete(evq);
+ *e=0;
+ ni_event* evt=ni_event_new(0, 0, ent_head, 0);
+ int constant=k_hashtable_is(ent_head, "CUX:", "C");
+ size_t m=constant? USE_MMAP: USE_MALL;
+ k_file_read(".", path, m, 0, cache_read, evt);
+ return;
+ }
+ ni_event* evt=context;
+ k_free(path);
+ evt->entity=data;
+ ni_event_show(evt, "File Cache Found:");
+ k_event_post("on", evt);
+}
+
+/* -}{----------------------------------------------------------------------- */
+
+
--- /dev/null
+
+/* -}{----------------------------------------------------------------------- */
+
+#include <kernelapi.h>
+#include <notification.h>
+
+/* -}{----------------------------------------------------------------------- */
+
+#define TMPBUFSIZE 4096
+static char tmpbuf[TMPBUFSIZE];
+static k_hashtable* own_resources;
+
+/* -}{----------------------------------------------------------------------- */
+
+extern void run_tests(void);
+
+extern char* make_cache_path(char* uri);
+extern void look_in_file_cache(ni_event* evq);
+extern void save_in_file_cache(ni_resource* res);
+
+extern void init_uri2chan(void);
+extern char* get_host_for(char* uri);
+extern char* get_channel_for(char* host);
+extern char* use_ping_info(k_hashtable*, k_channel*);
+extern void use_from_info(k_hashtable*, k_channel*);
+extern void ping_tunnels(void);
+extern void send_ping(k_channel* chan, char* firstline, char* to);
+
+/* -}{----------------------------------------------------------------------- */
+
+static int handles_resource(char* name);
+static void sync_resource(ni_resource* res);
+ int connection_writable(k_channel* chan, int bufpos, int len);
+ int connection_readable(k_channel* chan, int bufpos, int len);
+static int recv_next_event( k_channel* chan);
+static void recv_request( k_channel* chan, char* header);
+static void recv_response( k_channel* chan, char* header);
+static void got_mmap(char*, char*, char*, int, k_stat, void*);
+static void set_read_buffer(k_channel*, char*, size_t, ni_event*);
+static int recv_entity( k_channel* chan, int bufpos, int eof);
+static int expecting_response(char* pub, ni_event* evt, k_channel*);
+static void do_request( ni_event* evq);
+ void ensure_self_sub(ni_event* evq);
+static void ping_resource_subs(void* arg, char* key, void* val);
+static void ping_sub(ni_resource* res, k_hashtable* sub);
+static ni_resource* own_resource(char* uri);
+static void send_request(ni_event* evq);
+static void send_response(ni_event* evt);
+static k_channel* ensure_chan(char* chanm);
+
+/* -}{----------------------------------------------------------------------- */
+
+EXPORT int op_module_loaded(void)
+{
+ ni_register_driver("op", handles_resource, sync_resource);
+
+ if(strstr(k_version, "test")){
+ //run_tests();
+ }
+
+ init_uri2chan();
+
+ own_resources=k_hashtable_new("Own Resources", 0);
+
+ k_log_out("OP Driver initialised");
+
+ return 0;
+}
+
+EXPORT void op_module_tick(void)
+{
+ static long tix;
+ tix++;
+ if(!(tix % 1000)){
+ k_hashtable_apply(own_resources, ping_resource_subs, 0);
+ }
+ if(!(tix % 3000)){
+ ping_tunnels();
+ }
+}
+
+EXPORT int op_module_event(void* data)
+{
+ ni_event* evt=data;
+ if(!k_hashtable_get(evt->ent_head, "Status:")){
+ do_request(evt);
+ }
+ else{
+ send_response(evt);
+ }
+ return 0;
+}
+
+/* -}{----------------------------------------------------------------------- */
+
+int handles_resource(char* name)
+{
+ return 0;
+}
+
+void sync_resource(ni_resource* res)
+{
+ save_in_file_cache(res);
+}
+
+/* -}{----------------------------------------------------------------------- */
+
+int connection_readable(k_channel* chan, int bufpos, int len)
+{
+ if(0) k_log_out("connection_readable %s %p %d %d %p",
+ chan->name, chan, bufpos, len, chan->context);
+ int sof=(len== 0);
+ int eof=(len== -1);
+
+ if(sof) return 0;
+
+ do{
+ ni_event* evt=chan->context;
+ if(!evt){
+ int n=recv_next_event(chan);
+ if(n<0) break;
+ bufpos-=n;
+ }
+ else{
+ int n=recv_entity(chan, bufpos, eof);
+ if(n<0) break;
+ bufpos-=n;
+ }
+
+ } while(1);
+
+ if(eof && chan->context){
+ ni_event* evt=chan->context;
+ evt->entity=0;
+ ni_event_delete(evt);
+ chan->context=0;
+ }
+
+ return 0;
+}
+
+int connection_writable(k_channel* chan, int bufpos, int len)
+{
+ if(0) k_log_out("connection_writable %p %d %d %p",
+ chan, bufpos, len, chan->context);
+//if(len>20000) exit(1);
+ int sof=(len== 0);
+ int eof=(len== -1);
+
+ if(sof){
+ send_ping(chan, "PING OP/0.5", 0);
+ return 0;
+ }
+
+ if(eof && chan->context){
+ ni_event* evt=chan->context;
+ evt->entity=0;
+ ni_event_delete(evt);
+ chan->context=0;
+ }
+
+ return 0;
+}
+
+/* -}{---- Receiving -------------------------------------------------------- */
+
+int recv_next_event(k_channel* chan)
+{
+ char* header=k_channel_chop_div(chan, CRLF CRLF);
+ if(!header) return -1;
+ int n=strlen(header)+strlen(CRLF CRLF);
+
+ if(!strncmp(header, "GET", 3) ||
+ !strncmp(header, "SUB", 3) ||
+ !strncmp(header, "UNSUB",5) ||
+ !strncmp(header, "HEAD", 4) ||
+ !strncmp(header, "PING", 4) ){
+
+ recv_request(chan, header);
+ return n;
+ }
+ if(!strncmp(header, "OP/", 4) ){
+
+ recv_response(chan, header);
+ return n;
+ }
+ k_free(header);
+ k_log_err("Failed reading request or response - closing connection");
+ k_channel_close(chan);
+ return n;
+}
+
+void recv_request(k_channel* chan, char* header)
+{
+ ni_event* evq;
+ evq=ni_get_request_headers(header);
+ if(!evq){
+ k_log_err("Failed reading request headers - closing connection");
+ k_channel_close(chan);
+ return;
+ }
+ if(!k_hashtable_isn(evq->evt_head, "Protocol:", "OP/", 4)){
+ ni_event_delete(evq);
+ k_log_err("Failed reading request not OP - closing connection");
+ k_channel_close(chan);
+ return;
+ }
+
+ k_hashtable* ent_head=evq->ent_head;
+ int ping=k_hashtable_is(ent_head, "Method:", "PING");
+
+ if(!evq->uri && !ping){
+ evq->uri=k_strdup(chan->name);
+ k_hashtable_put_dup(ent_head, "URI:", chan->name);
+ }
+
+ ni_event_show(evq, "OP Protocol Request");
+
+ if(k_hashtable_isi(evq->evt_head, "Connection:", "Keep-Alive")){
+ chan->linger=1;
+ if(k_hashtable_isn(ent_head, "Sub-To:", "./test", 6)){
+ chan->linger=0;
+ }
+ }
+ if(ping){
+ char* from=use_ping_info(ent_head, chan);
+ if(from) send_ping(chan, "OP/0.5 270 PING", from);
+ ni_event_delete(evq);
+ return;
+ }
+ //use_from_info(ent_head, chan);
+
+ ni_event* evp=ni_event_new(evq->uri, 0, k_hashtable_dup(ent_head), 0);
+
+ ni_event_delete(evq);
+
+ k_event_post("on", evp);
+}
+
+void recv_response(k_channel* chan, char* header)
+{
+ ni_event* evt=ni_get_response_headers(header);
+ if(!evt){
+ k_log_err("recv_response: headers failed but doing nothing!");
+ return;
+ }
+ char* pub= evt->uri;
+ k_hashtable* ent_head=evt->ent_head;
+
+ if(!expecting_response(pub, evt, chan)) return;
+
+ ni_event_show(evt, "Response");
+
+ int head=k_hashtable_is( ent_head, "Status:", "260");
+ int nmod=k_hashtable_is( ent_head, "Status:", "304");
+ int ping=k_hashtable_is( ent_head, "Status:", "270");
+ int cl =k_hashtable_get_int(ent_head, "Content-Length:");
+ int entity=!(head || nmod || ping || cl==0);
+
+ if(ping){
+ use_ping_info(ent_head, chan);
+ ni_event_delete(evt);
+ return;
+ }
+ use_from_info(ent_head, chan);
+
+ if(entity){
+ k_hashtable_set(ent_head, "Status:", "260");
+ k_hashtable_set(ent_head, "Status-Text:", "Headers Only");
+ }
+ k_event_post("on", evt);
+
+ if(entity){
+
+ k_hashtable* eh=k_hashtable_new("nHeaders/recv_response", 1);
+ char* from =k_hashtable_get(ent_head, "From:");
+ char* contlen =k_hashtable_get(ent_head, "Content-Length:");
+ char* cux =k_hashtable_get(ent_head, "CUX:");
+ k_hashtable_set(eh, "Status:", "206");
+ k_hashtable_set(eh, "Status-Text:", "Partial Content");
+ k_hashtable_put_dup(eh, "From:", from);
+ k_hashtable_put_dup(eh, "Content-Length:", contlen);
+ k_hashtable_put_dup(eh, "CUX:", cux);
+ ni_event* evc=ni_event_new(pub, 0, eh, 0);
+ chan->context=evc;
+
+ int constant=k_hashtable_is(ent_head, "CUX:", "C");
+ if(constant){
+ char* path=make_cache_path(pub); if(!path) return;
+ k_file_read(".", path, USE_MMAP, cl, got_mmap, chan);
+ }
+ else{
+ char* data=k_malloc(cl);
+ set_read_buffer(chan, data, cl, evc);
+ }
+ }
+}
+
+void got_mmap(char* basedir,
+ char* path,
+ char* data,
+ int usedmmap,
+ k_stat kstat,
+ void* context){
+
+ k_free(path);
+ k_channel* chan=context;
+ ni_event* evt=chan->context;
+ if(!evt){ k_log_err("got_mmap: evt=0"); return; }
+ if(!data || !usedmmap){ k_log_err("got_mmap: mmap failed"); return; }
+
+ size_t cl=k_hashtable_get_int(evt->ent_head, "Content-Length:");
+ set_read_buffer(chan, data, cl, evt);
+}
+
+void set_read_buffer(k_channel* chan, char* data, size_t cl, ni_event* evt)
+{
+ evt->entity=data;
+ int r=k_channel_setbuf(chan, data, cl);
+ if(0) k_log_out("k_channel_setbuf %d", r);
+ if(r==BUFFER_ALREADY_SET){
+ k_log_err("oops! k_channel_setbuf BUFFER_ALREADY_SET");
+ return;
+ }
+ if(r==BUFFER_FILLED){
+ k_hashtable_set(evt->ent_head, "Status:", "200");
+ k_hashtable_set(evt->ent_head, "Status-Text:", "OK");
+ chan->context=0;
+ k_event_post("on", evt);
+ }
+}
+
+int recv_entity(k_channel* chan, int bufpos, int eof)
+{
+ ni_event* evt=chan->context;
+ k_hashtable* ent_head=evt->ent_head;
+
+ char* cls=k_hashtable_get( ent_head, "Content-Length:");
+ int cl =k_hashtable_get_int(ent_head, "Content-Length:");
+
+ if(!cls && !eof) return -1;
+
+ int partial=0;
+ int eofcontlen=eof && (!cls || bufpos < cl);
+ if(eofcontlen){
+ if(cls){
+ char* clg=k_strdup(cls);
+ k_hashtable_put(ent_head, "Content-Length-Given:", clg);
+ partial=1;
+ }
+ cl=bufpos;
+ char b[32]; snprintf(b, 32, "%d", cl);
+ k_hashtable_put_dup(ent_head, "Content-Length:", b);
+ }
+
+ if(bufpos < cl){
+ if(bufpos){
+ ni_event* evp=ni_event_dup(evt);
+ snprintf(tmpbuf, TMPBUFSIZE, "0-%d", bufpos);
+ char* cr=k_strdup(tmpbuf);
+ k_hashtable_put(evp->ent_head, "Content-Range:", cr);
+ k_event_post("on", evp);
+ }
+ return -1;
+ }
+
+ static char dummy_empty_entity[0];
+ if(!k_channel_getbuf(chan)){
+ int cn=k_hashtable_is(ent_head, "CUX:", "C");
+ if(cl) evt->entity=k_channel_chop_len(chan, cl);
+ else evt->entity=cn? dummy_empty_entity: k_malloc(1);
+ }
+
+ if(!partial){
+ k_hashtable_set(ent_head, "Status:", "200");
+ k_hashtable_set(ent_head, "Status-Text:", "OK");
+ }
+ chan->context=0;
+ k_event_post("on", evt);
+
+ return cl;
+}
+
+int expecting_response(char* pub, ni_event* evt, k_channel* chan)
+{
+ if(pub && 0){
+ k_log_err("unwanted response: %s", pub);
+ ni_event_delete(evt);
+ k_channel_close(chan);
+ return 0;
+ }
+ return 1;
+}
+
+/* -}{---- Sending ---------------------------------------------------------- */
+
+void do_request(ni_event* evq)
+{
+ k_hashtable* sub=evq->ent_head;
+ int tc=k_hashtable_isi(sub, "Sub-Type:", "Cache");
+ int to=k_hashtable_isi(sub, "Sub-Type:", "Original");
+
+ if(tc){
+ char* ims=k_hashtable_get(sub, "If-Modified-Since:");
+ if(ims) ensure_self_sub(evq);
+ else look_in_file_cache(evq);
+ }
+ else
+ if(to){
+ send_request(evq);
+ }
+}
+
+void ensure_self_sub(ni_event* evq)
+{
+ k_hashtable* sub=evq->ent_head;
+ char* pub=k_hashtable_get(sub, "Sub-To:");
+
+ ni_resource* res=own_resource(pub);
+ k_hashtable* enh=res->ent_head;
+ k_hashtable* selfsub=k_hashtable_get(enh, "Sub-To:");
+ if(selfsub && !k_hashtable_is(selfsub, "Status-Cache:", "OK")){
+ k_log_err("cancel selfsub as new one needed");
+ }
+
+ k_hashtable* ss=k_hashtable_dup(sub);
+ k_hashtable_remove( ss, "From:");
+ k_hashtable_put_dup(ss, "URI:", pub);
+ k_hashtable_set( ss, "Sub-Type:", "Original");
+ k_hashtable_put_dup(ss, "Via:", get_host_for(pub));
+ if(k_hashtable_get( ss, "If-Modified-Since:")){
+ char* lm=k_hashtable_get(enh, "Last-Modified:");
+ if(!res->entity) lm=0;
+ k_hashtable_set(ss, "If-Modified-Since:", lm? lm: "0");
+ }
+ ni_event* evs=ni_event_new(0, 0, ss, 0);
+ k_event_post("on", evs);
+
+ ni_event_delete(evq);
+}
+
+void ping_resource_subs(void* arg, char* key, void* val)
+{
+ ni_resource* res=val;
+ k_hashtable* pubcache=k_hashtable_get(res->ent_head, "Pub-Cache:");
+ if(!pubcache || !k_hashtable_get(pubcache, "Method:")) return;
+ k_hashtable* subs=k_hashtable_get(res->ent_head, "Sub-To:");
+ k_hashtable* sub;
+ for(sub=subs; sub; sub=sub->next){
+ if(!k_hashtable_is(sub, "Status-Cache:", "OK")){
+ if(!k_hashtable_get(sub, "Status:")){
+ ping_sub(res, sub);
+ }
+ else{
+ int ts=k_hashtable_get_int(sub, "Timestamp:");
+ if(0) k_log_out("check dried-up request: %d", ts);
+ }
+ }
+ }
+}
+
+void ping_sub(ni_resource* res, k_hashtable* sub)
+{
+ ni_resource_show(res, "ping_resource_subs");
+
+ k_hashtable* ss=k_hashtable_dup(sub);
+
+ char* subto=k_hashtable_extract(ss, "URI:");
+ k_hashtable_put_dup(ss, "URI:", res->uri);
+ k_hashtable_put( ss, "Sub-To:", subto);
+ k_hashtable_set( ss, "Sub-Type:", "Original");
+ k_hashtable_put_dup(ss, "Via:", get_host_for(res->uri));
+
+ ni_event* evs=ni_event_new(0, 0, ss, 0);
+ k_event_post("on", evs);
+}
+
+ni_resource* own_resource(char* uri)
+{
+ ni_resource* res=k_hashtable_get(own_resources, uri);
+ if(!res){
+ res=ni_resource_get(uri);
+ k_hashtable_set(own_resources, uri, res);
+ }
+ return res;
+}
+
+void send_request(ni_event* evt)
+{
+ k_hashtable* eh=evt->ent_head;
+ char* method=k_strdup(k_hashtable_get(eh, "Method:"));
+ char* to =k_strdup(k_hashtable_get(eh, "Sub-To:"));
+ char* via =k_strdup(k_hashtable_get(eh, "Via:"));
+
+ char* chanm=get_channel_for(via);
+ if(!chanm) goto free_and_return;
+
+ k_channel* chan=ensure_chan(chanm);
+ if(!chan) goto free_and_return;
+
+ ni_fix_ni_headers(eh, 0);
+ ni_request(evt, to, method, chan);
+
+ free_and_return:
+ k_free(method); k_free(to); k_free(via);
+ ni_event_delete(evt);
+}
+
+void send_response(ni_event* evt)
+{
+ ni_event_show(evt, "send_response");
+
+ k_hashtable* eh=evt->ent_head;
+
+ k_hashtable* sub=k_hashtable_get(eh, "Pub-To:");
+ char* uri =k_hashtable_get(sub, "URI:");
+ char* from =k_hashtable_get(sub, "From:");
+ char* method =k_hashtable_get(sub, "Method:");
+ int methead =k_hashtable_is( sub, "Method:", "HEAD");
+
+ char* to=from? from: uri;
+
+ char* host=from? from: get_host_for(uri);
+ char* chanm=get_channel_for(host);
+ if(!chanm){
+ if(0) k_log_out("no OP protocol channel %s", to);
+ ni_event_delete(evt);
+ return;
+ }
+
+ k_channel* chan=ensure_chan(chanm);
+ if(!chan){
+ if(0) k_log_out("no OP protocol channel %s", to);
+ ni_event_delete(evt);
+ return;
+ }
+
+ k_hashtable_extract(eh, "Pub-To:");
+
+ char* protocol="OP/0.5";
+
+ ni_fix_ni_headers(eh, methead);
+ ni_response(evt, to, method, protocol, 0, chan);
+
+ k_hashtable_delete(sub);
+ evt->entity=0;
+ ni_event_delete(evt);
+}
+
+k_channel* ensure_chan(char* chanm)
+{
+ k_channel* chan=k_channel_get_name(chanm);
+ if(!chan){
+ k_log_err("Cannot find current channel for %s", chanm);
+ k_channel_connect_name(chanm, connection_readable,
+ connection_writable);
+ }
+ return chan;
+}
+
+/* -}{----------------------------------------------------------------------- */
+
--- /dev/null
+
+/* -}{----------------------------------------------------------------------- */
+
+#include <kernelapi.h>
+#include <notification.h>
+
+/* -}{----------------------------------------------------------------------- */
+
+extern int connection_writable(k_channel* chan, int bufpos, int len);
+extern int connection_readable(k_channel* chan, int bufpos, int len);
+
+/* -}{----------------------------------------------------------------------- */
+
+#define TMPBUFSIZE 4096
+static char tmpbuf[TMPBUFSIZE];
+static int is_np;
+static char* nexus_channel;
+static k_hashtable* chans_for_host;
+
+/* -}{----------------------------------------------------------------------- */
+
+static void nexus_file_read(char*, char*, char*, int, k_stat, void*);
+static void write_nexus(char* hostname);
+static void nexus_file_written(char*, char*, char*, int, k_stat, void*);
+static int root_nexus(void);
+static void listen_http(void);
+static void listen_nexus(void);
+static void connect_to_nexus(void);
+static void ping_this(void* arg, char* key, void* val);
+static char* generate_new_hostname(k_hashtable* ent_head, k_channel* chan);
+static void set_channel_for(char* host, char* chanm);
+static void show_np(void);
+static void show_list(void* arg, char* key, void* val);
+
+/* -}{----------------------------------------------------------------------- */
+
+void init_uri2chan(void)
+{
+ chans_for_host =k_hashtable_new("Channels for Host", 0);
+
+ k_file_read(".", "nexus.txt", USE_MALL, 0, nexus_file_read, 0);
+
+ is_np=!strcmp(k_ciux, "op");
+ if(is_np) listen_nexus();
+ if(root_nexus()){
+ k_log_out("root nexus - but listening on http");
+ listen_http();
+ }
+ else{
+ k_log_out("connecting to nexus %s", nexus_channel);
+ connect_to_nexus();
+ }
+}
+
+char* get_host_for(char* uri)
+{
+ if(0) k_log_out("get_host_for %s", uri);
+ char* host=0;
+ if(0) k_log_out("host for %s=%s", uri, host);
+ return host;
+}
+
+char* get_channel_for(char* host)
+{
+ if(0) k_log_out("get_channel_for %s", host);
+ char* chanm=k_hashtable_get(chans_for_host, host);
+ if(!chanm){
+ }
+ if(0) k_log_out("channel for %s=%s", host, chanm);
+ return chanm;
+}
+
+char* use_ping_info(k_hashtable* ent_head, k_channel* chan)
+{
+ char* from=k_hashtable_get(ent_head, "From:");
+ char* to =k_hashtable_get(ent_head, "To:");
+
+ if(!from) return 0;
+ if(!strcmp(from, "-")) from=generate_new_hostname(ent_head, chan);
+ if(!from) return 0;
+ if(!ni_hostname() && to) write_nexus(to);
+
+ set_channel_for(from, chan->name);
+
+ if(0) k_log_out("%s PING %s", chan->name, from);
+ if(0) show_np();
+
+ return from;
+}
+
+void use_from_info(k_hashtable* ent_head, k_channel* chan)
+{
+ char* from=k_hashtable_get(ent_head, "From:");
+
+ if(!from) return;
+
+ set_channel_for(from, chan->name);
+
+ if(0) show_np();
+}
+
+void ping_tunnels(void)
+{
+ k_hashtable* channelspinged=k_hashtable_new("channelspinged", 0);
+ k_hashtable_apply(chans_for_host, ping_this, channelspinged);
+ k_hashtable_delete(channelspinged);
+}
+
+void send_ping(k_channel* chan, char* firstline, char* to)
+{
+ char* from=ni_hostname();
+ if(!from) from="-";
+
+ int ln=0;
+ int bufsize=TMPBUFSIZE;
+
+ ln+=snprintf(tmpbuf+ln, bufsize-ln, "%s" CRLF, firstline);
+ if(ln>=bufsize) return;
+ ln+=snprintf(tmpbuf+ln, bufsize-ln, "From: %s" CRLF, from);
+ if(ln>=bufsize) return;
+ if(to){
+ ln+=snprintf(tmpbuf+ln, bufsize-ln, "To: %s" CRLF, to);
+ if(ln>=bufsize) return;
+ }
+ ln+=snprintf(tmpbuf+ln, bufsize-ln, "Server: %s" CRLF, k_version);
+ if(ln>=bufsize) return;
+ ln+=snprintf(tmpbuf+ln, bufsize-ln, "Channels: %s" CRLF, "-");
+ if(ln>=bufsize) return;
+ ln+=snprintf(tmpbuf+ln, bufsize-ln, CRLF);
+ if(ln>=bufsize) return;
+
+ char* head=k_strdup(tmpbuf);
+ k_channel_send(chan, head, ln, FREE_ON_SENT);
+}
+
+/* -}{----------------------------------------------------------------------- */
+
+void nexus_file_read(char* basedir,
+ char* filepath,
+ char* data,
+ int usedmmap,
+ k_stat kstat,
+ void* context)
+{
+ int L=0;
+ if(data) data[kstat.size-1]=0;
+ else data=k_strdup("");
+ k_hashtable* nex=k_hashtable_new("nexus", 1);
+ if(!ni_get_headers(data, nex, 0)){
+ k_log_err("Corrupt nexus.txt file");
+ k_hashtable_delete(nex);
+ k_free(data);
+ data=k_strdup("");
+ nex=k_hashtable_new("nexus", 1);
+ ni_get_headers(data, nex, 0);
+ }
+
+ char* hostname;
+ nexus_channel=k_hashtable_get_dup(nex, "Nexus-Channel:");
+ hostname =k_hashtable_get( nex, "Hostname:");
+
+ if(hostname) ni_hostname_set(hostname);
+
+ if(L) if(nexus_channel) k_log_out("Nexus-Channel: %s", nexus_channel);
+ if(L) if(hostname) k_log_out("Hostname: %s", hostname);
+
+ k_hashtable_delete(nex);
+ k_free(data);
+}
+
+void write_nexus(char* hostname)
+{
+ ni_hostname_set(hostname);
+
+ snprintf(tmpbuf, TMPBUFSIZE, "Nexus-Channel: %s\r\n"
+ "Hostname: %s\r\n", nexus_channel,
+ hostname);
+
+ k_file_write(".", "nexus.txt", tmpbuf, strlen(tmpbuf),
+ nexus_file_written, 0);
+}
+
+void nexus_file_written(char* basedir,
+ char* filepath,
+ char* data,
+ int usedmmap,
+ k_stat kstat,
+ void* context)
+{
+ if(!data) k_fatal("Failed to write nexus.txt");
+ else k_log_out("New nexus.txt written:\n%s", data);
+}
+
+int root_nexus(void)
+{
+ char* hostname=ni_hostname();
+ if(!hostname || strchr(hostname, '-')) return 0;
+ return 1;
+}
+
+void listen_http(void)
+{
+ char* chanm="|nip-server|-|8081|-|";
+ k_channel_connect_name(chanm, connection_readable,
+ connection_writable);
+}
+
+void listen_nexus(void)
+{
+ char* chanm="|nip-server|-|7747|-|";
+ k_channel_connect_name(chanm, connection_readable,
+ connection_writable);
+}
+
+void connect_to_nexus(void)
+{
+ if(nexus_channel){
+ k_channel_connect_name(nexus_channel, connection_readable,
+ connection_writable);
+ }
+ else k_log_out("discovery of nexus not implemented yet!");
+}
+
+void ping_this(void* arg, char* key, void* val)
+{
+ k_hashtable* channelspinged=arg;
+ char* chanm=val;
+
+ if(strncmp(chanm, "nip-client", 11) ) return;
+ if(k_hashtable_get(channelspinged, chanm)) return;
+ k_hashtable_set(channelspinged, chanm, chanm);
+
+ k_channel* chan=k_channel_get_name(chanm);
+ //k_log_out("ping_this: host %s channel %s got=%p", key, chanm, chan);
+
+ if(!chan) k_channel_connect_name(chanm, connection_readable,
+ connection_writable);
+
+ int pingtodeath=0;
+ if(chan && pingtodeath) send_ping(chan, "PING OP/0.5", 0);
+}
+
+char* generate_new_hostname(k_hashtable* ent_head, k_channel* chan)
+{
+ if(!ni_hostname()) return 0;
+ unsigned long a=chan->clientip.s_addr;
+ #define IPQUAD(a) \
+ ((unsigned char *)&a)[0], \
+ ((unsigned char *)&a)[1], \
+ ((unsigned char *)&a)[2], \
+ ((unsigned char *)&a)[3]
+ snprintf(tmpbuf, TMPBUFSIZE, "%s-%02x%02x%02x%02x.%d",
+ ni_hostname(), IPQUAD(a), 7747);
+ if(0) k_log_out("generated new hostname: %s\n", tmpbuf);
+ return k_strdup(tmpbuf);
+}
+
+/* -}{----------------------------------------------------------------------- */
+
+void set_channel_for(char* host, char* chanm)
+{
+ k_hashtable_put_dup(chans_for_host, host, chanm);
+}
+
+void show_np(void)
+{
+ k_log_out("-------- channel for host ---------------");
+ k_hashtable_apply(chans_for_host, show_list, 0);
+ k_channel_show_all();
+}
+
+void show_list(void* arg, char* key, void* val)
+{
+ char* chanm=val;
+ k_log_out("%s %s", key, chanm);
+}
+
+void generate_random(void)
+{
+ time_t t=time(0);
+ short r;
+ k_random_bytes((char*)&r, sizeof(r));
+ unsigned char r1=(t >>24) & 255;
+ unsigned char r2=(t >>16) & 255;
+ unsigned char r3=(t >> 8) & 255;
+ unsigned char r4=(t ) & 255;
+ unsigned char r5=(r >> 8) & 255;
+ unsigned char r6=(r ) & 255;
+ snprintf(tmpbuf, TMPBUFSIZE, "%02x-%02x-%02x-%02x-%02x-%02x",
+ r1, r2, r3, r4, r5, r6);
+}
+
+/* -}{----------------------------------------------------------------------- */
+
--- /dev/null
+
+/* -------------------------------------------------------------------------- */
+
+#include <kernelapi.h>
+#include <notification.h>
+
+/* -------------------------------------------------------------------------- */
+
+#define WINDOW_WIDTH 640
+#define WINDOW_HEIGHT 480
+
+#define POS_ARRAY 0
+#define NORMAL_ARRAY 1
+#define TEXCOORD_ARRAY 2
+
+#define TEX_SIZE 128
+
+/* -------------------------------------------------------------------------- */
+
+static GLfloat xco= 0;
+static GLfloat yco= 1;
+static GLfloat zco= -35;
+static GLfloat view_rotx=0.0, view_roty=0.0, view_rotz=0.0;
+static int shift=0;
+
+GLuint program;
+GLuint texture;
+GLuint vbo;
+unsigned int numberOfVertices;
+unsigned int posStep;
+unsigned int normStep;
+unsigned int tcStep;
+unsigned int stride;
+float angle=0.0;
+float viewAngle = 0.0;
+
+/* -------------------------------------------------------------------------- */
+
+static int handles_resource(char* name);
+static void sync_resource(ni_resource* res);
+static void init_gl(void);
+static void reshape(int width, int height);
+static void draw(void);
+static void key(unsigned char k, int down);
+
+static int useTheProgram();
+static int setUpTnL();
+static int drawStuff(int width, int height);
+
+/* -------------------------------------------------------------------------- */
+
+EXPORT int mid_module_loaded(void)
+{
+ ni_register_driver("mid", handles_resource, sync_resource);
+
+ init_gl();
+
+ k_gl_register_reshape(reshape);
+ k_gl_register_draw(draw);
+ k_gl_register_key(key);
+
+ k_log_out("MID Driver initialised");
+
+ return 1;
+}
+
+EXPORT int mid_module_event(void* data)
+{
+ k_log_out("MID got event: %p", data);
+ ni_event* evt=data;
+ ni_event_delete(evt);
+ return 1;
+}
+
+EXPORT int mid_module_tick(void)
+{
+ if(!drawStuff(WINDOW_WIDTH, WINDOW_HEIGHT)) k_gl_end();
+ return 1;
+}
+
+/* -------------------------------------------------------------------------- */
+
+int handles_resource(char* name)
+{
+ return 0;
+}
+
+void sync_resource(ni_resource* res)
+{
+}
+
+/* -------------------------------------------------------------------------- */
+
+void init_gl(void)
+{
+ if(!useTheProgram()) k_gl_end();
+ if(!setUpTnL()) k_gl_end();
+}
+
+void reshape(int width, int height)
+{
+}
+
+void draw(void)
+{
+ if(!drawStuff(WINDOW_WIDTH, WINDOW_HEIGHT)) k_gl_end();
+}
+
+#define SHIFT 0
+void key(unsigned char k, int down)
+{
+ if(k == 113) viewAngle += 0.1;
+ if(k == 114) viewAngle -= 0.1;
+
+ if(k==SHIFT && down){ shift=1; return; }
+ if(k==SHIFT && !down){ shift=0; return; }
+ if(!down) return;
+
+ if(shift) k-=('a'-'A');
+
+ float speed=0.25;
+ switch (k) {
+ case 'H':
+ xco-=speed*(float)sin((view_roty-90)*3.14/180);
+ zco+=speed*(float)cos((view_roty-90)*3.14/180);
+ if(xco< -35) xco= -35;
+ if(xco> 35) xco= 35;
+ if(zco< -35) zco= -35;
+ if(zco> 35) zco= 35;
+ break;
+ case 'L':
+ xco+=speed*(float)sin((view_roty-90)*3.14/180);
+ zco-=speed*(float)cos((view_roty-90)*3.14/180);
+ if(xco< -35) xco= -35;
+ if(xco> 35) xco= 35;
+ if(zco< -35) zco= -35;
+ if(zco> 35) zco= 35;
+ break;
+ case 'i':
+ xco-=speed*(float)sin(view_roty*3.14/180);
+ zco+=speed*(float)cos(view_roty*3.14/180);
+ if(xco< -35) xco= -35;
+ if(xco> 35) xco= 35;
+ if(zco< -35) zco= -35;
+ if(zco> 35) zco= 35;
+ break;
+ case 'o':
+ xco+=speed*(float)sin(view_roty*3.14/180);
+ zco-=speed*(float)cos(view_roty*3.14/180);
+ if(xco< -35) xco= -35;
+ if(xco> 35) xco= 35;
+ if(zco< -35) zco= -35;
+ if(zco> 35) zco= 35;
+ break;
+ case 'j':
+ yco-=speed;
+ if(yco< 0.2) yco= 0.2;
+ break;
+ case 'k':
+ yco+=speed;
+ break;
+ case 'l':
+ view_roty += speed*20;
+ break;
+ case 'h':
+ view_roty -= speed*20;
+ break;
+ case 'J':
+ view_rotx += 2.0;
+ break;
+ case 'K':
+ view_rotx -= 2.0;
+ break;
+ case 'z':
+ view_rotz += 2.0;
+ break;
+ case 'Z':
+ view_rotz -= 2.0;
+ break;
+ default:
+ return;
+ }
+ draw();
+}
+
+/* ------------------------------------------------------------- */
+
+GLuint isShaderError(GLuint thing)
+{
+ GLint isShader = glIsShader(thing);
+
+ GLint ok;
+ if(isShader){
+ glGetShaderiv(thing, GL_COMPILE_STATUS, &ok);
+ }else{
+ glGetProgramiv(thing, GL_LINK_STATUS, &ok);
+ }
+ if(ok) return 0;
+
+ GLint infoLen=0;
+ if(isShader){
+ glGetShaderiv(thing, GL_INFO_LOG_LENGTH, &infoLen);
+ }else{
+ glGetProgramiv(thing, GL_INFO_LOG_LENGTH, &infoLen);
+ }
+ if(infoLen){
+ char* infoLog = malloc(sizeof(char)*infoLen);
+ if(isShader){
+ glGetShaderInfoLog(thing, infoLen, NULL, infoLog);
+ }else{
+ glGetProgramInfoLog(thing, infoLen, NULL, infoLog);
+ }
+ printf("%s: %s\n", isShader? "Shader compile": "Program link", infoLog);
+ free(infoLog);
+ }
+ return 1;
+}
+
+char* file2string(const char *path)
+{
+ FILE *fd;
+ long len, r;
+ char *str;
+
+ if(!(fd=fopen(path, "r"))) {
+ fprintf(stderr, "Can't open file '%s' for reading\n", path);
+ return NULL;
+ }
+
+ fseek(fd, 0, SEEK_END);
+ len = ftell(fd);
+ fseek(fd, 0, SEEK_SET);
+
+ if(!(str=malloc(len*sizeof(char)))) {
+ fprintf(stderr, "Can't malloc space for '%s'\n", path);
+ return NULL;
+ }
+
+ r = fread(str, sizeof(char), len, fd);
+
+ str[r-1] = '\0';
+
+ fclose(fd);
+
+ return str;
+}
+
+/* ------------------------------------------------------------- */
+
+int useTheProgram()
+{
+ const char *vsSource = file2string("tnl.vert");
+ const char *fsSource = file2string("tnl.frag");
+
+ GLuint vs = glCreateShader(GL_VERTEX_SHADER);
+ glShaderSource(vs, 1, &vsSource, NULL);
+ glCompileShader(vs);
+ if(isShaderError(vs)) return 0;
+
+ GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
+ glShaderSource(fs, 1, &fsSource, NULL);
+ glCompileShader(fs);
+ if(isShaderError(fs)) return 0;
+
+ free((void*)vsSource);
+ free((void*)fsSource);
+
+ program = glCreateProgram();
+ glAttachShader(program, vs);
+ glAttachShader(program, fs);
+
+ glBindAttribLocation(program, POS_ARRAY, "vertPos");
+ glBindAttribLocation(program, NORMAL_ARRAY, "vertNormal");
+ /* vertNormal and vertTexCoord don't need to be bound here.. ? */
+ glBindAttribLocation(program, TEXCOORD_ARRAY, "vertTexCoord");
+
+ glLinkProgram(program);
+ if(isShaderError(program)) return 0;
+
+ glUseProgram(program);
+
+ glUniform3f(glGetUniformLocation(program, "frameLightDirection"), 1.0, 0.0, 1.0);
+ glUniform1i(glGetUniformLocation(program, "texture"), 0); /* 0 ?? */
+
+ return 1;
+}
+
+int setUpTnL()
+{
+ glClearColor(1.0f, 1.0f, 0.0f, 0.0f);
+
+ glGenTextures(1, &texture);
+ glBindTexture(GL_TEXTURE_2D, texture);
+
+ GLuint* td = malloc(sizeof(GLuint)*TEX_SIZE*TEX_SIZE);
+ int i,j;
+ for(i=0; i<TEX_SIZE; i++)
+ for(j=0; j<TEX_SIZE; j++) {
+ GLuint col = (255L<<24) + ((255L-j*2)<<16) + ((255L-i)<<8) + (255L-i*2);
+ if ( ((i*j)/8) % 2 ) col = (GLuint) (255L<<24) + (255L<<16) + (0L<<8) + (255L);
+ td[j*TEX_SIZE+i] = col;
+ }
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, TEX_SIZE, TEX_SIZE, 0, GL_RGBA, GL_UNSIGNED_BYTE, td);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+ free(td);
+
+ GLfloat trivertices[] = {
+ -0.4f,-0.4f,0.4f, // Pos
+ 0.0f,0.0f,1.0f, // Normal
+ 0.0f,0.0f, // TexCoord
+
+ 0.4f,-0.0f,0.0f, // Pos
+ 0.0f,0.0f,1.0f, // Normal
+ 1.0f,0.0f, // TexCoord
+
+ 0.0f,0.4f,0.4f, // Pos
+ 0.5f,0.5f,0.5f, // Normal
+ 0.5f,1.0f, // TexCoord
+
+ 0.4f,0.0f,0.4f, // Pos
+ 0.5f,0.5f,0.5f, // Normal
+ 0.5f,0.0f, // TexCoord
+
+ 0.4f,0.4f,0.4f, // Pos
+ 0.0f,0.0f,1.0f, // Normal
+ 0.0f,0.0f, // TexCoord
+
+ };
+
+ numberOfVertices = 4;
+ posStep = 3 * sizeof(GLfloat);
+ normStep = 3 * sizeof(GLfloat);
+ tcStep = 2 * sizeof(GLfloat);
+ stride = posStep + normStep + tcStep;
+
+ glGenBuffers(1, &vbo);
+ glBindBuffer(GL_ARRAY_BUFFER, vbo);
+ glBufferData(GL_ARRAY_BUFFER, numberOfVertices * stride, trivertices, GL_STATIC_DRAW);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+ return 1;
+}
+
+int drawStuff(int width, int height)
+{
+ glViewport(0, 0, width, height);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ float TransRotScaleVerticeMatrix[] = {
+ cos(angle), 0, sin(angle), 0,
+ 0, 1, 0, 0,
+ -sin(angle), 0, cos(angle), 0,
+ 0, 0, 0, 1
+ };
+
+ float ModelViewProjectionMatrix[] = {
+ cos(viewAngle), 0, sin(viewAngle), 0,
+ 0, 1, 0, 0,
+ -sin(viewAngle), 0, cos(viewAngle), 0,
+ 0, 0, 0, 1
+ };
+
+ float TransRotScaleNormalMatrix[] = {
+ cos(angle), 0, sin(angle),
+ 0, 1, 0,
+ -sin(angle), 0, cos(angle)
+ };
+
+ glUniformMatrix4fv(glGetUniformLocation(program, "frameTRSV"), 1, GL_FALSE, TransRotScaleVerticeMatrix);
+ glUniformMatrix4fv(glGetUniformLocation(program, "frameMVP"), 1, GL_FALSE, ModelViewProjectionMatrix);
+ glUniformMatrix3fv(glGetUniformLocation(program, "frameTRSN"), 1, GL_FALSE, TransRotScaleNormalMatrix);
+
+
+ glBindBuffer(GL_ARRAY_BUFFER, vbo);
+
+ glEnableVertexAttribArray(POS_ARRAY);
+ glVertexAttribPointer(POS_ARRAY, 3, GL_FLOAT, GL_FALSE, stride, 0);
+
+ glEnableVertexAttribArray(NORMAL_ARRAY);
+ glVertexAttribPointer(NORMAL_ARRAY, 3, GL_FLOAT, GL_FALSE, stride, (void*)posStep );
+
+ glEnableVertexAttribArray(TEXCOORD_ARRAY);
+ glVertexAttribPointer(TEXCOORD_ARRAY, 2, GL_FLOAT, GL_FALSE, stride, (void*)(posStep + normStep) );
+
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, numberOfVertices);
+
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+ k_gl_swap_buffers();
+
+ angle += .007f;
+
+ return 1;
+}
+
+void deleteStuff(){
+ glDeleteTextures(1, &texture);
+ glDeleteBuffers(1, &vbo);
+ glDeleteProgram(program);
+/* glDeleteShader();
+ glDeleteShader();*/
+}
+
+/* ------------------------------------------------------------- */
+
+
+
--- /dev/null
+
+/* -------------------------------------------------------------------------- */
+
+#include <kernelapi.h>
+#include <notification.h>
+
+/* -------------------------------------------------------------------------- */
+
+static int handles_resource(char* name);
+static void sync_resource(ni_resource* res);
+
+static void start_tests(void);
+static void running_tests(ni_event* evt);
+
+static void test_state(n_object* o, char* os, char* uid, char* cont);
+
+/* -------------------------------------------------------------------------- */
+
+EXPORT int teston_module_loaded(void)
+{
+ ni_register_driver("teston", handles_resource, sync_resource);
+
+ k_log_out("Test ON Driver initialised");
+
+ start_tests();
+
+ return 1;
+}
+
+EXPORT int teston_module_event(void* data)
+{
+ ni_event* evt=data;
+
+ running_tests(evt);
+
+ ni_event_delete(evt);
+ return 1;
+}
+
+EXPORT int teston_module_tick(void)
+{
+ return 1;
+}
+
+/* -------------------------------------------------------------------------- */
+
+int handles_resource(char* name)
+{
+ return 1;
+}
+
+void sync_resource(ni_resource* res)
+{
+}
+
+/* -------------------------------------------------------------------------- */
+
+/*
+ - object.create .update .commit .rollback (auto inc version #?)
+ - object.see - may return empty so wait for ..
+ - seestate(object) - state asked for /or/ object is subscribing
+ */
+void start_tests(void)
+{
+ k_log_out("Creating o11111");
+
+ char* o11111s = "UID: 11111-4141a\n"
+ "\n"
+ "This: is one content\n";
+
+ n_object* o11111 = n_object_new(o11111s);
+
+ test_state(o11111, o11111s, "11111-4141a", "is one content");
+
+ k_log_out("Committing o11111");
+
+ n_commit(o11111);
+
+ k_log_out("Creating o22222");
+
+ char* o22222s = "UID: 22222-ef990\n"
+ "\n"
+ "This: is two content\n";
+
+ n_object* o22222 = n_object_new(o22222s);
+
+ test_state(o22222, o22222s, "22222-ef990", "is two content");
+
+ n_object* o2 = n_see(o11111, "22222-ef990");
+
+ k_assert(!o2, "Object 2 has not been committed yet, but Object 1 can see it:\n%s\n", n_to_string(o2));
+
+ n_commit(o22222);
+
+ o2 = n_see(o11111, "22222-ef990");
+
+ k_assert(o2!=0, "Object 2 has been committed, but can't be seen by Object 1");
+
+ test_state(o2, o22222s, "22222-ef990", "is two content");
+
+ n_object* o3 = n_see(o22222, "33333-18bbc");
+
+ k_assert(!o3, "Object 3 has not been created yet, but Object 2 can see it:\n%s", n_to_string(o3));
+}
+
+void running_tests(ni_event* evt)
+{
+ char* o33333s =
+ "UID: 33333-18bbc\n"
+ "\n"
+ "This: is three content\n";
+
+ n_object* o33333 = n_object_new(o33333s);
+
+ n_commit(o33333);
+
+}
+
+/* -------------------------------------------------------------------------- */
+
+void test_state(n_object* o, char* os, char* uid, char* cont)
+{
+ char* c;
+
+ k_log_out("Checking %s", uid);
+
+ c=n_to_string(o);
+ k_assert(c && !strcmp(c, os), "To-string was\n%s", c? c: "null");
+
+ c=n_uid(o);
+ k_assert(c && !strcmp(c, uid), "UID was %s in n_uid", c? c: "null");
+
+ c=n_header(o, "UID");
+ k_assert(c && !strcmp(c, uid), "UID was %s in n_header", c? c: "null");
+
+ c=k_hashtable_get(n_headers(o), "UID");
+ k_assert(c && !strcmp(c, uid), "UID was %s in hash get", c? c: "null");
+
+ c=k_hashtable_get(n_content(o), "This");
+ k_assert(c && !strcmp(c, cont), "Content was %s", c? c: "null");
+
+ c=n_to_string(o);
+ k_assert(c && !strcmp(c, os), "To-string was\n%s", c? c: "null");
+}
+
+/* -------------------------------------------------------------------------- */
+
+
+
+++ /dev/null
-
-#ifndef ni_H
-#define ni_H
-
-/* -------------------------------------------------------------------------- */
-
-typedef struct n_object{
- k_hashtable* headers;
- k_hashtable* content;
-} n_object;
-
-PUBLIC n_object* n_object_new(char* s);
-PUBLIC void n_commit(n_object* o);
-PUBLIC n_object* n_see(n_object* o, char* uid);
-PUBLIC char* n_to_string(n_object* o);
-PUBLIC char* n_uid(n_object* o);
-PUBLIC char* n_header(n_object* o, char* name);
-PUBLIC k_hashtable* n_headers(n_object* o);
-PUBLIC k_hashtable* n_content(n_object* o);
-
-/* -------------------------------------------------------------------------- */
-
-PUBLIC char* ni_hostname(void);
-PUBLIC void ni_hostname_set(char* name);
-
-/* -------------------------------------------------------------------------- */
-
-typedef struct ni_resource{
- char* uri;
- k_hashtable* ent_head;
- void* entity;
-} ni_resource;
-
-PUBLIC ni_resource* ni_resource_new(char* uri,
- k_hashtable* ent_head,
- char* entity);
-PUBLIC ni_resource* ni_resource_dup( ni_resource* res);
-PUBLIC void ni_resource_delete(ni_resource* res);
-PUBLIC void ni_resource_show( ni_resource* res, char* text);
-PUBLIC ni_resource* ni_resource_get(char* uri);
-
-/* -------------------------------------------------------------------------- */
-
-typedef struct ni_event{
- char* uri;
- k_hashtable* evt_head;
- k_hashtable* ent_head;
- void* entity;
-} ni_event;
-
-PUBLIC ni_event* ni_event_new(char* uri,
- k_hashtable* evt_head,
- k_hashtable* ent_head,
- char* entity);
-PUBLIC ni_event* ni_event_dup( ni_event* res);
-PUBLIC void ni_event_delete(ni_event* res);
-PUBLIC void ni_event_show( ni_event* res, char* text);
-
-/* -------------------------------------------------------------------------- */
-
-PUBLIC ni_event* ni_res_to_evt(ni_resource* res);
-
-/* -------------------------------------------------------------------------- */
-
-typedef int (*ni_handles_resource)(char*);
-typedef void (*ni_sync_resource )(ni_resource*);
-
-PUBLIC void ni_register_driver(char* name,
- ni_handles_resource handles_resource,
- ni_sync_resource sync_resource);
-
-/* -------------------------------------------------------------------------- */
-
-PUBLIC ni_event* ni_get_request_headers( char* header);
-PUBLIC ni_event* ni_get_response_headers(char* header);
-PUBLIC char* ni_get_headers( char* header, k_hashtable*, k_hashtable*);
-PUBLIC void ni_fix_http_headers(k_hashtable* ent_head);
-PUBLIC void ni_fix_ni_headers(k_hashtable* ent_head, int methead);
-PUBLIC void ni_response(ni_event* evt,
- char* to,
- char* method,
- char* protocol,
- char* connection,
- k_channel* chan);
-PUBLIC void ni_request(ni_event* evt,
- char* to,
- char* method,
- k_channel* chan);
-
-/* -------------------------------------------------------------------------- */
-
-#endif
-
--- /dev/null
+
+#ifndef ni_H
+#define ni_H
+
+/* -------------------------------------------------------------------------- */
+
+typedef struct n_object{
+ k_hashtable* headers;
+ k_hashtable* content;
+} n_object;
+
+PUBLIC n_object* n_object_new(char* s);
+PUBLIC void n_commit(n_object* o);
+PUBLIC n_object* n_see(n_object* o, char* uid);
+PUBLIC char* n_to_string(n_object* o);
+PUBLIC char* n_uid(n_object* o);
+PUBLIC char* n_header(n_object* o, char* name);
+PUBLIC k_hashtable* n_headers(n_object* o);
+PUBLIC k_hashtable* n_content(n_object* o);
+
+/* -------------------------------------------------------------------------- */
+
+PUBLIC char* ni_hostname(void);
+PUBLIC void ni_hostname_set(char* name);
+
+/* -------------------------------------------------------------------------- */
+
+typedef struct ni_resource{
+ char* uri;
+ k_hashtable* ent_head;
+ void* entity;
+} ni_resource;
+
+PUBLIC ni_resource* ni_resource_new(char* uri,
+ k_hashtable* ent_head,
+ char* entity);
+PUBLIC ni_resource* ni_resource_dup( ni_resource* res);
+PUBLIC void ni_resource_delete(ni_resource* res);
+PUBLIC void ni_resource_show( ni_resource* res, char* text);
+PUBLIC ni_resource* ni_resource_get(char* uri);
+
+/* -------------------------------------------------------------------------- */
+
+typedef struct ni_event{
+ char* uri;
+ k_hashtable* evt_head;
+ k_hashtable* ent_head;
+ void* entity;
+} ni_event;
+
+PUBLIC ni_event* ni_event_new(char* uri,
+ k_hashtable* evt_head,
+ k_hashtable* ent_head,
+ char* entity);
+PUBLIC ni_event* ni_event_dup( ni_event* res);
+PUBLIC void ni_event_delete(ni_event* res);
+PUBLIC void ni_event_show( ni_event* res, char* text);
+
+/* -------------------------------------------------------------------------- */
+
+PUBLIC ni_event* ni_res_to_evt(ni_resource* res);
+
+/* -------------------------------------------------------------------------- */
+
+typedef int (*ni_handles_resource)(char*);
+typedef void (*ni_sync_resource )(ni_resource*);
+
+PUBLIC void ni_register_driver(char* name,
+ ni_handles_resource handles_resource,
+ ni_sync_resource sync_resource);
+
+/* -------------------------------------------------------------------------- */
+
+PUBLIC ni_event* ni_get_request_headers( char* header);
+PUBLIC ni_event* ni_get_response_headers(char* header);
+PUBLIC char* ni_get_headers( char* header, k_hashtable*, k_hashtable*);
+PUBLIC void ni_fix_http_headers(k_hashtable* ent_head);
+PUBLIC void ni_fix_ni_headers(k_hashtable* ent_head, int methead);
+PUBLIC void ni_response(ni_event* evt,
+ char* to,
+ char* method,
+ char* protocol,
+ char* connection,
+ k_channel* chan);
+PUBLIC void ni_request(ni_event* evt,
+ char* to,
+ char* method,
+ k_channel* chan);
+
+/* -------------------------------------------------------------------------- */
+
+#endif
+
+++ /dev/null
-
-/* -}{----------------------------------------------------------------------- */
-
-#include <kernelapi.h>
-#undef PUBLIC
-#define PUBLIC EXPORT
-#include <ni.h>
-
-/* -}{---- ------------------------------------------------------------------ */
-
-static k_hashtable* entity_headers;
-
-/* -}{---- ------------------------------------------------------------------ */
-
-#define TMPBUFSIZE 4096
-static char tmpbuf[TMPBUFSIZE];
-
-/* -}{----------------------------------------------------------------------- */
-
-static char* get_request( char* header, k_hashtable*, k_hashtable*);
-static char* get_response(char* header, k_hashtable*, k_hashtable*);
-static char* get_val(char** atp);
-static char* end_of_val(char* at);
-static void fix_keepalive(k_hashtable* evt_head);
-static void fix_cache_control(k_hashtable* ent_head);
-static void fix_uri(k_hashtable* ent_head);
-static void fix_subscribe(k_hashtable*, k_hashtable*);
-
-/* -}{----------------------------------------------------------------------- */
-
-#define WHITESPACEH " \t"
-#define WHITESPACEV "\012\015"
-#define WHITESPACE WHITESPACEH WHITESPACEV
-
-EXPORT ni_event* ni_get_request_headers(char* header)
-{
- k_hashtable* evt_head=k_hashtable_new("vHeaders/get_req_hdrs", 1);
- k_hashtable* ent_head=k_hashtable_new("nHeaders/get_req_hdrs", 1);
- k_hashtable_put(ent_head, "", header);
-
- char* h=get_request(header, evt_head, ent_head);
- if(!h){
- k_hashtable_delete(evt_head);
- k_hashtable_delete(ent_head);
- return 0;
- }
-
- h=ni_get_headers(h, evt_head, ent_head);
- if(!h){
- k_hashtable_delete(evt_head);
- k_hashtable_delete(ent_head);
- return 0;
- }
-
- fix_keepalive(evt_head);
- fix_cache_control(ent_head);
- fix_uri(ent_head);
- fix_subscribe(evt_head, ent_head);
-
- ni_event* evq=ni_event_new(0, evt_head, ent_head, 0);
-
- return evq;
-}
-
-EXPORT ni_event* ni_get_response_headers(char* header)
-{
- k_hashtable* evt_head=k_hashtable_new("vHeaders/get_resp_hdrs", 1);
- k_hashtable* ent_head=k_hashtable_new("nHeaders/get_resp_hdrs", 1);
- k_hashtable_put(ent_head, "", header);
-
- char* h=get_response(header, evt_head, ent_head);
- if(!h){
- k_hashtable_delete(evt_head);
- k_hashtable_delete(ent_head);
- return 0;
- }
-
- h=ni_get_headers(h, evt_head, ent_head);
- if(!h){
- k_hashtable_delete(evt_head);
- k_hashtable_delete(ent_head);
- return 0;
- }
-
- ni_event* evt=ni_event_new(0, evt_head, ent_head, 0);
-
- return evt;
-}
-
-EXPORT char* ni_get_headers(char* header,
- k_hashtable* evt_head,
- k_hashtable* ent_head)
-{
- char* at=header;
- char* tag;
- char* val;
- while(*at){
-
- tag=at;
- at=strpbrk(at, WHITESPACE);
- if(!at || at==tag) return 0;
- char* e=at;
- val=get_val(&at);
- *e=0;
-
- if(strlen(val) > 2048) return 0;
-
- k_hashtable* h;
- h=k_hashtable_get(entity_headers, tag)? ent_head: evt_head;
- if(h){
- char* old=k_hashtable_get(h, tag);
- if(!old) k_hashtable_set(h, tag, val);
- }
- }
- return at;
-}
-
-EXPORT void ni_fix_http_headers(k_hashtable* ent_head)
-{
- if(k_hashtable_is(ent_head, "Status:", "260")){
- char* crn=k_hashtable_get(ent_head, "Content-Range:");
- char* clg=k_hashtable_get(ent_head, "Content-Length-Given:");
- if(crn || clg){
- k_hashtable_set(ent_head, "Status:", "206");
- k_hashtable_set(ent_head, "Status-Text:", "Partial Content");
- }
- else{
- k_hashtable_set(ent_head, "Status:", "200");
- k_hashtable_set(ent_head, "Status-Text:", "OK");
- }
- }
- k_hashtable_remove(ent_head, "URI:");
- k_hashtable_remove(ent_head, "Method:");
- k_hashtable_remove(ent_head, "From:");
- k_hashtable_remove(ent_head, "Content-Length-Given:");
- k_hashtable_remove(ent_head, "Last-Modified-Epoch:");
-
- char* cc=k_hashtable_get(ent_head, "Cache-Control:");
- if(cc && strstr(cc, "no-cache")){
- k_hashtable_set(ent_head, "Pragma:", "no-cache");
- }
-}
-
-EXPORT void ni_fix_ni_headers(k_hashtable* ent_head, int methead)
-{
- if(methead && (k_hashtable_is(ent_head, "Status:", "200") ||
- k_hashtable_is(ent_head, "Status:", "206") )){
-
- k_hashtable_set(ent_head, "Status:", "260");
- k_hashtable_set(ent_head, "Status-Text:", "Headers Only");
- }
- k_hashtable_remove(ent_head, "Method:");
- k_hashtable_remove(ent_head, "Sub-To:");
- k_hashtable_remove(ent_head, "Via:");
- k_hashtable_set( ent_head, "From:", ni_hostname());
-
- char* uri=k_hashtable_get(ent_head, "URI:");
- if(*uri=='.'){
- snprintf(tmpbuf, TMPBUFSIZE, "%s/%s", ni_hostname(), uri+2);
- k_hashtable_put_dup(ent_head, "URI:", tmpbuf);
- }
-}
-
-EXPORT void ni_response(ni_event* evt,
- char* to,
- char* method,
- char* protocol,
- char* connection,
- k_channel* chan)
-{
- int L=0;
- snprintf(tmpbuf, TMPBUFSIZE, "%s", k_time_to_rfc_relative(0));
- k_hashtable_put_dup(evt->evt_head, "Date:", tmpbuf);
- k_hashtable_set( evt->evt_head, "Server:", k_version);
- if(connection)
- k_hashtable_put_dup(evt->evt_head, "Connection:", connection);
-
- int status =k_hashtable_get_int(evt->ent_head, "Status:");
- char* statustext=k_hashtable_get( evt->ent_head, "Status-Text:");
- int datalength=k_hashtable_get_int(evt->ent_head, "Content-Length:");
- int constant =k_hashtable_is( evt->ent_head, "CUX:", "C");
-
- char* buf =tmpbuf;
- int bufsize=TMPBUFSIZE;
- int ln=0;
-
- ln+=snprintf(buf+ln, bufsize-ln, "%s %d %s" CRLF,
- protocol, status, statustext);
- if(ln>=bufsize) return;
-
- static char* exheaders[]={ "Status:", "Status-Text:",
- "Protocol:", "CUX:", 0 };
-
- ln+=k_hashtable_snprintf_x(evt->evt_head, buf+ln,bufsize-ln, exheaders);
- if(ln>=bufsize) return;
-
- ln+=k_hashtable_snprintf_x(evt->ent_head, buf+ln,bufsize-ln, exheaders);
- if(ln>=bufsize) return;
-
- ln+=snprintf(buf+ln, bufsize-ln, CRLF);
- if(ln>=bufsize) return;
-
- char* head=k_strdup(buf);
- if(L) k_log_out("Actual response headers:\n%s", head);
- k_channel_send(chan, head, ln, FREE_ON_SENT);
-
- if(evt->entity && datalength){
- k_channel_send(chan, evt->entity, datalength, !constant);
- }
- else{
- datalength=0;
- if(!constant) k_free(evt->entity);
- }
- k_log_out("%s %s %s %d %d", to, method, evt->uri, status, datalength);
-}
-
-EXPORT void ni_request(ni_event* evt, char* to, char* method, k_channel* chan)
-{
- k_hashtable* sub=evt->ent_head;
-
- int ln=0;
- int bufsize=TMPBUFSIZE;
-
- ln+=snprintf(tmpbuf+ln, bufsize-ln, "%s //%s ni/0.5" CRLF, method, to);
- if(ln>=bufsize) return;
-
- ln+=k_hashtable_snprintf(sub, tmpbuf+ln, bufsize-ln);
- if(ln>=bufsize) return;
-
- ln+=snprintf(tmpbuf+ln, bufsize-ln, CRLF);
- if(ln>=bufsize) return;
-
- char* head=k_strdup(tmpbuf);
- if(0) k_log_out("Actual request headers:\n%s", head);
- k_channel_send(chan, head, ln, FREE_ON_SENT);
-}
-
-/* -}{----------------------------------------------------------------------- */
-
-char* get_request(char* header, k_hashtable* evt_head, k_hashtable* ent_head)
-{
- char* at=header;
- char* method=at;
- at=strpbrk(at, WHITESPACEH);
- if(!at) return 0;
- *at++=0;
-
- k_hashtable_set(ent_head, "Method:", method);
-
- char* file=0;
- char* host=0;
- if(strcmp(method, "PING")){
-
- at+=strspn(at, WHITESPACEH);
- file=at;
- at=strpbrk(at, WHITESPACEH);
- if(!at) return 0;
- *at++=0;
- if(strlen(file) > 1024 ) return 0;
-
- if(!strncmp(file, "http://", 7)){
- char* s=file+7;
- if(!*s || *s=='/') return 0;
- char* e=strchr(s, '/');
- if(!e) return 0;
- host=s;
- *e++=0;
- file=e;
- }
- else
- if(*file=='/') file++;
- else return 0;
-
- if(*file=='/'){
- char* s=file+1;
- if(!*s || *s=='/') return 0;
- char* e=strchr(s, '/');
- if(!e) return 0;
- host=s;
- *e++=0;
- file=e;
- }
- }
- if(file) k_hashtable_set(evt_head, "File:", file);
- if(host) k_hashtable_set(evt_head, "Host:", host);
-
- at+=strspn(at, WHITESPACEH);
- char* protocol=at;
- at=strpbrk(at, WHITESPACE);
- if(!at) at=protocol+strlen(protocol);
- else *at++=0;
-
- k_hashtable_set(evt_head, "Protocol:", protocol);
-
- at+=strspn(at, WHITESPACE);
- return at;
-}
-
-char* get_response(char* header, k_hashtable* evt_head, k_hashtable* ent_head)
-{
- char* at=header;
- char* protocol=at;
- at=strpbrk(at, WHITESPACEH);
- if(!at) return 0;
- *at++=0;
-
- k_hashtable_set(evt_head, "Protocol:", protocol);
-
- at+=strspn(at, WHITESPACEH);
- char* status=at;
- at=strpbrk(at, WHITESPACEH);
- if(!at) return 0;
- *at++=0;
-
- at+=strspn(at, WHITESPACEH);
- char* statustext=at;
- at=strpbrk(at, WHITESPACEV);
- if(!at) return 0;
- *at++=0;
-
- k_hashtable_set(ent_head, "Status:", status);
- k_hashtable_set(ent_head, "Status-Text:", statustext);
-
- at+=strspn(at, WHITESPACE);
- return at;
-}
-
-char* get_val(char** atp)
-{
- char* at=*atp;
- char* val=at;
-
- val+=strspn(val, WHITESPACEH);
- val+=strspn(val, WHITESPACEV);
-
- char* eov=end_of_val(at);
- if(eov<val) val=eov;
- if(*eov) *eov++=0;
-
- *atp=eov+strspn(eov, WHITESPACEV);
- return val;
-}
-
-char* end_of_val(char* at)
-{
- char* eov;
- do{
- char* v=strpbrk(at, WHITESPACEV);
- if(!v) return at+strlen(at);
- eov=v;
- at=v+strspn(v, WHITESPACEV);
-
- }while(strspn(at, WHITESPACEH));
-
- return eov;
-}
-
-void fix_keepalive(k_hashtable* evt_head)
-{
- int keepalive=0;
- int is11=k_hashtable_is( evt_head, "Protocol:", "HTTP/1.1");
- int isps=k_hashtable_isn(evt_head, "Protocol:", "ni/", 4);
- int iska=k_hashtable_isi(evt_head, "Connection:", "Keep-Alive");
- int iscl=k_hashtable_isi(evt_head, "Connection:", "close");
- if((!is11 && iska) || (is11 && !iscl) || isps){
- keepalive=1;
- }
- if(0) k_log_out("is11=%d iska=%d iscl=%d isps=%d ka=%d",
- is11, iska, iscl, isps, keepalive);
- k_hashtable_set(evt_head, "Connection:",
- keepalive? "Keep-Alive": "close");
-}
-
-void fix_cache_control(k_hashtable* ent_head)
-{
- char* cachec=k_hashtable_get( ent_head, "Cache-Control:");
- char* pragma=k_hashtable_extract(ent_head, "Pragma:");
- if(!cachec && pragma && strstr(pragma, "no-cache")){
- k_hashtable_set( ent_head, "Cache-Control:","no-cache");
- }
-}
-
-void fix_uri(k_hashtable* ent_head)
-{
- char* uri=k_hashtable_get(ent_head, "URI:");
- if(!uri) return;
- char* nihostname=ni_hostname();
- int l=strlen(nihostname);
- if(strncmp(uri, nihostname, l)) return;
- snprintf(tmpbuf, TMPBUFSIZE, ".%s", uri+l);
- k_hashtable_put_dup(ent_head, "URI:", tmpbuf);
-}
-
-void fix_subscribe(k_hashtable* evt_head, k_hashtable* ent_head)
-{
- char* host=k_hashtable_extract(evt_head, "Host:");
- char* file=k_hashtable_extract(evt_head, "File:");
- if(host){
- k_string_url_decode(host);
- int localhostdns=!strcmp( host, "localhost") ||
- !strncmp(host, "localhost:", 10);
- int localhostni=!strcmp(host, ni_hostname());
- char* lastdot=strrchr(host, '.');
- int dotdotnumber=lastdot && atoi(lastdot+1) >0;
- if(localhostdns || localhostni || dotdotnumber){
- host=".";
- }
- }
- else{
- host=".";
- }
- if(file){
- k_string_url_decode(file);
- snprintf(tmpbuf, TMPBUFSIZE, "%s/%s", host, file);
- k_hashtable_put_dup(ent_head, "Sub-To:", tmpbuf);
- k_hashtable_set( ent_head, "Sub-Type:", "Original");
- }
-}
-
-void init_headers(void)
-{
- entity_headers =k_hashtable_new("Entity Headers", 1);
-
- k_hashtable_set(entity_headers, "URI:", (void*)1);
- k_hashtable_set(entity_headers, "From:", (void*)1);
- k_hashtable_set(entity_headers, "To:", (void*)1);
- k_hashtable_set(entity_headers, "Via:", (void*)1);
- k_hashtable_set(entity_headers, "Sub-To:", (void*)1);
- k_hashtable_set(entity_headers, "Sub-Type:", (void*)1);
- k_hashtable_set(entity_headers, "Method:", (void*)1);
- k_hashtable_set(entity_headers, "Status:", (void*)1);
- k_hashtable_set(entity_headers, "Status-Text:", (void*)1);
- k_hashtable_set(entity_headers, "Last-Modified-Epoch:", (void*)1);
- k_hashtable_set(entity_headers, "CUX:", (void*)1);
-
- k_hashtable_set(entity_headers, "Range:", (void*)1);
- k_hashtable_set(entity_headers, "If-Modified-Since:", (void*)1);
- k_hashtable_set(entity_headers, "If-None-Match:", (void*)1);
- k_hashtable_set(entity_headers, "Cache-Control:", (void*)1);
- k_hashtable_set(entity_headers, "Pragma:", (void*)1);
-
- k_hashtable_set(entity_headers, "Content-Length:", (void*)1);
- k_hashtable_set(entity_headers, "Content-Type:", (void*)1);
- k_hashtable_set(entity_headers, "Content-Encoding:", (void*)1);
- k_hashtable_set(entity_headers, "Content-Location:", (void*)1);
- k_hashtable_set(entity_headers, "Content-MD5:", (void*)1);
- k_hashtable_set(entity_headers, "Content-Language:", (void*)1);
- k_hashtable_set(entity_headers, "Content-Range:", (void*)1);
- k_hashtable_set(entity_headers, "Last-Modified:", (void*)1);
- k_hashtable_set(entity_headers, "ETag:", (void*)1);
- k_hashtable_set(entity_headers, "Expires:", (void*)1);
-
- k_hashtable_set(entity_headers, "Allow:", (void*)1);
-}
-
-void drop_entity_headers(k_hashtable* ent_head)
-{
- k_hashtable_remove(ent_head, "Content-Length:");
- k_hashtable_remove(ent_head, "Content-Range:");
- k_hashtable_remove(ent_head, "Content-Type:");
- k_hashtable_remove(ent_head, "Content-Encoding:");
- k_hashtable_remove(ent_head, "Content-Location:");
- k_hashtable_remove(ent_head, "Last-Modified:");
-#ifdef DO_THESE_ONES_TOO
- k_hashtable_remove(ent_head, "Allow:");
- k_hashtable_remove(ent_head, "Content-Language:");
- k_hashtable_remove(ent_head, "Content-MD5:");
- k_hashtable_remove(ent_head, "Expires:");
-#endif
-}
-
-void fill_headers(k_hashtable* ent_head,
- char* status,
- char* statustext,
- char* uri,
- time_t modifitime,
- int datalength,
- char* mimetype,
- char* encoding,
- int nocache)
-{
- if(status){
- k_hashtable_put_dup(ent_head, "Status:", status);
- k_hashtable_put_dup(ent_head, "Status-Text:", statustext);
- }
- if(uri){
- k_hashtable_put_dup(ent_head, "URI:", uri);
- }
- if(modifitime>=0){
- snprintf(tmpbuf, TMPBUFSIZE, "%s", k_time_to_rfc(modifitime));
- k_hashtable_put_dup(ent_head, "Last-Modified:", tmpbuf);
- }
- if(datalength>=0){
- snprintf(tmpbuf, TMPBUFSIZE, "%d", datalength);
- k_hashtable_put_dup(ent_head, "Content-Length:", tmpbuf);
- }
- if(mimetype){
- k_hashtable_put_dup(ent_head, "Content-Type:", mimetype);
- }
- if(encoding){
- k_hashtable_put_dup(ent_head, "Content-Encoding:", encoding);
- }
- if(nocache==1){
- k_hashtable_put_dup(ent_head, "Cache-Control:",
- "no-cache,no-store");
- }
- else
- if(nocache==0){
- long maxage=31449600;
- snprintf(tmpbuf, TMPBUFSIZE, "max-age=%ld", maxage);
- char* maxages=k_time_to_rfc_relative(maxage);
- k_hashtable_put_dup(ent_head, "Cache-Control:", tmpbuf);
- k_hashtable_put_dup(ent_head, "Expires:", maxages);
- }
- else
- if(nocache== -1){
- k_hashtable_remove(ent_head, "Cache-Control:");
- k_hashtable_remove(ent_head, "Expires:");
- }
-}
-
-/* -}{---- ------------------------------------------------------------------ */
-
+++ /dev/null
-
-/* -}{----------------------------------------------------------------------- */
-
-#include <kernelapi.h>
-#undef PUBLIC
-#define PUBLIC EXPORT
-#include <ni.h>
-
-/* -}{---- ------------------------------------------------------------------ */
-
-EXPORT n_object* n_object_new(char* s)
-{
- return 0;
-}
-
-EXPORT void n_commit(n_object* o)
-{
-}
-
-EXPORT n_object* n_see(n_object* o, char* uid)
-{
- return 0;
-}
-
-EXPORT char* n_to_string(n_object* o)
-{
- return 0;
-}
-
-EXPORT char* n_uid(n_object* o)
-{
- return 0;
-}
-
-EXPORT char* n_header(n_object* o, char* name)
-{
- return 0;
-}
-
-EXPORT k_hashtable* n_headers(n_object* o)
-{
- return 0;
-}
-
-EXPORT k_hashtable* n_content(n_object* o)
-{
- return 0;
-}
-
-/* -}{---- ------------------------------------------------------------------ */
-
-#define TMPBUFSIZE 4096
-static char tmpbuf[TMPBUFSIZE];
-static char* hostname;
-static k_hashtable* resources;
-
-/* -}{---- ------------------------------------------------------------------ */
-
-typedef struct ni_driver{
- char* name;
- ni_handles_resource handles_resource;
- ni_sync_resource sync_resource;
-} ni_driver;
-
-/* -}{---- From headers.c --------------------------------------------------- */
-
-extern void init_headers(void);
-extern void drop_entity_headers(k_hashtable* ent_head);
-extern void fill_headers(k_hashtable* ent_head,
- char* status,
- char* statustext,
- char* uri,
- time_t modifitime,
- int datalength,
- char* mimetype,
- char* encoding,
- int nocache);
-
-/* -}{---- ------------------------------------------------------------------ */
-
-static void incoming_request(ni_event* evq);
-static ni_resource* ensure_res(char* pub);
-static void ensure_sub_entry(k_hashtable* ent_head, k_hashtable* sub);
-static void ensure_pub_entry(k_hashtable* ent_head, k_hashtable* sub);
-static k_hashtable* get_this(k_hashtable*, char*, k_hashtable*);
-static k_hashtable* get_using(k_hashtable* curr, char* tag, char* val);
-static void post_to_driver(char* pub, ni_event* evq);
-static void incoming_resource(ni_event* evt);
-static void test_pub_tos(ni_resource* res, ni_event* evt, int entityok);
-static int satisfiable(k_hashtable*, ni_resource*, ni_event*, int);
-static void update_pubcache(int, k_hashtable**, k_hashtable*, k_hashtable*);
-static int sub_less(k_hashtable* sub1, k_hashtable* sub2);
-static void fix_via_subs(k_hashtable* evteh, k_hashtable* reseh);
-static int sub_ok(k_hashtable* sub);
-static int range_ok(char* range, char* conrange);
-static void merge_non_entity_headers(k_hashtable* reseh, k_hashtable* evteh);
-static void merge_entity_range(ni_resource* res, ni_event* evt);
-static void respond( k_hashtable* sub, ni_resource* res, ni_event* evt);
-static void respond_ok(k_hashtable* sub, ni_event* evv);
-static void respond_nf(k_hashtable* sub, ni_event* evv);
-static void* entity_to_octets(k_hashtable* ent_head, void* entity);
-static char* handled_by(char* pub);
-static void call_sync_resource(ni_resource* res);
-static ni_driver* ni_driver_new(char* name,
- ni_handles_resource handles_resource,
- ni_sync_resource sync_resource);
-
-/* -}{---- ------------------------------------------------------------------ */
-
-EXPORT int ni_module_loaded(void)
-{
- resources=k_hashtable_new("Resources", 0);
-
- init_headers();
-
- k_log_out("NI initialised");
- return 1;
-}
-
-EXPORT void ni_module_tick(void)
-{
-}
-
-EXPORT int ni_module_event(void* data)
-{
- ni_event* evt=data;
-
- if(!k_hashtable_get(evt->ent_head, "Status:")){
-
- incoming_request(evt);
- }
- else{
- incoming_resource(evt);
- }
- return 1;
-}
-
-/* -}{---- ------------------------------------------------------------------ */
-
-void incoming_request(ni_event* evq)
-{
- int L=1;
- if(L) ni_event_show(evq, "NI got request event");
-
- k_hashtable* sub=evq->ent_head;
- char* uri =k_hashtable_get(sub, "URI:");
- char* pub =k_hashtable_get(sub, "Sub-To:"); if(!pub) return;
- int styor=k_hashtable_isi(sub, "Sub-Type:", "Original");
- char* via =k_hashtable_get(sub, "Via:");
- char* from =k_hashtable_get(sub, "From:");
- if(L) k_log_out("------------------ %s", pub);
-
- int nocache=k_hashtable_isi(sub, "Cache-Control:", "no-cache");
- if(nocache){
- k_hashtable_remove( sub, "Cache-Control:");
- k_hashtable_set( sub, "If-Modified-Since:", "0");
- }
-
- if(!from){
- ni_resource* ses=k_hashtable_get(resources, uri);
- if(ses) ensure_sub_entry(ses->ent_head, sub);
- if(ses) if(L) ni_resource_show(ses, "Subscribing Resource:");
- if(styor && via){
- post_to_driver(pub, evq);
- return;
- }
- }
-
- ni_resource* res=ensure_res(pub);
- if(L) ni_resource_show(res, "Publishing Resource:");
-
- k_hashtable* pubcache=0;
- int sat=satisfiable(sub, res, 0, 0);
- update_pubcache(sat, &pubcache, res->ent_head, sub);
- if(sat){
- if(L) k_log_out("Memory cache hit for %s", pub);
- respond(k_hashtable_dup(sub), res, 0);
- ni_event_delete(evq);
- }
- else{
- ensure_pub_entry(res->ent_head, sub);
- if(L) ni_resource_show(res, "Pending Resource:");
- if(pubcache){
- evq->ent_head=pubcache;
- post_to_driver(pub, evq);
- k_hashtable_delete(sub);
- }
- else{
- if(L) k_log_out("In-progress Pub-Cache sufficient");
- ni_event_delete(evq);
- }
- }
-}
-
-ni_resource* ensure_res(char* pub)
-{
- ni_resource* res=k_hashtable_get(resources, pub);
- if(!res){
- res=ni_resource_new(pub, k_hashtable_new("resHeaders", 1), 0);
- k_hashtable_set(resources, pub, res);
- }
- return res;
-}
-
-void ensure_sub_entry(k_hashtable* ent_head, k_hashtable* sub)
-{
- char* tag="Sub-To:";
- k_hashtable* sup=get_this(ent_head, tag, sub);
- if(!sup){
- k_hashtable* sup=k_hashtable_dup(sub);
- char* uri=k_hashtable_extract(sup, "Sub-To:");
- k_hashtable_put( sup, "URI:", uri);
- k_hashtable_remove( sup, "Sub-Type:");
- k_hashtable_sub(ent_head, tag, sup);
- }
- else{
- k_hashtable_remove(sup, "Range:");
- k_hashtable_remove(sup, "Content-Range:");
- k_hashtable_remove(sup, "Status:");
- k_hashtable_remove(sup, "Status-Cache:");
- char* mth=k_strdup(k_hashtable_get(sub, "Method:"));
- char* via=k_strdup(k_hashtable_get(sub, "Via:"));
- char* ims=k_strdup(k_hashtable_get(sub, "If-Modified-Since:"));
- char* rng=k_strdup(k_hashtable_get(sub, "Range:"));
- if(mth) k_hashtable_put(sup, "Method:", mth);
- if(via) k_hashtable_put(sup, "Via:", via);
- if(ims) k_hashtable_put(sup, "If-Modified-Since:", ims);
- if(rng) k_hashtable_put(sup, "Range:", rng);
- }
-}
-
-void ensure_pub_entry(k_hashtable* ent_head, k_hashtable* sub)
-{
- char* tag="Pub-To:";
- k_hashtable* sup=get_this(ent_head, tag, sub);
- if(!sup){
- k_hashtable* sup=k_hashtable_dup(sub);
- k_hashtable_remove(sup, "Sub-To:");
- k_hashtable_remove(sup, "Sub-Type:");
- k_hashtable_sub(ent_head, tag, sup);
- }
- else {
- k_hashtable_remove(sup, "Method:");
- k_hashtable_remove(sup, "If-Modified-Since:");
- k_hashtable_remove(sup, "Cache-Control:");
- k_hashtable_remove(sup, "Update:");
- char* mth=k_strdup(k_hashtable_get(sub, "Method:"));
- char* ims=k_strdup(k_hashtable_get(sub, "If-Modified-Since:"));
- char* ccn=k_strdup(k_hashtable_get(sub, "Cache-Control:"));
- char* upd=k_strdup(k_hashtable_get(sub, "Update:"));
- if(mth) k_hashtable_put(sup, "Method:", mth);
- if(ims) k_hashtable_put(sup, "If-Modified-Since:", ims);
- if(ccn) k_hashtable_put(sup, "Cache-Control:", ccn);
- if(upd) k_hashtable_put(sup, "Update:", upd);
- }
-}
-
-k_hashtable* get_this(k_hashtable* ent_head, char* pubsub, k_hashtable* try)
-{
- k_hashtable* curr=k_hashtable_get(ent_head, pubsub);
- if(!curr) return 0;
-
- char* tag;
- char* val;
-
- tag="From:";
- val=k_hashtable_get(try, tag);
- if(val) return get_using(curr, tag, val);
-
- tag="URI:";
- val=k_hashtable_get(try, tag);
- if(val) return get_using(curr, tag, val);
-
- return 0;
-}
-
-k_hashtable* get_using(k_hashtable* curr, char* tag, char* val)
-{
- k_hashtable* c;
- for(c=curr; c; c=c->next) if(k_hashtable_is(c, tag, val)) return c;
- return c;
-}
-
-/* -}{---- ------------------------------------------------------------------ */
-
-void incoming_resource(ni_event* evt)
-{
- int L=0;
- if(L) ni_event_show(evt, "ni got resource incoming event");
-
- ni_resource* res=k_hashtable_get(resources, evt->uri);
- int fullconst=res && k_hashtable_is(res->ent_head, "Status:", "200") &&
- k_hashtable_is(res->ent_head, "CUX:", "C");
-
- if(fullconst){
- k_log_err("Resource is complete and Constant");
- ni_event_delete(evt);
- return;
- }
- if(!res) res=ensure_res(evt->uri);
-
- k_hashtable* reseh=res->ent_head;
- k_hashtable* evteh=evt->ent_head;
- int okfull =k_hashtable_is(evteh, "Status:", "200");
- int partial =k_hashtable_is(evteh, "Status:", "206");
- int headonly=k_hashtable_is(evteh, "Status:", "260");/*
- int updated =k_hashtable_is(evteh, "Status:", "266");*/
- int notmod =k_hashtable_is(evteh, "Status:", "304");
- int notfound=k_hashtable_is(evteh, "Status:", "404");
-
- int entityok= (okfull || partial || notmod);
- int entityev=!(headonly || notmod || notfound);
- int entityin=!!evt->entity;
- int entityon=!!res->entity;
-
- if(!entityev){
- }
- if(okfull || !entityon){
- k_hashtable_merge(reseh, evteh);
- if(okfull) k_hashtable_remove(reseh, "Content-Range:");
- }
- else{
- merge_non_entity_headers(reseh, evteh);
- }
-
- fix_via_subs(evteh, reseh);
-
- if(entityin){
- if(okfull || (partial && !entityon)){
- if(res->entity!=evt->entity){
- if(!k_hashtable_is(reseh, "CUX:", "C")){
- k_free(res->entity);
- }
- res->entity=evt->entity;
- }
- }
- else
- if(partial && entityon){
- merge_entity_range(res, evt);
- }
- }
-
- if(L) ni_resource_show(res, "updated resource - sync and try pubs:");
-
- call_sync_resource(res);
-
- test_pub_tos(res, evt, entityok);
-
- evt->entity=0;
- ni_event_delete(evt);
-
- if(L) ni_resource_show(res, "resource after ni:");
-}
-
-void fix_via_subs(k_hashtable* evteh, k_hashtable* reseh)
-{
- char* from=k_hashtable_get(evteh, "From:");
- if(!from) return;
- k_hashtable* subs=k_hashtable_get(reseh, "Sub-To:");
- k_hashtable* sub;
- for(sub=subs; sub; sub=sub->next){
- if(!k_hashtable_is(sub, "Via:", from)) continue;
- int st=k_hashtable_get_int(evteh, "Status:");
- char* cr=k_hashtable_get_dup(evteh, "Content-Range:");
- if(st!=304) k_hashtable_put_int(sub, "Status:", st);
- if(st==200) k_hashtable_remove( sub, "Content-Range:");
- else
- if(cr) k_hashtable_put(sub, "Content-Range:", cr);
- if(sub_ok(sub)) k_hashtable_set(sub, "Status-Cache:", "OK");
- }
-}
-
-void test_pub_tos(ni_resource* res, ni_event* evt, int entityok)
-{
- k_hashtable* keeps=0;
- k_hashtable* sub=k_hashtable_extract(res->ent_head, "Pub-To:");
- while(sub){
- k_hashtable* subnext=sub->next;
- sub->next=0;
- int keep=1;
- int sat=satisfiable(sub, res, evt, entityok);
- update_pubcache(sat, 0, res->ent_head, sub);
- if(sat){
- respond(k_hashtable_dup(sub), res, evt);
- if(!k_hashtable_get(sub, "Update:")) keep=0;
- }
- if(keep){
- sub->next=keeps;
- keeps=sub;
- }
- else{
- k_hashtable_delete(sub);
- }
- sub=subnext;
- }
- sub=keeps;
- while(sub){
- k_hashtable* subnext=sub->next;
- k_hashtable_sub(res->ent_head, "Pub-To:", sub);
- sub=subnext;
- }
-}
-
-int satisfiable(k_hashtable* sub,
- ni_resource* res,
- ni_event* evt,
- int entityok)
-{
- int L=0;
- int get =k_hashtable_is( sub, "Method:", "GET");
- int head =k_hashtable_is( sub, "Method:", "HEAD");
- int dosub=k_hashtable_is( sub, "Method:", "SUB");
- int unsub=k_hashtable_is( sub, "Method:", "UNSUB");
- int full=!k_hashtable_isi(sub, "Cache-Control:", "no-full");
- int updt =k_hashtable_isi(sub, "Update:", "changes");
- char* ims =k_hashtable_get(sub, "If-Modified-Since:");
- char* range=k_hashtable_get(sub, "Range:");
-
- int getsub =get || dosub;
- int getrange=getsub && range;
-
- k_hashtable* reseh=res->ent_head;
- int gotall= k_hashtable_is( reseh, "Status:", "200");
- int gotrange= k_hashtable_is( reseh, "Status:", "206");
- int gothead= k_hashtable_is( reseh, "Status:", "260");
- int gotupdated=evt &&
- k_hashtable_is(evt->ent_head, "Status:", "266");
- int notfound= k_hashtable_is( reseh, "Status:", "404");
- int constant= k_hashtable_is( reseh, "CUX:", "C" );
- char* conrange= k_hashtable_get(reseh, "Content-Range:");
-
- if(unsub) return 0;
- if(notfound) return 1;
-
- int gotany=(gothead || gotrange || gotall);
- int snapok=(constant || !ims || entityok);
-
- int sat=
- (full &&
- ((getsub && gotall && snapok) ||
- (getrange && gotrange && range_ok(range, conrange) && snapok) ||
- (head && gotany ) ))
- ||
- (updt &&
- ((dosub && gotupdated)));
-
- if(L) k_log_out("satisfiable %d", sat);
- return sat;
-}
-
-void update_pubcache(int sat,
- k_hashtable** pubcachep,
- k_hashtable* reseh,
- k_hashtable* sub)
-{
- if(!sat){ if(pubcachep){
- k_hashtable* pubcache;
- pubcache=k_hashtable_get(reseh, "Pub-Cache:");
- if(!pubcache || sub_less(pubcache, sub)){
- if(!pubcache){
- pubcache=k_hashtable_dup(sub);
- k_hashtable_sub(reseh, "Pub-Cache:", pubcache);
- }
- else{
- k_hashtable_merge(pubcache, sub);
- }
- k_hashtable_remove(pubcache, "URI:");
- k_hashtable_remove(pubcache, "Sub-Type:");
- *pubcachep=k_hashtable_dup(pubcache);
- k_hashtable_set(*pubcachep, "Sub-Type:", "Cache");
- }
- }}
- else{ if(!pubcachep){
- k_hashtable* pubcache;
- pubcache=k_hashtable_get(reseh, "Pub-Cache:");
- if(!sub_less(sub, pubcache)){
- k_hashtable_remove(pubcache, "Method:");
- k_hashtable_remove(pubcache, "If-Modified-Since:");
- }
- }}
-}
-
-int sub_ok(k_hashtable* sub)
-{
- char* gotresp =k_hashtable_get(sub, "Status:");
- if(!gotresp) return 0;
- int notfound=k_hashtable_is( sub, "Status:", "404");
- if(notfound) return 0;
- int gotall =k_hashtable_is( sub, "Status:", "200");
- int gotrange=k_hashtable_is( sub, "Status:", "206");
- int gothead= k_hashtable_is( sub, "Status:", "260");
- int doget =k_hashtable_is( sub, "Method:", "GET");
- int dohead =k_hashtable_is( sub, "Method:", "HEAD");
- int dosub =k_hashtable_is( sub, "Method:", "SUB");
- char* range =k_hashtable_get(sub, "Range:");
- char* conrange=k_hashtable_get(sub, "Content-Range:");
-
- int dogetsub=doget || dosub;
- int dogetrange=dogetsub && range;
- int gotany =(gothead || gotrange || gotall);
-
- return (dogetsub && gotall ) ||
- (dogetrange && gotrange && range_ok(range, conrange)) ||
- (dohead && gotany );
-}
-
-int sub_less(k_hashtable* sub1, k_hashtable* sub2)
-{
- int L=0;
- if(L) k_log_out("sub_less sub1:");
- if(L) k_hashtable_show_chars(sub1);
- if(L) k_log_out("sub_less sub2:");
- if(L) k_hashtable_show_chars(sub2);
- char* mth1 =k_hashtable_get(sub1, "Method:");
- int head1=k_hashtable_is( sub1, "Method:", "HEAD");
- int get2 =k_hashtable_is( sub2, "Method:", "GET");
- char* ims1 =k_hashtable_get(sub1, "If-Modified-Since:");
- char* ims2 =k_hashtable_get(sub2, "If-Modified-Since:");
- int full=!k_hashtable_isi(sub2, "Cache-Control:", "no-full");
- return full && ((!mth1) || (head1 && get2) || (!ims1 && ims2));
-}
-
-int range_ok(char* range, char* conrange)
-{
- k_log_out("range_ok not implemented: %s vs %s", range, conrange);
- return 0;
-}
-
-void merge_non_entity_headers(k_hashtable* reseh, k_hashtable* evteh)
-{
-}
-
-void merge_entity_range(ni_resource* res, ni_event* evt)
-{
- k_log_out("merge_entity_range not implemented yet");
-}
-
-/* -}{---- ------------------------------------------------------------------ */
-
-void respond(k_hashtable* sub, ni_resource* res, ni_event* evt)
-{
- int updated=evt && k_hashtable_is(evt->ent_head, "Status:", "266");
- ni_event* evv=updated? ni_event_dup(evt):
- ni_res_to_evt(res);
- int L=0;
- if(L) ni_event_show(evv, "respond");
-
- k_hashtable_remove(evv->ent_head, "Permit:");
- k_hashtable_remove(evv->ent_head, "Sub-To:");
- k_hashtable_remove(evv->ent_head, "Pub-To:");
- k_hashtable_remove(evv->ent_head, "Pub-Cache:");
- k_hashtable_sub( evv->ent_head, "Pub-To:", sub);
-
- int nf;
- nf=k_hashtable_is( evv->ent_head, "Status:", "404");
- if(!nf) respond_ok(sub, evv);
- else respond_nf(sub, evv);
-}
-
-void respond_ok(k_hashtable* sub, ni_event* evv)
-{
- char* status=0;
- char* statustext=0;
- int datalength= -1;
- int nocache=0;
- k_hashtable* ent_head=evv->ent_head;
-
- time_t modifitime=k_hashtable_get_int(ent_head, "Last-Modified-Epoch:");
- char* modistring=k_hashtable_get( ent_head, "Last-Modified:");
- if(!modifitime){
- modifitime=k_time_from_rfc(modistring);
- }
- char* imss=k_hashtable_get(sub, "If-Modified-Since:");
- time_t imst=k_time_from_rfc(imss);
-
- if(modifitime== -1 || imst== -1 || modifitime > imst){
- if(k_hashtable_is(sub, "Method:", "HEAD")){
- evv->entity=0;
- }
- if(!k_hashtable_is(ent_head, "CUX:", "C")){
- evv->entity=entity_to_octets(ent_head, evv->entity);
- nocache=1;
- }
- }
- else{
- status="304";
- statustext="Not Modified";
- modifitime= -1;
- nocache= -1;
- evv->entity=0;
- drop_entity_headers(ent_head);
- }
-
- fill_headers(ent_head, status, statustext, 0,
- modistring? -1: modifitime,
- datalength, 0, 0, nocache);
-
- char* pub =k_hashtable_get(sub, "URI:");
- int L=0;
- if(L) ni_event_show(evv, "respond_ok");
- post_to_driver(pub, evv);
-}
-
-void respond_nf(k_hashtable* sub, ni_event* evv)
-{
- fill_headers(evv->ent_head, "404", "File Not Found", 0, -1, 0, 0, 0, 1);
- char* pub =k_hashtable_get(sub, "URI:");
- post_to_driver(pub, evv);
-}
-
-void post_to_driver(char* pub, ni_event* evq)
-{
- char* driver=handled_by(pub);
- if(0) k_log_out("Passing %s on to %s", pub, driver);
- if(0) ni_event_show(evq, "Post to Driver:");
- k_event_post(driver, evq);
-}
-
-void* entity_to_octets(k_hashtable* ent_head, void* entity)
-{
- if(!entity) return 0;
- size_t size=k_hashtable_get_int(ent_head, "Content-Length:");
- return k_memdup(entity, size);
-}
-
-/* -}{---- ------------------------------------------------------------------ */
-
-EXPORT char* ni_hostname()
-{
- return hostname? hostname: "not set";
-}
-
-EXPORT void ni_hostname_set(char* name)
-{
- k_free(hostname);
- hostname=k_strdup(name);
-}
-
-/* -}{---- ------------------------------------------------------------------ */
-
-static ni_driver* npdriver;
-static ni_driver* moddriver;
-
-char* handled_by(char* pub)
-{
- if(moddriver->handles_resource(pub)) return moddriver->name;
- return "np";
-}
-
-void call_sync_resource(ni_resource* res)
-{
- if(moddriver->handles_resource(res->uri)) moddriver->sync_resource(res);
- else npdriver->sync_resource(res);
-}
-
-ni_driver* ni_driver_new(char* name,
- ni_handles_resource handles_resource,
- ni_sync_resource sync_resource)
-{
- ni_driver* driver=k_malloc(sizeof(ni_driver));
- driver->name =name;
- driver->handles_resource=handles_resource;
- driver->sync_resource =sync_resource;
- return driver;
-}
-
-EXPORT void ni_register_driver(char* name,
- ni_handles_resource handles_resource,
- ni_sync_resource sync_resource)
-{
- ni_driver* d=ni_driver_new(name, handles_resource, sync_resource);
- if(!strcmp(name, "np")) npdriver=d;
- else moddriver=d;
-}
-
-/* -}{---- ------------------------------------------------------------------ */
-
-EXPORT ni_resource* ni_resource_new(char* uri,
- k_hashtable* ent_head,
- char* entity)
-{
- char* urih=k_hashtable_get(ent_head, "URI:");
- if(urih) uri=urih;
- else
- if(uri) k_hashtable_put_dup(ent_head, "URI:", uri);
-
- ni_resource* res=k_malloc(sizeof(ni_resource));
- res->uri =(uri? k_strdup(uri): 0);
- res->ent_head=ent_head;
- res->entity =entity;
- return res;
-}
-
-EXPORT ni_resource* ni_resource_dup(ni_resource* res)
-{
- ni_resource* rep=k_malloc(sizeof(ni_resource));
- rep->uri =k_strdup( res->uri);
- rep->ent_head=k_hashtable_dup(res->ent_head);
- rep->entity = res->entity;
- return rep;
-}
-
-EXPORT void ni_resource_delete(ni_resource* res)
-{
- if(!res) return;
- if(res->entity && res->ent_head){
- int constant=k_hashtable_is(res->ent_head, "CUX:", "C");
- if(!constant) k_free(res->entity);
- }
- k_hashtable_delete(res->ent_head);
- k_free( res->uri);
- k_free( res);
-}
-
-static char* excto[]={ "Permit:", "Sub-To:", "Pub-To:", 0 };
-static char* perto[]={ "Permit:", 0 };
-static char* subto[]={ "Sub-To:", 0 };
-static char* pubto[]={ "Pub-To:", 0 };
-
-EXPORT void ni_resource_show(ni_resource* res, char* text)
-{
- if(!res){
- k_log_out("\n---%s--------\n------------\n\n----------",
- text);
- }
- else{
- char* b=tmpbuf;
- size_t s=TMPBUFSIZE;
- size_t l=0;
- l+=k_hashtable_snprintf_x(res->ent_head, b+l, s-l, excto);
- l+=k_hashtable_snprintf_i(res->ent_head, b+l, s-l, perto);
- l+=k_hashtable_snprintf_i(res->ent_head, b+l, s-l, subto);
- l+=k_hashtable_snprintf_i(res->ent_head, b+l, s-l, pubto);
- k_log_out("\n---%s----%s--\n%s----------\n%p\n----------",
- text, res->uri, tmpbuf, res->entity);
- }
-}
-
-/* -}{---- ------------------------------------------------------------------ */
-
-EXPORT ni_resource* ni_resource_get(char* uri)
-{
- return k_hashtable_get(resources, uri);
-}
-
-/* -}{---- ------------------------------------------------------------------ */
-
-EXPORT ni_event* ni_res_to_evt(ni_resource* res)
-{
- ni_event* evp=k_malloc(sizeof(ni_event));
- evp->uri =k_strdup( res->uri);
- evp->evt_head=k_hashtable_new("vHeaders/ni_res_to_evt", 1);
- evp->ent_head=k_hashtable_dup(res->ent_head);
- evp->entity = res->entity;
- return evp;
-}
-
-/* -}{---- ------------------------------------------------------------------ */
-
-EXPORT ni_event* ni_event_new(char* uri,
- k_hashtable* evt_head,
- k_hashtable* ent_head,
- char* entity)
-{
- char* urih=k_hashtable_get(ent_head, "URI:");
- if(urih) uri=urih;
- else
- if(uri) k_hashtable_put_dup(ent_head, "URI:", uri);
-
- ni_event* evt=k_malloc(sizeof(ni_event));
- evt->uri =(uri? k_strdup(uri): 0);
- evt->evt_head=evt_head;
- evt->ent_head=ent_head;
- evt->entity =entity;
- return evt;
-}
-
-EXPORT ni_event* ni_event_dup(ni_event* evt)
-{
- ni_event* evp=k_malloc(sizeof(ni_event));
- evp->uri =k_strdup( evt->uri);
- evp->evt_head=k_hashtable_dup(evt->evt_head);
- evp->ent_head=k_hashtable_dup(evt->ent_head);
- evp->entity = evt->entity;
- return evp;
-}
-
-EXPORT void ni_event_delete(ni_event* evt)
-{
- if(!evt) return;
- if(evt->entity && evt->ent_head){
- int constant=k_hashtable_is(evt->ent_head, "CUX:", "C");
- if(!constant) k_free(evt->entity);
- }
- k_hashtable_delete(evt->evt_head);
- k_hashtable_delete(evt->ent_head);
- k_free( evt->uri);
- k_free( evt);
-}
-
-EXPORT void ni_event_show(ni_event* evt, char* text)
-{
- if(!evt){
- k_log_out("\n---%s--------\n------------\n\n----------",
- text);
- }
- else{
- char* buf=tmpbuf;
- int siz=TMPBUFSIZE;
- int n=k_hashtable_snprintf(evt->evt_head, buf, siz)+1;
- ; k_hashtable_snprintf(evt->ent_head, buf+n, siz-n);
- k_log_out("\n---%s----%s--\n"
- "%s----------\n"
- "%s----------\n"
- "%p\n----------",
- text, evt->uri, buf, buf+n, evt->entity);
- }
-}
-
-/* -}{----------------------------------------------------------------------- */
-
-
-
-
--- /dev/null
+
+/* -}{----------------------------------------------------------------------- */
+
+#include <kernelapi.h>
+#undef PUBLIC
+#define PUBLIC EXPORT
+#include <notification.h>
+
+/* -}{---- ------------------------------------------------------------------ */
+
+static k_hashtable* entity_headers;
+
+/* -}{---- ------------------------------------------------------------------ */
+
+#define TMPBUFSIZE 4096
+static char tmpbuf[TMPBUFSIZE];
+
+/* -}{----------------------------------------------------------------------- */
+
+static char* get_request( char* header, k_hashtable*, k_hashtable*);
+static char* get_response(char* header, k_hashtable*, k_hashtable*);
+static char* get_val(char** atp);
+static char* end_of_val(char* at);
+static void fix_keepalive(k_hashtable* evt_head);
+static void fix_cache_control(k_hashtable* ent_head);
+static void fix_uri(k_hashtable* ent_head);
+static void fix_subscribe(k_hashtable*, k_hashtable*);
+
+/* -}{----------------------------------------------------------------------- */
+
+#define WHITESPACEH " \t"
+#define WHITESPACEV "\012\015"
+#define WHITESPACE WHITESPACEH WHITESPACEV
+
+EXPORT ni_event* ni_get_request_headers(char* header)
+{
+ k_hashtable* evt_head=k_hashtable_new("vHeaders/get_req_hdrs", 1);
+ k_hashtable* ent_head=k_hashtable_new("nHeaders/get_req_hdrs", 1);
+ k_hashtable_put(ent_head, "", header);
+
+ char* h=get_request(header, evt_head, ent_head);
+ if(!h){
+ k_hashtable_delete(evt_head);
+ k_hashtable_delete(ent_head);
+ return 0;
+ }
+
+ h=ni_get_headers(h, evt_head, ent_head);
+ if(!h){
+ k_hashtable_delete(evt_head);
+ k_hashtable_delete(ent_head);
+ return 0;
+ }
+
+ fix_keepalive(evt_head);
+ fix_cache_control(ent_head);
+ fix_uri(ent_head);
+ fix_subscribe(evt_head, ent_head);
+
+ ni_event* evq=ni_event_new(0, evt_head, ent_head, 0);
+
+ return evq;
+}
+
+EXPORT ni_event* ni_get_response_headers(char* header)
+{
+ k_hashtable* evt_head=k_hashtable_new("vHeaders/get_resp_hdrs", 1);
+ k_hashtable* ent_head=k_hashtable_new("nHeaders/get_resp_hdrs", 1);
+ k_hashtable_put(ent_head, "", header);
+
+ char* h=get_response(header, evt_head, ent_head);
+ if(!h){
+ k_hashtable_delete(evt_head);
+ k_hashtable_delete(ent_head);
+ return 0;
+ }
+
+ h=ni_get_headers(h, evt_head, ent_head);
+ if(!h){
+ k_hashtable_delete(evt_head);
+ k_hashtable_delete(ent_head);
+ return 0;
+ }
+
+ ni_event* evt=ni_event_new(0, evt_head, ent_head, 0);
+
+ return evt;
+}
+
+EXPORT char* ni_get_headers(char* header,
+ k_hashtable* evt_head,
+ k_hashtable* ent_head)
+{
+ char* at=header;
+ char* tag;
+ char* val;
+ while(*at){
+
+ tag=at;
+ at=strpbrk(at, WHITESPACE);
+ if(!at || at==tag) return 0;
+ char* e=at;
+ val=get_val(&at);
+ *e=0;
+
+ if(strlen(val) > 2048) return 0;
+
+ k_hashtable* h;
+ h=k_hashtable_get(entity_headers, tag)? ent_head: evt_head;
+ if(h){
+ char* old=k_hashtable_get(h, tag);
+ if(!old) k_hashtable_set(h, tag, val);
+ }
+ }
+ return at;
+}
+
+EXPORT void ni_fix_http_headers(k_hashtable* ent_head)
+{
+ if(k_hashtable_is(ent_head, "Status:", "260")){
+ char* crn=k_hashtable_get(ent_head, "Content-Range:");
+ char* clg=k_hashtable_get(ent_head, "Content-Length-Given:");
+ if(crn || clg){
+ k_hashtable_set(ent_head, "Status:", "206");
+ k_hashtable_set(ent_head, "Status-Text:", "Partial Content");
+ }
+ else{
+ k_hashtable_set(ent_head, "Status:", "200");
+ k_hashtable_set(ent_head, "Status-Text:", "OK");
+ }
+ }
+ k_hashtable_remove(ent_head, "URI:");
+ k_hashtable_remove(ent_head, "Method:");
+ k_hashtable_remove(ent_head, "From:");
+ k_hashtable_remove(ent_head, "Content-Length-Given:");
+ k_hashtable_remove(ent_head, "Last-Modified-Epoch:");
+
+ char* cc=k_hashtable_get(ent_head, "Cache-Control:");
+ if(cc && strstr(cc, "no-cache")){
+ k_hashtable_set(ent_head, "Pragma:", "no-cache");
+ }
+}
+
+EXPORT void ni_fix_ni_headers(k_hashtable* ent_head, int methead)
+{
+ if(methead && (k_hashtable_is(ent_head, "Status:", "200") ||
+ k_hashtable_is(ent_head, "Status:", "206") )){
+
+ k_hashtable_set(ent_head, "Status:", "260");
+ k_hashtable_set(ent_head, "Status-Text:", "Headers Only");
+ }
+ k_hashtable_remove(ent_head, "Method:");
+ k_hashtable_remove(ent_head, "Sub-To:");
+ k_hashtable_remove(ent_head, "Via:");
+ k_hashtable_set( ent_head, "From:", ni_hostname());
+
+ char* uri=k_hashtable_get(ent_head, "URI:");
+ if(*uri=='.'){
+ snprintf(tmpbuf, TMPBUFSIZE, "%s/%s", ni_hostname(), uri+2);
+ k_hashtable_put_dup(ent_head, "URI:", tmpbuf);
+ }
+}
+
+EXPORT void ni_response(ni_event* evt,
+ char* to,
+ char* method,
+ char* protocol,
+ char* connection,
+ k_channel* chan)
+{
+ int L=0;
+ snprintf(tmpbuf, TMPBUFSIZE, "%s", k_time_to_rfc_relative(0));
+ k_hashtable_put_dup(evt->evt_head, "Date:", tmpbuf);
+ k_hashtable_set( evt->evt_head, "Server:", k_version);
+ if(connection)
+ k_hashtable_put_dup(evt->evt_head, "Connection:", connection);
+
+ int status =k_hashtable_get_int(evt->ent_head, "Status:");
+ char* statustext=k_hashtable_get( evt->ent_head, "Status-Text:");
+ int datalength=k_hashtable_get_int(evt->ent_head, "Content-Length:");
+ int constant =k_hashtable_is( evt->ent_head, "CUX:", "C");
+
+ char* buf =tmpbuf;
+ int bufsize=TMPBUFSIZE;
+ int ln=0;
+
+ ln+=snprintf(buf+ln, bufsize-ln, "%s %d %s" CRLF,
+ protocol, status, statustext);
+ if(ln>=bufsize) return;
+
+ static char* exheaders[]={ "Status:", "Status-Text:",
+ "Protocol:", "CUX:", 0 };
+
+ ln+=k_hashtable_snprintf_x(evt->evt_head, buf+ln,bufsize-ln, exheaders);
+ if(ln>=bufsize) return;
+
+ ln+=k_hashtable_snprintf_x(evt->ent_head, buf+ln,bufsize-ln, exheaders);
+ if(ln>=bufsize) return;
+
+ ln+=snprintf(buf+ln, bufsize-ln, CRLF);
+ if(ln>=bufsize) return;
+
+ char* head=k_strdup(buf);
+ if(L) k_log_out("Actual response headers:\n%s", head);
+ k_channel_send(chan, head, ln, FREE_ON_SENT);
+
+ if(evt->entity && datalength){
+ k_channel_send(chan, evt->entity, datalength, !constant);
+ }
+ else{
+ datalength=0;
+ if(!constant) k_free(evt->entity);
+ }
+ k_log_out("%s %s %s %d %d", to, method, evt->uri, status, datalength);
+}
+
+EXPORT void ni_request(ni_event* evt, char* to, char* method, k_channel* chan)
+{
+ k_hashtable* sub=evt->ent_head;
+
+ int ln=0;
+ int bufsize=TMPBUFSIZE;
+
+ ln+=snprintf(tmpbuf+ln, bufsize-ln, "%s //%s OP/0.5" CRLF, method, to);
+ if(ln>=bufsize) return;
+
+ ln+=k_hashtable_snprintf(sub, tmpbuf+ln, bufsize-ln);
+ if(ln>=bufsize) return;
+
+ ln+=snprintf(tmpbuf+ln, bufsize-ln, CRLF);
+ if(ln>=bufsize) return;
+
+ char* head=k_strdup(tmpbuf);
+ if(0) k_log_out("Actual request headers:\n%s", head);
+ k_channel_send(chan, head, ln, FREE_ON_SENT);
+}
+
+/* -}{----------------------------------------------------------------------- */
+
+char* get_request(char* header, k_hashtable* evt_head, k_hashtable* ent_head)
+{
+ char* at=header;
+ char* method=at;
+ at=strpbrk(at, WHITESPACEH);
+ if(!at) return 0;
+ *at++=0;
+
+ k_hashtable_set(ent_head, "Method:", method);
+
+ char* file=0;
+ char* host=0;
+ if(strcmp(method, "PING")){
+
+ at+=strspn(at, WHITESPACEH);
+ file=at;
+ at=strpbrk(at, WHITESPACEH);
+ if(!at) return 0;
+ *at++=0;
+ if(strlen(file) > 1024 ) return 0;
+
+ if(!strncmp(file, "http://", 7)){
+ char* s=file+7;
+ if(!*s || *s=='/') return 0;
+ char* e=strchr(s, '/');
+ if(!e) return 0;
+ host=s;
+ *e++=0;
+ file=e;
+ }
+ else
+ if(*file=='/') file++;
+ else return 0;
+
+ if(*file=='/'){
+ char* s=file+1;
+ if(!*s || *s=='/') return 0;
+ char* e=strchr(s, '/');
+ if(!e) return 0;
+ host=s;
+ *e++=0;
+ file=e;
+ }
+ }
+ if(file) k_hashtable_set(evt_head, "File:", file);
+ if(host) k_hashtable_set(evt_head, "Host:", host);
+
+ at+=strspn(at, WHITESPACEH);
+ char* protocol=at;
+ at=strpbrk(at, WHITESPACE);
+ if(!at) at=protocol+strlen(protocol);
+ else *at++=0;
+
+ k_hashtable_set(evt_head, "Protocol:", protocol);
+
+ at+=strspn(at, WHITESPACE);
+ return at;
+}
+
+char* get_response(char* header, k_hashtable* evt_head, k_hashtable* ent_head)
+{
+ char* at=header;
+ char* protocol=at;
+ at=strpbrk(at, WHITESPACEH);
+ if(!at) return 0;
+ *at++=0;
+
+ k_hashtable_set(evt_head, "Protocol:", protocol);
+
+ at+=strspn(at, WHITESPACEH);
+ char* status=at;
+ at=strpbrk(at, WHITESPACEH);
+ if(!at) return 0;
+ *at++=0;
+
+ at+=strspn(at, WHITESPACEH);
+ char* statustext=at;
+ at=strpbrk(at, WHITESPACEV);
+ if(!at) return 0;
+ *at++=0;
+
+ k_hashtable_set(ent_head, "Status:", status);
+ k_hashtable_set(ent_head, "Status-Text:", statustext);
+
+ at+=strspn(at, WHITESPACE);
+ return at;
+}
+
+char* get_val(char** atp)
+{
+ char* at=*atp;
+ char* val=at;
+
+ val+=strspn(val, WHITESPACEH);
+ val+=strspn(val, WHITESPACEV);
+
+ char* eov=end_of_val(at);
+ if(eov<val) val=eov;
+ if(*eov) *eov++=0;
+
+ *atp=eov+strspn(eov, WHITESPACEV);
+ return val;
+}
+
+char* end_of_val(char* at)
+{
+ char* eov;
+ do{
+ char* v=strpbrk(at, WHITESPACEV);
+ if(!v) return at+strlen(at);
+ eov=v;
+ at=v+strspn(v, WHITESPACEV);
+
+ }while(strspn(at, WHITESPACEH));
+
+ return eov;
+}
+
+void fix_keepalive(k_hashtable* evt_head)
+{
+ int keepalive=0;
+ int is11=k_hashtable_is( evt_head, "Protocol:", "HTTP/1.1");
+ int isps=k_hashtable_isn(evt_head, "Protocol:", "OP/", 4);
+ int iska=k_hashtable_isi(evt_head, "Connection:", "Keep-Alive");
+ int iscl=k_hashtable_isi(evt_head, "Connection:", "close");
+ if((!is11 && iska) || (is11 && !iscl) || isps){
+ keepalive=1;
+ }
+ if(0) k_log_out("is11=%d iska=%d iscl=%d isps=%d ka=%d",
+ is11, iska, iscl, isps, keepalive);
+ k_hashtable_set(evt_head, "Connection:",
+ keepalive? "Keep-Alive": "close");
+}
+
+void fix_cache_control(k_hashtable* ent_head)
+{
+ char* cachec=k_hashtable_get( ent_head, "Cache-Control:");
+ char* pragma=k_hashtable_extract(ent_head, "Pragma:");
+ if(!cachec && pragma && strstr(pragma, "no-cache")){
+ k_hashtable_set( ent_head, "Cache-Control:","no-cache");
+ }
+}
+
+void fix_uri(k_hashtable* ent_head)
+{
+ char* uri=k_hashtable_get(ent_head, "URI:");
+ if(!uri) return;
+ char* nihostname=ni_hostname();
+ int l=strlen(nihostname);
+ if(strncmp(uri, nihostname, l)) return;
+ snprintf(tmpbuf, TMPBUFSIZE, ".%s", uri+l);
+ k_hashtable_put_dup(ent_head, "URI:", tmpbuf);
+}
+
+void fix_subscribe(k_hashtable* evt_head, k_hashtable* ent_head)
+{
+ char* host=k_hashtable_extract(evt_head, "Host:");
+ char* file=k_hashtable_extract(evt_head, "File:");
+ if(host){
+ k_string_url_decode(host);
+ int localhostdns=!strcmp( host, "localhost") ||
+ !strncmp(host, "localhost:", 10);
+ int localhostni=!strcmp(host, ni_hostname());
+ char* lastdot=strrchr(host, '.');
+ int dotdotnumber=lastdot && atoi(lastdot+1) >0;
+ if(localhostdns || localhostni || dotdotnumber){
+ host=".";
+ }
+ }
+ else{
+ host=".";
+ }
+ if(file){
+ k_string_url_decode(file);
+ snprintf(tmpbuf, TMPBUFSIZE, "%s/%s", host, file);
+ k_hashtable_put_dup(ent_head, "Sub-To:", tmpbuf);
+ k_hashtable_set( ent_head, "Sub-Type:", "Original");
+ }
+}
+
+void init_headers(void)
+{
+ entity_headers =k_hashtable_new("Entity Headers", 1);
+
+ k_hashtable_set(entity_headers, "URI:", (void*)1);
+ k_hashtable_set(entity_headers, "From:", (void*)1);
+ k_hashtable_set(entity_headers, "To:", (void*)1);
+ k_hashtable_set(entity_headers, "Via:", (void*)1);
+ k_hashtable_set(entity_headers, "Sub-To:", (void*)1);
+ k_hashtable_set(entity_headers, "Sub-Type:", (void*)1);
+ k_hashtable_set(entity_headers, "Method:", (void*)1);
+ k_hashtable_set(entity_headers, "Status:", (void*)1);
+ k_hashtable_set(entity_headers, "Status-Text:", (void*)1);
+ k_hashtable_set(entity_headers, "Last-Modified-Epoch:", (void*)1);
+ k_hashtable_set(entity_headers, "CUX:", (void*)1);
+
+ k_hashtable_set(entity_headers, "Range:", (void*)1);
+ k_hashtable_set(entity_headers, "If-Modified-Since:", (void*)1);
+ k_hashtable_set(entity_headers, "If-None-Match:", (void*)1);
+ k_hashtable_set(entity_headers, "Cache-Control:", (void*)1);
+ k_hashtable_set(entity_headers, "Pragma:", (void*)1);
+
+ k_hashtable_set(entity_headers, "Content-Length:", (void*)1);
+ k_hashtable_set(entity_headers, "Content-Type:", (void*)1);
+ k_hashtable_set(entity_headers, "Content-Encoding:", (void*)1);
+ k_hashtable_set(entity_headers, "Content-Location:", (void*)1);
+ k_hashtable_set(entity_headers, "Content-MD5:", (void*)1);
+ k_hashtable_set(entity_headers, "Content-Language:", (void*)1);
+ k_hashtable_set(entity_headers, "Content-Range:", (void*)1);
+ k_hashtable_set(entity_headers, "Last-Modified:", (void*)1);
+ k_hashtable_set(entity_headers, "ETag:", (void*)1);
+ k_hashtable_set(entity_headers, "Expires:", (void*)1);
+
+ k_hashtable_set(entity_headers, "Allow:", (void*)1);
+}
+
+void drop_entity_headers(k_hashtable* ent_head)
+{
+ k_hashtable_remove(ent_head, "Content-Length:");
+ k_hashtable_remove(ent_head, "Content-Range:");
+ k_hashtable_remove(ent_head, "Content-Type:");
+ k_hashtable_remove(ent_head, "Content-Encoding:");
+ k_hashtable_remove(ent_head, "Content-Location:");
+ k_hashtable_remove(ent_head, "Last-Modified:");
+#ifdef DO_THESE_ONES_TOO
+ k_hashtable_remove(ent_head, "Allow:");
+ k_hashtable_remove(ent_head, "Content-Language:");
+ k_hashtable_remove(ent_head, "Content-MD5:");
+ k_hashtable_remove(ent_head, "Expires:");
+#endif
+}
+
+void fill_headers(k_hashtable* ent_head,
+ char* status,
+ char* statustext,
+ char* uri,
+ time_t modifitime,
+ int datalength,
+ char* mimetype,
+ char* encoding,
+ int nocache)
+{
+ if(status){
+ k_hashtable_put_dup(ent_head, "Status:", status);
+ k_hashtable_put_dup(ent_head, "Status-Text:", statustext);
+ }
+ if(uri){
+ k_hashtable_put_dup(ent_head, "URI:", uri);
+ }
+ if(modifitime>=0){
+ snprintf(tmpbuf, TMPBUFSIZE, "%s", k_time_to_rfc(modifitime));
+ k_hashtable_put_dup(ent_head, "Last-Modified:", tmpbuf);
+ }
+ if(datalength>=0){
+ snprintf(tmpbuf, TMPBUFSIZE, "%d", datalength);
+ k_hashtable_put_dup(ent_head, "Content-Length:", tmpbuf);
+ }
+ if(mimetype){
+ k_hashtable_put_dup(ent_head, "Content-Type:", mimetype);
+ }
+ if(encoding){
+ k_hashtable_put_dup(ent_head, "Content-Encoding:", encoding);
+ }
+ if(nocache==1){
+ k_hashtable_put_dup(ent_head, "Cache-Control:",
+ "no-cache,no-store");
+ }
+ else
+ if(nocache==0){
+ long maxage=31449600;
+ snprintf(tmpbuf, TMPBUFSIZE, "max-age=%ld", maxage);
+ char* maxages=k_time_to_rfc_relative(maxage);
+ k_hashtable_put_dup(ent_head, "Cache-Control:", tmpbuf);
+ k_hashtable_put_dup(ent_head, "Expires:", maxages);
+ }
+ else
+ if(nocache== -1){
+ k_hashtable_remove(ent_head, "Cache-Control:");
+ k_hashtable_remove(ent_head, "Expires:");
+ }
+}
+
+/* -}{---- ------------------------------------------------------------------ */
+
--- /dev/null
+
+/* -}{----------------------------------------------------------------------- */
+
+#include <kernelapi.h>
+#undef PUBLIC
+#define PUBLIC EXPORT
+#include <notification.h>
+
+/* -}{---- ------------------------------------------------------------------ */
+
+EXPORT n_object* n_object_new(char* s)
+{
+ return 0;
+}
+
+EXPORT void n_commit(n_object* o)
+{
+}
+
+EXPORT n_object* n_see(n_object* o, char* uid)
+{
+ return 0;
+}
+
+EXPORT char* n_to_string(n_object* o)
+{
+ return 0;
+}
+
+EXPORT char* n_uid(n_object* o)
+{
+ return 0;
+}
+
+EXPORT char* n_header(n_object* o, char* name)
+{
+ return 0;
+}
+
+EXPORT k_hashtable* n_headers(n_object* o)
+{
+ return 0;
+}
+
+EXPORT k_hashtable* n_content(n_object* o)
+{
+ return 0;
+}
+
+/* -}{---- ------------------------------------------------------------------ */
+
+#define TMPBUFSIZE 4096
+static char tmpbuf[TMPBUFSIZE];
+static char* hostname;
+static k_hashtable* resources;
+
+/* -}{---- ------------------------------------------------------------------ */
+
+typedef struct ni_driver{
+ char* name;
+ ni_handles_resource handles_resource;
+ ni_sync_resource sync_resource;
+} ni_driver;
+
+/* -}{---- From headers.c --------------------------------------------------- */
+
+extern void init_headers(void);
+extern void drop_entity_headers(k_hashtable* ent_head);
+extern void fill_headers(k_hashtable* ent_head,
+ char* status,
+ char* statustext,
+ char* uri,
+ time_t modifitime,
+ int datalength,
+ char* mimetype,
+ char* encoding,
+ int nocache);
+
+/* -}{---- ------------------------------------------------------------------ */
+
+static void incoming_request(ni_event* evq);
+static ni_resource* ensure_res(char* pub);
+static void ensure_sub_entry(k_hashtable* ent_head, k_hashtable* sub);
+static void ensure_pub_entry(k_hashtable* ent_head, k_hashtable* sub);
+static k_hashtable* get_this(k_hashtable*, char*, k_hashtable*);
+static k_hashtable* get_using(k_hashtable* curr, char* tag, char* val);
+static void post_to_driver(char* pub, ni_event* evq);
+static void incoming_resource(ni_event* evt);
+static void test_pub_tos(ni_resource* res, ni_event* evt, int entityok);
+static int satisfiable(k_hashtable*, ni_resource*, ni_event*, int);
+static void update_pubcache(int, k_hashtable**, k_hashtable*, k_hashtable*);
+static int sub_less(k_hashtable* sub1, k_hashtable* sub2);
+static void fix_via_subs(k_hashtable* evteh, k_hashtable* reseh);
+static int sub_ok(k_hashtable* sub);
+static int range_ok(char* range, char* conrange);
+static void merge_non_entity_headers(k_hashtable* reseh, k_hashtable* evteh);
+static void merge_entity_range(ni_resource* res, ni_event* evt);
+static void respond( k_hashtable* sub, ni_resource* res, ni_event* evt);
+static void respond_ok(k_hashtable* sub, ni_event* evv);
+static void respond_nf(k_hashtable* sub, ni_event* evv);
+static void* entity_to_octets(k_hashtable* ent_head, void* entity);
+static char* handled_by(char* pub);
+static void call_sync_resource(ni_resource* res);
+static ni_driver* ni_driver_new(char* name,
+ ni_handles_resource handles_resource,
+ ni_sync_resource sync_resource);
+
+/* -}{---- ------------------------------------------------------------------ */
+
+EXPORT int on_module_loaded(void)
+{
+ resources=k_hashtable_new("Resources", 0);
+
+ init_headers();
+
+ k_log_out("ON initialised");
+ return 1;
+}
+
+EXPORT void on_module_tick(void)
+{
+}
+
+EXPORT int on_module_event(void* data)
+{
+ ni_event* evt=data;
+
+ if(!k_hashtable_get(evt->ent_head, "Status:")){
+
+ incoming_request(evt);
+ }
+ else{
+ incoming_resource(evt);
+ }
+ return 1;
+}
+
+/* -}{---- ------------------------------------------------------------------ */
+
+void incoming_request(ni_event* evq)
+{
+ int L=1;
+ if(L) ni_event_show(evq, "ON got request event");
+
+ k_hashtable* sub=evq->ent_head;
+ char* uri =k_hashtable_get(sub, "URI:");
+ char* pub =k_hashtable_get(sub, "Sub-To:"); if(!pub) return;
+ int styor=k_hashtable_isi(sub, "Sub-Type:", "Original");
+ char* via =k_hashtable_get(sub, "Via:");
+ char* from =k_hashtable_get(sub, "From:");
+ if(L) k_log_out("------------------ %s", pub);
+
+ int nocache=k_hashtable_isi(sub, "Cache-Control:", "no-cache");
+ if(nocache){
+ k_hashtable_remove( sub, "Cache-Control:");
+ k_hashtable_set( sub, "If-Modified-Since:", "0");
+ }
+
+ if(!from){
+ ni_resource* ses=k_hashtable_get(resources, uri);
+ if(ses) ensure_sub_entry(ses->ent_head, sub);
+ if(ses) if(L) ni_resource_show(ses, "Subscribing Resource:");
+ if(styor && via){
+ post_to_driver(pub, evq);
+ return;
+ }
+ }
+
+ ni_resource* res=ensure_res(pub);
+ if(L) ni_resource_show(res, "Publishing Resource:");
+
+ k_hashtable* pubcache=0;
+ int sat=satisfiable(sub, res, 0, 0);
+ update_pubcache(sat, &pubcache, res->ent_head, sub);
+ if(sat){
+ if(L) k_log_out("Memory cache hit for %s", pub);
+ respond(k_hashtable_dup(sub), res, 0);
+ ni_event_delete(evq);
+ }
+ else{
+ ensure_pub_entry(res->ent_head, sub);
+ if(L) ni_resource_show(res, "Pending Resource:");
+ if(pubcache){
+ evq->ent_head=pubcache;
+ post_to_driver(pub, evq);
+ k_hashtable_delete(sub);
+ }
+ else{
+ if(L) k_log_out("In-progress Pub-Cache sufficient");
+ ni_event_delete(evq);
+ }
+ }
+}
+
+ni_resource* ensure_res(char* pub)
+{
+ ni_resource* res=k_hashtable_get(resources, pub);
+ if(!res){
+ res=ni_resource_new(pub, k_hashtable_new("resHeaders", 1), 0);
+ k_hashtable_set(resources, pub, res);
+ }
+ return res;
+}
+
+void ensure_sub_entry(k_hashtable* ent_head, k_hashtable* sub)
+{
+ char* tag="Sub-To:";
+ k_hashtable* sup=get_this(ent_head, tag, sub);
+ if(!sup){
+ k_hashtable* sup=k_hashtable_dup(sub);
+ char* uri=k_hashtable_extract(sup, "Sub-To:");
+ k_hashtable_put( sup, "URI:", uri);
+ k_hashtable_remove( sup, "Sub-Type:");
+ k_hashtable_sub(ent_head, tag, sup);
+ }
+ else{
+ k_hashtable_remove(sup, "Range:");
+ k_hashtable_remove(sup, "Content-Range:");
+ k_hashtable_remove(sup, "Status:");
+ k_hashtable_remove(sup, "Status-Cache:");
+ char* mth=k_strdup(k_hashtable_get(sub, "Method:"));
+ char* via=k_strdup(k_hashtable_get(sub, "Via:"));
+ char* ims=k_strdup(k_hashtable_get(sub, "If-Modified-Since:"));
+ char* rng=k_strdup(k_hashtable_get(sub, "Range:"));
+ if(mth) k_hashtable_put(sup, "Method:", mth);
+ if(via) k_hashtable_put(sup, "Via:", via);
+ if(ims) k_hashtable_put(sup, "If-Modified-Since:", ims);
+ if(rng) k_hashtable_put(sup, "Range:", rng);
+ }
+}
+
+void ensure_pub_entry(k_hashtable* ent_head, k_hashtable* sub)
+{
+ char* tag="Pub-To:";
+ k_hashtable* sup=get_this(ent_head, tag, sub);
+ if(!sup){
+ k_hashtable* sup=k_hashtable_dup(sub);
+ k_hashtable_remove(sup, "Sub-To:");
+ k_hashtable_remove(sup, "Sub-Type:");
+ k_hashtable_sub(ent_head, tag, sup);
+ }
+ else {
+ k_hashtable_remove(sup, "Method:");
+ k_hashtable_remove(sup, "If-Modified-Since:");
+ k_hashtable_remove(sup, "Cache-Control:");
+ k_hashtable_remove(sup, "Update:");
+ char* mth=k_strdup(k_hashtable_get(sub, "Method:"));
+ char* ims=k_strdup(k_hashtable_get(sub, "If-Modified-Since:"));
+ char* ccn=k_strdup(k_hashtable_get(sub, "Cache-Control:"));
+ char* upd=k_strdup(k_hashtable_get(sub, "Update:"));
+ if(mth) k_hashtable_put(sup, "Method:", mth);
+ if(ims) k_hashtable_put(sup, "If-Modified-Since:", ims);
+ if(ccn) k_hashtable_put(sup, "Cache-Control:", ccn);
+ if(upd) k_hashtable_put(sup, "Update:", upd);
+ }
+}
+
+k_hashtable* get_this(k_hashtable* ent_head, char* pubsub, k_hashtable* try)
+{
+ k_hashtable* curr=k_hashtable_get(ent_head, pubsub);
+ if(!curr) return 0;
+
+ char* tag;
+ char* val;
+
+ tag="From:";
+ val=k_hashtable_get(try, tag);
+ if(val) return get_using(curr, tag, val);
+
+ tag="URI:";
+ val=k_hashtable_get(try, tag);
+ if(val) return get_using(curr, tag, val);
+
+ return 0;
+}
+
+k_hashtable* get_using(k_hashtable* curr, char* tag, char* val)
+{
+ k_hashtable* c;
+ for(c=curr; c; c=c->next) if(k_hashtable_is(c, tag, val)) return c;
+ return c;
+}
+
+/* -}{---- ------------------------------------------------------------------ */
+
+void incoming_resource(ni_event* evt)
+{
+ int L=0;
+ if(L) ni_event_show(evt, "ON got resource incoming event");
+
+ ni_resource* res=k_hashtable_get(resources, evt->uri);
+ int fullconst=res && k_hashtable_is(res->ent_head, "Status:", "200") &&
+ k_hashtable_is(res->ent_head, "CUX:", "C");
+
+ if(fullconst){
+ k_log_err("Resource is complete and Constant");
+ ni_event_delete(evt);
+ return;
+ }
+ if(!res) res=ensure_res(evt->uri);
+
+ k_hashtable* reseh=res->ent_head;
+ k_hashtable* evteh=evt->ent_head;
+ int okfull =k_hashtable_is(evteh, "Status:", "200");
+ int partial =k_hashtable_is(evteh, "Status:", "206");
+ int headonly=k_hashtable_is(evteh, "Status:", "260");/*
+ int updated =k_hashtable_is(evteh, "Status:", "266");*/
+ int notmod =k_hashtable_is(evteh, "Status:", "304");
+ int notfound=k_hashtable_is(evteh, "Status:", "404");
+
+ int entityok= (okfull || partial || notmod);
+ int entityev=!(headonly || notmod || notfound);
+ int entityin=!!evt->entity;
+ int entityon=!!res->entity;
+
+ if(!entityev){
+ }
+ if(okfull || !entityon){
+ k_hashtable_merge(reseh, evteh);
+ if(okfull) k_hashtable_remove(reseh, "Content-Range:");
+ }
+ else{
+ merge_non_entity_headers(reseh, evteh);
+ }
+
+ fix_via_subs(evteh, reseh);
+
+ if(entityin){
+ if(okfull || (partial && !entityon)){
+ if(res->entity!=evt->entity){
+ if(!k_hashtable_is(reseh, "CUX:", "C")){
+ k_free(res->entity);
+ }
+ res->entity=evt->entity;
+ }
+ }
+ else
+ if(partial && entityon){
+ merge_entity_range(res, evt);
+ }
+ }
+
+ if(L) ni_resource_show(res, "updated resource - sync and try pubs:");
+
+ call_sync_resource(res);
+
+ test_pub_tos(res, evt, entityok);
+
+ evt->entity=0;
+ ni_event_delete(evt);
+
+ if(L) ni_resource_show(res, "resource after ON:");
+}
+
+void fix_via_subs(k_hashtable* evteh, k_hashtable* reseh)
+{
+ char* from=k_hashtable_get(evteh, "From:");
+ if(!from) return;
+ k_hashtable* subs=k_hashtable_get(reseh, "Sub-To:");
+ k_hashtable* sub;
+ for(sub=subs; sub; sub=sub->next){
+ if(!k_hashtable_is(sub, "Via:", from)) continue;
+ int st=k_hashtable_get_int(evteh, "Status:");
+ char* cr=k_hashtable_get_dup(evteh, "Content-Range:");
+ if(st!=304) k_hashtable_put_int(sub, "Status:", st);
+ if(st==200) k_hashtable_remove( sub, "Content-Range:");
+ else
+ if(cr) k_hashtable_put(sub, "Content-Range:", cr);
+ if(sub_ok(sub)) k_hashtable_set(sub, "Status-Cache:", "OK");
+ }
+}
+
+void test_pub_tos(ni_resource* res, ni_event* evt, int entityok)
+{
+ k_hashtable* keeps=0;
+ k_hashtable* sub=k_hashtable_extract(res->ent_head, "Pub-To:");
+ while(sub){
+ k_hashtable* subnext=sub->next;
+ sub->next=0;
+ int keep=1;
+ int sat=satisfiable(sub, res, evt, entityok);
+ update_pubcache(sat, 0, res->ent_head, sub);
+ if(sat){
+ respond(k_hashtable_dup(sub), res, evt);
+ if(!k_hashtable_get(sub, "Update:")) keep=0;
+ }
+ if(keep){
+ sub->next=keeps;
+ keeps=sub;
+ }
+ else{
+ k_hashtable_delete(sub);
+ }
+ sub=subnext;
+ }
+ sub=keeps;
+ while(sub){
+ k_hashtable* subnext=sub->next;
+ k_hashtable_sub(res->ent_head, "Pub-To:", sub);
+ sub=subnext;
+ }
+}
+
+int satisfiable(k_hashtable* sub,
+ ni_resource* res,
+ ni_event* evt,
+ int entityok)
+{
+ int L=0;
+ int get =k_hashtable_is( sub, "Method:", "GET");
+ int head =k_hashtable_is( sub, "Method:", "HEAD");
+ int dosub=k_hashtable_is( sub, "Method:", "SUB");
+ int unsub=k_hashtable_is( sub, "Method:", "UNSUB");
+ int full=!k_hashtable_isi(sub, "Cache-Control:", "no-full");
+ int updt =k_hashtable_isi(sub, "Update:", "changes");
+ char* ims =k_hashtable_get(sub, "If-Modified-Since:");
+ char* range=k_hashtable_get(sub, "Range:");
+
+ int getsub =get || dosub;
+ int getrange=getsub && range;
+
+ k_hashtable* reseh=res->ent_head;
+ int gotall= k_hashtable_is( reseh, "Status:", "200");
+ int gotrange= k_hashtable_is( reseh, "Status:", "206");
+ int gothead= k_hashtable_is( reseh, "Status:", "260");
+ int gotupdated=evt &&
+ k_hashtable_is(evt->ent_head, "Status:", "266");
+ int notfound= k_hashtable_is( reseh, "Status:", "404");
+ int constant= k_hashtable_is( reseh, "CUX:", "C" );
+ char* conrange= k_hashtable_get(reseh, "Content-Range:");
+
+ if(unsub) return 0;
+ if(notfound) return 1;
+
+ int gotany=(gothead || gotrange || gotall);
+ int snapok=(constant || !ims || entityok);
+
+ int sat=
+ (full &&
+ ((getsub && gotall && snapok) ||
+ (getrange && gotrange && range_ok(range, conrange) && snapok) ||
+ (head && gotany ) ))
+ ||
+ (updt &&
+ ((dosub && gotupdated)));
+
+ if(L) k_log_out("satisfiable %d", sat);
+ return sat;
+}
+
+void update_pubcache(int sat,
+ k_hashtable** pubcachep,
+ k_hashtable* reseh,
+ k_hashtable* sub)
+{
+ if(!sat){ if(pubcachep){
+ k_hashtable* pubcache;
+ pubcache=k_hashtable_get(reseh, "Pub-Cache:");
+ if(!pubcache || sub_less(pubcache, sub)){
+ if(!pubcache){
+ pubcache=k_hashtable_dup(sub);
+ k_hashtable_sub(reseh, "Pub-Cache:", pubcache);
+ }
+ else{
+ k_hashtable_merge(pubcache, sub);
+ }
+ k_hashtable_remove(pubcache, "URI:");
+ k_hashtable_remove(pubcache, "Sub-Type:");
+ *pubcachep=k_hashtable_dup(pubcache);
+ k_hashtable_set(*pubcachep, "Sub-Type:", "Cache");
+ }
+ }}
+ else{ if(!pubcachep){
+ k_hashtable* pubcache;
+ pubcache=k_hashtable_get(reseh, "Pub-Cache:");
+ if(!sub_less(sub, pubcache)){
+ k_hashtable_remove(pubcache, "Method:");
+ k_hashtable_remove(pubcache, "If-Modified-Since:");
+ }
+ }}
+}
+
+int sub_ok(k_hashtable* sub)
+{
+ char* gotresp =k_hashtable_get(sub, "Status:");
+ if(!gotresp) return 0;
+ int notfound=k_hashtable_is( sub, "Status:", "404");
+ if(notfound) return 0;
+ int gotall =k_hashtable_is( sub, "Status:", "200");
+ int gotrange=k_hashtable_is( sub, "Status:", "206");
+ int gothead= k_hashtable_is( sub, "Status:", "260");
+ int doget =k_hashtable_is( sub, "Method:", "GET");
+ int dohead =k_hashtable_is( sub, "Method:", "HEAD");
+ int dosub =k_hashtable_is( sub, "Method:", "SUB");
+ char* range =k_hashtable_get(sub, "Range:");
+ char* conrange=k_hashtable_get(sub, "Content-Range:");
+
+ int dogetsub=doget || dosub;
+ int dogetrange=dogetsub && range;
+ int gotany =(gothead || gotrange || gotall);
+
+ return (dogetsub && gotall ) ||
+ (dogetrange && gotrange && range_ok(range, conrange)) ||
+ (dohead && gotany );
+}
+
+int sub_less(k_hashtable* sub1, k_hashtable* sub2)
+{
+ int L=0;
+ if(L) k_log_out("sub_less sub1:");
+ if(L) k_hashtable_show_chars(sub1);
+ if(L) k_log_out("sub_less sub2:");
+ if(L) k_hashtable_show_chars(sub2);
+ char* mth1 =k_hashtable_get(sub1, "Method:");
+ int head1=k_hashtable_is( sub1, "Method:", "HEAD");
+ int get2 =k_hashtable_is( sub2, "Method:", "GET");
+ char* ims1 =k_hashtable_get(sub1, "If-Modified-Since:");
+ char* ims2 =k_hashtable_get(sub2, "If-Modified-Since:");
+ int full=!k_hashtable_isi(sub2, "Cache-Control:", "no-full");
+ return full && ((!mth1) || (head1 && get2) || (!ims1 && ims2));
+}
+
+int range_ok(char* range, char* conrange)
+{
+ k_log_out("range_ok not implemented: %s vs %s", range, conrange);
+ return 0;
+}
+
+void merge_non_entity_headers(k_hashtable* reseh, k_hashtable* evteh)
+{
+}
+
+void merge_entity_range(ni_resource* res, ni_event* evt)
+{
+ k_log_out("merge_entity_range not implemented yet");
+}
+
+/* -}{---- ------------------------------------------------------------------ */
+
+void respond(k_hashtable* sub, ni_resource* res, ni_event* evt)
+{
+ int updated=evt && k_hashtable_is(evt->ent_head, "Status:", "266");
+ ni_event* evv=updated? ni_event_dup(evt):
+ ni_res_to_evt(res);
+ int L=0;
+ if(L) ni_event_show(evv, "respond");
+
+ k_hashtable_remove(evv->ent_head, "Permit:");
+ k_hashtable_remove(evv->ent_head, "Sub-To:");
+ k_hashtable_remove(evv->ent_head, "Pub-To:");
+ k_hashtable_remove(evv->ent_head, "Pub-Cache:");
+ k_hashtable_sub( evv->ent_head, "Pub-To:", sub);
+
+ int nf;
+ nf=k_hashtable_is( evv->ent_head, "Status:", "404");
+ if(!nf) respond_ok(sub, evv);
+ else respond_nf(sub, evv);
+}
+
+void respond_ok(k_hashtable* sub, ni_event* evv)
+{
+ char* status=0;
+ char* statustext=0;
+ int datalength= -1;
+ int nocache=0;
+ k_hashtable* ent_head=evv->ent_head;
+
+ time_t modifitime=k_hashtable_get_int(ent_head, "Last-Modified-Epoch:");
+ char* modistring=k_hashtable_get( ent_head, "Last-Modified:");
+ if(!modifitime){
+ modifitime=k_time_from_rfc(modistring);
+ }
+ char* imss=k_hashtable_get(sub, "If-Modified-Since:");
+ time_t imst=k_time_from_rfc(imss);
+
+ if(modifitime== -1 || imst== -1 || modifitime > imst){
+ if(k_hashtable_is(sub, "Method:", "HEAD")){
+ evv->entity=0;
+ }
+ if(!k_hashtable_is(ent_head, "CUX:", "C")){
+ evv->entity=entity_to_octets(ent_head, evv->entity);
+ nocache=1;
+ }
+ }
+ else{
+ status="304";
+ statustext="Not Modified";
+ modifitime= -1;
+ nocache= -1;
+ evv->entity=0;
+ drop_entity_headers(ent_head);
+ }
+
+ fill_headers(ent_head, status, statustext, 0,
+ modistring? -1: modifitime,
+ datalength, 0, 0, nocache);
+
+ char* pub =k_hashtable_get(sub, "URI:");
+ int L=0;
+ if(L) ni_event_show(evv, "respond_ok");
+ post_to_driver(pub, evv);
+}
+
+void respond_nf(k_hashtable* sub, ni_event* evv)
+{
+ fill_headers(evv->ent_head, "404", "File Not Found", 0, -1, 0, 0, 0, 1);
+ char* pub =k_hashtable_get(sub, "URI:");
+ post_to_driver(pub, evv);
+}
+
+void post_to_driver(char* pub, ni_event* evq)
+{
+ char* driver=handled_by(pub);
+ if(0) k_log_out("Passing %s on to %s", pub, driver);
+ if(0) ni_event_show(evq, "Post to Driver:");
+ k_event_post(driver, evq);
+}
+
+void* entity_to_octets(k_hashtable* ent_head, void* entity)
+{
+ if(!entity) return 0;
+ size_t size=k_hashtable_get_int(ent_head, "Content-Length:");
+ return k_memdup(entity, size);
+}
+
+/* -}{---- ------------------------------------------------------------------ */
+
+EXPORT char* ni_hostname()
+{
+ return hostname? hostname: "not set";
+}
+
+EXPORT void ni_hostname_set(char* name)
+{
+ k_free(hostname);
+ hostname=k_strdup(name);
+}
+
+/* -}{---- ------------------------------------------------------------------ */
+
+static ni_driver* opdriver;
+static ni_driver* moddriver;
+
+char* handled_by(char* pub)
+{
+ if(moddriver->handles_resource(pub)) return moddriver->name;
+ return "op";
+}
+
+void call_sync_resource(ni_resource* res)
+{
+ if(moddriver->handles_resource(res->uri)) moddriver->sync_resource(res);
+ else opdriver->sync_resource(res);
+}
+
+ni_driver* ni_driver_new(char* name,
+ ni_handles_resource handles_resource,
+ ni_sync_resource sync_resource)
+{
+ ni_driver* driver=k_malloc(sizeof(ni_driver));
+ driver->name =name;
+ driver->handles_resource=handles_resource;
+ driver->sync_resource =sync_resource;
+ return driver;
+}
+
+EXPORT void ni_register_driver(char* name,
+ ni_handles_resource handles_resource,
+ ni_sync_resource sync_resource)
+{
+ ni_driver* d=ni_driver_new(name, handles_resource, sync_resource);
+ if(!strcmp(name, "op")) opdriver=d;
+ else moddriver=d;
+}
+
+/* -}{---- ------------------------------------------------------------------ */
+
+EXPORT ni_resource* ni_resource_new(char* uri,
+ k_hashtable* ent_head,
+ char* entity)
+{
+ char* urih=k_hashtable_get(ent_head, "URI:");
+ if(urih) uri=urih;
+ else
+ if(uri) k_hashtable_put_dup(ent_head, "URI:", uri);
+
+ ni_resource* res=k_malloc(sizeof(ni_resource));
+ res->uri =(uri? k_strdup(uri): 0);
+ res->ent_head=ent_head;
+ res->entity =entity;
+ return res;
+}
+
+EXPORT ni_resource* ni_resource_dup(ni_resource* res)
+{
+ ni_resource* rep=k_malloc(sizeof(ni_resource));
+ rep->uri =k_strdup( res->uri);
+ rep->ent_head=k_hashtable_dup(res->ent_head);
+ rep->entity = res->entity;
+ return rep;
+}
+
+EXPORT void ni_resource_delete(ni_resource* res)
+{
+ if(!res) return;
+ if(res->entity && res->ent_head){
+ int constant=k_hashtable_is(res->ent_head, "CUX:", "C");
+ if(!constant) k_free(res->entity);
+ }
+ k_hashtable_delete(res->ent_head);
+ k_free( res->uri);
+ k_free( res);
+}
+
+static char* excto[]={ "Permit:", "Sub-To:", "Pub-To:", 0 };
+static char* perto[]={ "Permit:", 0 };
+static char* subto[]={ "Sub-To:", 0 };
+static char* pubto[]={ "Pub-To:", 0 };
+
+EXPORT void ni_resource_show(ni_resource* res, char* text)
+{
+ if(!res){
+ k_log_out("\n---%s--------\n------------\n\n----------",
+ text);
+ }
+ else{
+ char* b=tmpbuf;
+ size_t s=TMPBUFSIZE;
+ size_t l=0;
+ l+=k_hashtable_snprintf_x(res->ent_head, b+l, s-l, excto);
+ l+=k_hashtable_snprintf_i(res->ent_head, b+l, s-l, perto);
+ l+=k_hashtable_snprintf_i(res->ent_head, b+l, s-l, subto);
+ l+=k_hashtable_snprintf_i(res->ent_head, b+l, s-l, pubto);
+ k_log_out("\n---%s----%s--\n%s----------\n%p\n----------",
+ text, res->uri, tmpbuf, res->entity);
+ }
+}
+
+/* -}{---- ------------------------------------------------------------------ */
+
+EXPORT ni_resource* ni_resource_get(char* uri)
+{
+ return k_hashtable_get(resources, uri);
+}
+
+/* -}{---- ------------------------------------------------------------------ */
+
+EXPORT ni_event* ni_res_to_evt(ni_resource* res)
+{
+ ni_event* evp=k_malloc(sizeof(ni_event));
+ evp->uri =k_strdup( res->uri);
+ evp->evt_head=k_hashtable_new("vHeaders/ni_res_to_evt", 1);
+ evp->ent_head=k_hashtable_dup(res->ent_head);
+ evp->entity = res->entity;
+ return evp;
+}
+
+/* -}{---- ------------------------------------------------------------------ */
+
+EXPORT ni_event* ni_event_new(char* uri,
+ k_hashtable* evt_head,
+ k_hashtable* ent_head,
+ char* entity)
+{
+ char* urih=k_hashtable_get(ent_head, "URI:");
+ if(urih) uri=urih;
+ else
+ if(uri) k_hashtable_put_dup(ent_head, "URI:", uri);
+
+ ni_event* evt=k_malloc(sizeof(ni_event));
+ evt->uri =(uri? k_strdup(uri): 0);
+ evt->evt_head=evt_head;
+ evt->ent_head=ent_head;
+ evt->entity =entity;
+ return evt;
+}
+
+EXPORT ni_event* ni_event_dup(ni_event* evt)
+{
+ ni_event* evp=k_malloc(sizeof(ni_event));
+ evp->uri =k_strdup( evt->uri);
+ evp->evt_head=k_hashtable_dup(evt->evt_head);
+ evp->ent_head=k_hashtable_dup(evt->ent_head);
+ evp->entity = evt->entity;
+ return evp;
+}
+
+EXPORT void ni_event_delete(ni_event* evt)
+{
+ if(!evt) return;
+ if(evt->entity && evt->ent_head){
+ int constant=k_hashtable_is(evt->ent_head, "CUX:", "C");
+ if(!constant) k_free(evt->entity);
+ }
+ k_hashtable_delete(evt->evt_head);
+ k_hashtable_delete(evt->ent_head);
+ k_free( evt->uri);
+ k_free( evt);
+}
+
+EXPORT void ni_event_show(ni_event* evt, char* text)
+{
+ if(!evt){
+ k_log_out("\n---%s--------\n------------\n\n----------",
+ text);
+ }
+ else{
+ char* buf=tmpbuf;
+ int siz=TMPBUFSIZE;
+ int n=k_hashtable_snprintf(evt->evt_head, buf, siz)+1;
+ ; k_hashtable_snprintf(evt->ent_head, buf+n, siz-n);
+ k_log_out("\n---%s----%s--\n"
+ "%s----------\n"
+ "%s----------\n"
+ "%p\n----------",
+ text, evt->uri, buf, buf+n, evt->entity);
+ }
+}
+
+/* -}{----------------------------------------------------------------------- */
+
+
+
+
}
else{
is_np=1;
- k_ciux="np";
+ k_ciux="op";
}
k_free(data);
}
k_log_out("========================================");
- load_module("ni", 0);
- load_module("np", 0);
+ load_module("on", 0);
+ load_module("op", 0);
if(!is_np) load_module(k_ciux, 1);
k_log_out("========================================");