WebUI 2.0.1

This commit is contained in:
Hassan DRAGA 2022-10-19 00:38:54 -04:00
parent efa10711a5
commit 937ab1cda5
24 changed files with 809 additions and 398 deletions

View File

@ -4,32 +4,39 @@
SHELL=CMD
SOURCE=../../../src
INCLUDE=../../../include
EXAMPLES=../../../examples
all: release
debug:
@echo Build WebUI (Debug Static)...
@gcc -g -m64 -o mongoose.o -I "$(INCLUDE)" -c "$(SOURCE)/mongoose.c"
# Static with Debug info
@echo Build WebUI Library (Debug Static)...
@gcc -g -m64 -o mongoose.o -I "$(INCLUDE)" -c "$(SOURCE)/mongoose.c" -Wno-stringop-overread
@gcc -g -m64 -o webui.o -I "$(INCLUDE)" -c "$(SOURCE)/webui.c"
@ar rc libwebui-2-static-x64.a webui.o mongoose.o
@ranlib libwebui-2-static-x64.a
@echo Build WebUI (Debug Dynamic)...
@gcc -g -fPIC -m64 -o mongoose.o -I "$(INCLUDE)" -c "$(SOURCE)/mongoose.c"
# Dynamic with Debug info
@echo Build WebUI Library (Debug Dynamic)...
@gcc -g -fPIC -m64 -o mongoose.o -I "$(INCLUDE)" -c "$(SOURCE)/mongoose.c" -Wno-stringop-overread
@gcc -g -fPIC -m64 -o webui.o -I "$(INCLUDE)" -c "$(SOURCE)/webui.c"
@gcc -g -shared -o webui-2-x64.dll webui.o mongoose.o -lws2_32
# Clean
@- del *.o >nul 2>&1
@echo Done.
release:
@echo Build WebUI (Release Static)...
@gcc -Os -m64 -o mongoose.o -I "$(INCLUDE)" -c "$(SOURCE)/mongoose.c"
# Static Release
@echo Build WebUI Library (Release Static)...
@gcc -Os -m64 -o mongoose.o -I "$(INCLUDE)" -c "$(SOURCE)/mongoose.c" -Wno-stringop-overread
@gcc -Os -m64 -o webui.o -I "$(INCLUDE)" -c "$(SOURCE)/webui.c"
@ar rc libwebui-2-static-x64.a webui.o mongoose.o
@ranlib libwebui-2-static-x64.a
@echo Build WebUI (Release Dynamic)...
@gcc -O3 -fPIC -m64 -o mongoose.o -I "$(INCLUDE)" -c "$(SOURCE)/mongoose.c"
# Dynamic Release
@echo Build WebUI Library (Release Dynamic)...
@gcc -O3 -fPIC -m64 -o mongoose.o -I "$(INCLUDE)" -c "$(SOURCE)/mongoose.c" -Wno-stringop-overread
@gcc -O3 -fPIC -m64 -o webui.o -I "$(INCLUDE)" -c "$(SOURCE)/webui.c"
@gcc -shared -o webui-2-x64.dll webui.o mongoose.o -lws2_32
# Clean
@- del *.o >nul 2>&1
@echo Done.
clean:

View File

@ -4,25 +4,36 @@
all: release
debug:
@echo Build WebUI (Debug Static)...
# Static with Debug info
@echo Build WebUI Library (Debug Static)...
@cl /Zi /Fomongoose.obj /c /EHsc "../../../src/mongoose.c" /I "../../../include" 1>NUL 2>&1
@cl /Zi /Fowebui.obj /c /EHsc "../../../src/webui.c" /I "../../../include" 1>NUL 2>&1
@lib /OUT:webui-2-static-x64.lib webui.obj mongoose.obj 1>NUL 2>&1
@echo Build WebUI (Debug Dynamic)...
# Dynamic with Debug info
@echo Build WebUI Library (Debug Dynamic)...
@cl /Zi /Fomongoose.obj /c /EHsc "../../../src/mongoose.c" /I "../../../include" 1>NUL 2>&1
@cl /Zi /Fowebui.obj /c /EHsc "../../../src/webui.c" /I "../../../include" 1>NUL 2>&1
@link /DLL /OUT:webui-2-x64.dll webui.obj mongoose.obj 1>NUL 2>&1
# Clean
@- del *.obj >nul 2>&1
@echo Done.
release:
@echo Build WebUI (Release Static)...
# Static Release
@echo Build WebUI Library (Release Static)...
@cl /Fomongoose.obj /c /EHsc "../../../src/mongoose.c" /I "../../../include" 1>NUL 2>&1
@cl /Fowebui.obj /c /EHsc "../../../src/webui.c" /I "../../../include" 1>NUL 2>&1
@lib /OUT:webui-2-static-x64.lib webui.obj mongoose.obj 1>NUL 2>&1
@echo Build WebUI (Release Dynamic)...
# Dynamic Release
@echo Build WebUI Library (Release Dynamic)...
@cl /Fomongoose.obj /c /EHsc "../../../src/mongoose.c" /I "../../../include" 1>NUL 2>&1
@cl /Fowebui.obj /c /EHsc "../../../src/webui.c" /I "../../../include" 1>NUL 2>&1
@link /DLL /OUT:webui-2-x64.dll webui.obj mongoose.obj 1>NUL 2>&1
# Clean
@- del *.obj >nul 2>&1
@- del *.ilk >nul 2>&1
@- del *.pdb >nul 2>&1
@- del *.exp >nul 2>&1
@echo Done.
clean:

View File

@ -4,30 +4,37 @@
SHELL=CMD
SOURCE=../../../src
INCLUDE=../../../include
EXAMPLES=../../../examples
all: release
debug:
@echo Build WebUI (Debug Static)...
# Static with Debug info
@echo Build WebUI Library (Debug Static)...
@tcc -g -m64 -o mongoose.o -I "$(INCLUDE)" -c "$(SOURCE)/mongoose.c"
@tcc -g -m64 -o webui.o -I "$(INCLUDE)" -c "$(SOURCE)/webui.c"
@tcc -m64 -ar rcs libwebui-2-static-x64.a webui.o mongoose.o
@echo Build WebUI (Debug Dynamic)...
# Dynamic with Debug info
@echo Build WebUI Library (Debug Dynamic)...
@tcc -g -fPIC -m64 -o mongoose.o -I "$(INCLUDE)" -c "$(SOURCE)/mongoose.c"
@tcc -g -fPIC -m64 -o webui.o -I "$(INCLUDE)" -c "$(SOURCE)/webui.c"
@tcc -g -shared -o webui-2-x64.dll webui.o mongoose.o -lws2_32
# Clean
@- del *.o >nul 2>&1
@echo Done.
release:
@echo Build WebUI (Release Static)...
# Static Release
@echo Build WebUI Library (Release Static)...
@tcc -m64 -o mongoose.o -I "$(INCLUDE)" -c "$(SOURCE)/mongoose.c"
@tcc -m64 -o webui.o -I "$(INCLUDE)" -c "$(SOURCE)/webui.c"
@tcc -m64 -ar rcs libwebui-2-static-x64.a webui.o mongoose.o
@echo Build WebUI (Release Dynamic)...
# Dynamic Release
@echo Build WebUI Library (Release Dynamic)...
@tcc -fPIC -m64 -o mongoose.o -I "$(INCLUDE)" -c "$(SOURCE)/mongoose.c"
@tcc -fPIC -m64 -o webui.o -I "$(INCLUDE)" -c "$(SOURCE)/webui.c"
@tcc -shared -o webui-2-x64.dll webui.o mongoose.o -lws2_32
# Clean
@- del *.o >nul 2>&1
@echo Done.
clean:

View File

@ -9,7 +9,7 @@ To build a C WebUI application, you will need to [build](https://github.com/alif
```sh
copy ..\..\build\Windows\MSVC\webui-2-static-x64.lib webui-2-static-x64.lib
rc win.rc
cl "example.c" /I "../../include" /link /MACHINE:X64 /SUBSYSTEM:WINDOWS win.res webui-2-static-x64.lib /OUT:example.exe
cl "main.c" /I "../../include" /link /MACHINE:X64 /SUBSYSTEM:WINDOWS win.res webui-2-static-x64.lib /OUT:main.exe
```
- **Build Tools for Microsoft Visual Studio - Dynamic**
@ -17,34 +17,34 @@ cl "example.c" /I "../../include" /link /MACHINE:X64 /SUBSYSTEM:WINDOWS win.res
copy ..\..\build\Windows\MSVC\webui-2-x64.dll webui-2-x64.dll
copy ..\..\build\Windows\MSVC\webui-2-x64.lib webui-2-x64.lib
rc win.rc
cl "example.c" /I "../../include" /link /MACHINE:X64 /SUBSYSTEM:WINDOWS win.res webui-2-x64.lib /OUT:example.exe
cl "main.c" /I "../../include" /link /MACHINE:X64 /SUBSYSTEM:WINDOWS win.res webui-2-x64.lib /OUT:main.exe
```
- **MinGW - Static**
```sh
copy ..\..\build\Windows\GCC\libwebui-2-static-x64.a libwebui-2-static-x64.a
windres win.rc -O coff -o win.res
gcc -static -Os -m64 -o example.exe "example.c" -I "../../include" -L. win.res -lwebui-2-static-x64 -lws2_32 -Wall -Wl,-subsystem=windows -luser32
strip --strip-all example.exe
gcc -static -Os -m64 -o main.exe "main.c" -I "../../include" -L. win.res -lwebui-2-static-x64 -lws2_32 -Wall -Wl,-subsystem=windows -luser32
strip --strip-all main.exe
```
- **MinGW - Dynamic**
```sh
copy ..\..\build\Windows\GCC\webui-2-x64.dll webui-2-x64.dll
windres win.rc -O coff -o win.res
gcc -m64 -o example.exe "example.c" -I "../../include" -L. win.res webui-2-x64.dll -lws2_32 -Wall -Wl,-subsystem=windows -luser32
gcc -m64 -o main.exe "main.c" -I "../../include" -L. win.res webui-2-x64.dll -lws2_32 -Wall -Wl,-subsystem=windows -luser32
strip --strip-all example_dynamic.exe
```
- **TCC - Static**
```sh
copy ..\..\build\Windows\TCC\libwebui-2-static-x64.a libwebui-2-static-x64.a
tcc -m64 -o example.exe "example.c" -I "../../include" -L. -lwebui-2-static-x64 -lws2_32 -Wall -Wl,-subsystem=windows -luser32
tcc -m64 -o main.exe "main.c" -I "../../include" -L. -lwebui-2-static-x64 -lws2_32 -Wall -Wl,-subsystem=windows -luser32
```
- **TCC - Dynamic**
```sh
copy ..\..\build\Windows\TCC\webui-2-x64.dll webui-2-x64.dll
tcc -impdef webui-2-x64.dll -o webui-2-x64.def
tcc -m64 -o example_dynamic.exe "example.c" -I "../../include" -L. webui-2-x64.def -lws2_32 -Wall -Wl,-subsystem=windows -luser32
tcc -m64 -o example_dynamic.exe "main.c" -I "../../include" -L. webui-2-x64.def -lws2_32 -Wall -Wl,-subsystem=windows -luser32
```

View File

@ -0,0 +1,51 @@
# WebUI Library 2.x
# C99 Example
# Windows - GCC
SHELL=CMD
LIB=../../../../build/Windows/GCC
INCLUDE=../../../../include
SOURCE=../..
all: release
debug:
# Build Lib
@cd "$(LIB)" && $(MAKE) debug
# Static with Debug info
@echo Build C99 Example (Debug Static)...
@windres win.rc -O coff -o win.res
@gcc -g -static -m64 -o main.exe "$(SOURCE)/main.c" -I "$(INCLUDE)" -L "$(LIB)" win.res -lwebui-2-static-x64 -lws2_32 -Wall -Wl,-subsystem=console -luser32
# Dynamic with Debug info
@echo Build C99 Example (Debug Dynamic)...
@windres win.rc -O coff -o win.res
@gcc -g -m64 -o main-dyn.exe "$(SOURCE)/main.c" -I "$(INCLUDE)" -L "$(LIB)" win.res "$(LIB)/webui-2-x64.dll" -lws2_32 -Wall -Wl,-subsystem=console -luser32
# Clean
@- del *.o >nul 2>&1
@- del *.res >nul 2>&1
@echo Done.
release:
# Build Lib
@cd "$(LIB)" && $(MAKE)
# Static Release
@echo Build C99 Example (Release Static)...
@windres win.rc -O coff -o win.res
@gcc -static -Os -m64 -o main.exe "$(SOURCE)/main.c" -I "$(INCLUDE)" -L "$(LIB)" win.res -lwebui-2-static-x64 -lws2_32 -Wall -Wl,-subsystem=windows -luser32
@strip --strip-all main.exe
# Dynamic Release
@echo Build C99 Example (Release Dynamic)...
@windres win.rc -O coff -o win.res
@gcc -m64 -o main-dyn.exe "$(SOURCE)/main.c" -I "$(INCLUDE)" -L "$(LIB)" win.res "$(LIB)/webui-2-x64.dll" -lws2_32 -Wall -Wl,-subsystem=windows -luser32
@strip --strip-all main-dyn.exe
# Clean
@- del *.o >nul 2>&1
@- del *.res >nul 2>&1
@echo Done.
clean:
- del *.o >nul 2>&1
- del *.dll >nul 2>&1
- del *.a >nul 2>&1
- del *.exe >nul 2>&1
- del *.res >nul 2>&1

View File

Before

Width:  |  Height:  |  Size: 105 KiB

After

Width:  |  Height:  |  Size: 105 KiB

View File

@ -0,0 +1,49 @@
# WebUI Library 2.x
# C99 Example
# Windows - Microsoft Visual C
SHELL=CMD
_LIB=../../../../build/Windows/MSVC/
_INCLUDE=../../../../include/
_SOURCE=../../
all: release
debug:
# Build Lib
@cd "$(_LIB)" && $(MAKE) debug
# Static with Debug info
@echo Build C99 Example (Debug Static)...
@rc win.rc
@cl /Zi "$(_SOURCE)/main.c" /I "$(_INCLUDE)" /link /LIBPATH:"$(_LIB)" /MACHINE:X64 /SUBSYSTEM:CONSOLE win.res webui-2-static-x64.lib /OUT:main.exe
# Dynamic with Debug info
@echo Build C99 Example (Debug Dynamic)...
@rc win.rc
@cl /Zi "$(_SOURCE)/main.c" /I "$(_INCLUDE)" /link /LIBPATH:"$(_LIB)" /MACHINE:X64 /SUBSYSTEM:CONSOLE win.res webui-2-x64.lib /OUT:main-dyn.exe
release:
# Build Lib
@cd "$(_LIB)" && $(MAKE)
# Static Release
@echo Build C99 Example (Release Static)...
@rc win.rc
@cl "$(_SOURCE)/main.c" /I "$(_INCLUDE)" /link /LIBPATH:"$(_LIB)" /MACHINE:X64 /SUBSYSTEM:WINDOWS win.res webui-2-static-x64.lib /OUT:main.exe
# Dynamic Release
@echo Build C99 Example (Release Dynamic)...
@rc win.rc
@cl "$(_SOURCE)/main.c" /I "$(_INCLUDE)" /link /LIBPATH:"$(_LIB)" /MACHINE:X64 /SUBSYSTEM:WINDOWS win.res webui-2-x64.lib /OUT:main-dyn.exe
# Clean
@- del *.res >nul 2>&1
@- del *.obj >nul 2>&1
@- del *.exp >nul 2>&1
@- del *.lib >nul 2>&1
@echo Done.
clean:
- del *.obj >nul 2>&1
- del *.ilk >nul 2>&1
- del *.pdb >nul 2>&1
- del *.exp >nul 2>&1
- del *.exe >nul 2>&1
- del *.lib >nul 2>&1
- del *.res >nul 2>&1

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

View File

@ -0,0 +1,24 @@
id ICON "win.ico"
1 VERSIONINFO
FILEVERSION 1,0,0,0
PRODUCTVERSION 1,0,0,0
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904E4"
BEGIN
VALUE "CompanyName", "My Business Name"
VALUE "LegalCopyright", "My Business Name"
VALUE "FileDescription", "My WebUI Application"
VALUE "InternalName", "MyApplication"
VALUE "ProductName", "My Application"
VALUE "FileVersion", "1.0"
VALUE "OriginalFilename", "webui.exe"
VALUE "ProductVersion", "1.0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1252
END
END

View File

@ -0,0 +1,43 @@
# WebUI Library 2.x
# C99 Example
# Windows - Tiny C Compiler
SHELL=CMD
LIB=../../../../build/Windows/TCC/
INCLUDE=../../../../include/
SOURCE=../../
all: release
debug:
# Build Lib
@cd "$(LIB)" && $(MAKE) debug
# Static with Debug info
@echo Build C99 Example (Debug Static)...
@tcc -g -m64 -o main.exe "$(SOURCE)/main.c" -I "$(INCLUDE)" -L "$(LIB)" -lwebui-2-static-x64 -lws2_32 -Wall -Wl,-subsystem=console -luser32
# Dynamic with Debug info
@echo Build C99 Example (Debug Dynamic)...
@tcc -g -m64 -o main-dyn.exe "$(SOURCE)/main.c" -I "$(INCLUDE)" -L "$(LIB)" "$(LIB)/webui-2-x64.def" -lws2_32 -Wall -Wl,-subsystem=console -luser32
# Clean
@- del *.o >nul 2>&1
@- del *.def >nul 2>&1
@echo Done.
release:
# Build Lib
@cd "$(LIB)" && $(MAKE)
# Static Release
@echo Build C99 Example (Release Static)...
@tcc -m64 -o main.exe "$(SOURCE)/main.c" -I "$(INCLUDE)" -L "$(LIB)" -lwebui-2-static-x64 -lws2_32 -Wall -Wl,-subsystem=windows -luser32
# Dynamic Release
@echo Build C99 Example (Release Dynamic)...
@tcc -m64 -o main-dyn.exe "$(SOURCE)/main.c" -I "$(INCLUDE)" -L "$(LIB)" "$(LIB)/webui-2-x64.def" -lws2_32 -Wall -Wl,-subsystem=windows -luser32
# Clean
@- del *.o >nul 2>&1
@- del *.def >nul 2>&1
@echo Done.
clean:
- del *.o >nul 2>&1
- del *.def >nul 2>&1
- del *.exe >nul 2>&1

Binary file not shown.

Before

Width:  |  Height:  |  Size: 108 KiB

View File

@ -1,7 +1,7 @@
/*
WebUI Library 2.x
C99 Example
http://webui.me
https://github.com/alifcommunity/webui
@ -16,18 +16,18 @@ webui_window_t* my_window;
// UI HTML
const char* my_html = "<!DOCTYPE html>"
"<html><head><title>WebUI 2.0 Example</title>"
"<html><head><title>WebUI 2 - C99 Example</title>"
"<style>body{color: white; background: #0F2027;"
"background: -webkit-linear-gradient(to right, #2C5364, #203A43, #0F2027);"
"background: linear-gradient(to right, #2C5364, #203A43, #0F2027);"
"text-align:center; font-size: 18px; font-family: sans-serif;}</style></head><body>"
"<h1>WebUI 2.0 Example</h1><br>"
"<h1>WebUI 2 - C99 Example</h1><br>"
"<input type=\"password\" id=\"MyInput\"><br><br>"
"<button id=\"MyButton1\">Check Password</button> - <button id=\"MyButton2\">Exit</button>"
"</body></html>";
// Check the password function
void check_the_password(const webui_event_t e) {
void check_the_password(webui_event_t* e) {
// This function get called every time the user click on "MyButton1"
@ -64,10 +64,11 @@ void check_the_password(const webui_event_t e) {
webui_run_js(my_window, &js);
}
// Free data resources
webui_free_js(&js);
}
void close_the_application(const webui_event_t e){
void close_the_application(webui_event_t* e){
// Close all opened windows
webui_exit();

View File

@ -1,99 +0,0 @@
// WebUI Library 2.0.0
//
// http://webui.me
// https://github.com/alifcommunity/webui
//
// Licensed under GNU General Public License v3.0.
// Copyright (C)2022 Hassan DRAGA <https://github.com/hassandraga>.
package main
//--[WebUI]-------------------------------------
import (
"C"
"fmt"
"syscall"
"unsafe"
)
var (
dll_webui, _ = syscall.LoadLibrary("webui-2-x64.dll")
//webui_window_t* webui_new_window();
dll_webui_new_window, _ = syscall.GetProcAddress(dll_webui, "webui_new_window")
// bool webui_show(webui_window_t* win, const char* html, unsigned int browser);
dll_webui_show, _ = syscall.GetProcAddress(dll_webui, "webui_show")
// void webui_loop();
dll_webui_loop, _ = syscall.GetProcAddress(dll_webui, "webui_loop")
)
func webui_new_window() (result uintptr) {
var arg uintptr = 0
ret, _, _ := syscall.Syscall(uintptr(dll_webui_new_window), arg, 0, 0, 0)
result = ret
return
}
func webui_show(win uintptr, html string, browser uint) (result bool) {
chtml := C.CString(html)
var arg uintptr = 3
ret, _, _ := syscall.Syscall(uintptr(dll_webui_show), arg, win, uintptr(unsafe.Pointer((chtml))), uintptr(browser))
if ret == 0x00 {
return false
}
return true
}
func webui_loop() {
var arg uintptr = 0
syscall.Syscall(uintptr(dll_webui_loop), arg, 0, 0, 0)
}
func ini() {
defer syscall.FreeLibrary(dll_webui)
}
func webui_test() (res int) {
return 0
}
//----------------------------------------------
// Application Example
const my_html string = `<!DOCTYPE html>
<html>
<head>
<title>WebUI 2.0 Example</title>
<style>
body {
color: white;
background: #0F2027;
background: -webkit-linear-gradient(to right, #2C5364, #203A43, #0F2027);
background: linear-gradient(to right, #2C5364, #203A43, #0F2027);
text-align: center;
font-size: 18px;
font-family: sans-serif;
}
</style>
</head>
<body>
<h1>WebUI 2.0 Example</h1>
<br>
<input type="password" id="MyInput">
<br>
<br>
<button id="MyButton1">Check Password</button> - <button id="MyButton2">Exit</button>
</body>
</html>`
func main() {
var my_window = webui_new_window()
webui_show(my_window, my_html, 0)
webui_loop()
fmt.Print("Bye.")
}

3
examples/Go/go.mod Normal file
View File

@ -0,0 +1,3 @@
module github.com/alifcommunity/webui
go 1.19

92
examples/Go/main.go Normal file
View File

@ -0,0 +1,92 @@
// WebUI Go Example
// https://github.com/alifcommunity/webui
package main
import (
"fmt"
"github.com/alifcommunity/webui/webui"
)
const my_html string = `<!DOCTYPE html>
<html>
<head>
<title>WebUI 2 - Go Example</title>
<style>
body {
color: white;
background: #0F2027;
background: -webkit-linear-gradient(to right, #2C5364, #203A43, #0F2027);
background: linear-gradient(to right, #2C5364, #203A43, #0F2027);
text-align: center;
font-size: 18px;
font-family: sans-serif;
}
</style>
</head>
<body>
<h1>WebUI 2 - Go Example</h1>
<br>
<input type="password" id="MyInput">
<br>
<br>
<button id="CheckPassword">Check Password</button> - <button id="Exit">Exit</button>
</body>
</html>`
func Exit(e webui.Event) {
webui.Exit()
}
func Check(e webui.Event) {
// Script to get the text value
js := webui.JavaScript{
Timeout: 10,
Script: "return document.getElementById(\"MyInput\").value;",
}
// Run the script
webui.RunJavaScript(e.Window, &js)
// Check if any error
if !js.Error {
fmt.Printf("Password: %s\n", js.Data)
// Check the password
if js.Data == "123456" {
js.Script = "alert('Good. Password is correct.')"
webui.RunJavaScript(e.Window, &js)
} else {
js.Script = "alert('Sorry. Wrong password.')"
webui.RunJavaScript(e.Window, &js)
}
} else {
// There is an error in our script
fmt.Printf("JavaScript Error: %s\n", js.Data)
}
}
func main() {
// New window
var my_window = webui.NewWindow()
// Bind
webui.Bind(my_window, "CheckPassword", Check)
webui.Bind(my_window, "Exit", Exit)
// Show window
webui.Show(my_window, my_html, 0)
// Loop
webui.Loop()
fmt.Println("Bye.")
}

111
examples/Go/webui/webui.go Normal file
View File

@ -0,0 +1,111 @@
package webui
// WebUI Library 2.0.1
//
// http://webui.me
// https://github.com/alifcommunity/webui
//
// Licensed under GNU General Public License v3.0.
// Copyright (C)2022 Hassan DRAGA <https://github.com/hassandraga>.
/*
#cgo CFLAGS: -I ./ -I ../../../include
#cgo windows LDFLAGS: -L ./ -L ../../../build/Windows/GCC/ -lwebui-2-static-x64 -lws2_32
#cgo darwin LDFLAGS: -L ./ -L ../../../build/macOS/Clang/ -lwebui-2-static-x64
#cgo linux LDFLAGS: -L ./ -L ../../../build/Linux/GCC/ -lwebui-2-static-x64
#include <webui.h>
extern void webui_go_handler(webui_window_t* _window, unsigned int _element_id, unsigned int _window_id, char* _element_name);
static void webui_bind_go_handler(webui_event_t* e) {
webui_go_handler(e->window, e->element_id, e->window_id, e->element_name);
}
static unsigned int webui_bind_go(webui_window_t* win, const char* element) {
return webui_bind(win, element, webui_bind_go_handler);
}
*/
import (
"C"
)
// Event Struct
type Event struct {
Window *C.webui_window_t
ElementID uint
WindowID uint
ElementName string
}
// JavaScript Struct
type JavaScript struct {
Timeout uint
Script string
Error bool
Length uint
Data string
}
// User Go Callback Functions list
var fun_list [64][256]func(Event)
//export webui_go_handler
func webui_go_handler(_window *C.webui_window_t, _element_id C.uint, _window_id C.uint, _element_name *C.char) {
var window *C.webui_window_t = (*C.webui_window_t)(_window)
var element_id uint = uint(_element_id)
var window_id uint = uint(_window_id)
var element_name string = C.GoString(_element_name)
e := Event{
Window: window,
ElementID: element_id,
WindowID: window_id,
ElementName: element_name,
}
fun_list[window_id][element_id](e)
}
func RunJavaScript(window *C.webui_window_t, js *JavaScript) {
c_js := C.webui_javascript_py_t{
script: C.CString(js.Script),
timeout: 30, // uint(js.Timeout),
error: C.bool(false),
// length: uint(0),
// data: C.CString(nil),
}
C.webui_run_js_py(window, &c_js)
js.Error = bool(c_js.error)
js.Data = C.GoString(c_js.data)
}
func NewWindow() *C.webui_window_t {
return C.webui_new_window()
}
func Exit() {
C.webui_exit()
}
func Show(window *C.webui_window_t, html string, browser uint) {
c_html := C.CString(html)
C.webui_show(window, c_html, C.uint(browser))
}
func Loop() {
C.webui_loop()
}
func Bind(window *C.webui_window_t, element string, callback func(Event)) {
c_element := C.CString(element)
var window_id uint = uint(C._webui_window_get_number(window))
var cb_index uint = uint(C.webui_bind_go(window, c_element))
fun_list[window_id][cb_index] = callback
}

View File

@ -3,11 +3,6 @@
To use WebUI in your Python script, you will need to [build](https://github.com/alifcommunity/webui/tree/main/build) the WebUI library first using your favorite C compiler, then copy into this folder the dynamic WebUI library, `webui-2-x64.dll` on Windows, or `webui-2-x64.so` on Linux.
**Requirement:**
- webui.py
- WebUI Dynamic Library
```sh
python example.py
python main.py
```

View File

@ -1,4 +1,6 @@
# WebUI Library 2.0.0
# WebUI Library 2.x
# Python Example
#
# http://webui.me
# https://github.com/alifcommunity/webui
@ -6,19 +8,21 @@
# Licensed under GNU General Public License v3.0.
# Copyright (C)2022 Hassan DRAGA <https://github.com/hassandraga>.
# [!] IMPORTANT
# Please build a dynamic version of WebUI library using
# your favorite C compiler, then copy file 'webui-2-x64'
# into this folder.
import webui
import webui # Importing 'webui.py' file
# Set the WebUI dynamic library location (Optional)
# Default is the same folder, otherwise use this option
webui.set_library_path("../../build/Windows/MSVC")
# Create a global window object
MyWindow = webui.window()
# HTML
my_html = """
<!DOCTYPE html>
<html>
<head>
<title>WebUI 2.0 Example</title>
<title>WebUI 2 - Python Example</title>
<style>
body{
color: white;
@ -32,10 +36,11 @@ my_html = """
</style>
</head>
<body>
<h1>WebUI 2.0 Example</h1>
<h1>WebUI 2 - Python Example</h1>
<br>
<input type="password" id="MyInput">
<br><br>
<br>
<br>
<button id="MyButton1">Check Password</button> - <button id="MyButton2">Exit</button>
</body>
</html>
@ -68,17 +73,19 @@ def check_the_password(e : webui.event):
def close_the_application(e : webui.event):
webui.exit()
# Create a window object
MyWindow = webui.window()
def main():
# Bind am HTML element ID with a python function
MyWindow.bind('MyButton1', check_the_password)
MyWindow.bind('MyButton2', close_the_application)
# Bind am HTML element ID with a python function
MyWindow.bind('MyButton1', check_the_password)
MyWindow.bind('MyButton2', close_the_application)
# Show the window
MyWindow.show(my_html)
# Show the window
MyWindow.show(my_html)
# Wait until all windows are closed
webui.loop()
# Wait until all windows are closed
webui.loop()
print('Bye.')
print('Bye.')
if __name__ == "__main__":
main()

View File

@ -1,4 +1,4 @@
# WebUI Library 2.0.0
# WebUI Library 2.0.1
#
# http://webui.me
# https://github.com/alifcommunity/webui
@ -6,18 +6,15 @@
# Licensed under GNU General Public License v3.0.
# Copyright (C)2022 Hassan DRAGA <https://github.com/hassandraga>.
# [!] IMPORTANT
# Please build a dynamic version of WebUI library using
# your favorite C compiler, then copy file 'webui-2-x64'
# into this folder.
import os
import platform
import sys
import ctypes
from ctypes import *
import shutil
lib = None
WebUI = None
WebUI_Path = os.getcwd()
# Event
class event:
@ -50,17 +47,17 @@ class window:
cb_fun_list = [64]
def __init__(self):
global lib
global WebUI
try:
# Load WebUI Shared Library
load_library()
# Check library if correctly loaded
if lib is None:
if WebUI is None:
print('Please download the latest library from https://webui.me')
sys.exit(1)
# Create new WebUI window
webui_wrapper = None
webui_wrapper = lib.webui_new_window
webui_wrapper = WebUI.webui_new_window
webui_wrapper.restype = c_void_p
self.window = c_void_p(webui_wrapper())
# Initializing events() to be called from WebUI Library
@ -71,9 +68,9 @@ class window:
sys.exit(1)
def __del__(self):
global lib
if self.window is not None and lib is not None:
lib.webui_close(self.window)
global WebUI
if self.window is not None and WebUI is not None:
WebUI.webui_close(self.window)
def events(self, element_id, window_id, element_name):
if self.cb_fun_list[int(element_id)] is None:
@ -86,39 +83,39 @@ class window:
self.cb_fun_list[element_id](e)
def bind(self, element, func):
global lib
global WebUI
if self.window is None:
err_window_is_none('bind')
return
if lib is None:
if WebUI is None:
err_library_not_found('bind')
return
cb_index = int(lib.webui_bind_py(self.window, element.encode('utf-8'), self.c_events))
cb_index = int(WebUI.webui_bind_py(self.window, element.encode('utf-8'), self.c_events))
self.cb_fun_list.insert(cb_index, func)
def show(self, html):
global lib
global WebUI
if self.window is None:
err_window_is_none('show')
return
if lib is None:
if WebUI is None:
err_library_not_found('show')
return
lib.webui_show(self.window, html.encode('utf-8'))
WebUI.webui_show(self.window, html.encode('utf-8'))
def close(self):
global lib
if lib is None:
global WebUI
if WebUI is None:
err_library_not_found('close')
return
lib.webui_close(self.window)
WebUI.webui_close(self.window)
def run_js(self, script, timeout = 0) -> javascript:
global lib
global WebUI
if self.window is None:
err_window_is_none('show')
return
if lib is None:
if WebUI is None:
err_library_not_found('show')
return
# Create Struct
@ -137,56 +134,96 @@ class window:
res.length = 7
res.data = "UNKNOWN"
# Run JavaScript
lib.webui_run_js_py(self.window, ctypes.byref(js))
WebUI.webui_run_js_py(self.window, ctypes.byref(js))
res.length = int(js.length)
res.data = js.data.decode('utf-8')
res.error = js.error
return res
# Exit app
def load_library():
global lib
def get_library_path() -> str:
global WebUI_Path
if platform.system() == 'Darwin':
lib = ctypes.CDLL('webui-2-x64.dylib')
if lib is None:
print("WebUI Error: Failed to load 'webui-2-x64.dylib' library.")
file = '/webui-2-x64.dylib'
path = os.getcwd() + file
if os.path.exists(path):
return path
path = WebUI_Path + file
if os.path.exists(path):
return path
return path
elif platform.system() == 'Windows':
file = '\webui-2-x64.dll'
path = os.getcwd() + file
if os.path.exists(path):
return path
path = WebUI_Path + file
if os.path.exists(path):
return path
return path
elif platform.system() == 'Linux':
file = '/webui-2-x64.so'
path = os.getcwd() + file
if os.path.exists(path):
return path
path = WebUI_Path + file
if os.path.exists(path):
return path
return path
else:
return ""
# Load WebUI Dynamic Library
def load_library():
global WebUI
global WebUI_Path
if platform.system() == 'Darwin':
WebUI = ctypes.CDLL(get_library_path())
if WebUI is None:
print("WebUI Error: Failed to load WebUI dynamic library.")
elif platform.system() == 'Windows':
if sys.version_info.major == 3 and sys.version_info.minor <= 8:
os.chdir(os.getcwd())
os.add_dll_directory(os.getcwd())
lib = ctypes.CDLL('webui-2-x64.dll')
WebUI = ctypes.CDLL(get_library_path())
else:
os.chdir(os.getcwd())
os.add_dll_directory(os.getcwd())
lib = cdll.LoadLibrary('webui-2-x64.dll')
if lib is None:
print("WebUI Error: Failed to load 'webui-2-x64.dll' library.")
WebUI = cdll.LoadLibrary(get_library_path())
if WebUI is None:
print("WebUI Error: Failed to load WebUI dynamic library.")
elif platform.system() == 'Linux':
os.chdir(os.getcwd())
lib = ctypes.CDLL(os.getcwd() + '/webui-2-x64.so')
if lib is None:
print("WebUI Error: Failed to load 'webui-2-x64.so' library.")
WebUI = ctypes.CDLL(get_library_path())
if WebUI is None:
print("WebUI Error: Failed to load WebUI dynamic library.")
else:
print("WebUI Error: Unsupported OS")
# Exit app
def exit():
global lib
if lib is None:
global WebUI
if WebUI is None:
err_library_not_found('exit')
return
lib.webui_exit()
WebUI.webui_exit()
# Wait until all windows get closed
def loop():
global lib
if lib is None:
global WebUI
if WebUI is None:
err_library_not_found('loop')
return
lib.webui_loop()
WebUI.webui_loop()
try:
shutil.rmtree(os.getcwd() + '/__pycache__/')
except OSError:
pass
def err_library_not_found(f):
print('WebUI ' + f + '(): Library Not Found.')
def err_window_is_none(f):
print('WebUI ' + f + '(): Window is None.')
def set_library_path(Path):
global WebUI_Path
WebUI_Path = Path

View File

@ -15,7 +15,7 @@
// Alternatively, you can license this software under a commercial
// license, as set out in https://www.mongoose.ws/licensing/
//
// SPDX-License-Identifier: GPL-2.0 or commercial
// SPDX-License-Identifier: GPL-2.0-only or commercial
#ifndef MONGOOSE_H
#define MONGOOSE_H
@ -70,6 +70,9 @@ extern "C" {
#endif
#endif // !defined(MG_ARCH)
// http://esr.ibiblio.org/?p=5095
#define MG_BIG_ENDIAN (*(uint16_t *)"\0\xff" < 0x100)
@ -98,10 +101,6 @@ extern "C" {
#include <nx_port.h>
#include <tx_port.h>
#ifdef __REDLIB__
#define va_copy(d, s) __builtin_va_copy(d, s)
#endif
#define PATH_MAX FX_MAXIMUM_PATH
#define MG_DIRSEP '\\'
@ -294,6 +293,12 @@ struct timeval {
#define EINTR pdFREERTOS_ERRNO_EINTR
#endif
// FreeRTOS-TCP uses non-standard semantics for listen() backlog size. It is
// not a backlog size for pending SYN connections, but a max socket number
#ifndef MG_SOCK_LISTEN_BACKLOG_SIZE
#define MG_SOCK_LISTEN_BACKLOG_SIZE 128
#endif
#endif // MG_ARCH == MG_ARCH_FREERTOS_TCP
@ -563,13 +568,6 @@ typedef int socklen_t;
#define sleep(x) Sleep(x)
#define mkdir(a, b) _mkdir(a)
#ifndef va_copy
#ifdef __va_copy
#define va_copy __va_copy
#else
#define va_copy(x, y) (x) = (y)
#endif
#endif
#ifndef S_ISDIR
#define S_ISDIR(x) (((x) &_S_IFMT) == _S_IFDIR)
#endif
@ -583,12 +581,12 @@ typedef int socklen_t;
#if MG_ARCH == MG_ARCH_ZEPHYR
#include <zephyr.h>
#include <zephyr/kernel.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <net/socket.h>
#include <zephyr/net/socket.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
@ -599,6 +597,9 @@ typedef int socklen_t;
#include <time.h>
#define MG_PUTCHAR(x) printk("%c", x)
#ifndef strdup
#define strdup(s) ((char *) mg_strdup(mg_str(s)).ptr)
#endif
#define strerror(x) zsock_gai_strerror(x)
#define FD_CLOEXEC 0
#define F_SETFD 0
@ -655,7 +656,7 @@ int sscanf(const char *, const char *, ...);
#endif
#ifndef MG_ENABLE_MD5
#define MG_ENABLE_MD5 0
#define MG_ENABLE_MD5 1
#endif
// Set MG_ENABLE_WINSOCK=0 for Win32 builds with external IP stack (like LWIP)
@ -993,6 +994,7 @@ enum {
MG_EV_RESOLVE, // Host name is resolved NULL
MG_EV_CONNECT, // Connection established NULL
MG_EV_ACCEPT, // Connection accepted NULL
MG_EV_TLS_HS, // TLS handshake succeeded NULL
MG_EV_READ, // Data received from socket long *bytes_read
MG_EV_WRITE, // Data written to socket long *bytes_written
MG_EV_CLOSE, // Connection closed NULL
@ -1005,7 +1007,7 @@ enum {
MG_EV_MQTT_MSG, // MQTT PUBLISH received struct mg_mqtt_message *
MG_EV_MQTT_OPEN, // MQTT CONNACK received int *connack_status_code
MG_EV_SNTP_TIME, // SNTP time received uint64_t *epoch_millis
MG_EV_USER, // Starting ID for user events
MG_EV_USER // Starting ID for user events
};
@ -1094,7 +1096,7 @@ struct mg_connection *mg_wrapfd(struct mg_mgr *mgr, int fd,
void mg_connect_resolved(struct mg_connection *);
bool mg_send(struct mg_connection *, const void *, size_t);
size_t mg_printf(struct mg_connection *, const char *fmt, ...);
size_t mg_vprintf(struct mg_connection *, const char *fmt, va_list ap);
size_t mg_vprintf(struct mg_connection *, const char *fmt, va_list *ap);
char *mg_straddr(struct mg_addr *, char *, size_t);
bool mg_aton(struct mg_str str, struct mg_addr *addr);
char *mg_ntoa(const struct mg_addr *addr, char *buf, size_t len);

View File

@ -1,5 +1,5 @@
/*
WebUI Library 2.0.0
WebUI Library 2.0.1
http://webui.me
https://github.com/alifcommunity/webui
@ -26,7 +26,7 @@
#define WEBUI_MAX_ARRAY (32) // Max thread, servers, windows..
#define WEBUI_MIN_PORT (8080) // Minimum socket port
#define WEBUI_MAX_PORT (8335) // Should be less than 65535
#define WEBUI_MAX_BUF (512000) // 512 Kb max dynamic memory
#define WEBUI_MAX_BUF (512000) // 512 Kb max dynamic memory allocation
#define WEBUI_DEFAULT_PATH "." // Default root path
// -- C STD -----------------------------------
@ -73,11 +73,14 @@
// -- macOS -----------------------------------
// ...
struct webui_window_t;
typedef struct webui_event_t {
unsigned int window_id;
unsigned int element_id;
char* element_name;
struct webui_window_t* window;
} webui_event_t;
@ -92,8 +95,9 @@ typedef struct webui_window_core_t {
unsigned int server_port;
bool is_bind_all;
char* url;
void (*cb_all[1]) (webui_event_t e);
void (*cb_all[1]) (webui_event_t* e);
const char* html;
const char* html_cpy;
const char* icon;
const char* icon_type;
unsigned int CurrentBrowser;
@ -189,7 +193,7 @@ typedef struct webui_t {
bool use_timeout;
bool timeout_extra;
bool exit_now;
char* run_responses[WEBUI_MAX_ARRAY];
const char* run_responses[WEBUI_MAX_ARRAY];
bool run_done[WEBUI_MAX_ARRAY];
bool run_error[WEBUI_MAX_ARRAY];
unsigned int run_last_id;
@ -198,7 +202,7 @@ typedef struct webui_t {
webui_browser_t browser;
webui_runtime_t runtime;
bool initialized;
void (*cb[WEBUI_MAX_ARRAY]) (webui_event_t e);
void (*cb[WEBUI_MAX_ARRAY]) (webui_event_t* e);
void (*cb_py[WEBUI_MAX_ARRAY])(unsigned int, unsigned int, char*);
char* executable_path;
@ -228,6 +232,7 @@ EXPORT bool webui_any_window_is_open();
EXPORT void webui_set_timeout(unsigned int second);
EXPORT webui_window_t* webui_new_window();
EXPORT bool webui_show(webui_window_t* win, const char* html, unsigned int browser);
EXPORT bool webui_copy_show(webui_window_t* win, const char* html, unsigned int browser);
EXPORT void webui_set_icon(webui_window_t* win, const char* icon_s, const char* type_s);
EXPORT void webui_allow_multi_access(webui_window_t* win, bool status);
EXPORT bool webui_set_root_folder(webui_window_t* win, const char* path);
@ -235,8 +240,8 @@ EXPORT const char* webui_new_server(webui_window_t* win, const char* path, const
EXPORT void webui_close(webui_window_t* win);
EXPORT bool webui_is_show(webui_window_t* win);
EXPORT void webui_run_js(webui_window_t* win, webui_javascript_t* javascript);
EXPORT unsigned int webui_bind(webui_window_t* win, const char* element, void (*func) (webui_event_t e));
EXPORT void webui_bind_all(webui_window_t* win, void (*func) (webui_event_t e));
EXPORT unsigned int webui_bind(webui_window_t* win, const char* element, void (*func) (webui_event_t* e));
EXPORT void webui_bind_all(webui_window_t* win, void (*func) (webui_event_t* e));
EXPORT bool webui_open(webui_window_t* win, const char* url, unsigned int browser);
EXPORT void webui_free_js(webui_javascript_t* javascript);
EXPORT void webui_runtime(webui_window_t* win, unsigned int runtime);
@ -259,14 +264,14 @@ EXPORT char* _webui_get_current_path();
EXPORT void _webui_window_receive(webui_window_t* win, const char* packet, size_t len);
EXPORT void _webui_window_send(webui_window_t* win, char* packet, size_t packets_size);
EXPORT void _webui_window_event(webui_window_t* win, char* element_id, char* element);
EXPORT unsigned int _webui_window_get_window_number(webui_window_t* win);
EXPORT unsigned int _webui_window_get_number(webui_window_t* win);
EXPORT void _webui_window_open(webui_window_t* win, char* link, unsigned int browser);
EXPORT int _webui_cmd_sync(char* cmd);
EXPORT int _webui_cmd_async(char* cmd);
EXPORT int _webui_run_browser(webui_window_t* win, char* cmd);
EXPORT void _webui_browser_clean();
EXPORT bool _webui_browser_exist(webui_window_t* win, unsigned int browser);
EXPORT char* _webui_browser_get_temp_path(unsigned int browser);
EXPORT const char* _webui_browser_get_temp_path(unsigned int browser);
EXPORT bool _webui_folder_exist(char* folder);
EXPORT bool _webui_browser_create_profile_folder(webui_window_t* win, unsigned int browser);
EXPORT bool _webui_browser_start_edge(webui_window_t* win, const char* address);

View File

@ -15,7 +15,7 @@
// Alternatively, you can license this software under a commercial
// license, as set out in https://www.mongoose.ws/licensing/
//
// SPDX-License-Identifier: GPL-2.0 or commercial
// SPDX-License-Identifier: GPL-2.0-only or commercial
#include "mongoose.h"
@ -90,9 +90,9 @@ int mg_base64_encode(const unsigned char *p, int n, char *to) {
}
int mg_base64_decode(const char *src, int n, char *dst) {
const char *end = src + n;
const char *end = src == NULL ? NULL : src + n; // Cannot add to NULL
int len = 0;
while (src + 3 < end) {
while (src != NULL && src + 3 < end) {
int a = mg_b64rev(src[0]), b = mg_b64rev(src[1]), c = mg_b64rev(src[2]),
d = mg_b64rev(src[3]);
if (a == 64 || a < 0 || b == 64 || b < 0 || c < 0 || d < 0) return 0;
@ -559,7 +559,9 @@ static size_t mg_dtoa(char *dst, size_t dstlen, double d, int width) {
}
while (n > 0 && buf[s + n - 1] == '0') n--; // Trim trailing zeros
if (n > 0 && buf[s + n - 1] == '.') n--; // Trim trailing dot
buf[s + n] = '\0';
n += s;
if (n >= (int) sizeof(buf)) n = (int) sizeof(buf) - 1;
buf[n] = '\0';
return mg_snprintf(dst, dstlen, "%s", buf);
}
@ -1540,7 +1542,7 @@ static void mg_http_parse_headers(const char *s, const char *end,
int mg_http_parse(const char *s, size_t len, struct mg_http_message *hm) {
int is_response, req_len = mg_http_get_request_len((unsigned char *) s, len);
const char *end = s + req_len, *qs;
const char *end = s == NULL ? NULL : s + req_len, *qs; // Cannot add to NULL
struct mg_str *cl;
memset(hm, 0, sizeof(*hm));
@ -1605,13 +1607,10 @@ int mg_http_parse(const char *s, size_t len, struct mg_http_message *hm) {
}
static void mg_http_vprintf_chunk(struct mg_connection *c, const char *fmt,
va_list ap) {
va_list *ap) {
size_t len = c->send.len;
va_list tmp;
mg_send(c, " \r\n", 10);
va_copy(tmp, ap);
mg_vxprintf(mg_pfn_iobuf, &c->send, fmt, &tmp);
va_end(tmp);
mg_vxprintf(mg_pfn_iobuf, &c->send, fmt, ap);
if (c->send.len >= len + 10) {
mg_snprintf((char *) c->send.buf + len, 9, "%08lx", c->send.len - len - 10);
c->send.buf[len + 8] = '\r';
@ -1623,7 +1622,7 @@ static void mg_http_vprintf_chunk(struct mg_connection *c, const char *fmt,
void mg_http_printf_chunk(struct mg_connection *c, const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
mg_http_vprintf_chunk(c, fmt, ap);
mg_http_vprintf_chunk(c, fmt, &ap);
va_end(ap);
}
@ -1903,12 +1902,12 @@ static void printdirentry(const char *name, void *userdata) {
}
#if defined(MG_HTTP_DIRLIST_TIME)
char time_str[30];
struct tm * time_info = localtime(&t);
struct tm *time_info = localtime(&t);
strftime(time_str, sizeof time_str, "%Y/%m/%d %H:%M:%S", time_info);
mg_snprintf(mod, sizeof(mod), "%s", time_str);
#elif defined(MG_HTTP_DIRLIST_TIME_UTC)
char time_str[30];
struct tm * time_info = gmtime(&t);
struct tm *time_info = gmtime(&t);
strftime(time_str, sizeof time_str, "%Y/%m/%d %H:%M:%S", time_info);
mg_snprintf(mod, sizeof(mod), "%s", time_str);
#else
@ -2238,7 +2237,7 @@ static void deliver_chunked_chunks(struct mg_connection *c, size_t hlen,
ofs += pl + dl + 2, del += pl + 2; // 2 is for \r\n suffix
processed += dl;
if (c->recv.len != saved) processed -= dl, buf -= dl;
mg_hexdump(c->recv.buf, hlen + processed);
//mg_hexdump(c->recv.buf, hlen + processed);
last = (dl == 0);
}
mg_iobuf_del(&c->recv, hlen + processed, del);
@ -2358,7 +2357,7 @@ int mg_iobuf_resize(struct mg_iobuf *io, size_t new_size) {
void *p = calloc(1, new_size);
if (p != NULL) {
size_t len = new_size < io->len ? new_size : io->len;
if (len > 0) memmove(p, io->buf, len);
if (len > 0 && io->buf != NULL) memmove(p, io->buf, len);
zeromem(io->buf, io->size);
free(io->buf);
io->buf = (unsigned char *) p;
@ -2801,29 +2800,18 @@ void mg_hexdump(const void *buf, size_t len) {
#if defined(MG_ENABLE_MD5) && MG_ENABLE_MD5
#if !defined(BYTE_ORDER) && defined(__BYTE_ORDER)
#define BYTE_ORDER __BYTE_ORDER
#ifndef LITTLE_ENDIAN
#define LITTLE_ENDIAN __LITTLE_ENDIAN
#endif /* LITTLE_ENDIAN */
#ifndef BIG_ENDIAN
#define BIG_ENDIAN __LITTLE_ENDIAN
#endif /* BIG_ENDIAN */
#endif /* BYTE_ORDER */
static void mg_byte_reverse(unsigned char *buf, unsigned longs) {
/* Forrest: MD5 expect LITTLE_ENDIAN, swap if BIG_ENDIAN */
#if BYTE_ORDER == BIG_ENDIAN
do {
uint32_t t = (uint32_t) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
((unsigned) buf[1] << 8 | buf[0]);
*(uint32_t *) buf = t;
buf += 4;
} while (--longs);
#else
(void) buf;
(void) longs;
#endif
if (MG_BIG_ENDIAN) {
do {
uint32_t t = (uint32_t) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
((unsigned) buf[1] << 8 | buf[0]);
*(uint32_t *) buf = t;
buf += 4;
} while (--longs);
} else {
(void) buf, (void) longs; // Little endian. Do nothing
}
}
#define F1(x, y, z) (z ^ (x & (y ^ z)))
@ -3275,11 +3263,9 @@ struct mg_connection *mg_mqtt_listen(struct mg_mgr *mgr, const char *url,
size_t mg_vprintf(struct mg_connection *c, const char *fmt, va_list ap) {
size_t mg_vprintf(struct mg_connection *c, const char *fmt, va_list *ap) {
size_t old = c->send.len;
va_list tmp;
va_copy(tmp, ap);
mg_vxprintf(mg_pfn_iobuf, &c->send, fmt, &tmp);
mg_vxprintf(mg_pfn_iobuf, &c->send, fmt, ap);
return c->send.len - old;
}
@ -3287,7 +3273,7 @@ size_t mg_printf(struct mg_connection *c, const char *fmt, ...) {
size_t len = 0;
va_list ap;
va_start(ap, fmt);
len = mg_vprintf(c, fmt, ap);
len = mg_vprintf(c, fmt, &ap);
va_end(ap);
return len;
}
@ -3494,8 +3480,10 @@ struct mg_connection *mg_wrapfd(struct mg_mgr *mgr, int fd,
struct mg_timer *mg_timer_add(struct mg_mgr *mgr, uint64_t milliseconds,
unsigned flags, void (*fn)(void *), void *arg) {
struct mg_timer *t = (struct mg_timer *) calloc(1, sizeof(*t));
mg_timer_init(&mgr->timers, t, milliseconds, flags, fn, arg);
t->id = mgr->timerid++;
if (t != NULL) {
mg_timer_init(&mgr->timers, t, milliseconds, flags, fn, arg);
t->id = mgr->timerid++;
}
return t;
}
@ -3547,8 +3535,10 @@ void mg_mgr_init(struct mg_mgr *mgr) {
void mg_rpc_add(struct mg_rpc **head, struct mg_str method,
void (*fn)(struct mg_rpc_req *), void *fn_data) {
struct mg_rpc *rpc = (struct mg_rpc *) calloc(1, sizeof(*rpc));
rpc->method = mg_strdup(method), rpc->fn = fn, rpc->fn_data = fn_data;
rpc->next = *head, *head = rpc;
if (rpc != NULL) {
rpc->method = mg_strdup(method), rpc->fn = fn, rpc->fn_data = fn_data;
rpc->next = *head, *head = rpc;
}
}
void mg_rpc_del(struct mg_rpc **head, void (*fn)(struct mg_rpc_req *)) {
@ -3646,21 +3636,6 @@ void mg_rpc_list(struct mg_rpc_req *r) {
/*
* clang with std=-c99 uses __LITTLE_ENDIAN, by default
* while for ex, RTOS gcc - LITTLE_ENDIAN, by default
* it depends on __USE_BSD, but let's have everything
*/
#if !defined(BYTE_ORDER) && defined(__BYTE_ORDER)
#define BYTE_ORDER __BYTE_ORDER
#ifndef LITTLE_ENDIAN
#define LITTLE_ENDIAN __LITTLE_ENDIAN
#endif /* LITTLE_ENDIAN */
#ifndef BIG_ENDIAN
#define BIG_ENDIAN __LITTLE_ENDIAN
#endif /* BIG_ENDIAN */
#endif /* BYTE_ORDER */
union char64long16 {
unsigned char c[64];
uint32_t l[16];
@ -3669,11 +3644,11 @@ union char64long16 {
#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
static uint32_t blk0(union char64long16 *block, int i) {
/* Forrest: SHA expect BIG_ENDIAN, swap if LITTLE_ENDIAN */
#if BYTE_ORDER == LITTLE_ENDIAN
block->l[i] =
(rol(block->l[i], 24) & 0xFF00FF00) | (rol(block->l[i], 8) & 0x00FF00FF);
#endif
if (MG_BIG_ENDIAN) {
} else {
block->l[i] = (rol(block->l[i], 24) & 0xFF00FF00) |
(rol(block->l[i], 8) & 0x00FF00FF);
}
return block->l[i];
}
@ -5101,6 +5076,7 @@ void mg_tls_handshake(struct mg_connection *c) {
if (rc == 0) { // Success
MG_DEBUG(("%lu success", c->id));
c->is_tls_hs = 0;
mg_call(c, MG_EV_TLS_HS, NULL);
} else if (rc == MBEDTLS_ERR_SSL_WANT_READ ||
rc == MBEDTLS_ERR_SSL_WANT_WRITE) { // Still pending
MG_VERBOSE(("%lu pending, %d%d %d (-%#x)", c->id, c->is_connecting,
@ -5238,7 +5214,8 @@ size_t mg_tls_pending(struct mg_connection *c) {
long mg_tls_recv(struct mg_connection *c, void *buf, size_t len) {
struct mg_tls *tls = (struct mg_tls *) c->tls;
long n = mbedtls_ssl_read(&tls->ssl, (unsigned char *) buf, len);
if (n == MBEDTLS_ERR_SSL_WANT_READ) return MG_IO_WAIT;
if (n == MBEDTLS_ERR_SSL_WANT_READ || n == MBEDTLS_ERR_SSL_WANT_WRITE)
return MG_IO_WAIT;
if (n <= 0) return MG_IO_ERR;
return n;
}
@ -5246,7 +5223,8 @@ long mg_tls_recv(struct mg_connection *c, void *buf, size_t len) {
long mg_tls_send(struct mg_connection *c, const void *buf, size_t len) {
struct mg_tls *tls = (struct mg_tls *) c->tls;
long n = mbedtls_ssl_write(&tls->ssl, (unsigned char *) buf, len);
if (n == MBEDTLS_ERR_SSL_WANT_WRITE) return MG_IO_WAIT;
if (n == MBEDTLS_ERR_SSL_WANT_READ || n == MBEDTLS_ERR_SSL_WANT_WRITE)
return MG_IO_WAIT;
if (n <= 0) return MG_IO_ERR;
return n;
}
@ -5373,6 +5351,7 @@ void mg_tls_handshake(struct mg_connection *c) {
if (rc == 1) {
MG_DEBUG(("%lu success", c->id));
c->is_tls_hs = 0;
mg_call(c, MG_EV_TLS_HS, NULL);
} else {
int code = mg_tls_err(tls, rc);
if (code != 0) mg_error(c, "tls hs: rc %d, err %d", rc, code);
@ -5606,6 +5585,8 @@ uint64_t mg_millis(void) {
return xTaskGetTickCount() * portTICK_PERIOD_MS;
#elif MG_ARCH == MG_ARCH_AZURERTOS
return tx_time_get() * (1000 /* MS per SEC */ / TX_TIMER_TICKS_PER_SECOND);
#elif MG_ARCH == MG_ARCH_ZEPHYR
return (uint64_t) k_uptime_get();
#elif MG_ARCH == MG_ARCH_UNIX && defined(__APPLE__)
// Apple CLOCK_MONOTONIC_RAW is equivalent to CLOCK_BOOTTIME on linux
// Apple CLOCK_UPTIME_RAW is equivalent to CLOCK_MONOTONIC_RAW on linux
@ -5633,6 +5614,7 @@ uint64_t mg_millis(void) {
}
#endif
#ifdef MG_ENABLE_LINES
#line 1 "src/ws.c"
#endif
@ -5830,9 +5812,10 @@ static void mg_ws_cb(struct mg_connection *c, int ev, void *ev_data,
if (final) mg_call(c, MG_EV_WS_MSG, &m);
break;
case WEBSOCKET_OP_CLOSE:
MG_DEBUG(("%lu Got WS CLOSE", c->id));
MG_DEBUG(("%lu WS CLOSE", c->id));
mg_call(c, MG_EV_WS_CTL, &m);
mg_ws_send(c, "", 0, WEBSOCKET_OP_CLOSE);
// Echo the payload of the received CLOSE message back to the sender
mg_ws_send(c, m.data.ptr, m.data.len, WEBSOCKET_OP_CLOSE);
c->is_draining = 1;
break;
default:
@ -5952,7 +5935,7 @@ static uint8_t rd(struct mip_spi *spi, uint8_t op, uint8_t addr) {
static bool mip_driver_enc28j60_init(uint8_t *mac, void *data) {
(void) mac, (void) data;
rd(data, OP_SRC, 0x1f);
rd((struct mip_spi *) data, OP_SRC, 0x1f);
return false;
}
@ -5971,10 +5954,9 @@ static bool mip_driver_enc28j60_up(void *data) {
return false;
}
struct mip_driver mip_driver_enc28j60 = {.init = mip_driver_enc28j60_init,
.tx = mip_driver_enc28j60_tx,
.rx = mip_driver_enc28j60_rx,
.up = mip_driver_enc28j60_up};
struct mip_driver mip_driver_enc28j60 = {
mip_driver_enc28j60_init, mip_driver_enc28j60_tx, mip_driver_enc28j60_rx,
mip_driver_enc28j60_up, NULL};
#endif
#ifdef MG_ENABLE_LINES
@ -5982,7 +5964,7 @@ struct mip_driver mip_driver_enc28j60 = {.init = mip_driver_enc28j60_init,
#endif
#if MG_ENABLE_MIP && defined(__arm__)
#if MG_ENABLE_MIP
struct stm32_eth {
volatile uint32_t MACCR, MACFFR, MACHTHR, MACHTLR, MACMIIAR, MACMIIDR, MACFCR,
MACVLANTR, RESERVED0[2], MACRWUFFR, MACPMTCSR, RESERVED1, MACDBGR, MACSR,
@ -6012,7 +5994,7 @@ static void *s_rxdata; // Recv callback data
enum { PHY_ADDR = 0, PHY_BCR = 0, PHY_BSR = 1 }; // PHY constants
static inline void spin(volatile uint32_t count) {
while (count--) asm("nop");
while (count--) (void) 0;
}
static uint32_t eth_read_phy(uint8_t addr, uint8_t reg) {
@ -6050,7 +6032,7 @@ static uint32_t get_hclk(void) {
} else {
clk = hsi;
}
int hpre = (RCC->CFGR & (0x0F << 4)) >> 4;
uint32_t hpre = (RCC->CFGR & (15 << 4)) >> 4;
if (hpre < 8) return clk;
uint8_t ahbptab[8] = {1, 2, 3, 4, 6, 7, 8, 9}; // log2(div)
@ -6108,7 +6090,7 @@ static bool mip_driver_stm32_init(uint8_t *mac, void *userdata) {
// Set MDC clock divider. If user told us the value, use it. Otherwise, guess
int cr = (d == NULL || d->mdc_cr < 0) ? guess_mdc_cr() : d->mdc_cr;
ETH->MACMIIAR = (cr & 3) << 2;
ETH->MACMIIAR = ((uint32_t)cr & 3) << 2;
// NOTE(cpq): we do not use extended descriptor bit 7, and do not use
// hardware checksum. Therefore, descriptor size is 4, not 8
@ -6183,10 +6165,9 @@ void ETH_IRQHandler(void) {
ETH->DMASR = sr & ~(BIT(2) | BIT(7)); // Clear status
}
struct mip_driver mip_driver_stm32 = {.init = mip_driver_stm32_init,
.tx = mip_driver_stm32_tx,
.setrx = mip_driver_stm32_setrx,
.up = mip_driver_stm32_up};
struct mip_driver mip_driver_stm32 = {
mip_driver_stm32_init, mip_driver_stm32_tx, NULL, mip_driver_stm32_up,
mip_driver_stm32_setrx};
#endif
#ifdef MG_ENABLE_LINES
@ -6200,8 +6181,9 @@ enum { W5500_CR = 0, W5500_S0 = 1, W5500_TX0 = 2, W5500_RX0 = 3 };
static void w5500_txn(struct mip_spi *s, uint8_t block, uint16_t addr, bool wr,
void *buf, size_t len) {
uint8_t *p = buf, cmd[] = {(uint8_t) (addr >> 8), (uint8_t) (addr & 255),
(uint8_t) ((block << 3) | (wr ? 4 : 0))};
uint8_t *p = (uint8_t *) buf;
uint8_t cmd[] = {(uint8_t) (addr >> 8), (uint8_t) (addr & 255),
(uint8_t) ((block << 3) | (wr ? 4 : 0))};
s->begin(s->spi);
for (size_t i = 0; i < sizeof(cmd); i++) s->txn(s->spi, cmd[i]);
for (size_t i = 0; i < len; i++) {
@ -6278,8 +6260,8 @@ static bool w5500_up(void *data) {
return phycfgr & 1; // Bit 0 of PHYCFGR is LNK (0 - down, 1 - up)
}
struct mip_driver mip_driver_w5500 = {
.init = w5500_init, .tx = w5500_tx, .rx = w5500_rx, .up = w5500_up};
struct mip_driver mip_driver_w5500 = {w5500_init, w5500_tx, w5500_rx, w5500_up,
NULL};
#endif
#ifdef MG_ENABLE_LINES
@ -6289,12 +6271,6 @@ struct mip_driver mip_driver_w5500 = {
#if MG_ENABLE_MIP
#if defined(_MSC_VER) || defined(ARDUINO)
#define _Atomic
#else
#include <stdatomic.h>
#endif
#define MIP_ETHEMERAL_PORT 49152
#define U16(ptr) ((((uint16_t) (ptr)[0]) << 8) | (ptr)[1])
#define PDIFF(a, b) ((size_t) (((char *) (b)) - ((char *) (a))))
@ -6307,8 +6283,11 @@ struct mip_driver mip_driver_w5500 = {
#define MIP_QSIZE (16 * 1024) // Queue size
#endif
#ifndef MIP_TCP_KEEPALIVE_MS
#define MIP_TCP_KEEPALIVE_MS 45000 // TCP keep-alive period, ms
#endif
#define MIP_ARP_CS (2 + 12 * MIP_ARP_ENTRIES) // ARP cache size
#define MIP_TCP_KEEPALIVE_MS 45000 // TCP keep-alive period, ms
#define MIP_TCP_ACK_MS 150 // Timeout for ACKing
struct connstate {
@ -6318,6 +6297,7 @@ struct connstate {
uint8_t ttype; // Timer type. 0: ack, 1: keep-alive
#define MIP_TTYPE_KEEPALIVE 0 // Connection is idle for long, send keepalive
#define MIP_TTYPE_ACK 1 // Peer sent us data, we have to ack it soon
uint8_t tmiss; // Number of keep-alive misses
struct mg_iobuf raw; // For TLS only. Incoming raw data
};
@ -6332,7 +6312,7 @@ struct str {
struct queue {
uint8_t *buf;
size_t len;
volatile _Atomic size_t tail, head;
volatile size_t tail, head;
};
// Network interface
@ -6349,6 +6329,7 @@ struct mip_if {
// Internal state, user can use it but should not change it
uint64_t now; // Current time
uint64_t timer_1000ms; // 1000 ms timer: for DHCP and link state
uint64_t lease_expire; // Lease expiration time
uint8_t arp_cache[MIP_ARP_CS]; // Each entry is 12 bytes
uint16_t eport; // Next ephemeral port
uint16_t dropped; // Number of dropped frames
@ -6598,11 +6579,17 @@ static void arp_ask(struct mip_if *ifp, uint32_t ip) {
ifp->driver->tx(eth, PDIFF(eth, arp + 1), ifp->driver_data);
}
static size_t mg_print_ipv4(mg_pfn_t fn, void *fn_data, va_list *ap) {
uint32_t ip = mg_ntohl(va_arg(*ap, uint32_t));
return mg_xprintf(fn, fn_data, "%d.%d.%d.%d", ip >> 24, (ip >> 16) & 255,
(ip >> 8) & 255, ip & 255);
}
static void onstatechange(struct mip_if *ifp) {
if (ifp->state == MIP_STATE_READY) {
char buf[40];
struct mg_addr addr = {.ip = ifp->ip};
MG_INFO(("READY, IP: %s", mg_ntoa(&addr, buf, sizeof(buf))));
MG_INFO(("READY, IP: %M", mg_print_ipv4, ifp->ip));
MG_INFO((" GW: %M", mg_print_ipv4, ifp->gw));
MG_INFO((" Lease: %lld sec", (ifp->lease_expire - ifp->now) / 1000));
arp_ask(ifp, ifp->gw);
} else if (ifp->state == MIP_STATE_UP) {
MG_ERROR(("Link up"));
@ -6658,11 +6645,19 @@ static void tx_udp(struct mip_if *ifp, uint32_t ip_src, uint16_t sport,
static void tx_dhcp(struct mip_if *ifp, uint32_t src, uint32_t dst,
uint8_t *opts, size_t optslen) {
struct dhcp dhcp = {.op = 1,
.htype = 1,
.hlen = 6,
.ciaddr = src,
.magic = mg_htonl(0x63825363)};
#if 0
struct dhcp {
uint8_t op, htype, hlen, hops;
uint32_t xid;
uint16_t secs, flags;
uint32_t ciaddr, yiaddr, siaddr, giaddr;
uint8_t hwaddr[208];
uint32_t magic;
uint8_t options[32];
};
#endif
struct dhcp dhcp = {1, 1, 6, 0, 0, 0, 0, 0, 0, 0, 0, {0}, 0, {0}};
dhcp.magic = mg_htonl(0x63825363);
memcpy(&dhcp.hwaddr, ifp->mac, sizeof(ifp->mac));
memcpy(&dhcp.xid, ifp->mac + 2, sizeof(dhcp.xid));
memcpy(&dhcp.options, opts, optslen);
@ -6719,15 +6714,16 @@ static void rx_arp(struct mip_if *ifp, struct pkt *pkt) {
static void rx_icmp(struct mip_if *ifp, struct pkt *pkt) {
// MG_DEBUG(("ICMP %d", (int) len));
if (pkt->icmp->type == 8 && pkt->ip->dst == ifp->ip) {
if (pkt->icmp->type == 8 && pkt->ip != NULL && pkt->ip->dst == ifp->ip) {
struct ip *ip = tx_ip(ifp, 1, ifp->ip, pkt->ip->src,
sizeof(struct icmp) + pkt->pay.len);
struct icmp *icmp = (struct icmp *) (ip + 1);
memset(icmp, 0, sizeof(*icmp)); // Important - set csum to 0
memcpy(icmp + 1, pkt->pay.buf, pkt->pay.len);
icmp->csum = ipcsum(icmp, sizeof(*icmp) + pkt->pay.len);
ifp->driver->tx(ifp->tx.buf, PDIFF(ifp->tx.buf, icmp + 1) + pkt->pay.len,
ifp->driver_data);
size_t len = PDIFF(ifp->tx.buf, icmp + 1), left = ifp->tx.len - len;
if (left > pkt->pay.len) left = pkt->pay.len; // Don't overflow TX
memset(icmp, 0, sizeof(*icmp)); // Set csum to 0
memcpy(icmp + 1, pkt->pay.buf, left); // Copy RX payload to TX
icmp->csum = ipcsum(icmp, sizeof(*icmp) + left);
ifp->driver->tx(ifp->tx.buf, len + left, ifp->driver_data);
}
}
@ -6735,21 +6731,20 @@ static void rx_dhcp(struct mip_if *ifp, struct pkt *pkt) {
uint32_t ip = 0, gw = 0, mask = 0;
uint8_t *p = pkt->dhcp->options, *end = &pkt->raw.buf[pkt->raw.len];
if (end < (uint8_t *) (pkt->dhcp + 1)) return;
// MG_DEBUG(("DHCP %u", (unsigned) pkt->raw.len));
while (p < end && p[0] != 255) {
if (p[0] == 1 && p[1] == sizeof(ifp->mask)) {
while (p + 1 < end && p[0] != 255) { // Parse options
if (p[0] == 1 && p[1] == sizeof(ifp->mask) && p + 6 < end) { // Mask
memcpy(&mask, p + 2, sizeof(mask));
// MG_DEBUG(("MASK %x", mask));
} else if (p[0] == 3 && p[1] == sizeof(ifp->gw)) {
} else if (p[0] == 3 && p[1] == sizeof(ifp->gw) && p + 6 < end) { // GW
memcpy(&gw, p + 2, sizeof(gw));
ip = pkt->dhcp->yiaddr;
// MG_DEBUG(("IP %x GW %x", ip, gw));
} else if (p[0] == 51 && p[1] == 4 && p + 6 < end) { // Lease
uint32_t lease = 0;
memcpy(&lease, p + 2, sizeof(lease));
ifp->lease_expire = ifp->now + mg_ntohl(lease) * 1000;
}
p += p[1] + 2;
}
if (ip && mask && gw && ifp->ip == 0) {
// MG_DEBUG(("DHCP offer ip %#08lx mask %#08lx gw %#08lx", (long) ip,
// (long) mask, (long) gw));
arp_cache_add(ifp, pkt->dhcp->siaddr, ((struct eth *) pkt->raw.buf)->src);
ifp->ip = ip, ifp->gw = gw, ifp->mask = mask;
ifp->state = MIP_STATE_READY;
@ -6936,7 +6931,8 @@ static void rx_tcp(struct mip_if *ifp, struct pkt *pkt) {
struct connstate *s = (struct connstate *) (c + 1);
if (c != NULL && s->ttype == MIP_TTYPE_KEEPALIVE) {
settmout(c, MIP_TTYPE_KEEPALIVE);
s->tmiss = 0; // Reset missed keep-alive counter
settmout(c, MIP_TTYPE_KEEPALIVE); // Advance keep-alive timer
}
#if 0
MG_INFO(("%lu %hhu %d", c ? c->id : 0, pkt->tcp->flags, (int) pkt->pay.len));
@ -7009,7 +7005,7 @@ static void rx_ip6(struct mip_if *ifp, struct pkt *pkt) {
if (pkt->pay.len < sizeof(*pkt->icmp)) return;
mkpay(pkt, pkt->icmp + 1);
rx_icmp(ifp, pkt);
} else if (pkt->ip->proto == 17) {
} else if (pkt->ip6->proto == 17) {
pkt->udp = (struct udp *) (pkt->ip6 + 1);
if (pkt->pay.len < sizeof(*pkt->udp)) return;
// MG_DEBUG((" UDP %u %u -> %u", len, mg_htons(udp->sport),
@ -7020,7 +7016,11 @@ static void rx_ip6(struct mip_if *ifp, struct pkt *pkt) {
static void mip_rx(struct mip_if *ifp, void *buf, size_t len) {
const uint8_t broadcast[] = {255, 255, 255, 255, 255, 255};
struct pkt pkt = {.raw = {.buf = (uint8_t *) buf, .len = len}};
// struct pkt pkt = {.raw = {.buf = (uint8_t *) buf, .len = len}};
struct pkt pkt;
memset(&pkt, 0, sizeof(pkt));
pkt.raw.buf = (uint8_t *) buf;
pkt.raw.len = len;
pkt.eth = (struct eth *) buf;
if (pkt.raw.len < sizeof(*pkt.eth)) return; // Truncated - runt?
if (memcmp(pkt.eth->dst, ifp->mac, sizeof(pkt.eth->dst)) != 0 &&
@ -7099,6 +7099,7 @@ static void mip_poll(struct mip_if *ifp, uint64_t uptime_ms) {
MG_DEBUG(("%lu keepalive", c->id));
tx_tcp(ifp, c->rem.ip, TH_ACK, c->loc.port, c->rem.port,
mg_htonl(s->seq - 1), mg_htonl(s->ack), "", 0);
if (s->tmiss++ > 2) mg_error(c, "keepalive");
}
settmout(c, MIP_TTYPE_KEEPALIVE);
}
@ -7122,32 +7123,38 @@ static void on_rx(void *buf, size_t len, void *userdata) {
}
}
static void if_init(struct mip_if *ifp, struct mg_mgr *mgr,
struct mip_cfg *ipcfg, struct mip_driver *driver,
void *driver_data, size_t maxpktsize, size_t qlen) {
memcpy(ifp->mac, ipcfg->mac, sizeof(ifp->mac));
ifp->use_dhcp = ipcfg->ip == 0;
ifp->ip = ipcfg->ip, ifp->mask = ipcfg->mask, ifp->gw = ipcfg->gw;
ifp->rx.buf = (uint8_t *) (ifp + 1), ifp->rx.len = maxpktsize;
ifp->tx.buf = ifp->rx.buf + maxpktsize, ifp->tx.len = maxpktsize;
ifp->driver = driver;
ifp->driver_data = driver_data;
ifp->mgr = mgr;
ifp->queue.buf = ifp->tx.buf + maxpktsize;
ifp->queue.len = qlen;
ifp->timer_1000ms = mg_millis();
arp_cache_init(ifp->arp_cache, MIP_ARP_ENTRIES, 12);
if (driver->setrx) driver->setrx(on_rx, ifp);
mgr->priv = ifp;
mgr->extraconnsize = sizeof(struct connstate);
#ifdef MIP_QPROFILE
qp_init();
#endif
}
void mip_init(struct mg_mgr *mgr, struct mip_cfg *ipcfg,
struct mip_driver *driver, void *driver_data) {
if (driver->init && !driver->init(ipcfg->mac, driver_data)) {
MG_ERROR(("driver init failed"));
} else {
size_t maxpktsize = 1518, qlen = driver->setrx ? MIP_QSIZE : 0;
size_t maxpktsize = 1540, qlen = driver->setrx ? MIP_QSIZE : 0;
struct mip_if *ifp =
(struct mip_if *) calloc(1, sizeof(*ifp) + 2 * maxpktsize + qlen);
memcpy(ifp->mac, ipcfg->mac, sizeof(ifp->mac));
ifp->use_dhcp = ipcfg->ip == 0;
ifp->ip = ipcfg->ip, ifp->mask = ipcfg->mask, ifp->gw = ipcfg->gw;
ifp->rx.buf = (uint8_t *) (ifp + 1), ifp->rx.len = maxpktsize;
ifp->tx.buf = ifp->rx.buf + maxpktsize, ifp->tx.len = maxpktsize;
ifp->driver = driver;
ifp->driver_data = driver_data;
ifp->mgr = mgr;
ifp->queue.buf = ifp->tx.buf + maxpktsize;
ifp->queue.len = qlen;
ifp->timer_1000ms = mg_millis();
arp_cache_init(ifp->arp_cache, MIP_ARP_ENTRIES, 12);
if (driver->setrx) driver->setrx(on_rx, ifp);
mgr->priv = ifp;
mgr->extraconnsize = sizeof(struct connstate);
#ifdef MIP_QPROFILE
qp_init();
#endif
if_init(ifp, mgr, ipcfg, driver, driver_data, maxpktsize, qlen);
}
}

View File

@ -1,5 +1,5 @@
/*
WebUI Library 2.0.0
WebUI Library 2.0.1
http://webui.me
https://github.com/alifcommunity/webui
@ -14,13 +14,15 @@
// -- WebUI ---------------------------
#include "webui.h"
// -- Log -----------------------------
// #define WEBUI_LOG
// -- Heap ----------------------------
#define WEBUI_LOG
webui_t webui;
// -- JavaScript Bridge ---------------
// Uncompressed version to allow debugging
// in the browser using the builtin dev-tools
// This is a uncompressed version to make the debugging
// more easy in the browser using the builtin dev-tools
static const char* webui_javascript_bridge =
"var _webui_log = false; \n"
"var _webui_ws; \n"
@ -305,6 +307,7 @@ static const char* webui_def_icon = "<?xml version=\"1.0\" ?><svg height=\"24\"
static const char* webui_def_icon_type = "image/svg+xml";
static const char* webui_js_empty = "WEBUI_JS_EMPTY";
static const char* webui_js_timeout = "WEBUI_JS_TIMEOUT";
static const char* webui_empty_string = ""; // .text
#ifdef _WIN32
static const char* webui_sep = "\\";
@ -485,12 +488,12 @@ bool _webui_file_exist(char* file) {
const char* _webui_get_extension(const char *f) {
if(f == NULL)
return "";
return webui_empty_string;
const char *ext = strrchr(f, '.');
if(ext == NULL || !ext || ext == f)
return "";
return webui_empty_string;
return ext + 1;
}
@ -1081,6 +1084,8 @@ static void _webui_server_event_handler(struct mg_connection *c, int ev, void *e
// Send main HTML
#ifdef WEBUI_LOG
printf("[%d] _webui_server_event_handler()... HTML Main\n", win->core.window_number);
#endif
@ -1353,7 +1358,7 @@ bool _webui_browser_create_profile_folder(webui_window_t* win, unsigned int brow
return true;
}
char* temp = _webui_browser_get_temp_path(browser);
const char* temp = _webui_browser_get_temp_path(browser);
// Chrome
// No need to create a folder
@ -1464,7 +1469,7 @@ bool _webui_folder_exist(char* folder) {
return false;
}
char* _webui_browser_get_temp_path(unsigned int browser) {
const char* _webui_browser_get_temp_path(unsigned int browser) {
#ifdef WEBUI_LOG
printf("[0] _webui_browser_get_temp_path([%d])... \n", browser);
@ -1476,11 +1481,11 @@ char* _webui_browser_get_temp_path(unsigned int browser) {
char* WinUserProfile = NULL;
size_t sz = 0;
if(_dupenv_s(&WinUserProfile, &sz, "USERPROFILE") != 0 || WinUserProfile == NULL)
return "";
return webui_empty_string;
#else
char* WinUserProfile = getenv("USERPROFILE"); // _dupenv_s
if(WinUserProfile == NULL)
return "";
return webui_empty_string;
#endif
#endif
@ -1519,7 +1524,7 @@ char* _webui_browser_get_temp_path(unsigned int browser) {
}
_webui_panic();
return "";
return webui_empty_string;
}
bool _webui_browser_exist(webui_window_t* win, unsigned int browser) {
@ -2179,10 +2184,10 @@ bool webui_any_window_is_open() {
return false;
}
unsigned int _webui_window_get_window_number(webui_window_t* win) {
unsigned int _webui_window_get_number(webui_window_t* win) {
#ifdef WEBUI_LOG
printf("[%d] _webui_window_get_window_number()... \n", win->core.window_number);
printf("[%d] _webui_window_get_number()... \n", win->core.window_number);
#endif
return win->core.window_number;
@ -2257,6 +2262,8 @@ void webui_set_icon(webui_window_t* win, const char* icon_s, const char* type_s)
bool webui_show(webui_window_t* win, const char* html, unsigned int browser) {
#ifdef WEBUI_LOG
printf("[%d] webui_show([%.*s..], [%d])... \n", win->core.window_number, 3, html, browser);
#endif
@ -2283,7 +2290,6 @@ bool webui_show(webui_window_t* win, const char* html, unsigned int browser) {
CloseHandle(thread);
// Run browser
if(!_webui_browser_start(win, win->core.url, browser))
return false;
}
@ -2308,7 +2314,28 @@ bool webui_show(webui_window_t* win, const char* html, unsigned int browser) {
return true;
}
void webui_bind_all(webui_window_t* win, void (*func) (webui_event_t e)) {
bool webui_copy_show(webui_window_t* win, const char* html, unsigned int browser) {
// Copy HTML, And show the window
// Free
if(win->core.html_cpy != NULL)
_webui_free_mem((void *) &win->core.html_cpy);
// Allocate
char* cpy = (char*) webui_empty_string;
size_t len = strlen(html);
if(len > 1) {
char* cpy = _webui_malloc(len + 1);
memcpy(cpy, html, len);
}
// Show window
return webui_show(win, cpy, browser);
}
void webui_bind_all(webui_window_t* win, void (*func) (webui_event_t* e)) {
#ifdef WEBUI_LOG
printf("[%d] webui_bind_all([*])... \n", win->core.window_number);
@ -2318,10 +2345,10 @@ void webui_bind_all(webui_window_t* win, void (*func) (webui_event_t e)) {
win->core.is_bind_all = true;
}
unsigned int webui_bind(webui_window_t* win, const char* element, void (*func) (webui_event_t e)) {
unsigned int webui_bind(webui_window_t* win, const char* element, void (*func) (webui_event_t* e)) {
#ifdef WEBUI_LOG
printf("[%d] webui_bind([%s], [*])... \n", win->core.window_number, element);
printf("[%d] webui_bind([%s], [%p])... \n", win->core.window_number, element, func);
#endif
char* element_id = _webui_malloc(strlen(element));
@ -2365,6 +2392,7 @@ unsigned int webui_bind(webui_window_t* win, const char* element, void (*func) (
webui_event_t e;
e.window_id = arg->win->core.window_number;
e.element_name = arg->element_name;
e.window = arg->win;
unsigned int cb_index = _webui_get_cb_index(arg->element_id);
@ -2373,14 +2401,14 @@ unsigned int webui_bind(webui_window_t* win, const char* element, void (*func) (
// User cb
e.element_id = cb_index;
webui.cb[cb_index](e);
webui.cb[cb_index](&e);
}
// General user cb
if(arg->win->core.is_bind_all && arg->win->core.cb_all[0] != NULL) {
e.element_id = 0;
arg->win->core.cb_all[0](e);
arg->win->core.cb_all[0](&e);
}
#ifdef WEBUI_LOG
@ -2444,8 +2472,22 @@ bool _webui_get_data(const char* packet, size_t packet_len, unsigned int pos, si
printf("[0] _webui_get_data()... \n");
#endif
if((pos + 1) > packet_len) {
*data = NULL;
data_len = 0;
return false;
}
*data = (char*) _webui_malloc((packet_len - pos) + 1);
// Check mem
if(*data == NULL) {
data_len = 0;
return false;
}
// Copy data part
char* p = *data;
for(unsigned int i = pos; i < packet_len; i++) {
@ -2459,6 +2501,8 @@ bool _webui_get_data(const char* packet, size_t packet_len, unsigned int pos, si
if(*data_len < 1) {
_webui_free_mem((void *) data);
*data = NULL;
data_len = 0;
return false;
}
@ -2507,31 +2551,44 @@ void _webui_window_receive(webui_window_t* win, const char* packet, size_t len)
// 3: [Error]
// 4: [Data]
// Get data part
char* data;
size_t data_len;
if(!_webui_get_data(packet, len, 4, &data_len, &data))
return;
// Get pipe id
unsigned char run_id = packet[2];
if(run_id < 0x01) {
_webui_free_mem((void *) &data);
// Fatal.
// The pipe ID is not valid
// we can't send the ready signal to webui_run_js()
return;
}
// Get data part
char* data;
size_t data_len;
bool data_status = _webui_get_data(packet, len, 4, &data_len, &data);
// Get js-error
bool error = true;
if((unsigned char) packet[3] == 0x00)
error = false;
// Set pipe
// Initialize pipe
_webui_free_mem((void *) &webui.run_responses[run_id]);
webui.run_error[run_id] = error;
webui.run_responses[run_id] = data;
// Ready signal
// Set pipe
if(data_status && data_len > 0) {
webui.run_error[run_id] = error;
webui.run_responses[run_id] = data;
}
else {
// Empty Result
webui.run_error[run_id] = error;
webui.run_responses[run_id] = webui_empty_string;
}
// Send ready signal to webui_run_js()
webui.run_done[run_id] = true;
}
}
@ -2544,6 +2601,7 @@ bool webui_open(webui_window_t* win, const char* url, unsigned int browser) {
// Just open an app-mode window using the link
webui_set_timeout(0);
webui_detect_process_close(win, true);
return _webui_browser_start(win, url, browser);
}
@ -2821,14 +2879,14 @@ unsigned int _webui_set_cb_index(char* element_id) {
return 0;
}
// --[Python Wrapper]---------------
// --[Python Interface]---------------
void webui_bind_py_handler(const webui_event_t e) {
void webui_bind_py_handler(webui_event_t* e) {
unsigned int cb_index = e.element_id;
unsigned int cb_index = e->element_id;
if(cb_index > 0 && webui.cb_py[cb_index] != NULL)
webui.cb_py[cb_index](e.element_id, e.window_id, e.element_name);
webui.cb_py[cb_index](e->element_id, e->window_id, e->element_name);
}
unsigned int webui_bind_py(webui_window_t* win, const char* element, void (*func)(unsigned int, unsigned int, char*)) {