Added group signature creation

Added return values for deferred sign function in identity and circles
Not ready for deferred sign testing yet

git-svn-id: http://svn.code.sf.net/p/retroshare/code/trunk@6199 b45a01b8-16f6-495d-af2f-9b41ad6348cc
This commit is contained in:
chrisparker126 2013-03-08 19:55:59 +00:00
parent 2cb52f0624
commit 83ec723d8d
8 changed files with 260 additions and 102 deletions

View File

@ -226,7 +226,7 @@ void RsGenExchange::generateGroupKeys(RsTlvSecurityKeySet& privatekeySet,
}
}
bool RsGenExchange::createGroup(RsNxsGrp *grp, RsTlvSecurityKeySet& privateKeySet, RsTlvSecurityKeySet& publicKeySet)
uint8_t RsGenExchange::createGroup(RsNxsGrp *grp, RsTlvSecurityKeySet& privateKeySet, RsTlvSecurityKeySet& publicKeySet)
{
std::cerr << "RsGenExchange::createGroup()";
std::cerr << std::endl;
@ -281,6 +281,11 @@ bool RsGenExchange::createGroup(RsNxsGrp *grp, RsTlvSecurityKeySet& privateKeySe
// add admin sign to grpMeta
meta->signSet.keySignSet[GXS_SERV::FLAG_AUTHEN_ADMIN] = adminSign;
RsTlvBinaryData grpData(mServType);
grpData.setBinData(allGrpData, allGrpDataLen);
uint8_t ret = createGroupSignatures(meta->signSet, grpData, *(grp->metaData));
// set meta to be transported as meta without private
// key components
grp->meta.setBinData(metaData, metaDataLen);
@ -298,9 +303,93 @@ bool RsGenExchange::createGroup(RsNxsGrp *grp, RsTlvSecurityKeySet& privateKeySe
{
std::cerr << "RsGenExchange::createGroup() ERROR !okay (getSignature error)";
std::cerr << std::endl;
return CREATE_FAIL;
}
return ok;
if(ret == SIGN_FAIL)
{
return CREATE_FAIL;
}else if(ret == SIGN_FAIL_TRY_LATER)
{
return CREATE_FAIL_TRY_LATER;
}else if(ret == SIGN_SUCCESS)
{
return CREATE_SUCCESS;
}else{
return CREATE_FAIL;
}
}
int RsGenExchange::createGroupSignatures(RsTlvKeySignatureSet& signSet, RsTlvBinaryData& grpData,
RsGxsGrpMetaData& grpMeta)
{
bool needIdentitySign = false;
int id_ret;
uint8_t author_flag = GXS_SERV::GRP_OPTION_AUTHEN_AUTHOR_SIGN;
PrivacyBitPos pos = GRP_OPTION_BITS;
// Check required permissions, and allow them to sign it - if they want too - as well!
if (checkAuthenFlag(pos, author_flag))
{
needIdentitySign = true;
std::cerr << "Needs Identity sign! (Service Flags)";
std::cerr << std::endl;
}
if (needIdentitySign)
{
if(mGixs)
{
bool haveKey = mGixs->havePrivateKey(grpMeta.mAuthorId);
if(haveKey)
{
RsTlvSecurityKey authorKey;
mGixs->getPrivateKey(grpMeta.mAuthorId, authorKey);
RsTlvKeySignature sign;
if(GxsSecurity::getSignature((char*)grpData.bin_data, grpData.bin_len,
&authorKey, sign))
{
id_ret = SIGN_SUCCESS;
}
else
{
id_ret = SIGN_FAIL;
}
signSet.keySignSet[GXS_SERV::FLAG_AUTHEN_IDENTITY] = sign;
}
else
{
mGixs->requestPrivateKey(grpMeta.mAuthorId);
std::cerr << "RsGenExchange::createGroupSignatures(): ";
std::cerr << " ERROR AUTHOR KEY: " << grpMeta.mAuthorId
<< " is not Cached / available for Message Signing\n";
std::cerr << "RsGenExchange::createGroupSignatures(): Requestiong AUTHOR KEY";
std::cerr << std::endl;
id_ret = SIGN_FAIL_TRY_LATER;
}
}
else
{
std::cerr << "RsGenExchange::createGroupSignatures()";
std::cerr << "Gixs not enabled while request identity signature validation!" << std::endl;
id_ret = SIGN_FAIL;
}
}
else
{
id_ret = SIGN_SUCCESS;
}
return id_ret;
}
int RsGenExchange::createMsgSignatures(RsTlvKeySignatureSet& signSet, RsTlvBinaryData& msgData,
@ -344,7 +433,7 @@ int RsGenExchange::createMsgSignatures(RsTlvKeySignatureSet& signSet, RsTlvBinar
needIdentitySign = false;
needPublishSign = false;
if (checkMsgAuthenFlag(pos, publish_flag))
if (checkAuthenFlag(pos, publish_flag))
{
needPublishSign = true;
std::cerr << "Needs Publish sign! (Service Flags)";
@ -352,7 +441,7 @@ int RsGenExchange::createMsgSignatures(RsTlvKeySignatureSet& signSet, RsTlvBinar
}
// Check required permissions, and allow them to sign it - if they want too - as well!
if (checkMsgAuthenFlag(pos, author_flag))
if (checkAuthenFlag(pos, author_flag))
{
needIdentitySign = true;
std::cerr << "Needs Identity sign! (Service Flags)";
@ -564,11 +653,11 @@ int RsGenExchange::validateMsg(RsNxsMsg *msg, const uint32_t& grpFlag, RsTlvSecu
pos = PRIVATE_GRP_BITS;
}
if (checkMsgAuthenFlag(pos, publish_flag))
if (checkAuthenFlag(pos, publish_flag))
needPublishSign = true;
// Check required permissions, if they have signed it anyway - we need to validate it.
if ((checkMsgAuthenFlag(pos, author_flag)) || (!msg->metaData->mAuthorId.empty()))
if ((checkAuthenFlag(pos, author_flag)) || (!msg->metaData->mAuthorId.empty()))
needIdentitySign = true;
@ -663,7 +752,7 @@ int RsGenExchange::validateMsg(RsNxsMsg *msg, const uint32_t& grpFlag, RsTlvSecu
}
bool RsGenExchange::checkMsgAuthenFlag(const PrivacyBitPos& pos, const uint8_t& flag) const
bool RsGenExchange::checkAuthenFlag(const PrivacyBitPos& pos, const uint8_t& flag) const
{
std::cerr << "RsGenExchange::checkMsgAuthenFlag(pos: " << pos << " flag: ";
std::cerr << (int) flag << " mAuthenPolicy: " << mAuthenPolicy << ")";
@ -1504,23 +1593,39 @@ void RsGenExchange::publishMsgs()
mMsgsToPublish.clear();
}
void RsGenExchange::service_CreateGroup(RsGxsGrpItem* grpItem, RsTlvSecurityKeySet& keySet)
RsGenExchange::ServiceCreate_Return RsGenExchange::service_CreateGroup(RsGxsGrpItem* grpItem, RsTlvSecurityKeySet& keySet)
{
#ifdef GEN_EXCH_DEBUG
std::cerr << "RsGenExchange::service_CreateGroup(): Does nothing"
<< std::endl;
#endif
return;
return SERVICE_CREATE_SUCCESS;
}
#define GEN_EXCH_GRP_CHUNK 3
#define GEN_EXCH_GRP_CHUNK 30
void RsGenExchange::publishGrps()
{
RsStackMutex stack(mGenMtx);
NxsGrpSignPendVect::iterator pend_it = mGrpPendingSign.begin();
for(; pend_it != mGrpPendingSign.end();)
{
GxsPendingSignItem<RsGxsGrpItem*, uint32_t>& gpsi = *pend_it;
if(gpsi.mAttempts == SIGN_MAX_ATTEMPTS)
{
pend_it = mGrpPendingSign.erase(pend_it);
}
else
{
gpsi.mAttempts++;
mGrpsToPublish.insert(std::make_pair(gpsi.mId, gpsi.mItem));
pend_it++;
}
}
std::map<uint32_t, RsGxsGrpItem*>::iterator mit = mGrpsToPublish.begin();
std::vector<uint32_t> toRemove;
int i = 0;
@ -1529,7 +1634,8 @@ void RsGenExchange::publishGrps()
if(i > GEN_EXCH_GRP_CHUNK-1) break;
toRemove.push_back(mit->first);
uint32_t token = mit->first;
toRemove.push_back(token);
i++;
RsNxsGrp* grp = new RsNxsGrp(mServType);
@ -1555,56 +1661,36 @@ void RsGenExchange::publishGrps()
}
}
bool ok = true;
uint8_t create = CREATE_FAIL;
if(privKeyFound)
{
// get group id from private admin key id
grpItem->meta.mGroupId = grp->grpId = privAdminKey.keyId;
}
else
{
ok = false;
}
//tempKeySet = privatekeySet;
privatekeySet.keys.insert(publicKeySet.keys.begin(),
publicKeySet.keys.end());
service_CreateGroup(grpItem, privatekeySet);
//privatekeySet = tempKeySet;
ServiceCreate_Return ret = service_CreateGroup(grpItem, privatekeySet);
uint32_t size = mSerialiser->size(grpItem);
char gData[size];
ok = mSerialiser->serialise(grpItem, gData, &size);
if (!ok)
{
std::cerr << "RsGenExchange::publishGrps() !ok ERROR After First Serialise" << std::endl;
}
bool serialOk = mSerialiser->serialise(grpItem, gData, &size);
grp->grp.setBinData(gData, size);
if(ok)
if(serialOk)
{
grp->metaData = new RsGxsGrpMetaData();
grpItem->meta.mPublishTs = time(NULL);
*(grp->metaData) = grpItem->meta;
grp->metaData->mSubscribeFlags = GXS_SERV::GROUP_SUBSCRIBE_ADMIN;
if (!createGroup(grp, privatekeySet, publicKeySet))
{
std::cerr << "RsGenExchange::publishGrps() !ok ERROR After createGroup" << std::endl;
}
else
{
create = createGroup(grp, privatekeySet, publicKeySet);
// ensure group size is not too large
ok &= mDataStore->validSize(grp);
if(ok)
if(create == CREATE_SUCCESS)
{
if(mDataStore->validSize(grp))
{
RsGxsGroupId grpId = grp->grpId;
mDataAccess->addGroupData(grp);
@ -1614,33 +1700,77 @@ void RsGenExchange::publishGrps()
// add to published to allow acknowledgement
mGrpNotify.insert(std::make_pair(mit->first, grpId));
mDataAccess->updatePublicRequestStatus(mit->first, RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE);
}
}
}
if(!ok)
}
else
{
create = CREATE_FAIL;
}
}
}
}
else
{
#ifdef GEN_EXCH_DEBUG
std::cerr << "RsGenExchange::publishGrps() Could not find private publish keys " << std::endl;
#endif
std::cerr << "RsGenExchange::publishGrps() failed to publish grp " << std::endl;
delete grp;
// add to published to allow acknowledgement, grpid is empty as grp creation failed
mGrpNotify.insert(std::make_pair(mit->first, RsGxsGroupId("")));
mDataAccess->updatePublicRequestStatus(mit->first, RsTokenService::GXS_REQUEST_V2_STATUS_FAILED);
continue;
create = CREATE_FAIL;
}
if(create == CREATE_FAIL)
{
#ifdef GEN_EXCH_DEBUG
std::cerr << "RsGenExchange::publishGrps() failed to publish grp " << std::endl;
#endif
delete grp;
delete grpItem;
// add to published to allow acknowledgement, grpid is empty as grp creation failed
mGrpNotify.insert(std::make_pair(token, RsGxsGroupId("")));
mDataAccess->updatePublicRequestStatus(token, RsTokenService::GXS_REQUEST_V2_STATUS_FAILED);
}
else if(create == CREATE_FAIL_TRY_LATER)
{
delete grp;
NxsGrpSignPendVect::iterator vit = std::find(mGrpPendingSign.begin(),
mGrpPendingSign.end(), token);
if(vit == mGrpPendingSign.end())
{
GxsPendingSignItem<RsGxsGrpItem*, uint32_t> gpsi(grpItem, token);
mGrpPendingSign.push_back(gpsi);
}else
{
if(vit->mAttempts == SIGN_MAX_ATTEMPTS)
{
delete vit->mItem;
}
}
}
else if(create == CREATE_SUCCESS)
{
delete grpItem;
}
if((create == CREATE_SUCCESS) || (create == CREATE_FAIL))
{
NxsGrpSignPendVect::iterator vit = std::find(mGrpPendingSign.begin(),
mGrpPendingSign.end(), token);
// set to max attempts so entry removed in next publish pass
if(vit != mGrpPendingSign.end())
{
vit->mAttempts = SIGN_MAX_ATTEMPTS;
}
}
}
// clear grp list as we're done publishing them and entries
// are invalid
for(int i = 0; i < toRemove.size(); i++)
for(std::vector<uint32_t>::size_type i = 0; i < toRemove.size(); i++)
mGrpsToPublish.erase(toRemove[i]);
}

