Merge branch 'dev-felipe' into dev-nelson
This commit is contained in:
commit
4c2ebba255
4
src/Notes.md
Normal file
4
src/Notes.md
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
# Notes et recherches sur le projet
|
||||||
|
|
||||||
|
Telecharger la librarie OpenSSl avec 'sudo apt-get install libssl-dev'
|
||||||
|
Utiliser 'gcc -o {exec} {fichier.c} -lssl -lcrypto' pour utiliser la librarie OpenSSL
|
5
src/README.md
Normal file
5
src/README.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# dazibao
|
||||||
|
|
||||||
|
Le but de ce projet est d’implémenter un dazibao (« journal à grandes lettres »), semblable à
|
||||||
|
un « mur » de réseau social, mais de façon complètement distribuée. Le protocole est basé sur un
|
||||||
|
algorithme non-fiable d’inondation.
|
60
src/hash.c
Normal file
60
src/hash.c
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
#include "hash.h"
|
||||||
|
|
||||||
|
// Hash a single data
|
||||||
|
void hash_data(pub_data *data, unsigned char *buf) {
|
||||||
|
// All three fields are concatenated into a single buffer
|
||||||
|
int totlen = data->length + 10;
|
||||||
|
unsigned char concat[totlen];
|
||||||
|
concat_data(data, concat);
|
||||||
|
|
||||||
|
// The resulting buf is hashed and put into a buffer
|
||||||
|
unsigned char hash[SHA256_DIGEST_LENGTH];
|
||||||
|
SHA256(concat, totlen, hash);
|
||||||
|
|
||||||
|
// Put truncated hash into buf
|
||||||
|
hash_trunc(hash, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hash every data contained in data_list then return a network hash
|
||||||
|
void hash_network(list *data_list, unsigned char *buf) {
|
||||||
|
unsigned char *concat = (unsigned char*) malloc(0);
|
||||||
|
unsigned char hash[SHA256_DIGEST_LENGTH];
|
||||||
|
int totlen = 0;
|
||||||
|
list *tmp = data_list;
|
||||||
|
|
||||||
|
// Hash every known data and concatenate it to buffer concat
|
||||||
|
while(tmp != NULL) {
|
||||||
|
hash_data((pub_data*) tmp->data, hash);
|
||||||
|
concat_hash(concat, hash, totlen);
|
||||||
|
totlen += 16;
|
||||||
|
tmp = tmp->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hash all of concat to obtain the network hash
|
||||||
|
SHA256(concat, totlen, hash);
|
||||||
|
|
||||||
|
// Put truncated hash into buf
|
||||||
|
hash_trunc(hash, buf);
|
||||||
|
|
||||||
|
// Get rid of concat
|
||||||
|
free(concat);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Truncate 32 octet hash to 16 octets
|
||||||
|
void hash_trunc(unsigned char *hash32oct, unsigned char *buf) {
|
||||||
|
// Copy the first 16 octets from hash32oct
|
||||||
|
memcpy(buf, hash32oct, 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Concat all fields of data and put them in buf
|
||||||
|
void concat_data(pub_data *data, unsigned char *buf) {
|
||||||
|
memcpy(buf, &(data->id), 8);
|
||||||
|
memcpy(buf+8, &(data->seqno), 2);
|
||||||
|
memcpy(buf+10, data->data, data->length);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Concat hash2 to hash1 (hash1 is modified)
|
||||||
|
void concat_hash(unsigned char *hash1, unsigned char *hash2, size_t size) {
|
||||||
|
hash1 = (unsigned char*) realloc(hash1, size + 16);
|
||||||
|
memcpy(hash1+size, hash2, 16);
|
||||||
|
}
|
23
src/hash.h
Normal file
23
src/hash.h
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#ifndef HASH_H
|
||||||
|
#define HASH_H
|
||||||
|
|
||||||
|
#include <openssl/sha.h>
|
||||||
|
#include "node.h"
|
||||||
|
#include "tlv.h"
|
||||||
|
|
||||||
|
// Hash a single data
|
||||||
|
void hash_data(pub_data *data, unsigned char *buf);
|
||||||
|
|
||||||
|
// Hash every data contained in data_list then return a network hash
|
||||||
|
void hash_network(list *data_list, unsigned char *buf);
|
||||||
|
|
||||||
|
// Truncate 32 octet hash to 16 octets
|
||||||
|
void hash_trunc(unsigned char *hash256bit, unsigned char *buf);
|
||||||
|
|
||||||
|
// Concat all fields of data and put them in buf
|
||||||
|
void concat_data(pub_data *data, unsigned char *buf);
|
||||||
|
|
||||||
|
// Concat hash2 to hash1 (hash1 is modified)
|
||||||
|
void concat_hash(unsigned char *hash1, unsigned char *hash2, size_t size);
|
||||||
|
|
||||||
|
#endif
|
1
src/install.sh
Executable file
1
src/install.sh
Executable file
@ -0,0 +1 @@
|
|||||||
|
sudo apt-get install libssl-dev
|
193
src/node.c
193
src/node.c
@ -217,20 +217,207 @@ void listen_for_packets(){
|
|||||||
// struct tlv_list received_tlvs;
|
// struct tlv_list received_tlvs;
|
||||||
// if (validate_tlvs(formated_rec_datagram) < 0)
|
// if (validate_tlvs(formated_rec_datagram) < 0)
|
||||||
|
|
||||||
|
<<<<<<< HEAD
|
||||||
int nbr_success_tlv = work_with_tlvs(formated_rec_datagram, &req, sender);
|
int nbr_success_tlv = work_with_tlvs(formated_rec_datagram, &req, sender);
|
||||||
if (nbr_success_tlv < 0){
|
if (nbr_success_tlv < 0){
|
||||||
perror(">> Error while treating the TLVs of the packet.");
|
perror(">> Error while treating the TLVs of the packet.");
|
||||||
printf(">> Managed to deal with %i TLVs\n", -nbr_success_tlv );
|
printf(">> Managed to deal with %i TLVs\n", -nbr_success_tlv );
|
||||||
} else {
|
} else {
|
||||||
printf(">> Done working with the TLVs of the packet, listenin for new packets.\n");
|
printf(">> Done working with the TLVs of the packet, listenin for new packets.\n");
|
||||||
|
=======
|
||||||
|
// If the sender is not in the neighbourhood, and we have 15 neighbours, we
|
||||||
|
// ignore the packet. Otherwise, we add him to the neighbourhood, marked as
|
||||||
|
// temporary.
|
||||||
|
int update_neighbours(){
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// We need to make sure the TLV announces a length that will no go onto
|
||||||
|
// another tlv, as we might end up reading bullshit.
|
||||||
|
int validate_tlv(char *data, int pos, short packet_len){
|
||||||
|
char type = data[pos];
|
||||||
|
|
||||||
|
// Nothing to do in this case
|
||||||
|
if(type == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Check that we can read a length
|
||||||
|
if(pos + 1 >= packet_len)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
unsigned char tlv_len = data[pos+1];
|
||||||
|
|
||||||
|
// Check that the tlv does not exceed the packet length
|
||||||
|
if(pos + length >= packet_len)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
// Returns the type of the tlv or -1 if something went wrong
|
||||||
|
switch(type) {
|
||||||
|
case 1:
|
||||||
|
return 1;
|
||||||
|
case 2:
|
||||||
|
if(tlv_len != LEN_NEIGHBOUR_REQ) return -1;
|
||||||
|
return 2;
|
||||||
|
case 3:
|
||||||
|
if(tlv_len != LEN_NEIGHBOUR) return -1;
|
||||||
|
return 3;
|
||||||
|
case 4:
|
||||||
|
if(tlv_len != LEN_NETWORK_HASH) return -1;
|
||||||
|
return 4;
|
||||||
|
case 5:
|
||||||
|
if(tlv_len != LEN_NETWORK_STATE_REQ) return -1;
|
||||||
|
return 5;
|
||||||
|
case 6:
|
||||||
|
if(tlv_len != LEN_NODE_HASH) return -1;
|
||||||
|
return 6;
|
||||||
|
case 7:
|
||||||
|
if(tlv_len != LEN_NODE_STATE_REQ) return -1;
|
||||||
|
return 7;
|
||||||
|
case 8:
|
||||||
|
if(tlv_len < MIN_LEN_NODE_STATE || tlv_len > MAX_LEN_NODE_STATE) return -1;
|
||||||
|
return 8;
|
||||||
|
case 9:
|
||||||
|
return 9;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We then look at the differents TLVs in the packet.
|
||||||
|
void work_with_tlvs(char *data, short packet_len){
|
||||||
|
int pos = 0;
|
||||||
|
unsigned char tlv_len;
|
||||||
|
tlv tmp_tlv;
|
||||||
|
|
||||||
|
while(pos < packet_len) {
|
||||||
|
switch(validate_tlv(data, pos, packet_len)) {
|
||||||
|
case 0:
|
||||||
|
// We received a padding tlv so it is ignored
|
||||||
|
pos += 1;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
// We received a padding tlv so it is ignored
|
||||||
|
tlv_len = data[pos+1];
|
||||||
|
pos += tlv_len + 2;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
// We received a neighbour request so a random neighbor tlv has to be sent
|
||||||
|
tlv_len = data[pos+1];
|
||||||
|
pos += tlv_len + 2;
|
||||||
|
|
||||||
|
// Send a neighbour tlv
|
||||||
|
neighbour_peer *random = get_random_neighbour();
|
||||||
|
build_neighbour(&tmp_tlv, random->ip, random->port);
|
||||||
|
|
||||||
|
// NOT FINISHED - What packet is it added to?
|
||||||
|
add_tlv(packet, &tmp_tlv, 3);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
// We received a neighbour tlv so a tlv network hash is sent to that address
|
||||||
|
neighbour* cur_tlv = ((neighbour*) data) + pos;
|
||||||
|
struct in6_addr ip = cur_tlv->ip;
|
||||||
|
short port = cur_tlv->port;
|
||||||
|
|
||||||
|
tlv_len = data[pos+1];
|
||||||
|
pos += tlv_len + 2;
|
||||||
|
|
||||||
|
// Build network hash
|
||||||
|
unsigned char hash[16];
|
||||||
|
hash_network(neighbour_list, hash);
|
||||||
|
build_network_hash(&tmp_tlv, hash);
|
||||||
|
|
||||||
|
// NOT FINISHED - What packet is it added to?
|
||||||
|
add_tlv(packet, &tmp_tlv, 4);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
// We reveived a network hash tlv so
|
||||||
|
tlv_len = data[pos+1];
|
||||||
|
pos += tlv_len +2;
|
||||||
|
|
||||||
|
// NOT FINISHED - Where is network_hash?
|
||||||
|
build_neighbour(&tmp_tlv, network_hash);
|
||||||
|
// NOT FINISHED - What packet is it added to?
|
||||||
|
add_tlv(packet, &tmp_tlv, 4);
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
// We received a network state request tlv so a series of tlv node hash have to be sent for each data known
|
||||||
|
pos += 2;
|
||||||
|
|
||||||
|
// NOT FINISHED - for each known data
|
||||||
|
list *tmp_list = data_list;
|
||||||
|
pub_data *tmp_data;
|
||||||
|
|
||||||
|
while(tmp_list != NULL) {
|
||||||
|
tmp_data = (pub_data*) tmp_list->data;
|
||||||
|
build_node_hash(&tmp_tlv, tmp_data->id, tmp_data->seqno);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
// We received a node hash tlv
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
// We received a node state request tlv
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
// We received a node state tlv
|
||||||
|
break;
|
||||||
|
case 9:
|
||||||
|
// We received a warning tlv so it's message is printed
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return ;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char const *argv[]) {
|
|
||||||
int continue = 1;
|
|
||||||
|
|
||||||
while(continue != 0){
|
|
||||||
|
void work_with_tlvs(struct tlvs_list receivied_tlvs){
|
||||||
|
|
||||||
|
// For every TLV,
|
||||||
|
// We make sure the TLV is legal.
|
||||||
|
if(!validate_tlvs(tlv)){
|
||||||
|
perror(">> Invalid TLV receivied, it will be ignored.");
|
||||||
|
>>>>>>> dev-felipe
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get list length
|
||||||
|
int len_list(list *l) {
|
||||||
|
int len = 0;
|
||||||
|
list *tmp = l;
|
||||||
|
|
||||||
|
while(tmp != NULL) {
|
||||||
|
tmp = tmp->next;
|
||||||
|
len++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get a random neighbour
|
||||||
|
neighbour_peer *get_random_neighbour() {
|
||||||
|
// Get a random number
|
||||||
|
time_t t;
|
||||||
|
srand((unsigned) time(&t));
|
||||||
|
int n = rand() % len_list(neighbour_list);
|
||||||
|
|
||||||
|
// Get nth neighbour
|
||||||
|
list *tmp = neighbour_list;
|
||||||
|
|
||||||
|
for(int i=0; i<n; i++) {
|
||||||
|
tmp = tmp->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (neighbour_peer*) tmp->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, const char *argv[]) {
|
||||||
|
int cont = 1;
|
||||||
|
|
||||||
|
while(cont){
|
||||||
|
|
||||||
// We create the neighbourhood table
|
// We create the neighbourhood table
|
||||||
neighbour_peer neighbour_list[NEIGHBOUR_MAX];
|
neighbour_peer neighbour_list[NEIGHBOUR_MAX];
|
||||||
|
32
src/node.h
32
src/node.h
@ -3,9 +3,16 @@
|
|||||||
#ifndef NODE_H
|
#ifndef NODE_H
|
||||||
#define NODE_H
|
#define NODE_H
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sys/types.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include "tlv.h"
|
#include "tlv.h"
|
||||||
|
#include "hash.h"
|
||||||
|
|
||||||
// On which port do we listen to
|
// On which port do we listen to
|
||||||
#define LISTEN_PORT 1212
|
#define LISTEN_PORT 1212
|
||||||
@ -36,11 +43,22 @@ typedef struct neighbour_peer {
|
|||||||
* Di : the data of the message 192 bytes
|
* Di : the data of the message 192 bytes
|
||||||
*/
|
*/
|
||||||
|
|
||||||
typedef struct message {
|
typedef struct pub_data {
|
||||||
long node_id_publisher;
|
unsigned char length;
|
||||||
|
long id;
|
||||||
short seqno;
|
short seqno;
|
||||||
char *data;
|
char *data;
|
||||||
} message;
|
} pub_data;
|
||||||
|
|
||||||
|
// General list
|
||||||
|
typedef struct list {
|
||||||
|
void *data;
|
||||||
|
void *next;
|
||||||
|
} list;
|
||||||
|
|
||||||
|
// Static variables
|
||||||
|
static list *data_list;
|
||||||
|
static list *neighbour_list;
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
|
|
||||||
@ -55,6 +73,10 @@ int update_neighbours();
|
|||||||
|
|
||||||
int work_with_tlvs(struct packet received_packet, char * data_from_packet[], struct sockaddr_in6 sender);
|
int work_with_tlvs(struct packet received_packet, char * data_from_packet[], struct sockaddr_in6 sender);
|
||||||
|
|
||||||
|
void add_tlv(packet *packet, tlv *tlv, char type);
|
||||||
|
|
||||||
|
int send_packet(struct tlv_list tlvs_to_send, );
|
||||||
|
|
||||||
// threaded functions
|
// threaded functions
|
||||||
|
|
||||||
void t_ask_for_more_peers();
|
void t_ask_for_more_peers();
|
||||||
@ -64,8 +86,8 @@ void t_update_neighbours();
|
|||||||
void t_get_network_state();
|
void t_get_network_state();
|
||||||
|
|
||||||
// Helper functions
|
// Helper functions
|
||||||
char * hash();
|
int len_list(list *l);
|
||||||
|
|
||||||
short * get_seq_no(short s, int n);
|
neighbour_peer *get_random_neighbour();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -22,8 +22,8 @@ cmd_token parse_cmd() {
|
|||||||
token.type = NETWORK_STATE_REQ;
|
token.type = NETWORK_STATE_REQ;
|
||||||
else if(strcmp("node state", arg) == 0)
|
else if(strcmp("node state", arg) == 0)
|
||||||
token.type = NODE_STATE_REQ;
|
token.type = NODE_STATE_REQ;
|
||||||
} else if(strcmp("send", cmd) == 0) {
|
} else if(strcmp("post", cmd) == 0) {
|
||||||
token.type = SEND;
|
token.type = POST;
|
||||||
//arg[192] = 0;
|
//arg[192] = 0;
|
||||||
strcpy(token.arg, arg);
|
strcpy(token.arg, arg);
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
#define PARSER_H
|
#define PARSER_H
|
||||||
|
|
||||||
typedef enum cmd_type {
|
typedef enum cmd_type {
|
||||||
NEIGHBOUR_REQ, NETWORK_STATE_REQ, NODE_STATE_REQ, SEND, ERROR
|
NEIGHBOUR_REQ, NETWORK_STATE_REQ, NODE_STATE_REQ, POST, ERROR
|
||||||
} cmd_type;
|
} cmd_type;
|
||||||
|
|
||||||
typedef struct cmd_token {
|
typedef struct cmd_token {
|
||||||
|
@ -12,11 +12,11 @@ int build_tlv(tlv *tlv, cmd_token token) {
|
|||||||
case NODE_STATE_REQ:
|
case NODE_STATE_REQ:
|
||||||
// a remplir
|
// a remplir
|
||||||
break;
|
break;
|
||||||
case SEND:
|
case POST:
|
||||||
// a remplir
|
// a remplir
|
||||||
break;
|
break;
|
||||||
case ERROR:
|
case ERROR:
|
||||||
printf("Wrong format, use 'req {neighbour | network state | node state}' or 'send {message}'");
|
printf("Wrong format, use 'req {neighbour | network state | node state}' or 'post {message}'");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
32
src/tlv.h
32
src/tlv.h
@ -1,10 +1,20 @@
|
|||||||
|
#ifndef TLV_H
|
||||||
|
#define TLV_H
|
||||||
|
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
|
#include "hash.h"
|
||||||
|
|
||||||
#ifndef TLV_H
|
#define LEN_NEIGHBOUR_REQ 0
|
||||||
#define TLV_H
|
#define LEN_NEIGHBOUR 18
|
||||||
|
#define LEN_NETWORK_HASH 16
|
||||||
|
#define LEN_NETWORK_STATE_REQ 0
|
||||||
|
#define LEN_NODE_HASH 26
|
||||||
|
#define LEN_NODE_STATE_REQ 8
|
||||||
|
#define MIN_LEN_NODE_STATE 26
|
||||||
|
#define MAX_LEN_NODE_STATE 218
|
||||||
|
|
||||||
// 8 octets min (struct pointer 4 octets), 1024 octets max
|
// 8 octets min (struct pointer 4 octets), 1024 octets max
|
||||||
typedef struct packet {
|
typedef struct packet {
|
||||||
@ -23,7 +33,7 @@ typedef struct pad1 {
|
|||||||
typedef struct padn {
|
typedef struct padn {
|
||||||
unsigned char type;
|
unsigned char type;
|
||||||
unsigned char length;
|
unsigned char length;
|
||||||
char *mbz;
|
char mbz[256];
|
||||||
} padn;
|
} padn;
|
||||||
|
|
||||||
// 2 octets
|
// 2 octets
|
||||||
@ -76,14 +86,14 @@ typedef struct node_state {
|
|||||||
long node_id;
|
long node_id;
|
||||||
short seqno;
|
short seqno;
|
||||||
char node_hash[16];
|
char node_hash[16];
|
||||||
char *data;
|
char data[192];
|
||||||
} node_state;
|
} node_state;
|
||||||
|
|
||||||
// 2 octets min, 258 ocets max (unsigned char 0 -> 255)
|
// 2 octets min, 258 ocets max (unsigned char 0 -> 255)
|
||||||
typedef struct warning {
|
typedef struct warning {
|
||||||
unsigned char type;
|
unsigned char type;
|
||||||
unsigned char length;
|
unsigned char length;
|
||||||
char *message;
|
char message[256];
|
||||||
} warning;
|
} warning;
|
||||||
|
|
||||||
typedef union tlv {
|
typedef union tlv {
|
||||||
@ -99,20 +109,14 @@ typedef union tlv {
|
|||||||
warning *warning;
|
warning *warning;
|
||||||
} tlv;
|
} tlv;
|
||||||
|
|
||||||
typedef struct tlv_list {
|
// build tlv from token
|
||||||
union tlv one_tlv;
|
|
||||||
struct tlv_list * next;
|
|
||||||
} tlv_list;
|
|
||||||
|
|
||||||
|
|
||||||
// creer un tlv
|
|
||||||
int build_tlv(tlv *tlv, cmd_token token);
|
int build_tlv(tlv *tlv, cmd_token token);
|
||||||
|
|
||||||
// creer un tlv specifique
|
// build specific tlv
|
||||||
int build_pad1(tlv *tlv);
|
int build_pad1(tlv *tlv);
|
||||||
int build_padn(tlv *tlv, size_t len);
|
int build_padn(tlv *tlv, size_t len);
|
||||||
int build_neighbour_req(tlv *tlv);
|
int build_neighbour_req(tlv *tlv);
|
||||||
int build_neighbour(tlv *tlv, struct in6_addr ip, short seqno);
|
int build_neighbour(tlv *tlv, struct in6_addr ip, short port);
|
||||||
int build_network_hash(tlv *tlv, char *network_hash);
|
int build_network_hash(tlv *tlv, char *network_hash);
|
||||||
int build_network_state_req(tlv *tlv);
|
int build_network_state_req(tlv *tlv);
|
||||||
int build_node_hash(tlv *tlv, long node_id, short seqno, char *node_hash);
|
int build_node_hash(tlv *tlv, long node_id, short seqno, char *node_hash);
|
||||||
|
BIN
src/énoncé.pdf
Normal file
BIN
src/énoncé.pdf
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user