5 * Daniel Lopez Ridruejo
6 * Gonzalo Paniagua Javier
8 * Copyright (c) 2002 Daniel Lopez Ridruejo
9 * (c) 2002-2005 Novell, Inc.
11 * Licensed under the Apache License, Version 2.0 (the "License");
12 * you may not use this file except in compliance with the License.
13 * You may obtain a copy of the License at
15 * http://www.apache.org/licenses/LICENSE-2.0
17 * Unless required by applicable law or agreed to in writing, software
18 * distributed under the License is distributed on an "AS IS" BASIS,
19 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 * See the License for the specific language governing permissions and
21 * limitations under the License.
24 #include "mod_mono_config.h"
27 /* uncomment this to get tons of messages in the log */
28 /* or use --enable-debug with configure */
34 DEFINE_MODULE (mono_module
);
36 /* Configuration pool. Cleared on restart. */
37 static apr_pool_t
*pconf
;
39 typedef struct per_dir_config
{
52 typedef struct xsp_data
{
56 char *executable_path
;
70 char status
; /* One of the FORK_* in the enum above.
71 * Don't care if run_xsp is "false" */
72 char is_virtual
; /* is the server virtual? */
82 search_for_alias (const char *alias
, module_cfg
*config
)
87 for (i
= 0; i
< config
->nservers
; i
++) {
88 xsp
= &config
->servers
[i
];
89 if (alias
== NULL
&& !strcmp (xsp
->alias
, "default"))
92 if (!strcmp (alias
, xsp
->alias
))
100 set_alias (cmd_parms
*cmd
, void *mconfig
, const char *alias
)
102 per_dir_config
*config
= mconfig
;
105 sconfig
= ap_get_module_config (cmd
->server
->module_config
, &mono_module
);
106 config
->alias
= (char *) alias
;
107 if (search_for_alias (alias
, sconfig
) == -1) {
108 char *err
= apr_pstrcat (cmd
->pool
, "Server alias '", alias
, ", not found.", NULL
);
116 add_xsp_server (apr_pool_t
*pool
, const char *alias
, module_cfg
*config
, int is_virtual
)
124 i
= search_for_alias (alias
, config
);
128 is_default
= (alias
== NULL
|| !strcmp (alias
, "default"));
129 server
= apr_pcalloc (pool
, sizeof (xsp_data
));
130 server
->alias
= apr_pstrdup (pool
, alias
);
131 server
->filename
= NULL
;
132 server
->run_xsp
= "True";
133 server
->executable_path
= EXECUTABLE_PATH
;
134 server
->path
= MONO_PATH
;
135 server
->server_path
= MODMONO_SERVER_PATH
;
136 server
->applications
= NULL
;
137 server
->wapidir
= WAPIDIR
;
138 server
->document_root
= DOCUMENT_ROOT
;
139 server
->appconfig_file
= APPCONFIG_FILE
;
141 server
->appconfig_dir
= APPCONFIG_DIR
;
143 server
->listen_port
= NULL
;
144 server
->listen_address
= NULL
;
145 server
->max_cpu_time
= NULL
;
146 server
->max_memory
= NULL
;
147 server
->debug
= "False";
148 server
->env_vars
= NULL
;
149 server
->status
= FORK_NONE
;
150 server
->is_virtual
= is_virtual
;
152 nservers
= config
->nservers
+ 1;
153 servers
= config
->servers
;
154 config
->servers
= apr_pcalloc (pool
, sizeof (xsp_data
) * nservers
);
155 if (config
->nservers
> 0)
156 memcpy (config
->servers
, servers
, sizeof (xsp_data
) * config
->nservers
);
158 memcpy (&config
->servers
[config
->nservers
], server
, sizeof (xsp_data
));
159 config
->nservers
= nservers
;
161 return config
->nservers
- 1;
165 store_config_xsp (cmd_parms
*cmd
, void *notused
, const char *first
, const char *second
)
169 char *prev_value
= NULL
;
174 unsigned long offset
;
176 offset
= (unsigned long) cmd
->info
;
177 DEBUG_PRINT (1, "store_config %lu '%s' '%s'", offset
, first
, second
);
178 config
= ap_get_module_config (cmd
->server
->module_config
, &mono_module
);
180 if (second
== NULL
) {
188 idx
= search_for_alias (alias
, config
);
190 idx
= add_xsp_server (cmd
->pool
, alias
, config
, cmd
->server
->is_virtual
);
192 ptr
= (char *) &config
->servers
[idx
];
195 /* MonoApplications/AddMonoApplications are accumulative */
196 if (offset
== APR_OFFSETOF (xsp_data
, applications
))
197 prev_value
= *((char **) ptr
);
199 if (prev_value
!= NULL
) {
200 new_value
= apr_pstrcat (cmd
->pool
, prev_value
, ",", value
, NULL
);
202 new_value
= apr_pstrdup (cmd
->pool
, value
);
205 *((char **) ptr
) = new_value
;
206 DEBUG_PRINT (1, "store_config end: %s", new_value
);
211 merge_config (apr_pool_t
*p
, void *base_conf
, void *new_conf
)
213 module_cfg
*base_module
= (module_cfg
*) base_conf
;
214 module_cfg
*new_module
= (module_cfg
*) new_conf
;
215 xsp_data
*base_config
;
216 xsp_data
*new_config
;
219 if (new_module
->nservers
== 0)
222 base_config
= base_module
->servers
;
223 new_config
= new_module
->servers
;
224 nservers
= base_module
->nservers
+ new_module
->nservers
;
226 /* FIXME: error out on duplicate aliases. */
227 base_module
->servers
= apr_pcalloc (p
, sizeof (xsp_data
) * nservers
);
228 memcpy (base_module
->servers
, base_config
, sizeof (xsp_data
) * base_module
->nservers
);
229 memcpy (&base_module
->servers
[base_module
->nservers
], new_config
, new_module
->nservers
* sizeof (xsp_data
));
230 base_module
->nservers
= nservers
;
231 DEBUG_PRINT (1, "Total mod-mono-servers to spawn so far: %d", nservers
);
236 create_dir_config (apr_pool_t
*p
, char *dirspec
)
240 DEBUG_PRINT (1, "creating dir config for %s", dirspec
);
242 cfg
= apr_pcalloc (p
, sizeof (per_dir_config
));
244 cfg
->location
= apr_pstrdup (p
, dirspec
);
250 create_mono_server_config (apr_pool_t
*p
, server_rec
*s
)
254 server
= apr_pcalloc (p
, sizeof (module_cfg
));
259 request_send_response_from_memory (request_rec
*r
, char *byteArray
, int size
)
262 if (r
->sent_bodyct
== 0)
263 ap_send_http_header (r
);
266 ap_rwrite (byteArray
, size
, r
);
270 request_send_response_string (request_rec
*r
, char *byteArray
)
272 request_send_response_from_memory (r
, byteArray
, strlen (byteArray
));
275 /* Not connection because actual port will vary depending on Apache configuration */
277 request_get_server_port (request_rec
*r
)
279 return ap_get_server_port (r
);
283 connection_get_remote_port (conn_rec
*c
)
286 return ntohs (c
->remote_addr
.sin_port
);
289 apr_sockaddr_port_get (&port
, c
->remote_addr
);
296 connection_get_local_port (request_rec
*r
)
299 return ap_get_server_port (r
);
302 apr_sockaddr_port_get (&port
, r
->connection
->local_addr
);
308 connection_get_remote_name (request_rec
*r
)
311 return ap_get_remote_host (r
->connection
, r
->per_dir_config
, REMOTE_NAME
);
313 return ap_get_remote_host (r
->connection
, r
->per_dir_config
, REMOTE_NAME
, NULL
);
318 * This does a kind of final flush which is not what we want.
319 * It caused bug 60117.
321 connection_flush (request_rec *r)
326 ap_flush_conn (r->connection);
332 set_response_header (request_rec
*r
,
336 if (!strcasecmp (name
,"Content-Type")) {
337 r
->content_type
= value
;
339 apr_table_addn (r
->headers_out
, name
, value
);
344 setup_client_block (request_rec
*r
)
349 return ap_setup_client_block (r
, REQUEST_CHUNKED_ERROR
);
353 write_data (apr_socket_t
*sock
, const void *str
, apr_size_t size
)
355 apr_size_t prevsize
= size
;
357 if (apr_socket_send (sock
, str
, &size
) != APR_SUCCESS
)
360 return (prevsize
== size
) ? size
: -1;
364 write_data_string (apr_socket_t
*sock
, const char *str
)
369 l
= (str
== NULL
) ? 0 : strlen (str
);
370 lel
= LE_FROM_INT (l
);
371 if (write_data (sock
, &lel
, sizeof (int)) != sizeof (int))
377 return write_data (sock
, str
, l
);
381 read_data (apr_socket_t
*sock
, void *ptr
, apr_size_t size
)
383 if (apr_socket_recv (sock
, ptr
, &size
) != APR_SUCCESS
)
390 read_data_string (apr_pool_t
*pool
, apr_socket_t
*sock
, char **ptr
, apr_size_t
*size
)
396 if (read_data (sock
, &l
, sizeof (int)) == -1)
400 buf
= apr_pcalloc (pool
, l
+ 1);
403 result
= read_data (sock
, buf
+ l
- count
, count
);
420 do_command (int command
, apr_socket_t
*sock
, request_rec
*r
, int *result
)
428 if (command
< 0 || command
>= LAST_COMMAND
) {
429 ap_log_error (APLOG_MARK
, APLOG_ERR
, STATUS_AND_SERVER
,
430 "Unknown command: %d", command
);
431 *result
= HTTP_INTERNAL_SERVER_ERROR
;
435 DEBUG_PRINT (2, "Command received: %s", cmdNames
[command
]);
438 case SEND_FROM_MEMORY
:
439 if (read_data_string (r
->pool
, sock
, &str
, &size
) == NULL
) {
443 request_send_response_from_memory (r
, str
, size
);
445 case GET_SERVER_VARIABLE
:
446 if (read_data_string (r
->pool
, sock
, &str
, NULL
) == NULL
)
449 if (!strcmp (str
, "SERVER_PORT_SECURE")) {
450 /* This does not work well for apache 1.3 */
451 str
= (strcmp (ap_http_method (r
), "https") == 0) ? "True" : NULL
;
453 str
= (char *) apr_table_get (r
->subprocess_env
, str
);
456 status
= write_data_string (sock
, str
);
458 case SET_RESPONSE_HEADER
:
459 if (read_data_string (r
->pool
, sock
, &str
, NULL
) == NULL
) {
463 if (read_data_string (r
->pool
, sock
, &str2
, NULL
) == NULL
) {
467 set_response_header (r
, str
, str2
);
470 i
= connection_get_local_port (r
);
472 status
= write_data (sock
, &i
, sizeof (int));
479 case SHOULD_CLIENT_BLOCK
:
480 size
= ap_should_client_block (r
);
481 size
= LE_FROM_INT (size
);
482 status
= write_data (sock
, &size
, sizeof (int));
484 case SETUP_CLIENT_BLOCK
:
485 if (setup_client_block (r
) != APR_SUCCESS
) {
486 size
= LE_FROM_INT (-1);
487 status
= write_data (sock
, &size
, sizeof (int));
491 size
= LE_FROM_INT (0);
492 status
= write_data (sock
, &size
, sizeof (int));
494 case GET_CLIENT_BLOCK
:
495 status
= read_data (sock
, &i
, sizeof (int));
500 str
= apr_pcalloc (r
->pool
, i
);
501 i
= ap_get_client_block (r
, str
, i
);
503 status
= write_data (sock
, &i
, sizeof (int));
505 status
= write_data (sock
, str
, i
);
508 status
= read_data (sock
, &i
, sizeof (int));
512 if (read_data_string (r
->pool
, sock
, &str
, NULL
) == NULL
) {
516 r
->status
= INT_FROM_LE (i
);
517 r
->status_line
= apr_pstrdup (r
->pool
, str
);
519 case DECLINE_REQUEST
:
523 ap_log_error (APLOG_MARK
, APLOG_ERR
, STATUS_AND_SERVER
,
524 "No application found for %s", r
->uri
);
526 ap_log_error (APLOG_MARK
, APLOG_ERR
, STATUS_AND_SERVER
,
527 "Host header was %s",
528 apr_table_get (r
->headers_in
, "host"));
530 *result
= HTTP_NOT_FOUND
;
533 *result
= HTTP_INTERNAL_SERVER_ERROR
;
538 *result
= HTTP_INTERNAL_SERVER_ERROR
;
547 apr_sockaddr_info_get (apr_sockaddr_t
**sa
, const char *hostname
,
548 int family
, int port
, int flags
, apr_pool_t
*p
)
550 struct addrinfo hints
, *list
;
552 struct sockaddr_in
*addr
;
554 if (port
< 0 || port
> 65535)
557 memset (&hints
, 0, sizeof (hints
));
558 hints
.ai_family
= family
;
559 hints
.ai_socktype
= SOCK_STREAM
;
560 error
= getaddrinfo (hostname
, NULL
, &hints
, &list
);
562 ap_log_error (APLOG_MARK
, APLOG_ERR
, STATUS_AND_SERVER
,
563 "mod_mono: getaddrinfo failed (%s) hostname: '%s' port: '%d'.",
564 strerror (error
), hostname
, port
);
569 *sa
= apr_pcalloc (p
, sizeof (apr_sockaddr_t
));
571 (*sa
)->addrlen
= list
->ai_addrlen
;
572 (*sa
)->addr
= apr_pcalloc (p
, list
->ai_addrlen
);
573 memcpy ((*sa
)->addr
, list
->ai_addr
, list
->ai_addrlen
);
574 addr
= (struct sockaddr_in
*) (*sa
)->addr
;
575 addr
->sin_port
= htons (port
);
583 apr_socket_connect (apr_socket_t
*sock
, apr_sockaddr_t
*sa
)
587 apr_os_sock_get (&sock_fd
, sock
);
588 if (connect (sock_fd
, sa
->addr
, sa
->addrlen
) != 0)
595 apr_socket_send (apr_socket_t
*sock
, const char *buf
, apr_size_t
*len
)
602 result
= write (sock
->fd
, buf
+ total
, (*len
) - total
);
605 } while ((result
>= 0 && total
< *len
) || (result
== -1 && errno
== EINTR
));
607 return (total
== *len
) ? 0 : -1;
611 apr_socket_recv (apr_socket_t
*sock
, char *buf
, apr_size_t
*len
)
615 apr_os_sock_t sock_fd
;
617 apr_os_sock_get (&sock_fd
, sock
);
620 result
= read (sock_fd
, buf
+ total
, (*len
) - total
);
623 } while ((result
>= 0 && total
< *len
) || (result
== -1 && errno
== EINTR
));
625 return (total
== *len
) ? 0 : -1;
633 tv
.tv_usec
= t
% 1000000;
634 tv
.tv_sec
= t
/ 1000000;
635 select (0, NULL
, NULL
, NULL
, &tv
);
637 #elif !defined (HAVE_APR_SOCKET_CONNECT)
638 /* libapr-0 <= 0.9.3 (or 0.9.2?) */
639 # define apr_socket_connect apr_connect
643 get_default_socket_name (apr_pool_t
*pool
, const char *alias
, const char *base
)
645 if (alias
== NULL
|| !strcmp (alias
, "default"))
646 return (char *) base
;
648 return apr_pstrcat (pool
, base
, "_", alias
, NULL
);
652 try_connect (xsp_data
*conf
, apr_socket_t
**sock
, apr_pool_t
*pool
)
655 struct sockaddr_un unix_address
;
656 struct sockaddr
*ptradd
;
661 if (conf
->listen_port
== NULL
) {
662 apr_os_sock_t sock_fd
;
664 apr_os_sock_get (&sock_fd
, *sock
);
665 unix_address
.sun_family
= PF_UNIX
;
666 if (conf
->filename
!= NULL
)
669 fn
= get_default_socket_name (pool
, conf
->alias
, SOCKET_FILE
);
671 DEBUG_PRINT (1, "Socket file name %s", fn
);
672 memcpy (unix_address
.sun_path
, fn
, strlen (fn
) + 1);
673 ptradd
= (struct sockaddr
*) &unix_address
;
674 if (connect (sock_fd
, ptradd
, sizeof (unix_address
)) != -1)
680 la
= conf
->listen_address
? conf
->listen_address
: LISTEN_ADDRESS
;
681 rv
= apr_sockaddr_info_get (&sa
, la
, APR_INET
,
682 atoi (conf
->listen_port
), 0, pool
);
684 if (rv
!= APR_SUCCESS
) {
685 ap_log_error (APLOG_MARK
, APLOG_ERR
, STATUS_AND_SERVER
,
686 "mod_mono: error in address ('%s') or port ('%s').",
687 la
, conf
->listen_port
);
691 rv
= apr_socket_connect (*sock
, sa
);
692 if (rv
== APR_SUCCESS
)
698 DEBUG_PRINT (1, "errno in try_connect %d %s", err
, strerror (err
));
702 return -1; /* Can try to launch mod-mono-server */
704 error
= strerror (err
);
705 if (conf
->listen_port
== NULL
)
706 ap_log_error (APLOG_MARK
, APLOG_ERR
, STATUS_AND_SERVER
,
707 "mod_mono: file %s exists, but wrong permissions.", fn
);
709 ap_log_error (APLOG_MARK
, APLOG_ERR
, STATUS_AND_SERVER
,
710 "mod_mono: no permission to listen on %s.",
714 apr_socket_close (*sock
);
715 return -2; /* Unrecoverable */
717 error
= strerror (err
);
718 if (conf
->listen_port
== NULL
)
719 ap_log_error (APLOG_MARK
, APLOG_ERR
, STATUS_AND_SERVER
,
720 "mod_mono: connect error (%s). File: %s",
723 ap_log_error (APLOG_MARK
, APLOG_ERR
, STATUS_AND_SERVER
,
724 "mod_mono: connect error (%s). Address: %s Port: %s",
725 error
, la
, conf
->listen_port
);
728 apr_socket_close (*sock
);
729 return -2; /* Unrecoverable */
734 get_directory (apr_pool_t
*pool
, const char *filepath
)
739 sep
= strrchr (filepath
, '/');
740 if (sep
== NULL
|| sep
== filepath
)
743 result
= apr_pcalloc (pool
, sep
- filepath
+ 1);
744 strncpy (result
, filepath
, sep
- filepath
);
749 # define SETENV(pool, name, value) setenv (name, value, 1)
752 # define SETENV(pool, name, value) setenv_to_putenv (pool, name, value)
754 setenv_to_putenv (apr_pool_t
*pool
, char *name
, char *value
)
758 arg
= apr_pcalloc (pool
, strlen (name
) + strlen (value
) + 2);
759 sprintf (arg
, "%s=%s", name
, value
);
764 # error No setenv or putenv found!
769 set_environment_variables (apr_pool_t
*pool
, char *environment_variables
)
775 /* were any environment_variables specified? */
776 if (environment_variables
== NULL
)
779 name
= environment_variables
;
780 tmp
= strchr (environment_variables
, '=');
781 while (tmp
!= NULL
) {
784 tmp
= strchr (value
, ';');
788 SETENV (pool
, name
, value
);
793 tmp
= strchr (name
, '=');
798 set_process_limits (int max_cpu_time
, int max_memory
)
800 #ifdef HAVE_SETRLIMIT
803 if (max_cpu_time
> 0) {
804 /* We don't want SIGXCPU */
805 limit
.rlim_cur
= max_cpu_time
;
806 limit
.rlim_max
= max_cpu_time
;
807 DEBUG_PRINT (1, "Setting CPU time limit to %d", max_cpu_time
);
808 (void) setrlimit (RLIMIT_CPU
, &limit
);
811 if (max_memory
> 0) {
812 /* We don't want ENOMEM */
813 limit
.rlim_cur
= max_memory
;
814 limit
.rlim_max
= max_memory
;
815 DEBUG_PRINT (1, "Setting memory limit to %d", max_memory
);
816 (void) setrlimit (RLIMIT_DATA
, &limit
);
822 fork_mod_mono_server (apr_pool_t
*pool
, xsp_data
*config
)
826 const int MAXARGS
= 21;
827 char *argv
[MAXARGS
];
835 int max_cpu_time
= 0;
838 /* Running mod-mono-server not requested */
839 if (!strcasecmp (config
->run_xsp
, "false")) {
840 DEBUG_PRINT (1, "Not running mod-mono-server: %s", config
->run_xsp
);
841 ap_log_error (APLOG_MARK
, APLOG_DEBUG
, STATUS_AND_SERVER
,
842 "Not running mod-mono-server.exe");
846 /* At least one of MonoApplications, MonoApplicationsConfigFile or
847 * MonoApplicationsConfigDir must be specified */
848 DEBUG_PRINT (1, "Applications: %s", config
->applications
);
849 DEBUG_PRINT (1, "Config file: %s", config
->appconfig_file
);
850 DEBUG_PRINT (1, "Config dir.: %s", config
->appconfig_dir
);
851 if (config
->applications
== NULL
&& config
->appconfig_file
== NULL
&&
852 config
->appconfig_dir
== NULL
) {
853 ap_log_error (APLOG_MARK
, APLOG_ERR
,
855 "Not running mod-mono-server.exe because no MonoApplications, "
856 "MonoApplicationsConfigFile or MonoApplicationConfigDir specified.");
860 /* Only one of MonoUnixSocket and MonoListenPort. */
861 DEBUG_PRINT (1, "Listen port: %s", config
->listen_port
);
862 if (config
->listen_port
!= NULL
&& config
->filename
!= NULL
) {
863 ap_log_error (APLOG_MARK
, APLOG_ERR
, STATUS_AND_SERVER
,
864 "Not running mod-mono-server.exe because both MonoUnixSocket and "
865 "MonoListenPort specified.");
869 /* MonoListenAddress must be used together with MonoListenPort */
870 DEBUG_PRINT (1, "Listen address: %s", config
->listen_address
);
871 if (config
->listen_port
== NULL
&& config
->listen_address
!= NULL
) {
872 ap_log_error (APLOG_MARK
, APLOG_ERR
, STATUS_AND_SERVER
,
873 "Not running mod-mono-server.exe because MonoListenAddress "
874 "is present and there is no MonoListenPort.");
878 if (config
->max_memory
!= NULL
)
879 max_memory
= atoi (config
->max_memory
);
881 if (config
->max_cpu_time
!= NULL
)
882 max_cpu_time
= atoi (config
->max_cpu_time
);
884 set_environment_variables (pool
, config
->env_vars
);
892 /* Double fork to prevent defunct/zombie processes */
900 DEBUG_PRINT (1, "child started");
905 for (i
= getdtablesize () - 1; i
>= 3; i
--)
908 set_process_limits (max_cpu_time
, max_memory
);
909 tmp
= getenv ("PATH");
910 DEBUG_PRINT (1, "PATH: %s", tmp
);
914 monodir
= get_directory (pool
, config
->executable_path
);
915 DEBUG_PRINT (1, "monodir: %s", monodir
);
916 serverdir
= get_directory (pool
, config
->server_path
);
917 DEBUG_PRINT (1, "serverdir: %s", serverdir
);
918 if (strcmp (monodir
, serverdir
)) {
919 path
= apr_pcalloc (pool
, strlen (tmp
) + strlen (monodir
) +
920 strlen (serverdir
) + 3);
921 sprintf (path
, "%s:%s:%s", monodir
, serverdir
, tmp
);
923 path
= apr_pcalloc (pool
, strlen (tmp
) + strlen (monodir
) + 2);
924 sprintf (path
, "%s:%s", monodir
, tmp
);
927 DEBUG_PRINT (1, "PATH after: %s", path
);
928 SETENV (pool
, "PATH", path
);
929 SETENV (pool
, "MONO_PATH", config
->path
);
930 wapidir
= apr_pcalloc (pool
, strlen (config
->wapidir
) + 5 + 2);
931 sprintf (wapidir
, "%s/%s", config
->wapidir
, ".wapi");
932 mkdir (wapidir
, 0700);
933 if (chmod (wapidir
, 0700) != 0 && (errno
== EPERM
|| errno
== EACCES
)) {
934 ap_log_error (APLOG_MARK
, APLOG_ERR
, STATUS_AND_SERVER
,
935 "%s: %s", wapidir
, strerror (errno
));
939 SETENV (pool
, "MONO_SHARED_DIR", config
->wapidir
);
941 memset (argv
, 0, sizeof (char *) * MAXARGS
);
943 argv
[argi
++] = config
->executable_path
;
944 if (!strcasecmp (config
->debug
, "True"))
945 argv
[argi
++] = "--debug";
947 argv
[argi
++] = config
->server_path
;
948 if (config
->listen_port
!= NULL
) {
951 la
= config
->listen_address
;
952 la
= la
? la
: LISTEN_ADDRESS
;
953 argv
[argi
++] = "--address";
955 argv
[argi
++] = "--port";
956 argv
[argi
++] = config
->listen_port
;
960 fn
= config
->filename
;
962 fn
= get_default_socket_name (pool
, config
->alias
, SOCKET_FILE
);
964 argv
[argi
++] = "--filename";
968 if (config
->applications
!= NULL
) {
969 argv
[argi
++] = "--applications";
970 argv
[argi
++] = config
->applications
;
973 argv
[argi
++] = "--nonstop";
974 if (config
->document_root
!= NULL
) {
975 argv
[argi
++] = "--root";
976 argv
[argi
++] = config
->document_root
;
979 if (config
->appconfig_file
!= NULL
) {
980 argv
[argi
++] = "--appconfigfile";
981 argv
[argi
++] = config
->appconfig_file
;
984 if (config
->appconfig_dir
!= NULL
) {
985 argv
[argi
++] = "--appconfigdir";
986 argv
[argi
++] = config
->appconfig_dir
;
990 * The last element in the argv array must always be NULL
991 * to terminate the array for execv().
993 * Any new argi++'s that are added here must also increase
994 * the maxargs argument at the top of this method to prevent
995 * array out-of-bounds.
998 ap_log_error (APLOG_MARK
, APLOG_DEBUG
, STATUS_AND_SERVER
,
999 "running '%s %s %s %s %s %s %s %s %s %s %s %s %s'",
1000 argv
[0], argv
[1], argv
[2], argv
[3], argv
[4],
1001 argv
[5], argv
[6], argv
[7], argv
[8],
1002 argv
[9], argv
[10], argv
[11], argv
[12]);
1004 execv (argv
[0], argv
);
1005 ap_log_error (APLOG_MARK
, APLOG_ERR
, STATUS_AND_SERVER
,
1006 "Failed running '%s %s %s %s %s %s %s %s %s %s %s %s %s'. Reason: %s",
1007 argv
[0], argv
[1], argv
[2], argv
[3], argv
[4],
1008 argv
[5], argv
[6], argv
[7], argv
[8],
1009 argv
[9], argv
[10], argv
[11], argv
[12],
1015 setup_socket (apr_socket_t
**sock
, xsp_data
*conf
, apr_pool_t
*pool
, int dontfork
)
1020 family
= (conf
->listen_port
!= NULL
) ? PF_INET
: PF_UNIX
;
1022 rv
= apr_socket_create (sock
, family
, SOCK_STREAM
, pool
);
1024 (*sock
)->fd
= ap_psocket (pool
, family
, SOCK_STREAM
, 0);
1025 (*sock
)->pool
= pool
;
1026 rv
= ((*sock
)->fd
!= -1) ? APR_SUCCESS
: -1;
1028 if (rv
!= APR_SUCCESS
) {
1029 ap_log_error (APLOG_MARK
, APLOG_ERR
, STATUS_AND_SERVER
,
1030 "mod_mono: error creating socket.");
1035 rv
= try_connect (conf
, sock
, pool
);
1036 DEBUG_PRINT (1, "try_connect: %d", (int) rv
);
1041 write_string_to_buffer (char *buffer
, int offset
, const char *str
)
1047 tmp
= (str
!= NULL
) ? strlen (str
) : 0;
1048 le
= LE_FROM_INT (tmp
);
1049 (*(int *) buffer
) = le
;
1051 buffer
+= sizeof (int);
1052 memcpy (buffer
, str
, tmp
);
1055 return tmp
+ sizeof (int);
1059 send_headers (request_rec
*r
, apr_socket_t
*sock
)
1061 const apr_array_header_t
*elts
;
1062 const apr_table_entry_t
*t_elt
;
1063 const apr_table_entry_t
*t_end
;
1069 elts
= apr_table_elts (r
->headers_in
);
1070 DEBUG_PRINT (3, "Elements: %d", (int) elts
->nelts
);
1071 if (elts
->nelts
== 0)
1072 return (write_data (sock
, &elts
->nelts
, sizeof (int)) == sizeof (int));
1074 size
= sizeof (int);
1075 t_elt
= (const apr_table_entry_t
*) (elts
->elts
);
1076 t_end
= t_elt
+ elts
->nelts
;
1080 size
+= sizeof (int) * 2;
1081 size
+= strlen (t_elt
->key
);
1082 size
+= strlen (t_elt
->val
);
1085 } while (t_elt
< t_end
);
1087 buffer
= apr_pcalloc (r
->pool
, size
);
1090 tmp
= LE_FROM_INT (tmp
);
1091 (*(int *) ptr
) = tmp
;
1092 ptr
+= sizeof (int);
1093 t_elt
= (const apr_table_entry_t
*) (elts
->elts
);
1094 t_end
= t_elt
+ elts
->nelts
;
1097 DEBUG_PRINT (3, "%s: %s", t_elt
->key
, t_elt
->val
);
1098 ptr
+= write_string_to_buffer (ptr
, 0, t_elt
->key
);
1099 ptr
+= write_string_to_buffer (ptr
, 0, t_elt
->val
);
1102 } while (t_elt
< t_end
);
1104 return (write_data (sock
, buffer
, size
) == size
);
1108 send_initial_data (request_rec
*r
, apr_socket_t
*sock
)
1114 DEBUG_PRINT (2, "Send init1");
1116 size
+= ((r
->method
!= NULL
) ? strlen (r
->method
) : 0) + sizeof (int);
1117 size
+= ((r
->uri
!= NULL
) ? strlen (r
->uri
) : 0) + sizeof (int);
1118 size
+= ((r
->args
!= NULL
) ? strlen (r
->args
) : 0) + sizeof (int);
1119 size
+= ((r
->protocol
!= NULL
) ? strlen (r
->protocol
) : 0) + sizeof (int);
1121 ptr
= str
= apr_pcalloc (r
->pool
, size
);
1122 *ptr
++ = 1; /* version */
1123 ptr
+= write_string_to_buffer (ptr
, 0, r
->method
);
1124 ptr
+= write_string_to_buffer (ptr
, 0, r
->uri
);
1125 ptr
+= write_string_to_buffer (ptr
, 0, r
->args
);
1126 ptr
+= write_string_to_buffer (ptr
, 0, r
->protocol
);
1127 if (write_data (sock
, str
, size
) != size
)
1130 DEBUG_PRINT (2, "Sending headers (init2)");
1131 if (!send_headers (r
, sock
))
1134 DEBUG_PRINT (2, "Done headers (init2)");
1136 size
= strlen (r
->connection
->local_ip
) + sizeof (int);
1137 size
+= sizeof (int);
1138 size
+= strlen (r
->connection
->remote_ip
) + sizeof (int);
1139 size
+= sizeof (int);
1140 size
+= strlen (connection_get_remote_name (r
)) + sizeof (int);
1142 ptr
= str
= apr_pcalloc (r
->pool
, size
);
1143 ptr
+= write_string_to_buffer (ptr
, 0, r
->connection
->local_ip
);
1144 i
= request_get_server_port (r
);
1145 i
= LE_FROM_INT (i
);
1147 ptr
+= sizeof (int);
1148 ptr
+= write_string_to_buffer (ptr
, 0, r
->connection
->remote_ip
);
1149 i
= connection_get_remote_port (r
->connection
);
1150 i
= LE_FROM_INT (i
);
1152 ptr
+= sizeof (int);
1153 ptr
+= write_string_to_buffer (ptr
, 0, connection_get_remote_name (r
));
1155 DEBUG_PRINT (2, "Sending init3");
1156 if (write_data (sock
, str
, size
) != size
)
1159 DEBUG_PRINT (2, "Done init3");
1165 mono_execute_request (request_rec
*r
)
1174 per_dir_config
*dir_config
= NULL
;
1177 config
= ap_get_module_config (r
->server
->module_config
, &mono_module
);
1178 DEBUG_PRINT (2, "config = %d", (int) config
);
1179 if (r
->per_dir_config
!= NULL
)
1180 dir_config
= ap_get_module_config (r
->per_dir_config
, &mono_module
);
1182 DEBUG_PRINT (2, "dir_config = %d", (int) dir_config
);
1183 if (dir_config
!= NULL
&& dir_config
->alias
!= NULL
)
1184 idx
= search_for_alias (dir_config
->alias
, config
);
1186 idx
= search_for_alias ("default", config
);
1188 DEBUG_PRINT (2, "idx = %d", idx
);
1190 sock
= apr_pcalloc (r
->pool
, sizeof (apr_socket_t
));
1192 rv
= setup_socket (&sock
, &config
->servers
[idx
], r
->pool
, FALSE
);
1193 DEBUG_PRINT (2, "After setup_socket");
1194 if (rv
!= APR_SUCCESS
)
1195 return HTTP_SERVICE_UNAVAILABLE
;
1197 ap_add_cgi_vars (r
);
1198 ap_add_common_vars (r
);
1199 DEBUG_PRINT (2, "Sending init data");
1200 if (send_initial_data (r
, sock
) != 0) {
1202 DEBUG_PRINT (1, "%d: %s", err
, strerror (err
));
1203 apr_socket_close (sock
);
1204 return HTTP_SERVICE_UNAVAILABLE
;
1207 DEBUG_PRINT (2, "Loop");
1209 input
= read_data (sock
, (char *) &command
, sizeof (int));
1210 if (input
== sizeof (int)) {
1211 command
= INT_FROM_LE (command
);
1212 result
= do_command (command
, sock
, r
, &status
);
1214 } while (input
== sizeof (int) && result
== TRUE
);
1216 apr_socket_close (sock
);
1217 if (input
!= sizeof (int))
1218 status
= HTTP_INTERNAL_SERVER_ERROR
;
1220 DEBUG_PRINT (2, "Done. Status: %d", status
);
1225 mono_handler (request_rec
*r
)
1227 if (strcmp (r
->handler
, "mono"))
1230 DEBUG_PRINT (1, "handler: %s", r
->handler
);
1231 return mono_execute_request (r
);
1235 start_xsp (module_cfg
*config
, int is_restart
)
1244 * NOTE: we might be trying to start the same mod-mono-server in several
1245 * different apache child processes. xsp->status tries to help avoiding this
1246 * and mod-mono-server uses a lock that checks for same command line, same
1249 for (i
= 0; i
< config
->nservers
; i
++) {
1250 xsp
= &config
->servers
[i
];
1251 if (xsp
->run_xsp
&& !strcasecmp (xsp
->run_xsp
, "false"))
1254 if (xsp
->status
!= FORK_NONE
)
1258 sock
= apr_pcalloc (pconf
, sizeof (apr_socket_t
));
1260 rv
= setup_socket (&sock
, xsp
, pconf
, TRUE
);
1262 if (rv
== APR_SUCCESS
) {
1264 DEBUG_PRINT (0, "connected %s", xsp
->alias
);
1266 write_data (sock
, termstr
, 1);
1267 apr_socket_close (sock
);
1268 apr_sleep (apr_time_from_sec (2));
1270 continue; /* Wait for the previous to die */
1273 apr_socket_close (sock
);
1274 xsp
->status
= FORK_SUCCEEDED
;
1276 apr_socket_close (sock
);
1278 xsp
->status
= FORK_INPROCESS
;
1279 DEBUG_PRINT (0, "forking %s", xsp
->alias
);
1280 /* Give some time for clean up */
1281 fork_mod_mono_server (pconf
, xsp
);
1282 xsp
->status
= FORK_SUCCEEDED
;
1288 terminate_xsp (void *data
)
1298 DEBUG_PRINT (0, "Terminate XSP");
1299 server
= (server_rec
*) data
;
1300 config
= ap_get_module_config (server
->module_config
, &mono_module
);
1302 for (i
= 0; i
< config
->nservers
; i
++) {
1303 xsp
= &config
->servers
[i
];
1304 if (xsp
->run_xsp
&& !strcasecmp (xsp
->run_xsp
, "false"))
1307 sock
= apr_pcalloc (pconf
, sizeof (apr_socket_t
));
1309 rv
= setup_socket (&sock
, xsp
, pconf
, TRUE
);
1310 if (rv
== APR_SUCCESS
) {
1311 write_data (sock
, termstr
, 1);
1312 apr_socket_close (sock
);
1315 if (xsp
->listen_port
== NULL
) {
1316 char *fn
= xsp
->filename
;
1319 fn
= get_default_socket_name (pconf
, xsp
->alias
, SOCKET_FILE
);
1321 remove (fn
); /* Don't bother checking error */
1324 xsp
->status
= FORK_NONE
;
1327 apr_sleep (apr_time_from_sec (1));
1332 mono_control_panel_handler (request_rec
*r
)
1337 if (strcmp (r
->handler
, "mono-ctrl"))
1340 DEBUG_PRINT (1, "control panel handler: %s", r
->handler
);
1342 config
= ap_get_module_config (r
->server
->module_config
, &mono_module
);
1344 set_response_header (r
, "Content-Type", "text/html");
1346 request_send_response_string (r
, "<html><body>\n");
1347 request_send_response_string (r
, "<h1 style=\"text-align: center;\">mod_mono Control Panel</h1>\n");
1349 uri
= &r
->parsed_uri
;
1350 if (!uri
->query
|| !strcmp (uri
->query
, "")) {
1351 /* No query string -> Emit links for configuration commands. */
1352 request_send_response_string (r
, "<ul style=\"text-align: center;\">\n");
1353 request_send_response_string (r
, "<li><a href=\"?restart\">Restart mod-mono-server processes</a></li>\n");
1354 request_send_response_string (r
, "</ul>\n");
1356 if (uri
->query
&& !strcmp (uri
->query
, "restart")) {
1357 /* Restart the mod-mono-server processes */
1358 terminate_xsp (r
->server
);
1359 start_xsp (config
, 1);
1360 request_send_response_string (r
, "<div style=\"text-align: center;\">mod-mono-server processes restarted.</div><br>\n");
1362 /* Invalid command. */
1363 request_send_response_string (r
, "<div style=\"text-align: center;\">Invalid query string command.</div>\n");
1366 request_send_response_string (r
, "<div style=\"text-align: center;\"><a href=\"?\">Return to Control Panel</a></div>\n");
1369 request_send_response_string(r
, "</body></html>\n");
1371 DEBUG_PRINT (2, "Done.");
1377 mono_init_handler (server_rec
*s
, pool
*p
)
1379 if (ap_standalone
&& ap_restart_time
== 0)
1382 DEBUG_PRINT (0, "Initializing handler");
1383 ap_add_version_component ("mod_mono/" VERSION
);
1385 ap_register_cleanup (p
, s
, (void (*)(void *)) terminate_xsp
, ap_null_cleanup
);
1389 mono_init_handler (apr_pool_t
*p
,
1395 const char *userdata_key
= "mono_module_init";
1398 * mono_init_handler() will be called twice, and if it's a DSO then all
1399 * static data from the first call will be lost. Only set up our static
1400 * data on the second call.
1402 apr_pool_userdata_get (&data
, userdata_key
, s
->process
->pool
);
1404 apr_pool_userdata_set ((const void *) 1, userdata_key
,
1405 apr_pool_cleanup_null
, s
->process
->pool
);
1409 DEBUG_PRINT (0, "Initializing handler");
1411 ap_add_version_component (p
, "mod_mono/" VERSION
);
1412 pconf
= s
->process
->pconf
;
1413 apr_pool_cleanup_register (pconf
, s
, terminate_xsp
, apr_pool_cleanup_null
);
1422 apr_pool_t
*p
, server_rec
*s
1424 server_rec
*s
, apr_pool_t
*p
1430 DEBUG_PRINT (0, "Mono Child Init");
1431 config
= ap_get_module_config (s
->module_config
, &mono_module
);
1433 start_xsp (config
, 0);
1437 static const handler_rec mono_handlers
[] = {
1438 { "mono", mono_handler
},
1439 { "mono-ctrl", mono_control_panel_handler
},
1444 mono_register_hooks (apr_pool_t
* p
)
1446 ap_hook_handler (mono_handler
, NULL
, NULL
, APR_HOOK_FIRST
);
1447 ap_hook_handler (mono_control_panel_handler
, NULL
, NULL
, APR_HOOK_FIRST
);
1448 ap_hook_post_config (mono_init_handler
, NULL
, NULL
, APR_HOOK_MIDDLE
);
1449 ap_hook_child_init (mono_child_init
, NULL
, NULL
, APR_HOOK_MIDDLE
);
1453 static const command_rec mono_cmds
[] = {
1454 MAKE_CMD12 (MonoUnixSocket
, filename
,
1455 "Named pipe file name. Mutually exclusive with MonoListenPort. "
1456 "Default: /tmp/mod_mono_server"
1459 MAKE_CMD12 (MonoListenPort
, listen_port
,
1460 "TCP port on which mod-mono-server should listen/is listening on. Mutually "
1461 "exclusive with MonoUnixSocket. "
1462 "When this options is specified, "
1463 "mod-mono-server and mod_mono will use a TCP socket for communication. "
1467 MAKE_CMD12 (MonoListenAddress
, listen_address
,
1468 "IP address where mod-mono-server should listen/is listening on. Can "
1469 "only be used when MonoListenPort is specified."
1470 "Default: \"127.0.0.1\""
1473 MAKE_CMD12 (MonoRunXSP
, run_xsp
,
1474 "It can be False or True. If it is True, asks the module to "
1475 "start mod-mono-server.exe if it's not already there. Default: True"
1478 MAKE_CMD12 (MonoExecutablePath
, executable_path
,
1479 "If MonoRunXSP is True, this is the full path where mono is located. "
1480 "Default: /usr/bin/mono"
1483 MAKE_CMD12 (MonoPath
, path
,
1484 "If MonoRunXSP is True, this will be the content of MONO_PATH "
1485 "environment variable. Default: \"\""
1488 MAKE_CMD12 (MonoServerPath
, server_path
,
1489 "If MonoRunXSP is True, this is the full path to mod-mono-server.exe. "
1490 "Default: " MODMONO_SERVER_PATH
1493 MAKE_CMD12 (MonoApplications
, applications
,
1494 "Comma separated list with virtual directories and real directories. "
1495 "One ASP.NET application will be created for each pair. Default: \"\" "
1498 MAKE_CMD12 (MonoWapiDir
, wapidir
,
1499 "The directory where mono runtime will create the '.wapi' directory "
1500 "used to emulate windows I/O. It's used to set MONO_SHARED_DIR. "
1501 "Default value: \"/tmp\""
1504 MAKE_CMD12 (MonoDocumentRootDir
, document_root
,
1505 "The argument passed in --root argument to mod-mono-server. "
1506 "This tells mod-mono-server to change the directory to the "
1507 "value specified before doing anything else. Default: /"
1510 MAKE_CMD12 (MonoApplicationsConfigFile
, appconfig_file
,
1511 "Adds application definitions from the XML configuration file. "
1512 "See Appendix C for details on the file format. "
1513 "Default value: \"\""
1516 MAKE_CMD12 (MonoApplicationsConfigDir
, appconfig_dir
,
1517 "Adds application definitions from all XML files found in the "
1518 "specified directory DIR. Files must have '.webapp' extension. "
1519 "Default value: \"\""
1522 #ifndef HAVE_SETRLIMIT
1523 MAKE_CMD12 (MonoMaxMemory
, max_memory
,
1524 "If MonoRunXSP is True, the maximum size of the process's data segment "
1525 "(data size) in bytes allowed for the spawned mono process. It will "
1526 "be restarted when the limit is reached. .. but your system doesn't "
1527 "support setrlimit. Sorry, this feature will not be available. "
1528 "Default value: system default"
1531 MAKE_CMD12 (MonoMaxMemory
, max_memory
,
1532 "If MonoRunXSP is True, the maximum size of the process's data "
1533 "segment (data size) in bytes allowed "
1534 "for the spawned mono process. It will be restarted when the limit "
1536 " Default value: system default"
1540 #ifndef HAVE_SETRLIMIT
1541 MAKE_CMD12 (MonoMaxCPUTime
, max_cpu_time
,
1542 "If MonoRunXSP is True, CPU time limit in seconds allowed for "
1543 "the spawned mono process. Beyond that, it will be restarted."
1544 ".. but your system doesn't support setrlimit. Sorry, this feature "
1545 "will not be available."
1546 " Default value: system default"
1549 MAKE_CMD12 (MonoMaxCPUTime
, max_cpu_time
,
1550 "If MonoRunXSP is True, CPU time limit in seconds allowed for "
1551 "the spawned mono process. Beyond that, it will be restarted."
1552 " Default value: system default"
1555 MAKE_CMD12 (MonoDebug
, debug
,
1556 "If MonoDebug is true, mono will be run in debug mode."
1557 " Default value: False"
1560 MAKE_CMD12 (MonoSetEnv
, env_vars
,
1561 "A string of name=value pairs separated by semicolons."
1562 "For each pair, setenv(name, value) is called before running "
1564 " Default value: Default: \"\""
1567 MAKE_CMD_ITERATE2 (AddMonoApplications
, applications
,
1568 "Appends an application."
1571 MAKE_CMD_ACCESS (MonoSetServerAlias
, set_alias
,
1572 "Uses the server named by this alias inside this Directory/Location."
1579 module MODULE_VAR_EXPORT mono_module
=
1581 STANDARD_MODULE_STUFF
,
1582 mono_init_handler
, /* initializer */
1583 create_dir_config
, /* dir config creater */
1584 NULL
, /* dir merger --- default is to override */
1585 create_mono_server_config
, /* server config */
1586 merge_config
, /* merge server configs */
1587 mono_cmds
, /* command table */
1588 mono_handlers
, /* handlers */
1589 NULL
, /* filename translation */
1590 NULL
, /* check_user_id */
1591 NULL
, /* check auth */
1592 NULL
, /* check access */
1593 NULL
, /* type_checker */
1596 NULL
, /* header parser */
1597 mono_child_init
, /* child_init */
1598 NULL
, /* child_exit */
1599 NULL
/* post read-request */
1602 module AP_MODULE_DECLARE_DATA mono_module
= {
1603 STANDARD20_MODULE_STUFF
,
1604 create_dir_config
, /* dir config creater */
1605 NULL
, /* dir merger --- default is to override */
1606 create_mono_server_config
, /* server config */
1607 merge_config
, /* merge server configs */
1608 mono_cmds
, /* command apr_table_t */
1609 mono_register_hooks
/* register hooks */