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

nanocoap: add server-side block2 support #8932

Merged
merged 2 commits into from
Oct 14, 2018

Conversation

bergzand
Copy link
Member

Contribution description

Making use of the new option handling and the work done by @kaspar030 with block1 support, this PR extends that to block2 support. The /.well-known/core URI is also adapted to support block2.

commit 54b275c (block2 support, not the example) adds 412 bytes to the text size of the nanocoap example on a samr21-xpro

Issues/PRs references

Depends on #8788

@bergzand bergzand added Area: network Area: Networking Type: new feature The issue requests / The PR implemements a new feature for RIOT labels Apr 11, 2018
@@ -263,6 +276,36 @@ typedef struct {
} coap_resource_t;

/**
<<<<<<< HEAD
Copy link
Contributor

Choose a reason for hiding this comment

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

mishap

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, I also noticed that I still have to squash in a bit of doxygen


/**
>>>>>>> 01c4c5265... nanocoap: Add server side block2 support
>>>>>>> nanocoap: Add server side block2 support
Copy link
Member

Choose a reason for hiding this comment

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

Another one ;-).

Copy link
Member Author

Choose a reason for hiding this comment

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

First ☕, otherwise half this PR is going to consist of me removing merge conflict indicators 😞

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 hope they're all gone now

@bergzand bergzand force-pushed the pr/nanocoap/block2 branch 2 times, most recently from 06b06dc to 31fb078 Compare April 25, 2018 13:19
@bergzand
Copy link
Member Author

bergzand commented Apr 25, 2018

Rebased because block1 support got merged.

@bergzand bergzand added the Area: CoAP Area: Constrained Application Protocol implementations label May 25, 2018
@kb2ma kb2ma mentioned this pull request Aug 20, 2018
@kb2ma
Copy link
Member

kb2ma commented Aug 23, 2018

Making progress on review. See WIP as C-style comments in code. Overall approach and structure seem fine. Right now I'm thinking about how the block payload is written.

I plan to finish the merge for #8920, and then finish this review. That PR provides examples for the naming of option functions, which I think we should follow here.

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.

As I mentioned before, I think the overall approach here makes sense. I like the switch for writing the payload contents depending on location within the overall transfer. Happy to provide more details and talk through my suggestions and comments.

sys/include/net/nanocoap.h Outdated Show resolved Hide resolved
sys/include/net/nanocoap.h Outdated Show resolved Hide resolved
sys/net/application_layer/nanocoap/nanocoap.c Outdated Show resolved Hide resolved
sys/net/application_layer/nanocoap/nanocoap.c Outdated Show resolved Hide resolved
sys/net/application_layer/nanocoap/nanocoap.c Outdated Show resolved Hide resolved
sys/net/application_layer/nanocoap/nanocoap.c Outdated Show resolved Hide resolved
sys/include/net/nanocoap.h Show resolved Hide resolved
sys/include/net/nanocoap.h Outdated Show resolved Hide resolved
sys/net/application_layer/nanocoap/nanocoap.c Outdated Show resolved Hide resolved
sys/net/application_layer/nanocoap/nanocoap.c Show resolved Hide resolved
@bergzand
Copy link
Member Author

Thanks for the review @kb2ma, I'll try to fix and rebase this PR asap.

@bergzand
Copy link
Member Author

bergzand commented Sep 1, 2018

@kb2ma I think I've fixed all of your issues besides your suggestion for a generic put_bytes. I have to take a look at that one later and see how the additional checks would change things.

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.

We're getting there. :-) I think all of the previous discussion is done except for the name/purpose of NANOCOAP_BLOCK_SZX_MAX. See the discussion.

Toward the goal of getting there, I'm OK with putting off a decision on use of 'coap_blockwise_put_xxx()' vs. 'coap_payload_put_[char|bytes]()'. coap_payload_put_xxx() is really additional to this PR rather than essential to it. The implementation of the function could probably call coap_blockwise_put_xxx() depending on whether the coap_blockbuilder_t parameter in coap_payload_put_xxx() is NULL. I can see how eventually it might be handy to have such a function, but let's see how use of block develops.

By the way, in the specific issues below, I mention use of 'coap_opt_put_xxx()' vs. 'coap_opt_add_xxx()'. I'm not asking for implementations of 'coap_opt_add_xxx()' for this PR! That's also follow-on work. ;-)

* @returns 0 if block2 option not present
* @returns 1 if structure has been filled
*/
int coap_opt_get_block2(coap_pkt_t *pkt, coap_block1_t *block2);
Copy link
Member

