Comparison

net/server_event.lua @ 7224:07a4c807a94a

Merge 0.9->0.10
author Kim Alvefur <zash@zash.se>
date Wed, 02 Mar 2016 16:32:37 +0100
parent 7040:bdcea2dd33b8
parent 7223:f911f929ca6c
child 7225:a74f0b7be6bf
child 7336:0d9ac472e58c
comparison
equal deleted inserted replaced
7218:6226307f6ac4 7224:07a4c807a94a
90 local interfacelist = { } 90 local interfacelist = { }
91 91
92 -- Client interface methods 92 -- Client interface methods
93 local interface_mt = {}; interface_mt.__index = interface_mt; 93 local interface_mt = {}; interface_mt.__index = interface_mt;
94 94
95 -- Private methods 95 -- Private methods
96 function interface_mt:_close() 96 function interface_mt:_close()
97 return self:_destroy(); 97 return self:_destroy();
98 end 98 end
99 99
100 function interface_mt:_start_connection(plainssl) -- should be called from addclient 100 function interface_mt:_start_connection(plainssl) -- should be called from addclient
101 local callback = function( event ) 101 local callback = function( event )
102 if EV_TIMEOUT == event then -- timeout during connection 102 if EV_TIMEOUT == event then -- timeout during connection
103 self.fatalerror = "connection timeout" 103 self.fatalerror = "connection timeout"
104 self:ontimeout() -- call timeout listener 104 self:ontimeout() -- call timeout listener
105 self:_close() 105 self:_close()
106 debug( "new connection failed. id:", self.id, "error:", self.fatalerror ) 106 debug( "new connection failed. id:", self.id, "error:", self.fatalerror )
107 else
108 if plainssl and has_luasec then -- start ssl session
109 self:starttls(self._sslctx, true)
110 else -- normal connection
111 self:_start_session(true)
112 end
113 debug( "new connection established. id:", self.id )
114 end
115 self.eventconnect = nil
116 return -1
117 end
118 self.eventconnect = addevent( base, self.conn, EV_WRITE, callback, cfg.CONNECT_TIMEOUT )
119 return true
120 end
121 function interface_mt:_start_session(call_onconnect) -- new session, for example after startssl
122 if self.type == "client" then
123 local callback = function( )
124 self:_lock( false, false, false )
125 --vdebug( "start listening on client socket with id:", self.id )
126 self.eventread = addevent( base, self.conn, EV_READ, self.readcallback, cfg.READ_TIMEOUT ); -- register callback
127 if call_onconnect then
128 self:onconnect()
129 end
130 self.eventsession = nil
131 return -1
132 end
133 self.eventsession = addevent( base, nil, EV_TIMEOUT, callback, 0 )
107 else 134 else
108 if plainssl and has_luasec then -- start ssl session 135 self:_lock( false )
109 self:starttls(self._sslctx, true) 136 --vdebug( "start listening on server socket with id:", self.id )
110 else -- normal connection 137 self.eventread = addevent( base, self.conn, EV_READ, self.readcallback ) -- register callback
111 self:_start_session(true) 138 end
112 end 139 return true
113 debug( "new connection established. id:", self.id ) 140 end
114 end 141 function interface_mt:_start_ssl(call_onconnect) -- old socket will be destroyed, therefore we have to close read/write events first
115 self.eventconnect = nil 142 --vdebug( "starting ssl session with client id:", self.id )
116 return -1 143 local _
117 end 144 _ = self.eventread and self.eventread:close( ) -- close events; this must be called outside of the event callbacks!
118 self.eventconnect = addevent( base, self.conn, EV_WRITE, callback, cfg.CONNECT_TIMEOUT ) 145 _ = self.eventwrite and self.eventwrite:close( )
119 return true 146 self.eventread, self.eventwrite = nil, nil
120 end 147 local err
121 function interface_mt:_start_session(call_onconnect) -- new session, for example after startssl 148 self.conn, err = ssl.wrap( self.conn, self._sslctx )
122 if self.type == "client" then 149 if err then
123 local callback = function( ) 150 self.fatalerror = err
124 self:_lock( false, false, false ) 151 self.conn = nil -- cannot be used anymore
125 --vdebug( "start listening on client socket with id:", self.id )
126 self.eventread = addevent( base, self.conn, EV_READ, self.readcallback, cfg.READ_TIMEOUT ); -- register callback
127 if call_onconnect then
128 self:onconnect()
129 end
130 self.eventsession = nil
131 return -1
132 end
133 self.eventsession = addevent( base, nil, EV_TIMEOUT, callback, 0 )
134 else
135 self:_lock( false )
136 --vdebug( "start listening on server socket with id:", self.id )
137 self.eventread = addevent( base, self.conn, EV_READ, self.readcallback ) -- register callback
138 end
139 return true
140 end
141 function interface_mt:_start_ssl(call_onconnect) -- old socket will be destroyed, therefore we have to close read/write events first
142 --vdebug( "starting ssl session with client id:", self.id )
143 local _
144 _ = self.eventread and self.eventread:close( ) -- close events; this must be called outside of the event callbacks!
145 _ = self.eventwrite and self.eventwrite:close( )
146 self.eventread, self.eventwrite = nil, nil
147 local err
148 self.conn, err = ssl.wrap( self.conn, self._sslctx )
149 if err then
150 self.fatalerror = err
151 self.conn = nil -- cannot be used anymore
152 if call_onconnect then
153 self.ondisconnect = nil -- dont call this when client isnt really connected
154 end
155 self:_close()
156 debug( "fatal error while ssl wrapping:", err )
157 return false
158 end
159 self.conn:settimeout( 0 ) -- set non blocking
160 local handshakecallback = coroutine_wrap(function( event )
161 local _, err
162 local attempt = 0
163 local maxattempt = cfg.MAX_HANDSHAKE_ATTEMPTS
164 while attempt < maxattempt do -- no endless loop
165 attempt = attempt + 1
166 debug( "ssl handshake of client with id:"..tostring(self)..", attempt:"..attempt )
167 if attempt > maxattempt then
168 self.fatalerror = "max handshake attempts exceeded"
169 elseif EV_TIMEOUT == event then
170 self.fatalerror = "timeout during handshake"
171 else
172 _, err = self.conn:dohandshake( )
173 if not err then
174 self:_lock( false, false, false ) -- unlock the interface; sending, closing etc allowed
175 self.send = self.conn.send -- caching table lookups with new client object
176 self.receive = self.conn.receive
177 if not call_onconnect then -- trigger listener
178 self:onstatus("ssl-handshake-complete");
179 end
180 self:_start_session( call_onconnect )
181 debug( "ssl handshake done" )
182 self.eventhandshake = nil
183 return -1
184 end
185 if err == "wantwrite" then
186 event = EV_WRITE
187 elseif err == "wantread" then
188 event = EV_READ
189 else
190 debug( "ssl handshake error:", err )
191 self.fatalerror = err
192 end
193 end
194 if self.fatalerror then
195 if call_onconnect then 152 if call_onconnect then
196 self.ondisconnect = nil -- dont call this when client isnt really connected 153 self.ondisconnect = nil -- dont call this when client isnt really connected
197 end 154 end
198 self:_close() 155 self:_close()
199 debug( "handshake failed because:", self.fatalerror ) 156 debug( "fatal error while ssl wrapping:", err )
200 self.eventhandshake = nil 157 return false
201 return -1 158 end
202 end 159 self.conn:settimeout( 0 ) -- set non blocking
203 event = coroutine_yield( event, cfg.HANDSHAKE_TIMEOUT ) -- yield this monster... 160 local handshakecallback = coroutine_wrap(function( event )
204 end 161 local _, err
205 end 162 local attempt = 0
206 ) 163 local maxattempt = cfg.MAX_HANDSHAKE_ATTEMPTS
207 debug "starting handshake..." 164 while attempt < maxattempt do -- no endless loop
208 self:_lock( false, true, true ) -- unlock read/write events, but keep interface locked 165 attempt = attempt + 1
209 self.eventhandshake = addevent( base, self.conn, EV_READWRITE, handshakecallback, cfg.HANDSHAKE_TIMEOUT ) 166 debug( "ssl handshake of client with id:"..tostring(self)..", attempt:"..attempt )
210 return true 167 if attempt > maxattempt then
211 end 168 self.fatalerror = "max handshake attempts exceeded"
212 function interface_mt:_destroy() -- close this interface + events and call last listener 169 elseif EV_TIMEOUT == event then
213 debug( "closing client with id:", self.id, self.fatalerror ) 170 self.fatalerror = "timeout during handshake"
214 self:_lock( true, true, true ) -- first of all, lock the interface to avoid further actions 171 else
215 local _ 172 _, err = self.conn:dohandshake( )
216 _ = self.eventread and self.eventread:close( ) 173 if not err then
217 if self.type == "client" then 174 self:_lock( false, false, false ) -- unlock the interface; sending, closing etc allowed
218 _ = self.eventwrite and self.eventwrite:close( ) 175 self.send = self.conn.send -- caching table lookups with new client object
219 _ = self.eventhandshake and self.eventhandshake:close( ) 176 self.receive = self.conn.receive
220 _ = self.eventstarthandshake and self.eventstarthandshake:close( ) 177 if not call_onconnect then -- trigger listener
221 _ = self.eventconnect and self.eventconnect:close( ) 178 self:onstatus("ssl-handshake-complete");
222 _ = self.eventsession and self.eventsession:close( ) 179 end
223 _ = self.eventwritetimeout and self.eventwritetimeout:close( ) 180 self:_start_session( call_onconnect )
224 _ = self.eventreadtimeout and self.eventreadtimeout:close( ) 181 debug( "ssl handshake done" )
225 _ = self.ondisconnect and self:ondisconnect( self.fatalerror ~= "client to close" and self.fatalerror) -- call ondisconnect listener (wont be the case if handshake failed on connect) 182 self.eventhandshake = nil
226 _ = self.conn and self.conn:close( ) -- close connection 183 return -1
227 _ = self._server and self._server:counter(-1); 184 end
228 self.eventread, self.eventwrite = nil, nil 185 if err == "wantwrite" then
229 self.eventstarthandshake, self.eventhandshake, self.eventclose = nil, nil, nil 186 event = EV_WRITE
230 self.readcallback, self.writecallback = nil, nil 187 elseif err == "wantread" then
231 else 188 event = EV_READ
232 self.conn:close( ) 189 else
233 self.eventread, self.eventclose = nil, nil 190 debug( "ssl handshake error:", err )
234 self.interface, self.readcallback = nil, nil 191 self.fatalerror = err
235 end 192 end
193 end
194 if self.fatalerror then
195 if call_onconnect then
196 self.ondisconnect = nil -- dont call this when client isnt really connected
197 end
198 self:_close()
199 debug( "handshake failed because:", self.fatalerror )
200 self.eventhandshake = nil
201 return -1
202 end
203 event = coroutine_yield( event, cfg.HANDSHAKE_TIMEOUT ) -- yield this monster...
204 end
205 end
206 )
207 debug "starting handshake..."
208 self:_lock( false, true, true ) -- unlock read/write events, but keep interface locked
209 self.eventhandshake = addevent( base, self.conn, EV_READWRITE, handshakecallback, cfg.HANDSHAKE_TIMEOUT )
210 return true
211 end
212 function interface_mt:_destroy() -- close this interface + events and call last listener
213 debug( "closing client with id:", self.id, self.fatalerror )
214 self:_lock( true, true, true ) -- first of all, lock the interface to avoid further actions
215 local _
216 _ = self.eventread and self.eventread:close( )
217 if self.type == "client" then
218 _ = self.eventwrite and self.eventwrite:close( )
219 _ = self.eventhandshake and self.eventhandshake:close( )
220 _ = self.eventstarthandshake and self.eventstarthandshake:close( )
221 _ = self.eventconnect and self.eventconnect:close( )
222 _ = self.eventsession and self.eventsession:close( )
223 _ = self.eventwritetimeout and self.eventwritetimeout:close( )
224 _ = self.eventreadtimeout and self.eventreadtimeout:close( )
225 _ = self.ondisconnect and self:ondisconnect( self.fatalerror ~= "client to close" and self.fatalerror) -- call ondisconnect listener (wont be the case if handshake failed on connect)
226 _ = self.conn and self.conn:close( ) -- close connection
227 _ = self._server and self._server:counter(-1);
228 self.eventread, self.eventwrite = nil, nil
229 self.eventstarthandshake, self.eventhandshake, self.eventclose = nil, nil, nil
230 self.readcallback, self.writecallback = nil, nil
231 else
232 self.conn:close( )
233 self.eventread, self.eventclose = nil, nil
234 self.interface, self.readcallback = nil, nil
235 end
236 interfacelist[ self ] = nil 236 interfacelist[ self ] = nil
237 return true 237 return true
238 end 238 end
239 239
240 function interface_mt:_lock(nointerface, noreading, nowriting) -- lock or unlock this interface or events 240 function interface_mt:_lock(nointerface, noreading, nowriting) -- lock or unlock this interface or events
241 self.nointerface, self.noreading, self.nowriting = nointerface, noreading, nowriting 241 self.nointerface, self.noreading, self.nowriting = nointerface, noreading, nowriting
242 return nointerface, noreading, nowriting 242 return nointerface, noreading, nowriting
243 end 243 end
244 244
245 --TODO: Deprecate 245 --TODO: Deprecate
246 function interface_mt:lock_read(switch) 246 function interface_mt:lock_read(switch)
247 if switch then 247 if switch then
248 return self:pause(); 248 return self:pause();
249 else 249 else
250 return self:resume(); 250 return self:resume();
251 end 251 end
252 end 252 end
253 253
254 function interface_mt:pause() 254 function interface_mt:pause()
255 return self:_lock(self.nointerface, true, self.nowriting); 255 return self:_lock(self.nointerface, true, self.nowriting);
256 end 256 end
257 257
258 function interface_mt:resume() 258 function interface_mt:resume()
259 self:_lock(self.nointerface, false, self.nowriting); 259 self:_lock(self.nointerface, false, self.nowriting);
260 if not self.eventread then 260 if self.readcallback and not self.eventread then
261 self.eventread = addevent( base, self.conn, EV_READ, self.readcallback, cfg.READ_TIMEOUT ); -- register callback 261 self.eventread = addevent( base, self.conn, EV_READ, self.readcallback, cfg.READ_TIMEOUT ); -- register callback
262 end 262 return true;
263 end 263 end
264 264 end
265 function interface_mt:counter(c) 265
266 if c then 266 function interface_mt:counter(c)
267 self._connections = self._connections + c 267 if c then
268 end 268 self._connections = self._connections + c
269 return self._connections 269 end
270 end 270 return self._connections
271 271 end
272 -- Public methods 272
273 function interface_mt:write(data) 273 -- Public methods
274 if self.nowriting then return nil, "locked" end 274 function interface_mt:write(data)
275 --vdebug( "try to send data to client, id/data:", self.id, data ) 275 if self.nowriting then return nil, "locked" end
276 data = tostring( data ) 276 --vdebug( "try to send data to client, id/data:", self.id, data )
277 local len = #data 277 data = tostring( data )
278 local total = len + self.writebufferlen 278 local len = #data
279 if total > cfg.MAX_SEND_LENGTH then -- check buffer length 279 local total = len + self.writebufferlen
280 local err = "send buffer exceeded" 280 if total > cfg.MAX_SEND_LENGTH then -- check buffer length
281 debug( "error:", err ) -- to much, check your app 281 local err = "send buffer exceeded"
282 return nil, err 282 debug( "error:", err ) -- to much, check your app
283 end 283 return nil, err
284 t_insert(self.writebuffer, data) -- new buffer 284 end
285 self.writebufferlen = total 285 t_insert(self.writebuffer, data) -- new buffer
286 if not self.eventwrite then -- register new write event 286 self.writebufferlen = total
287 --vdebug( "register new write event" ) 287 if not self.eventwrite then -- register new write event
288 self.eventwrite = addevent( base, self.conn, EV_WRITE, self.writecallback, cfg.WRITE_TIMEOUT ) 288 --vdebug( "register new write event" )
289 end 289 self.eventwrite = addevent( base, self.conn, EV_WRITE, self.writecallback, cfg.WRITE_TIMEOUT )
290 return true 290 end
291 end 291 return true
292 function interface_mt:close() 292 end
293 if self.nointerface then return nil, "locked"; end 293 function interface_mt:close()
294 debug( "try to close client connection with id:", self.id ) 294 if self.nointerface then return nil, "locked"; end
295 if self.type == "client" then 295 debug( "try to close client connection with id:", self.id )
296 self.fatalerror = "client to close" 296 if self.type == "client" then
297 if self.eventwrite then -- wait for incomplete write request 297 self.fatalerror = "client to close"
298 if self.eventwrite then -- wait for incomplete write request
299 self:_lock( true, true, false )
300 debug "closing delayed until writebuffer is empty"
301 return nil, "writebuffer not empty, waiting"
302 else -- close now
303 self:_lock( true, true, true )
304 self:_close()
305 return true
306 end
307 else
308 debug( "try to close server with id:", tostring(self.id))
309 self.fatalerror = "server to close"
310 self:_lock( true )
311 self:_close( 0 )
312 return true
313 end
314 end
315
316 function interface_mt:socket()
317 return self.conn
318 end
319
320 function interface_mt:server()
321 return self._server or self;
322 end
323
324 function interface_mt:port()
325 return self._port
326 end
327
328 function interface_mt:serverport()
329 return self._serverport
330 end
331
332 function interface_mt:ip()
333 return self._ip
334 end
335
336 function interface_mt:ssl()
337 return self._usingssl
338 end
339 interface_mt.clientport = interface_mt.port -- COMPAT server_select
340
341 function interface_mt:type()
342 return self._type or "client"
343 end
344
345 function interface_mt:connections()
346 return self._connections
347 end
348
349 function interface_mt:address()
350 return self.addr
351 end
352
353 function interface_mt:set_sslctx(sslctx)
354 self._sslctx = sslctx;
355 if sslctx then
356 self.starttls = nil; -- use starttls() of interface_mt
357 else
358 self.starttls = false; -- prevent starttls()
359 end
360 end
361
362 function interface_mt:set_mode(pattern)
363 if pattern then
364 self._pattern = pattern;
365 end
366 return self._pattern;
367 end
368
369 function interface_mt:set_send(new_send) -- luacheck: ignore 212
370 -- No-op, we always use the underlying connection's send
371 end
372
373 function interface_mt:starttls(sslctx, call_onconnect)
374 debug( "try to start ssl at client id:", self.id )
375 local err
376 self._sslctx = sslctx;
377 if self._usingssl then -- startssl was already called
378 err = "ssl already active"
379 end
380 if err then
381 debug( "error:", err )
382 return nil, err
383 end
384 self._usingssl = true
385 self.startsslcallback = function( ) -- we have to start the handshake outside of a read/write event
386 self.startsslcallback = nil
387 self:_start_ssl(call_onconnect);
388 self.eventstarthandshake = nil
389 return -1
390 end
391 if not self.eventwrite then
392 self:_lock( true, true, true ) -- lock the interface, to not disturb the handshake
393 self.eventstarthandshake = addevent( base, nil, EV_TIMEOUT, self.startsslcallback, 0 ) -- add event to start handshake
394 else -- wait until writebuffer is empty
298 self:_lock( true, true, false ) 395 self:_lock( true, true, false )
299 debug "closing delayed until writebuffer is empty" 396 debug "ssl session delayed until writebuffer is empty..."
300 return nil, "writebuffer not empty, waiting" 397 end
301 else -- close now 398 self.starttls = false;
302 self:_lock( true, true, true )
303 self:_close()
304 return true
305 end
306 else
307 debug( "try to close server with id:", tostring(self.id))
308 self.fatalerror = "server to close"
309 self:_lock( true )
310 self:_close( 0 )
311 return true 399 return true
312 end 400 end
313 end 401
314 402 function interface_mt:setoption(option, value)
315 function interface_mt:socket() 403 if self.conn.setoption then
316 return self.conn 404 return self.conn:setoption(option, value);
317 end 405 end
318 406 return false, "setoption not implemented";
319 function interface_mt:server() 407 end
320 return self._server or self; 408
321 end 409 function interface_mt:setlistener(listener)
322 410 self:ondetach(); -- Notify listener that it is no longer responsible for this connection
323 function interface_mt:port()
324 return self._port
325 end
326
327 function interface_mt:serverport()
328 return self._serverport
329 end
330
331 function interface_mt:ip()
332 return self._ip
333 end
334
335 function interface_mt:ssl()
336 return self._usingssl
337 end
338 interface_mt.clientport = interface_mt.port -- COMPAT server_select
339
340 function interface_mt:type()
341 return self._type or "client"
342 end
343
344 function interface_mt:connections()
345 return self._connections
346 end
347
348 function interface_mt:address()
349 return self.addr
350 end
351
352 function interface_mt:set_sslctx(sslctx)
353 self._sslctx = sslctx;
354 if sslctx then
355 self.starttls = nil; -- use starttls() of interface_mt
356 else
357 self.starttls = false; -- prevent starttls()
358 end
359 end
360
361 function interface_mt:set_mode(pattern)
362 if pattern then
363 self._pattern = pattern;
364 end
365 return self._pattern;
366 end
367
368 function interface_mt:set_send(new_send) -- luacheck: ignore 212
369 -- No-op, we always use the underlying connection's send
370 end
371
372 function interface_mt:starttls(sslctx, call_onconnect)
373 debug( "try to start ssl at client id:", self.id )
374 local err
375 self._sslctx = sslctx;
376 if self._usingssl then -- startssl was already called
377 err = "ssl already active"
378 end
379 if err then
380 debug( "error:", err )
381 return nil, err
382 end
383 self._usingssl = true
384 self.startsslcallback = function( ) -- we have to start the handshake outside of a read/write event
385 self.startsslcallback = nil
386 self:_start_ssl(call_onconnect);
387 self.eventstarthandshake = nil
388 return -1
389 end
390 if not self.eventwrite then
391 self:_lock( true, true, true ) -- lock the interface, to not disturb the handshake
392 self.eventstarthandshake = addevent( base, nil, EV_TIMEOUT, self.startsslcallback, 0 ) -- add event to start handshake
393 else -- wait until writebuffer is empty
394 self:_lock( true, true, false )
395 debug "ssl session delayed until writebuffer is empty..."
396 end
397 self.starttls = false;
398 return true
399 end
400
401 function interface_mt:setoption(option, value)
402 if self.conn.setoption then
403 return self.conn:setoption(option, value);
404 end
405 return false, "setoption not implemented";
406 end
407
408 function interface_mt:setlistener(listener)
409 self:ondetach(); -- Notify listener that it is no longer responsible for this connection
410 self.onconnect, self.ondisconnect, self.onincoming, self.ontimeout, 411 self.onconnect, self.ondisconnect, self.onincoming, self.ontimeout,
411 self.onreadtimeout, self.onstatus, self.ondetach 412 self.onreadtimeout, self.onstatus, self.ondetach
412 = listener.onconnect, listener.ondisconnect, listener.onincoming, listener.ontimeout, 413 = listener.onconnect, listener.ondisconnect, listener.onincoming, listener.ontimeout,
413 listener.onreadtimeout, listener.onstatus, listener.ondetach; 414 listener.onreadtimeout, listener.onstatus, listener.ondetach;
414 end 415 end
415 416
416 -- Stub handlers 417 -- Stub handlers
417 function interface_mt:onconnect() 418 function interface_mt:onconnect()
418 end 419 end
419 function interface_mt:onincoming() 420 function interface_mt:onincoming()
420 end 421 end
421 function interface_mt:ondisconnect() 422 function interface_mt:ondisconnect()
422 end 423 end
423 function interface_mt:ontimeout() 424 function interface_mt:ontimeout()
424 end 425 end
425 function interface_mt:onreadtimeout() 426 function interface_mt:onreadtimeout()
426 self.fatalerror = "timeout during receiving" 427 self.fatalerror = "timeout during receiving"
427 debug( "connection failed:", self.fatalerror ) 428 debug( "connection failed:", self.fatalerror )
428 self:_close() 429 self:_close()
429 self.eventread = nil 430 self.eventread = nil
430 end 431 end
431 function interface_mt:ondrain() 432 function interface_mt:ondrain()
432 end 433 end
433 function interface_mt:ondetach() 434 function interface_mt:ondetach()
434 end 435 end
435 function interface_mt:onstatus() 436 function interface_mt:onstatus()
436 end 437 end
437 438
438 -- End of client interface methods 439 -- End of client interface methods
439 440
440 local function handleclient( client, ip, port, server, pattern, listener, sslctx ) -- creates an client interface 441 local function handleclient( client, ip, port, server, pattern, listener, sslctx ) -- creates an client interface
441 --vdebug("creating client interfacce...") 442 --vdebug("creating client interfacce...")
442 local interface = { 443 local interface = {
443 type = "client"; 444 type = "client";
444 conn = client; 445 conn = client;
445 currenttime = socket_gettime( ); -- safe the origin 446 currenttime = socket_gettime( ); -- safe the origin
446 writebuffer = {}; -- writebuffer 447 writebuffer = {}; -- writebuffer
447 writebufferlen = 0; -- length of writebuffer 448 writebufferlen = 0; -- length of writebuffer
448 send = client.send; -- caching table lookups 449 send = client.send; -- caching table lookups
449 receive = client.receive; 450 receive = client.receive;
450 onconnect = listener.onconnect; -- will be called when client disconnects 451 onconnect = listener.onconnect; -- will be called when client disconnects
451 ondisconnect = listener.ondisconnect; -- will be called when client disconnects 452 ondisconnect = listener.ondisconnect; -- will be called when client disconnects
452 onincoming = listener.onincoming; -- will be called when client sends data 453 onincoming = listener.onincoming; -- will be called when client sends data
453 ontimeout = listener.ontimeout; -- called when fatal socket timeout occurs 454 ontimeout = listener.ontimeout; -- called when fatal socket timeout occurs
454 onreadtimeout = listener.onreadtimeout; -- called when socket inactivity timeout occurs 455 onreadtimeout = listener.onreadtimeout; -- called when socket inactivity timeout occurs
455 ondrain = listener.ondrain; -- called when writebuffer is empty 456 ondrain = listener.ondrain; -- called when writebuffer is empty
456 ondetach = listener.ondetach; -- called when disassociating this listener from this connection 457 ondetach = listener.ondetach; -- called when disassociating this listener from this connection
457 onstatus = listener.onstatus; -- called for status changes (e.g. of SSL/TLS) 458 onstatus = listener.onstatus; -- called for status changes (e.g. of SSL/TLS)
458 eventread = false, eventwrite = false, eventclose = false, 459 eventread = false, eventwrite = false, eventclose = false,
459 eventhandshake = false, eventstarthandshake = false; -- event handler 460 eventhandshake = false, eventstarthandshake = false; -- event handler
460 eventconnect = false, eventsession = false; -- more event handler... 461 eventconnect = false, eventsession = false; -- more event handler...
461 eventwritetimeout = false; -- even more event handler... 462 eventwritetimeout = false; -- even more event handler...
462 eventreadtimeout = false; 463 eventreadtimeout = false;
463 fatalerror = false; -- error message 464 fatalerror = false; -- error message
464 writecallback = false; -- will be called on write events 465 writecallback = false; -- will be called on write events
465 readcallback = false; -- will be called on read events 466 readcallback = false; -- will be called on read events
466 nointerface = true; -- lock/unlock parameter of this interface 467 nointerface = true; -- lock/unlock parameter of this interface
467 noreading = false, nowriting = false; -- locks of the read/writecallback 468 noreading = false, nowriting = false; -- locks of the read/writecallback
468 startsslcallback = false; -- starting handshake callback 469 startsslcallback = false; -- starting handshake callback
469 position = false; -- position of client in interfacelist 470 position = false; -- position of client in interfacelist
470 471
471 -- Properties 472 -- Properties
472 _ip = ip, _port = port, _server = server, _pattern = pattern, 473 _ip = ip, _port = port, _server = server, _pattern = pattern,
473 _serverport = (server and server:port() or nil), 474 _serverport = (server and server:port() or nil),
474 _sslctx = sslctx; -- parameters 475 _sslctx = sslctx; -- parameters
475 _usingssl = false; -- client is using ssl; 476 _usingssl = false; -- client is using ssl;
476 } 477 }
477 if not has_luasec then interface.starttls = false; end 478 if not has_luasec then interface.starttls = false; end
478 interface.id = tostring(interface):match("%x+$"); 479 interface.id = tostring(interface):match("%x+$");
479 interface.writecallback = function( event ) -- called on write events 480 interface.writecallback = function( event ) -- called on write events
480 --vdebug( "new client write event, id/ip/port:", interface, ip, port ) 481 --vdebug( "new client write event, id/ip/port:", interface, ip, port )
481 if interface.nowriting or ( interface.fatalerror and ( "client to close" ~= interface.fatalerror ) ) then -- leave this event 482 if interface.nowriting or ( interface.fatalerror and ( "client to close" ~= interface.fatalerror ) ) then -- leave this event
482 --vdebug( "leaving this event because:", interface.nowriting or interface.fatalerror ) 483 --vdebug( "leaving this event because:", interface.nowriting or interface.fatalerror )
483 interface.eventwrite = false 484 interface.eventwrite = false
484 return -1
485 end
486 if EV_TIMEOUT == event then -- took too long to write some data to socket -> disconnect
487 interface.fatalerror = "timeout during writing"
488 debug( "writing failed:", interface.fatalerror )
489 interface:_close()
490 interface.eventwrite = false
491 return -1
492 else -- can write :)
493 if interface._usingssl then -- handle luasec
494 if interface.eventreadtimeout then -- we have to read first
495 local ret = interface.readcallback( ) -- call readcallback
496 --vdebug( "tried to read in writecallback, result:", ret )
497 end
498 if interface.eventwritetimeout then -- luasec only
499 interface.eventwritetimeout:close( ) -- first we have to close timeout event which where regged after a wantread error
500 interface.eventwritetimeout = false
501 end
502 end
503 interface.writebuffer = { t_concat(interface.writebuffer) }
504 local succ, err, byte = interface.conn:send( interface.writebuffer[1], 1, interface.writebufferlen )
505 --vdebug( "write data:", interface.writebuffer, "error:", err, "part:", byte )
506 if succ then -- writing succesful
507 interface.writebuffer[1] = nil
508 interface.writebufferlen = 0
509 interface:ondrain();
510 if interface.fatalerror then
511 debug "closing client after writing"
512 interface:_close() -- close interface if needed
513 elseif interface.startsslcallback then -- start ssl connection if needed
514 debug "starting ssl handshake after writing"
515 interface.eventstarthandshake = addevent( base, nil, EV_TIMEOUT, interface.startsslcallback, 0 )
516 elseif interface.eventreadtimeout then
517 return EV_WRITE, EV_TIMEOUT
518 end
519 interface.eventwrite = nil
520 return -1 485 return -1
521 elseif byte and (err == "timeout" or err == "wantwrite") then -- want write again 486 end
522 --vdebug( "writebuffer is not empty:", err ) 487 if EV_TIMEOUT == event then -- took too long to write some data to socket -> disconnect
488 interface.fatalerror = "timeout during writing"
489 debug( "writing failed:", interface.fatalerror )
490 interface:_close()
491 interface.eventwrite = false
492 return -1
493 else -- can write :)
494 if interface._usingssl then -- handle luasec
495 if interface.eventreadtimeout then -- we have to read first
496 local ret = interface.readcallback( ) -- call readcallback
497 --vdebug( "tried to read in writecallback, result:", ret )
498 end
499 if interface.eventwritetimeout then -- luasec only
500 interface.eventwritetimeout:close( ) -- first we have to close timeout event which where regged after a wantread error
501 interface.eventwritetimeout = false
502 end
503 end
504 interface.writebuffer = { t_concat(interface.writebuffer) }
505 local succ, err, byte = interface.conn:send( interface.writebuffer[1], 1, interface.writebufferlen )
506 --vdebug( "write data:", interface.writebuffer, "error:", err, "part:", byte )
507 if succ then -- writing succesful
508 interface.writebuffer[1] = nil
509 interface.writebufferlen = 0
510 interface:ondrain();
511 if interface.fatalerror then
512 debug "closing client after writing"
513 interface:_close() -- close interface if needed
514 elseif interface.startsslcallback then -- start ssl connection if needed
515 debug "starting ssl handshake after writing"
516 interface.eventstarthandshake = addevent( base, nil, EV_TIMEOUT, interface.startsslcallback, 0 )
517 elseif interface.eventreadtimeout then
518 return EV_WRITE, EV_TIMEOUT
519 end
520 interface.eventwrite = nil
521 return -1
522 elseif byte and (err == "timeout" or err == "wantwrite") then -- want write again
523 --vdebug( "writebuffer is not empty:", err )
523 interface.writebuffer[1] = s_sub( interface.writebuffer[1], byte + 1, interface.writebufferlen ) -- new buffer 524 interface.writebuffer[1] = s_sub( interface.writebuffer[1], byte + 1, interface.writebufferlen ) -- new buffer
524 interface.writebufferlen = interface.writebufferlen - byte 525 interface.writebufferlen = interface.writebufferlen - byte
525 if "wantread" == err then -- happens only with luasec 526 if "wantread" == err then -- happens only with luasec
526 local callback = function( ) 527 local callback = function( )
527 interface:_close() 528 interface:_close()
528 interface.eventwritetimeout = nil 529 interface.eventwritetimeout = nil
529 return -1; 530 return -1;
531 end
532 interface.eventwritetimeout = addevent( base, nil, EV_TIMEOUT, callback, cfg.WRITE_TIMEOUT ) -- reg a new timeout event
533 debug( "wantread during write attempt, reg it in readcallback but dont know what really happens next..." )
534 -- hopefully this works with luasec; its simply not possible to use 2 different write events on a socket in luaevent
535 return -1
530 end 536 end
531 interface.eventwritetimeout = addevent( base, nil, EV_TIMEOUT, callback, cfg.WRITE_TIMEOUT ) -- reg a new timeout event 537 return EV_WRITE, cfg.WRITE_TIMEOUT
532 debug( "wantread during write attempt, reg it in readcallback but dont know what really happens next..." ) 538 else -- connection was closed during writing or fatal error
533 -- hopefully this works with luasec; its simply not possible to use 2 different write events on a socket in luaevent 539 interface.fatalerror = err or "fatal error"
540 debug( "connection failed in write event:", interface.fatalerror )
541 interface:_close()
542 interface.eventwrite = nil
534 return -1 543 return -1
535 end 544 end
536 return EV_WRITE, cfg.WRITE_TIMEOUT 545 end
537 else -- connection was closed during writing or fatal error 546 end
538 interface.fatalerror = err or "fatal error" 547
539 debug( "connection failed in write event:", interface.fatalerror ) 548 interface.readcallback = function( event ) -- called on read events
540 interface:_close() 549 --vdebug( "new client read event, id/ip/port:", tostring(interface.id), tostring(ip), tostring(port) )
541 interface.eventwrite = nil 550 if interface.noreading or interface.fatalerror then -- leave this event
551 --vdebug( "leaving this event because:", tostring(interface.noreading or interface.fatalerror) )
552 interface.eventread = nil
542 return -1 553 return -1
543 end 554 end
544 end
545 end
546
547 interface.readcallback = function( event ) -- called on read events
548 --vdebug( "new client read event, id/ip/port:", tostring(interface.id), tostring(ip), tostring(port) )
549 if interface.noreading or interface.fatalerror then -- leave this event
550 --vdebug( "leaving this event because:", tostring(interface.noreading or interface.fatalerror) )
551 interface.eventread = nil
552 return -1
553 end
554 if EV_TIMEOUT == event and interface:onreadtimeout() ~= true then 555 if EV_TIMEOUT == event and interface:onreadtimeout() ~= true then
555 return -1 -- took too long to get some data from client -> disconnect 556 return -1 -- took too long to get some data from client -> disconnect
556 end 557 end
557 if interface._usingssl then -- handle luasec 558 if interface._usingssl then -- handle luasec
558 if interface.eventwritetimeout then -- ok, in the past writecallback was regged 559 if interface.eventwritetimeout then -- ok, in the past writecallback was regged
559 local ret = interface.writecallback( ) -- call it 560 local ret = interface.writecallback( ) -- call it
560 --vdebug( "tried to write in readcallback, result:", tostring(ret) ) 561 --vdebug( "tried to write in readcallback, result:", tostring(ret) )
561 end 562 end
562 if interface.eventreadtimeout then 563 if interface.eventreadtimeout then
563 interface.eventreadtimeout:close( ) 564 interface.eventreadtimeout:close( )
564 interface.eventreadtimeout = nil 565 interface.eventreadtimeout = nil
565 end 566 end
566 end 567 end
567 local buffer, err, part = interface.conn:receive( interface._pattern ) -- receive buffer with "pattern" 568 local buffer, err, part = interface.conn:receive( interface._pattern ) -- receive buffer with "pattern"
568 --vdebug( "read data:", tostring(buffer), "error:", tostring(err), "part:", tostring(part) ) 569 --vdebug( "read data:", tostring(buffer), "error:", tostring(err), "part:", tostring(part) )
569 buffer = buffer or part 570 buffer = buffer or part
570 if buffer and #buffer > cfg.MAX_READ_LENGTH then -- check buffer length 571 if buffer and #buffer > cfg.MAX_READ_LENGTH then -- check buffer length
571 interface.fatalerror = "receive buffer exceeded" 572 interface.fatalerror = "receive buffer exceeded"
572 debug( "fatal error:", interface.fatalerror ) 573 debug( "fatal error:", interface.fatalerror )
573 interface:_close() 574 interface:_close()
574 interface.eventread = nil 575 interface.eventread = nil
575 return -1 576 return -1
576 end 577 end
577 if err and ( err ~= "timeout" and err ~= "wantread" ) then 578 if err and ( err ~= "timeout" and err ~= "wantread" ) then
578 if "wantwrite" == err then -- need to read on write event 579 if "wantwrite" == err then -- need to read on write event
579 if not interface.eventwrite then -- register new write event if needed 580 if not interface.eventwrite then -- register new write event if needed
580 interface.eventwrite = addevent( base, interface.conn, EV_WRITE, interface.writecallback, cfg.WRITE_TIMEOUT ) 581 interface.eventwrite = addevent( base, interface.conn, EV_WRITE, interface.writecallback, cfg.WRITE_TIMEOUT )
581 end 582 end
582 interface.eventreadtimeout = addevent( base, nil, EV_TIMEOUT, 583 interface.eventreadtimeout = addevent( base, nil, EV_TIMEOUT,
583 function( ) 584 function( )
585 interface:_close()
586 end, cfg.READ_TIMEOUT
587 )
588 debug( "wantwrite during read attempt, reg it in writecallback but dont know what really happens next..." )
589 -- to be honest i dont know what happens next, if it is allowed to first read, the write etc...
590 else -- connection was closed or fatal error
591 interface.fatalerror = err
592 debug( "connection failed in read event:", interface.fatalerror )
584 interface:_close() 593 interface:_close()
585 end, cfg.READ_TIMEOUT 594 interface.eventread = nil
586 ) 595 return -1
587 debug( "wantwrite during read attempt, reg it in writecallback but dont know what really happens next..." ) 596 end
588 -- to be honest i dont know what happens next, if it is allowed to first read, the write etc... 597 else
589 else -- connection was closed or fatal error 598 interface.onincoming( interface, buffer, err ) -- send new data to listener
590 interface.fatalerror = err 599 end
591 debug( "connection failed in read event:", interface.fatalerror ) 600 if interface.noreading then
592 interface:_close() 601 interface.eventread = nil;
602 return -1;
603 end
604 return EV_READ, cfg.READ_TIMEOUT
605 end
606
607 client:settimeout( 0 ) -- set non blocking
608 setmetatable(interface, interface_mt)
609 interfacelist[ interface ] = true -- add to interfacelist
610 return interface
611 end
612
613 local function handleserver( server, addr, port, pattern, listener, sslctx ) -- creates an server interface
614 debug "creating server interface..."
615 local interface = {
616 _connections = 0;
617
618 type = "server";
619 conn = server;
620 onconnect = listener.onconnect; -- will be called when new client connected
621 eventread = false; -- read event handler
622 eventclose = false; -- close event handler
623 readcallback = false; -- read event callback
624 fatalerror = false; -- error message
625 nointerface = true; -- lock/unlock parameter
626
627 _ip = addr, _port = port, _pattern = pattern,
628 _sslctx = sslctx;
629 }
630 interface.id = tostring(interface):match("%x+$");
631 interface.readcallback = function( event ) -- server handler, called on incoming connections
632 --vdebug( "server can accept, id/addr/port:", interface, addr, port )
633 if interface.fatalerror then
634 --vdebug( "leaving this event because:", self.fatalerror )
593 interface.eventread = nil 635 interface.eventread = nil
594 return -1 636 return -1
595 end 637 end
596 else 638 local delay = cfg.ACCEPT_DELAY
597 interface.onincoming( interface, buffer, err ) -- send new data to listener 639 if EV_TIMEOUT == event then
598 end 640 if interface._connections >= cfg.MAX_CONNECTIONS then -- check connection count
599 if interface.noreading then 641 debug( "to many connections, seconds to wait for next accept:", delay )
600 interface.eventread = nil; 642 return EV_TIMEOUT, delay -- timeout...
601 return -1; 643 else
602 end 644 return EV_READ -- accept again
603 return EV_READ, cfg.READ_TIMEOUT 645 end
604 end 646 end
605 647 --vdebug("max connection check ok, accepting...")
606 client:settimeout( 0 ) -- set non blocking 648 local client, err = server:accept() -- try to accept; TODO: check err
607 setmetatable(interface, interface_mt) 649 while client do
608 interfacelist[ interface ] = true -- add to interfacelist 650 if interface._connections >= cfg.MAX_CONNECTIONS then
609 return interface 651 client:close( ) -- refuse connection
610 end 652 debug( "maximal connections reached, refuse client connection; accept delay:", delay )
611 653 return EV_TIMEOUT, delay -- delay for next accept attempt
612 local function handleserver( server, addr, port, pattern, listener, sslctx ) -- creates an server interface 654 end
613 debug "creating server interface..." 655 local client_ip, client_port = client:getpeername( )
614 local interface = { 656 interface._connections = interface._connections + 1 -- increase connection count
615 _connections = 0; 657 local clientinterface = handleclient( client, client_ip, client_port, interface, pattern, listener, sslctx )
616 658 --vdebug( "client id:", clientinterface, "startssl:", startssl )
617 type = "server";
618 conn = server;
619 onconnect = listener.onconnect; -- will be called when new client connected
620 eventread = false; -- read event handler
621 eventclose = false; -- close event handler
622 readcallback = false; -- read event callback
623 fatalerror = false; -- error message
624 nointerface = true; -- lock/unlock parameter
625
626 _ip = addr, _port = port, _pattern = pattern,
627 _sslctx = sslctx;
628 }
629 interface.id = tostring(interface):match("%x+$");
630 interface.readcallback = function( event ) -- server handler, called on incoming connections
631 --vdebug( "server can accept, id/addr/port:", interface, addr, port )
632 if interface.fatalerror then
633 --vdebug( "leaving this event because:", self.fatalerror )
634 interface.eventread = nil
635 return -1
636 end
637 local delay = cfg.ACCEPT_DELAY
638 if EV_TIMEOUT == event then
639 if interface._connections >= cfg.MAX_CONNECTIONS then -- check connection count
640 debug( "to many connections, seconds to wait for next accept:", delay )
641 return EV_TIMEOUT, delay -- timeout...
642 else
643 return EV_READ -- accept again
644 end
645 end
646 --vdebug("max connection check ok, accepting...")
647 local client, err = server:accept() -- try to accept; TODO: check err
648 while client do
649 if interface._connections >= cfg.MAX_CONNECTIONS then
650 client:close( ) -- refuse connection
651 debug( "maximal connections reached, refuse client connection; accept delay:", delay )
652 return EV_TIMEOUT, delay -- delay for next accept attempt
653 end
654 local client_ip, client_port = client:getpeername( )
655 interface._connections = interface._connections + 1 -- increase connection count
656 local clientinterface = handleclient( client, client_ip, client_port, interface, pattern, listener, sslctx )
657 --vdebug( "client id:", clientinterface, "startssl:", startssl )
658 if has_luasec and sslctx then 659 if has_luasec and sslctx then
659 clientinterface:starttls(sslctx, true) 660 clientinterface:starttls(sslctx, true)
660 else 661 else
661 clientinterface:_start_session( true ) 662 clientinterface:_start_session( true )
662 end 663 end
663 debug( "accepted incoming client connection from:", client_ip or "<unknown IP>", client_port or "<unknown port>", "to", port or "<unknown port>"); 664 debug( "accepted incoming client connection from:", client_ip or "<unknown IP>", client_port or "<unknown port>", "to", port or "<unknown port>");
664 665
665 client, err = server:accept() -- try to accept again 666 client, err = server:accept() -- try to accept again
666 end 667 end
667 return EV_READ 668 return EV_READ
668 end 669 end
669 670
670 server:settimeout( 0 ) 671 server:settimeout( 0 )
671 setmetatable(interface, interface_mt) 672 setmetatable(interface, interface_mt)
672 interfacelist[ interface ] = true 673 interfacelist[ interface ] = true
673 interface:_start_session() 674 interface:_start_session()
674 return interface 675 return interface
675 end 676 end
676 677
677 local function addserver( addr, port, listener, pattern, sslctx, startssl ) -- TODO: check arguments 678 local function addserver( addr, port, listener, pattern, sslctx, startssl ) -- TODO: check arguments
678 --vdebug( "creating new tcp server with following parameters:", addr or "nil", port or "nil", sslctx or "nil", startssl or "nil") 679 --vdebug( "creating new tcp server with following parameters:", addr or "nil", port or "nil", sslctx or "nil", startssl or "nil")
679 if sslctx and not has_luasec then 680 if sslctx and not has_luasec then
680 debug "fatal error: luasec not found" 681 debug "fatal error: luasec not found"
681 return nil, "luasec not found" 682 return nil, "luasec not found"
682 end
683 local server, err = socket.bind( addr, port, cfg.ACCEPT_QUEUE ) -- create server socket
684 if not server then
685 debug( "creating server socket on "..addr.." port "..port.." failed:", err )
686 return nil, err
687 end
688 local interface = handleserver( server, addr, port, pattern, listener, sslctx, startssl ) -- new server handler
689 debug( "new server created with id:", tostring(interface))
690 return interface
691 end 683 end
684 local server, err = socket.bind( addr, port, cfg.ACCEPT_QUEUE ) -- create server socket
685 if not server then
686 debug( "creating server socket on "..addr.." port "..port.." failed:", err )
687 return nil, err
688 end
689 local interface = handleserver( server, addr, port, pattern, listener, sslctx, startssl ) -- new server handler
690 debug( "new server created with id:", tostring(interface))
691 return interface
692 end
692 693
693 local function wrapclient( client, ip, port, listeners, pattern, sslctx ) 694 local function wrapclient( client, ip, port, listeners, pattern, sslctx )
694 local interface = handleclient( client, ip, port, nil, pattern, listeners, sslctx ) 695 local interface = handleclient( client, ip, port, nil, pattern, listeners, sslctx )
695 interface:_start_connection(sslctx) 696 interface:_start_connection(sslctx)
696 return interface, client 697 return interface, client
697 --function handleclient( client, ip, port, server, pattern, listener, _, sslctx ) -- creates an client interface 698 --function handleclient( client, ip, port, server, pattern, listener, _, sslctx ) -- creates an client interface
698 end 699 end
699 700
700 local function addclient( addr, serverport, listener, pattern, sslctx, typ ) 701 local function addclient( addr, serverport, listener, pattern, sslctx, typ )
701 if sslctx and not has_luasec then 702 if sslctx and not has_luasec then
702 debug "need luasec, but not available" 703 debug "need luasec, but not available"
703 return nil, "luasec not found" 704 return nil, "luasec not found"
704 end 705 end
705 if not typ then 706 if not typ then
706 local addrinfo, err = getaddrinfo(addr) 707 local addrinfo, err = getaddrinfo(addr)
707 if not addrinfo then return nil, err end 708 if not addrinfo then return nil, err end
708 if addrinfo[1] and addrinfo[1].family == "inet6" then 709 if addrinfo[1] and addrinfo[1].family == "inet6" then
709 typ = "tcp6" 710 typ = "tcp6"
710 else 711 else
711 typ = "tcp" 712 typ = "tcp"
712 end 713 end
713 end 714 end
714 local create = socket[typ] 715 local create = socket[typ]
715 if type( create ) ~= "function" then 716 if type( create ) ~= "function" then
716 return nil, "invalid socket type" 717 return nil, "invalid socket type"
717 end 718 end
718 local client, err = create() -- creating new socket 719 local client, err = create() -- creating new socket
719 if not client then 720 if not client then
720 debug( "cannot create socket:", err ) 721 debug( "cannot create socket:", err )
721 return nil, err 722 return nil, err
722 end 723 end
723 client:settimeout( 0 ) -- set nonblocking 724 client:settimeout( 0 ) -- set nonblocking
724 local res, err = client:connect( addr, serverport ) -- connect 725 local res, err = client:connect( addr, serverport ) -- connect
725 if res or ( err == "timeout" ) then 726 if res or ( err == "timeout" ) then
726 local ip, port = client:getsockname( ) 727 local ip, port = client:getsockname( )
727 local interface = wrapclient( client, ip, serverport, listener, pattern, sslctx ) 728 local interface = wrapclient( client, ip, serverport, listener, pattern, sslctx )
728 interface:_start_connection( sslctx ) 729 interface:_start_connection( sslctx )
729 debug( "new connection id:", interface.id ) 730 debug( "new connection id:", interface.id )
730 return interface, err 731 return interface, err
731 else 732 else
732 debug( "new connection failed:", err ) 733 debug( "new connection failed:", err )
733 return nil, err 734 return nil, err
734 end 735 end
735 end 736 end
736 737
737 local function loop( ) -- starts the event loop 738 local function loop( ) -- starts the event loop
738 base:loop( ) 739 base:loop( )
739 return "quitting"; 740 return "quitting";
740 end 741 end
741 742
742 local function newevent( ... ) 743 local function newevent( ... )
743 return addevent( base, ... ) 744 return addevent( base, ... )
744 end 745 end
745 746
746 local function closeallservers ( arg ) 747 local function closeallservers ( arg )
747 for item in pairs( interfacelist ) do 748 for item in pairs( interfacelist ) do
748 if item.type == "server" then 749 if item.type == "server" then
749 item:close( arg ) 750 item:close( arg )
751 end 752 end
752 end 753 end
753 754
754 local function setquitting(yes) 755 local function setquitting(yes)
755 if yes then 756 if yes then
756 -- Quit now 757 -- Quit now
757 closeallservers(); 758 closeallservers();
758 base:loopexit(); 759 base:loopexit();
759 end 760 end
760 end 761 end
761 762
762 local function get_backend() 763 local function get_backend()
763 return base:method(); 764 return base:method();