mod_tls: Merged duplicate 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-2009 Matthew Wild, Waqas Hussain
6 --
7
8 -- // wrapping luadch stuff // --
9
10 local use = function( what )
11         return _G[ what ]
12 end
13 local clean = function( tbl )
14         for i, k in pairs( tbl ) do
15                 tbl[ i ] = nil
16         end
17 end
18
19 local log, table_concat = require ("util.logger").init("socket"), table.concat;
20 local out_put = function (...) return log("debug", table_concat{...}); end
21 local out_error = function (...) return log("warn", table_concat{...}); end
22 local mem_free = collectgarbage
23
24 ----------------------------------// DECLARATION //--
25
26 --// constants //--
27
28 local STAT_UNIT = 1 -- byte
29
30 --// lua functions //--
31
32 local type = use "type"
33 local pairs = use "pairs"
34 local ipairs = use "ipairs"
35 local tostring = use "tostring"
36 local collectgarbage = use "collectgarbage"
37
38 --// lua libs //--
39
40 local os = use "os"
41 local table = use "table"
42 local string = use "string"
43 local coroutine = use "coroutine"
44
45 --// lua lib methods //--
46
47 local os_time = os.time
48 local os_difftime = os.difftime
49 local table_concat = table.concat
50 local table_remove = table.remove
51 local string_len = string.len
52 local string_sub = string.sub
53 local coroutine_wrap = coroutine.wrap
54 local coroutine_yield = coroutine.yield
55
56 --// extern libs //--
57
58 local luasec = select( 2, pcall( require, "ssl" ) )
59 local luasocket = require "socket"
60
61 --// extern lib methods //--
62
63 local ssl_wrap = ( luasec and luasec.wrap )
64 local socket_bind = luasocket.bind
65 local socket_sleep = luasocket.sleep
66 local socket_select = luasocket.select
67 local ssl_newcontext = ( luasec and luasec.newcontext )
68
69 --// functions //--
70
71 local id
72 local loop
73 local stats
74 local idfalse
75 local addtimer
76 local closeall
77 local addserver
78 local getserver
79 local wrapserver
80 local getsettings
81 local closesocket
82 local removesocket
83 local removeserver
84 local changetimeout
85 local wrapconnection
86 local changesettings
87
88 --// tables //--
89
90 local _server
91 local _readlist
92 local _timerlist
93 local _sendlist
94 local _socketlist
95 local _closelist
96 local _readtimes
97 local _writetimes
98
99 --// simple data types //--
100
101 local _
102 local _readlistlen
103 local _sendlistlen
104 local _timerlistlen
105
106 local _sendtraffic
107 local _readtraffic
108
109 local _selecttimeout
110 local _sleeptime
111
112 local _starttime
113 local _currenttime
114
115 local _maxsendlen
116 local _maxreadlen
117
118 local _checkinterval
119 local _sendtimeout
120 local _readtimeout
121
122 local _cleanqueue
123
124 local _timer
125
126 local _maxclientsperserver
127
128 ----------------------------------// DEFINITION //--
129
130 _server = { } -- key = port, value = table; list of listening servers
131 _readlist = { } -- array with sockets to read from
132 _sendlist = { } -- arrary with sockets to write to
133 _timerlist = { } -- array of timer functions
134 _socketlist = { } -- key = socket, value = wrapped socket (handlers)
135 _readtimes = { } -- key = handler, value = timestamp of last data reading
136 _writetimes = { } -- key = handler, value = timestamp of last data writing/sending
137 _closelist = { } -- handlers to close
138
139 _readlistlen = 0 -- length of readlist
140 _sendlistlen = 0 -- length of sendlist
141 _timerlistlen = 0 -- lenght of timerlist
142
143 _sendtraffic = 0 -- some stats
144 _readtraffic = 0
145
146 _selecttimeout = 1 -- timeout of socket.select
147 _sleeptime = 0 -- time to wait at the end of every loop
148
149 _maxsendlen = 51000 * 1024 -- max len of send buffer
150 _maxreadlen = 25000 * 1024 -- max len of read buffer
151
152 _checkinterval = 1200000 -- interval in secs to check idle clients
153 _sendtimeout = 60000 -- allowed send idle time in secs
154 _readtimeout = 6 * 60 * 60 -- allowed read idle time in secs
155
156 _cleanqueue = false -- clean bufferqueue after using
157
158 _maxclientsperserver = 1000
159
160 _maxsslhandshake = 30 -- max handshake round-trips
161
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
256         local bufferqueue = { } -- buffer array
257         local bufferqueuelen = 0        -- end of buffer array
258
259         local toclose
260         local fatalerror
261         local needtls
262
263         local bufferlen = 0
264
265         local noread = false
266         local nosend = false
267
268         local sendtraffic, readtraffic = 0, 0
269
270         local maxsendlen = _maxsendlen
271         local maxreadlen = _maxreadlen
272
273         --// public methods of the object //--
274
275         local handler = bufferqueue -- saves a table ^_^
276
277         handler.dispatch = function( )
278                 return dispatch
279         end
280         handler.disconnect = function( )
281                 return disconnect
282         end
283         handler.setlistener = function( self, listeners )
284                 dispatch = listeners.onincoming
285                 disconnect = listeners.ondisconnect
286                 status = listeners.onstatus
287         end
288         handler.getstats = function( )
289                 return readtraffic, sendtraffic
290         end
291         handler.ssl = function( )
292                 return ssl
293         end
294         handler.sslctx = function ( )
295                 return sslctx
296         end
297         handler.send = function( _, data, i, j )
298                 return send( socket, data, i, j )
299         end
300         handler.receive = function( pattern, prefix )
301                 return receive( socket, pattern, prefix )
302         end
303         handler.shutdown = function( pattern )
304                 return shutdown( socket, pattern )
305         end
306         handler.setoption = function (self, option, value)
307                 if socket.setoption then
308                         return socket:setoption(option, value);
309                 end
310                 return false, "setoption not implemented";
311         end
312         handler.close = function( self, forced )
313                 if not handler then return true; end
314                 _readlistlen = removesocket( _readlist, socket, _readlistlen )
315                 _readtimes[ handler ] = nil
316                 if bufferqueuelen ~= 0 then
317                         if not ( forced or fatalerror ) then
318                                 handler.sendbuffer( )
319                                 if bufferqueuelen ~= 0 then -- try again...
320                                         if handler then
321                                                 handler.write = nil -- ... but no further writing allowed
322                                         end
323                                         toclose = true
324                                         return false
325                                 end
326                         else
327                                 send( socket, table_concat( bufferqueue, "", 1, bufferqueuelen ), 1, bufferlen )        -- forced send
328                         end
329                 end
330                 if socket then
331                         _ = shutdown and shutdown( socket )
332                         socket:close( )
333                         _sendlistlen = removesocket( _sendlist, socket, _sendlistlen )
334                         _socketlist[ socket ] = nil
335                         socket = nil
336                 else
337                         out_put "server.lua: socket already closed"
338                 end
339                 if handler then
340                         _writetimes[ handler ] = nil
341                         _closelist[ handler ] = nil
342                         handler = nil
343                 end
344         if server then
345                 server.remove( )
346         end
347                 out_put "server.lua: closed client handler and removed socket from list"
348                 return true
349         end
350         handler.ip = function( )
351                 return ip
352         end
353         handler.serverport = function( )
354                 return serverport
355         end
356         handler.clientport = function( )
357                 return clientport
358         end
359         local write = function( self, data )
360                 bufferlen = bufferlen + string_len( data )
361                 if bufferlen > maxsendlen then
362                         _closelist[ handler ] = "send buffer exceeded"   -- cannot close the client at the moment, have to wait to the end of the cycle
363                         handler.write = idfalse -- dont write anymore
364                         return false
365                 elseif socket and not _sendlist[ socket ] then
366                         _sendlistlen = addsocket(_sendlist, socket, _sendlistlen)
367                 end
368                 bufferqueuelen = bufferqueuelen + 1
369                 bufferqueue[ bufferqueuelen ] = data
370                 if handler then
371                         _writetimes[ handler ] = _writetimes[ handler ] or _currenttime
372                 end
373                 return true
374         end
375         handler.write = write
376         handler.bufferqueue = function( self )
377                 return bufferqueue
378         end
379         handler.socket = function( self )
380                 return socket
381         end
382         handler.pattern = function( self, new )
383                 pattern = new or pattern
384                 return pattern
385         end
386         handler.set_send = function ( self, newsend )
387                 send = newsend or send
388                 return send
389         end
390         handler.bufferlen = function( self, readlen, sendlen )
391                 maxsendlen = sendlen or maxsendlen
392                 maxreadlen = readlen or maxreadlen
393                 return bufferlen, maxreadlen, maxsendlen
394         end
395         handler.lock_read = function (self, switch)
396                 if switch == true then
397                         local tmp = _readlistlen
398                         _readlistlen = removesocket( _readlist, socket, _readlistlen )
399                         _readtimes[ handler ] = nil
400                         if _readlistlen ~= tmp then
401                                 noread = true
402                         end
403                 elseif switch == false then
404                         if noread then
405                                 noread = false
406                                 _readlistlen = addsocket(_readlist, socket, _readlistlen)
407                                 _readtimes[ handler ] = _currenttime
408                         end
409                 end
410                 return noread
411         end
412         handler.lock = function( self, switch )
413                 handler.lock_read (switch)
414                 if switch == true then
415                         handler.write = idfalse
416                         local tmp = _sendlistlen
417                         _sendlistlen = removesocket( _sendlist, socket, _sendlistlen )
418                         _writetimes[ handler ] = nil
419                         if _sendlistlen ~= tmp then
420                                 nosend = true
421                         end
422                 elseif switch == false then
423                         handler.write = write
424                         if nosend then
425                                 nosend = false
426                                 write( "" )
427                         end
428                 end
429                 return noread, nosend
430         end
431         local _readbuffer = function( ) -- this function reads data
432                 local buffer, err, part = receive( socket, pattern )    -- receive buffer with "pattern"
433                 if not err or (err == "wantread" or err == "timeout") or string_len(part) > 0 then -- received something
434                         local buffer = buffer or part or ""
435                         local len = string_len( buffer )
436                         if len > maxreadlen then
437                                 disconnect( handler, "receive buffer exceeded" )
438                                 handler.close( true )
439                                 return false
440                         end
441                         local count = len * STAT_UNIT
442                         readtraffic = readtraffic + count
443                         _readtraffic = _readtraffic + count
444                         _readtimes[ handler ] = _currenttime
445                         --out_put( "server.lua: read data '", buffer:gsub("[^%w%p ]", "."), "', error: ", err )
446                         return dispatch( handler, buffer, err )
447                 else    -- connections was closed or fatal error
448                         out_put( "server.lua: client ", tostring(ip), ":", tostring(clientport), " read error: ", tostring(err) )
449                         fatalerror = true
450                         disconnect( handler, err )
451                 _ = handler and handler.close( )
452                         return false
453                 end
454         end
455         local _sendbuffer = function( ) -- this function sends data
456                 local succ, err, byte, buffer, count;
457                 local count;
458                 if socket then
459                         buffer = table_concat( bufferqueue, "", 1, bufferqueuelen )
460                         succ, err, byte = send( socket, buffer, 1, bufferlen )
461                         count = ( succ or byte or 0 ) * STAT_UNIT
462                         sendtraffic = sendtraffic + count
463                         _sendtraffic = _sendtraffic + count
464                         _ = _cleanqueue and clean( bufferqueue )
465                         --out_put( "server.lua: sended '", buffer, "', bytes: ", tostring(succ), ", error: ", tostring(err), ", part: ", tostring(byte), ", to: ", tostring(ip), ":", tostring(clientport) )
466                 else
467                         succ, err, count = false, "closed", 0;
468                 end
469                 if succ then    -- sending succesful
470                         bufferqueuelen = 0
471                         bufferlen = 0
472                         _sendlistlen = removesocket( _sendlist, socket, _sendlistlen ) -- delete socket from writelist
473                         _ = needtls and handler:starttls(nil, true)
474                         _writetimes[ handler ] = nil
475                 _ = toclose and handler.close( )
476                         return true
477                 elseif byte and ( err == "timeout" or err == "wantwrite" ) then -- want write
478                         buffer = string_sub( buffer, byte + 1, bufferlen ) -- new buffer
479                         bufferqueue[ 1 ] = buffer        -- insert new buffer in queue
480                         bufferqueuelen = 1
481                         bufferlen = bufferlen - byte
482                         _writetimes[ handler ] = _currenttime
483                         return true
484                 else    -- connection was closed during sending or fatal error
485                         out_put( "server.lua: client ", tostring(ip), ":", tostring(clientport), " write error: ", tostring(err) )
486                         fatalerror = true
487                         disconnect( handler, err )
488                         _ = handler and handler.close( )
489                         return false
490                 end
491         end
492
493         -- Set the sslctx
494         local handshake;
495         function handler.set_sslctx(self, new_sslctx)
496                 ssl = true
497                 sslctx = new_sslctx;
498                 local wrote
499                 local read
500                 handshake = coroutine_wrap( function( client ) -- create handshake coroutine
501                                 local err
502                                 for i = 1, _maxsslhandshake do
503                                         _sendlistlen = ( wrote and removesocket( _sendlist, client, _sendlistlen ) ) or _sendlistlen
504                                         _readlistlen = ( read and removesocket( _readlist, client, _readlistlen ) ) or _readlistlen
505                                         read, wrote = nil, nil
506                                         _, err = client:dohandshake( )
507                                         if not err then
508                                                 out_put( "server.lua: ssl handshake done" )
509                                                 handler.readbuffer = _readbuffer        -- when handshake is done, replace the handshake function with regular functions
510                                                 handler.sendbuffer = _sendbuffer
511                                                 _ = status and status( handler, "ssl-handshake-complete" )
512                                                 _readlistlen = addsocket(_readlist, client, _readlistlen)
513                                                 return true
514                                         else
515                                                 out_put( "server.lua: error during ssl handshake: ", tostring(err) )
516                                                 if err == "wantwrite" and not wrote then
517                                                         _sendlistlen = addsocket(_sendlist, client, _sendlistlen)
518                                                         wrote = true
519                                                 elseif err == "wantread" and not read then
520                                                         _readlistlen = addsocket(_readlist, client, _readlistlen)
521                                                         read = true
522                                                 else
523                                                         break;
524                                                 end
525                                                 --coroutine_yield( handler, nil, err )   -- handshake not finished
526                                                 coroutine_yield( )
527                                         end
528                                 end
529                                 disconnect( handler, "ssl handshake failed" )
530                                 _ = handler and handler:close( true )    -- forced disconnect
531                                 return false    -- handshake failed
532                         end
533                 )
534         end
535         if luasec then
536                 if sslctx then -- ssl?
537                         handler:set_sslctx(sslctx);
538                         out_put("server.lua: ", "starting ssl handshake")
539                         local err
540                         socket, err = ssl_wrap( socket, sslctx )        -- wrap socket
541                         if err then
542                                 out_put( "server.lua: ssl error: ", tostring(err) )
543                                 --mem_free( )
544                                 return nil, nil, err    -- fatal error
545                         end
546                         socket:settimeout( 0 )
547                         handler.readbuffer = handshake
548                         handler.sendbuffer = handshake
549                         handshake( socket ) -- do handshake
550                         if not socket then
551                                 return nil, nil, "ssl handshake failed";
552                         end
553                 else
554                         local sslctx;
555                         handler.starttls = function( self, _sslctx, now )
556                                 if _sslctx then
557                                         sslctx = _sslctx;
558                                         handler:set_sslctx(sslctx);
559                                 end
560                                 if not now then
561                                         out_put "server.lua: we need to do tls, but delaying until later"
562                                         needtls = true
563                                         return
564                                 end
565                                 out_put( "server.lua: attempting to start tls on " .. tostring( socket ) )
566                                 local oldsocket, err = socket
567                                 socket, err = ssl_wrap( socket, sslctx )        -- wrap socket
568                                 --out_put( "server.lua: sslwrapped socket is " .. tostring( socket ) )
569                                 if err then
570                                         out_put( "server.lua: error while starting tls on client: ", tostring(err) )
571                                         return nil, err -- fatal error
572                                 end
573
574                                 socket:settimeout( 0 )
575         
576                                 -- add the new socket to our system
577         
578                                 send = socket.send
579                                 receive = socket.receive
580                                 shutdown = id
581
582                                 _socketlist[ socket ] = handler
583                                 _readlistlen = addsocket(_readlist, socket, _readlistlen)
584
585                                 -- remove traces of the old socket
586
587                                 _readlistlen = removesocket( _readlist, oldsocket, _readlistlen )
588                                 _sendlistlen = removesocket( _sendlist, oldsocket, _sendlistlen )
589                                 _socketlist[ oldsocket ] = nil
590
591                                 handler.starttls = nil
592                                 needtls = nil
593
594                                 -- Secure now
595                                 ssl = true
596
597                                 handler.readbuffer = handshake
598                                 handler.sendbuffer = handshake
599                                 handshake( socket ) -- do handshake
600                         end
601                         handler.readbuffer = _readbuffer
602                         handler.sendbuffer = _sendbuffer
603                 end
604         end
605
606         send = socket.send
607         receive = socket.receive
608         shutdown = ( ssl and id ) or socket.shutdown
609
610         _socketlist[ socket ] = handler
611         _readlistlen = addsocket(_readlist, socket, _readlistlen)
612
613         return handler, socket
614 end
615
616 id = function( )
617 end
618
619 idfalse = function( )
620         return false
621 end
622
623 addsocket = function( list, socket, len )
624         if not list[ socket ] then
625                 len = len + 1
626                 list[ len ] = socket
627                 list[ socket ] = len
628         end
629         return len;
630 end
631
632 removesocket = function( list, socket, len )    -- this function removes sockets from a list ( copied from copas )
633         local pos = list[ socket ]
634         if pos then
635                 list[ socket ] = nil
636                 local last = list[ len ]
637                 list[ len ] = nil
638                 if last ~= socket then
639                         list[ last ] = pos
640                         list[ pos ] = last
641                 end
642                 return len - 1
643         end
644         return len
645 end
646
647 closesocket = function( socket )
648         _sendlistlen = removesocket( _sendlist, socket, _sendlistlen )
649         _readlistlen = removesocket( _readlist, socket, _readlistlen )
650         _socketlist[ socket ] = nil
651         socket:close( )
652         --mem_free( )
653 end
654
655 ----------------------------------// PUBLIC //--
656
657 addserver = function( addr, port, listeners, pattern, sslctx ) -- this function provides a way for other scripts to reg a server
658         local err
659         if type( listeners ) ~= "table" then
660                 err = "invalid listener table"
661         end
662         if not type( port ) == "number" or not ( port >= 0 and port <= 65535 ) then
663                 err = "invalid port"
664         elseif _server[ port ] then
665                 err = "listeners on port '" .. port .. "' already exist"
666         elseif sslctx and not luasec then
667                 err = "luasec not found"
668         end
669         if err then
670                 out_error( "server.lua, port ", port, ": ", err )
671                 return nil, err
672         end
673         addr = addr or "*"
674         local server, err = socket_bind( addr, port )
675         if err then
676                 out_error( "server.lua, port ", port, ": ", err )
677                 return nil, err
678         end
679         local handler, err = wrapserver( listeners, server, addr, port, pattern, sslctx, _maxclientsperserver ) -- wrap new server socket
680         if not handler then
681                 server:close( )
682                 return nil, err
683         end
684         server:settimeout( 0 )
685         _readlistlen = addsocket(_readlist, server, _readlistlen)
686         _server[ port ] = handler
687         _socketlist[ server ] = handler
688         out_put( "server.lua: new "..(sslctx and "ssl " or "").."server listener on '", addr, ":", port, "'" )
689         return handler
690 end
691
692 getserver = function ( port )
693         return _server[ port ];
694 end
695
696 removeserver = function( port )
697         local handler = _server[ port ]
698         if not handler then
699                 return nil, "no server found on port '" .. tostring( port ) .. "'"
700         end
701         handler:close( )
702         _server[ port ] = nil
703         return true
704 end
705
706 closeall = function( )
707         for _, handler in pairs( _socketlist ) do
708                 handler:close( )
709                 _socketlist[ _ ] = nil
710         end
711         _readlistlen = 0
712         _sendlistlen = 0
713         _timerlistlen = 0
714         _server = { }
715         _readlist = { }
716         _sendlist = { }
717         _timerlist = { }
718         _socketlist = { }
719         --mem_free( )
720 end
721
722 getsettings = function( )
723         return  _selecttimeout, _sleeptime, _maxsendlen, _maxreadlen, _checkinterval, _sendtimeout, _readtimeout, _cleanqueue, _maxclientsperserver, _maxsslhandshake
724 end
725
726 changesettings = function( new )
727         if type( new ) ~= "table" then
728                 return nil, "invalid settings table"
729         end
730         _selecttimeout = tonumber( new.timeout ) or _selecttimeout
731         _sleeptime = tonumber( new.sleeptime ) or _sleeptime
732         _maxsendlen = tonumber( new.maxsendlen ) or _maxsendlen
733         _maxreadlen = tonumber( new.maxreadlen ) or _maxreadlen
734         _checkinterval = tonumber( new.checkinterval ) or _checkinterval
735         _sendtimeout = tonumber( new.sendtimeout ) or _sendtimeout
736         _readtimeout = tonumber( new.readtimeout ) or _readtimeout
737         _cleanqueue = new.cleanqueue
738         _maxclientsperserver = new._maxclientsperserver or _maxclientsperserver
739         _maxsslhandshake = new._maxsslhandshake or _maxsslhandshake
740         return true
741 end
742
743 addtimer = function( listener )
744         if type( listener ) ~= "function" then
745                 return nil, "invalid listener function"
746         end
747         _timerlistlen = _timerlistlen + 1
748         _timerlist[ _timerlistlen ] = listener
749         return true
750 end
751
752 stats = function( )
753         return _readtraffic, _sendtraffic, _readlistlen, _sendlistlen, _timerlistlen
754 end
755
756 local dontstop = true; -- thinking about tomorrow, ...
757
758 setquitting = function (quit)
759         dontstop = not quit;
760         return;
761 end
762
763 loop = function( ) -- this is the main loop of the program
764         while dontstop do
765                 local read, write, err = socket_select( _readlist, _sendlist, _selecttimeout )
766                 for i, socket in ipairs( write ) do -- send data waiting in writequeues
767                         local handler = _socketlist[ socket ]
768                         if handler then
769                                 handler.sendbuffer( )
770                         else
771                                 closesocket( socket )
772                                 out_put "server.lua: found no handler and closed socket (writelist)"    -- this should not happen
773                         end
774                 end
775                 for i, socket in ipairs( read ) do -- receive data
776                         local handler = _socketlist[ socket ]
777                         if handler then
778                                 handler.readbuffer( )
779                         else
780                                 closesocket( socket )
781                                 out_put "server.lua: found no handler and closed socket (readlist)" -- this can happen
782                         end
783                 end
784                 for handler, err in pairs( _closelist ) do
785                         handler.disconnect( )( handler, err )
786                         handler:close( true )    -- forced disconnect
787                 end
788                 clean( _closelist )
789                 _currenttime = os_time( )
790                 if os_difftime( _currenttime - _timer ) >= 1 then
791                         for i = 1, _timerlistlen do
792                                 _timerlist[ i ]( _currenttime ) -- fire timers
793                         end
794                         _timer = _currenttime
795                 end
796                 socket_sleep( _sleeptime ) -- wait some time
797                 --collectgarbage( )
798         end
799         return "quitting"
800 end
801
802 local function get_backend()
803         return "select";
804 end
805
806 --// EXPERIMENTAL //--
807
808 local wrapclient = function( socket, ip, serverport, listeners, pattern, sslctx )
809         local handler = wrapconnection( nil, listeners, socket, ip, serverport, "clientport", pattern, sslctx )
810         _socketlist[ socket ] = handler
811         _sendlistlen = addsocket(_sendlist, socket, _sendlistlen)
812         return handler, socket
813 end
814
815 local addclient = function( address, port, listeners, pattern, sslctx )
816         local client, err = luasocket.tcp( )
817         if err then
818                 return nil, err
819         end
820         client:settimeout( 0 )
821         _, err = client:connect( address, port )
822         if err then -- try again
823                 local handler = wrapclient( client, address, port, listeners )
824         else
825                 wrapconnection( nil, listeners, client, address, port, "clientport", pattern, sslctx )
826         end
827 end
828
829 --// EXPERIMENTAL //--
830
831 ----------------------------------// BEGIN //--
832
833 use "setmetatable" ( _socketlist, { __mode = "k" } )
834 use "setmetatable" ( _readtimes, { __mode = "k" } )
835 use "setmetatable" ( _writetimes, { __mode = "k" } )
836
837 _timer = os_time( )
838 _starttime = os_time( )
839
840 addtimer( function( )
841                 local difftime = os_difftime( _currenttime - _starttime )
842                 if difftime > _checkinterval then
843                         _starttime = _currenttime
844                         for handler, timestamp in pairs( _writetimes ) do
845                                 if os_difftime( _currenttime - timestamp ) > _sendtimeout then
846                                         --_writetimes[ handler ] = nil
847                                         handler.disconnect( )( handler, "send timeout" )
848                                         handler:close( true )    -- forced disconnect
849                                 end
850                         end
851                         for handler, timestamp in pairs( _readtimes ) do
852                                 if os_difftime( _currenttime - timestamp ) > _readtimeout then
853                                         --_readtimes[ handler ] = nil
854                                         handler.disconnect( )( handler, "read timeout" )
855                                         handler:close( )        -- forced disconnect?
856                                 end
857                         end
858                 end
859         end
860 )
861
862 local function setlogger(new_logger)
863         local old_logger = log;
864         if new_logger then
865                 log = new_logger;
866         end
867         return old_logger;
868 end
869
870 ----------------------------------// PUBLIC INTERFACE //--
871
872 return {
873
874         addclient = addclient,
875         wrapclient = wrapclient,
876         
877         loop = loop,
878         stats = stats,
879         closeall = closeall,
880         addtimer = addtimer,
881         addserver = addserver,
882         getserver = getserver,
883         setlogger = setlogger,
884         getsettings = getsettings,
885         setquitting = setquitting,
886         removeserver = removeserver,
887         get_backend = get_backend,
888         changesettings = changesettings,
889 }