getaddrinfo error Device or resource busy - c

I am trying to run FreeCoap (https://github.com/keith-cullen/FreeCoAP) to be able to communicate with COAP and DTLS on a Intel Galileo gen. 2 board. I have seen that out of the box tests compile and run correctly (as long as I have been able to test by now).
I have seen that it is prepared to run over IPv6. I am no expert on it, but I have seen that it has the value host configured as ::1, what I understand is the localhost. When I have tried to change it to IPv4, that is 127.0.0.1 or the actual IP address of the board I am getting errors.
I have seen that it uses netdb.h to create the server.
#include <netdb.h>
...
#define HOST "127.0.0.1" /**< Host address to listen on */
#define PORT "12436"
...
unsigned char msg_id[2] = {0};
struct addrinfo hints = {0};
struct addrinfo *list = NULL;
struct addrinfo *node = NULL;
hints.ai_flags = 0;
hints.ai_family = AF_INET; /* value = 2 preferred socket domain */
hints.ai_socktype = SOCK_DGRAM; /* value = 3 preferred socket type */
hints.ai_protocol = 0; /* preferred protocol (3rd argument to socket()) - 0 specifies that any protocol will do */
hints.ai_addrlen = 0; /* must be 0 */
hints.ai_addr = NULL; /* must be NULL */
hints.ai_canonname = NULL; /* must be NULL */
hints.ai_next = NULL; /* must be NULL */
ret = getaddrinfo(HOST, PORT, &hints, &list);
As result of getaddrinfo what I get is a -16 value, indicating the following error:
Error : Device or resource busy
I have tried searchig with netstat -a and there is no such port in use.
What I am missing? What resource is busy and not allowing me to get the address?

Related

Send GET Request in C to IPv6 web server on windows

I am trying to make a simple GET request to a webserver that has an IPv6 address, and it does not work. My code has to be available on Windows, so I use the Windows libraries, e.g.
#include <stdio.h>
#include <winsock2.h>
#pragma comment (lib, "Ws2_32.lib")
#include <windows.h>
#include <winuser.h>
#include <string.h>
Here is the part of the code that establishes the connection :
int portno = 825;
//yes, strange port number...
const char *adress = "[2a02:842a:86d1:d001:26dd:8d7a:8202:d9a3]";
WSADATA wsa;
SOCKET sockfd;
char message[4096] = "GET //page//index.php?data=somedata HTTP/1.1\r\nHost: [2a02:842a:86d1:d001:26dd:8d7a:8202:d9a3]\r\nUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:89.0) Gecko/20100101 Firefox/89.0\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8\r\n\r\n");
struct hostent *server;
struct sockaddr_in6 serv_addr;
int bytes, sent, received, total;
char response[4096];
int iResult = WSAStartup(MAKEWORD(2,2),&wsa);
sockfd = socket(AF_INET6 , SOCK_STREAM , 0 );
//while debugging i noticed that this line does not work
server = gethostbyname(adress);
memset(&serv_addr,0,sizeof(serv_addr));
printf("1\n");
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(portno);
memcpy(&serv_addr.sin_addr.s_addr,server->h_addr,server->h_length);
connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr));
If anybody knows how to change this code so that it will allow IPv6 connections, please tell me :)
Your call to gethostbyname() cannot possibly work, as this function only works with IPv4 addresses or hostnames, while you are providing an IPv6 address in URI notation ([addr]). Furthermore, gethostbyname() is obsolete and should not be used in new code.
Since you already have an IPv6 address, you don't need to perform a lookup. You could use getaddrinfo(), but you're better off just transforming that in binary form through the much simpler inet_pton(). Remember that you need to remove the enclosing [] brackets as they are only needed for URIs, not for literal addresses.
Here's an example:
const char *address = "2a02:842a:86d1:d001:26dd:8d7a:8202:d9a3";
if (inet_pton(AF_INET6, address, &serv_addr.sin6_addr.s6_addr) != 1) {
// invalid address, handle the error somehow
}
Also, note that the correct sockaddr_in6 has the following fields (see man 7 ipv6):
struct sockaddr_in6 {
sa_family_t sin6_family; /* AF_INET6 */
in_port_t sin6_port; /* port number */
uint32_t sin6_flowinfo; /* IPv6 flow information */
struct in6_addr sin6_addr; /* IPv6 address */
uint32_t sin6_scope_id; /* Scope ID (new in 2.4) */
};
struct in6_addr {
unsigned char s6_addr[16]; /* IPv6 address */
};
While you are using sin_addr, sin_family, etc, as if it were a sockaddr_in structure. What you want instead is:
serv_addr.sin6_family = AF_INET6;
serv_addr.sin6_port = htons(portno);

Understanding code open_clientfd(char *hostname, char *port) from book CSAPP? : issue for argument hostname and port

