/** * Fill `p_addr' with the socket's local address/port information. */ int socket_addr_getsockname(socket_addr_t *p_addr, int fd) { struct sockaddr_in sin4; socklen_t len; host_addr_t addr = zero_host_addr; uint16 port = 0; bool success = FALSE; len = sizeof sin4; if (-1 != getsockname(fd, cast_to_pointer(&sin4), &len)) { addr = host_addr_peek_ipv4(&sin4.sin_addr.s_addr); port = ntohs(sin4.sin_port); success = TRUE; } #ifdef HAS_IPV6 if (!success) { struct sockaddr_in6 sin6; len = sizeof sin6; if (-1 != getsockname(fd, cast_to_pointer(&sin6), &len)) { addr = host_addr_peek_ipv6(sin6.sin6_addr.s6_addr); port = ntohs(sin6.sin6_port); success = TRUE; } } #endif /* HAS_IPV6 */ if (success) { socket_addr_set(p_addr, addr, port); } return success ? 0 : -1; }
host_addr_t addrinfo_to_addr(const struct addrinfo *ai) { host_addr_t addr = zero_host_addr; switch (ai->ai_family) { case PF_INET: if (ai->ai_addrlen >= 4) { const struct sockaddr_in *sin4; sin4 = cast_to_constpointer(ai->ai_addr); addr = host_addr_peek_ipv4(&sin4->sin_addr.s_addr); } break; #ifdef HAS_IPV6 case PF_INET6: if (ai->ai_addrlen >= 16) { const struct sockaddr_in6 *sin6; sin6 = cast_to_constpointer(ai->ai_addr); addr = host_addr_peek_ipv6(cast_to_constpointer( sin6->sin6_addr.s6_addr)); } break; #endif /* HAS_IPV6 */ } return addr; }
/** * Parses IPv4 and IPv6 addresses. The latter requires IPv6 support to be * enabled. * * For convenience, if the first character is '[' then the address is parsed * as an IPv6 one and the trailing ']' is both expected and swallowed. This * allows the routine to be used when parsing "ipv4:port" or "[ipv6]:port" * strings. * * @param s The string to parse. * @param endptr This will point to the first character after the parsed * address. * @param addr_ptr If not NULL, it is set to the parsed host address or * ``zero_host_addr'' on failure. * @return Returns TRUE on success; otherwise FALSE. */ bool string_to_host_addr(const char *s, const char **endptr, host_addr_t *addr_ptr) { uint32 ip; bool brackets = FALSE; g_assert(s); if ('[' == *s) { brackets = TRUE; s++; } if (!brackets && string_to_ip_strict(s, &ip, endptr)) { if (addr_ptr) { *addr_ptr = host_addr_get_ipv4(ip); } return TRUE; } else { uint8 ipv6[16]; const char *end; bool ok; ok = parse_ipv6_addr(s, ipv6, &end); if (ok) { if (addr_ptr) { *addr_ptr = host_addr_peek_ipv6(ipv6); } if (brackets) { if (']' == *end) { end++; } else { ok = FALSE; /* Trailing ']' required if we had '[' */ } } } if (endptr != NULL) *endptr = end; if (ok) return TRUE; /* FALL THROUGH */ } if (addr_ptr) *addr_ptr = zero_host_addr; return FALSE; }
/** * Deserialization convenience for IP:port. * * The supplied buffer must hold either 6 or 18 more bytes of data, depending * on the address type we want to deserialize. */ void host_ip_port_peek(const void *p, enum net_type nt, host_addr_t *addr, uint16 *port) { const void *q = p; if (NET_TYPE_IPV4 == nt) { *addr = host_addr_peek_ipv4(q); q = const_ptr_add_offset(q, 4); } else if (NET_TYPE_IPV6 == nt) { *addr = host_addr_peek_ipv6(q); q = const_ptr_add_offset(q, 16); } else { /* Can only deserialize IPv4:port or IPv6:port */ g_assert_not_reached(); } *port = peek_le16(q); }