1 #include "utils.hpp"
2 
3 #include <libpldm/base.h>
4 #include <sys/socket.h>
5 #include <sys/types.h>
6 #include <sys/un.h>
7 #include <unistd.h>
8 
9 #include <phosphor-logging/lg2.hpp>
10 
11 PHOSPHOR_LOG2_USING;
12 
13 namespace pldm
14 {
15 namespace responder
16 {
17 namespace utils
18 {
19 int setupUnixSocket(const std::string& socketInterface)
20 {
21     int sock;
22     struct sockaddr_un addr;
23     memset(&addr, 0, sizeof(addr));
24     addr.sun_family = AF_UNIX;
25     if (strnlen(socketInterface.c_str(), sizeof(addr.sun_path)) ==
26         sizeof(addr.sun_path))
27     {
28         error("setupUnixSocket: UNIX socket path too long");
29         return -1;
30     }
31 
32     strncpy(addr.sun_path, socketInterface.c_str(), sizeof(addr.sun_path) - 1);
33 
34     if ((sock = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0)) == -1)
35     {
36         error("setupUnixSocket: socket() call failed");
37         return -1;
38     }
39 
40     if (bind(sock, (struct sockaddr*)&addr, sizeof(addr)) == -1)
41     {
42         error("setupUnixSocket: bind() call failed  with errno {ERR}", "ERR",
43               errno);
44         close(sock);
45         return -1;
46     }
47 
48     if (listen(sock, 1) == -1)
49     {
50         error("setupUnixSocket: listen() call failed");
51         close(sock);
52         return -1;
53     }
54 
55     fd_set rfd;
56     struct timeval tv;
57     tv.tv_sec = 1;
58     tv.tv_usec = 0;
59 
60     FD_ZERO(&rfd);
61     FD_SET(sock, &rfd);
62     int nfd = sock + 1;
63     int fd = -1;
64 
65     int retval = select(nfd, &rfd, NULL, NULL, &tv);
66     if (retval < 0)
67     {
68         error("setupUnixSocket: select call failed {ERR}", "ERR", errno);
69         close(sock);
70         return -1;
71     }
72 
73     if ((retval > 0) && (FD_ISSET(sock, &rfd)))
74     {
75         fd = accept(sock, NULL, NULL);
76         if (fd < 0)
77         {
78             error("setupUnixSocket: accept() call failed {ERR}", "ERR", errno);
79             close(sock);
80             return -1;
81         }
82         close(sock);
83     }
84     return fd;
85 }
86 
87 int writeToUnixSocket(const int sock, const char* buf, const uint64_t blockSize)
88 {
89     uint64_t i;
90     int nwrite = 0;
91 
92     for (i = 0; i < blockSize; i = i + nwrite)
93     {
94         fd_set wfd;
95         struct timeval tv;
96         tv.tv_sec = 1;
97         tv.tv_usec = 0;
98 
99         FD_ZERO(&wfd);
100         FD_SET(sock, &wfd);
101         int nfd = sock + 1;
102 
103         int retval = select(nfd, NULL, &wfd, NULL, &tv);
104         if (retval < 0)
105         {
106             error("writeToUnixSocket: select call failed {ERR}", "ERR", errno);
107             close(sock);
108             return -1;
109         }
110         if (retval == 0)
111         {
112             nwrite = 0;
113             continue;
114         }
115         if ((retval > 0) && (FD_ISSET(sock, &wfd)))
116         {
117             nwrite = write(sock, buf + i, blockSize - i);
118             if (nwrite < 0)
119             {
120                 if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
121                 {
122                     error(
123                         "writeToUnixSocket: Write call failed with EAGAIN or EWOULDBLOCK or EINTR");
124                     nwrite = 0;
125                     continue;
126                 }
127                 error("writeToUnixSocket: Failed to write {ERR}", "ERR", errno);
128                 close(sock);
129                 return -1;
130             }
131         }
132         else
133         {
134             nwrite = 0;
135         }
136     }
137     return 0;
138 }
139 
140 } // namespace utils
141 } // namespace responder
142 } // namespace pldm
143