Put X11 and EGL into the kernel leaving ES 2.0 only in driver
[cilux] / src / platform / kernelapi.c
1
2 /* -------------------------------------------------------------------------- */
3
4 #define PUBLIC EXPORT
5 #include <kernelapi.h>
6 #include <kernelplat.h>
7 #include <container.h>
8
9 /* -------------------------------------------------------------------------- */
10
11 #define OTHER_THREAD
12 #define CERNDATE              "%d/%b/%Y:%H:%M:%S"
13 #define RDSIZE                40960
14 #define WRSIZE                2
15 #define TMPBUFSIZE            40960
16 #define WRITEMAX              30000
17 #define LOGBUFSIZE            1024
18 #define OOM_STRING            "Out of memory!\nBailing."
19 #define MAX_MODULES           64
20 #define MAX_EVENTS_PER_MODULE 3
21 #define CHAN_CLOSING(chan)    (chan->priv->state!=CHAN_OPEN)
22 #define CHAN_CLOSE            0
23 #define CHAN_LINGER           1
24 #define CHAN_OPEN             2
25 #define SETCB_RD              1
26 #define SETCB_WR              2
27 #define MIN(a,b)              (((a) < (b))? (a): (b))
28
29 /* -------------------------------------------------------------------------- */
30
31 typedef struct wrbuffer{
32         char*  base;
33         size_t size;
34         char*  free;
35 } wrbuffer;
36
37 struct k_channel_priv{
38
39         SOCK_T    SOCK;
40         int       state;
41         int       event;
42         int       rwmask;
43         char*     rdbuffer;
44         size_t    rdbufpos;
45         size_t    rdbufsize;
46         int       rdbufforeign;
47         wrbuffer* wrbuffers;
48         int       wrbufpos;
49         int       wrbufsize;
50         int       lingercount;
51 };
52
53 typedef struct event{ struct event* next;
54         void* data;
55 } event;
56
57 typedef struct k_module{
58         char*             name;
59         k_module_tick_fn  tick_fn;
60         k_module_event_fn event_fn;
61         event*            queue;
62 } k_module;
63
64 typedef struct key_event{ struct key_event* next;
65         unsigned char key;
66         int           down;
67 } key_event;
68
69 /* -------------------------------------------------------------------------- */
70
71 static int                running=2;
72 static k_gl_reshape_event reshape_fn=0;
73 static k_gl_draw_event    draw_fn=0;
74 static k_gl_key_event     key_fn=0;
75 static k_module           modules[MAX_MODULES];
76 static int                nextmodule=0;
77 static key_event*         key_consumer=0;
78 static key_event*         key_producer=0;
79 static k_channel*         k_channels=0;
80 static k_hashtable*       connecting_chans;
81 static k_hashtable*       current_chans;
82 static k_hashtable*       monthhash;
83 static char               tmpbuf[TMPBUFSIZE];
84 static char               logbuf[LOGBUFSIZE];
85 static FILEP              logfile=0;
86 static int                log_gmt=0;
87 static char               dummy_empty_data[0];
88
89 /* -------------------------------------------------------------------------- */
90
91 static void    gen_conn_name(k_channel* chan);
92 static void    chan_closed(k_channel* chan);
93 static SOCK_T  make_listen_socket(int listenport);
94 static SOCK_T  make_connect_socket(void);
95 static int     listen_socket(SOCK_T s, int listenport);
96 static int     connect_socket(SOCK_T s, char*, int);
97 static void    add_module_entry(char*, k_module_tick_fn, k_module_event_fn);
98 static int                run_queues(void);
99 static void               show_open_channels(void);
100 static k_channel*         find_k_channel_for_socket(SOCK_T s);
101 static k_channel*         register_k_channel(char*           name,
102                                              char*           listenhost,
103                                              int             listenport,
104                                              char*           banner,
105                                              k_channel_event rdcallback,
106                                              k_channel_event wrcallback,
107                                              void*           context,
108                                              int             type,
109                                              struct in_addr  clientip,
110                                              SOCK_T          s);
111 static event**            get_module_queue(char* name);
112 static k_module_loaded_fn get_module_loaded_fn(char* name, MODULE module);
113 static k_module_tick_fn   get_module_tick_fn(  char* name, MODULE module);
114 static k_module_event_fn  get_module_event_fn( char* name, MODULE module);
115 static int                check_i(char* key, char* includes[], int ignorecase);
116 static int                check_x(char* key, char* excludes[], int ignorecase);
117 static unsigned int       string_hash(char* p);
118 static int                set_rdbuffer(k_channel*, char* rdbuffer, size_t size);
119 static char*              get_rdbuffer(k_channel* chan);
120 static void    append_to_wrbuffers(k_channel*, char*, size_t, int);
121 static char*   chop_from_rdbuffer_div(k_channel* chan, char* div);
122 static char*   chop_from_rdbuffer_len(k_channel* chan, size_t size);
123 static void    chop_from_wrbuffers(   k_channel* chan, size_t size);
124 static void    got_key(unsigned char key, int down);
125 static void    init_keys(void);
126 static void    dir_read(char*, char*, char*, int, k_stat, void*);
127 static void    load_module(char* name, int dot);
128 static void    init_modules(void);
129 static void    log_net_err(char* where, int e);
130 static int     dir_list(char*, int, char*, char*, char*);
131 static int     ensure_dir(char* fullname);
132 static void    next_keys(void);
133 static void    read_more_and_notify(k_channel* chan);
134 static void    readable_socket(k_channel* chan);
135 static void    register_connections(k_channel* chan);
136 static void    do_regular_things(void);
137 static void    tick_modules(void);
138 static void    remove_dead_k_channels(void);
139 static void    unregister_k_channel(k_channel* chan, int now);
140 static void    write_more_and_notify(k_channel* chan);
141 static char    hex_to_int(char c);
142 static void    write_to_logfile_cern_style(char* text, int error);
143 static void    writeable_socket(k_channel* chan);
144 static void               exception_socket(k_channel* chan);
145 static SOCK_T             make_udp_listen_socket(int listenport);
146 static struct sockaddr_in make_sockaddr_in(unsigned long address,
147                                            unsigned int port);
148 static void               init_hashtables(void);
149
150 /* -------------------------------------------------------------------------- */
151
152 #include <kernelplat.c>
153
154 /* -------------------------------------------------------------------------- */
155
156 EXPORT void c_init(char*   version,
157                    char*   ciux,
158                    void  (*terminate)(void))
159 {
160         k_version  =version;
161         k_ciux     =ciux;
162         k_terminate=terminate;
163
164         init_hashtables();
165         init_keys();
166
167         if(LOAD_MODULES_EARLY){
168                 init_gl();
169                 init_net();
170                 init_modules();
171         }
172 }
173
174 EXPORT C_RUN_RV c_run(C_RUN_ARG arg)
175 {
176         init_thread();
177
178         if(!LOAD_MODULES_EARLY){
179                 init_gl();
180                 init_net();
181                 init_modules();
182         }
183
184         if(reshape_fn)(*reshape_fn)(640,480);
185         if(draw_fn)   (*draw_fn)();
186
187         k_log_out("Cilux U-Web Exchange started");
188         k_log_out("%s", k_version);
189         k_log_out("---------------------------------------------");
190
191         int queue_events_to_do=0;
192         while(1){
193                 if(running==2) poller(queue_events_to_do);
194                 if(running==1) SLEEP_MS(LOOP_TICK);
195                 if(running==0) break;
196
197                 if(running==2) queue_events_to_do=run_queues();
198                 if(running==1) ;
199                 if(running==0) break;
200         }
201
202         k_log_out("Cilux U-Web Exchange terminated");
203
204         return 0;
205 }
206
207 EXPORT OTHER_THREAD void c_running(int r)
208 {
209         running=r;
210 }
211
212 EXPORT OTHER_THREAD void c_key(unsigned char key, int down)
213 {
214         got_key(key, down);
215 }
216
217 EXPORT OTHER_THREAD void c_signal(int signum)
218 {
219         k_log_out("Received signal %d", signum);
220 }
221
222 /* -------------------------------------------------------------------------- */
223
224 EXPORT void k_gl_register_reshape(k_gl_reshape_event callback){
225         reshape_fn=callback;
226 }
227
228 EXPORT void k_gl_register_draw(k_gl_draw_event callback){
229         draw_fn=callback;
230 }
231
232 EXPORT void k_gl_register_key(k_gl_key_event callback){
233         key_fn=callback;
234 }
235
236 /* -------------------------------------------------------------------------- */
237
238 void init_hashtables(void)
239 {
240         connecting_chans=k_hashtable_new("Connecting Channels", 0);
241         current_chans   =k_hashtable_new("Current Channels", 0);
242         monthhash       =k_hashtable_new("Months", 1);
243         k_hashtable_set(monthhash, "Jan", (void*)1);
244         k_hashtable_set(monthhash, "Feb", (void*)2);
245         k_hashtable_set(monthhash, "Mar", (void*)3);
246         k_hashtable_set(monthhash, "Apr", (void*)4);
247         k_hashtable_set(monthhash, "May", (void*)5);
248         k_hashtable_set(monthhash, "Jun", (void*)6);
249         k_hashtable_set(monthhash, "Jul", (void*)7);
250         k_hashtable_set(monthhash, "Aug", (void*)8);
251         k_hashtable_set(monthhash, "Sep", (void*)9);
252         k_hashtable_set(monthhash, "Oct", (void*)10);
253         k_hashtable_set(monthhash, "Nov", (void*)11);
254         k_hashtable_set(monthhash, "Dec", (void*)12);
255 }
256
257 void init_logging(void)
258 {
259         snprintf(tmpbuf, TMPBUFSIZE, "%s.log", k_ciux);
260         logfile=FOPEN(tmpbuf, "a");
261         if(!logfile) k_log_err("couldn't open logfile %s", tmpbuf);
262 }
263
264 void init_modules(void)
265 {
266         char* patts[]={ "{*.dll,*.so}", 0};
267         char* temps[]={ "%s:", 0 };
268         k_dir_list(".", ".", patts, temps, dir_read, 0);
269 }
270
271 void dir_read(char*  basedir,
272               char*  path,
273               char*  data,
274               int    usedmmap,
275               k_stat kstat,
276               void*  context)
277 {
278         int is_np=0;
279         if(data){
280                 if(!strncmp(data, MODPRE, strlen(MODPRE))){
281                         k_ciux=k_strdup(data+strlen(MODPRE));
282                         char* c=strchr(k_ciux, '.');
283                         *c=0;
284                 }
285                 else{
286                         is_np=1;
287                         k_ciux="np";
288                 }
289                 k_free(data);
290         }
291
292         init_logging();
293
294         k_log_out("========================================");
295
296         load_module("ni", 0);
297         load_module("np", 0);
298         if(!is_np) load_module(k_ciux, 1);
299
300         k_log_out("========================================");
301 }
302
303 void load_module(char* name, int dot)
304 {
305         k_log_out("------------ %s --------------", name);
306         char dlname[64];
307         snprintf(dlname, 64, "%s%s%s%s", dot? "./": "", MODPRE, name, MODPOST);
308         MODULE module=DLOPEN(dlname);
309         if(module){
310                 k_module_loaded_fn loaded_fn=get_module_loaded_fn(name, module);
311                 k_module_tick_fn   tick_fn  =get_module_tick_fn(  name, module);
312                 k_module_event_fn  event_fn =get_module_event_fn( name, module);
313                 if(loaded_fn && event_fn){
314                         add_module_entry(name, tick_fn, event_fn);
315                         (*loaded_fn)();
316                 }
317                 else k_log_err("Couldn't load module %s (hooks)", dlname);
318         }
319         else k_log_err("Couldn't load module %s (dlopen) %s", dlname, DLERROR);
320 }
321
322 k_module_loaded_fn get_module_loaded_fn(char* name, MODULE module)
323 {
324         snprintf(tmpbuf, TMPBUFSIZE, "%s%s", name, NAME_OF_MODULE_LOADED_FN);
325         k_module_loaded_fn f=(k_module_loaded_fn)DLSYM(module, tmpbuf);
326         if(!f) k_log_err("no %s", tmpbuf);
327         return f;
328 }
329
330 k_module_tick_fn get_module_tick_fn(char* name, MODULE module)
331 {
332         snprintf(tmpbuf, TMPBUFSIZE, "%s%s", name, NAME_OF_MODULE_TICK_FN);
333         k_module_tick_fn f=(k_module_tick_fn)DLSYM(module, tmpbuf);
334         if(!f) k_log_err("no %s", tmpbuf);
335         return f;
336 }
337
338 k_module_event_fn get_module_event_fn(char* name, MODULE module)
339 {
340         snprintf(tmpbuf, TMPBUFSIZE, "%s%s", name, NAME_OF_MODULE_EVENT_FN);
341         k_module_event_fn f=(k_module_event_fn)DLSYM(module, tmpbuf);
342         if(!f) k_log_err("no %s", tmpbuf);
343         return f;
344 }
345
346 /* -------------------------------------------------------------------------- */
347
348 void add_module_entry(char*             name,
349                       k_module_tick_fn  tick_fn,
350                       k_module_event_fn event_fn)
351 {
352         if(nextmodule==MAX_MODULES){
353                 k_fatal("Too many modules! Maximum %d", MAX_MODULES);
354         }
355         modules[nextmodule  ].name    =name;
356         modules[nextmodule  ].tick_fn =tick_fn;
357         modules[nextmodule  ].event_fn=event_fn;
358         modules[nextmodule++].queue   =0;
359 }
360
361 event* event_new(void* data)
362 {
363         event* ev;
364         ev=k_malloc(sizeof(event));
365         ev->next=0;
366         ev->data=data;
367         return ev;
368 }
369
370 EXPORT int k_event_post(char* module, void* data)
371 {
372         event* ev=event_new(data);
373         event** queue=get_module_queue(module);
374         if(!queue){
375                 k_log_err("k_event_post(%s): no such module", module);
376                 return 0;
377         }
378         if(!*queue) *queue=ev;
379         else{
380                 event* p=*queue;
381                 do{
382                         if(!p->next){
383                                 p->next=ev;
384                                 break;
385                         }
386                         p=p->next;
387                 } while(1);
388         }
389         return 1;
390 }
391
392 event** get_module_queue(char* name)
393 {
394         int i;
395         for(i=0; i< nextmodule; i++){
396                 if(!strcmp(modules[i].name, name)) return &modules[i].queue;
397         }
398         return 0;
399 }
400
401 int run_queues(void)
402 {
403         int i,j;
404         for(i=0; i< nextmodule; i++){
405                 for(j=0; modules[i].queue && j < MAX_EVENTS_PER_MODULE; j++){
406                         event* event=modules[i].queue;
407                         modules[i].queue=event->next;
408                         event->next=0;
409                         (*modules[i].event_fn)(event->data);
410                         k_free(event);
411                 }
412         }
413         for(i=0; i< nextmodule; i++){
414                 if(modules[i].queue) return 1;
415         }
416         return 0;
417 }
418
419 /* -------------------------------------------------------------------------- */
420
421 void init_keys(void)
422 {
423         key_event* ke;
424         ke=k_malloc(sizeof(key_event));
425         ke->key=0;
426         ke->down=0;
427         ke->next=0;
428         key_consumer=ke;
429         key_producer=ke;
430 }
431
432 OTHER_THREAD void got_key(unsigned char key, int down)
433 {
434         if(!key_producer) return;
435         key_event* ke;
436         ke=k_malloc(sizeof(key_event));
437         ke->key=key;
438         ke->down=down;
439         ke->next=0;
440         key_producer->next=ke;
441         key_producer=ke;
442 }
443
444 void next_keys(void)
445 {
446         while(key_consumer!=key_producer){
447                 key_event* ke=key_consumer->next;
448                 if(key_fn)  (*key_fn)(ke->key, ke->down);
449                 k_free(key_consumer);
450                 key_consumer=ke;
451         }
452 }
453
454 /* -}{----------------------------------------------------------------------- */
455
456 EXPORT char* k_channel_name(char* type, char* ip, int port, char* other)
457 {
458         int ln=0;
459         int bufsize=TMPBUFSIZE;
460
461         if(type)  ln+=snprintf(tmpbuf+ln, bufsize-ln, "|%s|", type);
462         else      ln+=snprintf(tmpbuf+ln, bufsize-ln,  "|-|");
463         if(ln>=bufsize) return 0;
464         
465         if(ip)    ln+=snprintf(tmpbuf+ln, bufsize-ln, "%s|", ip);
466         else      ln+=snprintf(tmpbuf+ln, bufsize-ln,  "-|");
467         if(ln>=bufsize) return 0;
468
469         if(port)  ln+=snprintf(tmpbuf+ln, bufsize-ln, "%d|", port);
470         else      ln+=snprintf(tmpbuf+ln, bufsize-ln,  "-|");
471         if(ln>=bufsize) return 0;
472
473         if(other) ln+=snprintf(tmpbuf+ln, bufsize-ln, "%s|", other);
474         else      ln+=snprintf(tmpbuf+ln, bufsize-ln,  "-|");
475         if(ln>=bufsize) return 0;
476
477         return k_strdup(tmpbuf);
478 }
479
480 EXPORT k_channel* k_channel_connect_name(char*           chanm,
481                                          k_channel_event rdcallback,
482                                          k_channel_event wrcallback)
483 {
484         if(k_hashtable_get(connecting_chans, chanm)){
485                 if(1) k_log_out("Already connecting to %s", chanm);
486                 return 0;
487         }
488         k_hashtable_set(connecting_chans, chanm, chanm);
489
490         k_channel* chan=0;
491         char* t=k_strdup(chanm);
492         char* a=strchr(t+1, '|'); *a++=0;
493         char* p=strchr(a,   '|'); *p++=0;
494         char* o=strchr(p,   '|'); *o++=0;
495         int   pi=atoi(p);
496
497         if(strstr(t, "-client")){
498                 chan=k_channel_connect(t, a, pi, rdcallback, wrcallback, 0);
499                 if(!chan) k_log_err("couldn't connect to %s:%d", a, pi);
500         }
501         else
502         if(strstr(t, "-server") && *a=='-'){
503                 chan=k_channel_listen(t, pi, 0, rdcallback, wrcallback, 0);
504                 if(!chan) k_log_err("couldn't listen on port %d", pi);
505         }
506         else
507         if(strstr(t, "-server")){
508                 chan=k_channel_connect(t, a, pi, rdcallback, wrcallback, 0);
509                 if(!chan) k_log_err("couldn't connect to %s:%d", a, pi);
510         }
511
512         *--a= '|';
513         *--p= '|';
514         *--o= '|';
515
516         if(!chan) k_free(t);
517
518         return chan;
519 }
520
521 EXPORT k_channel* k_channel_get_name(char* chanm)
522 {
523         k_channel* chan=k_hashtable_get(current_chans, chanm);
524         return chan;
525 }
526
527 EXPORT void k_channel_show_all()
528 {
529         k_log_out("----------------------------------------");
530         k_hashtable_show(connecting_chans);
531         k_log_out("----------------------------------------");
532         k_hashtable_show(current_chans);
533         k_log_out("----------------------------------------");
534 }
535
536 void gen_conn_name(k_channel* chan)
537 {
538         char* t=chan->name+1;
539         char* a=strchr(t, '|'); *a++=0;
540         char* p=strchr(a, '|'); *p++=0;
541         char* o=strchr(p, '|'); *o++=0;
542         char* ip=inet_ntoa(chan->clientip);
543         int   pi=atoi(p);
544
545         char b[32];
546         static long uniquenum;
547         snprintf(b, 32, "%ld", ++uniquenum);
548         chan->name=k_channel_name(t, ip, pi, b);
549
550         *--a= '|';
551         *--p= '|';
552         *--o= '|';
553 }
554
555 /* -------------------------------------------------------------------------- */
556
557 EXPORT k_channel* k_channel_listen(char*           name,
558                                    int             listenport,
559                                    char*           banner,
560                                    k_channel_event rdcallback,
561                                    k_channel_event wrcallback,
562                                    void*           context)
563 {
564         SOCK_T s=make_listen_socket(listenport);
565         if(!s) return 0;
566
567         struct in_addr noclientip=EMPTY_IN_ADDR;
568         k_channel* chan=register_k_channel(name, 
569                                            0, 
570                                            listenport, 
571                                            banner, 
572                                            rdcallback, 
573                                            wrcallback, 
574                                            context,
575                                            CHAN_LISTEN, 
576                                            noclientip, 
577                                            s);
578         int r=listen_socket(s, listenport);
579         if(r== -1){
580                 unregister_k_channel(chan,1);
581                 return 0;
582         }
583         return chan;
584 }
585
586 EXPORT k_channel* k_channel_connect(char*           name,
587                                     char*           listenhost,
588                                     int             listenport,
589                                     k_channel_event rdcallback,
590                                     k_channel_event wrcallback,
591                                     void*           context)
592 {
593         SOCK_T s=make_connect_socket();
594         if(!s) return 0;
595
596         struct in_addr noclientip=EMPTY_IN_ADDR;
597         k_channel* chan=register_k_channel(name,
598                                            listenhost,
599                                            listenport, 
600                                            0, 
601                                            rdcallback, 
602                                            wrcallback, 
603                                            context,
604                                            CHAN_ESTABL, 
605                                            noclientip, 
606                                            s);
607         int r=connect_socket(s, listenhost, listenport);
608         if(r== -1){
609                 unregister_k_channel(chan,1);
610                 return 0;
611         }
612         return chan;
613 }
614
615 EXPORT k_channel* k_channel_send(k_channel* chan,
616                                  char*      base,
617                                  size_t     size,
618                                  int        free)
619 {
620         append_to_wrbuffers(chan, base, size, free);
621         set_callback(chan, SETCB_WR);
622         return chan;
623 }
624
625 EXPORT char* k_channel_chop_div(k_channel* chan, char* divider)
626 {
627         return chop_from_rdbuffer_div(chan, divider);
628 }
629
630 EXPORT char* k_channel_chop_len(k_channel* chan, size_t size)
631 {
632         return chop_from_rdbuffer_len(chan, size);
633 }
634
635 EXPORT int k_channel_setbuf(k_channel* chan, char* rdbuffer, size_t size)
636 {
637         return set_rdbuffer(chan, rdbuffer, size);
638 }
639
640 EXPORT char* k_channel_getbuf(k_channel* chan)
641 {
642         return get_rdbuffer(chan);
643 }
644
645 EXPORT void k_channel_close(k_channel* chan)
646 {
647         unregister_k_channel(chan,0);
648 }
649
650 k_channel* register_k_channel(char*           name,
651                               char*           listenhost,
652                               int             listenport,
653                               char*           banner,
654                               k_channel_event rdcallback,
655                               k_channel_event wrcallback,
656                               void*           context,
657                               int             type,
658                               struct in_addr  clientip,
659                               SOCK_T          s)
660 {
661         k_channel* chan;
662         chan=k_malloc(sizeof(k_channel));
663
664         chan->name=name;
665         chan->listenhost=listenhost;
666         chan->listenport=listenport;
667         chan->banner=banner;
668         chan->rdcallback=rdcallback;
669         chan->wrcallback=wrcallback;
670         chan->context=context;
671         chan->type=type;
672         chan->clientip=clientip;
673         chan->linger=0;
674
675         chan->priv=k_malloc(sizeof(k_channel_priv));
676         chan->priv->SOCK=s;
677         chan->priv->state=CHAN_OPEN;
678         chan->priv->event=0;                            /* what is this for? */
679         chan->priv->rwmask=0;                           /* what is this for? */
680         chan->priv->rdbuffer=(char*)k_malloc(RDSIZE);   /* 40K per connection??!! */
681         chan->priv->rdbufpos=0;
682         chan->priv->rdbufsize=RDSIZE;
683         chan->priv->rdbufforeign=0;
684         chan->priv->wrbuffers=(wrbuffer*)k_malloc(WRSIZE*sizeof(wrbuffer));
685         chan->priv->wrbufpos=0;
686         chan->priv->wrbufsize=WRSIZE;
687         chan->priv->lingercount=LINGER_LOOPS;
688
689         if(1){
690                 set_callback(chan, SETCB_RD);
691         }
692         if(chan->listenhost){
693                 set_callback(chan, SETCB_WR);
694         }
695
696         chan->next=k_channels;
697         k_channels=chan;
698
699         return chan;
700 }
701
702 void unregister_k_channel(k_channel* chan, int now)
703 {
704         int closing=CHAN_CLOSING(chan);
705         if(closing && !now) return;
706         int linger=chan->linger && !now;
707         chan->priv->state=linger? CHAN_LINGER: CHAN_CLOSE;
708         if(linger) un_set_callback(chan, SETCB_WR);
709         else       un_set_callback(chan, SETCB_WR | SETCB_RD);
710         if(closing) return;
711         chan_closed(chan);
712         if(chan->rdcallback)(*chan->rdcallback)(chan, chan->priv->rdbufpos, -1);
713         else
714         if(chan->wrcallback)(*chan->wrcallback)(chan, chan->priv->wrbufpos, -1);
715 }
716
717 void chan_closed(k_channel* chan)
718 {
719         if(0) k_log_out("chan_closed %s", chan->name);
720         k_hashtable_remove(connecting_chans, chan->name);
721         k_hashtable_remove(current_chans,    chan->name);
722         if(0) k_channel_show_all();
723 }
724
725 void do_regular_things(void)
726 {
727         tick_modules();
728         remove_dead_k_channels();
729 }
730
731 void tick_modules(void)
732 {
733         int i;
734         for(i=0; i< nextmodule; i++){
735                 k_module_tick_fn tf=modules[i].tick_fn;
736                 if(tf) (*tf)();
737         }
738 }
739
740 void remove_dead_k_channels(void)
741 {
742         int i;
743         k_channel* cn;
744         k_channel* cp=0;
745         k_channel* cc=k_channels;
746         while(cc){
747                 cn=cc->next;
748                 if( cc->priv->state==CHAN_CLOSE ||
749                    (cc->priv->state==CHAN_LINGER && !cc->priv->lingercount--)){
750                         un_set_callback(cc, SETCB_WR | SETCB_RD);
751                         if(!cp) k_channels=cn;
752                         else    cp->next  =cn;
753                         SOCKET_CLOSE(cc->priv->SOCK);
754                         for(i=0; i< cc->priv->wrbufpos; i++){
755                                 k_free(cc->priv->wrbuffers[i].free);
756                         }
757                         k_free(cc->priv->wrbuffers);
758                         k_free(cc->priv->rdbuffer);
759                         k_free(cc->priv);
760                         k_free(cc->name);
761                         k_free(cc);
762                 }
763                 else cp=cc;
764                 cc=cn;
765         }
766 }
767
768 k_channel* find_k_channel_for_socket(SOCK_T s)
769 {
770         k_channel* chan;
771         for(chan=k_channels; chan; chan=chan->next){
772                 if(chan->priv->SOCK==s) break;
773         }
774         return chan;
775 }
776
777 void show_open_channels(void)
778 {
779         k_channel* chan=k_channels;
780         while(chan){
781                 if(chan->priv->state==CHAN_OPEN  ){
782                         if(0) k_log_out("chan open      %x", chan->priv->SOCK);
783                 }
784                 if(chan->priv->state==CHAN_LINGER){
785                         if(0) k_log_out("chan lingering %x", chan->priv->SOCK);
786                 }
787                 if(chan->priv->state==CHAN_CLOSE ){
788                         if(0) k_log_out("chan closed    %x", chan->priv->SOCK);
789                 }
790                 chan=chan->next;
791         }
792 }
793
794 void readable_socket(k_channel* chan)
795 {
796         if(chan->type==CHAN_LISTEN){
797                 register_connections(chan);
798         }
799         else{
800                 read_more_and_notify(chan);
801         }
802 }
803
804 void writeable_socket(k_channel* chan)
805 {
806         write_more_and_notify(chan);
807 }
808
809 void exception_socket(k_channel* chan)
810 {
811         if(0) k_log_out("exception_socket");
812         unregister_k_channel(chan,1);
813 }
814
815 void register_connections(k_channel* chan)
816 {
817         SOCK_T             as=chan->priv->SOCK;
818         struct sockaddr_in iaddr;
819         struct sockaddr*   iaddrp=(struct sockaddr*)&iaddr;
820         socklen_t          size=sizeof(struct sockaddr_in);
821         while(1){
822                 SOCK_T s;
823                 int r=ACCEPT(as, iaddrp, &size, s);
824                 GETERRNO(r);
825                 if(r== -1){
826                         if(ERRNO==INTERRUPTED) break;
827                         if(ISNOTACTIVE(ERRNO)) break;
828                         log_net_err("accept", ERRNO);
829                         break;
830                 }
831                 SET_NON_BLOCKING(s);
832                 SET_NO_DELAY(s);
833
834                 if(chan->banner){
835                         SOCKET_WRITE(s, chan->banner, strlen(chan->banner));
836                 }
837
838                 k_channel* chann=register_k_channel(chan->name,
839                                                     0,
840                                                     chan->listenport,
841                                                     chan->banner,
842                                                     chan->rdcallback,
843                                                     chan->wrcallback,
844                                                     chan->context,
845                                                     CHAN_ESTABL,
846                                                     iaddr.sin_addr,
847                                                     s);
848                 gen_conn_name(chann);
849                 k_hashtable_set(current_chans, chann->name, chann);
850                 if(chann->rdcallback) (*chann->rdcallback)(chann, 0, 0);
851         }
852 }
853
854 void read_more_and_notify(k_channel* chan)
855 {
856         int pos=chan->priv->rdbufpos;
857         int size=SOCKET_READ(chan->priv->SOCK,
858                              chan->priv->rdbuffer +pos,
859                              chan->priv->rdbufsize-pos);
860         GETERRNO(size);
861         if(size==0){ size= -1; ERRNO=EPIPE; }
862         if(size== -1){
863                 if(ERRNO==INTERRUPTED) return;
864                 if(ISNOTACTIVE(ERRNO)) return;
865                 log_net_err("socket_read", ERRNO);
866                 unregister_k_channel(chan,1);
867                 return;
868         }
869         if(CHAN_CLOSING(chan)) return;
870
871         chan->priv->rdbufpos+=size;
872
873         if(chan->rdcallback){
874                 (*chan->rdcallback)(chan, chan->priv->rdbufpos, size);
875         }
876
877         if(chan->priv->rdbufpos==chan->priv->rdbufsize){
878                 if(chan->priv->rdbufforeign){
879                         k_log_err("Run out of room in given buffer");
880                         k_log_err("rdbufsize=%d", chan->priv->rdbufsize);
881                         unregister_k_channel(chan,1);
882                         return;
883                 }
884                 chan->priv->rdbufsize*=2;
885                 chan->priv->rdbuffer=k_realloc(chan->priv->rdbuffer,
886                                                chan->priv->rdbufsize);
887                 if(0) k_log_out("rdbufsize=%d", chan->priv->rdbufsize);
888                 // DoS vulnerability unless buffer size limited
889         }
890 }
891
892 void write_more_and_notify(k_channel* chan)
893 {
894         if(!chan->priv->wrbufpos){
895                 if(chan->name){
896                         k_hashtable_remove(connecting_chans, chan->name);
897                         k_hashtable_set(   current_chans,    chan->name, chan);
898                 }
899                 if(chan->wrcallback) (*chan->wrcallback)(chan, 0, 0);
900                 if(!chan->priv->wrbufpos) un_set_callback(chan, SETCB_WR); // Eerrk?
901                 return;
902         }
903
904         int writemax=MIN(WRITEMAX, chan->priv->wrbuffers[0].size);
905         int size=SOCKET_WRITE(chan->priv->SOCK,
906                               chan->priv->wrbuffers[0].base,
907                               writemax);
908         GETERRNO(size);
909         if(size==0){ size= -1; ERRNO=NOTACTIVE; }
910         if(size== -1){
911                 if(ERRNO==INTERRUPTED) return;
912                 if(ISNOTACTIVE(ERRNO)) return;
913                 log_net_err("socket_write", ERRNO);
914                 unregister_k_channel(chan,1);
915                 return;
916         }
917
918         chop_from_wrbuffers(chan, size);
919
920         if(chan->wrcallback){
921                 (*chan->wrcallback)(chan, chan->priv->wrbufpos, size);
922         }
923
924         if(!chan->priv->wrbufpos) un_set_callback(chan, SETCB_WR);
925 }
926
927 char* strnstr(char* haystack, size_t size, char* needle) // Errk!
928 {
929         if(!needle || !*needle) return haystack;
930         char* h;
931         char* e=haystack+size;
932         for(h=haystack; h < e && *h; h++){
933                 char* i=h;
934                 char* n=needle;
935                 while(i < e && *i && *n && *i==*n){ i++; n++; }
936                 if(!*n) return h;
937         }
938         return 0;
939 }
940
941 char* chop_from_rdbuffer_div(k_channel* chan, char* divider)
942 {
943         char* s=strnstr(chan->priv->rdbuffer, chan->priv->rdbufpos, divider);
944         if(!s) return 0;
945         *s=0;
946         size_t size=(s+1 - chan->priv->rdbuffer);
947         s+=strlen(divider);
948         char* chunk=k_memdup(chan->priv->rdbuffer, size);
949         char* e=chan->priv->rdbuffer+chan->priv->rdbufpos;
950         memmove(chan->priv->rdbuffer, s, e-s);
951         chan->priv->rdbufpos=e-s;
952         return chunk;
953 }
954
955 char* chop_from_rdbuffer_len(k_channel* chan, size_t size)
956 {
957         if(!size || size > chan->priv->rdbufpos) return 0;
958         char* chunk=k_memdup(chan->priv->rdbuffer, size);
959         char* s=chan->priv->rdbuffer+size;
960         char* e=chan->priv->rdbuffer+chan->priv->rdbufpos;
961         memmove(chan->priv->rdbuffer, s, e-s);
962         chan->priv->rdbufpos=e-s;
963         return chunk;
964 }
965
966 int set_rdbuffer(k_channel* chan, char* rdbuffer, size_t size)
967 {
968         if(chan->priv->rdbufforeign) return BUFFER_ALREADY_SET;
969         size_t pos=chan->priv->rdbufpos;
970         if(pos>=size){
971                 memcpy(rdbuffer, chan->priv->rdbuffer, size);
972                 char* s=chan->priv->rdbuffer+size;
973                 char* e=chan->priv->rdbuffer+pos;
974                 memmove(chan->priv->rdbuffer, s, e-s);
975                 chan->priv->rdbufpos=e-s;
976                 return BUFFER_FILLED;
977         }
978         memcpy(rdbuffer, chan->priv->rdbuffer, pos);
979         k_free(chan->priv->rdbuffer);
980         chan->priv->rdbuffer=rdbuffer;
981         chan->priv->rdbufsize=size;
982         chan->priv->rdbufforeign=1;
983         return BUFFER_SET;
984 }
985
986 char* get_rdbuffer(k_channel* chan)
987 {
988         if(!chan->priv->rdbufforeign) return 0;
989         char* rdbuffer=chan->priv->rdbuffer;
990         chan->priv->rdbuffer=(char*)k_malloc(RDSIZE);
991         chan->priv->rdbufpos=0;
992         chan->priv->rdbufsize=RDSIZE;
993         chan->priv->rdbufforeign=0;
994         return rdbuffer;
995 }
996
997 void append_to_wrbuffers(k_channel* chan, char* base, size_t size, int free)
998 {
999         if(chan->priv->wrbufpos==chan->priv->wrbufsize){
1000                 chan->priv->wrbufsize*=2;
1001                 chan->priv->wrbuffers=k_realloc(chan->priv->wrbuffers, 
1002                                                 chan->priv->wrbufsize *
1003                                                           sizeof(wrbuffer));
1004                 if(0) k_log_out("wrbufsize=%d", chan->priv->wrbufsize);
1005         }
1006         chan->priv->wrbuffers[chan->priv->wrbufpos].base=base;
1007         chan->priv->wrbuffers[chan->priv->wrbufpos].size=size;
1008         chan->priv->wrbuffers[chan->priv->wrbufpos].free=free? base: 0;
1009         chan->priv->wrbufpos++;
1010 }
1011
1012 void chop_from_wrbuffers(k_channel* chan, size_t size)
1013 {
1014         if(chan->priv->wrbuffers[0].size != size){
1015                 chan->priv->wrbuffers[0].base+=size;
1016                 chan->priv->wrbuffers[0].size-=size;
1017         }
1018         else{
1019                 k_free(chan->priv->wrbuffers[0].free);
1020                 chan->priv->wrbufpos--;
1021                 int i;
1022                 for(i=0; i< chan->priv->wrbufpos; i++){
1023                         chan->priv->wrbuffers[i]=chan->priv->wrbuffers[i+1];
1024                 }
1025         }
1026 }
1027
1028 /* -------------------------------------------------------------------------- */
1029
1030 SOCK_T make_listen_socket(int listenport)
1031 {
1032         SOCK_T s;
1033         int r=SOCKET(AF_INET, SOCK_STREAM, IPPROTO_TCP, s);
1034         GETERRNO(r);
1035         if(r== -1){
1036                 log_net_err("socket", ERRNO);
1037                 return 0;
1038         }
1039         SET_NON_BLOCKING(s);
1040         SET_REUSEADDR(s);
1041
1042         struct sockaddr_in iaddr;
1043         struct sockaddr*   iaddrp=(struct sockaddr*)&iaddr;
1044         iaddr=make_sockaddr_in(INADDR_ANY, listenport);
1045
1046         r=BIND(s, iaddrp, sizeof(iaddr));
1047         GETERRNO(r);
1048         if(r== -1){
1049                 log_net_err("bind", ERRNO);
1050                 SOCKET_CLOSE(s);
1051                 return 0;
1052         }
1053
1054         return s;
1055 }
1056
1057 SOCK_T make_connect_socket(void)
1058 {
1059         SOCK_T s;
1060         int r=SOCKET(AF_INET, SOCK_STREAM, IPPROTO_TCP, s);
1061         GETERRNO(r);
1062         if(r== -1){
1063                 log_net_err("socket", ERRNO);
1064                 return 0;
1065         }
1066         SET_NON_BLOCKING(s);
1067         SET_NO_DELAY(s);
1068         return s;
1069 }
1070
1071 int listen_socket(SOCK_T s, int listenport)
1072 {
1073         if(0) k_log_out("Listening on port %d", listenport);
1074         int r=LISTEN(s, 128);
1075         GETERRNO(r);
1076         if(r== -1){
1077                 log_net_err("listen", ERRNO);
1078                 SOCKET_CLOSE(s);
1079                 return -1;
1080         }
1081         return 0;
1082 }
1083
1084 int connect_socket(SOCK_T s, char* listenhost, int listenport)
1085 {
1086         if(0) k_log_out("Hanging on gethostbyname for %s", listenhost);
1087         struct hostent* hostaddr=gethostbyname(listenhost);
1088         if(!hostaddr){
1089                 SOCKET_CLOSE(s);
1090                 return -1;
1091         }
1092
1093         struct sockaddr_in iaddr;
1094         struct sockaddr*   iaddrp=(struct sockaddr*)&iaddr;
1095         iaddr=make_sockaddr_in(0, listenport);
1096         memcpy(&iaddr.sin_addr, hostaddr->h_addr, hostaddr->h_length);
1097
1098         if(0) k_log_out("Connect: %s(%s):%d ",
1099                             listenhost, inet_ntoa(iaddr.sin_addr), listenport);
1100         do{
1101                 int r=CONNECT(s, iaddrp, sizeof(iaddr));
1102                 GETERRNO(r);
1103                 if(r== -1 && ERRNO==INTERRUPTED) continue;
1104                 if(r== -1 && !ISCONNECTING(ERRNO)){
1105                         log_net_err("connect", ERRNO);
1106                         SOCKET_CLOSE(s);
1107                         return -1;
1108                 }
1109                 break;
1110         }while(1);
1111
1112         return 0;
1113 }
1114
1115 SOCK_T make_udp_listen_socket(int listenport)
1116 {
1117         SOCK_T s;
1118         int r;
1119         struct sockaddr_in iaddr;
1120         struct sockaddr*   iaddrp=(struct sockaddr*)&iaddr;
1121
1122         r=SOCKET(AF_INET, SOCK_DGRAM, IPPROTO_UDP, s);
1123         GETERRNO(r);
1124         if(r== -1){
1125                 log_net_err("socket", ERRNO);
1126                 return 0;
1127         }
1128
1129         SET_REUSEADDR(s);
1130
1131         iaddr=make_sockaddr_in(INADDR_ANY, listenport);
1132
1133         r=BIND(s, iaddrp, sizeof(iaddr));
1134         GETERRNO(r);
1135         if(r== -1){
1136                 log_net_err("bind", ERRNO);
1137                 SOCKET_CLOSE(s);
1138                 return 0;
1139         }
1140
1141         return s;
1142 }
1143
1144 EXPORT SOCK_T make_udp_send_socket(char* listenhost, int listenport)
1145 {
1146         SOCK_T s;
1147         int r;
1148         struct sockaddr_in iaddr;
1149         struct sockaddr*   iaddrp=(struct sockaddr*)&iaddr;
1150
1151         r=SOCKET(AF_INET, SOCK_DGRAM, IPPROTO_UDP, s);
1152         GETERRNO(r);
1153         if(r== -1){
1154                 log_net_err("socket", ERRNO);
1155                 return 0;
1156         }
1157
1158         struct hostent* hostaddr=gethostbyname(listenhost);
1159         if(!hostaddr){
1160                 log_net_err("gethostbyname", h_errno);
1161                 SOCKET_CLOSE(s);
1162                 return 0;
1163         }
1164
1165         iaddr=make_sockaddr_in(0, listenport);
1166         memcpy(&iaddr.sin_addr, hostaddr->h_addr, hostaddr->h_length);
1167
1168         r=CONNECT(s, iaddrp, sizeof(iaddr));
1169         GETERRNO(r);
1170         if(r== -1){
1171                 log_net_err("connect", ERRNO);
1172                 SOCKET_CLOSE(s);
1173                 return 0;
1174         }
1175
1176         return s;
1177 }
1178
1179 struct sockaddr_in make_sockaddr_in(unsigned long address, unsigned int port)
1180 {
1181         struct sockaddr_in iaddr;
1182         struct sockaddr*   iaddrp=(struct sockaddr*)&iaddr;
1183         memset(iaddrp, 0, sizeof(iaddr));
1184         iaddr.sin_addr.s_addr=htonl(address);
1185         iaddr.sin_port       =htons(port);
1186         iaddrp->sa_family=AF_INET;
1187         return iaddr;
1188 }
1189
1190 void log_net_err(char* where, int e)
1191 {
1192         if(0) k_log_out("Network (%s): %s (%d)", where, str_error(e), e);
1193 }
1194
1195 /* -------------------------------------------------------------------------- */
1196
1197 EXPORT void k_file_stat(char*        basedir,
1198                         char*        filename,
1199                         k_file_event callback,
1200                         void*        context)
1201 {
1202         snprintf(tmpbuf, TMPBUFSIZE, "%s/%s", basedir, filename);
1203         char* fullname=tmpbuf;
1204
1205         k_stat kstat={0,0,0,0};
1206
1207         stat_only(fullname, &kstat);
1208         (*callback)(basedir, filename, 0, 0, kstat, context);
1209 }
1210
1211 EXPORT void k_file_read(char*        basedir,
1212                         char*        filename,
1213                         size_t       mmapsize,
1214                         size_t       size,
1215                         k_file_event callback,
1216                         void*        context)
1217 {
1218         snprintf(tmpbuf, TMPBUFSIZE, "%s/%s", basedir, filename);
1219         char* fullname=tmpbuf;
1220
1221         FILE_T filehandle;
1222         k_stat kstat={0,0,0,0};
1223
1224         int write=!!size;
1225         if(write && !ensure_dir(fullname)){
1226                 (*callback)(basedir, filename, 0, 0, kstat, context);
1227                 return;
1228         }
1229
1230         stat_only(fullname, &kstat);
1231         if(!kstat.type && !write){
1232                 (*callback)(basedir, filename, 0, 0, kstat, context);
1233                 return;
1234         }
1235         filehandle=open_only(fullname, write);
1236         if(!filehandle){
1237                 (*callback)(basedir, filename, 0, 0, kstat, context);
1238                 return;
1239         }
1240         if(!kstat.type || (write && kstat.size!=size)){
1241                 if(ftruncate(filehandle, size)){
1242                         FCLOSE(filehandle);
1243                         (*callback)(basedir, filename, 0, 0, kstat, context);
1244                         return;
1245                 }
1246         }
1247         FCLOSE(filehandle);
1248
1249         if(!write) size=kstat.size;
1250         else       kstat.size=size;
1251
1252         if(size>MAX_FILESIZE){
1253                 (*callback)(basedir, filename, 0, 0, kstat, context);
1254                 return;
1255         }
1256         int dommap=(size >= mmapsize);
1257
1258         int prot=(write? PROT_WRITE: 0)|PROT_READ;
1259
1260         char* data;
1261
1262         if(size==0) data=dommap? dummy_empty_data: k_malloc(1);
1263         else
1264         if(dommap)  data=mmap_name(  0, size, prot, MAP_SHARED, fullname, 0);
1265         else        data=mmap_malloc(0, size, prot, MAP_SHARED, fullname, 0);
1266
1267         if(data==MAP_FAILED){
1268                 (*callback)(basedir, filename, 0, 0, kstat, context);
1269                 return;
1270         }
1271         (*callback)(basedir, filename, data, dommap, kstat, context);
1272 }
1273
1274 EXPORT int k_file_sync(char* data, size_t size)
1275 {
1276         int r=msync(data, size, MS_ASYNC);
1277         return !r;
1278 }
1279
1280 EXPORT void k_file_write(char*        basedir,
1281                          char*        filename,
1282                          char*        data,
1283                          size_t       datalength,
1284                          k_file_event callback,
1285                          void*        context)
1286 {
1287         snprintf(tmpbuf, TMPBUFSIZE, "%s/%s", basedir, filename);
1288         char* fullname=tmpbuf;
1289
1290         FILE_T filehandle;
1291         k_stat kstat={0,0,0,0};
1292
1293         if(!ensure_dir(fullname)){
1294                 (*callback)(basedir, filename, 0, 0, kstat, context);
1295                 return;
1296         }
1297
1298         filehandle=open_only(fullname, 1);
1299         if(!filehandle){
1300                 (*callback)(basedir, filename, 0, 0, kstat, context);
1301                 return;
1302         }
1303         if(datalength!=0) kstat.size=WRITEFILE(filehandle, data, datalength);
1304         if(kstat.size== -1){
1305                 FCLOSE(filehandle);
1306                 (*callback)(basedir, filename, 0, 0, kstat, context);
1307                 return;
1308         }
1309         FCLOSE(filehandle);
1310         (*callback)(basedir, filename, data, 0, kstat, context);
1311 }
1312
1313 EXPORT void k_dir_list(char*        basedir,
1314                        char*        dirname,
1315                        char*        pattern[],
1316                        char*        format[],
1317                        k_file_event callback,
1318                        void*        context)
1319 {
1320         snprintf(tmpbuf, TMPBUFSIZE, "%s/%s", basedir, dirname);
1321         char* fullname=k_strdup(tmpbuf);
1322
1323         k_stat kstat={ STAT_D, 0, 0, 0 };
1324         char* buf=tmpbuf;
1325         int   size=TMPBUFSIZE;
1326         int i;
1327         for(i=0; format[i]; i++){
1328                 int n=dir_list(buf, size, fullname, pattern[i], format[i]);
1329                 if(n== -1){
1330                         (*callback)(basedir, dirname, 0, 0, kstat, context);
1331                         k_free(fullname);
1332                         return;
1333                 }
1334                 buf+=n; size-=n;
1335         }
1336         kstat.size=TMPBUFSIZE-size;
1337         (*callback)(basedir, dirname, k_strdup(tmpbuf), 0, kstat, context);
1338         k_free(fullname);
1339 }
1340
1341 int dir_list(char* buf, int size, char* fullname, char* pattern, char* format)
1342 {
1343         DIR* d=opendir(fullname);
1344         if(!d) return -1;
1345
1346         char* b=buf;
1347         int   s=size;
1348         *b=0;
1349         struct dirent* de;
1350         while((de=readdir(d))){
1351
1352                 char* name=de->d_name;
1353                 if(*name=='.') continue;
1354
1355                 if(pattern && *pattern &&
1356                           !k_string_matches_pattern(name, pattern)) continue;
1357
1358                 int n=snprintf(b, s, format, name, name, name, name, name);
1359                 if(n< 0 || n>=s){ closedir(d); return -1; }
1360                 b+=n; s-=n;
1361         }
1362         closedir(d);
1363         return size-s;
1364 }
1365
1366 int ensure_dir(char* fullname)
1367 {
1368         char* e=strrchr(fullname, '/');
1369         if(!e) return 1;
1370         *e=0;
1371         k_stat kstat={0,0,0,0};
1372         stat_only(fullname, &kstat);
1373         if(kstat.type!=STAT_D){
1374                 MKDIR(fullname);
1375                 stat_only(fullname, &kstat);
1376         }
1377         *e='/';
1378         return kstat.type==STAT_D;
1379 }
1380
1381 /* -------------------------------------------------------------------------- */
1382
1383 EXPORT int k_string_matches_pattern(char* string, char* pattern)
1384 {
1385         char patt[32];
1386         strncpy(patt, pattern, 32);
1387         patt[31]=0;
1388         pattern=patt;
1389         if(*pattern=='{'){
1390                 while(1){
1391                         pattern++;
1392                         char* e=strpbrk(pattern, ",}");
1393                         if(!e) return 0;
1394                         char x=*e; *e=0;
1395                         if(k_string_matches_pattern(string, pattern)) return 1;
1396                         *e=x;
1397                         pattern=e;
1398                 }
1399         }
1400         else
1401         if(*pattern=='*'){
1402                 pattern++;
1403                 return k_string_ends_with(string, pattern);
1404         }
1405         return 0;
1406 }
1407
1408 EXPORT int k_string_ends_with(char* string, char* postfix)
1409 {
1410         char* i=string+strlen(string)-strlen(postfix);
1411         if(i<string) return 0;
1412         return !strcmp(i, postfix);
1413 }
1414
1415 EXPORT void k_string_url_decode(char* s)
1416 {
1417         char* t=s;
1418         while(*s){
1419                 if(s[0]=='%' && isxdigit(s[1]) && isxdigit(s[2])){
1420                         *t=hex_to_int(s[1])*16+hex_to_int(s[2]);
1421                         s+=3; t++;
1422                 }
1423                 else{
1424                         *t=*s;
1425                         s++; t++;
1426                 }
1427         }
1428         *t=0;
1429 }
1430
1431 char hex_to_int(char c)
1432 {
1433         return
1434         (c >= '0' && c <= '9')? c-'0':
1435         (c >= 'A' && c <= 'F')? c-'A'+10:
1436         (c >= 'a' && c <= 'f')? c-'a'+10: 0;
1437 }
1438
1439 /* -------------------------------------------------------------------------- */
1440
1441 EXPORT void k_log_out(char* format, ...)
1442 {
1443         va_list ap;
1444         va_start(ap, format);
1445         if(LOG_TO_STD){
1446                 VPRINTFOUT(format,ap);
1447                 PRINTFOUT("\n");
1448                 FFLUSH(stdout);
1449         }
1450         else{
1451                 vsnprintf(logbuf, LOGBUFSIZE,format,ap);
1452                 *(logbuf+LOGBUFSIZE-2)='\n';
1453                 *(logbuf+LOGBUFSIZE-1)=0;
1454                 write_to_logfile_cern_style(logbuf,0);
1455         }
1456         va_end(ap);
1457 }
1458
1459 EXPORT void k_log_err(char* format, ...)
1460 {
1461         va_list ap;
1462         va_start(ap, format);
1463         if(LOG_TO_STD){
1464                 VPRINTFERR(format,ap);
1465                 PRINTFERR("\n");
1466                 FFLUSH(stderr);
1467         }
1468         else{
1469                 vsnprintf(logbuf, LOGBUFSIZE,format,ap);
1470                 *(logbuf+LOGBUFSIZE-2)='\n';
1471                 *(logbuf+LOGBUFSIZE-1)=0;
1472                 write_to_logfile_cern_style(logbuf,1);
1473         }
1474         va_end(ap);
1475 }
1476
1477 EXPORT void k_fatal(char* format, ...)
1478 {
1479         va_list ap;
1480         va_start(ap, format);
1481         k_log_out(format, ap);
1482         va_end(ap);
1483         k_log_out("Terminating Cilux");
1484         k_log_out("---------------------");
1485         EXIT(1);
1486 }
1487
1488 void write_to_logfile_cern_style(char* text, int error)
1489 {
1490         if(!logfile) return;
1491
1492         time_t now=time(0);
1493         struct tm* tm;
1494         int        z;
1495         if(log_gmt){
1496                 tm=gmtime(&now);
1497                 z=0;
1498         }
1499         else{
1500                 tm=localtime(&now);
1501                 z=TIMEZONE(tm)/60;
1502         }
1503         char sgn;
1504         if(z >=0){ sgn='+';        }
1505         else{      sgn='-'; z= -z; }
1506
1507         char cern[64];
1508         char date[64];
1509         strftime(cern, sizeof(cern), CERNDATE, tm);
1510 #ifdef SHOW_ZONE
1511         snprintf(date, sizeof(date), "%s %c%02d%02d", cern, sgn, z/60, z%60);
1512 #else
1513         snprintf(date, sizeof(date), "%s",            cern);
1514 #endif
1515         FPRINTF(logfile, "[%s|%s] %s%s\n", date, k_ciux,
1516                                            error? "Warning: ": "", text);
1517         FFLUSH(logfile);
1518 }
1519
1520 /* -------------------------------------------------------------------------- */
1521
1522 #define EXAMPLE_DATE   Fri, 04 Feb 2005 12:14:48 GMT
1523 #define RFC1123STRF   "%a, %d %b %Y %H:%M:%S GMT"
1524 #define RFC1123SSCANF "%3s, %d %3s %4d %2d:%2d:%2d GMT"
1525
1526 static char b[100];
1527
1528 EXPORT char* k_time_to_rfc(time_t t)
1529 {
1530         strftime(b, sizeof(b), RFC1123STRF, gmtime(&t));
1531         return b;
1532 }
1533
1534 EXPORT char* k_time_to_rfc_relative(int plus)
1535 {
1536         time_t t=time(0)+plus;
1537         strftime(b, sizeof(b), RFC1123STRF, gmtime(&t));
1538         return b;
1539 }
1540
1541 EXPORT time_t k_time_from_rfc(char* s)
1542 {
1543         if(!s || strlen(s)!=29) return -1;
1544         struct tm tm; tm.tm_wday=0; tm.tm_yday=0; tm.tm_isdst=0;
1545         char wd[32], mn[32];
1546         int r=sscanf(s, RFC1123SSCANF, wd, &tm.tm_mday, mn, &tm.tm_year,
1547                                        &tm.tm_hour, &tm.tm_min, &tm.tm_sec);
1548         if(r!=7) return -1;
1549         tm.tm_mon=(int)k_hashtable_get(monthhash, mn);
1550         if(tm.tm_mon) tm.tm_mon -=1;
1551         tm.tm_year-=1900;
1552         return MKTIME(&tm);
1553 }
1554
1555 EXPORT void k_time_get_now(char* buf, size_t size, char* format)
1556 {
1557         time_t now=time(0);
1558         struct tm* tm;
1559         int gmt=1;
1560         if(gmt){
1561                 tm=gmtime(&now);
1562         }
1563         else{
1564                 tm=localtime(&now);
1565         }
1566         strftime(buf, size, format, tm);
1567 }
1568
1569 /* -------------------------------------------------------------------------- */
1570
1571 typedef struct hash_item hash_item;
1572
1573 typedef struct hashtable{ struct hashtable* next;
1574         char*       name;
1575         int         buckets;
1576         int         size;
1577         hash_item** lists;
1578         int         ignorecase;
1579 } hashtable;
1580
1581 struct hash_item{ hash_item* next;
1582         char*        key;
1583         void*        val;
1584         int          free;
1585         k_hashtable* sub;
1586 };
1587
1588 /* -------------------------------------------------------------------------- */
1589
1590 #define STRCMPCASE(tab, listkey, key)\
1591 ((tab)->ignorecase? strcasecmp((listkey), (key)): strcmp((listkey), (key)))
1592 #define BX 30
1593 #define WARN_SIZE(h)\
1594 if((h)->size && !((h)->size % BX)) k_log_out("%s# %d", (h)->name, (h)->size);
1595
1596 EXPORT k_hashtable* k_hashtable_new(char* name, int ignorecase)
1597 {
1598         hashtable* tab;
1599         tab=k_malloc(sizeof(hashtable));
1600         tab->name=name;
1601         tab->buckets=BX;
1602         tab->size=0;
1603         tab->lists=k_malloc((tab->buckets)*sizeof(hash_item*));
1604         tab->ignorecase=ignorecase;
1605         tab->next=0;
1606         int i; for(i=0; i< tab->buckets; i++) tab->lists[i]=0;
1607         return (k_hashtable*)tab;
1608 }
1609
1610 k_hashtable* k_hashtable_dup2(k_hashtable* tab, int deep)
1611 {
1612         if(!tab) return 0;
1613         hashtable* tah=(hashtable*)tab;
1614         hashtable* tad;
1615         tad=k_malloc(sizeof(hashtable));
1616         tad->name=tah->name;
1617         tad->buckets=tah->buckets;
1618         tad->size=tah->size;
1619         tad->lists=k_malloc((tah->buckets)*sizeof(hash_item*));
1620         tad->ignorecase=tah->ignorecase;
1621         tad->next=0;
1622         hash_item** lisp=0;
1623         hash_item** lisd=0;
1624         int i;
1625         for(i=0; i< tah->buckets; i++){
1626                 for(lisp=&tah->lists[i], lisd=&tad->lists[i];
1627                     (*lisp);
1628                     lisp=&(*lisp)->next, lisd=&(*lisd)->next){
1629
1630                         (*lisd)=k_malloc(sizeof(hash_item));
1631                         (*lisd)->key=k_strdup((*lisp)->key);
1632                         (*lisd)->val=0;
1633                         (*lisd)->free=0;
1634                         (*lisd)->sub=0;
1635                         if((*lisp)->val){
1636                                 (*lisd)->val=k_strdup((*lisp)->val);
1637                                 (*lisd)->free=1;
1638                         }
1639                         if(deep && (*lisp)->sub){
1640                                 (*lisd)->sub=k_hashtable_dup2((*lisp)->sub, 1);
1641                         }
1642                         if(!(*lisd)->val && !(*lisd)->sub){
1643                                 (*lisd)->val="...";
1644                         }
1645                 }
1646                 (*lisd)=0;
1647         }
1648         tad->next=(hashtable*)k_hashtable_dup2(tab->next, deep);
1649         return (k_hashtable*)tad;
1650 }
1651
1652 EXPORT k_hashtable* k_hashtable_dup(k_hashtable* tab)
1653 {
1654         return k_hashtable_dup2(tab, 0);
1655 }
1656
1657 EXPORT k_hashtable* k_hashtable_deep(k_hashtable* tab)
1658 {
1659         return k_hashtable_dup2(tab, 1);
1660 }
1661
1662 EXPORT k_hashtable* k_hashtable_dip(k_hashtable* tab, char* includes[])
1663 {
1664         if(!tab) return 0;
1665         hashtable* tah=(hashtable*)tab;
1666         hashtable* tad;
1667         tad=(hashtable*)k_hashtable_new(tah->name, tah->ignorecase);
1668         int i;
1669         for(i=0; includes[i]; i++){
1670                 char* in=k_hashtable_get((k_hashtable*)tah, includes[i]);
1671                 if(!in) continue;
1672                 in=k_strdup(in);
1673                 k_hashtable_put((k_hashtable*)tad, includes[i], in);
1674         }
1675         tad->next=(hashtable*)k_hashtable_dip(tab->next, includes);
1676         return (k_hashtable*)tad;
1677 }
1678
1679 EXPORT void k_hashtable_merge(k_hashtable* tab, k_hashtable* tam)
1680 {
1681         hashtable* tan=(hashtable*)tam;
1682         hash_item** lisp;
1683         int i;
1684         for(i=0; i< tan->buckets; i++){
1685                 for(lisp=&tan->lists[i]; (*lisp); lisp=&(*lisp)->next){
1686                         char*        key =(*lisp)->key;
1687                         void*        val =(*lisp)->val;
1688                         int          free=(*lisp)->free;
1689                         k_hashtable* sub =(*lisp)->sub;
1690                         if(!*key && free) continue;
1691                         if(val){
1692                                 k_hashtable_put(tab, key, k_strdup(val));
1693                         }
1694                         if(sub){
1695                                 k_hashtable_sub(tab, key, k_hashtable_dup(sub));
1696                         }
1697                 }
1698         }
1699 }
1700
1701 void k_hashtable_set_put(k_hashtable* tab, char* key, void* val, int free)
1702 {
1703         if(!(tab && key && val)) return;
1704         hashtable* tah=(hashtable*)tab;
1705         hash_item** lisp;
1706         lisp=&tah->lists[string_hash(key) % tah->buckets];
1707         while((*lisp) && STRCMPCASE(tah, (*lisp)->key, key)){
1708                 lisp=&(*lisp)->next;
1709         }
1710         if(!(*lisp)){
1711                 (*lisp)=k_malloc(sizeof(hash_item));
1712                 (*lisp)->key=k_strdup(key);
1713                 (*lisp)->val=val;
1714                 (*lisp)->free=free;
1715                 (*lisp)->sub=0;
1716                 (*lisp)->next=0;
1717                 tah->size++;
1718                 WARN_SIZE(tah);
1719         }
1720         else{
1721                 if((*lisp)->free) k_free((*lisp)->val);
1722                 k_hashtable_delete((*lisp)->sub);
1723                 (*lisp)->val=val;
1724                 (*lisp)->free=free;
1725                 (*lisp)->sub=0;
1726         }
1727 }
1728
1729 EXPORT void k_hashtable_set(k_hashtable* tab, char* key, void* val)
1730 {
1731         k_hashtable_set_put(tab, key, val, 0);
1732 }
1733
1734 EXPORT void k_hashtable_put_int(k_hashtable* tab, char* key, int val)
1735 {
1736         snprintf(tmpbuf, TMPBUFSIZE, "%d", val);
1737         k_hashtable_set_put(tab, key, k_strdup(tmpbuf), 1);
1738 }
1739
1740 EXPORT void k_hashtable_put(k_hashtable* tab, char* key, void* val)
1741 {
1742         k_hashtable_set_put(tab, key, val, 1);
1743 }
1744
1745 EXPORT void k_hashtable_put_dup(k_hashtable* tab, char* key, char* val)
1746 {
1747         k_hashtable_set_put(tab, key, k_strdup(val), 1);
1748 }
1749
1750 EXPORT void k_hashtable_sub(k_hashtable* tab, char* key, k_hashtable* sub)
1751 {
1752         if(!(tab && key && sub)) return;
1753         sub->next=0;
1754         hashtable* tah=(hashtable*)tab;
1755         hash_item** lisp;
1756         lisp=&tah->lists[string_hash(key) % tah->buckets];
1757         while((*lisp) && STRCMPCASE(tah, (*lisp)->key, key)){
1758                 lisp=&(*lisp)->next;
1759         }
1760         if(!(*lisp)){
1761                 (*lisp)=k_malloc(sizeof(hash_item));
1762                 (*lisp)->key=k_strdup(key);
1763                 (*lisp)->val=0;
1764                 (*lisp)->free=0;
1765                 (*lisp)->sub=sub;
1766                 (*lisp)->next=0;
1767                 tah->size++;
1768                 WARN_SIZE(tah);
1769         }
1770         else{
1771                 k_hashtable* val =(*lisp)->val;
1772                 k_hashtable* head=(*lisp)->sub;
1773                 if(!head){
1774                         if(val) k_log_err("key '%s' in use: no sub!", key);
1775                         else (*lisp)->sub=sub;
1776                 }
1777                 else{
1778                         while(head->next) head=head->next;
1779                         head->next=sub;
1780                 }
1781         }
1782 }
1783
1784 EXPORT void* k_hashtable_get(k_hashtable* tab, char* key)
1785 {
1786         if(!(tab && key)) return 0;
1787         hashtable* tah=(hashtable*)tab;
1788         hash_item* list;
1789         list=tah->lists[string_hash(key) % tah->buckets];
1790         while(list && STRCMPCASE(tah, list->key, key)){
1791                 list=list->next;
1792         }
1793         return list? (list->val? list->val: list->sub): 0;
1794 }
1795
1796 EXPORT int k_hashtable_get_int(k_hashtable* tab, char* key)
1797 {
1798         char* val=k_hashtable_get(tab, key);
1799         return val? atoi(val): 0;
1800 }
1801
1802 EXPORT char* k_hashtable_get_dup(k_hashtable* tab, char* key)
1803 {
1804         char* v=k_hashtable_get(tab, key);
1805         return k_strdup(v);
1806 }
1807
1808 EXPORT int k_hashtable_is(k_hashtable* tab, char* key, char* val)
1809 {
1810         char* v=k_hashtable_get(tab, key);
1811         return (v && val && !strcmp(v, val));
1812 }
1813
1814 EXPORT int k_hashtable_isi(k_hashtable* tab, char* key, char* val)
1815 {
1816         char* v=k_hashtable_get(tab, key);
1817         return (v && val && !strcasecmp(v, val));
1818 }
1819
1820 EXPORT int k_hashtable_isn(k_hashtable* tab, char* key, char* val, size_t size)
1821 {
1822         char* v=k_hashtable_get(tab, key);
1823         return (v && val && !strncmp(v, val, size));
1824 }
1825
1826 EXPORT void* k_hashtable_extract(k_hashtable* tab, char* key)
1827 {
1828         hashtable*  tah=(hashtable*)tab;
1829         hash_item** lisp;
1830         hash_item*  next;
1831         lisp=&tah->lists[string_hash(key) % tah->buckets];
1832         while((*lisp) && STRCMPCASE(tah, (*lisp)->key, key)){
1833                 lisp=&(*lisp)->next;
1834         }
1835         void* val=0;
1836         if((*lisp)){
1837                 next=  (*lisp)->next;
1838                 k_free((*lisp)->key);
1839                 val=   (*lisp)->val;
1840                 if(!val) val=(*lisp)->sub;
1841                 k_free((*lisp));
1842                 (*lisp)=next;
1843                 tah->size--;
1844                 WARN_SIZE(tah);
1845         }
1846         return val;
1847 }
1848
1849 EXPORT void k_hashtable_remove(k_hashtable* tab, char* key)
1850 {
1851         hashtable*  tah=(hashtable*)tab;
1852         hash_item** lisp;
1853         hash_item*  next;
1854         lisp=&tah->lists[string_hash(key) % tah->buckets];
1855         while((*lisp) && STRCMPCASE(tah, (*lisp)->key, key)){
1856                 lisp=&(*lisp)->next;
1857         }
1858         if((*lisp)){
1859                 next=  (*lisp)->next;
1860                 k_free((*lisp)->key);
1861                 if((*lisp)->free) k_free((*lisp)->val);
1862                 k_hashtable_delete((*lisp)->sub);
1863                 k_free((*lisp));
1864                 (*lisp)=next;
1865                 tah->size--;
1866                 WARN_SIZE(tah);
1867         }
1868 }
1869
1870 EXPORT void k_hashtable_delete(k_hashtable* tab)
1871 {
1872         if(!tab) return;
1873         hashtable* tah=(hashtable*)tab;
1874         hash_item* list;
1875         hash_item* next;
1876         int i;
1877         for(i=0; i< tah->buckets; i++){
1878                 list=tah->lists[i];
1879                 while(list){
1880                         next=list->next;
1881                         k_free(list->key);
1882                         if(list->free) k_free(list->val);
1883                         k_hashtable_delete(list->sub);
1884                         k_free(list);
1885                         list=next;
1886                 }
1887         }
1888         k_free(tah->lists);
1889         k_hashtable_delete((k_hashtable*)tah->next);
1890         k_free(tah);
1891 }
1892
1893 EXPORT void k_hashtable_apply(k_hashtable*         tab,
1894                               k_hashtable_apply_fn fn,
1895                               void*                arg)
1896 {
1897         if(!tab) return;
1898         hashtable* tah=(hashtable*)tab;
1899         hash_item** lisp;
1900         int i;
1901         for(i=0; i< tah->buckets; i++){
1902                 for(lisp=&tah->lists[i]; (*lisp); lisp=&(*lisp)->next){
1903                         if((*lisp)->val){
1904                                 (*fn)(arg, (*lisp)->key, (*lisp)->val);
1905                         }
1906                         else{
1907                                 (*fn)(arg, (*lisp)->key, (*lisp)->sub);
1908                         }
1909                 }
1910         }
1911 }
1912
1913 void k_hashtable_show2(k_hashtable* tab, int chars)
1914 {
1915         if(!tab) return;
1916         hashtable* tah=(hashtable*)tab;
1917         if(!chars) k_log_out("%s size=%d", tah->name, tah->size);
1918         hash_item** lisp;
1919         int i;
1920         for(i=0; i< tah->buckets; i++){
1921                 for(lisp=&tah->lists[i]; (*lisp); lisp=&(*lisp)->next){
1922                         if(chars){
1923                                 if(*((*lisp)->key)){
1924                                         k_log_out("%s %s",
1925                                            (*lisp)->key, (char*)((*lisp)->val));
1926                                 }
1927                         }
1928                         else{
1929                                 k_log_out("buck %d key '%s' val %x sub %x",
1930                                  i, (*lisp)->key, (*lisp)->val, (*lisp)->sub);
1931                         }
1932                 }
1933         }
1934 }
1935
1936 EXPORT void k_hashtable_show(k_hashtable* tab)
1937 {
1938         k_hashtable_show2(tab,0);
1939 }
1940
1941 EXPORT void k_hashtable_show_chars(k_hashtable* tab)
1942 {
1943         k_hashtable_show2(tab,1);
1944 }
1945
1946 int k_hashtable_snprintf_xi(k_hashtable* tab,
1947                             char*        buf,
1948                             size_t       size,
1949                             char*        includes[],
1950                             char*        excludes[],
1951                             int          indent)
1952 {
1953         if(!tab){ if(size) *buf=0; return 0; }
1954         char ind[]="                                                         ";
1955         ind[indent]=0;
1956         hashtable* tah=(hashtable*)tab;
1957         *buf=0;
1958         char* at=buf;
1959         int   ln=size;
1960         hash_item** lisp;
1961         int i;
1962         for(i=0; i< tah->buckets; i++){
1963         for(lisp=&tah->lists[i]; (*lisp); lisp=&(*lisp)->next){
1964                 if(!*((*lisp)->key)) continue;
1965                 if(check_i((*lisp)->key, includes, tah->ignorecase)) continue;
1966                 if(check_x((*lisp)->key, excludes, tah->ignorecase)) continue;
1967                 int n;
1968                 if((*lisp)->val){
1969                         n=snprintf(at, ln, "%s%s %s" CRLF, ind, (*lisp)->key,
1970                                                         (char*)((*lisp)->val));
1971                         if(n<  0) return n;
1972                         if(n>=ln) return size;
1973                         at+=n; ln-=n;
1974                 }
1975                 else{
1976                         k_hashtable* sub=(*lisp)->sub;
1977                         do{
1978                                 n=snprintf(at, ln, "%s%s" CRLF,
1979                                                            ind, (*lisp)->key);
1980                                 if(n<  0) return n;
1981                                 if(n>=ln) return size;
1982                                 at+=n; ln-=n;
1983         
1984                                 n=k_hashtable_snprintf_xi(sub, at, ln, 0, 0,
1985                                                           indent+8);
1986                                 if(n<  0) return n;
1987                                 if(n>=ln) return size;
1988                                 at+=n; ln-=n;
1989
1990                         }while((sub=sub->next));
1991                 }
1992         }
1993         }
1994         return size-ln;
1995 }
1996
1997 EXPORT int k_hashtable_snprintf(k_hashtable* tab, char* buf, size_t size)
1998 {
1999         return k_hashtable_snprintf_xi(tab, buf, size, 0, 0, 0);
2000 }
2001
2002 EXPORT int k_hashtable_snprintf_i(k_hashtable* tab,
2003                                   char*        buf,
2004                                   size_t       size,
2005                                   char*        includes[])
2006 {
2007         return k_hashtable_snprintf_xi(tab, buf, size, includes, 0, 0);
2008 }
2009
2010 EXPORT int k_hashtable_snprintf_x(k_hashtable* tab,
2011                                   char*        buf,
2012                                   size_t       size,
2013                                   char*        excludes[])
2014 {
2015         return k_hashtable_snprintf_xi(tab, buf, size, 0, excludes, 0);
2016 }
2017
2018 int check_i(char* key, char* includes[], int ignorecase)
2019 {
2020         if(!includes) return 0;
2021         int e;
2022         for(e=0; includes[e]; e++){
2023                 if(ignorecase?  !strcasecmp(key, includes[e]):
2024                                 !strcmp(    key, includes[e]) ) break;
2025         }
2026         return !includes[e];
2027 }
2028
2029 int check_x(char* key, char* excludes[], int ignorecase)
2030 {
2031         if(!excludes) return 0;
2032         int e;
2033         for(e=0; excludes[e]; e++){
2034                 if(ignorecase?  !strcasecmp(key, excludes[e]):
2035                                 !strcmp(    key, excludes[e]) ) break;
2036         }
2037         return !!excludes[e];
2038 }
2039
2040 unsigned int string_hash(char* p)
2041 {
2042         unsigned int h=0;
2043         while(*p) h=(h<<5)-h+tolower(*p++);
2044         return h;
2045 }
2046
2047
2048 /* -------------------------------------------------------------------------- */
2049
2050
2051