Enviado em 22/06/2021 - 18:42h
TL;DR#include <stdio.h> #include <errno.h> #include <string.h> #include <stdlib.h> #include <netdb.h> #include <unistd.h> #include <arpa/inet.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #define SERVICE "9009" #define MAXCONN 3 static int make_server_socket(void) { int sockfd, ecode; struct addrinfo hints, *result = NULL, *rp = NULL; memset(&hints, 0, sizeof(hints)); hints.ai_flags = AI_PASSIVE; hints.ai_family = AF_INET6; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = 0; if ((ecode = getaddrinfo(NULL, SERVICE, &hints, &result)) != 0 ) { fprintf(stderr, "make_server_socket() -> getaddrinfo() -> ERROR: %s\n", gai_strerror(ecode)); exit(EXIT_FAILURE); } for (rp = result; rp != NULL; rp = rp->ai_next) { if ((sockfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol)) < 0 ) { continue; } if (bind(sockfd, rp->ai_addr, rp->ai_addrlen) != -1 ) { break; } close(sockfd); } if (rp == NULL) { fprintf(stderr, "make_server_socket() -> socket()/bind() -> ERROR: %s\n", strerror(errno)); close(sockfd); exit(EXIT_FAILURE); } if (listen(sockfd, SOMAXCONN) < 0 ) { fprintf(stderr, "make_server_socket() -> listen() -> ERROR: %s\n", strerror(errno)); close(sockfd); exit(EXIT_FAILURE); } return sockfd; } static int check_addr(int af, const unsigned char *buff_addr, unsigned char **buff_addr_table, size_t count) { int res = 0; if (af == AF_INET) { struct sockaddr_in *addr4 = (struct sockaddr_in*)buff_addr; for (size_t i = 0; i < count; i++) { struct sockaddr_in *addr4_from_table = (struct sockaddr_in*)buff_addr_table[i]; if (memcmp(&addr4->sin_addr.s_addr, &addr4_from_table->sin_addr.s_addr, sizeof(addr4->sin_addr.s_addr)) == 0 ) { res = -1; } } } else if (af == AF_INET6) { struct sockaddr_in6 *addr6 = (struct sockaddr_in6*)buff_addr; for(size_t i = 0; i < count; i++) { struct sockaddr_in6 *addr6_from_table = (struct sockaddr_in6*)buff_addr_table[i]; if (memcmp(&addr6->sin6_addr.s6_addr, &addr6_from_table->sin6_addr.s6_addr, sizeof(addr6->sin6_addr.s6_addr)) == 0 ) { res = -1; } } } else { res = -1; } return res; } static void show_addr(int af, unsigned char *buff_addr) { char *ip = NULL; if (af == AF_INET) { ip = malloc(INET_ADDRSTRLEN * sizeof(*ip)); struct sockaddr_in *addr4 = (struct sockaddr_in*)buff_addr; if (inet_ntop(af, &addr4->sin_addr.s_addr, ip, INET_ADDRSTRLEN) < 0 ) { fprintf(stderr, "show_addr() -> inet_ntop() -> ERROR: %s\n", strerror(errno)); } else { printf("%s\n", ip); } } else { ip = malloc(INET6_ADDRSTRLEN * sizeof(*ip)); struct sockaddr_in6 *addr6 = (struct sockaddr_in6*)buff_addr; if (inet_ntop(af, &addr6->sin6_addr.s6_addr, ip, INET6_ADDRSTRLEN) < 0 ) { fprintf(stderr, "show_addr() -> inet_ntop() -> ERROR: %s\n", strerror(errno)); } else { printf("%s\n", ip); } } free(ip); } static unsigned char **realloc_addr_table(unsigned char **buff_addr_table, size_t count, size_t addrlen) { buff_addr_table = realloc(buff_addr_table, count * sizeof(*buff_addr_table)); if (buff_addr_table == NULL) { fprintf(stderr, "ERROR: Memory allocation for %zu bytes failed\n", count * sizeof(unsigned char *)); fprintf(stderr, "realloc_addr_table -> realloc() -> ERROR: %s\n", strerror(errno)); } buff_addr_table[count-1] = calloc(count, addrlen * sizeof(*buff_addr_table)); if (buff_addr_table == NULL) { fprintf(stderr, "ERROR: Memory allocation for %zu bytes failed\n", count * sizeof(unsigned char *)); fprintf(stderr, "realloc_addr_table -> realloc() -> ERROR: %s\n", strerror(errno)); } return buff_addr_table; } static void free_addr_table(unsigned char **buff_addr_table, size_t count) { for (size_t i = 0; i < count; i++) { free(buff_addr_table[i]); } free(buff_addr_table); } static void search(void) { size_t i = 0; int sockfd = make_server_socket(); unsigned char *buff_addr = NULL, **buff_addr_table = NULL; const char msg_1[] = "Welcome!\n", msg_2[] = "Get out!\n"; while (i < MAXCONN) { int new_sockfd; struct sockaddr addr; socklen_t addrlen = sizeof(addr); if ((new_sockfd = accept(sockfd, &addr, &addrlen)) < 0 ) { fprintf(stderr, "search() -> accept() -> ERROR: %s\n", strerror(errno)); } else { buff_addr = (unsigned char *)&addr; if (check_addr(addr.sa_family, buff_addr, buff_addr_table, i) != -1 ) { i++; buff_addr_table = realloc_addr_table(buff_addr_table, i, addrlen); memcpy(buff_addr_table[i-1], &addr, addrlen * sizeof(*buff_addr_table)); show_addr(addr.sa_family, buff_addr); send(new_sockfd, msg_1, sizeof(msg_1), 0); }else{ send(new_sockfd, msg_2, sizeof(msg_2), 0); } close(new_sockfd); } } free_addr_table(buff_addr_table, i); close(sockfd); } int main(void) { search(); return EXIT_SUCCESS; }
[AB2201@fedora TCP]$ gcc -Wall server.c -o server [AB2201@fedora TCP]$ ./server ::d00:0:0:0
[AB2201@fedora TCP]$ nc 127.0.0.1 9009 Welcome! ^C [AB2201@fedora TCP]$ nc ::1 9009 Get out! ^C [AB2201@fedora TCP]$ nc 192.168.1.107 9009 Get out! ^C [AB2201@fedora TCP]$
::ffff:127.0.0.1 ::1 ::ffff:192.168.1.107
Enviado em 22/06/2021 - 19:03h
Aproveitando a pergunta... Aquele último else em check_addr() faz sentido?static int check_addr(int af, const unsigned char *buff_addr, unsigned char **buff_addr_table, size_t count) { int res = 0; if (af == AF_INET) { struct sockaddr_in *addr4 = (struct sockaddr_in*)buff_addr; for (size_t i = 0; i < count; i++) { struct sockaddr_in *addr4_from_table = (struct sockaddr_in*)buff_addr_table[i]; if (memcmp(&addr4->sin_addr.s_addr, &addr4_from_table->sin_addr.s_addr, sizeof(addr4->sin_addr.s_addr)) == 0 ) { res = -1; } } } else if (af == AF_INET6) { struct sockaddr_in6 *addr6 = (struct sockaddr_in6*)buff_addr; for(size_t i = 0; i < count; i++) { struct sockaddr_in6 *addr6_from_table = (struct sockaddr_in6*)buff_addr_table[i]; if (memcmp(&addr6->sin6_addr.s6_addr, &addr6_from_table->sin6_addr.s6_addr, sizeof(addr6->sin6_addr.s6_addr)) == 0 ) { res = -1; } } } else { res = -1; } return res; }
static int check_addr(int af, const unsigned char *buff_addr, unsigned char **buff_addr_table, size_t count) { int res = 0; if (af == AF_INET) { struct sockaddr_in *addr4 = (struct sockaddr_in*)buff_addr; for (size_t i = 0; i < count; i++) { struct sockaddr_in *addr4_from_table = (struct sockaddr_in*)buff_addr_table[i]; if (memcmp(&addr4->sin_addr.s_addr, &addr4_from_table->sin_addr.s_addr, sizeof(addr4->sin_addr.s_addr)) == 0 ) { res = -1; } } } else { struct sockaddr_in6 *addr6 = (struct sockaddr_in6*)buff_addr; for(size_t i = 0; i < count; i++) { struct sockaddr_in6 *addr6_from_table = (struct sockaddr_in6*)buff_addr_table[i]; if (memcmp(&addr6->sin6_addr.s6_addr, &addr6_from_table->sin6_addr.s6_addr, sizeof(addr6->sin6_addr.s6_addr)) == 0 ) { res = -1; } } } return res; }
Enviado em 22/06/2021 - 21:22h
Veja se o seguinte bloco lhe ajuda a ver o que está errado.$ cat x.c #include <sys/socket.h> #include <sys/un.h> #include <netinet/in.h> #include <stdio.h> int main(void){ printf("%zu\n", sizeof(struct sockaddr)); printf("%zu\n", sizeof(struct sockaddr_in)); printf("%zu\n", sizeof(struct sockaddr_in6)); printf("%zu\n", sizeof(struct sockaddr_un)); } $ gcc x.c -o x $ ./x 16 16 28 110
union sockaddr_any { int addr_family; struct sockaddr generic; struct sockaddr_in in; struct sockaddr_in6 in6; struct sockaddr_un un; };
union sockaddr_any client_addr; sockaddr_len addrlen=sizeof client_addr; /* Note que, abaixo, eu economizo uma conversão de ponteiro passando o endereço do campo que já tem o tipo que a função deseja, valendo-me do fato de que o endereço da união como um todo é numericamente idêntico ao endereço de cada um dos seus componentes. */ int cli_sock=accept(serv_sock, &client_addr.generic, &addrlen); switch(client_addr.addr_family){ case AF_INET: print_IPv4(client_addr.in.sin_addr.s_addr); break; case AF_INET: print_IPv6(&client_addr.in6.sin6_addr); break; case AF_LOCAL: printf("%s", client_addr.un.sun_path); break; default: fprintf(stderr, "Unexpected socket type.\n"; }
Enviado em 22/06/2021 - 23:19h
Algumas outras sugestões:void *new_ptr=realloc(buf_addr_table, count*sizeof *buf_addr_table); if(new_buf) buf_addr_table=new_ptr;
Enviado em 23/06/2021 - 15:00h
static unsigned char *check_addr(int af, unsigned char *buff_addr, unsigned char **buff_addr_table, size_t count) { unsigned char *res = buff_addr; if (af == AF_INET) { struct sockaddr_in *addr4 = (struct sockaddr_in*)buff_addr; for (size_t i = 0; i < count; i++) { struct sockaddr_in *addr4_from_table = (struct sockaddr_in*)buff_addr_table[i]; if (memcmp(&addr4->sin_addr.s_addr, &addr4_from_table->sin_addr.s_addr, sizeof(addr4->sin_addr.s_addr)) == 0 ) { res = NULL; } } } else { struct sockaddr_in6 *addr6 = (struct sockaddr_in6*)buff_addr; for(size_t i = 0; i < count; i++) { struct sockaddr_in6 *addr6_from_table = (struct sockaddr_in6*)buff_addr_table[i]; if (memcmp(&addr6->sin6_addr.s6_addr, &addr6_from_table->sin6_addr.s6_addr, sizeof(addr6->sin6_addr.s6_addr)) == 0 ) { res = NULL; } } } return res; }
void *new_ptr=realloc(buf_addr_table, count*sizeof *buf_addr_table); if(new_buf) buf_addr_table=new_ptr;
/*(código... etc)*/ /*Mantém a implementação original da função realloc_addr_table()*/ static unsigned char **realloc_addr_table(unsigned char **buff_addr_table, size_t count, size_t addrlen) { buff_addr_table = realloc(buff_addr_table, count * sizeof(*buff_addr_table)); if (buff_addr_table == NULL) { fprintf(stderr, "ERROR: Memory allocation for %zu bytes failed\n", count * sizeof(*buff_addr_table)); fprintf(stderr, "realloc_addr_table -> realloc() -> ERROR: %s\n", strerror(errno)); } buff_addr_table[count-1] = calloc(1, addrlen); if (buff_addr_table == NULL) { fprintf(stderr, "ERROR: Memory allocation for %zu bytes failed\n", addrlen); fprintf(stderr, "realloc_addr_table -> realloc() -> ERROR: %s\n", strerror(errno)); } return buff_addr_table; } static void free_addr_table(unsigned char **buff_addr_table, size_t count) { for (size_t i = 0; i < count; i++) { free(buff_addr_table[i]); } free(buff_addr_table); } static void search(void) { size_t i = 0; int sockfd = make_server_socket(); unsigned char *buff_addr = NULL, **buff_addr_table = NULL; const char msg_1[] = "Welcome!\n", msg_2[] = "Get out!\n"; while (i < MAXCONN) { int new_sockfd; struct sockaddr addr; socklen_t addrlen = sizeof(addr); if ((new_sockfd = accept(sockfd, &addr, &addrlen)) < 0 ) { fprintf(stderr, "search() -> accept() -> ERROR: %s\n", strerror(errno)); } else { buff_addr = (unsigned char *)&addr; if (check_addr(addr.sa_family, buff_addr, buff_addr_table, i) != NULL ) { unsigned char **tmp = realloc_addr_table(buff_addr_table, i+1, addrlen); /*Faz o uso do ponteiro auxiliar dentro da função search()*/ if (tmp != NULL) { i++; buff_addr_table = tmp; memcpy(buff_addr_table[i-1], &addr, addrlen); show_addr(addr.sa_family, buff_addr); send(new_sockfd, msg_1, sizeof(msg_1), 0); } }else{ send(new_sockfd, msg_2, sizeof(msg_2), 0); } close(new_sockfd); } } free_addr_table(buff_addr_table, i); close(sockfd); }
static void show_addr(int af, const unsigned char *buff_addr) { char ip[INET6_ADDRSTRLEN]; if (af == AF_INET) { struct sockaddr_in *addr4 = (struct sockaddr_in*)buff_addr; if (inet_ntop(af, &addr4->sin_addr.s_addr, ip, INET_ADDRSTRLEN) < 0 ) { fprintf(stderr, "show_addr() -> inet_ntop() -> ERROR: %s\n", strerror(errno)); } else { printf("%s\n", ip); } } else { struct sockaddr_in6 *addr6 = (struct sockaddr_in6*)buff_addr; if (inet_ntop(af, &addr6->sin6_addr.s6_addr, ip, INET6_ADDRSTRLEN) < 0 ) { fprintf(stderr, "show_addr() -> inet_ntop() -> ERROR: %s\n", strerror(errno)); } else { printf("%s\n", ip); } } }
Enviado em 23/06/2021 - 15:28h
Hey, Paulo! Além de todos os problemas que você indicou ainda há alguns que você não percebeu e só reparei agora pouco.static unsigned char **realloc_addr_table(unsigned char **buff_addr_table, size_t count, size_t addrlen) { buff_addr_table = realloc(buff_addr_table, count * sizeof(*buff_addr_table)); //Isso tá ok if (buff_addr_table == NULL) { fprintf(stderr, "ERROR: Memory allocation for %zu bytes failed\n", count * sizeof(unsigned char *)); fprintf(stderr, "realloc_addr_table -> realloc() -> ERROR: %s\n", strerror(errno)); } buff_addr_table[count-1] = calloc(count, addrlen * sizeof(*buff_addr_table)); /*count não deveria está dentro da função calloc, o certo seria alocar apenas o quantidade de bytes armazenados em addrlen*/ if (buff_addr_table == NULL) { fprintf(stderr, "ERROR: Memory allocation for %zu bytes failed\n", count * sizeof(unsigned char *)); //Isso tá errado também, deveria mostrar apenas a quantidade de bytes armazenados em addrlen fprintf(stderr, "realloc_addr_table -> realloc() -> ERROR: %s\n", strerror(errno)); } return buff_addr_table; }
static unsigned char **realloc_addr_table(unsigned char **buff_addr_table, size_t count, size_t addrlen) { buff_addr_table = realloc(buff_addr_table, count * sizeof(*buff_addr_table)); if (buff_addr_table == NULL) { fprintf(stderr, "ERROR: Memory allocation for %zu bytes failed\n", count * sizeof(*buff_addr_table)); fprintf(stderr, "realloc_addr_table -> realloc() -> ERROR: %s\n", strerror(errno)); } buff_addr_table[count-1] = calloc(1, addrlen); if (buff_addr_table == NULL) { fprintf(stderr, "ERROR: Memory allocation for %zu bytes failed\n", addrlen); fprintf(stderr, "realloc_addr_table -> realloc() -> ERROR: %s\n", strerror(errno)); } return buff_addr_table; }
} else { buff_addr = (unsigned char *)&addr; if (check_addr(addr.sa_family, buff_addr, buff_addr_table, i) != -1 ) { i++; buff_addr_table = realloc_addr_table(buff_addr_table, i, addrlen); memcpy(buff_addr_table[i-1], &addr, addrlen * sizeof(*buff_addr_table)); //Esse sizeof não faz sentido, deveria ser apenas addrlen para informar o tamanho do buffer de destino show_addr(addr.sa_family, buff_addr); send(new_sockfd, msg_1, sizeof(msg_1), 0); }else{ send(new_sockfd, msg_2, sizeof(msg_2), 0); } close(new_sockfd); }
Enviado em 23/06/2021 - 21:01h
static unsigned char *check_addr(int af, unsigned char *buff_addr, unsigned char **buff_addr_table, size_t count) { unsigned char *res = buff_addr; if (af == AF_INET) { struct sockaddr_in *addr4 = (struct sockaddr_in*)buff_addr; for (size_t i = 0; i < count; i++) { struct sockaddr_in *addr4_from_table = (struct sockaddr_in*)buff_addr_table[i]; if (memcmp(&addr4->sin_addr.s_addr, &addr4_from_table->sin_addr.s_addr, sizeof(addr4->sin_addr.s_addr)) == 0 ) { res = NULL; } } } else { struct sockaddr_in6 *addr6 = (struct sockaddr_in6*)buff_addr; for(size_t i = 0; i < count; i++) { struct sockaddr_in6 *addr6_from_table = (struct sockaddr_in6*)buff_addr_table[i]; if (memcmp(&addr6->sin6_addr.s6_addr, &addr6_from_table->sin6_addr.s6_addr, sizeof(addr6->sin6_addr.s6_addr)) == 0 ) { res = NULL; } } } return res; }
if(check_addr(/* ... */)){ /* Algo a executar quando encontra. */ } else{ /* Algo a executar quando não encontra. */ }
void *new_ptr=realloc(buf_addr_table, count*sizeof *buf_addr_table); if(new_buf) buf_addr_table=new_ptr;
// 1º argumento: ponteiro (referência) para o array dinâmico de cache de endereços. // 2º argumento: ponteiro para tamanho do cache. // 3º argumento: novo endereço, referenciado por ponteiro para uma “union sockaddr_any” que eu mostrei em outra mensagem. bool add_new_table_addr(void ***cache, size_t *cache_size, const union sockaddr_any *addr){ if(!cache || !cache_size || !addr){ errno=EFAULT; return false; } // Verifica quanto espaço de memória precisará ser alocado, e depois aloca. size_t addr_len= addr->addr_family==AF_INET? sizeof addr->in: addr->addr_family==AF_INET6? sizeof addr->in6: addr->addr_family==AF_UNIX? sizeof addr->un: sizeof addr->generic ; void *new_addr=malloc(addr_len); if(!new_addr) return false; // Retorna falso por causa do erro de alocação. // Não copia os dados de *addr ainda. Primeiro vamos ver se a realocação do cache inteiro também vai funcionar. void *new_ptr=realloc(*cache, (1+*cache_size)*sizeof **cache); if(!new_ptr){ free(new_addr); // Por causa do erro de alocação, descarta o espaço já alocado para o novo endereço. return false; // Retorna false, indicando erro. } // Neste ponto, todas as alocações já deram certo. Copia os dados e coloca o ponteiro para o novo endereço no cache. memcpy(new_addr, addr, addr_len); *cache=new_ptr; (*cache)[*cache_size]=new_addr; ++*cache_size; // Incrementa o dado com o tamanho do cache, apontado pelo ponteiro. return true; // Retorna true, indicando sucesso. }
/* ... Código suprimido por brevidade. ... */
Enviado em 23/06/2021 - 22:04h
static unsigned char **realloc_addr_table(unsigned char **buff_addr_table, size_t count, size_t addrlen) { buff_addr_table = realloc(buff_addr_table, count * sizeof(*buff_addr_table)); //Isso tá ok
if (buff_addr_table == NULL) { fprintf(stderr, "ERROR: Memory allocation for %zu bytes failed\n", count * sizeof(unsigned char *)); fprintf(stderr, "realloc_addr_table -> realloc() -> ERROR: %s\n", strerror(errno)); } buff_addr_table[count-1] = calloc(count, addrlen * sizeof(*buff_addr_table)); /*count não deveria está dentro da função calloc, o certo seria alocar apenas o quantidade de bytes armazenados em addrlen*/
buff_addr_table[count-1]=calloc(addrlen, 1); // Porque sizeof(unsigned char)==1.
if (buff_addr_table == NULL) { fprintf(stderr, "ERROR: Memory allocation for %zu bytes failed\n", count * sizeof(unsigned char *)); //Isso tá errado também, deveria mostrar apenas a quantidade de bytes armazenados em addrlen fprintf(stderr, "realloc_addr_table -> realloc() -> ERROR: %s\n", strerror(errno)); } return buff_addr_table; }
static unsigned char **realloc_addr_table(unsigned char **buff_addr_table, size_t count, size_t addrlen) { buff_addr_table = realloc(buff_addr_table, count * sizeof(*buff_addr_table));
if (buff_addr_table == NULL) { fprintf(stderr, "ERROR: Memory allocation for %zu bytes failed\n", count * sizeof(*buff_addr_table)); fprintf(stderr, "realloc_addr_table -> realloc() -> ERROR: %s\n", strerror(errno)); } buff_addr_table[count-1] = calloc(1, addrlen);
if (buff_addr_table == NULL) { fprintf(stderr, "ERROR: Memory allocation for %zu bytes failed\n", addrlen); fprintf(stderr, "realloc_addr_table -> realloc() -> ERROR: %s\n", strerror(errno));
} return buff_addr_table; }
} else { buff_addr = (unsigned char *)&addr; if (check_addr(addr.sa_family, buff_addr, buff_addr_table, i) != -1 ) { i++; buff_addr_table = realloc_addr_table(buff_addr_table, i, addrlen); memcpy(buff_addr_table[i-1], &addr, addrlen * sizeof(*buff_addr_table)); //Esse sizeof não faz sentido, deveria ser apenas addrlen para informar o tamanho do buffer de destino
show_addr(addr.sa_family, buff_addr); send(new_sockfd, msg_1, sizeof(msg_1), 0); }else{ send(new_sockfd, msg_2, sizeof(msg_2), 0); } close(new_sockfd); }
Enviado em 24/06/2021 - 20:29h
if(check_addr(/* ... */)){ /* Algo a executar quando encontra. */ } else{ /* Algo a executar quando não encontra. */ }
Enviado em 24/06/2021 - 21:14h
void *calloc(size_t nmemb, size_t size);
//No meu programa tmp[count-1] = calloc(1, addrlen); //Quantidade de elementos, tamanho do elemento
Enviado em 24/06/2021 - 21:20h
Atualizei o código (e adicionei algumas coisas novas também):#include <stdio.h> #include <errno.h> #include <string.h> #include <stdlib.h> #include <limits.h> #include <stdbool.h> #include <netdb.h> #include <unistd.h> #include <sys/un.h> #include <sys/time.h> #include <arpa/inet.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #define SNDTIMEO 5 #define MAXCONN 10 static bool set_sock_opts(int sockfd, bool only_ipv6) { bool ok = false; const int optval = 1; struct timeval timeout = {SNDTIMEO, 0}; do { if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) != 0 ) { break; } if (setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)) != 0 ) { break; } if (only_ipv6 == true) { if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, &optval, sizeof(optval)) != 0 ) { break; } } ok = true; } while (false); return ok; } static int make_server_socket(int af, const char *service, bool only_ipv6, size_t somaxconn) { int sockfd, ecode; struct addrinfo hints, *result = NULL, *rp = NULL; memset(&hints, 0, sizeof(hints)); hints.ai_flags = AI_PASSIVE; hints.ai_family = af; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = 0; if ((ecode = getaddrinfo(NULL, service, &hints, &result)) != 0 ) { fprintf(stderr, "make_server_socket() -> getaddrinfo() -> ERROR: %s\n", gai_strerror(ecode)); exit(EXIT_FAILURE); } for (rp = result; rp != NULL; rp = rp->ai_next) { if ((sockfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol)) < 0 ) { continue; } if (set_sock_opts(sockfd, only_ipv6) != true ) { close(sockfd); continue; } if (bind(sockfd, rp->ai_addr, rp->ai_addrlen) != -1 ) { break; } close(sockfd); } if (rp == NULL) { fprintf(stderr, "make_server_socket() -> socket()/bind() -> ERROR: %s\n", strerror(errno)); freeaddrinfo(rp); close(sockfd); exit(EXIT_FAILURE); } freeaddrinfo(rp); if (listen(sockfd, somaxconn) < 0 ) { fprintf(stderr, "make_server_socket() -> listen() -> ERROR: %s\n", strerror(errno)); close(sockfd); exit(EXIT_FAILURE); } return sockfd; } static bool check_addr(int af, void *addr, void **addr_table, size_t count) { bool found = false; if (af == AF_LOCAL) { struct sockaddr_un *local = addr; for (size_t i = 0; i < count; i++) { struct sockaddr_un *local_from_table = addr_table[i]; if (memcmp(local->sun_path, local_from_table->sun_path, sizeof(local->sun_path)) == 0 ) { found = true; } } } else if (af == AF_INET) { struct sockaddr_in *addr4 = addr; for (size_t i = 0; i < count; i++) { struct sockaddr_in *addr4_from_table = addr_table[i]; if (memcmp(&addr4->sin_addr.s_addr, &addr4_from_table->sin_addr.s_addr, sizeof(addr4->sin_addr.s_addr)) == 0 ) { found = true; } } } else { struct sockaddr_in6 *addr6 = addr; for(size_t i = 0; i < count; i++) { struct sockaddr_in6 *addr6_from_table = addr_table[i]; if (memcmp(&addr6->sin6_addr.s6_addr, &addr6_from_table->sin6_addr.s6_addr, sizeof(addr6->sin6_addr.s6_addr)) == 0 ) { found = true; } } } return found; } static void show_addr(int af, void *addr) { char buff[INET6_ADDRSTRLEN]; if (af == AF_LOCAL) { struct sockaddr_un *local = addr; printf("%s\n", local->sun_path); } else if (af == AF_INET) { struct sockaddr_in *addr4 = addr; if (inet_ntop(af, &addr4->sin_addr.s_addr, buff, INET_ADDRSTRLEN) < 0 ) { fprintf(stderr, "show_addr() -> inet_ntop() -> ERROR: %s\n", strerror(errno)); } else { printf("%s\n", buff); } } else { struct sockaddr_in6 *addr6 = addr; if (inet_ntop(af, &addr6->sin6_addr.s6_addr, buff, INET6_ADDRSTRLEN) < 0 ) { fprintf(stderr, "show_addr() -> inet_ntop() -> ERROR: %s\n", strerror(errno)); } else { printf("%s\n", buff); } } } static void **realloc_addr_table(void **addr_table, size_t count, size_t addrlen) { void **tmp = realloc(addr_table, count * sizeof(*addr_table)); if (tmp == NULL) { fprintf(stderr, "ERROR: Memory allocation for %zu bytes failed\nrealloc_addr_table() -> realloc() -> ERROR: %s\n", count * sizeof(*addr_table), strerror(errno)); } else { tmp[count-1] = calloc(1, addrlen); if (tmp == NULL) { fprintf(stderr, "ERROR: Memory allocation for %zu bytes failed\nrealloc_addr_table -> realloc() -> ERROR: %s\n", addrlen, strerror(errno)); } } return tmp; } static void free_addr_table(void **addr_table, size_t count) { for (size_t i = 0; i < count; i++) { free(addr_table[i]); } free(addr_table); } static void search(char **argv, size_t somaxconn, size_t maxconn) { int af; bool only_ipv6 = false; socklen_t addrlen; if (strcmp(argv[1], "-u") == 0 ) { af = AF_LOCAL; addrlen = sizeof(struct sockaddr_un); } else if (strcmp(argv[1], "-4") == 0 ) { af = AF_INET; addrlen = sizeof(struct sockaddr_in); } else if (strcmp(argv[1], "-6") == 0 ) { af = AF_INET6; only_ipv6 = true; addrlen = sizeof(struct sockaddr_in6); } else { af = AF_INET6; addrlen = sizeof(struct sockaddr_in6); } size_t i = 0; int sockfd = make_server_socket(af, argv[2], only_ipv6, somaxconn); void *addr = calloc(1, addrlen); void **addr_table = NULL; const char msg_1[] = "Welcome!\n", msg_2[] = "Get out!\n"; while (i < maxconn) { int new_sockfd; if ((new_sockfd = accept(sockfd, addr, &addrlen)) < 0 ) { fprintf(stderr, "search() -> accept() -> ERROR: %s\n", strerror(errno)); } else { if (check_addr(af, addr, addr_table, i) == false ) { void **tmp = realloc_addr_table(addr_table, i+1, addrlen); if (tmp != NULL) { i++; addr_table = tmp; memcpy(addr_table[i-1], addr, addrlen); show_addr(af, addr); send(new_sockfd, msg_1, sizeof(msg_1), 0); } }else{ send(new_sockfd, msg_2, sizeof(msg_2), 0); } close(new_sockfd); } } free(addr); free_addr_table(addr_table, i); close(sockfd); } int main(int argc, char **argv) { if (argc == 1) { printf(" *** ERROR: No arguments! ***\n"); printf("Usage: %s [OPTION] [PORT/SERVICE] [SOMAXCONN] [MAXCONN]\n", argv[0]); printf(" -4 Use IPv4\n"); printf(" -6 Use IPv6\n"); printf(" -M Use IPv4 and IPv6 (IPv4-Mapped IPv6 Adress)\n"); printf(" -h Show this page\n"); exit(EXIT_FAILURE); } int opt = getopt(argc, argv, "u46Mh"); if (strlen(argv[1]) > 2 ) { printf("*** Invalid value for [OPTION]! ***\n"); printf("Usage: %s [OPTION] [PORT/SERVICE] [SOMAXCONN] [MAXCONN]\n", argv[0]); printf(" -4 Use IPv4\n"); printf(" -6 Use IPv6\n"); printf(" -M Use IPv4 and IPv6 (IPv4-Mapped IPv6 Adress)\n"); printf(" -h Show this page\n"); } else if (opt == 'h' || opt == '?') { printf("Usage: %s [OPTION] [PORT/SERVICE] [SOMAXCONN] [MAXCONN]\n", argv[0]); printf(" -4 Use IPv4\n"); printf(" -6 Use IPv6\n"); printf(" -M Use IPv4 and IPv6 (IPv4-Mapped IPv6 Adress)\n"); printf(" -h Show this page\n"); } else if ((argc < 5) || (argc > 5)) { printf("*** Invalid values! ***\n"); printf("Usage: %s [OPTION] [PORT/SERVICE] [SOMAXCONN] [MAXCONN]\n", argv[0]); printf(" -4 Use IPv4\n"); printf(" -6 Use IPv6\n"); printf(" -M Use IPv4 and IPv6 (IPv4-Mapped IPv6 Adress)\n"); printf(" -h Show this page\n"); }else{ size_t somaxconn = strtoull(argv[3], NULL, 10); size_t maxconn = strtoull(argv[4], NULL, 10); if (somaxconn > SOMAXCONN) { printf("*** Invalid value for [SOMAXCONN]. The value is too long! ***\n"); printf("The maximum allowed value is %u\n", SOMAXCONN); } else if ( maxconn > MAXCONN ) { printf("*** Invalid value for [MAXCONN]. The value is too long! ***\n"); printf("The maximum allowed value is %u\n", MAXCONN); } else { search(argv, somaxconn, maxconn); } } return EXIT_SUCCESS; }
[AB2201@fedora TCP]$ gcc -Wall server.c -o server [AB2201@fedora TCP]$ ./server -M 9009 128 3 ::ffff:127.0.0.1 ::1 ::ffff:192.168.1.107 [AB2201@fedora TCP]$
Resolver problemas de Internet
Como compartilhar a tela do Ubuntu com uma Smart TV (LG, Samsung, etc.)
Descritores de Arquivos e Swappiness
Fez porcaria no teu repositório Git? Aprenda a restaurar uma versão anterior do seu código!
Restaurando Fontes de Download do Hydra no Linux
Atualizando "na marra" o YT-DLP quando começa a dar erro de downloads
Como instalar o WPS com interface e corretor ortográfico em PT-BR no Arch Linux
Firewall filtrando portas que estão abertas (2)
Atualização do Linux para 21 "Vanessa... (1)