View File

@ -94,7 +94,7 @@ class RsGenExchange : public RsNxsObserver, public RsThread, public RsGxsIface
public:
/// used by class derived for RsGenExchange to indicate if service create passed or not
enum { SERVICE_CREATE_SUCCESS, SERVICE_CREATE_FAIL, SERVICE_FAIL_TRY_LATER } ServiceCreate_Returns;
enum ServiceCreate_Return { SERVICE_CREATE_SUCCESS, SERVICE_CREATE_FAIL, SERVICE_FAIL_TRY_LATER } ;
/*!
* Constructs a RsGenExchange object, the owner ship of gds, ns, and serviceserialiser passes \n
@ -441,6 +441,7 @@ protected:
* This represents the group before its signature is calculated
* Reimplement this function if you need to access keys to further extend
* security of your group items using keyset properties
* Derived service should return one of three ServiceCreate_Return enum values below
* @warning do not modify keySet!
* @param grp The group which is stored by GXS prior
* service can make specific modifications need
@ -448,8 +449,9 @@ protected:
* @param keySet this is the key set used to define the group
* contains private and public admin and publish keys
* (use key flags to distinguish)
* @return SERVICE_CREATE_SUCCESS, SERVICE_CREATE_FAIL, SERVICE_FAIL_TRY_LATER
*/
virtual void service_CreateGroup(RsGxsGrpItem* grpItem, RsTlvSecurityKeySet& keySet);
virtual ServiceCreate_Return service_CreateGroup(RsGxsGrpItem* grpItem, RsTlvSecurityKeySet& keySet);
public:
@ -550,8 +552,10 @@ private:
* by assigning it a groupId and signature via SHA1 and EVP_sign respectively \n
* Meta is serialised and stored in group at this point also
* @param grp Nxs group to create
* @return CREATE_SUCCESS for success, CREATE_FAIL for fail,
* CREATE_FAIL_TRY_LATER for Id sign key not avail (but requested)
*/
bool createGroup(RsNxsGrp* grp, RsTlvSecurityKeySet& privateKeySet, RsTlvSecurityKeySet& publicKeySet);
uint8_t createGroup(RsNxsGrp* grp, RsTlvSecurityKeySet& privateKeySet, RsTlvSecurityKeySet& publicKeySet);
/*!
* This completes the creation of an instance on RsNxsMsg
@ -561,7 +565,7 @@ private:
* @param msg the Nxs message to create
* CREATE_FAIL, CREATE_SUCCESS, CREATE_ID_SIGN_NOT_AVAIL
* @return CREATE_SUCCESS for success, CREATE_FAIL for fail,
* CREATE_ID_SIGN_NOT_AVAIL for Id sign key not avail (but requested)
* CREATE_FAIL_TRY_LATER for Id sign key not avail (but requested)
*/
int createMessage(RsNxsMsg* msg);
@ -571,11 +575,22 @@ private:
* @param msgData message data to be signed
* @param grpMeta the meta data for group the message belongs to
* @return SIGN_SUCCESS for success, SIGN_FAIL for fail,
* ID_NOT_AVAIL for Id sign key not avail (but requested), try later
* SIGN_FAIL_TRY_LATER for Id sign key not avail (but requested), try later
*/
int createMsgSignatures(RsTlvKeySignatureSet& signSet, RsTlvBinaryData& msgData,
const RsGxsMsgMetaData& msgMeta, RsGxsGrpMetaData& grpMeta);
/*!
* convenience function to create sign for groups
* @param signSet signatures are stored here
* @param grpData group data to be signed
* @param grpMeta the meta data for group to be signed
* @return SIGN_SUCCESS for success, SIGN_FAIL for fail,
* SIGN_FAIL_TRY_LATER for Id sign key not avail (but requested), try later
*/
int createGroupSignatures(RsTlvKeySignatureSet& signSet, RsTlvBinaryData& grpData,
RsGxsGrpMetaData& grpMeta);
/*!
* check meta change is legal
* @return false if meta change is not legal
@ -606,7 +621,7 @@ private:
* @param flag the flag to and(&) against
* @param the result of the (bit-block & flag)
*/
bool checkMsgAuthenFlag(const PrivacyBitPos& pos, const uint8_t& flag) const;
bool checkAuthenFlag(const PrivacyBitPos& pos, const uint8_t& flag) const;
void groupShareKeys(std::list<std::string> peers);
@ -617,6 +632,8 @@ private:
RsGeneralDataService* mDataStore;
RsNetworkExchangeService *mNetService;
RsSerialType *mSerialiser;
/// service type
uint16_t mServType;
RsGixs* mGixs;
std::vector<RsNxsMsg*> mReceivedMsgs;
@ -634,8 +651,7 @@ private:
std::vector<RsGxsNotify*> mNotifications;
/// service type
uint16_t mServType;
/// authentication policy
uint32_t mAuthenPolicy;
@ -646,8 +662,12 @@ private:
std::vector<GxsPendingSignItem<RsNxsMsg*, RsGxsGrpMsgIdPair> > mMsgPendingValidate;
typedef std::vector<GxsPendingSignItem<RsNxsMsg*, RsGxsGrpMsgIdPair> > NxsMsgPendingVect;
std::map<RsGxsGroupId, GxsPendingSignItem<RsGxsGrpItem*> >
mGrpPendingSign, mGrpPendingValidation;
std::vector<GxsPendingSignItem<RsGxsGrpItem*, RsGxsGroupId> >
mGrpPendingValidation;
std::vector<GxsPendingSignItem<RsGxsGrpItem*, uint32_t> > mGrpPendingSign;
typedef std::vector<GxsPendingSignItem<RsGxsGrpItem*, uint32_t> > NxsGrpSignPendVect;
private:

