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.