Mixe for Privacy and Anonymity in the Internet
CADynamicCascadeConfigurator.cpp
Go to the documentation of this file.
1 /*
2 Copyright (c) 2000, The JAP-Team
3 All rights reserved.
4 Redistribution and use in source and binary forms, with or without modification,
5 are permitted provided that the following conditions are met:
6 
7  - Redistributions of source code must retain the above copyright notice,
8  this list of conditions and the following disclaimer.
9 
10  - Redistributions in binary form must reproduce the above copyright notice,
11  this list of conditions and the following disclaimer in the documentation and/or
12  other materials provided with the distribution.
13 
14  - Neither the name of the University of Technology Dresden, Germany nor the names of its contributors
15  may be used to endorse or promote products derived from this software without specific
16  prior written permission.
17 
18 
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS
20 OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
21 AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS
22 BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
24 OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25 IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
27 */
28 #include "StdAfx.h"
29 
30 #ifdef DYNAMIC_MIX
32 #include "CACmdLnOptions.hpp"
33 #include "CAListenerInterface.hpp"
34 #include "CASocketAddrINet.hpp"
35 #include "CASocket.hpp"
36 #include "CAHttpClient.hpp"
37 #include "CACertificate.hpp"
38 #include "CAMsg.hpp"
39 
46 CADynamicCascadeConfigurator::CADynamicCascadeConfigurator(CASignature *a_pSignature, CAMix *a_pMix)
47 {
48  this->m_pSignature = a_pSignature;
49  this->m_pMix = a_pMix;
50  m_proposals = NULL;
51 }
52 
58 CADynamicCascadeConfigurator::~CADynamicCascadeConfigurator()
59 {
60  if(m_proposals != NULL)
61  {
62  PROPOSALENTRY *tmpProposal = NULL;
63  PROPOSERENTRY *tmpProposer = NULL;
64  while( (tmpProposal = m_proposals) != NULL )
65  {
66  while( (tmpProposer = tmpProposal->proposers) != NULL)
67  {
68  tmpProposal->proposers = tmpProposer->next;
69  delete tmpProposer->ski;
70  tmpProposer->ski = NULL;
71  delete tmpProposer;
72  tmpProposer = NULL;
73  }
74  delete tmpProposal->proposal;
75  tmpProposal->proposal = NULL;
76 // delete tmpProposal->elem;
77  m_proposals = tmpProposal->next;
78  delete tmpProposal;
79  tmpProposal = NULL;
80  }
81  }
82 
83 }
84 
100 SINT32 CADynamicCascadeConfigurator::configure()
101 {
102  UINT32 nrAddresses;
103  CAListenerInterface** ppSocketAddresses = pglobalOptions->getInfoServices(nrAddresses);
104 
105 #ifdef DEBUG
106  CAMsg::printMsg( LOG_DEBUG, "CADynamicCascadeConfigurator::configure - Querying %i infoservices...\n", nrAddresses);
107 #endif
108  UINT8 bufMixId[255];
109  UINT32 mixIdLen = 255;
110  UINT8 request[255];
111  pglobalOptions->getMixId( bufMixId, mixIdLen );
112  sprintf((char*)request, "/reconfigure/%s",bufMixId );
113 
114  for (UINT32 i = 0; i < nrAddresses; i++)
115  {
116  CASocketAddrINet* pAddr=(CASocketAddrINet*)ppSocketAddresses[i]->getAddr();
117  DOM_Element elem;
118  if( sendInfoserviceGetRequest(pAddr, request, &elem) != E_SUCCESS)
119  {
120 #ifdef DEBUG
121  CAMsg::printMsg( LOG_DEBUG, "CADynamicCascadeConfigurator::configure - Query %i WAS NOT SUCCESSFULL!\n", i);
122 #endif
123  delete pAddr;
124  pAddr = NULL;
125  continue;
126  }
127 #ifdef DEBUG
128  CAMsg::printMsg( LOG_DEBUG, "CADynamicCascadeConfigurator::configure - Query %i successful, adding proposal now...\n", i);
129 #endif
130  delete pAddr;
131  pAddr = NULL;
132 /* UINT8* sendBuff=NULL;
133  UINT32 sendBuffLen = 0;
134  sendBuff=DOM_Output::dumpToMem(elem,&sendBuffLen);
135  if(sendBuff!=NULL)
136  CAMsg::printMsg( LOG_DEBUG, "CADynamicCascadeConfigurator::configure - Proposal %s\n", sendBuff);*/
137  addProposal( elem );
138 }
139 
140 #ifdef DEBUG
141  CAMsg::printMsg( LOG_DEBUG, "CADynamicCascadeConfigurator::configure - Queried all infoservices, will now vote...\n");
142 #endif
143 
144  DOM_Node *newCascade = NULL;
145  UINT8 proposal[1024];
146  if( getMajorityVote( nrAddresses, newCascade, proposal ) == E_SUCCESS )
147  {
149  UINT8 buff[1024];
150  UINT32 len = 1024;
151  if(pglobalOptions->getLastCascadeProposal(buff, len) == E_SUCCESS)
152  {
153  if(strcmp((char*)proposal, (char*)buff) == 0)
154  {
155  CAMsg::printMsg(LOG_DEBUG, "New proposal == old proposal: SKIPPING\n");
156  return E_SUCCESS;
157  }
158  }
159  CAMsg::printMsg( LOG_DEBUG, "CADynamicCascadeConfigurator::configure - Vote successful!\n");
160  if(newCascade != NULL)
161  {
162  return reconfigureMix(*newCascade, proposal);
163  }
164  }
165  else
166  {
167  CAMsg::printMsg(LOG_DEBUG, "CADynamicCascadeConfigurator::configure - Vote not successful, no majority found, remaining as I am\n");
168  }
169  return E_SUCCESS;
170 }
171 
180 SINT32 CADynamicCascadeConfigurator::getMajorityVote(UINT32 a_nrInfoServices, DOM_Node *&r_elemMajority, UINT8* r_strProposal)
181 {
182  SINT32 ret = E_UNKNOWN;
183  r_elemMajority = NULL;
184  PROPOSALENTRY *tmp = m_proposals;
185  while( tmp != NULL )
186  {
187  if(tmp->count >= MIN_MAJORITY_QUOTE(a_nrInfoServices))
188  {
189 #ifdef DEBUG
190  CAMsg::printMsg( LOG_DEBUG, "CADynamicCascadeConfigurator::getMajorityVote - Proposal (%s) has %i votes, thats the majority (%i were needed)!\n", tmp->proposal, tmp->count,
191  MIN_MAJORITY_QUOTE(a_nrInfoServices));
192 #endif
193  r_elemMajority = &tmp->elem;
194  if( r_elemMajority != NULL)
195  {
196  strcpy((char*)r_strProposal, (char*)tmp->proposal);
197  ret = E_SUCCESS;
198  }
199  }
200 #ifdef DEBUG
201  else
202  {
203  CAMsg::printMsg( LOG_DEBUG, "CADynamicCascadeConfigurator::getMajorityVote - Proposal (%s) has %i votes, discarting, majority would be (%i)\n", tmp->proposal, tmp->count,
204  MIN_MAJORITY_QUOTE(a_nrInfoServices));
205  }
206 #endif
207  tmp = tmp->next;
208  }
209  return ret;
210 }
211 
219 SINT32 CADynamicCascadeConfigurator::reconfigureMix(DOM_Node a_elemNewCascade, UINT8* a_strProposal)
220 {
221  DOM_Element mixesElement;
222  getDOMChildByName(a_elemNewCascade,(UINT8*)"Mixes", mixesElement, false);
223  DOM_Node child = mixesElement.getFirstChild();
224  char* mixId;
225  UINT8 myMixId[255];
226  UINT32 len=255;
227  pglobalOptions->getMixId(myMixId, len);
228  char* prevMixId = NULL;
229  char* myNextMixId = NULL;
230  char* myPrevMixId = NULL;
231  bool bFoundMix = false;
232  while(child!=NULL)
233  {
234  if(child.getNodeName().equals("Mix") && child.getNodeType() == DOM_Node::ELEMENT_NODE)
235  {
236  mixId = static_cast<const DOM_Element&>(child).getAttribute("id").transcode();
237  if(strcmp(mixId,(char*)myMixId) == 0)
238  {
239  bFoundMix = true;
240  myPrevMixId = prevMixId;
241  }
242  else if(bFoundMix == true)
243  {
244  myNextMixId = mixId;
245  break;
246  }
247  prevMixId = mixId;
248  }
249  child = child.getNextSibling();
250  }
251 
252  if(!bFoundMix)
253  {
254  CAMsg::printMsg(LOG_ERR, "CADynamicCascadeConfigurator::reconfigureMix - Unable to find my mix ID in the majority cascade info\n");
255  return E_UNKNOWN;
256  }
257 
258  // Empty cascade info -> I wasn't assigned a new cascade, stop the old one
260  if(myPrevMixId == NULL && myNextMixId == NULL)
261  {
262  // Only stops the cascade, now reconfiguration is done yet
263  pglobalOptions->resetPrevMix();
264  pglobalOptions->resetNextMix();
265  pglobalOptions->setCascadeProposal(a_strProposal, strlen((char*)a_strProposal));
266  m_pMix->dynaReconfigure( false );
267  return E_SUCCESS;
268  }
269  m_pMix->setReconfiguring(true);
270  SINT32 ret = 0;
271 
272  bool typeChanged = false;
273 
275  if(myPrevMixId == NULL)
276  {
277 
278  if(pglobalOptions->isLastMix())
279  {
280  CAMsg::printMsg( LOG_ERR, "CADynamicCascadeConfigurator::reconfigureMix - I am a LastMix and should be reconfigured as a FirstMix! Won't do that!!\n");
281  return E_UNKNOWN;
282  }
283  else if(pglobalOptions->isMiddleMix())
284  {
285 #ifdef DEBUG
286  CAMsg::printMsg( LOG_DEBUG, "CADynamicCascadeConfigurator::reconfigureMix - I am a MiddleMix and should be reconfigured as a FirstMix!\n");
287 #endif
288  pglobalOptions->changeMixType(CAMix::FIRST_MIX);
289  typeChanged = true;
290  }
291  else if(pglobalOptions->isFirstMix())
292  {
293 #ifdef DEBUG
294  CAMsg::printMsg( LOG_DEBUG, "CADynamicCascadeConfigurator::reconfigureMix - CADynamicCascadeConfigurator::reconfigureMix - I am (and will remain) a first mix!\n");
295 #endif
296  }
297  else
298  {
299 #ifdef DEBUG
300  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");
301 #endif
302  pglobalOptions->changeMixType(CAMix::FIRST_MIX);
303  typeChanged = true;
304  }
305  }
306 
308  if( myNextMixId == NULL )
309  {
310  if(!pglobalOptions->isLastMix())
311  {
312  CAMsg::printMsg( LOG_ERR, "CADynamicCascadeConfigurator::reconfigureMix - I am NOT a LastMix and should be reconfigured as a LastMix! Won't do that!!\n");
313  return E_UNKNOWN;
314  }
315 #ifdef DEBUG
316  else
317  {
318  CAMsg::printMsg( LOG_DEBUG, "CADynamicCascadeConfigurator::reconfigureMix - I am (and will remain) a last mix!\n");
319  }
320 #endif
321  }
322 
324  if(myPrevMixId != NULL && myNextMixId != NULL)
325  {
326  if(pglobalOptions->isLastMix())
327  {
328  CAMsg::printMsg( LOG_ERR, "CADynamicCascadeConfigurator::reconfigureMix - I am a LastMix and should be reconfigured as a MiddleMix! Won't do that!!\n");
329  return E_UNKNOWN;
330  }
331  else if(pglobalOptions->isFirstMix())
332  {
333 #ifdef DEBUG
334  CAMsg::printMsg( LOG_DEBUG, "CADynamicCascadeConfigurator::reconfigureMix - I am a FirstMix and should be reconfigured as a MiddleMix!\n");
335 #endif
336  pglobalOptions->changeMixType(CAMix::MIDDLE_MIX);
337  typeChanged = true;
338  }
339  else if(pglobalOptions->isMiddleMix())
340  {
341  CAMsg::printMsg( LOG_DEBUG, "CADynamicCascadeConfigurator::reconfigureMix - I am (and will remain) a middle mix!\n");
342  }
343  else
344  {
345 #ifdef DEBUG
346  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");
347 #endif
348  pglobalOptions->changeMixType(CAMix::MIDDLE_MIX);
349  typeChanged = true;
350  }
351  }
352 
353  // MiddleMix or LastMox
354  if(myPrevMixId != NULL)
355  {
356  CAMsg::printMsg(LOG_INFO,"CADynamicCascadeConfigurator::reconfigureMix - Asking InfoService about previous mix ...\n");
357  char buf[255];
358  sprintf(buf, "/mixinfo/%s", (char*)myPrevMixId);
359  DOM_Element result;
361  ret = sendRandomInfoserviceGetRequest( (UINT8*)buf, &result);
362  if(ret != E_SUCCESS)
363  {
364  CAMsg::printMsg(LOG_ERR,"CADynamicCascadeConfigurator::reconfigureMix - Error retrieving mix info from InfoService!\n");
365  return ret;
366  }
367  DOM_Document doc = result.getOwnerDocument();
368  ret = pglobalOptions->setPrevMix( doc );
369  if(ret != E_SUCCESS)
370  {
371  CAMsg::printMsg(LOG_ERR,"CADynamicCascadeConfigurator::reconfigureMix - Error setting next mix info!\n");
372  pglobalOptions->resetPrevMix();
373  return E_UNKNOWN;
374  }
375  }
376  else
377  {
378  if(pglobalOptions->resetPrevMix() != E_SUCCESS)
379  {
380  CAMsg::printMsg( LOG_ERR, "CADynamicCascadeConfigurator::reconfigureMix - Unable to reset prev mix information\n");
381  return E_UNKNOWN;
382  }
383  }
384 
385  // MiddleMix or FirstMix
386  if(myNextMixId != NULL)
387  {
388  CAMsg::printMsg(LOG_INFO,"CADynamicCascadeConfigurator::reconfigureMix - Asking InfoService about next mix ...\n");
389  char buf[255];
390  sprintf(buf, "/mixinfo/%s", (char*)myNextMixId);
391  DOM_Element result;
392  if( sendRandomInfoserviceGetRequest( (UINT8*)buf, &result) != E_SUCCESS )
393  {
394  CAMsg::printMsg(LOG_ERR,"CADynamicCascadeConfigurator::reconfigureMix - Error retrieving mix info from InfoService!\n");
395  return E_UNKNOWN;
396  }
397  DOM_Document doc = result.getOwnerDocument();
398  if(pglobalOptions->setNextMix( doc ) != E_SUCCESS)
399  {
400  CAMsg::printMsg(LOG_ERR,"CADynamicCascadeConfigurator::reconfigureMix - Error setting next mix info!\n");
401  return E_UNKNOWN;
402  }
403  }
404  else
405  {
406  if(pglobalOptions->resetNextMix() != E_SUCCESS)
407  {
408  CAMsg::printMsg( LOG_ERR, "CADynamicCascadeConfigurator::reconfigureMix - Unable to reset next mix information\n");
409  return E_UNKNOWN;
410  }
411  }
412 
413  pglobalOptions->setCascadeProposal(a_strProposal, strlen((char*)a_strProposal));
414 /* if(pglobalOptions->isFirstMix())
415  {
416  pglobalOptions->setCascadeXML((DOM_Element&)a_elemNewCascade);
417  }*/
418 #ifdef DEBUG
419  CAMsg::printMsg( LOG_DEBUG, "CADynamicCascadeConfigurator::reconfigureMix - Calling dynaReconfigure on the mix, grab a hold of something!\n");
420 #endif
421  m_pMix->dynaReconfigure( typeChanged );
422  return E_SUCCESS;
423 }
424 
436 SINT32 CADynamicCascadeConfigurator::addProposal(DOM_Element a_elem)
437 {
439  // FIXME Signature cannot be verified. Why is that?
440  /* if( m_pSignature->verifyXML( a_elem, NULL ) != E_SUCCESS)
441  {
442  CAMsg::printMsg( LOG_DEBUG, "Signature was not ok, throwing it away...\n");
443  return E_UNKNOWN;
444  }*/
446  DOM_Element mixesElement;
447  getDOMChildByName(a_elem,(UINT8*)"Mixes", mixesElement, false);
448  DOM_Node child = mixesElement.getFirstChild();
449  char* mixId;
450  char* tmpProposal = NULL;
451  while(child!=NULL)
452  {
453  if(child.getNodeName().equals("Mix") && child.getNodeType() == DOM_Node::ELEMENT_NODE)
454  {
455  mixId = static_cast<const DOM_Element&>(child).getAttribute("id").transcode();
456  if(tmpProposal == NULL)
457  {
458  tmpProposal = new char[strlen(mixId)+1];
459  strncpy(tmpProposal, mixId, strlen(mixId)+1);
460  }
461  else
462  {
463  char *tmp = new char[strlen(tmpProposal)+1];
464  strncpy(tmp, tmpProposal, strlen(tmpProposal)+1);
465  delete tmpProposal;
466  tmpProposal = new char[ strlen(mixId) + strlen(tmp) + 1];
467  strncpy(tmpProposal, tmp, strlen(tmp) + 1);
468  delete tmp;
469  tmp = NULL;
470  strcat(tmpProposal, mixId);
471  }
472  }
473  child = child.getNextSibling();
474  }
475  UINT8* proposal = NULL;
476  UINT32 lenProposal = 0;
477  proposal = new UINT8[strlen(tmpProposal) + 1];
478  memcpy(proposal, tmpProposal, strlen(tmpProposal) + 1);
479  lenProposal = strlen(tmpProposal);
480  delete tmpProposal;
481  tmpProposal = NULL;
482 
483 #ifdef DEBUG
484 // CAMsg::printMsg(LOG_DEBUG, "CADynamicCascadeConfigurator::addProposal - next proposal is %s\n", proposal);
485 #endif
486 
488  DOM_Element elemSig, elemCert;
489  getDOMChildByName(a_elem,(UINT8*)"Signature",elemSig,false);
490  getDOMChildByName(elemSig,(UINT8*)"X509Data",elemCert,true);
491  CACertificate *cert = NULL;
492  if(elemSig!=NULL)
493  cert = CACertificate::decode(elemCert.getFirstChild(),CERT_X509CERTIFICATE);
494 
495  UINT8 proposerSki[60];
496  UINT32 lenProposerSki = 60;
497  if(cert != NULL)
498  cert->getSubjectKeyIdentifier( proposerSki, &lenProposerSki );
499 
500 #ifdef DEBUG
501 // CAMsg::printMsg(LOG_DEBUG, "CADynamicCascadeConfigurator::addProposal - the proposer is %s\n", proposerSki);
502 #endif
503 
504  bool added = false;
505 
507  PROPOSALENTRY *tmpEntry;
508  if( m_proposals == NULL )
509  {
510  m_proposals = createProposal( proposal, lenProposal, proposerSki, lenProposerSki, &a_elem );
511 #ifdef DEBUG
512 /* CAMsg::printMsg(LOG_DEBUG, "CADynamicCascadeConfigurator::addProposal - Adding proposal %s from InfoService %s. Got %i proposing IS for this value\n", m_proposals->proposal,
513  m_proposals->proposers->ski, m_proposals->count );*/
514 #endif
515  }
516  else
517  {
518  tmpEntry=m_proposals;
519  while(true)
520  {
521  if(memcmp(tmpEntry->proposal, proposal, lenProposal) == 0)
522  {
523  PROPOSERENTRY *proposer = tmpEntry->proposers;
524  bool ok = true;
525  while(true)
526  {
527  if(memcmp(proposer->ski, proposerSki, lenProposerSki) == 0)
528  {
529  // Duplicate!
530  ok = false;
531  added = true;
532  break;
533  }
534  if(proposer->next == NULL)
535  break;
536  proposer = proposer->next;
537  }
538  if(ok)
539  {
540  PROPOSERENTRY *tmpProposer = new PROPOSERENTRY;
541  tmpProposer->next = NULL;
542  tmpProposer->ski = new UINT8[lenProposerSki+1];
543  memcpy(tmpProposer->ski, proposerSki, lenProposerSki+1);
544  proposer->next = tmpProposer;
545  tmpEntry->count++;
546 #ifdef DEBUG
547 /* 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 );*/
548 #endif
549  added = true;
550  break;
551  }
552  }
553  if(tmpEntry->next == NULL)
554  break;
555  tmpEntry = tmpEntry->next;
556  }
557  if(!added)
558  {
559  tmpEntry->next = createProposal( proposal, lenProposal, proposerSki, lenProposerSki, &a_elem );
560 #ifdef DEBUG
561 /* 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 );*/
562 #endif
563  }
564  }
565  return E_SUCCESS;
566 }
567 
578 PROPOSALENTRY *CADynamicCascadeConfigurator::createProposal(UINT8* a_strProposal, UINT32 a_lenProposal, UINT8 *a_strProposer, UINT32 a_lenProposer, DOM_Element *a_elem)
579 {
580  PROPOSALENTRY *entry = new PROPOSALENTRY;
581  entry->proposal = new UINT8[a_lenProposal+1];
582  memcpy(entry->proposal, a_strProposal, a_lenProposal+1);
583  entry->count = 1;
584  entry->next = NULL;
585  PROPOSERENTRY *proposer = new PROPOSERENTRY;
586  proposer->next = NULL;
587  proposer->ski = new UINT8[a_lenProposer+1];
588  memcpy(proposer->ski, a_strProposer, a_lenProposer+1);
589  entry->proposers = proposer;
590  entry->elem = a_elem->cloneNode( true );
591  return entry;
592 }
593 #endif // DYNAMIC_MIX
#define CERT_X509CERTIFICATE
SINT32 getDOMChildByName(const DOMNode *pNode, const char *const name, DOMElement *&child, bool deep)
Definition: CAUtil.cpp:458
signed int SINT32
Definition: basetypedefs.h:132
unsigned char UINT8
Definition: basetypedefs.h:135
unsigned int UINT32
Definition: basetypedefs.h:131
SINT32 getSubjectKeyIdentifier(UINT8 *r_ski, UINT32 *r_skiLen)
LERNGRUPPE Accessor method for the subjectKeyIdentifier (SKI) extension stored in this certificate.
static CACertificate * decode(const UINT8 *const buff, UINT32 bufflen, UINT32 type, const char *const passwd=NULL)
Extracts a certificate from an encoded (DER,XML) form.
Definition: CAMix.hpp:49
@ FIRST_MIX
Definition: CAMix.hpp:53
@ MIDDLE_MIX
Definition: CAMix.hpp:54
static SINT32 printMsg(UINT32 typ, const char *format,...)
Writes a given message to the log.
Definition: CAMsg.cpp:251
This class represents a socket address for Internet (IP) connections.
const SINT32 E_SUCCESS
Definition: errorcodes.hpp:2
#define E_UNKNOWN
Definition: errorcodes.hpp:3
UINT16 len
Definition: typedefs.hpp:0