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.