listen(): invalid argument - c

Trying to create a server-client application, and I'm having quite a bit of trouble setting up the connection on the server-side. After setting up the socket, and bind()ing the socket, my listen()-call fails with the error message
listen: Invalid argument
which I get from perror()-ing the case where listen() returns -1.
The synopsis of the program is the following: I use getaddrinfo() to generate a linked list of struct addrinfo's, loop through that until I find one that I can successfully create a socket with, then bind() and finally listen().
The listen() call goes as follows:
if ((status = listen(socket_fd, BACKLOG_SIZE)) == -1) {
perror("listen");
close(socket_fd);
freeaddrinfo(res);
exit(EXIT_FAILURE);
}
To be sure, I've printed the values of socket_fd and BACKLOG_SIZE, turning out to be 3 and 5, respectively. Have been debugging for hours now, and I simply cannot find out where the problem lies. Haven't found anyone with the same issue on stackOverflow, either...
Thank you in advance for any help!
Full program:
int main(int argc, char* argv[]) {
int port_no = server_usage(argc, argv);
ready_connection(port_no);
/* Synopsis:
getaddrinfo()
socket()
bind()
listen()
accept()
*/
int socket_fd = setup_socket(NULL, port_no);
struct sockaddr_storage their_addr;
socklen_t addr_size = sizeof(their_addr);
int new_fd = 0;
// Allow reuse of sockets
int activate=1;
setsockopt(socket_fd, IPPROTO_TCP, TCP_NODELAY, &activate, sizeof(int));
if ((status = bind(socket_fd, res->ai_addr, res->ai_addrlen)) == -1) {
perror("bind");
exit(EXIT_FAILURE);
}
if ((status = connect(socket_fd, res->ai_addr, res->ai_addrlen)) == -1) {
perror("connect");
close(socket_fd);
freeaddrinfo(res); // free the linked-list
exit(EXIT_FAILURE);
}
if ((status = listen(socket_fd, BACKLOG_SIZE)) == -1) {
perror("listen");
close(socket_fd);
freeaddrinfo(res); // free the linked-list
exit(EXIT_FAILURE);
}
if ((new_fd == accept(socket_fd, (struct sockaddr *)&their_addr, &addr_size)) == -1) {
perror("accept");
exit(EXIT_FAILURE);
}
char buffer[BUFSIZE];
recv(new_fd, buffer, BUFSIZE, 0);
close(socket_fd);
close(new_fd);
freeaddrinfo(res); // free the linked-list
return 0;
}
setup_socket()-function:
int setup_socket(char* hostname, int port_no) {
// hints is mask struct, p is loop variable
struct addrinfo hints, *p;
memset(&hints, 0, sizeof hints); // make sure the struct is empty
// TODO IPv6-support?
hints.ai_family = AF_INET; // only IPv4 supported
hints.ai_socktype = SOCK_STREAM; // TCP stream sockets
hints.ai_flags = AI_PASSIVE; // fill in my IP for me
char port_str[6]; // max port size is 5 digits + 0-byte
memset(port_str, 0, 6);
sprintf(port_str, "%d", port_no);
if ((status = getaddrinfo(hostname, port_str, &hints, &res)) == -1) {
fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(status));
exit(EXIT_FAILURE);
}
int socket_fd = 0;
for (p = res; p != NULL; p = p->ai_next) {
if ((socket_fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) {
perror("socket");
exit(EXIT_FAILURE);
}
}
if (socket_fd == 0) {
errno = ENOTSOCK;
perror("no socket");
exit(EXIT_FAILURE);
}
return socket_fd;
}

You cannot connect(), then listen() on the same socket. Lose the connect().

Related

Prob with binary files using sockets

