|
@@ -17,12 +17,17 @@
|
|
|
#include "exception/Jmp.h"
|
|
|
#include "memory/Allocator.h"
|
|
|
#include "net/InterfaceController.h"
|
|
|
-#include "util/events/UDPAddrIface.h"
|
|
|
#include "util/events/EventBase.h"
|
|
|
#include "util/events/FakeNetwork.h"
|
|
|
#include "util/platform/Sockaddr.h"
|
|
|
#include "crypto/Key.h"
|
|
|
#include "interface/UDPInterface_admin.h"
|
|
|
+#include "interface/UDPInterface.h"
|
|
|
+#include "util/Identity.h"
|
|
|
+
|
|
|
+#define ArrayList_TYPE struct UDPInterface
|
|
|
+#define ArrayList_NAME UDPInterface
|
|
|
+#include "util/ArrayList.h"
|
|
|
|
|
|
struct Context
|
|
|
{
|
|
@@ -30,43 +35,61 @@ struct Context
|
|
|
struct Allocator* alloc;
|
|
|
struct Log* logger;
|
|
|
struct Admin* admin;
|
|
|
- struct AddrIface* udpIf;
|
|
|
+ struct ArrayList_UDPInterface* ifaces;
|
|
|
struct InterfaceController* ic;
|
|
|
struct FakeNetwork* fakeNet;
|
|
|
+ Identity
|
|
|
};
|
|
|
|
|
|
+static struct UDPInterface* getIface(struct Context* ctx,
|
|
|
+ Dict* args,
|
|
|
+ String* txid,
|
|
|
+ struct Allocator* requestAlloc,
|
|
|
+ uint32_t* ifNumP)
|
|
|
+{
|
|
|
+ int64_t* interfaceNumber = Dict_getIntC(args, "interfaceNumber");
|
|
|
+ uint32_t ifNum = (interfaceNumber) ? ((uint32_t) *interfaceNumber) : 0;
|
|
|
+ if (ifNumP) { *ifNumP = ifNum; }
|
|
|
+ struct UDPInterface* udpif = ArrayList_UDPInterface_get(ctx->ifaces, ifNum);
|
|
|
+ if (!udpif) {
|
|
|
+ Dict* out = Dict_new(requestAlloc);
|
|
|
+ Dict_putStringCC(out, "error", "no such interface for interfaceNumber", requestAlloc);
|
|
|
+ Admin_sendMessage(out, txid, ctx->admin);
|
|
|
+ }
|
|
|
+ return udpif;
|
|
|
+}
|
|
|
+
|
|
|
static void beginConnection(Dict* args,
|
|
|
void* vcontext,
|
|
|
String* txid,
|
|
|
struct Allocator* requestAlloc)
|
|
|
{
|
|
|
- struct Context* ctx = vcontext;
|
|
|
+ struct Context* ctx = Identity_check((struct Context*) vcontext);
|
|
|
+
|
|
|
+ uint32_t ifNum = 0;
|
|
|
+ struct UDPInterface* udpIf = getIface(ctx, args, txid, requestAlloc, &ifNum);
|
|
|
+ if (!udpIf) { return; }
|
|
|
|
|
|
String* password = Dict_getStringC(args, "password");
|
|
|
String* login = Dict_getStringC(args, "login");
|
|
|
String* publicKey = Dict_getStringC(args, "publicKey");
|
|
|
String* address = Dict_getStringC(args, "address");
|
|
|
- int64_t* interfaceNumber = Dict_getIntC(args, "interfaceNumber");
|
|
|
- uint32_t ifNum = (interfaceNumber) ? ((uint32_t) *interfaceNumber) : 0;
|
|
|
String* peerName = Dict_getStringC(args, "peerName");
|
|
|
- String* error = NULL;
|
|
|
+ char* error = NULL;
|
|
|
|
|
|
Log_debug(ctx->logger, "Peering with [%s]", publicKey->bytes);
|
|
|
|
|
|
struct Sockaddr_storage ss;
|
|
|
uint8_t pkBytes[32];
|
|
|
int ret;
|
|
|
- if (interfaceNumber && *interfaceNumber < 0) {
|
|
|
- error = String_CONST("negative interfaceNumber");
|
|
|
-
|
|
|
- } else if ((ret = Key_parse(publicKey, pkBytes, NULL))) {
|
|
|
- error = String_CONST(Key_parse_strerror(ret));
|
|
|
+ if ((ret = Key_parse(publicKey, pkBytes, NULL))) {
|
|
|
+ error = Key_parse_strerror(ret);
|
|
|
|
|
|
} else if (Sockaddr_parse(address->bytes, &ss)) {
|
|
|
- error = String_CONST("unable to parse ip address and port.");
|
|
|
+ error = "unable to parse ip address and port.";
|
|
|
|
|
|
- } else if (Sockaddr_getFamily(&ss.addr) != Sockaddr_getFamily(ctx->udpIf->addr)) {
|
|
|
- error = String_CONST("different address type than this socket is bound to.");
|
|
|
+ } else if (Sockaddr_getFamily(&ss.addr) != Sockaddr_getFamily(udpIf->generic.addr)) {
|
|
|
+ error = "different address type than this socket is bound to.";
|
|
|
|
|
|
} else {
|
|
|
|
|
@@ -95,86 +118,79 @@ static void beginConnection(Dict* args,
|
|
|
if (ret) {
|
|
|
switch(ret) {
|
|
|
case InterfaceController_bootstrapPeer_BAD_IFNUM:
|
|
|
- error = String_CONST("no such interface for interfaceNumber");
|
|
|
+ // Should never happen, should be caught in getIface()
|
|
|
+ error = "interface deregistered";
|
|
|
break;
|
|
|
|
|
|
case InterfaceController_bootstrapPeer_BAD_KEY:
|
|
|
- error = String_CONST("invalid cjdns public key.");
|
|
|
+ error = "invalid cjdns public key.";
|
|
|
break;
|
|
|
|
|
|
case InterfaceController_bootstrapPeer_OUT_OF_SPACE:
|
|
|
- error = String_CONST("no more space to register with the switch.");
|
|
|
+ error = "no more space to register with the switch.";
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
- error = String_CONST("unknown error");
|
|
|
+ error = "unknown error";
|
|
|
break;
|
|
|
}
|
|
|
} else {
|
|
|
- error = String_CONST("none");
|
|
|
+ error = "none";
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- Dict out = Dict_CONST(String_CONST("error"), String_OBJ(error), NULL);
|
|
|
- Admin_sendMessage(&out, txid, ctx->admin);
|
|
|
+ Dict* out = Dict_new(requestAlloc);
|
|
|
+ Dict_putStringCC(out, "error", error, requestAlloc);
|
|
|
+ Admin_sendMessage(out, txid, ctx->admin);
|
|
|
}
|
|
|
|
|
|
-static struct AddrIface* setupLibuvUDP(struct Context* ctx,
|
|
|
+static struct UDPInterface* setupLibuvUDP(struct Context* ctx,
|
|
|
struct Sockaddr* addr,
|
|
|
+ uint16_t beaconPort,
|
|
|
uint8_t dscp,
|
|
|
String* txid,
|
|
|
struct Allocator* alloc)
|
|
|
{
|
|
|
- struct UDPAddrIface* udpIf = NULL;
|
|
|
+ struct UDPInterface* udpIf = NULL;
|
|
|
struct Jmp jmp;
|
|
|
Jmp_try(jmp) {
|
|
|
- udpIf = UDPAddrIface_new(ctx->eventBase, addr, alloc, &jmp.handler, ctx->logger);
|
|
|
+ udpIf = UDPInterface_new(
|
|
|
+ ctx->eventBase, addr, beaconPort, alloc, &jmp.handler, ctx->logger);
|
|
|
if (dscp) {
|
|
|
- if (UDPAddrIface_setDSCP(udpIf, dscp)) {
|
|
|
+ if (UDPInterface_setDSCP(udpIf, dscp)) {
|
|
|
Log_warn(ctx->logger, "Set DSCP failed");
|
|
|
}
|
|
|
}
|
|
|
} Jmp_catch {
|
|
|
- String* errStr = String_CONST(jmp.message);
|
|
|
- Dict out = Dict_CONST(String_CONST("error"), String_OBJ(errStr), NULL);
|
|
|
- Admin_sendMessage(&out, txid, ctx->admin);
|
|
|
+ Dict* out = Dict_new(alloc);
|
|
|
+ Dict_putStringCC(out, "error", jmp.message, alloc);
|
|
|
+ Admin_sendMessage(out, txid, ctx->admin);
|
|
|
Allocator_free(alloc);
|
|
|
return NULL;
|
|
|
}
|
|
|
- return &udpIf->generic;
|
|
|
-}
|
|
|
-
|
|
|
-static struct AddrIface* setupFakeUDP(struct FakeNetwork* fakeNet,
|
|
|
- struct Sockaddr* addr,
|
|
|
- struct Allocator* alloc)
|
|
|
-{
|
|
|
- struct FakeNetwork_UDPIface* fni = FakeNetwork_iface(fakeNet, addr, alloc);
|
|
|
- return &fni->generic;
|
|
|
+ return udpIf;
|
|
|
}
|
|
|
|
|
|
static void newInterface2(struct Context* ctx,
|
|
|
struct Sockaddr* addr,
|
|
|
uint8_t dscp,
|
|
|
String* txid,
|
|
|
- struct Allocator* requestAlloc)
|
|
|
+ struct Allocator* requestAlloc,
|
|
|
+ uint16_t beaconPort)
|
|
|
{
|
|
|
struct Allocator* const alloc = Allocator_child(ctx->alloc);
|
|
|
- struct AddrIface* ai;
|
|
|
- if (ctx->fakeNet) {
|
|
|
- ai = setupFakeUDP(ctx->fakeNet, addr, alloc);
|
|
|
- } else {
|
|
|
- ai = setupLibuvUDP(ctx, addr, dscp, txid, alloc);
|
|
|
- }
|
|
|
- if (!ai) { return; }
|
|
|
- ctx->udpIf = ai;
|
|
|
+ struct UDPInterface* udpif = setupLibuvUDP(ctx, addr, beaconPort, dscp, txid, alloc);
|
|
|
+ if (!udpif) { return; }
|
|
|
+
|
|
|
struct InterfaceController_Iface* ici =
|
|
|
InterfaceController_newIface(ctx->ic, String_CONST("UDP"), alloc);
|
|
|
- Iface_plumb(&ici->addrIf, &ai->iface);
|
|
|
+ Iface_plumb(&ici->addrIf, &udpif->generic.iface);
|
|
|
+ ArrayList_UDPInterface_put(ctx->ifaces, ici->ifNum, udpif);
|
|
|
|
|
|
Dict* out = Dict_new(requestAlloc);
|
|
|
Dict_putStringCC(out, "error", "none", requestAlloc);
|
|
|
Dict_putIntC(out, "interfaceNumber", ici->ifNum, requestAlloc);
|
|
|
- char* printedAddr = Sockaddr_print(ai->addr, requestAlloc);
|
|
|
+ char* printedAddr = Sockaddr_print(udpif->generic.addr, requestAlloc);
|
|
|
Dict_putStringCC(out,
|
|
|
"bindAddress",
|
|
|
printedAddr,
|
|
@@ -185,10 +201,12 @@ static void newInterface2(struct Context* ctx,
|
|
|
|
|
|
static void newInterface(Dict* args, void* vcontext, String* txid, struct Allocator* requestAlloc)
|
|
|
{
|
|
|
- struct Context* ctx = vcontext;
|
|
|
+ struct Context* ctx = Identity_check((struct Context*) vcontext);
|
|
|
String* bindAddress = Dict_getStringC(args, "bindAddress");
|
|
|
int64_t* dscpValue = Dict_getIntC(args, "dscp");
|
|
|
uint8_t dscp = dscpValue ? ((uint8_t) *dscpValue) : 0;
|
|
|
+ int64_t* beaconPort_p = Dict_getIntC(args, "beaconPort");
|
|
|
+ uint16_t beaconPort = beaconPort_p ? ((uint16_t) *beaconPort_p) : 0;
|
|
|
struct Sockaddr_storage addr;
|
|
|
if (Sockaddr_parse((bindAddress) ? bindAddress->bytes : "0.0.0.0", &addr)) {
|
|
|
Dict out = Dict_CONST(
|
|
@@ -197,7 +215,99 @@ static void newInterface(Dict* args, void* vcontext, String* txid, struct Alloca
|
|
|
Admin_sendMessage(&out, txid, ctx->admin);
|
|
|
return;
|
|
|
}
|
|
|
- newInterface2(ctx, &addr.addr, dscp, txid, requestAlloc);
|
|
|
+ newInterface2(ctx, &addr.addr, dscp, txid, requestAlloc, beaconPort);
|
|
|
+}
|
|
|
+
|
|
|
+static void listDevices(Dict* args, void* vcontext, String* txid, struct Allocator* requestAlloc)
|
|
|
+{
|
|
|
+ struct Context* ctx = Identity_check((struct Context*) vcontext);
|
|
|
+ Dict* out = Dict_new(requestAlloc);
|
|
|
+ struct Jmp jmp;
|
|
|
+ Jmp_try(jmp) {
|
|
|
+ List* list = UDPInterface_listDevices(requestAlloc, &jmp.handler);
|
|
|
+ Dict_putListC(out, "ret", list, requestAlloc);
|
|
|
+ } Jmp_catch {
|
|
|
+ Dict_putStringCC(out, "error", jmp.message, requestAlloc);
|
|
|
+ }
|
|
|
+ Admin_sendMessage(out, txid, ctx->admin);
|
|
|
+}
|
|
|
+
|
|
|
+static void setBroadcastDevices(
|
|
|
+ Dict* args, void* vcontext, String* txid, struct Allocator* requestAlloc)
|
|
|
+{
|
|
|
+ struct Context* ctx = Identity_check((struct Context*) vcontext);
|
|
|
+ struct UDPInterface* udpif = getIface(ctx, args, txid, requestAlloc, NULL);
|
|
|
+ if (!udpif) { return; }
|
|
|
+ UDPInterface_setBroadcastDevices(udpif, Dict_getListC(args, "devices"));
|
|
|
+ Dict* out = Dict_new(requestAlloc);
|
|
|
+ Dict_putStringCC(out, "error", "none", requestAlloc);
|
|
|
+ Admin_sendMessage(out, txid, ctx->admin);
|
|
|
+}
|
|
|
+
|
|
|
+static void getBroadcastDevices(
|
|
|
+ Dict* args, void* vcontext, String* txid, struct Allocator* requestAlloc)
|
|
|
+{
|
|
|
+ struct Context* ctx = Identity_check((struct Context*) vcontext);
|
|
|
+ struct UDPInterface* udpif = getIface(ctx, args, txid, requestAlloc, NULL);
|
|
|
+ if (!udpif) { return; }
|
|
|
+ Dict* out = Dict_new(requestAlloc);
|
|
|
+ Dict_putStringCC(out, "error", "none", requestAlloc);
|
|
|
+ List* devices = UDPInterface_getBroadcastDevices(udpif, requestAlloc);
|
|
|
+ Dict_putListC(out, "devices", devices, requestAlloc);
|
|
|
+ Admin_sendMessage(out, txid, ctx->admin);
|
|
|
+}
|
|
|
+
|
|
|
+static void getBroadcastAddrs(
|
|
|
+ Dict* args, void* vcontext, String* txid, struct Allocator* requestAlloc)
|
|
|
+{
|
|
|
+ struct Context* ctx = Identity_check((struct Context*) vcontext);
|
|
|
+ struct UDPInterface* udpif = getIface(ctx, args, txid, requestAlloc, NULL);
|
|
|
+ if (!udpif) { return; }
|
|
|
+ Dict* out = Dict_new(requestAlloc);
|
|
|
+ Dict_putStringCC(out, "error", "none", requestAlloc);
|
|
|
+ List* addrs = UDPInterface_getBroadcastAddrs(udpif, requestAlloc);
|
|
|
+ Dict_putListC(out, "addrs", addrs, requestAlloc);
|
|
|
+ Admin_sendMessage(out, txid, ctx->admin);
|
|
|
+}
|
|
|
+
|
|
|
+static void beacon(Dict* args, void* vcontext, String* txid, struct Allocator* requestAlloc)
|
|
|
+{
|
|
|
+ int64_t* stateP = Dict_getIntC(args, "state");
|
|
|
+ int64_t* ifNumP = Dict_getIntC(args, "interfaceNumber");
|
|
|
+ uint32_t ifNum = (ifNumP) ? ((uint32_t) *ifNumP) : 0;
|
|
|
+ uint32_t state = (stateP) ? ((uint32_t) *stateP) : 0xffffffff;
|
|
|
+ struct Context* ctx = Identity_check((struct Context*) vcontext);
|
|
|
+
|
|
|
+ char* error = NULL;
|
|
|
+ int ret = InterfaceController_beaconState(ctx->ic, ifNum, state);
|
|
|
+ if (ret == InterfaceController_beaconState_NO_SUCH_IFACE) {
|
|
|
+ error = "invalid interfaceNumber";
|
|
|
+ } else if (ret == InterfaceController_beaconState_INVALID_STATE) {
|
|
|
+ error = "invalid state";
|
|
|
+ } else if (ret) {
|
|
|
+ error = "internal";
|
|
|
+ }
|
|
|
+
|
|
|
+ if (error) {
|
|
|
+ Dict* out = Dict_new(requestAlloc);
|
|
|
+ Dict_putStringCC(out, "error", error, requestAlloc);
|
|
|
+ Admin_sendMessage(out, txid, ctx->admin);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ char* stateStr = "disabled";
|
|
|
+ if (state == InterfaceController_beaconState_newState_ACCEPT) {
|
|
|
+ stateStr = "accepting";
|
|
|
+ } else if (state == InterfaceController_beaconState_newState_SEND) {
|
|
|
+ stateStr = "sending and accepting";
|
|
|
+ }
|
|
|
+
|
|
|
+ Dict out = Dict_CONST(
|
|
|
+ String_CONST("error"), String_OBJ(String_CONST("none")), Dict_CONST(
|
|
|
+ String_CONST("state"), Int_OBJ(state), Dict_CONST(
|
|
|
+ String_CONST("stateName"), String_OBJ(String_CONST(stateStr)), NULL
|
|
|
+ )));
|
|
|
+ Admin_sendMessage(&out, txid, ctx->admin);
|
|
|
}
|
|
|
|
|
|
void UDPInterface_admin_register(struct EventBase* base,
|
|
@@ -215,11 +325,14 @@ void UDPInterface_admin_register(struct EventBase* base,
|
|
|
.ic = ic,
|
|
|
.fakeNet = fakeNet
|
|
|
}));
|
|
|
+ Identity_set(ctx);
|
|
|
+ ctx->ifaces = ArrayList_UDPInterface_new(alloc);
|
|
|
|
|
|
Admin_registerFunction("UDPInterface_new", newInterface, ctx, true,
|
|
|
((struct Admin_FunctionArg[]) {
|
|
|
{ .name = "bindAddress", .required = 0, .type = "String" },
|
|
|
- { .name = "dscp", .required = 0, .type = "Int" }
|
|
|
+ { .name = "dscp", .required = 0, .type = "Int" },
|
|
|
+ { .name = "beaconPort", .required = 0, .type = "Int" }
|
|
|
}), admin);
|
|
|
|
|
|
Admin_registerFunction("UDPInterface_beginConnection", beginConnection, ctx, true,
|
|
@@ -230,4 +343,28 @@ void UDPInterface_admin_register(struct EventBase* base,
|
|
|
{ .name = "address", .required = 1, .type = "String" },
|
|
|
{ .name = "login", .required = 0, .type = "String" }
|
|
|
}), admin);
|
|
|
+
|
|
|
+ Admin_registerFunction("UDPInterface_listDevices", listDevices, ctx, true, NULL, admin);
|
|
|
+
|
|
|
+ Admin_registerFunction("UDPInterface_setBroadcastDevices", setBroadcastDevices, ctx, true,
|
|
|
+ ((struct Admin_FunctionArg[]) {
|
|
|
+ { .name = "interfaceNumber", .required = 0, .type = "Int" },
|
|
|
+ { .name = "devices", .required = 1, .type = "List" }
|
|
|
+ }), admin);
|
|
|
+
|
|
|
+ Admin_registerFunction("UDPInterface_getBroadcastDevices", getBroadcastDevices, ctx, true,
|
|
|
+ ((struct Admin_FunctionArg[]) {
|
|
|
+ { .name = "interfaceNumber", .required = 0, .type = "Int" }
|
|
|
+ }), admin);
|
|
|
+
|
|
|
+ Admin_registerFunction("UDPInterface_getBroadcastAddrs", getBroadcastAddrs, ctx, true,
|
|
|
+ ((struct Admin_FunctionArg[]) {
|
|
|
+ { .name = "interfaceNumber", .required = 0, .type = "Int" }
|
|
|
+ }), admin);
|
|
|
+
|
|
|
+ Admin_registerFunction("UDPInterface_beacon", beacon, ctx, true,
|
|
|
+ ((struct Admin_FunctionArg[]) {
|
|
|
+ { .name = "interfaceNumber", .required = 0, .type = "Int" },
|
|
|
+ { .name = "state", .required = 0, .type = "Int" }
|
|
|
+ }), admin);
|
|
|
}
|