Numerous BOSH improvements... handle client disconnects, either explicit or implicit...
[prosody.git] / net / server.lua
1 --[[
2
3                 server.lua by blastbeat of the luadch project
4                 
5                 re-used here under the MIT/X Consortium License
6                 
7                 Modifications (C) 2008 Matthew Wild, Waqas Hussain
8 ]]--
9
10 ----------------------------------// DECLARATION //--
11
12 --// constants //--
13
14 local STAT_UNIT = 1 / ( 1024 * 1024 )    -- mb
15
16 --// lua functions //--
17
18 local function use( what ) return _G[ what ] end
19
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"
25
26 --// lua libs //--
27
28 local table = use "table"
29 local coroutine = use "coroutine"
30
31 --// lua lib methods //--
32
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
38 local print = print;
39 local out_put = function () end --print;
40 local out_error = print;
41
42 --// extern libs //--
43
44 local luasec = select(2, pcall(require, "ssl"))
45 local luasocket = require "socket"
46
47 --// extern lib methods //--
48
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 )
53
54 --// functions //--
55
56 local loop
57 local stats
58 local addtimer
59 local closeall
60 local addserver
61 local firetimer
62 local closesocket
63 local removesocket
64 local wrapserver
65 local wraptcpclient
66 local wrapsslclient
67
68 --// tables //--
69
70 local listener
71 local readlist
72 local writelist
73 local socketlist
74 local timelistener
75
76 --// simple data types //--
77
78 local _
79 local readlen = 0    -- length of readlist
80 local writelen = 0    -- lenght of writelist
81
82 local sendstat= 0
83 local receivestat = 0
84
85 ----------------------------------// DEFINITION //--
86
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
91 timelistener = { }
92
93 stats = function( )
94         return receivestat, sendstat
95 end
96
97 wrapserver = function( listener, socket, ip, serverport, mode, sslctx, wrapper_function )    -- this function wraps a server
98
99         local dispatch, disconnect = listener.listener, listener.disconnect    -- dangerous
100
101         local wrapclient, err
102
103         out_put("Starting a new server on "..tostring(serverport).." with ssl: "..tostring(sslctx));
104         if sslctx then
105                 if not ssl_newcontext then
106                         return nil, "luasec not found"
107                 end
108                 if type( sslctx ) ~= "table" then
109                         out_error "server.lua: wrong server sslctx"
110                         return nil, "wrong server sslctx"
111                 end
112                 sslctx, err = ssl_newcontext( sslctx )
113                 if not sslctx then
114                         err = err or "wrong sslctx parameters"
115                         out_error( "server.lua: ", err )
116                         return nil, err
117                 end
118         end
119         
120         if wrapper_function then
121                 wrapclient = wrapper_function
122         elseif sslctx then
123                 wrapclient = wrapsslclient
124         else
125                 wrapclient = wraptcpclient
126         end
127         
128         local accept = socket.accept
129         local close = socket.close
130
131         --// public methods of the object //--    
132
133         local handler = { }
134
135         handler.shutdown = function( ) end
136
137         --[[handler.listener = function( data, err )
138                 return ondata( handler, data, err )
139         end]]
140         handler.ssl = function( )
141                 return sslctx and true or false
142         end
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
148                 handler = nil
149         end
150         handler.ip = function( )
151                 return ip
152         end
153         handler.serverport = function( )
154                 return serverport
155         end
156         handler.socket = function( )
157                 return socket
158         end
159         handler.receivedata = function( )
160                 local client, err = accept( socket )    -- try to accept
161                 if client then
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
166                                 return false
167                         end
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 )
172                         return false
173                 end
174         end
175         return handler
176 end
177
178 wrapsslclient = function( listener, socket, ip, serverport, clientport, mode, sslctx )    -- this function wraps a ssl cleint
179
180         local dispatch, disconnect = listener.listener, listener.disconnect
181
182         --// transform socket to ssl object //--
183
184         local err
185         socket, err = ssl_wrap( socket, sslctx )    -- wrap socket
186         if err then
187                 out_put( "server.lua: ssl error: ", err )
188                 return nil, nil, err    -- fatal error
189         end
190         socket:settimeout( 0 )
191
192         --// private closures of the object //--
193
194         local writequeue = { }    -- buffer for messages to send
195
196         local eol, fatal_send_error, wants_closing
197
198         local sstat, rstat = 0, 0
199
200         --// local import of socket methods //--
201
202         local send = socket.send
203         local receive = socket.receive
204         local close = socket.close
205         --local shutdown = socket.shutdown
206
207         --// public methods of the object //--
208
209         local handler = { }
210
211         handler.getstats = function( )
212                 return rstat, sstat
213         end
214
215         handler.listener = function( data, err )
216                 return listener( handler, data, err )
217         end
218         handler.ssl = function( )
219                 return true
220         end
221         handler.send = function( _, data, i, j )
222                         return send( socket, data, i, j )
223         end
224         handler.receive = function( pattern, prefix )
225                         return receive( socket, pattern, prefix )
226         end
227         handler.shutdown = function( pattern )
228                 --return shutdown( socket, pattern )
229         end
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();
235                         if eol then
236                                 -- and there is *still* data in the buffer
237                                 -- we'll give up for now, and close later
238                                 wants_closing = true;
239                                 return;
240                         end
241                 end
242                 close( socket )
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"
247         end
248         handler.ip = function( )
249                 return ip
250         end
251         handler.serverport = function( )
252                 return serverport
253         end
254         handler.clientport = function( ) 
255                 return clientport
256         end
257
258         handler.write = function( data )
259                 if not eol then
260                         writelen = writelen + 1
261                         writelist[ writelen ] = socket
262                         eol = 0
263                 end
264                 eol = eol + 1
265                 writequeue[ eol ] = data
266         end
267         handler.writequeue = function( )
268                 return writequeue
269         end
270         handler.socket = function( )
271                 return socket
272         end
273         handler.mode = function( )
274                 return mode
275         end
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 )
287                         handler.close( )
288                         disconnect( handler, err )
289                         writequeue = nil
290                         handler = nil
291                         return false
292                 end
293         end
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
302                         --writequeue = { }
303                         eol = nil
304                         writelen = removesocket( writelist, socket, writelen )    -- delete socket from writelist
305                         if wants_closing then
306                                 handler.close();
307                         end
308                         return true
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
312                         eol = 1
313                         return true
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 )
317                         handler.close( )
318                         disconnect( handler, err )
319                         writequeue = nil
320                         handler = nil
321                         return false
322                 end
323         end
324
325         -- // COMPAT // --
326
327         handler.getIp = handler.ip
328         handler.getPort = handler.clientport
329
330         --// handshake //--
331
332         local wrote
333
334         handler.handshake = coroutine_wrap( function( client )
335                         local err
336                         for i = 1, 10 do    -- 10 handshake attemps
337                                 _, err = client:dohandshake( )
338                                 if not err then
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 )
344                                 else
345                                         out_put( "server.lua: error during ssl handshake: ", err )
346                                         if err == "wantwrite" then
347                                                 if wrote == nil then
348                                                         writelen = writelen + 1
349                                                         writelist[ writelen ] = client
350                                                         wrote = true
351                                                 end
352                                         end
353                                         coroutine_yield( handler, nil, err )    -- handshake not finished
354                                 end
355                         end
356                         _ = err ~= "closed" and close( socket )
357                         handler.close( )
358                         disconnect( handler, err )
359                         writequeue = nil
360                         handler = nil
361                         return false    -- handshake failed
362                 end
363         )
364         handler.receivedata = handler.handshake
365         handler.dispatchdata = handler.handshake
366
367         handler.handshake( socket )    -- do handshake
368
369         socketlist[ socket ] = handler
370         readlen = readlen + 1
371         readlist[ readlen ] = socket
372
373         return handler, socket
374 end
375
376 wraptlsclient = function( listener, socket, ip, serverport, clientport, mode, sslctx )    -- this function wraps a tls cleint
377
378         local dispatch, disconnect = listener.listener, listener.disconnect
379
380         --// transform socket to ssl object //--
381
382         local err
383
384         socket:settimeout( 0 )
385         --// private closures of the object //--
386
387         local writequeue = { }    -- buffer for messages to send
388
389         local eol, fatal_send_error, wants_closing
390
391         local sstat, rstat = 0, 0
392
393         --// local import of socket methods //--
394
395         local send = socket.send
396         local receive = socket.receive
397         local close = socket.close
398         --local shutdown = socket.shutdown
399
400         --// public methods of the object //--
401
402         local handler = { }
403
404         handler.getstats = function( )
405                 return rstat, sstat
406         end
407
408         handler.listener = function( data, err )
409                 return listener( handler, data, err )
410         end
411         handler.ssl = function( )
412                 return false
413         end
414         handler.send = function( _, data, i, j )
415                         return send( socket, data, i, j )
416         end
417         handler.receive = function( pattern, prefix )
418                         return receive( socket, pattern, prefix )
419         end
420         handler.shutdown = function( pattern )
421                 --return shutdown( socket, pattern )
422         end
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();
428                         if eol then
429                                 -- and there is *still* data in the buffer
430                                 -- we'll give up for now, and close later
431                                 wants_closing = true;
432                                 return;
433                         end
434                 end
435                 close( socket )
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"
440         end
441         handler.ip = function( )
442                 return ip
443         end
444         handler.serverport = function( )
445                 return serverport
446         end
447         handler.clientport = function( ) 
448                 return clientport
449         end
450
451         handler.write = function( data )
452                 if not eol then
453                         writelen = writelen + 1
454                         writelist[ writelen ] = socket
455                         eol = 0
456                 end
457                 eol = eol + 1
458                 writequeue[ eol ] = data
459         end
460         handler.writequeue = function( )
461                 return writequeue
462         end
463         handler.socket = function( )
464                 return socket
465         end
466         handler.mode = function( )
467                 return mode
468         end
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 )
480                         handler.close( )
481                         disconnect( handler, err )
482                         writequeue = nil
483                         handler = nil
484                         return false
485                 end
486         end
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
495                         --writequeue = { }
496                         eol = nil
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);
501                         end
502                         if wants_closing then
503                                 handler.close();
504                         end
505                         return true
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
509                         eol = 1
510                         return true
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 )
514                         handler.close( )
515                         disconnect( handler, err )
516                         writequeue = nil
517                         handler = nil
518                         return false
519                 end
520         end
521
522         handler.receivedata, handler.dispatchdata = handler._receivedata, handler._dispatchdata;
523         -- // COMPAT // --
524
525         handler.getIp = handler.ip
526         handler.getPort = handler.clientport
527
528         --// handshake //--
529
530         local wrote, read
531         
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));
538                 if err then
539                         out_put( "server.lua: ssl error: ", err )
540                         return nil, nil, err    -- fatal error
541                 end
542                 socket:settimeout(0);
543                 
544                 -- Add the new socket to our system
545                 socketlist[ socket ] = handler
546                 readlen = readlen + 1
547                 readlist[ readlen ] = socket
548                 
549                 -- Remove traces of the old socket
550                 readlen = removesocket( readlist, oldsocket, readlen )
551                 socketlist [ oldsocket ] = nil;
552                 
553                 send = socket.send
554                 receive = socket.receive
555                 close = socket.close
556                 handler.ssl = function( )
557                         return true
558                 end
559                 handler.send = function( _, data, i, j )
560                         return send( socket, data, i, j )
561                 end
562                 handler.receive = function( pattern, prefix )
563                         return receive( socket, pattern, prefix )
564                 end
565                 
566                 handler.starttls = nil;
567                 handler.need_tls = nil
568                 
569                         handler.handshake = coroutine_wrap( function( client )
570                                         local err
571                                         for i = 1, 10 do    -- 10 handshake attemps
572                                                 _, err = client:dohandshake( )
573                                                 if not err then
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;
578                                                         return true;
579                                                 else
580                                                         out_put( "server.lua: error during ssl handshake: ", err )
581                                                         if err == "wantwrite" then
582                                                                 if wrote == nil then
583                                                                         writelen = writelen + 1
584                                                                         writelist[ writelen ] = client
585                                                                         wrote = true
586                                                                 end
587                                                         end
588                                                         coroutine_yield( handler, nil, err )    -- handshake not finished
589                                                 end
590                                         end
591                                         _ = err ~= "closed" and close( socket )
592                                         handler.close( )
593                                         disconnect( handler, err )
594                                         writequeue = nil
595                                         handler = nil
596                                         return false    -- handshake failed
597                                 end
598                         )
599                         handler.receivedata = handler.handshake
600                         handler.dispatchdata = handler.handshake
601                         
602                         handler.handshake( socket )    -- do handshake
603                 end
604         socketlist[ socket ] = handler
605         readlen = readlen + 1
606         readlist[ readlen ] = socket
607
608         return handler, socket
609 end
610
611 wraptcpclient = function( listener, socket, ip, serverport, clientport, mode )    -- this function wraps a socket
612
613         local dispatch, disconnect = listener.listener, listener.disconnect
614
615         --// private closures of the object //--
616
617         local writequeue = { }    -- list for messages to send
618
619         local eol, fatal_send_error, wants_closing
620
621         socket:settimeout(0);
622         
623         local rstat, sstat = 0, 0
624
625         --// local import of socket methods //--
626
627         local send = socket.send
628         local receive = socket.receive
629         local close = socket.close
630         local shutdown = socket.shutdown
631
632         --// public methods of the object //--
633
634         local handler = { }
635
636         handler.getstats = function( )
637                 return rstat, sstat
638         end
639
640         handler.listener = function( data, err )
641                 return listener( handler, data, err )
642         end
643         handler.ssl = function( )
644                 return false
645         end
646         handler.send = function( _, data, i, j )
647                         return send( socket, data, i, j )
648         end
649         handler.receive = function( pattern, prefix )
650                         return receive( socket, pattern, prefix )
651         end
652         handler.shutdown = function( pattern )
653                 return shutdown( socket, pattern )
654         end
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();
660                         if eol then
661                                 -- and there is *still* data in the buffer
662                                 -- we'll give up for now, and close later
663                                 wants_closing = true;
664                                 return;
665                         end
666                 end
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"
673         end
674         handler.ip = function( )
675                 return ip
676         end
677         handler.serverport = function( )
678                 return serverport
679         end
680         handler.clientport = function( ) 
681                 return clientport
682         end
683         handler.write = function( data )
684                 if not eol then
685                         writelen = writelen + 1
686                         writelist[ writelen ] = socket
687                         eol = 0
688                 end
689                 eol = eol + 1
690                 writequeue[ eol ] = data
691         end
692         handler.writequeue = function( )
693                 return writequeue
694         end
695         handler.socket = function( )
696                 return socket
697         end
698         handler.mode = function( )
699                 return mode
700         end
701         
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 )
713                         handler.close( )
714                         disconnect( handler, err )
715                         writequeue = nil
716                         handler = nil
717                         return false
718                 end
719         end
720         
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
729                         --writequeue = { }
730                         eol = nil
731                         writelen = removesocket( writelist, socket, writelen )    -- delete socket from writelist
732                         if wants_closing then
733                                 handler.close();
734                         end
735                         return true
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
739                         eol = 1
740                         return true
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 )
744                         handler.close( )
745                         disconnect( handler, err )
746                         writequeue = nil
747                         handler = nil
748                         return false
749                 end
750         end
751
752         -- // COMPAT // --
753
754         handler.getIp = handler.ip
755         handler.getPort = handler.clientport
756
757         socketlist[ socket ] = handler
758         readlen = readlen + 1
759         readlist[ readlen ] = socket
760
761         return handler, socket
762 end
763
764 addtimer = function( listener )
765         timelistener[ #timelistener + 1 ] = listener
766 end
767
768 firetimer = function( listener )
769         for i, listener in ipairs( timelistener ) do
770                 listener( )
771         end
772 end
773
774 addserver = function( listeners, port, addr, mode, sslctx, wrapper_function )    -- this function provides a way for other scripts to reg a server
775         local err
776         if type( listeners ) ~= "table" then
777                 err = "invalid listener table"
778         else
779                 for name, func in pairs( listeners ) do
780                         if type( func ) ~= "function" then
781                                 --err = "invalid listener function"
782                                 break
783                         end
784                 end
785         end
786         if not type( port ) == "number" or not ( port >= 0 and port <= 65535 ) then
787                 err = "invalid port"
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"
792         end
793         if err then
794                 out_error( "server.lua: ", err )
795                 return nil, err
796         end
797         addr = addr or "*"
798         local server, err = socket_bind( addr, port )
799         if err then
800                 out_error( "server.lua: ", err )
801                 return nil, err
802         end
803         local handler, err = wrapserver( listeners, server, addr, port, mode, sslctx, wrapper_function )    -- wrap new server socket
804         if not handler then
805                 server:close( )
806                 return nil, err
807         end
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 )
814         return true
815 end
816
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
820                         len = len - 1
821                         table_remove( tbl, i )
822                         return len
823                 end
824         end
825         return len
826 end
827
828 closeall = function( )
829         for sock, handler in pairs( socketlist ) do
830                 handler.shutdown( )
831                 handler.close( )
832                 socketlist[ sock ] = nil
833         end
834         writelist, readlist, socketlist = { }, { }, { }
835 end
836
837 closesocket = function( socket )
838         writelen = removesocket( writelist, socket, writelen )
839         readlen = removesocket( readlist, socket, readlen )
840         socketlist[ socket ] = nil
841         socket:close( )
842 end
843
844 loop = function( )    -- this is the main loop of the program
845         --signal_set( "hub", "run" )
846         repeat
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 ]
850                         if handler then
851                                 handler.dispatchdata( )
852                         else
853                                 closesocket( socket )
854                                 out_put "server.lua: found no handler and closed socket (writelist)"    -- this should not happen
855                         end
856                 end
857                 for i, socket in ipairs( read ) do    -- receive data
858                         local handler = socketlist[ socket ]
859                         if handler then
860                                 handler.receivedata( )
861                         else
862                                 closesocket( socket )
863                                 out_put "server.lua: found no handler and closed socket (readlist)"    -- this can happen
864                         end
865                 end
866                 firetimer( )
867         until false
868         return
869 end
870
871 ----------------------------------// BEGIN //--
872
873 ----------------------------------// PUBLIC INTERFACE //--
874
875 return {
876
877         add = addserver,
878         loop = loop,
879         stats = stats,
880         closeall = closeall,
881         addtimer = addtimer,
882         wraptcpclient = wraptcpclient,
883         wrapsslclient = wrapsslclient,
884         wraptlsclient = wraptlsclient,
885 }