As reading the book < Computer Systems: A Programmer's Perspective > and in the chapter of Network Programming, I saw a this function:
int open_clientfd(char *hostname, char *port) {
int clientfd;
struct addrinfo hints, *listp, *p;
/* Get a list of potential server addresses */
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_socktype = SOCK_STREAM; /* Open a connection */
hints.ai_flags = AI_NUMERICSERV; /* ... using a numeric port arg. */
hints.ai_flags |= AI_ADDRCONFIG; /* Recommended for connections */
Getaddrinfo(hostname, port, &hints, &listp);
/* Walk the list for one that we can successfully connect to */
for (p = listp; p; p = p->ai_next) {
/* Create the socket descriptor */
if ((clientfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) < 0)
continue; /* Socket failed, try the next */
if (connect(clientfd, p->ai_addr, p->ai_addrlen) != -1)
break; /* Success */
Close(clientfd); /* Connect failed, try another */
}
/* Clean up */
Freeaddrinfo(listp);
if (!p) /* All connects failed */
return -1;
else /* The last connect succeeded */
return clientfd
}
In this function, the book said "The open_clientfd function establishes a connection with a server running on host hostname and listening for connection requests on port number port."
Therefore, I understand that hostname is for client and port is for server on client-server transaction.
My doubt come from the code, Getaddrinfo(hostname, port, &hints, &listp);
Since getaddrinfo's host and service arguments are the two components of a socket address(as the book said), I think this open_clientfd function only work when client and server are on the same host.
Am I right?
What's wrong with me?
Your understanding of the significance of host and port is not correct.
A server runs an specific host and a specific port. So the combination of host and port identifies a single server.
Getaddrinfo returns a list of (ip, port) combinations to try, using DNS to translate the host name to a list of IP addresses if needed. The function then tries to connect them one by one until one succeeds.
And it works no matter where the server runs.

how to set string specific hostname in C?

So, I am trying to learn socket programming in C (and I am a noob in C), but how do we set string based hostname. For example:
memset(&echoServAddr, 0, sizeof(echoServAddr)); /* Zero out structure */
echoServAddr.sin_family = AF_INET; /* Internet address family */
echoServAddr.sin_addr.s_addr = inet_addr(servIP); /* Server IP address */
//echoServAddr.sin_addr.s_addr = servIP;
echoServAddr.sin_port = htons(echoServPort); /* Server port */
Over here:
echoServAddr.sin_addr.s_addr = inet_addr(servIP);
servIP must be of form 127.0.0.1 but I want to use strings like localhost?
You have to use getaddrinfo function. It's used like:
getaddrinfo(machine, port, &addrinfo, &addrinfo_result)
As example:
struct addrinfo hints; //This "helps" to search
struct addrinfo *result;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_DGRAM; //Your socket's type
/* There are some more like protocol, flags.. */
error = getaddrinfo(argv[1], argv[2], &hints, &result);
In addition to getaddrinfo, you will want to look into gethostbyname and gethostbyaddr.
gethostbyname, particularly, does what you are looking to do. It asks the resolver library to take a string and perform a forward lookup to resolve it to a number:
#include <netdb.h>
extern int h_errno;
struct hostent *gethostbyname(const char *name);

getaddrinfo and IPv6

