linuxOS_D21X/source/artinchip/wifimanager/demo/main.c
2025-08-14 15:17:16 +08:00

396 lines
9.7 KiB
C

/*
* Copyright (C) 2022-2025 ArtInChip Technology Co., Ltd.
*
* SPDX-License-Identifier: Apache-2.0
*
* Authors: lv.wu <lv.wu@artinchip.com>
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <sys/wait.h>
#include <stdint.h>
#include <sys/prctl.h>
#include <pthread.h>
#include <unistd.h>
#include "wifimanager.h"
#define LIST_NETWORK_MAX 4096
#define USER_SOCKET "/var/run/user_cb_socket"
struct cb_info {
int evt;
int buff_length;
};
static pthread_t gp_user_callback;
static int g_server_fd = -1;
static int g_cli_fd = -1;
static const char *wifistate2string(wifistate_t state)
{
switch (state) {
case WIFI_STATE_GOT_IP:
return "WIFI_STATE_GOT_IP";
case WIFI_STATE_CONNECTING:
return "WIFI_STATE_CONNECTING";
case WIFI_STATE_DHCPC_REQUEST:
return "WIFI_STATE_DHCPC_REQUEST";
case WIFI_STATE_DISCONNECTED:
return "WIFI_STATE_DISCONNECTED";
case WIFI_STATE_CONNECTED:
return "WIFI_STATE_CONNECTED";
default:
return "WIFI_STATE_ERROR";
}
}
static const char *disconn_reason2string(wifimanager_disconn_reason_t reason)
{
switch (reason) {
case AUTO_DISCONNECT:
return "wpa auto disconnect";
case ACTIVE_DISCONNECT:
return "active disconnect";
case KEYMT_NO_SUPPORT:
return "keymt is not supported";
case CMD_OR_PARAMS_ERROR:
return "wpas command error";
case IS_CONNECTTING:
return "wifi is still connecting";
case CONNECT_TIMEOUT:
return "connect timeout";
case REQUEST_IP_TIMEOUT:
return "request ip address timeout";
case WPA_TERMINATING:
return "wpa_supplicant is closed";
case AP_ASSOC_REJECT:
return "AP assoc reject";
case NETWORK_NOT_FOUND:
return "can't search such ssid";
case PASSWORD_INCORRECT:
return "incorrect password";
default:
return "other reason";
}
}
/* This callback is running in wifimanager daemon process,
* So you can't process other logic in this callback, such as UI display...
*
* It is recommended to use inter-process communication (IPC) to send the
* results of the WIFIMANAGER DAEMON to the process that needs to execute them.
*/
static void print_scan_result(char *result)
{
int fd;
struct sockaddr_un saddr = { .sun_family = AF_UNIX };
struct cb_info info;
snprintf(saddr.sun_path, sizeof(saddr.sun_path) - 1, USER_SOCKET);
if ((fd = socket(PF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0)) == -1) {
printf("client: socket alloc error\n");
return;
}
if (connect(fd, (struct sockaddr *)(&saddr), sizeof(saddr)) == -1) {
printf("client: connect error\n");
close(fd);
return;
}
info.evt = 0;
info.buff_length = strlen(result);
send(fd, &info, sizeof(struct cb_info), 0);
send(fd, result, strlen(result), 0);
close(fd);
}
/* This callback is running in wifimanager daemon process,
* So you can't process other logic in this callback, such as UI display...
*
* It is recommended to use inter-process communication (IPC) to send the
* results of the WIFIMANAGER DAEMON to the process that needs to execute them.
*/
static void print_stat_change(wifistate_t stat, wifimanager_disconn_reason_t reason)
{
int fd;
struct sockaddr_un saddr = { .sun_family = AF_UNIX };
struct cb_info info;
int buff[2];
snprintf(saddr.sun_path, sizeof(saddr.sun_path) - 1, USER_SOCKET);
if ((fd = socket(PF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0)) == -1)
printf("client: socket alloc error\n");
return;
if (connect(fd, (struct sockaddr *)(&saddr), sizeof(saddr)) == -1) {
printf("client: connect error\n");
close(fd);
return;
}
info.evt = 1;
info.buff_length = sizeof(int) * 2;
buff[0] = stat;
buff[1] = reason;
send(fd, &info, sizeof(struct cb_info),0);
send(fd, buff, sizeof(int) * 2,0);
close(fd);
}
static void *user_callback_thread(void *arg)
{
struct sockaddr_un saddr = { .sun_family = AF_UNIX };
snprintf(saddr.sun_path, sizeof(saddr.sun_path) - 1, USER_SOCKET);
int header[2];
void *buff;
g_server_fd = socket(PF_UNIX, SOCK_SEQPACKET, 0);
if (g_server_fd == -1) {
printf("server: socket alloc error\n");
return NULL;
}
if (bind(g_server_fd, (struct sockaddr *)(&saddr), sizeof(saddr)) == -1) {
printf("server: bind error\n");
goto fail;
}
if (chmod(saddr.sun_path, 0660) == -1) {
printf("server: chmod error\n");
goto fail;
}
if (listen(g_server_fd, 2) == -1) {
printf("server: listen error\n");
goto fail;
}
while (1) {
int len;
g_cli_fd = accept(g_server_fd, NULL, NULL);
len = recv(g_cli_fd, header, sizeof(int) * 2, 0);
if (len <= 0) {
close(g_cli_fd);
g_cli_fd = -1;
continue;
}
buff = malloc(header[1] + 1);
if (len <= 0) {
close(g_cli_fd);
g_cli_fd = -1;
continue;
}
len = recv(g_cli_fd, buff, header[1], 0);
if (len <= 0) {
free(buff);
close(g_cli_fd);
g_cli_fd = -1;
continue;
}
if (header[0] == 0) {
printf("\n-------------------------scan result-------------------------\n");
printf("%s\n", buff);
printf("---------------------------------------------------------------\n");
} else if (header[0] == 1) {
printf("\n-------------------connection change result------------------\n");
printf("%s\n", wifistate2string(((int *)buff)[0]));
if (((int *)buff)[0] == WIFI_STATE_DISCONNECTED)
printf("disconnect reason: %s\n", disconn_reason2string(((int *)buff)[1]));
printf("---------------------------------------------------------------\n");
}
free(buff);
close(g_cli_fd);
g_cli_fd = -1;
}
fail:
close(g_server_fd);
g_server_fd = -1;
pthread_exit(NULL);
}
/* release socket resource */
static void loop_stop(int sig)
{
struct sigaction sigact = { .sa_handler = SIG_DFL };
sigaction(sig, &sigact, NULL);
pthread_cancel(gp_user_callback);
pthread_join(gp_user_callback, NULL);
if (g_server_fd != -1)
close(g_server_fd);
if (g_cli_fd != -1)
close(g_cli_fd);
unlink(USER_SOCKET);
}
static int wait_loop()
{
pid_t pid;
if((pid = fork()) < 0)
return 0;
else if(pid)
return 0;
pthread_create(&gp_user_callback, NULL, user_callback_thread, NULL);
struct sigaction sigact = { .sa_handler = SIG_IGN };
sigaction(SIGPIPE, &sigact, NULL);
/* free ctl resource */
sigact.sa_handler = loop_stop;
sigaction(SIGTERM, &sigact, NULL);
sigaction(SIGINT, &sigact, NULL);
while(1) {
sleep(1);
}
return 0;
}
int main(int argc, char *argv[])
{
int opt;
const char *opts = "c:hslriod";
char list_net_results[LIST_NETWORK_MAX];
wifi_status_t status = {0};
int ret = -1;
struct option longopts[] = {
{"connect", required_argument, NULL, 'c'},
{"scan", no_argument, NULL, 's'},
{"list_network", no_argument, NULL, 'l'},
{"remove_network", no_argument, NULL, 'r'},
{"status", no_argument, NULL, 'i'},
{"help", no_argument, NULL, 'h'},
{"open", no_argument, NULL, 'o'},
{"close", no_argument, NULL, 'd'},
{ 0, 0, 0, 0 },
};
wifimanager_cb_t cb = {
.scan_result_cb = print_scan_result,
.stat_change_cb = print_stat_change,
};
if(argc == 1)
goto usage;
while ((opt = getopt_long(argc, argv, opts, longopts, NULL)) != -1) {
switch(opt) {
case 'c':
if(argc > 5 || argc < 3) {
printf(" -c, --connect\t\tconnect AP, -c <ssid> [password]\n");
} else if (argc == 3) {
/* Open */
printf("connecting open wifi [ssid:%s] \n", argv[2]);
wifimanager_connect(argv[2], NULL);
} else {
printf("connecting ssid:%s passward:%s\n", argv[optind-1], argv[optind]);
wifimanager_connect(argv[optind-1], argv[optind]);
}
return EXIT_SUCCESS;
case 'h':
usage:
printf(" -h, --help\t\tprint this help\n");
printf(" -c, --connect\t\tconnect AP, -c <ssid> [password]\n");
printf(" -s, --scan\t\tscan AP\n");
printf(" -l, --list\tlist all networks\n");
printf(" -i, --status\t\tget wifi status information\n");
printf(" -r, --remove\tremove network in config, -r <ssid>\n");
printf(" -o, --open\topen WifiManager\n");
printf(" -d, --close\tclose WifiManager\n");
return EXIT_SUCCESS;
case 's':
ret = wifimanager_scan();
return EXIT_SUCCESS;
case 'l':
ret = wifimanager_list_networks(list_net_results, LIST_NETWORK_MAX);
if(ret != -1) {
printf("%s\n", list_net_results);
}
return EXIT_SUCCESS;
case 'i':
ret = wifimanager_get_status(&status);
if(ret >= 0) {
printf("wifi state: %s\n", wifistate2string(status.state));
if((status.state == WIFI_STATE_GOT_IP) ||
(status.state == WIFI_STATE_CONNECTED) ||
(status.state == WIFI_STATE_DHCPC_REQUEST)) {
printf("ssid:%s\n", status.ssid);
printf("bssid:%s\n", status.bssid);
printf("key mgmt: %s\n", status.key_mgmt);
printf("current frequency: %d GHz\n", status.freq);
printf("ip address: %s\n", status.ip_address);
printf("mac address: %s\n", status.mac_address);
printf("rssi: %d\n", status.rssi);
printf("link speed: %d\n", status.link_speed);
printf("noise: %d\n", status.noise);
}
}
return EXIT_SUCCESS;
case 'r':
if(argc < 2) {
printf(" -r, --remove_net\tremove network in config, -r <ssid>\n");
return EXIT_SUCCESS;
}
printf("removing ssid:%s\n", argv[optind]);
wifimanager_remove_networks(argv[optind], strlen(argv[optind]));
return EXIT_SUCCESS;
case 'o':
if (wifimanager_init(&cb)) {
printf("wifimanager init failed\n");
return -1;
}
printf("wifimanager init ok\n");
/* create a child process, in case user_callback_thread don't be closed
* just for this test. if your farther process won't exit, ignore it
*/
wait_loop();
return EXIT_SUCCESS;
case 'd':
wifimanager_deinit();
printf("wifimanager deinit ok\n");
return EXIT_SUCCESS;
default:
printf("Try '%s -h' for more information.\n", argv[0]);
return EXIT_FAILURE;
}
if (optind == argc)
goto usage;
}
}