Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

net/nanocoap: rework option handling #8772

Merged
merged 2 commits into from
Apr 10, 2018

Conversation

kaspar030
Copy link
Contributor

Contribution description

This PR reworks nanocoap's option handling. Instead of having a field in coap_pkt_t for each supported CoAP option, the parsing step now just notes down the options with option number and offset in an array. Furthermore, some layers of parsing/iterating functions are provided.

As gcoap is not yet adapted, some compatibility layer makes it still work.

As a first user for the new option handling, this PR also adds block1 support to nanocoap, with an example, blockwise-capable /sha256 enpoint for examples/nanocoap_server.

@kaspar030 kaspar030 added Type: enhancement The issue suggests enhanceable parts / The PR enhances parts of the codebase / documentation Area: network Area: Networking CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR labels Mar 13, 2018
pkt->hdr = hdr;

uint8_t *pkt_pos = hdr->data;
uint8_t *pkt_end = buf + len;

memset(pkt->url, '\0', NANOCOAP_URL_MAX);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this change documented? If not, may it cause nasty surprises to existing code?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or does the change on line #L119 override always the URL field?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

coap->pkt does not exist anymore, unless gcoap is used. In that case, #L119 does overwrite the field.

Anyhow, I've added another null-termination for the case that the option is not present.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, you mean whether removing the field might cause nasty surprises? Very probably. :)

@@ -67,9 +65,13 @@ int coap_parse(coap_pkt_t *pkt, uint8_t *buf, size_t len)
pkt->token = NULL;
}

coap_optpos_t *optpos = pkt->options;
unsigned option_count = 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is using just unsigned instead of the "more standard" unsigned int according to the used style guide?�

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In RIOT just unsigned seems to be "more standard". Personally I prefer less typing and one-word type identifiers...

@kaspar030 kaspar030 force-pushed the rework_nanocoap_option_handling branch from 969fb19 to 7a32be1 Compare March 14, 2018 13:39
@kb2ma
Copy link
Member

kb2ma commented Mar 15, 2018

Thanks for this work, Kaspar! I have browsed through it, and just from a structural perspective:

  • I would separate Block support into another PR. It seems too much to refactor coap_pkt_t and option parsing -- and to add support for a CoAP extension RFC in a single PR.
  • With work at this level, I would expect to see at least some basic unit tests to validate reading options.

Naturally, I want to adapt gcoap to use this work ASAP. This will be a good way for me to get familiar with the implementation, and provide more detailed comments.

@kaspar030
Copy link
Contributor Author

I would separate Block support into another PR. It seems too much to refactor coap_pkt_t and option parsing -- and to add support for a CoAP extension RFC in a single PR.

Done -> #8788

With work at this level, I would expect to see at least some basic unit tests to validate reading options.

No time. :) Maybe sometimes extensive testing is enough?

@kaspar030
Copy link
Contributor Author

No time. :) Maybe sometimes extensive testing is enough?

Ok, that's no excuse. I've added a (basic) test for get_option_uri(), which tests parsing options into the array, iterating through multi options and finally also the get_option_uri().

@kb2ma
Copy link
Member

kb2ma commented Mar 16, 2018

Excellent, thanks a lot for that rework. I understand the ambivalence about unit tests, and appreciate sinking the extra time into it. We can build on it as needed.

Now it's time for me to get to work and provide some feedback. :-)


#ifdef MODULE_GCOAP
coap_get_uri(pkt, pkt->url);
pkt->observe_value = UINT32_MAX;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Must update this attribute if observe option is present.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This idea points to a more general question -- should the get/set option functions be based on the type of data format rather than the specific option?

Yeah, very good idea. I've started in this direction with a coap_get_option_uint() for getting the observe value.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(that reply belongs to the getting/setting options comment below)

Copy link
Member

@kb2ma kb2ma left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall, this work is nice improvement to remove the url and qs attributes in coap_pkt_t. Tested on native for nanocoap and gcoap. Works OK except for the specific comment in the code for reading an Observe option.

Getting/Setting option values

If you add an option number parameter to coap_get_option_uri(), you could retrieve a Uri-Query option, as is done when setting these options in coap_put_option_uri(). This idea points to a more general question -- should the get/set option functions be based on the type of data format rather than the specific option? Sec. 3.2 in RFC 7252 shows there are just four possibilities for data format -- string, uint, opaque (byte array), and empty. String and byte array can be handled similarly. Specific option numbers could then be get/set by an inline function that just sets the parameters for the data-format based get/set functions.

Maybe this work is a follow-on PR, but it seems like a small step. Certainly gcoap will need to read the Observe value when it is adapted to this PR.

coap_hdr_... functions

This is more of a general/FYI comment. I see you have removed coap_hdr_get_ver(). gcoap does not need this function specifically, but it does need coap_hdr_ functions for message type and token length. msg_type is used in gcoap_req_send2() to determine if confirmable. token_len is used when reading a confirmable observe ack in open PR #7548. In both cases no coap_pkt_t is available. Presently I manually inline the bit manipulation. So, a PR to add these functions is high on my list.

@kb2ma
Copy link
Member

kb2ma commented Mar 17, 2018

Shouldn't coap_find_option(), coap_get_content_type(), coap_get_len(), and coap_iterate_option() be declared in nanocoap.h?

