inet_ntop() -> ERROR 97: Address family not supported by protocol [RESOLVIDO]

1. inet_ntop() -> ERROR 97: Address family not supported by protocol [RESOLVIDO]

Perfil removido
removido

(usa Nenhuma)

Enviado em 20/06/2021 - 14:40h

Já revisei o código abaixo diversas vezes e eu ainda não encontrei um motivo claro para a função inet_ntop() falhar toda vez que é invocada pela primeira vez dentro do seu loop for.

Isso ocorre com qualquer conexão vinda de um cliente, isto é, com o netcat, telnet ou com a minha própria implementação de um software cliente.

Sendo assim, aqui vai o programa em questão:


#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>

#include <unistd.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

#define PORT 9009
#define ADDR "127.0.0.1"
#define MAXCONN 5

int main(void) {

int sockfd;
struct sockaddr_in addr;

memset(&addr, 0, sizeof(addr));

if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) {

fprintf(stderr, "socket() -> ERROR %d: %s\n", errno, strerror(errno));

exit(EXIT_FAILURE);
}

addr.sin_family = AF_INET;
addr.sin_port = htons(PORT);
inet_pton(AF_INET, ADDR, &addr.sin_addr.s_addr);

if (bind(sockfd, (struct sockaddr*)&addr, sizeof(addr)) < 0 ) {

fprintf(stderr, "bind() -> ERROR %d: %s\n", errno, strerror(errno));

close(sockfd);

exit(EXIT_FAILURE);
}

if (listen(sockfd, SOMAXCONN) < 0 ) {

fprintf(stderr, "listen() -> ERROR %d: %s\n", errno, strerror(errno));

close(sockfd);

exit(EXIT_FAILURE);
}

for (size_t i = 0; i < MAXCONN; i++) {

struct sockaddr_in client;
socklen_t addrlen;
char caddr[INET_ADDRSTRLEN];
int new_sockfd;

memset(&client, 0, sizeof(client));

if ((new_sockfd = accept(sockfd, (struct sockaddr*)&client, &addrlen)) < 0 ) {

fprintf(stderr, "accept() -> ERROR %d: %s\n", errno, strerror(errno));

} else {

if (inet_ntop(client.sin_family, &client.sin_addr.s_addr, caddr, sizeof(caddr)) == NULL ) {

fprintf(stderr, "inet_ntop() -> ERROR %d: %s\n", errno, strerror(errno));

} else {

printf("%s\n", caddr);
}

const char msg[] = "What's up, [*****]. Names John. You here to help me?";

if (write(new_sockfd, msg, sizeof(msg)) < 0 ) {

fprintf(stderr, "write() -> ERROR %d: %s\n", errno, strerror(errno));
}

close(new_sockfd);
}
}

close(sockfd);

return EXIT_SUCCESS;
}


Minha implementação de um programa cliente:


#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>

#include <unistd.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

#define PORT 9009
#define ADDR "127.0.0.1"

int main(void) {

int sockfd;
struct sockaddr_in server;

memset(&server, 0, sizeof(server));

if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) {

fprintf(stderr, "socket() -> ERROR %d: %s\n", errno, strerror(errno));

exit(EXIT_FAILURE);
}

server.sin_family = AF_INET;
server.sin_port = htons(PORT);
inet_pton(AF_INET, ADDR, &server.sin_addr.s_addr);

if (connect(sockfd, (struct sockaddr*)&server, sizeof(server)) < 0 ) {

fprintf(stderr, "connect() -> ERROR %d: %s\n", errno, strerror(errno));

close(sockfd);

exit(EXIT_FAILURE);

} else {

char msg[256];

if (read(sockfd, msg, sizeof(msg)) < 0 ) {

fprintf(stderr, "read() -> ERROR %d: %s\n", errno, strerror(errno));

close(sockfd);

exit(EXIT_FAILURE);
}

printf("\nServer: %s\n\n", msg);
}

close(sockfd);

return EXIT_SUCCESS;
}



RUNTIME

Usando a minha versão de software cliente:


//Terminal para a execução do servidor
[[email protected] TCP]$ gcc -Wall server.c -o server
[[email protected] TCP]$ ./server
inet_ntop() -> ERROR 97: Address family not supported by protocol
127.0.0.1
127.0.0.1
127.0.0.1
127.0.0.1
[[email protected] TCP]$

//Terminal para a execução do cliente
[[email protected] TCP]$ gcc -Wall client.c -o client
[[email protected] TCP]$ ./client

Server: What's up, [*****]. Names John. You here to help me?

[[email protected] TCP]$ ./client

Server: What's up, [*****]. Names John. You here to help me?

[[email protected] TCP]$ ./client

Server: What's up, [*****]. Names John. You here to help me?

[[email protected] TCP]$ ./client

Server: What's up, [*****]. Names John. You here to help me?

[[email protected] TCP]$ ./client

Server: What's up, [*****]. Names John. You here to help me?

[[email protected] TCP]$


Usando o netcat:


