1 #include "utils.hpp"
2 
3 #include "common/utils.hpp"
4 
5 #include <libpldm/base.h>
6 #include <sys/socket.h>
7 #include <sys/types.h>
8 #include <sys/un.h>
9 #include <unistd.h>
10 
11 #include <phosphor-logging/lg2.hpp>
12 #include <xyz/openbmc_project/Inventory/Decorator/Asset/client.hpp>
13 #include <xyz/openbmc_project/Inventory/Item/Connector/client.hpp>
14 #include <xyz/openbmc_project/ObjectMapper/client.hpp>
15 
16 PHOSPHOR_LOG2_USING;
17 
18 namespace pldm
19 {
20 namespace responder
21 {
22 namespace utils
23 {
24 int setupUnixSocket(const std::string& socketInterface)
25 {
26     int sock;
27     struct sockaddr_un addr;
28     memset(&addr, 0, sizeof(addr));
29     addr.sun_family = AF_UNIX;
30     size_t interfaceLength = strnlen(socketInterface.c_str(),
31                                      sizeof(addr.sun_path));
32     if (interfaceLength == sizeof(addr.sun_path))
33     {
34         error("Setup unix socket path '{PATH}' is too long '{LENGTH}'", "PATH",
35               socketInterface, "LENGTH", interfaceLength);
36         return -1;
37     }
38 
39     strncpy(addr.sun_path, socketInterface.c_str(), sizeof(addr.sun_path) - 1);
40 
41     if ((sock = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0)) == -1)
42     {
43         error("Failed to open unix socket");
44         return -1;
45     }
46 
47     if (bind(sock, (struct sockaddr*)&addr, sizeof(addr)) == -1)
48     {
49         error("Failed to bind unix socket, error number - {ERROR_NUM}",
50               "ERROR_NUM", errno);
51         close(sock);
52         return -1;
53     }
54 
55     if (listen(sock, 1) == -1)
56     {
57         error("Failed listen() call while setting up unix socket");
58         close(sock);
59         return -1;
60     }
61 
62     fd_set rfd;
63     struct timeval tv;
64     tv.tv_sec = 1;
65     tv.tv_usec = 0;
66 
67     FD_ZERO(&rfd);
68     FD_SET(sock, &rfd);
69     int nfd = sock + 1;
70     int fd = -1;
71 
72     int retval = select(nfd, &rfd, NULL, NULL, &tv);
73     if (retval < 0)
74     {
75         error(
76             "Failed select() call while setting up unix socket, error number - {ERROR_NUM}",
77             "ERROR_NUM", errno);
78         close(sock);
79         return -1;
80     }
81 
82     if ((retval > 0) && (FD_ISSET(sock, &rfd)))
83     {
84         fd = accept(sock, NULL, NULL);
85         if (fd < 0)
86         {
87             error(
88                 "Failed accept() call while setting up unix socket, error number - {ERROR_NUM}",
89                 "ERROR_NUM", errno);
90             close(sock);
91             return -1;
92         }
93         close(sock);
94     }
95     return fd;
96 }
97 
98 int writeToUnixSocket(const int sock, const char* buf, const uint64_t blockSize)
99 {
100     uint64_t i;
101     int nwrite = 0;
102 
103     for (i = 0; i < blockSize; i = i + nwrite)
104     {
105         fd_set wfd;
106         struct timeval tv;
107         tv.tv_sec = 1;
108         tv.tv_usec = 0;
109 
110         FD_ZERO(&wfd);
111         FD_SET(sock, &wfd);
112         int nfd = sock + 1;
113 
114         int retval = select(nfd, NULL, &wfd, NULL, &tv);
115         if (retval < 0)
116         {
117             error(
118                 "Failed to write to unix socket select, error number - {ERROR_NUM}",
119                 "ERROR_NUM", errno);
120             close(sock);
121             return -1;
122         }
123         if (retval == 0)
124         {
125             nwrite = 0;
126             continue;
127         }
128         if ((retval > 0) && (FD_ISSET(sock, &wfd)))
129         {
130             nwrite = write(sock, buf + i, blockSize - i);
131             if (nwrite < 0)
132             {
133                 if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
134                 {
135                     error(
136                         "Failed to write to unix socket, error number - {ERROR_NUM}",
137                         "ERROR_NUM", errno);
138                     nwrite = 0;
139                     continue;
140                 }
141                 error(
142                     "Failed to write to unix socket, error number - {ERROR_NUM}",
143                     "ERROR_NUM", errno);
144                 close(sock);
145                 return -1;
146             }
147         }
148         else
149         {
150             nwrite = 0;
151         }
152     }
153     return 0;
154 }
155 
156 bool checkIfIBMFru(const std::string& objPath)
157 {
158     using DecoratorAsset =
159         sdbusplus::client::xyz::openbmc_project::inventory::decorator::Asset<>;
160 
161     try
162     {
163         auto propVal = pldm::utils::DBusHandler().getDbusPropertyVariant(
164             objPath.c_str(), "Model", DecoratorAsset::interface);
165         const auto& model = std::get<std::string>(propVal);
166         if (!model.empty())
167         {
168             return true;
169         }
170     }
171     catch (const std::exception&)
172     {
173         return false;
174     }
175     return false;
176 }
177 
178 std::vector<std::string> findPortObjects(const std::string& adapterObjPath)
179 {
180     using ItemConnector =
181         sdbusplus::client::xyz::openbmc_project::inventory::item::Connector<>;
182 
183     std::vector<std::string> portObjects;
184     try
185     {
186         portObjects = pldm::utils::DBusHandler().getSubTreePaths(
187             adapterObjPath, 0,
188             std::vector<std::string>({ItemConnector::interface}));
189     }
190     catch (const std::exception& e)
191     {
192         error("No ports under adapter '{ADAPTER_OBJ_PATH}'  - {ERROR}.",
193               "ADAPTER_OBJ_PATH", adapterObjPath.c_str(), "ERROR", e);
194     }
195 
196     return portObjects;
197 }
198 } // namespace utils
199 } // namespace responder
200 } // namespace pldm
201