3 server.lua by blastbeat of the luadch project
5 re-used here under the MIT/X Consortium License
7 Modifications (C) 2008 Matthew Wild, Waqas Hussain
10 ----------------------------------// DECLARATION //--
14 local STAT_UNIT = 1 / ( 1024 * 1024 ) -- mb
16 --// lua functions //--
18 local function use( what ) return _G[ what ] end
20 local type = use "type"
21 local pairs = use "pairs"
22 local ipairs = use "ipairs"
23 local tostring = use "tostring"
24 local collectgarbage = use "collectgarbage"
28 local table = use "table"
29 local coroutine = use "coroutine"
31 --// lua lib methods //--
33 local table_concat = table.concat
34 local table_remove = table.remove
35 local string_sub = use'string'.sub
36 local coroutine_wrap = coroutine.wrap
37 local coroutine_yield = coroutine.yield
39 local out_put = function () end --print;
40 local out_error = print;
44 local luasec = select(2, pcall(require, "ssl"))
45 local luasocket = require "socket"
47 --// extern lib methods //--
49 local ssl_wrap = ( luasec and luasec.wrap )
50 local socket_bind = luasocket.bind
51 local socket_select = luasocket.select
52 local ssl_newcontext = ( luasec and luasec.newcontext )
76 --// simple data types //--
79 local readlen = 0 -- length of readlist
80 local writelen = 0 -- lenght of writelist
85 ----------------------------------// DEFINITION //--
87 listener = { } -- key = port, value = table
88 readlist = { } -- array with sockets to read from
89 writelist = { } -- arrary with sockets to write to
90 socketlist = { } -- key = socket, value = wrapped socket
94 return receivestat, sendstat
97 wrapserver = function( listener, socket, ip, serverport, mode, sslctx, wrapper_function ) -- this function wraps a server
99 local dispatch, disconnect = listener.listener, listener.disconnect -- dangerous
101 local wrapclient, err
103 out_put("Starting a new server on "..tostring(serverport).." with ssl: "..tostring(sslctx));
105 if not ssl_newcontext then
106 return nil, "luasec not found"
108 if type( sslctx ) ~= "table" then
109 out_error "server.lua: wrong server sslctx"
110 return nil, "wrong server sslctx"
112 sslctx, err = ssl_newcontext( sslctx )
114 err = err or "wrong sslctx parameters"
115 out_error( "server.lua: ", err )
120 if wrapper_function then
121 wrapclient = wrapper_function
123 wrapclient = wrapsslclient
125 wrapclient = wraptcpclient
128 local accept = socket.accept
129 local close = socket.close
131 --// public methods of the object //--
135 handler.shutdown = function( ) end
137 --[[handler.listener = function( data, err )
138 return ondata( handler, data, err )
140 handler.ssl = function( )
141 return sslctx and true or false
143 handler.close = function( closed )
144 _ = not closed and close( socket )
145 writelen = removesocket( writelist, socket, writelen )
146 readlen = removesocket( readlist, socket, readlen )
147 socketlist[ socket ] = nil
150 handler.ip = function( )
153 handler.serverport = function( )
156 handler.socket = function( )
159 handler.receivedata = function( )
160 local client, err = accept( socket ) -- try to accept
162 local ip, clientport = client:getpeername( )
163 client:settimeout( 0 )
164 local handler, client, err = wrapclient( listener, client, ip, serverport, clientport, mode, sslctx ) -- wrap new client socket
165 if err then -- error while wrapping ssl socket
168 out_put( "server.lua: accepted new client connection from ", ip, ":", clientport )
169 return dispatch( handler )
170 elseif err then -- maybe timeout or something else
171 out_put( "server.lua: error with new client connection: ", err )
178 wrapsslclient = function( listener, socket, ip, serverport, clientport, mode, sslctx ) -- this function wraps a ssl cleint
180 local dispatch, disconnect = listener.listener, listener.disconnect
182 --// transform socket to ssl object //--
185 socket, err = ssl_wrap( socket, sslctx ) -- wrap socket
187 out_put( "server.lua: ssl error: ", err )
188 return nil, nil, err -- fatal error
190 socket:settimeout( 0 )
192 --// private closures of the object //--
194 local writequeue = { } -- buffer for messages to send
196 local eol, fatal_send_error, wants_closing
198 local sstat, rstat = 0, 0
200 --// local import of socket methods //--
202 local send = socket.send
203 local receive = socket.receive
204 local close = socket.close
205 --local shutdown = socket.shutdown
207 --// public methods of the object //--
211 handler.getstats = function( )
215 handler.listener = function( data, err )
216 return listener( handler, data, err )
218 handler.ssl = function( )
221 handler.send = function( _, data, i, j )
222 return send( socket, data, i, j )
224 handler.receive = function( pattern, prefix )
225 return receive( socket, pattern, prefix )
227 handler.shutdown = function( pattern )
228 --return shutdown( socket, pattern )
230 handler.close = function( closed )
231 if eol and not fatal_send_error then
232 -- There is data in the buffer, and we haven't experienced
233 -- an error trying to send yet, so we'll flush the buffer now
234 handler._dispatchdata();
236 -- and there is *still* data in the buffer
237 -- we'll give up for now, and close later
238 wants_closing = true;
243 writelen = ( eol and removesocket( writelist, socket, writelen ) ) or writelen
244 readlen = removesocket( readlist, socket, readlen )
245 socketlist[ socket ] = nil
246 out_put "server.lua: closed handler and removed socket from list"
248 handler.ip = function( )
251 handler.serverport = function( )
254 handler.clientport = function( )
258 handler.write = function( data )
260 writelen = writelen + 1
261 writelist[ writelen ] = socket
265 writequeue[ eol ] = data
267 handler.writequeue = function( )
270 handler.socket = function( )
273 handler.mode = function( )
276 handler._receivedata = function( )
277 local data, err, part = receive( socket, mode ) -- receive data in "mode"
278 if not err or ( err == "timeout" or err == "wantread" ) then -- received something
279 local data = data or part or ""
280 local count = #data * STAT_UNIT
281 rstat = rstat + count
282 receivestat = receivestat + count
283 --out_put( "server.lua: read data '", data, "', error: ", err )
284 return dispatch( handler, data, err )
285 else -- connections was closed or fatal error
286 out_put( "server.lua: client ", ip, ":", clientport, " error: ", err )
288 disconnect( handler, err )
294 handler._dispatchdata = function( ) -- this function writes data to handlers
295 local buffer = table_concat( writequeue, "", 1, eol )
296 local succ, err, byte = send( socket, buffer )
297 local count = ( succ or 0 ) * STAT_UNIT
298 sstat = sstat + count
299 sendstat = sendstat + count
300 out_put( "server.lua: sended '", buffer, "', bytes: ", succ, ", error: ", err, ", part: ", byte, ", to: ", ip, ":", clientport )
301 if succ then -- sending succesful
304 writelen = removesocket( writelist, socket, writelen ) -- delete socket from writelist
305 if wants_closing then
309 elseif byte and ( err == "timeout" or err == "wantwrite" ) then -- want write
310 buffer = string_sub( buffer, byte + 1, -1 ) -- new buffer
311 writequeue[ 1 ] = buffer -- insert new buffer in queue
314 else -- connection was closed during sending or fatal error
315 fatal_send_error = true;
316 out_put( "server.lua: client ", ip, ":", clientport, " error: ", err )
318 disconnect( handler, err )
327 handler.getIp = handler.ip
328 handler.getPort = handler.clientport
334 handler.handshake = coroutine_wrap( function( client )
336 for i = 1, 10 do -- 10 handshake attemps
337 _, err = client:dohandshake( )
339 out_put( "server.lua: ssl handshake done" )
340 writelen = ( wrote and removesocket( writelist, socket, writelen ) ) or writelen
341 handler.receivedata = handler._receivedata -- when handshake is done, replace the handshake function with regular functions
342 handler.dispatchdata = handler._dispatchdata
343 return dispatch( handler )
345 out_put( "server.lua: error during ssl handshake: ", err )
346 if err == "wantwrite" then
348 writelen = writelen + 1
349 writelist[ writelen ] = client
353 coroutine_yield( handler, nil, err ) -- handshake not finished
356 _ = err ~= "closed" and close( socket )
358 disconnect( handler, err )
361 return false -- handshake failed
364 handler.receivedata = handler.handshake
365 handler.dispatchdata = handler.handshake
367 handler.handshake( socket ) -- do handshake
369 socketlist[ socket ] = handler
370 readlen = readlen + 1
371 readlist[ readlen ] = socket
373 return handler, socket
376 wraptlsclient = function( listener, socket, ip, serverport, clientport, mode, sslctx ) -- this function wraps a tls cleint
378 local dispatch, disconnect = listener.listener, listener.disconnect
380 --// transform socket to ssl object //--
384 socket:settimeout( 0 )
385 --// private closures of the object //--
387 local writequeue = { } -- buffer for messages to send
389 local eol, fatal_send_error, wants_closing
391 local sstat, rstat = 0, 0
393 --// local import of socket methods //--
395 local send = socket.send
396 local receive = socket.receive
397 local close = socket.close
398 --local shutdown = socket.shutdown
400 --// public methods of the object //--
404 handler.getstats = function( )
408 handler.listener = function( data, err )
409 return listener( handler, data, err )
411 handler.ssl = function( )
414 handler.send = function( _, data, i, j )
415 return send( socket, data, i, j )
417 handler.receive = function( pattern, prefix )
418 return receive( socket, pattern, prefix )
420 handler.shutdown = function( pattern )
421 --return shutdown( socket, pattern )
423 handler.close = function( closed )
424 if eol and not fatal_send_error then
425 -- There is data in the buffer, and we haven't experienced
426 -- an error trying to send yet, so we'll flush the buffer now
427 handler._dispatchdata();
429 -- and there is *still* data in the buffer
430 -- we'll give up for now, and close later
431 wants_closing = true;
436 writelen = ( eol and removesocket( writelist, socket, writelen ) ) or writelen
437 readlen = removesocket( readlist, socket, readlen )
438 socketlist[ socket ] = nil
439 out_put "server.lua: closed handler and removed socket from list"
441 handler.ip = function( )
444 handler.serverport = function( )
447 handler.clientport = function( )
451 handler.write = function( data )
453 writelen = writelen + 1
454 writelist[ writelen ] = socket
458 writequeue[ eol ] = data
460 handler.writequeue = function( )
463 handler.socket = function( )
466 handler.mode = function( )
469 handler._receivedata = function( )
470 local data, err, part = receive( socket, mode ) -- receive data in "mode"
471 if not err or ( err == "timeout" or err == "wantread" ) then -- received something
472 local data = data or part or ""
473 local count = #data * STAT_UNIT
474 rstat = rstat + count
475 receivestat = receivestat + count
476 --out_put( "server.lua: read data '", data, "', error: ", err )
477 return dispatch( handler, data, err )
478 else -- connections was closed or fatal error
479 out_put( "server.lua: client ", ip, ":", clientport, " error: ", err )
481 disconnect( handler, err )
487 handler._dispatchdata = function( ) -- this function writes data to handlers
488 local buffer = table_concat( writequeue, "", 1, eol )
489 local succ, err, byte = send( socket, buffer )
490 local count = ( succ or 0 ) * STAT_UNIT
491 sstat = sstat + count
492 sendstat = sendstat + count
493 out_put( "server.lua: sended '", buffer, "', bytes: ", succ, ", error: ", err, ", part: ", byte, ", to: ", ip, ":", clientport )
494 if succ then -- sending succesful
497 writelen = removesocket( writelist, socket, writelen ) -- delete socket from writelist
498 if handler.need_tls then
499 out_put("server.lua: connection is ready for tls handshake");
500 handler.starttls(true);
502 if wants_closing then
506 elseif byte and ( err == "timeout" or err == "wantwrite" ) then -- want write
507 buffer = string_sub( buffer, byte + 1, -1 ) -- new buffer
508 writequeue[ 1 ] = buffer -- insert new buffer in queue
511 else -- connection was closed during sending or fatal error
512 fatal_send_error = true; -- :(
513 out_put( "server.lua: client ", ip, ":", clientport, " error: ", err )
515 disconnect( handler, err )
522 handler.receivedata, handler.dispatchdata = handler._receivedata, handler._dispatchdata;
525 handler.getIp = handler.ip
526 handler.getPort = handler.clientport
532 handler.starttls = function (now)
533 if not now then out_put("server.lua: we need to do tls, but delaying until later"); handler.need_tls = true; return; end
534 out_put( "server.lua: attempting to start tls on "..tostring(socket) )
535 local oldsocket = socket;
536 socket, err = ssl_wrap( socket, sslctx ) -- wrap socket
537 out_put("sslwrapped socket is "..tostring(socket));
539 out_put( "server.lua: ssl error: ", err )
540 return nil, nil, err -- fatal error
542 socket:settimeout(0);
544 -- Add the new socket to our system
545 socketlist[ socket ] = handler
546 readlen = readlen + 1
547 readlist[ readlen ] = socket
549 -- Remove traces of the old socket
550 readlen = removesocket( readlist, oldsocket, readlen )
551 socketlist [ oldsocket ] = nil;
554 receive = socket.receive
556 handler.ssl = function( )
559 handler.send = function( _, data, i, j )
560 return send( socket, data, i, j )
562 handler.receive = function( pattern, prefix )
563 return receive( socket, pattern, prefix )
566 handler.starttls = nil;
567 handler.need_tls = nil
569 handler.handshake = coroutine_wrap( function( client )
571 for i = 1, 10 do -- 10 handshake attemps
572 _, err = client:dohandshake( )
574 out_put( "server.lua: ssl handshake done" )
575 writelen = ( wrote and removesocket( writelist, socket, writelen ) ) or writelen
576 handler.receivedata = handler._receivedata -- when handshake is done, replace the handshake function with regular functions
577 handler.dispatchdata = handler._dispatchdata;
580 out_put( "server.lua: error during ssl handshake: ", err )
581 if err == "wantwrite" then
583 writelen = writelen + 1
584 writelist[ writelen ] = client
588 coroutine_yield( handler, nil, err ) -- handshake not finished
591 _ = err ~= "closed" and close( socket )
593 disconnect( handler, err )
596 return false -- handshake failed
599 handler.receivedata = handler.handshake
600 handler.dispatchdata = handler.handshake
602 handler.handshake( socket ) -- do handshake
604 socketlist[ socket ] = handler
605 readlen = readlen + 1
606 readlist[ readlen ] = socket
608 return handler, socket
611 wraptcpclient = function( listener, socket, ip, serverport, clientport, mode ) -- this function wraps a socket
613 local dispatch, disconnect = listener.listener, listener.disconnect
615 --// private closures of the object //--
617 local writequeue = { } -- list for messages to send
619 local eol, fatal_send_error, wants_closing
621 socket:settimeout(0);
623 local rstat, sstat = 0, 0
625 --// local import of socket methods //--
627 local send = socket.send
628 local receive = socket.receive
629 local close = socket.close
630 local shutdown = socket.shutdown
632 --// public methods of the object //--
636 handler.getstats = function( )
640 handler.listener = function( data, err )
641 return listener( handler, data, err )
643 handler.ssl = function( )
646 handler.send = function( _, data, i, j )
647 return send( socket, data, i, j )
649 handler.receive = function( pattern, prefix )
650 return receive( socket, pattern, prefix )
652 handler.shutdown = function( pattern )
653 return shutdown( socket, pattern )
655 handler.close = function( closed )
656 if eol and not fatal_send_error then
657 -- There is data in the buffer, and we haven't experienced
658 -- an error trying to send yet, so we'll flush the buffer now
659 handler.dispatchdata();
661 -- and there is *still* data in the buffer
662 -- we'll give up for now, and close later
663 wants_closing = true;
667 _ = not closed and shutdown( socket )
668 _ = not closed and close( socket )
669 writelen = ( eol and removesocket( writelist, socket, writelen ) ) or writelen
670 readlen = removesocket( readlist, socket, readlen )
671 socketlist[ socket ] = nil
672 out_put "server.lua: closed handler and removed socket from list"
674 handler.ip = function( )
677 handler.serverport = function( )
680 handler.clientport = function( )
683 handler.write = function( data )
685 writelen = writelen + 1
686 writelist[ writelen ] = socket
690 writequeue[ eol ] = data
692 handler.writequeue = function( )
695 handler.socket = function( )
698 handler.mode = function( )
702 handler.receivedata = function( )
703 local data, err, part = receive( socket, mode ) -- receive data in "mode"
704 if not err or ( err == "timeout" or err == "wantread" ) then -- received something
705 local data = data or part or ""
706 local count = #data * STAT_UNIT
707 rstat = rstat + count
708 receivestat = receivestat + count
709 --out_put( "server.lua: read data '", data, "', error: ", err )
710 return dispatch( handler, data, err )
711 else -- connections was closed or fatal error
712 out_put( "server.lua: client ", ip, ":", clientport, " error: ", err )
714 disconnect( handler, err )
721 handler.dispatchdata = function( ) -- this function writes data to handlers
722 local buffer = table_concat( writequeue, "", 1, eol )
723 local succ, err, byte = send( socket, buffer )
724 local count = ( succ or 0 ) * STAT_UNIT
725 sstat = sstat + count
726 sendstat = sendstat + count
727 out_put( "server.lua: sended '", buffer, "', bytes: ", succ, ", error: ", err, ", part: ", byte, ", to: ", ip, ":", clientport )
728 if succ then -- sending succesful
731 writelen = removesocket( writelist, socket, writelen ) -- delete socket from writelist
732 if wants_closing then
736 elseif byte and ( err == "timeout" or err == "wantwrite" ) then -- want write
737 buffer = string_sub( buffer, byte + 1, -1 ) -- new buffer
738 writequeue[ 1 ] = buffer -- insert new buffer in queue
741 else -- connection was closed during sending or fatal error
742 fatal_send_error = true; -- :'-(
743 out_put( "server.lua: client ", ip, ":", clientport, " error: ", err )
745 disconnect( handler, err )
754 handler.getIp = handler.ip
755 handler.getPort = handler.clientport
757 socketlist[ socket ] = handler
758 readlen = readlen + 1
759 readlist[ readlen ] = socket
761 return handler, socket
764 addtimer = function( listener )
765 timelistener[ #timelistener + 1 ] = listener
768 firetimer = function( listener )
769 for i, listener in ipairs( timelistener ) do
774 addserver = function( listeners, port, addr, mode, sslctx, wrapper_function ) -- this function provides a way for other scripts to reg a server
776 if type( listeners ) ~= "table" then
777 err = "invalid listener table"
779 for name, func in pairs( listeners ) do
780 if type( func ) ~= "function" then
781 --err = "invalid listener function"
786 if not type( port ) == "number" or not ( port >= 0 and port <= 65535 ) then
788 elseif listener[ port ] then
789 err= "listeners on port '" .. port .. "' already exist"
790 elseif sslctx and not luasec then
791 err = "luasec not found"
794 out_error( "server.lua: ", err )
798 local server, err = socket_bind( addr, port )
800 out_error( "server.lua: ", err )
803 local handler, err = wrapserver( listeners, server, addr, port, mode, sslctx, wrapper_function ) -- wrap new server socket
808 server:settimeout( 0 )
809 readlen = readlen + 1
810 readlist[ readlen ] = server
811 listener[ port ] = listeners
812 socketlist[ server ] = handler
813 out_put( "server.lua: new server listener on ", addr, ":", port )
817 removesocket = function( tbl, socket, len ) -- this function removes sockets from a list
818 for i, target in ipairs( tbl ) do
819 if target == socket then
821 table_remove( tbl, i )
828 closeall = function( )
829 for sock, handler in pairs( socketlist ) do
832 socketlist[ sock ] = nil
834 writelist, readlist, socketlist = { }, { }, { }
837 closesocket = function( socket )
838 writelen = removesocket( writelist, socket, writelen )
839 readlen = removesocket( readlist, socket, readlen )
840 socketlist[ socket ] = nil
844 loop = function( ) -- this is the main loop of the program
845 --signal_set( "hub", "run" )
847 local read, write, err = socket_select( readlist, writelist, 1 ) -- 1 sec timeout, nice for timers
848 for i, socket in ipairs( write ) do -- send data waiting in writequeues
849 local handler = socketlist[ socket ]
851 handler.dispatchdata( )
853 closesocket( socket )
854 out_put "server.lua: found no handler and closed socket (writelist)" -- this should not happen
857 for i, socket in ipairs( read ) do -- receive data
858 local handler = socketlist[ socket ]
860 handler.receivedata( )
862 closesocket( socket )
863 out_put "server.lua: found no handler and closed socket (readlist)" -- this can happen
871 ----------------------------------// BEGIN //--
873 ----------------------------------// PUBLIC INTERFACE //--
882 wraptcpclient = wraptcpclient,
883 wrapsslclient = wrapsslclient,
884 wraptlsclient = wraptlsclient,