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