This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
Cozzimoto's profile picture

Dynamic Rednet Connectivity

Started by Cozzimoto, 28 July 2013 - 10:04 AM
Cozzimoto #1
Posted 28 July 2013 - 12:04 PM
first before i get into the problem at hand, im not too familiar with timers and modem_messages with the os.pullevent(). im not entirely sure if a modem_message will still trigger if the computer is going through a current process.

problem trying to solve:
i am trying to create dynamic rednet sucurity with the modem api, i know a computer can only have 128 maximum channels (or ports i call them) open at the same time, so i figure that a server can listen on a certain channel as a public channel for clients to connect to. channels 1 - 128 would be public and channels 129 - 65535 would be private channels for interacting with servers.

problem i ran into:
i think i am getting the timing wrong but my test client is pinging on the test server, but the client isnt showing the response the server should have sent. im not sure how long i should wait between the transmit and reply and a little longer of a wait for a timer so if nothing happens the timer will fire and the client will continue on to other public ports.

i have both programs here and a screenshot of 1 run on the client program to the server.

tell me what yall think and test it out

P.S. im not giving out my encoding and decoding port functions due for the security purpose of this build.



test server code
Spoiler

-- rednet security server

local serverProperties = {publicPort = 10}
local privatePorts = {}
MODEM = peripheral.wrap("top")
MODEM.open(serverProperties.publicPort)
  print("opened: "..serverProperties.publicPort)

while true do
  local ev = { os.pullEvent() }
  if ev[1] == "modem_message" then
	os.sleep(0.2)
	local iC = ev[3]
	local rC = ev[4]
	local pkg = textutils.unserialize(ev[5])

	if type(pkg) == "table" then -- verify if its a table
	  if pkg.cid ~= nil then -- pkg must have a cid
		privatePorts[pkg.cid] = {status = nil, name = pkg.name, port = nil}

		if pkg.protocol == "_ping" then
		  privatePorts[pkg.cid].status = 1
		  MODEM.transmit(rC,serverProperties.publicPort,"_pong")
		  print("pinged from "..pkg.cid)

		elseif pkg.protocol == "whoareyou?" and privatePorts[pkg.cid].status == 1 then
		  privatePorts[pkg.cid].status = 2
		  MODEM.transmit(rC,serverProperties.publicPort,"bankSer")

		elseif pkg.protocol == "connectionRequest" and privatePorts[pkg.cid].status == 2 then
		  local gPort = RNGen() --RANDOM NUMBER GENERATOR TAKEN OUT
		  local packet = encodePort(gPort) --ENCODE PORT TAKEN OUT
		  privatePorts[pkg.cid].status = 3
		  privatePorts[pkg.cid].port = gPort
		  MODEM.open(gPort)
			print("opened: "..gPort)
			print("for cid: "..privatePorts[pkg.cid].status)
			print("encoded at: "..textutils.serialize(packet))
		  MODEM.transmit(rC,serverProperties.publicPort,textutils.serialize(packet))

		elseif pkg.protocol == "connectionVerify" and privatePorts[pkg.cid].status == 3 then
		  privatePorts[pkg.cid].status = "successful"
		  MODEM.transmit(rC,rC,"connectionEstablished")

		else -- if pkg.protocol doesnt exist or doesnt match
		  MODEM.transmit(rC,serverProperties.publicPort,"invalid protocol")
		  print("invalid protocol")

		end
	  else -- if pkg.cid is nil
		MODEM.transmit(rC,serverProperties.publicPort,"invalid Credentials")
		print("invalid Credentials")
	  end
	else -- if pkg is a string
	  MODEM.transmit(rC,serverProperties.publicPort,"invalid packet")
	  print("invalid packet..")
	end
  elseif ev[1] == "key" then

  end
  os.sleep(0.1)
end

test client code
Spoiler

-- rednet security client

MODEM = peripheral.wrap("top")

-- lets find the server
local serverFound = false
local connected = false
local targetServ = "bankSer"
local count = 1
local status = 1
local credentials = {cid = os.getComputerID(), name = os.getComputerLabel(), protocol = nil}
  print("Searching..")

