Browse Source

Suppression de anneau.c, suppression des warnings de compilation et ajout d'un fichier readme mal rédigé

master
Squiz 6 years ago
parent
commit
312088ee77
4 changed files with 41 additions and 566 deletions
  1. +1
    -6
      Makefile
  2. +0
    -555
      anneau.c
  3. +5
    -5
      node.c
  4. +35
    -0
      readme

+ 1
- 6
Makefile View File

@@ -1,7 +1,7 @@
CC=gcc
CFLAGS=-Wall -std=c99 -D_BSD_SOURCE
LDFLAGS=-lpthread
EXECS=node anneau
EXECS=node

debug: CFLAGS+= -g -Ddebug

@@ -13,14 +13,9 @@ debug: all
node: node.o interface.o
$(CC) $^ $(LDFLAGS) -o $@

anneau: anneau.o
$(CC) $^ $(LDFLAGS) -o $@


%.o: %.c $(wildcard *.h) Makefile
$(CC) $< $(CFLAGS) -c -o $@


.PHONY: clean, mproper

clean:

+ 0
- 555
anneau.c View File

@@ -1,555 +0,0 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <pthread.h>
#include <signal.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <inttypes.h>

#define UDP_LISTEN_PORT 4242
#define UDP_DEFAULT_CONNECT_ADDR "127.0.0.1"
#define UDP_DEFAULT_CONNECT_PORT 4242

#define MY_ADDR 0xabcd0123
#define TRAME_MAX_LENGTH 65503 /* la taille totale de la trame est sur 16 bits, on ne peut pas dépasser 65507 octets à cause d'udp */

#define DEFAULT_TIME_BEFORE_DISCOVERY 1
#define NB_TURN_BEFORE_DISCOVERY 5

/*
trame
|00|01|02|03|04|05|06|07||08|09|10|11|12|13|14|15||16|17|18|19|20|21|22|23||24|25|26|27|28|29|30|31|
| 0 || 1 || 2 || 3 |
| type || taille totale || données…

paquet
|00|01|02|03|04|05|06|07||08|09|10|11|12|13|14|15||16|17|18|19|20|21|22|23||24|25|26|27|28|29|30|31|
| 0 || 1 || 2 || 3 |
| adresse destination |
| adresse source |
| taille du paquet entete comprise || taille du message |
| numéro du paquet || type || somme de controle sur les données |
| données_ |

*/
enum boolean {false, true};

struct watch_stat_t {
enum boolean received_trame;
unsigned int time_before_discovery;
};

enum trame_type_t {
TRAME_TOKEN,
TRAME_DISCOVERY
};

struct trame_t {
enum trame_type_t type;
u_int16_t length;
void *data;
};

enum packet_type_t {
PACKET_DATA,
PACKET_DISCOVERY, /* paquet d'une trame discovery */
PACKET_JOIN, /* paquet qui demande le branchement d'un cable */
PACKET_LEAVE /* paquet qui demande le débranchement d'un cable */
};

struct packet_t {
u_int32_t addr_dest;
u_int32_t addr_src;
u_int16_t packet_length;
u_int16_t message_length;
u_int8_t fragment;
enum packet_type_t type;
u_int16_t checksum;
void *data;
};


/* variables globales */
pthread_mutex_t mutex_in, mutex_out, mutex_stat;
enum boolean quit;
int fd_sock;
struct sockaddr_in sock_listen, sock_in, sock_out;

struct watch_stat_t watch_stat;
char buffer_in[TRAME_MAX_LENGTH], buffer_out[TRAME_MAX_LENGTH];

/* prototype */
void quit_signal_handler(int sig);
void* watchdog_discovery(void *argv);
int send_trame(const struct trame_t *const trame_p);
int recv_trame(struct trame_t *const trame_p, enum boolean extract_data);
int add_packet(struct trame_t *const trame_p, const struct packet_t *const packet_p);
int retr_packet(struct trame_t *trame_p, struct packet_t **packet_pp, enum boolean extract_data);
u_int16_t checksum(const struct packet_t *const packet);

