Code Monkey home page Code Monkey logo

node-coap's Introduction

node-coap

Build Status Coverage Status gitter

node-coap is a client and server library for CoAP modeled after the http module.

NPM

NPM

Introduction

What is CoAP?

Constrained Application Protocol (CoAP) is a software protocol intended to be used in very simple electronics devices that allows them to communicate interactively over the Internet. - Wikipedia

This library follows:

It does not parse the protocol but it use CoAP-packet instead.

If you need a command line interface for CoAP, check out coap-cli.

node-coap is an OPEN Open Source Project, see the Contributing section to find out what this means.

The library is tested with LTS versions (currently 12, 14, 16 and 18).

Installation

$ npm install coap --save

Basic Example

The following example opens a UDP server and sends a CoAP message to it:

const coap = require('coap')
const server = coap.createServer()

server.on('request', (req, res) => {
  res.end('Hello ' + req.url.split('/')[1] + '\n')
})

// the default CoAP port is 5683
server.listen(() => {
  const req = coap.request('coap://localhost/Matteo')

  req.on('response', (res) => {
    res.pipe(process.stdout)
    res.on('end', () => {
      process.exit(0)
    })
  })

  req.end()
})

or on IPv6:

const coap = require('coap')
const server = coap.createServer({ type: 'udp6' })

server.on('request', (req, res) => {
  res.end('Hello ' + req.url.split('/')[1] + '\n')
})

// the default CoAP port is 5683
server.listen(() => {
  const req = coap.request('coap://[::1]/Matteo')

  req.on('response', (res) => {
    res.pipe(process.stdout)
    res.on('end', () => {
      process.exit(0)
    })
  })

  req.end()
})

Proxy features

The library now comes with the ability to behave as a COAP proxy for other COAP endpoints. In order to activate the proxy features, create the server with the proxy option activated.

A proxy-enabled service behaves as usual for all requests, except for those coming with the Proxy-Uri option. This requests will be redirected to the URL specified in the option, and the response from this option will, in turn, be redirected to the caller. In this case, the proxy server handler is not called at all (redirection is automatic).

You can find an example of how this mechanism works in examples/proxy.js. This example features one target server that writes all the information it receives along with the origin port and a proxy server. Once the servers are up:

  • Ten requests are sent directly to the server (without reusing ports)
  • Ten requests are sent through the proxy (without reusing ports)

The example shows that the target server sees the last ten requests as coming from the same port (the proxy), while the first ten come from different ports.

API


request(requestParams)

Execute a CoAP request. requestParams can be a string or an object. If it is a string, it is parsed using new URL(requestParams). If it is an object:

  • host: A domain name or IP address of the server to issue the request to. Defaults to 'localhost'.
  • hostname: To support URL hostname is preferred over host
  • port: Port of remote server. Defaults to 5683.
  • method: A string specifying the CoAP request method. Defaults to 'GET'.
  • confirmable: send a CoAP confirmable message (CON), defaults to true.
  • observe: send a CoAP observe message, allowing the streaming of updates from the server.
  • pathname: Request path. Defaults to '/'. Should not include query string
  • query: Query string. Defaults to ''. Should not include the path, e.g. 'a=b&c=d'
  • options: object that includes the CoAP options, for each key-value pair the setOption() will be called.
  • headers: alias for options, but it works only if options is missing.
  • agent: Controls Agent behavior. Possible values:
    • undefined (default): use globalAgent, a single socket for all concurrent requests.
    • Agent object: explicitly use the passed in Agent.
    • false: opts out of socket reuse with an Agent, each request uses a new UDP socket.
  • proxyUri: adds the Proxy-Uri option to the request, so if the request is sent to a proxy (or a server with proxy features) the request will be forwarded to the selected URI. The expected value is the URI of the target. E.g.: 'coap://192.168.5.13:6793'
  • multicast: If set to true, it forces request to be multicast. Several response events will be emitted for each received response. It's user's responsibility to set proper multicast host parameter in request configuration. Default false.
  • multicastTimeout: time to wait for multicast reponses in milliseconds. It is only applicable in case if multicast is true. Default 20000 ms.
  • retrySend: overwrite the default maxRetransmit, useful when you want to use a custom retry count for a request

coap.request() returns an instance of OutgoingMessage. If you need to add a payload, just pipe into it. Otherwise, you must call end to submit the request.

If hostname is a IPv6 address then the payload is sent through a IPv6 UDP socket, dubbed in node.js as 'udp6'.

Event: 'response'

function (response) { }

Emitted when a response is received. response is an instance of IncomingMessage.

If the observe flag is specified, the 'response' event will return an instance of ObserveReadStream. Which represent the updates coming from the server, according to the observe spec.


createServer([options], [requestListener])

Returns a new CoAP Server object.

The requestListener is a function which is automatically added to the 'request' event.

