Как я могу превратить либо дескриптор файла 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.
Но, похоже, никто не собрал все так, как вам нужно. Странный.