ionian 0.4.1 → 0.5.0

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.
@@ -1,5 +1,6 @@
1
1
  require 'ionian/extension/io'
2
2
  require 'socket'
3
+ require 'ipaddr'
3
4
 
4
5
  module Ionian
5
6
  module Extension
@@ -23,20 +24,223 @@ module Ionian
23
24
  def initialize_ionian_socket
24
25
  end
25
26
 
26
- # Returns true if the TCP_NODELAY flag is enabled (Nagle disabled).
27
- # Otherwise false.
27
+ # Returns true if local address reuse is allowed.
28
+ # ( SO_REUSEADDR )
29
+ def reuse_addr
30
+ param = self.getsockopt(::Socket::SOL_SOCKET, ::Socket::SO_REUSEADDR)
31
+ .data.unpack('i').first
32
+ param > 0 ? true : false
33
+ end
34
+
35
+ alias_method :reuse_addr?, :reuse_addr
36
+
37
+ # Allows local address reuse if true.
38
+ # ( SO_REUSEADDR )
39
+ def reuse_addr=(value)
40
+ param = value ? 1 : 0
41
+ self.setsockopt ::Socket::SOL_SOCKET, ::Socket::SO_REUSEADDR, [param].pack('i')
42
+ end
43
+
44
+ # Returns the time to live (hop limit).
45
+ # ( IP_TTL )
46
+ def ttl
47
+ self.getsockopt(::Socket::IPPROTO_IP, ::Socket::IP_TTL)
48
+ .data.unpack('i').first
49
+ end
50
+
51
+ alias_method :ttl?, :ttl
52
+
53
+ # Sets the time to live (hop limit).
54
+ # ( IP_TTL )
55
+ def ttl=(value)
56
+ self.setsockopt ::Socket::IPPROTO_IP, ::Socket::IP_TTL, [value].pack('i')
57
+ end
58
+
59
+ # Returns true if the Nagle algorithm is disabled.
60
+ # ( TCP_NODELAY )
28
61
  def no_delay
29
- nagle_disabled = self.getsockopt(::Socket::IPPROTO_TCP, ::Socket::TCP_NODELAY).data.ord
30
- nagle_disabled > 0 ? true : false
62
+ param = self.getsockopt(::Socket::IPPROTO_TCP, ::Socket::TCP_NODELAY)
63
+ .data.unpack('i').first
64
+ param > 0 ? true : false
31
65
  end
32
66
 
33
- # Setting to true enables the TCP_NODELAY flag (disables Nagle).
34
- # Setting to false disables the flag (enables Nagle).
67
+ alias_method :no_delay?, :no_delay
68
+
69
+ # Disables the Nagle algorithm if true.
70
+ # ( TCP_NODELAY )
35
71
  def no_delay=(value)
