I found this piece of C code:
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <netinet/in.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;
}
There are two lines that I don't know how to interpret:
struct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr;
struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)p->ai_addr;
Why does the author of this program use parentheses?
I tried following a wonderful guide about interpreting complex declarations but I still don't understand.
It's called casting. It converts from one type to another, but the theory behind it is a lot more complicated. Casting doesn't mean you have an object describing a Dog (for example a struct) and you can cast it to a Human. Obviously you can't.
Casting means having identical memory blocks that can map on another block. A simpler explanation is when you have a complex structure and you cast from a pointer to the structure or from the data structure to the pointer.
Also note, that a data structure doesn't necessarily mean a struct. It can also mean an array. And, an array is a concept so it can mean something like int some_data[20]; or int** some_data;.
Now, as for why the author uses the parenthesis, it's because this is the syntax. You can't use any character.
Along with further reading about casting, please look up static_cast, dynamic_cast and reinterpret_cast. These 3 functions (well, almost, but I'm trying to not complicate it even more) use native casting. static_cast is similar to (type_a*)type_b.
For some examples, look up casting from int to enum and vice-versa to get an idea.
If you want to keep it simple, don't check any C++ concepts about casting just yet until you get a hang of the concepts in C first. They are common, but C++ will fork a lot from C because of classes, polymorphism and inheritance in general.
Related
Can someone help me to get the IPs of google.com?
I can't find any good resource on this.
Most tutorials on C network programming create a client socket and a server socket on the same computer. (I don't know in which situation that would make sense)
And none of the codes on beej.us worked for me.
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netdb.h>
int main(void)
{
struct addrinfo* res = NULL;
getaddrinfo("google.com", "443", 0, &res);
struct addrinfo* i;
for(i=res; i!=0; res=res->ai_next)
{
printf("%s\n", res->ai_addr->sa_data);
}
}
Output:
�
�
�
���$u
���$u
���$u
���"u
���"u
���"u
��� u
��� u
��� u
���&u
���&u
���&u
Segmentation fault
First, you never modify i inside of the loop so you end up with an infinite loop. You need to change to loop statement to:
for(i=res; i!=NULL; i=i->ai_next)
Regarding the output, the ai_addr field is of type struct sockaddr *, which is a pointer to a generic socket address struct, and its sa_data field is just a binary blob of the data for that address, not a printable string.
To print these values correctly, you need to inet_ntop function. First, you need to inspect ai_addr->sa_family to see if it is an IPv4 address or an IPv6 address. Then you'll need to cast ai_addr to either a struct sockaddr_in * for IPv4 or struct sockaddr_in6 * for IPv6, then pass the sin_addr or sin6_addr field respectively to inet_ntop along with the address family to convert it to a string.
for(i=res; i!=NULL; i=i->ai_next)
{
char str[INET6_ADDRSTRLEN];
if (i->ai_addr->sa_family == AF_INET) {
struct sockaddr_in *p = (struct sockaddr_in *)i->ai_addr;
printf("%s\n", inet_ntop(AF_INET, &p->sin_addr, str, sizeof(str)));
} else if (i->ai_addr->sa_family == AF_INET6) {
struct sockaddr_in6 *p = (struct sockaddr_in6 *)i->ai_addr;
printf("%s\n", inet_ntop(AF_INET6, &p->sin6_addr, str, sizeof(str)));
}
}
Output:
172.217.10.238
172.217.10.238
172.217.10.238
2607:f8b0:4006:813::200e
2607:f8b0:4006:813::200e
2607:f8b0:4006:813::200e
In This statement i is never being modified in loop body, and because it is not initialized, it never even enters the loop:
for(i=res; i!=0; res=res->ai_next)
{
printf("%s\n", res->ai_addr->sa_data);
}
Additionally, you are missing a few other parts. The following steps are part of a full example linked below:
Create the following instances of struct addrinfo:
struct addrinfo *result = NULL;
struct addrinfo *ptr = NULL;
struct addrinfo hints;
Then initialize Winsock
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
Setup the hints address info structure
ZeroMemory( &hints, sizeof(hints) );
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
Call getaddrinfo
dwRetval = getaddrinfo(argv[1], argv[2], &hints, &result);
if ( dwRetval != 0 ){//handle error}
Now, for example based on above, your loop would look like:
for(ptr=result; ptr != NULL ;ptr=ptr->ai_next) {//
Entering "www.google.com" 0 on the command line for the complete example (linked below) will look similar to this:
This full Windows example is here. Note: Bug in code, i.e. ptr->ai_cannonname can be null with "www.google.com" so change this line to test before calling:
if(ptr->ai_canonname) printf("\tCanonical name: %s\n", ptr->ai_canonname);
A full Linux example is here.
I'm writing a client side as part of a TCP client server program.
My code reaches the connect part and throws an Invalid argument error, I have gone through the code several times and I couldn't find the problem.
The code receives 3 arguments, first one is an IP address or a hostname, second one is port and the third is the maximum length of the message to be sent.
My code uses getaddrinfo in order to convert the ip address or hostname, creates the needed variables, starts a connection, read from file, send data and receive data.
I run the code with:
gcc -std=gnu99 -O3 -Wall -o pcc_client pcc_client.c
./pcc_client 127.0.0.1 2233 4
The output is:
sockaddr_in initialized
Error starting connection : Invalid argument
#include <stdlib.h>
#include <stdio.h>
#include <stdio.h>
#include <unistd.h>
#include <assert.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <dirent.h>
#define FILE_ADDR "/dev/urandom"
int main(int argc, char *argv[]) {
if (argc != 4) {
printf("should receive 3 arguments Received %d args\n", argc);
exit(1);
}
//Get command line arguments
unsigned int port = atoi(argv[2]);
int length = atoi(argv[3]); //Number of bytes to read
char* buffer = malloc(length * sizeof(char)); //Buffer to hold data read from file
char* recvBuf = malloc(10 * sizeof(char)); // Buffer to hold response from server
struct addrinfo hints, *servinfo, *p;
struct sockaddr_in *serv_addr;
int rv;
char ip[100];
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
if ((rv = getaddrinfo(argv[1], argv[2], &hints, &servinfo)) != 0) {
perror("getaddrinfo error\n");
return 1;
}
for (p = servinfo; p != NULL; p = p->ai_next) {
serv_addr = (struct sockaddr_in *) p->ai_addr;
strcpy(ip, inet_ntoa(serv_addr->sin_addr));
}
// inet_aton(ip, &h.sin_addr);
freeaddrinfo(servinfo);
//Initialize socket
int sockfd;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) //Error creating socket
{
perror("Error creating socket \n");
exit(1);
}
printf("socket created\n");
//Initialize sockaddr_in structure
memset((void*)serv_addr, 0,(size_t) sizeof(*serv_addr));
serv_addr->sin_family = AF_INET;
serv_addr->sin_port = htons(port);
serv_addr->sin_addr.s_addr = inet_addr("127.0.0.1"); //change?
//Initialize connection
if (connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) { //Error connecting
perror("Error starting connection \n");
exit(1);
}
printf("connect succesful\n");
exit(0);
}
You are using serv_addr all wrong.
You have declared serv_addr as a sockaddr_in* pointer. After getaddrinfo() exits successfully, you are looping through the output list, assigning serv_addr to point at every ai_addr in the list, and then you free the list, leaving serv_addr pointing at invalid memory. You then trash memory when you try to populate serv_addr with data. And then you end up not even passing a valid pointer to a sockaddr_in to connect() at all, you are actually passing a pointer to a pointer to a sockaddr_in, which is why it complains about an "invalid argument".
In fact, you are going about this situation all wrong in general. When using getaddrinfo(), since it returns a linked list of potentially multiple socket addresses, you need to loop through the list attempting to connect() to every address until one of them is successful. This is especially important if you ever want to upgrade the code to support both IPv4 and IPv6 (by setting hints.ai_family = AF_UNSPEC;).
Try something more like this instead:
int main(int argc, char *argv[])
{
if (argc != 4)
{
printf("should receive 3 arguments Received %d args\n", argc);
exit(1);
}
struct addrinfo hints, *servinfo, *p;
int sockfd = -1;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_INET; // or AF_UNSPEC
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
int rv = getaddrinfo(argv[1], argv[2], &hints, &servinfo);
if (rv != 0)
{
perror("getaddrinfo error\n");
return 1;
}
for (p = servinfo; p != NULL; p = p->ai_next) {
//Initialize socket
sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
if (sockfd < 0) continue;
//Initialize connection
rv = connect(sockfd, p->ai_addr, (socklen_t) p->ai_addrlen);
if (rv == 0) break;
close(sockfd);
sockfd = -1;
}
freeaddrinfo(servinfo);
if (sockfd < 0) //Error creating/connecting socket
{
perror("Error creating/connecting socket \n");
exit(1);
}
printf("connect successful\n");
...
close(sockfd);
exit(0);
}
You define serv_addr
struct sockaddr_in *serv_addr;
Then you use it
memset((void*)serv_addr, 0,(size_t) sizeof(*serv_addr));
serv_addr->sin_family = AF_INET;
serv_addr->sin_port = htons(port);
serv_addr->sin_addr.s_addr = inet_addr("127.0.0.1"); //change?
But nowhere in between those two places in the code do you initialize the pointer! That means serv_addr is uninitialized and its value is indeterminate and will point to some seemingly random location. Dereferencing the pointer will lead to undefined behavior.
The simple and natural and de facto standard solution is to make serv_addr not a pointer, but a structure object:
struct sockaddr_in serv_addr;
Then when you need a pointer you use the address-of operator &.
The issue above is further complicated by you actually using the & operator when calling connect. With serv_addr being a pointer, then &serv_addr is a pointer to the pointer. It will be of type struct sockaddr_in **. It is this issue, with the pointer to the pointer, that leads to the error message, since the pointer you send in is not a pointer to a sockaddr_in structure object.
By using a structure object as shown above will solve this problem as well.
I am creating a UDP server-client program. Client requests a file and the server sends to client if found.
Based on Beej's Guide to Networking,
inet_ntoa() returns the dots-and-numbers string in a static buffer that is overwritten with each call to the function.
inet_ntop() returns the dst parameter on success, or NULL on failure (and errno is set).
The guide mentions ntoa is deprecated so ntop is recommended since it supports IPv4 and IPv6.
On my code I am getting different results when I use function or the other and my understanding is that they should throw the same result. Anything I am missing? Any help would be greatly appreciated.
Code:
//UDP Client
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#define MAXBUFLEN 1024
#define SER_IP "176.180.226.0"
#define SER_PORT "1212"
// Get port, IPv4 or IPv6:
in_port_t get_in_port(struct sockaddr *sa){
if (sa->sa_family == AF_INET) {
return (((struct sockaddr_in*)sa)->sin_port);
}
return (((struct sockaddr_in6*)sa)->sin6_port);
}
int main(int argc, char *argv[]){
int sock, rv, numbytes;
struct addrinfo hints, *servinfo, *p;
char buffer[MAXBUFLEN];
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM;
rv = getaddrinfo(NULL, SER_PORT, &hints, &servinfo);
if (rv != 0){
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
exit(1);
}
// Printing IP, should provide same result
for(p = servinfo; p != NULL; p = p->ai_next) {
char str1[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &p->ai_addr, str1, INET_ADDRSTRLEN);
printf("ntop:%s\n", str1) ;
printf("inet_ntoa:%s \n", inet_ntoa(((struct sockaddr_in *)p->ai_addr)->sin_addr));
printf("\n");
}
exit(1);
}
Current output:
ntop:64.80.142.0
inet_ntoa:0.0.0.0
ntop:160.80.142.0
inet_ntoa:127.0.0.1
As per the man page, in the case of AF_INET the argument src must point to a struct in_addr (network byte order).
In your struct addrinfo you have a pointer to struct sockaddr which is basically
sa_family_t sa_family;
char sa_data[];
However, struct sockaddr_in is
sa_family_t sin_family;
in_port_t sin_port;
struct in_addr sin_addr;
So, you need to replace
inet_ntop(AF_INET, &p->ai_addr, str1, INET_ADDRSTRLEN);
by either
inet_ntop(AF_INET, &p->ai_addr->sa_data[2], str1, INET_ADDRSTRLEN);
(the src argument may be &p->ai_addr->sa_data[1 << 1] to avoid the "magic number" 2 - the offset which counts for the port number storage)
or
inet_ntop(AF_INET, &((struct sockaddr_in *)p->ai_addr)->sin_addr, str1, INET_ADDRSTRLEN);
Then it will produce correct output.
I am reading Beej's guide to network programming and in chapter 5.1, in the showip.c program I see the following line of code:
memset(&hints, 0, sizeof hints);
After a discussion on the ##c channel on freenode I deducted that the reasoning of that memset call could be to set the value of hints.ai_flags to 0(note that the program works fine I remove that line and I explicitly initialize hints.ai_flags to 0). If this is true, why does he need to set the whole struct to 0?
This is the full source:
/*
** 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>
#include <netinet/in.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;
}
It's required by getaddrinfo() function documentation (where you pass your hints variable as parameter). From man getaddrinfo:
All the other fields in the structure pointed to by hints must contain either 0 or a NULL pointer, as appropriate.
It's because you are only going to fill/use/initialize some of the fields of the struct, giving 0 to the other fields prevents reading an uninitialzied variable, and sometimes 0 is the default value for those variables.
note that the program works fine I remove that line and I explicitly initialize hints.ai_flags to 0
Not necessarily, if you are on linux, I suggest using valgrind to detect reads to uninitialized variables, since that causes undefined behavior, the behavior could be that nothing wierd happens.
Am trying my hand at sockets programming and I need some help because I can't build any of the programs I write. Whenever I try to build any sockets application, the compiler reports the following error:
error: expected specifier-qualifier-list before '_uid32_t'
This variable is inside a struct, which in turn is located in the header file "socket.h", and looks like this:
struct ucred {
pid_t pid;
__uid32_t uid;
__gid32_t gid;
};
There aren't any other errors in the other files and this is the only error the compiler returns.
I don't know if this is of any consequence but the header file is the one that comes with cygwin because the guides and tutorials am using are on Unix sockets and am running Windows XP. Am also using Code::Blocks running a gcc compiler.
I really hope that it's possible to run a program using the Unix sockets API on Windows because I'd really hate to confine myself to winsock only. Also, most of the freely available and comprehensive tutorials on sockets and network programming use Unix sockets.
Here's the code, though I don't think it really matters because I get the exact same error no matter program as long as it's using socket.h.
#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_in *ipv6 = (struct sockaddr_in6 *)p ->ai_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 linked list
return 0;
}
There's also other source code from other programs I could have added but I chose this one instead because I got it from the internet and not a textbook so anyone can look it up here.
Try including <unistd.h> and <sys/types.h> before your socket.h.