Merge branch 'msp' into development

This commit is contained in:
Jeremy Lakeman 2014-01-09 15:08:00 +10:30
commit 31ab78fdf2
52 changed files with 2301 additions and 803 deletions

View File

@ -1080,7 +1080,10 @@ int app_mdp_ping(const struct cli_parsed *parsed, struct cli_context *context)
if (broadcast)
WARN("broadcast ping packets will not be encrypted");
for (; icount==0 || tx_count<icount; ++sequence_number) {
sigIntFlag = 0;
signal(SIGINT, sigIntHandler);
for (; sigIntFlag==0 && (icount==0 || tx_count<icount); ++sequence_number) {
// send a ping packet
{
@ -1100,7 +1103,7 @@ int app_mdp_ping(const struct cli_parsed *parsed, struct cli_context *context)
with appropriate information as required */
time_ms_t now = gettime_ms();
time_ms_t finish = now + ((tx_count < icount || icount==0)?interval_ms:timeout_ms);
for (; !servalShutdown && now < finish; now = gettime_ms()) {
for (; sigIntFlag==0 && now < finish; now = gettime_ms()) {
time_ms_t poll_timeout_ms = finish - gettime_ms();
if (mdp_poll(mdp_sockfd, poll_timeout_ms)<=0)
@ -1163,6 +1166,8 @@ int app_mdp_ping(const struct cli_parsed *parsed, struct cli_context *context)
}
}
signal(SIGINT, SIG_DFL);
sigIntFlag = 0;
mdp_close(mdp_sockfd);
{
@ -2261,6 +2266,7 @@ static int app_keyring_set_tag(const struct cli_parsed *parsed, struct cli_conte
return r;
}
// returns -1 on error, -2 on timeout, packet length on success.
ssize_t mdp_poll_recv(int mdp_sock, time_ms_t timeout, struct mdp_header *rev_header, unsigned char *payload, size_t buffer_size)
{
time_ms_t now = gettime_ms();
@ -3055,6 +3061,10 @@ struct cli_schema command_line_options[]={
"Run byte order handling test"},
{app_slip_test,{"test","slip","[--seed=<N>]","[--duration=<seconds>|--iterations=<N>]",NULL}, 0,
"Run serial encapsulation test"},
{app_msp_connection,{"msp", "listen", "[--once]", "[--forward=<local_port>]", "<port>", NULL}, 0,
"Listen for incoming connections"},
{app_msp_connection,{"msp", "connect", "[--once]", "[--forward=<local_port>]", "<sid>", "<port>", NULL}, 0,
"Connect to a remote party"},
#ifdef HAVE_VOIPTEST
{app_pa_phone,{"phone",NULL}, 0,
"Run phone test application"},

View File

@ -985,14 +985,6 @@ int vld_network_interface(const struct cf_om_node *parent, struct config_network
return result | CFINCOMPLETE;
}
} else {
if (nifp->socket_type == SOCK_DGRAM && nifp->file[0]){
int nodei_socket_type = cf_om_get_child(parent, "socket_type", NULL);
int nodei_file = cf_om_get_child(parent, "file", NULL);
assert(nodei_socket_type != -1);
assert(nodei_file != -1);
cf_warn_incompatible(parent->nodv[nodei_socket_type], parent->nodv[nodei_file]);
return result | CFSUB(CFINCOMPATIBLE);
}
if (nifp->socket_type != SOCK_DGRAM && !nifp->file[0]){
cf_warn_missing_node(parent, "file");
return result | CFSUB(CFINCOMPATIBLE);

View File

@ -242,6 +242,7 @@ ATOM(bool_t, gateway, 0, boolean,, "")
ATOM(bool_t, keyring, 0, boolean,, "")
ATOM(bool_t, security, 0, boolean,, "")
ATOM(bool_t, mdprequests, 0, boolean,, "")
ATOM(bool_t, msp, 0, boolean,, "")
ATOM(bool_t, radio_link, 0, boolean,, "")
ATOM(bool_t, peers, 0, boolean,, "")
ATOM(bool_t, overlaybuffer, 0, boolean,, "")

View File

@ -239,3 +239,13 @@ uint16_t read_uint16(const unsigned char *o)
for(i=0;i<2;i++) v=(v<<8)|o[2-1-i];
return v;
}
int compare_wrapped_uint8(uint8_t one, uint8_t two)
{
return (int8_t)(one - two);
}
int compare_wrapped_uint16(uint16_t one, uint16_t two)
{
return (int16_t)(one - two);
}

View File

@ -42,4 +42,9 @@ uint64_t read_uint64(const unsigned char *o);
uint32_t read_uint32(const unsigned char *o);
uint16_t read_uint16(const unsigned char *o);
// compare sequence numbers that wrap
// returns <0 if one is before two, 0 if they are the same, else >0
int compare_wrapped_uint8(uint8_t one, uint8_t two);
int compare_wrapped_uint16(uint16_t one, uint16_t two);
#endif //__SERVAL_DNA___DATA_FORMATS_H

View File

@ -22,7 +22,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#endif
#include <stdio.h>
#include <unistd.h>
#include <inttypes.h>
#include "constants.h"
#include "serval.h"
#include "mdp_client.h"
#include "str.h"

View File

@ -204,7 +204,9 @@ int _watch(struct __sourceloc __whence, struct sched_ent *alarm)
WARN("watch() called without supplying an alarm name");
if (!alarm->function)
return WHY("Can't watch if you haven't set the function pointer");
FATAL("Can't watch if you haven't set the function pointer");
if (!alarm->poll.events)
FATAL("Can't watch if you haven't set any poll flags");
if (alarm->_poll_index>=0 && fd_callbacks[alarm->_poll_index]==alarm){
// updating event flags

View File

@ -3,6 +3,7 @@ HDRS= fifo.h \
overlay_buffer.h \
overlay_address.h \
overlay_packet.h \
overlay_interface.h \
rhizome.h \
serval.h \
keyring.h \
@ -28,5 +29,6 @@ HDRS= fifo.h \
constants.h \
monitor-client.h \
mdp_client.h \
msp_client.h \
radio_link.h \
sqlite-amalgamation-3070900/sqlite3.h

View File

@ -30,6 +30,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "nacl.h"
#include "overlay_address.h"
#include "crypto.h"
#include "overlay_interface.h"
#include "overlay_packet.h"
#include "keyring.h"
#include "dataformats.h"

54
lsif.c
View File

@ -26,9 +26,6 @@
*
*/
#include "serval.h"
#include "conf.h"
#include <assert.h>
#include <errno.h>
#include <stdlib.h>
@ -61,6 +58,9 @@
#include <ifaddrs.h>
#endif
#include "conf.h"
#include "overlay_interface.h"
/* On platforms that have variable length
ifreq use the old fixed length interface instead */
#ifdef OSIOCGIFCONF
@ -97,12 +97,22 @@ int scrapeProcNetRoute()
line[0] = '\0';
if (fgets(line,1024,f) == NULL)
return WHYF_perror("fgets(%p,1024,\"/proc/net/route\")", line);
struct socket_address addr, broadcast;
bzero(&addr, sizeof(addr));
bzero(&broadcast, sizeof(broadcast));
addr.addrlen = sizeof(addr.inet);
addr.inet.sin_family = AF_INET;
broadcast.addrlen = sizeof(addr.inet);
broadcast.inet.sin_family = AF_INET;
while(line[0]) {
int r;
if ((r=sscanf(line,"%s %s %*s %*s %*s %*s %*s %s",name,dest,mask))==3) {
struct in_addr addr = {.s_addr=strtol(dest,NULL,16)};
addr.inet.sin_addr.s_addr=strtol(dest,NULL,16);
struct in_addr netmask = {.s_addr=strtol(mask,NULL,16)};
overlay_interface_register(name,addr,netmask);
broadcast.inet.sin_addr.s_addr=addr.inet.sin_addr.s_addr | ~netmask.s_addr;
overlay_interface_register(name,&addr,&broadcast);
}
line[0] = '\0';
if (fgets(line,1024,f) == NULL)
@ -126,8 +136,11 @@ lsif(void) {
struct ifconf ifc;
int sck;
struct ifreq *ifr;
struct in_addr addr, netmask;
struct in_addr netmask;
struct socket_address addr, broadcast;
bzero(&addr, sizeof(addr));
bzero(&broadcast, sizeof(broadcast));
if (config.debug.overlayinterfaces) DEBUG("called");
/* Get a socket handle. */
@ -146,6 +159,9 @@ lsif(void) {
return 1;
}
broadcast.addrlen = sizeof(addr.inet);
broadcast.inet.sin_family = AF_INET;
/* Iterate through the list of interfaces. */
unsigned nInterfaces = 0;
unsigned ofs = 0;
@ -158,8 +174,9 @@ lsif(void) {
if (config.debug.overlayinterfaces) DEBUGF("Skipping non-AF_INET address on %s", ifr->ifr_name);
continue;
}
addr = ((struct sockaddr_in *)&ifr->ifr_ifru.ifru_addr)->sin_addr;
addr.addrlen = sizeof(addr.inet);
bcopy(&ifr->ifr_ifru.ifru_addr, &addr.addr, addr.addrlen);
/* Get interface flags */
if (ioctl(sck, SIOCGIFFLAGS, ifr) == -1)
@ -178,7 +195,9 @@ lsif(void) {
}
netmask = ((struct sockaddr_in *)&ifr->ifr_ifru.ifru_addr)->sin_addr;
overlay_interface_register(ifr->ifr_name, addr, netmask);
broadcast.inet.sin_addr.s_addr=addr.inet.sin_addr.s_addr | ~netmask.s_addr;
overlay_interface_register(ifr->ifr_name, &addr, &broadcast);
nInterfaces++;
}
@ -195,13 +214,19 @@ int
doifaddrs(void) {
struct ifaddrs *ifaddr, *ifa;
char *name;
struct in_addr addr, netmask;
struct socket_address addr, broadcast;
struct in_addr netmask;
bzero(&addr, sizeof(addr));
bzero(&broadcast, sizeof(broadcast));
if (config.debug.overlayinterfaces) DEBUGF("called");
if (getifaddrs(&ifaddr) == -1)
return WHY_perror("getifaddr()");
broadcast.addrlen = sizeof(addr.inet);
broadcast.inet.sin_family = AF_INET;
for (ifa = ifaddr; ifa != NULL ; ifa = ifa->ifa_next) {
if (!ifa->ifa_addr || !ifa->ifa_netmask)
continue;
@ -219,10 +244,13 @@ doifaddrs(void) {
}
name = ifa->ifa_name;
addr = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
addr.addrlen = sizeof(addr.inet);
bcopy(ifa->ifa_addr, &addr.addr, addr.addrlen);
netmask = ((struct sockaddr_in *)ifa->ifa_netmask)->sin_addr;
broadcast.inet.sin_addr.s_addr=addr.inet.sin_addr.s_addr | ~netmask.s_addr;
overlay_interface_register(name, addr, netmask);
overlay_interface_register(name, &addr, &broadcast);
}
freeifaddrs(ifaddr);

View File

@ -26,6 +26,7 @@
#include "strbuf_helpers.h"
#include "overlay_buffer.h"
#include "overlay_address.h"
#include "overlay_interface.h"
#include "overlay_packet.h"
#include "mdp_client.h"
#include "socket.h"
@ -36,22 +37,6 @@ int mdp_socket(void)
return overlay_mdp_client_socket();
}
static void mdp_unlink(int mdp_sock)
{
// get the socket name and unlink it from the filesystem if not abstract
struct socket_address addr;
addr.addrlen = sizeof addr.store;
if (getsockname(mdp_sock, &addr.addr, &addr.addrlen))
WHYF_perror("getsockname(%d)", mdp_sock);
else if (addr.addr.sa_family==AF_UNIX
&& addr.addrlen > sizeof addr.local.sun_family
&& addr.addrlen <= sizeof addr.local && addr.local.sun_path[0] != '\0') {
if (unlink(addr.local.sun_path) == -1)
WARNF_perror("unlink(%s)", alloca_str_toprint(addr.local.sun_path));
}
close(mdp_sock);
}
int mdp_close(int socket)
{
// tell the daemon to drop all bindings
@ -63,7 +48,7 @@ int mdp_close(int socket)
mdp_send(socket, &header, NULL, 0);
// remove socket
mdp_unlink(socket);
socket_unlink_close(socket);
return 0;
}
@ -229,7 +214,7 @@ int overlay_mdp_client_close(int mdp_sockfd)
mdp.packetTypeAndFlags = MDP_GOODBYE;
overlay_mdp_send(mdp_sockfd, &mdp, 0, 0);
mdp_unlink(mdp_sockfd);
socket_unlink_close(mdp_sockfd);
return 0;
}

View File

@ -19,8 +19,6 @@
#ifndef __SERVAL_DNA__MDP_CLIENT_H
#define __SERVAL_DNA__MDP_CLIENT_H
#include "serval.h"
// define 3rd party mdp API without any structure padding
#pragma pack(push, 1)
@ -95,7 +93,6 @@ ssize_t mdp_recv(int socket, struct mdp_header *header, uint8_t *payload, ssize_
int mdp_poll(int socket, time_ms_t timeout_ms);
/* Client-side MDP function */
int overlay_mdp_client_socket(void);
int overlay_mdp_client_close(int mdp_sockfd);

674
msp_client.c Normal file
View File

@ -0,0 +1,674 @@
#include <assert.h>
#include <inttypes.h>
#include "serval.h"
#include "conf.h"
#include "mdp_client.h"
#include "msp_client.h"
#include "str.h"
#include "dataformats.h"
#include "socket.h"
#include "log.h"
#define FLAG_SHUTDOWN (1<<0)
#define FLAG_ACK (1<<1)
struct msp_packet{
struct msp_packet *_next;
uint16_t seq;
uint8_t flags;
time_ms_t added;
time_ms_t sent;
const uint8_t *payload;
size_t len;
};
#define MAX_WINDOW_SIZE 4
struct msp_window{
int packet_count;
uint32_t base_rtt;
uint32_t rtt;
uint16_t next_seq; // seq of next expected TX or RX packet.
time_ms_t last_activity;
struct msp_packet *_head, *_tail;
};
struct msp_sock{
struct msp_sock *_next;
struct msp_sock *_prev;
int mdp_sock;
msp_state_t state;
struct msp_window tx;
struct msp_window rx;
uint16_t previous_ack;
time_ms_t next_ack;
int (*handler)(struct msp_sock *sock, msp_state_t state, const uint8_t *payload, size_t len, void *context);
void *context;
struct mdp_header header;
time_ms_t timeout;
time_ms_t next_action;
};
struct msp_sock *root=NULL;
struct msp_sock * msp_socket(int mdp_sock)
{
struct msp_sock *ret = emalloc_zero(sizeof(struct msp_sock));
ret->mdp_sock = mdp_sock;
ret->state = MSP_STATE_UNINITIALISED;
ret->_next = root;
// TODO set base rtt to ensure that we send the first packet a few times before giving up
ret->tx.base_rtt = ret->tx.rtt = 0xFFFFFFFF;
ret->tx.last_activity = TIME_NEVER_HAS;
ret->rx.last_activity = TIME_NEVER_HAS;
ret->next_action = TIME_NEVER_WILL;
ret->timeout = gettime_ms() + 10000;
ret->previous_ack = 0x7FFF;
if (root)
root->_prev=ret;
root = ret;
return ret;
}
unsigned msp_socket_count()
{
unsigned i=0;
struct msp_sock *p=root;
while(p){
i++;
p=p->_next;
}
return i;
}
void msp_debug()
{
time_ms_t now = gettime_ms();
struct msp_sock *p=root;
DEBUGF("Msp sockets;");
while(p){
DEBUGF("State %d, from %s:%d to %s:%d, next %"PRId64"ms, ack %"PRId64"ms timeout %"PRId64"ms",
p->state,
alloca_tohex_sid_t(p->header.local.sid), p->header.local.port,
alloca_tohex_sid_t(p->header.remote.sid), p->header.remote.port,
(p->next_action - now),
(p->next_ack - now),
(p->timeout - now));
p=p->_next;
}
}
static void free_all_packets(struct msp_window *window)
{
struct msp_packet *p = window->_head;
while(p){
struct msp_packet *free_me=p;
p=p->_next;
if (free_me->payload)
free((void *)free_me->payload);
free(free_me);
}
}
static void free_acked_packets(struct msp_window *window, uint16_t seq)
{
if (!window->_head)
return;
struct msp_packet *p = window->_head;
uint32_t rtt=0;
time_ms_t now = gettime_ms();
while(p && compare_wrapped_uint16(p->seq, seq)<=0){
if (p->sent)
rtt = now - p->sent;
struct msp_packet *free_me=p;
p=p->_next;
if (free_me->payload)
free((void *)free_me->payload);
free(free_me);
window->packet_count--;
}
window->_head = p;
if (rtt){
if (rtt < 10)
rtt=10;
window->rtt = rtt;
if (window->base_rtt > rtt)
window->base_rtt = rtt;
if (config.debug.msp)
DEBUGF("RTT %u, base %u", rtt, window->base_rtt);
}
if (!p)
window->_tail = NULL;
}
static void msp_free(struct msp_sock *sock)
{
sock->state |= MSP_STATE_CLOSED;
// remove from the list first
if (sock->_prev)
sock->_prev->_next = sock->_next;
else
root=sock->_next;
if (sock->_next)
sock->_next->_prev = sock->_prev;
// last chance to free other resources
if (sock->handler)
sock->handler(sock, sock->state, NULL, 0, sock->context);
free_all_packets(&sock->tx);
free_all_packets(&sock->rx);
free(sock);
}
void msp_close(struct msp_sock *sock)
{
// TODO if never sent / received, just free it
sock->state |= MSP_STATE_CLOSED;
}
void msp_close_all(int mdp_sock)
{
struct msp_sock *p = root;
while(p){
struct msp_sock *sock=p;
p=p->_next;
if (sock->mdp_sock == mdp_sock)
msp_free(sock);
}
}
int msp_set_handler(struct msp_sock *sock,
int (*handler)(struct msp_sock *sock, msp_state_t state, const uint8_t *payload, size_t len, void *context),
void *context)
{
sock->handler = handler;
sock->context = context;
return 0;
}
msp_state_t msp_get_state(struct msp_sock *sock)
{
return sock->state;
}
int msp_set_local(struct msp_sock *sock, struct mdp_sockaddr local)
{
assert(sock->state == MSP_STATE_UNINITIALISED);
sock->header.local = local;
return 0;
}
int msp_set_remote(struct msp_sock *sock, struct mdp_sockaddr remote)
{
assert(sock->state == MSP_STATE_UNINITIALISED);
sock->header.remote = remote;
sock->state|=MSP_STATE_DATAOUT;
// make sure we send a packet soon
sock->next_ack = gettime_ms()+10;
sock->next_action = sock->next_ack;
return 0;
}
int msp_listen(struct msp_sock *sock)
{
assert(sock->state == MSP_STATE_UNINITIALISED);
assert(sock->header.local.port);
sock->state |= MSP_STATE_LISTENING;
sock->header.flags |= MDP_FLAG_BIND;
if (mdp_send(sock->mdp_sock, &sock->header, NULL, 0)==-1){
sock->state|=MSP_STATE_ERROR|MSP_STATE_CLOSED;
return -1;
}
sock->timeout = gettime_ms()+1000;
sock->next_action = sock->timeout;
return 0;
}
int msp_get_remote_adr(struct msp_sock *sock, struct mdp_sockaddr *remote)
{
*remote = sock->header.remote;
return 0;
}
static int add_packet(struct msp_window *window, uint16_t seq, uint8_t flags,
const uint8_t *payload, size_t len)
{
struct msp_packet **insert_pos=NULL;
if (!window->_head){
insert_pos = &window->_head;
}else{
if (window->_tail->seq == seq){
// ignore duplicate packets
return 0;
}else if (compare_wrapped_uint16(window->_tail->seq, seq)<0){
if (compare_wrapped_uint16(window->_head->seq, seq)>0){
// this is ambiguous
return WHYF("%04x is both < tail (%04x) and > head (%04x)", seq, window->_tail->seq, window->_head->seq);
}
insert_pos = &window->_tail->_next;
}else{
insert_pos = &window->_head;
while(compare_wrapped_uint16((*insert_pos)->seq, seq)<0)
insert_pos = &(*insert_pos)->_next;
if ((*insert_pos)->seq == seq){
// ignore duplicate packets
return 0;
}
}
}
struct msp_packet *packet = emalloc_zero(sizeof(struct msp_packet));
if (!packet)
return -1;
packet->_next = (*insert_pos);
*insert_pos = packet;
if (!packet->_next)
window->_tail = packet;
packet->added = gettime_ms();
packet->seq = seq;
packet->flags = flags;
packet->len = len;
if (payload && len){
uint8_t *p = emalloc(len);
if (!p){
free(packet);
return -1;
}
packet->payload = p;
bcopy(payload, p, len);
}
window->packet_count++;
return 1;
}
struct socket_address daemon_addr={.addrlen=0,};
static int msp_send_packet(struct msp_sock *sock, struct msp_packet *packet)
{
assert(sock->header.remote.port);
if (daemon_addr.addrlen == 0){
if (make_local_sockaddr(&daemon_addr, "mdp.2.socket") == -1)
return -1;
}
uint8_t msp_header[5];
msp_header[0]=packet->flags;
// only set the ack flag if we've received a sequenced packet
if (sock->state & MSP_STATE_RECEIVED_DATA)
msp_header[0]|=FLAG_ACK;
write_uint16(&msp_header[1], sock->rx.next_seq);
write_uint16(&msp_header[3], packet->seq);
sock->previous_ack = sock->rx.next_seq;
struct fragmented_data data={
.fragment_count=3,
.iov={
{
.iov_base = (void*)&sock->header,
.iov_len = sizeof(struct mdp_header)
},
{
.iov_base = &msp_header,
.iov_len = sizeof(msp_header)
},
{
.iov_base = (void*)packet->payload,
.iov_len = packet->len
}
}
};
// allow for sending an empty payload body
if (!(packet->payload && packet->len))
data.fragment_count --;
ssize_t r = send_message(sock->mdp_sock, &daemon_addr, &data);
if (r==-1){
if (errno==11)
return 1;
msp_close_all(sock->mdp_sock);
return -1;
}
if (config.debug.msp)
DEBUGF("Sent packet seq %02x len %zd (acked %02x)", packet->seq, packet->len, sock->rx.next_seq);
sock->tx.last_activity = packet->sent = gettime_ms();
sock->next_ack = packet->sent + 1500;
return 0;
}
static int send_ack(struct msp_sock *sock)
{
assert(sock->header.remote.port);
if (daemon_addr.addrlen == 0){
if (make_local_sockaddr(&daemon_addr, "mdp.2.socket") == -1)
return -1;
}
uint8_t msp_header[3];
msp_header[0]=0;
// if we haven't heard a sequence number, we can't ack data
// (but we can indicate the existence of the connection)
if (sock->state & MSP_STATE_RECEIVED_DATA)
msp_header[0]|=FLAG_ACK;
write_uint16(&msp_header[1], sock->rx.next_seq);
struct fragmented_data data={
.fragment_count=2,
.iov={
{
.iov_base = (void*)&sock->header,
.iov_len = sizeof(struct mdp_header)
},
{
.iov_base = &msp_header,
.iov_len = sizeof(msp_header)
}
}
};
ssize_t r = send_message(sock->mdp_sock, &daemon_addr, &data);
if (r==-1){
if (errno!=11)
msp_close_all(sock->mdp_sock);
return -1;
}
if (config.debug.msp)
DEBUGF("Sent packet (acked %02x)", sock->rx.next_seq);
sock->previous_ack = sock->rx.next_seq;
sock->tx.last_activity = gettime_ms();
sock->next_ack = sock->tx.last_activity + 1500;
return 0;
}
// add a packet to the transmit buffer
int msp_send(struct msp_sock *sock, const uint8_t *payload, size_t len)
{
assert(sock->header.remote.port);
assert((sock->state & MSP_STATE_SHUTDOWN_LOCAL)==0);
if (sock->tx.packet_count > MAX_WINDOW_SIZE)
return -1;
if (add_packet(&sock->tx, sock->tx.next_seq, 0, payload, len)==-1)
return -1;
sock->tx.next_seq++;
if (sock->tx.packet_count>=MAX_WINDOW_SIZE)
sock->state&=~MSP_STATE_DATAOUT;
// make sure we attempt to process packets from this sock soon
// TODO calculate based on congestion window
sock->next_action = gettime_ms();
return 0;
}
int msp_shutdown(struct msp_sock *sock)
{
if (sock->tx._tail && sock->tx._tail->sent==0){
sock->tx._tail->flags |= FLAG_SHUTDOWN;
}else{
if (add_packet(&sock->tx, sock->tx.next_seq, FLAG_SHUTDOWN, NULL, 0)==-1)
return -1;
sock->tx.next_seq++;
}
sock->state|=MSP_STATE_SHUTDOWN_LOCAL;
sock->state&=~MSP_STATE_DATAOUT;
// make sure we send a packet soon
sock->next_action = gettime_ms();
return 0;
}
static int process_sock(struct msp_sock *sock)
{
time_ms_t now = gettime_ms();
if (sock->timeout < now){
WHY("MSP socket timed out");
sock->state |= (MSP_STATE_CLOSED|MSP_STATE_ERROR);
return -1;
}
sock->next_action = sock->timeout;
if (sock->state & MSP_STATE_LISTENING)
return 0;
struct msp_packet *p;
// deliver packets that have now arrived in order
p = sock->rx._head;
// TODO ... ? (sock->state & MSP_STATE_POLLIN)
while(p && p->seq == sock->rx.next_seq){
struct msp_packet *packet=p;
// process packet flags when we have delivered the packet
if (packet->flags & FLAG_SHUTDOWN)
sock->state|=MSP_STATE_SHUTDOWN_REMOTE;
if (sock->handler && packet->payload){
int r = sock->handler(sock, sock->state, packet->payload, packet->len, sock->context);
if (r==-1){
sock->state |= MSP_STATE_CLOSED;
return -1;
}
// keep the packet if the handler refused to accept it.
if (r){
sock->next_action=gettime_ms()+1;
break;
}
}
p=p->_next;
sock->rx.next_seq++;
}
free_acked_packets(&sock->rx, sock->rx.next_seq -1);
// transmit packets that can now be sent
p = sock->tx._head;
while(p){
if (p->sent==0 || p->sent + 1500 < now){
if (!sock->header.local.port){
if (sock->header.flags & MDP_FLAG_BIND)
// wait until we have heard back from the daemon with our port number before sending another packet.
break;
sock->header.flags |= MDP_FLAG_BIND;
}
int r = msp_send_packet(sock, p);
if (r==-1)
return -1;
if (r)
break;
}
if (sock->next_action > p->sent + 1500)
sock->next_action = p->sent + 1500;
p=p->_next;
}
// should we send an ack now without sending a payload?
if (now > sock->next_ack){
if (!sock->header.local.port){
if (sock->header.flags & MDP_FLAG_BIND)
// wait until we have heard back from the daemon with our port number before sending another packet.
return 0;
sock->header.flags |= MDP_FLAG_BIND;
}
int r = send_ack(sock);
if (r==-1)
return -1;
}
if (sock->next_action > sock->next_ack)
sock->next_action = sock->next_ack;
if (sock->state & MSP_STATE_SHUTDOWN_LOCAL
&& sock->state & MSP_STATE_SHUTDOWN_REMOTE
&& sock->tx.packet_count == 0
&& sock->rx.packet_count == 0
&& sock->previous_ack == sock->rx.next_seq){
sock->state |= MSP_STATE_CLOSED;
return -1;
}
return 0;
}
int msp_processing(time_ms_t *next_action)
{
*next_action=TIME_NEVER_WILL;
struct msp_sock *sock = root;
time_ms_t now = gettime_ms();
while(sock){
if (!(sock->state & MSP_STATE_CLOSED)
&& sock->next_action <= now){
// this might cause the socket to be closed.
if (process_sock(sock)==0){
// remember the time of the next thing we need to do.
if (sock->next_action < *next_action)
*next_action=sock->next_action;
}
}else if (sock->next_action < *next_action)
*next_action=sock->next_action;
if (sock->state & MSP_STATE_CLOSED){
struct msp_sock *s = sock->_next;
msp_free(sock);
sock=s;
}else{
sock = sock->_next;
}
}
return 0;
}
static int process_packet(int mdp_sock, struct mdp_header *header, const uint8_t *payload, size_t len)
{
// any kind of error reported by the daemon, close all related msp connections
if (header->flags & MDP_FLAG_ERROR){
WHY("Error returned from daemon");
msp_close_all(mdp_sock);
return -1;
}
// find or create mdp_sock...
struct msp_sock *sock=NULL;
{
struct msp_sock *s=root;
struct msp_sock *listen=NULL;
while(s){
if (s->mdp_sock == mdp_sock ){
if ((s->header.flags & MDP_FLAG_BIND) && (header->flags & MDP_FLAG_BIND)){
// process bind response from the daemon
s->header.local = header->local;
s->header.flags &= ~MDP_FLAG_BIND;
if (config.debug.msp)
DEBUGF("Bound to %s:%d", alloca_tohex_sid_t(header->local.sid), header->local.port);
s->next_action = gettime_ms();
if (s->state & MSP_STATE_LISTENING)
s->timeout = TIME_NEVER_WILL;
return 0;
}
if (s->state & MSP_STATE_LISTENING){
// remember any matching listen socket so we can create a connection on first use
if (s->header.local.port == header->local.port
&& (is_sid_t_any(s->header.local.sid)
|| memcmp(&s->header.local.sid, &header->local.sid, SID_SIZE)==0))
listen=s;
}else if (memcmp(&s->header.remote, &header->remote, sizeof header->remote)==0
&& memcmp(&s->header.local, &header->local, sizeof header->local)==0){
// if the addresses match, we found it.
sock=s;
break;
}
}
s = s->_next;
}
if (listen && !sock){
// create a new socket for the incoming connection
sock = msp_socket(listen->mdp_sock);
sock->header = *header;
// use the same handler initially
sock->handler = listen->handler;
sock->context = listen->context;
}
if (!sock){
WARNF("Unexpected packet from %s:%d", alloca_tohex_sid_t(header->remote.sid), header->remote.port);
// TODO reply with shutdown ack to forcefully break the connection?
return 0;
}
}
if (len<3)
return WHY("Expected at least 3 bytes");
sock->rx.last_activity = gettime_ms();
sock->timeout = sock->rx.last_activity + 10000;
uint8_t flags = payload[0];
if (flags & FLAG_ACK){
uint16_t ack_seq = read_uint16(&payload[1]);
// release acknowledged packets
free_acked_packets(&sock->tx, ack_seq);
// TODO if their ack seq has not advanced, we may need to hurry up and retransmit a packet
}
if (sock->tx.packet_count < MAX_WINDOW_SIZE
&& !(sock->state & MSP_STATE_DATAOUT)
&& !(sock->state & MSP_STATE_SHUTDOWN_LOCAL)){
sock->state|=MSP_STATE_DATAOUT;
if (sock->handler)
sock->handler(sock, sock->state, NULL, 0, sock->context);
}
// make sure we attempt to process packets from this sock soon
// TODO calculate based on congestion window
sock->state |= MSP_STATE_RECEIVED_PACKET;
sock->next_action = gettime_ms();
if (len<5)
return 0;
sock->state |= MSP_STATE_RECEIVED_DATA;
uint16_t seq = read_uint16(&payload[3]);
if (add_packet(&sock->rx, seq, flags, &payload[5], len - 5)==1)
sock->next_ack = gettime_ms();
return 0;
}
int msp_recv(int mdp_sock)
{
struct mdp_header header;
uint8_t payload[1200];
ssize_t len = mdp_recv(mdp_sock, &header, payload, sizeof(payload));
if (len<0)
return -1;
return process_packet(mdp_sock, &header, payload, len);
}

57
msp_client.h Normal file
View File

@ -0,0 +1,57 @@
#ifndef __SERVALD_MSP_CLIENT_H
#define __SERVALD_MSP_CLIENT_H
#define MSP_STATE_UNINITIALISED 0
#define MSP_STATE_LISTENING (1<<0)
#define MSP_STATE_RECEIVED_DATA (1<<1)
#define MSP_STATE_RECEIVED_PACKET (1<<2)
#define MSP_STATE_SHUTDOWN_LOCAL (1<<3)
#define MSP_STATE_SHUTDOWN_REMOTE (1<<4)
// this connection is about to be free'd, release any other resources or references to the state
#define MSP_STATE_CLOSED (1<<5)
// something has gone wrong somewhere
#define MSP_STATE_ERROR (1<<6)
// is there space for sending more data?
#define MSP_STATE_DATAOUT (1<<7)
struct msp_sock;
typedef uint16_t msp_state_t;
// allocate a new socket
struct msp_sock * msp_socket(int mdp_sock);
void msp_close(struct msp_sock *sock);
void msp_close_all(int mdp_sock);
unsigned msp_socket_count();
void msp_debug();
int msp_set_handler(struct msp_sock *sock,
int (*handler)(struct msp_sock *sock, msp_state_t state, const uint8_t *payload, size_t len, void *context),
void *context);
// the local address is only set when calling msp_listen or msp_send
int msp_set_local(struct msp_sock *sock, struct mdp_sockaddr local);
int msp_set_remote(struct msp_sock *sock, struct mdp_sockaddr remote);
int msp_listen(struct msp_sock *sock);
int msp_get_remote_adr(struct msp_sock *sock, struct mdp_sockaddr *remote);
msp_state_t msp_get_state(struct msp_sock *sock);
// bind, send data, and potentially shutdown this end of the connection
int msp_send(struct msp_sock *sock, const uint8_t *payload, size_t len);
int msp_shutdown(struct msp_sock *sock);
// receive and process an incoming packet
int msp_recv(int mdp_sock);
// next_action indicates the next time that msp_processing should be called
int msp_processing(time_ms_t *next_action);
#endif

492
msp_proxy.c Normal file
View File

@ -0,0 +1,492 @@
#include "serval.h"
#include "str.h"
#include "strbuf.h"
#include "strbuf_helpers.h"
#include "dataformats.h"
#include "mdp_client.h"
#include "msp_client.h"
#include "socket.h"
struct buffer{
size_t position;
size_t limit;
size_t capacity;
uint8_t bytes[];
};
struct connection{
struct sched_ent alarm_in;
struct sched_ent alarm_out;
struct msp_sock *sock;
struct buffer *in;
struct buffer *out;
int last_state;
};
int saw_error=0;
int once =0;
struct msp_sock *listener=NULL;
struct mdp_sockaddr remote_addr;
struct socket_address ip_addr;
static int try_send(struct connection *conn);
static void msp_poll(struct sched_ent *alarm);
static void listen_poll(struct sched_ent *alarm);
static void io_poll(struct sched_ent *alarm);
struct profile_total mdp_sock_stats={
.name="msp_poll"
};
struct sched_ent mdp_sock={
.poll.revents = 0,
.poll.events = POLLIN,
.poll.fd = -1,
.function = msp_poll,
.stats = &mdp_sock_stats,
};
struct profile_total io_stats={
.name="io_stats"
};
struct profile_total listen_stats={
.name="listen_poll"
};
struct sched_ent listen_alarm={
.poll.revents = 0,
.poll.events = POLLIN,
.poll.fd = -1,
.function = listen_poll,
.stats = &listen_stats,
};
static struct connection *alloc_connection(
struct msp_sock *sock,
int fd_in,
void (*func_in)(struct sched_ent *alarm),
int fd_out,
void (*func_out)(struct sched_ent *alarm))
{
struct connection *conn = emalloc_zero(sizeof(struct connection));
if (!conn)
return NULL;
conn->sock = sock;
conn->alarm_in.poll.fd = fd_in;
conn->alarm_in.poll.events = POLLIN;
conn->alarm_in.function = func_in;
conn->alarm_in.stats = &io_stats;
conn->alarm_in.context = conn;
conn->alarm_out.poll.fd = fd_out;
conn->alarm_out.poll.events = POLLOUT;
conn->alarm_out.function = func_out;
conn->alarm_out.stats = &io_stats;
conn->alarm_out.context = conn;
watch(&conn->alarm_in);
conn->in = emalloc(1024 + sizeof(struct buffer));
if (!conn->in){
free(conn);
return NULL;
}
conn->out = emalloc(1024 + sizeof(struct buffer));
if (!conn->out){
free(conn->in);
free(conn);
return NULL;
}
conn->in->position = conn->out->position = 0;
conn->in->limit = conn->out->limit = 0;
conn->in->capacity = conn->out->capacity = 1024;
return conn;
}
static void free_connection(struct connection *conn)
{
if (!conn)
return;
if (is_watching(&conn->alarm_in))
unwatch(&conn->alarm_in);
if (is_watching(&conn->alarm_out))
unwatch(&conn->alarm_out);
if (conn->in)
free(conn->in);
if (conn->out)
free(conn->out);
if (conn->alarm_in.poll.fd!=-1)
close(conn->alarm_in.poll.fd);
if (conn->alarm_out.poll.fd!=-1 && conn->alarm_out.poll.fd != conn->alarm_in.poll.fd)
close(conn->alarm_out.poll.fd);
conn->in=NULL;
conn->out=NULL;
conn->alarm_in.poll.fd=-1;
conn->alarm_out.poll.fd=-1;
free(conn);
if (msp_socket_count()==0){
unschedule(&mdp_sock);
if (is_watching(&mdp_sock))
unwatch(&mdp_sock);
}
}
static void process_msp_asap()
{
mdp_sock.alarm = gettime_ms();
mdp_sock.deadline = mdp_sock.alarm+10;
unschedule(&mdp_sock);
schedule(&mdp_sock);
}
static int msp_handler(struct msp_sock *sock, msp_state_t state, const uint8_t *payload, size_t len, void *context)
{
struct connection *conn = context;
conn->last_state=state;
if (state & MSP_STATE_ERROR)
saw_error=1;
if (payload && len){
if (conn->out->limit){
// attempt to write immediately
conn->alarm_out.poll.revents=POLLOUT;
conn->alarm_out.function(&conn->alarm_out);
}
if (conn->out->capacity < len + conn->out->limit)
return 1;
bcopy(payload, &conn->out->bytes[conn->out->limit], len);
conn->out->limit+=len;
if (!is_watching(&conn->alarm_out))
watch(&conn->alarm_out);
// attempt to write immediately
conn->alarm_out.poll.revents=POLLOUT;
conn->alarm_out.function(&conn->alarm_out);
}
if (state & MSP_STATE_CLOSED){
struct mdp_sockaddr remote;
msp_get_remote_adr(sock, &remote);
INFOF(" - Connection with %s:%d closed", alloca_tohex_sid_t(remote.sid), remote.port);
conn->sock = NULL;
if (is_watching(&conn->alarm_in))
unwatch(&conn->alarm_in);
if (!is_watching(&conn->alarm_out))
free_connection(conn);
return 0;
}
if (state&MSP_STATE_DATAOUT)
try_send(conn);
return 0;
}
static int msp_listener(struct msp_sock *sock, msp_state_t state, const uint8_t *payload, size_t len, void *UNUSED(context))
{
if (state & MSP_STATE_ERROR){
WHY("Error listening for incoming connections");
}
if (state & MSP_STATE_CLOSED){
if (msp_socket_count()==0){
unschedule(&mdp_sock);
if (is_watching(&mdp_sock))
unwatch(&mdp_sock);
}
return 0;
}
struct mdp_sockaddr remote;
msp_get_remote_adr(sock, &remote);
INFOF(" - New connection from %s:%d", alloca_tohex_sid_t(remote.sid), remote.port);
int fd_in = STDIN_FILENO;
int fd_out = STDOUT_FILENO;
if (ip_addr.addrlen){
int fd = esocket(PF_INET, SOCK_STREAM, 0);
if (fd==-1){
msp_close(sock);
return -1;
}
if (socket_connect(fd, &ip_addr.addr, ip_addr.addrlen)==-1){
msp_close(sock);
close(fd);
return -1;
}
fd_in = fd_out = fd;
}
struct connection *conn = alloc_connection(sock, fd_in, io_poll, fd_out, io_poll);
if (!conn)
return -1;
conn->sock = sock;
watch(&conn->alarm_in);
msp_set_handler(sock, msp_handler, conn);
if (payload)
return msp_handler(sock, state, payload, len, conn);
if (once){
// stop listening after the first incoming connection
msp_close(listener);
}
return 0;
}
static void msp_poll(struct sched_ent *alarm)
{
if (alarm->poll.revents & POLLIN)
// process incoming data packet
msp_recv(alarm->poll.fd);
// do any timed actions that need to be done, either in response to receiving or due to a timed alarm.
msp_processing(&alarm->alarm);
if (alarm->alarm){
time_ms_t now = gettime_ms();
if (alarm->alarm < now)
alarm->alarm = now;
alarm->deadline = alarm->alarm +10;
unschedule(alarm);
schedule(alarm);
}
}
static void local_shutdown(struct connection *conn)
{
struct mdp_sockaddr remote;
msp_get_remote_adr(conn->sock, &remote);
msp_shutdown(conn->sock);
INFOF(" - Connection with %s:%d local shutdown", alloca_tohex_sid_t(remote.sid), remote.port);
}
static int try_send(struct connection *conn)
{
if (!conn->in->limit)
return 0;
if (msp_send(conn->sock, conn->in->bytes, conn->in->limit)==-1)
return 0;
// if this packet was acceptted, clear the read buffer
conn->in->limit = conn->in->position = 0;
// hit end of data?
if (conn->alarm_in.poll.events==0){
local_shutdown(conn);
}else{
if (!is_watching(&conn->alarm_in))
watch(&conn->alarm_in);
}
return 1;
}
static void io_poll(struct sched_ent *alarm)
{
struct connection *conn = alarm->context;
if (alarm->poll.revents & POLLIN) {
size_t remaining = conn->in->capacity - conn->in->limit;
if (remaining>0){
ssize_t r = read(alarm->poll.fd,
conn->in->bytes + conn->in->limit,
remaining);
if (r>0){
conn->in->limit+=r;
if (try_send(conn))
process_msp_asap();
// stop reading input when the buffer is full
if (conn->in->limit==conn->in->capacity){
unwatch(alarm);
}
}else{
// EOF? trigger a graceful shutdown
alarm->poll.revents = POLLHUP;
}
}
}
if (alarm->poll.revents & POLLOUT) {
// try to write some data
size_t data = conn->out->limit-conn->out->position;
if (data>0){
ssize_t r = write(alarm->poll.fd,
conn->out->bytes+conn->out->position,
data);
if (r > 0)
conn->out->position+=r;
}
// if the buffer is empty now, reset it and unwatch the handle
if (conn->out->position==conn->out->limit){
conn->out->limit = conn->out->position = 0;
if (is_watching(alarm))
unwatch(alarm);
}
if (conn->out->limit < conn->out->capacity){
if (conn->sock){
process_msp_asap();
}else{
free_connection(conn);
}
}
}
if (alarm->poll.revents & POLLHUP) {
// EOF? trigger a graceful shutdown
unwatch(alarm);
alarm->poll.events = 0;
if (!conn->in->limit){
local_shutdown(conn);
process_msp_asap();
}
}
if (alarm->poll.revents & POLLERR) {
free_connection(conn);
process_msp_asap();
}
}
static void listen_poll(struct sched_ent *alarm)
{
if (alarm->poll.revents & POLLIN) {
struct socket_address addr;
addr.addrlen = sizeof addr.store;
int fd = accept(alarm->poll.fd, &addr.addr, &addr.addrlen);
if (fd==-1){
WHYF_perror("accept(%d)", alarm->poll.fd);
return;
}
INFOF("- Incoming TCP connection from %s", alloca_socket_address(&addr));
struct msp_sock *sock = msp_socket(mdp_sock.poll.fd);
if (!sock)
return;
struct connection *connection = alloc_connection(sock, fd, io_poll, fd, io_poll);
if (!connection){
msp_close(sock);
return;
}
msp_set_handler(sock, msp_handler, connection);
msp_set_remote(sock, remote_addr);
if (once){
unwatch(alarm);
close(alarm->poll.fd);
alarm->poll.fd=-1;
}
}
}
int app_msp_connection(const struct cli_parsed *parsed, struct cli_context *UNUSED(context))
{
const char *sidhex, *port_string, *local_port_string;
once = cli_arg(parsed, "--once", NULL, NULL, NULL) == 0;
if ( cli_arg(parsed, "--forward", &local_port_string, cli_uint, NULL) == -1
|| cli_arg(parsed, "sid", &sidhex, str_is_subscriber_id, NULL) == -1
|| cli_arg(parsed, "port", &port_string, cli_uint, NULL) == -1)
return -1;
struct mdp_sockaddr addr;
bzero(&addr, sizeof addr);
addr.port = atoi(port_string);
saw_error=0;
if (sidhex && *sidhex){
if (str_to_sid_t(&addr.sid, sidhex) == -1)
return WHY("str_to_sid_t() failed");
}
int ret=-1;
struct msp_sock *sock = NULL;
mdp_sock.poll.fd = mdp_socket();
if (mdp_sock.poll.fd==-1)
goto end;
watch(&mdp_sock);
set_nonblock(STDIN_FILENO);
set_nonblock(STDOUT_FILENO);
bzero(&ip_addr, sizeof ip_addr);
if (local_port_string){
ip_addr.addrlen = sizeof(ip_addr.inet);
ip_addr.inet.sin_family = AF_INET;
ip_addr.inet.sin_port = htons(atoi(local_port_string));
ip_addr.inet.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
}
if (sidhex && *sidhex){
if (local_port_string){
remote_addr = addr;
listen_alarm.poll.fd = esocket(PF_INET, SOCK_STREAM, 0);
if (listen_alarm.poll.fd==-1)
goto end;
if (socket_bind(listen_alarm.poll.fd, &ip_addr.addr, ip_addr.addrlen)==-1)
goto end;
if (socket_listen(listen_alarm.poll.fd, 0)==-1)
goto end;
watch(&listen_alarm);
INFOF("- Forwarding from %s to %s:%d", alloca_socket_address(&ip_addr), alloca_tohex_sid_t(addr.sid), addr.port);
}else{
sock = msp_socket(mdp_sock.poll.fd);
once = 1;
struct connection *conn=alloc_connection(sock, STDIN_FILENO, io_poll, STDOUT_FILENO, io_poll);
if (!conn)
goto end;
msp_set_handler(sock, msp_handler, conn);
msp_set_remote(sock, addr);
INFOF("- Connecting to %s:%d", alloca_tohex_sid_t(addr.sid), addr.port);
}
}else{
sock = msp_socket(mdp_sock.poll.fd);
msp_set_handler(sock, msp_listener, NULL);
msp_set_local(sock, addr);
// sock will be closed if listen fails
if (msp_listen(sock)==-1)
goto end;
listener=sock;
if (local_port_string){
INFOF("- Forwarding from port %d to %s", addr.port, alloca_socket_address(&ip_addr));
}else{
once = 1;
INFOF(" - Listening on port %d", addr.port);
}
}
process_msp_asap();
sigIntFlag = 0;
signal(SIGINT, sigIntHandler);
while(sigIntFlag==0 && fd_poll()){
;
}
ret = saw_error;
signal(SIGINT, SIG_DFL);
sigIntFlag = 0;
end:
listener=NULL;
if (is_watching(&mdp_sock))
unwatch(&mdp_sock);
if (mdp_sock.poll.fd!=-1){
msp_close_all(mdp_sock.poll.fd);
mdp_close(mdp_sock.poll.fd);
}
if (listen_alarm.poll.fd !=-1 && is_watching(&listen_alarm))
unwatch(&listen_alarm);
if (listen_alarm.poll.fd!=-1)
close(listen_alarm.poll.fd);
unschedule(&mdp_sock);
return ret;
}

View File

@ -73,6 +73,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "rhizome.h"
#include "strbuf.h"
#include "keyring.h"
#include "overlay_interface.h"
int overlayMode=0;

View File

@ -27,13 +27,14 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <assert.h>
#include <arpa/inet.h>
#include "serval.h"
#include "conf.h"
#include "str.h"
#include "overlay_address.h"
#include "overlay_buffer.h"
#include "overlay_interface.h"
#include "overlay_packet.h"
#include <arpa/inet.h>
#define MAX_BPIS 1024
#define BPI_MASK 0x3ff
@ -476,7 +477,7 @@ int send_please_explain(struct decode_context *context, struct subscriber *sourc
frame->destination = destination;
frame->destinations[frame->destination_count++].destination=add_destination_ref(context->interface->destination);
struct network_destination *dest = create_unicast_destination(context->addr, context->interface);
struct network_destination *dest = create_unicast_destination(&context->addr, context->interface);
if (dest)
frame->destinations[frame->destination_count++].destination=dest;

View File

@ -21,6 +21,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#define __SERVAL_DNA__OVERLAY_ADDRESS_H
#include "constants.h"
#include "socket.h"
// not reachable
#define REACHABLE_NONE 0
@ -94,7 +95,7 @@ struct decode_context{
int sender_interface;
int packet_version;
int encapsulation;
struct sockaddr_in addr;
struct socket_address addr;
union{
// only valid while decoding
int invalid_addresses;

View File

@ -17,7 +17,9 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <assert.h>
@ -27,6 +29,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "conf.h"
#include "net.h"
#include "socket.h"
#include "overlay_interface.h"
#include "strbuf.h"
#include "strbuf_helpers.h"
#include "overlay_buffer.h"
@ -46,19 +49,21 @@ int overlay_last_interface_number=-1;
struct profile_total interface_poll_stats;
struct sched_ent sock_any;
struct sockaddr_in sock_any_addr;
struct socket_address sock_any_addr;
struct profile_total sock_any_stats;
static void overlay_interface_poll(struct sched_ent *alarm);
static int re_init_socket(int interface_index);
static void
overlay_interface_close(overlay_interface *interface){
link_interface_down(interface);
INFOF("Interface %s addr %s is down",
interface->name, inet_ntoa(interface->address.sin_addr));
interface->name, alloca_socket_address(&interface->address));
if (interface->address.addr.sa_family == AF_UNIX)
unlink(interface->address.local.sun_path);
link_interface_down(interface);
unschedule(&interface->alarm);
unwatch(&interface->alarm);
if (is_watching(&interface->alarm))
unwatch(&interface->alarm);
close(interface->alarm.poll.fd);
if (interface->radio_link_state)
radio_link_free(interface);
@ -66,6 +71,15 @@ overlay_interface_close(overlay_interface *interface){
interface->state=INTERFACE_STATE_DOWN;
}
void overlay_interface_close_all()
{
unsigned i;
for (i=0;i<OVERLAY_MAX_INTERFACES;i++){
if (overlay_interfaces[i].state == INTERFACE_STATE_UP)
overlay_interface_close(&overlay_interfaces[i]);
}
}
void interface_state_html(struct strbuf *b, struct overlay_interface *interface)
{
switch(interface->state){
@ -97,12 +111,9 @@ void interface_state_html(struct strbuf *b, struct overlay_interface *interface)
break;
case SOCK_DGRAM:
{
char addrtxt[INET_ADDRSTRLEN];
strbuf_puts(b, "Socket: DGram<br>");
if (inet_ntop(AF_INET, (const void *)&interface->address.sin_addr, addrtxt, INET_ADDRSTRLEN))
strbuf_sprintf(b, "Address: %s:%d<br>", addrtxt, ntohs(interface->address.sin_port));
if (inet_ntop(AF_INET, (const void *)&interface->destination->address.sin_addr, addrtxt, INET_ADDRSTRLEN))
strbuf_sprintf(b, "Broadcast Address: %s:%d<br>", addrtxt, ntohs(interface->destination->address.sin_port));
strbuf_sprintf(b, "Address: %s<br>", alloca_socket_address(&interface->address));
strbuf_sprintf(b, "Broadcast Address: %s<br>", alloca_socket_address(&interface->destination->address));
}
break;
case SOCK_FILE:
@ -115,16 +126,26 @@ void interface_state_html(struct strbuf *b, struct overlay_interface *interface)
// create a socket with options common to all our UDP sockets
static int
overlay_bind_socket(const struct sockaddr *addr, size_t addr_size, char *interface_name){
overlay_bind_socket(const struct socket_address *addr){
int fd;
int reuseP = 1;
int broadcastP = 1;
int protocol;
fd = socket(PF_INET,SOCK_DGRAM,0);
if (fd < 0) {
WHY_perror("Error creating socket");
return -1;
}
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));
}
fd = socket(protocol, SOCK_DGRAM, 0);
if (fd < 0)
return WHY_perror("Error creating socket");
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuseP, sizeof(reuseP)) < 0) {
WHY_perror("setsockopt(SO_REUSEADR)");
@ -154,18 +175,7 @@ overlay_bind_socket(const struct sockaddr *addr, size_t addr_size, char *interfa
#endif
);
#ifdef SO_BINDTODEVICE
/*
Limit incoming and outgoing packets to this interface, no matter what the routing table says.
This should allow for a device with multiple interfaces on the same subnet.
Don't abort if this fails, I believe it requires root, just log it.
*/
if (interface_name && setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, interface_name, strlen(interface_name)+1) < 0) {
WHY_perror("setsockopt(SO_BINDTODEVICE)");
}
#endif
if (bind(fd, addr, addr_size)) {
if (bind(fd, &addr->addr, addr->addrlen)) {
WHY_perror("Bind failed");
goto error;
}
@ -187,7 +197,7 @@ overlay_interface * overlay_interface_get_default(){
return NULL;
}
// find an interface that can send a packet to this address
// find an interface that can send a packet to this IPv4 address
overlay_interface * overlay_interface_find(struct in_addr addr, int return_default){
int i;
overlay_interface *ret = NULL;
@ -195,7 +205,8 @@ overlay_interface * overlay_interface_find(struct in_addr addr, int return_defau
if (overlay_interfaces[i].state!=INTERFACE_STATE_UP)
continue;
if ((overlay_interfaces[i].netmask.s_addr & addr.s_addr) == (overlay_interfaces[i].netmask.s_addr & overlay_interfaces[i].address.sin_addr.s_addr)){
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)){
return &overlay_interfaces[i];
}
@ -296,25 +307,23 @@ overlay_interface_read_any(struct sched_ent *alarm)
// for now, we don't have a graceful close for this interface but it should go away when the process dies
static int overlay_interface_init_any(int port)
{
struct sockaddr_in addr;
if (sock_any.poll.fd>0){
// Check the port number matches
if (sock_any_addr.sin_port != htons(port))
return WHYF("Unable to listen to broadcast packets for ports %d & %d", port, ntohs(sock_any_addr.sin_port));
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));
return 0;
}
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = INADDR_ANY;
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;
sock_any.poll.fd = overlay_bind_socket((const struct sockaddr *)&addr, sizeof(addr), NULL);
sock_any.poll.fd = overlay_bind_socket(&sock_any_addr);
if (sock_any.poll.fd<0)
return -1;
sock_any_addr = addr;
sock_any.poll.events=POLLIN;
sock_any.function = overlay_interface_read_any;
@ -325,10 +334,8 @@ static int overlay_interface_init_any(int port)
}
static int
overlay_interface_init_socket(int interface_index)
overlay_interface_init_socket(overlay_interface *interface)
{
overlay_interface *const interface = &overlay_interfaces[interface_index];
/*
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.
@ -344,20 +351,15 @@ overlay_interface_init_socket(int interface_index)
overlay_interface_init_any(interface->port);
interface->alarm.poll.fd = overlay_bind_socket(
(const struct sockaddr *)&interface->address,
sizeof(interface->address), interface->name);
interface->alarm.poll.fd = overlay_bind_socket(&interface->address);
if (interface->alarm.poll.fd<0){
interface->state=INTERFACE_STATE_DOWN;
return WHYF("Failed to bind interface %s", interface->name);
}
if (config.debug.packetrx || config.debug.io) {
char srctxt[INET_ADDRSTRLEN];
if (inet_ntop(AF_INET, (const void *)&interface->address.sin_addr, srctxt, INET_ADDRSTRLEN))
DEBUGF("Bound to %s:%d", srctxt, ntohs(interface->address.sin_port));
}
if (config.debug.packetrx || config.debug.io)
DEBUGF("Bound to %s", alloca_socket_address(&interface->address));
interface->alarm.poll.events=POLLIN;
watch(&interface->alarm);
@ -365,29 +367,13 @@ overlay_interface_init_socket(int interface_index)
return 0;
}
static int re_init_socket(int interface_index){
if (overlay_interface_init_socket(interface_index))
return -1;
overlay_interface *interface = &overlay_interfaces[interface_index];
// schedule the first tick asap
interface->alarm.alarm=gettime_ms();
interface->alarm.deadline=interface->alarm.alarm;
schedule(&interface->alarm);
interface->state=INTERFACE_STATE_UP;
INFOF("Interface %s addr %s:%d, is up",interface->name,
inet_ntoa(interface->address.sin_addr), ntohs(interface->address.sin_port));
directory_registration();
return 0;
}
/* 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).
*/
static int
overlay_interface_init(const char *name, struct in_addr src_addr, struct in_addr netmask, struct in_addr broadcast,
overlay_interface_init(const char *name, struct socket_address *addr,
struct socket_address *broadcast,
const struct config_network_interface *ifconfig)
{
int cleanup_ret = -1;
@ -397,7 +383,9 @@ overlay_interface_init(const char *name, struct in_addr src_addr, struct in_addr
return WHY("Too many interfaces -- Increase OVERLAY_MAX_INTERFACES");
overlay_interface *const interface = &overlay_interfaces[overlay_interface_count];
bzero(interface, sizeof(overlay_interface));
interface->state=INTERFACE_STATE_DOWN;
strncpy(interface->name, name, sizeof interface->name);
// copy ifconfig values
@ -420,7 +408,6 @@ overlay_interface_init(const char *name, struct in_addr src_addr, struct in_addr
interface->mtu = 1200;
interface->point_to_point = ifconfig->point_to_point;
interface->state=INTERFACE_STATE_DOWN;
interface->alarm.poll.fd=0;
interface->debug = ifconfig->debug;
interface->tx_count=0;
@ -488,30 +475,23 @@ overlay_interface_init(const char *name, struct in_addr src_addr, struct in_addr
limit_init(&interface->destination->transfer_limit, packet_interval);
interface->address.sin_family=AF_INET;
interface->address.sin_port = htons(ifconfig->port);
interface->destination->address.sin_family=AF_INET;
interface->destination->address.sin_port = htons(ifconfig->port);
if (addr)
interface->address = *addr;
if (broadcast)
interface->destination->address = *broadcast;
interface->alarm.function = overlay_interface_poll;
interface_poll_stats.name="overlay_interface_poll";
interface->alarm.stats=&interface_poll_stats;
if (ifconfig->socket_type==SOCK_DGRAM){
interface->address.sin_addr = src_addr;
interface->destination->address.sin_addr = broadcast;
interface->netmask = netmask;
if (ifconfig->socket_type == SOCK_DGRAM){
interface->local_echo = 1;
if (overlay_interface_init_socket(overlay_interface_count))
if (overlay_interface_init_socket(interface))
return WHY("overlay_interface_init_socket() failed");
}else{
char read_file[1024];
interface->address.sin_addr = ifconfig->dummy_address;
interface->netmask = ifconfig->dummy_netmask;
interface->destination->address.sin_addr.s_addr = interface->address.sin_addr.s_addr | ~interface->netmask.s_addr;
interface->local_echo = interface->point_to_point?0:1;
strbuf d = strbuf_local(read_file, sizeof read_file);
@ -551,8 +531,7 @@ overlay_interface_init(const char *name, struct in_addr src_addr, struct in_addr
interface->alarm.deadline=interface->alarm.alarm;
schedule(&interface->alarm);
interface->state=INTERFACE_STATE_UP;
INFOF("Interface %s addr %s:%d, is up",interface->name,
inet_ntoa(interface->address.sin_addr), ntohs(interface->address.sin_port));
INFOF("Interface %s addr %s, is up",interface->name, alloca_socket_address(addr));
directory_registration();
@ -597,8 +576,8 @@ static void interface_read_dgram(struct overlay_interface *interface)
}
struct file_packet{
struct sockaddr_in src_addr;
struct sockaddr_in dst_addr;
struct socket_address src_addr;
struct socket_address dst_addr;
int pid;
int payload_length;
@ -619,14 +598,14 @@ struct file_packet{
unsigned char payload[1400];
};
static int should_drop(struct overlay_interface *interface, struct sockaddr_in addr){
static int should_drop(struct overlay_interface *interface, struct socket_address *addr){
if (interface->drop_packets>=100)
return 1;
if (memcmp(&addr, &interface->address, sizeof(addr))==0){
if (cmp_sockaddr(addr, &interface->address)==0){
if (interface->drop_unicasts)
return 1;
}else if (memcmp(&addr, &interface->destination->address, sizeof(addr))==0){
}else if (cmp_sockaddr(addr, &interface->destination->address)==0){
if (interface->drop_broadcasts)
return 1;
}else
@ -647,10 +626,12 @@ static void interface_read_file(struct overlay_interface *interface)
/* Read from interface file */
off_t length = lseek(interface->alarm.poll.fd, (off_t)0, SEEK_END);
if (interface->recv_offset > length)
FATALF("File shrunk? It shouldn't shrink! Ever");
int new_packets = (length - interface->recv_offset) / sizeof packet;
if (new_packets > 20)
WARNF("Getting behind, there are %d unread packets", new_packets);
WARNF("Getting behind, there are %d unread packets (%"PRId64" vs %"PRId64")",
new_packets, (int64_t)interface->recv_offset, (int64_t)length);
if (interface->recv_offset<length){
if (lseek(interface->alarm.poll.fd,interface->recv_offset,SEEK_SET) == -1){
@ -668,26 +649,23 @@ static void interface_read_file(struct overlay_interface *interface)
if (nread == sizeof packet) {
if (config.debug.overlayinterfaces)
DEBUGF("Read from interface %s (filesize=%"PRId64") at offset=%d: src_addr=%s dst_addr=%s pid=%d length=%d",
interface->name, (int64_t)length, interface->recv_offset,
alloca_sockaddr(&packet.src_addr, sizeof packet.src_addr),
alloca_sockaddr(&packet.dst_addr, sizeof packet.dst_addr),
DEBUGF("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
);
interface->recv_offset += nread;
if (should_drop(interface, packet.dst_addr) || (packet.pid == getpid() && !interface->local_echo)){
if (should_drop(interface, &packet.dst_addr) || (packet.pid == getpid() && !interface->local_echo)){
if (config.debug.packetrx)
DEBUGF("Ignoring packet from pid=%d src_addr=%s dst_addr=%s",
packet.pid,
alloca_sockaddr_in(&packet.src_addr),
alloca_sockaddr_in(&packet.dst_addr)
alloca_socket_address(&packet.src_addr),
alloca_socket_address(&packet.dst_addr)
);
}else{
struct socket_address srcaddr;
srcaddr.addrlen = sizeof packet.src_addr;
srcaddr.inet = packet.src_addr;
packetOkOverlay(interface, packet.payload, packet.payload_length, &srcaddr);
packetOkOverlay(interface, packet.payload, packet.payload_length, &packet.src_addr);
}
}
}
@ -806,6 +784,44 @@ static void overlay_interface_poll(struct sched_ent *alarm)
}
}
static int send_local_broadcast(int fd, const uint8_t *bytes, size_t len, struct socket_address *address)
{
DIR *dir;
struct dirent *dp;
if ((dir = opendir(address->local.sun_path)) == NULL) {
WARNF_perror("opendir(%s)", alloca_str_toprint(address->local.sun_path));
return -1;
}
while ((dp = readdir(dir)) != NULL) {
struct socket_address addr;
strbuf d = strbuf_local(addr.local.sun_path, sizeof addr.local.sun_path);
strbuf_path_join(d, address->local.sun_path, dp->d_name, NULL);
if (strbuf_overrun(d)){
WHYF("interface file name overrun: %s", alloca_str_toprint(strbuf_str(d)));
continue;
}
struct stat st;
if (lstat(addr.local.sun_path, &st)) {
WARNF_perror("stat(%s)", alloca_str_toprint(addr.local.sun_path));
continue;
}
if (S_ISSOCK(st.st_mode)){
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);
if (sent == -1)
WHYF_perror("sendto(%d, %zu, %s)", fd, len, alloca_socket_address(&addr));
}
}
closedir(dir);
return 0;
}
int overlay_broadcast_ensemble(struct network_destination *destination, struct overlay_buffer *buffer)
{
assert(destination && destination->interface);
@ -886,29 +902,35 @@ int overlay_broadcast_ensemble(struct network_destination *destination, struct o
case SOCK_DGRAM:
{
if (config.debug.overlayinterfaces)
DEBUGF("Sending %zu byte overlay frame on %s to %s", len, interface->name, inet_ntoa(destination->address.sin_addr));
ssize_t sent = sendto(interface->alarm.poll.fd,
bytes, (size_t)len, 0,
(struct sockaddr *)&destination->address, sizeof(destination->address));
ob_free(buffer);
if (sent == -1 || (size_t)sent != len) {
if (sent == -1)
DEBUGF("Sending %zu byte overlay frame on %s to %s",
(size_t)len, interface->name, alloca_socket_address(&destination->address));
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,
bytes, (size_t)len, &destination->address);
}else{
ssize_t sent = sendto(interface->alarm.poll.fd,
bytes, (size_t)len, 0,
&destination->address.addr, destination->address.addrlen);
if (sent == -1){
WHYF_perror("sendto(fd=%d,len=%zu,addr=%s) on interface %s",
interface->alarm.poll.fd,
len,
alloca_sockaddr((struct sockaddr *)&destination->address, sizeof destination->address),
(size_t)len,
alloca_socket_address(&destination->address),
interface->name
);
else
WHYF("sendto() sent %zu bytes of overlay frame (%zu) to interface %s (socket=%d)",
(size_t)sent, len, interface->name, interface->alarm.poll.fd);
// close the interface if we had any error while sending broadcast packets,
// unicast packets should not bring the interface down
if (destination == interface->destination)
overlay_interface_close(interface);
// TODO mark unicast destination as failed
return -1;
// 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;
}
}
ob_free(buffer);
return 0;
}
@ -921,15 +943,13 @@ int overlay_broadcast_ensemble(struct network_destination *destination, struct o
/* Register the real interface, or update the existing interface registration. */
int
overlay_interface_register(char *name,
struct in_addr addr,
struct in_addr mask)
struct socket_address *addr,
struct socket_address *broadcast)
{
struct in_addr broadcast = {.s_addr = addr.s_addr | ~mask.s_addr};
if (config.debug.overlayinterfaces) {
// note, inet_ntop doesn't seem to behave on android
DEBUGF("%s address: %s", name, inet_ntoa(addr));
DEBUGF("%s broadcast address: %s", name, inet_ntoa(broadcast));
DEBUGF("%s address: %s", name, alloca_socket_address(addr));
DEBUGF("%s broadcast address: %s", name, alloca_socket_address(broadcast));
}
// Find the matching non-dummy interface rule.
@ -958,49 +978,32 @@ overlay_interface_register(char *name,
DEBUGF("Interface %s is explicitly excluded", name);
return 0;
}
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);
/* Search in the exist list of interfaces */
int found_interface= -1;
for(i = 0; i < overlay_interface_count; i++){
int broadcast_match = 0;
int name_match =0;
if (overlay_interfaces[i].state==INTERFACE_STATE_DOWN){
continue;
}
if (overlay_interfaces[i].destination->address.sin_addr.s_addr == broadcast.s_addr)
broadcast_match = 1;
name_match = !strcasecmp(overlay_interfaces[i].name, name);
// if we find an exact match we can stop searching
if (name_match && broadcast_match){
if (strcasecmp(overlay_interfaces[i].name, name)
&& cmp_sockaddr(addr, &overlay_interfaces[i].address)==0
&& overlay_interfaces[i].state!=INTERFACE_STATE_DOWN){
// mark this interface as still alive
if (overlay_interfaces[i].state==INTERFACE_STATE_DETECTING)
overlay_interfaces[i].state=INTERFACE_STATE_UP;
// try to bring the interface back up again even if the address has changed
if (overlay_interfaces[i].state==INTERFACE_STATE_DOWN){
overlay_interfaces[i].address.sin_addr = addr;
re_init_socket(i);
}
// we already know about this interface, and it's up so stop looking immediately
return 0;
}
// remember this slot to bring the interface back up again, even if the address has changed
if (name_match && overlay_interfaces[i].state==INTERFACE_STATE_DOWN)
found_interface=i;
}
if (found_interface>=0){
// try to reactivate the existing interface
overlay_interfaces[found_interface].address.sin_addr = addr;
overlay_interfaces[found_interface].destination->address.sin_addr = broadcast;
overlay_interfaces[found_interface].netmask = mask;
return re_init_socket(found_interface);
}
/* New interface, so register it */
if (overlay_interface_init(name, addr, mask, broadcast, ifconfig))
if (overlay_interface_init(name, addr, broadcast, ifconfig))
return WHYF("Could not initialise newly seen interface %s", name);
else
if (config.debug.overlayinterfaces) DEBUGF("Registered interface %s", name);
@ -1023,7 +1026,7 @@ void overlay_interface_discover(struct sched_ent *alarm)
ifconfig = &config.interfaces.av[i].value;
if (ifconfig->exclude)
continue;
if (ifconfig->socket_type==SOCK_DGRAM) {
if (!*ifconfig->file) {
detect_real_interfaces = 1;
continue;
}
@ -1038,9 +1041,55 @@ void overlay_interface_discover(struct sched_ent *alarm)
}
if (j >= overlay_interface_count) {
// New dummy interface, so register it.
struct in_addr dummyaddr = hton_in_addr(INADDR_NONE);
overlay_interface_init(ifconfig->file, dummyaddr, dummyaddr, dummyaddr, ifconfig);
// New file interface, so register it.
struct socket_address addr, broadcast;
bzero(&addr, sizeof addr);
bzero(&broadcast, sizeof broadcast);
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;
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:
overlay_interface_init(ifconfig->file, &addr, &broadcast, ifconfig);
break;
case SOCK_DGRAM:
{
// use a local dgram socket
// no abstract sockets for now
strbuf d = strbuf_local(addr.local.sun_path, sizeof addr.local.sun_path);
strbuf_path_join(d, serval_instancepath(), config.server.interface_path, ifconfig->file, NULL);
if (strbuf_overrun(d)){
WHYF("interface file name overrun: %s", alloca_str_toprint(strbuf_str(d)));
// 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;
DEBUGF("Attempting to bind local socket w. addr %s, broadcast %s",
alloca_socket_address(&addr), alloca_socket_address(&broadcast));
overlay_interface_init(ifconfig->file, &addr, &broadcast, ifconfig);
break;
}
}
}
}
@ -1067,7 +1116,6 @@ void overlay_interface_discover(struct sched_ent *alarm)
// Close any interfaces that have gone away.
for(i = 0; i < overlay_interface_count; i++)
if (overlay_interfaces[i].state==INTERFACE_STATE_DETECTING) {
DEBUGF("Closing interface stuck in DETECTING state.");
overlay_interface_close(&overlay_interfaces[i]);
}

146
overlay_interface.h Normal file
View File

@ -0,0 +1,146 @@
#ifndef __SERVAL_DNA__OVERLAY_INTERFACE_H
#define __SERVAL_DNA__OVERLAY_INTERFACE_H
#include "socket.h"
#define INTERFACE_STATE_FREE 0
#define INTERFACE_STATE_UP 1
#define INTERFACE_STATE_DOWN 2
#define INTERFACE_STATE_DETECTING 3
struct overlay_interface;
// where should packets be sent to?
struct network_destination {
int _ref_count;
// which interface are we actually sending packets out of
struct overlay_interface *interface;
// The network destination address
// this may be the interface broadcast IP address
// but could be a unicast address
struct socket_address address;
// should outgoing packets be marked as unicast?
char unicast;
char packet_version;
// should we aggregate packets, or send one at a time
char encapsulation;
// time last packet was sent
time_ms_t last_tx;
int min_rtt;
int max_rtt;
int resend_delay;
// sequence number of last packet sent to this destination.
// Used to allow NACKs that can request retransmission of recent packets.
int sequence_number;
// rate limit for outgoing packets
struct limit_state transfer_limit;
/* Number of milli-seconds per tick for this interface, which is basically
* related to the the typical TX range divided by the maximum expected
* speed of nodes in the network. This means that short-range communications
* has a higher bandwidth requirement than long-range communications because
* the tick interval has to be shorter to still allow fast-convergence time
* to allow for mobility.
*
* For wifi (nominal range 100m) it is usually 500ms.
* For ~100K ISM915MHz (nominal range 1000m) it will probably be about 5000ms.
* For ~10K ISM915MHz (nominal range ~3000m) it will probably be about 15000ms.
*
* These figures will be refined over time, and we will allow people to set
* them per-interface.
*/
unsigned tick_ms;
// Number of milliseconds of no packets until we assume the link is dead.
unsigned reachable_timeout_ms;
};
typedef struct overlay_interface {
struct sched_ent alarm;
char name[256];
off_t recv_offset; /* file offset */
int recv_count;
int tx_count;
struct radio_link_state *radio_link_state;
// copy of ifconfig flags
uint16_t drop_packets;
char drop_broadcasts;
char drop_unicasts;
int port;
int type;
int socket_type;
char send_broadcasts;
char prefer_unicast;
/* Not necessarily the real MTU, but the largest frame size we are willing to TX.
For radio links the actual maximum and the maximum that is likely to be delivered reliably are
potentially two quite different values. */
int mtu;
// can we use this interface for routes to addresses in other subnets?
int default_route;
// should we log more debug info on this interace? eg hex dumps of packets
char debug;
char local_echo;
unsigned int uartbps; // set serial port speed (which might be different from link speed)
int ctsrts; // enabled hardware flow control if non-zero
struct network_destination *destination;
// can we assume that we will only receive packets from one device?
char point_to_point;
struct subscriber *other_device;
// the actual address of the interface.
struct socket_address address;
struct in_addr netmask;
/* Use one of the INTERFACE_STATE_* constants to indicate the state of this interface.
If the interface stops working or disappears, it will be marked as DOWN and the socket closed.
But if it comes back up again, we should try to reuse this structure, even if the broadcast address has changed.
*/
int state;
} overlay_interface;
/* Maximum interface count is rather arbitrary.
Memory consumption is O(n) with respect to this parameter, so let's not make it too big for now.
*/
extern overlay_interface overlay_interfaces[OVERLAY_MAX_INTERFACES];
extern unsigned overlay_interface_count;
struct network_destination * new_destination(struct overlay_interface *interface, char encapsulation);
struct network_destination * create_unicast_destination(struct socket_address *addr, struct overlay_interface *interface);
struct network_destination * add_destination_ref(struct network_destination *ref);
void release_destination_ref(struct network_destination *ref);
int set_destination_ref(struct network_destination **ptr, struct network_destination *ref);
void overlay_interface_discover(struct sched_ent *alarm);
int overlay_interface_register(char *name,
struct socket_address *addr,
struct socket_address *broadcast);
void overlay_interface_close_all();
overlay_interface * overlay_interface_get_default();
overlay_interface * overlay_interface_find(struct in_addr addr, int return_default);
overlay_interface * overlay_interface_find_name(const char *name);
int overlay_interface_compare(overlay_interface *one, overlay_interface *two);
int overlay_broadcast_ensemble(struct network_destination *destination, struct overlay_buffer *buffer);
void interface_state_html(struct strbuf *b, struct overlay_interface *interface);
#endif // __SERVAL_DNA__OVERLAY_INTERFACE_H

View File

@ -23,16 +23,13 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "str.h"
#include "overlay_address.h"
#include "overlay_buffer.h"
#include "overlay_interface.h"
#include "overlay_packet.h"
#include "keyring.h"
#include "strbuf_helpers.h"
#define MIN_BURST_LENGTH 5000
struct probe_contents{
struct sockaddr_in addr;
unsigned char interface;
};
static void update_limit_state(struct limit_state *state, time_ms_t now){
if (state->next_interval > now || state->burst_size==0){
return;
@ -177,14 +174,15 @@ int load_subscriber_address(struct subscriber *subscriber)
if (!interface)
return WHY("Can't fund configured interface");
}
struct sockaddr_in addr;
struct socket_address addr;
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr = hostc->address;
addr.sin_port = htons(hostc->port);
if (addr.sin_addr.s_addr==INADDR_NONE){
addr.addrlen = sizeof(addr.inet);
addr.inet.sin_family = AF_INET;
addr.inet.sin_addr = hostc->address;
addr.inet.sin_port = htons(hostc->port);
if (addr.inet.sin_addr.s_addr==INADDR_NONE){
if (interface || overlay_interface_get_default()){
if (resolve_name(hostc->host, &addr.sin_addr))
if (resolve_name(hostc->host, &addr.inet.sin_addr))
return -1;
}else{
// interface isnt up yet
@ -192,8 +190,8 @@ int load_subscriber_address(struct subscriber *subscriber)
}
}
if (config.debug.overlayrouting)
DEBUGF("Loaded address %s:%d for %s", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port), alloca_tohex_sid_t(subscriber->sid));
struct network_destination *destination = create_unicast_destination(addr, interface);
DEBUGF("Loaded address %s for %s", alloca_socket_address(&addr), alloca_tohex_sid_t(subscriber->sid));
struct network_destination *destination = create_unicast_destination(&addr, interface);
if (!destination)
return -1;
int ret=overlay_send_probe(subscriber, destination, OQ_MESH_MANAGEMENT);
@ -206,7 +204,7 @@ int
overlay_mdp_service_probe(struct overlay_frame *frame, overlay_mdp_frame *mdp)
{
IN();
if (mdp->out.src.port!=MDP_PORT_ECHO || mdp->out.payload_length != sizeof(struct probe_contents)){
if (mdp->out.src.port!=MDP_PORT_ECHO){
WARN("Probe packets should be returned from remote echo port");
RETURN(-1);
}
@ -214,12 +212,16 @@ overlay_mdp_service_probe(struct overlay_frame *frame, overlay_mdp_frame *mdp)
if (frame->source->reachable == REACHABLE_SELF)
RETURN(0);
struct probe_contents probe;
bcopy(&mdp->out.payload, &probe, sizeof(struct probe_contents));
if (probe.addr.sin_family!=AF_INET)
RETURN(WHY("Unsupported address family"));
uint8_t interface = mdp->out.payload[0];
struct socket_address addr;
addr.addrlen = mdp->out.payload_length - 1;
RETURN(link_unicast_ack(frame->source, &overlay_interfaces[probe.interface], probe.addr));
if (addr.addrlen > sizeof(addr.store))
RETURN(-1);
bcopy(&mdp->out.payload[1], &addr.addr, addr.addrlen);
RETURN(link_unicast_ack(frame->source, &overlay_interfaces[interface], &addr));
OUT();
}
@ -250,25 +252,18 @@ int overlay_send_probe(struct subscriber *peer, struct network_destination *dest
// TODO call mdp payload encryption / signing without calling overlay_mdp_dispatch...
overlay_mdp_encode_ports(frame->payload, MDP_PORT_ECHO, MDP_PORT_PROBE);
// not worried about byte order here as we are the only node that should be parsing the contents.
unsigned char *dst=ob_append_space(frame->payload, sizeof(struct probe_contents));
if (!dst){
op_free(frame);
return -1;
}
struct probe_contents probe;
probe.addr=destination->address;
// get interface number
probe.interface = destination->interface - overlay_interfaces;
bcopy(&probe, dst, sizeof(struct probe_contents));
ob_append_byte(frame->payload, destination->interface - overlay_interfaces);
ob_append_bytes(frame->payload, (uint8_t*)&destination->address.addr, destination->address.addrlen);
if (overlay_payload_enqueue(frame)){
op_free(frame);
return -1;
}
if (config.debug.overlayrouting)
DEBUGF("Queued probe packet on interface %s to %s:%d for %s",
DEBUGF("Queued probe packet on interface %s to %s for %s",
destination->interface->name,
inet_ntoa(destination->address.sin_addr), ntohs(destination->address.sin_port),
alloca_socket_address(&destination->address),
peer?alloca_tohex_sid_t(peer->sid):"ANY");
return 0;
}
@ -278,11 +273,11 @@ static void overlay_append_unicast_address(struct subscriber *subscriber, struct
{
if ( subscriber->destination
&& subscriber->destination->unicast
&& subscriber->destination->address.sin_family==AF_INET
&& subscriber->destination->address.addr.sa_family==AF_INET
) {
overlay_address_append(NULL, buff, subscriber);
ob_append_ui32(buff, subscriber->destination->address.sin_addr.s_addr);
ob_append_ui16(buff, subscriber->destination->address.sin_port);
ob_append_ui32(buff, subscriber->destination->address.inet.sin_addr.s_addr);
ob_append_ui16(buff, subscriber->destination->address.inet.sin_port);
if (config.debug.overlayrouting)
DEBUGF("Added STUN info for %s", alloca_tohex_sid_t(subscriber->sid));
}else{
@ -349,22 +344,22 @@ int overlay_mdp_service_stun(overlay_mdp_frame *mdp)
while(ob_remaining(buff)>0){
struct subscriber *subscriber=NULL;
struct sockaddr_in addr;
// TODO explain addresses, link expiry time, resolve differences between addresses...
if (overlay_address_parse(NULL, buff, &subscriber)){
break;
}
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = ob_get_ui32(buff);
addr.sin_port = ob_get_ui16(buff);
struct socket_address addr;
addr.addrlen = sizeof(addr.inet);
addr.inet.sin_family = AF_INET;
addr.inet.sin_addr.s_addr = ob_get_ui32(buff);
addr.inet.sin_port = ob_get_ui16(buff);
if (!subscriber || (subscriber->reachable!=REACHABLE_NONE))
continue;
struct network_destination *destination = create_unicast_destination(addr, NULL);
struct network_destination *destination = create_unicast_destination(&addr, NULL);
if (destination){
overlay_send_probe(subscriber, destination, OQ_MESH_MANAGEMENT);
release_destination_ref(destination);

View File

@ -57,6 +57,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "strbuf_helpers.h"
#include "overlay_buffer.h"
#include "overlay_address.h"
#include "overlay_interface.h"
#include "overlay_packet.h"
#include "mdp_client.h"
#include "crypto.h"
@ -86,7 +87,7 @@ static int mdp_send2(struct socket_address *client, struct mdp_header *header,
const uint8_t *payload, size_t payload_len);
/* Delete all UNIX socket files in instance directory. */
static void overlay_mdp_clean_socket_files()
void overlay_mdp_clean_socket_files()
{
const char *instance_path = serval_instancepath();
DIR *dir;
@ -166,14 +167,6 @@ struct mdp_binding mdp_bindings[MDP_MAX_BINDINGS];
int mdp_bindings_initialised=0;
mdp_port_t next_port_binding=256;
static int compare_client(struct socket_address *one, struct socket_address *two)
{
if (one->addrlen==two->addrlen
&& memcmp(&one->addr, &two->addr, two->addrlen)==0)
return 1;
return 0;
}
static int overlay_mdp_reply(int sock, struct socket_address *client,
overlay_mdp_frame *mdpreply)
{
@ -228,7 +221,7 @@ static int overlay_mdp_releasebindings(struct socket_address *client)
/* Free up any MDP bindings held by this client. */
int i;
for(i=0;i<MDP_MAX_BINDINGS;i++)
if (compare_client(&mdp_bindings[i].client, client))
if (cmp_sockaddr(&mdp_bindings[i].client, client)==0)
mdp_bindings[i].port=0;
return 0;
@ -259,7 +252,7 @@ static int overlay_mdp_process_bind_request(struct subscriber *subscriber, mdp_p
for(i=0;i<MDP_MAX_BINDINGS;i++) {
/* Look for duplicate bindings */
if (mdp_bindings[i].port == port && mdp_bindings[i].subscriber == subscriber) {
if (compare_client(&mdp_bindings[i].client, client)) {
if (cmp_sockaddr(&mdp_bindings[i].client, client)==0) {
// this client already owns this port binding?
INFO("Identical binding exists");
return 0;
@ -495,7 +488,7 @@ static int overlay_saw_mdp_frame(struct overlay_frame *frame, overlay_mdp_frame
*/
if (config.debug.mdprequests)
DEBUGF("Received packet with listener (MDP ports: src=%s*:%"PRImdp_port_t", dst=%"PRImdp_port_t")",
DEBUGF("Received packet (MDP ports: src=%s*:%"PRImdp_port_t", dst=%"PRImdp_port_t")",
alloca_tohex_sid_t_trunc(mdp->out.src.sid, 14),
mdp->out.src.port, mdp->out.dst.port);
@ -530,6 +523,8 @@ static int overlay_saw_mdp_frame(struct overlay_frame *frame, overlay_mdp_frame
if (len < 0)
RETURN(WHY("unsupported MDP packet type"));
struct socket_address *client = &mdp_bindings[match].client;
if (config.debug.mdprequests)
DEBUGF("Forwarding packet to client %s", alloca_socket_address(client));
ssize_t r = sendto(mdp_sock.poll.fd,mdp,len,0, &client->addr, client->addrlen);
if (r == -1){
WHYF_perror("sendto(fd=%d,len=%zu,addr=%s)", mdp_sock.poll.fd, (size_t)len, alloca_socket_address(client));
@ -546,6 +541,7 @@ static int overlay_saw_mdp_frame(struct overlay_frame *frame, overlay_mdp_frame
}
case 1:
{
struct socket_address *client = &mdp_bindings[match].client;
struct mdp_header header;
header.local.sid=mdp->out.dst.sid;
header.local.port=mdp->out.dst.port;
@ -562,7 +558,9 @@ static int overlay_saw_mdp_frame(struct overlay_frame *frame, overlay_mdp_frame
if (mdp_bindings[match].internal)
RETURN(mdp_bindings[match].internal(&header, mdp->out.payload, mdp->out.payload_length));
RETURN(mdp_send2(&mdp_bindings[match].client, &header, mdp->out.payload, mdp->out.payload_length));
if (config.debug.mdprequests)
DEBUGF("Forwarding packet to client v2 %s", alloca_socket_address(client));
RETURN(mdp_send2(client, &header, mdp->out.payload, mdp->out.payload_length));
}
}
} else {
@ -617,7 +615,7 @@ static int overlay_mdp_check_binding(struct subscriber *subscriber, mdp_port_t p
continue;
if ((!mdp_bindings[i].subscriber) || mdp_bindings[i].subscriber == subscriber) {
/* Binding matches, now make sure the sockets match */
if (compare_client(&mdp_bindings[i].client, client)) {
if (cmp_sockaddr(&mdp_bindings[i].client, client)==0) {
/* Everything matches, so this unix socket and MDP address combination is valid */
return 0;
}
@ -740,6 +738,11 @@ static int overlay_send_frame(
if (!source)
return WHYF("No source specified");
if (config.debug.mdprequests)
DEBUGF("Attempting to queue mdp packet from %s:%d to %s:%d",
alloca_tohex_sid_t(source->sid), src_port,
destination?alloca_tohex_sid_t(destination->sid):"broadcast", dst_port);
/* Prepare the overlay frame for dispatch */
struct overlay_frame *frame = emalloc_zero(sizeof(struct overlay_frame));
if (!frame)
@ -774,7 +777,8 @@ static int overlay_send_frame(
}
if (config.debug.mdprequests) {
DEBUGF("Send frame %zu bytes", ob_position(plaintext));
dump("Frame plaintext", ob_ptr(plaintext), ob_position(plaintext));
if (config.debug.verbose)
dump("Frame plaintext", ob_ptr(plaintext), ob_position(plaintext));
}
/* Work out the disposition of the frame-> For now we are only worried
@ -1047,20 +1051,21 @@ struct scan_state scans[OVERLAY_MAX_INTERFACES];
static void overlay_mdp_scan(struct sched_ent *alarm)
{
struct sockaddr_in addr={
.sin_family=AF_INET,
.sin_port=htons(PORT_DNA),
.sin_addr={0},
};
struct socket_address addr;
bzero(&addr, sizeof(addr));
addr.addrlen = sizeof(addr.inet);
addr.inet.sin_family=AF_INET;
addr.inet.sin_port=htons(PORT_DNA);
struct scan_state *state = (struct scan_state *)alarm;
uint32_t stop = state->last;
if (stop - state->current > 25)
stop = state->current+25;
while(state->current <= stop){
addr.sin_addr.s_addr=htonl(state->current);
if (addr.sin_addr.s_addr != state->interface->address.sin_addr.s_addr){
struct network_destination *destination = create_unicast_destination(addr, state->interface);
addr.inet.sin_addr.s_addr=htonl(state->current);
if (addr.inet.sin_addr.s_addr != state->interface->address.inet.sin_addr.s_addr){
struct network_destination *destination = create_unicast_destination(&addr, state->interface);
if (!destination)
break;
int ret = overlay_send_probe(NULL, destination, OQ_ORDINARY);
@ -1243,7 +1248,7 @@ static void mdp_process_packet(struct socket_address *client, struct mdp_header
int i;
for(i=0;i<MDP_MAX_BINDINGS;i++) {
if (mdp_bindings[i].port!=0
&& compare_client(&mdp_bindings[i].client, client)){
&& cmp_sockaddr(&mdp_bindings[i].client, client)==0){
if (config.debug.mdprequests)
DEBUGF("Unbind MDP %s:%d from %s",
mdp_bindings[i].subscriber?alloca_tohex_sid_t(mdp_bindings[i].subscriber->sid):"All",
@ -1342,8 +1347,13 @@ static void mdp_process_packet(struct socket_address *client, struct mdp_header
// double check that this binding belongs to this connection
if (!binding
|| binding->internal
|| !compare_client(&binding->client, client))
|| cmp_sockaddr(&binding->client, client)!=0){
mdp_reply_error(client, header);
WHYF("Already bound by someone else? %s vs %s",
alloca_socket_address(&binding->client),
alloca_socket_address(client));
}
break;
case MDP_IDENTITY:
if (config.debug.mdprequests)
@ -1368,7 +1378,7 @@ static void mdp_process_packet(struct socket_address *client, struct mdp_header
|| binding->internal
|| !source
|| header->local.port == 0
|| !compare_client(&binding->client, client)){
|| cmp_sockaddr(&binding->client, client)!=0){
mdp_reply_error(client, header);
WHY("No matching binding found");
return;
@ -1406,9 +1416,6 @@ static void mdp_process_packet(struct socket_address *client, struct mdp_header
overlay_saw_mdp_frame(NULL, &mdp);
}
if (config.debug.mdprequests)
DEBUGF("Attempting to queue mdp packet");
// construct, encrypt, sign and queue the packet
if (overlay_send_frame(
source, header->local.port,
@ -1425,7 +1432,7 @@ static void mdp_process_packet(struct socket_address *client, struct mdp_header
if (binding
&& !binding->internal
&& header->flags & MDP_FLAG_CLOSE
&& compare_client(&binding->client, client)){
&& cmp_sockaddr(&binding->client, client)==0){
if (config.debug.mdprequests)
DEBUGF("Unbind MDP %s:%d from %s",
binding->subscriber?alloca_tohex_sid_t(binding->subscriber->sid):"All",
@ -1622,12 +1629,14 @@ static void overlay_mdp_poll(struct sched_ent *alarm)
struct overlay_interface *interface = &overlay_interfaces[i];
if (interface->state!=INTERFACE_STATE_UP)
continue;
if (interface->address.addr.sa_family!=AF_INET)
continue;
scans[i].interface = interface;
scans[i].current = ntohl(interface->address.sin_addr.s_addr & interface->netmask.s_addr)+1;
scans[i].last = ntohl(interface->destination->address.sin_addr.s_addr)-1;
scans[i].current = ntohl(interface->address.inet.sin_addr.s_addr & ~interface->netmask.s_addr)+1;
scans[i].last = ntohl(interface->destination->address.inet.sin_addr.s_addr)-1;
if (scans[i].last - scans[i].current>0x10000){
INFOF("Skipping scan on interface %s as the address space is too large",interface->name);
INFOF("Skipping scan on interface %s as the address space is too large (%04x %04x)",
interface->name, scans[i].last, scans[i].current);
continue;
}
scans[i].alarm.alarm=start;

View File

@ -62,6 +62,7 @@
#include "serval.h"
#include "conf.h"
#include "overlay_interface.h"
#include "overlay_packet.h"
#include "overlay_buffer.h"
#include "overlay_address.h"

View File

@ -84,8 +84,8 @@ struct overlay_frame {
int source_full;
// how did we receive this packet?
overlay_interface *interface;
struct sockaddr_in recvaddr;
struct overlay_interface *interface;
// packet envelope header;
// Was it a unicast frame
char unicast;

View File

@ -22,9 +22,12 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "socket.h"
#include "str.h"
#include "strbuf.h"
#include "strbuf_helpers.h"
#include "overlay_buffer.h"
#include "overlay_interface.h"
#include "overlay_packet.h"
struct sockaddr_in loopback;
@ -259,7 +262,7 @@ int parseMdpPacketHeader(struct decode_context *context, struct overlay_frame *f
}
int parseEnvelopeHeader(struct decode_context *context, struct overlay_interface *interface,
struct sockaddr_in *addr, struct overlay_buffer *buffer){
struct socket_address *addr, struct overlay_buffer *buffer){
IN();
context->interface = interface;
@ -386,9 +389,6 @@ int packetOkOverlay(struct overlay_interface *interface,unsigned char *packet, s
}
}
if (recvaddr && recvaddr->addr.sa_family != AF_INET)
RETURN(WHYF("Unexpected protocol family %d", recvaddr->addr.sa_family));
struct overlay_frame f;
struct decode_context context;
bzero(&context, sizeof context);
@ -399,12 +399,8 @@ int packetOkOverlay(struct overlay_interface *interface,unsigned char *packet, s
ob_limitsize(b, len);
f.interface = interface;
if (recvaddr)
f.recvaddr = recvaddr->inet;
else
bzero(&f.recvaddr, sizeof f.recvaddr);
int ret=parseEnvelopeHeader(&context, interface, recvaddr ? &recvaddr->inet : NULL, b);
int ret=parseEnvelopeHeader(&context, interface, recvaddr, b);
if (ret){
ob_free(b);
RETURN(ret);

View File

@ -18,9 +18,10 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <termios.h>
#include "serval.h"
#include "conf.h"
#include <termios.h>
#include "overlay_interface.h"
int overlay_packetradio_setup_port(overlay_interface *interface)
{

View File

@ -21,6 +21,7 @@
#include "serval.h"
#include "conf.h"
#include "overlay_buffer.h"
#include "overlay_interface.h"
#include "overlay_packet.h"
#include "radio_link.h"
#include "str.h"
@ -568,6 +569,9 @@ int overlay_queue_ack(struct subscriber *neighbour, struct network_destination *
if (acked){
int rtt = now - frame->destinations[j].transmit_time;
// if we're on a fake network, the actual rtt can be unrealistic
if (rtt <5)
rtt=5;
if (!destination->min_rtt || rtt < destination->min_rtt){
destination->min_rtt = rtt;
int delay = rtt * 2 + 40;

View File

@ -178,9 +178,6 @@ int fd_showstats()
stats = stats->_next;
}
// Show periodic rhizome transfer information
rhizome_fetch_log_short_status();
// Report any functions that take too much time
if (!config.debug.timing)
{

View File

@ -47,6 +47,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "serval.h"
#include "conf.h"
#include "overlay_buffer.h"
#include "overlay_interface.h"
#include "golay.h"
#include "radio_link.h"

View File

@ -706,7 +706,7 @@ void rhizome_list_release(struct rhizome_list_cursor *);
#define MAX_RHIZOME_MANIFESTS 40
#define MAX_CANDIDATES 32
int rhizome_suggest_queue_manifest_import(rhizome_manifest *m, const struct sockaddr_in *peerip, const sid_t *peersidp);
int rhizome_suggest_queue_manifest_import(rhizome_manifest *m, const struct socket_address *addr, const sid_t *peersidp);
rhizome_manifest * rhizome_fetch_search(const unsigned char *id, int prefix_length);
/* Rhizome file storage api */
@ -994,7 +994,10 @@ enum rhizome_start_fetch_result {
SLOTBUSY
};
enum rhizome_start_fetch_result rhizome_fetch_request_manifest_by_prefix(const struct sockaddr_in *peerip, const sid_t *sidp, const unsigned char *prefix, size_t prefix_length);
enum rhizome_start_fetch_result
rhizome_fetch_request_manifest_by_prefix(const struct socket_address *addr,
const sid_t *peersidp,
const unsigned char *prefix, size_t prefix_length);
int rhizome_any_fetch_active();
int rhizome_any_fetch_queued();
int rhizome_fetch_status_html(struct strbuf *b);

View File

@ -17,16 +17,19 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <assert.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <arpa/inet.h>
#include "serval.h"
#include "rhizome.h"
#include "conf.h"
#include "str.h"
#include "strbuf.h"
#include "strbuf_helpers.h"
#include <assert.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <arpa/inet.h>
#include "socket.h"
static int _form_temporary_file_path(struct __sourceloc __whence, rhizome_http_request *r, char *pathbuf, size_t bufsiz, const char *field)
{
@ -488,14 +491,15 @@ void rhizome_direct_http_dispatch(rhizome_direct_sync_request *r)
goto end;
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(state->port);
addr.sin_addr = *((struct in_addr *)hostent->h_addr);
bzero(&(addr.sin_zero),8);
struct socket_address addr;
bzero(&addr,sizeof(addr));
addr.addrlen = sizeof(addr.inet);
addr.inet.sin_family = AF_INET;
addr.inet.sin_port = htons(state->port);
addr.inet.sin_addr = *((struct in_addr *)hostent->h_addr);
if (connect(sock, (struct sockaddr *)&addr, sizeof addr) == -1) {
WHYF_perror("connect(%s)", alloca_sockaddr(&addr, sizeof addr));
if (connect(sock, &addr.addr, addr.addrlen) == -1) {
WHYF_perror("connect(%s)", alloca_socket_address(&addr));
close(sock);
goto end;
}
@ -693,18 +697,13 @@ void rhizome_direct_http_dispatch(rhizome_direct_sync_request *r)
len+=m->manifest_all_bytes;
len+=snprintf(&buffer[len],8192-len,template3,boundary);
addr.sin_family = AF_INET;
addr.sin_port = htons(state->port);
addr.sin_addr = *((struct in_addr *)hostent->h_addr);
bzero(&(addr.sin_zero),8);
sock=socket(AF_INET, SOCK_STREAM, 0);
if (sock==-1) {
if (config.debug.rhizome_tx)
DEBUGF("could not open socket");
goto closeit;
}
if (connect(sock,(struct sockaddr *)&addr,sizeof(struct sockaddr)) == -1) {
if (connect(sock,&addr.addr,addr.addrlen) == -1) {
if (config.debug.rhizome_tx)
DEBUGF("Could not connect to remote");
goto closeit;

View File

@ -37,7 +37,7 @@ struct rhizome_fetch_candidate {
/* Address of node offering manifest.
Can be either IP+port for HTTP or it can be a SID
for MDP. */
struct sockaddr_in peer_ipandport;
struct socket_address addr;
sid_t peer_sid;
int priority;
@ -50,7 +50,7 @@ struct rhizome_fetch_slot {
struct sched_ent alarm; // must be first element in struct
rhizome_manifest *manifest;
struct sockaddr_in peer_ipandport;
struct socket_address addr;
sid_t peer_sid;
int state;
@ -593,34 +593,25 @@ schedule_fetch(struct rhizome_fetch_slot *slot)
slot->alarm.function = rhizome_fetch_poll;
slot->alarm.stats = &fetch_stats;
if (slot->peer_ipandport.sin_family == AF_INET && slot->peer_ipandport.sin_port) {
if (slot->addr.addr.sa_family == AF_INET && slot->addr.inet.sin_port) {
/* Transfer via HTTP over IPv4 */
if ((sock = esocket(AF_INET, SOCK_STREAM, 0)) == -1)
goto bail_http;
if (set_nonblock(sock) == -1)
goto bail_http;
char buf[INET_ADDRSTRLEN];
if (inet_ntop(AF_INET, &slot->peer_ipandport.sin_addr, buf, sizeof buf) == NULL) {
buf[0] = '*';
buf[1] = '\0';
}
if (connect(sock, (struct sockaddr*)&slot->peer_ipandport,
sizeof slot->peer_ipandport) == -1) {
if (connect(sock, &slot->addr.addr, slot->addr.addrlen) == -1) {
if (errno == EINPROGRESS) {
if (config.debug.rhizome_rx)
DEBUGF("connect() returned EINPROGRESS");
} else {
WHYF_perror("connect(%d, %s:%u)", sock, buf,
ntohs(slot->peer_ipandport.sin_port));
WHYF_perror("connect(%d, %s)", sock, alloca_socket_address(&slot->addr));
goto bail_http;
}
}
if (config.debug.rhizome_rx)
DEBUGF("RHIZOME HTTP REQUEST family=%u addr=%s sid=%s port=%u %s",
slot->peer_ipandport.sin_family,
buf,
DEBUGF("RHIZOME HTTP REQUEST addr=%s sid=%s %s",
alloca_socket_address(&slot->addr),
alloca_tohex_sid_t(slot->peer_sid),
ntohs(slot->peer_ipandport.sin_port),
alloca_str_toprint(slot->request)
);
slot->alarm.poll.fd = sock;
@ -684,7 +675,8 @@ schedule_fetch(struct rhizome_fetch_slot *slot)
* @author Andrew Bettison <andrew@servalproject.com>
*/
static enum rhizome_start_fetch_result
rhizome_fetch(struct rhizome_fetch_slot *slot, rhizome_manifest *m, const struct sockaddr_in *peerip, const sid_t *peersidp)
rhizome_fetch(struct rhizome_fetch_slot *slot, rhizome_manifest *m,
const struct socket_address *addr, const sid_t *peersidp)
{
IN();
if (slot->state != RHIZOME_FETCH_FREE)
@ -705,12 +697,12 @@ rhizome_fetch(struct rhizome_fetch_slot *slot, rhizome_manifest *m, const struct
*/
if (config.debug.rhizome_rx)
DEBUGF("Fetching bundle slot=%d bid=%s version=%"PRIu64" size=%"PRIu64" peerip=%s",
DEBUGF("Fetching bundle slot=%d bid=%s version=%"PRIu64" size=%"PRIu64" addr=%s",
slotno(slot),
alloca_tohex_rhizome_bid_t(m->cryptoSignPublic),
m->version,
m->filesize,
alloca_sockaddr(peerip, sizeof(struct sockaddr_in))
alloca_socket_address(addr)
);
// If the payload is empty, no need to fetch, so import now.
@ -767,7 +759,7 @@ rhizome_fetch(struct rhizome_fetch_slot *slot, rhizome_manifest *m, const struct
DEBUGF(" is new");
/* Prepare for fetching */
slot->peer_ipandport = *peerip;
slot->addr = *addr;
slot->peer_sid = *peersidp;
slot->manifest = m;
@ -787,17 +779,17 @@ rhizome_fetch(struct rhizome_fetch_slot *slot, rhizome_manifest *m, const struct
* Returns -1 on error.
*/
enum rhizome_start_fetch_result
rhizome_fetch_request_manifest_by_prefix(const struct sockaddr_in *peerip,
rhizome_fetch_request_manifest_by_prefix(const struct socket_address *addr,
const sid_t *peersidp,
const unsigned char *prefix, size_t prefix_length)
{
assert(peerip);
assert(addr);
struct rhizome_fetch_slot *slot = rhizome_find_fetch_slot(MAX_MANIFEST_BYTES);
if (slot == NULL)
return SLOTBUSY;
/* Prepare for fetching via HTTP */
slot->peer_ipandport = *peerip;
slot->addr = *addr;
slot->manifest = NULL;
slot->peer_sid = *peersidp;
bcopy(prefix, slot->bid.binary, prefix_length);
@ -824,7 +816,7 @@ static void rhizome_start_next_queued_fetch(struct rhizome_fetch_slot *slot)
unsigned i = 0;
struct rhizome_fetch_candidate *c;
while (i < q->candidate_queue_size && (c = &q->candidate_queue[i])->manifest) {
int result = rhizome_fetch(slot, c->manifest, &c->peer_ipandport, &c->peer_sid);
int result = rhizome_fetch(slot, c->manifest, &c->addr, &c->peer_sid);
switch (result) {
case SLOTBUSY:
OUT(); return;
@ -880,7 +872,7 @@ int rhizome_fetch_has_queue_space(unsigned char log2_size){
return 0;
}
/* Queue a fetch for the payload of the given manifest. If 'peerip' is not NULL, then it is used as
/* Queue a fetch for the payload of the given manifest. If 'addr' is not NULL, then it is used as
* the port and IP address of an HTTP server from which the fetch is performed. Otherwise the fetch
* is performed over MDP.
*
@ -897,7 +889,7 @@ int rhizome_fetch_has_queue_space(unsigned char log2_size){
*
* @author Andrew Bettison <andrew@servalproject.com>
*/
int rhizome_suggest_queue_manifest_import(rhizome_manifest *m, const struct sockaddr_in *peerip, const sid_t *peersidp)
int rhizome_suggest_queue_manifest_import(rhizome_manifest *m, const struct socket_address *addr, const sid_t *peersidp)
{
IN();
@ -1000,7 +992,7 @@ int rhizome_suggest_queue_manifest_import(rhizome_manifest *m, const struct sock
struct rhizome_fetch_candidate *c = rhizome_fetch_insert(qi, ci);
c->manifest = m;
c->priority = priority;
c->peer_ipandport = *peerip;
c->addr = *addr;
c->peer_sid = *peersidp;
if (config.debug.rhizome_rx) {
@ -1332,13 +1324,8 @@ static int rhizome_write_complete(struct rhizome_fetch_slot *slot)
}
if (slot->state==RHIZOME_FETCH_RXFILE) {
char buf[INET_ADDRSTRLEN];
if (inet_ntop(AF_INET, &slot->peer_ipandport.sin_addr, buf, sizeof buf) == NULL) {
buf[0] = '*';
buf[1] = '\0';
}
INFOF("Completed http request from %s:%u for file %s",
buf, ntohs(slot->peer_ipandport.sin_port),
INFOF("Completed http request from %s for file %s",
alloca_socket_address(&slot->addr),
alloca_tohex_rhizome_filehash_t(slot->manifest->filehash));
} else {
INFOF("Completed MDP request from %s for file %s",
@ -1362,11 +1349,12 @@ static int rhizome_write_complete(struct rhizome_fetch_slot *slot)
rhizome_manifest_free(m);
} else {
if (config.debug.rhizome_rx){
DEBUGF("All looks good for importing manifest id=%s", alloca_tohex_rhizome_bid_t(m->cryptoSignPublic));
dump("slot->peerip",&slot->peer_ipandport,sizeof(slot->peer_ipandport));
dump("slot->peersid",&slot->peer_sid,sizeof(slot->peer_sid));
DEBUGF("All looks good for importing manifest id=%s, addr=%s, sid=%s",
alloca_tohex_rhizome_bid_t(m->cryptoSignPublic),
alloca_socket_address(&slot->addr),
alloca_tohex_sid_t(slot->peer_sid));
}
rhizome_suggest_queue_manifest_import(m, &slot->peer_ipandport, &slot->peer_sid);
rhizome_suggest_queue_manifest_import(m, &slot->addr, &slot->peer_sid);
}
}
}

View File

@ -35,6 +35,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "rhizome.h"
#include "dataformats.h"
#include "http_server.h"
#include "overlay_interface.h"
#define RHIZOME_SERVER_MAX_LIVE_REQUESTS 32

View File

@ -290,14 +290,17 @@ int overlay_rhizome_saw_advertisements(struct decode_context *context, struct ov
RETURN(0);
int ad_frame_type=ob_get(f->payload);
struct sockaddr_in httpaddr = context->addr;
httpaddr.sin_port = htons(RHIZOME_HTTP_PORT);
struct socket_address httpaddr = context->addr;
if (httpaddr.addr.sa_family == AF_INET)
httpaddr.inet.sin_port = htons(RHIZOME_HTTP_PORT);
rhizome_manifest *m=NULL;
int (*oldfunc)() = sqlite_set_tracefunc(is_debug_rhizome_ads);
if (ad_frame_type & HAS_PORT){
httpaddr.sin_port = htons(ob_get_ui16(f->payload));
uint16_t port = ob_get_ui16(f->payload);
if (httpaddr.addr.sa_family == AF_INET)
httpaddr.inet.sin_port = htons(port);
}
if (ad_frame_type & HAS_MANIFESTS){

View File

@ -20,6 +20,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "serval.h"
#include "overlay_address.h"
#include "overlay_buffer.h"
#include "overlay_interface.h"
#include "overlay_packet.h"
#include "str.h"
#include "conf.h"
@ -38,7 +39,6 @@ Link state routing;
*/
#define INCLUDE_ANYWAY (200)
#define MAX_LINK_STATES 512
#define FLAG_HAS_INTERFACE (1<<0)
@ -171,6 +171,7 @@ static struct profile_total link_send_stats={
static struct sched_ent link_send_alarm={
.function = link_send,
.stats = &link_send_stats,
.alarm = TIME_NEVER_WILL,
};
struct neighbour *neighbours=NULL;
@ -184,14 +185,15 @@ struct network_destination * new_destination(struct overlay_interface *interface
ret->encapsulation = encapsulation;
ret->interface = interface;
ret->resend_delay = 1000;
ret->last_tx = TIME_NEVER_HAS;
// DEBUGF("Create ref %p, %d - %s", ret, ret->_ref_count, ret->interface->name);
}
return ret;
}
struct network_destination * create_unicast_destination(struct sockaddr_in addr, struct overlay_interface *interface){
if (!interface)
interface = overlay_interface_find(addr.sin_addr, 1);
struct network_destination * create_unicast_destination(struct socket_address *addr, struct overlay_interface *interface){
if (!interface && addr->addr.sa_family == AF_INET)
interface = overlay_interface_find(addr->inet.sin_addr, 1);
if (!interface){
WHY("I don't know which interface to use");
return NULL;
@ -200,14 +202,12 @@ struct network_destination * create_unicast_destination(struct sockaddr_in addr,
WHY("The interface is down.");
return NULL;
}
if (addr.sin_addr.s_addr==0 || addr.sin_port==0){
// WHY("Invalid unicast address");
if (addr->addr.sa_family == AF_INET && (addr->inet.sin_addr.s_addr==0 || addr->inet.sin_port==0))
return NULL;
}
struct network_destination *ret = new_destination(interface, ENCAP_OVERLAY);
if (ret){
ret->address = addr;
ret->address = *addr;
ret->unicast = 1;
ret->tick_ms = interface->destination->tick_ms;
ret->sequence_number = -1;
@ -526,7 +526,7 @@ static int append_link(struct subscriber *subscriber, void *context)
struct link *best_link = find_best_link(subscriber);
if (subscriber->reachable==REACHABLE_SELF){
if (state->next_update - INCLUDE_ANYWAY <= now){
if (state->next_update - 20 <= now){
// Other entries in our keyring are always one hop away from us.
if (append_link_state(payload, 0, my_subscriber, subscriber, -1, 1, -1, 0, 0)){
link_send_alarm.alarm = now+5;
@ -540,7 +540,7 @@ static int append_link(struct subscriber *subscriber, void *context)
if (subscriber->identity)
keyring_send_unlock(subscriber);
if (state->next_update - INCLUDE_ANYWAY <= now){
if (state->next_update - 20 <= now){
if (append_link_state(payload, 0, state->transmitter, subscriber, -1,
best_link?best_link->link_version:-1, -1, 0, best_link?best_link->drop_rate:32)){
link_send_alarm.alarm = now+5;
@ -854,7 +854,7 @@ static int link_send_neighbours()
while (n){
neighbour_find_best_link(n);
if (n->next_neighbour_update - INCLUDE_ANYWAY <= now){
if (n->next_neighbour_update <= now){
send_neighbour_link(n);
}
@ -880,9 +880,7 @@ static int link_send_neighbours()
// send link details
static void link_send(struct sched_ent *alarm)
{
time_ms_t now = gettime_ms();
alarm->alarm=now + 60000;
alarm->alarm=TIME_NEVER_WILL;
// TODO use a separate alarm
link_send_neighbours();
@ -905,11 +903,9 @@ static void link_send(struct sched_ent *alarm)
op_free(frame);
else if (overlay_payload_enqueue(frame))
op_free(frame);
if (neighbours){
alarm->deadline = alarm->alarm;
schedule(alarm);
}else
alarm->alarm=0;
alarm->deadline = alarm->alarm;
schedule(alarm);
}
}
@ -917,7 +913,7 @@ static void update_alarm(struct __sourceloc __whence, time_ms_t limit)
{
if (limit == 0)
FATALF("limit == 0");
if (link_send_alarm.alarm>limit || link_send_alarm.alarm==0){
if (link_send_alarm.alarm>limit){
unschedule(&link_send_alarm);
link_send_alarm.alarm = limit;
link_send_alarm.deadline = limit+10;
@ -1066,8 +1062,8 @@ int link_state_ack_soon(struct subscriber *subscriber)
if (neighbour->using_us
&& subscriber->reachable & REACHABLE_DIRECT
&& subscriber->destination){
if (neighbour->next_neighbour_update > now + subscriber->destination->min_rtt){
neighbour->next_neighbour_update = now + subscriber->destination->min_rtt;
if (neighbour->next_neighbour_update > now + 40 + subscriber->destination->min_rtt){
neighbour->next_neighbour_update = now + 40 + subscriber->destination->min_rtt;
if (config.debug.ack)
DEBUGF("Asking for next ACK Real Soon Now");
}
@ -1107,20 +1103,20 @@ int link_received_duplicate(struct subscriber *subscriber, int payload_seq)
}
// remote peer has confirmed hearing a recent unicast packet
int link_unicast_ack(struct subscriber *UNUSED(subscriber), struct overlay_interface *UNUSED(interface), struct sockaddr_in UNUSED(addr))
int link_unicast_ack(struct subscriber *UNUSED(subscriber), struct overlay_interface *UNUSED(interface), struct socket_address *UNUSED(addr))
{
// TODO find / create network destination, keep it alive
return 0;
}
static struct link_out *create_out_link(struct neighbour *neighbour, overlay_interface *interface, struct sockaddr_in *addr, char unicast)
static struct link_out *create_out_link(struct neighbour *neighbour, overlay_interface *interface, struct socket_address *addr, char unicast)
{
struct link_out *ret=emalloc_zero(sizeof(struct link_out));
if (ret){
ret->_next=neighbour->out_links;
neighbour->out_links=ret;
if (unicast)
ret->destination = create_unicast_destination(*addr, interface);
ret->destination = create_unicast_destination(addr, interface);
else
ret->destination = add_destination_ref(interface->destination);
if (config.debug.linkstate)
@ -1135,7 +1131,7 @@ static struct link_out *create_out_link(struct neighbour *neighbour, overlay_int
return ret;
}
static void create_out_links(struct neighbour *neighbour, overlay_interface *interface, struct sockaddr_in *addr){
static void create_out_links(struct neighbour *neighbour, overlay_interface *interface, struct socket_address *addr){
struct link_out *l = neighbour->out_links;
while(l){
if (l->destination->interface==interface)
@ -1143,13 +1139,12 @@ static void create_out_links(struct neighbour *neighbour, overlay_interface *int
l=l->_next;
}
// if this packet arrived in an IPv4 packet, assume we need to send them unicast packets
if (addr && addr->sin_family==AF_INET && addr->sin_port!=0 && addr->sin_addr.s_addr!=0)
create_out_link(neighbour, interface, addr, 1);
create_out_link(neighbour, interface, addr, 1);
// if this packet arrived from the same IPv4 subnet, or a different type of network, assume they can hear our broadcasts
if (!addr || addr->sin_family!=AF_INET ||
(addr->sin_addr.s_addr & interface->netmask.s_addr)
== (interface->address.sin_addr.s_addr & interface->netmask.s_addr))
if (!addr || addr->addr.sa_family!=AF_INET ||
(addr->inet.sin_addr.s_addr & interface->netmask.s_addr)
== (interface->address.inet.sin_addr.s_addr & interface->netmask.s_addr))
create_out_link(neighbour, interface, addr, 0);
}
@ -1421,7 +1416,7 @@ int link_receive(struct overlay_frame *frame, overlay_mdp_frame *mdp)
if (changed){
route_version++;
neighbour->path_version ++;
if (link_send_alarm.alarm>now+5 || link_send_alarm.alarm==0){
if (link_send_alarm.alarm>now+5){
unschedule(&link_send_alarm);
link_send_alarm.alarm=now+5;
// read all incoming packets first
@ -1494,7 +1489,7 @@ int link_state_legacy_ack(struct overlay_frame *frame, time_ms_t now)
if (changed){
route_version++;
neighbour->path_version ++;
if (link_send_alarm.alarm>now+5 || link_send_alarm.alarm==0){
if (link_send_alarm.alarm>now+5){
unschedule(&link_send_alarm);
link_send_alarm.alarm=now+5;
// read all incoming packets first

199
serval.h
View File

@ -244,12 +244,12 @@ extern char *batman_peerfile;
struct subscriber;
struct decode_context;
struct socket_address;
struct overlay_interface;
struct network_destination;
/* Make sure we have space to put bytes of the packet as we go along */
#define CHECK_PACKET_LEN(B) {if (((*packet_len)+(B))>=packet_maxlen) { return WHY("Packet composition ran out of space."); } }
extern int sock;
struct limit_state{
// length of time for a burst
time_ms_t burst_length;
@ -270,11 +270,6 @@ struct broadcast;
extern int overlayMode;
#define INTERFACE_STATE_FREE 0
#define INTERFACE_STATE_UP 1
#define INTERFACE_STATE_DOWN 2
#define INTERFACE_STATE_DETECTING 3
// Specify 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
@ -305,123 +300,6 @@ struct slip_decode_state{
unsigned dst_offset;
};
struct overlay_interface;
// where should packets be sent to?
struct network_destination {
int _ref_count;
// which interface are we actually sending packets out of
struct overlay_interface *interface;
// The IPv4 destination address, this may be the interface broadcast address.
struct sockaddr_in address;
// should outgoing packets be marked as unicast?
char unicast;
char packet_version;
// should we aggregate packets, or send one at a time
char encapsulation;
// time last packet was sent
time_ms_t last_tx;
int min_rtt;
int max_rtt;
int resend_delay;
// sequence number of last packet sent to this destination.
// Used to allow NACKs that can request retransmission of recent packets.
int sequence_number;
// rate limit for outgoing packets
struct limit_state transfer_limit;
/* Number of milli-seconds per tick for this interface, which is basically
* related to the the typical TX range divided by the maximum expected
* speed of nodes in the network. This means that short-range communications
* has a higher bandwidth requirement than long-range communications because
* the tick interval has to be shorter to still allow fast-convergence time
* to allow for mobility.
*
* For wifi (nominal range 100m) it is usually 500ms.
* For ~100K ISM915MHz (nominal range 1000m) it will probably be about 5000ms.
* For ~10K ISM915MHz (nominal range ~3000m) it will probably be about 15000ms.
*
* These figures will be refined over time, and we will allow people to set
* them per-interface.
*/
unsigned tick_ms;
// Number of milliseconds of no packets until we assume the link is dead.
unsigned reachable_timeout_ms;
};
struct network_destination * new_destination(struct overlay_interface *interface, char encapsulation);
struct network_destination * create_unicast_destination(struct sockaddr_in addr, struct overlay_interface *interface);
struct network_destination * add_destination_ref(struct network_destination *ref);
void release_destination_ref(struct network_destination *ref);
int set_destination_ref(struct network_destination **ptr, struct network_destination *ref);
typedef struct overlay_interface {
struct sched_ent alarm;
char name[256];
int recv_offset; /* file offset */
int recv_count;
int tx_count;
struct radio_link_state *radio_link_state;
// copy of ifconfig flags
uint16_t drop_packets;
char drop_broadcasts;
char drop_unicasts;
int port;
int type;
int socket_type;
char send_broadcasts;
char prefer_unicast;
/* Not necessarily the real MTU, but the largest frame size we are willing to TX.
For radio links the actual maximum and the maximum that is likely to be delivered reliably are
potentially two quite different values. */
int mtu;
// can we use this interface for routes to addresses in other subnets?
int default_route;
// should we log more debug info on this interace? eg hex dumps of packets
char debug;
char local_echo;
unsigned int uartbps; // set serial port speed (which might be different from link speed)
int ctsrts; // enabled hardware flow control if non-zero
struct network_destination *destination;
// can we assume that we will only receive packets from one device?
char point_to_point;
struct subscriber *other_device;
// the actual address of the interface.
struct sockaddr_in address;
struct in_addr netmask;
/* Use one of the INTERFACE_STATE_* constants to indicate the state of this interface.
If the interface stops working or disappears, it will be marked as DOWN and the socket closed.
But if it comes back up again, we should try to reuse this structure, even if the broadcast address has changed.
*/
int state;
} overlay_interface;
/* Maximum interface count is rather arbitrary.
Memory consumption is O(n) with respect to this parameter, so let's not make it too big for now.
*/
extern overlay_interface overlay_interfaces[OVERLAY_MAX_INTERFACES];
extern int overlay_last_interface_number; // used to remember where a packet came from
extern unsigned int overlay_sequence_number;
int server_pid();
void server_save_argv(int argc, const char *const *argv);
@ -429,6 +307,7 @@ int server(const struct cli_parsed *parsed);
int server_create_stopfile();
int server_remove_stopfile();
int server_check_stopfile();
void overlay_mdp_clean_socket_files();
void serverCleanUp();
int isTransactionInCache(unsigned char *transaction_id);
void insertTransactionInCache(unsigned char *transaction_id);
@ -439,14 +318,11 @@ int packetOkOverlay(struct overlay_interface *interface,unsigned char *packet, s
int parseMdpPacketHeader(struct decode_context *context, struct overlay_frame *frame,
struct overlay_buffer *buffer, struct subscriber **nexthop);
int parseEnvelopeHeader(struct decode_context *context, struct overlay_interface *interface,
struct sockaddr_in *addr, struct overlay_buffer *buffer);
struct socket_address *addr, struct overlay_buffer *buffer);
int process_incoming_frame(time_ms_t now, struct overlay_interface *interface,
struct overlay_frame *f, struct decode_context *context);
int overlay_frame_process(struct overlay_interface *interface, struct overlay_frame *f);
int overlay_frame_resolve_addresses(struct overlay_frame *f);
time_ms_t overlay_time_until_next_tick();
int overlay_frame_append_payload(struct decode_context *context, int encapsulation,
struct overlay_frame *p, struct overlay_buffer *b,
@ -454,20 +330,9 @@ int overlay_frame_append_payload(struct decode_context *context, int encapsulati
int overlay_packet_init_header(int packet_version, int encapsulation,
struct decode_context *context, struct overlay_buffer *buff,
char unicast, char interface, int seq);
int overlay_interface_args(const char *arg);
void overlay_rhizome_advertise(struct sched_ent *alarm);
void rhizome_sync_status_html(struct strbuf *b, struct subscriber *subscriber);
int rhizome_cache_count();
int overlay_add_local_identity(unsigned char *s);
extern unsigned overlay_interface_count;
extern int overlay_local_identity_count;
extern unsigned char *overlay_local_identities[OVERLAY_MAX_LOCAL_IDENTITIES];
int rfs_length(int l);
int rfs_encode(int l,unsigned char *b);
int rfs_decode(unsigned char *b,int *offset);
int overlayServerMode(const struct cli_parsed *parsed);
int overlay_payload_enqueue(struct overlay_frame *p);
@ -477,7 +342,6 @@ int overlay_send_tick_packet(struct network_destination *destination);
int overlay_queue_ack(struct subscriber *neighbour, struct network_destination *destination, uint32_t ack_mask, int ack_seq);
int overlay_rhizome_saw_advertisements(struct decode_context *context, struct overlay_frame *f);
int rhizome_server_get_fds(struct pollfd *fds,int *fdcount,int fdmax);
int rhizome_saw_voice_traffic();
int overlay_saw_mdp_containing_frame(struct overlay_frame *f);
@ -486,13 +350,10 @@ int serval_packetvisualise_xpf(XPRINTF xpf, const char *message, const unsigned
void logServalPacket(int level, struct __sourceloc __whence, const char *message, const unsigned char *packet, size_t len);
#define DEBUG_packet_visualise(M,P,N) logServalPacket(LOG_LEVEL_DEBUG, __WHENCE__, (M), (P), (N))
int rhizome_fetching_get_fds(struct pollfd *fds,int *fdcount,int fdmax);
int rhizome_opendb();
int parseCommandLine(struct cli_context *context, const char *argv0, int argc, const char *const *argv);
int overlay_mdp_get_fds(struct pollfd *fds,int *fdcount,int fdmax);
typedef uint32_t mdp_port_t;
#define PRImdp_port_t "#08" PRIx32
@ -567,7 +428,6 @@ int mdp_unbind_internal(struct subscriber *subscriber, mdp_port_t port,
struct vomp_call_state;
void set_codec_flag(int codec, unsigned char *flags);
int is_codec_set(int codec, unsigned char *flags);
struct vomp_call_state *vomp_find_call_by_session(unsigned int session_token);
int vomp_mdp_received(overlay_mdp_frame *mdp);
@ -580,17 +440,6 @@ int vomp_received_audio(struct vomp_call_state *call, int audio_codec, int time,
const unsigned char *audio, int audio_length);
void monitor_get_all_supported_codecs(unsigned char *codecs);
int overlay_route_node_info(overlay_mdp_nodeinfo *node_info);
int overlay_interface_register(char *name,
struct in_addr addr,
struct in_addr mask);
overlay_interface * overlay_interface_get_default();
overlay_interface * overlay_interface_find(struct in_addr addr, int return_default);
overlay_interface * overlay_interface_find_name(const char *name);
int overlay_interface_compare(overlay_interface *one, overlay_interface *two);
int overlay_broadcast_ensemble(struct network_destination *destination, struct overlay_buffer *buffer);
void interface_state_html(struct strbuf *b, struct overlay_interface *interface);
int directory_registration();
int directory_service_init();
@ -602,6 +451,7 @@ int app_meshms_conversations(const struct cli_parsed *parsed, struct cli_context
int app_meshms_send_message(const struct cli_parsed *parsed, struct cli_context *context);
int app_meshms_list_messages(const struct cli_parsed *parsed, struct cli_context *context);
int app_meshms_mark_read(const struct cli_parsed *parsed, struct cli_context *context);
int app_msp_connection(const struct cli_parsed *parsed, struct cli_context *context);
int monitor_get_fds(struct pollfd *fds,int *fdcount,int fdmax);
@ -615,37 +465,9 @@ int monitor_tell_formatted(int mask, char *fmt, ...);
int monitor_client_interested(int mask);
extern int monitor_socket_count;
typedef struct monitor_audio {
char name[128];
int (*start)();
int (*stop)();
int (*poll_fds)(struct pollfd *,int);
int (*read)(unsigned char *,int);
int (*write)(unsigned char *,int);
} monitor_audio;
extern monitor_audio *audev;
monitor_audio *audio_msm_g1_detect();
monitor_audio *audio_alsa_detect();
monitor_audio *audio_reflector_detect();
int detectAudioDevice();
int getAudioPlayFd();
int getAudioRecordFd();
int getAudioBytes(unsigned char *buffer,
int offset,
int bufferSize);
int encodeAndDispatchRecordedAudio(int fd,int callSessionToken,
int recordCodec,
unsigned char *sampleData,
int sampleBytes);
int scrapeProcNetRoute();
int lsif();
int doifaddrs();
int bufferAudioForPlayback(int codec, time_ms_t start_time, time_ms_t end_time,
unsigned char *data,int dataLen);
int startAudio();
int stopAudio();
#define SERVER_UNKNOWN 1
#define SERVER_NOTRESPONDING 2
@ -661,16 +483,14 @@ int dna_return_resolution(overlay_mdp_frame *mdp, unsigned char *fromSid,
int parseDnaReply(const char *buf, size_t len, char *token, char *did, char *name, char *uri, const char **bufp);
extern int sigPipeFlag;
extern int sigIoFlag;
extern int sigIntFlag;
void sigPipeHandler(int signal);
void sigIoHandler(int signal);
void sigIntHandler(int signal);
int overlay_mdp_setup_sockets();
void overlay_interface_discover(struct sched_ent *alarm);
void overlay_packetradio_poll(struct sched_ent *alarm);
int overlay_packetradio_setup_port(overlay_interface *interface);
int overlay_packetradio_tx_packet(struct overlay_frame *frame);
void overlay_dummy_poll(struct sched_ent *alarm);
int overlay_packetradio_setup_port(struct overlay_interface *interface);
void server_config_reload(struct sched_ent *alarm);
void server_shutdown_check(struct sched_ent *alarm);
int overlay_mdp_try_internal_services(struct overlay_frame *frame, overlay_mdp_frame *mdp);
@ -679,7 +499,6 @@ int overlay_send_stun_request(struct subscriber *server, struct subscriber *requ
void fd_periodicstats(struct sched_ent *alarm);
void rhizome_check_connections(struct sched_ent *alarm);
int overlay_tick_interface(int i, time_ms_t now);
int overlay_queue_init();
void monitor_client_poll(struct sched_ent *alarm);
@ -721,7 +540,7 @@ int link_state_announce_links();
int link_state_legacy_ack(struct overlay_frame *frame, time_ms_t now);
int link_state_ack_soon(struct subscriber *sender);
int link_state_should_forward_broadcast(struct subscriber *transmitter);
int link_unicast_ack(struct subscriber *subscriber, struct overlay_interface *interface, struct sockaddr_in addr);
int link_unicast_ack(struct subscriber *subscriber, struct overlay_interface *interface, struct socket_address *addr);
int link_add_destinations(struct overlay_frame *frame);
void link_neighbour_short_status_html(struct strbuf *b, const char *link_prefix);
void link_neighbour_status_html(struct strbuf *b, struct subscriber *neighbour);

View File

@ -27,6 +27,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "conf.h"
#include "strbuf.h"
#include "strbuf_helpers.h"
#include "overlay_interface.h"
#define PIDFILE_NAME "servald.pid"
#define STOPFILE_NAME "servald.stop"
@ -233,17 +234,10 @@ void serverCleanUp()
if (serverMode){
rhizome_close_db();
dna_helper_shutdown();
overlay_interface_close_all();
}
char filename[1024];
if (FORM_SERVAL_INSTANCE_PATH(filename, "mdp.socket"))
unlink(filename);
if (FORM_SERVAL_INSTANCE_PATH(filename, "mdp.2.socket"))
unlink(filename);
if (FORM_SERVAL_INSTANCE_PATH(filename, "monitor.socket"))
unlink(filename);
overlay_mdp_clean_socket_files();
/* Try to remove shutdown and PID files and exit */
server_remove_stopfile();

View File

@ -21,6 +21,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
int sigPipeFlag=0;
int sigIoFlag=0;
int sigIntFlag=0;
void sigPipeHandler(int UNUSED(signal))
{
@ -33,3 +34,8 @@ void sigIoHandler(int UNUSED(signal))
sigIoFlag++;
return;
}
void sigIntHandler(int UNUSED(signal))
{
sigIntFlag++;
}

View File

@ -164,6 +164,7 @@ int cmp_sockaddr(const struct socket_address *addrA, const struct socket_address
(addrA->addrlen < addrB->addrlen ? addrA->addrlen : addrB->addrlen) - sizeof addrA->addr.sa_family);
if (c == 0)
c = addrA->addrlen < addrB->addrlen ? -1 : addrA->addrlen > addrB->addrlen ? 1 : 0;
return c;
}
@ -234,6 +235,24 @@ int _socket_set_rcvbufsize(struct __sourceloc __whence, int sock, unsigned buffe
return 0;
}
int socket_unlink_close(int sock)
{
// get the socket name and unlink it from the filesystem if not abstract
struct socket_address addr;
addr.addrlen = sizeof addr.store;
if (getsockname(sock, &addr.addr, &addr.addrlen))
WHYF_perror("getsockname(%d)", sock);
else if (addr.addr.sa_family==AF_UNIX
&& addr.addrlen > sizeof addr.local.sun_family
&& addr.addrlen <= sizeof addr.local
&& addr.local.sun_path[0] != '\0') {
if (unlink(addr.local.sun_path) == -1)
WARNF_perror("unlink(%s)", alloca_str_toprint(addr.local.sun_path));
}
close(sock);
return 0;
}
ssize_t _send_message(struct __sourceloc __whence, int fd, const struct socket_address *address, const struct fragmented_data *data)
{
struct msghdr hdr={
@ -260,5 +279,6 @@ ssize_t _recv_message(struct __sourceloc __whence, int fd, struct socket_address
ssize_t ret = recvmsg(fd, &hdr, 0);
if (ret==-1)
WHYF_perror("recvmsg(%d,%s,%lu)", fd, alloca_socket_address(address), (unsigned long)address->addrlen);
address->addrlen = hdr.msg_namelen;
return ret;
}

View File

@ -54,6 +54,7 @@ int _socket_connect(struct __sourceloc, int sock, const struct sockaddr *addr, s
int _socket_listen(struct __sourceloc, int sock, int backlog);
int _socket_set_reuseaddr(struct __sourceloc, int sock, int reuseP);
int _socket_set_rcvbufsize(struct __sourceloc, int sock, unsigned buffer_size);
int socket_unlink_close(int sock);
#define make_local_sockaddr(sockname, fmt,...) _make_local_sockaddr(__WHENCE__, (sockname), (fmt), ##__VA_ARGS__)
#define esocket(domain, type, protocol) _esocket(__WHENCE__, (domain), (type), (protocol))

View File

@ -24,6 +24,8 @@ SERVAL_SOURCES = \
$(SERVAL_BASE)meshms.c \
$(SERVAL_BASE)mdp_client.c \
$(SERVAL_BASE)mdp_net.c \
$(SERVAL_BASE)msp_client.c \
$(SERVAL_BASE)msp_proxy.c \
$(SERVAL_BASE)os.c \
$(SERVAL_BASE)mem.c \
$(SERVAL_BASE)instance.c \

View File

@ -259,6 +259,7 @@ setup_servald_so() {
start_servald_server() {
push_instance
set_instance_fromarg "$1" && shift
configure_servald_server
# Start servald server
local -a before_pids
local -a after_pids
@ -654,7 +655,38 @@ create_identities() {
# - set up the configuration immediately prior to starting a servald server process
# - called by start_servald_instances
configure_servald_server() {
:
add_servald_interface
}
add_servald_interface() {
local SOCKET_TYPE="dgram"
local INTERFACE="1"
local TYPE="wifi"
while [ $# -ne 0 ]; do
case "$1" in
--wifi) TYPE="wifi"; shift;;
--ethernet) TYPE="ethernet"; shift;;
--file) SOCKET_TYPE="file"; shift;;
*) INTERFACE="$1"; shift;;
esac
done
if [ "${SOCKET_TYPE}" == "file" ]; then
>>$SERVALD_VAR/dummy$INTERFACE
executeOk_servald config \
set server.interface_path $SERVALD_VAR \
set interfaces.$INTERFACE.socket_type $SOCKET_TYPE \
set interfaces.$INTERFACE.file dummy$INTERFACE \
set interfaces.$INTERFACE.type $TYPE \
set interfaces.$INTERFACE.dummy_address 127.0.$INTERFACE.$instance_number \
set interfaces.$INTERFACE.dummy_netmask 255.255.255.224
else
mkdir "$SERVALD_VAR/dummy$INTERFACE/"
executeOk_servald config \
set server.interface_path $SERVALD_VAR \
set interfaces.$INTERFACE.socket_type $SOCKET_TYPE \
set interfaces.$INTERFACE.file dummy$INTERFACE/$instance_name \
set interfaces.$INTERFACE.type $TYPE
fi
}
# Utility function:
@ -666,29 +698,13 @@ configure_servald_server() {
# - wait for all instances to detect each other
# - assert that all instances are in each others' peer lists
start_servald_instances() {
local DUMMY=dummy
case "$1" in
dummy*) DUMMY="$1"; shift;;
esac
push_instance
tfw_log "# start servald instances DUMMY=$DUMMY $*"
local DUMMYNET="$SERVALD_VAR/$DUMMY"
>$DUMMYNET
local I
for I; do
set_instance $I
# These config settings can be overridden in a caller-supplied configure_servald_server().
# They are extremely useful for the majority of fixtures.
executeOk_servald config \
set interfaces.1.file "$DUMMYNET"
configure_servald_server
tfw_log "# start servald instances $*"
foreach_instance "$@" \
start_servald_server
eval DUMMY$instance_name="\$DUMMYNET"
done
# Now wait until they see each other.
foreach_instance "$@" \
wait_until --sleep=0.25 has_seen_instances "$@"
tfw_log "# dummynet file:" $(ls -l $DUMMYNET)
pop_instance
}

View File

@ -25,6 +25,7 @@ includeTests config
includeTests keyring
includeTests server
includeTests routing
includeTests msp
includeTests dnahelper
includeTests dnaprotocol
includeTests rhizomeops

View File

@ -22,6 +22,7 @@ source "${0%/*}/../testframework.sh"
source "${0%/*}/../testdefs.sh"
configure_servald_server() {
add_servald_interface
executeOk_servald config \
set log.console.show_pid on \
set log.console.show_time on \

View File

@ -41,6 +41,7 @@ teardown() {
# Called by start_servald_instances immediately before starting the server
# process in each instance.
configure_servald_server() {
add_servald_interface
executeOk_servald config \
set log.console.level debug \
set log.console.show_pid on \

View File

@ -25,7 +25,7 @@ setup() {
setup_servald
assert_no_servald_processes
foreach_instance +A +B create_single_identity
configure_servald_server() { set_server_vars; }
configure_servald_server() { add_servald_interface; set_server_vars; }
start_servald_instances +A +B
set_instance +A
}
@ -45,17 +45,10 @@ set_server_vars() {
set log.console.level debug \
set log.console.show_pid on \
set log.console.show_time on \
set mdp.iftype.wifi.tick_ms 100 \
set rhizome.enable No \
set debug.overlayinterfaces No \
set debug.overlaybuffer No \
set debug.packetformats No \
set debug.overlayframes No \
set debug.overlayrouting No \
set debug.packettx No \
set debug.packetrx No \
set debug.mdprequests Yes \
set debug.keyring Yes
set debug.keyring Yes \
set debug.linkstate Yes
}
doc_LookupWildcard="Lookup by wildcard"
@ -125,6 +118,7 @@ EOF
chmod 0755 "$dnahelper"
foreach_instance +A +B +C +D create_single_identity
configure_servald_server() {
add_servald_interface
set_server_vars
executeOk_servald config \
set debug.dnahelper on \

201
tests/msp Executable file
View File

@ -0,0 +1,201 @@
#!/bin/bash
# Tests for stream connections
#
# Copyright 2012 Serval Project, Inc.
#
# 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.
source "${0%/*}/../testframework.sh"
source "${0%/*}/../testdefs.sh"
teardown() {
stop_all_servald_servers
kill_all_servald_processes
assert_no_servald_processes
report_all_servald_servers
}
configure_servald_server() {
create_single_identity
add_servald_interface
executeOk_servald config \
set debug.mdprequests on \
set debug.msp on \
set log.console.level DEBUG \
set log.console.show_time on
}
doc_connect_fail="Timeout when the connection isn't reachable"
setup_connect_fail() {
setup_servald
assert_no_servald_processes
set_instance +B
create_single_identity
start_servald_instances +A
}
test_connect_fail() {
set_instance +A
execute --exit-status=1 --timeout=20 $servald msp connect $SIDB 512 <<EOF
Hello from the client
EOF
tfw_cat --stderr
}
doc_hello="Simple Hello World"
setup_hello() {
setup_servald
assert_no_servald_processes
start_servald_instances +A +B
}
server_hello() {
executeOk_servald --timeout=20 msp listen 512 <<EOF
Hello from the server
EOF
assertStdoutGrep --matches=1 "^Hello from the client$"
tfw_cat --stderr
}
test_hello() {
set_instance +A
fork server_hello
wait_until grep "Bind MDP $SIDA:512" "$instance_servald_log"
set_instance +B
executeOk_servald --timeout=20 msp connect $SIDA 512 <<EOF
Hello from the client
EOF
assertStdoutGrep --matches=1 "^Hello from the server$"
fork_wait_all
}
doc_client_no_data="Client connection with no data"
setup_client_no_data() {
setup_servald
assert_no_servald_processes
create_file file1 64000
start_servald_instances +A +B
}
server_client_no_data() {
executeOk_servald --timeout=20 msp listen 512 <file1
tfw_cat --stderr
}
test_client_no_data() {
set_instance +A
fork server_client_no_data
wait_until grep "Bind MDP $SIDA:512" "$instance_servald_log"
set_instance +B
executeOk_servald --timeout=20 msp connect $SIDA 512 <<EOF
EOF
tfw_cat --stderr
assert diff file1 "$TFWSTDOUT"
fork_wait_all
}
doc_server_no_data="Server sends no data"
setup_server_no_data() {
setup_servald
assert_no_servald_processes
create_file file1 64000
start_servald_instances +A +B
}
server_server_no_data() {
executeOk_servald --timeout=20 msp listen 512 <<EOF
EOF
tfw_cat --stderr
assert diff file1 "$TFWSTDOUT"
}
test_server_no_data() {
set_instance +A
fork server_server_no_data
wait_until grep "Bind MDP $SIDA:512" "$instance_servald_log"
set_instance +B
executeOk_servald --timeout=20 msp connect $SIDA 512 <file1
tfw_cat --stderr
fork_wait_all
}
doc_keep_alive="Keep the connection alive with no data"
setup_keep_alive() {
setup_servald
assert_no_servald_processes
start_servald_instances +A +B
}
listen_pipe() {
executeOk_servald msp listen 512 < <(echo "START" && sleep 20 && echo "END")
tfw_cat --stdout --stderr
}
connect_pipe() {
executeOk_servald msp connect $1 512 < <(echo "START" && sleep 20 && echo "END")
tfw_cat --stdout --stderr
}
test_keep_alive() {
set_instance +A
fork listen_pipe
wait_until --timeout=10 grep "Bind MDP $SIDA:512" "$instance_servald_log"
set_instance +B
fork connect_pipe $SIDA
fork_wait_all
}
doc_forward="Forward TCP connections to a remote server"
setup_forward() {
setup_servald
assert_no_servald_processes
start_servald_instances +A +B
}
client_forward() {
executeOk --timeout=20 $servald msp connect --once --forward=$1 $2 512
tfw_cat --stdout --stderr
}
test_forward() {
set_instance +A
fork server_hello
wait_until --timeout=10 grep "Bind MDP $SIDA:512" "$instance_servald_log"
set_instance +B
fork client_forward 2048 $SIDA
sleep 1
executeOk nc -v 127.0.0.1 2048 < <(echo "Hello from the client")
assertStdoutGrep --matches=1 "^Hello from the server$"
fork_wait_all
}
doc_tcp_tunnel="Tunnel a tcp connection"
setup_tcp_tunnel() {
setup_servald
assert_no_servald_processes
start_servald_instances +A +B
}
server_forward() {
executeOk_servald msp listen --once --forward=$1 512
tfw_cat --stderr
}
nc_listen() {
execute nc -v -l $1 < <(echo "Hello from the server")
tfw_cat --stdout --stderr
}
test_tcp_tunnel() {
fork nc_listen 6000
set_instance +A
fork server_forward 6000
set_instance +B
fork client_forward 6001 $SIDA
sleep 1
executeOk nc -v 127.0.0.1 6001 < <(echo "Hello from the client")
assertStdoutGrep --matches=1 "^Hello from the server$"
fork_wait_all
}
runTests "$@"

View File

@ -36,6 +36,7 @@ teardown() {
# Called by start_servald_instances for each instance.
configure_servald_server() {
add_servald_interface
executeOk_servald config \
set log.show_pid on \
set log.show_time on \

View File

@ -36,6 +36,7 @@ teardown() {
# Called by start_servald_instances for each instance.
configure_servald_server() {
add_servald_interface --file
executeOk_servald config \
set log.console.level debug \
set log.console.show_pid on \
@ -574,7 +575,7 @@ setup_direct() {
rhizome_add_file fileA3 100000
BID_A3=$BID
VERSION_A3=$VERSION
start_servald_instances dummy1 +A
start_servald_instances +A
wait_until rhizome_http_server_started +A
get_rhizome_server_port PORTA +A
set_instance +B

View File

@ -36,6 +36,7 @@ teardown() {
# Called by start_servald_instances for each instance.
configure_servald_server() {
add_servald_interface
executeOk_servald config \
set log.file.show_pid on \
set log.file.show_time on \

View File

@ -22,43 +22,38 @@
source "${0%/*}/../testframework.sh"
source "${0%/*}/../testdefs.sh"
add_interface() {
>$SERVALD_VAR/dummy$1
executeOk_servald config \
set interfaces.$1.file dummy$1 \
set interfaces.$1.dummy_address 127.0.$1.$instance_number \
set interfaces.$1.dummy_netmask 255.255.255.224
}
interface_up() {
$GREP "Interface .* is up" $instance_servald_log || return 1
return 0
}
has_link() {
interface_ex=".*"
case "$1" in
dummy*) interface_ex="$1"; shift;;
esac
set_instance $1
executeOk_servald route print
tfw_log "Looking for link from $1 to $2 ($4)"
if ! grep "^${4}:\(BROADCAST\|UNICAST\):${interface_ex}:0*\$" $_tfw_tmp/stdout; then
link_matches() {
local interface_ex=".*"
local link_type="\(BROADCAST\|\UNICAST\)"
local via="0*"
local sid=""
while [ $# -ne 0 ]; do
case "$1" in
--interface) interface_ex="$2"; shift 2;;
--broadcast) link_type="BROADCAST"; shift;;
--unicast) link_type="UNICAST"; shift;;
--via) link_type="INDIRECT"; via="$2"; interface_ex=""; shift 2;;
*) break;;
esac
done
sid="$1"
tfw_log "Looking for link ${sid}, ${link_type}, ${interface_ex}, ${via}"
if ! grep "^${sid}:${link_type}:${interface_ex}:${via}\$" $_tfw_tmp/stdout; then
tfw_log "Link not found"
# tfw_log "^${4}:\(BROADCAST\|UNICAST\):${interface_ex}:0*\$"
# tfw_cat --stdout --stderr
return 1
fi
[ $4 = $5 ] && return 0;
tfw_log "Path from $1 to $3 should be via $2 ($5, $4)"
if ! grep "^${5}:INDIRECT::${4}\$" $_tfw_tmp/stdout; then
tfw_log "No path found"
# tfw_log "^${5}:INDIRECT::${4}\$"
# tfw_cat --stdout --stderr
return 1
fi
}
has_link() {
executeOk_servald route print
link_matches $@
}
path_exists() {
local dest
eval dest=\$$#
@ -69,26 +64,26 @@ path_exists() {
for I; do
local sidvar=SID${I#+}
[ -n "${!sidvar}" ] || break
has_link $next_inst $I $dest ${!sidvar} ${!dest_sidvar} || return 1
set_instance $next_inst
executeOk_servald route print
link_matches ${!sidvar} || return 1
[ $I = $dest ] && return 0
link_matches --via ${!sidvar} ${!dest_sidvar} || return 1
next_inst=$I
done
return 0
}
start_routing_instance() {
configure_servald_server() {
executeOk_servald config \
set server.interface_path "$SERVALD_VAR" \
set debug.mdprequests yes \
set debug.linkstate yes \
set debug.verbose yes \
set debug.subscriber yes \
set debug.overlayrouting yes \
set log.console.level debug \
set log.console.show_pid on \
set log.console.show_time on \
set rhizome.enable no
start_servald_server
wait_until interface_up
}
log_routing_table() {
@ -109,8 +104,8 @@ setup_single_link() {
setup_servald
assert_no_servald_processes
foreach_instance +A +B create_single_identity
foreach_instance +A +B add_interface 1
foreach_instance +A +B start_routing_instance
foreach_instance +A +B add_servald_interface 1
foreach_instance +A +B start_servald_server
}
test_single_link() {
wait_until --timeout=10 path_exists +A +B
@ -125,26 +120,28 @@ setup_multiple_ids() {
setup_servald
assert_no_servald_processes
foreach_instance +A +B create_identities 2
foreach_instance +A +B add_interface 1
foreach_instance +A +B start_routing_instance
foreach_instance +A +B add_servald_interface 1
foreach_instance +A +B start_servald_server
}
test_multiple_ids() {
wait_until path_exists +A +B
wait_until has_link +A +B +B $SIDB1 $SIDB2
set_instance +A
wait_until has_link --via $SIDB1 $SIDB2
wait_until path_exists +B +A
wait_until has_link +B +A +A $SIDA1 $SIDA2
set_instance +B
wait_until has_link --via $SIDA1 $SIDA2
set_instance +A
executeOk_servald mdp ping --timeout=3 $SIDB2 1
tfw_cat --stdout --stderr
executeOk_servald route print
assertStdoutGrep --matches=1 "^$SIDB1:BROADCAST:dummy.*:0*"
assertStdoutGrep --matches=1 "^$SIDB2:INDIRECT::$SIDB1"
link_matches --broadcast $SIDB1
link_matches --via $SIDB1 $SIDB2
set_instance +B
executeOk_servald mdp ping --timeout=3 $SIDA2 1
tfw_cat --stdout --stderr
executeOk_servald route print
assertStdoutGrep --matches=1 "^$SIDA1:BROADCAST:dummy.*:0*"
assertStdoutGrep --matches=1 "^$SIDA2:INDIRECT::$SIDA1"
link_matches --broadcast $SIDA1
link_matches --via $SIDA1 $SIDA2
}
doc_unlock_ids="Routes appear and disappear as identities are [un]locked"
@ -152,18 +149,19 @@ setup_unlock_ids() {
setup_servald
assert_no_servald_processes
foreach_instance +A +B create_single_identity
foreach_instance +A +B add_interface 1
foreach_instance +A +B add_servald_interface 1
set_instance +A
executeOk_servald keyring add 'entry-pin'
extract_stdout_keyvalue SIDX sid "$rexp_sid"
foreach_instance +A +B start_routing_instance
foreach_instance +A +B start_servald_server
}
test_unlock_ids() {
wait_until path_exists +A +B
wait_until path_exists +B +A
set_instance +A
executeOk_servald id enter pin 'entry-pin'
wait_until has_link +B +A +A $SIDA $SIDX
set_instance +B
wait_until has_link --via $SIDA $SIDX
set_instance +A
executeOk_servald id relinquish pin 'entry-pin'
set_instance +B
@ -182,18 +180,20 @@ setup_migrate_id() {
set_instance +B
executeOk_servald keyring load sidx '' 'entry-pin'
foreach_instance +A +B create_single_identity
foreach_instance +A +B add_interface 1
foreach_instance +A +B start_routing_instance
foreach_instance +A +B add_servald_interface 1
foreach_instance +A +B start_servald_server
}
test_migrate_id() {
wait_until path_exists +A +B
wait_until path_exists +B +A
set_instance +A
executeOk_servald id enter pin 'entry-pin'
wait_until has_link +B +A +A $SIDA $SIDX
set_instance +B
wait_until has_link --via $SIDA $SIDX
set_instance +B
executeOk_servald id enter pin 'entry-pin'
wait_until --timeout=30 has_link +A +B +B $SIDB $SIDX
set_instance +A
wait_until --timeout=30 has_link --via $SIDB $SIDX
}
doc_single_mdp="Use single MDP per packet encapsulation"
@ -201,9 +201,9 @@ setup_single_mdp() {
setup_servald
assert_no_servald_processes
foreach_instance +A +B create_single_identity
foreach_instance +A +B add_interface 1
foreach_instance +A +B add_servald_interface 1
foreach_instance +A +B executeOk_servald config set interfaces.1.encapsulation single
foreach_instance +A +B start_routing_instance
foreach_instance +A +B start_servald_server
}
test_single_mdp() {
wait_until path_exists +A +B
@ -218,9 +218,9 @@ setup_mismatched_encap() {
setup_servald
assert_no_servald_processes
foreach_instance +A +B create_single_identity
foreach_instance +A +B add_interface 1
foreach_instance +A +B add_servald_interface 1
foreach_instance +A executeOk_servald config set interfaces.1.encapsulation single
foreach_instance +A +B start_routing_instance
foreach_instance +A +B start_servald_server
}
test_mismatched_encap() {
wait_until path_exists +A +B
@ -235,13 +235,12 @@ setup_single_p2p() {
setup_servald
assert_no_servald_processes
foreach_instance +A +B create_single_identity
foreach_instance +A +B add_interface 1
foreach_instance +A +B add_servald_interface 1
foreach_instance +A +B \
executeOk_servald config \
set interfaces.1.debug 1 \
set interfaces.1.encapsulation single \
set interfaces.1.point_to_point on
foreach_instance +A +B start_routing_instance
foreach_instance +A +B start_servald_server
}
test_single_p2p() {
wait_until path_exists +A +B
@ -293,7 +292,7 @@ setup_simulate_extender() {
set interfaces.1.socket_type STREAM \
set interfaces.1.encapsulation SINGLE \
set interfaces.1.point_to_point on
foreach_instance +A +B start_routing_instance
foreach_instance +A +B start_servald_server
}
test_simulate_extender() {
wait_until path_exists +A +B
@ -314,8 +313,8 @@ setup_multiple_nodes() {
setup_servald
assert_no_servald_processes
foreach_instance +A +B +C +D create_single_identity
foreach_instance +A +B +C +D add_interface 1
foreach_instance +A +B +C +D start_routing_instance
foreach_instance +A +B +C +D add_servald_interface 1
foreach_instance +A +B +C +D start_servald_server
}
test_multiple_nodes() {
wait_until path_exists +A +B
@ -338,11 +337,13 @@ setup_scan() {
setup_servald
assert_no_servald_processes
foreach_instance +A +B +C create_single_identity
foreach_instance +A +B +C add_interface 1
foreach_instance +A +B +C add_servald_interface --file 1
foreach_instance +A +B +C \
executeOk_servald config \
set interfaces.1.drop_broadcasts on
foreach_instance +A +B +C start_routing_instance
foreach_instance +A +B +C start_servald_server
foreach_instance +A +B +C \
wait_until interface_up
}
test_scan() {
set_instance +A
@ -350,14 +351,14 @@ test_scan() {
wait_until scan_completed
wait_until --timeout=10 has_seen_instances +B +C
executeOk_servald route print
assertStdoutGrep --matches=1 "^$SIDB:UNICAST:"
assertStdoutGrep --matches=1 "^$SIDC:UNICAST:"
link_matches --unicast $SIDB
link_matches --unicast $SIDC
executeOk_servald mdp ping --timeout=3 $SIDB 1
tfw_cat --stdout --stderr
set_instance +B
executeOk_servald route print
assertStdoutGrep --matches=1 "^$SIDA:UNICAST:"
assertStdoutGrep --matches=1 "^$SIDC:INDIRECT:"
link_matches --unicast $SIDA
link_matches --via $SIDA $SIDC
executeOk_servald mdp ping --timeout=3 $SIDC 1
tfw_cat --stdout --stderr
}
@ -372,7 +373,7 @@ test_scan_one() {
wait_until scan_completed
wait_until --timeout=10 has_seen_instances +B
executeOk_servald route print
assertStdoutGrep --matches=1 "^$SIDB:UNICAST:"
link_matches --unicast $SIDB
assertStdoutGrep --matches=0 "^$SIDC:"
executeOk_servald mdp ping --timeout=3 $SIDB 1
tfw_cat --stdout --stderr
@ -388,23 +389,19 @@ setup_single_filter() {
setup_servald
assert_no_servald_processes
foreach_instance +A +B create_single_identity
foreach_instance +A +B add_interface 1
foreach_instance +A +B add_servald_interface --file 1
set_instance +B
executeOk_servald config \
set interfaces.1.drop_broadcasts on
foreach_instance +A +B start_routing_instance
foreach_instance +A +B start_servald_server
}
test_single_filter() {
wait_until --timeout=10 path_exists +A +B
wait_until --timeout=5 path_exists +B +A
set_instance +A
wait_until --timeout=10 has_link --unicast $SIDB
set_instance +B
wait_until --timeout=5 has_link --broadcast $SIDA
executeOk_servald mdp ping --timeout=3 $SIDB 1
tfw_cat --stdout --stderr
executeOk_servald route print
assertStdoutGrep --matches=1 "^$SIDB:UNICAST:"
set_instance +B
executeOk_servald route print
assertStdoutGrep --matches=1 "^$SIDA:BROADCAST:"
}
doc_broadcast_only="Broadcast packets only"
@ -412,19 +409,19 @@ setup_broadcast_only() {
setup_servald
assert_no_servald_processes
foreach_instance +A +B create_single_identity
foreach_instance +A +B add_interface 1
foreach_instance +A +B add_servald_interface --file 1
foreach_instance +A +B \
executeOk_servald config set interfaces.1.drop_unicasts 1
foreach_instance +A +B start_routing_instance
foreach_instance +A +B start_servald_server
}
test_broadcast_only() {
wait_until path_exists +A +B
wait_until path_exists +B +A
set_instance +A
wait_until has_link --broadcast $SIDB
set_instance +B
wait_until has_link --broadcast $SIDA
set_instance +A
executeOk_servald mdp ping --timeout=3 $SIDB 1
tfw_cat --stdout --stderr
executeOk_servald route print
assertStdoutGrep --matches=1 "^$SIDB:BROADCAST:"
}
doc_prefer_unicast="Prefer unicast packets"
@ -432,21 +429,23 @@ setup_prefer_unicast() {
setup_servald
assert_no_servald_processes
foreach_instance +A +B create_single_identity
foreach_instance +A +B add_interface 1
foreach_instance +A +B add_servald_interface 1
foreach_instance +A +B \
executeOk_servald config \
set interfaces.1.prefer_unicast 1 \
set debug.overlayframes 1
foreach_instance +A +B start_routing_instance
foreach_instance +A +B start_servald_server
}
test_prefer_unicast() {
set_instance +A
wait_until has_link --unicast $SIDB
set_instance +B
wait_until has_link --unicast $SIDA
wait_until path_exists +A +B
wait_until path_exists +B +A
set_instance +A
executeOk_servald mdp ping --timeout=3 $SIDB 1
tfw_cat --stdout --stderr
executeOk_servald route print
assertStdoutGrep --matches=1 "^$SIDB:UNICAST:"
}
doc_multihop_linear="Start 4 instances in a linear arrangement"
@ -454,10 +453,10 @@ setup_multihop_linear() {
setup_servald
assert_no_servald_processes
foreach_instance +A +B +C +D create_single_identity
foreach_instance +A +B add_interface 1
foreach_instance +B +C add_interface 2
foreach_instance +C +D add_interface 3
foreach_instance +A +B +C +D start_routing_instance
foreach_instance +A +B add_servald_interface 1
foreach_instance +B +C add_servald_interface 2
foreach_instance +C +D add_servald_interface 3
foreach_instance +A +B +C +D start_servald_server
}
test_multihop_linear() {
wait_until path_exists +A +B +C +D
@ -480,9 +479,9 @@ setup_unicast_route() {
setup_servald
assert_no_servald_processes
foreach_instance +A +B +C +D create_single_identity
foreach_instance +A +B add_interface 1
foreach_instance +B +C add_interface 2
foreach_instance +C +D add_interface 3
foreach_instance +A +B add_servald_interface --file 1
foreach_instance +B +C add_servald_interface --file 2
foreach_instance +C +D add_servald_interface --file 3
set_instance +A
executeOk_servald config \
set interfaces.1.drop_broadcasts on
@ -490,7 +489,7 @@ setup_unicast_route() {
executeOk_servald config \
set interfaces.2.drop_broadcasts on \
set interfaces.3.drop_broadcasts on
foreach_instance +A +B +C +D start_routing_instance
foreach_instance +A +B +C +D start_servald_server
}
test_unicast_route() {
wait_until --timeout=20 path_exists +A +B +C +D
@ -504,9 +503,9 @@ setup_offline() {
setup_servald
assert_no_servald_processes
foreach_instance +A +B +C +D create_single_identity
foreach_instance +A +B +C add_interface 1
foreach_instance +A +B +D add_interface 2
foreach_instance +A +B +C +D start_routing_instance
foreach_instance +A +B +C add_servald_interface 1
foreach_instance +A +B +D add_servald_interface 2
foreach_instance +A +B +C +D start_servald_server
}
sid_offline() {
@ -543,9 +542,9 @@ setup_lose_neighbours() {
setup_servald
assert_no_servald_processes
foreach_instance +A +B +C create_single_identity
foreach_instance +A +B add_interface 1
foreach_instance +B +C add_interface 2
foreach_instance +A +B +C start_routing_instance
foreach_instance +A +B add_servald_interface 1
foreach_instance +B +C add_servald_interface 2
foreach_instance +A +B +C start_servald_server
}
test_lose_neighbours() {
wait_until path_exists +A +B +C
@ -556,45 +555,35 @@ test_lose_neighbours() {
set_instance +A
wait_until --timeout=30 instance_offline +C
start_servald_server +B
wait_until path_exists +A +B +C
wait_until path_exists +C +B +A
wait_until --timeout=20 path_exists +A +B +C
wait_until --timeout=20 path_exists +C +B +A
}
setup_multi_interface() {
setup_servald
assert_no_servald_processes
foreach_instance +A +B create_single_identity
>$SERVALD_VAR/dummywifi
>$SERVALD_VAR/dummyeth
foreach_instance +A +B \
executeOk_servald config \
set interfaces.1.file dummywifi \
set interfaces.1.dummy_address 127.0.1.$instance_number \
set interfaces.1.dummy_netmask 255.255.255.224 \
set interfaces.1.type wifi \
set interfaces.2.file dummyeth \
set interfaces.2.dummy_address 127.0.2.$instance_number \
set interfaces.2.dummy_netmask 255.255.255.224 \
set interfaces.2.type ethernet
foreach_instance +A +B start_routing_instance
foreach_instance +A +B add_servald_interface --wifi 1
foreach_instance +A +B add_servald_interface --ethernet 2
foreach_instance +A +B start_servald_server
}
doc_multi_interface="Multiple links of different types to the same neighbour"
test_multi_interface() {
set_instance +A
wait_until has_link dummyeth +A +B +B $SIDB $SIDB
wait_until has_link --interface "dummy2.*" $SIDB
set_instance +B
wait_until has_link dummyeth +B +A +A $SIDA $SIDA
wait_until has_link --interface "dummy2.*" $SIDA
set_instance +A
executeOk_servald config set interfaces.2.exclude 1
wait_until has_link dummywifi +A +B +B $SIDB $SIDB
wait_until has_link --interface "dummy1.*" $SIDB
set_instance +B
wait_until has_link dummywifi +B +A +A $SIDA $SIDA
wait_until has_link --interface "dummy1.*" $SIDA
set_instance +A
executeOk_servald config del interfaces.2.exclude
wait_until has_link dummyeth +A +B +B $SIDB $SIDB
wait_until has_link --interface "dummy2.*" $SIDB
set_instance +B
wait_until has_link dummyeth +B +A +A $SIDA $SIDA
wait_until has_link --interface "dummy2.*" $SIDA
}
# TODO assert that all packets arrive? assert that no duplicates arrive?
@ -603,11 +592,11 @@ setup_ping_unreliable() {
setup_servald
assert_no_servald_processes
foreach_instance +A +B create_single_identity
foreach_instance +A +B add_interface 1
foreach_instance +A +B add_servald_interface --file 1
foreach_instance +A +B \
executeOk_servald config \
set interfaces.1.drop_packets 40
foreach_instance +A +B start_routing_instance
foreach_instance +A +B start_servald_server
}
test_ping_unreliable() {
wait_until path_exists +A +B
@ -622,15 +611,15 @@ setup_ping_unreliable2() {
setup_servald
assert_no_servald_processes
foreach_instance +A +B +C create_single_identity
foreach_instance +A +B add_interface 1
foreach_instance +A +B add_servald_interface --file 1
foreach_instance +A +B \
executeOk_servald config \
set interfaces.1.drop_packets 40
foreach_instance +B +C add_interface 2
foreach_instance +B +C add_servald_interface --file 2
foreach_instance +B +C \
executeOk_servald config \
set interfaces.2.drop_packets 40
foreach_instance +A +B +C start_routing_instance
foreach_instance +A +B +C start_servald_server
}
test_ping_unreliable2() {
wait_until path_exists +A +B +C
@ -645,11 +634,11 @@ setup_brping_unreliable() {
setup_servald
assert_no_servald_processes
foreach_instance +A +B create_single_identity
foreach_instance +A +B add_interface 1
foreach_instance +A +B add_servald_interface --file 1
foreach_instance +A +B \
executeOk_servald config \
set interfaces.1.drop_packets 20
foreach_instance +A +B start_routing_instance
foreach_instance +A +B start_servald_server
}
test_brping_unreliable() {
wait_until path_exists +A +B
@ -664,9 +653,9 @@ setup_unreliable_links() {
setup_servald
assert_no_servald_processes
foreach_instance +A +B +C create_single_identity
foreach_instance +A +B add_interface 1
foreach_instance +B +C add_interface 2
foreach_instance +A +C add_interface 3
foreach_instance +A +B add_servald_interface --file 1
foreach_instance +B +C add_servald_interface --file 2
foreach_instance +A +C add_servald_interface --file 3
set_instance +A
executeOk_servald config \
set interfaces.1.drop_packets 5 \
@ -679,7 +668,7 @@ setup_unreliable_links() {
executeOk_servald config \
set interfaces.2.drop_packets 5 \
set interfaces.3.drop_packets 70
foreach_instance +A +B +C start_routing_instance
foreach_instance +A +B +C start_servald_server
}
test_unreliable_links() {
wait_until path_exists +A +B +C
@ -696,12 +685,12 @@ setup_unreliable_links2() {
setup_servald
assert_no_servald_processes
foreach_instance +A +B +C +D create_single_identity
foreach_instance +A +B add_interface 1
foreach_instance +A +C add_interface 2
foreach_instance +A +D add_interface 3
foreach_instance +B +C add_interface 4
foreach_instance +B +D add_interface 5
foreach_instance +C +D add_interface 6
foreach_instance +A +B add_servald_interface --file 1
foreach_instance +A +C add_servald_interface --file 2
foreach_instance +A +D add_servald_interface --file 3
foreach_instance +B +C add_servald_interface --file 4
foreach_instance +B +D add_servald_interface --file 5
foreach_instance +C +D add_servald_interface --file 6
set_instance +A
executeOk_servald config \
set interfaces.1.drop_packets 5 \
@ -722,7 +711,7 @@ setup_unreliable_links2() {
set interfaces.3.drop_packets 90 \
set interfaces.5.drop_packets 40 \
set interfaces.6.drop_packets 5
foreach_instance +A +B +C +D start_routing_instance
foreach_instance +A +B +C +D start_servald_server
}
test_unreliable_links2() {
wait_until path_exists +A +B +C +D
@ -736,15 +725,15 @@ setup_circle() {
setup_servald
assert_no_servald_processes
foreach_instance +A +B +C +D +E +F +G +H create_single_identity
foreach_instance +A +B add_interface 1
foreach_instance +B +C add_interface 2
foreach_instance +C +D add_interface 3
foreach_instance +D +E add_interface 4
foreach_instance +E +F add_interface 5
foreach_instance +F +G add_interface 6
foreach_instance +G +H add_interface 7
foreach_instance +H +A add_interface 8
foreach_instance +A +B +C +D +E +F +G +H start_routing_instance
foreach_instance +A +B add_servald_interface 1
foreach_instance +B +C add_servald_interface 2
foreach_instance +C +D add_servald_interface 3
foreach_instance +D +E add_servald_interface 4
foreach_instance +E +F add_servald_interface 5
foreach_instance +F +G add_servald_interface 6
foreach_instance +G +H add_servald_interface 7
foreach_instance +H +A add_servald_interface 8
foreach_instance +A +B +C +D +E +F +G +H start_servald_server
}
doc_circle="Circle of nodes with one going offline"
@ -756,8 +745,6 @@ test_circle() {
set_instance +A
executeOk_servald mdp ping --timeout=3 $SIDC 1
tfw_cat --stdout --stderr
executeOk_servald route print
assertStdoutGrep --matches=1 "^$SIDC:INDIRECT:"
stop_servald_server +B
foreach_instance +A +C \
wait_until --timeout=10 instance_offline +B
@ -766,8 +753,6 @@ test_circle() {
set_instance +A
executeOk_servald mdp ping --timeout=3 $SIDC 1
tfw_cat --stdout --stderr
executeOk_servald route print
assertStdoutGrep --matches=1 "^$SIDC:INDIRECT:"
}
setup_crowded_mess() {
@ -775,26 +760,25 @@ setup_crowded_mess() {
assert_no_servald_processes
# BCDE & DEFG form squares, ABC & FGH form triangles
foreach_instance +A +B +C +D +E +F +G +H create_single_identity
foreach_instance +A +B +C add_interface 1
foreach_instance +B +D add_interface 2
foreach_instance +C +E add_interface 3
foreach_instance +D +E add_interface 4
foreach_instance +D +F add_interface 5
foreach_instance +E +G add_interface 6
foreach_instance +F +G +H add_interface 7
foreach_instance +A +B +C add_servald_interface 1
foreach_instance +B +D add_servald_interface 2
foreach_instance +C +E add_servald_interface 3
foreach_instance +D +E add_servald_interface 4
foreach_instance +D +F add_servald_interface 5
foreach_instance +E +G add_servald_interface 6
foreach_instance +F +G +H add_servald_interface 7
foreach_instance +A +B +C +D +E +F +G +H \
executeOk_servald config \
set mdp.iftype.wifi.reachable_timeout_ms 60000
foreach_instance +A +B +C +D +E +F +G +H start_routing_instance
foreach_instance +A +B +C +D +E +F +G +H start_servald_server
}
doc_crowded_mess="Multiple possible paths"
test_crowded_mess() {
foreach_instance +A +H \
wait_until has_seen_instances +A +H
set_instance +H
wait_until has_link --via "[0-9A-F]*" $SIDA
set_instance +A
executeOk_servald route print
assertStdoutGrep --matches=1 "^$SIDH:INDIRECT:"
wait_until has_link --via "[0-9A-F]*" $SIDH
executeOk_servald mdp ping --timeout=3 $SIDH 1
tfw_cat --stdout --stderr
}

View File

@ -26,17 +26,17 @@ setup() {
assert_no_servald_processes
}
setup_interfaces() {
>$TFWTMP/dummy
executeOk_servald config set interfaces "+>$TFWTMP/dummy"
}
teardown() {
get_servald_server_pidfile && stop_servald_server
kill_all_servald_processes
assert_no_servald_processes
}
# make sure servald config is blank
configure_servald_server() {
:
}
doc_StartCreateInstanceDir="Starting server creates instance directory"
setup_StartCreateInstanceDir() {
setup
@ -53,10 +53,8 @@ setup_StartLogfile() {
executeOk_servald config set log.file.directory_path "$PWD/log"
}
test_StartLogfile() {
executeOk_servald start
sleep 0.1
assert [ -s log/*.log ]
tfw_cat log/*.log
start_servald_server
assert_servald_server_no_errors
}
doc_StartNoInterfaces="Starting server with no configured interfaces gives warning"
@ -70,14 +68,26 @@ test_StartNoInterfaces() {
tfw_cat "$instance_servald_log"
}
doc_StartNoErrors="Starting server on dummy interface gives no errors"
doc_StartNoErrors="Starting server on dummy file interface gives no errors"
setup_StartNoErrors() {
setup
setup_interfaces
add_servald_interface --file
}
test_StartNoErrors() {
start_servald_server
sleep 0.1
wait_until grep "Interface .* is up" $instance_servald_log
assert_servald_server_no_errors
tfw_cat "$instance_servald_log"
}
doc_StartLocalNoErrors="Starting server on local interface gives no errors"
setup_StartLocalNoErrors() {
setup
add_servald_interface
}
test_StartLocalNoErrors() {
start_servald_server
wait_until grep "Interface .* is up" $instance_servald_log
assert_servald_server_no_errors
tfw_cat "$instance_servald_log"
}
@ -85,7 +95,6 @@ test_StartNoErrors() {
doc_StartStart="Start server while already running"
setup_StartStart() {
setup
setup_interfaces
start_servald_server
}
test_StartStart() {
@ -99,7 +108,6 @@ test_StartStart() {
doc_StartStopFast="Stop server before it finishes starting"
setup_StartStopFast() {
setup
setup_interfaces
export SERVALD_SERVER_START_DELAY=250
}
test_StartStopFast() {
@ -110,7 +118,6 @@ test_StartStopFast() {
doc_NoZombie="Server process does not become a zombie"
setup_NoZombie() {
setup
setup_interfaces
export SERVALD_START_POST_SLEEP=1000
servald_start &
start_pid=$!