bind() needs a length of the sockaddr structure you've given it. Now, for unix sockets, sockaddr_un is used
What's the proper ways of calculating the length of this when you've filled in the sun_path
member ? I've seen multiple approaches:
socklen_t len = sizeof(sockaddr_un);
socklen_t len = offsetof(sockaddr_un,sun_path) + strlen(addr.sun_path);
socklen_t len = offsetof(sockaddr_un,sun_path) + strlen(addr.sun_path) + 1;
socklen_t len = sizeof(sockaddr.sun_family ) + strlen(addr.sun_path);
And even other approaches. Is it ok to just take the sizeof(sockaddr_un) - or what is the proper way ?
The AF_UNIX (also known as AF_LOCAL) socket family is used to communicate between processes on the same machine efficiently. Traditionally, UNIX domain sockets can be either unnamed, or bound to a filesystem pathname (marked as being of type socket).
After a UNIX domain socket is created, you must bind the socket to a unique file path by using the bind function. Unlike internet sockets in the AF_INET domain where the socket is bound to a unique IP address and port number, a UNIX domain socket is bound to a file path.
Unix domain sockets are often twice as fast as a TCP socket when both peers are on the same host. The Unix domain protocols are not an actual protocol suite, but a way of performing client/server communication on a single host using the same API that is used for clients and servers on different hosts.
The default location for the Unix socket file that the server uses for communication with local clients is /var/lib/mysql/mysql. sock. In case you are using VPS, depending on the Operating system you choose - the socket path might differ.
You are supposed to use SUN_LEN
macro. Here's from /usr/include/sys/un.h
on my Mac:
#if !defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE)
/* actual length of an initialized sockaddr_un */
#define SUN_LEN(su) \
(sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
#endif /* (!_POSIX_C_SOURCE || _DARWIN_C_SOURCE) */
Yes, it's not portable and not POSIX, but we work on real platforms, don't we?
The thing is that you have to zero-terminate the path and the above code is as good as sizeof( struct sockaddr_un )
but might save you a few bytes when copying from user to kernel but wastes a few cycles in strlen
.
Look at how Linux handles that length (from http://lxr.linux.no/linux+v2.6.32/net/unix/af_unix.c#L200):
static int unix_mkname(struct sockaddr_un *sunaddr, int len, unsigned *hashp)
{
if (len <= sizeof(short) || len > sizeof(*sunaddr))
return -EINVAL;
if (!sunaddr || sunaddr->sun_family != AF_UNIX)
return -EINVAL;
if (sunaddr->sun_path[0]) {
/*
* This may look like an off by one error but it is a bit more
* subtle. 108 is the longest valid AF_UNIX path for a binding.
* sun_path[108] doesnt as such exist. However in kernel space
* we are guaranteed that it is a valid memory location in our
* kernel address buffer.
*/
((char *)sunaddr)[len] = 0;
len = strlen(sunaddr->sun_path)+1+sizeof(short);
return len;
}
*hashp = unix_hash_fold(csum_partial(sunaddr, len, 0));
return len;
}
Here len
is directly from third argument to bind
system call, but sunaddr
is already copied into kernel space with that length. You can't have address longer then sizeof( sockadd_un )
. Kernel does the strlen
anyway.
So yes, doing sizeof( sockaddr_un )
is probably safer across the board, but telling kernel exact length doesn't hurt either.
sizeof(struct sockaddr_un)
is fine.
Take a look at the manpage unix(7)
. The field sun_path
is a character array that is part of the struct.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With