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