diff --git a/picoquic/packet.c b/picoquic/packet.c index d9753b319a327e27c056ebdbd00845f6cab2ef8d..4bdb5d053e9a4beafe4b5d9ad637f9653e859382 100644 --- a/picoquic/packet.c +++ b/picoquic/packet.c @@ -4,4 +4,48 @@ * or a combination of source address, source port and partial context value. * - Has to find the sequence number, based on partial values and windows. * - For initial packets, has to perform version checks. - */ \ No newline at end of file + */ + +#include <stdint.h> +#include "picoquic.h" + +int picoquic_incoming_packet( + uint8_t * bytes, + uint32_t length, + struct soackaddr * addr_from) +{ + /* Parse the clear text header */ + uint8_t first_byte = bytes[0]; + uint64_t cnx_id; + uint32_t pn; + uint32_t vn; + uint32_t offset; + + if ((first_byte & 0x80) != 0) + { + /* long packet format */ + cnx_id = PICOPARSE_64(&bytes[1]); + pn = PICOPARSE_64(&bytes[9]); + vn = PICOPARSE_64(&bytes[13]); + offset = 17; + + /* Get CNX by CNX_ID */ + } + else + { + /* short format */ + if ((first_byte & 0x40) != 0) + { + cnx_id = PICOPARSE_64(&bytes[1]); + offset = 9; + /* need to identify CNX by CNX_ID */ + } + else + { + /* need to identify CNX by socket ID */ + offset = 1; + } + /* Get the length of pn from the CNX */ + } +} + diff --git a/picoquic/parse_util.c b/picoquic/parse_util.c new file mode 100644 index 0000000000000000000000000000000000000000..32e81c8feef57741610de4bb3b583529a6fa6176 --- /dev/null +++ b/picoquic/parse_util.c @@ -0,0 +1,3 @@ +#include "picoquic.h" + + diff --git a/picoquic/picohash.c b/picoquic/picohash.c index 7b65c2d799ae161c3aae6b9714bf903916715cb8..ae8fe07b6d2dffcc7a11f66d8c688b2ef42ca91d 100644 --- a/picoquic/picohash.c +++ b/picoquic/picohash.c @@ -115,4 +115,18 @@ void picohash_delete(picohash_table * hash_table, int delete_key_too) free(hash_table->hash_bin); free(hash_table); +} + + +uint64_t picohash_bytes(uint8_t * key, uint32_t length) +{ + uint64_t hash = 0xDEADBEEF; + + for (uint32_t i = 0; i < length; i++) + { + hash ^= key[i]; + hash ^= ((hash << 31) ^ (hash >> 17)); + } + + return hash; } \ No newline at end of file diff --git a/picoquic/picohash.h b/picoquic/picohash.h index a9e996a951ad1ff82866c6dcac41ba6b72bb6345..e7ce62ed29e1b54de179674d151a742cbdae598e 100644 --- a/picoquic/picohash.h +++ b/picoquic/picohash.h @@ -43,6 +43,8 @@ extern "C" { void picohash_delete(picohash_table * hash_table, int delete_key_too); + uint64_t picohash_bytes(uint8_t * key, uint32_t length); + #ifdef __cplusplus } diff --git a/picoquic/ctxhash.c b/picoquic/picoquic.cpp similarity index 100% rename from picoquic/ctxhash.c rename to picoquic/picoquic.cpp diff --git a/picoquic/picoquic.h b/picoquic/picoquic.h index 8129db283759f5ff29d89289adee931c20a00b3b..c3f354c8eae19d98cacf4cd2abf0c8d62837cb6f 100644 --- a/picoquic/picoquic.h +++ b/picoquic/picoquic.h @@ -2,32 +2,55 @@ #define PICOQUIC_H #include <stdint.h> +#include <winsock2.h> +#include <Ws2def.h> +#include <WS2tcpip.h> +#include "picohash.h" #ifdef __cplusplus extern "C" { #endif + /* + * QUIC context, defining the tables of connections, + * open sockets, etc. + */ + typedef struct _picoquic_quic + { + picohash_table * table_cnx_by_id; + picohash_table * table_cnx_by_net; + + } picoquic_quic; + /* * Connection context, and links between context and addresses */ typedef struct _picoquic_cnx { + picoquic_quic * quic; struct _picoquic_cnx * next_in_table; + struct _picoquic_cnx_id * first_cnx_id; + struct _picoquic_net_id * first_net_id; + uint64_t last_sequence_sent; uint64_t last_sequence_received; - } picoquic_cnx; - /* - * Structures used in the hash table of connections - */ - typedef struct _picoquic_cnx_id - { - struct _picoquic_cnx * next_in_bin; + /* QUIC context create and dispose */ + picoquic_quic * picoquic_create(uint32_t nb_connections); + void picoquic_free(picoquic_quic * quic); + + /* Context retrieval functions */ + picoquic_cnx * get_cnx_by_id(picoquic_quic * quic, uint64_t cnx_id); + picoquic_cnx * get_cnx_by_net(picoquic_quic * quic, struct sockaddr* addr); + +/* Parsing macros */ +#define PICOPARSE_16(b) ((((uint16_t)(b)[0])<<8)|(b)[1]) +#define PICOPARSE_32(b) ((((uint32_t)PICOPARSE_16(b))<<16)|PICOPARSE_16((b)+2)) +#define PICOPARSE_64(b) ((((uint64_t)PICOPARSE_32(b))<<16)|PICOPARSE_32((b)+4)) - } picoquic_cnx_id; #ifdef __cplusplus diff --git a/picoquic/picoquic.vcxproj b/picoquic/picoquic.vcxproj index 23d9d53274d65e06c7ea26c5c3afa60097442e74..63c7f852ebdaaf6a9b5e4207e839adf263e877ba 100644 --- a/picoquic/picoquic.vcxproj +++ b/picoquic/picoquic.vcxproj @@ -131,8 +131,9 @@ <Text Include="ReadMe.txt" /> </ItemGroup> <ItemGroup> - <ClCompile Include="ctxhash.c" /> + <ClCompile Include="quicctx.c" /> <ClCompile Include="packet.c" /> + <ClCompile Include="parse_util.c" /> <ClCompile Include="picohash.c" /> </ItemGroup> <ItemGroup> diff --git a/picoquic/picoquic.vcxproj.filters b/picoquic/picoquic.vcxproj.filters index 7ec50e0a203645c9947b45a83b34c1b6bb0d18e4..5dd14dd205d346a17ccaedf082dd02ec145c2673 100644 --- a/picoquic/picoquic.vcxproj.filters +++ b/picoquic/picoquic.vcxproj.filters @@ -21,10 +21,13 @@ <ClCompile Include="packet.c"> <Filter>Source Files</Filter> </ClCompile> - <ClCompile Include="ctxhash.c"> + <ClCompile Include="picohash.c"> <Filter>Source Files</Filter> </ClCompile> - <ClCompile Include="picohash.c"> + <ClCompile Include="parse_util.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="quicctx.c"> <Filter>Source Files</Filter> </ClCompile> </ItemGroup> diff --git a/picoquic/quicctx.c b/picoquic/quicctx.c new file mode 100644 index 0000000000000000000000000000000000000000..cfd098c9ca110acc61f6310a6c6d88c2ffe35e6c --- /dev/null +++ b/picoquic/quicctx.c @@ -0,0 +1,139 @@ +#include "picoquic.h" + +/* +* Structures used in the hash table of connections +*/ +typedef struct _picoquic_cnx_id +{ + uint64_t cnx_id; + picoquic_cnx * cnx; + struct picoquic_cnx_id * next_cnx_id; +} picoquic_cnx_id; + +typedef struct _picoquic_net_id +{ + uint64_t cnx_id; + struct sockaddr_storage saddr; + struct picoquic_cnx_id * next_cnx_id; +} picoquic_net_id; + +/* Hash and compare for CNX hash tables */ +static uint64_t picoquic_cnx_id_hash(void * key) +{ + picoquic_cnx_id * cid = (picoquic_cnx_id *)key; + + // TODO: should scramble the value for security and DOS protection + + return cid->cnx_id; +} + +static int picoquic_cnx_id_compare(void * key1, void * key2) +{ + picoquic_cnx_id * cid1 = (picoquic_cnx_id *)key1; + picoquic_cnx_id * cid2 = (picoquic_cnx_id *)key2; + + return (cid1->cnx_id == cid2->cnx_id) ? 0 : -1; +} + +static uint64_t picoquic_net_id_hash(void * key) +{ + picoquic_net_id * net = (picoquic_net_id *)key; + + return picohash_bytes(&net->saddr, sizeof(net->saddr)); +} + +static int picoquic_net_id_compare(void * key1, void * key2) +{ + picoquic_net_id * net1 = (picoquic_net_id *)key1; + picoquic_net_id * net2 = (picoquic_net_id *)key2; + + return memcmp(&net1->saddr, &net2->saddr, sizeof(net1->saddr)); +} + +/* QUIC context create and dispose */ +picoquic_quic * picoquic_create(uint32_t nb_connections) +{ + picoquic_quic * quic = (picoquic_quic *)malloc(sizeof(picoquic_quic)); + + if (quic != NULL) + { + /* TODO: winsock init */ + /* TODO: open UDP sockets - maybe */ + /* TODO: chain of connections - maybe */ + + quic->table_cnx_by_id = picohash_create(nb_connections * 4, + picoquic_cnx_id_hash, picoquic_cnx_id_compare); + + quic->table_cnx_by_net = picohash_create(nb_connections * 4, + picoquic_net_id_hash, picoquic_net_id_compare); + + if (quic->table_cnx_by_id == NULL || + quic->table_cnx_by_net == NULL) + { + picoquic_free(quic); + quic = NULL; + } + } + + return quic; +} + +void picoquic_free(picoquic_quic * quic) +{ + if (quic != NULL) + { + /* TODO: delete all the connection contexts */ + /* TODO: close the network connections */ + + if (quic->table_cnx_by_id != NULL) + { + picohash_delete(quic->table_cnx_by_id, 1); + } + + if (quic->table_cnx_by_net != NULL) + { + picohash_delete(quic->table_cnx_by_net, 1); + } + } +} + +/* Context retrieval functions */ +picoquic_cnx * get_cnx_by_id(picoquic_quic * quic, uint64_t cnx_id) +{ + picoquic_cnx * ret = NULL; + picohash_item * item; + picoquic_cnx_id key = { 0 }; + key.cnx_id = cnx_id; + + item = picohash_retrieve(quic->table_cnx_by_id, &key); + + if (item != NULL) + { + ret = ((picoquic_cnx_id *)item->key)->cnx; + } + return ret; +} + +picoquic_cnx * get_cnx_by_net(picoquic_quic * quic, struct sockaddr* addr) +{ + picoquic_cnx * ret = NULL; + picohash_item * item; + picoquic_net_id key = { 0 }; + + if (addr->sa_family == AF_INET) + { + memcpy(&key.saddr, addr, sizeof(struct sockaddr_in)); + } + else + { + memcpy(&key.saddr, addr, sizeof(struct sockaddr_in6)); + } + + item = picohash_retrieve(quic->table_cnx_by_id, &key); + + if (item != NULL) + { + ret = ((picoquic_cnx_id *)item->key)->cnx; + } + return ret; +} diff --git a/picoquictest/hashtest.c b/picoquictest/hashtest.c index d58b6d7272dda0f93d305fde4027370eb2dd43d2..a90a6594d620796a85e0c8af912d4a69f3e48ffc 100644 --- a/picoquictest/hashtest.c +++ b/picoquictest/hashtest.c @@ -1,4 +1,6 @@ #include "../picoquic/picohash.h" +#include <stdlib.h> +#include <malloc.h> struct hashtestkey { @@ -20,7 +22,7 @@ static int hashtest_compare(void * v1, void *v2) return (k1->x == k2->x) ? 0 : -1; } -static picohash_item * hashtest_item(uint64_t x) +static struct hashtestkey * hashtest_item(uint64_t x) { struct hashtestkey * p = (struct hashtestkey *) malloc(sizeof(struct hashtestkey));