ionian 0.6.6 → 0.6.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -103,7 +103,7 @@
103
103
  </div>
104
104
 
105
105
  <div id="footer">
106
- Generated on Sat Apr 12 13:24:31 2014 by
106
+ Generated on Sun Apr 13 09:26:35 2014 by
107
107
  <a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
108
108
  0.8.7.4 (ruby-2.1.1).
109
109
  </div>
@@ -1,3 +1,5 @@
1
+ Thread.abort_on_exception = true
2
+
1
3
  module Ionian
2
4
  module Extension
3
5
  # A mixin for IO objects that allows regular expression matching
@@ -31,7 +33,7 @@ module Ionian
31
33
  # Args:
32
34
  # Timeout: Number of seconds to wait for data until
33
35
  # giving up. Set to nil for blocking.
34
- def has_data?(timeout: 0)
36
+ def has_data? timeout: 0
35
37
  ::IO.select([self], nil, nil, timeout) ? true : false
36
38
  end
37
39
 
@@ -53,8 +55,11 @@ module Ionian
53
55
 
54
56
  # Read all data in the buffer.
55
57
  # An alternative to using #readpartial with a large length.
56
- # Blocks until data is available.
57
- def read_all
58
+ # Blocks until data is available unless nonblocking: true.
59
+ # If nonblocking, returns nil if no data available.
60
+ def read_all nonblocking: false
61
+ return nil if nonblocking and not has_data?
62
+
58
63
  # Block until data has arrived.
59
64
  data = readpartial 0xFFFF
60
65
  # If there is more data in the buffer, retrieve it nonblocking.
@@ -54,10 +54,16 @@ module Ionian
54
54
  # For connection-oriented protocols, prevent #close from returning
55
55
  # immediately and try to deliver any data in the send buffer if value
56
56
  # is true.
57
+ #
58
+ # Args:
59
+ # Time: Time in seconds to remain open before discarding data and
60
+ # sending a RST packet.
57
61
  # ( SO_LINGER )
58
- def linger= value
59
- param = value ? 1 : 0
60
- self.setsockopt ::Socket::SOL_SOCKET, ::Socket::SO_LINGER, [param].pack('i')
62
+ def linger= enable, time: 60
63
+ # TODO: Passing a kwarg doesn't work here because of the
64
+ # assignment operator. Causes parser error.
65
+ param = enable ? 1 : 0
66
+ self.setsockopt ::Socket::SOL_SOCKET, ::Socket::SO_LINGER, [param, time.to_i].pack('ii')
61
67
  end
62
68
 
63
69
  alias_method :linger?, :linger
data/lib/ionian/server.rb CHANGED
@@ -1,6 +1,9 @@
1
1
  require 'socket'
2
2
  require 'ionian/socket'
3
3
 
4
+ Thread.abort_on_exception = true
5
+
6
+
4
7
  module Ionian
5
8
 
6
9
  # A convenient wrapper for TCP, UDP, and Unix server sockets.
@@ -59,7 +62,6 @@ module Ionian
59
62
  @interface = host_port_ary[0]
60
63
  @port ||= host_port_ary[1]
61
64
 
62
- # TODO: Parse port from interface if TCP.
63
65
  raise ArgumentError, "Port not specified." unless @port
64
66
  @port = @port.to_i
65
67
 
@@ -85,19 +87,18 @@ module Ionian
85
87
  register_accept_listener &block if block_given?
86
88
 
87
89
  @accept_thread ||= Thread.new do
88
- # Package in an Ionian::Socket
89
- begin
90
- client = Ionian::Socket.new @server.accept
91
-
92
- @accept_listeners.each do |listener|
93
- listener.call client
90
+ loop do
91
+ # Package in an Ionian::Socket
92
+ begin
93
+ client = Ionian::Socket.new @server.accept
94
+ @accept_listeners.each { |listener| listener.call client }
95
+ rescue Errno::EBADF
96
+ # This ignores the connection if the client closed it before it
97
+ # could be accepted.
98
+ rescue IOError
99
+ # This ignores the connection if the client closed it before it
100
+ # could be accepted.
94
101
  end