The constructor can be given an optional options object, containing one of the following options:

  • type: indicates if the server should create IPv4 connections (udp4) or IPv6 connections (udp6). Defaults to udp4.
  • proxy: indicates that the server should behave like a proxy for incoming requests containing the Proxy-Uri header. An example of how the proxy feature works, refer to the example in the /examples folder. Defaults to false.
  • multicastAddress: Optional. Use this in order to force server to listen on multicast address
  • multicastInterface: Optional. Use this in order to force server to listen on multicast interface. This is only applicable if multicastAddress is set. If absent, server will try to listen multicastAddress on all available interfaces
  • piggybackReplyMs: set the number of milliseconds to wait for a piggyback response. Default 50.
  • sendAcksForNonConfirmablePackets: Optional. Use this to suppress sending ACK messages for non-confirmable packages
  • clientIdentifier: Optional. If specified, it should be a callback function with a signature like clientIdentifier(request), where request is an IncomingMessage. The function should return a string that the caches can assume will uniquely identify the client.
  • reuseAddr: Optional. Use this to specify whether it should be possible to have multiple server instances listening to the same port. Default true.

Event: 'request'

function (request, response) { }

Emitted each time there is a request. request is an instance of IncomingMessage and response is an instance of OutgoingMessage.

If the observe flag is specified, the response variable will return an instance of ObserveWriteStream. Each write(data) to the stream will cause a new observe message sent to the client.

server.listen(port, [address], [callback])

Begin accepting connections on the specified port and hostname. If the hostname is omitted, the server will accept connections directed to any IPv4 or IPv6 address by passing null as the address to the underlining socket.

To listen to a unix socket, supply a filename instead of port and hostname.

A custom socket object can be passed as a port parameter. This custom socket must be an instance of EventEmitter which emits message, error and close events and implements send(msg, offset, length, port, address, callback) function, just like dgram.Socket. In such case, the custom socket must be pre-configured manually, i.e. CoAP server will not bind, add multicast groups or do any other configuration.

This function is asynchronous.

server.close([callback])

Closes the server.

This function is synchronous, but it provides an asynchronous callback for convenience.


OutgoingMessage

An OutgoingMessage object is returned by coap.request or emitted by the coap.createServer 'response' event. It may be used to access response status, headers and data.

It implements the Writable Stream interface, as well as the following additional properties, methods and events.

message.code

The CoAP code of the message. It is HTTP-compatible, as it can be passed 404.

message.statusCode

(same as message.code)

message.setOption(name, value)

Sets a single option value. All the options are in binary format, except for 'Content-Format', 'Accept', 'Max-Age' and 'ETag'. See registerOption to know how to register more.

Use an array of buffers if you need to send multiple options with the same name.

If you need to pass a custom option, pass a string containing a a number as key and a Buffer as value.

Example:

message.setOption('Content-Format', 'application/json')

or

message.setOption('555', [Buffer.from('abcde'), Buffer.from('ghi')])

setOption is also aliased as setHeader for HTTP API compatibility.

Also, 'Content-Type' is aliased to 'Content-Format' for HTTP compatibility.

Since v0.7.0, this library supports blockwise transfers, you can trigger them by adding a req.setOption('Block2', Buffer.of(0x2)) to the output of request.

And since v0.25.0, this library supports rudimentry type 1 blockwise transfers, you can trigger them by adding a req.setOption('Block1', Buffer.of(0x2)) to the options of request.

(The hex value 0x2 specifies the size of the blocks to transfer with. Use values 0 to 6 for 16 to 1024 byte block sizes respectively.)

See the spec for all the possible options.

message.reset()

Returns a Reset COAP Message to the sender. The RST message will appear as an empty message with code 0.00 and the reset flag set to true to the caller. This action ends the interaction with the caller.

message.writeHead(code, headers)

Functions somewhat like http's writeHead() function. If code is does not match the CoAP code mask of #.##, it is coerced into this mask. headers is an object with keys being the header names, and values being the header values.

message.on('timeout', function(err) { })

Emitted when the request does not receive a response or acknowledgement within a transaction lifetime. Error object with message No reply in XXXs and retransmitTimeout property is provided as a parameter.

message.on('error', function(err) { })

Emitted when an error occurs. This can be due to socket error, confirmable message timeout or any other generic error. Error object is provided, that describes the error.


IncomingMessage

An IncomingMessage object is created by coap.createServer or coap.request and passed as the first argument to the 'request' and 'response' event respectively. It may be used to access response status, headers and data.

It implements the Readable Stream interface, as well as the following additional methods and properties.

message.payload

The full payload of the message, as a Buffer.

message.options

All the CoAP options, as parsed by CoAP-packet.

All the options are in binary format, except for 'Content-Format', 'Accept' and 'ETag'. See registerOption() to know how to register more.

