windows-dev branch that relate to
the native Windows GUI (mcaster1win.exe), Visual Studio build infrastructure, and
Windows-specific runtime fixes. Cross-platform server changes are in
CHANGELOG.md.
Critical Bug Fix
HTTP Admin Authentication — WWW-Authenticate Header Missing on Windows
Root cause: A struct field order mismatch in the MSVC-specific code path in src/params.c.
The mc_param_t struct is declared as {next, flags, name_len, value_len, name, value, …} but
both mc_params_printf() and mc_http_printf() MSVC blocks used a positional initializer:
mc_param_t hdr = { NULL, (char*)name, content, flags };
// ^next ^flags(!) ^name_len(!) ...
This left hdr.name = NULL and hdr.value = NULL. mc_http_apply() checked for both null
and returned -1 immediately — silently discarding every response header set via
mc_http_printf() on Windows. Affected headers included: WWW-Authenticate, Content-Type,
Content-Length, Location, Content-Range, User-Agent, and all per-response headers.
Effect: Admin 401 responses had no WWW-Authenticate header, so browsers displayed
an error page instead of a credentials dialog. Other endpoints lost Content-Type etc.
Fix (src/params.c): Replaced wrong positional initializers with memset + explicit field
assignments in both mc_params_printf and mc_http_printf MSVC blocks:
mc_param_t hdr;
memset (&hdr, 0, sizeof hdr);
hdr.name = (char*)name;
hdr.value = content;
hdr.flags = (uint32_t)flags;
Affects both Mcaster1Win.vcxproj and Mcaster1Console.vcxproj builds.
New Features
Per-Listener SSL Enforcement (ssl: true/false)
- Added
int sslfield tolistener_t/_listener_tstruct (src/cfgfile.h) - XML config:
<ssl>0</ssl>or<ssl>1</ssl>inside<listen-socket>block - YAML config:
ssl: falseorssl: trueper entry inlisten-sockets: global.ssl_on_sock[]parallel array tracks per-socket SSL requirementconnection_peek()enforces policy strictly:- Port with
ssl: true→ rejects plain HTTP, accepts TLS only - Port with
ssl: false→ rejects TLS, accepts plain HTTP only - Port with no
ssl:key → auto-detects as before (backwards-compatible)
- Port with
- WARN log entries when policy is violated:
"TLS rejected on plain-HTTP port"/"Plain HTTP rejected on SSL-only port"
Example YAML:
listen-sockets:
- port: 9330
bind-address: "127.0.0.1"
ssl: false # plain HTTP only
- port: 9443
bind-address: "127.0.0.1"
ssl: true # TLS only
SSL Certificate Generation CLI (src/ssl_gen.h / src/ssl_gen.c)
New cross-platform OpenSSL-based certificate/CSR generator guarded by #ifdef HAVE_OPENSSL.
New flags (all platforms):
| Flag | Description |
|---|---|
--ssl-gencert | Trigger SSL generation mode (server does not start) |
--ssl-gentype=selfsigned|csr | Output type: self-signed cert or CSR |
--subj="/C=.../CN=..." | X.509 subject string (standard openssl format) |
--ssl-gencert-savepath=<dir> | Output directory (created if absent) |
--ssl-gencert-addtoconfig=true | Patch ssl-certificate/ssl-private-key paths in the -c config file |
Self-signed output (--ssl-gentype=selfsigned)
<savepath>/selfsigned.key— PEM private key<savepath>/selfsigned.crt— PEM certificate<savepath>/selfsigned.pem— combined cert+key (for server config)
CSR output (--ssl-gentype=csr)
<savepath>/server.key— PEM private key<savepath>/server.csr— PEM certificate signing request
Windows C++ wrapper (windows/SslGen.h / windows/SslGen.cpp)
CSslGen::Run(SslGenParams)— callsssl_gen_run()from C codewin_ssl_gencert(argc, argv)— C entry point forMcaster1Win.cpp- When
--ssl-gencertpresent in WinUI args: generates cert, showsMessageBoxwith result, then exits without launching the server GUI
Example usage (console):
mcaster1.exe --ssl-gencert --ssl-gentype=selfsigned \
--subj="/C=US/ST=TX/L=Dallas/O=MyStation/CN=localhost" \
--ssl-gencert-savepath=ssl/certs \
--ssl-gencert-addtoconfig=true -c windows/mcaster1dnas.yaml
See SSL Certificate Generation for the full guide.
Config File Auto-Discovery
When no -c <file> argument is given the server searches in this order:
<exe-directory>/mcaster1dnas.yaml./mcaster1dnas.yaml(current working directory)- If neither found → prompt user
- Console / Linux / macOS prompt: reads a path from stdin
- WinUI dialog: opens a
GetOpenFileNamefile-picker dialog (*.yaml;*.xml)
Windows GUI Log Viewer Tabs (4 new tabs)
Added LogTab.h / LogTab.cpp implementing CLogTab : CTabPageSSL:
| Tab | Log File |
|---|---|
| Access Log | cfg->access_log.name in cfg->log_dir |
| Error Log | cfg->error_log.name in cfg->log_dir |
| YP Health | cfg->yp_logfile[0] (first YP directory) |
| Playlist Log | cfg->playlist_log.name in cfg->log_dir |
- Black background / white monospace (Consolas 9pt) rich edit control
- Error log colour-coding:
EROR→ red,WARN→ yellow,INFO→ cyan,DBUG→ grey - Real-time tail via
WM_TIMER(2-second poll) - Uses
_fsopen(path, "rb", _SH_DENYNO)— reads files while the server has them open for writing - Path resolved from
config_get_config_unlocked()after server starts - Log rotation detection: resets
m_fileOffsetwhen file shrinks Mcaster1Win.vcxprojupdated:LogTab.cpp+LogTab.hadded
Uptime Clock
- New
IDC_UPTIME(CStatic) added toIDD_MCASTER1WIN_DIALOGRC andresource.h - Positioned below the Server Status label/bitmap in the header strip
- Updates every 500 ms (reuses timer 1) while server is running
- Format:
"Up: HH:MM:SS"/"Stopped"when halted - Anchored
TOP_RIGHT → TOP_RIGHTvia ResizableLib
System Time Status Bar
- New
IDC_SYSCLOCK(CStatic) added toIDD_MCASTER1WIN_DIALOGRC andresource.h - Positioned at bottom of dialog below the tab control (full width)
- Dedicated timer 3 fires every 1 second via
SetTimer(3, 1000)inOnInitDialog - Timer 3 killed in
OnDestroy - Format:
"System Time: Sat Feb 22 2026 10:30:45 AM" - Anchored
BOTTOM_LEFT → BOTTOM_RIGHTvia ResizableLib
Portable Windows Dev Config (windows/mcaster1dnas.yaml)
Updated to use relative paths ("." as basedir) and full ICY 2.2 mount metadata:
- Paths resolve relative to exe working directory (no hard-coded user paths)
- Per-listener
ssl: true/falseflags applied - Example mounts for live broadcast, podcast, and social media types
- All ICY 2.2 metadata fields documented per mount
Bug Fixes
ResizableLib Anchoring
IDC_STATICBLACK(banner bitmap): renamed from genericIDC_STATICto give it a unique ID addressable byAddAnchor(); all header-strip controls now correctly pin on maximizeIDC_STATIC_SLS(“Click source to view statistics” label in Source Level Stats tab): renamed fromIDC_STATIC; addedAddAnchor(IDC_STATIC_SLS, BOTTOM_LEFT, BOTTOM_LEFT)inCStatsTab::OnInitDialog— label now stays at the bottom of the tab on resizeIDC_UPTIME,IDC_SYSCLOCKanchors: new controls registered with ResizableLib
About → Help
OnAboutHelp() now calls ShellExecuteA to open https://mcaster1.com/mcaster1dnas/ in
the default browser instead of launching a CHM file that no longer existed.
Tab Header Label Overlap
- Removed oversized “Source Level Statistics” label from
IDD_STATSDIALOG(was rendered behind the tab strip;CStaticfont still being applied at 10pt Bold causing visual noise) - Removed “Global Statistics” label from
IDD_SSTATUSfor same reason - List controls repositioned to
y=7filling available height; hint text moved toy=182/y=183
Build Verification
| Test | Result |
|---|---|
MSBuild x64 Debug Mcaster1Win — 0 errors | PASS |
MSBuild x64 Debug Mcaster1Console — 0 errors | PASS |
| HTTP admin auth (browser login dialog appears) | PASS (after mc_http_printf fix) |
| Log tabs real-time tailing while server running | PASS |
| Uptime clock ticking | PASS |
| System time clock updating | PASS |
| Resize / Maximize — all controls anchored | PASS |
Visual Studio 2022 Build Infrastructure
Project & Solution Modernisation
- Migrated solution and project files to Visual Studio 2022 / MSBuild v17 toolset (
v143) - Added
Mcaster1DNAS.slnas the primary solution file replacing the legacy VC6-era.dsw - All four sub-projects compile cleanly under x64 Debug and Release configurations:
mcaster1win.exe— Windows GUI tray applicationmcaster1.exe— Headless console servermcaster1Service.exe— Windows Service wrappermcaster1Console.exe— Lightweight console runner
- Removed stale VC6
.dsp/.dswbuild files from active build paths (retained inArchive/for historical reference)
vcpkg Dependency Integration
All third-party libraries now sourced through vcpkg (x64-windows triplet):
libxml2,libxslt,libcurl,openssl,libyaml,ogg,vorbis,theora,speex,pthreads- Include paths, library paths, and DLL copy steps wired into
Mcaster1Win.vcxproj<AdditionalIncludeDirectories>and post-build events
Automatic Git Version Stamping (PreBuildEvent)
- Added
windows/git-version.ps1— PowerShell script invoked as a PreBuildEvent - Generates
src/git_hash.hat build time withGIT_VERSION,GIT_HASH,GIT_BRANCH,GIT_DIRTY - Window title bar now shows
Mcaster1DNAS vX.Y.Z-dev.HASH(or-modifiedsuffix when working tree is dirty) - Confirmed output:
GIT_VERSION = 2.5.1-dev.c2bad3c-modified
Windows GUI Enhancements
Command-Line Flags
Added full CLI argument parsing to Mcaster1WinDlg.cpp:
| Flag | Behaviour |
|---|---|
-c <file> | Specify config file path (overrides default .\mcaster1.yaml search) |
-s | Auto-start the server on launch (no button click required) |
-m | Start minimised to system tray |
-v | Print version string and exit |
-h | Print help and exit |
These allow the GUI to be scripted, launched from shortcuts with specific configs, or started automatically as a login item.
ResizableLib Integration (Resizable Dialogs)
Integrated ResizableLib by Paolo Messina (MIT/Artistic-2.0) into the project:
windows/ResizableLib/— full library source (8 compilation units) added to the repository- All four MFC dialog classes migrated from
CDialog→CResizableDialog:CMcaster1WinDlg(main window)CTabPageSSL(shared tab base class → transitively:CStatus,CStatsTab,CConfigTab)
AddAnchor()calls activated for all resizable controls:- Main window:
IDC_MAINTABanchoredTOP_LEFT → BOTTOM_RIGHT - Status tab:
IDC_GLOBALSTAT_LISTfills tab;IDC_STATIC_RUN,IDC_RUNNINGFORpinned to bottom - Stats tab:
IDC_SOURCELISTfixed-width left panel;IDC_STATSLISTfills right side - Config tab:
IDC_CONFIGeditor fills entire tab
- Main window:
EnableSaveRestore("mcaster1win")— window position and size now persist between sessions (registry keyHKCU\Software\mcaster1win\positions)- 40-line hand-rolled
OnSize()pixel math replaced with 8-line ResizableLib cascade:
CResizableDialog::OnSize(nType, cx, cy); // moves IDC_MAINTAB via anchor
m_MainTab.ResizeDialog(active, ...); // propagates to active tab page
Bugs fixed during ResizableLib integration
IDC_STATICBLACKreferenced in oldAddAnchorcalls but not present in dialog resource → removed (banner usesIDC_STATIC)IDC_FILLER1similarly absent fromIDD_STATSDIALOG→ removedEnableSaveRestore("mcaster1win", "positions")passed a string as second arg; actual API signature isEnableSaveRestore(LPCTSTR pszSection, BOOL bRectOnly = FALSE)→ fixed toEnableSaveRestore("mcaster1win")
Build configuration for ResizableLib in vcxproj: Each ResizableLib .cpp entry carries per-file
<PrecompiledHeader>NotUsing</PrecompiledHeader> and <AdditionalIncludeDirectories>$(ProjectDir)ResizableLib;...</AdditionalIncludeDirectories>
so the library finds its own StdAfx.h (which defines WINVER 0x0501, uxtheme.h, shlwapi.h)
without conflicting with the main project’s precompiled header.
YAML Configuration — Windows Runtime Fix
Root Cause
yaml_parser_load() crashed on Windows when called with a FILE* opened by the main exe.
yaml.dll (from vcpkg) was compiled against a different C runtime (UCRT) than the MSVC-compiled
exe, making the FILE struct layout binary-incompatible. Any read attempt inside libyaml
dereferenced invalid struct offsets → access violation.
The last successful trace line before the crash was:
[yaml] yaml_parser_load ← trace written BEFORE the call; nothing after = crash inside
XML config was unaffected because libxml2 opens the file internally using its own CRT handles.
Fix Applied (src/cfgfile_yaml.c — config_parse_yaml_file())
- Read the entire config file into a heap buffer using the exe’s own CRT
fread()/ftell() - Close the
FILE*before calling any libyaml function - Call
yaml_parser_set_input_string(&parser, buf, len)instead ofyaml_parser_set_input_file(&parser, fp) - No
FILE*ever crosses the DLL boundary
Verified by full trace log after fix:
[yaml] file read into memory
[yaml] yaml_parser_initialize ok
[yaml] yaml_parser_load
[yaml] yaml_parser_load ok ← was the crash point; now passes cleanly
[yaml] root node ok
[yaml] root is mapping
[yaml] config_init_configuration ok
[yaml] yaml_parse_root
[yaml] yaml_parse_root done
[si] connection_setup_sockets ok
[si] server_init done -> returning 0
[3] server_process starting
Diagnostic Infrastructure (retained for future use)
CFG_TRACE(msg)macro insrc/cfgfile.c— appends tomcaster1win_start.login the exe’s working directory (WIN32 only, no-op on Linux/macOS)YAML_TRACE(msg)macro insrc/cfgfile_yaml.c— same log file,[yaml]prefix- 23 trace checkpoints from server init through
server_process starting
Graphics & Branding
Full Visual Rebrand: Icecast2 → Mcaster1DNAS
Replaced all Icecast2 bitmap assets in windows/ with Mcaster1DNAS branded equivalents:
mcaster1dnaslogo2.bmp— main application logomcaster1dnastitle.bmp— title bar / about screen bannerrunning.bmp/stopped.bmp— server status indicator iconscredits.bmp— credits screen image
- Dialog resource (
Mcaster1Win.rc) updated to reference new bitmaps - Application icon (
mcaster1.ico) updated to Mcaster1DNAS icon - Installer scripts (
mcaster1dnas.iss,mcaster164.nsis) updated with new branding, paths, and version strings - Original developer credits preserved in full — the Credits dialog continues to display acknowledgment of Xiph.Org Foundation (Icecast2), Karl Heyes (Icecast-KH), Jack Moffitt, Michael Smith, oddsock, and all upstream contributors in accordance with GNU GPL v2 attribution requirements
Configuration Files (Windows Dev)
XML Config (windows/x64/Debug/mcaster1.xml)
- Created Windows-specific XML development config targeting
127.0.0.1:9300(HTTP) and127.0.0.1:9443(HTTPS) - Absolute Windows paths for basedir, logdir, webroot, adminroot, ssl-certificate, pidfile
- Used to verify XML code path and isolate YAML crash during diagnosis
YAML Config (windows/x64/Debug/mcaster1.yaml)
- Created equivalent YAML development config with identical settings to
mcaster1.xml - Both configs now start the server cleanly and produce identical runtime behaviour
- Config auto-detection (
detect_config_format()) reads the first non-whitespace byte:<→ XML,#/-/word → YAML
Build Verification
| Test | Result |
|---|---|
| MSBuild x64 Debug — 0 errors | PASS |
| Window launch + 15s resize stress test | PASS |
| Resize to 900×700 | PASS |
| Maximize → 1550×830 | PASS |
| Restore → 900×700 | PASS |
| Process survival (no crash) | PASS |
XML config server start (-c mcaster1.xml -s) | PASS — 15s healthy |
YAML config server start (-c mcaster1.yaml -s) | PASS — 15s healthy |
| Full YAML trace (23/23 checkpoints) | PASS |
Known Issues / In Progress
- Config dialog editor — planned visual editor for
mcaster1.yaml/mcaster1.xmldirectly inside the GUI (no hand-editing required) - Stats tab auto-refresh — GUI polls admin HTTP API; requires server to be listening on the configured port for tabs to populate
- Windows Service installer —
mcaster1Service.vcxprojcompiles; NSIS/Inno Setup installer packaging not yet automated in CI
Upcoming Windows-Specific Roadmap
See also the main README.md roadmap section.
- Config Dialog Editor — GUI-based config editor with validation, replacing raw file editing
- Enhanced Documentation — Windows-specific installation guide, dependency setup wizard
- Podcast & On-Demand File Manager — GUI panel for managing podcast episode files and on-demand audio assets
- RSS Podcast Feed Generator — Built-in feed builder that publishes an RSS 2.0 / Apple Podcasts compatible feed from the on-demand library
- Podcast Core Server Features — Episode scheduling, chapter markers, podcast-specific ICY metadata fields, listener analytics per episode
- Windows Installer (MSI/Inno) — Full automated installer with dependency bundling (vcredist, vcpkg DLLs, config wizard)
- Auto-Update Mechanism — In-app update check against GitHub releases
- Dark Mode — Windows 10/11 dark mode support via
DwmSetWindowAttribute
See Also
- Windows GUI Guide — full mcaster1win.exe user guide
- SSL Certificate Setup — cert generation CLI and config patching
- ICY2 Protocol — full ICY 2.2 protocol reference
- Static Mount Points — podcast, socialcast, and on-demand mounts
- Song History API — track history ring buffer and XML API