diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..be4fa79 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "shroom-controller/components/libssh2/libssh2"] + path = shroom-controller/components/libssh2/libssh2 + url = https://github.com/libssh2/libssh2 diff --git a/shroom-controller/components/libssh2/CMakeLists.txt b/shroom-controller/components/libssh2/CMakeLists.txt new file mode 100644 index 0000000..9651504 --- /dev/null +++ b/shroom-controller/components/libssh2/CMakeLists.txt @@ -0,0 +1,10 @@ +idf_component_register( + SRC_DIRS "libssh2/src" # "libssh2/src/threads" "libssh2/src/external" + INCLUDE_DIRS "libssh2/include" + PRIV_INCLUDE_DIRS "libssh2/src" + REQUIRES "mbedtls" +) + + +# _3DS is used to have libssh2 provide its own iovec; it doesn't seem to trigger any other behavior for now +target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-error=format -Wno-error=char-subscripts -DLIBSSH2_MBEDTLS -DHAVE_SYS_SOCKET_H) diff --git a/shroom-controller/components/libssh2/libssh2 b/shroom-controller/components/libssh2/libssh2 new file mode 160000 index 0000000..a312b43 --- /dev/null +++ b/shroom-controller/components/libssh2/libssh2 @@ -0,0 +1 @@ +Subproject commit a312b43325e3383c865a87bb1d26cb52e3292641 diff --git a/shroom-controller/main/.gitignore b/shroom-controller/main/.gitignore index 455c367..3578cb3 100644 --- a/shroom-controller/main/.gitignore +++ b/shroom-controller/main/.gitignore @@ -1 +1,5 @@ wifi_private.h +shrooms-key +shrooms-key.pub +shrooms-key.o +shrooms-key.pub.o diff --git a/shroom-controller/main/CMakeLists.txt b/shroom-controller/main/CMakeLists.txt index 3feeacf..d4d870b 100644 --- a/shroom-controller/main/CMakeLists.txt +++ b/shroom-controller/main/CMakeLists.txt @@ -5,4 +5,15 @@ idf_component_register( esp_driver_gpio esp_wifi nvs_flash + libssh2 +) + +# TODO maybe add the commands to generate these? +# xtensa-esp-elf-objcopy -I binary -O elf32-xtensa-le shrooms-key shrooms-key.o +# xtensa-esp-elf-objcopy -I binary -O elf32-xtensa-le shrooms-key.pub shrooms-key.pub.o + +target_link_libraries( + ${COMPONENT_LIB} + ${CMAKE_CURRENT_SOURCE_DIR}/shrooms-key.o + ${CMAKE_CURRENT_SOURCE_DIR}/shrooms-key.pub.o ) diff --git a/shroom-controller/main/controller.c b/shroom-controller/main/controller.c new file mode 100644 index 0000000..caabde6 --- /dev/null +++ b/shroom-controller/main/controller.c @@ -0,0 +1,9 @@ +static void controller_job(void* args); + +void controller_init(void) { +} + +static void controller_job(void* args) { +} + + diff --git a/shroom-controller/main/main.c b/shroom-controller/main/main.c index 9d3fe81..fae92ad 100644 --- a/shroom-controller/main/main.c +++ b/shroom-controller/main/main.c @@ -5,12 +5,33 @@ #include "esp_wifi.h" #include "esp_wifi_default.h" +#include "freertos/FreeRTOS.h" +#include "freertos/event_groups.h" +#include "freertos/task.h" + #include "nvs_flash.h" +#include +#include +#include + +#include "libssh2.h" + #include "wifi_private.h" const char TAG[] = "main"; +// assigned to an esp timer to run after a set time +static void reconnect_job(void* arg) { + // TODO: if it's still disconnected try to reconnect +} +static void reconnect_in(int ticks_ms) { +} + +EventGroupHandle_t s_wifi_event_group; +#define WIFI_FAIL_BIT (1) +#define WIFI_CONNECTED_BIT (2) + static int s_retry_num = 0; static void event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) { @@ -22,17 +43,116 @@ static void event_handler(void* arg, esp_event_base_t event_base, s_retry_num++; ESP_LOGI(TAG, "retry to connect to the AP"); } else { - //xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT); + xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT); } ESP_LOGI(TAG,"connect to the AP fail"); } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) { ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data; ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip)); s_retry_num = 0; - //xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT); + xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT); } } +void main_task(void* args) { + + // connect via TCP here + struct addrinfo *results = 0; + + int rc = libssh2_init(0); + if (rc) { + ESP_LOGE(TAG, "libssh2 initialization failed: %d", rc); + // TODO panic + } + + while (true) { + xEventGroupWaitBits(s_wifi_event_group, WIFI_CONNECTED_BIT, 0, pdTRUE, portMAX_DELAY); + if (!(xEventGroupGetBits(s_wifi_event_group) & WIFI_CONNECTED_BIT)) { + continue; + } + + struct addrinfo hints = {}; + hints.ai_family = AF_UNSPEC; + hints.ai_socktype= SOCK_STREAM; + + ESP_LOGI(TAG, "looking up server..."); + rc = getaddrinfo("batmanbatman.local", "22", &hints, &results); + if (rc) { + ESP_LOGE(TAG, "getaddrinfo failed: %d", rc); + break; + } + + if (!results) { + ESP_LOGE(TAG, "getaddrinfo returned no results"); + // TODO sleep and try again? + break; + } + + bool connect_success = false; + libssh2_socket_t sock = LIBSSH2_INVALID_SOCKET; + for (struct addrinfo* rp = results; rp; rp = rp->ai_next) { + ESP_LOGI(TAG, "creating socket fam %d type %d proto %d", rp->ai_family, rp->ai_socktype, rp->ai_protocol); + sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); + + if (sock == LIBSSH2_INVALID_SOCKET) { + ESP_LOGE(TAG, "failed to create socket"); + continue; + } + + if (connect(sock, results->ai_addr, results->ai_addrlen) != -1) { + ESP_LOGE(TAG, "connected successfully"); + connect_success = true; + break; + } + + close(sock); + sock = LIBSSH2_INVALID_SOCKET; + } + + freeaddrinfo(results); + if (!connect_success) { + // TODO I guess sleep for a bit and retry? + break; + } + + ESP_LOGI(TAG, "connection established, creating SSH session..."); + + LIBSSH2_SESSION* session = libssh2_session_init(); + if (!session) { + ESP_LOGE(TAG, "could not create libssh2 session"); + // TODO error out + } + + libssh2_trace(session, -0); + + libssh2_session_handshake(session, sock); + + const char* fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1); + + const char username[] = "shrooms"; + extern char* _binary_shrooms_key_start; + extern size_t _binary_shrooms_key_size; + extern char* _binary_shrooms_key_pub_start; + extern size_t _binary_shrooms_key_pub_size; + + rc = libssh2_userauth_publickey_frommemory( + session, + username, + sizeof(username) - 1, + _binary_shrooms_key_pub_start, + _binary_shrooms_key_pub_size, + _binary_shrooms_key_start, + _binary_shrooms_key_size, + NULL); + + // TODO the rest of it + break; + } + + while (true); +} + + void app_main(void) { esp_err_t ret = nvs_flash_init(); if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { @@ -43,6 +163,8 @@ void app_main(void) { wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); + s_wifi_event_group = xEventGroupCreate(); + ESP_ERROR_CHECK(esp_netif_init()); ESP_ERROR_CHECK(esp_event_loop_create_default()); esp_netif_create_default_wifi_sta(); @@ -68,4 +190,9 @@ void app_main(void) { ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config)); ESP_ERROR_CHECK(esp_wifi_start()); + + if (xTaskCreate(main_task, "ssh task", 4096, NULL, 17, NULL) != pdPASS) { + ESP_LOGE(TAG, "unable to create ssh task"); + // TODO panic + } }