net/server.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 tostring = use "tostring"
36
local collectgarbage = use "collectgarbage"
37
 
38
--// lua libs //--
39
 
40
local os = use "os"
41
local table = use "table"
42
local string = use "string"
43
local coroutine = use "coroutine"
44
 
45
--// lua lib methods //--
46
 
47
local os_time = os.time
48
local os_difftime = os.difftime
49
local table_concat = table.concat
50
local table_remove = table.remove
51
local string_len = string.len
52
local string_sub = string.sub
53
local coroutine_wrap = coroutine.wrap
54
local coroutine_yield = coroutine.yield
55
 
56
--// extern libs //--
57
 
58
local luasec = use "ssl"
59
local luasocket = use "socket" or require "socket"
60
 
61
--// extern lib methods //--
62
 
63
local ssl_wrap = ( luasec and luasec.wrap )
64
local socket_bind = luasocket.bind
65
local socket_sleep = luasocket.sleep
66
local socket_select = luasocket.select
67
local ssl_newcontext = ( luasec and luasec.newcontext )
68
 
69
--// functions //--
70
 
71
local id
72
local loop
73
local stats
74
local idfalse
75
local addtimer
76
local closeall
77
local addserver
78
local getserver
79
local wrapserver
80
local getsettings
81
local closesocket
82
local removesocket
83
local removeserver
84
local changetimeout
85
local wrapconnection
86
local changesettings
87
 
88
--// tables //--
89
 
90
local _server
91
local _readlist
92
local _timerlist
93
local _sendlist
94
local _socketlist
95
local _closelist
96
local _readtimes
97
local _writetimes
98
 
99
--// simple data types //--
100
 
101
local _
102
local _readlistlen
103
local _sendlistlen
104
local _timerlistlen
105
 
106
local _sendtraffic
107
local _readtraffic
108
 
109
local _selecttimeout
110
local _sleeptime
111
 
112
local _starttime
113
local _currenttime
114
 
115
local _maxsendlen
116
local _maxreadlen
117
 
118
local _checkinterval
119
local _sendtimeout
120
local _readtimeout
121
 
122
local _cleanqueue
123
 
124
local _timer
125
 
126
local _maxclientsperserver
127
 
128
----------------------------------// DEFINITION //--
129
 
130
_server = { } -- key = port, value = table; list of listening servers
131
_readlist = { } -- array with sockets to read from
132
_sendlist = { } -- arrary with sockets to write to
133
_timerlist = { } -- array of timer functions
134
_socketlist = { } -- key = socket, value = wrapped socket (handlers)
135
_readtimes = { } -- key = handler, value = timestamp of last data reading
136
_writetimes = { } -- key = handler, value = timestamp of last data writing/sending
137
_closelist = { } -- handlers to close
138
 
139
_readlistlen = 0 -- length of readlist
140
_sendlistlen = 0 -- length of sendlist
141
_timerlistlen = 0 -- lenght of timerlist
142
 
143
_sendtraffic = 0 -- some stats
144
_readtraffic = 0
145
 
146
_selecttimeout = 1 -- timeout of socket.select
147
_sleeptime = 0 -- time to wait at the end of every loop
148
 
149
_maxsendlen = 51000 * 1024 -- max len of send buffer
150
_maxreadlen = 25000 * 1024 -- max len of read buffer
151
 
152
_checkinterval = 1200000 -- interval in secs to check idle clients
153
_sendtimeout = 60000 -- allowed send idle time in secs
154
_readtimeout = 6 * 60 * 60 -- allowed read idle time in secs
155
 
156
_cleanqueue = false -- clean bufferqueue after using
157
 
158
_maxclientsperserver = 1000
159
 
160
_maxsslhandshake = 30 -- max handshake round-trips
161
 
162
----------------------------------// PRIVATE //--
163
 
164
wrapserver = function( listeners, socket, ip, serverport, pattern, sslctx, maxconnections ) -- this function wraps a server
165
 
166
	maxconnections = maxconnections or _maxclientsperserver
167
 
168
	local connections = 0
169
 
170
	local dispatch, disconnect = listeners.onconnect or 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
	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
			_writetimes[ handler ] = nil
483
			if drain then
484
				drain(handler)
485
			end
486
			_ = needtls and handler:starttls(nil)
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)
568
				if _sslctx then
569
					sslctx = _sslctx;
570
					handler:set_sslctx(sslctx);
571
				end
572
				if bufferqueuelen > 0 then
573
					out_put "server.lua: we need to do tls, but delaying until send buffer empty"
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
	return handler, socket
627
end
628
 
629
id = function( )
630
end
631
 
632
idfalse = function( )
633
	return false
634
end
635
 
636
addsocket = function( list, socket, len )
637
	if not list[ socket ] then
638
		len = len + 1
639
		list[ len ] = socket
640
		list[ socket ] = len
641
	end
642
	return len;
643
end
644
 
645
removesocket = function( list, socket, len )	-- this function removes sockets from a list ( copied from copas )
646
	local pos = list[ socket ]
647
	if pos then
648
		list[ socket ] = nil
649
		local last = list[ len ]
650
		list[ len ] = nil