See the spec for all the possible options.

message.headers

All the CoAP options that can be represented in a human-readable format. Currently they are only 'Content-Format', 'Accept' and 'ETag'. See to know how to register more.

Also, 'Content-Type' is aliased to 'Content-Format' for HTTP compatibility.

message.code

The CoAP code of the message.

message.method

The method of the message, it might be 'GET', 'POST', 'PUT', 'DELETE' or null. It is null if the CoAP code cannot be parsed into a method, i.e. it is not in the '0.' range.

message.url

The URL of the request, e.g. 'coap://localhost:12345/hello/world?a=b&b=c'.

message.rsinfo

The sender informations, as emitted by the socket. See the dgram docs for details

message.outSocket

Information about the socket used for the communication (address and port).


ObserveReadStream

An ObserveReadStream object is created by coap.request to handle observe requests. It is passed as the first argument to the 'response' event. It may be used to access response status, headers and data as they are sent by the server. Each new observe message from the server is a new 'data' event.

It implements the Readable Stream and IncomingMessage interfaces, as well as the following additional methods, events and properties.

close()

Closes the stream.

message.rsinfo

The sender's information, as emitted by the socket. See the dgram docs for details

message.outSocket

Information about the socket used for the communication (address and port).


ObserveWriteStream

An ObserveWriteStream object is emitted by the coap.createServer 'response' event as a response object. It may be used to set response status, headers and stream changing data to the client.

Each new write() call is a new message being sent to the client.

It implements the Writable Stream interface, as well as the following additional methods and properties.

Event: 'finish'

Emitted when the client is not sending 'acks' anymore for the sent messages.

reset()

Returns a Reset COAP Message to the sender. The RST message will appear as an empty message with code 0.00 and the reset flag set to true to the caller. This action ends the interaction with the caller.


coap.registerOption(name, toBinary, toString)

Register a new option to be converted to string and added to the message.headers. toBinary is a function that accept a string and returns a Buffer. toString is a function that accept a Buffer and returns a String.


coap.ignoreOption(name)

Explicitly ignore an option; useful for compatibility with http-based modules.


coap.registerFormat(name, value)

Register a new format to be interpreted and sent in CoAP Content-Format option. Each format is identified by a number, see the Content-Format registry.

These are the defaults formats:

Media Type ID
text/plain 0
application/cose; cose-type="cose-encrypt0" 16
application/cose; cose-type="cose-mac0" 17
application/cose; cose-type="cose-sign1" 18
application/link-format 40
application/xml 41
application/octet-stream 42
application/exi 47
application/json 50
application/json-patch+json 51
application/merge-patch+json 52
application/cbor 60
application/cwt 61
application/multipart-core 62
application/cbor-seq 63
application/cose-key 101
application/cose-key-set 102
application/senml+json 110
application/sensml+json 111
application/senml+cbor 112
application/sensml+cbor 113
application/senml-exi 114
application/sensml-exi 115
application/coap-group+json 256
application/dots+cbor 271
application/missing-blocks+cbor-seq 272
application/pkcs7-mime; smime-type=server-generated-key 280
application/pkcs7-mime; smime-type=certs-only 281
application/pkcs8 284
application/csrattrs 285
application/pkcs10 286
application/pkix-cert 287
application/senml+xml 310
application/sensml+xml 311
application/senml-etch+json 320
application/senml-etch+cbor 322
application/td+json 432
application/vnd.ocf+cbor 10000
application/oscore 10001
application/javascript 10002
application/vnd.oma.lwm2m+tlv 11542
application/vnd.oma.lwm2m+json 11543
application/vnd.oma.lwm2m+cbor 11544
text/css 20000
image/svg+xml 30000

coap.Agent([opts])

An Agent encapsulate an UDP Socket. It uses a combination of messageId and token to distinguish between the different exchanges. The socket will auto-close itself when no more exchange are in place.

By default, no UDP socket are open, and it is opened on demand to send the messages.

Opts is an optional object with the following optional properties:

  • type: 'udp4' or 'udp6' if we want an Agent on an IPv4 or IPv6 UDP socket.

  • socket: use existing socket instead of creating a new one.


coap.globalAgent

The default Agent for IPv4.


coap.globalAgentIPv6

The default Agent for IPv6.


coap.updateTiming

You can update the CoAP timing settings, take a look at the examples:

const coapTiming = {
  ackTimeout: 0.25,
  ackRandomFactor: 1.0,
  maxRetransmit: 3,
  maxLatency: 2,
  piggybackReplyMs: 10
}
coap.updateTiming(coapTiming)

coap.defaultTiming

Reset the CoAP timings to the default values

Contributing

node-coap is an OPEN Open Source Project. This means that:

Individuals making significant and valuable contributions are given commit-access to the project to contribute as they see fit. This project is more like an open wiki than a standard guarded open source project.

