Support recursive tables.
[olsrd.git] / lib / tas / src / http.c
1 /*
2  * The olsr.org Optimized Link-State Routing daemon (olsrd)
3  *
4  * Copyright (c) 2004, Thomas Lopatic (thomas@olsr.org)
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without 
8  * modification, are permitted provided that the following conditions 
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright 
12  *   notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above copyright 
14  *   notice, this list of conditions and the following disclaimer in 
15  *   the documentation and/or other materials provided with the 
16  *   distribution.
17  * * Neither the name of olsr.org, olsrd nor the names of its 
18  *   contributors may be used to endorse or promote products derived 
19  *   from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
32  * POSSIBILITY OF SUCH DAMAGE.
33  *
34  * Visit http://www.olsr.org for more information.
35  *
36  * If you find this software useful feel free to make a donation
37  * to the project. For more information see the website or contact
38  * the copyright holders.
39  *
40  * $Id: http.c,v 1.2 2005/04/12 19:57:26 tlopatic Exp $
41  */
42
43 #include "link.h"
44 #include "plugin.h"
45 #include "lib.h"
46 #include "os_unix.h"
47 #include "http.h"
48 #include "glua.h"
49 #include "glua_ext.h"
50
51 #include <string.h>
52 #include <stdarg.h>
53
54 // #define TAS_BLOCK
55
56 #define DEF_CONFIG_ROOT_DIR "/etc/tas"
57 #define DEF_CONFIG_WORK_DIR "/var/run/tas"
58 #define DEF_CONFIG_PORT 1979
59 #define DEF_CONFIG_ADDR "127.0.0.1"
60 #define DEF_CONFIG_INDEX_FILE "index.html"
61 #define DEF_CONFIG_USER NULL
62 #define DEF_CONFIG_PASSWORD NULL
63 #define DEF_CONFIG_SESS_TIME 600
64 #define DEF_CONFIG_PUB_DIR "pub"
65 #define DEF_CONFIG_QUANTUM 30
66 #define DEF_CONFIG_MESS_TIME 60
67 #define DEF_CONFIG_MESS_LIMIT 100
68
69 static struct ipAddr confAddr;
70 static int confPort;
71 static char *confRootDir;
72 static char *confWorkDir;
73 static char *confIndexFile;
74 static char *confUser;
75 static char *confPassword;
76 static int confSessTime;
77 static char *confPubDir;
78 static int confQuantum;
79 static int confMessTime;
80 static int confMessLimit;
81
82 static struct
83 {
84   unsigned int sessId;
85   unsigned char key[16];
86 } cookieStruct;
87
88 #define MAX_CONN 5
89
90 static int numConn;
91 static struct connInfo *conn[MAX_CONN];
92
93 struct sessInfo
94 {
95   unsigned int id;
96   void *data;
97   struct timeStamp time;
98 };
99
100 #define MAX_SESS 10
101
102 static int numSess;
103 static struct sessInfo *sess[MAX_SESS];
104
105 static struct extMap
106 {
107   char *ext;
108   char *type;
109   int state;
110 }
111 extMap[] =
112 {
113   { ".png", "image/png", STATE_FILE },
114   { ".gif", "image/gif", STATE_FILE },
115   { ".jpg", "image/jpg", STATE_FILE },
116   { ".lsp", "text/html; charset=iso-8859-1", STATE_LSP },
117   { ".html", "text/html; charset=iso-8859-1", STATE_FILE },
118   { ".htm", "text/html; charset=iso-8859-1", STATE_FILE },
119   { NULL, NULL, 0 }
120 };
121
122 struct tasMessage
123 {
124   struct tasMessage *next;
125
126   struct timeStamp time;
127
128   char *service;
129   char *string;
130   char *from;
131 };
132
133 static struct tasMessage *firstTasMsg, *lastTasMsg;
134 static int numTasMsg;
135
136 static void rc4(unsigned char *buff, int len, unsigned char *key, int keyLen)
137 {
138   int i, m, n;
139   unsigned char state[256];
140   unsigned char aux;
141         
142   for (i = 0; i < 256; i++)
143     state[i] = (unsigned char)i;
144         
145   m = 0;
146   n = 0;
147         
148   for (i = 0; i < 256; i++)
149   {
150     m = (m + key[n] + state[i]) & 255;
151                 
152     aux = state[i];
153     state[i] = state[m];
154     state[m] = aux;
155
156     n = (n + 1) % keyLen;
157   }
158         
159   m = 0;
160   n = 0;
161         
162   for (i = 0; i < len; i++)
163   {
164     n = (n + 1) & 255;
165     m = (m + state[n]) & 255;
166                 
167     aux = state[n];
168     state[n] = state[m];
169     state[m] = aux;
170                 
171     buff[i] ^= state[(state[m] + state[n]) & 255];
172   }
173 }
174
175 static int mapHexDigit(int digit)
176 {
177   if (digit >= 'A' && digit <= 'F')
178     return digit + 10 - 'A';
179
180   if (digit >= 'a' && digit <= 'f')
181     return digit + 10 - 'a';
182
183   if (digit >= '0' && digit <= '9')
184     return digit - '0';
185
186   return -1;
187 }
188
189 static int addHexDigit(int *val, int digit)
190 {
191   digit = mapHexDigit(digit);
192
193   if (digit < 0)
194     return -1;
195
196   *val = (*val << 4) | digit;
197
198   return 0;
199 }
200
201 static void encHexString(char *hexString, unsigned char *hex, int len)
202 {
203   static char *map = "0123456789ABCDEF";
204
205   while (len-- > 0)
206   {
207     *hexString++ = map[*hex >> 4];
208     *hexString++ = map[*hex++ & 15];
209   }
210
211   *hexString = 0;
212 }
213
214 static int decHexString(unsigned char *hex, char *hexString, int len)
215 {
216   int val;
217
218   while (len-- > 0)
219   {
220     val = 0;
221
222     if (addHexDigit(&val, *hexString++) < 0 ||
223         addHexDigit(&val, *hexString++) < 0)
224       return -1;
225
226     *hex++ = (unsigned char)val;
227   }
228
229   return 0;
230 }
231
232 static int decBase64(unsigned char *out, char *in)
233 {
234   static int map[256] =
235   {
236     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
237     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
238     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
239     52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
240     -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
241     15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
242     -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
243     41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
244     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
245     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
246     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
247     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
248     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
249     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
250     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
251     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
252   };
253   int state;
254   unsigned int val;
255   int digit;
256
257   val = 0;
258   state = 0;
259
260   while (*in != 0 && *in != '=')
261   {
262     digit = map[(unsigned char)*in++];
263
264     if (digit < 0)
265       return -1;
266
267     val = (val << 6) | digit;
268
269     if (state == 1)
270       *out++ = (unsigned char)(val >> 4);
271
272     else if (state == 2)
273       *out++ = (unsigned char)(val >> 2);
274
275     else if (state == 3)
276       *out++ = (unsigned char)val;
277
278     state = (state + 1) & 3;
279   }
280
281   return 0;
282 }
283
284 static void initInOutBuff(struct inOutBuff *buff)
285 {
286   buff->off = 0;
287   buff->len = 0;
288   buff->cont = 0;
289
290   buff->first = NULL;
291   buff->last = NULL;
292 }
293
294 static struct connInfo *newConnInfo(struct fileId *sockId, struct ipAddr *addr)
295 {
296   struct connInfo *info = allocMem(sizeof (struct connInfo));
297
298   info->sockId = sockId;
299   info->addr = addr;
300
301   info->state = STATE_REQUEST;
302
303   initInOutBuff(&info->read);
304   initInOutBuff(&info->write[0]);
305   initInOutBuff(&info->write[1]);
306   initInOutBuff(&info->write[2]);
307
308   info->which = 0;
309
310   info->flags = FLAG_READ | FLAG_WRITE;
311
312   info->buff = NULL;
313
314   info->buffUsed = 0;
315   info->buffTotal = 0;
316
317   info->firstHead = NULL;
318   info->lastHead = NULL;
319
320   info->verb = NULL;
321   info->host = NULL;
322   info->path = NULL;
323   info->para = NULL;
324   info->proto = NULL;
325
326   info->contType = "text/html; charset=iso-8859-1";
327   info->contLen = -1;
328
329   info->newSess = NULL;
330
331   info->authUser = NULL;
332   info->authPass = NULL;
333
334   return info;
335 }
336
337 static void freeInOutBuff(struct inOutBuff *buff)
338 {
339   struct chunk *walker, *next;
340
341   for (walker = buff->first; walker != NULL; walker = next)
342   {
343     next = walker->next;
344     freeMem(walker);
345   }
346 }
347
348 static void freeWorkBuff(struct workBuff *buff)
349 {
350   struct workBuff *next;
351
352   while (buff != NULL)
353   {
354     next = buff->next;
355     freeMem(buff);
356     buff = next;
357   }
358 }
359
360 static void freeConnInfo(struct connInfo *info)
361 {
362   freeMem(info->sockId);
363   freeMem(info->addr);
364
365   freeInOutBuff(&info->read);
366   freeInOutBuff(&info->write[0]);
367   freeInOutBuff(&info->write[1]);
368   freeInOutBuff(&info->write[2]);
369
370   freeWorkBuff(info->buff);
371
372   freeMem(info);
373 }
374
375 static struct sessInfo *newSessInfo(void)
376 {
377   static unsigned int sessId = 0;
378   struct sessInfo *info;
379
380   info = allocMem(sizeof (struct sessInfo));
381
382   info->id = sessId++;
383   info->data = NULL;
384
385   now(&info->time);
386
387   debug(DEBUG_SESSION, "new session, id = %u\n", info->id);
388
389   return info;
390 }
391
392 void *allocBuff(struct connInfo *info, int len)
393 {
394   struct workBuff *buff;
395   unsigned char *res;
396
397   debug(DEBUG_CONNECTION, "%d bytes of buffer space requested\n", len);
398
399   if (info->buff != NULL)
400     debug(DEBUG_CONNECTION,
401           "existing buffer, size = %d bytes, used = %d bytes, remaining = %d bytes\n",
402           info->buffTotal, info->buffUsed, info->buffTotal - info->buffUsed);
403
404   else
405     debug(DEBUG_CONNECTION, "no existing buffer\n");
406
407   if (info->buff == NULL || len > info->buffTotal - info->buffUsed)
408   {
409     info->buffTotal = (len > BUFF_SIZE) ? len : BUFF_SIZE;
410     info->buffUsed = 0;
411
412     debug(DEBUG_CONNECTION, "new buffer of %d bytes\n", info->buffTotal);
413
414     buff = allocMem(sizeof (struct workBuff) + info->buffTotal);
415
416     buff->data = (unsigned char *)(buff + 1);
417
418     buff->next = info->buff;
419     info->buff = buff;
420   }
421
422   res = info->buff->data + info->buffUsed;
423
424   info->buffUsed += len;
425
426   debug(DEBUG_CONNECTION, "used = %d bytes, remaining = %d bytes\n",
427         info->buffUsed, info->buffTotal - info->buffUsed);
428
429   return res;
430 }
431
432 void httpInit(void)
433 {
434   parseIpAddr(&confAddr, DEF_CONFIG_ADDR);
435   confPort = DEF_CONFIG_PORT;
436   confRootDir = DEF_CONFIG_ROOT_DIR;
437   confWorkDir = DEF_CONFIG_WORK_DIR;
438   confIndexFile = DEF_CONFIG_INDEX_FILE;
439   confUser = DEF_CONFIG_USER;
440   confPassword = DEF_CONFIG_PASSWORD;
441   confSessTime = DEF_CONFIG_SESS_TIME;
442   confPubDir = DEF_CONFIG_PUB_DIR;
443   confQuantum = DEF_CONFIG_QUANTUM;
444   confMessTime = DEF_CONFIG_MESS_TIME;
445   confMessLimit = DEF_CONFIG_MESS_LIMIT;
446
447   memset(cookieStruct.key, 0, 16);
448 }
449
450 int httpSetAddress(const char *addrStr)
451 {
452   if (parseIpAddr(&confAddr, addrStr) < 0)
453   {
454     error("invalid IP address: %s\n", addrStr);
455     return -1;
456   }
457
458   return 0;
459 }
460
461 int httpSetPort(const char *portStr)
462 {
463   unsigned int port;
464
465   if (stringToInt(&port, portStr) < 0)
466   {
467     error("invalid port number: %s\n", portStr);
468     return -1;
469   }
470
471   if (port > 65535)
472   {
473     error("invalid port number: %u\n", port);
474     return -1;
475   }
476
477   confPort = port;
478
479   return 0;
480 }
481
482 int httpSetRootDir(const char *rootDir)
483 {
484   if (checkAbsPath(rootDir) < 0)
485   {
486     error("root directory (%s) requires an absolute path\n", rootDir);
487     return -1;
488   }
489
490   confRootDir = myStrdup(rootDir);
491   return 0;
492 }
493
494 int httpSetWorkDir(const char *workDir)
495 {
496   if (checkAbsPath(workDir) < 0)
497   {
498     error("work directory (%s) requires an absolute path\n", workDir);
499     return -1;
500   }
501
502   confWorkDir = myStrdup(workDir);
503   return 0;
504 }
505
506 void httpSetIndexFile(const char *indexFile)
507 {
508   confIndexFile = myStrdup(indexFile);
509 }
510
511 void httpSetUser(const char *user)
512 {
513   confUser = myStrdup(user);
514 }
515
516 void httpSetPassword(const char *password)
517 {
518   confPassword = myStrdup(password);
519 }
520
521 int httpSetSessTime(const char *timeStr)
522 {
523   unsigned int time;
524
525   if (stringToInt(&time, timeStr) < 0)
526   {
527     error("invalid timeout: %s\n", timeStr);
528     return -1;
529   }
530
531   if (time > 86400)
532   {
533     error("invalid timeout: %u\n", time);
534     return -1;
535   }
536
537   confSessTime = time;
538
539   return 0;
540 }
541
542 void httpSetPubDir(const char *pubDir)
543 {
544   confPubDir = myStrdup(pubDir);
545 }
546
547 int httpSetQuantum(const char *quantumStr)
548 {
549   unsigned int quantum;
550
551   if (stringToInt(&quantum, quantumStr) < 0)
552   {
553     error("invalid quantum: %s\n", quantumStr);
554     return -1;
555   }
556
557   if (quantum > 100)
558   {
559     error("invalid quantum: %u\n", quantum);
560     return -1;
561   }
562
563   confQuantum = quantum;
564
565   return 0;
566 }
567
568 int httpSetMessTime(const char *timeStr)
569 {
570   unsigned int time;
571
572   if (stringToInt(&time, timeStr) < 0)
573   {
574     error("invalid timeout: %s\n", timeStr);
575     return -1;
576   }
577
578   if (time > 365 * 86400)
579   {
580     error("invalid timeout: %u\n", time);
581     return -1;
582   }
583
584   confMessTime = time;
585
586   return 0;
587 }
588
589 int httpSetMessLimit(const char *limitStr)
590 {
591   unsigned int limit;
592
593   if (stringToInt(&limit, limitStr) < 0)
594   {
595     error("invalid limit: %s\n", limitStr);
596     return -1;
597   }
598
599   if (limit > 1000000)
600   {
601     error("invalid limit: %u\n", limit);
602     return -1;
603   }
604
605   confMessLimit = limit;
606
607   return 0;
608 }
609
610 int httpSetup(void)
611 {
612   int i;
613
614   if (createMainSocket(&confAddr, confPort) < 0)
615   {
616     error("cannot create main socket\n");
617     return -1;
618   }
619
620   numConn = 0;
621
622   for (i = 0; i < MAX_CONN; i++)
623     conn[i] = NULL;
624
625   numSess = 0;
626
627   for (i = 0; i < MAX_SESS; i++)
628     sess[i] = NULL;
629
630   firstTasMsg = NULL;
631   lastTasMsg = NULL;
632
633   numTasMsg = 0;
634
635   return 0;
636 }
637
638 static int readConn(struct connInfo *info)
639 {
640   struct inOutBuff *read = &info->read;
641   int readLen;
642   struct chunk *chunk;
643
644   for (;;)
645   {
646     if (read->last == NULL || read->len == CHUNK_SIZE)
647     {
648       chunk = allocMem(sizeof (struct chunk));
649
650       chunk->next = NULL;
651
652       if (read->last != NULL)
653         read->last->next = chunk;
654
655       read->last = chunk;
656
657       if (read->first == NULL)
658         read->first = chunk;
659
660       read->len = 0;
661     }
662
663     readLen = readFileOs(info->sockId, &read->last->data[read->len],
664                          CHUNK_SIZE - read->len);
665
666     if (readLen < 0)
667     {
668       error("cannot read from network connection\n");
669       return -1;
670     }
671
672     debug(DEBUG_CONNECTION, "read %d bytes from connection\n", readLen);
673
674     if (readLen == 0)
675       return 0;
676
677     read->len += readLen;
678     read->cont += readLen;
679   }
680 }
681
682 void writeBuff(struct inOutBuff *write, const unsigned char *data, int dataLen)
683 {
684   int writeLen;
685   struct chunk *chunk;
686
687   while (dataLen > 0)
688   {
689     if (write->last == NULL || write->len == CHUNK_SIZE)
690     {
691       chunk = allocMem(sizeof (struct chunk));
692
693       chunk->next = NULL;
694
695       if (write->last != NULL)
696         write->last->next = chunk;
697
698       write->last = chunk;
699
700       if (write->first == NULL)
701         write->first = chunk;
702
703       write->len = 0;
704     }
705
706     writeLen = CHUNK_SIZE - write->len;
707
708     if (dataLen < writeLen)
709       writeLen = dataLen;
710
711     memcpy(&write->last->data[write->len], data, writeLen);
712
713     write->len += writeLen;
714     write->cont += writeLen;
715
716     dataLen -= writeLen;
717     data += writeLen;
718   }
719 }
720
721 static int lineLength(const struct inOutBuff *read)
722 {
723   struct chunk *chunk;
724   int idx, len, off;
725   int count;
726
727   count = 0;
728
729   for (chunk = read->first; chunk != NULL; chunk = chunk->next)
730   {
731     len = (chunk == read->last) ? read->len : CHUNK_SIZE;
732     off = (chunk == read->first) ? read->off : 0;
733
734     for (idx = off; idx < len; idx++)
735     {
736       count++;
737
738       if (chunk->data[idx] == 10)
739         return count;
740     }
741   }
742
743   return -1;
744 }
745
746 static int readBuff(struct inOutBuff *read, unsigned char *data, int dataLen)
747 {
748   int readLen;
749   struct chunk *chunk;
750   int len;
751
752   while (dataLen > 0)
753   {
754     if (read->first == NULL)
755       return -1;
756
757     len = (read->first == read->last) ? read->len : CHUNK_SIZE;
758
759     readLen = len - read->off;
760
761     if (dataLen < readLen)
762       readLen = dataLen;
763
764     memcpy(data, &read->first->data[read->off], readLen);
765
766     read->off += readLen;
767     read->cont -= readLen;
768
769     dataLen -= readLen;
770     data += readLen;
771
772     if (read->off == len)
773     {
774       chunk = read->first;
775
776       read->first = chunk->next;
777
778       if (read->first == NULL)
779         read->last = NULL;
780
781       freeMem(chunk);
782
783       read->off = 0;
784     }
785   }
786
787   return 0;
788 }
789
790 static int writeConn(struct connInfo *info)
791 {
792   struct inOutBuff *write = &info->write[info->which];
793   int writeLen;
794   struct chunk *chunk;
795   int len;
796
797   for (;;)
798   {
799     if (write->first == NULL)
800       return 0;
801
802     len = (write->first == write->last) ? write->len : CHUNK_SIZE;
803
804     writeLen = writeFileOs(info->sockId, &write->first->data[write->off],
805                            len - write->off);
806
807     if (writeLen < 0)
808     {
809       error("cannot write to network connection\n");
810       return -1;
811     }
812
813     debug(DEBUG_CONNECTION, "wrote %d bytes to connection\n", writeLen);
814
815     if (writeLen == 0)
816       return 0;
817
818     write->off += writeLen;
819     write->cont -= writeLen;
820
821     if (write->off == len)
822     {
823       chunk = write->first;
824
825       write->first = chunk->next;
826
827       if (write->first == NULL)
828         write->last = NULL;
829
830       freeMem(chunk);
831
832       write->off = 0;
833     }
834   }
835 }
836
837 static char *getToken(char **point)
838 {
839   char *localPoint = *point;
840   char *start;
841
842   while (*localPoint == 9 || *localPoint == 32)
843     localPoint++;
844
845   start = localPoint;
846
847   while (*localPoint != 9 && *localPoint != 32 && *localPoint != 0)
848     localPoint++;
849
850   if (localPoint == start)
851     return NULL;
852
853   if (*localPoint != 0)
854     *localPoint++ = 0;
855
856   *point = localPoint;
857
858   return start;
859 }
860
861 static void writeBuffString(struct inOutBuff *write, const char *string)
862 {
863   writeBuff(write, string, strlen(string));
864 }
865
866 static int cookieToSession(unsigned int *sessId, char *cookie)
867 {
868   unsigned char mac1[16];
869   unsigned char mac2[16];
870
871   debug(DEBUG_SESSION, "cookie = %s\n", cookie);
872
873   if (decHexString((unsigned char *)&cookieStruct.sessId, cookie, 4) < 0)
874   {
875     debug(DEBUG_SESSION, "cannot decode session id\n");
876     return -1;
877   }
878
879   if (decHexString(mac1, cookie + 8, 16) < 0)
880   {
881     debug(DEBUG_SESSION, "cannot decode authenticator\n");
882     return -1;
883   }
884
885   memset(mac2, 0, 16);
886   rc4(mac2, 16, (unsigned char *)&cookieStruct, sizeof (cookieStruct));
887
888   if (memcmp(mac1, mac2, 16) != 0)
889   {
890     debug(DEBUG_SESSION, "invalid authenticator\n");
891     return -1;
892   }
893
894   *sessId = cookieStruct.sessId;
895
896   debug(DEBUG_SESSION, "session id = %u\n", *sessId);
897
898   return 0;
899 }
900
901 static char *sessionToCookie(unsigned int sessId)
902 {
903   unsigned char mac[16];
904   static char buff[41];
905
906   debug(DEBUG_SESSION, "session id = %u\n", sessId);
907
908   cookieStruct.sessId = sessId;
909
910   memset(mac, 0, 16);
911   rc4(mac, 16, (unsigned char *)&cookieStruct, sizeof (cookieStruct));
912
913   encHexString(buff, (unsigned char *)&cookieStruct.sessId, 4);
914   encHexString(buff + 8, mac, 16);
915
916   debug(DEBUG_SESSION, "cookie = %s\n", buff);
917
918   return buff;
919 }
920
921 static void writeBuffInt(struct inOutBuff *write, unsigned int val)
922 {
923   char buff[10];
924
925   writeBuffString(write, intToString(buff, val));
926 }
927
928 static void printBuff(struct inOutBuff *buff, const char *form, ...)
929 {
930   int i = 0;
931   int start = 0;
932   char *strVal;
933   int intVal;
934
935   va_list args;
936
937   va_start(args, form);
938
939   for (;;)
940   {
941     start = i;
942
943     while (form[i] != '%' && form[i] != 0)
944       i++;
945
946     if (i > start)
947       writeBuff(buff, form + start, i - start);
948
949     if (form[i] == 0)
950       break;
951
952     if (form[i + 1] == '%')
953       writeBuff(buff, "%", 1);
954
955     else if (form[i + 1] == 's')
956     {
957       strVal = va_arg(args, char *);
958       writeBuffString(buff, strVal);
959     }
960
961     else if (form[i + 1] == 'd')
962     {
963       intVal = va_arg(args, int);
964       writeBuffInt(buff, intVal);
965     }
966
967     i += 2;
968   }
969
970   va_end(args);
971 }
972
973 static char *errNoToErrStr(int errNo)
974 {
975   switch (errNo)
976   {
977   case 200:
978     return "OK";
979
980   case 400:
981     return "Bad Request";
982
983   case 401:
984     return "Unauthorized";
985
986   case 404:
987     return "Not Found";
988
989   case 500:
990     return "Internal Server Error";
991
992   case 501:
993     return "Not Implemented";
994
995   case 505:
996     return "HTTP Version Not Supported";
997
998   default:
999     return "For No Reason";
1000   }
1001 }
1002
1003 static int writeHeaders(struct connInfo *info, int errNo)
1004 {
1005   printBuff(&info->write[0], "HTTP/1.1 %d %s\r\n", errNo,
1006             errNoToErrStr(errNo));
1007
1008   printBuff(&info->write[0], "Server: TAS/0.1\r\n");
1009
1010   if (info->contType != NULL)
1011     printBuff(&info->write[0], "Content-Type: %s\r\n", info->contType);
1012
1013   if (info->contLen >= 0)
1014     printBuff(&info->write[0], "Content-Length: %d\r\n", info->contLen);
1015
1016   if (info->newSess != NULL)
1017     printBuff(&info->write[0], "Set-Cookie: %s\r\n", sessionToCookie(info->newSess->id));
1018
1019   if (errNo == 401)
1020     printBuff(&info->write[0], "WWW-Authenticate: Basic realm=\"TAS\"\r\n");
1021
1022   printBuff(&info->write[0], "Accept-Ranges: none\r\n");
1023   printBuff(&info->write[0], "Connection: close\r\n");
1024
1025   printBuff(&info->write[0], "Expires: Thu, 01 Jan 1970 00:00:00 GMT\r\n");
1026   printBuff(&info->write[0], "Cache-Control: no-cache\r\n");
1027   printBuff(&info->write[0], "Pragma: No-cache\r\n");
1028
1029   printBuff(&info->write[1], "\r\n");
1030
1031   return 0;
1032 }
1033
1034 static void writeErrorMsg(struct connInfo *info, int errNo, char *errMsg)
1035 {
1036   if (info->verb == NULL || strcmp(info->verb, "HEAD") != 0)
1037   {
1038     printBuff(&info->write[2], "<html>\r\n");
1039     printBuff(&info->write[2], "<head><title>Error %d: %s</title></head>\r\n",
1040               errNo, errNoToErrStr(errNo));
1041     printBuff(&info->write[2], "<body>Error %d: %s (%s)</body>\r\n", errNo,
1042               errNoToErrStr(errNo),
1043               (errMsg == NULL) ? "Unknown Reason" : errMsg);
1044     printBuff(&info->write[2], "</html>\r\n");
1045
1046     info->contLen = info->write[2].cont;
1047   }
1048
1049   writeHeaders(info, errNo);
1050
1051   info->state = STATE_DRAIN;
1052 }
1053
1054 static void writeError(struct connInfo *info, int errNo)
1055 {
1056   writeErrorMsg(info, errNo, NULL);
1057 }
1058
1059 static void toLower(char *string)
1060 {
1061   while (*string != 0)
1062   {
1063     if (*string >= 'A' && *string <= 'Z')
1064       *string += 32;
1065
1066     string++;
1067   }
1068 }
1069
1070 static void unescape(char *string)
1071 {
1072   int i, k, val;
1073
1074   debug(DEBUG_REQUEST | DEBUG_LUA, "unescaped string = %s\n", string);
1075
1076   k = 0;
1077
1078   for (i = 0; string[i] != 0; i++)
1079   {
1080     if (string[i] == '%' && string[i + 1] != 0 && string[i + 2] != 0)
1081     {
1082       val = 0;
1083
1084       if (addHexDigit(&val, string[i + 1]) >= 0 &&
1085           addHexDigit(&val, string[i + 2]) >= 0)
1086       {
1087         string[k++] = (char)val;
1088         i += 2;
1089         continue;
1090       }
1091     }
1092
1093     string[k++] = string[i];
1094   }
1095
1096   string[k] = 0;
1097
1098   debug(DEBUG_REQUEST | DEBUG_LUA, "escaped string = %s\n", string);
1099 }
1100
1101 static int serviceConn(struct connInfo *info)
1102 {
1103   int i, k, len, len2;
1104   char *line, *tmp, *tmp2;
1105   struct httpHeader *head;
1106   unsigned char fileBuff[8192];
1107   char **argList;
1108   char *errMsg;
1109   unsigned int sessId;
1110   struct sessInfo *currSess;
1111   int pub;
1112
1113   switch (info->state)
1114   {
1115   case STATE_REQUEST:
1116     debug(DEBUG_CONNECTION, "connection state is STATE_REQUEST\n");
1117
1118     len = lineLength(&info->read);
1119
1120     if (len <= 0)
1121       return 0;
1122
1123     line = allocBuff(info, len);
1124
1125     readBuff(&info->read, line, len);
1126     chomp(line, len);
1127
1128     debug(DEBUG_REQUEST, "request line is '%s'\n", line);
1129
1130     info->verb = getToken(&line);
1131     tmp = getToken(&line);
1132     info->proto = getToken(&line);
1133
1134     debug(DEBUG_REQUEST, "verb = %s, uri = %s, protocol = %s\n",
1135           (info->verb == NULL) ? "none" : info->verb,
1136           (tmp == NULL) ? "none" : tmp,
1137           (info->proto == NULL) ? "none" : info->proto);
1138
1139     if (info->verb == NULL || tmp == NULL || info->proto == NULL)
1140     {
1141       error("request without verb (%s), URI (%s), or protocol (%s)\n",
1142             (info->verb == NULL) ? "none" : info->verb,
1143             (tmp == NULL) ? "none" : tmp,
1144             (info->proto == NULL) ? "none" : info->proto);
1145       writeError(info, 400);
1146       return 0;
1147     }
1148
1149     if (strcmp(info->verb, "GET") != 0 && strcmp(info->verb, "HEAD") != 0)
1150     {
1151       error("unsupported verb: %s\n", info->verb);
1152       writeError(info, 501);
1153       return 0;
1154     }
1155
1156     if (strcmp(info->proto, "HTTP/1.1") != 0)
1157     {
1158       error("unsupported protocol version: %s\n", info->proto);
1159       writeError(info, 505);
1160       return 0;
1161     }
1162
1163     if (strncmp(tmp, "http://", 7) == 0)
1164     {
1165       tmp += 7;
1166
1167       info->host = tmp;
1168
1169       while (*tmp != ':' && *tmp != '/' && *tmp != 0)
1170         tmp++;
1171
1172       if (*tmp == 0)
1173       {
1174         error("URI host part does not end in ':' or '/'\n");
1175         writeError(info, 400);
1176         return 0;
1177       }
1178
1179       if (*tmp == ':')
1180       {
1181         *tmp++ = 0;
1182
1183         while (*tmp != '/' && *tmp != 0)
1184           tmp++;
1185
1186         if (*tmp == 0)
1187         {
1188           error("URI port part does not end in '/'\n");
1189           writeError(info, 400);
1190           return 0;
1191         }
1192
1193         tmp++;
1194       }
1195
1196       else
1197         *tmp++ = 0;
1198
1199       debug(DEBUG_REQUEST, "host = %s\n", info->host);
1200
1201       info->path = tmp;
1202     }
1203
1204     else if (tmp[0] == '/')
1205       info->path = ++tmp;
1206
1207     else
1208     {
1209       error("URI path part is not an absolute path\n");
1210       writeError(info, 400);
1211       return 0;
1212     }
1213
1214     while (*tmp != '?' && *tmp != 0)
1215     {
1216       if (tmp[0] == '.' && tmp[1] == '.')
1217       {
1218         error("URI path part contains '..'\n");
1219         writeError(info, 400);
1220         return 0;
1221       }
1222
1223       tmp++;
1224     }
1225
1226     if (*tmp == '?')
1227     {
1228       *tmp++ = 0;
1229       info->para = tmp;
1230     }
1231
1232     debug(DEBUG_REQUEST, "path = %s, parameters = %s\n", info->path,
1233           (info->para == NULL) ? "none" : info->para);
1234
1235     info->state = STATE_HEADERS;
1236     return 0;
1237
1238   case STATE_HEADERS:
1239     debug(DEBUG_CONNECTION, "connection state is STATE_HEADERS\n");
1240
1241     len = lineLength(&info->read);
1242
1243     if (len <= 0)
1244       return 0;
1245
1246     line = allocBuff(info, len);
1247
1248     readBuff(&info->read, line, len);
1249     chomp(line, len);
1250
1251     debug(DEBUG_REQUEST, "header line is '%s'\n", line);
1252
1253     if (*line == 0)
1254     {
1255       if (info->host == NULL)
1256         for (head = info->firstHead; head != NULL; head = head->next)
1257           if (strcmp(head->name, "host") == 0)
1258             info->host = head->value;
1259
1260       debug(DEBUG_REQUEST, "last header line, host = %s\n",
1261             (info->host == NULL) ? "none" : info->host);
1262
1263       info->state = STATE_RESPONSE;
1264       return 0;
1265     }
1266
1267     if (*line == 9 || *line == 32)
1268     {
1269       debug(DEBUG_REQUEST, "continued header line\n");
1270       
1271       if (info->lastHead == NULL)
1272       {
1273         error("no previous header to continue\n");
1274         writeError(info, 400);
1275         return 0;
1276       }
1277
1278       len2 = strlen(info->lastHead->value);
1279
1280       tmp = allocBuff(info, len2 + len);
1281
1282       memcpy(tmp, info->lastHead->value, len2);
1283       memcpy(tmp + len2, line, len);
1284
1285       info->lastHead->value = tmp;
1286
1287       debug(DEBUG_REQUEST, "updated header, name = %s, value = '%s'\n",
1288             info->lastHead->name, info->lastHead->value);
1289     }
1290
1291     else
1292     {
1293       tmp = getToken(&line);
1294
1295       if (tmp == NULL)
1296       {
1297         error("header without name\n");
1298         writeError(info, 400);
1299         return 0;
1300       }
1301
1302       for (i = 0; tmp[i] != ':' && tmp[i] != 0; i++);
1303
1304       if (tmp[i] != ':' || tmp[i + 1] != 0)
1305       {
1306         error("header name does not end in ':'\n");
1307         writeError(info, 400);
1308         return 0;
1309       }
1310
1311       tmp[i] = 0;
1312
1313       toLower(tmp);
1314
1315       head = allocBuff(info, sizeof (struct httpHeader));
1316
1317       head->next = NULL;
1318       head->name = tmp;
1319       head->value = line;
1320
1321       if (info->lastHead == NULL)
1322         info->firstHead = head;
1323
1324       else
1325         info->lastHead->next = head;
1326
1327       info->lastHead = head;
1328
1329       debug(DEBUG_REQUEST, "new header, name = %s, value = '%s'\n",
1330             info->lastHead->name, info->lastHead->value);
1331     }
1332
1333     return 0;
1334
1335   case STATE_RESPONSE:
1336     debug(DEBUG_CONNECTION, "connection state is STATE_RESPONSE\n");
1337
1338     unescape(info->path);
1339
1340     len = strlen(confPubDir);
1341
1342     pub = (len > 0 && strncmp(info->path, confPubDir, len) == 0 &&
1343            (info->path[len] == 0 || info->path[len] == '/'));
1344
1345     debug(DEBUG_REQUEST, "%s path\n", (pub == 0) ? "protected" : "public");
1346
1347     if (pub == 0 && (confUser != NULL || confPassword != NULL))
1348     {
1349       debug(DEBUG_REQUEST, "authentication required\n");
1350
1351       for (head = info->firstHead; head != NULL; head = head->next)
1352         if (memcmp(head->name, "authorization", 14) == 0)
1353           break;
1354
1355       if (head == NULL)
1356       {
1357         debug(DEBUG_REQUEST, "no authorization header present\n");
1358
1359         writeError(info, 401);
1360         return 0;
1361       }
1362
1363       tmp = getToken(&head->value);
1364
1365       if (tmp == NULL || strcmp(tmp, "Basic") != 0)
1366       {
1367         error("\"Basic\" authorization info expected\n");
1368         writeError(info, 401);
1369         return 0;
1370       }
1371
1372       tmp = getToken(&head->value);
1373
1374       if (tmp == NULL)
1375       {
1376         error("authorization info lacks base-64 encoded data\n");
1377         writeError(info, 401);
1378         return 0;
1379       }
1380
1381       tmp2 = allocBuff(info, strlen(tmp) * 3 / 4 + 1);
1382
1383       if (decBase64(tmp2, tmp) < 0)
1384       {
1385         error("base-64 decode failed\n");
1386         writeError(info, 401);
1387         return 0;
1388       }
1389
1390       for (i = 0; tmp2[i] != ':' && tmp2[i] != 0; i++);
1391
1392       if (tmp2[i] == 0)
1393       {
1394         error("authorization info lacks ':'\n");
1395         writeError(info, 401);
1396         return 0;
1397       }
1398
1399       tmp2[i++] = 0;
1400
1401       debug(DEBUG_REQUEST, "user = %s, password = %s\n", tmp2, tmp2 + i);
1402
1403       if ((confUser != NULL && strcmp(confUser, tmp2) != 0) ||
1404           (confPassword != NULL && strcmp(confPassword, tmp2 + i) != 0))
1405       {
1406         error("user authentication failed\n");
1407         writeError(info, 401);
1408         return 0;
1409       }     
1410     }
1411
1412     if (isDirectory(confRootDir, info->path) > 0)
1413     {
1414       debug(DEBUG_REQUEST, "path is a directory\n");
1415
1416       tmp = fullPath(info->path, confIndexFile);
1417
1418       debug(DEBUG_REQUEST, "updated path = %s\n", tmp);
1419
1420       info->path = allocBuff(info, strlen(tmp) + 1);
1421       strcpy(info->path, tmp);
1422
1423       freeMem(tmp);
1424     }
1425
1426     if (openFile(&info->fileId, confRootDir, info->path) < 0)
1427     {
1428       error("cannot find resource %s in root directory %s\n", info->path,
1429             confRootDir);
1430       writeError(info, 404);
1431       return 0;
1432     }
1433
1434     for (i = 0; extMap[i].ext != NULL; i++)
1435     {
1436       len = strlen(extMap[i].ext);
1437       len2 = strlen(info->path);
1438
1439       if (len2 >= len &&
1440           memcmp(info->path + len2 - len, extMap[i].ext, len) == 0)
1441         break;      
1442     }
1443
1444     if (extMap[i].ext != NULL)
1445     {
1446       info->state = extMap[i].state;
1447       info->contType = extMap[i].type;
1448
1449       debug(DEBUG_REQUEST,
1450             "extension recognized, next state = %d, content type = %s\n",
1451             info->state, info->contType);
1452     }
1453
1454     else
1455       info->state = STATE_FILE;
1456
1457     if (strcmp(info->verb, "HEAD") == 0)
1458     {
1459       closeFile(&info->fileId);
1460
1461       writeHeaders(info, 200);
1462
1463       info->state = STATE_DRAIN;
1464     }
1465
1466     return 0;
1467
1468   case STATE_FILE:
1469     debug(DEBUG_CONNECTION, "connection state is STATE_FILE\n");
1470
1471     for (;;)
1472     {
1473       len = readFileOs(&info->fileId, fileBuff, sizeof (fileBuff));
1474
1475       debug(DEBUG_CONNECTION, "read %d bytes from file\n", len);
1476
1477       if (len <= 0)
1478       {
1479         if (len < 0)
1480         {
1481           closeFile(&info->fileId);
1482
1483           info->contLen = info->write[2].cont;
1484           writeHeaders(info, 200);
1485
1486           info->state = STATE_DRAIN;
1487         }
1488
1489         break;
1490       }
1491
1492       writeBuff(&info->write[2], fileBuff, len);
1493     }
1494     
1495     return 0;
1496
1497   case STATE_LSP:
1498     debug(DEBUG_CONNECTION, "connection state is STATE_LSP\n");
1499
1500     tmp = allocBuff(info, strlen(info->path) + 4 + 1);
1501     setExtension(tmp, info->path, ".lua");
1502
1503     debug(DEBUG_LUA, "lua file name = %s\n", tmp);
1504
1505     if (lspToLua(confRootDir, info->path, confWorkDir, tmp) < 0)
1506     {
1507       error("cannot transform %s into %s\n", info->path, tmp);
1508       writeError(info, 500);
1509       return 0;
1510     }
1511
1512     tmp2 = allocBuff(info, strlen(info->path) + 4 + 1);
1513     setExtension(tmp2, info->path, ".lex");
1514
1515     debug(DEBUG_LUA, "lex file name = %s\n", tmp2);
1516
1517     if (luaToLex(&errMsg, confWorkDir, tmp, tmp2) < 0)
1518     {
1519       error("cannot transform %s into %s\n", tmp, tmp2);
1520       writeErrorMsg(info, 500, errMsg);
1521
1522       if (errMsg != NULL)
1523         freeMem(errMsg);
1524
1525       return 0;
1526     }
1527
1528     tmp = info->para;
1529
1530     if (tmp != NULL)
1531     {
1532       len = 3 * sizeof (char *);
1533
1534       for (i = 0; tmp[i] != 0; i++)
1535       {
1536         if (tmp[i] == '+')
1537           tmp[i] = ' ';
1538
1539         if (tmp[i] == '=' || tmp[i] == '&')
1540           len += sizeof (char *);
1541       }
1542
1543       argList = allocBuff(info, len);
1544
1545       i = 0;
1546       k = 0;
1547
1548       while (tmp[i] != 0)
1549       {
1550         argList[k++] = tmp + i;
1551
1552         while (tmp[i] != 0 && tmp[i] != '=')
1553           i++;
1554
1555         if (tmp[i] == 0)
1556         {
1557           error("end of parameters while looking for '='\n");
1558           writeError(info, 400);
1559           return 0;
1560         }
1561
1562         tmp[i++] = 0;
1563
1564         debug(DEBUG_LUA, "parameter name = '%s'\n", argList[k - 1]);
1565
1566         argList[k++] = tmp + i;
1567
1568         while (tmp[i] != 0 && tmp[i] != '&')
1569           i++;
1570
1571         if (tmp[i] != 0)
1572           tmp[i++] = 0;
1573
1574         debug(DEBUG_LUA, "parameter value = '%s'\n", argList[k - 1]);
1575       }
1576
1577       for (i = 0; i < k; i++)
1578         unescape(argList[i]);
1579
1580       argList[k++] = NULL;
1581       argList[k++] = NULL;
1582     }
1583
1584     else
1585       argList = NULL;
1586
1587     currSess = NULL;
1588
1589     for (head = info->firstHead; head != NULL; head = head->next)
1590       if (memcmp(head->name, "cookie", 7) == 0)
1591         break;
1592
1593     if (head != NULL && cookieToSession(&sessId, head->value) >= 0)
1594     {
1595       debug(DEBUG_SESSION, "looking for existing session\n");
1596
1597       for (i = 0; i < numSess && sess[i]->id != sessId; i++);
1598
1599       if (i < numSess)
1600       {
1601         debug(DEBUG_SESSION, "existing session found\n");
1602
1603         currSess = sess[i];
1604       }
1605     }
1606
1607     if (currSess == NULL)
1608     {
1609       debug(DEBUG_SESSION, "no existing session\n");
1610
1611       info->newSess = newSessInfo();
1612       currSess = info->newSess;
1613     }
1614
1615     if (runLua(&errMsg, info, confWorkDir, tmp2, argList, &currSess->data) < 0)
1616     {
1617       error("cannot run %s\n", tmp2);
1618
1619       if (info->newSess != NULL)
1620       {
1621         debug(DEBUG_SESSION, "cleaning up newly created session\n");
1622
1623         if (info->newSess->data != NULL)
1624         {
1625           debug(DEBUG_SESSION, "freeing lua context\n");
1626         
1627           freeLuaSession(info->newSess->data);
1628         }
1629
1630         freeMem(info->newSess);
1631         info->newSess = NULL;
1632       }
1633
1634       debug(DEBUG_SESSION, "purging io buffer\n");
1635         
1636       freeInOutBuff(&info->write[1]);
1637       freeInOutBuff(&info->write[2]);
1638
1639       initInOutBuff(&info->write[1]);
1640       initInOutBuff(&info->write[2]);
1641
1642       writeErrorMsg(info, 500, errMsg);
1643
1644       if (errMsg != NULL)
1645         freeMem(errMsg);
1646
1647       return 0;
1648     }
1649
1650     debug(DEBUG_SESSION, "lua code successfully executed\n");
1651
1652     if (info->newSess != NULL)
1653     {
1654       if (info->newSess->data == NULL)
1655       {
1656         debug(DEBUG_SESSION, "no session required\n");
1657
1658         freeMem(info->newSess);
1659         info->newSess = NULL;
1660       }
1661
1662       else
1663       {
1664         if (numSess == MAX_SESS)
1665         {
1666           error("session limit reached, deleting least recently used session %d\n",
1667                 sess[0]->id);
1668           freeLuaSession(sess[0]->data);
1669           freeMem(sess[0]);
1670
1671           for (i = 0; i < MAX_SESS - 1; i++)
1672             sess[i] = sess[i + 1];
1673
1674           numSess--;
1675         }
1676
1677         sess[numSess++] = info->newSess;
1678
1679         debug(DEBUG_SESSION, "session added\n");
1680       }
1681     }
1682
1683     else
1684     {
1685       debug(DEBUG_SESSION, "aging sessions\n");
1686
1687       for (i = 0; sess[i]->id != currSess->id; i++);
1688
1689       while (i < numSess - 1)
1690       {
1691         sess[i] = sess[i + 1];
1692         i++;
1693       }
1694
1695       if (currSess->data == NULL)
1696       {
1697         debug(DEBUG_SESSION, "session not required any longer\n");
1698
1699         sess[i] = NULL;
1700         freeMem(currSess);
1701
1702         numSess--;
1703       }
1704
1705       else
1706       {
1707         debug(DEBUG_SESSION, "session stored\n");
1708
1709         sess[i] = currSess;
1710       }
1711     }
1712
1713     info->contLen = info->write[2].cont;
1714     writeHeaders(info, 200);
1715
1716     info->state = STATE_DRAIN;
1717     return 0;
1718
1719   case STATE_DRAIN:
1720     debug(DEBUG_CONNECTION, "connection state is STATE_DRAIN\n");
1721     debug(DEBUG_CONNECTION, "which = %d\n", info->which);
1722
1723     if (info->write[info->which].first == NULL)
1724       info->which++;
1725
1726     if (info->which == 3)
1727       return -1;
1728
1729     return 0;
1730   }
1731
1732   return 0;
1733 }
1734
1735 int httpService(int freq)
1736 {
1737   struct fileId *sockId;
1738   struct ipAddr *addr;
1739   int i, k;
1740 #ifdef TAS_BLOCK
1741   struct fileId *waitIds[MAX_CONN];
1742   int *waitFlags[MAX_CONN];
1743 #endif
1744   unsigned int micro, microLimit;
1745   struct tasMessage *tasMsg;
1746
1747   micro = getMicro();
1748
1749 #ifdef TAS_BLOCK
1750   for (i = 0; i < numConn; i++)
1751   {
1752     waitIds[i] = conn[i]->sockId;
1753     waitFlags[i] = &conn[i]->flags;
1754
1755     conn[i]->flags = FLAG_READ;
1756
1757     if (conn[i]->firstWrite != NULL)
1758       conn[i]->flags |= FLAG_WRITE;
1759   }
1760
1761   if (waitForSockets(waitIds, waitFlags, numConn) < 0)
1762     return 0;
1763 #endif
1764
1765   while (numConn < MAX_CONN)
1766   {
1767     if (acceptConn(&sockId, &addr) < 0)
1768       break;
1769
1770     conn[numConn++] = newConnInfo(sockId, addr);
1771   }
1772
1773   i = 0;
1774
1775   while (i < numConn)
1776   {
1777     if (((conn[i]->flags & FLAG_READ) != 0 && readConn(conn[i]) < 0) ||
1778         ((conn[i]->flags & FLAG_WRITE) != 0 && writeConn(conn[i]) < 0) ||
1779         serviceConn(conn[i]) < 0)
1780     {
1781       closeFile(conn[i]->sockId);
1782
1783       freeConnInfo(conn[i]);
1784
1785       for (k = i; k < numConn - 1; k++)
1786         conn[k] = conn[k + 1];
1787
1788       conn[k] = NULL;
1789
1790       numConn--;
1791     }
1792
1793     else
1794       i++;
1795   }
1796
1797   while (numSess > 0 && confSessTime > 0 &&
1798          timedOut(&sess[0]->time, confSessTime) >= 0)
1799   {
1800     error("session %d timed out\n", sess[0]->id);
1801
1802     freeLuaSession(sess[0]->data);
1803
1804     freeMem(sess[0]);
1805
1806     for (i = 0; i < numSess - 1; i++)
1807       sess[i] = sess[i + 1];
1808
1809     numSess--;
1810
1811     debug(DEBUG_SESSION, "%d sessions left\n", numSess);
1812   }
1813
1814   while (numTasMsg > 0 && confMessTime > 0 &&
1815          timedOut(&firstTasMsg->time, confMessTime) >= 0)
1816   {
1817     tasMsg = firstTasMsg;
1818
1819     debug(DEBUG_MESSAGE,
1820           "message timed out, service ='%s', string = '%s', from = %s\n",
1821           tasMsg->service, tasMsg->string, tasMsg->from);
1822     
1823     firstTasMsg = firstTasMsg->next;
1824
1825     if (lastTasMsg == tasMsg)
1826       lastTasMsg = NULL;
1827
1828     freeMem(tasMsg->service);
1829     freeMem(tasMsg->string);
1830     freeMem(tasMsg->from);
1831     freeMem(tasMsg);
1832
1833     numTasMsg--;
1834
1835     debug(DEBUG_MESSAGE, "%d messages left\n", numTasMsg);
1836   }
1837
1838   micro = getMicro() - micro;
1839   microLimit = (10000 * confQuantum) / freq;
1840
1841   debug(DEBUG_QUANTUM, "service time = %u us, limit = %u us\n",
1842         micro, microLimit);
1843
1844   if (microLimit > 0 && micro > microLimit)
1845     error("service took longer than expected (%u us, limit is %u us)\n",
1846           micro, microLimit);
1847
1848   return 0;
1849 }
1850
1851 void httpShutdown(void)
1852 {
1853   closeMainSocket();
1854 }
1855
1856 void httpAddTasMessage(const char *service, const char *string,
1857                        const char *from)
1858 {
1859   struct tasMessage *msg;
1860
1861   debug(DEBUG_MESSAGE, "adding message, service = %s, string = %s, from = %s\n",
1862         service, string, from);
1863
1864   msg = allocMem(sizeof (struct tasMessage));
1865
1866   msg->next = NULL;
1867
1868   now(&msg->time);
1869
1870   msg->service = myStrdup(service);
1871   msg->string = myStrdup(string);
1872   msg->from = myStrdup(from);
1873   
1874   if (lastTasMsg != NULL)
1875     lastTasMsg->next = msg;
1876
1877   else
1878     firstTasMsg = msg;
1879
1880   lastTasMsg = msg;
1881
1882   numTasMsg++;
1883
1884   debug(DEBUG_MESSAGE, "new number of messages: %d\n", numTasMsg);
1885   debug(DEBUG_MESSAGE, "limiting message queue length\n");
1886
1887   while (confMessLimit > 0 && numTasMsg > confMessLimit)
1888   {
1889     msg = firstTasMsg;
1890
1891     debug(DEBUG_MESSAGE,
1892           "message removed, service ='%s', string = '%s', from = %s\n",
1893           msg->service, msg->string, msg->from);
1894     
1895     firstTasMsg = firstTasMsg->next;
1896
1897     if (lastTasMsg == msg)
1898       lastTasMsg = NULL;
1899
1900     freeMem(msg->service);
1901     freeMem(msg->string);
1902     freeMem(msg->from);
1903     freeMem(msg);
1904
1905     numTasMsg--;
1906   }
1907
1908   debug(DEBUG_MESSAGE, "%d messages left\n", numTasMsg);
1909 }
1910
1911 int httpGetTasMessage(const char *service, char **string, char **from)
1912 {
1913   struct tasMessage *msg, *prevMsg;
1914
1915   debug(DEBUG_MESSAGE, "getting message, service = %s\n", service);
1916
1917   prevMsg = NULL;
1918
1919   debug(DEBUG_MESSAGE, "walking through message queue\n");
1920
1921   for (msg = firstTasMsg; msg != NULL; msg = msg->next)
1922   {
1923     debug(DEBUG_MESSAGE, "  service = %s, string = %s\n",
1924           msg->service, msg->string);
1925
1926     if (strcmp(msg->service, service) == 0)
1927       break;
1928
1929     prevMsg = msg;
1930   }
1931
1932   debug(DEBUG_MESSAGE, "walk finished\n");
1933
1934   if (msg == NULL)
1935   {
1936     debug(DEBUG_MESSAGE, "no message found\n");
1937
1938     return -1;
1939   }
1940
1941   if (msg == firstTasMsg)
1942     firstTasMsg = msg->next;
1943
1944   else
1945     prevMsg->next = msg->next;
1946
1947   if (msg == lastTasMsg)
1948     lastTasMsg = prevMsg;
1949
1950   *string = msg->string;
1951   *from = msg->from;
1952
1953   freeMem(msg->service);
1954   freeMem(msg);
1955
1956   numTasMsg--;
1957
1958   debug(DEBUG_MESSAGE, "%d messages left\n", numTasMsg);
1959   debug(DEBUG_MESSAGE, "returning '%s' received from %s\n", *string, *from);
1960
1961   return 0;
1962 }