Stun Server  Compliant with the latest RFCs including 5389, 5769, and 5780
discover the local host's own external IP address
stunbuilder.cpp
Go to the documentation of this file.
1 /*
2  Copyright 2011 John Selbie
3 
4  Licensed under the Apache License, Version 2.0 (the "License");
5  you may not use this file except in compliance with the License.
6  You may obtain a copy of the License at
7 
8  http://www.apache.org/licenses/LICENSE-2.0
9 
10  Unless required by applicable law or agreed to in writing, software
11  distributed under the License is distributed on an "AS IS" BASIS,
12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  See the License for the specific language governing permissions and
14  limitations under the License.
15 */
16 
17 
18 
19 #include "commonincludes.hpp"
20 
21 #include "stringhelper.h"
22 #include "atomichelpers.h"
23 
24 #include "stunbuilder.h"
25 #include <boost/crc.hpp>
26 
27 #ifndef __APPLE__
28 #include <openssl/md5.h>
29 #include <openssl/hmac.h>
30 #else
31 #define COMMON_DIGEST_FOR_OPENSSL
32 #include <CommonCrypto/CommonCrypto.h>
33 #endif
34 
35 
36 #include "stunauth.h"
37 
38 
39 static int g_sequence_number = 0xaaaaaaaa;
40 
41 
43 _transactionid(),
44 _fLegacyMode(false)
45 {
46  ;
47 }
48 
49 void CStunMessageBuilder::SetLegacyMode(bool fLegacyMode)
50 {
51  _fLegacyMode = fLegacyMode;
52 }
53 
54 
56 {
57  uint16_t msgTypeField=0;
58  HRESULT hr = S_OK;
59 
60  ChkA(_stream.SetSizeHint(200));
61 
62  // merge the _msgType and _msgClass, and the leading zero bits into a 16-bit field
63  msgTypeField = (msgType & 0x0f80) << 2;
64  msgTypeField |= (msgType & 0x0070) << 1;
65  msgTypeField |= (msgType & 0x000f);
66  msgTypeField |= (msgClass & 0x02) << 7;
67  msgTypeField |= (msgClass & 0x01) << 4;
68 
69  ChkA(_stream.WriteUint16(htons(msgTypeField))); // htons for big-endian
70  ChkA(_stream.WriteUint16(0)); // place holder for length
71 
72 Cleanup:
73  return hr;
74 }
75 
77 {
79 }
80 
82 {
84 }
85 
87 {
88  _transactionid = transid;
89 
90  return _stream.Write(transid.id, sizeof(transid.id));
91 }
92 
94 {
95  StunTransactionId transid;
96  uint32_t stun_cookie_nbo = htonl(STUN_COOKIE);
97 
98  uint32_t entropy=0;
99 
100 
101  // on x86, the rdtsc instruction is about as good as it gets for a random sequence number
102  // on linux, there's /dev/urandom
103 
104 
105 #ifdef _WIN32
106  // on windows, there's lots of simple stuff we can get at to give us a random number
107  // the rdtsc instruction is about as good as it gets
108  uint64_t clock = __rdtsc();
109  entropy ^= (uint32_t)(clock);
110 #else
111  // on linux, /dev/urandom should be sufficient
112  {
113  int randomfile = ::open("/dev/urandom", O_RDONLY);
114  if (randomfile >= 0)
115  {
116  int readret = read(randomfile, &entropy, sizeof(entropy));
117  UNREFERENCED_VARIABLE(readret);
118  ASSERT(readret > 0);
119  close(randomfile);
120  }
121  }
122 
123 
124  if (entropy == 0)
125  {
126  entropy ^= getpid();
127  entropy ^= reinterpret_cast<uintptr_t>(this);
128  entropy ^= time(NULL);
129  entropy ^= AtomicIncrement(&g_sequence_number);
130  }
131 
132 #endif
133 
134 
135  srand(entropy);
136 
137 
138  // the first four bytes of the transaction id is always the magic cookie
139  // followed by 12 bytes of the real transaction id
140  memcpy(transid.id, &stun_cookie_nbo, sizeof(stun_cookie_nbo));
141  for (int x = 4; x < (STUN_TRANSACTION_ID_LENGTH-4); x++)
142  {
143  transid.id[x] = (uint8_t)(rand() % 256);
144  }
145 
146  if (pTransId)
147  {
148  *pTransId = transid;
149  }
150 
151  return AddTransactionId(transid);
152 }
153 
154 HRESULT CStunMessageBuilder::AddAttributeHeader(uint16_t attribType, uint16_t size)
155 {
156  HRESULT hr = S_OK;
157 
158  Chk(_stream.WriteUint16(htons(attribType)));
159  Chk(_stream.WriteUint16(htons(size)));
160 
161 Cleanup:
162  return hr;
163 }
164 
165 HRESULT CStunMessageBuilder::AddAttribute(uint16_t attribType, const void* data, uint16_t size)
166 {
167  uint8_t padBytes[4] = {0};
168  size_t padding = 0;
169  HRESULT hr = S_OK;
170  uint16_t sizeheader = size;
171 
172  if (data == NULL)
173  {
174  size = 0;
175  }
176 
177  // attributes always start on a 4-byte boundary
178  padding = (size % 4) ? (4 - (size % 4)) : 0;
179 
180  if (_fLegacyMode)
181  {
182  // in legacy mode (RFC 3489), the header size of the attribute includes the padding
183  // in RFC 5389, the attribute header is the exact size of the data, and extra padding bytes are implicitly assumed
184  sizeheader += padding;
185  }
186 
187  // I suppose you can have zero length attributes as an indicator of something
188  Chk(AddAttributeHeader(attribType, sizeheader));
189 
190  if (size > 0)
191  {
192  Chk(_stream.Write(data, size));
193  }
194 
195  // pad with zeros to get the 4-byte alignment
196  if (padding > 0)
197  {
198  Chk(_stream.Write(padBytes, padding));
199  }
200 
201 Cleanup:
202  return hr;
203 }
204 
205 HRESULT CStunMessageBuilder::AddStringAttribute(uint16_t attribType, const char* pstr)
206 {
207  HRESULT hr = S_OK;
208  // I can't think of a single string attribute that could be legitimately empty
209  // AddNonce, AddRealm, AddUserName below depend on this check. So if this check gets removed, add it back to everywhere else
211 
212  // AddAttribute allows empty attribute values, so if someone needs to add empty attribute values, do it with that call
213  hr = AddAttribute(attribType, pstr, pstr?strlen(pstr):0);
214 
215 Cleanup:
216  return hr;
217 }
218 
219 HRESULT CStunMessageBuilder::AddErrorCode(uint16_t errorNumber, const char* pszReason)
220 {
221  HRESULT hr = S_OK;
222  uint8_t padBytes[4] = {0};
223  size_t strsize = (pszReason==NULL) ? 0 : strlen(pszReason);
224  size_t size = strsize + 4;
225  size_t sizeheader = size;
226  size_t padding = 0;
227  uint8_t cl = 0;
228  uint8_t ernum = 0;
229 
230  ChkIf(strsize >= 128, E_INVALIDARG);
231  ChkIf(errorNumber < 300, E_INVALIDARG);
232  ChkIf(errorNumber > 600, E_INVALIDARG);
233 
234  padding = (size%4) ? (4-size%4) : 0;
235 
236  // fix for RFC 3489 clients - explicitly do the 4-byte padding alignment on the string with spaces instead of
237  // padding the message with zeros. Adjust the length field to always be a multiple of 4.
238  if ((size % 4) && _fLegacyMode)
239  {
240  padding = 4 - (size % 4);
241  }
242 
243  if (_fLegacyMode)
244  {
245  sizeheader += padding;
246  }
247 
249 
250  Chk(_stream.WriteInt16(0));
251 
252  cl = (uint8_t)(errorNumber / 100);
253  ernum = (uint8_t)(errorNumber % 100);
254 
255  Chk(_stream.WriteUint8(cl));
256  Chk(_stream.WriteUint8(ernum));
257 
258  if (strsize > 0)
259  {
260  _stream.Write(pszReason, strsize);
261  }
262 
263  if (padding > 0)
264  {
265  Chk(_stream.Write(padBytes, padding));
266  }
267 
268 Cleanup:
269  return hr;
270 }
271 
272 HRESULT CStunMessageBuilder::AddUnknownAttributes(const uint16_t* arr, size_t count)
273 {
274  HRESULT hr = S_OK;
275  uint16_t size = count * sizeof(uint16_t);
276  uint16_t unpaddedsize = size;
277  bool fPad = false;
278 
279  ChkIfA(arr == NULL, E_INVALIDARG);
280  ChkIfA(count <= 0, E_INVALIDARG);
281 
282  // fix for RFC 3489. Since legacy clients can't understand implicit padding rules
283  // of rfc 5389, then we do what rfc 3489 suggests. If there are an odd number of attributes
284  // that would make the length of the attribute not a multiple of 4, then repeat one
285  // attribute.
286 
287  fPad = _fLegacyMode && (!!(count % 2));
288 
289  if (fPad)
290  {
291  size += sizeof(uint16_t);
292  }
293 
295 
296  Chk(_stream.Write(arr, unpaddedsize));
297 
298  if (fPad)
299  {
300  // repeat the last attribute in the array to get an even alignment of 4 bytes
301  _stream.Write(&arr[count-1], sizeof(arr[0]));
302  }
303 
304 
305 Cleanup:
306  return hr;
307 }
308 
310 {
311  CSocketAddress addrxor(addr);
313 
315 
316  return AddMappedAddressImpl(attributeID, addrxor);
317 }
318 
320 {
322 }
323 
325 {
327 
328  return AddMappedAddressImpl(attribid, addr);
329 }
330 
332 {
334  return AddMappedAddressImpl(attribid, addr);
335 }
336 
338 {
339 
340  // convert to network byte order
341  port = htons(port);
342  return AddAttribute(STUN_ATTRIBUTE_RESPONSE_PORT, &port, sizeof(port));
343 }
344 
346 {
347  HRESULT hr = S_OK;
348  const uint16_t PADDING_BUFFER_SIZE = 128;
349  static char padding_bytes[PADDING_BUFFER_SIZE] = {};
350 
351  // round up so we're a multiple of 4
352  if (paddingSize % 4)
353  {
354  paddingSize = paddingSize + 4 - (paddingSize % 4);
355  }
356 
357 
359 
360  while (paddingSize > 0)
361  {
362  uint16_t blocksize = (paddingSize >= PADDING_BUFFER_SIZE) ? PADDING_BUFFER_SIZE : paddingSize;
363  Chk(_stream.Write(padding_bytes, blocksize));
364  paddingSize -= blocksize;
365  }
366 
367 Cleanup:
368  return hr;
369 
370 }
371 
372 
374 {
375  uint16_t port;
376  size_t length;
377  uint8_t ip[STUN_IPV6_LENGTH];
378  HRESULT hr = S_OK;
379  uint8_t family = (addr.GetFamily()==AF_INET) ? STUN_ATTRIBUTE_FIELD_IPV4 :STUN_ATTRIBUTE_FIELD_IPV6;
381 
382  Chk(AddAttributeHeader(attribute, attributeSize));
383 
384  port = addr.GetPort_NBO();
385  length = addr.GetIP_NBO(ip, sizeof(ip));
386  // if we ever had a length that was not a multiple of 4, we'd need to add padding
387  ASSERT((length == STUN_IPV4_LENGTH) || (length == STUN_IPV6_LENGTH));
388 
389 
390  Chk(_stream.WriteUint8(0));
391  Chk(_stream.WriteUint8(family));
392  Chk(_stream.WriteUint16(port));
393  Chk(_stream.Write(ip, length));
394 
395 
396 Cleanup:
397  return hr;
398 }
399 
401 {
402  uint32_t changeData = 0;
403 
404  if (changeAttrib.fChangeIP)
405  {
406  changeData |= 0x04;
407  }
408 
409  if (changeAttrib.fChangePort)
410  {
411  changeData |= 0x02;
412  }
413 
414  changeData = htonl(changeData);
415  return AddAttribute(STUN_ATTRIBUTE_CHANGEREQUEST, &changeData, sizeof(changeData));
416 }
417 
418 
419 
421 {
422  boost::crc_32_type result;
423  uint32_t value;
424  CRefCountedBuffer spBuffer;
425  void* pData = NULL;
426  size_t length = 0;
427  int offset;
428 
429  HRESULT hr = S_OK;
430 
432  Chk(_stream.WriteUint16(htons(sizeof(uint32_t)))); // field length is 4 bytes
433  Chk(_stream.WriteUint32(0)); // dummy value for start
434 
435  Chk(FixLengthField());
436 
437  // now do a CRC-32 on everything but the last 8 bytes
438 
439  ChkA(_stream.GetBuffer(&spBuffer));
440  pData = spBuffer->GetData();
441  length = spBuffer->GetSize();
442 
443  ASSERT(length > 8);
444  length = length-8;
445  result.process_bytes(pData, length);
446 
447  value = result.checksum();
448  value = value ^ STUN_FINGERPRINT_XOR;
449 
450  offset = -(int)(sizeof(value));
451 
452  Chk(_stream.SeekRelative(offset));
453 
454  Chk(_stream.WriteUint32(htonl(value)));
455 
456 Cleanup:
457  return hr;
458 }
459 
461 {
462  return AddStringAttribute(STUN_ATTRIBUTE_USERNAME, pszUserName);
463 }
464 
466 {
467  return AddStringAttribute(STUN_ATTRIBUTE_NONCE, pszNonce);
468 }
469 
471 {
472  return AddStringAttribute(STUN_ATTRIBUTE_REALM, pszRealm);
473 }
474 
475 
477 {
478  HRESULT hr = S_OK;
479  const size_t c_hmacsize = 20;
480  uint8_t hmacvaluedummy[c_hmacsize] = {}; // zero-init
481  unsigned int resultlength = c_hmacsize;
482  uint8_t* pDstBuf = NULL;
483 
484  CRefCountedBuffer spBuffer;
485  void* pData = NULL;
486  size_t length = 0;
487  unsigned char* pHashResult = NULL;
488  UNREFERENCED_VARIABLE(pHashResult);
489 
490  ChkIfA(key==NULL || keysize <= 0, E_INVALIDARG);
491 
492  // add in a "zero-init" HMAC value. This adds 24 bytes to the length
493  Chk(AddAttribute(STUN_ATTRIBUTE_MESSAGEINTEGRITY, hmacvaluedummy, ARRAYSIZE(hmacvaluedummy)));
494 
495  Chk(FixLengthField());
496  // now do a SHA1 on everything but the last 24 bytes (4 bytes of the attribute header and 20 bytes for the dummy content)
497 
498  ChkA(_stream.GetBuffer(&spBuffer));
499  pData = spBuffer->GetData();
500  length = spBuffer->GetSize();
501 
502  ASSERT(length > 24);
503  length = length-24;
504 
505 
506  // now do a little pointer math so that HMAC can write exactly to where the hash bytes will appear
507  pDstBuf = ((uint8_t*)pData) + length + 4;
508 
509 #ifndef __APPLE__
510  pHashResult = HMAC(EVP_sha1(), key, keysize, (uint8_t*)pData, length, pDstBuf, &resultlength);
511  ASSERT(resultlength == 20);
512  ASSERT(pHashResult != NULL);
513 #else
514  CCHmac(kCCHmacAlgSHA1, key, keysize,(uint8_t*)pData, length, pDstBuf);
515  UNREFERENCED_VARIABLE(resultlength);
516 #endif
517 
518 Cleanup:
519  return hr;
520 }
521 
523 {
524  return AddMessageIntegrityImpl((uint8_t*)pszPassword, strlen(pszPassword)); // if password is null/empty, AddMessageIntegrityImpl will ChkIfA on it
525 }
526 
527 HRESULT CStunMessageBuilder::AddMessageIntegrityLongTerm(const char* pszUserName, const char* pszRealm, const char* pszPassword)
528 {
529  HRESULT hr = S_OK;
530  const size_t MAX_KEY_SIZE = MAX_STUN_AUTH_STRING_SIZE*3 + 2;
531  uint8_t key[MAX_KEY_SIZE + 1]; // long enough for 64-char strings and two semicolons and a null char for debugging
532 
533  uint8_t hash[MD5_DIGEST_LENGTH] = {};
534  uint8_t* pResult = NULL;
535  uint8_t* pDst = key;
536 
537  size_t lenUserName = pszUserName ? strlen(pszUserName) : 0;
538  size_t lenRealm = pszRealm ? strlen(pszRealm) : 0;
539  size_t lenPassword = pszPassword ? strlen(pszPassword) : 0;
540  size_t lenTotal = lenUserName + lenRealm + lenPassword + 2; // +2 for the two colons
541 
542  UNREFERENCED_VARIABLE(pResult);
543 
544  ChkIfA(lenTotal > MAX_KEY_SIZE, E_INVALIDARG); // if we ever hit this limit, just increase MAX_STUN_AUTH_STRING_SIZE
545 
546  // too bad CDatastream really only works on refcounted buffers. Otherwise, we wouldn't have to do all this messed up pointer math
547 
548  // We could create a refcounted buffer in this function, but that would mean a call to "new and delete", and we're trying to avoid memory allocations in
549  // critical code paths because they are a proven perf hit
550 
551  // TODO - Fix CDataStream and CBuffer so that "ref counted buffers" are no longer needed
552 
553  pDst = key;
554 
555  memcpy(pDst, pszUserName, lenUserName);
556  pDst += lenUserName;
557 
558  *pDst = ':';
559  pDst++;
560 
561  memcpy(pDst, pszRealm, lenRealm);
562  pDst += lenRealm;
563 
564  *pDst = ':';
565  pDst++;
566 
567  memcpy(pDst, pszPassword, lenPassword);
568  pDst += lenPassword;
569  *pDst ='\0'; // null terminate for debugging (this char doesn not get hashed
570 
571  ASSERT((pDst-key) == lenTotal);
572 
573 #ifndef __APPLE__
574  pResult = MD5(key, lenTotal, hash);
575 #else
576  pResult = CC_MD5(key, lenTotal, hash);
577 #endif
578 
579  ASSERT(pResult != NULL);
580  hr= AddMessageIntegrityImpl(hash, MD5_DIGEST_LENGTH);
581 
582 Cleanup:
583  return hr;
584 }
585 
586 
587 
589 {
590  size_t size = _stream.GetSize();
591  size_t currentPos = _stream.GetPos();
592  HRESULT hr = S_OK;
593 
595 
596  if (size < STUN_HEADER_SIZE)
597  {
598  size = 0;
599  }
600  else
601  {
602  size = size - STUN_HEADER_SIZE;
603  }
604 
605  ChkA(_stream.SeekDirect(2)); // 2 bytes into the stream is the length
606  ChkA(_stream.WriteUint16(ntohs(size)));
607  ChkA(_stream.SeekDirect(currentPos));
608 
609 Cleanup:
610  return hr;
611 }
612 
614 {
615  HRESULT hr;
616 
617  hr = FixLengthField();
618  if (SUCCEEDED(hr))
619  {
620  hr = _stream.GetBuffer(pspBuffer);
621  }
622  return hr;
623 }
624 
626 {
627  return _stream;
628 }
#define S_OK
Definition: hresult.h:46
StunTransactionId _transactionid
Definition: stunbuilder.h:35
size_t GetPos()
Definition: datastream.cpp:177
const uint16_t STUN_ATTRIBUTE_USERNAME
Definition: stuntypes.h:39
#define ASSERT(expr)
HRESULT AddUnknownAttributes(const uint16_t *arrAttributeIds, size_t count)
const uint16_t STUN_ATTRIBUTE_MAPPEDADDRESS_SIZE_IPV6
Definition: stuntypes.h:139
HRESULT AddPaddingAttribute(uint16_t paddingSize)
HRESULT AddStringAttribute(uint16_t attribType, const char *pstr)
HRESULT AddRandomTransactionId(StunTransactionId *pTransId)
Definition: stunbuilder.cpp:93
HRESULT WriteUint16(uint16_t val)
Definition: datastream.h:49
const uint16_t STUN_ATTRIBUTE_ERRORCODE
Definition: stuntypes.h:45
HRESULT AddRealm(const char *pszRealm)
int AtomicIncrement(int *pInt)
const uint16_t STUN_IPV6_LENGTH
Definition: stuntypes.h:81
const uint16_t STUN_ATTRIBUTE_PADDING
Definition: stuntypes.h:55
#define Chk(expr)
Definition: chkmacros.h:53
HRESULT FixLengthField()
const uint16_t STUN_ATTRIBUTE_RESPONSE_ORIGIN
Definition: stuntypes.h:69
HRESULT AddXorMappedAddress(const CSocketAddress &addr)
HRESULT AddAttributeHeader(uint16_t attribType, uint16_t size)
HRESULT SeekRelative(int nOffset)
Definition: datastream.cpp:207
void ApplyStunXorMap(const StunTransactionId &id)
HRESULT AddBindingRequestHeader()
Definition: stunbuilder.cpp:76
HRESULT GetBuffer(CRefCountedBuffer *pRefCountedBuffer)
Definition: datastream.cpp:213
const uint32_t STUN_COOKIE
Definition: stuntypes.h:165
const uint16_t STUN_ATTRIBUTE_REALM
Definition: stuntypes.h:51
HRESULT AddMappedAddressImpl(uint16_t attribute, const CSocketAddress &addr)
#define UNREFERENCED_VARIABLE(unrefparam)
#define ARRAYSIZE(arr)
bool IsNullOrEmpty(const char *psz)
const uint16_t STUN_ATTRIBUTE_FINGERPRINT
Definition: stuntypes.h:67
const uint16_t STUN_ATTRIBUTE_NONCE
Definition: stuntypes.h:52
#define ChkIf(expr, hrerror)
Definition: chkmacros.h:63
HRESULT AddMappedAddress(const CSocketAddress &addr)
#define E_UNEXPECTED
Definition: hresult.h:48
const uint16_t STUN_ATTRIBUTE_UNKNOWNATTRIBUTES
Definition: stuntypes.h:46
size_t GetIP_NBO(void *pAddr, size_t length) const
static int g_sequence_number
Definition: stunbuilder.cpp:39
#define SUCCEEDED(hr)
Definition: hresult.h:28
void SetLegacyMode(bool fLegacyMode)
Definition: stunbuilder.cpp:49
HRESULT AddAttribute(uint16_t attribType, const void *data, uint16_t size)
const uint16_t STUN_ATTRIBUTE_CHANGEREQUEST
Definition: stuntypes.h:35
const uint16_t STUN_ATTRIBUTE_XORMAPPEDADDRESS
Definition: stuntypes.h:53
const uint32_t MAX_STUN_AUTH_STRING_SIZE
Definition: stunauth.h:22
const uint16_t STUN_ATTRIBUTE_RESPONSE_PORT
Definition: stuntypes.h:56
const uint16_t STUN_IPV4_LENGTH
Definition: stuntypes.h:80
HRESULT AddHeader(StunMessageType msgType, StunMessageClass msgClass)
Definition: stunbuilder.cpp:55
HRESULT AddTransactionId(const StunTransactionId &transid)
Definition: stunbuilder.cpp:86
HRESULT AddBindingResponseHeader(bool fSuccess)
Definition: stunbuilder.cpp:81
HRESULT AddResponseOriginAddress(const CSocketAddress &other)
HRESULT AddMessageIntegrityLongTerm(const char *pszUserName, const char *pszRealm, const char *pszPassword)
const uint16_t STUN_ATTRIBUTE_MAPPEDADDRESS
Definition: stuntypes.h:33
HRESULT AddFingerprintAttribute()
HRESULT AddNonce(const char *pszNonce)
int32_t HRESULT
Definition: hresult.h:22
HRESULT AddResponsePort(uint16_t port)
StunMessageClass
Definition: stuntypes.h:93
const uint16_t STUN_ATTRIBUTE_CHANGEDADDRESS
Definition: stuntypes.h:37
HRESULT GetResult(CRefCountedBuffer *pspBuffer)
const uint8_t STUN_ATTRIBUTE_FIELD_IPV4
Definition: stuntypes.h:77
HRESULT Write(const void *data, size_t size)
Definition: datastream.cpp:138
HRESULT AddErrorCode(uint16_t errorNumber, const char *pszReason)
HRESULT AddMessageIntegrityShortTerm(const char *pszPassword)
StunMessageType
Definition: stuntypes.h:102
const uint16_t STUN_ATTRIBUTE_XORMAPPEDADDRESS_OPTIONAL
Definition: stuntypes.h:62
HRESULT AddChangeRequest(const StunChangeRequestAttribute &changeAttrib)
#define E_INVALIDARG
Definition: hresult.h:51
uint8_t id[STUN_TRANSACTION_ID_LENGTH]
Definition: stuntypes.h:154
uint16_t GetPort_NBO() const
HRESULT SeekDirect(size_t pos)
Definition: datastream.cpp:187
CDataStream _stream
Definition: stunbuilder.h:34
const uint16_t STUN_ATTRIBUTE_SOURCEADDRESS
Definition: stuntypes.h:36
#define ChkA(expr)
Definition: chkmacros.h:73
const uint16_t STUN_TRANSACTION_ID_LENGTH
Definition: stuntypes.h:75
const uint16_t STUN_ATTRIBUTE_MESSAGEINTEGRITY
Definition: stuntypes.h:44
HRESULT SetSizeHint(size_t size)
Definition: datastream.cpp:41
size_t GetSize()
Definition: datastream.cpp:182
const uint16_t STUN_ATTRIBUTE_MAPPEDADDRESS_SIZE_IPV4
Definition: stuntypes.h:138
const uint32_t STUN_FINGERPRINT_XOR
Definition: stuntypes.h:172
uint16_t GetFamily() const
boost::shared_ptr< CBuffer > CRefCountedBuffer
Definition: buffer.h:65
HRESULT WriteUint32(uint32_t val)
Definition: datastream.h:50
HRESULT AddMessageIntegrityImpl(uint8_t *key, size_t keysize)
HRESULT WriteInt16(int16_t val)
Definition: datastream.h:54
#define ChkIfA(expr, hrerror)
Definition: chkmacros.h:84
const uint32_t STUN_HEADER_SIZE
Definition: stuntypes.h:176
CDataStream & GetStream()
const uint8_t STUN_ATTRIBUTE_FIELD_IPV6
Definition: stuntypes.h:78
HRESULT AddUserName(const char *pszUserName)
HRESULT WriteUint8(uint8_t val)
Definition: datastream.h:48
const uint16_t STUN_ATTRIBUTE_OTHER_ADDRESS
Definition: stuntypes.h:70
HRESULT AddOtherAddress(const CSocketAddress &other)