82f1be97de7c313e79b64f0accbb1080b929d527
[project/luci.git] / libs / httpd / luasrc / httpd.lua
1 --[[
2
3 HTTP server implementation for LuCI - core
4 (c) 2008 Freifunk Leipzig / Jo-Philipp Wich <xm@leipzig.freifunk.net>
5
6 Licensed under the Apache License, Version 2.0 (the "License");
7 you may not use this file except in compliance with the License.
8 You may obtain a copy of the License at
9
10         http://www.apache.org/licenses/LICENSE-2.0
11
12 $Id$
13
14 ]]--
15
16 module("luci.httpd", package.seeall)
17 require("socket")
18 require("luci.util")
19
20 function Socket(ip, port)
21         local sock, err = socket.bind( ip, port )
22
23         if sock then
24                 sock:settimeout( 0, "t" )
25         end
26
27         return sock, err
28 end
29
30
31 Daemon = luci.util.class()
32
33 function Daemon.__init__(self, threadlimit, timeout)
34         self.reading = {}
35         self.running = {}
36         self.handler = {}
37         self.debug   = false
38         self.threadlimit = threadlimit
39         self.timeout = timeout or 0.1
40 end
41
42 function Daemon.dprint(self, msg)
43         if self.debug then
44                 io.stderr:write("[daemon] " .. msg .. "\n")
45         end
46 end
47
48 function Daemon.register(self, sock, clhandler, errhandler)
49         table.insert( self.reading, sock )
50         self.handler[sock] = { clhandler = clhandler, errhandler = errhandler }
51 end
52
53 function Daemon.run(self)
54         while true do
55                 self:step()
56         end
57 end
58
59 function Daemon.step(self)      
60         local input, output, err = socket.select( self.reading, nil, 0 )
61
62         if err == "timeout" and #self.running == 0 then
63                 socket.sleep(self.timeout)
64         end
65
66         -- accept new connections
67         for i, connection in ipairs(input) do
68
69                 local sock = connection:accept()
70
71                 -- check capacity
72                 if not self.threadlimit or #self.running < self.threadlimit then
73
74                         self:dprint("Accepted incoming connection from " .. sock:getpeername())
75
76                         table.insert( self.running, {
77                                 coroutine.create( self.handler[connection].clhandler ),
78                                 sock
79                         } )
80
81                         self:dprint("Created " .. tostring(self.running[#self.running][1]))
82
83                 -- reject client
84                 else
85                         self:dprint("Rejected incoming connection from " .. sock:getpeername())
86
87                         if self.handler[connection].errhandler then
88                                 self.handler[connection].errhandler( sock )
89                         end
90
91                         sock:close()
92                 end
93         end
94
95         -- create client handler
96         for i, client in ipairs( self.running ) do
97
98                 -- reap dead clients
99                 if coroutine.status( client[1] ) == "dead" then
100                         self:dprint("Completed " .. tostring(client[1]))
101                         table.remove( self.running, i )
102                 else
103                         self:dprint("Resuming " .. tostring(client[1]))
104
105                         local stat, err = coroutine.resume( client[1], client[2] )
106
107                         self:dprint(tostring(client[1]) .. " returned")
108
109                         if not stat then
110                                 self:dprint("Error in " .. tostring(client[1]) .. " " .. err)
111                         end
112                 end
113         end
114 end