|
Mixe for Privacy and Anonymity in the Internet
|
00001 /* 00002 Copyright (c) 2000, The JAP-Team 00003 All rights reserved. 00004 Redistribution and use in source and binary forms, with or without modification, 00005 are permitted provided that the following conditions are met: 00006 00007 - Redistributions of source code must retain the above copyright notice, 00008 this list of conditions and the following disclaimer. 00009 00010 - Redistributions in binary form must reproduce the above copyright notice, 00011 this list of conditions and the following disclaimer in the documentation and/or 00012 other materials provided with the distribution. 00013 00014 - Neither the name of the University of Technology Dresden, Germany nor the names of its contributors 00015 may be used to endorse or promote products derived from this software without specific 00016 prior written permission. 00017 00018 00019 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS 00020 OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 00021 AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS 00022 BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 00023 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 00024 OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 00025 IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 00026 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE 00027 */ 00028 #include "StdAfx.h" 00029 00030 #ifdef DYNAMIC_MIX 00031 #include "CADynamicCascadeConfigurator.hpp" 00032 #include "CACmdLnOptions.hpp" 00033 #include "CAListenerInterface.hpp" 00034 #include "CASocketAddrINet.hpp" 00035 #include "CASocket.hpp" 00036 #include "CAHttpClient.hpp" 00037 #include "CACertificate.hpp" 00038 #include "CAMsg.hpp" 00039 00046 CADynamicCascadeConfigurator::CADynamicCascadeConfigurator(CASignature *a_pSignature, CAMix *a_pMix) 00047 { 00048 this->m_pSignature = a_pSignature; 00049 this->m_pMix = a_pMix; 00050 m_proposals = NULL; 00051 } 00052 00058 CADynamicCascadeConfigurator::~CADynamicCascadeConfigurator() 00059 { 00060 if(m_proposals != NULL) 00061 { 00062 PROPOSALENTRY *tmpProposal = NULL; 00063 PROPOSERENTRY *tmpProposer = NULL; 00064 while( (tmpProposal = m_proposals) != NULL ) 00065 { 00066 while( (tmpProposer = tmpProposal->proposers) != NULL) 00067 { 00068 tmpProposal->proposers = tmpProposer->next; 00069 delete tmpProposer->ski; 00070 tmpProposer->ski = NULL; 00071 delete tmpProposer; 00072 tmpProposer = NULL; 00073 } 00074 delete tmpProposal->proposal; 00075 tmpProposal->proposal = NULL; 00076 // delete tmpProposal->elem; 00077 m_proposals = tmpProposal->next; 00078 delete tmpProposal; 00079 tmpProposal = NULL; 00080 } 00081 } 00082 00083 } 00084 00100 SINT32 CADynamicCascadeConfigurator::configure() 00101 { 00102 UINT32 nrAddresses; 00103 CAListenerInterface** ppSocketAddresses = pglobalOptions->getInfoServices(nrAddresses); 00104 00105 #ifdef DEBUG 00106 CAMsg::printMsg( LOG_DEBUG, "CADynamicCascadeConfigurator::configure - Querying %i infoservices...\n", nrAddresses); 00107 #endif 00108 UINT8 bufMixId[255]; 00109 UINT32 mixIdLen = 255; 00110 UINT8 request[255]; 00111 pglobalOptions->getMixId( bufMixId, mixIdLen ); 00112 sprintf((char*)request, "/reconfigure/%s",bufMixId ); 00113 00114 for (UINT32 i = 0; i < nrAddresses; i++) 00115 { 00116 CASocketAddrINet* pAddr=(CASocketAddrINet*)ppSocketAddresses[i]->getAddr(); 00117 DOM_Element elem; 00118 if( sendInfoserviceGetRequest(pAddr, request, &elem) != E_SUCCESS) 00119 { 00120 #ifdef DEBUG 00121 CAMsg::printMsg( LOG_DEBUG, "CADynamicCascadeConfigurator::configure - Query %i WAS NOT SUCCESSFULL!\n", i); 00122 #endif 00123 delete pAddr; 00124 pAddr = NULL; 00125 continue; 00126 } 00127 #ifdef DEBUG 00128 CAMsg::printMsg( LOG_DEBUG, "CADynamicCascadeConfigurator::configure - Query %i successful, adding proposal now...\n", i); 00129 #endif 00130 delete pAddr; 00131 pAddr = NULL; 00132 /* UINT8* sendBuff=NULL; 00133 UINT32 sendBuffLen = 0; 00134 sendBuff=DOM_Output::dumpToMem(elem,&sendBuffLen); 00135 if(sendBuff!=NULL) 00136 CAMsg::printMsg( LOG_DEBUG, "CADynamicCascadeConfigurator::configure - Proposal %s\n", sendBuff);*/ 00137 addProposal( elem ); 00138 } 00139 00140 #ifdef DEBUG 00141 CAMsg::printMsg( LOG_DEBUG, "CADynamicCascadeConfigurator::configure - Queried all infoservices, will now vote...\n"); 00142 #endif 00143 00144 DOM_Node *newCascade = NULL; 00145 UINT8 proposal[1024]; 00146 if( getMajorityVote( nrAddresses, newCascade, proposal ) == E_SUCCESS ) 00147 { 00149 UINT8 buff[1024]; 00150 UINT32 len = 1024; 00151 if(pglobalOptions->getLastCascadeProposal(buff, len) == E_SUCCESS) 00152 { 00153 if(strcmp((char*)proposal, (char*)buff) == 0) 00154 { 00155 CAMsg::printMsg(LOG_DEBUG, "New proposal == old proposal: SKIPPING\n"); 00156 return E_SUCCESS; 00157 } 00158 } 00159 CAMsg::printMsg( LOG_DEBUG, "CADynamicCascadeConfigurator::configure - Vote successful!\n"); 00160 if(newCascade != NULL) 00161 { 00162 return reconfigureMix(*newCascade, proposal); 00163 } 00164 } 00165 else 00166 { 00167 CAMsg::printMsg(LOG_DEBUG, "CADynamicCascadeConfigurator::configure - Vote not successful, no majority found, remaining as I am\n"); 00168 } 00169 return E_SUCCESS; 00170 } 00171 00180 SINT32 CADynamicCascadeConfigurator::getMajorityVote(UINT32 a_nrInfoServices, DOM_Node *&r_elemMajority, UINT8* r_strProposal) 00181 { 00182 SINT32 ret = E_UNKNOWN; 00183 r_elemMajority = NULL; 00184 PROPOSALENTRY *tmp = m_proposals; 00185 while( tmp != NULL ) 00186 { 00187 if(tmp->count >= MIN_MAJORITY_QUOTE(a_nrInfoServices)) 00188 { 00189 #ifdef DEBUG 00190 CAMsg::printMsg( LOG_DEBUG, "CADynamicCascadeConfigurator::getMajorityVote - Proposal (%s) has %i votes, thats the majority (%i were needed)!\n", tmp->proposal, tmp->count, 00191 MIN_MAJORITY_QUOTE(a_nrInfoServices)); 00192 #endif 00193 r_elemMajority = &tmp->elem; 00194 if( r_elemMajority != NULL) 00195 { 00196 strcpy((char*)r_strProposal, (char*)tmp->proposal); 00197 ret = E_SUCCESS; 00198 } 00199 } 00200 #ifdef DEBUG 00201 else 00202 { 00203 CAMsg::printMsg( LOG_DEBUG, "CADynamicCascadeConfigurator::getMajorityVote - Proposal (%s) has %i votes, discarting, majority would be (%i)\n", tmp->proposal, tmp->count, 00204 MIN_MAJORITY_QUOTE(a_nrInfoServices)); 00205 } 00206 #endif 00207 tmp = tmp->next; 00208 } 00209 return ret; 00210 } 00211 00219 SINT32 CADynamicCascadeConfigurator::reconfigureMix(DOM_Node a_elemNewCascade, UINT8* a_strProposal) 00220 { 00221 DOM_Element mixesElement; 00222 getDOMChildByName(a_elemNewCascade,(UINT8*)"Mixes", mixesElement, false); 00223 DOM_Node child = mixesElement.getFirstChild(); 00224 char* mixId; 00225 UINT8 myMixId[255]; 00226 UINT32 len=255; 00227 pglobalOptions->getMixId(myMixId, len); 00228 char* prevMixId = NULL; 00229 char* myNextMixId = NULL; 00230 char* myPrevMixId = NULL; 00231 bool bFoundMix = false; 00232 while(child!=NULL) 00233 { 00234 if(child.getNodeName().equals("Mix") && child.getNodeType() == DOM_Node::ELEMENT_NODE) 00235 { 00236 mixId = static_cast<const DOM_Element&>(child).getAttribute("id").transcode(); 00237 if(strcmp(mixId,(char*)myMixId) == 0) 00238 { 00239 bFoundMix = true; 00240 myPrevMixId = prevMixId; 00241 } 00242 else if(bFoundMix == true) 00243 { 00244 myNextMixId = mixId; 00245 break; 00246 } 00247 prevMixId = mixId; 00248 } 00249 child = child.getNextSibling(); 00250 } 00251 00252 if(!bFoundMix) 00253 { 00254 CAMsg::printMsg(LOG_ERR, "CADynamicCascadeConfigurator::reconfigureMix - Unable to find my mix ID in the majority cascade info\n"); 00255 return E_UNKNOWN; 00256 } 00257 00258 // Empty cascade info -> I wasn't assigned a new cascade, stop the old one 00260 if(myPrevMixId == NULL && myNextMixId == NULL) 00261 { 00262 // Only stops the cascade, now reconfiguration is done yet 00263 pglobalOptions->resetPrevMix(); 00264 pglobalOptions->resetNextMix(); 00265 pglobalOptions->setCascadeProposal(a_strProposal, strlen((char*)a_strProposal)); 00266 m_pMix->dynaReconfigure( false ); 00267 return E_SUCCESS; 00268 } 00269 m_pMix->setReconfiguring(true); 00270 SINT32 ret = 0; 00271 00272 bool typeChanged = false; 00273 00275 if(myPrevMixId == NULL) 00276 { 00277 00278 if(pglobalOptions->isLastMix()) 00279 { 00280 CAMsg::printMsg( LOG_ERR, "CADynamicCascadeConfigurator::reconfigureMix - I am a LastMix and should be reconfigured as a FirstMix! Won't do that!!\n"); 00281 return E_UNKNOWN; 00282 } 00283 else if(pglobalOptions->isMiddleMix()) 00284 { 00285 #ifdef DEBUG 00286 CAMsg::printMsg( LOG_DEBUG, "CADynamicCascadeConfigurator::reconfigureMix - I am a MiddleMix and should be reconfigured as a FirstMix!\n"); 00287 #endif 00288 pglobalOptions->changeMixType(CAMix::FIRST_MIX); 00289 typeChanged = true; 00290 } 00291 else if(pglobalOptions->isFirstMix()) 00292 { 00293 #ifdef DEBUG 00294 CAMsg::printMsg( LOG_DEBUG, "CADynamicCascadeConfigurator::reconfigureMix - CADynamicCascadeConfigurator::reconfigureMix - I am (and will remain) a first mix!\n"); 00295 #endif 00296 } 00297 else 00298 { 00299 #ifdef DEBUG 00300 CAMsg::printMsg( LOG_DEBUG, "CADynamicCascadeConfigurator::reconfigureMix - Ugh! I do not have a current mix type! Trying to become a FirstMix nevertheless, but that might fail\n"); 00301 #endif 00302 pglobalOptions->changeMixType(CAMix::FIRST_MIX); 00303 typeChanged = true; 00304 } 00305 } 00306 00308 if( myNextMixId == NULL ) 00309 { 00310 if(!pglobalOptions->isLastMix()) 00311 { 00312 CAMsg::printMsg( LOG_ERR, "CADynamicCascadeConfigurator::reconfigureMix - I am NOT a LastMix and should be reconfigured as a LastMix! Won't do that!!\n"); 00313 return E_UNKNOWN; 00314 } 00315 #ifdef DEBUG 00316 else 00317 { 00318 CAMsg::printMsg( LOG_DEBUG, "CADynamicCascadeConfigurator::reconfigureMix - I am (and will remain) a last mix!\n"); 00319 } 00320 #endif 00321 } 00322 00324 if(myPrevMixId != NULL && myNextMixId != NULL) 00325 { 00326 if(pglobalOptions->isLastMix()) 00327 { 00328 CAMsg::printMsg( LOG_ERR, "CADynamicCascadeConfigurator::reconfigureMix - I am a LastMix and should be reconfigured as a MiddleMix! Won't do that!!\n"); 00329 return E_UNKNOWN; 00330 } 00331 else if(pglobalOptions->isFirstMix()) 00332 { 00333 #ifdef DEBUG 00334 CAMsg::printMsg( LOG_DEBUG, "CADynamicCascadeConfigurator::reconfigureMix - I am a FirstMix and should be reconfigured as a MiddleMix!\n"); 00335 #endif 00336 pglobalOptions->changeMixType(CAMix::MIDDLE_MIX); 00337 typeChanged = true; 00338 } 00339 else if(pglobalOptions->isMiddleMix()) 00340 { 00341 CAMsg::printMsg( LOG_DEBUG, "CADynamicCascadeConfigurator::reconfigureMix - I am (and will remain) a middle mix!\n"); 00342 } 00343 else 00344 { 00345 #ifdef DEBUG 00346 CAMsg::printMsg( LOG_DEBUG, "CADynamicCascadeConfigurator::reconfigureMix - Ugh! I do not have a current mix type! Trying to become a MiddleMix nevertheless, but that might fail\n"); 00347 #endif 00348 pglobalOptions->changeMixType(CAMix::MIDDLE_MIX); 00349 typeChanged = true; 00350 } 00351 } 00352 00353 // MiddleMix or LastMox 00354 if(myPrevMixId != NULL) 00355 { 00356 CAMsg::printMsg(LOG_INFO,"CADynamicCascadeConfigurator::reconfigureMix - Asking InfoService about previous mix ...\n"); 00357 char buf[255]; 00358 sprintf(buf, "/mixinfo/%s", (char*)myPrevMixId); 00359 DOM_Element result; 00361 ret = sendRandomInfoserviceGetRequest( (UINT8*)buf, &result); 00362 if(ret != E_SUCCESS) 00363 { 00364 CAMsg::printMsg(LOG_ERR,"CADynamicCascadeConfigurator::reconfigureMix - Error retrieving mix info from InfoService!\n"); 00365 return ret; 00366 } 00367 DOM_Document doc = result.getOwnerDocument(); 00368 ret = pglobalOptions->setPrevMix( doc ); 00369 if(ret != E_SUCCESS) 00370 { 00371 CAMsg::printMsg(LOG_ERR,"CADynamicCascadeConfigurator::reconfigureMix - Error setting next mix info!\n"); 00372 pglobalOptions->resetPrevMix(); 00373 return E_UNKNOWN; 00374 } 00375 } 00376 else 00377 { 00378 if(pglobalOptions->resetPrevMix() != E_SUCCESS) 00379 { 00380 CAMsg::printMsg( LOG_ERR, "CADynamicCascadeConfigurator::reconfigureMix - Unable to reset prev mix information\n"); 00381 return E_UNKNOWN; 00382 } 00383 } 00384 00385 // MiddleMix or FirstMix 00386 if(myNextMixId != NULL) 00387 { 00388 CAMsg::printMsg(LOG_INFO,"CADynamicCascadeConfigurator::reconfigureMix - Asking InfoService about next mix ...\n"); 00389 char buf[255]; 00390 sprintf(buf, "/mixinfo/%s", (char*)myNextMixId); 00391 DOM_Element result; 00392 if( sendRandomInfoserviceGetRequest( (UINT8*)buf, &result) != E_SUCCESS ) 00393 { 00394 CAMsg::printMsg(LOG_ERR,"CADynamicCascadeConfigurator::reconfigureMix - Error retrieving mix info from InfoService!\n"); 00395 return E_UNKNOWN; 00396 } 00397 DOM_Document doc = result.getOwnerDocument(); 00398 if(pglobalOptions->setNextMix( doc ) != E_SUCCESS) 00399 { 00400 CAMsg::printMsg(LOG_ERR,"CADynamicCascadeConfigurator::reconfigureMix - Error setting next mix info!\n"); 00401 return E_UNKNOWN; 00402 } 00403 } 00404 else 00405 { 00406 if(pglobalOptions->resetNextMix() != E_SUCCESS) 00407 { 00408 CAMsg::printMsg( LOG_ERR, "CADynamicCascadeConfigurator::reconfigureMix - Unable to reset next mix information\n"); 00409 return E_UNKNOWN; 00410 } 00411 } 00412 00413 pglobalOptions->setCascadeProposal(a_strProposal, strlen((char*)a_strProposal)); 00414 /* if(pglobalOptions->isFirstMix()) 00415 { 00416 pglobalOptions->setCascadeXML((DOM_Element&)a_elemNewCascade); 00417 }*/ 00418 #ifdef DEBUG 00419 CAMsg::printMsg( LOG_DEBUG, "CADynamicCascadeConfigurator::reconfigureMix - Calling dynaReconfigure on the mix, grab a hold of something!\n"); 00420 #endif 00421 m_pMix->dynaReconfigure( typeChanged ); 00422 return E_SUCCESS; 00423 } 00424 00436 SINT32 CADynamicCascadeConfigurator::addProposal(DOM_Element a_elem) 00437 { 00439 // FIXME Signature cannot be verified. Why is that? 00440 /* if( m_pSignature->verifyXML( a_elem, NULL ) != E_SUCCESS) 00441 { 00442 CAMsg::printMsg( LOG_DEBUG, "Signature was not ok, throwing it away...\n"); 00443 return E_UNKNOWN; 00444 }*/ 00446 DOM_Element mixesElement; 00447 getDOMChildByName(a_elem,(UINT8*)"Mixes", mixesElement, false); 00448 DOM_Node child = mixesElement.getFirstChild(); 00449 char* mixId; 00450 char* tmpProposal = NULL; 00451 while(child!=NULL) 00452 { 00453 if(child.getNodeName().equals("Mix") && child.getNodeType() == DOM_Node::ELEMENT_NODE) 00454 { 00455 mixId = static_cast<const DOM_Element&>(child).getAttribute("id").transcode(); 00456 if(tmpProposal == NULL) 00457 { 00458 tmpProposal = new char[strlen(mixId)+1]; 00459 strncpy(tmpProposal, mixId, strlen(mixId)+1); 00460 } 00461 else 00462 { 00463 char *tmp = new char[strlen(tmpProposal)+1]; 00464 strncpy(tmp, tmpProposal, strlen(tmpProposal)+1); 00465 delete tmpProposal; 00466 tmpProposal = new char[ strlen(mixId) + strlen(tmp) + 1]; 00467 strncpy(tmpProposal, tmp, strlen(tmp) + 1); 00468 delete tmp; 00469 tmp = NULL; 00470 strcat(tmpProposal, mixId); 00471 } 00472 } 00473 child = child.getNextSibling(); 00474 } 00475 UINT8* proposal = NULL; 00476 UINT32 lenProposal = 0; 00477 proposal = new UINT8[strlen(tmpProposal) + 1]; 00478 memcpy(proposal, tmpProposal, strlen(tmpProposal) + 1); 00479 lenProposal = strlen(tmpProposal); 00480 delete tmpProposal; 00481 tmpProposal = NULL; 00482 00483 #ifdef DEBUG 00484 // CAMsg::printMsg(LOG_DEBUG, "CADynamicCascadeConfigurator::addProposal - next proposal is %s\n", proposal); 00485 #endif 00486 00488 DOM_Element elemSig, elemCert; 00489 getDOMChildByName(a_elem,(UINT8*)"Signature",elemSig,false); 00490 getDOMChildByName(elemSig,(UINT8*)"X509Data",elemCert,true); 00491 CACertificate *cert = NULL; 00492 if(elemSig!=NULL) 00493 cert = CACertificate::decode(elemCert.getFirstChild(),CERT_X509CERTIFICATE); 00494 00495 UINT8 proposerSki[60]; 00496 UINT32 lenProposerSki = 60; 00497 if(cert != NULL) 00498 cert->getSubjectKeyIdentifier( proposerSki, &lenProposerSki ); 00499 00500 #ifdef DEBUG 00501 // CAMsg::printMsg(LOG_DEBUG, "CADynamicCascadeConfigurator::addProposal - the proposer is %s\n", proposerSki); 00502 #endif 00503 00504 bool added = false; 00505 00507 PROPOSALENTRY *tmpEntry; 00508 if( m_proposals == NULL ) 00509 { 00510 m_proposals = createProposal( proposal, lenProposal, proposerSki, lenProposerSki, &a_elem ); 00511 #ifdef DEBUG 00512 /* CAMsg::printMsg(LOG_DEBUG, "CADynamicCascadeConfigurator::addProposal - Adding proposal %s from InfoService %s. Got %i proposing IS for this value\n", m_proposals->proposal, 00513 m_proposals->proposers->ski, m_proposals->count );*/ 00514 #endif 00515 } 00516 else 00517 { 00518 tmpEntry=m_proposals; 00519 while(true) 00520 { 00521 if(memcmp(tmpEntry->proposal, proposal, lenProposal) == 0) 00522 { 00523 PROPOSERENTRY *proposer = tmpEntry->proposers; 00524 bool ok = true; 00525 while(true) 00526 { 00527 if(memcmp(proposer->ski, proposerSki, lenProposerSki) == 0) 00528 { 00529 // Duplicate! 00530 ok = false; 00531 added = true; 00532 break; 00533 } 00534 if(proposer->next == NULL) 00535 break; 00536 proposer = proposer->next; 00537 } 00538 if(ok) 00539 { 00540 PROPOSERENTRY *tmpProposer = new PROPOSERENTRY; 00541 tmpProposer->next = NULL; 00542 tmpProposer->ski = new UINT8[lenProposerSki+1]; 00543 memcpy(tmpProposer->ski, proposerSki, lenProposerSki+1); 00544 proposer->next = tmpProposer; 00545 tmpEntry->count++; 00546 #ifdef DEBUG 00547 /* CAMsg::printMsg(LOG_DEBUG, "CADynamicCascadeConfigurator::addProposal - Adding proposal %s from InfoService %s. Got %i proposing IS for this value\n", tmpEntry->proposal,tmpProposer->ski, tmpEntry->count );*/ 00548 #endif 00549 added = true; 00550 break; 00551 } 00552 } 00553 if(tmpEntry->next == NULL) 00554 break; 00555 tmpEntry = tmpEntry->next; 00556 } 00557 if(!added) 00558 { 00559 tmpEntry->next = createProposal( proposal, lenProposal, proposerSki, lenProposerSki, &a_elem ); 00560 #ifdef DEBUG 00561 /* CAMsg::printMsg(LOG_DEBUG, "CADynamicCascadeConfigurator::addProposal - Adding proposal %s from InfoService %s. Got %i proposing IS for this value\n", tmpEntry->next->proposal,tmpEntry->next->proposers->ski, tmpEntry->next->count );*/ 00562 #endif 00563 } 00564 } 00565 return E_SUCCESS; 00566 } 00567 00578 PROPOSALENTRY *CADynamicCascadeConfigurator::createProposal(UINT8* a_strProposal, UINT32 a_lenProposal, UINT8 *a_strProposer, UINT32 a_lenProposer, DOM_Element *a_elem) 00579 { 00580 PROPOSALENTRY *entry = new PROPOSALENTRY; 00581 entry->proposal = new UINT8[a_lenProposal+1]; 00582 memcpy(entry->proposal, a_strProposal, a_lenProposal+1); 00583 entry->count = 1; 00584 entry->next = NULL; 00585 PROPOSERENTRY *proposer = new PROPOSERENTRY; 00586 proposer->next = NULL; 00587 proposer->ski = new UINT8[a_lenProposer+1]; 00588 memcpy(proposer->ski, a_strProposer, a_lenProposer+1); 00589 entry->proposers = proposer; 00590 entry->elem = a_elem->cloneNode( true ); 00591 return entry; 00592 } 00593 #endif // DYNAMIC_MIX
1.7.6.1