diff --git a/headers/our_utils.h b/headers/our_utils.h index 8647c5ccc90e9c90280e64d3315f6d6ed13741c0..421c0dae01cc65dc592bf4cadfe457a498f5519a 100644 --- a/headers/our_utils.h +++ b/headers/our_utils.h @@ -44,11 +44,11 @@ int create_socket(struct sockaddr_in6 *source_addr, int src_port, struct sockadd /* Block the caller until a message is received on sfd, * and connect the socket to the source addresse of the received message * @sfd: a file descriptor to a bound socket but not yet connected - * @buffer : a non null buffer where it writes the received message. - * @len: after reading the message it sents the amount bytes read in len. * @return: 0 in case of success, -1 otherwise + * @POST: This call is idempotent, it does not 'consume' the data of the message, + * and could be repeated several times blocking only at the first call. */ -int wait_for_client(int sfd, int MAX_MESSAGE_SIZE, char * buffer, ssize_t * len); +int wait_for_client(int sfd); #endif \ No newline at end of file diff --git a/headers/receiver.h b/headers/receiver.h index c1fcb39dc5a5e3a8f6b3b68c0b849b86fbd58fdc..7bdbfea3ecaa2589d31346efa7d1a7ae6be47111 100644 --- a/headers/receiver.h +++ b/headers/receiver.h @@ -1,4 +1,25 @@ /** * @file receiver.h * @brief This header contains all the structures and functions definitions that ae going to be used by the receiver.c - */ \ No newline at end of file + */ + +#ifndef __RECEIVER_UTILS_ +#define __RECEIVER_UTILS_ + +/* We are using 8 bits to encode the seqnum therefore to fight redondance our window is of 2**(8)/2 */ +#define MAX_SELECTIVE_REPEAT_WINDOW 8 + +/* Represent the receiver's connection state */ +typedef struct __attribute__((__packed__)) +{ +} con_state_t; + + +/** + * Loop reading on socket and printing to the stdout + * @sfd : The socket file descriptor. It is both bound and connected. + * @return: as soon as the whole transfer is done. + */ +void receiver_read_write_loop(int sfd); + +#endif \ No newline at end of file diff --git a/headers/receiver_utils.h b/headers/receiver_utils.h deleted file mode 100644 index 572e45a56d126586e1b7d0858a2d9d6410708ff3..0000000000000000000000000000000000000000 --- a/headers/receiver_utils.h +++ /dev/null @@ -1,26 +0,0 @@ -/** - * @file receiver_utils.h - * @brief This header contains utils will be used by the receiver - * @date 2022-03-17 - */ - -#ifndef __RECEIVER_UTILS_ -#define __RECEIVER_UTILS_ - -/* We are using 8 bits to encode the seqnum therefore to fight redondance our window is of 2**(8)/2 */ -#define MAX_SELECTIVE_REPEAT_WINDOW 8 - -/* Represent the receiver's connection state */ -typedef struct __attribute__((__packed__)) -{ -} con_state_t; - - -/** - * Loop reading on socket and printing to the stdout - * @sfd : The socket file descriptor. It is both bound and connected. - * @return: as soon as the whole transfer is done. - */ -void receiver_read_write_loop(int sfd); - -#endif \ No newline at end of file diff --git a/receiver b/receiver new file mode 100755 index 0000000000000000000000000000000000000000..719d1d48efb0681ed0c3ffc65d75b512bda1a658 Binary files /dev/null and b/receiver differ diff --git a/sender b/sender new file mode 100755 index 0000000000000000000000000000000000000000..d9d0d784c392e7d8abde67d555244cfa9bef5cc1 Binary files /dev/null and b/sender differ diff --git a/src/our_utils.c b/src/our_utils.c index 0628f0102d40987a9084981633ff6a97bbbddc25..c07a716fce1e74ec34a929dadbdb637e76160481 100644 --- a/src/our_utils.c +++ b/src/our_utils.c @@ -89,22 +89,18 @@ int create_socket(struct sockaddr_in6 *source_addr, int src_port, struct sockadd return -1; } - -int wait_for_client(int sfd, int MAX_MESSAGE_SIZE, char * buffer, ssize_t * len) +int wait_for_client(int sfd) { + int MAX_MESSAGE_SIZE = 1024; + uint8_t buff[MAX_MESSAGE_SIZE]; // allocate the receive buffer on the stack struct sockaddr_storage peer_addr; // allocate the peer's address on the stack. It will be initialized when we receive a message socklen_t peer_addr_len = sizeof(struct sockaddr_storage); // variable that will contain the length of the peer's address - *len = recvfrom(sfd, buffer, MAX_MESSAGE_SIZE, MSG_PEEK, (struct sockaddr *) &peer_addr, &peer_addr_len); - if (*len == -1) - { - ERROR("On recvfrom while waiting for client"); + ssize_t amount_read = recvfrom(sfd, buff, MAX_MESSAGE_SIZE, MSG_PEEK, (struct sockaddr *) &peer_addr, &peer_addr_len); + if (amount_read == -1){ return -1; } - int err = connect(sfd, (struct sockaddr *) &peer_addr, sizeof(struct sockaddr_storage)); + int err = connect(sfd, (struct sockaddr *) &peer_addr, sizeof(struct sockaddr_storage)); if (err != EISCONN && err != 0) - { - ERROR("When connecting to client"); return -1; - } return 0; } \ No newline at end of file diff --git a/src/receiver.c b/src/receiver.c index 9afa9775c19c30501c8e0ad4911c8c7b5c27e1b1..ef5a129cefc927ba0adcef2cf69e55202a3d4161 100644 --- a/src/receiver.c +++ b/src/receiver.c @@ -13,7 +13,7 @@ #include "log.h" #include "packet_interface.h" #include "our_utils.h" -#include "receiver_utils.h" +#include "receiver.h" int print_usage(char *prog_name) { ERROR("Usage:\n\t%s [-s stats_filename] listen_ip listen_port", prog_name); diff --git a/src/receiver_utils.c b/src/receiver_utils.c index 9722c5553688598aa98af498046b537a024626fc..fdb3e2257aeb2983d173747537e5c3d85a4f5f5d 100644 --- a/src/receiver_utils.c +++ b/src/receiver_utils.c @@ -3,7 +3,7 @@ #include "packet_interface.h" #include <poll.h> #include "our_utils.h" -#include "receiver_utils.h" +#include "receiver.h" int send_data_if_inneed() { @@ -74,7 +74,7 @@ int connect_to_a_client(int sfd, pkt_t * init_pkt) char * buffer[PKT_MAX_LEN]; ssize_t written_in_buffer; // We suppose that the first contact is going to be our client no need to check for more - int err = wait_for_client(sfd, PKT_MAX_LEN, (char *)buffer, &written_in_buffer); + int err = wait_for_client(sfd); if (err != 0) return -1; DEBUG_DUMP(buffer, written_in_buffer); @@ -105,6 +105,7 @@ void receiver_read_write_loop(int sfd) int err = connect_to_a_client(sfd, pkt); if (err == 0) return; + // Handle initial packet. err = fwrite((void *) pkt_get_payload(pkt), sizeof(char), pkt_get_length(pkt), stdout); diff --git a/temp/get_ipv6_address.c b/temp/get_ipv6_address.c new file mode 100644 index 0000000000000000000000000000000000000000..d7f38800d1fe5a4f9ffbd3668b819e0c5efa9e27 --- /dev/null +++ b/temp/get_ipv6_address.c @@ -0,0 +1,253 @@ +#include <arpa/inet.h> +#include <errno.h> +#include <fcntl.h> +#include <netdb.h> +#include <netinet/in.h> +#include <poll.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <unistd.h> + +/*************************** Utilities ******************************/ + + +/*************************** Start Q1 *******************************/ +/* Resolve the resource name to an usable IPv6 address + * @address: The name to resolve + * @rval: Where the resulting IPv6 address descriptor should be stored + * @return: NULL if it succeeded, or a pointer towards + * a string describing the error if any. + * (const char* means the caller cannot modify or free the return value, + * so do not use malloc!) + */ +const char * real_address(const char *address, struct sockaddr_in6 *rval) +{ + struct addrinfo hints; + struct addrinfo *result; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET6; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = AI_CANONNAME; + hints.ai_protocol = 0; + int res = getaddrinfo(address, NULL, &hints, &result); + if ( res != 0 ) + return gai_strerror(res); + rval = (struct sockaddr_in6 *) memcpy( (void *) rval, result->ai_addr, sizeof(struct sockaddr_in6)); + freeaddrinfo(result); + return NULL; +} +/*************************** End Q1 *******************************/ + +/*************************** Start Q2 *****************************/ +void ipv6_to_str_unexpanded(char *str, const struct in6_addr *addr) { + sprintf(str, "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x", + (int)addr->s6_addr[0], (int)addr->s6_addr[1], + (int)addr->s6_addr[2], (int)addr->s6_addr[3], + (int)addr->s6_addr[4], (int)addr->s6_addr[5], + (int)addr->s6_addr[6], (int)addr->s6_addr[7], + (int)addr->s6_addr[8], (int)addr->s6_addr[9], + (int)addr->s6_addr[10], (int)addr->s6_addr[11], + (int)addr->s6_addr[12], (int)addr->s6_addr[13], + (int)addr->s6_addr[14], (int)addr->s6_addr[15]); +} + +int create_socket_bind(struct sockaddr_in6 * source_addr) +{ + // TODO: Create a IPv6 socket supporting datagrams + int sock = socket(AF_INET6, SOCK_DGRAM, 0); + // TODO: Bind it to the source + int err = bind(sock, (struct sockaddr *) source_addr, sizeof(struct sockaddr_in6)); + if (err == -1) + return -1; + + char text[100]; + ipv6_to_str_unexpanded(text, &(source_addr->sin6_addr)); + //const char * addr_str = inet_ntop(AF_INET6, (void *) &(source_addr->sin6_addr), text, 100); + fprintf(stderr, "Successfully bound to IPv6 address : %s, port : %d\n", text, ntohs(source_addr->sin6_port)); + return sock; +} + +int create_socket_connect(struct sockaddr_in6 * dest_addr) +{ + int sock = socket(AF_INET6, SOCK_DGRAM, 0); + int err = connect(sock, (struct sockaddr *) dest_addr, sizeof(*dest_addr)); + if (err == -1) + return -1; + char text[100]; + ipv6_to_str_unexpanded(text, &(dest_addr->sin6_addr)); + fprintf(stderr, "Successfully connected to IPv6 addresss: %s, port : %d\n", text, ntohs(dest_addr->sin6_port)); + return sock; +} + +/* Creates a socket and initialize it + * @source_addr: if !NULL, the source address that should be bound to this socket + * @src_port: if >0, the port on which the socket is listening + * @dest_addr: if !NULL, the destination address to which the socket should send data + * @dst_port: if >0, the destination port to which the socket should be connected + * @return: a file descriptor number representing the socket, + * or -1 in case of error (explanation will be printed on stderr) + */ +int create_socket(struct sockaddr_in6 *source_addr, int src_port, struct sockaddr_in6 *dest_addr, int dst_port) +{ + if ( source_addr != NULL && dest_addr == NULL ) + { + source_addr->sin6_port = htons(src_port); + return create_socket_bind(source_addr); + } else if ( source_addr == NULL && dest_addr != NULL ){ + dest_addr->sin6_port = htons(dst_port); + return create_socket_connect(dest_addr); + } + return -1; +} +/*************************** End Q2 *******************************/ + +/*************************** Start Q3 *****************************/ + +int handle_event(struct pollfd * pfd, ssize_t MAX_SIZE, char * buff) +{ + if (pfd->revents & POLLIN){ + ssize_t read_bytes = read(pfd->fd, (void *) buff, MAX_SIZE); + if (read_bytes == -1) + return 0; + size_t err = fwrite("Incoming : \n\t", sizeof(char), 14, stderr); + err = fflush(stderr); + err = fwrite((void *) buff, sizeof(char), read_bytes, stdout); + if (err == 0) + fprintf(stderr, "Nonesense\n"); + err = fflush(stdout); + return 1; + } else if (pfd->events & POLLHUP){ /*EOF or Error*/ + fprintf(stderr, "Error...\n"); + return 0; + } else { /* POLLOUT */ + size_t err; + size_t read_bytes = fread(buff, sizeof(char), MAX_SIZE, stdin); + if (read_bytes != 0) + { + err = write(pfd->fd, (void *) buff, read_bytes); + if (err == 0) + return 0; + err = fwrite("\n Sent\n", sizeof(char), 8, stderr); + } + err = fflush(stderr); + return 1; + } +} + +/* Loop reading a socket and printing to stdout, + * while reading stdin and writing to the socket + * @sfd: The socket file descriptor. It is both bound and connected. + * @return: as soon as stdin signals EOF + */ +void read_write_loop(int sfd) +{ + struct pollfd * pfds; + pfds = (struct pollfd *) calloc(2, sizeof(struct pollfd)); + if (pfds == NULL) + return; + pfds[0].fd = sfd; + pfds[0].events = POLLIN | POLLOUT; + + pfds[1].fd = 0; // stdin is defined to be file descriptor 0 + pfds[1].events = POLLIN ; + + int nb_open_fds = 2; + int MAX_SIZE = 1024; // Bytes + char buff[MAX_SIZE]; + size_t writen; + while (nb_open_fds > 1) + { + int ready = poll(pfds, 2, -1); + if (ready == -1) + return; + + if (pfds[0].revents & POLLIN){ + ssize_t read_bytes = read(pfds[0].fd, (void *) buff, MAX_SIZE); + if (read_bytes == -1) + return; + writen = fwrite((void *) buff, sizeof(char), read_bytes, stdout); + writen = fflush(stdout); + } else if ((pfds[0].revents & POLLHUP) || (pfds[0].revents & POLLERR)){ + nb_open_fds--; + } else if ((pfds[0].revents & POLLOUT) && (pfds[1].revents & POLLIN)){ + size_t read_bytes = fread(buff, sizeof(char), 1, stdin); + writen = fflush(stdin); + writen = write(pfds[0].fd, (void *) buff, read_bytes); + size_t e = -1; + if (writen == e || feof(stdin) != 0) + return; + } + } +} +/*************************** End Q3 *******************************/ + +/*************************** Start Q4 *****************************/ + +/* Block the caller until a message is received on sfd, + * and connect the socket to the source addresse of the received message + * @sfd: a file descriptor to a bound socket but not yet connected + * @return: 0 in case of success, -1 otherwise + * @POST: This call is idempotent, it does not 'consume' the data of the message, + * and could be repeated several times blocking only at the first call. + */ +int wait_for_client(int sfd) +{ + int MAX_MESSAGE_SIZE = 1024; + uint8_t buff[MAX_MESSAGE_SIZE]; // allocate the receive buffer on the stack + struct sockaddr_storage peer_addr; // allocate the peer's address on the stack. It will be initialized when we receive a message + socklen_t peer_addr_len = sizeof(struct sockaddr_storage); // variable that will contain the length of the peer's address + ssize_t amount_read = recvfrom(sfd, buff, MAX_MESSAGE_SIZE, MSG_PEEK, (struct sockaddr *) &peer_addr, &peer_addr_len); + if (amount_read == -1){ + return -1; + } + int err = connect(sfd, (struct sockaddr *) &peer_addr, sizeof(struct sockaddr_storage)); + if (err != EISCONN && err != 0) + return -1; + return 0; +} + +/*************************** End Q4 *******************************/ + +int main(int argc, char const *argv[]) +{ + if (argc != 4) + { + fprintf(stderr, "./get_ipv6_addr <name_to_resolve> <port> <flag>\n - <flag> ::= c `|` s\n"); + return (EXIT_SUCCESS); + } + + // Name resolving + struct sockaddr_in6 * addr = (struct sockaddr_in6 *) malloc(sizeof(struct sockaddr_in6)); + const char * res = real_address(argv[1], addr); + if (res != NULL) + { + fprintf(stderr, "An error occured when name resolving :\n\t%s\n", res); + return (EXIT_FAILURE); + } + + // Socket Binding or Connecting + int socket; + if (strncasecmp(argv[3], "c", 1) == 0) + { + socket = create_socket(NULL, 0, addr, atoi(argv[2])); + } else if (strncasecmp(argv[3], "s", 1) == 0) + { + socket = create_socket(addr, atoi(argv[2]), NULL, 0); + wait_for_client(socket); + } + if (socket == -1) + { + fprintf(stderr, "An error occured when connecting/binding to address\n"); + return (EXIT_FAILURE); + } + + read_write_loop(socket); + + close(socket); + // Writing and reading + return (EXIT_SUCCESS ); +} \ No newline at end of file