Serenity Operating System
1/*
2 * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include <AK/IPv4Address.h>
28#include <AK/Types.h>
29#include <LibCore/Notifier.h>
30#include <LibCore/UDPServer.h>
31#include <LibCore/UDPSocket.h>
32#include <stdio.h>
33
34namespace Core {
35
36UDPServer::UDPServer(Object* parent)
37 : Object(parent)
38{
39 m_fd = socket(AF_INET, SOCK_DGRAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
40 ASSERT(m_fd >= 0);
41}
42
43UDPServer::~UDPServer()
44{
45}
46
47bool UDPServer::bind(const IPv4Address& address, u16 port)
48{
49 if (m_bound)
50 return false;
51
52 int rc;
53 auto saddr = SocketAddress(address, port);
54 auto in = saddr.to_sockaddr_in();
55
56 rc = ::bind(m_fd, (const sockaddr*)&in, sizeof(in));
57 ASSERT(rc == 0);
58
59 m_notifier = Notifier::construct(m_fd, Notifier::Event::Read, this);
60 m_notifier->on_ready_to_read = [this] {
61 if (on_ready_to_receive)
62 on_ready_to_receive();
63 };
64 return true;
65}
66
67ByteBuffer UDPServer::receive(size_t size, sockaddr_in& in)
68{
69 auto buf = ByteBuffer::create_zeroed(size);
70 socklen_t in_len = sizeof(in);
71 ssize_t rlen = ::recvfrom(m_fd, buf.data(), size, 0, (sockaddr*)&in, &in_len);
72 if (rlen < 0) {
73 dbg() << "recvfrom: " << strerror(errno);
74 return {};
75 }
76 return buf;
77}
78
79Optional<IPv4Address> UDPServer::local_address() const
80{
81 if (m_fd == -1)
82 return {};
83
84 sockaddr_in address;
85 socklen_t len = sizeof(address);
86 if (getsockname(m_fd, (sockaddr*)&address, &len) != 0)
87 return {};
88
89 return IPv4Address(address.sin_addr.s_addr);
90}
91
92Optional<u16> UDPServer::local_port() const
93{
94 if (m_fd == -1)
95 return {};
96
97 sockaddr_in address;
98 socklen_t len = sizeof(address);
99 if (getsockname(m_fd, (sockaddr*)&address, &len) != 0)
100 return {};
101
102 return ntohs(address.sin_port);
103}
104
105}