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.
Related
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 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.
I know that this is obviously elementary question and I know that there are many tutorials and ready-to-go examples but I must missing something. I am trying to send for example text (char *) via UDP socket to other machine in local network. So far I tried some tutorials like http://gafferongames.com/networking-for-game-programmers/sending-and-receiving-packets/ and so on but I always get error in bind() function with errno "Cannot assign requested address".
I just have some data in char array and I want to push them via network to another host. Could someone please point me to the right direction? Do I need socket server or client? Do I need to bind the socket to some interface?
This is my playground:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <errno.h>
int handle;
int init_socket()
{
handle = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (handle <= 0)
{
printf("failed to create socket\n");
return 1;
}
printf("sockets successfully initialized\n");
return 0;
}
int main ()
{
unsigned short port = 30000;
char * data = "hovno";
init_socket();
struct sockaddr_in address;
memset((char *) &address, 0, sizeof(address));
address.sin_family = AF_INET;
address.sin_addr.s_addr = inet_addr("192.168.11.129"); // this is address of host which I want to send the socket
address.sin_port = htons(port);
printf("handle: %d\n", handle); // prints number greater than 0 so I assume handle is initialized properly
if (bind(handle, (const struct sockaddr*) &address, sizeof(struct sockaddr_in)) < 0)
{
printf("failed to bind socket (%s)\n", strerror(errno)); // Cannot assign requested address
return 1;
}
int nonBlocking = 1;
if (fcntl(handle, F_SETFL, O_NONBLOCK, nonBlocking) == -1)
{
printf("failed to set non-blocking\n");
return 2;
}
int sent_bytes = sendto(handle, data, strlen(data), 0, (const struct sockaddr*) &address, sizeof(struct sockaddr_in));
if (sent_bytes != strlen(data))
{
printf("failed to send packet\n");
return 3;
}
return 0;
}
bind is called for the local address (one you intend to recv packets to). The IP address must be a local IP address of the machine, or (most frequently) INADDR_ANY.
Normally you don't have to use bind on the client side at all. The system will pick a suitable free port for you automatically.
To specify the remote address for a UDP socket, use sendto, not send.
If you search Google for udp client c code, one of the first results is this one. You can see that the networking part is basically just two calls, socket and sendto.
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.
I am creating a server daemon in c that accepts numerous simultaneous connections, and the clients will be sending data to the server. I currently have each client connection being spawned into a new thread. I am seeing that accept() will sometimes (not always) return the ID of existing connection which (obviously) causes a wide variety of issues, including segmentation faults.
I even turned off the socket option SO_REUSEADDR to make sure that wasn't the case. Whenever a single client makes numerous consecutive calls, everything is fine (conid in my code below increments - 5,6,7,8,9, etc...). But whenever more than one client ties to simultaneously connect, sometimes conid gets duplicated (an example from one run: 5,6,7,7,8,9,10,10,10,11,12,12, ...).
I'm wondering how accept() can return an existing connection?? It would make sense if I was calling accept() within more than one thread, but as you can see below it only exists in the main process thread. On the other hand, I never experienced this issue with select(), so maybe it is an issue with threading??? At this point, I've tried just about everything I can think of, but it's apparent to me I'm just missing something
Edit: edited code to show that mystruct wasn't being free'd in the while loop, and (hopefully) provide more insight.
Edit #2: per request, I have posted the full source of my example.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <stdarg.h>
#include <time.h>
#include <errno.h>
#include <netdb.h>
//this is my test structure
struct mystruct_ {
int id; //only id for testing
};
typedef struct mystruct_ mystruct;
//error logging function
void merr(const char *msg, ...) {
//get the time
time_t t;
time(&t);
//grab this function's arguments
va_list args;
char buf[BUFSIZ];
va_start(args,msg);
//build the message
vsprintf(buf,msg,args);
//output the message
printf(" ERROR :: %s\n",buf);
//that's it!
va_end(args);
}
//this function handles the threads
void *ThreadedFunction(void *arg) {
//get the passed structure
mystruct *test = (mystruct *)arg;
//print conid -- this is where I am seeing the duplicates
printf("my connection id is %d\n",test->id);
// do some stuff, like: pull vars out of mystruct
int nbytes;
char buf[256];
while(1) {
if((nbytes=recv(test->id, buf, sizeof buf, 0)) <= 0) {
//handle break in connection
close(test->id);
} else {
//for this example, just print out data from client to make my point
buf[nbytes] = 0;
printf("%s",buf);
}
}
}
//main just sets up the connections and creates threads
int main(int argc, char *argv[])
{
char *port = "1234";
//get ready for connection
struct sockaddr_storage addr;
socklen_t addrsize = sizeof addr;
struct addrinfo hints, *res, *ai, *p;
int sockfd, conid, rv;
int yes = 1;
//
//load up address structs with getaddrinfo():
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC; // use IPv4 or IPv6, whichever
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE; // fill in my IP for me
if((rv = getaddrinfo(NULL, port, &hints, &ai))!= 0) {
merr("failed to bind port '%s': %s\n",port,gai_strerror(rv));
exit(1);
}
//
//bind the port
for(p=ai; p!=NULL; p=p->ai_next) {
sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
if(sockfd<0) continue;
//setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)); //commented for testing
if(bind(sockfd,p->ai_addr,p->ai_addrlen)<0) { close(sockfd); continue; }
break;
}
//if we don't have p, it means server didn't get bound
if(p==NULL) { merr("failed to bind port '%s' (reason unknown)",port); exit(2); }
freeaddrinfo(ai); //all done with this
//
// listen to the (now bounded) socket:
if(listen(sockfd,10)==-1) { merr("listen; errmsg: \"%s\"",strerror(errno)); exit(3); }
// bind(), listen(), etc... blah blah blah
mystruct test[1024]; //just for testing
printf("Ready and Listening...\n");
while(1) {
conid = accept(sockfd, (struct sockaddr *)&addr, &addrsize);//get a connection
test[conid].id = conid;
pthread_t p;
pthread_create(&p,NULL,ThreadedFunction,&test[conid]); //create new thread
}
}
This is broken:
while(1) {
conid = accept(sockfd, (struct sockaddr *)&addr, &addrsize);//get a connection
test[conid].id = conid;
pthread_t p;
pthread_create(&p,NULL,ThreadedFunction,&test[conid]); //create new thread
}
pthread_t p; declares an opaque handle on the stack which pthread_create will fill in. That handle's lifetime must last until you call pthread_join or pthread_detach.
In this case, the storage for that pthread_t is probably being reused, messing up the passing of the argument to the thread function. At least, that is my guess.
Try calling pthread_detach after pthread_create.
accept returns a file descriptor that my be reused. As your ThreadedFunction never terminates when done with a file descriptor you will get a race condition. So after the close statement put return;