-
Notifications
You must be signed in to change notification settings - Fork 2k
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
net/nanocoap: rework option handling #8772
Conversation
pkt->hdr = hdr; | ||
|
||
uint8_t *pkt_pos = hdr->data; | ||
uint8_t *pkt_end = buf + len; | ||
|
||
memset(pkt->url, '\0', NANOCOAP_URL_MAX); |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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?�
There was a problem hiding this comment.
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...
969fb19
to
7a32be1
Compare
Thanks for this work, Kaspar! I have browsed through it, and just from a structural perspective:
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. |
b42a1a3
to
c44a9c6
Compare
Done -> #8788
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(). |
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; |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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)
There was a problem hiding this 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.
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'; |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
Removal of |
They should... Can we postpone that? 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. |
sys/include/net/nanocoap.h
Outdated
* @param[in] pkt pkt to work on | ||
* @param[out] target buffer for target URI | ||
* | ||
* @returns -EBADMSG if no URI option in packet |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No reason. folo?
There was a problem hiding this comment.
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?!
6dfcaa0
to
da6ca3d
Compare
sys/include/net/nanocoap.h
Outdated
* | ||
* @param[in] pkt packet to work on | ||
* | ||
* @returns the packet's content type value |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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) { |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, fixed.
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. |
da6ca3d
to
6417167
Compare
@kb2ma addressed your comments |
There was a problem hiding this 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://github.com/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) |
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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?!
@haukepetersen, see the comments above starting here, which match your comments. I agree on more generic functions. See my ideas for gcoap in #8331. |
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. |
Whoops, meant #8831, for gcoap adaptation to these changes. It includes similar thoughts on data-centric option functions.
I agree. I plan to test latest fixups today. |
6417167
to
b33ae7d
Compare
@bergzand @haukepetersen you good for now? |
There was a problem hiding this 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 :)
comments addressed / postponed
Nice, thanks for the reviews! |
Thanks for the actual work :-) |
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.