opus/sys/apps/network/transport.lua

152 lines
3.6 KiB
Lua
Raw Normal View History

2017-05-09 05:57:00 +00:00
--[[
2018-01-24 22:39:38 +00:00
Low level socket protocol implementation.
2017-05-09 05:57:00 +00:00
2018-01-24 22:39:38 +00:00
* sequencing
* background read buffering
2017-05-09 05:57:00 +00:00
]]--
2019-06-30 03:43:21 +00:00
local Crypto = require('opus.crypto.chacha20')
local Event = require('opus.event')
2017-10-25 03:01:40 +00:00
2019-06-29 20:35:33 +00:00
local network = _G.network
2018-01-13 20:17:26 +00:00
local os = _G.os
2017-05-09 05:57:00 +00:00
local computerId = os.getComputerID()
2017-10-25 03:01:40 +00:00
local transport = {
2018-01-24 22:39:38 +00:00
timers = { },
sockets = { },
2019-06-30 18:47:45 +00:00
encryptQueue = { },
2018-01-24 22:39:38 +00:00
UID = 0,
2017-05-09 05:57:00 +00:00
}
2019-06-29 20:35:33 +00:00
getmetatable(network).__index.getTransport = function()
return transport
end
2017-05-09 05:57:00 +00:00
function transport.open(socket)
2018-01-24 22:39:38 +00:00
transport.UID = transport.UID + 1
2018-01-20 12:18:13 +00:00
2018-01-24 22:39:38 +00:00
transport.sockets[socket.sport] = socket
socket.activityTimer = os.clock()
socket.uid = transport.UID
2017-05-09 05:57:00 +00:00
end
function transport.read(socket)
2018-01-24 22:39:38 +00:00
local data = table.remove(socket.messages, 1)
if data then
2019-06-30 03:43:21 +00:00
if socket.options.ENCRYPT then
return table.unpack(Crypto.decrypt(data[1], socket.enckey)), data[2]
end
return table.unpack(data)
2018-01-24 22:39:38 +00:00
end
2017-05-09 05:57:00 +00:00
end
2019-06-30 18:47:45 +00:00
function transport.write(socket, msg)
if socket.options.ENCRYPT then
if #transport.encryptQueue == 0 then
os.queueEvent('transport_encrypt')
end
table.insert(transport.encryptQueue, { socket.sport, msg })
else
socket.transmit(socket.dport, socket.dhost, msg)
end
2019-06-30 02:02:00 +00:00
socket.wseq = socket.wrng:nextInt(5)
2017-05-09 05:57:00 +00:00
end
2018-01-07 03:25:33 +00:00
function transport.ping(socket)
2018-01-24 22:39:38 +00:00
if os.clock() - socket.activityTimer > 10 then
socket.activityTimer = os.clock()
socket.transmit(socket.dport, socket.dhost, {
type = 'PING',
seq = -1,
})
2019-06-29 20:35:33 +00:00
local timerId = os.startTimer(3)
2018-01-24 22:39:38 +00:00
transport.timers[timerId] = socket
socket.timers[-1] = timerId
end
2018-01-07 03:25:33 +00:00
end
2017-05-09 05:57:00 +00:00
function transport.close(socket)
2018-01-24 22:39:38 +00:00
transport.sockets[socket.sport] = nil
2017-05-09 05:57:00 +00:00
end
2019-06-30 18:47:45 +00:00
Event.on('transport_encrypt', function()
while #transport.encryptQueue > 0 do
local entry = table.remove(transport.encryptQueue, 1)
local socket = transport.sockets[entry[1]]
if socket and socket.connected then
local msg = entry[2]
msg.data = Crypto.encrypt({ msg.data }, socket.enckey)
socket.transmit(socket.dport, socket.dhost, msg)
end
end
end)
2018-01-13 20:17:26 +00:00
Event.on('timer', function(_, timerId)
2018-01-24 22:39:38 +00:00
local socket = transport.timers[timerId]
2018-01-07 03:25:33 +00:00
2018-01-24 22:39:38 +00:00
if socket and socket.connected then
print('transport timeout - closing socket ' .. socket.sport)
socket:close()
transport.timers[timerId] = nil
end
2018-01-13 20:17:26 +00:00
end)
2017-05-09 05:57:00 +00:00
2018-01-13 20:17:26 +00:00
Event.on('modem_message', function(_, _, dport, dhost, msg, distance)
2018-03-30 17:12:46 +00:00
if dhost == computerId and type(msg) == 'table' then
2018-01-24 22:39:38 +00:00
local socket = transport.sockets[dport]
if socket and socket.connected then
2018-12-02 23:40:19 +00:00
if socket.co and coroutine.status(socket.co) == 'dead' then
2019-05-03 19:30:09 +00:00
_G._syslog('socket coroutine dead')
2018-12-02 23:40:19 +00:00
socket:close()
2018-01-24 22:39:38 +00:00
2018-12-02 23:40:19 +00:00
elseif msg.type == 'DISC' then
2018-01-24 22:39:38 +00:00
-- received disconnect from other end
2019-06-29 20:35:33 +00:00
if msg.seq == socket.rseq then
if socket.connected then
os.queueEvent('transport_' .. socket.uid)
end
socket.connected = false
socket:close()
2018-01-24 22:39:38 +00:00
end
elseif msg.type == 'ACK' then
local ackTimerId = socket.timers[msg.seq]
if ackTimerId then
os.cancelTimer(ackTimerId)
socket.timers[msg.seq] = nil
socket.activityTimer = os.clock()
transport.timers[ackTimerId] = nil
end
elseif msg.type == 'PING' then
socket.activityTimer = os.clock()
socket.transmit(socket.dport, socket.dhost, {
type = 'ACK',
seq = msg.seq,
})
elseif msg.type == 'DATA' and msg.data then
if msg.seq ~= socket.rseq then
2019-06-30 18:47:45 +00:00
print('transport seq error ' .. socket.sport)
2019-05-03 19:30:09 +00:00
_syslog(msg.data)
2019-06-29 20:35:33 +00:00
_syslog('expected ' .. socket.rseq)
_syslog('got ' .. msg.seq)
2018-01-24 22:39:38 +00:00
else
2019-06-29 20:35:33 +00:00
socket.activityTimer = os.clock()
2019-06-30 02:02:00 +00:00
socket.rseq = socket.rrng:nextInt(5)
2018-01-24 22:39:38 +00:00
table.insert(socket.messages, { msg.data, distance })
if not socket.messages[2] then -- table size is 1
os.queueEvent('transport_' .. socket.uid)
end
end
end
end
end
2018-01-13 20:17:26 +00:00
end)