mirror of
https://github.com/servalproject/serval-dna.git
synced 2024-12-19 21:27:57 +00:00
Add support for mdp clients to provide a link layer packet transport
This commit is contained in:
parent
3ae0e95e0b
commit
a9b9f51a9f
@ -760,6 +760,10 @@ int cf_opt_socket_type(short *typep, const char *text)
|
||||
*typep = SOCK_FILE;
|
||||
return CFOK;
|
||||
}
|
||||
if (strcasecmp(text, "external") == 0) {
|
||||
*typep = SOCK_EXT;
|
||||
return CFOK;
|
||||
}
|
||||
return CFINVALID;
|
||||
}
|
||||
|
||||
@ -1018,7 +1022,7 @@ 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]){
|
||||
if (nifp->socket_type != SOCK_DGRAM && nifp->socket_type != SOCK_EXT && !nifp->file[0]){
|
||||
cf_warn_missing_node(parent, "file");
|
||||
return result | CFSUB(CFINCOMPATIBLE);
|
||||
}
|
||||
|
@ -184,6 +184,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
// force state packet interval
|
||||
#define VOMP_CALL_STATUS_INTERVAL 1000
|
||||
|
||||
// mdp client interface
|
||||
#define SOCK_EXT 0xFE
|
||||
// dummy file interface
|
||||
#define SOCK_FILE 0xFF
|
||||
#define SOCK_UNSPECIFIED 0
|
||||
|
||||
|
@ -24,12 +24,13 @@ import java.lang.StringBuilder;
|
||||
|
||||
public class Base64 {
|
||||
|
||||
public static final char[] SYMBOLS = {
|
||||
'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
|
||||
'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
|
||||
'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
|
||||
'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/',
|
||||
'='
|
||||
public static final char[] SYMBOLS;
|
||||
public static final String charSet="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
static{
|
||||
char chars[] = new char[64];
|
||||
for (int i=0;i<chars.length;i++)
|
||||
chars[i]=charSet.charAt(i);
|
||||
SYMBOLS=chars;
|
||||
};
|
||||
|
||||
public static String encode(byte[] binary)
|
||||
@ -38,20 +39,19 @@ public class Base64 {
|
||||
int place = 0;
|
||||
byte buf = 0;
|
||||
for (byte b: binary) {
|
||||
switch (place) {
|
||||
int val = b&0xFF;
|
||||
switch (place++) {
|
||||
case 0:
|
||||
sb.append(SYMBOLS[b >>> 2]);
|
||||
buf = (byte)((b << 4) & 0x3f);
|
||||
place = 1;
|
||||
sb.append(SYMBOLS[val >>> 2]);
|
||||
buf = (byte)((val << 4) & 0x3f);
|
||||
break;
|
||||
case 1:
|
||||
sb.append(SYMBOLS[(b >>> 4) | buf]);
|
||||
buf = (byte)((b << 2) & 0x3f);
|
||||
place = 2;
|
||||
sb.append(SYMBOLS[(val >>> 4) | buf]);
|
||||
buf = (byte)((val << 2) & 0x3f);
|
||||
break;
|
||||
case 2:
|
||||
sb.append(SYMBOLS[(b >>> 6) | buf]);
|
||||
sb.append(SYMBOLS[b & 0x3f]);
|
||||
sb.append(SYMBOLS[(val >>> 6) | buf]);
|
||||
sb.append(SYMBOLS[val & 0x3f]);
|
||||
place = 0;
|
||||
break;
|
||||
}
|
||||
@ -60,11 +60,47 @@ public class Base64 {
|
||||
sb.append(SYMBOLS[buf]);
|
||||
switch (place) {
|
||||
case 1:
|
||||
sb.append(SYMBOLS[64]);
|
||||
sb.append('=');
|
||||
case 2:
|
||||
sb.append(SYMBOLS[64]);
|
||||
sb.append('=');
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static byte[] decode(String value)
|
||||
{
|
||||
int len = value.length()/4 * 3;
|
||||
if (value.endsWith("=="))
|
||||
len -=2;
|
||||
else if(value.endsWith("="))
|
||||
len --;
|
||||
byte ret[] = new byte[len];
|
||||
int pos=0;
|
||||
for (int i=0;i<value.length();i++){
|
||||
if (value.charAt(i)=='=')
|
||||
break;
|
||||
int val = charSet.indexOf(value.charAt(i));
|
||||
if (val<0)
|
||||
return null;
|
||||
switch(i%4){
|
||||
case 0:
|
||||
ret[pos] = (byte) (val<<2);
|
||||
break;
|
||||
case 1:
|
||||
ret[pos++] |= (byte) ((val>>4)&0x03);
|
||||
if (pos>=ret.length) break;
|
||||
ret[pos] = (byte) (val<<4);
|
||||
break;
|
||||
case 2:
|
||||
ret[pos++] |= (byte) ((val>>2)&0x0F);
|
||||
if (pos>=ret.length) break;
|
||||
ret[pos] = (byte) (val<<6);
|
||||
break;
|
||||
case 3:
|
||||
ret[pos++] |= (byte) (val & 0x3f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,97 @@
|
||||
package org.servalproject.servaldna;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.DatagramChannel;
|
||||
import java.nio.channels.SelectableChannel;
|
||||
import java.nio.channels.SelectionKey;
|
||||
|
||||
/**
|
||||
* Created by jeremy on 8/05/14.
|
||||
*/
|
||||
public abstract class AbstractExternalInterface extends ChannelSelector.Handler {
|
||||
private final ChannelSelector selector;
|
||||
protected final MdpSocket socket;
|
||||
|
||||
public AbstractExternalInterface(ChannelSelector selector, int loopbackMdpPort) throws IOException {
|
||||
this.socket = new MdpSocket(loopbackMdpPort);
|
||||
|
||||
this.selector = selector;
|
||||
selector.register(this);
|
||||
}
|
||||
|
||||
public void close(){
|
||||
try {
|
||||
selector.unregister(this);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
socket.close();
|
||||
}
|
||||
|
||||
private static final int MDP_INTERFACE=4;
|
||||
private static final int MDP_INTERFACE_UP=0;
|
||||
private static final int MDP_INTERFACE_DOWN=1;
|
||||
private static final int MDP_INTERFACE_RECV=2;
|
||||
|
||||
public void up(String config) throws IOException {
|
||||
MdpPacket packet = new MdpPacket();
|
||||
packet.setRemotePort(MDP_INTERFACE);
|
||||
packet.payload.put((byte) MDP_INTERFACE_UP);
|
||||
packet.payload.put(config.getBytes());
|
||||
packet.payload.flip();
|
||||
packet.send((DatagramChannel)socket.getChannel());
|
||||
}
|
||||
|
||||
public void down() throws IOException {
|
||||
MdpPacket packet = new MdpPacket();
|
||||
packet.setRemotePort(MDP_INTERFACE);
|
||||
packet.payload.put((byte) MDP_INTERFACE_DOWN);
|
||||
packet.payload.flip();
|
||||
packet.send((DatagramChannel) socket.getChannel());
|
||||
}
|
||||
|
||||
public void receivedPacket(byte recvaddr[], byte recvbytes[]) throws IOException {
|
||||
receivedPacket(recvaddr, recvbytes, 0, recvbytes==null?0:recvbytes.length);
|
||||
}
|
||||
public void receivedPacket(byte recvaddr[], byte recvbytes[], int offset, int len) throws IOException {
|
||||
MdpPacket packet = new MdpPacket();
|
||||
packet.setRemotePort(MDP_INTERFACE);
|
||||
packet.payload.put((byte) MDP_INTERFACE_RECV);
|
||||
packet.payload.put((byte) recvaddr.length);
|
||||
packet.payload.put(recvaddr);
|
||||
if (len>0)
|
||||
packet.payload.put(recvbytes, offset, len);
|
||||
packet.payload.flip();
|
||||
packet.send((DatagramChannel) socket.getChannel());
|
||||
}
|
||||
|
||||
protected abstract void sendPacket(byte addr[], ByteBuffer payload);
|
||||
|
||||
@Override
|
||||
public void read() {
|
||||
try {
|
||||
MdpPacket response = new MdpPacket();
|
||||
socket.receive(response);
|
||||
int addrlen = response.payload.get() & 0xFF;
|
||||
byte addr[]=null;
|
||||
if (addrlen>0) {
|
||||
addr = new byte[addrlen];
|
||||
response.payload.get(addr);
|
||||
}
|
||||
sendPacket(addr, response.payload);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SelectableChannel getChannel() throws IOException {
|
||||
return socket.getChannel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInterest() {
|
||||
return SelectionKey.OP_READ;
|
||||
}
|
||||
}
|
11
mdp_client.h
11
mdp_client.h
@ -89,6 +89,17 @@ struct mdp_identity_request {
|
||||
*/
|
||||
#define MDP_SYNC_CONFIG 3
|
||||
|
||||
/* External interface implementation
|
||||
*
|
||||
* Messages used for talking to a client application that implements a network
|
||||
* interface that isn't based on simple file descriptors
|
||||
* eg android bluetooth & wifi-direct
|
||||
*/
|
||||
#define MDP_INTERFACE 4
|
||||
#define MDP_INTERFACE_UP 0
|
||||
#define MDP_INTERFACE_DOWN 1
|
||||
#define MDP_INTERFACE_RECV 2
|
||||
|
||||
struct overlay_route_record{
|
||||
sid_t sid;
|
||||
char interface_name[256];
|
||||
|
@ -59,22 +59,27 @@ struct profile_total sock_any_stats;
|
||||
|
||||
static void overlay_interface_poll(struct sched_ent *alarm);
|
||||
|
||||
static void
|
||||
overlay_interface_close(overlay_interface *interface){
|
||||
void overlay_interface_close(overlay_interface *interface)
|
||||
{
|
||||
if (interface->alarm.poll.fd>=0){
|
||||
if (interface->address.addr.sa_family == AF_UNIX)
|
||||
unlink(interface->address.local.sun_path);
|
||||
if (is_watching(&interface->alarm))
|
||||
unwatch(&interface->alarm);
|
||||
close(interface->alarm.poll.fd);
|
||||
interface->alarm.poll.fd=-1;
|
||||
}
|
||||
|
||||
unschedule(&interface->alarm);
|
||||
if (interface->radio_link_state)
|
||||
radio_link_free(interface);
|
||||
interface->state=INTERFACE_STATE_DOWN;
|
||||
|
||||
monitor_tell_formatted(MONITOR_INTERFACE, "\nINTERFACE:%s:DOWN\n", interface->name);
|
||||
INFOF("Interface %s addr %s is down",
|
||||
interface->name, alloca_socket_address(&interface->address));
|
||||
if (interface->address.addr.sa_family == AF_UNIX)
|
||||
unlink(interface->address.local.sun_path);
|
||||
|
||||
link_interface_down(interface);
|
||||
unschedule(&interface->alarm);
|
||||
if (is_watching(&interface->alarm))
|
||||
unwatch(&interface->alarm);
|
||||
close(interface->alarm.poll.fd);
|
||||
if (interface->radio_link_state)
|
||||
radio_link_free(interface);
|
||||
interface->alarm.poll.fd=-1;
|
||||
interface->state=INTERFACE_STATE_DOWN;
|
||||
}
|
||||
|
||||
void overlay_interface_close_all()
|
||||
@ -134,6 +139,12 @@ void interface_state_html(struct strbuf *b, struct overlay_interface *interface)
|
||||
case SOCK_FILE:
|
||||
strbuf_puts(b, "Socket: File<br>");
|
||||
break;
|
||||
case SOCK_EXT:
|
||||
{
|
||||
strbuf_puts(b, "Socket: External<br>");
|
||||
strbuf_sprintf(b, "Client: %s<br>", alloca_socket_address(&interface->address));
|
||||
}
|
||||
break;
|
||||
}
|
||||
strbuf_sprintf(b, "TX: %d<br>", interface->tx_count);
|
||||
strbuf_sprintf(b, "RX: %d<br>", interface->recv_count);
|
||||
@ -268,6 +279,22 @@ overlay_interface * overlay_interface_find_name(const char *name){
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// find an interface by name and address
|
||||
overlay_interface * overlay_interface_find_name_addr(const char *name, struct socket_address *addr){
|
||||
int i;
|
||||
for(i = 0; i < OVERLAY_MAX_INTERFACES; i++){
|
||||
if (overlay_interfaces[i].state==INTERFACE_STATE_DOWN)
|
||||
continue;
|
||||
|
||||
if (cmp_sockaddr(addr, &overlay_interfaces[i].address)==0
|
||||
&& (!name || strcasecmp(overlay_interfaces[i].name, name)==0)){
|
||||
return &overlay_interfaces[i];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int interface_type_priority(int type)
|
||||
{
|
||||
switch(type){
|
||||
@ -405,61 +432,28 @@ overlay_interface_init_socket(overlay_interface *interface)
|
||||
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 socket_address *addr,
|
||||
struct socket_address *netmask,
|
||||
struct socket_address *broadcast,
|
||||
const struct config_network_interface *ifconfig)
|
||||
int overlay_interface_configure(struct overlay_interface *interface, const struct config_network_interface *ifconfig)
|
||||
{
|
||||
int cleanup_ret = -1;
|
||||
|
||||
int interface_id=-1;
|
||||
int i;
|
||||
for (i=0; i<OVERLAY_MAX_INTERFACES; i++){
|
||||
if (overlay_interfaces[i].state==INTERFACE_STATE_DOWN){
|
||||
interface_id=i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (interface_id==-1)
|
||||
return WHY("Too many interfaces -- Increase OVERLAY_MAX_INTERFACES");
|
||||
|
||||
overlay_interface *const interface = &overlay_interfaces[interface_id];
|
||||
bzero(interface, sizeof(overlay_interface));
|
||||
interface->state=INTERFACE_STATE_DOWN;
|
||||
|
||||
strncpy(interface->name, name, sizeof interface->name);
|
||||
|
||||
// copy ifconfig values
|
||||
interface->drop_broadcasts = ifconfig->drop_broadcasts;
|
||||
interface->drop_unicasts = ifconfig->drop_unicasts;
|
||||
interface->drop_packets = ifconfig->drop_packets;
|
||||
interface->port = ifconfig->port;
|
||||
interface->type = ifconfig->type;
|
||||
interface->send_broadcasts = ifconfig->send_broadcasts;
|
||||
interface->dont_route = ifconfig->dont_route;
|
||||
interface->prefer_unicast = ifconfig->prefer_unicast;
|
||||
interface->default_route = ifconfig->default_route;
|
||||
interface->destination->encapsulation = ifconfig->encapsulation;
|
||||
interface->port = ifconfig->port;
|
||||
interface->socket_type = ifconfig->socket_type;
|
||||
interface->uartbps = ifconfig->uartbps;
|
||||
interface->ctsrts = ifconfig->ctsrts;
|
||||
set_destination_ref(&interface->destination, NULL);
|
||||
interface->destination = new_destination(interface, ifconfig->encapsulation);
|
||||
interface->point_to_point = ifconfig->point_to_point;
|
||||
interface->debug = ifconfig->debug;
|
||||
|
||||
/* Pick a reasonable default MTU.
|
||||
This will ultimately get tuned by the bandwidth and other properties of the interface */
|
||||
interface->mtu = 1200;
|
||||
interface->point_to_point = ifconfig->point_to_point;
|
||||
|
||||
interface->alarm.poll.fd=0;
|
||||
interface->debug = ifconfig->debug;
|
||||
interface->tx_count=0;
|
||||
interface->recv_count=0;
|
||||
|
||||
// How often do we announce ourselves on this interface?
|
||||
int tick_ms=-1;
|
||||
int packet_interval=-1;
|
||||
@ -505,72 +499,125 @@ overlay_interface_init(const char *name, struct socket_address *addr,
|
||||
reachable_timeout_ms = ifconfig->mdp.reachable_timeout_ms;
|
||||
|
||||
if (packet_interval<0)
|
||||
return WHYF("Invalid packet interval %d specified for interface %s", packet_interval, name);
|
||||
return WHYF("Invalid packet interval %d specified for interface %s", packet_interval, interface->name);
|
||||
if (packet_interval==0){
|
||||
INFOF("Interface %s is not sending any traffic!", name);
|
||||
INFOF("Interface %s is not sending any traffic!", interface->name);
|
||||
tick_ms=0;
|
||||
}else if (!interface->send_broadcasts){
|
||||
INFOF("Interface %s is not sending any broadcast traffic!", name);
|
||||
INFOF("Interface %s is not sending any broadcast traffic!", interface->name);
|
||||
}else if (tick_ms==0)
|
||||
INFOF("Interface %s is running tickless", name);
|
||||
INFOF("Interface %s is running tickless", interface->name);
|
||||
|
||||
if (tick_ms<0)
|
||||
return WHYF("No tick interval specified for interface %s", name);
|
||||
return WHYF("No tick interval specified for interface %s", interface->name);
|
||||
|
||||
interface->destination->tick_ms = tick_ms;
|
||||
interface->destination->reachable_timeout_ms = reachable_timeout_ms >= 0 ? reachable_timeout_ms : tick_ms > 0 ? tick_ms * 5 : 2500;
|
||||
|
||||
limit_init(&interface->destination->transfer_limit, packet_interval);
|
||||
|
||||
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).
|
||||
*/
|
||||
int
|
||||
overlay_interface_init(const char *name, struct socket_address *addr,
|
||||
struct socket_address *netmask,
|
||||
struct socket_address *broadcast,
|
||||
const struct config_network_interface *ifconfig)
|
||||
{
|
||||
int cleanup_ret = -1;
|
||||
|
||||
int interface_id=-1;
|
||||
int i;
|
||||
for (i=0; i<OVERLAY_MAX_INTERFACES; i++){
|
||||
if (overlay_interfaces[i].state==INTERFACE_STATE_DOWN){
|
||||
interface_id=i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (interface_id==-1)
|
||||
return WHY("Too many interfaces -- Increase OVERLAY_MAX_INTERFACES");
|
||||
|
||||
overlay_interface *const interface = &overlay_interfaces[interface_id];
|
||||
|
||||
bzero(interface, sizeof(overlay_interface));
|
||||
interface->state=INTERFACE_STATE_DOWN;
|
||||
|
||||
strncpy(interface->name, name, sizeof interface->name);
|
||||
|
||||
set_destination_ref(&interface->destination, NULL);
|
||||
interface->destination = new_destination(interface);
|
||||
|
||||
if (overlay_interface_configure(interface, ifconfig)==-1)
|
||||
return -1;
|
||||
|
||||
interface->alarm.poll.fd=0;
|
||||
interface->tx_count=0;
|
||||
interface->recv_count=0;
|
||||
|
||||
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){
|
||||
if (ifconfig->drop_broadcasts || ifconfig->drop_unicasts || ifconfig->drop_packets)
|
||||
FATALF("Invalid interface definition. We only support dropping packets on dummy file interfaces");
|
||||
if (netmask)
|
||||
interface->netmask = netmask->inet.sin_addr;
|
||||
else
|
||||
interface->netmask = ifconfig->dummy_netmask;
|
||||
interface->local_echo = 1;
|
||||
|
||||
if (overlay_interface_init_socket(interface))
|
||||
return WHY("overlay_interface_init_socket() failed");
|
||||
}else{
|
||||
char read_file[1024];
|
||||
interface->local_echo = interface->point_to_point?0:1;
|
||||
if (!FORMF_SERVAL_TMP_PATH(read_file, "%s/%s", config.server.interface_path, ifconfig->file))
|
||||
return -1;
|
||||
if ((interface->alarm.poll.fd = open(read_file, O_APPEND|O_RDWR)) == -1) {
|
||||
if (errno == ENOENT && ifconfig->socket_type == SOCK_FILE) {
|
||||
cleanup_ret = 1;
|
||||
WARNF("dummy interface not enabled: %s does not exist", alloca_str_toprint(read_file));
|
||||
} else {
|
||||
cleanup_ret = WHYF_perror("file interface not enabled: open(%s, O_APPEND|O_RDWR)", alloca_str_toprint(read_file));
|
||||
}
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (ifconfig->type==OVERLAY_INTERFACE_PACKETRADIO)
|
||||
overlay_packetradio_setup_port(interface);
|
||||
|
||||
switch (ifconfig->socket_type) {
|
||||
switch(ifconfig->socket_type){
|
||||
case SOCK_DGRAM:
|
||||
if (ifconfig->drop_broadcasts || ifconfig->drop_unicasts || ifconfig->drop_packets)
|
||||
FATALF("Invalid interface definition. We only support dropping packets on dummy file interfaces");
|
||||
if (netmask)
|
||||
interface->netmask = netmask->inet.sin_addr;
|
||||
else
|
||||
interface->netmask = ifconfig->dummy_netmask;
|
||||
interface->local_echo = 1;
|
||||
|
||||
if (overlay_interface_init_socket(interface))
|
||||
return WHY("overlay_interface_init_socket() failed");
|
||||
break;
|
||||
|
||||
case SOCK_EXT:
|
||||
interface->local_echo = 0;
|
||||
interface->alarm.poll.fd = -1;
|
||||
break;
|
||||
|
||||
case SOCK_STREAM:
|
||||
radio_link_init(interface);
|
||||
interface->alarm.poll.events=POLLIN|POLLOUT;
|
||||
watch(&interface->alarm);
|
||||
|
||||
break;
|
||||
case SOCK_FILE:
|
||||
/* Seek to end of file as initial reading point */
|
||||
interface->recv_offset = lseek(interface->alarm.poll.fd,0,SEEK_END);
|
||||
break;
|
||||
{
|
||||
char read_file[1024];
|
||||
interface->local_echo = interface->point_to_point?0:1;
|
||||
if (!FORMF_SERVAL_TMP_PATH(read_file, "%s/%s", config.server.interface_path, ifconfig->file))
|
||||
return -1;
|
||||
if ((interface->alarm.poll.fd = open(read_file, O_APPEND|O_RDWR)) == -1) {
|
||||
if (errno == ENOENT && ifconfig->socket_type == SOCK_FILE) {
|
||||
cleanup_ret = 1;
|
||||
WARNF("dummy interface not enabled: %s does not exist", alloca_str_toprint(read_file));
|
||||
} else {
|
||||
cleanup_ret = WHYF_perror("file interface not enabled: open(%s, O_APPEND|O_RDWR)", alloca_str_toprint(read_file));
|
||||
}
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (ifconfig->type==OVERLAY_INTERFACE_PACKETRADIO)
|
||||
overlay_packetradio_setup_port(interface);
|
||||
|
||||
switch (ifconfig->socket_type) {
|
||||
case SOCK_STREAM:
|
||||
radio_link_init(interface);
|
||||
interface->alarm.poll.events=POLLIN|POLLOUT;
|
||||
watch(&interface->alarm);
|
||||
break;
|
||||
|
||||
case SOCK_FILE:
|
||||
/* Seek to end of file as initial reading point */
|
||||
interface->recv_offset = lseek(interface->alarm.poll.fd,0,SEEK_END);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -786,6 +833,7 @@ static void overlay_interface_poll(struct sched_ent *alarm)
|
||||
radio_link_tx(interface);
|
||||
return;
|
||||
case SOCK_DGRAM:
|
||||
case SOCK_EXT:
|
||||
break;
|
||||
case SOCK_FILE:
|
||||
interface_read_file(interface);
|
||||
@ -808,6 +856,7 @@ static void overlay_interface_poll(struct sched_ent *alarm)
|
||||
case SOCK_STREAM:
|
||||
radio_link_tx(interface);
|
||||
return;
|
||||
case SOCK_EXT:
|
||||
case SOCK_DGRAM:
|
||||
case SOCK_FILE:
|
||||
//XXX error? fatal?
|
||||
@ -831,6 +880,8 @@ static void overlay_interface_poll(struct sched_ent *alarm)
|
||||
case SOCK_FILE:
|
||||
interface_read_file(interface);
|
||||
break;
|
||||
case SOCK_EXT:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -903,9 +954,11 @@ int overlay_broadcast_ensemble(struct network_destination *destination, struct o
|
||||
return WHYF("Cannot send to interface %s as it is down", interface->name);
|
||||
}
|
||||
|
||||
if (interface->debug)
|
||||
DEBUGF("Sending on %s, len %zu: %s", interface->name, len, alloca_tohex(bytes, len>64?64:len));
|
||||
|
||||
if (config.debug.overlayinterfaces || interface->debug)
|
||||
DEBUGF("Sending %zu byte overlay frame on %s to %s [%s]",
|
||||
(size_t)len, interface->name, alloca_socket_address(&destination->address),
|
||||
alloca_tohex(bytes, len>64?64:len));
|
||||
|
||||
interface->tx_count++;
|
||||
|
||||
switch(interface->socket_type){
|
||||
@ -960,13 +1013,14 @@ int overlay_broadcast_ensemble(struct network_destination *destination, struct o
|
||||
return WHYF("only wrote %d of %d bytes", (int)nwrite, (int)sizeof(packet));
|
||||
return 0;
|
||||
}
|
||||
|
||||
case SOCK_EXT:
|
||||
{
|
||||
mdp_send_external_packet(interface, &destination->address, bytes, (size_t)len);
|
||||
ob_free(buffer);
|
||||
return 0;
|
||||
}
|
||||
case SOCK_DGRAM:
|
||||
{
|
||||
if (config.debug.overlayinterfaces)
|
||||
DEBUGF("Sending %zu byte overlay frame on %s to %s",
|
||||
(size_t)len, interface->name, alloca_socket_address(&destination->address));
|
||||
|
||||
set_nonblock(interface->alarm.poll.fd);
|
||||
if (destination->address.addr.sa_family == AF_UNIX
|
||||
&& !destination->unicast){
|
||||
@ -1051,20 +1105,12 @@ overlay_interface_register(char *name,
|
||||
DEBUGF("%s broadcast address: %s", name, alloca_socket_address(broadcast));
|
||||
}
|
||||
|
||||
/* Search in the exist list of interfaces */
|
||||
for(i = 0; i < OVERLAY_MAX_INTERFACES; i++){
|
||||
if (overlay_interfaces[i].state==INTERFACE_STATE_DOWN)
|
||||
continue;
|
||||
|
||||
if (strcasecmp(overlay_interfaces[i].name, name)==0
|
||||
&& cmp_sockaddr(addr, &overlay_interfaces[i].address)==0){
|
||||
|
||||
// mark this interface as still alive
|
||||
if (overlay_interfaces[i].state==INTERFACE_STATE_DETECTING)
|
||||
overlay_interfaces[i].state=INTERFACE_STATE_UP;
|
||||
|
||||
return 0;
|
||||
}
|
||||
struct overlay_interface *interface = overlay_interface_find_name_addr(name, addr);
|
||||
if (interface){
|
||||
// mark this interface as still alive
|
||||
if (interface->state == INTERFACE_STATE_DETECTING)
|
||||
interface->state = INTERFACE_STATE_UP;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* New interface, so register it */
|
||||
@ -1135,6 +1181,9 @@ void overlay_interface_discover(struct sched_ent *alarm)
|
||||
case SOCK_STREAM:
|
||||
overlay_interface_init(ifconfig->file, &addr, NULL, &broadcast, ifconfig);
|
||||
break;
|
||||
case SOCK_EXT:
|
||||
// FAIL?
|
||||
break;
|
||||
case SOCK_DGRAM:
|
||||
{
|
||||
// use a local dgram socket
|
||||
|
@ -143,7 +143,7 @@ typedef struct overlay_interface {
|
||||
*/
|
||||
extern overlay_interface overlay_interfaces[OVERLAY_MAX_INTERFACES];
|
||||
|
||||
struct network_destination * new_destination(struct overlay_interface *interface, char encapsulation);
|
||||
struct network_destination * new_destination(struct overlay_interface *interface);
|
||||
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);
|
||||
@ -151,6 +151,15 @@ int set_destination_ref(struct network_destination **ptr, struct network_destina
|
||||
|
||||
DECLARE_ALARM(overlay_interface_discover);
|
||||
|
||||
struct config_network_interface;
|
||||
int overlay_interface_configure(struct overlay_interface *interface, const struct config_network_interface *ifconfig);
|
||||
int
|
||||
overlay_interface_init(const char *name, struct socket_address *addr,
|
||||
struct socket_address *netmask,
|
||||
struct socket_address *broadcast,
|
||||
const struct config_network_interface *ifconfig);
|
||||
void overlay_interface_close(overlay_interface *interface);
|
||||
|
||||
int overlay_interface_register(char *name,
|
||||
struct socket_address *addr,
|
||||
struct socket_address *netmask,
|
||||
@ -159,6 +168,7 @@ 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);
|
||||
overlay_interface * overlay_interface_find_name_addr(const char *name, struct socket_address *addr);
|
||||
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);
|
||||
|
111
overlay_mdp.c
111
overlay_mdp.c
@ -1110,7 +1110,7 @@ static int search_subscribers(struct subscriber *subscriber, void *context){
|
||||
return 0;
|
||||
}
|
||||
|
||||
int overlay_mdp_address_list(struct overlay_mdp_addrlist *request, struct overlay_mdp_addrlist *response)
|
||||
static int overlay_mdp_address_list(struct overlay_mdp_addrlist *request, struct overlay_mdp_addrlist *response)
|
||||
{
|
||||
if (config.debug.mdprequests)
|
||||
DEBUGF("MDP_GETADDRS first_sid=%u mode=%d", request->first_sid, request->mode);
|
||||
@ -1340,6 +1340,110 @@ static int mdp_search_identities(struct socket_address *client, struct mdp_heade
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *external_name="ext"; // TODO?
|
||||
|
||||
int mdp_send_external_packet(struct overlay_interface *interface, struct socket_address *address, const uint8_t *payload, size_t len)
|
||||
{
|
||||
struct mdp_header header;
|
||||
bzero(&header, sizeof header);
|
||||
header.remote.port = MDP_INTERFACE;
|
||||
uint8_t addrlen = address->addrlen;
|
||||
|
||||
struct iovec iov[]={
|
||||
{
|
||||
.iov_base = (void *)&header,
|
||||
.iov_len = sizeof(struct mdp_header)
|
||||
},
|
||||
{
|
||||
.iov_base = (void *)&addrlen,
|
||||
.iov_len = sizeof addrlen
|
||||
},
|
||||
{
|
||||
.iov_base = (void *)&address->raw,
|
||||
.iov_len = addrlen
|
||||
},
|
||||
{
|
||||
.iov_base = (void *)payload,
|
||||
.iov_len = len
|
||||
}
|
||||
};
|
||||
|
||||
struct msghdr hdr={
|
||||
.msg_name=&interface->address.addr,
|
||||
.msg_namelen=interface->address.addrlen,
|
||||
.msg_iov=iov,
|
||||
.msg_iovlen=4,
|
||||
};
|
||||
|
||||
int fd=-1;
|
||||
switch(interface->address.addr.sa_family){
|
||||
case AF_UNIX:
|
||||
fd = mdp_sock2.poll.fd;
|
||||
break;
|
||||
case AF_INET:
|
||||
fd = mdp_sock2_inet.poll.fd;
|
||||
break;
|
||||
}
|
||||
if (fd==-1)
|
||||
return WHYF("Unhandled client family %d", interface->address.addr.sa_family);
|
||||
|
||||
if (sendmsg(fd, &hdr, 0)<0)
|
||||
return WHY_perror("sendmsg");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mdp_interface_packet(struct socket_address *client, struct mdp_header *UNUSED(header),
|
||||
struct overlay_buffer *payload){
|
||||
int msg_type = ob_get(payload);
|
||||
switch (msg_type){
|
||||
case MDP_INTERFACE_UP:{
|
||||
struct config_network_interface ifconfig;
|
||||
cf_dfl_config_network_interface(&ifconfig);
|
||||
|
||||
struct cf_om_node *conf_node = NULL;
|
||||
int result = cf_om_parse(external_name, (char*)ob_current_ptr(payload), ob_remaining(payload), &conf_node);
|
||||
if (result == CFOK || result == CFEMPTY){
|
||||
result = conf_node ? cf_opt_config_network_interface(&ifconfig, conf_node) : CFEMPTY;
|
||||
}
|
||||
|
||||
if (result == CFOK || result == CFEMPTY){
|
||||
if (ifconfig.socket_type != SOCK_EXT){
|
||||
// TODO log nice warning, pick right result code
|
||||
result |= CFSUB(CFUNSUPPORTED);
|
||||
}
|
||||
}
|
||||
|
||||
if (result == CFOK || result == CFEMPTY){
|
||||
struct overlay_interface *interface=overlay_interface_find_name_addr(external_name, client);
|
||||
if (!interface){
|
||||
overlay_interface_init(external_name, client, NULL, NULL, &ifconfig);
|
||||
}else{
|
||||
if (overlay_interface_configure(interface, &ifconfig)==-1)
|
||||
overlay_interface_close(interface);
|
||||
}
|
||||
}
|
||||
}break;
|
||||
case MDP_INTERFACE_DOWN:{
|
||||
struct overlay_interface *interface=overlay_interface_find_name_addr(external_name, client);
|
||||
if (interface)
|
||||
overlay_interface_close(interface);
|
||||
}break;
|
||||
case MDP_INTERFACE_RECV:{
|
||||
struct overlay_interface *interface=overlay_interface_find_name_addr(external_name, client);
|
||||
if (interface){
|
||||
struct socket_address addr;
|
||||
addr.addrlen = ob_get(payload);
|
||||
if (addr.addrlen > sizeof(addr))
|
||||
break; // TODO errors
|
||||
bcopy(ob_get_bytes_ptr(payload, addr.addrlen), addr.raw, addr.addrlen);
|
||||
packetOkOverlay(interface, ob_current_ptr(payload), ob_remaining(payload), &addr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void mdp_process_packet(struct socket_address *client, struct mdp_header *header,
|
||||
struct overlay_buffer *payload)
|
||||
{
|
||||
@ -1485,6 +1589,11 @@ static void mdp_process_packet(struct socket_address *client, struct mdp_header
|
||||
server_config_reload(NULL);
|
||||
mdp_reply_ok(client, header);
|
||||
break;
|
||||
case MDP_INTERFACE:
|
||||
if (config.debug.mdprequests)
|
||||
DEBUGF("Processing MDP_INTERFACE from %s", alloca_socket_address(client));
|
||||
mdp_interface_packet(client, header, payload);
|
||||
break;
|
||||
default:
|
||||
WHYF("Unknown command port %d", header->remote.port);
|
||||
mdp_reply_error(client, header);
|
||||
|
@ -172,12 +172,11 @@ static int neighbour_find_best_link(struct neighbour *n);
|
||||
struct neighbour *neighbours=NULL;
|
||||
int route_version=0;
|
||||
|
||||
struct network_destination * new_destination(struct overlay_interface *interface, char encapsulation){
|
||||
struct network_destination * new_destination(struct overlay_interface *interface){
|
||||
assert(interface);
|
||||
struct network_destination *ret = emalloc_zero(sizeof(struct network_destination));
|
||||
if (ret){
|
||||
ret->_ref_count=1;
|
||||
ret->encapsulation = encapsulation;
|
||||
ret->interface = interface;
|
||||
ret->resend_delay = 1000;
|
||||
ret->last_tx = TIME_MS_NEVER_HAS;
|
||||
@ -201,8 +200,9 @@ struct network_destination * create_unicast_destination(struct socket_address *a
|
||||
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);
|
||||
struct network_destination *ret = new_destination(interface);
|
||||
if (ret){
|
||||
ret->encapsulation = ENCAP_OVERLAY;
|
||||
ret->address = *addr;
|
||||
ret->unicast = 1;
|
||||
ret->tick_ms = interface->destination->tick_ms;
|
||||
|
1
serval.h
1
serval.h
@ -174,6 +174,7 @@ struct overlay_frame;
|
||||
struct broadcast;
|
||||
|
||||
void overlay_mdp_clean_socket_files();
|
||||
int mdp_send_external_packet(struct overlay_interface *interface, struct socket_address *address, const uint8_t *payload, size_t len);
|
||||
|
||||
int overlay_forward_payload(struct overlay_frame *f);
|
||||
int packetOkOverlay(struct overlay_interface *interface,unsigned char *packet, size_t len,
|
||||
|
Loading…
Reference in New Issue
Block a user