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