/* 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 Control_H
#define Control_H
#include "wire/SwitchHeader.h"
#include "util/Endian.h"
#include "util/Assert.h"
/**
* Type two, error.
*/
#define Control_ERROR 2
#define Control_ERROR_be Endian_hostToBigEndian16(Control_ERROR)
#define Control_Error_HEADER_SIZE 4
#define Control_Error_MIN_SIZE (Control_Error_HEADER_SIZE + SwitchHeader_SIZE + 4)
#define Control_Error_MAX_SIZE 256
struct Control_Error
{
/** The type of error, see Error.h */
uint32_t errorType_be;
/** The header of the packet which caused the error. */
struct SwitchHeader cause;
/** The handle which sits below the SwitchHeader. */
uint32_t causeHandle;
};
Assert_compileTime(sizeof(struct Control_Error) == Control_Error_MIN_SIZE);
/**
* Type three, ping.
*/
#define Control_PING_be Endian_hostToBigEndian16(3)
#define Control_Ping_HEADER_SIZE 8
#define Control_Ping_MIN_SIZE 8
#define Control_Ping_MAX_SIZE 256
#define Control_Ping_MAGIC Endian_hostToBigEndian32(0x09f91102)
struct Control_Ping
{
/** Magic: equal to Control_Ping_MAGIC in a ping and Control_Pong_MAGIC in a pong. */
uint32_t magic;
/** The version of the sending node. */
uint32_t version_be;
/**
* Between 0 and 256 bytes of opaque data.
* Since a ping is inherently a message to one's self,
* the format is only of interest to the sender and thus undefined.
*/
uint8_t data[4];
};
Assert_compileTime(sizeof(struct Control_Ping) == Control_Ping_MIN_SIZE + 4);
/**
* Type four, pong.
* A pong is identical to a ping.
*/
#define Control_PONG_be Endian_hostToBigEndian16(4)
#define Control_Pong_HEADER_SIZE Control_Ping_HEADER_SIZE
#define Control_Pong_MIN_SIZE Control_Ping_MIN_SIZE
#define Control_Pong_MAX_SIZE Control_Ping_MAX_SIZE
#define Control_Pong_MAGIC Endian_hostToBigEndian32(0x9d74e35b)
/**
* Type five, key request/response.
* Request a node's public key, for use in debugging.
*
* Any data (up to 64 bytes) following the end of the KeyPing structure
* is the cookie which must be reflected.
*/
#define Control_KEYPING_be Endian_hostToBigEndian16(5)
#define Control_KeyPing_HEADER_SIZE 40
#define Control_KeyPing_MAX_SIZE (Control_KeyPing_HEADER_SIZE + 64)
#define Control_KeyPing_MAGIC Endian_hostToBigEndian32(0x01234567)
struct Control_KeyPing
{
/** Magic: equal to Control_KeyPing_MAGIC in a ping and Control_KeyPong_MAGIC in a pong. */
uint32_t magic;
/** The version of the sending node. */
uint32_t version_be;
/** The permanent public key. */
uint8_t key[32];
};
Assert_compileTime(sizeof(struct Control_KeyPing) == Control_KeyPing_HEADER_SIZE);
#define Control_KEYPONG_be Endian_hostToBigEndian16(6)
#define Control_KeyPong_HEADER_SIZE Control_KeyPing_HEADER_SIZE
#define Control_KeyPong_MAX_SIZE Control_KeyPing_MAX_SIZE
#define Control_KeyPong_MAGIC Endian_hostToBigEndian32(0x89abcdef)
#define Control_GETSNODE_QUERY_be Endian_hostToBigEndian16(7)
#define Control_GETSNODE_QUERY_MAGIC Endian_hostToBigEndian32(0x736e6f71) // snoq
#define Control_GETSNODE_REPLY_be Endian_hostToBigEndian16(8)
#define Control_GETSNODE_REPLY_MAGIC Endian_hostToBigEndian32(0x736e6f72) // snor
#define Control_GetSnode_HEADER_SIZE 56
struct Control_GetSnode
{
// Control_SNODE_QUERY_MAGIC for queries
// Control_SNODE_REPLY_MAGIC for replies
uint32_t magic;
// version of the node sending the packet
uint32_t version_be;
// version of the supernode belonging to the node sending the packet
// 0 if unknown
uint32_t snodeVersion_be;
// If the highest bit is set then this number is per configuration and no more than this
// should be sent by the peer, otherwise it is an estimate of the link speed.
// Nodes should send no more than min(minimumConfigured, avg(nodeAVal, nodeBVal)
// so if A configures 1000Mb, B estimates 100Mb -> use avg(100, 1000)
// but if A configures or estimates 1000Mb, B configures 100Mb -> use 100Mb
//
// Nodes MUST check if this message comes from a direct peer before using this value.
// 0 if unknown
uint32_t kbps_be;
// Key of the supernode belonging to the node sending, zero if no supernode is known or
// configured.
uint8_t snodeKey[32];
// Path from sender to sender's supernode, "corrected" so that recipient can splice to it
// without knowing sender's encoding scheme. 0 if unknown.
uint8_t pathToSnode_be[8];
};
Assert_compileTime(sizeof(struct Control_GetSnode) == Control_GetSnode_HEADER_SIZE);
#define Control_RPATH_QUERY_be Endian_hostToBigEndian16(9)
#define Control_RPATH_QUERY_MAGIC Endian_hostToBigEndian32(0x736e6f71) // rpaq
#define Control_RPATH_REPLY_be Endian_hostToBigEndian16(10)
#define Control_RPATH_REPLY_MAGIC Endian_hostToBigEndian32(0x736e6f72) // rpar
#define Control_RPath_HEADER_SIZE 16
struct Control_RPath
{
// Control_RPATH_QUERY_MAGIC for queries
// Control_RPATH_REPLY_MAGIC for replies
uint32_t magic;
// Version of the node sending the query or the reply
uint32_t version_be;
// The reverse path back to the node who sent the query
uint8_t rpath_be[8];
};
static inline char* Control_typeString(uint16_t type_be)
{
if (type_be == Control_ERROR_be) {
return "ERROR";
} else if (type_be == Control_PING_be) {
return "PING";
} else if (type_be == Control_PONG_be) {
return "PONG";
} else if (type_be == Control_KEYPING_be) {
return "KEYPING";
} else if (type_be == Control_KEYPONG_be) {
return "KEYPONG";
} else if (type_be == Control_GETSNODE_QUERY_be) {
return "GETSNODE_QUERY";
} else if (type_be == Control_GETSNODE_REPLY_be) {
return "GETSNODE_REPLY";
} else if (type_be == Control_RPATH_QUERY_be) {
return "RPATH_QUERY";
} else if (type_be == Control_RPATH_REPLY_be) {
return "RPATH_REPLY";
} else {
return "UNKNOWN";
}
}
struct Control_Header
{
/**
* This should be the one's complement checksum
* of the control packet with 0'd checksum field.
*/
uint16_t checksum_be;
/** The type of control message, eg: Control_ERROR. */
uint16_t type_be;
};
#define Control_Header_SIZE 4
Assert_compileTime(sizeof(struct Control_Header) == Control_Header_SIZE);
/**
* A return message which is treated specially by switches.
*
* 1 2 3
* 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* 0 | Checksum | Type |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* 4 | |
* + First Bytes of Packet Which Caused The Error +
* 8 | |
*
*/
struct Control
{
struct Control_Header header;
union {
struct Control_Error error;
struct Control_Ping ping;
struct Control_Ping pong;
struct Control_KeyPing keyPing;
struct Control_Ping keyPong;
struct Control_GetSnode getSnode;
struct Control_RPath rpath;
/** The control packet content. */
uint8_t bytes[4];
} content;
};
// Control_KeyPing is the largest structure and thus defines the length of the "content" union.
Assert_compileTime(
sizeof(struct Control) == (Control_Header_SIZE + Control_GetSnode_HEADER_SIZE)
);
#endif