uint8_t *opt_pos = coap_find_option(pkt, COAP_OPT_URI_PATH);
if (!opt_pos) {
DEBUG("nanocoap: no COAP_OPT_URI_PATH option\n");
*target = '\0';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The absence of a Uri-Path option means the path is "/". See Item 7 in sec. 6.5 of 7252. This actually is a bug in the current implementation as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

@kb2ma
Copy link
Member

kb2ma commented Mar 25, 2018

I just added my thoughts on adaptation of gcoap to this PR in #8831. No concerns beyond the issues I raised above.

@kaspar030
Copy link
Contributor Author

I see you have removed coap_hdr_get_ver(). gcoap does not need this function specifically, but it does need coap_hdr_ functions for message type and token length.

Removal of coap_hdr_get_ver() was an accident. Probably happened when we moved nanocoap into main while adding doxygen. I intend to keep the coap_hdr_* functions.

@kaspar030
Copy link
Contributor Author

Shouldn't coap_find_option(), coap_get_content_type(), coap_get_len(), and coap_iterate_option() be declared in nanocoap.h?

They should... Can we postpone that? I hoped to clean up the naming consistency a little.
IMO, the prefixing is a little off, and there should be clear coap_pkt_get/set(), coap_hdr_get/set(), coap_opt_X_get/set() ... naming conventions. I think they are a off sometimes.

@kb2ma
Copy link
Member

kb2ma commented Apr 4, 2018

I hoped to clean up the naming consistency a little.

No worries. I'm definitely in favor of standardizing the function names to make it easier to use them. I can experiment with the declarations as needed to prototype the gcoap adaptation.

* @param[in] pkt pkt to work on
* @param[out] target buffer for target URI
*
* @returns -EBADMSG if no URI option in packet
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With the comment from @kb2ma resolved, this return error code is not valid anymore for the specified situation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed. I also fixed the return value for the case where there's no URI option. It returned 1, but doc and other cases return 2, because the '\0' gets counted.

This makes me wonder - what's more appropriate from an API perspective? Return the number of bytes written to the output buffer, or return the length of the extracted path string? We can change that now, not so much later on...


return 0;
}

uint8_t *coap_find_option(coap_pkt_t *pkt, unsigned opt_num)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason for not marking the coap_pkt_t *pkt as const (const coap_pkt_t *pkt) here and in the other getters below?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No reason. folo?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function should be exported in the header, right?!

*
* @param[in] pkt packet to work on
*
* @returns the packet's content type value
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be clear, specify value is COAP_FORMAT_NONE if packet does not include a content type.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good idea, done

uint16_t delta;
int option_len = 0;
uint8_t *pkt_pos = _parse_option(pkt, opt_pos, &delta, &option_len);
if (option_len) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test also should be true when option_len is zero.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, fixed.

@kb2ma
Copy link
Member

kb2ma commented Apr 10, 2018

Just added a couple of inline comments. My Observe tests passed after I updated coap_get_option_uint(). When these comments are addressed, I'm ready to approve.

@kaspar030 kaspar030 force-pushed the rework_nanocoap_option_handling branch from da6ca3d to 6417167 Compare April 10, 2018 08:02
@kaspar030
Copy link
Contributor Author

@kb2ma addressed your comments

Copy link
Contributor

@haukepetersen haukepetersen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did not test in detail yet, trying to map the functionality of this PR to what I PRed in https:/kaspar030/sock/pull/18/files.

On first sight, it seems to me, that coap_get_option_uri() is very similar to what would be coap_get_option_query_string() and coap_get_option_location_path() (and possibly others). It seems to me, that we can probably handle all these multi-field, string type options with a more generic function.

So should we merge this PR as is and add this after?


return 0;
}

uint8_t *coap_find_option(coap_pkt_t *pkt, unsigned opt_num)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function should be exported in the header, right?!

return -1;
}

uint8_t *coap_iterate_option(coap_pkt_t *pkt, uint8_t **optpos, int *opt_len, int first)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here: should be exported, right?!

@kb2ma
Copy link
Member

kb2ma commented Apr 10, 2018

@haukepetersen, see the comments above starting here, which match your comments. I agree on more generic functions. See my ideas for gcoap in #8331.

@haukepetersen
Copy link
Contributor

haukepetersen commented Apr 10, 2018

sorry, the comments above slipped through.

@kb2ma are you referring to #7700? #8331 seems to be something quite different :-)

For further proceedings, I suggest we go with this PR as is - after another thorough round of testing of course. Then I could prepare a first step of generalization when adding the 'LOCATION_PATH' option needed for the RD client.

@kb2ma
Copy link
Member

kb2ma commented Apr 10, 2018

are you referring to #7700? #8331 seems to be something quite different :-)

Whoops, meant #8831, for gcoap adaptation to these changes. It includes similar thoughts on data-centric option functions.

For further proceedings, I suggest we go with this PR as is.

I agree. I plan to test latest fixups today.

@kaspar030 kaspar030 force-pushed the rework_nanocoap_option_handling branch from 6417167 to b33ae7d Compare April 10, 2018 18:58
@kaspar030
Copy link
Contributor Author

  • squashed

@bergzand @haukepetersen you good for now?

Copy link
Member

@bergzand bergzand left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All OK, Unless you want me to start nagging about function parameters that could have been declared as const :)

@kaspar030 kaspar030 dismissed haukepetersen’s stale review April 10, 2018 19:11

comments addressed / postponed

@kaspar030 kaspar030 merged commit 012c016 into RIOT-OS:master Apr 10, 2018
@kaspar030 kaspar030 deleted the rework_nanocoap_option_handling branch April 10, 2018 19:11
@kaspar030
Copy link
Contributor Author

Nice, thanks for the reviews!

@haukepetersen
Copy link
Contributor

Thanks for the actual work :-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area: network Area: Networking CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR Type: enhancement The issue suggests enhanceable parts / The PR enhances parts of the codebase / documentation
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants