tags:

views:

156

answers:

2

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 ?

+3  A: 

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.

Shtééf
Yes, also `man 2 bind` has an example of binding a Unix domain socket. http://www.opengroup.org/onlinepubs/9699919799/functions/bind.html
mark4o
A: 

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) */

Edit:

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.

Nikolai N Fetissov
I didn't know about `SUN_LEN`, and didn't vote you down either. But I was interested in where `SUN_LEN` came from, so I Google'd it, and found this very informative post: http://mail-index.netbsd.org/tech-net/2006/10/11/0008.html
Shtééf
`SUN_LEN` is not portable, and is not in POSIX.
mark4o
@nos, the other way around - strlen is called for normal path.
Nikolai N Fetissov