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

   print_usage(0);

  case 'm':

   /* Пользователь ввел -m или --module-dir. */

   {

    struct stat dir_info;

    /* Проверка существования каталога */

    if (access(optarg, F_OK) != 0)

     error(optarg, "module directory does not exist");

    /* Проверка доступности каталога. */

    if (access(optarg, R_OK | X_OK) != 0)

     error(optarg, "module directory is not accessible");

    /* Проверка того, что это каталог. */

    if (stat(optarg, &dir_info) != 0 || !S_ISDIR(dir_info.st_mode))

     error(optarg, "not a directory");

    /* Все правильно. */

    module_dir = strdup(optarg);

   }

   break;

  case 'p':

   /* Пользователь ввел -p или --port. */

   {

    long value;

    char* end;

    value = strtol(optarg, &end, 10);

    if (*end != '\0')

     /* В номере порта указаны не только цифры. */

     print_usage(1);

    /* Преобразуем номер порта в число с сетевым (обратным)

       порядком следования байтов. */

    port = (uint16_t)htons(value);

   }

   break;

  case 'v':

   /* Пользователь ввел -v или --verbose. */

   verbose = 1;

   break;

  case '?':

   /* Пользователь ввел непонятную опцию. */

   print_usage(1);

  case -1:

   /* Обработка опций завершена. */

   break;

  default:

   abort();

  }

 } while (next_option != -1);

 /* Программа не принимает никаких дополнительных аргументов.

    Если они есть, выдается сообщение об ошибке. */

 if (optind != argc)

  print_usage(1);

 /* Отображение имени каталога, если программа работает в режиме

    развернутых сообщений. */

 if (verbose)

  printf("modules will be loaded from %s\n", module_dir);

 /* Запуск сервера. */

 server_run(local_address, port);

 return 0;

}

Файл main.c содержит следующие функции.

■ Функция getopt_long() (см. раздел 21.3, "Функция getopt_long()") вызывается для анализа опций командной строки. Опции могут задаваться в двух форматах: длинном и коротком. Описание длинных опций приведено в массиве long_options, а коротких — в массиве short_options.

По умолчанию серверный порт имеет номер 0, а локальный адрес задан в виде константы INADDR_ANY. Эти установки можно переопределить с помощью опций --port (-p) и --address (-a) соответственно. Если пользователь ввел адрес, вызывается библиотечная функция gethostbyname(), преобразующая его в числовой Internet-адрес.[38]

По умолчанию серверные модули загружаются из каталога, где находится исполняемый файл. Этот каталог определяется с помощью функции get_self_executable_directory(). Данную установку можно переопределить с помощью опции --module (-m). В таком случае проверяется, является ли указанный каталог доступным.

По умолчанию развернутые сообщения не отображаются, если не указать опцию --verbose (-v).

■ Если пользователь ввел опцию --help (-h) или указал неправильную опцию, вызывается функция print_usage(), которая отображает сообщение о правильном использовании программы и завершает работу.

11.3. Модули

В дополнение к основной программе созданы четыре модуля, в которых реализованы функции сервера. Чтобы создать собственный модуль, достаточно определить функцию module_generate(), которая будет возвращать HTML-код.

11.3.1. Отображение текущего времени

Модуль time.so (исходный текст приведен в листинге 11.6) генерирует простую страницу, где отображается текущее время на сервере. В функции module_generate() вызывается функция gettimeofday(), возвращающая значение текущего времени (см. раздел 8.7, "Функция gettimeofday(): системные часы"), после чего функции localtime() и strftime() преобразуют это значение в текстовый формат. Полученная строка встраивается в шаблон HTML-страницы page_template.

Листинг 11.6. (time.c) серверный модуль, отображающий текущее время

#include <assert.h>

#include <stdio.h>

#include <sys/time.h>

#include <time.h>

#include "server.h"

/* шаблон HTML-страницы, генерируемой данным модулем. */

static char* page_template =

вернуться

38

При необходимости функция gethostbyname() осуществляет поиск имен в DNS.