Class: Irc::Socket

Inherits:
Object show all
Defined in:
/home/apoc/projects/ruby/rbot/lib/rbot/ircsocket.rb

Overview

wrapped TCPSocket for communication with the server. emulates a subset of TCPSocket functionality

Defined Under Namespace

Classes: IdentityFilter

Constant Summary

MAX_IRC_SEND_PENALTY =
10

Instance Attribute Summary (collapse)

Instance Method Summary (collapse)

Constructor Details

- (Socket) initialize(server_list, host, opts = {})

server_list

list of servers to connect to

host

optional local host to bind to (ruby 1.7+ required)

create a new Irc::Socket



277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
# File '/home/apoc/projects/ruby/rbot/lib/rbot/ircsocket.rb', line 277

def initialize(server_list, host, opts={})
  @server_list = server_list.dup
  @server_uri = nil
  @conn_count = 0
  @host = host
  @sock = nil
  @filter = IdentityFilter.new
  @spooler = false
  @lines_sent = 0
  @lines_received = 0
  @ssl = opts[:ssl]
  @ssl_verify = opts[:ssl_verify]
  @ssl_ca_file = opts[:ssl_ca_file]
  @ssl_ca_path = opts[:ssl_ca_path]
  @penalty_pct = opts[:penalty_pct] || 100
end

Instance Attribute Details

- (Object) bytes_received (readonly)

total number of bytes received from the irc server



243
244
245
# File '/home/apoc/projects/ruby/rbot/lib/rbot/ircsocket.rb', line 243

def bytes_received
  @bytes_received
end

- (Object) bytes_sent (readonly)

total number of bytes sent to the irc server



240
241
242
# File '/home/apoc/projects/ruby/rbot/lib/rbot/ircsocket.rb', line 240

def bytes_sent
  @bytes_sent
end

- (Object) filter

an optional filter object. we call @filter.in(data) for all incoming data and @filter.out(data) for all outgoing data



250
251
252
# File '/home/apoc/projects/ruby/rbot/lib/rbot/ircsocket.rb', line 250

def filter
  @filter
end

- (Object) lines_received (readonly)

total number of lines received from the irc server



237
238
239
# File '/home/apoc/projects/ruby/rbot/lib/rbot/ircsocket.rb', line 237

def lines_received
  @lines_received
end

- (Object) lines_sent (readonly)

total number of lines sent to the irc server



234
235
236
# File '/home/apoc/projects/ruby/rbot/lib/rbot/ircsocket.rb', line 234

def lines_sent
  @lines_sent
end

- (Object) penalty_pct

penalty multiplier (percent)



256
257
258
# File '/home/apoc/projects/ruby/rbot/lib/rbot/ircsocket.rb', line 256

def penalty_pct
  @penalty_pct
end

- (Object) server_uri (readonly)

normalized uri of the current server



253
254
255
# File '/home/apoc/projects/ruby/rbot/lib/rbot/ircsocket.rb', line 253

def server_uri
  @server_uri
end

- (Object) throttle_bytes (readonly)

accumulator for the throttle



246
247
248
# File '/home/apoc/projects/ruby/rbot/lib/rbot/ircsocket.rb', line 246

def throttle_bytes
  @throttle_bytes
end

Instance Method Details

- (Object) clearq



398
399
400
# File '/home/apoc/projects/ruby/rbot/lib/rbot/ircsocket.rb', line 398

def clearq
  @sendq.clear
end

- (Object) connect

open a TCP connection to the server



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
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
# File '/home/apoc/projects/ruby/rbot/lib/rbot/ircsocket.rb', line 299

