X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=lib%2Fsocket-util.c;h=2dff9f5924331495790e43f89e244f053fa8ecbf;hb=3efb60637b9a6741e7e5b7f04e4daa4d2464d8b3;hp=d31bc769ede67dfded099011e61f12768de25627;hpb=ed36537ebf48108accf21a8aa073279eceeafa98;p=sliver-openvswitch.git diff --git a/lib/socket-util.c b/lib/socket-util.c index d31bc769e..2dff9f592 100644 --- a/lib/socket-util.c +++ b/lib/socket-util.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc. + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,7 +17,6 @@ #include #include "socket-util.h" #include -#include #include #include #include @@ -179,30 +178,61 @@ lookup_ipv6(const char *host_name, struct in6_addr *addr) * successful, otherwise a positive errno value. * * Most Open vSwitch code should not use this because it causes deadlocks: - * gethostbyname() sends out a DNS request but that starts a new flow for which + * getaddrinfo() sends out a DNS request but that starts a new flow for which * OVS must set up a flow, but it can't because it's waiting for a DNS reply. * The synchronous lookup also delays other activity. (Of course we can solve * this but it doesn't seem worthwhile quite yet.) */ int lookup_hostname(const char *host_name, struct in_addr *addr) { - struct hostent *h; + struct addrinfo *result; + struct addrinfo hints; if (inet_aton(host_name, addr)) { return 0; } - h = gethostbyname(host_name); - if (h) { - *addr = *(struct in_addr *) h->h_addr; + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_INET; + + switch (getaddrinfo(host_name, NULL, &hints, &result)) { + case 0: + *addr = ((struct sockaddr_in *) result->ai_addr)->sin_addr; + freeaddrinfo(result); return 0; - } - return (h_errno == HOST_NOT_FOUND ? ENOENT - : h_errno == TRY_AGAIN ? EAGAIN - : h_errno == NO_RECOVERY ? EIO - : h_errno == NO_ADDRESS ? ENXIO - : EINVAL); +#ifdef EAI_ADDRFAMILY + case EAI_ADDRFAMILY: +#endif + case EAI_NONAME: + case EAI_SERVICE: + return ENOENT; + + case EAI_AGAIN: + return EAGAIN; + + case EAI_BADFLAGS: + case EAI_FAMILY: + case EAI_SOCKTYPE: + return EINVAL; + + case EAI_FAIL: + return EIO; + + case EAI_MEMORY: + return ENOMEM; + +#ifdef EAI_NODATA + case EAI_NODATA: + return ENXIO; +#endif + + case EAI_SYSTEM: + return errno; + + default: + return EPROTO; + } } int @@ -410,13 +440,8 @@ make_unix_socket(int style, bool nonblock, * it will only happen if style is SOCK_STREAM or SOCK_SEQPACKET, and only * if a backlog of un-accepted connections has built up in the kernel.) */ if (nonblock) { - int flags = fcntl(fd, F_GETFL, 0); - if (flags == -1) { - error = errno; - goto error; - } - if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) { - error = errno; + error = set_nonblocking(fd); + if (error) { goto error; } } @@ -690,6 +715,7 @@ int inet_open_passive(int style, const char *target, int default_port, struct sockaddr_in *sinp, uint8_t dscp) { + bool kernel_chooses_port; struct sockaddr_in sin; int fd = 0, error; unsigned int yes = 1; @@ -739,9 +765,10 @@ inet_open_passive(int style, const char *target, int default_port, goto error; } - if (sinp) { + kernel_chooses_port = sin.sin_port == htons(0); + if (sinp || kernel_chooses_port) { socklen_t sin_len = sizeof sin; - if (getsockname(fd, (struct sockaddr *) &sin, &sin_len) < 0){ + if (getsockname(fd, (struct sockaddr *) &sin, &sin_len) < 0) { error = errno; VLOG_ERR("%s: getsockname: %s", target, strerror(error)); goto error; @@ -751,7 +778,13 @@ inet_open_passive(int style, const char *target, int default_port, VLOG_ERR("%s: getsockname: invalid socket name", target); goto error; } - *sinp = sin; + if (sinp) { + *sinp = sin; + } + if (kernel_chooses_port) { + VLOG_INFO("%s: listening on port %"PRIu16, + target, ntohs(sin.sin_port)); + } } return fd; @@ -1101,7 +1134,7 @@ send_iovec_and_fds(int sock, const struct iovec *iovs, size_t n_iovs, const int fds[], size_t n_fds) { - assert(sock >= 0); + ovs_assert(sock >= 0); if (n_fds > 0) { union { struct cmsghdr cm; @@ -1109,8 +1142,8 @@ send_iovec_and_fds(int sock, } cmsg; struct msghdr msg; - assert(!iovec_is_empty(iovs, n_iovs)); - assert(n_fds <= SOUTIL_MAX_FDS); + ovs_assert(!iovec_is_empty(iovs, n_iovs)); + ovs_assert(n_fds <= SOUTIL_MAX_FDS); memset(&cmsg, 0, sizeof cmsg); cmsg.cm.cmsg_len = CMSG_LEN(n_fds * sizeof *fds); @@ -1120,7 +1153,7 @@ send_iovec_and_fds(int sock, msg.msg_name = NULL; msg.msg_namelen = 0; - msg.msg_iov = (struct iovec *) iovs; + msg.msg_iov = CONST_CAST(struct iovec *, iovs); msg.msg_iovlen = n_iovs; msg.msg_control = &cmsg.cm; msg.msg_controllen = CMSG_SPACE(n_fds * sizeof *fds); @@ -1285,7 +1318,7 @@ recv_data_and_fds(int sock, size_t n_fds = (p->cmsg_len - CMSG_LEN(0)) / sizeof *fds; const int *fds_data = (const int *) CMSG_DATA(p); - assert(n_fds > 0); + ovs_assert(n_fds > 0); if (n_fds > SOUTIL_MAX_FDS) { VLOG_ERR("%zu fds received but only %d supported", n_fds, SOUTIL_MAX_FDS);