From 8211a1620751d1941b2b361b53be9ab2cc23e846 Mon Sep 17 00:00:00 2001 From: Kedar Sovani Date: Sun, 4 Feb 2018 10:02:31 +0530 Subject: [PATCH] Use esp-tls in the http2 example --- components/esp-tls/esp-tls.c | 26 +++ components/esp-tls/esp-tls.h | 3 + .../components/sh2lib/connectlib.c | 164 ------------------ .../components/sh2lib/connectlib.h | 34 ---- .../http2_request/components/sh2lib/sh2lib.c | 53 ++---- .../http2_request/components/sh2lib/sh2lib.h | 6 +- 6 files changed, 47 insertions(+), 239 deletions(-) delete mode 100644 examples/protocols/http2_request/components/sh2lib/connectlib.c delete mode 100644 examples/protocols/http2_request/components/sh2lib/connectlib.h diff --git a/components/esp-tls/esp-tls.c b/components/esp-tls/esp-tls.c index 3ed8939c07..d7599ed53b 100644 --- a/components/esp-tls/esp-tls.c +++ b/components/esp-tls/esp-tls.c @@ -7,6 +7,7 @@ #include #include +#include #include "esp-tls.h" @@ -209,3 +210,28 @@ struct esp_tls *esp_tls_conn_new(const char *hostname, int hostlen, int port, st return tls; } +static int get_port(const char *url, struct http_parser_url *u) +{ + if (u->field_data[UF_PORT].len) { + return strtol(&url[u->field_data[UF_PORT].off], NULL, 10); + } else { + if (strncmp(&url[u->field_data[UF_SCHEMA].off], "http", u->field_data[UF_SCHEMA].len) == 0) { + return 80; + } else if (strncmp(&url[u->field_data[UF_SCHEMA].off], "https", u->field_data[UF_SCHEMA].len) == 0) { + return 443; + } + } + return 0; +} + +struct esp_tls *esp_tls_conn_http_new(const char *url, struct esp_tls_cfg *cfg) +{ + /* Parse URI */ + struct http_parser_url u; + http_parser_url_init(&u); + http_parser_parse_url(url, strlen(url), 0, &u); + + /* Connect to host */ + return esp_tls_conn_new(&url[u.field_data[UF_HOST].off], u.field_data[UF_HOST].len, + get_port(url, &u), cfg); +} diff --git a/components/esp-tls/esp-tls.h b/components/esp-tls/esp-tls.h index 08cc63cf21..f921a5e6f6 100644 --- a/components/esp-tls/esp-tls.h +++ b/components/esp-tls/esp-tls.h @@ -37,6 +37,9 @@ struct esp_tls { */ struct esp_tls *esp_tls_conn_new(const char *hostname, int hostlen, int port, struct esp_tls_cfg *cfg); +/* Convenience API for HTTP URIs */ +struct esp_tls *esp_tls_conn_http_new(const char *url, struct esp_tls_cfg *cfg); + static inline ssize_t esp_tls_conn_write(struct esp_tls *tls, const char *data, size_t datalen) { return tls->write(tls, data, datalen); diff --git a/examples/protocols/http2_request/components/sh2lib/connectlib.c b/examples/protocols/http2_request/components/sh2lib/connectlib.c deleted file mode 100644 index 2fe42cbdcd..0000000000 --- a/examples/protocols/http2_request/components/sh2lib/connectlib.c +++ /dev/null @@ -1,164 +0,0 @@ -/* With adaptations by Espressif Systems - * - * Copyright (c) 2013 Tatsuhiro Tsujikawa - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "connectlib.h" - -/* Basic parser from nghttp2/examples/client.c */ -int parse_uri(struct uri *res, const char *uri) -{ - /* We only interested in https */ - size_t len, i, offset; - int ipv6addr = 0; - memset(res, 0, sizeof(struct uri)); - len = strlen(uri); - if (len < 9 || memcmp("https://", uri, 8) != 0) { - return -1; - } - offset = 8; - res->host = res->hostport = &uri[offset]; - res->hostlen = 0; - if (uri[offset] == '[') { - /* IPv6 literal address */ - ++offset; - ++res->host; - ipv6addr = 1; - for (i = offset; i < len; ++i) { - if (uri[i] == ']') { - res->hostlen = i - offset; - offset = i + 1; - break; - } - } - } else { - const char delims[] = ":/?#"; - for (i = offset; i < len; ++i) { - if (strchr(delims, uri[i]) != NULL) { - break; - } - } - res->hostlen = i - offset; - offset = i; - } - if (res->hostlen == 0) { - return -1; - } - /* Assuming https */ - res->port = 443; - if (offset < len) { - if (uri[offset] == ':') { - /* port */ - const char delims[] = "/?#"; - int port = 0; - ++offset; - for (i = offset; i < len; ++i) { - if (strchr(delims, uri[i]) != NULL) { - break; - } - if ('0' <= uri[i] && uri[i] <= '9') { - port *= 10; - port += uri[i] - '0'; - if (port > 65535) { - return -1; - } - } else { - return -1; - } - } - if (port == 0) { - return -1; - } - offset = i; - res->port = (uint16_t)port; - } - } - res->hostportlen = (size_t)(uri + offset + ipv6addr - res->host); - for (i = offset; i < len; ++i) { - if (uri[i] == '#') { - break; - } - } - if (i - offset == 0) { - res->path = "/"; - res->pathlen = 1; - } else { - res->path = &uri[offset]; - res->pathlen = i - offset; - } - return 0; -} - -int connect_to_host(const char *host, size_t hostlen, uint16_t port) -{ - int ret; - struct addrinfo hints = { - .ai_family = AF_UNSPEC, - .ai_socktype = SOCK_STREAM, - }; - - char service[6]; - snprintf(service, sizeof(service), "%u", port); - - char *use_host = calloc(1, hostlen + 1); - if (!use_host) { - return -1; - } - strncpy(use_host, host, hostlen); - - struct addrinfo *res; - ret = getaddrinfo(use_host, service, &hints, &res); - if (ret) { - free(use_host); - return -1; - } - free(use_host); - - ret = socket(res->ai_family, res->ai_socktype, res->ai_protocol); - if (ret < 0) { - goto err_freeaddr; - } - - int fd = ret; - ret = connect(fd, res->ai_addr, res->ai_addrlen); - if (ret < 0) { - goto err_freesocket; - } - - return fd; - -err_freesocket: - close(fd); -err_freeaddr: - freeaddrinfo(res); - return -1; -} - diff --git a/examples/protocols/http2_request/components/sh2lib/connectlib.h b/examples/protocols/http2_request/components/sh2lib/connectlib.h deleted file mode 100644 index 86677fd7a3..0000000000 --- a/examples/protocols/http2_request/components/sh2lib/connectlib.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2017 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -#ifndef __ESP_EXAMPLE_CONNECT_LIB_H_ -#define __ESP_EXAMPLE_CONNECT_LIB_H_ - -struct uri { - const char *host; - /* In this program, path contains query component as well. */ - const char *path; - size_t pathlen; - const char *hostport; - size_t hostlen; - size_t hostportlen; - uint16_t port; -}; - -/* connect() to a TCP host, return socket descriptor */ -int connect_to_host(const char *host, size_t hostlen, uint16_t port); - -/* Parse a URI into its components */ -int parse_uri(struct uri *res, const char *uri); - -#endif /* ! __ESP_EXAMPLE_CONNECT_LIB_H_ */ diff --git a/examples/protocols/http2_request/components/sh2lib/sh2lib.c b/examples/protocols/http2_request/components/sh2lib/sh2lib.c index ba46593f62..04817e16fb 100644 --- a/examples/protocols/http2_request/components/sh2lib/sh2lib.c +++ b/examples/protocols/http2_request/components/sh2lib/sh2lib.c @@ -21,8 +21,8 @@ #include #include #include +#include -#include "connectlib.h" #include "sh2lib.h" static const char *TAG = "sh2lib"; @@ -75,10 +75,9 @@ static int do_ssl_connect(struct sh2lib_handle *hd, int sockfd, const char *host static ssize_t callback_send_inner(struct sh2lib_handle *hd, const uint8_t *data, size_t length) { - int rv = SSL_write(hd->ssl, data, (int)length); + int rv = esp_tls_conn_write(hd->http2_tls, (const char *)data, (int)length); if (rv <= 0) { - int err = SSL_get_error(hd->ssl, rv); - if (err == SSL_ERROR_WANT_WRITE || err == SSL_ERROR_WANT_READ) { + if (rv == -SSL_ERROR_WANT_WRITE || rv == -SSL_ERROR_WANT_READ) { rv = NGHTTP2_ERR_WOULDBLOCK; } else { rv = NGHTTP2_ERR_CALLBACK_FAILURE; @@ -128,10 +127,9 @@ static ssize_t callback_recv(nghttp2_session *session, uint8_t *buf, { struct sh2lib_handle *hd = user_data; int rv; - rv = SSL_read(hd->ssl, buf, (int)length); + rv = esp_tls_conn_read(hd->http2_tls, (char *)buf, (int)length); if (rv < 0) { - int err = SSL_get_error(hd->ssl, rv); - if (err == SSL_ERROR_WANT_WRITE || err == SSL_ERROR_WANT_READ) { + if (rv == -SSL_ERROR_WANT_WRITE || rv == -SSL_ERROR_WANT_READ) { rv = NGHTTP2_ERR_WOULDBLOCK; } else { rv = NGHTTP2_ERR_CALLBACK_FAILURE; @@ -281,24 +279,10 @@ static int do_http2_connect(struct sh2lib_handle *hd) int sh2lib_connect(struct sh2lib_handle *hd, const char *uri) { memset(hd, 0, sizeof(*hd)); - - struct uri res; - /* Parse the URI */ - if (parse_uri(&res, uri) != 0) { - ESP_LOGE(TAG, "[sh2-connect] Failed to parse URI"); - return -1; - } - - /* TCP connection with the server */ - int sockfd = connect_to_host(res.host, res.hostlen, res.port); - if (sockfd < 0) { - ESP_LOGE(TAG, "[sh2-connect] Failed to connect to %s", uri); - return -1; - } - - /* SSL Connection on the socket */ - if (do_ssl_connect(hd, sockfd, res.host) != 0) { - ESP_LOGE(TAG, "[sh2-connect] SSL Handshake failed with %s", uri); + struct esp_tls_cfg tls_cfg; + tls_cfg.alpn_protos = (unsigned char *) "\x02h2"; + if ((hd->http2_tls = esp_tls_conn_http_new(uri, &tls_cfg)) == NULL) { + ESP_LOGE(TAG, "[sh2-connect] esp-tls connection failed"); goto error; } @@ -308,6 +292,9 @@ int sh2lib_connect(struct sh2lib_handle *hd, const char *uri) goto error; } + int flags = fcntl(hd->http2_tls->sockfd, F_GETFL, 0); + fcntl(hd->http2_tls->sockfd, F_SETFL, flags | O_NONBLOCK); + return 0; error: sh2lib_free(hd); @@ -320,17 +307,9 @@ void sh2lib_free(struct sh2lib_handle *hd) nghttp2_session_del(hd->http2_sess); hd->http2_sess = NULL; } - if (hd->ssl) { - SSL_free(hd->ssl); - hd->ssl = NULL; - } - if (hd->ssl_ctx) { - SSL_CTX_free(hd->ssl_ctx); - hd->ssl_ctx = NULL; - } - if (hd->sockfd) { - close(hd->sockfd); - hd->ssl_ctx = 0; + if (hd->http2_tls) { + esp_tls_conn_delete(hd->http2_tls); + hd->http2_tls = NULL; } if (hd->hostname) { free(hd->hostname); @@ -346,11 +325,13 @@ int sh2lib_execute(struct sh2lib_handle *hd) ESP_LOGE(TAG, "[sh2-execute] HTTP2 session send failed %d", ret); return -1; } + ret = nghttp2_session_recv(hd->http2_sess); if (ret != 0) { ESP_LOGE(TAG, "[sh2-execute] HTTP2 session recv failed %d", ret); return -1; } + return 0; } diff --git a/examples/protocols/http2_request/components/sh2lib/sh2lib.h b/examples/protocols/http2_request/components/sh2lib/sh2lib.h index 97095eb5af..0112768bbb 100644 --- a/examples/protocols/http2_request/components/sh2lib/sh2lib.h +++ b/examples/protocols/http2_request/components/sh2lib/sh2lib.h @@ -33,14 +33,10 @@ * @brief Handle for working with sh2lib APIs */ struct sh2lib_handle { - /* Ideally, CTX is per-program, so we could potentially take it out of this - * per-connection structure - */ - SSL_CTX *ssl_ctx; /*!< Pointer to the SSL context */ - SSL *ssl; /*!< Pointer to the SSL handle */ nghttp2_session *http2_sess; /*!< Pointer to the HTTP2 session handle */ int sockfd; /*!< Socket file descriptor */ char *hostname; /*!< The hostname we are connected to */ + struct esp_tls *http2_tls; /*!< Pointer to the TLS session handle */ }; /** Flag indicating receive stream is reset */ -- 2.40.0