Анимация
JavaScript


Главная  Библионтека 

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 [ 206 ] 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242

17.15. Создание сервера-демона 635

> Смотри также-

Описание функции getsockname в perlfunc(l)\ документация по стандартным модулям Socket и IO::Socket; раздел «Sockets» врегИрс{\).

17.15. Создание сервера-демона

Проблема

Вы хотите, чтобы ваша программа работала в качестве демона.

Решение

Если вы - параноик с правами привилегированного пользователя, для начала вызовите chroot для безопасного каталога:

oh root ("/var/daemon )

or die "Couldnt chroot to /var/daemon: $!";

Вызовите fork и завершите родительский процесс.

$pid = fork; exit if Spid;

die "Couldnt fork; S!" unless defined($pid);

Разорвите связь с управляющим терминалом, с которого был запущен процесс, - при этом процесс перестает входить в группу процессов, к которой он принадлежал.

use POSIX;

POSIX;;setsid()

or die "Cant start a new session; $!";

Перехватывайте фатальные сигналы и устанавливайте флаг, означающий, что мы хотим корректно завершиться:

Stime to die = 0;

sub signal handler { $time to die = 1;

$SIG{INT} = SSIG{TERM} = $SIG{HUP} = \&signal handler; # Перехватить или игнорировать $SIG{PIPE}

Настоящий код сервера включается в цикл следующего вида:

until ($time to die) { «...

Комментарий

До появления стандарта POSIX у каждой операционной системы были свои средства, с помощью которых процесс говорил системе: «Я работаю в одиночку;



пожалуйста, не мешайте мне». Появление POSIX внесло в происходящее относительный порядок. Впрочем, это не мешает вам использовать любые специфические функции вашей операционной системы.

К числу этих функций принадлежит chroot, которая изменяет корневой каталог процесса (/). Например, после вызова chroot /var/daemon при попытке прочитать файл /etc/passwd процесс в действительности прочитает файл /var/ daemon/etc/passwd. Конечно, при вызове функции chroot необходимо скопировать все файлы, с которыми работает процесс, в новый каталог. Например, процессу может потребоваться файл /var/daemon/bin/csh. По соображениям безопасности вызов chroot разрешен только привилегированным пользователям. Он выполняется на серверах FTP при анонимной регистрации. На самом деле становиться демоном необязательно.

Операционная система иреднолагает, что родитель ожидает смерти потомка. Для нашего процесса-демона это не нужно, поэтому мы разрываем наследственные связи. Для этого программа вызывает fork и exit, чтобы потомок не был связан с процессом, запустившем родителя. Затем потомок закрывает все файловые манипуляторы, полученные от родителя (STDIN, STDERR и STDOUT), и вызывает POSIX setsid, чтобы обеспечить полное отсоединение от родительского терминала.

Все почти готово. Сигналы типа SIGINT не должны немедленно убивать наш процесс (поведение по умолчанию), поэтому мы перехватываем их с помощью %SIG и устанавливаем флаг заверщения Далее главная программа работает по принципу: «Пока не убили, что-то делаем».

Сигнал SIGPIPE - особый случай. Получить его нетрудно (достаточно записать что-нибудь в манипулятор, закрытый с другого конца), а по умолчанию он ведет себя довольно сурово (завершает процесс). Вероятно, его желательно либо проигнорировать ($SIG{PIPE} = IGNORE ), либо определить собственный обработчик сигнала и организовать его обработку.

> Смотри также-

Страницы руководства setsid(2) и chroot(i) вашей системы (если есть); описание функции chroot Bperlfunc{\).

17.16. Перезапуск сервера по требованию

Проблема

При получении сигнала HUP сервер должен нерезанускаться, но аналогии с metd или httpd.

Решение

Перехватите сигнал SIGHUP и нерезанустите свою программу:

$SELF = /usr/local/libexec/myd , # Моя программа @ARGS = qw(-l /var/log/myd -d), # Аргументы

$SIG{HUP} = \&phoenix,



17.17. Программа: backsniff 637

sub phoenix {

# Закрыть все соединения, убить потомков и

# приготовиться к корректному возрождению

exec($SELF, @ARGS) or die Couldn t restart $i\n ,

Комментарий

Внешне все выглядит просто («Получил сигнал HUP - перезапустись»), но на самом деле проблем хватает. Вы должны знать имя своей программы, а определить его непросто. Конечно, можно воспользоваться переменной $0 модуля FmdBin. Для нормальных программ этого достаточно, но важнейшие системные утилиты должны проявлять большую осторожность, поскольку правильность $0 не гарантирована. Имя программы и аргументы можно жестко закодировать в программе, как это сделано в нашем примере. Однако такое решение не всегда удобно, поэтому имя и аргументы можно читать из внешнего файла (зашишая подлинность его содержимого на уровне файловой системы).

Обработчик сигнала обязательно должен устанавливаться после определения $SELF и laARGS, в противном случае может возникнуть ситуация перехвата - SIGHUP потребует перезапуска, а вы не будете знать, что запускать. Это приведет к гибели вашей программы.

Некоторые серверы при получении SIGHUP не должны перезапускаться - они всего лишь заново читают свой конфигурационный файл:

$CDNFIG FILE = /usr/local/etc/myprog/server conf pi , $SIG{HUP} = \&read config sub read config { do $CONFIG FILE,

Некоторые умные серверы даже автоматически перезагружают свои конфигурационные файлы в случае их обновления. Вам даже не придется ни о чем сигнализировать.

> Смотри также-

Описание функции exec в рег1/ипс(\); рецепты 8.16-8.17; 16.15.

17.17. Программа: backsniff

Программа backsniff регистрирует попытки подключения к портам. Она использует модуль Sys::Syslog, а ему, в свою очередь, нужна библиотека syslog.ph, которая не обязательно присутствует в вашей системе. Попытка подключения регистрируется с параметрами LOG NOTICE и LOG DAEMON. Функция getsockname идентифицирует порт, к которому произошло подключение, а getpeername - компьютер, установивший соединение. Функция getservbyport преобразует локальный номер порта (например, 7) в название службы (например, echo ).



0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 [ 206 ] 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242