36
- disable_nagle = value ? 1 : 0
37
- self.setsockopt ::Socket::IPPROTO_TCP, ::Socket::TCP_NODELAY, disable_nagle
72
+ param = value ? 1 : 0
73
+ self.setsockopt ::Socket::IPPROTO_TCP, ::Socket::TCP_NODELAY, [param].pack('i')
74
+ end
75
+
76
+ # Returns true if multiple writes are buffered into a single segment.
77
+ # See #recork.
78
+ # Linux only.
79
+ # ( TCP_CORK )
80
+ def cork
81
+ param = self.getsockopt(::Socket::IPPROTO_TCP, ::Socket::TCP_CORK)
82
+ .data.unpack('i').first
83
+ param > 0 ? true : false
84
+ end
85
+
86
+ alias_method :cork?, :cork
87
+
88
+ # Buffers multiple writes into a single segment if true.
89
+ # The segment is sent once the cork flag is disabled,
90
+ # the upper limit on the size of a segment is reached,
91
+ # the socket is closed, or 200ms elapses from the time
92
+ # the first corked byte is written.
93
+ # See #recork.
94
+ # Linux only.
95
+ # ( TCP_CORK )
96
+ def cork=(value)
97
+ param = value ? 1 : 0
98
+ self.setsockopt ::Socket::IPPROTO_TCP, ::Socket::TCP_CORK, [param].pack('i')
99
+ end
100
+
101
+ # Unsets cork to transmit data, then reapplies cork.
102
+ # ( TCP_CORK )
103
+ def recork
104
+ self.setsockopt ::Socket::IPPROTO_TCP, ::Socket::TCP_CORK, [0].pack('i')
105
+ self.setsockopt ::Socket::IPPROTO_TCP, ::Socket::TCP_CORK, [1].pack('i')
106
+ end
107
+
108
+ # Join a multicast group.
109
+ # Address is the class D multicast address (uses remote
110
+ # address if not specified).
111
+ # Interface is the local network interface to receive the
112
+ # multicast traffic on (all interfaces if not specified).
113
+ # ( IP_ADD_MEMBERSHIP )
114
+ def ip_add_membership(address = nil, interface = nil)
115
+ address ||= self.remote_address.ip_address
116
+ interface ||= '0.0.0.0'
117
+
118
+ self.setsockopt \
119
+ ::Socket::IPPROTO_IP,
120
+ ::Socket::IP_ADD_MEMBERSHIP,
121
+ IPAddr.new(address).hton + IPAddr.new(interface).hton
122
+ end
123
+
124
+ # Leave a multicast group.
125
+ # Address is the class D multicast address (uses remote
126
+ # address if not specified).
127
+ # Interface is the local network interface the multicast
128
+ # traffic is received on (all interfaces if not specified).
129
+ # ( IP_DROP_MEMBERSHIP )
130
+ def ip_drop_membership(address = nil, interface = nil)
131
+ address ||= self.remote_address.ip_address
132
+ interface ||= '0.0.0.0'
133
+
134
+ self.setsockopt \
135
+ ::Socket::IPPROTO_IP,
136
+ ::Socket::IP_DROP_MEMBERSHIP,
137
+ IPAddr.new(address).hton + IPAddr.new(interface).hton
138
+ end
139
+
140
+ # Returns the default interface for outgoing multicasts.
141
+ # ( IP_MULTICAST_IF )
142
+ def ip_multicast_if
143
+ self.getsockopt(::Socket::IPPROTO_IP, ::Socket::IP_MULTICAST_IF)
144
+ .data.unpack('CCCC').join('.')
145
+ end
146
+
147
+ # Specify default interface for outgoing multicasts.
148
+ # ( IP_MULTICAST_IF )
149
+ def ip_multicast_if=(interface = nil)
150
+ interface ||= '0.0.0.0'
151
+
152
+ self.setsockopt \
153
+ ::Socket::IPPROTO_IP,
154
+ ::Socket::IP_MULTICAST_IF,
155
+ IPAddr.new(interface).hton
156
+ end
157
+
158
+ # Returns the time to live (hop limit) for outgoing multicasts.
159
+ # ( IP_MULTICAST_TTL )
160
+ def ip_multicast_ttl
161
+ self.getsockopt(::Socket::IPPROTO_IP, ::Socket::IP_MULTICAST_TTL)
162
+ .data.unpack('C').first
163
+ end
164
+
165
+ # Set the time to live (hop limit) for outgoing multicasts.
166
+ # ( IP_MULTICAST_TTL )
167
+ def ip_multicast_ttl=(value)
168
+ self.setsockopt ::Socket::IPPROTO_IP, ::Socket::IP_MULTICAST_TTL, [value].pack('C')
169
+ end
170
+
171
+ # Returns true if loopback of outgoing multicasts is enabled.
172
+ # ( IP_MULTICAST_LOOP )
173
+ def ip_multicast_loop
174
+ param = self.getsockopt(::Socket::IPPROTO_IP, ::Socket::IP_MULTICAST_LOOP)
175
+ .data.unpack('C').first
176
+ param > 0 ? true : false
177
+ end
178
+
179
+ alias_method :ip_multicast_loop?, :ip_multicast_loop
180
+
181
+ # Enables loopback of outgoing multicasts if true.
182
+ # ( IP_MULTICAST_LOOP )
183
+ def ip_multicast_loop=(value)
184
+ param = value ? 1 : 0
185
+ self.setsockopt ::Socket::IPPROTO_IP, ::Socket::IP_MULTICAST_LOOP, [param].pack('C')
186
+ end
187
+
188
+ def ipv6_add_membership
189
+ # TODO: Implement
190
+ false
38
191
  end
39
192
 
193
+ def ipv6_drop_membership
194
+ # TODO: Implement
195
+ false
196
+ end
197
+
198
+ def ipv6_multicast_if
199
+ # TODO: Implement
200
+ false
201
+ end
202
+
203
+ def ipv6_multicast_if=(value)
204
+ # TODO: Implement
205
+ end
206
+
207
+ def ipv6_multicast_hops
208
+ # TODO: Implement
209
+ false
210
+ end
211
+
212
+ def ipv6_multicast_hops=(value)
213
+ # TODO: Implement
214
+ end
215
+
216
+ def ipv6_multicast_loop
217
+ # TODO: Implement
218
+ false
219
+ end
220
+
221
+ alias_method :ipv6_multicast_loop?, :ipv6_multicast_loop
222
+
223
+ def ipv6_multicast_loop=(value)
224
+ # TODO: Implement
225
+ end
226
+
227
+
228
+ class << self
229
+ # Returns true if the given address is within the multicast range.
230
+ def multicast(address)
231
+ address >= '224.0.0.0' and address <= '239.255.255.255' ? true : false
232
+ end
233
+
234
+ alias_method :multicast?, :multicast
235
+ end
236
+
237
+ # Returns true if the socket's address is in the multicast range.
238
+ def multicast
239
+ Ionian::Extension::Socket.multicast self.remote_address.ip_address
240
+ end
241
+
242
+ alias_method :multicast?, :multicast
243
+
40
244
  end
