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     if (strnlen(socketInterface.c_str(), sizeof(addr.sun_path)) ==
31         sizeof(addr.sun_path))
32     {
33         error("setupUnixSocket: UNIX socket path too long");
34         return -1;
35     }
36 
37     strncpy(addr.sun_path, socketInterface.c_str(), sizeof(addr.sun_path) - 1);
38 
39     if ((sock = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0)) == -1)
40     {
41         error("setupUnixSocket: socket() call failed");
42         return -1;
43     }
44 
45     if (bind(sock, (struct sockaddr*)&addr, sizeof(addr)) == -1)
46     {
47         error("setupUnixSocket: bind() call failed  with errno {ERR}", "ERR",
48               errno);
49         close(sock);
50         return -1;
51     }
52 
53     if (listen(sock, 1) == -1)
54     {
55         error("setupUnixSocket: listen() call failed");
56         close(sock);
57         return -1;
58     }
59 
60     fd_set rfd;
61     struct timeval tv;
62     tv.tv_sec = 1;
63     tv.tv_usec = 0;
64 
65     FD_ZERO(&rfd);
66     FD_SET(sock, &rfd);
67     int nfd = sock + 1;
68     int fd = -1;
69 
70     int retval = select(nfd, &rfd, NULL, NULL, &tv);
71     if (retval < 0)
72     {
73         error("setupUnixSocket: select call failed {ERR}", "ERR", errno);
74         close(sock);
75         return -1;
76     }
77 
78     if ((retval > 0) && (FD_ISSET(sock, &rfd)))
79     {
80         fd = accept(sock, NULL, NULL);
81         if (fd < 0)
82         {
83             error("setupUnixSocket: accept() call failed {ERR}", "ERR", errno);
84             close(sock);
85             return -1;
86         }
87         close(sock);
88     }
89     return fd;
90 }
91 
92 int writeToUnixSocket(const int sock, const char* buf, const uint64_t blockSize)
93 {
94     uint64_t i;
95     int nwrite = 0;
96 
97     for (i = 0; i < blockSize; i = i + nwrite)
98     {
99         fd_set wfd;
100         struct timeval tv;
101         tv.tv_sec = 1;
102         tv.tv_usec = 0;
103 
104         FD_ZERO(&wfd);
105         FD_SET(sock, &wfd);
106         int nfd = sock + 1;
107 
108         int retval = select(nfd, NULL, &wfd, NULL, &tv);
109         if (retval < 0)
110         {
111             error("writeToUnixSocket: select call failed {ERR}", "ERR", errno);
112             close(sock);
113             return -1;
114         }
115         if (retval == 0)
116         {
117             nwrite = 0;
118             continue;
119         }
120         if ((retval > 0) && (FD_ISSET(sock, &wfd)))
121         {
122             nwrite = write(sock, buf + i, blockSize - i);
123             if (nwrite < 0)
124             {
125                 if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
126                 {
127                     error(
128                         "writeToUnixSocket: Write call failed with EAGAIN or EWOULDBLOCK or EINTR");
129                     nwrite = 0;
130                     continue;
131                 }
132                 error("writeToUnixSocket: Failed to write {ERR}", "ERR", errno);
133                 close(sock);
134                 return -1;
135             }
136         }
137         else
138         {
139             nwrite = 0;
140         }
141     }
142     return 0;
143 }
144 
145 bool checkIfIBMFru(const std::string& objPath)
146 {
147     using DecoratorAsset =
148         sdbusplus::client::xyz::openbmc_project::inventory::decorator::Asset<>;
149 
150     try
151     {
152         auto propVal = pldm::utils::DBusHandler().getDbusPropertyVariant(
153             objPath.c_str(), "Model", DecoratorAsset::interface);
154         const auto& model = std::get<std::string>(propVal);
155         if (!model.empty())
156         {
157             return true;
158         }
159     }
160     catch (const std::exception&)
161     {
162         return false;
163     }
164     return false;
165 }
166 
167 std::vector<std::string> findPortObjects(const std::string& adapterObjPath)
168 {
169     using ItemConnector =
170         sdbusplus::client::xyz::openbmc_project::inventory::item::Connector<>;
171 
172     std::vector<std::string> portObjects;
173     try
174     {
175         portObjects = pldm::utils::DBusHandler().getSubTreePaths(
176             adapterObjPath, 0,
177             std::vector<std::string>({ItemConnector::interface}));
178     }
179     catch (const std::exception& e)
180     {
181         error("No ports under adapter '{ADAPTER_OBJ_PATH}'  - {ERROR}.",
182               "ADAPTER_OBJ_PATH", adapterObjPath.c_str(), "ERROR", e);
183     }
184 
185     return portObjects;
186 }
187 } // namespace utils
188 } // namespace responder
189 } // namespace pldm
190