UDPServer.cpp 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. /*
  2. * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
  3. * Copyright (c) 2022, Alexander Narsudinov <a.narsudinov@gmail.com>
  4. *
  5. * SPDX-License-Identifier: BSD-2-Clause
  6. */
  7. #include <AK/IPv4Address.h>
  8. #include <AK/Types.h>
  9. #include <LibCore/Notifier.h>
  10. #include <LibCore/System.h>
  11. #include <LibCore/UDPServer.h>
  12. #include <errno.h>
  13. #include <stdio.h>
  14. #include <unistd.h>
  15. #ifndef SOCK_NONBLOCK
  16. # include <fcntl.h>
  17. # include <sys/ioctl.h>
  18. #endif
  19. namespace Core {
  20. UDPServer::UDPServer(EventReceiver* parent)
  21. : EventReceiver(parent)
  22. {
  23. #ifdef SOCK_NONBLOCK
  24. m_fd = socket(AF_INET, SOCK_DGRAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
  25. #else
  26. m_fd = socket(AF_INET, SOCK_DGRAM, 0);
  27. int option = 1;
  28. ioctl(m_fd, FIONBIO, &option);
  29. fcntl(m_fd, F_SETFD, FD_CLOEXEC);
  30. #endif
  31. VERIFY(m_fd >= 0);
  32. }
  33. UDPServer::~UDPServer()
  34. {
  35. ::close(m_fd);
  36. }
  37. bool UDPServer::bind(IPv4Address const& address, u16 port)
  38. {
  39. if (m_bound)
  40. return false;
  41. auto saddr = SocketAddress(address, port);
  42. auto in = saddr.to_sockaddr_in();
  43. if (::bind(m_fd, (sockaddr const*)&in, sizeof(in)) != 0) {
  44. perror("UDPServer::bind");
  45. return false;
  46. }
  47. m_bound = true;
  48. m_notifier = Notifier::construct(m_fd, Notifier::Type::Read, this);
  49. m_notifier->on_activation = [this] {
  50. if (on_ready_to_receive)
  51. on_ready_to_receive();
  52. };
  53. return true;
  54. }
  55. ErrorOr<ByteBuffer> UDPServer::receive(size_t size, sockaddr_in& in)
  56. {
  57. auto buf = TRY(ByteBuffer::create_uninitialized(size));
  58. socklen_t in_len = sizeof(in);
  59. auto bytes_received = TRY(Core::System::recvfrom(m_fd, buf.data(), size, 0, (sockaddr*)&in, &in_len));
  60. buf.resize(bytes_received);
  61. return buf;
  62. }
  63. Optional<IPv4Address> UDPServer::local_address() const
  64. {
  65. if (m_fd == -1)
  66. return {};
  67. sockaddr_in address;
  68. socklen_t len = sizeof(address);
  69. if (getsockname(m_fd, (sockaddr*)&address, &len) != 0)
  70. return {};
  71. return IPv4Address(address.sin_addr.s_addr);
  72. }
  73. Optional<u16> UDPServer::local_port() const
  74. {
  75. if (m_fd == -1)
  76. return {};
  77. sockaddr_in address;
  78. socklen_t len = sizeof(address);
  79. if (getsockname(m_fd, (sockaddr*)&address, &len) != 0)
  80. return {};
  81. return ntohs(address.sin_port);
  82. }
  83. ErrorOr<size_t> UDPServer::send(ReadonlyBytes buffer, sockaddr_in const& to)
  84. {
  85. if (m_fd < 0) {
  86. return Error::from_errno(EBADF);
  87. }
  88. auto result = ::sendto(m_fd, buffer.data(), buffer.size(), 0, (sockaddr const*)&to, sizeof(to));
  89. if (result < 0) {
  90. return Error::from_errno(errno);
  91. }
  92. return result;
  93. }
  94. }