Class: IRC::Server::Dispatcher::ConnectionDispatcher

Inherits:
Object
  • Object
show all
Defined in:
lib/failirc/server/dispatcher/connectiondispatcher.rb

Defined Under Namespace

Classes: Connections, Data

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(dispatcher) ⇒ ConnectionDispatcher

Returns a new instance of ConnectionDispatcher.



188
189
190
191
192
193
194
195
196
# File 'lib/failirc/server/dispatcher/connectiondispatcher.rb', line 188

def initialize (dispatcher)
    @server     = dispatcher.server
    @dispatcher = dispatcher

    @connections   = Connections.new(server)
    @input         = Data.new(dispatcher)
    @output        = Data.new(dispatcher)
    @disconnecting = []
end

Instance Attribute Details

#connectionsObject (readonly)

Returns the value of attribute connections.



186
187
188
# File 'lib/failirc/server/dispatcher/connectiondispatcher.rb', line 186

def connections
  @connections
end

#disconnectingObject (readonly)

Returns the value of attribute disconnecting.



186
187
188
# File 'lib/failirc/server/dispatcher/connectiondispatcher.rb', line 186

def disconnecting
  @disconnecting
end

#dispatcherObject (readonly)

Returns the value of attribute dispatcher.



186
187
188
# File 'lib/failirc/server/dispatcher/connectiondispatcher.rb', line 186

def dispatcher
  @dispatcher
end

#inputObject (readonly)

Returns the value of attribute input.



186
187
188
# File 'lib/failirc/server/dispatcher/connectiondispatcher.rb', line 186

def input
  @input
end

#outputObject (readonly)

Returns the value of attribute output.



186
187
188
# File 'lib/failirc/server/dispatcher/connectiondispatcher.rb', line 186

def output
  @output
end

#serverObject (readonly)

Returns the value of attribute server.



186
187
188
# File 'lib/failirc/server/dispatcher/connectiondispatcher.rb', line 186

def server
  @server
end

Instance Method Details

#accept(timeout = 0) ⇒ Object



222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
# File 'lib/failirc/server/dispatcher/connectiondispatcher.rb', line 222

def accept (timeout=0)
    begin
        listening, = IO::select @connections.listening[:sockets], nil, nil, timeout

        if listening
            listening.each {|server|
                begin
                    socket, = server.accept_nonblock

                    if socket
                        newConnection socket, @connections.listening[:data][server][:listen], @connections.listening[:data][server][:context]
                    end
                rescue Errno::EAGAIN
                rescue Exception => e
                    self.debug e
                end
            }
        end
    rescue IOError
        @connections.listening[:sockets].each {|socket|
            if socket.closed?
                @connections.listening[:sockets].delete(socket)
                @connections.listening[:data].delete(socket                 @connections.listening[:data].delete(socket))
            end
        }
    rescue
    end
end

#cleanObject



335
336
337
338
339
340
341
342
343
344
345
346
# File 'lib/failirc/server/dispatcher/connectiondispatcher.rb', line 335

def clean
    @disconnecting.each {|data|
        thing  = data[:thing]
        output = data[:output]

        if output.first == :EOC
            output.shift
            handleDisconnection thing, output.shift
            @disconnecting.delete(data)
        end
    }
end

#clientsObject



202
203
204
# File 'lib/failirc/server/dispatcher/connectiondispatcher.rb', line 202

def clients
    @connections.clients
end

#finalizeObject



444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
# File 'lib/failirc/server/dispatcher/connectiondispatcher.rb', line 444

def finalize
    begin
        @connections.listening[:sockets].each {|server|
            server.close
        }

        @clients.each {|key, client|
            kill client, 'Good night sweet prince.'
        }

        @links.each {|key, link|
            kill client, 'Good night sweet prince.'
        }
    rescue Exception => e
        self.debug e
    end
end

#handleObject



348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
# File 'lib/failirc/server/dispatcher/connectiondispatcher.rb', line 348

def handle
    @input.each {|socket|
        if dispatcher.event.handling[socket] || @input.empty?(socket)
            next
        end

        Thread.new {
            begin
                if string = @input.pop(socket)
                    dispatcher.dispatch(:input, thing(socket), string)
                end
            rescue Exception => e
                self.debug e
            end
        }
    }
end

#handleDisconnection(thing, message) ⇒ Object



420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
# File 'lib/failirc/server/dispatcher/connectiondispatcher.rb', line 420

def handleDisconnection (thing, message)
    @dispatcher.execute(:kill, thing, message) rescue nil

    if thing.is_a?(Client)
        thing.modes[:quitting] = true

        if thing.modes[:registered]
            thing.channels.each_value {|channel|
                channel.users.delete(thing.nick)
            }
        end
    elsif thing.is_a?(Link)
        # wat
    end

    @input.delete(thing.socket)
    @output.delete(thing.socket)
    connections.delete(thing.socket)

    self.debug "#{thing.mask}[#{thing.ip}/#{thing.port}] disconnected."

    thing.socket.close rescue nil
end


206
207
208
# File 'lib/failirc/server/dispatcher/connectiondispatcher.rb', line 206

def links
    @connections.links
end

#listen(options, listen) ⇒ Object



