STRLEN sockaddrlen;
char * sun_ad = SvPVbyte(sun_sv,sockaddrlen);
int addr_len;
-# ifdef __linux__
- /* On Linux sockaddrlen on sockets returned by accept, recvfrom,
+# if defined(__linux__) || defined(HAS_SOCKADDR_SA_LEN)
+ /* On Linux or *BSD sockaddrlen on sockets returned by accept, recvfrom,
getpeername and getsockname is not equal to sizeof(addr). */
if (sockaddrlen < sizeof(addr)) {
Copy(sun_ad, &addr, sockaddrlen, char);
} else {
Copy(sun_ad, &addr, sizeof(addr), char);
}
+# ifdef HAS_SOCKADDR_SA_LEN
+ /* In this case, sun_len must be checked */
+ if (sockaddrlen != addr.sun_len)
+ croak("Invalid arg sun_len field for %s, length is %"UVuf", but sun_len is %"UVuf,
+ "Socket::unpack_sockaddr_un", (UV)sockaddrlen, (UV)addr.sun_len);
+# endif
# else
if (sockaddrlen != sizeof(addr))
croak("Bad arg length for %s, length is %"UVuf", should be %"UVuf,
if (addr.sun_family != AF_UNIX)
croak("Bad address family for %s, got %d, should be %d",
"Socket::unpack_sockaddr_un", addr.sun_family, AF_UNIX);
-
+# ifdef __linux__
if (addr.sun_path[0] == '\0') {
/* Linux-style abstract socket address begins with a nul
* and can contain nuls. */
addr_len = (char *)&addr - (char *)&(addr.sun_path) + sockaddrlen;
- } else {
+ } else
+# endif
+ {
+# if defined(HAS_SOCKADDR_SA_LEN)
+ /* On *BSD sun_path not always ends with a '\0' */
+ int maxlen = addr.sun_len - 2; /* should use offsetof(struct sockaddr_un, sun_path) instead of 2 */
+ if (maxlen > (int)sizeof(addr.sun_path))
+ maxlen = (int)sizeof(addr.sun_path);
+# else
+ const int maxlen = (int)sizeof(addr.sun_path);
+# endif
for (addr_len = 0; addr.sun_path[addr_len]
- && addr_len < (int)sizeof(addr.sun_path); addr_len++);
+ && addr_len < maxlen; addr_len++);
}
ST(0) = sv_2mortal(newSVpvn(addr.sun_path, addr_len));