Main Page | Class Hierarchy | Class List | File List | Class Members

Open Diameter C++ API

Version1.0.7

Author:
Victor I. Fajardo
Date:
June 25, 2004
This document is a general descripton of the Open Diameter C++ API. The C++ API in this release (1.0.7) is essentially the same as release (1.0.5). Minor modification has occured in terms of the API itself due to the introduction of the framework template.

Changes

Server Session Accept(..) method is deprecated

As of this release, the Accept() method that is invoked upon determination of successful authentication/authorization by a server session is no longer required and has been removed from the API. This has been replace by invoking Update(EVENT_AUTH_SUCCESS) to clarify the usage of EVENT_AUTH_SUCCESS in the server session. Users MUST now invoke Update(EVENT_AUTH_SUCESS) in place of Accept().

Client Session invoking Update(EVENT_AUTH_REQUEST)

As of this release, client applications are no longer required to invoke ClientSession->Update(AAASession::EVENT_AUTH_REQUEST) upon sending or completing an authorization/authentication request message. The library will handle the event notification internally since it is un-natural for the application to be resposible for invoking this method.

Session Event Handler

Additional timer event handlers has been added to allow applications to capture specific timer expirations such as authorization lifetime and grace period. The following is a summary of all the event handler methods available. Note that this are also documented in the succeeding AAAEventHandler class documentation. See the sample code for specifics on capturing these events.

This is invoked by the library when an incomming message needs to be delivered to the application. This event occurs only after a valid message with a session id matching the session id of this session object has been received. The msg argument is pre-allocated by the library and is valid only within the context of this method. It is the responsibility of the derived class to override this function and capture this events.

This is invoked by the library during session disconnect event. Disconnection event occurs when a session is terminated because of network connectivity failure. For the library, this means that all transport connections to all peers has been lost. Note that this event can occur at any moment after the application core has been started even prior to any session transmitting or receiving messages. It is the responsibility of the derived class to override this function and capture this events.

This is invoked by the library if session timeout negotiated between the client and server expires. Note that the values are based on Session-Timeout AVP's exchange between client and server with initial values dictated by configuration entries. It is the responsibility of the derived class to override this function and capture this events if it is interested in it.

This is invoked by the library if authorization lifetime negotiated between the client and server expires. Note that the values are based on Authorization-Lifetime AVP's exchange between client and server with initial values dictated by configuration entries. It is the responsibility of the derived class to override this function and capture this events if it is interested in it.

This is invoked by the library if authorization grace period negotiated between the client and server expires. Note that the values are based on Authorization-Grace-Period AVP's exchange between client and server with initial values dictated by configuration entries. It is the responsibility of the derived class to override this function and capture this events if it is interested in it.

This is invoked by the library during session abort event. An abort occurs when the server decides to terminate the client session by sending an ASR to the client session. The library will process the ASR message and notify the application that the server wishes to abort the session via this handler. It is the responsibility of the derived class to override this function and capture this event.

Notes

Automatically Generated AVP's

The Open Diameter library automatically appends the following AVP's into an outgoing message:

The Session-Id AVP is automatically generated and appended by the Open Diameter library. For client sessions, the library will generate a new session id for each session. For server sessions, it will extract the session id from initial incomming authentication/authorization request. Applications that appends a Session-Id AVP and assign their own value will have that value over-written by the library.

