modules/freifunk: set ipv4 broadcast to 255.255.255.255 by default
[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 (c) 2008 Steven Barth <steven@midlink.org>
6
7 Licensed under the Apache License, Version 2.0 (the "License");
8 you may not use this file except in compliance with the License.
9 You may obtain a copy of the License at
10
11         http://www.apache.org/licenses/LICENSE-2.0
12
13 $Id$
14
15 ]]--
16
17 module("luci.httpd", package.seeall)
18 require("socket")
19
20 THREAD_IDLEWAIT = 0.01
21 THREAD_TIMEOUT  = 90
22 THREAD_LIMIT    = nil
23
24 local reading   = {}
25 local clhandler = {}
26 local erhandler = {}
27
28 local threadc = 0
29 local threads = {}
30 local threadm = {}
31 local threadi = {}
32
33 local _meta = {__mode = "k"}
34 setmetatable(threadm, _meta)
35 setmetatable(threadi, _meta)
36
37
38 function Socket(ip, port)
39         local sock, err = socket.bind( ip, port )
40
41         if sock then
42                 sock:settimeout( 0, "t" )
43         end
44
45         return sock, err
46 end
47
48 function corecv(socket, ...)
49         threadi[socket] = true
50
51         while true do
52                 local chunk, err, part = socket:receive(...)
53
54                 if err ~= "timeout" then
55                         threadi[socket] = false
56                         return chunk, err, part
57                 end
58  
59                 coroutine.yield()
60         end
61 end
62
63 function cosend(socket, chunk, i, ...)
64         threadi[socket] = true
65         i = i or 1
66
67         while true do
68                 local stat, err, sent = socket:send(chunk, i, ...)
69
70                 if err ~= "timeout" then
71                         threadi[socket] = false
72                         return stat, err, sent
73                 else
74                         i = sent and (sent + 1) or i
75                 end
76  
77                 coroutine.yield()
78         end
79 end
80
81 function register(socket, s_clhandler, s_errhandler)
82         table.insert(reading, socket)
83         clhandler[socket] = s_clhandler
84         erhandler[socket] = s_errhandler
85 end
86
87 function run()
88         while true do
89                 step()
90         end
91 end
92
93 function step()
94         local idle = true
95         if not THREAD_LIMIT or threadc < THREAD_LIMIT then
96                 local now = os.time()
97                 for i, server in ipairs(reading) do
98                         local client = server:accept()
99                         if client then
100                                 threadm[client] = now
101                                 threadc = threadc + 1
102                                 threads[client] = coroutine.create(clhandler[server])
103                         end
104                 end
105         end
106         
107         for client, thread in pairs(threads) do
108                 coroutine.resume(thread, client)
109                 local now = os.time()
110                 if coroutine.status(thread) == "dead" then
111                         threadc = threadc - 1
112                         threads[client] = nil
113                 elseif threadm[client] and threadm[client] + THREAD_TIMEOUT < now then
114                         threads[client] = nil
115                         threadc = threadc - 1   
116                         client:close()
117                 elseif not threadi[client] then 
118                         threadm[client] = now
119                         idle = false
120                 end
121         end
122         
123         if idle then
124                 socket.sleep(THREAD_IDLEWAIT)
125         end
126 end