Comparison

net/server_event.lua @ 7336:0d9ac472e58c

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