Index: trunk/Common/cm_log.h
===================================================================
--- trunk/Common/cm_log.h	(revision 61)
+++ trunk/Common/cm_log.h	(revision 62)
@@ -5,4 +5,5 @@
 
 void cm_log(const char* name, const char* log, ...);
+void cm_force_log(const char* log);
 
 #endif
Index: trunk/Common/log.c
===================================================================
--- trunk/Common/log.c	(revision 61)
+++ trunk/Common/log.c	(revision 62)
@@ -5,4 +5,5 @@
 #include "cm_string.h"
 
+#include <time.h>
 #include <stdio.h>
 #include <stdbool.h>
@@ -11,7 +12,18 @@
 #include <stdarg.h>
 
+FILE* logfile;
+
 bool cm_do_log = false;
 
 #define LOGNAME_LENGTH 12
+
+void cm_force_log(const char* log) {
+	time_t t = time(NULL);
+	struct tm* tm = localtime(&t);
+	char date[513];
+	strftime(date, 512, "%a %b %d %H:%M:%S %Z %Y", tm);
+	fprintf(logfile, "[%s] %s\n", date, log);
+	fflush(logfile);
+}
 
 void cm_log(const char* name, const char* log, ...) {
@@ -57,5 +69,5 @@
 	}
 
-	fprintf(stderr, "%s %s\n", namebuf, result);
+	fprintf(logfile, "%s %s\n", namebuf, result);
 	va_end(args);
 
Index: trunk/Module/Makefile
===================================================================
--- trunk/Module/Makefile	(revision 61)
+++ trunk/Module/Makefile	(revision 62)
@@ -15,3 +15,3 @@
 
 clean:
-	rm -f *.o *.so *.a
+	rm -f *.o *.so *.a *.dll
Index: trunk/Platform/win32-service.mk
===================================================================
--- trunk/Platform/win32-service.mk	(revision 62)
+++ trunk/Platform/win32-service.mk	(revision 62)
@@ -0,0 +1,13 @@
+# $Id$
+
+PREFIX = C:/Tewi
+
+CC = i686-w64-mingw32-gcc
+AR = i686-w64-mingw32-ar
+WINDRES = i686-w64-mingw32-windres
+CFLAGS = -g -std=c99 -DPREFIX=\"$(PREFIX)\" -I $(PWD)/Common -fPIC -DSERVICE -mwindows
+LDFLAGS = -mwindows
+LIBS = -lws2_32
+EXEC = .exe
+LIB = .dll
+PREOBJS = tewi.res
Index: trunk/Platform/win32.mk
===================================================================
--- trunk/Platform/win32.mk	(revision 61)
+++ trunk/Platform/win32.mk	(revision 62)
@@ -12,3 +12,2 @@
 LIB = .dll
 PREOBJS = tewi.res
-INSTALLER = install.exe
Index: trunk/Platform/win64-service.mk
===================================================================
--- trunk/Platform/win64-service.mk	(revision 62)
+++ trunk/Platform/win64-service.mk	(revision 62)
@@ -0,0 +1,13 @@
+# $Id$
+
+PREFIX = C:/Tewi
+
+CC = x86_64-w64-mingw32-gcc
+AR = x86_64-w64-mingw32-ar
+WINDRES = x86_64-w64-mingw32-windres
+CFLAGS = -g -std=c99 -DPREFIX=\"$(PREFIX)\" -I $(PWD)/Common -fPIC -mwindows
+LDFLAGS = -mwindows
+LIBS = -lws2_32
+EXEC = .exe
+LIB = .dll
+PREOBJS = tewi.res
Index: trunk/Platform/win64.mk
===================================================================
--- trunk/Platform/win64.mk	(revision 61)
+++ trunk/Platform/win64.mk	(revision 62)
@@ -12,3 +12,2 @@
 LIB = .dll
 PREOBJS = tewi.res
-INSTALLER = install.exe
Index: trunk/Server/Makefile
===================================================================
--- trunk/Server/Makefile	(revision 61)
+++ trunk/Server/Makefile	(revision 62)
@@ -8,8 +8,5 @@
 OBJS = version.o main.o config.o server.o http.o module.o strptime.o $(EXTOBJS) $(PREOBJS)
 
