echo client using threads



WANTED: This program is a TCP echo server-client. server is written using
poll() while client is written using threads.

1.) server recv()s some characters from a client and then echoes the
characters to all clients except the one who sent it.

2.) client has 2 threads, one thread send()s something to the server
once, 2nd thread waits infinitely for recv(), as I want the thread to
remain connected to recv() the input.


PROBLEM: one client disconnects as soon as another connects. after that
no client remains connected. After 2 or 3 attempts server
disconnects too.

I am at the bginning stage of learning TCP/IP things, as you already know
and most of the things I have written do not make much sense to me. e.g. I
do know what socket(), bind(), listen(), connect(), send() and recv() work
but I do not have much idea about how poll() works and when server poll()
starts etc. I just did it as told in UNP volume 1.


--------------------------- poll-server.c ------------------------------------
/* A server handeling multiple clients using poll()

VERSION: 1.1

*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <poll.h>

#define SERVER_IP "127.0.0.1"

enum { ARRSIZE = 101, BACKLOG = 100, OPEN_MAX = 12 };

int main( int argc, char** argv )
{
int sockfd, accept_fd, tempfd, myport;
struct sockaddr_in servaddr, cliaddr;
socklen_t clilen;
char arrc[ARRSIZE];

/* preparations for poll() */
struct pollfd clients[OPEN_MAX];
int i, j, recv_bytes, nready;
int curr_index, max_index;

/* clear the array and the address structures */
memset( arrc, '\0', ARRSIZE );
memset( &servaddr, '\0', sizeof(servaddr) );
memset( &cliaddr, '\0', sizeof(cliaddr) );

if( argc != 2 )
{
fprintf(stderr, "USAGE: ./file PORT\n");
exit( EXIT_FAILURE );
}
else
{
myport = atoi( argv[1] );
}

if( (sockfd = socket(PF_INET, SOCK_STREAM, 0)) < 0 )
{
perror("SOCKET() error\n");
exit( EXIT_FAILURE );
}

servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(myport);
if( inet_pton(AF_INET, SERVER_IP, &servaddr.sin_addr) <= 0 )
{
perror("inet_pton: error\n");
exit(EXIT_FAILURE);
}

if( bind(sockfd, (struct sockaddr*)&servaddr, sizeof(struct sockaddr)) < 0 )
{
perror("BIND() error\n");
exit( EXIT_FAILURE );
}

if( listen(sockfd, BACKLOG) < 0 )
{
perror("LISTEN() error\n");
exit( EXIT_FAILURE );
}


/* poll() initialisation */
clients[0].fd = sockfd;
clients[0].events = POLLIN;
max_index = 0;
curr_index = 0;

for(i = 1; i < OPEN_MAX; ++i )
{
clients[i].fd = -1;
}

/* here we start to accept connections */
for( ; ; )
{
if( (nready = poll(clients, max_index + 1, -1)) <= 0 )
{
perror("can not POLL()");
exit( EXIT_FAILURE );
}


if( clients[0].revents & POLLIN )
{
clilen = sizeof( cliaddr );
accept_fd = accept(sockfd, (struct sockaddr*)&cliaddr, &clilen);

printf("ACCEPT()ed \n");

/* check if the poll() is full of connections
this solution is buggy */
if( curr_index > OPEN_MAX )
{
fprintf(stdout, "I am not supposed to accept more than %d connections\n", OPEN_MAX);
continue;
}

/* add the new FD to the poll() */
for( i=1; i < OPEN_MAX; ++i )
{
if( clients[i].fd < 0 )
{
clients[i].fd = accept_fd;
printf("added FD#%d in clients[%d]\n", clients[i].fd, i);
break;
}
}

curr_index = i;

printf("curr_index = %d\n", curr_index);

/* After the check, now we can add to events */
clients[curr_index].events = POLLIN;

if( (curr_index > max_index) && (curr_index < OPEN_MAX) )
{
max_index = curr_index;
}

if( --nready <= 0 )
{
continue;
}



} /* if condition for checking connection is done with */


/* now we check & read the data */
for( i = 1; i <= max_index; ++i )
{
if( (tempfd = clients[i].fd) < 0 )
{
continue;
}

if( clients[i].revents & (POLLIN | POLLERR) )
{
if( (recv_bytes = recv(tempfd, arrc, ARRSIZE, 0)) <= 0 )
{
perror("remote-client CLOSED the connection.");
close( tempfd );
tempfd = -1;
}
else
{
printf("RECV()ed Data...\n");
/* here we we will send this data to every accepted file-decriptor
stored on poll array named clients. We do so using a for loop
till we hit the max_index.
*/
for( j=1; j <= max_index; j++ )
{
if( clients[j].fd > 0 )
{
/* this prevents the server to write back to the client who sent the message.
* we only need to write to all other clients except the one who sent the
* data to server. */
if( i != j )
{
if( send( clients[j].fd, arrc, ARRSIZE, 0 ) < 0 )
{
fprintf(stdout, "SEND() error to # %d\n", clients[j].fd);
}
else
{
printf("written to %d, FD# %d\t i = %d, iFD#= %d\n", j, clients[j].fd, i, clients[i].fd);
}
}
}
}
}


printf("::\n");
if( --nready <= 0 )
{
break;
}
}

}
}

