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_put = print;
41 local out_error = print;
45 local luasec = select(2, pcall(require, "ssl"))
46 local luasocket = require "socket"
48 --// extern lib methods //--
50 local ssl_wrap = ( luasec and luasec.wrap )
51 local socket_bind = luasocket.bind
52 local socket_select = luasocket.select
53 local ssl_newcontext = ( luasec and luasec.newcontext )
77 --// simple data types //--
80 local readlen = 0 -- length of readlist
81 local writelen = 0 -- lenght of writelist
86 ----------------------------------// DEFINITION //--
88 listener = { } -- key = port, value = table
89 readlist = { } -- array with sockets to read from
90 writelist = { } -- arrary with sockets to write to
91 socketlist = { } -- key = socket, value = wrapped socket
95 return receivestat, sendstat
98 wrapserver = function( listener, socket, ip, serverport, mode, sslctx ) -- this function wraps a server
100 local dispatch, disconnect = listener.listener, listener.disconnect -- dangerous
102 local wrapclient, err
104 out_put("Starting a new server on "..tostring(serverport).." with ssl: "..tostring(sslctx));
107 if not ssl_newcontext then
108 return nil, "luasec not found"
110 if type( sslctx ) ~= "table" then
111 out_error "server.lua: wrong server sslctx"
112 return nil, "wrong server sslctx"
114 sslctx, err = ssl_newcontext( sslctx )
116 err = err or "wrong sslctx parameters"
117 out_error( "server.lua: ", err )
120 wrapclient = wrapsslclient
121 wrapclient = wraptlsclient
123 wrapclient = wraptcpclient
126 local accept = socket.accept
127 local close = socket.close
129 --// public methods of the object //--
133 handler.shutdown = function( ) end
135 --[[handler.listener = function( data, err )
136 return ondata( handler, data, err )
138 handler.ssl = function( )
139 return sslctx and true or false
141 handler.close = function( closed )
142 _ = not closed and close( socket )
143 writelen = removesocket( writelist, socket, writelen )
144 readlen = removesocket( readlist, socket, readlen )
145 socketlist[ socket ] = nil
148 handler.ip = function( )
151 handler.serverport = function( )
154 handler.socket = function( )
157 handler.receivedata = function( )
158 local client, err = accept( socket ) -- try to accept
160 local ip, clientport = client:getpeername( )
161 client:settimeout( 0 )
162 local handler, client, err = wrapclient( listener, client, ip, serverport, clientport, mode, sslctx ) -- wrap new client socket
163 if err then -- error while wrapping ssl socket
166 out_put( "server.lua: accepted new client connection from ", ip, ":", clientport )
167 return dispatch( handler )
168 elseif err then -- maybe timeout or something else
169 out_put( "server.lua: error with new client connection: ", err )
176 wrapsslclient = function( listener, socket, ip, serverport, clientport, mode, sslctx ) -- this function wraps a ssl cleint
178 local dispatch, disconnect = listener.listener, listener.disconnect
180 --// transform socket to ssl object //--
183 socket, err = ssl_wrap( socket, sslctx ) -- wrap socket
185 out_put( "server.lua: ssl error: ", err )
186 return nil, nil, err -- fatal error
188 socket:settimeout( 0 )
190 --// private closures of the object //--
192 local writequeue = { } -- buffer for messages to send
194 local eol, fatal_send_error, wants_closing
196 local sstat, rstat = 0, 0
198 --// local import of socket methods //--
200 local send = socket.send
201 local receive = socket.receive
202 local close = socket.close
203 --local shutdown = socket.shutdown
205 --// public methods of the object //--
209 handler.getstats = function( )
213 handler.listener = function( data, err )
214 return listener( handler, data, err )
216 handler.ssl = function( )
219 handler.send = function( _, data, i, j )
220 return send( socket, data, i, j )
222 handler.receive = function( pattern, prefix )
223 return receive( socket, pattern, prefix )
225 handler.shutdown = function( pattern )
226 --return shutdown( socket, pattern )
228 handler.close = function( closed )
229 if eol and not fatal_send_error then
230 -- There is data in the buffer, and we haven't experienced
231 -- an error trying to send yet, so we'll flush the buffer now
232 handler._dispatchdata();
234 -- and there is *still* data in the buffer
235 -- we'll give up for now, and close later
236 wants_closing = true;
241 writelen = ( eol and removesocket( writelist, socket, writelen ) ) or writelen
242 readlen = removesocket( readlist, socket, readlen )
243 socketlist[ socket ] = nil
244 out_put "server.lua: closed handler and removed socket from list"
246 handler.ip = function( )
249 handler.serverport = function( )
252 handler.clientport = function( )
256 handler.write = function( data )
258 writelen = writelen + 1
259 writelist[ writelen ] = socket
263 writequeue[ eol ] = data
265 handler.writequeue = function( )
268 handler.socket = function( )
271 handler.mode = function( )
274 handler._receivedata = function( )
275 local data, err, part = receive( socket, mode ) -- receive data in "mode"
276 if not err or ( err == "timeout" or err == "wantread" ) then -- received something
277 local data = data or part or ""
278 local count = #data * STAT_UNIT
279 rstat = rstat + count
280 receivestat = receivestat + count
281 --out_put( "server.lua: read data '", data, "', error: ", err )
282 return dispatch( handler, data, err )
283 else -- connections was closed or fatal error
284 out_put( "server.lua: client ", ip, ":", clientport, " error: ", err )
286 disconnect( handler, err )
292 handler._dispatchdata = function( ) -- this function writes data to handlers
293 local buffer = table_concat( writequeue, "", 1, eol )
294 local succ, err, byte = send( socket, buffer )
295 local count = ( succ or 0 ) * STAT_UNIT
296 sstat = sstat + count
297 sendstat = sendstat + count
298 out_put( "server.lua: sended '", buffer, "', bytes: ", succ, ", error: ", err, ", part: ", byte, ", to: ", ip, ":", clientport )
299 if succ then -- sending succesful
302 writelen = removesocket( writelist, socket, writelen ) -- delete socket from writelist
303 if wants_closing then
307 elseif byte and ( err == "timeout" or err == "wantwrite" ) then -- want write
308 buffer = string_sub( buffer, byte + 1, -1 ) -- new buffer
309 writequeue[ 1 ] = buffer -- insert new buffer in queue
312 else -- connection was closed during sending or fatal error
313 fatal_send_error = true;
314 out_put( "server.lua: client ", ip, ":", clientport, " error: ", err )
316 disconnect( handler, err )
325 handler.getIp = handler.ip
326 handler.getPort = handler.clientport
332 handler.handshake = coroutine_wrap( function( client )
334 for i = 1, 10 do -- 10 handshake attemps
335 _, err = client:dohandshake( )
337 out_put( "server.lua: ssl handshake done" )
338 writelen = ( wrote and removesocket( writelist, socket, writelen ) ) or writelen
339 handler.receivedata = handler._receivedata -- when handshake is done, replace the handshake function with regular functions
340 handler.dispatchdata = handler._dispatchdata
341 return dispatch( handler )
343 out_put( "server.lua: error during ssl handshake: ", err )
344 if err == "wantwrite" then
346 writelen = writelen + 1
347 writelist[ writelen ] = client
351 coroutine_yield( handler, nil, err ) -- handshake not finished
354 _ = err ~= "closed" and close( socket )
356 disconnect( handler, err )
359 return false -- handshake failed
362 handler.receivedata = handler.handshake
363 handler.dispatchdata = handler.handshake
365 handler.handshake( socket ) -- do handshake
367 socketlist[ socket ] = handler
368 readlen = readlen + 1
369 readlist[ readlen ] = socket
371 return handler, socket
374 wraptlsclient = function( listener, socket, ip, serverport, clientport, mode, sslctx ) -- this function wraps a tls cleint
376 local dispatch, disconnect = listener.listener, listener.disconnect
378 --// transform socket to ssl object //--
382 socket:settimeout( 0 )
383 --// private closures of the object //--
385 local writequeue = { } -- buffer for messages to send
387 local eol, fatal_send_error, wants_closing
389 local sstat, rstat = 0, 0
391 --// local import of socket methods //--
393 local send = socket.send
394 local receive = socket.receive
395 local close = socket.close
396 --local shutdown = socket.shutdown
398 --// public methods of the object //--
402 handler.getstats = function( )
406 handler.listener = function( data, err )
407 return listener( handler, data, err )
409 handler.ssl = function( )
412 handler.send = function( _, data, i, j )
413 return send( socket, data, i, j )
415 handler.receive = function( pattern, prefix )
416 return receive( socket, pattern, prefix )
418 handler.shutdown = function( pattern )
419 --return shutdown( socket, pattern )
421 handler.close = function( closed )
422 if eol and not fatal_send_error then
423 -- There is data in the buffer, and we haven't experienced
424 -- an error trying to send yet, so we'll flush the buffer now
425 handler._dispatchdata();
427 -- and there is *still* data in the buffer
428 -- we'll give up for now, and close later
429 wants_closing = true;
434 writelen = ( eol and removesocket( writelist, socket, writelen ) ) or writelen
435 readlen = removesocket( readlist, socket, readlen )
436 socketlist[ socket ] = nil
437 out_put "server.lua: closed handler and removed socket from list"
439 handler.ip = function( )
442 handler.serverport = function( )
445 handler.clientport = function( )
449 handler.write = function( data )
451 writelen = writelen + 1
452 writelist[ writelen ] = socket
456 writequeue[ eol ] = data
458 handler.writequeue = function( )
461 handler.socket = function( )
464 handler.mode = function( )
467 handler._receivedata = function( )
468 local data, err, part = receive( socket, mode ) -- receive data in "mode"
469 if not err or ( err == "timeout" or err == "wantread" ) then -- received something
470 local data = data or part or ""
471 local count = #data * STAT_UNIT
472 rstat = rstat + count
473 receivestat = receivestat + count
474 --out_put( "server.lua: read data '", data, "', error: ", err )
475 return dispatch( handler, data, err )
476 else -- connections was closed or fatal error
477 out_put( "server.lua: client ", ip, ":", clientport, " error: ", err )
479 disconnect( handler, err )
485 handler._dispatchdata = function( ) -- this function writes data to handlers
486 local buffer = table_concat( writequeue, "", 1, eol )
487 local succ, err, byte = send( socket, buffer )
488 local count = ( succ or 0 ) * STAT_UNIT
489 sstat = sstat + count
490 sendstat = sendstat + count
491 out_put( "server.lua: sended '", buffer, "', bytes: ", succ, ", error: ", err, ", part: ", byte, ", to: ", ip, ":", clientport )
492 if succ then -- sending succesful
495 writelen = removesocket( writelist, socket, writelen ) -- delete socket from writelist
496 if handler.need_tls then
497 out_put("server.lua: connection is ready for tls handshake");
498 handler.starttls(true);
500 if wants_closing then
504 elseif byte and ( err == "timeout" or err == "wantwrite" ) then -- want write
505 buffer = string_sub( buffer, byte + 1, -1 ) -- new buffer
506 writequeue[ 1 ] = buffer -- insert new buffer in queue
509 else -- connection was closed during sending or fatal error
510 fatal_send_error = true; -- :(
511 out_put( "server.lua: client ", ip, ":", clientport, " error: ", err )
513 disconnect( handler, err )
520 handler.receivedata, handler.dispatchdata = handler._receivedata, handler._dispatchdata;
523 handler.getIp = handler.ip
524 handler.getPort = handler.clientport
530 handler.starttls = function (now)
531 if not now then out_put("server.lua: we need to do tls, but delaying until later"); handler.need_tls = true; return; end
532 out_put( "server.lua: attempting to start tls on "..tostring(socket) )
533 local oldsocket = socket;
534 socket, err = ssl_wrap( socket, sslctx ) -- wrap socket
535 out_put("sslwrapped socket is "..tostring(socket));
537 out_put( "server.lua: ssl error: ", err )
538 return nil, nil, err -- fatal error
540 socket:settimeout(0);
542 -- Add the new socket to our system
543 socketlist[ socket ] = handler
544 readlen = readlen + 1
545 readlist[ readlen ] = socket
547 -- Remove traces of the old socket
548 readlen = removesocket( readlist, oldsocket, readlen )
549 socketlist [ oldsocket ] = nil;
552 receive = socket.receive
554 handler.ssl = function( )
557 handler.send = function( _, data, i, j )
558 return send( socket, data, i, j )
560 handler.receive = function( pattern, prefix )
561 return receive( socket, pattern, prefix )
564 handler.starttls = nil;
565 handler.need_tls = nil
567 handler.handshake = coroutine_wrap( function( client )
569 for i = 1, 10 do -- 10 handshake attemps
570 _, err = client:dohandshake( )
572 out_put( "server.lua: ssl handshake done" )
573 writelen = ( wrote and removesocket( writelist, socket, writelen ) ) or writelen
574 handler.receivedata = handler._receivedata -- when handshake is done, replace the handshake function with regular functions
575 handler.dispatchdata = handler._dispatchdata;
578 out_put( "server.lua: error during ssl handshake: ", err )
579 if err == "wantwrite" then
581 writelen = writelen + 1
582 writelist[ writelen ] = client
586 coroutine_yield( handler, nil, err ) -- handshake not finished
589 _ = err ~= "closed" and close( socket )
591 disconnect( handler, err )
594 return false -- handshake failed
597 handler.receivedata = handler.handshake
598 handler.dispatchdata = handler.handshake
600 handler.handshake( socket ) -- do handshake
602 socketlist[ socket ] = handler
603 readlen = readlen + 1
604 readlist[ readlen ] = socket
606 return handler, socket
609 wraptcpclient = function( listener, socket, ip, serverport, clientport, mode ) -- this function wraps a socket
611 local dispatch, disconnect = listener.listener, listener.disconnect
613 --// private closures of the object //--
615 local writequeue = { } -- list for messages to send
617 local eol, fatal_send_error, wants_closing
619 socket:settimeout(0);
621 local rstat, sstat = 0, 0
623 --// local import of socket methods //--
625 local send = socket.send
626 local receive = socket.receive
627 local close = socket.close
628 local shutdown = socket.shutdown
630 --// public methods of the object //--
634 handler.getstats = function( )
638 handler.listener = function( data, err )
639 return listener( handler, data, err )
641 handler.ssl = function( )
644 handler.send = function( _, data, i, j )
645 return send( socket, data, i, j )
647 handler.receive = function( pattern, prefix )
648 return receive( socket, pattern, prefix )
650 handler.shutdown = function( pattern )
651 return shutdown( socket, pattern )
653 handler.close = function( closed )
654 if eol and not fatal_send_error then
655 -- There is data in the buffer, and we haven't experienced
656 -- an error trying to send yet, so we'll flush the buffer now
657 handler.dispatchdata();
659 -- and there is *still* data in the buffer
660 -- we'll give up for now, and close later
661 wants_closing = true;
665 _ = not closed and shutdown( socket )
666 _ = not closed and close( socket )
667 writelen = ( eol and removesocket( writelist, socket, writelen ) ) or writelen
668 readlen = removesocket( readlist, socket, readlen )
669 socketlist[ socket ] = nil
670 out_put "server.lua: closed handler and removed socket from list"
672 handler.ip = function( )
675 handler.serverport = function( )
678 handler.clientport = function( )
681 handler.write = function( data )
683 writelen = writelen + 1
684 writelist[ writelen ] = socket
688 writequeue[ eol ] = data
690 handler.writequeue = function( )
693 handler.socket = function( )
696 handler.mode = function( )
700 handler.receivedata = function( )
701 local data, err, part = receive( socket, mode ) -- receive data in "mode"
702 if not err or ( err == "timeout" or err == "wantread" ) then -- received something
703 local data = data or part or ""
704 local count = #data * STAT_UNIT
705 rstat = rstat + count
706 receivestat = receivestat + count
707 --out_put( "server.lua: read data '", data, "', error: ", err )
708 return dispatch( handler, data, err )
709 else -- connections was closed or fatal error
710 out_put( "server.lua: client ", ip, ":", clientport, " error: ", err )
712 disconnect( handler, err )
719 handler.dispatchdata = function( ) -- this function writes data to handlers
720 local buffer = table_concat( writequeue, "", 1, eol )
721 local succ, err, byte = send( socket, buffer )
722 local count = ( succ or 0 ) * STAT_UNIT
723 sstat = sstat + count
724 sendstat = sendstat + count
725 out_put( "server.lua: sended '", buffer, "', bytes: ", succ, ", error: ", err, ", part: ", byte, ", to: ", ip, ":", clientport )
726 if succ then -- sending succesful
729 writelen = removesocket( writelist, socket, writelen ) -- delete socket from writelist
730 if wants_closing then
734 elseif byte and ( err == "timeout" or err == "wantwrite" ) then -- want write
735 buffer = string_sub( buffer, byte + 1, -1 ) -- new buffer
736 writequeue[ 1 ] = buffer -- insert new buffer in queue
739 else -- connection was closed during sending or fatal error
740 fatal_send_error = true; -- :'-(
741 out_put( "server.lua: client ", ip, ":", clientport, " error: ", err )
743 disconnect( handler, err )
752 handler.getIp = handler.ip
753 handler.getPort = handler.clientport
755 socketlist[ socket ] = handler
756 readlen = readlen + 1
757 readlist[ readlen ] = socket
759 return handler, socket
762 addtimer = function( listener )
763 timelistener[ #timelistener + 1 ] = listener
766 firetimer = function( listener )
767 for i, listener in ipairs( timelistener ) do
772 addserver = function( listeners, port, addr, mode, sslctx ) -- this function provides a way for other scripts to reg a server
774 if type( listeners ) ~= "table" then
775 err = "invalid listener table"
777 for name, func in pairs( listeners ) do
778 if type( func ) ~= "function" then
779 --err = "invalid listener function"
784 if not type( port ) == "number" or not ( port >= 0 and port <= 65535 ) then
786 elseif listener[ port ] then
787 err= "listeners on port '" .. port .. "' already exist"
788 elseif sslctx and not luasec then
789 err = "luasec not found"
792 out_error( "server.lua: ", err )
796 local server, err = socket_bind( addr, port )
798 out_error( "server.lua: ", err )
801 local handler, err = wrapserver( listeners, server, addr, port, mode, sslctx ) -- wrap new server socket
806 server:settimeout( 0 )
807 readlen = readlen + 1
808 readlist[ readlen ] = server
809 listener[ port ] = listeners
810 socketlist[ server ] = handler
811 out_put( "server.lua: new server listener on ", addr, ":", port )
815 removesocket = function( tbl, socket, len ) -- this function removes sockets from a list
816 for i, target in ipairs( tbl ) do
817 if target == socket then
819 table_remove( tbl, i )
826 closeall = function( )
827 for sock, handler in pairs( socketlist ) do
830 socketlist[ sock ] = nil
832 writelist, readlist, socketlist = { }, { }, { }
835 closesocket = function( socket )
836 writelen = removesocket( writelist, socket, writelen )
837 readlen = removesocket( readlist, socket, readlen )
838 socketlist[ socket ] = nil
842 loop = function( ) -- this is the main loop of the program
843 --signal_set( "hub", "run" )
845 local read, write, err = socket_select( readlist, writelist, 1 ) -- 1 sec timeout, nice for timers
846 for i, socket in ipairs( write ) do -- send data waiting in writequeues
847 local handler = socketlist[ socket ]
849 handler.dispatchdata( )
851 closesocket( socket )
852 out_put "server.lua: found no handler and closed socket (writelist)" -- this should not happen
855 for i, socket in ipairs( read ) do -- receive data
856 local handler = socketlist[ socket ]
858 handler.receivedata( )
860 closesocket( socket )
861 out_put "server.lua: found no handler and closed socket (readlist)" -- this can happen
869 ----------------------------------// BEGIN //--
871 ----------------------------------// PUBLIC INTERFACE //--
880 wraptcpclient = wraptcpclient,
881 wraptlsclient = wraptlsclient,