调用bind()时AF_UNIX套接字的正确长度

时间:2010-02-21 21:24:56

标签: c unix sockets

bind()需要你给出的sockaddr结构的长度。 现在,对于unix套接字,使用了sockaddr_un

当您填写sun_path成员时,计算此长度的正确方法是什么?我见过多种方法:

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);

甚至其他方法。是否可以采用sizeof(sockaddr_un) - 或者正确的方法是什么?

2 个答案:

答案 0 :(得分:9)

您应该使用SUN_LEN宏。这是我Mac上的/usr/include/sys/un.h

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

编辑:

是的,它不是便携式而不是POSIX,但我们在真实平台上工作,不是吗?

问题是你必须对路径进行零终止,并且上面的代码与sizeof( struct sockaddr_un )一样好,但是当从用户复制到内核时可能会节省几个字节,但在{{1}中浪费了几个周期}}

了解Linux如何处理该长度(来自http://lxr.linux.no/linux+v2.6.32/net/unix/af_unix.c#L200):

strlen

这里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; } 直接来自第三个参数到len系统调用,但是bind已经被复制到具有该长度的内核空间中。您的地址不能超过sunaddr。无论如何,内核都会执行sizeof( sockadd_un )

所以是的,做strlen可能会更安全,但告诉内核的确切长度也不会有任何影响。

答案 1 :(得分:4)

sizeof(struct sockaddr_un)没问题。

查看联系人unix(7)。字段sun_path是一个字符数组,它是结构的一部分。