An Introductory Example

Below is an example demonstrating the use of SETREF. A similar example will be explicated in much greater detail at the end of the chapter.

asn1set__SWIdent   swIdent[] = { { asn1set__SWIdent__printableString, 
                                   { "Terisa Demo Merchant Software v.beta1" } } };
extern asn__any   *mer_dn;   /* Merchant DN */
extern asn__any   *pay_dn;   /* Payment Gateway DN */

int
merchant_reads_PInitReq_writes_PInitRes()
{
    set_app_ctx             app_ctx    = 0;  /* thread-specific global data */
    log_ctx                 history    = 0;  /* past-transaction info */
    cache_ctx               msg_cache  = 0;  /* per-transaction data */
    int                     msg_type;        /* asn1set__Message__... */
    PInitReq                pInitReq   = 0;  /* SET message subtype */
    PInitRes                pInitRes   = 0;  /* SET message subtype */
    set_msg                 request    = 0;  /* SET message base type */
    set_msg                 response   = 0;  /* SET message base type */
    asn1set__XID            xid;             /* transaction ID */
    int                     status;          /* return value */
    io_ctx                  stdin_ctx;       /* stdin input stream */
    io_ctx                  stdout_ctx;      /* stdout output stream */


    /*  Open the log, which contains information about previous 
     *  messages that have been processed.  The log is used 
     *  primarily to detect repeated/replayed messages. */

    status = create_log_ctx_db(&history, "merchant.log");
    assert(status == NO_ERROR);

    /*  Create the thread-specific context, setting the default software
     *  identifier to "swIdent", and using the 8-character password 
     *  "password" to unlock the certificate database.  No callback  
     *  function is specified. */ 
 
    status = create_set_app_ctx(&app_ctx, swIdent, history, "password", 8, 0, 0);
    assert(status == NO_ERROR);

    /*  Create a blank SET message and associate the heap "standard_heap"
     *  with the message.  All memory allocated and placed into 
     *  "request" by receive_set_msg() or decode_set_msg()
     *  will be allocated out of "standard_heap", which is a globally-defined
     *  alloc_ctx that performs no garbage collection. */

    status = create_set_msg(&request, app_ctx, standard_heap);
    assert(status == NO_ERROR);

    /*  Attached the standard I/O input stream "stdin" to the
     *  io_ctx "stdin_ctx" */

    status = create_stdio_ctx(&stdin_ctx, stdin);
    assert(status == NO_ERROR);

    /*  Get the PInitReq message from the stdin, which is specified using
     *  "stdin_ctx", an io_ctx connected to stdin.  After the call
     *  to receive_set_msg(), "msg_type" contains the type of the
     *  message that was read from the input stream. */

    status = receive_set_msg(request, app_ctx, stdin_ctx, &msg_type);
    assert(status == NO_ERROR);
    assert(msg_type == asn1set__Message__pInitReq);

    /*  Decode and decrypt the message. */

    status = decode_set_msg(request, app_ctx);
    assert(status == NO_ERROR);

    /*  The PInitReq message does not contain a transaction ID (XID), 
     *  so the merchant must create the XID */

    status = create_new_XID(&xid);
    assert(status == NO_ERROR);

    /*  Open the per-transaction cache.  Since the PInitReq message is
     *  probably the first message of the transaction that the merchant
     *  has received or sent, the following call will create a new
     *  cache with the supplied name, which in this case uses the 
     *  transaction ID (XID).  Moreover, this XID is then inserted into
     *  the cache to be later used by SETREF. */

    status = create_cache_ctx_db(&msg_cache, xid2filename(&xid));     
    assert(status == NO_ERROR);

    status = CACHE_put(msg_cache, STATE_XID, &xid);
    assert(status == NO_ERROR);

    /*  Verify the request message.  After the message has been verified,
     *  the contents of the message can safely be used.  Note, all memory
     *  allocated by verify_set_msg() that is passed back is allocated out
     *  of "standard_heap". */
     
    status = verify_set_msg(request, app_ctx, &msg_cache);
    assert(status == NO_ERROR);
 
    /*  After a call to verify_set_msg(), "request" can be cast to 
     *  its specific SET message subtype, in this case PInitReq.  If
     *  request is not a PInitReq message, then 0 is returned. */
     
    pInitReq = safe_cast_PInitReq(request);
    assert(pInitReq != 0);


    /* insert GATEWAY_DN into cache, based on BrandID in PInitReq */
    status = CACHE_put(msg_cache, STATE_GATEWAY_DN, pay_dn);
    assert(status == NO_ERROR);


    /*  Create a blank SET message and associate the heap "standard_heap"
     *  with the message.  All memory allocated and placed into 
     *  "response" by make_set_msg() or send_set_msg() will be
     *  allocated out of standard_heap, which is a globally-defined alloc_ctx
     *  that performs no garbage collection. */

    status = create_set_msg(&response, app_ctx, standard_heap);
    assert(status == NO_ERROR);

    /*  Build the PInitRes message by calling make_set_msg().  Previous  
     *  state in this transaction (which at this point only consists of
     *  the previous PInitReq message and XID) is obtained using 
     *  "msg_cache".  Protocol layer data is inserted into the message
     *  by make_set_msg(). */

    msg_type = asn1set__Message__pInitRes;
    status = make_set_msg(response, app_ctx, &msg_cache, msg_type);
    assert(status == NO_ERROR);

    /*  After a call to make_set_msg(), "response" can be cast to
     *  its specific SET message subtype, in this case PInitRes. */

    pInitRes = safe_cast_PInitRes(response);
    assert(pInitRes != 0);

    /*  Application-layer data is inserted into the message. */

    pInitRes->pInitResData.transIDs.pReqDate = time(0);
    pInitRes->merchantSignatureCID = mer_dn;

    /*  Attached the standard I/O output stream "stdout" to the
     *  io_ctx "stdout_ctx" */

    status = create_stdio_ctx(&stdout_ctx, stdout);
    assert(status == NO_ERROR);

    /*  The PInitRes message is sent to the output stream stdout,
     *  which is specified using stdout_ctx, an io_ctx connected
     *  to stdout. */
     
    status = send_set_msg(response, app_ctx, &msg_cache, stdout_ctx);
    assert(status == NO_ERROR);

    /*  Perform the cleanup by deleting any contexts which had been 
     *  created.  If another message is going to be processed, even 
     *  one that is part of another transaction, then app_ctx can
     *  be used to process that message, rather than being deleted. 
     *  The log is closed here, but as long as the application 
     *  doesn't quit, the log could remain open because there is
     *  normally only a single, global log. */

    status = IO_delete(&stdin_ctx);
    assert(status == NO_ERROR);

    status = IO_delete(&stdout_ctx);
    assert(status == NO_ERROR);

    status = CACHE_delete(&msg_cache);
    assert(status == NO_ERROR);

    status = delete_set_msg(&response);
    assert(status == NO_ERROR);

    status = delete_set_msg(&request);
    assert(status == NO_ERROR);

    status = delete_set_app_ctx(&app_ctx);
    assert(status == NO_ERROR);

    status = LOG_delete(&history);
    assert(status == NO_ERROR);

    return NO_ERROR;
}


Copyright © 1996, 1997, Visa International Service Association and MasterCard International Incorporated
All Rights Reserved.