asn1set__SWIdent swIdent[] = { { asn1set__SWIdent__printableString,
{ "Terisa Demo Gateway Software v.beta1" } } };
int
gateway_reads_CapReq_writes_CapRes(instream, outstream)
io_ctx instream;
io_ctx outstream;
{
set_app_ctx app_ctx = 0; /* per-thread global data */
CapReq capReq = 0; /* SET message subtype */
CapRes capRes = 0; /* SET message subtype */
alloc_ctx heap = 0; /* memory is allocated from */
log_ctx history = 0; /* past-transaction info */
cache_ctx msg_cache[2]; /* per-transaction data */
int msg_type; /* asn1set__Message__... */
set_msg request = 0; /* SET message base type */
set_msg response = 0; /* SET message base type */
int status; /* return value */
/* Open the log. The log contains, for the most part, the
* RRPID and/or XID of messages that have been processed. This
* information is used primarily to detect repeated/replayed
* messages.
*
* SETREF expects there to be a single, global log file
* which the user manages. Instead of creating a local copy of
* the log, as is done here, it is more likely that a single,
* global 'history' would created when the application
* starts up. */
status = create_log_ctx_db(&history, "gateway.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.
*
* The set_app_ctx context contains "global" data that is specific
* to a single thread, in order to support multi-threaded
* applications. A single set_app_ctx may not be shared among
* threads.
*
* A set_app_ctx is independent of any message or transaction, such
* that a single set_app_ctx may be used to process multiple
* messages (or transactions) concurrently. */
status = create_set_app_ctx(&app_ctx, swIdent, history, "password", 8, 0, 0);
assert(status == NO_ERROR);
/* Create an alloc_ctx, which is a memory allocation abstraction
* based on the standard malloc allocator package.
*
* SETREF uses user-supplied heaps to allocate any memory that
* is "passed back" to the user. The user can incrementally free
* pointers using the AC_free() method, or can deallocate the
* entire heap using the AC_delete() method. */
status = create_pool_ctx(&heap);
assert(status == NO_ERROR);
/* Create a blank SET message and associate the heap "heap"
* with the message. All memory allocated and placed into
* "request" by receive_set_msg() or decode_set_msg() is
* allocated out of this heap.
*
* An instance of set_msg may only be associated with a
* single SET message. It may not be re-used.
*
* set_msg is the parent class for all SET messages.
* set_msg provides access to the SET message wrapper
* associated with an instance of a SET message.
*
* Objects of type set_msg, once they have a subtype, can be
* "cast" to their specific subtype. A newly-created set_msg
* does not yet have a subtype. */
status = create_set_msg(&request, app_ctx, heap);
assert(status == NO_ERROR);
/* Get the CapReq message from the io_ctx instream. After the
* call to receive_set_msg(), "msg_type" contains the subtype of
* the message that was read from the input stream. In addition,
* "request" now has a subtype and may be cast to its specific
* subtype.
*
* receive_set_msg() decodes the message's MessageWrapper,
* although this information is suspect and should only
* be used as a possible "hint" as to the contents of the
* message.
*
* receive_set_msg() will receive a message of any type, so it
* is important to check the msg_type parameter after receiving
* the message. */
status = receive_set_msg(request, app_ctx, instream, &msg_type);
assert(status == NO_ERROR);
assert(msg_type == asn1set__Message__capReq);
/* Decode and decrypt the message. After this call, the contents
* have been cryptographically verified, so the contents may
* be used to locate the appropriate per-transaction cache_ctx.
* Since the protocol verification step has not yet been performed,
* the contents should not be used for much more than locating
* the appropriate cache(s).
*
* decode_set_msg() will return a SET_WARN_ILLEGAL_REPLAY
* warning if this message has be received before. */
status = decode_set_msg(request, app_ctx);
assert(status == NO_ERROR);
/* Cast the set_msg "request" to its subtype, CapReq. If
* set_msg is not of type CapReq, then safe_cast_CapReq()
* will return a 0 pointer. */
capReq = safe_cast_CapReq(request);
assert(capReq != 0);
/* Open the per-transaction cache.
*
* Batch messages--which may contain more than one transaction--
* take an array of cache_ctx. Specifically, the user is expected
* to supply 1 cache_ctx per transaction, in the order in which
* they appear in the "CapSeq" capture sequence. The array element
* following the last cache_ctx must be zeroed.
*
* The code below assumes only a single transaction in the
* capture. This is incorrect.
*
* The transaction ID (XID) is used to identify the appropriate
* cache. */
status = create_cache_ctx_db(&msg_cache[0], xid2filename(
&capReq->capReqData.capSeq->capItem.transIDs.xID));
assert(status == NO_ERROR);
memset(&msg_cache[1], 0, sizeof(msg_cache[1]));
/* Perform protocol verification of the request message.
* After these checks have been performed, the contents
* of "request" can be used by the application.
*
* As a last step, verify_set_msg() will store message data in
* the cache(s). */
status = verify_set_msg(request, app_ctx, msg_cache);
assert(status == NO_ERROR);
/* Process CapReq message */
/* ... */
/* Create a blank SET message and associate the heap "heap"
* with the message. All memory allocated and placed into
* "request" by receive_set_msg() or decode_set_msg() is
* allocated out of this heap. */
status = create_set_msg(&response, app_ctx, heap);
assert(status == NO_ERROR);
/* Build the CapRes message by calling make_set_msg(). Previous
* state in this transaction (which at this point consists of
* at least the previous CapReq message) is obtained using
* "msg_cache".
*
* Protocol layer data is inserted into the message by
* make_set_msg(). The documentation for each message type
* enumerates the fields that make_set_msg() completes.
*
* As with verify_set_msg(), the user is expected to supply
* 1 cache_ctx per transaction, in the order in which
* the transactions are to appear in the CapResSeq
* sequence. */
msg_type = asn1set__Message__capRes;
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 CapRes. */
capRes = safe_cast_CapRes(response);
assert(capReq != 0);
/* Application-layer data is inserted into the message.
* Documentation for each message type enumerates the fields
* that the user _must_ complete. */
capRes->capResData.capResSeq->capResItem.capResPayload.capCode =
asn1set__CapCode__success;
capRes->capResData.capResSeq->capResItem.capResPayload.capAmt.currency =
capReq->capReqData.capSeq->capItem.capPayload.capReqAmt.currency;
capRes->capResData.capResSeq->capResItem.capResPayload.capAmt.amount =
capReq->capReqData.capSeq->capItem.capPayload.capReqAmt.amount;
capRes->capResData.capResSeq->capResItem.capResPayload.capAmt.amtExp10 =
capReq->capReqData.capSeq->capItem.capPayload.capReqAmt.amtExp10;
/* Send the CapRes message to the output stream "outstream".
* Again, the user is expected to supply an array of cache_ctx,
* 1 per transaction.
*
* As a last step, send_set_msg() will store message data in
* the cache(s). */
status = send_set_msg(response, app_ctx, msg_cache, outstream);
assert(status == NO_ERROR);
/* Perform the cleanup, by deleting any contexts which had been
* created. After being deleted, these contexts can no longer
* be used (unless they are created again). */
/* Delete the cache object. If another messages associated
* with this transaction were going to be processed, the
* cache could remain open and used to process messages
* associated with the transaction. */
status = CACHE_delete(&msg_cache[0]);
assert(status == NO_ERROR);
/* Delete the "response" and "request" set_msg objects. All
* memory allocated and placed in either of these objects was
* allocated from the alloc_ctx "heap". This memory will not
* be de-allocated by delete_set_msg(). Instead, the user is
* given control of when this memory will be deallocated.
*
* A set_msg object should be deleted before to deleting the
* heap associated with that object in order to prevent
* "dangling pointers". */
status = delete_set_msg(&response);
assert(status == NO_ERROR);
status = delete_set_msg(&request);
assert(status == NO_ERROR);
/* Delete the alloc_ctx "heap". After this call, there will
* be no per-message data left allocated. */
status = AC_delete(&heap);
assert(status == NO_ERROR);
/* Delete the thread-specific global context.
*
* If another message is going to be processed by this thread,
* even one that is part of another transaction, then app_ctx can
* be used to process that message, rather than being deleted. */
status = delete_set_app_ctx(&app_ctx);
assert(status == NO_ERROR);
/* Delete the global log context.
*
* Although the log is closed here, as long as the application
* doesn't exit, the log could remain open because there is
* only a single, global log.
*
* The log must be the last object deleted. */
status = LOG_delete(&history);
assert(status == NO_ERROR);
/* At this point, there is no SETREF memory left allocated. */
return NO_ERROR;
}
Copyright © 1996, 1997, Visa International Service Association and MasterCard International Incorporated
All Rights Reserved.