net: remove networking code

this now forms a separate library, libcruft-net.
This commit is contained in:
Danny Robson 2016-08-12 15:15:37 +10:00
parent ead926bed2
commit b8c88c1292
12 changed files with 2 additions and 1320 deletions

View File

@ -165,8 +165,6 @@ UTIL_FILES = \
io.cpp \
io.hpp \
io.ipp \
ip.cpp \
ip.hpp \
iterator.hpp \
json/fwd.hpp \
json/except.cpp \
@ -277,14 +275,6 @@ UTIL_FILES = \
POSIX_FILES = \
net/address.cpp \
net/address.hpp \
net/except.cpp \
net/except.hpp \
net/socket.cpp \
net/socket.hpp \
net/types.cpp \
net/types.hpp \
memory/buffer/circular.cpp \
memory/buffer/circular.hpp \
memory/buffer/paged.cpp \
@ -349,8 +339,8 @@ BACKTRACE_FILES=$(firstword $(__BACKTRACE_FILES) backtrace_null.cpp)
###############################################################################
## Local build rules
CLEANFILES = json.cpp version.cpp ip.cpp uri.cpp
EXTRA_DIST = json/flat.cpp.rl version.cpp.rl ip.cpp.rl uri.cpp.rl
CLEANFILES = json.cpp version.cpp uri.cpp
EXTRA_DIST = json/flat.cpp.rl version.cpp.rl uri.cpp.rl
RAGELFLAGS = -F1
SUFFIXES = .cpp .cpp.rl
@ -427,7 +417,6 @@ TEST_BIN = \
test/hash/sha2 \
test/hton \
test/introspection \
test/ip \
test/json_types \
test/maths \
test/matrix \

View File