return 0;

}



--------------------------- thread-client.c ------------------------------------
/* a client using threads to send() and recv() messages to and from server */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <poll.h>
#include <pthread.h>


#define SERVER_IP "127.0.0.1"

enum { ARRSIZE = 101, FD_ARRSIZE = 1 };


static void* send_function( void * );
static void* recv_function( void * );


int main( int argc, char* argv[] )
{
int sockfd, myport;
struct sockaddr_in cliaddr;

memset( &cliaddr, '\0', sizeof(struct sockaddr_in) );

/* thread preparations */
pthread_t tid_send, tid_recv;


if( 2 == argc )
{
myport = atoi( argv[1] );
}
else
{
perror("USAGE: ./file PORT");
exit( EXIT_FAILURE );
}


cliaddr.sin_family = AF_INET;
cliaddr.sin_port = htons(myport);
if( inet_pton( AF_INET, SERVER_IP, &cliaddr.sin_addr) <= 0 )
{
perror("INET_PTON() error");
exit( EXIT_FAILURE );
}


if( (sockfd = socket(PF_INET, SOCK_STREAM, 0)) < 0 )
{
perror("SOCKET error");
exit( EXIT_FAILURE );
}

if( connect(sockfd, (struct sockaddr*) &cliaddr, sizeof(struct sockaddr)) < 0 )
{
perror("CONNECT() error :\\ ");
exit( EXIT_FAILURE );
}



pthread_create( &tid_send, NULL, &send_function, (void *) sockfd );
pthread_create( &tid_recv, NULL, &recv_function, (void *) sockfd );

pthread_join( tid_send, NULL);
pthread_join( tid_recv, NULL);


return 0;
}




static void* send_function( void* sockfd )
{
int i;
char arrc[ARRSIZE] = "This is from client-side\n";
int connfd = (int) sockfd;


/* poll() preparation */
struct pollfd fd_array[FD_ARRSIZE];
int nready;

/* poll initialization */
fd_array[0].fd = connfd;
fd_array[0].events = POLLOUT;


for( i = 0; i != 1; ++i )
{
if( (nready = poll( fd_array, 1, -1 )) <= 0 )
{
perror("can not POLL()\n");
exit( EXIT_FAILURE );
}

if( fd_array[0].revents & POLLOUT )
{
if( send(connfd, arrc, strlen(arrc), 0) < 0 )
{
perror("SEND() error");
exit( EXIT_FAILURE );
}
}


if( --nready <= 0 )
{
break;
}

}


return (NULL);
}


static void* recv_function( void* sockfd )
{
char arrc[ARRSIZE];
int connfd = (int) sockfd;

/* poll() preparation */
struct pollfd fd_array[FD_ARRSIZE];
int nready;

/* poll initialization */
fd_array[0].fd = connfd;
fd_array[0].events = POLLIN;


for( ; ; )
{
if( (nready = poll( fd_array, 1, -1 )) <= 0 )
{
perror("can not POLL()\n");
exit( EXIT_FAILURE );
}

if( fd_array[0].revents & POLLIN )
{
if( recv(connfd, arrc, ARRSIZE, 0) < 0 )
{
perror("RECV() error");
exit( EXIT_FAILURE );
}

printf("%s\n", arrc);

}

if( --nready <= 0 )
{
break;
}
}


return (NULL);
}





--
www.lispmachine.wordpress.com
my email is @ the above blog
check the "About Myself" page

.



Relevant Pages

  • RE: SSPI Kerberos for delegation
    ... you have to check on 'trust this machine for delegation' in the server computer's ADUC property page. ... Doing this will tell the client kerberos package that it should get a forwardable ticket and that it should forward it ... int n = ib.cbBuffer; ... // wserr() displays winsock errors and aborts. ...
    (comp.protocols.kerberos)
  • [NT] Dark Age of Camelot Man-In-The-Middle
    ... use of RSA public key cryptography and an RC4 based symmetric algorithm. ... Seeing the imminent release of code for cracking the game client (which ... At the beginning of each TCP session, the server sends a 1536 bit RSA ... void bytes_out(unsigned char *data, int len) ...
    (Securiteam)
  • Re: Problem with SslStream when using Windows Vista
    ... The code for the server & client follow. ... private int _port = 0; ... // SslStream using the client's network stream. ...
    (microsoft.public.dotnet.framework)
  • [UNIX] Multiple up-imapproxy DoS Vulnerabilities
    ... The following security advisory is sent to the securiteam mailing list, and can be found at the SecuriTeam web site: http://www.securiteam.com ... connections open after client has logged out, ... allows attacker to cause the server to crash by sending them when they ... extern void HandleRequest(int); ...
    (Securiteam)
  • TCP server eating up the whole CPU
    ... A TCP server using polland a threaded-client to send the messages to ... int main ... exit(EXIT_FAILURE); ... memset(&servaddr, '\0', sizeof(struct sockaddr_in)); ...
    (comp.unix.programmer)