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:In here you are using pointer
p
after callingYou need to copy the struct
sockaddr
andsocklen_t
you got fromgetaddrinfo
in some variables, or store the structaddrinfo
for further use. Otherwise you will cause undefined behavior, like you are now experiencing. Remember, Valgrind is your friend.Well, the other answers (getsockname) is probably already what you need.
I just would like to highlight one of the best sources available to understanding network programming:
Beej's guide to network programming
What you might need to use is the
getsockname
function: