#include /* UINT_MAX */ #include #include #include #include /* time() */ #include /* sig_atomic_t */ #include "rtr.h" /* Copyright 1994 Compaq Computer Corporation. Confidential computer software. Valid license from Compaq required for possession, use or copying. Consistent with FAR 12.211 and 12.212, Commercial Computer Software, Computer Software, Computer Software Documentation, and Technical Data for Commercial Items are licensed to the U.S. Government under vendor's standard commercial license. Compaq, the Compaq logo, and the Digital logo are registered in the U.S. Patent and Trademark Office. */ /* File: rtrreq.c Purpose: sample RTR application, used in Installation Verification Procedure On Tru64 Unix: compile with ANSI C compiler and link using: % cc -std -o rtrreq rtrreq.c -lrtr or % cc -std -pthread -o rtrreq rtrreq.c -lrtr_r On Windows: build multithreaded console application using: > nmake rtrreq.exe CFLAGS="/MT rtrdll.lib" On OpenVMS: build using: $ CC/DECC rtrreq $ LINK rtrreq,sys$input/opt sys$share:librtr.exe/share or sys$share:librtr_r.exe/share Simple test on one node: - start rtr and create the facility on your node: > rtr start rtr % rtr create facility /all_roles=`uname -n` $ rtr create facility /all_roles='F$GETSYI("NODENAME") > rtr create facility /all_roles=%COMPUTERNAME% - run the server, in another window or in the background: % ./rtrsrv & $ spawn/nowait rtrsrv > start rtrsrv - run this client: > rtrreq */ /* This RTR application program is written in ANSI C with the assumption * that printf "%d" int format tokens can also be used for 32 bit datatypes. */ /******************************************************************************/ static void print_rtr_status_data ( const void *rcvbuf ) { const rtr_status_data_t *pstd ; pstd = rcvbuf ; /* assumes caller provided an aligned rcvbuf */ printf ( " status: %s (%d)\n", rtr_error_text(pstd->status), pstd->status ) ; printf ( " reason: %d\n", pstd->reason ) ; } /******************************************************************************/ static void print_rtr_event_text ( rtr_evtnum_t evtnum ) { switch ( evtnum ) { case RTR_EVTNUM_FACREADY: printf ( "FACREADY - facility ready\n" ) ; break ; case RTR_EVTNUM_FACDEAD: printf ( "FACDEAD - facility not ready\n" ) ; break ; case RTR_EVTNUM_FERTRGAIN: printf ( "FERTRGAIN - FE link to router\n" ) ; break ; case RTR_EVTNUM_FERTRLOSS: printf ( "FERTRLOSS - FE lost link to router\n" ) ; break ; case RTR_EVTNUM_RTRBEGAIN: printf ( "RTRBEGAIN - router link to BE\n" ) ; break ; case RTR_EVTNUM_RTRBELOSS: printf ( "RTRBELOSS - router lost link to BE\n" ) ; break ; case RTR_EVTNUM_KEYRANGEGAIN: printf ( "KEYRANGEGAIN - new key range available\n" ) ; break ; case RTR_EVTNUM_KEYRANGELOSS: printf ( "KEYRANGELOSS - a key range not available\n" ) ; break ; case RTR_EVTNUM_BERTRGAIN: printf ( "BERTRGAIN - BE link to a router\n" ) ; break ; case RTR_EVTNUM_BERTRLOSS: printf ( "BERTRLOSS - BE lost link to a router\n" ) ; break ; case RTR_EVTNUM_RTRFEGAIN: printf ( "RTRFEGAIN - Router link to an FE\n" ) ; break ; case RTR_EVTNUM_RTRFELOSS: printf ( "RTRFELOSS - Router lost link to an FE\n" ) ; break ; case RTR_EVTNUM_SRPRIMARY: printf ( "SRPRIMARY - Server is primary mode\n" ) ; break ; case RTR_EVTNUM_SRSTANDBY: printf ( "SRSTANDBY - Server is standby mode\n" ) ; break ; case RTR_EVTNUM_SRSECONDARY: printf ( "SRSECONDARY - Server is secondary mode\n" ) ; break ; case RTR_EVTNUM_SRSHADOWLOST: printf ( "SRSHADOWLOST - Server lost shadow\n" ) ; break ; case RTR_EVTNUM_SRSHADOWGAIN: printf ( "SRSHADOWGAIN - Server gained shadow\n" ) ; break ; case RTR_EVTNUM_SRRECOVERCMPL: printf ("SRRECOVERCMPL - Server recovered\n" ) ; break ; default: printf ( "Unexpected RTR event %u\n", evtnum ) ; } } /******************************************************************************/ static volatile int nr_wakeup_calls; /* strictly: volatile sig_atomic_t */ /* asynchronous callback */ static void application_wakeup_routine ( void ) { /* CAUTION: wakeup callback routines are executed asynchronously. * Please consult your programming documentation to see what is allowed here. * * - OpenVMS AST * non-blocking rtr api calls are permitted * AST-reentrant library and system calls are permitted * in main code: disable and restore AST to access shared data safely * * - WIN32 threads and UNIX pthreads (wakeups supported but not needed) * application must be built with threads and linked with reentrant libraries * non-blocking rtr api calls are permitted * thread-safe library and system calls are permitted * use CRITICAL_SECTION or mutex to access shared data safely * * - unthreaded UNIX signal * NO rtr api calls, NO malloc(), NO printf(), NO exit()! * in main code: disable and restore SIGIO to access shared data safely */ nr_wakeup_calls++ ; /* volatile sig_atomic_t */ /* Typical AST wakeup handler (also works with threads): * do * rtr_receive_message with zero timeout * insert any message received in a properly synchronised queue * while status == RTR_STS_OK * * in main code: wait on queue for rtr and other messages * * Typical UNIX signal wakeup handler: * if volatile flag not set, write() one byte to a pipe and set flag * * in main code: select(), reset flag, read() all, receive message(s) */ } /******************************************************************************/ static void print_msgsb ( const rtr_msgsb_t *pmsgsb, const void *rcvbuf ) { switch ( pmsgsb->msgtype ) { case rtr_mt_msg1: printf ( "rtr_mt_msg1 - first message of a transaction\n" ) ; break ; case rtr_mt_msgn: printf ( "rtr_mt_msgn - nth message (i.e. not the first) of a tx\n" ) ; break ; case rtr_mt_msg1_uncertain: printf ( "rtr_mt_msg1_uncertain - first message - might have been received\n" ) ; break ; case rtr_mt_reply: printf ( "rtr_mt_reply - message sent by a server to a client\n" ) ; break ; case rtr_mt_prepare: printf ( "rtr_mt_prepare - expects server to accept or reject\n" ) ; break ; case rtr_mt_rtr_event: printf ( "rtr_mt_rtr_event - received message is an RTR event\n" ) ; print_rtr_event_text ( pmsgsb->evtnum ) ; break ; case rtr_mt_user_event: printf ( "rtr_mt_user_event - received message is a user event\n" ) ; break ; case rtr_mt_accepted: printf ( "rtr_mt_accepted - tx has been accepted by all participants\n" ) ; print_rtr_status_data ( rcvbuf ) ; break ; case rtr_mt_rejected: printf ( "rtr_mt_rejected - specified tx was rejected by a participant\n" ) ; print_rtr_status_data ( rcvbuf ) ; break ; case rtr_mt_opened: printf ( "rtr_mt_opened - channel opened\n" ) ; print_rtr_status_data ( rcvbuf ) ; break ; case rtr_mt_closed: printf ( "rtr_mt_closed - channel closed\n" ) ; print_rtr_status_data ( rcvbuf ) ; break ; case rtr_mt_request_info: printf ( "rtr_mt_request_info - message from rtr_request_info\n" ) ; break ; case rtr_mt_set_info: printf ( "rtr_mt_set_info - message from rtr_set_info\n" ) ; break ; case rtr_mt_rettosend: printf ( "rtr_mt_rettosend - message has been returned to sender\n" ) ; break ; case rtr_mt_prepared: /* new in RTR 3.2 */ printf ( "rtr_mt_prepared - tx has been prepared by all participants\n" ) ; break ; default: printf ( "Unexpected msgtype %d\n", pmsgsb->msgtype ) ; } printf (" usrhdl: %lu msglen: %u evtnum: %u\n", (unsigned long)pmsgsb->usrhdl, pmsgsb->msglen, pmsgsb->evtnum ) ; printf (" tid: %x,%x,%x,%x,%x,%x,%x\n", /* varies between runs */ pmsgsb->tid.tid32[0], pmsgsb->tid.tid32[1], pmsgsb->tid.tid32[2], pmsgsb->tid.tid32[3], pmsgsb->tid.tid32[4], pmsgsb->tid.tid32[5], pmsgsb->tid.tid32[6] ) ; } /******************************************************************************/ static void exit_if_error ( const char *msgtxt, rtr_status_t sts ) { if ( sts > 0 ) /* success */ { return ; } /* this sample application does not attempt to survive acp restart */ printf ( "%s unexpected error\n", msgtxt); printf ( " status: %s (%d)\n", rtr_error_text(sts), sts ) ; rtr_set_wakeup ( NULL ) ; exit (EXIT_FAILURE); } /******************************************************************************/ static void continue_if_error ( const char *msgtxt, rtr_status_t sts ) { if ( sts > 0 ) { printf ( "%s didn't get expected error\n", msgtxt); printf ( " status: %s (%d)\n", rtr_error_text(sts), sts); rtr_set_wakeup ( NULL ) ; exit (EXIT_FAILURE); } else { /* might even get a completely different error... */ printf ( "%s got expected error\n", msgtxt); printf ( " status: %s (%d)\n", rtr_error_text(sts), sts); return ; } } /******************************************************************************/ /* Application-specific definitions */ #define APITSTBUFSIZ 10000 /* Client application */ int main ( int argc, char *argv[] ) { char string_buf[128]; /* real programs check array bounds before strcpy() */ /* ensure sufficient alignment for print_rtr_status_data using: * union or * void * rcvbuf = malloc(APITSTBUFSIZ); */ union { char buf [ APITSTBUFSIZ ] ; rtr_status_data_t aligned_status_data; } rcvbuffer, *rcvbuf = &rcvbuffer; /* buffer for incoming rtr_receive_messages */ rtr_channel_t opened_client_channel ; /* set by rtr_open_channel */ rtr_channel_t received_message_channel ; /* set by rtr_receive_message */ rtr_msgsb_t msgsb; /* message status block */ rtr_status_t sts; const rtr_evtnum_t pevtnum[] = { RTR_EVTNUM_USERDEF, RTR_EVTNUM_USERBASE, RTR_EVTNUM_UP_TO, RTR_EVTNUM_USERMAX, RTR_EVTNUM_RTRDEF, RTR_EVTNUM_RTRBASE, RTR_EVTNUM_UP_TO, RTR_EVTNUM_RTRMAX, RTR_EVTNUM_ENDLIST }; printf ( "RTR V3.2 rtrreq Test Client\n" ) ; printf ( "------------------------------ rtr_set_wakeup\n" ) ; sts = rtr_set_wakeup ( /* wakeup routine */ application_wakeup_routine ); /* remember to cancel rtr_set_wakeup before exit */ exit_if_error ( "rtr_set_wakeup", sts ) ; printf ( "------------------------------ client rtr_open_channel\n" ) ; sts = rtr_open_channel ( /* pchannel */ &opened_client_channel, /* flags */ RTR_F_OPE_CLIENT, /* facnam */ "RTR$DEFAULT_FACILITY", /* chanam */ "TEST_CHUNNEL", /* pevtnum */ pevtnum, /* access */ "ACCSTR", /* numseg */ 0, /* pkeyseg */ RTR_NO_PKEYSEG ) ; exit_if_error ( "rtr_open_channel", sts ) ; /* expect rtr_mt_opened */ printf ( "------------------------------ rtr_receive_message\n" ) ; sts = rtr_receive_message ( /* pchannel */ &received_message_channel, /* flags */ RTR_NO_FLAGS, /* prcvchan */ RTR_ANYCHAN, /* pmsg */ rcvbuf, /* maxlen */ APITSTBUFSIZ, /* timoutms */ RTR_NO_TIMOUTMS, /* forever */ /* pmsgsb */ &msgsb ) ; exit_if_error ( "rtr_receive_message", sts ) ; printf ( "Got message on channel %u\n", received_message_channel ) ; print_msgsb ( &msgsb, rcvbuf ) ; printf ( "------------------------------ rtr_send_to_server\n" ) ; strcpy ( string_buf, "message from client to server" ); sts = rtr_send_to_server ( /* channel */ opened_client_channel, /* flags */ RTR_NO_FLAGS, /* pmsg */ string_buf, /* msglen */ strlen (string_buf) + 1, /* msgfmt */ RTR_NO_MSGFMT ) ; exit_if_error ( "rtr_send_to_server", sts ) ; printf ( "------------------------------ rtr_send_to_server again\n" ) ; strcpy ( string_buf, "a second message" ); sts = rtr_send_to_server ( /* channel */ opened_client_channel, /* flags */ RTR_NO_FLAGS, /* pmsg */ string_buf, /* msglen */ strlen (string_buf) + 1, /* msgfmt */ RTR_NO_MSGFMT ) ; exit_if_error ( "rtr_send_to_server", sts ) ; printf ( "------------------------------ rtr_accept_tx\n" ) ; sts = rtr_accept_tx ( /* channel */ opened_client_channel, /* flags */ RTR_NO_FLAGS, /* reason */ RTR_NO_REASON ) ; exit_if_error ( "rtr_accept_tx", sts ) ; printf ( "------------------------------ wait on wrong channel\n" ) ; { const rtr_channel_t rcvchans[] = { UINT_MAX-1, RTR_CHAN_ENDLIST } ; sts = rtr_receive_message ( /* pchannel */ &received_message_channel, /* flags */ RTR_NO_FLAGS, /* prcvchan */ rcvchans, /* pmsg */ rcvbuf, /* maxlen */ APITSTBUFSIZ, /* timoutms */ 10000, /* 10 seconds */ /* pmsgsb */ &msgsb ) ; } /* expect INVCHANNEL * or CHANOTOPE */ continue_if_error ( "rtr_receive_message", sts ) ; printf ( "------------------------------ rtr_receive_message\n" ) ; /* what message(s) are we expecting here? */ sts = rtr_receive_message ( /* pchannel */ &received_message_channel, /* flags */ RTR_NO_FLAGS, /* prcvchan */ RTR_ANYCHAN, /* pmsg */ rcvbuf, /* maxlen */ APITSTBUFSIZ, /* timoutms */ RTR_NO_TIMOUTMS, /* forever */ /* pmsgsb */ &msgsb ) ; exit_if_error ( "rtr_receive_message", sts ) ; printf ( "Got message on channel %u\n", received_message_channel ) ; print_msgsb ( &msgsb, rcvbuf ) ; printf ( "------------------------------ rtr_broadcast_event\n" ) ; sts = rtr_broadcast_event ( /* channel */ opened_client_channel, /* flags */ RTR_NO_FLAGS, /* pmsg */ string_buf, /* msglen */ strlen (string_buf) + 1, /* evtnum */ RTR_EVTNUM_USERBASE+42, /* rcpnam */ "RECEIVER", /* msgfmt */ RTR_NO_MSGFMT ) ; printf ( "------------------------------ incorrect rtr_reject_tx\n" ) ; sts = rtr_reject_tx ( /* channel */ opened_client_channel, /* flags */ RTR_NO_FLAGS, /* reason */ RTR_NO_REASON ) ; /* expect TXNOTACT */ continue_if_error ( "rtr_reject_tx", sts ) ; printf ( "------------------------------ client rtr_close_channel\n" ) ; sts = rtr_close_channel ( /* channel */ opened_client_channel, /* flags */ RTR_NO_FLAGS ) ; exit_if_error ( "rtr_close_channel", sts ) ; /* expect rtr_mt_closed */ printf ( "------------------------------ rtr_set_wakeup NULL\n" ) ; rtr_set_wakeup ( /* wakeup routine */ NULL ) ; printf ( "Wakeups: %d\n", nr_wakeup_calls ) ; /* varies between runs */ printf ( "------------------------------ normal exit\n" ) ; return( EXIT_SUCCESS ); }