本文章介紹Raspberry Pi Pico W使用LwIP & MbedTLS,利用Cookie建立Session管理。
實驗建立需要登入驗證的網頁與無須登入驗證的網頁兩類別。當開啟需要驗證的網頁時,若尚未登入,則重新導到驗證頁面。
將需要驗證後才能使用的uri存在list中。
軟體主要使用LwIP httpd application, 加入Cookies功能的patch後,利用cookie建立client與server的session管理。
logout 清除client 端session cookie,下次開啟需要驗證的網頁時,需再登入一次。
為了實現session management增加三個實作functions:
char *httpd_set_cookies(const void *connection, const char *uri);
執行上述patch後在httpd.c新增的function call,用於加入Set-Cookie: header。
void httpd_received_cookies(const void *connection, char **cookies);
執行上述patch後在httpd.c新增的function call,本專案修改cookies的parameter屬性,因為server在收到 client送來cookie中的session-id,若在server端已不存在(也許timeout), 將重設cookie為NULL。
void httpd_redirect_uri(char* uri, u16_t *uri_len);
若client的cookie為NULL,則server 將重新導到登入頁面。
每個session設有timeout時間,當在設定的timeout時間內沒有任何存取網頁,則清除server上該session object。當每次存取網頁時就會重設timeout時間。
流程如下圖所示:
當cookie設定 Secure ,則只能以https方式傳送cookie。因此以http開啟網頁時,因為cookie設定為Secure,即使登入成功,browser也不會送出cookie,因此server將認定為未登入。
成果影片
程式碼
- picow_https_auth.c(main)
- picow_https_ssi.c
- picow_https_fs.c
- CMakeLists.txt
- lwipopts.h
- mbedtls_config.h
- index.shtml
- login.html
#include <stdio.h>
#include "pico/stdlib.h"
#include "pico/cyw43_arch.h"
#include "hardware/adc.h"
#include "lwip/altcp_tls.h"
#include "lwip/altcp_tcp.h"
#include "lwip/altcp.h"
#include "lwip/apps/httpd.h"
#include "lwip/apps/sntp.h"
#include "picow_https_cert.h"
#include "ff.h"
#include "pico_storage.h"
#include "mbedtls/ssl.h"
#define LIGHT_PIN 16
#define WIFI_SSID "your-ssid"
#define WIFI_PASSWORD "your-password"
struct altcp_tls_config {
mbedtls_ssl_config conf;
mbedtls_x509_crt *cert;
mbedtls_pk_context *pkey;
u8_t cert_count;
u8_t cert_max;
u8_t pkey_count;
u8_t pkey_max;
mbedtls_x509_crt *ca;
#if defined(MBEDTLS_SSL_CACHE_C) && ALTCP_MBEDTLS_USE_SESSION_CACHE
/** Inter-connection cache for fast connection startup */
struct mbedtls_ssl_cache_context cache;
#endif
#if defined(MBEDTLS_SSL_SESSION_TICKETS) && ALTCP_MBEDTLS_USE_SESSION_TICKETS
mbedtls_ssl_ticket_context ticket_ctx;
#endif
};
struct altcp_tls_config *tls_config = NULL;
void fs_ex_init(const char *httpd_root_dir);
void netif_status_cb(struct netif *netif) {
if (netif_is_link_up(netif)) {
ip_addr_t ipaddr;
ip_addr_t netmask;
ip_addr_t gateway;
ipaddr_aton("192.168.1.70", &ipaddr);
ipaddr_aton("255.255.255.0", &netmask);
ipaddr_aton("192.168.1.1", &gateway);
netif_set_addr(netif, &ipaddr, &netmask, &gateway);
}
}
bool sntp_time_geted=false;
void sntp_set_system_time(uint32_t sec, uint32_t us)
{
struct tm info;
time_t tim = sec;
struct timeval tmv;
tmv.tv_sec=sec;
tmv.tv_usec=us;
settimeofday(&tmv, 0);
printf("set time :%s\n", ctime(&tim));
sntp_time_geted=true;
}
void ssi_handler_init();
void cgi_handler_init();
void format_current_time(char *time_str, uint8_t count) {
while(!sntp_time_geted) {
cyw43_arch_poll();
tight_loop_contents();
};
time_t timer=time(NULL);
struct tm *tm_info = localtime(&timer);
strftime(time_str, count, "%a, %d-%b-%Y %X %Z", tm_info);
}
#include <malloc.h>
uint32_t getTotalHeap(void) {
extern char __StackLimit, __bss_end__;
return &__StackLimit - &__bss_end__;
}
uint32_t getFreeHeap(void) {
struct mallinfo m = mallinfo();
return getTotalHeap() - m.uordblks;
}
DWORD get_sd_free_size() {
FATFS *fs;
DWORD fre_clust, fre_sect, tot_sect;
/* Get volume information and free clusters of drive 1 */
if (f_getfree(SDMMC_PATH, &fre_clust, &fs)!= FR_OK) return 0;
/* Get total sectors and free sectors */
tot_sect = (fs->n_fatent - 2) * fs->csize;
fre_sect = fre_clust * fs->csize;
/* Print the free space (assuming 512 bytes/sector) */
// printf("%10lu KiB total drive space.\n%10lu KiB available.\n", tot_sect / 2, fre_sect / 2);
return fre_sect / 2;
}
float read_onboard_temperature() {
/* 12-bit conversion, assume max value == ADC_VREF == 3.3 V */
const float conversionFactor = 3.3f / (1 << 12);
float adc = (float)adc_read() * conversionFactor;
float tempC = 27.0f - (adc - 0.706f) / 0.001721f;
return tempC;
}
extern void check_timeout_sessions_timer();
void system_error_blink() {
while(1) {
cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, !cyw43_arch_gpio_get(CYW43_WL_GPIO_LED_PIN));
sleep_ms(500);
}
}
int main()
{
stdio_init_all();
adc_init();
adc_set_temp_sensor_enabled(true);
adc_select_input(4);
if (cyw43_arch_init()) {
printf("cyw43 arch init error\n");
system_error_blink();
}
gpio_init(LIGHT_PIN);
gpio_set_dir(LIGHT_PIN, true);
gpio_put(LIGHT_PIN, 0);
//1. connect to WiFi network and set static IP
cyw43_arch_enable_sta_mode();
netif_set_status_callback(netif_default, netif_status_cb);
int wifi_stat = cyw43_arch_wifi_connect_timeout_ms(WIFI_SSID, WIFI_PASSWORD, CYW43_AUTH_WPA2_AES_PSK, 30000);
if (wifi_stat) {
printf("wifi connect error:%d\n", wifi_stat);
system_error_blink();
}
printf("Wifi connected\n");
printf("get ip addr:%s\n",ipaddr_ntoa(&(cyw43_state.netif[0].ip_addr)));
// 2. set SNTP
sntp_setoperatingmode(SNTP_OPMODE_POLL);
sntp_init();
// 3. set TLS connection
tls_config = altcp_tls_create_config_server_privkey_cert(SERVER_KEY, sizeof(SERVER_KEY), NULL, 0, SERVER_CERT, sizeof(SERVER_CERT));
mbedtls_x509_crt_parse(tls_config->cert, CA_CERT, sizeof(CA_CERT));
// for large file size
mbedtls_ssl_conf_max_frag_len( &tls_config->conf, MBEDTLS_SSL_MAX_FRAG_LEN_4096 );
//4. mount FS in SD card and start https server
FATFS fs;
FIL fil;
FRESULT res;
if (f_mount(&fs, SDMMC_PATH, 1) != FR_OK) {
printf("mount error\n");
system_error_blink();
}
int i;
ssi_handler_init();
cgi_handler_init();
check_timeout_sessions_timer();
fs_ex_init(SDMMC_PATH"/");
httpd_inits(tls_config);
//httpd_init();
char buf[61];
format_current_time(buf, 60);
printf(buf);
cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN,1);
while(1) {
cyw43_arch_poll();
sleep_ms(50);
}
return 0;
}
#include <stdio.h>
#include "pico/stdlib.h"
#include "pico/cyw43_arch.h"
#include "lwip/altcp_tls.h"
#include "lwip/altcp_tcp.h"
#include "lwip/altcp.h"
#include "lwip/apps/httpd.h"
#include "lwip/apps/sntp.h"
#include "ff.h"
#define DOMAIN "httpsserver"
#define SESSION_TIMEOUT_SEC (10*60)
#define AUTH_USER "picow"
#define AUTH_PASS "passw0rd"
#define LIGHT_PIN 16
char* session_check_uri[]={
"/light.shtml",
"/demo1.shtml",
"/demo2.shtml",
"/light.cgi"
};
typedef struct _sess_id_t{
uint8_t sess_id[26];
absolute_time_t timeout;
struct _sess_id_t *next;
} sess_id_t;
typedef struct _conn_t {
void *connection;
time_t start_time;
enum {
NORMAL_PAGE=0,
LOGIN_PAGE=1,
LOGIN_SUCCESSFUL=2,
LOGOUT_PAGE=3,
} verified;
struct _conn_t *next;
} conn_t;
char light_img[20];
sess_id_t *sess_header=NULL;
conn_t * conn_header=NULL;
void gen_sess_cookie(char *sess_id, char* sess_cookie, uint8_t count) {
char time_str[40];
uint8_t sid[26];
time_t timer=time(NULL);
struct tm *tm_info = localtime(&timer);
srand((unsigned)time(NULL));
sprintf(sid, "sess_%04d%04d%04d",rand()%10000, rand()%10000, rand()%10000);
printf("sess_id:%s\n", sid);
sprintf(sess_id, sid);
timer+=86400; // 1 day
tm_info = localtime(&timer);
strftime(time_str, 40, "%a, %d-%b-%Y %X %Z", tm_info);
sprintf(sess_cookie, "sess_id=%s; expires=%s; domain=%s; path=/; Secure", sid, time_str, DOMAIN);
//sprintf(sess_cookie, "sess_id=%s; expires=%s; domain=%s; path=/; SameSite=Lax", sid, time_str, DOMAIN);
}
void new_session_id(char *sid) {
sess_id_t *newid = (sess_id_t*)calloc(1,sizeof(sess_id_t));
newid->next = NULL;
newid->timeout=make_timeout_time_ms(SESSION_TIMEOUT_SEC*1000); // 10 min
strcpy(newid->sess_id, sid);
sess_id_t *tidp;
if (sess_header == NULL) {
sess_header = newid;
return;
} else {
tidp = sess_header;
while (tidp->next != NULL) {
tidp = tidp->next;
}
}
tidp->next=newid;
return;
}
extern DWORD get_sd_free_size();
extern float read_onboard_temperature();
extern uint32_t getFreeHeap(void);
/* ==== cgi begin ======*/
const char *
cgi_light_handler(int iIndex, int iNumParams, char *pcParam[], char *pcValue[]) {
if (iIndex == 0 && iNumParams ==1) {
if (strcmp(pcParam[0],"action") == 0) {
strcpy(light_img,"");
if (strcmp(pcValue[0], "ON")==0) {
gpio_put(LIGHT_PIN, 1);
strcpy(light_img, "/img/light_on.png");
}
if (strcmp(pcValue[0],"OFF")==0) {
gpio_put(LIGHT_PIN, 0);
strcpy(light_img, "/img/light_off.png");
}
return "/light.shtml";
}
}
return "/404.html";
}
static const tCGI cgi_handlers[] = {
{
"/light.cgi", cgi_light_handler
},
};
void cgi_handler_init() {
http_set_cgi_handlers(cgi_handlers, LWIP_ARRAYSIZE(cgi_handlers));
}
/* ==== cgi end ======*/
/* === ssi begin =====*/
const char* ssi_tags[] = {
"temp",
"freeram",
"freesd",
"logout",
"light",
};
u16_t __time_critical_func(ssi_handler)(int iIndex, char *pcInsert, int iInsertLen, u16_t current_tag_part, u16_t *next_tag_part)
{
size_t printed;
static uint32_t counter=0;
switch (iIndex) {
case 0: //temp, Temperature
printed = snprintf(pcInsert, iInsertLen, "%.02f°C", read_onboard_temperature());
break;
case 1: // free RAM
printed = sniprintf(pcInsert, iInsertLen, "%d B", getFreeHeap());
break;
case 2: // SD Free Size
printed = sniprintf(pcInsert, iInsertLen, "%ld KB", get_sd_free_size());
break;
case 3: // logout uri
printed = snprintf(pcInsert, iInsertLen,
"<button onClick='javascript:logout();'>Logout</button>");
break;
case 4: // light
printed = snprintf(pcInsert, iInsertLen,light_img);
break;
default:
printed = snprintf(pcInsert, iInsertLen, "");
}
return printed;
}
void ssi_handler_init() {
http_set_ssi_handler(ssi_handler,
#if LWIP_HTTPD_SSI_RAW
NULL, 0
#else
ssi_tags, LWIP_ARRAYSIZE(ssi_tags)
#endif
);
if (gpio_get(LIGHT_PIN))
strcpy(light_img, "/img/light_on.png");
else
strcpy(light_img, "/img/light_off.png");
}
/* === ssi end =====*/
/*===== post begin =====*/
#define USER_PASS_BUFSIZE 16
err_t
httpd_post_begin(void *connection, const char *uri, const char *http_request,
u16_t http_request_len, int content_len, char *response_uri,
u16_t response_uri_len, u8_t *post_auto_wnd)
{
LWIP_UNUSED_ARG(connection);
LWIP_UNUSED_ARG(http_request);
LWIP_UNUSED_ARG(http_request_len);
LWIP_UNUSED_ARG(content_len);
LWIP_UNUSED_ARG(post_auto_wnd);
conn_t *conn = (conn_t*)calloc(1, sizeof(conn_t));
conn->connection = connection;
conn->start_time = time(NULL);
conn->verified = NORMAL_PAGE;
conn->next=NULL;
if (conn_header == NULL) {
conn_header = conn;
} else {
conn->next=conn_header;
conn_header = conn;
}
if (!memcmp(uri, "/login.cgi", 11)) {
conn->verified = LOGIN_PAGE;
snprintf(response_uri, response_uri_len, "/loginfail.html");
*post_auto_wnd = 1;
return ERR_OK;
}
return ERR_VAL;
}
err_t
httpd_post_receive_data(void *connection, struct pbuf *p)
{
err_t ret;
LWIP_ASSERT("NULL pbuf", p != NULL);
ret = ERR_VAL;
conn_t *start = conn_header;
while(start != NULL) {
if (start->connection == connection) {
if (start->verified == LOGIN_PAGE) {
u16_t token_user = pbuf_memfind(p, "user=", 5, 0);
u16_t token_pass = pbuf_memfind(p, "pass=", 5, 0);
if ((token_user != 0xFFFF) && (token_pass != 0xFFFF)) {
u16_t value_user = token_user + 5;
u16_t value_pass = token_pass + 5;
u16_t len_user = 0;
u16_t len_pass = 0;
u16_t tmp;
/* find user len */
tmp = pbuf_memfind(p, "&", 1, value_user);
if (tmp != 0xFFFF) {
len_user = tmp - value_user;
} else {
len_user = p->tot_len - value_user;
}
/* find pass len */
tmp = pbuf_memfind(p, "&", 1, value_pass);
if (tmp != 0xFFFF) {
len_pass = tmp - value_pass;
} else {
len_pass = p->tot_len - value_pass;
}
if ((len_user > 0) && (len_user < USER_PASS_BUFSIZE) &&
(len_pass > 0) && (len_pass < USER_PASS_BUFSIZE)) {
/* provide contiguous storage if p is a chained pbuf */
char buf_user[USER_PASS_BUFSIZE];
char buf_pass[USER_PASS_BUFSIZE];
char *user = (char *)pbuf_get_contiguous(p, buf_user, sizeof(buf_user), len_user, value_user);
char *pass = (char *)pbuf_get_contiguous(p, buf_pass, sizeof(buf_pass), len_pass, value_pass);
if (user && pass) {
user[len_user] = 0;
pass[len_pass] = 0;
if (!strcmp(user, AUTH_USER) && !strcmp(pass, AUTH_PASS)) {
/* user and password are correct, create a "session" */
start->verified=LOGIN_SUCCESSFUL;
}
}
}
}
/* not returning ERR_OK aborts the connection, so return ERR_OK unless the
connection is unknown */
ret = ERR_OK;
break;
}
}
start = start->next;
}
/* this function must ALWAYS free the pbuf it is passed or it will leak memory */
pbuf_free(p);
return ret;
}
void
httpd_post_finished(void *connection, char *response_uri, u16_t response_uri_len)
{
/* default page is "login failed" */
snprintf(response_uri, response_uri_len, "/loginfail.html");
conn_t *start = conn_header;
conn_t *pre_conn = conn_header;
while (start != NULL) {
if (start->connection == connection) {
if (start->verified == LOGIN_SUCCESSFUL) {
/* login succeeded */
snprintf(response_uri, response_uri_len, "/session.html");
break;
}
if (start == conn_header) {
conn_header = start->next;
}
else {
pre_conn->next = start->next;
}
free(start);
break;
}
pre_conn = start;
start=start->next;
break;
}
}
/*===== post end =====*/
/* ==== Session manager ===*/
#define SET_COOKIE_SIZE 120
char setCookie[SET_COOKIE_SIZE];
char *httpd_set_cookies(const void *connection, const char *uri) {
LWIP_UNUSED_ARG(uri);
char cookie[SET_COOKIE_SIZE];
conn_t *start = conn_header;
conn_t *pre_conn = start;
while(start!=NULL) {
if (start->connection == connection && start->verified == LOGIN_SUCCESSFUL) {
char sessid[26];
gen_sess_cookie(sessid, cookie, SET_COOKIE_SIZE);
new_session_id(sessid);
snprintf(setCookie, SET_COOKIE_SIZE, HDR_HTTP_RES_SET_COOKIE "%s\r\n", cookie);
if (start == conn_header) {
conn_header = start->next;
}
else {
pre_conn->next = start->next;
}
free(start);
return setCookie;
}
pre_conn = start;
start=start->next;
}
return NULL;
}
void httpd_received_cookies(const void *connection, char **cookies) {
char *session = strstr(*cookies, "sess_id=");
if (session) session+=8;
sess_id_t* start = sess_header;
while (start!= NULL) {
if (strcmp(start->sess_id, session) == 0) {
// match! reset timeout
start->timeout = make_timeout_time_ms(SESSION_TIMEOUT_SEC*1000);
return;
break;
} else {
start = start->next;
}
}
// not an avail connection cookie, reset cookie to NULL(invalid cookie)
*cookies=NULL;
}
void httpd_redirect_uri(char* uri, u16_t *uri_len) {
char new_uri[(*uri_len)+1];
strncpy(new_uri, uri, *uri_len);
new_uri[*uri_len]=0;
for (int idx=0; idx < LWIP_ARRAYSIZE(session_check_uri); idx++) {
if(strstr(new_uri, session_check_uri[idx])){
// redirect to authenticate web page
strcpy(uri, "/login.html");
*uri_len = strlen("/login.html");
break;
}
}
return ;
}
repeating_timer_t timer;
bool check_timeout_sessions_isr(repeating_timer_t *t) {
sess_id_t *start = sess_header;
sess_id_t *pre_sess = start;
while (start != NULL) {
if (absolute_time_diff_us(get_absolute_time(), start->timeout) < 0) {
if (start == sess_header) {
sess_header = NULL;
free(start);
break;
} else {
pre_sess->next = start->next;
free(start);
start=pre_sess->next;
}
} else {
pre_sess = start;
start = start->next;
}
}
return true;
}
void check_timeout_sessions_timer() {
add_repeating_timer_ms(1000*60, check_timeout_sessions_isr, NULL, &timer);
}
/* ==== Session manager end ===*/
/**
* @file
* HTTPD custom file system example
*
* This file demonstrates how to add support for an external file system to httpd.
* It provides access to the specified root directory and uses stdio.h file functions
* to read files.
*
* ATTENTION: This implementation is *not* secure: no checks are added to ensure
* files are only read below the specified root directory!
*/
/*
* Copyright (c) 2017 Simon Goldschmidt
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Simon Goldschmidt <goldsimon@gmx.de>
*
*/
#include "lwip/opt.h"
#include "lwip/apps/fs.h"
#include "lwip/def.h"
#include "lwip/mem.h"
#include "stdio.h"
#include "string.h"
#include "ff.h"
#include "pico_storage.h"
/////////////////////////////////////////////////////////
#if !LWIP_HTTPD_CUSTOM_FILES
#error This needs LWIP_HTTPD_CUSTOM_FILES
#endif
//#if !LWIP_HTTPD_DYNAMIC_HEADERS
//#error This needs LWIP_HTTPD_DYNAMIC_HEADERS
//#endif
//#if !LWIP_HTTPD_DYNAMIC_FILE_READ
//#error This wants to demonstrate read-after-open, so LWIP_HTTPD_DYNAMIC_FILE_READ is required!
//#endif
//#if !LWIP_HTTPD_FS_ASYNC_READ
//#error This needs LWIP_HTTPD_FS_ASYNC_READ
//#endif
#if !LWIP_HTTPD_FILE_EXTENSION
#error This needs LWIP_HTTPD_FILE_EXTENSION
#endif
struct fs_custom_data {
//FILE *f;
FIL *f;
};
const char* fs_ex_root_dir;
void
fs_ex_init(const char *httpd_root_dir)
{
fs_ex_root_dir = strdup(httpd_root_dir);
}
#if LWIP_HTTPD_CUSTOM_FILES
int
fs_open_custom(struct fs_file *file, const char *name)
{
char full_filename[256];
//FILE *f;
FIL f;
FRESULT res;
snprintf(full_filename, 255, "%s%s", fs_ex_root_dir, name);
full_filename[255] = 0;
//f = fopen(full_filename, "rb");
res =f_open(&f, full_filename, FA_READ);
//if (f != NULL) {
if (res == FR_OK) {
//if (!fseek(f, 0, SEEK_END)) {
if (f_lseek(&f, 0) == FR_OK) {
//int len = (int)ftell(f);
int len = (int)f_size(&f);
//if(!fseek(f, 0, SEEK_SET)) {
struct fs_custom_data *data = (struct fs_custom_data *)mem_malloc(sizeof(struct fs_custom_data));
LWIP_ASSERT("out of memory?", data != NULL);
memset(file, 0, sizeof(struct fs_file));
file->len = len;
file->flags = FS_FILE_FLAGS_HEADER_PERSISTENT;
data->f = &f;
file->pextension = data;
return 1;
//}
} else {
printf("open file error:%s\n", name);
}
//fclose(f);
f_close(&f);
}
return 0;
}
void
fs_close_custom(struct fs_file *file)
{
//FRESULT res;
if (file && file->pextension) {
struct fs_custom_data *data = (struct fs_custom_data *)file->pextension;
if (data->f != NULL) {
//fclose(data->f);
f_close(data->f);
data->f = NULL;
}
mem_free(data);
}
}
#if LWIP_HTTPD_FS_ASYNC_READ
u8_t
fs_canread_custom(struct fs_file *file)
{
/* This function is only necessary for asynchronous I/O:
If reading would block, return 0 and implement fs_wait_read_custom() to call the
supplied callback if reading works. */
LWIP_UNUSED_ARG(file);
return 1;
}
u8_t
fs_wait_read_custom(struct fs_file *file, fs_wait_cb callback_fn, void *callback_arg)
{
//LWIP_ASSERT("not implemented in this example configuration", 0);
LWIP_UNUSED_ARG(file);
LWIP_UNUSED_ARG(callback_fn);
LWIP_UNUSED_ARG(callback_arg);
/* Return
- 0 if ready to read (at least one byte)
- 1 if reading should be delayed (call 'tcpip_callback(callback_fn, callback_arg)' when ready) */
return 1;
}
int
fs_read_async_custom(struct fs_file *file, char *buffer, int count, fs_wait_cb callback_fn, void *callback_arg)
{
struct fs_custom_data *data = (struct fs_custom_data *)file->pextension;
//FILE *f;
FIL *f;
int len;
int read_count = count;
LWIP_ASSERT("data not set", data != NULL);
f = data->f;
//len = (int)fread(buffer, 1, read_count, f);
f_read(f, buffer,read_count, &len);
LWIP_UNUSED_ARG(callback_fn);
LWIP_UNUSED_ARG(callback_arg);
file->index += len;
/* Return
- FS_READ_EOF if all bytes have been read
- FS_READ_DELAYED if reading is delayed (call 'tcpip_callback(callback_fn, callback_arg)' when done) */
if (len == 0) {
/* all bytes read already */
return FS_READ_EOF;
}
return len;
}
#else /* LWIP_HTTPD_FS_ASYNC_READ */
int
fs_read_custom(struct fs_file *file, char *buffer, int count)
{
struct fs_custom_data *data = (struct fs_custom_data *)file->pextension;
//FILE *f;
FIL *f;
int len;
int read_count = count;
LWIP_ASSERT("data not set", data != NULL);
f = data->f;
//len = (int)fread(buffer, 1, read_count, f);
f_read(f, buffer, read_count, &len);
file->index += len;
/* Return FS_READ_EOF if all bytes have been read */
return len;
}
#endif /* LWIP_HTTPD_FS_ASYNC_READ */
#endif /* LWIP_HTTPD_CUSTOM_FILES */
# Generated Cmake Pico project file
cmake_minimum_required(VERSION 3.13)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
# Initialise pico_sdk from installed location
# (note this can come from environment, CMake cache etc)
set(PICO_SDK_PATH "/home/duser/pico/pico-sdk")
set(PICO_BOARD pico_w CACHE STRING "Board type")
# Pull in Raspberry Pi Pico SDK (must be before project)
include(pico_sdk_import.cmake)
if (PICO_SDK_VERSION_STRING VERSION_LESS "1.4.0")
message(FATAL_ERROR "Raspberry Pi Pico SDK version 1.4.0 (or later) required. Your version is ${PICO_SDK_VERSION_STRING}")
endif()
project(picow_https_auth C CXX ASM)
# Initialise the Raspberry Pi Pico SDK
pico_sdk_init()
# Add executable. Default name is the project name, version 0.1
add_executable(picow_https_auth
picow_https_auth.c
picow_https_ssi.c
picow_httpd_fs.c
)
pico_set_program_name(picow_https_auth "picow_https_auth")
pico_set_program_version(picow_https_auth "0.1")
pico_enable_stdio_uart(picow_https_auth 1)
pico_enable_stdio_usb(picow_https_auth 0)
# Add the standard library to the build
target_link_libraries(picow_https_auth
pico_stdlib
hardware_adc)
# Add the standard include files to the build
target_include_directories(picow_https_auth PRIVATE
${CMAKE_CURRENT_LIST_DIR}
${CMAKE_CURRENT_LIST_DIR}/.. # for our common lwipopts or any other standard includes, if required
)
# Add any user requested libraries
target_link_libraries(picow_https_auth
pico_cyw43_arch_lwip_poll
pico_lwip_sntp
pico_lwip_http
pico_mbedtls
pico_lwip_mbedtls
)
add_subdirectory(pico_storage_drv)
target_link_libraries(picow_https_auth
pico_storage_drv
)
pico_add_extra_outputs(picow_https_auth)
# Ignore warnings from lwip code
set_source_files_properties(
${PICO_LWIP_PATH}/src/apps/altcp_tls/altcp_tls_mbedtls.c
PROPERTIES
COMPILE_OPTIONS "-Wno-unused-result"
)
add_definitions(
-DSNTP_SERVER_DNS=1
-DSNTP_SERVER_ADDRESS="pool.ntp.org"
-DSNTP_SET_SYSTEM_TIME=sntp_set_system_time
-DSNTP_STARTUP_DELAY=0
)
#ifndef __LWIPOPTS_H__
#define __LWIPOPTS_H__
// Common settings used in most of the pico_w examples
// (see https://www.nongnu.org/lwip/2_1_x/group__lwip__opts.html for details)
// allow override in some examples
#ifndef NO_SYS
#define NO_SYS 1
#endif
// allow override in some examples
#ifndef LWIP_SOCKET
#define LWIP_SOCKET 0
#endif
#if PICO_CYW43_ARCH_POLL
#define MEM_LIBC_MALLOC 1
#else
// MEM_LIBC_MALLOC is incompatible with non polling versions
#define MEM_LIBC_MALLOC 0
#endif
#define MEM_ALIGNMENT 4
#define MEM_SIZE 4000
#define MEMP_NUM_TCP_SEG 32
#define MEMP_NUM_ARP_QUEUE 10
#define PBUF_POOL_SIZE 24
#define LWIP_ARP 1
#define LWIP_ETHERNET 1
#define LWIP_ICMP 1
#define LWIP_RAW 1
#define TCP_WND (8 * TCP_MSS)
#define TCP_MSS 1460
#define TCP_SND_BUF (8 * TCP_MSS)
#define TCP_SND_QUEUELEN ((4 * (TCP_SND_BUF) + (TCP_MSS - 1)) / (TCP_MSS))
#define LWIP_NETIF_STATUS_CALLBACK 1
#define LWIP_NETIF_LINK_CALLBACK 1
#define LWIP_NETIF_HOSTNAME 1
#define LWIP_NETCONN 0
#define MEM_STATS 0
#define SYS_STATS 0
#define MEMP_STATS 0
#define LINK_STATS 0
// #define ETH_PAD_SIZE 2
#define LWIP_CHKSUM_ALGORITHM 3
#define LWIP_DHCP 1
#define LWIP_IPV4 1
#define LWIP_TCP 1
#define LWIP_UDP 1
#define LWIP_DNS 1
#define LWIP_TCP_KEEPALIVE 1
#define LWIP_NETIF_TX_SINGLE_PBUF 1
#define DHCP_DOES_ARP_CHECK 0
#define LWIP_DHCP_DOES_ACD_CHECK 0
#ifndef NDEBUG
#define LWIP_DEBUG 1
#define LWIP_STATS 1
#define LWIP_STATS_DISPLAY 1
#endif
#define ETHARP_DEBUG LWIP_DBG_OFF
#define NETIF_DEBUG LWIP_DBG_OFF
#define PBUF_DEBUG LWIP_DBG_OFF
#define API_LIB_DEBUG LWIP_DBG_OFF
#define API_MSG_DEBUG LWIP_DBG_OFF
#define SOCKETS_DEBUG LWIP_DBG_OFF
#define ICMP_DEBUG LWIP_DBG_OFF
#define INET_DEBUG LWIP_DBG_OFF
#define IP_DEBUG LWIP_DBG_OFF
#define IP_REASS_DEBUG LWIP_DBG_OFF
#define RAW_DEBUG LWIP_DBG_OFF
#define MEM_DEBUG LWIP_DBG_OFF
#define MEMP_DEBUG LWIP_DBG_OFF
#define SYS_DEBUG LWIP_DBG_OFF
#define TCP_DEBUG LWIP_DBG_OFF
#define TCP_INPUT_DEBUG LWIP_DBG_OFF
#define TCP_OUTPUT_DEBUG LWIP_DBG_OFF
#define TCP_RTO_DEBUG LWIP_DBG_OFF
#define TCP_CWND_DEBUG LWIP_DBG_OFF
#define TCP_WND_DEBUG LWIP_DBG_OFF
#define TCP_FR_DEBUG LWIP_DBG_OFF
#define TCP_QLEN_DEBUG LWIP_DBG_OFF
#define TCP_RST_DEBUG LWIP_DBG_OFF
#define UDP_DEBUG LWIP_DBG_OFF
#define TCPIP_DEBUG LWIP_DBG_OFF
#define PPP_DEBUG LWIP_DBG_OFF
#define SLIP_DEBUG LWIP_DBG_OFF
#define DHCP_DEBUG LWIP_DBG_OFF
/* in Pico-SDK above 1.5.0 */
#define MEMP_NUM_SYS_TIMEOUT (LWIP_NUM_SYS_TIMEOUT_INTERNAL+1)
/* TCP WND must be at least 16 kb to match TLS record size
or you will get a warning "altcp_tls: TCP_WND is smaller than the RX decrypion buffer, connection RX might stall!" */
// tls
#undef TCP_WND
#define TCP_WND 16384
#define LWIP_ALTCP 1
#define LWIP_ALTCP_TLS 1
#define LWIP_ALTCP_TLS_MBEDTLS 1
//#define LWIP_DEBUG 1
#define ALTCP_MBEDTLS_DEBUG LWIP_DBG_ON
/* set authmode */
#define ALTCP_MBEDTLS_AUTHMODE MBEDTLS_SSL_VERIFY_NONE
//#define ALTCP_MBEDTLS_AUTHMODE MBEDTLS_SSL_VERIFY_REQUIRED
// httpd
#define HTTPD_ENABLE_HTTPS 1 // enable https
#define LWIP_HTTPD 1
#define LWIP_HTTPD_SSI 1
#define LWIP_HTTPD_CGI 1
#define LWIP_HTTPD_SSI_MULTIPART 1
#define LWIP_HTTPD_SUPPORT_POST 1
#define LWIP_HTTPD_SSI_INCLUDE_TAG 0
// extern wbe page files
#define LWIP_HTTPD_CUSTOM_FILES 1
#define LWIP_HTTPD_DYNAMIC_HEADERS 1
#define LWIP_HTTPD_FS_ASYNC_READ 1
#define LWIP_HTTPD_DYNAMIC_FILE_READ 1
#define LWIP_HTTPD_FILE_EXTENSION 1
#define LWIP_HTTPD_SUPPORT_COOKIES 1
#endif /* __LWIPOPTS_H__ */
/* Workaround for some mbedtls source files using INT_MAX without including limits.h */
#include <limits.h>
#define MBEDTLS_NO_PLATFORM_ENTROPY
#define MBEDTLS_ENTROPY_HARDWARE_ALT
#define MBEDTLS_SSL_OUT_CONTENT_LEN 2048
#define MBEDTLS_ALLOW_PRIVATE_ACCESS
#define MBEDTLS_HAVE_TIME
#define MBEDTLS_HAVE_TIME_DATE
#define MBEDTLS_CIPHER_MODE_CBC
#define MBEDTLS_ECP_DP_SECP192R1_ENABLED
#define MBEDTLS_ECP_DP_SECP224R1_ENABLED
#define MBEDTLS_ECP_DP_SECP256R1_ENABLED
#define MBEDTLS_ECP_DP_SECP384R1_ENABLED
#define MBEDTLS_ECP_DP_SECP521R1_ENABLED
#define MBEDTLS_ECP_DP_SECP192K1_ENABLED
#define MBEDTLS_ECP_DP_SECP224K1_ENABLED
#define MBEDTLS_ECP_DP_SECP256K1_ENABLED
#define MBEDTLS_ECP_DP_BP256R1_ENABLED
#define MBEDTLS_ECP_DP_BP384R1_ENABLED
#define MBEDTLS_ECP_DP_BP512R1_ENABLED
#define MBEDTLS_ECP_DP_CURVE25519_ENABLED
#define MBEDTLS_KEY_EXCHANGE_RSA_ENABLED
#define MBEDTLS_PKCS1_V15
#define MBEDTLS_SHA256_SMALLER
#define MBEDTLS_SSL_SERVER_NAME_INDICATION
#define MBEDTLS_AES_C
#define MBEDTLS_ASN1_PARSE_C
#define MBEDTLS_BIGNUM_C
#define MBEDTLS_CIPHER_C
#define MBEDTLS_CTR_DRBG_C
#define MBEDTLS_ENTROPY_C
#define MBEDTLS_ERROR_C
#define MBEDTLS_MD_C
#define MBEDTLS_MD5_C
#define MBEDTLS_OID_C
#define MBEDTLS_PKCS5_C
#define MBEDTLS_PK_C
#define MBEDTLS_PK_PARSE_C
#define MBEDTLS_PLATFORM_C
#define MBEDTLS_RSA_C
#define MBEDTLS_SHA1_C
#define MBEDTLS_SHA224_C
#define MBEDTLS_SHA256_C
#define MBEDTLS_SHA512_C
#define MBEDTLS_SSL_CLI_C
#define MBEDTLS_SSL_SRV_C
#define MBEDTLS_SSL_TLS_C
#define MBEDTLS_X509_CRT_PARSE_C
#define MBEDTLS_X509_USE_C
#define MBEDTLS_AES_FEWER_TABLES
/* TLS 1.2 */
#define MBEDTLS_SSL_PROTO_TLS1_2
#define MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
#define MBEDTLS_GCM_C
#define MBEDTLS_ECDH_C
#define MBEDTLS_ECP_C
#define MBEDTLS_ECDSA_C
#define MBEDTLS_ASN1_WRITE_C
// The following is needed to parse a certificate
#define MBEDTLS_PEM_PARSE_C
#define MBEDTLS_BASE64_C
// for large file size
#define MBEDTLS_SSL_MAX_FRAGMENT_LENGTH
<html lang="en">
<head><title>Raspberry Pi Pico W - HTTPS Session</title></head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<Script>
function logout() {
const cookies = document.cookie.split(";");
for (let i = 0; i < cookies.length; i++) {
const cookie = cookies[i];
const eqPos = cookie.indexOf("=");
const name = eqPos > -1 ? cookie.substr(0, eqPos) : cookie;
if (name=="sess_id"){
document.cookie = name + "=;expires=Thu, 01 Jan 1970 00:00:00 GMT";
}
}
}
</Script>
<body bgcolor="white" text="black">
<h1><strong>Raspberry Pi Pico W - </strong>HTTPS Session</h1>
<table style="border-collapse: collapse; width: 1000; height: 127px;" border="1">
<tbody>
<tr style="height: 18px;">
<td style="width: 36.5145%; height: 18px;">
<p><a title="System Info" href="index.shtml">Sysem Info</a></p>
<p><button onClick="location.href='login.html'">Login</button>
<p>Login Require:</p>
<ul>
<li><a title="Light Control" href="light.shtml">Light control</a></li>
<li><a title="Demo Page 1" href="demo1.shtml">Demo page 1</a></li>
<li><a title="Demo Page 2" href="demo2.shtml">Demo Page2</a></li>
</ul>
<p>Login not required:</p>
<ul>
<li><a title="Demo Page 3" href="demo3.html">Demo page 3</a></li>
<li><a title="Demo page 4" href="demo4.html">Demo Page 4</a></li>
</ul>
<!--#logout-->
</td>
<td style="width: 63.4855%; height: 18px;">
<p style="text-align: center;"><span style="color: #0000ff; font-size: 24px;"><strong>System information</strong></span></p>
<div style="margin-left:20px;">
<p>Onboard Temp.:<font color=red><!--#temp--></font></p>
<p>Free RAM Size:<font color=red><!--#freeram--></font></p>
<p>Free SD Size:<font color=red><!--#freesd--></font></p>
</div>
</td>
</tr>
</tbody>
</table>
</body></html>
<html lang="en">
<head><title>Raspberry Pi Pico W - HTTPS Session</title></head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<Script>
function logout() {
const cookies = document.cookie.split(";");
for (let i = 0; i < cookies.length; i++) {
const cookie = cookies[i];
const eqPos = cookie.indexOf("=");
const name = eqPos > -1 ? cookie.substr(0, eqPos) : cookie;
if (name=="sess_id"){
document.cookie = name + "=;expires=Thu, 01 Jan 1970 00:00:00 GMT";
}
document.location.href="index.shtml";
}
}
</Script>
<body bgcolor="white" text="black">
<h1><strong>Raspberry Pi Pico W - </strong>HTTPS Session</h1>
<table style="border-collapse: collapse; width: 1000; height: 127px;" border="1">
<tbody>
<tr style="height: 18px;">
<td style="width: 400; height: 18px;">
<p><a title="System Info" href="index.shtml">Sysem Info</a></p>
<p><button onClick="location.href='login.html'">Login</button>
<p>Login Require:</p>
<ul>
<li><a title="Light Control" href="light.shtml">Light control</a></li>
<li><a title="Demo Page 1" href="demo1.shtml">Demo page 1</a></li>
<li><a title="Demo Page 2" href="demo2.shtml">Demo Page2</a></li>
</ul>
<p>Login not required:</p>
<ul>
<li><a title="Demo Page 3" href="demo3.html">Demo page 3</a></li>
<li><a title="Demo page 4" href="demo4.html">Demo Page 4</a></li>
</ul>
<button onClick='javascript:logout();'>Logout</button>
</td>
<td style="width: 600; height: 18px;">
<h1>Login</h1>
<form name="login" action="login.cgi" method="post">
<div align="center">
<label><b>Username:</b></label>
<input type="text" placeholder="Enter Username" name="user" required><br><br>
<label><b>Password:</b></label>
<input type="password" placeholder="Enter Password" name="pass" required><br><br>
<button type="submit">Login</button>
</div>
</form>
</td>
</tr>
</table>
</body>
</html>
沒有留言:
張貼留言