Merge with 0.7
[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 = use "ssl"
59 local luasocket = use "socket" or require "socket"
60
61 --// extern lib methods //--
62
63 local ssl_wrap = ( luasec and luasec.wrap )
64 local socket_bind = luasocket.bind
65 local socket_sleep = luasocket.sleep
66 local socket_select = luasocket.select
67 local ssl_newcontext = ( luasec and luasec.newcontext )
68
69 --// functions //--
70
71 local id
72 local loop
73 local stats
74 local idfalse
75 local addtimer
76 local closeall
77 local addserver
78 local getserver
79 local wrapserver
80 local getsettings
81 local closesocket
82 local removesocket
83 local removeserver
84 local changetimeout
85 local wrapconnection
86 local changesettings
87
88 --// tables //--
89
90 local _server
91 local _readlist
92 local _timerlist
93 local _sendlist
94 local _socketlist
95 local _closelist
96 local _readtimes
97 local _writetimes
98
99 --// simple data types //--
100
101 local _
102 local _readlistlen
103 local _sendlistlen
104 local _timerlistlen
105
106 local _sendtraffic
107 local _readtraffic
108
109 local _selecttimeout
110 local _sleeptime
111
112 local _starttime
113 local _currenttime
114
115 local _maxsendlen
116 local _maxreadlen
117
118 local _checkinterval
119 local _sendtimeout
120 local _readtimeout
121
122 local _cleanqueue
123
124 local _timer
125
126 local _maxclientsperserver
127
128 ----------------------------------// DEFINITION //--
129
130 _server = { } -- key = port, value = table; list of listening servers
131 _readlist = { } -- array with sockets to read from
132 _sendlist = { } -- arrary with sockets to write to
133 _timerlist = { } -- array of timer functions
134 _socketlist = { } -- key = socket, value = wrapped socket (handlers)
135 _readtimes = { } -- key = handler, value = timestamp of last data reading
136 _writetimes = { } -- key = handler, value = timestamp of last data writing/sending
137 _closelist = { } -- handlers to close
138
139 _readlistlen = 0 -- length of readlist
140 _sendlistlen = 0 -- length of sendlist
141 _timerlistlen = 0 -- lenght of timerlist
142
143 _sendtraffic = 0 -- some stats
144 _readtraffic = 0
145
146 _selecttimeout = 1 -- timeout of socket.select
147 _sleeptime = 0 -- time to wait at the end of every loop
148
149 _maxsendlen = 51000 * 1024 -- max len of send buffer
150 _maxreadlen = 25000 * 1024 -- max len of read buffer
151
152 _checkinterval = 1200000 -- interval in secs to check idle clients
153 _sendtimeout = 60000 -- allowed send idle time in secs
154 _readtimeout = 6 * 60 * 60 -- allowed read idle time in secs
155
156 _cleanqueue = false -- clean bufferqueue after using
157
158 _maxclientsperserver = 1000
159
160 _maxsslhandshake = 30 -- max handshake round-trips
161
162 ----------------------------------// PRIVATE //--
163
164 wrapserver = function( listeners, socket, ip, serverport, pattern, sslctx, maxconnections ) -- this function wraps a server
165
166         maxconnections = maxconnections or _maxclientsperserver
167
168         local connections = 0
169
170         local dispatch, disconnect = listeners.onincoming, listeners.ondisconnect
171
172         local accept = socket.accept
173
174         --// public methods of the object //--
175
176         local handler = { }
177
178         handler.shutdown = function( ) end
179
180         handler.ssl = function( )
181                 return sslctx ~= nil
182         end
183         handler.sslctx = function( )
184                 return sslctx
185         end
186         handler.remove = function( )
187                 connections = connections - 1
188         end
189         handler.close = function( )
190                 for _, handler in pairs( _socketlist ) do
191                         if handler.serverport == serverport then
192                                 handler.disconnect( handler, "server closed" )
193                                 handler:close( true )
194                         end
195                 end
196                 socket:close( )
197                 _sendlistlen = removesocket( _sendlist, socket, _sendlistlen )
198                 _readlistlen = removesocket( _readlist, socket, _readlistlen )
199                 _socketlist[ socket ] = nil
200                 handler = nil
201                 socket = nil
202                 --mem_free( )
203                 out_put "server.lua: closed server handler and removed sockets from list"
204         end
205         handler.ip = function( )
206                 return ip
207         end
208         handler.serverport = function( )
209                 return serverport
210         end
211         handler.socket = function( )
212                 return socket
213         end
214         handler.readbuffer = function( )
215                 if connections > maxconnections then
216                         out_put( "server.lua: refused new client connection: server full" )
217                         return false
218                 end
219                 local client, err = accept( socket )    -- try to accept
220                 if client then
221                         local ip, clientport = client:getpeername( )
222                         client:settimeout( 0 )
223                         local handler, client, err = wrapconnection( handler, listeners, client, ip, serverport, clientport, pattern, sslctx ) -- wrap new client socket
224                         if err then -- error while wrapping ssl socket
225                                 return false
226                         end
227                         connections = connections + 1
228                         out_put( "server.lua: accepted new client connection from ", tostring(ip), ":", tostring(clientport), " to ", tostring(serverport))
229                         return dispatch( handler )
230                 elseif err then -- maybe timeout or something else
231                         out_put( "server.lua: error with new client connection: ", tostring(err) )
232                         return false
233                 end
234         end
235         return handler
236 end
237
238 wrapconnection = function( server, listeners, socket, ip, serverport, clientport, pattern, sslctx ) -- this function wraps a client to a handler object
239
240         socket:settimeout( 0 )
241
242         --// local import of socket methods //--
243
244         local send
245         local receive
246         local shutdown
247
248         --// private closures of the object //--
249
250         local ssl
251
252         local dispatch = listeners.onincoming
253         local status = listeners.onstatus
254         local disconnect = listeners.ondisconnect
255
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         else
605                 handler.readbuffer = _readbuffer
606                 handler.sendbuffer = _sendbuffer
607         end
608         send = socket.send
609         receive = socket.receive
610         shutdown = ( ssl and id ) or socket.shutdown
611
612         _socketlist[ socket ] = handler
613         _readlistlen = addsocket(_readlist, socket, _readlistlen)
614
615         return handler, socket
616 end
617
618 id = function( )
619 end
620
621 idfalse = function( )
622         return false
623 end
624
625 addsocket = function( list, socket, len )
626         if not list[ socket ] then
627                 len = len + 1
628                 list[ len ] = socket
629                 list[ socket ] = len
630         end
631         return len;
632 end
633
634 removesocket = function( list, socket, len )    -- this function removes sockets from a list ( copied from copas )
635         local pos = list[ socket ]
636         if pos then
637                 list[ socket ] = nil
638                 local last = list[ len ]
639                 list[ len ] = nil
640                 if last ~= socket then
641                         list[ last ] = pos
642                         list[ pos ] = last
643                 end
644                 return len - 1
645         end
646         return len
647 end
648
649 closesocket = function( socket )
650         _sendlistlen = removesocket( _sendlist, socket, _sendlistlen )
651         _readlistlen = removesocket( _readlist, socket, _readlistlen )
652         _socketlist[ socket ] = nil
653         socket:close( )
654         --mem_free( )
655 end
656
657 ----------------------------------// PUBLIC //--
658
659 addserver = function( addr, port, listeners, pattern, sslctx ) -- this function provides a way for other scripts to reg a server
660         local err
661         if type( listeners ) ~= "table" then
662                 err = "invalid listener table"
663         end
664         if not type( port ) == "number" or not ( port >= 0 and port <= 65535 ) then
665                 err = "invalid port"
666         elseif _server[ port ] then
667                 err = "listeners on port '" .. port .. "' already exist"
668         elseif sslctx and not luasec then
669                 err = "luasec not found"
670         end
671         if err then
672                 out_error( "server.lua, port ", port, ": ", err )
673                 return nil, err
674         end
675         addr = addr or "*"
676         local server, err = socket_bind( addr, port )
677         if err then
678                 out_error( "server.lua, port ", port, ": ", err )
679                 return nil, err
680         end
681         local handler, err = wrapserver( listeners, server, addr, port, pattern, sslctx, _maxclientsperserver ) -- wrap new server socket
682         if not handler then
683                 server:close( )
684                 return nil, err
685         end
686         server:settimeout( 0 )
687         _readlistlen = addsocket(_readlist, server, _readlistlen)
688         _server[ port ] = handler
689         _socketlist[ server ] = handler
690         out_put( "server.lua: new "..(sslctx and "ssl " or "").."server listener on '", addr, ":", port, "'" )
691         return handler
692 end
693
694 getserver = function ( port )
695         return _server[ port ];
696 end
697
698 removeserver = function( port )
699         local handler = _server[ port ]
700         if not handler then
701                 return nil, "no server found on port '" .. tostring( port ) .. "'"
702         end
703         handler:close( )
704         _server[ port ] = nil
705         return true
706 end
707
708 closeall = function( )
709         for _, handler in pairs( _socketlist ) do
710                 handler:close( )
711                 _socketlist[ _ ] = nil
712         end
713         _readlistlen = 0
714         _sendlistlen = 0
715         _timerlistlen = 0
716         _server = { }
717         _readlist = { }
718         _sendlist = { }
719         _timerlist = { }
720         _socketlist = { }
721         --mem_free( )
722 end
723
724 getsettings = function( )
725         return  _selecttimeout, _sleeptime, _maxsendlen, _maxreadlen, _checkinterval, _sendtimeout, _readtimeout, _cleanqueue, _maxclientsperserver, _maxsslhandshake
726 end
727
728 changesettings = function( new )
729         if type( new ) ~= "table" then
730                 return nil, "invalid settings table"
731         end
732         _selecttimeout = tonumber( new.timeout ) or _selecttimeout
733         _sleeptime = tonumber( new.sleeptime ) or _sleeptime
734         _maxsendlen = tonumber( new.maxsendlen ) or _maxsendlen
735         _maxreadlen = tonumber( new.maxreadlen ) or _maxreadlen
736         _checkinterval = tonumber( new.checkinterval ) or _checkinterval
737         _sendtimeout = tonumber( new.sendtimeout ) or _sendtimeout
738         _readtimeout = tonumber( new.readtimeout ) or _readtimeout
739         _cleanqueue = new.cleanqueue
740         _maxclientsperserver = new._maxclientsperserver or _maxclientsperserver
741         _maxsslhandshake = new._maxsslhandshake or _maxsslhandshake
742         return true
743 end
744
745 addtimer = function( listener )
746         if type( listener ) ~= "function" then
747                 return nil, "invalid listener function"
748         end
749         _timerlistlen = _timerlistlen + 1
750         _timerlist[ _timerlistlen ] = listener
751         return true
752 end
753
754 stats = function( )
755         return _readtraffic, _sendtraffic, _readlistlen, _sendlistlen, _timerlistlen
756 end
757
758 local dontstop = true; -- thinking about tomorrow, ...
759
760 setquitting = function (quit)
761         dontstop = not quit;
762         return;
763 end
764
765 loop = function( ) -- this is the main loop of the program
766         while dontstop do
767                 local read, write, err = socket_select( _readlist, _sendlist, _selecttimeout )
768                 for i, socket in ipairs( write ) do -- send data waiting in writequeues
769                         local handler = _socketlist[ socket ]
770                         if handler then
771                                 handler.sendbuffer( )
772                         else
773                                 closesocket( socket )
774                                 out_put "server.lua: found no handler and closed socket (writelist)"    -- this should not happen
775                         end
776                 end
777                 for i, socket in ipairs( read ) do -- receive data
778                         local handler = _socketlist[ socket ]
779                         if handler then
780                                 handler.readbuffer( )
781                         else
782                                 closesocket( socket )
783                                 out_put "server.lua: found no handler and closed socket (readlist)" -- this can happen
784                         end
785                 end
786                 for handler, err in pairs( _closelist ) do
787                         handler.disconnect( )( handler, err )
788                         handler:close( true )    -- forced disconnect
789                 end
790                 clean( _closelist )
791                 _currenttime = os_time( )
792                 if os_difftime( _currenttime - _timer ) >= 1 then
793                         for i = 1, _timerlistlen do
794                                 _timerlist[ i ]( _currenttime ) -- fire timers
795                         end
796                         _timer = _currenttime
797                 end
798                 socket_sleep( _sleeptime ) -- wait some time
799                 --collectgarbage( )
800         end
801         return "quitting"
802 end
803
804 local function get_backend()
805         return "select";
806 end
807
808 --// EXPERIMENTAL //--
809
810 local wrapclient = function( socket, ip, serverport, listeners, pattern, sslctx )
811         local handler = wrapconnection( nil, listeners, socket, ip, serverport, "clientport", pattern, sslctx )
812         _socketlist[ socket ] = handler
813         _sendlistlen = addsocket(_sendlist, socket, _sendlistlen)
814         return handler, socket
815 end
816
817 local addclient = function( address, port, listeners, pattern, sslctx )
818         local client, err = luasocket.tcp( )
819         if err then
820                 return nil, err
821         end
822         client:settimeout( 0 )
823         _, err = client:connect( address, port )
824         if err then -- try again
825                 local handler = wrapclient( client, address, port, listeners )
826         else
827                 wrapconnection( nil, listeners, client, address, port, "clientport", pattern, sslctx )
828         end
829 end
830
831 --// EXPERIMENTAL //--
832
833 ----------------------------------// BEGIN //--
834
835 use "setmetatable" ( _socketlist, { __mode = "k" } )
836 use "setmetatable" ( _readtimes, { __mode = "k" } )
837 use "setmetatable" ( _writetimes, { __mode = "k" } )
838
839 _timer = os_time( )
840 _starttime = os_time( )
841
842 addtimer( function( )
843                 local difftime = os_difftime( _currenttime - _starttime )
844                 if difftime > _checkinterval then
845                         _starttime = _currenttime
846                         for handler, timestamp in pairs( _writetimes ) do
847                                 if os_difftime( _currenttime - timestamp ) > _sendtimeout then
848                                         --_writetimes[ handler ] = nil
849                                         handler.disconnect( )( handler, "send timeout" )
850                                         handler:close( true )    -- forced disconnect
851                                 end
852                         end
853                         for handler, timestamp in pairs( _readtimes ) do
854                                 if os_difftime( _currenttime - timestamp ) > _readtimeout then
855                                         --_readtimes[ handler ] = nil
856                                         handler.disconnect( )( handler, "read timeout" )
857                                         handler:close( )        -- forced disconnect?
858                                 end
859                         end
860                 end
861         end
862 )
863
864 local function setlogger(new_logger)
865         local old_logger = log;
866         if new_logger then
867                 log = new_logger;
868         end
869         return old_logger;
870 end
871
872 ----------------------------------// PUBLIC INTERFACE //--
873
874 return {
875
876         addclient = addclient,
877         wrapclient = wrapclient,
878         
879         loop = loop,
880         stats = stats,
881         closeall = closeall,
882         addtimer = addtimer,
883         addserver = addserver,
884         getserver = getserver,
885         setlogger = setlogger,
886         getsettings = getsettings,
887         setquitting = setquitting,
888         removeserver = removeserver,
889         get_backend = get_backend,
890         changesettings = changesettings,
891 }