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.
#include <assert.h>
#include <stdio.h>
#include <sys/time.h>
#include <time.h>
#include "server.h"
/* шаблон HTML-страницы, генерируемой данным модулем. */
static char* page_template =