2005-04-21 Gonzalo Paniagua Javier <gonzalo@ximian.com>
[mod_mono.git] / src / mod_mono.c
blobfbebea2c8768371f58019a44c95c298c6886ad31
1 /*
2 * mod_mono.c
3 *
4 * Authors:
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.
23 #ifdef HAVE_CONFIG_H
24 #include "mod_mono_config.h"
25 #endif
27 /* uncomment this to get tons of messages in the log */
28 /* or use --enable-debug with configure */
29 /* #define DEBUG */
30 #define DEBUG_LEVEL 0
32 #include "mod_mono.h"
34 DEFINE_MODULE (mono_module);
36 /* Configuration pool. Cleared on restart. */
37 static apr_pool_t *pconf;
39 typedef struct per_dir_config {
40 char *location;
41 char *alias;
42 } per_dir_config;
44 enum {
45 FORK_NONE,
46 FORK_INPROCESS,
47 FORK_ATTEMPTED,
48 FORK_FAILED,
49 FORK_SUCCEEDED
52 typedef struct xsp_data {
53 char *alias;
54 char *filename;
55 char *run_xsp;
56 char *executable_path;
57 char *path;
58 char *server_path;
59 char *applications;
60 char *wapidir;
61 char *document_root;
62 char *appconfig_file;
63 char *appconfig_dir;
64 char *listen_port;
65 char *listen_address;
66 char *max_cpu_time;
67 char *max_memory;
68 char *debug;
69 char *env_vars;
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? */
73 } xsp_data;
75 typedef struct {
76 int nservers;
77 xsp_data *servers;
78 } module_cfg;
80 /* */
81 static int
82 search_for_alias (const char *alias, module_cfg *config)
84 int i;
85 xsp_data *xsp;
87 for (i = 0; i < config->nservers; i++) {
88 xsp = &config->servers [i];
89 if (alias == NULL && !strcmp (xsp->alias, "default"))
90 return i;
92 if (!strcmp (alias, xsp->alias))
93 return i;
96 return -1;
99 static const char *
100 set_alias (cmd_parms *cmd, void *mconfig, const char *alias)
102 per_dir_config *config = mconfig;
103 module_cfg *sconfig;
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);
109 return err;
112 return NULL;
115 static int
116 add_xsp_server (apr_pool_t *pool, const char *alias, module_cfg *config, int is_virtual)
118 xsp_data *server;
119 xsp_data *servers;
120 int nservers;
121 int i;
122 char is_default;
124 i = search_for_alias (alias, config);
125 if (i >= 0)
126 return i;
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;
140 if (is_default)
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;
164 static const char *
165 store_config_xsp (cmd_parms *cmd, void *notused, const char *first, const char *second)
167 const char *alias;
168 const char *value;
169 char *prev_value = NULL;
170 char *new_value;
171 int idx;
172 module_cfg *config;
173 char *ptr;
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) {
181 alias = "default";
182 value = first;
183 } else {
184 alias = first;
185 value = second;
188 idx = search_for_alias (alias, config);
189 if (idx == -1)
190 idx = add_xsp_server (cmd->pool, alias, config, cmd->server->is_virtual);
192 ptr = (char *) &config->servers [idx];
193 ptr += offset;
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);
201 } else {
202 new_value = apr_pstrdup (cmd->pool, value);
205 *((char **) ptr) = new_value;
206 DEBUG_PRINT (1, "store_config end: %s", new_value);
207 return NULL;
210 static void *
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;
217 int nservers;
219 if (new_module->nservers == 0)
220 return new_module;
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);
232 return new_module;
235 static void *
236 create_dir_config (apr_pool_t *p, char *dirspec)
238 per_dir_config *cfg;
240 DEBUG_PRINT (1, "creating dir config for %s", dirspec);
242 cfg = apr_pcalloc (p, sizeof (per_dir_config));
243 if (dirspec != NULL)
244 cfg->location = apr_pstrdup (p, dirspec);
246 return cfg;
249 static void *
250 create_mono_server_config (apr_pool_t *p, server_rec *s)
252 module_cfg *server;
254 server = apr_pcalloc (p, sizeof (module_cfg));
255 return server;
258 static void
259 request_send_response_from_memory (request_rec *r, char *byteArray, int size)
261 #ifdef APACHE13
262 if (r->sent_bodyct == 0)
263 ap_send_http_header (r);
264 #endif
266 ap_rwrite (byteArray, size, r);
269 static void
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 */
276 static int
277 request_get_server_port (request_rec *r)
279 return ap_get_server_port (r);
282 static int
283 connection_get_remote_port (conn_rec *c)
285 #ifdef APACHE13
286 return ntohs (c->remote_addr.sin_port);
287 #else
288 apr_port_t port;
289 apr_sockaddr_port_get (&port, c->remote_addr);
290 return port;
291 #endif
295 static int
296 connection_get_local_port (request_rec *r)
298 #ifdef APACHE13
299 return ap_get_server_port (r);
300 #else
301 apr_port_t port;
302 apr_sockaddr_port_get (&port, r->connection->local_addr);
303 return port;
304 #endif
307 static const char *
308 connection_get_remote_name (request_rec *r)
310 #ifdef APACHE13
311 return ap_get_remote_host (r->connection, r->per_dir_config, REMOTE_NAME);
312 #else
313 return ap_get_remote_host (r->connection, r->per_dir_config, REMOTE_NAME, NULL);
314 #endif
317 /* Do nothing
318 * This does a kind of final flush which is not what we want.
319 * It caused bug 60117.
320 static void
321 connection_flush (request_rec *r)
323 #ifdef APACHE13
324 ap_rflush (r);
325 #else
326 ap_flush_conn (r->connection);
327 #endif
331 static void
332 set_response_header (request_rec *r,
333 const char *name,
334 const char *value)
336 if (!strcasecmp (name,"Content-Type")) {
337 r->content_type = value;
338 } else {
339 apr_table_addn (r->headers_out, name, value);
343 static int
344 setup_client_block (request_rec *r)
346 if (r->read_length)
347 return APR_SUCCESS;
349 return ap_setup_client_block (r, REQUEST_CHUNKED_ERROR);
352 static int
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)
358 return -1;
360 return (prevsize == size) ? size : -1;
363 static int
364 write_data_string (apr_socket_t *sock, const char *str)
366 int l;
367 int lel;
369 l = (str == NULL) ? 0 : strlen (str);
370 lel = LE_FROM_INT (l);
371 if (write_data (sock, &lel, sizeof (int)) != sizeof (int))
372 return -1;
374 if (l == 0)
375 return 0;
377 return write_data (sock, str, l);
380 static int
381 read_data (apr_socket_t *sock, void *ptr, apr_size_t size)
383 if (apr_socket_recv (sock, ptr, &size) != APR_SUCCESS)
384 return -1;
386 return size;
389 static char *
390 read_data_string (apr_pool_t *pool, apr_socket_t *sock, char **ptr, apr_size_t *size)
392 int l, count;
393 char *buf;
394 apr_status_t result;
396 if (read_data (sock, &l, sizeof (int)) == -1)
397 return NULL;
399 l = INT_FROM_LE (l);
400 buf = apr_pcalloc (pool, l + 1);
401 count = l;
402 while (count > 0) {
403 result = read_data (sock, buf + l - count, count);
404 if (result == -1)
405 return NULL;
407 count -= result;
410 if (ptr)
411 *ptr = buf;
413 if (size)
414 *size = l;
416 return buf;
419 static int
420 do_command (int command, apr_socket_t *sock, request_rec *r, int *result)
422 apr_size_t size;
423 char *str;
424 char *str2;
425 int i;
426 int status = 0;
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;
432 return FALSE;
435 DEBUG_PRINT (2, "Command received: %s", cmdNames [command]);
436 *result = OK;
437 switch (command) {
438 case SEND_FROM_MEMORY:
439 if (read_data_string (r->pool, sock, &str, &size) == NULL) {
440 status = -1;
441 break;
443 request_send_response_from_memory (r, str, size);
444 break;
445 case GET_SERVER_VARIABLE:
446 if (read_data_string (r->pool, sock, &str, NULL) == NULL)
447 break;
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;
452 } else {
453 str = (char *) apr_table_get (r->subprocess_env, str);
456 status = write_data_string (sock, str);
457 break;
458 case SET_RESPONSE_HEADER:
459 if (read_data_string (r->pool, sock, &str, NULL) == NULL) {
460 status = -1;
461 break;
463 if (read_data_string (r->pool, sock, &str2, NULL) == NULL) {
464 status = -1;
465 break;
467 set_response_header (r, str, str2);
468 break;
469 case GET_LOCAL_PORT:
470 i = connection_get_local_port (r);
471 i = LE_FROM_INT (i);
472 status = write_data (sock, &i, sizeof (int));
473 break;
474 case FLUSH:
475 break;
476 case CLOSE:
477 return FALSE;
478 break;
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));
483 break;
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));
488 break;
491 size = LE_FROM_INT (0);
492 status = write_data (sock, &size, sizeof (int));
493 break;
494 case GET_CLIENT_BLOCK:
495 status = read_data (sock, &i, sizeof (int));
496 if (status == -1)
497 break;
499 i = INT_FROM_LE (i);
500 str = apr_pcalloc (r->pool, i);
501 i = ap_get_client_block (r, str, i);
502 i = LE_FROM_INT (i);
503 status = write_data (sock, &i, sizeof (int));
504 i = INT_FROM_LE (i);
505 status = write_data (sock, str, i);
506 break;
507 case SET_STATUS:
508 status = read_data (sock, &i, sizeof (int));
509 if (status == -1)
510 break;
512 if (read_data_string (r->pool, sock, &str, NULL) == NULL) {
513 status = -1;
514 break;
516 r->status = INT_FROM_LE (i);
517 r->status_line = apr_pstrdup (r->pool, str);
518 break;
519 case DECLINE_REQUEST:
520 *result = DECLINED;
521 return FALSE;
522 case MYNOT_FOUND:
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;
531 return FALSE;
532 default:
533 *result = HTTP_INTERNAL_SERVER_ERROR;
534 return FALSE;
537 if (status == -1) {
538 *result = HTTP_INTERNAL_SERVER_ERROR;
539 return FALSE;
542 return TRUE;
545 #ifndef APACHE2
546 static apr_status_t
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;
551 int error;
552 struct sockaddr_in *addr;
554 if (port < 0 || port > 65535)
555 return EINVAL;
557 memset (&hints, 0, sizeof (hints));
558 hints.ai_family = family;
559 hints.ai_socktype = SOCK_STREAM;
560 error = getaddrinfo (hostname, NULL, &hints, &list);
561 if (error != 0) {
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);
566 return error;
569 *sa = apr_pcalloc (p, sizeof (apr_sockaddr_t));
570 (*sa)->pool = p;
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);
577 freeaddrinfo (list);
579 return APR_SUCCESS;
582 static apr_status_t
583 apr_socket_connect (apr_socket_t *sock, apr_sockaddr_t *sa)
585 int sock_fd;
587 apr_os_sock_get (&sock_fd, sock);
588 if (connect (sock_fd, sa->addr, sa->addrlen) != 0)
589 return errno;
591 return APR_SUCCESS;
594 static apr_status_t
595 apr_socket_send (apr_socket_t *sock, const char *buf, apr_size_t *len)
597 int result;
598 int total;
600 total = 0;
601 do {
602 result = write (sock->fd, buf + total, (*len) - total);
603 if (result >= 0)
604 total += result;
605 } while ((result >= 0 && total < *len) || (result == -1 && errno == EINTR));
607 return (total == *len) ? 0 : -1;
610 static apr_status_t
611 apr_socket_recv (apr_socket_t *sock, char *buf, apr_size_t *len)
613 int result;
614 int total;
615 apr_os_sock_t sock_fd;
617 apr_os_sock_get (&sock_fd, sock);
618 total = 0;
619 do {
620 result = read (sock_fd, buf + total, (*len) - total);
621 if (result >= 0)
622 total += result;
623 } while ((result >= 0 && total < *len) || (result == -1 && errno == EINTR));
625 return (total == *len) ? 0 : -1;
628 static void
629 apr_sleep (long t)
631 struct timeval tv;
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
640 #endif
642 static char *
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);
651 static apr_status_t
652 try_connect (xsp_data *conf, apr_socket_t **sock, apr_pool_t *pool)
654 char *error;
655 struct sockaddr_un unix_address;
656 struct sockaddr *ptradd;
657 char *fn = NULL;
658 char *la = NULL;
659 int err;
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)
667 fn = conf->filename;
668 else
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)
675 return APR_SUCCESS;
676 } else {
677 apr_status_t rv;
678 apr_sockaddr_t *sa;
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);
688 return -2;
691 rv = apr_socket_connect (*sock, sa);
692 if (rv == APR_SUCCESS)
693 return APR_SUCCESS;
694 errno = rv;
697 err = errno;
698 DEBUG_PRINT (1, "errno in try_connect %d %s", err, strerror (err));
699 switch (err) {
700 case ENOENT:
701 case ECONNREFUSED:
702 return -1; /* Can try to launch mod-mono-server */
703 case EPERM:
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);
708 else
709 ap_log_error (APLOG_MARK, APLOG_ERR, STATUS_AND_SERVER,
710 "mod_mono: no permission to listen on %s.",
711 conf->listen_port);
714 apr_socket_close (*sock);
715 return -2; /* Unrecoverable */
716 default:
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",
721 error, fn);
722 else
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 */
733 static char *
734 get_directory (apr_pool_t *pool, const char *filepath)
736 char *sep;
737 char *result;
739 sep = strrchr (filepath, '/');
740 if (sep == NULL || sep == filepath)
741 return "/";
743 result = apr_pcalloc (pool, sep - filepath + 1);
744 strncpy (result, filepath, sep - filepath);
745 return result;
748 #ifdef HAVE_SETENV
749 # define SETENV(pool, name, value) setenv (name, value, 1)
750 #else
751 # ifdef HAVE_PUTENV
752 # define SETENV(pool, name, value) setenv_to_putenv (pool, name, value)
753 static int
754 setenv_to_putenv (apr_pool_t *pool, char *name, char *value)
756 char *arg;
758 arg = apr_pcalloc (pool, strlen (name) + strlen (value) + 2);
759 sprintf (arg, "%s=%s", name, value);
760 return putenv (arg);
763 # else
764 # error No setenv or putenv found!
765 #endif
766 #endif
768 static void
769 set_environment_variables (apr_pool_t *pool, char *environment_variables)
771 char *tmp;
772 char *name;
773 char *value;
775 /* were any environment_variables specified? */
776 if (environment_variables == NULL)
777 return;
779 name = environment_variables;
780 tmp = strchr (environment_variables, '=');
781 while (tmp != NULL) {
782 *tmp = '\0';
783 value = tmp + 1;
784 tmp = strchr (value, ';');
785 if (tmp != NULL)
786 *tmp = '\0';
788 SETENV (pool, name, value);
789 if (tmp == NULL)
790 break;
792 name = tmp + 1;
793 tmp = strchr (name, '=');
797 static void
798 set_process_limits (int max_cpu_time, int max_memory)
800 #ifdef HAVE_SETRLIMIT
801 struct rlimit limit;
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);
818 #endif
821 static void
822 fork_mod_mono_server (apr_pool_t *pool, xsp_data *config)
824 pid_t pid;
825 int i;
826 const int MAXARGS = 21;
827 char *argv [MAXARGS];
828 int argi;
829 char *path;
830 char *tmp;
831 char *monodir;
832 char *serverdir;
833 char *wapidir;
834 int max_memory = 0;
835 int max_cpu_time = 0;
836 int status;
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");
843 return;
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,
854 STATUS_AND_SERVER,
855 "Not running mod-mono-server.exe because no MonoApplications, "
856 "MonoApplicationsConfigFile or MonoApplicationConfigDir specified.");
857 return;
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.");
866 return;
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.");
875 return;
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);
886 pid = fork ();
887 if (pid > 0) {
888 wait (&status);
889 return;
892 /* Double fork to prevent defunct/zombie processes */
893 pid = fork ();
894 if (pid > 0)
895 exit (0);
897 setsid ();
898 chdir ("/");
899 umask (0077);
900 DEBUG_PRINT (1, "child started");
902 #ifdef DEBUG
903 dup2 (2, 1);
904 #endif
905 for (i = getdtablesize () - 1; i >= 3; i--)
906 close (i);
908 set_process_limits (max_cpu_time, max_memory);
909 tmp = getenv ("PATH");
910 DEBUG_PRINT (1, "PATH: %s", tmp);
911 if (tmp == NULL)
912 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);
922 } else {
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));
936 exit (1);
939 SETENV (pool, "MONO_SHARED_DIR", config->wapidir);
941 memset (argv, 0, sizeof (char *) * MAXARGS);
942 argi = 0;
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) {
949 char *la;
951 la = config->listen_address;
952 la = la ? la : LISTEN_ADDRESS;
953 argv [argi++] = "--address";
954 argv [argi++] = la;
955 argv [argi++] = "--port";
956 argv [argi++] = config->listen_port;
957 } else {
958 char *fn;
960 fn = config->filename;
961 if (fn == NULL)
962 fn = get_default_socket_name (pool, config->alias, SOCKET_FILE);
964 argv [argi++] = "--filename";
965 argv [argi++] = fn;
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],
1010 strerror (errno));
1011 exit (1);
1014 static apr_status_t
1015 setup_socket (apr_socket_t **sock, xsp_data *conf, apr_pool_t *pool, int dontfork)
1017 apr_status_t rv;
1018 int family;
1020 family = (conf->listen_port != NULL) ? PF_INET : PF_UNIX;
1021 #ifdef APACHE2
1022 rv = apr_socket_create (sock, family, SOCK_STREAM, pool);
1023 #else
1024 (*sock)->fd = ap_psocket (pool, family, SOCK_STREAM, 0);
1025 (*sock)->pool = pool;
1026 rv = ((*sock)->fd != -1) ? APR_SUCCESS : -1;
1027 #endif
1028 if (rv != APR_SUCCESS) {
1029 ap_log_error (APLOG_MARK, APLOG_ERR, STATUS_AND_SERVER,
1030 "mod_mono: error creating socket.");
1032 return rv;
1035 rv = try_connect (conf, sock, pool);
1036 DEBUG_PRINT (1, "try_connect: %d", (int) rv);
1037 return rv;
1040 static int
1041 write_string_to_buffer (char *buffer, int offset, const char *str)
1043 int tmp;
1044 int le;
1046 buffer += offset;
1047 tmp = (str != NULL) ? strlen (str) : 0;
1048 le = LE_FROM_INT (tmp);
1049 (*(int *) buffer) = le;
1050 if (tmp > 0) {
1051 buffer += sizeof (int);
1052 memcpy (buffer, str, tmp);
1055 return tmp + sizeof (int);
1058 static 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;
1064 int tmp;
1065 int size;
1066 char *buffer;
1067 char *ptr;
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;
1077 tmp = 0;
1079 do {
1080 size += sizeof (int) * 2;
1081 size += strlen (t_elt->key);
1082 size += strlen (t_elt->val);
1083 t_elt++;
1084 tmp++;
1085 } while (t_elt < t_end);
1087 buffer = apr_pcalloc (r->pool, size);
1088 ptr = buffer;
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;
1096 do {
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);
1101 t_elt++;
1102 } while (t_elt < t_end);
1104 return (write_data (sock, buffer, size) == size);
1107 static int
1108 send_initial_data (request_rec *r, apr_socket_t *sock)
1110 int i;
1111 char *str, *ptr;
1112 int size;
1114 DEBUG_PRINT (2, "Send init1");
1115 size = 1;
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)
1128 return -1;
1130 DEBUG_PRINT (2, "Sending headers (init2)");
1131 if (!send_headers (r, sock))
1132 return -1;
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);
1146 (*(int *) ptr) = 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);
1151 (*(int *) ptr) = 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)
1157 return -1;
1159 DEBUG_PRINT (2, "Done init3");
1161 return 0;
1164 static int
1165 mono_execute_request (request_rec *r)
1167 apr_socket_t *sock;
1168 apr_status_t rv;
1169 int command;
1170 int result = FALSE;
1171 apr_status_t input;
1172 int status;
1173 module_cfg *config;
1174 per_dir_config *dir_config = NULL;
1175 int idx;
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);
1185 else
1186 idx = search_for_alias ("default", config);
1188 DEBUG_PRINT (2, "idx = %d", idx);
1189 #ifdef APACHE13
1190 sock = apr_pcalloc (r->pool, sizeof (apr_socket_t));
1191 #endif
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) {
1201 int err = errno;
1202 DEBUG_PRINT (1, "%d: %s", err, strerror (err));
1203 apr_socket_close (sock);
1204 return HTTP_SERVICE_UNAVAILABLE;
1207 DEBUG_PRINT (2, "Loop");
1208 do {
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);
1221 return status;
1224 static int
1225 mono_handler (request_rec *r)
1227 if (strcmp (r->handler, "mono"))
1228 return DECLINED;
1230 DEBUG_PRINT (1, "handler: %s", r->handler);
1231 return mono_execute_request (r);
1234 static void
1235 start_xsp (module_cfg *config, int is_restart)
1237 apr_socket_t *sock;
1238 apr_status_t rv;
1239 char *termstr = "";
1240 xsp_data *xsp;
1241 int i;
1243 /*****
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
1247 * user...
1248 *****/
1249 for (i = 0; i < config->nservers; i++) {
1250 xsp = &config->servers [i];
1251 if (xsp->run_xsp && !strcasecmp (xsp->run_xsp, "false"))
1252 continue;
1254 if (xsp->status != FORK_NONE)
1255 continue;
1257 #ifdef APACHE13
1258 sock = apr_pcalloc (pconf, sizeof (apr_socket_t));
1259 #endif
1260 rv = setup_socket (&sock, xsp, pconf, TRUE);
1262 if (rv == APR_SUCCESS) {
1263 /* connected */
1264 DEBUG_PRINT (0, "connected %s", xsp->alias);
1265 if (is_restart) {
1266 write_data (sock, termstr, 1);
1267 apr_socket_close (sock);
1268 apr_sleep (apr_time_from_sec (2));
1269 i--;
1270 continue; /* Wait for the previous to die */
1273 apr_socket_close (sock);
1274 xsp->status = FORK_SUCCEEDED;
1275 } else {
1276 apr_socket_close (sock);
1277 /* need fork */
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;
1287 static apr_status_t
1288 terminate_xsp (void *data)
1290 server_rec *server;
1291 module_cfg *config;
1292 apr_socket_t *sock;
1293 apr_status_t rv;
1294 char *termstr = "";
1295 xsp_data *xsp;
1296 int i;
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"))
1305 continue;
1306 #ifdef APACHE13
1307 sock = apr_pcalloc (pconf, sizeof (apr_socket_t));
1308 #endif
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;
1318 if (fn == NULL)
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));
1328 return APR_SUCCESS;
1331 static int
1332 mono_control_panel_handler (request_rec *r)
1334 module_cfg *config;
1335 apr_uri_t *uri;
1337 if (strcmp (r->handler, "mono-ctrl"))
1338 return DECLINED;
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");
1355 } else {
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");
1361 } else {
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.");
1372 return OK;
1375 #ifdef APACHE13
1376 static void
1377 mono_init_handler (server_rec *s, pool *p)
1379 if (ap_standalone && ap_restart_time == 0)
1380 return;
1382 DEBUG_PRINT (0, "Initializing handler");
1383 ap_add_version_component ("mod_mono/" VERSION);
1384 pconf = p;
1385 ap_register_cleanup (p, s, (void (*)(void *)) terminate_xsp, ap_null_cleanup);
1387 #else
1388 static int
1389 mono_init_handler (apr_pool_t *p,
1390 apr_pool_t *plog,
1391 apr_pool_t *ptemp,
1392 server_rec *s)
1394 void *data;
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);
1403 if (!data) {
1404 apr_pool_userdata_set ((const void *) 1, userdata_key,
1405 apr_pool_cleanup_null, s->process->pool);
1406 return OK;
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);
1415 return OK;
1417 #endif
1419 static void
1420 mono_child_init (
1421 #ifdef APACHE2
1422 apr_pool_t *p, server_rec *s
1423 #else
1424 server_rec *s, apr_pool_t *p
1425 #endif
1428 module_cfg *config;
1430 DEBUG_PRINT (0, "Mono Child Init");
1431 config = ap_get_module_config (s->module_config, &mono_module);
1433 start_xsp (config, 0);
1436 #ifdef APACHE13
1437 static const handler_rec mono_handlers [] = {
1438 { "mono", mono_handler },
1439 { "mono-ctrl", mono_control_panel_handler },
1440 { NULL, NULL }
1442 #else
1443 static void
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);
1451 #endif
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. "
1464 "Default: none"
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"
1530 #else
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 "
1535 "is reached."
1536 " Default value: system default"
1538 #endif
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"
1548 #else
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"
1554 #endif
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 "
1563 "mod-mono-server."
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."
1575 { NULL }
1578 #ifdef APACHE13
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 */
1594 NULL, /* fixups */
1595 NULL, /* logger */
1596 NULL, /* header parser */
1597 mono_child_init, /* child_init */
1598 NULL, /* child_exit */
1599 NULL /* post read-request */
1601 #else
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 */
1611 #endif