Class: EventMachine::Synchrony::TCPSocket

Inherits:
Connection
  • Object
show all
Defined in:
lib/em-synchrony/tcpsocket.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#unbind_reasonObject (readonly)

Returns the value of attribute unbind_reason.



111
112
113
# File 'lib/em-synchrony/tcpsocket.rb', line 111

def unbind_reason
  @unbind_reason
end

Class Method Details

._old_newObject



5
# File 'lib/em-synchrony/tcpsocket.rb', line 5

alias_method :_old_new, :new

.new(*args) ⇒ Object Also known as: open



6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# File 'lib/em-synchrony/tcpsocket.rb', line 6

def new(*args)
  if args.size == 1
    _old_new(*args)
  else
    # In TCPSocket, new against an unknown hostname raises SocketError with
    # a message "getaddrinfo: nodename nor servname provided, or not known".
    # In EM, connect against an unknown hostname raises EM::ConnectionError
    # with a message of "unable to resolve server address" 
    begin
      socket = EventMachine::connect(*args[0..1], self)
    rescue EventMachine::ConnectionError => e
      raise SocketError, e.message
    end
    # In TCPSocket, new against a closed port raises Errno::ECONNREFUSED.
    # In EM, connect against a closed port result in a call to unbind with
    # a reason param of Errno::ECONNREFUSED as a class, not an instance.
    unless socket.sync(:in)  # wait for connection
      raise socket.unbind_reason.new if socket.unbind_reason.is_a? Class
      raise SocketError
    end
    socket
  end
end

Instance Method Details

#closeObject

Raises:

  • (IOError)


95
96
97
98
99
100
101
102
103
# File 'lib/em-synchrony/tcpsocket.rb', line 95

def close
  # close on a closed socket raises IOError with a message of "closed stream"
  raise IOError, "closed stream" if @closed
  @closed = true
  close_connection true
  @in_req = @out_req = nil
  # close on an open socket returns nil
  nil
end

#closed?Boolean

Returns:

  • (Boolean)


39
40
41
42
43
44
45
46
# File 'lib/em-synchrony/tcpsocket.rb', line 39

def closed?
  # In TCPSocket, 
  # closed? on a remotely closed socket, when we've not yet read EOF, returns false
  # closed? on a remotely closed socket, when we've read EOF, returns false
  # closed? on a socket after #close, returns true
  # Therefore, we set @close to true when #close is called, but not when unbind is. 
  @closed
end

#connection_completedObject

EventMachine interface



106
107
108
109
# File 'lib/em-synchrony/tcpsocket.rb', line 106

def connection_completed
  @opening = false
  @in_req.succeed self
end

#post_initObject



32
33
34
35
36
37
# File 'lib/em-synchrony/tcpsocket.rb', line 32

def post_init
  @in_buff, @out_buff = '', ''
  @in_req = @out_req = @unbind_reason = @read_type = nil
  @opening = true
  @closed = @remote_closed = false
end

#read(num_bytes = nil, dest = nil) ⇒ Object Also known as: read_nonblock



85
86
87
# File 'lib/em-synchrony/tcpsocket.rb', line 85

def read(num_bytes = nil, dest = nil)
  handle_read(:read, num_bytes, dest)
end

#receive_data(data) ⇒ Object



128
129
130
131
132
133
# File 'lib/em-synchrony/tcpsocket.rb', line 128

def receive_data(data)
  @in_buff << data
  if @in_req && (data = read_data)
    @in_req.succeed data unless data == :block
  end
end

#recv(num_bytes, flags = 0) ⇒ Object



90
91
92
93
# File 'lib/em-synchrony/tcpsocket.rb', line 90

def recv(num_bytes, flags = 0)
  raise "Unknown flags in recv(): #{flags}" if flags.nonzero?
  handle_read(:recv, num_bytes)
end

#send(msg, flags) ⇒ Object

Raises:

  • (IOError)


59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/em-synchrony/tcpsocket.rb', line 59

def send(msg, flags)
  raise "Unknown flags in send(): #{flags}" if flags.nonzero?
  # write(X) on a socket after #close, raises IOError with message "closed stream"
  # send(X,0) on a socket after #close, raises IOError with message "closed stream"
  raise IOError, "closed stream" if @closed
  # the first write(X) on a remotely closed socket, <= than some buffer size, generates no error
  # the first write(X) on a remotely closed socket, > than some buffer size, generates no error
  # (on my box this buffer appears to be 80KB)
  # further write(X) on a remotely closed socket, raises Errno::EPIPE
  # the first send(X,0) on a remotely closed socket, <= than some buffer size, generates no error
  # the first send(X,0) on a remotely closed socket, > than some buffer size, generates no error
  # (on my box this buffer appears to be 80KB)
  # further send(X,0) on a remotely closed socket, raises Errno::EPIPE
  raise Errno::EPIPE if @remote_closed
  
  len = msg.bytesize
  # write(X) on an open socket, where the remote end closes during the write, raises Errno::EPIPE
  # send(X,0) on an open socket, where the remote end closes during the write, raises Errno::EPIPE
  write_data(msg) or sync(:out) or raise(Errno::EPIPE)
  len
end

#setsockopt(level, name, value) ⇒ Object

TCPSocket interface



57
# File 'lib/em-synchrony/tcpsocket.rb', line 57

def setsockopt(level, name, value); end

#sync(direction) ⇒ Object

direction must be one of :in or :out



49
50
51
52
53
54
# File 'lib/em-synchrony/tcpsocket.rb', line 49

def sync(direction)
  req = self.instance_variable_set "@#{direction.to_s}_req", EventMachine::DefaultDeferrable.new
  EventMachine::Synchrony.sync req
ensure
  self.instance_variable_set "@#{direction.to_s}_req", nil
end

#unbind(reason) ⇒ Object

Can’t set a default value for reason (e.g. reason=nil), as in that case EM fails to pass in the reason argument and you’ll always get the default value.



116
117
118
119
120
121
122
123
124
125
126
# File 'lib/em-synchrony/tcpsocket.rb', line 116

def unbind(reason)
  @unbind_reason = reason
  @remote_closed = true unless @closed
  if @opening
    @in_req.fail nil if @in_req
  else
    @in_req.succeed read_data if @in_req
  end
  @out_req.fail nil if @out_req
  @in_req = @out_req = nil
end

#write(msg) ⇒ Object



81
82
83
# File 'lib/em-synchrony/tcpsocket.rb', line 81

def write(msg)
  send(msg,0)
end