net.server_select: *Major* whitespace refactoring to meet Prosody's coding style...
[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 sslctx then -- ssl?
536                 handler:set_sslctx(sslctx);
537                 out_put("server.lua: ", "starting ssl handshake")
538                 local err
539                 socket, err = ssl_wrap( socket, sslctx )        -- wrap socket
540                 if err then
541                         out_put( "server.lua: ssl error: ", tostring(err) )
542                         --mem_free( )
543                         return nil, nil, err    -- fatal error
544                 end
545                 socket:settimeout( 0 )
546                 handler.readbuffer = handshake
547                 handler.sendbuffer = handshake
548                 handshake( socket ) -- do handshake
549                 if not socket then
550                         return nil, nil, "ssl handshake failed";
551                 end
552         else
553                 local sslctx;
554                 handler.starttls = function( self, _sslctx, now )
555                         if _sslctx then
556                                 sslctx = _sslctx;
557                                 handler:set_sslctx(sslctx);
558                         end
559                         if not now then
560                                 out_put "server.lua: we need to do tls, but delaying until later"
561                                 needtls = true
562                                 return
563                         end
564                         out_put( "server.lua: attempting to start tls on " .. tostring( socket ) )
565                         local oldsocket, err = socket
566                         socket, err = ssl_wrap( socket, sslctx )        -- wrap socket
567                         --out_put( "server.lua: sslwrapped socket is " .. tostring( socket ) )
568                         if err then
569                                 out_put( "server.lua: error while starting tls on client: ", tostring(err) )
570                                 return nil, err -- fatal error
571                         end
572                         
573                         socket:settimeout( 0 )
574
575                         -- add the new socket to our system
576
577                         send = socket.send
578                         receive = socket.receive
579                         shutdown = id
580
581                         _socketlist[ socket ] = handler
582                         _readlistlen = addsocket(_readlist, socket, _readlistlen)
583
584                         -- remove traces of the old socket
585
586                         _readlistlen = removesocket( _readlist, oldsocket, _readlistlen )
587                         _sendlistlen = removesocket( _sendlist, oldsocket, _sendlistlen )
588                         _socketlist[ oldsocket ] = nil
589
590                         handler.starttls = nil
591                         needtls = nil
592                                 
593                         -- Secure now
594                         ssl = true
595
596                         handler.readbuffer = handshake
597                         handler.sendbuffer = handshake
598                         handshake( socket ) -- do handshake
599                 end
600                 handler.readbuffer = _readbuffer
601                 handler.sendbuffer = _sendbuffer
602         end
603
604         send = socket.send
605         receive = socket.receive
606         shutdown = ( ssl and id ) or socket.shutdown
607
608         _socketlist[ socket ] = handler
609         _readlistlen = addsocket(_readlist, socket, _readlistlen)
610
611         return handler, socket
612 end
613
614 id = function( )
615 end
616
617 idfalse = function( )
618         return false
619 end
620
621 addsocket = function( list, socket, len )
622         if not list[ socket ] then
623                 len = len + 1
624                 list[ len ] = socket
625                 list[ socket ] = len
626         end
627         return len;
628 end
629
630 removesocket = function( list, socket, len )    -- this function removes sockets from a list ( copied from copas )
631         local pos = list[ socket ]
632         if pos then
633                 list[ socket ] = nil
634                 local last = list[ len ]
635                 list[ len ] = nil
636                 if last ~= socket then
637                         list[ last ] = pos
638                         list[ pos ] = last
639                 end
640                 return len - 1
641         end
642         return len
643 end
644
645 closesocket = function( socket )
646         _sendlistlen = removesocket( _sendlist, socket, _sendlistlen )
647         _readlistlen = removesocket( _readlist, socket, _readlistlen )
648         _socketlist[ socket ] = nil
649         socket:close( )
650         --mem_free( )
651 end
652
653 ----------------------------------// PUBLIC //--
654
655 addserver = function( addr, port, listeners, pattern, sslctx ) -- this function provides a way for other scripts to reg a server
656         local err
657         if type( listeners ) ~= "table" then
658                 err = "invalid listener table"
659         end
660         if not type( port ) == "number" or not ( port >= 0 and port <= 65535 ) then
661                 err = "invalid port"
662         elseif _server[ port ] then
663                 err = "listeners on port '" .. port .. "' already exist"
664         elseif sslctx and not luasec then
665                 err = "luasec not found"
666         end
667         if err then
668                 out_error( "server.lua, port ", port, ": ", err )
669                 return nil, err
670         end
671         addr = addr or "*"
672         local server, err = socket_bind( addr, port )
673         if err then
674                 out_error( "server.lua, port ", port, ": ", err )
675                 return nil, err
676         end
677         local handler, err = wrapserver( listeners, server, addr, port, pattern, sslctx, _maxclientsperserver ) -- wrap new server socket
678         if not handler then
679                 server:close( )
680                 return nil, err
681         end
682         server:settimeout( 0 )
683         _readlistlen = addsocket(_readlist, server, _readlistlen)
684         _server[ port ] = handler
685         _socketlist[ server ] = handler
686         out_put( "server.lua: new "..(sslctx and "ssl " or "").."server listener on '", addr, ":", port, "'" )
687         return handler
688 end
689
690 getserver = function ( port )
691         return _server[ port ];
692 end
693
694 removeserver = function( port )
695         local handler = _server[ port ]
696         if not handler then
697                 return nil, "no server found on port '" .. tostring( port ) .. "'"
698         end
699         handler:close( )
700         _server[ port ] = nil
701         return true
702 end
703
704 closeall = function( )
705         for _, handler in pairs( _socketlist ) do
706                 handler:close( )
707                 _socketlist[ _ ] = nil
708         end
709         _readlistlen = 0
710         _sendlistlen = 0
711         _timerlistlen = 0
712         _server = { }
713         _readlist = { }
714         _sendlist = { }
715         _timerlist = { }
716         _socketlist = { }
717         --mem_free( )
718 end
719
720 getsettings = function( )
721         return  _selecttimeout, _sleeptime, _maxsendlen, _maxreadlen, _checkinterval, _sendtimeout, _readtimeout, _cleanqueue, _maxclientsperserver, _maxsslhandshake
722 end
723
724 changesettings = function( new )
725         if type( new ) ~= "table" then
726                 return nil, "invalid settings table"
727         end
728         _selecttimeout = tonumber( new.timeout ) or _selecttimeout
729         _sleeptime = tonumber( new.sleeptime ) or _sleeptime
730         _maxsendlen = tonumber( new.maxsendlen ) or _maxsendlen
731         _maxreadlen = tonumber( new.maxreadlen ) or _maxreadlen
732         _checkinterval = tonumber( new.checkinterval ) or _checkinterval
733         _sendtimeout = tonumber( new.sendtimeout ) or _sendtimeout
734         _readtimeout = tonumber( new.readtimeout ) or _readtimeout
735         _cleanqueue = new.cleanqueue
736         _maxclientsperserver = new._maxclientsperserver or _maxclientsperserver
737         _maxsslhandshake = new._maxsslhandshake or _maxsslhandshake
738         return true
739 end
740
741 addtimer = function( listener )
742         if type( listener ) ~= "function" then
743                 return nil, "invalid listener function"
744         end
745         _timerlistlen = _timerlistlen + 1
746         _timerlist[ _timerlistlen ] = listener
747         return true
748 end
749
750 stats = function( )
751         return _readtraffic, _sendtraffic, _readlistlen, _sendlistlen, _timerlistlen
752 end
753
754 local dontstop = true; -- thinking about tomorrow, ...
755
756 setquitting = function (quit)
757         dontstop = not quit;
758         return;
759 end
760
761 loop = function( ) -- this is the main loop of the program
762         while dontstop do
763                 local read, write, err = socket_select( _readlist, _sendlist, _selecttimeout )
764                 for i, socket in ipairs( write ) do -- send data waiting in writequeues
765                         local handler = _socketlist[ socket ]
766                         if handler then
767                                 handler.sendbuffer( )
768                         else
769                                 closesocket( socket )
770                                 out_put "server.lua: found no handler and closed socket (writelist)"    -- this should not happen
771                         end
772                 end
773                 for i, socket in ipairs( read ) do -- receive data
774                         local handler = _socketlist[ socket ]
775                         if handler then
776                                 handler.readbuffer( )
777                         else
778                                 closesocket( socket )
779                                 out_put "server.lua: found no handler and closed socket (readlist)" -- this can happen
780                         end
781                 end
782                 for handler, err in pairs( _closelist ) do
783                         handler.disconnect( )( handler, err )
784                         handler:close( true )    -- forced disconnect
785                 end
786                 clean( _closelist )
787                 _currenttime = os_time( )
788                 if os_difftime( _currenttime - _timer ) >= 1 then
789                         for i = 1, _timerlistlen do
790                                 _timerlist[ i ]( _currenttime ) -- fire timers
791                         end
792                         _timer = _currenttime
793                 end
794                 socket_sleep( _sleeptime ) -- wait some time
795                 --collectgarbage( )
796         end
797         return "quitting"
798 end
799
800 local function get_backend()
801         return "select";
802 end
803
804 --// EXPERIMENTAL //--
805
806 local wrapclient = function( socket, ip, serverport, listeners, pattern, sslctx )
807         local handler = wrapconnection( nil, listeners, socket, ip, serverport, "clientport", pattern, sslctx )
808         _socketlist[ socket ] = handler
809         _sendlistlen = addsocket(_sendlist, socket, _sendlistlen)
810         return handler, socket
811 end
812
813 local addclient = function( address, port, listeners, pattern, sslctx )
814         local client, err = luasocket.tcp( )
815         if err then
816                 return nil, err
817         end
818         client:settimeout( 0 )
819         _, err = client:connect( address, port )
820         if err then -- try again
821                 local handler = wrapclient( client, address, port, listeners )
822         else
823                 wrapconnection( nil, listeners, client, address, port, "clientport", pattern, sslctx )
824         end
825 end
826
827 --// EXPERIMENTAL //--
828
829 ----------------------------------// BEGIN //--
830
831 use "setmetatable" ( _socketlist, { __mode = "k" } )
832 use "setmetatable" ( _readtimes, { __mode = "k" } )
833 use "setmetatable" ( _writetimes, { __mode = "k" } )
834
835 _timer = os_time( )
836 _starttime = os_time( )
837
838 addtimer( function( )
839                 local difftime = os_difftime( _currenttime - _starttime )
840                 if difftime > _checkinterval then
841                         _starttime = _currenttime
842                         for handler, timestamp in pairs( _writetimes ) do
843                                 if os_difftime( _currenttime - timestamp ) > _sendtimeout then
844                                         --_writetimes[ handler ] = nil
845                                         handler.disconnect( )( handler, "send timeout" )
846                                         handler:close( true )    -- forced disconnect
847                                 end
848                         end
849                         for handler, timestamp in pairs( _readtimes ) do
850                                 if os_difftime( _currenttime - timestamp ) > _readtimeout then
851                                         --_readtimes[ handler ] = nil
852                                         handler.disconnect( )( handler, "read timeout" )
853                                         handler:close( )        -- forced disconnect?
854                                 end
855                         end
856                 end
857         end
858 )
859
860 local function setlogger(new_logger)
861         local old_logger = log;
862         if new_logger then
863                 log = new_logger;
864         end
865         return old_logger;
866 end
867
868 ----------------------------------// PUBLIC INTERFACE //--
869
870 return {
871
872         addclient = addclient,
873         wrapclient = wrapclient,
874         
875         loop = loop,
876         stats = stats,
877         closeall = closeall,
878         addtimer = addtimer,
879         addserver = addserver,
880         getserver = getserver,
881         setlogger = setlogger,
882         getsettings = getsettings,
883         setquitting = setquitting,
884         removeserver = removeserver,
885         get_backend = get_backend,
886         changesettings = changesettings,
887 }