2011-12-21 09:55:05 +00:00
|
|
|
/*
|
2014-04-07 05:09:21 +00:00
|
|
|
Serval DNA overlay network interfaces
|
2011-12-21 09:55:05 +00:00
|
|
|
Copyright (C) 2010 Paul Gardner-Stephen
|
2014-04-07 05:09:21 +00:00
|
|
|
Copyright (C) 2012-2013 Serval Project Inc.
|
2011-12-21 09:55:05 +00:00
|
|
|
|
|
|
|
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 2
|
|
|
|
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, write to the Free Software
|
|
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
|
2013-12-11 06:11:57 +00:00
|
|
|
#include <dirent.h>
|
2012-09-05 09:23:22 +00:00
|
|
|
#include <sys/types.h>
|
2013-12-11 06:11:57 +00:00
|
|
|
#include <sys/stat.h>
|
2012-09-05 09:23:22 +00:00
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <arpa/inet.h>
|
2012-06-15 05:34:36 +00:00
|
|
|
#include <assert.h>
|
2012-05-10 04:37:11 +00:00
|
|
|
#include <time.h>
|
2012-12-04 03:42:28 +00:00
|
|
|
#include <fnmatch.h>
|
2012-02-23 02:15:42 +00:00
|
|
|
#include "serval.h"
|
2012-12-04 03:42:28 +00:00
|
|
|
#include "conf.h"
|
2013-11-29 02:26:59 +00:00
|
|
|
#include "net.h"
|
|
|
|
#include "socket.h"
|
2013-12-09 07:15:47 +00:00
|
|
|
#include "overlay_interface.h"
|
2012-06-28 08:04:21 +00:00
|
|
|
#include "strbuf.h"
|
2012-12-04 03:42:28 +00:00
|
|
|
#include "strbuf_helpers.h"
|
2012-08-22 00:51:38 +00:00
|
|
|
#include "overlay_buffer.h"
|
2012-08-27 00:34:59 +00:00
|
|
|
#include "overlay_packet.h"
|
2012-10-31 07:46:05 +00:00
|
|
|
#include "str.h"
|
2013-10-30 06:39:37 +00:00
|
|
|
#include "radio_link.h"
|
2014-08-25 04:54:00 +00:00
|
|
|
#include "server.h"
|
2011-08-08 06:41:05 +00:00
|
|
|
|
2011-08-08 14:41:46 +00:00
|
|
|
#ifdef HAVE_IFADDRS_H
|
|
|
|
#include <ifaddrs.h>
|
|
|
|
#endif
|
|
|
|
|
2014-04-07 06:41:01 +00:00
|
|
|
// The size of the receive buffer. This effectively sets the MRU for packet radio interfaces where
|
|
|
|
// we have to buffer packets on the receive side.
|
|
|
|
#define OVERLAY_INTERFACE_RX_BUFFER_SIZE 2048
|
|
|
|
|
2011-08-08 06:41:05 +00:00
|
|
|
int overlay_ready=0;
|
|
|
|
overlay_interface overlay_interfaces[OVERLAY_MAX_INTERFACES];
|
2012-01-08 17:49:52 +00:00
|
|
|
int overlay_last_interface_number=-1;
|
2011-08-08 06:41:05 +00:00
|
|
|
|
2012-07-02 06:34:00 +00:00
|
|
|
struct profile_total interface_poll_stats;
|
2012-07-02 05:50:30 +00:00
|
|
|
|
2012-08-08 05:27:27 +00:00
|
|
|
struct sched_ent sock_any;
|
2013-12-09 07:15:47 +00:00
|
|
|
struct socket_address sock_any_addr;
|
2012-08-08 05:27:27 +00:00
|
|
|
struct profile_total sock_any_stats;
|
|
|
|
|
2012-08-31 02:41:31 +00:00
|
|
|
static void overlay_interface_poll(struct sched_ent *alarm);
|
2012-10-16 06:16:52 +00:00
|
|
|
|
2015-03-02 05:11:07 +00:00
|
|
|
void overlay_interface_close(overlay_interface *interface)
|
|
|
|
{
|
|
|
|
if (interface->alarm.poll.fd>=0){
|
|
|
|
if (interface->address.addr.sa_family == AF_UNIX)
|
|
|
|
unlink(interface->address.local.sun_path);
|
|
|
|
if (is_watching(&interface->alarm))
|
|
|
|
unwatch(&interface->alarm);
|
|
|
|
close(interface->alarm.poll.fd);
|
|
|
|
interface->alarm.poll.fd=-1;
|
|
|
|
}
|
|
|
|
|
2012-07-25 07:23:44 +00:00
|
|
|
unschedule(&interface->alarm);
|
2013-10-30 06:39:37 +00:00
|
|
|
if (interface->radio_link_state)
|
|
|
|
radio_link_free(interface);
|
2012-07-25 07:23:44 +00:00
|
|
|
interface->state=INTERFACE_STATE_DOWN;
|
2015-03-02 05:11:07 +00:00
|
|
|
|
|
|
|
monitor_tell_formatted(MONITOR_INTERFACE, "\nINTERFACE:%s:DOWN\n", interface->name);
|
|
|
|
INFOF("Interface %s addr %s is down",
|
|
|
|
interface->name, alloca_socket_address(&interface->address));
|
|
|
|
|
|
|
|
link_interface_down(interface);
|
2012-07-25 07:23:44 +00:00
|
|
|
}
|
|
|
|
|
2013-12-11 06:11:57 +00:00
|
|
|
void overlay_interface_close_all()
|
|
|
|
{
|
|
|
|
unsigned i;
|
|
|
|
for (i=0;i<OVERLAY_MAX_INTERFACES;i++){
|
2013-12-13 01:12:01 +00:00
|
|
|
if (overlay_interfaces[i].state == INTERFACE_STATE_UP)
|
2013-12-11 06:11:57 +00:00
|
|
|
overlay_interface_close(&overlay_interfaces[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-13 04:04:10 +00:00
|
|
|
void overlay_interface_monitor_up()
|
|
|
|
{
|
|
|
|
unsigned i;
|
|
|
|
for (i=0;i<OVERLAY_MAX_INTERFACES;i++){
|
|
|
|
if (overlay_interfaces[i].state == INTERFACE_STATE_UP)
|
|
|
|
monitor_tell_formatted(MONITOR_INTERFACE, "\nINTERFACE:%s:UP\n", overlay_interfaces[i].name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-23 01:41:58 +00:00
|
|
|
void interface_state_html(struct strbuf *b, struct overlay_interface *interface)
|
|
|
|
{
|
|
|
|
switch(interface->state){
|
|
|
|
case INTERFACE_STATE_UP:
|
|
|
|
strbuf_sprintf(b, "Interface %s is Up<br>", interface->name);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
strbuf_puts(b, "Interface Down");
|
|
|
|
return;
|
|
|
|
}
|
2015-03-16 01:52:38 +00:00
|
|
|
switch(interface->ifconfig.type){
|
2013-09-23 01:41:58 +00:00
|
|
|
case OVERLAY_INTERFACE_PACKETRADIO:
|
|
|
|
strbuf_puts(b, "Type: Packet Radio<br>");
|
2013-11-25 04:35:33 +00:00
|
|
|
radio_link_state_html(b, interface);
|
2013-09-23 01:41:58 +00:00
|
|
|
break;
|
|
|
|
case OVERLAY_INTERFACE_ETHERNET:
|
|
|
|
strbuf_puts(b, "Type: Ethernet<br>");
|
|
|
|
break;
|
|
|
|
case OVERLAY_INTERFACE_WIFI:
|
|
|
|
strbuf_puts(b, "Type: Wifi<br>");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
case OVERLAY_INTERFACE_UNKNOWN:
|
|
|
|
strbuf_puts(b, "Type: Unknown<br>");
|
|
|
|
}
|
2015-03-16 01:52:38 +00:00
|
|
|
switch(interface->ifconfig.socket_type){
|
2013-09-23 01:41:58 +00:00
|
|
|
case SOCK_STREAM:
|
|
|
|
strbuf_puts(b, "Socket: Stream<br>");
|
|
|
|
break;
|
|
|
|
case SOCK_DGRAM:
|
|
|
|
{
|
|
|
|
strbuf_puts(b, "Socket: DGram<br>");
|
2013-12-09 07:15:47 +00:00
|
|
|
strbuf_sprintf(b, "Address: %s<br>", alloca_socket_address(&interface->address));
|
|
|
|
strbuf_sprintf(b, "Broadcast Address: %s<br>", alloca_socket_address(&interface->destination->address));
|
2013-09-23 01:41:58 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case SOCK_FILE:
|
|
|
|
strbuf_puts(b, "Socket: File<br>");
|
|
|
|
break;
|
2015-03-02 05:11:07 +00:00
|
|
|
case SOCK_EXT:
|
|
|
|
{
|
|
|
|
strbuf_puts(b, "Socket: External<br>");
|
|
|
|
strbuf_sprintf(b, "Client: %s<br>", alloca_socket_address(&interface->address));
|
|
|
|
}
|
|
|
|
break;
|
2013-09-23 01:41:58 +00:00
|
|
|
}
|
|
|
|
strbuf_sprintf(b, "TX: %d<br>", interface->tx_count);
|
|
|
|
strbuf_sprintf(b, "RX: %d<br>", interface->recv_count);
|
|
|
|
}
|
|
|
|
|
2012-08-08 05:27:27 +00:00
|
|
|
// create a socket with options common to all our UDP sockets
|
2012-08-31 02:41:31 +00:00
|
|
|
static int
|
2013-12-09 07:15:47 +00:00
|
|
|
overlay_bind_socket(const struct socket_address *addr){
|
2012-08-08 05:27:27 +00:00
|
|
|
int fd;
|
|
|
|
int reuseP = 1;
|
|
|
|
int broadcastP = 1;
|
2013-12-09 07:15:47 +00:00
|
|
|
int protocol;
|
2012-07-02 03:49:54 +00:00
|
|
|
|
2013-12-09 07:15:47 +00:00
|
|
|
switch(addr->addr.sa_family){
|
|
|
|
case AF_INET:
|
|
|
|
protocol = PF_INET;
|
|
|
|
break;
|
|
|
|
case AF_UNIX:
|
|
|
|
protocol = PF_UNIX;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return WHYF("Unsupported address %s", alloca_socket_address(addr));
|
|
|
|
}
|
|
|
|
|
2014-02-20 04:14:38 +00:00
|
|
|
fd = esocket(protocol, SOCK_DGRAM, 0);
|
2013-12-09 07:15:47 +00:00
|
|
|
if (fd < 0)
|
2014-02-20 04:14:38 +00:00
|
|
|
return -1;
|
2012-08-08 05:27:27 +00:00
|
|
|
|
|
|
|
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuseP, sizeof(reuseP)) < 0) {
|
2012-07-25 07:23:44 +00:00
|
|
|
WHY_perror("setsockopt(SO_REUSEADR)");
|
|
|
|
goto error;
|
|
|
|
}
|
2012-08-08 05:27:27 +00:00
|
|
|
|
|
|
|
#ifdef SO_REUSEPORT
|
|
|
|
if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &reuseP, sizeof(reuseP)) < 0) {
|
|
|
|
WHY_perror("setsockopt(SO_REUSEPORT)");
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &broadcastP, sizeof(broadcastP)) < 0) {
|
2012-07-25 07:23:44 +00:00
|
|
|
WHY_perror("setsockopt(SO_BROADCAST)");
|
2012-06-08 08:59:27 +00:00
|
|
|
goto error;
|
|
|
|
}
|
2012-08-08 05:27:27 +00:00
|
|
|
|
2012-02-23 01:27:46 +00:00
|
|
|
/* Automatically close socket on calls to exec().
|
2012-08-08 05:27:27 +00:00
|
|
|
This makes life easier when we restart with an exec after receiving
|
|
|
|
a bad signal. */
|
2012-09-05 09:23:22 +00:00
|
|
|
fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, NULL) |
|
|
|
|
#ifdef FD_CLOEXEC
|
|
|
|
FD_CLOEXEC
|
|
|
|
#else
|
|
|
|
O_CLOEXEC
|
|
|
|
#endif
|
|
|
|
);
|
2012-08-08 05:27:27 +00:00
|
|
|
|
2014-02-20 04:14:38 +00:00
|
|
|
if (socket_bind(fd, addr))
|
2012-06-08 08:59:27 +00:00
|
|
|
goto error;
|
2012-08-08 05:27:27 +00:00
|
|
|
|
|
|
|
return fd;
|
|
|
|
|
|
|
|
error:
|
|
|
|
close(fd);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-05-01 06:16:47 +00:00
|
|
|
// find an interface marked for use as a default internet route
|
2012-12-07 05:34:40 +00:00
|
|
|
overlay_interface * overlay_interface_get_default(){
|
|
|
|
int i;
|
|
|
|
for (i=0;i<OVERLAY_MAX_INTERFACES;i++){
|
2015-03-16 01:52:38 +00:00
|
|
|
if (overlay_interfaces[i].state==INTERFACE_STATE_UP && overlay_interfaces[i].ifconfig.default_route)
|
2012-12-07 05:34:40 +00:00
|
|
|
return &overlay_interfaces[i];
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2013-12-09 07:15:47 +00:00
|
|
|
// find an interface that can send a packet to this IPv4 address
|
2012-12-07 05:34:40 +00:00
|
|
|
overlay_interface * overlay_interface_find(struct in_addr addr, int return_default){
|
2012-08-30 00:04:52 +00:00
|
|
|
int i;
|
2012-12-04 04:17:57 +00:00
|
|
|
overlay_interface *ret = NULL;
|
2014-10-31 01:44:37 +00:00
|
|
|
|
|
|
|
|
2012-08-30 00:04:52 +00:00
|
|
|
for (i=0;i<OVERLAY_MAX_INTERFACES;i++){
|
|
|
|
if (overlay_interfaces[i].state!=INTERFACE_STATE_UP)
|
|
|
|
continue;
|
2012-12-04 04:17:57 +00:00
|
|
|
|
2013-12-09 07:15:47 +00:00
|
|
|
if (overlay_interfaces[i].address.addr.sa_family == AF_INET
|
|
|
|
&& (overlay_interfaces[i].netmask.s_addr & addr.s_addr) == (overlay_interfaces[i].netmask.s_addr & overlay_interfaces[i].address.inet.sin_addr.s_addr)){
|
2014-10-31 01:44:37 +00:00
|
|
|
|
2015-07-06 08:19:49 +00:00
|
|
|
DEBUGF(overlayinterfaces, "Found interface #%d for in_addr=0x%08x, interface mask=0x%08x, interface addr=0x%08x\n",
|
|
|
|
i,
|
|
|
|
addr.s_addr,
|
|
|
|
overlay_interfaces[i].netmask.s_addr,
|
|
|
|
overlay_interfaces[i].address.inet.sin_addr.s_addr
|
|
|
|
);
|
2014-10-31 01:44:37 +00:00
|
|
|
|
2012-08-30 00:04:52 +00:00
|
|
|
return &overlay_interfaces[i];
|
2014-10-31 01:44:37 +00:00
|
|
|
} else {
|
2015-07-06 08:19:49 +00:00
|
|
|
DEBUGF(overlayinterfaces, "in_addr=0x%08x is not from interface #%d (interface mask=0x%08x, interface addr=0x%08x)\n",
|
|
|
|
addr.s_addr,i,
|
|
|
|
overlay_interfaces[i].netmask.s_addr,
|
|
|
|
overlay_interfaces[i].address.inet.sin_addr.s_addr
|
|
|
|
);
|
2012-08-30 00:04:52 +00:00
|
|
|
}
|
2012-12-04 04:17:57 +00:00
|
|
|
|
|
|
|
// check if this is a default interface
|
2015-03-16 01:52:38 +00:00
|
|
|
if (return_default && overlay_interfaces[i].ifconfig.default_route) {
|
2012-12-04 04:17:57 +00:00
|
|
|
ret=&overlay_interfaces[i];
|
2015-07-06 08:19:49 +00:00
|
|
|
DEBUGF(overlayinterfaces, "in_addr=0x%08x is being deemed to default-route interface #%d (interface mask=0x%08x, interface addr=0x%08x)\n",
|
|
|
|
addr.s_addr,i,
|
|
|
|
overlay_interfaces[i].netmask.s_addr,
|
|
|
|
overlay_interfaces[i].address.inet.sin_addr.s_addr
|
|
|
|
);
|
2014-10-31 01:44:37 +00:00
|
|
|
}
|
2012-08-30 00:04:52 +00:00
|
|
|
}
|
|
|
|
|
2012-12-04 04:17:57 +00:00
|
|
|
return ret;
|
2012-08-30 00:04:52 +00:00
|
|
|
}
|
|
|
|
|
2013-05-01 06:16:47 +00:00
|
|
|
// find an interface by name
|
2012-09-14 02:20:45 +00:00
|
|
|
overlay_interface * overlay_interface_find_name(const char *name){
|
|
|
|
int i;
|
|
|
|
for (i=0;i<OVERLAY_MAX_INTERFACES;i++){
|
|
|
|
if (overlay_interfaces[i].state!=INTERFACE_STATE_UP)
|
|
|
|
continue;
|
2012-12-05 05:17:14 +00:00
|
|
|
if (strcasecmp(name, overlay_interfaces[i].name) == 0)
|
2012-09-14 02:20:45 +00:00
|
|
|
return &overlay_interfaces[i];
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2015-03-02 05:11:07 +00:00
|
|
|
// find an interface by name and address
|
|
|
|
overlay_interface * overlay_interface_find_name_addr(const char *name, struct socket_address *addr){
|
|
|
|
int i;
|
|
|
|
for(i = 0; i < OVERLAY_MAX_INTERFACES; i++){
|
|
|
|
if (overlay_interfaces[i].state==INTERFACE_STATE_DOWN)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (cmp_sockaddr(addr, &overlay_interfaces[i].address)==0
|
|
|
|
&& (!name || strcasecmp(overlay_interfaces[i].name, name)==0)){
|
|
|
|
return &overlay_interfaces[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2013-05-01 06:16:47 +00:00
|
|
|
static int interface_type_priority(int type)
|
|
|
|
{
|
|
|
|
switch(type){
|
|
|
|
case OVERLAY_INTERFACE_ETHERNET:
|
|
|
|
return 1;
|
|
|
|
case OVERLAY_INTERFACE_WIFI:
|
|
|
|
return 2;
|
|
|
|
case OVERLAY_INTERFACE_PACKETRADIO:
|
|
|
|
return 4;
|
|
|
|
}
|
|
|
|
return 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Which interface is better for routing packets?
|
2013-08-08 05:50:31 +00:00
|
|
|
// returns -1 to indicate the first is better, 0 for equal, 1 for the second
|
2013-05-01 06:16:47 +00:00
|
|
|
int overlay_interface_compare(overlay_interface *one, overlay_interface *two)
|
|
|
|
{
|
|
|
|
if (one==two)
|
|
|
|
return 0;
|
2015-03-16 01:52:38 +00:00
|
|
|
int p1 = interface_type_priority(one->ifconfig.type);
|
|
|
|
int p2 = interface_type_priority(two->ifconfig.type);
|
2013-05-01 06:16:47 +00:00
|
|
|
if (p1<p2)
|
2013-08-08 05:50:31 +00:00
|
|
|
return -1;
|
2013-05-01 06:16:47 +00:00
|
|
|
if (p2<p1)
|
|
|
|
return 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-08-08 05:27:27 +00:00
|
|
|
// OSX doesn't recieve broadcast packets on sockets bound to an interface's address
|
|
|
|
// So we have to bind a socket to INADDR_ANY to receive these packets.
|
2012-08-31 02:41:31 +00:00
|
|
|
static void
|
2013-11-29 02:26:59 +00:00
|
|
|
overlay_interface_read_any(struct sched_ent *alarm)
|
|
|
|
{
|
2012-08-22 05:20:14 +00:00
|
|
|
if (alarm->poll.revents & POLLIN) {
|
|
|
|
int plen=0;
|
|
|
|
int recvttl=1;
|
|
|
|
unsigned char packet[16384];
|
|
|
|
overlay_interface *interface=NULL;
|
2013-11-29 02:26:59 +00:00
|
|
|
struct socket_address recvaddr;
|
|
|
|
recvaddr.addrlen = sizeof recvaddr.store;
|
2012-08-27 00:34:59 +00:00
|
|
|
|
2012-08-22 05:20:14 +00:00
|
|
|
/* Read only one UDP packet per call to share resources more fairly, and also
|
|
|
|
enable stats to accurately count packets received */
|
2013-11-29 02:26:59 +00:00
|
|
|
plen = recvwithttl(alarm->poll.fd, packet, sizeof(packet), &recvttl, &recvaddr);
|
2012-08-22 05:20:14 +00:00
|
|
|
if (plen == -1) {
|
2013-11-30 19:14:01 +00:00
|
|
|
WHYF_perror("recvwithttl(%d,%p,%zu,&%d,%p(%s))",
|
|
|
|
alarm->poll.fd, packet, sizeof packet, recvttl,
|
|
|
|
&recvaddr, alloca_socket_address(&recvaddr)
|
|
|
|
);
|
2012-08-22 05:20:14 +00:00
|
|
|
unwatch(alarm);
|
|
|
|
close(alarm->poll.fd);
|
|
|
|
return;
|
|
|
|
}
|
2012-08-27 00:34:59 +00:00
|
|
|
|
2012-08-22 05:20:14 +00:00
|
|
|
/* Try to identify the real interface that the packet arrived on */
|
2013-11-29 02:26:59 +00:00
|
|
|
interface = overlay_interface_find(recvaddr.inet.sin_addr, 0);
|
2012-08-27 00:34:59 +00:00
|
|
|
|
2012-08-30 00:04:52 +00:00
|
|
|
/* Drop the packet if we don't find a match */
|
2012-08-22 05:20:14 +00:00
|
|
|
if (!interface){
|
2015-07-06 08:19:49 +00:00
|
|
|
DEBUGF(overlayinterfaces, "Could not find matching interface for packet received from %s", inet_ntoa(recvaddr.inet.sin_addr));
|
2012-08-22 05:20:14 +00:00
|
|
|
return;
|
|
|
|
}
|
2013-12-09 07:52:18 +00:00
|
|
|
packetOkOverlay(interface, packet, plen, &recvaddr);
|
2012-08-22 05:20:14 +00:00
|
|
|
}
|
|
|
|
if (alarm->poll.revents & (POLLHUP | POLLERR)) {
|
|
|
|
INFO("Closing broadcast socket due to error");
|
|
|
|
unwatch(alarm);
|
|
|
|
close(alarm->poll.fd);
|
|
|
|
alarm->poll.fd=-1;
|
2012-08-27 00:34:59 +00:00
|
|
|
}
|
2012-08-08 05:27:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// bind a socket to INADDR_ANY:port
|
|
|
|
// for now, we don't have a graceful close for this interface but it should go away when the process dies
|
2012-12-04 03:42:28 +00:00
|
|
|
static int overlay_interface_init_any(int port)
|
|
|
|
{
|
2012-08-08 05:27:27 +00:00
|
|
|
if (sock_any.poll.fd>0){
|
2012-08-24 05:51:23 +00:00
|
|
|
// Check the port number matches
|
2013-12-09 07:15:47 +00:00
|
|
|
if (sock_any_addr.inet.sin_port != htons(port))
|
|
|
|
return WHYF("Unable to listen to broadcast packets for ports %d & %d",
|
|
|
|
port, ntohs(sock_any_addr.inet.sin_port));
|
2012-08-24 05:51:23 +00:00
|
|
|
|
2012-08-08 05:27:27 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2013-12-09 07:15:47 +00:00
|
|
|
sock_any_addr.addrlen = sizeof(sock_any_addr.inet);
|
|
|
|
sock_any_addr.inet.sin_family = AF_INET;
|
|
|
|
sock_any_addr.inet.sin_port = htons(port);
|
|
|
|
sock_any_addr.inet.sin_addr.s_addr = INADDR_ANY;
|
2012-08-24 05:51:23 +00:00
|
|
|
|
2013-12-09 07:15:47 +00:00
|
|
|
sock_any.poll.fd = overlay_bind_socket(&sock_any_addr);
|
2012-08-08 05:27:27 +00:00
|
|
|
if (sock_any.poll.fd<0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
sock_any.poll.events=POLLIN;
|
|
|
|
sock_any.function = overlay_interface_read_any;
|
|
|
|
|
|
|
|
sock_any_stats.name="overlay_interface_read_any";
|
|
|
|
sock_any.stats=&sock_any_stats;
|
|
|
|
watch(&sock_any);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-03-23 03:03:15 +00:00
|
|
|
static void calc_next_tick(struct overlay_interface *interface)
|
|
|
|
{
|
|
|
|
time_ms_t interval = interface->destination->ifconfig.tick_ms;
|
|
|
|
// only tick every 5s if we have no neighbours here
|
|
|
|
if (interval < 5000 && !link_interface_has_neighbours(interface))
|
|
|
|
interval = 5000;
|
|
|
|
|
|
|
|
time_ms_t next_tick = interface->destination->last_tx+interval;
|
2015-03-30 06:00:10 +00:00
|
|
|
if (!interface->destination->ifconfig.tick_ms){
|
|
|
|
next_tick=TIME_MS_NEVER_WILL;
|
|
|
|
}
|
2015-03-23 03:03:15 +00:00
|
|
|
time_ms_t next_allowed = limit_next_allowed(&interface->destination->transfer_limit);
|
|
|
|
if (next_tick < next_allowed)
|
|
|
|
next_tick = next_allowed;
|
|
|
|
|
2015-03-30 06:00:10 +00:00
|
|
|
if (interface->ifconfig.socket_type==SOCK_FILE){
|
|
|
|
time_ms_t next_read = gettime_ms()+10;
|
|
|
|
if (next_tick > next_read)
|
|
|
|
next_tick = next_read;
|
|
|
|
}
|
|
|
|
|
2015-03-23 03:03:15 +00:00
|
|
|
interface->alarm.alarm = next_tick;
|
|
|
|
interface->alarm.deadline=interface->alarm.alarm+interface->destination->ifconfig.tick_ms/2;
|
|
|
|
}
|
|
|
|
|
2012-08-31 02:41:31 +00:00
|
|
|
static int
|
2013-12-11 06:11:57 +00:00
|
|
|
overlay_interface_init_socket(overlay_interface *interface)
|
2012-08-08 05:27:27 +00:00
|
|
|
{
|
|
|
|
/*
|
2012-09-11 05:50:44 +00:00
|
|
|
On linux you can bind to the broadcast address to receive broadcast packets per interface [or subnet],
|
|
|
|
but then you can't receive unicast packets on the same socket.
|
|
|
|
|
|
|
|
On osx, you can only receive broadcast packets if you bind to INADDR_ANY.
|
|
|
|
|
|
|
|
So the most portable way to do this is to bind to each interface's IP address for sending broadcasts
|
|
|
|
and receiving unicasts, and bind a separate socket to INADDR_ANY just for receiving broadcast packets.
|
|
|
|
|
|
|
|
Sending packets from INADDR_ANY would probably work, but gives us less control over which interfaces are sending packets.
|
|
|
|
But there may be some platforms that need some other combination for everything to work.
|
2012-08-08 05:27:27 +00:00
|
|
|
*/
|
2012-09-11 05:50:44 +00:00
|
|
|
|
2015-03-16 01:52:38 +00:00
|
|
|
overlay_interface_init_any(interface->ifconfig.port);
|
2012-09-11 05:50:44 +00:00
|
|
|
|
2013-12-09 07:15:47 +00:00
|
|
|
interface->alarm.poll.fd = overlay_bind_socket(&interface->address);
|
2013-08-08 05:50:31 +00:00
|
|
|
|
2012-08-08 05:27:27 +00:00
|
|
|
if (interface->alarm.poll.fd<0){
|
|
|
|
interface->state=INTERFACE_STATE_DOWN;
|
2013-02-15 05:31:04 +00:00
|
|
|
return WHYF("Failed to bind interface %s", interface->name);
|
2012-08-08 05:27:27 +00:00
|
|
|
}
|
|
|
|
|
2015-07-06 08:19:49 +00:00
|
|
|
DEBUGF2(packetrx, io, "Bound to %s", alloca_socket_address(&interface->address));
|
2011-08-08 06:41:05 +00:00
|
|
|
|
2012-07-31 08:19:24 +00:00
|
|
|
interface->alarm.poll.events=POLLIN;
|
|
|
|
watch(&interface->alarm);
|
2012-09-14 02:20:45 +00:00
|
|
|
|
2011-08-12 07:47:29 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-03-16 01:52:38 +00:00
|
|
|
int overlay_destination_configure(struct network_destination *dest, const struct config_mdp_iftype *ifconfig)
|
2011-08-12 07:47:29 +00:00
|
|
|
{
|
2015-03-16 01:52:38 +00:00
|
|
|
dest->ifconfig = *ifconfig;
|
2012-12-04 03:42:28 +00:00
|
|
|
// How often do we announce ourselves on this interface?
|
2013-02-14 03:48:56 +00:00
|
|
|
int tick_ms=-1;
|
2012-12-13 07:20:09 +00:00
|
|
|
int packet_interval=-1;
|
2015-03-16 01:52:38 +00:00
|
|
|
|
2012-12-13 07:20:09 +00:00
|
|
|
// hard coded defaults:
|
2015-03-16 01:52:38 +00:00
|
|
|
switch(dest->interface->ifconfig.type){
|
2012-12-04 03:42:28 +00:00
|
|
|
case OVERLAY_INTERFACE_PACKETRADIO:
|
2013-02-14 03:48:56 +00:00
|
|
|
tick_ms = 15000;
|
2012-12-13 07:20:09 +00:00
|
|
|
packet_interval = 1000;
|
2012-12-04 03:42:28 +00:00
|
|
|
break;
|
|
|
|
case OVERLAY_INTERFACE_ETHERNET:
|
2013-02-14 03:48:56 +00:00
|
|
|
tick_ms = 500;
|
2012-12-13 07:20:09 +00:00
|
|
|
packet_interval = 100;
|
2012-12-04 03:42:28 +00:00
|
|
|
break;
|
|
|
|
case OVERLAY_INTERFACE_WIFI:
|
2013-02-14 03:48:56 +00:00
|
|
|
tick_ms = 500;
|
2014-02-28 18:58:54 +00:00
|
|
|
packet_interval = 800;
|
2012-12-04 03:42:28 +00:00
|
|
|
break;
|
|
|
|
case OVERLAY_INTERFACE_UNKNOWN:
|
2013-02-14 03:48:56 +00:00
|
|
|
tick_ms = 500;
|
2012-12-13 07:20:09 +00:00
|
|
|
packet_interval = 100;
|
2012-12-04 03:42:28 +00:00
|
|
|
break;
|
2012-12-13 07:20:09 +00:00
|
|
|
}
|
|
|
|
|
2015-03-16 01:52:38 +00:00
|
|
|
if (dest->ifconfig.tick_ms<0)
|
|
|
|
dest->ifconfig.tick_ms = tick_ms;
|
|
|
|
if (dest->ifconfig.packet_interval<0)
|
|
|
|
dest->ifconfig.packet_interval = packet_interval;
|
|
|
|
|
|
|
|
if (dest->ifconfig.packet_interval<0)
|
|
|
|
return WHYF("Invalid packet interval %d specified for destination",
|
|
|
|
dest->ifconfig.packet_interval);
|
|
|
|
if (dest->ifconfig.packet_interval==0){
|
|
|
|
INFOF("Destination is not sending any traffic!");
|
|
|
|
dest->ifconfig.tick_ms=0;
|
|
|
|
}else if (!dest->ifconfig.send){
|
|
|
|
INFOF("Destination is not sending any traffic!");
|
2015-03-23 03:03:15 +00:00
|
|
|
dest->ifconfig.tick_ms=0;
|
2015-03-16 01:52:38 +00:00
|
|
|
}else if (dest->ifconfig.tick_ms==0)
|
|
|
|
INFOF("Destination is running tickless");
|
2012-12-13 07:20:09 +00:00
|
|
|
|
2015-03-16 01:52:38 +00:00
|
|
|
if (dest->ifconfig.tick_ms<0)
|
|
|
|
return WHYF("No tick interval specified for destination");
|
|
|
|
|
|
|
|
if (dest->ifconfig.reachable_timeout_ms<0)
|
|
|
|
dest->ifconfig.reachable_timeout_ms = tick_ms>0 ? tick_ms * 5 : 2500;
|
2013-02-14 03:48:56 +00:00
|
|
|
|
2015-03-16 01:52:38 +00:00
|
|
|
|
|
|
|
limit_init(&dest->transfer_limit, dest->ifconfig.packet_interval);
|
2015-03-02 05:11:07 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-03-16 01:52:38 +00:00
|
|
|
int overlay_interface_configure(struct overlay_interface *interface, const struct config_network_interface *ifconfig)
|
|
|
|
{
|
|
|
|
// copy ifconfig values
|
|
|
|
interface->ifconfig = *ifconfig;
|
|
|
|
overlay_destination_configure(interface->destination, &interface->ifconfig.broadcast);
|
|
|
|
|
|
|
|
if (ifconfig->socket_type==SOCK_STREAM)
|
|
|
|
interface->ifconfig.unicast.send=0;
|
2015-03-23 03:03:15 +00:00
|
|
|
|
|
|
|
// schedule the first tick asap
|
|
|
|
unschedule(&interface->alarm);
|
|
|
|
calc_next_tick(interface);
|
|
|
|
schedule(&interface->alarm);
|
|
|
|
|
2015-03-16 01:52:38 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-03-02 05:11:07 +00:00
|
|
|
/* Returns 0 if interface is successfully added.
|
|
|
|
* Returns 1 if interface is not added (eg, dummy file does not exist).
|
|
|
|
* Returns -1 in case of error (misconfiguration or system error).
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
overlay_interface_init(const char *name, struct socket_address *addr,
|
|
|
|
struct socket_address *netmask,
|
|
|
|
struct socket_address *broadcast,
|
|
|
|
const struct config_network_interface *ifconfig)
|
|
|
|
{
|
|
|
|
int cleanup_ret = -1;
|
|
|
|
|
|
|
|
int interface_id=-1;
|
|
|
|
int i;
|
|
|
|
for (i=0; i<OVERLAY_MAX_INTERFACES; i++){
|
|
|
|
if (overlay_interfaces[i].state==INTERFACE_STATE_DOWN){
|
|
|
|
interface_id=i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (interface_id==-1)
|
|
|
|
return WHY("Too many interfaces -- Increase OVERLAY_MAX_INTERFACES");
|
|
|
|
|
|
|
|
overlay_interface *const interface = &overlay_interfaces[interface_id];
|
|
|
|
|
|
|
|
bzero(interface, sizeof(overlay_interface));
|
|
|
|
interface->state=INTERFACE_STATE_DOWN;
|
|
|
|
|
|
|
|
strncpy(interface->name, name, sizeof interface->name);
|
|
|
|
|
|
|
|
set_destination_ref(&interface->destination, NULL);
|
|
|
|
interface->destination = new_destination(interface);
|
|
|
|
|
|
|
|
interface->alarm.poll.fd=0;
|
|
|
|
interface->tx_count=0;
|
|
|
|
interface->recv_count=0;
|
2013-01-29 00:57:13 +00:00
|
|
|
|
2013-12-11 06:11:57 +00:00
|
|
|
if (addr)
|
|
|
|
interface->address = *addr;
|
|
|
|
if (broadcast)
|
|
|
|
interface->destination->address = *broadcast;
|
2013-02-14 03:48:56 +00:00
|
|
|
interface->alarm.function = overlay_interface_poll;
|
|
|
|
interface_poll_stats.name="overlay_interface_poll";
|
|
|
|
interface->alarm.stats=&interface_poll_stats;
|
|
|
|
|
2015-03-23 03:03:15 +00:00
|
|
|
if (overlay_interface_configure(interface, ifconfig)==-1)
|
|
|
|
return -1;
|
|
|
|
|
2015-03-02 05:11:07 +00:00
|
|
|
switch(ifconfig->socket_type){
|
|
|
|
case SOCK_DGRAM:
|
2015-03-16 01:52:38 +00:00
|
|
|
if (ifconfig->broadcast.drop || ifconfig->unicast.drop || ifconfig->drop_packets)
|
2015-03-02 05:11:07 +00:00
|
|
|
FATALF("Invalid interface definition. We only support dropping packets on dummy file interfaces");
|
|
|
|
if (netmask)
|
|
|
|
interface->netmask = netmask->inet.sin_addr;
|
|
|
|
else
|
|
|
|
interface->netmask = ifconfig->dummy_netmask;
|
|
|
|
interface->local_echo = 1;
|
|
|
|
|
|
|
|
if (overlay_interface_init_socket(interface))
|
|
|
|
return WHY("overlay_interface_init_socket() failed");
|
2013-04-15 07:00:07 +00:00
|
|
|
break;
|
2015-03-02 05:11:07 +00:00
|
|
|
|
|
|
|
case SOCK_EXT:
|
|
|
|
interface->local_echo = 0;
|
|
|
|
interface->alarm.poll.fd = -1;
|
2013-04-15 07:00:07 +00:00
|
|
|
break;
|
2015-03-02 05:11:07 +00:00
|
|
|
|
|
|
|
case SOCK_STREAM:
|
|
|
|
case SOCK_FILE:
|
|
|
|
{
|
|
|
|
char read_file[1024];
|
2015-03-16 01:52:38 +00:00
|
|
|
interface->local_echo = ifconfig->point_to_point?0:1;
|
2015-03-02 05:11:07 +00:00
|
|
|
if (!FORMF_SERVAL_TMP_PATH(read_file, "%s/%s", config.server.interface_path, ifconfig->file))
|
|
|
|
return -1;
|
|
|
|
if ((interface->alarm.poll.fd = open(read_file, O_APPEND|O_RDWR)) == -1) {
|
|
|
|
if (errno == ENOENT && ifconfig->socket_type == SOCK_FILE) {
|
|
|
|
cleanup_ret = 1;
|
|
|
|
WARNF("dummy interface not enabled: %s does not exist", alloca_str_toprint(read_file));
|
|
|
|
} else {
|
|
|
|
cleanup_ret = WHYF_perror("file interface not enabled: open(%s, O_APPEND|O_RDWR)", alloca_str_toprint(read_file));
|
|
|
|
}
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ifconfig->type==OVERLAY_INTERFACE_PACKETRADIO)
|
|
|
|
overlay_packetradio_setup_port(interface);
|
|
|
|
|
|
|
|
switch (ifconfig->socket_type) {
|
|
|
|
case SOCK_STREAM:
|
|
|
|
radio_link_init(interface);
|
|
|
|
interface->alarm.poll.events=POLLIN|POLLOUT;
|
|
|
|
watch(&interface->alarm);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SOCK_FILE:
|
|
|
|
/* Seek to end of file as initial reading point */
|
|
|
|
interface->recv_offset = lseek(interface->alarm.poll.fd,0,SEEK_END);
|
|
|
|
break;
|
|
|
|
}
|
2013-02-04 11:36:49 +00:00
|
|
|
}
|
2011-08-13 11:17:49 +00:00
|
|
|
}
|
2013-02-14 03:48:56 +00:00
|
|
|
|
|
|
|
interface->state=INTERFACE_STATE_UP;
|
2014-06-13 04:04:10 +00:00
|
|
|
monitor_tell_formatted(MONITOR_INTERFACE, "\nINTERFACE:%s:UP\n", interface->name);
|
2013-12-09 07:15:47 +00:00
|
|
|
INFOF("Interface %s addr %s, is up",interface->name, alloca_socket_address(addr));
|
2013-02-14 03:48:56 +00:00
|
|
|
|
|
|
|
directory_registration();
|
|
|
|
|
2013-10-09 00:01:52 +00:00
|
|
|
INFOF("Allowing a maximum of %d packets every %"PRId64"ms",
|
2013-08-08 05:50:31 +00:00
|
|
|
interface->destination->transfer_limit.burst_size,
|
|
|
|
interface->destination->transfer_limit.burst_length);
|
2011-08-12 07:47:29 +00:00
|
|
|
|
2011-08-08 06:41:05 +00:00
|
|
|
return 0;
|
2013-02-14 03:48:56 +00:00
|
|
|
|
|
|
|
cleanup:
|
|
|
|
if (interface->alarm.poll.fd>=0){
|
|
|
|
unwatch(&interface->alarm);
|
|
|
|
close(interface->alarm.poll.fd);
|
|
|
|
interface->alarm.poll.fd=-1;
|
|
|
|
}
|
|
|
|
interface->state=INTERFACE_STATE_DOWN;
|
2013-04-15 07:00:07 +00:00
|
|
|
return cleanup_ret;
|
2011-08-08 06:41:05 +00:00
|
|
|
}
|
|
|
|
|
2013-11-29 02:26:59 +00:00
|
|
|
static void interface_read_dgram(struct overlay_interface *interface)
|
|
|
|
{
|
2013-02-14 03:48:56 +00:00
|
|
|
int plen=0;
|
|
|
|
unsigned char packet[8096];
|
|
|
|
|
2013-11-29 02:26:59 +00:00
|
|
|
struct socket_address recvaddr;
|
|
|
|
recvaddr.addrlen = sizeof recvaddr.store;
|
|
|
|
|
2013-02-14 03:48:56 +00:00
|
|
|
/* Read only one UDP packet per call to share resources more fairly, and also
|
|
|
|
enable stats to accurately count packets received */
|
|
|
|
int recvttl=1;
|
2013-11-29 02:26:59 +00:00
|
|
|
plen = recvwithttl(interface->alarm.poll.fd,packet, sizeof(packet), &recvttl, &recvaddr);
|
2013-02-14 03:48:56 +00:00
|
|
|
if (plen == -1) {
|
2013-11-30 19:14:01 +00:00
|
|
|
WHYF_perror("recvwithttl(%d,%p,%zu,&%d,%p(%s))",
|
2013-12-10 00:08:03 +00:00
|
|
|
interface->alarm.poll.fd, packet, sizeof packet, recvttl,
|
2013-11-30 19:14:01 +00:00
|
|
|
&recvaddr, alloca_socket_address(&recvaddr)
|
|
|
|
);
|
2013-02-14 03:48:56 +00:00
|
|
|
overlay_interface_close(interface);
|
2012-07-06 00:28:54 +00:00
|
|
|
return;
|
|
|
|
}
|
2013-12-09 07:52:18 +00:00
|
|
|
packetOkOverlay(interface, packet, plen, &recvaddr);
|
2012-06-22 03:55:41 +00:00
|
|
|
}
|
2012-06-21 07:32:36 +00:00
|
|
|
|
2013-02-14 03:48:56 +00:00
|
|
|
struct file_packet{
|
2013-12-09 07:15:47 +00:00
|
|
|
struct socket_address src_addr;
|
|
|
|
struct socket_address dst_addr;
|
2012-12-08 04:39:41 +00:00
|
|
|
int pid;
|
|
|
|
int payload_length;
|
|
|
|
|
|
|
|
/* TODO ? ;
|
2013-02-14 03:48:56 +00:00
|
|
|
half-power beam height (uint16)
|
|
|
|
half-power beam width (uint16)
|
|
|
|
range in metres, centre beam (uint32)
|
|
|
|
latitude (uint32)
|
|
|
|
longitude (uint32)
|
|
|
|
X/Z direction (uint16)
|
|
|
|
Y direction (uint16)
|
|
|
|
speed in metres per second (uint16)
|
|
|
|
TX frequency in Hz, uncorrected for doppler (which must be done at the receiving end to take into account
|
|
|
|
relative motion)
|
|
|
|
coding method (use for doppler response etc) null terminated string
|
|
|
|
*/
|
2012-12-08 04:39:41 +00:00
|
|
|
|
|
|
|
unsigned char payload[1400];
|
|
|
|
};
|
|
|
|
|
2013-12-09 07:15:47 +00:00
|
|
|
static int should_drop(struct overlay_interface *interface, struct socket_address *addr){
|
2015-03-16 01:52:38 +00:00
|
|
|
if (interface->ifconfig.drop_packets>=100)
|
2013-08-12 04:51:31 +00:00
|
|
|
return 1;
|
|
|
|
|
2013-12-09 07:15:47 +00:00
|
|
|
if (cmp_sockaddr(addr, &interface->address)==0){
|
2015-03-16 01:52:38 +00:00
|
|
|
if (interface->ifconfig.unicast.drop)
|
2013-05-07 03:59:42 +00:00
|
|
|
return 1;
|
2013-12-09 07:15:47 +00:00
|
|
|
}else if (cmp_sockaddr(addr, &interface->destination->address)==0){
|
2015-03-16 01:52:38 +00:00
|
|
|
if (interface->ifconfig.broadcast.drop)
|
2013-08-12 04:51:31 +00:00
|
|
|
return 1;
|
|
|
|
}else
|
|
|
|
return 1;
|
|
|
|
|
2015-03-16 01:52:38 +00:00
|
|
|
if (interface->ifconfig.drop_packets <= 0)
|
2013-08-12 04:51:31 +00:00
|
|
|
return 0;
|
2015-03-16 01:52:38 +00:00
|
|
|
if (rand()%100 >= interface->ifconfig.drop_packets)
|
2013-08-12 04:51:31 +00:00
|
|
|
return 0;
|
2013-05-07 03:59:42 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2013-02-14 03:48:56 +00:00
|
|
|
static void interface_read_file(struct overlay_interface *interface)
|
2011-08-08 06:41:05 +00:00
|
|
|
{
|
2013-02-15 07:39:39 +00:00
|
|
|
IN();
|
2011-08-08 06:41:05 +00:00
|
|
|
/* Grab packets, unpackage and dispatch frames to consumers */
|
2013-02-14 03:48:56 +00:00
|
|
|
struct file_packet packet;
|
|
|
|
|
|
|
|
/* Read from interface file */
|
2013-10-06 19:24:46 +00:00
|
|
|
off_t length = lseek(interface->alarm.poll.fd, (off_t)0, SEEK_END);
|
2013-12-13 07:18:58 +00:00
|
|
|
if (interface->recv_offset > length)
|
|
|
|
FATALF("File shrunk? It shouldn't shrink! Ever");
|
2015-03-30 06:00:10 +00:00
|
|
|
|
2013-02-14 03:48:56 +00:00
|
|
|
if (interface->recv_offset<length){
|
2015-03-30 06:00:10 +00:00
|
|
|
int new_packets = (length - interface->recv_offset) / sizeof packet;
|
|
|
|
if (new_packets > 20)
|
|
|
|
WARNF("Getting behind, there are %d unread packets (%"PRId64" vs %"PRId64")",
|
|
|
|
new_packets, (int64_t)interface->recv_offset, (int64_t)length);
|
|
|
|
|
2013-02-14 03:48:56 +00:00
|
|
|
if (lseek(interface->alarm.poll.fd,interface->recv_offset,SEEK_SET) == -1){
|
2012-07-31 08:19:24 +00:00
|
|
|
WHY_perror("lseek");
|
2013-02-15 07:39:39 +00:00
|
|
|
OUT();
|
2012-12-08 04:39:41 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-02-14 03:48:56 +00:00
|
|
|
ssize_t nread = read(interface->alarm.poll.fd, &packet, sizeof packet);
|
2012-12-08 04:39:41 +00:00
|
|
|
if (nread == -1){
|
|
|
|
WHY_perror("read");
|
2013-02-16 17:47:24 +00:00
|
|
|
OUT();
|
2012-12-08 04:39:41 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nread == sizeof packet) {
|
2015-07-06 08:19:49 +00:00
|
|
|
DEBUGF(overlayinterfaces, "Read from interface %s (filesize=%"PRId64") at offset=%"PRId64": src_addr=%s dst_addr=%s pid=%d length=%d",
|
|
|
|
interface->name, (int64_t)length, (int64_t)interface->recv_offset,
|
|
|
|
alloca_socket_address(&packet.src_addr),
|
|
|
|
alloca_socket_address(&packet.dst_addr),
|
|
|
|
packet.pid,
|
|
|
|
packet.payload_length
|
2013-11-26 03:22:29 +00:00
|
|
|
);
|
2012-12-08 04:39:41 +00:00
|
|
|
interface->recv_offset += nread;
|
2013-12-09 07:15:47 +00:00
|
|
|
if (should_drop(interface, &packet.dst_addr) || (packet.pid == getpid() && !interface->local_echo)){
|
2015-07-06 08:19:49 +00:00
|
|
|
DEBUGF(overlayinterfaces, "Ignoring packet from pid=%d src_addr=%s dst_addr=%s",
|
|
|
|
packet.pid,
|
|
|
|
alloca_socket_address(&packet.src_addr),
|
|
|
|
alloca_socket_address(&packet.dst_addr)
|
2013-11-26 03:22:29 +00:00
|
|
|
);
|
2013-07-16 05:46:07 +00:00
|
|
|
}else{
|
2013-12-09 07:15:47 +00:00
|
|
|
packetOkOverlay(interface, packet.payload, packet.payload_length, &packet.src_addr);
|
2013-07-16 05:46:07 +00:00
|
|
|
}
|
2012-01-10 03:35:26 +00:00
|
|
|
}
|
2013-02-14 03:48:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* if there's no input, while we want to check for more soon,
|
|
|
|
we need to allow all other low priority alarms to fire first,
|
|
|
|
otherwise we'll dominate the scheduler without accomplishing anything */
|
2013-06-19 05:57:17 +00:00
|
|
|
time_ms_t now = gettime_ms();
|
2013-02-14 03:48:56 +00:00
|
|
|
if (interface->recv_offset>=length){
|
2015-03-30 06:00:10 +00:00
|
|
|
if (now + 5 < interface->alarm.alarm){
|
2013-02-14 03:48:56 +00:00
|
|
|
interface->alarm.alarm = now + 5;
|
2013-06-19 07:22:01 +00:00
|
|
|
interface->alarm.deadline = interface->alarm.alarm + 500;
|
2013-02-14 03:48:56 +00:00
|
|
|
}
|
|
|
|
}else{
|
2012-07-31 08:19:24 +00:00
|
|
|
/* keep reading new packets as fast as possible,
|
2013-02-14 03:48:56 +00:00
|
|
|
but don't completely prevent other high priority alarms */
|
2015-03-30 06:00:10 +00:00
|
|
|
if (now < interface->alarm.alarm){
|
2013-02-14 03:48:56 +00:00
|
|
|
interface->alarm.alarm = now;
|
2013-06-19 07:22:01 +00:00
|
|
|
interface->alarm.deadline = interface->alarm.alarm + 100;
|
2013-02-14 03:48:56 +00:00
|
|
|
}
|
|
|
|
}
|
2013-02-16 17:47:24 +00:00
|
|
|
OUT();
|
2013-02-14 03:48:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void interface_read_stream(struct overlay_interface *interface){
|
2013-02-15 07:39:39 +00:00
|
|
|
IN();
|
2013-02-14 03:48:56 +00:00
|
|
|
unsigned char buffer[OVERLAY_INTERFACE_RX_BUFFER_SIZE];
|
|
|
|
ssize_t nread = read(interface->alarm.poll.fd, buffer, OVERLAY_INTERFACE_RX_BUFFER_SIZE);
|
|
|
|
if (nread == -1){
|
2013-02-14 06:47:45 +00:00
|
|
|
WHY_perror("read");
|
2013-02-15 07:39:39 +00:00
|
|
|
OUT();
|
2013-02-14 03:48:56 +00:00
|
|
|
return;
|
2012-07-31 08:19:24 +00:00
|
|
|
}
|
2013-10-30 06:39:37 +00:00
|
|
|
|
2013-02-14 03:48:56 +00:00
|
|
|
|
2013-09-18 04:16:38 +00:00
|
|
|
int i;
|
|
|
|
for (i=0;i<nread;i++)
|
2013-10-30 06:39:37 +00:00
|
|
|
radio_link_decode(interface, buffer[i]);
|
2013-09-18 04:16:38 +00:00
|
|
|
|
2013-02-15 07:39:39 +00:00
|
|
|
OUT();
|
2013-02-14 03:48:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void overlay_interface_poll(struct sched_ent *alarm)
|
|
|
|
{
|
|
|
|
struct overlay_interface *interface = (overlay_interface *)alarm;
|
2013-08-27 11:13:56 +00:00
|
|
|
time_ms_t now = gettime_ms();
|
|
|
|
|
2013-02-14 03:48:56 +00:00
|
|
|
if (alarm->poll.revents==0){
|
2015-03-30 06:00:10 +00:00
|
|
|
alarm->alarm=TIME_MS_NEVER_WILL;
|
2013-02-14 03:48:56 +00:00
|
|
|
|
2013-08-13 01:25:48 +00:00
|
|
|
if (interface->state==INTERFACE_STATE_UP
|
2015-03-16 01:52:38 +00:00
|
|
|
&& interface->destination->ifconfig.tick_ms>0
|
|
|
|
&& interface->destination->ifconfig.send
|
2013-11-25 04:35:33 +00:00
|
|
|
&& !radio_link_is_busy(interface)){
|
2013-08-28 07:34:26 +00:00
|
|
|
|
2015-03-16 01:52:38 +00:00
|
|
|
if (now >= interface->destination->last_tx+interface->destination->ifconfig.tick_ms)
|
2013-08-08 05:50:31 +00:00
|
|
|
overlay_send_tick_packet(interface->destination);
|
2014-06-13 06:04:47 +00:00
|
|
|
|
2015-03-23 03:03:15 +00:00
|
|
|
calc_next_tick(interface);
|
2013-02-14 03:48:56 +00:00
|
|
|
}
|
2013-06-04 02:42:45 +00:00
|
|
|
|
2015-03-16 01:52:38 +00:00
|
|
|
switch(interface->ifconfig.socket_type){
|
2013-02-14 03:48:56 +00:00
|
|
|
case SOCK_STREAM:
|
2013-11-25 04:35:33 +00:00
|
|
|
radio_link_tx(interface);
|
|
|
|
return;
|
2013-08-27 11:13:56 +00:00
|
|
|
case SOCK_DGRAM:
|
2015-03-02 05:11:07 +00:00
|
|
|
case SOCK_EXT:
|
2013-02-14 03:48:56 +00:00
|
|
|
break;
|
|
|
|
case SOCK_FILE:
|
|
|
|
interface_read_file(interface);
|
2013-06-19 05:57:17 +00:00
|
|
|
now = gettime_ms();
|
2013-02-14 03:48:56 +00:00
|
|
|
break;
|
|
|
|
}
|
2013-08-27 11:13:56 +00:00
|
|
|
|
2013-09-18 04:16:38 +00:00
|
|
|
unschedule(alarm);
|
2015-03-30 06:00:10 +00:00
|
|
|
if (alarm->alarm!=TIME_MS_NEVER_WILL && interface->state==INTERFACE_STATE_UP) {
|
2014-11-12 09:36:34 +00:00
|
|
|
if (alarm->alarm < now) {
|
2013-06-19 05:57:17 +00:00
|
|
|
alarm->alarm = now;
|
2015-03-16 01:52:38 +00:00
|
|
|
alarm->deadline = alarm->alarm + interface->destination->ifconfig.tick_ms / 2;
|
2014-11-12 09:36:34 +00:00
|
|
|
}
|
2013-02-14 03:48:56 +00:00
|
|
|
schedule(alarm);
|
2013-02-15 19:52:37 +00:00
|
|
|
}
|
2013-02-14 03:48:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (alarm->poll.revents & POLLOUT){
|
2015-03-16 01:52:38 +00:00
|
|
|
switch(interface->ifconfig.socket_type){
|
2013-02-14 03:48:56 +00:00
|
|
|
case SOCK_STREAM:
|
2013-11-25 04:35:33 +00:00
|
|
|
radio_link_tx(interface);
|
|
|
|
return;
|
2015-03-02 05:11:07 +00:00
|
|
|
case SOCK_EXT:
|
2013-02-14 03:48:56 +00:00
|
|
|
case SOCK_DGRAM:
|
|
|
|
case SOCK_FILE:
|
|
|
|
//XXX error? fatal?
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (alarm->poll.revents & POLLIN) {
|
2015-03-16 01:52:38 +00:00
|
|
|
switch(interface->ifconfig.socket_type){
|
2013-02-14 03:48:56 +00:00
|
|
|
case SOCK_DGRAM:
|
|
|
|
interface_read_dgram(interface);
|
|
|
|
break;
|
|
|
|
case SOCK_STREAM:
|
|
|
|
interface_read_stream(interface);
|
2013-09-20 02:54:06 +00:00
|
|
|
// if we read a valid heartbeat packet, we may be able to write more bytes now.
|
2013-11-25 04:35:33 +00:00
|
|
|
if (interface->state==INTERFACE_STATE_UP){
|
|
|
|
radio_link_tx(interface);
|
|
|
|
return;
|
2013-09-20 02:54:06 +00:00
|
|
|
}
|
2013-02-14 03:48:56 +00:00
|
|
|
break;
|
|
|
|
case SOCK_FILE:
|
|
|
|
interface_read_file(interface);
|
|
|
|
break;
|
2015-03-02 05:11:07 +00:00
|
|
|
case SOCK_EXT:
|
|
|
|
break;
|
2013-02-14 03:48:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (alarm->poll.revents & (POLLHUP | POLLERR)) {
|
|
|
|
overlay_interface_close(interface);
|
|
|
|
}
|
2011-08-08 06:41:05 +00:00
|
|
|
}
|
|
|
|
|
2014-05-02 04:32:25 +00:00
|
|
|
static int send_local_packet(int fd, const uint8_t *bytes, size_t len, const char *folder, const char *file)
|
2013-12-11 06:11:57 +00:00
|
|
|
{
|
2014-05-02 04:32:25 +00:00
|
|
|
struct socket_address addr;
|
|
|
|
|
|
|
|
strbuf d = strbuf_local(addr.local.sun_path, sizeof addr.local.sun_path);
|
|
|
|
strbuf_path_join(d, folder, file, NULL);
|
|
|
|
if (strbuf_overrun(d))
|
|
|
|
return WHYF("interface file name overrun: %s", alloca_str_toprint(strbuf_str(d)));
|
|
|
|
|
|
|
|
struct stat st;
|
|
|
|
if (lstat(addr.local.sun_path, &st))
|
|
|
|
return 1;
|
|
|
|
if (!S_ISSOCK(st.st_mode))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
addr.local.sun_family = AF_UNIX;
|
|
|
|
addr.addrlen = sizeof(addr.local.sun_family) + strlen(addr.local.sun_path)+1;
|
|
|
|
|
|
|
|
ssize_t sent = sendto(fd, bytes, len, 0,
|
|
|
|
&addr.addr, addr.addrlen);
|
2014-06-12 06:33:52 +00:00
|
|
|
if (sent == -1){
|
|
|
|
if (errno != EAGAIN && errno != EWOULDBLOCK)
|
|
|
|
return WHYF_perror("sendto(%d, %zu, %s)", fd, len, alloca_socket_address(&addr));
|
|
|
|
}
|
2014-05-02 04:32:25 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int send_local_broadcast(int fd, const uint8_t *bytes, size_t len, const char *folder)
|
|
|
|
{
|
|
|
|
if (send_local_packet(fd, bytes, len, folder, "broadcast")==0)
|
|
|
|
return 0;
|
|
|
|
|
2013-12-11 06:11:57 +00:00
|
|
|
DIR *dir;
|
|
|
|
struct dirent *dp;
|
2014-05-02 04:32:25 +00:00
|
|
|
if ((dir = opendir(folder)) == NULL) {
|
|
|
|
WARNF_perror("opendir(%s)", alloca_str_toprint(folder));
|
2013-12-11 06:11:57 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
while ((dp = readdir(dir)) != NULL) {
|
2014-05-02 04:32:25 +00:00
|
|
|
send_local_packet(fd, bytes, len, folder, dp->d_name);
|
2013-12-11 06:11:57 +00:00
|
|
|
}
|
|
|
|
closedir(dir);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-09-11 01:43:33 +00:00
|
|
|
int overlay_broadcast_ensemble(struct network_destination *destination, struct overlay_buffer *buffer)
|
2011-08-08 06:41:05 +00:00
|
|
|
{
|
2013-08-08 05:50:31 +00:00
|
|
|
assert(destination && destination->interface);
|
2013-09-11 01:43:33 +00:00
|
|
|
const unsigned char *bytes = ob_ptr(buffer);
|
2013-12-10 06:33:30 +00:00
|
|
|
size_t len = ob_position(buffer);
|
2013-08-08 05:50:31 +00:00
|
|
|
|
|
|
|
struct overlay_interface *interface = destination->interface;
|
|
|
|
destination->last_tx = gettime_ms();
|
2013-09-11 01:43:33 +00:00
|
|
|
|
2015-07-06 08:19:49 +00:00
|
|
|
if (IF_DEBUG(packettx)) {
|
|
|
|
DEBUGF(packettx, "Sending this packet via interface %s (len=%zu)",interface->name, len);
|
2013-09-11 01:43:33 +00:00
|
|
|
DEBUG_packet_visualise(NULL, bytes, len);
|
2013-08-08 05:50:31 +00:00
|
|
|
}
|
2012-04-13 20:56:20 +00:00
|
|
|
|
2012-07-25 07:23:44 +00:00
|
|
|
if (interface->state!=INTERFACE_STATE_UP){
|
2013-09-11 01:43:33 +00:00
|
|
|
ob_free(buffer);
|
2012-07-25 07:23:44 +00:00
|
|
|
return WHYF("Cannot send to interface %s as it is down", interface->name);
|
|
|
|
}
|
2011-08-08 06:41:05 +00:00
|
|
|
|
2015-07-06 08:19:49 +00:00
|
|
|
if (IF_DEBUG(overlayinterfaces) || interface->ifconfig.debug)
|
|
|
|
_DEBUGF_TAG("overlayinterfaces", "Sending %zu byte overlay frame on %s to %s [%s]",
|
|
|
|
(size_t)len, interface->name, alloca_socket_address(&destination->address),
|
|
|
|
alloca_tohex(bytes, len>64?64:len)
|
|
|
|
);
|
2015-03-02 05:11:07 +00:00
|
|
|
|
2013-09-23 01:41:58 +00:00
|
|
|
interface->tx_count++;
|
|
|
|
|
2015-03-16 01:52:38 +00:00
|
|
|
switch(interface->ifconfig.socket_type){
|
2013-02-14 03:48:56 +00:00
|
|
|
case SOCK_STREAM:
|
2013-11-25 04:35:33 +00:00
|
|
|
return radio_link_queue_packet(interface, buffer);
|
2013-02-14 03:48:56 +00:00
|
|
|
|
|
|
|
case SOCK_FILE:
|
|
|
|
{
|
|
|
|
struct file_packet packet={
|
2012-12-08 04:39:41 +00:00
|
|
|
.src_addr = interface->address,
|
2013-08-08 05:50:31 +00:00
|
|
|
.dst_addr = destination->address,
|
2012-12-08 04:39:41 +00:00
|
|
|
.pid = getpid(),
|
|
|
|
};
|
|
|
|
|
2013-12-10 06:33:30 +00:00
|
|
|
if (len > sizeof packet.payload) {
|
2012-12-08 04:39:41 +00:00
|
|
|
WARN("Truncating long packet to fit within MTU byte limit for dummy interface");
|
2013-12-10 06:33:30 +00:00
|
|
|
len = sizeof packet.payload;
|
2011-08-14 15:58:27 +00:00
|
|
|
}
|
2013-12-10 06:33:30 +00:00
|
|
|
packet.payload_length = len;
|
2012-12-08 04:39:41 +00:00
|
|
|
bcopy(bytes, packet.payload, len);
|
2013-09-11 01:43:33 +00:00
|
|
|
ob_free(buffer);
|
2012-07-03 06:06:51 +00:00
|
|
|
/* This lseek() is unneccessary because the dummy file is opened in O_APPEND mode. It's
|
2013-02-14 03:48:56 +00:00
|
|
|
only purpose is to find out the offset to print in the DEBUG statement. It is vulnerable
|
|
|
|
to a race condition with other processes appending to the same file. */
|
2015-07-06 08:19:49 +00:00
|
|
|
if (IF_DEBUG(overlayinterfaces)) {
|
2013-08-26 08:08:37 +00:00
|
|
|
off_t fsize = lseek(interface->alarm.poll.fd, (off_t) 0, SEEK_END);
|
|
|
|
if (fsize == -1) {
|
|
|
|
/* Don't complain if the seek fails because we are writing to a pipe or device that does
|
|
|
|
not support seeking. */
|
|
|
|
if (errno != ESPIPE)
|
|
|
|
return WHY_perror("lseek");
|
2015-07-06 08:19:49 +00:00
|
|
|
DEBUGF(overlayinterfaces, "Write to interface %s at offset unknown: src_addr=%s dst_addr=%s pid=%d length=%d",
|
2013-11-26 03:22:29 +00:00
|
|
|
interface->name,
|
2015-03-30 06:00:10 +00:00
|
|
|
alloca_socket_address(&packet.src_addr),
|
|
|
|
alloca_socket_address(&packet.dst_addr),
|
2013-11-26 03:22:29 +00:00
|
|
|
packet.pid,
|
|
|
|
packet.payload_length
|
|
|
|
);
|
2013-08-26 08:08:37 +00:00
|
|
|
} else
|
2015-07-06 08:19:49 +00:00
|
|
|
DEBUGF(overlayinterfaces, "Write to interface %s at offset=%"PRId64": src_addr=%s dst_addr=%s pid=%d length=%d",
|
2013-11-26 03:22:29 +00:00
|
|
|
interface->name, (int64_t)fsize,
|
2015-03-30 06:00:10 +00:00
|
|
|
alloca_socket_address(&packet.src_addr),
|
|
|
|
alloca_socket_address(&packet.dst_addr),
|
2013-11-26 03:22:29 +00:00
|
|
|
packet.pid,
|
|
|
|
packet.payload_length
|
|
|
|
);
|
2013-02-14 17:32:19 +00:00
|
|
|
}
|
2012-12-08 04:39:41 +00:00
|
|
|
ssize_t nwrite = write(interface->alarm.poll.fd, &packet, sizeof(packet));
|
2012-07-03 06:06:51 +00:00
|
|
|
if (nwrite == -1)
|
|
|
|
return WHY_perror("write");
|
2012-12-08 04:39:41 +00:00
|
|
|
if (nwrite != sizeof(packet))
|
2013-07-15 00:29:24 +00:00
|
|
|
return WHYF("only wrote %d of %d bytes", (int)nwrite, (int)sizeof(packet));
|
2012-07-03 06:06:51 +00:00
|
|
|
return 0;
|
2011-08-12 07:47:29 +00:00
|
|
|
}
|
2015-03-02 05:11:07 +00:00
|
|
|
case SOCK_EXT:
|
|
|
|
{
|
|
|
|
mdp_send_external_packet(interface, &destination->address, bytes, (size_t)len);
|
|
|
|
ob_free(buffer);
|
|
|
|
return 0;
|
|
|
|
}
|
2013-02-14 03:48:56 +00:00
|
|
|
case SOCK_DGRAM:
|
2011-08-13 11:17:49 +00:00
|
|
|
{
|
2014-03-03 22:06:31 +00:00
|
|
|
set_nonblock(interface->alarm.poll.fd);
|
2013-12-11 06:11:57 +00:00
|
|
|
if (destination->address.addr.sa_family == AF_UNIX
|
|
|
|
&& !destination->unicast){
|
|
|
|
// find all sockets in this folder and send to them
|
|
|
|
send_local_broadcast(interface->alarm.poll.fd,
|
2014-05-02 04:32:25 +00:00
|
|
|
bytes, (size_t)len, destination->address.local.sun_path);
|
2013-12-11 06:11:57 +00:00
|
|
|
}else{
|
|
|
|
ssize_t sent = sendto(interface->alarm.poll.fd,
|
|
|
|
bytes, (size_t)len, 0,
|
|
|
|
&destination->address.addr, destination->address.addrlen);
|
|
|
|
if (sent == -1){
|
2014-06-27 03:15:53 +00:00
|
|
|
if (errno!=EAGAIN && errno!=EWOULDBLOCK && errno!=ENOENT && errno!=ENOTDIR)
|
|
|
|
WHYF_perror("sendto(fd=%d,len=%zu,addr=%s) on interface %s",
|
|
|
|
interface->alarm.poll.fd,
|
|
|
|
(size_t)len,
|
|
|
|
alloca_socket_address(&destination->address),
|
|
|
|
interface->name
|
|
|
|
);
|
2013-12-11 06:11:57 +00:00
|
|
|
// close the interface if we had any error while sending broadcast packets,
|
|
|
|
// unicast packets should not bring the interface down
|
|
|
|
// TODO mark unicast destination as failed?
|
|
|
|
if (destination == interface->destination)
|
|
|
|
overlay_interface_close(interface);
|
|
|
|
ob_free(buffer);
|
|
|
|
return -1;
|
|
|
|
}
|
2012-07-25 07:23:44 +00:00
|
|
|
}
|
2014-03-03 22:06:31 +00:00
|
|
|
set_block(interface->alarm.poll.fd);
|
2013-12-11 06:11:57 +00:00
|
|
|
ob_free(buffer);
|
2012-07-03 06:06:51 +00:00
|
|
|
return 0;
|
2011-08-13 11:17:49 +00:00
|
|
|
}
|
2013-02-14 03:48:56 +00:00
|
|
|
|
|
|
|
default:
|
2013-09-11 01:43:33 +00:00
|
|
|
ob_free(buffer);
|
2013-02-14 03:48:56 +00:00
|
|
|
return WHY("Unsupported socket type");
|
|
|
|
}
|
2011-08-08 06:41:05 +00:00
|
|
|
}
|
2011-08-08 14:41:46 +00:00
|
|
|
|
2012-12-04 03:42:28 +00:00
|
|
|
/* Register the real interface, or update the existing interface registration. */
|
2012-06-08 08:59:27 +00:00
|
|
|
int
|
|
|
|
overlay_interface_register(char *name,
|
2013-12-09 07:15:47 +00:00
|
|
|
struct socket_address *addr,
|
2014-10-31 04:30:03 +00:00
|
|
|
struct socket_address *netmask,
|
2013-12-09 07:15:47 +00:00
|
|
|
struct socket_address *broadcast)
|
2012-12-04 03:42:28 +00:00
|
|
|
{
|
|
|
|
// Find the matching non-dummy interface rule.
|
|
|
|
const struct config_network_interface *ifconfig = NULL;
|
2013-12-10 05:51:23 +00:00
|
|
|
unsigned i;
|
2012-12-04 03:42:28 +00:00
|
|
|
for (i = 0; i < config.interfaces.ac; ++i, ifconfig = NULL) {
|
|
|
|
ifconfig = &config.interfaces.av[i].value;
|
2013-02-14 03:48:56 +00:00
|
|
|
if (ifconfig->socket_type==SOCK_DGRAM) {
|
2013-12-10 05:51:23 +00:00
|
|
|
unsigned j;
|
2012-12-10 04:48:22 +00:00
|
|
|
for (j = 0; j < ifconfig->match.patc; ++j){
|
2012-12-04 03:42:28 +00:00
|
|
|
if (fnmatch(ifconfig->match.patv[j], name, 0) == 0)
|
|
|
|
break;
|
2012-12-10 04:48:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (j < ifconfig->match.patc)
|
|
|
|
break;
|
2012-12-04 03:42:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (ifconfig == NULL) {
|
2015-07-06 08:19:49 +00:00
|
|
|
DEBUGF(overlayinterfaces, "Interface %s does not match any rule", name);
|
2012-12-04 03:42:28 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (ifconfig->exclude) {
|
2015-07-06 08:19:49 +00:00
|
|
|
DEBUGF(overlayinterfaces, "Interface %s is explicitly excluded", name);
|
2012-06-08 08:59:27 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2013-12-09 07:15:47 +00:00
|
|
|
|
|
|
|
if (addr->addr.sa_family==AF_INET)
|
|
|
|
addr->inet.sin_port = htons(ifconfig->port);
|
|
|
|
if (broadcast->addr.sa_family==AF_INET)
|
|
|
|
broadcast->inet.sin_port = htons(ifconfig->port);
|
2012-06-08 08:59:27 +00:00
|
|
|
|
2015-07-06 08:19:49 +00:00
|
|
|
// note, inet_ntop doesn't seem to behave on android
|
|
|
|
DEBUGF(overlayinterfaces, "%s address: %s", name, alloca_socket_address(addr));
|
|
|
|
DEBUGF(overlayinterfaces, "%s netmask: %s", name, alloca_socket_address(netmask));
|
|
|
|
DEBUGF(overlayinterfaces, "%s broadcast address: %s", name, alloca_socket_address(broadcast));
|
2014-01-20 05:31:24 +00:00
|
|
|
|
2015-03-02 05:11:07 +00:00
|
|
|
struct overlay_interface *interface = overlay_interface_find_name_addr(name, addr);
|
|
|
|
if (interface){
|
|
|
|
// mark this interface as still alive
|
|
|
|
if (interface->state == INTERFACE_STATE_DETECTING)
|
|
|
|
interface->state = INTERFACE_STATE_UP;
|
|
|
|
return 0;
|
2012-07-25 07:23:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* New interface, so register it */
|
2014-10-31 04:30:03 +00:00
|
|
|
if (overlay_interface_init(name, addr, netmask, broadcast, ifconfig))
|
2012-07-25 07:23:44 +00:00
|
|
|
return WHYF("Could not initialise newly seen interface %s", name);
|
2012-06-08 08:59:27 +00:00
|
|
|
|
2015-07-06 08:19:49 +00:00
|
|
|
DEBUGF(overlayinterfaces, "Registered interface %s", name);
|
2012-04-28 02:55:19 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2014-05-29 07:11:27 +00:00
|
|
|
|
|
|
|
// poll the OS's network interfaces
|
|
|
|
DEFINE_ALARM(overlay_interface_discover);
|
2012-12-04 03:42:28 +00:00
|
|
|
void overlay_interface_discover(struct sched_ent *alarm)
|
|
|
|
{
|
2012-07-25 07:23:44 +00:00
|
|
|
/* Mark all UP interfaces as DETECTING, so we can tell which interfaces are new, and which are dead */
|
2013-12-10 05:51:23 +00:00
|
|
|
unsigned i;
|
2014-01-20 05:31:24 +00:00
|
|
|
for (i = 0; i < OVERLAY_MAX_INTERFACES; i++)
|
2012-07-25 07:23:44 +00:00
|
|
|
if (overlay_interfaces[i].state==INTERFACE_STATE_UP)
|
2013-08-29 06:20:13 +00:00
|
|
|
overlay_interfaces[i].state=INTERFACE_STATE_DETECTING;
|
2011-08-12 07:47:29 +00:00
|
|
|
|
2014-06-02 04:39:22 +00:00
|
|
|
/* Register new file interfaces */
|
2012-12-04 03:42:28 +00:00
|
|
|
int detect_real_interfaces = 0;
|
|
|
|
const struct config_network_interface *ifconfig = NULL;
|
|
|
|
for (i = 0; i < config.interfaces.ac; ++i, ifconfig = NULL) {
|
|
|
|
ifconfig = &config.interfaces.av[i].value;
|
2013-08-30 07:53:24 +00:00
|
|
|
if (ifconfig->exclude)
|
|
|
|
continue;
|
2013-12-11 06:11:57 +00:00
|
|
|
if (!*ifconfig->file) {
|
2012-07-25 07:23:44 +00:00
|
|
|
detect_real_interfaces = 1;
|
2012-06-15 05:34:36 +00:00
|
|
|
continue;
|
2012-07-25 07:23:44 +00:00
|
|
|
}
|
2013-12-10 05:51:23 +00:00
|
|
|
unsigned j;
|
2014-01-20 05:31:24 +00:00
|
|
|
for (j = 0; j < OVERLAY_MAX_INTERFACES; j++){
|
2015-03-16 01:52:38 +00:00
|
|
|
if (overlay_interfaces[j].ifconfig.socket_type == ifconfig->socket_type &&
|
2013-02-14 03:48:56 +00:00
|
|
|
strcasecmp(overlay_interfaces[j].name, ifconfig->file) == 0 &&
|
|
|
|
overlay_interfaces[j].state==INTERFACE_STATE_DETECTING){
|
|
|
|
overlay_interfaces[j].state=INTERFACE_STATE_UP;
|
2012-06-15 05:34:36 +00:00
|
|
|
break;
|
2012-07-25 07:23:44 +00:00
|
|
|
}
|
2013-02-14 03:48:56 +00:00
|
|
|
}
|
|
|
|
|
2014-01-20 05:31:24 +00:00
|
|
|
if (j >= OVERLAY_MAX_INTERFACES) {
|
2013-12-11 06:11:57 +00:00
|
|
|
// New file interface, so register it.
|
2014-10-31 04:30:03 +00:00
|
|
|
struct socket_address addr, netmask, broadcast;
|
2013-12-09 07:15:47 +00:00
|
|
|
bzero(&addr, sizeof addr);
|
2014-10-31 04:30:03 +00:00
|
|
|
bzero(&netmask, sizeof addr);
|
2013-12-09 07:15:47 +00:00
|
|
|
bzero(&broadcast, sizeof broadcast);
|
|
|
|
|
2013-12-11 06:11:57 +00:00
|
|
|
switch(ifconfig->socket_type){
|
|
|
|
case SOCK_FILE:
|
|
|
|
// use a fake inet address
|
|
|
|
addr.addrlen=sizeof addr.inet;
|
|
|
|
addr.inet.sin_family=AF_INET;
|
|
|
|
addr.inet.sin_port=htons(ifconfig->port);
|
|
|
|
addr.inet.sin_addr=ifconfig->dummy_address;
|
2014-10-31 04:30:03 +00:00
|
|
|
|
|
|
|
netmask.addrlen=sizeof addr.inet;
|
|
|
|
netmask.inet.sin_family=AF_INET;
|
|
|
|
netmask.inet.sin_port=htons(ifconfig->port);
|
|
|
|
netmask.inet.sin_addr.s_addr=ifconfig->dummy_netmask.s_addr;
|
2013-12-11 06:11:57 +00:00
|
|
|
|
|
|
|
broadcast.addrlen=sizeof addr.inet;
|
|
|
|
broadcast.inet.sin_family=AF_INET;
|
|
|
|
broadcast.inet.sin_port=htons(ifconfig->port);
|
|
|
|
broadcast.inet.sin_addr.s_addr=ifconfig->dummy_address.s_addr | ~ifconfig->dummy_netmask.s_addr;
|
|
|
|
// Fallthrough
|
|
|
|
case SOCK_STREAM:
|
2014-10-31 04:30:03 +00:00
|
|
|
overlay_interface_init(ifconfig->file, &addr, NULL, &broadcast, ifconfig);
|
2013-12-11 06:11:57 +00:00
|
|
|
break;
|
2015-03-02 05:11:07 +00:00
|
|
|
case SOCK_EXT:
|
|
|
|
// FAIL?
|
|
|
|
break;
|
2013-12-11 06:11:57 +00:00
|
|
|
case SOCK_DGRAM:
|
|
|
|
{
|
|
|
|
// use a local dgram socket
|
|
|
|
// no abstract sockets for now
|
2014-03-26 05:05:43 +00:00
|
|
|
if (!FORMF_SERVAL_RUN_PATH(addr.local.sun_path, "%s/%s", config.server.interface_path, ifconfig->file)) {
|
2013-12-11 06:11:57 +00:00
|
|
|
// TODO set ifconfig->exclude to prevent spam??
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
unlink(addr.local.sun_path);
|
|
|
|
addr.local.sun_family=AF_UNIX;
|
|
|
|
size_t len = strlen(addr.local.sun_path);
|
|
|
|
|
|
|
|
addr.addrlen=sizeof addr.local.sun_family + len + 1;
|
|
|
|
|
|
|
|
broadcast = addr;
|
|
|
|
while(len && broadcast.local.sun_path[len]!='/')
|
|
|
|
broadcast.local.sun_path[len--]='\0';
|
|
|
|
broadcast.addrlen = sizeof addr.local.sun_family + len + 2;
|
|
|
|
|
2015-07-06 08:19:49 +00:00
|
|
|
INFOF("Attempting to bind local socket w. addr %s, broadcast %s",
|
|
|
|
alloca_socket_address(&addr), alloca_socket_address(&broadcast));
|
2014-10-31 04:30:03 +00:00
|
|
|
overlay_interface_init(ifconfig->file, &addr, &netmask, &broadcast, ifconfig);
|
2013-12-11 06:11:57 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2011-08-13 11:17:49 +00:00
|
|
|
}
|
|
|
|
}
|
2012-06-15 05:34:36 +00:00
|
|
|
|
2012-12-04 03:42:28 +00:00
|
|
|
// Register new real interfaces
|
|
|
|
if (detect_real_interfaces) {
|
2012-07-25 07:23:44 +00:00
|
|
|
int no_route = 1;
|
2012-06-08 07:01:59 +00:00
|
|
|
#ifdef HAVE_IFADDRS_H
|
2012-07-25 07:23:44 +00:00
|
|
|
if (no_route != 0)
|
|
|
|
no_route = doifaddrs();
|
2012-06-08 07:01:59 +00:00
|
|
|
#endif
|
2012-05-28 05:24:33 +00:00
|
|
|
#ifdef SIOCGIFCONF
|
2012-07-25 07:23:44 +00:00
|
|
|
if (no_route != 0)
|
|
|
|
no_route = lsif();
|
2012-05-03 13:16:00 +00:00
|
|
|
#endif
|
2012-05-28 05:24:33 +00:00
|
|
|
#ifdef linux
|
2012-07-25 07:23:44 +00:00
|
|
|
if (no_route != 0)
|
|
|
|
no_route = scrapeProcNetRoute();
|
2012-05-28 05:24:33 +00:00
|
|
|
#endif
|
2012-07-25 07:23:44 +00:00
|
|
|
if (no_route != 0) {
|
|
|
|
FATAL("Unable to get any interface information");
|
|
|
|
}
|
2012-04-28 02:55:19 +00:00
|
|
|
}
|
2012-12-04 03:42:28 +00:00
|
|
|
|
|
|
|
// Close any interfaces that have gone away.
|
2014-06-12 06:33:52 +00:00
|
|
|
unsigned inet_up_count=0;
|
2014-06-02 04:39:22 +00:00
|
|
|
for(i = 0; i < OVERLAY_MAX_INTERFACES; i++){
|
|
|
|
if (overlay_interfaces[i].state==INTERFACE_STATE_DETECTING)
|
2012-07-25 07:23:44 +00:00
|
|
|
overlay_interface_close(&overlay_interfaces[i]);
|
2014-06-12 06:33:52 +00:00
|
|
|
if (overlay_interfaces[i].state==INTERFACE_STATE_UP &&
|
|
|
|
overlay_interfaces[i].address.addr.sa_family == AF_INET)
|
|
|
|
inet_up_count++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (inet_up_count==0 && sock_any.poll.fd>0){
|
|
|
|
unwatch(&sock_any);
|
|
|
|
close(sock_any.poll.fd);
|
|
|
|
sock_any.poll.fd=-1;
|
2014-06-02 04:39:22 +00:00
|
|
|
}
|
2012-12-04 03:42:28 +00:00
|
|
|
|
2014-06-02 04:39:22 +00:00
|
|
|
// if there are no real interfaces to detect, we can wait for the config file to change
|
|
|
|
if (detect_real_interfaces){
|
|
|
|
alarm->alarm = gettime_ms()+5000;
|
|
|
|
alarm->deadline = alarm->alarm + 10000;
|
|
|
|
schedule(alarm);
|
|
|
|
}
|
2012-06-22 03:55:41 +00:00
|
|
|
return;
|
2011-08-08 14:41:46 +00:00
|
|
|
}
|
|
|
|
|
2013-09-01 08:03:32 +00:00
|
|
|
void logServalPacket(int level, struct __sourceloc __whence, const char *message, const unsigned char *packet, size_t len) {
|
2012-08-03 07:14:05 +00:00
|
|
|
struct mallocbuf mb = STRUCT_MALLOCBUF_NULL;
|
2013-02-04 20:20:06 +00:00
|
|
|
if (!message) message="<no message>";
|
2013-09-02 05:24:33 +00:00
|
|
|
if (serval_packetvisualise_xpf(XPRINTF_MALLOCBUF(&mb), message, packet, len) == -1)
|
2012-08-01 08:24:02 +00:00
|
|
|
WHY("serval_packetvisualise() failed");
|
2012-08-03 07:14:05 +00:00
|
|
|
else if (mb.buffer == NULL)
|
2013-07-19 01:14:54 +00:00
|
|
|
WHYF("serval_packetvisualise() output buffer missing, message=%s packet=%p len=%lu", alloca_toprint(-1, message, strlen(message)), packet, (long unsigned int)len);
|
2012-08-01 08:24:02 +00:00
|
|
|
else
|
2012-10-16 06:16:52 +00:00
|
|
|
logString(level, __whence, mb.buffer);
|
2012-08-03 07:14:05 +00:00
|
|
|
if (mb.buffer)
|
|
|
|
free(mb.buffer);
|
2012-08-01 08:24:02 +00:00
|
|
|
}
|