Coverage Report

Created: 2025-12-31 06:34

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/resiprocate/resip/stack/Transport.hxx
Line
Count
Source
1
#if !defined(RESIP_TRANSPORT_HXX)
2
#define RESIP_TRANSPORT_HXX
3
4
#include "rutil/BaseException.hxx"
5
#include "rutil/Data.hxx"
6
#include "rutil/FdSetIOObserver.hxx"
7
#include "rutil/ProducerFifoBuffer.hxx"
8
#include "resip/stack/TransportFailure.hxx"
9
#include "resip/stack/TcpConnectState.hxx"
10
#include "resip/stack/Tuple.hxx"
11
#include "resip/stack/NameAddr.hxx"
12
#include "resip/stack/Compression.hxx"
13
#include "resip/stack/SendData.hxx"
14
15
#include <list>
16
#include <memory>
17
#include <utility>
18
19
namespace resip
20
{
21
22
class TransactionMessage;
23
class SipMessage;
24
class Connection;
25
class Compression;
26
class FdPollGrp;
27
28
/**
29
 * TransportFlags is bit-mask that can be set when creating a transport.
30
 * All flags default to "off" to preserve "traditional" resip behavior.
31
 * Not all Transports support all flags. All options are experimental.
32
 * The flags are:
33
 * NOBIND:
34
 *    On transports that support it (TCP/TLS), do not bind a listening
35
 *    socket; thus no in-bound connections are possible. This can conserve
36
 *    ports and avoid port conflicts in pure-outbound (NAT'd) cases.
37
 * RXALL:
38
 *    When receiving from socket, read all possible messages before
39
 *    returning to event loop. This allows higher thruput. Without this flag,
40
 *    only one message is read at a time, which is slower over-all, but
41
 *    is more "even" and balanced.
42
 * TXALL:
43
 *    When transmitting to a socket, write all possible messages before
44
 *    returning to event loop. This allows higher thruput but burstier.
45
 * TXNOW:
46
 *    When a message to transmit is posted to Transport's transmit queue
47
 *    immediately try sending it. This should have less latency
48
 *    and less overhead with select/poll stuff, but will have deeper
49
 *    call stacks.
50
 * OWNTHREAD:
51
 *    Specifies whether this Transport object has its own thread (ie; if
52
 *    set, the TransportSelector should not run the select/poll loop for
53
 *    this transport, since that is another thread's job)
54
 */
55
#define RESIP_TRANSPORT_FLAG_NOBIND      (1<<0)
56
#define RESIP_TRANSPORT_FLAG_RXALL       (1<<1)
57
#define RESIP_TRANSPORT_FLAG_TXALL       (1<<2)
58
#define RESIP_TRANSPORT_FLAG_TXNOW       (1<<4)
59
#define RESIP_TRANSPORT_FLAG_OWNTHREAD   (1<<5)
60
61
/**
62
   @brief The base class for Transport classes.
63
64
   A Transport presents layer 4 of the OSI model, the transport layer.
65
   For IP-based protocols, this means that a Transport object has an
66
   IP address (v4 or v6), a transport layer protocol (UDP or TCP/TLS),
67
   and a port number.  These are managed through the Transport's Tuple
68
   member.
69
70
*/
71
class Transport : public FdSetIOObserver
72
{
73
   public:
74
75
      class SipMessageLoggingHandler
76
      {
77
      public:
78
          SipMessageLoggingHandler() = default;
79
          SipMessageLoggingHandler(const SipMessageLoggingHandler&) = delete;
80
          SipMessageLoggingHandler(SipMessageLoggingHandler&&) = delete;
81
          virtual ~SipMessageLoggingHandler() = default;
82
83
          SipMessageLoggingHandler& operator=(const SipMessageLoggingHandler&) = delete;
84
          SipMessageLoggingHandler& operator=(SipMessageLoggingHandler&&) = delete;
85
86
          virtual void outboundMessage(const Tuple &source, const Tuple &destination, const SipMessage &msg) = 0;
87
          // Note:  retransmissions store already encoded messages, so callback doesn't send SipMessage it sends
88
          //        the encoded version of the SipMessage instead.  If you need a SipMessage you will need to
89
          //        re-parse back into a SipMessage in the callback handler.
90
0
          virtual void outboundRetransmit(const Tuple &source, const Tuple &destination, const SendData &data) {}
91
          virtual void inboundMessage(const Tuple& source, const Tuple& destination, const SipMessage &msg) = 0;
92
      };
93
94
      using SipMessageLoggingHandlerList = std::vector<std::shared_ptr<SipMessageLoggingHandler> >;
95
96
      void setSipMessageLoggingHandler(std::shared_ptr<SipMessageLoggingHandler> handler);
97
      void addSipMessageLoggingHandler(std::shared_ptr<SipMessageLoggingHandler> handler);
98
      void setSipMessageLoggingHandlers(const SipMessageLoggingHandlerList& handlers);
99
      void unsetSipMessageLoggingHandler() noexcept;
100
      SipMessageLoggingHandlerList getSipMessageLoggingHandlers() const noexcept;
101
102
      /**
103
         @brief General exception class for Transport.
104
105
         This would be thrown if there was an attempt to bind to a port
106
         that is already in use.
107
      */
108
      class Exception final : public BaseException
109
      {
110
         public:
111
            Exception(const Data& msg, const Data& file, int line);
112
0
            const char* name() const noexcept override { return "TransportException"; }
113
      };
114
      
115
      /**
116
         @param rxFifo the TransactionMessage Fifo that will receive
117
         any ConnectionTerminated or TransportFailure messages.
118
      
119
         @param tlsDomain the domain name of the Transport
120
      
121
         @param socketFunc subclassers can call this function after
122
         the socket is created.  This is not currently used by
123
         Transport.
124
      */
125
      Transport(Fifo<TransactionMessage>& rxFifo, 
126
                const GenericIPAddress& address,
127
                const Data& tlsDomain = Data::Empty, // !dcm! where is this used?
128
                AfterSocketCreationFuncPtr socketFunc = nullptr,
129
                Compression &compression = Compression::Disabled
130
         );
131
132
      /**
133
         @param rxFifo the TransactionMessage Fifo that will receive
134
         any ConnectionTerminated or TransportFailure messages.
135
      
136
         @param interfaceObj a "presentation format" representation
137
         of the IP address of this transport
138
         @see Tuple::inet_ntop() for information about "presentation
139
         format"
140
      
141
         @param portNum is the port to receive and/or send on
142
      
143
         @param tlsDomain the domain name of the Transport
144
145
         @todo Note that because of InternalTransport's constructor,
146
         tlsDomain is always set to Data::Empty at construction time,
147
         in practice.
148
      
149
         @param socketFunc subclassers can call this function after
150
         the socket is created.  This is not currently used by
151
         Transport.
152
      */
153
      Transport(Fifo<TransactionMessage>& rxFifo, 
154
                int portNum, 
155
                IpVersion version, 
156
                const Data& interfaceObj,
157
                const Data& tlsDomain = Data::Empty,
158
                AfterSocketCreationFuncPtr socketFunc = nullptr,
159
                Compression &compression = Compression::Disabled,
160
                unsigned transportFlags = 0,
161
                const Data& netNs = Data::Empty);
162
163
      virtual ~Transport();
164
165
      virtual void onReload();
166
167
      /**
168
         @note Subclasses override this method by checking whether
169
         there are unprocessed messages on the TransactionMessage
170
         Fifo (that was passed in to the constructor).
171
      */
172
      virtual bool isFinished() const=0;
173
      
174
      std::unique_ptr<SendData> makeSendData( const Tuple& tuple, const Data& data, const Data& tid, const Data &sigcompId = Data::Empty);
175
      
176
      /**
177
         @todo !bwc! What we do with a SendData is flexible. It might make a
178
         copy, or send synchronously, or convert to another type,
179
         etc.
180
181
         @todo !bch! Should this be protected and not public?
182
               !bwc! TransportSelector uses this directly for retransmissions.
183
      */
184
      virtual void send(std::unique_ptr<SendData> data)=0;
185
186
      /**
187
         Called when a writer is done adding messages to the TxFifo; this is
188
         used to interrupt the select call if the Transport is running in its
189
         own thread. This does nothing if select is not currently blocking, so
190
         don't bother calling this from the same thread that selects on this
191
         Transport's fds. Default impl is a no-op.
192
      */
193
0
      virtual void poke(){};
194
195
      /**
196
         If there is work to do, this is the method that does it. If
197
         the socket is readable, it is read.  If the socket is
198
         writable and there are outgoing messages to be sent, they are
199
         sent.
200
201
         Incoming messages are parsed and dispatched to the relevant
202
         entity.  SIP messages will be posted to the
203
         TransactionMessage Fifo.
204
205
         @see sendData()
206
207
         @param fdset is the FdSet after select() has been called.
208
         @see FdSet::select()
209
      */
210
      virtual void process(FdSet& fdset) = 0;
211
212
      /**
213
         Adds the Transport's socket FD to the appropriate read or
214
         write sets as applicable.
215
      */
216
      virtual void buildFdSet( FdSet& fdset) =0;
217
218
0
      virtual unsigned int getTimeTillNextProcessMS(){return UINT_MAX;}
219
220
      /**
221
         Version of process to be invoked periodically when using callback-based 
222
         IO (via FdPollGrp).
223
      */
224
      virtual void process() = 0;
225
226
      virtual void setPollGrp(FdPollGrp *grp) = 0;
227
228
      /**
229
         Posts a ConnectionTerminated message to TransactionMessage
230
         Fifo.
231
      */
232
      void flowTerminated(const Tuple& flow, 
233
                          TransportFailure::FailureReason failureReason, 
234
                          int failureSubCode, 
235
                          const Data& failureString, 
236
                          const std::list<Data> additionalFailureStrings);
237
      void keepAlivePong(const Tuple& flow);
238
239
      /**
240
         Posts a TransportFailure to the TransactionMessage Fifo.
241
      */
242
      void fail(const Data& tid,
243
                TransportFailure::FailureReason reason = TransportFailure::Failure,
244
                int subCode = 0);
245
246
      /**
247
         Posts a TcpConnectState to the TransactionMessage Fifo.
248
      */
249
      void setTcpConnectState(const Data& tid, TcpConnectState::State state);
250
251
      /**
252
         Generates a generic log for the platform specific socket
253
         error number.
254
255
         @param e the socket error number
256
      */
257
      static void error(int e);
258
      static Data errorToString(int e);
259
260
      // These methods are used by the TransportSelector
261
0
      const Data& interfaceName() const { return mInterface; }
262
263
0
      int port() const { return mTuple.getPort(); } 
264
    
265
      /// @deprecated use ipVersion()
266
0
      bool isV4() const { return mTuple.isV4(); } // !dcm! -- deprecate ASAP
267
268
0
      IpVersion ipVersion() const { return mTuple.ipVersion(); }
269
    
270
      /**
271
         @return the domain name that will be used for TLS, to, for
272
         example, find the certificate to present in the TLS
273
         handshake.
274
      */
275
0
      const Data& tlsDomain() const { return mTlsDomain; }
276
0
      const sockaddr& boundInterface() const { return mTuple.getSockaddr(); }
277
0
      const Tuple& getTuple() const { return mTuple; }
278
    
279
      /// @return This transport's TransportType.
280
0
      const TransportType transport() const { return mTuple.getType(); }
281
      virtual bool isReliable() const =0;
282
      virtual bool isDatagram() const =0;
283
284
      /// @return net namespace in which Transport is bound
285
0
      const Data& netNs() const { return(mTuple.getNetNs()); }
286
287
      /**
288
         @return true here if the subclass has a specific contact
289
         value that it wishes the TransportSelector to use.
290
      */
291
0
      virtual bool hasSpecificContact() const { return false; }
292
293
      /**
294
         Perform basic sanity checks on message. Return false
295
         if there is a problem eg) no Vias.
296
297
         @note --SIDE EFFECT-- This will queue a response if it CAN
298
         for a via-less request. Response will go straight into the
299
         TxFifo
300
      */
301
      bool basicCheck(const SipMessage& msg);
302
303
      void makeFailedResponse(const SipMessage& msg,
304
                              int responseCode = 400,
305
                              const char * warning = nullptr);
306
      std::unique_ptr<SendData> make503(SipMessage& msg,
307
                                      uint16_t retryAfter);
308
309
      std::unique_ptr<SendData> make100(SipMessage& msg);
310
      void setRemoteSigcompId(SipMessage&msg, Data& id);
311
      // mark the received= and rport parameters if necessary
312
      static void stampReceived(SipMessage* request);
313
314
      /**
315
         Returns true if this Transport should be included in the
316
         FdSet processing loop, false if the Transport will provide
317
         its own cycles.  If the Transport is going to provide its own
318
         cycles, the startOwnProcessing() and shutdown() will be
319
         called to tell the Transport when to process.
320
      
321
         @retval true will run in the SipStack's processing context
322
         @retval false provides own cycles, just puts messages in rxFifo
323
      */
324
      virtual bool shareStackProcessAndSelect() const=0;
325
326
      /**
327
         transports that returned false to
328
         shareStackProcessAndSelect() shouldn't put messages into the
329
         fifo until this is called
330
       
331
         @todo ?dcm? avoid the received a message but haven't added a
332
         transport to the TransportSelector race, but this might not
333
         be necessary.
334
      */
335
      virtual void startOwnProcessing()=0;
336
337
      /// only applies to transports that shareStackProcessAndSelect 
338
      virtual bool hasDataToSend() const = 0;
339
      
340
      /**
341
         This starts shutting-down procedures for this Transport.  New
342
         requests may be denied while "mShuttingDown" is true.
343
         
344
         Overriding implementations should chain through to this.
345
       
346
         @todo ?dcm? pure virtual protected method to enforce this?
347
         @see basicCheck()
348
         @see isFinished()
349
      */
350
      virtual void shutdown()
351
0
      {
352
         // !jf! should use the fifo to pass this in
353
0
         mShuttingDown = true;
354
0
      }
355
0
      virtual bool isShuttingDown() { return mShuttingDown; }
356
357
      // also used by the TransportSelector.
358
      // requires that the two transports be
359
      bool operator==(const Transport& rhs) const;
360
361
      //# queued messages on this transport
362
      virtual unsigned int getFifoSize() const=0;
363
364
      void callSocketFunc(Socket sock);
365
      virtual void invokeAfterSocketCreationFunc() const = 0;  //used to invoke the after socket creation func immediately for all existing sockets - can be used to modify QOS settings at runtime
366
367
      virtual void setCongestionManager(CongestionManager* manager)
368
0
      {
369
0
         mCongestionManager=manager;
370
0
      }
371
372
      CongestionManager::RejectionBehavior getRejectionBehaviorForIncoming() const
373
0
      {
374
0
         if(mCongestionManager)
375
0
         {
376
0
            return mCongestionManager->getRejectionBehavior(&mStateMachineFifo.getFifo());
377
0
         }
378
0
         return CongestionManager::NORMAL;
379
0
      }
380
381
      void flushStateMacFifo()
382
0
      {
383
0
          mStateMachineFifo.flush();
384
0
      }
385
386
      uint32_t getExpectedWaitForIncoming() const
387
0
      {
388
0
         return (uint32_t)mStateMachineFifo.getFifo().expectedWaitTimeMilliSec()/1000;
389
0
      }
390
391
      // called by Connection to deliver a received message
392
      virtual void pushRxMsgUp(SipMessage* msg);
393
394
      // set the receive buffer length (SO_RCVBUF)
395
0
      virtual void setRcvBufLen(int buflen) { }; // make pure?
396
397
0
      inline unsigned int getKey() const {return mTuple.mTransportKey;} 
398
0
      inline void setKey(unsigned int pKey) { mTuple.mTransportKey = pKey;} // should only be called once after creation
399
400
   protected:
401
402
      Data mInterface;
403
      Tuple mTuple;
404
405
      CongestionManager* mCongestionManager;
406
      ProducerFifoBuffer<TransactionMessage> mStateMachineFifo; // passed in
407
      bool mShuttingDown;
408
409
0
      void setTlsDomain(const Data& domain) { mTlsDomain = domain; }
410
   private:
411
      static const Data transportNames[MAX_TRANSPORT];
412
      friend EncodeStream& operator<<(EncodeStream& strm, const Transport& rhs);
413
414
      Data mTlsDomain;
415
      SipMessageLoggingHandlerList mSipMessageLoggingHandlers;
416
417
   protected:
418
      AfterSocketCreationFuncPtr mSocketFunc;
419
      Compression &mCompression;
420
      unsigned mTransportFlags;
421
};
422
423
EncodeStream& operator<<(EncodeStream& strm, const Transport& rhs);
424
425
}
426
427
#endif
428
429
/* ====================================================================
430
 * The Vovida Software License, Version 1.0
431
 *
432
 * Copyright (c) 2000 Vovida Networks, Inc.  All rights reserved.
433
 *
434
 * Redistribution and use in source and binary forms, with or without
435
 * modification, are permitted provided that the following conditions
436
 * are met:
437
 *
438
 * 1. Redistributions of source code must retain the above copyright
439
 *    notice, this list of conditions and the following disclaimer.
440
 *
441
 * 2. Redistributions in binary form must reproduce the above copyright
442
 *    notice, this list of conditions and the following disclaimer in
443
 *    the documentation and/or other materials provided with the
444
 *    distribution.
445
 *
446
 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
447
 *    and "Vovida Open Communication Application Library (VOCAL)" must
448
 *    not be used to endorse or promote products derived from this
449
 *    software without prior written permission. For written
450
 *    permission, please contact vocal@vovida.org.
451
 *
452
 * 4. Products derived from this software may not be called "VOCAL", nor
453
 *    may "VOCAL" appear in their name, without prior written
454
 *    permission of Vovida Networks, Inc.
455
 *
456
 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
457
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
458
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
459
 * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL VOVIDA
460
 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
461
 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
462
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
463
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
464
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
465
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
466
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
467
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
468
 * DAMAGE.
469
 *
470
 * ====================================================================
471
 *
472
 * This software consists of voluntary contributions made by Vovida
473
 * Networks, Inc. and many individuals on behalf of Vovida Networks,
474
 * Inc.  For more information on Vovida Networks, Inc., please see
475
 * <http://www.vovida.org/>.
476
 *
477
 * vi: set shiftwidth=3 expandtab:
478
 */