The Auth-Session-State AVP in the client or server message based on the configuration settings and the rules defined by RFC 3588. For the server, if the configuration entry for a stateful session is not present then it will not be included by the library and will assume that all sessions will be stateless. If the entry is present, then the AVP will be appended and the value of the setting will be binding for the server, i.e. the server will be statefull or stateless depending on that value. For the client, the configuration entry (or it's absence) will also initially dictate the presence of Auth-Session-State AVP in the message but the AVP value set by the server will be binding.

The Authorization-Lifetime AVP is appended to the server message by the library if a configuration entry is present for session lifetime and if the application has not already added a valid Authorization-Lifetime AVP to the message. If a valid value is already present, then the library performs no action.

As with the Authorization-Lifetime AVP, Auth-Grace-Period will be added to the server message if a grace period entry is present in the configuration file and if the application has not already added a valid Auth-Grace-Period to the message. If a valid value is already present, then the library performs no action.

As with the Authorization-Lifetime AVP, the Session-Timeout AVP will be added to the server message if a session timeout entry is present in the configuration file and if the application has not already added a valid Session-Timeout AVP to the message. If a valid value is already present, then the library performs no action.

Rounds of Authorization/Authenticaion Request/Answer

To support multiple rounds of request and answer message exchange between client and server, applications must invoke Update(EVENT_AUTH_SUCCESS) method of the client session object upon successful processing and completion of the message exchanges. This procedure is valid only for client sessions (as shown in the example code) wether a single or multiple rounds of authenticaton/authorization of request/answer messages are exchanged. For clients, the call to Update(EVENT_AUTH_SUCCESS) method after successful authentication/authorization will notify the Open Diameter library that the current "Pending" state needs to switch to an "Open" state which then performs necessary operations such as start session timers. For server, there is no need for applications to invoke Update() methods. The server session factory will create instances of server sessions with each initial authentication/authorization request for that session. The initial state of the server session would then be "Idle" and one or more messages exchanges may occur until the application decides that the peer is authorized/authenticated and it invokes Accpet() method. This will switch the server session state into "Open". If the peer is not authorized, the application can simply delete the server session.

Server Application Sample Code

This document uses sample code to desribe usage of the C++ API. The code below provides ample comments on describing API usage.

Server Header File

/* BEGIN_COPYRIGHT                                                        */
/*                                                                        */
/* Open Diameter: Open-source software for the Diameter and               */
/*                Diameter related protocols                              */
/*                                                                        */
/* Copyright (C) 2002-2004 Open Diameter Project                          */
/*                                                                        */
/* This library is free software; you can redistribute it and/or modify   */
/* it under the terms of the GNU Lesser General Public License as         */
/* published by the Free Software Foundation; either version 2.1 of the   */
/* License, or (at your option) any later version.                        */
/*                                                                        */
/* This library is distributed in the hope that it will be useful,        */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of         */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU      */
/* Lesser General Public License for more details.                        */
/*                                                                        */
/* You should have received a copy of the GNU Lesser General Public       */
/* License along with this library; if not, write to the Free Software    */
/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307    */
/* USA.                                                                   */
/*                                                                        */
/* In addition, when you copy and redistribute some or the entire part of */
/* the source code of this software with or without modification, you     */
/* MUST include this copyright notice in each copy.                       */
/*                                                                        */
/* If you make any changes that are appeared to be useful, please send    */
/* sources that include the changed part to                               */
/* diameter-developers@lists.sourceforge.net so that we can reflect your  */
/* changes to one unified version of this software.                       */
/*                                                                        */
/* END_COPYRIGHT                                                          */

/* Author   : Victor I. Fajardo
 * Synopsis : Server application test 
 */

#ifndef __SAMPLE_SERVER_H__
#define __SAMPLE_SERVER_H__

#include "diameter_api.h"
#include "ace/Synch.h"

/* forward declaration */
class AAASampleServer;

/*
 * This is a sample message handler object. An application
 * derives from a message handler if it wants to process
 * a specific message. Note that you can reuse this class
 * for any session wishing to process a specific message.
 *
 * You need to have more of these derived classes for 
 * each message you wish to handle. This gives you the
 * flexibility of coding handlers specific to a message.
 */
class AAASampleAuthAnswerMessage : public AAASessionMessageHandler {
    public:
       /*
        * The constructor forces us to pass in the session registering
        * this handler. This gives us access to the session once a
        * message has been receieved.
        */
       AAASampleAuthAnswerMessage(AAASampleServer &client, AAACommandCode code);

       ~AAASampleAuthAnswerMessage();

       /*
        * Actual message handler for this command code
        */
       AAAReturnCode HandleMessage(AAAMessage &msg);

    protected:
       AAASampleServer &_session; /* reference to the original session */
};

/*
 * This is a sample application server. It derives
 * from AAAServerSession base class. Applications
 * interested in caputring events has to override
 * virtual handlers in this class.
 *
 * The sample server is a passive entity. Applications
 * has to define a class which overrides AAAServerSession
 * and performs the necessary functioning specific to
 * the application. Once the class is defined, the application
 * merely has to register the class via a class factory.
 * The application is not responsible for creating instances
 * of the classs it defined.
 *
 * Once an authentication request is received which has
 * a valid session id that this application supports,
 * the factory will create an instance of the sample
 * server session class. Then the request message will
 * be passed on to its default HandleMessage() method
 * where the application can examine it to determine
 * whether to accept the request or not. If the application
 * wishes to accept the request, it may call Accept()
 * on the message and the session will be valid.
 *
 * This sample server shows a simple state machine wherein
 * it accepts initial authentication request from the client.
 * The succeding request is treated as a signal to terminate
 * the session. Hence, if you look at the state machine, it
 * quickly transitions to termination on the 2nd request by
 * the client.
 */
class AAASampleServer : public AAAServerSession {
    public:
       /*
        * Sample state definitions for
        * application state machine
        */
       typedef enum {
         IDLE,
         AUTHORIZED,
         TERMINATING,
       } STATE;

    public:
       AAASampleServer(AAAApplicationCore &appCore, 
                       diameter_unsigned32_t appId);

       /*
        * For server session, this handler is invoked when
        * an incomming message belonging to this session
        * is not formally via RegisterMessageHandler().
        * This is a default catch all message handler.
        *
        * Note that if you do not wish to register a specific
        * message handler for a particular message, you may
        * capture that message here.
        */
       AAAReturnCode HandleMessage(AAAMessage &msg);

       /*
        * On creation of a server session, the HandleDisconnect,
        * HandleSessionTimeout, HandleAuthLifetimeTimeout,
        * HandleAuthGracePeriodTimeout and HandleAbort methods 
        * available to the internal library if any of the events 
        * require thier invocation.
        */

       AAAReturnCode HandleDisconnect();

       AAAReturnCode HandleSessionTimeout();

       AAAReturnCode HandleAuthLifetimeTimeout();

       AAAReturnCode HandleAuthGracePeriodTimeout();

       AAAReturnCode HandleAbort();

       /*
        * Test code to send a sample authentication
        * request answers. The command code is 300 
        * for the sample client message.
        */
       AAAReturnCode SendTestAuthAnswer(AAAMessage &request);

       /*
        * State access functions
        */

       inline void state(AAASampleServer::STATE s) { _state = s; }

       inline AAASampleServer::STATE state() { return _state; }

       /*
        * This semaphore allows the sample application to wait
        * till all sessions are completed before allowing the
        * application to exit cleanly. This is for controlled
        * test purposes only and does not reflect any real
        * applications.
        */
       inline static ACE_Semaphore &semaphore() { return AAASampleServer::_semaphore; }

       /*
        * session index is a way to track how many client 
        * has attempted an authentication request.
        */
       inline int sessionIndex() { return _sessionIndex; }

       /*
        * This flag is passed in as parameter to this application.
        * It tells the application whether to send an abort message
        * once the last message from the client is received.
        */
       inline static bool sendAbort() { return AAASampleServer::_sendAbort; }

       inline static void sendAbort(bool send) { AAASampleServer::_sendAbort = send; }

    protected:
       static bool _sendAbort; /* abort flag */

       std::string _destHost; /* client hostname */

       std::string _destRealm; /* client realm */

       int _sessionIndex; /* current index */

       static int _sessionCount; /* session counter */

       AAASampleServer::STATE _state; /* application specific state */

       static ACE_Semaphore _semaphore; /* simple sync solution */

       AAASampleAuthAnswerMessage _answerMsgHandler; /* convinient to store it here */
};

/*
 * This is the sample authentication server factory definition.
 * When registered, this factory will create instances
 * of AAASampleServer when an incomming request message
 * not matching any session and containing an application
 * id of this factory is received.
 */
typedef AAAServerSessionClassFactory<AAASampleServer> serverFactory;

class AAASampleAccountingServer;

/*
 * We inherit the default transformer so we can
 * over-ride the output methods. In this method,
 * we can provide application specific storage
 * mechanism.
 */
class AAASampleXMLTrans : public AAAAccountingXMLRecTransformer
{
    public:
        AAASampleXMLTrans(AAASampleAccountingServer &server) : session(server) { }

        AAAReturnCode OutputRecord(AAAMessage *originalMsg);

    protected:
        AAASampleAccountingServer &session;
};

/*
 * This is a sample accounting server. It derives
 * from AAAServerAccountingSession base class. 
 * Applications interested in providing accounting
 * record storage or forwarding records to an
 * accounting server MUST implement an accounting
 * server session.
 *
 * As with authentication, the accounting server
 * is a passive entity. All internal functionings
 * are similar to authentication sessions. It even
 * uses the same session database. The biggest
 * difference would be the alternative use of 
 * record transformers. These objects allows the
 * transformation of AAAMessage to an application
 * specific message type. Open diameter currently
 * provides a default transformer that converts
 * AAAMessage to a streamed XML format. An application
 * may implement it's own transformer as it wishes.
 * This sample code uses the default transfomer.
 *
 * In this sample code, since we are using a
 * transformer, we DO NOT need to assign a
 * message handler. We can let the transformer
 * be the message handler for each incomming
 * message for this session.
 */
class AAASampleAccountingServer : public AAAAccountingServerSession {
    public:
       typedef enum {
          ACR = 271 // Accounting request command code value
       };

    public:
       AAASampleAccountingServer(AAAApplicationCore &appCore, 
                                 diameter_unsigned32_t appId);

       ~AAASampleAccountingServer();

       /*
        * Test code to send a sample authentication
        * request answers. The command code is 271
        * for the sample client message.
        */
       AAAReturnCode SendAcctAnswer(AAAMessage &request);

    private:
       AAASampleXMLTrans xml; /* Default transformer */
};

/*
 * This is the sample accounting server factory definition.
 * When registered, this factory will create instances
 * of AAASampleServer when an incomming request message
 * not matching any session and containing an application
 * id of this factory is received.
 */
typedef AAAServerSessionClassFactory<AAASampleAccountingServer> acctFactory;

#endif /* __SAMPLE_SERVER_H__ */







Server Source File

/* BEGIN_COPYRIGHT                                                        */
/*                                                                        */
/* Open Diameter: Open-source software for the Diameter and               */
/*                Diameter related protocols                              */
/*                                                                        */
/* Copyright (C) 2002-2004 Open Diameter Project                          */
/*                                                                        */
/* This library is free software; you can redistribute it and/or modify   */
/* it under the terms of the GNU Lesser General Public License as         */
/* published by the Free Software Foundation; either version 2.1 of the   */
/* License, or (at your option) any later version.                        */
/*                                                                        */
/* This library is distributed in the hope that it will be useful,        */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of         */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU      */
/* Lesser General Public License for more details.                        */
/*                                                                        */
/* You should have received a copy of the GNU Lesser General Public       */
/* License along with this library; if not, write to the Free Software    */
/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307    */
/* USA.                                                                   */
/*                                                                        */
/* In addition, when you copy and redistribute some or the entire part of */
/* the source code of this software with or without modification, you     */
/* MUST include this copyright notice in each copy.                       */
/*                                                                        */
/* If you make any changes that are appeared to be useful, please send    */
/* sources that include the changed part to                               */
/* diameter-developers@lists.sourceforge.net so that we can reflect your  */
/* changes to one unified version of this software.                       */
/*                                                                        */
/* END_COPYRIGHT                                                          */

/* Author   : Victor I. Fajardo
 * Synopsis : Server application test 
 */

#include "sample_server.h"

/* session counter for counting authenitcation request */
int AAASampleServer::_sessionCount = 0;

/* abort flag */
bool AAASampleServer::_sendAbort = false;

/* simple synchronization tool */
ACE_Semaphore AAASampleServer::_semaphore(0);

AAASampleAuthAnswerMessage::AAASampleAuthAnswerMessage(AAASampleServer &server, AAACommandCode code) :
    AAASessionMessageHandler((AAAApplicationCore&)server.GetApplicationCore(), code),
    _session(server)
{
   /*
    * To facilitate simplicity, the registration of
    * the message handler to the session is done 
    * in the handlers constructor
    */
   _session.RegisterMessageHandler(this);
}

AAASampleAuthAnswerMessage::~AAASampleAuthAnswerMessage()
{
   /*
    * Likewise, the registration removal is done
    * in the destructor
    */
   _session.RemoveMessageHandler(this);
}

AAAReturnCode AAASampleAuthAnswerMessage::HandleMessage(AAAMessage &msg)
{
   /*
    * For test purposes, we leave error messages unhandled
    * for the moment.
    */
   if (msg.hdr.flags.e) {
      ACE_ERROR((LM_ERROR, "(%P|%t) Server: Error message received, unhandled at the moment\n"));
      return (AAA_ERR_SUCCESS);
   }

   /*
    * This is the sample state machine. For every message
    * received by this handler, it simply replys with
    * an answer message. This server functions much like
    * an echo server. However, if an abort flag is set
    * then it will send an ASR message upon receipt of
    * a request message.
    */
   switch (_session.state()) {
      case AAASampleServer::IDLE:

         ACE_DEBUG((LM_DEBUG, "(%P|%t) Server: ^^^^^ New Auth Request\n"));
         _session.Update(AAASession::EVENT_AUTH_SUCCESS); 
         _session.state(AAASampleServer::AUTHORIZED);
         _session.SendTestAuthAnswer(msg);
         break;

      case AAASampleServer::AUTHORIZED:
      case AAASampleServer::TERMINATING:
      default:
         ACE_DEBUG((LM_DEBUG, "(%P|%t) Server: ^^^^^ Responding for session # %d\n", 
                   _session.sessionIndex()));

         _session.SendTestAuthAnswer(msg);

         if (AAASampleServer::sendAbort()) {
            _session.Abort();
         }
         break;
   }
   return (AAA_ERR_SUCCESS);
}

AAASampleServer::AAASampleServer(AAAApplicationCore &appCore, 
                                 diameter_unsigned32_t appId) :
   AAAServerSession(appCore, appId),
   _answerMsgHandler(AAASampleAuthAnswerMessage(*this, 300))
{
   /*
    * A simple servers session counter is maintained here
    * since the factory will create instances of this
    * class.
    *
    * Note also that we store references to message handler
    * objects as part of the session object. This is
    * convinient since the bindings between message handlers
    * and session is by being a member variables.
    */

   _state = AAASampleServer::IDLE;

   AAASampleServer::_sessionCount ++;

   _sessionIndex = AAASampleServer::_sessionCount;
}

AAAReturnCode AAASampleServer::HandleMessage(AAAMessage &msg)
{
   /* 
    * After being created by the factory on receipt of a
    * request message, this default HandleMessage is called 
    * to process the request.
    *
    * Note that by being the default message handler. Any 
    * message belonging to the session but does not have a 
    * registered handler will also be passed to this method.
    *
    * In this case, we treat any other message as an 
    * unknown. The application may send an unknown 
    * message error if it wishes.
    */
   ACE_ERROR((LM_ERROR, "(%P|%t) Server: **** Unknown message received **** \n"));
   return (AAA_ERR_SUCCESS);
}

AAAReturnCode AAASampleServer::HandleDisconnect()
{
   ACE_DEBUG((LM_DEBUG, "(%P|%t) Server: Ending session for session # %d\n",  
             _sessionIndex));

   /*
    * This handler can be called when the transport
    * fails, when a session termination request is
    * received or when an application core is exiting.
    *
    * In the case of this sample, we are expecting
    * this function to get called on events other
    * than the receipt of a termination request.
    */

   return (AAA_ERR_SUCCESS);
}

AAAReturnCode AAASampleServer::HandleSessionTimeout()
{
   /* 
    * Called on session timeout
    */

   ACE_DEBUG((LM_DEBUG, "(%P|%t) Server: Session timeout event for session # %d\n",  
              _sessionIndex));

   return (AAA_ERR_SUCCESS);
}

AAAReturnCode AAASampleServer::HandleAuthLifetimeTimeout()
{
   /* 
    * Called on auth lifetime timeout
    */

   ACE_DEBUG((LM_DEBUG, "(%P|%t) Server: Authorization lifetime timeout event for session # %d\n",  
              _sessionIndex));

   return (AAA_ERR_SUCCESS);
}

AAAReturnCode AAASampleServer::HandleAuthGracePeriodTimeout()
{
   /* 
    * Called on auth grace period timeout
    */

   ACE_DEBUG((LM_DEBUG, "(%P|%t) Server: Authorization grace period timeout event for session # %d\n",  
              _sessionIndex));

   return (AAA_ERR_SUCCESS);
}

AAAReturnCode AAASampleServer::HandleAbort()
{
   ACE_DEBUG((LM_DEBUG, "(%P|%t) Server: Abort event for session # %d\n",  
             _sessionIndex));

   /*
    * Called when an abort session request is
    * received. Internally, the library has
    * received an ASR from the client and hence
    * the session will be terminated.
    * This sample does not do anything upon
    * receipt of this event.
    */

   return (AAA_ERR_SUCCESS);
}

AAAReturnCode AAASampleServer::SendTestAuthAnswer(AAAMessage &request)
{
   /*
    * Sample authorization request answer. This message
    * composition follows libdiamparser rules in
    * composing an AAAMessage. 
    */

   AAAAvpContainerManager cm;
   AAAAvpContainerEntryManager em;

   AAAAvpContainer *c_sessId = cm.acquire("Session-Id");
   AAAAvpContainer *c_orhost = cm.acquire("Origin-Host");
   AAAAvpContainer *c_orrealm = cm.acquire("Origin-Realm");
   AAAAvpContainerEntry *e;

   e = em.acquire(AAA_AVP_UTF8_STRING_TYPE);
   c_sessId->add(e);
 
   e = em.acquire(AAA_AVP_DIAMID_TYPE);
   c_orhost->add(e);
 
   e = em.acquire(AAA_AVP_DIAMID_TYPE);
   c_orrealm->add(e);
 
   AAAMessage asrMsg;
   hdr_flag flag = {0,0,0};
   AAADiameterHeader h(1, 0, flag, request.hdr.code, 0, 0, 0);
   asrMsg.hdr = h;

   asrMsg.acl.add(c_sessId);
   asrMsg.acl.add(c_orhost);
   asrMsg.acl.add(c_orrealm);

   /*
    * The use of AAAMessageControl is shown here.
    * It is a utility class used in sending messages
    * via the local session object as well as setting
    * the result code.
    */
   AAAMessageControl msgControl(this);
   msgControl.SetResultCode(asrMsg, request, DIAMETER_SUCCESS);
   if (msgControl.Send(asrMsg) != AAA_ERR_SUCCESS) {
      ACE_ERROR((LM_ERROR, "(%P|%t) Server: Failed sending message\n"));
      return (AAA_ERR_FAILURE);
   }
   else {
      ACE_DEBUG((LM_DEBUG, "(%P|%t) Server: Sent Auth Message\n"));
   }

   return (AAA_ERR_SUCCESS);
}

AAASampleAccountingServer::AAASampleAccountingServer(AAAApplicationCore &appCore, 
                                                     diameter_unsigned32_t appId) 
  : AAAAccountingServerSession(appCore, appId), xml(*this)
{
   // we assign the instance of our XML transformer
   // to the base class so it can invoke it when
   // needed
   SetTransformer(&xml);
}

AAASampleAccountingServer::~AAASampleAccountingServer()
{
   // do nothing
}

AAAReturnCode AAASampleAccountingServer::SendAcctAnswer(AAAMessage &request)
{
   /*
    * Sample accounting request. This message
    * composition follows libdiamparser rules in
    * composing an AAAMessage. The commandn code
    * for accounting request is AAASampleAccountingRequestMsg::ACR.
    */

   ACE_DEBUG((LM_DEBUG, "(%P|%t) Server: Sending test acct answer message\n"));

   AAAAvpContainerManager cm;
   AAAAvpContainerEntryManager em;

   AAAAvpContainer *c_sessId = cm.acquire("Session-Id");
   AAAAvpContainer *c_orhost = cm.acquire("Origin-Host");
   AAAAvpContainer *c_orrealm = cm.acquire("Origin-Realm");
   AAAAvpContainer *c_drealm = cm.acquire("Destination-Realm");
   AAAAvpContainer *c_rectype = cm.acquire("Accounting-Record-Type");
   AAAAvpContainer *c_recnum = cm.acquire("Accounting-Record-Number");
   AAAAvpContainer *c_acctid = cm.acquire("Accounting-Application-Id");
   AAAAvpContainer *c_user = cm.acquire("User-Name");
   AAAAvpContainer *c_subid = cm.acquire("Accounting-Sub-Session-Id");
   AAAAvpContainer *c_acctsid = cm.acquire("Accounting-Session-Id");
   AAAAvpContainer *c_acctmsid = cm.acquire("Acct-Multi-Session-Id");
   AAAAvpContainer *c_intvl = cm.acquire("Accounting-Interim-Interval");
   AAAAvpContainer *c_realtime = cm.acquire("Accounting-Realtime-Required");
   AAAAvpContainer *c_origin = cm.acquire("Origin-State-Id");

   AAAAvpContainerEntry *e;

   e = em.acquire(AAA_AVP_UTF8_STRING_TYPE);
   c_sessId->add(e);
 
   e = em.acquire(AAA_AVP_DIAMID_TYPE);
   c_orhost->add(e);
 
   e = em.acquire(AAA_AVP_DIAMID_TYPE);
   c_orrealm->add(e);
 
   e = em.acquire(AAA_AVP_DIAMID_TYPE);
   c_drealm->add(e);
 
   e = em.acquire(AAA_AVP_UINTEGER32_TYPE);
   diameter_unsigned32_t &rectyp = e->dataRef(Type2Type<diameter_unsigned32_t>());
   c_rectype->add(e);

   e = em.acquire(AAA_AVP_UINTEGER32_TYPE);
   diameter_unsigned32_t &recnum = e->dataRef(Type2Type<diameter_unsigned32_t>());
   c_recnum->add(e);

   e = em.acquire(AAA_AVP_INTEGER32_TYPE);
   diameter_integer32_t &acctid = e->dataRef(Type2Type<diameter_integer32_t>());
   c_acctid->add(e);
 
   e = em.acquire(AAA_AVP_UTF8_STRING_TYPE);
   diameter_utf8string_t &user = e->dataRef(Type2Type<diameter_utf8string_t>());
   c_user->add(e);

   e = em.acquire(AAA_AVP_UINTEGER64_TYPE);
   diameter_unsigned64_t &subid = e->dataRef(Type2Type<diameter_unsigned64_t>());
   c_subid->add(e);
 
   e = em.acquire(AAA_AVP_STRING_TYPE);
   diameter_octetstring_t &acctsid = e->dataRef(Type2Type<diameter_octetstring_t>());
   c_acctsid->add(e);
 
   e = em.acquire(AAA_AVP_UTF8_STRING_TYPE);
   diameter_utf8string_t &acctmsid = e->dataRef(Type2Type<diameter_utf8string_t>());
   c_acctmsid->add(e);
 
   e = em.acquire(AAA_AVP_UINTEGER32_TYPE);
   diameter_unsigned32_t &intvl = e->dataRef(Type2Type<diameter_unsigned32_t>());
   c_intvl->add(e);

   e = em.acquire(AAA_AVP_UINTEGER32_TYPE);
   diameter_unsigned32_t &realtime = e->dataRef(Type2Type<diameter_unsigned32_t>());
   c_realtime->add(e);

   e = em.acquire(AAA_AVP_UINTEGER32_TYPE);
   diameter_unsigned32_t &origin = e->dataRef(Type2Type<diameter_unsigned32_t>());
   c_origin->add(e);

   AAAMessage acctMsg;
   hdr_flag flag = {0,0,0};
   AAADiameterHeader h(0, 0, flag, AAASampleAccountingServer::ACR, 0, 0, 0);
   acctMsg.hdr = h;

   acctMsg.acl.add(c_sessId);
   acctMsg.acl.add(c_orhost);
   acctMsg.acl.add(c_orrealm);
   acctMsg.acl.add(c_drealm);
   acctMsg.acl.add(c_rectype);
   acctMsg.acl.add(c_recnum);
   acctMsg.acl.add(c_acctid);
   acctMsg.acl.add(c_user);
   acctMsg.acl.add(c_subid);
   acctMsg.acl.add(c_acctsid);
   acctMsg.acl.add(c_acctmsid);
   acctMsg.acl.add(c_intvl);
   acctMsg.acl.add(c_realtime);
   acctMsg.acl.add(c_origin);

   rectyp = 1; // event record only
   recnum = 0;
   acctid = 0; // sample only 
   user.assign("sample user");
   subid = 0; // sample only
   acctsid.assign("sample sid");
   acctmsid.assign("sample multi sid");
   intvl = 30; // 30 sec interval for sampling
   realtime = 2; // grant and store
   origin = 0; // sample only

   /*
    * The use of AAAMessageControl is shown here.
    * It is a utility class used in sending messages
    * via the local session object as well as setting
    * the result code.
    */
   AAAMessageControl msgControl(this);
   msgControl.SetResultCode(acctMsg, request, DIAMETER_SUCCESS);
   if (msgControl.Send(acctMsg) != AAA_ERR_SUCCESS) {
      ACE_ERROR((LM_ERROR, "(%P|%t) Server: Failed sending message\n"));
      return (AAA_ERR_FAILURE);
   }
   else {
      ACE_DEBUG((LM_DEBUG, "(%P|%t) Server: Sent Acct Message\n"));
   }

   return (AAA_ERR_SUCCESS);
}

AAAReturnCode AAASampleXMLTrans::OutputRecord(AAAMessage *originalMsg)
{
   ACE_DEBUG((LM_DEBUG, "(%P|%t) Server: Accounting transformer successfully converted record\n"));

   if (record) {
      ACE_DEBUG((LM_DEBUG, "(%P|%t) Server: Record Size: %d\n", record_size));
      ACE_DEBUG((LM_DEBUG, "(%P|%t) Server: Record: %s\n", (char*)record));

      /*
       * Note that it is the responsibility of the handler
       * to free the record holder when it is done
       * using it. In real applications, this section
       * MAY be used to store XML stream into databases.
       *
       * Note also that the default implementation of
       * the XML transformer OutputRecord method
       * automatically frees the record pointer.
       * Hence, you may invoke this method so it
       * handles record release for us.
       */
      AAAAccountingXMLRecTransformer::OutputRecord(originalMsg);
   }

   ACE_DEBUG((LM_DEBUG, "(%P|%t) Server: Sending answer back to client (test purpose only)\n"));
   return session.SendAcctAnswer(*originalMsg);
}

int main(int argc, char *argv[])
{
   /*
    * This sample server test program is straight forward.
    * After creating an instance of the application core
    * and passing it the configuration file, it registers
    * a class factory for handling requests with application
    * id 0. The the configuration filename is passed in as
    * an argument as well as the abort flag.
    * 
    * Note that a semaphore is used to mimic application
    * specific processing. On exit, the factory is removed
    * from the application core and the application cores
    * destructor will perform internal cleanup.
    *
    */

   if (argc != 3) {
      ACE_DEBUG((LM_DEBUG, "(%P|%t) Server: Usage: sample_server [wait|nowait] [config file]\n"));
      return (1);
   }

   ACE_DEBUG((LM_DEBUG, "(%P|%t) Server: Application starting\n"));

   AAAApplicationCore myCore;
   if (myCore.Open(argv[2]) != AAA_ERR_SUCCESS) {
      ACE_ERROR((LM_ERROR, "(%P|%t) Server: Application core open error\n"));
      return (1);
   }

   /* abort flag */
   std::string abort(argv[1]);
   AAASampleServer::sendAbort((abort == "wait") ? true : false);

   /* 
    * application id is for this sample
    */
   serverFactory authFactory(0, AAA_STYPE_AUTHENTICATION);
   acctFactory acctFactory(0, AAA_STYPE_ACCOUNTING);
   
   /*
    * Register the factory to our application core.
    * All request with application id 0 will be
    * handled here.
    */
   myCore.RegisterServerSessionFactory(&authFactory);
   myCore.RegisterServerSessionFactory(&acctFactory);

   /*
    * This will block until all session are done.
    * In the case of this sample, this will block
    * indefinitely because we did not provide an
    * exit routine.
    */
   AAASampleServer::semaphore().acquire();

   myCore.RemoveServerSessionFactory(&authFactory);
   myCore.RemoveServerSessionFactory(&acctFactory);

   ACE_DEBUG((LM_DEBUG, "(%P|%t) Server: Exiting\n"));

   return (0);
}






Client Application Sample Code

This document uses sample code to desribe usage of the C++ API. The code below provides ample comments on describing API usage.

Client Header File

/* BEGIN_COPYRIGHT                                                        */
/*                                                                        */
/* Open Diameter: Open-source software for the Diameter and               */
/*                Diameter related protocols                              */
/*                                                                        */
/* Copyright (C) 2002-2004 Open Diameter Project                          */
/*                                                                        */
/* This library is free software; you can redistribute it and/or modify   */
/* it under the terms of the GNU Lesser General Public License as         */
/* published by the Free Software Foundation; either version 2.1 of the   */
/* License, or (at your option) any later version.                        */
/*                                                                        */
/* This library is distributed in the hope that it will be useful,        */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of         */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU      */
/* Lesser General Public License for more details.                        */
/*                                                                        */
/* You should have received a copy of the GNU Lesser General Public       */
/* License along with this library; if not, write to the Free Software    */
/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307    */
/* USA.                                                                   */
/*                                                                        */
/* In addition, when you copy and redistribute some or the entire part of */
/* the source code of this software with or without modification, you     */
/* MUST include this copyright notice in each copy.                       */
/*                                                                        */
/* If you make any changes that are appeared to be useful, please send    */
/* sources that include the changed part to                               */
/* diameter-developers@lists.sourceforge.net so that we can reflect your  */
/* changes to one unified version of this software.                       */
/*                                                                        */
/* END_COPYRIGHT                                                          */

/* Author   : Victor I. Fajardo
 * Synopsis : Client application test 
 */

#ifndef __SAMPLE_CLIENT_H__
#define __SAMPLE_CLIENT_H__

#include <string>
#include <list>
#include "ace/Synch.h"
#include "diameter_api.h"

/*
 * This is a sample application client. It derives
 * from AAAClientSession base class. Applications
 * interested in caputring events has to override
 * virtual handlers in this class.
 *
 * The sample client attempts to establish a session
 * with a sample server. The sample server is designated
 * by destination host and realm and passed in as a
 * parameter to this program. The initial request sent
 * out by this client is processed by the server and
 * an answer is sent back. Once the answer is received
 * another test message is sent to test normal traffic.
 * If the second request message is recieved properly
 * by the server, an answer is sent back and the server
 * prepares to abort the session. Once the client receives
 * the answer it sends a termination request to the server.
 * Once a complete cycle of abort and termination answers
 * are sent by the client and server respectively, the
 * session is terminated on both sides.
 */
class AAASampleClient : public AAAClientSession {
    public:
       /*
        * Sample state definitions for
        * application state machine
        */
       typedef enum {
         IDLE,
         AUTHORIZED,
         TERMINATING,
       } STATE;

    public:
       AAASampleClient(AAAApplicationCore &appCore, 
                       diameter_unsigned32_t appId);

       /*
        * For client session, this handler is invoked when
        * an incomming message belonging to this session
        * is not formally via RegisterMessageHandler().
        * This is a default catch all message handler.
        *
        * Note that if you do not wish to register a specific
        * message handler for a particular message, you may
        * capture that message here.
        */
       AAAReturnCode HandleMessage(AAAMessage &msg);

       /*
        * On creation of a server session, the HandleDisconnect,
        * HandleSessionTimeout, HandleAuthLifetimeTimeout,
        * HandleAuthGracePeriodTimeout and HandleAbort methods 
        * available to the internal library if any of the events 
        * require thier invocation.
        */

       AAAReturnCode HandleDisconnect();

       AAAReturnCode HandleSessionTimeout();

       AAAReturnCode HandleAuthLifetimeTimeout();

       AAAReturnCode HandleAuthGracePeriodTimeout();

       AAAReturnCode HandleAbort();

       /*
        * Test code to send a sample authentication
        * request. The command code is 300 for the
        * sample test message.
        */
       AAAReturnCode SendTestAuth();

       /*
        * Session counter and session index is a way
        * to track how many client this sample application
        * will create. These are mostly for sample purposes
        * and does not in anyway relate to a real application
        */

       inline static int sessionCount() { return AAASampleClient::_sessionCount; }

       inline static void sessionCount(int count) { AAASampleClient::_sessionCount = count; }

       inline int sessionIndex() { return _sessionIndex; }

       /*
        * Allows this session to keep track of the host and
        * realm it's connected to
        */

       inline std::string &destHost() { return _destHost; }

       inline void destHost(std::string &host) { _destHost = host; }

       inline std::string &destRealm() { return _destRealm; }

       inline void destRealm(std::string &realm) { _destRealm = realm; }

       /*
        * State access functions
        */

       inline void state(AAASampleClient::STATE s) { _state = s; }

       inline AAASampleClient::STATE state() { return _state; }

       /*
        * This semaphore allows the sample application to wait
        * till all sessions are completed before allowing the
        * application to exit cleanly. This is for controlled
        * test purposes only and does not reflect any real
        * applications.
        */
       inline static ACE_Semaphore &semaphore() { return AAASampleClient::_semaphore; }

    protected:
       std::string _destHost; /* session destination host */

       std::string _destRealm; /* session destination realm */

       int _sessionIndex; /* session local index */

       static int _sessionCount; /* number of sessions in this application */

       AAASampleClient::STATE _state; /* application specific state */

       static ACE_Semaphore _semaphore; /* simple sync solution */
};

/*
 * This is a sample message handler object. An application
 * derives from a message handler if it wants to process
 * a specific message. Note that you can reuse this class
 * for any session wishing to process a specific message.
 *
 * You need to have more of these derived classes for 
 * each message you wish to handle. This gives you the
 * flexibility of coding handlers specific to a message.
 */
class AAASampleAuthMessage : public AAASessionMessageHandler {
    public:
       /*
        * The constructor forces us to pass in the session registering
        * this handler. This gives us access to the session once a
        * message has been receieved.
        */
       AAASampleAuthMessage(AAASampleClient &client, AAACommandCode code);

       ~AAASampleAuthMessage();

       /*
        * Actual message handler for code
        */
       AAAReturnCode HandleMessage(AAAMessage &msg);

    protected:
       AAASampleClient &session; /* reference to the original authentication session */
};

/*
 * This is a sample accounting session client. An application
 * derives from this class to add accounting functionality
 * to an application. Note that accounting sessions mimic
 * authentication sessions. The only differences is the
 * addition of the interim record handler in the session
 * class.
 */
class AAASampleAccountingClient : public AAAAccountingClientSession
{
   public:
      AAASampleAccountingClient(AAAApplicationCore &appCore, 
                                diameter_unsigned32_t appId);

      ~AAASampleAccountingClient();

       /*
        * Auxillary method to generate an accounting
        * request message. The message is a general
        * accounting message.
        */
       AAAReturnCode SendAcctMessage(RECTYPE type);

       AAAReturnCode HandleInterimRecordEvent(RECTYPE type, 
                                              AAASessionPayload payload);

       inline void destRealm(std::string &realm) { _destRealm = realm; }

       inline int numRecords() { return rec_counter; }

   protected:
       std::string _destRealm; /* session destination realm */

       int rec_counter; /* session record counter */
};

/*
 * This is a sample message handler object. An application
 * derives from a message handler if it wants to process
 * a specific message. Note that you can reuse this class
 * for any session wishing to process a specific message.
 *
 * You need to have more of these derived classes for 
 * each message you wish to handle. This gives you the
 * flexibility of coding handlers specific to a message.
 */
class AAASampleAccountingRequestMsg : public AAASessionMessageHandler
{
    public:
       typedef enum {
          rec_threshold = 1  // this defines an arbitrary number of records
                             // that we are willing to process. This is for
                             // testing purposes only. You may modify this
                             // number to suite your needs
       };

       typedef enum {
          ACR = 271 // Accounting request command code value
       };

    public:
       AAASampleAccountingRequestMsg(AAASampleAccountingClient &session, 
                                     AAACommandCode code);

       ~AAASampleAccountingRequestMsg();

       /* 
        * This handler method is invoked when an incomming
        * message matches the registration of this event
        * handler. In this example, we use the session 
        * object itself as the registered event handler.
        */
       AAAReturnCode HandleMessage(AAAMessage &msg);

    protected:
       AAASampleAccountingClient &session; /* reference to the original session */
};

/*
 * This class is for convience only. Since this
 * application creates more than one session, we
 * created a simple class which holds both instances
 * of the message handlers and the session themselves.
 */
class AAASampleSessionHolder
{
   public:
      AAASampleSessionHolder(AAAApplicationCore &appCore, 
                             diameter_unsigned32_t appId);

      /*
       * Access functions to client session and
       * message handler instance
       */

      AAASampleAuthMessage &authMsgHandler() { return _authMsgHandler; }

      AAASampleClient &clientSession() { return _authSampleClient; }

      AAASampleAccountingClient &acctSession() { return _acctSampleClient; }

      AAASampleAccountingRequestMsg &acctMsgHandler() { return _acctMsgHandler; }

   protected:
      AAASampleClient _authSampleClient; /* instance of sample client */

      AAASampleAuthMessage _authMsgHandler; /* instance of message handler,
                                             * if you want to handle more
                                             * command codes, you may create
                                             * more instances of the handler.
                                             * One for each command code
                                             */

      AAASampleAccountingClient _acctSampleClient; /* instance of an authentication client */

      AAASampleAccountingRequestMsg _acctMsgHandler;  /* instance of message handler,
                                                       * if you want to handle more
                                                       * command codes, you may create
                                                       * more instances of the handler.
                                                       * One for each command code
                                                       */
};

/*
 * simple list database of session holders
 */
typedef std::list<AAASampleSessionHolder*> holderList;

#endif /* __SAMPLE_CLIENT_H__ */




Client Source File

/* BEGIN_COPYRIGHT                                                        */
/*                                                                        */
/* Open Diameter: Open-source software for the Diameter and               */
/*                Diameter related protocols                              */
/*                                                                        */
/* Copyright (C) 2002-2004 Open Diameter Project                          */
/*                                                                        */
/* This library is free software; you can redistribute it and/or modify   */
/* it under the terms of the GNU Lesser General Public License as         */
/* published by the Free Software Foundation; either version 2.1 of the   */
/* License, or (at your option) any later version.                        */
/*                                                                        */
/* This library is distributed in the hope that it will be useful,        */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of         */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU      */
/* Lesser General Public License for more details.                        */
/*                                                                        */
/* You should have received a copy of the GNU Lesser General Public       */
/* License along with this library; if not, write to the Free Software    */
/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307    */
/* USA.                                                                   */
/*                                                                        */
/* In addition, when you copy and redistribute some or the entire part of */
/* the source code of this software with or without modification, you     */
/* MUST include this copyright notice in each copy.                       */
/*                                                                        */
/* If you make any changes that are appeared to be useful, please send    */
/* sources that include the changed part to                               */
/* diameter-developers@lists.sourceforge.net so that we can reflect your  */
/* changes to one unified version of this software.                       */
/*                                                                        */
/* END_COPYRIGHT                                                          */

/* Author   : Victor I. Fajardo
 * Synopsis : Client application test 
 */

#include <string>
#include "ace/OS.h"
#include "sample_client.h"

/* session counter for indexing session holders */
int AAASampleClient::_sessionCount = 0;

/* simple synchronization tool */
ACE_Semaphore AAASampleClient::_semaphore(0);

/*
 * Session holder instance automatically
 * initializes the session client and
 * message handler
 */
AAASampleSessionHolder::AAASampleSessionHolder(AAAApplicationCore &appCore, 
                                               diameter_unsigned32_t appId) :
   _authSampleClient(appCore, appId),
   _authMsgHandler(_authSampleClient, 300),
   _acctSampleClient(appCore, appId),
   _acctMsgHandler(_acctSampleClient, AAASampleAccountingRequestMsg::ACR)
{
   // do nothing     
}

AAASampleAuthMessage::AAASampleAuthMessage(AAASampleClient &client, AAACommandCode code) :
    AAASessionMessageHandler((AAAApplicationCore&)client.GetApplicationCore(), code),
    session(client)
{
   /*
    * To facilitate simplicity, the registration of
    * the message handler to the session is done 
    * in the handlers constructor
    */
   session.RegisterMessageHandler(this);
}

AAASampleAuthMessage::~AAASampleAuthMessage()
{
   /*
    * Likewise, the registration removal is done
    * in the destructor
    */
   session.RemoveMessageHandler(this);
}

AAAReturnCode AAASampleAuthMessage::HandleMessage(AAAMessage &msg)
{
   /*
    * For test purposes, we leave error messages unhandled
    * for the moment.
    */
   if (msg.hdr.flags.e) {
      ACE_ERROR((LM_ERROR, "(%P|%t) Client: Error message received, unhandled at the moment\n"));
      return (AAA_ERR_SUCCESS);
   }

   /*
    * This is the sample state machine. For every message
    * received from the server we transition to another
    * state finally leading to termination. Details of
    * the message exchange is in the header files.
    *
    * Notice that we send a test auth only once after
    * receiving an answer to our first request. Then
    * the state transitions to termination state. On
    * termination state, the library will handle STR
    * processing sent by the server. After processing
    * the client will be notified by HandleDisconnect().
    */
   switch (session.state()) {
      case AAASampleClient::IDLE:
         if (! msg.hdr.flags.r) {

            ACE_DEBUG((LM_DEBUG, "(%P|%t) Client: ^^^^^^^ Authenticated for Session # %d\n", session.sessionIndex()));

            session.Update(AAASession::EVENT_AUTH_SUCCESS);

            session.SendTestAuth();

            session.state(AAASampleClient::TERMINATING);
         }
         break;

      case AAASampleClient::AUTHORIZED:
         // un-used for now
         break;

      case AAASampleClient::TERMINATING:
         if (! msg.hdr.flags.r) {
            ACE_DEBUG((LM_DEBUG, "(%P|%t) Client: Ready for termination  Session # %d\n", session.sessionIndex()));
         }
         break;
   }
   return (AAA_ERR_SUCCESS);
}

AAASampleClient::AAASampleClient(AAAApplicationCore &appCore, 
                                 diameter_unsigned32_t appId) :
   AAAClientSession(appCore, appId)
{
   /*
    * A simple client session counter is introduced 
    * for referencing each session
    */

   _state = AAASampleClient::IDLE;

   AAASampleClient::_sessionCount ++;

   _sessionIndex = AAASampleClient::_sessionCount;
}

AAAReturnCode AAASampleClient::HandleMessage(AAAMessage &msg)
{
   /*
    * This is the default message handler. Any message
    * belonging to the session but does not have a 
    * registered handler will be passed to this method
    *
    * In this case, we treat any other message as an 
    * unknown. The application may send an unknown 
    * message error if it wishes.
    */

   ACE_ERROR((LM_ERROR, "(%P|%t) Client: Unknown message received\n"));
   return (AAA_ERR_SUCCESS);
}

AAAReturnCode AAASampleClient::HandleDisconnect()
{
   /*
    * This handler can be called when the transport
    * fails, when a session termination request is
    * received or when an application core is exiting.
    *
    * In the case of this sample, we are expecting
    * this function to get called on receipt of a
    * session termination request. In other cases,
    * the code here will work to.
    */

   ACE_DEBUG((LM_DEBUG, "(%P|%t) Client: Ending session for session # %d\n",  _sessionIndex));

   End(); /* calling end will remove this session
                 * from the database and terminate it
                 * cleanly.
                 */

   /*
    * This is allows us to release the semaphore
    * on the main program once all the client
    * session has terminated.
    */
   AAASampleClient::_sessionCount --;

   if (AAASampleClient::_sessionCount == 0) {
      AAASampleClient::_semaphore.release();
   }

   return (AAA_ERR_SUCCESS);
}

AAAReturnCode AAASampleClient::HandleSessionTimeout()
{
   /* 
    * Called on session timeout
    */

   ACE_DEBUG((LM_DEBUG, "(%P|%t) Client: Session timeout event for session # %d\n",  
              _sessionIndex));

   return (AAA_ERR_SUCCESS);
}

AAAReturnCode AAASampleClient::HandleAuthLifetimeTimeout()
{
   /* 
    * Called on auth lifetime timeout
    */

   ACE_DEBUG((LM_DEBUG, "(%P|%t) Client: Authorization lifetime timeout event for session # %d\n",  
              _sessionIndex));

   return (AAA_ERR_SUCCESS);
}

AAAReturnCode AAASampleClient::HandleAuthGracePeriodTimeout()
{
   /* 
    * Called on auth grace period timeout
    */

   ACE_DEBUG((LM_DEBUG, "(%P|%t) Client: Authorization grace period timeout event for session # %d\n",  
              _sessionIndex));

   return (AAA_ERR_SUCCESS);
}

AAAReturnCode AAASampleClient::HandleAbort()
{
   /*
    * Called when an abort session request is
    * received. We will never receive this because
    * we are acting as a client. The server session
    * may process this.
    */

   ACE_DEBUG((LM_DEBUG, "(%P|%t) Client: Abort event for session # %d\n",  _sessionIndex));

   return (AAA_ERR_SUCCESS);
}

AAAReturnCode AAASampleClient::SendTestAuth()
{
   /*
    * Sample authorization request. This message
    * composition follows libdiamparser rules in
    * composing an AAAMessage. The test command
    * code we use is 300.
    */

   ACE_DEBUG((LM_DEBUG, "(%P|%t) Client: Sending test auth message # %d\n",  _sessionIndex));

   AAAAvpContainerManager cm;
   AAAAvpContainerEntryManager em;

   AAAAvpContainer *c_sessId = cm.acquire("Session-Id");
   AAAAvpContainer *c_orhost = cm.acquire("Origin-Host");
   AAAAvpContainer *c_orrealm = cm.acquire("Origin-Realm");
   AAAAvpContainer *c_dhost = cm.acquire("Destination-Host");
   AAAAvpContainer *c_drealm = cm.acquire("Destination-Realm");
   AAAAvpContainer *c_authid = cm.acquire("Auth-Application-Id");
   AAAAvpContainer *c_reauth = cm.acquire("Re-Auth-Request-Type");
   AAAAvpContainerEntry *e;

   e = em.acquire(AAA_AVP_UTF8_STRING_TYPE);
   c_sessId->add(e);
 
   e = em.acquire(AAA_AVP_DIAMID_TYPE);
   c_orhost->add(e);
 
   e = em.acquire(AAA_AVP_DIAMID_TYPE);
   c_orrealm->add(e);
 
   e = em.acquire(AAA_AVP_DIAMID_TYPE);
   diameter_identity_t &dhost = e->dataRef(Type2Type<diameter_identity_t>());
   c_dhost->add(e);
 
   e = em.acquire(AAA_AVP_DIAMID_TYPE);
   diameter_identity_t &drealm = e->dataRef(Type2Type<diameter_identity_t>());
   c_drealm->add(e);
 
   e = em.acquire(AAA_AVP_UINTEGER32_TYPE);
   diameter_unsigned32_t &authid = e->dataRef(Type2Type<diameter_unsigned32_t>());
   c_authid->add(e);
 
   e = em.acquire(AAA_AVP_UINTEGER32_TYPE);
   diameter_unsigned32_t &reauth = e->dataRef(Type2Type<diameter_unsigned32_t>());
   c_reauth->add(e);
 
   AAAMessage asrMsg;
   hdr_flag flag = {1,0,0};
   AAADiameterHeader h(1, 0, flag, 300, 0, 0, 0);
   asrMsg.hdr = h;

   asrMsg.acl.add(c_sessId);
   asrMsg.acl.add(c_orhost);
   asrMsg.acl.add(c_orrealm);
   asrMsg.acl.add(c_dhost);
   asrMsg.acl.add(c_drealm);
   asrMsg.acl.add(c_authid);
   asrMsg.acl.add(c_reauth);

   dhost = _destHost;
   drealm = _destRealm;

   authid = 8; // SAMPLE
   reauth = 1;

   /*
    * The use of AAAMessageControl is shown here.
    * It is a utility class used in sending messages
    * via the local session object as well as setting
    * the result code.
    */
   AAAMessageControl msgControl(this);
   if (msgControl.Send(asrMsg) != AAA_ERR_SUCCESS) {
      ACE_ERROR((LM_ERROR, "(%P|%t) Client: Failed sending message\n"));
      return (AAA_ERR_FAILURE);
   }
   else {
      ACE_DEBUG((LM_DEBUG, "(%P|%t) Client: Sent Auth Message\n"));
   }

   return (AAA_ERR_SUCCESS);
}

AAASampleAccountingClient::AAASampleAccountingClient(AAAApplicationCore &appCore, 
                                                     diameter_unsigned32_t appId)
  : AAAAccountingClientSession(appCore, appId)
{
   rec_counter = 0;
}

AAASampleAccountingClient::~AAASampleAccountingClient()
{
   // do nothing
}

AAAReturnCode AAASampleAccountingClient::SendAcctMessage(RECTYPE type)
{
   /*
    * Sample accounting request. This message
    * composition follows libdiamparser rules in
    * composing an AAAMessage. The commandn code
    * for accounting request is AAASampleAccountingRequestMsg::ACR.
    */

   ACE_DEBUG((LM_DEBUG, "(%P|%t) Client: Sending test acct message\n"));

   AAAAvpContainerManager cm;
   AAAAvpContainerEntryManager em;

   AAAAvpContainer *c_sessId = cm.acquire("Session-Id");
   AAAAvpContainer *c_orhost = cm.acquire("Origin-Host");
   AAAAvpContainer *c_orrealm = cm.acquire("Origin-Realm");
   AAAAvpContainer *c_drealm = cm.acquire("Destination-Realm");
   AAAAvpContainer *c_rectype = cm.acquire("Accounting-Record-Type");
   AAAAvpContainer *c_recnum = cm.acquire("Accounting-Record-Number");
   AAAAvpContainer *c_acctid = cm.acquire("Acct-Application-Id");
   AAAAvpContainer *c_user = cm.acquire("User-Name");
   AAAAvpContainer *c_subid = cm.acquire("Accounting-Sub-Session-Id");
   AAAAvpContainer *c_acctsid = cm.acquire("Accounting-Session-Id");
   AAAAvpContainer *c_acctmsid = cm.acquire("Acct-Multi-Session-Id");
   AAAAvpContainer *c_intvl = cm.acquire("Accounting-Interim-Interval");
   AAAAvpContainer *c_realtime = cm.acquire("Accounting-Realtime-Required");
   AAAAvpContainer *c_origin = cm.acquire("Origin-State-Id");

   AAAAvpContainerEntry *e;

   e = em.acquire(AAA_AVP_UTF8_STRING_TYPE);
   c_sessId->add(e);
 
   e = em.acquire(AAA_AVP_DIAMID_TYPE);
   c_orhost->add(e);
 
   e = em.acquire(AAA_AVP_DIAMID_TYPE);
   c_orrealm->add(e);
 
   e = em.acquire(AAA_AVP_DIAMID_TYPE);
   diameter_identity_t &drealm = e->dataRef(Type2Type<diameter_identity_t>());
   c_drealm->add(e);
 
   e = em.acquire(AAA_AVP_UINTEGER32_TYPE);
   diameter_unsigned32_t &rectyp = e->dataRef(Type2Type<diameter_unsigned32_t>());
   c_rectype->add(e);

   e = em.acquire(AAA_AVP_UINTEGER32_TYPE);
   diameter_unsigned32_t &recnum = e->dataRef(Type2Type<diameter_unsigned32_t>());
   c_recnum->add(e);

   e = em.acquire(AAA_AVP_INTEGER32_TYPE);
   diameter_integer32_t &acctid = e->dataRef(Type2Type<diameter_integer32_t>());
   c_acctid->add(e);
 
   e = em.acquire(AAA_AVP_UTF8_STRING_TYPE);
   diameter_utf8string_t &user = e->dataRef(Type2Type<diameter_utf8string_t>());
   c_user->add(e);

   e = em.acquire(AAA_AVP_UINTEGER64_TYPE);
   diameter_unsigned64_t &subid = e->dataRef(Type2Type<diameter_unsigned64_t>());
   c_subid->add(e);
 
   e = em.acquire(AAA_AVP_STRING_TYPE);
   diameter_octetstring_t &acctsid = e->dataRef(Type2Type<diameter_octetstring_t>());
   c_acctsid->add(e);
 
   e = em.acquire(AAA_AVP_UTF8_STRING_TYPE);
   diameter_utf8string_t &acctmsid = e->dataRef(Type2Type<diameter_utf8string_t>());
   c_acctmsid->add(e);
 
   e = em.acquire(AAA_AVP_UINTEGER32_TYPE);
   diameter_unsigned32_t &intvl = e->dataRef(Type2Type<diameter_unsigned32_t>());
   c_intvl->add(e);

   e = em.acquire(AAA_AVP_UINTEGER32_TYPE);
   diameter_unsigned32_t &realtime = e->dataRef(Type2Type<diameter_unsigned32_t>());
   c_realtime->add(e);

   e = em.acquire(AAA_AVP_UINTEGER32_TYPE);
   diameter_unsigned32_t &origin = e->dataRef(Type2Type<diameter_unsigned32_t>());
   c_origin->add(e);

   AAAMessage acctMsg;
   hdr_flag flag = {1,0,0};
   AAADiameterHeader h(1, 0, flag, AAASampleAccountingRequestMsg::ACR, 0, 0, 0);
   acctMsg.hdr = h;

   acctMsg.acl.add(c_sessId);
   acctMsg.acl.add(c_orhost);
   acctMsg.acl.add(c_orrealm);
   acctMsg.acl.add(c_drealm);
   acctMsg.acl.add(c_rectype);
   acctMsg.acl.add(c_recnum);
   acctMsg.acl.add(c_acctid);
   acctMsg.acl.add(c_user);
   acctMsg.acl.add(c_subid);
   acctMsg.acl.add(c_acctsid);
   acctMsg.acl.add(c_acctmsid);
   acctMsg.acl.add(c_intvl);
   acctMsg.acl.add(c_realtime);
   acctMsg.acl.add(c_origin);

   drealm = _destRealm;
   rectyp = type; // event record only
   recnum = ++ rec_counter;
   acctid = 0; // sample only 
   user.assign("user@sample");
   subid = 0; // sample only
   acctsid.assign("samplesessid");
   acctmsid.assign("samplemsid");
   intvl = 30; // 30 sec interval for sampling
   realtime = 2; // grant and store
   origin = 0; // sample only

   /*
    * The use of AAAMessageControl is shown here.
    * It is a utility class used in sending messages
    * via the local session object as well as setting
    * the result code.
    */
   AAAMessageControl msgControl(this);
   if (msgControl.Send(acctMsg) != AAA_ERR_SUCCESS) {
      ACE_ERROR((LM_ERROR, "(%P|%t) Client: Failed sending message\n"));
      return (AAA_ERR_FAILURE);
   }
   else {
      ACE_DEBUG((LM_DEBUG, "(%P|%t) Client: Sent Acct Message\n"));
   }

   return (AAA_ERR_SUCCESS);
}

AAAReturnCode AAASampleAccountingClient::HandleInterimRecordEvent(RECTYPE type, 
                                                                  AAASessionPayload payload)
{
  ACE_DEBUG((LM_DEBUG, "(%P|%t) Client: Interim record event ... collecting data\n"));

  /* The interim handler is our queue
   * to collect accounting data and
   * send a request. In our sample
   * we simply send a request to and
   * mimic collection
   */
   return SendAcctMessage(type);
}

AAASampleAccountingRequestMsg::AAASampleAccountingRequestMsg(AAASampleAccountingClient &sess   , 
                                                             AAACommandCode code)
  : AAASessionMessageHandler((AAAApplicationCore&)sess.GetApplicationCore(), code),
    session(sess)
{
   /*
    * To facilitate simplicity, the registration of
    * the message handler to the session is done 
    * in the handlers constructor
    */
   session.RegisterMessageHandler(this);
}

AAASampleAccountingRequestMsg::~AAASampleAccountingRequestMsg()
{
   /*
    * Likewise, the registration removal is done
    * in the destructor
    */
   session.RemoveMessageHandler(this);
}

AAAReturnCode AAASampleAccountingRequestMsg::HandleMessage(AAAMessage &msg)
{
   /* This is the default handler for accounting messages.
    * In real implementations, applications MUST examine 
    * the contents of the answer message and act accordingly.
    * Applications may terminate in interim record generator
    * as a result.
    */
   if (msg.hdr.code == AAASampleAccountingRequestMsg::ACR && ! msg.hdr.flags.r) {
      /*
       * It is important to note that for test purposes, you have to
       * make sure that accounting interval will occurr while this
       * peer still has an active connection to the server. This
       * sample code DOES NOT check for this. Real application MUST
       * do so.
       */
      if (session.numRecords() == AAASampleAccountingRequestMsg::rec_threshold) {
         ACE_DEBUG((LM_DEBUG, "(%P|%t) Client: Accounting session ready for termination\n"));
      }
      else {

         ACE_DEBUG((LM_DEBUG, "(%P|%t) Client: Scheduling an accounting interim\n"));
         /* 
          * We set a 1 sec interval in scheduling an interim
          * handler event.
          */
         session.SetInterimRecordInterval(AAAAccountingClientSession::RECTYPE_EVENT, 
                                                0, // collect records immediately
                                                NULL);
      }
   }
   return (AAA_ERR_SUCCESS);
}

int main(int argc, char *argv[])
{
   /*
    * The main test program is straightforward. It
    * processes all arguments passed to it then 
    * creates the appropriate number of sessions.
    * It then waits till all sessions have terminated
    * completely before exiting.
    *
    * The number of sessions as well as the authorizing
    * host and realm is passed in as arguments. Also,
    * the configuration file is an argument.
    */

   if (argc != 5) {
      ACE_DEBUG((LM_DEBUG, "(%P|%t) Client: Usage: aaa_sample_client [host] [realm] [num session] [config file]\n"));
      return (1);
   }

   int howManySessions = atoi(argv[3]);
   if (howManySessions <= 0) {
      ACE_ERROR((LM_ERROR, "(%P|%t) Client: Invalid number of sessions\n"));
      return (1);
   }

   ACE_DEBUG((LM_DEBUG, "(%P|%t) Client: Application starting\n"));

   AAAApplicationCore myCore;
   if (myCore.Open(argv[4]) != AAA_ERR_SUCCESS) {
      ACE_ERROR((LM_ERROR, "(%P|%t) Client: Application core open error\n"));
      return (1);
   }

   std::string destHost(argv[1]);
   std::string destRealm(argv[2]);

   holderList _holderList;

   // Primitive wait. Waiting for the client to
   // establish connection with the peers
   while (myCore.GetNumActivePeerConnections() == 0); 

   for (int i = 0; i < howManySessions; i++) {

      /*
       * This creates the session and sets 
       * application id to zero for this sample.
       *
       * Note that we are repsonsible for creating
       * instances of the client session. Hence,
       * we are able to make references of our
       * allocation and delete it afterwards.
       *
       * For accounting sessions, creation of
       * a new instance of the holder will
       * create a session id for the accounting
       * session.
       */
      AAASampleSessionHolder *holder = new AAASampleSessionHolder(myCore, 0);

      if (holder) {

         ACE_DEBUG((LM_DEBUG, "(%P|%t) Client: Starting client # %d\n", i));

         holder->clientSession().destHost(destHost);

         holder->clientSession().destRealm(destRealm);

         holder->acctSession().destRealm(destRealm);

         /*
          * A call to start session will create the session
          * id and add this session to the local database.
          * On success, a session may be established with
          * a server by sending an authorization request.
          */
         holder->clientSession().Start();

         /*
          * Send the auth request
          */
         holder->clientSession().SendTestAuth();

         /*
          * Start accounting
          */
         holder->acctSession().SetInterimRecordInterval(AAAAccountingClientSession::RECTYPE_EVENT, 
                                                        0, // collect records immediately 
                                                        NULL);

         /*
          * Applications need to call Update on the session
          * to notify the library wether the application
          * specific authorization request was successful or
          * not. This processing is application specific and
          * can only be done at the application level. But since
          * the result is required by the session state machine,
          * an update call is necessary.
          */
         holder->clientSession().Update(AAASession::EVENT_AUTH_REQUEST);

         /* store our holders and cleanup later */
         _holderList.push_back(holder);
      }
   }

   /*
    * This is to make sure we wait for accounting
    * session to complete
    */
   ACE_OS::sleep(AAASampleAccountingRequestMsg::rec_threshold * 2);

   /*
    * this will block until all session are done.
    * i.e. thier HandleDisconnect() is called.
    */
   AAASampleClient::semaphore().acquire();

   /*
    * cleanup our allocations. we delete all
    * our client allocations here.
    */
   while (! _holderList.empty()) {
      AAASampleSessionHolder *holder = _holderList.front();
      _holderList.pop_front();
      delete holder;
   }

   ACE_DEBUG((LM_DEBUG, "(%P|%t) Client: Exiting\n"));

   return (0);
}




Generated on Fri Jun 25 19:12:01 2004 for Open Diameter C++ API by doxygen 1.3.5