diff --git a/src/main.c b/src/main.c index d5e7a18c..79b793aa 100644 --- a/src/main.c +++ b/src/main.c @@ -423,8 +423,12 @@ static void _ch_root_uid_setup(void) } #endif } - -int main(int argc, char **argv) + +#ifdef WIN32_SERVICE +int mainService(int argc, char **argv) +#else +int main(int argc, char **argv) +#endif { int res, ret; char filename[512]; diff --git a/win32/Icecast2win.dsw b/win32/Icecast2win.dsw index 7b02280a..d722d561 100644 --- a/win32/Icecast2win.dsw +++ b/win32/Icecast2win.dsw @@ -17,6 +17,12 @@ Package=<4> Begin Project Dependency Project_Dep_Name icecast End Project Dependency + Begin Project Dependency + Project_Dep_Name icecastService + End Project Dependency + Begin Project Dependency + Project_Dep_Name icecast2 console + End Project Dependency }}} ############################################################################### @@ -48,6 +54,21 @@ Package=<4> ############################################################################### +Project: "icecastService"=.\icecastService.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name icecast + End Project Dependency +}}} + +############################################################################### + Global: Package=<5> diff --git a/win32/icecast2.iss b/win32/icecast2.iss index 92f75d91..da760483 100644 --- a/win32/icecast2.iss +++ b/win32/icecast2.iss @@ -32,6 +32,7 @@ Name: "{app}\logs" [Files] Source: "Release\Icecast2.exe"; DestDir: "{app}"; Flags: ignoreversion Source: "Release\icecast2console.exe"; DestDir: "{app}"; Flags: ignoreversion +Source: "Release\icecastService.exe"; DestDir: "{app}"; Flags: ignoreversion Source: "..\doc\icecast2.chm"; DestDir: "{app}\doc"; Flags: ignoreversion Source: "..\web\*.xsl"; DestDir: "{app}\web"; Flags: ignoreversion Source: "..\web\*.png"; DestDir: "{app}\web"; Flags: ignoreversion @@ -51,4 +52,8 @@ Name: "{group}\Icecast2 Win32"; Filename: "{app}\Icecast2.exe";WorkingDir: "{app Name: "{userdesktop}\Icecast2 Win32"; Filename: "{app}\Icecast2.exe"; MinVersion: 4,4; Tasks: desktopicon;WorkingDir: "{app}"; [Run] +Filename: "{app}\icecastService.exe"; Parameters: "install ""{app}""";Description: "Install Icecast as a windows service.";Flags: postinstall + +[UninstallRun] +Filename: "{app}\icecastService.exe"; Parameters: "remove" diff --git a/win32/icecastService.cpp b/win32/icecastService.cpp new file mode 100644 index 00000000..3176d689 --- /dev/null +++ b/win32/icecastService.cpp @@ -0,0 +1,170 @@ +#include +#include +#include +#include +extern "C" { +#include "thread.h" +#include "avl.h" +#include "log.h" +#include "global.h" +#include "httpp.h" +#include "sock.h" +#include "connection.h" +#include "refbuf.h" +#include "client.h" +#include "stats.h" +} + + +SERVICE_STATUS ServiceStatus; +SERVICE_STATUS_HANDLE hStatus; + +void ServiceMain(int argc, char** argv); +void ControlHandler(DWORD request); +int InitService(); +extern "C" int mainService(int argc, char **argv); + +int InitService() +{ + int result = 0; + return(result); +} + +void installService(char *path) +{ + if (path) { + char fullPath[8096*2] = ""; + + sprintf(fullPath, "\"%s\\icecastService.exe\" \"%s\"", path, path); + SC_HANDLE handle = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS ); + SC_HANDLE service = CreateService( + handle, + "Icecast", + "Icecast Media Server", + GENERIC_READ | GENERIC_EXECUTE, + SERVICE_WIN32_OWN_PROCESS, + SERVICE_AUTO_START, + SERVICE_ERROR_IGNORE, + fullPath, + NULL, + NULL, + NULL, + NULL, + NULL + ); + printf("Service Installed\n"); + } +} +void removeService() +{ + SC_HANDLE handle = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS ); + SC_HANDLE service = OpenService(handle, "Icecast", DELETE); + if (service) { + DeleteService(service); + } + printf("Service Removed\n"); +} +void ControlHandler(DWORD request) +{ + switch(request) { + case SERVICE_CONTROL_STOP: + global.running = ICE_HALTING; + ServiceStatus.dwWin32ExitCode = 0; + ServiceStatus.dwCurrentState = SERVICE_STOPPED; + SetServiceStatus (hStatus, &ServiceStatus); + return; + + case SERVICE_CONTROL_SHUTDOWN: + global.running = ICE_HALTING; + ServiceStatus.dwWin32ExitCode = 0; + ServiceStatus.dwCurrentState = SERVICE_STOPPED; + SetServiceStatus (hStatus, &ServiceStatus); + return; + default: + break; + } + + // Report current status + SetServiceStatus (hStatus, &ServiceStatus); + + return; +} + +void ServiceMain(int argc, char** argv) +{ + int error; + + ServiceStatus.dwServiceType = SERVICE_WIN32; + ServiceStatus.dwCurrentState = SERVICE_START_PENDING; + ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN; + ServiceStatus.dwWin32ExitCode = 0; + ServiceStatus.dwServiceSpecificExitCode = 0; + ServiceStatus.dwCheckPoint = 0; + ServiceStatus.dwWaitHint = 0; + + hStatus = RegisterServiceCtrlHandler("Icecast", (LPHANDLER_FUNCTION)ControlHandler); + if (hStatus == (SERVICE_STATUS_HANDLE)0) { + // Registering Control Handler failed + return; + } + // Initialize Service + error = InitService(); + if (error) { + // Initialization failed + ServiceStatus.dwCurrentState = SERVICE_STOPPED; + ServiceStatus.dwWin32ExitCode = -1; + SetServiceStatus(hStatus, &ServiceStatus); + return; + } + // We report the running status to SCM. + ServiceStatus.dwCurrentState = SERVICE_RUNNING; + SetServiceStatus (hStatus, &ServiceStatus); + + /* Here we do the work */ + + int argc2 = 3; + char* argv2[3]; + + argv2[0] = "icecastService.exe"; + argv2[1] = "-c"; + argv2[2] = "icecast.xml"; + + int ret = mainService(argc2, (char **)argv2); + + ServiceStatus.dwCurrentState = SERVICE_STOPPED; + ServiceStatus.dwWin32ExitCode = -1; + SetServiceStatus(hStatus, &ServiceStatus); + return; +} + + +void main(int argc, char **argv) +{ + + bool matched = false; + if (argv[0]) { + if (argv[1]) { + if (!strcmp(argv[1], "install")) { + installService(argv[2]); + matched = true; + } + if (!strcmp(argv[1], "remove")) { + removeService(); + matched = true; + } + } + } + if (matched) { + return; + } + _chdir(argv[1]); + + SERVICE_TABLE_ENTRY ServiceTable[2]; + ServiceTable[0].lpServiceName = "Icecast Server"; + ServiceTable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain; + + ServiceTable[1].lpServiceName = NULL; + ServiceTable[1].lpServiceProc = NULL; + // Start the control dispatcher thread for our service + StartServiceCtrlDispatcher(ServiceTable); +} \ No newline at end of file diff --git a/win32/icecastService.dsp b/win32/icecastService.dsp new file mode 100644 index 00000000..527db14e --- /dev/null +++ b/win32/icecastService.dsp @@ -0,0 +1,107 @@ +# Microsoft Developer Studio Project File - Name="icecastService" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=icecastService - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "icecastService.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "icecastService.mak" CFG="icecastService - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "icecastService - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "icecastService - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "icecastService - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "../" /I "../../libxslt/include" /I "../../curl/include" /I "../../iconv/include" /I "../../libxml2/include" /I "..\src" /I "..\src/httpp" /I "..\src/thread" /I "..\src/log" /I "..\src/avl" /I "..\src/net" /I "..\src/timings" /I "../../pthreads" /I "../../oggvorbis-win32sdk-1.0.1/include" /I "../../theora/include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "WIN32_SERVICE" /D "HAVE_CURL" /D "USE_YP" /D "HAVE_SYS_STAT_H" /D PACKAGE_VERSION=\"2.3.0\" /D "HAVE_THEORA" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib Releaseicecast\icecast.lib ..\..\curl\lib\Release\libcurl.lib ..\..\oggvorbis-win32sdk-1.0.1\lib\ogg_static.lib ..\..\oggvorbis-win32sdk-1.0.1\lib\vorbis_static.lib ..\..\libxml2\lib\libxml2.lib ..\..\libxslt\lib\libxslt.lib ..\..\iconv\lib\iconv.lib ..\..\pthreads\pthreadVSE.lib ws2_32.lib ..\..\theora\win32\Static_Release\theora_static.lib ../../speex/win32/libspeex/Release/libspeex.lib /nologo /subsystem:console /machine:I386 /nodefaultlib:"libc.lib" +# SUBTRACT LINK32 /pdb:none + +!ELSEIF "$(CFG)" == "icecastService - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "icecastService___Win32_Debug" +# PROP BASE Intermediate_Dir "icecastService___Win32_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "icecastService___Win32_Debug" +# PROP Intermediate_Dir "icecastService___Win32_Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "../" /I "../../libxslt/include" /I "../../curl/include" /I "../../iconv/include" /I "../../libxml2/include" /I "..\src" /I "..\src/httpp" /I "..\src/thread" /I "..\src/log" /I "..\src/avl" /I "..\src/net" /I "..\src/timings" /I "../../pthreads" /I "../../oggvorbis-win32sdk-1.0.1/include" /I "../../theora/include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "WIN32_SERVICE" /D "HAVE_CURL" /D "USE_YP" /D "HAVE_SYS_STAT_H" /D PACKAGE_VERSION=\"2.3.0\" /D "HAVE_THEORA" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 Debugicecast\icecast.lib ..\..\curl\lib\Release\libcurl.lib ..\..\oggvorbis-win32sdk-1.0.1\lib\ogg_static.lib ..\..\oggvorbis-win32sdk-1.0.1\lib\vorbis_static.lib ..\..\libxml2\lib\libxml2.lib ..\..\libxslt\lib\libxslt.lib ..\..\iconv\lib\iconv.lib ..\..\pthreads\pthreadVSE.lib ws2_32.lib ..\..\theora\win32\Static_Debug\theora_static_d.lib ../../speex/win32/libspeex/Release/libspeex.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /nodefaultlib:"libcd.lib" /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "icecastService - Win32 Release" +# Name "icecastService - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\icecastService.cpp +# End Source File +# Begin Source File + +SOURCE=..\src\main.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project