Spending way too much time trying to figure out why inet_ntop is always returning the same IP address of 2.0.19.86 inside of my barebones C UDP socket program.
Here is the code:
#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 SERVERPORT "4950" // the port users will be connecting to
int main(int argc, char *argv[])
{
int sock;
struct addrinfo addr_type, *server_info, *p;
int err;
int numbytes;
if (argc != 3) {
fprintf(stderr,"usage: talker hostname message\n");
exit(1);
}
//Specify type of response we want to git
memset(&addr_type, 0, sizeof addr_type);
addr_type.ai_family = AF_INET; // set to AF_INET to use IPv4
addr_type.ai_socktype = SOCK_DGRAM;
//Get the address info (like IP address) and store in server_info struct
if ((err = getaddrinfo(argv[1], SERVERPORT, &addr_type, &server_info)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(err));
return 1;
}
// There might be multiple IP addresses...loop through and use the first one that works
for(p = server_info; p != NULL; p = p->ai_next) {
if ((sock = socket(p->ai_family, p->ai_socktype,
p->ai_protocol)) == -1) {
perror("Error when creating socket");
continue;
}
break;
}
if (p == NULL) {
fprintf(stderr, "Client failed to create socket\n");
return 2;
}
char s[INET_ADDRSTRLEN];
inet_ntop(AF_INET,(struct sockaddr_in *)p->ai_addr,s, sizeof s);
printf("sending to %s....\n",s);
if ((numbytes = sendto(sock, argv[2], strlen(argv[2]), 0,
p->ai_addr, p->ai_addrlen)) == -1) {
perror("Error sending message");
exit(1);
}
printf("client sent %d bytes to %s\n", numbytes, argv[1]);
freeaddrinfo(server_info);
close(sock);
return 0;
}
The lines I am particularly stuck on is:
char s[INET_ADDRSTRLEN];
inet_ntop(AF_INET,(struct sockaddr_in *)p->ai_addr,s, sizeof s);
printf("sending to %s....\n",s);
For example I run the program with ./client www.google.com hello and get the following:
sending to 2.0.19.86....
client sent 5 bytes to www.google.com
I run the program again with ./client localhost hello and inet_ntop still returns the same IP.
sending to 2.0.19.86....
client sent 5 bytes to localhost
No errors are being thrown when I am creating the socket, and the message sends successfully when I send it to the receiving program over localhost, why is inet_ntop still outputting this weird address?
In your call to inet_ntop:
inet_ntop(AF_INET,(struct sockaddr_in *)p->ai_addr,s, sizeof s);
You're not passing in the correct structure. When AF_INET is passed as the first argument, the second argument should have type struct in_addr *, not struct sockaddr_in *.
You need to call out the sin_addr member which is of this type.
inet_ntop(AF_INET, &((struct sockaddr_in *)p->ai_addr)->sin_addr, s, sizeof s);
Related
this maybe is a simple question but I'm trying to just read a server response using the sockets API adapting the code from Geeks for Geeks [site]1, when I try to read the data, it becomes blocked forever in the valread = read(server_fd, buffer, 2048); line, and doesn't execute any of the prints. Am I doing something wrong?
#include <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
#include <errno.h>
int send_request() {
int server_fd, new_socket, valread;
struct sockaddr_in address;
int opt = 1;
int addrlen = sizeof(address);
char buffer[512] = {0};
char *hello = "Hello from server";
// Creating socket file descriptor
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
perror("socket failed");
exit(EXIT_FAILURE);
}
// Forcefully attaching socket to the port 8080
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {
perror("setsockopt");
exit(EXIT_FAILURE);
}
// CONNECT TO HOST
struct hostent *he;
char* host = "www.columbia.edu";
he = gethostbyname(host);
if(!he) {
printf("Host doesn't exist!\n");
return 0;
}
address.sin_family = AF_INET;
bcopy(he->h_addr, &address.sin_addr, sizeof(struct in_addr));
address.sin_port = htons(80);
if(connect(server_fd, (struct sockaddr *) &address, sizeof(struct sockaddr_in)) < 0) {
printf("Error in the connection");
return 0;
}
valread = read(server_fd, buffer, 2048);
printf("%s\n", buffer);
printf("%d\n", valread);
printf("%d\n", errno);
return 0;
}
int main(int argc, char const *argv[]) {
send_request();
return 0;
}
You are connecting to an HTTP server. The HTTP protocol specifies that the client (that is, the side that makes the connection to the server) must send a request first. You aren't sending a request, so the server is not going to send you a reply.
Also, this is a bug:
valread = read(server_fd, buffer, 2048);
printf("%s\n", buffer);
The %s format specifier can only be used with C-style strings. It can't be used for arbitrary data. For one thing, how would it know how many bytes to output? The only place that information is currently contained is in valread, and you didn't pass it to printf.
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'm trying to access the website https://www.000webhost.com with C sockets:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main(int argc, char** argv) {
struct sockaddr_in servaddr;
struct hostent *hp;
int sock_id;
char message[1024*1024];
char request[] = "GET / HTTP/1.1\n" "From: ...\n";
//get a socket
if((sock_id = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
fprintf(stderr,"Couldn't get a socket.\n");
exit(EXIT_FAILURE);
}else {
fprintf(stderr,"Got a socket.\n");
}
memset(&servaddr,0,sizeof(servaddr));
//get address
if((hp = gethostbyname("000webhost.com")) == NULL) {
fprintf(stderr,"Couldn't get an address.\n");
exit(EXIT_FAILURE);
}else {
fprintf(stderr,"Got an address.\n");
}
memcpy((char *)&servaddr.sin_addr.s_addr, (char *)hp->h_addr, hp->h_length);
//port number and type
servaddr.sin_port = htons(80);
servaddr.sin_family = AF_INET;
//connect
if(connect(sock_id, (struct sockaddr *)&servaddr, sizeof(servaddr)) != 0) {
fprintf(stderr, "Couldn't connect.\n");
}else {
fprintf(stderr,"Got a connection.\n");
}
//request
write(sock_id,request,strlen(request));
//response
read(sock_id,message,1024*1024);
fprintf(stdout,"%s",message);
return 0;
}
If I change the request[] array from "GET / HTTP/1.1\n" "From: ...\n" to "GET / HTTP/1.1\n" "Host: https://www.000webhost.com" "From: ...\n" (therefore removing the direct-IP adress from the request), I still get the error Error 1003. Direct IP access not allowed. Is there some other part of the request that I need to modify? What else do I need to do?
Your request is malformed:
Each line needs to be terminated by \r\n, not just \n. (Some web servers will let you get away with \n, but I have no idea whether that'll work on 000webhost.)
Every header needs a \r\n after it. The modified code you mention in the last paragraph is missing a \r\n at the end of the Host header.
The Host header needs to just be a hostname (e.g, "Host: example.com"). Don't include http://.
I am writing a simple illustrative UDP server client. Server should, based on the client input calculate client's network byte order, and send it back to client. I've been trying to fix this error for whole day now. Any help would be apprecciated. Here is the server start and output:
./udpserver.out 4545
from.sin_family: 12079
Little Endian
ERROR UDP_SRV_004 - can not send message to client: Address family not supported by protocol
Client start:
./udpclient.out localhost 4545
Server code:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <strings.h>
#include <string.h>
#include <netinet/in.h>
#define BUFFER_SIZE 80
static void error(char *msg){
perror(msg);
exit(1);
}
int main(int argc, char ** argv){
int socketfd, portno, fromlen, n, length;
struct sockaddr_in server, from;
char buffer[BUFFER_SIZE];
char response[BUFFER_SIZE];
const char *le = "Little Endian\n";
const char *be = "Big Endian\n";
const char *unk = "Unknown \n";
int cli_family;
if(argc!=2){
fprintf(stderr,"Error starting the client, please start server as: %s port\n", argv[0]);
exit(0);
}
if((socketfd=socket(AF_INET,SOCK_DGRAM,0))<0)
error("ERROR UDP_SRV_001 - can not create socket");
portno=atoi(argv[1]);
bzero(&server,sizeof(server));
server.sin_family=AF_INET;
server.sin_addr.s_addr=INADDR_ANY;
server.sin_port=htons(portno);
if(bind(socketfd,(struct sockaddr *)&server,sizeof(server))<0)
error("ERROR UDP_SRV_002 - can not bind server address to a socket file descriptor");
bzero(buffer, BUFFER_SIZE);
bzero(response,BUFFER_SIZE);
n=recvfrom(socketfd,buffer,BUFFER_SIZE-1,0,(struct sockaddr *)&from,&fromlen);
if (n<0)
error("ERROR UDP_SRV_003 - can not receive client's message");
cli_family=from.sin_family;
printf("from.sin_family: %d\n", cli_family);
if (buffer[0] == 1 && buffer[1] == 2)
strcpy(response, be);
else if (buffer[0] == 2 && buffer[1] == 1)
strcpy(response, le);
else
strcpy(response, unk);
length=strlen(response);
printf("%s\n",response);
n=sendto(socketfd,response,length,0,(struct sockaddr *)&from,fromlen);
if(n<0)
error("ERROR UDP_SRV_004 - can not send message to client");
return 0;
}
Client code:
#include <stdio.h>
#include <sys/types.h>
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <strings.h>
#include <string.h>
#include <unistd.h>
#define BUFFER_SIZE 80
static void error(char *msg){
perror(msg);
exit(1);
}
typedef union UNIT{
short s;
char c[sizeof(short)];
}unit;
int main(int argc, char ** argv){
int socketfd, portno, n, length;
struct sockaddr_in server, from;
struct hostent *host;
char buffer[BUFFER_SIZE];
unit un;
un.s=0x0102;
if(argc!=3){
fprintf(stderr,"Error starting the client, please start client as: %s hostname port\n", argv[0]);
exit(0);
}
if((host=gethostbyname(argv[1]))==NULL)
error("ERROR UDP_CLI_001 - no such host defined, please check your /etc/hosts file");
portno=atoi(argv[2]);
if((socketfd=socket(AF_INET,SOCK_DGRAM,0))<0)
error("ERROR UDP_CLI_002 - can not create socket");
bzero((char *)&server,sizeof(server));
server.sin_family=AF_INET;
server.sin_port=htons(portno);
bcopy((char *)host->h_addr,(char *)&server.sin_addr,host->h_length);
length=sizeof(server);
if(sizeof(short)!=2){
exit(0);
}
n=sendto(socketfd,un.c,strlen(un.c),0,(struct sockaddr *)&server,length);
if(n<0)
error("ERROR UDP_CLI_003 - can not send to server");
bzero(buffer,BUFFER_SIZE);
n=recvfrom(socketfd,buffer,BUFFER_SIZE,0,(struct sockaddr *)&from, &length);
if(n<0)
error("ERROR UDP_CLI_004 - can receive from server");
printf("%s",buffer);
return 0;
}
In the server, you failed to initialize fromlen prior to the call to sendto. As a result, from was not populated.
From the man page:
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.
The recvfrom function attempts to read the value of fromlen, but because it is not initialized you invoke undefined behavior.
Initialize fromlen and that will address the issue.
fromlen = sizeof from;
n=recvfrom(socketfd,buffer,BUFFER_SIZE-1,0,(struct sockaddr *)&from,&fromlen);
I have a C function to check a host and its port, when I use FQDN host name, the function return error like: connect() failed: connect time out, but if I use IP address instead, it seems ok, how to fix this?
Thanks.
#include <unistd.h>
#include <string.h>
#include <syslog.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <errno.h>
int is_network_up(char *chkhost, unsigned short chkport) {
int sock;
struct sockaddr_in chksock;
struct hostent *host = NULL;
if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
syslog(LOG_ERR, "socket() creation error: %s", strerror(errno));
return 0;
}
memset(&chksock, 0, sizeof(chksock));
chksock.sin_family = AF_INET;
chksock.sin_port = htons(chkport);
/* get the server address */
if (inet_pton(AF_INET, chkhost, &(chksock.sin_addr.s_addr)) <= 0) {
if ((host = gethostbyname(chkhost)) == NULL) {
syslog(LOG_ERR, "%s", hstrerror(h_errno));
return 0;
}
memcpy(&(chksock.sin_addr.s_addr), &(host->h_addr_list[0]),
sizeof(struct in_addr));
}
/* try to connect */
if (connect(sock, (struct sockaddr *) &chksock, sizeof(chksock)) < 0) {
syslog(LOG_ERR, "connect() failed: %s", strerror(errno));
return 0;
}
close(sock);
return 1;
}
inet_pton() is the wrong task for that. It only accepts numerical addresses.
In former times, people used to use gethostbyname() for name resolution.
But as we have 2012 meanwhile, this method is outdated for several years now, as it is still restricted to AF_INET.
With the program below, you should achieve about the same and stay future compatible.
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdlib.h>
#include <stdio.h>
int is_network_up(char *chkhost, unsigned short chkport) {
int sock = -1;
struct addrinfo * res, *rp;
int ret = 0;
char sport[10];
snprintf(sport, sizeof sport, "%d", chkport);
struct addrinfo hints = { .ai_socktype=SOCK_STREAM };
if (getaddrinfo(chkhost, sport, &hints, &res)) {
perror("gai");
return 0;
}
for (rp = res; rp && !ret; rp = rp->ai_next) {
sock = socket(rp->ai_family, rp->ai_socktype,
rp->ai_protocol);
if (sock == -1) continue;
if (connect(sock, rp->ai_addr, rp->ai_addrlen) != -1) {
char node[200], service[100];
getnameinfo(res->ai_addr, res->ai_addrlen, node, sizeof node, service, sizeof
service, NI_NUMERICHOST);
printf("Success on %s, %s\n", node, service);
ret = 1; /* Success */
}
close(sock);
}
freeaddrinfo(res);
return ret;
}
int main(int argc, char** argv) {
if (argc > 1) {
printf("%s: %d\n", argv[1], is_network_up(argv[1], 22));
}
}
Make sure name resolution is working. See if you can ping the machine by name from the exact same environment in which your code runs.
If ping works, try telnet <machinename> <portnumber> -- If both of those work it is likely a problem with your code (which I did not look at in depth, too sleepy:).
Make sure you're converting anything returned by the OS as an ip address from network order to host order. IIRC, gethostbyname returns binary ip addresses in network order.
ntohl can be used on chksock.sin_addr.s_addr after the memcpy to achieve this.