/* IBM_PROLOG_BEGIN_TAG */ /* This is an automatically generated prolog. */ /* */ /* */ /* */ /* Licensed Materials - Property of IBM */ /* */ /* (C) COPYRIGHT International Business Machines Corp. 1998,2019 */ /* All Rights Reserved */ /* */ /* US Government Users Restricted Rights - Use, duplication or */ /* disclosure restricted by GSA ADP Schedule Contract with IBM Corp. */ /* */ /* IBM_PROLOG_END_TAG */ static const char *sccsid = "@(#)54 1.5 src/rsct/pgs/samples/Sample_Subscription.C, gssamples, rsct_rady, rady2035a 5/31/14 14:45:05"; #if !defined(_HAGSD_COPYRIGHT_H) #define _HAGSD_COPYRIGHT_H static const char copyright[] = "Licensed Materials - Property of IBM\n\ (C) COPYRIGHT International Business Machines Corp. 1998,2001.\n\ All Rights Reserved.\n\ US Government Users Restricted Rights - Use, duplication or \n\ disclosure restricted by GSA ADP Schedule Contract with IBM Corp.\n"; #endif /*********************************************************************/ /* * Name: Sample_Subscription.C * * This class represents a "subscription" to a group with Group * Services. It takes as input the targeted group name and other * control info, sets up the subscription, and deals with the * notifications we receive from GS. * * See Sample_Subscribe.C for more info. */ /*********************************************************************/ #include #include #include "Sample_Subscription.h" #include "Sample_ProviderTable.h" // The group's provider display table. #include "Sample_FrameTable.h" // Used to build each frame. /*********************************************************************/ /* * Construct a Subscription. Use the group name and control information * to register a subscription with Group Services. If all goes well, * then set the status based on synchronous return code, we have to * await a notification for final results. */ /*********************************************************************/ Subscription::Subscription(char *_targetGroup, int _subControl, int _persistent, providerDisplayType _displayType, specialDisplayType _displaySpecial, ha_gs_subscription_cb_t _callback) { groupName = NULL; displayType = _displayType; persistence = _persistent; displaySpecial = (specialDisplayType)(_displaySpecial & kAllSpecial); subControl = _subControl; if (kNothing == _subControl) { cerr << "ERROR: Invalid subscription control [" << _subControl << "] given." << endl; status = HA_GS_NOT_OK; return; } groupName = new char[strlen(_targetGroup) + 1]; strcpy(groupName, _targetGroup); info.gs_subscribe_request.gs_subscription_control = (ha_gs_subscription_ctrl_t)_subControl; info.gs_subscribe_request.gs_subscription_group = groupName; info.gs_subscribe_request.gs_subscription_callback = _callback; status = ha_gs_subscribe(&subToken, &info); if (HA_GS_OK == status) { cout << "Subscription for group [" << groupName << "] accepted with token [" << subToken << "]. Awaiting notifications." << endl; } else { cerr << "ERROR: Subscription for group [" << groupName << "] NOT accepted, error[" << WriteAnRC(status) << "] Exiting." << endl; exit(status); } cout.flush(); // Ensure output goes out. return; } /*********************************************************************/ /* * Destructor. Unsubscribe to the group if currently subscribed. */ /*********************************************************************/ Subscription::~Subscription(void) { if (Good() && !Dissolved()) { status = ha_gs_unsubscribe(subToken); if (HA_GS_OK == status) { cout << "Unsubscription for group [" << groupName << "] accepted with token [" << subToken << "]." << endl; } else { cerr << "ERROR: Unsubscription for group [" << groupName << "] NOT accepted, error[" << WriteAnRC(status) << "] Exiting." << endl; exit(status); } cout.flush(); // Ensure output goes out. } delete groupName; return; } /*********************************************************************/ /* * Handle a delayed error. This means that the subsription is nuked, * so we are not valid. */ /*********************************************************************/ ha_gs_rc_t Subscription::HandleDelayedError(const ha_gs_delayed_error_notification_t *_note) { ha_gs_token_t eToken; ha_gs_request_t eRequest; ha_gs_rc_t eRC; eToken = _note->gs_request_token; eRequest = _note->gs_protocol_type; eRC = _note->gs_delayed_return_code; cerr << "Time now [" << WriteTheTime() << "]" << endl; cerr << "ERROR: Delayed error on subscription to [" << groupName << "]. Error code [" << WriteAnRC(eRC) << "]." << endl; persistence = 0; status = eRC; return(status); } /*********************************************************************/ /* * What we live for, a subscription notification. Parse it, print out * the provider list in the specified mode. Special interest is whether * the subscription has been dissolved for some reason, if so, be sure * to turn off the persistence flag if it is set. * * Return the number of providers. */ /*********************************************************************/ int Subscription::HandleNotification(const ha_gs_subscription_notification_t *_note) { int _numProviders = 0; cout << "Time now [" << WriteTheTime() << "]" << endl; cout << "Subscription notification for group [" << groupName << "]" << endl; subSummary = _note->gs_subscription_type; WriteSubType(subSummary); WriteSpecialControl(_note->gs_subscription_type, _note->gs_subscription_special_data); if (HA_GS_SUBSCRIPTION_DISSOLVED & _note->gs_subscription_type) { persistence = 0; } /*********************************************************************/ /* * If we want membership, we may want either full membership all of * the time, or deltas only, or both... * * Display control specifies what we do next. If "raw", we want to * display in order given by Group Services. If "ordered" or "table" * then we need to do some more involved processing. */ if ((HA_GS_SUBSCRIPTION_MEMBERSHIP & _note->gs_subscription_type) || (HA_GS_SUBSCRIPTION_DELTA_LEAVE & _note->gs_subscription_type) || (HA_GS_SUBSCRIPTION_DELTA_JOIN & _note->gs_subscription_type)) { if (!((kJoins|kLeaves|kMembership) & subControl)) { cerr << "ERROR: Do not want membership info, but received it!" << endl; persistence = 0; return(_numProviders); } // Deal with leaving and joining providers. if ((HA_GS_SUBSCRIPTION_DELTA_LEAVE & _note->gs_subscription_type) || (HA_GS_SUBSCRIPTION_DELTA_JOIN & _note->gs_subscription_type)) { cout << "Changing providers list:"; PrintProviders(_note->gs_changing_membership, FindSpecial(HA_GS_CHANGING_ADAPTER_ALIAS_ARRAY, _note->gs_subscription_special_data), FindSpecial(HA_GS_ADAPTER_DEATH_ARRAY, _note->gs_subscription_special_data)); } // Now the full provider list. if (HA_GS_SUBSCRIPTION_MEMBERSHIP & _note->gs_subscription_type) { cout << "Current providers list:"; _numProviders = PrintProviders(_note->gs_full_membership, FindSpecial(HA_GS_CURRENT_ADAPTER_ALIAS_ARRAY, _note->gs_subscription_special_data)); } } if (HA_GS_SUBSCRIPTION_STATE & _note->gs_subscription_type) { PrintState(_note->gs_state_value); } return(_numProviders); } /*********************************************************************/ /* * Detrmine print control, print provider list as appropriate. */ /*********************************************************************/ int Subscription::PrintProviders(ha_gs_membership_t *_membership, ha_gs_special_block_t *_aliasBlock, ha_gs_special_block_t *_deathBlock) { int _numProviders = _membership->gs_count; ha_gs_provider_t *_provider = _membership->gs_providers; if (0 == _numProviders) { cout << " Provider count [" << _numProviders << "] Provider list [Empty!]" << endl; } else { cout << " Provider count [" << _numProviders << "] Provider list [" << endl; if (kRaw == displayType) { PrintRaw(_numProviders, _provider, _aliasBlock, _deathBlock); } else if (kOrdered == displayType) { PrintOrdered(_numProviders, _provider, _aliasBlock, _deathBlock); } else { PrintTabular(_numProviders, _provider, _aliasBlock, _deathBlock); } cout << "]" << endl; } cout.flush(); return(_numProviders); } /*********************************************************************/ /* * Print out the membership list in "raw" format, ordered exactly as * given to us. * * Only care is to try and limit each line to 80 chars, to allow the * "usual" screen width. * * Since it is the case that any special data will be ordered to match * the "raw" membership list, we need simply walk the special data and * print it out in the given order. Do this as a separate step after * printing out the membership. */ /*********************************************************************/ void Subscription::PrintRaw(int _count, ha_gs_provider_t *_provider, ha_gs_special_block_t *_aliasBlock, ha_gs_special_block_t *_deathBlock) { int _outNum, _pLen; short _instance, _node; _outNum = 0; for (int i = 0; i < _count; i++, _provider++) { _instance = _provider->gs_instance_number; _node = _provider->gs_node_number; _pLen = PrintLength(_instance, _node); if (80 < (_pLen + _outNum)) { cout << endl; _outNum = 0; } cout << _instance << "/" << _node << " "; _outNum += _pLen; } if (0 != _outNum) cout << endl; int _entries, _length; unsigned int *_IPaddr; ha_gs_adapter_death_t *_death; char *_IPprint; if (NULL != _aliasBlock) { _entries = _aliasBlock->gs_special_num_entries; _length = (_aliasBlock->gs_special_length / sizeof(unsigned int)); _IPaddr = (unsigned int *)_aliasBlock->gs_special; cout << "Adapter alias array: " << endl; for (_outNum = 0, _pLen = 0; 0 < _entries; _entries--, _IPaddr += _length, _outNum += _pLen) { _IPprint = inet_ntoa(*(struct in_addr *)_IPaddr); _pLen = strlen(_IPprint); if (80 < (_outNum + _pLen)) { cout << endl; _outNum = 0; } cout << _IPprint << " "; } cout << endl; } if (NULL != _deathBlock) { _entries = _deathBlock->gs_special_num_entries; _length = _deathBlock->gs_special_length; _death = (ha_gs_adapter_death_t *)_deathBlock->gs_special; cout << "Adapter death array: " << endl; for (_outNum = 0; 0 < _entries; _entries--, _death++) { if (80 < _outNum) { cout << endl; _outNum = 0; } if (HA_GS_ADAPTER_DEAD == *_death) { cout << "Dead "; _outNum += 5; } else if (HA_GS_ADAPTER_REMOVED == *_death) { cout << "Removed "; _outNum += 8; } else { cout << "Unknown "; _outNum += 8; } } cout << endl; } return; } /*********************************************************************/ /* * Print out the membership list in "ordered" format, sorted by node * number. * * As for the special data, we will have to walk the special data * blocks, if given, and pass the data in so that it can be held with * the providers. That allows us to "sort" the special data and print * it out in the same order as we print the providers. */ /*********************************************************************/ void Subscription::PrintOrdered(int _count, ha_gs_provider_t *_provider, ha_gs_special_block_t *_aliasBlock, ha_gs_special_block_t *_deathBlock) { short _instance, _node; ProviderTable _providerTable; int _IPentries, _IPlength, _deathEntries, _deathLength; unsigned int *_IPaddr; ha_gs_adapter_death_t *_death; VerifySpecialEntries(_count, &_aliasBlock, &_deathBlock, &_IPentries, &_IPlength, &_IPaddr, &_deathEntries, &_deathLength, &_death); for (int i = 0; i < _count; i++, _provider++) { _instance = _provider->gs_instance_number; _node = _provider->gs_node_number; _providerTable.Add(_instance, _node, _IPaddr, _death); if (NULL != _IPaddr) _IPaddr++; if (NULL != _death) _death++; } _providerTable.Print(); return; } /*********************************************************************/ /* * Print out the membership list in "tabular" format, convert to * frame/node number pairs, with list of provider instances on each * node. * * As for the special data, we will have to walk the special data * blocks, if given, and pass the data in so that it can be held with * the providers. That allows us to "sort" the special data and print * it out in the same order as we print the providers. */ /*********************************************************************/ void Subscription::PrintTabular(int _count, ha_gs_provider_t *_provider, ha_gs_special_block_t *_aliasBlock, ha_gs_special_block_t *_deathBlock) { short _instance, _node; FrameTable _frameTable; int _IPentries, _IPlength, _deathEntries, _deathLength; unsigned int *_IPaddr; ha_gs_adapter_death_t *_death; VerifySpecialEntries(_count, &_aliasBlock, &_deathBlock, &_IPentries, &_IPlength, &_IPaddr, &_deathEntries, &_deathLength, &_death); for (int i = 0; i < _count; i++, _provider++) { _instance = _provider->gs_instance_number; _node = _provider->gs_node_number; _frameTable.Add(_instance, _node, _IPaddr, _death); if (NULL != _IPaddr) _IPaddr++; if (NULL != _death) _death++; } _frameTable.Print(); return; } /*********************************************************************/ /* * Print out the group's state. Attempt to handle cases where the * state is not made up of printable characters. * * We first display as characters, representing non-printable characters * as periods ('.'). We then do either or both of the following: * - if the length is equivalent to one or more integers, display each * word as its integral value. * - display the whole value as a raw hex stream. */ /*********************************************************************/ void Subscription::PrintState(ha_gs_state_value_t *_state) { char *_val, *_val2; int _len, _len2, _cnt, _isize, _stpbmint; char *_buffer; char *_bufPtr; _len = _state->gs_length; _val = _state->gs_state; cout << "Group state value: Length [" << _len << "] Contents ["; if (0 >= _len) { /* Nothing here. */ cout << "]" << endl; return; } cout << endl; _buffer = new char[_len * 5]; /* Buffer in which to build string. */ /* * Display assuming it is actually printable. */ for (_len2 = _len, _val2 = _val, _bufPtr = _buffer; 0 < _len2; ) { for (_cnt = 0; ((4 > _cnt) && (0 < _len2)); _cnt++, _len2--) { if (isprint(*_val2)) { sprintf(_bufPtr++, "%c", *_val2++); } else { *_bufPtr++ = '.'; _val2++; } } } *_bufPtr++ = '\0'; cout << " [" << _buffer << "]" << endl; /* * If integral number of words, display as series of ints. */ _isize = sizeof(_stpbmint); if (0 == (_len % _isize)) { cout << " ["; if (_isize == _len) { /* assume an int */ memcpy(&_stpbmint, _val, sizeof(_stpbmint)); cout << _stpbmint; } else { /* assume series of ints */ for (_len2 = 0, _val2 = _val; _len2 < _len; _len2 += 4, _val2 += 4) { memcpy(&_stpbmint, _val2, sizeof(_stpbmint)); cout << _stpbmint; if (_len2 != (_len - 4)) { cout << " "; } } } cout << "]" << endl; } /* * Now, convert to "printable" hex. */ for (_len2 = _len, _val2 = _val, _bufPtr = _buffer; 0 < _len2; ) { sprintf(_bufPtr, "0x"); _bufPtr += 2; for (_cnt = 0; ((4 > _cnt) && (0 < _len2)); _cnt++, _len2--) { sprintf(_bufPtr, "%02x", *_val2++); _bufPtr += 2; } *_bufPtr++ = ' '; } *_bufPtr++ = '\0'; cout << " [" << _buffer << "]]" << endl; delete _buffer; return; } /*********************************************************************/ /* * Service routine, print out notification data. */ /*********************************************************************/ void Subscription::WriteSubType(const ha_gs_subscription_type_t _subType) { int foo; foo = 0; cout << "Subscription data["; if (HA_GS_SUBSCRIPTION_STATE & _subType) { cout << "HA_GS_SUBSCRIPTION_STATE"; foo++; } if (HA_GS_SUBSCRIPTION_DELTA_JOIN & _subType) { if (foo) { cout << endl << " "; foo = 0; } cout << "HA_GS_SUBSCRIPTION_DELTA_JOIN"; foo++; } if (HA_GS_SUBSCRIPTION_DELTA_LEAVE & _subType) { if (foo) { cout << endl << " "; foo = 0; } cout << "HA_GS_SUBSCRIPTION_DELTA_LEAVE"; foo++; } if (HA_GS_SUBSCRIPTION_MEMBERSHIP & _subType) { if (foo) { cout << endl << " "; foo = 0; } cout << "HA_GS_SUBSCRIPTION_MEMBERSHIP"; foo++; } if (HA_GS_SUBSCRIPTION_DISSOLVED & _subType) { if (foo) { cout << endl << " "; foo = 0; } cout << "HA_GS_SUBSCRIPTION_DISSOLVED"; foo++; } if (HA_GS_SUBSCRIPTION_SPECIAL_DATA & _subType) { if (foo) { cout << endl << " "; foo = 0; } cout << "HA_GS_SUBSCRIPTION_SPECIAL_DATA"; foo++; } #ifndef SAMPLE_22 if (HA_GS_SUBSCRIPTION_GS_HAS_DIED & _subType) { if (foo) { cout << endl << " "; foo = 0; } cout << "HA_GS_SUBSCRIPTION_GS_HAS_DIED"; } #endif /* SAMPLE_22 */ cout << "]" << endl; cout.flush(); } /*********************************************************************/ /* * Routines for dealing with the subscription "special" data. */ /*********************************************************************/ /*********************************************************************/ /* * Look for the specified type of special data block being included * in the notification. If found, return a pointer the special block * itself. If not found, or if the user doesn't want to display that * type of special data, return NULL. * * The blocks will be chained off of the _special block sent as input * to this method. */ /*********************************************************************/ ha_gs_special_block_t * Subscription::FindSpecial(const unsigned int _whichSpecial, ha_gs_special_data_t *_special) { ha_gs_special_block_t *_theBlock = NULL; if(_special == 0) return 0; // Check for "our kind" of special block being available, and also // being included in the display control list. if ((_whichSpecial & _special->gs_flag) && (_whichSpecial & displaySpecial)) { for (_theBlock = (ha_gs_special_block_t *)_special->gs_special_data; NULL != _theBlock; _theBlock = _theBlock->gs_next_special_block) { if (_whichSpecial & _theBlock->gs_special_flag) { break; } } } return(_theBlock); } /*********************************************************************/ /* * Verify that the counts for special data matches the count given for * the provider list. If it matches, then set the given count and * length variables for the caller. If a given "block" pointer is * NULL, simply leave its counts as zero, and consider it a valid * match. * * Return TRUE if all counts match (or one or more pointers are NULL) * and set the pointers to the first element in the special data array. * Return FALSE if either doesn't match, set that block pointer to * NULL, and its count and length to 0. */ /*********************************************************************/ int Subscription::VerifySpecialEntries(const int _count, ha_gs_special_block_t **_aliasBlock, ha_gs_special_block_t **_deathBlock, int *_IPentries, int *_IPlength, unsigned int **_IPaddr, int *_deathEntries, int *_deathLength, ha_gs_adapter_death_t **_death) { int _retVal = 1; ha_gs_special_block_t *_aBlock = *_aliasBlock; ha_gs_special_block_t *_bBlock = *_deathBlock; *_IPentries = 0; *_IPlength = 0; *_IPaddr = NULL; *_deathEntries = 0; *_deathLength = 0; *_death = NULL; if (NULL != _aBlock) { if (_count != _aBlock->gs_special_num_entries) { cerr << "ERROR: provider count is [" << _count << "] alias array count [" << *_IPentries << "]. Skipping alias printing." << endl; *_aliasBlock = NULL; _retVal = 0; } else { *_IPentries = _aBlock->gs_special_num_entries; *_IPlength = _aBlock->gs_special_length; *_IPaddr = (unsigned int *)_aBlock->gs_special; } } if (NULL != _bBlock) { if (_count != _bBlock->gs_special_num_entries) { cerr << "ERROR: provider count is [" << _count << "] death array count [" << *_deathEntries << "]. Skipping death printing." << endl; *_deathBlock = NULL; _retVal = 0; } else { *_deathEntries = _bBlock->gs_special_num_entries; *_deathLength = _bBlock->gs_special_length; *_death = (ha_gs_adapter_death_t *)_bBlock->gs_special; } } return(_retVal); } /*********************************************************************/ /* * Service routine, print out special data flags. */ /*********************************************************************/ void Subscription::WriteSpecialFlag(const unsigned int flag) { if (HA_GS_ADAPTER_DEATH_ARRAY & flag) { cout << " HA_GS_ADAPTER_DEATH_ARRAY"; } if (HA_GS_CURRENT_ADAPTER_ALIAS_ARRAY & flag) { cout << " HA_GS_CURRENT_ADAPTER_ALIAS_ARRAY"; } if (HA_GS_CHANGING_ADAPTER_ALIAS_ARRAY & flag) { cout << " HA_GS_CHANGING_ADAPTER_ALIAS_ARRAY"; } return; } /*********************************************************************/ /* * Service routine, print out special data control information. */ /*********************************************************************/ void Subscription::WriteSpecialControl(const ha_gs_subscription_type_t _subType, const ha_gs_special_data_t *_special) { if (0 == (HA_GS_SUBSCRIPTION_SPECIAL_DATA & _subType)) { return; } else if (NULL == _special) { cerr << "ERROR: Subscription type specifies \"special\" data, but pointer null!" << endl; return; } cout << "Subscription special data: Number blocks [" << _special->gs_length << "] Flags:" << endl; WriteSpecialFlag(_special->gs_flag); cout << endl; return; }