Understanding getaddrinfo function in C - c

I'm new to C and socket programming, just a question on getaddrinfo function. The function prototype of getaddrinfo is:
int getaddrinfo(const char *host, const char *service, const struct addrinfo *hints, struct addrinfo **result);
and getaddrinfo returns a result that points to a linked list of addrinfo structures, each of which points to a socket address structure that corresponds to host and service.
Below is my questions:
Q1-Why it needs to return a result that points to a linked list of addrinfo structures? I mean that given a host and service, these is only one unique socket address, how could it be more than one valid socket address so that a linked list is needed?
Q2-the last parameter is struct addrinfo **result, why it is a pointer to a pointer? Why it is not struct addrinfo *result, and then getaddrinfo creates sth internally and let result(struct addrinfo *) point to it?
someone says it is due to getaddrinfo call malloc internally, but I can also code like this
int main()
{
char *ptr_main;
test(ptr_main);
free(ptr_main);
}
void test(char * ptr)
{
ptr = malloc(10);
}
so the parameter to the function is char *ptr, not char **ptr.

getaddrinfo() returns a list of address because an hostname can have more than an address. Think for example to those high traffic sites that need to distribute visitors through different IPs.
Since getaddrinfo()
combines the functionality provided by the gethostbyname(3) and getservbyname(3) functions into a single interface, but unlike the latter functions, getaddrinfo() is reentrant and allows programs to eliminate IPv4-versus-IPv6 dependencies
it might trigger a DNS session to resolve an host name. In case of those aforementioned high traffic sites the same hostname will correspond to a list of actual addresses.
You also ask:
struct addrinfo **result, why is it a pointer to a pointer?
In C a pointer to something is passing as a parameter of a function when it has to modify it. So, for example, in case you need to modify an integer, you pass int *. This particular kind of modification is very common in C when you want to return something through a parameter; in our previous example we can return an extra integer by accessing the pointer passed as a parameter.
But what if a function wants to allocate something? It will result, internally in a type * var = malloc(), meaning that a pointer to type would be returned. And in order to return it as a parameter we need to pass a type ** parameter.
Is it clear the logic? Given a type, if you wat to return it as a parameter you have to define it as a pointer to type.
In conclusion, in our case the function getaddrinfo needs to modify a variable which type is struct addrinfo *, so struct addrinfo ** is the parameter type.
Just to mention the meaning of this parameter:
The getaddrinfo() function allocates and initializes a linked list of addrinfo structures, one for each network address that matches node and service, subject to any restrictions imposed by hints, and returns a pointer to the start of the list in res. The items in the linked list are linked by the ai_next field.
As you can see we actually have an allocation inside the function. So this memory will need to be eventually freed:
The freeaddrinfo() function frees the memory that was allocated for the dynamically allocated linked list res.
Why not just a type * parameter?
Your code example results in undefined behavior, and when I run it it caused a program crash.
Why? Is I wrote above, in C parameters are passed by value. It means that in case of a func(int c) function, called in this way
int b = 1234;
funct(b);
the parameter c internally used by the function will be a copy of b, and any change on it won't survive outside the function.
The same happens in case of func(char * ptr) (please note the huge spacing, to underline how the type is char * and the variable is ptr): any change on ptr won't survive outside the function. **You'll be able to change the memory it points, and these changes will be available after the function returns, but the variable passed as a parameter will be the same it was before the call to func().
And what was the value of ptr_main, in your example, before test was called? We don't know, as the variable is uninitialized. So, the behavior is undefined.
If you still have doubts, here it is a program that demonstrates that the newly allocated address obtained by value cannot be accessed from outside the function:
#include <stdlib.h>
#include <stdio.h>
void test(char * ptr)
{
ptr = malloc(10);
printf("test:\t%p\n", ptr);
}
int main()
{
char *ptr_main = (char *) 0x7777;
printf("main-1:\t%p\n", ptr_main);
test(ptr_main);
printf("main-2:\t%p\n", ptr_main);
}
Output:
main-1: 0000000000007777
test: 0000000000A96D60
main-2: 0000000000007777
Even after the function call the value of ptr_main is the same it after I initialized it (0x7777).

Related

What does struct hostent stands for?

