--- /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, 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" CRLF, 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);
+}
+
+/* -}{----------------------------------------------------------------------- */
+