1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
|
/*
* uhub - A tiny ADC p2p connection hub
* Copyright (C) 2007-2010, Jan Vidar Krey
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "uhub.h"
#ifdef USE_EPOLL
#include "network/connection.h"
#include "network/common.h"
#include "network/backend.h"
#define EPOLL_EVBUFFER 512
struct net_connection_epoll
{
NET_CON_STRUCT_COMMON
struct epoll_event ev;
};
struct net_backend_epoll
{
int epfd;
struct net_connection_epoll** conns;
struct epoll_event events[EPOLL_EVBUFFER];
struct net_backend_common* common;
};
static void net_backend_set_handlers(struct net_backend_handler* handler);
const char* net_backend_name_epoll()
{
return "epoll";
}
int net_backend_poll_epoll(struct net_backend* data, int ms)
{
struct net_backend_epoll* backend = (struct net_backend_epoll*) data;
int res = epoll_wait(backend->epfd, backend->events, MIN(backend->common->num, EPOLL_EVBUFFER), ms);
if (res == -1 && errno == EINTR)
return 0;
return res;
}
void net_backend_process_epoll(struct net_backend* data, int res)
{
int n, ev;
struct net_backend_epoll* backend = (struct net_backend_epoll*) data;
for (n = 0; n < res; n++)
{
struct net_connection_epoll* con = backend->conns[backend->events[n].data.fd];
if (con)
{
ev = 0;
if (backend->events[n].events & EPOLLIN) ev |= NET_EVENT_READ;
if (backend->events[n].events & EPOLLOUT) ev |= NET_EVENT_WRITE;
net_con_callback((struct net_connection*) con, ev);
}
}
}
struct net_connection* net_con_create_epoll(struct net_backend* data)
{
struct net_connection* con = (struct net_connection*) hub_malloc_zero(sizeof(struct net_connection_epoll));
con->sd = -1;
return con;
}
void net_con_initialize_epoll(struct net_backend* data, struct net_connection* con_, int sd, net_connection_cb callback, const void* ptr)
{
struct net_connection_epoll* con = (struct net_connection_epoll*) con_;
con->sd = sd;
con->flags = 0;
con->callback = callback;
con->ev.events = 0;
con->ptr = (void*) ptr;
con->ev.data.fd = sd;
}
void net_con_backend_add_epoll(struct net_backend* data, struct net_connection* con_, int events)
{
struct net_backend_epoll* backend = (struct net_backend_epoll*) data;
struct net_connection_epoll* con = (struct net_connection_epoll*) con_;
backend->conns[con->sd] = con;
if (events & NET_EVENT_READ) con->ev.events |= EPOLLIN;
if (events & NET_EVENT_WRITE) con->ev.events |= EPOLLOUT;
if (epoll_ctl(backend->epfd, EPOLL_CTL_ADD, con->sd, &con->ev) == -1)
{
LOG_TRACE("epoll_ctl() add failed.");
}
}
void net_con_backend_mod_epoll(struct net_backend* data, struct net_connection* con_, int events)
{
struct net_backend_epoll* backend = (struct net_backend_epoll*) data;
struct net_connection_epoll* con = (struct net_connection_epoll*) con_;
int newev = 0;
if (events & NET_EVENT_READ) newev |= EPOLLIN;
if (events & NET_EVENT_WRITE) newev |= EPOLLOUT;
if (newev == con->ev.events)
return;
con->ev.events = newev;
if (epoll_ctl(backend->epfd, EPOLL_CTL_MOD, con->sd, &con->ev) == -1)
{
LOG_TRACE("epoll_ctl() modify failed.");
}
}
void net_con_backend_del_epoll(struct net_backend* data, struct net_connection* con_)
{
struct net_backend_epoll* backend = (struct net_backend_epoll*) data;
struct net_connection_epoll* con = (struct net_connection_epoll*) con_;
backend->conns[con->sd] = 0;
if (epoll_ctl(backend->epfd, EPOLL_CTL_DEL, con->sd, &con->ev) == -1)
{
LOG_WARN("epoll_ctl() delete failed.");
}
}
void net_backend_shutdown_epoll(struct net_backend* data)
{
struct net_backend_epoll* backend = (struct net_backend_epoll*) data;
close(backend->epfd);
hub_free(backend->conns);
hub_free(backend);
}
struct net_backend* net_backend_init_epoll(struct net_backend_handler* handler, struct net_backend_common* common)
{
struct net_backend_epoll* backend;
if (getenv("EVENT_NOEPOLL"))
return 0;
backend = hub_malloc_zero(sizeof(struct net_backend_epoll));
backend->epfd = epoll_create(common->max);
if (backend->epfd == -1)
{
LOG_WARN("Unable to create epoll socket.");
hub_free(backend);
return 0;
}
backend->conns = hub_malloc_zero(sizeof(struct net_connection_epoll*) * common->max);
backend->common = common;
net_backend_set_handlers(handler);
return (struct net_backend*) backend;
}
static void net_backend_set_handlers(struct net_backend_handler* handler)
{
handler->backend_name = net_backend_name_epoll;
handler->backend_poll = net_backend_poll_epoll;
handler->backend_process = net_backend_process_epoll;
handler->backend_shutdown = net_backend_shutdown_epoll;
handler->con_create = net_con_create_epoll;
handler->con_init = net_con_initialize_epoll;
handler->con_add = net_con_backend_add_epoll;
handler->con_mod = net_con_backend_mod_epoll;
handler->con_del = net_con_backend_del_epoll;
}
#endif /* USE_EPOLL */
|