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