From 07f01d932f24cca77f2150bf6f666f3d12f92660 Mon Sep 17 00:00:00 2001 From: "Juan F. Codagnone" Date: Thu, 15 Mar 2018 13:02:19 -0300 Subject: [PATCH] =?UTF-8?q?netutils.c=20--=20peque=C3=B1as=20utilidades?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clasicas funciones de utilidad para imprimir de forma humana direcciones IP, y escribir de forma bloquante asegurando que cada byte fue escrito. --- src/netutils.c | 101 ++++++++++++++++++++++++++++++++++++++++++++ src/netutils.h | 43 +++++++++++++++++++ src/netutils_test.c | 91 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 235 insertions(+) create mode 100644 src/netutils.c create mode 100644 src/netutils.h create mode 100644 src/netutils_test.c diff --git a/src/netutils.c b/src/netutils.c new file mode 100644 index 0000000..6f4786e --- /dev/null +++ b/src/netutils.c @@ -0,0 +1,101 @@ +#include +#include +#include +#include + +#include +#include + +#include "netutils.h" + +#define N(x) (sizeof(x)/sizeof((x)[0])) + +extern const char * +sockaddr_to_human(char *buff, const size_t buffsize, + const struct sockaddr *addr) { + if(addr == 0) { + strncpy(buff, "null", buffsize); + return buff; + } + in_port_t port; + void *p = 0x00; + bool handled = false; + + switch(addr->sa_family) { + case AF_INET: + p = &((struct sockaddr_in *) addr)->sin_addr; + port = ((struct sockaddr_in *) addr)->sin_port; + handled = true; + break; + case AF_INET6: + p = &((struct sockaddr_in6 *) addr)->sin6_addr; + port = ((struct sockaddr_in6 *) addr)->sin6_port; + handled = true; + break; + } + if(handled) { + if (inet_ntop(addr->sa_family, p, buff, buffsize) == 0) { + strncpy(buff, "unknown ip", buffsize); + buff[buffsize - 1] = 0; + } + } else { + strncpy(buff, "unknown", buffsize); + } + + strncat(buff, ":", buffsize); + buff[buffsize - 1] = 0; + const size_t len = strlen(buff); + + if(handled) { + snprintf(buff + len, buffsize - len, "%d", ntohs(port)); + } + buff[buffsize - 1] = 0; + + return buff; +} + +int +sock_blocking_write(const int fd, buffer *b) { + int ret = 0; + ssize_t nwritten; + size_t n; + uint8_t *ptr; + + do { + ptr = buffer_read_ptr(b, &n); + nwritten = send(fd, ptr, n, MSG_NOSIGNAL); + if (nwritten > 0) { + buffer_read_adv(b, nwritten); + } else /* if (errno != EINTR) */ { + ret = errno; + break; + } + } while (buffer_can_read(b)); + + return ret; +} + +int +sock_blocking_copy(const int source, const int dest) { + int ret = 0; + char buf[4096]; + ssize_t nread; + while ((nread = recv(source, buf, N(buf), 0)) > 0) { + char* out_ptr = buf; + ssize_t nwritten; + do { + nwritten = send(dest, out_ptr, nread, MSG_NOSIGNAL); + if (nwritten > 0) { + nread -= nwritten; + out_ptr += nwritten; + } else /* if (errno != EINTR) */ { + ret = errno; + goto error; + } + } while (nread > 0); + } + error: + + return ret; +} + diff --git a/src/netutils.h b/src/netutils.h new file mode 100644 index 0000000..553d391 --- /dev/null +++ b/src/netutils.h @@ -0,0 +1,43 @@ +#ifndef NETUTILS_H_CTCyWGhkVt1pazNytqIRptmAi5U +#define NETUTILS_H_CTCyWGhkVt1pazNytqIRptmAi5U + +#include + +#include "buffer.h" + +#define SOCKADDR_TO_HUMAN_MIN (INET6_ADDRSTRLEN + 5 + 1) +/** + * Describe de forma humana un sockaddr: + * + * @param buff el buffer de escritura + * @param buffsize el tamaño del buffer de escritura + * + * @param af address family + * @param addr la dirección en si + * @param nport puerto en network byte order + * + */ +const char * +sockaddr_to_human(char *buff, const size_t buffsize, + const struct sockaddr *addr); + + + +/** + * Escribe n bytes de buff en fd de forma bloqueante + * + * Retorna 0 si se realizó sin problema y errno si hubo problemas + */ +int +sock_blocking_write(const int fd, buffer *b); + + +/** + * copia todo el contenido de source a dest de forma bloqueante. + * + * Retorna 0 si se realizó sin problema y errno si hubo problemas + */ +int +sock_blocking_copy(const int source, const int dest); + +#endif diff --git a/src/netutils_test.c b/src/netutils_test.c new file mode 100644 index 0000000..c21e66a --- /dev/null +++ b/src/netutils_test.c @@ -0,0 +1,91 @@ +#include +#include +#include + +#include "netutils.h" + +START_TEST (test_sockaddr_to_human_ipv4) { + char buff[50] = {0}; + + struct sockaddr_in addr = { + .sin_family = AF_INET, + .sin_port = htons(9090), + }; + addr.sin_addr.s_addr = htonl(0x01020304); + const struct sockaddr *x = (const struct sockaddr *) &addr; + + ck_assert_str_eq(sockaddr_to_human(buff, sizeof(buff)/sizeof(buff[0]), x), + "1.2.3.4:9090"); + ck_assert_str_eq(sockaddr_to_human(buff, 5, x), "unkn"); + ck_assert_str_eq(sockaddr_to_human(buff, 8, x), "1.2.3.4"); + ck_assert_str_eq(sockaddr_to_human(buff, 9, x), "1.2.3.4:"); + ck_assert_str_eq(sockaddr_to_human(buff, 10, x), "1.2.3.4:9"); + ck_assert_str_eq(sockaddr_to_human(buff, 11, x), "1.2.3.4:90"); + ck_assert_str_eq(sockaddr_to_human(buff, 12, x), "1.2.3.4:909"); + ck_assert_str_eq(sockaddr_to_human(buff, 13, x), "1.2.3.4:9090"); +} +END_TEST + + +START_TEST (test_sockaddr_to_human_ipv6) { + char buff[50] = {0}; + + struct sockaddr_in6 addr = { + .sin6_family = AF_INET6, + .sin6_port = htons(9090), + }; + uint8_t *d = ((uint8_t *)&addr.sin6_addr); + for(int i = 0; i < 16; i++) { + d[i] = 0xFF; + } + + const struct sockaddr *x = (const struct sockaddr *) &addr; + ck_assert_str_eq(sockaddr_to_human(buff, 10, x), "unknown i"); + ck_assert_str_eq(sockaddr_to_human(buff, 39, x), "unknown ip:9090"); + ck_assert_str_eq(sockaddr_to_human(buff, 40, x), + "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"); + ck_assert_str_eq(sockaddr_to_human(buff, 41, x), + "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:"); + ck_assert_str_eq(sockaddr_to_human(buff, 42, x), + "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:9"); + ck_assert_str_eq(sockaddr_to_human(buff, 43, x), + "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:90"); + ck_assert_str_eq(sockaddr_to_human(buff, 44, x), + "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:909"); + ck_assert_str_eq(sockaddr_to_human(buff, 45, x), + "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:9090"); +} +END_TEST + +Suite * +hello_suite(void) { + Suite *s; + TCase *tc; + + s = suite_create("socks"); + + /* Core test case */ + tc = tcase_create("netutils"); + + tcase_add_test(tc, test_sockaddr_to_human_ipv4); + tcase_add_test(tc, test_sockaddr_to_human_ipv6); + suite_add_tcase(s, tc); + + return s; +} + +int +main(void) { + int number_failed; + Suite *s; + SRunner *sr; + + s = hello_suite(); + sr = srunner_create(s); + + srunner_run_all(sr, CK_NORMAL); + number_failed = srunner_ntests_failed(sr); + srunner_free(sr); + return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} +