class ShadowsocksRuby::Protocols::ProtocolStack

Factory class for build protocol stacks

@see Protocols

Public Class Methods

new(cfg_ary, cipher_name, password) click to toggle source

@example This is what a cfg_ary Array look like

[ 
  ["some_packet_protocol_name"], # a packet protocol is required
  ["some_cipher_protocol_name", {:cipher => "some_cipher_object"}], # a cipher protocol is optional
  ["some_obfs_protocol_name", {:obfs_params => "..."}] # a obfs protocol is optional
]

@param [Array] cfg_ary @param [String] cipher_name @param [password] password

# File lib/shadowsocks_ruby/protocols/protocol_stack.rb, line 21
def initialize cfg_ary, cipher_name, password
  @cfg_ary = cfg_ary.map do |protocol_name, param|
    protocol_class = protocol_name.to_camel_case + "Protocol"
    protocol_class = Protocols.const_get(protocol_class)
    [protocol_class, param ||= {}]
  end
  @cipher_name = cipher_name
  @password = password
end

Public Instance Methods

build!(conn) click to toggle source

Factory method for build a protocol stack

@param [EventMachine::Connection] conn @return top protocol (packet protocol) in the stack

# File lib/shadowsocks_ruby/protocols/protocol_stack.rb, line 35
def build! conn
  cipher = nil

  protocols = @cfg_ary.map do | klass, params|
    case klass.to_s
    when Protocols::PlainProtocol.to_s, Protocols::Socks5Protocol.to_s, \
      Protocols::ShadowsocksProtocol.to_s, Protocols::HttpSimpleProtocol.to_s
      # do nothing, these are known protocols don't need cipher
    when Protocols::TlsTicketProtocol.to_s
      # this protocol need a key
      params = {:key => (cipher ||= Cipher.build(@cipher_name, @password)).key}.merge(params)
    else
      params = {:cipher => (cipher ||= Cipher.build(@cipher_name, @password))}.merge(params)
    end
      klass.new(params)
  end

  protocols.each_cons(2) do | p, p1 |
    p.next_protocol = p1
  end

  protocols.last.tap do |p|
    p.next_protocol = conn
  end

  protocols.each do |p|
    case
    when conn.is_a?(ShadowsocksRuby::Connections::TCP::ClientConnection)
      class << p
        extend Forwardable
        def_delegator :@next_protocol, :tcp_receive_from_client, :async_recv
        def_delegator :@next_protocol, :tcp_send_to_client, :send_data
      end
    when conn.is_a?(ShadowsocksRuby::Connections::TCP::RemoteServerConnection)
      class << p
        extend Forwardable
        def_delegator :@next_protocol, :tcp_receive_from_remoteserver, :async_recv
        def_delegator :@next_protocol, :tcp_send_to_remoteserver, :send_data
      end
    when conn.is_a?(ShadowsocksRuby::Connections::TCP::LocalBackendConnection)
      class << p
        extend Forwardable
        def_delegator :@next_protocol, :tcp_receive_from_localbackend, :async_recv
        def_delegator :@next_protocol, :tcp_send_to_localbackend, :send_data
      end
    when conn.is_a?(ShadowsocksRuby::Connections::TCP::DestinationConnection)
      class << p
        extend Forwardable
        def_delegator :@next_protocol, :tcp_receive_from_destination, :async_recv
        def_delegator :@next_protocol, :tcp_send_to_destination, :send_data
      end
    when conn.is_a?(ShadowsocksRuby::Connections::UDP::ClientConnection)
      class << p
        extend Forwardable
        def_delegator :@next_protocol, :udp_receive_from_client, :async_recv
        def_delegator :@next_protocol, :udp_send_to_client, :send_data
      end
    when conn.is_a?(ShadowsocksRuby::Connections::UDP::RemoteServerConnection)
      class << p
        extend Forwardable
        def_delegator :@next_protocol, :udp_receive_from_remoteserver, :async_recv
        def_delegator :@next_protocol, :udp_send_to_remoteserver, :send_data
      end
    when conn.is_a?(ShadowsocksRuby::Connections::UDP::LocalBackendConnection)
      class << p
        extend Forwardable
        def_delegator :@next_protocol, :udp_receive_from_localbackend, :async_recv
        def_delegator :@next_protocol, :udp_send_to_localbackend, :send_data
      end
    when conn.is_a?(ShadowsocksRuby::Connections::UDP::DestinationConnection)
      class << p
        extend Forwardable
        def_delegator :@next_protocol, :udp_receive_from_destination, :async_recv
        def_delegator :@next_protocol, :udp_send_to_destination, :send_data
      end
    end
  end          
  
  protocols.first
end