Add simple UDP socket wrapper classes
Change-Id: Iad836899a1c91c9a5a7e95ff3cf2d2687a1bbdf8
diff --git a/aos/vision/events/BUILD b/aos/vision/events/BUILD
new file mode 100644
index 0000000..e5be1b0
--- /dev/null
+++ b/aos/vision/events/BUILD
@@ -0,0 +1,19 @@
+cc_library(
+ name = 'udp',
+ srcs = ['udp.cc'],
+ hdrs = ['udp.h'],
+ deps = [
+ '//aos/common:macros',
+ '//aos/common/logging',
+ '//aos/common:scoped_fd',
+ ],
+)
+
+cc_test(
+ name = 'udp_test',
+ srcs = ['udp_test.cc'],
+ deps = [
+ ':udp',
+ '//aos/testing:googletest'
+ ],
+)
diff --git a/aos/vision/events/udp.cc b/aos/vision/events/udp.cc
new file mode 100644
index 0000000..febb835
--- /dev/null
+++ b/aos/vision/events/udp.cc
@@ -0,0 +1,44 @@
+#include "aos/vision/events/udp.h"
+
+#include <string.h>
+
+#include "aos/common/logging/logging.h"
+
+namespace aos {
+namespace vision {
+
+TXUdpSocket::TXUdpSocket(const char *ip_addr, int port)
+ : fd_(PCHECK(socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))) {
+ sockaddr_in destination_in{};
+ destination_in.sin_family = AF_INET;
+ destination_in.sin_port = htons(port);
+ if (inet_aton(ip_addr, &destination_in.sin_addr) == 0) {
+ LOG(FATAL, "invalid IP address %s\n", ip_addr);
+ }
+
+ PCHECK(connect(fd_.get(), reinterpret_cast<sockaddr *>(&destination_in),
+ sizeof(destination_in)));
+}
+
+int TXUdpSocket::Send(const void *data, int size) {
+ return PCHECK(send(fd_.get(), static_cast<const char *>(data), size, 0));
+}
+
+RXUdpSocket::RXUdpSocket(int port)
+ : fd_(PCHECK(socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))) {
+ sockaddr_in bind_address{};
+
+ bind_address.sin_family = AF_INET;
+ bind_address.sin_port = htons(port);
+ bind_address.sin_addr.s_addr = htonl(INADDR_ANY);
+
+ PCHECK(bind(fd_.get(), reinterpret_cast<sockaddr *>(&bind_address),
+ sizeof(bind_address)));
+}
+
+int RXUdpSocket::Recv(void *data, int size) {
+ return PCHECK(recv(fd_.get(), static_cast<char *>(data), size, 0));
+}
+
+} // namespace vision
+} // namespace aos
diff --git a/aos/vision/events/udp.h b/aos/vision/events/udp.h
new file mode 100644
index 0000000..a12a8bf
--- /dev/null
+++ b/aos/vision/events/udp.h
@@ -0,0 +1,51 @@
+#ifndef AOS_VISION_IMAGE_UDP_H_
+#define AOS_VISION_IMAGE_UDP_H_
+
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <math.h>
+#include <unistd.h>
+#include <vector>
+
+#include "aos/common/macros.h"
+#include "aos/common/scoped_fd.h"
+
+namespace aos {
+namespace vision {
+
+// Simple wrapper around a transmitting UDP socket.
+//
+// LOG(FATAL)s for all errors, including from Send.
+class TXUdpSocket {
+ public:
+ TXUdpSocket(const char *ip_addr, int port);
+
+ // Returns the number of bytes actually sent.
+ int Send(const void *data, int size);
+
+ private:
+ ScopedFD fd_;
+
+ DISALLOW_COPY_AND_ASSIGN(TXUdpSocket);
+};
+
+// Simple wrapper around a receiving UDP socket.
+//
+// LOG(FATAL)s for all errors, including from Recv.
+class RXUdpSocket {
+ public:
+ RXUdpSocket(int port);
+
+ // Returns the number of bytes received.
+ int Recv(void *data, int size);
+
+ private:
+ ScopedFD fd_;
+
+ DISALLOW_COPY_AND_ASSIGN(RXUdpSocket);
+};
+
+} // namespace vision
+} // namespace aos
+
+#endif // AOS_VISION_IMAGE_UDP_H_
diff --git a/aos/vision/events/udp_test.cc b/aos/vision/events/udp_test.cc
new file mode 100644
index 0000000..87046ba
--- /dev/null
+++ b/aos/vision/events/udp_test.cc
@@ -0,0 +1,23 @@
+#include "aos/vision/events/udp.h"
+
+#include "gtest/gtest.h"
+
+namespace aos {
+namespace vision {
+
+TEST(UDPTest, SendRecv) {
+ RXUdpSocket rx(1109);
+ TXUdpSocket tx("127.0.0.01", 1109);
+
+ int txdata[] = {1, 2, 3, 4};
+ int rxdata[4];
+ tx.Send(static_cast<const void *>(&txdata), sizeof(txdata));
+ rx.Recv(static_cast<void *>(&rxdata), sizeof(rxdata));
+ EXPECT_EQ(txdata[0], rxdata[0]);
+ EXPECT_EQ(txdata[1], rxdata[1]);
+ EXPECT_EQ(txdata[2], rxdata[2]);
+ EXPECT_EQ(txdata[3], rxdata[3]);
+}
+
+} // namespace vision
+} // namespace aos