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