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 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 146