1 // Copyright 2021 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "socket_manager.hpp"
16
17 #include "serializer.hpp"
18
19 #include <errno.h>
20 #include <sys/socket.h>
21 #include <unistd.h>
22
23 #include <phosphor-logging/log.hpp>
24
25 #include <cstring>
26 #include <format>
27
28 using phosphor::logging::level;
29 using phosphor::logging::log;
30
~SocketManager()31 SocketManager::~SocketManager()
32 {
33 std::lock_guard<std::mutex> lock(open_sockets_lock_);
34 for (auto fd : open_sockets_)
35 {
36 close(fd);
37 }
38 }
39
SendDatagram(const NemoraDatagram * bcast)40 void SocketManager::SendDatagram(const NemoraDatagram* bcast)
41 {
42 std::string serialized = Serializer::Serialize(bcast);
43
44 // Create socket
45 auto fd = socket(AF_INET6, SOCK_DGRAM, 0);
46 if (fd < 0)
47 {
48 log<level::ERR>("SocketManager::SendDatagram: Couldn't open socket");
49 }
50 TrackSocket(fd);
51
52 // Because we aren't sure whether the v6 or v4 target IP will be present,
53 // we send UDP packets to both. This puts us at feature parity with EC.
54
55 // Send serialized data (v6)
56 auto addr6 = reinterpret_cast<const sockaddr*>(&bcast->destination6);
57 auto err = sendto(fd, serialized.c_str(), serialized.length(), 0, addr6,
58 sizeof(bcast->destination6));
59 if (err < 0)
60 {
61 log<level::ERR>(
62 std::format("SocketManager::SendDatagram: Couldn't sendto "
63 "socket (IPv6): {}",
64 std::strerror(errno))
65 .c_str());
66 }
67
68 // Send serialized data (v4)
69 auto addr4 = reinterpret_cast<const sockaddr*>(&bcast->destination);
70 err = sendto(fd, serialized.c_str(), serialized.length(), 0, addr4,
71 sizeof(bcast->destination));
72 if (err < 0)
73 {
74 log<level::ERR>(
75 std::format("SocketManager::SendDatagram: Couldn't sendto "
76 "socket (IPv4): {}",
77 std::strerror(errno))
78 .c_str());
79 }
80
81 CloseSocketSafely(fd);
82 }
83
CloseSocketSafely(int fd)84 void SocketManager::CloseSocketSafely(int fd)
85 {
86 std::lock_guard<std::mutex> lock(open_sockets_lock_);
87 if (open_sockets_.find(fd) != open_sockets_.end())
88 {
89 close(fd);
90 open_sockets_.erase(fd);
91 }
92 }
93
TrackSocket(int fd)94 void SocketManager::TrackSocket(int fd)
95 {
96 std::lock_guard<std::mutex> lock(open_sockets_lock_);
97 open_sockets_.insert(fd);
98 }
99