Files
BeatDetector/lib/Socket.h

200 lines
5.3 KiB
C++

#ifndef SOCKET_H
#define SOCKET_H
#include <sys/socket.h>
#include <vector>
#include <errno.h>
#include <netinet/in.h>
#include "NetworkAddress.h"
#include "../exception.h"
class SocketUDP {
private:
static constexpr int MAX_DATAGRAM_SIZE = 64*1024;
bool bound = false;
public:
/** ctor */
SocketUDP() : handle(0) {
// create socket
handle = socket(AF_INET, SOCK_DGRAM, 0);
if (handle == -1) {throw Exception("error while creating socket");}
}
/** dtor */
~SocketUDP() {
close();
}
/**
* @brief bind the socket to receive all datagrams sent to the given (local) port
* a localPort of 0 will let the OS determine a free one.
* @param localPort the local endpoint for datagrams sent from a remote
*/
void bind(const uint16_t localPort) {
if (bound) {throw Exception("socket already bound!");}
// local endpoint AF_INET struct
struct sockaddr_in srvAddr;
memset((char*)&srvAddr, 0, sizeof(srvAddr));
srvAddr.sin_family = AF_INET;
srvAddr.sin_addr.s_addr = htonl(INADDR_ANY); // every interface
srvAddr.sin_port = htons(localPort);
// bind the socket to the given port
int ret = ::bind(handle, (struct sockaddr*) &srvAddr, sizeof(srvAddr));
if (ret < 0) {throw Exception("error while binding socket");}
// mark as bound
bound = true;
}
/** close the socket */
void close() {
// cleanup
if (handle) {
::close(handle);
handle = 0;
}
}
// /** is the socket currently closed? */
// bool isClosed() const {
// return handle == 0;
// }
// /** allow to broadcast packets using this socket? */
// void allowBroadcast(const bool allow) {
// #if defined(__GNUC__)
// const int broadcastEnable = (allow) ? (1) : (0);
// const int ret = setsockopt(handle, SOL_SOCKET, SO_BROADCAST, &broadcastEnable, sizeof(broadcastEnable));
// if (ret < 0) { throw SocketException("error while enabling broadcast", errno); }
// #elif defined(_WIN32)
// ;
// #endif
// }
/**
* @brief send a datagram to the given destination address
* @param data the data to send
* @param len the length of the data to send (max 64k!)
* @param addr the destination address
*/
void sendDatagram(const uint8_t* data, uint32_t len, const NetworkAddress& addr) {
// sanity check
if (!bound) {throw Exception("bind() the socket first!");}
// ensure max datagram size
if (len > MAX_DATAGRAM_SIZE) {throw Exception("max datagram size is " + std::to_string(MAX_DATAGRAM_SIZE)+ " bytes!");}
// ensure correct destination address
if (!addr.isValidTargetPort()) {throw Exception("the given destination address has no valid port number");}
if (!addr.isValidTargetHost()) {throw Exception("the given destination address has no valid hostname");}
// send datagram to the given destionation
const struct sockaddr_in& sockAddr = addr.getAsSocketAddress();
const int options = 0;
const int res = sendto(handle, (const char*)data, len, options, (struct sockaddr*) &sockAddr, sizeof(sockaddr));
// check
if (res < 0) {throw Exception("error while sending datagram");}
}
/**
* @brief send a datagram to the given destination address
* @param data the data to send (max 64k!)
* @param addr the destination address
*/
void sendDatagram(const std::vector<uint8_t>& data, const NetworkAddress& addr) {
sendDatagram(data.data(), (uint32_t) data.size(), addr);
}
void sendDatagram(const std::string& data, const NetworkAddress& addr) {
sendDatagram((const uint8_t*)data.data(), data.length(), addr);
}
// /**
// * @brief send the given datagram to its internal destination address
// * @param d the datagram to send
// */
// void sendDatagram(const Datagram& d) {
// sendDatagram(d.getData(), d.getLength(), d.getAddress());
// }
// /**
// * @brief convenience function for receiveDatagram(d) which returns a new
// * datagram instead of reusing an existing one.
// * @return a newly created datagram holding the received message
// */
// DefaultDatagram receiveDatagram() {
// DefaultDatagram dd;
// receiveDatagram(dd);
// return dd;
// }
// /**
// * @brief this method will block until a new datagram is received on the bound
// * port of the underlying socket. the received data will be stored within the
// * given datagram
// * @param d the buffer to store the received datagram to
// */
// void receiveDatagram(Datagram& d) {
// const int flags = 0;
// const int maxSize = MAX_DATAGRAM_SIZE;
// // sanity check
// if (!bound) {throw SocketException("bind() the socket first!");}
// // ensure the target buffer may hold the largest possible datagram
// d.ensureSpace(maxSize);
// // the datagrams sender will be stored here
// struct sockaddr_in senderAddr;
// socklen_t senderLength = sizeof(senderAddr);
// // receive datagram from socket and store sender information
// int len = recvfrom(handle, (char*) d.getDataWriteable(), maxSize, flags, (struct sockaddr*) &senderAddr, &senderLength);
// if (len < 0) {throw SocketException("error while receiving datagram", errno);}
// // store senders network-address in the datagram
// NetworkAddress na(senderAddr);
// d.setAddress(na);
// // inform buffer about the actual size of the datagram
// d.setLength( (uint32_t) len );
// }
private:
/** the socket handle */
int handle;
/** the local address the socket is bound to */
NetworkAddress localAddress;
};
#endif // SOCKET_H