while not serverFound and count < 16 do -- 120 public ports
  MODEM.open(count)
  print("opened: "..count)

  if status == 1 then
	credentials.protocol = "_ping"
	status = 2
	MODEM.transmit(count,count,textutils.serialize(credentials))

  elseif status == 2 then
	credentials.protocol = "whoareyou?"
	MODEM.transmit(count,count,textutils.serialize(credentials))

  elseif status == 3 then
	credentials.protocol = "connectionRequest"
	MODEM.transmit(count,count,textutils.serialize(credentials))

  elseif status == 4 then
	credentials.protocol = "connectionVerify"
	MODEM.transmit(privatePort,privatePort,textutils.serialize(credentials))

  end

  credentials.protocol = nil
  local T = os.startTimer(0.3)
  local ev = { os.pullEvent() }

  if ev[1] == "modem_message" then
	local iC = ev[3]
	local rC = ev[4]
	local pkg = textutils.unserialize(ev[5])

	if pkg == "_pong" then
	  serverFound = true
	  print("PINGED!")
	end
  end


  count = count + 1
  os.sleep(0.1)
end

print("Search ended")
immibis #2
Posted 28 July 2013 - 10:10 PM
You might want to print out the messages that are sent and received, for easier debugging.
Cozzimoto #3
Posted 29 July 2013 - 08:38 AM
the reason i put a status variable there for each computer id is i am making several steps to connect to the server, the client doesnt know what channel the server is listening on, so what the client does is i want it to scan each channel (most all the public channels [1-128]) and try and find the server its looking for. and the server keeps track of credentials that every connection needs, with is a table of the computerID computerName (if available), the status of the connection process and the port number assigned to that computer.

im not sure if i need to keep track of status of the connection, i mainly put it in there to make it hack proof and have a computer follow a specific format to connecting to the server without skipping a step.


this is the thought process i have drawn out of how i want the dynamic connection to work
  • so the client sends out pings for a server reply, if no rely go on to next channel and ping again.
  • once there is a pong, the client then asks "whoareyou?" so the server can reply with a unique id of what purpose that server does.
  • if the unique id isnt what the client wants then it will continue on the next channel.
  • if it is the right server then the client asks permission to connect
  • the server then encodes a port over rednet and sends it back to the client opening that private port
  • the client then decodes the port received by the server and closes all ports and opens the private port
  • last the client then sends a "connectionVerify" to see if it decoded the correct port from the server, and if so the server replies with "connectionEstablished"


and all the important information i am printing to the screen, im just not seeing the pong return from the server on the client that sent the ping. for testing i reduced the scan down to 15 channels and i should see a pong on the client on channel 10 but i dont, so thats why i am coming to the forums to see if i had a timing issue, or if i need to run the parallel api to try and solve this issue. i mainly think its a timing issue but im gunna keep tinkering with it and illl still listen on your guys' input like always
Cozzimoto #4
Posted 29 July 2013 - 02:16 PM
ok so after tinkering around alot, i have a proof of concept dynamically creating private ports on certain computer ids. expanding on the idea of hashing everything broadcasted on the public channels yes, but i did have timing issues, i learned today that i can sleep(0) to yield just long enough that a modem_message isnt triggered when i was sending a reply. code is very rough but im gunns work on it and place the beta builds in my pastebin. again i took out the RNG and encode and decode functions due to security. but here is a few screen shots and some data of the two programs i made, now i need to implement this on my banking system im creating.

Client Side

Spoiler

-- rednet security client

MODEM = peripheral.wrap("top")

local decodePort = function(TAB)
  -- TAKEN OUT
end

-- lets find the server
local serverFound = false
local connected = false
local targetServ = "bankSer"
local targetPort = nil
local count = 8
local status = 1
local credentials = {cid = os.getComputerID(), name = os.getComputerLabel(), protocol = nil}
  print("Searching..")

