
- Fix various incompatibilities and differences between Linux and Cygwin builds - Make usrsctp an optional dependency - Fix building without SSL - Add new secure random bytes function, use it for websockets - Switch to libsrtp2 v2.6.0 (currently latest release) - Add patch that makes latest libsrtp2 build in latest Cygwin - Add patch that makes srt build in latest Cygwin - Correctly allow linking libsrtp2 and srt to local mbedtls version
299 lines
13 KiB
C++
299 lines
13 KiB
C++
/// \file socket.h
|
|
/// A handy Socket wrapper library.
|
|
/// Written by Jaron Vietor in 2010 for DDVTech
|
|
|
|
#pragma once
|
|
#include <arpa/inet.h>
|
|
#include <deque>
|
|
#include <fcntl.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <string>
|
|
#include <sys/socket.h>
|
|
#include <sys/types.h>
|
|
#include <sys/un.h>
|
|
#include <unistd.h>
|
|
#include "util.h"
|
|
|
|
#ifdef SSL
|
|
#include <mbedtls/ctr_drbg.h>
|
|
#include <mbedtls/debug.h>
|
|
#include <mbedtls/entropy.h>
|
|
#include <mbedtls/error.h>
|
|
|
|
#if !HAVE_UPSTREAM_MBEDTLS_SRTP
|
|
#include <mbedtls/net.h>
|
|
#else
|
|
#include <mbedtls/net_sockets.h>
|
|
#endif
|
|
|
|
#include <mbedtls/ssl.h>
|
|
#include <mbedtls/ssl_cookie.h>
|
|
#include <mbedtls/timing.h>
|
|
#include <mbedtls/version.h>
|
|
|
|
#if MBEDTLS_VERSION_MAJOR == 2
|
|
#include <mbedtls/certs.h>
|
|
#include <mbedtls/config.h>
|
|
#else
|
|
#include <mbedtls/build_info.h>
|
|
#endif
|
|
|
|
#endif
|
|
|
|
#include "util.h"
|
|
|
|
// for being friendly with Socket::Connection down below
|
|
namespace Buffer{
|
|
class user;
|
|
}
|
|
|
|
/// Holds Socket tools.
|
|
namespace Socket{
|
|
|
|
void hostBytesToStr(const char *bytes, size_t len, std::string &target);
|
|
bool isBinAddress(const std::string &binAddr, std::string matchTo);
|
|
bool matchIPv6Addr(const std::string &A, const std::string &B, uint8_t prefix);
|
|
std::string getBinForms(std::string addr);
|
|
/// Returns true if given human-readable address (address, not hostname) is a local address.
|
|
bool isLocal(const std::string &host);
|
|
/// Returns true if given human-readable hostname is a local address.
|
|
bool isLocalhost(const std::string &host);
|
|
bool checkTrueSocket(int sock);
|
|
std::string resolveHostToBestExternalAddrGuess(const std::string &host, int family = AF_UNSPEC,
|
|
const std::string &hint = "");
|
|
bool getSocketName(int fd, std::string &host, uint32_t &port);
|
|
bool getPeerName(int fd, std::string &host, uint32_t &port);
|
|
bool getPeerName(int fd, std::string &host, uint32_t &port, sockaddr * tmpaddr, socklen_t * addrlen);
|
|
|
|
/// A buffer made out of std::string objects that can be efficiently read from and written to.
|
|
class Buffer{
|
|
private:
|
|
std::deque<std::string> data;
|
|
|
|
public:
|
|
std::string splitter; ///< String to automatically split on if encountered. \n by default
|
|
Buffer();
|
|
unsigned int size();
|
|
unsigned int bytes(unsigned int max);
|
|
unsigned int bytesToSplit();
|
|
void append(const std::string &newdata);
|
|
void append(const char *newdata, const unsigned int newdatasize);
|
|
void prepend(const std::string &newdata);
|
|
void prepend(const char *newdata, const unsigned int newdatasize);
|
|
std::string &get();
|
|
bool available(unsigned int count);
|
|
bool available(unsigned int count) const;
|
|
std::string remove(unsigned int count);
|
|
void remove(Util::ResizeablePointer & ptr, unsigned int count);
|
|
std::string copy(unsigned int count);
|
|
void clear();
|
|
};
|
|
// Buffer
|
|
|
|
/// This class is for easy communicating through sockets, either TCP or Unix.
|
|
/// Internally, sSend and sRecv hold the file descriptor to read/write from/to.
|
|
/// If they are not identical and sRecv is closed but sSend still open, reading from sSend will be attempted.
|
|
class Connection{
|
|
protected:
|
|
void clear(); ///< Clears the internal data structure. Meant only for use in constructors.
|
|
bool isTrueSocket;
|
|
int sSend; ///< Write end of socket.
|
|
int sRecv; ///< Read end of socket.
|
|
std::string remotehost; ///< Stores remote host address.
|
|
std::string boundaddr; ///< Stores bound interface address.
|
|
struct sockaddr_in6 remoteaddr; ///< Stores remote host address.
|
|
uint64_t up;
|
|
uint64_t down;
|
|
long long int conntime;
|
|
Buffer downbuffer; ///< Stores temporary data coming in.
|
|
int iread(void *buffer, int len, int flags = 0); ///< Incremental read call.
|
|
bool iread(Buffer &buffer, int flags = 0); ///< Incremental write call that is compatible with Socket::Buffer.
|
|
void setBoundAddr();
|
|
|
|
protected:
|
|
std::string lastErr; ///< Stores last error, if any.
|
|
#ifdef SSL
|
|
/// optional extension that uses mbedtls for SSL
|
|
bool sslConnected;
|
|
int ssl_iread(void *buffer, int len, int flags = 0); ///< Incremental read call.
|
|
unsigned int ssl_iwrite(const void *buffer, int len); ///< Incremental write call.
|
|
mbedtls_net_context *server_fd;
|
|
mbedtls_entropy_context *entropy;
|
|
mbedtls_ctr_drbg_context *ctr_drbg;
|
|
mbedtls_ssl_context *ssl;
|
|
mbedtls_ssl_config *conf;
|
|
#endif
|
|
|
|
public:
|
|
// friends
|
|
friend class ::Buffer::user;
|
|
// constructors
|
|
Connection(); ///< Create a new disconnected base socket.
|
|
Connection(int sockNo); ///< Create a new base socket.
|
|
Connection(std::string hostname, int port, bool nonblock, bool with_ssl = false); ///< Create a new TCP socket.
|
|
Connection(std::string adres, bool nonblock = false); ///< Create a new Unix Socket.
|
|
Connection(int write, int read); ///< Simulate a socket using two file descriptors.
|
|
// copy/assignment constructors
|
|
Connection(const Connection &rhs);
|
|
Connection &operator=(const Connection &rhs);
|
|
// destructor
|
|
~Connection();
|
|
// generic methods
|
|
void open(int sockNo); // Open from existing socket connection.
|
|
void open(std::string hostname, int port, bool nonblock, bool with_ssl = false); // Open TCP connection.
|
|
void open(std::string adres, bool nonblock = false); // Open Unix connection.
|
|
void open(int write, int read); // Open from two existing file descriptors.
|
|
void close(); ///< Close connection.
|
|
void drop(); ///< Close connection without shutdown.
|
|
void setBlocking(bool blocking); ///< Set this socket to be blocking (true) or nonblocking (false).
|
|
bool isBlocking(); ///< Check if this socket is blocking (true) or nonblocking (false).
|
|
std::string getHost() const; ///< Gets hostname for connection, if available.
|
|
std::string getBinHost() const;
|
|
void setHost(std::string host); ///< Sets hostname for connection manually.
|
|
std::string getBoundAddress() const;
|
|
int getSocket(); ///< Returns internal socket number.
|
|
int getPureSocket(); ///< Returns non-piped internal socket number.
|
|
std::string getError(); ///< Returns a string describing the last error that occured.
|
|
bool connected() const; ///< Returns the connected-state for this socket.
|
|
bool isAddress(const std::string &addr);
|
|
bool isLocal(); ///< Returns true if remote address is a local address.
|
|
// buffered i/o methods
|
|
bool spool(bool strictMode = false); ///< Updates the downbufferinternal variables.
|
|
bool peek(); ///< Clears the downbuffer and fills it with peek
|
|
Buffer &Received(); ///< Returns a reference to the download buffer.
|
|
const Buffer &Received() const; ///< Returns a reference to the download buffer.
|
|
void SendNow(const std::string &data); ///< Will not buffer anything but always send right away. Blocks.
|
|
void SendNow(const char *data); ///< Will not buffer anything but always send right away. Blocks.
|
|
void SendNow(const char *data,
|
|
size_t len); ///< Will not buffer anything but always send right away. Blocks.
|
|
void skipBytes(uint32_t byteCount);
|
|
uint32_t skipCount;
|
|
// unbuffered i/o methods
|
|
unsigned int iwrite(const void *buffer, int len); ///< Incremental write call.
|
|
bool iwrite(std::string &buffer); ///< Write call that is compatible with std::string.
|
|
// stats related methods
|
|
unsigned int connTime(); ///< Returns the time this socket has been connected.
|
|
uint64_t dataUp(); ///< Returns total amount of bytes sent.
|
|
uint64_t dataDown(); ///< Returns total amount of bytes received.
|
|
void resetCounter(); ///< Resets the up/down bytes counter to zero.
|
|
void addUp(const uint32_t i);
|
|
void addDown(const uint32_t i);
|
|
friend class Server;
|
|
bool Error; ///< Set to true if a socket error happened.
|
|
bool Blocking; ///< Set to true if a socket is currently or wants to be blocking.
|
|
// overloaded operators
|
|
bool operator==(const Connection &B) const;
|
|
bool operator!=(const Connection &B) const;
|
|
operator bool() const;
|
|
};
|
|
|
|
/// This class is for easily setting up listening socket, either TCP or Unix.
|
|
class Server{
|
|
private:
|
|
std::string errors; ///< Stores errors that may have occured.
|
|
int sock; ///< Internally saved socket number.
|
|
bool IPv6bind(int port, std::string hostname, bool nonblock); ///< Attempt to bind an IPv6 socket
|
|
bool IPv4bind(int port, std::string hostname, bool nonblock); ///< Attempt to bind an IPv4 socket
|
|
public:
|
|
Server(); ///< Create a new base Server.
|
|
Server(int existingSock); ///< Create a new Server from existing socket.
|
|
Server(int port, std::string hostname, bool nonblock = false); ///< Create a new TCP Server.
|
|
Server(std::string adres, bool nonblock = false); ///< Create a new Unix Server.
|
|
Connection accept(bool nonblock = false); ///< Accept any waiting connections.
|
|
void setBlocking(bool blocking); ///< Set this socket to be blocking (true) or nonblocking (false).
|
|
bool connected() const; ///< Returns the connected-state for this socket.
|
|
bool isBlocking(); ///< Check if this socket is blocking (true) or nonblocking (false).
|
|
void close(); ///< Close connection.
|
|
void drop(); ///< Close connection without shutdown.
|
|
int getSocket(); ///< Returns internal socket number.
|
|
};
|
|
|
|
class UDPConnection{
|
|
private:
|
|
void init(bool nonblock, int family = AF_INET6);
|
|
int sock; ///< Internally saved socket number.
|
|
std::string remotehost; ///< Stores remote host address
|
|
void *destAddr; ///< Destination address pointer.
|
|
unsigned int destAddr_size; ///< Size of the destination address pointer.
|
|
void *recvAddr; ///< Destination address pointer.
|
|
unsigned int recvAddr_size; ///< Size of the destination address pointer.
|
|
unsigned int up; ///< Amount of bytes transferred up.
|
|
unsigned int down; ///< Amount of bytes transferred down.
|
|
int family; ///< Current socket address family
|
|
std::string boundAddr, boundMulti;
|
|
int boundPort;
|
|
void checkRecvBuf();
|
|
std::deque<Util::ResizeablePointer> paceQueue;
|
|
uint64_t lastPace;
|
|
int recvInterface;
|
|
bool hasReceiveData;
|
|
bool isBlocking;
|
|
bool isConnected;
|
|
bool pretendReceive; ///< If true, will pretend to have just received the current data buffer on new Receive() call
|
|
bool onData();
|
|
|
|
// dTLS-related members
|
|
bool hasDTLS; ///< True if dTLS is enabled
|
|
void * nextDTLSRead;
|
|
size_t nextDTLSReadLen;
|
|
#ifdef SSL
|
|
mbedtls_entropy_context entropy_ctx;
|
|
mbedtls_ctr_drbg_context rand_ctx;
|
|
mbedtls_ssl_context ssl_ctx;
|
|
mbedtls_ssl_config ssl_conf;
|
|
mbedtls_ssl_cookie_ctx cookie_ctx;
|
|
mbedtls_timing_delay_context timer_ctx;
|
|
#endif
|
|
|
|
public:
|
|
Util::ResizeablePointer data;
|
|
UDPConnection(const UDPConnection &o);
|
|
UDPConnection(bool nonblock = false);
|
|
~UDPConnection();
|
|
bool operator==(const UDPConnection& b) const;
|
|
operator bool() const;
|
|
#ifdef SSL
|
|
void initDTLS(mbedtls_x509_crt *cert, mbedtls_pk_context *key);
|
|
void deinitDTLS();
|
|
int dTLSRead(unsigned char *buf, size_t len);
|
|
int dTLSWrite(const unsigned char *buf, size_t len);
|
|
void dTLSReset();
|
|
#endif
|
|
bool wasEncrypted;
|
|
void close();
|
|
int getSock();
|
|
uint16_t bind(int port, std::string iface = "", const std::string &multicastAddress = "");
|
|
bool connect();
|
|
void setBlocking(bool blocking);
|
|
void allocateDestination();
|
|
void SetDestination(std::string hostname, uint32_t port);
|
|
void GetDestination(std::string &hostname, uint32_t &port);
|
|
void GetLocalDestination(std::string &hostname, uint32_t &port);
|
|
std::string getBinDestination();
|
|
const void * getDestAddr(){return destAddr;}
|
|
size_t getDestAddrLen(){return destAddr_size;}
|
|
std::string getBoundAddress();
|
|
uint32_t getDestPort() const;
|
|
bool Receive();
|
|
void SendNow(const std::string &data);
|
|
void SendNow(const char *data);
|
|
void SendNow(const char *data, size_t len);
|
|
void SendNow(const char *sdata, size_t len, sockaddr * dAddr, size_t dAddrLen);
|
|
void sendPaced(const char * data, size_t len, bool encrypt = true);
|
|
void sendPaced(uint64_t uSendWindow);
|
|
size_t timeToNextPace(uint64_t uTime = 0);
|
|
void setSocketFamily(int AF_TYPE);
|
|
|
|
|
|
#ifdef SSL
|
|
// dTLS-related public members
|
|
std::string cipher, remote_key, local_key, remote_salt, local_salt;
|
|
#if HAVE_UPSTREAM_MBEDTLS_SRTP
|
|
unsigned char master_secret[48];
|
|
unsigned char randbytes[64];
|
|
mbedtls_tls_prf_types tls_prf_type;
|
|
#endif
|
|
#endif
|
|
};
|
|
}// namespace Socket
|