blob: 06f3a416a15031ba4ccc355a6427435e39afc63d [file] [log] [blame]
Parker Schuhb59bf5e2016-12-28 21:09:36 -08001#include "aos/vision/events/tcp_server.h"
2
3#include <arpa/inet.h>
4#include <errno.h>
5#include <fcntl.h>
6#include <netdb.h>
7#include <netinet/in.h>
8#include <stdio.h>
9#include <stdlib.h>
10#include <string.h>
11#include <sys/epoll.h>
12#include <sys/socket.h>
13#include <sys/types.h>
14#include <unistd.h>
15
16#include "aos/common/logging/logging.h"
17
18namespace aos {
19namespace events {
20
21namespace {
22
23int MakeSocketNonBlocking(int sfd) {
24 int flags;
25
26 PCHECK(flags = fcntl(sfd, F_GETFL, 0));
27
28 flags |= O_NONBLOCK;
29 PCHECK(fcntl(sfd, F_SETFL, flags));
30
31 return 0;
32}
33} // namespace
34
35// This is all copied from somewhere.
36int TCPServerBase::SocketBindListenOnPort(int portno) {
37 int parentfd; /* parent socket */
38 struct sockaddr_in serveraddr; /* server's addr */
39 int optval; /* flag value for setsockopt */
40
41 /*
42 * socket: create the parent socket
43 */
44 PCHECK(parentfd = socket(AF_INET, SOCK_STREAM, 0));
45
46 /* setsockopt: Handy debugging trick that lets
47 * us rerun the server immediately after we kill it;
48 * otherwise we have to wait about 20 secs.
49 * Eliminates "ERROR on binding: Address already in use" error.
50 */
51 optval = 1;
52 PCHECK(setsockopt(parentfd, SOL_SOCKET, SO_REUSEADDR, (const void *)&optval,
53 sizeof(int)));
54
55 /*
56 * build the server's Internet address
57 */
58 bzero((char *)&serveraddr, sizeof(serveraddr));
59
60 /* this is an Internet address */
61 serveraddr.sin_family = AF_INET;
62
63 /* Listen on 0.0.0.0 */
64 serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
65
66 /* this is the port we will listen on */
67 serveraddr.sin_port = htons((uint16_t)portno);
68
69 /*
70 * bind: associate the parent socket with a port
71 */
72 PCHECK(bind(parentfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)));
73
74 PCHECK(listen(parentfd, SOMAXCONN));
75
76 LOG(INFO, "connected to port: %d on fd: %d\n", portno, parentfd);
77 return parentfd;
78}
79
80TCPServerBase::~TCPServerBase() { close(fd()); }
81
82void TCPServerBase::ReadEvent() {
83 /* We have a notification on the listening socket, which
84 means one or more incoming connections. */
85 struct sockaddr in_addr;
86 socklen_t in_len;
87 int infd;
88
89 in_len = sizeof in_addr;
90 infd = accept(fd(), &in_addr, &in_len);
91 if (infd == -1) {
92 if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
93 /* We have processed all incoming
94 connections. */
95 return;
96 } else {
97 PLOG(WARNING, "accept");
98 return;
99 }
100 }
101
102 /* Make the incoming socket non-blocking and add it to the
103 list of fds to monitor. */
104 PCHECK(MakeSocketNonBlocking(infd));
105
106 loop()->Add(Construct(infd));
107}
108
109} // namespace events
110} // namespace aos