A pointer to hostent is the struct returned by gethostbyname().
Exact function signature : struct hostent* gethostbyname(const char*)
And I have no idea what the 'ent' part means here at the end of hostent.
I get very forgetful when I try to memorize that I don't understand, so please help me out.
A quick search on GitHub points to basedefs/netdb.h (definitions for network database operations)
The <netdb.h> header shall define the hostent structure that includes at least the following members:
char *h_name Official name of the host.
char **h_aliases A pointer to an array of pointers to
alternative host names, terminated by a
null pointer.
int h_addrtype Address type.
int h_length The length, in bytes, of the address.
char **h_addr_list A pointer to an array of pointers to network
addresses (in network byte order) for the host,
terminated by a null pointer.
From there, the official documentation for gethostbyaddr() includes:
Entries shall be returned in hostent structures.
The gethostbyaddr() function shall return an entry containing addresses of address family type for the host with address addr.
The len argument contains the length of the address pointed to by addr.
The gethostbyaddr() function need not be reentrant. A function that is not required to be reentrant is not required to be thread-safe.
Entries shall be returned in hostent structures.
Upon successful completion, these functions shall return a pointer to a hostent structure if the requested entry was found, and a null pointer if the end of the database was reached or the requested entry was not found.
So there you have it: ent for entry. Not entity.

Struct points as parameter to function C

