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/gcoap: Use nanocoap pkt/options API #9156

Merged
merged 6 commits into from
Nov 26, 2018

Conversation

kb2ma
Copy link
Member

@kb2ma kb2ma commented May 19, 2018

Contribution description

Updates gcoap to use the nanocoap pkt/options API in #9085. This work allows removal of the gcoap-specific attributes in coap_pkt_t, which add a painful 130 bytes. (Now you know why I've been working so hard lately!)

Use of this API allows gcoap to fully build on nanocoap as a higher-level API. gcoap has always used a coap_pkt_t to build a message, and now nanocoap does too. See how gcoap_req_init() prepares for coap_build_hdr(), and then calls coap_pkt_init(), coap_opt_add_string() for the path, and coap_opt_add_uint() for the content format.

2018-10-23 Update

Simplified implementation of gcoap_finish(), which results in a minor API change. gcoap_finish() adds a Content-Format option to the packet after writing the payload. The original implementation of this PR accommodated options with any other option number that may have been added to the packet. Today I updated the implementation to accept options only with an option number less than Content-Format.

Fundamentally, the gcoap_finish() function has become obsolete as we have increased the use of CoAP options. The updated CoAP API now uses coap_opt_finish() to finalize the packet header before writing the payload. We plan to deprecate gcoap_finish() soon.

This change significantly simplifies gcoap_finish() until we deprecate it, and reduces the text space in the executable for this function by half, around 120 bytes. The cost is that existing code breaks when setting a Uri-Query option and then setting the format in gcoap_finish(). (Uri-Query is the only option with an option number greater than Content-Format that gcoap used before this PR.) In fact, the new Resource Directory implementation, cord_ep, had this problem, so I added a commit to this PR to fix it.

Issues/PRs references

Depends on #10223

See CoAP API Options Update wiki page for background, including how gcoap uses it.

@kb2ma kb2ma added Type: enhancement The issue suggests enhanceable parts / The PR enhances parts of the codebase / documentation State: WIP State: The PR is still work-in-progress and its code is not in its final presentable form yet labels May 19, 2018
@kb2ma kb2ma added State: waiting for other PR State: The PR requires another PR to be merged first Area: network Area: Networking labels May 19, 2018
@kb2ma
Copy link
Member Author

kb2ma commented May 20, 2018

I think code complete, but I'll give it a little time before removing WIP. I was able to remove most of the gcoap attributes in coap_pkt_t, with the nice reduction in size. I partially converted use of the observe value attribute, but removal will require a little work in nanocoap. I'll leave that for a follow-on PR.

@bergzand bergzand added the Area: CoAP Area: Constrained Application Protocol implementations label May 25, 2018
@kb2ma kb2ma changed the title [WIP] net/gcoap: Use nanocoap pkt/options API net/gcoap: Use nanocoap pkt/options API May 30, 2018
@kb2ma kb2ma removed the State: WIP State: The PR is still work-in-progress and its code is not in its final presentable form yet label May 30, 2018
@kb2ma kb2ma removed the State: waiting for other PR State: The PR requires another PR to be merged first label Jun 12, 2018
@kb2ma
Copy link
Member Author

kb2ma commented Jun 12, 2018

Rebased and ready for review now that #9085 has been merged.

* Not intended for use in a transmitted packet. Must be a 3-byte unsigned
* value.
*/
#define COAP_FORMAT_NO_PAYLOAD (65536)
Copy link
Member

Choose a reason for hiding this comment

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

Could you please right align all format values here?

Copy link
Member Author

Choose a reason for hiding this comment

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

Sure, no problem.

