/* Transmit the file using Selective Repeat protocol **************************************************** */ void transmit(char* filename, int speed, int delay, double loss, double corrupt) { /* Compute window size */ int window_sz = (int) ( (double) ( ( (double)(speed * delay) / 8) \ * (1 << 20) ) / (1000 * 1408) + 1 ); /* Attempt to get stats of the file */ struct stat buf; if ( stat(filename, &buf) < 0 ) { perror("Stat failed"); return; } /* Open the file */ int file = open(filename, O_RDONLY); if (file < 0) { perror("Couldn't open file"); return; } charge t, *ok = NULL;; memset(&t, 0, sizeof(charge)); int not_sent = 1; /* Type 1: Handshake message; filename + filesize */ t.msg.type = 1; sprintf(t.pack.load, "%s\n%d\n", filename, (int) buf.st_size); t.msg.len = strlen(t.pack.load) + 1; t.pack.id = (unsigned int) window_sz; /* window size in place of id */ /* Compute CRC of the handshake message */ compcrc(t.crc.payload, CRC_LOAD_SZ, &t.crc.crc); /* Make sure the first frame containing filename and its size is recieved */ while (not_sent) { send_message((msg *)&t); fprintf(stderr, "Handshake message attempted\n"); ok = (charge *)receive_message_timeout(delay * 2 + 20); if(!ok) { fprintf(stderr, "Handshake message receive failure\n"); continue; } if (ok->msg.type == 1000 && ok->crc.crc == t.crc.crc) not_sent = 0; free(ok); } /* Get window size from reciever */ charge *win_rec = NULL; win_rec = (charge *)receive_message(); if (!win_rec) { fprintf(stderr, "Window size not recieved\n"); } if (win_rec->msg.type != 2000) fprintf(stderr, "Error, window size from reciever expected\n"); /* Reciever's window size */ const int win_recv = win_rec->pack.id; free(win_rec); /* Recompute the window size */ if (win_recv != 0 && window_sz > win_recv) window_sz = win_recv; if (window_sz < 10) window_sz = 10; /* Transmit the content of the file ********************************** */ unsigned int seq = 0; unsigned int front = 0, count = 0; charge *buff = (charge *) calloc(window_sz, sizeof(charge)); charge tr, *rr; memset(&tr, 0, sizeof(charge)); int flen = (int) buf.st_size; /* While there are ACKs to wait */ while (flen) { if ( (tr.msg.len = read(file, &tr.pack.load, PCK_LOAD_SZ) ) > 0 ) { tr.msg.type = 2; /* Data */ tr.pack.id = seq; compcrc(tr.crc.payload, CRC_LOAD_SZ, &tr.crc.crc); /* Send message and push it into the queue */ send_message((msg *) &tr); push(buff, tr, front, &count, window_sz); seq++; if ( count < window_sz && tr.msg.len == PCK_LOAD_SZ ) { memset(&tr, 0, sizeof(charge)); continue; /* Fulfill buffer */ } } read: /* Read ACK or NAK */ rr = NULL; rr = (charge *)receive_message_timeout(delay * 2 + 20); charge nkd, ackd; if (rr != NULL) switch (rr->pack.type) { /* Case for NAK */ case 4: t_out: /* Timeout situations are handled here too */ nkd = pop(buff, &front, &count, window_sz); send_message((msg *) &nkd); push(buff, nkd, front, &count, window_sz); free(rr); goto read; break; /* Case for ACK */ case 3: ackd = pop(buff, &front, &count, window_sz); while ( ackd.pack.id != rr->pack.id ) { send_message((msg *) &ackd); push(buff, ackd, front, &count, window_sz); ackd = pop(buff, &front, &count, window_sz); } flen -= ackd.pack.len; free(rr); break; default: break; } else goto t_out; } close(file); free(buff); }
int main(int argc, char** argv){ init(HOST,PORT); msg m1, *m2; frame f; //fisierul de log FILE* log_file; log_file = fopen ("log.txt","w"); fclose(log_file); // fisierul de intrare int in = open(argv[1], O_RDONLY); lseek(in, 0, SEEK_SET); struct stat s; fstat (in, &s); int file_size = (int) s.st_size; unsigned char checksum; int got_correct_ack = 1; int size; unsigned char nr_frame = 0; char str[80]; while (file_size != 0) { log_file = fopen ("log.txt","a"); // daca s-a primit ACK corect se intra pe aceasta ramura if (got_correct_ack) { // se trimite marimea fisierului de intrare, am considerat acest // mesaj ca fiind un caz separat if (nr_frame == 0) { m1.len = sizeof(int); f.payload = malloc(sizeof(int)); memcpy(&m1.data[0], &nr_frame, 1); sprintf(&m1.data[1],"%d", file_size); sprintf((char*)f.payload,"%d", file_size); checksum = get_checksum(m1); memcpy(&m1.data[5], &checksum, 1); send_message(&m1); char to_binary[9]; strcpy(to_binary, byte_to_binary(checksum)); fprintf (log_file, "%s", currentDateTime(str)); fprintf(log_file, "[%s] Am trimis pachetul cu:\n\tSeq no:" "%d\n\tPayload: %s\n\tChecksum: %s\n", argv[0], 0, f.payload, to_binary); fprintf(log_file,"------------------------------------------" "-----------------------------------------------------\n"); } // daca a fost trimisa marimea fisierului atunci se intra numai pe // aceasta ramura else { int payload_size = (rand() % (60 + 1 - 1)) + 1; if (file_size <= payload_size) { payload_size = file_size; f.payload = malloc(payload_size); read(in, f.payload, file_size); } else { f.payload = malloc(payload_size); read(in, f.payload, payload_size); } m1.len = payload_size; size = m1.len; memcpy(&m1.data[0], &nr_frame, 1); memcpy (&m1.data[1], &f.payload[0], payload_size); checksum = get_checksum(m1); memcpy(&m1.data[1 + payload_size], &checksum, 1); send_message(&m1); char to_binary[9]; strcpy(to_binary, byte_to_binary(checksum)); fprintf (log_file, "%s", currentDateTime(str)); fprintf(log_file, "[%s] Am trimis pachetul cu:\n\tSeq no:" "%d\n\tPayload: %s\n\tChecksum: %s\n", argv[0], nr_frame, f.payload, to_binary); fprintf(log_file,"------------------------------------------" "-----------------------------------------------------\n"); } } // daca nu s-a primit ACK corect se retrimite ultimul pachet else { send_message(&m1); } // verific daca s-a primit timeout if ((m2 = receive_message_timeout(50)) == NULL) { got_correct_ack = 0; fprintf (log_file, "%s", currentDateTime(str)); fprintf(log_file, "[%s] Am primit timeout, retrimit pachetul" "cu no_seq: %d\n", argv[0], nr_frame); fprintf(log_file,"------------------------------------------" "-----------------------------------------------------\n"); fflush(log_file); } // daca nu s-a primit timeout verific daca s-a primit ACK corect else { memcpy(&f.no_seq, m2->data, 1); memcpy(&f.checksum, m2->data + 1, 1); if (f.no_seq == f.checksum) { fprintf (log_file, "%s", currentDateTime(str)); fprintf(log_file, "[%s] Am primit ACK corect pentru " "pachetul cu no_seq: %d, trimit urmatorul pachet\n", argv[0], nr_frame); fprintf(log_file,"------------------------------------------" "-----------------------------------------------------\n"); fclose(log_file); got_correct_ack = 1; file_size -= size; nr_frame ++; free(f.payload); } else { fprintf (log_file, "%s", currentDateTime(str)); fprintf(log_file, "[%s] Am primit ACK gresit, retrimit " "pachetul cu no_seq: %d", argv[0], nr_frame); fprintf(log_file,"------------------------------------------" "-----------------------------------------------------\n"); fclose(log_file); got_correct_ack = 0; } } } log_file = fopen ("log.txt","a"); fprintf (log_file, "%s", currentDateTime(str)); fprintf(log_file, "[%s] Am trimis tot fisierul %s\n", argv[0], argv[1]); fclose(log_file); return 0; }
/* ======================================================= metoda trimite mesaje de confirmare/neconfirmare inapoi catre sender pentru toate pachetele primite ======================================================== */ void send_data(unsigned short int BUF) { unsigned short int new_seq = 0, far = BUF; int i; msg *buffer=calloc(1000,sizeof(msg)); int *arrived_messages=calloc(BUF,sizeof(int)); unsigned short int crc; unsigned short payload_crc; /*cat timp nu am primit intreg continutul fisierului*/ for (;size > 0;) { /*primesc mesaj de la sender*/ r = receive_message_timeout( delay); if (r != NULL) { /*daca nu este mesaj de tip 2 (de date) trimit nak*/ if (r->type != DATA) { msg m = message((new_seq + MAX_SEQ) % (MAX_SEQ + 1),"NAK"); send_message(&m); } else { /*altfel verfici dac numarul de secventa se incadreaza in fereastra curenta si daca bufferul este liber pe acea pozitie */ memcpy(&next_seq, r->payload + 2, 2); if (between(new_seq, next_seq, far)) if(arrived_messages[next_seq % BUF] == 0) { /*calculez crc-ul*/ crc = calc_crc(r, crc_table); memcpy(&payload_crc, r->payload, 2); /*daca am primit un mesaj nedeteriorat*/ if ((payload_crc == crc)) { /*marchez bufferul ca fiind ocupat pe acea pozitie*/ arrived_messages[next_seq % BUF] = 1; buffer[next_seq % BUF] = *r; while (arrived_messages[new_seq % BUF]) { size =size- buffer[new_seq % BUF].len; arrived_messages[new_seq % BUF] = 0; /*scriu datele in fisier*/ write(fd, buffer[new_seq % BUF].payload + 4,buffer[new_seq % BUF].len); /*deplasez fereastra*/ increment(&new_seq, MAX_SEQ); increment(&far, MAX_SEQ); } /*trimit mesaj de confirmare*/ msg m = message((new_seq + MAX_SEQ) % (MAX_SEQ + 1),"ACK"); send_message(&m); if (size == 0) break; } else { /*mesaj corupt*/ msg m = message((new_seq + MAX_SEQ) % (MAX_SEQ + 1),"NAK"); send_message(&m); } } else { /* nu se incadreaza in limitele ferestrei*/ msg m = message((new_seq + MAX_SEQ) % (MAX_SEQ + 1),"NAK"); send_message(&m); } } } else { /*am primit mesaj gol*/ msg m = message((new_seq + MAX_SEQ) % (MAX_SEQ + 1),"NAK"); send_message(&m); } } }
int main(int argc,char** argv){ init(HOST,PORT); msg t, *r; char nr_secv_sender = 0; FILE *fd = fopen("date_intrare", "r"); //variabile folosite pentru a scrie data si ora in fisierul log.txt; time_t timp = time(NULL); struct tm timp_str = *(localtime(&timp)); //alegem o dimensiune de pachet aleatoare, care imi intoarca un numar intre 1 si 60; int rnd = rand() % 61; //cat timp mai citesc din fisier; while(fgets(t.payload, rnd, fd) != NULL){ //pun textul in payload; t.len = strlen(t.payload); //calculez CheckSum char CheckSum = getXor(t.payload); //printez data, ora, numarul secventei, payloadul si CheckSumul cadrului trimis; printf("[sender] %d-%02d-", timp_str.tm_year + 1900, timp_str.tm_mon + 1); printf("%d %2d:%2d:%02d\n", timp_str.tm_mday, timp_str.tm_hour, timp_str.tm_min, timp_str.tm_sec); printf("Am trimis urmatorul pachet:\n"); printf("Seq_No: %d\n", nr_secv_sender); printf("Payload: %s\n", t.payload); printf("CheckSum: %s\n", toBin(CheckSum)); printf("--------------------------------------------------------------------\n"); //pun paritatea pe penultima pozitie t.payload[t.len + 2] = CheckSum; //pun seq_nr pe ultima pozitie t.payload[t.len + 3] = nr_secv_sender; //trimit mesajul send_message(&t); //resetez dimensiunea pachetului de trimis rnd = rand() % 61; //primesc ack; setez valoarea de timeout la 200 ms r = receive_message_timeout(200); //cat timp nu am trimis pachetul in timp util; while(r == NULL){ //printez data, ora, numarul secventei, payloadul si CheckSumul cadrului trimis; printf("[sender] %d-%02d-", timp_str.tm_year + 1900, timp_str.tm_mon + 1); printf("%d %2d:%2d:%02d\n", timp_str.tm_mday, timp_str.tm_hour, timp_str.tm_min, timp_str.tm_sec); printf("Am trimis urmatorul pachet:\n"); printf("Seq_No: %d\n", nr_secv_sender); printf("Payload: %s\n", t.payload); printf("CheckSum: %s\n", toBin(CheckSum)); printf("--------------------------------------------------------------------\n"); send_message(&t); r = receive_message_timeout(200); } char nr_secv_receiver = r->payload[0]; //cat timp primesc ack pentru acelasi pachet, il retrimit //si reprimesc ack pentru a ma asigura ca a fost trimis bine while(nr_secv_receiver == nr_secv_sender || r == NULL){ //printez data, ora, numarul secventei, payloadul si CheckSumul cadrului trimis; printf("[sender] %d-%02d-", timp_str.tm_year + 1900, timp_str.tm_mon + 1); printf("%d %2d:%2d:%02d\n", timp_str.tm_mday, timp_str.tm_hour, timp_str.tm_min, timp_str.tm_sec); printf("Am trimis urmatorul pachet:\n"); printf("Seq_No: %d\n", nr_secv_sender); printf("Payload: %s\n", t.payload); printf("CheckSum: %s\n", toBin(CheckSum)); printf("--------------------------------------------------------------------\n"); send_message(&t); r = receive_message_timeout(200); nr_secv_receiver = r->payload[0]; } //incrementez numarul secventei; nr_secv_sender++; } return 0; }
/* ======================================================================= trimit primul frame ======================================================================= */ void send_first_frame(int window) { unsigned short int crc; unsigned short payload_crc; for(;;) { r = receive_message_timeout(2*delay); if (r != NULL) { /*daca a sosot un mesaj care nu este de tipul FIRSt trimit NAK */ if (r->type != FIRST) { msg m=message(FIRST_FRAME,"NAK"); send_message(&m); } else { /*calculez crc-ul si verfic daca mesajul este sau nu deteriorat*/ crc = calc_crc(r, crc_table); memcpy(&payload_crc, r->payload, 2); if ((payload_crc == crc)) { int len=r->len; /*determin valorile pentru - delay - numele fisierului - MAX_SEQ - dimensiunea fisierului*/ memcpy(&delay, r->payload + len + 8, 4); memcpy(filename, r->payload + 4, len); memcpy(&MAX_SEQ, r->payload + 2, 2); memcpy(&size, r->payload + len + 4, 4); /* determin minminimul dintre valoarea parametrului window si dimensiunea ferestrei senderului */ int min ; if(window != 0) min= ((MAX_SEQ+1)/2>window)?window:(MAX_SEQ+1)/2; if(window!=0)MAX_SEQ =min *2 - 1; send_ack2(FIRST_FRAME, crc_table, MAX_SEQ); break; } else { /*daca mesajul este corupt trimit nak*/ msg m=message(FIRST_FRAME,"NAK"); send_message(&m); } } } else { /*daca am primt un mesaj gol trimit nak*/ msg m=message(FIRST_FRAME,"NAK"); send_message(&m); } } }