This is not the total code.
This is working fine for normal files like text files, but not working for tar.gz and binary files transfer please help me.
And how to send the chunks of memory using sockets.
server.c
void main()
{
int sockfd, new_fd; // listen on sock_fd, new connection on new_fd
struct sockaddr_in my_addr; // my address information
struct sockaddr_in their_addr; // connector's address information
socklen_t sin_size;
struct sigaction sa;
int yes=1;
char buf[16384];
char remotefile[MAXDATASIZE];
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("socket");
exit(1);
}
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1)
{
perror("setsockopt");
exit(1);
}
my_addr.sin_family = AF_INET; // host byte order
my_addr.sin_port = htons(MYPORT); // short, network byte order
my_addr.sin_addr.s_addr = INADDR_ANY; // automatically fill with my IP
memset(my_addr.sin_zero, '\0', sizeof my_addr.sin_zero);
printf("call binding\n");
if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof my_addr) == -1)
{
perror("bind");
exit(1);
}
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);
}
while(1)
{ // main accept() loop
sin_size = sizeof their_addr;
if ((new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size)) == -1)
{
perror("accept");
exit(1);
continue;
}
printf("server: got connection from %s\n",inet_ntoa(their_addr.sin_addr));
if (!fork())
{ // this is the child process
if ((byt=recv(new_fd, remotefile, MAXDATASIZE-1, 0)) == -1)
{
perror("server recv");
exit(1);
}
int serverfile_fd;
size_t result;
printf("\nremotefile in val1 is %s\n",remotefile);
if((serverfile_fd = open(remotefile,O_RDONLY)) < 0)
{
printf("error at remotefile\n");
exit(1);
}
else
{
read(serverfile_fd, &buf[0], sizeof(buf));
}
//printf("file is\n%s", buf);
/* 3. sending buf in val 0*/
if (send(new_fd, buf, 16384, 0) == -1)
perror("send");
close(new_fd);
exit(0);
}
client.c
int remote_to_local(const char *remotehost,const char *remotefile,const char *localfile)
{
int sockfd, numbytes,i = 0,j = 0;
char buf[16384];
struct hostent *he;
struct sockaddr_in s_addr; // connector's address information
printf("\n");
printf("Remotehost is %s\n", remotehost);
if ((he=gethostbyname(remotehost)) == NULL)
{ // get the host info
perror("gethostbyname");
exit(1);
}
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("socket");
exit(1);
}
s_addr.sin_family = AF_INET; // host byte order
s_addr.sin_port = htons(PORT); // short, network byte order
s_addr.sin_addr = *((struct in_addr *)he->h_addr);
//inet_aton(he->h_addr, &s_addr.sin_addr);
memset(s_addr.sin_zero, '\0', sizeof s_addr.sin_zero);
if (connect(sockfd, (struct sockaddr *)&s_addr, sizeof s_addr) == -1)
{
perror("connect");
exit(1);
}
//send(sockfd, remotefile, MAXDATASIZE-1, 0);
val[0] = 1;
printf("Val 0 is %d\n", val[0]);
printf("Val 1 is %d\n", val[1]);
/*1 sending val in r to l*/
if (send(sockfd, val, MAXDATASIZE-1, 0) == -1)
perror("send");
printf("remotefile is %s\n",remotefile);
/* 2 sending remotefile in r to l*/
if (send(sockfd, remotefile, MAXDATASIZE-1, 0) == -1)
perror("send");
/* 3. recieve buf in r to l */
if ((numbytes=recv(sockfd, buf, 16384, 0)) == -1)
{
perror("recv");
exit(1);
}
buf[numbytes] = '\0';
//printf("Received: \n%s",buf);
int clientfile_fd;
printf("Local file is %s\n",localfile);
if((clientfile_fd = open(localfile,O_CREAT|O_WRONLY,0777)) < 0)
{
printf("error at remotefile\n");
exit(1);
}
else
{
//read(clientfile_fd, &buf[0], sizeof(buf));
int result = strlen(buf);
//printf("Result size is %d\n",result);
open(localfile,O_TRUNC);
write(clientfile_fd, &buf[0], result);
}
close(sockfd);
return 0;
}
Go through ALL your code and fix/change ALL the places where you:
don't correctly handle the results returned by system calls like
recv(). If a positive value is returned, that value is the ONLY safe
way of finding out how much data has been read into the buffer.
Get rid of all the strlen(), printf("%s...) etc. that are either
useless, (the binary data may contain nulls and so the action will
complete early), or dangerous, (binary data contains no nulls at all
and so the calls are UB).
Following logic for receiving a file is already a lot better than what you have. But there are a lot more problems with your code than just this :
FILE *received_file;
received_file = fopen(FILENAME, "w");
...
//copy logic, copies data received from the socket into the file as is.
while (((len = recv(client_socket, buffer, BUFSIZ, 0)) > 0))
{
fwrite(buffer, sizeof(char), len, received_file);
}
fclose(received_file);
close(client_socket);
The receive is continuously called until your receive 0 or a negative number, if you receive 0 that means you need to close the socket because the transfer is finished and the peer has closed its end of the connection too.
The file handle should be created right after accept.
Bottom line is that your code needs a total revision because it is too lengthy for what it is supposed to do, and it is based on totally wrong assumptions. Read first about network programming before attempting anything like this. Socket programming is an advanced topic, without proper understanding you will fail.

Server-Client Threading Accept error/leak

I keep getting a "Accept: too many files" error after running my server.c code. Trying to get it to create new threads for clients and limit connections with semaphores.
This is my code:
#define MAX_CLIENTS 30
sem_t s;
void *handle(void *pnewsock);
int sockfd, new_fd, numbytes; // listen on sock_fd, new connection on new_fd
struct sockaddr_in my_addr; // my address information
struct sockaddr_in their_addr; // connector's address information
socklen_t sin_size;
pthread_t thread;
int main(void){
//initialise locks
sem_init(&s, 0, 0);
/* generate the socket */
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket");
exit(true);
}
my_addr.sin_family = AF_INET; // host byte order
my_addr.sin_port = htons(MYPORT); // short, network byte order
my_addr.sin_addr.s_addr = INADDR_ANY; // auto-fill with my IP
/* bind the socket to the end point */
if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) \
== -1) {
perror("bind");
exit(true);
}
/* start listnening */
if (listen(sockfd, BACKLOG) == -1) {
perror("listen");
exit(true);
}
printf("server starts listening ...\n");
/* Main loop */
while (1) {
sin_size = sizeof(struct sockaddr_in);
if (pthread_create(&thread, NULL, handle, &new_fd) != 0) {
fprintf(stderr, "Failed to create thread\n");
}
}
return 0;
}
void *handle(void *pnewsock){
int value;
sem_getvalue(&s,&value);
while (value >= MAX_CLIENTS){
printf("too many connections");
sem_wait(&s);
}
if (value < MAX_CLIENTS){
if ((new_fd = accept(sockfd, (struct sockaddr *)&their_addr, \
&sin_size)) == -1) {
perror("accept");
exit(1);
}
printf("server: got connection from %s\n", \
inet_ntoa(their_addr.sin_addr));
char buffer[MAXDATASIZE];
char res[MAXDATASIZE];
memset(buffer, '\0', MAXDATASIZE);
memset(res, '\0', sizeof(res));
if ((numbytes=recv(new_fd, buffer, sizeof(buffer), 0)) == -1) {
perror("recv");
exit(true);
}
else if(numbytes == 0) {
printf("client left");
sem_post(&s);
close(new_fd);
exit(false);
}
else {
buffer[numbytes] = '\0'; // add null terminator
printf("Request: %s\n",buffer);
//search function
}
}
close(new_fd);
exit(false);
return NULL;
}
Can anyone give me some insight to this file leak? Thanks
The main() function is creating pthreads using an infinite loop. Your error is very likely related to this since the loop will keep on creating newer threads.
/* Main loop */
while (1) {
sin_size = sizeof(struct sockaddr_in);
if (pthread_create(&thread, NULL, handle, &new_fd) != 0) {
fprintf(stderr, "Failed to create thread\n");
}
}
What you probably meant was to create one thread for each client. And if that is the case, then the handle() function should call pthread_create() whenever it gets a new client from the accept() call. The server (the socket for which we call listen and accept) does not need multiple threads -- one thread -- which can be the main thread -- is all it needs.