/* couches :
1 : niveau physique : gestion de l'anneau par sockets udp
2 : circulation de la trame
3 : encapsulation de paquets dans la trame
*/

void quit_signal_handler(int sig) {
sig = 0; /* pour compiler sans warning en pedantic */
quit = true;
}


void* watchdog_discovery(void *argv) {
unsigned int time_to_sleep;
enum boolean send_discovery;
struct trame_t trame_discovery;
struct packet_t packet_discovery;
argv=NULL; /* pour compiler sans warning en pedantic */

/* on prépare la trame */
trame_discovery.type = TRAME_DISCOVERY;
trame_discovery.length = 3;
trame_discovery.data = NULL;

/* on prépare le paquet qu'on met dans la trame */
packet_discovery.addr_dest = MY_ADDR;
packet_discovery.addr_src = MY_ADDR;
packet_discovery.packet_length = 16;
packet_discovery.message_length = 0;
packet_discovery.fragment = 0;
packet_discovery.type = PACKET_DISCOVERY;
packet_discovery.checksum = checksum(&packet_discovery);
packet_discovery.data = NULL;

/* on insère le paquet dans la trame */
if(add_packet(&trame_discovery, &packet_discovery) == -1) {
#ifdef debug
fputs("impossible d'ajouter le paquet de discovery dans la trame\n", stderr);
#endif
quit = 1;
pthread_exit(NULL); /* il faudrait peut etre retourner une erreur */
}

do {
pthread_mutex_lock(&mutex_stat);
time_to_sleep = watch_stat.time_before_discovery;
watch_stat.received_trame = false;
pthread_mutex_unlock(&mutex_stat);
sleep(time_to_sleep);
pthread_mutex_lock(&mutex_stat);
send_discovery = !watch_stat.received_trame;
pthread_mutex_unlock(&mutex_stat);
if(send_discovery) {
#ifdef debug
fputs("envoie d'une trame de discovery\n", stderr);
#endif
send_trame(&trame_discovery);
}
} while(!quit);
pthread_exit(NULL);
}


int send_trame(const struct trame_t *const trame_p) {
int res;
u_int16_t length;
pthread_mutex_lock(&mutex_out);
/* on remplit le buffer */
length = htons(trame_p->length);
memcpy(buffer_out, &(trame_p->type), 1);
memcpy(buffer_out+1, &(length), 2);
memcpy(buffer_out+3, trame_p->data, (size_t) ((trame_p->length)-3)); /* on enlève les 3 octets d'entete */
/* on envoie la trame */
if(( res = sendto(fd_sock, buffer_out, trame_p->length, 0, (struct sockaddr*)&sock_out, sizeof(struct sockaddr_in))) == -1) {
#ifdef debug
perror("sendto()");
#endif
}
pthread_mutex_unlock(&mutex_out);
return res;
}


int recv_trame(struct trame_t *const trame_p, enum boolean extract_data) {
static time_t previous_time = 0;
socklen_t sock_length;
ssize_t recvfrom_length;
pthread_mutex_lock(&mutex_in);
/* on reçoit la trame */
if((recvfrom_length = recvfrom(fd_sock, buffer_in, sizeof(buffer_in)-1, 0, (struct sockaddr*)&sock_in, &sock_length)) == -1) {
#ifdef debug
perror("recvfrom()");
#endif
pthread_mutex_unlock(&mutex_in);
return -1;
}

/* on retient qu'on a reçu une trame et on adapte le temps d'attente du watchdog */
pthread_mutex_lock(&mutex_stat);
watch_stat.received_trame = true;
/* adaptation du temps d'attente */
if(previous_time)
watch_stat.time_before_discovery = NB_TURN_BEFORE_DISCOVERY*( (watch_stat.time_before_discovery+(time(NULL)-previous_time))/2 );
previous_time = time(NULL);
pthread_mutex_unlock(&mutex_stat);

/* on initialise la trame */
memset(trame_p, 0, sizeof(struct trame_t));
/* on lit les champs de l'entete */
memcpy(&(trame_p->type), buffer_in, 1);
memcpy(&(trame_p->length), buffer_in+1, 2);
trame_p->length = ntohs(trame_p->length);
/* on vérifie la taille */
if(recvfrom_length != trame_p->length ) {
#ifdef debug
fputs("taille de trame invalide\n", stderr);
#endif
pthread_mutex_unlock(&mutex_in);
return -1;
}
/* s'il y a des donées, on les récupère */
if(extract_data && trame_p->length > 3) { /* taille de l'entete de la trame*/
if((trame_p->data = realloc(trame_p->data,(trame_p->length)-3)) == NULL) {
#ifdef debug
fputs("bad alloc\n", stderr);
#endif
pthread_mutex_unlock(&mutex_in);
return -1;
}
memcpy(trame_p->data, buffer_in+3, (size_t) ((trame_p->length)-3));
} else
trame_p->data = NULL;
pthread_mutex_unlock(&mutex_in);
return 1;
}

