// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC") // // 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. // // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY // AND FITNESS. IN NO EVENT SHALL ISC 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. #include "sockcreator.h" #include #include #include #include #include #include #include using namespace isc::util::io; namespace isc { namespace socket_creator { int get_sock(const int type, struct sockaddr *bind_addr, const socklen_t addr_len) { int sock(socket(bind_addr->sa_family, type, 0)); if (sock == -1) { return -1; } const int on(1); if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) { return -2; // This is part of the binding process, so it's a bind error } if (bind_addr->sa_family == AF_INET6 && setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) == -1) { return -2; // This is part of the binding process, so it's a bind error } if (bind(sock, bind_addr, addr_len) == -1) { return -2; } return sock; } // These are macros so they can exit the function #define READ(WHERE, HOW_MANY) do { \ size_t how_many = (HOW_MANY); \ if (read_data(input_fd, (WHERE), how_many) < how_many) { \ return 1; \ } \ } while (0) #define WRITE(WHAT, HOW_MANY) do { \ if (!write_data(output_fd, (WHAT), (HOW_MANY))) { \ return 2; \ } \ } while (0) #define DEFAULT \ default: /* Unrecognized part of protocol */ \ WRITE("FI", 2); \ return 3; int run(const int input_fd, const int output_fd, const get_sock_t get_sock, const send_fd_t send_fd) { for (;;) { // Read the command char command; READ(&command, 1); switch (command) { case 'T': // The "terminate" command return 0; case 'S': { // Create a socket // Read what type of socket they want char type[2]; READ(type, 2); // Read the address they ask for struct sockaddr *addr(NULL); size_t addr_len(0); struct sockaddr_in addr_in; struct sockaddr_in6 addr_in6; switch (type[1]) { // The address family /* * Here are some casts. They are required by C++ and * the low-level interface (they are implicit in C). */ case '4': addr = static_cast( static_cast(&addr_in)); addr_len = sizeof addr_in; memset(&addr_in, 0, sizeof addr_in); addr_in.sin_family = AF_INET; READ(static_cast(static_cast( &addr_in.sin_port)), 2); READ(static_cast(static_cast( &addr_in.sin_addr.s_addr)), 4); break; case '6': addr = static_cast( static_cast(&addr_in6)); addr_len = sizeof addr_in6; memset(&addr_in6, 0, sizeof addr_in6); addr_in6.sin6_family = AF_INET6; READ(static_cast(static_cast( &addr_in6.sin6_port)), 2); READ(static_cast(static_cast( &addr_in6.sin6_addr.s6_addr)), 16); break; DEFAULT } int sock_type; switch (type[0]) { // Translate the type case 'T': sock_type = SOCK_STREAM; break; case 'U': sock_type = SOCK_DGRAM; break; DEFAULT } int result(get_sock(sock_type, addr, addr_len)); if (result >= 0) { // We got the socket WRITE("S", 1); // FIXME: Check the output and write a test for it send_fd(output_fd, result); // Don't leak the socket close(result); } else { WRITE("E", 1); switch (result) { case -1: WRITE("S", 1); break; case -2: WRITE("B", 1); break; default: return 4; } int error(errno); WRITE(static_cast(static_cast(&error)), sizeof error); } break; } DEFAULT } } } } // End of the namespaces }