Using select() for non-blocking sockets

I am trying to use the select function to have non-blocking i/o between a server and 1 client (no more) where the communication flows nicely (can send at any time and the other will receive without waiting to send). I found a tutorial with some code and tried to adapt it to mine. This is what I have -
Server
#define PORT "4950"
#define STDIN 0
struct sockaddr name;
void set_nonblock(int socket) {
int flags;
flags = fcntl(socket,F_GETFL,0);
assert(flags != -1);
fcntl(socket, F_SETFL, flags | O_NONBLOCK);
}
// 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(int agrc, char** argv) {
int status, sock, adrlen, new_sd;
struct addrinfo hints;
struct addrinfo *servinfo; //will point to the results
//store the connecting address and size
struct sockaddr_storage their_addr;
socklen_t their_addr_size;
fd_set read_flags,write_flags; // the flag sets to be used
struct timeval waitd; // the max wait time for an event
int sel; // holds return value for select();
//socket infoS
memset(&hints, 0, sizeof hints); //make sure the struct is empty
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM; //tcp
hints.ai_flags = AI_PASSIVE; //use local-host address
//get server info, put into servinfo
if ((status = getaddrinfo("127.0.0.1", PORT, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(status));
exit(1);
}
//make socket
sock = socket(servinfo->ai_family, servinfo->ai_socktype, servinfo->ai_protocol);
if (sock < 0) {
printf("\nserver socket failure %m", errno);
exit(1);
}
//allow reuse of port
int yes=1;
if (setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1) {
perror("setsockopt");
exit(1);
}
//unlink and bind
unlink("127.0.0.1");
if(bind (sock, servinfo->ai_addr, servinfo->ai_addrlen) < 0) {
printf("\nBind error %m", errno);
exit(1);
}
freeaddrinfo(servinfo);
//listen
if(listen(sock, 5) < 0) {
printf("\nListen error %m", errno);
exit(1);
}
their_addr_size = sizeof(their_addr);
//accept
new_sd = accept(sock, (struct sockaddr*)&their_addr, &their_addr_size);
if( new_sd < 0) {
printf("\nAccept error %m", errno);
exit(1);
}
set_nonblock(new_sd);
cout<<"\nSuccessful Connection!";
char* in = new char[255];
char* out = new char[255];
int numSent;
int numRead;
while(1) {
waitd.tv_sec = 10;
FD_ZERO(&read_flags);
FD_ZERO(&write_flags);
FD_SET(new_sd, &read_flags);
if(strlen(out) != 0)
FD_SET(new_sd, &write_flags);
sel = select(new_sd+1, &read_flags, &write_flags, (fd_set*)0, &waitd);
if(sel < 0)
continue;
//socket ready for reading
if(FD_ISSET(new_sd, &read_flags)) {
FD_CLR(new_sd, &read_flags);
memset(&in, 0, sizeof(in));
if(recv(new_sd, in, sizeof(in), 0) <= 0) {
close(new_sd);
break;
}
else
cout<<"\n"<<in;
} //end if ready for read
//socket ready for writing
if(FD_ISSET(new_sd, &write_flags)) {
FD_CLR(new_sd, &write_flags);
send(new_sd, out, strlen(out), 0);
memset(&out, 0, sizeof(out));
}
} //end while
cout<<"\n\nExiting normally\n";
return 0;
}
Client (basically the same just minus an accept call) -
#define PORT "4950"
struct sockaddr name;
void set_nonblock(int socket) {
int flags;
flags = fcntl(socket,F_GETFL,0);
assert(flags != -1);
fcntl(socket, F_SETFL, flags | O_NONBLOCK);
}
// 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(int agrc, char** argv) {
int status, sock, adrlen;
struct addrinfo hints;
struct addrinfo *servinfo; //will point to the results
fd_set read_flags,write_flags; // the flag sets to be used
struct timeval waitd; // the max wait time for an event
int sel; // holds return value for select();
memset(&hints, 0, sizeof hints); //make sure the struct is empty
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM; //tcp
hints.ai_flags = AI_PASSIVE; //use local-host address
//get server info, put into servinfo
if ((status = getaddrinfo("127.0.0.1", PORT, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(status));
exit(1);
}
//make socket
sock = socket(servinfo->ai_family, servinfo->ai_socktype, servinfo->ai_protocol);
if (sock < 0) {
printf("\nserver socket failure %m", errno);
exit(1);
}
if(connect(sock, servinfo->ai_addr, servinfo->ai_addrlen) < 0) {
printf("\nclient connection failure %m", errno);
exit(1);
}
cout<<"\nSuccessful connection!";
set_nonblock(sock);
char* out = new char[255];
char* in = new char[255];
int numRead;
int numSent;
while(1) {
waitd.tv_sec = 10;
FD_ZERO(&read_flags);
FD_ZERO(&write_flags);
FD_SET(sock, &read_flags);
if(strlen(out) != 0)
FD_SET(sock, &write_flags);
sel = select(sock+1, &read_flags, &write_flags, (fd_set*)0, &waitd);
if(sel < 0)
continue;
//socket ready for reading
if(FD_ISSET(sock, &read_flags)) {
FD_CLR(sock, &read_flags);
memset(&in, 0, sizeof(in));
if(recv(sock, in, sizeof(in), 0) <= 0) {
close(sock);
break;
}
else
cout<<"\n"<<in;
} //end if ready for read
//socket ready for writing
if(FD_ISSET(sock, &write_flags)) {
FD_CLR(sock, &write_flags);
send(sock, out, strlen(out), 0);
memset(&out, 0, sizeof(out));
}
} //end while
cout<<"\n\nExiting normally\n";
return 0;
}
The problem is that when I run them, nothing happens. I can type into one and hit enter and nothing shows up on the other screen (and vice versa). Thats not a whole of information for me to debug and this is my first real attempt at using select so I thought maybe I am just unaware of something simple. If anything can be spotted as wrong or weird please point it out, any help is appreciated.
The problem is that when I run them, nothing happens.
The real problem is that people have been pasting stuff from Beej for years without understanding it. That's why I don't really like that guide; it gives large blocks of code without really explaining them in detail.
You're not reading anything and not sending anything; no fgets, scanf, cin, etc. Here's what I would do:
FD_SET(sock, &read_flags);
FD_SET(STDIN_FILENO, &read_flags);
/* .. snip .. */
if(FD_ISSET(STDIN_FILENO, &read_flags)) {
fgets(out, len, stdin);
}
This will monitor stdin and read from it when input is available; then, when the socket is writeable (FD_ISSET(sock, &write_flags)), it will send the buffer.
I have the program working correctly now.
server -
#define PORT "4950"
#define STDIN 0
struct sockaddr name;
void set_nonblock(int socket) {
int flags;
flags = fcntl(socket,F_GETFL,0);
assert(flags != -1);
fcntl(socket, F_SETFL, flags | O_NONBLOCK);
}
// 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(int agrc, char** argv) {
int status, sock, adrlen, new_sd;
struct addrinfo hints;
struct addrinfo *servinfo; //will point to the results
//store the connecting address and size
struct sockaddr_storage their_addr;
socklen_t their_addr_size;
fd_set read_flags,write_flags; // the flag sets to be used
struct timeval waitd = {10, 0}; // the max wait time for an event
int sel; // holds return value for select();
//socket infoS
memset(&hints, 0, sizeof hints); //make sure the struct is empty
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM; //tcp
hints.ai_flags = AI_PASSIVE; //use local-host address
//get server info, put into servinfo
if ((status = getaddrinfo("127.0.0.1", PORT, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(status));
exit(1);
}
//make socket
sock = socket(servinfo->ai_family, servinfo->ai_socktype, servinfo->ai_protocol);
if (sock < 0) {
printf("\nserver socket failure %m", errno);
exit(1);
}
//allow reuse of port
int yes=1;
if (setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1) {
perror("setsockopt");
exit(1);
}
//unlink and bind
unlink("127.0.0.1");
if(bind (sock, servinfo->ai_addr, servinfo->ai_addrlen) < 0) {
printf("\nBind error %m", errno);
exit(1);
}
freeaddrinfo(servinfo);
//listen
if(listen(sock, 5) < 0) {
printf("\nListen error %m", errno);
exit(1);
}
their_addr_size = sizeof(their_addr);
//accept
new_sd = accept(sock, (struct sockaddr*)&their_addr, &their_addr_size);
if( new_sd < 0) {
printf("\nAccept error %m", errno);
exit(1);
}
//set non blocking
set_nonblock(new_sd);
cout<<"\nSuccessful Connection!\n";
char in[255];
char out[255];
memset(&in, 0, 255);
memset(&out, 0, 255);
int numSent;
int numRead;
while(1) {
FD_ZERO(&read_flags);
FD_ZERO(&write_flags);
FD_SET(new_sd, &read_flags);
FD_SET(new_sd, &write_flags);
FD_SET(STDIN_FILENO, &read_flags);
FD_SET(STDIN_FILENO, &write_flags);
sel = select(new_sd+1, &read_flags, &write_flags, (fd_set*)0, &waitd);
//if an error with select
if(sel < 0)
continue;
//socket ready for reading
if(FD_ISSET(new_sd, &read_flags)) {
//clear set
FD_CLR(new_sd, &read_flags);
memset(&in, 0, 255);
numRead = recv(new_sd, in, 255, 0);
if(numRead <= 0) {
printf("\nClosing socket");
close(new_sd);
break;
}
else if(in[0] != '\0')
cout<<"\nClient: "<<in;
} //end if ready for read
//if stdin is ready to be read
if(FD_ISSET(STDIN_FILENO, &read_flags))
fgets(out, 255, stdin);
//socket ready for writing
if(FD_ISSET(new_sd, &write_flags)) {
//printf("\nSocket ready for write");
FD_CLR(new_sd, &write_flags);
send(new_sd, out, 255, 0);
memset(&out, 0, 255);
} //end if
} //end while
cout<<"\n\nExiting normally\n";
return 0;
}
The client is basically the same...only difference really is the lack of listen and accept.
I just want to add that above example may not work as expected on Linux. On Linux waitd may be modified by select. So for Linux, waitd should be rewritten before select.
See the "timeout" section in the man page for select.

