OC-Minitel/vTunnel/bridge.lua

153 lines
3.2 KiB
Lua

local socket = require "socket"
local imt = require "interminitel"
local pcap = require "pcap"
local tArgs = {...}
local port, timeout, pf = tonumber(tArgs[1]) or 4096, tonumber(tArgs[2]) or 60, tArgs[3]
local clients, coroutines, messages = {}, {}, {}
local clientcounter = 1
local function spawn(f)
coroutines[#coroutines+1] = coroutine.create(function()
pid = #coroutines
while true do
print(pid,pcall(f))
end
end)
end
function reprint(...)
local tA = {...}
for k,v in pairs(tA) do
local s = ""
v=tostring(v)
for i = 1, v:len() do
if string.byte(v:sub(i,i)) < 32 or string.byte(v:sub(i,i)) > 127 then
s=s .. "\\" .. tostring(string.byte(v:sub(i,i)))
else
s=s..v:sub(i,i)
end
end
print(s)
end
end
local function hasValidPacket(s)
local w, res = pcall(imt.decodePacket,s)
if res then return true end
end
hasValidPacket("")
function socketLoop()
local server = socket.bind("*", port)
server:settimeout(0.01)
print("vTunnel bridge server listening on port "..tostring(port))
while true do
local client,err = server:accept()
if client then
client:settimeout(0)
clients[clientcounter+1] = {["conn"]=client,last=os.time(),buffer=""}
clientcounter = clientcounter + 1
local i,p = client:getsockname()
print("Gained client #"..tostring(clientcounter)..": "..i..":"..tostring(p))
end
coroutine.yield()
end
end
spawn(socketLoop)
function clientLoop()
while true do
for id,client in pairs(clients) do
local s,b,c=client.conn:receive(1)
if s then
client.buffer = client.buffer .. s
client.last=os.time()
elseif b == "closed" then
print("Client "..tostring(id).." disconnected")
client.conn:close()
clients[id] = nil
end
if client.buffer:sub(1,3) == "\0\1\0" then
client.buffer=client.buffer:sub(4)
end
if client.buffer:len() > 16384 then
print("Dropping client "..tostring(id).." for wasting resources")
client.conn:close()
clients[id] = nil
end
if client.last+timeout < os.time() then
print("Dropping client "..tostring(id).." for inactivity")
client.conn:close()
clients[id] = nil
end
end
coroutine.yield()
end
end
spawn(clientLoop)
function pushLoop()
while true do
for id,msg in pairs(messages) do
if msg[1]:len() > 3 then
for k,client in pairs(clients) do
if k ~= msg[2] then
client.conn:send(msg[1])
reprint("Message #"..tostring(id).." (Client #"..tostring(msg[2]).." -> Client #"..tostring(k)..") - "..msg[1])
end
end
if pf then
local f=io.open(pf,"ab")
if f then
f:write(pcap.packet(msg[1]))
print(pcap.packet(msg[1]))
f:close()
end
end
end
messages[id] = nil
end
coroutine.yield()
end
end
spawn(pushLoop)
function bufferLoop()
while true do
for id,client in pairs(clients) do
if client.buffer:len() > 0 then
if imt.decodePacket(client.buffer) then
messages[#messages+1] = {imt.encodePacket(imt.decodePacket(client.buffer)),id}
client.buffer = imt.getRemainder(client.buffer) or ""
end
end
end
coroutine.yield()
end
end
spawn(bufferLoop)
if pf then
local f=io.open(pf,"wb")
if f then
f:write(pcap.header())
f:close()
else
pf=nil
end
end
while #coroutines > 0 do
for k,v in pairs(coroutines) do
coroutine.resume(v)
end
end