UPnP 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
data.tar.gz.sig CHANGED
@@ -1,2 +1,5 @@
1
- j*��-��:�8&HAبe��(Ƹ$�q��" ����c�8N�/6���@ു�Y]J �%79rF���M�yŽŚ��G�����*���� �-�#��|շux\=��GR T�#�8��N'
2
- b��Meg��s�i����{,��$��ifa�A����;1�j1ANK���ΤW��إ��G�JE!&�(��\"�ˤ$��ԙ�R_�MLbGs��|;'��%rB>1��H�6Q)�c���ڛ����
1
+ ���%2v Py;�٦��pH���]z�Thj�*��6�O)��J�^X :�٠ݷ)(9��Ĝ������$B8C�Ľ�a��*L��o��~ٓ�6:�Qm�
2
+ �+q �́w;�
3
+ �1(NU����X�
4
+ ��qה
5
+ �w.�a��M��4\��sD���:��堼�z�")X����r]
@@ -1,3 +1,16 @@
1
+ === 1.2.0 / 2009-06-16
2
+
3
+ * 2 minor enhancements
4
+ * Workaround for missing socket constants on Windows. Reported by Yuri.
5
+ * upnp_discover now shows action argument and return value names.
6
+
7
+ * 4 bug fixes
8
+ * Method name must not include entire URI. Reported by Ian Macdonald.
9
+ * Step in allowedValueRange is optional. Reported by Ian Macdonald.
10
+ * upnp_listen works with all notification types. Reported by Ian Macdonald.
11
+ * upnp_discover now warns when a device failed to instantiate. Reported by
12
+ Ian Macdonald.
13
+
1
14
  === 1.1.0 / 2008-07-23
2
15
 
3
16
  * 2 major enhancements
@@ -9,6 +22,5 @@
9
22
  === 1.0.0 / 2008-06-25
10
23
 
11
24
  * 1 major enhancement
12
-
13
25
  * Birthday!
14
26
 
@@ -14,6 +14,7 @@ lib/UPnP/control/service.rb
14
14
  lib/UPnP/device.rb
15
15
  lib/UPnP/root_server.rb
16
16
  lib/UPnP/service.rb
17
+ lib/UPnP/test_utilities.rb
17
18
  test/test_UPnP_SSDP.rb
18
19
  test/test_UPnP_SSDP_notification.rb
19
20
  test/test_UPnP_SSDP_response.rb
data/Rakefile CHANGED
@@ -2,14 +2,15 @@
2
2
 
3
3
  require 'rubygems'
4
4
  require 'hoe'
5
- require './lib/upnp.rb'
6
5
 
7
- Hoe.new('UPnP', UPnP::VERSION) do |p|
8
- p.rubyforge_name = 'seattlerb'
9
- p.developer('Eric Hodel', 'drbrain@segment7.net')
6
+ Hoe.plugin :perforce
10
7
 
11
- p.extra_deps << 'soap4r'
12
- p.extra_deps << 'builder'
8
+ Hoe.spec 'UPnP' do
9
+ self.rubyforge_name = 'seattlerb'
10
+ developer 'Eric Hodel', 'drbrain@segment7.net'
11
+
12
+ extra_deps << 'soap4r'
13
+ extra_deps << 'builder'
13
14
  end
14
15
 
15
16
  # vim: syntax=Ruby
@@ -22,8 +22,13 @@ Prints information about UPnP internet gateway devices
22
22
  ssdp.timeout = timeout
23
23
 
24
24
  devices = ssdp.search(:root).map do |resource|
25
- UPnP::Control::Device.new resource.location
26
- end
25
+ begin
26
+ UPnP::Control::Device.new resource.location
27
+ rescue UPnP::Error => e
28
+ puts "Error creating device:\n\t#{e}"
29
+ nil
30
+ end
31
+ end.compact
27
32
 
28
33
  if devices.empty? then
29
34
  puts 'No UPnP devices found'
@@ -72,8 +77,12 @@ devices.each do |device|
72
77
  puts " Event subscription URL: #{service.event_sub_url}"
73
78
  puts
74
79
  puts " Actions:"
75
- service.driver.methods(false).sort.each do |method|
76
- puts " #{method}"
80
+ service.actions.sort.each do |method, arguments|
81
+ inn, out = arguments.partition { |dir,| dir == 'in' }
82
+ out = out.map { |dir, name,| name }
83
+ out = out.empty? ? '' : " => #{out.join ', '}"
84
+ inn = inn.map { |dir, name,| name }
85
+ puts " #{method}(#{inn.join ', '})#{out}"
77
86
  end
78
87
 
79
88
  puts
@@ -8,19 +8,31 @@ ssdp = UPnP::SSDP.new
8
8
  ssdp.discover do |notification|
9
9
  schemas = Regexp.union UPnP::DEVICE_SCHEMA_PREFIX, UPnP::SERVICE_SCHEMA_PREFIX
10
10
 
11
- type = notification.type.sub(/#{schemas}:/, '')
11
+ case notification
12
+ when UPnP::SSDP::Notification then
13
+ type = notification.type.sub(/#{schemas}:/, '')
14
+
15
+ if notification.alive? then
16
+ puts "#{type} is alive"
17
+ puts "Description: #{notification.location}"
18
+ else
19
+ puts "#{type} says byebye"
20
+ end
21
+
22
+ puts "USN: #{notification.name}"
23
+ when UPnP::SSDP::Response then
24
+ puts "Response from #{target}"
25
+ puts "Description: #{location}"
26
+ puts "USN: #{notification.name}"
27
+ when UPnP::SSDP::Search then
28
+ puts "Search for #{notification.target}"
29
+ end
12
30
 
13
- if notification.alive? then
14
- puts "#{type} is alive"
15
- puts "Description: #{notification.location}"
31
+ if notification.expiration then
16
32
  expiration = notification.expiration.strftime '%c'
17
33
  puts "Valid until #{expiration}"
18
- else
19
- puts "#{type} says byebye"
20
34
  end
21
35
 
22
- puts "USN: #{notification.name}"
23
-
24
36
  puts
25
37
  end
26
38
 
@@ -23,7 +23,7 @@ module UPnP
23
23
  ##
24
24
  # The version of UPnP you are using
25
25
 
26
- VERSION = '1.1.0'
26
+ VERSION = '1.2.0'
27
27
 
28
28
  ##
29
29
  # UPnP error base class
@@ -45,14 +45,14 @@ class UPnP::SSDP
45
45
  # Expiration time of this advertisement
46
46
 
47
47
  def expiration
48
- date + max_age
48
+ date + max_age if date and max_age
49
49
  end
50
50
 
51
51
  ##
52
52
  # True if this advertisement has expired
53
53
 
54
54
  def expired?
55
- Time.now > expiration
55
+ Time.now > expiration if expiration
56
56
  end
57
57
 
58
58
  end
@@ -303,6 +303,13 @@ class UPnP::SSDP
303
303
  @wait_time = wait_time
304
304
  end
305
305
 
306
+ ##
307
+ # Expiration time of this advertisement
308
+
309
+ def expiration
310
+ date + wait_time
311
+ end
312
+
306
313
  ##
307
314
  # A friendlier inspect
308
315
 
@@ -536,11 +543,11 @@ class UPnP::SSDP
536
543
  adv = parse response
537
544
 
538
545
  info = case adv
539
- when Notification then adv.type
540
- when Response then adv.target
541
- when Search then adv.target
542
- else 'unknown'
543
- end
546
+ when Notification then adv.type
547
+ when Response then adv.target
548
+ when Search then adv.target
549
+ else 'unknown'
550
+ end
544
551
 
545
552
  response =~ /\A(\S+)/
546
553
  log :debug, "SSDP recv #{$1} #{hostname}:#{port} #{info}"
@@ -756,3 +763,24 @@ ST: #{search_target}\r
756
763
 
757
764
  end
758
765
 
766
+ # :stopdoc:
767
+
768
+ ##
769
+ # Workaround for mising constants on Windows
770
+
771
+ module Socket::Constants
772
+ IP_ADD_MEMBERSHIP = 12 unless defined? IP_ADD_MEMBERSHIP
773
+ IP_MULTICAST_LOOP = 11 unless defined? IP_MULTICAST_LOOP
774
+ IP_MULTICAST_TTL = 10 unless defined? IP_MULTICAST_TTL
775
+ IP_TTL = 4 unless defined? IP_TTL
776
+ end
777
+
778
+ class Socket
779
+ IP_ADD_MEMBERSHIP = 12 unless defined? IP_ADD_MEMBERSHIP
780
+ IP_MULTICAST_LOOP = 11 unless defined? IP_MULTICAST_LOOP
781
+ IP_MULTICAST_TTL = 10 unless defined? IP_MULTICAST_TTL
782
+ IP_TTL = 4 unless defined? IP_TTL
783
+ end
784
+
785
+ # :startdoc:
786
+
@@ -175,6 +175,16 @@ class UPnP::Control::Service
175
175
 
176
176
  end
177
177
 
178
+ ##
179
+ # Hash mapping UPnP Actions to arguments
180
+ #
181
+ # {
182
+ # 'GetTotalPacketsSent' =>
183
+ # [['out', 'NewTotalPacketsSent', 'TotalPacketsSent']]
184
+ # }
185
+
186
+ attr_reader :actions
187
+
178
188
  ##
179
189
  # Control URL
180
190
 
@@ -259,7 +269,7 @@ class UPnP::Control::Service
259
269
 
260
270
  @actions.each do |name, arguments|
261
271
  soapaction = "#{@type}##{name}"
262
- qname = XSD::QName.new @type, soapaction
272
+ qname = XSD::QName.new @type, name
263
273
 
264
274
  # TODO map ranges, enumerations
265
275
  arguments = arguments.map do |direction, arg_name, variable|
@@ -278,7 +288,6 @@ class UPnP::Control::Service
278
288
 
279
289
  @driver.mapping_registry = mapping_registry
280
290
 
281
- @actions = nil
282
291
  @variables = nil
283
292
  end
284
293
 
@@ -385,7 +394,8 @@ class UPnP::Control::Service
385
394
  maximum = range.elements['maximum']
386
395
  step = range.elements['step']
387
396
 
388
- range = [minimum, maximum, step]
397
+ range = [minimum, maximum]
398
+ range << step if step
389
399
 
390
400
  range.map do |value|
391
401
  value = value.text
@@ -405,6 +415,8 @@ class UPnP::Control::Service
405
415
 
406
416
  service_state_table = description.elements['scpd/serviceStateTable']
407
417
  parse_service_state_table service_state_table
418
+ rescue OpenURI::HTTPError
419
+ raise Error, "Unable to open SCPD at #{@scpd_url.inspect} from device #{@url.inspect}"
408
420
  end
409
421
 
410
422
  ##
@@ -190,8 +190,12 @@ class UPnP::Device
190
190
  @option_parser = nil
191
191
  @options = nil
192
192
 
193
- def self.add_service_id(service, id)
194
- SERVICE_IDS[self][service] = id
193
+ ##
194
+ # Sets the serivceId for +service+ using +domain+ and +id+. Used in
195
+ # UPnP::Service#description via #description.
196
+
197
+ def self.add_service_id(service, id, domain = 'upnp.org')
198
+ SERVICE_IDS[self][service] = "urn:#{domain.tr '.', '-'}:serviceId:#{id}"
195
199
  end
196
200
 
197
201
  ##
@@ -374,6 +378,8 @@ class UPnP::Device
374
378
  @sub_services ||= []
375
379
  @parent ||= parent_device
376
380
 
381
+ @cache_dir = nil
382
+
377
383
  yield self if block_given?
378
384
 
379
385
  @name ||= "uuid:#{UPnP::UUID.generate}"
@@ -438,6 +444,20 @@ class UPnP::Device
438
444
  end
439
445
  end
440
446
 
447
+ ##
448
+ # A directory for storing device-specific persistent data
449
+
450
+ def cache_dir
451
+ return @cache_dir if @cache_dir
452
+
453
+ @cache_dir = File.join '~', '.UPnP', '_cache', @name
454
+ @cache_dir = File.expand_path @cache_dir
455
+
456
+ FileUtils.mkdir_p @cache_dir
457
+
458
+ @cache_dir
459
+ end
460
+
441
461
  ##
442
462
  # Returns an XML document describing the root device
443
463
 
@@ -156,6 +156,8 @@ class UPnP::Service < SOAP::RPC::StandaloneServer
156
156
  @device = device
157
157
  @type = type
158
158
 
159
+ @cache_dir = nil
160
+
159
161
  # HACK PS3 disobeys spec
160
162
  SOAP::NS::KNOWN_TAG[type_urn] = 'u'
161
163
  SOAP::NS::KNOWN_TAG[SOAP::EnvelopeNamespace] = 's'
@@ -194,6 +196,20 @@ class UPnP::Service < SOAP::RPC::StandaloneServer
194
196
  end
195
197
  end
196
198
 
199
+ ##
200
+ # A directory for storing service-specific persistent data
201
+
202
+ def cache_dir
203
+ return @cache_dir if @cache_dir
204
+
205
+ @cache_dir = File.join '~', '.UPnP', '_cache', "#{@device.name}-#{@type}"
206
+ @cache_dir = File.expand_path @cache_dir
207
+
208
+ FileUtils.mkdir_p @cache_dir
209
+
210
+ @cache_dir
211
+ end
212
+
197
213
  ##
198
214
  # The control URL for this service
199
215
 
@@ -216,7 +232,7 @@ class UPnP::Service < SOAP::RPC::StandaloneServer
216
232
  def description(xml)
217
233
  xml.service do
218
234
  xml.serviceType type_urn
219
- xml.serviceId "urn:upnp-org:serviceId:#{root_device.service_id self}"
235
+ xml.serviceId root_device.service_id(self)
220
236
  xml.SCPDURL scpd_url
221
237
  xml.controlURL control_url
222
238
  xml.eventSubURL event_sub_url
@@ -0,0 +1,13 @@
1
+ require 'UPnP/device'
2
+ require 'UPnP/service'
3
+
4
+ class UPnP::Service::TestService < UPnP::Service
5
+ VERSION = '1.0'
6
+ end
7
+
8
+ class UPnP::Device::TestDevice < UPnP::Device
9
+ VERSION = '1.0'
10
+
11
+ add_service_id UPnP::Service::TestService, 'TestService', 'example.com'
12
+ end
13
+
@@ -2,6 +2,7 @@ require 'test/unit'
2
2
  require 'test/utilities'
3
3
  require 'UPnP/SSDP'
4
4
  require 'UPnP/device'
5
+ require 'UPnP/test_utilities'
5
6
 
6
7
  class TestUPnPSSDP < UPnP::TestCase
7
8
 
@@ -293,7 +294,7 @@ ST: bunnies\r
293
294
  end
294
295
 
295
296
  def util_device_version
296
- "UPnP::Device::TestDevice/#{UPnP::VERSION}"
297
+ "UPnP::Device::TestDevice/#{UPnP::Device::TestDevice::VERSION}"
297
298
  end
298
299
 
299
300
  end
@@ -1,6 +1,7 @@
1
1
  require 'test/unit'
2
2
  require 'test/utilities'
3
3
  require 'UPnP/device'
4
+ require 'UPnP/test_utilities'
4
5
 
5
6
  class TestUPnPDevice < UPnP::TestCase
6
7
 
@@ -18,6 +19,11 @@ class TestUPnPDevice < UPnP::TestCase
18
19
  @service = @device.add_service 'TestService'
19
20
  end
20
21
 
22
+ def test_self_add_serivce_id
23
+ assert_equal 'urn:example-com:serviceId:TestService',
24
+ @device.service_id(@service)
25
+ end
26
+
21
27
  def test_self_create
22
28
  device1 = UPnP::Device.create 'TestDevice', 'test device'
23
29
 
@@ -98,6 +104,13 @@ class TestUPnPDevice < UPnP::TestCase
98
104
  assert @device.sub_services.include?(@service)
99
105
  end
100
106
 
107
+ def test_cache_dir
108
+ assert_match %r%.UPnP/_cache/uuid:.{8}-.{4}-.{4}-.{4}-.{12}$%,
109
+ @device.cache_dir
110
+
111
+ assert File.exist?(@device.cache_dir)
112
+ end
113
+
101
114
  def test_description
102
115
  desc = @device.description
103
116
 
@@ -120,7 +133,7 @@ class TestUPnPDevice < UPnP::TestCase
120
133
  <serviceList>
121
134
  <service>
122
135
  <serviceType>urn:schemas-upnp-org:service:TestService:1</serviceType>
123
- <serviceId>urn:upnp-org:serviceId:TestService</serviceId>
136
+ <serviceId>urn:example-com:serviceId:TestService</serviceId>
124
137
  <SCPDURL>/TestDevice/TestService</SCPDURL>
125
138
  <controlURL>/TestDevice/TestService/control</controlURL>
126
139
  <eventSubURL>/TestDevice/TestService/event_sub</eventSubURL>
@@ -235,11 +248,15 @@ class TestUPnPDevice < UPnP::TestCase
235
248
  end
236
249
 
237
250
  def test_service_id
238
- assert_equal 'TestService', @device.service_id(@service)
251
+ assert_equal 'urn:example-com:serviceId:TestService',
252
+ @device.service_id(@service)
239
253
  end
240
254
 
241
255
  def test_service_ids
242
- expected = { UPnP::Service::TestService => 'TestService' }
256
+ expected = {
257
+ UPnP::Service::TestService => 'urn:example-com:serviceId:TestService'
258
+ }
259
+
243
260
  assert_equal expected, @device.service_ids
244
261
  end
245
262
 
@@ -1,6 +1,7 @@
1
1
  require 'test/unit'
2
2
  require 'test/utilities'
3
3
  require 'UPnP/service'
4
+ require 'UPnP/test_utilities'
4
5
 
5
6
  class TestUPnPService < UPnP::TestCase
6
7
 
@@ -47,6 +48,13 @@ class TestUPnPService < UPnP::TestCase
47
48
  assert_equal [qname], operations.keys
48
49
  end
49
50
 
51
+ def test_cache_dir
52
+ assert_match %r%.UPnP/_cache/uuid:.{8}-.{4}-.{4}-.{4}-.{12}-TestService$%,
53
+ @service.cache_dir
54
+
55
+ assert File.exist?(@service.cache_dir)
56
+ end
57
+
50
58
  def test_control_url
51
59
  assert_equal '/TestDevice/TestService/control', @service.control_url
52
60
  end
@@ -64,7 +72,7 @@ class TestUPnPService < UPnP::TestCase
64
72
  expected = <<-XML
65
73
  <service>
66
74
  <serviceType>urn:schemas-upnp-org:service:TestService:1</serviceType>
67
- <serviceId>urn:upnp-org:serviceId:TestService</serviceId>
75
+ <serviceId>urn:example-com:serviceId:TestService</serviceId>
68
76
  <SCPDURL>/TestDevice/TestService</SCPDURL>
69
77
  <controlURL>/TestDevice/TestService/control</controlURL>
70
78
  <eventSubURL>/TestDevice/TestService/event_sub</eventSubURL>
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: UPnP
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Eric Hodel
@@ -30,7 +30,7 @@ cert_chain:
30
30
  x52qPcexcYZR7w==
31
31
  -----END CERTIFICATE-----
32
32
 
33
- date: 2008-07-23 00:00:00 -07:00
33
+ date: 2009-06-16 00:00:00 -07:00
34
34
  default_executable:
35
35
  dependencies:
36
36
  - !ruby/object:Gem::Dependency
@@ -61,7 +61,7 @@ dependencies:
61
61
  requirements:
62
62
  - - ">="
63
63
  - !ruby/object:Gem::Version
64
- version: 1.7.0
64
+ version: 2.1.0
65
65
  version:
66
66
  description: An implementation of the UPnP protocol
67
67
  email:
@@ -92,6 +92,7 @@ files:
92
92
  - lib/UPnP/device.rb
93
93
  - lib/UPnP/root_server.rb
94
94
  - lib/UPnP/service.rb
95
+ - lib/UPnP/test_utilities.rb
95
96
  - test/test_UPnP_SSDP.rb
96
97
  - test/test_UPnP_SSDP_notification.rb
97
98
  - test/test_UPnP_SSDP_response.rb
@@ -104,6 +105,8 @@ files:
104
105
  - test/utilities.rb
105
106
  has_rdoc: true
106
107
  homepage: http://seattlerb.org/UPnP
108
+ licenses: []
109
+
107
110
  post_install_message:
108
111
  rdoc_options:
109
112
  - --main
@@ -125,9 +128,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
125
128
  requirements: []
126
129
 
127
130
  rubyforge_project: seattlerb
128
- rubygems_version: 1.2.0
131
+ rubygems_version: 1.3.4.2217
129
132
  signing_key:
130
- specification_version: 2
133
+ specification_version: 3
131
134
  summary: An implementation of the UPnP protocol
132
135
  test_files:
133
136
  - test/test_UPnP_control_device.rb
metadata.gz.sig CHANGED
Binary file