651
		if last ~= socket then
652
			list[ last ] = pos
653
			list[ pos ] = last
654
		end
655
		return len - 1
656
	end
657
	return len
658
end
659
 
660
closesocket = function( socket )
661
	_sendlistlen = removesocket( _sendlist, socket, _sendlistlen )
662
	_readlistlen = removesocket( _readlist, socket, _readlistlen )
663
	_socketlist[ socket ] = nil
664
	socket:close( )
665
	--mem_free( )
666
end
667
 
668
local function link(sender, receiver, buffersize)
669
	sender:set_mode(buffersize);
670
	local sender_locked;
671
	local _sendbuffer = receiver.sendbuffer;
672
	function receiver.sendbuffer()
673
		_sendbuffer();
674
		if sender_locked and receiver.bufferlen() < buffersize then
675
			sender:lock_read(false); -- Unlock now
676
			sender_locked = nil;
677
		end
678
	end
679
	
680
	local _readbuffer = sender.readbuffer;
681
	function sender.readbuffer()
682
		_readbuffer();
683
		if not sender_locked and receiver.bufferlen() >= buffersize then
684
			sender_locked = true;
685
			sender:lock_read(true);
686
		end
687
	end
688
end
689
 
690
----------------------------------// PUBLIC //--
691
 
692
addserver = function( addr, port, listeners, pattern, sslctx ) -- this function provides a way for other scripts to reg a server
693
	local err
694
	if type( listeners ) ~= "table" then
695
		err = "invalid listener table"
696
	end
697
	if type( port ) ~= "number" or not ( port >= 0 and port <= 65535 ) then
698
		err = "invalid port"
699
	elseif _server[ port ] then
700
		err = "listeners on port '" .. port .. "' already exist"
701
	elseif sslctx and not luasec then
702
		err = "luasec not found"
703
	end
704
	if err then
705
		out_error( "server.lua, port ", port, ": ", err )
706
		return nil, err
707
	end
708
	addr = addr or "*"
709
	local server, err = socket_bind( addr, port )
710
	if err then
711
		out_error( "server.lua, port ", port, ": ", err )
712
		return nil, err
713
	end
714
	local handler, err = wrapserver( listeners, server, addr, port, pattern, sslctx, _maxclientsperserver ) -- wrap new server socket
715
	if not handler then
716
		server:close( )
717
		return nil, err
718
	end
719
	server:settimeout( 0 )
720
	_readlistlen = addsocket(_readlist, server, _readlistlen)
721
	_server[ port ] = handler
722
	_socketlist[ server ] = handler
723
	out_put( "server.lua: new "..(sslctx and "ssl " or "").."server listener on '", addr, ":", port, "'" )
724
	return handler
725
end
726
 
727
getserver = function ( port )
728
	return _server[ port ];
729
end
730
 
731
removeserver = function( port )
732
	local handler = _server[ port ]
733
	if not handler then
734
		return nil, "no server found on port '" .. tostring( port ) .. "'"
735
	end
736
	handler:close( )
737
	_server[ port ] = nil
738
	return true
739
end
740
 
741
closeall = function( )
742
	for _, handler in pairs( _socketlist ) do
743
		handler:close( )
744
		_socketlist[ _ ] = nil
745
	end
746
	_readlistlen = 0
747
	_sendlistlen = 0
748
	_timerlistlen = 0
749
	_server = { }
750
	_readlist = { }
751
	_sendlist = { }
752
	_timerlist = { }
753
	_socketlist = { }
754
	--mem_free( )
755
end
756
 
757
getsettings = function( )
758
	return	_selecttimeout, _sleeptime, _maxsendlen, _maxreadlen, _checkinterval, _sendtimeout, _readtimeout, _cleanqueue, _maxclientsperserver, _maxsslhandshake
759
end
760
 
761
changesettings = function( new )
762
	if type( new ) ~= "table" then
763
		return nil, "invalid settings table"
764
	end
765
	_selecttimeout = tonumber( new.timeout ) or _selecttimeout
766
	_sleeptime = tonumber( new.sleeptime ) or _sleeptime
767
	_maxsendlen = tonumber( new.maxsendlen ) or _maxsendlen
768
	_maxreadlen = tonumber( new.maxreadlen ) or _maxreadlen
769
	_checkinterval = tonumber( new.checkinterval ) or _checkinterval
770
	_sendtimeout = tonumber( new.sendtimeout ) or _sendtimeout
771
	_readtimeout = tonumber( new.readtimeout ) or _readtimeout
772
	_cleanqueue = new.cleanqueue
773
	_maxclientsperserver = new._maxclientsperserver or _maxclientsperserver
774
	_maxsslhandshake = new._maxsslhandshake or _maxsslhandshake
775
	return true
776
end
777
 
778
addtimer = function( listener )
779
	if type( listener ) ~= "function" then
780
		return nil, "invalid listener function"
781
	end
782
	_timerlistlen = _timerlistlen + 1
783
	_timerlist[ _timerlistlen ] = listener
784
	return true
785
end
786
 
787
stats = function( )
788
	return _readtraffic, _sendtraffic, _readlistlen, _sendlistlen, _timerlistlen
789
end
790
 
791
local dontstop = true; -- thinking about tomorrow, ...
792
 
793
setquitting = function (quit)
794
	dontstop = not quit;
795
	return;
796
end
797
 
798
loop = function( ) -- this is the main loop of the program
799
	while dontstop do
800
		local read, write, err = socket_select( _readlist, _sendlist, _selecttimeout )
801
		for i, socket in ipairs( write ) do -- send data waiting in writequeues
802
			local handler = _socketlist[ socket ]
803
			if handler then
804
				handler.sendbuffer( )
805
			else
806
				closesocket( socket )
807
				out_put "server.lua: found no handler and closed socket (writelist)"	-- this should not happen
808
			end
809
		end
810
		for i, socket in ipairs( read ) do -- receive data
811
			local handler = _socketlist[ socket ]
812
			if handler then
813
				handler.readbuffer( )
814
			else
815
				closesocket( socket )
816
				out_put "server.lua: found no handler and closed socket (readlist)" -- this can happen
817
			end
818
		end
819
		for handler, err in pairs( _closelist ) do
820
			handler.disconnect( )( handler, err )
821
			handler:close( true )	 -- forced disconnect
822
		end
823
		clean( _closelist )
824
		_currenttime = os_time( )
825
		if os_difftime( _currenttime - _timer ) >= 1 then
826
			for i = 1, _timerlistlen do
827
				_timerlist[ i ]( _currenttime ) -- fire timers
828
			end
829
			_timer = _currenttime
830
		end
831
		socket_sleep( _sleeptime ) -- wait some time
832
		--collectgarbage( )
833
	end
834
	return "quitting"
835
end
836
 
837
local function get_backend()
838
	return "select";
839
end
840
 
841
--// EXPERIMENTAL //--
842
 
843
local wrapclient = function( socket, ip, serverport, listeners, pattern, sslctx )
844
	local handler = wrapconnection( nil, listeners, socket, ip, serverport, "clientport", pattern, sslctx )
845
	_socketlist[ socket ] = handler
846
	_sendlistlen = addsocket(_sendlist, socket, _sendlistlen)
847
	if listeners.onconnect then
848
		-- When socket is writeable, call onconnect
849
		local _sendbuffer = handler.sendbuffer;
850
		handler.sendbuffer = function ()
851
			listeners.onconnect(handler);
852
			handler.sendbuffer = _sendbuffer;
853
			-- If there was data with the incoming packet, handle it now.
854
			if #handler:bufferqueue() > 0 then
855
				return _sendbuffer();
856
			end
857
		end
858
	end
859
	return handler, socket
860
end
861
 
862
local addclient = function( address, port, listeners, pattern, sslctx )
863
	local client, err = luasocket.tcp( )
864
	if err then
865
		return nil, err
866
	end
867
	client:settimeout( 0 )
868
	_, err = client:connect( address, port )
869
	if err then -- try again
870
		local handler = wrapclient( client, address, port, listeners )
871
	else
872
		wrapconnection( nil, listeners, client, address, port, "clientport", pattern, sslctx )
873
	end
874
end
875
 
876
--// EXPERIMENTAL //--
877
 
878
----------------------------------// BEGIN //--
879
 
880
use "setmetatable" ( _socketlist, { __mode = "k" } )
881
use "setmetatable" ( _readtimes, { __mode = "k" } )
882
use "setmetatable" ( _writetimes, { __mode = "k" } )
883
 
884
_timer = os_time( )
885
_starttime = os_time( )
886
 
887
addtimer( function( )
888
		local difftime = os_difftime( _currenttime - _starttime )
889
		if difftime > _checkinterval then
890
			_starttime = _currenttime
891
			for handler, timestamp in pairs( _writetimes ) do
892
				if os_difftime( _currenttime - timestamp ) > _sendtimeout then
893
					--_writetimes[ handler ] = nil
894
					handler.disconnect( )( handler, "send timeout" )
895
					handler:close( true )	 -- forced disconnect
896
				end
897
			end
898
			for handler, timestamp in pairs( _readtimes ) do
899
				if os_difftime( _currenttime - timestamp ) > _readtimeout then
900
					--_readtimes[ handler ] = nil
901
					handler.disconnect( )( handler, "read timeout" )
902
					handler:close( )	-- forced disconnect?
903
				end
904
			end
905
		end
906
	end
907
)
908
 
909
local function setlogger(new_logger)
910
	local old_logger = log;
911
	if new_logger then
912
		log = new_logger;
913
	end
914
	return old_logger;
915
end
916
 
917
----------------------------------// PUBLIC INTERFACE //--
918
 
919
return {
920
 
921
	addclient = addclient,
922
	wrapclient = wrapclient,
923
	
924
	loop = loop,
925
	link = link,
926
	stats = stats,
927
	closeall = closeall,
928
	addtimer = addtimer,
929
	addserver = addserver,
930
	getserver = getserver,
931
	setlogger = setlogger,
932
	getsettings = getsettings,
933
	setquitting = setquitting,
934
	removeserver = removeserver,
935
	get_backend = get_backend,
936
	changesettings = changesettings,
937
}