BE_reseau/src/mictcp.c
2023-05-10 11:08:05 +01:00

708 lines
20 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <pthread.h>
#include <stdio.h>
#include <mictcp.h>
#include <api/mictcp_core.h>
#define NBR_SOCKETS 1024
#define TIMEOUT_DEFAUT 1000
#define WINDOW_SIZE 10
#define LOSS_ACCEPTABILITY 20 // sur 100
#define ATTENTE_ACK 1
#define PAYLOAD_SIZE 64
//================================== STRUCTURES =============================
typedef struct {
char table[WINDOW_SIZE];
char last_index;
} circularBuffer;
typedef struct
{
mic_tcp_sock socket;
mic_tcp_sock_addr dist_addr;
char NoSeqLoc; // = -1;
char NoSeqDist; // = -1;
circularBuffer buffer;
} enhanced_socket;
typedef struct
{
int recpt;
int socket;
mic_tcp_pdu pdu_r;
}arg_thread;
//================================== VARIABLES GLOBALES =============================
static int socket_desc = 0;
static enhanced_socket tab_sockets[NBR_SOCKETS];
int timeout = TIMEOUT_DEFAUT;
int established = 0;
pthread_t envoi_syn_ack_tid;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t end_accept_cond = PTHREAD_COND_INITIALIZER;
char debug=1;
char version=1;
//================================== SIGNATURES DES FONCTIONS PRIVEES =============================
int valid_socket(int socket);
int bound_socket(int socket);
int same_addr(mic_tcp_sock_addr *addr1, mic_tcp_sock_addr *addr2);
void display_mic_tcp_pdu(mic_tcp_pdu pdu, char* prefix);
void display_enhanced_socket(enhanced_socket sock, char* prefix);
void display_mic_tcp_sock_addr(mic_tcp_sock_addr addr, char* prefix);
void * attente_ack(void * arg);
void error(char * message, int line);
void addValueCircularBuff(circularBuffer* buffer, char Value );
int accept_loss(int socket);
void set_mic_tcp_pdu(mic_tcp_pdu* pdu, unsigned short source_port, unsigned short dest_port, unsigned int seq_num, unsigned int ack_num, unsigned char syn, unsigned char ack, unsigned char fin, char* data, int size);
void process_syn_pdu(mic_tcp_pdu pdu,mic_tcp_sock_addr addr, int mic_sock);
void * envoi_syn_ack(void * arg);
//================================== FONCTIONS DE MICTCP =============================
/*
* Permet de créer un socket entre lapplication et MIC-TCP
* Retourne le descripteur du socket ou bien -1 en cas d'erreur
*/
int mic_tcp_socket(start_mode sm)
{
printf("[MIC-TCP] Appel de la fonction: ");
printf(__FUNCTION__);
printf("\n");
enhanced_socket *socket = &tab_sockets[socket_desc];
socket->socket.fd = socket_desc++;
socket->socket.state = IDLE;
// not bound yet
display_enhanced_socket(*socket, "état du socket");
socket->NoSeqLoc =0;
int result = initialize_components(sm); /* Appel obligatoire */
if (result < 0)
{
return -1;
}
return socket->socket.fd;
}
/*
* Permet dattribuer une adresse à un socket.
* Retourne 0 si succès, et -1 en cas déchec
*/
int mic_tcp_bind(int socket, mic_tcp_sock_addr addr)
{
printf("[MIC-TCP] Appel de la fonction: ");
printf(__FUNCTION__);
printf("\n");
if (valid_socket(socket) && tab_sockets[socket].socket.state == IDLE)
{
tab_sockets[socket].socket.addr = addr;
tab_sockets[socket].socket.state = WAITING;
display_enhanced_socket(tab_sockets[socket],"");
return 0;
}
return -1;
}
/*
* Met le socket en état d'acceptation de connexion et bloque jusqu'a ce que la connexion soit établie
* Retourne 0 si succès, -1 si erreur
*/
int mic_tcp_accept(int socket, mic_tcp_sock_addr *addr)
{
printf("[MIC-TCP] Appel de la fonction: ");
printf(__FUNCTION__);
printf("\n");
if (valid_socket(socket))
{
tab_sockets[socket].socket.state = ACCEPTING;
display_enhanced_socket(tab_sockets[socket], "état du socket en attendant l'établissement de connection");
if (version<4){
tab_sockets[socket].socket.state = ESTABLISHED;
tab_sockets[socket].NoSeqDist=0;
tab_sockets[socket].NoSeqLoc=0;
}
while (tab_sockets[socket].socket.state != ESTABLISHED){ //attente jusqu'a l'etablissement de la connexion
if(pthread_mutex_lock(&mutex)!= 0){error("erreur lock mutex",__LINE__);} //lock mutex
pthread_cond_wait(&end_accept_cond,&mutex);
if(pthread_mutex_unlock(&mutex)!= 0){error("erreur unlock mutex",__LINE__);} //unlock mutex
}
display_enhanced_socket(tab_sockets[socket], "État du socket aprés la connection :");
return 0;
}
return -1;
}
/*
* Permet de réclamer létablissement dune connexion
* Retourne 0 si la connexion est établie, et -1 en cas déchec
*/
int mic_tcp_connect(int socket, mic_tcp_sock_addr addr)
{
tab_sockets[socket].dist_addr = addr;
tab_sockets[socket].NoSeqLoc = 0;
if (version>2){
circularBuffer* buffer = &tab_sockets[socket].buffer;
buffer->last_index = 0;
for (int i = 0; i<WINDOW_SIZE;i++){
buffer->table[i]=0;
}
}
if (version<4){
tab_sockets[socket].socket.state = ESTABLISHED;
display_enhanced_socket(tab_sockets[socket], "État du socket aprés l'établissement de la connection :");
return 0;
}
tab_sockets[socket].socket.state = SYN_SENT;
// create pdu syn
mic_tcp_pdu pdu;
set_mic_tcp_pdu(
&pdu,
tab_sockets[socket].socket.addr.port,
tab_sockets[socket].dist_addr.port,
tab_sockets[socket].NoSeqLoc,
-1,
1,0,0,
NULL,0
);
display_mic_tcp_pdu(pdu, "creation du pdu SYN:");
display_mic_tcp_sock_addr(addr, "envoi du pdu SYN vers l'adresse :");
IP_send(pdu, addr);
// display_enhanced_socket(tab_sockets[socket], "état du socket en attente du syn ack :");
pthread_t attente_ack_tid;
arg_thread* args = malloc(sizeof(arg_thread));
while (1){
args->recpt=-1;
printf("avant creation thread TAA\n");
pthread_create(&attente_ack_tid, NULL,attente_ack,(void *)args);
printf("aprés creation thread TAA\n");
usleep(timeout);
if (pthread_cancel(attente_ack_tid)) printf("destruction du TAA");
if (args->recpt == -1){
if (tab_sockets[socket].socket.state == ESTABLISHED){
break;
}
IP_send(pdu, tab_sockets[socket].dist_addr);
printf("SYN ACK pas encore recu, envoi d'un doublon du syn\n");
continue;
}
display_mic_tcp_pdu(args->pdu_r,"pdu reçu :");
if (args->pdu_r.header.ack == 1 && args->pdu_r.header.syn == 1 /*on s'occuppe plus tard de la verif du num de seq*/){
printf("Bon PDU SYN ACK recu \n");
tab_sockets[socket].NoSeqDist = args->pdu_r.header.seq_num; // récupérer n° de seq du server
set_mic_tcp_pdu(
&pdu,
tab_sockets[socket].socket.addr.port,
tab_sockets[socket].dist_addr.port,
-1,
args->pdu_r.header.seq_num,
0,1,0,
NULL,0
);
display_mic_tcp_pdu(pdu, "creation du pdu ACK:");
display_mic_tcp_sock_addr(addr, "envoi du pdu ACK vers l'adresse :");
IP_send(pdu, addr);
// mic_tcp_pdu* args = malloc(sizeof(mic_tcp_pdu));
// args->header=pdu.header;
// args->payload=pdu.payload;
tab_sockets[socket].socket.state = ESTABLISHED;
/*on attend naivement l'arrivee d'un nouveau syn ack au cas ou le ack a ete perdu, puis on relance la boucle, pour verifier*/
continue;
}
else {
printf(debug?"Le pdu recu n'est pas un SYN ACK\n":"");
continue;
}
}
display_enhanced_socket(tab_sockets[socket], "État du socket aprés l'établissement de la connection :");
return 0;
}
/*
* Permet de réclamer lNULL
*/
int mic_tcp_send(int mic_sock, char *mesg, int mesg_size)
{
if (tab_sockets[mic_sock].socket.state != ESTABLISHED)
{
printf("l'utilisateur nest pas connecté \n");
exit(1);
}
// create pdu
mic_tcp_pdu pdu;
set_mic_tcp_pdu(
&pdu,
tab_sockets[mic_sock].socket.addr.port,
tab_sockets[mic_sock].dist_addr.port,
tab_sockets[mic_sock].NoSeqLoc,
-1,
0,0,0,
mesg,mesg_size
);
display_mic_tcp_pdu(pdu, "creation du pdu data:");
display_mic_tcp_sock_addr(tab_sockets[mic_sock].dist_addr, "envoi du pdu data vers l'adresse :");
display_enhanced_socket(tab_sockets[mic_sock],"etat du socket");
int sent_size = IP_send(pdu, tab_sockets[mic_sock].dist_addr);
printf("Packet envoye\n");
if (version<2) return sent_size;
tab_sockets[mic_sock].socket.state = WAITING;
pthread_t attente_ack_tid;
arg_thread* args = malloc(sizeof(arg_thread));
while (1)
{
args->recpt=-1;
printf("avant creation thread TAA\n");
pthread_create(&attente_ack_tid, NULL,attente_ack,(void *)args);
printf("aprés creation thread TAA\n");
usleep(timeout);
if (pthread_cancel(attente_ack_tid)) printf("destruction du TAA");
if (args->recpt == -1){ // Si on ne reçoit pas le ACK
if (version>2){
if (accept_loss(mic_sock)) { // Si on peut accepter la perte, on ne retransmet pas
addValueCircularBuff(&tab_sockets[mic_sock].buffer,0);
printf("===========Perte Acceptée============\n");
tab_sockets[mic_sock].socket.state = ESTABLISHED;
return sent_size;
} else {
printf("============Perte inacceptable=============\n");
}
}
sent_size = IP_send(pdu, tab_sockets[mic_sock].dist_addr);
printf("Pas de pdu recu, envoi d'un doublon\n");
continue;
}
display_mic_tcp_pdu(args->pdu_r,"pdu reçu :");
if (args->pdu_r.header.ack == 1 && (tab_sockets[mic_sock].NoSeqLoc ==args->pdu_r.header.ack_num)){
printf("le bon Ack a été reçu\n");
tab_sockets[mic_sock].socket.state = ESTABLISHED;
tab_sockets[mic_sock].NoSeqLoc = ((tab_sockets[mic_sock].NoSeqLoc + 1) % 2); //maj du no de seq uniquement lorsque ACK reçu (= synchronisation du noseq entre puits et src)
display_enhanced_socket(tab_sockets[mic_sock], "État du socket aprés la reception du ack");
if (version>2){
addValueCircularBuff(&tab_sockets[mic_sock].buffer, 1);
}
return sent_size;
}else if(args->pdu_r.header.ack == 1 && args->pdu_r.header.syn == 1){
printf("PDU SYN ACK recu a nouveau (Doublon) \n");
mic_tcp_pdu pdu_d;
set_mic_tcp_pdu(
&pdu_d,
tab_sockets[mic_sock].socket.addr.port,
tab_sockets[mic_sock].dist_addr.port,
-1,
args->pdu_r.header.seq_num,
0,1,0,
NULL,0
);
display_mic_tcp_pdu(pdu_d, "creation du pdu ACK:");
display_mic_tcp_sock_addr(tab_sockets[mic_sock].dist_addr, "envoi du pdu ACK vers l'adresse :");
IP_send(pdu_d, tab_sockets[mic_sock].dist_addr);
}else {
printf("mauvais pdu reçu\n");
}
// si ACK de bon numéro de séquence
// addValueCircularBuff(&tab_sockets[mic_sock].buffer,1); // PDU bien reçu
//update seq num ?
// tab_sockets[mic_sock].socket.state = ESTABLISHED;
}
}
/*
* Permet à lapplication réceptrice de réclamer la récupération dune donnée
* stockée dans les buffers de réception du socket
* Retourne le nombre doctets lu ou bien -1 en cas derreur
* NB : cette fonction fait appel à la fonction app_buffer_get()
*/
int mic_tcp_recv(int socket, char *mesg, int max_mesg_size)
{
printf("[MIC-TCP] Appel de la fonction: ");
printf(__FUNCTION__);
printf("\n");
if (!valid_socket(socket))
{
return -1;
}
int delivered_size;
mic_tcp_payload *payload = malloc(sizeof(mic_tcp_payload));
payload->data = mesg;
payload->size = max_mesg_size;
printf("procède au app_buffer_get\n");
delivered_size = app_buffer_get(*payload);
printf("payload récupéré\n");
return delivered_size;
}
/*
* Permet de traiter un PDU MIC-TCP reçu (mise à jour des numéros de séquence
* et d'acquittement, etc.) puis d'insérer les données utiles du PDU dans
* le buffer de réception du socket. Cette fonction utilise la fonction
* app_buffer_put(). Elle est appelée par initialize_components()
*/
void process_syn_pdu(mic_tcp_pdu pdu,mic_tcp_sock_addr addr, int mic_sock){
printf("[MIC-TCP] Appel de la fonction: ");
printf(__FUNCTION__);
printf("\n");
tab_sockets[mic_sock].socket.state = SYN_RECEIVED;
tab_sockets[mic_sock].dist_addr=addr;
tab_sockets[mic_sock].NoSeqDist=pdu.header.seq_num;
tab_sockets[mic_sock].NoSeqLoc=0; //Premier numéro de seq toujours à 0
mic_tcp_pdu pdu_r;
set_mic_tcp_pdu(&pdu_r,
tab_sockets[mic_sock].socket.addr.port,
tab_sockets[mic_sock].dist_addr.port,
tab_sockets[mic_sock].NoSeqLoc,
tab_sockets[mic_sock].NoSeqDist,
1,1,0,NULL,0
);
display_mic_tcp_pdu(pdu_r, "Construction du Pdu SYN ACK : \n");
display_mic_tcp_sock_addr(tab_sockets[mic_sock].dist_addr, "Envoi du PDU SYN ACK à l'adresse:");
IP_send(pdu_r, addr);
arg_thread* args = malloc(sizeof(arg_thread));
args->socket=mic_sock;
args->pdu_r=pdu_r;
printf("avant creation thread TESA\n");
pthread_create(&envoi_syn_ack_tid, NULL,envoi_syn_ack,(void *)args);
printf("aprés creation thread TESA\n");
}
void process_received_PDU(mic_tcp_pdu pdu, mic_tcp_sock_addr addr) //addr = adresse distante
{
int mic_sock;
display_mic_tcp_pdu(pdu, "pdu reçu");
for (mic_sock = 0; (mic_sock < socket_desc) && !(tab_sockets[mic_sock].socket.addr.port==pdu.header.dest_port); mic_sock++)
; // trouver le socket destinataire
if (mic_sock == socket_desc)
{ // si aucun socket trouvé, alors retourne une erreur
printf(debug?"socket non trouvé\n":"");
}
if (version<2) {
app_buffer_put(pdu.payload); // envoyer la data dans le buffer
printf("data in the buffer\n");
return;
}
if (pdu.header.syn == 1 && tab_sockets[mic_sock].socket.state == ACCEPTING) // si PDU SYN
{
process_syn_pdu(pdu,addr, mic_sock);
}
else if (pdu.header.syn == 1 && tab_sockets[mic_sock].socket.state == SYN_RECEIVED) // si Doublon PDU SYN
{
printf("Doublon PDU SYN recu\n");
}
else if (pdu.header.ack == 1 && tab_sockets[mic_sock].socket.state == SYN_RECEIVED)
{ // Si ACK de connection reçu
printf("PDU ACK recu \n");
tab_sockets[mic_sock].socket.state = ESTABLISHED;
if(pthread_mutex_lock(&mutex)!= 0){error("erreur lock mutex",__LINE__);} //lock mutex
pthread_cond_broadcast(&end_accept_cond); // Rendre la main au client une fois le accept terminé
if(pthread_mutex_unlock(&mutex)!= 0){error("erreur unlock mutex",__LINE__);} //unlock mutex
printf("Connexion établie\n");
}
else if(pdu.header.ack == 0 && pdu.header.seq_num == tab_sockets[mic_sock].NoSeqDist && tab_sockets[mic_sock].socket.state == ESTABLISHED)
{ // Si PDU de DATA
printf("PDU data recu \n");
mic_tcp_pdu pdu_d;
set_mic_tcp_pdu(
&pdu_d,
tab_sockets[mic_sock].socket.addr.port,
tab_sockets[mic_sock].dist_addr.port,
-1,
pdu.header.seq_num,
0,1,0,
NULL,0
);
display_mic_tcp_pdu(pdu_d, "creation du pdu ACK:");
display_mic_tcp_sock_addr(addr, "envoi du pdu ACK vers l'adresse :");
IP_send(pdu_d, addr);
tab_sockets[mic_sock].NoSeqDist = ((tab_sockets[mic_sock].NoSeqDist) + 1) % 2; //update n° seq distant
app_buffer_put(pdu.payload); // envoyer la data dans le buffer
printf("data in the buffer\n");
}
else if(pdu.header.ack == 0 && pdu.header.seq_num != tab_sockets[mic_sock].NoSeqDist && tab_sockets[mic_sock].socket.state == ESTABLISHED)
{ // Si Doublon PDU de DATA
printf("PDU data recu (Doublon)\n");
mic_tcp_pdu pdu_d;
set_mic_tcp_pdu(
&pdu_d,
tab_sockets[mic_sock].socket.addr.port,
tab_sockets[mic_sock].dist_addr.port,
-1,
pdu.header.seq_num,
0,1,0,
NULL,0
);
display_mic_tcp_pdu(pdu_d, "recreation du pdu ACK:");
display_mic_tcp_sock_addr(addr, "renvoi du pdu ACK vers l'adresse :");
IP_send(pdu_d, addr);
}else{
printf("PDU inattendu recu :\n");
display_enhanced_socket(tab_sockets[mic_sock], "l'état du socket");
}
}
/*
* Permet de réclamer la destruction dun socket.
* Engendre la fermeture de la connexion suivant le modèle de TCP.
* Retourne 0 si tout se passe bien et -1 en cas d'erreur
*/
int mic_tcp_close(int socket)
{
printf("[MIC-TCP] Appel de la fonction : ");
printf(__FUNCTION__);
printf("\n");
if (valid_socket(socket) && tab_sockets[socket].socket.state == ESTABLISHED)
{
tab_sockets[socket].socket.state = CLOSED;
tab_sockets[socket].socket.fd = -1;
}
return -1;
}
//================================== CORPS DES FONCTIONS PRIVEES =============================
int valid_socket(int socket)
{
if (socket > socket_desc - 1 || tab_sockets[socket].socket.fd == -1)
{
// printf("ah, ton socket il existe pas\n");
return 0;
}
return 1;
}
int bound_socket(int socket)
{
if (tab_sockets[socket].socket.state == IDLE || tab_sockets[socket].socket.state == CLOSING || tab_sockets[socket].socket.state == CLOSED )
{
// printf("socket not bound\n");
return 0;
}
return 1;
}
int same_addr(mic_tcp_sock_addr *addr1, mic_tcp_sock_addr *addr2)
{
if (addr1->port == addr2->port && addr1->ip_addr_size == addr2->ip_addr_size && !memcmp(addr1->ip_addr, addr2->ip_addr, addr1->ip_addr_size))
{
return 1;
}
return 0;
}
void set_mic_tcp_pdu(mic_tcp_pdu* pdu, unsigned short source_port, unsigned short dest_port, unsigned int seq_num, unsigned int ack_num, unsigned char syn, unsigned char ack, unsigned char fin, char* data, int size) {
pdu->header.source_port = source_port;
pdu->header.dest_port = dest_port;
pdu->header.seq_num = seq_num;
pdu->header.ack_num = ack_num;
pdu->header.syn = syn;
pdu->header.ack = ack;
pdu->header.fin = fin;
pdu->payload.data = data;
pdu->payload.size = size;
}
void display_mic_tcp_pdu(mic_tcp_pdu pdu, char* prefix) {
if (!debug) return ;
printf("------------------------------------------\n%s\n", prefix);
printf("ACK Flag: %d\n", pdu.header.ack);
printf("FIN Flag: %d\n", pdu.header.fin);
printf("SYN Flag: %d\n", pdu.header.syn);
printf("Source Port: %hu\n", pdu.header.source_port);
printf("Destination Port: %hu\n", pdu.header.dest_port);
printf("Sequence Number: %u\n", pdu.header.seq_num);
printf("Acknowledgment Number: %u\n", pdu.header.ack_num);
printf("Payload Size: %d\n", pdu.payload.size);
if (pdu.payload.size != 0) {
printf("Payload Data: %.*s\n", pdu.payload.size, pdu.payload.data);
} else {
printf("Payload Data is NULL\n");
}
printf("----------------------------------\n");
}
void display_enhanced_socket(enhanced_socket sock,char* prefix) {
if (!debug) return ;
printf("----------------------------------\n");
printf("%s\n", prefix);
printf("Socket File Descriptor: %d\n", sock.socket.fd);
const char* protocol_states[] = {"IDLE", "CLOSED", "SYN_SENT", "SYN_RECEIVED", "ESTABLISHED", "CLOSING", "ACCEPTING", "WAITING"};
printf("Socket Protocol State: %s\n", protocol_states[sock.socket.state]);
printf("Socket Address IP: %.*s\n", sock.socket.addr.ip_addr_size, sock.socket.addr.ip_addr);
printf("Socket Address Port: %hu\n", sock.socket.addr.port);
printf("Remote Address IP: %.*s\n", sock.dist_addr.ip_addr_size, sock.dist_addr.ip_addr);
printf("Remote Address Port: %hu\n", sock.dist_addr.port);
printf("Local Sequence Number: %d\n", sock.NoSeqLoc);
printf("Remote Sequence Number: %d\n", sock.NoSeqDist);
if (version>2){
printf("Buffer: --------------- \n");
for (int i =0;i<WINDOW_SIZE; i++){
printf(" %d ;",sock.buffer.table[i]);
}
printf("\n-----------------\n");
}
printf("\n----------------------------------\n");
}
void display_mic_tcp_sock_addr(mic_tcp_sock_addr addr, char* prefix) {
printf("----------------------------------\n");
if (!debug) return ;
printf("%s\n", prefix);
printf("IP Address: %.*s\n", addr.ip_addr_size, addr.ip_addr);
printf("Port: %hu\n", addr.port);
printf("----------------------------------\n");
}
void * attente_ack(void * arg) {
printf(debug?"début du TAA: thread d'attente de ACK'\n":"");
arg_thread* args = (arg_thread*)arg;
args->recpt=IP_recv(&args->pdu_r,NULL, 0) ;
printf("TAA: reception effectuee, autodestruction entamee\n");
pthread_exit(NULL);
}
void * envoi_syn_ack(void * arg) {
printf(debug?"début du TESA : thread d'envoi de SYN ACK'\n":"");
arg_thread* args = (arg_thread*)arg;
while (1)
{
if (tab_sockets[args->socket].socket.state == SYN_RECEIVED)
{
display_mic_tcp_pdu(args->pdu_r, "renvoi du pdu syn ack");
display_mic_tcp_sock_addr(tab_sockets[args->socket].dist_addr,"a l'adresse");
IP_send(args->pdu_r, tab_sockets[args->socket].dist_addr);
printf(debug?"TESA: je renvoie le Syn ack\n":"");
}
else if (tab_sockets[args->socket].socket.state == ESTABLISHED)
{
printf("!Destruction du TESA!");
pthread_exit(NULL);
}
usleep(timeout);
}
}
void error(char * message, int line){
printf("%s at line %d\n",message,line);
exit(1);
}
int accept_loss(int socket){
int sum = 0;
for(int i = 0; i < WINDOW_SIZE; i++){ // somme de tous les packets reçus
sum += tab_sockets[socket].buffer.table[i];
}
if(sum < WINDOW_SIZE*(100-LOSS_ACCEPTABILITY)/100){// si le nombre de packets reçus est inférieur au nombre acceptable
return 0; // on accepte pas la perte
}
return 1;
}
void addValueCircularBuff(circularBuffer* buffer, char Value ){
buffer->table[buffer->last_index+1%WINDOW_SIZE]=Value;
buffer->last_index = buffer->last_index + 1 % WINDOW_SIZE;
}