122d774e19a9e756f1010cf5a0164785e2e6e61d
[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
23 ----------------------------------// DECLARATION //--
24
25 --// constants //--
26
27 local STAT_UNIT = 1 -- byte
28
29 --// lua functions //--
30
31 local type = use "type"
32 local pairs = use "pairs"
33 local ipairs = use "ipairs"
34 local tonumber = use "tonumber"
35 local tostring = use "tostring"
36
37 --// lua libs //--
38
39 local os = use "os"
40 local table = use "table"
41 local string = use "string"
42 local coroutine = use "coroutine"
43
44 --// lua lib methods //--
45
46 local os_difftime = os.difftime
47 local math_min = math.min
48 local math_huge = math.huge
49 local table_concat = table.concat
50 local string_len = string.len
51 local string_sub = string.sub
52 local coroutine_wrap = coroutine.wrap
53 local coroutine_yield = coroutine.yield
54
55 --// extern libs //--
56
57 local luasec = use "ssl"
58 local luasocket = use "socket" or require "socket"
59 local luasocket_gettime = luasocket.gettime
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
68 --// functions //--
69
70 local id
71 local loop
72 local stats
73 local idfalse
74 local closeall
75 local addsocket
76 local addserver
77 local addtimer
78 local getserver
79 local wrapserver
80 local getsettings
81 local closesocket
82 local removesocket
83 local removeserver
84 local wrapconnection
85 local changesettings
86
87 --// tables //--
88
89 local _server
90 local _readlist
91 local _timerlist
92 local _sendlist
93 local _socketlist
94 local _closelist
95 local _readtimes
96 local _writetimes
97
98 --// simple data types //--
99
100 local _
101 local _readlistlen
102 local _sendlistlen
103 local _timerlistlen
104
105 local _sendtraffic
106 local _readtraffic
107
108 local _selecttimeout
109 local _sleeptime
110
111 local _starttime
112 local _currenttime
113
114 local _maxsendlen
115 local _maxreadlen
116
117 local _checkinterval
118 local _sendtimeout
119 local _readtimeout
120
121 local _cleanqueue
122
123 local _timer
124
125 local _maxclientsperserver
126
127 local _maxsslhandshake
128
129 ----------------------------------// DEFINITION //--
130
131 _server = { } -- key = port, value = table; list of listening servers
132 _readlist = { } -- array with sockets to read from
133 _sendlist = { } -- arrary with sockets to write to
134 _timerlist = { } -- array of timer functions
135 _socketlist = { } -- key = socket, value = wrapped socket (handlers)
136 _readtimes = { } -- key = handler, value = timestamp of last data reading
137 _writetimes = { } -- key = handler, value = timestamp of last data writing/sending
138 _closelist = { } -- handlers to close
139
140 _readlistlen = 0 -- length of readlist
141 _sendlistlen = 0 -- length of sendlist
142 _timerlistlen = 0 -- lenght of timerlist
143
144 _sendtraffic = 0 -- some stats
145 _readtraffic = 0
146
147 _selecttimeout = 1 -- timeout of socket.select
148 _sleeptime = 0 -- time to wait at the end of every loop
149
150 _maxsendlen = 51000 * 1024 -- max len of send buffer
151 _maxreadlen = 25000 * 1024 -- max len of read buffer
152
153 _checkinterval = 1200000 -- interval in secs to check idle clients
154 _sendtimeout = 60000 -- allowed send idle time in secs
155 _readtimeout = 6 * 60 * 60 -- allowed read idle time in secs
156
157 _cleanqueue = false -- clean bufferqueue after using
158
159 _maxclientsperserver = 1000
160
161 _maxsslhandshake = 30 -- max handshake round-trips
162
163 ----------------------------------// PRIVATE //--
164
165 wrapserver = function( listeners, socket, ip, serverport, pattern, sslctx, maxconnections ) -- this function wraps a server
166
167         maxconnections = maxconnections or _maxclientsperserver
168
169         local connections = 0
170
171         local dispatch, disconnect = listeners.onconnect, listeners.ondisconnect
172
173         local accept = socket.accept
174
175         --// public methods of the object //--
176
177         local handler = { }
178
179         handler.shutdown = function( ) end
180
181         handler.ssl = function( )
182                 return sslctx ~= nil
183         end
184         handler.sslctx = function( )
185                 return sslctx
186         end
187         handler.remove = function( )
188                 connections = connections - 1
189                 if handler then
190                         handler.resume( )
191                 end
192         end
193         handler.close = function()
194                 socket:close( )
195                 _sendlistlen = removesocket( _sendlist, socket, _sendlistlen )
196                 _readlistlen = removesocket( _readlist, socket, _readlistlen )
197                 _server[ip..":"..serverport] = nil;
198                 _socketlist[ socket ] = nil
199                 handler = nil
200                 socket = nil
201                 --mem_free( )
202                 out_put "server.lua: closed server handler and removed sockets from list"
203         end
204         handler.pause = function()
205                 if not handler.paused then
206                         socket:close( )
207                         _sendlistlen = removesocket( _sendlist, socket, _sendlistlen )
208                         _readlistlen = removesocket( _readlist, socket, _readlistlen )
209                         _socketlist[ socket ] = nil
210                         socket = nil;
211                         handler.paused = true;
212                 end
213         end
214         handler.resume = function()
215                 if handler.paused then
216                         socket = socket_bind( ip, serverport );
217                         socket:settimeout( 0 )
218                         _readlistlen = addsocket(_readlist, socket, _readlistlen)
219                         _socketlist[ socket ] = handler
220                         handler.paused = false;
221                 end
222         end
223         handler.ip = function( )
224                 return ip
225         end
226         handler.serverport = function( )
227                 return serverport
228         end
229         handler.socket = function( )
230                 return socket
231         end
232         handler.readbuffer = function( )
233                 if connections > maxconnections then
234                         handler.pause( )
235                         out_put( "server.lua: refused new client connection: server full" )
236                         return false
237                 end
238                 local client, err = accept( socket )    -- try to accept
239                 if client then
240                         local ip, clientport = client:getpeername( )
241                         client:settimeout( 0 )
242                         local handler, client, err = wrapconnection( handler, listeners, client, ip, serverport, clientport, pattern, sslctx ) -- wrap new client socket
243                         if err then -- error while wrapping ssl socket
244                                 return false
245                         end
246                         connections = connections + 1
247                         out_put( "server.lua: accepted new client connection from ", tostring(ip), ":", tostring(clientport), " to ", tostring(serverport))
248                         if dispatch then
249                                 return dispatch( handler );
250                         end
251                         return;
252                 elseif err then -- maybe timeout or something else
253                         out_put( "server.lua: error with new client connection: ", tostring(err) )
254                         return false
255                 end
256         end
257         return handler
258 end
259
260 wrapconnection = function( server, listeners, socket, ip, serverport, clientport, pattern, sslctx ) -- this function wraps a client to a handler object
261
262         socket:settimeout( 0 )
263
264         --// local import of socket methods //--
265
266         local send
267         local receive
268         local shutdown
269
270         --// private closures of the object //--
271
272         local ssl
273
274         local dispatch = listeners.onincoming
275         local status = listeners.onstatus
276         local disconnect = listeners.ondisconnect
277         local drain = listeners.ondrain
278
279         local bufferqueue = { } -- buffer array
280         local bufferqueuelen = 0        -- end of buffer array
281
282         local toclose
283         local fatalerror
284         local needtls
285
286         local bufferlen = 0
287
288         local noread = false
289         local nosend = false
290
291         local sendtraffic, readtraffic = 0, 0
292
293         local maxsendlen = _maxsendlen
294         local maxreadlen = _maxreadlen
295
296         --// public methods of the object //--
297
298         local handler = bufferqueue -- saves a table ^_^
299
300         handler.dispatch = function( )
301                 return dispatch
302         end
303         handler.disconnect = function( )
304                 return disconnect
305         end
306         handler.setlistener = function( self, listeners )
307                 dispatch = listeners.onincoming
308                 disconnect = listeners.ondisconnect
309                 status = listeners.onstatus
310                 drain = listeners.ondrain
311         end
312         handler.getstats = function( )
313                 return readtraffic, sendtraffic
314         end
315         handler.ssl = function( )
316                 return ssl
317         end
318         handler.sslctx = function ( )
319                 return sslctx
320         end
321         handler.send = function( _, data, i, j )
322                 return send( socket, data, i, j )
323         end
324         handler.receive = function( pattern, prefix )
325                 return receive( socket, pattern, prefix )
326         end
327         handler.shutdown = function( pattern )
328                 return shutdown( socket, pattern )
329         end
330         handler.setoption = function (self, option, value)
331                 if socket.setoption then
332                         return socket:setoption(option, value);
333                 end
334                 return false, "setoption not implemented";
335         end
336         handler.force_close = function ( self, err )
337                 if bufferqueuelen ~= 0 then
338                         out_put("server.lua: discarding unwritten data for ", tostring(ip), ":", tostring(clientport))
339                         for i = bufferqueuelen, 1, -1 do
340                                 bufferqueue[i] = nil;
341                         end
342                         bufferqueuelen = 0;
343                 end
344                 return self:close(err);
345         end
346         handler.close = function( self, err )
347                 if not handler then return true; end
348                 _readlistlen = removesocket( _readlist, socket, _readlistlen )
349                 _readtimes[ handler ] = nil
350                 if bufferqueuelen ~= 0 then
351                         handler.sendbuffer() -- Try now to send any outstanding data
352                         if bufferqueuelen ~= 0 then -- Still not empty, so we'll try again later
353                                 if handler then
354                                         handler.write = nil -- ... but no further writing allowed
355                                 end
356                                 toclose = true
357                                 return false
358                         end
359                 end
360                 if socket then
361                         _ = shutdown and shutdown( socket )
362                         socket:close( )
363                         _sendlistlen = removesocket( _sendlist, socket, _sendlistlen )
364                         _socketlist[ socket ] = nil
365                         socket = nil
366                 else
367                         out_put "server.lua: socket already closed"
368                 end
369                 if handler then
370                         _writetimes[ handler ] = nil
371                         _closelist[ handler ] = nil
372                         local _handler = handler;
373                         handler = nil
374                         if disconnect then
375                                 disconnect(_handler, err or false);
376                                 disconnect = nil
377                         end
378                 end
379                 if server then
380                         server.remove( )
381                 end
382                 out_put "server.lua: closed client handler and removed socket from list"
383                 return true
384         end
385         handler.ip = function( )
386                 return ip
387         end
388         handler.serverport = function( )
389                 return serverport
390         end
391         handler.clientport = function( )
392                 return clientport
393         end
394         local write = function( self, data )
395                 bufferlen = bufferlen + string_len( data )
396                 if bufferlen > maxsendlen then
397                         _closelist[ handler ] = "send buffer exceeded"   -- cannot close the client at the moment, have to wait to the end of the cycle
398                         handler.write = idfalse -- dont write anymore
399                         return false
400                 elseif socket and not _sendlist[ socket ] then
401                         _sendlistlen = addsocket(_sendlist, socket, _sendlistlen)
402                 end
403                 bufferqueuelen = bufferqueuelen + 1
404                 bufferqueue[ bufferqueuelen ] = data
405                 if handler then
406                         _writetimes[ handler ] = _writetimes[ handler ] or _currenttime
407                 end
408                 return true
409         end
410         handler.write = write
411         handler.bufferqueue = function( self )
412                 return bufferqueue
413         end
414         handler.socket = function( self )
415                 return socket
416         end
417         handler.set_mode = function( self, new )
418                 pattern = new or pattern
419                 return pattern
420         end
421         handler.set_send = function ( self, newsend )
422                 send = newsend or send
423                 return send
424         end
425         handler.bufferlen = function( self, readlen, sendlen )
426                 maxsendlen = sendlen or maxsendlen
427                 maxreadlen = readlen or maxreadlen
428                 return bufferlen, maxreadlen, maxsendlen
429         end
430         --TODO: Deprecate
431         handler.lock_read = function (self, switch)
432                 if switch == true then
433                         local tmp = _readlistlen
434                         _readlistlen = removesocket( _readlist, socket, _readlistlen )
435                         _readtimes[ handler ] = nil
436                         if _readlistlen ~= tmp then
437                                 noread = true
438                         end
439                 elseif switch == false then
440                         if noread then
441                                 noread = false
442                                 _readlistlen = addsocket(_readlist, socket, _readlistlen)
443                                 _readtimes[ handler ] = _currenttime
444                         end
445                 end
446                 return noread
447         end
448         handler.pause = function (self)
449                 return self:lock_read(true);
450         end
451         handler.resume = function (self)
452                 return self:lock_read(false);
453         end
454         handler.lock = function( self, switch )
455                 handler.lock_read (switch)
456                 if switch == true then
457                         handler.write = idfalse
458                         local tmp = _sendlistlen
459                         _sendlistlen = removesocket( _sendlist, socket, _sendlistlen )
460                         _writetimes[ handler ] = nil
461                         if _sendlistlen ~= tmp then
462                                 nosend = true
463                         end
464                 elseif switch == false then
465                         handler.write = write
466                         if nosend then
467                                 nosend = false
468                                 write( "" )
469                         end
470                 end
471                 return noread, nosend
472         end
473         local _readbuffer = function( ) -- this function reads data
474                 local buffer, err, part = receive( socket, pattern )    -- receive buffer with "pattern"
475                 if not err or (err == "wantread" or err == "timeout") then -- received something
476                         local buffer = buffer or part or ""
477                         local len = string_len( buffer )
478                         if len > maxreadlen then
479                                 handler:close( "receive buffer exceeded" )
480                                 return false
481                         end
482                         local count = len * STAT_UNIT
483                         readtraffic = readtraffic + count
484                         _readtraffic = _readtraffic + count
485                         _readtimes[ handler ] = _currenttime
486                         --out_put( "server.lua: read data '", buffer:gsub("[^%w%p ]", "."), "', error: ", err )
487                         return dispatch( handler, buffer, err )
488                 else    -- connections was closed or fatal error
489                         out_put( "server.lua: client ", tostring(ip), ":", tostring(clientport), " read error: ", tostring(err) )
490                         fatalerror = true
491                         _ = handler and handler:force_close( err )
492                         return false
493                 end
494         end
495         local _sendbuffer = function( ) -- this function sends data
496                 local succ, err, byte, buffer, count;
497                 if socket then
498                         buffer = table_concat( bufferqueue, "", 1, bufferqueuelen )
499                         succ, err, byte = send( socket, buffer, 1, bufferlen )
500                         count = ( succ or byte or 0 ) * STAT_UNIT
501                         sendtraffic = sendtraffic + count
502                         _sendtraffic = _sendtraffic + count
503                         _ = _cleanqueue and clean( bufferqueue )
504                         --out_put( "server.lua: sended '", buffer, "', bytes: ", tostring(succ), ", error: ", tostring(err), ", part: ", tostring(byte), ", to: ", tostring(ip), ":", tostring(clientport) )
505                 else
506                         succ, err, count = false, "unexpected close", 0;
507                 end
508                 if succ then    -- sending succesful
509                         bufferqueuelen = 0
510                         bufferlen = 0
511                         _sendlistlen = removesocket( _sendlist, socket, _sendlistlen ) -- delete socket from writelist
512                         _writetimes[ handler ] = nil
513                         if drain then
514                                 drain(handler)
515                         end
516                         _ = needtls and handler:starttls(nil)
517                         _ = toclose and handler:force_close( )
518                         return true
519                 elseif byte and ( err == "timeout" or err == "wantwrite" ) then -- want write
520                         buffer = string_sub( buffer, byte + 1, bufferlen ) -- new buffer
521                         bufferqueue[ 1 ] = buffer        -- insert new buffer in queue
522                         bufferqueuelen = 1
523                         bufferlen = bufferlen - byte
524                         _writetimes[ handler ] = _currenttime
525                         return true
526                 else    -- connection was closed during sending or fatal error
527                         out_put( "server.lua: client ", tostring(ip), ":", tostring(clientport), " write error: ", tostring(err) )
528                         fatalerror = true
529                         _ = handler and handler:force_close( err )
530                         return false
531                 end
532         end
533
534         -- Set the sslctx
535         local handshake;
536         function handler.set_sslctx(self, new_sslctx)
537                 sslctx = new_sslctx;
538                 local read, wrote
539                 handshake = coroutine_wrap( function( client ) -- create handshake coroutine
540                                 local err
541                                 for i = 1, _maxsslhandshake do
542                                         _sendlistlen = ( wrote and removesocket( _sendlist, client, _sendlistlen ) ) or _sendlistlen
543                                         _readlistlen = ( read and removesocket( _readlist, client, _readlistlen ) ) or _readlistlen
544                                         read, wrote = nil, nil
545                                         _, err = client:dohandshake( )
546                                         if not err then
547                                                 out_put( "server.lua: ssl handshake done" )
548                                                 handler.readbuffer = _readbuffer        -- when handshake is done, replace the handshake function with regular functions
549                                                 handler.sendbuffer = _sendbuffer
550                                                 _ = status and status( handler, "ssl-handshake-complete" )
551                                                 if self.autostart_ssl and listeners.onconnect then
552                                                         listeners.onconnect(self);
553                                                 end
554                                                 _readlistlen = addsocket(_readlist, client, _readlistlen)
555                                                 return true
556                                         else
557                                                 if err == "wantwrite" then
558                                                         _sendlistlen = addsocket(_sendlist, client, _sendlistlen)
559                                                         wrote = true
560                                                 elseif err == "wantread" then
561                                                         _readlistlen = addsocket(_readlist, client, _readlistlen)
562                                                         read = true
563                                                 else
564                                                         break;
565                                                 end
566                                                 err = nil;
567                                                 coroutine_yield( ) -- handshake not finished
568                                         end
569                                 end
570                                 out_put( "server.lua: ssl handshake error: ", tostring(err or "handshake too long") )
571                                 _ = handler and handler:force_close("ssl handshake failed")
572                return false, err -- handshake failed
573                         end
574                 )
575         end
576         if luasec then
577                 handler.starttls = function( self, _sslctx)
578                         if _sslctx then
579                                 handler:set_sslctx(_sslctx);
580                         end
581                         if bufferqueuelen > 0 then
582                                 out_put "server.lua: we need to do tls, but delaying until send buffer empty"
583                                 needtls = true
584                                 return
585                         end
586                         out_put( "server.lua: attempting to start tls on " .. tostring( socket ) )
587                         local oldsocket, err = socket
588                         socket, err = ssl_wrap( socket, sslctx )        -- wrap socket
589                         if not socket then
590                                 out_put( "server.lua: error while starting tls on client: ", tostring(err or "unknown error") )
591                                 return nil, err -- fatal error
592                         end
593
594                         socket:settimeout( 0 )
595
596                         -- add the new socket to our system
597                         send = socket.send
598                         receive = socket.receive
599                         shutdown = id
600                         _socketlist[ socket ] = handler
601                         _readlistlen = addsocket(_readlist, socket, _readlistlen)
602                         
603                         -- remove traces of the old socket
604                         _readlistlen = removesocket( _readlist, oldsocket, _readlistlen )
605                         _sendlistlen = removesocket( _sendlist, oldsocket, _sendlistlen )
606                         _socketlist[ oldsocket ] = nil
607
608                         handler.starttls = nil
609                         needtls = nil
610
611                         -- Secure now (if handshake fails connection will close)
612                         ssl = true
613
614                         handler.readbuffer = handshake
615                         handler.sendbuffer = handshake
616                        return handshake( socket ) -- do handshake
617                 end
618         end
619
620         handler.readbuffer = _readbuffer
621         handler.sendbuffer = _sendbuffer
622         send = socket.send
623         receive = socket.receive
624         shutdown = ( ssl and id ) or socket.shutdown
625
626         _socketlist[ socket ] = handler
627         _readlistlen = addsocket(_readlist, socket, _readlistlen)
628
629         if sslctx and luasec then
630                 out_put "server.lua: auto-starting ssl negotiation..."
631                 handler.autostart_ssl = true;
632                local ok, err = handler:starttls(sslctx);
633                if ok == false then
634                        return nil, nil, err
635                end
636         end
637
638         return handler, socket
639 end
640
641 id = function( )
642 end
643
644 idfalse = function( )
645         return false
646 end
647
648 addsocket = function( list, socket, len )
649         if not list[ socket ] then
650                 len = len + 1
651                 list[ len ] = socket
652                 list[ socket ] = len
653         end
654         return len;
655 end
656
657 removesocket = function( list, socket, len )    -- this function removes sockets from a list ( copied from copas )
658         local pos = list[ socket ]
659         if pos then
660                 list[ socket ] = nil
661                 local last = list[ len ]
662                 list[ len ] = nil
663                 if last ~= socket then
664                         list[ last ] = pos
665                         list[ pos ] = last
666                 end
667                 return len - 1
668         end
669         return len
670 end
671
672 closesocket = function( socket )
673         _sendlistlen = removesocket( _sendlist, socket, _sendlistlen )
674         _readlistlen = removesocket( _readlist, socket, _readlistlen )
675         _socketlist[ socket ] = nil
676         socket:close( )
677         --mem_free( )
678 end
679
680 local function link(sender, receiver, buffersize)
681         local sender_locked;
682         local _sendbuffer = receiver.sendbuffer;
683         function receiver.sendbuffer()
684                 _sendbuffer();
685                 if sender_locked and receiver.bufferlen() < buffersize then
686                         sender:lock_read(false); -- Unlock now
687                         sender_locked = nil;
688                 end
689         end
690         
691         local _readbuffer = sender.readbuffer;
692         function sender.readbuffer()
693                 _readbuffer();
694                 if not sender_locked and receiver.bufferlen() >= buffersize then
695                         sender_locked = true;
696                         sender:lock_read(true);
697                 end
698         end
699 end
700
701 ----------------------------------// PUBLIC //--
702
703 addserver = function( addr, port, listeners, pattern, sslctx ) -- this function provides a way for other scripts to reg a server
704         local err
705         if type( listeners ) ~= "table" then
706                 err = "invalid listener table"
707         end
708         if type( port ) ~= "number" or not ( port >= 0 and port <= 65535 ) then
709                 err = "invalid port"
710         elseif _server[ addr..":"..port ] then
711                 err = "listeners on '[" .. addr .. "]:" .. 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, [", addr, "]:", 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, [", addr, "]:", port, ": ", err )
723                 return nil, err
724         end
725         local handler, err = wrapserver( listeners, server, addr, port, pattern, sslctx, _maxclientsperserver ) -- 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[ addr..":"..port ] = handler
733         _socketlist[ server ] = handler
734         out_put( "server.lua: new "..(sslctx and "ssl " or "").."server listener on '[", addr, "]:", port, "'" )
735         return handler
736 end
737
738 getserver = function ( addr, port )
739         return _server[ addr..":"..port ];
740 end
741
742 removeserver = function( addr, port )
743         local handler = _server[ addr..":"..port ]
744         if not handler then
745                 return nil, "no server found on '[" .. addr .. "]:" .. tostring( port ) .. "'"
746         end
747         handler:close( )
748         _server[ addr..":"..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.select_timeout ) or _selecttimeout
777         _sleeptime = tonumber( new.select_sleep_time ) or _sleeptime
778         _maxsendlen = tonumber( new.max_send_buffer_size ) or _maxsendlen
779         _maxreadlen = tonumber( new.max_receive_buffer_size ) or _maxreadlen
780         _checkinterval = tonumber( new.select_idle_check_interval ) or _checkinterval
781         _sendtimeout = tonumber( new.send_timeout ) or _sendtimeout
782         _readtimeout = tonumber( new.read_timeout ) or _readtimeout
783         _cleanqueue = new.select_clean_queue
784         _maxclientsperserver = new.max_connections or _maxclientsperserver
785         _maxsslhandshake = new.max_ssl_handshake_roundtrips 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 quitting;
803
804 local function setquitting(quit)
805         quitting = not not quit;
806 end
807
808 loop = function(once) -- this is the main loop of the program
809         if quitting then return "quitting"; end
810         if once then quitting = "once"; end
811         local next_timer_time = math_huge;
812         repeat
813                 local read, write, err = socket_select( _readlist, _sendlist, math_min(_selecttimeout, next_timer_time) )
814                 for i, socket in ipairs( write ) do -- send data waiting in writequeues
815                         local handler = _socketlist[ socket ]
816                         if handler then
817                                 handler.sendbuffer( )
818                         else
819                                 closesocket( socket )
820                                 out_put "server.lua: found no handler and closed socket (writelist)"    -- this should not happen
821                         end
822                 end
823                 for i, socket in ipairs( read ) do -- receive data
824                         local handler = _socketlist[ socket ]
825                         if handler then
826                                 handler.readbuffer( )
827                         else
828                                 closesocket( socket )
829                                 out_put "server.lua: found no handler and closed socket (readlist)" -- this can happen
830                         end
831                 end
832                 for handler, err in pairs( _closelist ) do
833                         handler.disconnect( )( handler, err )
834                         handler:force_close()    -- forced disconnect
835                 end
836                 clean( _closelist )
837                 _currenttime = luasocket_gettime( )
838                 if _currenttime - _timer >= math_min(next_timer_time, 1) then
839                         next_timer_time = math_huge;
840                         for i = 1, _timerlistlen do
841                                 local t = _timerlist[ i ]( _currenttime ) -- fire timers
842                                 if t then next_timer_time = math_min(next_timer_time, t); end
843                         end
844                         _timer = _currenttime
845                 else
846                         next_timer_time = next_timer_time - (_currenttime - _timer);
847                 end
848                 socket_sleep( _sleeptime ) -- wait some time
849                 --collectgarbage( )
850         until quitting;
851         if once and quitting == "once" then quitting = nil; return; end
852         return "quitting"
853 end
854
855 local function step()
856         return loop(true);
857 end
858
859 local function get_backend()
860         return "select";
861 end
862
863 --// EXPERIMENTAL //--
864
865 local wrapclient = function( socket, ip, serverport, listeners, pattern, sslctx )
866         local handler = wrapconnection( nil, listeners, socket, ip, serverport, "clientport", pattern, sslctx )
867         _socketlist[ socket ] = handler
868         if not sslctx then
869                 _sendlistlen = addsocket(_sendlist, socket, _sendlistlen)
870                 if listeners.onconnect then
871                         -- When socket is writeable, call onconnect
872                         local _sendbuffer = handler.sendbuffer;
873                         handler.sendbuffer = function ()
874                                 _sendlistlen = removesocket( _sendlist, socket, _sendlistlen );
875                                 handler.sendbuffer = _sendbuffer;
876                                 listeners.onconnect(handler);
877                                 -- If there was data with the incoming packet, handle it now.
878                                 if #handler:bufferqueue() > 0 then
879                                         return _sendbuffer();
880                                 end
881                         end
882                 end
883         end
884         return handler, socket
885 end
886
887 local addclient = function( address, port, listeners, pattern, sslctx )
888         local client, err = luasocket.tcp( )
889         if err then
890                 return nil, err
891         end
892         client:settimeout( 0 )
893         _, err = client:connect( address, port )
894         if err then -- try again
895                 local handler = wrapclient( client, address, port, listeners )
896         else
897                 wrapconnection( nil, listeners, client, address, port, "clientport", pattern, sslctx )
898         end
899 end
900
901 --// EXPERIMENTAL //--
902
903 ----------------------------------// BEGIN //--
904
905 use "setmetatable" ( _socketlist, { __mode = "k" } )
906 use "setmetatable" ( _readtimes, { __mode = "k" } )
907 use "setmetatable" ( _writetimes, { __mode = "k" } )
908
909 _timer = luasocket_gettime( )
910 _starttime = luasocket_gettime( )
911
912 addtimer( function( )
913                 local difftime = os_difftime( _currenttime - _starttime )
914                 if difftime > _checkinterval then
915                         _starttime = _currenttime
916                         for handler, timestamp in pairs( _writetimes ) do
917                                 if os_difftime( _currenttime - timestamp ) > _sendtimeout then
918                                         --_writetimes[ handler ] = nil
919                                         handler.disconnect( )( handler, "send timeout" )
920                                         handler:force_close()    -- forced disconnect
921                                 end
922                         end
923                         for handler, timestamp in pairs( _readtimes ) do
924                                 if os_difftime( _currenttime - timestamp ) > _readtimeout then
925                                         --_readtimes[ handler ] = nil
926                                         handler.disconnect( )( handler, "read timeout" )
927                                         handler:close( )        -- forced disconnect?
928                                 end
929                         end
930                 end
931         end
932 )
933
934 local function setlogger(new_logger)
935         local old_logger = log;
936         if new_logger then
937                 log = new_logger;
938         end
939         return old_logger;
940 end
941
942 ----------------------------------// PUBLIC INTERFACE //--
943
944 return {
945         _addtimer = addtimer,
946
947         addclient = addclient,
948         wrapclient = wrapclient,
949         
950         loop = loop,
951         link = link,
952         step = step,
953         stats = stats,
954         closeall = closeall,
955         addserver = addserver,
956         getserver = getserver,
957         setlogger = setlogger,
958         getsettings = getsettings,
959         setquitting = setquitting,
960         removeserver = removeserver,
961         get_backend = get_backend,
962         changesettings = changesettings,
963 }