Skip to content

Commit

Permalink
Added switch core
Browse files Browse the repository at this point in the history
  • Loading branch information
cjdelisle committed Nov 21, 2011
1 parent 54acfd1 commit 1706066
Show file tree
Hide file tree
Showing 8 changed files with 621 additions and 0 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Expand Up @@ -42,6 +42,7 @@ add_subdirectory(crypto)
add_subdirectory(dht)
add_subdirectory(dns)
add_subdirectory(util)
add_subdirectory(switch)

include_directories(${LIBEVENT2_INCLUDE_DIRS})

Expand Down
5 changes: 5 additions & 0 deletions switch/CMakeLists.txt
@@ -0,0 +1,5 @@
add_library(switch SwitchCore.c)

# Everything must be tested.
#enable_testing()
#add_subdirectory(test)
203 changes: 203 additions & 0 deletions switch/SwitchCore.c
@@ -0,0 +1,203 @@
#include <string.h>

#include "memory/MemAllocator.h"
#include "switch/SwitchCore.h"
#include "wire/Error.h"
#include "wire/Headers.h"
#include "wire/Message.h"
#include "wire/MessageType.h"

struct SwitchCore_Interface
{
struct SwitchCore* core;

uint8_t (* sendMessage)(struct Message* toSend, void* callbackContext);

void* callbackContext;
};

struct SwitchCore
{
struct SwitchCore_Interface interfaces[256];

struct MemAllocator* allocator;

uint32_t interfaceCount;
};


struct SwitchCore* SwitchCore_new(struct MemAllocator* allocator)
{
struct SwitchCore* core = allocator->malloc(sizeof(struct SwitchCore), allocator);
core->allocator = allocator;
core->interfaceCount = 0;
return core;
}

struct SwitchCore_Interface* SwitchCore_addInterface(
uint8_t (* sendMessage)(struct Message* toSend, void* callbackContext),
void* callbackContext,
struct SwitchCore* core)
{
if (core->interfaceCount == 256) {
return NULL;
}
struct SwitchCore_Interface* out = &core->interfaces[core->interfaceCount];
out->core = core;
out->sendMessage = sendMessage;
out->callbackContext = callbackContext;
core->interfaceCount++;
return out;
}

/**
* Bitwise reversal of the a number.
*/
static inline uint64_t bitReverse(uint64_t toReverse)
{
uint64_t out = 0;
for (uint32_t i = 0; i < Headers_SWITCH_LABEL_BITS; i++) {
out |= toReverse & 1;
out <<= 1;
toReverse >>= 1;
}
return out;
}

/*
* Number compression scheme:
*
* scheme data suffix range bits used
* 0 00-10 (0-2) 2
* 1 0000-1111 011 (0-15) 7
* 2 000000-111111 0111 (0-63) 10
* 3 00000000-11111111 01111 (0-255) 13
*/
#define GET_MAX(bits) ((1 << bits) - 1)
#define SCHEME_ZERO_BITS 2
#define SCHEME_ONE_BITS 7
#define SCHEME_TWO_BITS 10
#define SCHEME_THREE_BITS 13
static inline uint32_t bitsUsedForLabel(const uint32_t label)
{
if ((label & GET_MAX(3)) == GET_MAX(3)) {
if ((label & GET_MAX(4)) == GET_MAX(4)) {
return SCHEME_THREE_BITS;
} else {
return SCHEME_TWO_BITS;
}
} else {
if ((label & GET_MAX(2)) == GET_MAX(2)) {
return SCHEME_ONE_BITS;
} else {
return SCHEME_ZERO_BITS;
}
}
}

static inline uint32_t bitsUsedForNumber(const uint32_t number)
{
if (number > 15) {
return (number > 15) ? SCHEME_THREE_BITS : SCHEME_TWO_BITS;
} else {
return (number > 2) ? SCHEME_ONE_BITS : SCHEME_ZERO_BITS;
}
}

static inline uint32_t getCompressed(const uint32_t number, const uint32_t bitsUsed)
{
switch (bitsUsed) {
case SCHEME_ZERO_BITS: return number;
case SCHEME_ONE_BITS: return (number << 3) | GET_MAX(2);
case SCHEME_TWO_BITS: return (number << 4) | GET_MAX(3);
case SCHEME_THREE_BITS: return (number << 5) | GET_MAX(4);
default: return 0;
};
}

