1 /* 2 * Copyright 2019 Google Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "net_handler.hpp" 18 19 #include <errno.h> 20 #include <netinet/in.h> 21 #include <poll.h> 22 #include <sys/socket.h> 23 #include <unistd.h> 24 25 #include <cstdio> 26 27 namespace ipmi_flash 28 { 29 30 bool NetDataHandler::open() 31 { 32 listenFd.reset(::socket(AF_INET6, SOCK_STREAM, 0)); 33 if (*listenFd < 0) 34 { 35 std::perror("Failed to create socket"); 36 (void)listenFd.release(); 37 return false; 38 } 39 40 struct sockaddr_in6 listenAddr; 41 listenAddr.sin6_family = AF_INET6; 42 listenAddr.sin6_port = htons(listenPort); 43 listenAddr.sin6_flowinfo = 0; 44 listenAddr.sin6_addr = in6addr_any; 45 listenAddr.sin6_scope_id = 0; 46 47 if (::bind(*listenFd, (struct sockaddr*)&listenAddr, sizeof(listenAddr)) < 48 0) 49 { 50 std::perror("Failed to bind"); 51 return false; 52 } 53 54 if (::listen(*listenFd, 1) < 0) 55 { 56 std::perror("Failed to listen"); 57 return false; 58 } 59 return true; 60 } 61 62 bool NetDataHandler::close() 63 { 64 connFd.reset(); 65 listenFd.reset(); 66 67 return true; 68 } 69 70 std::vector<std::uint8_t> NetDataHandler::copyFrom(std::uint32_t length) 71 { 72 if (!connFd) 73 { 74 struct pollfd fds; 75 fds.fd = *listenFd; 76 fds.events = POLLIN; 77 78 int ret = ::poll(&fds, 1, timeoutS * 1000); 79 if (ret < 0) 80 { 81 std::perror("Failed to poll"); 82 return std::vector<uint8_t>(); 83 } 84 else if (ret == 0) 85 { 86 fprintf(stderr, "Timed out waiting for connection\n"); 87 return std::vector<uint8_t>(); 88 } 89 else if (fds.revents != POLLIN) 90 { 91 fprintf(stderr, "Invalid poll state: 0x%x\n", fds.revents); 92 return std::vector<uint8_t>(); 93 } 94 95 connFd.reset(::accept(*listenFd, nullptr, nullptr)); 96 if (*connFd < 0) 97 { 98 std::perror("Failed to accept connection"); 99 (void)connFd.release(); 100 return std::vector<uint8_t>(); 101 } 102 103 struct timeval tv = {}; 104 tv.tv_sec = timeoutS; 105 if (setsockopt(*connFd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) 106 { 107 std::perror("Failed to set receive timeout"); 108 return std::vector<uint8_t>(); 109 } 110 } 111 112 std::vector<std::uint8_t> data(length); 113 114 std::uint32_t bytesRead = 0; 115 ssize_t ret; 116 do 117 { 118 ret = read(*connFd, data.data() + bytesRead, length - bytesRead); 119 if (ret < 0) 120 { 121 if (errno == EINTR || errno == EAGAIN) 122 continue; 123 std::perror("Failed to read from socket"); 124 break; 125 } 126 127 bytesRead += ret; 128 } while (ret > 0 && bytesRead < length); 129 130 if (bytesRead != length) 131 { 132 fprintf(stderr, 133 "Couldn't read full expected amount. Wanted %u but got %u\n", 134 length, bytesRead); 135 data.resize(bytesRead); 136 } 137 138 return data; 139 } 140 141 bool NetDataHandler::writeMeta(const std::vector<std::uint8_t>&) 142 { 143 // TODO: have the host tool send the expected IP address that it will 144 // connect from 145 return true; 146 } 147 148 std::vector<std::uint8_t> NetDataHandler::readMeta() 149 { 150 return std::vector<std::uint8_t>(); 151 } 152 153 } // namespace ipmi_flash 154