mirror of
https://github.com/servalproject/serval-dna.git
synced 2025-04-08 03:24:13 +00:00
Merge branch 'msp' into development
This commit is contained in:
commit
31ab78fdf2
@ -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"},
|
||||
|
@ -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);
|
||||
|
@ -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,, "")
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
54
lsif.c
@ -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);
|
||||
|
||||
|
21
mdp_client.c
21
mdp_client.c
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
674
msp_client.c
Normal 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
57
msp_client.h
Normal 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
492
msp_proxy.c
Normal 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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
146
overlay_interface.h
Normal 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
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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"
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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){
|
||||
|
61
route_link.c
61
route_link.c
@ -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
199
serval.h
@ -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);
|
||||
|
12
server.c
12
server.c
@ -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();
|
||||
|
@ -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++;
|
||||
}
|
20
socket.c
20
socket.c
@ -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;
|
||||
}
|
||||
|
1
socket.h
1
socket.h
@ -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))
|
||||
|
@ -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 \
|
||||
|
54
testdefs.sh
54
testdefs.sh
@ -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
|
||||
}
|
||||
|
||||
|
@ -25,6 +25,7 @@ includeTests config
|
||||
includeTests keyring
|
||||
includeTests server
|
||||
includeTests routing
|
||||
includeTests msp
|
||||
includeTests dnahelper
|
||||
includeTests dnaprotocol
|
||||
includeTests rhizomeops
|
||||
|
@ -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 \
|
||||
|
@ -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 \
|
||||
|
@ -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
201
tests/msp
Executable 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 "$@"
|
@ -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 \
|
||||
|
@ -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
|
||||
|
@ -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 \
|
||||
|
312
tests/routing
312
tests/routing
@ -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
|
||||
}
|
||||
|
37
tests/server
37
tests/server
@ -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=$!
|
||||
|
Loading…
x
Reference in New Issue
Block a user