@ -83,8 +83,6 @@ AC_SEARCH_LIBS([clock_gettime], [rt c], [], [
AC_SEARCH_LIBS([cos], [m], [], [AC_MSG_ERROR([unable to find the maths library])])
AC_SEARCH_LIBS([htons], [ws2_32], [], [AC_MSG_ERROR([unable to find htons library])])
###############################################################################
## Debug features

128
ip.cpp.rl
View File

@ -1,128 +0,0 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*
* Copyright 2011-2016 Danny Robson <danny@nerdcruft.net>
*/
#include "ip.hpp"
#include "cast.hpp"
#include <stdexcept>
#include <iostream>
///////////////////////////////////////////////////////////////////////////////
const ipv4::ip ipv4::ip::LOOPBACK (127, 0, 0, 1);
const ipv4::ip ipv4::ip::ANY ( 0, 0, 0, 0);
//-----------------------------------------------------------------------------
const util::range<ipv4::port_t> ipv4::WELL_KNOWN_PORT ( 0, 1023),
ipv4::REGISTERED_PORT ( 1024, 49151),
ipv4::PRIVATE_PORT (49152, 65535);
///////////////////////////////////////////////////////////////////////////////
ipv4::ip::ip (uint32_t _integer):
m_integer (_integer)
{ ; }
//-----------------------------------------------------------------------------
ipv4::ip::ip (uint8_t a, uint8_t b, uint8_t c, uint8_t d)
{
m_octets[0] = a;
m_octets[1] = b;
m_octets[2] = c;
m_octets[3] = d;
}
///////////////////////////////////////////////////////////////////////////////
bool
ipv4::ip::operator== (const ipv4::ip &rhs) const
{
return m_integer == rhs.m_integer;
}
///////////////////////////////////////////////////////////////////////////////
// RFC 3986
%%{
machine ipv4;
octet = ( [0-9][0-9]? |
'1'[0-9][0-9] |
'2'[0-4][0-9] |
'25'[0-5])
> {
octetstart = fpc;
}
% {
octetend = fpc;
__octet = 0;
for (auto i = octetstart; i < octetend; ++i)
__octet = __octet * 10u + sign_cast<unsigned> (*i - '0');
};
ipv4 := (octet %{ __octets[0] = __octet; } '.'
octet %{ __octets[1] = __octet; } '.'
octet %{ __octets[2] = __octet; } '.'
octet %{ __octets[3] = __octet; })
> { __success = false; }
% { __success = true; }
$!{ __success = false; };
}%%
//-----------------------------------------------------------------------------
%%write data;
///////////////////////////////////////////////////////////////////////////////
ipv4::ip::ip (const std::string &data)
{
bool __success = true;
uint8_t __octets[4] = { 0, 0, 0, 0 };
const char *octetstart = data.data ();
const char *octetend = nullptr;
uint8_t __octet;
int cs = 0;
const char *p = data.data (),
*pe = p + data.size (),
*eof = pe;
%%write init;
%%write exec;
if (!__success)
throw ipv4::error ();
m_octets[0] = __octets[0];
m_octets[1] = __octets[1];
m_octets[2] = __octets[2];
m_octets[3] = __octets[3];
}
//-----------------------------------------------------------------------------
ipv4::ip
ipv4::ip::parse (const std::string &data)
{ return ipv4::ip (data); }

79
ip.hpp
View File

@ -1,79 +0,0 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2011-2016 Danny Robson <danny@nerdcruft.net>
*/
#ifndef __UTIL_IP_HPP
#define __UTIL_IP_HPP
#include "range.hpp"
#include <cstdint>
#include <string>
namespace ipv4 {
struct ip {
union {
uint8_t m_octets[4];
uint32_t m_integer;
};
explicit ip (const std::string &);
explicit ip (uint32_t i);
ip (uint8_t a, uint8_t b, uint8_t c, uint8_t d);
bool operator== (const ip &) const;
explicit operator uint32_t (void);
static ip parse (const std::string &);
static const ip LOOPBACK;
static const ip ANY;
};
typedef uint16_t port_t;
typedef uint32_t mask_t;
extern const util::range<port_t> WELL_KNOWN_PORT,
REGISTERED_PORT,
PRIVATE_PORT;
class error : public std::exception { };
}
namespace ipv6 {
struct ip {
uint32_t m_quads[4];
explicit ip (const std::string&) { ; }
};
typedef uint16_t port_t;
struct mask_t {
uint32_t m_quads[4];
explicit mask_t (uint32_t) { ; }
};
class error : public std::exception { };
}
#endif // __UTIL_IP_HPP

View File

@ -1,167 +0,0 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2011 Danny Robson <danny@nerdcruft.net>
*/
#include "address.hpp"
#include "except.hpp"
#include "../debug.hpp"
#include "../endian.hpp"
#include "../types.hpp"
#include "../raii.hpp"
#ifdef __WIN32
#else
#include <netdb.h>
#include <arpa/inet.h>
#endif
using net::address;
///////////////////////////////////////////////////////////////////////////////
#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
///////////////////////////////////////////////////////////////////////////////
template <net::domain D>
typename address<D>::port_type
address<D>::port (void) const
{ return m_port; }
//-----------------------------------------------------------------------------
template <net::domain D>
void
address<D>::set_port (const port_type &_port)
{ m_port = _port; }
//-----------------------------------------------------------------------------
template <net::domain D>
typename address<D>::ip_type
address<D>::resolve (const std::string &str) {
addrinfo hint;
memset (&hint, 0, sizeof (hint));
hint.ai_family = static_cast<int> (D);
addrinfo* resolved;
int err = getaddrinfo (str.c_str (), nullptr, nullptr, &resolved);
if (err)
net::error::throw_code ();
auto deletor = [] (addrinfo *a) { freeaddrinfo (a); };
std::unique_ptr<addrinfo, decltype(deletor)> raii(resolved, deletor);
return ip_type (reinterpret_cast<sockaddr_type*> (resolved->ai_addr)->sin_addr.s_addr);
}
///////////////////////////////////////////////////////////////////////////////
namespace net {
template <>
address<net::domain::INET>::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)net::domain::INET);
}
template <net::domain D>
address<D>::address (const std::string &_addr,
port_type _port):
m_ip (resolve (_addr)),
m_mask ( 0),
m_port (_port)
{ ; }
template <>
address<net::domain::INET>::sockaddr_type
address<net::domain::INET>::to_sockaddr (void) const {
sockaddr_type addr;
addr.sin_family = (int)net::domain::INET;
addr.sin_port = hton (m_port);
addr.sin_addr.s_addr = m_ip.m_integer;
return addr;
}
template <>
std::string
address<net::domain::INET>::to_string (void) const {
char dest[INET_ADDRSTRLEN + 1];
sockaddr_type addr = to_sockaddr ();
if (NULL == inet_ntop ((int)net::domain::INET, &addr.sin_addr, dest, sizeof (dest)))
net::error::throw_code ();
return dest;
}
template <>
bool
address<net::domain::INET>::operator ==(const address<net::domain::INET> &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<net::domain::INET> &addr) {
os << addr.to_string () << ":" << addr.port ();
return os;
}
///////////////////////////////////////////////////////////////////////////////
template <> const address<net::domain::INET>
address<net::domain::INET>::LOOPBACK ("127.0.0.1", 0);
template <> const address<net::domain::INET>
address<net::domain::INET>::ANY ("0.0.0.0", 0);
namespace net {
template class address<net::domain::INET>;
}
//-----------------------------------------------------------------------------
//template <> const address<net::domain::INET6>
//address<net::domain::INET6>::LOOPBACK ("::1", 0);
//
//template <> const address<net::domain::INET6>
//address<net::domain::INET6>::ANY ("::0", 0);
//
//template class address<net::domain::INET6>;