int add_packet(struct trame_t *const trame_p, const struct packet_t *const packet_p) {
char *new_data;
u_int16_t size;

u_int32_t addr_dest;
u_int32_t addr_src;
u_int16_t packet_length;
u_int16_t message_length;
u_int16_t checksum;

size = (trame_p->length-3) + packet_p->packet_length;
if(size > TRAME_MAX_LENGTH-3) {
#ifdef debug
fputs("trame too long\n", stderr);
#endif
return -1;
}
if( (new_data = realloc(trame_p->data, size)) == NULL) {
#ifdef debug
fputs("bad alloc\n", stderr);
#endif
return -1;
}
trame_p->data = new_data;
new_data = ((char*)trame_p->data)+trame_p->length-3;
trame_p->length += packet_p->packet_length;

addr_dest = htonl(packet_p->addr_dest);
addr_src = htonl(packet_p->addr_src);
packet_length = htons(packet_p->packet_length);
message_length = htons(packet_p->message_length);
checksum = htons(packet_p->checksum);

memcpy(new_data, &(addr_dest), 4);
new_data += 4;
memcpy(new_data, &(addr_src), 4);
new_data += 4;
memcpy(new_data, &(packet_length), 2);
new_data += 2;
memcpy(new_data, &(message_length), 2);
new_data += 2;
memcpy(new_data, &(packet_p->fragment), 1);
new_data += 1;
memcpy(new_data, &(packet_p->type), 1);
new_data += 1;
memcpy(new_data, &(checksum), 2);
new_data += 2;

memcpy((char*)new_data, packet_p->data, packet_p->packet_length-16);

return 1;
}
int retr_packet(struct trame_t *trame_p, struct packet_t **packet_pp, enum boolean extract_data) {
int nb_packet, i;
char *ptr, *ptr_move, *limit;
struct trame_t tmp_trame;
struct packet_t tmp_packet, *new_packet_p;

nb_packet = 0;
*packet_pp = NULL;
if(!trame_p->data || trame_p->length <= 3)
return 0;

/* on copie la trame, en cas d'erreur, on ne se retrouvera pas dans un état incohérent */
tmp_trame = *trame_p;
if( (tmp_trame.data = malloc(tmp_trame.length-3)) == NULL) {
return -1;
}
memcpy(tmp_trame.data, trame_p->data, tmp_trame.length-3);

/* on regarde l'adresse de dest de chaque paquet, si le paquet n'est pas pour moi, on décale dans la trame, sinon on recopie dans un struct packet_t */

limit = (void*) (((char*) tmp_trame.data) + tmp_trame.length - 3);
ptr_move = ptr = tmp_trame.data;
while(ptr < limit) {
/* on extrait l'entete destination */
memset(&tmp_packet, 0, sizeof(struct packet_t));

memcpy(&(tmp_packet.addr_dest), ptr, 4);
ptr += 4;
tmp_packet.addr_dest = ntohl(tmp_packet.addr_dest);

memcpy(&(tmp_packet.addr_src), ptr, 4);
ptr += 4;
tmp_packet.addr_src = ntohl(tmp_packet.addr_src);

memcpy(&(tmp_packet.packet_length), ptr, 2);
ptr += 2;
tmp_packet.packet_length = ntohs(tmp_packet.packet_length);

memcpy(&(tmp_packet.message_length), ptr, 2);
ptr += 2;
tmp_packet.message_length = ntohs(tmp_packet.message_length);

memcpy(&(tmp_packet.fragment), ptr++, 1);
memcpy(&(tmp_packet.type), ptr++, 1);

memcpy(&(tmp_packet.checksum), ptr, 2);
ptr += 2;
tmp_packet.checksum = ntohs(tmp_packet.checksum);


if(tmp_packet.addr_dest == MY_ADDR) {
/* on retire le paquet de la trame */
if((new_packet_p = realloc(*packet_pp, ((size_t) (nb_packet+1))*sizeof(struct packet_t))) == NULL) {
#ifdef debug
fputs("bad alloc\n", stderr);
#endif
/* on désalloue tout */
for(i = 0 ; i<nb_packet ; i++) {
if(packet_pp[i]->data)
free(packet_pp[i]->data);
}
free(*packet_pp);
*packet_pp = NULL;
return -1;
}
*packet_pp = new_packet_p;
/* on recopie le paquet temporaire dans le tableau et on réaffecte la taille de la trame */
*(packet_pp[nb_packet]) = tmp_packet;
if(extract_data && tmp_packet.packet_length > 16)
memcpy(&(packet_pp[nb_packet]->data), ptr, tmp_packet.packet_length-16);
nb_packet++;
tmp_trame.length -= tmp_packet.packet_length;
} else {
/* on décale le paquet */
if(ptr-16 != ptr_move) {
memmove(ptr_move, ptr-16, tmp_packet.packet_length);
ptr = ptr_move+16;
}
ptr_move += tmp_packet.packet_length;
}


/* on se place sur le paquet suivant */
ptr += (tmp_packet.packet_length-16);
}

free(trame_p->data);
*trame_p = tmp_trame;

return nb_packet;
}


u_int16_t checksum(const struct packet_t *const packet) {
u_int16_t res, res1;
res = 0;
res += (u_int16_t) (htonl(packet->addr_dest) >> 16);
res += (u_int16_t) htonl(packet->addr_dest);
res += (u_int16_t) (htonl(packet->addr_src) >> 16);
res += (u_int16_t) htonl(packet->addr_src);
res += htons(packet->packet_length);
res += htons(packet->message_length);
res1 = (packet->fragment << 8);
res1 += packet->type;
res += res1;
return (res^0xffff);
}


int main(int argc, char** argv) {
pthread_t watchdog_discovery_thread;
socklen_t sock_length;
int trame_max_length, nb_packet;
struct trame_t trame;
struct packet_t *packet_p;


trame_max_length = TRAME_MAX_LENGTH;
sock_length = sizeof(struct sockaddr_in);

/* on initialise le mutex */
if(pthread_mutex_init(&mutex_in, NULL) || pthread_mutex_init(&mutex_out, NULL) || pthread_mutex_init(&mutex_stat, NULL)) {
#ifdef debug
fputs("erreur lors de l'initialisation des mutex\n", stderr);
#endif
exit(1);
}

/* on paramètre à qui on va envoyer nos trames */
sock_out.sin_family = AF_INET;
switch(argc) {
case 1:
#ifdef debug
fprintf(stderr, "les trames seront envoyées à %s sur le port %d\n", UDP_DEFAULT_CONNECT_ADDR, UDP_DEFAULT_CONNECT_PORT);
#endif
sock_out.sin_addr.s_addr = inet_addr(UDP_DEFAULT_CONNECT_ADDR);
sock_out.sin_port = htons(UDP_DEFAULT_CONNECT_PORT);
break;
case 3:
#ifdef debug
fprintf(stderr, "les trames seront envoyées à %s sur le port %d\n", argv[1], atoi(argv[2]));
#endif
sock_out.sin_addr.s_addr = inet_addr(argv[1]);
sock_out.sin_port = htons(atoi(argv[2]));
break;
default:
fprintf(stderr, "usage: %s [ip port]\n", argv[0]);
exit(2);
}

/* on ouvre le socket */
if((fd_sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
#ifdef debug
perror("socket()");
#endif
exit(errno);
}

/* on agrandit le buffer d'udp pour pouvoir envoyer et recevoir de grandes trames (sinon on est bloqué à 9216 octets) */
if(setsockopt(fd_sock, SOL_SOCKET, SO_SNDBUF, &trame_max_length, sock_length) == -1 || setsockopt(fd_sock, SOL_SOCKET, SO_RCVBUF, &trame_max_length, sock_length) == -1) {
#ifdef debug
perror("setsockopt()");
#endif
close(fd_sock);
exit(errno);
}

/* on se met en écoute */
memset(&sock_listen, 0, sizeof(struct sockaddr_in));
sock_listen.sin_addr.s_addr = htonl(INADDR_ANY);
sock_listen.sin_family = AF_INET;
sock_listen.sin_port = htons(UDP_LISTEN_PORT);
if(bind(fd_sock, (struct sockaddr*) &sock_listen, sizeof(sock_listen)) == -1) {
#ifdef debug
perror("bind()");
#endif
close(fd_sock);
exit(errno);
}

/* on initialise la valeur de quit et on paramètre un signal pour quitter */
quit = false;
signal(SIGINT, quit_signal_handler);

/* on démarre le watchdog */
watch_stat.received_trame = false;
watch_stat.time_before_discovery = DEFAULT_TIME_BEFORE_DISCOVERY;
if(pthread_create(&watchdog_discovery_thread, NULL, watchdog_discovery, NULL)) {
#ifdef debug
fputs("erreur lors de la création du thread\n", stderr);
#endif
close(fd_sock);
exit(3);
}

/* boucle de traitement */
do {
wait_trame:
/* on attend de recevoir une trame */
if(recv_trame(&trame, true) == -1) {
#ifdef debug
fputs("erreur lors de la réception de la trame\n", stderr);
#endif
goto wait_trame;
}

#ifdef debug
fprintf(stderr, "trame reçue : type:%d taille:%d\n", trame.type, trame.length);
#endif

if( (nb_packet = retr_packet(&trame, &packet_p, true)) == -1) {
/* on a une erreur donc on renvoie la trame telle quelle */
#ifdef debug
fputs("erreur lors de l'analyse des paquets de la trame\n", stderr);
#endif
goto send_trame;
}

switch(trame.type) {
case TRAME_TOKEN:

break;
case TRAME_DISCOVERY:

break;
}

/* on free les paquets reçus */
while(nb_packet > 0) {
if(packet_p[--nb_packet].data)
free(packet_p[nb_packet].data);
}
if(packet_p)
free(packet_p);


/*
printf("dest : %"PRIx32"\n", packet_p[0].addr_dest);
printf("src : %"PRIx32"\n", packet_p[0].addr_src);
printf("packet length : %"PRIu16"\n", packet_p[0].packet_length);
printf("message length : %"PRIu16"\n", packet_p[0].message_length);
printf("fragment : %"PRIu8"\n", packet_p[0].fragment);
printf("type : %"PRIu8"\n", packet_p[0].type);
printf("checksum : %"PRIx16"\n", packet_p[0].checksum);
*/
send_trame:
/* on renvoie la trame */
if(send_trame(&trame) == -1) {
#ifdef debug
fputs("erreur lors de l'émission de la trame\n", stderr);
#endif
}

} while(!quit);

if(trame.data)
free(trame.data);



pthread_join(watchdog_discovery_thread, NULL);
pthread_mutex_destroy(&mutex_in);
pthread_mutex_destroy(&mutex_out);
pthread_mutex_destroy(&mutex_stat);
close(fd_sock);

#ifdef debug
fputs("exited\n", stderr);
#endif

return 0;
}

+ 5
- 5
node.c View File

@@ -107,7 +107,7 @@ size_t packet_to_raw(const struct packet_t* packet, void** output)
if (tmp == NULL) // Unable to malloc
return 0;

#warning Ordre valide, selon la spec ?
//#warning Ordre valide, selon la spec ?
*((uint32_t*) tmp) = htonl(packet->exp_addr);
tmp += sizeof(uint32_t);
*((uint32_t*) tmp) = htonl(packet->dest_addr);
@@ -133,7 +133,7 @@ int packet_of_raw(const void* raw_packet, struct packet_t* output_packet)
{
const void* tmp = raw_packet;

#warning Ordre valide, selon la spec ?
//#warning Ordre valide, selon la spec ?
output_packet->exp_addr = ntohl(*((uint32_t*) tmp));
tmp += sizeof(uint32_t);
output_packet->dest_addr = ntohl(*((uint32_t*) tmp));
@@ -174,14 +174,14 @@ void process_token_frame(struct frame_t* frame, uint32_t our_address, const unsi
printfdbg("%p\t%p\t%d\n", current_read_position, current_write_position, count);
if (packet_of_raw(current_read_position, &packet) != 0)
{
#warning Maybe change current_read_position?
//#warning Maybe change current_read_position?
printdbg("Error: process_raw_token_frame: packet_of_raw returned an error.");
continue;
}

if (packet.data_hash != checksum(packet.data, packet.data_size))
{
#warning Maybe change current_read_position? (again)
//#warning Maybe change current_read_position? (again)
printdbg("Error: invalid checksum. Deleting the packet.\n");
}
//else
@@ -432,7 +432,7 @@ int is_ushort(char *str) {
int is_uint32(char *str) {
char *error = str;
long int val = strtol(str, &error, 10);
#warning dépassement de l’int
//#warning dépassement de l’int
return ( error != str && val > 0 && val < 4294967296 );
}


+ 35
- 0
readme View File

@@ -0,0 +1,35 @@
Conception de protocole

1. Compilation

La cible « debug » permet d'activer l'affichage de l'état du protocole lors du déroulement du programme.

2. Exécution

Pour exécuter le programme, les arguments à utiliser sont :
parms: <next node IP> <next node port> <our node port> <our ID> <subscribe port>

<next node IP> : adresse IP de la machine à laquelle on va envoyer la trame (la machine suivante dans l'anneau).
<next node port> : le port UDP de la machine à laquelle on va envoyer la trame.
<our node port> : notre port UDP sur lequel on va se mettre en écoute pour recevoir la trame
<our ID> : notre adresse dans le protocole (en hexadécimal ; au maximum 8 caractères)
<subscribe port> : port local sur lequel on va se connecter (en local) pour envoyer les commandes. Les commandes permettent notamment de paramétrer un port (local lui aussi) de la machine afin que les messages envoyés à ce port soit transmis à une machine de
l'anneau.

3. Utilisation

1. Exemple d'utilisation
On exécute le programme avec par exemple la commande
./node 89.234.129.131 4242 4243 c0de 1300

ainsi on enverra la trame à la machine testlns.vm.gixe.net(89.234.129.131) sur le port 4242. On recevra la trame sur le port 4243.
Notre adresse dans l'anneau est «c0de». Enfin le port de commande est le port 1300.

Une fois l'anneau formé, on peut associer un port local à une machine de l'anneau. Par exemple pour associer la machine « cafe » au port 1200, on doit envoyer la commande
« echo 'subscribe cafe 1200' | nc localhost 1300 ».
À partir de là, tout ce qu'on envoie dans le port local 1200, sera transmis via l'annea à la machine « cafe »

2. Liste des commandes
Les commandes que l'on peut envoyer sur le port de commande sont
« subscribe <ID> <local port> » qui associe l'hote d'adresse <ID> sur le port <local port>.
et « unsubscribe <ID> » qui permet défaire l'association.

Loading…
Cancel
Save