qclient.cc
/* $Id: qclient.cc,v 1.2 2002/04/07 19:21:46 vickery Exp $
*
* This is a client program that acts as the intermediary between
* the user and the qserver program for the Remote Shell Project.
*
* Functions:
*
* main() Main function for the module.
*
* CS-701, Spring 2002
* C. Vickery
*
*
* $Log: qclient.cc,v $
* Revision 1.2 2002/04/07 19:21:46 vickery
* Changed default host name from "localhost"
* to local host's name. This way, the client
* can connect to a server running on the local
* machine without using the -h option.
*
* Revision 1.1 2002/03/28 19:57:51 vickery
* Initial revision
*
*
*/
#include "qclient.h"
#include <getopt.h>
#include <netdb.h>
#include <netinet/in.h>
#include <poll.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
// Constants
// ------------------------------------------------------------------
static const int HOSTNAME_MAX = 64;
static const int BUF_SIZE = 8192;
static const char *VERSION =
"$Id: qclient.cc,v 1.2 2002/04/07 19:21:46 vickery Exp $";
// Module Globals
// ------------------------------------------------------------------
static char hostName [ HOSTNAME_MAX ];
static char serverName[ HOSTNAME_MAX ];
// usage()
// ------------------------------------------------------------------
/*
* Display usage message
*/
void
usage( const char *cmdName )
{
fprintf( stderr,
"Usage: %s [options]n"
" Options:n"
" -p or --port <num> "
" Server's port number (default 0x8000)n"
" -h or --host <str> "
" Server's host name (default %s)n"
" -v or --version Print program version number and exitn"
" -? or --help Print this message and exitn",
cmdName, hostName );
}
// main()
// ------------------------------------------------------------------
/*
* Process command line arguments, establish communcation with
* server, and manage interactions between the user and the server.
*
* Arguments
*
* The standard arguments to main().
*/
int
main(int argc, char *argv[], char * envp[] )
{
// Get this host's name for default server name.
int result = gethostname( hostName, sizeof( hostName ) );
if ( result < 0 )
{
perror( "Unable to determine local host name" );
exit( 1 );
}
strcpy( serverName, hostName );
// Process command line options
int serverPort = 0x8000;
const char *short_options = "p:h:?v";
const struct option long_options[] =
{
{ "port", required_argument, 0, 'p' },
{ "host", required_argument, 0, 'h' },
{ "help", no_argument, 0, '?' },
{ "version", no_argument, 0, 'v' },
{ 0, 0, 0, 0 },
};
int optchar;
while ( -1 != ( optchar = getopt_long( argc, argv, short_options,
long_options, 0 ) ) )
{
switch ( optchar )
{
// Server's well-known port number
case 'p':
serverPort = strtol( optarg, 0, 0 );
if ( ( serverPort < 0 ) || ( serverPort > 0xFFFF ) )
{
fprintf( stderr, "%s: invalid port numbern", optarg );
usage( argv[0] );
exit( 1 );
}
break;
// Server's host name
case 'h':
strcpy ( serverName, optarg );
break;
// Version number
case 'v':
printf( "%s: %sn", argv[0], VERSION );
exit( 0 );
case '?':
default :
usage( argv[0] );
exit( 1 );
}
}
#ifdef DEBUG
fprintf( stderr, " Host: %sn Port: 0x%04X (%d)n",
serverName, serverPort, serverPort );
#endif
// Connect to the server
struct hostent *hp;
if ( 0 == (hp = gethostbyname( serverName ) ) )
{
fprintf( stderr,"%s: %s: unknown hostn", argv[ 0 ], serverName );
exit( EXIT_FAILURE );
}
struct sockaddr_in server_sockaddr;
memset( &server_sockaddr, 0, sizeof( server_sockaddr ) );
server_sockaddr.sin_family = AF_INET;
memcpy( &server_sockaddr.sin_addr, hp->h_addr, hp->h_length );
server_sockaddr.sin_port = htons( serverPort );
int server_fd;
if ( ( server_fd = socket( AF_INET, SOCK_STREAM, 0 ) ) < 0 )
{
perror( "socket" );
exit( EXIT_FAILURE );
}
if ( connect( server_fd, (struct sockaddr *) &server_sockaddr,
sizeof ( server_sockaddr ) ) < 0 )
{
perror( "connect" );
exit( EXIT_FAILURE );
}
printf( "Connected to %s:%dn", serverName, serverPort );
// Initialize the array of pollfds
struct pollfd fds_to_read[2];
fds_to_read[0].fd = fileno( stdin );
fds_to_read[0].events = POLLIN;
fds_to_read[1].fd = server_fd;
fds_to_read[1].events = POLLIN;
// Allow the user to exchange text messages with the server.
// Continue until server closes its end of the socket.
char inBuf[ BUF_SIZE ];
int bytesRead = 0;
for ( ;; )
{
if ( poll( fds_to_read, 2, -1 ) < 0 )
{
perror( "poll" );
exit( EXIT_FAILURE );
}
// Process a server message, if there is one
if ( fds_to_read[1].revents & POLLIN )
{
bytesRead = read( server_fd, inBuf, sizeof ( inBuf ) );
if ( bytesRead < 0 )
{
perror("socket read");
exit( EXIT_FAILURE );
}
if ( 0 == bytesRead )
{
printf( "exit: server closed connectionn" );
exit( EXIT_SUCCESS );
}
// Write to stdout exactly what the server wrote to our socket.
inBuf[ bytesRead ] = '0';
printf( "%s", inBuf );
fflush( stdout );
}
// Process a user message, if there is one
if ( fds_to_read[0].revents & POLLIN )
{
if ( feof( stdin ) )
{
close(server_fd);
exit(EXIT_SUCCESS);
}
bytesRead = read( STDIN_FILENO, inBuf, sizeof( inBuf ) );
if ( 0 == bytesRead )
{
// End of user input
close( server_fd );
exit( 0 );
}
while ( ( bytesRead >= 0 )
&& ( ( 'r' == inBuf[ bytesRead - 1 ] )
|| ( 'n' == inBuf[ bytesRead - 1 ] ) ) )
{
inBuf[ --bytesRead ] = '0';
}
write( server_fd, inBuf, bytesRead );
}
}
}