ionian 0.6.6 → 0.6.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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