Move crystallised network wrapper to libgim
This commit is contained in:
parent
481f55a9c4
commit
419c1d48f6
@ -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 \
|
||||
|
139
net/address.cpp
Normal file
139
net/address.cpp
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Copyright 2011 Danny Robson <danny@nerdcruft.net>
|
||||
*/
|
||||
|
||||
#include "address.hpp"
|
||||
|
||||
#include "except.hpp"
|
||||
#include "../debug.hpp"
|
||||
#include "../endian.hpp"
|
||||
#include "../types.hpp"
|
||||
|
||||
#ifdef __WIN32
|
||||
#else
|
||||
#include <arpa/inet.h>
|
||||
#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<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)domain::INET);
|
||||
}
|
||||
|
||||
|
||||
template <domain D>
|
||||
address<D>::address (const std::string &_ip,
|
||||
port_type _port):
|
||||
m_ip (_ip),
|
||||
m_mask ( 0),
|
||||
m_port (_port)
|
||||
{ ; }
|
||||
|
||||
|
||||
template <>
|
||||
address<domain::INET>::sockaddr_type
|
||||
address<domain::INET>::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<domain::INET>::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<domain::INET>::operator ==(const address<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<domain::INET>
|
||||
address<domain::INET>::LOOPBACK ("127.0.0.1", 0);
|
||||
|
||||
|
||||
template <>
|
||||
const address<domain::INET>
|
||||
address<domain::INET>::ANY ("0.0.0.0", 0);
|
||||
|
||||
|
||||
template <>
|
||||
const address<domain::INET6>
|
||||
address<domain::INET6>::LOOPBACK ("::1", 0);
|
||||
|
||||
|
||||
template <>
|
||||
const address<domain::INET6>
|
||||
address<domain::INET6>::ANY ("::0", 0);
|
||||
|
||||
template class address<domain::INET>;
|
||||
template class address<domain::INET6>;
|
||||
|
109
net/address.hpp
Normal file
109
net/address.hpp
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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 <iostream>
|
||||
#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 mask;
|
||||
typedef ipv4::port port;
|
||||
typedef sockaddr_in sockaddr;
|
||||
};
|
||||
|
||||
|
||||
template <>
|
||||
struct address_types <domain::INET6> {
|
||||
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 <domain D>
|
||||
class address {
|
||||
public:
|
||||
typedef typename address_types<D>::ip ip_type;
|
||||
typedef typename address_types<D>::mask mask_type;
|
||||
typedef typename address_types<D>::port 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;
|
||||
|
||||
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<D> &rhs);
|
||||
};
|
||||
|
||||
std::ostream&
|
||||
operator<< (std::ostream &os, const net::address<net::domain::INET> &addr);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif // __NET_ADDRESS_HPP
|
||||
|
119
net/except.cpp
Normal file
119
net/except.cpp
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Copyright 2011 Danny Robson <danny@nerdcruft.net>
|
||||
*/
|
||||
|
||||
#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<c> (); \
|
||||
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 <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; }
|
79
net/except.hpp
Normal file
79
net/except.hpp
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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>
|
||||
|
||||
#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 <int CODE>
|
||||
class error_code : public error {
|
||||
public:
|
||||
error_code ();
|
||||
|
||||
int code (void) const;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // __NET_EXCEPT_HPP
|
297
net/socket.cpp
Normal file
297
net/socket.cpp
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Copyright 2011 Danny Robson <danny@nerdcruft.net>
|
||||
*/
|
||||
|
||||
#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 <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_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 <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_HARD (data != NULL);
|
||||
CHECK (len > 0);
|
||||
|
||||
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_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<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) {
|
||||
int newfd = ::accept (this->m_fd, NULL, 0);
|
||||
if (newfd < 0)
|
||||
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 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_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<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_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<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>;
|
||||
|
109
net/socket.hpp
Normal file
109
net/socket.hpp
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Copyright 2011 Danny Robson <danny@nerdcruft.net>
|
||||
*/
|
||||
|
||||
#ifndef __NET_SOCKET_HPP
|
||||
#define __NET_SOCKET_HPP
|
||||
|
||||
#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
|
||||
|
53
net/types.cpp
Normal file
53
net/types.cpp
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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_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;
|
||||
}
|
||||
|
182
net/types.hpp
Normal file
182
net/types.hpp
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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;
|
||||
#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
|
||||
|
Loading…
Reference in New Issue
Block a user