#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
-#include <sys/resource.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/uio.h>
#include "poll-loop.h"
#include "util.h"
#include "vlog.h"
-#if AF_PACKET && LINUX_DATAPATH
+#ifdef __linux__
#include <linux/if_packet.h>
#endif
#ifdef HAVE_NETLINK
/* #ifdefs make it a pain to maintain code: you have to try to build both ways.
* Thus, this file compiles all of the code regardless of the target, by
- * writing "if (LINUX_DATAPATH)" instead of "#ifdef __linux__". */
-#ifndef LINUX_DATAPATH
-#define LINUX_DATAPATH 0
+ * writing "if (LINUX)" instead of "#ifdef __linux__". */
+#ifdef __linux__
+#define LINUX 1
+#else
+#define LINUX 0
#endif
#ifndef O_DIRECTORY
* space for a null terminator. */
#define MAX_UN_LEN (sizeof(((struct sockaddr_un *) 0)->sun_path) - 1)
-#ifdef _WIN32
-/* Buffer used by sock_strerror(). */
-DEFINE_STATIC_PER_THREAD_DATA(struct { char s[128]; },
- sockerror_buffer,
- { "" });
-#endif
-
static int getsockopt_int(int fd, int level, int option, const char *optname,
int *valuep);
int
set_nonblocking(int fd)
{
+#ifndef _WIN32
int flags = fcntl(fd, F_GETFL, 0);
if (flags != -1) {
if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) != -1) {
VLOG_ERR("fcntl(F_GETFL) failed: %s", ovs_strerror(errno));
return errno;
}
+#else
+ unsigned long arg = 1;
+ if (ioctlsocket(fd, FIONBIO, &arg)) {
+ int error = sock_errno();
+ VLOG_ERR("set_nonblocking failed: %s", sock_strerror(error));
+ return error;
+ }
+ return 0;
+#endif
}
void
set_dscp(int fd, uint8_t dscp)
{
int val;
+ bool success;
if (dscp > 63) {
return EINVAL;
}
+ /* Note: this function is used for both of IPv4 and IPv6 sockets */
+ success = false;
val = dscp << 2;
if (setsockopt(fd, IPPROTO_IP, IP_TOS, &val, sizeof val)) {
- return errno;
- }
-
- return 0;
-}
-
-static bool
-rlim_is_finite(rlim_t limit)
-{
- if (limit == RLIM_INFINITY) {
- return false;
- }
-
-#ifdef RLIM_SAVED_CUR /* FreeBSD 8.0 lacks RLIM_SAVED_CUR. */
- if (limit == RLIM_SAVED_CUR) {
- return false;
- }
+#ifndef _WIN32
+ if (sock_errno() != ENOPROTOOPT) {
+#else
+ if (sock_errno() != WSAENOPROTOOPT) {
#endif
-
-#ifdef RLIM_SAVED_MAX /* FreeBSD 8.0 lacks RLIM_SAVED_MAX. */
- if (limit == RLIM_SAVED_MAX) {
- return false;
+ return sock_errno();
+ }
+ } else {
+ success = true;
}
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, &val, sizeof val)) {
+#ifndef _WIN32
+ if (sock_errno() != ENOPROTOOPT) {
+#else
+ if (sock_errno() != WSAENOPROTOOPT) {
#endif
-
- return true;
-}
-
-/* Returns the maximum valid FD value, plus 1. */
-int
-get_max_fds(void)
-{
- static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;
- static int max_fds;
-
- if (ovsthread_once_start(&once)) {
- struct rlimit r;
- if (!getrlimit(RLIMIT_NOFILE, &r) && rlim_is_finite(r.rlim_cur)) {
- max_fds = r.rlim_cur;
- } else {
- VLOG_WARN("failed to obtain fd limit, defaulting to 1024");
- max_fds = 1024;
+ return sock_errno();
}
- ovsthread_once_done(&once);
+ } else {
+ success = true;
+ }
+ if (!success) {
+ return ENOPROTOOPT;
}
- return max_fds;
+ return 0;
}
/* Translates 'host_name', which must be a string representation of an IP
int
lookup_ip(const char *host_name, struct in_addr *addr)
{
- if (!inet_aton(host_name, addr)) {
+ if (!inet_pton(AF_INET, host_name, addr)) {
static 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;
struct addrinfo *result;
struct addrinfo hints;
- if (inet_aton(host_name, addr)) {
+ if (inet_pton(AF_INET, host_name, addr)) {
return 0;
}
case EAI_MEMORY:
return ENOMEM;
-#ifdef EAI_NODATA
+#if defined (EAI_NODATA) && EAI_NODATA != EAI_NONAME
case EAI_NODATA:
return ENXIO;
#endif
+#ifdef EAI_SYSTEM
case EAI_SYSTEM:
- return errno;
+ return sock_errno();
+#endif
default:
return EPROTO;
pfd.fd = fd;
pfd.events = POLLOUT;
+
+#ifndef _WIN32
do {
retval = poll(&pfd, 1, 0);
} while (retval < 0 && errno == EINTR);
+#else
+ retval = WSAPoll(&pfd, 1, 0);
+#endif
if (retval == 1) {
if (pfd.revents & POLLERR) {
- ssize_t n = send(fd, "", 1, MSG_DONTWAIT);
+ ssize_t n = send(fd, "", 1, 0);
if (n < 0) {
- return errno;
+ return sock_errno();
} else {
VLOG_ERR_RL(&rl, "poll return POLLERR but send succeeded");
return EPROTO;
}
return 0;
} else if (retval < 0) {
- VLOG_ERR_RL(&rl, "poll: %s", ovs_strerror(errno));
+ VLOG_ERR_RL(&rl, "poll: %s", sock_strerror(sock_errno()));
return errno;
} else {
return EAGAIN;
}
}
+#ifndef _WIN32
/* Drain all the data currently in the receive queue of a datagram socket (and
* possibly additional data). There is no way to know how many packets are in
* the receive queue, but we do know that the total number of bytes queued does
*
* On other Unix-like OSes, MSG_TRUNC has no effect in the flags
* argument. */
- char buffer[LINUX_DATAPATH ? 1 : 2048];
+ char buffer[LINUX ? 1 : 2048];
ssize_t n_bytes = recv(fd, buffer, sizeof buffer,
MSG_TRUNC | MSG_DONTWAIT);
if (n_bytes <= 0 || n_bytes >= rcvbuf) {
}
return 0;
}
+#endif
/* Returns the size of socket 'sock''s receive buffer (SO_RCVBUF), or a
* negative errno value if an error occurs. */
}
}
+#ifndef _WIN32
/* Attempts to shorten 'name' by opening a file descriptor for the directory
* part of the name and indirecting through /proc/self/fd/<dirfd>/<basename>.
* On systems with Linux-like /proc, this works as long as <basename> isn't too
int dirfd;
int len;
- if (!LINUX_DATAPATH) {
+ if (!LINUX) {
return ENAMETOOLONG;
}
? sun_len - offsetof(struct sockaddr_un, sun_path)
: 0);
}
+#endif /* _WIN32 */
ovs_be32
guess_netmask(ovs_be32 ip_)
/* Create non-blocking socket. */
fd = socket(ss.ss_family, style, 0);
if (fd < 0) {
- VLOG_ERR("%s: socket: %s", target, ovs_strerror(errno));
- error = errno;
+ error = sock_errno();
+ VLOG_ERR("%s: socket: %s", target, sock_strerror(error));
goto exit;
}
error = set_nonblocking(fd);
* connect(), the handshake SYN frames will be sent with a TOS of 0. */
error = set_dscp(fd, dscp);
if (error) {
- VLOG_ERR("%s: socket: %s", target, ovs_strerror(error));
+ VLOG_ERR("%s: set_dscp: %s", target, sock_strerror(error));
goto exit;
}
/* Connect. */
error = connect(fd, (struct sockaddr *) &ss, ss_length(&ss)) == 0
? 0
- : errno;
- if (error == EINPROGRESS) {
+ : sock_errno();
+ if (error == EINPROGRESS
+#ifdef _WIN32
+ || error == WSAEALREADY || error == WSAEWOULDBLOCK
+#endif
+ ) {
error = EAGAIN;
}
memset(ssp, 0, sizeof *ssp);
}
if (fd >= 0) {
- close(fd);
+ closesocket(fd);
fd = -1;
}
} else {
/* Create non-blocking socket, set SO_REUSEADDR. */
fd = socket(ss.ss_family, style, 0);
if (fd < 0) {
- error = errno;
- VLOG_ERR("%s: socket: %s", target, ovs_strerror(error));
+ error = sock_errno();
+ VLOG_ERR("%s: socket: %s", target, sock_strerror(error));
return -error;
}
error = set_nonblocking(fd);
}
if (style == SOCK_STREAM
&& setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes) < 0) {
- error = errno;
+ error = sock_errno();
VLOG_ERR("%s: setsockopt(SO_REUSEADDR): %s",
- target, ovs_strerror(error));
+ target, sock_strerror(error));
goto error;
}
/* Bind. */
if (bind(fd, (struct sockaddr *) &ss, ss_length(&ss)) < 0) {
- error = errno;
- VLOG_ERR("%s: bind: %s", target, ovs_strerror(error));
+ error = sock_errno();
+ VLOG_ERR("%s: bind: %s", target, sock_strerror(error));
goto error;
}
* connect(), the handshake SYN frames will be sent with a TOS of 0. */
error = set_dscp(fd, dscp);
if (error) {
- VLOG_ERR("%s: socket: %s", target, ovs_strerror(error));
+ VLOG_ERR("%s: set_dscp: %s", target, sock_strerror(error));
goto error;
}
/* Listen. */
if (style == SOCK_STREAM && listen(fd, 10) < 0) {
- error = errno;
- VLOG_ERR("%s: listen: %s", target, ovs_strerror(error));
+ error = sock_errno();
+ VLOG_ERR("%s: listen: %s", target, sock_strerror(error));
goto error;
}
if (ssp || kernel_chooses_port) {
socklen_t ss_len = sizeof ss;
if (getsockname(fd, (struct sockaddr *) &ss, &ss_len) < 0) {
- error = errno;
- VLOG_ERR("%s: getsockname: %s", target, ovs_strerror(error));
+ error = sock_errno();
+ VLOG_ERR("%s: getsockname: %s", target, sock_strerror(error));
goto error;
}
if (kernel_chooses_port) {
if (ssp) {
memset(ssp, 0, sizeof *ssp);
}
- close(fd);
+ closesocket(fd);
return -error;
}
-/* 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 struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;
- static int null_fd;
-
- if (ovsthread_once_start(&once)) {
- null_fd = open("/dev/null", O_RDWR);
- if (null_fd < 0) {
- int error = errno;
- VLOG_ERR("could not open /dev/null: %s", ovs_strerror(error));
- null_fd = -error;
- }
- ovsthread_once_done(&once);
- }
-
- return null_fd;
-}
-
int
read_fully(int fd, void *p_, size_t size, size_t *bytes_read)
{
fsync_parent_dir(const char *file_name)
{
int error = 0;
+#ifndef _WIN32
char *dir;
int fd;
VLOG_ERR("%s: open failed (%s)", dir, ovs_strerror(error));
}
free(dir);
+#endif
return error;
}
}
}
+#ifndef _WIN32
void
xpipe(int fds[2])
{
xset_nonblocking(fds[0]);
xset_nonblocking(fds[1]);
}
+#endif
static int
getsockopt_int(int fd, int level, int option, const char *optname, int *valuep)
len = sizeof value;
if (getsockopt(fd, level, option, &value, &len)) {
- error = errno;
- VLOG_ERR_RL(&rl, "getsockopt(%s): %s", optname, ovs_strerror(error));
+ error = sock_errno();
+ VLOG_ERR_RL(&rl, "getsockopt(%s): %s", optname, sock_strerror(error));
} else if (len != sizeof value) {
error = EINVAL;
VLOG_ERR_RL(&rl, "getsockopt(%s): value is %u bytes (expected %"PRIuSIZE")",
ds_put_format(string, "%s:%"PRIu16,
ss_format_address(&ss, addrbuf, sizeof addrbuf),
ss_get_port(&ss));
+#ifndef _WIN32
} else if (ss.ss_family == AF_UNIX) {
struct sockaddr_un sun;
const char *null;
null = memchr(sun.sun_path, '\0', maxlen);
ds_put_buffer(string, sun.sun_path,
null ? null - sun.sun_path : maxlen);
+#endif
}
#ifdef HAVE_NETLINK
else if (ss.ss_family == AF_NETLINK) {
}
}
#endif
-#if AF_PACKET && LINUX_DATAPATH
+#if __linux__
else if (ss.ss_family == AF_PACKET) {
struct sockaddr_ll sll;
}
-#ifdef LINUX_DATAPATH
+#ifdef __linux__
static void
put_fd_filename(struct ds *string, int fd)
{
struct stat s;
ds_init(&string);
+#ifndef _WIN32
if (fstat(fd, &s)) {
ds_put_format(&string, "fstat failed (%s)", ovs_strerror(errno));
} else if (S_ISSOCK(s.st_mode)) {
: S_ISFIFO(s.st_mode) ? "FIFO"
: S_ISLNK(s.st_mode) ? "symbolic link"
: "unknown"));
-#ifdef LINUX_DATAPATH
+#ifdef __linux__
put_fd_filename(&string, fd);
#endif
}
+#else
+ ds_put_format(&string,"file descriptor");
+#endif /* _WIN32 */
return ds_steal_cstr(&string);
}
+#ifndef _WIN32
/* Calls ioctl() on an AF_INET sock, passing the specified 'command' and
* 'arg'. Returns 0 if successful, otherwise a positive errno value. */
int
if (ovsthread_once_start(&once)) {
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0) {
- sock = -errno;
- VLOG_ERR("failed to create inet socket: %s", ovs_strerror(errno));
+ int error = sock_errno();
+ VLOG_ERR("failed to create inet socket: %s", sock_strerror(error));
+ sock = -error;
}
ovsthread_once_done(&once);
}
}
return error;
}
+#endif
\f
/* sockaddr_storage helpers. */
/* For Windows socket calls, 'errno' is not set. One has to call
* WSAGetLastError() to get the error number and then pass it to
- * FormatMessage() (through this function) to get the correct error string.
-
+ * this function to get the correct error string.
+ *
* ovs_strerror() calls strerror_r() and would not get the correct error
* string for Windows sockets, but is good for POSIX. */
const char *
sock_strerror(int error)
{
#ifdef _WIN32
- enum { BUFSIZE = sizeof sockerror_buffer_get()->s };
- char *buffer = sockerror_buffer_get()->s;
-
- FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
- | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, error, 0,
- buffer, BUFSIZE, NULL);
- return buffer;
+ return ovs_format_message(error);
#else
return ovs_strerror(error);
#endif