TCP server for the vision library.
Change-Id: Id73304cabe3f746d72d51cc7dfe5adbe61c20c16
diff --git a/aos/vision/events/tcp_server.cc b/aos/vision/events/tcp_server.cc
new file mode 100644
index 0000000..06f3a41
--- /dev/null
+++ b/aos/vision/events/tcp_server.cc
@@ -0,0 +1,110 @@
+#include "aos/vision/events/tcp_server.h"
+
+#include <arpa/inet.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "aos/common/logging/logging.h"
+
+namespace aos {
+namespace events {
+
+namespace {
+
+int MakeSocketNonBlocking(int sfd) {
+ int flags;
+
+ PCHECK(flags = fcntl(sfd, F_GETFL, 0));
+
+ flags |= O_NONBLOCK;
+ PCHECK(fcntl(sfd, F_SETFL, flags));
+
+ return 0;
+}
+} // namespace
+
+// This is all copied from somewhere.
+int TCPServerBase::SocketBindListenOnPort(int portno) {
+ int parentfd; /* parent socket */
+ struct sockaddr_in serveraddr; /* server's addr */
+ int optval; /* flag value for setsockopt */
+
+ /*
+ * socket: create the parent socket
+ */
+ PCHECK(parentfd = socket(AF_INET, SOCK_STREAM, 0));
+
+ /* setsockopt: Handy debugging trick that lets
+ * us rerun the server immediately after we kill it;
+ * otherwise we have to wait about 20 secs.
+ * Eliminates "ERROR on binding: Address already in use" error.
+ */
+ optval = 1;
+ PCHECK(setsockopt(parentfd, SOL_SOCKET, SO_REUSEADDR, (const void *)&optval,
+ sizeof(int)));
+
+ /*
+ * build the server's Internet address
+ */
+ bzero((char *)&serveraddr, sizeof(serveraddr));
+
+ /* this is an Internet address */
+ serveraddr.sin_family = AF_INET;
+
+ /* Listen on 0.0.0.0 */
+ serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
+
+ /* this is the port we will listen on */
+ serveraddr.sin_port = htons((uint16_t)portno);
+
+ /*
+ * bind: associate the parent socket with a port
+ */
+ PCHECK(bind(parentfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)));
+
+ PCHECK(listen(parentfd, SOMAXCONN));
+
+ LOG(INFO, "connected to port: %d on fd: %d\n", portno, parentfd);
+ return parentfd;
+}
+
+TCPServerBase::~TCPServerBase() { close(fd()); }
+
+void TCPServerBase::ReadEvent() {
+ /* We have a notification on the listening socket, which
+ means one or more incoming connections. */
+ struct sockaddr in_addr;
+ socklen_t in_len;
+ int infd;
+
+ in_len = sizeof in_addr;
+ infd = accept(fd(), &in_addr, &in_len);
+ if (infd == -1) {
+ if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
+ /* We have processed all incoming
+ connections. */
+ return;
+ } else {
+ PLOG(WARNING, "accept");
+ return;
+ }
+ }
+
+ /* Make the incoming socket non-blocking and add it to the
+ list of fds to monitor. */
+ PCHECK(MakeSocketNonBlocking(infd));
+
+ loop()->Add(Construct(infd));
+}
+
+} // namespace events
+} // namespace aos