Merge with trunk
[prosody.git] / net / server_event.lua
index 15d1dea0d54fe60e890e125f07950d67a5713376..b467a84dc6c147e6f8ca034fb1e0809d5dcf25a7 100644 (file)
@@ -52,6 +52,7 @@ local log = require ("util.logger").init("socket")
 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
@@ -71,11 +72,6 @@ local bitor = ( function( ) -- thx Rici Lake
        end\r
 end )( )\r
 \r
-local getid = function( )\r
-       return function( )\r
-       end\r
-end\r
-\r
 local event = require "luaevent.core"\r
 local base = event.new( )\r
 local EV_READ = event.EV_READ\r
@@ -144,14 +140,14 @@ do
                                        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
@@ -163,28 +159,28 @@ do
                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
@@ -203,7 +199,7 @@ do
                                        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
@@ -216,16 +212,16 @@ do
                                                                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
@@ -253,7 +249,7 @@ do
                        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
@@ -279,6 +275,7 @@ do
                        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
@@ -293,7 +290,8 @@ do
        \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
@@ -311,7 +309,8 @@ do
                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
@@ -324,7 +323,7 @@ do
                                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
@@ -358,7 +357,7 @@ do
        end\r
        \r
        function interface_mt:ssl()\r
-               return self.usingssl\r
+               return self._usingssl\r
        end\r
 \r
        function interface_mt:type()\r
@@ -373,22 +372,25 @@ do
                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
@@ -448,6 +450,7 @@ do
                        _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
@@ -462,7 +465,7 @@ do
                                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
@@ -472,7 +475,7 @@ do
                                                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
@@ -513,7 +516,7 @@ do
                                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
@@ -528,7 +531,7 @@ do
                                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
@@ -538,8 +541,8 @@ do
                                                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
@@ -549,7 +552,7 @@ do
                                        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
@@ -596,6 +599,7 @@ do
                        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
@@ -644,9 +648,9 @@ do
 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
@@ -745,6 +749,7 @@ return {
        base = base,\r
        loop = loop,\r
        event = event,\r
+       event_base = base,\r
        addevent = newevent,\r
        addserver = addserver,\r
        addclient = addclient,\r