I am writing a server-client program and in the server I use getaddrinfo and getsockname on the server to get info about the local IP addr and locally bound port number .
Using this info, I start my client program and use the getaddrinfo and then just print out the returned values in the servinfo data structure:
getaddrinfo(argc[1], argc[2], &hints, &servinfo); >> server hostname and server port number are passed via command line.
But I notice that the sin_port in servinfo is not the port I am passing via the command line.
1) Does this getaddrinfo return the port number being used by the client as the source port number ?
2) My connect call after the getaddrinfo and socket calls in failing. I do not know why. How do I debug it ?
My client code snippet:
memset(&hints, 0 ,sizeof hints);
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_CANONNAME | AI_NUMERICSERV;
getaddrinfo(argc[1], argc[2], &hints, &servinfo);
for (p = servinfo till p!=NULL)
sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)
connect(sockfd, p->ai_addr, p->ai_addrlen) >>>>> Connect not going through.
I start my client program like this:
./a.out myservername 18844
Thanks !
New answer: You are invoking your program with only one argument, so argv[1] contains "18844" and argv[2] is a null pointer. This is going to try to connect to a host with numeric IP 18844 and an unspecified port number (which will end up being 0 and failing).
Old answer: (relevant but not your problem) sin_port and the whole sockaddr_in structure is in network byte order. You'll need to convert the port with ntohl to use it as a number, but you would be better off never touching sockaddr structures' internals whatsoever. Instead, use getnameinfo with NI_NUMERICHOST and NI_NUMERICSERV to get the address back into a string-based numeric form, then strtol to read the port ("service") number into an integer. This works even for non-IPv4 network address/protocol families (like IPv6) and requires no additional code for supporting new ones.
Related
I'm trying to get my head around socket programming and have encountered some unexpected (for me) behaviour.
When I try to send data to "localhost" and set addrinfo.ai_family to AF_INET the message I send isn't coming through from my client process to my host process (recvfrom() doesn't return). If I set it to AF_INET6 all is fine. Same for AF_UNSPEC in which case it picks the IPv6 addrinfo (first in the list). Both host and client use the same ai_family of course.
I've also tried this with code copy pasted from beej's guide to network programming which had the same result. I'm using DGRAM sockets.
I tried connecting from a different pc I got the opposite results, IPv4 worked fine, IPv6 did not. I gather this may be due to me using a '6to4 gateway'. I really have no idea what this means.
The problem is related to my own machine as the code does work over IPv4 on another machine I tested it on.
I can't say if it's a sending or receiving problem.
What could prevent me from sending or receiving data to/from localhost using AF_INET sockets?
I'm on a windows7 64bit machine compiling with MingW.
If it makes any difference I'm running the same program for host and client processes with different arguments. I ran the release and debug programs together (so it's not the same program twice) but got the same results.
Thanks in advance and apologies if this is considered a stupid question.
code:
typedef struct addrinfo addrinfo_t;
typedef struct sockaddr_storage sockaddr_storage_t;
typedef struct sockaddr_in sockaddr_in_t;
typedef struct sockaddr_in6 sockaddr_in6_t;
void connect_to_server(const char* server_name, const char* message)
{
int status;
init_networking();
addrinfo_t hints;
addrinfo_t* res;
memset(&hints, 0, sizeof(addrinfo_t));
hints.ai_family = AF_INET; //or AF_INET6
hints.ai_socktype = SOCK_DGRAM;
if ((status = getaddrinfo(server_name, "4950", &hints, &res)) != 0)
{
fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(status));
exit(1);
}
SOCKET s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (s == -1)
{
fprintf(stderr, "could not create a socket, errno: %u\n", errno);
exit(1);
}
int bytes_sent = sendto(s, message, strlen(message), 0, res->ai_addr, res->ai_addrlen);
close(s);
printf("Sent %i bytes to port %i\n", bytes_sent, ((sockaddr_in_t*)res->ai_addr)->sin_port);
freeaddrinfo(res);
}
void setup_server()
{
int status;
init_networking();
addrinfo_t hints;
addrinfo_t* res;
memset(&hints, 0, sizeof(addrinfo_t));
hints.ai_family = AF_INET; //or AF_INET6
hints.ai_socktype = SOCK_DGRAM;
hints.ai_flags = AI_PASSIVE;
if ((status = getaddrinfo(NULL, "4950", &hints, &res)) != 0)
{
fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(status));
exit(1);
}
SOCKET s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (s == -1)
{
fprintf(stderr, "could not create a socket, errno: %u\n", errno);
exit(1);
}
//Bind the socket to own address (mostly the port number contained in the address)
if (bind(s, res->ai_addr, res->ai_addrlen) < 0)
{
fprintf(stderr, "failed to bind, errno: %u\n", errno);
exit(1);
}
freeaddrinfo(res);
const size_t read_buffer_size = 1024;
void* read_buffer = malloc(read_buffer_size);
sockaddr_storage_t peer_address;
int peer_address_length = sizeof(sockaddr_storage_t);
sockaddr_storage_t own_sock_addr;
int own_sock_addr_len = sizeof(sockaddr_storage_t);
getsockname(s, (struct sockaddr*)&own_sock_addr, &own_sock_addr_len);
printf("Listening on port %i\n", ((sockaddr_in_t*)&own_sock_addr)->sin_port);
int bytes_received = recvfrom(s,
read_buffer,
read_buffer_size-1,
0,
(struct sockaddr*)&peer_address,
&peer_address_length );
printf("Received %i byte message:\n%s\n", bytes_received, (char*)read_buffer);
}
AF_INET is for IPv4, and AF_INET6 is for IPv6. When sending an IPv4 datagram, the receiver must be receiving data on the destination IP/port using either an IPv4 socket or an IPv6 dual stack socket (an IPv6 socket that accepts both IPv4 and IPv6 traffic). When sending an IPv6 datagram, the receiver must be receiving data using an IPv6 socket. Otherwise, the datagram will be ignored, So it sounds like the one machine is using an IPv6 socket that ignores your IPv4 datagram, and the other machine is using an IPv4 socket that ignores your IPv6 datagram.
When you are calling getaddrinfo(), you are specifying AF_UNSPEC as the address family in both client and server. AF_UNSPEC tells getaddrinfo() that you want both IPv4 and IPv6 addresses, so it returns a linked list that potentially contains multiple entries for all of the available IPv4 and IPv6 addresses. On the server side, you are creating a single listening socket for only the first entry in the list, which may be IPv4 or IPv6. On the client side, you are creating a single sending socket for only the first entry in the list, which may be IPv4 or IPv6. So the actual address families used in both operations are going to be random and may mismatch each other at times.
On the server side, you need to either:
use AF_INET or AF_INET6 directly, instead of AF_UNSPEC, and then code the client accordingly to match.
loop through the entire addrinfo list creating a separate listening socket for every entry. That way, clients can send data to any IP/Port family the server is listening on.
use AF_INET6 only when creating the listening socket(s), but then enable dual stack functionality on them (Vista+ only) so they can receive both IPv4 and IPv6 datagrams. You will then have to pay attention to the address family reported by the sockaddr that recvfrom() returns in order to know whether any given datagram is using IPv4 or IPv6.
On the client side, you need to use AF_INET or AF_INET6 directly, instead of AF_UNSPEC, depending on what the server is actually listening on. It does not make sense to use AF_UNSPEC for a UDP client socket (it does make sense for a TCP client socket), unless the UDP protocol you are implementing replies to each datagram with an ack. Without that, the client has no way to know whether the server is accepting IPv4 or IPv6 datagrams (unless the user tells the app). With acks, the client could loop through the returned addrinfo list, sending a datagram to an entry in the list, wait a few seconds for an ack, and if not received then move on to the next entry in the list, repeating as needed until an ack actually arrives or the list is exhausted.
I wanted to add IPv6 support for my program and came across odd error. I want to open socket which accepts connections. Here is my scenario:
First I use getaddrinfo() to find socket configuration:
struct addrinfo hint, *info = NULL;
memset((void *)&hint, 0, sizeof(hint));
hint.ai_family = AF_INET6;
hint.ai_flags = AI_PASSIVE | AI_NUMERICSERV;
hint.ai_socktype = SOCK_STREAM;
if ((error = getaddrinfo(NULL, "1234", &hint, &info))) {
/* some error handling */
}
I gen non-NULL result in info. Then I want to create socket:
socket(info->ai_family, info->ai_socktype, info->ai_protocol)
Here I get -1
strerror(errno)
returns Address family not supported by protocol
I thought that getaddrinfo() returns only addresses that can be bound and I would expect it to return NULL in this case. What am I missing?
I want to add that my eth0 does not have IPv6 address right now. I am using uClibc 0.9.32
You need to add AI_ADDRCONFIG to ai_flags to make sure it doesn't return address families unsupported by the kernel. I pretty much always add that flag nowadays.
If you want to support kernels without IPv6 you'll have to avoid setting ai_family to AF_INET6. Instead you have to listen on all the returned addresses, and make sure to set IPV6_V6ONLY on the AF_INET6 ones. There's no guarantee that the AF_INET6 address will be returned first, unfortunately.
getaddrinfo returns a linked list of struct addrinfo objects, which you can traverse using the ai_next member. You should try each returned addrinfo object in turn until you get a connection (or hit NULL/end of list).
I am binding a socket to my address to listen to connections. To do this, I get my address information using getaddrinfo() syscall, which grants me an ip independent way of doing what I want. The problem is that the structs which this syscall returns have the ip address field all blank. For example:
struct addrinfo hints, *servinfo, *p;
int sock;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
getaddrinfo(NULL, port, &hints, &servinfo)
for (p = servinfo; p != NULL; p = p->ai_next)
if (p->ai_family == AF_INET6)
break;
sock = socket(p->ai_family, p->sock_type, p->protocol);
bind(sock, p->ai_addr, p->ai_addrlen)
In the code above. the *p variable should have some kind of information on an IPv6 address of my machine since the bind succeeds, but the field p->ai_addr->sin6_addr (assume this would work without a casting) is blank. How can I know exactly what address I will be using?
The address is not blank - it is all zeroes, which is 0::0. This is the special wildcard address which means to bind to all local interfaces.
You should not care what address(es) your host has - this list might change at any time, including immediately after you check it.
Once you have a client connected, you can use getsockname() on the socket returned by accept() to determine which one of your local addresses that client connected to.
Why don't you bind to localhost (i.e. IPV4 127.0.0.1) or to ip6-localhost (i.e. IPV6 ::1) if you want to listen to local connections only?
Otherwise, leave all zeroes in the address like #caf suggested.
Does anyone know if it's possible to use getaddrinfo with unix sockets in C (AF_UNIX). I've tried a couple of things but I can't make it work.
This is basically what I'm trying:
struct addrinfo hints, *res;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNIX;
hints.ai_socktype = SOCK_STREAM;
if(getaddrinfo("What should I put here?", "What should I put here?", &hints, &res) != 0){
//do sth about
}
My question is how to fill the node and service fields, in case that is possible to use it with unix sockets.
Thanks in advance.
Some implementations of getaddrinfo() have supported AF_UNIX socket addresses, but they no longer do so due to security concerns.
You don't really need a function to "look up" an AF_UNIX address anyway - if you know the socket path, then you can just copy it straight into a sockaddr_un of sufficient size. There's no resolution step for AF_UNIX addresses - the socket name is the socket address.
From man 3 getaddrinfo:
The hints parameter specifies the preferred socket type, or protocol. A NULL hints specifies that any network address or protocol is acceptable. If this parameter is not NULL it points to an addrinfo structure whose ai_family, ai_socktype, and ai_protocol members specify the preferred socket type. AF_UNSPEC in ai_family specifies any protocol family (either IPv4 or IPv6, for example). 0 in ai_socktype or ai_protocol specifies that any socket type or protocol is acceptable as well. The ai_flags member specifies additional options, defined below. Multiple flags are specified by logically OR-ing them together. All the other members in the hints parameter must contain either 0, or a null pointer.
So it looks like you need to pass in the hints parameter to tell it you want a unix socket.
A lot late, but just for the records, did you try this -
struct addrinfo hints, *res;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC; //is the address family(IPV4 or 6) or UNSPEC for either
hints.ai_socktype = SOCK_STREAM;
if(getaddrinfo(parm1, parm2, &hints, &res) != 0){
//do sth about
}
parm1 -> is the host name or address to connect to. A call with NULL here puts the address of local host, in which case you specify hints.ai_flags=AI_PASSIVE.
parm2 -> is the name of the intended service (http, ftp etc) or the corresponding port number for that service the socket is used for
I'm having trouble figuring this out - I'm working with sockets in C using this guide - http://binarii.com/files/papers/c_sockets.txt
I'm trying to automatically get my ip and port using:
server.sin_port = 0; /* bind() will choose a random port*/
server.sin_addr.s_addr = INADDR_ANY; /* puts server's IP automatically */
...
...
bind(int fd, struct sockaddr *my_addr,int addrlen); // Bind function
After a successful bind, how do I find out what IP and Port I'm actually assigned?
If it's a server socket, you should call listen() on your socket, and then getsockname() to find the port number on which it is listening:
struct sockaddr_in sin;
socklen_t len = sizeof(sin);
if (getsockname(sock, (struct sockaddr *)&sin, &len) == -1)
perror("getsockname");
else
printf("port number %d\n", ntohs(sin.sin_port));
As for the IP address, if you use INADDR_ANY then the server socket can accept connections to any of the machine's IP addresses and the server socket itself does not have a specific IP address. For example if your machine has two IP addresses then you might get two incoming connections on this server socket, each with a different local IP address. You can use getsockname() on the socket for a specific connection (which you get from accept()) in order to find out which local IP address is being used on that connection.
The comment in your code is wrong. INADDR_ANY doesn't put server's IP automatically'. It essentially puts 0.0.0.0, for the reasons explained in mark4o's answer.