Solaris 10: корректно обрабатывать ошибку ENOBUFS при изменении буфера сокета

#c #sockets #unix #solaris #portability

#c #сокеты #unix #solaris #переносимость

Вопрос:

Я наткнулся на своеобразную разницу между сокетами Solaris 10 и другими сокетами Linux / * NIX. Пример:

 int temp1, rc;
temp1 = 16*1024*1024;  /* from config, a value greater than system limit */
rc = setsockopt( sd, SOL_SOCKET, SO_RCVBUF, amp;temp1, sizeof(temp1);
  

Приведенный выше код будет работать rc == 0 на всех системах — Linux, HP-UX и AIX — за исключением Solaris 10. Другие системы автоматически усекают предоставленное значение до допустимого максимума. Solaris 10 справедливо завершается ошибкой, errno == ENOBUFS указывая на ошибку конфигурации.

После некоторого обсуждения было решено, что, поскольку конкретное приложение является критичным, вместо сбоя оно должно продолжать работать как можно более корректно:

  1. Создайте предупреждение в файле журнала о несоответствии конфигурации (легко, добавьте проверку с помощью getsockopt() ) и
  2. Попробуйте установить максимальный размер буфера (чтобы получить максимально возможную производительность).

# 2 — это то, что я застрял. Во всех системах, отличных от Solaris, мне не нужно ничего делать: сокеты уже делают это за меня.

Но на Solaris я в растерянности, что делать. Я реализовал некоторую тривиальную дихотомию вокруг (setsockopt(...) == -1 amp;amp; errno == ENOBUFS) условия определения максимального размера буфера, но это выглядит некрасиво. (У меня также нет контекста для сохранения результатов поиска: поиск пришлось бы повторять для каждого соединения с такой плохой конфигурацией. Глобальные переменные проблематичны, поскольку код находится внутри разделяемой библиотеки и используется из приложения MT.)

Есть ли в Solaris 10 какой-либо лучший способ определить максимально допустимый размер буфера с помощью sockets API?

Есть ли какой-либо способ сообщить Solaris’sockets API усекать значение, как это делают другие системы?

Комментарии:

1. Долгое время не пользовался solaris — можете ли вы получить tcp_max_buf из /dev / tcp? В противном случае какой-нибудь взлом с помощью «ndd -get /dev/ tcp tcp_max_buf» и каким-то образом передайте ее в pgm.

2. Да … Если OpenSolaris имеет какое-либо отношение, то это кажется невозможным : tcps_max_buf только считывается, но никогда не используется как возврат функции или не записывается в переменную. К базовому tcps_propinfo_tbl файлу также можно получить доступ только целиком.

3. Довольно иронично для (бывшего) системного программиста оказаться жертвой строго совместимого интерфейса…

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

Ответ №1:

На данный момент у меня нет доступа к системе Solaris 10, но, согласно документации Oracle, вы можете использовать ndd утилиту для запроса (и установки) настроенных максимальных размеров буфера для TCP и UDP:

 $ ndd -get /dev/tcp tcp_max_buf
$ ndd -get /dev/udp udp_max_buf
  

Я не в курсе C API, но, возможно, какие ndd виды использования доступны?

Комментарии:

1. Я truss отредактировал ее, и она переходит к /dev/tcp , а затем запускает пару специфичных для потоков ioctl() вызовов: I_CANPUT и I_STR. И I_STR, по-видимому, используется для отправки сообщения в модуль stream. И это было, когда заканчивался POSIX — и начиналось что-то, полностью специфичное для Solaris и недостаточно документированное (не удалось найти никакой документации).

2. Исходный код здесь показывает , что это не общедоступный интерфейс. Например, mod_prop_info_t даже не объявлено в /usr/include . На данный момент кажется, что это невыполнимо.