UDPServer.cpp 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  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. auto buf = ByteBuffer::create_uninitialized(size);
  56. socklen_t in_len = sizeof(in);
  57. ssize_t rlen = ::recvfrom(m_fd, buf.data(), size, 0, (sockaddr*)&in, &in_len);
  58. if (rlen < 0) {
  59. dbgln("recvfrom: {}", strerror(errno));
  60. return {};
  61. }
  62. buf.resize(rlen);
  63. return buf;
  64. }
  65. Optional<IPv4Address> UDPServer::local_address() const
  66. {
  67. if (m_fd == -1)
  68. return {};
  69. sockaddr_in address;
  70. socklen_t len = sizeof(address);
  71. if (getsockname(m_fd, (sockaddr*)&address, &len) != 0)
  72. return {};
  73. return IPv4Address(address.sin_addr.s_addr);
  74. }
  75. Optional<u16> UDPServer::local_port() const
  76. {
  77. if (m_fd == -1)
  78. return {};
  79. sockaddr_in address;
  80. socklen_t len = sizeof(address);
  81. if (getsockname(m_fd, (sockaddr*)&address, &len) != 0)
  82. return {};
  83. return ntohs(address.sin_port);
  84. }
  85. }