while not serverFound and count < 13 do -- 120 public ports
  MODEM.open(count)
  print("opened: "..count)

  if status == 1 then
	credentials.protocol = "_ping"
	MODEM.transmit(count,count,textutils.serialize(credentials))

	local T = os.startTimer(0.5)
	os.sleep(0)
	local ev = { os.pullEvent() }
	if ev[1] == "modem_message" then
	  local iC = ev[3]
	  local rC = ev[4]
	  local str = ev[5]

	  if str == "_pong" then
		status = 2
		print("PINGED!")
	  end

	  os.sleep(0)
	  if status == 2 then
		credentials.protocol = "whoareyou?"
		MODEM.transmit(count,count,textutils.serialize(credentials))

		local T = os.startTimer(0.4)
		os.sleep(0)
		local ev = { os.pullEvent() }
		if ev[1] == "modem_message" then
		  local iC = ev[3]
		  local rC = ev[4]
		  local str = ev[5]

		  if str == targetServ then
			status = 3
			serverFound = true
			targetPort = count
			print("Found Target Server, Requesting to Connect")
		  end
		end
	  end
	end  
  end

  credentials.protocol = nil
  count = count + 1
  os.sleep(0.4)
end

print("Search ended, trying to connect")

local attempts = 0
while serverFound and not connected and attempts < 3 do
  if status == 3 then
	credentials.protocol = "connectionRequest"
	MODEM.transmit(targetPort,targetPort,textutils.serialize(credentials))

	local T = os.startTimer(0.4)
	os.sleep(0)
	local ev = { os.pullEvent() }
	if ev[1] == "modem_message" then
	  local iC = ev[3]
	  local rC = ev[4]
	  local pkg = textutils.unserialize(ev[5])

	  targetPort = tonumber(decodePort(pkg))
	  print(targetPort)
	  connected = true

	end
  end

  attempts = attempts + 1
end

print("ENDOF program")


Server-Side

Spoiler

-- rednet security server

local serverProperties = {publicPort = 10, serverType = "bankSer"}
local privatePorts = {}
MODEM = peripheral.wrap("top")
MODEM.open(serverProperties.publicPort)
  print("opened: "..serverProperties.publicPort)

local RNGen = function()
  -- TAKEN OUT
end

local encodePort = function(RNG)
  -- TAKEN OUT
end

local decodePort = function(TAB)
  -- TAKEN OUT
end

while true do
  local ev = { os.pullEvent() }
  if ev[1] == "modem_message" then
	local iC = ev[3]
	local rC = ev[4]
	local pkg = textutils.unserialize(ev[5])

	if type(pkg) == "table" then -- verify if its a table
	  if pkg.cid ~= nil then -- pkg must have a cid -computer id-
		if privatePorts[pkg.cid] == nil then -- if cid isnt in memory create a slot
		  privatePorts[pkg.cid] = {name = pkg.name, port = 0}
		end
		os.sleep(0)

		if pkg.protocol == "_ping" then
		  MODEM.transmit(rC,serverProperties.publicPort,"_pong")
			print("pinged from "..pkg.cid)

		elseif pkg.protocol == "whoareyou?" then
		  MODEM.transmit(rC,serverProperties.publicPort,serverProperties.serverType)
			print("send Server ID to "..pkg.cid)

		elseif pkg.protocol == "connectionRequest" then
		  local gPort = RNGen()
		  local packet = encodePort(gPort)
		  privatePorts[pkg.cid].port = gPort
		  MODEM.open(gPort)
			print(" opened: "..gPort)
			print(" for cid: "..pkg.cid)
			print(" encoded at: "..textutils.serialize(packet))
		  MODEM.transmit(rC,serverProperties.publicPort,textutils.serialize(packet))

		elseif pkg.protocol == "connectionVerify" then
		  MODEM.transmit(rC,rC,"connectionEstablished")

		else -- if pkg.protocol doesnt exist or doesnt match
		  MODEM.transmit(rC,serverProperties.publicPort,"error: invalid protocol")
			print("invalid protocol")
		end
	  else -- if pkg.cid is nil
		MODEM.transmit(rC,serverProperties.publicPort,"error: invalid Credentials")
		  print("invalid Credentials")
	  end
	else -- if pkg is a string
	  MODEM.transmit(rC,serverProperties.publicPort,"error: invalid packet")
		print("invalid packet..")
	end
  os.sleep(0)

  elseif ev[1] == "key" then
	print(textutils.serialize(privatePorts))
	os.sleep(1.5)
  end
end

and a picture of a monitor listening to all the events happening