//Terminal para a execução servidor
[[email protected] TCP]$ ./server
inet_ntop() -> ERROR 97: Address family not supported by protocol
127.0.0.1
127.0.0.1
127.0.0.1
127.0.0.1
[[email protected] TCP]$

//Terminal para a execução do netcat (nc)
[[email protected] TCP]$ nc localhost 9009
What's up, [*****]. Names John. You here to help me?^C
[[email protected] TCP]$ nc localhost 9009
What's up, [*****]. Names John. You here to help me?^C
[[email protected] TCP]$ nc localhost 9009
What's up, [*****]. Names John. You here to help me?^C
[[email protected] TCP]$ nc localhost 9009
What's up, [*****]. Names John. You here to help me?^C
[[email protected] TCP]$ nc localhost 9009
What's up, [*****]. Names John. You here to help me?^C
[[email protected] TCP]$


A única pista que eu tenho até agora é que a função accept() não esteja preenchendo o membro ai_family da estrutura de endereço do cliente corretamente. Descobrir isso quando fiz a seguinte alteração em um trecho do código do servidor:


if (inet_ntop(AF_INET, &client.sin_addr.s_addr, caddr, sizeof(caddr)) == NULL ) { //Troquei client.sin_family por AF_INET

fprintf(stderr, "inet_ntop() -> ERROR %d: %s\n", errno, strerror(errno));

} else {

printf("%s\n", caddr);
}


E o retorno dessa vez foi o seguinte:


[[email protected] TCP]$ gcc -Wall server.c -o server
[[email protected] TCP]$ ./server
0.0.0.0
127.0.0.1
127.0.0.1
127.0.0.1
127.0.0.1
[[email protected] TCP]$


Por que 0.0.0.0? O problema realmente está em accept() ou em inet_ntop()? Como eu posso resolver isso?


  


2. MELHOR RESPOSTA

Paulo
paulo1205

(usa Ubuntu)

Enviado em 20/06/2021 - 17:18h

Faltou a inicialização de addrlen antes de invocar accept(). Imagino que isso seja suficiente para explicar o erro que você recebeu.

No seu programa, com as suas variáveis, você deveria fazer “addrlen=sizeof client;” antes de chamar accept().

EDIT (20:51): Outro “erro”, que me ocorreu agora, é que você está comparando o valor de retorno de inet_ntop(), que é do tipo int, com NULL, que é de um tipo ponteiro (void *). O compilador não reclama porque casualmente o valor NULL é automaticamente conversível para o inteiro 0, mas é melhor evitar o erro conceitual dessa comparação entre tipos diferentes, até porque eu não estou certo de que esse mesmo código compilaria sem problemas se você usasse um compilador C++, por exemplo. Já que a função retorna 1 quando funciona OK e 0 quando dá erro, você não precisa comparar o valor de retorno com nada, mas sim usá-lo diretamente como valor passado ao if.


... Então Jesus afirmou de novo: “(...) eu vim para que tenham vida, e a tenham plenamente.” (João 10:7-10)

3. Re: inet_ntop() -> ERROR 97: Address family not supported by protocol [RESOLVIDO]

Perfil removido
removido

(usa Nenhuma)

Enviado em 20/06/2021 - 14:55h

O engraçado é que isso não ocorre com essa outra implementação de servidor que eu fiz usando getaddrinfo():


#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 5

int main(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, "getaddrinfo() -> ERROR (errcode: %d): %s\n", ecode, 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) == 0 ) {

break;
}

close(sockfd);
}

if (rp == NULL) {

fprintf(stderr, "socket()/bind() -> ERROR (errno: %d): %s\n", errno, strerror(errno));

freeaddrinfo(result);

close(sockfd);

exit(EXIT_FAILURE);
}

freeaddrinfo(result);

if (listen(sockfd, SOMAXCONN) < 0 ) {

fprintf(stderr, "listen() -> ERROR (errno: %d): %s\n", errno, strerror(errno));

close(sockfd);

exit(EXIT_FAILURE);
}

for (size_t i = 0; i < MAXCONN; i++) {

int new_sockfd;
struct sockaddr client;
socklen_t addrlen;
char *caddr = NULL;

if ((new_sockfd = accept(sockfd, &client, &addrlen)) < 0 ) {

fprintf(stderr, "accept() -> ERROR (errno: %d): %s\n", errno, strerror(errno));

} else {

if (client.sa_family == AF_INET) {

struct sockaddr_in *addr4 = (struct sockaddr_in*)&client;

caddr = malloc(INET_ADDRSTRLEN);

if (inet_ntop(AF_INET, &addr4->sin_addr.s_addr, caddr, INET_ADDRSTRLEN) < 0 ) {

fprintf(stderr, "inet_ntop() -> ERROR (errno: %d): %s\n", errno, strerror(errno));

} else {

printf("%s\n", caddr);
}

} else {

struct sockaddr_in6 *addr6 = (struct sockaddr_in6*)&client;

caddr = malloc(INET6_ADDRSTRLEN);

if (inet_ntop(AF_INET6, &addr6->sin6_addr.s6_addr, caddr, INET6_ADDRSTRLEN) < 0 ) {

fprintf(stderr, "inet_ntop() -> ERROR (errno: %d): %s\n", errno, strerror(errno));

} else {

printf("%s\n", caddr);
}
}

char msg[] = "What's up, [*****]. Names John. You here to help me?\n";

if (send(new_sockfd, msg, sizeof(msg), 0) < 0 ) {

fprintf(stderr, "send() -> ERROR (errno: %d): %s\n", errno, strerror(errno));
}

close(new_sockfd);

free(caddr);
}
}

