diff --git a/bin/coap b/bin/coap index 97f9081..30ce1d2 100755 --- a/bin/coap +++ b/bin/coap @@ -17,6 +17,8 @@ Usage: #{File.basename($0)} [options] STDOUT or a file path. --payload, -p Payload for POST and PUT as string. --payload-file, -f Read payload for POST and PUT from file. + --identity-file, -i Read DTLS identity from file. + --key-file, -k Read DTLS PSK form file. --type, -t Message type (con, non, ack, rst). --help, -h This usage message. @@ -27,6 +29,8 @@ end METHODS = CoAP::METHODS + [:observe] opts = GetoptLong.new( + ['--identity-file', '-i', GetoptLong::REQUIRED_ARGUMENT], + ['--key-file', '-k', GetoptLong::REQUIRED_ARGUMENT], ['--content-format', '-c', GetoptLong::REQUIRED_ARGUMENT], ['--debug', '-d', GetoptLong::NO_ARGUMENT], ['--output', '-o', GetoptLong::REQUIRED_ARGUMENT], @@ -36,13 +40,18 @@ opts = GetoptLong.new( ['--help', '-h', GetoptLong::NO_ARGUMENT] ) -$DEBUG = false -output = nil -payload = nil -options = {} +$DEBUG = false +output = nil +payload = nil +options = {} +initopts = {} opts.each do |opt, arg| case opt + when '--identity-file' + initopts[:dtls_id] = File.read(arg) + when '--key-file' + initopts[:dtls_key] = File.read(arg) when '--content-format' cf = CoAP::Registry.convert_content_format(arg) options[:content_format] = cf @@ -78,7 +87,7 @@ uri = URI.parse(uri) usage unless uri.scheme[/^coap/] -client = CoAP::Client.new +client = CoAP::Client.new(initopts) answer = case method when :get diff --git a/lib/core/coap/client.rb b/lib/core/coap/client.rb index 6328e00..8ec3598 100644 --- a/lib/core/coap/client.rb +++ b/lib/core/coap/client.rb @@ -11,7 +11,8 @@ class Client # (maximum retransmission count, default 4), # recv_timeout (timeout for ACK responses, default: 2), # host (destination host), post (destination port, - # default 5683). + # default 5683), dtls_id (DTLS client identity) + # and dtls_key (DTLS pre-shared key). def initialize(options = {}) @max_payload = options[:max_payload] || 256 @@ -25,8 +26,18 @@ def initialize(options = {}) # Enable DTLS socket. def use_dtls - require 'CoDTLS' - @options[:socket] = CoDTLS::SecureSocket + require 'tinydtls' + + id = @options[:dtls_id] + key = @options[:dtls_key] + + if id.nil? or key.nil? + raise ArgumentError.new("DTLS support requires specification of an identity/key pair") + end + + @options[:socket] = TinyDTLS::UDPSocket.new + @options[:socket].add_client(id, key) + self end @@ -267,7 +278,12 @@ def decode_uri(uri) @logger.debug 'URI decoded: ' + uri.inspect fail ArgumentError, 'Invalid URI' if uri.nil? - uri + scheme = uri.first + if scheme == "coaps" + self.use_dtls + end + + uri.drop(1) end def initialize_message(method, path, query = nil, payload = nil) diff --git a/lib/core/coap/coding.rb b/lib/core/coap/coding.rb index 9b3015f..fe37f94 100644 --- a/lib/core/coap/coding.rb +++ b/lib/core/coap/coding.rb @@ -89,10 +89,17 @@ def scheme_and_authority_encode(host, port) end def scheme_and_authority_decode(s) - if s =~ %r{\A(?:coap://)((?:\[|%5B)([^\]]*)(?:\]|%5D)|([^:/]*))(:(\d+))?(/.*)?\z}i - host = $2 || $3 # Should check syntax... - port = $5 || CoAP::PORT - [$6, host, port.to_i] + if s =~ %r{\A(?:(coap|coaps)://)((?:\[|%5B)([^\]]*)(?:\]|%5D)|([^:/]*))(:(\d+))?(/.*)?\z}i + scheme = $1 || "coap" + host = $3 || $4 # Should check syntax... + port = $6 + + if port.nil? + port = scheme == "coap" ? + CoAP::PORT : CoAP::PORT_DTLS + end + + [scheme, $7, host, port.to_i] end end diff --git a/test/test_message.rb b/test/test_message.rb index 848050f..bab5e60 100644 --- a/test/test_message.rb +++ b/test/test_message.rb @@ -71,10 +71,12 @@ def test_scheme_and_authority_encode end def test_scheme_and_authority_decode - assert_equal [nil, "foo.bar", 4711], CoRE::CoAP.scheme_and_authority_decode("coap://foo.bar:4711") - assert_equal [nil, "foo.bar", 5683], CoRE::CoAP.scheme_and_authority_decode("coap://foo.bar") - assert_equal [nil, "foo:bar", 4711], CoRE::CoAP.scheme_and_authority_decode("coap://[foo:bar]:4711") - assert_equal [nil, "foo:bar", 5683], CoRE::CoAP.scheme_and_authority_decode("coap://%5Bfoo:bar%5D") + assert_equal ["coap", nil, "foo.bar", 4711], CoRE::CoAP.scheme_and_authority_decode("coap://foo.bar:4711") + assert_equal ["coap", nil, "foo.bar", 5683], CoRE::CoAP.scheme_and_authority_decode("coap://foo.bar") + assert_equal ["coap", nil, "foo:bar", 4711], CoRE::CoAP.scheme_and_authority_decode("coap://[foo:bar]:4711") + assert_equal ["coap", nil, "foo:bar", 5683], CoRE::CoAP.scheme_and_authority_decode("coap://%5Bfoo:bar%5D") + + assert_equal ["coaps", nil, "foo.bar", 5684], CoRE::CoAP.scheme_and_authority_decode("coaps://foo.bar") end def test_coap_message