Google Answers Logo
View Question
 
Q: How can I get the ip of a machine that connect to my machine(daemon) ( Answered 4 out of 5 stars,   0 Comments )
Question  
Subject: How can I get the ip of a machine that connect to my machine(daemon)
Category: Computers > Programming
Asked by: adamhsu-ga
List Price: $20.00
Posted: 12 Sep 2003 01:45 PDT
Expires: 12 Oct 2003 01:45 PDT
Question ID: 254937
I have write some socket program at Unix(sun-solaris). 
With the socket-api "getpeername", 
I can get the IP of a machine that connect to my machine. 
Now,I must write a daemon program at Unix(sun-solaris). 
I can get the information that the client send to my machine. 
But,how can I get the IP that connect to my machine at my daemon-program??? 
I provide an sample code,I wish my answer can write some code in my program. 
Let me know how can I get the IP of a machine that connect to my machine  
and let me see and check the answer is correct. 
Thanks...... 
// daemon sample code 
#include <stdio.h> 
#include <string.h> 
#include <strings.h> 
#include <stdlib.h> 
int main(void) 
{ 
 char ap_command[1024]; 
 memset(ap_command,'\0',1024);  
 setvbuf(stdout,NULL,_IOLBF,0);  
 /////////////////////////////////////////// 
 // How can I get the IP-address of a machine  
 // that connect to my machine.  
 ///////////////////////////////////////////   
 while(fgets(ap_command,sizeof(ap_command),stdin) != NULL) 
 { 
  printf("ECHO:%s\n\r",ap_command); 
  memset(ap_command,'\0',1024); 
 } 
 return(0); 
}

Request for Question Clarification by maniac-ga on 12 Sep 2003 05:21 PDT
Hello Adamhsu,

Hmm. From what you said, it appears that when this sample code runs,
it is reading the data from stdin - which I assume is already bound to
a socket connected to a remote machine. Please confirm that is
correct.

If correct, it may be as simple as calling
  retval = getpeername(stdin, name, namelen);
Do you need help writing that function call or do you need sample code
that confirms that the method works?

If not correct, you will need to describe the setup a little more
clearly so we can suggest some approaches to use.

  --Maniac

Clarification of Question by adamhsu-ga on 13 Sep 2003 00:40 PDT
I am happy to receive your response...
After I think what you say, I find the stdin is the standard input.
It is an kind of file.
It can't convert it to a socket type(int).
An daemon program not need handle the socket,
because O.S has handle it...(I think)
...Now,Let us think my sample code.
My sample is a small daemon-code.
It is a echo program.
After compile it,and set inetd.conf & services.
If I send "Hello World",It will send "ECHO:Hello World" to me.
From my code,we can't see any socket-api.
But the sample can do the work about "ECHO".
We know "socket" do the transmission between client and my sample.
And the system know anything about the socket.But we can't see it.
The socket also have the ip-address.
Now,my question is to get the ip of a client.
thanks...and god bless you have a good day
Answer  
Subject: Re: How can I get the ip of a machine that connect to my machine(daemon)
Answered By: maniac-ga on 15 Sep 2003 17:34 PDT
Rated:4 out of 5 stars
 
Hello Adamhsu,

Your clarification provided enough information to answer your original
question. The answer is in four parts - updated source code,
explanation of the updates, sample output, and additional comments on
finding information about this topic.

Updated Source Code
======= ====== ====

// daemon sample code  
#include <stdio.h>  
#include <string.h>  
#include <strings.h>  
#include <stdlib.h>  
#include <sys/socket.h>
#include <netinet/in.h>

struct sockaddr_in mysock;
int namelen;

int main(void)  
{  
 char ap_command[1024];  
 int errcode;
 char myname[]="mydaemon";

 namelen = sizeof(struct sockaddr_in);
 if (getpeername(0, (struct sockaddr *)&mysock, &namelen)) {
   fprintf(stderr, "%s : Failed to get peer name\n", myname);
   perror(myname);
 }
 else
   fprintf(stdout, "IP is %d.%d.%d.%d\n",
	   (mysock.sin_addr.s_addr>>24) & 255,
	   (mysock.sin_addr.s_addr>>16) & 255,
	   (mysock.sin_addr.s_addr>>8) & 255,
	   mysock.sin_addr.s_addr & 255);
   
 
 memset(ap_command,'\0',1024);   
 setvbuf(stdout,NULL,_IOLBF,0);   
 while(fgets(ap_command,sizeof(ap_command),stdin) != NULL)  
 {  
  printf("ECHO:%s\n\r",ap_command);  
  memset(ap_command,'\0',1024);  
 }  
 return(0);  
}

