Compare commits

...

19 Commits

Author SHA1 Message Date
2afef5d0fe cleaning up files 2023-06-27 23:01:24 -04:00
0efb553d7c Added multi submodule for easy testing 2023-06-27 22:56:28 -04:00
eb6c7ba651 merge conflicts 2023-06-27 22:52:56 -04:00
50a6cf88f4 Changes from ages ago 2023-06-26 10:08:05 -04:00
Ryan Ward
b7636e977d testing 2022-06-16 21:32:13 -04:00
=
fbd63a9aea Doing some tests with ssl 2022-06-16 21:22:51 -04:00
e2503cf103 http/https working async now! 2021-07-17 23:33:43 -04:00
808c73cf93 http/https working async now 2021-07-17 23:33:20 -04:00
36ae77e98a Updated some files 2021-07-17 18:27:51 -04:00
a7ce660e3b Changed names to reflect package 2021-07-10 15:30:39 -04:00
4a5b9433f5 fixed rockspec 2021-07-10 15:22:17 -04:00
9d5a7b559c fixed rockspec 2021-07-10 15:21:46 -04:00
b98058f84e updated files 2021-07-10 15:19:56 -04:00
97578e5073 updated readme 2021-07-09 19:42:03 -04:00
b4a8ec0360 requests working together 2021-07-09 19:33:55 -04:00
1760935658 doing some tests 2021-07-08 22:23:01 -04:00
c61ee0537d working on tcp, not working yet 2021-07-07 22:10:19 -04:00
8f8fd31e64 Working on tcp 2021-07-06 22:17:09 -04:00
7633e87ab9 Working on rewrite 2021-07-06 08:56:48 -04:00
19 changed files with 1157 additions and 1122 deletions

3
.gitignore vendored
View File

