C socket get IP address from filedescriptor returned from accept
Asked Answered
T

4

14

I know this question seems typical and multiple times answered but I think if you read the details it is not so common (I did not find it).

The point is that I am developing a unix service in c that opens a socket and waits for connections, when I have a connection I create a new process to treat it, so there can be multiple connections opened at the same time.

int newfd = accept(sockfd, (struct sockaddr *)&clientaddr, (socklen_t*)&clientaddr_size);

Later on (after and inside some other methods and code) the child process save the connection information to the BBDD and I need also, in that precise moment, to get the IP address that opened that connection being treated.

As there can be multiple connections at the same time and the variable struct sockaddr_in clientaddr that I pass to the accept method is shared for all the process I am not sure that later on is a good idea to get the IP address information from that way because then I could get the IP address from another connection opened.

I would like to be able to access the IP address from the file descriptor int newfd that I get from the accept method (the returned integer). Is it possible? Or I misunderstood the file descriptor function?

Toleration answered 9/12, 2013 at 13:40 Comment(5)
possible duplicate of How to get the ip address of the accepted in-bound socket?Larval
Thanks @Larval I see is so similar, although (for sure because of my english), I didn't need the bind address, I need the client address. Now I have seen the way is similar but with the getpeername() method :)Toleration
Ahok, I see. So you might like to add an answer to you own question, and even accept it.Larval
possible duplicate of Get remote address/IP - C Berkeley SocketsCandytuft
Ok. This one yes @JosephQuinsey, equal and and simpler.. Sorry I didn't find it before...Toleration
T
28

Ok. Thanks to @alk and @rileyberton I found the correct method to use, the getpeername:

int sockfd;

void main(void) {
    //[...]
    struct sockaddr_in clientaddr;
    socklen_t clientaddr_size = sizeof(clientaddr);
    int newfd = accept(sockfd, (struct sockaddr *)&clientaddr, &clientaddr_size);
    //fork() and other code
    foo(newfd);
    //[...]
}
void foo(int newfd) {
    //[...]
    struct sockaddr_in addr;
    socklen_t addr_size = sizeof(struct sockaddr_in);
    int res = getpeername(newfd, (struct sockaddr *)&addr, &addr_size);
    char *clientip = new char[20];
    strcpy(clientip, inet_ntoa(addr.sin_addr));
    //[...]
}

So now in a different process I can get the IP address (in the "string" clientip) of the client that originated the connection only carrying the file descriptor newfd obtained with the accept method.

Toleration answered 9/12, 2013 at 16:17 Comment(2)
Do not declare addr_size as int, but as socklen_t. Casting the int* to socklen_t* in the call to getpeername() hides possible issues in case socklen_t would be of different size then int. Same for the call to accept().Larval
Done! and also I changed it in the call to accept() method. Thank you very much for the suggestion:)Toleration
S
3

You would use getsockname() (http://linux.die.net/man/2/getsockname) to get the IP of the bound socket.

Also answered before, here: C - Public IP from file descriptor

Sulphurbottom answered 9/12, 2013 at 13:44 Comment(3)
Thanks @rileyberton, the correct method it worked for me is getpeername() (linux.die.net/man/2/getpeername) I can see is so similar the post but a little bit confusing the question with so much talk between the processes :PToleration
The IP address of the bound socket is not what he asked for. Read the question.Pains
Is the bound socket after bind or accept functions (bind --> listen --> accept)?Db
M
0

Statefull connection is uniquely identified by two end points Peer(address:port)<=>My(address:port). Both getpeername() and getsockname() are needed to get this information.

Meek answered 17/2, 2020 at 18:44 Comment(1)
Would you put some web link reference to "stateful connection is ...two end points"? Is this for only TCP or UDP as well?Db
U
0

Found this helpful example

This is how I did it

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <time.h> 

int main(int argc, char *argv[])
{
    int listenfd = 0, connfd = 0;
    struct sockaddr_in serv_addr; 
    socklen_t len; 


    char sendBuff[1025];

    time_t ticks; 

    listenfd = socket(AF_INET, SOCK_STREAM, 0);
    memset(&serv_addr, '0', sizeof(serv_addr));
    memset(sendBuff, '0', sizeof(sendBuff)); 

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    serv_addr.sin_port = htons(5000); 

    bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)); 

    listen(listenfd, 10); 

    while(1)
    {
        connfd = accept(listenfd, (struct sockaddr*)NULL, NULL); 

        ticks = time(NULL);
        snprintf(sendBuff, sizeof(sendBuff), "%.24s\r\n", ctime(&ticks));
        printf("%d \n",connfd);
        
        getpeername(connfd, (struct sockaddr*)&serv_addr, &len );
        printf("Peer connected %s:%d\n", inet_ntoa(serv_addr.sin_addr),ntohs(serv_addr.sin_port));

        write(connfd, sendBuff, strlen(sendBuff)); 

        close(connfd);
        sleep(1);
     }
}

Urba answered 11/3, 2022 at 9:32 Comment(1)
What is the purpose of write(connfd, sendBuff, strlen(sendBuff)) code line?Db

© 2022 - 2025 — McMap. All rights reserved.