how to set string specific hostname in C? - 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);

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);

getaddrinfo error Device or resource busy

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?

How can I get the connected client's IP address using WinSock2 and C?

I want to get the IP address of the client who’s just connected into my server running WinSock2. I’m using C.
You could get the client's IP-address and port via the call to accept().
Just pass in the appropriate data into the last two parameters.
struct sockaddr_in sa = {0}; /* for TCP/IP */
socklen_t socklen = sizeof sa;
... = accept(..., (struct sockaddr *) &sa, &socklen);
For details please read here.
Have not done it myself, but take a look at getpeername. Looks like this is what you need.
This work for me on winsock2. No need of getpeername
SOCKET newConnection;
SOCKADDR_IN addr;
int addrlen = sizeof(addr);
newConnection = accept(sListen, (SOCKADDR*)&addr, &addrlen);
char *ip = inet_ntoa(addr.sin_addr);
printf("Accepted Connection from : %s", ip);

Sockets UDP: Using Sender Info from Recvfrom() in Sendto() Fails

I'm trying to write a server that that receives a query via UDP and sends a response via UDP. The problem I'm running into is that when I try to send my response, I get a "101 Network is unreachable" error.
Based on the question here I tried to resolve this by taking out the hints.ai_flags = AI_PASSIVE; line, but then the server never successfully gets the message. I looked at the man page for addrinfo and it sounds like if the AI_PASSIVE flag is set, the socket can only recvfrom(), while if it's not set, the socket can only sendto(). I've seen a bunch of examples online with people doing both from a single socket, though; what am I missing?
Relevant code:
struct addrinfo hints;
struct addrinfo *serverinfo;
memset(&hints,0,sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_flags = AI_PASSIVE;
int status = getaddrinfo(NULL, port, &hints, &serverinfo);
int sock = socket(serverinfo->ai_family, serverinfo->ai_socktype, serverinfo->ai_protocol);
status = bind(sock, serverinfo->ai_addr, serverinfo->ai_addrlen);
freeaddrinfo(serverinfo);
// poll until there's an incoming packet
struct sockaddr sender;
socklen_t sendsize = sizeof(sender);
bzero(&sender, sizeof(sender));
recvfrom(sock, message, sizeof(message), 0, &sender, &sendsize);
// message processing
sendto(sock, response, sizeof(response), 0, (struct sockaddr *)&sender, sendsize);
Yes, I have error checking for all those calls (that's how I found the problem); it's simply been left out here for brevity's sake.
You shouldn't use a struct sockaddr to store the source address in the recvfrom call, it might not be able to represent an IP socket address.
You're supposed to use a struct sockaddr_in for an IPv4 address or a struct sockaddr_in6 for an IPv6 address, or better yet, a struct sockaddr_storage to cope with either.
struct sockaddr_storage sender;
socklen_t sendsize = sizeof(sender);
bzero(&sender, sizeof(sender));
recvfrom(sock, message, sizeof(message), 0, (struct sockaddr*)&sender, &sendsize);

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