while (listener) {
coap_resource_t *resource = listener->resources;
for (size_t i = 0; i < listener->resources_len; i++) {
if (i) {
resource++;
}

int res = strcmp((char *)&pdu->url[0], resource->path);
int res = strcmp((char *)&uri[0], resource->path);
Copy link
Member

Choose a reason for hiding this comment

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

Does it make sense to use strncmp here with NANOCOAP_URI_MAX as an extra safety precaution?

Copy link
Member Author

Choose a reason for hiding this comment

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

coap_get_uri() inserts the terminator, but I agree it's better to be safe.

Copy link
Member

Choose a reason for hiding this comment

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

Small note here, I'm not sure whether strncmp is in the C99 libc. (It's not the case with strnlen by default)

Copy link
Member Author

Choose a reason for hiding this comment

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

Use of strncmp() adds 40 bytes to the samr21-xpro executable text space. Since coap_get_uri() documentation asserts that it inserts the terminator, would you be OK with beefing up the unit tests for that function as an alternative way to accomplish the goal?

Copy link
Member

Choose a reason for hiding this comment

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

Agreed, especially since it is a string build in our own functions.

Copy link
Member Author

Choose a reason for hiding this comment

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

Perfect. I'm working up a PR in my nanocoap/test_get_uri_path branch.

Copy link
Member Author

Choose a reason for hiding this comment

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

Merged in tests in #9444.

@@ -1017,26 +988,25 @@ int gcoap_get_resource_list(void *buf, size_t maxlen, uint8_t cf)

int gcoap_add_qstring(coap_pkt_t *pdu, const char *key, const char *val)
{
size_t qs_len = strlen((char *)pdu->qs);
char qs[NANOCOAP_URI_MAX];
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 reusing NANOCOAP_URI_MAX and not keeping and using the NANOCOAP_QS_MAX here?

Copy link
Member Author

Choose a reason for hiding this comment

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

NANOCOAP_QS_MAX definition goes away in nanocoap.h.

Copy link
Member

Choose a reason for hiding this comment

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

Why not keep NANOCOAP_QS_MAX and use it here? To me it makes sense to separate these two defines, even if they have the same value.

Copy link
Member Author

Choose a reason for hiding this comment

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

I am inclined to leave as-is until we have a reason to differentiate max length of query string. Why add a constant we don't need? The use is internal/invisible to the user, so we can add it whenever necessary.

Copy link
Member

Choose a reason for hiding this comment

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

To me it feels as if the define is forcefully removed with this PR while there was still a use case for the define. For me defines are a way to make code more readable by giving a meaning to a constant.

Using the NANOCOAP_URI_MAX define here where the use case is not to fix the size of a uri array feels dirty.

So my opinion would be to keep the NANOCOAP_QS_MAX, maybe define the value as NANOCOAP_URI_MAX, but to at least keep it here for clarity reasons.

Copy link
Member Author

Choose a reason for hiding this comment

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

I understand your motivation. I removed the macro because nanocoap removed it from generic use in #8772, and left if for gcoap for historical reasons. I just pushed a fixup for gcoap only, as it was before this PR. We can reinstate NANOCOAP_QS_MAX generically for nanocoap when we work on merging #8920.

size_t key_len = strlen(key);
size_t val_len = (val) ? (strlen(val) + 1) : 0;

/* make sure if url_len + the new query string fit into the url buffer */
if ((qs_len + key_len + val_len + 2) >= NANOCOAP_QS_MAX) {
if ((key_len + val_len + 2) >= NANOCOAP_URI_MAX) {
Copy link
Member

Choose a reason for hiding this comment

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

Could you please add a comment what the + 2 here is for. The NULL terminator and something else I'm missing I guess :)

Copy link
Member Author

Choose a reason for hiding this comment

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

Actually it's the query punctuation, but yes, let's describe the magic.

* length in the buffer. Allows us to reconstruct buffer length later. */
pdu->payload_len = len - (pdu->payload - buf);
pdu->content_type = COAP_FORMAT_NONE;
unsigned header_len = sizeof(coap_hdr_t) + coap_get_token_len(pdu);
Copy link
Member

Choose a reason for hiding this comment

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

This looks like a coap_get_total_hdr_len(pdu);

Copy link
Member Author

Choose a reason for hiding this comment

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

I agree. It looks like I don't even need the header_len variable itself. I'll take a closer look.


pdu->options_len = 0;
pdu->payload = buf + header_len;
pdu->payload_len = len - (pdu->payload - buf);
Copy link
Member

Choose a reason for hiding this comment

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

pdu->payload - buf is equal to header_len right?

Copy link
Member Author

Choose a reason for hiding this comment

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

That looks right to me. I'll work to simplify this section.

coap_pkt_init(pdu, buf, len, hdrlen);
coap_opt_add_string(pdu, COAP_OPT_URI_PATH, path, '/');
/* placeholder until gcoap_finish() */
coap_opt_add_uint(pdu, COAP_OPT_CONTENT_FORMAT, COAP_FORMAT_NO_PAYLOAD);
Copy link
Member

Choose a reason for hiding this comment

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

Is this to guarantee space for the content format in the buffer?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, I'll make that clearer.

@@ -769,12 +675,68 @@ int gcoap_req_init(coap_pkt_t *pdu, uint8_t *buf, size_t len,

ssize_t gcoap_finish(coap_pkt_t *pdu, size_t payload_len, unsigned format)
{
/* reconstruct full PDU buffer length */
size_t len = pdu->payload_len + (pdu->payload - (uint8_t *)pdu->hdr);
unsigned format_offset = UINT_MAX;
Copy link
Member

Choose a reason for hiding this comment

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

The use of this variable confuses me. It looks to me as if it is only used to remember if there was a content-format option

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, that's right. I will generally add more comments to make the logic in gcoap_finish() clearer. This tortured nature of this code is why I plan to deprecate gcoap_finish() in favor of gcoap_opt_format_finish(), which is called after all options have been entered but before the payload has been written. See API Options page for details.

if (format == COAP_FORMAT_NONE) {
if (!move_pos) {
move_pos = (uint8_t *)pdu->hdr + pdu->options[i].offset;
}
Copy link
Member

Choose a reason for hiding this comment

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

These snippet of 3 lines is in both branches of the if. Is it possible to move it outside of the if statement

Copy link
Member Author

Choose a reason for hiding this comment

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

I agree -- looks like an oversight.

uint8_t *move_pos = 0; /* buffer position to move forward */

/* Remove or adjust Content-Format option for request, if any.
* Assumes current payload format is COAP_FORMAT_NO_PAYLOAD */
Copy link
Member

Choose a reason for hiding this comment

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

I had a hard time understanding the code below. Maybe some additional comments would help the next person. Something like:

/* Remove or adjust Content-Format option for request, if any.
 * Assumes current payload format is COAP_FORMAT_NO_PAYLOAD
 * First the content format is updated and the option size difference is
 * stored in len_delta. Then the Option array is updated. Finally the options as 
 * placed in the buffer are moved to their updated position (offset) */

Feel free to adjust to your liking

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, as I described in a reply above.

@kb2ma
Copy link
Member Author

kb2ma commented Jun 14, 2018

Thanks for the detailed review, @bergzand! I plan to implement the adjustments above soon.

@kb2ma
Copy link
Member Author

kb2ma commented Jun 26, 2018

Added fixups, except for a couple of items with replies above.

@kb2ma
Copy link
Member Author

kb2ma commented Jun 27, 2018

Addressed latest comments, including a fixup.

@kb2ma
Copy link
Member Author

kb2ma commented Jul 2, 2018

I plan to rebase on #9474. Actually I have rebased locally with no conflicts. I'd like to test a little to be sure there are no regressions.

@kb2ma kb2ma force-pushed the gcoap/use_opt_add_api branch 2 times, most recently from c03b533 to 0078e6d Compare July 3, 2018 04:57
@kb2ma
Copy link
Member Author

kb2ma commented Jul 3, 2018

Rebased; tests OK.

@kb2ma
Copy link
Member Author

kb2ma commented Nov 22, 2018

Thanks, @haukepetersen. Let me know your reactions on GCOAP_X_OPTIONS_BUF and any concerns about the change to the assertion check in gcoap_finish().

@haukepetersen
Copy link
Contributor

done.

@kb2ma
Copy link
Member Author

kb2ma commented Nov 22, 2018

Rebased on master for #10223.

@kb2ma
Copy link
Member Author

kb2ma commented Nov 23, 2018

All comments addressed.

@kb2ma kb2ma removed the State: waiting for other PR State: The PR requires another PR to be merged first label Nov 23, 2018
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.

Nothing to add -> ACK

@haukepetersen
Copy link
Contributor

feel free to squash :-)

@kb2ma
Copy link
Member Author

kb2ma commented Nov 26, 2018

Done, and all code bits accounted for!

@haukepetersen
Copy link
Contributor

@bergzand:

@haukepetersen Feel free to dismiss my review if it is blocking

done that :-)

@haukepetersen haukepetersen dismissed bergzand’s stale review November 26, 2018 10:11

quote "@haukepetersen Feel free to dismiss my review if it is blocking"

@haukepetersen
Copy link
Contributor

now let's see what Murdock is saying, but seems we are pretty much ready to go (fingers crossed).

@haukepetersen
Copy link
Contributor

all green -> let's go!

@haukepetersen haukepetersen merged commit b603c29 into RIOT-OS:master Nov 26, 2018
@kb2ma
Copy link
Member Author

kb2ma commented Nov 26, 2018

That was a big one. Thanks @haukepetersen and @bergzand!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area: CoAP Area: Constrained Application Protocol implementations Area: network Area: Networking CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR Process: API change Integration Process: PR contains or issue proposes an API change. Should be handled with care. Reviewed: 1-fundamentals The fundamentals of the PR were reviewed according to the maintainer guidelines 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.

4 participants