From 091f6e6354a25a1d1d413f611b99077f76fcceb5 Mon Sep 17 00:00:00 2001 From: David Guillen Fandos Date: Thu, 3 Dec 2020 21:43:47 +0100 Subject: [PATCH] Improving Wifi API and connman implementation This sets the ground for more PRs to come. Clean up how scanning and listing SSID works, and adds attributes to the newtworks. Frontend will be able to know which networks are "remembered" and thus require no password to re-connect. For now scans are performed every 2 minutes or on demand if no networks found (either for real or in the "cache"). --- menu/menu_displaylist.c | 25 ++++--- retroarch.c | 4 +- wifi/drivers/connmanctl.c | 146 ++++++++++++++------------------------ wifi/wifi_driver.h | 20 +++++- 4 files changed, 84 insertions(+), 111 deletions(-) diff --git a/menu/menu_displaylist.c b/menu/menu_displaylist.c index 49ab3b0c17..a56e67c98b 100644 --- a/menu/menu_displaylist.c +++ b/menu/menu_displaylist.c @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -4527,7 +4528,7 @@ static void wifi_scan_callback(retro_task_t *task, { unsigned i; file_list_t *file_list = NULL; - struct string_list *ssid_list = NULL; + wifi_network_scan_t *scan = NULL; const char *path = NULL; const char *label = NULL; @@ -4543,21 +4544,19 @@ static void wifi_scan_callback(retro_task_t *task, file_list = menu_entries_get_selection_buf_ptr(0); menu_entries_ctl(MENU_ENTRIES_CTL_CLEAR, file_list); - ssid_list = string_list_new(); + scan = driver_wifi_get_ssids(); + if (!scan) + return; - driver_wifi_get_ssids(ssid_list); - - for (i = 0; i < ssid_list->size; i++) + for (i = 0; i < RBUF_LEN(scan->net_list); i++) { - const char *ssid = ssid_list->elems[i].data; + const char *ssid = scan->net_list[i].ssid; menu_entries_append_enum(file_list, ssid, msg_hash_to_str(MENU_ENUM_LABEL_CONNECT_WIFI), MENU_ENUM_LABEL_CONNECT_WIFI, MENU_WIFI, 0, 0); } - - string_list_free(ssid_list); } #endif @@ -5459,17 +5458,17 @@ unsigned menu_displaylist_build_list( settings_t *settings = config_get_ptr(); if (!string_is_equal(settings->arrays.wifi_driver, "null")) { - struct string_list *ssid_list = string_list_new(); - driver_wifi_get_ssids(ssid_list); + wifi_network_scan_t *scan = driver_wifi_get_ssids(); - if (ssid_list->size == 0) + /* Temporary hack: scan periodically, until we have a submenu */ + if (!scan || RBUF_LEN(scan->net_list) == 0 || time(NULL) > scan->scan_time + 120) task_push_wifi_scan(wifi_scan_callback); else { unsigned i; - for (i = 0; i < ssid_list->size; i++) + for (i = 0; i < RBUF_LEN(scan->net_list); i++) { - const char *ssid = ssid_list->elems[i].data; + const char *ssid = scan->net_list[i].ssid; if (menu_entries_append_enum(list, ssid, msg_hash_to_str(MENU_ENUM_LABEL_CONNECT_WIFI), diff --git a/retroarch.c b/retroarch.c index b042e381d4..44d7b25c2d 100644 --- a/retroarch.c +++ b/retroarch.c @@ -18937,10 +18937,10 @@ void driver_wifi_scan(void) p_rarch->wifi_driver->scan(p_rarch->wifi_data); } -void driver_wifi_get_ssids(struct string_list* ssids) +wifi_network_scan_t* driver_wifi_get_ssids() { struct rarch_state *p_rarch = &rarch_st; - p_rarch->wifi_driver->get_ssids(p_rarch->wifi_data, ssids); + return p_rarch->wifi_driver->get_ssids(p_rarch->wifi_data); } bool driver_wifi_ssid_is_online(unsigned i) diff --git a/wifi/drivers/connmanctl.c b/wifi/drivers/connmanctl.c index 97cb1c1daf..5bc83dcded 100644 --- a/wifi/drivers/connmanctl.c +++ b/wifi/drivers/connmanctl.c @@ -15,6 +15,8 @@ #include #include +#include +#include #include #include #include @@ -29,9 +31,7 @@ typedef struct { - bool connman_cache[64]; - unsigned connman_counter; - struct string_list* lines; + wifi_network_scan_t scan; char command[256]; bool connmanctl_widgets_supported; } connman_t; @@ -47,6 +47,9 @@ static void *connmanctl_init(void) static void connmanctl_free(void *data) { + connman_t *connman = (connman_t*)data; + if (connman->scan.net_list) + RBUF_FREE(connman->scan.net_list); if (data) free(data); } @@ -164,15 +167,12 @@ static void connmanctl_tether_toggle( static void connmanctl_scan(void *data) { char line[512]; - union string_list_elem_attr attr; FILE *serv_file = NULL; settings_t *settings = config_get_ptr(); connman_t *connman = (connman_t*)data; - attr.i = RARCH_FILETYPE_UNSET; - if (connman->lines) - free(connman->lines); - connman->lines = string_list_new(); + if (connman->scan.net_list) + RBUF_FREE(connman->scan.net_list); if (connmanctl_tether_status(connman)) { @@ -195,74 +195,61 @@ static void connmanctl_scan(void *data) serv_file = popen("connmanctl services", "r"); while (fgets(line, 512, serv_file)) { + int i; + struct string_list* list = NULL; + wifi_network_info_t entry; size_t len = strlen(line); if (len > 0 && line[len-1] == '\n') line[--len] = '\0'; - string_list_append(connman->lines, line, attr); + /* Parse lines directly and store net info directly */ + memset(&entry, 0, sizeof(entry)); + entry.connected = (line[2] == 'R' || line[2] == 'O'); + entry.saved_password = (line[0] == '*'); + + /* connmanctl services outputs a 4 character prefixed lines, + * either whitespace or an identifier. i.e.: + * $ connmanctl services + * '*A0 SSID some_unique_id' + * ' SSID some_another_unique_id' + */ + list = string_split(&line[4], " "); + if (!list) + break; + + if (list->size == 0) + continue; + + for (i = 0; i < list->size-1; i++) + { + strlcat(entry.ssid, list->elems[i].data, sizeof(entry.ssid)-1); + strlcat(entry.ssid, " ", sizeof(entry.ssid)-1); + } + /* Store the connman network id here, for later */ + strlcpy(entry.netid, list->elems[list->size-1].data, sizeof(entry.netid)-1); + string_list_free(list); + + /* Filter only wifi nets */ + if (!strncmp(entry.netid, "wifi_", 5)) + RBUF_PUSH(connman->scan.net_list, entry); } + + connman->scan.scan_time = time(NULL); pclose(serv_file); } -static void connmanctl_get_ssids(void *data, struct string_list* ssids) +static wifi_network_scan_t* connmanctl_get_ssids(void *data) { unsigned i; - union string_list_elem_attr attr; - attr.i = RARCH_FILETYPE_UNSET; connman_t *connman = (connman_t*)data; - if (!connman->lines) - return; - - for (i = 0; i < connman->lines->size; i++) - { - char ssid[32]; - const char *line = connman->lines->elems[i].data; - - strlcpy(ssid, line+4, sizeof(ssid)); - string_list_append(ssids, ssid, attr); - } + return &connman->scan; } static bool connmanctl_ssid_is_online(void *data, unsigned i) { - char ln[512] = {0}; - char service[128] = {0}; connman_t *connman = (connman_t*)data; - const char *line = connman->lines->elems[i].data; - FILE *command_file = NULL; - - if (connman->connman_counter >= 64) - { - static struct string_list* list = NULL; - connman->connman_counter = 0; - list = string_split(line, " "); - if (!list) - return false; - - if (list->size == 0) - { - string_list_free(list); - return false; - } - - strlcpy(service, list->elems[list->size-1].data, sizeof(service)); - string_list_free(list); - - snprintf(connman->command, sizeof(connman->command), "\ - connmanctl services %s | grep 'State = \\(online\\|ready\\)'", - service); - - command_file = popen(connman->command, "r"); - connman->connman_cache[i] = (fgets(ln, 512, command_file)); - pclose(command_file); - } - else - { - connman->connman_counter++; - } - - return connman->connman_cache[i]; + return connman->scan.net_list[i].connected; } static bool connmanctl_connect_ssid( @@ -270,46 +257,19 @@ static bool connmanctl_connect_ssid( { unsigned i; char ln[512] = {0}; - char name[64] = {0}; - char service[128] = {0}; char settings_dir[PATH_MAX_LENGTH] = {0}; char settings_path[PATH_MAX_LENGTH] = {0}; FILE *command_file = NULL; FILE *settings_file = NULL; connman_t *connman = (connman_t*)data; - const char *line = connman->lines->elems[idx].data; + wifi_network_info_t *netinfo = &connman->scan.net_list[idx]; settings_t *settings = config_get_ptr(); static struct string_list* list = NULL; #ifdef HAVE_GFX_WIDGETS bool widgets_active = connman->connmanctl_widgets_supported; #endif - /* connmanctl services outputs a 4 character prefixed lines, - * either whitespace or an identifier. i.e.: - * $ connmanctl services - * '*A0 SSID some_unique_id' - * ' SSID some_another_unique_id' - */ - list = string_split(line+4, " "); - if (!list) - return false; - - if (list->size == 0) - { - string_list_free(list); - return false; - } - - for (i = 0; i < list->size-1; i++) - { - strlcat(name, list->elems[i].data, sizeof(name)); - strlcat(name, " ", sizeof(name)); - } - strlcpy(service, list->elems[list->size-1].data, sizeof(service)); - - string_list_free(list); - strlcat(settings_dir, LAKKA_CONNMAN_DIR, sizeof(settings_dir)); - strlcat(settings_dir, service, sizeof(settings_dir)); + strlcat(settings_dir, netinfo->netid, sizeof(settings_dir)); path_mkdir(settings_dir); @@ -317,12 +277,12 @@ static bool connmanctl_connect_ssid( strlcat(settings_path, "/settings", sizeof(settings_path)); settings_file = fopen(settings_path, "w"); - fprintf(settings_file, "[%s]\n", service); - fprintf(settings_file, "Name=%s\n", name); + fprintf(settings_file, "[%s]\n", netinfo->netid); + fprintf(settings_file, "Name=%s\n", netinfo->ssid); fprintf(settings_file, "SSID="); - for (i = 0; i < strlen(name); i++) - fprintf(settings_file, "%02x", (unsigned int) name[i]); + for (i = 0; i < strlen(netinfo->ssid); i++) + fprintf(settings_file, "%02x", (unsigned int) netinfo->ssid[i]); fprintf(settings_file, "\n"); fprintf(settings_file, "Favorite=%s\n", "true"); @@ -345,7 +305,7 @@ static bool connmanctl_connect_ssid( snprintf(connman->command, sizeof(connman->command), "\ connmanctl connect %s 2>&1", - service); + netinfo->netid); command_file = popen(connman->command, "r"); diff --git a/wifi/wifi_driver.h b/wifi/wifi_driver.h index da9c531b7e..11ab811fda 100644 --- a/wifi/wifi_driver.h +++ b/wifi/wifi_driver.h @@ -22,7 +22,6 @@ #include #include -#include RETRO_BEGIN_DECLS @@ -41,6 +40,21 @@ enum rarch_wifi_ctl_state RARCH_WIFI_CTL_INIT }; +typedef struct wifi_network_info +{ + char ssid[33]; + bool connected; + bool saved_password; + char netid[160]; /* Do not use, internal */ + /* TODO Add signal strength & other info */ +} wifi_network_info_t; + +typedef struct wifi_network_scan +{ + time_t scan_time; + wifi_network_info_t *net_list; /* This is an rbuf array */ +} wifi_network_scan_t; + typedef struct wifi_driver { void *(*init)(void); @@ -51,7 +65,7 @@ typedef struct wifi_driver void (*stop)(void *data); void (*scan)(void *data); - void (*get_ssids)(void *data, struct string_list *list); + wifi_network_scan_t* (*get_ssids)(void *data); bool (*ssid_is_online)(void *data, unsigned i); bool (*connect_ssid)(void *data, unsigned i, const char* passphrase); void (*tether_start_stop)(void *data, bool start, char* configfile); @@ -78,7 +92,7 @@ bool driver_wifi_start(void); void driver_wifi_scan(void); -void driver_wifi_get_ssids(struct string_list *list); +wifi_network_scan_t* driver_wifi_get_ssids(); bool driver_wifi_ssid_is_online(unsigned i);