netutils.c -- pequeñas utilidades
Clasicas funciones de utilidad para imprimir de forma humana direcciones IP, y escribir de forma bloquante asegurando que cada byte fue escrito.
This commit is contained in:
parent
b9ce264b75
commit
07f01d932f
|
@ -0,0 +1,101 @@
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
#ifndef NETUTILS_H_CTCyWGhkVt1pazNytqIRptmAi5U
|
||||||
|
#define NETUTILS_H_CTCyWGhkVt1pazNytqIRptmAi5U
|
||||||
|
|
||||||
|
#include <netinet/in.h>
|
||||||
|
|
||||||
|
#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
|
|
@ -0,0 +1,91 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <check.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue