Index: Makefile.win =================================================================== --- Makefile.win (revision 0) +++ Makefile.win (revision 0) @@ -0,0 +1,212 @@ +# Valid targets are: +# _mod_mono_r - build mod_mono in Release mode +# _mod_mono_d - build mod_mono in Debug mode +# _cleanr - remove (most) files generated by a Release build +# _cleand - remove (most) files generated by a Debug build +# +# The following install defaults may be customized; +# +# Option Default +# APACHEDIR ..\..\ +# APACHEVER APACHE2 +# +# APACHEDIR - Must be the root of your Apache 2 for windows installation +# - or where you have unpacked and built Apache 2 for windows sources +# APACHEVER - The allowed values are APACHE2 and APACHE22 +# +# For example; +# +# nmake /f Makefile.win APACHEDIR=..\Apache2 _mod_mono_r + +default: _mod_mono_r + +_mod_mono_r: + @$(MAKE) $(MAKEOPT) -f Makefile.win CFG="mod_mono - Win32 Release" ALL + +_mod_mono_d: + @$(MAKE) $(MAKEOPT) -f Makefile.win CFG="mod_mono - Win32 Debug" ALL + +_cleanr: + @$(MAKE) $(MAKEOPT) -f Makefile.win CFG="mod_mono - Win32 Release" CLEAN +_clean_r:_cleanr + +_cleand: + @$(MAKE) $(MAKEOPT) -f Makefile.win CFG="mod_mono - Win32 Debug" CLEAN +_clean_d:_cleand + +!IF "$(APACHEVER)" == "" +APACHEVER=APACHE2 +!ENDIF + +!IF "$(CFG)" == "" +CFG=mod_mono - Win32 Release +!ENDIF + +!IF "$(CFG)" != "mod_mono - Win32 Release" && "$(CFG)" != "mod_mono - Win32 Debug" +!ERROR An invalid configuration is specified. +!ENDIF + +!IF "$(CFG)" == "mod_mono - Win32 Release" +APACHE_BUILD=Release +OUTDIR=.\Release +INTDIR=.\Release +!ELSE +APACHE_BUILD=Debug +OUTDIR=.\Debug +INTDIR=.\Debug +!ENDIF + +!IF "$(APACHEDIR)" == "" +APACHEDIR=../../ +!ENDIF + +!IF "$(APACHEVER)" == "APACHE2" || "$(APACHEVER)" == "APACHE22" +!IF !EXIST("$(APACHEDIR)") +!ERROR mod_mono needs Apache for win32 +!ELSE IF EXIST("$(APACHEDIR)\srclib") +!IF !EXIST("$(APACHEDIR)\srclib\apr") || !EXIST("$(APACHEDIR)\srclib\apr-util") +!MESSAGE Please check out or download and unpack the Apache Source for Win32 +!MESSAGE mod_mono cannot build without building Apache before! +!MESSAGE +!ERROR mod_mono needs Apache for win32 +!ELSE +APACHE_LIB=$(APACHEDIR)\$(APACHE_BUILD) +APACHE_INCLUDE=$(APACHEDIR)\include +APACHE_APR_LIB=$(APACHEDIR)\srclib\apr\$(APACHE_BUILD) +APACHE_APR_INCLUDE=$(APACHEDIR)\srclib\apr\include +APACHE_APRUTIL_INCLUDE=$(APACHEDIR)\srclib\apr-util\include +!ENDIF +!ELSE IF EXIST("$(APACHEDIR)\bin\Apache.exe") || EXIST("$(APACHEDIR)\bin\httpd.exe") +!IF !EXIST("$(APACHEDIR)\include") || !EXIST("$(APACHEDIR)\lib") +!MESSAGE Please check your installation of Apache for Win32 +!MESSAGE mod_mono cannot build without the headers and libraries! +!MESSAGE from Apache for Win32 +!MESSAGE +!ERROR mod_mono needs Apache for win32 +!ELSE +APACHE_LIB=$(APACHEDIR)\lib +APACHE_INCLUDE=$(APACHEDIR)\include +APACHE_APR_LIB=$(APACHEDIR)\lib +APACHE_APR_INCLUDE=$(APACHEDIR)\include +APACHE_APRUTIL_INCLUDE=$(APACHEDIR)\include +!ENDIF +!ELSE +!ERROR mod_mono needs Apache for win32 +!ENDIF +!ELSE +!ERROR mod_mono only builds with APACHE 2 under windows +!ENDIF + +!IF "$(OS)" == "Windows_NT" +NULL= +!ELSE +NULL=nul +!ENDIF + +CLEAN : + -@erase ".\include\mod_mono_config.h" + -@erase "$(INTDIR)\mod_mono.obj" + -@erase "$(INTDIR)\mod_mono_src.idb" + -@erase "$(INTDIR)\mod_mono_src.pdb" + -@erase "$(OUTDIR)\mod_mono.exp" + -@erase "$(OUTDIR)\mod_mono.lib" + -@erase "$(OUTDIR)\mod_mono.pdb" + -@erase "$(OUTDIR)\mod_mono.so" + +!IF "$(CFG)" == "mod_mono - Win32 Release" + +ALL : "$(OUTDIR)\mod_mono.so" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP=cl.exe +CPP_PROJ=/nologo /MD /W3 /Zi /O2 /I "./include" /I "$(APACHE_INCLUDE)" /I "$(APACHE_APR_INCLUDE)" /I "$(APACHE_APRUTIL_INCLUDE)" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "$(APACHEVER)" /D "HAVE_CONFIG_H" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\mod_mono_src" /FD /c +!IF "$(APACHEVER)" == "APACHE22" +CPP_PROJ=$(CPP_PROJ) /D "APACHE2" +!ENDIF +.c{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +MTL=midl.exe +MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32 + +LINK32=link.exe +LINK32_FLAGS=kernel32.lib /nologo /subsystem:windows /dll /incremental:no /pdb:"$(OUTDIR)\mod_mono.pdb" /debug /machine:I386 /out:"$(OUTDIR)\mod_mono.so" /implib:"$(OUTDIR)\mod_mono.lib" +!IF "$(APACHEVER)" == "APACHE22" +LINK32_OBJS= \ + "$(INTDIR)\mod_mono.obj" \ + "$(APACHE_APR_LIB)\libapr-1.lib" \ + "$(APACHE_LIB)\libhttpd.lib" +!ELSE +LINK32_OBJS= \ + "$(INTDIR)\mod_mono.obj" \ + "$(APACHE_APR_LIB)\libapr.lib" \ + "$(APACHE_LIB)\libhttpd.lib" +!ENDIF + +"$(OUTDIR)\mod_mono.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ELSEIF "$(CFG)" == "mod_mono - Win32 Debug" + +OUTDIR=.\Debug +INTDIR=.\Debug + +ALL : "$(OUTDIR)\mod_mono.so" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP=cl.exe +CPP_PROJ=/nologo /MD /W3 /GX /Zi /Od /I "./include" /I "$(APACHE_INCLUDE)" /I "$(APACHE_APR_INCLUDE)" /I "$(APACHE_APRUTIL_INCLUDE)" /D "DEBUG" /D "WIN32" /D "_WINDOWS" /D "$(APACHEVER)" /D "HAVE_CONFIG_H" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\mod_mono_src" /FD /c +!IF "$(APACHEVER)" == "APACHE22" +CPP_PROJ=$(CPP_PROJ) /D "APACHE2" +!ENDIF + +.c{$(INTDIR)}.obj:: + $(CPP) @<< + $(CPP_PROJ) $< +<< + +MTL=midl.exe +MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /win32 + +LINK32=link.exe +LINK32_FLAGS=kernel32.lib /nologo /subsystem:windows /dll /incremental:no /pdb:"$(OUTDIR)\mod_mono.pdb" /debug /machine:I386 /out:"$(OUTDIR)\mod_mono.so" /implib:"$(OUTDIR)\mod_mono.lib" +!IF "$(APACHEVER)" == "APACHE22" +LINK32_OBJS= \ + "$(INTDIR)\mod_mono.obj" \ + "$(APACHE_APR_LIB)\libapr-1.lib" \ + "$(APACHE_LIB)\libhttpd.lib" +!ELSE +LINK32_OBJS= \ + "$(INTDIR)\mod_mono.obj" \ + "$(APACHE_APR_LIB)\libapr.lib" \ + "$(APACHE_LIB)\libhttpd.lib" +!ENDIF + + +"$(OUTDIR)\mod_mono.so" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ENDIF + +SOURCE=.\src\mod_mono.c + +"$(INTDIR)\mod_mono.obj" : $(SOURCE) "$(INTDIR)" ".\include\mod_mono_config.h" + $(CPP) $(CPP_PROJ) $(SOURCE) + +".\include\mod_mono_config.h" : $(SOURCE) "$(INTDIR)" + if not exist "include" mkdir "include" + < ".\include\mod_mono_config.h" +<< + Index: src/mod_mono.c =================================================================== --- src/mod_mono.c (revision 78965) +++ src/mod_mono.c (working copy) @@ -149,6 +149,46 @@ return NULL; } +#ifdef WIN32 +static char *get_regkey_prefix(apr_pool_t *p) { + ap_regkey_t *key_mono; + ap_regkey_t *key_clr; + apr_status_t rv; + char *default_clr; + char *sdk_root; + rv = ap_regkey_open(&key_mono, AP_REGKEY_LOCAL_MACHINE, "SOFTWARE\\Novell\\Mono", APR_READ, p); + if (rv != APR_SUCCESS) { + return NULL; + } + rv = ap_regkey_value_get(&default_clr, key_mono, "DefaultCLR", p); + if (rv != APR_SUCCESS) { + ap_regkey_close(key_mono); + return NULL; + } + rv = ap_regkey_open(&key_clr, key_mono, default_clr, APR_READ, p); + ap_regkey_close(key_mono); + if (rv != APR_SUCCESS) { + return NULL; + } + rv = ap_regkey_value_get(&sdk_root, key_clr, "SdkInstallRoot", p); + if (rv != APR_SUCCESS) { + ap_regkey_close(key_clr); + return NULL; + } + ap_regkey_close(key_clr); + DEBUG_PRINT (1, "Registry key found. SdkInstallRoot: '%s'", sdk_root); + return sdk_root; +} +static char *get_mono_path(apr_pool_t *pool, char *default_value, const char *suffix) { + char *sdk_root = get_regkey_prefix(pool); + if ( sdk_root==NULL ) { + DEBUG_PRINT (1, "Registry key not found, defaulting setting to '%s'", default_value); + return default_value; + } + return apr_pstrcat(pool, sdk_root, suffix, NULL); +} +#endif + static int add_xsp_server (apr_pool_t *pool, const char *alias, module_cfg *config, int is_default, int is_virtual) { @@ -167,17 +207,25 @@ server->filename = NULL; server->umask_value = NULL; server->run_xsp = "True"; +#ifndef WIN32 /* (Obsolete) server->executable_path = EXECUTABLE_PATH; */ server->path = NULL; server->server_path = MODMONO_SERVER_PATH; + server->listen_port = NULL; + server->wapidir = WAPIDIR; +#else + /* (Obsolete) server->executable_path = get_mono_path(pool, EXECUTABLE_PATH, "/bin/mono.exe"); */ + server->path = NULL; + server->server_path = get_mono_path(pool, MODMONO_SERVER_PATH, "/bin/mod-mono-server.bat"); + server->listen_port = apr_psprintf (pool, "%d", atoi(LISTEN_PORT) + config->nservers); + apr_env_get(&server->wapidir, "TEMP", pool); +#endif server->applications = NULL; - server->wapidir = WAPIDIR; server->document_root = DOCUMENT_ROOT; server->appconfig_file = APPCONFIG_FILE; if (is_default) server->appconfig_dir = APPCONFIG_DIR; - server->listen_port = NULL; server->listen_address = NULL; server->max_cpu_time = NULL; server->max_memory = NULL; @@ -327,7 +375,9 @@ server->auto_app = TRUE; server->auto_app_set = FALSE; add_xsp_server (p, "XXGLOBAL", server, FALSE, FALSE); +#ifndef WIN32 server->servers [0].filename = get_default_global_socket_name (p, SOCKET_FILE); +#endif return server; } @@ -859,13 +909,20 @@ try_connect (xsp_data *conf, apr_socket_t **sock, apr_pool_t *pool) { char *error; +#ifndef WIN32 struct sockaddr_un unix_address; struct sockaddr *ptradd; +#endif char *fn = NULL; char *la = NULL; int err; if (conf->listen_port == NULL) { +#ifdef WIN32 + ap_log_error (APLOG_MARK, APLOG_ERR, STATUS_AND_SERVER, + "mod_mono: MonoUnixSocket not supported under windows. MonoListenPort must be used instead."); + return -2; /* Unrecoverable */ +#else apr_os_sock_t sock_fd; apr_os_sock_get (&sock_fd, *sock); @@ -880,6 +937,7 @@ ptradd = (struct sockaddr *) &unix_address; if (connect (sock_fd, ptradd, sizeof (unix_address)) != -1) return APR_SUCCESS; +#endif } else { apr_status_t rv; apr_sockaddr_t *sa; @@ -904,9 +962,11 @@ err = errno; DEBUG_PRINT (1, "errno in try_connect %d %s", err, strerror (err)); switch (err) { +#ifdef APACHE13 case ENOENT: case ECONNREFUSED: return -1; /* Can try to launch mod-mono-server */ +#endif case EPERM: error = strerror (err); if (conf->listen_port == NULL) @@ -921,6 +981,10 @@ apr_socket_close (*sock); return -2; /* Unrecoverable */ default: +#ifdef APACHE2 + if ( APR_STATUS_IS_ECONNREFUSED(errno) || APR_STATUS_IS_ENOENT(errno) ) + return -1; /* Can try to launch mod-mono-server */ +#endif error = strerror (err); if (conf->listen_port == NULL) ap_log_error (APLOG_MARK, APLOG_ERR, STATUS_AND_SERVER, @@ -968,9 +1032,13 @@ } # else -# error No setenv or putenv found! +# ifdef WIN32 +# define SETENV(pool, name, value) apr_env_set (name, value, pool) +# else +# error No setenv or putenv found! #endif #endif +#endif static void set_environment_variables (apr_pool_t *pool, char *environment_variables) @@ -1025,9 +1093,195 @@ #endif } +#ifdef WIN32 static void fork_mod_mono_server (apr_pool_t *pool, xsp_data *config) { + apr_status_t rc; + apr_procattr_t *procattr; + apr_proc_t *procnew; + const int MAXARGS = 21; + char *argv [21]; + int argi; + char *path; + char *tmp; + char *serverdir; + char *wapidir; + int max_memory = 0; + int max_cpu_time = 0; + char is_master; + + /* Running mod-mono-server not requested */ + if (!strcasecmp (config->run_xsp, "false")) { + DEBUG_PRINT (1, "Not running mod-mono-server: %s", config->run_xsp); + ap_log_error (APLOG_MARK, APLOG_DEBUG, STATUS_AND_SERVER, + "Not running mod-mono-server.exe"); + return; + } + + is_master = (0 == strcmp ("XXGLOBAL", config->alias)); + /* + * At least one of MonoApplications, MonoApplicationsConfigFile or + * MonoApplicationsConfigDir must be specified, except for the 'global' + * instance that will be used to create applications on demand. + */ + DEBUG_PRINT (1, "Applications: %s", config->applications); + DEBUG_PRINT (1, "Config file: %s", config->appconfig_file); + DEBUG_PRINT (1, "Config dir.: %s", config->appconfig_dir); + if (!is_master && config->applications == NULL && config->appconfig_file == NULL && + config->appconfig_dir == NULL) { + ap_log_error (APLOG_MARK, APLOG_ERR, + STATUS_AND_SERVER, + "Not running mod-mono-server.exe because no MonoApplications, " + "MonoApplicationsConfigFile or MonoApplicationConfigDir specified."); + return; + } + + /* Only one of MonoUnixSocket and MonoListenPort. */ + DEBUG_PRINT (1, "Listen port: %s", config->listen_port); + if (config->listen_port != NULL && config->filename != NULL) { + ap_log_error (APLOG_MARK, APLOG_ERR, STATUS_AND_SERVER, + "Not running mod-mono-server.exe because both MonoUnixSocket and " + "MonoListenPort specified."); + return; + } + + /* MonoListenAddress must be used together with MonoListenPort */ + DEBUG_PRINT (1, "Listen address: %s", config->listen_address); + if (config->listen_port == NULL && config->listen_address != NULL) { + ap_log_error (APLOG_MARK, APLOG_ERR, STATUS_AND_SERVER, + "Not running mod-mono-server.exe because MonoListenAddress " + "is present and there is no MonoListenPort."); + return; + } + if (config->max_memory != NULL) + max_memory = atoi (config->max_memory); + + if (config->max_cpu_time != NULL) + max_cpu_time = atoi (config->max_cpu_time); + + set_environment_variables (pool, config->env_vars); + + tmp = getenv ("PATH"); + DEBUG_PRINT (1, "PATH: %s", tmp); + if (tmp == NULL) + tmp = ""; + + serverdir = get_directory (pool, config->server_path); + DEBUG_PRINT (1, "serverdir: %s", serverdir); + path = apr_pcalloc (pool, strlen (tmp) + strlen (serverdir) + 2); + sprintf (path, "%s" DIRECTORY_SEPARATOR "%s", serverdir, tmp); + + DEBUG_PRINT (1, "PATH after: %s", path); + SETENV (pool, "PATH", path); + if (config->path != NULL) + SETENV (pool, "MONO_PATH", config->path); + wapidir = apr_pcalloc (pool, strlen (config->wapidir) + 5 + 2); + sprintf (wapidir, "%s/%s", config->wapidir, ".wapi"); + apr_dir_make (wapidir, (APR_UREAD | APR_UWRITE | APR_UEXECUTE), pool); + if (chmod (wapidir, 0700) != 0 && (errno == EPERM || errno == EACCES)) { + ap_log_error (APLOG_MARK, APLOG_ERR, STATUS_AND_SERVER, + "%s: %s", wapidir, strerror (errno)); + exit (1); + } + + SETENV (pool, "MONO_SHARED_DIR", config->wapidir); + if (config->debug && !strcasecmp (config->debug, "True")) + SETENV (pool, "MONO_OPTIONS", "--debug"); + + memset (argv, 0, sizeof (char *) * MAXARGS); + argi = 0; + + argv [argi++] = config->server_path; + if (config->listen_port != NULL) { + char *la; + + la = config->listen_address; + la = la ? la : LISTEN_ADDRESS; + argv [argi++] = "--address"; + argv [argi++] = la; + argv [argi++] = "--port"; + argv [argi++] = config->listen_port; + } else { + char *fn; + + fn = config->filename; + if (fn == NULL) + fn = get_default_socket_name (pool, config->alias, SOCKET_FILE); + + argv [argi++] = "--filename"; + argv [argi++] = fn; + } + + if (config->applications != NULL) { + argv [argi++] = "--applications"; + argv [argi++] = config->applications; + } + + argv [argi++] = "--nonstop"; + if (config->document_root != NULL) { + argv [argi++] = "--root"; + argv [argi++] = config->document_root; + } + + if (config->appconfig_file != NULL) { + argv [argi++] = "--appconfigfile"; + argv [argi++] = config->appconfig_file; + } + + if (config->appconfig_dir != NULL) { + argv [argi++] = "--appconfigdir"; + argv [argi++] = config->appconfig_dir; + } + + if (is_master) + argv [argi++] = "--master"; + /* + * The last element in the argv array must always be NULL + * to terminate the array for execv(). + * + * Any new argi++'s that are added here must also increase + * the maxargs argument at the top of this method to prevent + * array out-of-bounds. + */ + + ap_log_error (APLOG_MARK, APLOG_DEBUG, STATUS_AND_SERVER, + "running '%s %s %s %s %s %s %s %s %s %s %s %s %s'", + argv [0], argv [1], argv [2], argv [3], argv [4], + argv [5], argv [6], argv [7], argv [8], + argv [9], argv [10], argv [11], argv [12]); + + if (((rc = apr_procattr_create(&procattr, pool)) != APR_SUCCESS) || + ((rc = apr_procattr_io_set(procattr, APR_FULL_BLOCK, APR_FULL_BLOCK, APR_FULL_BLOCK)) != APR_SUCCESS) || + ((rc = apr_procattr_dir_set(procattr, ap_make_dirstr_parent(pool, argv[0]))) != APR_SUCCESS) || + ((rc = apr_procattr_cmdtype_set(procattr, APR_PROGRAM_ENV)) != APR_SUCCESS)) { + /* Something bad happened, give up and go away. */ + ap_log_error (APLOG_MARK, APLOG_ERR, STATUS_AND_SERVER, + "Failed running '%s %s %s %s %s %s %s %s %s %s %s %s %s'. Reason: %s", + argv [0], argv [1], argv [2], argv [3], argv [4], + argv [5], argv [6], argv [7], argv [8], + argv [9], argv [10], argv [11], argv [12], + strerror (errno)); + } else { + procnew = apr_pcalloc(pool, sizeof(*procnew)); + rc = apr_proc_create(procnew, argv[0], (const char **)argv, NULL, procattr, pool); + if (rc == APR_SUCCESS) { + apr_pool_note_subprocess(pool, procnew, APR_KILL_ALWAYS); + } else { + ap_log_error (APLOG_MARK, APLOG_ERR, STATUS_AND_SERVER, + "Failed running '%s %s %s %s %s %s %s %s %s %s %s %s %s'. Reason: %s", + argv [0], argv [1], argv [2], argv [3], argv [4], + argv [5], argv [6], argv [7], argv [8], + argv [9], argv [10], argv [11], argv [12], + strerror (errno)); + } + } +} +#else + +static void +fork_mod_mono_server (apr_pool_t *pool, xsp_data *config) +{ pid_t pid; int i; const int MAXARGS = 21; @@ -1225,6 +1479,7 @@ strerror (errno)); exit (1); } +#endif static apr_status_t setup_socket (apr_socket_t **sock, xsp_data *conf, apr_pool_t *pool) @@ -1980,3 +2235,4 @@ }; #endif + Index: src/mod_mono.h =================================================================== --- src/mod_mono.h (revision 78965) +++ src/mod_mono.h (working copy) @@ -52,6 +52,13 @@ #include "http_log.h" #include "http_config.h" +#ifdef WIN32 +#include +#include +typedef __int32 int32_t; +typedef unsigned __int32 uint32_t; +#define HAVE_APR_SOCKET_CONNECT +#endif #ifdef APACHE13 /* Functions needed for making Apache 1.3 module as similar @@ -167,6 +174,7 @@ #define APPCONFIG_DIR NULL #define SOCKET_FILE "/tmp/mod_mono_server" #define LISTEN_ADDRESS "127.0.0.1" +#define LISTEN_PORT "2000" /* Converts every int sent into little endian */ #ifdef MODMONO_BIGENDIAN @@ -263,12 +271,27 @@ /* Debugging */ #ifdef DEBUG +#ifdef WIN32 +#define DEBUG_PRINT debug_print +static void debug_print(int a, char *format,...) { + if (a >= DEBUG_LEVEL) { + char buffer[1024]; + va_list args; + errno = 0; + va_start (args, format); + apr_vsnprintf (buffer, sizeof(buffer), format, args); + ap_log_error (APLOG_MARK, APLOG_WARNING, STATUS_AND_SERVER, buffer); + va_end (args); + } +} +#else #define DEBUG_PRINT(a,...) \ if (a >= DEBUG_LEVEL) { \ errno = 0; \ ap_log_error (APLOG_MARK, APLOG_WARNING, STATUS_AND_SERVER, \ __VA_ARGS__); \ } +#endif /* WIN32 */ #else #define DEBUG_PRINT dummy_print static void @@ -279,3 +302,4 @@ #endif /* __MOD_MONO_H */ +