Explanations
============

The explanations have the following pattern
 - added source code
 - explanation of that source code

---

#include <sys/socket.h>
#include <netinet/in.h>

struct sockaddr_in mysock;
int namelen;

The header files are needed to define the functions and data types
used in the added source code. The two declarations (mysock, namelen)
define two of the three parameters passed to getpeername (I will
describe the third later).

---

 char myname[]="mydaemon";

 namelen = sizeof(struct sockaddr_in);
 if (getpeername(0, (struct sockaddr *)&mysock, &namelen)) {
   fprintf(stderr, "%s : Failed to get peer name\n", myname);
   perror(myname);
 }
 else
   fprintf(stdout, "IP is %d.%d.%d.%d\n",
	   (mysock.sin_addr.s_addr>>24) & 255,
	   (mysock.sin_addr.s_addr>>16) & 255,
	   (mysock.sin_addr.s_addr>>8) & 255,
	   mysock.sin_addr.s_addr & 255);
   
This is the added code that basically takes the place of the block
comment in your original main function. Getpeername is called using
file 0 (stdin) as its first parameter. This is because inetd connects
I/O to the server process to the socket. If this call fails, an error
message is printed. If the  call succeeds, the IP address is printed
with the "fprintf" call.

Sample Output
====== ======

I tested the sample program using the telnet application after setting
it up as you described. The following is the output from running both
the daemon and the telnet program on the same computer. Port 9999 was
the port number I chose to connect to the daemon.

telnet -e ! localhost 9999
Telnet escape character is '!'.
Trying 127.0.0.1...
Connected to localhost.
Escape character is '!'.
IP is 127.0.0.1
Hello
ECHO:Hello

Goodbye
ECHO:Goodbye

!
telnet> quit
Connection closed.

This demonstrates the output of both the IP address and your original
echo output.

Other Comments
===== ========

The first reference used were the "man pages" available on Unix. For
example,
  man getpeername
describes how to call the getpeername function. In particular it notes
that you need to add
  #include <sys/socket.h>
to the list of header files, that it returns 0 on success (or -1 on
error), and it takes three parameters and how they are used.

The next reference is more difficult to describe. The second parameter
(sockaddr) has a number of different definitions - depending on the
type of network connection. Based on what you said in the
clarification - I knew that you are using "Internet Protocols" so I
used
  man ip
and then
  man 4 inet
to find out if additional header files are needed. That lead me to add
  #include <netinet/in.h>
to the list of header files. The inet man page describes the use of
sockaddr_in for addresses. That is why
  struct sockaddr_in mysock;
is used instead of
  struct sockaddr mysock;

The use of sizeof is based on information from the book "The C
Programming Language" where it describes how to use it to get the size
of an object (in this case - the size of mysock). You should be able
to look this up in any good C language book. As an alternative, search
with Google for
  C language "size of" object operator
to get pages describing sizeof.

The second and third parameters to getpeername require an address (not
a value) for the parameters. The use of & (address of) operator is
used to generate the addresses to the variables mysock and namelen.
Also note that the types sockaddr and sockaddr_in are not strictly
compatible so you should include the type cast. This is why the phrase
(struct sockaddr *) is included in the call to getpeername.

The statements added if getpeername returns a non-zero value are
strictly for error reporting. Both fprintf(stderr, ...) and perror()
are used for that purpose.

The ugly looking code in the pattern
	   (mysock.sin_addr.s_addr>>##) & 255,
basically chops the IP address into four bytes to print the address in
dotted decimal format. The IP address is a 32 bit integer - that is
why this works.

For some additional references, I suggest viewing
  http://www.scit.wlv.ac.uk/~jphb/comms/sockets.example.html
which has some good sample code. Note the call to getpeername and
another way to print the dotted IP address.

You can also search using phrases such as
  C source code getpeername
  getpeername example code
and others.

  --Maniac

Request for Answer Clarification by adamhsu-ga on 19 Sep 2003 01:28 PDT
I am happy to get your response...

After I try your sample code...
I telnet 127.0.0.1 at port = 9999.
I always get the message => "IP is 0.0.0.0".
I can't get a message like "IP is 127.0.0.1".  
After I try the following statement
"fprintf(stdout, "IP is %s\n", inet_ntoa(mysock.sin_addr); "
I still get "IP is 0.0.0.0".
---------------------------------------------------------------
After read the maniac-ga's answer.
I consider the following things...
1. inetd call accept and then return the socket's descriptor and the
ip-address of the peer.
2. then call fork and create the child-process of the inetd. Since the
child-process can see his father's socket,so the child-process also
can use the socket's descriptor .
3. when the child-process call exec to run the real server.The memory
of the real server's process will replace the memory of the
child-process.he sockethe server process to tNow,we lose the
ip-address of the peer.But the socket that have connected alaways open
after exec.

If my concept is correct , then how can I get the socket
descriptor.....
Myabe the answers have other ideas can solve my problem to get what I
want...

AdamHsu

Request for Answer Clarification by adamhsu-ga on 19 Sep 2003 01:36 PDT
...The first request have some error,I fix it...
I am happy to get your response... 
 
After I try your sample code... 
I telnet 127.0.0.1 at port = 9999. 
I always get the message => "IP is 0.0.0.0". 
I can't get a message like "IP is 127.0.0.1".   
After I try the following statement 
"fprintf(stdout, "IP is %s\n", inet_ntoa(mysock.sin_addr); " 
I still get "IP is 0.0.0.0". 
--------------------------------------------------------------- 
After read the maniac-ga's answer. 
I consider the following things... 
1. inetd call accept and then return the socket's descriptor and the
ip-address of the peer.
2. then call fork and create the child-process of the inetd. Since the
child-process can see his father's socket,so the child-process also
can use the socket's descriptor .
3. when the child-process call exec to run the real server.The memory
of the real server's process will replace the memory of the
child-process.Now,we lose the ip-address of the peer.But the socket
that have connected alaways open.
 
If my concept is correct , then how can I get the socket
descriptor.....
Myabe the answers have other ideas can solve my problem to get what I
want...
 
AdamHsu

Clarification of Answer by maniac-ga on 19 Sep 2003 05:21 PDT
Hello Adamhsu,

When you exec the daemon, the file associations (stdin, stdout,
stderr) should not change. For reference
  http://docs.sun.com/db/doc/805-8068/6j7j9178p?a=view
the explanation of file descriptions is about a third to half way
down. There is a comment about "close on exec" but that should not
apply in this case (since I/O does work).

A few other possibilities to check
 - add a printf statement to display the value of namelen before and
after the call to getpeername. This is unlikely, but if zero or too
small, the address won't be written to mysock.
 - what is the command line you use to build the daemon application?
From
  http://docs.sun.com/db/doc/817-0665/6mgetsveb?q=getpeername&a=view
you need both -lsocket and -lnsl on the command line to use it
properly. There is also another function with the same name,
referenced by using -lxnet.
 - which version of Solaris are you using? There were some bugs with
older versions with getpeername. I can certainly do more research if
needed based on your answer.

  --Maniac

Request for Answer Clarification by adamhsu-ga on 02 Oct 2003 03:25 PDT
Dear maniac-ga

  I have try again with you suggestion.
  But I still can't get what I want.

  I use SunOS 5.8
  I use the following code.
  I use two ways to make the file.
  One is -socket -nsl
  One is -xnet
  But I get the same result......
  
  // daemon sample code   
  #include <stdio.h>   
  #include <string.h>   
  #include <strings.h>   
  #include <stdlib.h>   
  #include <sys/socket.h> 
  #include <netinet/in.h> 
 
  struct sockaddr_in mysock; 
  socklen_t namelen; 
 
  int main(void)   
  {   
   char ap_command[1024];   
   int errcode; 
   char myname[]="mydaemon"; 
   
   namelen = sizeof(struct sockaddr_in); 
   setvbuf(stdout,NULL,_IOLBF,0); 
   printf("namelen 1 => %d\n\r",namelen);
   if (getpeername(0, (struct sockaddr *)&mysock, &namelen)) 
   {    
     printf("namelen 2 => %d\n\r",namelen);
     printf("%s : Failed to get peer name\n", myname); 
     perror(myname); 
   } 
   else 
   {
     printf("namelen 3 => %d\n\r",namelen);
     printf("IP is %d.%d.%d.%d\n", 
      (mysock.sin_addr.s_addr>>24) & 255, 
      (mysock.sin_addr.s_addr>>16) & 255, 
      (mysock.sin_addr.s_addr>>8) & 255, 
      mysock.sin_addr.s_addr & 255); 
   }
    
   memset(ap_command,'\0',1024);    
   setvbuf(stdout,NULL,_IOLBF,0);    
   while(fgets(ap_command,sizeof(ap_command),stdin) != NULL)   
   {   
    printf("ECHO:%s\n\r",ap_command);   
    memset(ap_command,'\0',1024);   
   }   
   return(0);   
  } 
 
  // result
  // 2900 is my port
  // 192.168.166.11 is the ip of the daemon program
  telnet 192.168.166.11 2900
  Trying 127.0.0.1...
  Connected to localhost.
  Escape character is '^]'.
  namelen 1 => 16
  namelen 3 => 32
  IP is 0.0.0.0

  // I found the namelen (16 -> 32)

  thanks...

AdamHsu

Clarification of Answer by maniac-ga on 02 Oct 2003 05:23 PDT
Hello Adamhsu,

Well - the size of namelen before the call to getpeername is
definitely the problem. You can see this because:
  sizeof(struct sockaddr_in) is 16
which is less than the size of namelen after calling getperrname. This
is very odd and looks like a bug. Try one of the following:

[1] Change 
 namelen = sizeof(struct sockaddr_in);
to
  namelen = sizeof(mysock);
This is based on references such as
  http://www.geocrawler.com/archives/3/342/1998/2/0/1937622/
and
  http://docs.sun.com/db/doc/801-6741/6i13kh8s7?a=view
If this works - there is a bug in the compiler since
  sizeof(struct sockaddr_in) and sizeof(mysock)
should be the same as they are on my system.... Some debug code added
shows
Size of type 16, size of item 16
IP is 127.0.0.1, namelen is 16
which is as I expected.

If the first approach does not work, try
[2] In addition to the above, change 
  struct sockaddr_in mysock;
to
  struct sockaddr mysock;
There are examples for Solaris showing this including:
  http://www.geocrawler.com/archives/3/342/1998/2/0/1937622/
and
  http://www.netsys.com/fwtk/1998/11/msg00122.html

Please let me know how this works for you.

  --Maniac

Request for Answer Clarification by adamhsu-ga on 03 Oct 2003 06:08 PDT
Dear maniac-ga

  I have get the ip....^_^...
  The following code is my sample
  // daemon sample code    
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <stdlib.h>
#include <dirent.h>
#include <unistd.h>
#include <time.h>
#include <fcntl.h>
#include <errno.h>
#include <netdb.h>
#include <signal.h>
#include <semaphore.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/utsname.h>
#include <sys/select.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h> 
  
  struct sockaddr_in mysock;  
  struct sockaddr sa1;
  struct sockaddr_in sa2;
  struct sockaddr sa3;
  struct sockaddr_in sa4;
  int rv, l;
  socklen_t namelen;  
  socklen_t namelen1;
  socklen_t namelen2;
  socklen_t namelen3;
  socklen_t namelen4;
    
  int main(void)    
  {    
   char ap_command[1024];    
   int errcode;  
   char myname[]="mydaemon";  
   setvbuf(stdout,NULL,_IOLBF,0);  
   
   printf("struct-sockaddr_in size is
%d=>%d\n\r",sizeof(sockaddr_in),sizeof(sa4));
   printf("struct-sockaddr size is
%d=>%d\n\r",sizeof(sockaddr),sizeof(sa3));
    
   printf("******case
1***************************************************************\n\r");
   printf("namelen1-1=>%d,sa1 size = %d\n\r",namelen1,sizeof(sa1));
   namelen1 =sizeof(sa1);
   printf("namelen1-2=>%d,sa1 size = %d\n\r",namelen1,sizeof(sa1));
   rv = getpeername(0, &sa1, &namelen1);
   printf("namelen1-3=>%d,sa1 size = %d\n\r",namelen1,sizeof(sa1));
   printf("IP is |%s|\n\r",inet_ntoa(((struct sockaddr_in
*)&sa1)->sin_addr));
   printf("***************************************************************************\n\r");
   
   printf("******case
2***************************************************************\n\r");
   printf("namelen2-1=>%d,sa2 size = %d\n\r",namelen2,sizeof(sa2));
   namelen2 =sizeof(sa2);
   printf("namelen2-2=>%d,sa2 size = %d\n\r",namelen2,sizeof(sa2));
   rv = getpeername(0, (struct sockaddr *)&sa2, &namelen2);
   printf("namelen2-3=>%d,sa2 size = %d\n\r",namelen2,sizeof(sa2));
   printf("IP is |%s|\n\r",inet_ntoa(((struct sockaddr_in
*)&sa2)->sin_addr));
   printf("***************************************************************************\n\r");
   
   printf("******case
3***************************************************************\n\r");
   printf("namelen3-1=>%d,sa3 size = %d\n\r",namelen3,sizeof(sa3));
   namelen3 =sizeof(struct sockaddr);   
   printf("namelen3-2=>%d,sa3 size = %d\n\r",namelen3,sizeof(sa3));
   rv = getpeername(0, (struct sockaddr *)&sa2, &namelen2);
   printf("namelen3-3=>%d,sa3 size = %d\n\r",namelen3,sizeof(sa3));
   printf("IP is |%s|\n\r",inet_ntoa(((struct sockaddr_in
*)&sa3)->sin_addr));
   printf("***************************************************************************\n\r");
   
   printf("******case
4***************************************************************\n\r");
   printf("namelen4-1=>%d,sa4 size = %d\n\r",namelen4,sizeof(sa4));
   namelen4 =sizeof(struct sockaddr_in);   
   printf("namelen4-2=>%d,sa4 size = %d\n\r",namelen4,sizeof(sa4));
   rv = getpeername(0, (struct sockaddr *)&sa4, &namelen4);
   printf("namelen4-3=>%d,sa4 size = %d\n\r",namelen4,sizeof(sa4));
   printf("IP is |%s|\n\r",inet_ntoa(((struct sockaddr_in
*)&sa4)->sin_addr));
   printf("***************************************************************************\n\r");
    
   namelen = sizeof(struct sockaddr_in);  
   setvbuf(stdout,NULL,_IOLBF,0);  
   printf("namelen 1 => %d\n\r",namelen); 
   if (getpeername(0, (struct sockaddr *)&mysock, &namelen))  
   {     
     printf("namelen 2 => %d\n\r",namelen); 
     printf("%s : Failed to get peer name\n", myname);  
     perror(myname);  
   }  
   else  
   { 
     printf("namelen 3 => %d\n\r",namelen); 
     printf("IP is %d.%d.%d.%d\n",  
      (mysock.sin_addr.s_addr>>24) & 255,  
      (mysock.sin_addr.s_addr>>16) & 255,  
      (mysock.sin_addr.s_addr>>8) & 255,  
      mysock.sin_addr.s_addr & 255);  
   } 
     
   return(0);    
  }  

// The following is my result
******case 1***************************************************************
namelen1-1=>0,sa1 size = 16
namelen1-2=>16,sa1 size = 16
namelen1-3=>32,sa1 size = 16
IP is |0.0.0.0|
***************************************************************************
******case 2***************************************************************
namelen2-1=>0,sa2 size = 16
namelen2-2=>16,sa2 size = 16
namelen2-3=>32,sa2 size = 16
IP is |0.0.0.0|
***************************************************************************
******case 3***************************************************************
namelen3-1=>0,sa3 size = 16
namelen3-2=>16,sa3 size = 16
namelen3-3=>16,sa3 size = 16
IP is |192.168.166.11|
***************************************************************************
******case 4***************************************************************
namelen4-1=>0,sa4 size = 16
namelen4-2=>16,sa4 size = 16
namelen4-3=>32,sa4 size = 16
IP is |0.0.0.0|
***************************************************************************
namelen 1 => 16
namelen 3 => 32
IP is 0.0.0.0
Connection closed by foreign host.

...thanks for your good suggestion....
...thanks

AdamHsu

Clarification of Answer by maniac-ga on 03 Oct 2003 10:13 PDT
Hello Adamhsu,

Glad to hear that it *finally* works. What an odd set of conditions to
diagnose on Solaris when it "just works" on other machines. Good luck
on your further work.

  --Maniac
adamhsu-ga rated this answer:4 out of 5 stars
Thanks...
Maybe,the answer is so simple,but I am happy to pay it.
God bless you have a good day...

Comments  
There are no comments at this time.

Important Disclaimer: Answers and comments provided on Google Answers are general information, and are not intended to substitute for informed professional medical, psychiatric, psychological, tax, legal, investment, accounting, or other professional advice. Google does not endorse, and expressly disclaims liability for any product, manufacturer, distributor, service or service provider mentioned or any opinion expressed in answers or comments. Please read carefully the Google Answers Terms of Service.

If you feel that you have found inappropriate content, please let us know by emailing us at answers-support@google.com with the question ID listed above. Thank you.
Search Google Answers for
Google Answers  


Google Home - Answers FAQ - Terms of Service - Privacy Policy