-all: tewi$(EXEC) $(INSTALLER)
-
-install.exe: tewi$(EXEC) install.nsi
-	makensis install.nsi
+all: tewi$(EXEC)
 
 tewi$(EXEC): $(OBJS) ../Common/common.a
Index: trunk/Server/install.nsi
===================================================================
--- trunk/Server/install.nsi	(revision 61)
+++ trunk/Server/install.nsi	(revision 62)
@@ -6,5 +6,10 @@
 Icon "tewi.ico"
 LicenseData ../LICENSE
+
+!include "LogicLib.nsh"
+!include "Sections.nsh"
+
 Page license
+Page components
 Page instfiles
 UninstPage uninstConfirm
@@ -18,6 +23,4 @@
 	SetOutPath "$INSTDIR"
 	File /oname=LICENSE.txt "../LICENSE"
-	SetOutPath "$INSTDIR\bin"
-	File "tewi.exe"
 	SetOutPath "$INSTDIR\modules"
 	File "../Module/*.dll"
@@ -43,5 +46,62 @@
 SectionEnd
 
+Section "Install the executable only" SEL_EXEC
+	SetOutPath "$INSTDIR\bin"
+	File "../tewi.exe"
+	WriteINIStr $INSTDIR\install.ini uninstall service false
+SectionEnd
+
+Section /o "Install the service too (NT-only)" SEL_SERVICE
+	WriteINIStr $INSTDIR\install.ini uninstall service true
+	FileOpen $9 $INSTDIR\install.bat w
+	FileWrite $9 '"$SYSDIR\sc.exe" stop "TewiHTTPd"$\r$\n'
+	FileClose $9
+	nsExec::Exec '"$INSTDIR\install.bat"'
+	Pop $0
+	DetailPrint "Waiting for 1s so service can stop..."
+	Sleep 1000
+	CreateDirectory "$INSTDIR\logs"
+	SetOutPath "$INSTDIR\bin"
+	File "../tewi.exe"
+	File /oname=tewisrv.exe "../tewi-service.exe"
+	FileOpen $9 $INSTDIR\install.bat w
+	FileWrite $9 '"$SYSDIR\sc.exe" delete "TewiHTTPd"$\r$\n'
+	FileWrite $9 '"$SYSDIR\sc.exe" create "TewiHTTPd" DisplayName= "Tewi HTTPd" binpath= "$INSTDIR\bin\tewisrv.exe" start= "auto"$\r$\n'
+	FileWrite $9 '"$SYSDIR\sc.exe" start "TewiHTTPd"$\r$\n'
+	FileClose $9
+	nsExec::Exec '"$INSTDIR\install.bat"'
+	Pop $0
+	Delete $INSTDIR\install.bat
+SectionEnd
+
+Function .onInit
+	StrCpy $1 ${SEL_EXEC}
+FunctionEnd
+
+Function .onSelChange
+	!insertmacro StartRadioButtons $1
+	!insertmacro RadioButton ${SEL_EXEC}
+	!insertmacro RadioButton ${SEL_SERVICE}
+	!insertmacro EndRadioButtons
+FunctionEnd
+
 Section "Uninstall"
+	ReadINIStr $8 $INSTDIR\install.ini uninstall service
+	${If} $8 == "true"
+		FileOpen $9 $INSTDIR\uninstall.bat w
+		FileWrite $9 '"$SYSDIR\sc.exe" stop "TewiHTTPd"$\r$\n'
+		FileClose $9
+		nsExec::Exec '"$INSTDIR\uninstall.bat"'
+		Pop $0
+		FileOpen $9 $INSTDIR\uninstall.bat w
+		DetailPrint "Waiting for 1s so service can stop..."
+		Sleep 1000
+		FileWrite $9 '"$SYSDIR\sc.exe" delete "TewiHTTPd"$\r$\n'
+		FileClose $9
+		nsExec::Exec '"$INSTDIR\uninstall.bat"'
+		Pop $0
+		Delete $INSTDIR\uninstall.bat
+	${EndIf}
+
 	RMDir /r "$INSTDIR"
 	RMDir /r "$SMPROGRAMS\Tewi HTTPd"
