net.server_select: Move socket timeout cleanup code out of a timer, into the select...
[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
14 local log, table_concat = require ("util.logger").init("socket"), table.concat;
15 local out_put = function (...) return log("debug", table_concat{...}); end
16 local out_error = function (...) return log("warn", table_concat{...}); end
17
18 ----------------------------------// DECLARATION //--
19
20 --// constants //--
21
22 local STAT_UNIT = 1 -- byte
23
24 --// lua functions //--
25
26 local type = use "type"
27 local pairs = use "pairs"
28 local ipairs = use "ipairs"
29 local tonumber = use "tonumber"
30 local tostring = use "tostring"
31
32 --// lua libs //--
33
34 local os = use "os"
35 local table = use "table"
36 local string = use "string"
37 local coroutine = use "coroutine"
38
39 --// lua lib methods //--
40
41 local os_difftime = os.difftime
42 local math_min = math.min
43 local math_huge = math.huge
44 local table_concat = table.concat
45 local string_sub = string.sub
46 local coroutine_wrap = coroutine.wrap
47 local coroutine_yield = coroutine.yield
48
49 --// extern libs //--
50
51 local luasec = use "ssl"
52 local luasocket = use "socket" or require "socket"
53 local luasocket_gettime = luasocket.gettime
54
55 --// extern lib methods //--
56
57 local ssl_wrap = ( luasec and luasec.wrap )
58 local socket_bind = luasocket.bind
59 local socket_sleep = luasocket.sleep
60 local socket_select = luasocket.select
61
62 --// functions //--
63
64 local id
65 local loop
66 local stats
67 local idfalse
68 local closeall
69 local addsocket
70 local addserver
71 local addtimer
72 local getserver
73 local wrapserver
74 local getsettings
75 local closesocket
76 local removesocket
77 local removeserver
78 local wrapconnection
79 local changesettings
80
81 --// tables //--
82
83 local _server
84 local _readlist
85 local _timerlist
86 local _sendlist
87 local _socketlist
88 local _closelist
89 local _readtimes
90 local _writetimes
91
92 --// simple data types //--
93
94 local _
95 local _readlistlen
96 local _sendlistlen
97 local _timerlistlen
98
99 local _sendtraffic
100 local _readtraffic
101
102 local _selecttimeout
103 local _sleeptime
104
105 local _starttime
106 local _currenttime
107
108 local _maxsendlen
109 local _maxreadlen
110
111 local _checkinterval
112 local _sendtimeout
113 local _readtimeout
114
115 local _timer
116
117 local _maxselectlen
118 local _maxfd
119
120 local _maxsslhandshake
121
122 ----------------------------------// DEFINITION //--
123
124 _server = { } -- key = port, value = table; list of listening servers
125 _readlist = { } -- array with sockets to read from
126 _sendlist = { } -- arrary with sockets to write to
127 _timerlist = { } -- array of timer functions
128 _socketlist = { } -- key = socket, value = wrapped socket (handlers)
129 _readtimes = { } -- key = handler, value = timestamp of last data reading
130 _writetimes = { } -- key = handler, value = timestamp of last data writing/sending
131 _closelist = { } -- handlers to close
132
133 _readlistlen = 0 -- length of readlist
134 _sendlistlen = 0 -- length of sendlist
135 _timerlistlen = 0 -- lenght of timerlist
136
137 _sendtraffic = 0 -- some stats
138 _readtraffic = 0
139
140 _selecttimeout = 1 -- timeout of socket.select
141 _sleeptime = 0 -- time to wait at the end of every loop
142
143 _maxsendlen = 51000 * 1024 -- max len of send buffer
144 _maxreadlen = 25000 * 1024 -- max len of read buffer
145
146 _checkinterval = 1200000 -- interval in secs to check idle clients
147 _sendtimeout = 60000 -- allowed send idle time in secs
148 _readtimeout = 6 * 60 * 60 -- allowed read idle time in secs
149
150 _maxfd = luasocket._SETSIZE or 1024 -- We should ignore this on Windows.  Perhaps by simply setting it to math.huge or something.
151 _maxselectlen = luasocket._SETSIZE or 1024 -- But this still applies on Windows
152
153 _maxsslhandshake = 30 -- max handshake round-trips
154
155 ----------------------------------// PRIVATE //--
156
157 wrapserver = function( listeners, socket, ip, serverport, pattern, sslctx ) -- this function wraps a server -- FIXME Make sure FD < _maxfd
158
159         if socket:getfd() >= _maxfd then
160                 out_error("server.lua: Disallowed FD number: "..socket:getfd())
161                 socket:close()
162                 return nil, "fd-too-large"
163         end
164
165         local connections = 0
166
167         local dispatch, disconnect = listeners.onconnect, listeners.ondisconnect
168
169         local accept = socket.accept
170
171         --// public methods of the object //--
172
173         local handler = { }
174
175         handler.shutdown = function( ) end
176
177         handler.ssl = function( )
178                 return sslctx ~= nil
179         end
180         handler.sslctx = function( )
181                 return sslctx
182         end
183         handler.remove = function( )
184                 connections = connections - 1
185                 if handler then
186                         handler.resume( )
187                 end
188         end
189         handler.close = function()
190                 socket:close( )
191                 _sendlistlen = removesocket( _sendlist, socket, _sendlistlen )
192                 _readlistlen = removesocket( _readlist, socket, _readlistlen )
193                 _server[ip..":"..serverport] = nil;
194                 _socketlist[ socket ] = nil
195                 handler = nil
196                 socket = nil
197                 --mem_free( )
198                 out_put "server.lua: closed server handler and removed sockets from list"
199         end
200         handler.pause = function( hard )
201                 if not handler.paused then
202                         _readlistlen = removesocket( _readlist, socket, _readlistlen )
203                         if hard then
204                                 _socketlist[ socket ] = nil
205                                 socket:close( )
206                                 socket = nil;
207                         end
208                         handler.paused = true;
209                 end
210         end
211         handler.resume = function( )
212                 if handler.paused then
213                         if not socket then
214                                 socket = socket_bind( ip, serverport );
215                                 socket:settimeout( 0 )
216                         end
217                         _readlistlen = addsocket(_readlist, socket, _readlistlen)
218                         _socketlist[ socket ] = handler
219                         handler.paused = false;
220                 end
221         end
222         handler.ip = function( )
223                 return ip
224         end
225         handler.serverport = function( )
226                 return serverport
227         end
228         handler.socket = function( )
229                 return socket
230         end
231         handler.readbuffer = function( )
232                 if _readlistlen >= _maxselectlen or _sendlistlen >= _maxselectlen then
233                         handler.pause( )
234                         out_put( "server.lua: refused new client connection: server full" )
235                         return false
236                 end
237                 local client, err = accept( socket )    -- try to accept
238                 if client then
239                         local ip, clientport = client:getpeername( )
240                         local handler, client, err = wrapconnection( handler, listeners, client, ip, serverport, clientport, pattern, sslctx ) -- wrap new client socket
241                         if err then -- error while wrapping ssl socket
242                                 return false
243                         end
244                         connections = connections + 1
245                         out_put( "server.lua: accepted new client connection from ", tostring(ip), ":", tostring(clientport), " to ", tostring(serverport))
246                         if dispatch then
247                                 return dispatch( handler );
248                         end
249                         return;
250                 elseif err then -- maybe timeout or something else
251                         out_put( "server.lua: error with new client connection: ", tostring(err) )
252                         return false
253                 end
254         end
255         return handler
256 end
257
258 wrapconnection = function( server, listeners, socket, ip, serverport, clientport, pattern, sslctx ) -- this function wraps a client to a handler object
259
260         if socket:getfd() >= _maxfd then
261                 out_error("server.lua: Disallowed FD number: "..socket:getfd()) -- PROTIP: Switch to libevent
262                 socket:close( ) -- Should we send some kind of error here?
263                 server.pause( )
264                 return nil, nil, "fd-too-large"
265         end
266         socket:settimeout( 0 )
267
268         --// local import of socket methods //--
269
270         local send
271         local receive
272         local shutdown
273
274         --// private closures of the object //--
275
276         local ssl
277
278         local dispatch = listeners.onincoming
279         local status = listeners.onstatus
280         local disconnect = listeners.ondisconnect
281         local drain = listeners.ondrain
282
283         local bufferqueue = { } -- buffer array
284         local bufferqueuelen = 0        -- end of buffer array
285
286         local toclose
287         local fatalerror
288         local needtls
289
290         local bufferlen = 0
291
292         local noread = false
293         local nosend = false
294
295         local sendtraffic, readtraffic = 0, 0
296
297         local maxsendlen = _maxsendlen
298         local maxreadlen = _maxreadlen
299
300         --// public methods of the object //--
301
302         local handler = bufferqueue -- saves a table ^_^
303
304         handler.dispatch = function( )
305                 return dispatch
306         end
307         handler.disconnect = function( )
308                 return disconnect
309         end
310         handler.setlistener = function( self, listeners )
311                 dispatch = listeners.onincoming
312                 disconnect = listeners.ondisconnect
313                 status = listeners.onstatus
314                 drain = listeners.ondrain
315         end
316         handler.getstats = function( )
317                 return readtraffic, sendtraffic
318         end
319         handler.ssl = function( )
320                 return ssl
321         end
322         handler.sslctx = function ( )
323                 return sslctx
324         end
325         handler.send = function( _, data, i, j )
326                 return send( socket, data, i, j )
327         end
328         handler.receive = function( pattern, prefix )
329                 return receive( socket, pattern, prefix )
330         end
331         handler.shutdown = function( pattern )
332                 return shutdown( socket, pattern )
333         end
334         handler.setoption = function (self, option, value)
335                 if socket.setoption then
336                         return socket:setoption(option, value);
337                 end
338                 return false, "setoption not implemented";
339         end
340         handler.force_close = function ( self, err )
341                 if bufferqueuelen ~= 0 then
342                         out_put("server.lua: discarding unwritten data for ", tostring(ip), ":", tostring(clientport))
343                         bufferqueuelen = 0;
344                 end
345                 return self:close(err);
346         end
347         handler.close = function( self, err )
348                 if not handler then return true; end
349                 _readlistlen = removesocket( _readlist, socket, _readlistlen )
350                 _readtimes[ handler ] = nil
351                 if bufferqueuelen ~= 0 then
352                         handler.sendbuffer() -- Try now to send any outstanding data
353                         if bufferqueuelen ~= 0 then -- Still not empty, so we'll try again later
354                                 if handler then
355                                         handler.write = nil -- ... but no further writing allowed
356                                 end
357                                 toclose = true
358                                 return false
359                         end
360                 end
361                 if socket then
362                         _ = shutdown and shutdown( socket )
363                         socket:close( )
364                         _sendlistlen = removesocket( _sendlist, socket, _sendlistlen )
365                         _socketlist[ socket ] = nil
366                         socket = nil
367                 else
368                         out_put "server.lua: socket already closed"
369                 end
370                 if handler then
371                         _writetimes[ handler ] = nil
372                         _closelist[ handler ] = nil
373                         local _handler = handler;
374                         handler = nil
375                         if disconnect then
376                                 disconnect(_handler, err or false);
377                                 disconnect = nil
378                         end
379                 end
380                 if server then
381                         server.remove( )
382                 end
383                 out_put "server.lua: closed client handler and removed socket from list"
384                 return true
385         end
386         handler.ip = function( )
387                 return ip
388         end
389         handler.serverport = function( )
390                 return serverport
391         end
392         handler.clientport = function( )
393                 return clientport
394         end
395         local write = function( self, data )
396                 bufferlen = bufferlen + #data
397                 if bufferlen > maxsendlen then
398                         _closelist[ handler ] = "send buffer exceeded"   -- cannot close the client at the moment, have to wait to the end of the cycle
399                         handler.write = idfalse -- dont write anymore
400                         return false
401                 elseif socket and not _sendlist[ socket ] then
402                         _sendlistlen = addsocket(_sendlist, socket, _sendlistlen)
403                 end
404                 bufferqueuelen = bufferqueuelen + 1
405                 bufferqueue[ bufferqueuelen ] = data
406                 if handler then
407                         _writetimes[ handler ] = _writetimes[ handler ] or _currenttime
408                 end
409                 return true
410         end
411         handler.write = write
412         handler.bufferqueue = function( self )
413                 return bufferqueue
414         end
415         handler.socket = function( self )
416                 return socket
417         end
418         handler.set_mode = function( self, new )
419                 pattern = new or pattern
420                 return pattern
421         end
422         handler.set_send = function ( self, newsend )
423                 send = newsend or send
424                 return send
425         end
426         handler.bufferlen = function( self, readlen, sendlen )
427                 maxsendlen = sendlen or maxsendlen
428                 maxreadlen = readlen or maxreadlen
429                 return bufferlen, maxreadlen, maxsendlen
430         end
431         --TODO: Deprecate
432         handler.lock_read = function (self, switch)
433                 if switch == true then
434                         local tmp = _readlistlen
435                         _readlistlen = removesocket( _readlist, socket, _readlistlen )
436                         _readtimes[ handler ] = nil
437                         if _readlistlen ~= tmp then
438                                 noread = true
439                         end
440                 elseif switch == false then
441                         if noread then
442                                 noread = false
443                                 _readlistlen = addsocket(_readlist, socket, _readlistlen)
444                                 _readtimes[ handler ] = _currenttime
445                         end
446                 end
447                 return noread
448         end
449         handler.pause = function (self)
450                 return self:lock_read(true);
451         end
452         handler.resume = function (self)
453                 return self:lock_read(false);
454         end
455         handler.lock = function( self, switch )
456                 handler.lock_read (switch)
457                 if switch == true then
458                         handler.write = idfalse
459                         local tmp = _sendlistlen
460                         _sendlistlen = removesocket( _sendlist, socket, _sendlistlen )
461                         _writetimes[ handler ] = nil
462                         if _sendlistlen ~= tmp then
463                                 nosend = true
464                         end
465                 elseif switch == false then
466                         handler.write = write
467                         if nosend then
468                                 nosend = false
469                                 write( "" )
470                         end
471                 end
472                 return noread, nosend
473         end
474         local _readbuffer = function( ) -- this function reads data
475                 local buffer, err, part = receive( socket, pattern )    -- receive buffer with "pattern"
476                 if not err or (err == "wantread" or err == "timeout") then -- received something
477                         local buffer = buffer or part or ""
478                         local len = #buffer
479                         if len > maxreadlen then
480                                 handler:close( "receive buffer exceeded" )
481                                 return false
482                         end
483                         local count = len * STAT_UNIT
484                         readtraffic = readtraffic + count
485                         _readtraffic = _readtraffic + count
486                         _readtimes[ handler ] = _currenttime
487                         --out_put( "server.lua: read data '", buffer:gsub("[^%w%p ]", "."), "', error: ", err )
488                         return dispatch( handler, buffer, err )
489                 else    -- connections was closed or fatal error
490                         out_put( "server.lua: client ", tostring(ip), ":", tostring(clientport), " read error: ", tostring(err) )
491                         fatalerror = true
492                         _ = handler and handler:force_close( err )
493                         return false
494                 end
495         end
496         local _sendbuffer = function( ) -- this function sends data
497                 local succ, err, byte, buffer, count;
498                 if socket then
499                         buffer = table_concat( bufferqueue, "", 1, bufferqueuelen )
500                         succ, err, byte = send( socket, buffer, 1, bufferlen )
501                         count = ( succ or byte or 0 ) * STAT_UNIT
502                         sendtraffic = sendtraffic + count
503                         _sendtraffic = _sendtraffic + count
504                         for i = bufferqueuelen,1,-1 do
505                                 bufferqueue[ i ] = nil
506                         end
507                         --out_put( "server.lua: sended '", buffer, "', bytes: ", tostring(succ), ", error: ", tostring(err), ", part: ", tostring(byte), ", to: ", tostring(ip), ":", tostring(clientport) )
508                 else
509                         succ, err, count = false, "unexpected close", 0;
510                 end
511                 if succ then    -- sending succesful
512                         bufferqueuelen = 0
513                         bufferlen = 0
514                         _sendlistlen = removesocket( _sendlist, socket, _sendlistlen ) -- delete socket from writelist
515                         _writetimes[ handler ] = nil
516                         if drain then
517                                 drain(handler)
518                         end
519                         _ = needtls and handler:starttls(nil)
520                         _ = toclose and handler:force_close( )
521                         return true
522                 elseif byte and ( err == "timeout" or err == "wantwrite" ) then -- want write
523                         buffer = string_sub( buffer, byte + 1, bufferlen ) -- new buffer
524                         bufferqueue[ 1 ] = buffer        -- insert new buffer in queue
525                         bufferqueuelen = 1
526                         bufferlen = bufferlen - byte
527                         _writetimes[ handler ] = _currenttime
528                         return true
529                 else    -- connection was closed during sending or fatal error
530                         out_put( "server.lua: client ", tostring(ip), ":", tostring(clientport), " write error: ", tostring(err) )
531                         fatalerror = true
532                         _ = handler and handler:force_close( err )
533                         return false
534                 end
535         end
536
537         -- Set the sslctx
538         local handshake;
539         function handler.set_sslctx(self, new_sslctx)
540                 sslctx = new_sslctx;
541                 local read, wrote
542                 handshake = coroutine_wrap( function( client ) -- create handshake coroutine
543                                 local err
544                                 for i = 1, _maxsslhandshake do
545                                         _sendlistlen = ( wrote and removesocket( _sendlist, client, _sendlistlen ) ) or _sendlistlen
546                                         _readlistlen = ( read and removesocket( _readlist, client, _readlistlen ) ) or _readlistlen
547                                         read, wrote = nil, nil
548                                         _, err = client:dohandshake( )
549                                         if not err then
550                                                 out_put( "server.lua: ssl handshake done" )
551                                                 handler.readbuffer = _readbuffer        -- when handshake is done, replace the handshake function with regular functions
552                                                 handler.sendbuffer = _sendbuffer
553                                                 _ = status and status( handler, "ssl-handshake-complete" )
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 ) -- 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 {
770                 select_timeout = _selecttimeout;
771                 select_sleep_time = _sleeptime;
772                 max_send_buffer_size = _maxsendlen;
773                 max_receive_buffer_size = _maxreadlen;
774                 select_idle_check_interval = _checkinterval;
775                 send_timeout = _sendtimeout;
776                 read_timeout = _readtimeout;
777                 max_connections = _maxselectlen;
778                 max_ssl_handshake_roundtrips = _maxsslhandshake;
779                 highest_allowed_fd = _maxfd;
780         }
781 end
782
783 changesettings = function( new )
784         if type( new ) ~= "table" then
785                 return nil, "invalid settings table"
786         end
787         _selecttimeout = tonumber( new.select_timeout ) or _selecttimeout
788         _sleeptime = tonumber( new.select_sleep_time ) or _sleeptime
789         _maxsendlen = tonumber( new.max_send_buffer_size ) or _maxsendlen
790         _maxreadlen = tonumber( new.max_receive_buffer_size ) or _maxreadlen
791         _checkinterval = tonumber( new.select_idle_check_interval ) or _checkinterval
792         _sendtimeout = tonumber( new.send_timeout ) or _sendtimeout
793         _readtimeout = tonumber( new.read_timeout ) or _readtimeout
794         _maxselectlen = new.max_connections or _maxselectlen
795         _maxsslhandshake = new.max_ssl_handshake_roundtrips or _maxsslhandshake
796         _maxfd = new.highest_allowed_fd or _maxfd
797         return true
798 end
799
800 addtimer = function( listener )
801         if type( listener ) ~= "function" then
802                 return nil, "invalid listener function"
803         end
804         _timerlistlen = _timerlistlen + 1
805         _timerlist[ _timerlistlen ] = listener
806         return true
807 end
808
809 stats = function( )
810         return _readtraffic, _sendtraffic, _readlistlen, _sendlistlen, _timerlistlen
811 end
812
813 local quitting;
814
815 local function setquitting(quit)
816         quitting = not not quit;
817 end
818
819 loop = function(once) -- this is the main loop of the program
820         if quitting then return "quitting"; end
821         if once then quitting = "once"; end
822         local next_timer_time = math_huge;
823         repeat
824                 local read, write, err = socket_select( _readlist, _sendlist, math_min(_selecttimeout, next_timer_time) )
825                 for i, socket in ipairs( write ) do -- send data waiting in writequeues
826                         local handler = _socketlist[ socket ]
827                         if handler then
828                                 handler.sendbuffer( )
829                         else
830                                 closesocket( socket )
831                                 out_put "server.lua: found no handler and closed socket (writelist)"    -- this should not happen
832                         end
833                 end
834                 for i, socket in ipairs( read ) do -- receive data
835                         local handler = _socketlist[ socket ]
836                         if handler then
837                                 handler.readbuffer( )
838                         else
839                                 closesocket( socket )
840                                 out_put "server.lua: found no handler and closed socket (readlist)" -- this can happen
841                         end
842                 end
843                 for handler, err in pairs( _closelist ) do
844                         handler.disconnect( )( handler, err )
845                         handler:force_close()    -- forced disconnect
846                         _closelist[ handler ] = nil;
847                 end
848                 _currenttime = luasocket_gettime( )
849
850                 local difftime = os_difftime( _currenttime - _starttime )
851                 if difftime > _checkinterval then
852                         _starttime = _currenttime
853                         for handler, timestamp in pairs( _writetimes ) do
854                                 if os_difftime( _currenttime - timestamp ) > _sendtimeout then
855                                         --_writetimes[ handler ] = nil
856                                         handler.disconnect( )( handler, "send timeout" )
857                                         handler:force_close()    -- forced disconnect
858                                 end
859                         end
860                         for handler, timestamp in pairs( _readtimes ) do
861                                 if os_difftime( _currenttime - timestamp ) > _readtimeout then
862                                         --_readtimes[ handler ] = nil
863                                         handler.disconnect( )( handler, "read timeout" )
864                                         handler:close( )        -- forced disconnect?
865                                 end
866                         end
867                 end
868
869                 if _currenttime - _timer >= math_min(next_timer_time, 1) then
870                         next_timer_time = math_huge;
871                         for i = 1, _timerlistlen do
872                                 local t = _timerlist[ i ]( _currenttime ) -- fire timers
873                                 if t then next_timer_time = math_min(next_timer_time, t); end
874                         end
875                         _timer = _currenttime
876                 else
877                         next_timer_time = next_timer_time - (_currenttime - _timer);
878                 end
879                 socket_sleep( _sleeptime ) -- wait some time
880                 --collectgarbage( )
881         until quitting;
882         if once and quitting == "once" then quitting = nil; return; end
883         return "quitting"
884 end
885
886 local function step()
887         return loop(true);
888 end
889
890 local function get_backend()
891         return "select";
892 end
893
894 --// EXPERIMENTAL //--
895
896 local wrapclient = function( socket, ip, serverport, listeners, pattern, sslctx )
897         local handler, socket, err = wrapconnection( nil, listeners, socket, ip, serverport, "clientport", pattern, sslctx )
898         if not handler then return nil, err end
899         _socketlist[ socket ] = handler
900         if not sslctx then
901                 _sendlistlen = addsocket(_sendlist, socket, _sendlistlen)
902                 if listeners.onconnect then
903                         -- When socket is writeable, call onconnect
904                         local _sendbuffer = handler.sendbuffer;
905                         handler.sendbuffer = function ()
906                                 _sendlistlen = removesocket( _sendlist, socket, _sendlistlen );
907                                 handler.sendbuffer = _sendbuffer;
908                                 listeners.onconnect(handler);
909                                 -- If there was data with the incoming packet, handle it now.
910                                 if #handler:bufferqueue() > 0 then
911                                         return _sendbuffer();
912                                 end
913                         end
914                 end
915         end
916         return handler, socket
917 end
918
919 local addclient = function( address, port, listeners, pattern, sslctx )
920         local client, err = luasocket.tcp( )
921         if err then
922                 return nil, err
923         end
924         client:settimeout( 0 )
925         _, err = client:connect( address, port )
926         if err then -- try again
927                 local handler = wrapclient( client, address, port, listeners )
928         else
929                 wrapconnection( nil, listeners, client, address, port, "clientport", pattern, sslctx )
930         end
931 end
932
933 --// EXPERIMENTAL //--
934
935 ----------------------------------// BEGIN //--
936
937 use "setmetatable" ( _socketlist, { __mode = "k" } )
938 use "setmetatable" ( _readtimes, { __mode = "k" } )
939 use "setmetatable" ( _writetimes, { __mode = "k" } )
940
941 _timer = luasocket_gettime( )
942 _starttime = luasocket_gettime( )
943
944 local function setlogger(new_logger)
945         local old_logger = log;
946         if new_logger then
947                 log = new_logger;
948         end
949         return old_logger;
950 end
951
952 ----------------------------------// PUBLIC INTERFACE //--
953
954 return {
955         _addtimer = addtimer,
956
957         addclient = addclient,
958         wrapclient = wrapclient,
959         
960         loop = loop,
961         link = link,
962         step = step,
963         stats = stats,
964         closeall = closeall,
965         addserver = addserver,
966         getserver = getserver,
967         setlogger = setlogger,
968         getsettings = getsettings,
969         setquitting = setquitting,
970         removeserver = removeserver,
971         get_backend = get_backend,
972         changesettings = changesettings,
973 }