Category: it

me

Верификация email регекспами.

https://data.iana.org/TLD/tlds-alpha-by-domain.txt
По ссылке - список актуальных TLD.

Мы видим, что:
- эпоха .com, .net, .org, .edu, .mil, малоизвестного .int и двухбуквенных геодоменов давно канула в Лету

- tld растут как грибы на навозной куче после дождя; регулярно появляются новые

- практически кто угодно может сделать свой tld с блекджеком и whois-серверами. Так, есть не только .YANDEX, .GOOGLE и .YAHOO, но и .GOODYEAR, .VIRGIN и даже .VODKA

- кроме того, есть куча непроизносимых tld типа .vermögensberatung или .சிங்கப்பூர்.

Обращаю на эти факты самое пристальное внимание всех любителей писать регекспы для верификации email: всё это плохо, очень плохо или вовсе никак не ложится в привычную схему "нагуглил и прикрутил раз и навсегда регексп". Поэтому правильный подход - не писать регекспы для верификации email.

На этом тему предлагаю закрыть.
me

Невыносимо лёгкая поступь прогресса

Лет 15 назад вместо этого был бы один шаблон на HTML::Template/Smarty, один обработчик на mod_perl/PHP, и это более чем сносно работало на Pentium 2, в на Pentium III-800 просто рвало всё вклочья. На поддержке кода мог бы работать джуниор.
Теперь же создание блога - 6 статей. Вот уж воистину - торжество бессмысленности. Технология ради технологии и только ради технологии. И с ценником программиста далеко за 150 000.

Цикл уроков "Создание блога на Symfony 2.8 lts"
https://habrahabr.ru/post/301760
https://habrahabr.ru/post/302032
https://habrahabr.ru/post/302438
https://habrahabr.ru/post/302602
https://habrahabr.ru/post/303114
https://habrahabr.ru/post/303578
me

Асинхронное программирование, ко-рутины и все-все-все

Всем известно, что написать асинхронное сетевое приложение, да ещё с поддержкой TLS/SSL - адский труд. По пути придётся преодолеть callback hell, сделать разбор состояний SSL_ERROR_WANT_READ/SSL_ERROR_WANT_WRITE сокета SSL и соотнести их с текущим состоянием асинхронного обработчика, не запутаться в перключениях socket -> TLS/SSL socket и т.п. Всё это очень сложно.

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