@ -1,3 +1,6 @@
# lua-env
luajit/*
# Compiled Lua sources # Compiled Lua sources
luac.out luac.out

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "multi"]
path = multi
url = https://github.com/rayaman/multi.git

File diff suppressed because one or more lines are too long

View File

@ -1,10 +1,8 @@
# net (2.0.1) # net (5.0.0) Total Rewrite
Updated from 2.0.0 to 2.0.1
Added:
- Examples
- Support for latest multi version
- Updated readme
This readme needs to be rewritten, that will happen when all planned features are added to v5
I've returned to this project. Mainly to create a way to test my multi-tasking library. Notable features, create server/client connections that work async. Added wrapper for http and https request (multi, luasocket and luasec required) to work in coroutines without needing a lua-core modifacation.
# Discord # Discord
For real-time assistance with my libraries! A place where you can ask questions and get help with any of my libraries</br> For real-time assistance with my libraries! A place where you can ask questions and get help with any of my libraries</br>
@ -26,12 +24,12 @@ A simple and powerful way to make servers and clients
- [ ] Improve 'stable' modules - [ ] Improve 'stable' modules
- [ ] AUDP - advance udp. Ensures packets arrive and handles late packets. - [ ] AUDP - advance udp. Ensures packets arrive and handles late packets.
- [ ] P2P - peer to peer (Server to set up initial connection) - [ ] P2P - peer to peer (Server to set up initial connection)
- [ ] Relay - offput server load (locally) - [ ] Threading (requires lanes which is installed when multi is installed)
- [ ] Threading - Simple threading ~~(UDP/AUDP Only)~~ Thanks to an updated multi library we can thread with ease
- [ ] Priority handling - [ ] Priority handling
# Note # Note
You will see a bunch of files inside of the net folder. All that is stable is the init.lua and sft.lua file. Everything else is a work in progress. Plus I am planning on rewritting all of the modules to take advantage of the new threading features that are found in the new multi updates. PRogress on this will be made soon. I have just been away from my PC for a while. You will see a bunch of files inside of the net folder. All that is stable is the init.lua and sft.lua file. Everything else is a work in progress. Plus I am planning on rewritting all of the modules to take advantage of the new threading features that are found in the new multi updates. PRogress on this will be made soon. I have just been away from my PC for a while.
# Usage # Usage
server.lua server.lua
```lua ```lua
@ -39,7 +37,7 @@ require("bin") -- this library needs a lot of work it has a bunch of old useless
require("multi") -- you need this to handle multiple connections and such require("multi") -- you need this to handle multiple connections and such
require("net") -- That requires the main library require("net") -- That requires the main library
server=net:newTCPServer(12345) -- create a server that listens on port 12345 server=net:newTCPServer(12345) -- create a server that listens on port 12345
server.OnDataRecieved(function(self,data,CID_OR_HANDLE,IP_OR_HANDLE,PORT_OR_IP,UPDATER_OR_NIL) -- a bit confusing, but dont worry you will hardly ever need more then the first 5 arguments, unless you are writing modules! server.OnDataRecieved(function(self, data, CID, IP, PORT) -- a bit confusing, but dont worry you will hardly ever need more then the first 5 arguments, unless you are writing modules!
if data=="Hello!" then if data=="Hello!" then
print("Got response from client sending back data!") print("Got response from client sending back data!")
self:send(IP_OR_HANDLE,"Hello Client!",PORT_OR_IP) -- doing it like this makes this code work for both udp and tcp self:send(IP_OR_HANDLE,"Hello Client!",PORT_OR_IP) -- doing it like this makes this code work for both udp and tcp

View File

@ -1,17 +1,29 @@
package.path="?/init.lua;"..package.path package.path = "./?/init.lua;./?.lua;"..package.path
local multi = require("multi") local net = require("lnet.tcp")
local net = require("net") local multi, thread = require("multi"):init()
client = net:newTCPClient("localhost",12345) --
client:enableBinaryMode() -- local http = require("lnet.http")
local file = bin.new() -- local http_ = require("socket.http")
client.OnDataRecieved(function(self,data)
if data == "END" then local https = require("lnet.https")
file:tofile("test2.mp3")
print("File transfered!") -- multi:newThread("Timer",function()
else -- while true do
file:tackE(data) -- thread.sleep(8)
end -- print("...")
end) -- end
client.OnClientReady:holdUT() -- waits until the client is ready... You can also connect to this event as well and have code do stuff too -- end)
client:send("Hello Server!") -- download("http://212.183.159.230/5MB.zip","test1.bin")
multi:mainloop() -- download("http://212.183.159.230/50MB.zip","test2.bin").OnError(print)
print(https.request("https://erowall.com/wallpapers/large/32757.jpg"))
-- local client = net.newCastedClient("Test")--net:newTCPClient("localhost",12345)
-- client:send("Test!")
-- client.OnDataRecieved(function(c,data)
-- print("Response: ",data)
-- end)
--multi:mainloop()

35
lnet/base/client.lua Normal file
View File

@ -0,0 +1,35 @@
local multi, thread = require("multi"):init()
local client = {}
client.__index = client
client.updaterRate = 1
client.sMode = "*l"
client.rMode = "*l"
function client:init(type)
self.Type = type
self.OnDataRecieved = multi:newConnection()
self.OnServerNotAvailable = multi:newConnection()
self.OnClientReady = multi:newConnection()
self.OnClientDisconnected = multi:newConnection()
self.OnConnectionRegained = multi:newConnection()
self.OnPreSend = multi:newConnection()
self.OnPreRecieved = multi:newConnection()
self.OnError = multi:newConnection()
self.process = multi:newProcessor()
self.process.Start()
end
function client:send(data)
-- Override this function
end
function client:close()
-- Override this function
end
function client:setUpdateRate(n)
self.updaterRate = n
end
function client:setReceiveMode(mode)
self.rMode = mode
end
function client:setSendMode(mode)
self.sMode = mode
end
return client

87
lnet/base/server.lua Normal file
View File

@ -0,0 +1,87 @@
local multi, thread = require("multi"):init()
local socket = require("socket")
local net = require("lnet")
local server = {}
local bCaster = 0
server.__index = server
server.updaterRate = 1
server.rMode = "*l"
server.sMode = "*l"
function server:init(type)
self.Type = type
self.OnClientsModulesList = multi:newConnection()
self.OnPreRecieved = multi:newConnection()
self.OnDataRecieved = multi:newConnection()
self.OnClientClosed = multi:newConnection()
self.OnClientConnected = multi:newConnection()
self.OnPreSend = multi:newConnection()
self.idleRate = 5
self.clientHandlers = {}
self.bannedCIDs = {}
self.bannedIPs = {}
self.broad = socket.udp()
self.localIP = net.getLocalIP()
self.ips = {}
self.links = {}
self.cids = {}
self.process = multi:newProcessor()
self.process.Start()
end
function server:setIdleRate(minutes)
self.idleRate = minutes
end
function server:setUpdateRate(n)
self.updaterRate = n
end
function server:banCID(cid)
table.insert(self.bannedCIDs,cid)
end
function server:banIP(ip)
table.insert(self.bannedIPs)
end
function server:setRecieveMode(mode)
self.rMode = mode
end
function server:setSendMode(mode)
self.sMode = mode
end
function server:broadcast(name)
if not self.isBroadcasting then
bCaster = bCaster + 1
self.isBroadcasting = true
self.process:newThread("Broadcast Handler<"..bCaster..">",function()
while true do
thread.yield()
self.broad:setoption("broadcast",true)
self.broad:sendto(table.concat({name,self.Type,self.localIP},"|")..":"..self.port, "255.255.255.255", 11111)
-- Send to localhost as well
self.broad:sendto(table.concat({name,self.Type,self.localIP},"|")..":"..self.port, self.localIP, 11111)
self.broad:setoption("broadcast", false)
end
end)
end
end
function server:send(cid,data)
-- Override this
end
function server:getCid(ip,port)
if self.cids[ip .. port] then
return self.cids[ip .. port]
end
end
function server:sendAll(data)
for i,v in pairs(self.cids) do
self:send(data,cid)
end
end
function server:sendAllBut(data,cid)
for i,v in pairs(self.cids) do
if v~=cid then
self:send(data,cid)
end
end
end
function server:clientRegistered(cid)
return self.cids[cid]
end
return server

372
lnet/http.lua Normal file
View File

@ -0,0 +1,372 @@
-----------------------------------------------------------------------------
-- HTTP/1.1 client support for the Lua language.
-- LuaSocket toolkit.
-- Author: Diego Nehab
-----------------------------------------------------------------------------
-----------------------------------------------------------------------------
-- Declare module and import dependencies
-------------------------------------------------------------------------------
local net = require("lnet")
local multi, thread = require("multi"):init()
local socket = require("socket")
local url = require("socket.url")
local ltn12 = require("ltn12")
local mime = require("mime")
local string = require("string")
local headers = require("socket.headers")
local base = _G
local table = require("table")
net.http = {}
local _M = net.http
local default_block_size = 1024
-----------------------------------------------------------------------------
-- Program constants
-----------------------------------------------------------------------------
-- connection timeout in seconds
TIMEOUT = 60
-- default port for document retrieval
_M.PORT = 80
-- user agent field sent in request
_M.USERAGENT = socket._VERSION
-----------------------------------------------------------------------------
-- Reads MIME headers from a connection, unfolding where needed
-----------------------------------------------------------------------------
local function receiveheaders(sock, headers)
local line, name, value, err
headers = headers or {}
-- get first line
line, err = sock:receive()
if err then return nil, err end
-- headers go until a blank line is found
while line ~= "" do
-- get field-name and value
name, value = socket.skip(2, string.find(line, "^(.-):%s*(.*)"))
if not (name and value) then return nil, "malformed reponse headers" end
name = string.lower(name)
-- get next line (value might be folded)
line, err = sock:receive()
if err then return nil, err end
-- unfold any folded values
while string.find(line, "^%s") do
value = value .. line
line = sock:receive()
if err then return nil, err end
end
-- save pair in table
if headers[name] then headers[name] = headers[name] .. ", " .. value
else headers[name] = value end
end
return headers
end
-----------------------------------------------------------------------------
-- Extra sources and sinks
-----------------------------------------------------------------------------
socket.sourcet["http-chunked"] = function(sock, headers)
return base.setmetatable({
getfd = function() return sock:getfd() end,
dirty = function() return sock:dirty() end
}, {
__call = function()
-- get chunk size, skip extention
local line, err = sock:receive()
if err then return nil, err end
local size = base.tonumber(string.gsub(line, ";.*", ""), 16)
if not size then return nil, "invalid chunk size" end
-- was it the last chunk?
if size > 0 then
-- if not, get chunk and skip terminating CRLF
local chunk, err, part = sock:receive(size)
if chunk then sock:receive() end
return chunk, err
else
-- if it was, read trailers into headers table
headers, err = receiveheaders(sock, headers)
if not headers then return nil, err end
end
end
})
end
socket.sinkt["http-chunked"] = function(sock)
return base.setmetatable({
getfd = function() return sock:getfd() end,
dirty = function() return sock:dirty() end
}, {
__call = function(self, chunk, err)
if not chunk then return sock:send("0\r\n\r\n") end
local size = string.format("%X\r\n", string.len(chunk))
return sock:send(size .. chunk .. "\r\n")
end
})
end
-----------------------------------------------------------------------------
-- Low level HTTP API
-----------------------------------------------------------------------------
local metat = { __index = {} }
function _M.open(host, port, create)
-- create socket with user connect function, or with default
local c = socket.try((create or socket.tcp)())
local h = base.setmetatable({ c = c }, metat)
-- create finalized try
h.try = socket.newtry(function() h:close() end)
-- set timeout before connecting
h.try(c:settimeout(_M.TIMEOUT))
h.try(c:connect(host, port or _M.PORT))
-- here everything worked
return h
end
function metat.__index:sendrequestline(method, uri)
local reqline = string.format("%s %s HTTP/1.1\r\n", method or "GET", uri)
return self.try(self.c:send(reqline))
end
function metat.__index:sendheaders(tosend)
local canonic = headers.canonic
local h = "\r\n"
for f, v in base.pairs(tosend) do
h = (canonic[f] or f) .. ": " .. v .. "\r\n" .. h
end
self.try(self.c:send(h))
return 1
end
function metat.__index:sendbody(headers, source, step)
source = source or ltn12.source.empty()
step = step or ltn12.pump.step
-- if we don't know the size in advance, send chunked and hope for the best
local mode = "http-chunked"
if headers["content-length"] then mode = "keep-open" end
return self.try(ltn12.pump.all(source, socket.sink(mode, self.c), step))
end
function metat.__index:receivestatusline()
local status = self.try(self.c:receive(5))
-- identify HTTP/0.9 responses, which do not contain a status line
-- this is just a heuristic, but is what the RFC recommends
if status ~= "HTTP/" then return nil, status end
-- otherwise proceed reading a status line
status = self.try(self.c:receive("*l", status))
local code = socket.skip(2, string.find(status, "HTTP/%d*%.%d* (%d%d%d)"))
return self.try(base.tonumber(code), status)
end
function metat.__index:receiveheaders()
return self.try(receiveheaders(self.c))
end
function metat.__index:receivebody(headers, sink, step)
sink = sink or ltn12.sink.null()
step = step or ltn12.pump.step
local length = base.tonumber(headers["content-length"])
local t = headers["transfer-encoding"] -- shortcut
local mode = "default" -- connection close
if t and t ~= "identity" then mode = "http-chunked"
elseif base.tonumber(headers["content-length"]) then mode = "by-length" end
local ret,lp
lp = length%default_block_size
for i=1,math.floor(length/default_block_size) do
thread.yield()
ret = self.try(ltn12.pump.step(socket.source(mode, self.c, default_block_size), sink, step))
thread.pushStatus(i,math.floor(length/default_block_size))
end
if lp~=0 then
ret = self.try(ltn12.pump.step(socket.source(mode, self.c, lp), sink, step))
end
return ret
end
function metat.__index:receive09body(status, sink, step)
local source = ltn12.source.rewind(socket.source("until-closed", self.c))
source(status)
return self.try(ltn12.pump.all(source, sink, step))
end
function metat.__index:close()
return self.c:close()
end
-----------------------------------------------------------------------------
-- High level HTTP API
-----------------------------------------------------------------------------
local function adjusturi(reqt)
local u = reqt
-- if there is a proxy, we need the full url. otherwise, just a part.
if not reqt.proxy and not PROXY then
u = {
path = socket.try(reqt.path, "invalid path 'nil'"),
params = reqt.params,
query = reqt.query,
fragment = reqt.fragment
}
end
return url.build(u)
end
local function adjustproxy(reqt)
local proxy = reqt.proxy or PROXY
if proxy then
proxy = url.parse(proxy)
return proxy.host, proxy.port or 3128
else
return reqt.host, reqt.port
end
end
local function adjustheaders(reqt)
-- default headers
local lower = {
["user-agent"] = _M.USERAGENT,
["host"] = reqt.host,
["connection"] = "close, TE",
["te"] = "trailers"
}
-- if we have authentication information, pass it along
if reqt.user and reqt.password then
lower["authorization"] =
"Basic " .. (mime.b64(reqt.user .. ":" .. reqt.password))
end
-- override with user headers
for i,v in base.pairs(reqt.headers or lower) do
lower[string.lower(i)] = v
end
return lower
end
-- default url parts
local default = {
host = "",
port = _M.PORT,
path ="/",
scheme = "http"
}
local function adjustrequest(reqt)
-- parse url if provided
local nreqt = reqt.url and url.parse(reqt.url, default) or {}
-- explicit components override url
for i,v in base.pairs(reqt) do nreqt[i] = v end
if nreqt.port == "" then nreqt.port = 80 end
socket.try(nreqt.host and nreqt.host ~= "",
"invalid host '" .. base.tostring(nreqt.host) .. "'")
-- compute uri if user hasn't overriden
nreqt.uri = reqt.uri or adjusturi(nreqt)
-- ajust host and port if there is a proxy
nreqt.host, nreqt.port = adjustproxy(nreqt)
-- adjust headers in request
nreqt.headers = adjustheaders(nreqt)
return nreqt
end
local function shouldredirect(reqt, code, headers)
return headers.location and
string.gsub(headers.location, "%s", "") ~= "" and
(reqt.redirect ~= false) and
(code == 301 or code == 302 or code == 303 or code == 307) and
(not reqt.method or reqt.method == "GET" or reqt.method == "HEAD")
and (not reqt.nredirects or reqt.nredirects < 5)
end
local function shouldreceivebody(reqt, code)
if reqt.method == "HEAD" then return nil end
if code == 204 or code == 304 then return nil end
if code >= 100 and code < 200 then return nil end
return 1
end
-- forward declarations
local trequest, tredirect
--[[local]] function tredirect(reqt, location)
local result, code, headers, status = trequest {
-- the RFC says the redirect URL has to be absolute, but some
-- servers do not respect that
url = url.absolute(reqt.url, location),
source = reqt.source,
sink = reqt.sink,
headers = reqt.headers,
proxy = reqt.proxy,
nredirects = (reqt.nredirects or 0) + 1,
create = reqt.create
}
-- pass location header back as a hint we redirected
headers = headers or {}
headers.location = headers.location or location
return result, code, headers, status
end
-- We don't need to protect this function the thread:newFunction wrapper handles errors for us
function trequest(reqt)
-- we loop until we get what we want, or
-- until we are sure there is no way to get it
local nreqt = adjustrequest(reqt)
local h = _M.open(nreqt.host, nreqt.port, nreqt.create)
-- send request line and headers
h:sendrequestline(nreqt.method, nreqt.uri)
h:sendheaders(nreqt.headers)
-- if there is a body, send it
if nreqt.source then
h:sendbody(nreqt.headers, nreqt.source, nreqt.step)
end
local code, status = h:receivestatusline()
-- if it is an HTTP/0.9 server, simply get the body and we are done
if not code then
h:receive09body(status, nreqt.sink, nreqt.step)
return 1, 200
end
local headers
-- ignore any 100-continue messages
while code == 100 do
headers = h:receiveheaders()
code, status = h:receivestatusline()
end
headers = h:receiveheaders()
-- at this point we should have a honest reply from the server
-- we can't redirect if we already used the source, so we report the error
if shouldredirect(nreqt, code, headers) and not nreqt.source then
h:close()
return tredirect(reqt, headers.location)
end
-- here we are finally done
if shouldreceivebody(nreqt, code) then
h:receivebody(headers, nreqt.sink, nreqt.step)
end
h:close()
return 1, code, headers, status
end
local function srequest(u, b)
local t = {}
local reqt = {
url = u,
sink = ltn12.sink.table(t)
}
if b then
reqt.source = ltn12.source.string(b)
reqt.headers = {
["content-length"] = string.len(b),
["content-type"] = "application/x-www-form-urlencoded"
}
reqt.method = "POST"
end
local code, headers, status = socket.skip(1, trequest(reqt))
local data = table.concat(t)
if #data>0 then
return data, code, headers, status
else
return nil, code, headers, status
end
end
_M.request = thread:newFunction(function(reqt, body)
if base.type(reqt) == "string" then return srequest(reqt, body)
else return trequest(reqt) end
end,true)
return _M

146
lnet/https.lua Normal file
View File

@ -0,0 +1,146 @@
----------------------------------------------------------------------------
-- LuaSec 1.0.1
-- Copyright (C) 2009-2021 PUC-Rio
--
-- Author: Pablo Musa
-- Author: Tomas Guisasola
---------------------------------------------------------------------------
local socket = require("socket")
local ssl = require("ssl")
local ltn12 = require("ltn12")
local http = require("lnet.http")
local url = require("socket.url")
local try = socket.try
--
-- Module
--
local _M = {
_VERSION = "1.0.1",
_COPYRIGHT = "LuaSec 1.0.1 - Copyright (C) 2009-2021 PUC-Rio",
PORT = 443,
TIMEOUT = 60
}
-- TLS configuration
local cfg = {
protocol = "any",
options = {"all", "no_sslv2", "no_sslv3", "no_tlsv1"},
verify = "none",
}
--------------------------------------------------------------------
-- Auxiliar Functions
--------------------------------------------------------------------
-- Insert default HTTPS port.
local function default_https_port(u)
return url.build(url.parse(u, {port = _M.PORT}))
end
-- Convert an URL to a table according to Luasocket needs.
local function urlstring_totable(url, body, result_table)
url = {
url = default_https_port(url),
method = body and "POST" or "GET",
sink = ltn12.sink.table(result_table)
}
if body then
url.source = ltn12.source.string(body)
url.headers = {
["content-length"] = #body,
["content-type"] = "application/x-www-form-urlencoded",
}
end
return url
end
-- Forward calls to the real connection object.
local function reg(conn)
local mt = getmetatable(conn.sock).__index
for name, method in pairs(mt) do
if type(method) == "function" then
conn[name] = function (self, ...)
return method(self.sock, ...)
end
end
end
end
-- Return a function which performs the SSL/TLS connection.
local function tcp(params)
params = params or {}
-- Default settings
for k, v in pairs(cfg) do
params[k] = params[k] or v
end
-- Force client mode
params.mode = "client"
-- 'create' function for LuaSocket
return function ()
local conn = {}
conn.sock = try(socket.tcp())
local st = getmetatable(conn.sock).__index.settimeout
function conn:settimeout(...)
return st(self.sock, _M.TIMEOUT)
end
-- Replace TCP's connection function
function conn:connect(host, port)
try(self.sock:connect(host, port))
self.sock = try(ssl.wrap(self.sock, params))
self.sock:sni(host)
self.sock:settimeout(_M.TIMEOUT)
try(self.sock:dohandshake())
reg(self, getmetatable(self.sock))
return 1
end
return conn
end
end
--------------------------------------------------------------------
-- Main Function
--------------------------------------------------------------------
-- Make a HTTP request over secure connection. This function receives
-- the same parameters of LuaSocket's HTTP module (except 'proxy' and
-- 'redirect') plus LuaSec parameters.
--
-- @param url mandatory (string or table)
-- @param body optional (string)
-- @return (string if url == string or 1), code, headers, status
--
local function request(url, body)
local result_table = {}
local stringrequest = type(url) == "string"
if stringrequest then
url = urlstring_totable(url, body, result_table)
else
url.url = default_https_port(url.url)
end
if http.PROXY or url.proxy then
return nil, "proxy not supported"
elseif url.redirect then
return nil, "redirect not supported"
elseif url.create then
return nil, "create function not permitted"
end
-- New 'create' function to establish a secure connection
url.create = tcp(url)
local res, code, headers, status = http.request(url)
if res and stringrequest then
return table.concat(result_table), code, headers, status
end
return res, code, headers, status
end
--------------------------------------------------------------------------------
-- Export module
--
_M.request = request
_M.tcp = tcp
return _M

195
lnet/init.lua Normal file
View File

@ -0,0 +1,195 @@
--[[
UPCOMMING ADDITIONS
AUDP - advance udp. Ensures packets arrive and handles late packets.
P2P - peer to peer (Server to set up initial connection)
Relay - offput server load (locally)
Threading - Simple threading ~~(UDP/AUDP Only)~~ Thanks to an updated multi library we can thread with ease
Priority handling
]]
--[[
TODO: Finish stuff for Priority handling
]]
function table.merge(t1, t2)
for k, v in pairs(t2) do
if type(v) == "table" then
if type(t1[k] or false) == "table" then
table.merge(t1[k] or {}, t2[k] or {})
else
t1[k] = v
end
else
t1[k] = v
end
end
return t1
end
function string.trim(s)
local from = s:match "^%s*()"
return from > #s and "" or s:match(".*%S", from)
end
local guid = {}
local char = {}
for i = 48, 57 do
char[#char + 1] = string.char(i)
end
for i = 65, 90 do
char[#char + 1] = string.char(i)
end
for i = 97, 122 do
char[#char + 1] = string.char(i)
end
math.random()
math.random()
math.random()
local multi, thread = require("multi").init()
local socket = require("socket")
local http = require("socket.http")
--ssl=require("ssl")
--https=require("ssl.https")
local net = {}
net.Version = {5, 0, 0} -- This will probably stay this version for quite a while... The modules on the otherhand will change more often
net._VERSION = "5.0.0"
net.ClientCache = {}
net.OnServerCreated = multi:newConnection()
net.OnClientCreated = multi:newConnection()
net.loadedModules = {}
net.OnCastedClientInfo = multi:newConnection()
net.autoInit = true
net.ConnectionDriver = {}
net.BroadcastDriver = {}
math.randomseed(math.ceil(os.time()+(os.clock()*1000)))
local isHyphen = {[9] = 1, [14] = 1, [19] = 1, [24] = 1}
net.generateGUID = function(t)
local pass = {}
local a = 0
local x = ""
for i in string.format("%x",os.time()+math.ceil(os.time()+os.clock()*1000)):gmatch(".") do
table.insert(pass,i)
end
for z = 9, 36 do
if isHyphen[z] then
x = "-"
else
a = math.random(1, #char)
x = char[a]
end
table.insert(pass, x)
if t == z then
break
end
end
z = nil
return tostring(table.concat(pass))
end
function net.normalize(input)
local enc = mime.b64(input)
return enc
end
function net.denormalize(input)
local unenc = mime.unb64(input)
return unenc
end
function net.getLocalIP()
local someRandomIP = "192.168.1.122"
local someRandomPort = "3102"
local mySocket = socket.udp()
mySocket:setpeername(someRandomIP, someRandomPort)
local dat = (mySocket:getsockname())
mySocket:close()
return dat
end
function net.getExternalIP()
local data = http.request("http://www.myipnumber.com/my-ip-address.asp")
return data:match("(%d+%.%d+%.%d+%.%d+)")
end
function net.registerModule(mod, version)
if net[mod] then
error("Module by the name: " .. mod .. " has already been registered! Remember some modules are internal and use certain names!")
end
table.insert(net.loadedModules, mod)
net[mod] = {}
if version then
net[mod].Version = version
net[mod]._VERSION = table.concat(version,".")
else
net[mod].Version = {1, 0, 0}
net[mod]._VERSION = {1, 0, 0}
end
return {Version = version, _VERSION = table.concat(version,".")}
end
function net.getModuleVersion(ext)
if not ext then
return string.format("%d.%d.%d", net.Version[1], net.Version[2], net.Version[3])
end
return string.format("%d.%d.%d", net[ext].Version[1], net[ext].Version[2], net[ext].Version[3])
end
function net.resolveID(obj)
local num = math.random(10000000, 99999999)
if obj[tostring(num)] then
return net.resolveID(obj)
end
obj.ids[tostring(num)] = true
return tostring(num)
end
function net.inList(list, dat)
for i, v in pairs(list) do
if v == dat then
return true
end
end
return false
end
function net.setTrigger(funcW, funcE)
multi:newTrigger(func)
end
net.registerModule("net", net.Version)
-- Client broadcast
function net.newCastedClient(name) -- connects to the broadcasted server
local listen = socket.udp() -- make a new socket
listen:setsockname(net.getLocalIP(), 11111)
listen:settimeout(0)
local timer = multi:newTimer()
while true do
local data, ip, port = listen:receivefrom()
if timer:Get() > 3 then
error("Timeout! Server by the name: " .. name .. " has not been found!")
end
if data then
local n, tp, ip, port = data:match("(%S-)|(%S-)|(%S-):(%d+)")
if n:match(name) then
if tp == "tcp" then
return net.newTCPClient(ip, tonumber(port))
else
return net.newClient(ip, tonumber(port))
end
end
end
end
end
function net.newCastedClients(name) -- connects to the broadcasted server
local listen = socket.udp() -- make a new socket
listen:setsockname(net.getLocalIP(), 11111)
listen:settimeout(0)
multi:newThread("net.castedTask",function()
while true do
thread.skip(24)
local data, ip, port = listen:receivefrom()
if data then
local n, tp, ip, port = data:match("(%S-)|(%S-)|(%S-):(%d+)")
if n:match(name) and not net.ClientCache[n] then
local capture = n:match(name)
local client = {}
if tp == "tcp" then
client = net:newTCPClient(ip, tonumber(port))
else
client = net:newUDPClient(ip, tonumber(port))
end
net.ClientCache[n] = client
net.OnCastedClientInfo:Fire(client, n, ip, port)
end
end
end
end)
end
return net

135
lnet/tcp/init.lua Normal file
View File

@ -0,0 +1,135 @@
local net = require("lnet")
local clientbase = require("lnet.base.client")
local serverbase = require("lnet.base.server")
local multi, thread = require("multi"):init()
local socket = require("socket")
local tcpcount = 0
net.newTCPServer = thread:newFunction(function(port)
local c = {}
setmetatable(c,serverbase)
c:init("tcp")
c.tcp = assert(socket.bind("*", port or 0))
c.tcp:settimeout(0)
c.ip, c.port = c.tcp:getsockname()
if port and port == 0 then
_, c.port = c.tcp:getsockname()
end
function c:send(cid,data)
local dat = {data = data, cid = cid}
self.OnPreSend:Fire(dat)
if self.sMode == "*l" then
cid:send(data .. "\n")
else
cid:send(data)
end
end
tcpcount = tcpcount + 1
c.updateThread = c.process:newThread("TCPServer Thread<"..tcpcount..">",function()
while true do
thread.skip(c.updaterRate)
local client = c.tcp:accept(c.rMode)
if client then
print("Got Client!")
table.insert(c.ips, client)
client:settimeout(0)
client:setoption("keepalive", true)
ip, port = client:getpeername()
if ip and port then
c.OnClientConnected:Fire(c, client, ip, port)
-- We need to cache the client handler so we can work with it
c.clientHandlers[client] = multi:newThread("ServerClientHandler<".. tostring(client):match(": (.+)") ..">",function()
local cli = client
while true do
thread.yield()
local data, err, dat, len
data, err = thread.hold(function()
data, err = cli:receive(c.rMode)
if data then print(data) end
if data~=nil and err then
print(err)
return multi.NIL, err
end
return data
end)
if err == "closed" then
for i = 1, #c.ips do
if c.ips[i] == cli then
table.remove(c.ips, i)
end
end
c.OnClientClosed:Fire(c, "Client Closed Connection!", cli, ip)
c.links[cli] = nil -- lets clean up
thread.kill()
end
if data then
if net.inList(c.bannedIPs, ip) then
return
end
c.OnDataRecieved:Fire(c, data, cli, ip, port)
end
end
end)
end
end
end
end).OnError(function(...)
print(...)
end)
net.OnServerCreated:Fire(c)
return c
end,true)
net.newTCPClient = thread:newFunction(function(host, port)
local c = {}
setmetatable(c,clientbase)
c:init("tcp")
c.ip = assert(socket.dns.toip(host))
c.tcp = socket.connect(c.ip,port)
c.tcp:settimeout(0)
c.tcp:setoption("keepalive",true)
function c:send(data)
if self.sMode == "*l" then
data = data .. "\n"
end
print("Sending:",data)
local dat = {data = data}
self.OnPreSend:Fire(dat)
local ind, err = self.tcp:send(dat.data)
print(ind,err)
print("Data Sent!")
if err == "closed" then
self.OnClientDisconnected:Fire(self,err)
elseif err == "timeout" then
self.OnClientDisconnected:Fire(self,err)
end
end
c.updateThread = c.process:newThread("TCPClient Thread<"..tcpcount..">",function()
while true do
thread.skip(c.updaterRate)
local data = thread.hold(function()
local d,err = c.tcp:receive(c.rMode)
if not(d) then
if err == "closed" then
c.OnClientDisconnected:Fire(c,err)
elseif err == "timeout" then
c.OnClientDisconnected:Fire(c,err)
else
print(err)
end
else
return d
end
end)
if data then
local dat = {data = data}
c.OnPreRecieved:Fire(dat)
c.OnDataRecieved:Fire(c,dat.data)
end
end
end).OnError(function(...)
print(...)
end)
net.OnClientCreated:Fire(c)
return c
end,true)
return net

102
lnet/udp/init.lua Normal file
View File

@ -0,0 +1,102 @@
local net = require("lnet")
local clientbase = require("lnet.base.client")
local serverbase = require("lnet.base.server")
local multi, thread = require("multi"):init()
local CID = {}
CID.__index = cid
local udpcount = 0
CID.ip = "0.0.0.0"
CID.port = 0
net.newUDPServer = thread:newFunction(function(port)
local c = {}
setmetatable(c,serverbase)
c:init("udp")
c.udp = assert(socket.udp())
c.udp:settimeout(0)
c.udp:setsockname("*",port)
local inactivity = {}
if port == 0 then
_,c.port = c.udp:getsockname()
else
c.port = port
end
udpcount = udpcount + 1
function c:send(cid,data)
local dat = {data = data, cid = cid}
self.OnPreSend:Fire(dat)
self.udp:sendto(dat.data,dat.cid.ip,dat.cid.port)
end
c.updateThread = c.process:newThread("UDPServer Thread<"..udpcount..">",function()
-- Every now and then we are going to check to see if a client has been inactive
local sideJob = thread:newFunction(function()
thread.sleep(60*c.idleRate)
for i,v in pairs(c.cids) do
thread.skip(1)
if os.clock() - v.activity >= 60*c.idleRate then
c.OnClientClosed:Fire(v)
c.cids[i] = nil
end
end
return true
end)
while true do
thread.skip(c.updaterRate)
local data, ip, port = c.udp:receivefrom()
sideJob().connect(function(yes)
if yes then
sideJob:Resume()
end
end)
sideJob:Pause()
if data then
local cid = c:getCid(ip,port)
if not cid then
local cd = {}
setmetatable(cd,CID)
cd.ip = ip
cd.port = port
cd.activity = os.clock()
c.cids[ip .. port] = cd
cid = cd
c.OnClientConnected:Fire(c, cd, ip, port)
end
cid.activity = os.clock()
local dat = {data = data,cid = cid}
c.OnPreRecieved:Fire(dat)
c.OnDataRecieved:Fire(c,dat.data,dat.cid,cid.ip,cid.port)
end
end
end).OnError(function(...)
print(...)
end)
net.OnServerCreated:Fire(c)
return c
end,true)
net.newUDPClient = thread:newFunction(function(host, port)
local c = {}
setmetatable(c,clientbase)
c:init("udp")
c.ip = assert(socket.dns.toip(host))
c.udp = assert(socket.udp())
c.udp:settimeout(0)
c.udp:setpeername(c.ip,port)
function c:send(data)
local dat = {data = data}
self.OnPreSend:Fire(dat)
self.udp:send(dat.data)
end
c.updateThread = c.process:newThread("UDPServer Thread<"..udpcount..">",function()
while true do
thread.skip(c.updaterRate)
local data = thread.hold(function()
return c.udp:receive()
end)
local dat = {data = data}
c.OnPreRecieved:Fire(dat)
c.OnDataRecieved:Fire(c,dat.data)
end
end)
net.OnClientCreated:Fire(c)
return c
end,true)
return net

1
multi Submodule

@ -0,0 +1 @@
Subproject commit d36204c87f5c63a4e6f7510040e495bbab3de2d1

View File

@ -1,893 +0,0 @@
--[[
UPCOMMING ADDITIONS
AUDP - advance udp. Ensures packets arrive and handles late packets.
P2P - peer to peer (Server to set up initial connection)
Relay - offput server load (locally)
Threading - Simple threading ~~(UDP/AUDP Only)~~ Thanks to an updated multi library we can thread with ease
Priority handling
]]
--[[
TODO: Finish stuff for Priority handling
]]
function table.merge(t1, t2)
for k,v in pairs(t2) do
if type(v) == 'table' then
if type(t1[k] or false) == 'table' then
table.merge(t1[k] or {}, t2[k] or {})
else
t1[k] = v
end
else
t1[k] = v
end
end
return t1
end
function string.trim(s)
local from = s:match"^%s*()"
return from > #s and "" or s:match(".*%S", from)
end
local guid = {}
local char = {}
for i = 48,57 do
char[#char+1]=string.char(i)
end
for i = 65,90 do
char[#char+1]=string.char(i)
end
for i = 97,122 do
char[#char+1]=string.char(i)
end
local isHyphen = {[9]=1,[14]=1,[19]=1,[24]=1}
math.randomseed(os.time())
local multi = require("multi")
local socket=require("socket")
local http=require("socket.http")
local mime=require("mime")
--ssl=require("ssl")
--https=require("ssl.https")
local net={}
net.Version={3,0,0} -- This will probably stay this version for quite a while... The modules on the otherhand will be more inconsistant
net._VERSION="3.0.0"
net.ClientCache = {}
net.OnServerCreated=multi:newConnection()
net.OnClientCreated=multi:newConnection()
net.loadedModules={}
net.OnCastedClientInfo=multi:newConnection()
net.autoInit=true
net.ConnectionDriver = {}
net.BroadcastDriver = {}
net.generateGUID = function(t)
local pass = {}
local a=0
local x=""
for z = 1,36 do
if isHyphen[z] then
x='-'
else
a = math.random(1,#char)
x = char[a]
end
table.insert(pass, x)
if t == z then break end
end
z = nil
return tostring(table.concat(pass))
end
function net.normalize(input)
local enc=mime.b64(input)
return enc
end
function net.denormalize(input)
local unenc=mime.unb64(input)
return unenc
end
function net.getLocalIP()
local someRandomIP = "192.168.1.122"
local someRandomPort = "3102"
local mySocket = socket.udp()
mySocket:setpeername(someRandomIP,someRandomPort)
local dat = (mySocket:getsockname())
mySocket:close()
return dat
end
function net.getExternalIP()
local data=http.request("http://whatismyip.host")
return data:match("(%d+.%d+.%d+.%d+)")
end
function net:registerModule(mod,version)
if net[mod] then
error("Module by the name: "..mod.." has already been registered! Remember some modules are internal and use certain names!")
end
table.insert(self.loadedModules,mod)
net[mod]={}
if version then
net[mod].Version=version
net[mod]._VERSION=version[1].."."..version[2].."."..version[3]
else
net[mod].Version={1,0,0}
net[mod]._VERSION={1,0,0}
end
return {Version=version,_VERSION=version[1].."."..version[2].."."..version[3]}
end
function net.getModuleVersion(ext)
if not ext then
return string.format("%d.%d.%d",net.Version[1],net.Version[2],net.Version[3])
end
return string.format("%d.%d.%d",net[ext].Version[1],net[ext].Version[2],net[ext].Version[3])
end
function net.resolveID(obj)
local num=math.random(10000000,99999999)
if obj[tostring(num)] then
return net.resolveID(obj)
end
obj.ids[tostring(num)]=true
return tostring(num)
end
function net.inList(list,dat)
for i,v in pairs(list) do
if v==dat then
return true
end
end
return false
end
function net.setTrigger(funcW,funcE)
multi:newTrigger(func)
end
net:registerModule("net",net.Version)
-- Client broadcast
function net:newCastedClient(name) -- connects to the broadcasted server
local listen = socket.udp() -- make a new socket
listen:setsockname(net.getLocalIP(), 11111)
listen:settimeout(0)
local timer=multi:newTimer()
while true do
local data, ip, port = listen:receivefrom()
if timer:Get()>3 then
error("Timeout! Server by the name: "..name.." has not been found!")
end
if data then
print("found!",data)
local n,tp,ip,port=data:match("(%S-)|(%S-)|(%S-):(%d+)")
if n:match(name) then
print("Found Server!",n,tp,ip,port)
if tp=="tcp" then
return net:newTCPClient(ip,tonumber(port))
else
return net:newClient(ip,tonumber(port))
end
end
end
end
end
function net:newCastedClients(name) -- connects to the broadcasted server
local listen = socket.udp() -- make a new socket
listen:setsockname(net.getLocalIP(), 11111)
listen:settimeout(0)
multi:newTLoop(function(self)
local data, ip, port = listen:receivefrom()
if data then
local n,tp,ip,port=data:match("(%S-)|(%S-)|(%S-):(%d+)")
if n:match(name) and not net.ClientCache[n] then
local capture = n:match(name)
local client = {}
if tp=="tcp" then
client=net:newTCPClient(ip,tonumber(port))
else
client=net:newUDPClient(ip,tonumber(port))
end
net.ClientCache[n]=client
net.OnCastedClientInfo:Fire(client,n,ip,port)
end
end
end,.1):setName("net.castedTask")
end
-- UDP Stuff
function net:newUDPServer(port,servercode,nonluaServer)
local c={}
c.udp=assert(socket.udp())
c.udp:settimeout(0)
c.udp:setsockname("*", port)
c.ips={}
c.Type="udp"
if port == 0 then
_, c.port = c.udp:getsockname()
end
c.ids={}
c.servercode=servercode
c.bannedIPs={}
c.bannedCIDs={}
c.autoNormalization=false
function c:setUpdateRate(n)
print("Not needed in a udp server!")
end
function c:banCID(cid)
table.insert(self.bannedCIDs,cid)
end
function c:banIP(ip)
table.insert(self.bannedIPs,cid)
end
c.broad=socket.udp()
c.hostip=net.getLocalIP()
function c:broadcast(name)
table.insert(net.BroadcastDriver,function(loop,dt)
self.broad:setoption('broadcast',true)
self.broad:sendto(name.."|"..self.Type.."|"..self.hostip..":"..self.port, "255.255.255.255", 11111)
self.broad:setoption('broadcast',false)
end)
end
function c:send(ip,data,port,cid)
if self.autoNormalization then
data=net.normalize(data)
end
if self.servercode then
cid=cid or self:CIDFrom(ip,port)
if not self.ips[cid] then
print("Can't determine cid from client... sending the client a new one!")
local cid=net.resolveID(self)
print("Sending unique cid to client: "..cid)
self.ips[cid]={ip,port,0,self.servercode==nil}
print(ip)
self.udp:sendto("I!"..cid,ip,port)
if self.servercode then
self.udp:sendto("S!",ip,port)
end
return
end
if net.inList(self.bannedIPs,ip) or net.inList(self.bannedCIDs,cid) then
self.udp:sendto("BANNED CLIENT", ip, port or self.port)
elseif self.ips[cid][4] then
self.udp:sendto(data, ip, port or self.port)
elseif self.ips[cid][4]==false then
self.udp:sendto("Make sure your server code is correct!", ip, port)
end
else
self.udp:sendto(data, ip, port or self.port)
end
end
function c:pollClientModules(ip,port)
self:send(ip,"L!",port)
end
function c:CIDFrom(ip,port)
for i,v in pairs(self.ips) do
if(ip==v[1] and v[2]==port) then
return i
end
end
end
function c:sendAll(data)
for i,v in pairs(self.ips) do
self:send(v[1],data,v[2],i)
end
end
function c:sendAllBut(data,cid)
for i,v in pairs(self.ips) do
if i~=cid then
self:send(v[1],data,v[2],i)
end
end
end
function c:clientRegistered(cid)
return self.ips[cid]
end
function c:clientLoggedIn(cid)
if not self.clientRegistered(cid) then
return nil
end
return self.ips[cid][4]
end
function c:update()
local data,ip,port=self.udp:receivefrom()
if net.inList(self.bannedIPs,ip) or net.inList(self.bannedCIDs,cid) then
print("We will ignore data from a banned client!")
return
end
if data then
if self.autoNormalization then
data=net.denormalize(data)
end
if data:sub(1,4)=="pong" then
--print("Recieved pong from: "..data:sub(5,-1))
self.ips[data:sub(5,-1)][3]=os.clock()
elseif data:sub(1,2)=="S!" then
local cid=self:CIDFrom(ip,port)
if data:sub(3,-1)==self.servercode then
print("Servercode Accepted: "..self.servercode)
if self.ips[cid] then
self.ips[cid][4]=true
else
print("Server can't keep up! CID: "..cid.." has been skipped! Sending new CID to the client!")
local cid=net.resolveID(self)
print("Sending unique cid to client: "..cid)
self.ips[cid]={ip,port,0,self.servercode==nil}
print(ip)
self.udp:sendto("I!"..cid,ip,port)
if self.servercode then
self.udp:sendto("S!",ip,port)
end
end
else
self.udp:sendto("Make sure your server code is correct!", ip, port)
end
elseif data:sub(1,2)=="C!" then
local hook=(data:sub(11,-1)):match("!(.-)!")
self.OnDataRecieved:getConnection(hook):Fire(self,data:sub(11,-1),data:sub(3,10),ip,port)
elseif data:sub(1,2)=="E!" then
self.ips[data:sub(3,10)]=nil
obj.ids[data:sub(3,10)]=false
self.OnClientClosed:Fire(self,"Client Closed Connection!",data:sub(3,10),ip,port)
elseif data=="I!" then
local cid=net.resolveID(self)
print("Sending unique cid to client: "..cid)
self.ips[cid]={ip,port,os.clock(),self.servercode==nil}
print(ip)
self.udp:sendto("I!"..cid,ip,port)
if self.servercode then
self.udp:sendto("S!",ip,port)
end
self.OnClientConnected:Fire(self,cid,ip,port)
elseif data:sub(1,2)=="L!" then
cid,cList=data:sub(3,10),data:sub(11,-1)
local list={}
for m,v in cList:gmatch("(%S-):(%S-)|") do
list[m]=v
end
self.OnClientsModulesList:Fire(list,cid,ip,port)
end
end
for cid,dat in pairs(self.ips) do
if not((os.clock()-dat[3])<65) then
self.ips[cid]=nil
self.OnClientClosed:Fire(self,"Client lost Connection: ping timeout",cid,ip,port)
end
end
end
c.OnClientsModulesList=multi:newConnection()
c.OnDataRecieved=multi:newConnection()
c.OnClientClosed=multi:newConnection()
c.OnClientConnected=multi:newConnection()
c.connectiontest=multi:newAlarm(30):setName("net.pingOutTask")
c.connectiontest.link=c
c.connectiontest:OnRing(function(alarm)
alarm.link:sendAll("ping")
alarm:Reset()
end)
table.insert(net.ConnectionDriver,c)
net.OnServerCreated:Fire(c)
return c
end
local pingManager = {}
function net:newUDPClient(host,port,servercode,nonluaServer)
local c={}
c.ip=assert(socket.dns.toip(host))
c.udp=assert(socket.udp())
c.udp:settimeout(0)
c.udp:setpeername(c.ip, port)
c.cid="NIL"
c.lastPing=0
c.Type="udp"
c.servercode=servercode
c.autoReconnect=true
c.autoNormalization=false
function c:pollPing(n)
return not((os.clock()-self.lastPing)<(n or 60))
end
function c:send(data)
if self.autoNormalization then
data=net.normalize(data)
end
self.udp:send("C!"..self.cid..data)
end
function c:sendRaw(data)
if self.autoNormalization then
data=net.normalize(data)
end
self.udp:send(data)
end
function c:getCID()
if self:IDAssigned() then
return self.cid
end
end
function c:close()
self:send("E!")
end
function c:IDAssigned()
return self.cid~="NIL"
end
function c:update()
local data=self.udp:receive()
if data then
if self.autoNormalization then
data=net.denormalize(data)
end
if data:sub(1,2)=="I!" then
self.cid=data:sub(3,-1)
self.OnClientReady:Fire(self)
elseif data=="S!" then
self.udp:send("S!"..(self.servercode or ""))
elseif data=="L!" then
local mods=""
local m=""
for i=1,#net.loadedModules do
m=net.loadedModules[i]
mods=mods..m..":"..net.getModuleVersion(m).."|"
end
self.udp:send("L!"..self.cid..mods)
elseif data=="ping" then
self.lastPing=os.clock()
self.OnPingRecieved:Fire(self)
self.udp:send("pong"..self.cid)
else
local hook=data:match("!(.-)!")
self.OnDataRecieved:getConnection(hook):Fire(self,data)
end
end
end
function c:reconnect()
if not nonluaServer then
self.cid="NIL"
c.udp:send("I!")
end
self.pingEvent:Resume()
self.OnConnectionRegained:Fire(self)
end
c.pingEvent=multi:newEvent(function(self) return self.link:pollPing() end)
c.pingEvent:OnEvent(function(self)
if self.link.autoReconnect then
self.link.OnServerNotAvailable:Fire("Connection to server lost: ping timeout! Attempting to reconnect...")
self.link.OnClientDisconnected:Fire(self,"closed")
self.link:reconnect()
else
self.link.OnServerNotAvailable:Fire("Connection to server lost: ping timeout!")
self.link.OnClientDisconnected:Fire(self,"closed")
end
self:Pause()
end):setName("net.pingInTask")
c.pingEvent.link=c
c.OnPingRecieved=multi:newConnection()
c.OnDataRecieved=multi:newConnection()
c.OnServerNotAvailable=multi:newConnection()
c.OnClientReady=multi:newConnection()
c.OnClientDisconnected=multi:newConnection()
c.OnConnectionRegained=multi:newConnection()
c.notConnected=multi:newFunction(function(self)
multi:newAlarm(3):OnRing(function(alarm)
if self.link:IDAssigned()==false then
self.link.OnServerNotAvailable:Fire("Can't connect to the server: no response from server")
end
alarm:Destroy()
end):setName("net.clientTimeout")
end)
c.notConnected.link=c
if not nonluaServer then
c.udp:send("I!")
end
table.insert(net.ConnectionDriver,c)
multi.nextStep(function() c.notConnected() end)
net.OnClientCreated:Fire(c)
return c
end
multi:newThread(function()
end)
--TCP Stuff
function net:newTCPClientObject(fd)
local c = {}
local client
c.Type="tcp-ClientObj"
c.rMode="*l"
c.sMode="*l"
function c:packMsg(data)
local temp = bin.new()
temp:addBlock(#data,self.numspace,"n")
temp:addBlock(data)
return temp:getData()
end
function c:enableBinaryMode()
self.rMode = "b"
self.sMode = "b"
end
if fd then
client=socket.tcp()
client:setfd(fd)
_,port = client:getsockname()
c.handle = client
else
error("You need to enter a fd in order to be able to create a tcp client object like this!")
end
function c:setUpdateRate(n)
self.updaterRate=n
end
function c:setReceiveMode(mode)
self.rMode=mode
end
function c:setSendMode(mode)
self.rMode=mode
end
function c:send(data)
if self.autoNormalization then
data=net.normalize(data)
end
if self.sMode=="*l" then
self.handle:send(data.."\n")
elseif self.sMode=="b" then
self.handle:send(self:packMsg(data))
else
self.handle:send(data)
end
end
multi:newThread("ServerClientHandler",function()
while true do
thread.skip(1)
local data, err, dat, len
if self.rMode == "b" then
thread.hold(function()
dat = client:receive(self.numspace)
return dat
end)
len = bin.new(dat):getBlock("n",self.numspace)
data, err = client:receive(len)
else
data, err = client:receive(self.rMode)
end
if err=="closed" then
for i=1,#self.ips do
if self.ips[i]==client then
table.remove(self.ips,i)
end
end
self.OnClientClosed:Fire(self,"Client Closed Connection!",client,client,ip)
self.links[client]=nil -- lets clean up
self:Destroy()
end
if data then
if self.autoNormalization then
data=net.denormalize(data)
end
if net.inList(self.bannedIPs,ip) then
print("We will ingore data from a banned client!")
return
end
local hook=data:match("!(.-)!")
self.OnDataRecieved:getConnection(hook):Fire(self,data,client,client,ip,self)
if data:sub(1,2)=="L!" then
cList=data
local list={}
for m,v in cList:gmatch("(%S-):(%S-)|") do
list[m]=v
end
self.OnClientsModulesList:Fire(list,client,client,ip)
end
end
end
end)
c.OnClientsModulesList=multi:newConnection()
c.OnDataRecieved=multi:newConnection()
c.OnClientClosed=multi:newConnection()
c.OnClientConnected=multi:newConnection()
return c
end
function net:newTCPServer(port)
local c={}
local port = port or 0
c.tcp=assert(socket.bind("*", port))
c.tcp:settimeout(0)
c.ip,c.port=c.tcp:getsockname()
c.ips={}
if port == 0 then
_, c.port = c.tcp:getsockname()
end
c.ids={}
c.bannedIPs={}
c.Type="tcp"
c.rMode="*l"
c.sMode="*l"
c.updaterRate=1
c.autoNormalization=false
c.updates={}
c.links={}
c.numspace = 4
c.broad=socket.udp()
c.hostip=net.getLocalIP()
function c:packMsg(data)
local temp = bin.new()
temp:addBlock(#data,self.numspace,"n")
temp:addBlock(data)
return temp:getData()
end
function c:enableBinaryMode()
self.rMode = "b"
self.sMode = "b"
end
function c:broadcast(name)
table.insert(net.BroadcastDriver,function(loop,dt)
self.broad:setoption('broadcast',true)
self.broad:sendto(name.."|"..self.Type.."|"..self.hostip..":"..self.port, "255.255.255.255", 11111)
self.broad:setoption('broadcast',false)
end)
end
function c:setUpdateRate(n)
self.updaterRate=n
end
function c:setReceiveMode(mode)
self.rMode=mode
end
function c:setSendMode(mode)
self.rMode=mode
end
function c:banCID(cid)
print("Function not supported on a tcp server!")
end
function c:banIP(ip)
table.insert(self.bannedIPs,cid)
end
function c:send(handle,data)
if self.autoNormalization then
data=net.normalize(data)
end
if self.sMode=="*l" then
handle:send(data.."\n")
elseif self.sMode=="b" then
handle:send(self:packMsg(data))
else
handle:send(data)
end
end
function c:sendAllData(handle,data)
if self.autoNormalization then
data=net.normalize(data)
end
handle:send(data)
end
function c:pollClientModules(ip,port)
self:send(ip,"L!",port)
end
function c:CIDFrom(ip,port)
print("Method not supported when using a TCP Server!")
return "CIDs in TCP work differently!"
end
function c:sendAll(data)
for i,v in pairs(self.ips) do
self:send(v,data)
end
end
function c:sendAllBut(data,cid)
for i,v in pairs(self.ips) do
if not(cid==i) then
self:send(v,data)
end
end
end
function c:clientRegistered(cid)
return self.ips[cid]
end
function c:clientLoggedIn(cid)
return self.ips[cid]
end
function c:getUpdater(cid)
return self.updates[cid]
end
function c:update()
local client = self.tcp:accept(self.rMode)
if not client then return end
table.insert(self.ips,client)
client:settimeout(0)
--client:setoption('tcp-nodelay', true)
client:setoption('keepalive', true)
ip,port=client:getpeername()
if ip and port then
print("Got connection from: ",ip,port)
-- local updater=multi:newUpdater(skip):setName("net.tcpClientObj")
-- self.updates[client]=updater
self.OnClientConnected:Fire(self,client,client,ip)
--updater:OnUpdate(function(self)
multi:newThread("ServerClientHandler",function()
while true do
thread.skip(1)
local data, err, dat, len
if self.rMode == "b" then
thread.hold(function()
dat = client:receive(self.numspace)
return dat
end)
len = bin.new(dat):getBlock("n",self.numspace)
data, err = client:receive(len)
else
data, err = client:receive(self.rMode)
end
if err=="closed" then
for i=1,#self.ips do
if self.ips[i]==client then
table.remove(self.ips,i)
end
end
self.OnClientClosed:Fire(self,"Client Closed Connection!",client,client,ip)
self.links[client]=nil -- lets clean up
self:Destroy()
thread.kill()
end
if data then
if self.autoNormalization then
data=net.denormalize(data)
end
if net.inList(self.bannedIPs,ip) then
print("We will ingore data from a banned client!")
return
end
local hook=data:match("!(.-)!")
self.OnDataRecieved:getConnection(hook):Fire(self,data,client,client,ip,self)
if data:sub(1,2)=="L!" then
cList=data
local list={}
for m,v in cList:gmatch("(%S-):(%S-)|") do
list[m]=v
end
self.OnClientsModulesList:Fire(list,client,client,ip)
end
end
end
end)
-- updater:SetSkip(self.updaterRate)
-- updater.client=client
-- updater.Link=self
-- function updater:setReceiveMode(mode)
-- self.rMode=mode
-- end
-- self.links[client]=updater
end
end
c.OnClientsModulesList=multi:newConnection()
c.OnDataRecieved=multi:newConnection()
c.OnClientClosed=multi:newConnection()
c.OnClientConnected=multi:newConnection()
table.insert(net.ConnectionDriver,c)
net.OnServerCreated:Fire(c)
return c
end
function net:newTCPClient(host,port)
local c={}
c.ip=assert(socket.dns.toip(host))
c.tcp=socket.connect(c.ip,port)
if not c.tcp then
print("Can't connect to the server: no response from server")
return false
end
c.tcp:settimeout(0)
--c.tcp:setoption('tcp-nodelay', true)
c.tcp:setoption('keepalive', true)
c.Type="tcp"
c.autoReconnect=true
c.rMode="*l"
c.sMode="*l"
c.autoNormalization=false
c.numspace = 4
function c:enableBinaryMode()
self.rMode = "b"
self.sMode = "b"
end
function c:setReceiveMode(mode)
self.rMode=mode
end
function c:setSendMode(mode)
self.sMode=mode
end
function c:packMsg(data)
local temp = bin.new()
temp:addBlock(#data,self.numspace)
temp:addBlock(data)
return temp:getData()
end
function c:send(data)
if self.autoNormalization then
data=net.normalize(data)
end
if self.sMode=="*l" then
ind,err=self.tcp:send(data.."\n")
elseif self.sMode=="b" then
ind,err=self.tcp:send(self:packMsg(data))
else
ind,err=self.tcp:send(data)
end
if err=="closed" then
self.OnClientDisconnected:Fire(self,err)
elseif err=="timeout" then
self.OnClientDisconnected:Fire(self,err)
elseif err then
print(err)
end
end
function c:sendRaw(data)
if self.autoNormalization then
data=net.normalize(data)
end
self.tcp:send(data)
end
function c:getCID()
return "No Cid on a tcp client!"
end
function c:close()
self.tcp:close()
end
function c:IDAssigned()
return true
end
function c:update()
if not self.tcp then return end
local data,err,dat
if self.rMode == "b" then
thread.hold(function()
dat = self.tcp:receive(self.numspace)
return dat
end)
len = bin.new(dat):getBlock("n",self.numspace)
data, err = self.tcp:receive(len)
else
data,err = self.tcp:receive()
end
if err=="closed" then
self.OnClientDisconnected:Fire(self,err)
elseif err=="timeout" then
self.OnClientDisconnected:Fire(self,err)
elseif err then
print(err)
end
if data then
if self.autoNormalization then
data=net.denormalize(data)
end
local hook=data:match("!(.-)!")
self.OnDataRecieved:getConnection(hook):Fire(self,data)
end
end
function c:reconnect()
multi:newFunction(function(func)
self.tcp=socket.connect(self.ip,self.port)
if self.tcp==nil then
print("Can't connect to the server: No response from server!")
multi:newAlarm(3):OnRing(function(alarm)
self:reconnect()
alarm:Destroy()
return
end):setName("net.timeoutTask")
end
self.OnConnectionRegained:Fire(self)
self.tcp:settimeout(0)
--self.tcp:setoption('tcp-nodelay', true)
self.tcp:setoption('keepalive', true)
end)
end
c.event=multi:newEvent(function(event)
return event.link:IDAssigned()
end):OnEvent(function(event)
event.link.OnClientReady:Fire(event.link)
event:Destroy()
end)
c.event:setName("net.handshakeTask")
c.event.link=c
c.OnClientReady=multi:newConnection()
c.OnClientDisconnected=multi:newConnection()
c.OnDataRecieved=multi:newConnection()
c.OnConnectionRegained=multi:newConnection()
table.insert(net.ConnectionDriver,c)
net.OnClientCreated:Fire(c)
return c
end
net.timer = multi:newTimer():Start()
multi:newThread("ClientServerHandler",function()
while true do
thread.skip()
for i=1,#net.ConnectionDriver do
thread.skip()
net.ConnectionDriver[i]:update()
end
if net.timer:Get()>=1 then
for i=1,#net.BroadcastDriver do
net.BroadcastDriver[i]()
end
net.timer:Reset()
end
end
end)
return net

View File

@ -18,7 +18,7 @@ net.OnServerCreated:connect(function(s)
local cmd,arg1,arg2=data:match("!version! ") local cmd,arg1,arg2=data:match("!version! ")
end,"version") end,"version")
s.OnClientConnected(function(self,CID_OR_HANDLE,IP_OR_HANDLE,PORT_OR_IP) s.OnClientConnected(function(self,CID_OR_HANDLE,IP_OR_HANDLE,PORT_OR_IP)
multi:newFunction(function(func) -- anom func, allows for fancy multitasking multi:newFunction(function(func) -- anon func, allows for fancy multitasking
multi:newFunction(function(self) multi:newFunction(function(self)
local range=self:newRange() local range=self:newRange()
for i in range(1,#self.loadedModules) do for i in range(1,#self.loadedModules) do

View File

@ -0,0 +1,32 @@
package = "llnet"
version = "5.0-0"
source = {
url = "git://github.com/rayaman/lnet.git",
tag = "lnet-v5",
}
description = {
summary = "Lua lnetworking library that wraps around lua-socket to make lnetworking easy.",
detailed = [[
This library uses the multi library. The new multitasking library and this one are now co-Dependant if using the lnetworkManager integration for lnetwork parallelism. This has an event driven approach for lnetworking which allows one to easily work async with the data.
]],
homepage = "https://github.com/rayaman/lnet",
license = "MIT"
}
dependencies = {
"lua >= 5.1",
"luasocket",
"luasec",
"multi",
}
build = {
type = "builtin",
modules = {
["lnet.init"] = "lnet/init.lua",
["lnet.tcp.init"] = "lnet/tcp/init.lua",
["lnet.udp.init"] = "lnet/udp/init.lua",
["lnet.base.client"] = "lnet/base/client.lua",
["lnet.base.server"] = "lnet/base/server.lua",
["lnet.http"] = "lnet/http.lua",
["lnet.https"] = "lnet/https.lua"
}
}

View File

@ -1,20 +1,11 @@
package.path="?/init.lua;"..package.path package.path = "./?/init.lua;./?.lua;"..package.path
local multi = require("multi") local net = require("lnet.tcp")
local net = require("net") local multi, thread = require("multi"):init()
local GLOBAL, THREAD = require("multi.integration.lanesManager").init() server = net.newTCPServer(12345)
server = net:newTCPServer(12345) server:broadcast("Test")
server:enableBinaryMode() print("Server has been broadcasted!")
print("Server hosted on "..net.getExternalIP().." listening on port: 12345") server.OnDataRecieved(function(serv, data,cid)
server.OnDataRecieved(function(self,data,cid,ip,port) print("Response: ",data)
print(data) server:send(cid,"Hello!")
local file = bin.load("test.mp3")
local dat = file:read(1024)
while dat do
thread.sleep(.002)
self:send(ip,dat,port,cid)
dat = file:read(1024)
end
self:send(ip,dat or "",port,cid)
self:send(ip,"END",port,cid)
end) end)
multi:mainloop() multi:mainloop()

BIN
test.mp3

Binary file not shown.

BIN
test2.mp3

Binary file not shown.