210
211
212
213
214
215
216
217
218
219
220
# File 'lib/failirc/server/dispatcher/connectiondispatcher.rb', line 210

def listen (options, listen)
    server  = TCPServer.new(options[:bind], options[:port])
    context = nil

    if options[:ssl] != 'disabled'
        context = SSLUtils::context(options[:ssl_cert], options[:ssl_key])
    end

    @connections.listening[:sockets].push(server)
    @connections.listening[:data][server] = { :listen => listen, :context => context }
end

#newConnection(socket, listen, context = nil) ⇒ Object

Executed with each incoming connection



252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
# File 'lib/failirc/server/dispatcher/connectiondispatcher.rb', line 252

def newConnection (socket, listen, context=nil)
    # here, somehow we should check if the incoming peer is a linked server or a real client

    host = socket.peeraddr[2]
    ip   = socket.peeraddr[3]
    port = socket.addr[1]

    self.debug "#{host}[#{ip}/#{port}] connecting."

    Thread.new {
        begin
            if listen.attributes['ssl'] != 'disabled'
                ssl = OpenSSL::SSL::SSLSocket.new socket, context

                ssl.accept
                socket = ssl
            end

            @connections.things[socket] = @connections.clients[socket] = Server::Client.new(server, socket, listen)
            @connections.sockets.push(socket)

            @input[socket]
        rescue OpenSSL::SSL::SSLError
            socket.write_nonblock "This is a SSL connection, faggot.\r\n" rescue nil
            self.debug "#{host}[#{ip}/#{port}] tried to connect to a SSL connection and failed the handshake."
            socket.close rescue nil
        rescue Errno::ECONNRESET
            socket.close rescue nil
            self.debug "#{host}[#{ip}/#{port}] connection reset."
        rescue Exception => e
            socket.close rescue nil
            self.debug(e)
        end
    }
end

#read(timeout = 0.1) ⇒ Object



288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
# File 'lib/failirc/server/dispatcher/connectiondispatcher.rb', line 288

def read (timeout=0.1)
    begin
        reading, = IO::select @connections.sockets, nil, nil, timeout
    rescue IOError
        @connections.sockets.each {|socket|
            if socket.closed?
                server.kill socket
            end
        }
    rescue Exception => e
        self.debug e
    end

    if !reading
        return
    end

    reading.each {|socket|
        thing = thing socket

        begin
            input = socket.read_nonblock 2048

            if !input || input.empty?
                raise Errno::EPIPE
            end

            input.split(/[\r\n]+/).each {|string|
                @input.push(socket, string)
            }
        rescue IOError
            server.kill thing, 'Input/output error', true
        rescue Errno::EBADF, Errno::EPIPE, OpenSSL::SSL::SSLError
            server.kill thing, 'Client exited', true
        rescue Errno::ECONNRESET
            server.kill thing, 'Connection reset by peer', true
        rescue Errno::ETIMEDOUT
            server.kill thing, 'Ping timeout', true
        rescue Errno::EHOSTUNREACH
            server.kill thing, 'No route to host', true
        rescue Errno::EAGAIN, IO::WaitReadable
        rescue Exception => e
            self.debug e
        end
    }
end

#socketsObject



198
199
200
# File 'lib/failirc/server/dispatcher/connectiondispatcher.rb', line 198

def sockets
    @connections.sockets
end

#thing(identifier) ⇒ Object



462
463
464
465
466
467
468
469
470
# File 'lib/failirc/server/dispatcher/connectiondispatcher.rb', line 462

def thing (identifier)
    if identifier.is_a?(Client) || identifier.is_a?(Link)
        return identifier
    elsif identifier.is_a?(User)
        return identifier.client
    else
        return @connections.things[identifier]
    end
end

#write(timeout = 0) ⇒ Object



366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
# File 'lib/failirc/server/dispatcher/connectiondispatcher.rb', line 366

def write (timeout=0)
    begin
        none, writing, erroring = IO::select nil, @connections.sockets, nil, timeout
    rescue IOError
        @connections.sockets.each {|socket|
            if socket.closed?
                server.kill thing socket, 'Client exited'
            end
        }
    rescue Exception => e
        self.debug e
    end

    if !writing
        return
    end

    writing.each {|socket|
        if @output.empty?(socket)
            next
        end

        thing = thing socket

        begin
            while !@output.empty?(socket)
                output = @output.first(socket)

                if output == :EOC
                    @output.delete(socket)
                else
                    output.force_encoding 'ASCII-8BIT'
                    socket.write_nonblock "#{output}\r\n"

                    @output.pop(socket)
                end
            end
        rescue IOError
            server.kill thing, 'Input/output error', true
        rescue Errno::EBADF, Errno::EPIPE, OpenSSL::SSL::SSLError
            server.kill thing, 'Client exited', true
        rescue Errno::ECONNRESET
            server.kill thing, 'Connection reset by peer', true
        rescue Errno::ETIMEDOUT
            server.kill thing, 'Ping timeout', true
        rescue Errno::EHOSTUNREACH
            server.kill thing, 'No route to host', true
        rescue Errno::EAGAIN, IO::WaitWritable
        rescue Exception => e
            self.debug e
        end
    }
end