How to get the ip address of the accepted in-bound socket?

My question is:
Server will create a socket, bind to a given port and with address = INADDR_ANY.
listen() & accept() the new connection. Then, we can get the client's ip-address
from accept().
Now, I want to know the ip-address of the Server, since the host of the server has
multiple NIC on it.
How to know the ip-address of the network interface with which the accepted in-bound socket is from?
I tried getsockname, it gave me the port number, but the ip is all-zero.
Update: Here is the code:
Server.c (header files are removed)
int main(void)
{
struct sockaddr_in stSockAddr;
int res, addr_len, SocketFD, ConnectFD;
struct sockaddr_in addr;
SocketFD = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if(-1 == SocketFD)
{
perror("can not create socket");
//exit(EXIT_FAILURE);
return -1;
}
memset(&stSockAddr, 0, sizeof stSockAddr);
stSockAddr.sin_family = AF_INET;
stSockAddr.sin_port = htons(49335);
stSockAddr.sin_addr.s_addr = INADDR_ANY;
if(-1 == bind(SocketFD,(struct sockaddr *)&stSockAddr, sizeof stSockAddr))
{
perror("error bind failed");
close(SocketFD);
return -1;
}
printf("going to listen!\n");
if(-1 == listen(SocketFD, 10))
{
perror("error listen failed");
close(SocketFD);
//exit(EXIT_FAILURE);
return -1;
}
ConnectFD = accept(SocketFD, NULL, NULL);
if(0 > ConnectFD)
{
perror("error accept failed");
close(SocketFD);
//exit(EXIT_FAILURE);
return -1;
}
addr.sin_family = AF_INET;
res = getsockname (ConnectFD, (struct sockaddr *)&addr, &addr_len);
// if you remove the following comment, that means, if you call
// two times of getsockname, the result will be correct.
//res = getsockname (ConnectFD, (struct sockaddr *)&addr, &addr_len);
printf("addr:%x\n", addr.sin_addr.s_addr);
while(1) {
if (getchar() == 'q')
break;
}
close(ConnectFD);
close(SocketFD);
return 0;
}
Below is client.c:
int main(void)
{
struct sockaddr_in stSockAddr;
int Res;
int SocketFD = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if (-1 == SocketFD)
{
perror("cannot create socket");
exit(EXIT_FAILURE);
}
memset(&stSockAddr, 0, sizeof stSockAddr);
stSockAddr.sin_family = AF_INET;
stSockAddr.sin_port = htons(49335);
Res = inet_pton(AF_INET, "192.168.1.102", &stSockAddr.sin_addr);
if (0 > Res)
{
perror("error: first parameter is not a valid address family");
close(SocketFD);
exit(EXIT_FAILURE);
}
else if (0 == Res)
{
perror("char string (second parameter does not contain valid ipaddress");
close(SocketFD);
exit(EXIT_FAILURE);
}
if (-1 == connect(SocketFD, (struct sockaddr *)&stSockAddr, sizeof stSockAddr))
{
perror("connect failed");
close(SocketFD);
exit(EXIT_FAILURE);
}
/* perform read write operations ... */
printf("client sockfd is successful\n");
while(1) {
if (getchar() == 'q')
break;
}
shutdown(SocketFD, SHUT_RDWR);
close(SocketFD);
return 0;
}
Use getsockname(2) on the socket returned from accept(2), not the socket returned from bind(2).
getsockname() gets name of passed socket.
in this example, you pass the socket which is created by
accept function in server.
this socket is in server side, so it's name & address is
related to server side.
if you want to know "who was connected to me"
you must use getpeername() instead of getsockname.
good luck
if you remove the following comment, that means, if you call
two times of getsockname, the result will be correct.
res = getsockname (ConnectFD, (struct sockaddr *)&addr, &addr_len);
you must init addr_len.
addr_len = sizeof(addr);