Choose a reason for hiding this comment

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

Actually, I thought this function name was OK as coap_get_block2(). I understand that this choice may seem confusing. You'll see that 'coap_get_block2()' is consistent with #8920. Let me explain.

I did originally think it best to include the 'opt' in all the 'get' functions. But once I started to do that, I had a hard time deciding where to stop. For example, should we use 'coap_opt_block2_init()'? Does 'coap_get_observe()' need to change to 'coap_opt_get_observe()'?

So, then I took minimalist approach -- only change what it necessary for clarity. The main necessity I see is to distinguish between building options directly with the byte array or indirectly with a coap_pkt_t. So then, use of byte array means to name the function 'coap_opt_put_xxx()', and use of the coap_pkt_t means to name the function 'coap_opt_add_xxx()'. I think others may not see this distinction as the basis for the names because we have only a few of the 'coap_opt_add_xxx()' functions. It will become clear as we add them though.

There is one additional use for a 'coap_opt' name, and that is for data-type based retrieval, like 'coap_opt_get_string()'. I think just 'coap_get_string()' would be too confusing (as in "really, any string?").

I think this confusion has helped me decide the next PR I'm going to write -- and that is to add header documentation to nanocoap.h to explain use of a byte buffer or a coap_pkt_t to build a packet. I can revive what I started in #9474.

Copy link
Member Author

Choose a reason for hiding this comment

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

So if I understand it correctly, you rather have me change this back to coap_get_block2?

Copy link
Member

Choose a reason for hiding this comment

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

Yes, please. Apologies for my contribution to any misunderstanding.

Copy link
Member Author

Choose a reason for hiding this comment

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

No worries :)

Copy link
Member

Choose a reason for hiding this comment

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

Following up on my comments above. I created #10036 with nanocoap module documentation. Might be worth a look.

Copy link
Member

Choose a reason for hiding this comment

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

Still using old name. I fixed in 7a67661.

*
* @returns amount of bytes written to @p buf
*/
size_t coap_block2_init(uint8_t* buf, uint16_t lastonum, coap_pkt_t *pkt, coap_blockbuilder_t *blk);
Copy link
Member

Choose a reason for hiding this comment

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

Now that I look more closely, I see this function needs to be refactored to work when building a message with a coap_pkt_t (coap_opt_add_xxx(), usually for gcoap) rather than a byte array (coap_opt_put_xxx()).

So, how about this declaration:
void coap_block2_init(coap_pkt_t *pkt, coap_block1_t *blk_opt, coap_blockbuilder_t *blk_builder);

The implementation of the function changes to set blknum and szx in blk_opt, and removes the call to coap_opt_put_block2(), which is incompatible with bulding a message with a coap_pkt_t.

Then, for example, coap_well_known_core_default_handler() begins like below:

    (void)context;
    coap_block1_t blk_opt;
    coap_blockbuilder_t blk_builder;
    uint8_t *payload = buf + coap_get_total_hdr_len(pkt);
    uint8_t *bufpos = payload;

    bufpos += coap_put_option_ct(bufpos, 0, COAP_CT_LINK_FORMAT);
    coap_block2_init(pkt, blk_opt, blk_builder);
    bufpos += coap_opt_put_block2(bufpos, COAP_OPT_CONTENT_FORMAT, blk_opt.blknum, blk_opt.szx);

Finally, there is not a similar compatibility problem (uint8_t* vs. coap_pkt_t) with coap_block_finish() because this function is called after the option has been added to message buffer, so we're just editing what's already there.

Copy link
Member Author

Choose a reason for hiding this comment

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

Let me try something here, I think I understand what you want and it makes sense to me.

Copy link
Member Author

Choose a reason for hiding this comment

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

@kb2ma I've reworked it to use only a coap_block_slicer_t here. It required 2 helper function which added 20 bytes of additional flash compared to previous fixup state. This prevents us from having to put that coap_block1_t struct on the stack during the full handler processing.