View File

@ -1,97 +0,0 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2011 Danny Robson <danny@nerdcruft.net>
*/
#ifndef __NET_ADDRESS_HPP
#define __NET_ADDRESS_HPP
#include "types.hpp"
#include "../ip.hpp"
#if defined(HAVE_WINSOCK2_H)
#include "ws2tcpip.h"
#endif
#include <ostream>
#include <string>
//-----------------------------------------------------------------------------
namespace net {
/// Supporting types used for defining addresses in various domains
template <domain D>
struct address_types;
template <>
struct address_types <domain::INET> {
typedef ipv4::ip ip;
typedef ipv4::mask_t mask_t;
typedef ipv4::port_t port_t;
typedef sockaddr_in sockaddr;
};
template <>
struct address_types <domain::INET6> {
typedef ipv6::ip ip;
typedef ipv6::mask_t mask_t;
typedef ipv6::port_t port_t;
typedef sockaddr_in6 sockaddr;
};
/// A full endpoint specification for a domain. Must be usable for bind/listen and send/recv.
template <domain D>
class address {
public:
typedef typename address_types<D>::ip ip_type;
typedef typename address_types<D>::mask_t mask_type;
typedef typename address_types<D>::port_t port_type;
typedef typename address_types<D>::sockaddr sockaddr_type;
protected:
ip_type m_ip;
mask_type m_mask;
port_type m_port;
public:
static const address<D> LOOPBACK;
static const address<D> ANY;
explicit address (const sockaddr_type &);
address (const std::string &address, port_type);
port_type port (void) const;
void set_port (const port_type &);
ip_type ip (void) const { return m_ip; }
sockaddr_type to_sockaddr (void) const;
std::string to_string (void) const;
static ip_type resolve (const std::string &);
bool operator ==(const address<D> &rhs);
};
std::ostream&
operator<< (std::ostream &os, const net::address<net::domain::INET> &addr);
}
#endif // __NET_ADDRESS_HPP

View File

@ -1,122 +0,0 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2011 Danny Robson <danny@nerdcruft.net>
*/
#include "except.hpp"
#include "../debug.hpp"
#include "../cast.hpp"
using net::error;
///////////////////////////////////////////////////////////////////////////////
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];
// It should be fine to signcast the code here as Windows guarantees all
// error messages are positive but appears to use int for compatibility
DWORD output = FormatMessage (0, NULL, sign_cast<unsigned> (code), 0, message, sizeof (message), NULL);
CHECK_NEQ (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<c> (); \
break;
ERROR_CODE(ECONNREFUSED);
ERROR_CODE(ECONNRESET);
ERROR_CODE(EINVAL);
ERROR_CODE(ENOTCONN);
default:
unreachable ();
#undef ERROR_CODE
}
#endif
}
void
net::error::throw_code (void)
{ throw_code (last_code ()); }
//-----------------------------------------------------------------------------
void
net::error::try_code (int err) {
if (__builtin_expect (err != 0, false))
throw_code (err);
}
void
net::error::try_code (void)
{ try_code (last_code ()); }
//-----------------------------------------------------------------------------
int
net::error::last_code (void) {
#ifdef __WIN32
return WSAGetLastError ();
#else
return errno;
#endif
}
//-----------------------------------------------------------------------------
template <int CODE>
net::error_code<CODE>::error_code (void):
net::error (CODE)
{ ; }
template <int CODE>
int
net::error_code<CODE>::code (void) const
{ return CODE; }

View File

