UPnP 1.1.0 → 1.2.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.
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