/* vim: set expandtab ts=4 sw=4: */
/*
* You may redistribute this program and/or modify it under the terms of
* the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#ifndef InterfaceController_H
#define InterfaceController_H
#include "benc/String.h"
#include "crypto/CryptoAuth.h"
#include "dht/Address.h"
#include "interface/Iface.h"
#include "memory/Allocator.h"
#include "switch/SwitchCore.h"
#include "net/SwitchPinger.h"
#include "net/EventEmitter.h"
#include "util/platform/Sockaddr.h"
#include "util/log/Log.h"
#include "util/Linker.h"
Linker_require("net/InterfaceController.c");
#include
#include
enum InterfaceController_PeerState
{
/**
* In state >= NEW, a valid packet has been received but it could still be a replay.
* Or it's an outgoing connection so we don't care about authentication.
*/
InterfaceController_PeerState_INIT = CryptoAuth_State_INIT,
InterfaceController_PeerState_SENT_HELLO = CryptoAuth_State_SENT_HELLO,
InterfaceController_PeerState_RECEIVED_HELLO = CryptoAuth_State_RECEIVED_HELLO,
InterfaceController_PeerState_SENT_KEY = CryptoAuth_State_SENT_KEY,
InterfaceController_PeerState_RECEIVED_KEY = CryptoAuth_State_RECEIVED_KEY,
/** In state == ESTABLISHED, we know the node at the other end is authentic. */
InterfaceController_PeerState_ESTABLISHED = CryptoAuth_State_ESTABLISHED,
/** If state == UNRESPONSIVE, the peer has not responded to pings in the required timeframe. */
InterfaceController_PeerState_UNRESPONSIVE = -1,
/** If state is UNAUTHENTICATED, the other node has not sent a single valid packet. */
InterfaceController_PeerState_UNAUTHENTICATED = -2,
// The other node has a version which is incompatible with ours, no communication is possible
InterfaceController_PeerState_INCOMPATIBLE = -3,
};
static inline char* InterfaceController_stateString(enum InterfaceController_PeerState ps)
{
switch (ps) {
case InterfaceController_PeerState_INIT: return "INIT";
case InterfaceController_PeerState_SENT_HELLO: return "SENT_HELLO";
case InterfaceController_PeerState_RECEIVED_HELLO: return "RECEIVED_HELLO";
case InterfaceController_PeerState_SENT_KEY: return "SENT_KEY";
case InterfaceController_PeerState_RECEIVED_KEY: return "RECEIVED_KEY";
case InterfaceController_PeerState_ESTABLISHED: return "ESTABLISHED";
case InterfaceController_PeerState_UNRESPONSIVE: return "UNRESPONSIVE";
case InterfaceController_PeerState_UNAUTHENTICATED: return "UNAUTHENTICATED";
case InterfaceController_PeerState_INCOMPATIBLE: return "INCOMPATIBLE";
default: return "INVALID";
}
}
enum InterfaceController_BeaconState
{
InterfaceController_BeaconState_DISABLED,
InterfaceController_BeaconState_ACCEPTING,
InterfaceController_BeaconState_SENDING
};
static inline char* InterfaceController_beaconStateString(enum InterfaceController_BeaconState bs)
{
switch (bs) {
case InterfaceController_BeaconState_DISABLED: return "DISABLED";
case InterfaceController_BeaconState_ACCEPTING: return "ACCEPTING";
case InterfaceController_BeaconState_SENDING: return "SENDING";
default: return "INVALID";
}
}
/**
* Stats about a peer
*/
struct InterfaceController_PeerStats
{
struct Address addr;
struct Sockaddr* lladdr;
int state;
int ifNum;
uint64_t timeOfLastMessage;
uint64_t bytesOut;
uint64_t bytesIn;
bool isIncomingConnection;
String* user;
/** Packet loss/duplication statistics. see: ReplayProtector */
uint32_t duplicates;
uint32_t lostPackets;
uint32_t receivedPackets;
uint32_t receivedOutOfRange;
uint32_t sendKbps;
uint32_t recvKbps;
};
struct InterfaceController
{
/*
* If set to true, high resolution timestamp data will be collected for each
* packet to help with estimating available bandwidth. Caution: this implies
* an extra syscall per packet.
*/
bool timestampPackets;
};
struct InterfaceController_Iface
{
struct Iface addrIf;
/** Interface number within InterfaceController. */
int ifNum;
enum InterfaceController_BeaconState beaconState;
String* name;
};
/**
* Register an Ethernet-like interface.
* Ethernet-like means the interface is capable of sending messages to one or more nodes
* and differentiates between them using an address.
*
* @param ifc the interface controller
* @param name a string which will identify this interface
* @param alloc an allocator, the interface will be removed when this is freed.
*/
struct InterfaceController_Iface* InterfaceController_newIface(struct InterfaceController* ifc,
String* name,
struct Allocator* alloc);
/** Get the number of interfaces registered with the controller. */
int InterfaceController_ifaceCount(struct InterfaceController* ifc);
/** Get an interface from the InterfaceController. */
struct InterfaceController_Iface* InterfaceController_getIface(struct InterfaceController* ifc,
int ifNum);
/**
* Add a new peer.
* Called from the network interface when it is asked to make a connection or it autoconnects.
* If the peer which is connected to becomes unresponsive, IC will *not* remove it but will
* set it's state to UNRESPONSIVE and it is the job of the caller to remove the peer by freeing
* the allocator which is provided with iface.
*
* @param ifc the interface controller.
* @param interfaceNumber a number for the interface to use, see regIface.
* @param herPublicKey the public key of the foreign node, NULL if unknown.
* @param lladdr the link level address, must be the size given by the interface for interfaceNumber
* @param password the password for authenticating with the other node.
* @param login an identity to provide to the other node with the password,
* if null then authtype 1 will be used.
* @param displayName the username to assign the other node in the CryptoAuth session. May be null.
* @param alloc the peer will be dropped if this is freed.
*
* @return 0 if all goes well.
* InterfaceController_bootstrapPeer_BAD_IFNUM if there is no such interface for this num.
* InterfaceController_bootstrapPeer_OUT_OF_SPACE if there is no space to store the peer.
* InterfaceController_bootstrapPeer_BAD_KEY the provided herPublicKey is not valid.
* InterfaceController_bootstrapPeer_INTERNAL unspecified error.
*/
#define InterfaceController_bootstrapPeer_BAD_IFNUM -1
#define InterfaceController_bootstrapPeer_BAD_KEY -2
#define InterfaceController_bootstrapPeer_OUT_OF_SPACE -3
#define InterfaceController_bootstrapPeer_INTERNAL -4
int InterfaceController_bootstrapPeer(struct InterfaceController* ifc,
int interfaceNumber,
uint8_t* herPublicKey,
const struct Sockaddr* lladdr,
String* password,
String* login,
String* displayName,
struct Allocator* alloc);
#define InterfaceController_beaconState_newState_OFF 0
#define InterfaceController_beaconState_newState_ACCEPT 1
#define InterfaceController_beaconState_newState_SEND 2
#define InterfaceController_beaconState_NO_SUCH_IFACE -1
#define InterfaceController_beaconState_INVALID_STATE -2
int InterfaceController_beaconState(struct InterfaceController* ifc,
int interfaceNumber,
int newState);
/**
* CryptoAuth_reset() a peer to reestablish the connection.
*
* @param ic the if controller
* @param herPublicKey the public key of the foreign node or NULL for all peers
* @return void
*/
void InterfaceController_resetPeering(struct InterfaceController* ifController,
uint8_t herPublicKey[32]);
/**
* Disconnect a previously registered peer.
*
* @param ic the if controller
* @param herPublicKey the public key of the foreign node
* @return 0 if all goes well.
* InterfaceController_disconnectPeer_NOTFOUND if no peer with herPublicKey is found.
*/
#define InterfaceController_disconnectPeer_NOTFOUND -1
int InterfaceController_disconnectPeer(struct InterfaceController* ifc, uint8_t herPublicKey[32]);
/**
* Get stats for the connected peers.
*
* @params ic the if controller
* @params alloc the Allocator to use for the peerStats array in statsOut
* @params statsOut pointer to the InterfaceController_peerStats array
* @return the number of InterfaceController_peerStats in statsOut
*/
int InterfaceController_getPeerStats(struct InterfaceController* ic,
struct Allocator* alloc,
struct InterfaceController_PeerStats** statsOut);
struct InterfaceController* InterfaceController_new(struct CryptoAuth* ca,
struct SwitchCore* switchCore,
struct Log* logger,
struct EventBase* eventBase,
struct SwitchPinger* switchPinger,
struct Random* rand,
struct Allocator* allocator,
struct EventEmitter* ee);
#endif