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 <fmt/format.h>
21 #include <sys/socket.h>
22 #include <unistd.h>
23 
24 #include <phosphor-logging/log.hpp>
25 
26 #include <cstring>
27 
28 using fmt::format;
29 using phosphor::logging::level;
30 using phosphor::logging::log;
31 
32 SocketManager::~SocketManager()
33 {
34     std::lock_guard<std::mutex> lock(open_sockets_lock_);
35     for (auto fd : open_sockets_)
36     {
37         close(fd);
38     }
39 }
40 
41 void SocketManager::SendDatagram(const NemoraDatagram* bcast)
42 {
43     std::string serialized = Serializer::Serialize(bcast);
44 
45     // Create socket
46     auto fd = socket(AF_INET6, SOCK_DGRAM, 0);
47     if (fd < 0)
48     {
49         log<level::ERR>("SocketManager::SendDatagram: Couldn't open socket");
50     }
51     TrackSocket(fd);
52 
53     // Because we aren't sure whether the v6 or v4 target IP will be present,
54     // we send UDP packets to both. This puts us at feature parity with EC.
55 
56     // Send serialized data (v6)
57     auto addr6 = reinterpret_cast<const sockaddr*>(&bcast->destination6);
58     auto err = sendto(fd, serialized.c_str(), serialized.length(), 0, addr6,
59                       sizeof(bcast->destination6));
60     if (err < 0)
61     {
62         log<level::ERR>(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>(format("SocketManager::SendDatagram: Couldn't sendto "
75                                "socket (IPv4): {}",
76                                std::strerror(errno))
77                             .c_str());
78     }
79 
80     CloseSocketSafely(fd);
81 }
82 
83 void SocketManager::CloseSocketSafely(int fd)
84 {
85     std::lock_guard<std::mutex> lock(open_sockets_lock_);
86     if (open_sockets_.find(fd) != open_sockets_.end())
87     {
88         close(fd);
89         open_sockets_.erase(fd);
90     }
91 }
92 
93 void SocketManager::TrackSocket(int fd)
94 {
95     std::lock_guard<std::mutex> lock(open_sockets_lock_);
96     open_sockets_.insert(fd);
97 }
98