Page MenuHome GnuPG

graceful shutdown: DEVINFO should be a gpg-agent command: also watching input close
Testing, HighPublic

Description

scdaemon supports DEVINFO --watch command to keep watching the device removal.
It loops forever (for the current implementation), and the only way to stop watcing is killing scdaemon.

It should work in the following way, like:
(1) It simultaneously polls device info updates and client input close.
(2) On device info update, send the information to client.
(3) On the client input close, finish the command (and finish the connection from client).

But it is not only scdaemon, but also gpg-agent should behave like that, because gpgme uses gpg-agent to access scdaemon.
That is:
(1) gpg-agent (for DEVINFO command) should simultaneously polls on (a) scdaemon's output and (b) client input close.
(2) On the scdaemon output, send the information to client.
(3) On the client input close, finish the command and finish the connection to scdaemon, and finish the connection from client).

Event Timeline

werner added a project: gnupg24.

Did some experiment and I concluded (for now) that new command for gpg-agent would not be needed.
Instead, it might be better doing following in GPGME.

(1) Asking gpg-agent for socket name of scdaemon (if gpg-agent is not yet running, start it).
(2) Then, use the socket to connect scdaemon for DEVINFO --watch.

Note that this (1) is the way how Poldi works to access scdaemon.

By doing this, we don't need to touch gpg-agent, and we don't need to consider difference between how to watch pipe connection and how to watch socket connection on Windows for gpg-agent.

And... for scdaemon, we can assume the connection is socket for DEVINFO --watch command, which allows use of select.

Maybe we can support this directly in gpgme's assuan API.

Asking a change of gpgme would need more time... So, I decided to change gpg-agent side.
gpg-agent part was done in: rGb3f1f2cd192b: agent: Handle SCD DEVINFO --watch command in a special way.

Tested on Debian machine. Test scenario is like following.

(1) Prepare gpg-agent running. Identify the PID by ps command and see the number of threads by ps -m -L PID command

(2) Run the following command to watch the device information

gpg-connect-agent "SCD DEVINFO --watch"

(3) On another terminal, you can see the number of threads of gpg-agent is now increased.

(4) With Ctrl-C, kill the gpg-connect-agent command

(5) Check the number of threads of gpg-agent again, it's now decreased.

Please test on Windows.

gniibe changed the task status from Open to Testing.Jul 1 2024, 4:25 AM
gniibe changed the status of subtask T7160: scd: pipe server shutdown from Open to Testing.

I realized that I put a bug on POSIX; When multiple clients do DEVINFO --watch, it is possible for scdaemon to hang (waiting pselect and read, read by one, read by another is blocked).

You mean it is possible that the initialization function is called by several threads - or that two scdaemon's are running before they realize that one of them is in the way?

I mean: two gpg-agent requests simultaneously running DEVINFO --watch.
Single scdaemon, two threads handling DEVINFO --watch simultaneously, by pselect + read.
Two threads waken up, but it was only one thread which can read(2), another was blocked (before the fix).

I see. the systemd race of having two gpg-agent processes. The second gpg-agent should eventually go away but than it is already too late.

Found another thinko; When there is no clients with DEVINFO --watch, the pipe to be notified is not consumed at all (no read). It eventually results blocked by write(2), when the pipe is filled.

Fixed in rG0a94582af5b1: scd: Fix DEVINFO, allowing no clients which watch the change.