Can D-Bus connect to a particular PID when there is more than one instance of a program running? - dbus

I'm trying to write a program which will interact with VLC over D-Bus.
When an instance of VLC is running I can execute things like this in the shell
qdbus org.mpris.MediaPlayer2.vlc /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.Pause
qdbus org.mpris.MediaPlayer2.vlc /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.Play
VLC pauses and resumes as expected. Great.
What if there is more than one instance of VLC running, how do I choose which instance the command is sent to? I know its PID. The DBus client doesn't have to be qdebus.

no
every d-bus connection gets unique name and you can ask for other name later using org.freedesktop.DBus.RequestName call, but it has to be unique as well. See "message bus names" part of spec. Note that one process can create multiple connections to bus (and thus have multiple names associated with it)
When you make a d-bus function call you use service name, object path, interface name and method name. First one is used by bus daemon to route your message, and service itself decides how to interpret path/interface/method/parameters part of message.
You can get pid the other way: well behaving dbus clients have to support org.freedesktop.DBus interface and you have org.freedesktop.DBus.GetConnectionUnixProcessID. You could iterate over all connections ( ListNames method ) and compare connection pid with what you have. This does not guarantee one to one mapping.

Related

Handling multiple ptys from a single process without direct protocol I/O

I am considering writing a BBS-like program in C and thinking about exactly how the I/O architecture would work with such a program. I'm familiar with sockets programming already, more specifically the master/remote model (not sure if there's a more official name for it) where a master process running as a daemon runs the vast majority of the application in a main process. When remote TTYs connect, they do so in a separate process that communicates with the main process via a Unix domain socket, and there's a thread on the main process for each remote TTY's I/O. All the modules and functionality are running in the main process.
This works well for things like CLIs for some kind of process, but I don't think it's as well suited for a significantly richer/more interactive program, where I think it'd make much more sense for all the TTYs to be managed in the same process rather than communicating over a socket. For example, you can't run ncurses over a socket, since the termios that we care about is in that remote process, not in our main process or usable over the socket. So taking the master/remote model further, you'd need to move a lot of logic from the main program to the remote processes.
The problem I'm a little stuck on is exactly how you can have the main process handling all the TTYs without itself handling all of the network socket traffic. For example, say we want to allow telnet and SSH connections. With the master/remote model, it might look like this:
Telnet:
Inbound telnet connection
Telnet server launches /usr/sbin/remote_process (custom login shell)
remote_process (a C program, shell script, etc.) begins executing, communicating with main_process
SSH:
Inbound SSH connection
Authentication
SSH server launches /usr/sbin/remote_process (custom login shell)
remote_process (a C program, shell script, etc.) begins executing, communicating with main_process
Importantly, with the master/remote model we consider above, the telnet/SSH protocol is abstracted away from the program in question. It doesn't care if the incoming connection is from Telnet, SSH, a serial port, etc. We don't need to handle the details of these protocols ourselves.
Naively trying to apply this to the single-process model, handling all the TTYs directly, I would think the thing to do would be that step # 3/4 somehow needs to have the main process take over its terminal/PTY. main_process can't be called directly though, since it's already running, and I'm not sure if anything like that would be possible since somehow it would be moving the master/slave for the pty between processes, but the goal would be to have main_process doing everything remote_process was doing in the other model, directly handling the I/O from the Telnet server, SSH server, etc.
The standard way of doing this kind of thing seems to be having the main_process directly run its own listeners - that is, instead of listening for UNIX domain socket connections, directly accept Telnet/SSH traffic, etc. But then, the program is now responsible for handling the details of each individual protocol.
You can see an example of this with SyncrhonetBBS: https://github.com/SynchronetBBS/sbbs/tree/b35365c2e470bde58838cbb7445fe7e8c4bc1beb/src/syncterm
The BBS program itself has code to handle each supported protocol: SSH, TELNET, TELNETS, etc.
(I suppose there is a third model: have the main daemon process itself be quite minimal in what it does, and just have each individual TTY process contain the bulk of all the logic, and just use the daemon process for IPC between the TTYs... but then that gets tricky if you want to do stuff like dynamically loadable and unloadable modules that are really at a "system" level as opposed to per-TTY... so I'm not really considering this other extreme).
Is there any way to have the best of both worlds - be able to control all the different TTYs from a single process, but without having to directly implement protocol-specific handling? And if so, how does the TTY setup occur? I'm not looking for code examples here so much as a general high-level explanation/guidance of what this would likely look and how the different components - processes, sockets, TTYs - would interact.

I don't know how to get orders from the terminal in a multithread situation

I am working on an UDP Socket project. I use 2 threads in my client program. The first thread registers and maintain connexion with the server. The second thread needs to answer some orders from the terminal, for example sending the configuration of the client to the server.
I would need to be able to type onto the terminal when the program is running to inform the second thread of what it needs to do but I don't know how to implement it in my code, and I don't even know what to look for on google.
I haven't tried anything since I have absolutely no idea how to do this
I would like to be able to type "sendconf" for example in the terminal while the program is running and have the second thread answering to that. I know how to send the configuration of the client to the server, I just don't know how to inform the thread it needs to do this.
Message queues?
Add a "message" (the command) to a queue that the second thread polls, it then processes the message and sends a reply to another queue which is polled by the first thread.
If you want to be synchronous instead, the second thread can instead set data directly in the message structure for the reply, and then set a flag that it's finished. The first thread keeps waiting on the flag and then gives the result to the user.

Register more than one MPRIS player with GDBus

I want to register more than one media player with glib. Minimal (non-)working example is here. As I can understand the specification, I should export many objects with the one name /org/mpris/MediaPlayer2 and that's strange.
If you have multiple media players in the same process, you would need to open one D-Bus connection to the session bus for each of them, and expose a separate /org/mpris/MediaPlayer2 object on each connection. You can’t expose multiple objects at the same path on a single D-Bus connection.
Be aware that if you’re using g_bus_get_sync() to get a bus connection, it will return a singleton session bus connection — i.e. the same connection every time you call it. In order to establish multiple connections to the session bus, you will need to connect using g_dbus_address_get_for_bus_sync() and g_dbus_connection_new_for_address(), as stated in the documentation for g_bus_get_sync():
The returned object is a singleton, that is, shared with other callers
of g_bus_get() and g_bus_get_sync() for bus_type. In the event that
you need a private message bus connection, use
g_dbus_address_get_for_bus_sync() and
g_dbus_connection_new_for_address().

How to detect when dbus app exits or craches?

How can a dbus user get notified when the dbus service it is using exits/crashes/restarts?
The tutorial suggests there is a way to do this, but in the specification I only found a signal intended for the name owner.
The dbus tutorial says:
Names have a second important use, other than routing messages. They are used to track lifecycle. When an application exits (or crashes), its connection to the message bus will be closed by the operating system kernel. The message bus then sends out notification messages telling remaining applications that the application's names have lost their owner. By tracking these notifications, your application can reliably monitor the lifetime of other applications.
The dbus specification has a section about the NameLost signal:
org.freedesktop.DBus.NameLost
This signal is sent to a specific application when it loses ownership of a name.
One way to find this out is to listen for the org.freedesktop.DBus.NameOwnerChanged signal, as specified in the D-Bus specification
Your client needs to have some logic implemented to analyse the arguments of the signal to figure out when a name has been claimed, when a service has been restarted, when it is gone etc. But the above signal can be used to receive the relevant information at least.
In your handler function you can check if the name argument matches the service name you want to know about. If the old_owner argument is empty, then the service has just claimed the name on the bus. If new_owner is empty then the service has gone away from the bus (for whatever reason).

Arbitrary two-way UNIX socket communication

I've been working on a complex server-client system in C and I'm not sure how to implement the socket communication.
In a nutshell, the system is a server application which communicates with a database and uses a UNIX socket to communicate with one or more child processes created with fork(). The purpose of the children is to run game servers. The process of launching a game server is like this:
The server/"manager" identifies a game server in the database that is to be made. (Assume database communication is already sorted.)
The manager forks a child (the "game controller").
The game controller sets up two pipe pairs, then forks, replacing its child's stdin with a pipe, and it's stdout and stderr with another pipe.
The game controller's child then runs execlp() to begin running the actual game server executable.
My experience with sockets is fairly minimal. I have used select() on a server application before to 'multiplex' numerous clients, as demonstrated by the simple example in the GNU C documentation here.
I now have a new challenge, as the system must be able to do more: the manager needs to be able to arbitrarily send commands to the game controller children (that it will find by periodically checking the database) and get replies, but also expect incoming arbitrary commands/errors from them and send replies back.
So, I need a sort-of "context" system, where sockets are meaningful only between themselves. In other words, when a command is sent from the manager to the game controller, each party needs to be aware of who is asking and know what the reply is (and, therefore, which command it is a reply to).
Because select() is only useful for knowing when we have incoming data, and a thread should block on it, would I need another thread that sends data and gets the replies? Will this require each game controller, although technically a 'client', to use a listening socket and use select() as well?
I hope I've explained the system and the problem concisely; I will add more detail if required. Thanks!
Ok, I am still not really sure I understand exactly where your trouble is, so I will just spout off some things about writing a client/server app. If I am off track, just let me know.
The way that the server will know which clients corresponds to which socket is that the clients will tell the server. Essentially, you need to have a log-in protocol. When the game controller connects to the server, it will send a message that says "Hi, i am registering as controller foo1 on host xyz, port abc..." and whatever else the server needs to know about its clients. The server will keep a data structure that maps sockets to client metadata, state, etc. Whenever it gets a new message, it can easily map from the incoming host/port to its metadata. Or your protocol can require that on each incoming message, the will client send the name it registered with as a field.
Handling the request/response can be done several ways. First lets deal with the networking part of it on the server side. One way to manage this, as you mentioned, is by using select (or poll, or epoll) to multiplex the sockets. This is actually usually considered the more complicated way to do things. Another way is to spawn off a thread (or fork a process, which is less common these days) for each incoming client. Each spawned thread can read its own assigned socket, responding to messages one at a time without worrying about the fact that there are other clients besides the own it is dealing with. This simple one to one thread to socket model breaks down if there are many clients, but if that is not the case, then it is worth consideration.
Part 2 really covers only the client sending the server a message, and the server replying. What happens when the server wants to initiate communication? How does it do it and how does the client handle it? Also, how do you model the model the communication at the application level, meaning assuming we have the read/write part down, how do we know what to send? You will probably want to model things in terms of state machines. There is also a lot more to deal with like what happens when a client crashes? What about when the server crashes? Also, what if you really have your heart set of using select, perhaps because you expect many client? I will try to add more to this answer tomorrow.

Resources