distTLI/tcpserver.c

///////////////////////////////////////////////////////////////////////////////
// Filename: tcpserver.c
///////////////////////////////////////////////////////////////////////////////
// Purpose: show how to use TCP (this file: TCP server) (TLI version)
//          uses tcpclient(.c) as TCP client
///////////////////////////////////////////////////////////////////////////////
// History:
// ========
//
// Date     Time     Name      Description   
// -------- -------- --------  ------------------------------------------------
// 96/02/26 13:52:19 muellerg: created
//
///////////////////////////////////////////////////////////////////////////////


// Feature test switches ///////////////////////////// Feature test switches //
    /* NONE */



// System headers /////////////////////////////////////////// System headers //

#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#ifndef sun
#include <strings.h>
#endif
#include <unistd.h>

#include <tiuser.h> 
#include <sys/types.h>
#include <sys/socket.h>
// #include <sys/in.h>              

#ifdef sun
// O_RDWR
#include <sys/fcntl.h>
#endif
#include <sys/wait.h>


// Local headers ///////////////////////////////////////////// Local headers //

#include "../common.h"



// Macros /////////////////////////////////////////////////////////// Macros //
    /* NONE */



// File scope objects /////////////////////////////////// File scope objects //
    /* NONE */



// External variables, functions, and classes ///////////// External objects //

int accept_call(int listenfd, struct t_call *callptr, char *name, int rwflag);



// Signal catching functions ///////////////////// Signal catching functions //
    /* NONE */



// Structures, unions, and class definitions /////////////////// Definitions //
    /* NONE */



// Functions and class implementation /// Functions and class implementation //


/*
 * Read a stream socket one line at a time, and write each line back
 * to the sender.
 *
 * Return when the connection is terminated.
 */

void
do_it(int sockfd)
{
    int n;
    char buffer[MAXLINE];

    while(true)
    {
        n = readline(sockfd, buffer, MAXLINE);
        if (n == 0)
            return;     // connection terminated 
        else
            if (n < 0)
                error.system("str_echo: readline error");

        if (writen(sockfd, buffer, n) != n)
            error.system("str_echo: writen error");
    }
}


// Main /////////////////////////////////////////////////////////////// Main //

/*
 * Example of server using TCP protocol. This program is lightly based on
 * example programs in [Stev90]
 *
 * paramteters:
 *
 *   argv[1]: port number to bind() & listen() to
 */

int 
main(int argc, char *argv[])
{
    error.set_program_name(argv[0]);    

    if(argc!=2)
    {
        cerr << "Usage: " << argv[0] << " port" << endl;
        exit(EXIT_FAILURE);
    }

    // establish a function that changes the signalhandler
    // to report child death so that they can be catched and
    // zombie processes are avoided

#ifndef hpux
    catch_children();
#endif

    int tfd, newtfd, clilen, childpid;
    struct sockaddr_in cli_addr, serv_addr;
    struct t_bind req;
    struct t_call *callptr;

    int portnumber = -1;

    // get port number

    portnumber = atoi(argv[1]);
    if(portnumber <1)
    {
        cerr << "illegal port number" << endl;
        exit(EXIT_FAILURE);
    }


    // create a TCP transport endpoint.

    if ( (tfd = t_open(DEV_TCP, O_RDWR, (struct t_info *) 0)) < 0)
    {
        error.warning("server: can't t_open %s", DEV_TCP);
        exit(EXIT_FAILURE);
    }

    // Bind our local address so that the client can send to us.

    bzero((char *) &serv_addr, sizeof(serv_addr));
    serv_addr.sin_family      = AF_INET;
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    serv_addr.sin_port        = htons(portnumber);

    req.addr.maxlen = sizeof(serv_addr);
    req.addr.len    = sizeof(serv_addr);
    req.addr.buf    = (char *) &serv_addr;
    req.qlen        = 5;

    if (t_bind(tfd, &req, (struct t_bind *) 0) < 0)
        error.system("server: can't t_bind local address");

    // Allocate a t_call structure for t_listen() and t_accept().

    if ( (callptr = (struct t_call *) t_alloc(tfd, T_CALL, T_ADDR)) == NULL)
        error.system("server: t_alloc error for T_CALL");

    while(true)
    {
        // check for zombies

        waitpid(WAIT_ANY, NULL, WNOHANG);


        // Wait for a connection from a client process.
        // This is an example of a concurrent server.

        if (t_listen(tfd, callptr) < 0)
            error.system("server: t_listen error");

        if ( (newtfd = accept_call(tfd, callptr, DEV_TCP, 1)) < 0)
            error.system("server: accept_call error");

        if ( (childpid = fork()) < 0)
            error.system("server: fork error");

        else if (childpid == 0)
             {  /* child process */
                t_close(tfd);       // close original endpoint 

                do_it(newtfd);      // process the request 

               exit(EXIT_SUCCESS);
             }

        close(newtfd);      /* parent process */
    }
}