xref: /openbmc/phosphor-ipmi-flash/tools/net.cpp (revision 36af21c513378d8ba1d8335ce922caa8c34cbf82)
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