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