See the CONTRIBUTING.md file for more details.

Contributors

node-coap is only possible due to the excellent work of the following contributors:

Matteo CollinaGitHub/mcollinaTwitter/@matteocollina
Nguyen Quoc DinhGitHub/nqdTwitter/@nqdinh
Daniel Moran JimenezGitHub/dmoranjTwitter/@erzeneca
Ignacio MartínGitHub/neichTwitter/@natxupitxu
Christopher HillerGitHub/boneskullTwitter/@b0neskull

LICENSE

MIT, see LICENSE.md file.

node-coap's People

Contributors

apollon77 avatar ats-org avatar barto- avatar beriberikix avatar boneskull avatar dmoranj avatar giedriusm avatar gmszone avatar guimier avatar highwall avatar htool avatar jcbernack avatar jimmybjorklund avatar jkrhb avatar jsonma avatar mast avatar mateusz- avatar maxired avatar mcollina avatar neich avatar neophob avatar ojford avatar petereb avatar relu91 avatar richardms avatar rmhowie avatar sammyt avatar sjlongland avatar teomurgi avatar treadingwell avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

node-coap's Issues

How to cancel the Observe?

When the client close ObserveReadStream,the server doesn't emit 'finish' event.But when I cancel observe in copper,the server emit immediately, how should I do?

Send POST with payload

Hi,

I can receive POST requests from COAPY (Python implementation of COAP) but in this package isnt implemented? If yes, how can I send payload data on a POST request?

Best regards

CoAP Server Not Receiving Requests on AWS

We recently used your CoAP NPM module to add CoAP support for all SkyNet.im REST API calls. It works fine on localhost but doesn't receive any requests when deployed to Amazon EC2 servers running Amazon Linux. I've opened UDP port 5683 and even tried opening the ports for all traffic and neither firewall setting works. I've also tried using localhost, skynet.im, the public ip address, and the private ip address for the CoAP server host but still no requests received from outside of the box.

I installed node-cli on the skynet server and set the host to CoAP host to localhost and I am able to get a response using:

coap get coap://localhost/status

No requests from outside of the box work - even other SkyNet servers on the same security group using private IP addresses.

Any help would be greatly appreciated.

Thanks,
Chris

Running IPv6

Trying to run a request over IPv6.