Please let me know if this is workable for gcoap since I didn't completely follow your instructions :)

@bergzand
Copy link
Member Author

bergzand commented Sep 3, 2018

@kb2ma What makes more sense to you, passing the individual block values (size, block number and "more") to the coap_opt_put_block2 or passing the coap_blockbuilder_t struct?

@kb2ma
Copy link
Member

kb2ma commented Sep 3, 2018

I think passing individual values makes sense at the lowest levels -- coap_get_blockopt() and coap put_option_block() (eventually to become coap_opt_put_block()). However, above that it seems more convenient to use a single coap_block1_t rather than its attributes. (I assume you meant coap_block1_t rather then coap_blockbuilder_t.)

So, yes, I think it makes more sense to pass a coap_block1_t to coap_opt_put_block2().

@kb2ma
Copy link
Member

kb2ma commented Sep 3, 2018

At the risk of you throwing things at me, would coap_block_serializer_t or coap_block_payload_t be better than coap_blockbuilder_t? I'm not asking you to change this, just thinking about the best name as my understanding evolves. [ducking and running]

@bergzand
Copy link
Member Author

At the risk of you throwing things at me, would coap_block_serializer_t or coap_block_payload_t be better than coap_blockbuilder_t? I'm not asking you to change this, just thinking about the best name as my understanding evolves. [ducking and running]

As long as this PR is not yet finalized I don't mind you suggesting new names. How about coap_block_slicer_t. I think serializer here is technically incorrect since the payload is not really transformed. I suggested slicer here since the payload is sliced into individual segments

@kb2ma
Copy link
Member

kb2ma commented Sep 21, 2018

How about coap_block_slicer_t.

+1! Nicely descriptive

@bergzand
Copy link
Member Author

+1! Nicely descriptive

Done!

Now back to the other issues remaining :)

@bergzand
Copy link
Member Author

@kb2ma I think I've fixed all your comments so far, please let me know if I skipped one.

@kb2ma
Copy link
Member

kb2ma commented Oct 3, 2018

Thanks for the update, @bergzand. I am reviewing as I write this. My goal is a concrete response as soon as possible.

*
* @returns amount of bytes written to @p buf
*/
void coap_block2_init(coap_pkt_t *pkt, coap_block_slicer_t *slicer);
Copy link
Member

Choose a reason for hiding this comment

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

Documentation out of sync with declaration. I fixed in b6b452d.

@kb2ma
Copy link
Member

kb2ma commented Oct 5, 2018

Besides the issues above, I also added module documentation in d1e999d. This documentation seems odd on its own, but I'll combine with #10036 when that's merged in the next few days. Also, I fixed some typos in c126ca8.

In the interest of time, I went ahead and pushed these fixes to @bergzand's repo. Besides, especially with coap_block2_finish() issue, writing the code helps convince yourself that it's the right thing to do. :-)

With these changes, no failures when testing. I had not really used block before this, but the design and @bergzand's implementation are well done! I used the nanocoap server example to test /.well-known/core and /riot/description. I tried adjusting the lengths of the output to catch off-by-1 problems. I tried various block lengths (16, 32, etc.).

I only tested on native, but it compiles and nanocoap server starts OK on samr21-xpro.

Let's wrap this up and get it merged! If @bergzand is OK with these fixups, from my perspective all we need is to rebase to get the new coap header file.

sys/include/net/nanocoap.h Outdated Show resolved Hide resolved
@kb2ma
Copy link
Member

kb2ma commented Oct 8, 2018

Found the issues above as I reviewed the maintainer guidelines. See #4 in @bergzand's repository. Also, added a commit based on uncrustify in 323e792.

Able to test on samr21-xpro. It works fine. Also checked executable size and found the block2 work excluding the example added 380 bytes to the text section of the executable. Max memory use for /.well-known/core did not increase according to ps(). Max memory use did increase by 68 bytes when running the /riot/description example.

My only suggestion for future work on memory/code space is to consider adding the block value to coap_block_slicer_t. This would remove the need for _size2szx() and _slicer_blknum() at the price of 4 bytes of RAM.

I'm going to check off all of the Reviewed labels now. Once we work through these changes, I'm happy to mark approved.