View File

@ -355,7 +355,7 @@ bool p3GxsCircles::createGroup(uint32_t& token, RsGxsCircleGroup &group)
return true;
}
void p3GxsCircles::service_CreateGroup(RsGxsGrpItem* grpItem, RsTlvSecurityKeySet& /*keySet*/)
RsGenExchange::ServiceCreate_Return p3GxsCircles::service_CreateGroup(RsGxsGrpItem* grpItem, RsTlvSecurityKeySet& /*keySet*/)
{
#ifdef DEBUG_CIRCLES
std::cerr << "p3GxsCircles::service_CreateGroup()";
@ -367,7 +367,7 @@ void p3GxsCircles::service_CreateGroup(RsGxsGrpItem* grpItem, RsTlvSecurityKeySe
{
std::cerr << "p3GxsCircles::service_CreateGroup() ERROR invalid cast";
std::cerr << std::endl;
return;
return SERVICE_CREATE_FAIL;
}
// Now copy the GroupId into the mCircleId, and set the mode.
@ -384,6 +384,8 @@ void p3GxsCircles::service_CreateGroup(RsGxsGrpItem* grpItem, RsTlvSecurityKeySe
RsStackMutex stack(mCircleMtx); /********** STACK LOCKED MTX ******/
mCircleIdList.push_back(grpItem->meta.mGroupId);
}
return SERVICE_CREATE_SUCCESS;
}

View File

@ -182,7 +182,7 @@ class p3GxsCircles: public RsGxsCircleExchange, public RsGxsCircles,
virtual void notifyChanges(std::vector<RsGxsNotify*>& changes);
/** Overloaded to add PgpIdHash to Group Definition **/
virtual void service_CreateGroup(RsGxsGrpItem* grpItem, RsTlvSecurityKeySet& keySet);
virtual ServiceCreate_Return service_CreateGroup(RsGxsGrpItem* grpItem, RsTlvSecurityKeySet& keySet);
// Overloaded from GxsTokenQueue for Request callbacks.
virtual void handleResponse(uint32_t token, uint32_t req_type);

View File

@ -73,6 +73,11 @@ uint32_t p3GxsForums::forumsAuthenPolicy()
RsGenExchange::setAuthenPolicyFlag(flag, policy, RsGenExchange::RESTRICTED_GRP_BITS);
RsGenExchange::setAuthenPolicyFlag(flag, policy, RsGenExchange::PUBLIC_GRP_BITS);
RsGenExchange::setAuthenPolicyFlag(flag, policy, RsGenExchange::PRIVATE_GRP_BITS);
flag = GXS_SERV::GRP_OPTION_AUTHEN_AUTHOR_SIGN;
RsGenExchange::setAuthenPolicyFlag(flag, policy, RsGenExchange::GRP_OPTION_BITS);
return policy;
}

