Module: ShadowsocksRuby::Connections::Connection

Overview

Mixed-in code to provide fiber enabled asynchronously receive function and pressure controled send_data to EventMachine::Connection

User code should define process_hook which hopefully implement a state machine .

Note: User code should not override post_init and receive_data, it is by design.

Examples:

class DummyConnection < EventMachine::Connection
  include ShadowsocksRuby::Connections::Connection
  def process_hook
    @i ||= 0
    @i += 1
    puts "I'm now in a fiber enabled context: #{@fiber}"
    Fiber.yield if @i >= 3
  end
end

Constant Summary collapse

PressureLevel =

512K, used to pause plexer when plexer.get_outbound_data_size > this value

524288

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#loggerObject

get the logger object, the defautl logger is App.instance.logger



52
53
54
# File 'lib/shadowsocks_ruby/connections/connection.rb', line 52

def logger
  @logger ||= App.instance.logger
end

#plexerConnection

It is where to relay peer’s traffic to For a server connection, plexer is backend connection. For a backend connection, plexer is server connection.

Returns:



46
47
48
# File 'lib/shadowsocks_ruby/connections/connection.rb', line 46

def plexer
  @plexer
end

Instance Method Details

#async_recv(n) ⇒ String Also known as: tcp_receive_from_client, tcp_receive_from_remoteserver, tcp_receive_from_localbackend, tcp_receive_from_destination, udp_receive_from_client, udp_receive_from_remoteserver, udp_receive_from_localbackend, udp_receive_from_destination

Asynchronously receive n bytes from @buffer

Parameters:

  • n (Integer)

    Bytes to receive, if n = -1 returns all data in @buffer

Returns:

  • (String)

    Returned n bytes data



95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/shadowsocks_ruby/connections/connection.rb', line 95

def async_recv n
  # wait n bytes
  if n == -1 && @buffer.size == 0 || @buffer.size < n
    @wait_length = n
    Fiber.yield
  end
  # read n bytes from buffer
  if n == -1
    s, @buffer = @buffer, String.new('', encoding: Encoding::ASCII_8BIT)
    return s
  else
    return @buffer.slice!(0, n)
  end
end

#async_recv_until(str) ⇒ String

Asynchronously receive data until str (eg: “\r\nr\n”) appears.

Parameters:

  • str (String)

    Desired endding str

Returns:

  • (String)

    Returned data, with str at end

Raises:

  • BufferOversizeError raise if cannot find str in first 65536 bytes (64K bytes)of @buffer, enough for a HTTP request head.



115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/shadowsocks_ruby/connections/connection.rb', line 115

def async_recv_until str
  # wait for str
  pos = @buffer =~ Regexp.new(str)
  while pos == nil
    @wait_length = -1
    Fiber.yield
    pos = @buffer =~ Regexp.new(str)
    raise BufferOversizeError, "oversized async_recv_until read" if @buffer.size > 65536
  end
  # read until str from buffer
  return @buffer.slice!(0, pos + str.length)
end

#peerObject



84
85
86
87
88
89
90
# File 'lib/shadowsocks_ruby/connections/connection.rb', line 84

def peer
  @peer ||=
  begin
    port, ip = Socket.unpack_sockaddr_in(get_peername)
    "#{ip}:#{port}"
  end
end

#send_data(data) ⇒ Object Also known as: tcp_send_to_client, tcp_send_to_remoteserver, tcp_send_to_localbackend, tcp_send_to_destination, udp_send_to_client, udp_send_to_remoteserver, udp_send_to_localbackend, udp_send_to_destination

send_data with pressure control @param data Data to send asynchronously



59
60
61
62
# File 'lib/shadowsocks_ruby/connections/connection.rb', line 59

def send_data data
  pressure_control
  super data
end

#unbindObject

Close plexer first if it exists



172
173
174
175
# File 'lib/shadowsocks_ruby/connections/connection.rb', line 172

def unbind
  @plexer ||= nil
  @plexer.close_connection_after_writing if @plexer != nil
end