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 <iostream> 10 11 namespace pldm 12 { 13 namespace responder 14 { 15 namespace utils 16 { 17 int setupUnixSocket(const std::string& socketInterface) 18 { 19 int sock; 20 struct sockaddr_un addr; 21 memset(&addr, 0, sizeof(addr)); 22 addr.sun_family = AF_UNIX; 23 if (strnlen(socketInterface.c_str(), sizeof(addr.sun_path)) == 24 sizeof(addr.sun_path)) 25 { 26 std::cerr << "setupUnixSocket: UNIX socket path too long" << std::endl; 27 return -1; 28 } 29 30 strncpy(addr.sun_path, socketInterface.c_str(), sizeof(addr.sun_path) - 1); 31 32 if ((sock = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0)) == -1) 33 { 34 std::cerr << "setupUnixSocket: socket() call failed" << std::endl; 35 return -1; 36 } 37 38 if (bind(sock, (struct sockaddr*)&addr, sizeof(addr)) == -1) 39 { 40 std::cerr << "setupUnixSocket: bind() call failed with errno " << errno 41 << std::endl; 42 close(sock); 43 return -1; 44 } 45 46 if (listen(sock, 1) == -1) 47 { 48 std::cerr << "setupUnixSocket: listen() call failed" << std::endl; 49 close(sock); 50 return -1; 51 } 52 53 fd_set rfd; 54 struct timeval tv; 55 tv.tv_sec = 1; 56 tv.tv_usec = 0; 57 58 FD_ZERO(&rfd); 59 FD_SET(sock, &rfd); 60 int nfd = sock + 1; 61 int fd = -1; 62 63 int retval = select(nfd, &rfd, NULL, NULL, &tv); 64 if (retval < 0) 65 { 66 std::cerr << "setupUnixSocket: select call failed " << errno 67 << std::endl; 68 close(sock); 69 return -1; 70 } 71 72 if ((retval > 0) && (FD_ISSET(sock, &rfd))) 73 { 74 fd = accept(sock, NULL, NULL); 75 if (fd < 0) 76 { 77 std::cerr << "setupUnixSocket: accept() call failed " << errno 78 << std::endl; 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 std::cerr << "writeToUnixSocket: select call failed " << errno 107 << std::endl; 108 close(sock); 109 return -1; 110 } 111 if (retval == 0) 112 { 113 nwrite = 0; 114 continue; 115 } 116 if ((retval > 0) && (FD_ISSET(sock, &wfd))) 117 { 118 nwrite = write(sock, buf + i, blockSize - i); 119 if (nwrite < 0) 120 { 121 if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) 122 { 123 std::cerr << "writeToUnixSocket: Write call failed with " 124 "EAGAIN or EWOULDBLOCK or EINTR" 125 << std::endl; 126 nwrite = 0; 127 continue; 128 } 129 std::cerr << "writeToUnixSocket: Failed to write" << std::endl; 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