portmanager: Show a friendly error message when initializing SSL fails (thanks MattJ...
[prosody.git] / net / server_event.lua
index 122d80fcc0dee0f8163fe2a46d893ea7521764c3..de44e5fdbf826e535dfe3f8d2c9c776529c371dd 100644 (file)
@@ -33,8 +33,6 @@ local cfg = {
 }
 
 local function use(x) return rawget(_G, x); end
-local print = use "print"
-local pcall = use "pcall"
 local ipairs = use "ipairs"
 local string = use "string"
 local select = use "select"
@@ -143,7 +141,7 @@ do
                                        debug( "new connection failed. id:", self.id, "error:", self.fatalerror )
                                else
                                        if plainssl and ssl then  -- start ssl session
-                                               self:starttls(nil, true)
+                                               self:starttls(self._sslctx, true)
                                        else  -- normal connection
                                                self:_start_session(true)
                                        end
@@ -212,7 +210,6 @@ do
                                                                self:_lock( false, false, false )  -- unlock the interface; sending, closing etc allowed
                                                                self.send = self.conn.send  -- caching table lookups with new client object
                                                                self.receive = self.conn.receive
-                                                               local onsomething
                                                                if not call_onconnect then  -- trigger listener
                                                                        self:onstatus("ssl-handshake-complete");
                                                                end
@@ -221,12 +218,12 @@ do
                                                                self.eventhandshake = nil
                                                                return -1
                                                        end
-                                                       debug( "error during ssl handshake:", err )
                                                        if err == "wantwrite" then
                                                                event = EV_WRITE
                                                        elseif err == "wantread" then
                                                                event = EV_READ
                                                        else
+                                                               debug( "ssl handshake error:", err )
                                                                self.fatalerror = err
                                                        end
                                                end
@@ -249,7 +246,7 @@ do
                        return true
        end
        function interface_mt:_destroy()  -- close this interface + events and call last listener
-                       debug( "closing client with id:", self.id )
+                       debug( "closing client with id:", self.id, self.fatalerror )
                        self:_lock( true, true, true )  -- first of all, lock the interface to avoid further actions
                        local _
                        _ = self.eventread and self.eventread:close( )  -- close events; this must be called outside of the event callbacks!
@@ -295,7 +292,10 @@ do
        end
 
        function interface_mt:resume()
-               return self:_lock(self.nointerface, false, self.nowriting);
+               self:_lock(self.nointerface, false, self.nowriting);
+               if not self.eventread then
+                       self.eventread = addevent( base, self.conn, EV_READ, self.readcallback, cfg.READ_TIMEOUT );  -- register callback
+               end
        end
 
        function interface_mt:counter(c)
@@ -325,39 +325,26 @@ do
                end
                return true
        end
-       function interface_mt:close(now)
+       function interface_mt:close()
                if self.nointerface then return nil, "locked"; end
                debug( "try to close client connection with id:", self.id )
                if self.type == "client" then
                        self.fatalerror = "client to close"
-                       if ( not self.eventwrite ) or now then  -- try to close immediately
-                               self:_lock( true, true, true )
-                               self:_close()
-                               return true
-                       else  -- wait for incomplete write request
+                       if self.eventwrite then -- wait for incomplete write request
                                self:_lock( true, true, false )
                                debug "closing delayed until writebuffer is empty"
                                return nil, "writebuffer not empty, waiting"
+                       else -- close now
+                               self:_lock( true, true, true )
+                               self:_close()
+                               return true
                        end
                else
-                       debug( "try to close server with id:", self.id, "args:", now )
+                       debug( "try to close server with id:", tostring(self.id))
                        self.fatalerror = "server to close"
                        self:_lock( true )
-                       local count = 0
-                       for _, item in ipairs( interfacelist( ) ) do
-                               if ( item.type ~= "server" ) and ( item._server == self ) then  -- client/server match
-                                       if item:close( now ) then  -- writebuffer was empty
-                                               count = count + 1
-                                       end
-                               end
-                       end
-                       local timeout = 0  -- dont wait for unfinished writebuffers of clients...
-                       if not now then
-                               timeout = cfg.WRITE_TIMEOUT  -- ...or wait for it
-                       end
-                       self:_close( timeout )  -- add new event to remove the server interface
-                       debug( "seconds remained until server is closed:", timeout )
-                       return count  -- returns finished clients with empty writebuffer
+                       self:_close( 0 )  -- add new event to remove the server interface
+                       return true
                end
        end
        
@@ -460,7 +447,6 @@ do
        
        -- Stub handlers
        function interface_mt:onconnect()
-               return self:onincoming(nil);
        end
        function interface_mt:onincoming()
        end
@@ -481,10 +467,8 @@ do
        local string_sub = string.sub  -- caching table lookups
        local string_len = string.len
        local addevent = base.addevent
-       local coroutine_wrap = coroutine.wrap
        local socket_gettime = socket.gettime
-       local coroutine_yield = coroutine.yield
-       function handleclient( client, ip, port, server, pattern, listener, _, sslctx )  -- creates an client interface
+       function handleclient( client, ip, port, server, pattern, listener, sslctx )  -- creates an client interface
                --vdebug("creating client interfacce...")
                local interface = {
                        type = "client";
@@ -643,6 +627,10 @@ do
                                                return -1
                                        end
                                end
+                               if interface.noreading then
+                                       interface.eventread = nil;
+                                       return -1;
+                               end
                                return EV_READ, cfg.READ_TIMEOUT
                        end
                end
@@ -699,7 +687,7 @@ do
                                end
                                local client_ip, client_port = client:getpeername( )
                                interface._connections = interface._connections + 1  -- increase connection count
-                               local clientinterface = handleclient( client, client_ip, client_port, interface, pattern, listener, nil, sslctx )
+                               local clientinterface = handleclient( client, client_ip, client_port, interface, pattern, listener, sslctx )
                                --vdebug( "client id:", clientinterface, "startssl:", startssl )
                                if ssl and sslctx then
                                        clientinterface:starttls(sslctx, true)
@@ -726,7 +714,7 @@ local addserver = ( function( )
                --vdebug( "creating new tcp server with following parameters:", addr or "nil", port or "nil", sslcfg or "nil", startssl or "nil")
                local server, err = socket.bind( addr, port, cfg.ACCEPT_QUEUE )  -- create server socket
                if not server then
-                       debug( "creating server socket failed because:", err )
+                       debug( "creating server socket on "..addr.." port "..port.." failed:", err )
                        return nil, err
                end
                local sslctx
@@ -749,9 +737,9 @@ end )( )
 
 local addclient, wrapclient
 do
-       function wrapclient( client, ip, port, listeners, pattern, sslctx, startssl )
+       function wrapclient( client, ip, port, listeners, pattern, sslctx )
                local interface = handleclient( client, ip, port, nil, pattern, listeners, sslctx )
-               interface:_start_session()
+               interface:_start_connection(sslctx)
                return interface, client
                --function handleclient( client, ip, port, server, pattern, listener, _, sslctx )  -- creates an client interface
        end
@@ -785,9 +773,6 @@ do
                local res, err = client:connect( addr, serverport )  -- connect
                if res or ( err == "timeout" ) then
                        local ip, port = client:getsockname( )
-                       local server = function( )
-                               return nil, "this is a dummy server interface"
-                       end
                        local interface = wrapclient( client, ip, serverport, listener, pattern, sslctx, startssl )
                        interface:_start_connection( startssl )
                        debug( "new connection id:", interface.id )
@@ -828,14 +813,14 @@ local function setquitting(yes)
        end
 end
 
-function get_backend()
+local function get_backend()
        return base:method();
 end
 
 -- We need to hold onto the events to stop them
 -- being garbage-collected
 local signal_events = {}; -- [signal_num] -> event object
-function hook_signal(signal_num, handler)
+local function hook_signal(signal_num, handler)
        local function _handler(event)
                local ret = handler();
                if ret ~= false then -- Continue handling this signal?