Add Book to My BookshelfPurchase This Book Online

Appendix A - Pthreads and DCE

Pthreads Programming
Bradford Nichols, Dick Buttlar and Jacqueline Proulx Farrell
 Copyright © 1996 O'Reilly & Associates, Inc.

Example: The ATM as a DCE Server
Because our ATM server is a distributed application based on a client/server model, it's well suited for conversion to DCE. We'll do so in this section. 
In Example A-1, we'll create an IDL (Interface Definition Language) file that defines all possible client calls. DCE will use this file to generate the stubs the rpc_server_listen routine will use to marshal and unmarshal client/server messages. 
Example A-1: The IDL File for the DCE Version of the ATM Server
interface atm
{
    void open_account(
           [in]  handle_t  handle,
           [out] long      *id,
           [out] long      *success,
           [out] long      *passwd,
           [out] char      estring[20]);
    void deposit(
           [in]  handle_t  handle,
           [in]  long      *id,
           [in]  long      *password,
           [in]  long      *amt,
           [out] long      *success,
           [out] char      estring[20]);
    void withdraw(
           [in]  handle_t  handle,
           [in]  long      *id,
           [in]  long      *password,
           [in]  long      *amt,
           [out] long      *success,
           [out] char      estring[20]);
    void balance(
           [in]  handle_t  handle,
           [in]  long      *id,
           [in]  long      *password,
           [out] long      *success,
           [out] long      *cur_balance,
           [out] char      estring[20]);
}
In Example A-2, we'll modify our server itself. We'll add some DCE-specific initialization calls to its main routine, set the maximum number of worker threads, and call rpc_server_listen. At that point, the main routine enters the DCE run time for the duration of its run. 
Example A-2: The main Routine of the DCE Version of the ATM Server
#define SINTERFACE_SPEC            atm_v1_0_s_ifspec
#define MAX_CONC_CALLS_PROTSEQ     1
#define MAX_CONC_CALLS_TOTAL       10
extern int
main(argc, argv)
int argc;
char **argv;
{
  unsigned32               status;
  rpc_binding_vector_t     *binding_vector_p;
  /************************************************/
  /* DCE Runtime and Communication Initialization */
  /************************************************/
  /* Register with runtime */
  rpc_server_register_if(SINTERFACE_SPEC, NULL, NULL, &status);
  /* Designate a protocol sequence */
  rpc_server_use_all_protseqs(MAX_CONC_CALLS_PROTSEQ, &status);
  /* Obtain binding vector from runtime */
  rpc_server_inq_bindings(&binding_vector_p, &status);
  /* Register bindings with endpoint mapper */
  rpc_ep_register(SINTERFACE_SPEC, binding_vector_p, NULL,
  (unsigned_char_t *)EP_ANNO, &status);
  /* Export binding information to name service */
  rpc_ns_binding_export(rpc_c_ns_syntax_dce,
  (unsigned_char_t *)SERVER_NAME,
  SINTERFACE_SPEC,
  binding_vector_p, NULL, &status);
  /*********************************************/
  /* Initialization Routine for the ATM Server */
  /*********************************************/
  atm_server_init(argc, argv);
  /**************************************************/
  /* Jump to runtime listening loop, (Boss for(;;)) */
  /**************************************************/
  rpc_server_listen(MAX_CONC_CALLS_TOTAL, &status);
  return 0;
}
In Example A-3, we'll fix up our worker thread routines-that is, the server management routines that will be triggered when our clients make an RPC to our server. We specified the interface to these routines in the IDL file. If we were writing these routines from scratch, we'd need to ensure that they contained appropriate synchronization code. However, because we added the synchronization calls in Chapter 3, Synchronizing Pthreads, we can simply reuse the existing routines. 
For example, the code for the deposit server management routine remains pretty much the same, with the exception of the few IDL hooks at the beginning. Notice, too, that we've removed all the low-level code dealing with communication from our source code. DCE will take care of this for us. Our routine can now focus on its particular role in our application—that is, access to the bank account database. 
Example A-3: The DCE ATM Server Deposit Server Management Routine
void deposit(
  rpc_binding_handle_t handle,       /* in */
  idl_long_int *id,                  /* in */
  idl_long_int *password,            /* in */
  idl_long_int *amount,              /* in */
  idl_long_int *success,             /* out */
  idl_char estring[20])              /* out */
{
  int rtn;
  int temp;
  account_t *accountp;
  /* Check inputs */
  if ((*id < 0) || (*id >= MAX_NUM_ACCOUNTS)) {
    *success = TRANS_FAILURE;
    strncpy((char *)estring,ERR_MSG_BAD_ACCOUNT, ERR_MSG_SIZE);
    return;
  }
  pthread_mutex_lock(&account_mutex[*id]);
  /* Retrieve account from database */
  if ((rtn = retrieve_account( *id, &accountp)) < 0) {
    *success = TRANS_FAILURE;
    strncpy((char *)estring,atm_err_tbl[-rtn], ERR_MSG_SIZE);
  /* Check password */
  }else if (*password != accountp->password)  {
    *success = TRANS_FAILURE;
    strncpy((char *estring, ERR_MSG_BAD_PASSWORD, ERR_MSG_SIZE);
  /* Add new balance */
  }else {
    (accountp->balance) = *amount;
    /* Store back to database */
    if ((rtn = store_account(accountp)) < 0) {
      *success = TRANS_FAILURE;
      strncpy((char *)estring,atm_err_tbl[-rtn], ERR_MSG_SIZE);
    /* Everything OK */
    }else {
      *success = TRANS_SUCCESS;
    }
  }
  pthread_mutex_unlock(&account_mutex[*id]);
}

Previous SectionNext Section
Books24x7.com, Inc © 2000 –  Feedback