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