opus/sys/apis/socket.lua

217 lines
5.0 KiB
Lua
Raw Normal View History

local Crypto = require('crypto')
local Logger = require('logger')
local Security = require('security')
local Util = require('util')
2016-12-11 19:24:52 +00:00
2017-10-08 21:45:01 +00:00
local device = _G.device
local os = _G.os
2016-12-11 19:24:52 +00:00
local socketClass = { }
2017-05-05 11:34:20 +00:00
2016-12-11 19:24:52 +00:00
function socketClass:read(timeout)
2017-10-09 17:08:38 +00:00
local data, distance = _G.transport.read(self)
2017-05-09 05:57:00 +00:00
if data then
return data, distance
2016-12-11 19:24:52 +00:00
end
2017-05-10 23:59:09 +00:00
if not self.connected then
Logger.log('socket', 'read: No connection')
return
end
2017-05-09 05:57:00 +00:00
local timerId = os.startTimer(timeout or 5)
2016-12-11 19:24:52 +00:00
while true do
2017-05-09 05:57:00 +00:00
local e, id = os.pullEvent()
2017-05-10 23:59:09 +00:00
if e == 'transport_' .. self.sport then
2017-10-09 17:08:38 +00:00
data, distance = _G.transport.read(self)
2017-05-09 05:57:00 +00:00
if data then
os.cancelTimer(timerId)
return data, distance
2016-12-11 19:24:52 +00:00
end
2017-05-09 05:57:00 +00:00
elseif e == 'timer' and id == timerId then
2016-12-11 19:24:52 +00:00
if timeout or not self.connected then
break
end
2017-05-09 05:57:00 +00:00
timerId = os.startTimer(5)
2018-01-07 03:25:33 +00:00
self:ping()
2016-12-11 19:24:52 +00:00
end
end
end
function socketClass:write(data)
2017-05-10 23:59:09 +00:00
if self.connected then
2017-10-09 17:08:38 +00:00
_G.transport.write(self, {
2017-05-10 23:59:09 +00:00
type = 'DATA',
seq = self.wseq,
data = data,
})
return true
2016-12-11 19:24:52 +00:00
end
end
2017-05-10 10:11:25 +00:00
function socketClass:ping()
2017-05-10 23:59:09 +00:00
if self.connected then
2018-01-07 03:25:33 +00:00
_G.transport.ping(self)
2017-05-10 23:59:09 +00:00
return true
2017-05-10 10:11:25 +00:00
end
end
2016-12-11 19:24:52 +00:00
function socketClass:close()
if self.connected then
Logger.log('socket', 'closing socket ' .. self.sport)
self.transmit(self.dport, self.dhost, {
type = 'DISC',
})
self.connected = false
end
device.wireless_modem.close(self.sport)
2017-10-09 17:08:38 +00:00
_G.transport.close(self)
2016-12-11 19:24:52 +00:00
end
local Socket = { }
local function loopback(port, sport, msg)
os.queueEvent('modem_message', 'loopback', port, sport, msg, 0)
end
local function newSocket(isLoopback)
2017-05-09 05:57:00 +00:00
for i = 16384, 32767 do
2016-12-11 19:24:52 +00:00
if not device.wireless_modem.isOpen(i) then
local socket = {
shost = os.getComputerID(),
sport = i,
transmit = device.wireless_modem.transmit,
2017-05-09 05:57:00 +00:00
wseq = math.random(100, 100000),
rseq = math.random(100, 100000),
timers = { },
messages = { },
2016-12-11 19:24:52 +00:00
}
setmetatable(socket, { __index = socketClass })
device.wireless_modem.open(socket.sport)
if isLoopback then
socket.transmit = loopback
end
return socket
end
end
error('No ports available')
end
function Socket.connect(host, port)
local socket = newSocket(host == os.getComputerID())
2017-10-23 23:33:53 +00:00
socket.dhost = tonumber(host)
2016-12-11 19:24:52 +00:00
Logger.log('socket', 'connecting to ' .. port)
socket.transmit(port, socket.sport, {
type = 'OPEN',
shost = socket.shost,
dhost = socket.dhost,
t = Crypto.encrypt({ ts = os.time(), seq = socket.seq }, Security.getPublicKey()),
2017-05-09 05:57:00 +00:00
rseq = socket.wseq,
wseq = socket.rseq,
2016-12-11 19:24:52 +00:00
})
local timerId = os.startTimer(3)
repeat
local e, id, sport, dport, msg = os.pullEvent()
if e == 'modem_message' and
sport == socket.sport and
2017-10-09 17:08:38 +00:00
msg.dhost == socket.shost then
2016-12-11 19:24:52 +00:00
os.cancelTimer(timerId)
2017-10-09 17:08:38 +00:00
if msg.type == 'CONN' then
2017-05-09 05:57:00 +00:00
2017-10-09 17:08:38 +00:00
socket.dport = dport
socket.connected = true
Logger.log('socket', 'connection established to %d %d->%d',
host, socket.sport, socket.dport)
_G.transport.open(socket)
return socket
elseif msg.type == 'REJE' then
return false, 'Password not set on target or not trusted'
end
2016-12-11 19:24:52 +00:00
end
until e == 'timer' and id == timerId
socket:close()
2017-10-09 17:08:38 +00:00
return false, 'Connection timed out'
2016-12-11 19:24:52 +00:00
end
2017-05-10 23:59:09 +00:00
local function trusted(msg, port)
2017-05-05 11:34:20 +00:00
2017-05-09 05:57:00 +00:00
if port == 19 or msg.shost == os.getComputerID() then
-- no auth for trust server or loopback
2017-05-05 11:34:20 +00:00
return true
end
2017-11-15 05:08:42 +00:00
if not Security.hasPassword() then
-- no password has been set on this computer
return true
end
2017-05-20 22:27:26 +00:00
local trustList = Util.readTable('usr/.known_hosts') or { }
2017-05-05 11:34:20 +00:00
local pubKey = trustList[msg.shost]
if pubKey then
2017-05-06 01:43:17 +00:00
local data = Crypto.decrypt(msg.t or '', pubKey)
2017-05-05 11:34:20 +00:00
--local sharedKey = modexp(pubKey, exchange.secretKey, public.primeMod)
2017-05-06 01:43:17 +00:00
return data.ts and tonumber(data.ts) and math.abs(os.time() - data.ts) < 1
2017-04-08 01:03:35 +00:00
end
end
2017-05-09 05:57:00 +00:00
function Socket.server(port)
2016-12-11 19:24:52 +00:00
device.wireless_modem.open(port)
Logger.log('socket', 'Waiting for connections on port ' .. port)
while true do
2017-10-08 21:45:01 +00:00
local _, _, sport, dport, msg = os.pullEvent('modem_message')
2016-12-11 19:24:52 +00:00
if sport == port and
msg and
msg.dhost == os.getComputerID() and
msg.type == 'OPEN' then
2017-10-09 17:08:38 +00:00
local socket = newSocket(msg.shost == os.getComputerID())
socket.dport = dport
socket.dhost = msg.shost
socket.wseq = msg.wseq
socket.rseq = msg.rseq
2017-05-05 11:34:20 +00:00
if trusted(msg, port) then
2017-04-08 01:03:35 +00:00
socket.connected = true
socket.transmit(socket.dport, socket.sport, {
type = 'CONN',
dhost = socket.dhost,
shost = socket.shost,
})
Logger.log('socket', 'Connection established %d->%d', socket.sport, socket.dport)
2016-12-11 19:24:52 +00:00
2017-10-09 17:08:38 +00:00
_G.transport.open(socket)
2017-04-08 01:03:35 +00:00
return socket
2016-12-11 19:24:52 +00:00
end
2017-10-09 17:08:38 +00:00
socket.transmit(socket.dport, socket.sport, {
type = 'REJE',
dhost = socket.dhost,
shost = socket.shost,
})
socket:close()
2016-12-11 19:24:52 +00:00
end
end
end
return Socket