Jeansburger Jeansburger - 6 days ago 5
C++ Question

Sockets: Why is accept() hanging but connect() is succeeding?

I have been trying to understand why on my server the accept() call is still blocking when the client has a successful connect() call?

server.cpp

#include <errno.h>
#include <strings.h>

#include <iostream>
#include "globals.h"

using namespace std;

/* Declaring errno */
extern int errno;

/* Function for printing error */

void report_error(char *s)
{
printf("receiver: error in%s, errno = %d\n", s, errno);
exit(1);
}

int main(int argc, char *argv[])
{
int s,c;
int res;
struct sockaddr_in socket_address = {0}, client_sa = {0};
unsigned int client_sa_len = sizeof(client_sa);


/* Creating the socket and returns error if unsuccesfull */
if((s= socket(AF_INET, SOCK_DGRAM, PF_UNSPEC)) == -1)
report_error("socket");

socket_address.sin_family = AF_INET;
socket_address.sin_addr.s_addr=INADDR_ANY;
socket_address.sin_port = htons(5318 + 2000);

/* Binding the socket and returns error if unsuccesfull */
if(bind(s, (struct sockaddr *)&socket_address, sizeof(socket_address))== -1)
report_error("bind");

listen(s, 10);
cout << "listening on port\n";

while(1)
{

/*The server just hangs here*/
c = accept(s, (struct sockaddr*)&client_sa, &client_sa_len);
if (c > 0)
{
cout << "LOG: Was the accept successful" << endl;
res = fork();
if (res < 0)
{
perror("Forking of child failed");
}
}

if(res == 0)
{
//close(s);
char msg[MSGL], reply[50], args[MSGL];
char command[MSGL];
cout << "LOG: Get message?" << endl;
GetRequest(msg, c, &client_sa);
if( (msg[0] == 'c') && (msg[1] == 'd') && (msg[2] == ' '))
{
strncpy(command, "cd", sizeof(command));

int arg_i = 0;
for(int i = 3; msg[i] != '\n'; ++i)
{
args[arg_i] = msg[i];
++arg_i;
}
}
else
{
for(int i = 0; msg[i] != '\n'; ++i)
{
command[i] = msg[i];
}
}

else
{
if(c > 0)
{
//close(c);
}
}
}

return 0;
}


When I run this server it prints that it is listening, then when I initialize the client it does not say that the client has connected

client.cpp

#include <errno.h>
#include <arpa/inet.h>

#include <iostream>
#include <string>
#include "globals.h"

using namespace std;


/* Declaring errno */
extern int errno;

int main(int argc, char *argv[])
{
int s;
char* server_address = argv[1];
char command[MSGL];
char reply[MSGL];
int connect_success;
struct sockaddr_in sa = {0} ,cli_sa = {0};
int length = sizeof(sa);
struct hostent *hp;

cli_sa.sin_family = AF_INET;
cli_sa.sin_addr.s_addr=INADDR_ANY;
cli_sa.sin_port = htons(5318 + 2001);
/* FILL SOCKET ADDRESS*/
if((hp = gethostbyname(server_address))==NULL)
report_error("gethostbyname");


bcopy((char*)hp->h_addr, (char *)&sa.sin_addr, hp->h_length);

sa.sin_family = hp->h_addrtype;

//memcpy(&sa.sin_addr, hp->h_addr, hp->h_length);
sa.sin_port = htons(5318 + 2000); /* define port number based on student ID*/

/* Creating the socket and returns error if unsuccessfull */
if((s=socket(AF_INET, SOCK_DGRAM, PF_UNSPEC))== -1)
report_error("socket");

/* Binding the socket and returns error if unsuccesfull */
if(bind(s, (struct sockaddr *)&cli_sa, sizeof(cli_sa))== -1)
report_error("bind");

connect_success = connect(s,(struct sockaddr*) &sa, length);
cout << connect_success << endl;
if (connect_success < 0)
{
report_error("connect");
cout << "LOG: is there an error?" << endl;
}
cout << "LOG: is the connection made?" << endl;
while(1)
{
cout << "myRPC>>";
fgets(command,MSGL,stdin);
if (DoOperation(command,reply,s,sa) == SEND_FAILURE)
{
cout << "Error: sending command\n";
}
}

return 0;
}

Answer

I'm fairly certain that your server process has undefined behavior.

accept() and connect() is for TCP sockets. You are creating UDP sockets. For UDP sockets, all that connect() does is set the default address for send(), and it always succeeds immediately. This is explained in the manual page for connect(2), which you should definitely read:

If the socket sockfd is of type SOCK_DGRAM, then addr is the address to which datagrams are sent by default, and the only address from which datagrams are received.

I expect accept() to fail for UDP (SOCK_DGRAM) sockets, most likely with EINVAL. If you review the logic in your server code, when accept() fails, res never gets initialized before its value is tested in the if() statement.

Undefined behavior.