UDPServer.cpp 2.2 KB

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