PageRenderTime 32ms CodeModel.GetById 2ms app.highlight 23ms RepoModel.GetById 1ms app.codeStats 0ms

/net/server_select.lua

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