@ -1,74 +0,0 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2011 Danny Robson <danny@nerdcruft.net>
*/
#ifndef __NET_EXCEPT_HPP
#define __NET_EXCEPT_HPP
#if defined(HAVE_WINSOCK2_H)
#include <winsock2.h>
#else
#include <cerrno>
#include <cstring>
#endif
#include <string>
#include <stdexcept>
//-----------------------------------------------------------------------------
namespace net {
class error : public std::runtime_error {
protected:
explicit error (const std::string &);
explicit 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 [[noreturn]] (int code);
/// 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 [[noreturn]] (void);
static void
try_code (int code);
static void
try_code (void);
static int
last_code (void);
};
template <int CODE>
class error_code : public error {
public:
error_code ();
int code (void) const;
};
}
#endif // __NET_EXCEPT_HPP

View File

@ -1,300 +0,0 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2011 Danny Robson <danny@nerdcruft.net>
*/
#include "socket.hpp"
#include "../debug.hpp"
#include "../except.hpp"
#include "../cast.hpp"
#include "../log.hpp"
#include "except.hpp"
#if defined(HAVE_WINSOCK2_H)
#include <winsock2.h>
#else
#include <sys/socket.h>
#endif
#include <sys/types.h>
#include <unistd.h>
using namespace net;
//-----------------------------------------------------------------------------
template <domain D>
socket_domain<D>::socket_domain (socket_t _fd):
m_fd (_fd)
{
#ifdef __WIN32
#else
CHECK_GE (m_fd, 0);
#endif
}
#if defined(HAVE_WINSOCK2_H)
// TODO: Make this not retarded. Fucking Windows.
#define dup(X) (X)
// Winsock has incorrect return and parameter types (according to POSIX)
// so we need some wrappers around the system implementations that casts
// to expected types. Mainly int vs ssize_t returns, and int vs size_t
// parameters.
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 <domain D>
socket_domain<D>::socket_domain (const socket_domain<D> &rhs):
m_fd (dup (rhs.m_fd))
{ ; }
template <domain D>
socket_domain<D>::~socket_domain () {
if (closesocket (m_fd) < 0) {
LOG_DEBUG ("closesocket: %s", strerror (errno));
}
}
template <domain D>
socket_t
socket_domain<D>::native (void) const
{ return m_fd; }
template <domain D>
void
socket_domain<D>::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 <domain D>
template <typename T>
T
socket_domain<D>::get_option (level, option) {
not_implemented ();
return T ();
}
template <domain D>
void
socket_domain<D>::set_option (level _level, option _option) {
if (setsockopt (this->m_fd, (int)_level, (int)_option, NULL, 0))
net::error::throw_code ();
}
template <domain D>
template <typename T>
void
socket_domain<D>::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 <domain D>
void
socket_domain<D>::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 <domain D>
net::socket<D, type::STREAM>::socket (socket_t _fd):
net::socket_domain<D> (_fd)
{ ; }
template <domain D>
net::socket<D, type::STREAM>::socket ():
net::socket_domain<D> (::socket ((int)D, (int)type::STREAM, (int)protocol::DEFAULT))
{ ; }
template <domain D>
net::socket<D, type::STREAM>::socket (const socket_type &rhs):
socket_domain<D> (rhs)
{ ; }
template <domain D>
void
net::socket<D, type::STREAM>::send (const uint8_t *restrict data, size_t len) {
CHECK (data != NULL);
CHECK_GT (len, 0u);
for (size_t sent = 0; sent < len; ) {
ssize_t result = ::send (this->m_fd, static_cast<const void *>(data + sent), len - sent, 0);
if (result < 0)
net::error::throw_code ();
sent += sign_cast<size_t> (result);
}
}
template <domain D>
size_t
net::socket<D, type::STREAM>::recv (uint8_t *restrict data, size_t len) {
CHECK (data != NULL);
CHECK_GT (len, 0u);
ssize_t received = ::recv (this->m_fd, data, len, 0);
if (received < 0)
net::error::throw_code ();
return sign_cast<size_t> (received);
}
template <domain D>
void
net::socket<D, type::STREAM>::connect (const address_type &_addr) {
typename address_type::sockaddr_type addr (_addr.to_sockaddr ());
if (::connect (this->m_fd, reinterpret_cast<sockaddr *> (&addr), sizeof (addr)) < 0)
net::error::throw_code ();
}
template <domain D>
void
net::socket<D, type::STREAM>::listen (const address_type &_addr, unsigned int _backlog) {
this->bind (_addr);
if (::listen (this->m_fd, sign_cast<int>(_backlog)) != 0)
net::error::throw_code ();
}
template <domain D>
typename net::socket<D, type::STREAM>::socket_ptr
net::socket<D, type::STREAM>::accept (void) {
socket_t newfd = ::accept (this->m_fd, NULL, 0);
if (newfd == INVALID_SOCKET)
net::error::throw_code ();
return socket_ptr(new socket<D, type::STREAM> (newfd));
}
template <domain D>
typename net::socket<D, type::STREAM>::address_type
net::socket<D, type::STREAM>::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 typename net::socket<D,type::STREAM>::address_type (addr);
}
//-----------------------------------------------------------------------------
template <domain D>
net::socket<D, type::DGRAM>::socket (socket_t _fd):
net::socket_domain<D> (_fd)
{ ; }
template <domain D>
net::socket<D, type::DGRAM>::socket ():
net::socket_domain<D> (::socket ((int)D, (int)type::DGRAM, (int)protocol::DEFAULT))
{ ; }
template <domain D>
net::socket<D, type::DGRAM>::socket (const socket_type &rhs):
net::socket_domain<D> (rhs)
{ ; }
template <domain D>
void
net::socket<D, type::DGRAM>::send_addr (const address_type &addr,
const uint8_t *restrict data,
size_t len) {
CHECK (data != NULL);
CHECK_GT (len, 0u);
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_EQ (sign_cast<size_t>(sent), len);
}
template <domain D>
typename net::socket<D, type::DGRAM>::address_type
net::socket<D, type::DGRAM>::recv_addr (uint8_t *restrict data,
size_t len) {
CHECK (data != NULL);
CHECK_GT (len, 0u);
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_EQ (sizeof (addr_in), addr_len);
if (recvd < 0)
net::error::throw_code ();
return net::socket<D,type::DGRAM>::address_type (addr_in);
}
//-----------------------------------------------------------------------------
template class net::socket_domain<domain::INET>;
template void net::socket_domain<domain::INET>::set_option<int>(level, option, const int&);
template class net::socket<domain::INET, type::STREAM>;
template class net::socket<domain::INET, type::DGRAM>;

