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