26 декабря 2011 г.

Как получить системную строку форматирования времени

Получение системной строки форматирования даты и/или времени:

  • В Linux:
    char *nl_langinfo(nl_item item);
    в параметре item задать значения D_T_FMT, D_FMT или T_FMT.
  • В Windows:
    int GetLocaleInfo(
      __in LCID Locale,
      __in LCTYPE LCType,
      __out LPTSTR lpLCData,
      __in int cchData);
    в параметре LCType задать значения LOCALE_SSHORTDATE, LOCALE_SSHORTDATE или LOCALE_SSHORTTIME.
P.S. Про кастомный парсер строки формата можно почитать здесь.

20 декабря 2011 г.

Code @ C++: Find sum of elements in the array

Code @ C++: Find sum of elements in the array: Наткнулся на задачу, которую предлагают в Yandex на собеседовании: Ниже приведены три варианта суммирования чисел с плавающей точкой (предполагается, что числа в массиве только положительные)...

21 октября 2011 г.

Как вернуться к интерфейсу Gnome Classic в Ubuntu 11.10

Новый интерфейс Ubuntu мне очень нравится, и он даже работает в режиме интеграции дисплея на VirtualBox. Но всё же на VirtualBox новый интерфейс подтормаживает, поэтому я вынужден вернуться на старый добрый Gnome Classic:

  1. Установить пакет gnome-session-fallback: sudo apt-get install gnome-session-fallback
  2. Выйти из текущей сессии (log out)
  3. На экране ввода пароля нужно в Настройках выбрать тип оболочки Gnome Classic
  4. Ввести пароль и выполнить вход. Теперь Ubuntu будет использовать Gnome Classic по умолчанию.

Источник: http://www.upubuntu.com/2011/10/how-to-use-gnome-classic-on-ubuntu-1110.html

19 сентября 2011 г.

Выключение компрессии в OpenSSL 0.9.8

В OpenSSL реализована встроенная поддержка zlib и по умолчанию включена компрессия пересылаемых пакетов данных. Причем при сжатии очередного пакета используется информация об уже сжатых и отосланых пакетах. Например, если вы отсылаете три одинаковых пакета по 400 байт, и первый пакет сжимается до 275 байт, то второй и третий пакеты в сжатом виде займут всего по 12 байт. Такой подход очень экономит трафик, но применим только к протоколу TLS, потому что он гарантирует доставку пакетов и сохраняет последовательность, в которой пакеты были отосланы. Понятно, что для протоколов с негарантированной доставкой такой подход к сжатию не может быть применён. Это подтверждает RFC 3749 "TLS Compression Methods", в котором написано следующее:

Some compression methods have the ability to maintain state/history information when compressing and decompressing packet payloads. The compression history allows a higher compression ratio to be achieved on a stream as compared to per-packet compression, but maintaining a history across packets implies that a packet might contain data needed to completely decompress data contained in a different packet. History maintenance thus requires both a reliable link and sequenced packet delivery.

Протокол DTLS, выбранный для нашего проекта, был разработан специально для UDP и не гарантирует доставку пакетов. Но большей частью он основан на TLS, и по идее реализация протокола DTLS должна учитывать требования RFC 3749.

К сожалению, в OpenSSL этот момент не учитывается и в DTLS сжатие используется точно также, как и в TLS. Совершенно очевидно, что при потере одного из пакетов вся передача будет нарушена, и даже если этот пакет придет позже, то восстановить исходную последовательность принимающая сторона уже не сможет. Такой неприятный момент должен решаться простым отключением компрессии при использовании DTLS, однако в OpenSSL 0.9.8 это превращается в проблему, потому что в API просто нет функции отключающей компрессию. Вот цитата из документации на метод SSL_COMP_add_compression_method:

An OpenSSL server will match the identifiers listed by a client against its own compression methods and will unconditionally activate compression when a matching identifier is found. There is no way to restrict the list of compression methods supported on a per connection basis.

Начиная с OpenSSL 1.0.0 добавлена опция SSL_OP_NO_COMPRESSION, которая делает то, что мне нужно, но в версии 0.9.8 ее нет. В поисках решения я порылся в сети, но ничего внятного, кроме вот этого не нашел:

void disable_openssl_compression()
{
  STACK_OF(SSL_COMP)* comp_methods = SSL_COMP_get_compression_methods();
  sk_SSL_COMP_zero(comp_methods);
}

Этот хак помогает решить проблему с отключением компрессии, но приносит другую — утечку памяти. Пользоваться таким сомнительным методом не нужно.

Между тем, изучив исходный код OpenSSL, я обнаружил, что информация о доступных компрессорах хранится в простом списке, в который можно добавлять свои компрессоры с помощью функции SSL_COMP_add_compression_method. А раз можно добавлять, то значит должен быть способ и удалять элементы списка. Такой функции в OpenSSL API нет, но после изучения исходников функции SSL_COMP_add_compression_method можно написать свою, не пользуясь хаками, а только предоставленным API:

void disable_openssl_compression (void)
{
  int n = sk_SSL_COMP_num(SSL_COMP_get_compression_methods());
  for (int j = 0; j < n; ++j)
  {
    SSL_COMP *comp = sk_SSL_COMP_pop(SSL_COMP_get_compression_methods());
    OPENSSL_free(comp);
  }
}

12 сентября 2011 г.

Этот загадочный SecurityError (Flex 3)

После очередной порции изменений моё Flash-приложение, загруженное на сервер, перестало работать. То есть не совсем перестало, потому что по click-событиям выполнялось то, что нужно, но визуальные элементы вообще перестали хоть как-то отображаться — кнопки не хайлайтились, текст не скроллился, картинки не отображались... Сложилось такое ощущение, что перестали обрабатываться сообщения, отвечающие за отображение компонентов.

Из-за того, что часть приложения продолжала функционировать, я даже не сразу заметил проблему. При этом локально всё замечательно продолжало работать. Я довольно долго тупил, думая, что это проблемы совместимости установленных Flash-плееров в браузерах и в системе. Но через какое-то время понял, что такое различие в поведении локального приложения и приложения на сервере может вызвать SecurityError. Только где? (Тут я в очередной раз порадовался своей привычке делать маленькие, логически законченные коммиты. Локализовывать баг при таком подходе одно удовольствие и всего лишь вопрос времени.)

Причина обнаружилась в установленном smoothBitmapContent="true" для одного из тегов mx:Image. Так как картинка для тега загружалась не с сервера приложения, то контент по определению считался небезопасным. Доступ к битовым данным в этом случае вызовет SecurityError, а smoothBitmapContent="true" как раз требует такого доступа. Это изменение попало в репозиторий совершенно случайно, в результате неудавшихся экспериментов, но оказалось фатальным для приложения.

Для меня остается загадкой, почему SecurityError вызвал именно такое поведение, когда одна половина приложения работает, а другая половина — нет.

5 сентября 2011 г.

Выбор реализации DTLS

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

К сожалению, удалось найти только три библиотеки, поддерживающие DTLS, и это при том, что протокол TSL, предназначенный для TCP, поддерживают около десятка некоммерческих библиотек, не говоря уже о коммерческих реализациях. Но как бы там ни было, выбирать приходится из того, что есть.

  1. CyaSSL. С момента появления поддержки DTLS в библиотеке CyaSSL прошло уже два с половиной года, но текущая версия (2.0.0 RC2) поддерживает DTLS всё ещё в экспериментальном режиме, а значит CyaSSL не может быть рассмотрена как постоянное решение для более-менее серьёзных продуктов.
  2. OpenSSL. Несмотря на то, что стандарт DTLS был опубликован в 2006 году, поддержка этого протокола в OpenSSL появилась ещё в версии 0.9.8 (2005 год). Версия 0.9.8 входит во многие дистрибутивы Linux, много раз фиксилась, и по всей видимости является стабильной. Хотя и имеет довольно уродский API.
  3. GnuTLS. Поддерживает DTLS начиная с версии 3.0.0, вышедшей в марте 2011 года. К сожалению, я не нашел дистрибутива Linux, в который была бы включена эта версия GnuTLS. Более того, похоже, что прежде, чем она будет куда-то включена, пройдет немало времени. Например, в последнюю версию Ubuntu (11.04) включена GnuTLS 2.8.6, а в будущей Ubuntu 11.10, будет использоваться GnuTLS 2.10.5. Когда будет поддержка 3.0.0 — неизвестно. Многие скажут, мол, собрать библиотеку из исходников не представляет никаких проблем, но на деле GnuTLS тянет за собой ряд библиотек, для которых также нет нативной поддержки в существующих дистрибутивах Linux, а значит они тоже должны быть собраны самостоятельно со всеми вытекающими. Дело вкуса.

