Need help getting the TCP port number and IP address in C

advertisements

I'm trying to find a way to get my server to print its TCP Port Number and IP address but how I have it right now is producing the wrong IP, I am getting an output of 0.0.33.32. Any help is appreciated!

#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 <netdb.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <signal.h>
#include <time.h>

#define PORT "21467"  // the port users will be connecting to

#define BACKLOG 10   // how many pending connections queue will hold

void sigchld_handler(int s)
{
while(waitpid(-1, NULL, WNOHANG) > 0);
}

// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa)
{
if (sa->sa_family == AF_INET) {
    return &(((struct sockaddr_in*)sa)->sin_addr);
}

return &(((struct sockaddr_in6*)sa)->sin6_addr);
}

int main(void)
{
int sockfd, new_fd;  // listen on sock_fd, new connection on new_fd
struct addrinfo hints, *servinfo, *p;
struct sockaddr_storage their_addr; // connector's address information
socklen_t sin_size;
struct sigaction sa;
int yes=1;
char s[INET6_ADDRSTRLEN];
int rv;

memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE; // use my IP

char hname[100];
gethostname(hname, sizeof hname);

if ((rv = getaddrinfo(hname, PORT, &hints, &servinfo)) != 0) {
    fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
    return 1;
}
// loop through all the results and bind to the first we can
for(p = servinfo; p != NULL; p = p->ai_next) {
    if ((sockfd = socket(p->ai_family, p->ai_socktype,
            p->ai_protocol)) == -1) {
        perror("server: socket");
        continue;
    }

    if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes,
            sizeof(int)) == -1) {
        perror("setsockopt");
        exit(1);
    }

    if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
        close(sockfd);
        perror("server: bind");
        continue;
    }

    break;
}

if (p == NULL)  {
    fprintf(stderr, "server: failed to bind\n");
    return 2;
}

freeaddrinfo(servinfo); // all done with this structure

if (listen(sockfd, BACKLOG) == -1) {
    perror("listen");
    exit(1);
}

sa.sa_handler = sigchld_handler; // reap all dead processes
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
if (sigaction(SIGCHLD, &sa, NULL) == -1) {
    perror("sigaction");
    exit(1);
}

char host[100];
char service[20];

getnameinfo(p->ai_addr, p->ai_addrlen, host, sizeof host, service, sizeof service, 0);
inet_ntop(p->ai_family, get_in_addr((struct sockaddr *)p->ai_addr),
        host, sizeof host);

printf("server: has TCP port number %s and IP address %s\n", service, host); 

printf("server: waiting for connections...\n");

int numbytes;
char buf[100];

while(1) {  // main accept() loop
    sin_size = sizeof their_addr;
    new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size);
    if (new_fd == -1) {
        perror("accept");
        continue;
    }

    inet_ntop(their_addr.ss_family,
        get_in_addr((struct sockaddr *)&their_addr),
        s, sizeof s);

    //getnameinfo(get_in_addr((struct sockaddr *)&their_addr), sizeof get_in_addr((struct sockaddr *)&their_addr), NULL, NULL, service, sizeof service, 0);

    if ((numbytes = recv(new_fd, buf, 100, 0)) == -1)
        perror("recv");

    /* if ((numbytes = recv(sockfd, buf, 100, 0)) == -1) {
    perror("recv");
    exit(1);
}*/ 

    struct tm* local;
    char toClient[50];
    printf("server: received '%s'\n",buf);
    time_t curTime = time(0);
    local = localtime(&curTime);
    if(buf[0] == 't'    ){
        printf("server: received time request\n", s);
        sprintf(toClient, "Time: %d::%d::%d", local->tm_hour, local->tm_min, local->tm_sec);  //Seg faulting
        printf("Sent the time to the client having IP address %s and port number %s\n", s, service);
    }
    else if(buf[0] == 'd'){
        printf("server: received date request\n", s);
        sprintf(toClient, "Date: %d::%d::%d", 1900+local->tm_year, 1+local->tm_mon, local->tm_mday);
        printf("Sent the date to the client having IP address %s and port number %s\n", s, service);
    }
    else{

    }   

    if ((numbytes = send(new_fd, toClient, sizeof toClient, 0)) == -1) {
    perror("send");
    exit(1);
}
    close(new_fd);
    break; //Temporary
}

close(sockfd);
return 0;
}


The problem is in your inet_ntop call:

inet_ntop(p->ai_family, get_in_addr((struct sockaddr *)p->ai_addr),
          host, sizeof host);

In here you are using pointer p after calling

freeaddrinfo(servinfo);

You need to copy the struct sockaddr and socklen_t you got from getaddrinfo in some variables, or store the struct addrinfo for further use. Otherwise you will cause undefined behavior, like you are now experiencing. Remember, Valgrind is your friend.