Merge 0.10->trunk
[prosody.git] / net / server_event.lua
index 677586645fd233b010ce82f66a169082d0a0ac86..c10173e48cea11f9678ef9276f9c518fda64ba0c 100644 (file)
@@ -30,6 +30,7 @@ local cfg = {
        WRITE_TIMEOUT         = 180,  -- timeout in seconds for write data on socket
        CONNECT_TIMEOUT       = 20,  -- timeout in seconds for connection attempts
        CLEAR_DELAY           = 5,  -- seconds to wait for clearing interface list (and calling ondisconnect listeners)
+       READ_RETRY_DELAY      = 1e-06, -- if, after reading, there is still data in buffer, wait this long and continue reading
        DEBUG                 = true,  -- show debug messages
 }
 
@@ -238,8 +239,8 @@ function interface_mt:_destroy()  -- close this interface + events and call last
 end
 
 function interface_mt:_lock(nointerface, noreading, nowriting)  -- lock or unlock this interface or events
-               self.nointerface, self.noreading, self.nowriting = nointerface, noreading, nowriting
-               return nointerface, noreading, nowriting
+       self.nointerface, self.noreading, self.nowriting = nointerface, noreading, nowriting
+       return nointerface, noreading, nowriting
 end
 
 --TODO: Deprecate
@@ -257,8 +258,9 @@ end
 
 function interface_mt:resume()
        self:_lock(self.nointerface, false, self.nowriting);
-       if not self.eventread then
+       if self.readcallback and not self.eventread then
                self.eventread = addevent( base, self.conn, EV_READ, self.readcallback, cfg.READ_TIMEOUT );  -- register callback
+               return true;
        end
 end
 
@@ -390,7 +392,8 @@ function interface_mt:starttls(sslctx, call_onconnect)
        if not self.eventwrite then
                self:_lock( true, true, true )  -- lock the interface, to not disturb the handshake
                self.eventstarthandshake = addevent( base, nil, EV_TIMEOUT, self.startsslcallback, 0 )  -- add event to start handshake
-       else  -- wait until writebuffer is empty
+       else
+               -- wait until writebuffer is empty
                self:_lock( true, true, false )
                debug "ssl session delayed until writebuffer is empty..."
        end
@@ -407,10 +410,13 @@ end
 
 function interface_mt:setlistener(listener)
        self:ondetach(); -- Notify listener that it is no longer responsible for this connection
-       self.onconnect, self.ondisconnect, self.onincoming, self.ontimeout,
-       self.onreadtimeout, self.onstatus, self.ondetach
-               = listener.onconnect, listener.ondisconnect, listener.onincoming, listener.ontimeout,
-                 listener.onreadtimeout, listener.onstatus, listener.ondetach;
+       self.onconnect = listener.onconnect;
+       self.ondisconnect = listener.ondisconnect;
+       self.onincoming = listener.onincoming;
+       self.ontimeout = listener.ontimeout;
+       self.onreadtimeout = listener.onreadtimeout;
+       self.onstatus = listener.onstatus;
+       self.ondetach = listener.ondetach;
 end
 
 -- Stub handlers
@@ -513,8 +519,11 @@ local function handleclient( client, ip, port, server, pattern, listener, sslctx
                                elseif interface.startsslcallback then  -- start ssl connection if needed
                                        debug "starting ssl handshake after writing"
                                        interface.eventstarthandshake = addevent( base, nil, EV_TIMEOUT, interface.startsslcallback, 0 )
+                               elseif interface.writebufferlen ~= 0 then
+                                       -- data possibly written from ondrain
+                                       return EV_WRITE, cfg.WRITE_TIMEOUT
                                elseif interface.eventreadtimeout then
-                                       return EV_WRITE, EV_TIMEOUT
+                                       return EV_WRITE, cfg.WRITE_TIMEOUT
                                end
                                interface.eventwrite = nil
                                return -1
@@ -551,7 +560,7 @@ local function handleclient( client, ip, port, server, pattern, listener, sslctx
                        interface.eventread = nil
                        return -1
                end
-               if EV_TIMEOUT == event and interface:onreadtimeout() ~= true then
+               if EV_TIMEOUT == event and not interface.conn:dirty() and interface:onreadtimeout() ~= true then
                        return -1 -- took too long to get some data from client -> disconnect
                end
                if interface._usingssl then  -- handle luasec
@@ -580,10 +589,7 @@ local function handleclient( client, ip, port, server, pattern, listener, sslctx
                                        interface.eventwrite = addevent( base, interface.conn, EV_WRITE, interface.writecallback, cfg.WRITE_TIMEOUT )
                                end
                                interface.eventreadtimeout = addevent( base, nil, EV_TIMEOUT,
-                                       function( )
-                                               interface:_close()
-                                       end, cfg.READ_TIMEOUT
-                               )
+                                       function( ) interface:_close() end, cfg.READ_TIMEOUT)
                                debug( "wantwrite during read attempt, reg it in writecallback but dont know what really happens next..." )
                                -- to be honest i dont know what happens next, if it is allowed to first read, the write etc...
                        else  -- connection was closed or fatal error
@@ -600,6 +606,9 @@ local function handleclient( client, ip, port, server, pattern, listener, sslctx
                        interface.eventread = nil;
                        return -1;
                end
+               if interface.conn:dirty() then -- still data left in buffer
+                       return EV_TIMEOUT, cfg.READ_RETRY_DELAY;
+               end
                return EV_READ, cfg.READ_TIMEOUT
        end
 
@@ -702,14 +711,16 @@ local function addclient( addr, serverport, listener, pattern, sslctx, typ )
                debug "need luasec, but not available"
                return nil, "luasec not found"
        end
-       if getaddrinfo and not typ then
+       if not typ then
                local addrinfo, err = getaddrinfo(addr)
                if not addrinfo then return nil, err end
                if addrinfo[1] and addrinfo[1].family == "inet6" then
                        typ = "tcp6"
+               else
+                       typ = "tcp"
                end
        end
-       local create = socket[typ or "tcp"]
+       local create = socket[typ]
        if type( create ) ~= "function"  then
                return nil, "invalid socket type"
        end
@@ -720,11 +731,9 @@ local function addclient( addr, serverport, listener, pattern, sslctx, typ )
        end
        client:settimeout( 0 )  -- set nonblocking
        local res, err = client:connect( addr, serverport )  -- connect
-       if res or ( err == "timeout" or err == "Operation already in progress" ) then
-               if client.getsockname then
-                       addr = client:getsockname( )
-               end
-               local interface = wrapclient( client, addr, serverport, listener, pattern, sslctx )
+       if res or ( err == "timeout" ) then
+               local ip, port = client:getsockname( )
+               local interface = wrapclient( client, ip, serverport, listener, pattern, sslctx )
                debug( "new connection id:", interface.id )
                return interface, err
        else
@@ -740,7 +749,7 @@ end
 
 local function newevent( ... )
        return addevent( base, ... )
-       end
+end
 
 local function closeallservers ( arg )
        for item in pairs( interfacelist ) do
@@ -752,9 +761,9 @@ end
 
 local function setquitting(yes)
        if yes then
-                -- Quit now
-                closeallservers();
-                base:loopexit();
+               -- Quit now
+               closeallservers();
+               base:loopexit();
        end
 end