X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=blobdiff_plain;f=net.c;h=64602a4bf60e7ce934f230cb0ae9d63f5ec404f5;hp=59b7f367fb2f119e338d9411f2060a71b39209fc;hb=edeb499676e6d042ef1a913914a9fcb45a8cadde;hpb=5b15980ce22a3a4244e2440f46eac19eb0ceb3ef diff --git a/net.c b/net.c index 59b7f367..64602a4b 100644 --- a/net.c +++ b/net.c @@ -521,6 +521,14 @@ static socklen_t salen(const struct sockaddr *sa) : sizeof(struct sockaddr_in); } +/** True if @ss holds a v6-mapped-v4 address (RFC 4291, 2.5.5.2) */ +static bool SS_IS_ADDR_V4MAPPED(const struct sockaddr_storage *ss) +{ + const struct sockaddr_in6 *ia6 = (const struct sockaddr_in6 *)ss; + + return ss->ss_family == AF_INET6 && IN6_IS_ADDR_V4MAPPED(&ia6->sin6_addr); +} + /** * Process IPv4/v6 address, turn v6-mapped-v4 address into normal IPv4 address. * \param ss Container of IPv4/6 address. @@ -531,11 +539,10 @@ static socklen_t salen(const struct sockaddr *sa) static const struct sockaddr * normalize_ip_address(const struct sockaddr_storage *ss) { - const struct sockaddr_in6 *ia6 = (const struct sockaddr_in6 *)ss; - assert(ss->ss_family == AF_INET || ss->ss_family == AF_INET6); - if (ss->ss_family == AF_INET6 && IN6_IS_ADDR_V4MAPPED(&ia6->sin6_addr)) { + if (SS_IS_ADDR_V4MAPPED(ss)) { + const struct sockaddr_in6 *ia6 = (const struct sockaddr_in6 *)ss; static struct sockaddr_in ia; ia.sin_family = AF_INET; @@ -546,30 +553,73 @@ normalize_ip_address(const struct sockaddr_storage *ss) return (const struct sockaddr *)ss; } +/** + * Generic/fallback MTU values + * + * These are taken from RFC 1122, RFC 2460, and RFC 5405. + * - RFC 1122, 3.3.3 defines EMTU_S ("Effective MTU for sending") and recommends + * to use an EMTU_S size of of 576 bytes if the IPv4 path MTU is unknown; + * - RFC 2460, 5. requires a minimum IPv6 MTU of 1280 bytes; + * - RFC 5405, 3.2 recommends that if path MTU discovery is not done, + * UDP senders should use the respective minimum values of EMTU_S. + */ +static inline int generic_mtu(const int af_type) +{ + return af_type == AF_INET6 ? 1280 : 576; +} + +/** Crude approximation of IP header overhead - neglecting options. */ +static inline int estimated_header_overhead(const int af_type) +{ + return af_type == AF_INET6 ? 40 : 20; +} + +/** + * Maximum transport-layer message size (MMS_S) as per RFC 1122, 3.3.3 + * Socket must be connected. + */ +int generic_max_transport_msg_size(int sockfd) +{ + struct sockaddr_storage ss; + socklen_t sslen = sizeof(ss); + int af_type = AF_INET; + + if (getpeername(sockfd, (struct sockaddr *)&ss, &sslen) < 0) { + PARA_ERROR_LOG("can not determine remote address type: %s\n", + strerror(errno)); + } else if (!SS_IS_ADDR_V4MAPPED(&ss)) { + af_type = ss.ss_family; + } + return generic_mtu(af_type) - estimated_header_overhead(af_type); +} + /** * Print numeric host and port number (beware - uses static char). * * \param sa The IPv4/IPv6 socket address to use. * + * \return Host string in numeric host:port format, \sa parse_url(). * \sa getnameinfo(3), services(5), nsswitch.conf(5) */ static char *host_and_port(const struct sockaddr_storage *ss) { const struct sockaddr *sa = normalize_ip_address(ss); char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV]; - static char output[sizeof(hbuf) + sizeof(sbuf) + 2]; + static char output[sizeof(hbuf) + sizeof(sbuf) + 4]; int ret; ret = getnameinfo(sa, salen(sa), hbuf, sizeof(hbuf), sbuf, sizeof(sbuf), - NI_NUMERICHOST); - if (ret == 0) { - snprintf(output, sizeof(output), "%s#%s", hbuf, sbuf); - } else { + NI_NUMERICHOST | NI_NUMERICSERV); + if (ret) { snprintf(output, sizeof(output), "(unknown)"); PARA_WARNING_LOG("hostname lookup error (%s).\n", gai_strerror(ret)); + } else if (sa->sa_family == AF_INET6) { + snprintf(output, sizeof(output), "[%s]:%s", hbuf, sbuf); + } else { + snprintf(output, sizeof(output), "%s:%s", hbuf, sbuf); } return output; } @@ -891,15 +941,17 @@ err: * This function creates a local socket for sequenced, reliable, two-way, * connection-based byte streams. * - * \return The file descriptor, on success, negative on errors. + * \return The file descriptor of the connected socket on success, negative on + * errors. * * \sa create_local_socket(), unix(7), connect(2). */ -int create_remote_socket(const char *name) +int connect_local_socket(const char *name) { struct sockaddr_un unix_addr; int fd, ret; + PARA_DEBUG_LOG("connecting to %s\n", name); ret = init_unix_addr(&unix_addr, name); if (ret < 0) return ret;