net/gcoap: Confirmable request with piggybacked ACK response#7337
net/gcoap: Confirmable request with piggybacked ACK response#7337smlng merged 5 commits intoRIOT-OS:masterfrom
Conversation
15e7d3f to
20065c1
Compare
|
No longer WIP. I plan to rebase ASAP. |
fc8cd9f to
e46d9c8
Compare
|
Rebased. This PR is a pretty significant milestone for gcoap, and I look forward to getting it merged. |
| 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; |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Right on, @nmeum! I just pushed your fix to my repository.
|
please rebase as #7336 is merged |
|
please rebase with #8250 merged right now |
3de19fd to
f396227
Compare
sys/include/net/gcoap.h
Outdated
| 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]; |
There was a problem hiding this comment.
why not uint8_t resend_bufs[GCOAP_RESEND_BUFS_MAX][GCOAP_PDU_BUF_SIZE]?
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
this looks IMHO a bit ugly, I would put the decrement as a separate instruction.
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
if you put the decrement, i.e. memo->send_limit--, above this statement you can omit the + 1 at the end of this line.
There was a problem hiding this comment.
I know its likely micro-optimisation, and the compiler will do that already. However, IMHO it makes the code also more readable.
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
I would recommend to enclose each condition in parentheses to clearly separate them.
There was a problem hiding this comment.
Yes, I try to do this with new code now.
|
|
||
| /* validate class and type for incoming */ | ||
| switch (coap_get_code_class(&pdu)) { | ||
|
|
| else { | ||
| memo->state = GCOAP_MEMO_UNUSED; | ||
| DEBUG("gcoap: can't wake up mbox; no timeout for msg\n"); | ||
| unsigned msg_type = (*buf & 0x30) >> 4; |
There was a problem hiding this comment.
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);
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
same as above, i.e., introduces floating point maths.
|
please squash, I'll test in the mean time, so this can go into release 2018.01 as planned. |
|
Thanks! I have squashed on my local workstation. I plan to test and upload later today. |
|
Looks like you need to rebase (again) to resolve the conflict, too. |
Also, create resend_bufs array to store PDU for resend.
f9cc42f to
d67dfe7
Compare
|
Squashed and rebased. |
|
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 It turns out that there are two other places in gcoap.c that expect 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 |
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, |
There was a problem hiding this comment.
maybe bytes or bytes_sent would be a better name than res2? Otherwise, looks good, please squash the fixup.
adf0a5a to
5e1d3fe
Compare
|
Thanks for the review. Fixed variable name and squashed. Travis and Murdock are happy. |
|
I really appreciate your feedback! Very happy to uncover the bug with handling |
|
I tested and saw CON and NON request on the wire(shark), looks good to me. |
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.