@kb2ma kb2ma added Reviewed: 2-code-design The code design of the PR was reviewed according to the maintainer guidelines Reviewed: 3-testing The PR was tested according to the maintainer guidelines Reviewed: 4-code-style The adherence to coding conventions by the PR were reviewed according to the maintainer guidelines CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR labels Oct 8, 2018
@kb2ma
Copy link
Member

kb2ma commented Oct 8, 2018

As @bergzand and I discussed, the block code needs some unit tests. For example, this will verify the fix for the issue with coap_get_block2(), which is not used in the nanocoap_server example. However, we agreed to add these tests in a follow-up.

@kb2ma
Copy link
Member

kb2ma commented Oct 8, 2018

Given Murdock issue, need to blacklist WSN430? Alternatively could remove the /riot/description example to free text space. Can reference coap_well_known_core_default_handler() to illustrate how to use block2.

@bergzand
Copy link
Member Author

My only suggestion for future work on memory/code space is to consider adding the block value to coap_block_slicer_t. This would remove the need for _size2szx() and _slicer_blknum() at the price of 4 bytes of RAM.

I'm not sure what the correct tradeoff is here. If I compile the example with these functions not flagged with static, they occupy 20 and 16 bytes of flash, so we're talking about trading 36B of flash for 4B of stack usage.

Given Murdock issue, need to blacklist WSN430? Alternatively could remove the /riot/description example to free text space. Can reference coap_well_known_core_default_handler() to illustrate how to use block2.

I prefer to have an as simple as possible example for this, IMHO the coap_well_known_core_default_handler() is not exactly trivial. In this case I'd prefer to blacklist the two boards, there are still other 16 bit boards that should be able to compile/run the example

@kb2ma
Copy link
Member

kb2ma commented Oct 14, 2018

I'm not sure what the correct tradeoff is here.

I agree that given the relative byte sizes of the tradeoff (RAM vs flash) it's a tough call. At least we've flagged it for future reference.

In this case I'd prefer to blacklist the two boards

It really gets into larger questions about the content of examples, and it's definitely not worth holding up this PR. For example, it would be easy enough in the future to create a 'block' app in the applications repository for /riot/ver and other uses of block. OTOH, it was definitely worthwhile to look at the flash and RAM sizes before merging.

@kb2ma
Copy link
Member

kb2ma commented Oct 14, 2018

So, I'd say were there, and just in time given the soft freeze on 10/16. :-) Please squash.

@kb2ma
Copy link
Member

kb2ma commented Oct 14, 2018

OK to blacklist the WSN boards in the squash.

@bergzand
Copy link
Member Author

So, I'd say were there, and just in time given the soft freeze on 10/16. :-) Please squash.

Squashed

OK to blacklist the WSN boards in the squash.

And added to the insufficient memory list.

@bergzand bergzand added CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR and removed CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR labels Oct 14, 2018
@kb2ma
Copy link
Member

kb2ma commented Oct 14, 2018

Thanks for the tag, @bergzand. I was just focused on waiting for Murdock to finish. :-)

@kb2ma kb2ma merged commit 14c9b30 into RIOT-OS:master Oct 14, 2018
@bergzand
Copy link
Member Author

🎉 thanks for the reviews @kb2ma!

@bergzand bergzand deleted the pr/nanocoap/block2 branch October 14, 2018 13:04
@kYc0o
Copy link
Contributor

kYc0o commented Oct 14, 2018

Yaaay!!! Thanks o everyone involved here! This feature is really really appreciated!

@jia200x
Copy link
Member

jia200x commented Oct 15, 2018

Awesome work! Thanks to everyone involved! :)

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 Reviewed: 1-fundamentals The fundamentals of the PR were reviewed according to the maintainer guidelines Reviewed: 2-code-design The code design of the PR was reviewed according to the maintainer guidelines Reviewed: 3-testing The PR was tested according to the maintainer guidelines Reviewed: 4-code-style The adherence to coding conventions by the PR were reviewed according to the maintainer guidelines Reviewed: 5-documentation The documentation details of the PR were reviewed according to the maintainer guidelines Type: new feature The issue requests / The PR implemements a new feature for RIOT
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants