Commit f49d11d3 authored by Martí Bolívar's avatar Martí Bolívar Committed by Marti Bolivar
Browse files

civetweb: remove obsolete code

This code has gone unmaintained and bugs continue to be reported
against it. We do not have the resources as a project to maintain this
in "odd fixes" mode, and nobody has stepped up to maintain it [1], so
sadly this must be removed for now.

If anyone would like to see civetweb supported in upstream Zephyr
again, they are welcome to add it back, as long as they promise to
maintain it going forward.

Many thanks to everyone who has contributed to civetweb support in
Zephyr while it was here. So long and thanks for all the fish.

Fixes: #45807
Fixes: #43910
Fixes: #34226
Fixes: #46743

[1] https://lists.zephyrproject.org/g/devel/message/8466

Signed-off-by: default avatarMartí Bolívar <marti.bolivar@nordicsemi.no>
parent 27eeee84
...@@ -664,7 +664,6 @@ ...@@ -664,7 +664,6 @@
/samples/net/mqtt_publisher/ @rlubos /samples/net/mqtt_publisher/ @rlubos
/samples/net/sockets/coap_*/ @rlubos /samples/net/sockets/coap_*/ @rlubos
/samples/net/sockets/ @rlubos @tbursztyka @pfalcon /samples/net/sockets/ @rlubos @tbursztyka @pfalcon
/samples/net/*civetweb* @Nukersson
/samples/sensor/ @MaureenHelm /samples/sensor/ @MaureenHelm
/samples/shields/ @avisconti /samples/shields/ @avisconti
/samples/subsys/logging/ @nordic-krch @jakub-uC /samples/subsys/logging/ @nordic-krch @jakub-uC
......
...@@ -1992,16 +1992,6 @@ West: ...@@ -1992,16 +1992,6 @@ West:
- manifest-canopennode - manifest-canopennode
- "area: CAN" - "area: CAN"
"West project: civetweb":
status: obsolete
files:
- samples/net/civetweb/
- modules/Kconfig.civetweb
labels:
- manifest-civetweb
- "area: Networking"
- "area: civetweb"
"West project: cmsis": "West project: cmsis":
status: maintained status: maintained
maintainers: maintainers:
......
...@@ -9,7 +9,6 @@ comment "Optional modules. Make sure they're installed, via the project manifest ...@@ -9,7 +9,6 @@ comment "Optional modules. Make sure they're installed, via the project manifest
source "modules/Kconfig.altera" source "modules/Kconfig.altera"
source "modules/Kconfig.atmel" source "modules/Kconfig.atmel"
source "modules/Kconfig.civetweb"
source "modules/Kconfig.cmsis" source "modules/Kconfig.cmsis"
source "modules/Kconfig.cypress" source "modules/Kconfig.cypress"
source "modules/Kconfig.eos_s3" source "modules/Kconfig.eos_s3"
......
# Copyright (c) 2019 Antmicro Ltd
# SPDX-License-Identifier: Apache-2.0
config CIVETWEB
bool "Civetweb Support (DEPRECATED)"
# The CONFIG_NET_TCP_ISN_RFC6528 option would pull in mbedtls,
# and there are include file issues if CONFIG_POSIX_API is set.
# Because Civetweb sets the POSIX API option in the samples,
# make sure that we do not try to use Civetweb if the TCP ISN
# option is set.
depends on !NET_TCP_ISN_RFC6528
help
This option enables the civetweb HTTP API.
Support for this module is now deprecated due to a lack
of maintainers. Please volunteer to maintain this module
if you would like to see support for it remain in upstream
Zephyr.
...@@ -11,9 +11,4 @@ ...@@ -11,9 +11,4 @@
# This is done in a separate CMake file because the modules.cmake file # This is done in a separate CMake file because the modules.cmake file
# in this same directory is evaluated before Kconfig runs. # in this same directory is evaluated before Kconfig runs.
if(CONFIG_CIVETWEB) # (No modules are currently deprecated.)
message(WARNING "The civetweb module is deprecated. \
Unless someone volunteers to maintain this module, \
support for it will be removed in Zephyr v3.2."
)
endif()
/*
* Copyright (c) 2019 Antmicro Ltd
* Copyright (c) 2020 Alexander Kozhinov <AlexanderKozhinov@yandex.com>
*
* SPDX-License-Identifier: Apache-2.0
*/
static void log_access(const struct mg_connection *conn)
{
const struct mg_request_info *ri;
char src_addr[IP_ADDR_STR_LEN];
if (!conn || !conn->dom_ctx) {
return;
}
ri = &conn->request_info;
sockaddr_to_string(src_addr, sizeof(src_addr), &conn->client.rsa);
LOG_DBG("%s - \"%s %s%s%s HTTP/%s\" %d\n",
STR_LOG_ALLOC(src_addr),
STR_LOG_ALLOC(ri->request_method),
STR_LOG_ALLOC(ri->request_uri),
(ri->query_string == NULL) ? log_strdup("?") : log_strdup(""),
STR_LOG_ALLOC(ri->query_string),
STR_LOG_ALLOC(ri->http_version),
conn->status_code);
}
/*
* Copyright (c) 2019 Antmicro Ltd
* Copyright (c) 2020 Alexander Kozhinov <AlexanderKozhinov@yandex.com>
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <logging/log.h>
LOG_MODULE_REGISTER(mg_cry_internal_impl, LOG_LEVEL_DBG);
#include "helper.h"
static void mg_cry_internal_impl(const struct mg_connection *conn,
const char *func,
unsigned line,
const char *fmt,
va_list ap)
{
(void)conn;
LOG_ERR("%s @ %d in civetweb.c", STR_LOG_ALLOC(func), line);
vprintf(fmt, ap);
}
/*
* Copyright (c) 2020 Alexander Kozhinov Mail: <AlexanderKozhinov@yandex.com>
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __HELPER__
#define __HELPER__
#include <zephyr/logging/log.h>
#define STR_LOG_ALLOC(str) ((str == NULL) ? log_strdup("null") :\
log_strdup(str))
#endif /* __HELPER__ */
/*
* Copyright (c) 2019 Antmicro Ltd
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/zephyr.h>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <zephyr/net/socket.h>
#define pollfd zsock_pollfd
#define fcntl zsock_fcntl
#define POLLIN ZSOCK_POLLIN
#define POLLOUT ZSOCK_POLLOUT
#define addrinfo zsock_addrinfo
#define F_SETFD 2
#define FD_CLOEXEC 1
size_t strcspn(const char *s1, const char *s2);
size_t strspn(const char *s1, const char *s2);
int iscntrl(int c);
double atof(const char *str);
int sscanf(const char *s, const char *format, ...);
char *strerror(int err);
time_t time(time_t *t);
struct tm *gmtime(const time_t *ptime);
size_t strftime(char *dst, size_t dst_size, const char *fmt,
const struct tm *tm);
double difftime(time_t end, time_t beg);
struct tm *localtime(const time_t *timer);
int fileno(FILE *stream);
int ferror(FILE *stream);
int fclose(FILE *stream);
int fseeko(FILE *stream, off_t offset, int whence);
FILE *fopen(const char *filename, const char *mode);
char *fgets(char *str, int num, FILE *stream);
size_t fread(void *ptr, size_t size, size_t count, FILE *stream);
int remove(const char *filename);
int getsockname(int sock, struct sockaddr *addr, socklen_t *addrlen);
int poll(struct zsock_pollfd *fds, int nfds, int timeout);
int getnameinfo(const struct sockaddr *addr, socklen_t addrlen,
char *host, socklen_t hostlen,
char *serv, socklen_t servlen, int flags);
ssize_t send(int sock, const void *buf, size_t len, int flags);
ssize_t recv(int sock, void *buf, size_t max_len, int flags);
int socket(int family, int type, int proto);
int getaddrinfo(const char *host, const char *service,
const struct zsock_addrinfo *hints,
struct zsock_addrinfo **res);
void freeaddrinfo(struct zsock_addrinfo *ai);
int connect(int sock, const struct sockaddr *addr, socklen_t addrlen);
int getsockopt(int sock, int level, int optname,
void *optval, socklen_t *optlen);
int setsockopt(int sock, int level, int optname,
const void *optval, socklen_t optlen);
int listen(int sock, int backlog);
int accept(int sock, struct sockaddr *addr, socklen_t *addrlen);
int bind(int sock, const struct sockaddr *addr, socklen_t addrlen);
/*
* Copyright (c) 2019 Antmicro Ltd
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(lib_extensions, LOG_LEVEL_DBG);
#include <zephyr/zephyr.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "libc_extensions.h"
#define FN_MISSING() LOG_DBG("[IMPLEMENTATION MISSING : %s]\n", __func__)
int iscntrl(int c)
{
/* All the characters placed before the space on the ASCII table
* and the 0x7F character (DEL) are control characters.
*/
return (int)(c < ' ' || c == 0x7F);
}
size_t strftime(char *dst, size_t dst_size,
const char *fmt,
const struct tm *tm)
{
FN_MISSING();
return 0;
}
double difftime(time_t end, time_t beg)
{
return end - beg;
}
struct __strerr_wrap {
int err;
const char *errstr;
};
/* Implementation suggested by @rakons in #16527 */
#define STRERR_DEFINE(e) {e, #e}
static const struct __strerr_wrap error_strings[] = {
STRERR_DEFINE(EILSEQ),
STRERR_DEFINE(EDOM),
STRERR_DEFINE(ERANGE),
STRERR_DEFINE(ENOTTY),
STRERR_DEFINE(EACCES),
STRERR_DEFINE(EPERM),
STRERR_DEFINE(ENOENT),
STRERR_DEFINE(ESRCH),
STRERR_DEFINE(EEXIST),
STRERR_DEFINE(ENOSPC),
STRERR_DEFINE(ENOMEM),
STRERR_DEFINE(EBUSY),
STRERR_DEFINE(EINTR),
STRERR_DEFINE(EAGAIN),
STRERR_DEFINE(ESPIPE),
STRERR_DEFINE(EXDEV),
STRERR_DEFINE(EROFS),
STRERR_DEFINE(ENOTEMPTY),
STRERR_DEFINE(ECONNRESET),
STRERR_DEFINE(ETIMEDOUT),
STRERR_DEFINE(ECONNREFUSED),
STRERR_DEFINE(EHOSTDOWN),
STRERR_DEFINE(EHOSTUNREACH),
STRERR_DEFINE(EADDRINUSE),
STRERR_DEFINE(EPIPE),
STRERR_DEFINE(EIO),
STRERR_DEFINE(ENXIO),
STRERR_DEFINE(ENOTBLK),
STRERR_DEFINE(ENODEV),
STRERR_DEFINE(ENOTDIR),
STRERR_DEFINE(EISDIR),
STRERR_DEFINE(ETXTBSY),
STRERR_DEFINE(ENOEXEC),
STRERR_DEFINE(EINVAL),
STRERR_DEFINE(E2BIG),
STRERR_DEFINE(ELOOP),
STRERR_DEFINE(ENAMETOOLONG),
STRERR_DEFINE(ENFILE),
STRERR_DEFINE(EMFILE),
STRERR_DEFINE(EBADF),
STRERR_DEFINE(ECHILD),
STRERR_DEFINE(EFAULT),
STRERR_DEFINE(EFBIG),
STRERR_DEFINE(EMLINK),
STRERR_DEFINE(ENOLCK),
STRERR_DEFINE(EDEADLK),
STRERR_DEFINE(ECANCELED),
STRERR_DEFINE(ENOSYS),
STRERR_DEFINE(ENOMSG),
STRERR_DEFINE(ENOSTR),
STRERR_DEFINE(ENODATA),
STRERR_DEFINE(ETIME),
STRERR_DEFINE(ENOSR),
STRERR_DEFINE(EPROTO),
STRERR_DEFINE(EBADMSG),
STRERR_DEFINE(ENOTSOCK),
STRERR_DEFINE(EDESTADDRREQ),
STRERR_DEFINE(EMSGSIZE),
STRERR_DEFINE(EPROTOTYPE),
STRERR_DEFINE(ENOPROTOOPT),
STRERR_DEFINE(EPROTONOSUPPORT),
STRERR_DEFINE(ESOCKTNOSUPPORT),
STRERR_DEFINE(ENOTSUP),
STRERR_DEFINE(EPFNOSUPPORT),
STRERR_DEFINE(EAFNOSUPPORT),
STRERR_DEFINE(EADDRNOTAVAIL),
STRERR_DEFINE(ENETDOWN),
STRERR_DEFINE(ENETUNREACH),
STRERR_DEFINE(ENETRESET),
STRERR_DEFINE(ECONNABORTED),
STRERR_DEFINE(ENOBUFS),
STRERR_DEFINE(EISCONN),
STRERR_DEFINE(ENOTCONN),
STRERR_DEFINE(ESHUTDOWN),
STRERR_DEFINE(EALREADY),
STRERR_DEFINE(EINPROGRESS),
};
static char *strerr_unknown = "UNKNOWN";
char *strerror(int err)
{
int i;
for (i = 0; i < ARRAY_SIZE(error_strings); ++i) {
if (error_strings[i].err == err) {
return (char *)error_strings[i].errstr;
}
}
return strerr_unknown;
}
int sscanf(const char *s, const char *format, ...)
{
FN_MISSING();
return 0;
}
double atof(const char *str)
{
/* XXX good enough for civetweb uses */
return (double)atoi(str);
}
/*
* Most of the wrappers below are copies of the wrappers in net/sockets.h,
* but they are available only if CONFIG_NET_SOCKETS_POSIX_NAMES is enabled
* which is impossible here.
*/
int getsockname(int sock, struct sockaddr *addr,
socklen_t *addrlen)
{
return zsock_getsockname(sock, addr, addrlen);
}
int poll(struct zsock_pollfd *fds, int nfds, int timeout)
{
return zsock_poll(fds, nfds, timeout);
}
int getnameinfo(const struct sockaddr *addr, socklen_t addrlen,
char *host, socklen_t hostlen,
char *serv, socklen_t servlen, int flags)
{
return zsock_getnameinfo(addr, addrlen, host, hostlen,
serv, servlen, flags);
}
ssize_t send(int sock, const void *buf, size_t len, int flags)
{
return zsock_send(sock, buf, len, flags);
}
ssize_t recv(int sock, void *buf, size_t max_len, int flags)
{
return zsock_recv(sock, buf, max_len, flags);
}
int socket(int family, int type, int proto)
{
return zsock_socket(family, type, proto);
}
int getaddrinfo(const char *host, const char *service,
const struct zsock_addrinfo *hints,
struct zsock_addrinfo **res)
{
return zsock_getaddrinfo(host, service, hints, res);
}
void freeaddrinfo(struct zsock_addrinfo *ai)
{
zsock_freeaddrinfo(ai);
}
int connect(int sock, const struct sockaddr *addr,
socklen_t addrlen)
{
return zsock_connect(sock, addr, addrlen);
}
int getsockopt(int sock, int level, int optname,
void *optval, socklen_t *optlen)
{
return zsock_getsockopt(sock, level, optname, optval, optlen);
}
int setsockopt(int sock, int level, int optname,
const void *optval, socklen_t optlen)
{
return zsock_setsockopt(sock, level, optname, optval, optlen);
}
int listen(int sock, int backlog)
{
return zsock_listen(sock, backlog);
}
int bind(int sock, const struct sockaddr *addr, socklen_t addrlen)
{
return zsock_bind(sock, addr, addrlen);
}
int accept(int sock, struct sockaddr *addr, socklen_t *addrlen)
{
return zsock_accept(sock, addr, addrlen);
}
# Copyright (c) 2020 Alexander Kozhinov
# Mail: AlexanderKozhinov@yandex.com
#
# SPDX-License-Identifier: Apache-2.0
cmake_minimum_required(VERSION 3.20.0)
set(common_dir ${CMAKE_CURRENT_SOURCE_DIR}/../common)
set(common_src_dir ${common_dir}/src)
set(common_include_dir ${common_dir}/include)
include_directories(
${common_include_dir}
)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(civetweb_http_server)
target_sources(app PRIVATE
src/main.c
${common_src_dir}/libc_extensions.c
)
.. _civetweb-http_server-sample:
Civetweb sample
###############
Overview
********
This sample application uses the HTTP APIs provided by the external `Civetweb <https://github.com/civetweb/civetweb>`_ module to create an HTTP server demonstrating selected Civetweb features.
The Civetweb module is available as a west :ref:`module <modules>`.
The source code for this sample application can be found at:
:zephyr_file:`samples/net/civetweb/http_server`.
Requirements
************
- A board with hardware networking
- The Civetweb module (made available via west)
Building and Running
********************
This sample was tested on the Atmel SAM E70 Xplained board, so this is the recommended target.
Build it with:
.. zephyr-app-commands::
:zephyr-app: samples/net/civetweb/http_server
:board: sam_e70_xplained
:goals: build
:compact:
The sample application uses a static IP configuration.
After flashing the board, the server can be accessed with the web browser of your choice at ``192.0.2.1:8080``.
The sample does not serve any files like HTTP (it does not use any filesystem).
Instead it serves the following three URLs:
- ``/`` - a basic hello world handler
- ``/info`` - shows OS information, uses the JSON format to achieve that
- ``/history`` - demonstrates the usage of cookies
A regular 404 status code is returned when trying to access any other URL.
The IP configuration can be changed in Zephyr config.
The default port can be changed in the sources of the sample.
# General config
CONFIG_CIVETWEB=y
CONFIG_JSON_LIBRARY=y
# pthreads
CONFIG_POSIX_API=y
CONFIG_PTHREAD_IPC=y
CONFIG_POSIX_MQUEUE=y
# networking
CONFIG_NETWORKING=y
CONFIG_NET_IPV4=y
# CONFIG_NET_IPV6 is not set
CONFIG_NET_TCP=y
CONFIG_NET_SOCKETS=y
CONFIG_MINIMAL_LIBC_MALLOC_ARENA_SIZE=16384
CONFIG_NET_TX_STACK_SIZE=2048
CONFIG_NET_RX_STACK_SIZE=2048
CONFIG_ISR_STACK_SIZE=2048
CONFIG_MAIN_STACK_SIZE=2048
CONFIG_IDLE_STACK_SIZE=1024
CONFIG_DNS_RESOLVER=y
CONFIG_NET_CONFIG_SETTINGS=y
CONFIG_NET_CONFIG_MY_IPV4_ADDR="192.0.2.1"
CONFIG_NET_CONFIG_MY_IPV4_NETMASK="255.255.255.0"
CONFIG_NET_CONFIG_MY_IPV4_GW="192.0.2.2"
CONFIG_NET_CONFIG_PEER_IPV4_ADDR="192.0.2.2"
# logging
CONFIG_NET_LOG=y
# Do not include mbedtls via this option as civetweb does not
# work properly with mbedtls.
CONFIG_NET_TCP_ISN_RFC6528=n
sample:
description: Civetweb HTTP API sample
name: http_server
tests:
sample.net.civetweb.http_server:
modules:
- civetweb
harness: net
arch_exclude: posix
depends_on: netif
filter: CONFIG_ENTROPY_DEVICE_RANDOM_GENERATOR
integration_platforms:
- sam_e70_xplained
/*
* Copyright (c) 2019 Antmicro Ltd
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/zephyr.h>
#include <zephyr/posix/pthread.h>
#include <zephyr/data/json.h>
#include "civetweb.h"
#define HTTP_PORT 8080
#define HTTPS_PORT 4443
#define CIVETWEB_MAIN_THREAD_STACK_SIZE CONFIG_MAIN_STACK_SIZE
/* Use smallest possible value of 1024 (see the line 18619 of civetweb.c) */
#define MAX_REQUEST_SIZE_BYTES 1024
K_THREAD_STACK_DEFINE(civetweb_stack, CIVETWEB_MAIN_THREAD_STACK_SIZE);
struct civetweb_info {
const char *version;
const char *os;
uint32_t features;
const char *feature_list;
const char *build;
const char *compiler;
const char *data_model;
};
#define FIELD(struct_, member_, type_) { \
.field_name = #member_, \
.field_name_len = sizeof(#member_) - 1, \
.offset = offsetof(struct_, member_), \
.type = type_ \
}
void send_ok(struct mg_connection *conn)
{
mg_printf(conn,
"HTTP/1.1 200 OK\r\n"
"Content-Type: text/html\r\n"
"Connection: close\r\n\r\n");
}
int hello_world_handler(struct mg_connection *conn, void *cbdata)
{
send_ok(conn);
mg_printf(conn, "<html><body>");
mg_printf(conn, "<h3>Hello World from Zephyr!</h3>");
mg_printf(conn, "See also:\n");
mg_printf(conn, "<ul>\n");
mg_printf(conn, "<li><a href=/info>system info</a></li>\n");
mg_printf(conn, "<li><a href=/history>cookie demo</a></li>\n");
mg_printf(conn, "</ul>\n");
mg_printf(conn, "</body></html>\n");
return 200;
}
int system_info_handler(struct mg_connection *conn, void *cbdata)
{
static const struct json_obj_descr descr[] = {
FIELD(struct civetweb_info, version, JSON_TOK_STRING),
FIELD(struct civetweb_info, os, JSON_TOK_STRING),
FIELD(struct civetweb_info, feature_list, JSON_TOK_STRING),
FIELD(struct civetweb_info, build, JSON_TOK_STRING),
FIELD(struct civetweb_info, compiler, JSON_TOK_STRING),
FIELD(struct civetweb_info, data_model, JSON_TOK_STRING),
};
struct civetweb_info info = {};
char info_str[1024] = {};
int ret;
int size;
size = mg_get_system_info(info_str, sizeof(info_str));
ret = json_obj_parse(info_str, size, descr, ARRAY_SIZE(descr), &info);
send_ok(conn);
if (ret < 0) {
mg_printf(conn, "Could not retrieve: %d\n", ret);
return 500;
}
mg_printf(conn, "<html><body>");
mg_printf(conn, "<h3>Server info</h3>");
mg_printf(conn, "<ul>\n");
mg_printf(conn, "<li>host os - %s</li>\n", info.os);
mg_printf(conn, "<li>server - civetweb %s</li>\n", info.version);
mg_printf(conn, "<li>compiler - %s</li>\n", info.compiler);
mg_printf(conn, "<li>board - %s</li>\n", CONFIG_BOARD);
mg_printf(conn, "</ul>\n");
mg_printf(conn, "</body></html>\n");
return 200;
}
int history_handler(struct mg_connection *conn, void *cbdata)
{
const struct mg_request_info *req_info = mg_get_request_info(conn);
const char *cookie = mg_get_header(conn, "Cookie");
char history_str[64];
mg_get_cookie(cookie, "history", history_str, sizeof(history_str));
mg_printf(conn, "HTTP/1.1 200 OK\r\n");
mg_printf(conn, "Connection: close\r\n");
mg_printf(conn, "Set-Cookie: history='%s'\r\n", req_info->local_uri);
mg_printf(conn, "Content-Type: text/html\r\n\r\n");
mg_printf(conn, "<html><body>");
mg_printf(conn, "<h3>Your URI is: %s<h3>\n", req_info->local_uri);
if (history_str[0] == 0) {
mg_printf(conn, "<h5>This is your first visit.</h5>\n");
} else {
mg_printf(conn, "<h5>your last /history visit was: %s</h5>\n",
history_str);
}
mg_printf(conn, "Some cookie-saving links to try:\n");
mg_printf(conn, "<ul>\n");
mg_printf(conn, "<li><a href=/history/first>first</a></li>\n");
mg_printf(conn, "<li><a href=/history/second>second</a></li>\n");
mg_printf(conn, "<li><a href=/history/third>third</a></li>\n");
mg_printf(conn, "<li><a href=/history/fourth>fourth</a></li>\n");
mg_printf(conn, "<li><a href=/history/fifth>fifth</a></li>\n");
mg_printf(conn, "</ul>\n");
mg_printf(conn, "</body></html>\n");
return 200;
}
void *main_pthread(void *arg)
{
static const char * const options[] = {
"listening_ports",
STRINGIFY(HTTP_PORT),
"num_threads",
"1",
"max_request_size",
STRINGIFY(MAX_REQUEST_SIZE_BYTES),
NULL
};
struct mg_callbacks callbacks;
struct mg_context *ctx;
(void)arg;
memset(&callbacks, 0, sizeof(callbacks));
ctx = mg_start(&callbacks, 0, (const char **)options);
if (ctx == NULL) {
printf("Unable to start the server.");
return 0;
}
mg_set_request_handler(ctx, "/$", hello_world_handler, 0);
mg_set_request_handler(ctx, "/info$", system_info_handler, 0);
mg_set_request_handler(ctx, "/history", history_handler, 0);
return 0;
}
void main(void)
{
pthread_attr_t civetweb_attr;
pthread_t civetweb_thread;
(void)pthread_attr_init(&civetweb_attr);
(void)pthread_attr_setstack(&civetweb_attr, &civetweb_stack,
CIVETWEB_MAIN_THREAD_STACK_SIZE);
(void)pthread_create(&civetweb_thread, &civetweb_attr,
&main_pthread, 0);
}
# Copyright (c) 2020 Alexander Kozhinov <AlexanderKozhinov@yandex.com>
#
# SPDX-License-Identifier: Apache-2.0
cmake_minimum_required(VERSION 3.20.0)
set(common_dir ${CMAKE_CURRENT_SOURCE_DIR}/../common)
set(common_src_dir ${common_dir}/src)
set(common_include_dir ${common_dir}/include)
set(inc_dir ${CMAKE_CURRENT_SOURCE_DIR}/include)
set(src_dir ${CMAKE_CURRENT_SOURCE_DIR}/src)
include_directories(
${inc_dir}
${common_include_dir}
)
option(CIVETWEB_ENABLE_WEBSOCKETS "Enable websockets connections" ON)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(civetweb_websocket_server)
target_sources(app PRIVATE
${src_dir}/main.c
${common_src_dir}/libc_extensions.c
${src_dir}/http_server_handlers.c
${src_dir}/websocket_server_handlers.c)
set(gen_dir ${ZEPHYR_BINARY_DIR}/include/generated/)
set(web_page_dir web_page)
file(MAKE_DIRECTORY ${gen_dir}/${web_page_dir})
# List of files that are used to generate .h file that can be included
# into .c file.
foreach(inc_file
${web_page_dir}/index.html
${web_page_dir}/index.css
${web_page_dir}/ws.js)
# Generate normal and gzipped versions of each file:
generate_inc_file_for_target(app
${inc_file}
${gen_dir}/${inc_file}.inc)
generate_inc_file_for_target(app
${inc_file}
${gen_dir}/${inc_file}.gz.inc
--gzip)
endforeach()
include(${ZEPHYR_BASE}/samples/net/common/common.cmake)
.. _civetweb-websocket-server-sample:
Civetweb WebSocket Server sample
################################
Overview
********
This sample application uses the HTTP APIs provided by the external
`Civetweb <https://github.com/civetweb/civetweb>`_ module to create an WebSocket
server demonstrating selected Civetweb features.
The Civetweb module is available as a west :ref:`module <modules>`.
The source code for this sample application can be found at:
:zephyr_file:`samples/net/civetweb/websocket_server`.
Requirements
************
- A board with hardware networking
- The Civetweb module (made available via west)
Building and Running
********************
This sample was tested on the NUCLEO H745ZI-Q board, so this is the recommended target.
Build it with:
.. zephyr-app-commands::
:zephyr-app: samples/net/civetweb/websocket_server
:board: nucleo_h745zi_q_m7
:goals: build
:compact:
The sample application uses a static IP configuration.
After flashing the board, the server can be accessed with the web browser
of your choice (preferably Chrome) under ``192.0.2.1`` IPv4 address.
The IP address can be changed in :zephyr_file:`samples/net/civetweb/websocket_server/prj.conf`
The port number can be changed in :zephyr_file:`samples/net/civetweb/websocket_server/main.c`
This sample application consists of two main parts:
- **HTTP Server** - ``http://192.0.2.1:8080`` or ``http://192.0.2.1:8080/index.html`` It is needed to serve application's main page and its dependencies.
- **WebSocket Server** - ``ws://192.0.2.1:8080/ws``. It is an echo server, which sends received data enclosed in **board name** and a string **too!** back.
The **HTTP Server*** serves following statically allocated files
(*no file system is present*):
- ``/`` - main application page (redirects requests to ``/index.html``)
- ``/index.html`` - main application page
- ``/index.css`` - main application page style sheet
- ``/ws.js`` - WebSocket client JavaScript
A regular 404 status code is returned when trying to access other links.
The **WebSocket Server** works as follows:
Calling the ``http://192.0.2.1:8080`` in your browser provides WebSocket
client JavaScript load. This script establishes the connection to the WebSocket
server running on your board.
Putting some message in ```Message Text``` window and pressing *Send* button generates
predefined answer from WebSocket server printed in log window.
/*
* Copyright (c) 2020 Alexander Kozhinov Mail: <AlexanderKozhinov@yandex.com>
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __HTTP_SERVER_HANDLERS__
#define __HTTP_SERVER_HANDLERS__
#include "civetweb.h"
void init_http_server_handlers(struct mg_context *ctx);
#endif /* __HTTP_SERVER_HANDLERS__ */
/*
* Copyright (c) 2020 Alexander Kozhinov <AlexanderKozhinov@yandex.com>
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __WEBSOCKET_SERVER_HANDLERS__
#define __WEBSOCKET_SERVER_HANDLERS__
#include "civetweb.h"
void init_websocket_server_handlers(struct mg_context *ctx);
#endif /* __WEBSOCKET_SERVER_HANDLERS__ */
# General config
CONFIG_CIVETWEB=y
# pthreads
CONFIG_POSIX_API=y
CONFIG_PTHREAD_IPC=y
CONFIG_POSIX_MQUEUE=y
# networking
CONFIG_NETWORKING=y
CONFIG_NET_IPV4=y
# CONFIG_NET_IPV6 is not set
CONFIG_NET_TCP=y
CONFIG_NET_SOCKETS=y
CONFIG_DNS_RESOLVER=y
CONFIG_NET_CONFIG_SETTINGS=y
CONFIG_NET_CONFIG_MY_IPV4_ADDR="192.0.2.1"
CONFIG_NET_CONFIG_MY_IPV4_NETMASK="255.255.255.0"
CONFIG_NET_CONFIG_MY_IPV4_GW="192.0.2.2"
CONFIG_NET_CONFIG_PEER_IPV4_ADDR="192.0.2.2"
# memory settings:
CONFIG_MINIMAL_LIBC_MALLOC_ARENA_SIZE=16384
CONFIG_NET_TX_STACK_SIZE=2048
CONFIG_NET_RX_STACK_SIZE=2048
CONFIG_ISR_STACK_SIZE=2048
CONFIG_MAIN_STACK_SIZE=2048
CONFIG_IDLE_STACK_SIZE=1024
# logging:
CONFIG_LOG=y
# CONFIG_NET_LOG=y
# Do not include mbedtls via this option as civetweb does not
# work properly with mbedtls.
CONFIG_NET_TCP_ISN_RFC6528=n
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment