Выбрать главу

В случае обращения к верной странице функция handle_get() возвращает клиенту HTTP-код 200, указывающий на успешную обработку запроса, и вызывает функцию module_generate(), содержащуюся в модуле. Последняя генерирует HTML-код Web-страницы и посылает его клиенту.

■ Функция server_run() регистрирует функцию clean_up_child_process() в качестве обработчика сигнала SIGCHLD. Обработчик просто очищает ресурсы завершившегося дочернего процесса (см. раздел 3.4.4. "Асинхронное удаление дочерних процессов").

11.2.4. Основная программа

В файле main.c (листинг 11.5) содержится функция main() сервера. Она отвечает за анализ аргументов командной строки и обнаружение ошибок в них, а также за конфигурирование и запуск сервера.

Листинг 11.5. (main.c) Главная серверная функция, выполняющая анализ аргументов командной строки

#include <assert.h>

#include <getopt.h>

#include <netdb.h>

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <sys/stat.h>

#include <unistd.h>

#include "server.h"

/* Описание длинных опций для функции getopt_long(). */

static const struct option long_options[] = {

 { "address",    1, NULL, 'a' },

 { "help",       0, NULL, 'h' },

 { "module-dir", 1, NULL, 'm' },

 { "port",       1, NULL, 'p' },

 { "verbose",    0, NULL, 'v' },

};

/* Описание коротких опций для функции getopt_long(). */

static const char* const short_options = "a:hm:p:v";

/* Сообщение о том, как правильно использовать программу. */

static const char* const usage_template =

 "Usage: %s { options }\n"

 " -a, --address ADDR   Bind to local address (by default, bind\n"

 "                      to all local addresses).\n"

 " -h, --help           Print this information.\n"

 " -m, --module-dir DIR Load modules from specified directory\n"

 "                      (by default, use executable directory).\n"

 " -p, --port PORT      Bind to specified port.\n"

 " -v, --verbose        Print verbose messages.\n";

/* Вывод сообщения о правильном использовании программы

   и завершение работы. Если аргумент IS_ERROR не равен нулю,

   сообщение записывается в поток stderr и возвращается

   признак ошибки, в противном случае сообщение выводится в

   поток stdout и возвращается обычный нулевой код. */

static void print_usage(int is_error) {

 fprintf(is_error ? stderr : stdout, usage_template,

  program_name);

 exit(is_error ? 1 : 0);

}

int main(int argc, char* const argv[]) {

 struct in_addr local_address;

 uint16_t port;

 int next_option;

 /* Сохранение имени программы для отображения в сообщениях

    об ошибке. */

 program_name = argv[0];

 /* Назначение стандартных установок. По умолчанию сервер

    связан со всеми локальными адресами, и ему автоматически

    назначается неиспользуемый порт. */

 local_address.s_addr = INADDR_ANY;

 port = 0;

 /* He отображать развернутые сообщения. */

 verbose = 0;

 /* Загружать модули из каталога, в котором содержится

    исполняемый файл. */

 module_dir = get_self_executable_directory();

 assert(module_dir != NULL);

 /* Анализ опций. */

 do {

  next_option =

   getopt_long(argc, argv, short_options,

  long_options, NULL);

  switch (next_option) {

  case 'a':

   /* Пользователь ввел -a или --address. */

   {

    struct hostent* local_host_name;

    /* Поиск заданного адреса. */

    local_host_name = gethostbyname(optarg);

    if (local_host_name == NULL ||

     local_host_name->h_length == 0)

     /* He удалось распознать имя. */

     error(optarg, "invalid host name");

    else

     /* Введено правильное имя */

     local_address.s_addr =

      *((int*)(local_host_name->h_addr_list[0]));

   }

   break;

  case 'h':

   /* Пользователь ввёл -h или --help. */