You are not logged in.

#1 2009-04-16 10:31:05

ret
Member
Registered: 2009-04-16
Posts: 4

C programming question (network socket code)

Hello all,

I'm currently learning network socket programming in C and I'm using Beej's guide to help me understand the ins and outs of it. I've been studying the code in the book and running back and forth between man pages and include files and, for the most part it's been going well.

Here's where I'm a little confused though:

void *addr;
struct addrinfo *p;
...
struct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr;
addr = &(ipv4->sin_addr);

From my understanding, this is what's going on:
- *ipv4 is being assigned the value of p->ai_addr.
- addr is being assigned the address of ipv4->sin_addr effectively loading the IP (in this case) into *addr.

How did ipv4->sin_addr get the value in p->ai_addr?
Shouldn't it have been somewhere along the lines of:

struct sockaddr_in *ipv4->sin_addr = (struct sockaddr_in *)p->ai_addr;

Also,

struct sockaddr_in *ipv4 = (struct sockaddr_in *)p-ai_addr;

This is a declaration right?

If someone can shed a little light on this for me, or point me in the right direction e.g. where to RTFM, I'd really appreciate it. I included the source code listing below in case I left out any pertinent info regarding my question. Thanks in advance for any help.

/*
** showip.c -- show IP addresses for a host given on the command line
*/
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>

int main(int argc, char *argv[])
{
    struct addrinfo hints, *res, *p;
    int status;
    char ipstr[INET6_ADDRSTRLEN];
    if (argc != 2) {
        fprintf(stderr,"usage: showip hostname\n");
        return 1;
    }
    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_UNSPEC; // AF_INET or AF_INET6 to force version
    hints.ai_socktype = SOCK_STREAM;
    if ((status = getaddrinfo(argv[1], NULL, &hints, &res)) != 0) {
        fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(status));
        return 2;
    }
    printf("IP addresses for %s:\n\n", argv[1]);
    for(p = res;p != NULL; p = p->ai_next) {
        void *addr;
        char *ipver;
        // get the pointer to the address itself,
        // different fields in IPv4 and IPv6:
        if (p->ai_family == AF_INET) { // IPv4
            struct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr;
            addr = &(ipv4->sin_addr);
            ipver = "IPv4";
        } else { // IPv6
            struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)p->ai_addr;
            addr = &(ipv6->sin6_addr);
            ipver = "IPv6";
        }
        // convert the IP to a string and print it:
        inet_ntop(p->ai_family, addr, ipstr, sizeof ipstr);
        printf(" %s: %s\n", ipver, ipstr);
    }
    freeaddrinfo(res); // free the linked list
    return 0;
}

Offline

#2 2009-04-16 10:51:50

Wilco
Member
Registered: 2008-11-09
Posts: 440

Re: C programming question (network socket code)

There's a lot of pointer stuff going on and it's quite hard in the beginning:

// Declare a variable i and give it a value
int i = 5;

// Make a pointer to i
int *pointer_to_i = &i;

// Print the value inside pointer_to_i. In this case *pointer_to_i represents the value inside i.
printf("i contains: %i\n", *pointer_to_i);

// Change pointer_to_i. In this case we shouldn't use the * because we don't want to use the actual value in pointer_to_i.
int j = 10;
pointer_to_i = j;

Hope this is correct because it's a while ago for me.


About the sruct:

struct sockaddr_in *ipv4->sin_addr = (struct sockaddr_in *)p->ai_addr;

Not correct because you declare a struct pointer called ipv4. sin_addr is a part of that struct and you cannot declare a field inside a struct, only the struct itself.

- *ipv4 is being assigned the value of p->ai_addr.

Almost correct, ipv4 points to ai_addr. (struct sockaddr_in *) is a cast in your example. At this point if you change ipv4, you actually change p->ai_addr


I hope this makes any sense and try to read up some information about pointers references, it really helps.

Last edited by Wilco (2009-04-16 10:52:13)

Offline

#3 2009-04-16 11:55:35

Adams
Member
From: Poland
Registered: 2007-02-12
Posts: 14

Re: C programming question (network socket code)

Wilco wrote:

There's a lot of pointer stuff going on and it's quite hard in the beginning:
[...]
// Change pointer_to_i. In this case we shouldn't use the * because we don't want to use the actual value in pointer_to_i.
int j = 10;
pointer_to_i = j;

Hope this is correct because it's a while ago for me.
[...]

It should be:

pointer_to_i = &j;

Now, i==5, j==10 and *pointer_to_i==10. On the other hand, if we would do something like this:

*pointer_to_i = j;

The results would be: i==10, j==10, *pointer_to_i==10

Think of a pointer as a variable that holds only the address of another variable.
As Wilco mentioned, struct addrinfo contains a pointer (ai_addr) to sockaddr_in. So in this example you declare a pointer to struct sockaddr_in and initialize it with the value of p->ai_addr. The '(struct sockaddr_in *)' part is only a cast. As you have a pointer to a struct you can get any of that struct members using '->' (side note: 'a->b' is equivalent to '(*a).b' ). Later you assign addr with the address of sin_addr in *ai_addr


"The bureaucracy is expanding to meet the needs of an expanding bureaucracy"

Offline

#4 2009-05-11 23:54:16

ret
Member
Registered: 2009-04-16
Posts: 4

Re: C programming question (network socket code)

Thanks for the info, I understand it much better now.

Offline

Board footer

Powered by FluxBB