1 // Copyright (C) 1999-2005 Open Source Telecom Corporation.
2 // Copyright (C) 2006-2014 David Sugar, Tycho Softworks.
3 // Copyright (C) 2015 Cherokees of Idaho.
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 2 of the License, or
8 // (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public License
16 // along with GNU ccRTP.  If not, see <http://www.gnu.org/licenses/>.
17 //
18 // As a special exception, you may use this file as part of a free software
19 // library without restriction.  Specifically, if other files instantiate
20 // templates or use macros or inline functions from this file, or you compile
21 // this file and link it with other files to produce an executable, this
22 // file does not by itself cause the resulting executable to be covered by
23 // the GNU General Public License.  This exception does not however
24 // invalidate any other reasons why the executable file might be covered by
25 // the GNU General Public License.
26 //
27 // This exception applies only to the code released under the name GNU
28 // ccRTP.  If you copy code from other releases into a copy of GNU
29 // ccRTP, as the General Public License permits, the exception does
30 // not apply to the code that you add in this way.  To avoid misleading
31 // anyone as to the status of such modified files, you must delete
32 // this exception notice from them.
33 //
34 // If you write modifications of your own for GNU ccRTP, it is your choice
35 // whether to permit this exception to apply to your modifications.
36 // If you do not wish that, delete this exception notice.
37 //
38 
39 /**
40  * @file rtp.h
41  *
42  * @short Generic and audio/video profile specific RTP interface of
43  * ccRTP.
44  *
45  * The classes and types in this header provide general RTP
46  * functionality (following RFC 3550) as well as audio/video RTP
47  * profile specific functionality (following RFC 3551).
48  **/
49 
50 #ifndef CCXX_RTP_RTP_H_
51 #define CCXX_RTP_RTP_H_
52 
53 #include <ccrtp/cqueue.h>
54 #include <ccrtp/channel.h>
55 
56 NAMESPACE_COMMONCPP
57 
58 /**
59  * @defgroup sessions RTP sessions.
60  * @{
61  **/
62 
63 /**
64  * @class RTPSessionBase
65  *
66  * Generic RTP protocol stack for exchange of realtime data.  This
67  * stack uses the concept of packet send and receive queues to schedule
68  * and buffer outgoing packets and to arrange or reorder incoming packets
69  * as they arrive.
70  *
71  * This is a template class that allows customization of two aspects:
72  * the underlying network and the control protocol. The RTPDataChannel
73  * and RTCPChannel template parameters specify the socket types to
74  * use. The ServiceQueue template parameter specify which packet queue
75  * is used.
76  *
77  * RTPSessionBase objects do not have any threading policy, thus
78  * allowing to customize this aspect in derived classes (see
79  * SingleThreadRTPSession or RTPSessionPoolBase).
80  *
81  * @author David Sugar <dyfet@ostel.com>
82  * @short RTP protocol stack based on Common C++.
83  **/
84     template <class RTPDataChannel = DualRTPUDPIPv4Channel,
85           class RTCPChannel = DualRTPUDPIPv4Channel,
86           class ServiceQueue = AVPQueue>
87     class __EXPORT TRTPSessionBase : public ServiceQueue
88     {
89     public:
90         /**
91          * Builds a session waiting for packets in a host address.
92          *
93          * @param ia Network address this socket is to be bound.
94          * @param dataPort Transport port the data socket is to be bound.
95          * @param controlPort Transport port the control socket is to be bound.
96          * @param membersSize Initial size of the membership table.
97          * @param app Application this session is associated to.
98          * */
TRTPSessionBase(const InetHostAddress & ia,tpport_t dataPort,tpport_t controlPort,uint32 membersSize,RTPApplication & app)99         TRTPSessionBase(const InetHostAddress& ia, tpport_t dataPort,
100                 tpport_t controlPort, uint32 membersSize,
101                 RTPApplication& app) :
102             ServiceQueue(membersSize,app)
103             { build(ia,dataPort,controlPort); }
104 
105         /**
106          * Builds a session with the specified ssrc identifier for the
107          * local source.
108          *
109          * @param ssrc SSRC identifier for the local source.
110          * @param ia Network address this socket is to be bound.
111          * @param dataPort Transport port the data socket is to be bound.
112          * @param controlPort Transport port the control socket is to be bound.
113          * @param membersSize Initial size of the membership table.
114          * @param app Application this session is associated to.
115          **/
TRTPSessionBase(uint32 ssrc,const InetHostAddress & ia,tpport_t dataPort,tpport_t controlPort,uint32 membersSize,RTPApplication & app)116         TRTPSessionBase(uint32 ssrc,
117                 const InetHostAddress& ia,
118                 tpport_t dataPort, tpport_t controlPort,
119                 uint32 membersSize, RTPApplication& app):
120             ServiceQueue(ssrc,membersSize,app)
121             { build(ia,dataPort,controlPort); }
122 
123         /**
124          * Builds a session waiting for packets in a multicast address.
125          * TODO: ssrc constructor for multicast!
126          *
127          * @param ia Multicast address this socket is to be bound.
128          * @param dataPort Transport port the data socket is to be bound.
129          * @param controlPort Transport port the control socket is to be bound.
130          * @param membersSize Initial size of the membership table.
131          * @param app Application this session is associated to.
132          * @param iface Index (from 0 to n) of network interface to join to
133          * multicast group.
134          **/
TRTPSessionBase(const InetMcastAddress & ia,tpport_t dataPort,tpport_t controlPort,uint32 membersSize,RTPApplication & app,uint32 iface)135         TRTPSessionBase(const InetMcastAddress& ia, tpport_t dataPort,
136                 tpport_t controlPort, uint32 membersSize,
137                 RTPApplication& app, uint32 iface) :
138             ServiceQueue(membersSize,app)
139             { build(ia,dataPort,controlPort,iface); }
140 
141         /**
142          * Builds a session waiting for packets in a multicast
143          * address, with the specified ssrc identifier for the local
144          * source.
145          *
146          * @param ssrc SSRC identifier for the local source.
147          * @param ia Multicast address this socket is to be bound.
148          * @param dataPort Transport port the data socket is to be bound.
149          * @param controlPort Transport port the control socket is to be bound.
150          * @param membersSize Initial size of the membership table.
151          * @param app Application this session is associated to.
152          * @param iface Index (from 0 to n) of network interface to join to
153          * multicast group.
154          **/
TRTPSessionBase(uint32 ssrc,const InetMcastAddress & ia,tpport_t dataPort,tpport_t controlPort,uint32 membersSize,RTPApplication & app,uint32 iface)155         TRTPSessionBase(uint32 ssrc,
156                 const InetMcastAddress& ia, tpport_t dataPort,
157                 tpport_t controlPort, uint32 membersSize,
158                 RTPApplication& app, uint32 iface) :
159             ServiceQueue(ssrc,membersSize,app)
160             { build(ia,dataPort,controlPort,iface); }
161 
dispatchBYE(const std::string & str)162         virtual size_t dispatchBYE(const std::string &str)
163             {
164                 return QueueRTCPManager::dispatchBYE(str);
165             }
166 
167         /**
168          * Set the value of the TTL field in the sent packets.
169          *
170          * @param ttl Time To Live
171          * @return error code from the socket operation
172          */
173         inline Socket::Error
setMcastTTL(uint8 ttl)174         setMcastTTL(uint8 ttl)
175             {
176                 Socket::Error error = dso->setMulticast(true);
177                 if ( error ) return error;
178                 error = dso->setTimeToLive(ttl);
179                 if ( error ) return error;
180                 error = cso->setMulticast(true);
181                 if ( error ) return error;
182                 return cso->setTimeToLive(ttl);
183             }
184 
185         inline virtual
~TRTPSessionBase()186         ~TRTPSessionBase()
187             {
188                 endSocket();
189             }
190 
getDSO(void)191         inline RTPDataChannel *getDSO(void)
192             {return dso;}
193 
194     protected:
195         /**
196          * @param timeout maximum timeout to wait, in microseconds
197          */
198         inline bool
isPendingData(microtimeout_t timeout)199         isPendingData(microtimeout_t timeout)
200             { return dso->isPendingRecv(timeout); }
201 
202         InetHostAddress
203         getDataSender(tpport_t *port = NULL) const
204             { return dso->getSender(port); }
205 
206         inline size_t
getNextDataPacketSize()207         getNextDataPacketSize() const
208             { return dso->getNextPacketSize(); }
209 
210         /**
211          * Receive data from the data channel/socket.
212          *
213          * @param buffer Memory region to read to.
214          * @param len Maximum number of octets to get.
215          * @param na Source network address.
216          * @param tp Source transport port.
217          * @return Number of octets actually read.
218          */
219         inline size_t
recvData(unsigned char * buffer,size_t len,InetHostAddress & na,tpport_t & tp)220         recvData(unsigned char* buffer, size_t len,
221              InetHostAddress& na, tpport_t& tp)
222             { na = dso->getSender(tp); return dso->recv(buffer, len); }
223 
224         inline void
setDataPeer(const InetAddress & host,tpport_t port)225         setDataPeer(const InetAddress &host, tpport_t port)
226             { dso->setPeer(host,port); }
227 
228 
229         /**
230          * @param buffer memory region to write from
231          * @param len number of octets to write
232          */
233         inline size_t
sendData(const unsigned char * const buffer,size_t len)234         sendData(const unsigned char* const buffer, size_t len)
235             { return dso->send(buffer, len); }
236 
getDataRecvSocket()237         inline SOCKET getDataRecvSocket() const
238             { return dso->getRecvSocket(); }
239 
240         /**
241          * @param timeout maximum timeout to wait, in microseconds
242          * @return whether there are packets waiting to be picked
243          */
244         inline bool
isPendingControl(microtimeout_t timeout)245         isPendingControl(microtimeout_t timeout)
246             { return cso->isPendingRecv(timeout); }
247 
248         InetHostAddress
249         getControlSender(tpport_t *port = NULL) const
250             { return cso->getSender(port); }
251 
252         /**
253          * Receive data from the control channel/socket.
254          *
255          * @param buffer Buffer where to get data.
256          * @param len Maximum number of octets to get.
257          * @param na Source network address.
258          * @param tp Source transport port.
259          * @return Number of octets actually read.
260          **/
261         inline size_t
recvControl(unsigned char * buffer,size_t len,InetHostAddress & na,tpport_t & tp)262         recvControl(unsigned char *buffer, size_t len,
263                 InetHostAddress& na, tpport_t& tp)
264             { na = cso->getSender(tp); return cso->recv(buffer,len); }
265 
266         inline void
setControlPeer(const InetAddress & host,tpport_t port)267         setControlPeer(const InetAddress &host, tpport_t port)
268             { cso->setPeer(host,port); }
269 
270         /**
271          * @return number of octets actually written
272          * @param buffer
273          * @param len
274          */
275         inline size_t
sendControl(const unsigned char * const buffer,size_t len)276         sendControl(const unsigned char* const buffer, size_t len)
277             { return cso->send(buffer,len); }
278 
getControlRecvSocket()279         inline SOCKET getControlRecvSocket() const
280             { return cso->getRecvSocket(); }
281 
282         /**
283          * Join a multicast group.
284          *
285          * @param ia address of the multicast group
286          * @return error code from the socket operation
287          */
288         inline Socket::Error
joinGroup(const InetMcastAddress & ia,uint32 iface)289         joinGroup(const InetMcastAddress& ia, uint32 iface)
290             {
291                 Socket::Error error  = dso->setMulticast(true);
292                 if ( error ) return error;
293                 error = dso->join(ia,iface);
294                 if ( error ) return error;
295                 error = cso->setMulticast(true);
296                 if ( error ) {
297                     dso->drop(ia);
298                     return error;
299                 }
300                 error = cso->join(ia,iface);
301                 if ( error ) {
302                     dso->drop(ia);
303                     return error;
304                 }
305                 return Socket::errSuccess;
306             }
307 
308         /**
309          * Leave a multicast group.
310          *
311          * @param ia address of the multicast group
312          * @return error code from the socket operation
313          */
314         inline Socket::Error
leaveGroup(const InetMcastAddress & ia)315         leaveGroup(const InetMcastAddress& ia)
316             {
317                 Socket::Error error = dso->setMulticast(false);
318                 if ( error ) return error;
319                 error = dso->leaveGroup(ia);
320                 if ( error ) return error;
321                 error = cso->setMulticast(false);
322                 if ( error ) return error;
323                 return cso->leaveGroup(ia);
324             }
325 
326         inline void
endSocket()327         endSocket()
328             {
329                 if (dso) {
330                     dso->endSocket();
331                     delete dso;
332                 }
333                 dso = NULL;
334                 if (cso) {
335                     cso->endSocket();
336                     delete cso;
337                 }
338                 cso = NULL;
339             }
340 
341     private:
342         void
build(const InetHostAddress & ia,tpport_t dataPort,tpport_t controlPort)343         build(const InetHostAddress& ia, tpport_t dataPort,
344               tpport_t controlPort)
345             {
346                 if ( 0 == controlPort ) {
347                     dataBasePort = even_port(dataPort);
348                     controlBasePort = dataBasePort + 1;
349                 } else {
350                     dataBasePort = dataPort;
351                     controlBasePort = controlPort;
352                 }
353                 dso = new RTPDataChannel(ia,dataBasePort);
354                 cso = new RTCPChannel(ia,controlBasePort);
355             }
356 
357         void
build(const InetMcastAddress & ia,tpport_t dataPort,tpport_t controlPort,uint32 iface)358         build(const InetMcastAddress& ia, tpport_t dataPort,
359               tpport_t controlPort, uint32 iface)
360             {
361                 if ( 0 == controlPort ) {
362                     dataBasePort = even_port(dataPort);
363                     controlBasePort = dataBasePort + 1;
364                 } else {
365                     dataBasePort = dataPort;
366                     controlBasePort = controlPort;
367                 }
368                 dso = new RTPDataChannel(InetHostAddress("0.0.0.0"),dataBasePort);
369                 cso = new RTCPChannel(InetHostAddress("0.0.0.0"),controlBasePort);
370                 joinGroup(ia,iface);
371             }
372 
373         /**
374          * Ensure a port number is odd. If it is an even number, return
375          * the next lower (odd) port number.
376          *
377          * @param port number to filter
378          * @return filtered (odd) port number
379          */
380         inline tpport_t
odd_port(tpport_t port)381         odd_port(tpport_t port)
382             { return (port & 0x01)? (port) : (port - 1); }
383 
384         /**
385          * Ensure a port number is even. If it is an odd number, return
386          * the next lower (even) port number.
387          *
388          * @param port number to filter
389          * @return filtered (even) port number
390          */
391         inline tpport_t
even_port(tpport_t port)392         even_port(tpport_t port)
393             { return (port & 0x01)? (port - 1) : (port); }
394 
395         tpport_t dataBasePort;
396         tpport_t controlBasePort;
397 
398     protected:
399         RTPDataChannel* dso;
400         RTCPChannel* cso;
401         friend class RTPSessionBaseHandler;
402     };
403 
404 /**
405  * @class SingleThreadRTPSession
406  *
407  * This template class adds the threading aspect to the RTPSessionBase
408  * template in one of the many possible ways. It inherits from a
409  * single execution thread that schedules sending of outgoing packets
410  * and receipt of incoming packets.
411  *
412  * @author Federico Montesino Pouzols <fedemp@altern.org>
413  **/
414     template
415     <class RTPDataChannel = DualRTPUDPIPv4Channel,
416      class RTCPChannel = DualRTPUDPIPv4Channel,
417      class ServiceQueue = AVPQueue>
418     class __EXPORT SingleThreadRTPSession :
419         protected Thread,
420         public TRTPSessionBase<RTPDataChannel,RTCPChannel,ServiceQueue>
421     {
422     public:
423         SingleThreadRTPSession(const InetHostAddress& ia,
424                        tpport_t dataPort = DefaultRTPDataPort,
425                        tpport_t controlPort = 0,
426                        int pri = 0,
427                        uint32 memberssize =
428                        MembershipBookkeeping::defaultMembersHashSize,
429                        RTPApplication& app = defaultApplication()
430 #if defined(_MSC_VER) && _MSC_VER >= 1300
431             );
432 #else
433         ):
434         Thread(pri),
435         TRTPSessionBase<RTPDataChannel,RTCPChannel,ServiceQueue>
436         (ia,dataPort,controlPort,memberssize,app)
437         { }
438 #endif
439 
440         SingleThreadRTPSession(uint32 ssrc, const InetHostAddress& ia,
441                                tpport_t dataPort = DefaultRTPDataPort,
442                                tpport_t controlPort = 0,
443                                int pri = 0,
444                                uint32 memberssize =
445                                MembershipBookkeeping::defaultMembersHashSize,
446                                RTPApplication& app = defaultApplication()
447 #if defined(_MSC_VER) && _MSC_VER >= 1300
448         );
449 #else
450     ):
451     Thread(pri),
452     TRTPSessionBase<RTPDataChannel,RTCPChannel,ServiceQueue>
453     (ssrc, ia,dataPort,controlPort,memberssize,app)
454 { }
455 #endif
456 
457 SingleThreadRTPSession(const InetMcastAddress& ia,
458                tpport_t dataPort = DefaultRTPDataPort,
459                tpport_t controlPort = 0,
460                int pri = 0,
461                uint32 memberssize =
462                MembershipBookkeeping::defaultMembersHashSize,
463                RTPApplication& app = defaultApplication(),
464                uint32 iface = 0
465 #if defined(_MSC_VER) && _MSC_VER >= 1300
466            );
467 #else
468         ):
469         Thread(pri),
470         TRTPSessionBase<RTPDataChannel,RTCPChannel,ServiceQueue>
471         (ia,dataPort,controlPort,memberssize,app,iface)
472         { }
473 #endif
474 
475 SingleThreadRTPSession(uint32 ssrc, const InetMcastAddress& ia,
476                tpport_t dataPort = DefaultRTPDataPort,
477                tpport_t controlPort = 0,
478                int pri = 0,
479                uint32 memberssize =
480                MembershipBookkeeping::defaultMembersHashSize,
481                RTPApplication& app = defaultApplication(),
482                uint32 iface = 0
483 #if defined(_MSC_VER) && _MSC_VER >= 1300
484                       );
485 #else
486                 ):
487                 Thread(pri),
488                 TRTPSessionBase<RTPDataChannel,RTCPChannel,ServiceQueue>
489                 (ssrc,ia,dataPort,controlPort,memberssize,app,iface)
490 { }
491 #endif
492 
493 
~SingleThreadRTPSession()494 ~SingleThreadRTPSession()
495 {
496     if (isRunning()) {
497         disableStack(); Thread::join();
498     }
499 }
500 
501 #if defined(_MSC_VER) && _MSC_VER >= 1300
502 virtual void startRunning();
503 #else
504 /**
505  * Activate stack and start service thread.
506  **/
507 void
startRunning()508 startRunning()
509 { enableStack(); Thread::start(); }
510 #endif
511 
512 
513 protected:
disableStack(void)514 inline void disableStack(void)
515 {TRTPSessionBase<RTPDataChannel,RTCPChannel,ServiceQueue>::disableStack();}
516 
enableStack(void)517 inline void enableStack(void)
518 {TRTPSessionBase<RTPDataChannel,RTCPChannel,ServiceQueue>::enableStack();}
519 
getSchedulingTimeout(void)520 inline microtimeout_t getSchedulingTimeout(void)
521 {return TRTPSessionBase<RTPDataChannel,RTCPChannel,ServiceQueue>::getSchedulingTimeout();}
522 
controlReceptionService(void)523 inline void controlReceptionService(void)
524 {TRTPSessionBase<RTPDataChannel,RTCPChannel,ServiceQueue>::controlReceptionService();}
525 
controlTransmissionService(void)526 inline void controlTransmissionService(void)
527 {TRTPSessionBase<RTPDataChannel,RTCPChannel,ServiceQueue>::controlTransmissionService();}
528 
getRTCPCheckInterval(void)529 inline timeval getRTCPCheckInterval(void)
530 {return TRTPSessionBase<RTPDataChannel,RTCPChannel,ServiceQueue>::getRTCPCheckInterval();}
531 
dispatchDataPacket(void)532 inline size_t dispatchDataPacket(void)
533 {return TRTPSessionBase<RTPDataChannel,RTCPChannel,ServiceQueue>::dispatchDataPacket();}
534 
535 #if defined(_MSC_VER) && _MSC_VER >= 1300
536 virtual void run(void);
537 
538 virtual void timerTick(void);
539 
540 virtual bool isPendingData(microtimeout_t timeout);
541 #else
542 
timerTick(void)543 virtual void timerTick(void)
544 {return;}
545 
isPendingData(microtimeout_t timeout)546 virtual bool isPendingData(microtimeout_t timeout)
547 {return TRTPSessionBase<RTPDataChannel,RTCPChannel,ServiceQueue>::isPendingData(timeout);}
548 
549 /**
550  * Single runnable method for this RTP stacks, schedules
551  * outgoing and incoming RTP data and RTCP packets.
552  **/
run(void)553 virtual void run(void)
554 {
555     microtimeout_t timeout = 0;
556     while ( ServiceQueue::isActive() ) {
557         if ( timeout < 1000 ){ // !(timeout/1000)
558             timeout = getSchedulingTimeout();
559         }
560         controlReceptionService();
561         controlTransmissionService();
562         microtimeout_t maxWait =
563             timeval2microtimeout(getRTCPCheckInterval());
564         // make sure the scheduling timeout is
565         // <= the check interval for RTCP
566         // packets
567         timeout = (timeout > maxWait)? maxWait : timeout;
568         if ( timeout < 1000 ) { // !(timeout/1000)
569             dispatchDataPacket();
570             timerTick();
571         } else {
572             if ( isPendingData(timeout/1000) ) {
573                                 if (ServiceQueue::isActive()) { // take in only if active
574                                     takeInDataPacket();
575                                 }
576             }
577             timeout = 0;
578         }
579     }
580     dispatchBYE("GNU ccRTP stack finishing.");
581 //        Thread::exit();
582 }
583 
584 #endif
585 
takeInDataPacket(void)586 inline size_t takeInDataPacket(void)
587 {return TRTPSessionBase<RTPDataChannel,RTCPChannel,ServiceQueue>::takeInDataPacket();}
588 
dispatchBYE(const std::string & str)589 inline size_t dispatchBYE(const std::string &str)
590 {return TRTPSessionBase<RTPDataChannel,RTCPChannel,ServiceQueue>::dispatchBYE(str);}
591 };
592 
593 /**
594  * @typedef RTPSession
595  *
596  * Uses two pairs of sockets for RTP data and RTCP
597  * transmission/reception.
598  *
599  * @short UDP/IPv4 RTP Session scheduled by one thread of execution.
600  **/
601 typedef SingleThreadRTPSession<> RTPSession;
602 
603 /**
604  * @typedef RTPSocket
605  *
606  * Alias for RTPSession.
607  **/
608 typedef RTPSession RTPSocket;
609 
610 /**
611  * @typedef SymmetricRTPSession
612  *
613  * Uses one pair of sockets, (1) for RTP data and (2) for RTCP
614  * transmission/reception.
615  *
616  * @short Symmetric UDP/IPv4 RTP session scheduled by one thread of execution.
617  **/
618 typedef SingleThreadRTPSession<SymmetricRTPChannel,
619                    SymmetricRTPChannel> SymmetricRTPSession;
620 
621 #ifdef  CCXX_IPV6
622 
623 /**
624  * @class RTPSessionBaseIPV6
625  *
626  * Generic RTP protocol stack for exchange of realtime data.  This
627  * stack uses the concept of packet send and receive queues to schedule
628  * and buffer outgoing packets and to arrange or reorder incoming packets
629  * as they arrive.
630  *
631  * This is a template class that allows customization of two aspects:
632  * the underlying network and the control protocol. The RTPDataChannel
633  * and RTCPChannel template parameters specify the socket types to
634  * use. The ServiceQueue template parameter specify which packet queue
635  * is used.
636  *
637  * RTPSessionBase objects do not have any threading policy, thus
638  * allowing to customize this aspect in derived classes (see
639  * SingleThreadRTPSession or RTPSessionPoolBase).
640  *
641  * @author David Sugar <dyfet@ostel.com>
642  * @short RTP protocol stack based on Common C++.
643  **/
644 template <class RTPDataChannel = DualRTPUDPIPv6Channel,
645       class RTCPChannel = DualRTPUDPIPv6Channel,
646       class ServiceQueue = AVPQueue>
647 class __EXPORT TRTPSessionBaseIPV6 : public ServiceQueue
648 {
649 public:
650 /**
651  * Builds a session waiting for packets in a host address.
652  *
653  * @param ia Network address this socket is to be bound.
654  * @param dataPort Transport port the data socket is to be bound.
655  * @param controlPort Transport port the control socket is to be bound.
656  * @param membersSize Initial size of the membership table.
657  * @param app Application this session is associated to.
658  * */
TRTPSessionBaseIPV6(const IPV6Host & ia,tpport_t dataPort,tpport_t controlPort,uint32 membersSize,RTPApplication & app)659 TRTPSessionBaseIPV6(const IPV6Host& ia, tpport_t dataPort,
660     tpport_t controlPort, uint32 membersSize,
661     RTPApplication& app) :
662     ServiceQueue(membersSize,app)
663 { build(ia,dataPort,controlPort); }
664 
665     /**
666      * Builds a session with the specified ssrc identifier for the
667      * local source.
668      *
669      * @param ssrc SSRC identifier for the local source.
670      * @param ia Network address this socket is to be bound.
671      * @param dataPort Transport port the data socket is to be bound.
672      * @param controlPort Transport port the control socket is to be bound.
673      * @param membersSize Initial size of the membership table.
674      * @param app Application this session is associated to.
675      **/
TRTPSessionBaseIPV6(uint32 ssrc,const IPV6Host & ia,tpport_t dataPort,tpport_t controlPort,uint32 membersSize,RTPApplication & app)676     TRTPSessionBaseIPV6(uint32 ssrc,
677                 const IPV6Host& ia,
678                 tpport_t dataPort, tpport_t controlPort,
679                 uint32 membersSize, RTPApplication& app):
680         ServiceQueue(ssrc,membersSize,app)
681         { build(ia,dataPort,controlPort); }
682 
683     /**
684      * Builds a session waiting for packets in a multicast address.
685      * TODO: ssrc constructor for multicast!
686      *
687      * @param ia Multicast address this socket is to be bound.
688      * @param dataPort Transport port the data socket is to be bound.
689      * @param controlPort Transport port the control socket is to be bound.
690      * @param membersSize Initial size of the membership table.
691      * @param app Application this session is associated to.
692      * @param iface Index (from 0 to n) of network interface to join to
693      * multicast group.
694      **/
TRTPSessionBaseIPV6(const IPV6Multicast & ia,tpport_t dataPort,tpport_t controlPort,uint32 membersSize,RTPApplication & app,uint32 iface)695     TRTPSessionBaseIPV6(const IPV6Multicast& ia, tpport_t dataPort,
696                 tpport_t controlPort, uint32 membersSize,
697                 RTPApplication& app, uint32 iface) :
698         ServiceQueue(membersSize,app)
699         { build(ia,dataPort,controlPort,iface); }
700 
701     /**
702      * Builds a session waiting for packets in a multicast
703      * address, with the specified ssrc identifier for the local
704      * source.
705      *
706      * @param ssrc SSRC identifier for the local source.
707      * @param ia Multicast address this socket is to be bound.
708      * @param dataPort Transport port the data socket is to be bound.
709      * @param controlPort Transport port the control socket is to be bound.
710      * @param membersSize Initial size of the membership table.
711      * @param app Application this session is associated to.
712      * @param iface Index (from 0 to n) of network interface to join to
713      * multicast group.
714      **/
TRTPSessionBaseIPV6(uint32 ssrc,const IPV6Multicast & ia,tpport_t dataPort,tpport_t controlPort,uint32 membersSize,RTPApplication & app,uint32 iface)715     TRTPSessionBaseIPV6(uint32 ssrc,
716                 const IPV6Multicast& ia, tpport_t dataPort,
717                 tpport_t controlPort, uint32 membersSize,
718                 RTPApplication& app, uint32 iface) :
719         ServiceQueue(ssrc,membersSize,app)
720         { build(ia,dataPort,controlPort,iface); }
721 
dispatchBYE(const std::string & str)722     virtual size_t dispatchBYE(const std::string &str)
723         {
724             return QueueRTCPManager::dispatchBYE(str);
725         }
726 
727     inline virtual
~TRTPSessionBaseIPV6()728     ~TRTPSessionBaseIPV6()
729         {
730             endSocket();
731         }
732 
getDSO(void)733     inline RTPDataChannel *getDSO(void)
734         {return dso;}
735 
736 protected:
737     /**
738      * @param timeout maximum timeout to wait, in microseconds
739      */
740     inline bool
isPendingData(microtimeout_t timeout)741     isPendingData(microtimeout_t timeout)
742         { return dso->isPendingRecv(timeout); }
743 
744     inline IPV6Host
745     getDataSender(tpport_t *port = NULL) const
746         { return dso->getSender(port); }
747 
748     inline size_t
getNextDataPacketSize()749     getNextDataPacketSize() const
750         { return dso->getNextPacketSize(); }
751 
752     /**
753      * Receive data from the data channel/socket.
754      *
755      * @param buffer Memory region to read to.
756      * @param len Maximum number of octets to get.
757      * @param na Source network address.
758      * @param tp Source transport port.
759      * @return Number of octets actually read.
760      */
761     inline size_t
recvData(unsigned char * buffer,size_t len,IPV6Host & na,tpport_t & tp)762     recvData(unsigned char* buffer, size_t len,
763          IPV6Host& na, tpport_t& tp)
764         { na = dso->getSender(tp); return dso->recv(buffer, len); }
765 
766         inline void
setDataPeerIPV6(const IPV6Host & host,tpport_t port)767         setDataPeerIPV6(const IPV6Host &host, tpport_t port)
768         { dso->setPeer(host,port); }
769 
770     /**
771      * @param buffer memory region to write from
772      * @param len number of octets to write
773      */
774     inline size_t
sendDataIPV6(const unsigned char * const buffer,size_t len)775     sendDataIPV6(const unsigned char* const buffer, size_t len)
776         { return dso->send(buffer, len); }
777 
getDataRecvSocket()778     inline SOCKET getDataRecvSocket() const
779         { return dso->getRecvSocket(); }
780 
781     /**
782      * @param timeout maximum timeout to wait, in microseconds
783      * @return whether there are packets waiting to be picked
784      */
785         inline bool
isPendingControl(microtimeout_t timeout)786     isPendingControl(microtimeout_t timeout)
787         { return cso->isPendingRecv(timeout); }
788 
789     inline IPV6Host
790     getControlSender(tpport_t *port = NULL) const
791         { return cso->getSender(port); }
792 
793     /**
794      * Receive data from the control channel/socket.
795      *
796      * @param buffer Buffer where to get data.
797      * @param len Maximum number of octets to get.
798      * @param na Source network address.
799      * @param tp Source transport port.
800      * @return Number of octets actually read.
801      **/
802         inline size_t
recvControl(unsigned char * buffer,size_t len,IPV6Host & na,tpport_t & tp)803     recvControl(unsigned char *buffer, size_t len,
804             IPV6Host& na, tpport_t& tp)
805         { na = cso->getSender(tp); return cso->recv(buffer,len); }
806 
807         inline void
setControlPeerIPV6(const IPV6Host & host,tpport_t port)808         setControlPeerIPV6(const IPV6Host &host, tpport_t port)
809         { cso->setPeer(host,port); }
810 
811     /**
812      * @return number of octets actually written
813      * @param buffer
814      * @param len
815      */
816         inline size_t
sendControl(const unsigned char * const buffer,size_t len)817     sendControl(const unsigned char* const buffer, size_t len)
818         { return cso->send(buffer,len); }
819 
getControlRecvSocket()820     inline SOCKET getControlRecvSocket() const
821         { return cso->getRecvSocket(); }
822 
823     inline void
endSocket()824     endSocket()
825         {
826             dso->endSocket();
827             cso->endSocket();
828             if (dso) delete dso;
829             dso = NULL;
830             if (cso) delete cso;
831             cso = NULL;
832         }
833 
834 private:
835     void
build(const IPV6Host & ia,tpport_t dataPort,tpport_t controlPort)836     build(const IPV6Host& ia, tpport_t dataPort,
837           tpport_t controlPort)
838         {
839             if ( 0 == controlPort ) {
840                 dataBasePort = even_port(dataPort);
841                 controlBasePort = dataBasePort + 1;
842             } else {
843                 dataBasePort = dataPort;
844                 controlBasePort = controlPort;
845             }
846             dso = new RTPDataChannel(ia,dataBasePort);
847             cso = new RTCPChannel(ia,controlBasePort);
848         }
849 
850     void
build(const IPV6Multicast & ia,tpport_t dataPort,tpport_t controlPort,uint32 iface)851     build(const IPV6Multicast& ia, tpport_t dataPort,
852           tpport_t controlPort, uint32 iface)
853         {
854             if ( 0 == controlPort ) {
855                 dataBasePort = even_port(dataPort);
856                 controlBasePort = dataBasePort + 1;
857             } else {
858                 dataBasePort = dataPort;
859                 controlBasePort = controlPort;
860             }
861             dso = new RTPDataChannel(IPV6Host("0.0.0.0"),dataBasePort);
862             cso = new RTCPChannel(IPV6Host("0.0.0.0"),controlBasePort);
863             joinGroup(ia,iface);
864         }
865 
866     /**
867      * Join a multicast group.
868      *
869      * @param ia address of the multicast group
870      * @return error code from the socket operation
871      */
872     inline Socket::Error
joinGroup(const IPV6Multicast & ia,uint32 iface)873     joinGroup(const IPV6Multicast& ia, uint32 iface)
874         {
875             Socket::Error error  = dso->setMulticast(true);
876             if ( error ) return error;
877             error = dso->join(ia,iface);
878             if ( error ) return error;
879             error = cso->setMulticast(true);
880             if ( error ) {
881                 dso->drop(ia);
882                 return error;
883             }
884             error = cso->join(ia,iface);
885             if ( error ) {
886                 dso->drop(ia);
887                 return error;
888             }
889             return Socket::errSuccess;
890         }
891 
892     /**
893      * Leave a multicast group.
894      *
895      * @param ia address of the multicast group
896      * @return error code from the socket operation
897      */
898     inline Socket::Error
leaveGroup(const IPV6Multicast & ia)899     leaveGroup(const IPV6Multicast& ia)
900         {
901             Socket::Error error = dso->setMulticast(false);
902             if ( error ) return error;
903             error = dso->leaveGroup(ia);
904             if ( error ) return error;
905             error = cso->setMulticast(false);
906             if ( error ) return error;
907             return cso->leaveGroup(ia);
908         }
909 
910     /**
911      * Set the value of the TTL field in the sent packets.
912      *
913      * @param ttl Time To Live
914      * @return error code from the socket operation
915      */
916     inline Socket::Error
setMcastTTL(uint8 ttl)917     setMcastTTL(uint8 ttl)
918         {
919             Socket::Error error = dso->setMulticast(true);
920             if ( error ) return error;
921             error = dso->setTimeToLive(ttl);
922             if ( error ) return error;
923             error = cso->setMulticast(true);
924             if ( error ) return error;
925             return cso->setTimeToLive(ttl);
926         }
927 
928     /**
929      * Ensure a port number is odd. If it is an even number, return
930      * the next lower (odd) port number.
931      *
932      * @param port number to filter
933      * @return filtered (odd) port number
934      */
935     inline tpport_t
odd_port(tpport_t port)936     odd_port(tpport_t port)
937         { return (port & 0x01)? (port) : (port - 1); }
938 
939     /**
940      * Ensure a port number is even. If it is an odd number, return
941      * the next lower (even) port number.
942      *
943      * @param port number to filter
944      * @return filtered (even) port number
945      */
946     inline tpport_t
even_port(tpport_t port)947     even_port(tpport_t port)
948         { return (port & 0x01)? (port - 1) : (port); }
949 
950     tpport_t dataBasePort;
951     tpport_t controlBasePort;
952 
953 protected:
954     RTPDataChannel* dso;
955     RTCPChannel* cso;
956     friend class RTPSessionBaseHandler;
957 };
958 
959 /**
960  * @class SingleThreadRTPSessionIPV6
961  *
962  * This template class adds the threading aspect to the RTPSessionBase
963  * template in one of the many possible ways. It inherits from a
964  * single execution thread that schedules sending of outgoing packets
965  * and receipt of incoming packets.
966  *
967  * @author David Sugar <dyfet@gnutelephony.org>
968  **/
969 template
970 <class RTPDataChannel = DualRTPUDPIPv6Channel,
971  class RTCPChannel = DualRTPUDPIPv6Channel,
972  class ServiceQueue = AVPQueue>
973 class __EXPORT SingleThreadRTPSessionIPV6 :
974     protected Thread,
975     public TRTPSessionBaseIPV6<RTPDataChannel,RTCPChannel,ServiceQueue>
976 {
977 public:
978     SingleThreadRTPSessionIPV6(const IPV6Host& ia,
979                    tpport_t dataPort = DefaultRTPDataPort,
980                    tpport_t controlPort = 0,
981                    int pri = 0,
982                    uint32 memberssize =
983                    MembershipBookkeeping::defaultMembersHashSize,
984                    RTPApplication& app = defaultApplication()
985 #if defined(_MSC_VER) && _MSC_VER >= 1300
986         );
987 #else
988     ):
989     Thread(pri),
990     TRTPSessionBaseIPV6<RTPDataChannel,RTCPChannel,ServiceQueue>
991     (ia,dataPort,controlPort,memberssize,app)
992 { }
993 #endif
994 
995 SingleThreadRTPSessionIPV6(const IPV6Multicast& ia,
996                tpport_t dataPort = DefaultRTPDataPort,
997                tpport_t controlPort = 0,
998                int pri = 0,
999                uint32 memberssize =
1000                MembershipBookkeeping::defaultMembersHashSize,
1001                RTPApplication& app = defaultApplication(),
1002                uint32 iface = 0
1003 #if defined(_MSC_VER) && _MSC_VER >= 1300
1004     );
1005 #else
1006         ):
1007         Thread(pri),
1008         TRTPSessionBaseIPV6<RTPDataChannel,RTCPChannel,ServiceQueue>
1009         (ia,dataPort,controlPort,memberssize,app,iface)
1010 { }
1011 #endif
1012 
~SingleThreadRTPSessionIPV6()1013 ~SingleThreadRTPSessionIPV6()
1014 {
1015     if (isRunning()) {
1016         disableStack(); Thread::join();
1017     }
1018 }
1019 
1020 #if defined(_MSC_VER) && _MSC_VER >= 1300
1021 virtual void startRunning();
1022 #else
1023 /**
1024  * Activate stack and start service thread.
1025  **/
1026 void
startRunning()1027 startRunning()
1028 { enableStack(); Thread::start(); }
1029 #endif
1030 
1031 
1032 protected:
enableStack(void)1033 inline void enableStack(void)
1034 {TRTPSessionBaseIPV6<RTPDataChannel,RTCPChannel,ServiceQueue>::enableStack();}
1035 
disableStack(void)1036 inline void disableStack(void)
1037 {TRTPSessionBaseIPV6<RTPDataChannel,RTCPChannel,ServiceQueue>::disableStack();}
1038 
getSchedulingTimeout(void)1039 inline microtimeout_t getSchedulingTimeout(void)
1040 {return TRTPSessionBaseIPV6<RTPDataChannel,RTCPChannel,ServiceQueue>::getSchedulingTimeout();}
1041 
controlReceptionService(void)1042 inline void controlReceptionService(void)
1043 {TRTPSessionBaseIPV6<RTPDataChannel,RTCPChannel,ServiceQueue>::controlReceptionService();}
1044 
controlTransmissionService(void)1045 inline void controlTransmissionService(void)
1046 {TRTPSessionBaseIPV6<RTPDataChannel,RTCPChannel,ServiceQueue>::controlTransmissionService();}
1047 
getRTCPCheckInterval(void)1048 inline timeval getRTCPCheckInterval(void)
1049 {return TRTPSessionBaseIPV6<RTPDataChannel,RTCPChannel,ServiceQueue>::getRTCPCheckInterval();}
1050 
dispatchDataPacket(void)1051 inline size_t dispatchDataPacket(void)
1052 {return TRTPSessionBaseIPV6<RTPDataChannel,RTCPChannel,ServiceQueue>::dispatchDataPacket();}
1053 
1054 #if defined(_MSC_VER) && _MSC_VER >= 1300
1055 virtual void run(void);
1056 
1057 virtual void timerTick(void);
1058 
1059 virtual bool isPendingData(microtimeout_t timeout);
1060 #else
1061 
timerTick(void)1062 virtual void timerTick(void)
1063 {return;}
1064 
isPendingData(microtimeout_t timeout)1065 virtual bool isPendingData(microtimeout_t timeout)
1066 {return TRTPSessionBaseIPV6<RTPDataChannel,RTCPChannel,ServiceQueue>::isPendingData(timeout);}
1067 
1068 /**
1069  * Single runnable method for this RTP stacks, schedules
1070  * outgoing and incoming RTP data and RTCP packets.
1071  **/
run(void)1072 virtual void run(void)
1073 {
1074     microtimeout_t timeout = 0;
1075     while ( ServiceQueue::isActive() ) {
1076         if ( timeout < 1000 ){ // !(timeout/1000)
1077             timeout = getSchedulingTimeout();
1078         }
1079         controlReceptionService();
1080         controlTransmissionService();
1081         microtimeout_t maxWait =
1082             timeval2microtimeout(getRTCPCheckInterval());
1083         // make sure the scheduling timeout is
1084         // <= the check interval for RTCP
1085         // packets
1086         timeout = (timeout > maxWait)? maxWait : timeout;
1087         if ( timeout < 1000 ) { // !(timeout/1000)
1088             dispatchDataPacket();
1089             timerTick();
1090         } else {
1091             if ( isPendingData(timeout/1000) ) {
1092                 takeInDataPacket();
1093             }
1094             timeout = 0;
1095         }
1096     }
1097     dispatchBYE("GNU ccRTP stack finishing.");
1098         Thread::exit();
1099 }
1100 
1101 #endif
1102 
takeInDataPacket(void)1103 inline size_t takeInDataPacket(void)
1104 {return TRTPSessionBaseIPV6<RTPDataChannel,RTCPChannel,ServiceQueue>::takeInDataPacket();}
1105 
dispatchBYE(const std::string & str)1106 inline size_t dispatchBYE(const std::string &str)
1107 {return TRTPSessionBaseIPV6<RTPDataChannel,RTCPChannel,ServiceQueue>::dispatchBYE(str);}
1108 };
1109 
1110 /**
1111  * @typedef RTPSession
1112  *
1113  * Uses two pairs of sockets for RTP data and RTCP
1114  * transmission/reception.
1115  *
1116  * @short UDP/IPv6 RTP Session scheduled by one thread of execution.
1117  **/
1118 typedef SingleThreadRTPSessionIPV6<> RTPSessionIPV6;
1119 
1120 /**
1121  * @typedef RTPSocket
1122  *
1123  * Alias for RTPSession.
1124  **/
1125 typedef RTPSessionIPV6 RTPSocketIPV6;
1126 
1127 /**
1128  * @typedef SymmetricRTPSession
1129  *
1130  * Uses one pair of sockets, (1) for RTP data and (2) for RTCP
1131  * transmission/reception.
1132  *
1133  * @short Symmetric UDP/IPv6 RTP session scheduled by one thread of execution.
1134  **/
1135  typedef SingleThreadRTPSessionIPV6<SymmetricRTPChannelIPV6,
1136                     SymmetricRTPChannelIPV6> SymmetricRTPSessionIPV6;
1137 
1138 
1139 #endif
1140 
1141 /** @}*/ // sessions
1142 
1143 END_NAMESPACE
1144 
1145 #endif  //CCXX_RTP_RTP_H_
1146 
1147 /** EMACS **
1148  * Local variables:
1149  * mode: c++
1150  * c-basic-offset: 8
1151  * End:
1152  */
1153