net/server_select.lua

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