close(sockfd);

return EXIT_SUCCESS;
}


RUNTIME


//Terminal para a execução servidor
[[email protected] TCP]$ gcc -Wall server.c -o server
[[email protected] TCP]$ ./server
::ffff:127.0.0.1
::ffff:127.0.0.1
::1
::1
::ffff:192.168.1.107
[[email protected] TCP]$

//Terminal para a execução do cliente
[[email protected] TCP]$ nc 127.0.0.1 9009
What's up, [*****]. Names John. You here to help me?
^C
[[email protected] TCP]$ nc 127.0.0.1 9009
What's up, [*****]. Names John. You here to help me?
^C
[[email protected] TCP]$ nc ::1 9009
What's up, [*****]. Names John. You here to help me?
^C
[[email protected] TCP]$ nc ::1 9009
What's up, [*****]. Names John. You here to help me?
^C
[[email protected] TCP]$ nc 192.168.1.107 9009
What's up, [*****]. Names John. You here to help me?
^C
[[email protected] TCP]$



Boom! Funcionou como o esperado nesse programa.


4. Re: inet_ntop() -> ERROR 97: Address family not supported by protocol

Paulo
paulo1205

(usa Ubuntu)

Enviado em 20/06/2021 - 17:46h

PC300-ITS44 escreveu:

O engraçado é que isso não ocorre com essa outra implementação de servidor que eu fiz usando getaddrinfo():

/* … Código suprimido por brevidade. … */

for (size_t i = 0; i < MAXCONN; i++) {
int new_sockfd;
struct sockaddr client;
socklen_t addrlen;
char *caddr = NULL;

if ((new_sockfd = accept(sockfd, &client, &addrlen)) < 0 )


Note que este código tem o mesmo erro que eu apontei na mensagem anterior, a saber: chamar accept() sem antes inicializar o valor apontado pelo terceiro argumento, efetivamente passando um valor desconhecido para a função.

A diferença entre o programa anterior e o último foi apenas que, por acaso†, no primeiro programa provavelmente havia um valor pequeno (possivelmente zero) na posição de memória usada por addrlen, ao passo que, no último programa, provavelmente havia um valor suficientemente grande para acomodar os endereços das conexões.

O fato é que ambos os programas têm o mesmo bug. Que um deles tenha funcionado foi uma casualidade, e eu costumo dizer que quando um programa assim funciona, deixando um bug como esse latente, isso acontece “por AZAR” do programador (não “por sorte”), já que impediu a detecção e correção do problema.

------
† Pode não ser totalmente por acaso, mas depender de como o código foi compilado e de alguma operação anterior que você executou. Como, no entanto, tais comportamentos não são previsíveis examinando apenas o código fonte, devem sempre ser considerados espúrios.


... Então Jesus afirmou de novo: “(...) eu vim para que tenham vida, e a tenham plenamente.” (João 10:7-10)


5. Re: inet_ntop() -> ERROR 97: Address family not supported by protocol [RESOLVIDO]

Perfil removido
removido

(usa Nenhuma)

Enviado em 23/06/2021 - 12:21h


paulo1205 escreveu:

EDIT (20:51): Outro “erro”, que me ocorreu agora, é que você está comparando o valor de retorno de inet_ntop(), que é do tipo int, com NULL, que é de um tipo ponteiro (void *). O compilador não reclama porque casualmente o valor NULL é automaticamente conversível para o inteiro 0, mas é melhor evitar o erro conceitual dessa comparação entre tipos diferentes, até porque eu não estou certo de que esse mesmo código compilaria sem problemas se você usasse um compilador C++, por exemplo. Já que a função retorna 1 quando funciona OK e 0 quando dá erro, você não precisa comparar o valor de retorno com nada, mas sim usá-lo diretamente como valor passado ao if.


Ué! Mas inet_ntop() retorna um ponteiro:


const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);


Dá uma olhada aqui:

https://linux.die.net/man/3/inet_ntop

De acordo com a man page:

Return Value
On success, inet_ntop() returns a non-NULL pointer to dst. NULL is returned if there was an error, with errno set to indicate the error.







6. Re: inet_ntop() -> ERROR 97: Address family not supported by protocol [RESOLVIDO]

Paulo
paulo1205

(usa Ubuntu)

Enviado em 23/06/2021 - 12:45h

PC300-ITS44 escreveu:

Ué! Mas inet_ntop() retorna um ponteiro:


Tem razão! Erro meu. Acho que eu confundi inet_ntop() com inet_pton().

Desculpe.


... Então Jesus afirmou de novo: “(...) eu vim para que tenham vida, e a tenham plenamente.” (João 10:7-10)