1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
5 * Copyright (C) 2001-2010, Eduardo Silva P. <edsiper@gmail.com>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Library General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24 #include <sys/types.h>
25 #include <sys/socket.h>
26 #include <netinet/in.h>
43 /* Raise a configuration error */
44 void mk_config_error(const char *path
, int line
, const char *msg
)
46 printf("\nReading %s", path
);
47 printf("\nError in line %i: %s\n\n", line
, msg
);
52 /* Returns a configuration section by [section name] */
53 struct mk_config_section
*mk_config_section_get(struct mk_config
*conf
,
54 const char *section_name
)
56 struct mk_config_section
*section
;
58 section
= conf
->section
;
60 if (strcasecmp(section
->name
, section_name
) == 0) {
63 section
= section
->next
;
69 /* Register a new section into the configuration struct */
70 void mk_config_section_add(struct mk_config
*conf
, char *section_name
)
72 struct mk_config_section
*new, *aux
;
74 /* Alloc section node */
75 new = mk_mem_malloc(sizeof(struct mk_config_section
));
76 new->name
= mk_string_dup(section_name
);
85 /* go to last section available */
95 /* Register a key/value entry in the last section available of the struct */
96 void mk_config_entry_add(struct mk_config
*conf
,
97 const char *key
, const char *val
)
99 struct mk_config_section
*section
;
100 struct mk_config_entry
*aux_entry
, *new_entry
;
102 if (!conf
->section
) {
103 puts("Error: there are not sections available!");
107 /* Go to last section */
108 section
= conf
->section
;
109 while (section
->next
) {
110 section
= section
->next
;
113 /* Alloc new entry */
114 new_entry
= mk_mem_malloc(sizeof(struct mk_config_entry
));
115 new_entry
->key
= mk_string_dup(key
);
116 new_entry
->val
= mk_string_dup(val
);
117 new_entry
->next
= NULL
;
119 /* Add first entry */
120 if (!section
->entry
) {
121 section
->entry
= new_entry
;
125 /* Go to last entry */
126 aux_entry
= section
->entry
;
127 while (aux_entry
->next
) {
128 aux_entry
= aux_entry
->next
;
131 aux_entry
->next
= new_entry
;
134 struct mk_config
*mk_config_create(const char *path
)
142 char *key
, *val
, *last
;
143 struct mk_config
*conf
= 0;
146 /* Open configuration file */
147 if ((f
= fopen(path
, "r")) == NULL
) {
148 fprintf(stderr
, "\nConfig Error: I can't open %s file\n\n", path
);
152 /* Alloc configuration node */
153 conf
= mk_mem_malloc(sizeof(struct mk_config
));
154 conf
->created
= time(NULL
);
155 conf
->file
= mk_string_dup(path
);
156 conf
->section
= NULL
;
158 /* looking for configuration directives */
159 while (fgets(buf
, 255, f
)) {
161 if (buf
[len
- 1] == '\n') {
163 if (len
&& buf
[len
- 1] == '\r') {
175 /* Skip commented lines */
178 mk_mem_free(section
);
184 /* Section definition */
187 end
= mk_string_char_search(buf
, ']', len
);
189 section
= mk_string_copy_substr(buf
, 1, end
);
190 mk_config_section_add(conf
, section
);
194 mk_config_error(path
, line
, "Bad header definition");
198 /* No separator defined */
202 do { i
++; } while (i
< len
&& isblank(buf
[i
]));
204 indent
= mk_string_copy_substr(buf
, 0, i
);
205 indent_len
= strlen(indent
);
207 /* Blank indented line */
213 /* Validate indentation level */
214 if (strncmp(buf
, indent
, indent_len
) != 0 || !section
||
215 isblank(buf
[indent_len
]) != 0) {
216 mk_config_error(path
, line
, "Invalid indentation level");
219 if (buf
[indent_len
] == '#' || indent_len
== len
) {
223 /* get line key and value */
224 key
= strtok_r(buf
+ indent_len
, "\"\t ", &last
);
225 val
= strtok_r(NULL
, "\"\t", &last
);
228 mk_config_error(path
, line
, "Each key must have a value");
233 mk_string_trim(&key
);
234 mk_string_trim(&val
);
237 mk_config_entry_add(conf
, key
, val
);
242 struct mk_config_section *s;
243 struct mk_config_entry *e;
247 printf("\n[%s]", s->name);
250 printf("\n %s = %s", e->key, e->val);
262 void mk_config_free(struct mk_config
*conf
)
264 struct mk_config_section
*prev
=0, *section
;
267 section
= conf
->section
;
269 while (section
->next
) {
271 section
= section
->next
;
274 /* Free section entries */
275 mk_config_free_entries(section
);
277 /* Free section node */
278 mk_mem_free(section
->name
);
279 mk_mem_free(section
);
281 if (section
== conf
->section
) {
285 section
= conf
->section
;
289 void mk_config_free_entries(struct mk_config_section
*section
)
291 struct mk_config_entry
*prev
= 0, *target
;
293 target
= section
->entry
;
295 while (target
->next
) {
297 target
= target
->next
;
300 /* Free memory assigned */
301 mk_mem_free(target
->key
);
302 mk_mem_free(target
->val
);
304 if (target
== section
->entry
) {
305 section
->entry
= NULL
;
310 target
= section
->entry
;
314 void *mk_config_section_getval(struct mk_config_section
*section
, char *key
, int mode
)
317 struct mk_config_entry
*entry
;
319 entry
= section
->entry
;
321 if (strcasecmp(entry
->key
, key
) == 0) {
323 case MK_CONFIG_VAL_STR
:
324 return (void *) entry
->val
;
325 case MK_CONFIG_VAL_NUM
:
326 return (void *) atoi(entry
->val
);
327 case MK_CONFIG_VAL_BOOL
:
328 on
= strcasecmp(entry
->val
, VALUE_ON
);
329 off
= strcasecmp(entry
->val
, VALUE_OFF
);
331 if (on
!= 0 && off
!= 0) {
335 return (void *) VAR_ON
;
338 return (void *) VAR_OFF
;
340 case MK_CONFIG_VAL_LIST
:
341 return mk_string_split_line(entry
->val
);
351 /* Read configuration files */
352 void mk_config_read_files(char *path_conf
, char *file_conf
)
356 struct stat checkdir
;
357 struct mk_config
*cnf
;
358 struct mk_config_section
*section
;
359 struct mk_string_line
*line
, *line_val
;
361 config
->serverconf
= mk_string_dup(path_conf
);
362 config
->workers
= MK_WORKERS_DEFAULT
;
364 if (stat(config
->serverconf
, &checkdir
) == -1) {
365 fprintf(stderr
, "\nERROR: Invalid path to configuration files");
366 fprintf(stderr
, "\nCannot find/open '%s'\n", config
->serverconf
);
370 mk_string_build(&path
, &len
, "%s/%s", path_conf
, file_conf
);
372 cnf
= mk_config_create(path
);
373 section
= mk_config_section_get(cnf
, "SERVER");
376 fprintf(stderr
, "\nERROR: No 'SERVER' section defined");
380 /* Map source configuration */
381 config
->config
= cnf
;
384 config
->listen_addr
= mk_config_section_getval(section
, "Listen",
386 if (!config
->listen_addr
) {
387 config
->listen_addr
= MK_DEFAULT_LISTEN_ADDR
;
390 /* Connection port */
391 config
->serverport
= (int) mk_config_section_getval(section
,
394 if (!config
->serverport
>= 1 && !config
->serverport
<= 65535) {
395 mk_config_print_error_msg("Port", path
);
398 /* Number of thread workers */
399 config
->workers
= (int) mk_config_section_getval(section
,
402 if (config
->workers
< 1) {
403 mk_config_print_error_msg("Workers", path
);
407 config
->timeout
= (int) mk_config_section_getval(section
,
408 "Timeout", MK_CONFIG_VAL_NUM
);
409 if (config
->timeout
< 1) {
410 mk_config_print_error_msg("Timeout", path
);
414 config
->keep_alive
= (int) mk_config_section_getval(section
,
417 if (config
->keep_alive
== VAR_ERR
) {
418 mk_config_print_error_msg("KeepAlive", path
);
421 /* MaxKeepAliveRequest */
422 config
->max_keep_alive_request
= (int)
423 mk_config_section_getval(section
,
424 "MaxKeepAliveRequest",
427 if (config
->max_keep_alive_request
== 0) {
428 mk_config_print_error_msg("MaxKeepAliveRequest", path
);
431 /* KeepAliveTimeout */
432 config
->keep_alive_timeout
= (int) mk_config_section_getval(section
,
435 if (config
->keep_alive_timeout
== 0) {
436 mk_config_print_error_msg("KeepAliveTimeout", path
);
440 config
->pid_file_path
= mk_config_section_getval(section
,
441 "PidFile", MK_CONFIG_VAL_STR
);
443 /* Home user's directory /~ */
444 config
->user_dir
= mk_config_section_getval(section
,
445 "UserDir", MK_CONFIG_VAL_STR
);
448 line_val
= line
= mk_config_section_getval(section
,
449 "Indexfile", MK_CONFIG_VAL_LIST
);
450 while (line_val
!= NULL
) {
451 mk_config_add_index(line_val
->val
);
452 line_val
= line_val
->next
;
455 /* HideVersion Variable */
456 config
->hideversion
= (int) mk_config_section_getval(section
,
459 if (config
->hideversion
== VAR_ERR
) {
460 mk_config_print_error_msg("HideVersion", path
);
464 config
->user
= mk_config_section_getval(section
, "User", MK_CONFIG_VAL_STR
);
467 config
->resume
= (int) mk_config_section_getval(section
,
468 "Resume", MK_CONFIG_VAL_BOOL
);
469 if (config
->resume
== VAR_ERR
) {
470 mk_config_print_error_msg("Resume", path
);
473 /* Max Request Size */
474 config
->max_request_size
= (int) mk_config_section_getval(section
,
477 if (config
->max_request_size
<= 0) {
478 mk_config_print_error_msg("MaxRequestSize", path
);
481 config
->max_request_size
*= 1024;
485 config
->symlink
= (int) mk_config_section_getval(section
,
486 "SymLink", MK_CONFIG_VAL_BOOL
);
487 if (config
->symlink
== VAR_ERR
) {
488 mk_config_print_error_msg("SymLink", path
);
492 mk_config_read_hosts(path_conf
);
495 void mk_config_read_hosts(char *path
)
501 struct host
*p_host
, *new_host
; /* debug */
504 mk_string_build(&buf
, &len
, "%s/sites/default", path
);
505 config
->hosts
= mk_config_get_host(buf
);
509 if (!config
->hosts
) {
510 printf("\nError parsing main configuration file 'default'\n");
514 mk_string_build(&buf
, &len
, "%s/sites/", path
);
515 if (!(dir
= opendir(buf
)))
519 p_host
= config
->hosts
;
521 /* Reading content */
522 while ((ent
= readdir(dir
)) != NULL
) {
523 if (strcmp((char *) ent
->d_name
, ".") == 0)
525 if (strcmp((char *) ent
->d_name
, "..") == 0)
527 if (strcasecmp((char *) ent
->d_name
, "default") == 0)
530 mk_string_build(&file
, &len
, "%s/sites/%s", path
, ent
->d_name
);
532 new_host
= (struct host
*) mk_config_get_host(file
);
538 p_host
->next
= new_host
;
546 struct host
*mk_config_get_host(char *path
)
548 unsigned long len
= 0;
549 struct stat checkdir
;
551 struct mk_config
*cnf
;
552 struct mk_config_section
*section
;
554 /* Read configuration file */
555 cnf
= mk_config_create(path
);
557 /* Read tag 'HOST' */
558 section
= mk_config_section_get(cnf
, "HOST");
560 /* Alloc configuration node */
561 host
= mk_mem_malloc_z(sizeof(struct host
));
563 host
->file
= mk_string_dup(path
);
564 host
->servername
= mk_config_section_getval(section
, "Servername",
567 /* document root handled by a mk_pointer */
568 host
->documentroot
.data
= mk_config_section_getval(section
,
571 host
->documentroot
.len
= strlen(host
->documentroot
.data
);
573 /* validate document root configured */
574 if (stat(host
->documentroot
.data
, &checkdir
) == -1) {
575 fprintf(stderr
, "ERROR: Invalid path to DocumentRoot in %s\n\n", path
);
578 else if (!(checkdir
.st_mode
& S_IFDIR
)) {
580 "ERROR: DocumentRoot variable in %s has an invalid directory path\n\n",
585 if (!host
->servername
) {
590 /* Server Signature */
591 if (config
->hideversion
== VAR_OFF
) {
592 mk_string_build(&host
->host_signature
, &len
,
593 "Monkey/%s", VERSION
);
596 mk_string_build(&host
->host_signature
, &len
, "Monkey");
598 mk_string_build(&host
->header_host_signature
.data
,
599 &host
->header_host_signature
.len
,
600 "Server: %s", host
->host_signature
);
604 host
->access_log_path
= mk_config_section_getval(section
,
608 host
->error_log_path
= mk_config_section_getval(section
,
615 /* Imprime error de configuracion y cierra */
616 void mk_config_print_error_msg(char *variable
, char *path
)
618 fprintf(stderr
, "\nError: %s variable in %s has an invalid value.\n",
624 /* Agrega distintos index.xxx */
625 void mk_config_add_index(char *indexname
)
627 struct indexfile
*new_index
= 0, *aux_index
;
629 new_index
= (struct indexfile
*) malloc(sizeof(struct indexfile
));
630 strncpy(new_index
->indexname
, indexname
, MAX_INDEX_NAME
- 1);
631 new_index
->indexname
[MAX_INDEX_NAME
- 1] = '\0';
632 new_index
->next
= NULL
;
634 if (first_index
== NULL
) {
635 first_index
= new_index
;
638 aux_index
= first_index
;
639 while (aux_index
->next
!= NULL
)
640 aux_index
= aux_index
->next
;
641 aux_index
->next
= new_index
;
645 void mk_config_set_init_values(void)
648 config
->timeout
= 15;
649 config
->hideversion
= VAR_OFF
;
650 config
->keep_alive
= VAR_ON
;
651 config
->keep_alive_timeout
= 15;
652 config
->max_keep_alive_request
= 50;
653 config
->resume
= VAR_ON
;
654 config
->standard_port
= 80;
655 config
->listen_addr
= MK_DEFAULT_LISTEN_ADDR
;
656 config
->serverport
= 2001;
657 config
->symlink
= VAR_OFF
;
660 config
->open_flags
= O_RDONLY
| O_NONBLOCK
;
662 /* Max request buffer size allowed
663 * right now, every chunk size is 4KB (4096 bytes),
664 * so we are setting a maximum request size to 32 KB */
665 config
->max_request_size
= MK_REQUEST_CHUNK
* 8;
668 config
->plugins
= NULL
;
671 /* read main configuration from monkey.conf */
672 void mk_config_start_configure(void)
676 mk_config_set_init_values();
677 mk_config_read_files(config
->file_config
, M_DEFAULT_CONFIG_FILE
);
679 /* if not index names defined, set default */
680 if (first_index
== NULL
) {
681 mk_config_add_index("index.html");
685 mk_mimetype_read_config();
687 /* Basic server information */
688 if (config
->hideversion
== VAR_OFF
) {
689 mk_string_build(&config
->server_software
.data
,
690 &len
, "Monkey/%s (%s)", VERSION
, OS
);
691 config
->server_software
.len
= len
;
694 mk_string_build(&config
->server_software
.data
, &len
, "Monkey Server");
695 config
->server_software
.len
= len
;
699 struct host
*mk_config_host_find(mk_pointer host
)
701 struct host
*aux_host
;
703 aux_host
= config
->hosts
;
706 if (strncasecmp(aux_host
->servername
, host
.data
, host
.len
) == 0) {
709 aux_host
= aux_host
->next
;
715 void mk_config_sanity_check()
717 /* Check O_NOATIME for current user, flag will just be used
718 * if running user is allowed to.
720 int fd
, flags
= config
->open_flags
;
723 fd
= open(config
->file_config
, flags
);
726 config
->open_flags
= flags
;