static inline uint32_t getDecompressed(const uint32_t label, const uint32_t bitsUsed)
{
switch (bitsUsed) {
case SCHEME_ZERO_BITS: return label & GET_MAX(2);
case SCHEME_ONE_BITS: return (label >> 3) & GET_MAX(4);
case SCHEME_TWO_BITS: return (label >> 4) & GET_MAX(6);
case SCHEME_THREE_BITS: return (label >> 5) & GET_MAX(8);
default: return 0;
};
}
#undef GET_MAX
#undef SCHEME_ZERO_BITS
#undef SCHEME_ONE_BITS
#undef SCHEME_TWO_BITS
#undef SCHEME_THREE_BITS

static inline uint8_t sendMessage(const struct SwitchCore_Interface* interface,
struct Message* toSend)
{
return interface->sendMessage(toSend, interface->callbackContext);
}

static inline void sendError(struct SwitchCore_Interface* interface,
struct Message* cause,
uint16_t code)
{
struct Headers_SwitchHeader* header = (struct Headers_SwitchHeader*) cause->bytes;
if (Headers_getMessageType(header) == MessageType_ERROR) {
// Errors never cause other errors to be sent.
return;
}
struct MessageType_Error* err =
cause->allocator->malloc(sizeof(struct MessageType_Error), cause->allocator);

err->switchHeader.label_be = bitReverse(header->label_be);
Headers_setPaymentFragmentNumAndMessageType(&err->switchHeader,
Headers_getPayment(header),
0,
MessageType_ERROR);
err->error.errorType_be = ntohs(code);
err->error.length = ((cause->length > 255) ? cause->length : 255);
memcpy(err->error.cause.bytes, cause->bytes, err->error.length);

// Just swap the error into the message used for the cause.
cause->bytes = (uint8_t*) err;
cause->length = sizeof(struct MessageType_Error) - (255 - err->error.length);
sendMessage(interface, cause);
}


void SwitchCore_receivedPacket(struct SwitchCore_Interface* sourceIf, struct Message* message)
{
if (message->length < sizeof(struct Headers_SwitchHeader)) {
// runt packet, don't bother trying to respond, there's no readable header anyway.
return;
}

const struct SwitchCore* core = sourceIf->core;
struct Headers_SwitchHeader* header = (struct Headers_SwitchHeader*) message->bytes;
const uint32_t label = ntohl(header->label_be);
const uint32_t bits = bitsUsedForLabel(label);
const uint32_t sourceIfIndex = sourceIf - core->interfaces;

//const int32_t sourceLabel = labelForInterface(sourceIf, destBits);
if (bitsUsedForNumber(sourceIfIndex) > bits) {
// Source address bigger than destination address, fail.
sendError(sourceIf, message, Error_MALFORMED_ADDRESS);
return;
}

const uint32_t destIndex = getDecompressed(label, bits);

if (destIndex >= core->interfaceCount) {
// No such interface
sendError(sourceIf, message, Error_MALFORMED_ADDRESS);
return;
}

header->label_be = ntohl((label >> bits) | bitReverse(getCompressed(sourceIfIndex, bits)));

const uint8_t err = sendMessage(&core->interfaces[destIndex], message);
if (err) {
header->label_be = ntohl(label);
sendError(sourceIf, message, Error_INTERFACE_ERROR | err);
}
}
3 changes: 3 additions & 0 deletions switch/SwitchCore.h
@@ -0,0 +1,3 @@
struct SwitchCore;

struct SwitchCore_Interface;
7 changes: 7 additions & 0 deletions wire/Error.h
@@ -0,0 +1,7 @@
#ifndef ERROR_H
#define ERROR_H

#define Error_MALFORMED_ADDRESS 0
#define Error_INTERFACE_ERROR (1<<16)

#endif
153 changes: 153 additions & 0 deletions wire/Headers.h
@@ -0,0 +1,153 @@
#ifndef HEADERS_H
#define HEADERS_H

