Commit 9cdc1bb9 authored by Robert Lubos's avatar Robert Lubos Committed by Christopher Friedt
Browse files

net: sockets: tls: Fix TLS POLLHUP notification



The `poll()` function did not report POLLHUP if the peer ended the DTLS
session, making it impossible to detect such event on the application
side.

On the other hand, TLS erroneusely reported POLLHUP along with each
POLLIN event, as the 0 returned by the `recv()` socket call was
wrongly interpreted (it was expected to get 0 in return as 0 bytes were
requested).

Fix this by introducing a helper function to process the mbedtls context
and verify if new application data is pendingi or session has ended.
Use this new function in the poll handler, instead of a socket `recv()`
call, to remove any ambiguity in the usage, for both TLS and DTLS.

Signed-off-by: default avatarRobert Lubos <robert.lubos@nordicsemi.no>
parent d0affeff
Loading
Loading
Loading
Loading
+46 −7
Original line number Diff line number Diff line
@@ -2034,6 +2034,42 @@ exit:
	return ret;
}

static int ztls_socket_data_check(struct tls_context *ctx)
{
	int ret;

	ctx->flags = ZSOCK_MSG_DONTWAIT;

	ret = mbedtls_ssl_read(&ctx->ssl, NULL, 0);
	if (ret < 0) {
		if (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) {
			/* Don't reset the context for STREAM socket - the
			 * application needs to reopen the socket anyway, and
			 * resetting the context would result in an error instead
			 * of 0 in a consecutive recv() call.
			 */
			if (ctx->type == SOCK_DGRAM) {
				ret = tls_mbedtls_reset(ctx);
				if (ret != 0) {
					return -ENOMEM;
				}
			}

			return -ENOTCONN;
		}

		if (ret == MBEDTLS_ERR_SSL_WANT_READ ||
		    ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
			return 0;
		}

		/* Treat any other error as fatal. */
		return -EIO;
	}

	return mbedtls_ssl_get_bytes_avail(&ctx->ssl);
}

static int ztls_poll_update_pollin(int fd, struct tls_context *ctx,
				   struct zsock_pollfd *pfd)
{
@@ -2056,17 +2092,20 @@ static int ztls_poll_update_pollin(int fd, struct tls_context *ctx,
		goto next;
	}

	ret = zsock_recv(fd, NULL, 0, ZSOCK_MSG_DONTWAIT);
	if (ret == 0 && ctx->type == SOCK_STREAM) {
	ret = ztls_socket_data_check(ctx);
	if (ret == -ENOTCONN) {
		/* Datagram does not return 0 on consecutive recv, but an error
		 * code, hence clear POLLIN.
		 */
		if (ctx->type == SOCK_DGRAM) {
			pfd->revents &= ~ZSOCK_POLLIN;
		}
		pfd->revents |= ZSOCK_POLLHUP;
		goto next;
	/* EAGAIN might happen during or just after DTLS  handshake. */
	} else if (ret < 0 && errno != EAGAIN) {
	} else if (ret < 0) {
		pfd->revents |= ZSOCK_POLLERR;
		goto next;
	}

	if (mbedtls_ssl_get_bytes_avail(&ctx->ssl) == 0) {
	} else if (ret == 0) {
		goto again;
	}