I'm trying to understand what the getaddrinfo function returns :
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netdb.h>
int main (int argc, char *argv[])
{
struct addrinfo *res = 0 ;
getaddrinfo("localhost", NULL ,NULL,&res);
printf("ai_flags -> %i\n", res->ai_flags) ;
printf("ai_family -> %i\n", res->ai_family) ;
printf("ai_socktype -> %i\n", res->ai_socktype) ;
printf("ai_protocol -> %i\n", res->ai_protocol) ;
printf("ai_addrlen -> %i\n", res->ai_addrlen) ;
struct sockaddr_in* saddr = (struct sockaddr_in*)res->ai_addr;
printf("ai_addr hostname -> %s\n", inet_ntoa(saddr->sin_addr));
freeaddrinfo(res);
return 0 ;
}
results :
ai_flags -> 40
ai_family -> 2
ai_socktype -> 1
ai_protocol -> 6
ai_addrlen -> 16
ai_addr hostname -> 127.0.0.1
In /etc/hosts, I 've got :
127.0.0.1 localhost
::1 localhost
Getaddrinfo returns only 127.0.0.1 and not ::1 ? I don't understand why ?
The second question is where can I find the meaning of those ints (40,2,1,6 etc) ? I've read the man but there is nothing about that.
I also wanted to know if it's possible to give a IPv6 adress (for example ::1) and the function returns the name : localhost ?
Thanks a lot !!
#jwodder and #onteria_ covered the IPv6 portion well, so I'll just tackle the numbers portion:
ai_flags -> 40
Probably this is going to be the sum of the following two in /usr/include/netdb.h:
# define AI_V4MAPPED 0x0008 /* IPv4 mapped addresses are acceptable. */
# define AI_ADDRCONFIG 0x0020 /* Use configuration of this host to choose
This is the protocol family, inet, inet6, apx, unix, etc.:
ai_family -> 2
bits/socket.h:78:#define PF_INET 2 /* IP protocol family. */
bits/socket.h:119:#define AF_INET PF_INET
This is the socket type, stream, dgram, packet, rdm, seqpacket:
ai_socktype -> 1
bits/socket.h:42: SOCK_STREAM = 1, /* Sequenced, reliable, connection-based
The higher-level protocol, TCP, UDP, TCP6, UDP6, UDPlite, ospf, icmp, etc:
ai_protocol -> 6
Funny enough, in /etc/protocols:
tcp 6 TCP # transmission control protocol
The size of the struct sockaddr. (Differs based on the address family! Ugh.)
ai_addrlen -> 16
This is because you're getting back a struct sockaddr_in, see linux/in.h:
#define __SOCK_SIZE__ 16 /* sizeof(struct sockaddr) */
struct sockaddr_in {
sa_family_t sin_family; /* Address family */
__be16 sin_port; /* Port number */
struct in_addr sin_addr; /* Internet address */
/* Pad to size of `struct sockaddr'. */
unsigned char __pad[__SOCK_SIZE__ - sizeof(short int) -
sizeof(unsigned short int) - sizeof(struct in_addr)];
};
And the last one, from /etc/hosts :)
ai_addr hostname -> 127.0.0.1
res also contains a field struct addrinfo *ai_next;, which is a pointer to additional entries found by getaddrinfo, or NULL if there were no other entries. If you examine res->ai_next, you should find the IPv6 entry.
As for the integer fields in a struct addrinfo, they correspond to predefined constants with implementation-defined values, and the integer values themselves are not of general interest. If you want to know what a given field means, compare it against the constants that can be assigned to that field (SOCK_STREAM, SOCK_DGRAM, etc. for ai_socktype; IPPROTO_TCP, IPPROTO_UDP, etc. for ai_protocol; and so forth) or, for ai_flags, test each bit corresponding to a predefined constant (e.g., if (res->ai_flags & AI_NUMERICHOST) {printf("ai_flags has AI_NUMERICHOST\n"); }).
extern struct sockaddr_in6 create_socket6(int port, const char * address) {
struct addrinfo hints, *res, *resalloc;
struct sockaddr_in6 input_socket6;
int errcode;
/* 0 out our structs to be on the safe side */
memset (&hints, 0, sizeof (hints));
memset (&input_socket6, 0, sizeof(struct sockaddr_in6));
/* We only care about IPV6 results */
hints.ai_family = AF_INET6;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_DEFAULT;
errcode = getaddrinfo (address, NULL, &hints, &res);
if (errcode != 0)
{
perror ("[ERROR] getaddrinfo ");
return input_socket6;
}
resalloc = res;
while (res)
{
/* Check to make sure we have a valid AF_INET6 address */
if(res->ai_family == AF_INET6) {
/* Use memcpy since we're going to free the res variable later */
memcpy (&input_socket6, res->ai_addr, res->ai_addrlen);
/* Here we convert the port to network byte order */
input_socket6.sin6_port = htons (port);
input_socket6.sin6_family = AF_INET6;
break;
}
res = res->ai_next;
}
freeaddrinfo(resalloc);
return input_socket6;
}
Here is some code that explains it. Basically unless you give getaddrinfo some hints to tell it to only work with IPV6, it will also give IPV4 results. That is why you have to loop through the results as shown.
Other answers have been given to most parts, but to answer this final part:
I also wanted to know if it's possible to give a IPv6 adress (for example ::1) and the function returns the name : localhost ?
The function you want there is getnameinfo(); given a socket address it returns a string name.

Why can't a bind linux service to the loop-back only?

I am writing a server application that will provide a service on an ephemeral port that I only want accessible on the loopback interface. In order to do this, I am writing code like the following:
struct sockaddr_in bind_addr;
memset(&bind_addr,0,sizeof(bind_addr));
bind_addr.sin_family = AF_INET;
bind_addr.sin_port = 0;
bind_addr.sin_addr.s_addr = htonl(inet_addr("127.0.0.1"));
rcd = ::bind(
socket_handle,
reinterpret_cast<struct sockaddr *>(&bind_addr),
sizeof(bind_addr));
The return value for this call to bind() is -1 and the value of errno is 99 (Cannot assign requested address). Is this failing because inet_addr() already returns its result in network order or is there some other reason?
inet_addr should be avoided, for there is a much saner method of constructing struct sockaddrs (which means it also obsoletes gethostby*):
#include <netdb.h>
/* Error checking omitted for brevity */
struct addrinfo hints = {.ai_flags = AI_PASSIVE};
struct addrinfo *res;
getaddrinfo("::1", NULL, &hints, &res); /* or 127.0.0.1 if you are 60+ */
bind(fd, res->ai_addr, res->ai_addrlen);
freeaddrinfo(res);
Is this failing because inet_addr() already returns its result in network order
Yes.
So remove the htonl call.

Resources