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: Confirmable request with piggybacked ACK response #7337

Merged
merged 5 commits into from
Jan 16, 2018

Conversation

kb2ma
Copy link
Member

@kb2ma kb2ma commented Jul 10, 2017

This PR implements the third step in the confirmable messaging plan in #7192, and depends on #7336. The goal is to use the extended attributes in the request memo to send a confirmable request, including resends on timeout.

Presently, the PR sends the confirmable request using the extended attributes, including a buffer to store the PDU. The next steps are to validate the received response code and type, and then to resend on timeout.

@kb2ma kb2ma changed the title net/gcoap: WIP for confirmable piggybacked ACK request net/gcoap: WIP for confirmable request with piggybacked ACK response Jul 10, 2017
@kb2ma kb2ma mentioned this pull request Jul 10, 2017
6 tasks
@aabadie aabadie modified the milestone: Release 2017.10 Jul 12, 2017
@kb2ma kb2ma force-pushed the gcoap/confirm_piggy_client branch from 15e7d3f to 20065c1 Compare July 25, 2017 22:27
@kb2ma kb2ma changed the title net/gcoap: WIP for confirmable request with piggybacked ACK response net/gcoap: Confirmable request with piggybacked ACK response Aug 15, 2017
@kb2ma
Copy link
Member Author

kb2ma commented Aug 15, 2017

No longer WIP. I plan to rebase ASAP.

@kb2ma kb2ma force-pushed the gcoap/confirm_piggy_client branch from fc8cd9f to e46d9c8 Compare August 18, 2017 04:11
@kb2ma
Copy link
Member Author

kb2ma commented Aug 18, 2017

Rebased. This PR is a pretty significant milestone for gcoap, and I look forward to getting it merged.

