You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

8174 lines
157 KiB

package.preload['verse']=(function(...)
package.preload['util.encodings']=(function(...)
local function e()
error("Function not implemented");
end
local t=require"mime";
module"encodings"
stringprep={};
base64={encode=t.b64,decode=e};
return _M;
end)
package.preload['util.hashes']=(function(...)
local e=require"util.sha1";
return{sha1=e.sha1};
end)
package.preload['util.sha1']=(function(...)
local c=string.len
local a=string.char
local b=string.byte
local g=string.sub
local m=math.floor
local t=require"bit"
local k=t.bnot
local e=t.band
local y=t.bor
local n=t.bxor
local i=t.lshift
local o=t.rshift
local u,l,d,h,r
local function p(e,t)
return i(e,t)+o(e,32-t)
end
local function s(i)
local t,o
local t=""
for n=1,8 do
o=e(i,15)
if(o<10)then
t=a(o+48)..t
else
t=a(o+87)..t
end
i=m(i/16)
end
return t
end
local function j(t)
local i,o
local n=""
i=c(t)*8
t=t..a(128)
o=56-e(c(t),63)
if(o<0)then
o=o+64
end
for e=1,o do
t=t..a(0)
end
for t=1,8 do
n=a(e(i,255))..n
i=m(i/256)
end
return t..n
end
local function q(w)
local m,t,i,o,f,s,c,v
local a,a
local a={}
while(w~="")do
for e=0,15 do
a[e]=0
for t=1,4 do
a[e]=a[e]*256+b(w,e*4+t)
end
end
for e=16,79 do
a[e]=p(n(n(a[e-3],a[e-8]),n(a[e-14],a[e-16])),1)
end
m=u
t=l
i=d
o=h
f=r
for h=0,79 do
if(h<20)then
s=y(e(t,i),e(k(t),o))
c=1518500249
elseif(h<40)then
s=n(n(t,i),o)
c=1859775393
elseif(h<60)then
s=y(y(e(t,i),e(t,o)),e(i,o))
c=2400959708
else
s=n(n(t,i),o)
c=3395469782
end
v=p(m,5)+s+f+c+a[h]
f=o
o=i
i=p(t,30)
t=m
m=v
end
u=e(u+m,4294967295)
l=e(l+t,4294967295)
d=e(d+i,4294967295)
h=e(h+o,4294967295)
r=e(r+f,4294967295)
w=g(w,65)
end
end
local function a(e,t)
e=j(e)
u=1732584193
l=4023233417
d=2562383102
h=271733878
r=3285377520
q(e)
local e=s(u)..s(l)..s(d)
..s(h)..s(r);
if t then
return e;
else
return(e:gsub("..",function(e)
return string.char(tonumber(e,16));
end));
end
end
_G.sha1={sha1=a};
return _G.sha1;
end)
package.preload['lib.adhoc']=(function(...)
local n,r=require"util.stanza",require"util.uuid";
local h="http://jabber.org/protocol/commands";
local i={}
local s={};
function _cmdtag(e,o,t,a)
local e=n.stanza("command",{xmlns=h,node=e.node,status=o});
if t then e.attr.sessionid=t;end
if a then e.attr.action=a;end
return e;
end
function s.new(e,a,t,o)
return{name=e,node=a,handler=t,cmdtag=_cmdtag,permission=(o or"user")};
end
function s.handle_cmd(o,s,a)
local e=a.tags[1].attr.sessionid or r.generate();
local t={};
t.to=a.attr.to;
t.from=a.attr.from;
t.action=a.tags[1].attr.action or"execute";
t.form=a.tags[1]:child_with_ns("jabber:x:data");
local t,h=o:handler(t,i[e]);
i[e]=h;
local a=n.reply(a);
if t.status=="completed"then
i[e]=nil;
cmdtag=o:cmdtag("completed",e);
elseif t.status=="canceled"then
i[e]=nil;
cmdtag=o:cmdtag("canceled",e);
elseif t.status=="error"then
i[e]=nil;
a=n.error_reply(a,t.error.type,t.error.condition,t.error.message);
s.send(a);
return true;
else
cmdtag=o:cmdtag("executing",e);
end
for t,e in pairs(t)do
if t=="info"then
cmdtag:tag("note",{type="info"}):text(e):up();
elseif t=="warn"then
cmdtag:tag("note",{type="warn"}):text(e):up();
elseif t=="error"then
cmdtag:tag("note",{type="error"}):text(e.message):up();
elseif t=="actions"then
local t=n.stanza("actions");
for a,e in ipairs(e)do
if(e=="prev")or(e=="next")or(e=="complete")then
t:tag(e):up();
else
module:log("error",'Command "'..o.name..
'" at node "'..o.node..'" provided an invalid action "'..e..'"');
end
end
cmdtag:add_child(t);
elseif t=="form"then
cmdtag:add_child((e.layout or e):form(e.values));
elseif t=="result"then
cmdtag:add_child((e.layout or e):form(e.values,"result"));
elseif t=="other"then
cmdtag:add_child(e);
end
end
a:add_child(cmdtag);
s.send(a);
return true;
end
return s;
end)
package.preload['util.rsm']=(function(...)
local h=require"util.stanza".stanza;
local a,i=tostring,tonumber;
local n=type;
local r=pairs;
local s='http://jabber.org/protocol/rsm';
local o={};
do
local e=o;
local function t(e)
return i((e:get_text()));
end
local function a(t)
return t:get_text();
end
e.after=a;
e.before=function(e)
local e=e:get_text();
return e==""or e;
end;
e.max=t;
e.index=t;
e.first=function(e)
return{index=i(e.attr.index);e:get_text()};
end;
e.last=a;
e.count=t;
end
local d=setmetatable({
first=function(t,e)
if n(e)=="table"then
t:tag("first",{index=e.index}):text(e[1]):up();
else
t:tag("first"):text(a(e)):up();
end
end;
before=function(t,e)
if e==true then
t:tag("before"):up();
else
t:tag("before"):text(a(e)):up();
end
end
},{
__index=function(t,e)
return function(t,o)
t:tag(e):text(a(o)):up();
end
end;
});
local function n(e)
local i={};
for t in e:childtags()do
local e=t.name;
local a=e and o[e];
if a then
i[e]=a(t);
end
end
return i;
end
local function i(e)
local t=h("set",{xmlns=s});
for e,a in r(e)do
if o[e]then
d[e](t,a);
end
end
return t;
end
local function t(e)
local e=e:get_child("set",s);
if e and#e.tags>0 then
return n(e);
end
end
return{parse=n,generate=i,get=t};
end)
package.preload['util.stanza']=(function(...)
local t=table.insert;
local d=table.remove;
local w=table.concat;
local s=string.format;
local l=string.match;
local f=tostring;
local u=setmetatable;
local n=pairs;
local i=ipairs;
local o=type;
local v=string.gsub;
local y=string.sub;
local c=string.find;
local e=os;
local m=not e.getenv("WINDIR");
local r,a;
if m then
local t,e=pcall(require,"util.termcolours");
if t then
r,a=e.getstyle,e.getstring;
else
m=nil;
end
end
local p="urn:ietf:params:xml:ns:xmpp-stanzas";
module"stanza"
stanza_mt={__type="stanza"};
stanza_mt.__index=stanza_mt;
local e=stanza_mt;
function stanza(t,a)
local t={name=t,attr=a or{},tags={}};
return u(t,e);
end
local h=stanza;
function e:query(e)
return self:tag("query",{xmlns=e});
end
function e:body(t,e)
return self:tag("body",e):text(t);
end
function e:tag(a,e)
local a=h(a,e);
local e=self.last_add;
if not e then e={};self.last_add=e;end
(e[#e]or self):add_direct_child(a);
t(e,a);
return self;
end
function e:text(t)
local e=self.last_add;
(e and e[#e]or self):add_direct_child(t);
return self;
end
function e:up()
local e=self.last_add;
if e then d(e);end
return self;
end
function e:reset()
self.last_add=nil;
return self;
end
function e:add_direct_child(e)
if o(e)=="table"then
t(self.tags,e);
end
t(self,e);
end
function e:add_child(t)
local e=self.last_add;
(e and e[#e]or self):add_direct_child(t);
return self;
end
function e:get_child(a,t)
for o,e in i(self.tags)do
if(not a or e.name==a)
and((not t and self.attr.xmlns==e.attr.xmlns)
or e.attr.xmlns==t)then
return e;
end
end
end
function e:get_child_text(e,t)
local e=self:get_child(e,t);
if e then
return e:get_text();
end
return nil;
end
function e:child_with_name(t)
for a,e in i(self.tags)do
if e.name==t then return e;end
end
end
function e:child_with_ns(t)
for a,e in i(self.tags)do
if e.attr.xmlns==t then return e;end
end
end
function e:children()
local e=0;
return function(t)
e=e+1
return t[e];
end,self,e;
end
function e:childtags(i,t)
local e=self.tags;
local a,o=1,#e;
return function()
for o=a,o do
local e=e[o];
if(not i or e.name==i)
and((not t and self.attr.xmlns==e.attr.xmlns)
or e.attr.xmlns==t)then
a=o+1;
return e;
end
end
end;
end
function e:maptags(i)
local a,t=self.tags,1;
local n,o=#self,#a;
local e=1;
while t<=o and o>0 do
if self[e]==a[t]then
local i=i(self[e]);
if i==nil then
d(self,e);
d(a,t);
n=n-1;
o=o-1;
e=e-1;
t=t-1;
else
self[e]=i;
a[t]=i;
end
t=t+1;
end
e=e+1;
end
return self;
end
function e:find(a)
local e=1;
local s=#a+1;
repeat
local o,t,i;
local n=y(a,e,e);
if n=="@"then
return self.attr[y(a,e+1)];
elseif n=="{"then
o,e=l(a,"^([^}]+)}()",e+1);
end
t,i,e=l(a,"^([^@/#]*)([/#]?)()",e);
t=t~=""and t or nil;
if e==s then
if i=="#"then
return self:get_child_text(t,o);
end
return self:get_child(t,o);
end
self=self:get_child(t,o);
until not self
end
local d
do
local t={["'"]="&apos;",["\""]="&quot;",["<"]="&lt;",[">"]="&gt;",["&"]="&amp;"};
function d(e)return(v(e,"['&<>\"]",t));end
_M.xml_escape=d;
end
local function y(a,e,h,o,r)
local i=0;
local s=a.name
t(e,"<"..s);
for a,n in n(a.attr)do
if c(a,"\1",1,true)then
local a,s=l(a,"^([^\1]*)\1?(.*)$");
i=i+1;
t(e," xmlns:ns"..i.."='"..o(a).."' ".."ns"..i..":"..s.."='"..o(n).."'");
elseif not(a=="xmlns"and n==r)then
t(e," "..a.."='"..o(n).."'");
end
end
local i=#a;
if i==0 then
t(e,"/>");
else
t(e,">");
for i=1,i do
local i=a[i];
if i.name then
h(i,e,h,o,a.attr.xmlns);
else
t(e,o(i));
end
end
t(e,"</"..s..">");
end
end
function e.__tostring(t)
local e={};
y(t,e,y,d,nil);
return w(e);
end
function e.top_tag(e)
local t="";
if e.attr then
for e,a in n(e.attr)do if o(e)=="string"then t=t..s(" %s='%s'",e,d(f(a)));end end
end
return s("<%s%s>",e.name,t);
end
function e.get_text(e)
if#e.tags==0 then
return w(e);
end
end
function e.get_error(a)
local o,e,t;
local a=a:get_child("error");
if not a then
return nil,nil,nil;
end
o=a.attr.type;
for o,a in i(a.tags)do
if a.attr.xmlns==p then
if not t and a.name=="text"then
t=a:get_text();
elseif not e then
e=a.name;
end
if e and t then
break;
end
end
end
return o,e or"undefined-condition",t;
end
do
local e=0;
function new_id()
e=e+1;
return"lx"..e;
end
end
function preserialize(e)
local a={name=e.name,attr=e.attr};
for i,e in i(e)do
if o(e)=="table"then
t(a,preserialize(e));
else
t(a,e);
end
end
return a;
end
function deserialize(a)
if a then
local s=a.attr;
for e=1,#s do s[e]=nil;end
local h={};
for e in n(s)do
if c(e,"|",1,true)and not c(e,"\1",1,true)then
local t,a=l(e,"^([^|]+)|(.+)$");
h[t.."\1"..a]=s[e];
s[e]=nil;
end
end
for t,e in n(h)do
s[t]=e;
end
u(a,e);
for t,e in i(a)do
if o(e)=="table"then
deserialize(e);
end
end
if not a.tags then
local n={};
for i,e in i(a)do
if o(e)=="table"then
t(n,e);
end
end
a.tags=n;
end
end
return a;
end
local function l(a)
local o,i={},{};
for t,e in n(a.attr)do o[t]=e;end
local o={name=a.name,attr=o,tags=i};
for e=1,#a do
local e=a[e];
if e.name then
e=l(e);
t(i,e);
end
t(o,e);
end
return u(o,e);
end
clone=l;
function message(e,t)
if not t then
return h("message",e);
else
return h("message",e):tag("body"):text(t):up();
end
end
function iq(e)
if e and not e.id then e.id=new_id();end
return h("iq",e or{id=new_id()});
end
function reply(e)
return h(e.name,e.attr and{to=e.attr.from,from=e.attr.to,id=e.attr.id,type=((e.name=="iq"and"result")or e.attr.type)});
end
do
local a={xmlns=p};
function error_reply(e,o,i,t)
local e=reply(e);
e.attr.type="error";
e:tag("error",{type=o})
:tag(i,a):up();
if(t)then e:tag("text",a):text(t):up();end
return e;
end
end
function presence(e)
return h("presence",e);
end
if m then
local u=r("yellow");
local h=r("red");
local l=r("red");
local t=r("magenta");
local r=" "..a(u,"%s")..a(t,"=")..a(h,"'%s'");
local h=a(t,"<")..a(l,"%s").."%s"..a(t,">");
local l=h.."%s"..a(t,"</")..a(l,"%s")..a(t,">");
function e.pretty_print(e)
local t="";
for a,e in i(e)do
if o(e)=="string"then
t=t..d(e);
else
t=t..e:pretty_print();
end
end
local a="";
if e.attr then
for e,t in n(e.attr)do if o(e)=="string"then a=a..s(r,e,f(t));end end
end
return s(l,e.name,a,t,e.name);
end
function e.pretty_top_tag(t)
local e="";
if t.attr then
for t,a in n(t.attr)do if o(t)=="string"then e=e..s(r,t,f(a));end end
end
return s(h,t.name,e);
end
else
e.pretty_print=e.__tostring;
e.pretty_top_tag=e.top_tag;
end
return _M;
end)
package.preload['util.timer']=(function(...)
local a=require"net.server";
local d=math.min
local l=math.huge
local n=require"socket".gettime;
local r=table.insert;
local h=pairs;
local s=type;
local i={};
local e={};
module"timer"
local t;
if not a.event then
function t(o,i)
local n=n();
o=o+n;
if o>=n then
r(e,{o,i});
else
local e=i(n);
if e and s(e)=="number"then
return t(e,i);
end
end
end
a._addtimer(function()
local a=n();
if#e>0 then
for a,t in h(e)do
r(i,t);
end
e={};
end
local e=l;
for h,o in h(i)do
local o,n=o[1],o[2];
if o<=a then
i[h]=nil;
local a=n(a);
if s(a)=="number"then
t(a,n);
e=d(e,a);
end
else
e=d(e,o-a);
end
end
return e;
end);
else
local e=a.event;
local a=a.event_base;
local o=(e.core and e.core.LEAVE)or-1;
function t(i,e)
local t;
t=a:addevent(nil,0,function()
local e=e(n());
if e then
return 0,e;
elseif t then
return o;
end
end
,i);
end
end
add_task=t;
return _M;
end)
package.preload['util.termcolours']=(function(...)
local i,n=table.concat,table.insert;
local t,a=string.char,string.format;
local h=tonumber;
local s=ipairs;
local r=io.write;
local e;
if os.getenv("WINDIR")then
e=require"util.windows";
end
local o=e and e.get_consolecolor and e.get_consolecolor();
module"termcolours"
local d={
reset=0;bright=1,dim=2,underscore=4,blink=5,reverse=7,hidden=8;
black=30;red=31;green=32;yellow=33;blue=34;magenta=35;cyan=36;white=37;
["black background"]=40;["red background"]=41;["green background"]=42;["yellow background"]=43;["blue background"]=44;["magenta background"]=45;["cyan background"]=46;["white background"]=47;
bold=1,dark=2,underline=4,underlined=4,normal=0;
}
local u={
["0"]=o,
["1"]=7+8,
["1;33"]=2+4+8,
["1;31"]=4+8
}
local l={
[1]="font-weight: bold",[2]="opacity: 0.5",[4]="text-decoration: underline",[8]="visibility: hidden",
[30]="color:black",[31]="color:red",[32]="color:green",[33]="color:#FFD700",
[34]="color:blue",[35]="color: magenta",[36]="color:cyan",[37]="color: white",
[40]="background-color:black",[41]="background-color:red",[42]="background-color:green",
[43]="background-color:yellow",[44]="background-color:blue",[45]="background-color: magenta",
[46]="background-color:cyan",[47]="background-color: white";
};
local c=t(27).."[%sm%s"..t(27).."[0m";
function getstring(t,e)
if t then
return a(c,t,e);
else
return e;
end
end
function getstyle(...)
local e,t={...},{};
for a,e in s(e)do
e=d[e];
if e then
n(t,e);
end
end
return i(t,";");
end
local a="0";
function setstyle(e)
e=e or"0";
if e~=a then
r("\27["..e.."m");
a=e;
end
end
if e then
function setstyle(t)
t=t or"0";
if t~=a then
e.set_consolecolor(u[t]or o);
a=t;
end
end
if not o then
function setstyle(e)end
end
end
local function a(e)
if e=="0"then return"</span>";end
local t={};
for e in e:gmatch("[^;]+")do
n(t,l[h(e)]);
end
return"</span><span style='"..i(t,";").."'>";
end
function tohtml(e)
return e:gsub("\027%[(.-)m",a);
end
return _M;
end)
package.preload['util.uuid']=(function(...)
local e=math.random;
local o=tostring;
local e=os.time;
local n=os.clock;
local i=require"util.hashes".sha1;
module"uuid"
local t=0;
local function a()
local e=e();
if t>=e then e=t+1;end
t=e;
return e;
end
local function t(e)
return i(e..n()..o({}),true);
end
local e=t(a());
local function o(a)
e=t(e..a);
end
local function t(t)
if#e<t then o(a());end
local a=e:sub(0,t);
e=e:sub(t+1);
return a;
end
local function e()
return("%x"):format(t(1):byte()%4+8);
end
function generate()
return t(8).."-"..t(4).."-4"..t(3).."-"..(e())..t(3).."-"..t(12);
end
seed=o;
return _M;
end)
package.preload['net.dns']=(function(...)
local s=require"socket";
local j=require"util.timer";
local e,v=pcall(require,"util.windows");
local _=(e and v)or os.getenv("WINDIR");
local u,z,b,a,i=
coroutine,io,math,string,table;
local c,n,o,f,r,p,k,x,t,e,q=
ipairs,next,pairs,print,setmetatable,tostring,assert,error,unpack,select,type;
local e={
get=function(t,...)
local a=e('#',...);
for a=1,a do
t=t[e(a,...)];
if t==nil then break;end
end
return t;
end;
set=function(a,...)
local s=e('#',...);
local h,o=e(s-1,...);
local t,i;
for s=1,s-2 do
local s=e(s,...)
local e=a[s]
if o==nil then
if e==nil then
return;
elseif n(e,n(e))then
t=nil;i=nil;
elseif t==nil then
t=a;i=s;
end
elseif e==nil then
e={};
a[s]=e;
end
a=e
end
if o==nil and t then
t[i]=nil;
else
a[h]=o;
return o;
end
end;
};
local d,l=e.get,e.set;
local E=15;
module('dns')
local t=_M;
local h=i.insert
local function m(e)
return(e-(e%256))/256;
end
local function w(e)
local t={};
for o,e in o(e)do
t[o]=e;
t[e]=e;
t[a.lower(e)]=e;
end
return t;
end
local function y(i)
local e={};
for t,i in o(i)do
local o=a.char(m(t),t%256);
e[t]=o;
e[i]=o;
e[a.lower(i)]=o;
end
return e;
end
t.types={
'A','NS','MD','MF','CNAME','SOA','MB','MG','MR','NULL','WKS',
'PTR','HINFO','MINFO','MX','TXT',
[28]='AAAA',[29]='LOC',[33]='SRV',
[252]='AXFR',[253]='MAILB',[254]='MAILA',[255]='*'};
t.classes={'IN','CS','CH','HS',[255]='*'};
t.type=w(t.types);
t.class=w(t.classes);
t.typecode=y(t.types);
t.classcode=y(t.classes);
local function g(e,i,o)
if a.byte(e,-1)~=46 then e=e..'.';end
e=a.lower(e);
return e,t.type[i or'A'],t.class[o or'IN'];
end
local function y(t,a,o)
a=a or s.gettime();
for n,e in c(t)do
if e.tod then
e.ttl=b.floor(e.tod-a);
if e.ttl<=0 then
t[e[e.type:lower()]]=nil;
i.remove(t,n);
return y(t,a,o);
end
elseif o=='soft'then
k(e.ttl==0);
t[e[e.type:lower()]]=nil;
i.remove(t,n);
end
end
end
local e={};
e.__index=e;
e.timeout=E;
local function w(e)
local e=e.type and e[e.type:lower()];
if q(e)~="string"then
return"<UNKNOWN RDATA TYPE>";
end
return e;
end
local k={
LOC=e.LOC_tostring;
MX=function(e)
return a.format('%2i %s',e.pref,e.mx);
end;
SRV=function(e)
local e=e.srv;
return a.format('%5d %5d %5d %s',e.priority,e.weight,e.port,e.target);
end;
};
local q={};
function q.__tostring(e)
local t=(k[e.type]or w)(e);
return a.format('%2s %-5s %6i %-28s %s',e.class,e.type,e.ttl,e.name,t);
end
local k={};
function k.__tostring(t)
local e={};
for a,t in c(t)do
h(e,p(t)..'\n');
end
return i.concat(e);
end
local w={};
function w.__tostring(t)
local a=s.gettime();
local e={};
for i,t in o(t)do
for i,t in o(t)do
for o,t in o(t)do
y(t,a);
h(e,p(t));
end
end
end
return i.concat(e);
end
function e:new()
local t={active={},cache={},unsorted={}};
r(t,e);
r(t.cache,w);
r(t.unsorted,{__mode='kv'});
return t;
end
function t.random(...)
b.randomseed(b.floor(1e4*s.gettime())%2147483648);
t.random=b.random;
return t.random(...);
end
local function E(e)
e=e or{};
e.id=e.id or t.random(0,65535);
e.rd=e.rd or 1;
e.tc=e.tc or 0;
e.aa=e.aa or 0;
e.opcode=e.opcode or 0;
e.qr=e.qr or 0;
e.rcode=e.rcode or 0;
e.z=e.z or 0;
e.ra=e.ra or 0;
e.qdcount=e.qdcount or 1;
e.ancount=e.ancount or 0;
e.nscount=e.nscount or 0;
e.arcount=e.arcount or 0;
local t=a.char(
m(e.id),e.id%256,
e.rd+2*e.tc+4*e.aa+8*e.opcode+128*e.qr,
e.rcode+16*e.z+128*e.ra,
m(e.qdcount),e.qdcount%256,
m(e.ancount),e.ancount%256,
m(e.nscount),e.nscount%256,
m(e.arcount),e.arcount%256
);
return t,e.id;
end
local function m(t)
local e={};
for t in a.gmatch(t,'[^.]+')do
h(e,a.char(a.len(t)));
h(e,t);
end
h(e,a.char(0));
return i.concat(e);
end
local function b(o,a,e)
o=m(o);
a=t.typecode[a or'a'];
e=t.classcode[e or'in'];
return o..a..e;
end
function e:byte(e)
e=e or 1;
local o=self.offset;
local t=o+e-1;
if t>#self.packet then
x(a.format('out of bounds: %i>%i',t,#self.packet));
end
self.offset=o+e;
return a.byte(self.packet,o,t);
end
function e:word()
local t,e=self:byte(2);
return 256*t+e;
end
function e:dword()
local o,t,a,e=self:byte(4);
return 16777216*o+65536*t+256*a+e;
end
function e:sub(e)
e=e or 1;
local t=a.sub(self.packet,self.offset,self.offset+e-1);
self.offset=self.offset+e;
return t;
end
function e:header(t)
local e=self:word();
if not self.active[e]and not t then return nil;end
local e={id=e};
local t,a=self:byte(2);
e.rd=t%2;
e.tc=t/2%2;
e.aa=t/4%2;
e.opcode=t/8%16;
e.qr=t/128;
e.rcode=a%16;
e.z=a/16%8;
e.ra=a/128;
e.qdcount=self:word();
e.ancount=self:word();
e.nscount=self:word();
e.arcount=self:word();
for a,t in o(e)do e[a]=t-t%1;end
return e;
end
function e:name()
local a,t=nil,0;
local e=self:byte();
local o={};
if e==0 then return"."end
while e>0 do
if e>=192 then
t=t+1;
if t>=20 then x('dns error: 20 pointers');end;
local e=((e-192)*256)+self:byte();
a=a or self.offset;
self.offset=e+1;
else
h(o,self:sub(e)..'.');
end
e=self:byte();
end
self.offset=a or self.offset;
return i.concat(o);
end
function e:question()
local e={};
e.name=self:name();
e.type=t.type[self:word()];
e.class=t.class[self:word()];
return e;
end
function e:A(e)
local o,t,n,i=self:byte(4);
e.a=a.format('%i.%i.%i.%i',o,t,n,i);
end
function e:AAAA(a)
local e={};
for t=1,a.rdlength,2 do
local a,t=self:byte(2);
i.insert(e,("%02x%02x"):format(a,t));
end
e=i.concat(e,":"):gsub("%f[%x]0+(%x)","%1");
local t={};
for e in e:gmatch(":[0:]+:")do
i.insert(t,e)
end
if#t==0 then
a.aaaa=e;
return
elseif#t>1 then
i.sort(t,function(t,e)return#t>#e end);
end
a.aaaa=e:gsub(t[1],"::",1):gsub("^0::","::"):gsub("::0$","::");
end
function e:CNAME(e)
e.cname=self:name();
end
function e:MX(e)
e.pref=self:word();
e.mx=self:name();
end
function e:LOC_nibble_power()
local e=self:byte();
return((e-(e%16))/16)*(10^(e%16));
end
function e:LOC(e)
e.version=self:byte();
if e.version==0 then
e.loc=e.loc or{};
e.loc.size=self:LOC_nibble_power();
e.loc.horiz_pre=self:LOC_nibble_power();
e.loc.vert_pre=self:LOC_nibble_power();
e.loc.latitude=self:dword();
e.loc.longitude=self:dword();
e.loc.altitude=self:dword();
end
end
local function m(e,i,t)
e=e-2147483648;
if e<0 then i=t;e=-e;end
local n,t,o;
o=e%6e4;
e=(e-o)/6e4;
t=e%60;
n=(e-t)/60;
return a.format('%3d %2d %2.3f %s',n,t,o/1e3,i);
end
function e.LOC_tostring(e)
local t={};
h(t,a.format(
'%s %s %.2fm %.2fm %.2fm %.2fm',
m(e.loc.latitude,'N','S'),
m(e.loc.longitude,'E','W'),
(e.loc.altitude-1e7)/100,
e.loc.size/100,
e.loc.horiz_pre/100,
e.loc.vert_pre/100
));
return i.concat(t);
end
function e:NS(e)
e.ns=self:name();
end
function e:SOA(e)
end
function e:SRV(e)
e.srv={};
e.srv.priority=self:word();
e.srv.weight=self:word();
e.srv.port=self:word();
e.srv.target=self:name();
end
function e:PTR(e)
e.ptr=self:name();
end
function e:TXT(e)
e.txt=self:sub(self:byte());
end
function e:rr()
local e={};
r(e,q);
e.name=self:name(self);
e.type=t.type[self:word()]or e.type;
e.class=t.class[self:word()]or e.class;
e.ttl=65536*self:word()+self:word();
e.rdlength=self:word();
if e.ttl<=0 then
e.tod=self.time+30;
else
e.tod=self.time+e.ttl;
end
local a=self.offset;
local t=self[t.type[e.type]];
if t then t(self,e);end
self.offset=a;
e.rdata=self:sub(e.rdlength);
return e;
end
function e:rrs(t)
local e={};
for t=1,t do h(e,self:rr());end
return e;
end
function e:decode(t,o)
self.packet,self.offset=t,1;
local t=self:header(o);
if not t then return nil;end
local t={header=t};
t.question={};
local i=self.offset;
for e=1,t.header.qdcount do
h(t.question,self:question());
end
t.question.raw=a.sub(self.packet,i,self.offset-1);
if not o then
if not self.active[t.header.id]or not self.active[t.header.id][t.question.raw]then
self.active[t.header.id]=nil;
return nil;
end
end
t.answer=self:rrs(t.header.ancount);
t.authority=self:rrs(t.header.nscount);
t.additional=self:rrs(t.header.arcount);
return t;
end
e.delays={1,3};
function e:addnameserver(e)
self.server=self.server or{};
h(self.server,e);
end
function e:setnameserver(e)
self.server={};
self:addnameserver(e);
end
function e:adddefaultnameservers()
if _ then
if v and v.get_nameservers then
for t,e in c(v.get_nameservers())do
self:addnameserver(e);
end
end
if not self.server or#self.server==0 then
self:addnameserver("208.67.222.222");
self:addnameserver("208.67.220.220");
end
else
local e=z.open("/etc/resolv.conf");
if e then
for e in e:lines()do
e=e:gsub("#.*$","")
:match('^%s*nameserver%s+(.*)%s*$');
if e then
e:gsub("%f[%d.](%d+%.%d+%.%d+%.%d+)%f[^%d.]",function(e)
self:addnameserver(e)
end);
end
end
end
if not self.server or#self.server==0 then
self:addnameserver("127.0.0.1");
end
end
end
function e:getsocket(a)
self.socket=self.socket or{};
self.socketset=self.socketset or{};
local e=self.socket[a];
if e then return e;end
local o,t;
e,t=s.udp();
if e and self.socket_wrapper then e,t=self.socket_wrapper(e,self);end
if not e then
return nil,t;
end
e:settimeout(0);
self.socket[a]=e;
self.socketset[e]=a;
o,t=e:setsockname('*',0);
if not o then return self:servfail(e,t);end
o,t=e:setpeername(self.server[a],53);
if not o then return self:servfail(e,t);end
return e;
end
function e:voidsocket(e)
if self.socket[e]then
self.socketset[self.socket[e]]=nil;
self.socket[e]=nil;
elseif self.socketset[e]then
self.socket[self.socketset[e]]=nil;
self.socketset[e]=nil;
end
e:close();
end
function e:socket_wrapper_set(e)
self.socket_wrapper=e;
end
function e:closeall()
for t,e in c(self.socket)do
self.socket[t]=nil;
self.socketset[e]=nil;
e:close();
end
end
function e:remember(e,t)
local i,o,a=g(e.name,e.type,e.class);
if t~='*'then
t=o;
local t=d(self.cache,a,'*',i);
if t then h(t,e);end
end
self.cache=self.cache or r({},w);
local a=d(self.cache,a,t,i)or
l(self.cache,a,t,i,r({},k));
if not a[e[o:lower()]]then
a[e[o:lower()]]=true;
h(a,e);
end
if t=='MX'then self.unsorted[a]=true;end
end
local function m(e,t)
return(e.pref==t.pref)and(e.mx<t.mx)or(e.pref<t.pref);
end
function e:peek(o,a,t,h)
o,a,t=g(o,a,t);
local e=d(self.cache,t,a,o);
if not e then
if h then if h<=0 then return end else h=3 end
e=d(self.cache,t,"CNAME",o);
if not(e and e[1])then return end
return self:peek(e[1].cname,a,t,h-1);
end
if y(e,s.gettime())and a=='*'or not n(e)then
l(self.cache,t,a,o,nil);
return nil;
end
if self.unsorted[e]then i.sort(e,m);self.unsorted[e]=nil;end
return e;
end
function e:purge(e)
if e=='soft'then
self.time=s.gettime();
for t,e in o(self.cache or{})do
for t,e in o(e)do
for t,e in o(e)do
y(e,self.time,'soft')
end
end
end
else self.cache=r({},w);end
end
function e:query(e,t,a)
e,t,a=g(e,t,a)
local n=u.running();
local o=d(self.wanted,a,t,e);
if n and o then
l(self.wanted,a,t,e,n,true);
return true;
end
if not self.server then self:adddefaultnameservers();end
local h=b(e,t,a);
local o=self:peek(e,t,a);
if o then return o;end
local i,o=E();
local i={
packet=i..h,
server=self.best_server,
delay=1,
retry=s.gettime()+self.delays[1]
};
self.active[o]=self.active[o]or{};
self.active[o][h]=i;
if n then
l(self.wanted,a,t,e,n,true);
end
local o,h=self:getsocket(i.server)
if not o then
return nil,h;
end
o:send(i.packet)
if j and self.timeout then
local r=#self.server;
local s=1;
j.add_task(self.timeout,function()
if d(self.wanted,a,t,e,n)then
if s<r then
s=s+1;
self:servfail(o);
i.server=self.best_server;
o,h=self:getsocket(i.server);
if o then
o:send(i.packet);
return self.timeout;
end
end
self:cancel(a,t,e);
end
end)
end
return true;
end
function e:servfail(t,i)
local h=self.socketset[t]
t=self:voidsocket(t);
self.time=s.gettime();
for s,a in o(self.active)do
for o,e in o(a)do
if e.server==h then
e.server=e.server+1
if e.server>#self.server then
e.server=1;
end
e.retries=(e.retries or 0)+1;
if e.retries>=#self.server then
a[o]=nil;
else
t,i=self:getsocket(e.server);
if t then t:send(e.packet);end
end
end
end
if n(a)==nil then
self.active[s]=nil;
end
end
if h==self.best_server then
self.best_server=self.best_server+1;
if self.best_server>#self.server then
self.best_server=1;
end
end
return t,i;
end
function e:settimeout(e)
self.timeout=e;
end
function e:receive(t)
self.time=s.gettime();
t=t or self.socket;
local e;
for a,t in o(t)do
if self.socketset[t]then
local t=t:receive();
if t then
e=self:decode(t);
if e and self.active[e.header.id]
and self.active[e.header.id][e.question.raw]then
for a,t in o(e.answer)do
self:remember(t,e.question[1].type)
end
local t=self.active[e.header.id];
t[e.question.raw]=nil;
if not n(t)then self.active[e.header.id]=nil;end
if not n(self.active)then self:closeall();end
local e=e.question[1];
local t=d(self.wanted,e.class,e.type,e.name);
if t then
for e in o(t)do
if u.status(e)=="suspended"then u.resume(e);end
end
l(self.wanted,e.class,e.type,e.name,nil);
end
end
end
end
end
return e;
end
function e:feed(a,e,t)
self.time=s.gettime();
local e=self:decode(e,t);
if e and self.active[e.header.id]
and self.active[e.header.id][e.question.raw]then
for a,t in o(e.answer)do
self:remember(t,e.question[1].type);
end
local t=self.active[e.header.id];
t[e.question.raw]=nil;
if not n(t)then self.active[e.header.id]=nil;end
if not n(self.active)then self:closeall();end
local e=e.question[1];
if e then
local t=d(self.wanted,e.class,e.type,e.name);
if t then
for e in o(t)do
if u.status(e)=="suspended"then u.resume(e);end
end
l(self.wanted,e.class,e.type,e.name,nil);
end
end
end
return e;
end
function e:cancel(i,t,e)
local a=d(self.wanted,i,t,e);
if a then
for e in o(a)do
if u.status(e)=="suspended"then u.resume(e);end
end
l(self.wanted,i,t,e,nil);
end
end
function e:pulse()
while self:receive()do end
if not n(self.active)then return nil;end
self.time=s.gettime();
for i,t in o(self.active)do
for a,e in o(t)do
if self.time>=e.retry then
e.server=e.server+1;
if e.server>#self.server then
e.server=1;
e.delay=e.delay+1;
end
if e.delay>#self.delays then
t[a]=nil;
if not n(t)then self.active[i]=nil;end
if not n(self.active)then return nil;end
else
local t=self.socket[e.server];
if t then t:send(e.packet);end
e.retry=self.time+self.delays[e.delay];
end
end
end
end
if n(self.active)then return true;end
return nil;
end
function e:lookup(t,o,a)
self:query(t,o,a)
while self:pulse()do
local e={}
for a,t in c(self.socket)do
e[a]=t
end
s.select(e,nil,4)
end
return self:peek(t,o,a);
end
function e:lookupex(o,e,t,a)
return self:peek(e,t,a)or self:query(e,t,a);
end
function e:tohostname(e)
return t.lookup(e:gsub("(%d+)%.(%d+)%.(%d+)%.(%d+)","%4.%3.%2.%1.in-addr.arpa."),"PTR");
end
local i={
qr={[0]='query','response'},
opcode={[0]='query','inverse query','server status request'},
aa={[0]='non-authoritative','authoritative'},
tc={[0]='complete','truncated'},
rd={[0]='recursion not desired','recursion desired'},
ra={[0]='recursion not available','recursion available'},
z={[0]='(reserved)'},
rcode={[0]='no error','format error','server failure','name error','not implemented'},
type=t.type,
class=t.class
};
local function n(t,e)
return(i[e]and i[e][t[e]])or'';
end
function e.print(e)
for o,t in o{'id','qr','opcode','aa','tc','rd','ra','z',
'rcode','qdcount','ancount','nscount','arcount'}do
f(a.format('%-30s','header.'..t),e.header[t],n(e.header,t));
end
for t,e in c(e.question)do
f(a.format('question[%i].name ',t),e.name);
f(a.format('question[%i].type ',t),e.type);
f(a.format('question[%i].class ',t),e.class);
end
local h={name=1,type=1,class=1,ttl=1,rdlength=1,rdata=1};
local t;
for s,i in o({'answer','authority','additional'})do
for s,e in o(e[i])do
for h,o in o({'name','type','class','ttl','rdlength'})do
t=a.format('%s[%i].%s',i,s,o);
f(a.format('%-30s',t),e[o],n(e,o));
end
for e,o in o(e)do
if not h[e]then
t=a.format('%s[%i].%s',i,s,e);
f(a.format('%-30s %s',p(t),p(o)));
end
end
end
end
end
function t.resolver()
local t={active={},cache={},unsorted={},wanted={},best_server=1};
r(t,e);
r(t.cache,w);
r(t.unsorted,{__mode='kv'});
return t;
end
local e=t.resolver();
t._resolver=e;
function t.lookup(...)
return e:lookup(...);
end
function t.tohostname(...)
return e:tohostname(...);
end
function t.purge(...)
return e:purge(...);
end
function t.peek(...)
return e:peek(...);
end
function t.query(...)
return e:query(...);
end
function t.feed(...)
return e:feed(...);
end
function t.cancel(...)
return e:cancel(...);
end
function t.settimeout(...)
return e:settimeout(...);
end
function t.cache()
return e.cache;
end
function t.socket_wrapper_set(...)
return e:socket_wrapper_set(...);
end
return t;
end)
package.preload['net.adns']=(function(...)
local c=require"net.server";
local a=require"net.dns";
local e=require"util.logger".init("adns");
local t,t=table.insert,table.remove;
local o,r,l=coroutine,tostring,pcall;
local function u(a,a,e,t)return(t-e)+1;end
module"adns"
function lookup(d,t,h,s)
return o.wrap(function(i)
if i then
e("debug","Records for %s already cached, using those...",t);
d(i);
return;
end
e("debug","Records for %s not in cache, sending query (%s)...",t,r(o.running()));
local i,n=a.query(t,h,s);
if i then
o.yield({s or"IN",h or"A",t,o.running()});
e("debug","Reply for %s (%s)",t,r(o.running()));
end
if i then
i,n=l(d,a.peek(t,h,s));
else
e("error","Error sending DNS query: %s",n);
i,n=l(d,nil,n);
end
if not i then
e("error","Error in DNS response handler: %s",r(n));
end
end)(a.peek(t,h,s));
end
function cancel(t,o,i)
e("warn","Cancelling DNS lookup for %s",r(t[3]));
a.cancel(t[1],t[2],t[3],t[4],o);
end
function new_async_socket(o,i)
local n="<unknown>";
local s={};
local t={};
local h;
function s.onincoming(o,e)
if e then
a.feed(t,e);
end
end
function s.ondisconnect(a,o)
if o then
e("warn","DNS socket for %s disconnected: %s",n,o);
local t=i.server;
if i.socketset[a]==i.best_server and i.best_server==#t then
e("error","Exhausted all %d configured DNS servers, next lookup will try %s again",#t,t[1]);
end
i:servfail(a);
end
end
t,h=c.wrapclient(o,"dns",53,s);
if not t then
return nil,h;
end
t.settimeout=function()end
t.setsockname=function(e,...)return o:setsockname(...);end
t.setpeername=function(i,...)n=(...);local a,e=o:setpeername(...);i:set_send(u);return a,e;end
t.connect=function(e,...)return o:connect(...)end
t.send=function(a,t)
e("debug","Sending DNS query to %s",n);
return o:send(t);
end
return t;
end
a.socket_wrapper_set(new_async_socket);
return _M;
end)
package.preload['net.server']=(function(...)
local l=function(e)
return _G[e]
end
local M,e=require("util.logger").init("socket"),table.concat;
local i=function(...)return M("debug",e{...});end
local H=function(...)return M("warn",e{...});end
local ce=1
local F=l"type"
local W=l"pairs"
local de=l"ipairs"
local y=l"tonumber"
local h=l"tostring"
local t=l"os"
local o=l"table"
local a=l"string"
local e=l"coroutine"
local Z=t.difftime
local X=math.min
local re=math.huge
local fe=o.concat
local me=a.sub
local we=e.wrap
local ye=e.yield
local x=l"ssl"
local b=l"socket"or require"socket"
local J=b.gettime
local ve=(x and x.wrap)
local he=b.bind
local pe=b.sleep
local be=b.select
local G
local B
local ae
local K
local te
local c
local ee
local oe
local ne
local ie
local se
local Q
local r
local le
local D
local ue
local p
local s
local R
local d
local n
local S
local g
local f
local m
local a
local o
local v
local U
local C
local T
local E
local k
local V
local u
local _
local z
local A
local I
local O
local L
local j
local q
local N
p={}
s={}
d={}
R={}
n={}
g={}
f={}
S={}
a=0
o=0
v=0
U=0
C=0
T=1
E=0
k=128
_=51e3*1024
z=25e3*1024
A=12e5
I=6e4
O=6*60*60
local e=package.config:sub(1,1)=="\\"
q=(e and math.huge)or b._SETSIZE or 1024
j=b._SETSIZE or 1024
N=30
ie=function(w,t,f,l,v,u)
if t:getfd()>=q then
H("server.lua: Disallowed FD number: "..t:getfd())
t:close()
return nil,"fd-too-large"
end
local m=0
local y,e=w.onconnect,w.ondisconnect
local b=t.accept
local e={}
e.shutdown=function()end
e.ssl=function()
return u~=nil
end
e.sslctx=function()
return u
end
e.remove=function()
m=m-1
if e then
e.resume()
end
end
e.close=function()
t:close()
o=r(d,t,o)
a=r(s,t,a)
p[f..":"..l]=nil;
n[t]=nil
e=nil
t=nil
i"server.lua: closed server handler and removed sockets from list"
end
e.pause=function(o)
if not e.paused then
a=r(s,t,a)
if o then
n[t]=nil
t:close()
t=nil;
end
e.paused=true;
end
end
e.resume=function()
if e.paused then
if not t then
t=he(f,l,k);
t:settimeout(0)
end
a=c(s,t,a)
n[t]=e
e.paused=false;
end
end
e.ip=function()
return f
end
e.serverport=function()
return l
end
e.socket=function()
return t
end
e.readbuffer=function()
if a>=j or o>=j then
e.pause()
i("server.lua: refused new client connection: server full")
return false
end
local t,o=b(t)
if t then
local o,a=t:getpeername()
local t,n,e=D(e,w,t,o,l,a,v,u)
if e then
return false
end
m=m+1
i("server.lua: accepted new client connection from ",h(o),":",h(a)," to ",h(l))
if y and not u then
return y(t);
end
return;
elseif o then
i("server.lua: error with new client connection: ",h(o))
return false
end
end
return e
end
D=function(E,y,t,I,Q,O,T,j)
if t:getfd()>=q then
H("server.lua: Disallowed FD number: "..t:getfd())
t:close()
if E then
E.pause()
end
return nil,nil,"fd-too-large"
end
t:settimeout(0)
local p
local A
local k
local P
local W=y.onincoming
local Y=y.onstatus
local b=y.ondisconnect
local F=y.ondrain
local M=y.ondetach
local v={}
local l=0
local V
local B
local L
local w=0
local q=false
local H=false
local D,R=0,0
local _=_
local z=z
local e=v
e.dispatch=function()
return W
end
e.disconnect=function()
return b
end
e.setlistener=function(a,t)
if M then
M(a)
end
W=t.onincoming
b=t.ondisconnect
Y=t.onstatus
F=t.ondrain
M=t.ondetach
end
e.getstats=function()
return R,D
end
e.ssl=function()
return P
end
e.sslctx=function()
return j
end
e.send=function(n,o,i,a)
return p(t,o,i,a)
end
e.receive=function(o,a)
return A(t,o,a)
end
e.shutdown=function(a)
return k(t,a)
end
e.setoption=function(i,a,o)
if t.setoption then
return t:setoption(a,o);
end
return false,"setoption not implemented";
end
e.force_close=function(t,a)
if l~=0 then
i("server.lua: discarding unwritten data for ",h(I),":",h(O))
l=0;
end
return t:close(a);
end
e.close=function(u,h)
if not e then return true;end
a=r(s,t,a)
g[e]=nil
if l~=0 then
e.sendbuffer()
if l~=0 then
if e then
e.write=nil
end
V=true
return false
end
end
if t then
m=k and k(t)
t:close()
o=r(d,t,o)
n[t]=nil
t=nil
else
i"server.lua: socket already closed"
end
if e then
f[e]=nil
S[e]=nil
local t=e;
e=nil
if b then
b(t,h or false);
b=nil
end
end
if E then
E.remove()
end
i"server.lua: closed client handler and removed socket from list"
return true
end
e.ip=function()
return I
end
e.serverport=function()
return Q
end
e.clientport=function()
return O
end
e.port=e.clientport
local b=function(i,a)
w=w+#a
if w>_ then
S[e]="send buffer exceeded"
e.write=K
return false
elseif t and not d[t]then
o=c(d,t,o)
end
l=l+1
v[l]=a
if e then
f[e]=f[e]or u
end
return true
end
e.write=b
e.bufferqueue=function(t)
return v
end
e.socket=function(a)
return t
end
e.set_mode=function(a,t)
T=t or T
return T
end
e.set_send=function(a,t)
p=t or p
return p
end
e.bufferlen=function(o,a,t)
_=t or _
z=a or z
return w,z,_
end
e.lock_read=function(i,o)
if o==true then
local o=a
a=r(s,t,a)
g[e]=nil
if a~=o then
q=true
end
elseif o==false then
if q then
q=false
a=c(s,t,a)
g[e]=u
end
end
return q
end
e.pause=function(t)
return t:lock_read(true);
end
e.resume=function(t)
return t:lock_read(false);
end
e.lock=function(i,a)
e.lock_read(a)
if a==true then
e.write=K
local a=o
o=r(d,t,o)
f[e]=nil
if o~=a then
H=true
end
elseif a==false then
e.write=b
if H then
H=false
b("")
end
end
return q,H
end
local b=function()
local a,t,o=A(t,T)
if not t or(t=="wantread"or t=="timeout")then
local o=a or o or""
local a=#o
if a>z then
e:close("receive buffer exceeded")
return false
end
local a=a*ce
R=R+a
C=C+a
g[e]=u
return W(e,o,t)
else
i("server.lua: client ",h(I),":",h(O)," read error: ",h(t))
B=true
m=e and e:force_close(t)
return false
end
end
local w=function()
local c,a,n,s,y;
if t then
s=fe(v,"",1,l)
c,a,n=p(t,s,1,w)
y=(c or n or 0)*ce
D=D+y
U=U+y
for e=l,1,-1 do
v[e]=nil
end
else
c,a,y=false,"unexpected close",0;
end
if c then
l=0
w=0
o=r(d,t,o)
f[e]=nil
if F then
F(e)
end
m=L and e:starttls(nil)
m=V and e:force_close()
return true
elseif n and(a=="timeout"or a=="wantwrite")then
s=me(s,n+1,w)
v[1]=s
l=1
w=w-n
f[e]=u
return true
else
i("server.lua: client ",h(I),":",h(O)," write error: ",h(a))
B=true
m=e and e:force_close(a)
return false
end
end
local u;
function e.set_sslctx(p,t)
j=t;
local l,f
u=we(function(n)
local t
for h=1,N do
o=(f and r(d,n,o))or o
a=(l and r(s,n,a))or a
l,f=nil,nil
m,t=n:dohandshake()
if not t then
i("server.lua: ssl handshake done")
e.readbuffer=b
e.sendbuffer=w
m=Y and Y(e,"ssl-handshake-complete")
if p.autostart_ssl and y.onconnect then
y.onconnect(p);
end
a=c(s,n,a)
return true
else
if t=="wantwrite"then
o=c(d,n,o)
f=true
elseif t=="wantread"then
a=c(s,n,a)
l=true
else
break;
end
t=nil;
ye()
end
end
i("server.lua: ssl handshake error: ",h(t or"handshake too long"))
m=e and e:force_close("ssl handshake failed")
return false,t
end
)
end
if x then
e.starttls=function(f,m)
if m then
e:set_sslctx(m);
end
if l>0 then
i"server.lua: we need to do tls, but delaying until send buffer empty"
L=true
return
end
i("server.lua: attempting to start tls on "..h(t))
local m,l=t
t,l=ve(t,j)
if not t then
i("server.lua: error while starting tls on client: ",h(l or"unknown error"))
return nil,l
end
t:settimeout(0)
p=t.send
A=t.receive
k=G
n[t]=e
a=c(s,t,a)
a=r(s,m,a)
o=r(d,m,o)
n[m]=nil
e.starttls=nil
L=nil
P=true
e.readbuffer=u
e.sendbuffer=u
return u(t)
end
end
e.readbuffer=b
e.sendbuffer=w
p=t.send
A=t.receive
k=(P and G)or t.shutdown
n[t]=e
a=c(s,t,a)
if j and x then
i"server.lua: auto-starting ssl negotiation..."
e.autostart_ssl=true;
local t,e=e:starttls(j);
if t==false then
return nil,nil,e
end
end
return e,t
end
G=function()
end
K=function()
return false
end
c=function(t,a,e)
if not t[a]then
e=e+1
t[e]=a
t[a]=e
end
return e;
end
r=function(e,a,t)
local o=e[a]
if o then
e[a]=nil
local i=e[t]
e[t]=nil
if i~=a then
e[i]=o
e[o]=i
end
return t-1
end
return t
end
Q=function(e)
o=r(d,e,o)
a=r(s,e,a)
n[e]=nil
e:close()
end
local function w(e,a,o)
local t;
local i=a.sendbuffer;
function a.sendbuffer()
i();
if t and a.bufferlen()<o then
e:lock_read(false);
t=nil;
end
end
local i=e.readbuffer;
function e.readbuffer()
i();
if not t and a.bufferlen()>=o then