diff --git a/Makefile.am b/Makefile.am index c92b79e9..20c12607 100644 --- a/Makefile.am +++ b/Makefile.am @@ -64,6 +64,14 @@ UTIL_FILES = \ matrix.hpp \ memory.cpp \ memory.hpp \ + net/address.cpp \ + net/address.hpp \ + net/except.cpp \ + net/except.hpp \ + net/types.cpp \ + net/types.hpp \ + net/socket.cpp \ + net/socket.hpp \ nocopy.hpp \ noise.cpp \ noise.hpp \ diff --git a/net/address.cpp b/net/address.cpp new file mode 100644 index 00000000..67f644c6 --- /dev/null +++ b/net/address.cpp @@ -0,0 +1,139 @@ +/* + * This file is part of libgim. + * + * libgim is free software: you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later + * version. + * + * libgim 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 General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with libgim. If not, see . + * + * Copyright 2011 Danny Robson + */ + +#include "address.hpp" + +#include "except.hpp" +#include "../debug.hpp" +#include "../endian.hpp" +#include "../types.hpp" + +#ifdef __WIN32 +#else + #include +#endif + +//----------------------------------------------------------------------------- +using namespace net; +using namespace std; + + +//----------------------------------------------------------------------------- +#ifdef __WIN32 +const char* inet_ntop(int af, const void* src, char* dst, int size){ + struct sockaddr_in srcaddr; + memset(&srcaddr, 0, sizeof(struct sockaddr_in)); + memcpy(&(srcaddr.sin_addr), src, sizeof(srcaddr.sin_addr)); + srcaddr.sin_family = af; + + if (WSAAddressToString ((struct sockaddr*) &srcaddr, sizeof (struct sockaddr_in), 0, dst, (LPDWORD) &size) != 0) + net::error::throw_code (); + + return dst; +} +#endif + + +//----------------------------------------------------------------------------- +namespace net { + template <> + address::address (const sockaddr_type &addr): + m_ip (addr.sin_addr.s_addr), + m_mask (0), + m_port (ntoh (addr.sin_port)) + { + CHECK (addr.sin_family == (int)domain::INET); + } + + + template + address::address (const std::string &_ip, + port_type _port): + m_ip (_ip), + m_mask ( 0), + m_port (_port) + { ; } + + + template <> + address::sockaddr_type + address::to_sockaddr (void) const { + sockaddr_type addr; + + addr.sin_family = (int)domain::INET; + addr.sin_port = hton (m_port); + addr.sin_addr.s_addr = m_ip.m_integer; + + return addr; + } + + + template <> + std::string + address::to_string (void) const { + char dest[INET_ADDRSTRLEN + 1]; + sockaddr_type addr = to_sockaddr (); + + if (NULL == inet_ntop ((int)domain::INET, &addr.sin_addr, dest, sizeof (dest))) + net::error::throw_code (); + return dest; + } + + + template <> + bool + address::operator ==(const address &rhs) { + return m_ip == rhs.m_ip && + m_mask == rhs.m_mask && + m_port == rhs.m_port; + } +} + + +//----------------------------------------------------------------------------- +std::ostream& +net::operator<< (std::ostream &os, const address &addr) { + os << addr.to_string () << ":" << addr.port (); + return os; +} + + +//----------------------------------------------------------------------------- +template <> +const address +address::LOOPBACK ("127.0.0.1", 0); + + +template <> +const address +address::ANY ("0.0.0.0", 0); + + +template <> +const address +address::LOOPBACK ("::1", 0); + + +template <> +const address +address::ANY ("::0", 0); + +template class address; +template class address; + diff --git a/net/address.hpp b/net/address.hpp new file mode 100644 index 00000000..0cd4569c --- /dev/null +++ b/net/address.hpp @@ -0,0 +1,109 @@ +/* + * This file is part of libgim. + * + * libgim is free software: you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later + * version. + * + * libgim 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 General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with libgim. If not, see . + * + * Copyright 2011 Danny Robson + */ + +#ifndef __NET_ADDRESS_HPP +#define __NET_ADDRESS_HPP + +#include "types.hpp" +#include "../ip.hpp" + +#if defined(HAVE_WINSOCK2_H) + #include "ws2tcpip.h" +#endif + +#include +#include + + +//----------------------------------------------------------------------------- +namespace net { + /// Supporting types used for defining addresses in various domains + template + struct address_types; + + + template <> + struct address_types { + typedef ipv4::ip ip; + typedef ipv4::mask mask; + typedef ipv4::port port; + typedef sockaddr_in sockaddr; + }; + + + template <> + struct address_types { + typedef ipv6::ip ip; + typedef ipv6::mask mask; + typedef ipv6::port port; + typedef sockaddr_in6 sockaddr; + }; + + + /// A full endpoint specification for a domain. Must be usable for bind/listen and send/recv. + template + class address { + public: + typedef typename address_types::ip ip_type; + typedef typename address_types::mask mask_type; + typedef typename address_types::port port_type; + typedef typename address_types::sockaddr sockaddr_type; + + protected: + ip_type m_ip; + mask_type m_mask; + port_type m_port; + + public: + static const address LOOPBACK; + static const address ANY; + + address (const sockaddr_type &); + address (const std::string&, + port_type); + + port_type + port (void) const + { return m_port; } + + void + set_port (const port_type &_port) + { m_port = _port; } + + ip_type + ip (void) const + { return m_ip; } + + sockaddr_type + to_sockaddr (void) const; + + std::string + to_string (void) const; + + bool operator ==(const address &rhs); + }; + + std::ostream& + operator<< (std::ostream &os, const net::address &addr); +} + + + +#endif // __NET_ADDRESS_HPP + diff --git a/net/except.cpp b/net/except.cpp new file mode 100644 index 00000000..398389d2 --- /dev/null +++ b/net/except.cpp @@ -0,0 +1,119 @@ +/* + * This file is part of libgim. + * + * libgim is free software: you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later + * version. + * + * libgim 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 General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with libgim. If not, see . + * + * Copyright 2011 Danny Robson + */ + +#include "except.hpp" + +#include "../debug.hpp" + + +//----------------------------------------------------------------------------- +using namespace std; +using namespace net; + + +//----------------------------------------------------------------------------- +net::error::error (const std::string &_what): + runtime_error (_what) +{ ; } + + +net::error::error (int _code): + runtime_error (strerror (_code)) +{ CHECK (_code != 0); } + + +std::string +net::error::code_to_string (int code) { +#ifdef __WIN32 + char message[256]; + int output = FormatMessage (0, NULL, code, 0, message, sizeof (message), NULL); + CHECK_HARD (output != 0); + + return std::string (message); +#else + return strerror (code); +#endif +} + + +void +net::error::throw_code (int code) { +#ifdef __WIN32 + throw net::error (code); +#else + + CHECK (code != 0); + switch (code) { +#define ERROR_CODE(c) \ + case c: \ + throw net::error_code (); \ + break; + + ERROR_CODE(ECONNREFUSED); + ERROR_CODE(ECONNRESET); + ERROR_CODE(EINVAL); + ERROR_CODE(ENOTCONN); + + default: + unreachable (); +#undef ERROR_CODE + } +#endif +} + + +void +net::error::try_code (int err) { + if (err == 0) + return; + + throw_code (err); +} + + +void +net::error::try_code (void) + { try_code (last_code ()); } + + +void +net::error::throw_code (void) + { throw_code (last_code ()); } + + +int +net::error::last_code (void) { +#ifdef __WIN32 + return WSAGetLastError (); +#else + return errno; +#endif +} + + +template +net::error_code::error_code (void): + net::error (CODE) +{ ; } + + +template +int +net::error_code::code (void) const + { return CODE; } diff --git a/net/except.hpp b/net/except.hpp new file mode 100644 index 00000000..a5bafcaf --- /dev/null +++ b/net/except.hpp @@ -0,0 +1,79 @@ +/* + * This file is part of libgim. + * + * libgim is free software: you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later + * version. + * + * libgim 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 General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with libgim. If not, see . + * + * Copyright 2011 Danny Robson + */ + +#ifndef __NET_EXCEPT_HPP +#define __NET_EXCEPT_HPP + +#if defined(HAVE_WINSOCK2_H) + #include +#else + #include + #include +#endif + +#include +#include + +#include "../annotations.hpp" + + +//----------------------------------------------------------------------------- +namespace net { + class error : public std::runtime_error { + protected: + error (const std::string &); + error (int code); + + static std::string + code_to_string (int code); + + public: + /// Throw an error corresponding the a given code. Code must be a valid error code, + /// not success otherwise the application will (at best) abort. + static void + throw_code (int code) terminal; + + /// Throw an error corresponding to the most recent error condition. This will check + /// the current error condition in a platform agnostic manner, and pass on to + /// throw_code(int). This should be used whenever an error has been detected, rather + /// than the more normal try_code(errno) due to Windows error reporting quirks. + static void + throw_code (void) terminal; + + static void + try_code (int code); + + static void + try_code (void); + + static int + last_code (void); + }; + + + template + class error_code : public error { + public: + error_code (); + + int code (void) const; + }; +} + +#endif // __NET_EXCEPT_HPP diff --git a/net/socket.cpp b/net/socket.cpp new file mode 100644 index 00000000..f9982f7b --- /dev/null +++ b/net/socket.cpp @@ -0,0 +1,297 @@ +/* + * This file is part of libgim. + * + * libgim is free software: you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later + * version. + * + * libgim 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 General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with libgim. If not, see . + * + * Copyright 2011 Danny Robson + */ + +#include "socket.hpp" + +#include "../debug.hpp" +#include "../except.hpp" +#include "../types/casts.hpp" +#include "../log.hpp" +#include "except.hpp" + +#if !defined(HAVE_WINSOCK2_H) + #include +#endif + +#include +#include + +using namespace net; + +//----------------------------------------------------------------------------- +template +socket_domain::socket_domain (socket_t _fd): + m_fd (_fd) +{ +#ifdef __WIN32 +#else + CHECK_HARD (m_fd >= 0); +#endif +} + + +#if defined(HAVE_WINSOCK2_H) + // TODO: Make this not retarded. Fucking Windows. + #define dup(X) (X) + + static_assert(sizeof(int) == sizeof(ssize_t), "int != ssize_t"); + static_assert(sizeof(int) == sizeof( size_t), "int != size_t"); + + ssize_t recv(socket_t _socket, void *_buf, size_t _len, int _flags) + { return (ssize_t)::recv(_socket, (char*)_buf, (int)_len, _flags); } + + ssize_t recvfrom(socket_t _socket, void *_buf, size_t _len, int _flags, struct sockaddr *_sockaddr, socklen_t *_socklen) + { return (ssize_t)::recvfrom(_socket, (char*)_buf, (int)_len, _flags, _sockaddr, (int*)_socklen); } + + ssize_t sendto(socket_t _socket, const void *_buf, size_t _len, int _flags, const struct sockaddr *_sockaddr, socklen_t _socklen) + { return (ssize_t)::sendto(_socket, (const char*)_buf, (int)_len, _flags, _sockaddr, (int)_socklen); } + + ssize_t send(socket_t _socket, const void *_buf, size_t _len, int _flags) + { return (ssize_t)::send(_socket, (const char*)_buf, (int)_len, _flags); } +#else + #define closesocket(X) close(X) +#endif + + +template +socket_domain::socket_domain (const socket_domain &rhs): + m_fd (dup (rhs.m_fd)) +{ ; } + + +template +socket_domain::~socket_domain () { + if (closesocket (m_fd) < 0) { + LOG_DEBUG ("closesocket: %s", strerror (errno)); + } +} + + +template +socket_t +socket_domain::native (void) const + { return m_fd; } + + +template +void +socket_domain::shutdown (void) { +#if defined(HAVE_WINSOCK2_H) + #define SHUT_SEND SD_SEND + #define SHUT_RECV SD_RECEIVE + #define SHUT_RDWR SD_BOTH +#endif + + if (::shutdown (m_fd, SHUT_RDWR) < 0) + net::error::throw_code (); +} + + +template +template +T +socket_domain::get_option (level, option) { + not_implemented (); + return T (); +} + + +template +void +socket_domain::set_option (level _level, option _option) { + if (setsockopt (this->m_fd, (int)_level, (int)_option, NULL, 0)) + net::error::throw_code (); +} + + +template +template +void +socket_domain::set_option (level _level, option _option, const T &value) { + if (setsockopt (this->m_fd, (int)_level, (int)_option, (const char*)&value, sizeof (value))) + net::error::throw_code (); +} + + +template +void +socket_domain::bind (const address_type &addr) { + typename address_type::sockaddr_type addr_in = addr.to_sockaddr (); + + if (::bind (m_fd, (sockaddr *)&addr_in, sizeof (addr_in)) != 0) + net::error::throw_code (); +} + +//----------------------------------------------------------------------------- +template +net::socket::socket (socket_t _fd): + net::socket_domain (_fd) +{ ; } + + +template +net::socket::socket (): + net::socket_domain (::socket ((int)D, (int)type::STREAM, (int)protocol::DEFAULT)) +{ ; } + + +template +net::socket::socket (const socket_type &rhs): + socket_domain (rhs) +{ ; } + + +template +void +net::socket::send (const uint8_t *restrict data, size_t len) { + CHECK_HARD (data != NULL); + CHECK (len > 0); + + for (size_t sent = 0; sent < len; ) { + ssize_t result = ::send (this->m_fd, static_cast(data + sent), len - sent, 0); + + if (result < 0) + net::error::throw_code (); + + sent += sign_cast (result); + } +} + + +template +size_t +net::socket::recv (uint8_t *restrict data, size_t len) { + CHECK_HARD (data != NULL); + CHECK (len > 0); + + ssize_t received = ::recv (this->m_fd, data, len, 0); + if (received < 0) + net::error::throw_code (); + + return sign_cast (received); +} + + +template +void +net::socket::connect (const address_type &_addr) { + typename address_type::sockaddr_type addr (_addr.to_sockaddr ()); + + if (::connect (this->m_fd, reinterpret_cast (&addr), sizeof (addr)) < 0) + net::error::throw_code (); +} + + +template +void +net::socket::listen (const address_type &_addr, unsigned int _backlog) { + this->bind (_addr); + + if (::listen (this->m_fd, sign_cast(_backlog)) != 0) + net::error::throw_code (); +} + + +template +typename net::socket::socket_ptr +net::socket::accept (void) { + int newfd = ::accept (this->m_fd, NULL, 0); + if (newfd < 0) + net::error::throw_code (); + + return socket_ptr(new socket (newfd)); +} + + +template +typename net::socket::address_type +net::socket::get_peer (void) const { + typename address_type::sockaddr_type addr; + socklen_t addr_len; + + if (getpeername (this->m_fd, (sockaddr*)&addr, &addr_len)) + net::error::throw_code (); + + CHECK (addr_len == sizeof (addr)); + return addr; +} + + +//----------------------------------------------------------------------------- +template +net::socket::socket (socket_t _fd): + net::socket_domain (_fd) +{ ; } + + +template +net::socket::socket (): + net::socket_domain (::socket ((int)D, (int)type::DGRAM, (int)protocol::DEFAULT)) +{ ; } + + +template +net::socket::socket (const socket_type &rhs): + net::socket_domain (rhs) +{ ; } + + +template +void +net::socket::send_addr (const address_type &addr, + const uint8_t *restrict data, + size_t len) { + CHECK_HARD (data != NULL); + CHECK (len > 0); + + typename address_type::sockaddr_type addr_in = addr.to_sockaddr (); + + ssize_t sent = ::sendto (this->m_fd, data, len, 0, (sockaddr *)&addr_in, sizeof (addr_in)); + if (sent < 0) + net::error::throw_code (); + + CHECK_HARD (sign_cast(sent) == len); +} + + +template +typename net::socket::address_type +net::socket::recv_addr (uint8_t *restrict data, + size_t len) { + CHECK_HARD (data != NULL); + CHECK (len > 0); + + typename address_type::sockaddr_type addr_in; + socklen_t addr_len = sizeof (addr_in); + + ssize_t recvd = recvfrom (this->m_fd, data, len, 0, (sockaddr *)&addr_in, &addr_len); + CHECK_HARD (sizeof (addr_in) == addr_len); + if (recvd < 0) + net::error::throw_code (); + + return addr_in; +} + +//----------------------------------------------------------------------------- +template class net::socket_domain; +template void net::socket_domain::set_option(level, option, const int&); + +template class net::socket; +template class net::socket; + diff --git a/net/socket.hpp b/net/socket.hpp new file mode 100644 index 00000000..8c971909 --- /dev/null +++ b/net/socket.hpp @@ -0,0 +1,109 @@ +/* + * This file is part of libgim. + * + * libgim is free software: you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later + * version. + * + * libgim 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 General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with libgim. If not, see . + * + * Copyright 2011 Danny Robson + */ + +#ifndef __NET_SOCKET_HPP +#define __NET_SOCKET_HPP + +#include "types.hpp" +#include "address.hpp" + + +//----------------------------------------------------------------------------- +namespace net { + template + class socket_domain { + public: + typedef address address_type; + + protected: + socket_t m_fd; + + socket_domain (socket_t _fd); + socket_domain (const socket_domain&); + ~socket_domain (); + + public: + socket_t native (void) const; + + void shutdown (void); + + template + T get_option (level, option); + + void set_option (level, option); + template + void set_option (level, option, const T &value); + + protected: + void bind (const address_type&); + }; + + + template + class socket; + + + template + class socket: public socket_domain { + public: + typedef socket socket_type; + typedef std::unique_ptr socket_ptr; + typedef address address_type; + + protected: + static const unsigned int DEFAULT_BACKLOG = 5; + + socket (socket_t _fd); + + public: + socket (); + socket (const socket_type &); + + void send (const uint8_t *restrict, size_t); + size_t recv (uint8_t *restrict, size_t); + + void connect (const address_type&); + + void listen (const address_type&, unsigned int backlog = DEFAULT_BACKLOG); + socket_ptr accept (void); + + address_type get_peer (void) const; + }; + + + template + class socket : public socket_domain { + public: + typedef socket socket_type; + typedef address address_type; + + socket (socket_t _fd); + + public: + socket (); + socket (const socket_type &); + + void send_addr (const address_type&, const uint8_t *restrict, size_t); + address_type recv_addr (uint8_t *restrict, size_t); + }; +} + + +#endif // __NET_SOCKET_HPP + diff --git a/net/types.cpp b/net/types.cpp new file mode 100644 index 00000000..50199e28 --- /dev/null +++ b/net/types.cpp @@ -0,0 +1,53 @@ +/* + * This file is part of libgim. + * + * libgim is free software: you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later + * version. + * + * libgim 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 General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with libgim. If not, see . + * + * Copyright 2011 Danny Robson + */ + +#include "types.hpp" +#include "../debug.hpp" + +#if defined(HAVE_WINSOCK2_H) +#else + #include +#endif + +//----------------------------------------------------------------------------- +using namespace net; + + +//----------------------------------------------------------------------------- +protocol +net::string_to_protocol (const std::string &_name) + { return net::string_to_protocol (_name.c_str ()); } + + +protocol +net::string_to_protocol (const char *_name) { + struct protoent *entry = getprotobyname (_name); + // TODO: Throw an exception... + CHECK_HARD (entry); + return (protocol)entry->p_proto; +} + + +std::string +net::protocol_to_string (protocol _protocol) { + struct protoent *entry = getprotobynumber ((int)_protocol); + CHECK_HARD (entry); + return entry->p_name; +} + diff --git a/net/types.hpp b/net/types.hpp new file mode 100644 index 00000000..30b61eee --- /dev/null +++ b/net/types.hpp @@ -0,0 +1,182 @@ +/* + * This file is part of libgim. + * + * libgim is free software: you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later + * version. + * + * libgim 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 General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with libgim. If not, see . + * + * Copyright 2011 Danny Robson + */ + +#ifndef __NET_TYPES_HPP +#define __NET_TYPES_HPP + + +#if defined(HAVE_WINSOCK2_H) + #include +#else + #include + #include + #include + #include + #include +#endif + +#include +#include + + +namespace net { + /// Cross platform socket type to deal with Winsock2 +#if defined(HAVE_WINSOCK2_H) + typedef SOCKET socket_t; +#else + typedef int socket_t; +#endif + + /// Defines the protocol family, or communication domain of a socket (see `man socket'). + enum class domain : int { +#define DEFINE_DOMAIN(V) \ + V = AF_##V + + DEFINE_DOMAIN(UNIX), + //DEFINE_DOMAIN(LOCAL), + DEFINE_DOMAIN(INET), + DEFINE_DOMAIN(INET6), + DEFINE_DOMAIN(IPX), + //DEFINE_DOMAIN(NETLINK), + //DEFINE_DOMAIN(X25), + //DEFINE_DOMAIN(AX25), + //DEFINE_DOMAIN(ATMPVC), + DEFINE_DOMAIN(APPLETALK) + //DEFINE_DOMAIN(PACKET) + +#undef DEFINE_DOMAIN + }; + + + /// Specifies the communication semantics of a socket; how a socket deals with data. + enum class type : int { +#define DEFINE_TYPE(V) \ + V = SOCK_##V + + DEFINE_TYPE(STREAM), + DEFINE_TYPE(DGRAM), + DEFINE_TYPE(SEQPACKET), + DEFINE_TYPE(RAW), + DEFINE_TYPE(RDM) + //DEFINE_TYPE(PACKET) + +#undef DEFINE_TYPE + }; + + + /// Indicates the wire transmission protocol to use. + /// + /// This DOES NOT mean what you think it does! It is included for completeness sake, and unless + /// you're doing something funky with the C API you really just want DEFAULT. + /// Values retrieved from /etc/protocols + enum class protocol : int { + DEFAULT = 0, + + IP = 0, + ICMP = 1, + TCP = 6, + UDP = 17, + IPV6 = 41 + }; + + + protocol + string_to_protocol (const std::string&); + + protocol + string_to_protocol (const char *name); + + std::string + protocol_to_string (protocol); + + + enum class option : int { +#define DEFINE_OPTION(V) \ + V = SO_##V + + DEFINE_OPTION(DEBUG), + DEFINE_OPTION(REUSEADDR), + DEFINE_OPTION(TYPE), + //DEFINE_OPTION(ERROR), + DEFINE_OPTION(DONTROUTE), + DEFINE_OPTION(BROADCAST), + //DEFINE_OPTION(SNDBUF), + DEFINE_OPTION(RCVBUF), + //DEFINE_OPTION(SNDBUFFORCE), + //DEFINE_OPTION(RCVBUFFORCE), + DEFINE_OPTION(KEEPALIVE), + DEFINE_OPTION(OOBINLINE), + //DEFINE_OPTION(NO_CHECK), + //DEFINE_OPTION(PRIORITY), + DEFINE_OPTION(LINGER), + //DEFINE_OPTION(BSDCOMPAT), + + //DEFINE_OPTION(PASSCRED), + //DEFINE_OPTION(PEERCRED), + DEFINE_OPTION(RCVLOWAT), + DEFINE_OPTION(SNDLOWAT), + DEFINE_OPTION(RCVTIMEO), + DEFINE_OPTION(SNDTIMEO), + + //DEFINE_OPTION(BINDTODEVICE), + + //DEFINE_OPTION(ATTACH_FILTER), + //DEFINE_OPTION(DETACH_FILTER), + + //DEFINE_OPTION(PEERNAME), + //DEFINE_OPTION(TIMESTAMP), + + DEFINE_OPTION(ACCEPTCONN), + + //DEFINE_OPTION(PEERSEC), + //DEFINE_OPTION(PASSSEC), + //DEFINE_OPTION(TIMESTAMPNS), + + //DEFINE_OPTION(MARK), + + //DEFINE_OPTION(TIMESTAMPING) +#undef DEFINE_OPTION + +#define DEFINE_OPTION(V) \ + V = TCP_##V + + //DEFINE_OPTION(CORK), + //DEFINE_OPTION(DEFER_ACCEPT), + //DEFINE_OPTION(INFO), + //DEFINE_OPTION(KEEPCNT), + //DEFINE_OPTION(KEEPIDLE), + //DEFINE_OPTION(KEEPINTVL), + //DEFINE_OPTION(LINGER2), + //DEFINE_OPTION(MAXSEG), + DEFINE_OPTION(NODELAY) + //DEFINE_OPTION(QUICKACK), + //DEFINE_OPTION(SYNCNT), + //DEFINE_OPTION(WINDOW_CLAMP) +#undef DEFINE_OPTION + }; + + + enum class level : int { + SOCKET = SOL_SOCKET, + TCP = IPPROTO_TCP + }; +} + +#endif // __NET_TYPES_HPP +