View File

@ -1229,7 +1229,7 @@ static void calcPGPHash(const RsGxsId &id, const PGPFingerprintType &pgp, GxsIdP
// Must Use meta.
void p3IdService::service_CreateGroup(RsGxsGrpItem* grpItem, RsTlvSecurityKeySet& keySet)
RsGenExchange::ServiceCreate_Return p3IdService::service_CreateGroup(RsGxsGrpItem* grpItem, RsTlvSecurityKeySet& keySet)
{
#ifdef DEBUG_IDS
std::cerr << "p3IdService::service_CreateGroup()";
@ -1241,7 +1241,7 @@ void p3IdService::service_CreateGroup(RsGxsGrpItem* grpItem, RsTlvSecurityKeySet
{
std::cerr << "p3IdService::service_CreateGroup() ERROR invalid cast";
std::cerr << std::endl;
return;
return SERVICE_CREATE_FAIL;
}
/********************* TEMP HACK UNTIL GXS FILLS IN GROUP_ID *****************/
@ -1262,7 +1262,7 @@ void p3IdService::service_CreateGroup(RsGxsGrpItem* grpItem, RsTlvSecurityKeySet
{
std::cerr << "p3IdService::service_CreateGroup() ERROR no admin key";
std::cerr << std::endl;
return;
return SERVICE_CREATE_FAIL;
}
@ -1297,8 +1297,6 @@ void p3IdService::service_CreateGroup(RsGxsGrpItem* grpItem, RsTlvSecurityKeySet
std::cerr << std::endl;
}
#ifdef DEBUG_IDS
std::cerr << "p3IdService::service_CreateGroup() for : " << item->group.mMeta.mGroupId;
std::cerr << std::endl;
@ -1326,7 +1324,7 @@ void p3IdService::service_CreateGroup(RsGxsGrpItem* grpItem, RsTlvSecurityKeySet
{
std::cerr << "p3IdService::service_CreateGroup() ERROR Own Finger is stuck";
std::cerr << std::endl;
return; // abandon attempt!
return SERVICE_CREATE_FAIL; // abandon attempt!
}
calcPGPHash(item->group.mMeta.mGroupId, ownFinger, hash);
@ -1376,6 +1374,7 @@ void p3IdService::service_CreateGroup(RsGxsGrpItem* grpItem, RsTlvSecurityKeySet
// Reload in a little bit.
// HACK to get it to work.
RsTickEvent::schedule_in(GXSID_EVENT_CACHEOWNIDS, OWNID_RELOAD_DELAY);
return SERVICE_CREATE_SUCCESS;
}

View File

@ -227,7 +227,7 @@ virtual bool getReputation(const RsGxsId &id, const GixsReputation &rep);
virtual void notifyChanges(std::vector<RsGxsNotify*>& changes);
/** Overloaded to add PgpIdHash to Group Definition **/
virtual void service_CreateGroup(RsGxsGrpItem* grpItem, RsTlvSecurityKeySet& keySet);
virtual ServiceCreate_Return service_CreateGroup(RsGxsGrpItem* grpItem, RsTlvSecurityKeySet& keySet);
// Overloaded from GxsTokenQueue for Request callbacks.
virtual void handleResponse(uint32_t token, uint32_t req_type);

View File

@ -350,6 +350,7 @@ void GxsGroupDialog::createGroup()
meta.mSignFlags = getGroupSignFlags();
setCircleParameters(meta);
ui.idChooser->getChosenId(meta.mAuthorId);
if (service_CreateGroup(token, meta))
{
@ -357,6 +358,7 @@ void GxsGroupDialog::createGroup()
if(mTokenQueue != NULL)
mTokenQueue->queueRequest(token, TOKENREQ_GROUPINFO, RS_TOKREQ_ANSTYPE_ACK, GXSGROUP_NEWGROUPID);
}
close();
}