Line data Source code
1 : /*
2 : START OF LICENSE STUB
3 : DeDOS: Declarative Dispersion-Oriented Software
4 : Copyright (C) 2017 University of Pennsylvania, Georgetown University
5 :
6 : This program is free software: you can redistribute it and/or modify
7 : it under the terms of the GNU General Public License as published by
8 : the Free Software Foundation, either version 3 of the License, or
9 : (at your option) any later version.
10 :
11 : This program is distributed in the hope that it will be useful,
12 : but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : GNU General Public License for more details.
15 :
16 : You should have received a copy of the GNU General Public License
17 : along with this program. If not, see <http://www.gnu.org/licenses/>.
18 : END OF LICENSE STUB
19 : */
20 : /**
21 : * @file socket_monitor.c
22 : *
23 : * Monitors an incoming port for messages from runtime or controller
24 : */
25 : #include "epollops.h"
26 : #include "communication.h"
27 : #include "logging.h"
28 : #include "controller_communication.h"
29 : #include "runtime_communication.h"
30 :
31 : #include <sys/epoll.h>
32 :
33 : /** The maximum file descriptor that can be associated with a runtime */
34 : #define MAX_RUNTIME_FD 1024
35 : /** Whether the file descriptor has been associated with a runtime */
36 : static bool runtime_fds[MAX_RUNTIME_FD];
37 :
38 : /** The socket on which incoming connections are monitored */
39 : int runtime_socket = -1;
40 : /** The epoll file descriptor monitoring sockets */
41 : int epoll_fd = -1;
42 :
43 : /** Initializes the socket monitor on the given port */
44 0 : static int init_socket_monitor(int port) {
45 0 : if (runtime_socket > 0) {
46 0 : log_error("Runtime socket already initialized to %d. Cannot reinitialize",
47 : runtime_socket);
48 0 : return -1;
49 : }
50 0 : runtime_socket = init_runtime_socket(port);
51 0 : if (runtime_socket < 0) {
52 0 : log_error("Error initializing runtime socket on port %d", port);
53 0 : return -1;
54 : }
55 0 : log_info("Initialized runtime socket on port %d", port);
56 :
57 0 : epoll_fd = init_epoll(runtime_socket);
58 :
59 0 : if (epoll_fd < 0) {
60 0 : log_error("Error initializing runtime epoll. Closing runtime socket.");
61 0 : close(runtime_socket);
62 0 : return -1;
63 : }
64 :
65 0 : return 0;
66 : }
67 :
68 : /** Checks if the file descriptor is a runtime or controller, and handles it appropraitely */
69 0 : static int handle_connection(int fd, void *data) {
70 0 : if (runtime_fds[fd]) {
71 0 : int rtn = handle_runtime_communication(fd);
72 0 : if (rtn != 0) {
73 0 : return rtn;
74 : }
75 0 : return 0;
76 : } else {
77 : // It's a controller file descriptor. Can add check if necessary,
78 : // but this epoll should only handle runtimes or controller
79 0 : int rtn = handle_controller_communication(fd);
80 0 : if (rtn != 0) {
81 0 : return rtn;
82 : }
83 0 : return 0;
84 : }
85 : return 0;
86 : }
87 :
88 : /** Accepts a new connection. Assumes it is a runtime */
89 0 : static int accept_connection(int fd, void *data) {
90 0 : if (fd > MAX_RUNTIME_FD) {
91 0 : log_error("Cannot accept runtime connection on file descriptor greater than %d",
92 : MAX_RUNTIME_FD);
93 : // note: returning 0, not -1, because -1 will make epoll loop exit
94 0 : return 0;
95 : }
96 0 : runtime_fds[fd] = true;
97 0 : return 0;
98 : }
99 :
100 : /** The main loop for the socket monitor. Simply calls epoll_loop */
101 0 : static int socket_monitor_epoll_loop() {
102 0 : if (runtime_socket == -1 || epoll_fd == -1) {
103 0 : log_error("Runtime socket or epoll not initialized. Cannot start monitor loop");
104 0 : return -1;
105 : }
106 :
107 0 : int rtn = epoll_loop(runtime_socket, epoll_fd, -1, -1, 0,
108 : handle_connection, accept_connection, NULL);
109 0 : if (rtn < 0) {
110 0 : log_error("Epoll loop exited with error");
111 : }
112 0 : log_info("Epoll loop exited");
113 0 : return rtn;
114 : }
115 :
116 0 : int monitor_controller_socket(int new_fd) {
117 0 : if ( epoll_fd == -1 ) {
118 0 : log_error("Epoll not initialized. Cannot monitor new socket");
119 0 : return -1;
120 : }
121 :
122 0 : int rtn = add_to_epoll(epoll_fd, new_fd, EPOLLIN, false);
123 0 : if (rtn < 0) {
124 0 : log_perror("Error adding socket %d to epoll", new_fd);
125 0 : return -1;
126 : }
127 0 : return 0;
128 : }
129 :
130 0 : int monitor_runtime_socket(int new_fd) {
131 0 : if ( epoll_fd == -1 ) {
132 0 : log_error("Epoll not initialized. Cannot monitor new socket");
133 0 : return -1;
134 : }
135 :
136 0 : int rtn = add_to_epoll(epoll_fd, new_fd, EPOLLIN, false);
137 0 : runtime_fds[new_fd] = true;
138 0 : if (rtn < 0) {
139 0 : log_perror("Error adding socket %d to epoll", new_fd);
140 0 : return -1;
141 : }
142 0 : return 0;
143 : }
144 :
145 0 : int run_socket_monitor(int local_port, struct sockaddr_in *ctrl_addr) {
146 0 : int rtn = init_socket_monitor(local_port);
147 0 : if (rtn < 0) {
148 0 : log_critical("Error initializing socket monitor");
149 0 : return -1;
150 : }
151 :
152 : int sock;
153 : do {
154 0 : log_info("Attempting to connect to controller");
155 0 : sock = init_controller_socket(ctrl_addr);
156 0 : if (sock < 0)
157 0 : sleep(1);
158 0 : } while (sock <= 0);
159 :
160 0 : log_info("Connected to global controller on socket %d. Entering socket monitor loop.", sock);
161 :
162 0 : return socket_monitor_epoll_loop();
163 : }
|