Index: trunk/Server/main.c
===================================================================
--- trunk/Server/main.c	(revision 61)
+++ trunk/Server/main.c	(revision 62)
@@ -15,4 +15,5 @@
 
 #include <cm_log.h>
+#include <cm_string.h>
 
 #include "tw_config.h"
@@ -26,43 +27,103 @@
 extern bool cm_do_log;
 extern struct tw_config config;
+extern FILE* logfile;
 
 char tw_server[2048];
 
+int startup(int argc, char** argv);
+
+#ifdef SERVICE
+SERVICE_STATUS status;
+SERVICE_STATUS_HANDLE status_handle;
+
+void WINAPI servhandler(DWORD control){
+	switch(control){
+		case SERVICE_CONTROL_STOP:
+		case SERVICE_CONTROL_SHUTDOWN:
+			status.dwCurrentState = SERVICE_STOP_PENDING;
+			break;
+	}
+	SetServiceStatus(status_handle, &status);
+}
+
+void WINAPI servmain(DWORD argc, LPSTR* argv){
+	logfile = fopen(PREFIX "/logs/tewi.log", "a");
+	if(logfile == NULL) logfile = stderr;
+	status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
+	status.dwCurrentState = SERVICE_START_PENDING;
+	status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
+	status.dwWin32ExitCode = NO_ERROR;
+	status.dwServiceSpecificExitCode = 0;
+	status.dwCheckPoint = 0;
+	status.dwWaitHint = 0;
+	status_handle = RegisterServiceCtrlHandler("Tewi HTTPd", servhandler);
+	if(status_handle == NULL) return;
+	if(SetServiceStatus(status_handle, &status) == 0) return;
+	int st = startup(argc, argv);
+	if(st != -1){
+		status.dwWin32ExitCode = NO_ERROR;
+		status.dwServiceSpecificExitCode = st;
+		status.dwCurrentState = SERVICE_STOPPED;
+		SetServiceStatus(status_handle, &status);
+		return;
+	}
+	status.dwCurrentState = SERVICE_RUNNING;
+	SetServiceStatus(status_handle, &status);
+	tw_server_loop();
+	status.dwCurrentState = SERVICE_STOPPED;
+	SetServiceStatus(status_handle, &status);
+}
+#endif
+
 int main(int argc, char** argv) {
+	logfile = stderr;
+#ifdef SERVICE
+	SERVICE_TABLE_ENTRY table[] = {{"Tewi HTTPd", servmain}, {NULL, NULL}};
+	StartServiceCtrlDispatcher(table);
+#else
+	int st = startup(argc, argv);
+	if(st != -1) return st;
+	tw_server_loop();
+#endif
+}
+
+int startup(int argc, char** argv){
 	int i;
 	const char* confpath = PREFIX "/etc/tewi.conf";
-	for(i = 1; i < argc; i++) {
-		if(argv[i][0] == '-') {
-			if(strcmp(argv[i], "--verbose") == 0 || strcmp(argv[i], "-v") == 0) {
-				if(!cm_do_log) {
-					cm_do_log = true;
-#ifndef NO_SSL
-					cm_log("", "This is Tewi HTTPd, version %s, using %s", tw_get_version(), OPENSSL_VERSION_TEXT);
-#else
-					cm_log("", "This is Tewi HTTPd, version %s", tw_get_version());
-#endif
+	if(argv != NULL){
+		for(i = 1; i < argc; i++) {
+			if(argv[i][0] == '-') {
+				if(strcmp(argv[i], "--verbose") == 0 || strcmp(argv[i], "-v") == 0) {
+					if(!cm_do_log) {
+						cm_do_log = true;
+	#ifndef NO_SSL
+						cm_log("", "This is Tewi HTTPd, version %s, using %s", tw_get_version(), OPENSSL_VERSION_TEXT);
+	#else
+						cm_log("", "This is Tewi HTTPd, version %s", tw_get_version());
+	#endif
+					} else {
+						cm_do_log = true;
+					}
+				} else if(strcmp(argv[i], "--config") == 0 || strcmp(argv[i], "-C") == 0) {
+					i++;
+					if(argv[i] == NULL) {
+						fprintf(stderr, "Missing argument\n");
+						return 1;
+					}
+					confpath = argv[i];
+				} else if(strcmp(argv[i], "--version") == 0 || strcmp(argv[i], "-V") == 0) {
+					printf("Tewi HTTPd Tewi/%s\n", tw_get_version());
+					printf("Under public domain.\n");
+					printf("Original by 2024 Nishi\n");
+					printf("\n");
+					printf("Usage: %s [--config|-C config] [--verbose|-v] [--version|-V]\n", argv[0]);
+					printf("--config  | -C config     : Specify config\n");
+					printf("--verbose | -v            : Verbose mode\n");
+					printf("--version | -V            : Version information\n");
+					return 0;
 				} else {
-					cm_do_log = true;
-				}
-			} else if(strcmp(argv[i], "--config") == 0 || strcmp(argv[i], "-C") == 0) {
-				i++;
-				if(argv[i] == NULL) {
-					fprintf(stderr, "Missing argument\n");
+					fprintf(stderr, "Unknown option: %s\n", argv[i]);
 					return 1;
 				}
-				confpath = argv[i];
-			} else if(strcmp(argv[i], "--version") == 0 || strcmp(argv[i], "-V") == 0) {
-				printf("Tewi HTTPd Tewi/%s\n", tw_get_version());
-				printf("Under public domain.\n");
-				printf("Original by 2024 Nishi\n");
-				printf("\n");
-				printf("Usage: %s [--config|-C config] [--verbose|-v] [--version|-V]\n", argv[0]);
-				printf("--config  | -C config     : Specify config\n");
-				printf("--verbose | -v            : Verbose mode\n");
-				printf("--version | -V            : Version information\n");
-				return 0;
-			} else {
-				fprintf(stderr, "Unknown option: %s\n", argv[i]);
-				return 1;
 			}
 		}
@@ -78,5 +139,7 @@
 	}
 	sprintf(tw_server, "Tewi/%s (%s)%s", tw_get_version(), tw_get_platform(), config.extension == NULL ? "" : config.extension);
-	cm_log("Daemon", "Ready, server: %s", tw_server);
+	char* r = cm_strcat(tw_server, " running...");
+	cm_force_log(r);
+	free(r);
 #ifndef __MINGW32__
 	signal(SIGCHLD, SIG_IGN);
@@ -84,4 +147,4 @@
 	SetConsoleTitle(tw_server);
 #endif
-	tw_server_loop();
+	return -1;
 }
Index: trunk/Server/server.c
===================================================================
--- trunk/Server/server.c	(revision 61)
+++ trunk/Server/server.c	(revision 62)
@@ -32,4 +32,5 @@
 #include <winsock2.h>
 #include <process.h>
+#include <windows.h>
 
 #include "strptime.h"
@@ -697,4 +698,9 @@
 }
 
+#ifdef SERVICE
+extern SERVICE_STATUS status;
+extern SERVICE_STATUS_HANDLE status_handle;
+#endif
+
 void tw_server_loop(void) {
 	struct timeval tv;
@@ -710,4 +716,10 @@
 		if(ret == -1) {
 			break;
+		}else if(ret == 0){
+#ifdef SERVICE
+			if(status.dwCurrentState == SERVICE_STOP_PENDING){
+				break;
+			}
+#endif
 		} else if(ret > 0) {
 			/* connection */
Index: trunk/installer.sh
===================================================================
--- trunk/installer.sh	(revision 62)
+++ trunk/installer.sh	(revision 62)
@@ -0,0 +1,19 @@
+#!/bin/sh
+# $Id$
+
+fail() {
+	rm -f tewi-service.exe
+	rm -f tewi.exe
+	exit 1
+}
+
+make clean || fail
+make PLATFORM=$1 -j4 || fail
+cp Server/tewi.exe tewi.exe
+make clean || fail
+make PLATFORM=$1-service -j4 || fail
+cp Server/tewi.exe tewi-service.exe
+cd Server
+makensis install.nsi
+rm -f tewi.exe tewi-service.exe
+cd ..
