1/*
2 * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
5#ifndef UNIX_ADDRESS_H
6#define UNIX_ADDRESS_H
7
8#include <sys/un.h>
9
10#include <SupportDefs.h>
11
12
13// NOTE: We support the standard FS address space as well as the alternative
14// internal address space Linux features (sun_path[0] is 0, followed by 5 hex
15// digits, without null-termination). The latter one is nice to have, because
16// the address lookup is quick (hash table lookup, instead of asking the VFS to
17// resolve the path), and we don't have to pollute the FS when auto-binding
18// sockets (e.g. on connect()).
19
20
21#define	INTERNAL_UNIX_ADDRESS_LEN	(2 + 1 + 5)
22	// sun_len + sun_family + null byte + 5 hex digits
23
24
25struct vnode;
26
27
28class UnixAddress {
29public:
30	UnixAddress()
31	{
32		Unset();
33	}
34
35	UnixAddress(const UnixAddress& other)
36	{
37		*this = other;
38	}
39
40	UnixAddress(int32 internalID)
41	{
42		SetTo(internalID);
43	}
44
45	UnixAddress(dev_t volumeID, ino_t nodeID, struct vnode* vnode)
46	{
47		SetTo(volumeID, nodeID, vnode);
48	}
49
50	void SetTo(int32 internalID)
51	{
52		fInternalID = internalID;
53		fVolumeID = -1;
54		fNodeID = -1;
55		fVnode = NULL;
56	}
57
58	void SetTo(dev_t volumeID, ino_t nodeID, struct vnode* vnode)
59	{
60		fInternalID = -1;
61		fVolumeID = volumeID;
62		fNodeID = nodeID;
63		fVnode = vnode;
64	}
65
66	void Unset()
67	{
68		fInternalID = -1;
69		fVolumeID = -1;
70		fNodeID = -1;
71		fVnode = NULL;
72	}
73
74	bool IsValid() const
75	{
76		return fInternalID >= 0 || fVolumeID >= 0;
77	}
78
79	bool IsInternalAddress() const
80	{
81		return fInternalID >= 0;
82	}
83
84	int32 InternalID() const
85	{
86		return fInternalID;
87	}
88
89	int32 VolumeID() const
90	{
91		return fVolumeID;
92	}
93
94	int32 NodeID() const
95	{
96		return fNodeID;
97	}
98
99	struct vnode* Vnode() const
100	{
101		return fVnode;
102	}
103
104	uint32 HashCode() const
105	{
106		return fInternalID >= 0
107			? fInternalID
108			: uint32(fVolumeID) ^ uint32(fNodeID);
109	}
110
111	char* ToString(char *buffer, size_t bufferSize) const;
112
113	UnixAddress& operator=(const UnixAddress& other)
114	{
115		fInternalID = other.fInternalID;
116		fVolumeID = other.fVolumeID;
117		fNodeID = other.fNodeID;
118		fVnode = other.fVnode;
119		return *this;
120	}
121
122	bool operator==(const UnixAddress& other) const
123	{
124		return fInternalID >= 0
125			? fInternalID == other.fInternalID
126			: fVolumeID == other.fVolumeID
127				&& fNodeID == other.fNodeID;
128	}
129
130	bool operator!=(const UnixAddress& other) const
131	{
132		return !(*this == other);
133	}
134
135	static bool IsEmptyAddress(const sockaddr_un& address)
136	{
137		return address.sun_len == sizeof(sockaddr)
138			&& address.sun_path[0] == '\0' && address.sun_path[1] == '\0';
139	}
140
141	static int32 InternalID(const sockaddr_un& address)
142	{
143		if (address.sun_len < INTERNAL_UNIX_ADDRESS_LEN
144				|| address.sun_path[0] != '\0') {
145			return B_BAD_VALUE;
146		}
147
148		// parse the ID
149		int32 id = 0;
150
151		for (int32 i = 0; i < 5; i++) {
152			char c = address.sun_path[i + 1];
153			if (c >= '0' && c <= '9')
154				id = (id << 4) + (c - '0');
155			else if (c >= 'a' && c <= 'f')
156				id = (id << 4) + 10 + (c - 'a');
157			else
158				return B_BAD_VALUE;
159		}
160
161		return id;
162	}
163
164private:
165	// fat interface: If fInternalID is >= 0, it's an address in the internal
166	// namespace, otherwise a FS address.
167	int32			fInternalID;
168	dev_t			fVolumeID;
169	ino_t			fNodeID;
170	struct vnode*	fVnode;
171};
172
173
174#endif	// UNIX_ADDRESS_H
175