Squashed 'third_party/allwpilib_2019/' content from commit bd05dfa1c

Change-Id: I2b1c2250cdb9b055133780c33593292098c375b7
git-subtree-dir: third_party/allwpilib_2019
git-subtree-split: bd05dfa1c7cca74c4fac451e7b9d6a37e7b53447
diff --git a/wpiutil/src/main/native/cpp/UDPClient.cpp b/wpiutil/src/main/native/cpp/UDPClient.cpp
new file mode 100644
index 0000000..aafdf47
--- /dev/null
+++ b/wpiutil/src/main/native/cpp/UDPClient.cpp
@@ -0,0 +1,237 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) 2017-2018 FIRST. All Rights Reserved.                        */
+/* Open Source Software - may be modified and shared by FRC teams. The code   */
+/* must be accompanied by the FIRST BSD license file in the root directory of */
+/* the project.                                                               */
+/*----------------------------------------------------------------------------*/
+
+#include "wpi/UDPClient.h"
+
+#ifdef _WIN32
+#include <WinSock2.h>
+#include <Ws2tcpip.h>
+#pragma comment(lib, "Ws2_32.lib")
+#else
+#include <arpa/inet.h>
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <unistd.h>
+#endif
+
+#include "wpi/Logger.h"
+#include "wpi/SocketError.h"
+
+using namespace wpi;
+
+UDPClient::UDPClient(Logger& logger) : UDPClient("", logger) {}
+
+UDPClient::UDPClient(const Twine& address, Logger& logger)
+    : m_lsd(0), m_port(0), m_address(address.str()), m_logger(logger) {}
+
+UDPClient::UDPClient(UDPClient&& other)
+    : m_lsd(other.m_lsd),
+      m_port(other.m_port),
+      m_address(std::move(other.m_address)),
+      m_logger(other.m_logger) {
+  other.m_lsd = 0;
+  other.m_port = 0;
+}
+
+UDPClient::~UDPClient() {
+  if (m_lsd > 0) {
+    shutdown();
+  }
+}
+
+UDPClient& UDPClient::operator=(UDPClient&& other) {
+  if (this == &other) return *this;
+  shutdown();
+  m_logger = other.m_logger;
+  m_lsd = other.m_lsd;
+  m_address = std::move(other.m_address);
+  m_port = other.m_port;
+  other.m_lsd = 0;
+  other.m_port = 0;
+  return *this;
+}
+
+int UDPClient::start() { return start(0); }
+
+int UDPClient::start(int port) {
+  if (m_lsd > 0) return 0;
+
+#ifdef _WIN32
+  WSAData wsaData;
+  WORD wVersionRequested = MAKEWORD(2, 2);
+  WSAStartup(wVersionRequested, &wsaData);
+#endif
+
+  m_lsd = socket(AF_INET, SOCK_DGRAM, 0);
+
+  if (m_lsd < 0) {
+    WPI_ERROR(m_logger, "could not create socket");
+    return -1;
+  }
+
+  struct sockaddr_in addr;
+  std::memset(&addr, 0, sizeof(addr));
+  addr.sin_family = AF_INET;
+  if (m_address.size() > 0) {
+#ifdef _WIN32
+    SmallString<128> addr_copy(m_address);
+    addr_copy.push_back('\0');
+    int res = InetPton(PF_INET, addr_copy.data(), &(addr.sin_addr));
+#else
+    int res = inet_pton(PF_INET, m_address.c_str(), &(addr.sin_addr));
+#endif
+    if (res != 1) {
+      WPI_ERROR(m_logger, "could not resolve " << m_address << " address");
+      return -1;
+    }
+  } else {
+    addr.sin_addr.s_addr = INADDR_ANY;
+  }
+  addr.sin_port = htons(port);
+
+  if (port != 0) {
+#ifdef _WIN32
+    int optval = 1;
+    setsockopt(m_lsd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE,
+               reinterpret_cast<char*>(&optval), sizeof optval);
+#else
+    int optval = 1;
+    setsockopt(m_lsd, SOL_SOCKET, SO_REUSEADDR,
+               reinterpret_cast<char*>(&optval), sizeof optval);
+#endif
+  }
+
+  int result = bind(m_lsd, reinterpret_cast<sockaddr*>(&addr), sizeof(addr));
+  if (result != 0) {
+    WPI_ERROR(m_logger, "bind() failed: " << SocketStrerror());
+    return result;
+  }
+  m_port = port;
+  return 0;
+}
+
+void UDPClient::shutdown() {
+  if (m_lsd > 0) {
+#ifdef _WIN32
+    ::shutdown(m_lsd, SD_BOTH);
+    closesocket(m_lsd);
+    WSACleanup();
+#else
+    ::shutdown(m_lsd, SHUT_RDWR);
+    close(m_lsd);
+#endif
+    m_lsd = 0;
+    m_port = 0;
+  }
+}
+
+int UDPClient::send(ArrayRef<uint8_t> data, const Twine& server, int port) {
+  // server must be a resolvable IP address
+  struct sockaddr_in addr;
+  std::memset(&addr, 0, sizeof(addr));
+  addr.sin_family = AF_INET;
+  SmallVector<char, 128> addr_store;
+  StringRef remoteAddr = server.toNullTerminatedStringRef(addr_store);
+  if (remoteAddr.empty()) {
+    WPI_ERROR(m_logger, "server must be passed");
+    return -1;
+  }
+
+#ifdef _WIN32
+  int res = InetPton(AF_INET, remoteAddr.data(), &(addr.sin_addr));
+#else
+  int res = inet_pton(AF_INET, remoteAddr.data(), &(addr.sin_addr));
+#endif
+  if (res != 1) {
+    WPI_ERROR(m_logger, "could not resolve " << server << " address");
+    return -1;
+  }
+  addr.sin_port = htons(port);
+
+  // sendto should not block
+  int result =
+      sendto(m_lsd, reinterpret_cast<const char*>(data.data()), data.size(), 0,
+             reinterpret_cast<sockaddr*>(&addr), sizeof(addr));
+  return result;
+}
+
+int UDPClient::send(StringRef data, const Twine& server, int port) {
+  // server must be a resolvable IP address
+  struct sockaddr_in addr;
+  std::memset(&addr, 0, sizeof(addr));
+  addr.sin_family = AF_INET;
+  SmallVector<char, 128> addr_store;
+  StringRef remoteAddr = server.toNullTerminatedStringRef(addr_store);
+  if (remoteAddr.empty()) {
+    WPI_ERROR(m_logger, "server must be passed");
+    return -1;
+  }
+
+#ifdef _WIN32
+  int res = InetPton(AF_INET, remoteAddr.data(), &(addr.sin_addr));
+#else
+  int res = inet_pton(AF_INET, remoteAddr.data(), &(addr.sin_addr));
+#endif
+  if (res != 1) {
+    WPI_ERROR(m_logger, "could not resolve " << server << " address");
+    return -1;
+  }
+  addr.sin_port = htons(port);
+
+  // sendto should not block
+  int result = sendto(m_lsd, data.data(), data.size(), 0,
+                      reinterpret_cast<sockaddr*>(&addr), sizeof(addr));
+  return result;
+}
+
+int UDPClient::receive(uint8_t* data_received, int receive_len) {
+  if (m_port == 0) return -1;  // return if not receiving
+  return recv(m_lsd, reinterpret_cast<char*>(data_received), receive_len, 0);
+}
+
+int UDPClient::receive(uint8_t* data_received, int receive_len,
+                       SmallVectorImpl<char>* addr_received,
+                       int* port_received) {
+  if (m_port == 0) return -1;  // return if not receiving
+
+  struct sockaddr_in remote;
+  socklen_t remote_len = sizeof(remote);
+  std::memset(&remote, 0, sizeof(remote));
+
+  int result =
+      recvfrom(m_lsd, reinterpret_cast<char*>(data_received), receive_len, 0,
+               reinterpret_cast<sockaddr*>(&remote), &remote_len);
+
+  char ip[50];
+#ifdef _WIN32
+  InetNtop(PF_INET, &(remote.sin_addr.s_addr), ip, sizeof(ip) - 1);
+#else
+  inet_ntop(PF_INET, reinterpret_cast<in_addr*>(&(remote.sin_addr.s_addr)), ip,
+            sizeof(ip) - 1);
+#endif
+
+  ip[49] = '\0';
+  int addr_len = std::strlen(ip);
+  addr_received->clear();
+  addr_received->append(&ip[0], &ip[addr_len]);
+
+  *port_received = ntohs(remote.sin_port);
+
+  return result;
+}
+
+int UDPClient::set_timeout(double timeout) {
+  if (timeout < 0) return -1;
+  struct timeval tv;
+  tv.tv_sec = timeout;             // truncating will give seconds
+  timeout -= tv.tv_sec;            // remove seconds portion
+  tv.tv_usec = timeout * 1000000;  // fractions of a second to us
+  int ret = setsockopt(m_lsd, SOL_SOCKET, SO_RCVTIMEO,
+                       reinterpret_cast<char*>(&tv), sizeof(tv));
+  if (ret < 0) WPI_ERROR(m_logger, "set timeout failed");
+  return ret;
+}