2 LuCI - Lua Development Framework
4 Copyright 2009 Steven Barth <steven@midlink.org>
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
10 http://www.apache.org/licenses/LICENSE-2.0
15 local os = require "os"
16 local nixio = require "nixio"
17 local lucid = require "luci.lucid"
19 local ipairs, type, require, setmetatable = ipairs, type, require, setmetatable
20 local pairs, print, tostring, unpack = pairs, print, tostring, unpack
22 module "luci.lucid.tcpserver"
24 local cursor = lucid.cursor
25 local UCINAME = lucid.UCINAME
30 function prepare_daemon(config, server)
31 nixio.syslog("info", "Preparing TCP-Daemon " .. config[".name"])
32 if type(config.address) ~= "table" then
33 config.address = {config.address}
36 local sockets, socket, code, err = {}
37 local sopts = {reuseaddr = 1}
38 for _, addr in ipairs(config.address) do
39 local host, port = addr:match("(.-):?([^:]*)")
41 nixio.syslog("err", "Invalid address: " .. addr)
42 return nil, -5, "invalid address format"
43 elseif #host == 0 then
46 socket, code, err = prepare_socket(config.family, host, port, sopts)
48 sockets[#sockets+1] = socket
52 nixio.syslog("info", "Sockets bound for " .. config[".name"])
55 return nil, -6, "no sockets bound"
58 nixio.syslog("info", "Preparing publishers for " .. config[".name"])
61 for k, pname in ipairs(config.publisher) do
62 local pdata = cursor:get_all(UCINAME, pname)
64 publisher[#publisher+1] = pdata
66 nixio.syslog("err", "Publisher " .. pname .. " not found")
70 nixio.syslog("info", "Preparing TLS for " .. config[".name"])
72 local tls = prepare_tls(config.tls)
73 if not tls and config.encryption == "enable" then
74 for _, s in ipairs(sockets) do
77 return nil, -4, "Encryption requested, but no TLS context given"
80 nixio.syslog("info", "Invoking daemon factory for " .. config[".name"])
81 local handler, err = config.slave.module.factory(publisher, config)
83 for _, s in ipairs(sockets) do
88 local pollin = nixio.poll_flags("in")
89 for _, s in ipairs(sockets) do
90 server.register_pollfd({
97 publisher = publisher,
105 function accept(polle)
106 local socket, host, port = polle.fd:accept()
108 return nixio.syslog("warn", "accept() failed: " .. port)
111 socket:setblocking(true)
113 local function thread()
114 lucid.close_pollfds()
115 local inst = setmetatable({
116 host = host, port = port, interfaces = lucid.get_interfaces()
117 }, {__index = polle})
118 if polle.config.encryption then
119 socket = polle.tls:create(socket)
120 if not socket:accept() then
122 return nixio.syslog("warning", "TLS handshake failed: " .. host)
126 return polle.accept(socket, inst)
129 local stat = {lucid.create_process(thread)}
134 function prepare_socket(family, host, port, opts, backlog)
135 nixio.syslog("info", "Preparing socket for port " .. port)
136 backlog = backlog or 1024
137 family = family or "inetany"
140 local inetany = family == "inetany"
141 family = inetany and "inet6" or family
143 local socket, code, err = nixio.socket(family, "stream")
144 if not socket and inetany then
146 socket, code, err = nixio.socket(family, "stream")
150 return nil, code, err
153 for k, v in pairs(opts) do
154 socket:setsockopt("socket", k, v)
157 local stat, code, err = socket:bind(host, port)
159 return nil, code, err
162 stat, code, err = socket:listen(backlog)
164 return nil, code, err
167 socket:setblocking(false)
169 return socket, family
172 function prepare_tls(tlskey)
173 local tls = nixio.tls("server")
174 if tlskey and cursor:get(UCINAME, tlskey) then
175 local cert = cursor:get(UCINAME, tlskey, "cert")
179 local key = cursor:get(UCINAME, tlskey, "key")
183 local ciphers = cursor:get(UCINAME, tlskey, "ciphers")
185 if type(ciphers) == "table" then
186 ciphers = table.concat(ciphers, ":")
188 tls:set_ciphers(ciphers)