130d09a31SBenjamin Fair /*
230d09a31SBenjamin Fair * Copyright 2019 Google Inc.
330d09a31SBenjamin Fair *
430d09a31SBenjamin Fair * Licensed under the Apache License, Version 2.0 (the "License");
530d09a31SBenjamin Fair * you may not use this file except in compliance with the License.
630d09a31SBenjamin Fair * You may obtain a copy of the License at
730d09a31SBenjamin Fair *
830d09a31SBenjamin Fair * http://www.apache.org/licenses/LICENSE-2.0
930d09a31SBenjamin Fair *
1030d09a31SBenjamin Fair * Unless required by applicable law or agreed to in writing, software
1130d09a31SBenjamin Fair * distributed under the License is distributed on an "AS IS" BASIS,
1230d09a31SBenjamin Fair * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1330d09a31SBenjamin Fair * See the License for the specific language governing permissions and
1430d09a31SBenjamin Fair * limitations under the License.
1530d09a31SBenjamin Fair */
1630d09a31SBenjamin Fair
1730d09a31SBenjamin Fair #include "net.hpp"
1830d09a31SBenjamin Fair
1930d09a31SBenjamin Fair #include "data.hpp"
2030d09a31SBenjamin Fair #include "flags.hpp"
2130d09a31SBenjamin Fair
2230d09a31SBenjamin Fair #include <errno.h>
2330d09a31SBenjamin Fair #include <fcntl.h>
2430d09a31SBenjamin Fair #include <netdb.h>
2530d09a31SBenjamin Fair #include <sys/sendfile.h>
2630d09a31SBenjamin Fair #include <sys/socket.h>
2730d09a31SBenjamin Fair #include <sys/types.h>
2830d09a31SBenjamin Fair
299b37b095SPatrick Venture #include <ipmiblob/blob_errors.hpp>
309b37b095SPatrick Venture #include <stdplus/handle/managed.hpp>
319bb21e3eSWilliam A. Kennington III #include <stdplus/util/cexec.hpp>
329b37b095SPatrick Venture
33*36af21c5SWilliam A. Kennington III #include <array>
3430d09a31SBenjamin Fair #include <cstdint>
3530d09a31SBenjamin Fair #include <cstring>
364152f096SBenjamin Fair #include <optional>
3730d09a31SBenjamin Fair #include <vector>
3830d09a31SBenjamin Fair
3930d09a31SBenjamin Fair namespace
4030d09a31SBenjamin Fair {
4130d09a31SBenjamin Fair
closefd(int && fd,const internal::Sys * & sys)4230d09a31SBenjamin Fair void closefd(int&& fd, const internal::Sys*& sys)
4330d09a31SBenjamin Fair {
4430d09a31SBenjamin Fair sys->close(fd);
4530d09a31SBenjamin Fair }
4630d09a31SBenjamin Fair using Fd = stdplus::Managed<int, const internal::Sys*>::Handle<closefd>;
4730d09a31SBenjamin Fair
4830d09a31SBenjamin Fair } // namespace
4930d09a31SBenjamin Fair
5030d09a31SBenjamin Fair namespace host_tool
5130d09a31SBenjamin Fair {
5230d09a31SBenjamin Fair
sendContents(const std::string & input,std::uint16_t session)5330d09a31SBenjamin Fair bool NetDataHandler::sendContents(const std::string& input,
5430d09a31SBenjamin Fair std::uint16_t session)
5530d09a31SBenjamin Fair {
5630d09a31SBenjamin Fair constexpr size_t blockSize = 64 * 1024;
5730d09a31SBenjamin Fair Fd inputFd(std::nullopt, sys);
5830d09a31SBenjamin Fair
5930d09a31SBenjamin Fair inputFd.reset(sys->open(input.c_str(), O_RDONLY));
6030d09a31SBenjamin Fair if (*inputFd < 0)
6130d09a31SBenjamin Fair {
6230d09a31SBenjamin Fair (void)inputFd.release();
6330d09a31SBenjamin Fair std::fprintf(stderr, "Unable to open file: '%s'\n", input.c_str());
6430d09a31SBenjamin Fair return false;
6530d09a31SBenjamin Fair }
6630d09a31SBenjamin Fair
6730d09a31SBenjamin Fair std::int64_t fileSize = sys->getSize(input.c_str());
6830d09a31SBenjamin Fair Fd connFd(std::nullopt, sys);
6930d09a31SBenjamin Fair
7030d09a31SBenjamin Fair {
7130d09a31SBenjamin Fair struct addrinfo hints;
7230d09a31SBenjamin Fair std::memset(&hints, 0, sizeof(hints));
7330d09a31SBenjamin Fair hints.ai_flags = AI_NUMERICHOST;
742aa55347SBenjamin Fair hints.ai_family = AF_UNSPEC;
7530d09a31SBenjamin Fair hints.ai_socktype = SOCK_STREAM;
7630d09a31SBenjamin Fair
7730d09a31SBenjamin Fair struct addrinfo *addrs, *addr;
7830d09a31SBenjamin Fair int ret = sys->getaddrinfo(host.c_str(), port.c_str(), &hints, &addrs);
7930d09a31SBenjamin Fair if (ret < 0)
8030d09a31SBenjamin Fair {
8130d09a31SBenjamin Fair std::fprintf(stderr, "Couldn't parse address %s with port %s: %s\n",
8230d09a31SBenjamin Fair host.c_str(), port.c_str(), gai_strerror(ret));
8330d09a31SBenjamin Fair return false;
8430d09a31SBenjamin Fair }
8530d09a31SBenjamin Fair
8630d09a31SBenjamin Fair for (addr = addrs; addr != nullptr; addr = addr->ai_next)
8730d09a31SBenjamin Fair {
8830d09a31SBenjamin Fair connFd.reset(sys->socket(addr->ai_family, addr->ai_socktype,
8930d09a31SBenjamin Fair addr->ai_protocol));
9030d09a31SBenjamin Fair if (*connFd == -1)
9130d09a31SBenjamin Fair continue;
9230d09a31SBenjamin Fair
9330d09a31SBenjamin Fair if (sys->connect(*connFd, addr->ai_addr, addr->ai_addrlen) != -1)
9430d09a31SBenjamin Fair break;
9530d09a31SBenjamin Fair }
9630d09a31SBenjamin Fair
9730d09a31SBenjamin Fair // TODO: use stdplus Managed for the addrinfo structs
9830d09a31SBenjamin Fair sys->freeaddrinfo(addrs);
9930d09a31SBenjamin Fair
10030d09a31SBenjamin Fair if (addr == nullptr)
10130d09a31SBenjamin Fair {
10230d09a31SBenjamin Fair std::fprintf(stderr, "Failed to connect\n");
10330d09a31SBenjamin Fair return false;
10430d09a31SBenjamin Fair }
10530d09a31SBenjamin Fair }
10630d09a31SBenjamin Fair
10730d09a31SBenjamin Fair try
10830d09a31SBenjamin Fair {
10930d09a31SBenjamin Fair int bytesSent = 0;
11030d09a31SBenjamin Fair off_t offset = 0;
11130d09a31SBenjamin Fair
11253ecd290SWilliam A. Kennington III progress->start(fileSize);
1139bb21e3eSWilliam A. Kennington III auto confirmSend = [&]() {
1149bb21e3eSWilliam A. Kennington III if (bytesSent == 0)
1159bb21e3eSWilliam A. Kennington III {
1169bb21e3eSWilliam A. Kennington III return;
1179bb21e3eSWilliam A. Kennington III }
1189bb21e3eSWilliam A. Kennington III struct ipmi_flash::ExtChunkHdr chunk;
1199bb21e3eSWilliam A. Kennington III chunk.length = bytesSent;
1209bb21e3eSWilliam A. Kennington III std::vector<uint8_t> chunkBytes(sizeof(chunk));
1219bb21e3eSWilliam A. Kennington III std::memcpy(chunkBytes.data(), &chunk, sizeof(chunk));
1229bb21e3eSWilliam A. Kennington III /* This doesn't return anything on success. */
1239bb21e3eSWilliam A. Kennington III blob->writeBytes(session, offset - bytesSent, chunkBytes);
1249bb21e3eSWilliam A. Kennington III progress->updateProgress(bytesSent);
1259bb21e3eSWilliam A. Kennington III };
12653ecd290SWilliam A. Kennington III
12730d09a31SBenjamin Fair do
12830d09a31SBenjamin Fair {
12930d09a31SBenjamin Fair bytesSent = sys->sendfile(*connFd, *inputFd, &offset, blockSize);
13030d09a31SBenjamin Fair if (bytesSent < 0)
13130d09a31SBenjamin Fair {
1329bb21e3eSWilliam A. Kennington III // Not all input files support sendfile, fall back to a simple
1339bb21e3eSWilliam A. Kennington III // buffered mechanism if unsupported.
1349bb21e3eSWilliam A. Kennington III if (errno != EINVAL)
1359bb21e3eSWilliam A. Kennington III {
1369bb21e3eSWilliam A. Kennington III CHECK_ERRNO(-1, "Sending data to BMC");
1379bb21e3eSWilliam A. Kennington III }
1389bb21e3eSWilliam A. Kennington III std::array<uint8_t, 4096> buf;
1399bb21e3eSWilliam A. Kennington III size_t left = 0;
1409bb21e3eSWilliam A. Kennington III do
1419bb21e3eSWilliam A. Kennington III {
1429bb21e3eSWilliam A. Kennington III left += CHECK_ERRNO(sys->read(*inputFd, buf.data() + left,
1439bb21e3eSWilliam A. Kennington III buf.size() - left),
1449bb21e3eSWilliam A. Kennington III "Reading data for BMC");
1459bb21e3eSWilliam A. Kennington III bytesSent =
1469bb21e3eSWilliam A. Kennington III CHECK_ERRNO(sys->send(*connFd, buf.data(), left, 0),
1479bb21e3eSWilliam A. Kennington III "Sending data to BMC");
1489bb21e3eSWilliam A. Kennington III std::memmove(buf.data(), buf.data() + bytesSent,
1499bb21e3eSWilliam A. Kennington III left - bytesSent);
1509bb21e3eSWilliam A. Kennington III left -= bytesSent;
1519bb21e3eSWilliam A. Kennington III offset += bytesSent;
1529bb21e3eSWilliam A. Kennington III confirmSend();
1539bb21e3eSWilliam A. Kennington III } while (bytesSent > 0);
1549bb21e3eSWilliam A. Kennington III break;
1559bb21e3eSWilliam A. Kennington III }
1569bb21e3eSWilliam A. Kennington III confirmSend();
1579bb21e3eSWilliam A. Kennington III } while (bytesSent > 0);
1589bb21e3eSWilliam A. Kennington III }
1599bb21e3eSWilliam A. Kennington III catch (const std::system_error& e)
1609bb21e3eSWilliam A. Kennington III {
1619bb21e3eSWilliam A. Kennington III std::fprintf(stderr, "%s\n", e.what());
1620d5bb784SWilliam A. Kennington III progress->abort();
16330d09a31SBenjamin Fair return false;
16430d09a31SBenjamin Fair }
16530d09a31SBenjamin Fair catch (const ipmiblob::BlobException& b)
16630d09a31SBenjamin Fair {
1670d5bb784SWilliam A. Kennington III progress->abort();
16830d09a31SBenjamin Fair return false;
16930d09a31SBenjamin Fair }
17030d09a31SBenjamin Fair
1710d5bb784SWilliam A. Kennington III progress->finish();
17230d09a31SBenjamin Fair return true;
17330d09a31SBenjamin Fair }
17430d09a31SBenjamin Fair
17530d09a31SBenjamin Fair } // namespace host_tool
176