Веб-сайт самохостера Lotigara

summaryrefslogtreecommitdiff
path: root/source/core/StarUdp.cpp
blob: c38da41577ee02bd93eda57fcd4ae072e265b316 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#include "StarUdp.hpp"
#include "StarLogging.hpp"
#include "StarNetImpl.hpp"

namespace Star {

UdpSocket::UdpSocket(NetworkMode networkMode) : Socket(SocketType::Udp, networkMode) {}

size_t UdpSocket::receive(HostAddressWithPort* address, char* data, size_t datasize) {
  ReadLocker locker(m_mutex);
  checkOpen("UdpSocket::receive");

  int flags = 0;
  int len;
  struct sockaddr_storage sockAddr;
  socklen_t sockAddrLen = sizeof(sockAddr);

  len = ::recvfrom(m_impl->socketDesc, data, datasize, flags, (struct sockaddr*)&sockAddr, &sockAddrLen);

  if (len < 0) {
    if (!isActive())
      throw SocketClosedException("Connection closed");
    else if (netErrorInterrupt())
      len = 0;
    else
      throw NetworkException(strf("udp recv error: {}", netErrorString()));
  }

  if (address)
    setAddressFromNative(*address, m_localAddress.address().mode(), &sockAddr);

  return len;
}

size_t UdpSocket::send(HostAddressWithPort const& address, char const* data, size_t size) {
  ReadLocker locker(m_mutex);
  checkOpen("UdpSocket::send");

  struct sockaddr_storage sockAddr;
  socklen_t sockAddrLen;
  setNativeFromAddress(address, &sockAddr, &sockAddrLen);

  int len = ::sendto(m_impl->socketDesc, data, size, 0, (struct sockaddr*)&sockAddr, sockAddrLen);
  if (len < 0) {
    if (!isActive())
      throw SocketClosedException("Connection closed");
    else if (netErrorInterrupt())
      len = 0;
    else
      throw NetworkException(strf("udp send error: {}", netErrorString()));
  }

  return len;
}

UdpServer::UdpServer(HostAddressWithPort const& address)
  : m_hostAddress(address), m_listenSocket(make_shared<UdpSocket>(m_hostAddress.address().mode())) {
  m_listenSocket->setNonBlocking(true);
  m_listenSocket->bind(m_hostAddress);
  Logger::debug("UdpServer listening on: {}", m_hostAddress);
}

UdpServer::~UdpServer() {
  close();
}

size_t UdpServer::receive(HostAddressWithPort* address, char* data, size_t bufsize, unsigned timeout) {
  Socket::poll({{m_listenSocket, {true, false}}}, timeout);
  return m_listenSocket->receive(address, data, bufsize);
}

size_t UdpServer::send(HostAddressWithPort const& address, char const* data, size_t len) {
  return m_listenSocket->send(address, data, len);
}

void UdpServer::close() {
  m_listenSocket->close();
}

bool UdpServer::isListening() const {
  return m_listenSocket->isActive();
}

}