adaway/webserver/jni/webserver.c

160 lines
5 KiB
C
Raw Normal View History

2025-11-20 14:05:12 +01:00
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <android/log.h>
#include <errno.h>
#include "mongoose/mongoose.h"
#define THIS_FILE "WebServer"
// TODO Test difference between 127.0.0.1 + [::1] and localhost
#define HTTP_URL "http://localhost:80"
#define HTTPS_URL "https://localhost:443"
#define OOM_ADJ_PATH "/proc/self/oom_score_adj"
#define OOM_ADJ_NOKILL -17
static int s_sig_num = 0;
struct settings {
bool init;
struct mg_tls_opts tls_opts;
char test_path[100];
char icon_path[100];
bool icon;
bool debug;
};
static void fn(struct mg_connection *c, int ev, void *ev_data) {
if (ev == MG_EV_HTTP_MSG && c->fn_data != NULL) {
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
struct settings *s = (struct settings *) c->fn_data;
if (mg_strcmp(hm->uri, mg_str("/internal-test")) == 0) {
struct mg_http_serve_opts opts;
memset(&opts, 0, sizeof(opts));
mg_http_serve_file(c, hm, s->test_path, &opts);
} else if (s->icon) {
struct mg_http_serve_opts opts;
memset(&opts, 0, sizeof(opts));
mg_http_serve_file(c, hm, s->icon_path, &opts);
} else {
mg_http_reply(c, 200, "", "");
}
}
}
static void tls_fn(struct mg_connection *c, int ev, void *ev_data) {
if (ev == MG_EV_ACCEPT && c->fn_data != NULL) {
struct settings *s = (struct settings *) c->fn_data;
mg_tls_init(c, &s->tls_opts);
} else {
fn(c, ev, ev_data);
}
}
static void signal_handler(int sig_num) {
signal(sig_num, signal_handler);
s_sig_num = sig_num;
}
/*
* Tell the kernel's out-of-memory killer to avoid this process.
*/
void oom_adjust_setup(void) {
FILE *fp;
int oom_score = INT_MIN;
if ((fp = fopen(OOM_ADJ_PATH, "r+")) != NULL) {
if (fscanf(fp, "%d", &oom_score) != 1)
__android_log_print(ANDROID_LOG_INFO, THIS_FILE, "error reading %s: %s", OOM_ADJ_PATH,
strerror(errno));
else {
rewind(fp);
if (fprintf(fp, "%d\n", OOM_ADJ_NOKILL) <= 0)
__android_log_print(ANDROID_LOG_INFO, THIS_FILE, "error writing %s: %s",
OOM_ADJ_PATH, strerror(errno));
else
__android_log_print(ANDROID_LOG_INFO, THIS_FILE, "Set %s from %d to %d",
OOM_ADJ_PATH, oom_score, OOM_ADJ_NOKILL);
}
fclose(fp);
}
}
struct settings parse_cli_parameters(int argc, char *argv[]) {
struct settings s = {
.init = false,
.tls_opts = { 0 },
.icon = false,
.debug = false
};
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "--resources") == 0 && i < argc - 1) {
char *resource_path = argv[++i];
// Initialize TLS options
char cert_path[100];
char key_path[100];
strcpy(cert_path, resource_path);
strcat(cert_path, "/localhost-2410.crt");
strcpy(key_path, resource_path);
strcat(key_path, "/localhost-2410.key");
s.tls_opts.cert = mg_file_read(&mg_fs_posix, cert_path);
s.tls_opts.key = mg_file_read(&mg_fs_posix, key_path);
// Initialize resource paths
strcpy(s.icon_path, resource_path);
strcat(s.icon_path, "/icon.svg");
strcpy(s.test_path, resource_path);
strcat(s.test_path, "/test.html");
s.init = true;
} else if (strcmp(argv[i], "--icon") == 0) {
s.icon = true;
} else if (strcmp(argv[i], "--debug") == 0) {
s.debug = true;
}
}
return s;
}
int main(int argc, char *argv[]) {
struct mg_mgr mgr;
struct mg_connection *http_connection;
struct mg_connection *https_connection;
struct settings s = parse_cli_parameters(argc, argv);
if (!s.init) {
__android_log_print(ANDROID_LOG_FATAL, THIS_FILE, "Missing parameters.");
return EXIT_FAILURE;
}
if (s.debug) {
__android_log_print(ANDROID_LOG_FATAL, THIS_FILE, "Debug mode activated.");
mg_log_set(MG_LL_DEBUG);
}
oom_adjust_setup();
mg_mgr_init(&mgr);
http_connection = mg_http_listen(&mgr, HTTP_URL, fn, &s);
if (http_connection == NULL) {
__android_log_print(ANDROID_LOG_FATAL, THIS_FILE, "Failed to listen on http port.");
return EXIT_FAILURE;
}
https_connection = mg_http_listen(&mgr, HTTPS_URL, tls_fn, &s);
if (https_connection == NULL) {
__android_log_print(ANDROID_LOG_FATAL, THIS_FILE, "Failed to listen on https port.");
return EXIT_FAILURE;
}
signal(SIGINT, signal_handler);
signal(SIGTERM, signal_handler);
__android_log_print(ANDROID_LOG_INFO, THIS_FILE, "Starting server.");
while (s_sig_num == 0) {
mg_mgr_poll(&mgr, 1000);
}
mg_mgr_free(&mgr);
__android_log_print(ANDROID_LOG_INFO, THIS_FILE, "Stopping server on signal %d.", s_sig_num);
return EXIT_SUCCESS;
}