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