2018-08-11 13:59:44 +10:00
|
|
|
local net = require "minitel"
|
2018-07-28 05:19:58 +10:00
|
|
|
local syslog = require "syslog"
|
|
|
|
local fs = require "filesystem"
|
2018-09-01 17:47:58 +10:00
|
|
|
local event = require "event"
|
2019-05-21 02:28:24 +10:00
|
|
|
local serial = require "serialization"
|
2020-02-19 20:36:23 +11:00
|
|
|
local thread = require "thread"
|
|
|
|
local internet = require "internet"
|
2018-07-28 05:19:58 +10:00
|
|
|
|
2018-09-01 17:47:58 +10:00
|
|
|
local coro = {} -- table of coroutines, one per socket
|
2018-07-28 05:19:58 +10:00
|
|
|
local cfg = {}
|
2018-09-01 17:47:58 +10:00
|
|
|
local timer, listener
|
|
|
|
local isRunning = false -- simple lock
|
|
|
|
|
|
|
|
cfg.path = "/srv" -- default config
|
|
|
|
cfg.port = 70
|
|
|
|
cfg.looptimer = 0.5
|
2020-02-19 20:36:23 +11:00
|
|
|
cfg.iproxy = false
|
2018-02-19 21:04:22 +11:00
|
|
|
|
2018-07-28 05:19:58 +10:00
|
|
|
local function log(msg,level)
|
|
|
|
syslog(msg,level,"frequestd")
|
|
|
|
end
|
2018-02-19 21:04:22 +11:00
|
|
|
|
2018-09-01 17:47:58 +10:00
|
|
|
local function loadConfig() -- load config from file
|
2018-07-28 05:19:58 +10:00
|
|
|
local fobj = io.open("/etc/fserv.cfg","rb")
|
|
|
|
if fobj then
|
2018-09-01 17:47:58 +10:00
|
|
|
local ncfg = serial.unserialize(fobj:read("*a"))
|
|
|
|
if ncfg then
|
|
|
|
for k,v in pairs(ncfg) do
|
|
|
|
cfg[k] = v
|
|
|
|
end
|
|
|
|
end
|
2018-07-28 05:19:58 +10:00
|
|
|
fobj:close()
|
2018-02-19 21:04:22 +11:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2018-07-28 05:19:58 +10:00
|
|
|
local function writeConfig()
|
|
|
|
local fobj = io.open("/etc/fserv.cfg","wb")
|
|
|
|
if fobj then
|
2018-07-28 05:26:19 +10:00
|
|
|
fobj:write(serial.serialize(cfg))
|
2018-07-28 05:19:58 +10:00
|
|
|
fobj:close()
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2018-09-01 17:47:58 +10:00
|
|
|
local function handleSocket(sock) -- create a coroutine for a new socket
|
2020-02-19 20:36:23 +11:00
|
|
|
coro[#coro+1] = thread.create(function()
|
2018-09-01 17:47:58 +10:00
|
|
|
local line
|
|
|
|
repeat
|
|
|
|
coroutine.yield()
|
|
|
|
line = sock:read()
|
|
|
|
until line
|
|
|
|
local ttype, path = line:match("([ts])(.+)")
|
|
|
|
if not ttype or not path then
|
|
|
|
sock:write("fIncomplete request")
|
|
|
|
sock:close()
|
|
|
|
return false
|
2018-07-28 05:19:58 +10:00
|
|
|
end
|
2018-09-01 17:47:58 +10:00
|
|
|
sock.cname = sock.addr..":"..tostring(sock.port)
|
2020-02-19 20:36:23 +11:00
|
|
|
if path:match("^/?(http[s]?)/") and cfg.iproxy then
|
|
|
|
local scheme, rpath = path:match("^/?(http[s]?)/(.+)")
|
|
|
|
log("["..sock.cname.."] "..scheme.."://"..rpath,6)
|
|
|
|
local r = internet.request(scheme.."://"..rpath)
|
|
|
|
if r then
|
|
|
|
log("["..sock.cname.."] Transferring remote file.",7)
|
|
|
|
sock:write("y")
|
|
|
|
for s in r do
|
2020-03-13 13:29:52 +11:00
|
|
|
os.sleep(0)
|
2020-02-19 20:36:23 +11:00
|
|
|
sock:write(s)
|
|
|
|
end
|
|
|
|
else
|
|
|
|
log("["..sock.cname.."] Unable to open remote file.",7)
|
|
|
|
sock:write("fUnable to open remote file.")
|
|
|
|
end
|
|
|
|
sock:close()
|
|
|
|
return
|
|
|
|
end
|
|
|
|
path = fs.canonical(cfg.path.."/"..fs.canonical(path))
|
2018-09-01 17:47:58 +10:00
|
|
|
log("["..sock.cname.."] "..ttype.." "..path,6)
|
|
|
|
if ttype == "t" then -- transfer request
|
|
|
|
if not fs.exists(path) then
|
|
|
|
sock:write("nFile not found.")
|
|
|
|
sock:close()
|
|
|
|
log("["..sock.cname.."] Not found.",7)
|
|
|
|
return
|
2018-02-19 22:49:23 +11:00
|
|
|
end
|
2018-09-01 17:47:58 +10:00
|
|
|
if fs.isDirectory(path) then
|
|
|
|
local rs = "d"
|
|
|
|
for file in fs.list(path) do
|
|
|
|
rs = rs..file.."\n"
|
2018-02-19 21:04:22 +11:00
|
|
|
end
|
2018-09-01 17:47:58 +10:00
|
|
|
sock:write(rs)
|
|
|
|
sock:close()
|
|
|
|
log("["..sock.cname.."] Directory.",7)
|
|
|
|
return
|
|
|
|
end
|
|
|
|
local f = io.open(path,"rb")
|
|
|
|
if not f then
|
|
|
|
sock:write("fUnable to open file for reading",7)
|
|
|
|
sock:close()
|
|
|
|
return
|
|
|
|
end
|
|
|
|
sock:write("y")
|
|
|
|
log("["..sock.cname.."] Transferring file.",7)
|
|
|
|
local chunk = f:read(net.mtu)
|
|
|
|
repeat
|
2020-03-13 13:29:52 +11:00
|
|
|
os.sleep(0)
|
|
|
|
sock:write(chunk or "")
|
2018-09-01 17:47:58 +10:00
|
|
|
chunk = f:read(net.mtu)
|
|
|
|
until not chunk
|
|
|
|
sock:close()
|
|
|
|
f:close()
|
|
|
|
log("["..sock.cname.."] file transferred.",7)
|
|
|
|
elseif ttype == "s" then -- stat request
|
|
|
|
if fs.exists(path) then
|
|
|
|
local ftype = "f"
|
|
|
|
if fs.isDirectory(path) then
|
|
|
|
ftype = "d"
|
|
|
|
end
|
|
|
|
sock:write("y"..ftype..tostring(fs.size(path)))
|
|
|
|
sock:close()
|
|
|
|
log("["..sock.cname.."] stat request returned.",7)
|
|
|
|
else
|
|
|
|
sock:write("nFile not found.",7)
|
|
|
|
sock:close()
|
|
|
|
log("["..sock.cname.."] Not found.",7)
|
2018-02-19 21:04:22 +11:00
|
|
|
end
|
|
|
|
end
|
2018-09-01 17:47:58 +10:00
|
|
|
end)
|
|
|
|
log("New connection: "..sock.addr..":"..tostring(sock.port),7)
|
2018-02-19 21:04:22 +11:00
|
|
|
end
|
|
|
|
|
2018-07-28 05:19:58 +10:00
|
|
|
function start()
|
2018-09-01 17:47:58 +10:00
|
|
|
if timer or listener then return end
|
2018-07-28 05:19:58 +10:00
|
|
|
loadConfig()
|
|
|
|
writeConfig()
|
2018-09-01 17:47:58 +10:00
|
|
|
listener = net.flisten(cfg.port, handleSocket)
|
2018-02-19 21:04:22 +11:00
|
|
|
end
|
2018-07-28 05:19:58 +10:00
|
|
|
function stop()
|
2018-09-01 17:47:58 +10:00
|
|
|
if not timer or not listener then return end
|
2020-02-19 20:36:23 +11:00
|
|
|
thread.waitForAll(coro)
|
2018-09-01 17:47:58 +10:00
|
|
|
event.ignore("net_msg",listener)
|
2018-07-28 05:19:58 +10:00
|
|
|
end
|
2018-09-01 17:47:58 +10:00
|
|
|
function restart()
|
|
|
|
stop()
|
|
|
|
start()
|
2018-02-19 21:04:22 +11:00
|
|
|
end
|