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