-
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/gcoap: Use nanocoap pkt/options API #9156
Conversation
ecc7cc4
to
2aea999
Compare
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. |
2aea999
to
1bdc3f8
Compare
1bdc3f8
to
d047a58
Compare
Rebased and ready for review now that #9085 has been merged. |
sys/include/net/nanocoap.h
Outdated
* Not intended for use in a transmitted packet. Must be a 3-byte unsigned | ||
* value. | ||
*/ | ||
#define COAP_FORMAT_NO_PAYLOAD (65536) |
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.
Could you please right align all format values here?
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.
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); |
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.
Does it make sense to use strncmp
here with NANOCOAP_URI_MAX
as an extra safety precaution?
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_get_uri() inserts the terminator, but I agree it's better to be safe.
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.
Small note here, I'm not sure whether strncmp is in the C99 libc. (It's not the case with strnlen by default)
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.
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?
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.
Agreed, especially since it is a string build in our own functions.
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.
Perfect. I'm working up a PR in my nanocoap/test_get_uri_path branch.
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.
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]; |
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 reusing NANOCOAP_URI_MAX
and not keeping and using the NANOCOAP_QS_MAX
here?
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.
NANOCOAP_QS_MAX definition goes away in nanocoap.h.
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.
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.
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.
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.
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 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.
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.
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) { |
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.
Could you please add a comment what the + 2
here is for. The NULL
terminator and something else I'm missing I guess :)
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.
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); |
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 looks like a coap_get_total_hdr_len(pdu);
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.
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); |
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.
pdu->payload - buf
is equal to header_len
right?
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 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); |
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 to guarantee space for the content format in the buffer?
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, 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; |
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 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
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, 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; | ||
} |
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.
These snippet of 3 lines is in both branches of the if
. Is it possible to move it outside of the if
statement
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.
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 */ |
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.
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
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, as I described in a reply above.
Thanks for the detailed review, @bergzand! I plan to implement the adjustments above soon. |
f556b98
to
7eb1ec6
Compare
Added fixups, except for a couple of items with replies above. |
Addressed latest comments, including a fixup. |
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. |
c03b533
to
0078e6d
Compare
Rebased; tests OK. |
Thanks, @haukepetersen. Let me know your reactions on |
done. |
71c0269
to
cd15b97
Compare
Rebased on master for #10223. |
All comments addressed. |
Observe still uses coap_pkt_t attribute.
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.
Nothing to add -> ACK
feel free to squash :-) |
0e275f9
to
8fa6f10
Compare
Done, and all code bits accounted for! |
done that :-) |
quote "@haukepetersen Feel free to dismiss my review if it is blocking"
now let's see what Murdock is saying, but seems we are pretty much ready to go (fingers crossed). |
all green -> let's go! |
That was a big one. Thanks @haukepetersen and @bergzand! |
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.