tags:

views:

129

answers:

2

Hello! This question is related to another question I just posted. I'm prepping for a simple work project and am trying to familiarize myself with the basics of socket programming in a Unix dev environment. At this point, I have some basic server side code and client side code setup to communicate. Currently, my client code successfully connects to the server code and the server code sends it a test message, then both quit out. Perfect! That's exactly what I wanted to accomplish. Now I'm playing around with the functions used to obtain info about the two environments (server and client). I'd like to obtain my server program's IP address. Here's the code I currently have to do this, but it's not working...

int sockfd;
unsigned int len;
socklen_t sin_size;
char msg[]="test message";
char buf[MAXLEN];
int st, rv;
struct addrinfo hints, *serverinfo, *p; 
struct sockaddr_storage client;
char s[INET6_ADDRSTRLEN];
char ip[INET6_ADDRSTRLEN];

//zero struct   
memset(&hints,0,sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;

//get the server info
if((rv = getaddrinfo(NULL, SERVERPORT, &hints, &serverinfo ) != 0)){
  perror("getaddrinfo");
  exit(-1);
}

// loop through all the results and bind to the first we can
for( p = serverinfo; p != NULL; p = p->ai_next)
{
  //Setup the socket
  if( (sockfd = socket( p->ai_family, p->ai_socktype, p->ai_protocol )) == -1 )
  {
    perror("socket");
    continue;
  }

  //Associate a socket id with an address to which other processes can connect
  if(bind(sockfd, p->ai_addr, p->ai_addrlen) == -1){
    close(sockfd);
    perror("bind");
    continue;
  }

  break;
}

if( p == NULL ){
  perror("Fail to bind");
}

inet_ntop(p->ai_family, get_in_addr((struct sockaddr *)p->ai_addr), s, sizeof(s));
printf("Server has TCP Port %s and IP Address %s\n", SERVERPORT, s);

and the output for the IP is always empty...

server has TCP Port 22513 and IP Address ::

any ideas for what I'm missing?

thanks in advance for your help! this stuff is really complicated at first.

+2  A: 

Your socket is probably listening to all available interfaces/addresses. "::" is shorthand for IPv6 address "0:0:0:0:0:0:0:0", which means that the address is unspecified.

This is probably because you request from getaddrinfo() a addrinfo to listen on any address and any protocol supporting streams and IPv6 with unspecified address happens to come first. I'm a bit unsure about this though...

Daniel Karling
As a side note, I don't know where you are reading right now but the definite source when it comes to Berkely Sockets is beejs tutorial: http://beej.us/guide/bgnet/Check it out if you haven't.
Daniel Karling
A: 

It appears that your code is functioning correctly as written, but probably not as expected / intended. The IP address you are printing is correct as you are binding to all available interfaces so the server will be able to accept incoming TCP connections on any network interface.

The hints structure you are passing to getaddrinfo() results in the following:

  • AF_UNSPEC for ai_family indicates that the caller shall accept any address family
  • SOCK_STREAM for ai_socktype specifies a stream socket type
  • AI_PASSIVE included in ai_flags causes the returned address to be suitable for use in binding a socket for accepting incoming connections
    • since nodename is NULL, the IP address portion of the socket address structure is set to INADDR_ANY for an IPv4 address or IN6ADDR_ANY_INIT for an IPv6 address

Because IPv6 addresses are sorted before IPv4 addresses in the RFC 3484 sorting, getaddrinfo() is returning an unspecified IPv6 address ("0:0:0:0:0:0:0:0").

In calls to inet_ntop(), unspecified IPv6 addresses may be represented simply as "::".


If you are looking for an address that can be equated to the host name of your server, you might be able to retrieve the host name for the machine via gethostname() and use it as the nodename in your call to getaddrinfo(). Since you are specifying AF_UNSPEC for ai_family, valid descriptive names for nodename include host names. If you do specify a particular IP address in place of INADDR_ANY / IN6ADDR_ANY_INIT, then the socket will only accept TCP connections through that interface.

jschmier