Serenity Operating System
at master 115 lines 2.6 kB view raw
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 8#include <AK/IPv4Address.h> 9#include <AK/Types.h> 10#include <LibCore/Notifier.h> 11#include <LibCore/System.h> 12#include <LibCore/UDPServer.h> 13#include <errno.h> 14#include <stdio.h> 15#include <unistd.h> 16 17#ifndef SOCK_NONBLOCK 18# include <fcntl.h> 19# include <sys/ioctl.h> 20#endif 21 22namespace Core { 23 24UDPServer::UDPServer(Object* parent) 25 : Object(parent) 26{ 27#ifdef SOCK_NONBLOCK 28 m_fd = socket(AF_INET, SOCK_DGRAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0); 29#else 30 m_fd = socket(AF_INET, SOCK_DGRAM, 0); 31 int option = 1; 32 ioctl(m_fd, FIONBIO, &option); 33 fcntl(m_fd, F_SETFD, FD_CLOEXEC); 34#endif 35 VERIFY(m_fd >= 0); 36} 37 38UDPServer::~UDPServer() 39{ 40 ::close(m_fd); 41} 42 43bool UDPServer::bind(IPv4Address const& address, u16 port) 44{ 45 if (m_bound) 46 return false; 47 48 auto saddr = SocketAddress(address, port); 49 auto in = saddr.to_sockaddr_in(); 50 51 if (::bind(m_fd, (sockaddr const*)&in, sizeof(in)) != 0) { 52 perror("UDPServer::bind"); 53 return false; 54 } 55 56 m_bound = true; 57 58 m_notifier = Notifier::construct(m_fd, Notifier::Event::Read, this); 59 m_notifier->on_ready_to_read = [this] { 60 if (on_ready_to_receive) 61 on_ready_to_receive(); 62 }; 63 return true; 64} 65 66ErrorOr<ByteBuffer> UDPServer::receive(size_t size, sockaddr_in& in) 67{ 68 auto buf = TRY(ByteBuffer::create_uninitialized(size)); 69 socklen_t in_len = sizeof(in); 70 auto bytes_received = TRY(Core::System::recvfrom(m_fd, buf.data(), size, 0, (sockaddr*)&in, &in_len)); 71 buf.resize(bytes_received); 72 return buf; 73} 74 75Optional<IPv4Address> UDPServer::local_address() const 76{ 77 if (m_fd == -1) 78 return {}; 79 80 sockaddr_in address; 81 socklen_t len = sizeof(address); 82 if (getsockname(m_fd, (sockaddr*)&address, &len) != 0) 83 return {}; 84 85 return IPv4Address(address.sin_addr.s_addr); 86} 87 88Optional<u16> UDPServer::local_port() const 89{ 90 if (m_fd == -1) 91 return {}; 92 93 sockaddr_in address; 94 socklen_t len = sizeof(address); 95 if (getsockname(m_fd, (sockaddr*)&address, &len) != 0) 96 return {}; 97 98 return ntohs(address.sin_port); 99} 100 101ErrorOr<size_t> UDPServer::send(ReadonlyBytes buffer, sockaddr_in const& to) 102{ 103 if (m_fd < 0) { 104 return Error::from_errno(EBADF); 105 } 106 107 auto result = ::sendto(m_fd, buffer.data(), buffer.size(), 0, (sockaddr const*)&to, sizeof(to)); 108 if (result < 0) { 109 return Error::from_errno(errno); 110 } 111 112 return result; 113} 114 115}