Coverage Report

Created: 2026-06-07 06:36

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