Permalink
Browse files

added util for manipulating file descriptors

  • Loading branch information...
Neverlord committed Aug 21, 2012
1 parent b2a8327 commit e0ba4709eb08daa3dca7e40e2816aa55592e3f79
Showing with 195 additions and 0 deletions.
  1. +75 −0 cppa/detail/fd_util.hpp
  2. +120 −0 src/fd_util.cpp
View
@@ -0,0 +1,75 @@
+/******************************************************************************\
+ * ___ __ *
+ * /\_ \ __/\ \ *
+ * \//\ \ /\_\ \ \____ ___ _____ _____ __ *
+ * \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
+ * \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ *
+ * /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ *
+ * \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ *
+ * \ \_\ \ \_\ *
+ * \/_/ \/_/ *
+ * *
+ * Copyright (C) 2011, 2012 *
+ * Dominik Charousset <dominik.charousset@haw-hamburg.de> *
+ * *
+ * This file is part of libcppa. *
+ * libcppa is free software: you can redistribute it and/or modify it under *
+ * the terms of the GNU Lesser General Public License as published by the *
+ * Free Software Foundation, either version 3 of the License *
+ * or (at your option) any later version. *
+ * *
+ * libcppa is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
+ * See the GNU Lesser General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser General Public License *
+ * along with libcppa. If not, see <http://www.gnu.org/licenses/>. *
+\******************************************************************************/
+
+
+#ifndef FD_UTIL_HPP
+#define FD_UTIL_HPP
+
+#include <unistd.h>
+#include "cppa/config.hpp"
+
+namespace cppa { namespace detail { namespace fd_util {
+
+#if defined(CPPA_MACOS) || defined(CPPA_LINUX)
+
+typedef int file_descriptor;
+
+// throws ios_base::failure and adds errno failure if @p add_errno_failure
+void throw_io_failure(std::string&& what, bool add_errno_failure = true);
+
+// returns true if fd is nonblocking
+// throws @p ios_base::failure on error
+bool nonblocking(file_descriptor fd);
+
+// sets fd to nonblocking if <tt>set_nonblocking == true</tt>
+// or to blocking if <tt>set_nonblocking == false</tt>
+// throws @p ios_base::failure on error
+void nonblocking(file_descriptor fd, bool new_value);
+
+// returns true if fd is nodelay socket
+// throws @p ios_base::failure on error
+bool tcp_nodelay(native_socket_type fd);
+
+// returns true if fd is nodelay socket
+// throws @p ios_base::failure on error
+void tcp_nodelay(native_socket_type fd, bool new_value);
+
+// reads @p result and @p errno and throws @p ios_base::failure on error
+void handle_write_result(ssize_t result, bool is_nonblocking_io);
+
+// reads @p result and @p errno and throws @p ios_base::failure on error
+void handle_read_result(ssize_t result, bool is_nonblocking_io);
+
+#else
+
+#endif
+
+} } } // namespace cppa::detail::fd_util
+
+#endif // FD_UTIL_HPP
View
@@ -0,0 +1,120 @@
+/******************************************************************************\
+ * ___ __ *
+ * /\_ \ __/\ \ *
+ * \//\ \ /\_\ \ \____ ___ _____ _____ __ *
+ * \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
+ * \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ *
+ * /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ *
+ * \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ *
+ * \ \_\ \ \_\ *
+ * \/_/ \/_/ *
+ * *
+ * Copyright (C) 2011, 2012 *
+ * Dominik Charousset <dominik.charousset@haw-hamburg.de> *
+ * *
+ * This file is part of libcppa. *
+ * libcppa is free software: you can redistribute it and/or modify it under *
+ * the terms of the GNU Lesser General Public License as published by the *
+ * Free Software Foundation, either version 3 of the License *
+ * or (at your option) any later version. *
+ * *
+ * libcppa is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
+ * See the GNU Lesser General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser General Public License *
+ * along with libcppa. If not, see <http://www.gnu.org/licenses/>. *
+\******************************************************************************/
+
+
+#include <ios>
+#include "cppa/exception.hpp"
+#include "cppa/detail/fd_util.hpp"
+
+#if defined(CPPA_LINUX) || defined(CPPA_MACOS)
+
+#include <errno.h>
+#include <netdb.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <fcntl.h>
+
+namespace cppa { namespace detail { namespace fd_util {
+
+void throw_io_failure(std::string&& what, bool add_errno_failure) {
+ if (add_errno_failure) {
+ std::string tmp(std::move(what));
+ tmp += ": ";
+ tmp += strerror(errno);
+ tmp += " [errno: ";
+ tmp += std::to_string(errno);
+ tmp += "]";
+ throw std::ios_base::failure(std::move(tmp));
+ }
+ throw std::ios_base::failure(std::move(what));
+}
+
+int rd_flags(file_descriptor fd) {
+ auto flags = fcntl(fd, F_GETFL, 0);
+ if (flags == -1) {
+ throw_io_failure("unable to read socket flags");
+ }
+ return flags;
+}
+
+bool nonblocking(file_descriptor fd) {
+ return (rd_flags(fd) & O_NONBLOCK) != 0;
+}
+
+void nonblocking(file_descriptor fd, bool new_value) {
+ auto rf = rd_flags(fd);
+ auto wf = new_value ? (rf | O_NONBLOCK) : (rf & (~(O_NONBLOCK)));
+ if (fcntl(fd, F_SETFL, wf) < 0) {
+ throw_io_failure("unable to set file descriptor flags");
+ }
+}
+
+bool tcp_nodelay(native_socket_type fd) {
+ int flag;
+ auto len = static_cast<socklen_t>(sizeof(flag));
+ if (getsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &flag, &len) < 0) {
+ throw_io_failure("unable to read TCP_NODELAY socket option");
+ }
+ return flag != 0;
+}
+
+void tcp_nodelay(native_socket_type fd, bool new_value) {
+ int flag = new_value ? 1 : 0;
+ if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(flag)) < 0) {
+ throw_io_failure("unable to set TCP_NODELAY");
+ }
+}
+
+void handle_write_result(ssize_t result, bool is_nonblocking_io) {
+ if (result < 0) {
+ if (is_nonblocking_io) {
+ if (errno == EAGAIN || errno == EWOULDBLOCK) {
+ return; // don't throw, just try again
+ }
+ }
+ throw_io_failure(strerror(errno));
+ }
+}
+
+void handle_read_result(ssize_t result, bool is_nonblocking_io) {
+ handle_write_result(result, is_nonblocking_io);
+ if (result == 0) {
+ throw_io_failure("cannot read from closed socket / file handle");
+ }
+}
+
+} } } // namespace cppa::detail::fd_util
+
+#else
+
+#endif

0 comments on commit e0ba470

Please sign in to comment.