sendto() crashes with error code "Success"

My problem is quite infuriating, actually. I'll show you the code first.
/*
** listener.c -- a datagram sockets "server" demo
*/
//Original Code: Brian Hall (beej#beej.us)
//Commented and modified by Vishal Kotcherlakota (PID A07124450)
#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 <arpa/inet.h>
#include <netdb.h>
#define MYPORT "4960" // the port users will be connecting to
#define YOURPORT "4961"
#define MAXBUFLEN 10000
// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa)
{
//If the socket address struct says it's an IPv4...
if (sa->sa_family == AF_INET) {
//...return the IPv4 variable.
return &(((struct sockaddr_in*)sa)->sin_addr);
}
//otherwise, assume it's IPv6, and get the IPv6 variable
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
int main(int argc, char *argv[])
{
int sockfd, sockfdAck; //socket file descriptor (handle)
struct addrinfo hints, *servinfo, *p, *q;
int rv;
int numbytes;
unsigned int seqNum, stateNum=0, ackNum;
struct sockaddr_storage their_addr;
struct timeval recvTime, timeStamp, latency;
char buf[MAXBUFLEN], junk[MAXBUFLEN];
size_t addr_len;
char *ackBack;
char s[INET6_ADDRSTRLEN];
if (argc != 2)
{
fprintf(stderr, "usage: <executable> <hostname>\n");
exit(0);
}
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC; // set to AF_INET to force IPv4
hints.ai_socktype = SOCK_DGRAM;
hints.ai_flags = AI_PASSIVE; // use my IP
if ((rv = getaddrinfo(NULL, MYPORT, &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(q = servinfo; q != NULL; q = q->ai_next) {
if ((sockfd = socket(q->ai_family, q->ai_socktype,
q->ai_protocol)) == -1) {
perror("listener: socket");
continue;
}
if (bind(sockfd, q->ai_addr, q->ai_addrlen) == -1) {
close(sockfd);
perror("listener: bind");
continue;
}
break;
}
if (q == NULL) {
fprintf(stderr, "listener: failed to bind socket\n");
return 2;
}
freeaddrinfo(servinfo);
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC; // set to AF_INET to force IPv4
hints.ai_socktype = SOCK_DGRAM;
if ((rv = getaddrinfo(argv[1], BACKPORT, &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 ((sockfdAck = socket(p->ai_family, p->ai_socktype,
p->ai_protocol)) == -1) {
perror("listener: socket");
continue;
}
break;
}
if (p == NULL) {
fprintf(stderr, "listener: failed to bind socket\n");
return 2;
}
freeaddrinfo(servinfo);
printf("listener: waiting to recvfrom...\n");
while (1)
{
addr_len = sizeof their_addr;
if ((numbytes = recvfrom(sockfd, buf, MAXBUFLEN-1 , 0,
(struct sockaddr *)&their_addr, &addr_len)) == -1) {
perror("recvfrom");
exit(1);
}
/*printf("listener: got packet from %s\n",
inet_ntop(their_addr.ss_family,
get_in_addr((struct sockaddr *)&their_addr),
s, sizeof s));
printf("listener: packet is %d bytes long\n", numbytes);
*/
buf[numbytes] = '\0';
sscanf(buf,"%u %s",&seqNum, junk);
if (seqNum == stateNum + 1)
{
stateNum = seqNum;
printf("Ok, state is now %u.\n", stateNum);
}
ackBack = malloc(20*sizeof(char));
sprintf(ackBack, "%u acknowledged\0", stateNum);
numbytes = sendto(sockfdAck, ackBack, strlen(ackBack), 0, p->ai_addr, p->ai_addrlen);
if (numbytes == -1);
{
perror("sendto");
exit(1);
}
free(ackBack);
}
return 0;
}
Please forgive the sloppy code; I'm desperately trying to finish this assignment on time. The goal is to develop an ARQ protocol using datagram sockets. This code should work, but when I run it, I get an error sendto: Success, meaning that my sendto() call failed. I can't find documentation for this anywhere, and I'm getting to be extremely desperate.
It has nothing to do with having to bind() - in fact take a look at this syntax:
if (numbytes == -1) ; // semicolon !
{
perror("sendto");
exit(1);
}
You have a condition without the body, and then the body without the condition, which always executes (as you can observe).
Add the printf of numbytes and you will see it is set correct, there is no error.
To avoid this kind of hard-to-see errors, I generally put the opening brace immediately after the condition - then you would have spotted this immediately. But of course this is a matter of the coding convention for the company/project.

Resources