diff --git a/Makefile b/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1aa601e7f92667314805137327237211aa6d1ea7 --- /dev/null +++ b/Makefile @@ -0,0 +1,58 @@ +# You can use clang if you prefer +CC = gcc + +# Feel free to add other C flags +CFLAGS += -c -std=gnu99 -Wall -Werror -Wextra -O2 +# By default, we colorize the output, but this might be ugly in log files, so feel free to remove the following line. +CFLAGS += -D_COLOR + +# You may want to add something here +LDFLAGS += + +# Adapt these as you want to fit with your project +SENDER_SOURCES = $(wildcard src/sender.c src/log.c) +RECEIVER_SOURCES = $(wildcard src/receiver.c src/log.c) + +SENDER_OBJECTS = $(SENDER_SOURCES:.c=.o) +RECEIVER_OBJECTS = $(RECEIVER_SOURCES:.c=.o) + +SENDER = sender +RECEIVER = receiver + +all: $(SENDER) $(RECEIVER) + +$(SENDER): $(SENDER_OBJECTS) + $(CC) $(SENDER_OBJECTS) -o $@ $(LDFLAGS) + +$(RECEIVER): $(RECEIVER_OBJECTS) + $(CC) $(RECEIVER_OBJECTS) -o $@ $(LDFLAGS) + +%.o: %.c + $(CC) $(CFLAGS) $< -o $@ $(LDFLAGS) + +.PHONY: clean mrproper + +clean: + rm -f $(SENDER_OBJECTS) $(RECEIVER_OBJECTS) + +mrproper: + rm -f $(SENDER) $(RECEIVER) + +# It is likely that you will need to update this +tests: all + ./tests/run_tests.sh + +# By default, logs are disabled. But you can enable them with the debug target. +debug: CFLAGS += -D_DEBUG +debug: clean all + +# Place the zip in the parent repository of the project +ZIP_NAME="../projet1_nom1_nom2.zip" + +# A zip target, to help you have a proper zip file. You probably need to adapt this code. +zip: + # Generate the log file stat now. Try to keep the repository clean. + git log --stat > gitlog.stat + zip -r $(ZIP_NAME) Makefile README.md src tests rapport.pdf gitlog.stat + # We remove it now, but you can leave it if you want. + rm gitlog.stat diff --git a/README.md b/README.md index 1d2844da5210e027ff50350bbfcbf653c94dfd81..afcd6691d8f0f55fd60f8f1eeee85a3a922456e5 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,19 @@ -# project_TRTP +# My Wonderful LINFO1341 Project +The very first thing you might want to do in this folder is the following command: +```bash +git init +``` + +This will initialize your Git repository. +You should also put it in a **private** repository (GitHub, GitLab, Bitbucket,... it is up to you but it **has to** stay private). + +The Makefile contains all the required targets, but you might want to extend their behavior. + +Very basic skelettons of receiver and sender source files are present, have a look to understand how you can enable logging or not. + +A very simple test case is present, you probably want to update it. + +You might be interested in the link simulator that can be found at https://github.com/cnp3/Linksimulator + +And finally, if this message is still there at your final submission, it looks like you forgot to provide a proper README. \ No newline at end of file diff --git a/src/log.c b/src/log.c new file mode 100644 index 0000000000000000000000000000000000000000..25874a85e483f67b32d15a94547d30ba7ee6684a --- /dev/null +++ b/src/log.c @@ -0,0 +1,21 @@ +/*** + * A set of logging macro and functions that can be used. + */ + +#include "log.h" + +/* Prints `len` bytes starting from `bytes` to stderr */ +void dump(const uint8_t *bytes, size_t len) { + for (size_t i = 0; i < len;) { + fprintf(stderr, "%04x: ", (int) i); + + for (size_t j = 0; j < 16 && i + j < len; j++) { + fprintf(stderr, "%02x ", bytes[i + j]); + } + fprintf(stderr, "\t"); + for (size_t j = 0; j < 16 && i < len; j++, i++) { + fprintf(stderr,"%c ", bytes[i]); + } + fprintf(stderr,"\n"); + } +} \ No newline at end of file diff --git a/src/log.h b/src/log.h new file mode 100644 index 0000000000000000000000000000000000000000..935275ff7a20fc8ef17cb1c10dac261b59686a7e --- /dev/null +++ b/src/log.h @@ -0,0 +1,57 @@ +/*** + * A set of logging macro and functions that can be used. + */ + +#ifndef __LOG_H_ +#define __LOG_H_ + +#include <stdlib.h> +#include <stdio.h> +#include <stdint.h> +#include <stddef.h> + +#ifdef _COLOR +/* Want more/other colors? See https://stackoverflow.com/a/3219471 and + * https://en.wikipedia.org/wiki/ANSI_escape_code#Colors + */ +#define ANSI_COLOR_BRIGHT_RED "\x1b[91m" +#define ANSI_COLOR_CYAN "\x1b[36m" +#define ANSI_COLOR_RESET "\x1b[0m" +#else +#define ANSI_COLOR_BRIGHT_RED +#define ANSI_COLOR_CYAN +#define ANSI_COLOR_RESET +#endif + +#define _LOG(color, prefix, msg, ...)\ + do {\ + fprintf(stderr, color prefix msg ANSI_COLOR_RESET "\n", ##__VA_ARGS__);\ + } while (0) + +#define ERROR(msg, ...) _LOG(ANSI_COLOR_BRIGHT_RED, "[ERROR] ", msg, ##__VA_ARGS__) + +#ifdef _DEBUG +#define DEBUG(msg, ...) _LOG(ANSI_COLOR_CYAN, "[DEBUG] ", msg, ##__VA_ARGS__) +#else +#define DEBUG(msg, ...) +#endif + +/* Displays an error if `cond` is not true */ +/* Maybe it could also stop the program ? */ +#define ASSERT(cond) if (!(cond)) { ERROR("Assertion \"%s\" failed at %s:%d", #cond, __FILE__, __LINE__); } + +/* Prints `len` bytes starting from `bytes` to stderr */ +void dump(const uint8_t *bytes, size_t len); + +/* Use this useful macro instead of the bare function*/ +#ifdef _DEBUG +#define DEBUG_DUMP(bytes, len) \ + do { \ + DEBUG("Dumping %ld bytes from pointer %p at %s:%d", (size_t) len, bytes, __FILE__, __LINE__); \ + dump((const uint8_t *) bytes, (size_t) len); \ + } while (0) +#else +#define DEBUG_DUMP(bytes, len) +#endif + +#endif // __LOG_H_ \ No newline at end of file diff --git a/src/receiver.c b/src/receiver.c new file mode 100644 index 0000000000000000000000000000000000000000..9b2c9aeb859e08d222937c1fcd863a343a3b4d79 --- /dev/null +++ b/src/receiver.c @@ -0,0 +1,58 @@ +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <stdint.h> + +#include "log.h" + +int print_usage(char *prog_name) { + ERROR("Usage:\n\t%s [-s stats_filename] listen_ip listen_port", prog_name); + return EXIT_FAILURE; +} + + +int main(int argc, char **argv) { + int opt; + + char *stats_filename = NULL; + char *listen_ip = NULL; + char *listen_port_err; + uint16_t listen_port; + + while ((opt = getopt(argc, argv, "s:h")) != -1) { + switch (opt) { + case 'h': + return print_usage(argv[0]); + case 's': + stats_filename = optarg; + break; + default: + return print_usage(argv[0]); + } + } + + if (optind + 2 != argc) { + ERROR("Unexpected number of positional arguments"); + return print_usage(argv[0]); + } + + listen_ip = argv[optind]; + listen_port = (uint16_t) strtol(argv[optind + 1], &listen_port_err, 10); + if (*listen_port_err != '\0') { + ERROR("Receiver port parameter is not a number"); + return print_usage(argv[0]); + } + + ASSERT(1 == 1); // Try to change it to see what happens when it fails + DEBUG_DUMP("Some bytes", 11); // You can use it with any pointer type + + // This is not an error per-se. + ERROR("Receiver has following arguments: stats_filename is %s, listen_ip is %s, listen_port is %u", + stats_filename, listen_ip, listen_port); + + DEBUG("You can only see me if %s", "you built me using `make debug`"); + ERROR("This is not an error, %s", "now let's code!"); + + // Now let's code! + return EXIT_SUCCESS; +} \ No newline at end of file diff --git a/src/sender.c b/src/sender.c new file mode 100644 index 0000000000000000000000000000000000000000..db31cc8e9d2b9cbfaeeba0851c29aefe35dedd59 --- /dev/null +++ b/src/sender.c @@ -0,0 +1,67 @@ +#include <stdlib.h> +#include <stdio.h> +#include <stdbool.h> +#include <unistd.h> +#include <stdint.h> + +#include "log.h" + +int print_usage(char *prog_name) { + ERROR("Usage:\n\t%s [-f filename] [-s stats_filename] [-c] receiver_ip receiver_port", prog_name); + return EXIT_FAILURE; +} + + +int main(int argc, char **argv) { + int opt; + + char *filename = NULL; + char *stats_filename = NULL; + char *receiver_ip = NULL; + char *receiver_port_err; + bool fec_enabled = false; + uint16_t receiver_port; + + while ((opt = getopt(argc, argv, "f:s:hc")) != -1) { + switch (opt) { + case 'f': + filename = optarg; + break; + case 'h': + return print_usage(argv[0]); + case 's': + stats_filename = optarg; + break; + case 'c': + fec_enabled = true; + break; + default: + return print_usage(argv[0]); + } + } + + if (optind + 2 != argc) { + ERROR("Unexpected number of positional arguments"); + return print_usage(argv[0]); + } + + receiver_ip = argv[optind]; + receiver_port = (uint16_t) strtol(argv[optind + 1], &receiver_port_err, 10); + if (*receiver_port_err != '\0') { + ERROR("Receiver port parameter is not a number"); + return print_usage(argv[0]); + } + + ASSERT(1 == 1); // Try to change it to see what happens when it fails + DEBUG_DUMP("Some bytes", 11); // You can use it with any pointer type + + // This is not an error per-se. + ERROR("Sender has following arguments: filename is %s, stats_filename is %s, fec_enabled is %d, receiver_ip is %s, receiver_port is %u", + filename, stats_filename, fec_enabled, receiver_ip, receiver_port); + + DEBUG("You can only see me if %s", "you built me using `make debug`"); + ERROR("This is not an error, %s", "now let's code!"); + + // Now let's code! + return EXIT_SUCCESS; +} diff --git a/tests/run_tests.sh b/tests/run_tests.sh new file mode 100755 index 0000000000000000000000000000000000000000..91f236b3e0597d0fbf25b24719d9682fdb754756 --- /dev/null +++ b/tests/run_tests.sh @@ -0,0 +1,6 @@ +# Note that this assumes to be called from the Makefile, you may want to adapt it. +@echo "A very simple test" +./tests/simple_test.sh +# Run the same test, but this time with valgrind +@echo "A very simple test, with Valgrind" +VALGRIND=1 ./tests/simple_test.sh \ No newline at end of file diff --git a/tests/simple_test.sh b/tests/simple_test.sh new file mode 100755 index 0000000000000000000000000000000000000000..58a3a1a1431524bd0655c3c671714ed7c9496fd3 --- /dev/null +++ b/tests/simple_test.sh @@ -0,0 +1,58 @@ +#!/bin/bash + +# cleanup d'un test précédent +rm -f received_file input_file + +# Fichier au contenu aléatoire de 512 octets +dd if=/dev/urandom of=input_file bs=1 count=512 &> /dev/null + +valgrind_sender="" +valgrind_receiver="" +if [ ! -z "$VALGRIND" ] ; then + valgrind_sender="valgrind --leak-check=full --log-file=valgrind_sender.log" + valgrind_receiver="valgrind --leak-check=full --log-file=valgrind_receiver.log" +fi + +# On lance le receiver et capture sa sortie standard +$valgrind ./receiver -f received_file :: 2456 2> receiver.log & +receiver_pid=$! + +cleanup() +{ + kill -9 $receiver_pid + kill -9 $link_pid + exit 0 +} +trap cleanup SIGINT # Kill les process en arrière plan en cas de ^-C + +# On démarre le transfert +if ! $valgrind ./sender ::1 1341 < input_file 2> sender.log ; then + echo "Crash du sender!" + cat sender.log + err=1 # On enregistre l'erreur +fi + +sleep 5 # On attend 5 seconde que le receiver finisse + +if kill -0 $receiver_pid &> /dev/null ; then + echo "Le receiver ne s'est pas arreté à la fin du transfert!" + kill -9 $receiver_pid + err=1 +else # On teste la valeur de retour du receiver + if ! wait $receiver_pid ; then + echo "Crash du receiver!" + cat receiver.log + err=1 + fi +fi + +# On vérifie que le transfert s'est bien déroulé +if [[ "$(md5sum input_file | awk '{print $1}')" != "$(md5sum received_file | awk '{print $1}')" ]]; then + echo "Le transfert a corrompu le fichier!" + echo "Diff binaire des deux fichiers: (attendu vs produit)" + diff -C 9 <(od -Ax -t x1z input_file) <(od -Ax -t x1z received_file) + exit 1 +else + echo "Le transfert est réussi!" + exit ${err:-0} # En cas d'erreurs avant, on renvoie le code d'erreur +fi \ No newline at end of file