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