Обычно проблема решается в несколько шагов:
1. Код пишется без поддержки SSL/TLS, а перед сервером устанавливается прокси-сервер, на который терминируется SSL/TLS со стороны клиента (хороший пример - https://github.com/bumptech/stud для чего угодно, или всем известный nginx для HTTP/POP3/IMAP4).

2. Берётся готовый асинхронный фреймворк и с помощью него пишется собственный код.

На словах всё прекрасно, однако на самом деле решение - так себе.
Во-первых, появляется лишняя сущность в виде прокси-сервера, который требует ресурсов. Снаружи трафик шифрованный, но внутри кластера - нет, а значит, есть возможность перехвата данных. Особенно актуально это при размещении в облачных сервисах.

Во-вторых, это очень плохо отлаживается, так как основная причина - callback hell асинхронной машины всё равно остаётся.

Можно ли упростить программирование и отладку? Есть мнение, что не только можно, но и нужно.

Решение следующее: сделать по возможности одинаковое API для работы как в асинхронном режиме, так и в линейном. Под линейным подразумевается нечто вроде:
struct pollfd fds;
fds.events = POLLIN;
poll(&fds, 1, timeout);
recv(fds.fd, buf, len);

fds.events = POLLOUT;
poll(&fds, 1, timeout);
send(fds.fd, buf, len);

В примере показано использование устаревшего вызова poll, но так как семантика вызова у poll, epoll и kqueue одинаковые, то принципиальной разницы нет.

Асинхронное API при этом должно мимикрировать под линейное. Приведём фантазийный пример:
struct async_pollfd fds;
fds.events = POLLIN;
async_poll(async_context, &fds, 1, timeout);
recv(fds.fd, buf, len);

fds.events = POLLOUT;
async_poll(async_context, &fds, 1, timeout);
send(fds.fd, buf, len);

Заметим, что глубокой переработке подлежит только вызов ожидания сокета, но не процедуры чтения или записи в него. Это позволит одновременно ожидать готовности нескольких сокетов, а главное - упростит написание самого кода и позволит вызывать любые функции по готовности сокета. Так, не составит практически никакого труда заменить recv на SSL_read и send - на SSL_write.

И самое главное: отлаживать логику программы станет возможно в простейшей для понимания тестовой среде, где без сайд-эффектов работают такие средства как valgrind, gdb, gcov, gprof, strace и т.п.

Читатель работавший с асинхронными фреймворками сразу же задаст резонный вопрос:
- Как, используя асинхронное API, например, libev/libevent "вывернуть наизнанку" callback? Ведь из event loop мы попадаем в процедуру-callback, которая исполняется вне нашего кода, и выйти можно только обратно в event loop?

Вопрос действительно небанальный, однако для обсуждаемой проблемы есть решение: необходимо воспользоваться ко-рутинами.

Теперь соберём всё воедино и опишем алгоритм работы:
Изначально исполнение программы идёт в линейном блоке. После захода в функцию async_poll мы настраиваем требуемые события для одного или нескольких сокетов и производим переключение контекста внутрь event loop. Как только один или несколько сокетов будут готовы к чтению или записи, мы переключаем контекст обратно и выходим из async_poll.

Таким образом мы из асинхронного API делаем псевдосинхронное, незначительно отличающееся от линейного. Массовый параллелизм достигается тем, что async_poll может выполняться во многих ко-рутинах и их количество ограничено только размером оперативной памяти.

Все рассуждения описаны на уровне псевдокода. Как же это выглядит в реальности и насколько дороже относительно линейно исполняемого нам обойдётся код с переключением контекстов?

Ответ на первый вопрос доступен по ссылке:
http://pastebin.com/pBudcdg5

Чтобы ответить на второй вопрос необходимо тестирование. Для этого напишем два эхо-сервера и сравним потребление CPU, а также - скорость передачи данных. В большей степени нас будет интересовать именно потребление CPU, так как остальные системные вызовы будут одинаковыми и расходы придутся на переключение контекста.

Результаты можно видеть в таблице:
 PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
19765 stellar   20   0  426456   4760   2220 S  39.9  0.2   2:32.68 coro
19864 stellar   20   0  411224   4444   2004 R  37.9  0.2   2:31.21 linear


Мы видим, что разница составляет порядка 5%. Это - хороший результат и очень небольшая цена за радикальное упрощение разработки и отладки программы.

Обсуждение в ФБ: https://www.facebook.com/sloneus/posts/636050909879742
me

FreeBSD 10.3/amd64

Нечастые новости из мира FreeBSD:

pkg install mysql57-server
echo 'mysql_enable="YES"' >> /etc/rc.conf
/usr/local/etc/rc.d/mysql-server start
/usr/local/etc/rc.d/mysql-server: WARNING: failed precmd routine for mysql

#FreeBSD как всегда SOSNOOLEY

Так скажите мйентейнеру, что первый тест под названием "поставь СУБД по дефолту" не проходит, потому что это тело не асилило написать шелл-скрипт без ошибок, ёпстыд. И вместо этого насрало себе в руки. А так-то суперсистема рулит, конечно.

Для тех, кто не врубается в причину сарказма: FreeBSD 10.3 доступна с 28.03.16. Сейчас - 20.05.2016 и при этом суперпопулярный сервер MySQL не работает "из коробки". Это значит, что система, как таковая сдохла. Увы и ах.
me

CAS 3.8.0

Давно я об этом не писал.
Вышел CAS 3.8.0; добавлен FastCGI сервер, Apache 2.X теперь, как и Apache 1.3 - deprecated. К сожалению, отличный в прошлом проект HTTP-сервер Apache сам себя похоронил под тяжестью лишней функциональности и массы глупых проверок, совершенно не нужных для сервера приложений.

http://cas.havoc.ru/download/cas-3.8.0.tar.gz
me

Линукс на десктопе

2015 год - год Линупса на десктопе.
Что имеем сейчас:
- Unity адски тормозит на любом разумном железе, делает диафильм из любого анимированного виджета. Найти через стандартный диалог поиска ничего нельзя. Регулярно, раз в 20-30 секунд падают программы из Unity, если у вас 1-2 Гбайт оперативной памяти.

- В KDE нормально нельзя сделать самые простые вещи: вытащить на рабочий стол шорткат для программы, передвинуть его( Карл, его нельзя передвинуть, потянув мышкой!), с первого раза добавить локализацию (а после рестарта - можно!), изменить шрифт в Konsole, все темы, даже контрастные, невообразимо блеклые, и хорошо смотрятся только на IPS. При установке русской локали ставится en_RU.UTF-8 вместо ru_RU.UTF-8, из-за чего куча qt-шных программ падает без четкой диагностики (в коредампе - sigsegv в каком-то messagebox). Поиска по помощи нет, от слова "совсем" (Control-F ищет только по текущей странице, ёбстыд!). Самые простые вещи закопаны внутрь меню третьего-четвертого уровня. Общая бессистемность настроек (в одном месте выбрал локализацию, совершенно в другом - раскладку клавиатуры). И все это тоже тормозит, хотя и меньше чем Gnome.

Я помню времена KDE2 и KDE3. Тормозило всё всегда, но, по крайней мере, раньше не было таких адских требований к оперативке, да и интерфейс был примитивнее и в своей примитивности - менее убогий.

Собственно, к вопросу о том, почему каждый год - год Линукса на десктопе, а как был 1% процент рынка, так он и остался. Причина проста: ваши десктопные продукты - говно, которым невозможно пользоваться. Если вы ими пользуетесь, то либо вас заставили из-под палки, либо вы - мазохист.

Пользоваться десктопным линуксом можно только как запускатором браузера и/или терминала в Windows. Вот и весь результат двадцатилетнего прогресса.

Обсуждение в ФБ: https://www.facebook.com/sloneus/posts/518416144976553
me

Email list

Если вы прочли rfc и вздумали написать парзер списка адресов, у меня для вас очень плохие новости. Эти же плохие новости относятся к Dovecot и Communigate.

Мир намного сложнее стандартов, особенно учитывая наличие программистов на PHP и мега-CMS Drupal, Joomla и 1C Bitrix.

Да, надо следовать стандартам, но если вы пишете парзер, то следовать надо не стандарту, а реальности, иначе у вас вместо логина и домена очень часто будет nil или MISSING_MAILBOX/MISSING_DOMAIN.

Вы не сможете объяснить заказчику, что адрес Ivan <ivan@example.com> - валидный, а адрес .Ivan <ivan@example.com> - нет только на том основании что еще один PHP-джуниор не смог осилить rfc. Особенно, если ведущие почтовые сервисы спокойно обрабатывают битые адреса.

https://tools.ietf.org/html/rfc2822
https://tools.ietf.org/html/rfc5322
https://tools.ietf.org/html/rfc6532
https://tools.ietf.org/html/rfc6854

P.S. И, да. У Мэйлрушечки в парзере списка адресов баги. Хорошо, что в большинстве случаев они не проявляются, но тестировщики их должны были бы найти.

https://www.facebook.com/sloneus/posts/478702688947899
me

Про ZeroMQ

Спасено из тонущего поста ФБ.
https://www.facebook.com/oleg.i.tsarev/posts/10206505560627604

Участники: slonik_v_domene, lionet и zamotivator

Претензии к 0MQ:
- повторяя семантику BSD sockets не работает как BSD sockets;
- дескриптор 0mq нельзя передавать между потоками;
- оно глючит при/после коредампа или любого некорректного завершения одного из peer;
- криво построена работа в асинхронном режиме (все эти poll);
- течёт;
- по дизайну (!) не даёт делать прокси;
- по имплементации не рассчитано на слишком большое количество клиентов;
- по дизайну (!) не рассчитано на облака и доступ интернетных клиентов, только на fixed IP и всякий энтерпрайз подобный;
В общем, использовать это в продакшене = наживать лишний геморрой и седые волосы.

Отдельное замечание про паттерн REQ-REP:
Дело в том, что в 0mq REQ-REP принципиально нельзя работать иначе как вызывая read и write в четкой последовательности.

Отсюда проблема с ребутом: если процесс упал, есть 50% вероятности что данные не были записаны или прочитаны. После чего оно залипает и приходится гасить второй peer. Это все проходили в продакшене, проходили с большой кровью, что когда один компонент отваливался, надо было рестартить все остальные из-за того, что 0mq находилось не в том состоянии.

REQ-REP 0mq - ужасно неудобная вещь, пользовыаться ею как альтернативой BSD sockets нельзя.

В паттерне PUB-SUB этой проблемы уже нет. Но проблема в том, что когда ты все паттерны разберешь и поймешь, что тебе нужен только один, и он — самый сложный, самый нерекомендуемый докой на ømq, самый недодокументированный, и с самыми неочевидными преимуществами над обычными сокетами паттерн ROUTER-ROUTER.

Вообще, с 0mq работа выглядит примерно так: ты что-то делаешь, как правило - простые вещи. И они у тебя получаются быстро и просто.
Потом ты осознаешь что в проекте надо сделать каую-то простую и очевидную вещь, ну там между потоками передать дескриптор очереди.

И вот тут получается Drupal learning curve.
me

systemd, как и ожидалось

Не прошло и пяти лет как появился systemd, якобы упрощающий процесс загрузки линукса, а уже все сколь-нибудь серьезные проекты пишут скрипты поднятия собственного мира в ExecStartPre и ExecStartPost.

Как всегда: хотели что поудобнее, а в результате вся пидерсия просто перекочевала из /etc в /usr/libexec, причем поп сути ничего не изменилось. Даже хуже стало.

Мораль же проста:
1) не надо улучшать то, что и так работало.
2) не следует делать универсальных решений - они неудобны, и в конечном итоге всё равно сведется к куче скриптов.
me

DIME вроде как родил полную спеку

https://darkmail.info/downloads/dark-internet-mail-environment-december-2014.pdf

Добрался до спеки. Посмотрел. Забавно то, что авторы не в состоянии выйти за ограничения собственного мирка текстовых протоколов и key=>value полей заголовков.

Это все очень печально. Предлагаемый стандарт откровенно плох. Это не кардинально новое слово в передаче почты, а 100500-е повторение старых идей.

Из очевидных претензий:
1. непонятно, почему протокол текстовый. Почему описание не в виде ASN.1 или в любом другом двоичном формате? На дворе 2015 год, какой смысл в текстовых протоколах? Особенно если учесть что оно всегда должно ходить over SSL.
2. зачем предлагать соместимость с (E)SMTP? Какой в этом глубокий смысл? Что это даст, кроме усложнения парзеров команд?
3. дикое количество полей заголовков. Зачем они в стандарте? Для чего там упоминания о валютах, структуре организации и прочей ненужной ерунде? Чтобы что?
4. Поля в UTF-8 с переводом строк CRLF смотрятся по меньшей мере странно.
5. DMAP - это вообще без комментариев.

В общем, если это начнут использовать, всем станет очень печально.

Мое мнение: протокол должен быть двоичным, с описанием в ASN.1. MIME версии 2.0 должен быть также двоичным, с описанием в ASN.1, с четким указанием размеров part-ов (например, как в BSON, хотя и там много кривизны). Заголовков должен быть минимум; единая кодировка - UTF-8уже обсудили, что плохо, двоичные данные (аттачменты) передаются как двоичный поток, нигде не должно быть никакого эскейпинга и рекодировки.

Всё не относящееся к передаче именно писем должно быть выкинуто из протокола на мороз. Все даты следует передавать как unix timestamp + localtime чтобы избежать проблем с часовыми поясами и их сменой.

Сокрытие получателя - хорошо, но не особо необходимо (потому, что есть механизм алиасинга в домене). Впрочем, все это решается шифрованием с использоанием пар приватный/публичный ключ. Правда, возникает вопрос выбора алгоритма, особенно учитывая наличие всяких GOST.

Еще одно обсуждение: https://www.facebook.com/permalink.php?story_fbid=421467708011496&id=100004448105790&pnref=story