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