tipcsocket 0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +7 -0
- data/LICENSE +20 -0
- data/README +77 -0
- data/Rakefile +56 -0
- data/demo/hello_world/client.rb +55 -0
- data/demo/hello_world/server.rb +29 -0
- data/demo/stream_demo/client.rb +121 -0
- data/demo/stream_demo/server.rb +69 -0
- data/lib/tipcsocket.rb +514 -0
- metadata +54 -0
data/CHANGELOG
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2007 Corey Burrows
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
= TIPCSocket
|
2
|
+
|
3
|
+
Ruby bindings for the TIPC[http://tipc.sourceforge.net] native socket API.
|
4
|
+
|
5
|
+
= Installing TIPCSocket
|
6
|
+
|
7
|
+
Get TIPCSocket from RubyForge.
|
8
|
+
|
9
|
+
$ gem install tipcsocket
|
10
|
+
|
11
|
+
= Example
|
12
|
+
|
13
|
+
Server:
|
14
|
+
|
15
|
+
require 'rubygems'
|
16
|
+
require 'tipcsocket'
|
17
|
+
|
18
|
+
include TIPCSocket::Constants
|
19
|
+
|
20
|
+
server_addr = TIPCNameSeq.new(18888, 17, 17, TIPC_ZONE_SCOPE)
|
21
|
+
|
22
|
+
s = TIPCSocket.new(:rdm)
|
23
|
+
s.bind(server_addr)
|
24
|
+
|
25
|
+
data, client = s.recvfrom(65535)
|
26
|
+
|
27
|
+
client = TIPCSocket.unpack_sockaddr(client)
|
28
|
+
|
29
|
+
p client
|
30
|
+
|
31
|
+
puts "server: message received: #{data}"
|
32
|
+
|
33
|
+
s.send("hello client!", 0, client)
|
34
|
+
|
35
|
+
s.close
|
36
|
+
|
37
|
+
Client:
|
38
|
+
|
39
|
+
require 'rubygems'
|
40
|
+
require 'tipcsocket'
|
41
|
+
|
42
|
+
include TIPCSocket::Constants
|
43
|
+
|
44
|
+
server_addr = TIPCName.new(18888, 17, TIPC_NODE_SCOPE)
|
45
|
+
|
46
|
+
s = TIPCSocket.new(:rdm)
|
47
|
+
s.send("hello server!", 0, server_addr)
|
48
|
+
|
49
|
+
msg = s.recv(65535)
|
50
|
+
|
51
|
+
puts "client: received response: #{msg}"
|
52
|
+
|
53
|
+
s.close
|
54
|
+
|
55
|
+
Server Output:
|
56
|
+
|
57
|
+
$ ruby server.rb
|
58
|
+
#<TIPCPortId:0xb79c89a4 @family=30, @ref=2292940796, @scope=0, @addrtype=3, @node=0>
|
59
|
+
server: message received: hello server!
|
60
|
+
|
61
|
+
Client Output:
|
62
|
+
|
63
|
+
$ ruby client.rb
|
64
|
+
client: received response: hello client!
|
65
|
+
|
66
|
+
= More Examples
|
67
|
+
|
68
|
+
See the demo/ directory for more examples.
|
69
|
+
|
70
|
+
= Project Page
|
71
|
+
|
72
|
+
http://rubyforge.org/projects/tipcsocket
|
73
|
+
|
74
|
+
= Author
|
75
|
+
|
76
|
+
Corey Burrows (mailto:corey.burrows@gmail.com)
|
77
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
|
2
|
+
require 'rubygems'
|
3
|
+
Gem::manage_gems
|
4
|
+
require 'rake/gempackagetask'
|
5
|
+
require 'rake/clean'
|
6
|
+
require 'rake/rdoctask'
|
7
|
+
|
8
|
+
NAME = 'tipcsocket'
|
9
|
+
VERS = '0.1'
|
10
|
+
RUBYFORGE_USER = "burrows"
|
11
|
+
WWW = "#{RUBYFORGE_USER}@rubyforge.org:/var/www/gforge-projects/#{NAME}/"
|
12
|
+
|
13
|
+
RDOC_MAIN = "README"
|
14
|
+
|
15
|
+
spec = Gem::Specification.new do |s|
|
16
|
+
s.name = NAME
|
17
|
+
s.version = VERS
|
18
|
+
s.author = "Corey Burrows"
|
19
|
+
s.email = "corey.burrows@gmail.com"
|
20
|
+
s.platform = Gem::Platform::RUBY
|
21
|
+
s.summary = "Ruby bindings for the TIPC socket API."
|
22
|
+
s.files = %w{README CHANGELOG LICENSE Rakefile} +
|
23
|
+
Dir.glob("lib/**/*.{rb}") +
|
24
|
+
Dir.glob("test/**/*.rb") +
|
25
|
+
Dir.glob("demo/**/*.rb")
|
26
|
+
s.require_path = "lib"
|
27
|
+
s.autorequire = "tipcsocket"
|
28
|
+
#s.test_file = ""
|
29
|
+
s.has_rdoc = true
|
30
|
+
end
|
31
|
+
|
32
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
33
|
+
pkg.need_tar = true
|
34
|
+
end
|
35
|
+
|
36
|
+
Rake::RDocTask.new do |rd|
|
37
|
+
rd.main = RDOC_MAIN
|
38
|
+
rd.rdoc_files.include(RDOC_MAIN, "lib/**/*.rb", "CHANGELOG", "LICENSE")
|
39
|
+
rd.options << "--all"
|
40
|
+
end
|
41
|
+
|
42
|
+
CLEAN += FileList["ext/**/*.o", "ext/**/*.so", "ext/**/*.bundle", "ext/**/mkmf.log"]
|
43
|
+
|
44
|
+
task :test => :build do
|
45
|
+
end
|
46
|
+
|
47
|
+
task :install do
|
48
|
+
name = "#{NAME}-#{VERS}.gem"
|
49
|
+
sh %{rake pkg/#{name}}
|
50
|
+
sh %{sudo gem install pkg/#{name}}
|
51
|
+
end
|
52
|
+
|
53
|
+
task :uninstall do
|
54
|
+
sh %{sudo gem uninstall #{NAME}}
|
55
|
+
end
|
56
|
+
|
@@ -0,0 +1,55 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$:.unshift File.join(File.dirname(__FILE__), '..', '..', 'lib')
|
4
|
+
|
5
|
+
require 'tipcsocket'
|
6
|
+
include TIPCSocket::Constants
|
7
|
+
|
8
|
+
puts "****** TIPC client hello world program started ******\n"
|
9
|
+
|
10
|
+
$server_type = 18888
|
11
|
+
$server_inst = 17
|
12
|
+
|
13
|
+
def wait_for_server(name, wait)
|
14
|
+
puts "Client: waiting for server #{name.type}, #{name.instance}..."
|
15
|
+
|
16
|
+
topsrv = TIPCName.new(TIPC_TOP_SRV, TIPC_TOP_SRV)
|
17
|
+
subscr = TIPCSubscr.new(
|
18
|
+
TIPCNameSeq.new(name.type, name.instance, name.instance),
|
19
|
+
wait,
|
20
|
+
TIPC_SUB_SERVICE)
|
21
|
+
|
22
|
+
s = TIPCSocket.new(:seqpacket)
|
23
|
+
s.connect(topsrv)
|
24
|
+
s.send(subscr.pack, 0)
|
25
|
+
|
26
|
+
rsp = s.recv(65535)
|
27
|
+
|
28
|
+
event = TIPCEvent.unpack(rsp)
|
29
|
+
|
30
|
+
if event.event != TIPC_PUBLISHED
|
31
|
+
puts "Client: server #{name.type}, #{name.instance} not published within #{wait/1000} [s]"
|
32
|
+
exit 1
|
33
|
+
end
|
34
|
+
|
35
|
+
s.close
|
36
|
+
end
|
37
|
+
|
38
|
+
s = TIPCSocket.new(:rdm)
|
39
|
+
|
40
|
+
# send a message to the server
|
41
|
+
server_addr = TIPCName.new($server_type, $server_inst, TIPC_NODE_SCOPE)
|
42
|
+
|
43
|
+
wait_for_server(server_addr, 10000)
|
44
|
+
|
45
|
+
s.send("Hello World", 0, server_addr)
|
46
|
+
|
47
|
+
# wait for a response
|
48
|
+
msg = s.recv(65535)
|
49
|
+
|
50
|
+
puts "Client: Received response: #{msg}"
|
51
|
+
|
52
|
+
s.close
|
53
|
+
|
54
|
+
puts "****** TIPC client hello program finished ******"
|
55
|
+
|
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$:.unshift File.join(File.dirname(__FILE__), '..', '..', 'lib')
|
4
|
+
|
5
|
+
require 'tipcsocket'
|
6
|
+
include TIPCSocket::Constants
|
7
|
+
|
8
|
+
$server_type = 18888
|
9
|
+
$server_inst = 17
|
10
|
+
|
11
|
+
puts "****** TIPC server hello world program started ******\n\n"
|
12
|
+
|
13
|
+
server_addr = TIPCNameSeq.new($server_type, $server_inst, $server_inst, TIPC_ZONE_SCOPE)
|
14
|
+
|
15
|
+
s = TIPCSocket.new(:rdm)
|
16
|
+
s.bind(server_addr)
|
17
|
+
|
18
|
+
data, client = s.recvfrom(65535)
|
19
|
+
|
20
|
+
client = TIPCSocket.unpack_sockaddr(client)
|
21
|
+
|
22
|
+
puts "Server: Message received: #{data} !"
|
23
|
+
|
24
|
+
s.send("Uh ?", 0, client)
|
25
|
+
|
26
|
+
s.close
|
27
|
+
|
28
|
+
puts "\n****** TIPC server hello program finished ******"
|
29
|
+
|
@@ -0,0 +1,121 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$:.unshift File.join(File.dirname(__FILE__), '..', '..', 'lib')
|
4
|
+
|
5
|
+
require 'tipcsocket'
|
6
|
+
include TIPCSocket::Constants
|
7
|
+
|
8
|
+
$server_type = 8888
|
9
|
+
$server_inst = 17
|
10
|
+
|
11
|
+
$buf_size = 2000
|
12
|
+
$msg_size = 80
|
13
|
+
|
14
|
+
def wait_for_server(name, wait)
|
15
|
+
puts "Client: waiting for server #{name.type}, #{name.instance}..."
|
16
|
+
|
17
|
+
topsrv = TIPCName.new(TIPC_TOP_SRV, TIPC_TOP_SRV)
|
18
|
+
subscr = TIPCSubscr.new(
|
19
|
+
TIPCNameSeq.new(name.type, name.instance, name.instance),
|
20
|
+
wait,
|
21
|
+
TIPC_SUB_SERVICE)
|
22
|
+
|
23
|
+
s = TIPCSocket.new(:seqpacket)
|
24
|
+
s.connect(topsrv)
|
25
|
+
s.send(subscr.pack, 0)
|
26
|
+
|
27
|
+
rsp = s.recv(65535)
|
28
|
+
|
29
|
+
event = TIPCEvent.unpack(rsp)
|
30
|
+
|
31
|
+
if event.event != TIPC_PUBLISHED
|
32
|
+
puts "Client: server #{name.type}, #{name.instance} not published within #{wait/1000} [s]"
|
33
|
+
exit 1
|
34
|
+
end
|
35
|
+
|
36
|
+
s.close
|
37
|
+
end
|
38
|
+
|
39
|
+
puts "****** TIPC stream demo client started ******"
|
40
|
+
|
41
|
+
server_addr = TIPCName.new($server_type, $server_inst)
|
42
|
+
|
43
|
+
wait_for_server(server_addr, 10000)
|
44
|
+
|
45
|
+
s = TIPCSocket.new(:stream)
|
46
|
+
|
47
|
+
begin
|
48
|
+
s.connect(server_addr)
|
49
|
+
rescue Exception => e
|
50
|
+
puts "Client: connect failed: #{e}"
|
51
|
+
exit 1
|
52
|
+
end
|
53
|
+
|
54
|
+
# create buffer containing numerous (size,data) records
|
55
|
+
|
56
|
+
tot_size = 0
|
57
|
+
rec_size = 1
|
58
|
+
rec_num = 0
|
59
|
+
buf = ""
|
60
|
+
|
61
|
+
while tot_size + 4 + rec_size < $buf_size
|
62
|
+
rec_num += 1
|
63
|
+
buf += [rec_size].pack("N")
|
64
|
+
rec_size.times do
|
65
|
+
buf += [rec_size].pack("C")
|
66
|
+
end
|
67
|
+
puts "Client: creating record #{rec_num} of size #{rec_size} bytes"
|
68
|
+
|
69
|
+
tot_size += (4 + rec_size)
|
70
|
+
rec_size = (rec_size + 147) & 0xFF;
|
71
|
+
|
72
|
+
rec_size = 1 if (rec_size == 0) # record size must me 1-255 bytes
|
73
|
+
end
|
74
|
+
|
75
|
+
# now send records using messages that break record boundaries
|
76
|
+
|
77
|
+
puts "Client: sending records using #{$msg_size} byte messages"
|
78
|
+
|
79
|
+
sent_size = 0
|
80
|
+
while sent_size < tot_size
|
81
|
+
if (sent_size + $msg_size) <= tot_size
|
82
|
+
msg_size = $msg_size
|
83
|
+
else
|
84
|
+
msg_size = (tot_size - sent_size)
|
85
|
+
end
|
86
|
+
|
87
|
+
if (0 > s.send(buf[sent_size, msg_size], 0))
|
88
|
+
puts "Client: failed to send"
|
89
|
+
exit 1
|
90
|
+
end
|
91
|
+
|
92
|
+
sent_size += msg_size
|
93
|
+
end
|
94
|
+
|
95
|
+
# now grab set of one-byte client acknowledgements all at once
|
96
|
+
|
97
|
+
puts "Client: waiting for server acknowledgements"
|
98
|
+
rsp = s.recv(rec_num, Socket::MSG_WAITALL)
|
99
|
+
if rsp.length != rec_num
|
100
|
+
puts "Client: acknowledge error 1"
|
101
|
+
exit 1
|
102
|
+
end
|
103
|
+
|
104
|
+
rsp = nil
|
105
|
+
begin
|
106
|
+
rsp = s.recv_nonblock(1)
|
107
|
+
rescue Errno::EAGAIN => e
|
108
|
+
end
|
109
|
+
|
110
|
+
if rsp
|
111
|
+
puts "Client: acknowledge error 2"
|
112
|
+
exit 1
|
113
|
+
end
|
114
|
+
|
115
|
+
puts "Client: received #{rec_num} acknowledgements"
|
116
|
+
|
117
|
+
s.shutdown(Socket::SHUT_RDWR)
|
118
|
+
s.close
|
119
|
+
|
120
|
+
puts "****** TIPC stream demo client finished ******"
|
121
|
+
exit 0
|
@@ -0,0 +1,69 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$:.unshift File.join(File.dirname(__FILE__), '..', '..', 'lib')
|
4
|
+
|
5
|
+
require 'tipcsocket'
|
6
|
+
include TIPCSocket::Constants
|
7
|
+
|
8
|
+
$server_type = 8888
|
9
|
+
$server_inst = 17
|
10
|
+
|
11
|
+
puts "****** TIPC stream demo server started ******"
|
12
|
+
|
13
|
+
listener = TIPCSocket.new(:stream)
|
14
|
+
|
15
|
+
server_addr = TIPCNameSeq.new($server_type, $server_inst, $server_inst, TIPC_ZONE_SCOPE)
|
16
|
+
|
17
|
+
listener.bind(server_addr)
|
18
|
+
listener.listen(0)
|
19
|
+
|
20
|
+
peer, peer_addr = listener.accept
|
21
|
+
|
22
|
+
rec_num = 0
|
23
|
+
|
24
|
+
loop do
|
25
|
+
begin
|
26
|
+
puts "calling peer.recv..."
|
27
|
+
msg = peer.recv(4, Socket::MSG_WAITALL)
|
28
|
+
puts "recieved #{msg.length} bytes"
|
29
|
+
rescue Exception => e
|
30
|
+
puts "Server: client terminated abnormally: #{e}"
|
31
|
+
exit 1
|
32
|
+
end
|
33
|
+
|
34
|
+
if msg.length == 0
|
35
|
+
puts "Server: client terminated normally"
|
36
|
+
break
|
37
|
+
end
|
38
|
+
|
39
|
+
rec_num += 1
|
40
|
+
|
41
|
+
rec_size = msg.unpack("N")[0]
|
42
|
+
puts "Server: receiving record #{rec_num} of #{rec_size} bytes"
|
43
|
+
|
44
|
+
msg = peer.recv(rec_size, Socket::MSG_WAITALL)
|
45
|
+
|
46
|
+
if msg.length != rec_size
|
47
|
+
puts "Server: receive error, got #{msg.length} bytes"
|
48
|
+
exit 1
|
49
|
+
end
|
50
|
+
|
51
|
+
msg.each_byte do |b|
|
52
|
+
if b != rec_size
|
53
|
+
puts "Server: record content error"
|
54
|
+
exit 1
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
puts "Server: record #{rec_num} received"
|
59
|
+
|
60
|
+
# send 1 byte acknowledgement (value is irrelevant)
|
61
|
+
peer.send("X", 0)
|
62
|
+
|
63
|
+
puts "Server: record #{rec_num} acknowledged"
|
64
|
+
end
|
65
|
+
|
66
|
+
puts "****** TIPC stream demo server finished ******"
|
67
|
+
|
68
|
+
exit 0
|
69
|
+
|
data/lib/tipcsocket.rb
ADDED
@@ -0,0 +1,514 @@
|
|
1
|
+
|
2
|
+
require 'socket'
|
3
|
+
|
4
|
+
module Socket::Constants
|
5
|
+
AF_TIPC = 30
|
6
|
+
PF_TIPC = AF_TIPC
|
7
|
+
SOL_TIPC = 271
|
8
|
+
end
|
9
|
+
|
10
|
+
# Represents a TIPC port identifier.
|
11
|
+
#
|
12
|
+
# From the {TIPC Programmer's Guide}[http://tipc.sourceforge.net/doc/Programmers_Guide.txt]:
|
13
|
+
#
|
14
|
+
# Each port in a TIPC network has a unique "port identifier" or "port ID",
|
15
|
+
# which is typically denoted as <Z.C.N:ref>. The port ID is assigned
|
16
|
+
# automatically by TIPC when the port is created, and consists of the 32-bit
|
17
|
+
# network address of the port's node and a 32-bit reference value. The
|
18
|
+
# reference value is guaranteed to be unique on a per-node basis and will not
|
19
|
+
# be reused for a long time once the port ceases to exist.
|
20
|
+
class TIPCPortId
|
21
|
+
attr_reader :family, :addrtype
|
22
|
+
attr_accessor :ref, :node, :scope
|
23
|
+
|
24
|
+
# Create a new TIPCPortId instance.
|
25
|
+
#
|
26
|
+
# === Parameters
|
27
|
+
# * ref - 32 bit reference value
|
28
|
+
# * node - 32 bit network address of the port's node
|
29
|
+
# * scope - the scope (zone, cluster, or node) to use when packing this port
|
30
|
+
# id as a TIPC address (optional)
|
31
|
+
def initialize(ref, node, scope = TIPCSocket::Constants::TIPC_NODE_SCOPE)
|
32
|
+
@family = Socket::Constants::AF_TIPC
|
33
|
+
@addrtype = TIPCSocket::Constants::TIPC_ADDR_ID
|
34
|
+
@ref = ref
|
35
|
+
@node = node
|
36
|
+
@scope = scope
|
37
|
+
end
|
38
|
+
|
39
|
+
# Pack an instance of a TIPCPortId as a 16 byte TIPC network address suitable
|
40
|
+
# for passing to one of the standard Socket methods (connect, send, etc.).
|
41
|
+
#
|
42
|
+
# Produces a 16 byte binary string with the following format:
|
43
|
+
# * family - unsigned short (2 bytes)
|
44
|
+
# * addrtype - unsigned char (1 byte)
|
45
|
+
# * scope - signed char (1 byte)
|
46
|
+
# * ref - uint32 (4 bytes)
|
47
|
+
# * node - uint32 (4 bytes)
|
48
|
+
# * padding - uint32 (4 bytes)
|
49
|
+
def pack_addr
|
50
|
+
[
|
51
|
+
self.family,
|
52
|
+
self.addrtype,
|
53
|
+
self.scope,
|
54
|
+
self.ref,
|
55
|
+
self.node,
|
56
|
+
0
|
57
|
+
].pack("SCcL3")
|
58
|
+
end
|
59
|
+
|
60
|
+
# Pack an instance of a TIPCPortId.
|
61
|
+
#
|
62
|
+
# Produces an 8 byte string with the following format:
|
63
|
+
# * ref - uint32 (4 bytes)
|
64
|
+
# * node - uint32 (4 bytes)
|
65
|
+
def pack
|
66
|
+
[
|
67
|
+
self.ref,
|
68
|
+
self.node,
|
69
|
+
].pack("L2")
|
70
|
+
end
|
71
|
+
|
72
|
+
# Create a new TIPCPortId instance from a 16 byte binary string containing a
|
73
|
+
# TIPC address.
|
74
|
+
#
|
75
|
+
# === Parameters
|
76
|
+
# * bytes - 16 byte string containing TIPC address
|
77
|
+
def self.unpack_addr(bytes)
|
78
|
+
data = bytes.unpack("SCcL3")
|
79
|
+
self.new(data[3], data[4], data[2])
|
80
|
+
end
|
81
|
+
|
82
|
+
# Create a new TIPCPortId instance from an 8 byte binary string containing
|
83
|
+
# a TIPC port indentifier.
|
84
|
+
#
|
85
|
+
# === Parameters
|
86
|
+
# * bytes - 8 byte string containing TIPC port identifier
|
87
|
+
def self.unpack(bytes)
|
88
|
+
data = bytes.unpack("L2")
|
89
|
+
self.new(data[0], data[1])
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# Represents a TIPC name address of the form <type, instance>.
|
94
|
+
#
|
95
|
+
# From the {TIPC Programmer's Guide}[http://tipc.sourceforge.net/doc/Programmers_Guide.txt]:
|
96
|
+
#
|
97
|
+
# The basic unit of functional addressing within TIPC is the "port name", which
|
98
|
+
# is typically denoted as {type,instance}. A port name consists of a 32-bit
|
99
|
+
# type field and a 32-bit instance field, both of which are chosen by the
|
100
|
+
# application. Typically, the type field is used to indicate the class of
|
101
|
+
# service provided by the port, while the instance field can be used as a sub-
|
102
|
+
# class indicator.
|
103
|
+
class TIPCName
|
104
|
+
attr_reader :family, :addrtype
|
105
|
+
attr_accessor :type, :instance, :scope, :domain
|
106
|
+
|
107
|
+
# Create a new TIPCName instance.
|
108
|
+
#
|
109
|
+
# === Parameters
|
110
|
+
# * type - arbitrary 32 bit type value
|
111
|
+
# * instance - arbitrary 32 bit instance value
|
112
|
+
# * scope - the scope (zone, cluster, or node) to use when packing
|
113
|
+
# this name as a TIPC address (optional)
|
114
|
+
# * domain - indicates the search domain used during the name lookup
|
115
|
+
# process (optional)
|
116
|
+
def initialize(type, instance, scope = TIPCSocket::Constants::TIPC_NODE_SCOPE, domain = 0)
|
117
|
+
@family = Socket::Constants::AF_TIPC
|
118
|
+
@addrtype = TIPCSocket::Constants::TIPC_ADDR_NAME
|
119
|
+
@type = type
|
120
|
+
@instance = instance
|
121
|
+
@scope = scope
|
122
|
+
@domain = 0
|
123
|
+
end
|
124
|
+
|
125
|
+
# Pack an instance of a TIPCName as a 16 byte TIPC network address suitable
|
126
|
+
# for passing to one of the standard Socket methods (connect, send, etc.).
|
127
|
+
#
|
128
|
+
# Produces a 16 byte binary string with the following format:
|
129
|
+
# * family - unsigned short (2 bytes)
|
130
|
+
# * addrtype - unsigned char (1 byte)
|
131
|
+
# * scope - signed char (1 byte)
|
132
|
+
# * type - uint32 (4 bytes)
|
133
|
+
# * instance - uint32 (4 bytes)
|
134
|
+
# * domain - uint32 (4 bytes)
|
135
|
+
def pack_addr
|
136
|
+
[
|
137
|
+
self.family,
|
138
|
+
self.addrtype,
|
139
|
+
self.scope,
|
140
|
+
self.type,
|
141
|
+
self.instance,
|
142
|
+
self.domain
|
143
|
+
].pack("SCcL3")
|
144
|
+
end
|
145
|
+
|
146
|
+
# Pack an instance of a TIPCName.
|
147
|
+
#
|
148
|
+
# Produces an 8 byte string with the following format:
|
149
|
+
# * type - uint32 (4 bytes)
|
150
|
+
# * instance - uint32 (4 bytes)
|
151
|
+
def pack
|
152
|
+
[
|
153
|
+
self.type,
|
154
|
+
self.instance
|
155
|
+
].pack("L2")
|
156
|
+
end
|
157
|
+
|
158
|
+
# Create a new TIPCName instance from a 16 byte binary string containing a
|
159
|
+
# TIPC address.
|
160
|
+
#
|
161
|
+
# === Parameters
|
162
|
+
# * bytes - 16 byte string containing TIPC address
|
163
|
+
def self.unpack_addr(bytes)
|
164
|
+
data = bytes.unpack("SCcL3")
|
165
|
+
self.new(data[3], data[4], data[2], data[5])
|
166
|
+
end
|
167
|
+
|
168
|
+
# Create a new TIPCName instance from an 8 byte binary string containing
|
169
|
+
# a TIPC name.
|
170
|
+
#
|
171
|
+
# === Parameters
|
172
|
+
# * bytes - 8 byte string containing TIPC name
|
173
|
+
def self.unpack(bytes)
|
174
|
+
data = bytes.unpack("L2")
|
175
|
+
self.new(data[0], data[1])
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
# Represents a TIPC port name sequence address of the form
|
180
|
+
# <type, lower bound, upper bound>.
|
181
|
+
#
|
182
|
+
# From the {TIPC Programmer's Guide}[http://tipc.sourceforge.net/doc/Programmers_Guide.txt]:
|
183
|
+
#
|
184
|
+
# A port name sequence consists of a 32-bit type field and a pair of 32-bit
|
185
|
+
# instance fields, and represents the set of port names from {type,lower bound}
|
186
|
+
# through {type,upper bound}, inclusive. The lower bound of a name sequence
|
187
|
+
# cannot be larger than the upper bound.
|
188
|
+
class TIPCNameSeq
|
189
|
+
attr_reader :family, :addrtype
|
190
|
+
attr_accessor :type, :lower, :upper, :scope
|
191
|
+
|
192
|
+
# Create a new TIPCNameSeq instance.
|
193
|
+
#
|
194
|
+
# === Parameters
|
195
|
+
# * type - arbitrary 32 bit type value
|
196
|
+
# * lower - 32-bit lower bound of the name sequence
|
197
|
+
# * upper - 32-bit upper bound of the name sequence
|
198
|
+
# * scope - the scope (zone, cluster, or node) to use when packing
|
199
|
+
# this name as a TIPC address (optional)
|
200
|
+
def initialize(type, lower, upper, scope = TIPCSocket::Constants::TIPC_NODE_SCOPE)
|
201
|
+
@family = Socket::Constants::AF_TIPC
|
202
|
+
@addrtype = TIPCSocket::Constants::TIPC_ADDR_NAMESEQ
|
203
|
+
@type = type
|
204
|
+
@lower = lower
|
205
|
+
@upper = upper
|
206
|
+
@scope = scope
|
207
|
+
end
|
208
|
+
|
209
|
+
# Pack an instance of a TIPCNameSeq as a 16 byte TIPC network address suitable
|
210
|
+
# for passing to one of the standard Socket methods (connect, send, etc.).
|
211
|
+
#
|
212
|
+
# Produces a 16 byte binary string with the following format:
|
213
|
+
# * family - unsigned short (2 bytes)
|
214
|
+
# * addrtype - unsigned char (1 byte)
|
215
|
+
# * scope - signed char (1 byte)
|
216
|
+
# * type - uint32 (4 bytes)
|
217
|
+
# * lower - uint32 (4 bytes)
|
218
|
+
# * upper - uint32 (4 bytes)
|
219
|
+
def pack_addr
|
220
|
+
[
|
221
|
+
self.family,
|
222
|
+
self.addrtype,
|
223
|
+
self.scope,
|
224
|
+
self.type,
|
225
|
+
self.lower,
|
226
|
+
self.upper
|
227
|
+
].pack("SCcL3")
|
228
|
+
end
|
229
|
+
|
230
|
+
# Pack an instance of a TIPCNameSeq.
|
231
|
+
#
|
232
|
+
# Produces an 12 byte string with the following format:
|
233
|
+
# * type - uint32 (4 bytes)
|
234
|
+
# * lower - uint32 (4 bytes)
|
235
|
+
# * upper - uint32 (4 bytes)
|
236
|
+
def pack
|
237
|
+
[
|
238
|
+
self.type,
|
239
|
+
self.lower,
|
240
|
+
self.upper
|
241
|
+
].pack("L3")
|
242
|
+
end
|
243
|
+
|
244
|
+
# Create a new TIPCNameSeq instance from a 16 byte binary string containing a
|
245
|
+
# TIPC address.
|
246
|
+
#
|
247
|
+
# === Parameters
|
248
|
+
# * bytes - 16 byte string containing TIPC address
|
249
|
+
def self.unpack_addr(bytes)
|
250
|
+
data = bytes.unpack("SCcL3")
|
251
|
+
self.new(data[3], data[4], data[5], data[2])
|
252
|
+
end
|
253
|
+
|
254
|
+
# Create a new TIPCNameSeq instance from a 12 byte binary string containing
|
255
|
+
# a TIPC name sequence.
|
256
|
+
#
|
257
|
+
# === Parameters
|
258
|
+
# * bytes - 12 byte string containing TIPC name sequence
|
259
|
+
def self.unpack(bytes)
|
260
|
+
data = bytes.unpack("L3")
|
261
|
+
self.new(data[0], data[1], data[2])
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
# Represents a TIPC subscription.
|
266
|
+
#
|
267
|
+
# From the {TIPC Programmer's Guide}[http://tipc.sourceforge.net/doc/Programmers_Guide.txt]:
|
268
|
+
#
|
269
|
+
# TIPC provides a network topology service that applications can use to receive
|
270
|
+
# information about what port names exist within the application's network zone.
|
271
|
+
#
|
272
|
+
# An application accesses the topology service by opening a message-based
|
273
|
+
# connection to port name {1,1} and then sending "subscription" messages to the
|
274
|
+
# topology service that indicate the port names of interest to the application;
|
275
|
+
# in return, the topology service sends "event" messages to the application when
|
276
|
+
# these names are published or withdrawn by ports within the network.
|
277
|
+
class TIPCSubscr
|
278
|
+
attr_accessor :name_seq, :timeout, :filter, :usr_handle
|
279
|
+
|
280
|
+
# Create a new TIPCSubscr instance.
|
281
|
+
#
|
282
|
+
# === Parameters
|
283
|
+
# * name_seq - the port name sequence of interest, must be an instance of
|
284
|
+
# TIPCNameSeq
|
285
|
+
# * timeout - subscription timeout value in milliseconds, use the constant
|
286
|
+
# TIPC_WAIT_FOREVER to specify no timeout
|
287
|
+
# * filter - a bitmask containing one or more event filters, see below
|
288
|
+
# for a description of filter types
|
289
|
+
# * usr_handle - 8 byte string that is application defined, this value is
|
290
|
+
# returned to the application as part of all events associated
|
291
|
+
# with the subscription event
|
292
|
+
#
|
293
|
+
# === Filter Types
|
294
|
+
# * TIPC_SUB_PORTS - causes the topology service to generate a TIPC_PUBLISHED
|
295
|
+
# event for each port name or port name sequence it finds
|
296
|
+
# that overlaps the specified port name sequence; a
|
297
|
+
# TIPC_WITHDRAWN event is issued each time a previously
|
298
|
+
# reported name becomes unavailable
|
299
|
+
# * TIPC_SUB_SERVICE - causes the topology service to generate a single publish
|
300
|
+
# event for the first port it finds with an overlapping
|
301
|
+
# name and a single withdraw event when the last such port
|
302
|
+
# becomes unavailable
|
303
|
+
# * TIPC_SUB_CANCEL - cancels and existing topology service subscription, all
|
304
|
+
# other parameters should match the original subscription
|
305
|
+
# request
|
306
|
+
def initialize(name_seq, timeout, filter, usr_handle = '')
|
307
|
+
@name_seq = name_seq
|
308
|
+
@timeout = timeout
|
309
|
+
@filter = filter
|
310
|
+
@usr_handle = usr_handle
|
311
|
+
end
|
312
|
+
|
313
|
+
# Pack an instance of a TIPCSubscr.
|
314
|
+
#
|
315
|
+
# Produces a 28 byte string with the following format:
|
316
|
+
# * name_seq (12 bytes)
|
317
|
+
# * timeout - uint32 (4 bytes)
|
318
|
+
# * filter - uint32 (4 bytes)
|
319
|
+
# * usr_handle - char[8] (8 bytes)
|
320
|
+
def pack
|
321
|
+
[
|
322
|
+
self.name_seq.pack,
|
323
|
+
self.timeout,
|
324
|
+
self.filter,
|
325
|
+
self.usr_handle
|
326
|
+
].pack("a12L2a8")
|
327
|
+
end
|
328
|
+
|
329
|
+
# Create a new TIPCSubscr instance from a 28 byte binary string containing
|
330
|
+
# a TIPC name sequence.
|
331
|
+
#
|
332
|
+
# === Parameters
|
333
|
+
# * bytes - 28 byte string containing TIPC name sequence
|
334
|
+
def self.unpack(bytes)
|
335
|
+
data = bytes.unpack("a12L2a8")
|
336
|
+
self.new(TIPCNameSeq.unpack(data[0]), data[1], data[2], data[3])
|
337
|
+
end
|
338
|
+
end
|
339
|
+
|
340
|
+
# Represents a TIPC event message.
|
341
|
+
#
|
342
|
+
# TIPC event messages are returned by the TIPC topology server when subscribed
|
343
|
+
# to events occur.
|
344
|
+
class TIPCEvent
|
345
|
+
attr_accessor :event, :found_lower, :found_upper, :port, :subscr
|
346
|
+
|
347
|
+
# Create a new TIPCEvent instance.
|
348
|
+
#
|
349
|
+
# === Parameters
|
350
|
+
# * event - 32-bit event type, may be either TIPC_PUBLISHED, TIPC_WITHDRAWN,
|
351
|
+
# or TIPC_SUBSCR_TIMEOUT
|
352
|
+
# * found_lower - 32-bit lower bound of the port name sequence that overlaps
|
353
|
+
# the name sequence specified by the subscription
|
354
|
+
# * found_upper - 32-bit upper bound of the port name sequence that overlaps
|
355
|
+
# the name sequence specified by the subscription
|
356
|
+
# * port - an instance of TIPCPortId that represents the port ID of the
|
357
|
+
# associated port
|
358
|
+
# * subscr - an instance of TIPCSubscr that represents the subscription
|
359
|
+
# request associated with the event
|
360
|
+
def initialize(event, found_lower, found_upper, port, subscr)
|
361
|
+
@event = event
|
362
|
+
@found_lower = found_lower
|
363
|
+
@found_upper = found_upper
|
364
|
+
@port = port
|
365
|
+
@subscr = subscr
|
366
|
+
end
|
367
|
+
|
368
|
+
# Pack an instance of a TIPCEvent.
|
369
|
+
#
|
370
|
+
# Produces an 48 byte string with the following format:
|
371
|
+
# * event - uint32 = 4
|
372
|
+
# * found_lower - uint32 = 4
|
373
|
+
# * found_upper - uint32 = 4
|
374
|
+
# * port_id = 8
|
375
|
+
# * subscr = 28
|
376
|
+
def pack
|
377
|
+
[
|
378
|
+
self.event,
|
379
|
+
self.found_lower,
|
380
|
+
self.found_upper,
|
381
|
+
port.pack,
|
382
|
+
subscr.pack
|
383
|
+
].pack("L3a8a28")
|
384
|
+
end
|
385
|
+
|
386
|
+
# Create a new TIPCEvent instance from a 48 byte binary string containing a
|
387
|
+
# TIPC event.
|
388
|
+
#
|
389
|
+
# === Parameters
|
390
|
+
# * bytes - 48 byte string containing TIPC address
|
391
|
+
def self.unpack(bytes)
|
392
|
+
data = bytes.unpack("L3a8a28")
|
393
|
+
self.new(data[0], data[1], data[2], TIPCPortId.unpack(data[3]),
|
394
|
+
TIPCSubscr.unpack(data[4]))
|
395
|
+
end
|
396
|
+
end
|
397
|
+
|
398
|
+
# Provides access to a TIPC[http://tipc.sourceforge.net] socket. Subclass of
|
399
|
+
# the standard ruby Socket class.
|
400
|
+
class TIPCSocket < Socket
|
401
|
+
module Constants
|
402
|
+
# application accessible port name types
|
403
|
+
TIPC_CFG_SRV = 0
|
404
|
+
TIPC_TOP_SRV = 1
|
405
|
+
TIPC_RESERVED_TYPES = 64
|
406
|
+
|
407
|
+
# publication scopes when binding port names and port name sequences
|
408
|
+
TIPC_ZONE_SCOPE = 1
|
409
|
+
TIPC_CLUSTER_SCOPE = 2
|
410
|
+
TIPC_NODE_SCOPE = 3
|
411
|
+
|
412
|
+
# limiting values for messages
|
413
|
+
TIPC_MAX_USER_MSG_SIZE = 66000
|
414
|
+
|
415
|
+
# message importance levels
|
416
|
+
TIPC_LOW_IMPORTANCE = 0
|
417
|
+
TIPC_MEDIUM_IMPORTANCE = 1
|
418
|
+
TIPC_HIGH_IMPORTANCE = 2
|
419
|
+
TIPC_CRITICAL_IMPORTANCE = 3
|
420
|
+
|
421
|
+
# message rejection/connection shutdown reasons
|
422
|
+
TIPC_OK = 0
|
423
|
+
TIPC_ERR_NO_NAME = 1
|
424
|
+
TIPC_ERR_NO_PORT = 2
|
425
|
+
TIPC_ERR_NO_NODE = 3
|
426
|
+
TIPC_ERR_OVERLOAD = 4
|
427
|
+
TIPC_CONN_SHUTDOWN = 5
|
428
|
+
|
429
|
+
# topology subscription service definitions
|
430
|
+
TIPC_SUB_PORTS = 0x01
|
431
|
+
TIPC_SUB_SERVICE = 0x02
|
432
|
+
TIPC_SUB_CANCEL = 0x04
|
433
|
+
|
434
|
+
TIPC_WAIT_FOREVER = -1
|
435
|
+
|
436
|
+
# address types
|
437
|
+
TIPC_ADDR_NAMESEQ = 1
|
438
|
+
TIPC_ADDR_MCAST = 1
|
439
|
+
TIPC_ADDR_NAME = 2
|
440
|
+
TIPC_ADDR_ID = 3
|
441
|
+
|
442
|
+
# events
|
443
|
+
TIPC_PUBLISHED = 1
|
444
|
+
TIPC_WITHDRAWN = 2
|
445
|
+
TIPC_SUBSCR_TIMEOUT = 3
|
446
|
+
end
|
447
|
+
|
448
|
+
# Create a new TIPCSocket instance from a 16 byte binary string containing a
|
449
|
+
# TIPC address. Returns one of the following depending on the addrtype
|
450
|
+
# field: TIPCNameSeq, TIPCName, TIPCPortId.
|
451
|
+
#
|
452
|
+
# === Parameters
|
453
|
+
# * bytes - 16 byte string containing TIPC address
|
454
|
+
def self.unpack_sockaddr(bytes)
|
455
|
+
family, addrtype = bytes.unpack("SC")
|
456
|
+
|
457
|
+
case
|
458
|
+
when addrtype == Constants::TIPC_ADDR_NAMESEQ
|
459
|
+
TIPCNameSeq.unpack_addr(bytes)
|
460
|
+
when addrtype == Constants::TIPC_ADDR_NAME
|
461
|
+
TIPCName.unpack_addr(bytes)
|
462
|
+
when addrtype == Constants::TIPC_ADDR_ID
|
463
|
+
TIPCPortId.unpack_addr(bytes)
|
464
|
+
else
|
465
|
+
raise ArgumentError, "invalid address type (#{addrtype})"
|
466
|
+
end
|
467
|
+
end
|
468
|
+
|
469
|
+
# Create a new instance of a TIPCSocket.
|
470
|
+
#
|
471
|
+
# === Parameters
|
472
|
+
# - type: must be one of the following
|
473
|
+
# * :stream - for reliable connection-oriented byte streams
|
474
|
+
# * :seqpacket - for reliable connection-oriented messages
|
475
|
+
# * :rdm - for reliable connectionless messages
|
476
|
+
# * :dgram - for unreliable connectionless messages
|
477
|
+
# - protocol: passed directly to Socket.new (optional)
|
478
|
+
def initialize(type, protocol = 0)
|
479
|
+
case type.to_s.downcase
|
480
|
+
when 'stream'
|
481
|
+
type = Socket::Constants::SOCK_STREAM
|
482
|
+
when 'seqpacket'
|
483
|
+
type = Socket::Constants::SOCK_SEQPACKET
|
484
|
+
when 'rdm'
|
485
|
+
type = Socket::Constants::SOCK_RDM
|
486
|
+
when 'dgram'
|
487
|
+
type = Socket::Constants::SOCK_DGRAM
|
488
|
+
else
|
489
|
+
raise TypeError, "invalid TIPC socket type (#{type})"
|
490
|
+
end
|
491
|
+
|
492
|
+
super(Socket::Constants::AF_TIPC, type, protocol)
|
493
|
+
end
|
494
|
+
|
495
|
+
def send(msg, flags, tipc_addr = nil)
|
496
|
+
if tipc_addr
|
497
|
+
tipc_addr = tipc_addr.is_a?(String) ? tipc_addr : tipc_addr.pack_addr
|
498
|
+
super(msg, flags, tipc_addr)
|
499
|
+
else
|
500
|
+
super(msg, flags)
|
501
|
+
end
|
502
|
+
end
|
503
|
+
|
504
|
+
def bind(tipc_addr)
|
505
|
+
tipc_addr = tipc_addr.is_a?(String) ? tipc_addr : tipc_addr.pack_addr
|
506
|
+
super(tipc_addr)
|
507
|
+
end
|
508
|
+
|
509
|
+
def connect(tipc_addr)
|
510
|
+
tipc_addr = tipc_addr.is_a?(String) ? tipc_addr : tipc_addr.pack_addr
|
511
|
+
super(tipc_addr)
|
512
|
+
end
|
513
|
+
end
|
514
|
+
|
metadata
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.9.4
|
3
|
+
specification_version: 1
|
4
|
+
name: tipcsocket
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: "0.1"
|
7
|
+
date: 2008-01-14 00:00:00 -06:00
|
8
|
+
summary: Ruby bindings for the TIPC socket API.
|
9
|
+
require_paths:
|
10
|
+
- lib
|
11
|
+
email: corey.burrows@gmail.com
|
12
|
+
homepage:
|
13
|
+
rubyforge_project:
|
14
|
+
description:
|
15
|
+
autorequire: tipcsocket
|
16
|
+
default_executable:
|
17
|
+
bindir: bin
|
18
|
+
has_rdoc: true
|
19
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">"
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.0.0
|
24
|
+
version:
|
25
|
+
platform: ruby
|
26
|
+
signing_key:
|
27
|
+
cert_chain:
|
28
|
+
post_install_message:
|
29
|
+
authors:
|
30
|
+
- Corey Burrows
|
31
|
+
files:
|
32
|
+
- README
|
33
|
+
- CHANGELOG
|
34
|
+
- LICENSE
|
35
|
+
- Rakefile
|
36
|
+
- lib/tipcsocket.rb
|
37
|
+
- demo/hello_world/client.rb
|
38
|
+
- demo/hello_world/server.rb
|
39
|
+
- demo/stream_demo/client.rb
|
40
|
+
- demo/stream_demo/server.rb
|
41
|
+
test_files: []
|
42
|
+
|
43
|
+
rdoc_options: []
|
44
|
+
|
45
|
+
extra_rdoc_files: []
|
46
|
+
|
47
|
+
executables: []
|
48
|
+
|
49
|
+
extensions: []
|
50
|
+
|
51
|
+
requirements: []
|
52
|
+
|
53
|
+
dependencies: []
|
54
|
+
|