1 #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 12 namespace pldm 13 { 14 namespace responder 15 { 16 namespace utils 17 { 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 std::cerr << "setupUnixSocket: UNIX socket path too long" << std::endl; 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 std::cerr << "setupUnixSocket: socket() call failed" << std::endl; 37 return -1; 38 } 39 40 if (bind(sock, (struct sockaddr*)&addr, sizeof(addr)) == -1) 41 { 42 std::cerr << "setupUnixSocket: bind() call failed" << std::endl; 43 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; 62 int fd = -1; 63 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 88 int 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 { 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 std::cerr << "writeToUnixSocket: select call failed " << errno 109 << std::endl; 110 close(sock); 111 return -1; 112 } 113 if (retval == 0) 114 { 115 nwrite = 0; 116 continue; 117 } 118 if ((retval > 0) && (FD_ISSET(sock, &wfd))) 119 { 120 nwrite = write(sock, buf + i, blockSize - i); 121 if (nwrite < 0) 122 { 123 if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) 124 { 125 std::cerr << "writeToUnixSocket: Write call failed with " 126 "EAGAIN or EWOULDBLOCK or EINTR" 127 << std::endl; 128 nwrite = 0; 129 continue; 130 } 131 std::cerr << "writeToUnixSocket: Failed to write" << std::endl; 132 close(sock); 133 return -1; 134 } 135 } 136 else 137 { 138 nwrite = 0; 139 } 140 } 141 return 0; 142 } 143 144 } // namespace utils 145 } // namespace responder 146 } // namespace pldm 147