#include <stdint.h>
#include <arpa/inet.h>

#define Headers_SWITCH_LABEL_BITS 40

/**
* The header which switches use to decide where to route traffic.
*/
struct Headers_SwitchHeader
{
/** The label, this is how the switch decides where to send the packet. Big Endian. */
uint32_t label_be;

/**
* Top 4 bits: messageType
* See: MessageType.h
*
* Next 4 bits: fragmentNumber
* 0 of the message is not fragmented, 1-15 if it is.
* Full headers for the packet along with enough user data to gather
* encryption nonces must be in the first fragment, if not, the router
* may drop the packet.
*
* Bottom 24 bits: payment
* Anti-flooding, this is a big endian uint32_t with the high 8 bits cut off.
*
* This entire number is in big endian encoding.
*/
uint32_t lowBits_be;
};

static inline uint32_t Headers_getMessageType(const struct Headers_SwitchHeader* header)
{
return ntohl(header->lowBits_be) >> 28;
}

static inline uint32_t Headers_getFragmentNumber(const struct Headers_SwitchHeader* header)
{
return (ntohl(header->lowBits_be) >> 24) & ((1 << 4) - 1);
}

static inline uint32_t Headers_getPayment(const struct Headers_SwitchHeader* header)
{
return ntohl(header->lowBits_be) & ((1 << 24) - 1);
}

static inline void Headers_setPaymentFragmentNumAndMessageType(struct Headers_SwitchHeader* header,
const uint32_t payment,
const uint32_t fragmentNum,
const uint32_t messageType)
{
header->lowBits_be = htonl(
(payment & ((1 << 24) - 1))
| ((fragmentNum & ((1 << 4) - 1)) << 24)
| messageType << 28
);
}

/** A return message which indicates an error has occured. */
struct Headers_Error
{
/** A nonce for supporting an outer layer of encryption. */
uint8_t nonce[15];

/** The number of bytes of original cause packet. */
uint8_t length;

/** The error code. Big Endian. */
uint16_t errorType_be;

union {
/** The header from the cause. */
struct Headers_SwitchHeader switchHeader;

/** The first 256 bytes of the packet which caused the error. */
uint8_t bytes[256];
} cause;
};

/**
* This is a handshake header packet, there are 2 required to begin an encrypted connection.
* the only difference between handshake1 and handshake2 is in handshake2, the content
* in the next level is encrypted.
*/
struct Headers_Handshake
{
/** Used as a nonce for the handshake. */
uint8_t nonce[8];

/** The public key to send for completing the handshake. */
uint8_t myPublicKey[32];
};

/** Used for routers authenticating with one another. */
struct Headers_Auth
{
uint8_t bytes[16];
};

/**
* Used for synchronizing time.
*/
struct Headers_Time
{
/**
* The current time according to the node which was contacted,
* the node who made the initial request must keep a time offset.
* Big Endian.
*/
uint64_t currentTimeMilliseconds_be;
};

/**
* A header for encrypted data, this may be for router data or end user data.
* This header cannot be used unless the Time header has already been used.
* After 65535 milliseconds with no data, an encrypted session must be dropped.
*/
struct Headers_Encrypted
{
/**
* The number of packet sent in a 2 second window,
* this only allows for sending 32k packets per second between endpoints.
* Big Endian.
*/
uint16_t nonce_be;

/**
* The number of milliseconds since the epoch mod 65535.
* Big Endian.
*/
uint16_t timeSync_be;
};

struct Headers_IP6Header
{
uint16_t versionClassAndFlowLabel;

/** Big Endian. */
uint16_t flowLabelLow_be;

/** Big Endian. */
uint16_t payloadLength_be;

uint8_t nextHeader;
uint8_t hopLimit;
uint8_t sourceAddr[16];
uint8_t destinationAddr[16];
};

#endif
10 changes: 10 additions & 0 deletions wire/Message.h
@@ -0,0 +1,10 @@
struct Message
{
/** The length of the message. */
uint16_t length;

/** The content. */
uint8_t* bytes;

struct MemAllocator* allocator;
};

0 comments on commit 1706066

Please sign in to comment.