mirror of
https://github.com/AR2000AR/openComputers_codes.git
synced 2025-09-06 21:51:14 +02:00
[osinetwork] TCP
This commit is contained in:
@@ -6,21 +6,31 @@ local os = require("os")
|
|||||||
local socket = require("socket")
|
local socket = require("socket")
|
||||||
|
|
||||||
|
|
||||||
local args, opts = shell.parse(...)
|
local args, opts = shell.parse(...)
|
||||||
local udpSocket, reason = socket.udp()
|
---@type TCPSocket|UDPSocket
|
||||||
|
local localSocket
|
||||||
|
---@type TCPSocket|nil
|
||||||
|
local clientSocket
|
||||||
|
---@type thread
|
||||||
local listenerThread
|
local listenerThread
|
||||||
|
|
||||||
|
|
||||||
opts.p = tonumber(opts.p) or 0
|
opts.p = tonumber(opts.p) or 0
|
||||||
opts.b = opts.b or "0.0.0.0"
|
opts.b = opts.b or "0.0.0.0"
|
||||||
|
|
||||||
---@param listenedSocket UDPSocket
|
---@param listenedSocket UDPSocket|TCPSocket
|
||||||
local function listenSocket(listenedSocket)
|
local function listenSocket(listenedSocket)
|
||||||
checkArg(1, listenedSocket, 'table')
|
checkArg(1, listenedSocket, 'table')
|
||||||
while true do
|
while true do
|
||||||
local datagram = listenedSocket:recieve()
|
if (listenedSocket:instanceOf(socket.tcp)) then
|
||||||
if (datagram) then
|
---@cast listenedSocket TCPSocket
|
||||||
term.write(datagram)
|
if (listenedSocket:getState() ~= "ESTABLISHED") then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local data = listenedSocket:recieve()
|
||||||
|
if (data) then
|
||||||
|
term.write(data)
|
||||||
end
|
end
|
||||||
os.sleep()
|
os.sleep()
|
||||||
end
|
end
|
||||||
@@ -37,8 +47,18 @@ local function help()
|
|||||||
print("\t nc -u 192.168.1.1 9999")
|
print("\t nc -u 192.168.1.1 9999")
|
||||||
end
|
end
|
||||||
|
|
||||||
event.listen("interrupted", function(...)
|
---read stdin indefenitely and send what's read through the socket
|
||||||
if (udpSocket) then udpSocket:close() end
|
---@param outSocket TCPSocket|UDPSocket
|
||||||
|
local function readUserInput(outSocket)
|
||||||
|
repeat
|
||||||
|
local msg = term.read()
|
||||||
|
if (msg) then outSocket:send(msg .. "\n") end
|
||||||
|
until not msg or listenerThread:status() == "dead"
|
||||||
|
end
|
||||||
|
|
||||||
|
local function exit()
|
||||||
|
if (localSocket) then localSocket:close() end
|
||||||
|
if (clientSocket) then clientSocket:close() end
|
||||||
if (listenerThread) then
|
if (listenerThread) then
|
||||||
if (not listenerThread:join(3)) then
|
if (not listenerThread:join(3)) then
|
||||||
listenerThread:kill()
|
listenerThread:kill()
|
||||||
@@ -46,63 +66,62 @@ event.listen("interrupted", function(...)
|
|||||||
end
|
end
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
)
|
|
||||||
|
event.listen("interrupted", exit)
|
||||||
|
|
||||||
if (opts.h or opts.help) then
|
if (opts.h or opts.help) then
|
||||||
help()
|
help()
|
||||||
os.exit()
|
os.exit()
|
||||||
elseif (opts.l and opts.u and (tonumber(args[1]) or opts.p)) then --listen UDP
|
elseif (opts.l and opts.u and (tonumber(args[1]) or opts.p)) then --listen UDP
|
||||||
assert(udpSocket:setsockname("*", tonumber(args[1]) or opts.p))
|
localSocket = socket.udp()
|
||||||
--udpSocket:setCallback(listenSocket)
|
assert(localSocket:setsockname("*", tonumber(args[1]) or opts.p))
|
||||||
print(string.format("Listening on %s:%d", udpSocket:getsockname()))
|
print(string.format("Listening on %s:%d", localSocket:getsockname()))
|
||||||
listenerThread = thread.create(listenSocket, udpSocket)
|
listenerThread = thread.create(listenSocket, localSocket)
|
||||||
while true do
|
while true do
|
||||||
--no remote addr/port. We cannot send msgs
|
--no remote addr/port. We cannot send msgs
|
||||||
os.sleep()
|
os.sleep()
|
||||||
end
|
end
|
||||||
udpSocket:close()
|
localSocket:close()
|
||||||
elseif (opts.u) then --connect UDP
|
elseif (opts.u) then --connect UDP
|
||||||
assert(udpSocket:setsockname(opts.b, opts.p))
|
localSocket = socket.udp()
|
||||||
|
assert(localSocket:setsockname(opts.b, opts.p))
|
||||||
args[2] = assert(tonumber(args[2]), "Invalid port number")
|
args[2] = assert(tonumber(args[2]), "Invalid port number")
|
||||||
assert(udpSocket:setpeername(args[1], args[2]))
|
assert(localSocket:setpeername(args[1], args[2]))
|
||||||
--udpSocket:setCallback(listenSocket)
|
print(string.format("Listening on %s:%d", localSocket:getsockname()))
|
||||||
print(string.format("Listening on %s:%d", udpSocket:getsockname()))
|
listenerThread = thread.create(listenSocket, localSocket)
|
||||||
listenerThread = thread.create(listenSocket, udpSocket)
|
readUserInput(localSocket)
|
||||||
repeat
|
localSocket:close()
|
||||||
local msg = term.read()
|
elseif (opts.l) then --listen tcp
|
||||||
if (msg) then udpSocket:send(msg .. "\n") end
|
localSocket = socket.tcp()
|
||||||
until not msg
|
args[1] = args[1] or opts.b
|
||||||
udpSocket:close()
|
args[2] = assert(tonumber(args[2] or opts.p), "Invalid port number")
|
||||||
elseif (opts.l) then
|
assert(localSocket:bind(args[1], args[2]))
|
||||||
local tcpsocket = socket.tcp()
|
print(string.format("Listening on %s:%d", localSocket:getsockname()))
|
||||||
assert(tcpsocket:bind(opts.b, opts.p))
|
localSocket:listen(1)
|
||||||
args[2] = assert(tonumber(args[2]), "Invalid port number")
|
local reason
|
||||||
assert(tcpsocket:bind(args[1], args[2]))
|
clientSocket = localSocket:accept()
|
||||||
print(string.format("Listening on %s:%d", tcpsocket:getsockname()))
|
localSocket:close() --client connected, we don't need the listening socket anymore
|
||||||
tcpsocket:listen(1)
|
if (clientSocket) then
|
||||||
local client = tcpsocket:accept()
|
print(string.format("Connected to : %s:%d", clientSocket:getpeername()))
|
||||||
if (client) then
|
listenerThread = thread.create(listenSocket, clientSocket)
|
||||||
listenerThread = thread.create(listenSocket, client)
|
readUserInput(clientSocket)
|
||||||
repeat
|
clientSocket:close()
|
||||||
local msg = term.read()
|
else
|
||||||
if (msg) then client:send(msg .. "\n") end
|
print(reason)
|
||||||
until not msg
|
|
||||||
client:close()
|
|
||||||
end
|
end
|
||||||
tcpsocket:close()
|
|
||||||
else --connect TCP
|
else --connect TCP
|
||||||
args[2] = assert(tonumber(args[2]), "Invalid port number")
|
args[2] = assert(tonumber(args[2]), "Invalid port number")
|
||||||
local tcpsocket = socket.tcp()
|
localSocket = socket.tcp()
|
||||||
tcpsocket:settimeout(5)
|
localSocket:settimeout(5)
|
||||||
local s = tcpsocket:connect(args[1], args[2])
|
local s = localSocket:connect(args[1], args[2])
|
||||||
if (s ~= 1) then
|
if (s ~= 1) then
|
||||||
print("Timeout")
|
print("Timeout")
|
||||||
os.exit(1)
|
else
|
||||||
|
print(string.format("Connected to %s:%d", localSocket:getpeername()))
|
||||||
|
listenerThread = thread.create(listenSocket, localSocket)
|
||||||
|
readUserInput(localSocket)
|
||||||
end
|
end
|
||||||
print(string.format("Connected to %s:%d", tcpsocket:getpeername()))
|
localSocket:close()
|
||||||
listenerThread = thread.create(listenSocket, tcpsocket)
|
|
||||||
repeat
|
|
||||||
local msg = term.read()
|
|
||||||
if (msg) then tcpsocket:send(msg .. "\n") end
|
|
||||||
until not msg
|
|
||||||
tcpsocket:close()
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
exit()
|
||||||
|
@@ -4,7 +4,7 @@ local TCPSegment = require("network.tcp.TCPSegment")
|
|||||||
local ipv4Address = require("network.ipv4.address")
|
local ipv4Address = require("network.ipv4.address")
|
||||||
local NetworkLayer = require('network.abstract.NetworkLayer')
|
local NetworkLayer = require('network.abstract.NetworkLayer')
|
||||||
local network = require("network")
|
local network = require("network")
|
||||||
local utils = require("network.utils")
|
local utils = require("network.utils")
|
||||||
local class = require("libClass2")
|
local class = require("libClass2")
|
||||||
|
|
||||||
|
|
||||||
@@ -30,7 +30,7 @@ end
|
|||||||
|
|
||||||
---@package
|
---@package
|
||||||
function TCPLayer:tick()
|
function TCPLayer:tick()
|
||||||
for _,s in pairs(utils.getTreeBottomValues(self._sockets)) do
|
for _, s in pairs(utils.getTreeBottomValues(self._sockets)) do
|
||||||
---@cast s TCPSocket
|
---@cast s TCPSocket
|
||||||
s:_tick()
|
s:_tick()
|
||||||
end
|
end
|
||||||
@@ -42,7 +42,7 @@ function TCPLayer:payloadHandler(from, to, payload)
|
|||||||
if (seg:flag(TCPSegment.Flags.SYN) and not seg:flag(TCPSegment.Flags.ACK)) then
|
if (seg:flag(TCPSegment.Flags.SYN) and not seg:flag(TCPSegment.Flags.ACK)) then
|
||||||
--initial sync packet
|
--initial sync packet
|
||||||
socket = self:getSocket(to, seg:dstPort(), 0, 0)
|
socket = self:getSocket(to, seg:dstPort(), 0, 0)
|
||||||
if (not socket) then
|
if (not socket) then --Send RST
|
||||||
local rstseg = TCPSegment(seg:dstPort(), seg:srcPort(), "")
|
local rstseg = TCPSegment(seg:dstPort(), seg:srcPort(), "")
|
||||||
rstseg:flags(TCPSegment.Flags.RST|TCPSegment.Flags.ACK)
|
rstseg:flags(TCPSegment.Flags.RST|TCPSegment.Flags.ACK)
|
||||||
rstseg:seq(seg:flag(TCPSegment.Flags.ACK) and seg:ack() or 0)
|
rstseg:seq(seg:flag(TCPSegment.Flags.ACK) and seg:ack() or 0)
|
||||||
|
@@ -28,7 +28,7 @@ local class = require("libClass2")
|
|||||||
---@class Buffer:Object
|
---@class Buffer:Object
|
||||||
---@field private _data string
|
---@field private _data string
|
||||||
---@operator call:Buffer
|
---@operator call:Buffer
|
||||||
local Buffer = require('libClass2')()
|
local Buffer = class()
|
||||||
|
|
||||||
---Comment
|
---Comment
|
||||||
---@return Buffer
|
---@return Buffer
|
||||||
|
@@ -1,12 +1,9 @@
|
|||||||
local TCPSocket = require("socket.tcp")
|
local TCPSocket = require("socket.tcp")
|
||||||
|
local UDPSocket = require("socket.udp")
|
||||||
|
|
||||||
return {
|
return {
|
||||||
udp = require("socket.udp"),
|
udp = UDPSocket,
|
||||||
---Creates and returns an TCP master object. A master object can be transformed into a server object with the method listen (after a call to bind) or into a client object with the method connect. The only other method supported by a master object is the close method.
|
tcp = TCPSocket,
|
||||||
---
|
|
||||||
---In case of success, a new master object is returned. In case of error, nil is returned, followed by an error message.
|
|
||||||
---@return TCPSocket
|
|
||||||
tcp = function() return TCPSocket() end,
|
|
||||||
---@type socketdns
|
---@type socketdns
|
||||||
dns = select(2, pcall(require, "socket.dns"))
|
dns = select(2, pcall(require, "socket.dns"))
|
||||||
}
|
}
|
||||||
|
@@ -155,6 +155,7 @@ function TCPSocket:_makeDataSegment(data)
|
|||||||
return seg
|
return seg
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--set the segment `seg` acknowledgment number to acknowledge the `recived` segment
|
||||||
---@protected
|
---@protected
|
||||||
---@param seg TCPSegment
|
---@param seg TCPSegment
|
||||||
---@param received TCPSegment
|
---@param received TCPSegment
|
||||||
@@ -165,6 +166,7 @@ function TCPSocket:_setAck(seg, received)
|
|||||||
return seg
|
return seg
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---make a new acknowledgment segment for the `recived` segment
|
||||||
---@protected
|
---@protected
|
||||||
---@param received TCPSegment
|
---@param received TCPSegment
|
||||||
---@return TCPSegment
|
---@return TCPSegment
|
||||||
@@ -243,7 +245,7 @@ function TCPSocket:bind(address, port)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function TCPSocket:close()
|
function TCPSocket:close()
|
||||||
if (self._kind == "client") then
|
if (self._kind == "client" and self._state ~= "CLOSED") then
|
||||||
local seg = self:_makeSegment()
|
local seg = self:_makeSegment()
|
||||||
seg:flag(f.FIN, true)
|
seg:flag(f.FIN, true)
|
||||||
seg:flag(f.ACK, true)
|
seg:flag(f.ACK, true)
|
||||||
@@ -338,7 +340,7 @@ end
|
|||||||
---Prefix is an optional string to be concatenated to the beginning of any received data before return.\
|
---Prefix is an optional string to be concatenated to the beginning of any received data before return.\
|
||||||
---
|
---
|
||||||
---If successful, the method returns the received pattern. In case of error, the method returns nil followed by an error message, followed by a (possibly empty) string containing the partial that was received. The error message can be the string 'closed' in case the connection was closed before the transmission was completed or the string 'timeout' in case there was a timeout during the operation.
|
---If successful, the method returns the received pattern. In case of error, the method returns nil followed by an error message, followed by a (possibly empty) string containing the partial that was received. The error message can be the string 'closed' in case the connection was closed before the transmission was completed or the string 'timeout' in case there was a timeout during the operation.
|
||||||
---@param pattern? string
|
---@param pattern? "*a"|"*l"|number
|
||||||
---@param prefix? string
|
---@param prefix? string
|
||||||
---@return string? data, string?reason
|
---@return string? data, string?reason
|
||||||
function TCPSocket:recieve(pattern, prefix)
|
function TCPSocket:recieve(pattern, prefix)
|
||||||
@@ -349,6 +351,7 @@ function TCPSocket:recieve(pattern, prefix)
|
|||||||
local data
|
local data
|
||||||
repeat
|
repeat
|
||||||
data = self._inBuffer:read(pattern)
|
data = self._inBuffer:read(pattern)
|
||||||
|
os.sleep()
|
||||||
until data ~= nil or self:_hasTimedOut(t1)
|
until data ~= nil or self:_hasTimedOut(t1)
|
||||||
if (not data) then
|
if (not data) then
|
||||||
return nil, self:_hasTimedOut(t1) and "timeout" or ""
|
return nil, self:_hasTimedOut(t1) and "timeout" or ""
|
||||||
@@ -473,6 +476,7 @@ function TCPSocket:payloadHandler(from, to, tcpSegment)
|
|||||||
if (tcpSegment:offset() > 5) then
|
if (tcpSegment:offset() > 5) then
|
||||||
self:handleOptions(tcpSegment)
|
self:handleOptions(tcpSegment)
|
||||||
end
|
end
|
||||||
|
|
||||||
if (self._state == "LISTEN") then
|
if (self._state == "LISTEN") then
|
||||||
if (tcpSegment:flag(f.SYN)) then
|
if (tcpSegment:flag(f.SYN)) then
|
||||||
if (#(self._backlog) < self._backlogLen) then
|
if (#(self._backlog) < self._backlogLen) then
|
||||||
|
@@ -173,10 +173,4 @@ function UDPSocket:payloadHandler(from, to, udpPacket)
|
|||||||
table.insert(self._buffer, {udpPacket:payload(), ipv4Address.tostring(from), udpPacket:srcPort()})
|
table.insert(self._buffer, {udpPacket:payload(), ipv4Address.tostring(from), udpPacket:srcPort()})
|
||||||
end
|
end
|
||||||
|
|
||||||
---Create and returns an unconnected UDP socket.
|
return UDPSocket
|
||||||
---@return UDPSocket
|
|
||||||
local function udp()
|
|
||||||
return UDPSocket()
|
|
||||||
end
|
|
||||||
|
|
||||||
return udp
|
|
||||||
|
Reference in New Issue
Block a user