Thread overview
How to do IPC using Unix Domain Socket?
Oct 10, 2019
Hossain Adnan
Oct 10, 2019
Hossain Adnan
Oct 10, 2019
Hossain Adnan
October 10, 2019
Here I have a program that wants to

1. detect whether if it's the only instance
    1.1. it does that by trying to create a Unix Domain Socket
    and trying to binding it to a specific address.

2. if a duplicate program is not running, establish an UDS
    and then listen to the socket.

    2.1. if any message comes through that socket, the program will log the incoming message
    2.2. otherwise it should keep listening to the socket forever

3. if there's a duplicate program it should send a message and then exit.

Here's what I have:

import std.socket, std.experimental.logger;

immutable string socketAddress = "\0/tmp/com.localserver.myapp";

void main()
{
	auto socket = new std.socket.Socket(std.socket.AddressFamily.UNIX,
			std.socket.SocketType.STREAM);
	auto addr = new std.socket.UnixAddress(socketAddress);

	auto isUnique = () {
		bool result;

		scope (success)
			log("returns: ", result);

		try
		{
			socket.bind(addr);
			result = true;
		}
		catch (std.socket.SocketOSException e)
			result = false;

		// else throw error
		return result;
	}();

	if (isUnique)
	{
		log("Unique instance detected. Listening...");
		// works upto now
		char[] buffer = [];
		while (1)
		{
			socket.listen(0);
			socket.receive(buffer);
			if (buffer != []) {
				log("Received message: ", buffer);
			}
			buffer = [];
		}
	}
	else
	{
		log("Duplicate instance detected.");
		socket.connect(addr);
		import std.stdio;
		stdout.write("Enter your message:\t");
		socket.send(readln());
		log("Message has been sent. Exiting.");
	}
}


The documentation does not seem very friendly to those who does not have any experience in socket programming.

October 10, 2019
On Thursday, 10 October 2019 at 12:30:25 UTC, Hossain Adnan wrote:
> Here I have a program that wants to
>
> 1. detect whether if it's the only instance
>     1.1. it does that by trying to create a Unix Domain Socket
>     and trying to binding it to a specific address.
>
> [...]

If it helps explaining better, similar rust code is here:
https://gitlab.com/snippets/1893594
October 10, 2019
On Thursday, 10 October 2019 at 12:30:25 UTC, Hossain Adnan wrote:
> Here I have a program that wants to
>
> 1. detect whether if it's the only instance
>     1.1. it does that by trying to create a Unix Domain Socket
>     and trying to binding it to a specific address.
>
> 2. if a duplicate program is not running, establish an UDS
>     and then listen to the socket.
>
>     2.1. if any message comes through that socket, the program will log the incoming message
>     2.2. otherwise it should keep listening to the socket forever
>
> 3. if there's a duplicate program it should send a message and then exit.
>
> Here's what I have:
>
> import std.socket, std.experimental.logger;
>
> immutable string socketAddress = "\0/tmp/com.localserver.myapp";
>
> void main()
> {
> 	auto socket = new std.socket.Socket(std.socket.AddressFamily.UNIX,
> 			std.socket.SocketType.STREAM);
> 	auto addr = new std.socket.UnixAddress(socketAddress);
>
> 	auto isUnique = () {
> 		bool result;
>
> 		scope (success)
> 			log("returns: ", result);
>
> 		try
> 		{
> 			socket.bind(addr);
> 			result = true;
> 		}
> 		catch (std.socket.SocketOSException e)
> 			result = false;
>
> 		// else throw error
> 		return result;
> 	}();
>
> 	if (isUnique)
> 	{
> 		log("Unique instance detected. Listening...");
> 		// works upto now
> 		char[] buffer = [];
> 		while (1)
> 		{
> 			socket.listen(0);
> 			socket.receive(buffer);
> 			if (buffer != []) {
> 				log("Received message: ", buffer);
> 			}
> 			buffer = [];
> 		}
> 	}
> 	else
> 	{
> 		log("Duplicate instance detected.");
> 		socket.connect(addr);
> 		import std.stdio;
> 		stdout.write("Enter your message:\t");
> 		socket.send(readln());
> 		log("Message has been sent. Exiting.");
> 	}
> }
>
>
> The documentation does not seem very friendly to those who does not have any experience in socket programming.

Consulted stackoverflow and came up with this:

import std.socket, std.experimental.logger;

class UDSIPC
{
private:
	static immutable string socketAddress = "\0/tmp/com.localserver.myapp";
	static immutable size_t messageBufferSize = 64;
	static immutable string socketAddressName = "\0/tmp/com.localserver.myapp";
	Socket socket;
	UnixAddress uaddr;

public:
	this(in string socketAddressName = socketAddressName)
	{
		socket = new Socket(AddressFamily.UNIX, SocketType.STREAM);
		uaddr = new UnixAddress(socketAddress);
	}

	bool getUniqueness()
	{
		bool result;

		scope (success)
			log("returns: ", result);

		try
		{
			socket.bind(uaddr);
			result = true;
		}
		catch (SocketOSException e)
			result = false;

		// else throw error
		return result;
	}

	string getMessage()
	{
		socket.listen(0);
		auto receiverSocket = socket.accept();
		char[messageBufferSize] buffer;
		auto amount = receiverSocket.receive(buffer);
		import std.string;
		return format!"%s"(buffer[0 .. amount]);
	}

	void sendMessage(in string message)
	{
		socket.connect(uaddr);
		socket.send(message);
	}

}

void main()
{
	auto ipc = new UDSIPC();

	if (ipc.getUniqueness())
	{
		while (true)
		{
			log(ipc.getMessage());
		}
	}
	else
	{
		import std.stdio, std.string;
		ipc.sendMessage(readln().chomp());
	}
}