Skip to content

Commit ba58cf1

Browse files
committed
webui_get_url now returns machine's IP instead of localhost
1 parent 699119f commit ba58cf1

File tree

1 file changed

+131
-3
lines changed

1 file changed

+131
-3
lines changed

src/webui.c

Lines changed: 131 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,7 @@ typedef struct _webui_window_t {
326326
bool connected; // Fast check
327327
size_t server_port;
328328
char* url;
329+
char* public_url;
329330
const char* html;
330331
char* server_root_path;
331332
#ifdef _WIN32
@@ -632,6 +633,7 @@ static int _webui_serve_file(_webui_window_t* win, struct mg_connection* client,
632633
static int _webui_external_file_handler(_webui_window_t* win, struct mg_connection* client, size_t client_id);
633634
static int _webui_interpret_file(_webui_window_t* win, struct mg_connection* client, char* index, size_t client_id);
634635
static void _webui_webview_update(_webui_window_t* win);
636+
static const char* _webui_get_local_ip(void);
635637
// WebView
636638
#ifdef _WIN32
637639
// Microsoft Windows
@@ -3157,13 +3159,24 @@ const char* webui_get_url(size_t window) {
31573159
return NULL;
31583160
_webui_window_t* win = _webui.wins[window];
31593161

3160-
// Check if server is started
3162+
// Check if local server is started
31613163
if (_webui_is_empty(win->url)) {
3162-
// Start server
3164+
// Start local server
3165+
bool backup = _webui.config.show_wait_connection;
3166+
_webui.config.show_wait_connection = true;
31633167
webui_show_browser(window, "<html><head><script src=\"webui.js\"></script></head></html>", NoBrowser);
3168+
_webui.config.show_wait_connection = backup;
31643169
}
31653170

3166-
return (const char*) win->url;
3171+
// Get local IP of first NIC
3172+
const char *ip = _webui_get_local_ip();
3173+
if (win->public_url != NULL)
3174+
_webui_free_mem((void*)win->public_url);
3175+
win->public_url = (char*)_webui_malloc(64); // [http][ip][port]
3176+
WEBUI_SN_PRINTF_DYN(win->public_url, 64, WEBUI_HTTP_PROTOCOL "%s:%zu", ip, win->server_port);
3177+
_webui_free_mem((void*)ip);
3178+
3179+
return (const char*) win->public_url;
31673180
}
31683181

31693182
void webui_set_public(size_t window, bool status) {
@@ -7902,6 +7915,121 @@ static bool _webui_tls_generate_self_signed_cert(char* root_cert, char* root_key
79027915
}
79037916
#endif
79047917

7918+
static const char* _webui_get_local_ip(void) {
7919+
char *buf = malloc(64);
7920+
if (!buf) return NULL;
7921+
#ifdef _WIN32
7922+
WSADATA wsa;
7923+
if (WSAStartup(MAKEWORD(2,2), &wsa) != 0) {
7924+
free(buf);
7925+
return NULL;
7926+
}
7927+
buf[0] = '\0';
7928+
// Approach 1: gethostname + getaddrinfo
7929+
char hostname[256] = {0};
7930+
if (gethostname(hostname, sizeof(hostname)) == 0) {
7931+
struct addrinfo hints = {0}, *res = NULL;
7932+
hints.ai_family = AF_INET;
7933+
if (getaddrinfo(hostname, NULL, &hints, &res) == 0) {
7934+
char first_ip[INET_ADDRSTRLEN] = {0};
7935+
for (struct addrinfo *p = res; p; p = p->ai_next) {
7936+
if (p->ai_family == AF_INET) {
7937+
struct sockaddr_in *sa = (struct sockaddr_in*)p->ai_addr;
7938+
char ip[INET_ADDRSTRLEN];
7939+
if (inet_ntop(AF_INET, &sa->sin_addr, ip, sizeof(ip))) {
7940+
if (strcmp(ip, "127.0.0.1")) {
7941+
strncpy(buf, ip, 63);
7942+
buf[63] = '\0';
7943+
break;
7944+
}
7945+
if (!first_ip[0]) {
7946+
strncpy(first_ip, ip, sizeof(first_ip)-1);
7947+
}
7948+
}
7949+
}
7950+
}
7951+
if (!buf[0] && first_ip[0]) {
7952+
strncpy(buf, first_ip, 63);
7953+
buf[63] = '\0';
7954+
}
7955+
freeaddrinfo(res);
7956+
}
7957+
}
7958+
if (buf[0]) {
7959+
WSACleanup();
7960+
return buf;
7961+
}
7962+
// Approach 2: WSAIoctl SIO_GET_INTERFACE_LIST
7963+
SOCKET s = socket(AF_INET, SOCK_DGRAM, 0);
7964+
if (s != INVALID_SOCKET) {
7965+
#define MAX_IFACES 32
7966+
INTERFACE_INFO ifaces[MAX_IFACES];
7967+
DWORD retlen;
7968+
if (!WSAIoctl(s, SIO_GET_INTERFACE_LIST, NULL, 0,
7969+
ifaces, sizeof(ifaces), &retlen, NULL, NULL)) {
7970+
int n = retlen / sizeof(INTERFACE_INFO);
7971+
char first_ip[INET_ADDRSTRLEN] = {0};
7972+
for (int i = 0; i < n; i++) {
7973+
struct sockaddr_in *sa = (struct sockaddr_in*)&ifaces[i].iiAddress;
7974+
char ip[INET_ADDRSTRLEN];
7975+
if (inet_ntop(AF_INET, &sa->sin_addr, ip, sizeof(ip))) {
7976+
if (!strcmp(ip, "0.0.0.0")) continue;
7977+
if (strcmp(ip, "127.0.0.1")) {
7978+
strncpy(buf, ip, 63);
7979+
buf[63] = '\0';
7980+
break;
7981+
}
7982+
if (!first_ip[0]) {
7983+
strncpy(first_ip, ip, sizeof(first_ip)-1);
7984+
}
7985+
}
7986+
}
7987+
if (!buf[0] && first_ip[0]) {
7988+
strncpy(buf, first_ip, 63);
7989+
buf[63] = '\0';
7990+
}
7991+
}
7992+
closesocket(s);
7993+
}
7994+
WSACleanup();
7995+
if (!buf[0]) {
7996+
free(buf);
7997+
return NULL;
7998+
}
7999+
return buf;
8000+
#else
8001+
struct ifaddrs *ifaddr = NULL, *ifa;
8002+
if (getifaddrs(&ifaddr) == -1) {
8003+
free(buf);
8004+
return NULL;
8005+
}
8006+
// first non-loopback IPv4
8007+
for (ifa = ifaddr; ifa; ifa = ifa->ifa_next) {
8008+
if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET &&
8009+
(ifa->ifa_flags & IFF_UP) && !(ifa->ifa_flags & IFF_LOOPBACK)) {
8010+
struct sockaddr_in *sa = (struct sockaddr_in*)ifa->ifa_addr;
8011+
if (inet_ntop(AF_INET, &sa->sin_addr, buf, 64)) {
8012+
freeifaddrs(ifaddr);
8013+
return buf;
8014+
}
8015+
}
8016+
}
8017+
// fallback first IPv4
8018+
for (ifa = ifaddr; ifa; ifa = ifa->ifa_next) {
8019+
if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET) {
8020+
struct sockaddr_in *sa = (struct sockaddr_in*)ifa->ifa_addr;
8021+
if (inet_ntop(AF_INET, &sa->sin_addr, buf, 64)) {
8022+
freeifaddrs(ifaddr);
8023+
return buf;
8024+
}
8025+
}
8026+
}
8027+
freeifaddrs(ifaddr);
8028+
free(buf);
8029+
return NULL;
8030+
#endif
8031+
}
8032+
79058033
static bool _webui_show_window(_webui_window_t* win, struct mg_connection* client, const char* content, int type, size_t browser) {
79068034

79078035
#ifdef WEBUI_LOG

0 commit comments

Comments
 (0)