Wie kann ich einen Unix-POSIX-Dateideskriptor oder ein Standardeingabe-Handle in einen Socket umwandeln?

8

In inetd und systemd -Typsystemen ist es möglich, dass das System einen Socket bindet und die Anwendung mit dem bereits vorhandenen Socket startet, um beispielsweise socket-basiert zu sein Dienst beginnt. Ich möchte diese Funktionalität in einem meiner Haskell-Daemons ausnutzen.

Der Daemon ruft derzeit socket , bindSocket , listen auf, um ein Objekt Socket zu erstellen, das ich später accept aufrufen kann. Um dies in ein inetd Typ System zu ändern, müsste ich die Standardeingabe als Socket verwenden, aber alles, was ich bisher finden kann, ist stdin :: Handle , oder fdToHandle :: CInt -> Handle - beides ist nicht das, was ich brauche.

Ich kann anscheinend nichts finden, das Handle -> Socket oder irgendetwas wie stdin :: Socket hat. Der nächste, den ich finden kann, ist mkSocket , was sehr niedrig ist, und die meisten anderen Sprachen (z. B. Ruby) bieten einen Aufruf, um einen Dateideskriptor in einen Socket zu verwandeln, ohne verschiedene andere Parameter angeben zu müssen.

    
ocharles 19.07.2012, 10:12
quelle

2 Antworten

4

C-Anwendungen haben den Luxus, sd-daemon.h zu haben, was Socket-Passing automatisch behandelt. In Haskell muss diese Datei manuell emuliert werden.

Sie können % co_de verwenden % , um den Dateideskriptor stdInput zu erhalten. Die stdin Funktion kann natürlich auch verwendet werden. Da Sie POSIX-spezifisches Verhalten wünschen, können Sie nicht erwarten, dass es unter Windows funktioniert.

Sobald Sie die FD haben, haben Sie keine andere Wahl, als die Funktion handleToFd zu verwenden. Haskell kann nicht erraten, welche Art von Socket Sie möchten, also müssen Sie es angeben. Sie möchten wahrscheinlich:

%Vor%

Bitte beachten Sie, dass dies nicht unbedingt ist, wie mkSocket Dateideskriptoren an Ihre Anwendung übergibt. Sie müssen die Umgebungsvariablen systemd und LISTEN_FDS überprüfen, um zu sehen, welche Dateideskriptoren verwendet werden sollen und ob es Ihr Job ist, die Sockets zu binden. Der Standard-Dateideskriptor, der den Standard-Socket darstellt, ist FD 3, nicht FD 0, wie Sie annehmen. LISTEN_PID könnte Ihnen auch mehrere Sockets geben, wenn die Servicedatei dies erfordert.

    
dflemstr 19.07.2012, 11:15
quelle
1

Der Haupttrick für MkSocket besteht darin, zu wissen, dass Sie die richtigen Parameter haben. Der sd-daemon.h hilft dabei. Ich sehe von systemd Manpage auf sd_is_fifo , dass es fstat und getsockname verwendet, das code für sd_is_socket ist hier in git .

Sie können fstat im Unix-Paket verwenden, um zu helfen

%Vor%

Das Netzwerkpaket (teilweise unter Verwendung des Network.Socket.Internals) verwendet auch die C getsockname -Funktion (der Helfer withNewSockAddr weist den richtigen Puffer für die Antwort zu). Dies erfordert entweder das Erraten der "Familie" oder vielleicht nur das Zuweisen eines großen Puffers für die Antwort ( sockaddr_storage von RFC 2553). Aber Network nimmt den Socket-Dateideskriptor von den Socket -Daten. Sie könnten den Code aus Network herausziehen und die Prüfungen, die die sd-daemons.h durchführt, erneut implementieren.

Der getsockopt Code wurde wahrscheinlich auch in das Paket für Netzwerk-Socket-Optionen eingeschlossen .

Aber es scheint nicht, dass irgendjemand es so zusammengestellt hat, wie Sie es brauchen. Seltsam.

    
Chris Kuklewicz 19.07.2012 12:54
quelle