Python1320

Garry's Mod (GMod) vstruct and luasocket tcp cross stream

Nov 12th, 2012
202
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 7.36 KB | None | 0 0
  1. print(pcall(hooks.ShutDown.streams))
  2.  
  3.  
  4. require'vstruct'
  5. local senddata
  6. timer.Create("asd",0.1,0,function()
  7. if not senddata then return end
  8. local fmt={"i1"}
  9. local count=0
  10. local data={}
  11. for k,v in pairs(player.GetHumans()) do
  12.     fmt[#fmt+1]="u4 f8 f8 f8"
  13.     local pos=v:GetPos()
  14.     table.insert(data,v:UserID())
  15.     table.insert(data,pos.x)
  16.     table.insert(data,pos.y)
  17.     table.insert(data,pos.z)
  18.     count=count+1
  19. end
  20. --print(count)
  21. table.insert(data,1,count)
  22. fmt=table.concat(fmt," ")
  23. local str=vstruct.pack(fmt,data)
  24. senddata:Send(str)
  25. end)
  26.  
  27.  
  28. require'socket'
  29. require'vstruct'
  30. pcall(require,'cares')
  31.  
  32. local Tag="streams"
  33. module (Tag,package.seeall)
  34.  
  35. function dbg(...)
  36.     Msg("[Streams] ") print(...)
  37. end
  38.  
  39.  
  40. function isip(ip)
  41.     assert(not ip:find":","IPv6 or port in ip not supported")
  42.     return ip:match("^%d%d?%d?.%d%d?%d?.%d%d?%d?.%d%d?%d?$")
  43. end
  44.  
  45.  
  46. ---------------------------------------------------------
  47. -- Stream logic here
  48. ---------------------------------------------------------
  49. local clients={}
  50. _M.clients=clients
  51.  
  52. local CLM={}
  53. function CLM:created()
  54.     dbg("New stream from",self.ip)
  55.     senddata=self
  56. end
  57.  
  58. function CLM:proc(gotdata,data)
  59.     assert(self.closed!=true,"still processing even when closed")
  60.     if not gotdata then
  61.         dbg("procerr",self.ip,data)
  62.         return true -- close
  63.     end
  64.     local ok,err=pcall(procdata,data)
  65.     if not ok then
  66.         dbg("procdata err",err)
  67.     end
  68. end
  69.  
  70. function CLM:Send(data)
  71.     if self.closed then error"closed" end
  72.     self.sendbuff=(self.sendbuff or "")..data
  73. end
  74.  
  75. local function CL(tbl)
  76.     tbl = tbl or {}
  77.     tbl.i=0
  78.     setmetatable(tbl,{__index=CLM})
  79.     return tbl
  80. end
  81.  
  82. ---------------------------------------------------------
  83. -- Connecting to somenoe
  84. ---------------------------------------------------------
  85.  
  86. local dnscache={--[[ domain=ip ]]}
  87. function ConnectStream(ip,port,cb) -- Must match with the recursive call signature below
  88.    
  89.     -- DNS Resolving
  90.     ip=dnscache[ip] or ip
  91.    
  92.     if not isip(ip) then
  93.         if not cares then return false end
  94.        
  95.         cares.Resolve(ip,function(identifier,errored,err,domain)
  96.            
  97.                
  98.                
  99.             if errored then
  100.                 if cb then cb(false,err) else
  101.                             dbg("Resolve error",err) end
  102.                 return
  103.             end
  104.                
  105.             local resolved=err
  106.                
  107.             if not resolved or not isip(resolved) then
  108.                 if cb then cb(false,"resolved to wrong type",resolved) else
  109.                                 dbg("resolved to wrong type",resolved) end
  110.                 return
  111.             end
  112.             --dbg("resolved",resolved)
  113.             dnscache[ip]=resolved
  114.            
  115.             ConnectStream(ip,port,cb) -- Must match with SendMessage parameters above
  116.                
  117.         end)
  118.        
  119.         return
  120.     end
  121.    
  122.     -- Sending and receiving
  123.    
  124.     local sock=socket.tcp()
  125.     sock:settimeout(0)
  126.     port=port or 37477
  127.    
  128.     local connected,err=sock:connect(ip,port)
  129.     if not connected and err~='timeout' then
  130.         if cb then cb(connected,err) else
  131.             dbg("SendMessage failed",connected,err) end
  132.         return false
  133.     end
  134.  
  135.     timer.Create(sock,0,0,function()
  136.  
  137.         local ok,err=sock:connect(ip,port)
  138.         if not ok and (err=='timeout' or (err and err:find"progress")) then return end
  139.         if not ok then
  140.             if cb then cb(ok,err) else
  141.                 dbg("Sock connect failed: ",err) end
  142.                 timer.Remove(sock)
  143.                 sock:close()
  144.             return
  145.         end
  146.  
  147.         local clid=#clients+1
  148.         assert(not clients[clid])
  149.         clients[clid]=CL{clid=clid,socket=sock,ip=ip,port=port,new=true}   
  150.            
  151.         cb(sock,true)
  152.         timer.Remove(sock)
  153.  
  154.     end)
  155.     return sock
  156. end
  157.  
  158. function Connect(ip,port)
  159.     ConnectStream(ip,port,function(sock,err)
  160.         if not sock then
  161.             dbg("Connect",sock,err)
  162.             return
  163.         end
  164.     end)
  165. end
  166.  
  167.  
  168. ---------------------------------------------------------
  169. -- Accepting, receiving, etc
  170. ---------------------------------------------------------
  171. local acceptor
  172. function ProcessConnection(client,db)
  173.     local close
  174.    
  175.     if db.new then
  176.         close = db:created()
  177.     end
  178.    
  179.     if close!=nil then return close end
  180.    
  181.     if db.sendbuff and #db.sendbuff>0 then
  182.         local data=db.sendbuff
  183.         local ok,err,sent=client:send(data)
  184.         if ok then
  185.             db.sendbuff=false
  186.         else
  187.             if err=='timeout' then
  188.                 if sent==0 then
  189.                     dbg("sent nothing??")
  190.                 end
  191.                 assert(sent<#data)
  192.                 db.sendbuff=data:sub(sent+1,-1)
  193.             else
  194.                 close=close or db:proc(false,err)
  195.             end
  196.         end
  197.     end
  198.    
  199.    
  200.     local ok,err,data=client:receive(db.receivemode or 1024)
  201.    
  202.     if not ok and err=='timeout' then
  203.         if not data or #data==0 then
  204.             return
  205.         end
  206.         -- timeout but we got data. Let's hack this up.
  207.         ok=data
  208.         err=nil
  209.         data=nil
  210.     end
  211.    
  212.     if ok then
  213.         assert(type(data)~="string")
  214.         data=ok
  215.     end
  216.    
  217.     if data then
  218.         assert(type(data)=="string")
  219.         close=close or db:proc(true,data)
  220.     end
  221.    
  222.     if not ok then
  223.         close=close or db:proc(false,err)
  224.     end
  225.    
  226.     return close
  227. end
  228.  
  229.  
  230. function Think()
  231.     if not acceptor then return end
  232.     local newclient,err=acceptor:accept()
  233.     if not newclient and err=='closed' then
  234.         error"acceptor socket closed"
  235.     end
  236.     if not newclient and err!='timeout' then
  237.         error("FATAL socket error: "..tostring(err))
  238.     end
  239.        
  240.     if newclient then
  241.         newclient:settimeout(0)
  242.         local ip,port=newclient:getpeername()
  243.        
  244.         /*if not whitelist[ip] and not hook.Call("tcpcommok",nil,ip) then
  245.             dbg("Non whitelisted connection from",ip)
  246.             newclient:close()
  247.             return -- dos possibility here, can you see it? C:
  248.         end*/
  249.                
  250.         dbg("New connection",newclient,"from",ip)
  251.         local clid=#clients+1
  252.         assert(not clients[clid])
  253.         clients[clid]=CL{clid=clid,socket=newclient,ip=ip,port=port,new=true}
  254.     end
  255.    
  256.     for clid,db in pairs(clients) do
  257.         if ProcessConnection(db.socket,db)==true then
  258.             db.socket:close()
  259.             db.closed=true
  260.             clients[clid]=nil
  261.         end
  262.         if db.new then db.new=false end
  263.     end
  264.        
  265. end
  266.  
  267. function StartServer()
  268.     acceptor=socket.tcp()
  269.     acceptor:settimeout(0)
  270.     acceptor:setoption('reuseaddr',true) -- we need this.
  271.     assert(acceptor:bind("*",37477))
  272.     assert(acceptor:listen(8))
  273.     hook.Add("Think",Tag,Think)
  274. end
  275.  
  276. timer.Simple(0,function()
  277.  
  278.     local ok,err=pcall(StartServer)
  279.     if not ok then
  280.         dbg("Failed to bind ("..err.."), retrying in 30 seconds.")
  281.         timer.Simple(123,StartServer) -- I heard 2 minutes is how long the kernel keeps the address reserved :c
  282.     end
  283.  
  284. end)
  285.  
  286. hook.Add("ShutDown",Tag,function()
  287.     if acceptor then
  288.         acceptor:close()
  289.     end
  290.     for _,v in pairs(clients) do
  291.         local client=v.socket
  292.         v.closed=true
  293.         if client then
  294.             client:close()
  295.         end
  296.     end
  297.     table.Empty(clients)
  298.     clients=nil
  299.     hook.Remove("Think",Tag)
  300. end)
  301.  
  302.  
  303. --- AAAHHHHAAA
  304.  
  305.  
  306.  
  307. local dats={}
  308. _M.dats=dats
  309.  
  310. timer.Create("qq",1,0,function()
  311.     for k,v in pairs(dats) do
  312.         if v.timeout<SysTime() then
  313.             print("removing uid",k)
  314.             dats[k]=nil
  315.             if IsValid(v.ent) then
  316.                 v.ent:Remove()
  317.             end
  318.         end
  319.     end
  320. end)
  321. function procdata(str)
  322.     local count=vstruct.unpack("i1",str)[1]
  323.     --print(count)
  324.     local fmt={"x1"}
  325.     for i=1,count do
  326.         fmt[#fmt+1]="u4 f8 f8 f8"
  327.     end
  328.     fmt=table.concat(fmt," ")
  329.     local data=vstruct.unpack(fmt,str)
  330.     local t={}
  331.     --PrintTable(data)
  332.     for i=0,count-1 do
  333.         i=i*4+1
  334.         local uid=data[i]
  335.         local x=data[i+1]
  336.         local y=data[i+2]
  337.         local z=data[i+3]
  338.         t[uid]=Vector(x,y,z)
  339.     end
  340.    
  341.     for uid,pos in pairs(t) do
  342.         local dd=dats[uid]
  343.         if not dd then
  344.             dd={}
  345.             dats[uid]=dd
  346.             dd.ent=ents.Create'prop_dynamic'
  347.             if IsValid(dd.ent) then
  348.                 dd.ent:SetModel"models/props_trainstation/trainstation_post001.mdl"
  349.                 dd.ent:Spawn()
  350.             end
  351.             print("created uid",uid)
  352.         end
  353.         if IsValid(dd.ent) then
  354.             dd.ent:SetPos(pos)
  355.             dd.timeout=SysTime()+10
  356.         end
  357.     end
  358. end
Add Comment
Please, Sign In to add comment