Limit outstanding CON requests to NSTART per session for congestion control

https://tools.ietf.org/html/rfc7641#section-4.5

In order not to cause congestion, servers MUST strictly limit the number of
simultaneous outstanding notifications/responses that they transmit to a given
client to NSTART (1 by default; see Section 4.7 of RFC 7252 [RFC7252]).
An outstanding notification/response is either a confirmable message for which
an acknowledgement has not yet been received and whose last retransmission
attempt has not yet timed out or a non-confirmable message for which the
waiting time that results from the following rate-limiting rules has not yet
elapsed.

Delay sending of PDUs if active CON request waiting for ACK.

Do not start of another Observer unsolicited response if active CON waiting
waiting for ACK.

Display outgoing PDU if log level DEBUG or higher to help troubleshooting.

This does not fix the ratelimiting of non-confirmable messages, which
should be handled by the application.
This commit is contained in:
Jon Shallow committed 2018-07-10 14:11:32 +01:00
1 parent 92994031ea
commit ea72c3d770
3 files changed
+23 -2

No files matched your search

+1
View File
@@ -68,6 +68,7 @@ typedef struct coap_session_t {
struct coap_context_t *context; /**< session's context */
void *tls; /**< security parameters */
uint16_t tx_mid; /**< the last message id that was used in this session */
uint8_t con_active; /**< Active CON request sent */
struct coap_queue_t *sendqueue; /**< list of messages waiting to be sent */
size_t partial_write; /**< if > 0 indicates number of bytes already written from the pdu at the head of sendqueue */
uint8_t read_header[8]; /**< storage space for header of incoming message header */
+20 -2
View File
@@ -617,6 +617,9 @@ coap_session_send_pdu(coap_session_t *session, coap_pdu_t *pdu) {
default:
break;
}
if (LOG_DEBUG <= coap_get_log_level()) {
coap_show_pdu(pdu);
}
return bytes_written;
}
@@ -631,7 +634,12 @@ coap_send_pdu(coap_session_t *session, coap_pdu_t *pdu, coap_queue_t *node) {
assert(session->endpoint != NULL);
sock = &session->endpoint->sock;
}
if (pdu->type == COAP_MESSAGE_CON)
session->con_active++;
bytes_written = coap_socket_send_pdu(sock, session, pdu);
if (LOG_DEBUG <= coap_get_log_level()) {
coap_show_pdu(pdu);
}
coap_ticks(&session->last_rx_tx);
#else
@@ -682,13 +690,17 @@ coap_send_pdu(coap_session_t *session, coap_pdu_t *pdu, coap_queue_t *node) {
}
}
if (session->state != COAP_SESSION_STATE_ESTABLISHED)
if (session->state != COAP_SESSION_STATE_ESTABLISHED ||
(pdu->type == COAP_MESSAGE_CON && session->con_active >= COAP_DEFAULT_NSTART)) {
return coap_session_delay_pdu(session, pdu, node);
}
if ((session->sock.flags & COAP_SOCKET_NOT_EMPTY) &&
(session->sock.flags & COAP_SOCKET_WANT_WRITE))
return coap_session_delay_pdu(session, pdu, node);
if (pdu->type == COAP_MESSAGE_CON)
session->con_active++;
bytes_written = coap_session_send_pdu(session, pdu);
#endif /* WITH_LWIP */
@@ -901,6 +913,8 @@ coap_retransmit(coap_context_t *context, coap_queue_t *node) {
debug("** %s tid=%d: retransmission #%d\n",
coap_session_str(node->session), node->id, node->retransmit_cnt);
if (node->session->con_active)
node->session->con_active--;
bytes_written = coap_send_pdu(node->session, node->pdu, node);
if (bytes_written == COAP_PDU_DELAYED) {
@@ -934,6 +948,8 @@ coap_retransmit(coap_context_t *context, coap_queue_t *node) {
coap_handle_failed_notify(context, node->session, &token);
}
#endif /* WITHOUT_OBSERVE */
if (node->session->con_active)
node->session->con_active--;
/* And finally delete the node */
if (node->pdu->type == COAP_MESSAGE_CON && context->nack_handler)
@@ -2070,8 +2086,10 @@ coap_dispatch(coap_context_t *context, coap_session_t *session,
/* find transaction in sendqueue to stop retransmission */
coap_remove_from_queue(&context->sendqueue, session, pdu->tid, &sent);
if (session->con_active)
session->con_active--;
if (pdu->code == 0)
goto cleanup;
goto cleanup;
/* if sent code was >= 64 the message might have been a
* notification. Then, we must flag the observer to be alive
+2
View File
@@ -712,6 +712,8 @@ coap_notify_observers(coap_context_t *context, coap_resource_t *r) {
if (r->dirty == 0 && obs->dirty == 0)
/* running this resource due to partiallydirty, but this observation's notification was already enqueued */
continue;
if (obs->session->con_active >= COAP_DEFAULT_NSTART)
continue;
coap_tid_t tid = COAP_INVALID_TID;
obs->dirty = 0;