Что касается переносимости, то OpenSSL и CyaSSL поддерживают Win/Linux/Mac, GnuTLS поддерживет Windows и "most Unix platforms", поэтому проблем с переходом на другую платформу быть не должно.

Как это не печально, выбор очевиден (по крайней мере для меня) — OpenSSL является самой стабильной и широко распространенной реализацией DTLS, с использованием этой реализации не должно возникнуть серьёзных проблем. Хотя лично я предпочел бы интерфейс GnuTLS, он какой-то более уютный что ли...

25 августа 2011 г.

Наши герои

Мейерс, Александреску и Саттер дают интервью Channel 9. Рассуждают на тему C++, D, международных стандартов и вообще о программировании.

ЗЫ. Что-то я не смог вставить сюда HTML5, так что вот iframe.

23 августа 2011 г.

Безопасность UDP трафика

Столкнулся с проблемой защиты UDP трафика в приложении. Оказалось, что вариантов не так уж много.

1) Ipsec. Не нужно делать никаких изменений в коде. Вся настройка происходит на уровне операционой системы и маршрутизаторов. Недостатки: Вероятные проблемы с установкой и настройкой IPsec в системе. Нужен админ, который бы всё время администрировал IPsec на обоих концах. Кроме этого, IPsec скорее всего не пройдет через NAT-шлюзы.

2) DTLS. Не зависит от настроек операционной системы, только от возможностей приложения на обоих концах соединения. Недостатки: Работает на уровне приложения, а значит придется делать изменения в коде. Существующие реализации можно пересчитать по пальцам одной руки.

3) Сделать защиту самостоятельно. Достоинств почти нет, недостатки - изобретение велосипеда со всеми вытекающими.

13 августа 2011 г.

Саттер рапортует: Стандарт одобрен!

Как сообщил Саттер новый Стандарт C++ был принят единогласно, и теперь он является полноценным Международным Стандартом. Если никаких проволочек не будет, мы имеем все шансы до конца года получить C++11. Ура, товарищи! :)

8 августа 2011 г.

Цитаты: Берра

В теории нет различия между теорией и практикой. На практике есть.
Йоги Берра

7 апреля 2011 г.

Вышел GCC 4.6.0

Вышел первый стабильный резиз GCC 4.6.

Помимо улучшений в оптимизаторе еще примечательны следующие изменения:

  • Появилась поддержка языка Go
  • Появилать новая опция предупреждений -Wsuggest-attribute, которая сообщает, что добавление к функциям атрибутов pure, const или noreturn может улучшить кодогенерацию
  • Новая прагма #pragma GCC diagnostic упрощает управление предупреждениями компилятора прямо из кода
  • Ну и в случае, когда какой-то идентификатор не найден в коде, g++ теперь предлагает свои варианты, которые на его взгляд кажутся наиболее подходяшими

Полный список изменений и нововведений можно почитать здесь: http://gcc.gnu.org/gcc-4.6/changes.html

Саттер рапортует

Как сообщает Саттер черновик стандарта C++ принят в окончательной редакции. Если всё будет хорошо, то стандарт выйдет летом 2011.

27 января 2011 г.

Отслеживание процессов, выполняющих операции ввода-вывода

Команда top в Линуксе, к сожалению, показывает только процессы занимающие процессорное время, а иногда нужно отследить процессы, которые что-то пишут или читают с диска. Для этого есть команда iotop — показывает процессы и потоки, которые в данный момент выполняют операции ввода-вывода.

Однако iotop не показывает процессы, которые находятся в состояии ожидания во время ввода-вывода. Ожидающие процессы можно посмотреть командой ps aux — такие процессы будут помечены буквой D в столбце STAT. Или более удобно отследить их в "реальном времени" с помощью комбинации ps и watch:

watch -n 1 "(ps aux | awk '\$8 ~ /D/ { print \$0 }')"