Branch: rosuav/systemd-sockets
Currently, you can create a Stdio.Port("stdin") as a means of accepting a socket handed to you as FD 0. However, there's no way to accept a socket given as any other FD, making it impossible to use this for systemd's sockets.
Example:
$ cat /etc/systemd/system/listendemo.service [Unit] Description=Listen Demo Requires=listendemo.socket
[Service] User=rosuav ExecStart=/usr/local/bin/pike /home/rosuav/listendemo.pike WorkingDirectory=/home/rosuav
$ cat /etc/systemd/system/listendemo.socket [Socket] ListenStream=123
$ cat listendemo.pike object mainsock = Stdio.Port("systemd", acceptloop); void acceptloop() { while (object sock=mainsock->accept()) { write("Accepted sock: %O\n", sock); sock->write("Stub\n"); sock->close(); } }
int main() { write("Main sock: %O\n", mainsock); return -1; }
Note that the "User=rosuav" directive means that Pike is run as a non-root user. This spares the application the hassle of managing privileges securely, as it never gets root privileges (assuming, of course, that the only reason it needed root was to bind to a privileged port, which is true for a lot of programs).
As with "stdin" mode, the second parameter is optional (blocking vs nonblocking).
This won't break on non-systemd systems for two reasons: firstly, all it ever does is query environment variables, and secondly, it does this only if the application requests it explicitly, so you have to actually ask for it.
Is this something that would be useful? Feel free to bikeshed the API - it's not in 8.1 yet, so anything can change.
ChrisA
Hi Chris,
I had a look at your branch. My feeling is that this would be better placed into a seperate module. Maybe there will be more things that might be useful when interacting with systemd?
If I understand the API correctly, then the number of passed file descriptors will be placed into an environment variable. Why does this not work purely in pike?
int n = (int)getenv("LISTEN_FDS"); array a = allocate(n);
for (int i = 0; i < n; i++) a[i] = Stdio.File(3+i);
Arne
On 02/03/17 04:48, Chris Angelico wrote:
Branch: rosuav/systemd-sockets
Currently, you can create a Stdio.Port("stdin") as a means of accepting a socket handed to you as FD 0. However, there's no way to accept a socket given as any other FD, making it impossible to use this for systemd's sockets.
Example:
$ cat /etc/systemd/system/listendemo.service [Unit] Description=Listen Demo Requires=listendemo.socket
[Service] User=rosuav ExecStart=/usr/local/bin/pike /home/rosuav/listendemo.pike WorkingDirectory=/home/rosuav
$ cat /etc/systemd/system/listendemo.socket [Socket] ListenStream=123
$ cat listendemo.pike object mainsock = Stdio.Port("systemd", acceptloop); void acceptloop() { while (object sock=mainsock->accept()) { write("Accepted sock: %O\n", sock); sock->write("Stub\n"); sock->close(); } }
int main() { write("Main sock: %O\n", mainsock); return -1; }
Note that the "User=rosuav" directive means that Pike is run as a non-root user. This spares the application the hassle of managing privileges securely, as it never gets root privileges (assuming, of course, that the only reason it needed root was to bind to a privileged port, which is true for a lot of programs).
As with "stdin" mode, the second parameter is optional (blocking vs nonblocking).
This won't break on non-systemd systems for two reasons: firstly, all it ever does is query environment variables, and secondly, it does this only if the application requests it explicitly, so you have to actually ask for it.
Is this something that would be useful? Feel free to bikeshed the API
- it's not in 8.1 yet, so anything can change.
ChrisA
On Sun, Feb 12, 2017 at 8:36 AM, Arne Goedeke el@laramies.com wrote:
I had a look at your branch. My feeling is that this would be better placed into a seperate module. Maybe there will be more things that might be useful when interacting with systemd?
Maybe; if so, Stdio.Port would need to expose a way for a module to say "here, make one of you from this fd".
If I understand the API correctly, then the number of passed file descriptors will be placed into an environment variable. Why does this not work purely in pike?
int n = (int)getenv("LISTEN_FDS"); array a = allocate(n);
for (int i = 0; i < n; i++) a[i] = Stdio.File(3+i);
You can't accept() on a Stdio.File. That technique would probably work for an active (connected) socket, but not for a passive (listening) one.
The reason I wrote the code as a patch to Pike rather than doing it in my own application is that Pike doesn't expose a way to construct a Stdio.Port from any existing fd other than stdin. Maybe there should be an API for that instead? I don't know of any other situations that would use it, though, and it's good to check LISTEN_PID before claiming the FDs. It might also be useful to parse LISTEN_FDNAMES and use that in the sprintf("%O") of the Port, which would help with debugging; not a huge feature, but one that can easily be added in the future if it's done this way, whereas there's no easy way to control that from pure Pike code.
ChrisA
I was reading the diff wrong, sorry about that. How about Stdio.Port()->listen_fd()?
Arne
On 02/11/17 23:11, Chris Angelico wrote:
On Sun, Feb 12, 2017 at 8:36 AM, Arne Goedeke el@laramies.com wrote:
I had a look at your branch. My feeling is that this would be better placed into a seperate module. Maybe there will be more things that might be useful when interacting with systemd?
Maybe; if so, Stdio.Port would need to expose a way for a module to say "here, make one of you from this fd".
If I understand the API correctly, then the number of passed file descriptors will be placed into an environment variable. Why does this not work purely in pike?
int n = (int)getenv("LISTEN_FDS"); array a = allocate(n);
for (int i = 0; i < n; i++) a[i] = Stdio.File(3+i);
You can't accept() on a Stdio.File. That technique would probably work for an active (connected) socket, but not for a passive (listening) one.
The reason I wrote the code as a patch to Pike rather than doing it in my own application is that Pike doesn't expose a way to construct a Stdio.Port from any existing fd other than stdin. Maybe there should be an API for that instead? I don't know of any other situations that would use it, though, and it's good to check LISTEN_PID before claiming the FDs. It might also be useful to parse LISTEN_FDNAMES and use that in the sprintf("%O") of the Port, which would help with debugging; not a huge feature, but one that can easily be added in the future if it's done this way, whereas there's no easy way to control that from pure Pike code.
ChrisA
On Sun, Feb 12, 2017 at 9:54 AM, Arne Goedeke el@laramies.com wrote:
I was reading the diff wrong, sorry about that. How about Stdio.Port()->listen_fd()?
*facepalm* That would be what I was looking for originally. How did I not see it?
Thanks Arne. So the question is... why Stdio.Port("stdin") rather than Stdio.Port()->listen_fd(0)?
ChrisA
I'm guessing that the original was "stdin", then someone had the same problem you had and expanded the API without breaking backwards.
I'm guessing that the original was "stdin", then someone had the same problem you had and expanded the API without breaking backwards.
pike-devel@lists.lysator.liu.se