Как я могу превратить либо дескриптор файла Unix POSIX, либо стандартный дескриптор ввода в Socket?

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

В настоящее время демон вызывает, socket, bindSocket, listen создать Socket объект, который я могу позже назвать accept на. Чтобы изменить это на inetd Система типов мне нужно будет использовать стандартный ввод в качестве Socket, но все, что я могу найти, так это stdin :: Handle, или же fdToHandle :: CInt -> Handle - тоже не то, что мне нужно.

Я не могу найти что-нибудь, что имеет тип Handle -> Socketи ничего подобного stdin :: Socket, Ближайшее, что я могу найти, это mkSocket который является очень низкоуровневым, и большинство других языков (например, Ruby) предоставляют вызов для превращения файлового дескриптора в сокет без необходимости указывать различные другие параметры.

2 ответа

Решение

С приложениями есть роскошь иметь sd-daemon.h который обрабатывает прохождение сокета автоматически. В Haskell этот файл должен быть эмулирован вручную.

Ты можешь использовать stdInput чтобы получить stdin дескриптор файла. handleToFd Функция, конечно, также может быть использована. Поскольку вам нужно поведение, специфичное для POSIX, вы не можете ожидать, что оно будет работать в Windows.

После того, как у вас есть FD, у вас нет выбора, кроме как использовать mkSocket функция. Haskell не может угадать, какой сокет вам нужен, поэтому вы должны указать его. Вы, скорее всего, хотите:

mkSocket fd AF_UNIX Stream defaultProtocol Listening

Пожалуйста, помните, что это не обязательно, как systemd передает файловые дескрипторы в ваше приложение. Вы должны проверить LISTEN_FDS а также LISTEN_PID переменные окружения, чтобы увидеть, какие файловые дескрипторы использовать и стоит ли связывать сокеты. Дескриптором файла по умолчанию, представляющим сокет по умолчанию, является FD 3, а не FD 0, как вы предполагаете. systemd может также дать вам несколько сокетов для использования, если этого требует файл службы.

Основной трюк для MkSocket - знать, что у вас есть правильные параметры. В этом помогает sd-daemon.h. Я вижу из справочной страницы systemd на sd_is_fifo, что он использует fstat и getsockname, код для sd_is_socket находится в git здесь.

Ты можешь использовать fstat завернутый в пакет Unix, чтобы помочь

getFdStatus :: Fd -> IO FileStatus

isSocket :: FileStatus -> Bool

Сетевой пакет (частично используя Network.Socket.Internals) также использует C getsockname функция (помощник withNewSockAddr выделяет правильный буфер для ответа). Для этого нужно либо угадать "семью", либо, возможно, просто выделить большой буфер для ответа (sockaddr_storage из RFC 2553). Но Сеть берет дескриптор файла сокета из Socket данные. Вы можете извлечь код из сети и повторно реализовать проверки, которые выполняет sd-daemons.h.

Так же getsockopt код, вероятно, был упакован в пакет network-socket-options.

Но, похоже, никто не собрал все так, как вам нужно. Странный.

Другие вопросы по тегам