local function debug(...)\r
return log("debug", ("%s "):rep(select('#', ...)), ...)\r
end\r
+local vdebug = debug;\r
\r
local bitor = ( function( ) -- thx Rici Lake\r
local hasbit = function( x, p )\r
self.fatalerror = "connection timeout"\r
self.listener.ontimeout( self ) -- call timeout listener\r
self:_close()\r
- debug( "new connection failed. id:", self, "error:", self.fatalerror )\r
+ debug( "new connection failed. id:", self.id, "error:", self.fatalerror )\r
else\r
if plainssl then -- start ssl session\r
self:_start_ssl( self.listener.onconnect )\r
else -- normal connection\r
self:_start_session( self.listener.onconnect )\r
end\r
- debug( "new connection established. id:", self )\r
+ debug( "new connection established. id:", self.id )\r
end\r
self.eventconnect = nil\r
return -1\r
if self.type == "client" then\r
local callback = function( )\r
self:_lock( false, false, false )\r
- --vdebug( "start listening on client socket with id:", self ) \r
+ --vdebug( "start listening on client socket with id:", self.id ) \r
self.eventread = addevent( base, self.conn, EV_READ, self.readcallback, cfg.READ_TIMEOUT ) -- register callback\r
- onconnect( self )\r
+ self:onconnect()\r
self.eventsession = nil\r
return -1\r
end\r
self.eventsession = addevent( base, nil, EV_TIMEOUT, callback, 0 )\r
else\r
self:_lock( false )\r
- --vdebug( "start listening on server socket with id:", self )\r
+ --vdebug( "start listening on server socket with id:", self.id )\r
self.eventread = addevent( base, self.conn, EV_READ, self.readcallback ) -- register callback\r
end\r
return true\r
end\r
function interface_mt:_start_ssl(arg) -- old socket will be destroyed, therefore we have to close read/write events first\r
- --vdebug( "starting ssl session with client id:", self )\r
+ --vdebug( "starting ssl session with client id:", self.id )\r
local _\r
_ = self.eventread and self.eventread:close( ) -- close events; this must be called outside of the event callbacks!\r
_ = self.eventwrite and self.eventwrite:close( )\r
self.eventread, self.eventwrite = nil, nil\r
local err\r
- self.conn, err = ssl.wrap( self.conn, self.sslctx )\r
+ self.conn, err = ssl.wrap( self.conn, self._sslctx )\r
if err then\r
self.fatalerror = err\r
self.conn = nil -- cannot be used anymore\r
local maxattempt = cfg.MAX_HANDSHAKE_ATTEMPS\r
while attempt < 1000 do -- no endless loop\r
attempt = attempt + 1\r
- debug( "ssl handshake of client with id:", self, "attemp:", attempt )\r
+ debug( "ssl handshake of client with id:"..tostring(self).."attemp:"..attempt )\r
if attempt > maxattempt then\r
self.fatalerror = "max handshake attemps exceeded"\r
elseif EV_TIMEOUT == event then\r
self.receive = self.conn.receive\r
local onsomething\r
if "onconnect" == arg then -- trigger listener\r
- onsomething = self.listener.onconnect\r
+ onsomething = self.onconnect\r
else\r
- onsomething = self.listener.onsslconnection\r
+ onsomething = self.onsslconnection\r
end\r
self:_start_session( onsomething )\r
debug( "ssl handshake done" )\r
self.eventhandshake = nil\r
return -1\r
end\r
- debug( "error during ssl handshake:", err ) \r
+ debug( "error during ssl handshake:", err ) \r
if err == "wantwrite" then\r
event = EV_WRITE\r
elseif err == "wantread" then\r
return true\r
end\r
function interface_mt:_destroy() -- close this interface + events and call last listener\r
- debug( "closing client with id:", self )\r
+ debug( "closing client with id:", self.id )\r
self:_lock( true, true, true ) -- first of all, lock the interface to avoid further actions\r
local _\r
_ = self.eventread and self.eventread:close( ) -- close events; this must be called outside of the event callbacks!\r
interfacelist( "delete", self )\r
return true\r
end\r
+ \r
function interface_mt:_lock(nointerface, noreading, nowriting) -- lock or unlock this interface or events\r
self.nointerface, self.noreading, self.nowriting = nointerface, noreading, nowriting\r
return nointerface, noreading, nowriting\r
\r
-- Public methods\r
function interface_mt:write(data)\r
- --vdebug( "try to send data to client, id/data:", self, data )\r
+ if self.nowriting then return nil, "locked" end\r
+ --vdebug( "try to send data to client, id/data:", self.id, data )\r
data = tostring( data )\r
local len = string_len( data )\r
local total = len + self.writebufferlen\r
return true\r
end\r
function interface_mt:close(now)\r
- debug( "try to close client connection with id:", self )\r
+ if self.nointerface then return nil, "locked"; end\r
+ debug( "try to close client connection with id:", self.id )\r
if self.type == "client" then\r
self.fatalerror = "client to close"\r
if ( not self.eventwrite ) or now then -- try to close immediately\r
return nil, "writebuffer not empty, waiting"\r
end\r
else\r
- debug( "try to close server with id:", self, "args:", now )\r
+ debug( "try to close server with id:", self.id, "args:", now )\r
self.fatalerror = "server to close"\r
self:_lock( true )\r
local count = 0\r
end\r
\r
function interface_mt:ssl()\r
- return self.usingssl\r
+ return self._usingssl\r
end\r
\r
function interface_mt:type()\r
return self.addr\r
end\r
\r
- \r
+ function interface_mt:set_sslctx(sslctx)\r
+ self._sslctx = sslctx;\r
+ end\r
\r
function interface_mt:starttls()\r
- debug( "try to start ssl at client id:", self )\r
+ debug( "try to start ssl at client id:", self.id )\r
local err\r
- if not self.sslctx then -- no ssl available\r
+ if not self._sslctx then -- no ssl available\r
err = "no ssl context available"\r
- elseif self.usingssl then -- startssl was already called\r
+ elseif self._usingssl then -- startssl was already called\r
err = "ssl already active"\r
end\r
if err then\r
debug( "error:", err )\r
return nil, err \r
end\r
- self.usingssl = true\r
+ self._usingssl = true\r
self.startsslcallback = function( ) -- we have to start the handshake outside of a read/write event\r
+ self.startsslcallback = nil\r
self:_start_ssl();\r
self.eventstarthandshake = nil\r
return -1\r
_sslctx = sslctx; -- parameters\r
_usingssl = false; -- client is using ssl;\r
}\r
+ interface.id = tostring(interface):match("%x+$");\r
interface.writecallback = function( event ) -- called on write events\r
--vdebug( "new client write event, id/ip/port:", interface, ip, port )\r
if interface.nowriting or ( interface.fatalerror and ( "client to close" ~= interface.fatalerror ) ) then -- leave this event\r
interface.eventwrite = false\r
return -1\r
else -- can write :)\r
- if interface.usingssl then -- handle luasec\r
+ if interface._usingssl then -- handle luasec\r
if interface.eventreadtimeout then -- we have to read first\r
local ret = interface.readcallback( ) -- call readcallback\r
--vdebug( "tried to read in writecallback, result:", ret )\r
interface.eventwritetimeout = false\r
end\r
end\r
- local succ, err, byte = interface.send( interface.conn, interface.writebuffer, 1, interface.writebufferlen )\r
+ local succ, err, byte = interface.conn:send( interface.writebuffer, 1, interface.writebufferlen )\r
--vdebug( "write data:", interface.writebuffer, "error:", err, "part:", byte )\r
if succ then -- writing succesful\r
interface.writebuffer = ""\r
end\r
end\r
end\r
- local usingssl, receive = interface._usingssl, interface.receive;\r
+ \r
interface.readcallback = function( event ) -- called on read events\r
--vdebug( "new client read event, id/ip/port:", interface, ip, port )\r
if interface.noreading or interface.fatalerror then -- leave this event\r
interface.eventread = nil\r
return -1\r
else -- can read\r
- if usingssl then -- handle luasec\r
+ if interface._usingssl then -- handle luasec\r
if interface.eventwritetimeout then -- ok, in the past writecallback was regged\r
local ret = interface.writecallback( ) -- call it\r
--vdebug( "tried to write in readcallback, result:", ret )\r
interface.eventreadtimeout = nil\r
end\r
end\r
- local buffer, err, part = receive( client, pattern ) -- receive buffer with "pattern"\r
- --vdebug( "read data:", buffer, "error:", err, "part:", part ) \r
+ local buffer, err, part = interface.conn:receive( pattern ) -- receive buffer with "pattern"\r
+ --vdebug( "read data:", tostring(buffer), "error:", tostring(err), "part:", tostring(part) ) \r
buffer = buffer or part or ""\r
local len = string_len( buffer )\r
if len > cfg.MAX_READ_LENGTH then -- check buffer length\r
interface.eventread = nil\r
return -1\r
end\r
- if err and ( "timeout" ~= err ) then\r
+ if err and ( err ~= "timeout" and err ~= "wantread" ) then\r
if "wantwrite" == err then -- need to read on write event\r
if not interface.eventwrite then -- register new write event if needed\r
interface.eventwrite = addevent( base, interface.conn, EV_WRITE, interface.writecallback, cfg.WRITE_TIMEOUT )\r
fatalerror = false; -- error message\r
nointerface = true; -- lock/unlock parameter\r
}\r
+ interface.id = tostring(interface):match("%x+$");\r
interface.readcallback = function( event ) -- server handler, called on incoming connections\r
--vdebug( "server can accept, id/addr/port:", interface, addr, port )\r
if interface.fatalerror then\r
end\r
\r
local addserver = ( function( )\r
- return function( addr, port, listener, pattern, backlog, sslcfg, startssl ) -- TODO: check arguments\r
- debug( "creating new tcp server with following parameters:", addr or "nil", port or "nil", sslcfg or "nil", startssl or "nil")\r
- local server, err = socket.bind( addr, port, backlog ) -- create server socket\r
+ return function( addr, port, listener, pattern, sslcfg, startssl ) -- TODO: check arguments\r
+ --vdebug( "creating new tcp server with following parameters:", addr or "nil", port or "nil", sslcfg or "nil", startssl or "nil")\r
+ local server, err = socket.bind( addr, port, cfg.ACCEPT_QUEUE ) -- create server socket\r
if not server then\r
debug( "creating server socket failed because:", err )\r
return nil, err\r
base = base,\r
loop = loop,\r
event = event,\r
+ event_base = base,\r
addevent = newevent,\r
addserver = addserver,\r
addclient = addclient,\r