X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=lib%2Fsocket-util.c;h=7c1975061ff01d8fd7703c726c07e69bcd5514f6;hb=67a4917b07031b387beafaedce413b4207214059;hp=fdd8e95aeea3b4a4c889d0eed555d2193479b319;hpb=78ff02708b11df94ac2cdf6fe82dc922758c7e30;p=sliver-openvswitch.git diff --git a/lib/socket-util.c b/lib/socket-util.c index fdd8e95ae..7c1975061 100644 --- a/lib/socket-util.c +++ b/lib/socket-util.c @@ -1,17 +1,17 @@ /* - * Copyright (c) 2008, 2009 Nicira Networks. + * Copyright (c) 2008, 2009, 2010 Nicira Networks. * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #include @@ -73,25 +73,16 @@ get_max_fds(void) return max_fds; } -/* Translates 'host_name', which may be a DNS name or an IP address, into a - * numeric IP address in '*addr'. Returns 0 if successful, otherwise a - * positive errno value. */ +/* Translates 'host_name', which must be a string representation of an IP + * address, into a numeric IP address in '*addr'. Returns 0 if successful, + * otherwise a positive errno value. */ int lookup_ip(const char *host_name, struct in_addr *addr) { if (!inet_aton(host_name, addr)) { - struct hostent *he = gethostbyname(host_name); - if (he == NULL) { - struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); - VLOG_ERR_RL(&rl, "gethostbyname(%s): %s", host_name, - (h_errno == HOST_NOT_FOUND ? "host not found" - : h_errno == TRY_AGAIN ? "try again" - : h_errno == NO_RECOVERY ? "non-recoverable error" - : h_errno == NO_ADDRESS ? "no address" - : "unknown error")); - return ENOENT; - } - addr->s_addr = *(uint32_t *) he->h_addr; + struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); + VLOG_ERR_RL(&rl, "\"%s\" is not a valid IP address", host_name); + return ENOENT; } return 0; } @@ -213,7 +204,7 @@ make_sockaddr_un(const char *name, struct sockaddr_un* un, socklen_t *un_len) * * Returns the socket's fd if successful, otherwise a negative errno value. */ int -make_unix_socket(int style, bool nonblock, bool passcred UNUSED, +make_unix_socket(int style, bool nonblock, bool passcred OVS_UNUSED, const char *bind_path, const char *connect_path) { int error; @@ -300,9 +291,12 @@ guess_netmask(uint32_t ip) : htonl(0)); /* ??? */ } -/* Opens a non-blocking TCP socket and connects to 'target', which should be a - * string in the format "[:]", where is required and - * is optional, with 'default_port' assumed if is omitted. +/* Opens a non-blocking IPv4 socket of the specified 'style' and connects to + * 'target', which should be a string in the format "[:]". + * is required. If 'default_port' is nonzero then is optional and + * defaults to 'default_port'. + * + * 'style' should be SOCK_STREAM (for TCP) or SOCK_DGRAM (for UDP). * * On success, returns 0 (indicating connection complete) or EAGAIN (indicating * connection in progress), in which case the new file descriptor is stored @@ -312,8 +306,8 @@ guess_netmask(uint32_t ip) * If 'sinp' is non-null, then on success the target address is stored into * '*sinp'. */ int -tcp_open_active(const char *target_, uint16_t default_port, - struct sockaddr_in *sinp, int *fdp) +inet_open_active(int style, const char *target_, uint16_t default_port, + struct sockaddr_in *sinp, int *fdp) { char *target = xstrdup(target_); char *save_ptr = NULL; @@ -344,10 +338,14 @@ tcp_open_active(const char *target_, uint16_t default_port, } if (port_string && atoi(port_string)) { sin.sin_port = htons(atoi(port_string)); + } else if (!default_port) { + VLOG_ERR("%s: port number must be specified", target_); + error = EAFNOSUPPORT; + goto exit; } /* Create non-blocking socket. */ - fd = socket(AF_INET, SOCK_STREAM, 0); + fd = socket(AF_INET, style, 0); if (fd < 0) { VLOG_ERR("%s: socket: %s", target_, strerror(errno)); error = errno; @@ -384,18 +382,20 @@ exit: return error; } -/* Opens a non-blocking TCP socket, binds to 'target', and listens for incoming - * connections. 'target' should be a string in the format "[][:]", - * where both and are optional. If is omitted, it defaults - * to 'default_port'; if is omitted it defaults to the wildcard IP - * address. +/* Opens a non-blocking IPv4 socket of the specified 'style', binds to + * 'target', and listens for incoming connections. 'target' should be a string + * in the format "[][:]". may be omitted if 'default_port' is + * nonzero, in which case it defaults to 'default_port'. If is omitted it + * defaults to the wildcard IP address. * - * The socket will have SO_REUSEADDR turned on. + * 'style' should be SOCK_STREAM (for TCP) or SOCK_DGRAM (for UDP). + * + * For TCP, the socket will have SO_REUSEADDR turned on. * * On success, returns a non-negative file descriptor. On failure, returns a * negative errno value. */ int -tcp_open_passive(const char *target_, uint16_t default_port) +inet_open_passive(int style, const char *target_, uint16_t default_port) { char *target = xstrdup(target_); char *string_ptr = target; @@ -415,6 +415,10 @@ tcp_open_passive(const char *target_, uint16_t default_port) port_string = strsep(&string_ptr, ":"); if (port_string && atoi(port_string)) { sin.sin_port = htons(atoi(port_string)); + } else if (!default_port) { + VLOG_ERR("%s: port number must be specified", target_); + error = EAFNOSUPPORT; + goto exit; } /* Parse optional bind IP. */ @@ -427,7 +431,7 @@ tcp_open_passive(const char *target_, uint16_t default_port) } /* Create non-blocking socket, set SO_REUSEADDR. */ - fd = socket(AF_INET, SOCK_STREAM, 0); + fd = socket(AF_INET, style, 0); if (fd < 0) { error = errno; VLOG_ERR("%s: socket: %s", target_, strerror(error)); @@ -437,7 +441,8 @@ tcp_open_passive(const char *target_, uint16_t default_port) if (error) { goto exit_close; } - if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes) < 0) { + if (style == SOCK_STREAM + && setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes) < 0) { error = errno; VLOG_ERR("%s: setsockopt(SO_REUSEADDR): %s", target_, strerror(error)); goto exit_close; @@ -466,6 +471,24 @@ exit: return error ? -error : fd; } +/* Returns a readable and writable fd for /dev/null, if successful, otherwise + * a negative errno value. The caller must not close the returned fd (because + * the same fd will be handed out to subsequent callers). */ +int +get_null_fd(void) +{ + static int null_fd = -1; + if (null_fd < 0) { + null_fd = open("/dev/null", O_RDWR); + if (null_fd < 0) { + int error = errno; + VLOG_ERR("could not open /dev/null: %s", strerror(error)); + return -error; + } + } + return null_fd; +} + int read_fully(int fd, void *p_, size_t size, size_t *bytes_read) {