свяжите (), нуждается в длине 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) - или каков надлежащий путь?
sizeof(struct sockaddr_un)
в порядке.
Посмотрите на manpage unix(7)
. Поле sun_path
- это символьный массив, который является частью struct.
Вы должны использовать макрос SUN_LEN
. Вот из /usr/include/sys/un.h
на моем 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) */
Да, он не переносится и не POSIX, но мы работаем на реальных платформах, не так ли? ?
Дело в том, что вам нужно завершить путь нулями, и приведенный выше код не хуже sizeof (struct sockaddr_un)
, но может сэкономить несколько байтов при копировании от пользователя к ядру, но тратит впустую несколько циклов в strlen
.
Посмотрите, как Linux обрабатывает эту длину (из 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;
}
Здесь len
напрямую из третьего аргумента системного вызова bind
, но sunaddr
уже скопирован в пространство ядра с такой длиной. У вас не может быть адреса длиннее sizeof (sockadd_un)
. Ядро все равно выполняет strlen
.
Так что да, выполнение sizeof (sockaddr_un)
, вероятно, безопаснее во всех отношениях, но указание точной длины ядра тоже не повредит.