I’m trying to use socket in C on CentOS 6.4.
Following LIST1 is my code.
My code gets hostname from command line and sends datagram to server with UDP successfully.
What I want to know is how to print IP address that getaddrinfo() resolved wiht 192.168.10.1 format.
When I try to print IP address segmentation error happens.
Does anyone know how to fix this code?
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <errno.h>
int
main(int argc,char *argv[]){
int sock;
struct addrinfo hints,*res;
int n;
int err;
if(argc != 2){
fprintf(stderr,"Usage : %s dst \n",argv[0]);
return 1;
}
memset(&hints,0,sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM;
err = getaddrinfo(argv[1],"12345",&hints,&res);
if(err != 0){
perror("getaddrinfo");
printf("getaddrinfo %s\n",strerror(errno));
printf("getaddrinfo : %s \n",gai_strerror(err));
return 1;
}
sock = socket(res->ai_family,res->ai_socktype,0);
if(sock < 0){
perror("socket");
return 1;
const char *ipverstr;
switch (res->ai_family){
case AF_INET:
ipverstr = "IPv4";
break;
case AF_INET6:
ipverstr = "IPv6";
break;
default:
ipverstr = "unknown";
break;
}
printf("ipverstr = %s\n ",ipverstr);
}
n = sendto(sock,"HELLO",5,0,res->ai_addr,res->ai_addrlen);
if(n<1){
perror("sendto");
return 1;
}
struct sockaddr_in *addr;
addr = (struct sockaddr_in *)res->ai_addr;
printf("inet_ntoa(in_addr)sin = %s\n",inet_ntoa((struct in_addr)addr->sin_addr));
printf("############ finish !! #######\n");
close(sock);
freeaddrinfo(res);
return 0;
}
The code misses to include the prototype for inet_ntoa().
The compiler should have told you this.
Do add:
#include <arpa/inet.h>
However the code still compiles as due to the missing protoype for inet_ntoa() it is assumed to return int, whereas it returns a char* which is a pointer, which on a 64bit system is 8 bytes, which is not the same size as int which typically has a size of 4. Due to this mismatch things go terribly wrong and end up in a segmentation violation.
Also please note: inet_ntoa() is to be used for ipv4 addresses only. Verbatim from man inet_ntoa (italics by me):
The inet_ntoa() function converts the Internet host address in, given in network byte order, to a string in IPv4 dotted-decimal notation. The string is returned in a statically allocated buffer, which subsequent calls will
overwrite
To be able to convert both (IPv4 and IPv6) struct sockaddr_XYZ's binary addresses to a char[] use inet_ntop().
The counterpart of getaddrinfo() is getnameinfo(). This turns a struct sockaddr into a string.
Related
Please help me! I need to translate (or convert) domain names (for example google.com) to IP address. For that purpose I have found code on interet, which work perfectly, but I don't understand, why there is called function inet_ntop() two times. Please help me. Here is code:
/*
* getaddrinfo.c - Simple example of using getaddrinfo(3) function.
*
* Michal Ludvig <michal#logix.cz> (c) 2002, 2003
* http://www.logix.cz/michal/devel/
*
* License: public domain.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
int
lookup_host (const char *host)
{
struct addrinfo hints, *res;
int errcode;
char addrstr[100];
void *ptr;
memset (&hints, 0, sizeof (hints));
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags |= AI_CANONNAME;
errcode = getaddrinfo (host, NULL, &hints, &res);
if (errcode != 0)
{
perror ("getaddrinfo");
return -1;
}
printf ("Host: %s\n", host);
while (res)
{
inet_ntop (res->ai_family, res->ai_addr->sa_data, addrstr, 100);
switch (res->ai_family)
{
case AF_INET:
ptr = &((struct sockaddr_in *) res->ai_addr)->sin_addr;
break;
case AF_INET6:
ptr = &((struct sockaddr_in6 *) res->ai_addr)->sin6_addr;
break;
}
inet_ntop (res->ai_family, ptr, addrstr, 100);
printf ("IPv%d address: %s (%s)\n", res->ai_family == PF_INET6 ? 6 : 4,
addrstr, res->ai_canonname);
res = res->ai_next;
}
return 0;
}
int
main (int argc, char *argv[])
{
if (argc < 2)
exit (1);
return lookup_host (argv[1]);
}
My question is - why there is function inet_ntop() used twice? I thought, that the first calling give you IP address...but why you need the second calling?
Thanks!
The first call to inet_ntop isn't doing anything useful here. What it writes to addrstr is overwritten on the following call.
The author either didn't understand why they were calling it twice or left in test code they shouldn't have.
I'm either very tired and not noticing something simple , or this is completely screwing with me. I'm getting a segmentation fault ( core dumped ) and I've managed to pinpoint it to the sendto() in the worker function. (in the server)
Server code:
//UDPServer.c
/*
* gcc -o server UDPServer.c
* ./server <port> <buffersize>
*/
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
void err(char *str)
{
perror(str);
exit(1);
}
int sock;
typedef struct
{
struct sockaddr_in client;
int buffsize;
char *msg;
} data;
void *worker (void* asd)
{
int len;
FILE *fp;
data d;
d = *(data*) asd;
char buff[d.buffsize];
printf("Received packet from %s:%d\nData:%sSize:%d\n",
inet_ntoa(d.client.sin_addr), ntohs(d.client.sin_port)
,d.msg,d.buffsize);
char * fn;
memcpy (fn,d.msg,strlen(d.msg)-1);
fp = fopen(fn,"rb");
int bytes;
len = sizeof(d.client);
printf ("%d\n",len);
while (bytes=fread(buff,sizeof(char),d.buffsize,fp))
{
printf ("Server sent %d bytes.\n",bytes);
-> this if right here. this causes the core dump when attempting to send
if(sendto(sock , &buff , sizeof(buff),0,(struct sockaddr *)&d.client,len)<0)
err("Error sending.");
}
fclose(fp);
}
int main(int argc, char** argv)
{
struct sockaddr_in server, client;
int port, i;
socklen_t slen=sizeof(client);
if(argc != 3)
{
printf("Usage: <Port> <Bytes>\n");
exit(0);
}
else
sscanf(argv[1],"%d",&port);
int buffsize = atoi(argv[2]);
char buff[buffsize];
if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1)
err("socket");
else
printf("Server : Socket() successful\n");
bzero(&server, sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(port);
server.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(sock, (struct sockaddr* ) &server, sizeof(server))==-1)
err("bind");
else
printf("Server : bind() successful\n");
while(1)
{
memset(&buff,0,sizeof(buff));
if (recvfrom(sock, &buff, sizeof(buff), 0, (struct sockaddr*)&client, &slen)==-1)
err("recvfrom()");
data d;
d.client = client;
d.buffsize = buffsize;
d.msg = buff;
pthread_t t;
pthread_create(&t,NULL,worker,&d);
pthread_join(t,NULL);
}
return 0;
}
I don't think the client is relevant here since it's only job is to send the filename. The read works btw , I've tested.
Anyway , I'm just trying to send the content of the file for the moment.I've been trying to figure this out for the past hour and for the life of me I can't find out what's it's problem. The segmentation fault makes no sense to me.
Any suggestions are greatly appreciated.
I'd be nervous about the sizeof(buff) in the sendto. buff's size is fixed at runtime based on the argument. But sizeof is a compile-time operation. (Or at least it was back in the good old days - I'm not sure about C99) Oh, nevermind - I see that has changed
Still, why not use d.buffsize there instead? Or maybe bytes, since you might not have filled the buffer.
Although #21Zoo is wrong about dynamic arrays in C99, I think he found the root problem
char * fn;
memcpy (fn,d.msg,strlen(d.msg)-1);
fn has no memory allocated to copy into, so you are writing to a random point in memory.
Something in the sendto is probably stumbling over that memory which now contains garbage.
You either need to malloc(strlen(d.msg)+1) or use strdup instead.
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.
Hi I am trying to make a simple server that takes in an IP address from getaddrinfo() and binds to it. Using ifconfig, I've found that I have an ip address of wlan0 192.168.2.10 which I would like to bind to. Unfortunately the address I seem to be binding to is my lo device. For some reason when I initialize getaddrinfo("192.168.2.10","3490",&hings,&res); res gets returned to a NULL pointer. I will show off my code bellow.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <signal.h>
#define MAXDATASIZE 500;
int main(int argc, char *argv[]){
// dealing with client socket
struct sockaddr_storage their_addr;
socklen_t addr_size;
// server socket
struct addrinfo serverSide,*serverInfo,*sortIP;
int optValRet;
int listenSock, newSock;
// this is for reading in information
char buf[501];
char point[INET6_ADDRSTRLEN];
char compare[INET6_ADDRSTRLEN] = "192.168.2.10";
// this is for handeling child processes and signals
struct sigaction sa;
sa.sa_handler = NULL;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
if(sigaction(SIGCHLD, &sa, NULL) == -1){
printf("We have a problem, sigaction is not working.\n");
perror("\n");
exit(1);
}
// this sets up addrinfo
memset(&serverSide, 0, sizeof serverSide);
serverSide.ai_family = AF_UNSPEC;
serverSide.ai_socktype = SOCK_STREAM;
serverSide.ai_flags = INADDR_ANY;
// set up the address
if(getaddrinfo("192.168.2.10","3490",&serverSide,&serverInfo)!=0){
printf("get addr not success\n");
perror("\n");
return 1;
}
printf("Got address lists\n");
for(sortIP = serverInfo; sortIP = sortIP->ai_next; sortIP != NULL){
if((listenSock = socket(sortIP->ai_family, sortIP->ai_socktype, sortIP->ai_protocol))==-1){
continue;
}
if(setsockopt(listenSock,SOL_SOCKET,SO_REUSEADDR,&optValRet,sizeof(int))==-1){
perror("\n");
exit(1);
}
if(bind(listenSock,sortIP->ai_addr,sortIP->ai_addrlen) == -1 ){
perror("\n");
close(listenSock);
continue;
}
break;
}
if(sortIP == NULL){printf("sort ip is null.");}
inet_ntop(sortIP->ai_family,sortIP->ai_addr,point,sizeof point);
printf("Tell the clients connect to ip address %s on port 3490\n",point);
listen(listenSock, 10);
addr_size = sizeof their_addr;
newSock = accept(listenSock,(struct sockaddr *)&their_addr,&addr_size);
recv(newSock, buf, 500, 0);
printf("%s\n",buf);
close(listenSock);
close(newSock);
freeaddrinfo(serverInfo);
return 0;
}
Now I have some other questions beside the fact that I'm returning null. Since the wifi router has assigned me the ip address 192.168.2.10 for my subnet, how do I find out what my ip address is if I'm outside the network and trying to contact my server? I'm assuming the inside network ip is different from the outside network ip ... am I wrong? Anyways those are my two questions.
Thanks for any help!
This is wrong and is your immediate problem:
for (sortIP = serverInfo; sortIP = sortIP->ai_next; sortIP != NULL)
You want something like:
for (sortIP = serverInfo; sortIP != NULL; sortIP = sortIP->ai_next)
but I would go with a while loop personally.
To your main question, you should just bind to INADDR_ANY. That avoids that whole mess. Also:
recv(newSock, buf, 500, 0);
printf("%s\n",buf);
The %s format specifier is only for C-style strings, it's not for arbitrary binary data. Also, you throw away the return value from recv. There is no other way to know how many bytes you received.
As for finding your dynamic IP address from outside your network, use any of the dozens of IP posting services that assign you a host name and map it to your dynamic IP address.
I have a program where an external component passes me a string which contains an IP address. I then need to turn it into a URI. For IPv4 this is easy; I prepend http:// and append /. However, for IPv6 I need to also surround it in brackets [].
Is there a standard sockets API call to determine the address family of the address?
Kind of. You could use inet_pton() to try parsing the string first as an IPv4 (AF_INET) then IPv6 (AF_INET6). The return code will let you know if the function succeeded, and the string thus contains an address of the attempted type.
For example:
#include <arpa/inet.h>
#include <stdio.h>
static int
ip_version(const char *src) {
char buf[16];
if (inet_pton(AF_INET, src, buf)) {
return 4;
} else if (inet_pton(AF_INET6, src, buf)) {
return 6;
}
return -1;
}
int
main(int argc, char *argv[]) {
for (int i = 1; i < argc; ++i) {
printf("%s\t%d\n", argv[i], ip_version(argv[i]));
}
return 0;
}
Use getaddrinfo() and set the hint flag AI_NUMERICHOST, family to AF_UNSPEC, upon successfull return from getaddrinfo, the resulting struct addrinfo .ai_family member will be either AF_INET or AF_INET6.
EDIT, small example
#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netdb.h>
int main(int argc, char *argv[])
{
struct addrinfo hint, *res = NULL;
int ret;
memset(&hint, '\0', sizeof hint);
hint.ai_family = PF_UNSPEC;
hint.ai_flags = AI_NUMERICHOST;
ret = getaddrinfo(argv[1], NULL, &hint, &res);
if (ret) {
puts("Invalid address");
puts(gai_strerror(ret));
return 1;
}
if(res->ai_family == AF_INET) {
printf("%s is an ipv4 address\n",argv[1]);
} else if (res->ai_family == AF_INET6) {
printf("%s is an ipv6 address\n",argv[1]);
} else {
printf("%s is an is unknown address format %d\n",argv[1],res->ai_family);
}
freeaddrinfo(res);
return 0;
}
$ ./a.out 127.0.0.1
127.0.0.1 is an ipv4 address
$ ./a.out ff01::01
ff01::01 is an ipv6 address