⛏️ index : haiku.git

/*
 * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de.
 * Distributed under the terms of the MIT License.
 */
#ifndef UNIX_ADDRESS_H
#define UNIX_ADDRESS_H

#include <sys/un.h>

#include <SupportDefs.h>


// NOTE: We support the standard FS address space as well as the alternative
// internal address space Linux features (sun_path[0] is 0, followed by 5 hex
// digits, without null-termination). The latter one is nice to have, because
// the address lookup is quick (hash table lookup, instead of asking the VFS to
// resolve the path), and we don't have to pollute the FS when auto-binding
// sockets (e.g. on connect()).


#define	INTERNAL_UNIX_ADDRESS_LEN	(2 + 1 + 5)
	// sun_len + sun_family + null byte + 5 hex digits


struct vnode;


class UnixAddress {
public:
	UnixAddress()
	{
		Unset();
	}

	UnixAddress(const UnixAddress& other)
	{
		*this = other;
	}

	UnixAddress(int32 internalID)
	{
		SetTo(internalID);
	}

	UnixAddress(dev_t volumeID, ino_t nodeID, struct vnode* vnode)
	{
		SetTo(volumeID, nodeID, vnode);
	}

	void SetTo(int32 internalID)
	{
		fInternalID = internalID;
		fVolumeID = -1;
		fNodeID = -1;
		fVnode = NULL;
	}

	void SetTo(dev_t volumeID, ino_t nodeID, struct vnode* vnode)
	{
		fInternalID = -1;
		fVolumeID = volumeID;
		fNodeID = nodeID;
		fVnode = vnode;
	}

	void Unset()
	{
		fInternalID = -1;
		fVolumeID = -1;
		fNodeID = -1;
		fVnode = NULL;
	}

	bool IsValid() const
	{
		return fInternalID >= 0 || fVolumeID >= 0;
	}

	bool IsInternalAddress() const
	{
		return fInternalID >= 0;
	}

	int32 InternalID() const
	{
		return fInternalID;
	}

	int32 VolumeID() const
	{
		return fVolumeID;
	}

	int32 NodeID() const
	{
		return fNodeID;
	}

	struct vnode* Vnode() const
	{
		return fVnode;
	}

	uint32 HashCode() const
	{
		return fInternalID >= 0
			? fInternalID
			: uint32(fVolumeID) ^ uint32(fNodeID);
	}

	char* ToString(char *buffer, size_t bufferSize) const;

	UnixAddress& operator=(const UnixAddress& other)
	{
		fInternalID = other.fInternalID;
		fVolumeID = other.fVolumeID;
		fNodeID = other.fNodeID;
		fVnode = other.fVnode;
		return *this;
	}

	bool operator==(const UnixAddress& other) const
	{
		return fInternalID >= 0
			? fInternalID == other.fInternalID
			: fVolumeID == other.fVolumeID
				&& fNodeID == other.fNodeID;
	}

	bool operator!=(const UnixAddress& other) const
	{
		return !(*this == other);
	}

	static bool IsEmptyAddress(const sockaddr_un& address)
	{
		return address.sun_len == sizeof(sockaddr)
			&& address.sun_path[0] == '\0' && address.sun_path[1] == '\0';
	}

	static int32 InternalID(const sockaddr_un& address)
	{
		if (address.sun_len < INTERNAL_UNIX_ADDRESS_LEN
				|| address.sun_path[0] != '\0') {
			return B_BAD_VALUE;
		}

		// parse the ID
		int32 id = 0;

		for (int32 i = 0; i < 5; i++) {
			char c = address.sun_path[i + 1];
			if (c >= '0' && c <= '9')
				id = (id << 4) + (c - '0');
			else if (c >= 'a' && c <= 'f')
				id = (id << 4) + 10 + (c - 'a');
			else
				return B_BAD_VALUE;
		}

		return id;
	}

private:
	// fat interface: If fInternalID is >= 0, it's an address in the internal
	// namespace, otherwise a FS address.
	int32			fInternalID;
	dev_t			fVolumeID;
	ino_t			fNodeID;
	struct vnode*	fVnode;
};


#endif	// UNIX_ADDRESS_H