def connect
  if connected?
    warning "reconnecting while connected"
    return
  end
  srv_uri = @server_list[@conn_count % @server_list.size].dup
  srv_uri = 'irc://' + srv_uri if !(srv_uri =~ /:\/\//)
  @conn_count += 1
  @server_uri = URI.parse(srv_uri)
  @server_uri.port = 6667 if !@server_uri.port

  debug "connection attempt \##{@conn_count} (#{@server_uri.host}:#{@server_uri.port})"

  # if the host is a bracketed (IPv6) address, strip the brackets
  # since Ruby doesn't like them in the Socket host parameter
  # FIXME it would be safer to have it check for a valid
  # IPv6 bracketed address rather than just stripping the brackets
  srv_host = @server_uri.host
  if srv_host.match(/\A\[(.*)\]\z/)
    srv_host = $1
  end

  if(@host)
    begin
      sock=TCPSocket.new(srv_host, @server_uri.port, @host)
    rescue ArgumentError => e
      error "Your version of ruby does not support binding to a "
      error "specific local address, please upgrade if you wish "
      error "to use HOST = foo"
      error "(this option has been disabled in order to continue)"
      sock=TCPSocket.new(srv_host, @server_uri.port)
    end
  else
    sock=TCPSocket.new(srv_host, @server_uri.port)
  end
  if(@ssl)
    require 'openssl'
    ssl_context = OpenSSL::SSL::SSLContext.new()
    if @ssl_verify
      ssl_context.ca_file = @ssl_ca_file if @ssl_ca_file and not @ssl_ca_file.empty?
      ssl_context.ca_path = @ssl_ca_path if @ssl_ca_path and not @ssl_ca_path.empty?
      ssl_context.verify_mode = OpenSSL::SSL::VERIFY_PEER 
    else
      ssl_context.verify_mode = OpenSSL::SSL::VERIFY_NONE
    end
    sock = OpenSSL::SSL::SSLSocket.new(sock, ssl_context)
    sock.sync_close = true
    sock.connect
  end
  @sock = sock
  @last_send = Time.new
  @flood_send = Time.new
  @burst = 0
  @sock.extend(MonitorMixin)
  @sendq = MessageQueue.new
  @qthread = Thread.new { writer_loop }
end

- (Boolean) connected?

Returns:

  • (Boolean)


294
295
296
# File '/home/apoc/projects/ruby/rbot/lib/rbot/ircsocket.rb', line 294

def connected?
  !@sock.nil?
end

- (Object) emergency_puts(message, penalty = false)

used to send lines to the remote IRCd by skipping the queue message: IRC message to send it should only be used for stuff that *must not* be queued, i.e. the initial PASS, NICK and USER command or the final QUIT message



362
363
364
365
366
367
# File '/home/apoc/projects/ruby/rbot/lib/rbot/ircsocket.rb', line 362

def emergency_puts(message, penalty = false)
  @sock.synchronize do
    # debug "In puts - got @sock"
    puts_critical(message, penalty)
  end
end

- (Object) flush

flush the TCPSocket



403
404
405
# File '/home/apoc/projects/ruby/rbot/lib/rbot/ircsocket.rb', line 403

def flush
  @sock.flush
end

- (Object) gets

get the next line from the server (blocks)



378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
# File '/home/apoc/projects/ruby/rbot/lib/rbot/ircsocket.rb', line 378

def gets
  if @sock.nil?
    warning "socket get attempted while closed"
    return nil
  end
  begin
    reply = @filter.in(@sock.gets)
    @lines_received += 1
    reply.strip! if reply
    debug "RECV: #{reply.inspect}"
    return reply
  rescue Exception => e
    handle_socket_error(:RECV, e)
  end
end

- (Object) handle_socket_error(string, e)

Raises:

  • (SocketError)


369
370
371
372
373
374
375
# File '/home/apoc/projects/ruby/rbot/lib/rbot/ircsocket.rb', line 369

def handle_socket_error(string, e)
  error "#{string} failed: #{e.pretty_inspect}"
  # We assume that an error means that there are connection
  # problems and that we should reconnect, so we
  shutdown
  raise SocketError.new(e.inspect)
end

- (Object) queue(msg, chan = nil, ring = 0)



394
395
396
# File '/home/apoc/projects/ruby/rbot/lib/rbot/ircsocket.rb', line 394

def queue(msg, chan=nil, ring=0)
  @sendq.push msg, chan, ring
end

- (Object) select(timeout = nil)

Wraps Kernel.select on the socket



408
409
410
# File '/home/apoc/projects/ruby/rbot/lib/rbot/ircsocket.rb', line 408

def select(timeout=nil)
  Kernel.select([@sock], nil, nil, timeout)
end

- (Object) shutdown(how = 2)

shutdown the connection to the server



413
414
415
416
417
418
419
420
421
422
423
424
425
# File '/home/apoc/projects/ruby/rbot/lib/rbot/ircsocket.rb', line 413

def shutdown(how=2)
  return unless connected?
  @qthread.kill
  @qthread = nil
  begin
    @sock.close
  rescue Exception => e
    error "error while shutting down: #{e.pretty_inspect}"
  end
  @sock = nil
  @server_uri = nil
  @sendq.clear
end