mod_saslauth: Add sasl_backend config parameter
[prosody.git] / net / server_select.lua
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.onincoming, listeners.ondisconnect
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.onincoming
304     local status = listeners.status
305     local disconnect = listeners.ondisconnect
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( self, listeners )
335         dispatch = listeners.onincoming
336         disconnect = listeners.ondisconnect
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( self, 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( self, 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( self )
421         return bufferqueue
422     end
423     handler.socket = function( self )
424         return socket
425     end
426     handler.pattern = function( self, new )
427         pattern = new or pattern
428         return pattern
429     end
430     handler.set_send = function ( self, newsend )
431         send = newsend or send
432         return send
433     end
434     handler.bufferlen = function( self, readlen, sendlen )
435         maxsendlen = sendlen or maxsendlen
436         maxreadlen = readlen or maxreadlen
437         return bufferlen, maxreadlen, maxsendlen
438     end
439     handler.lock_read  = function (self, switch)
440         if switch == true then
441             local tmp = _readlistlen
442             _readlistlen = removesocket( _readlist, socket, _readlistlen )
443             _readtimes[ handler ] = nil
444             if _readlistlen ~= tmp then
445                 noread = true
446             end
447         elseif switch == false then
448             if noread then
449                 noread = false
450                 _readlistlen = addsocket(_readlist, socket, _readlistlen)
451                 _readtimes[ handler ] = _currenttime
452             end
453         end
454         return noread
455     end
456     handler.lock = function( self, switch )
457         handler.lock_read (switch)
458         if switch == true then
459             handler.write = idfalse
460             local tmp = _sendlistlen
461             _sendlistlen = removesocket( _sendlist, socket, _sendlistlen )
462             _writetimes[ handler ] = nil
463             if _sendlistlen ~= tmp then
464                 nosend = true
465             end
466         elseif switch == false then
467             handler.write = write
468             if nosend then
469                 nosend = false
470                 write( "" )
471             end
472         end
473         return noread, nosend
474     end
475     local _readbuffer = function( )    -- this function reads data
476         local buffer, err, part = receive( socket, pattern )    -- receive buffer with "pattern"
477         if not err or (err == "wantread" or err == "timeout") or string_len(part) > 0 then    -- received something
478             local buffer = buffer or part or ""
479             local len = string_len( buffer )
480             if len > maxreadlen then
481                 disconnect( handler, "receive buffer exceeded" )
482                 handler.close( true )
483                 return false
484             end
485             local count = len * STAT_UNIT
486             readtraffic = readtraffic + count
487             _readtraffic = _readtraffic + count
488             _readtimes[ handler ] = _currenttime
489             --out_put( "server.lua: read data '", buffer:gsub("[^%w%p ]", "."), "', error: ", err )
490             return dispatch( handler, buffer, err )
491         else    -- connections was closed or fatal error
492             out_put( "server.lua: client ", tostring(ip), ":", tostring(clientport), " read error: ", tostring(err) )
493             fatalerror = true
494             disconnect( handler, err )
495             _ = handler and handler.close( )
496             return false
497         end
498     end
499     local _sendbuffer = function( )    -- this function sends data
500         local succ, err, byte, buffer, count;
501         local count;
502         if socket then
503             buffer = table_concat( bufferqueue, "", 1, bufferqueuelen )
504             succ, err, byte = send( socket, buffer, 1, bufferlen )
505             count = ( succ or byte or 0 ) * STAT_UNIT
506             sendtraffic = sendtraffic + count
507             _sendtraffic = _sendtraffic + count
508             _ = _cleanqueue and clean( bufferqueue )
509             --out_put( "server.lua: sended '", buffer, "', bytes: ", tostring(succ), ", error: ", tostring(err), ", part: ", tostring(byte), ", to: ", tostring(ip), ":", tostring(clientport) )
510         else
511             succ, err, count = false, "closed", 0;
512         end
513         if succ then    -- sending succesful
514             bufferqueuelen = 0
515             bufferlen = 0
516             _sendlistlen = removesocket( _sendlist, socket, _sendlistlen )    -- delete socket from writelist
517             _ = needtls and handler:starttls(true)
518             _writetimes[ handler ] = nil
519             _ = toclose and handler.close( )
520             return true
521         elseif byte and ( err == "timeout" or err == "wantwrite" ) then    -- want write
522             buffer = string_sub( buffer, byte + 1, bufferlen )    -- new buffer
523             bufferqueue[ 1 ] = buffer    -- insert new buffer in queue
524             bufferqueuelen = 1
525             bufferlen = bufferlen - byte
526             _writetimes[ handler ] = _currenttime
527             return true
528         else    -- connection was closed during sending or fatal error
529             out_put( "server.lua: client ", tostring(ip), ":", tostring(clientport), " write error: ", tostring(err) )
530             fatalerror = true
531             disconnect( handler, err )
532             _ = handler and handler.close( )
533             return false
534         end
535     end
536
537     -- Set the sslctx
538     local handshake;
539     function handler.set_sslctx(self, new_sslctx)
540         ssl = true
541         sslctx = new_sslctx;
542         local wrote
543         local read
544         handshake = coroutine_wrap( function( client )    -- create handshake coroutine
545                 local err
546                 for i = 1, _maxsslhandshake do
547                     _sendlistlen = ( wrote and removesocket( _sendlist, client, _sendlistlen ) ) or _sendlistlen
548                     _readlistlen = ( read and removesocket( _readlist, client, _readlistlen ) ) or _readlistlen
549                     read, wrote = nil, nil
550                     _, err = client:dohandshake( )
551                     if not err then
552                         out_put( "server.lua: ssl handshake done" )
553                         handler.readbuffer = _readbuffer    -- when handshake is done, replace the handshake function with regular functions
554                         handler.sendbuffer = _sendbuffer
555                         _ = status and status( handler, "ssl-handshake-complete" )
556                         _readlistlen = addsocket(_readlist, client, _readlistlen)
557                         return true
558                     else
559                        out_put( "server.lua: error during ssl handshake: ", tostring(err) )
560                        if err == "wantwrite" and not wrote then
561                            _sendlistlen = addsocket(_sendlist, client, _sendlistlen)
562                            wrote = true
563                        elseif err == "wantread" and not read then
564                            _readlistlen = addsocket(_readlist, client, _readlistlen)
565                            read = true
566                        else
567                            break;
568                        end
569                        --coroutine_yield( handler, nil, err )    -- handshake not finished
570                        coroutine_yield( )
571                     end
572                 end
573                 disconnect( handler, "ssl handshake failed" )
574                 _ = handler and handler:close( true )    -- forced disconnect
575                 return false    -- handshake failed
576             end
577         )
578     end
579     if sslctx then    -- ssl?
580         handler:set_sslctx(sslctx);
581         if startssl then    -- ssl now?
582             --out_put("server.lua: ", "starting ssl handshake")
583             local err
584             socket, err = ssl_wrap( socket, sslctx )    -- wrap socket
585             if err then
586                 out_put( "server.lua: ssl error: ", tostring(err) )
587                 --mem_free( )
588                 return nil, nil, err    -- fatal error
589             end
590             socket:settimeout( 0 )
591             handler.readbuffer = handshake
592             handler.sendbuffer = handshake
593             handshake( socket ) -- do handshake
594             if not socket then
595                 return nil, nil, "ssl handshake failed";
596             end
597         else
598             -- We're not automatically doing SSL, so we're not secure (yet)
599             ssl = false
600             handler.starttls = function( self, now )
601                 if not now then
602                     --out_put "server.lua: we need to do tls, but delaying until later"
603                     needtls = true
604                     return
605                 end
606                 --out_put( "server.lua: attempting to start tls on " .. tostring( socket ) )
607                 local oldsocket, err = socket
608                 socket, err = ssl_wrap( socket, sslctx )    -- wrap socket
609                 --out_put( "server.lua: sslwrapped socket is " .. tostring( socket ) )
610                 if err then
611                     out_put( "server.lua: error while starting tls on client: ", tostring(err) )
612                     return nil, err    -- fatal error
613                 end
614
615                 socket:settimeout( 0 )
616
617                 -- add the new socket to our system
618
619                 send = socket.send
620                 receive = socket.receive
621                 shutdown = id
622
623                 _socketlist[ socket ] = handler
624                 _readlistlen = addsocket(_readlist, socket, _readlistlen)
625
626                 -- remove traces of the old socket
627
628                 _readlistlen = removesocket( _readlist, oldsocket, _readlistlen )
629                 _sendlistlen = removesocket( _sendlist, oldsocket, _sendlistlen )
630                 _socketlist[ oldsocket ] = nil
631
632                 handler.starttls = nil
633                 needtls = nil
634                 
635                 -- Secure now
636                 ssl = true
637
638                 handler.readbuffer = handshake
639                 handler.sendbuffer = handshake
640                 handshake( socket )    -- do handshake
641             end
642             handler.readbuffer = _readbuffer
643             handler.sendbuffer = _sendbuffer
644         end
645     else    -- normal connection
646         ssl = false
647         handler.readbuffer = _readbuffer
648         handler.sendbuffer = _sendbuffer
649     end
650
651     send = socket.send
652     receive = socket.receive
653     shutdown = ( ssl and id ) or socket.shutdown
654
655     _socketlist[ socket ] = handler
656     _readlistlen = addsocket(_readlist, socket, _readlistlen)
657
658     return handler, socket
659 end
660
661 id = function( )
662 end
663
664 idfalse = function( )
665     return false
666 end
667
668 addsocket = function( list, socket, len )
669     if not list[ socket ] then
670       len = len + 1
671       list[ len ] = socket
672       list[ socket ] = len
673     end
674     return len;
675 end
676
677 removesocket = function( list, socket, len )    -- this function removes sockets from a list ( copied from copas )
678     local pos = list[ socket ]
679     if pos then
680         list[ socket ] = nil
681         local last = list[ len ]
682         list[ len ] = nil
683         if last ~= socket then
684             list[ last ] = pos
685             list[ pos ] = last
686         end
687         return len - 1
688     end
689     return len
690 end
691
692 closesocket = function( socket )
693     _sendlistlen = removesocket( _sendlist, socket, _sendlistlen )
694     _readlistlen = removesocket( _readlist, socket, _readlistlen )
695     _socketlist[ socket ] = nil
696     socket:close( )
697     --mem_free( )
698 end
699
700 ----------------------------------// PUBLIC //--
701
702 addserver = function( addr, port, listeners, pattern, sslctx, startssl )    -- this function provides a way for other scripts to reg a server
703     local err
704     --out_put("server.lua: autossl on ", port, " is ", startssl)
705     if type( listeners ) ~= "table" then
706         err = "invalid listener table"
707     end
708     if not type( port ) == "number" or not ( port >= 0 and port <= 65535 ) then
709         err = "invalid port"
710     elseif _server[ port ] then
711         err =  "listeners on port '" .. port .. "' already exist"
712     elseif sslctx and not luasec then
713         err = "luasec not found"
714     end
715     if err then
716         out_error( "server.lua, port ", port, ": ", err )
717         return nil, err
718     end
719     addr = addr or "*"
720     local server, err = socket_bind( addr, port )
721     if err then
722         out_error( "server.lua, port ", port, ": ", err )
723         return nil, err
724     end
725     local handler, err = wrapserver( listeners, server, addr, port, pattern, sslctx, _maxclientsperserver, startssl )    -- wrap new server socket
726     if not handler then
727         server:close( )
728         return nil, err
729     end
730     server:settimeout( 0 )
731     _readlistlen = addsocket(_readlist, server, _readlistlen)
732     _server[ port ] = handler
733     _socketlist[ server ] = handler
734     out_put( "server.lua: new server listener on '", addr, ":", port, "'" )
735     return handler
736 end
737
738 getserver = function ( port )
739         return _server[ port ];
740 end
741
742 removeserver = function( port )
743     local handler = _server[ port ]
744     if not handler then
745         return nil, "no server found on port '" .. tostring( port ) .. "'"
746     end
747     handler:close( )
748     _server[ port ] = nil
749     return true
750 end
751
752 closeall = function( )
753     for _, handler in pairs( _socketlist ) do
754         handler:close( )
755         _socketlist[ _ ] = nil
756     end
757     _readlistlen = 0
758     _sendlistlen = 0
759     _timerlistlen = 0
760     _server = { }
761     _readlist = { }
762     _sendlist = { }
763     _timerlist = { }
764     _socketlist = { }
765     --mem_free( )
766 end
767
768 getsettings = function( )
769     return  _selecttimeout, _sleeptime, _maxsendlen, _maxreadlen, _checkinterval, _sendtimeout, _readtimeout, _cleanqueue, _maxclientsperserver, _maxsslhandshake
770 end
771
772 changesettings = function( new )
773     if type( new ) ~= "table" then
774         return nil, "invalid settings table"
775     end
776     _selecttimeout = tonumber( new.timeout ) or _selecttimeout
777     _sleeptime = tonumber( new.sleeptime ) or _sleeptime
778     _maxsendlen = tonumber( new.maxsendlen ) or _maxsendlen
779     _maxreadlen = tonumber( new.maxreadlen ) or _maxreadlen
780     _checkinterval = tonumber( new.checkinterval ) or _checkinterval
781     _sendtimeout = tonumber( new.sendtimeout ) or _sendtimeout
782     _readtimeout = tonumber( new.readtimeout ) or _readtimeout
783     _cleanqueue = new.cleanqueue
784     _maxclientsperserver = new._maxclientsperserver or _maxclientsperserver
785     _maxsslhandshake = new._maxsslhandshake or _maxsslhandshake
786     return true
787 end
788
789 addtimer = function( listener )
790     if type( listener ) ~= "function" then
791         return nil, "invalid listener function"
792     end
793     _timerlistlen = _timerlistlen + 1
794     _timerlist[ _timerlistlen ] = listener
795     return true
796 end
797
798 stats = function( )
799     return _readtraffic, _sendtraffic, _readlistlen, _sendlistlen, _timerlistlen
800 end
801
802 local dontstop = true; -- thinking about tomorrow, ...
803
804 setquitting = function (quit)
805         dontstop = not quit;
806         return;
807 end
808
809 loop = function( )    -- this is the main loop of the program
810     while dontstop do
811         local read, write, err = socket_select( _readlist, _sendlist, _selecttimeout )
812         for i, socket in ipairs( write ) do    -- send data waiting in writequeues
813             local handler = _socketlist[ socket ]
814             if handler then
815                 handler.sendbuffer( )
816             else
817                 closesocket( socket )
818                 out_put "server.lua: found no handler and closed socket (writelist)"    -- this should not happen
819             end
820         end
821         for i, socket in ipairs( read ) do    -- receive data
822             local handler = _socketlist[ socket ]
823             if handler then
824                 handler.readbuffer( )
825             else
826                 closesocket( socket )
827                 out_put "server.lua: found no handler and closed socket (readlist)"    -- this can happen
828             end
829         end
830         for handler, err in pairs( _closelist ) do
831             handler.disconnect( )( handler, err )
832             handler:close( true )    -- forced disconnect
833         end
834         clean( _closelist )
835         _currenttime = os_time( )
836         if os_difftime( _currenttime - _timer ) >= 1 then
837             for i = 1, _timerlistlen do
838                 _timerlist[ i ]( _currenttime )    -- fire timers
839             end
840             _timer = _currenttime
841         end
842         socket_sleep( _sleeptime )    -- wait some time
843         --collectgarbage( )
844     end
845     return "quitting"
846 end
847
848 local function get_backend()
849         return "select";
850 end
851
852 --// EXPERIMENTAL //--
853
854 local wrapclient = function( socket, ip, serverport, listeners, pattern, sslctx, startssl )
855     local handler = wrapconnection( nil, listeners, socket, ip, serverport, "clientport", pattern, sslctx, startssl )
856     _socketlist[ socket ] = handler
857     _sendlistlen = addsocket(_sendlist, socket, _sendlistlen)
858     return handler, socket
859 end
860
861 local addclient = function( address, port, listeners, pattern, sslctx, startssl )
862     local client, err = luasocket.tcp( )
863     if err then
864         return nil, err
865     end
866     client:settimeout( 0 )
867     _, err = client:connect( address, port )
868     if err then    -- try again
869         local handler = wrapclient( client, address, port, listeners )
870     else
871         wrapconnection( nil, listeners, client, address, port, "clientport", pattern, sslctx, startssl )
872     end
873 end
874
875 --// EXPERIMENTAL //--
876
877 ----------------------------------// BEGIN //--
878
879 use "setmetatable" ( _socketlist, { __mode = "k" } )
880 use "setmetatable" ( _readtimes, { __mode = "k" } )
881 use "setmetatable" ( _writetimes, { __mode = "k" } )
882
883 _timer = os_time( )
884 _starttime = os_time( )
885
886 addtimer( function( )
887         local difftime = os_difftime( _currenttime - _starttime )
888         if difftime > _checkinterval then
889             _starttime = _currenttime
890             for handler, timestamp in pairs( _writetimes ) do
891                 if os_difftime( _currenttime - timestamp ) > _sendtimeout then
892                     --_writetimes[ handler ] = nil
893                     handler.disconnect( )( handler, "send timeout" )
894                     handler:close( true )    -- forced disconnect
895                 end
896             end
897             for handler, timestamp in pairs( _readtimes ) do
898                 if os_difftime( _currenttime - timestamp ) > _readtimeout then
899                     --_readtimes[ handler ] = nil
900                     handler.disconnect( )( handler, "read timeout" )
901                     handler:close( )    -- forced disconnect?
902                 end
903             end
904         end
905     end
906 )
907
908 ----------------------------------// PUBLIC INTERFACE //--
909
910 return {
911
912     addclient = addclient,
913     wrapclient = wrapclient,
914     
915     loop = loop,
916     stats = stats,
917     closeall = closeall,
918     addtimer = addtimer,
919     addserver = addserver,
920     getserver = getserver,
921     getsettings = getsettings,
922     setquitting = setquitting,
923     removeserver = removeserver,
924     get_backend = get_backend,
925     changesettings = changesettings,
926 }