I have a few months that i started programming in C, but I now find myself with a doubt, for example, let see the next example code:
typedef struct
{
char *var1;
}myFooStruct;
myFooStruct struct1 [ 200 ];
my doubt is what would I get for **struct1, &struct1, *struct1, struct1,
as I passed the struct to a function that takes a two-dimenssion pointer ( **myFooStruct ), I have basic knowledge about pointers 1-but I find myself confused with pointers to structs and 2-how can I modify the struct if I passed it as at parameter to a function
If there is another similar question post it here please, I could not find anything alike, if you know some lecture I could read is welcome too, thank you very much!!
* is a dereference operator - think of it as meaning "the value contained at location xyz".
& is a reference operator - think of it as meaning "the location in memory of variable xyz".
Accordingly:
myFooStruct struct1 is a physical structure - this is the actual object.
&struct1 is equivalent to the location in memory of struct1 - this is usually an address (like 0xf0004782). You'll usually see this used when passing by reference (see Wikipedia for more info) or when assigning to a pointer (which literally points to a location in memory - get it?).
*struct1 dereferences struct1 - that is, it returns the value contained at location struct1. In the example you give, this is invalid, as struct1 is not a pointer to a location in memory.
**struct1 is tricky - it returns the value contained at the location that is contained within struct1. In other words: struct1 points to a certain location in memory. At that location is the address of another location in memory! Think of it as a scavenger hunt - you go to a location, find a clue, and follow that to another location.
As to how to access structs: think of a struct as a box. When you have the box in front of you, you simply need to open it up and look at what's inside. In C, we do this using the . operator:
char *my_var = struct1.var1
When you don't have the box in front of you - that is, you have a pointer to the struct - you need to access the location the box is at before you can look at what's inside. In C, we have a shortcut for this - the -> operator:
myFooStruct *pointer_to_struct1 = &struct1
char *my_var = pointer_to_struct1->var1
//NOTE: the previous line is equivalent to:
// char *my_var = (*pointer_to_struct1).var1
Way 1 Using dynamic memory allocation. Generally used in linked list and all..
If you want to modify the struct in another function. first declare a pointer to a struct.
myFooStruct* struct1;
Allot memory for the struct
struct1 = malloc(sizeof(myFooStruct));
Send the address to the function
func1(struct1);
Receive it and access it to modify in the function.
void func(myFooStruct* struct1)
{
(*struct1).member1 = ...; // whatever you wanna do
...
Way 2
Declare a struct.
myFooStruct struct1;
Send the address of the struct to the function
func1(&struct1);
Receive it and access it to modify in the function.
void func(myFooStruct* struct1)
{
(*struct1).member1 = ...; // whatever you wanna do
...
If you need to access myFooStruct from function, you can define single pointer: fn( myFooStruct * st ). The you call the function with fn( struct1 ) and change values st[N].var1 = .... Double pointer may be necessary if your object is pointer with allocated memory, not static array as yours.
struct1 is just a table and to be speciffic it's just pointer to a place in the memory.
*struct1 would be thing, that is pointed by struct1, so it's a first struct in a table of structs.
But **struct1 won't be any string. First of all you do not allocate memory for string and second string is member of this struct not struct itself. **struct is undefined behavior, nothing more.
&struct is a pointer to the table, so it's a pointer to the pointer, that points first struct in a table.
You have to decide on your own, what you want. If you want to pass table of your structs then the cleanest way would be:
void function(myFooStruct structTab[]);
1. You should pass a struct pointer to function to access struct inside it .
Declare a struct pointer -
myFooStruct *struct1;
Allocate memory for struct
And pass it to function which is declared as -
type fn(myFooStruct *struct1){
.....
}
Call this function like this -
fn(struct1);
Access struct member like this -struct->member1
2. You can also pass what you have declared right now.
myFooStruct struct1[ 200 ];
define function as -
type fn(myFooStruct struct1[]){
.....
}
Access struct members like this - struct[i].member1.

Function name for returning a struct

I want to make a function in which I change an already existing struct. So the return value of that function should be a struct. If I want an int as return value I call the function "int example()" ... How do I call the function if I want to return a struct? Since "struct" is already taken — I already take "struct whatever" to create one.
If you want the function to modify an existing struct, you should pass the struct in by pointer:
void modify_thing(struct whatever *thing);
If you want to return a modified copy of the struct, you can return the struct by value:
struct whatever edit_thing(const struct whatever *input);
Note that it is usually more efficient to pass struct variables by pointer, rather than by value.
passing a struct by value will cause the compiler to establish 1 or more reserved areas in memory that can only be used for that function.
Each of those memory areas are manipulated by the compiler inserting calls to memcpy().
Much better to pass a pointer to the struct, then return a simple indication of success/failure of the struct update operation.

Casting void pointer to struct pointer does not return correct pointers inside structure

I have a function that allows me to set some void *user_data which I am using to store a pointer to a struct job_data defined as:
struct job_data {
int *i
struct *j;
}
It does this by allowing me to pass my pointer to the user_data setting function through the call, so if I've got struct job_data job_info, I would set it via set_user_data(&job_info) where *set_user_data* receives a void * as a parameter.
However, when I get my pointer back later and cast it via struct job_data *job=user_data, the pointers inside (job.i and job.j) are set to different pointers than in the original job_data structure that I had cast to void *. Why is that? What should I do differently to recapture my original i and j pointers?
Most likely the scope that allocated struct job_data job_info on the stack no longer exists when you retrieve your pointer.
If the scope has ended by the time you retrieve your pointer then the contents will most likely have been overwritten by then.
You can fix this by either making sure the scope is valid as long as the pointer has to be accessed or to allocate the struct on the heap (malloc and family).

getaddrinfo addrinfo result in stack or heap

I am a bit confused at least.
getaddrinfo() call 'updates' a pointer to a addrinfo struct, all is well when I am going to use the addrinfo in the same scope (that function) but what happens if I copy the struct to another one (by assigning it).
Please help me understand the undergoing basics (not seeking advice for alternative approaches).
Correct me if I am wrong:
a) getaddrinfo() requires a pointer to struct-pointer to addrinfo.
b) getaddrinfo creates a addrinfo struct in the current function scope and updates the pointer required in a)
Now my real question: i would like to store that addrinfo somewhere else. Using an assigning to an other pointer does not do a deep copy, and after the function all the pointers become invalid?
Better give an extremely simplified example:
void GetAddrInfo(struct addrinfo *update)
{
struct addrinfo *res;
getaddrinfo(xx,xx,xx,&res);
//is this save? After this 'scope' ends all pointed fields are invalid?
//this doesn't copy the linked list ai_next.
*update=*res;
}
Directly using &update on getaddrinfo seems to not work because the problem remains: the original struct get destroyed after the function scope ends.
Anyone able to give me more insight here (please explain what gets created where and destroyed where, stack, heap all info is welcome)
the original struct get destroyed after the function scope ends
No, the struct's pointer is destroyed. The rest of the data is still in the heap. This would be a memory leak if you don't call freeaddrinfo() when you're finished with the result.
i would like to store that addrinfo somewhere else
Since the data still exists, feel free to copy the pointer; no need for a deep copy. From your example:
void GetAddrInfo(struct addrinfo **update) /* pointer to pointer */
{
struct addrinfo *res;
getaddrinfo(xx,xx,xx,&res);
*update=res; /* save the pointer to the struct */
}
You would simply call this function with:
struct addrinfo *mycopy;
GetAddrInfo(&mycopy);
getaddrinfo allocates a list of addrinfo structures, and gives you the pointer to the head of the list. You release all allocated memory by passing this pointer to freeaddrinfo when you're done with it.
What you're doing is safe enough, but leaks memory.
void GetAddrInfo(struct addrinfo **update)
{
getaddrinfo(xx,xx,xx,update);
}
addrinfo * myai;
GetAddrInfo(&myai);
freeaddrinfo(myai)
This approach will not leak memory - you're simply retrieving a pointer to the addrinfo list head.

Resources