linuxOS_D21X/source/artinchip/http-wificonfig/http.c
2025-08-14 15:17:16 +08:00

661 lines
16 KiB
C

// SPDX-License-Identifier: Apache-2.0
/*
* Copyright (C) 2025 Artinchip Technology Co., Ltd.
* Authors: wulv <lv.wu@artinchip.com>
*/
#include <stdlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <ctype.h>
#include <unistd.h>
#include <errno.h>
#include <sys/stat.h>
#include <arpa/inet.h>
#include "wifimanager.h"
#define SERVER_STRING "Server: artinchiphttpd/0.1.0\r\n"
#define SERVER_PORT 80
#define HTML_DEFAULT "/var/http_wificonfig/html/"
#define WIFI_CONNECT_TIMEOUT_S 15
struct stat st;
static int get_line(int sock, char *buff, int size);
static void handle_get(int sock, char *url);
static int handle_post(int sock, char *url);
int do_http(int sock);
void not_found(int sock);
void responce_headers(int sock, FILE *file);
void responce_bodys(int sock, FILE *file);
void unimplement(int sock);
void do_responce(int sock, const char *path);
enum
{
HTTP_WIFICONFIG_ERROR = 0,
HTTP_WIFICONFIG_WARNING,
HTTP_WIFICONFIG_INFO,
HTTP_WIFICONFIG_DEBUG,
};
static int debug_level = HTTP_WIFICONFIG_INFO;
void http_wificonfig_debug(int level, const char *fmt, ...)
{
va_list args;
if (level > debug_level)
return;
va_start(args, fmt);
printf("[http_wificonfig]: ");
vprintf(fmt, args);
va_end(args);
}
static int get_line(int sock, char *buff, int size)
{
int count = 0;
char ch = '\0';
int len = 0;
while (count < size - 1 && ch != '\n')
{
len = read(sock, &ch, 1);
if (len == 1)
{
if (ch == '\r')
{
continue;
}
else if (ch == '\n')
{
break;
}
buff[count] = ch;
count++;
}
else if (len == -1)
{
http_wificonfig_debug(HTTP_WIFICONFIG_ERROR, "read error\n");
count = -1;
break;
}
else
{
http_wificonfig_debug(HTTP_WIFICONFIG_ERROR, "client error\n");
count = -1;
break;
}
}
if (count >= 0)
buff[count] = '\0';
return count;
}
static void handle_get(int sock, char *url)
{
int len = 0;
char buff[512];
char path[128];
snprintf(path, 127, HTML_DEFAULT "%s", url);
http_wificonfig_debug(HTTP_WIFICONFIG_DEBUG, "method: GET \n ");
do
{
len = get_line(sock, buff, sizeof(buff));
http_wificonfig_debug(HTTP_WIFICONFIG_ERROR, "%s\n", buff);
} while (len > 0);
if (stat(path, &st) == -1)
{
http_wificonfig_debug(HTTP_WIFICONFIG_ERROR, "The file: %s is not exist!\n", path);
not_found(sock);
}
else
{
do_responce(sock, path);
}
}
static void bad_request(int client)
{
char buf[128];
snprintf(buf, 127, "HTTP/1.0 400 BAD REQUEST\r\n");
send(client, buf, sizeof(buf), 0);
snprintf(buf, 127, "Content-type: text/html\r\n");
send(client, buf, sizeof(buf), 0);
snprintf(buf, 127, "\r\n");
send(client, buf, sizeof(buf), 0);
snprintf(buf, 127, "<P>Your browser sent a bad request, ");
send(client, buf, sizeof(buf), 0);
snprintf(buf, 127, "such as a POST without a Content-Length.\r\n");
send(client, buf, sizeof(buf), 0);
}
static int hex_to_char(char c)
{
if (c >= '0' && c <= '9')
return c - '0';
if (c >= 'A' && c <= 'F')
return c - 'A' + 10;
if (c >= 'a' && c <= 'f')
return c - 'a' + 10;
return -1;
}
static char *url_decode(const char *str)
{
if (str == NULL)
return NULL;
size_t len = strlen(str);
char *decoded = (char *)malloc(len + 1);
if (decoded == NULL)
return NULL;
size_t i = 0, j = 0;
while (str[i] != '\0')
{
if (str[i] == '%' && str[i + 1] != '\0' && str[i + 2] != '\0')
{
int high = hex_to_char(str[i + 1]);
int low = hex_to_char(str[i + 2]);
if (high != -1 && low != -1)
{
decoded[j++] = (char)((high << 4) | low);
i += 3;
continue;
}
else
{
decoded[j++] = str[i++];
}
}
else
{
decoded[j++] = str[i++];
}
}
decoded[j] = '\0';
return decoded;
}
static int parse_wificonfig_info(char *buff, char *ssid, char *password)
{
char *ptr = NULL;
int i;
char *decode = NULL;
decode = url_decode(buff);
if (!decode)
{
http_wificonfig_debug(HTTP_WIFICONFIG_ERROR, "decode error\n");
return -1;
}
ptr = strstr(decode, "ssid=");
if (ptr == NULL)
{
http_wificonfig_debug(HTTP_WIFICONFIG_ERROR, "Can't get ssid info\n");
free(decode);
return -1;
}
ptr += 5;
for (i = 0; *ptr != '&' && i < 64; i++)
{
ssid[i] = *ptr;
ptr++;
}
ssid[i] = '\0';
ptr = strstr(ptr, "password=");
if (ptr == NULL)
{
http_wificonfig_debug(HTTP_WIFICONFIG_ERROR, "Can't get password info\n");
free(decode);
return -1;
}
ptr += 9;
for (i = 0; *ptr != '\0' && i < 64; i++)
{
password[i] = *ptr;
ptr++;
}
password[i] = '\0';
http_wificonfig_debug(HTTP_WIFICONFIG_INFO, "ssid = %s\n password = %s\n", ssid, password);
free(decode);
return 0;
}
static int handle_post(int sock, char *url)
{
int len = 0;
char buff[128];
char *ptr = NULL;
char ssid[32];
char password[64];
int content_length = -1;
int ret = 0;
http_wificonfig_debug(HTTP_WIFICONFIG_INFO, "method: POST \n ");
do
{
len = get_line(sock, buff, sizeof(buff));
if (len < 0)
return 0;
if (len == 0 && content_length != -1)
{
http_wificonfig_debug(HTTP_WIFICONFIG_DEBUG, "content_length == %d\n", content_length);
len = recv(sock, buff, content_length, 0);
if (len <= 0)
{
http_wificonfig_debug(HTTP_WIFICONFIG_ERROR, "recv post request body filed\n");
content_length = -1;
}
else
{
buff[content_length] = '\0';
}
http_wificonfig_debug(HTTP_WIFICONFIG_DEBUG, "POST:body: %s\n", buff);
break;
}
http_wificonfig_debug(HTTP_WIFICONFIG_DEBUG, "%s\n", buff);
ptr = strstr(buff, "Content-Length:");
if (ptr != NULL)
{
content_length = atoi(&(ptr[16]));
}
} while (len > 0);
if (content_length == -1)
{
bad_request(sock);
return 0;
}
ret = parse_wificonfig_info(buff, ssid, password);
if (ret != 0)
{
bad_request(sock);
return 0;
}
wifi_status_t status;
memset(&status, 0, sizeof(wifi_status_t));
int timeout = WIFI_CONNECT_TIMEOUT_S;
char new_path[64];
wifimanager_connect(ssid, password);
do
{
sleep(1);
wifimanager_get_status(&status);
if (status.state == WIFI_STATE_GOT_IP || status.state == WIFI_STATE_CONNECTED)
break;
} while (timeout-- > 0);
if (timeout > 0)
snprintf(new_path, 63, HTML_DEFAULT "success_%s", url);
else
snprintf(new_path, 63, HTML_DEFAULT "fail_%s", url);
http_wificonfig_debug(HTTP_WIFICONFIG_DEBUG, "path:%s\n", new_path);
if (stat(new_path, &st) == -1)
{
http_wificonfig_debug(HTTP_WIFICONFIG_ERROR, "The file: %s is not exist!\n", new_path);
not_found(sock);
}
do_responce(sock, new_path);
if (timeout > 0)
{
sleep(10);
system("killall hostapd");
system("killall udhcpd");
return 1;
}
return 0;
}
int do_http(int sock)
{
int len = 0;
char buff[512];
char url[256];
char method[64];
char path[256];
len = get_line(sock, buff, sizeof(buff));
int i = 0, j = 0;
if (len > 0)
{
while (!isspace(buff[j]) && i < sizeof(method) - 1)
{
method[i] = buff[j];
i++;
j++;
}
method[i] = '\0';
http_wificonfig_debug(HTTP_WIFICONFIG_DEBUG, "request method:%s\n", method);
}
while (isspace(buff[j++])) {}
i = 0;
while (!isspace(buff[j]) && i < sizeof(url) - 1)
{
url[i] = buff[j];
i++;
j++;
}
url[i] = '\0';
char *p = strchr(url, '?');
if (p)
*p = '\0';
if (url[0] == '\0' || url[0] == '/')
strcat(url, "index.html");
http_wificonfig_debug(HTTP_WIFICONFIG_INFO, "actual url:%s\n", url);
if (strncasecmp(method, "GET", i) == 0)
{
handle_get(sock, url);
}
else if (strncasecmp(method, "POST", i) == 0)
{
return handle_post(sock, url);
}
else
{
fprintf(stderr, "warning! other request:%s\n !", method);
do
{
len = get_line(sock, buff, sizeof(buff));
http_wificonfig_debug(HTTP_WIFICONFIG_DEBUG, "read:%s\n", buff);
} while (len > 0);
unimplement(sock);
}
return 0;
}
/**********************************************************************/
/* Give a client a 404 not found status message. */
/**********************************************************************/
void not_found(int sock)
{
char buf[128];
snprintf(buf, 127, "HTTP/1.0 404 NOT FOUND\r\n");
send(sock, buf, strlen(buf), 0);
snprintf(buf, 127, SERVER_STRING);
send(sock, buf, strlen(buf), 0);
snprintf(buf, 127, "Content-Type: text/html\r\n");
send(sock, buf, strlen(buf), 0);
snprintf(buf, 127, "\r\n");
send(sock, buf, strlen(buf), 0);
snprintf(buf, 127, "<HTML><TITLE>Not Found</TITLE>\r\n");
send(sock, buf, strlen(buf), 0);
snprintf(buf, 127, "<BODY><P>The server could not fulfill\r\n");
send(sock, buf, strlen(buf), 0);
snprintf(buf, 127, "your request because the resource specified\r\n");
send(sock, buf, strlen(buf), 0);
snprintf(buf, 127, "is unavailable or nonexistent.\r\n");
send(sock, buf, strlen(buf), 0);
snprintf(buf, 127, "</BODY></HTML>\r\n");
send(sock, buf, strlen(buf), 0);
}
void responce_headers(int sock, FILE *file)
{
struct stat st1;
char buff[1024] = {0};
char temp[64];
const char *head = "HTTP/1.0 200 OK\r\nServer:ArtInChip Private Server\r\nContent-Type: text/html\r\nConnection: Close\r\n";
strcpy(buff, head);
int fd = fileno(file);
fstat(fd, &st1);
int size = st1.st_size;
snprintf(temp, 63, "Content-Length:%d\r\n\r\n", size);
strcat(buff, temp);
write(sock, buff, strlen(buff));
http_wificonfig_debug(HTTP_WIFICONFIG_DEBUG, "%s\n", buff);
}
void responce_bodys(int sock, FILE *file)
{
fseek(file, 0, SEEK_END);
long fileSize = ftell(file);
rewind(file);
char *buffer = (char *)malloc(fileSize);
if (buffer == NULL)
{
perror("Failed to allocate memory");
return;
}
fread(buffer, 1, fileSize, file);
write(sock, buffer, fileSize);
free(buffer);
}
void unimplement(int sock)
{
char buf[128];
snprintf(buf, 127, "HTTP/1.0 501 Method Not Implemented\r\n");
send(sock, buf, strlen(buf), 0);
snprintf(buf, 127, SERVER_STRING);
send(sock, buf, strlen(buf), 0);
snprintf(buf, 127, "Content-Type: text/html\r\n");
send(sock, buf, strlen(buf), 0);
snprintf(buf, 127, "\r\n");
send(sock, buf, strlen(buf), 0);
snprintf(buf, 127, "<HTML><HEAD><TITLE>Method Not Implemented\r\n");
send(sock, buf, strlen(buf), 0);
snprintf(buf, 127, "</TITLE></HEAD>\r\n");
send(sock, buf, strlen(buf), 0);
snprintf(buf, 127, "<BODY><P>HTTP request method not supported.\r\n");
send(sock, buf, strlen(buf), 0);
snprintf(buf, 127, "</BODY></HTML>\r\n");
send(sock, buf, strlen(buf), 0);
}
void do_responce(int sock, const char *path)
{
FILE *resource = NULL;
resource = fopen(path, "r");
if (resource == NULL)
{
http_wificonfig_debug(HTTP_WIFICONFIG_ERROR, "open file %s\n error!\n", path);
not_found(sock);
return;
}
responce_headers(sock, resource);
responce_bodys(sock, resource);
fclose(resource);
}
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";
}
}
static void print_scan_result(char *result)
{
http_wificonfig_debug(HTTP_WIFICONFIG_INFO, "%s\n", result);
}
static void print_stat_change(wifistate_t stat, wifimanager_disconn_reason_t reason)
{
http_wificonfig_debug(HTTP_WIFICONFIG_INFO, "%s\n", wifistate2string(stat));
if (stat == WIFI_STATE_DISCONNECTED)
http_wificonfig_debug(HTTP_WIFICONFIG_INFO, "disconnect reason: %s\n", disconn_reason2string(reason));
}
int main(int argc, char *argv[])
{
int server_sock = -1;
struct sockaddr_in server_addr;
int ret;
int on = 1;
wifimanager_cb_t cb = {
.scan_result_cb = print_scan_result,
.stat_change_cb = print_stat_change,
};
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(SERVER_PORT);
server_sock = socket(AF_INET, SOCK_STREAM, 0);
if (server_sock < 0)
{
http_wificonfig_debug(HTTP_WIFICONFIG_ERROR, "socket failed\n");
return -1;
}
if ((setsockopt(server_sock, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &on, sizeof(on))) < 0)
{
http_wificonfig_debug(HTTP_WIFICONFIG_ERROR, "setsockopt failed\n");
close(server_sock);
return -1;
}
if (bind(server_sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
{
http_wificonfig_debug(HTTP_WIFICONFIG_ERROR, "bind failed\n");
close(server_sock);
return -1;
}
if (listen(server_sock, 5) < 0)
{
http_wificonfig_debug(HTTP_WIFICONFIG_ERROR, "listen failed\n");
close(server_sock);
return -1;
}
wifimanager_init(&cb);
system("hostapd -d /etc/http_wificonfig/hostapd.conf -B");
// sleep(1);
system("ifconfig wlan1 192.168.1.1");
system("udhcpd /etc/http_wificonfig/udhcpd.conf");
while (1)
{
struct sockaddr_in client_addr;
int client_sock;
char buff[64];
int client_length = sizeof(client_addr);
client_sock = accept(server_sock, (struct sockaddr *)&client_addr, &client_length);
if (client_sock == -1)
{
http_wificonfig_debug(HTTP_WIFICONFIG_ERROR, "accept error\n");
close(server_sock);
return -1;
}
http_wificonfig_debug(HTTP_WIFICONFIG_INFO, "client ip:%s\t port:%d\n ",
inet_ntop(AF_INET, &client_addr.sin_addr.s_addr, buff, sizeof(buff)),
ntohs(client_addr.sin_port));
ret = do_http(client_sock);
close(client_sock);
/* wifi configration success, exit! */
if (ret)
{
close(server_sock);
break;
}
}
return 0;
}