ospfv2 0.0.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.
Files changed (56) hide show
  1. data/bin/ospfv2 +136 -0
  2. data/lib/ie/au_type.rb +79 -0
  3. data/lib/ie/external_route.rb +181 -0
  4. data/lib/ie/id.rb +97 -0
  5. data/lib/ie/interface_mtu.rb +64 -0
  6. data/lib/ie/ls_age.rb +89 -0
  7. data/lib/ie/ls_type.rb +148 -0
  8. data/lib/ie/metric.rb +63 -0
  9. data/lib/ie/mt_metric.rb +119 -0
  10. data/lib/ie/options.rb +356 -0
  11. data/lib/ie/ospf_version.rb +67 -0
  12. data/lib/ie/packet_type.rb +65 -0
  13. data/lib/ie/router_link.rb +167 -0
  14. data/lib/ie/router_link_factory.rb +53 -0
  15. data/lib/ie/router_link_type.rb +86 -0
  16. data/lib/ie/sequence_number.rb +144 -0
  17. data/lib/ie/tos_metric.rb +102 -0
  18. data/lib/infra/ospf_common.rb +291 -0
  19. data/lib/infra/ospf_constants.rb +73 -0
  20. data/lib/infra/ospf_io.rb +133 -0
  21. data/lib/infra/ospf_socket.rb +126 -0
  22. data/lib/infra/parse_options.rb +135 -0
  23. data/lib/infra/timer.rb +104 -0
  24. data/lib/infra/to_s.rb +38 -0
  25. data/lib/ls_db/advertised_routers.rb +78 -0
  26. data/lib/ls_db/common.rb +31 -0
  27. data/lib/ls_db/link_state_database.rb +376 -0
  28. data/lib/ls_db/link_state_database_build.rb +181 -0
  29. data/lib/ls_db/link_state_database_links.rb +178 -0
  30. data/lib/ls_db/links.rb +160 -0
  31. data/lib/lsa/external.rb +347 -0
  32. data/lib/lsa/lsa.rb +438 -0
  33. data/lib/lsa/lsa_factory.rb +59 -0
  34. data/lib/lsa/network.rb +166 -0
  35. data/lib/lsa/router.rb +336 -0
  36. data/lib/lsa/summary.rb +393 -0
  37. data/lib/neighbor/neighbor.rb +298 -0
  38. data/lib/neighbor/neighbor_event_handler.rb +61 -0
  39. data/lib/neighbor/recv_database_description.rb +153 -0
  40. data/lib/neighbor/recv_hello.rb +53 -0
  41. data/lib/neighbor/recv_ospf_packet.rb +68 -0
  42. data/lib/neighbor_sm/attempt_state.rb +44 -0
  43. data/lib/neighbor_sm/down_state.rb +46 -0
  44. data/lib/neighbor_sm/exchange_state.rb +32 -0
  45. data/lib/neighbor_sm/exstart_state.rb +69 -0
  46. data/lib/neighbor_sm/full_state.rb +36 -0
  47. data/lib/neighbor_sm/init_state.rb +43 -0
  48. data/lib/neighbor_sm/loading_state.rb +33 -0
  49. data/lib/neighbor_sm/neighbor_state.rb +87 -0
  50. data/lib/packet/database_description.rb +300 -0
  51. data/lib/packet/hello.rb +327 -0
  52. data/lib/packet/link_state_ack.rb +144 -0
  53. data/lib/packet/link_state_request.rb +153 -0
  54. data/lib/packet/link_state_update.rb +189 -0
  55. data/lib/packet/ospf_packet.rb +306 -0
  56. metadata +116 -0
