emonti-rbkb 0.6.1.1
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.
- data/README.rdoc +39 -0
- data/bin/b64 +57 -0
- data/bin/bgrep +91 -0
- data/bin/blit +97 -0
- data/bin/c +14 -0
- data/bin/crc32 +60 -0
- data/bin/d64 +41 -0
- data/bin/dedump +53 -0
- data/bin/hexify +85 -0
- data/bin/len +74 -0
- data/bin/rex +10 -0
- data/bin/rstrings +123 -0
- data/bin/slice +74 -0
- data/bin/telson +109 -0
- data/bin/unhexify +65 -0
- data/bin/urldec +56 -0
- data/bin/urlenc +55 -0
- data/bin/xor +60 -0
- data/lib/rbkb/command_line.rb +41 -0
- data/lib/rbkb/extends.rb +672 -0
- data/lib/rbkb/plug/blit.rb +220 -0
- data/lib/rbkb/plug/peer.rb +64 -0
- data/lib/rbkb/plug/plug.rb +195 -0
- data/lib/rbkb/plug.rb +6 -0
- data/lib/rbkb.rb +6 -0
- data/usage.txt +224 -0
- metadata +109 -0
@@ -0,0 +1,220 @@
|
|
1
|
+
|
2
|
+
module Plug
|
3
|
+
module Blit
|
4
|
+
include Base
|
5
|
+
|
6
|
+
DEFAULT_IPADDR = "127.0.0.1"
|
7
|
+
DEFAULT_PORT = 25195
|
8
|
+
DEFAULT_PROTOCOL = :TCP
|
9
|
+
|
10
|
+
OPCODES = {
|
11
|
+
0 => :squelch,
|
12
|
+
1 => :unsquelch,
|
13
|
+
2 => :delete,
|
14
|
+
5 => :sendmsg,
|
15
|
+
6 => :list_peers,
|
16
|
+
|
17
|
+
0xfe => :clear,
|
18
|
+
0xff => :kill,
|
19
|
+
}
|
20
|
+
|
21
|
+
attr_accessor :kind
|
22
|
+
|
23
|
+
def initialize(transport, slave)
|
24
|
+
super(transport)
|
25
|
+
|
26
|
+
@kind = :blitsrv
|
27
|
+
@slave = slave
|
28
|
+
@peers = slave.peers
|
29
|
+
initbuf
|
30
|
+
end
|
31
|
+
|
32
|
+
def post_init
|
33
|
+
# override so we don't get unneccessary "Start" message from Base
|
34
|
+
end
|
35
|
+
|
36
|
+
def unbind
|
37
|
+
# override so we don't get unneccessary "closed" message from Base
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
### Blit protocol stuff
|
42
|
+
SIG = "BLT"
|
43
|
+
|
44
|
+
# (re)initializes the blit buffer
|
45
|
+
def initbuf
|
46
|
+
@buf = StringIO.new
|
47
|
+
end
|
48
|
+
|
49
|
+
def receive_data dat
|
50
|
+
return unless (@buf.write(dat) > SIG.size) or (@buf.pos > (SIG.size + 1))
|
51
|
+
|
52
|
+
@buf.rewind
|
53
|
+
|
54
|
+
return unless @buf.read(SIG.size) == SIG and
|
55
|
+
op = OPCODES[ @buf.read(1)[0] ]
|
56
|
+
|
57
|
+
initbuf if self.send(op)
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
def self.blit_header(op)
|
62
|
+
return nil unless opno = OPCODES.invert[op]
|
63
|
+
SIG + opno.chr
|
64
|
+
end
|
65
|
+
|
66
|
+
def mute
|
67
|
+
unless ( peerno=@buf.read(2) and peerno.size == 2 and
|
68
|
+
peer=@peers[peerno.dat_to_num(:big)] )
|
69
|
+
|
70
|
+
UI.log "** BLIT-ERROR(Malformed or missing peer for mute)"
|
71
|
+
return true
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def self.make_mute(peerno)
|
76
|
+
self.blit_header(:squelch) +
|
77
|
+
peerno.to_bytes(2, :big)
|
78
|
+
end
|
79
|
+
|
80
|
+
def unmute
|
81
|
+
unless ( peerno=@buf.read(2) and peerno.size == 2 and
|
82
|
+
peer=@peers[peerno.dat_to_num(:big)] )
|
83
|
+
UI.log "** BLIT-ERROR(Malformed or missing peer for unmute)"
|
84
|
+
return true
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def self.make_squelch(peerno)
|
89
|
+
self.blit_header(:squelch) +
|
90
|
+
peerno.to_bytes(2, :big)
|
91
|
+
end
|
92
|
+
|
93
|
+
def sendmsg
|
94
|
+
unless peerno=@buf.read(2) and peerno.size == 2 and
|
95
|
+
bufsiz=@buf.read(4) and bufsiz.size == 4
|
96
|
+
UI.log "** BLIT-ERROR(Malformed sendmsg)"
|
97
|
+
return true
|
98
|
+
end
|
99
|
+
|
100
|
+
peerno = peerno.dat_to_num(:big)
|
101
|
+
bufsiz = bufsiz.dat_to_num(:big)
|
102
|
+
|
103
|
+
if (rdat=@buf.read(bufsiz)).size == bufsiz
|
104
|
+
if peer=@peers[peerno]
|
105
|
+
peer.say(rdat, self)
|
106
|
+
return true
|
107
|
+
else
|
108
|
+
UI.log "** BLIT-ERROR(Invalid peer index #{peerno})"
|
109
|
+
return true
|
110
|
+
end
|
111
|
+
else
|
112
|
+
return nil
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
# Blit packed message format is (SUBJECT TO CHANGE):
|
117
|
+
# "BLT"
|
118
|
+
# char opcode
|
119
|
+
# uint16be idx = index of slave peer to send to
|
120
|
+
# uint32le size = length of data
|
121
|
+
# str data
|
122
|
+
def self.make_sendmsg(idx, dat)
|
123
|
+
self.blit_header(:sendmsg) +
|
124
|
+
idx.to_bytes(2, :big) +
|
125
|
+
dat.size.to_bytes(4, :big) +
|
126
|
+
dat
|
127
|
+
end
|
128
|
+
|
129
|
+
def kill
|
130
|
+
UI.log("** BLIT-KILL - Received shutdown command")
|
131
|
+
EM.stop
|
132
|
+
end
|
133
|
+
|
134
|
+
def self.make_kill(idx=nil)
|
135
|
+
self.blit_header(:kill)
|
136
|
+
end
|
137
|
+
|
138
|
+
def clear
|
139
|
+
@peers.each { |p| p.close }
|
140
|
+
@peers.replace []
|
141
|
+
end
|
142
|
+
|
143
|
+
def self.make_clear
|
144
|
+
self.blit_header(:clear)
|
145
|
+
end
|
146
|
+
|
147
|
+
def delete(peerno)
|
148
|
+
@peers.delete(peerno)
|
149
|
+
end
|
150
|
+
|
151
|
+
def self.make_delete(idx=0)
|
152
|
+
self.blit_header(:delete) +
|
153
|
+
idx.to_bytes(2, :big)
|
154
|
+
end
|
155
|
+
|
156
|
+
def list_peers
|
157
|
+
UI.log("** BLIT-LISTPEERS - Received list peers command")
|
158
|
+
|
159
|
+
@peers.each_index {|i| UI.log "** #{i} - #{@peers[i].name}"}
|
160
|
+
UI.log("** BLIT-LISTPEERS-END - End of peer list")
|
161
|
+
end
|
162
|
+
|
163
|
+
def self.make_list_peers
|
164
|
+
self.blit_header(:list_peers)
|
165
|
+
end
|
166
|
+
|
167
|
+
#----------------------------------------------------------------------
|
168
|
+
# Convenience methods for blit clients
|
169
|
+
#----------------------------------------------------------------------
|
170
|
+
|
171
|
+
BLIT_HANDLERS = {
|
172
|
+
:TCP => lambda {|msg|
|
173
|
+
s=TCPSocket.new(@blit_addr, @blit_port)
|
174
|
+
wl=s.write(msg)
|
175
|
+
s.close
|
176
|
+
return wl
|
177
|
+
},
|
178
|
+
:UDP => lambda {|msg|
|
179
|
+
s=UDPSocket.new
|
180
|
+
wl=s.send( msg, 0, @blit_addr, @blit_port)
|
181
|
+
s.close
|
182
|
+
return wl
|
183
|
+
}
|
184
|
+
}
|
185
|
+
|
186
|
+
def self.blit_init(opts={})
|
187
|
+
@blit_addr = (opts[:addr] || DEFAULT_IPADDR)
|
188
|
+
@blit_port = (opts[:port] || DEFAULT_PORT)
|
189
|
+
proto = (opts[:protocol] || DEFAULT_PROTOCOL)
|
190
|
+
@blit_handler = BLIT_HANDLERS[ proto ]
|
191
|
+
raise "invalid blit transport protocol" unless @blit_handler
|
192
|
+
end
|
193
|
+
|
194
|
+
def self.initialized?
|
195
|
+
@blit_addr and @blit_port and @blit_handler
|
196
|
+
end
|
197
|
+
|
198
|
+
def self.blit_send(data, idx=0)
|
199
|
+
msg = make_sendmsg(idx, data)
|
200
|
+
blit_raw(msg)
|
201
|
+
end
|
202
|
+
|
203
|
+
def self.blit_raw(buf)
|
204
|
+
raise "use blit_init first!" unless self.initialized?
|
205
|
+
@blit_handler.call buf
|
206
|
+
end
|
207
|
+
|
208
|
+
end # of module Blit
|
209
|
+
|
210
|
+
|
211
|
+
end # of module Plug
|
212
|
+
|
213
|
+
class String
|
214
|
+
#----------------------------------------------------------------------
|
215
|
+
# A Blit sender convenience method for strings
|
216
|
+
def blit(idx=0)
|
217
|
+
raise "blit must be initialized with blit_init" unless Plug::Blit.initialized?
|
218
|
+
Plug::Blit.blit_send(self, idx)
|
219
|
+
end
|
220
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'socket'
|
2
|
+
|
3
|
+
module Plug
|
4
|
+
|
5
|
+
class Peer
|
6
|
+
attr_reader :addr, :transport, :name, :owner, :host, :port
|
7
|
+
attr_accessor :mute
|
8
|
+
|
9
|
+
def initialize(addr, owner)
|
10
|
+
@addr = addr
|
11
|
+
@owner = owner
|
12
|
+
@transport = @owner.transport
|
13
|
+
|
14
|
+
@port, @host = Socket.unpack_sockaddr_in(@addr)
|
15
|
+
@name = "PEER-#{@host}:#{@port}(#{@transport})"
|
16
|
+
end
|
17
|
+
|
18
|
+
def say(dat, sender)
|
19
|
+
UI.dump(sender.name, self.name, dat)
|
20
|
+
|
21
|
+
if @transport == :UDP
|
22
|
+
@owner.send_datagram(dat, @host, @port)
|
23
|
+
else
|
24
|
+
@owner.send_data(dat)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def close
|
29
|
+
@owner.unbind unless @transport == :UDP
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
class PeerList < Array
|
35
|
+
def initialize(owner, *args)
|
36
|
+
@owner = owner
|
37
|
+
@transport = @owner.transport
|
38
|
+
|
39
|
+
super(*args)
|
40
|
+
end
|
41
|
+
|
42
|
+
def find_peer(addr)
|
43
|
+
self.find {|p| p.addr == addr }
|
44
|
+
return nil
|
45
|
+
end
|
46
|
+
|
47
|
+
def add_peer(addr)
|
48
|
+
self << Peer.new(addr, @owner)
|
49
|
+
self.last
|
50
|
+
end
|
51
|
+
|
52
|
+
def add_peer_manually(host, port)
|
53
|
+
addr = Socket.pack_sockaddr_in(port, host)
|
54
|
+
return (find_peer(addr) || add_peer(addr))
|
55
|
+
end
|
56
|
+
|
57
|
+
def delete(addr)
|
58
|
+
if p=find_peer(addr)
|
59
|
+
p.close
|
60
|
+
super(p)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,195 @@
|
|
1
|
+
|
2
|
+
require "rbkb/plug/peer.rb"
|
3
|
+
require 'stringio'
|
4
|
+
require 'socket'
|
5
|
+
|
6
|
+
|
7
|
+
module Plug
|
8
|
+
module UI
|
9
|
+
LOGCFG = {:out => STDERR, :dump => :hex}
|
10
|
+
|
11
|
+
def self.prompt(*msg); STDERR.puts msg ; STDIN.gets ; end
|
12
|
+
|
13
|
+
def self.log(*msg); LOGCFG[:out].puts msg ; end
|
14
|
+
|
15
|
+
def self.verbose(*msg); LOGCFG[:out].puts msg if LOGCFG[:verbose] ; end
|
16
|
+
|
17
|
+
def self.debug(*msg); LOGCFG[:out].puts msg if LOGCFG[:debug] ; end
|
18
|
+
|
19
|
+
def self.dump(from, to, dat)
|
20
|
+
if dump=LOGCFG[:dump]
|
21
|
+
LOGCFG[:out].puts "%% #{from} SAYS TO #{to} LEN=#{dat.size}",
|
22
|
+
(dump == :hex)? dat.hexdump(:out => StringIO.new) : dat,
|
23
|
+
"%%"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
module Base
|
30
|
+
attr_accessor :peers, :transport, :kind
|
31
|
+
|
32
|
+
def initialize(transport)
|
33
|
+
# raise "Invalid transport #{transport.inspect}" unless (:UDP, :TCP).include?(transport)
|
34
|
+
@transport = transport
|
35
|
+
@peers = PeerList.new(self)
|
36
|
+
end
|
37
|
+
|
38
|
+
def name
|
39
|
+
sn = get_sockname
|
40
|
+
addr = sn ? Socket.unpack_sockaddr_in(sn).reverse.join(":") : "PENDING"
|
41
|
+
"#{kind.to_s.upcase}-#{addr}(#{@transport})"
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
# plug_peer creates a peering association for a given peer based on
|
46
|
+
# get_peername. The existing or newly created peer object is returned.
|
47
|
+
def plug_peer
|
48
|
+
paddr = get_peername
|
49
|
+
peer = (@peers.find_peer(paddr) || @peers.add_peer(paddr) )
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
# plug_receive is used by receive_data to divert incoming messages.
|
54
|
+
# The "peer" is added if it is not already present. This instance
|
55
|
+
# will check whether # a peer is "muted" and will return the peer if not.
|
56
|
+
# This method can be overriden by child classes to implement additional
|
57
|
+
# checks. It receives "dat" so that such checks can optionally make
|
58
|
+
# forwarding decisions based on message data contents as well.
|
59
|
+
#
|
60
|
+
# Returns:
|
61
|
+
# - nil : indicates that the message should be stifled
|
62
|
+
# - A peer object : indicates that the message should be processed
|
63
|
+
# further
|
64
|
+
def plug_receive(dat)
|
65
|
+
peer = plug_peer
|
66
|
+
return peer unless peer.mute
|
67
|
+
end
|
68
|
+
|
69
|
+
# This instance of the say method is an abstract stub and just
|
70
|
+
# "dumps" the message. It should be overridden and optionally called
|
71
|
+
# with super() if you actually want to do anything useful when
|
72
|
+
# incoming messages are received.
|
73
|
+
def say(dat, sender)
|
74
|
+
UI.dump(sender.name, self.name, dat)
|
75
|
+
end
|
76
|
+
|
77
|
+
def post_init
|
78
|
+
UI.verbose "** #{name} Started"
|
79
|
+
if @kind==:server and peer=plug_peer
|
80
|
+
UI.log "** #{name} CONNECTED TO #{peer.name}"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def receive_data(dat)
|
85
|
+
if peer=plug_receive(dat)
|
86
|
+
say(dat, peer)
|
87
|
+
end
|
88
|
+
return peer
|
89
|
+
end
|
90
|
+
|
91
|
+
def connection_completed
|
92
|
+
peer = plug_peer
|
93
|
+
UI.log "** #{name} CONNECTED TO #{peer.name}"
|
94
|
+
return peer
|
95
|
+
end
|
96
|
+
|
97
|
+
def unbind
|
98
|
+
UI.log "** Connection " + ((@peers.empty?)? "refused." : "closed.")
|
99
|
+
EM.stop
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
|
104
|
+
# An abstract module to implement custom servers for any protocol
|
105
|
+
# incoming messages are diverted to 'process(dat, sender)' which takes
|
106
|
+
# a block, the yields to which are messages to respond with
|
107
|
+
module UdpServer
|
108
|
+
include Base
|
109
|
+
|
110
|
+
def kind ; :server ; end
|
111
|
+
|
112
|
+
def say(dat, sender)
|
113
|
+
super(dat, sender)
|
114
|
+
|
115
|
+
if self.respond_to? :process
|
116
|
+
self.send(:process, dat, sender) { |rply| sender.say(rply, self) }
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
|
122
|
+
|
123
|
+
# Telson is just a receiver for blit
|
124
|
+
module Telson
|
125
|
+
include Base
|
126
|
+
def kind ; :telson ; end
|
127
|
+
end
|
128
|
+
|
129
|
+
|
130
|
+
# Uses an array of static messages as a datasource for opaque protocol
|
131
|
+
# messages. Useful as a generic blit-able loop
|
132
|
+
module ArrayFeeder
|
133
|
+
include Base
|
134
|
+
attr_accessor :pos, :feed, :step, :close_at_end, :go_first,
|
135
|
+
:squelch_exhausted
|
136
|
+
|
137
|
+
def initialize(transport, opts={})
|
138
|
+
super(transport)
|
139
|
+
|
140
|
+
@pos = 0
|
141
|
+
@feed = []
|
142
|
+
|
143
|
+
opts.each_pair do |k,v|
|
144
|
+
accessor = k.to_s + "="
|
145
|
+
if self.respond_to?(accessor)
|
146
|
+
self.send(accessor, v)
|
147
|
+
else
|
148
|
+
raise "Bad attribute: #{k}"
|
149
|
+
end
|
150
|
+
end
|
151
|
+
raise "feed must be enumerable" unless @feed.kind_of? Enumerable
|
152
|
+
end
|
153
|
+
|
154
|
+
def go
|
155
|
+
if @go_first
|
156
|
+
feed_data
|
157
|
+
@go_first = false
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
def connection_completed
|
162
|
+
peer=super()
|
163
|
+
go if @go_first
|
164
|
+
return peer
|
165
|
+
end
|
166
|
+
|
167
|
+
|
168
|
+
def say(dat, sender)
|
169
|
+
super(dat, sender)
|
170
|
+
if @step
|
171
|
+
EventMachine.defer(
|
172
|
+
proc { UI.prompt ">> Hit [enter] to continue at #{@pos}:" },
|
173
|
+
proc {|x| feed_data }
|
174
|
+
)
|
175
|
+
else
|
176
|
+
feed_data
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
def feed_data(dst=plug_peer)
|
181
|
+
unless dat=@feed[@pos]
|
182
|
+
UI.log "** FEED EXHAUSTED" unless @squelch_exhausted
|
183
|
+
return nil
|
184
|
+
end
|
185
|
+
|
186
|
+
dst.say dat.to_s, self
|
187
|
+
|
188
|
+
if (@pos += 1) >= @feed.size and @close_at_end
|
189
|
+
close_connection_after_writing
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
end # ArrayFeeder
|
194
|
+
end # Plug
|
195
|
+
|