#!/usr/local/bin/perl -Tw ###################################################################### # server.pl # Tom Kelliher, CS 318 # # This program is a demonstration of a simple server application. The # server merely returns a brief message reporting the number of times # it has been contacted. It works with its companion program, # client.pl, as well as telnet. # # By default, the server binds to port 50001. This can be changed by # providing a port number on the command line. # # After binding to the port, the server enters an infinite loop. Use # ^C to terminate the server. # # Note that taint checking (-T) has been enabled in addition to the # standard warnings (-w) on the shebang line. ###################################################################### # Initial declarations. require 5.002; use strict; use sigtrap; # Use some basic signal traps. use Socket; # Use the socket library. # Globals. my $SERVER_PORT = 50001; # Default server port. # Prototypes. sub TERM_handler(); $SIG{'INT'} = 'TERM_handler'; # Install a ^C handler. ###################################################################### # MAIN ###################################################################### MAIN: { my $sport = shift || $SERVER_PORT; # Server port. my $proto; # TCP protocol number. my $paddr; # Packed address (port # and # IP address). my $cport; # Client port. my $cipaddr; # Client IP address. my $chostname; # Client hostname; my $visits = 0; # Number of client visits; # If we've taken a port number from the command line, it's now # tainted. If it is only digits, we'll go ahead and untaint it. if ($sport =~ /^(\d+)$/) { $sport = $1; } else { die "Bad data in server port: $sport.\n"; } $proto = getprotobyname("tcp"); # Get the TCP protocol number. # Attempt to create a socket. SOCK is the handle. This socket # uses a protocol family of Internet, it's a stream socket, and it's # a TCP socket. socket(SOCK, PF_INET, SOCK_STREAM, $proto) or die "Socket: $!"; # Set the option bit allowing us to reuse the port number. setsockopt(SOCK, SOL_SOCKET, SO_REUSEADDR, 1) or die "Setsockopt: $!"; # Attempt to bind the socket to the port, using any available # ethernet interface (IP address). bind(SOCK, sockaddr_in($sport, INADDR_ANY)) or die "Bind: $!"; # Set the length of the request queue to the maximum value (64). listen(SOCK, SOMAXCONN); print "Server started on port $sport.\n\n"; while (1) # Enter the server loop. { # Wait for, and accept, a connection from a client. accept() # returns the packed address (port # and IP address) of the # client. SOCK is the socket we listen on. CLIENT is the socket # we use to communicate with the client. $paddr = accept(CLIENT, SOCK); # Unpack the address. ($cport, $cipaddr) = sockaddr_in($paddr); # Attempt to get the client's hostname by reverse DNS mapping # its IP address. $chostname = gethostbyaddr($cipaddr, AF_INET) || "Could not resolve hostname"; ++$visits; print "Client Hostname: $chostname \[", inet_ntoa($cipaddr), "\]\n"; print "Client Port: $cport\n"; print "Visit: $visits.\n\n"; # Send a message to the client. The third parameter to send() # is option bits, ordinarily 0. send(CLIENT, "This server has been contacted $visits times.\n", 0); close(CLIENT); } exit 0; } ###################################################################### # TERM_handler # # This subroutine provides a very basic signal handler for the # TERM signal, ^C. All it does is close any open sockets and exit. ###################################################################### sub TERM_handler() { print "\nTerminating.\n"; close CLIENT; close SOCK; exit 0; }