-
Notifications
You must be signed in to change notification settings - Fork 2.1k
gcoap: Send separate response #14395
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
base: master
Are you sure you want to change the base?
gcoap: Send separate response #14395
Conversation
This generalizes the existing code for answering CoAP pings into general message-layer responses. Such responses are now also sent as a reaction to CON responses, which can otherwise follow the same code path as existing other responses. As a side effect, issues that would crop up when responding to odd empty requests that have token length set are resolved. Contributes-To: RIOT-OS#14169
Simplify the code path and give consistent debug messages.
The actual implementation will follow in a separate commit, this does the groundwork and sets the intention.
This introduces an additional state to the COAP_MEMO_* series to avoid enlarging the memo struct needlessly. While they are documented publicly, practically only the COAP_MEMO_TIMEOUT and COAP_MEMO_RESPONSE are used in communication with the application, as a gcoap_request_memo_t is only handed out in that state.
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.
Just a few minor remarks, since this PR is still in draft state. Do you envision the current design choice (separate responses on application level) to be merged, or would you work on a tighter integration with gcoap?
static ssize_t _riot_board_handler_blocking(coap_pkt_t *pdu, uint8_t *buf, size_t len, void *ctx) | ||
{ | ||
(void)ctx; | ||
gcoap_resp_init(pdu, buf, len, COAP_CODE_CONTENT); | ||
coap_opt_add_format(pdu, COAP_FORMAT_TEXT); | ||
size_t resp_len = coap_opt_finish(pdu, COAP_OPT_FINISH_PAYLOAD); | ||
|
||
xtimer_sleep(3); | ||
|
||
/* write the RIOT board name in the response buffer */ | ||
if (pdu->payload_len >= strlen(RIOT_BOARD)) { | ||
memcpy(pdu->payload, RIOT_BOARD, strlen(RIOT_BOARD)); | ||
return resp_len + strlen(RIOT_BOARD); | ||
} | ||
else { | ||
puts("gcoap_cli: msg buffer too small"); | ||
return gcoap_response(pdu, buf, len, COAP_CODE_INTERNAL_SERVER_ERROR); | ||
} | ||
} |
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 code is almost identical to the handler in https://github.com/RIOT-OS/RIOT/pull/14395/files#diff-1ad46e1aa545fa54a91a5563e03a4ee8R220. The only addition is the sleep call .. can we deduplicate?
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.
Probably, yes -- but this now serves primarily for demonstration during development, we may want to have different examples anyway on the long run.
*/ | ||
pdu->hdr = (coap_hdr_t *)buf; | ||
|
||
/* generate token */ |
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.
/* generate token */ | |
/* generate message id */ |
?
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 (but I'm not pulling it in yet as this is from copy-pasting, so there's another occurrence somewhere...)
pdu->hdr = (coap_hdr_t *)buf; | ||
|
||
/* generate token */ | ||
uint16_t msgid = 4; /* FIXME determined by random dice roll as we can't access gcoap internals */ |
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.
Would we need to expose the message id generation code in gcoap in order to fix this later? Then again, if we move the separate response generation into gcoap (if we decide to), then we do not need this line here anymore.
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, and that's one of the open items. I don't expect gcoap to handle all of the separate response process as a framework, but we may instead of exposing the msgid-take-and-increment have a "prepare header with a new message ID"-ish function.
puts("gcoap_cli: msg buffer too small"); | ||
pdu->hdr->code = COAP_CODE_INTERNAL_SERVER_ERROR; | ||
/* unwinding the TEXXT option*/ | ||
resp_len = resp_len - 1; |
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.
Hmm, this is not very intuitive .. could you also add something along the lines:
/* ... unwinding the TEXT option added by coap_opt_finish(..., COAP_OPT_FINISH_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 think it's even wrong; as opt_finish adds one byte payload marker and there's another something to unwind from the coap_opt_add_format, it's gotta be more.
The better thing to do would be to get (extract, or better add a function to expose) the length that coap_opt_finish(pdu, COAP_OPT_FINISH_NO_PAYLOAD)
would return at the current stage of writing, and store that to roll back.
I think it's best if that stays an application choice. Those applications that take longer (than, say, a few milliseconds) to prepare their response need to hand off request processing to their own thread anyway, lest they block gcoap and thus any coap processing completely. (This is different from the large computer situation where the coap server would run on threads or async tasks, and messages would be processed concurrently with the handler). This is not ideal, but a consequence of how gcoap handles things. (Some automagic would make sense in a completely different CoAP server where requests are processed into IPC messages and handed to a thread that's not the server for processing, but gcoap is not such a server). |
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. If you want me to ignore this issue, please mark it with the "State: don't stale" label. Thank you for your contributions. |
Is this PR still active and if yes, what remains to be done? I would be interested in this feature. |
Is this PR still active and if yes, what remains to be done? I would
be interested in this feature.
Active yes, not sure off my head what's missing (probably guidance as to
how to actually do this as a server when you're not very deep inside the
stack anyway) -- sorry, am currently in a completely different project.
Do you have a use case that could be used to shape the guidance to
users?
|
Great! I think I don't have a very good use case - a blocking call is fine, only an empty ACK needs to be sent before processing. (Before I saw the PR I had the idea that the ACK could be sent before the actual handler is already called, to take some work from the application and to make sure it is sent as soon as possible). |
Yeah, a way for the application to say that this is gonna take a while,
to send an empty ack and to block in the handler until a result is ready
is probably a useful thing.
(It's not the *best* thing, as any other requests coming in during that
time do not get the same benefit, but then again it is an improvement
over the current situation, and probably good enough for many a case).
|
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. If you want me to ignore this issue, please mark it with the "State: don't stale" label. Thank you for your contributions. |
Thanks for the reminder stalebot, I'll see when I can continue here. |
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. If you want me to ignore this issue, please mark it with the "State: don't stale" label. Thank you for your contributions. |
This will need porting to ztimer. |
Contribution description
This is currently a first sketch to get separate responses working, and will be evolved along the outline of #14393 later on.
Right now it is just application code (doing things manually), and while most of the following work will be finding suitable helpers to make that cleaner, the two wrong parts here are:
Testing procedure
Run the gcoap example as a server. From a client, GET the
/riot/board+block
and/riot/board+nonblock
resources. (For now, running this more than two times in a row will fill up the retransmission buffers; that can be mitigated by enhancements to #14178 later.)From a second client, GET
/riot/board
while one of the long-running requests is pending and observe that while the nonblocking is being requested, that new request can still be served. Request nonblocking in the same situation to see that this application limits the concurrent blocking requests to 1 with a 5.03 response.Issues/PRs references
Requires: #14178
Closes: #14393