@@ -0,0 +1,291 @@
1
+ #--
2
+ # Copyright 2010 Jean-Michel Esnault.
3
+ # All rights reserved.
4
+ # See LICENSE.txt for permissions.
5
+ #
6
+ #
7
+ # This file is part of OSPFv2.
8
+ #
9
+ # OSPFv2 is free software: you can redistribute it and/or modify
10
+ # it under the terms of the GNU General Public License as published by
11
+ # the Free Software Foundation, either version 3 of the License, or
12
+ # (at your option) any later version.
13
+ #
14
+ # OSPFv2 is distributed in the hope that it will be useful,
15
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
16
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
+ # GNU General Public License for more details.
18
+ #
19
+ # You should have received a copy of the GNU General Public License
20
+ # along with OSPFv2. If not, see <http://www.gnu.org/licenses/>.
21
+ #++
22
+
23
+
24
+ require 'ipaddr'
25
+
26
+ class Class
27
+ def attr_checked(attribute, &validation)
28
+ define_method "#{attribute}=" do |val|
29
+ raise "Invalid attribute #{val.inspect}" unless validation.call(val)
30
+ instance_variable_set("@#{attribute}", val)
31
+ end
32
+ define_method attribute do
33
+ instance_variable_get "@#{attribute}"
34
+ end
35
+ end
36
+ def attr_writer_delegate(*args)
37
+ # p self
38
+ args.each do |name|
39
+ define_method "#{name}=" do |value|
40
+ # p "in method..", self.class
41
+ instance_variable_set("@#{name}",
42
+ self.class.const_get(name.to_s.to_camel.to_sym).new(value))
43
+ end
44
+ end
45
+ end
46
+ end
47
+
48
+ class String
49
+
50
+ def to_underscore
51
+ gsub(/([A-Z]+|[A-Z][a-z])/) {|x| ' ' + x }.gsub(/[A-Z][a-z]+/) {|x| ' ' + x }.split.collect{|x| x.downcase}.join('_')
52
+ end
53
+
54
+ def to_camel
55
+ split('_').collect {|x| x.capitalize}.join
56
+ end
57
+
58
+ def hexlify
59
+ l,n,ls,s=0,0,[''],self.dup
60
+ while s.size>0
61
+ l = s.slice!(0,16)
62
+ ls << format("0x%4.4x: %s", n, l.unpack("n#{l.size/2}").collect { |x| format("%4.4x",x) }.join(' '))
63
+ n+=1
64
+ end
65
+ if l.size%2 >0
66
+ ns = if l.size>1 then 1 else 0 end
67
+ ls.last << format("%s%2.2x",' '*ns,l[-1])
68
+ end
69
+ ls
70
+ end
71
+
72
+ end
73
+
74
+ class Symbol
75
+ def to_klass
76
+ to_s.to_camel.to_sym
77
+ end
78
+ def to_setter
79
+ (to_s + "=").to_sym
80
+ end
81
+ end
82
+
83
+
84
+ class Object
85
+ def to_shex(*args)
86
+ self.respond_to?(:encode) ? self.encode(*args).unpack('H*')[0] : ""
87
+ end
88
+ def to_shex_len(len, *args)
89
+ s = to_shex(*args)
90
+ "#{s[0..len]}#{s.size>len ? '...' : ''}"
91
+ end
92
+ def to_shex4_len(len, *args)
93
+ s = to_shex4(*args)
94
+ "#{s[0..len]}#{s.size>len ? '...' : ''}"
95
+ end
96
+ def to_bitstring
97
+ if self.respond_to?(:encode)
98
+ self.enc.unpack('B*')[0]
99
+ else
100
+ ""
101
+ end
102
+ end
103
+ def method_missing(method, *args, &block)
104
+ # puts "COMMON method_missing: #{method}"
105
+
106
+ if method.to_s =~ /^to_s(\d+)/
107
+ to_s($1.to_i)
108
+ else
109
+ # p caller
110
+ super
111
+ end
112
+ end
113
+ def define_to_s
114
+ if defined?($style)
115
+ self.class.class_eval { eval("alias :to_s :to_s_#{$style}") }
116
+ elsif respond_to?(:to_s_default)
117
+ self.class.class_eval { alias :to_s :to_s_default }
118
+ else
119
+ puts "You're screwed!"
120
+ end
121
+ end
122
+ end
123
+
124
+ class Time
125
+ class << self
126
+ def to_ts
127
+ Time.now.strftime("%M:%S")
128
+ end
129
+ end
130
+ end
131
+
132
+ class IPAddr
133
+ alias encode hton
134
+
135
+ def self.create(arg)
136
+ if arg.is_a?(String) and arg.is_packed?
137
+ IPAddr.new_ntoh(arg)
138
+ elsif arg.is_a?(Integer)
139
+ IPAddr.new_ntoh([arg].pack('N'))
140
+ elsif arg.is_a?(Array) and arg[0].is_a?(Fixnum)
141
+ IPAddr.new_ntoh([arg].pack('C*'))
142
+ elsif arg.is_a?(self)
143
+ IPAddr.new
144
+ else
145
+ IPAddr.new(arg)
146
+ end
147
+ end
148
+
149
+ def mlen
150
+ @_jme_mlen_ ||= _mlen_
151
+ end
152
+
153
+ def +(i)
154
+ [IPAddr.create(to_i + i).to_s, mlen].join("/")
155
+ end
156
+ def ^(i)
157
+ @increment ||= _generate_network_inc_
158
+ [IPAddr.create(to_i + @increment.call(i)).to_s, mlen].join("/")
159
+ end
160
+
161
+ def netmask
162
+ if ipv4?
163
+ [@mask_addr].pack('N').unpack('C4').collect { |x| x.to_s}.join('.')
164
+ else
165
+ i = @mask_addr
166
+ arr=[]
167
+ while i>0
168
+ arr << (i & 0xffff) and i >>= 16
169
+ end
170
+ arr.reverse.collect { |x| x.to_s(16) }.join(':')
171
+ end
172
+ end
173
+
174
+ def to_s_net
175
+ [to_s,mlen].join('/')
176
+ end
177
+
178
+ def IPAddr.to_ary(prefix)
179
+ source_address,mlen = prefix.split('/')
180
+ ip = IPAddr.new(prefix)
181
+ network = ip.to_s
182
+ [ip, source_address, mlen.to_i, network, ip.netmask]
183
+ end
184
+
185
+ private
186
+
187
+ def _mlen_
188
+ m = @mask_addr
189
+ len = ipv6? ? 128 : 32
190
+ loop do
191
+ break if m & 1 > 0
192
+ m = m >> 1
193
+ len += -1
194
+ end
195
+ len
196
+ end
197
+
198
+ def _generate_network_inc_
199
+ max_len = ipv4? ? 32 : 128
200
+ Proc.new { |n| n*(2**(max_len - mlen)) }
201
+ end
202
+
203
+
204
+
205
+ end
206
+
207
+
208
+ module OSPFv2
209
+ module Common
210
+
211
+ def ivar_to_klassname(ivar)
212
+ ivar.to_s.to_camel.to_sym
213
+ end
214
+
215
+ def set(h)
216
+ # p "\n\n\n#{self.class}: IN SET(): ivars; #{ivars.inspect} - h: #{h.inspect}:"
217
+ for key in [ivars].flatten
218
+ # p key
219
+ if h.has_key?(key) and ! h[key].nil?
220
+ # puts " h has key #{key}"
221
+ begin
222
+ klassname = key.to_klass
223
+ if self.class.const_defined?(klassname)
224
+ # puts " class #{klassname} exists! => set @#{key.to_s} = #{klassname}.new(#{h[key]})"
225
+ instance_variable_set("@#{key.to_s}", self.class.const_get(klassname).new(h[key]))
226
+ elsif OSPFv2.const_defined?(klassname)
227
+ # puts " class OSPFv2::#{klassname} exists! => set @#{key.to_s} = #{klassname}.new(#{h[key]})"
228
+ instance_variable_set("@#{key.to_s}", OSPFv2.const_get(klassname).new(h[key]))
229
+ # elsif OSPFv2::LSDB::const_defined?(klassname)
230
+ # # puts " class OSPFv2::LSDB::#{klassname} exists! => set @#{key.to_s} = #{klassname}.new(#{h[key]})"
231
+ # instance_variable_set("@#{key.to_s}", OSPFv2::LSDB::const_get(klassname).new(h[key]))
232
+ elsif self.respond_to?(key.to_setter)
233
+ # puts " self respond to #{key.to_setter} => self.__send__ #{key.to_setter}, #{h[key]}"
234
+ self.send key.to_setter, h[key]
235
+ #elsif has an instance variable of that name ?
236
+ #or create ivar on the fly ?
237
+ else
238
+ # puts " just set ivar: @#{key} = #{h[key]}"
239
+ instance_variable_set("@#{key.to_s}", h[key])
240
+ end
241
+ rescue ArgumentError => e
242
+ raise
243
+ #
244
+ # #FIXME: attr_writer_delegate generate a NameError (in link_state_database)
245
+ # p "WE HAVE A NAME ERROR: #{e.inspect}"
246
+ # # instance_variable_set("@#{key.to_s}", h[key])
247
+ ensure
248
+ h.delete(key)
249
+ end
250
+ else
251
+ # puts "did not find #{key} in #{h.inspect}"
252
+ end
253
+ end
254
+ end
255
+
256
+ def to_hash
257
+ h = {}
258
+ for key in [ivars].flatten
259
+ ivar = instance_variable_get("@#{key.to_s}")
260
+ if ivar.respond_to?(:to_hash)
261
+ # p "#{key} respond to hash"
262
+ # p ivar
263
+ # p "#{key} --"
264
+ # p ivar
265
+ h.store(key,ivar.to_hash)
266
+ elsif ivar.is_a?(Array)
267
+ h.store(key, ivar.collect { |x| x.to_hash })
268
+ else
269
+ # p "#{key} don't respond to hast"
270
+ # p ivar
271
+ # p ivar.class
272
+ # p "#{key} --"
273
+ #FIXME: ivar.to_s ? ivar.value ? ivar.hash_value ?
274
+ h.store(key,ivar) unless ivar.nil?
275
+ end
276
+ end
277
+ h
278
+ end
279
+ end
280
+
281
+ module Common
282
+
283
+ def ivars
284
+ instance_variables.reject { |x| x =~ /^@_/ }.collect { |x| x[1..-1].to_sym }
285
+ end
286
+
287
+ end
288
+
289
+ end
290
+
291
+ load "../../../test/ospfv2/infra/#{ File.basename($0.gsub(/.rb/,'_test.rb'))}" if __FILE__ == $0
@@ -0,0 +1,73 @@
1
+ #--
2
+ # Copyright 2010 Jean-Michel Esnault.
3
+ # All rights reserved.
4
+ # See LICENSE.txt for permissions.
5
+ #
6
+ #
7
+ # This file is part of OSPFv2.
8
+ #
9
+ # OSPFv2 is free software: you can redistribute it and/or modify
10
+ # it under the terms of the GNU General Public License as published by
11
+ # the Free Software Foundation, either version 3 of the License, or
12
+ # (at your option) any later version.
13
+ #
14
+ # OSPFv2 is distributed in the hope that it will be useful,
15
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
16
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
+ # GNU General Public License for more details.
18
+ #
19
+ # You should have received a copy of the GNU General Public License
20
+ # along with OSPFv2. If not, see <http://www.gnu.org/licenses/>.
21
+ #++
22
+
23
+ module OSPFv2
24
+
25
+ module Constant
26
+ V2=2
27
+ V3=3
28
+ HELLO = 1
29
+ DATABASE_DESCRIPTION = 2
30
+ LINK_STATE_REQUEST = 3
31
+ LINK_STATE_UPDATE = 4
32
+ LINK_STATE_ACKNOWLEDGEMENT = 5
33
+ end
34
+
35
+ VERSION=2
36
+ LSRefreshTime = 30*60
37
+ MinLSInterval = 5
38
+ MinLSArrival = 1
39
+ MaxAge = 3600
40
+ CheckAge = 5*60
41
+ MaxAgeDiff = 15*60
42
+ LSInfinity = 0xffffffff
43
+ DefaultDestination = "0.0.0.0"
44
+ N = 0x80000000
45
+ InitialSequenceNumber = N + 1
46
+ MaxSequenceNumber = N - 1
47
+
48
+ ROUTER_LINK_P2P = 1
49
+ ROUTER_LINK_TRANSIT = 2
50
+ ROUTER_LINK_STUB = 3
51
+ ROUTER_LINK_VL = 4
52
+
53
+ ROUTER_LSA = 1
54
+ NETWORK_LSA = 2
55
+ SUMMARY_LSA = 3
56
+ ASBR_SUMMMARY_LSA = 4
57
+ EXTERNAL_LSA = 5
58
+ NSSA_LSA = 7
59
+
60
+ IPPROTO_OSPF = 89
61
+ AllSPFRouters = "224.0.0.5"
62
+ AllDRouters = "224.0.0.6"
63
+
64
+ EXTERNAL_BASE_ADDRESS='50.0.0.0/24'
65
+ SUMMARY_BASE_ADDRESS='30.0.0.0/24'
66
+ NETWORK_BASE_ADDRESS='20.0.0.0/24'
67
+ LINK_BASE_ADDRESS='13.0.0.0/30'
68
+
69
+ PACKET_HEADER_LEN = 24
70
+ LSA_HEADER_LEN = 20
71
+
72
+
73
+ end
@@ -0,0 +1,133 @@
1
+ #--
2
+ # Copyright 2010 Jean-Michel Esnault.
3
+ # All rights reserved.
4
+ # See LICENSE.txt for permissions.
5
+ #
6
+ #
7
+ # This file is part of OSPFv2.
8
+ #
9
+ # OSPFv2 is free software: you can redistribute it and/or modify
10
+ # it under the terms of the GNU General Public License as published by
11
+ # the Free Software Foundation, either version 3 of the License, or
12
+ # (at your option) any later version.
13
+ #
14
+ # OSPFv2 is distributed in the hope that it will be useful,
15
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
16
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
+ # GNU General Public License for more details.
18
+ #
19
+ # You should have received a copy of the GNU General Public License
20
+ # along with OSPFv2. If not, see <http://www.gnu.org/licenses/>.
21
+ #++
22
+
23
+
24
+ require 'observer'
25
+ require 'thread'
26
+
27
+ module OSPFv2
28
+
29
+ class Input
30
+ include Observable
31
+
32
+ attr_reader :sock
33
+
34
+ def initialize(sock, neighbor, ev_handler)
35
+ super()
36
+ @sock=sock
37
+ @neighbor=neighbor
38
+ add_observer(ev_handler)
39
+ @continue=true
40
+ end
41
+
42
+ attr_reader :thread
43
+
44
+ def our_address
45
+ @neighbor.address
46
+ end
47
+
48
+ def stop
49
+ @thread.exit
50
+ @thread.join
51
+ rescue
52
+ end
53
+
54
+ def start
55
+ @thread = Thread.new(@sock) do |s|
56
+ Thread.current['name'] = self.class.to_s
57
+ begin
58
+ while @continue
59
+ from, port, data = s.recv
60
+ hdr = header(data)
61
+ if hdr[:ip_proto] == 89 and data[20] == 2
62
+ if from != our_address
63
+ changed and notify_observers(:ev_recv, data, from, port) # * @sock.recv ....
64
+ end
65
+ end
66
+ end
67
+ rescue Exception => e
68
+ p e
69
+ end
70
+ end
71
+ end
72
+
73
+ private
74
+
75
+
76
+ def long2ip(ip)
77
+ return ip if ip.is_a?(String)
78
+ [ip].pack('N').unpack('CCCC').collect {|c| c}.join('.')
79
+ end
80
+ def header(_h)
81
+ h = _h.unpack('CCnnnCCnNN')
82
+ {
83
+ :ip_ver => h[0] >> 4,
84
+ :ip_hlen => (h[0] & 0xf) <<2,
85
+ :ip_tos => h[1],
86
+ :ip_length => h[2],
87
+ :ip_id => h[3],
88
+ :ip_offset => h[4],
89
+ :ip_ttl => h[5],
90
+ :ip_proto => h[6],
91
+ :ip_csum => h[7],
92
+ :ip_src => long2ip(h[8]),
93
+ :ip_dst => long2ip(h[9]),
94
+ }
95
+ end
96
+
97
+ end
98
+
99
+ class OutputQ < Queue
100
+ include Observable
101
+
102
+ def initialize(sock, *obs)
103
+ super()
104
+ @sock= sock
105
+ obs.each { |o| self.add_observer(o) }
106
+ @continue = true
107
+ end
108
+
109
+ attr_reader :thread
110
+
111
+ def stop
112
+ @thread.exit
113
+ @thread.join
114
+ rescue
115
+ end
116
+
117
+ def start
118
+ @thread = Thread.new(@sock) do |s|
119
+ Thread.current['name'] = self.class.to_s
120
+ begin
121
+ while @continue
122
+ el = deq
123
+ @sock.send *el
124
+ end
125
+ rescue => e
126
+ p e
127
+ end
128
+ end
129
+ end
130
+ end
131
+
132
+ end
133
+
@@ -0,0 +1,126 @@
1
+ #--
2
+ # Copyright 2010 Jean-Michel Esnault.
3
+ # All rights reserved.
4
+ # See LICENSE.txt for permissions.
5
+ #
6
+ #
7
+ # This file is part of OSPFv2.
8
+ #
9
+ # OSPFv2 is free software: you can redistribute it and/or modify
10
+ # it under the terms of the GNU General Public License as published by
11
+ # the Free Software Foundation, either version 3 of the License, or
12
+ # (at your option) any later version.
13
+ #
14
+ # OSPFv2 is distributed in the hope that it will be useful,
15
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
16
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
+ # GNU General Public License for more details.
18
+ #
19
+ # You should have received a copy of the GNU General Public License
20
+ # along with OSPFv2. If not, see <http://www.gnu.org/licenses/>.
21
+ #++
22
+
23
+
24
+ require 'socket'
25
+ require 'ipaddr'
26
+ require 'infra/ospf_constants'
27
+
28
+ module OSPFv2
29
+
30
+ class SendSocket
31
+
32
+ attr_reader :sock
33
+
34
+ def initialize(src, options={})
35
+ @src = src
36
+ @sock = Socket.open(Socket::PF_INET, Socket::SOCK_RAW, IPPROTO_OSPF)
37
+ add_membership OSPFv2::AllSPFRouters
38
+ add_membership OSPFv2::AllDRouters
39
+ rescue Errno::EPERM
40
+ $stderr.puts "#{e}: You are not root, cannot run: #{$0}!"
41
+ exit(1)
42
+ rescue Errno::EADDRNOTAVAIL
43
+ STDERR.puts "TODO: check if 127/8 and exit if not."
44
+ # for testing with 127/8
45
+ rescue Exception => e
46
+ STDERR.puts "#{e} Cannot Open Socket!"
47
+ exit(1)
48
+ end
49
+
50
+ #TODO: use all_spf_routers, all_dr_routers, ...
51
+ # 8.1 Sending protocol packets .............................. 58
52
+
53
+ def send(packet, location={:to=> :all_spf_routers})
54
+ case location
55
+ when :all_spf_routers ; send_all_spf_routers(packet)
56
+ when :all_dr_routers ; send_all_dr_routers(packet)
57
+ else
58
+ send_to(packet, location[:to])
59
+ end
60
+ end
61
+
62
+ def send_all_spf_routers
63
+ _send_ (packet.respond_to?(:encode) ? packet.encode : packet), 0, @sock_addr_all_spf_routers
64
+ end
65
+
66
+ def send_all_dr_routers
67
+ _send_ (packet.respond_to?(:encode) ? packet.encode : packet), 0, @send_all_dr_routers
68
+ end
69
+
70
+ def send_to(packet, dest)
71
+ _send_ (packet.respond_to?(:encode) ? packet.encode : packet), 0, Socket.pack_sockaddr_in(0, dest)
72
+ end
73
+
74
+ def send(packet, dest)
75
+ addr = Socket.pack_sockaddr_in(0, dest)
76
+ @sock.send((packet.respond_to?(:encode) ? packet.encode : packet),0,addr)
77
+ end
78
+
79
+ def close
80
+ @sock.close unless @sock.closed?
81
+ end
82
+
83
+ private
84
+
85
+ def add_membership(group)
86
+ @sock.setsockopt(Socket::IPPROTO_IP, Socket::IP_ADD_MEMBERSHIP, (IPAddr.new(group).hton + IPAddr.new(@src).hton))
87
+ puts "*** ADDED #{group} membership to Send Socket ***"
88
+ rescue Errno::EADDRNOTAVAIL
89
+ end
90
+
91
+ def _send_(bits, sock_addr)
92
+ @sock.send(bits,0,addr)
93
+ end
94
+ end
95
+
96
+ class RecvSocket
97
+ require 'socket'
98
+ require 'ipaddr'
99
+ attr_reader :sock
100
+ def initialize(src, options={})
101
+ @src=src
102
+ @sock = Socket.open(Socket::PF_INET, Socket::SOCK_RAW,89)
103
+ add_membership OSPFv2::AllSPFRouters
104
+ add_membership OSPFv2::AllDRouters
105
+ end
106
+ def recv(size=8192)
107
+ begin
108
+ data, sender = @sock.recvfrom(size)
109
+ port, host = Socket.unpack_sockaddr_in(sender)
110
+ [host,port,data]
111
+ rescue => e
112
+ STDERR.puts "RSocket recv() error: #{e}"
113
+ end
114
+ end
115
+ def close
116
+ begin ; @sock.close ; rescue ; end
117
+ @sock=nil
118
+ end
119
+ def add_membership(group)
120
+ @sock.setsockopt(Socket::IPPROTO_IP, Socket::IP_ADD_MEMBERSHIP, (IPAddr.new(group).hton + IPAddr.new(@src).hton))
121
+ puts "*** ADDED #{group} membership to Recv Socket ***"
122
+ rescue Errno::EADDRNOTAVAIL
123
+ end
124
+ end
125
+
126
+ end