e8a4349cfb145f8af2e1f1594f6734ad8e5323fa
[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 )    -- this function wraps a server
98
99         local dispatch, disconnect = listener.listener, listener.disconnect    -- dangerous
100
101         local wrapclient, err
102
103         if sslctx then
104                 if not ssl_newcontext then
105                         return nil, "luasec not found"
106                 end
107                 if type( sslctx ) ~= "table" then
108                         out_error "server.lua: wrong server sslctx"
109                         return nil, "wrong server sslctx"
110                 end
111                 sslctx, err = ssl_newcontext( sslctx )
112                 if not sslctx then
113                         err = err or "wrong sslctx parameters"
114                         out_error( "server.lua: ", err )
115                         return nil, err
116                 end
117                 wrapclient = wrapsslclient
118                 wrapclient = wraptlsclient
119         else
120                 wrapclient = wraptcpclient
121         end
122
123         local accept = socket.accept
124         local close = socket.close
125
126         --// public methods of the object //--    
127
128         local handler = { }
129
130         handler.shutdown = function( ) end
131
132         --[[handler.listener = function( data, err )
133                 return ondata( handler, data, err )
134         end]]
135         handler.ssl = function( )
136                 return sslctx and true or false
137         end
138         handler.close = function( closed )
139                 _ = not closed and close( socket )
140                 writelen = removesocket( writelist, socket, writelen )
141                 readlen = removesocket( readlist, socket, readlen )
142                 socketlist[ socket ] = nil
143                 handler = nil
144         end
145         handler.ip = function( )
146                 return ip
147         end
148         handler.serverport = function( )
149                 return serverport
150         end
151         handler.socket = function( )
152                 return socket
153         end
154         handler.receivedata = function( )
155                 local client, err = accept( socket )    -- try to accept
156                 if client then
157                         local ip, clientport = client:getpeername( )
158                         client:settimeout( 0 )
159                         local handler, client, err = wrapclient( listener, client, ip, serverport, clientport, mode, sslctx )    -- wrap new client socket
160                         if err then    -- error while wrapping ssl socket
161                                 return false
162                         end
163                         out_put( "server.lua: accepted new client connection from ", ip, ":", clientport )
164                         return dispatch( handler )
165                 elseif err then    -- maybe timeout or something else
166                         out_put( "server.lua: error with new client connection: ", err )
167                         return false
168                 end
169         end
170         return handler
171 end
172
173 wrapsslclient = function( listener, socket, ip, serverport, clientport, mode, sslctx )    -- this function wraps a ssl cleint
174
175         local dispatch, disconnect = listener.listener, listener.disconnect
176
177         --// transform socket to ssl object //--
178
179         local err
180         socket, err = ssl_wrap( socket, sslctx )    -- wrap socket
181         if err then
182                 out_put( "server.lua: ssl error: ", err )
183                 return nil, nil, err    -- fatal error
184         end
185         socket:settimeout( 0 )
186
187         --// private closures of the object //--
188
189         local writequeue = { }    -- buffer for messages to send
190
191         local eol, fatal_send_error   -- end of buffer
192
193         local sstat, rstat = 0, 0
194
195         --// local import of socket methods //--
196
197         local send = socket.send
198         local receive = socket.receive
199         local close = socket.close
200         --local shutdown = socket.shutdown
201
202         --// public methods of the object //--
203
204         local handler = { }
205
206         handler.getstats = function( )
207                 return rstat, sstat
208         end
209
210         handler.listener = function( data, err )
211                 return listener( handler, data, err )
212         end
213         handler.ssl = function( )
214                 return true
215         end
216         handler.send = function( _, data, i, j )
217                         return send( socket, data, i, j )
218         end
219         handler.receive = function( pattern, prefix )
220                         return receive( socket, pattern, prefix )
221         end
222         handler.shutdown = function( pattern )
223                 --return shutdown( socket, pattern )
224         end
225         handler.close = function( closed )
226                 if eol and not fatal_send_error then handler._dispatchdata(); end
227                 close( socket )
228                 writelen = ( eol and removesocket( writelist, socket, writelen ) ) or writelen
229                 readlen = removesocket( readlist, socket, readlen )
230                 socketlist[ socket ] = nil
231                 out_put "server.lua: closed handler and removed socket from list"
232         end
233         handler.ip = function( )
234                 return ip
235         end
236         handler.serverport = function( )
237                 return serverport
238         end
239         handler.clientport = function( ) 
240                 return clientport
241         end
242
243         handler.write = function( data )
244                 if not eol then
245                         writelen = writelen + 1
246                         writelist[ writelen ] = socket
247                         eol = 0
248                 end
249                 eol = eol + 1
250                 writequeue[ eol ] = data
251         end
252         handler.writequeue = function( )
253                 return writequeue
254         end
255         handler.socket = function( )
256                 return socket
257         end
258         handler.mode = function( )
259                 return mode
260         end
261         handler._receivedata = function( )
262                 local data, err, part = receive( socket, mode )    -- receive data in "mode"
263                 if not err or ( err == "timeout" or err == "wantread" ) then    -- received something
264                         local data = data or part or ""
265                         local count = #data * STAT_UNIT
266                         rstat = rstat + count
267                         receivestat = receivestat + count
268                         out_put( "server.lua: read data '", data, "', error: ", err )
269                         return dispatch( handler, data, err )
270                 else    -- connections was closed or fatal error
271                         out_put( "server.lua: client ", ip, ":", clientport, " error: ", err )
272                         handler.close( )
273                         disconnect( handler, err )
274                         writequeue = nil
275                         handler = nil
276                         return false
277                 end
278         end
279         handler._dispatchdata = function( )    -- this function writes data to handlers
280                 local buffer = table_concat( writequeue, "", 1, eol )
281                 local succ, err, byte = send( socket, buffer )
282                 local count = ( succ or 0 ) * STAT_UNIT
283                 sstat = sstat + count
284                 sendstat = sendstat + count
285                 out_put( "server.lua: sended '", buffer, "', bytes: ", succ, ", error: ", err, ", part: ", byte, ", to: ", ip, ":", clientport )
286                 if succ then    -- sending succesful
287                         --writequeue = { }
288                         eol = nil
289                         writelen = removesocket( writelist, socket, writelen )    -- delete socket from writelist
290                         return true
291                 elseif byte and ( err == "timeout" or err == "wantwrite" ) then    -- want write
292                         buffer = string_sub( buffer, byte + 1, -1 )    -- new buffer
293                         writequeue[ 1 ] = buffer    -- insert new buffer in queue
294                         eol = 1
295                         return true
296                 else    -- connection was closed during sending or fatal error
297                         fatal_send_error = true;
298                         out_put( "server.lua: client ", ip, ":", clientport, " error: ", err )
299                         handler.close( )
300                         disconnect( handler, err )
301                         writequeue = nil
302                         handler = nil
303                         return false
304                 end
305         end
306
307         -- // COMPAT // --
308
309         handler.getIp = handler.ip
310         handler.getPort = handler.clientport
311
312         --// handshake //--
313
314         local wrote
315
316         handler.handshake = coroutine_wrap( function( client )
317                         local err
318                         for i = 1, 10 do    -- 10 handshake attemps
319                                 _, err = client:dohandshake( )
320                                 if not err then
321                                         out_put( "server.lua: ssl handshake done" )
322                                         writelen = ( wrote and removesocket( writelist, socket, writelen ) ) or writelen
323                                         handler.receivedata = handler._receivedata    -- when handshake is done, replace the handshake function with regular functions
324                                         handler.dispatchdata = handler._dispatchdata
325                                         return dispatch( handler )
326                                 else
327                                         out_put( "server.lua: error during ssl handshake: ", err )
328                                         if err == "wantwrite" then
329                                                 if wrote == nil then
330                                                         writelen = writelen + 1
331                                                         writelist[ writelen ] = client
332                                                         wrote = true
333                                                 end
334                                         end
335                                         coroutine_yield( handler, nil, err )    -- handshake not finished
336                                 end
337                         end
338                         _ = err ~= "closed" and close( socket )
339                         handler.close( )
340                         disconnect( handler, err )
341                         writequeue = nil
342                         handler = nil
343                         return false    -- handshake failed
344                 end
345         )
346         handler.receivedata = handler.handshake
347         handler.dispatchdata = handler.handshake
348
349         handler.handshake( socket )    -- do handshake
350
351         socketlist[ socket ] = handler
352         readlen = readlen + 1
353         readlist[ readlen ] = socket
354
355         return handler, socket
356 end
357
358 wraptlsclient = function( listener, socket, ip, serverport, clientport, mode, sslctx )    -- this function wraps a tls cleint
359
360         local dispatch, disconnect = listener.listener, listener.disconnect
361
362         --// transform socket to ssl object //--
363
364         local err
365
366         socket:settimeout( 0 )
367         --// private closures of the object //--
368
369         local writequeue = { }    -- buffer for messages to send
370
371         local eol, fatal_send_error   -- end of buffer
372
373         local sstat, rstat = 0, 0
374
375         --// local import of socket methods //--
376
377         local send = socket.send
378         local receive = socket.receive
379         local close = socket.close
380         --local shutdown = socket.shutdown
381
382         --// public methods of the object //--
383
384         local handler = { }
385
386         handler.getstats = function( )
387                 return rstat, sstat
388         end
389
390         handler.listener = function( data, err )
391                 return listener( handler, data, err )
392         end
393         handler.ssl = function( )
394                 return false
395         end
396         handler.send = function( _, data, i, j )
397                         return send( socket, data, i, j )
398         end
399         handler.receive = function( pattern, prefix )
400                         return receive( socket, pattern, prefix )
401         end
402         handler.shutdown = function( pattern )
403                 --return shutdown( socket, pattern )
404         end
405         handler.close = function( closed )
406                 if eol and not fatal_send_error then handler._dispatchdata(); end
407                 close( socket )
408                 writelen = ( eol and removesocket( writelist, socket, writelen ) ) or writelen
409                 readlen = removesocket( readlist, socket, readlen )
410                 socketlist[ socket ] = nil
411                 out_put "server.lua: closed handler and removed socket from list"
412         end
413         handler.ip = function( )
414                 return ip
415         end
416         handler.serverport = function( )
417                 return serverport
418         end
419         handler.clientport = function( ) 
420                 return clientport
421         end
422
423         handler.write = function( data )
424                 if not eol then
425                         writelen = writelen + 1
426                         writelist[ writelen ] = socket
427                         eol = 0
428                 end
429                 eol = eol + 1
430                 writequeue[ eol ] = data
431         end
432         handler.writequeue = function( )
433                 return writequeue
434         end
435         handler.socket = function( )
436                 return socket
437         end
438         handler.mode = function( )
439                 return mode
440         end
441         handler._receivedata = function( )
442                 local data, err, part = receive( socket, mode )    -- receive data in "mode"
443                 if not err or ( err == "timeout" or err == "wantread" ) then    -- received something
444                         local data = data or part or ""
445                         local count = #data * STAT_UNIT
446                         rstat = rstat + count
447                         receivestat = receivestat + count
448                         --out_put( "server.lua: read data '", data, "', error: ", err )
449                         return dispatch( handler, data, err )
450                 else    -- connections was closed or fatal error
451                         out_put( "server.lua: client ", ip, ":", clientport, " error: ", err )
452                         handler.close( )
453                         disconnect( handler, err )
454                         writequeue = nil
455                         handler = nil
456                         return false
457                 end
458         end
459         handler._dispatchdata = function( )    -- this function writes data to handlers
460                 local buffer = table_concat( writequeue, "", 1, eol )
461                 local succ, err, byte = send( socket, buffer )
462                 local count = ( succ or 0 ) * STAT_UNIT
463                 sstat = sstat + count
464                 sendstat = sendstat + count
465                 out_put( "server.lua: sended '", buffer, "', bytes: ", succ, ", error: ", err, ", part: ", byte, ", to: ", ip, ":", clientport )
466                 if succ then    -- sending succesful
467                         --writequeue = { }
468                         eol = nil
469                         writelen = removesocket( writelist, socket, writelen )    -- delete socket from writelist
470                         if handler.need_tls then
471                                 out_put("server.lua: connection is ready for tls handshake");
472                                 handler.starttls(true);
473                                 if handler.need_tls then
474                                         out_put("server.lua: uh-oh... we still want tls, something must be wrong");
475                                 end
476                         end
477                         return true
478                 elseif byte and ( err == "timeout" or err == "wantwrite" ) then    -- want write
479                         buffer = string_sub( buffer, byte + 1, -1 )    -- new buffer
480                         writequeue[ 1 ] = buffer    -- insert new buffer in queue
481                         eol = 1
482                         return true
483                 else    -- connection was closed during sending or fatal error
484                         fatal_send_error = true; -- :(
485                         out_put( "server.lua: client ", ip, ":", clientport, " error: ", err )
486                         handler.close( )
487                         disconnect( handler, err )
488                         writequeue = nil
489                         handler = nil
490                         return false
491                 end
492         end
493
494         handler.receivedata, handler.dispatchdata = handler._receivedata, handler._dispatchdata;
495         -- // COMPAT // --
496
497         handler.getIp = handler.ip
498         handler.getPort = handler.clientport
499
500         --// handshake //--
501
502         local wrote, read
503         
504         handler.starttls = function (now)
505                 if not now then out_put("server.lua: we need to do tls, but delaying until later"); handler.need_tls = true; return; end
506                 out_put( "server.lua: attempting to start tls on "..tostring(socket) )
507                 socket, err = ssl_wrap( socket, sslctx )    -- wrap socket
508                 out_put("sslwrapped socket is "..tostring(socket));
509                 if err then
510                         out_put( "server.lua: ssl error: ", err )
511                         return nil, nil, err    -- fatal error
512                 end
513                 socket:settimeout( 1 )
514                 send = socket.send
515                 receive = socket.receive
516                 close = socket.close
517                 handler.ssl = function( )
518                         return true
519                 end
520                 handler.send = function( _, data, i, j )
521                         return send( socket, data, i, j )
522                 end
523                 handler.receive = function( pattern, prefix )
524                         return receive( socket, pattern, prefix )
525                 end
526                 
527                 handler.starttls = nil;
528                 
529                         handler.handshake = coroutine_wrap( function( client )
530                                         local err
531                                         for i = 1, 10 do    -- 10 handshake attemps
532                                                 _, err = client:dohandshake( )
533                                                 if not err then
534                                                         out_put( "server.lua: ssl handshake done" )
535                                                         writelen = ( wrote and removesocket( writelist, socket, writelen ) ) or writelen
536                                                         handler.receivedata = handler._receivedata    -- when handshake is done, replace the handshake function with regular functions
537                                                         handler.dispatchdata = handler._dispatchdata
538                                                         handler.need_tls = nil
539                                                         socketlist[ client ] = handler
540                                                         readlen = readlen + 1
541                                                         readlist[ readlen ] = client                                                                                            
542                                                         return true;
543                                                 else
544                                                         out_put( "server.lua: error during ssl handshake: ", err )
545                                                         if err == "wantwrite" then
546                                                                 if wrote == nil then
547                                                                         writelen = writelen + 1
548                                                                         writelist[ writelen ] = client
549                                                                         wrote = true
550                                                                 end
551                                                         end
552                                                         coroutine_yield( handler, nil, err )    -- handshake not finished
553                                                 end
554                                         end
555                                         _ = err ~= "closed" and close( socket )
556                                         handler.close( )
557                                         disconnect( handler, err )
558                                         writequeue = nil
559                                         handler = nil
560                                         return false    -- handshake failed
561                                 end
562                         )
563                         handler.receivedata = handler.handshake
564                         handler.dispatchdata = handler.handshake
565
566                         handler.handshake( socket )    -- do handshake
567                 end
568         socketlist[ socket ] = handler
569         readlen = readlen + 1
570         readlist[ readlen ] = socket
571
572         return handler, socket
573 end
574
575 wraptcpclient = function( listener, socket, ip, serverport, clientport, mode )    -- this function wraps a socket
576
577         local dispatch, disconnect = listener.listener, listener.disconnect
578
579         --// private closures of the object //--
580
581         local writequeue = { }    -- list for messages to send
582
583         local eol, fatal_send_error
584
585         local rstat, sstat = 0, 0
586
587         --// local import of socket methods //--
588
589         local send = socket.send
590         local receive = socket.receive
591         local close = socket.close
592         local shutdown = socket.shutdown
593
594         --// public methods of the object //--
595
596         local handler = { }
597
598         handler.getstats = function( )
599                 return rstat, sstat
600         end
601
602         handler.listener = function( data, err )
603                 return listener( handler, data, err )
604         end
605         handler.ssl = function( )
606                 return false
607         end
608         handler.send = function( _, data, i, j )
609                         return send( socket, data, i, j )
610         end
611         handler.receive = function( pattern, prefix )
612                         return receive( socket, pattern, prefix )
613         end
614         handler.shutdown = function( pattern )
615                 return shutdown( socket, pattern )
616         end
617         handler.close = function( closed )
618                 if eol and not fatal_send_error then handler.dispatchdata(); end
619                 _ = not closed and shutdown( socket )
620                 _ = not closed and close( socket )
621                 writelen = ( eol and removesocket( writelist, socket, writelen ) ) or writelen
622                 readlen = removesocket( readlist, socket, readlen )
623                 socketlist[ socket ] = nil
624                 out_put "server.lua: closed handler and removed socket from list"
625         end
626         handler.ip = function( )
627                 return ip
628         end
629         handler.serverport = function( )
630                 return serverport
631         end
632         handler.clientport = function( ) 
633                 return clientport
634         end
635         handler.write = function( data )
636                 if not eol then
637                         writelen = writelen + 1
638                         writelist[ writelen ] = socket
639                         eol = 0
640                 end
641                 eol = eol + 1
642                 writequeue[ eol ] = data
643         end
644         handler.writequeue = function( )
645                 return writequeue
646         end
647         handler.socket = function( )
648                 return socket
649         end
650         handler.mode = function( )
651                 return mode
652         end
653         
654         handler.receivedata = function( )
655                 local data, err, part = receive( socket, mode )    -- receive data in "mode"
656                 if not err or ( err == "timeout" or err == "wantread" ) then    -- received something
657                         local data = data or part or ""
658                         local count = #data * STAT_UNIT
659                         rstat = rstat + count
660                         receivestat = receivestat + count
661                         out_put( "server.lua: read data '", data, "', error: ", err )
662                         return dispatch( handler, data, err )
663                 else    -- connections was closed or fatal error
664                         out_put( "server.lua: client ", ip, ":", clientport, " error: ", err )
665                         handler.close( )
666                         disconnect( handler, err )
667                         writequeue = nil
668                         handler = nil
669                         return false
670                 end
671         end
672         
673         handler.dispatchdata = function( )    -- this function writes data to handlers
674                 local buffer = table_concat( writequeue, "", 1, eol )
675                 local succ, err, byte = send( socket, buffer )
676                 local count = ( succ or 0 ) * STAT_UNIT
677                 sstat = sstat + count
678                 sendstat = sendstat + count
679                 out_put( "server.lua: sended '", buffer, "', bytes: ", succ, ", error: ", err, ", part: ", byte, ", to: ", ip, ":", clientport )
680                 if succ then    -- sending succesful
681                         --writequeue = { }
682                         eol = nil
683                         writelen = removesocket( writelist, socket, writelen )    -- delete socket from writelist
684                         return true
685                 elseif byte and ( err == "timeout" or err == "wantwrite" ) then    -- want write
686                         buffer = string_sub( buffer, byte + 1, -1 )    -- new buffer
687                         writequeue[ 1 ] = buffer    -- insert new buffer in queue
688                         eol = 1
689                         return true
690                 else    -- connection was closed during sending or fatal error
691                         fatal_send_error = true; -- :'-(
692                         out_put( "server.lua: client ", ip, ":", clientport, " error: ", err )
693                         handler.close( )
694                         disconnect( handler, err )
695                         writequeue = nil
696                         handler = nil
697                         return false
698                 end
699         end
700
701         -- // COMPAT // --
702
703         handler.getIp = handler.ip
704         handler.getPort = handler.clientport
705
706         socketlist[ socket ] = handler
707         readlen = readlen + 1
708         readlist[ readlen ] = socket
709
710         return handler, socket
711 end
712
713 addtimer = function( listener )
714         timelistener[ #timelistener + 1 ] = listener
715 end
716
717 firetimer = function( listener )
718         for i, listener in ipairs( timelistener ) do
719                 listener( )
720         end
721 end
722
723 addserver = function( listeners, port, addr, mode, sslctx )    -- this function provides a way for other scripts to reg a server
724         local err
725         if type( listeners ) ~= "table" then
726                 err = "invalid listener table"
727         else
728                 for name, func in pairs( listeners ) do
729                         if type( func ) ~= "function" then
730                                 --err = "invalid listener function"
731                                 break
732                         end
733                 end
734         end
735         if not type( port ) == "number" or not ( port >= 0 and port <= 65535 ) then
736                 err = "invalid port"
737         elseif listener[ port ] then
738                 err=  "listeners on port '" .. port .. "' already exist"
739         elseif sslctx and not luasec then
740                 err = "luasec not found"
741         end
742         if err then
743                 out_error( "server.lua: ", err )
744                 return nil, err
745         end
746         addr = addr or "*"
747         local server, err = socket_bind( addr, port )
748         if err then
749                 out_error( "server.lua: ", err )
750                 return nil, err
751         end
752         local handler, err = wrapserver( listeners, server, addr, port, mode, sslctx )    -- wrap new server socket
753         if not handler then
754                 server:close( )
755                 return nil, err
756         end
757         server:settimeout( 0 )
758         readlen = readlen + 1
759         readlist[ readlen ] = server
760         listener[ port ] = listeners
761         socketlist[ server ] = handler
762         out_put( "server.lua: new server listener on ", addr, ":", port )
763         return true
764 end
765
766 removesocket = function( tbl, socket, len )    -- this function removes sockets from a list
767         for i, target in ipairs( tbl ) do
768                 if target == socket then
769                         len = len - 1
770                         table_remove( tbl, i )
771                         return len
772                 end
773         end
774         return len
775 end
776
777 closeall = function( )
778         for sock, handler in pairs( socketlist ) do
779                 handler.shutdown( )
780                 handler.close( )
781                 socketlist[ sock ] = nil
782         end
783         writelist, readlist, socketlist = { }, { }, { }
784 end
785
786 closesocket = function( socket )
787         writelen = removesocket( writelist, socket, writelen )
788         readlen = removesocket( readlist, socket, readlen )
789         socketlist[ socket ] = nil
790         socket:close( )
791 end
792
793 loop = function( )    -- this is the main loop of the program
794         --signal_set( "hub", "run" )
795         repeat
796                 --[[print(readlen, writelen)
797                 for _, s in ipairs(readlist) do print("R:", tostring(s)) end
798                 for _, s in ipairs(writelist) do print("W:", tostring(s)) end
799                 out_put("select()"..os.time())]]
800                 local read, write, err = socket_select( readlist, writelist, 1 )    -- 1 sec timeout, nice for timers
801                 for i, socket in ipairs( write ) do    -- send data waiting in writequeues
802                         local handler = socketlist[ socket ]
803                         if handler then
804                                 handler.dispatchdata( )
805                         else
806                                 closesocket( socket )
807                                 out_put "server.lua: found no handler and closed socket (writelist)"    -- this should not happen
808                         end
809                 end
810                 for i, socket in ipairs( read ) do    -- receive data
811                         local handler = socketlist[ socket ]
812                         if handler then
813                                 handler.receivedata( )
814                         else
815                                 closesocket( socket )
816                                 out_put "server.lua: found no handler and closed socket (readlist)"    -- this can happen
817                         end
818                 end
819                 firetimer( )
820         until false
821         return
822 end
823
824 ----------------------------------// BEGIN //--
825
826 ----------------------------------// PUBLIC INTERFACE //--
827
828 return {
829
830         add = addserver,
831         loop = loop,
832         stats = stats,
833         closeall = closeall,
834         addtimer = addtimer,
835         wraptlsclient = wraptlsclient,
836 }