Reorganized sources slightly.
This commit is contained in:
326
src/network/network-epoll.c
Normal file
326
src/network/network-epoll.c
Normal file
@@ -0,0 +1,326 @@
|
||||
/*
|
||||
* uhub - A tiny ADC p2p connection hub
|
||||
* Copyright (C) 2007, 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 HAVE_EPOLL
|
||||
|
||||
// #define DEBUG_EPOLL
|
||||
static struct epoll_event* events = 0;
|
||||
static int epfd = -1;
|
||||
|
||||
#ifdef DEBUG_EPOLL
|
||||
static void dump_listeners()
|
||||
{
|
||||
int i;
|
||||
struct net_event_listener* listener;
|
||||
|
||||
|
||||
hub_log(log_dump, "listeners: number=%d", num_connections);
|
||||
|
||||
for (i = 0; i < num_connections; i++)
|
||||
{
|
||||
listener = &listeners[i];
|
||||
|
||||
if (listener)
|
||||
{
|
||||
if (listener->fd != -1)
|
||||
{
|
||||
hub_log(log_dump, "epoll_dump_listeners: pos=%d/%d fd=%d, ptr=%p", i, num_connections, listeners->fd, listeners);
|
||||
}
|
||||
else
|
||||
{
|
||||
hub_log(log_dump, "epoll_dump_listeners: pos=%d/%d (unused)", i, num_connections);
|
||||
}
|
||||
|
||||
listener = 0;
|
||||
}
|
||||
}
|
||||
|
||||
getc(stdin);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
static void set_poll_events(struct epoll_event* handle, short trigger)
|
||||
{
|
||||
memset(handle, 0, sizeof(struct epoll_event));
|
||||
|
||||
if (trigger & evt_accept || trigger & evt_read || trigger & evt_close)
|
||||
handle->events |= EPOLLIN;
|
||||
|
||||
if (trigger & evt_write)
|
||||
handle->events |= EPOLLOUT;
|
||||
|
||||
if (trigger & evt_urgent)
|
||||
handle->events |= EPOLLPRI;
|
||||
|
||||
#ifdef EPOLLRDHUP
|
||||
if (triggers & evt_close)
|
||||
handle->events |= EPOLLRDHUP;
|
||||
#endif
|
||||
}
|
||||
|
||||
static short get_poll_events(struct epoll_event* handle)
|
||||
{
|
||||
short trig = handle->events;
|
||||
short evt = 0;
|
||||
|
||||
if (trig & EPOLLIN)
|
||||
evt |= evt_read;
|
||||
|
||||
if (trig & EPOLLPRI)
|
||||
evt |= evt_urgent;
|
||||
|
||||
if (trig & EPOLLOUT)
|
||||
evt |= evt_write;
|
||||
|
||||
if (trig & EPOLLHUP)
|
||||
evt |= evt_close;
|
||||
|
||||
if (trig & EPOLLERR)
|
||||
evt |= evt_error;
|
||||
|
||||
#ifdef EPOLLRDHUP
|
||||
if (trig & EPOLLRDHUP)
|
||||
evt |= evt_close;
|
||||
#endif
|
||||
|
||||
return evt;
|
||||
}
|
||||
|
||||
|
||||
int net_initialize(int capacity)
|
||||
{
|
||||
int i;
|
||||
max_connections = capacity;
|
||||
num_connections = 0;
|
||||
epfd = epoll_create(max_connections);
|
||||
if (epfd == -1)
|
||||
{
|
||||
hub_log(log_error, "net_initialize(): epoll_create failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
events = hub_malloc_zero(sizeof(struct epoll_event) * max_connections);
|
||||
if (!events)
|
||||
{
|
||||
hub_log(log_error, "net_initialize(): hub_malloc failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
monitor_allocate((size_t) capacity);
|
||||
|
||||
|
||||
|
||||
#ifdef DEBUG_EPOLL
|
||||
dump_listeners();
|
||||
#endif
|
||||
|
||||
net_stats_initialize();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int net_shutdown()
|
||||
{
|
||||
hub_log(log_trace, "Shutting down network monitor");
|
||||
if (epfd != -1)
|
||||
{
|
||||
close(epfd);
|
||||
}
|
||||
|
||||
hub_free(events);
|
||||
hub_free(listeners);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_EPOLL
|
||||
uint64_t get_time_difference_in_msec(struct timeval before, struct timeval after)
|
||||
{
|
||||
uint64_t seconds = (after.tv_sec - before.tv_sec);
|
||||
uint64_t out = seconds*1000;
|
||||
if (seconds > 0)
|
||||
out += ((after.tv_usec / 1000) + (1000 - (before.tv_usec / 1000)));
|
||||
else
|
||||
out += ((after.tv_usec - before.tv_usec) / 1000);
|
||||
return out;
|
||||
}
|
||||
#endif
|
||||
|
||||
int net_wait(int timeout_ms)
|
||||
{
|
||||
int fired, n, max, ret;
|
||||
struct net_event_listener* listener;
|
||||
|
||||
#ifdef DEBUG_EPOLL
|
||||
struct timeval tm_before;
|
||||
struct timeval tm_after;
|
||||
gettimeofday(&tm_before, NULL);
|
||||
dump_listeners();
|
||||
#endif
|
||||
|
||||
fired = epoll_wait(epfd, events, num_connections, timeout_ms);
|
||||
if (fired == -1) {
|
||||
if (errno != EINTR)
|
||||
{
|
||||
hub_log(log_error, "net_wait(): epoll_wait failed");
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (n = 0; n < fired; n++)
|
||||
{
|
||||
listener = (struct net_event_listener*) events[n].data.ptr;
|
||||
listener->revents = get_poll_events(&events[n]);
|
||||
hub_log(log_dump, "net_wait(): epoll event detected (fd=%d, evt=%d, ptr=%p)", listener->fd, listener->revents, listener);
|
||||
}
|
||||
|
||||
max = num_connections;
|
||||
|
||||
for (n = 0; n < max; n++)
|
||||
{
|
||||
listener = &listeners[n];
|
||||
if (listener && listener->fd != -1 && listener->revents)
|
||||
{
|
||||
hub_log(log_dump, "net_wait(): epoll trigger call (fd=%d, evt=%d, ptr=%p)", listener->fd, listener->revents, listener);
|
||||
ret = listener->handler(listener);
|
||||
listener->revents = 0;
|
||||
}
|
||||
#ifdef DEBUG_EPOLL
|
||||
else
|
||||
{
|
||||
if (listener)
|
||||
hub_log(log_dump, "net_wait(): epoll trigger ignore (fd=%d, evt=%d, ptr=%p)", listener->fd, listener->revents, listener);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef DEBUG_EPOLL
|
||||
gettimeofday(&tm_after, NULL);
|
||||
size_t diff = (size_t) get_time_difference_in_msec(tm_before, tm_after);
|
||||
dump_listeners();
|
||||
hub_log(log_debug, "net_wait(): time=%dms, triggered=%d", diff, fired);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int net_add(int fd, short events, void* data, net_event_handler_t handler)
|
||||
{
|
||||
struct epoll_event ev;
|
||||
struct net_event_listener* listener = monitor_get_free_listener();
|
||||
|
||||
hub_log(log_trace, "net_add(): adding socket (fd=%d, pos=%d)", fd, pos);
|
||||
|
||||
if (!listener)
|
||||
{
|
||||
hub_log(log_error, "net_add(): unable to poll more sockets");
|
||||
return -1;
|
||||
}
|
||||
|
||||
net_event_listener_set(listener, fd, events, data, handler);
|
||||
|
||||
set_poll_events(&ev, events);
|
||||
ev.data.ptr = listener;
|
||||
|
||||
if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev) < 0)
|
||||
{
|
||||
hub_log(log_error, "net_add(): epoll_ctl error while adding socket (fd=%d)", fd);
|
||||
net_event_listener_clear(listener);
|
||||
return -1;
|
||||
}
|
||||
|
||||
num_connections++;
|
||||
|
||||
#ifdef DEBUG_EPOLL
|
||||
dump_listeners();
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int net_modify(int fd, short events)
|
||||
{
|
||||
struct epoll_event ev;
|
||||
struct net_event_listener* listener = monitor_get_listener(fd);
|
||||
hub_log(log_trace, "net_modify(): modifying socket events (fd=%d)", fd);
|
||||
|
||||
if (!listener)
|
||||
{
|
||||
hub_log(log_error, "net_modify(): unable to find socket.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
listener->events = events;
|
||||
set_poll_events(&ev, events);
|
||||
ev.data.ptr = listener;
|
||||
|
||||
if (epoll_ctl(epfd, EPOLL_CTL_MOD, fd, &ev) < 0)
|
||||
{
|
||||
hub_log(log_error, "net_add(): epoll_ctl error while modifying socket (fd=%d)", fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_EPOLL
|
||||
dump_listeners();
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int net_remove(int fd)
|
||||
{
|
||||
struct epoll_event ev;
|
||||
struct net_event_listener* listener = monitor_get_listener(fd);
|
||||
|
||||
hub_log(log_trace, "net_remove(): removing socket (fd=%d, pos=%d)", fd, pos);
|
||||
|
||||
if (!listener)
|
||||
{
|
||||
/* The socket is not being monitored */
|
||||
hub_log(log_error, "net_remove(): unable to remove socket (fd=%d)", fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
net_event_listener_clear(listener);
|
||||
|
||||
if (epoll_ctl(epfd, EPOLL_CTL_DEL, fd, &ev) < 0)
|
||||
{
|
||||
hub_log(log_error, "net_remove(): epoll_ctl error while removing socket (fd=%d)", fd);
|
||||
return -1;
|
||||
}
|
||||
num_connections--;
|
||||
|
||||
#ifdef DEBUG_EPOLL
|
||||
dump_listeners();
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#endif /* HAVE_EPOLL */
|
||||
|
||||
|
||||
|
||||
290
src/network/network-kqueue.c
Normal file
290
src/network/network-kqueue.c
Normal file
@@ -0,0 +1,290 @@
|
||||
/*
|
||||
* uhub - A tiny ADC p2p connection hub
|
||||
* Copyright (C) 2007-2009, 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 HAVE_KQUEUE
|
||||
|
||||
static struct kevent* events = 0;
|
||||
static struct kevent* change = 0;
|
||||
static int kfd = -1;
|
||||
|
||||
|
||||
static void set_poll_events(struct kevent* handle, short trigger)
|
||||
{
|
||||
if (!handle) {
|
||||
hub_log(log_error, "OOOPS!!");
|
||||
return;
|
||||
}
|
||||
|
||||
memset(handle, 0, sizeof(struct kevent));
|
||||
|
||||
if (trigger & evt_accept || trigger & evt_read || trigger & evt_close)
|
||||
handle->filter |= EVFILT_READ;
|
||||
|
||||
if (trigger & evt_write /* || trigger & evt_accept*/)
|
||||
handle->filter |= EVFILT_WRITE;
|
||||
}
|
||||
|
||||
static short get_poll_events(struct kevent* handle)
|
||||
{
|
||||
short trig = handle->flags;
|
||||
short evt = 0;
|
||||
|
||||
if (trig & EVFILT_READ)
|
||||
evt |= evt_read;
|
||||
|
||||
if (trig & EVFILT_WRITE)
|
||||
evt |= evt_write;
|
||||
|
||||
if (trig & EV_EOF)
|
||||
{
|
||||
evt |= evt_close;
|
||||
|
||||
if (handle->fflags)
|
||||
evt |= evt_error;
|
||||
}
|
||||
|
||||
if (handle->filter == -1)
|
||||
{
|
||||
|
||||
evt |= evt_error;
|
||||
}
|
||||
|
||||
if (handle->data)
|
||||
{
|
||||
evt |= evt_accept;
|
||||
}
|
||||
|
||||
if (evt)
|
||||
{
|
||||
hub_log(log_error, "Evt: fd=%d, filter=%d, flags=%d, fflags=%d, data=%d evt=%#x", handle->ident, handle->filter, handle->flags, handle->fflags, (int) handle->data, evt);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
return evt;
|
||||
}
|
||||
|
||||
int net_initialize(int capacity)
|
||||
{
|
||||
int i;
|
||||
max_connections = capacity;
|
||||
num_connections = 0;
|
||||
kfd = kqueue();
|
||||
if (kfd == -1)
|
||||
{
|
||||
hub_log(log_error, "net_initialize(): kqueue failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
events = (void*) hub_malloc_zero(sizeof(struct kevent) * max_connections);
|
||||
if (!events)
|
||||
{
|
||||
hub_log(log_error, "net_initialize(): hub_malloc failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
change = (void*) hub_malloc_zero(sizeof(struct kevent) * max_connections);
|
||||
if (!events)
|
||||
{
|
||||
hub_log(log_error, "net_initialize(): hub_malloc failed");
|
||||
hub_free(events);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
listeners = (void*) hub_malloc_zero(sizeof(struct net_event_listener) * max_connections);
|
||||
if (!listeners)
|
||||
{
|
||||
hub_log(log_error, "net_initialize(): hub_malloc failed");
|
||||
hub_free(change);
|
||||
hub_free(events);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < max_connections; i++)
|
||||
{
|
||||
listeners[i].fd = -1;
|
||||
}
|
||||
|
||||
net_stats_initialize();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int net_shutdown()
|
||||
{
|
||||
if (kfd != -1) {
|
||||
return close(kfd);
|
||||
}
|
||||
|
||||
hub_free(events);
|
||||
hub_free(change);
|
||||
hub_free(listeners);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int net_wait(int timeout_ms)
|
||||
{
|
||||
int fired, n, max, ret;
|
||||
struct net_event_listener* listener;
|
||||
struct timespec timeout = { (timeout_ms / 1000), (timeout_ms % 1000) * 1000 };
|
||||
|
||||
fired = kevent(kfd, events, num_connections, change, num_connections, &timeout);
|
||||
if (fired == -1) {
|
||||
if (errno != EINTR)
|
||||
{
|
||||
hub_log(log_error, "net_wait(): kevent failed");
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (n = 0; n < fired; n++)
|
||||
{
|
||||
listener = (struct net_event_listener*) events[n].udata;
|
||||
if (listener)
|
||||
{
|
||||
listener->revents = get_poll_events(&events[n]);
|
||||
hub_log(log_dump, "net_wait(): kqueue event detected (fd=%d, evt=%d, ptr=%p)", listener->fd, listener->revents, listener);
|
||||
}
|
||||
}
|
||||
|
||||
max = num_connections;
|
||||
for (n = 0; n < max; n++)
|
||||
{
|
||||
listener = &listeners[n];
|
||||
if (listener && listener->fd != -1 && listener->revents != 0)
|
||||
{
|
||||
hub_log(log_dump, "net_wait(): kqueue trigger call (fd=%d, evt=%d, ptr=%p)", listener->fd, listener->revents, listener);
|
||||
ret = listener->handler(listener);
|
||||
listener->revents = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int net_add(int fd, short events_, void* data, net_event_handler_t handler)
|
||||
{
|
||||
struct kevent* event;
|
||||
struct net_event_listener* listener = monitor_get_listener(fd);
|
||||
|
||||
hub_log(log_trace, "net_add(): adding socket (fd=%d)", fd);
|
||||
|
||||
if (listener)
|
||||
{
|
||||
/* Already added! */
|
||||
return -1;
|
||||
}
|
||||
|
||||
listener = monitor_get_free_listener();
|
||||
if (!listener)
|
||||
{
|
||||
hub_log(log_error, "net_add(): unable to poll more sockets");
|
||||
return -1;
|
||||
}
|
||||
|
||||
net_event_listener_set(listener, fd, events_, data, handler);
|
||||
|
||||
event = &events[pos];
|
||||
set_poll_events(event, events_);
|
||||
event->ident = fd;
|
||||
|
||||
event->flags |= EV_ADD;
|
||||
event->flags |= EV_ONESHOT;
|
||||
|
||||
#ifdef __APPLE__
|
||||
event->flags |= EV_ENABLE;
|
||||
#endif
|
||||
event->udata = listener;
|
||||
|
||||
num_connections++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int net_modify(int fd, short events_)
|
||||
{
|
||||
struct kevent* event;
|
||||
struct net_event_listener* listener = monitor_get_listener(fd);
|
||||
|
||||
hub_log(log_trace, "net_modify(): modifying socket (fd=%d)", fd);
|
||||
|
||||
if (!listener)
|
||||
{
|
||||
/* The socket is not being monitored */
|
||||
hub_log(log_error, "net_modify(): unable to find socket (fd=%d)", fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
event = &events[pos];
|
||||
// set_poll_events(event, events_);
|
||||
|
||||
event->ident = fd;
|
||||
event->flags |= EV_ADD;
|
||||
event->flags |= EV_ONESHOT;
|
||||
#ifdef __APPLE__
|
||||
event->flags |= EV_ENABLE;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int net_remove(int fd)
|
||||
{
|
||||
struct kevent* event;
|
||||
struct net_event_listener* listener = monitor_get_listener(fd);
|
||||
|
||||
hub_log(log_trace, "net_remove(): removing socket (fd=%d)", fd);
|
||||
|
||||
if (!listener)
|
||||
{
|
||||
/* The socket is not being monitored */
|
||||
hub_log(log_error, "net_remove(): unable to remove socket (fd=%d)", fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
net_event_listener_clear(listener);
|
||||
|
||||
event = &events[pos];
|
||||
event->ident = fd;
|
||||
event->filter = 0;
|
||||
event->flags = EV_DELETE;
|
||||
|
||||
#ifdef __APPLE__
|
||||
event->flasg |= EV_DISABLE;
|
||||
#endif
|
||||
|
||||
event->fflags = 0;
|
||||
event->data = 0;
|
||||
event->udata = 0;
|
||||
|
||||
num_connections--;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#endif /* HAVE_KQUEUE */
|
||||
|
||||
|
||||
|
||||
688
src/network/network.c
Normal file
688
src/network/network.c
Normal file
@@ -0,0 +1,688 @@
|
||||
/*
|
||||
* uhub - A tiny ADC p2p connection hub
|
||||
* Copyright (C) 2007-2009, 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"
|
||||
|
||||
static int is_ipv6_supported = -1; /* -1 = CHECK, 0 = NO, 1 = YES */
|
||||
static int net_initialized = 0;
|
||||
static struct net_statistics stats;
|
||||
static struct net_statistics stats_total;
|
||||
|
||||
#if defined(IPV6_BINDV6ONLY)
|
||||
#define SOCK_DUAL_STACK_OPT IPV6_BINDV6ONLY
|
||||
#elif defined(IPV6_V6ONLY)
|
||||
#define SOCK_DUAL_STACK_OPT IPV6_V6ONLY
|
||||
#endif
|
||||
|
||||
|
||||
int net_initialize()
|
||||
{
|
||||
if (!net_initialized)
|
||||
{
|
||||
|
||||
#ifdef WINSOCK
|
||||
struct WSAData wsa;
|
||||
if (WSAStartup(MAKEWORD(2, 2), &wsa) != NO_ERROR)
|
||||
{
|
||||
hub_log(log_error, "Unable to initialize winsock.");
|
||||
return -1;
|
||||
}
|
||||
#endif /* WINSOCK */
|
||||
|
||||
hub_log(log_trace, "Initializing network monitor.");
|
||||
net_stats_initialize();
|
||||
|
||||
#ifdef SSL_SUPPORT
|
||||
hub_log(log_trace, "Initializing OpenSSL...");
|
||||
SSL_load_error_strings();
|
||||
SSL_library_init();
|
||||
OpenSSL_add_all_algorithms();
|
||||
#endif /* SSL_SUPPORT */
|
||||
|
||||
net_initialized = 1;
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int net_destroy()
|
||||
{
|
||||
if (net_initialized)
|
||||
{
|
||||
hub_log(log_trace, "Shutting down network monitor");
|
||||
|
||||
#ifdef SSL_SUPPORT
|
||||
/* FIXME: Shutdown OpenSSL here. */
|
||||
#endif
|
||||
|
||||
#ifdef WINSOCK
|
||||
WSACleanup();
|
||||
#endif
|
||||
net_initialized = 0;
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void net_error_out(int fd, const char* func)
|
||||
{
|
||||
int err = net_error();
|
||||
hub_log(log_error, "%s, fd=%d: %s (%d)", func, fd, net_error_string(err), err);
|
||||
}
|
||||
|
||||
int net_error()
|
||||
{
|
||||
#ifdef WINSOCK
|
||||
return WSAGetLastError();
|
||||
#else
|
||||
return errno;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
const char* net_error_string(int code)
|
||||
{
|
||||
#ifdef WINSOCK
|
||||
static char string[32];
|
||||
snprintf(string, 32, "error code: %d", code);
|
||||
return string;
|
||||
#else
|
||||
return strerror(code);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static int net_setsockopt(int fd, int level, int opt, const void* optval, socklen_t optlen)
|
||||
{
|
||||
int ret = -1;
|
||||
#ifdef WINSOCK
|
||||
ret = setsockopt(fd, level, opt, (const char*) optval, optlen);
|
||||
#else
|
||||
ret = setsockopt(fd, level, opt, optval, optlen);
|
||||
#endif
|
||||
|
||||
if (ret == -1)
|
||||
{
|
||||
net_error_out(fd, "net_setsockopt");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int net_getsockopt(int fd, int level, int opt, void* optval, socklen_t* optlen)
|
||||
{
|
||||
int ret = -1;
|
||||
#ifdef WINSOCK
|
||||
ret = getsockopt(fd, level, opt, (char*) optval, optlen);
|
||||
#else
|
||||
ret = getsockopt(fd, level, opt, optval, optlen);
|
||||
#endif
|
||||
|
||||
if (ret == -1)
|
||||
{
|
||||
net_error_out(fd, "net_getsockopt");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int net_set_nonblocking(int fd, int toggle)
|
||||
{
|
||||
int ret = -1;
|
||||
#ifdef WINSOCK
|
||||
u_long on = toggle ? 1 : 0;
|
||||
ret = ioctlsocket(fd, FIONBIO, &on);
|
||||
#else
|
||||
ret = ioctl(fd, FIONBIO, &toggle);
|
||||
#endif
|
||||
if (ret == -1)
|
||||
{
|
||||
net_error_out(fd, "net_set_nonblocking");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* NOTE: Possibly only supported on BSD and OSX? */
|
||||
int net_set_nosigpipe(int fd, int toggle)
|
||||
{
|
||||
int ret = -1;
|
||||
#ifdef SO_NOSIGPIPE
|
||||
ret = net_setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &toggle, sizeof(toggle));
|
||||
if (ret == -1)
|
||||
{
|
||||
net_error_out(fd, "net_set_nosigpipe");
|
||||
}
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
int net_set_close_on_exec(int fd, int toggle)
|
||||
{
|
||||
#ifdef WINSOCK
|
||||
return -1; /* FIXME: How is this done on Windows? */
|
||||
#else
|
||||
return fcntl(fd, F_SETFD, toggle);
|
||||
#endif
|
||||
}
|
||||
|
||||
int net_set_linger(int fd, int toggle)
|
||||
{
|
||||
int ret;
|
||||
ret = net_setsockopt(fd, SOL_SOCKET, SO_LINGER, &toggle, sizeof(toggle));
|
||||
if (ret == -1)
|
||||
{
|
||||
net_error_out(fd, "net_set_linger");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int net_set_keepalive(int fd, int toggle)
|
||||
{
|
||||
int ret;
|
||||
ret = net_setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &toggle, sizeof(toggle));
|
||||
if (ret == -1)
|
||||
{
|
||||
net_error_out(fd, "net_set_keepalive");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int net_set_reuseaddress(int fd, int toggle)
|
||||
{
|
||||
int ret;
|
||||
ret = net_setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &toggle, sizeof(toggle));
|
||||
if (ret == -1)
|
||||
{
|
||||
net_error_out(fd, "net_set_reuseaddress");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int net_set_sendbuf_size(int fd, size_t size)
|
||||
{
|
||||
return net_setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size));
|
||||
}
|
||||
|
||||
int net_get_sendbuf_size(int fd, size_t* size)
|
||||
{
|
||||
socklen_t sz = sizeof(*size);
|
||||
return net_getsockopt(fd, SOL_SOCKET, SO_SNDBUF, size, &sz);
|
||||
}
|
||||
|
||||
int net_set_recvbuf_size(int fd, size_t size)
|
||||
{
|
||||
return net_setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
|
||||
}
|
||||
|
||||
int net_get_recvbuf_size(int fd, size_t* size)
|
||||
{
|
||||
socklen_t sz = sizeof(*size);
|
||||
return net_getsockopt(fd, SOL_SOCKET, SO_RCVBUF, size, &sz);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int net_close(int fd)
|
||||
{
|
||||
#ifdef WINSOCK
|
||||
int ret = closesocket(fd);
|
||||
#else
|
||||
int ret = close(fd);
|
||||
#endif
|
||||
|
||||
if (ret == 0)
|
||||
{
|
||||
net_stats_add_close();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fd != -1)
|
||||
{
|
||||
net_stats_add_error();
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int net_shutdown_r(int fd)
|
||||
{
|
||||
#ifdef WINSOCK
|
||||
return shutdown(fd, SD_RECEIVE);
|
||||
#else
|
||||
return shutdown(fd, SHUT_RD);
|
||||
#endif
|
||||
}
|
||||
|
||||
int net_shutdown_w(int fd)
|
||||
{
|
||||
#ifdef WINSOCK
|
||||
return shutdown(fd, SD_SEND);
|
||||
#else
|
||||
return shutdown(fd, SHUT_WR);
|
||||
#endif
|
||||
}
|
||||
|
||||
int net_shutdown_rw(int fd)
|
||||
{
|
||||
#ifdef WINSOCK
|
||||
return shutdown(fd, SD_BOTH);
|
||||
#else
|
||||
return shutdown(fd, SHUT_RDWR);
|
||||
#endif
|
||||
}
|
||||
|
||||
int net_accept(int fd, struct ip_addr_encap* ipaddr)
|
||||
{
|
||||
struct sockaddr_storage addr;
|
||||
struct sockaddr_in* addr4;
|
||||
struct sockaddr_in6* addr6;
|
||||
socklen_t addr_size;
|
||||
int ret = 0;
|
||||
addr_size = sizeof(struct sockaddr_storage);
|
||||
|
||||
memset(&addr, 0, addr_size);
|
||||
addr4 = (struct sockaddr_in*) &addr;
|
||||
addr6 = (struct sockaddr_in6*) &addr;
|
||||
|
||||
ret = accept(fd, (struct sockaddr*) &addr, &addr_size);
|
||||
|
||||
if (ret == -1)
|
||||
{
|
||||
switch (net_error())
|
||||
{
|
||||
#if defined(__linux__)
|
||||
case ENETDOWN:
|
||||
case EPROTO:
|
||||
case ENOPROTOOPT:
|
||||
case EHOSTDOWN:
|
||||
case ENONET:
|
||||
case EHOSTUNREACH:
|
||||
case EOPNOTSUPP:
|
||||
errno = EWOULDBLOCK;
|
||||
#endif
|
||||
case EWOULDBLOCK:
|
||||
break;
|
||||
default:
|
||||
net_error_out(fd, "net_accept");
|
||||
net_stats_add_error();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
net_stats_add_accept();
|
||||
|
||||
if (ipaddr)
|
||||
{
|
||||
memset(ipaddr, 0, sizeof(struct ip_addr_encap));
|
||||
ipaddr->af = addr4->sin_family;
|
||||
if (ipaddr->af == AF_INET6)
|
||||
{
|
||||
memcpy(&ipaddr->internal_ip_data.in6, &addr6->sin6_addr, sizeof(struct in6_addr));
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(&ipaddr->internal_ip_data.in, &addr4->sin_addr, sizeof(struct in_addr));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int net_connect(int fd, const struct sockaddr *serv_addr, socklen_t addrlen)
|
||||
{
|
||||
int ret = connect(fd, serv_addr, addrlen);
|
||||
if (ret == -1)
|
||||
{
|
||||
if (net_error() != EINPROGRESS)
|
||||
{
|
||||
net_error_out(fd, "net_connect");
|
||||
net_stats_add_error();
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int net_is_ipv6_supported()
|
||||
{
|
||||
if (is_ipv6_supported == -1)
|
||||
{
|
||||
int ret = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
|
||||
if (ret == -1)
|
||||
{
|
||||
#ifdef WINSOCK
|
||||
if (net_error() == WSAEAFNOSUPPORT)
|
||||
#else
|
||||
if (net_error() == EAFNOSUPPORT)
|
||||
#endif
|
||||
{
|
||||
hub_log(log_trace, "net_is_ipv6_supported(): IPv6 is not supported on this system.");
|
||||
is_ipv6_supported = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
net_error_out(ret, "net_is_ipv6_supported");
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef SOCK_DUAL_STACK_OPT
|
||||
int off = 0;
|
||||
if (net_setsockopt(ret, IPPROTO_IPV6, SOCK_DUAL_STACK_OPT, (char*) &off, sizeof(off)) < 0)
|
||||
{
|
||||
hub_log(log_error, "net_socket_create(): Dual stack IPv6/IPv4 is not supported.");
|
||||
is_ipv6_supported = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
is_ipv6_supported = 1;
|
||||
}
|
||||
#else
|
||||
is_ipv6_supported = 0;
|
||||
#endif
|
||||
net_close(ret);
|
||||
}
|
||||
}
|
||||
return is_ipv6_supported;
|
||||
}
|
||||
|
||||
|
||||
int net_socket_create(int af, int type, int protocol)
|
||||
{
|
||||
int sd = socket(af, type, protocol);
|
||||
if (sd == -1)
|
||||
{
|
||||
net_error_out(sd, "net_socket_create");
|
||||
}
|
||||
|
||||
#ifdef SOCK_DUAL_STACK_OPT
|
||||
/* BSD style */
|
||||
if (af == AF_INET6)
|
||||
{
|
||||
int off = 0;
|
||||
if (net_setsockopt(sd, IPPROTO_IPV6, SOCK_DUAL_STACK_OPT, (char*) &off, sizeof(off)) < 0)
|
||||
{
|
||||
hub_log(log_error, "net_socket_create(): Cannot set socket to dual stack mode IPv6/IPv4 (%d - %s).", net_error(), net_error_string(net_error()));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return sd;
|
||||
}
|
||||
|
||||
const char* net_address_to_string(int af, const void* src, char* dst, socklen_t cnt)
|
||||
{
|
||||
#ifdef WINSOCK
|
||||
struct sockaddr_in sin4;
|
||||
struct sockaddr_in6 sin6;
|
||||
struct in_addr* addr4 = (struct in_addr*) src;
|
||||
struct in6_addr* addr6 = (struct in6_addr*) src;
|
||||
size_t size;
|
||||
LPSOCKADDR addr;
|
||||
DWORD len = cnt;
|
||||
|
||||
switch (af)
|
||||
{
|
||||
case AF_INET:
|
||||
sin4.sin_family = AF_INET;
|
||||
sin4.sin_port = 0;
|
||||
sin4.sin_addr = *addr4;
|
||||
size = sizeof(sin4);
|
||||
addr = (LPSOCKADDR) &sin4;
|
||||
break;
|
||||
|
||||
case AF_INET6:
|
||||
sin6.sin6_family = AF_INET6;
|
||||
sin6.sin6_port = 0;
|
||||
sin6.sin6_addr = *addr6;
|
||||
size = sizeof(sin6);
|
||||
addr = (LPSOCKADDR) &sin6;
|
||||
break;
|
||||
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (WSAAddressToString(addr, size, NULL, dst, &len) == 0)
|
||||
{
|
||||
return dst;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
#else
|
||||
return inet_ntop(af, src, dst, cnt);
|
||||
#endif
|
||||
}
|
||||
|
||||
int net_string_to_address(int af, const char* src, void* dst)
|
||||
{
|
||||
#ifdef WINSOCK
|
||||
int ret, size;
|
||||
struct sockaddr_in addr4;
|
||||
struct sockaddr_in6 addr6;
|
||||
struct sockaddr* addr = 0;
|
||||
if (af == AF_INET6)
|
||||
{
|
||||
if (net_is_ipv6_supported() != 1) return -1;
|
||||
size = sizeof(struct sockaddr_in6);
|
||||
addr = (struct sockaddr*) &addr6;
|
||||
}
|
||||
else
|
||||
{
|
||||
size = sizeof(struct sockaddr_in);
|
||||
addr = (struct sockaddr*) &addr4;
|
||||
}
|
||||
|
||||
if (!net_initialized)
|
||||
net_initialize();
|
||||
|
||||
ret = WSAStringToAddressA((char*) src, af, NULL, addr, &size);
|
||||
if (ret == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (af == AF_INET6)
|
||||
{
|
||||
memcpy(dst, &addr6.sin6_addr, sizeof(addr6.sin6_addr));
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(dst, &addr4.sin_addr, sizeof(addr4.sin_addr));
|
||||
}
|
||||
|
||||
return 1;
|
||||
#else
|
||||
return inet_pton(af, src, dst);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
const char* net_get_peer_address(int fd)
|
||||
{
|
||||
static char address[INET6_ADDRSTRLEN+1];
|
||||
struct sockaddr_storage storage;
|
||||
struct sockaddr_in6* name6;
|
||||
struct sockaddr_in* name4;
|
||||
struct sockaddr* name;
|
||||
|
||||
memset(address, 0, INET6_ADDRSTRLEN);
|
||||
socklen_t namelen = sizeof(struct sockaddr_storage);
|
||||
memset(&storage, 0, namelen);
|
||||
|
||||
name6 = (struct sockaddr_in6*) &storage;
|
||||
name4 = (struct sockaddr_in*) &storage;
|
||||
name = (struct sockaddr*) &storage;
|
||||
|
||||
if (getpeername(fd, (struct sockaddr*) name, &namelen) != -1)
|
||||
{
|
||||
int af = name4->sin_family;
|
||||
if (af == AF_INET6)
|
||||
{
|
||||
net_address_to_string(af, (void*) &name6->sin6_addr, address, INET6_ADDRSTRLEN);
|
||||
if (strncmp(address, "::ffff:", 7) == 0) /* IPv6 mapped IPv4 address. */
|
||||
{
|
||||
return &address[7];
|
||||
}
|
||||
return address;
|
||||
}
|
||||
else
|
||||
{
|
||||
net_address_to_string(af, (void*) &name4->sin_addr, address, INET6_ADDRSTRLEN);
|
||||
return address;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
net_error_out(fd, "net_get_peer_address");
|
||||
net_stats_add_error();
|
||||
}
|
||||
|
||||
return "0.0.0.0";
|
||||
}
|
||||
|
||||
|
||||
ssize_t net_recv(int fd, void* buf, size_t len, int flags)
|
||||
{
|
||||
ssize_t ret = recv(fd, buf, len, flags);
|
||||
if (ret >= 0)
|
||||
{
|
||||
net_stats_add_rx(ret);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (net_error() != EWOULDBLOCK)
|
||||
{
|
||||
/* net_error_out(fd, "net_recv"); */
|
||||
net_stats_add_error();
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
ssize_t net_send(int fd, const void* buf, size_t len, int flags)
|
||||
{
|
||||
ssize_t ret = send(fd, buf, len, flags);
|
||||
if (ret >= 0)
|
||||
{
|
||||
net_stats_add_tx(ret);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (net_error() != EWOULDBLOCK)
|
||||
{
|
||||
/* net_error_out(fd, "net_send"); */
|
||||
net_stats_add_error();
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int net_bind(int fd, const struct sockaddr *my_addr, socklen_t addrlen)
|
||||
{
|
||||
int ret = bind(fd, my_addr, addrlen);
|
||||
if (ret == -1)
|
||||
{
|
||||
net_error_out(fd, "net_bind");
|
||||
net_stats_add_error();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int net_listen(int fd, int backlog)
|
||||
{
|
||||
int ret = listen(fd, backlog);
|
||||
if (ret == -1)
|
||||
{
|
||||
net_error_out(fd, "net_listen");
|
||||
net_stats_add_error();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void net_stats_initialize()
|
||||
{
|
||||
memset(&stats_total, 0, sizeof(struct net_statistics));
|
||||
stats_total.timestamp = time(NULL);
|
||||
|
||||
memset(&stats, 0, sizeof(struct net_statistics));
|
||||
stats.timestamp = time(NULL);
|
||||
}
|
||||
|
||||
void net_stats_get(struct net_statistics** intermediate, struct net_statistics** total)
|
||||
{
|
||||
*intermediate = &stats;
|
||||
*total = &stats_total;
|
||||
}
|
||||
|
||||
void net_stats_reset()
|
||||
{
|
||||
stats_total.tx += stats.tx;
|
||||
stats_total.rx += stats.rx;
|
||||
stats_total.accept += stats.accept;
|
||||
stats_total.errors += stats.errors;
|
||||
stats_total.closed += stats.closed;
|
||||
|
||||
memset(&stats, 0, sizeof(struct net_statistics));
|
||||
stats.timestamp = time(NULL);
|
||||
}
|
||||
|
||||
int net_stats_timeout()
|
||||
{
|
||||
return (difftime(time(NULL), stats.timestamp) > TIMEOUT_STATS) ? 1 : 0;
|
||||
}
|
||||
|
||||
void net_stats_add_tx(size_t bytes)
|
||||
{
|
||||
stats.tx += bytes;
|
||||
}
|
||||
|
||||
void net_stats_add_rx(size_t bytes)
|
||||
{
|
||||
stats.rx += bytes;
|
||||
}
|
||||
|
||||
void net_stats_add_accept()
|
||||
{
|
||||
stats.accept++;
|
||||
}
|
||||
|
||||
void net_stats_add_error()
|
||||
{
|
||||
stats.errors++;
|
||||
}
|
||||
|
||||
void net_stats_add_close()
|
||||
{
|
||||
stats.closed++;
|
||||
}
|
||||
|
||||
|
||||
299
src/network/network.h
Normal file
299
src/network/network.h
Normal file
@@ -0,0 +1,299 @@
|
||||
/*
|
||||
* uhub - A tiny ADC p2p connection hub
|
||||
* Copyright (C) 2007-2009, 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef HAVE_UHUB_NETWORK_H
|
||||
#define HAVE_UHUB_NETWORK_H
|
||||
|
||||
struct net_statistics
|
||||
{
|
||||
time_t timestamp;
|
||||
size_t tx;
|
||||
size_t rx;
|
||||
size_t accept;
|
||||
size_t closed;
|
||||
size_t errors;
|
||||
};
|
||||
|
||||
struct net_socket_t;
|
||||
|
||||
#define NET_WANT_READ 0x01
|
||||
#define NET_WANT_WRITE 0x02
|
||||
#define NET_WANT_ACCEPT 0x08
|
||||
#define NET_WANT_SSL_READ 0x10
|
||||
#define NET_WANT_SSL_WRITE 0x20
|
||||
#define NET_WANT_SSL_ACCEPT 0x40
|
||||
#define NET_WANT_SSL_CONNECT 0x40
|
||||
#define NET_WANT_SSL_X509_LOOKUP 0x80
|
||||
|
||||
/**
|
||||
* Initialize the socket monitor subsystem.
|
||||
* On some operating systems this will also involve loading the TCP/IP stack
|
||||
* (needed on Windows at least).
|
||||
*
|
||||
* @param max_connections The maximum number of sockets the monitor can handle.
|
||||
* @return -1 on error, 0 on success
|
||||
*/
|
||||
extern int net_initialize();
|
||||
|
||||
/**
|
||||
* Shutdown the socket monitor.
|
||||
* On some operating systems this will also ensure the TCP/IP stack
|
||||
* is loaded.
|
||||
*
|
||||
* @return -1 on error, 0 on success
|
||||
*/
|
||||
extern int net_destroy();
|
||||
|
||||
/**
|
||||
* @return the number of sockets currrently being monitored.
|
||||
*/
|
||||
extern int net_monitor_count();
|
||||
|
||||
/**
|
||||
* @return the monitor's socket capacity.
|
||||
*/
|
||||
extern int net_monitor_capacity();
|
||||
|
||||
/**
|
||||
* @return the last error code occured.
|
||||
*
|
||||
* NOTE: On Windows this is the last error code from the socket library, but
|
||||
* on UNIX this is the errno variable that can be overwritten by any
|
||||
* libc function.
|
||||
* For this reason, only rely on net_error() immediately after a
|
||||
* socket function call.
|
||||
*/
|
||||
extern int net_error();
|
||||
extern const char* net_error_string(int code);
|
||||
|
||||
/**
|
||||
* A wrapper for the socket() function call.
|
||||
*/
|
||||
extern int net_socket_create(int af, int type, int protocol);
|
||||
|
||||
/**
|
||||
* A wrapper for the close() function call.
|
||||
*/
|
||||
extern int net_close(int fd);
|
||||
|
||||
extern int net_shutdown_r(int fd);
|
||||
extern int net_shutdown_w(int fd);
|
||||
extern int net_shutdown_rw(int fd);
|
||||
|
||||
/**
|
||||
* A wrapper for the accept() function call.
|
||||
* @param fd socket descriptor
|
||||
* @param ipaddr (in/out) if non-NULL the ip address of the
|
||||
* accepted peer is filled in.
|
||||
*/
|
||||
extern int net_accept(int fd, struct ip_addr_encap* ipaddr);
|
||||
|
||||
/**
|
||||
* A wrapper for the connect() call.
|
||||
*/
|
||||
extern int net_connect(int fd, const struct sockaddr *serv_addr, socklen_t addrlen);
|
||||
|
||||
/**
|
||||
* A wrapper for the bind() function call.
|
||||
*/
|
||||
extern int net_bind(int fd, const struct sockaddr *my_addr, socklen_t addrlen);
|
||||
|
||||
/**
|
||||
* A wrapper for the listen() function call.
|
||||
*/
|
||||
extern int net_listen(int sockfd, int backlog);
|
||||
|
||||
/**
|
||||
* This will set the socket to blocking or nonblocking mode.
|
||||
* @param fd socket descriptor
|
||||
* @param toggle if non-zero nonblocking mode, otherwise blocking mode is assumed
|
||||
* @return -1 on error, 0 on success
|
||||
*/
|
||||
extern int net_set_nonblocking(int fd, int toggle);
|
||||
|
||||
/**
|
||||
* This will prevent the socket to generate a SIGPIPE in case the socket goes down.
|
||||
* NOTE: Not all operating systems support this feature. In that case this will return success value.
|
||||
*
|
||||
* @param fd socket descriptor
|
||||
* @param toggle if non-zero ignore sigpipe, otherwise disable it.
|
||||
* @return -1 on error, 0 on success
|
||||
*/
|
||||
extern int net_set_nosigpipe(int fd, int toggle);
|
||||
|
||||
/**
|
||||
* This will set the close-on-exec flag. This means if any subprocess is
|
||||
* started any open file descriptors or sockets will not be inherited if this
|
||||
* is turned on. Otherwise, subprocesses invoked via exec() can read/write
|
||||
* to these sockets.
|
||||
*
|
||||
* @param fd socket descriptor
|
||||
* @param toggle if non-zero close-on-exec is enabled, otherwise disabled.
|
||||
* @return -1 on error, 0 on success.
|
||||
*/
|
||||
extern int net_set_close_on_exec(int fd, int toggle);
|
||||
|
||||
/**
|
||||
* Enable/disable linger on close if data is present.
|
||||
*
|
||||
* @param fd socket descriptor
|
||||
* @param toggle enable if non-zero
|
||||
* @return -1 on error, 0 on success.
|
||||
*/
|
||||
extern int net_set_linger(int fd, int toggle);
|
||||
|
||||
/**
|
||||
* This will set or unset the SO_REUSEADDR flag.
|
||||
* @param fd socket descriptor
|
||||
* @param toggle Set SO_REUSEADDR if non-zero, otherwise unset it.
|
||||
* @return -1 on error, 0 on success
|
||||
*/
|
||||
extern int net_set_reuseaddress(int fd, int toggle);
|
||||
|
||||
/**
|
||||
* Set the send buffer size for the socket.
|
||||
* @param fd socket descriptor
|
||||
* @param size size to set
|
||||
* @return -1 on error, 0 on success.
|
||||
*/
|
||||
extern int net_set_sendbuf_size(int fd, size_t size);
|
||||
|
||||
/**
|
||||
* Get the send buffer size for the socket.
|
||||
* @param fd socket descriptor
|
||||
* @param[out] size existing size, cannot be NULL.
|
||||
* @return -1 on error, 0 on success.
|
||||
*/
|
||||
extern int net_get_sendbuf_size(int fd, size_t* size);
|
||||
|
||||
/**
|
||||
* Set the receive buffer size for the socket.
|
||||
* @param fd socket descriptor
|
||||
* @param size size to set
|
||||
* @return -1 on error, 0 on success.
|
||||
*/
|
||||
extern int net_set_recvbuf_size(int fd, size_t size);
|
||||
|
||||
/**
|
||||
* Get the receive buffer size for the socket.
|
||||
* @param fd socket descriptor
|
||||
* @param[out] size existing size, cannot be NULL.
|
||||
* @return -1 on error, 0 on success.
|
||||
*/
|
||||
extern int net_get_recvbuf_size(int fd, size_t* size);
|
||||
|
||||
/**
|
||||
* A wrapper for the recv() function call.
|
||||
*/
|
||||
extern ssize_t net_recv(int fd, void* buf, size_t len, int flags);
|
||||
|
||||
/**
|
||||
* A wrapper for the send() function call.
|
||||
*/
|
||||
extern ssize_t net_send(int fd, const void* buf, size_t len, int flags);
|
||||
|
||||
/**
|
||||
* This tries to create a AF_INET6 socket.
|
||||
* If it succeeds it concludes IPv6 is supported on the host operating
|
||||
* system. If the call fails with EAFNOSUPPORT the host system
|
||||
* does not support IPv6.
|
||||
* The result is cached so further calls to this function are cheap.
|
||||
*/
|
||||
extern int net_is_ipv6_supported();
|
||||
|
||||
/**
|
||||
* This will return a string containing the peer IP-address of
|
||||
* the connected peer associated with the given socket.
|
||||
*
|
||||
* @param fd socket descriptor
|
||||
* @return IP address (IPv6 or IPv4), or "0.0.0.0" if unable to determine the address.
|
||||
*/
|
||||
extern const char* net_get_peer_address(int fd);
|
||||
|
||||
/**
|
||||
* See man(3) inet_ntop.
|
||||
*/
|
||||
extern const char* net_address_to_string(int af, const void *src, char *dst, socklen_t cnt);
|
||||
|
||||
/**
|
||||
* See man(3) inet_pton.
|
||||
*/
|
||||
extern int net_string_to_address(int af, const char *src, void *dst);
|
||||
|
||||
|
||||
/**
|
||||
* Network statistics monitor.
|
||||
*
|
||||
* Keeps track of bandwidth usage, sockets accepted, closed,
|
||||
* errors etc.
|
||||
*/
|
||||
extern void net_stats_initialize();
|
||||
extern void net_stats_report();
|
||||
extern void net_stats_reset();
|
||||
extern void net_stats_add_tx(size_t bytes);
|
||||
extern void net_stats_add_rx(size_t bytes);
|
||||
extern void net_stats_add_accept();
|
||||
extern void net_stats_add_error();
|
||||
extern void net_stats_add_close();
|
||||
extern int net_stats_timeout();
|
||||
extern void net_stats_get(struct net_statistics** intermediate, struct net_statistics** total);
|
||||
|
||||
|
||||
#if defined(WINSOCK) && !defined(__CYGWIN__)
|
||||
|
||||
#define EWOULDBLOCK WSAEWOULDBLOCK
|
||||
#define EINPROGRESS WSAEINPROGRESS
|
||||
#define EALREADY WSAEALREADY
|
||||
#define ENOTSOCK WSAENOTSOCK
|
||||
#define EDESTADDRREQ WSAEDESTADDRREQ
|
||||
#define EMSGSIZE WSAEMSGSIZE
|
||||
#define EPROTOTYPE WSAEPROTOTYPE
|
||||
#define ENOPROTOOPT WSAENOPROTOOPT
|
||||
#define EPROTONOSUPPORT WSAEPROTONOSUPPORT
|
||||
#define ESOCKTNOSUPPORT WSAESOCKTNOSUPPORT
|
||||
#define EOPNOTSUPP WSAEOPNOTSUPP
|
||||
#define EPFNOSUPPORT WSAEPFNOSUPPORT
|
||||
#define EAFNOSUPPORT WSAEAFNOSUPPORT
|
||||
#define EADDRINUSE WSAEADDRINUSE
|
||||
#define EADDRNOTAVAIL WSAEADDRNOTAVAIL
|
||||
#define ENETDOWN WSAENETDOWN
|
||||
#define ENETUNREACH WSAENETUNREACH
|
||||
#define ENETRESET WSAENETRESET
|
||||
#define ECONNABORTED WSAECONNABORTED
|
||||
#define ECONNRESET WSAECONNRESET
|
||||
#define ENOBUFS WSAENOBUFS
|
||||
#define EISCONN WSAEISCONN
|
||||
#define ENOTCONN WSAENOTCONN
|
||||
#define ESHUTDOWN WSAESHUTDOWN
|
||||
#define ETOOMANYREFS WSAETOOMANYREFS
|
||||
#define ETIMEDOUT WSAETIMEDOUT
|
||||
#define ECONNREFUSED WSAECONNREFUSED
|
||||
#define ELOOP WSAELOOP
|
||||
#define EHOSTDOWN WSAEHOSTDOWN
|
||||
#define EHOSTUNREACH WSAEHOSTUNREACH
|
||||
#define EPROCLIM WSAEPROCLIM
|
||||
#define EUSERS WSAEUSERS
|
||||
#define EDQUOT WSAEDQUOT
|
||||
#define ESTALE WSAESTALE
|
||||
#define EREMOTE WSAEREMOTE
|
||||
|
||||
#endif /* WINSOCK && !__CYGWIN__ */
|
||||
|
||||
|
||||
#endif /* HAVE_UHUB_NETWORK_H */
|
||||
Reference in New Issue
Block a user