I have a mobile configured to run IPv6 only in a mobile network. The mobile is wifi hotspot to my laptop, which runs a node.js application using this CoAP library.

  1. Looking in index.js I see the statement `ipv6 = net.isIPv6(url.hostname || url.host)``. According to
    https://nodejs.org/api/net.html#net_net_isipv6_input the input parameter should be an IP-address, which means that this method will always return false if the input parameter is a host or hostname.
  2. To get around this I tried the set the agent to IPv6 in the request with:
    request.agent = coap.globalAgentIPv6;
    or
    request.agent = new coap.Agent({ type: 'udp6' });

However, in both these case node gave error "Converting circular structure to JSON"

Any advice?

Listening on the same port used for sending

I'm currently involved in the development of a OMA Lightweight M2M library, based on node-coap (you can find it here and I'm struggling with one aspect of the specification: it requires the server to communicate with the devices using the same IP and Port used in the registration message (a POST COAP message to the server). That IP and port is used then for bidirectional communications: the server can send COAP Messages to that address and that is the address that is expected to be used to initiate messages from the device side as well.

I'm trying to overcome this issue using a customized Agent for every request, bound to the same 5683 port where the device listens for requests originated from the server. The problem here is that this situation generates two listening handlers: the one set up in the createServer() function, and the listener for the "response" event from the request. The problem arises when a request is sent using port 5683, and the response arrives to the port with two listeners.

This wouldn't be a problem in case both handlers were called, as I could simply ignore answers in the server handler (e.g.: identified by the lack of method), but that's not the case: the answer to the request arrives exclusively to the server handler, thus leaving the response listener blocked forever.

I know this scenario may be too specific for the Lightweight M2M protocol, but I would appreciate any idea for dealing with this problem, as I'm a bit stuck with it, including any contribution I could make to the library to support this weird case.

Blockwise 'block1' mode

Hi,

it seems that the 'block1' mode is not implemented. There is only 'block2' mode.
Part 2.3, in the IETF document, it's written that block1 mode should be use in case of a POST or a PUT to the server and block2 in a response (GET).

Looking at the agent.js file, there is nothing concerning block1.

Thanks
Sylvain

Packet Parser

Hi,

there a problem in the index parser for the payload.
If you look at the function
module.exports.parse = function parse(buffer) { ... }

There is a variable index=4.
This value is changed in the function parseToken { ... }
So when it's time to parse the payload result.payload = buffer.slice(index+1); back in the parse function, the index value is out of range, so the payload is empty.

Look at this example (this is a real coap package recived from a contiki node):
The payload should be "light" but the index value is 19, instead of 5, so the payload is empty.
image

Just change the index value name and it works

Sylvain

Provide an easy way to mark a response as RESET

This behavior can be currently achieved in the following way:

server.on('request', function (req, res) {
    console.log('This is it: ' + req.payload.toString());
    res._packet.reset = true;
    res._packet.ack = false;
    res.end();
});

It seems there isn't any direct way to achieve the same result with the public API. The RESET behavior can be useful to implement some behaviors, as COAP Ping (a RST response to an empty confirmable body, as specified in the COAP specification).

DTLS

If DTLS is not yet available, would libsodium via node-ffi work?

How to read Token and Message Type?

Hi,

I am experimenting with this excellent library and have two questions:

  • How to read the Token field in a GET Observe response? Could it also be set in the request?
  • How to read the Message Type (Confirmable, Non-Confirmable, Acknowledgement, Reset) in a response?

Fail to install on remote machine

Hi, I tried to install node-coap locally (OSX) and worked like a charm. I wanted to install it on a remote machine running ubuntu, but I got the following error:

masiar@neha:~/coap-test$ sudo npm install coap --save
npm http GET https://registry.npmjs.org/coap
npm http 200 https://registry.npmjs.org/coap
npm http GET https://registry.npmjs.org/coap/-/coap-0.7.1.tgz
npm http 200 https://registry.npmjs.org/coap/-/coap-0.7.1.tgz
npm http GET https://registry.npmjs.org/bl
npm http GET https://registry.npmjs.org/coap-packet
npm http GET https://registry.npmjs.org/lru-cache
npm http 200 https://registry.npmjs.org/lru-cache
npm http GET https://registry.npmjs.org/lru-cache/-/lru-cache-2.5.0.tgz
npm http 200 https://registry.npmjs.org/lru-cache/-/lru-cache-2.5.0.tgz
npm http 200 https://registry.npmjs.org/coap-packet
npm http GET https://registry.npmjs.org/coap-packet/-/coap-packet-0.1.11.tgz
npm http 200 https://registry.npmjs.org/coap-packet/-/coap-packet-0.1.11.tgz
npm http 200 https://registry.npmjs.org/bl
npm http GET https://registry.npmjs.org/bl/-/bl-0.7.0.tgz
npm http 200 https://registry.npmjs.org/bl/-/bl-0.7.0.tgz
npm http GET https://registry.npmjs.org/stream-browserify
npm http 200 https://registry.npmjs.org/stream-browserify
npm http GET https://registry.npmjs.org/stream-browserify/-/stream-browserify-1.0.0.tgz
npm http 200 https://registry.npmjs.org/stream-browserify/-/stream-browserify-1.0.0.tgz
npm http GET https://registry.npmjs.org/inherits
npm http GET https://registry.npmjs.org/readable-stream
npm http 200 https://registry.npmjs.org/inherits
npm http GET https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz
npm http 200 https://registry.npmjs.org/readable-stream
npm ERR! Error: No compatible version found: readable-stream@'^1.0.27-1'
npm ERR! Valid install targets:
npm ERR!  ["0.0.1","0.0.2","0.0.3","0.0.4","0.1.0","0.2.0","0.3.0","0.3.1","1.0.0","1.0.1","1.0.2","1.0.15","1.0.17","1.1.7","1.1.8","1.1.9","1.0.24","1.0.25","1.1.10","1.0.25-1","1.1.11","1.0.26","1.0.26-1","1.1.11-1","1.0.26-2","1.1.12","1.0.26-3","1.0.26-4","1.1.12-1","1.0.27-1","1.1.13-1"]
npm ERR!     at installTargetsError (/usr/local/lib/node_modules/npm/lib/cache.js:674:10)
npm ERR!     at /usr/local/lib/node_modules/npm/lib/cache.js:589:10
npm ERR!     at saved (/usr/local/lib/node_modules/npm/node_modules/npm-registry-client/lib/get.js:138:7)
npm ERR!     at /usr/local/lib/node_modules/npm/node_modules/graceful-fs/graceful-fs.js:218:7
npm ERR!     at Object.oncomplete (fs.js:297:15)
npm ERR! If you need help, you may report this log at:
npm ERR!     <http://github.com/isaacs/npm/issues>
npm ERR! or email it to:
npm ERR!     <[email protected]>

npm ERR! System Linux 3.5.0-37-generic
npm ERR! command "/usr/local/bin/node" "/usr/local/bin/npm" "install" "coap" "--save"
npm ERR! cwd /home/masiar/coap-test
npm ERR! node -v v0.8.18
npm ERR! npm -v 1.2.2
npm http 200 https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz
npm ERR! 
npm ERR! Additional logging details can be found in:
npm ERR!     /home/masiar/coap-test/npm-debug.log
npm ERR! not ok code 0

I tried to clear npm cache and manually install readable-stream globally but that wasn't working either.

Possible memory leak when request gets error

Hi,

I'm working in a project that at some point starts to make a COAP GET request every second. If the response is OK there is no problem, heap keeps stable. But if, for example, the network gos down and I start to get ENETUNREACH errors, the heap starts to grow since I got a out of memory error.

I've created a small test to show what I mean:

https://gist.github.com/neich/97743a806fc76ff06932

My understanding is that since there is a 247s timeout for requests, if you start to get ENETUNREACH, all requests are kept until the timeout is fired. But once have passed 247s, requests should be able to be GC and the heap should stop to grow.

In my test, after 1000 sec approx, I got an out of memory error. Does the timeout not clean the request ? Am I missing something ?

Is there a way to abort a request a let it ready for GC ?

Thanks

ReferenceError: err is not defined

I just saw this error in a log file:

/usr/lib/node_modules/coap-cli/node_modules/coap/lib/agent.js:180
      return req.emit('error', err)
                              ^

ReferenceError: err is not defined
    at Agent.handle [as _handle] (/usr/lib/node_modules/coap-cli/node_modules/coap/lib/agent.js:180:32)
    at Socket.<anonymous> (/usr/lib/node_modules/coap-cli/node_modules/coap/lib/agent.js:66:10)
    at emitTwo (events.js:87:13)
    at Socket.emit (events.js:172:7)
    at UDP.onMessage (dgram.js:481

Currently I cannot reproduce it as I don't know how it happend.

HTTP vs CoAP

As far as I can tell, CoAP seems like a far more flexible, minimal version of HTTP (in terms of functionality), what can HTTP do that CoAP cannot?

One obvious thing was the ability to reuse a connection via keep-alive, but what else? Specifically, what are CoAPs drawbacks (other than support)? Why not transition away from HTTP and use CoAP for everything?

This question isn't specific to node-coap, it's a general question about CoAP, but I figure rather than asking privately I'd ask here so someone else may stumble upon it. If you'd prefer to not have such things in the issue queue, let me know and I will not repeat!

IPV6 client requests

Hey I have to make IPV6 requests to my COAP server located at some IPV6 address. say 2001:131:aabc:12::1 for example.

How do I put that information in the client example of coap node js

Thanks in advance for the reply.

Improve time-related tests to make them safer

There are some tests, labeled "should retry four times before 45s" that fail from time to time, by retrying 5 times instead of 4. That's a typical problem with time-related tests and we should try to make them safer (we are already using the timers, so we should be able to fine-tune this somehow).

Crash when receiving two confirmable responses with same message ID & token

Hi,

I'm getting a crash with a long running process that happens very rarely. I've been able to write a test that shows the crash:

https://gist.github.com/neich/b4788c093a100ade7cfe

It seems that if by accident you receive two CON responses with the same message ID & token, it crashes with the second because the library believes is an observable request: there is a req.response from the previous response, but it an OutgoingMessage, an not an ObservableStrem, so .append() fails.

Right now I've solved with this:

  if (req.response) {
    if (req.response.append) {
      // it is an observe request
      // and we are already streaming
      return req.response.append(packet)
    } else {
      // TODO There is a previous response but is not an ObserveStream !
      req.response = null
    }

but I'm not sure if it's right. Should I PR?

How do you send PUT message with payload?

Hello,
Not sure I get it, is this the way to send PUT message?

var req = coap.request({host: 'coap://localhost/Matteo', method : 'PUT'})
var payload = {
title: 'this is a test payload',
body: 'containing nothing useful'
}

req.write(new Buffer(JSON.stringify(payload)));
req.on('response', function(res) {
res.pipe(process.stdout)
})
req.end()

ignore charset info when converting content format to binary

a content format Content-Type: application/json; charset=utf8 will blow up. I believe we can strip the semicolon (inclusive) to the end during conversion.

CoAP does not include a separate way to convey content-encoding
information with a request or response, and for that reason the
content-encoding is also specified for each identifier (if any). If
multiple content-encodings will be used with a media type, then a
separate Content-Format identifier for each is to be registered.
Similarly, other parameters related to an Internet media type, such
as level, can be defined for a CoAP Content-Format entry.

Format 0 must be utf-8

Format 0 is defined as text/plain; charset=utf-8. By definition, text/* defaults to US-ASCII and causes encoding problems if a Unicode-encoded document is served without this charset parameter - e.g. in CoAP-to-HTTP translators.

Instead, the module serves option 0 as merely text/plain i.e. US-ASCII.

non-confirmable message behavior (bug)

From IETF CoAP draff 18:
Non-confirmable Message
Some other messages do not require an acknowledgement. This is
particularly true for messages that are repeated regularly for
application requirements, such as repeated readings from a sensor.

With bellow simple client, without a coap server running locally, I still receive timeout error, which should not appear due to non-confirmable posting.

var url = {
hostname: 'localhost',
pathname: '/matteo',
confirmable: false,
method: 'POST',
payload: 'nothings'
};
var req = coap.request(url)
req.on('response', function(res) {
res.pipe(process.stdout)
})
req.on('error', function(err) {
console.log('error: ', err);
})
req.end()

Multicast Support

At the moment, node-coap does not support multicast communication, as it it does not expose any API to add/remove the membership to a group.

need type in req?

As type (CON, NON, ACK, RST) of a message is importance, e.g. a server determine not to shoot an ack response for a non-confirmable post message, or give out a reply for a confirmable get request, I suggest to make type item in req.

An example from console.log(req), which still lack type to check if this req is CON/NON. I refuse to check in _packet (because of its name).

PS: do you think we need both code (0.01) and method (GET)?

readable: true,
domain: null,
_events: {},
_maxListeners: 10,
payload: ,
options: [],
code: '0.01',
method: 'GET',
headers: {},
url: '/',
_packet:
{ code: '0.01',
confirmable: false,
reset: false,
ack: false,
messageId: 1575,
token: <Buffer 2c ee 3b 9d>,
options: [],
payload: },
_payloadIndex: 0,

Error when token length is not 4

Hi,

I use node-coap as client of another coap server.
In my case, the token length is not 4, ans so I have an error when dealing with it.
This seems to be a valid case since in https://tools.ietf.org/html/draft-ietf-core-coap-18#section-5.3.1 is it specified : The Token is used to match a response with a request. The token value is a sequence of 0 to 8 bytes.

Here is the error :

buffer.js:582
    throw new RangeError('Trying to access beyond buffer length');
          ^
RangeError: Trying to access beyond buffer length
    at checkOffset (buffer.js:582:11)
    at Buffer.readUInt32BE (buffer.js:649:5)
    at Agent.handle [as _handle] (/root/hyve-coap/node_modules/coap/lib/agent.js:168:39)
    at Socket.<anonymous> (/root/hyve-coap/node_modules/coap/lib/agent.js:59:10)
    at Socket.EventEmitter.emit (events.js:98:17)
    at UDP.onMessage (dgram.js:440:8)

I made a hack which fix my case, but I am not sure whether I 'm introducing a memory leak or not. : maxired@20b452b

coap [Malformed Packet] and async calls

Hi,
I'm using cooja simulator to simulate my coap server so i can´t paste here the code of the server, but basically it has a resource /test/hello that has the following information {info:{name: "sensor1", location:"Room"}}.
When i make my request i check that in wireshar it gives me a Malformed Packet, but it retrives the data that i want, what am i doing wrong? my client code is:

const coap = require('coap');
var option = {'Content-Format': 'application/link-format'};
var obj = {hostname:"aaaa::c30c:0:0:3",
    port:5683,
    pathname:"test/hello",
    method: 'GET',
    //query: 'ASDFGASHDT',
    options: option
    };
const req = coap.request(obj);
req.on('response', function(res) {

    res.pipe(process.stdout);
});
req.end();

and a screenshoot of wireshark capture
wireshark

and i want to make this call to a set of ip's and wait for the response to send it all when finished, so i've made this functions:

var coap=require('coap');
var bl=require('bl');

var ips=["aaaa::c30c:0:0:3","aaaa::c30c:0:0:2"];


function async(ip, callback) {
    var option = {accept: 'application/json'};
        var obj = {hostname : ip,
        port:5683,
    method: 'GET',
    confirmable: true,
        pathname:"test/hello",      
    options: [{"Accept": "application/json"}]
    };

    var data="";
    var reqCoap = coap.request(obj);

    reqCoap.on('response',function(res){
       res.pipe(bl(function(err, data) {          
            var json = JSON.parse(data);
            callback(json);            
        }));
       res.on('end', function() {
            console.log("ended");
        }); 
    });
    reqCoap.end();
};

with this code it only returns the code sometimes but most times it doesn't return the data.

Can you please help me with this?

Test "request should emit the errors in the req" fails with timeout

I note that Travis-CI shows the build passing, so maybe I've got some kind of incompatibility. I'm running using node version 0.10.36 on the Mac and 0.10.29 on a Debian BeagleBone image 2015-03-01. The same problem occurs on both using "npm test" to execute the tests. Here is the exact error...

1) request should emit the errors in the req:
     Error: timeout of 2000ms exceeded
      at null.<anonymous> (/root/node-coap/node_modules/mocha/lib/runnable.js:158:19)
      at Timer.listOnTimeout [as ontimeout] (timers.js:110:15)

Any suggestions? Thanks!

Blockwise support dont work with pipe()

Look like the blockwise support (Block2 option) is implemented in OutMessage.end(), so when the end() is called without payload (or when stream end) is skipped and the OutoingMessage.end() is called instead, so a 'Max packet size is 1280: current is XXX" error is thrown.

coapServer.on('request', function router(request, response) {
  ...
  largestream.pipe(response)
  ...
}

a workaround we found is collect the buffer outside:

coapServer.on('request', function router(request, response) {
  ...
  largestream.pipe(bl(function (err, data) {
    response.end(data)
  }))
  ...
}

sporadic travis failures

I just modified README.md, which triggered a build. The build failed.

The issue is:

  1) server with a confirmable message should retry sending the response if it does not receive an ack four times before 45s:
      Uncaught AssertionError: expected 4 to deeply equal 5
      + expected - actual
      +5
      -4

      at /home/travis/build/mcollina/node-coap/test/server.js:624:29
      at Object.sinon.clock.callTimer (/home/travis/build/mcollina/node-coap/node_modules/sinon/lib/sinon/util/fake_timers.js:200:32)
      at Object.tick (/home/travis/build/mcollina/node-coap/node_modules/sinon/lib/sinon/util/fake_timers.js:145:28)
      at fastForward (/home/travis/build/mcollina/node-coap/test/server.js:51:11)
      at processImmediate [as _immediateCallback] (timers.js:363:15)
1``

I imagine this is just a timing issue, but I'm wondering if it's indicative of a code problem or simply a test problem.

POST method in server.js

Hello All,

I am entirely new to Node.js in COAP. I need to accomplish a simple task using server.js. I will send some data using POST from a client and the server should be able to store it in a variable.

Can somebody please suggest me what modifications i should make in server.js

case-insensitive option matching

I have something that's trying to send option content-type. This results in:

    Error: Unknown string to Buffer converter for option: content-type
    at module.exports.toBinary (/Volumes/alien/projects/digs/tmp/node_modules/coap/lib/option_converter.js:18:11)
    at OutMessage.setOption (/Volumes/alien/projects/digs/tmp/node_modules/coap/lib/helpers.js:46:16)

@mcollina Would you accept a PR to just run .toLowercase() across the option names?

Cloud and CoAP

Hello nice work with this module.

I am new at this protocol and as i was playing around in one cloud server of IBM i had some problems.
My server seemed to run properly but the client( my Pc) could not send requests.
So my question is to what hosting providers have you used this module . SHould it work for all of them ?.
Thank you,
Spiritnlife

'index out of range' error

Hi,

I'm getting this error while performing some GETs on real devices:

buffer.js:506
    throw new RangeError('index out of range');
          ^
RangeError: index out of range
    at checkOffset (buffer.js:506:11)
    at Buffer.readUInt32BE (buffer.js:580:5)
    at Agent.handle [as _handle] (/..../coap-ngsi-agent/node_modules/coap/lib/agent.js:222:39)
    at Socket.<anonymous> (/..../coap-ngsi-agent/node_modules/coap/lib/agent.js:65:10)
    at Socket.emit (events.js:110:17)
    at UDP.onMessage (dgram.js:472:8)

Since it is very difficult to produce a simple test case, I'm attaching the debuggin session just at the point where it fails. It seems that at some point, lib/agent.js is trying to call readUInt32BE on an empty buffer.

Any hints?

coap_problem

Proxy blocks ACKs to Confirmable Observe messages

@dmoranj , thanks for fixing #56. Now GET Observe messages pass the Proxy fine. However, unfortunately there still is a problem as it seems as the ACKs to each Observe message send from the observe client do not pass the proxy.

I got the following error message for the observe server, i.e. the peer that received the GET Observe request and sends CON Observe:
Error: No reply in 247s at null._onTimeout (C:\node_modules\coap\lib\retry_send.js:61:18) at Timer.listOnTimeout [as ontimeout] (timers.js:112:15) .

Checking with Wireshark confirmed that the ACKs were not received by the observe server. When I run without a proxy the ACKs were received correctly.

BR

coapServer.listen doesn't work without any input

coapServer.listen() without any parameter, e.g. port, callback, doesn't make any 'request' emit.

const coap   = require('../') // or coap
, coapServer = coap.createServer()

coapServer.on('request', function(req, res) {
  res.end('Hello ' + req.url.split('/')[1] + '\n')
})
coapServer.listen()  // this coapServer then doesnt work

JSON as playload

Hi,
I am new to nodejs, how can I add a JSON payload to post request?

Thanks

http header compatibility strategy

So I'm wondering to what degree does this module want to allow common HTTP headers? The spec only defines a few options of course, but for compatibility with modules based on http, it'd be cool if we could at least not throw exceptions if they want to use headers such as Cache-Control or Content-Length.

In addition to registerOption(), perhaps we can implement an ignoreOption(), which just silently tosses out headers which are not applicable?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.