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>
44 /* Raise a configuration error */
45 void mk_config_error(const char *path
, int line
, const char *msg
)
47 printf("\nReading %s", path
);
48 printf("\nError in line %i: %s\n\n", line
, msg
);
53 /* Returns a configuration section by [section name] */
54 struct mk_config_section
*mk_config_section_get(struct mk_config
*conf
,
55 const char *section_name
)
57 struct mk_config_section
*section
;
59 section
= conf
->section
;
61 if (strcasecmp(section
->name
, section_name
) == 0) {
64 section
= section
->next
;
70 /* Register a new section into the configuration struct */
71 void mk_config_section_add(struct mk_config
*conf
, char *section_name
)
73 struct mk_config_section
*new, *aux
;
75 /* Alloc section node */
76 new = mk_mem_malloc(sizeof(struct mk_config_section
));
77 new->name
= mk_string_dup(section_name
);
86 /* go to last section available */
96 /* Register a key/value entry in the last section available of the struct */
97 void mk_config_entry_add(struct mk_config
*conf
,
98 const char *key
, const char *val
)
100 struct mk_config_section
*section
;
101 struct mk_config_entry
*aux_entry
, *new_entry
;
103 if (!conf
->section
) {
104 puts("Error: there are not sections available!");
108 /* Go to last section */
109 section
= conf
->section
;
110 while (section
->next
) {
111 section
= section
->next
;
114 /* Alloc new entry */
115 new_entry
= mk_mem_malloc(sizeof(struct mk_config_entry
));
116 new_entry
->key
= mk_string_dup(key
);
117 new_entry
->val
= mk_string_dup(val
);
118 new_entry
->next
= NULL
;
120 /* Add first entry */
121 if (!section
->entry
) {
122 section
->entry
= new_entry
;
126 /* Go to last entry */
127 aux_entry
= section
->entry
;
128 while (aux_entry
->next
) {
129 aux_entry
= aux_entry
->next
;
132 aux_entry
->next
= new_entry
;
135 struct mk_config
*mk_config_create(const char *path
)
143 char *key
, *val
, *last
;
144 struct mk_config
*conf
= 0;
147 /* Open configuration file */
148 if ((f
= fopen(path
, "r")) == NULL
) {
149 fprintf(stderr
, "\nConfig Error: I can't open %s file\n\n", path
);
153 /* Alloc configuration node */
154 conf
= mk_mem_malloc(sizeof(struct mk_config
));
155 conf
->created
= time(NULL
);
156 conf
->file
= mk_string_dup(path
);
157 conf
->section
= NULL
;
159 /* looking for configuration directives */
160 while (fgets(buf
, 255, f
)) {
162 if (buf
[len
- 1] == '\n') {
164 if (len
&& buf
[len
- 1] == '\r') {
176 /* Skip commented lines */
179 mk_mem_free(section
);
185 /* Section definition */
188 end
= mk_string_char_search(buf
, ']', len
);
190 section
= mk_string_copy_substr(buf
, 1, end
);
191 mk_config_section_add(conf
, section
);
195 mk_config_error(path
, line
, "Bad header definition");
199 /* No separator defined */
203 do { i
++; } while (i
< len
&& isblank(buf
[i
]));
205 indent
= mk_string_copy_substr(buf
, 0, i
);
206 indent_len
= strlen(indent
);
208 /* Blank indented line */
214 /* Validate indentation level */
215 if (strncmp(buf
, indent
, indent_len
) != 0 || !section
||
216 isblank(buf
[indent_len
]) != 0) {
217 mk_config_error(path
, line
, "Invalid indentation level");
220 if (buf
[indent_len
] == '#' || indent_len
== len
) {
224 /* get line key and value */
225 key
= strtok_r(buf
+ indent_len
, "\"\t ", &last
);
226 val
= strtok_r(NULL
, "\"\t", &last
);
229 mk_config_error(path
, line
, "Each key must have a value");
234 mk_string_trim(&key
);
235 mk_string_trim(&val
);
238 mk_config_entry_add(conf
, key
, val
);
243 struct mk_config_section *s;
244 struct mk_config_entry *e;
248 printf("\n[%s]", s->name);
251 printf("\n %s = %s", e->key, e->val);
263 void mk_config_free(struct mk_config
*conf
)
265 struct mk_config_section
*prev
=0, *section
;
268 section
= conf
->section
;
270 while (section
->next
) {
272 section
= section
->next
;
275 /* Free section entries */
276 mk_config_free_entries(section
);
278 /* Free section node */
279 mk_mem_free(section
->name
);
280 mk_mem_free(section
);
282 if (section
== conf
->section
) {
286 section
= conf
->section
;
290 void mk_config_free_entries(struct mk_config_section
*section
)
292 struct mk_config_entry
*prev
= 0, *target
;
294 target
= section
->entry
;
296 while (target
->next
) {
298 target
= target
->next
;
301 /* Free memory assigned */
302 mk_mem_free(target
->key
);
303 mk_mem_free(target
->val
);
305 if (target
== section
->entry
) {
306 section
->entry
= NULL
;
311 target
= section
->entry
;
315 void *mk_config_section_getval(struct mk_config_section
*section
, char *key
, int mode
)
318 struct mk_config_entry
*entry
;
320 entry
= section
->entry
;
322 if (strcasecmp(entry
->key
, key
) == 0) {
324 case MK_CONFIG_VAL_STR
:
325 return (void *) entry
->val
;
326 case MK_CONFIG_VAL_NUM
:
327 return (void *) (size_t) atoi(entry
->val
);
328 case MK_CONFIG_VAL_BOOL
:
329 on
= strcasecmp(entry
->val
, VALUE_ON
);
330 off
= strcasecmp(entry
->val
, VALUE_OFF
);
332 if (on
!= 0 && off
!= 0) {
336 return (void *) VAR_ON
;
339 return (void *) VAR_OFF
;
341 case MK_CONFIG_VAL_LIST
:
342 return mk_string_split_line(entry
->val
);
352 /* Read configuration files */
353 void mk_config_read_files(char *path_conf
, char *file_conf
)
357 struct stat checkdir
;
358 struct mk_config
*cnf
;
359 struct mk_config_section
*section
;
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\n");
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
= (size_t) 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
= (size_t) mk_config_section_getval(section
,
402 if (config
->workers
< 1) {
403 mk_config_print_error_msg("Workers", path
);
405 /* Get each worker clients capacity based on FDs system limits */
406 config
->worker_capacity
= mk_server_worker_capacity(config
->workers
);
409 config
->timeout
= (size_t) mk_config_section_getval(section
,
410 "Timeout", MK_CONFIG_VAL_NUM
);
411 if (config
->timeout
< 1) {
412 mk_config_print_error_msg("Timeout", path
);
416 config
->keep_alive
= (size_t) mk_config_section_getval(section
,
419 if (config
->keep_alive
== VAR_ERR
) {
420 mk_config_print_error_msg("KeepAlive", path
);
423 /* MaxKeepAliveRequest */
424 config
->max_keep_alive_request
= (size_t)
425 mk_config_section_getval(section
,
426 "MaxKeepAliveRequest",
429 if (config
->max_keep_alive_request
== 0) {
430 mk_config_print_error_msg("MaxKeepAliveRequest", path
);
433 /* KeepAliveTimeout */
434 config
->keep_alive_timeout
= (size_t) mk_config_section_getval(section
,
437 if (config
->keep_alive_timeout
== 0) {
438 mk_config_print_error_msg("KeepAliveTimeout", path
);
442 config
->pid_file_path
= mk_config_section_getval(section
,
443 "PidFile", MK_CONFIG_VAL_STR
);
445 /* Home user's directory /~ */
446 config
->user_dir
= mk_config_section_getval(section
,
447 "UserDir", MK_CONFIG_VAL_STR
);
450 config
->index_files
= mk_config_section_getval(section
,
451 "Indexfile", MK_CONFIG_VAL_LIST
);
453 /* HideVersion Variable */
454 config
->hideversion
= (size_t) mk_config_section_getval(section
,
457 if (config
->hideversion
== VAR_ERR
) {
458 mk_config_print_error_msg("HideVersion", path
);
462 config
->user
= mk_config_section_getval(section
, "User", MK_CONFIG_VAL_STR
);
465 config
->resume
= (size_t) mk_config_section_getval(section
,
466 "Resume", MK_CONFIG_VAL_BOOL
);
467 if (config
->resume
== VAR_ERR
) {
468 mk_config_print_error_msg("Resume", path
);
471 /* Max Request Size */
472 config
->max_request_size
= (size_t) mk_config_section_getval(section
,
475 if (config
->max_request_size
<= 0) {
476 mk_config_print_error_msg("MaxRequestSize", path
);
479 config
->max_request_size
*= 1024;
483 config
->symlink
= (size_t) mk_config_section_getval(section
,
484 "SymLink", MK_CONFIG_VAL_BOOL
);
485 if (config
->symlink
== VAR_ERR
) {
486 mk_config_print_error_msg("SymLink", path
);
490 mk_config_read_hosts(path_conf
);
493 void mk_config_read_hosts(char *path
)
499 struct host
*p_host
, *new_host
; /* debug */
502 mk_string_build(&buf
, &len
, "%s/sites/default", path
);
503 config
->hosts
= mk_config_get_host(buf
);
507 if (!config
->hosts
) {
508 printf("\nError parsing main configuration file 'default'\n");
512 mk_string_build(&buf
, &len
, "%s/sites/", path
);
513 if (!(dir
= opendir(buf
)))
517 p_host
= config
->hosts
;
519 /* Reading content */
520 while ((ent
= readdir(dir
)) != NULL
) {
521 if (strcmp((char *) ent
->d_name
, ".") == 0)
523 if (strcmp((char *) ent
->d_name
, "..") == 0)
525 if (strcasecmp((char *) ent
->d_name
, "default") == 0)
528 mk_string_build(&file
, &len
, "%s/sites/%s", path
, ent
->d_name
);
530 new_host
= (struct host
*) mk_config_get_host(file
);
536 p_host
->next
= new_host
;
544 struct host
*mk_config_get_host(char *path
)
546 unsigned long len
= 0;
547 struct stat checkdir
;
549 struct mk_config
*cnf
;
550 struct mk_config_section
*section
;
552 /* Read configuration file */
553 cnf
= mk_config_create(path
);
555 /* Read tag 'HOST' */
556 section
= mk_config_section_get(cnf
, "HOST");
558 /* Alloc configuration node */
559 host
= mk_mem_malloc_z(sizeof(struct host
));
561 host
->file
= mk_string_dup(path
);
562 host
->servername
= mk_config_section_getval(section
, "Servername",
565 /* document root handled by a mk_pointer */
566 host
->documentroot
.data
= mk_config_section_getval(section
,
569 host
->documentroot
.len
= strlen(host
->documentroot
.data
);
571 /* validate document root configured */
572 if (stat(host
->documentroot
.data
, &checkdir
) == -1) {
573 fprintf(stderr
, "ERROR: Invalid path to DocumentRoot in %s\n\n", path
);
576 else if (!(checkdir
.st_mode
& S_IFDIR
)) {
578 "ERROR: DocumentRoot variable in %s has an invalid directory path\n\n",
583 if (!host
->servername
) {
588 /* Server Signature */
589 if (config
->hideversion
== VAR_OFF
) {
590 mk_string_build(&host
->host_signature
, &len
,
591 "Monkey/%s", VERSION
);
594 mk_string_build(&host
->host_signature
, &len
, "Monkey");
596 mk_string_build(&host
->header_host_signature
.data
,
597 &host
->header_host_signature
.len
,
598 "Server: %s", host
->host_signature
);
602 host
->access_log_path
= mk_config_section_getval(section
,
606 host
->error_log_path
= mk_config_section_getval(section
,
613 /* Imprime error de configuracion y cierra */
614 void mk_config_print_error_msg(char *variable
, char *path
)
616 fprintf(stderr
, "\nError: %s variable in %s has an invalid value.\n",
622 void mk_config_set_init_values(void)
625 config
->timeout
= 15;
626 config
->hideversion
= VAR_OFF
;
627 config
->keep_alive
= VAR_ON
;
628 config
->keep_alive_timeout
= 15;
629 config
->max_keep_alive_request
= 50;
630 config
->resume
= VAR_ON
;
631 config
->standard_port
= 80;
632 config
->listen_addr
= MK_DEFAULT_LISTEN_ADDR
;
633 config
->serverport
= 2001;
634 config
->symlink
= VAR_OFF
;
637 config
->open_flags
= O_RDONLY
| O_NONBLOCK
;
638 config
->index_files
= NULL
;
640 /* Max request buffer size allowed
641 * right now, every chunk size is 4KB (4096 bytes),
642 * so we are setting a maximum request size to 32 KB */
643 config
->max_request_size
= MK_REQUEST_CHUNK
* 8;
646 config
->plugins
= NULL
;
649 /* read main configuration from monkey.conf */
650 void mk_config_start_configure(void)
654 mk_config_set_init_values();
655 mk_config_read_files(config
->file_config
, M_DEFAULT_CONFIG_FILE
);
658 mk_mimetype_read_config();
660 /* Basic server information */
661 if (config
->hideversion
== VAR_OFF
) {
662 mk_string_build(&config
->server_software
.data
,
663 &len
, "Monkey/%s (%s)", VERSION
, OS
);
664 config
->server_software
.len
= len
;
667 mk_string_build(&config
->server_software
.data
, &len
, "Monkey Server");
668 config
->server_software
.len
= len
;
672 struct host
*mk_config_host_find(mk_pointer host
)
674 struct host
*aux_host
;
676 aux_host
= config
->hosts
;
679 if (strncasecmp(aux_host
->servername
, host
.data
, host
.len
) == 0) {
682 aux_host
= aux_host
->next
;
688 void mk_config_sanity_check()
690 /* Check O_NOATIME for current user, flag will just be used
691 * if running user is allowed to.
693 int fd
, flags
= config
->open_flags
;
696 fd
= open(config
->file_config
, flags
);
699 config
->open_flags
= flags
;