Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
cjdelisle
committed
Nov 21, 2011
1 parent
54acfd1
commit 1706066
Showing
8 changed files
with
621 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
add_library(switch SwitchCore.c) | ||
|
||
# Everything must be tested. | ||
#enable_testing() | ||
#add_subdirectory(test) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
struct SwitchCore; | ||
|
||
struct SwitchCore_Interface; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
#ifndef ERROR_H | ||
#define ERROR_H | ||
|
||
#define Error_MALFORMED_ADDRESS 0 | ||
#define Error_INTERFACE_ERROR (1<<16) | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
struct Message | ||
{ | ||
/** The length of the message. */ | ||
uint16_t length; | ||
|
||
/** The content. */ | ||
uint8_t* bytes; | ||
|
||
struct MemAllocator* allocator; | ||
}; |
Oops, something went wrong.