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.
Related
I know how struct pointers work in general. But for struct spi_controller * spi_busnum_to_master(u16 bus_num),
What is holding the address of the struct spi_controller it is pointing towards ?
Can someone decode the logic of this declaration?. ( this style creating struct pointers)
From my understanding, a struct pointer is to enable a variable hold the address of some structure that it points to.
struct spi_controller * spi_busnum_to_master(u16 bus_num) declares spi_busnum_to_master to be a function taking a parameter of type u16 and returning a pointer to struct spi_controller.
The return value is passed by whatever method is defined by the Application Binary Interface for the target platform. Often it is in a processor register.
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).
In C socket programming the accept() declaration looks like:
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
I can understand the uses of sockfd, struct sockaddr *addr.
But why we have to pass the address of the length of the socket, it could have been socklen_t. Because if the accept() function needs the length then it can get it by socklen_t. Why the protype of the function is declared in such that way?
So what is the reason behind using socklen_t * type?
In code that's agnostic to the address/protocol family of the socket it's accepting from, it may be using a generic sockaddr_storage structure to hold the result. The initial value of the pointed-to socklen_t is the size of this storage; the value after accept returns is the actual size of the resulting peer address. Also, some address/protocol families like AF_UNIX have variable length addresses, so even if you know the type you may not know the size.
why addrlen is needed
accept designed to deal with lots of protocal family, their addr struct maybe different length.
The argument addr is a pointer to a sockaddr structure. This structure is filled in with
the address of the peer socket, as known to the communications layer. The exact format
of the address returned addr is determined by the socket's address family (see socket(2)
and the respective protocol man pages). When addr is NULL, nothing is filled in; in this
case, addrlen is not used, and should also be NULL.
why pointer
The addrlen argument is a value-result argument: the caller must initialize it to contain
the size (in bytes) of the structure pointed to by addr; on return it will contain the
actual size of the peer address.
why socklen_t
The socklen_t type
The third argument of accept() was originally declared as an int * (and is that under
libc4 and libc5 and on many other systems like 4.x BSD, SunOS 4, SGI); a POSIX.1g draft
standard wanted to change it into a size_t *, and that is what it is for SunOS 5. Later
POSIX drafts have socklen_t *, and so do the Single UNIX Specification and glibc2. Quot‐
ing Linus Torvalds:
"Any sane library must have "socklen_t" be the same size as int. Anything else
breaks any BSD socket layer stuff. POSIX initially did make it a size_t, and I (and
hopefully others, but obviously not too many) complained to them very loudly indeed.
Making it a size_t is completely broken, exactly because size_t very seldom is the same
size as "int" on 64-bit architectures, for example. And it has to be the same size as
"int" because that's what the BSD socket interface is. Anyway, the POSIX people eventu‐
ally got a clue, and created "socklen_t". They shouldn't have touched it in the first
place, but once they did they felt it had to have a named type for some unfathomable rea‐
son (probably somebody didn't like losing face over having done the original stupid
thing, so they silently just renamed their blunder)."
ref: man accept, man socket
I'm using recvfrom in my program to get DGRAM data from a server I specify in src_addr. However, I'm not sure why I need to initialize and pass in addrlen.
I read the man page and I didn't really understand what it's getting at.
If src_addr is not NULL, and the underlying protocol provides the source address, this source address is filled in. When
src_addr is NULL, nothing is filled in; in this case, addrlen is not
used, and should also be NULL. The argument addrlen is a value-result argument, which the caller should initialize before the
call to the size of the buffer associated with src_addr, and
modified on return to indicate the actual size of the source address. The returned address is truncated if the buffer provided is too small;
in this case, addrlen will return a value greater than was supplied to the call.
I'm guessing that it's got something to do with src_addr being ipv4 or ipv6. Is this correct?
Thanks!
Maybe there is a missinterpretation from your side. Talking about:
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
struct sockaddr *src_addr, socklen_t *addrlen);
src_addr is not used to hand in the adress that you would like to listen to, but rather a storage location provided by you to get the actual source address handed out.
Thus if you set src_addr to NULL because youre not interested in the address at all, you don't have to care about addrlen as it won't get used anyway.
If on the other hand you want to be informed about the source address, you not only have to provide a storage location, but also tell how big the storage location you provided is.
Thats why you should initialize *addr_len to the buffer size you allocated.
After your call the value pointed to by addrlen will inform you about how much (if any) of the space you allocated to store the source address got actually filled with data.
About sizes
The whole hassle with struct sockaddr and passing sizes back and forth has to do with the fact that even thoug they're most heavily used in networking sockets were intended to be much more general concept.
Think about unix domain sockets as an an example as they are implemented via the filesystem they require an adressing scheme totaly different from that known from IP based networking. The type of sockaddr used here is:
struct sockaddr_un {
sa_family_t sun_family; /* AF_UNIX */
sun_path[UNIX_PATH_MAX]; /* pathname */
};
Compare this to the struct used in IP based networking:
struct sockaddr_in {
sa_family_t sin_family; /* address family: AF_INET */
in_port_t sin_port; /* port in network byte order */
struct in_addr sin_addr; /* internet address */
};
it should be clear both don't have too much in common.
sockets were designed to be able to fit both cases.
ssize_t recvfrom(int socket, void *buffer, size_t length, int flags,
struct sockaddr *address, socklen_t *address_len);`
The address_len argument specifies the length of the address structure i.e. the number of bytes to use from the start address indicated at address(start address of memory location + number of bytes from the start address that hold the value)
The structure is defined in /usr/include/bits/socket.h
/* Structure describing a generic socket address. */
struct sockaddr
{
__SOCKADDR_COMMON (sa_); /* Common data: address family and length. */
char sa_data[14]; /* Address data. */
};
Thus the sa_data field holds the address data (start address of the data) whose length is indicated by the address_len argument.
... whenever a function says it takes a struct sockaddr* you can cast your
struct sockaddr_in*, struct sockaddr_in6*, or struct sockadd_storage*
to that type with ease and safety.
Therefore, as indicated in the man page and #WhozCraig in the comment to your question, this field is updated with the actual size when the method returns.
More information
recvfrom
Beej's Guide to Network Programming - struct sockaddr and pals
I'm working with this structure in C:
/** This structure describes an Internet host address. */
typedef struct pj_hostent
{
char *h_name; /**< The official name of the host. */
char **h_aliases; /**< Aliases list. */
int h_addrtype; /**< Host address type. */
int h_length; /**< Length of address. */
char **h_addr_list; /**< List of addresses. */
} pj_hostent;
I can access the h_name part of the structure fine like this:
strcpy(test1, he->h_name); // copy part of struct into char[] array
and it contains a meaningful "sip2" value. However, when I try to access the elements of h_addr_list like this:
strcpy(test1, he->h_addr_list[0]);
I get meaningless jibberish.
What's the correct way in C to access values like this?
h_addr_list[0] is not a string, it is a pj_in_addr, which is a 32-bit integer which is not null terminated.
printf() it with %d or %x, not %s.
See PJLIB Reference: Network Address Resolution for an example of use.
You are accessing it correctly. That field really does contain gibberish.
Just because it is declared as a char** does NOT mean that it is an array of strings.
It may be a pointer to a byte-buffer of unknown format. (ie. jibberish)
You should check any available documentation or other source code for details of exactly what h_addr_list is, and how it should be interpreted.
The struct only contains a pointer. You need to allocate some storage for that pointer to point at before you can use it. As it is, the pointer almost certainly just contains a (more or less) random value. When you use that as a target in your call to strcpy, you're overwriting that random memory location -- which can and will lead to major problems elsewhere.
h_addr_list is pretty much the same way -- it's just a pointer to a pointer. That'll (normally) be used to refer to an array of strings, but something has to allocate that array of strings before it can be put to any meaningful use. Given the similarity to a hostent structure, along with this structure there's presumably some analog to (or wrapper around) gethostbyname and/or gethostbyaddress that initializes this. In the case of the wrapper (which I'd judge the more likely of the two), it probably gets the correct data in a hostent, and then copies data from the hostent to this structure.
A short Example that does work. Remember that allocating for the struct does not allocate for the pointer.
typedef struct pj_hostent
{
char *h_name; /**< The official name of the host. */
char **h_aliases; /**< Aliases list. */
int h_addrtype; /**< Host address type. */
int h_length; /**< Length of address. */
char **h_addr_list; /**< List of addresses. */
} pj_hostent;
int _tmain(int argc, _TCHAR* argv[])
{
char* s[]= {"this","is","couple of words"};
pj_hostent hst = {"high",s,3,4,s };
char buff[255] = {};
//Access as a local initialized struct
strcpy(buff,hst.h_addr_list[0]);
printf("%s\n",buff);
pj_hostent * he = & hst;
//Access as a pointer
strcpy(buff,he->h_addr_list[0]);
printf("%s\n",buff);
gets(buff);
}
If you never initialized/allocated memory for those pointers, you would get jibberish and/or segmentation faults because they are pointing to random points in memory.
strcpy assumes that you have already allocated memory to the character pointer. So, probably, the pointer is still having a NULL value.
struct elements are accessed with the dot operator
strcpy(test1, he.h_addr_list[0]);
elements of structs that are "pointed" to are accessed with the -> operator
strcpy(test1, he->h_addr_list->[0]);
If you're getting gibberish, then either test1 isn't big enough, h_addr_list isn't pointing to an array of char*, or the first element of the array is actually gibberish.