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