blob: 7b0bd09e2327269fdcd01becf9b5455efb5eacb4 [file] [log] [blame]
Ravi Tejace1c96f2020-10-05 23:13:01 -05001#include "utils.hpp"
2
3#include "libpldm/base.h"
4
5#include <sys/socket.h>
6#include <sys/types.h>
7#include <sys/un.h>
8#include <unistd.h>
9
10#include <iostream>
11
12namespace pldm
13{
14namespace responder
15{
16namespace utils
17{
Ravi Tejace1c96f2020-10-05 23:13:01 -050018int setupUnixSocket(const std::string& socketInterface)
19{
20 int sock;
21 struct sockaddr_un addr;
22 memset(&addr, 0, sizeof(addr));
23 addr.sun_family = AF_UNIX;
24 if (strnlen(socketInterface.c_str(), sizeof(addr.sun_path)) ==
25 sizeof(addr.sun_path))
26 {
27 std::cerr << "setupUnixSocket: UNIX socket path too long" << std::endl;
28 return -1;
29 }
30
31 strncpy(addr.sun_path, socketInterface.c_str(), sizeof(addr.sun_path) - 1);
32
33 if ((sock = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0)) == -1)
34 {
35 std::cerr << "setupUnixSocket: socket() call failed" << std::endl;
36 return -1;
37 }
38
39 if (bind(sock, (struct sockaddr*)&addr, sizeof(addr)) == -1)
40 {
Jayashankar Padathe64f5522022-09-28 21:30:24 -050041 std::cerr << "setupUnixSocket: bind() call failed with errno " << errno
42 << std::endl;
Ravi Tejace1c96f2020-10-05 23:13:01 -050043 close(sock);
44 return -1;
45 }
46
47 if (listen(sock, 1) == -1)
48 {
49 std::cerr << "setupUnixSocket: listen() call failed" << std::endl;
50 close(sock);
51 return -1;
52 }
53
54 fd_set rfd;
55 struct timeval tv;
56 tv.tv_sec = 1;
57 tv.tv_usec = 0;
58
59 FD_ZERO(&rfd);
60 FD_SET(sock, &rfd);
61 int nfd = sock + 1;
Andrew Geisslerefbb5942020-12-15 10:12:30 -060062 int fd = -1;
Ravi Tejace1c96f2020-10-05 23:13:01 -050063
64 int retval = select(nfd, &rfd, NULL, NULL, &tv);
65 if (retval < 0)
66 {
67 std::cerr << "setupUnixSocket: select call failed " << errno
68 << std::endl;
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 std::cerr << "setupUnixSocket: accept() call failed " << errno
79 << std::endl;
80 close(sock);
81 return -1;
82 }
83 close(sock);
84 }
85 return fd;
86}
87
88int writeToUnixSocket(const int sock, const char* buf, const uint64_t blockSize)
89{
90 uint64_t i;
91 int nwrite = 0;
92
93 for (i = 0; i < blockSize; i = i + nwrite)
94 {
Ravi Tejace1c96f2020-10-05 23:13:01 -050095 fd_set wfd;
96 struct timeval tv;
97 tv.tv_sec = 1;
98 tv.tv_usec = 0;
99
100 FD_ZERO(&wfd);
101 FD_SET(sock, &wfd);
102 int nfd = sock + 1;
103
104 int retval = select(nfd, NULL, &wfd, NULL, &tv);
105 if (retval < 0)
106 {
107 std::cerr << "writeToUnixSocket: select call failed " << errno
108 << std::endl;
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 std::cerr << "writeToUnixSocket: Write call failed with "
125 "EAGAIN or EWOULDBLOCK or EINTR"
126 << std::endl;
127 nwrite = 0;
128 continue;
129 }
130 std::cerr << "writeToUnixSocket: Failed to write" << std::endl;
131 close(sock);
132 return -1;
133 }
134 }
135 else
136 {
137 nwrite = 0;
138 }
139 }
140 return 0;
141}
142
143} // namespace utils
144} // namespace responder
145} // namespace pldm