My Project
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Macros
epollops.c
Go to the documentation of this file.
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 */
26 #include "epollops.h"
27 #include "logging.h"
28 #include <inttypes.h>
29 #include <netinet/in.h>
30 #include <sys/epoll.h>
31 #include <unistd.h>
32 #include <fcntl.h>
33 #include <stdbool.h>
34 
40 #define MAX_EPOLL_EVENTS 512
41 
42 int enable_epoll(int epoll_fd, int new_fd, uint32_t events) {
43  struct epoll_event event;
44  memset(&event, 0, sizeof(event));
45  event.data.fd = new_fd;
46  event.events = events | EPOLLONESHOT;
47 
48  int rtn = epoll_ctl(epoll_fd, EPOLL_CTL_MOD, new_fd, &event);
49 
50  if (rtn == -1) {
51  log(LOG_EPOLL_OPS, "failed to enable fd %d on epoll %d: %s",
52  new_fd, epoll_fd, strerror(errno));
53  return -1;
54  }
55  log(LOG_EPOLL_OPS, "enabled fd %d on epoll", new_fd);
56  return 0;
57 }
58 
59 int add_to_epoll(int epoll_fd, int new_fd, uint32_t events, bool oneshot) {
60  struct epoll_event event;
61  memset(&event, 0, sizeof(event));
62  event.data.fd = new_fd;
63  if (oneshot) {
64  event.events = events | EPOLLONESHOT;
65  } else {
66  event.events = events;
67  }
68 
69  int rtn = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, new_fd, &event);
70 
71  if (rtn == -1) {
72  log(LOG_EPOLL_OPS, "failed to add fd %d on epoll %d: %s",
73  new_fd, epoll_fd, strerror(errno));
74  return -1;
75  }
76  log(LOG_EPOLL_OPS, "Added fd %d to epoll", new_fd);
77  return 0;
78 }
79 
87 static int accept_new_connection(int socketfd, int epoll_fd, int oneshot) {
88  int rtn;
89  log(LOG_EPOLL_OPS, "Accepting a new connection");
90 
91  struct sockaddr_in client_addr;
92  socklen_t addr_len = sizeof(client_addr);
93 
94  int new_fd = accept(socketfd, (struct sockaddr*) &client_addr, &addr_len);
95  if (new_fd == -1) {
96  log_perror("Error accepting new connection from socket handler");
97  return -1;
98  }
99 
101 #ifdef GET_NAME_INFO
102  char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
103  rtn = getnameinfo((struct sockaddr*)&client_addr, addr_len,
104  hbuf, sizeof(hbuf),
105  sbuf, sizeof(sbuf),
106  NI_NUMERICHOST| NI_NUMERICSERV);
107  if ( rtn == 0) {
108  log(LOG_EPOLL_OPS, "Accepted connection on descriptor %d"
109  "host=%s, port=%s",
110  new_fd, hbuf, sbuf);
111  }
112 #endif
113 
114  if (oneshot) {
115  int flags = O_NONBLOCK;;
116  rtn = fcntl(new_fd, F_SETFL, flags);
117  if (rtn == -1) {
118  log_perror("Error setting O_NONBLOCK");
119  // TODO: Error handling :?
120  return -1;
121  }
122  }
123  rtn = add_to_epoll(epoll_fd, new_fd, EPOLLIN, oneshot);
124  if (rtn < 0) {
125  return -1;
126  } else {
127  return new_fd;
128  }
129 }
130 
131 
132 int epoll_loop(int socket_fd, int epoll_fd, int batch_size, int timeout, bool oneshot,
133  int (*connection_handler)(int, void*),
134  int (*accept_handler)(int, void*),
135  void *data) {
136  struct epoll_event events[MAX_EPOLL_EVENTS];
137 
138  for (int j=0; j<batch_size || batch_size == -1; j++) {
139  log(LOG_EPOLL_OPS, "Waiting on epoll");
140  int n = epoll_wait(epoll_fd, events, MAX_EPOLL_EVENTS, timeout);
141  if (n == 0) {
142  break;
143  }
144  log(LOG_EPOLL_OPS, "Epoll returned %d events", n);
145  for (int i=0; i < n; ++i) {
146  if (socket_fd == events[i].data.fd) {
147  log(LOG_EPOLL_OPS, "Accepting connection on %d", socket_fd);
148  int new_fd = accept_new_connection(socket_fd, epoll_fd, oneshot);
149  if ( new_fd < 0) {
150  //log_error("Failed accepting new connection on epoll %d", epoll_fd);
151  return -1;
152  } else {
153  if (accept_handler) {
154  accept_handler(new_fd, data);
155  }
156  log(LOG_EPOLL_OPS, "Accepted new connection");
157  }
158  } else {
159  log(LOG_EPOLL_OPS, "Processing connection (fd: %d)",
160  events[i].data.fd);
161  int rtn = connection_handler(events[i].data.fd, data);
162  if (rtn != 0) {
163  if (rtn < 0) {
164  log_error("Failed processing existing connection (fd: %d)",
165  events[i].data.fd);
166  } else {
167  log(LOG_EPOLL_OPS, "Got exit code %d from fd %d",
168  rtn, events[i].data.fd);
169  }
170  return rtn;
171  } else {
172  log(LOG_EPOLL_OPS, "Processed connection (fd: %d)",
173  events[i].data.fd);
174  }
175  }
176  }
177  }
178  return 0;
179 }
180 
181 
182 int init_epoll(int socket_fd) {
183  int epoll_fd = epoll_create1(0);
184  if (epoll_fd == -1) {
185  log_perror("epoll_create1() failed");
186  return -1;
187  }
188 
189  if (socket_fd > 0) {
190  struct epoll_event event;
191  memset(&event, 0, sizeof(event));
192  event.data.fd = socket_fd;
193  event.events = EPOLLIN;
194 
195  if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, socket_fd, &event) == -1) {
196  log_perror("epoll_ctl() failed to add socket");
197  close(epoll_fd);
198  return -1;
199  }
200  }
201  log(LOG_EPOLL_OPS, "Created epoll fd %d",epoll_fd);
202  return epoll_fd;
203 }
flags
Definition: http_parser.h:234
Wrapper functions for epoll to manage event-based communication.
int epoll_fd
The epoll file descriptor monitoring sockets.
#define log_perror(fmt,...)
Definition: logging.h:102
Logging of status messages to the terminal.
int add_to_epoll(int epoll_fd, int new_fd, uint32_t events, bool oneshot)
Adds a file descriptor to an epoll instance.
Definition: epollops.c:59
int init_epoll(int socket_fd)
Initializes a new instance of an epoll file descriptor and adds a socket to it, listening for input o...
Definition: epollops.c:182
#define log_error(fmt,...)
Definition: logging.h:101
int enable_epoll(int epoll_fd, int new_fd, uint32_t events)
Enables a file descriptor which has already been aded to an epoll instance.
Definition: epollops.c:42
static int accept_new_connection(int socketfd, int epoll_fd, int oneshot)
Accepts a new connection and adds it to the epoll instance.
Definition: epollops.c:87
int epoll_loop(int socket_fd, int epoll_fd, int batch_size, int timeout, bool oneshot, int(*connection_handler)(int, void *), int(*accept_handler)(int, void *), void *data)
The event-based loop for epoll_wait.
Definition: epollops.c:132
unsigned int uint32_t
Definition: uthash.h:96
#define log(level, fmt,...)
Log at a custom level.
Definition: logging.h:147