@smlng smlng added Type: enhancement The issue suggests enhanceable parts / The PR enhances parts of the codebase / documentation Area: network Area: Networking State: waiting for other PR State: The PR requires another PR to be merged first labels Oct 14, 2017
if (!_coap_state.resend_bufs[i*GCOAP_PDU_BUF_SIZE]) {
memo->msg.data.pdu_buf = &_coap_state.resend_bufs[i*GCOAP_PDU_BUF_SIZE];
memcpy(memo->msg.data.pdu_buf, buf, GCOAP_PDU_BUF_SIZE);
memo->msg.data.pdu_len = len;
Copy link
Member

@nmeum nmeum Nov 3, 2017

Choose a reason for hiding this comment

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

You forgot a break; here, didn't you?

Because if gcoap found a free receive buffer it doesn't need to look for an additional one, right? This is of cause not a problem when GCOAP_RESEND_BUFS_MAX == 1 (which is the default value) but if you increase that number the code doesn't seem to work properly.

Copy link
Member Author

Choose a reason for hiding this comment

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

Right on, @nmeum! I just pushed your fix to my repository.

@smlng
Copy link
Member

smlng commented Dec 1, 2017

please rebase as #7336 is merged

@smlng smlng removed the State: waiting for other PR State: The PR requires another PR to be merged first label Dec 1, 2017
@kb2ma
Copy link
Member Author

kb2ma commented Dec 14, 2017

@smlng, I plan to rebase on #8250. Let me know of any concerns. Thanks.

@smlng
Copy link
Member

smlng commented Dec 18, 2017

please rebase with #8250 merged right now

@kb2ma
Copy link
Member Author

kb2ma commented Dec 20, 2017

Rebased; apologies for the delay. Thanks to @miri64 and @bergzand for #8268, which allowed me to run my pyexpect tests on a real board.

@smlng smlng added the CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR label Dec 20, 2017
@@ -484,6 +493,10 @@ typedef struct {
observe memos */
gcoap_observe_memo_t observe_memos[GCOAP_OBS_REGISTRATIONS_MAX];
/**< Observed resource registrations */
uint8_t resend_bufs[GCOAP_RESEND_BUFS_MAX * GCOAP_PDU_BUF_SIZE];
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 uint8_t resend_bufs[GCOAP_RESEND_BUFS_MAX][GCOAP_PDU_BUF_SIZE]?

Copy link
Member Author

Choose a reason for hiding this comment

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

Good idea, makes the intent clearer.

/* retries remaining; double timeout and resend */
else {
/* decrement send limit, and add 1 to advance the timeout */
unsigned i = COAP_MAX_RETRANSMIT - memo->send_limit-- + 1;
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 IMHO a bit ugly, I would put the decrement as a separate instruction.

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. With this update, I removed the 'decrement' comment because it's not really necessary.

else {
unsigned i = COAP_MAX_RETRANSMIT - memo->send_limit + 1;
uint32_t timeout = ((uint32_t)COAP_ACK_TIMEOUT << i) * US_PER_SEC;
timeout = random_uint32_range(timeout, timeout * COAP_RANDOM_FACTOR);
Copy link
Member

Choose a reason for hiding this comment

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

mhm, I don't like that, bc COAP_RANDOM_FACTOR is 1.5 thereby introducing floating point maths here. We know that timeout is a multiple of COAP_ACK_TIMEOUT (which is two seconds). Hence, I would rather do something like

#define COAP_TIMEOUT_VARIANCE    (500U * US_PER_MS)

uint32_t timeout = ((uint32_t)COAP_ACK_TIMEOUT << i) * US_PER_SEC;
timeout = random_uint32_range(timeout - COAP_TIMEOUT_VARIANCE, timeout + COAP_TIMEOUT_VARIANCE);

}
/* retries remaining; double timeout and resend */
else {
unsigned i = COAP_MAX_RETRANSMIT - memo->send_limit + 1;
Copy link
Member

Choose a reason for hiding this comment

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

if you put the decrement, i.e. memo->send_limit--, above this statement you can omit the + 1 at the end of this line.

Copy link
Member

Choose a reason for hiding this comment

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

I know its likely micro-optimisation, and the compiler will do that already. However, IMHO it makes the code also more readable.

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, it's fine and clear with the decrement first. I had it in my head to increase timeout first, but it doesn't matter.

gcoap_request_memo_t *memo = (gcoap_request_memo_t *)msg_rcvd.content.ptr;

/* no retries remaining */
if (memo->send_limit == GCOAP_SEND_LIMIT_NON
Copy link
Member

Choose a reason for hiding this comment

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

I would recommend to enclose each condition in parentheses to clearly separate them.

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 try to do this with new code now.

}

/* validate class and type for incoming */
switch (coap_get_code_class(&pdu)) {

Copy link
Member

Choose a reason for hiding this comment

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

remove empty line

else {
memo->state = GCOAP_MEMO_UNUSED;
DEBUG("gcoap: can't wake up mbox; no timeout for msg\n");
unsigned msg_type = (*buf & 0x30) >> 4;
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 use coap_get_type from nanocoap? Though the variable name indicates what you want here, its not clear why this works, the following should work (I hope):

unsigned msg_type = coap_get_type((coap_pkt_t *)buf);

Copy link
Member Author

@kb2ma kb2ma Jan 14, 2018

Choose a reason for hiding this comment

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

I agree my solution was not clear. Unfortunately, your suggestion generates a segfault. I wonder if the best appoach is to define a second set of inline functions with the prefix 'coap_hdr_get', like

coap_hdr_get_type((coap_hdr_t *)buf);

Leave this for future work? Just define this one function for now?

Copy link
Member

Choose a reason for hiding this comment

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

ah, buf is not a full packet, hence coap_get_type fails, i.e., reads data from where it shouldn't -> segfault.

okay than leave as is (for now).

if (memo->msg.data.pdu_buf) {
memo->send_limit = COAP_MAX_RETRANSMIT;
timeout = (uint32_t)COAP_ACK_TIMEOUT * US_PER_SEC;
timeout = random_uint32_range(timeout, timeout * COAP_RANDOM_FACTOR);
Copy link
Member

Choose a reason for hiding this comment

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

same as above, i.e., introduces floating point maths.

@smlng
Copy link
Member

smlng commented Jan 15, 2018

please squash, I'll test in the mean time, so this can go into release 2018.01 as planned.

@kb2ma
Copy link
Member Author

kb2ma commented Jan 15, 2018

Thanks! I have squashed on my local workstation. I plan to test and upload later today.

@smlng
Copy link
Member

smlng commented Jan 15, 2018

Looks like you need to rebase (again) to resolve the conflict, too.

@kb2ma
Copy link
Member Author

kb2ma commented Jan 16, 2018

Squashed and rebased.

@kb2ma
Copy link
Member Author

kb2ma commented Jan 16, 2018

The Murdock build failed after I squashed and rebased. It revealed a type issue in a debug statement on MIPS platforms. It turns out that I was expecting a size_t response from sock_udp_send(), but the function really returns an ssize_t. I created a fixup commit so you can review. I can quickly squash this on your approval.

It turns out that there are two other places in gcoap.c that expect sock_udp_send() to return a size_t, in gcoap_req_send2() and in gcoap_obs_send(). I think a fix for the return handling requires a separate PR. Let me know how you'd like to approach it.

How could this code have been wrong for so long. :-/

@smlng
Copy link
Member

smlng commented Jan 16, 2018

How could this code have been wrong for so long

well, we recently (yesterday) merged #5166 which changed the handling of debug messages, i.e., previously they were guarded by preprocessor #ifs and hence not checked if debug wasn't enabled. Now they are checked every time even if debug is disabled.

@smlng
Copy link
Member

smlng commented Jan 16, 2018

I think a fix for the return handling requires a separate PR

Yes, your minimal fixup seems to be enough to get this PR through Murdock. Anything on top, should be a separate PR.

uint32_t variance = ((uint32_t)COAP_ACK_VARIANCE << i) * US_PER_SEC;
timeout = random_uint32_range(timeout, timeout + variance);

ssize_t res2 = sock_udp_send(&_sock, memo->msg.data.pdu_buf,
Copy link
Member

Choose a reason for hiding this comment

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

maybe bytes or bytes_sent would be a better name than res2? Otherwise, looks good, please squash the fixup.

@kb2ma
Copy link
Member Author

kb2ma commented Jan 16, 2018

Thanks for the review. Fixed variable name and squashed. Travis and Murdock are happy.

Copy link
Member

@smlng smlng left a comment

Choose a reason for hiding this comment

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

Re-ACK, still I'd like to run some short tests before merge. Nevertheless, this goes into the release, thx @kb2ma for acting quickly 😄

@kb2ma
Copy link
Member Author

kb2ma commented Jan 16, 2018

I really appreciate your feedback! Very happy to uncover the bug with handling sock_udp_send(). I'll make that my next priority.

@smlng
Copy link
Member

smlng commented Jan 16, 2018

I tested and saw CON and NON request on the wire(shark), looks good to me.

@smlng smlng merged commit 50f3d6a into RIOT-OS:master Jan 16, 2018
@kb2ma kb2ma deleted the gcoap/confirm_piggy_client branch February 4, 2019 11:29
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.

4 participants