Proposal: Create Stdio.Port from systemd-provided socket

classic Classic list List threaded Threaded
7 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Proposal: Create Stdio.Port from systemd-provided socket

Chris Angelico
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
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Proposal: Create Stdio.Port from systemd-provided socket

Arne Goedeke
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
>

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Proposal: Create Stdio.Port from systemd-provided socket

Chris Angelico
On Sun, Feb 12, 2017 at 8:36 AM, Arne Goedeke <[hidden email]> 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
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Proposal: Create Stdio.Port from systemd-provided socket

Arne Goedeke
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 <[hidden email]> 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
>

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Proposal: Create Stdio.Port from systemd-provided socket

Chris Angelico
On Sun, Feb 12, 2017 at 9:54 AM, Arne Goedeke <[hidden email]> 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
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Proposal: Create Stdio.Port from systemd-provided socket

Martin Nilsson (Coppermist) @ Pike (-) developers forum
I'm guessing that the original was "stdin", then someone had the same
problem you had and expanded the API without breaking backwards.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Proposal: Create Stdio.Port from systemd-provided socket

Chris Angelico
In reply to this post by Chris Angelico
On Sun, Feb 12, 2017 at 6:40 PM, Mirar @ Pike  developers forum
<[hidden email]> wrote:
> I'm guessing that the original was "stdin", then someone had the same
> problem you had and expanded the API without breaking backwards.

Entirely possible. I've deleted the branch for this feature, since
it's not needed (although at some point, I might make a pure-Pike
helper function that does the proper verification; my app currently
short-cuts things a bit, since it never needs more than one socket),
and made a small docs tweak to link "stdin" mode with listen_fd.

Thanks for the info, Mirar and Arne! This is where this mailing list
is awesome :)

ChrisA
Loading...