PTLib Version 2.12.9

- Main Page
- Related Pages
- Namespaces
- Classes
- Files

- File List
- File Members

All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
pstun.h
Go to the documentation of this file.
1 /*
2 * pstun.h
3 *
4 * STUN client
5 *
6 * Portable Windows Library
7 *
8 * Copyright (c) 2003 Equivalence Pty. Ltd.
9 *
10 * The contents of this file are subject to the Mozilla Public License
11 * Version 1.0 (the "License"); you may not use this file except in
12 * compliance with the License. You may obtain a copy of the License at
13 * http://www.mozilla.org/MPL/
14 *
15 * Software distributed under the License is distributed on an "AS IS"
16 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
17 * the License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * The Original Code is Portable Windows Library.
21 *
22 * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
23 *
24 * Contributor(s): ______________________________________.
25 *
26 * $Revision: 28623 $
27 * $Author: rjongbloed $
28 * $Date: 2012-12-03 15:09:17 +1100 (Mon, 03 Dec 2012) $
29 */
30
31 #ifndef PTLIB_PSTUN_H
32 #define PTLIB_PSTUN_H
33
34 #ifdef P_USE_PRAGMA
35 #pragma interface
36 #endif
37
38 #include <ptbuildopts.h>
39
40 #if P_STUN
41
42 #include <ptclib/pnat.h>
43 #include <ptlib/sockets.h>
44
46
47 class PSTUNMessage;
48 class PSTUNUDPSocket;
49
50 class PSTUN {
51 public:
52 enum {
53 DefaultPort = 3478
54 };
55
56 enum {
57 MinChannelNumber = 0x4000,
58 MaxChannelNumber = 0x7ffe,
59 };
60
61 PSTUN();
62 virtual ~PSTUN() { }
63
66 virtual PNatMethod::NatTypes DoRFC3489Discovery(
67 PSTUNUDPSocket * socket,
68 const PIPSocketAddressAndPort & serverAddress,
69 PIPSocketAddressAndPort & baseAddressAndPort,
70 PIPSocketAddressAndPort & externalAddressAndPort
71 );
72
73 virtual PNatMethod::NatTypes FinishRFC3489Discovery(
74 PSTUNMessage & responseI,
75 PSTUNUDPSocket * socket,
76 PIPSocketAddressAndPort & externalAddressAndPort
77 );
78
79 virtual int MakeAuthenticatedRequest(
80 PSTUNUDPSocket * socket,
81 PSTUNMessage & request,
82 PSTUNMessage & response
83 );
84
85 virtual bool GetFromBindingResponse(
86 const PSTUNMessage & response,
87 PIPSocketAddressAndPort & externalAddress
88 );
89
90 virtual void AppendMessageIntegrity(
91 PSTUNMessage & message
92 );
93
94 virtual void SetCredentials(
95 const PString & username,
96 const PString & password,
97 const PString & realm
98 );
99
102 virtual const PTimeInterval GetTimeout() const { return replyTimeout; }
103
106 virtual void SetTimeout(
107 const PTimeInterval & timeout
108 ) { replyTimeout = timeout; }
109
112 virtual PINDEX GetRetries() const { return m_pollRetries; }
113
116 virtual void SetRetries(
117 PINDEX retries
118 ) { m_pollRetries = retries; }
119
120 PNatMethod::NatTypes m_natType;
121 PINDEX m_pollRetries;
122 PTime m_timeAddressObtained;
123 PString m_userName;
124 PString m_realm;
125 PString m_nonce;
126 PBYTEArray m_credentialsHash;
127 PIPSocket::Address m_interface;
128 PIPSocketAddressAndPort m_serverAddress;
129 PTimeInterval replyTimeout;
130 };
131
133
134 #pragma pack(1)
135
136 struct PSTUNAttribute
137 {
138 enum Types {
139 MAPPED_ADDRESS = 0x0001, // RFC 3489 & RFC 5389
140 RESPONSE_ADDRESS = 0x0002, // RFC 3489 & RFC 5389
141 CHANGE_REQUEST = 0x0003, // RFC 3489 & RFC 5389 (added in RFC 5780)
142 SOURCE_ADDRESS = 0x0004, // RFC 3489
143 CHANGED_ADDRESS = 0x0005, // RFC 3489
144 USERNAME = 0x0006, // RFC 3489 & RFC 5389
145 PASSWORD = 0x0007, // RFC 3489
146 MESSAGE_INTEGRITY = 0x0008, // RFC 3489 & RFC 5389
147 ERROR_CODE = 0x0009, // RFC 3489 & RFC 5389
148 UNKNOWN_ATTRIBUTES = 0x000a, // RFC 3489 & RFC 5389
149 REFLECTED_FROM = 0x000b, // RFC 3489
150
151 CHANNEL_NUMBER = 0x000C, // RFC 5766
152 LIFETIME = 0x000D, // RFC 5766
153 //BANDWIDTH = 0x0010,
154 XOR_PEER_ADDRESS = 0x0012, // RFC 5766
155 DATA = 0x0013, // RFC 5766
156
157 REALM = 0x0014, // RFC 5389
158 NONCE = 0x0015, // RFC 5389
159
160 XOR_RELAYED_ADDRESS = 0x0016, // RFC 5766
161 EVEN_PORT = 0x0018, // RFC 5766
162 REQUESTED_TRANSPORT = 0x0019, // RFC 5766
163 DONT_FRAGMENT = 0x001A, // RFC 5766
164 XOR_MAPPED_ADDRESS = 0x0020, // RFC 5389
165
166 // TIMER-VAL = 0x0021,
167 RESERVATION_TOKEN = 0x0022, // RFC 5766
168
169 PADDING = 0x0026, // RFC 5389 (added in RFC 5780)
170 RESPONSE_PORT = 0x0027, // RFC 5389 (added in RFC 5780)
171
172 ALTERNATE_SERVER = 0x8023, // RFC 5389
173
174 RESPONSE_ORIGIN = 0x802b, // RFC 5389 (added in RFC 5780)
175 OTHER_ADDRESS = 0x802c // RFC 5389 (added in RFC 5780)
176 };
177
178 PUInt16b type;
179 PUInt16b length;
180
181 PSTUNAttribute * GetNext() const;
182 };
183
185
186 class PSTUNAddressAttribute : public PSTUNAttribute
187 {
188 protected:
189 BYTE pad;
190 BYTE family;
191 PUInt16b port;
192 BYTE ip[4];
193
194 public:
195 void InitAddrAttr(Types newType)
196 {
197 pad = 0;
198 family = 1;
199 type = (WORD)newType;
200 length = SizeofAddressAttribute;
201 }
202
203 WORD GetPort() const;
204 PIPSocket::Address GetIP() const;
205 void SetIPAndPort(const PIPSocketAddressAndPort & addrAndPort);
206 void GetIPAndPort(PIPSocketAddressAndPort & addrAndPort);
207
208 protected:
209 enum { SizeofAddressAttribute = sizeof(BYTE)+sizeof(BYTE)+sizeof(WORD)+4 };
210 bool IsValidAddrAttr(Types checkType) const
211 {
212 return type == checkType && length == SizeofAddressAttribute;
213 }
214 };
215
216
217 class PSTUNStringAttribute : public PSTUNAttribute
218 {
219 public:
220 char m_string[763]; // not actually 763, but this will do
221
222 PSTUNStringAttribute(Types newType, const PString & str)
223 { InitStringAttr(newType, str); }
224
225 PString GetString() const { return PString(m_string, length); }
226
227 void InitStringAttr(Types newType, const PString & str)
228 {
229 type = (WORD)newType;
230 length = (WORD)str.GetLength();
231 memcpy(m_string, (const char *)str, length);
232 }
233
234 bool IsValidStringAttr(Types checkType) const
235 {
236 return (type == checkType) && (length == strlen(m_string));
237 }
238 };
239
240
241 class PSTUNChangeRequest : public PSTUNAttribute
242 {
243 public:
244 BYTE flags[4];
245
246 PSTUNChangeRequest() { }
247
248 PSTUNChangeRequest(bool changeIP, bool changePort)
249 {
250 Initialise();
251 SetChangeIP(changeIP);
252 SetChangePort(changePort);
253 }
254
255 void Initialise()
256 {
257 type = CHANGE_REQUEST;
258 length = sizeof(flags);
259 memset(flags, 0, sizeof(flags));
260 }
261
262 bool IsValid() const { return type == CHANGE_REQUEST && length == sizeof(flags); }
263
264 bool GetChangeIP() const { return (flags[3]&4) != 0; }
265 void SetChangeIP(bool on) { if (on) flags[3] |= 4; else flags[3] &= ~4; }
266
267 bool GetChangePort() const { return (flags[3]&2) != 0; }
268 void SetChangePort(bool on) { if (on) flags[3] |= 2; else flags[3] &= ~2; }
269 };
270
271 class PSTUNMessageIntegrity : public PSTUNAttribute
272 {
273 public:
274 BYTE hmac[20];
275
276 PSTUNMessageIntegrity(const BYTE * data = NULL)
277 { Initialise(data); }
278
279 void Initialise(const BYTE * data = NULL)
280 {
281 type = MESSAGE_INTEGRITY;
282 length = sizeof(hmac);
283 if (data == NULL)
284 memset(hmac, 0, sizeof(hmac));
285 else
286 memcpy(hmac, data, sizeof(hmac));
287 }
288 bool IsValid() const { return type == MESSAGE_INTEGRITY && length == sizeof(hmac); }
289 };
290
291 class PSTUNErrorCode : public PSTUNAttribute
292 {
293 public:
294 PSTUNErrorCode()
295 { Initialise(); }
296
297 BYTE m_zero1;
298 BYTE m_zero2;
299 BYTE m_hundreds;
300 BYTE m_units;
301 char m_reason[256]; // not actually 256, but this will do
302
303 void Initialise();
304 void SetErrorCode(int code, const PString & reason);
305 int GetErrorCode() const { return (m_hundreds * 100) + m_units; }
306 PString GetReason() { return PString(m_reason); }
307 bool IsValid() const { return (type == ERROR_CODE) && (length == 4 + strlen(m_reason) + 1); }
308 };
309
310 struct PSTUNChannelNumber : public PSTUNAttribute
311 {
312 PSTUNChannelNumber()
313 { Initialise(); }
314
315 PUInt16b m_channelNumber;
316 PUInt16b m_rffu;
317
318 void Initialise();
319 };
320
321 struct PSTUNMessageHeader
322 {
323 PUInt16b msgType;
324 PUInt16b msgLength;
325 BYTE transactionId[16];
326 };
327
328 #pragma pack()
329
331
332
333 class PSTUNClient;
334
337 class PSTUNUDPSocket : public PNATUDPSocket
338 {
339 PCLASSINFO(PSTUNUDPSocket, PNATUDPSocket);
340 public:
341 PSTUNUDPSocket();
342
343 bool OpenSTUN(PSTUNClient & client);
344 PNatCandidate GetCandidateInfo();
345
346 bool BaseWriteTo(const void * buf, PINDEX len, const PIPSocketAddressAndPort & ap)
347 { Slice slice((void *)buf, len); return PUDPSocket::InternalWriteTo(&slice, 1, ap); }
348
349 bool BaseReadFrom(void * buf, PINDEX len, PIPSocketAddressAndPort & ap)
350 { Slice slice(buf, len); return PUDPSocket::InternalReadFrom(&slice, 1, ap); }
351
352 protected:
353 friend class PSTUN;
354 friend class PSTUNClient;
355
356 PIPSocketAddressAndPort m_serverReflexiveAddress;
357 PIPSocketAddressAndPort m_baseAddressAndPort;
358
359 bool InternalGetLocalAddress(PIPSocketAddressAndPort & addr);
360 bool InternalGetBaseAddress(PIPSocketAddressAndPort & addr);
361
362 private:
363 PNatMethod::NatTypes m_natType;
364 };
365
367
368 class PSTUNMessage : public PBYTEArray
369 {
370 public:
371 enum MsgType {
372 BindingRequest = 0x0001,
373 BindingResponse = 0x0101,
374 BindingError = 0x0111,
375
376 SharedSecretRequest = 0x0002,
377 SharedSecretResponse = 0x0102,
378 SharedSecretError = 0x0112,
379
380 Allocate = 0x0003, // RFC 5766
381 AllocateResponse = 0x0103, // RFC 5766
382 AllocateError = 0x0113, // RFC 5766
383
384 Refresh = 0x0004, // RFC 5766
385 Send = 0x0006, // RFC 5766
386 Data = 0x0007, // RFC 5766
387 CreatePermission = 0x0008, // RFC 5766
388 ChannelBind = 0x0009, // RFC 5766
389
390 };
391
392 PSTUNMessage();
393 PSTUNMessage(MsgType newType, const BYTE * id = NULL);
394
395 void SetType(MsgType newType, const BYTE * id = NULL);
396 MsgType GetType() const;
397
398 const BYTE * GetTransactionID() const;
399
400 const PSTUNMessageHeader * operator->() const { return (const PSTUNMessageHeader *)theArray; }
401
402 PSTUNAttribute * GetFirstAttribute() const;
403
404 bool Validate();
405 bool Validate(const PSTUNMessage & request);
406
407 PSTUNAttribute * AddAttribute(const PSTUNAttribute & attribute);
408 PSTUNAttribute * SetAttribute(const PSTUNAttribute & attribute);
409 PSTUNAttribute * FindAttribute(PSTUNAttribute::Types type) const;
410
411 template <class Type> Type * FindAttributeOfType(PSTUNAttribute::Types type) const
412 { return static_cast<Type *>(FindAttribute(type)); }
413
414 bool Read(PUDPSocket & socket);
415 bool Write(PUDPSocket & socket) const;
416 bool Poll(PUDPSocket & socket, const PSTUNMessage & request, PINDEX pollRetries);
417
418 bool IsRFC5389() const { return m_isRFC5389; }
419
420 const PIPSocketAddressAndPort GetSourceAddressAndPort() const { return m_sourceAddressAndPort; }
421
422 void InsertMessageIntegrity(BYTE * credentialsHash, PINDEX credentialsHashLen);
423 void InsertMessageIntegrity(BYTE * credentialsHash, PINDEX credentialsHashLen, PSTUNMessageIntegrity * mi);
424
425 bool CheckMessageIntegrity(BYTE * credentialsHash, PINDEX credentialsHashLen);
426 void CalculateMessageIntegrity(BYTE * credentialsHash, PINDEX credentialsHashLen, PSTUNMessageIntegrity * mi, BYTE * hmac);
427
428 protected:
429 PIPSocketAddressAndPort m_sourceAddressAndPort;
430 bool m_isRFC5389;
431 };
432
434
437 class PSTUNClient : public PNatMethod, public PSTUN
438 {
439 PCLASSINFO(PSTUNClient, PNatMethod);
440 public:
441 PSTUNClient();
442 ~PSTUNClient();
443
446 static PString GetNatMethodName();
447 virtual PString GetName() const;
448
455 bool SetServer(
456 const PString & server
457 );
458
462 virtual PString GetServer() const;
463
464 virtual bool GetServerAddress(
465 PIPSocketAddressAndPort & serverAddressAndPort
466 ) const;
467
468 virtual bool GetExternalAddress(
469 PIPSocket::Address & externalAddress,
470 const PTimeInterval & maxAge = 1000
471 );
472
473 virtual bool GetInterfaceAddress(
474 PIPSocket::Address & internalAddress
475 ) const;
476
477 virtual bool Open(
478 const PIPSocket::Address & ifaceAddr
479 );
480
481 bool IsAvailable(
482 const PIPSocket::Address & binding
483 );
484
485 virtual void Close();
486
487 // new functions
488 NatTypes FindNatType(
489 const PIPSocket::Address & binding
490 );
491
504 bool CreateSocket(
505 Component component,
506 PUDPSocket * & socket,
507 const PIPSocket::Address & = PIPSocket::GetDefaultIpAny(),
508 WORD port = 0
509 );
510
524 virtual bool CreateSocketPair(
525 PUDPSocket * & socket1,
526 PUDPSocket * & socket2,
527 const PIPSocket::Address & = PIPSocket::GetDefaultIpAny()
528 );
529
530 bool InternalOpenSocket(Component component, const PIPSocket::Address & binding, PSTUNUDPSocket & socket, PortInfo & portInfo);
531
532 protected:
533 virtual NatTypes InternalGetNatType(bool forced, const PTimeInterval & maxAge);
534
535 PSTUNUDPSocket * m_socket;
536 PMutex m_mutex;
537
538 private:
539 PIPSocketAddressAndPort m_externalAddress;
540 PINDEX numSocketsForPairing;
541 };
542
543
545
549 class PTURNRequestedTransport : public PSTUNAttribute
550 {
551 public:
552 enum {
553 ProtocolUDP = IPPROTO_UDP,
554 ProtocolTCP = IPPROTO_TCP
555 };
556 BYTE m_protocol;
557 BYTE m_rffu1;
558 BYTE m_rffu2;
559 BYTE m_rffu3;
560
561 PTURNRequestedTransport(BYTE protocol = ProtocolUDP)
562 { Initialise(protocol); }
563
564 void Initialise(BYTE protocol = ProtocolUDP);
565 bool IsValid() const { return (type == REQUESTED_TRANSPORT) && (length == 4); }
566 };
567
568
569 class PTURNLifetime : public PSTUNAttribute
570 {
571 public:
572 PUInt32b m_lifetime;
573
574 PTURNLifetime(DWORD lifetime = 600)
575 : m_lifetime(lifetime)
576 { type = LIFETIME; length = 4; }
577
578 bool IsValid() const { return (type == LIFETIME) && (length == 8); }
579
580 DWORD GetLifetime() const { return m_lifetime; }
581 };
582
583
584 class PTURNEvenPort : public PSTUNAttribute
585 {
586 public:
587 BYTE m_bits;
588
589 PTURNEvenPort(bool evenPort = true)
590 { type = EVEN_PORT; m_bits = evenPort ? 1 : 0; length = 1; }
591
592 bool IsValid() const { return (type == EVEN_PORT) && (length == 1); }
593
594 bool IsEven() const { return (m_bits & 1) != 0; }
595 };
596
598
599 class PTURNClient;
600
601 #pragma pack(1)
602
603 struct PTURNChannelHeader {
604 PUInt16b m_channelNumber;
605 PUInt16b m_length;
606 };
607
608 #pragma pack()
609
610 class PTURNUDPSocket : public PSTUNUDPSocket, public PSTUN
611 {
612 public:
613
614 friend class PTURNClient;
615
616 PTURNUDPSocket();
617 ~PTURNUDPSocket();
618
619 virtual bool Close();
620
621 virtual PNatCandidate GetCandidateInfo();
622
623 int OpenTURN(PTURNClient & client);
624
625 protected:
626 bool InternalGetLocalAddress(PIPSocketAddressAndPort & addr);
627 bool InternalWriteTo(const Slice * slices, size_t sliceCount, const PIPSocketAddressAndPort & ipAndPort);
628 bool InternalReadFrom(Slice * slices, size_t sliceCount, PIPSocketAddressAndPort & ipAndPort);
629 void InternalSetSendAddress(const PIPSocketAddressAndPort & addr);
630 void InternalGetSendAddress(PIPSocketAddressAndPort & addr);
631
632 bool m_allocationMade;
633 int m_channelNumber;
634 bool m_usingTURN;
635
636 BYTE m_protocol;
637 PIPSocketAddressAndPort m_relayedAddress;
638 DWORD m_lifeTime;
639 PIPSocketAddressAndPort m_peerIpAndPort;
640
641 std::vector<Slice> m_txVect;
642 PTURNChannelHeader m_txHeader;
643 BYTE m_txPadding[4];
644
645 std::vector<Slice> m_rxVect;
646 PTURNChannelHeader m_rxHeader;
647 BYTE m_rxPadding[4];
648 };
649
651
652 class PTURNClient : public PSTUNClient
653 {
654 PCLASSINFO(PTURNClient, PSTUNClient);
655 public:
656
657 friend class PTURNUDPSocket;
658
661 static PString GetNatMethodName();
662 virtual PString GetName() const;
663
664 PTURNClient();
665
666 // overrides from PNatMethod
667 virtual bool Open(
668 const PIPSocket::Address & iface
669 );
670
671 virtual void SetCredentials(
672 const PString & username,
673 const PString & password,
674 const PString & realm
675 );
676
677 bool CreateSocket(
678 Component component,
679 PUDPSocket * & socket,
680 const PIPSocket::Address & = PIPSocket::GetDefaultIpAny(),
681 WORD port = 0
682 );
683
684 bool CreateSocketPair(
685 PUDPSocket * & socket1,
686 PUDPSocket * & socket2,
687 const PIPSocket::Address & binding
688 );
689
693 virtual RTPSupportTypes GetRTPSupport(
694 bool force = false
695 );
696
697 protected:
698 // New functions
699 virtual bool RefreshAllocation(DWORD lifetime = 600);
700 PString m_password;
701 };
702
703
704 #endif // P_STUN
705
706 #endif // PTLIB_PSTUN_H