View File

@ -1,108 +0,0 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2011 Danny Robson <danny@nerdcruft.net>
*/
#ifndef __NET_SOCKET_HPP
#define __NET_SOCKET_HPP
#include <memory>
#include "types.hpp"
#include "address.hpp"
//-----------------------------------------------------------------------------
namespace net {
template <domain D>
class socket_domain {
public:
typedef address<D> address_type;
protected:
socket_t m_fd;
socket_domain (socket_t _fd);
socket_domain (const socket_domain<D>&);
~socket_domain ();
public:
socket_t native (void) const;
void shutdown (void);
template <typename T>
T get_option (level, option);
void set_option (level, option);
template <typename T>
void set_option (level, option, const T &value);
protected:
void bind (const address_type&);
};
template <domain D, type T>
class socket;
template <domain D>
class socket<D, type::STREAM>: public socket_domain<D> {
public:
typedef socket<D, type::STREAM> socket_type;
typedef std::unique_ptr<socket_type> socket_ptr;
typedef address<D> 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 <domain D>
class socket<D, type::DGRAM> : public socket_domain<D> {
public:
typedef socket<D, type::DGRAM> socket_type;
typedef address<D> 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

View File

@ -1,50 +0,0 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2011 Danny Robson <danny@nerdcruft.net>
*/
#include "types.hpp"
#include "../debug.hpp"
#if defined(HAVE_WINSOCK2_H)
#else
#include <netdb.h>
#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 (entry);
return (protocol)entry->p_proto;
}
std::string
net::protocol_to_string (protocol _protocol) {
struct protoent *entry = getprotobynumber ((int)_protocol);
CHECK (entry);
return entry->p_name;
}

View File

@ -1,180 +0,0 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright 2011 Danny Robson <danny@nerdcruft.net>
*/
#ifndef __NET_TYPES_HPP
#define __NET_TYPES_HPP
#if defined(HAVE_WINSOCK2_H)
#include <winsock2.h>
#else
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <cstring>
#endif
#include <string>
#include <stdexcept>
namespace net {
/// Cross platform socket type to deal with Winsock2
#if defined(HAVE_WINSOCK2_H)
typedef SOCKET socket_t;
#else
typedef int socket_t;
const socket_t INVALID_SOCKET = -1;
#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