123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161 |
- // 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 <util/io/fd.h>
- #include <unistd.h>
- #include <cerrno>
- #include <string.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- 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<struct sockaddr *>(
- static_cast<void *>(&addr_in));
- addr_len = sizeof addr_in;
- memset(&addr_in, 0, sizeof addr_in);
- addr_in.sin_family = AF_INET;
- READ(static_cast<char *>(static_cast<void *>(
- &addr_in.sin_port)), 2);
- READ(static_cast<char *>(static_cast<void *>(
- &addr_in.sin_addr.s_addr)), 4);
- break;
- case '6':
- addr = static_cast<struct sockaddr *>(
- static_cast<void *>(&addr_in6));
- addr_len = sizeof addr_in6;
- memset(&addr_in6, 0, sizeof addr_in6);
- addr_in6.sin6_family = AF_INET6;
- READ(static_cast<char *>(static_cast<void *>(
- &addr_in6.sin6_port)), 2);
- READ(static_cast<char *>(static_cast<void *>(
- &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<char *>(static_cast<void *>(&error)),
- sizeof error);
- }
- break;
- }
- DEFAULT
- }
- }
- }
- } // End of the namespaces
- }
|