net/server_select.lua
changeset 2093 abfa1cc3a42f
parent 2059 d4fb80b60c65
child 2109 0dc5eb9dbb62
equal deleted inserted replaced
2092:28c0b313b610 2093:abfa1cc3a42f
       
     1 -- 
       
     2 -- server.lua by blastbeat of the luadch project
       
     3 -- Re-used here under the MIT/X Consortium License
       
     4 -- 
       
     5 -- Modifications (C) 2008-2009 Matthew Wild, Waqas Hussain
       
     6 --
       
     7 
       
     8 -- // wrapping luadch stuff // --
       
     9 
       
    10 local use = function( what )
       
    11     return _G[ what ]
       
    12 end
       
    13 local clean = function( tbl )
       
    14     for i, k in pairs( tbl ) do
       
    15         tbl[ i ] = nil
       
    16     end
       
    17 end
       
    18 
       
    19 local log, table_concat = require ("util.logger").init("socket"), table.concat;
       
    20 local out_put = function (...) return log("debug", table_concat{...}); end
       
    21 local out_error = function (...) return log("warn", table_concat{...}); end
       
    22 local mem_free = collectgarbage
       
    23 
       
    24 ----------------------------------// DECLARATION //--
       
    25 
       
    26 --// constants //--
       
    27 
       
    28 local STAT_UNIT = 1    -- byte
       
    29 
       
    30 --// lua functions //--
       
    31 
       
    32 local type = use "type"
       
    33 local pairs = use "pairs"
       
    34 local ipairs = use "ipairs"
       
    35 local tostring = use "tostring"
       
    36 local collectgarbage = use "collectgarbage"
       
    37 
       
    38 --// lua libs //--
       
    39 
       
    40 local os = use "os"
       
    41 local table = use "table"
       
    42 local string = use "string"
       
    43 local coroutine = use "coroutine"
       
    44 
       
    45 --// lua lib methods //--
       
    46 
       
    47 local os_time = os.time
       
    48 local os_difftime = os.difftime
       
    49 local table_concat = table.concat
       
    50 local table_remove = table.remove
       
    51 local string_len = string.len
       
    52 local string_sub = string.sub
       
    53 local coroutine_wrap = coroutine.wrap
       
    54 local coroutine_yield = coroutine.yield
       
    55 
       
    56 --// extern libs //--
       
    57 
       
    58 local luasec = select( 2, pcall( require, "ssl" ) )
       
    59 local luasocket = require "socket"
       
    60 
       
    61 --// extern lib methods //--
       
    62 
       
    63 local ssl_wrap = ( luasec and luasec.wrap )
       
    64 local socket_bind = luasocket.bind
       
    65 local socket_sleep = luasocket.sleep
       
    66 local socket_select = luasocket.select
       
    67 local ssl_newcontext = ( luasec and luasec.newcontext )
       
    68 
       
    69 --// functions //--
       
    70 
       
    71 local id
       
    72 local loop
       
    73 local stats
       
    74 local idfalse
       
    75 local addtimer
       
    76 local closeall
       
    77 local addserver
       
    78 local getserver
       
    79 local wrapserver
       
    80 local getsettings
       
    81 local closesocket
       
    82 local removesocket
       
    83 local removeserver
       
    84 local changetimeout
       
    85 local wrapconnection
       
    86 local changesettings
       
    87 
       
    88 --// tables //--
       
    89 
       
    90 local _server
       
    91 local _readlist
       
    92 local _timerlist
       
    93 local _sendlist
       
    94 local _socketlist
       
    95 local _closelist
       
    96 local _readtimes
       
    97 local _writetimes
       
    98 
       
    99 --// simple data types //--
       
   100 
       
   101 local _
       
   102 local _readlistlen
       
   103 local _sendlistlen
       
   104 local _timerlistlen
       
   105 
       
   106 local _sendtraffic
       
   107 local _readtraffic
       
   108 
       
   109 local _selecttimeout
       
   110 local _sleeptime
       
   111 
       
   112 local _starttime
       
   113 local _currenttime
       
   114 
       
   115 local _maxsendlen
       
   116 local _maxreadlen
       
   117 
       
   118 local _checkinterval
       
   119 local _sendtimeout
       
   120 local _readtimeout
       
   121 
       
   122 local _cleanqueue
       
   123 
       
   124 local _timer
       
   125 
       
   126 local _maxclientsperserver
       
   127 
       
   128 ----------------------------------// DEFINITION //--
       
   129 
       
   130 _server = { }    -- key = port, value = table; list of listening servers
       
   131 _readlist = { }    -- array with sockets to read from
       
   132 _sendlist = { }    -- arrary with sockets to write to
       
   133 _timerlist = { }    -- array of timer functions
       
   134 _socketlist = { }    -- key = socket, value = wrapped socket (handlers)
       
   135 _readtimes = { }   -- key = handler, value = timestamp of last data reading
       
   136 _writetimes = { }   -- key = handler, value = timestamp of last data writing/sending
       
   137 _closelist = { }    -- handlers to close
       
   138 
       
   139 _readlistlen = 0    -- length of readlist
       
   140 _sendlistlen = 0    -- length of sendlist
       
   141 _timerlistlen = 0    -- lenght of timerlist
       
   142 
       
   143 _sendtraffic = 0    -- some stats
       
   144 _readtraffic = 0
       
   145 
       
   146 _selecttimeout = 1    -- timeout of socket.select
       
   147 _sleeptime = 0    -- time to wait at the end of every loop
       
   148 
       
   149 _maxsendlen = 51000 * 1024    -- max len of send buffer
       
   150 _maxreadlen = 25000 * 1024    -- max len of read buffer
       
   151 
       
   152 _checkinterval = 1200000    -- interval in secs to check idle clients
       
   153 _sendtimeout = 60000    -- allowed send idle time in secs
       
   154 _readtimeout = 6 * 60 * 60    -- allowed read idle time in secs
       
   155 
       
   156 _cleanqueue = false    -- clean bufferqueue after using
       
   157 
       
   158 _maxclientsperserver = 1000
       
   159 
       
   160 _maxsslhandshake = 30 -- max handshake round-trips
       
   161 ----------------------------------// PRIVATE //--
       
   162 
       
   163 wrapserver = function( listeners, socket, ip, serverport, pattern, sslctx, maxconnections, startssl )    -- this function wraps a server
       
   164 
       
   165     maxconnections = maxconnections or _maxclientsperserver
       
   166 
       
   167     local connections = 0
       
   168 
       
   169     local dispatch, disconnect = listeners.incoming or listeners.listener, listeners.disconnect
       
   170 
       
   171     local err
       
   172 
       
   173     local ssl = false
       
   174 
       
   175     if sslctx then
       
   176         ssl = true
       
   177         if not ssl_newcontext then
       
   178             out_error "luasec not found"
       
   179             ssl = false
       
   180         end
       
   181         if type( sslctx ) ~= "table" then
       
   182             out_error "server.lua: wrong server sslctx"
       
   183             ssl = false
       
   184         end
       
   185         local ctx;
       
   186         ctx, err = ssl_newcontext( sslctx )
       
   187         if not ctx then
       
   188             err = err or "wrong sslctx parameters"
       
   189             local file;
       
   190             file = err:match("^error loading (.-) %(");
       
   191             if file then
       
   192             	if file == "private key" then
       
   193             		file = sslctx.key or "your private key";
       
   194             	elseif file == "certificate" then
       
   195             		file = sslctx.certificate or "your certificate file";
       
   196             	end
       
   197 	        local reason = err:match("%((.+)%)$") or "some reason";
       
   198 	        if reason == "Permission denied" then
       
   199 	        	reason = "Check that the permissions allow Prosody to read this file.";
       
   200 	        elseif reason == "No such file or directory" then
       
   201 	        	reason = "Check that the path is correct, and the file exists.";
       
   202 	        elseif reason == "system lib" then
       
   203 	        	reason = "Previous error (see logs), or other system error.";
       
   204 	        else
       
   205 	        	reason = "Reason: "..tostring(reason or "unknown"):lower();
       
   206 	        end
       
   207 	        log("error", "SSL/TLS: Failed to load %s: %s", file, reason);
       
   208 	    else
       
   209                 log("error", "SSL/TLS: Error initialising for port %d: %s", serverport, err );
       
   210             end
       
   211             ssl = false
       
   212         end
       
   213         sslctx = ctx;
       
   214     end
       
   215     if not ssl then
       
   216       sslctx = false;
       
   217       if startssl then
       
   218          log("error", "Failed to listen on port %d due to SSL/TLS to SSL/TLS initialisation errors (see logs)", serverport )
       
   219          return nil, "Cannot start ssl,  see log for details"
       
   220        end
       
   221     end
       
   222 
       
   223     local accept = socket.accept
       
   224 
       
   225     --// public methods of the object //--
       
   226 
       
   227     local handler = { }
       
   228 
       
   229     handler.shutdown = function( ) end
       
   230 
       
   231     handler.ssl = function( )
       
   232         return ssl
       
   233     end
       
   234     handler.sslctx = function( )
       
   235         return sslctx
       
   236     end
       
   237     handler.remove = function( )
       
   238         connections = connections - 1
       
   239     end
       
   240     handler.close = function( )
       
   241         for _, handler in pairs( _socketlist ) do
       
   242             if handler.serverport == serverport then
       
   243                 handler.disconnect( handler, "server closed" )
       
   244                 handler.close( true )
       
   245             end
       
   246         end
       
   247         socket:close( )
       
   248         _sendlistlen = removesocket( _sendlist, socket, _sendlistlen )
       
   249         _readlistlen = removesocket( _readlist, socket, _readlistlen )
       
   250         _socketlist[ socket ] = nil
       
   251         handler = nil
       
   252         socket = nil
       
   253         --mem_free( )
       
   254         out_put "server.lua: closed server handler and removed sockets from list"
       
   255     end
       
   256     handler.ip = function( )
       
   257         return ip
       
   258     end
       
   259     handler.serverport = function( )
       
   260         return serverport
       
   261     end
       
   262     handler.socket = function( )
       
   263         return socket
       
   264     end
       
   265     handler.readbuffer = function( )
       
   266         if connections > maxconnections then
       
   267             out_put( "server.lua: refused new client connection: server full" )
       
   268             return false
       
   269         end
       
   270         local client, err = accept( socket )    -- try to accept
       
   271         if client then
       
   272             local ip, clientport = client:getpeername( )
       
   273             client:settimeout( 0 )
       
   274             local handler, client, err = wrapconnection( handler, listeners, client, ip, serverport, clientport, pattern, sslctx, startssl )    -- wrap new client socket
       
   275             if err then    -- error while wrapping ssl socket
       
   276                 return false
       
   277             end
       
   278             connections = connections + 1
       
   279             out_put( "server.lua: accepted new client connection from ", tostring(ip), ":", tostring(clientport), " to ", tostring(serverport))
       
   280             return dispatch( handler )
       
   281         elseif err then    -- maybe timeout or something else
       
   282             out_put( "server.lua: error with new client connection: ", tostring(err) )
       
   283             return false
       
   284         end
       
   285     end
       
   286     return handler
       
   287 end
       
   288 
       
   289 wrapconnection = function( server, listeners, socket, ip, serverport, clientport, pattern, sslctx, startssl )    -- this function wraps a client to a handler object
       
   290 
       
   291     socket:settimeout( 0 )
       
   292 
       
   293     --// local import of socket methods //--
       
   294 
       
   295     local send
       
   296     local receive
       
   297     local shutdown
       
   298 
       
   299     --// private closures of the object //--
       
   300 
       
   301     local ssl
       
   302 
       
   303     local dispatch = listeners.incoming or listeners.listener
       
   304     local status = listeners.status
       
   305     local disconnect = listeners.disconnect
       
   306 
       
   307     local bufferqueue = { }    -- buffer array
       
   308     local bufferqueuelen = 0    -- end of buffer array
       
   309 
       
   310     local toclose
       
   311     local fatalerror
       
   312     local needtls
       
   313 
       
   314     local bufferlen = 0
       
   315 
       
   316     local noread = false
       
   317     local nosend = false
       
   318 
       
   319     local sendtraffic, readtraffic = 0, 0
       
   320 
       
   321     local maxsendlen = _maxsendlen
       
   322     local maxreadlen = _maxreadlen
       
   323 
       
   324     --// public methods of the object //--
       
   325 
       
   326     local handler = bufferqueue    -- saves a table ^_^
       
   327 
       
   328     handler.dispatch = function( )
       
   329         return dispatch
       
   330     end
       
   331     handler.disconnect = function( )
       
   332         return disconnect
       
   333     end
       
   334     handler.setlistener = function( listeners )
       
   335         dispatch = listeners.incoming
       
   336         disconnect = listeners.disconnect
       
   337     end
       
   338     handler.getstats = function( )
       
   339         return readtraffic, sendtraffic
       
   340     end
       
   341     handler.ssl = function( )
       
   342         return ssl
       
   343     end
       
   344     handler.sslctx = function ( )
       
   345         return sslctx
       
   346     end
       
   347     handler.send = function( _, data, i, j )
       
   348         return send( socket, data, i, j )
       
   349     end
       
   350     handler.receive = function( pattern, prefix )
       
   351         return receive( socket, pattern, prefix )
       
   352     end
       
   353     handler.shutdown = function( pattern )
       
   354         return shutdown( socket, pattern )
       
   355     end
       
   356     handler.close = function( forced )
       
   357         if not handler then return true; end
       
   358         _readlistlen = removesocket( _readlist, socket, _readlistlen )
       
   359         _readtimes[ handler ] = nil
       
   360         if bufferqueuelen ~= 0 then
       
   361             if not ( forced or fatalerror ) then
       
   362                 handler.sendbuffer( )
       
   363                 if bufferqueuelen ~= 0 then   -- try again...
       
   364                     if handler then
       
   365                         handler.write = nil    -- ... but no further writing allowed
       
   366                     end
       
   367                     toclose = true
       
   368                     return false
       
   369                 end
       
   370             else
       
   371                 send( socket, table_concat( bufferqueue, "", 1, bufferqueuelen ), 1, bufferlen )    -- forced send
       
   372             end
       
   373         end
       
   374         if socket then
       
   375           _ = shutdown and shutdown( socket )
       
   376           socket:close( )
       
   377           _sendlistlen = removesocket( _sendlist, socket, _sendlistlen )
       
   378           _socketlist[ socket ] = nil
       
   379           socket = nil
       
   380         else
       
   381           out_put "server.lua: socket already closed"
       
   382         end
       
   383         if handler then
       
   384             _writetimes[ handler ] = nil
       
   385             _closelist[ handler ] = nil
       
   386             handler = nil
       
   387         end
       
   388 	if server then
       
   389 		server.remove( )
       
   390 	end
       
   391         out_put "server.lua: closed client handler and removed socket from list"
       
   392         return true
       
   393     end
       
   394     handler.ip = function( )
       
   395         return ip
       
   396     end
       
   397     handler.serverport = function( )
       
   398         return serverport
       
   399     end
       
   400     handler.clientport = function( )
       
   401         return clientport
       
   402     end
       
   403     local write = function( data )
       
   404         bufferlen = bufferlen + string_len( data )
       
   405         if bufferlen > maxsendlen then
       
   406             _closelist[ handler ] = "send buffer exceeded"   -- cannot close the client at the moment, have to wait to the end of the cycle
       
   407             handler.write = idfalse    -- dont write anymore
       
   408             return false
       
   409         elseif socket and not _sendlist[ socket ] then
       
   410             _sendlistlen = addsocket(_sendlist, socket, _sendlistlen)
       
   411         end
       
   412         bufferqueuelen = bufferqueuelen + 1
       
   413         bufferqueue[ bufferqueuelen ] = data
       
   414         if handler then
       
   415         	_writetimes[ handler ] = _writetimes[ handler ] or _currenttime
       
   416         end
       
   417         return true
       
   418     end
       
   419     handler.write = write
       
   420     handler.bufferqueue = function( )
       
   421         return bufferqueue
       
   422     end
       
   423     handler.socket = function( )
       
   424         return socket
       
   425     end
       
   426     handler.pattern = function( new )
       
   427         pattern = new or pattern
       
   428         return pattern
       
   429     end
       
   430     handler.setsend = function ( newsend )
       
   431         send = newsend or send
       
   432         return send
       
   433     end
       
   434     handler.bufferlen = function( readlen, sendlen )
       
   435         maxsendlen = sendlen or maxsendlen
       
   436         maxreadlen = readlen or maxreadlen
       
   437         return maxreadlen, maxsendlen
       
   438     end
       
   439     handler.lock = function( switch )
       
   440         if switch == true then
       
   441             handler.write = idfalse
       
   442             local tmp = _sendlistlen
       
   443             _sendlistlen = removesocket( _sendlist, socket, _sendlistlen )
       
   444             _writetimes[ handler ] = nil
       
   445             if _sendlistlen ~= tmp then
       
   446                 nosend = true
       
   447             end
       
   448             tmp = _readlistlen
       
   449             _readlistlen = removesocket( _readlist, socket, _readlistlen )
       
   450             _readtimes[ handler ] = nil
       
   451             if _readlistlen ~= tmp then
       
   452                 noread = true
       
   453             end
       
   454         elseif switch == false then
       
   455             handler.write = write
       
   456             if noread then
       
   457                 noread = false
       
   458                 _readlistlen = addsocket(_readlist, socket, _readlistlen)
       
   459                 _readtimes[ handler ] = _currenttime
       
   460             end
       
   461             if nosend then
       
   462                 nosend = false
       
   463                 write( "" )
       
   464             end
       
   465         end
       
   466         return noread, nosend
       
   467     end
       
   468     local _readbuffer = function( )    -- this function reads data
       
   469         local buffer, err, part = receive( socket, pattern )    -- receive buffer with "pattern"
       
   470         if not err or ( err == "timeout" or err == "wantread" ) then    -- received something
       
   471             local buffer = buffer or part or ""
       
   472             local len = string_len( buffer )
       
   473             if len > maxreadlen then
       
   474                 disconnect( handler, "receive buffer exceeded" )
       
   475                 handler.close( true )
       
   476                 return false
       
   477             end
       
   478             local count = len * STAT_UNIT
       
   479             readtraffic = readtraffic + count
       
   480             _readtraffic = _readtraffic + count
       
   481             _readtimes[ handler ] = _currenttime
       
   482             --out_put( "server.lua: read data '", buffer:gsub("[^%w%p ]", "."), "', error: ", err )
       
   483             return dispatch( handler, buffer, err )
       
   484         else    -- connections was closed or fatal error
       
   485             out_put( "server.lua: client ", tostring(ip), ":", tostring(clientport), " read error: ", tostring(err) )
       
   486             fatalerror = true
       
   487             disconnect( handler, err )
       
   488 	    _ = handler and handler.close( )
       
   489             return false
       
   490         end
       
   491     end
       
   492     local _sendbuffer = function( )    -- this function sends data
       
   493     	local succ, err, byte, buffer, count;
       
   494     	local count;
       
   495     	if socket then
       
   496             buffer = table_concat( bufferqueue, "", 1, bufferqueuelen )
       
   497             succ, err, byte = send( socket, buffer, 1, bufferlen )
       
   498             count = ( succ or byte or 0 ) * STAT_UNIT
       
   499             sendtraffic = sendtraffic + count
       
   500             _sendtraffic = _sendtraffic + count
       
   501             _ = _cleanqueue and clean( bufferqueue )
       
   502             --out_put( "server.lua: sended '", buffer, "', bytes: ", tostring(succ), ", error: ", tostring(err), ", part: ", tostring(byte), ", to: ", tostring(ip), ":", tostring(clientport) )
       
   503         else
       
   504             succ, err, count = false, "closed", 0;
       
   505         end
       
   506         if succ then    -- sending succesful
       
   507             bufferqueuelen = 0
       
   508             bufferlen = 0
       
   509             _sendlistlen = removesocket( _sendlist, socket, _sendlistlen )    -- delete socket from writelist
       
   510             _ = needtls and handler.starttls(true)
       
   511             _writetimes[ handler ] = nil
       
   512 	    _ = toclose and handler.close( )
       
   513             return true
       
   514         elseif byte and ( err == "timeout" or err == "wantwrite" ) then    -- want write
       
   515             buffer = string_sub( buffer, byte + 1, bufferlen )    -- new buffer
       
   516             bufferqueue[ 1 ] = buffer    -- insert new buffer in queue
       
   517             bufferqueuelen = 1
       
   518             bufferlen = bufferlen - byte
       
   519             _writetimes[ handler ] = _currenttime
       
   520             return true
       
   521         else    -- connection was closed during sending or fatal error
       
   522             out_put( "server.lua: client ", tostring(ip), ":", tostring(clientport), " write error: ", tostring(err) )
       
   523             fatalerror = true
       
   524             disconnect( handler, err )
       
   525             _ = handler and handler.close( )
       
   526             return false
       
   527         end
       
   528     end
       
   529 
       
   530     -- Set the sslctx
       
   531     local handshake;
       
   532     function handler.set_sslctx(new_sslctx)
       
   533         ssl = true
       
   534         sslctx = new_sslctx;
       
   535         local wrote
       
   536         local read
       
   537         handshake = coroutine_wrap( function( client )    -- create handshake coroutine
       
   538                 local err
       
   539                 for i = 1, _maxsslhandshake do
       
   540                     _sendlistlen = ( wrote and removesocket( _sendlist, client, _sendlistlen ) ) or _sendlistlen
       
   541                     _readlistlen = ( read and removesocket( _readlist, client, _readlistlen ) ) or _readlistlen
       
   542                     read, wrote = nil, nil
       
   543                     _, err = client:dohandshake( )
       
   544                     if not err then
       
   545                         out_put( "server.lua: ssl handshake done" )
       
   546                         handler.readbuffer = _readbuffer    -- when handshake is done, replace the handshake function with regular functions
       
   547                         handler.sendbuffer = _sendbuffer
       
   548                         _ = status and status( handler, "ssl-handshake-complete" )
       
   549                         _readlistlen = addsocket(_readlist, client, _readlistlen)
       
   550                         return true
       
   551                     else
       
   552                        out_put( "server.lua: error during ssl handshake: ", tostring(err) )
       
   553                        if err == "wantwrite" and not wrote then
       
   554                            _sendlistlen = addsocket(_sendlist, client, _sendlistlen)
       
   555                            wrote = true
       
   556                        elseif err == "wantread" and not read then
       
   557                            _readlistlen = addsocket(_readlist, client, _readlistlen)
       
   558                            read = true
       
   559                        else
       
   560                            break;
       
   561                        end
       
   562                        --coroutine_yield( handler, nil, err )    -- handshake not finished
       
   563                        coroutine_yield( )
       
   564                     end
       
   565                 end
       
   566                 disconnect( handler, "ssl handshake failed" )
       
   567                 _ = handler and handler.close( true )    -- forced disconnect
       
   568                 return false    -- handshake failed
       
   569             end
       
   570         )
       
   571     end
       
   572     if sslctx then    -- ssl?
       
   573     	handler.set_sslctx(sslctx);
       
   574         if startssl then    -- ssl now?
       
   575             --out_put("server.lua: ", "starting ssl handshake")
       
   576 	    local err
       
   577             socket, err = ssl_wrap( socket, sslctx )    -- wrap socket
       
   578             if err then
       
   579                 out_put( "server.lua: ssl error: ", tostring(err) )
       
   580                 --mem_free( )
       
   581                 return nil, nil, err    -- fatal error
       
   582             end
       
   583             socket:settimeout( 0 )
       
   584             handler.readbuffer = handshake
       
   585             handler.sendbuffer = handshake
       
   586             handshake( socket ) -- do handshake
       
   587             if not socket then
       
   588                 return nil, nil, "ssl handshake failed";
       
   589             end
       
   590         else
       
   591             -- We're not automatically doing SSL, so we're not secure (yet)
       
   592             ssl = false
       
   593             handler.starttls = function( now )
       
   594                 if not now then
       
   595                     --out_put "server.lua: we need to do tls, but delaying until later"
       
   596                     needtls = true
       
   597                     return
       
   598                 end
       
   599                 --out_put( "server.lua: attempting to start tls on " .. tostring( socket ) )
       
   600                 local oldsocket, err = socket
       
   601                 socket, err = ssl_wrap( socket, sslctx )    -- wrap socket
       
   602                 --out_put( "server.lua: sslwrapped socket is " .. tostring( socket ) )
       
   603                 if err then
       
   604                     out_put( "server.lua: error while starting tls on client: ", tostring(err) )
       
   605                     return nil, err    -- fatal error
       
   606                 end
       
   607 
       
   608                 socket:settimeout( 0 )
       
   609 
       
   610                 -- add the new socket to our system
       
   611 
       
   612                 send = socket.send
       
   613                 receive = socket.receive
       
   614                 shutdown = id
       
   615 
       
   616                 _socketlist[ socket ] = handler
       
   617                 _readlistlen = addsocket(_readlist, socket, _readlistlen)
       
   618 
       
   619                 -- remove traces of the old socket
       
   620 
       
   621                 _readlistlen = removesocket( _readlist, oldsocket, _readlistlen )
       
   622                 _sendlistlen = removesocket( _sendlist, oldsocket, _sendlistlen )
       
   623                 _socketlist[ oldsocket ] = nil
       
   624 
       
   625                 handler.starttls = nil
       
   626                 needtls = nil
       
   627                 
       
   628                 -- Secure now
       
   629                 ssl = true
       
   630 
       
   631                 handler.readbuffer = handshake
       
   632                 handler.sendbuffer = handshake
       
   633                 handshake( socket )    -- do handshake
       
   634             end
       
   635             handler.readbuffer = _readbuffer
       
   636             handler.sendbuffer = _sendbuffer
       
   637         end
       
   638     else    -- normal connection
       
   639         ssl = false
       
   640         handler.readbuffer = _readbuffer
       
   641         handler.sendbuffer = _sendbuffer
       
   642     end
       
   643 
       
   644     send = socket.send
       
   645     receive = socket.receive
       
   646     shutdown = ( ssl and id ) or socket.shutdown
       
   647 
       
   648     _socketlist[ socket ] = handler
       
   649     _readlistlen = addsocket(_readlist, socket, _readlistlen)
       
   650 
       
   651     return handler, socket
       
   652 end
       
   653 
       
   654 id = function( )
       
   655 end
       
   656 
       
   657 idfalse = function( )
       
   658     return false
       
   659 end
       
   660 
       
   661 addsocket = function( list, socket, len )
       
   662     if not list[ socket ] then
       
   663       len = len + 1
       
   664       list[ len ] = socket
       
   665       list[ socket ] = len
       
   666     end
       
   667     return len;
       
   668 end
       
   669 
       
   670 removesocket = function( list, socket, len )    -- this function removes sockets from a list ( copied from copas )
       
   671     local pos = list[ socket ]
       
   672     if pos then
       
   673         list[ socket ] = nil
       
   674         local last = list[ len ]
       
   675         list[ len ] = nil
       
   676         if last ~= socket then
       
   677             list[ last ] = pos
       
   678             list[ pos ] = last
       
   679         end
       
   680         return len - 1
       
   681     end
       
   682     return len
       
   683 end
       
   684 
       
   685 closesocket = function( socket )
       
   686     _sendlistlen = removesocket( _sendlist, socket, _sendlistlen )
       
   687     _readlistlen = removesocket( _readlist, socket, _readlistlen )
       
   688     _socketlist[ socket ] = nil
       
   689     socket:close( )
       
   690     --mem_free( )
       
   691 end
       
   692 
       
   693 ----------------------------------// PUBLIC //--
       
   694 
       
   695 addserver = function( listeners, port, addr, pattern, sslctx, maxconnections, startssl )    -- this function provides a way for other scripts to reg a server
       
   696     local err
       
   697     --out_put("server.lua: autossl on ", port, " is ", startssl)
       
   698     if type( listeners ) ~= "table" then
       
   699         err = "invalid listener table"
       
   700     end
       
   701     if not type( port ) == "number" or not ( port >= 0 and port <= 65535 ) then
       
   702         err = "invalid port"
       
   703     elseif _server[ port ] then
       
   704         err =  "listeners on port '" .. port .. "' already exist"
       
   705     elseif sslctx and not luasec then
       
   706         err = "luasec not found"
       
   707     end
       
   708     if err then
       
   709         out_error( "server.lua, port ", port, ": ", err )
       
   710         return nil, err
       
   711     end
       
   712     addr = addr or "*"
       
   713     local server, err = socket_bind( addr, port )
       
   714     if err then
       
   715         out_error( "server.lua, port ", port, ": ", err )
       
   716         return nil, err
       
   717     end
       
   718     local handler, err = wrapserver( listeners, server, addr, port, pattern, sslctx, maxconnections, startssl )    -- wrap new server socket
       
   719     if not handler then
       
   720         server:close( )
       
   721         return nil, err
       
   722     end
       
   723     server:settimeout( 0 )
       
   724     _readlistlen = addsocket(_readlist, server, _readlistlen)
       
   725     _server[ port ] = handler
       
   726     _socketlist[ server ] = handler
       
   727     out_put( "server.lua: new server listener on '", addr, ":", port, "'" )
       
   728     return handler
       
   729 end
       
   730 
       
   731 getserver = function ( port )
       
   732 	return _server[ port ];
       
   733 end
       
   734 
       
   735 removeserver = function( port )
       
   736     local handler = _server[ port ]
       
   737     if not handler then
       
   738         return nil, "no server found on port '" .. tostring( port ) .. "'"
       
   739     end
       
   740     handler.close( )
       
   741     _server[ port ] = nil
       
   742     return true
       
   743 end
       
   744 
       
   745 closeall = function( )
       
   746     for _, handler in pairs( _socketlist ) do
       
   747         handler.close( )
       
   748         _socketlist[ _ ] = nil
       
   749     end
       
   750     _readlistlen = 0
       
   751     _sendlistlen = 0
       
   752     _timerlistlen = 0
       
   753     _server = { }
       
   754     _readlist = { }
       
   755     _sendlist = { }
       
   756     _timerlist = { }
       
   757     _socketlist = { }
       
   758     --mem_free( )
       
   759 end
       
   760 
       
   761 getsettings = function( )
       
   762     return  _selecttimeout, _sleeptime, _maxsendlen, _maxreadlen, _checkinterval, _sendtimeout, _readtimeout, _cleanqueue, _maxclientsperserver, _maxsslhandshake
       
   763 end
       
   764 
       
   765 changesettings = function( new )
       
   766     if type( new ) ~= "table" then
       
   767         return nil, "invalid settings table"
       
   768     end
       
   769     _selecttimeout = tonumber( new.timeout ) or _selecttimeout
       
   770     _sleeptime = tonumber( new.sleeptime ) or _sleeptime
       
   771     _maxsendlen = tonumber( new.maxsendlen ) or _maxsendlen
       
   772     _maxreadlen = tonumber( new.maxreadlen ) or _maxreadlen
       
   773     _checkinterval = tonumber( new.checkinterval ) or _checkinterval
       
   774     _sendtimeout = tonumber( new.sendtimeout ) or _sendtimeout
       
   775     _readtimeout = tonumber( new.readtimeout ) or _readtimeout
       
   776     _cleanqueue = new.cleanqueue
       
   777     _maxclientsperserver = new._maxclientsperserver or _maxclientsperserver
       
   778     _maxsslhandshake = new._maxsslhandshake or _maxsslhandshake
       
   779     return true
       
   780 end
       
   781 
       
   782 addtimer = function( listener )
       
   783     if type( listener ) ~= "function" then
       
   784         return nil, "invalid listener function"
       
   785     end
       
   786     _timerlistlen = _timerlistlen + 1
       
   787     _timerlist[ _timerlistlen ] = listener
       
   788     return true
       
   789 end
       
   790 
       
   791 stats = function( )
       
   792     return _readtraffic, _sendtraffic, _readlistlen, _sendlistlen, _timerlistlen
       
   793 end
       
   794 
       
   795 local dontstop = true; -- thinking about tomorrow, ...
       
   796 
       
   797 setquitting = function (quit)
       
   798 	dontstop = not quit;
       
   799 	return;
       
   800 end
       
   801 
       
   802 loop = function( )    -- this is the main loop of the program
       
   803     while dontstop do
       
   804         local read, write, err = socket_select( _readlist, _sendlist, _selecttimeout )
       
   805         for i, socket in ipairs( write ) do    -- send data waiting in writequeues
       
   806             local handler = _socketlist[ socket ]
       
   807             if handler then
       
   808                 handler.sendbuffer( )
       
   809             else
       
   810                 closesocket( socket )
       
   811                 out_put "server.lua: found no handler and closed socket (writelist)"    -- this should not happen
       
   812             end
       
   813         end
       
   814         for i, socket in ipairs( read ) do    -- receive data
       
   815             local handler = _socketlist[ socket ]
       
   816             if handler then
       
   817                 handler.readbuffer( )
       
   818             else
       
   819                 closesocket( socket )
       
   820                 out_put "server.lua: found no handler and closed socket (readlist)"    -- this can happen
       
   821             end
       
   822         end
       
   823         for handler, err in pairs( _closelist ) do
       
   824             handler.disconnect( )( handler, err )
       
   825             handler.close( true )    -- forced disconnect
       
   826         end
       
   827         clean( _closelist )
       
   828         _currenttime = os_time( )
       
   829         if os_difftime( _currenttime - _timer ) >= 1 then
       
   830             for i = 1, _timerlistlen do
       
   831                 _timerlist[ i ]( _currenttime )    -- fire timers
       
   832             end
       
   833             _timer = _currenttime
       
   834         end
       
   835         socket_sleep( _sleeptime )    -- wait some time
       
   836         --collectgarbage( )
       
   837     end
       
   838     return "quitting"
       
   839 end
       
   840 
       
   841 --// EXPERIMENTAL //--
       
   842 
       
   843 local wrapclient = function( socket, ip, serverport, listeners, pattern, sslctx, startssl )
       
   844     local handler = wrapconnection( nil, listeners, socket, ip, serverport, "clientport", pattern, sslctx, startssl )
       
   845     _socketlist[ socket ] = handler
       
   846     _sendlistlen = addsocket(_sendlist, socket, _sendlistlen)
       
   847     return handler, socket
       
   848 end
       
   849 
       
   850 local addclient = function( address, port, listeners, pattern, sslctx, startssl )
       
   851     local client, err = luasocket.tcp( )
       
   852     if err then
       
   853         return nil, err
       
   854     end
       
   855     client:settimeout( 0 )
       
   856     _, err = client:connect( address, port )
       
   857     if err then    -- try again
       
   858         local handler = wrapclient( client, address, port, listeners )
       
   859     else
       
   860         wrapconnection( nil, listeners, client, address, port, "clientport", pattern, sslctx, startssl )
       
   861     end
       
   862 end
       
   863 
       
   864 --// EXPERIMENTAL //--
       
   865 
       
   866 ----------------------------------// BEGIN //--
       
   867 
       
   868 use "setmetatable" ( _socketlist, { __mode = "k" } )
       
   869 use "setmetatable" ( _readtimes, { __mode = "k" } )
       
   870 use "setmetatable" ( _writetimes, { __mode = "k" } )
       
   871 
       
   872 _timer = os_time( )
       
   873 _starttime = os_time( )
       
   874 
       
   875 addtimer( function( )
       
   876         local difftime = os_difftime( _currenttime - _starttime )
       
   877         if difftime > _checkinterval then
       
   878             _starttime = _currenttime
       
   879             for handler, timestamp in pairs( _writetimes ) do
       
   880                 if os_difftime( _currenttime - timestamp ) > _sendtimeout then
       
   881                     --_writetimes[ handler ] = nil
       
   882                     handler.disconnect( )( handler, "send timeout" )
       
   883                     handler.close( true )    -- forced disconnect
       
   884                 end
       
   885             end
       
   886             for handler, timestamp in pairs( _readtimes ) do
       
   887                 if os_difftime( _currenttime - timestamp ) > _readtimeout then
       
   888                     --_readtimes[ handler ] = nil
       
   889                     handler.disconnect( )( handler, "read timeout" )
       
   890                     handler.close( )    -- forced disconnect?
       
   891                 end
       
   892             end
       
   893         end
       
   894     end
       
   895 )
       
   896 
       
   897 ----------------------------------// PUBLIC INTERFACE //--
       
   898 
       
   899 return {
       
   900 
       
   901     addclient = addclient,
       
   902     wrapclient = wrapclient,
       
   903     
       
   904     loop = loop,
       
   905     stats = stats,
       
   906     closeall = closeall,
       
   907     addtimer = addtimer,
       
   908     addserver = addserver,
       
   909     getserver = getserver,
       
   910     getsettings = getsettings,
       
   911     setquitting = setquitting,
       
   912     removeserver = removeserver,
       
   913     changesettings = changesettings,
       
   914 }