95
- rescue Errno::EBADF
96
- # This ignores the connection if the client closed it before it
97
- # could be accepted.
98
- rescue IOError
99
- # This ignores the connection if the client closed it before it
100
- # could be accepted.
101
102
  end
102
103
  end
103
104
  end
@@ -105,7 +106,7 @@ module Ionian
105
106
  # Shutdown the server socket and stop listening for connections.
106
107
  def close
107
108
  @server.close if @server
108
- @accept_thread.join if @accept_thread
109
+ @accept_thread.kill if @accept_thread
109
110
  @accept_thread = nil
110
111
  end
111
112
 
data/lib/ionian/socket.rb CHANGED
@@ -36,6 +36,8 @@ module Ionian
36
36
  # no_delay: Set true to enable the TCP_NODELAY flag. Disables Nagle algorithm.
37
37
  # cork: Set true to enable the TCP_CORK flag. Buffers multiple writes
38
38
  # into one segment.
39
+ # linger: Set true to enable the SO_LINGER flag. When #close is called,
40
+ # waits for the send buffer to empty before closing the socket.
39
41
  # expression: Overrides the #read_match regular expression for received data.
40
42
  def initialize existing_socket = nil, **kwargs
41
43
  @socket = existing_socket
@@ -91,8 +93,14 @@ module Ionian
91
93
  @persistent = true if @protocol == :udp
92
94
 
93
95
  @reuse_addr = kwargs.fetch :reuse_addr, false
94
- @no_delay = kwargs.fetch :no_delay, false
95
96
  @cork = kwargs.fetch :cork, false
97
+ @no_delay = kwargs.fetch :no_delay, @persistent ? false : true
98
+
99
+ # Default to false for persistent sockets, true for
100
+ # nonpersistent sockets. When nonpersistent, the socket
101
+ # should remain open to send data in the buffer after
102
+ # close is called (typically right after write).
103
+ @linger = kwargs.fetch :linger, @persistent ? false : true
96
104
 
97
105
 
98
106
  create_socket if @persistent
@@ -122,12 +130,7 @@ module Ionian
122
130
  def cmd string, **kwargs, &block
123
131
  create_socket unless @persistent
124
132
 
125
- if @protocol == :udp
126
- @socket.send string, 0
127
- else
128
- @socket.write string
129
- end
130
-
133
+ write string
131
134
  @socket.flush
132
135
 
133
136
  matches = @socket.read_match(kwargs) { |match| yield match if block_given? }
@@ -198,10 +201,16 @@ module Ionian
198
201
  end
199
202
 
200
203
  unless @persistent
204
+ @socket.flush
205
+
201
206
  # Read in data to prevent RST packets.
202
- has_data = ::IO.select [@socket], nil, nil, 0
203
- @socket.readpartial 0xFFFF if has_data
207
+ # TODO: Shutdown read stream instead?
208
+ @socket.read_all nonblocking: true
204
209
 
210
+ # TODO: Sleep added so that data can be read on the receiving
211
+ # end. Can this be changed to shutdown write?
212
+ # Why isn't so_linger taking care of this?
213
+ sleep 0.01
205
214
  @socket.close
206
215
  end
207
216
 
@@ -221,9 +230,9 @@ module Ionian
221
230
  when :tcp
222
231
  @socket = ::TCPSocket.new @host, @port
223
232
  @socket.extend Ionian::Extension::Socket
224
- @socket.expression = @expression if @expression
225
- @socket.no_delay = true if @no_delay
226
- @socket.cork = true if @cork
233
+
234
+ @socket.no_delay = @no_delay
235
+ @socket.cork = @cork
227
236
 
228
237
  when :udp
229
238
  @socket = ::UDPSocket.new
@@ -240,10 +249,10 @@ module Ionian
240
249
  when :unix
241
250
  @socket = ::UNIXSocket.new @host
242
251
  @socket.extend Ionian::Extension::Socket
252
+
243
253
  end
244
254
 
245
- # TODO: Implement SO_LINGER flag for non-persistent sockets;
246
- # especially send-and-forget.
255
+ @socket.linger = @linger
247
256
 
248
257
  @socket.expression = @expression if @expression
249
258
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ionian
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.6
4
+ version: 0.6.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alex McLain
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-04-12 00:00:00.000000000 Z
11
+ date: 2014-04-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake