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