Commit 7a7c4007 authored by Kenton Varda's avatar Kenton Varda Committed by GitHub

Merge pull request #533 from ohwgiles/master

RPC: Support abstract unix socket addresses on Linux
parents 8fffb02d d01db3c9
...@@ -28,6 +28,8 @@ ...@@ -28,6 +28,8 @@
#include "windows-sanity.h" #include "windows-sanity.h"
#else #else
#include <netdb.h> #include <netdb.h>
#include <unistd.h>
#include <fcntl.h>
#endif #endif
namespace kj { namespace kj {
...@@ -102,6 +104,7 @@ TEST(AsyncIo, AddressParsing) { ...@@ -102,6 +104,7 @@ TEST(AsyncIo, AddressParsing) {
#if !_WIN32 #if !_WIN32
EXPECT_EQ("unix:foo/bar/baz", tryParse(w, network, "unix:foo/bar/baz")); EXPECT_EQ("unix:foo/bar/baz", tryParse(w, network, "unix:foo/bar/baz"));
EXPECT_EQ("unix-abstract:foo/bar/baz", tryParse(w, network, "unix-abstract:foo/bar/baz"));
#endif #endif
// We can parse services by name... // We can parse services by name...
...@@ -387,5 +390,27 @@ TEST(AsyncIo, Udp) { ...@@ -387,5 +390,27 @@ TEST(AsyncIo, Udp) {
#endif // !_WIN32 #endif // !_WIN32
#ifdef __linux__ // Abstract unix sockets are only supported on Linux
TEST(AsyncIo, AbstractUnixSocket) {
auto ioContext = setupAsyncIo();
auto& network = ioContext.provider->getNetwork();
Own<NetworkAddress> addr = network.parseAddress("unix-abstract:foo").wait(ioContext.waitScope);
Own<ConnectionReceiver> listener = addr->listen();
// chdir proves no filesystem dependence. Test fails for regular unix socket
// but passes for abstract unix socket.
int originalDirFd;
KJ_SYSCALL(originalDirFd = open(".", O_RDONLY | O_DIRECTORY | O_CLOEXEC));
KJ_DEFER(close(originalDirFd));
KJ_SYSCALL(chdir("/tmp"));
KJ_DEFER(KJ_SYSCALL(fchdir(originalDirFd)));
addr->connect().attach(kj::mv(listener)).wait(ioContext.waitScope);
}
#endif // __linux__
} // namespace } // namespace
} // namespace kj } // namespace kj
...@@ -449,8 +449,12 @@ public: ...@@ -449,8 +449,12 @@ public:
return str('[', buffer, "]:", ntohs(addr.inet6.sin6_port)); return str('[', buffer, "]:", ntohs(addr.inet6.sin6_port));
} }
case AF_UNIX: { case AF_UNIX: {
if (addr.unixDomain.sun_path[0] == '\0') {
return str("unix-abstract:", addr.unixDomain.sun_path + 1);
} else {
return str("unix:", addr.unixDomain.sun_path); return str("unix:", addr.unixDomain.sun_path);
} }
}
default: default:
return str("(unknown address family ", addr.generic.sa_family, ")"); return str("(unknown address family ", addr.generic.sa_family, ")");
} }
...@@ -470,6 +474,9 @@ public: ...@@ -470,6 +474,9 @@ public:
StringPtr path = str.slice(strlen("unix:")); StringPtr path = str.slice(strlen("unix:"));
KJ_REQUIRE(path.size() < sizeof(addr.unixDomain.sun_path), KJ_REQUIRE(path.size() < sizeof(addr.unixDomain.sun_path),
"Unix domain socket address is too long.", str); "Unix domain socket address is too long.", str);
KJ_REQUIRE(path.size() == strlen(path.cStr()),
"Unix domain socket address contains NULL. Use"
" 'unix-abstract:' for the abstract namespace.");
result.addr.unixDomain.sun_family = AF_UNIX; result.addr.unixDomain.sun_family = AF_UNIX;
strcpy(result.addr.unixDomain.sun_path, path.cStr()); strcpy(result.addr.unixDomain.sun_path, path.cStr());
result.addrlen = offsetof(struct sockaddr_un, sun_path) + path.size() + 1; result.addrlen = offsetof(struct sockaddr_un, sun_path) + path.size() + 1;
...@@ -478,6 +485,21 @@ public: ...@@ -478,6 +485,21 @@ public:
return array.finish(); return array.finish();
} }
if (str.startsWith("unix-abstract:")) {
StringPtr path = str.slice(strlen("unix-abstract:"));
KJ_REQUIRE(path.size() + 1 < sizeof(addr.unixDomain.sun_path),
"Unix domain socket address is too long.", str);
result.addr.unixDomain.sun_family = AF_UNIX;
result.addr.unixDomain.sun_path[0] = '\0';
// although not strictly required by Linux, also copy the trailing
// NULL terminator so that we can safely read it back in toString
memcpy(result.addr.unixDomain.sun_path + 1, path.cStr(), path.size() + 1);
result.addrlen = offsetof(struct sockaddr_un, sun_path) + path.size() + 1;
auto array = kj::heapArrayBuilder<SocketAddress>(1);
array.add(result);
return array.finish();
}
// Try to separate the address and port. // Try to separate the address and port.
ArrayPtr<const char> addrPart; ArrayPtr<const char> addrPart;
Maybe<StringPtr> portPart; Maybe<StringPtr> portPart;
......
...@@ -390,7 +390,8 @@ int main(int argc, const char* argv[]) { ...@@ -390,7 +390,8 @@ int main(int argc, const char* argv[]) {
{% endhighlight %} {% endhighlight %}
Note that for the connect address, Cap'n Proto supports DNS host names as well as IPv4 and IPv6 Note that for the connect address, Cap'n Proto supports DNS host names as well as IPv4 and IPv6
addresses. Additionally, a Unix domain socket can be specified as `unix:` followed by a path name. addresses. Additionally, a Unix domain socket can be specified as `unix:` followed by a path name,
and an abstract Unix domain socket can be specified as `unix-abstract:` followed by an identifier.
For a more complete example, see the For a more complete example, see the
[calculator client sample](https://github.com/sandstorm-io/capnproto/tree/master/c++/samples/calculator-client.c++). [calculator client sample](https://github.com/sandstorm-io/capnproto/tree/master/c++/samples/calculator-client.c++).
...@@ -429,7 +430,8 @@ int main(int argc, const char* argv[]) { ...@@ -429,7 +430,8 @@ int main(int argc, const char* argv[]) {
Note that for the bind address, Cap'n Proto supports DNS host names as well as IPv4 and IPv6 Note that for the bind address, Cap'n Proto supports DNS host names as well as IPv4 and IPv6
addresses. The special address `*` can be used to bind to the same port on all local IPv4 and addresses. The special address `*` can be used to bind to the same port on all local IPv4 and
IPv6 interfaces. Additionally, a Unix domain socket can be specified as `unix:` followed by a IPv6 interfaces. Additionally, a Unix domain socket can be specified as `unix:` followed by a
path name. path name, and an abstract Unix domain socket can be specified as `unix-abstract:` followed by
an identifier.
For a more complete example, see the For a more complete example, see the
[calculator server sample](https://github.com/sandstorm-io/capnproto/tree/master/c++/samples/calculator-server.c++). [calculator server sample](https://github.com/sandstorm-io/capnproto/tree/master/c++/samples/calculator-server.c++).
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment