patch-memcached-udp
Thursday, December 13, 2007
Memcached UDP fix
patch-memcached-udp
Monday, December 10, 2007
XCLIENT в Exim
xclient_allow_hosts = 127.0.0.1 : 192.168.1.1
Пример SMTP диалога:
Connected to localhost.
Escape character is '^]'.
220 dhcp-ng2 ESMTP Exim 4.68 Mon, 10 Dec 2007 19:26:44 +0300
XCLIENT NAME=spike.porcupine.org ADDR=168.100.189.2 HELO=blah
220 XCLIENT success
MAIL FROM:<wietse@porcupine.org>
250 OK
RCPT TO:<user@example.com>
550 relay not permitted
patch-exim-xclient
Friday, December 7, 2007
Memcached UDP
Данные тестирования:
UDP:
Results of memcached stress test:
Total number of connections: 10000
Number of seconds for test: 2.23
Number of successfull connections: 10000
Connections per second: 4494.25
TCP:
Results of memcached stress test:
Total number of connections: 10000
Number of seconds for test: 4.38
Number of successfull connections: 10000
Connections per second: 2280.87
При этом, использовалось 100 одновременных коннекций к серверу, каждая из которых выполняла 3 операции над своим ключом: set, get и delete.
Старые статьи
Friday, November 23, 2007
Использование libmilter во FreeBSD
libmilter.patch
Thursday, November 8, 2007
Извлечение данных из sysctl (3) в FreeBSD
к mib-у приписываются с начала два дополнительных целых - 0,4, то есть, целевой миб будет выглядеть так:
0,4,[mib]
где mib - искомый mib
Далее делается sysctl для этого mib-а, размер лучше задать равным BUFSIZ или же получить размер, указав в качестве буфера NULL.
Чтобы узнать, что хранится в mib'е необходимо разобрать полученный буфер следующим образом:
(unsigned int) (char) [(char) [(char)...]]
Для извлечения значения первое поле можно не использовать, но в нем также хранится тип, который извлекается бинарным "И" с константой CTLTYPE (number & CTLTYPE). Полученное значение сравнивается с CTL константами в /usr/include/sys/sysctl.h. Два символа после этого значения также можно использовать для опеределения типа - 1-й символ определяет тип, второй символ (которого может не быть) определяет наличие знака для численных типов. Соответствие типов и символов типа:
int - 'I'
long - 'L'
quad_t - 'Q'
pointer - 'P'
typedef - 'T'
struct - 'S'
Для 'S' и 'T' типов тип описывается после запятой, то есть, строчка будет 'S,some_struct' или 'T,some_type_t'. Для численных типов второй символ может быть 'U', тогда это число - беззнаковое число.
Wednesday, November 7, 2007
Autotools
Исходные файлы:
configure.ac (можно генерить autoscan'ом)
Makefile.am
Остальное генерируется само.
Утилиты:
autoscan - создает базовый вид configure.ac
autoheader - создает config.h.in на основе configure.ac
aclocal - объединяет макросы, существующие в системе, в файл aclocal.m4
automake - создает файл Makefile.in на базе Makefile.am и configure.ac. Полезные опции: -a (создавать все недостаточные файлы), --foreign (не ругаться на отсутствие гнутой документации и прочей байды)
autoconf - создает configure скрипт, которым далее можно пользоваться
Форматы файлов:
Makefile.am - похож немного на формат обычного make. Для plain конфигураций достаточно простого синтаксиса NAME [?|+]= VALUE
bin_PROGRAMS = some-cli
some_cli_SOURCES = some.c server.c
if GNOME_GUI
bin_PROGRAMS += some-gnome
endif
some_gnome_SOURCES = some.c server.c gnome-some.c
some_gnome_CFLAGS = @DEPS_CFLAGS@
some_gnome_LDADD = @DEPS_LIBS@
Символы @@ подменяются скриптом configure на значения соответствующих configure переменных - происходит это на этапе конфигурации Makefile.in в конечный Makefile.
GNOME_GUI специально передается из autoconf в automake - об этом далее. Переменные, в принципе, достаточно очевидные.
configure.ac - набор специализированных m4 макросов, которые после обработки препроцессором превращаются в исполняемый shell скрипт. Вкратце об m4 - синтаксис примерно такой: MACRO (param, param...) при этом есть специальный синтаксис - подстановки. Если param окружить квадратными скобками, то выполняются следующие подстановки:
[value value value] - передает список значений, как один параметр
[shell code] - выполняет соответствующи shell код, при этом все переменные, определенные внутри квадратных скобок могут использоваться и далее
[M4_MACRO (param...) M4_MACRO(param...)] - выполняет один или несколько макросов для вычисления параметра
Полезные макросы и конструкции autoconf:
- проверка --enable параметра и установка его по умолчанию
AC_ARG_ENABLE([gnome-gui],
[ --enable-gnome-gui Turn on gnome gui],
[case "${enableval}" in
yes) gnomegui=true ;;
no) gnomegui=false ;;
*) AC_MSG_ERROR([bad value ${enableval} for --enable-gnome-gui]) ;;
esac],[gnomegui=true])
Общий вид: AC_ARG_ENABLE(name, help, action_if_set, action_if_unset)
из-за эскейпа этот макрос делается не очень читаемым, так как используется шелл-код внутри макроса.
- для передачи переменной для automake (см. выше) используется такая конструкция, которая дефайнит переменную GNOME_GUI, если была указана опция --enable-gnome-gui:
AM_CONDITIONAL([GNOME_GUI], [test x$gnomegui = xtrue])
- для записи некоторых параметров в файл config.h при указании опции можно пользоваться таким синтаксисом:
AC_ARG_WITH([icn-ip],
[AS_HELP_STRING([--with-ip],
[specify ip to use])],
[with_icn_ip=${withval}],
[with_icn_ip=127.0.0.1])
AC_DEFINE_UNQUOTED([ICN_IP], ["$with_icn_ip"], ["Ip address of server to connect"]
Первый макрос похож на макрос для проверки enable, второй опеределяет соответствующий #define в config.h. Если в квадратных скобках указывать значение без кавычек, то и в config.h оно будет без кавычек (для числовых значений, например).
- шапка файла
m4_include([version.m4])
AC_INIT([ICNet], VERSION_NUMBER)
AM_INIT_AUTOMAKE([no-installinfo no-installman])
AC_CONFIG_HEADER([config.h])
version.m4 содержит одну строку - m4_define([VERSION_NUMBER], [1.0])
Остальное можно взять из того, что нагенерил autoscan
- использование pkg-config
AS_IF([test x$gnomegui = xtrue],
[PKG_CHECK_MODULES(DEPS, gtk+-2.0 libbonoboui-2.0)
AC_SUBST(DEPS_CFLAGS)
AC_SUBST(DEPS_LIBS)
]
)
AS_IF проверяет установленную ранее переменную и если условие выполняется, выполняет проверку библиотек gnome - gtk+-2.0 и libbonoboui-2.0 используя pkg-config. Результаты записываются в переменные DEPS_CFLAGS и DEPS_LIBS, которые мы будем заменять в Makefile.in (там они экранируются символами @DEPS_CFLAGS@).
- проверка библиотеки .so
AC_CHECK_LIB([event], [event_loop])
1-й параметр - имя библиотеки, 2-й - проверка наличия определенного символа в этой библиотеке
- проверка хедеров
AC_CHECK_HEADERS([endian.h arpa/inet.h netinet/in.h stdlib.h string.h sys/socket.h syslog.h unistd.h])
- проверка функций
AC_CHECK_FUNCS([bzero memset socket strerror strtol strtoul])
Порядок запуска autotools
Makefile.am ->
autoscan ->
cp configure.scan configure.ac ->
(edit configure.ac) ->
aclocal ->
autoheader ->
automake ->
autoconf
./configure
make...
Thursday, November 1, 2007
Настройка cgi репозитария для mercurial
для выполнения коммиттов нескольих пользователей в несколько репозитариев лучше всего использовать cgi расширение mercurial. Для этого необходимо настроить соответствующим образом apache, и hgwebdir.
Настройка web-серверва
создаем какую-то директорию, например /usr/local/hgstore, назначаем ее владельца www
записываем в httpd.conf:
Alias /hg/ "/usr/local/hgstore/"
<Directory "/usr/local/hgstore/">
Order allow,deny
Allow from all
AllowOverride All
Options ExecCGI FollowSymLinks
AddHandler cgi-script .cgi
RewriteEngine On
#write base depending on where the base url lives
RewriteBase /hg
RewriteRule ^$ hgwebdir.cgi [L]
# Send requests for files that exist to those files.
RewriteCond %{REQUEST_FILENAME} !-f
# Send requests for directories that exist to those directories.
RewriteCond %{REQUEST_FILENAME} !-d
# Send requests to hgwebdir.cgi, appending the rest of url.
RewriteRule (.*) hgwebdir.cgi/$1 [QSA,L]
</Directory>
Создаем в этой директории такой .htaccess:
AuthUserFile /usr/local/www/htpasswd_hgstore
AuthName "Mercurial Repository"
AuthType Basic
<LimitExcept GET>
Require valid-user
</LimitExcept>
При таких настройках смотреть и чекаутить репозитарий смогут все пользователи, а коммиты и пуши могут делаться только с авторизацией через соответствующий файл паролей.
Настройка mercurial
Далее копируем hgwebdir в заданную директорию:
# install -b /usr/local/share/mercurial/www/hgwebdir.cgi /usr/local/hgstore
# chmod +x /usr/local/hgstore/hgwebdir.cgi
Для каждого репозитария прописываем соответствующую строчку в hgweb.config:
[paths]
VIRTUAL_PATH = FILESYSTEM_PATH
VIRTUAL_PATH - путь, который будет показан в url: https://host/hg/path
FILESYSTEM_PATH - путь, относительно расположения hgwebdir.cgi
Далее создаем hgrc по умолчанию:
[extensions]
hgext.notify =
hgext.gpg =
[email]
from = mercury@example.com
[smtp]
host = localhost
[web]
allow_push = *
push_ssl = false
contact = Vsevolod Stakhov
description = Get our elephants
baseurl = https://hostname/hg/rmilter/
allow_archive = bz2 gz zip
style = gitweb
[hooks]
# send one email per group of changes
changegroup.notify = python:hgext.notify.hook
#incoming.notify = python:hgext.notify.hook
[notify]
# multiple sources can be specified as a whitespace separated list
sources = serve push pull bundle
# really send email
test = false
# subscriber data lives in the notify repo
config = /usr/local/hgstore/notify.conf
#repos live in /usr/local/hgstore/repos on server, so strip 4 "/" chars
strip = 4
template = X-Hg-Repo: {webroot}\nSubject: {webroot}: {desc|firstline|strip}\nFrom: {author}\n\nchangeset {node|short} in {root}\ndetails: {baseurl}{webroot}?cmd=changeset;node={node|short}\n\t{desc|tabindent|strip}\n
maxdiff = -1
Этот файл нужно копировать в каталог repo/REPONAME/,hg/hgrc
для каждого репозитория:
# mkdir repo
# hg init repo/REPONAME
# cp hgrc repo/REPONAME/.hg/hgrc
Поправив соответствующим образом.
Далее нужно не забыть прописать этот путь в hgweb.config.
После этого можно делать push и смотреть репозиторий через web.
Для добавления нового репозитария надо:
* сделать начальный каталог при помощи hg init repos/REPONAME
* прописать путь к нему в файле hgweb.config
* скопировать hgrc по умолчанию в каталог repos/REPONAME/.hg/hgrc
* отредактировать файл repos/REPONAME/.hg/hgrc
После всего нужно сменить фладельца всех файлов на www:
# chown -R www /usr/local/hgstore
Friday, October 26, 2007
Встроенные функции gcc для атомарных операций
Например, следующий код берет адрес позиции указателя в определенном массиве и инкрементирует указатель (после операции он указывает на следующий элемент в массиве):
cur_pos = __sync_fetch_and_add (&pos, sizeof(u_char));
В gcc3 этих функций нет.
Wednesday, October 24, 2007
Определение порядка прохождения пакетов по различным пакетным фильтрам в FreeBSD
Как происходит передача пакета хуку pfil'om:
for (pfh = pfil_hook_get(dir, ph);
pfh != NULL;
pfh = TAILQ_NEXT(pfh, pfil_link)) {
if (pfh->pfil_func != NULL) {
rv = (*pfh->pfil_func)(pfh->pfil_arg, &m, ifp, dir, inp);
if (rv != 0 || m == NULL)
break;
}
}
То есть, перебираются все хуки, начиная с TAILQ_FIRST и им передается пакет в качестве параметра.
Если пакет дропается, то дальше по цепочке он не передается (это надо помнить при записи данных о дропнутых пакетах в лог).
Регистрируются хуки таким образом:
/*
* insert the input list in reverse order of the output list
* so that the same path is followed in or out of the kernel.
*/
if (flags & PFIL_IN)
TAILQ_INSERT_HEAD(list, pfh1, pfil_link);
else
TAILQ_INSERT_TAIL(list, pfh1, pfil_link);
То есть, для входящего трафика модуль, добавивший свой хук последним, будет обрабатывать пакеты первым, и наоборот - для исходящего модуль, добавивший свой хук первым будет обрабатывать пакеты первым.
Теперь надо определиться с порядком загрузки модулей в ядро:
модули при загрузке присоединяются к определенным подсистемам в ядре: эти подсистемы описаны в файле sys/kernel.h:
нас интересуют
SI_SUB_PROTO_IF = 0x8400000, /* interfaces*/
SI_SUB_PROTO_DOMAIN = 0x8800000, /* domains (address families?)*/
SI_SUB_PROTO_IFATTACHDOMAIN = 0x8800001, /* domain dependent data init*/
Системы загружаются по очереди, то есть, чем меньше номер, тем раньше загрузится подсистема и тем раньше к ней присоединится модуль. Сам модуль может присоединиться к подсистеме, указывая ряд различных позиций (согласно аргументу order в функции DECLARE_MODULE):
enum sysinit_elem_order {
SI_ORDER_FIRST = 0x0000000, /* first*/
SI_ORDER_SECOND = 0x0000001, /* second*/
SI_ORDER_THIRD = 0x0000002, /* third*/
SI_ORDER_MIDDLE = 0x1000000, /* somewhere in the middle */
SI_ORDER_ANY = 0xfffffff /* last*/
};
Таким образом, смотрим на подсистему и порядок подключения к подсистеме у каждого интересующего модуля:
pf:
DECLARE_MODULE(pf, pf_mod, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_FIRST);
ipfw:
DECLARE_MODULE(ipfw, ipfwmod, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY);
ipfilter:
DECLARE_MODULE(ipfilter, ipfiltermod, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY);
Согласно порядку загрузки подсистем, имеем SI_SUB_PROTO_DOMAIN -> SI_SUB_PROTO_IFATTACHDOMAIN (ipfilter -> (ipfw, pf)), согласно порядку присоединения модулей к подсистеме имеем окончательный порядок загрузки модулей: ipfilter -> pf -> ipfw.
Таким образом, для входящего трафика:
ipfw -> pf -> ipfilter -> stack
для исходящего:
stack -> ipfilter -> pf -> ipfw
С другой стороны, pf часто загружают в качестве kld, а не компилируют в ядро статически, тогда, если kldstat показывает модуль pf.ko, то загрузился он после ipfw, и порядок прохождения пакетов тоже изменился:
pf -> ipfw -> ipfilter -> stack - для входящего
stack -> ipfilter -> ipfw -> pf - для исходящего
Эта деталь очень важна, особенно при составлении правил, включающих трансляцию адресов, так как фильтру, находящемуся дальше в цепочке приходит уже модифицированный пакет.
Немного о mercurial
Так как в настоящее время я все больше для своих наработок использую mercurial, то для тех, кто с этой rcs не знаком я написал некоторые рекоммендации (предполагается знание хотя бы cvs):
Коротко как использовать mercurial:
идея распределенного хранилища проста - каждая рабочая копия - это целиком хранилище. Для создания хранилища в рабочей копии используем команду
hg init <PATH>
Далее добавляем файлы и каталоги:
cd <PATH>
hg add *
Для помещения хранилища на удаленную машину (аналог клиент-сервера) используем:
hg push ssh://<machine>/<PATH>
но предварительно на удаленной машине надо сделать hg init <PATH>
(можно также использовать вместо push clone). После этого мы имеем 2 одинаковых репозитария. Для коммита в локальный репозитарий используем обычный hg commit. Для синхронизации - hg push. Следующее действие - извлечение рабочей копии из репозитария (checkout) делается следующим образом:
hg clone <PATH> <DEST>, где <PATH> может быть ssh://machine/<PATH>
в каталоге <DEST> создается рабочая копия репозитария и сам репозитарий (каталог .hg). Чтобы получить изменения из общего репозитария можно воспользоваться командой pull, которая делает обратное push - вытаскивает из удаленного репозитария копию и синхронизирует с локальным репозитарием:
hg pull <PATH>, как обычно <PATH> может быть удаленным (ssh)
Остальные команды похожи на cvs, но всегда надо помнить о том, что ты работаешь с _локальным_ репозитарием и о том, что локальный репозитарий необходимо синхронизировать командой push (commit) или pull (checkout) в зависимости от характера изменений.
Полезные ссылки:
Tuesday, October 23, 2007
unreal ircd + codepage patch
patch-codepage
ng_fixttl - netgraph модуль, исправляющий ttl пакетов
ipfw add netgraph 2 ip from any to $host
При этом необходимо помнить о sysctl net.inet.ip.fw.one_pass, который определяет, будет ли правило netgraph эквивалентно allow, или же пакет будет возвращаться в ipfw (на следующее за правилом netgraph правило), или же сразу же будет отдаваться сетевому стеку (если эта переменная установлена в 1).
ng_fixttl.tar.gz
Премодерируемые конференции в innd
* Создаем новую группу: ctlinnd newgroup testgroup m
* Прописываем approver'а в etc/moderators:
testgroup:moderator@hostname
* Где moderator@hostname - валидный почтовый адрес, куда будут приходить посты в группу. Я его сделал локальным, не знаю, можно ли иначе, без доступа к inews.
* Устанавливаем MUA.
* Устанавливаем procmail (для formail)
* Пишем скрипт, похожий на этот:
#!/bin/sh
SUFFIX=$$
formail \
-I"NNTP-Posting-Host" \
-I"X-Trace" \
-I"X-Complaints-To" \
-I"NNTP-Posting-Date" \
-I"Xref" \
-I"Date-Received" \
-I"Received" \
-I"Posted" \
-I"Posting-Version" \
-I"Relay-Version" \
-I"Approved: moderator@hostname" | sed -e '/From .*/d' > /tmp/article.${SUFFIX}
NNTPSERVER=localhost /usr/local/news/bin/inews -h /tmp/article.${SUFFIX}
rm -f /tmp/article.${SUFFIX}
* Отправляем нужные статьи при помощи пайпа к post.sh
Настройка gmirror в FreeBSD
1. Инсталируем FreeBSD
2. Ребутимся,загружаясь вновь с install CD
3. Переходим в fixit mode (для FreeBSD < 5.4 нужен CD2)
4. Выполняем следующие операции:
# chroot /dist
# mount_devfs devfs /dev
# gmirror load
# gmirror label -v -b round-robin gm0 /dev/ad0
# gmirror insert gm0 /dev/ad1
# mount /dev/mirror/gm0s1a /mnt
# echo ‘geom_mirror_load=”YES”‘ >> /mnt/boot/loader.conf
5. Правим fstab (sed или ed)
# sed “s,ad0,mirror/gm0,” /mnt/etc/fstab > /mnt/etc/fstab.new
# mv /mnt/etc/fstab.new /mnt/etc/fstab
6. Ребутимся, загружаясь с жесткого диска
7. Ждем некоторое время, пока mirror просинхронизируется (минимальная установка в 100 Mb синхронизировалась минут 15).
8. Вынимаем любой из дисков; наслаждаемся :)