forwarding message between clients with a server in middle - c

I want to take a message from one client and send it to the other with a server in middle.
I use the select function to make several connections to the server possible but here is the problem:
I store the socket descriptor sock in Queue[pq] using dup and it's working. the sock = 4 & Queue[0] = 5. now I need to take the other client's socket descriptor, and again I store it in Queue. the values of Queue for Client(2) equals to Queue[0] = 5 , Queue[1] = 7 but for the first client it's still Queue[0] = 5 and Queue[1] = 0 it means the code for first client doesn't have access to the second client's socket descriptor and i cant forward it to the other client using his socket descriptor with send() and client 3 has the the first 2 client's socket descriptor but the first 2 client doesn't have the third one's socket descriptor.
I think that's because select() use different memory address for the values for each client just like sock which has different values for each connection.
how I can solve this problem? how the clients can access each other's socket descriptor?
the code:
Global Values:
int tcpfd, udpfd, Sock, nready, maxfdp1;
int Queue[64];
int pq = -1;
int max(int x, int y) {
if (x > y)
return x;
else
return y;
}
int main(){
pid_t childpid;
fd_set rset;
ssize_t n;
socklen_t len;
const int on = 1;
struct sockaddr_in cliaddr, servaddr;
void sig_chld(int);
/* create listening TCP socket */
tcpfd = socket(AF_INET, SOCK_STREAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = inet_addr("192.168.1.5");
servaddr.sin_port = htons(PORT);
// binding server addr structure to tcpfd
bind(tcpfd, (struct sockaddr*)&servaddr, sizeof(servaddr));
listen(tcpfd, 10);
// clear the descriptor set
// get maxfd
maxfdp1 = max(tcpfd, udpfd) + 1;
for (;;) {
// set tcpfd and udpfd in readset
FD_ZERO(&rset);
FD_SET(tcpfd, &rset);
// select the ready descriptor
nready = select(maxfdp1, &rset, NULL, NULL, NULL);
// if tcp socket is readable then handle
// it by accepting the connection
if (FD_ISSET(tcpfd, &rset)){
len = sizeof(cliaddr);
Sock = accept(tcpfd, (struct sockaddr*)&cliaddr, &len);
pq++;
Queue[pq] = dup(Sock);
printf("%d\n",Sock);
if ((childpid = fork()) == 0) {
Access_Request();
while(1) { //rest of the code
}

Related

TCP cannot detect closed socket in client

I have server that just connects to a client and right after that disconnects, while client tries to send an integer to a closed socket (scanf is to ensure server closese it first). I use send with MSG_NOSIGNAL and check for EPIPE but the flag is not set. I think result should have printed value of -1, or 0, but it is equal to 1, because I am writing on already closed socket. Can someone explain that?
Server Code:
#define QUEUE_LENGTH 5
#define PORT_NUM 10002
#define BUFFER_SIZE 512000
int main(int argc, char *argv[]) {
int sock, msg_sock;
struct sockaddr_in server_address;
struct sockaddr_in client_address;
socklen_t client_address_len;
sock = socket(PF_INET, SOCK_STREAM, 0); // creating IPv4 TCP socket
if (sock < 0)
syserr("socket");
server_address.sin_family = AF_INET; // IPv4
server_address.sin_addr.s_addr = htonl(
INADDR_ANY); // listening on all interfaces
server_address.sin_port = htons(PORT_NUM);
// bind the socket to a concrete address
if (bind(sock, (struct sockaddr *) &server_address,
sizeof(server_address)) < 0)
syserr("bind");
// switch to listening (passive open)
if (listen(sock, QUEUE_LENGTH) < 0)
syserr("listen");
printf("accepting client connections on port %hu\n",
ntohs(server_address.sin_port));
for (;;) {
client_address_len = sizeof(client_address);
msg_sock = accept(sock, (struct sockaddr *) &client_address,
&client_address_len);
if (msg_sock < 0)
syserr("accept");
printf("ending connection\n");
if (close(msg_sock) < 0) {
printf("ErrorClosingSocket\n");
break;
}
continue;
}
return 0;
}
Client code:
int sendSomething(void *to_send, int socket, uint32_t length) {
if (send(socket, to_send, length, MSG_NOSIGNAL) !=
length) {
if (errno == EPIPE) // Sending on closed connection
return 0;
return -1;
}
return 1;
}
int main(int argc, char *argv[]) {
int sock;
struct addrinfo addr_hints;
struct addrinfo *addr_result;
int err;
if (argc != 3)
fatal("Usage: %s host port\n", argv[0]);
// 'converting' host/port in string to struct addrinfo
memset(&addr_hints, 0, sizeof(struct addrinfo));
addr_hints.ai_family = AF_INET; // IPv4
addr_hints.ai_socktype = SOCK_STREAM;
addr_hints.ai_protocol = IPPROTO_TCP;
// argv[1] is localhost and argv[2] is 10002
err = getaddrinfo(argv[1], argv[2], &addr_hints, &addr_result);
if (err == EAI_SYSTEM) // system error
syserr("getaddrinfo: %s", gai_strerror(err));
else if (err != 0) // other error (host not found, etc.)
fatal("getaddrinfo: %s", gai_strerror(err));
// initialize socket according to getaddrinfo results
sock = socket(addr_result->ai_family, addr_result->ai_socktype,
addr_result->ai_protocol);
if (sock < 0)
syserr("socket");
// connect socket to the server
if (connect(sock, addr_result->ai_addr, addr_result->ai_addrlen) < 0)
syserr("connect");
freeaddrinfo(addr_result);
int result;
scanf("%d", &result);
uint16_t test;
test = htons(1);
result = sendSomething(&test, sock, sizeof(test));
printf("result:%d\n", result);
if (close(sock) < 0) {
printf("ErrorClosingSocket\n");
}
return 0;
}
Note: Fatal and Syserr are just for reporting errors
That's the way TCP works. When the server closes the socket, then a FIN is sent to the client. This only signals, that the server will not send any more data. It does not necessarily mean, that it does not want to receive more data.
Thus, the client can call send() on the socket without the OS reporting an error. If the server indeed closed the whole socket, then it will send a TCP reset packet as a response to incoming data indicating that condition. Now, future operations on the socket (write/close) will indicate an error.
It is indeed possible for the server (or any peer) to only shutdown the connection half-way (the reading or the writing side) with the syscall shutdown(). If the server shuts down the connection for writing, the same thing happens on the network as if the server closed the whole connection with close(). It is the duty of a higher level protocol to determine, when a connection should be closed for each side.
If you want to make sure, that all data that you sent was indeed acknowledged by the peer, you can use the SO_LINGER socket option. But a more common way is, to make this sure as a part of the communication protocol, i.e. one part requests to shutdown the connection on a higher level (for example, the smtp QUIT command) and the peer reacts on it by closing the tcp connection.

C submit command to server from client

I have a client-server application which runs on UDP ( I need it UDP not tcp ).
A client can send a message to server and it's working fine and vice versa.
I want the client to be able to pass a message as "_connect game1 10" and trigger a function on the server correspondingly which is called _connect(char *name, int num).
How can this be performed to analyse each command to trigger what command ? and is serialisation is a solution and how to implement it.
You can do something on the lines of the following steps
1. Create a message structure
typedef struct info
{
char clientReq[MAX_LENGTH];
char sub[MAX_LENGTH];
u_int32_t value;
u_int16_t end; //Set for the packet which closes the connection
}messageInfo;
On Client
Create socket and bind locally //and connect to server socket(optionally)
fd = socket( family, SOCK_DGRAM, 0 );
//handle error
struct sockaddr_in peerV4;
struct sockaddr_in clientV4;
rc = bind(fd,(struct sockaddr *) &clientV4,
sizeof clientV4);
//error handling
Send the packet data to server.
//update peer(server) socket info here
peerV4.sin_family = AF_INET;
peerV4.sin_port = htons(serverPort);
peerV4.sin_addr.s_addr = "x.x.x.x";
uint8_t *tBuf = (uint8_t *)malloc(sizeof (info)); //memset to zero
info *pHeader = (info *)tBuf;
pHeader->value = htonl(10); //local value to send
pHeader->end = htons(0);
pHeader->clientReq = "connect";
pheader->sub = "game1";
sendto(serverSock, tBuf, sizeof(info),0
,(struct sockaddr *) &peerV4,
sizeof(peerV4));
Send last packet and close local socket.
pHeader->end = htons(1); // so the server closes the socket
//send packet
close(fd);
On Server
1. Create a UDP socket, bind to a local address wait for client to send you the data and use recvfrom
fd = socket( family, SOCK_DGRAM, 0 );
//bind socket
uint8_t *recvBuf = (uint8_t *)malloc(sizeof(info));
info *pheader = (info *)recvBuf;
int currLen = recvfrom( fd, recvBuf,
mBufLen),0,(struct sockaddr *)&peerV4,
&sockaddrLen);
//error handling
if(currLen > 0)
{
if(htons(pheader->end) == 1)
//close socket
char *localSub = pheader->sub;
char *localRecv = pheader->clientReq;
//do something with the values on the server like
if (strcasecmp(localRecv,"connect") == 0) //pseudo
connect(sub,pheader->value)
}

send() and sendto() blocking in a file transfer program

it seems that when i use send() function (in a TCP file transfer program) like this
while((count = recv(socketConnection, buff, 100000, 0))>0)
myfile.write(buff,count);
the function recv() just waits untill the whole data comes and exits the loop when it is no more receiving any data but in a similar program for a UDP program
while((n = recvfrom(sockfd,mesg,1024,0,(struct sockaddr *)&cliaddr,&len))>0)
myfile.write(mesg,n);
the recvfrom() function just blocks and does not exit the loop for some reason, as far as i know both recv() and recvfrom() are blocking right?? Then why the difference. Does it have something to do with the functions or just the nature of TCP,UDP(which i guess is not a reason)??
P.S. Please help me understand this guys, I'm a newbie to socket programming and networking.
EDIT: full server program for both TCP and UDP
UDP server (with recvfrom() )
int i=0;
int sockfd,n;
struct sockaddr_in servaddr,cliaddr;
socklen_t len;
char mesg[1024];
sockfd=socket(AF_INET,SOCK_DGRAM,0);
bzero(&servaddr,sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr=htonl(INADDR_ANY);
servaddr.sin_port=htons(32000);
bind(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr));
ofstream myfile;
// fcntl(sockfd,F_SETFL,O_NONBLOCK);
myfile.open("2gb",ios::out);
while((n = recvfrom(sockfd,mesg,1024,0,(struct sockaddr *)&cliaddr,&len))>0)
myfile.write(mesg,n);
TCP (recv() ) server program
struct sockaddr_in socketInfo;
char sysHost[MAXHOSTNAME+1]; // Hostname of this computer we are running on
struct hostent *hPtr;
int socketHandle;
int portNumber = 8070;
//queue<char*> my_queue;
bzero(&socketInfo, sizeof(sockaddr_in)); // Clear structure memory
gethostname(sysHost, MAXHOSTNAME); // Get the name of this computer we are running on
if((hPtr = gethostbyname(sysHost)) == NULL)
{
cerr << "System hostname misconfigured." << endl;
exit(EXIT_FAILURE);
}
if((socketHandle = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
close(socketHandle);
exit(EXIT_FAILURE);
}
// std::cout<<"hi starting server";
socklen_t optlen;
int rcvbuff=262144;
optlen = sizeof(rcvbuff);
socketInfo.sin_family = AF_INET;
socketInfo.sin_addr.s_addr = htonl(INADDR_ANY);
socketInfo.sin_port = htons(portNumber); // Set port number
if( bind(socketHandle, (struct sockaddr *) &socketInfo, sizeof(socketInfo)) < 0)
{
close(socketHandle);
perror("bind");
exit(EXIT_FAILURE);
}
listen(socketHandle, 1);
int socketConnection;
if( (socketConnection = accept(socketHandle, NULL, NULL)) < 0)
{
exit(EXIT_FAILURE);
}
close(socketHandle);
time_start(boost::posix_time::microsec_clock::local_time());
int rc = 0; // Actual number of bytes read
int count=0;
char *buff;
int a=100000;
buff=new char[a];
ofstream myfile;
myfile.open("345kb.doc",ios::out|ios::app);
if(myfile.is_open())
{
long i=0;
while((count = recv(socketConnection, buff, 100000, 0))>0)
{
myfile.write(buff,count);
}}
the function recv() just waits untill the whole data comes and exits the loop when it is no more receiving any data
recv() on a TCP connection returns 0 when the sending side has closed the connection and this is the condition for your loop to terminate.
for a UDP program the recvfrom() function just blocks and does not exit the loop for some reason,
Because UDP is a connection-less protocol hence there is no special return code from recv() for a closed UDP connection. Unless someone sends you a 0-length datagram.
recv() will end the loop because at the other side the socket is closed, so recv() will return 0 (socket gracefully closed) whereas, recvfrom that does not have that signal, it does not know about closing, because it's an unconnected socket. It's stay there until it receives a packet or timeout, with UDP you need a way to tell that the communication is over (finish).

client socket unable to receive data using poll/select

/* SEND FUNC. */
int mysend(unsigned char *buffer, int len) {
int sock,ret;
int status,flags;
struct sockaddr_in6 servaddr;
int opt = 1;
char *addr = "1101::1";
sock = socket(AF_INET6,SOCK_DGRAM,0);
if (sock < 0)
return -1;
if( setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt)) < 0 )
return -1;
flags = fcntl(sock, F_GETFL, 0);
fcntl(sock, F_SETFL, flags|O_NONBLOCK);
servaddr.sin6_family = AF_INET6;
servaddr.sin6_port = htons(61616);
status = inet_pton(AF_INET6, addr, &servaddr.sin6_addr);
if (status <= 0) {
perror("inet_pton");
return -1;
}
/* send message to server */
status = sendto(sock, buffer, len, 0, (struct sockaddr *)&servaddr, sizeof(servaddr));
if (status < 0) {
perror("sendto");
return -1;
}
close(sock);
printf("MESSAGE SENT SUCCESSFULLY\n");
return 0;
}
/* RECEIVE FUNC. */
int myrcv() {
int sock,ret;
int status,len,rx_bytes;
int timeout,nfds =1;
struct sockaddr_in6 servaddr;
struct timeval wait;
unsigned char rxbuff[1024];
char *rcv;
char *addr = "1101::1";
fd_set rd;
struct pollfd *fds;
sock = socket(AF_INET6,SOCK_DGRAM,0);
if (sock < 0)
return -1;
servaddr.sin6_family = AF_INET6;
servaddr.sin6_port = htons(61616);
status = inet_pton(AF_INET6, addr, &servaddr.sin6_addr);
if (status <= 0)
return -1;
bind(sock,(struct sockaddr *)&servaddr,sizeof(servaddr));
timeout = (1* 1000);
wait.tv_sec = 10;
wait.tv_usec = 0;
len = sizeof(servaddr);
fds->fd = sock;
fds->events = POLLIN;
for(;;) {
//FD_ZERO(&rd);
//FD_SET(sock,&rd);
printf("Waiting for data....\n");
ret = poll(fds,nfds,timeout);
//ret = select(1,&rd,NULL,NULL,&wait);
if(ret < 0)
break;
if(fds->revents == 0)
printf("revents 0 %d\n",ret);
if(ret == 0)
continue;
memset(rxbuff,0,1024);
//if(FD_ISSET(sock,&rd)) {
printf("receiving message\n");
rx_bytes = recvfrom(sock,rxbuff,1024,0,(struct sockaddr *)&servaddr,&len);
memcpy(rcv,rxbuff,rx_bytes);
//}
}
close(sock);
return 0;
}
int main()
{
/* call mysend() periodically using sigaction() */
/* create a thread that continuously monitors(calls myrcv()) for incoming data */
return 0;
}
I'm unable to receive the packets from the server, but I could see the packets in the tcpdump output. Above are the sample client code snippets, which tries to receive and send the data from/to the server. The scenario is: the client needs to send data periodically to server and should also be able to receive any data from the server.
I have tried using both poll and select methods but failed to receive. Please let me know if I'm missing anything. Thanks for your support.
The problem you have with receiving is that you need to bind the receiving socket to the local port.
You also have other things that can be improved, like creating a single socket for both sending and receiving and using SO_REUSEADDR on the sending socket (not needed on a write-only socket).
What you should do is:
Create socket
Set socket options
Bind to local address (Use IN6ADDR_ANY_INIT to bind to all interfaces)
Write to server
Poll for reply
Several things:
Your receive function (myrcv) isn't specifying a listen port via the bind() call. That's the most likely problem. Ditto for your send function, although a port is chosen randomly for you.
In you myrcv() function, I don't see where you have actually initialized fds or nfsd prior to calling poll().
Re-opening and closing the socket on each call to mysend() looks problematic. If you are expecting the server to send back to the same client on the same port it received the message on, chances are high you have already closed the socket. You should just open one socket for both sending and receiving. You can share the same socket between your send thread and your receive thread.

Socket programming in C, using the select() function

Based from the answers I got from this thread, I've created this:
//Server
sock_init(); //from SFL, see http://legacy.imatix.com/html/sfl/
timeout = 50000;
serv_sock_input[0] = TCP(1234);
serv_sock_input[1] = UDP(9876);
input_protocols[0] = "tcp";
input_protocols[1] = "udp";
while (1)
{
FD_ZERO(&sock_set);
for (x = 0; x<number_of_inputs; x++)
{
FD_SET(serv_sock_input[x], &sock_set);
}
select_timeout.tv_sec = timeout;
select_timeout.tv_usec = 0;
if (select(0, &sock_set, NULL, NULL, &select_timeout) == 0)
printf("No requests");
else
{
for (x = 0; x<number_of_inputs; x++)
{
if (FD_ISSET(serv_sock_input[x],&sock_set))
{
printf("\nRequest on port %d: \n", x);
if ((strcmp(input_protocols[x],"tcp")) == 0) //in this case, 0 returned == TRUE
{
accept_socket(serv_sock_input[x]);
printf("Input TCP Port %d\n",x);
close_socket(serv_sock_input[x]);
}
else
{
printf("Input UDP Port %d\n",x);
}
}
}
}
}
sock_term();
}
int TCP (unsigned short port)
{
int sock;
struct sockaddr_in servAddr;
if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
exit(1);
memset(&servAddr, 0, sizeof(servAddr));
servAddr.sin_family = AF_INET;
servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
servAddr.sin_port = htons(port);
if (bind(sock, (struct sockaddr *) &servAddr, sizeof(servAddr)) < 0)
exit(1);
if (listen(sock, 5) < 0)
exit(1);
return sock;
}
int UDP (unsigned short port)
{
int sock; /* socket to create */
struct sockaddr_in servAddr; /* Local address */
/* Create socket for sending/receiving datagrams */
if ((sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
exit(1);
/* Construct local address structure */
memset(&servAddr, 0, sizeof(servAddr)); /* Zero out structure */
servAddr.sin_family = AF_INET; /* Internet address family */
servAddr.sin_addr.s_addr = htonl(INADDR_ANY); /* Any incoming interface */
servAddr.sin_port = htons(port); /* Local port */
/* Bind to the local address */
if (bind(sock, (struct sockaddr *) &servAddr, sizeof(servAddr)) < 0)
exit(1);
return sock;
}
//Client
sock_init();
if ((client_sock_output = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
exit(1);
memset(&client_addr, 0, sizeof(client_addr));
client_addr.sin_family = AF_INET;
client_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
client_addr.sin_port = htons(1234);
if (connect(client_sock_output, (struct sockaddr *) &client_addr, sizeof(client_addr)) < 0)
exit(1);
closesocket(client_sock_output);
sock_term();
When the server starts, the server gets blocked at the if(select(...)) statement.
So when I run the Server, and then the client, the client connects to the server (sometimes it takes a couple times to run the client before they connect). Then the if(select...)) statement is no longer true and it proceeds to the else.
After that, the client closes the connection, and the program. However, and this is where my problem happens, the if(select(...)) statement is always false. I get this output:
Request on port 0:
Input TCP Port 0
Request on port 1:
Input UDP Port 1
This output repeats forever. How come it doesn't get stuck at the if(select(...))?
You have two problems: you don't understand how accept() works in TCP, and you need to read the incoming data in UDP.
select() tells you that a listening socket has connection to accept, or reading socket has data to read.
For select to stop telling you this, you need to actually read the data or accept the connection.
In your UDP branch, you need to call receiv to actually get the data. If you don't, select will keep telling you that you have data.
In your TCP branch, you call accept_socket. I don't know what is your implementation of it, but it's most probably wrong to close the socket you just called accept() on. accept() returns a new socket for you - the one you should be using for IO. If anything needs to be closed, it's that new socket.
Please check why you have this in server.
if (select(0, &sock_set, NULL, NULL, &select_timeout) == 0)
replace it with
if (select(maxDescPlus1, &sock_set, NULL, NULL, &select_timeout) == 0)
where maxDescPlus1 --> is number of descriptors to select plus 1 value.

Resources