//Editor-Info: -*- C++ -*-
//
//Subject: TOVE project / TESTING
//
//File: svcsockettest.cpp
//
//Version: $Revision: 1.2 $
//
//State: $State: Exp $
//
//Date: $Date: 1999/03/02 14:39:17 $
//
//Organisation:
//      Helsinki University of Technology
//      Laboratory of Telecommunications Software and Multimedia
//
//Author:
//      Jussi Turunen
//
//Description:
//      Simple software to test SVC sockets.
//
//Copyright:
//      Copyright 1999 Helsinki University of Technology
//      ALL RIGHTS RESERVED BETWEEN JANUARY 1996 AND JUNE 1999.
//
//Licence:
//
//
//History: 

#include <typeinfo>
#include <string>

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <sys/uio.h>
#include <sys/socket.h>
#include <net/if.h>
#include <atm.h>
#include <time.h>
#include <iostream.h>

typedef const char * SAPnumber;
typedef const char * ATMnumber;

string getLocalTime(void)
{
    time_t currentTime;
    time(&currentTime);
    string currentTimeStr = ctime(&currentTime);
    return currentTimeStr;
}

void writeSocket(ATMnumber phoneno_, SAPnumber sap_)
{
    struct sockaddr_atmsvc addr;
    struct atm_qos qos;
    struct atm_blli blli;
    
    int descriptor = socket(PF_ATMSVC, SOCK_DGRAM, 0);
    if (descriptor < 0)
    {
        cerr << "toveATM: Error in atmconnect" << endl;
        perror("socket");
        exit(1);
    }

    memset(&qos, 0, sizeof(qos));
    qos.aal = ATM_AAL5;
    qos.txtp.traffic_class = qos.rxtp.traffic_class = ATM_UBR;
    qos.txtp.max_sdu = qos.rxtp.max_sdu = 160;
    if (setsockopt(descriptor, SOL_ATM, SO_ATMQOS, &qos, sizeof(qos)) < 0)
    {
        cerr << "toveATM: Error in atmconnect" << endl;
        perror("setsockopt");
        exit(1);
    }

    memset(&addr, 0, sizeof(addr));
    addr.sas_family = AF_ATMSVC;

    if (text2atm(phoneno_, (struct sockaddr *)&addr, sizeof(addr), T2A_SVC) < 0)
    {
        cerr << "toveATM: Error in atmconnect" << endl;
        perror("text2atm");
        exit(1);
    }

    /* Define the SAP in the BLLI */
    memset(&blli, 0, sizeof(struct atm_blli));
    blli.l2_proto = ATM_L2_NONE;
    blli.l3_proto = ATM_L3_USER;
    blli.l3.user = (unsigned char) atoi(sap_);
    blli.next = 0;

    cerr << "Called addr " << phoneno_ << " SAP " << sap_ << endl;
    
    string timeLabel = getLocalTime();
    string lahete;
    cout << "enter text: ";
    cin >> lahete;

    lahete = timeLabel + lahete;

    cout << "lahete: " << lahete << endl;
    
    if (::connect(descriptor, (struct sockaddr *) &addr, sizeof(addr)) < 0)
    {
        cerr << "toveATM: Error in atmconnect" << endl;
        perror("connect");
        exit(1);
    }

    if((write(descriptor, lahete.c_str(), lahete.length())) == -1)
    {
	perror("read");
	exit(1);
    }    

    if (::close(descriptor) < 0)
    {
        cerr << "toveATM: Error in atmlisten" << endl;
        perror("close (lsoc)");
        exit(1);
    }    

    return;
}


void readSocket(SAPnumber sap_)
{
    struct sockaddr_atmsvc addr;
    struct atm_qos qos;
    struct atm_blli blli;

    int descriptor = socket(PF_ATMSVC, SOCK_DGRAM, 0);
    if (descriptor < 0)
    {
        cerr << "toveATM: Error in atmlisten" << endl;
        perror("socket");
        exit(1);
    }

    memset(&qos, 0, sizeof(qos));
    qos.aal = ATM_AAL5;
    qos.txtp.traffic_class = ATM_ANYCLASS;
    qos.rxtp.traffic_class = qos.txtp.traffic_class;
    if (setsockopt(descriptor, SOL_ATM, SO_ATMQOS, &qos, sizeof(qos)) < 0)
    {
        cerr << "toveATM: Error in atmlisten" << endl;
        perror("setsockopt");
        exit(1);

    }

    memset(&addr, 0, sizeof(addr));
    addr.sas_family = AF_ATMSVC;

    /* Define the SAP in the BLLI */
    memset(&blli, 0, sizeof(blli));
    blli.l2_proto = ATM_L2_NONE;
    blli.l3_proto = ATM_L3_USER;
    blli.l3.user = (unsigned char) atoi(sap_);
    blli.next = 0;

    if (::bind(descriptor, (struct sockaddr *) &addr, sizeof(addr)) < 0)
    {
        cerr << "toveATM: Error in atmlisten" << endl;
        perror("bind");
        exit(1);
    }
    
    if (::listen(descriptor, 1) < 0)
    {
        cerr << "toveATM: Error in atmlisten" << endl;
        perror("listen");
        exit(1);
    }
    
    int realDescriptor = 0;
    unsigned int addrlen;
    if ((realDescriptor =
        ::accept(descriptor, (struct sockaddr *) &addr, &addrlen)) < 0)
    {
        cerr << "toveATM: Error in atmlisten" << endl;
        perror("accept");
        exit(1);
    }
    
    if (::close(descriptor) < 0)
    {
        cerr << "toveATM: Error in atmlisten" << endl;
        perror("close (lsoc)");
        exit(1);
    }
    
    char luettu[80] = "\0";
    
    int readBytes = 0;
    if((readBytes=read(realDescriptor, luettu, 80)) == -1)
    {
	perror("read");
	exit(1);
    }
    
    cout << "read from socket: " << luettu << endl;
    cout << "read " << readBytes << " bytes." << endl;
    
    if (::close(realDescriptor) < 0)
    {
        cerr << "toveATM: Error in atmlisten" << endl;
        perror("close real (lsoc)");
        exit(1);
    }

    return;
}

void usage(const char *argv_)
{
    cout << "Writemode usage:" << endl;
    cout << argv_ << " w NSAP" << endl;
    
    cout << "Readmode usage:" << endl;
    cout << argv_ << " r" << endl;
    
    cout << "Note! addresses from current /etc/hosts.atm are used as NSAPs" 
         << endl;
    exit(1);
}

int main(int argc, char *argv[])
{
    SAPnumber defaultSAP = "100";  
  
    if (argc == 1)
    {
        usage(argv[0]);
    }
    
    if (argv[1][0] == 'r')
    {
        if (argc == 2)
        {
            readSocket(defaultSAP);
        }
        else
        {
            usage(argv[0]);
        }
    }
    else if (argv[1][0] == 'w')
    {
        if (argc == 3)
        {
            writeSocket(argv[2], defaultSAP);
        }
        else
        {
            usage(argv[0]);
        }
    }
    else 
    {
        cout << "Illegal mode, allowed modes read(r) or write(w)" << endl;
	usage(argv[0]);
        exit(1);
    }
    
    return 1;
}
