net.server_select: Remove some debugging code.
[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-2010 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 = use "ssl"
59 local luasocket = use "socket" or 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
162 ----------------------------------// PRIVATE //--
163
164 wrapserver = function( listeners, socket, ip, serverport, pattern, sslctx, maxconnections ) -- this function wraps a server
165
166         maxconnections = maxconnections or _maxclientsperserver
167
168         local connections = 0
169
170         local dispatch, disconnect = listeners.onincoming, listeners.ondisconnect
171
172         local accept = socket.accept
173
174         --// public methods of the object //--
175
176         local handler = { }
177
178         handler.shutdown = function( ) end
179
180         handler.ssl = function( )
181                 return sslctx ~= nil
182         end
183         handler.sslctx = function( )
184                 return sslctx
185         end
186         handler.remove = function( )
187                 connections = connections - 1
188         end
189         handler.close = function( )
190                 for _, handler in pairs( _socketlist ) do
191                         if handler.serverport == serverport then
192                                 handler.disconnect( handler, "server closed" )
193                                 handler:close( true )
194                         end
195                 end
196                 socket:close( )
197                 _sendlistlen = removesocket( _sendlist, socket, _sendlistlen )
198                 _readlistlen = removesocket( _readlist, socket, _readlistlen )
199                 _socketlist[ socket ] = nil
200                 handler = nil
201                 socket = nil
202                 --mem_free( )
203                 out_put "server.lua: closed server handler and removed sockets from list"
204         end
205         handler.ip = function( )
206                 return ip
207         end
208         handler.serverport = function( )
209                 return serverport
210         end
211         handler.socket = function( )
212                 return socket
213         end
214         handler.readbuffer = function( )
215                 if connections > maxconnections then
216                         out_put( "server.lua: refused new client connection: server full" )
217                         return false
218                 end
219                 local client, err = accept( socket )    -- try to accept
220                 if client then
221                         local ip, clientport = client:getpeername( )
222                         client:settimeout( 0 )
223                         local handler, client, err = wrapconnection( handler, listeners, client, ip, serverport, clientport, pattern, sslctx ) -- wrap new client socket
224                         if err then -- error while wrapping ssl socket
225                                 return false
226                         end
227                         connections = connections + 1
228                         out_put( "server.lua: accepted new client connection from ", tostring(ip), ":", tostring(clientport), " to ", tostring(serverport))
229                         return dispatch( handler )
230                 elseif err then -- maybe timeout or something else
231                         out_put( "server.lua: error with new client connection: ", tostring(err) )
232                         return false
233                 end
234         end
235         return handler
236 end
237
238 wrapconnection = function( server, listeners, socket, ip, serverport, clientport, pattern, sslctx ) -- this function wraps a client to a handler object
239
240         socket:settimeout( 0 )
241
242         --// local import of socket methods //--
243
244         local send
245         local receive
246         local shutdown
247
248         --// private closures of the object //--
249
250         local ssl
251
252         local dispatch = listeners.onincoming
253         local status = listeners.onstatus
254         local disconnect = listeners.ondisconnect
255         local drain = listeners.ondrain
256
257         local bufferqueue = { } -- buffer array
258         local bufferqueuelen = 0        -- end of buffer array
259
260         local toclose
261         local fatalerror
262         local needtls
263
264         local bufferlen = 0
265
266         local noread = false
267         local nosend = false
268
269         local sendtraffic, readtraffic = 0, 0
270
271         local maxsendlen = _maxsendlen
272         local maxreadlen = _maxreadlen
273
274         --// public methods of the object //--
275
276         local handler = bufferqueue -- saves a table ^_^
277
278         handler.dispatch = function( )
279                 return dispatch
280         end
281         handler.disconnect = function( )
282                 return disconnect
283         end
284         handler.setlistener = function( self, listeners )
285                 dispatch = listeners.onincoming
286                 disconnect = listeners.ondisconnect
287                 status = listeners.onstatus
288                 drain = listeners.ondrain
289         end
290         handler.getstats = function( )
291                 return readtraffic, sendtraffic
292         end
293         handler.ssl = function( )
294                 return ssl
295         end
296         handler.sslctx = function ( )
297                 return sslctx
298         end
299         handler.send = function( _, data, i, j )
300                 return send( socket, data, i, j )
301         end
302         handler.receive = function( pattern, prefix )
303                 return receive( socket, pattern, prefix )
304         end
305         handler.shutdown = function( pattern )
306                 return shutdown( socket, pattern )
307         end
308         handler.setoption = function (self, option, value)
309                 if socket.setoption then
310                         return socket:setoption(option, value);
311                 end
312                 return false, "setoption not implemented";
313         end
314         handler.close = function( self, forced )
315                 if not handler then return true; end
316                 _readlistlen = removesocket( _readlist, socket, _readlistlen )
317                 _readtimes[ handler ] = nil
318                 if bufferqueuelen ~= 0 then
319                         if not ( forced or fatalerror ) then
320                                 handler.sendbuffer( )
321                                 if bufferqueuelen ~= 0 then -- try again...
322                                         if handler then
323                                                 handler.write = nil -- ... but no further writing allowed
324                                         end
325                                         toclose = true
326                                         return false
327                                 end
328                         else
329                                 send( socket, table_concat( bufferqueue, "", 1, bufferqueuelen ), 1, bufferlen )        -- forced send
330                         end
331                 end
332                 if socket then
333                         _ = shutdown and shutdown( socket )
334                         socket:close( )
335                         _sendlistlen = removesocket( _sendlist, socket, _sendlistlen )
336                         _socketlist[ socket ] = nil
337                         socket = nil
338                 else
339                         out_put "server.lua: socket already closed"
340                 end
341                 if handler then
342                         _writetimes[ handler ] = nil
343                         _closelist[ handler ] = nil
344                         handler = nil
345                 end
346         if server then
347                 server.remove( )
348         end
349                 out_put "server.lua: closed client handler and removed socket from list"
350                 return true
351         end
352         handler.ip = function( )
353                 return ip
354         end
355         handler.serverport = function( )
356                 return serverport
357         end
358         handler.clientport = function( )
359                 return clientport
360         end
361         local write = function( self, data )
362                 bufferlen = bufferlen + string_len( data )
363                 if bufferlen > maxsendlen then
364                         _closelist[ handler ] = "send buffer exceeded"   -- cannot close the client at the moment, have to wait to the end of the cycle
365                         handler.write = idfalse -- dont write anymore
366                         return false
367                 elseif socket and not _sendlist[ socket ] then
368                         _sendlistlen = addsocket(_sendlist, socket, _sendlistlen)
369                 end
370                 bufferqueuelen = bufferqueuelen + 1
371                 bufferqueue[ bufferqueuelen ] = data
372                 if handler then
373                         _writetimes[ handler ] = _writetimes[ handler ] or _currenttime
374                 end
375                 return true
376         end
377         handler.write = write
378         handler.bufferqueue = function( self )
379                 return bufferqueue
380         end
381         handler.socket = function( self )
382                 return socket
383         end
384         handler.set_mode = function( self, new )
385                 pattern = new or pattern
386                 return pattern
387         end
388         handler.set_send = function ( self, newsend )
389                 send = newsend or send
390                 return send
391         end
392         handler.bufferlen = function( self, readlen, sendlen )
393                 maxsendlen = sendlen or maxsendlen
394                 maxreadlen = readlen or maxreadlen
395                 return bufferlen, maxreadlen, maxsendlen
396         end
397         --TODO: Deprecate
398         handler.lock_read = function (self, switch)
399                 if switch == true then
400                         local tmp = _readlistlen
401                         _readlistlen = removesocket( _readlist, socket, _readlistlen )
402                         _readtimes[ handler ] = nil
403                         if _readlistlen ~= tmp then
404                                 noread = true
405                         end
406                 elseif switch == false then
407                         if noread then
408                                 noread = false
409                                 _readlistlen = addsocket(_readlist, socket, _readlistlen)
410                                 _readtimes[ handler ] = _currenttime
411                         end
412                 end
413                 return noread
414         end
415         handler.pause = function (self)
416                 return self:lock_read(true);
417         end
418         handler.resume = function (self)
419                 return self:lock_read(false);
420         end
421         handler.lock = function( self, switch )
422                 handler.lock_read (switch)
423                 if switch == true then
424                         handler.write = idfalse
425                         local tmp = _sendlistlen
426                         _sendlistlen = removesocket( _sendlist, socket, _sendlistlen )
427                         _writetimes[ handler ] = nil
428                         if _sendlistlen ~= tmp then
429                                 nosend = true
430                         end
431                 elseif switch == false then
432                         handler.write = write
433                         if nosend then
434                                 nosend = false
435                                 write( "" )
436                         end
437                 end
438                 return noread, nosend
439         end
440         local _readbuffer = function( ) -- this function reads data
441                 local buffer, err, part = receive( socket, pattern )    -- receive buffer with "pattern"
442                 if not err or (err == "wantread" or err == "timeout") then -- received something
443                         local buffer = buffer or part or ""
444                         local len = string_len( buffer )
445                         if len > maxreadlen then
446                                 disconnect( handler, "receive buffer exceeded" )
447                                 handler:close( true )
448                                 return false
449                         end
450                         local count = len * STAT_UNIT
451                         readtraffic = readtraffic + count
452                         _readtraffic = _readtraffic + count
453                         _readtimes[ handler ] = _currenttime
454                         --out_put( "server.lua: read data '", buffer:gsub("[^%w%p ]", "."), "', error: ", err )
455                         return dispatch( handler, buffer, err )
456                 else    -- connections was closed or fatal error
457                         out_put( "server.lua: client ", tostring(ip), ":", tostring(clientport), " read error: ", tostring(err) )
458                         fatalerror = true
459                         disconnect( handler, err )
460                 _ = handler and handler:close( )
461                         return false
462                 end
463         end
464         local _sendbuffer = function( ) -- this function sends data
465                 local succ, err, byte, buffer, count;
466                 local count;
467                 if socket then
468                         buffer = table_concat( bufferqueue, "", 1, bufferqueuelen )
469                         succ, err, byte = send( socket, buffer, 1, bufferlen )
470                         count = ( succ or byte or 0 ) * STAT_UNIT
471                         sendtraffic = sendtraffic + count
472                         _sendtraffic = _sendtraffic + count
473                         _ = _cleanqueue and clean( bufferqueue )
474                         --out_put( "server.lua: sended '", buffer, "', bytes: ", tostring(succ), ", error: ", tostring(err), ", part: ", tostring(byte), ", to: ", tostring(ip), ":", tostring(clientport) )
475                 else
476                         succ, err, count = false, "closed", 0;
477                 end
478                 if succ then    -- sending succesful
479                         bufferqueuelen = 0
480                         bufferlen = 0
481                         _sendlistlen = removesocket( _sendlist, socket, _sendlistlen ) -- delete socket from writelist
482                         _ = needtls and handler:starttls(nil, true)
483                         _writetimes[ handler ] = nil
484                         if drain then
485                                 drain(handler)
486                         end
487                         _ = toclose and handler:close( )
488                         return true
489                 elseif byte and ( err == "timeout" or err == "wantwrite" ) then -- want write
490                         buffer = string_sub( buffer, byte + 1, bufferlen ) -- new buffer
491                         bufferqueue[ 1 ] = buffer        -- insert new buffer in queue
492                         bufferqueuelen = 1
493                         bufferlen = bufferlen - byte
494                         _writetimes[ handler ] = _currenttime
495                         return true
496                 else    -- connection was closed during sending or fatal error
497                         out_put( "server.lua: client ", tostring(ip), ":", tostring(clientport), " write error: ", tostring(err) )
498                         fatalerror = true
499                         disconnect( handler, err )
500                         _ = handler and handler:close( )
501                         return false
502                 end
503         end
504
505         -- Set the sslctx
506         local handshake;
507         function handler.set_sslctx(self, new_sslctx)
508                 ssl = true
509                 sslctx = new_sslctx;
510                 local wrote
511                 local read
512                 handshake = coroutine_wrap( function( client ) -- create handshake coroutine
513                                 local err
514                                 for i = 1, _maxsslhandshake do
515                                         _sendlistlen = ( wrote and removesocket( _sendlist, client, _sendlistlen ) ) or _sendlistlen
516                                         _readlistlen = ( read and removesocket( _readlist, client, _readlistlen ) ) or _readlistlen
517                                         read, wrote = nil, nil
518                                         _, err = client:dohandshake( )
519                                         if not err then
520                                                 out_put( "server.lua: ssl handshake done" )
521                                                 handler.readbuffer = _readbuffer        -- when handshake is done, replace the handshake function with regular functions
522                                                 handler.sendbuffer = _sendbuffer
523                                                 _ = status and status( handler, "ssl-handshake-complete" )
524                                                 _readlistlen = addsocket(_readlist, client, _readlistlen)
525                                                 return true
526                                         else
527                                                 out_put( "server.lua: error during ssl handshake: ", tostring(err) )
528                                                 if err == "wantwrite" and not wrote then
529                                                         _sendlistlen = addsocket(_sendlist, client, _sendlistlen)
530                                                         wrote = true
531                                                 elseif err == "wantread" and not read then
532                                                         _readlistlen = addsocket(_readlist, client, _readlistlen)
533                                                         read = true
534                                                 else
535                                                         break;
536                                                 end
537                                                 --coroutine_yield( handler, nil, err )   -- handshake not finished
538                                                 coroutine_yield( )
539                                         end
540                                 end
541                                 disconnect( handler, "ssl handshake failed" )
542                                 _ = handler and handler:close( true )    -- forced disconnect
543                                 return false    -- handshake failed
544                         end
545                 )
546         end
547         if luasec then
548                 if sslctx then -- ssl?
549                         handler:set_sslctx(sslctx);
550                         out_put("server.lua: ", "starting ssl handshake")
551                         local err
552                         socket, err = ssl_wrap( socket, sslctx )        -- wrap socket
553                         if err then
554                                 out_put( "server.lua: ssl error: ", tostring(err) )
555                                 --mem_free( )
556                                 return nil, nil, err    -- fatal error
557                         end
558                         socket:settimeout( 0 )
559                         handler.readbuffer = handshake
560                         handler.sendbuffer = handshake
561                         handshake( socket ) -- do handshake
562                         if not socket then
563                                 return nil, nil, "ssl handshake failed";
564                         end
565                 else
566                         local sslctx;
567                         handler.starttls = function( self, _sslctx, now )
568                                 if _sslctx then
569                                         sslctx = _sslctx;
570                                         handler:set_sslctx(sslctx);
571                                 end
572                                 if not now then
573                                         out_put "server.lua: we need to do tls, but delaying until later"
574                                         needtls = true
575                                         return
576                                 end
577                                 out_put( "server.lua: attempting to start tls on " .. tostring( socket ) )
578                                 local oldsocket, err = socket
579                                 socket, err = ssl_wrap( socket, sslctx )        -- wrap socket
580                                 --out_put( "server.lua: sslwrapped socket is " .. tostring( socket ) )
581                                 if err then
582                                         out_put( "server.lua: error while starting tls on client: ", tostring(err) )
583                                         return nil, err -- fatal error
584                                 end
585
586                                 socket:settimeout( 0 )
587         
588                                 -- add the new socket to our system
589         
590                                 send = socket.send
591                                 receive = socket.receive
592                                 shutdown = id
593
594                                 _socketlist[ socket ] = handler
595                                 _readlistlen = addsocket(_readlist, socket, _readlistlen)
596
597                                 -- remove traces of the old socket
598
599                                 _readlistlen = removesocket( _readlist, oldsocket, _readlistlen )
600                                 _sendlistlen = removesocket( _sendlist, oldsocket, _sendlistlen )
601                                 _socketlist[ oldsocket ] = nil
602
603                                 handler.starttls = nil
604                                 needtls = nil
605
606                                 -- Secure now
607                                 ssl = true
608
609                                 handler.readbuffer = handshake
610                                 handler.sendbuffer = handshake
611                                 handshake( socket ) -- do handshake
612                         end
613                         handler.readbuffer = _readbuffer
614                         handler.sendbuffer = _sendbuffer
615                 end
616         else
617                 handler.readbuffer = _readbuffer
618                 handler.sendbuffer = _sendbuffer
619         end
620         send = socket.send
621         receive = socket.receive
622         shutdown = ( ssl and id ) or socket.shutdown
623
624         _socketlist[ socket ] = handler
625         _readlistlen = addsocket(_readlist, socket, _readlistlen)
626         if listeners.onconnect then
627                 _sendlistlen = addsocket(_sendlist, socket, _sendlistlen)
628                 handler.sendbuffer = function ()
629                         listeners.onconnect(handler);
630                         handler.sendbuffer = _sendbuffer;
631                         if bufferqueuelen > 0 then
632                                 return _sendbuffer();
633                         end
634                 end
635         end
636         return handler, socket
637 end
638
639 id = function( )
640 end
641
642 idfalse = function( )
643         return false
644 end
645
646 addsocket = function( list, socket, len )
647         if not list[ socket ] then
648                 len = len + 1
649                 list[ len ] = socket
650                 list[ socket ] = len
651         end
652         return len;
653 end
654
655 removesocket = function( list, socket, len )    -- this function removes sockets from a list ( copied from copas )
656         local pos = list[ socket ]
657         if pos then
658                 list[ socket ] = nil
659                 local last = list[ len ]
660                 list[ len ] = nil
661                 if last ~= socket then
662                         list[ last ] = pos
663                         list[ pos ] = last
664                 end
665                 return len - 1
666         end
667         return len
668 end
669
670 closesocket = function( socket )
671         _sendlistlen = removesocket( _sendlist, socket, _sendlistlen )
672         _readlistlen = removesocket( _readlist, socket, _readlistlen )
673         _socketlist[ socket ] = nil
674         socket:close( )
675         --mem_free( )
676 end
677
678 local function link(sender, receiver, buffersize)
679         sender:set_mode(buffersize);
680         local sender_locked;
681         local _sendbuffer = receiver.sendbuffer;
682         function receiver.sendbuffer()
683                 _sendbuffer();
684                 if sender_locked and receiver.bufferlen() < buffersize then
685                         sender:lock_read(false); -- Unlock now
686                         sender_locked = nil;
687                 end
688         end
689         
690         local _readbuffer = sender.readbuffer;
691         function sender.readbuffer()
692                 _readbuffer();
693                 if not sender_locked and receiver.bufferlen() >= buffersize then
694                         sender_locked = true;
695                         sender:lock_read(true);
696                 end
697         end
698 end
699
700 ----------------------------------// PUBLIC //--
701
702 addserver = function( addr, port, listeners, pattern, sslctx ) -- this function provides a way for other scripts to reg a server
703         local err
704         if type( listeners ) ~= "table" then
705                 err = "invalid listener table"
706         end
707         if type( port ) ~= "number" or not ( port >= 0 and port <= 65535 ) then
708                 err = "invalid port"
709         elseif _server[ port ] then
710                 err = "listeners on port '" .. port .. "' already exist"
711         elseif sslctx and not luasec then
712                 err = "luasec not found"
713         end
714         if err then
715                 out_error( "server.lua, port ", port, ": ", err )
716                 return nil, err
717         end
718         addr = addr or "*"
719         local server, err = socket_bind( addr, port )
720         if err then
721                 out_error( "server.lua, port ", port, ": ", err )
722                 return nil, err
723         end
724         local handler, err = wrapserver( listeners, server, addr, port, pattern, sslctx, _maxclientsperserver ) -- wrap new server socket
725         if not handler then
726                 server:close( )
727                 return nil, err
728         end
729         server:settimeout( 0 )
730         _readlistlen = addsocket(_readlist, server, _readlistlen)
731         _server[ port ] = handler
732         _socketlist[ server ] = handler
733         out_put( "server.lua: new "..(sslctx and "ssl " or "").."server listener on '", addr, ":", port, "'" )
734         return handler
735 end
736
737 getserver = function ( port )
738         return _server[ port ];
739 end
740
741 removeserver = function( port )
742         local handler = _server[ port ]
743         if not handler then
744                 return nil, "no server found on port '" .. tostring( port ) .. "'"
745         end
746         handler:close( )
747         _server[ port ] = nil
748         return true
749 end
750
751 closeall = function( )
752         for _, handler in pairs( _socketlist ) do
753                 handler:close( )
754                 _socketlist[ _ ] = nil
755         end
756         _readlistlen = 0
757         _sendlistlen = 0
758         _timerlistlen = 0
759         _server = { }
760         _readlist = { }
761         _sendlist = { }
762         _timerlist = { }
763         _socketlist = { }
764         --mem_free( )
765 end
766
767 getsettings = function( )
768         return  _selecttimeout, _sleeptime, _maxsendlen, _maxreadlen, _checkinterval, _sendtimeout, _readtimeout, _cleanqueue, _maxclientsperserver, _maxsslhandshake
769 end
770
771 changesettings = function( new )
772         if type( new ) ~= "table" then
773                 return nil, "invalid settings table"
774         end
775         _selecttimeout = tonumber( new.timeout ) or _selecttimeout
776         _sleeptime = tonumber( new.sleeptime ) or _sleeptime
777         _maxsendlen = tonumber( new.maxsendlen ) or _maxsendlen
778         _maxreadlen = tonumber( new.maxreadlen ) or _maxreadlen
779         _checkinterval = tonumber( new.checkinterval ) or _checkinterval
780         _sendtimeout = tonumber( new.sendtimeout ) or _sendtimeout
781         _readtimeout = tonumber( new.readtimeout ) or _readtimeout
782         _cleanqueue = new.cleanqueue
783         _maxclientsperserver = new._maxclientsperserver or _maxclientsperserver
784         _maxsslhandshake = new._maxsslhandshake or _maxsslhandshake
785         return true
786 end
787
788 addtimer = function( listener )
789         if type( listener ) ~= "function" then
790                 return nil, "invalid listener function"
791         end
792         _timerlistlen = _timerlistlen + 1
793         _timerlist[ _timerlistlen ] = listener
794         return true
795 end
796
797 stats = function( )
798         return _readtraffic, _sendtraffic, _readlistlen, _sendlistlen, _timerlistlen
799 end
800
801 local dontstop = true; -- thinking about tomorrow, ...
802
803 setquitting = function (quit)
804         dontstop = not quit;
805         return;
806 end
807
808 loop = function( ) -- this is the main loop of the program
809         while dontstop do
810                 local read, write, err = socket_select( _readlist, _sendlist, _selecttimeout )
811                 for i, socket in ipairs( write ) do -- send data waiting in writequeues
812                         local handler = _socketlist[ socket ]
813                         if handler then
814                                 handler.sendbuffer( )
815                         else
816                                 closesocket( socket )
817                                 out_put "server.lua: found no handler and closed socket (writelist)"    -- this should not happen
818                         end
819                 end
820                 for i, socket in ipairs( read ) do -- receive data
821                         local handler = _socketlist[ socket ]
822                         if handler then
823                                 handler.readbuffer( )
824                         else
825                                 closesocket( socket )
826                                 out_put "server.lua: found no handler and closed socket (readlist)" -- this can happen
827                         end
828                 end
829                 for handler, err in pairs( _closelist ) do
830                         handler.disconnect( )( handler, err )
831                         handler:close( true )    -- forced disconnect
832                 end
833                 clean( _closelist )
834                 _currenttime = os_time( )
835                 if os_difftime( _currenttime - _timer ) >= 1 then
836                         for i = 1, _timerlistlen do
837                                 _timerlist[ i ]( _currenttime ) -- fire timers
838                         end
839                         _timer = _currenttime
840                 end
841                 socket_sleep( _sleeptime ) -- wait some time
842                 --collectgarbage( )
843         end
844         return "quitting"
845 end
846
847 local function get_backend()
848         return "select";
849 end
850
851 --// EXPERIMENTAL //--
852
853 local wrapclient = function( socket, ip, serverport, listeners, pattern, sslctx )
854         local handler = wrapconnection( nil, listeners, socket, ip, serverport, "clientport", pattern, sslctx )
855         _socketlist[ socket ] = handler
856         _sendlistlen = addsocket(_sendlist, socket, _sendlistlen)
857         return handler, socket
858 end
859
860 local addclient = function( address, port, listeners, pattern, sslctx )
861         local client, err = luasocket.tcp( )
862         if err then
863                 return nil, err
864         end
865         client:settimeout( 0 )
866         _, err = client:connect( address, port )
867         if err then -- try again
868                 local handler = wrapclient( client, address, port, listeners )
869         else
870                 wrapconnection( nil, listeners, client, address, port, "clientport", pattern, sslctx )
871         end
872 end
873
874 --// EXPERIMENTAL //--
875
876 ----------------------------------// BEGIN //--
877
878 use "setmetatable" ( _socketlist, { __mode = "k" } )
879 use "setmetatable" ( _readtimes, { __mode = "k" } )
880 use "setmetatable" ( _writetimes, { __mode = "k" } )
881
882 _timer = os_time( )
883 _starttime = os_time( )
884
885 addtimer( function( )
886                 local difftime = os_difftime( _currenttime - _starttime )
887                 if difftime > _checkinterval then
888                         _starttime = _currenttime
889                         for handler, timestamp in pairs( _writetimes ) do
890                                 if os_difftime( _currenttime - timestamp ) > _sendtimeout then
891                                         --_writetimes[ handler ] = nil
892                                         handler.disconnect( )( handler, "send timeout" )
893                                         handler:close( true )    -- forced disconnect
894                                 end
895                         end
896                         for handler, timestamp in pairs( _readtimes ) do
897                                 if os_difftime( _currenttime - timestamp ) > _readtimeout then
898                                         --_readtimes[ handler ] = nil
899                                         handler.disconnect( )( handler, "read timeout" )
900                                         handler:close( )        -- forced disconnect?
901                                 end
902                         end
903                 end
904         end
905 )
906
907 local function setlogger(new_logger)
908         local old_logger = log;
909         if new_logger then
910                 log = new_logger;
911         end
912         return old_logger;
913 end
914
915 ----------------------------------// PUBLIC INTERFACE //--
916
917 return {
918
919         addclient = addclient,
920         wrapclient = wrapclient,
921         
922         loop = loop,
923         link = link,
924         stats = stats,
925         closeall = closeall,
926         addtimer = addtimer,
927         addserver = addserver,
928         getserver = getserver,
929         setlogger = setlogger,
930         getsettings = getsettings,
931         setquitting = setquitting,
932         removeserver = removeserver,
933         get_backend = get_backend,
934         changesettings = changesettings,
935 }