41
245
  end
42
246
  end
data/lib/ionian/socket.rb CHANGED
@@ -6,22 +6,43 @@ module Ionian
6
6
  class Socket
7
7
 
8
8
  # Args:
9
- # host: IP or hostname to connect to.
10
- # port: Connection's port number. Default is 23. Unused by :unix protocol.
11
- # protocol: Type of socket to create. :tcp, :udp, :unix. Default is :tcp.
9
+ # host: IP or hostname to connect to.
10
+ # port: Connection's port number. Default is 23. Unused by :unix protocol.
11
+ # protocol: Type of socket to create. :tcp, :udp, :unix. Default is :tcp.
12
+ # :udp will be automatically selected for addresses in the multicast range.
12
13
  # persistent: The socket remains open after data is sent if this is true.
13
14
  # The socket closes after data is sent and a packet is received
14
15
  # if this is false. Default is true.
16
+ # bind_port: Local UDP port to bind to for receiving data, if different than
17
+ # the remote port being connected to.
18
+ # reuse_addr: Set true to enable the SO_REUSEADDR flag. Allows local address reuse.
19
+ # no_delay: Set true to enable the TCP_NODELAY flag. Disables Nagle algorithm.
20
+ # cork: Set true to enable the TCP_CORK flag. Buffers multiple writes
21
+ # into one segment.
15
22
  # expression: Overrides the #read_match regular expression for received data.
16
23
  def initialize(**kwargs)
17
24
  @socket = nil
18
25
 
26
+ # TODO: Should be able to parse the port out of host.
27
+ # :port should override this parsed value.
28
+
19
29
  @host = kwargs.fetch :host
20
- @port = kwargs.fetch :port, 23
21
- @protocol = kwargs.fetch :protocol, :tcp
30
+ @port = kwargs.fetch :port, 23
31
+ @bind_port = kwargs.fetch :bind_port, @port
32
+
33
+ # Automatically select UDP for the multicast range. Otherwise default to TCP.
34
+ default_protocol = :tcp
35
+ default_protocol = :udp if Ionian::Extension::Socket.multicast? @host
36
+ default_protocol = :unix if @host.start_with? '/'
37
+
38
+ @protocol = kwargs.fetch :protocol, default_protocol
22
39
  @persistent = kwargs.fetch :persistent, true
23
40
  @expression = kwargs.fetch :expression, nil
24
41
 
42
+ @reuse_addr = kwargs.fetch :reuse_addr, false
43
+ @no_delay = kwargs.fetch :no_delay, false
44
+ @cork = kwargs.fetch :cork, false
45
+
25
46
  create_socket if @persistent
26
47
  end
27
48
 
@@ -123,15 +144,30 @@ module Ionian
123
144
  case @protocol
124
145
  when :tcp
125
146
  @socket = ::TCPSocket.new @host, @port
147
+ @socket.extend Ionian::Extension::Socket
148
+ @socket.no_delay = true if @no_delay
149
+ @socket.cork = true if @cork
150
+
126
151
  when :udp
127
152
  @socket = ::UDPSocket.new
128
- @socket.bind '', @port
153
+ @socket.extend Ionian::Extension::Socket
154
+
155
+ @socket.reuse_addr = true if
156
+ @reuse_addr or Ionian::Extension::Socket.multicast? @host
157
+
158
+ @socket.bind ::Socket::INADDR_ANY, @bind_port
129
159
  @socket.connect @host, @port
160
+
161
+ @socket.ip_add_membership if Ionian::Extension::Socket.multicast? @host
162
+
130
163
  when :unix
131
164
  @socket = ::UNIXSocket.new @host
165
+ @socket.extend Ionian::Extension::Socket
132
166
  end
133
167
 
134
- @socket.extend Ionian::Extension::Socket
168
+ # TODO: Implement SO_LINGER flag for non-persistent sockets;
169
+ # especially send-and-forget.
170
+
135
171
  @socket.expression = @expression if @expression
136
172
 
137
173
  initialize_socket_methods
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.4.1
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alex McLain
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-12-03 00:00:00.000000000 Z
11
+ date: 2013-12-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake