diff --git a/Makefile b/Makefile index 3a9ef3d..6bff332 100644 --- a/Makefile +++ b/Makefile @@ -5,13 +5,14 @@ CLIENT=client SERVER=server ERROR=errors.o CHALLENGE=challenges.o +RANDOM=random.o TMP := $(shell mktemp) -all: $(ERROR) $(CHALLENGE) $(CLIENT) $(SERVER) +all: $(ERROR) $(CHALLENGE) $(RANDOM) $(CLIENT) $(SERVER) -$(SERVER): server.c challenges.c errors.c include/errors.h include/challenges.h include/server.h - $(CC) $(CCFLAGS) server.c -o server challenges.o errors.o +$(SERVER): server.c challenges.c errors.c include/errors.h include/challenges.h include/server.h include/challengesLib.h + $(CC) $(CCFLAGS) server.c -o server challenges.o errors.o random.o -lm objcopy --add-section .RUN_ME="$(TMP)" --set-section-flags .mydata=noload,readonly server strip --strip-debug server rm "$(TMP)" @@ -23,7 +24,7 @@ $(CLIENT): client.c errors.c include/errors.h include/client.h $(CC) $(CCFLAGS) -I./include -c $< clean: - rm -rf $(ERROR) $(CHALLENGE) $(CLIENT) $(SERVER) + rm -rf $(ERROR) $(CHALLENGE) $(CLIENT) $(SERVER) $(RANDOM) test: pvs-studio-analyzer trace -- make diff --git a/README.md b/README.md index 7b3744a..0406afd 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,19 @@ make all ## Ejecución -Ahora, tendrá dos ejecutables: `client` y `server`. +Ahora, tendrá dos ejecutables: `client` y `server`. Note que primero debe correr el `server` y luego conectarse con el `client`. + +```bash +./server +``` + +y en otra terminal + +```bash +./client +``` + +Debe notar que el `server` usará el puerto 8080 de localhost por lo que si tiene algún otro servidor en ese puerto debe cerrarlo antes de correrlo. ## Testeos @@ -37,7 +49,17 @@ En orden de realizar un análisis estático del sistema usted debe tener instala make test ``` -Por último, si quiere hacer un análisis dinámico (usando [valgrind](https://valgrind.org/)) debe... +Por último, si quiere hacer un análisis dinámico (usando [valgrind](https://valgrind.org/)) puede hacerlo mediante: + +```bash +valgrind ./server +``` + +y en otra terminal + +```bash +valgrind ./client +``` # Autores - Barmasch, Juan Martín (61033) diff --git a/challenges.c b/challenges.c index cb9e3ed..bcc116e 100644 --- a/challenges.c +++ b/challenges.c @@ -2,8 +2,6 @@ // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com #include "include/challenges.h" -char too_easy = 'a'; - char genChallenge(FILE * stream, char ** output, challenge_t challenge) { printf("------------- DESAFIO -------------\n"); printf("%s\n\n", challenge.message); @@ -19,7 +17,6 @@ char genChallenge(FILE * stream, char ** output, challenge_t challenge) { printSystemError("Challenges: getline()"); int ans = strcmp(*output, challenge.flag); - // free(*output); return !ans; } @@ -32,14 +29,14 @@ void filterChallenge() { char * ans = "La respuesta es K5n2UFfpFMUN\n"; int i = 0; while (ans[i] != '\0') { - int fdRandom = (rand() % (UPPER - LOWER + 1)) + LOWER; - if (fdRandom == STDOUT_FILENO) { + double fdRandom = getUniform(1); + if (fdRandom <= 0.25) { if (write(STDOUT_FILENO, ans + i++, 1) < 0) printSystemError("Challenges: write()"); } else { - for (int i = (rand() % (6)) + 1; i > 0; i--) { - int randNum = 90 * (rand() / (RAND_MAX + 1.0)); + for (int j = (int) getUniform(3) + 1; j > 0; j--) { + int randNum = (int) getUniform(90); char randLetter = (char) (randNum + '#'); if (write(STDERR_FILENO, &randLetter, 1) < 0) printSystemError("Challenges: write()"); @@ -95,4 +92,19 @@ void gdbChallenge() { printf("La respuesta es gdb_rules\n"); else printf("ENTER para reintentar.\n"); +} + +void boxMuller(double * normal) { + double random1 = getUniform(1); + double random2 = getUniform(1); + *normal = sqrt(-2 * log(random1)) * cos(2 * M_PI * random2); +} + +void normalChallenge() { + for (int i = 0; i < MAX_NORMALS; i++) { + double normal = 0; + boxMuller(&normal); + printf("%.6f ", normal); + } + printf("\n"); } \ No newline at end of file diff --git a/client.c b/client.c index cac786e..46cb63f 100644 --- a/client.c +++ b/client.c @@ -2,15 +2,15 @@ // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com #include "include/client.h" +void setSockAddress(int argc, char *argv[], struct sockaddr_in * address); + int main(int argc, char *argv[]) { - int fd = 0; + int fd; if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) printSystemError("User: socket()"); struct sockaddr_in serv_addr; - serv_addr.sin_family = AF_INET; - serv_addr.sin_port = htons(PORT); - serv_addr.sin_addr.s_addr = inet_addr(ADDRESS); + setSockAddress(argc, argv, &serv_addr); if (connect(fd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) printSystemError("User: connect()"); @@ -30,3 +30,30 @@ int main(int argc, char *argv[]) { return EXIT_SUCCESS; } + +void setSockAddress(int argc, char *argv[], struct sockaddr_in * address) { + address->sin_family = AF_INET; + + if (argc == 1) { + address->sin_addr.s_addr = inet_addr(ADDRESS); + address->sin_port = htons(PORT); + } + + int opt; + while ((opt = getopt(argc, argv, "a:p:")) != -1) { + switch (opt) { + case 'a': + if (optarg[0] == '-') + printError("Usage: server [-a address] [-p port]\n"); + address->sin_addr.s_addr = inet_addr(optarg); + break; + case 'p': + if (optarg[0] == '-') + printError("Usage: server [-a address] [-p port]\n"); + address->sin_port = htons(atoi(optarg)); + break; + default: + printError("Usage: server [-a address] [-p port]\n"); + } + } +} \ No newline at end of file diff --git a/errors.c b/errors.c index dd8ed0a..cb59560 100644 --- a/errors.c +++ b/errors.c @@ -3,8 +3,7 @@ #include "include/errors.h" void printError(char * string) { - fprintf(stderr, "%s", string); - fprintf(stderr, "\n"); + fprintf(stderr, "%s\n", string); exit(EXIT_FAILURE); } diff --git a/include/challenges.h b/include/challenges.h index a42626a..ae657b1 100644 --- a/include/challenges.h +++ b/include/challenges.h @@ -7,11 +7,15 @@ #include #include #include +#include #include "errors.h" +#include "random.h" #define MAX_LEN 100 +#define MAX_NORMALS 1000 #define UPPER 2 #define LOWER 1 +#define M_PI 3.14159265358979323846 typedef struct challenge_t { char * message; @@ -26,5 +30,6 @@ void filterChallenge(); void questionChallenge(); void quineChallenge(); void gdbChallenge(); +void normalChallenge(); #endif \ No newline at end of file diff --git a/include/challengesLib.h b/include/challengesLib.h new file mode 100644 index 0000000..01c942d --- /dev/null +++ b/include/challengesLib.h @@ -0,0 +1,51 @@ +#ifndef CHALLENGESLIB_H +#define CHALLENGESLIB_H + +#include "challenges.h" + +#define MAX_CHALLENGES 12 + +challenge_t challenges[] = { + {"Bienvenidos al TP3 y felicitaciones, ya resolvieron el primer acertijo.\n\n\ +En este TP deberán finalizar el juego que ya comenzaron resolviendo los desafíos \ +de cada nivel.\nAdemás tendrán que investigar otras preguntas para responder \ +durante la defensa.\nEl desafío final consiste en crear un programa que se \ +comporte igual que yo, es decir, que provea los mismos desafíos y que sea necesario \ +hacer lo mismo para resolverlos. No basta con esperar la respuesta.\nAdemás, \ +deberán implementar otro programa para comunicarse conmigo.\n\nDeberán estar atentos \ +a los easter eggs.\n\nPara verificar que sus respuestas tienen el formato correcto \ +respondan a este desafío con la palabra 'entendido\\n'", "¿Cómo descubrieron el protocolo, \ +la dirección y el puerto para conectarse?", "entendido\n", NULL}, + {"The Wire S1E5\n5295 888 6288", "¿Qué diferencias hay entre TCP y UDP y en qué casos \ +conviene usar cada uno?", "itba\n", NULL}, + {"https://ibb.co/tc0Hb6w", "¿El puerto que usaron para conectarse al server es el mismo \ +que usan para mandar las respuestas? ¿Por qué?", "M4GFKZ289aku\n", NULL}, + {"EBADF...", "¿Qué útil abstracción es utilizada para comunicarse con sockets? ¿se puede \ +utilizar read(2) y write(2) para operar?", "fk3wfLCm3QvS\n", writeChallenge}, + {"respuesta = strings:269", "¿Cómo garantiza TCP que los paquetes llegan en orden y no se \ +pierden?", "too_easy\n", NULL}, + {".data .bss .comment ? .shstrtab .symtab .strtab", "Un servidor suele crear un nuevo proceso \ +o thread para atender las conexiones entrantes. ¿Qué conviene más?", ".RUN_ME\n", NULL}, + {"Filter error", "¿Cómo se puede implementar un servidor que atienda muchas conexiones sin usar \ +procesos ni threads?", "K5n2UFfpFMUN\n", filterChallenge}, + {"¿?", "¿Qué aplicaciones se pueden utilizar para ver el tráfico por la red?", + "BUmyYq5XxXGt\n", questionChallenge}, + {"Latexme\n\nSi\n \\mathrm{d}y = u^v{\\cdot}(v'{\\cdot}\\ln{(u)}+v{\\cdot}\\frac{u'}{u})\n\ +entonces\ny = ", "sockets es un mecanismo de IPC. ¿Qué es más eficiente entre sockets y pipes?", + "u^v\n", NULL}, + {"quine", "¿Cuáles son las características del protocolo SCTP?", "chin_chu_lan_cha\n", quineChallenge}, + {"b gdbme y encontrá el valor mágico", "¿Qué es un RFC?", "gdb_rules\n", gdbChallenge}, + {"Me conoces", "¿Fue divertido?", "normal\n", normalChallenge} +}; + +char too_easy = 'a'; +char * easter_egg1 = " _______________________\n\ +< ESTO ES UN EASTER_EGG >\n\ + -----------------------\n\ + \\ ^__^\n\ + \\ (oo)\\_______\n\n\ + (__)\\ )\\/\\\n\ + ||----w |\n\ + || ||\n"; + +#endif \ No newline at end of file diff --git a/include/client.h b/include/client.h index 277e179..f123fb2 100644 --- a/include/client.h +++ b/include/client.h @@ -1,6 +1,8 @@ #ifndef CLIENT_H #define CLIENT_H +#define _POSIX_C_SOURCE 200809L + #include #include #include diff --git a/include/random.h b/include/random.h new file mode 100644 index 0000000..dc80db5 --- /dev/null +++ b/include/random.h @@ -0,0 +1,8 @@ +#ifndef MATH_H +#define MATH_H + +#include + +double getUniform(uint32_t max); + +#endif \ No newline at end of file diff --git a/include/server.h b/include/server.h index 420629c..66839f7 100644 --- a/include/server.h +++ b/include/server.h @@ -13,46 +13,14 @@ #include #include "errors.h" #include "challenges.h" +#include "challengesLib.h" #define MAX_LEN 100 #define PORT 8080 #define ADDRESS "127.0.0.1" #define MAX_PEND_REQ 3 -#define MAX_CHALLENGES 11 #define TIME_SLEEP 2 -challenge_t challenges[] = { - {"Bienvenidos al TP3 y felicitaciones, ya resolvieron el primer acertijo.\n\n\ -En este TP deberán finalizar el juego que ya comenzaron resolviendo los desafíos \ -de cada nivel.\n\nAdemás tendrán que investigar otras preguntas para responder \ -durante la defensa.\n\nEl desafío final consiste en crear un programa que se \ -comporte igual que yo, es decir, que provea los mismos desafíos y que sea necesario \ -hacer lo mismo para resolverlos. No basta con esperar la respuesta.\n\nAdemás, \ -deberán implementar otro programa para comunicarse conmigo.\n\nDeberán estar atentos \ -a los easter eggs.\n\nPara verificar que sus respuestas tienen el formato correcto \ -respondan a este desafío con la palabra 'entendido\\n'", "¿Cómo descubrieron el protocolo, \ -la dirección y el puerto para conectarse?", "entendido\n", NULL}, - {"The Wire S1E5\n\n5295 888 6288", "¿Qué diferencias hay entre TCP y UDP y en qué casos \ -conviene usar cada uno?", "itba\n", NULL}, - {"https://ibb.co/tc0Hb6w", "¿El puerto que usaron para conectarse al server es el mismo \ -que usan para mandar las respuestas? ¿Por qué?", "M4GFKZ289aku\n", NULL}, - {"EBADF...", "¿Qué útil abstracción es utilizada para comunicarse con sockets? ¿se puede \ -utilizar read(2) y write(2) para operar?", "fk3wfLCm3QvS\n", writeChallenge}, - {"respuesta = strings:269", "¿Cómo garantiza TCP que los paquetes llegan en orden y no se \ -pierden?", "too_easy\n", NULL}, - {".data .bss .comment ? .shstrtab .symtab .strtab", "Un servidor suele crear un nuevo proceso \ -o thread para atender las conexiones entrantes. ¿Qué conviene más?", ".RUN_ME\n", NULL}, - {"Filter error", "¿Cómo se puede implementar un servidor que atienda muchas conexiones sin usar \ -procesos ni threads?", "K5n2UFfpFMUN\n", filterChallenge}, - {"¿?", "¿Qué aplicaciones se pueden utilizar para ver el tráfico por la red?", - "BUmyYq5XxXGt\n", questionChallenge}, - {"Latexme\n\nSi\n \\mathrm{d}y = u^v{\\cdot}(v'{\\cdot}\\ln{(u)}+v{\\cdot}\\frac{u'}{u})\n\ -entonces\ny =", "sockets es un mecanismo de IPC. ¿Qué es más eficiente entre sockets y pipes?", - "u^v\n", NULL}, - {"quine", "¿Cuáles son las características del protocolo SCTP?", "chin_chu_lan_cha\n", quineChallenge}, - {"b gdbme y encontrá el valor mágico", "¿Qué es un RFC?", "gdb_rules\n", gdbChallenge}, -}; - void startChallenge(); #endif \ No newline at end of file diff --git a/quine.c b/quine.c index 9927c54..c86c7ce 100644 --- a/quine.c +++ b/quine.c @@ -1,3 +1 @@ -// This is a personal academic project. Dear PVS-Studio, please check it. -// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com main() { char *s="main() { char *s=%c%s%c; printf(s,34,s,34,10); }%c"; printf(s,34,s,34,10); } diff --git a/random.c b/random.c new file mode 100644 index 0000000..db49d70 --- /dev/null +++ b/random.c @@ -0,0 +1,17 @@ +// This is a personal academic project. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +#include "include/random.h" + +static uint32_t m_z = 362436069; +static uint32_t m_w = 521288629; + +uint32_t getUint() { + m_z = 36969 * (m_z & 65535) + (m_z >> 16); + m_w = 18000 * (m_w & 65535) + (m_w >> 16); + return (m_z << 16) + m_w; +} + +double getUniform(uint32_t max) { + uint32_t u = getUint(); + return (u + 1.0) * 2.328306435454494e-10 * max; +} \ No newline at end of file diff --git a/server.c b/server.c index e9b97fb..44b7c54 100644 --- a/server.c +++ b/server.c @@ -2,6 +2,8 @@ // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com #include "include/server.h" +void setSockAddress(int argc, char *argv[], struct sockaddr_in * address); + int main(int argc, char *argv[]) { int fd; if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) @@ -12,10 +14,7 @@ int main(int argc, char *argv[]) { printSystemError("Server: setsockopt()"); struct sockaddr_in address; - address.sin_family = AF_INET; - // address.sin_addr.s_addr = INADDR_ANY; - address.sin_addr.s_addr = inet_addr(ADDRESS); - address.sin_port = htons(PORT); + setSockAddress(argc, argv, &address); if (bind(fd, (struct sockaddr *) &address, sizeof(address)) < 0) printSystemError("Server: bind()"); @@ -27,6 +26,9 @@ int main(int argc, char *argv[]) { if ((fdAux = accept(fd, (struct sockaddr *) &address, (socklen_t *) &addrlen)) < 0) printSystemError("Server: accept()"); + if (setvbuf(stdout, NULL, _IONBF, 0) != 0) + printSystemError("Server: setvbuf()"); + startChallenge(fdAux); close(fdAux); @@ -43,7 +45,6 @@ void startChallenge(int fd) { int challengeCount = 0; char * output = NULL; - srand(time(NULL)); while (challengeCount < MAX_CHALLENGES) { challenge_t currentChallenge = challenges[challengeCount]; printf("\033[1;1H\033[2J"); @@ -57,7 +58,38 @@ void startChallenge(int fd) { free(output); } - fclose(stream); + printf("\033[1;1H\033[2J"); + printf("Felicitaciones, finalizaron el juego. Ahora deberán implementar el servidor que se comporte como el servidor provisto\n"); + + if (stream != NULL) + fclose(stream); return; +} + +void setSockAddress(int argc, char *argv[], struct sockaddr_in * address) { + address->sin_family = AF_INET; + + if (argc == 1) { + address->sin_addr.s_addr = inet_addr(ADDRESS); + address->sin_port = htons(PORT); + } + + int opt; + while ((opt = getopt(argc, argv, "a:p:")) != -1) { + switch (opt) { + case 'a': + if (optarg[0] == '-') + printError("Usage: server [-a address] [-p port]\n"); + address->sin_addr.s_addr = inet_addr(optarg); + break; + case 'p': + if (optarg[0] == '-') + printError("Usage: server [-a address] [-p port]\n"); + address->sin_port = htons(atoi(optarg)); + break; + default: + printError("Usage: server [-a address] [-p port]\n"); + } + } } \ No newline at end of file