Coverage Report

Created: 2025-11-05 06:27

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/resiprocate/resip/stack/Transport.cxx
Line
Count
Source
1
#if defined(HAVE_CONFIG_H)
2
#include "config.h"
3
#endif
4
5
#include <iostream>
6
7
#if defined(HAVE_SYS_SOCKIO_H)
8
#include <sys/sockio.h>
9
#endif
10
11
#include "rutil/Socket.hxx"
12
#include "rutil/DnsUtil.hxx"
13
#include "rutil/Logger.hxx"
14
#include "rutil/ParseBuffer.hxx"
15
16
#include "resip/stack/ConnectionTerminated.hxx"
17
#include "resip/stack/KeepAlivePong.hxx"
18
#include "resip/stack/Transport.hxx"
19
#include "resip/stack/SipMessage.hxx"
20
#include "resip/stack/TransportFailure.hxx"
21
#include "resip/stack/Helper.hxx"
22
#include "resip/stack/SendData.hxx"
23
#include "rutil/WinLeakCheck.hxx"
24
25
using namespace resip;
26
using namespace std;
27
28
#define RESIPROCATE_SUBSYSTEM Subsystem::TRANSPORT
29
30
void
31
Transport::setSipMessageLoggingHandler(std::shared_ptr<SipMessageLoggingHandler> handler)
32
0
{
33
0
   mSipMessageLoggingHandlers.clear();
34
35
0
   if (handler)
36
0
   {
37
0
      mSipMessageLoggingHandlers.push_back(handler);
38
0
   }
39
0
}
40
41
void
42
Transport::addSipMessageLoggingHandler(std::shared_ptr<SipMessageLoggingHandler> handler)
43
0
{
44
0
   if (handler)
45
0
   {
46
0
      mSipMessageLoggingHandlers.push_back(handler);
47
0
   }
48
0
}
49
50
void
51
Transport::setSipMessageLoggingHandlers(const SipMessageLoggingHandlerList& handlers)
52
0
{
53
0
   mSipMessageLoggingHandlers = handlers;
54
0
}
55
56
void
57
Transport::unsetSipMessageLoggingHandler() noexcept
58
0
{
59
0
   mSipMessageLoggingHandlers.clear();
60
0
}
61
62
Transport::SipMessageLoggingHandlerList
63
Transport::getSipMessageLoggingHandlers() const noexcept
64
0
{
65
0
   return mSipMessageLoggingHandlers;
66
0
}
67
68
Transport::Exception::Exception(const Data& msg, const Data& file, const int line) :
69
0
   BaseException(msg,file,line)
70
0
{
71
0
}
72
73
Transport::Transport(Fifo<TransactionMessage>& rxFifo,
74
                     const GenericIPAddress& address,
75
                     const Data& tlsDomain,
76
                     AfterSocketCreationFuncPtr socketFunc,
77
                     Compression &compression) :
78
0
   mTuple(address),
79
0
   mCongestionManager(nullptr),
80
0
   mStateMachineFifo(rxFifo, 8),
81
0
   mShuttingDown(false),
82
0
   mTlsDomain(tlsDomain),
83
0
   mSocketFunc(socketFunc),
84
0
   mCompression(compression),
85
0
   mTransportFlags(0)
86
0
{
87
#ifdef USE_NETNS
88
   // Needs to be implemented for NETNS
89
   resip_assert(0);
90
#endif
91
0
   mInterface = Tuple::inet_ntop(mTuple);
92
0
}
93
94
Transport::Transport(Fifo<TransactionMessage>& rxFifo,
95
                     int portNum,
96
                     IpVersion version,
97
                     const Data& intfc,
98
                     const Data& tlsDomain,
99
                     AfterSocketCreationFuncPtr socketFunc,
100
                     Compression &compression,
101
                     unsigned transportFlags,
102
                     const Data& netNs) :
103
0
   mInterface(intfc),
104
0
   mTuple(intfc, portNum, version, UNKNOWN_TRANSPORT, Data::Empty, netNs),
105
0
   mCongestionManager(nullptr),
106
0
   mStateMachineFifo(rxFifo,8),
107
0
   mShuttingDown(false),
108
0
   mTlsDomain(tlsDomain),
109
0
   mSocketFunc(socketFunc),
110
0
   mCompression(compression),
111
0
   mTransportFlags(transportFlags)
112
0
{
113
0
}
114
115
Transport::~Transport()
116
0
{
117
0
}
118
119
void
120
Transport::onReload()
121
0
{
122
0
}
123
124
void
125
Transport::error(int e)
126
0
{
127
0
   if (e != EAGAIN)
128
0
   {
129
0
      InfoLog(<< errorToString(e));
130
0
   }
131
0
}
132
133
Data
134
Transport::errorToString(int e)
135
0
{
136
0
   Data errorString;
137
0
   DataStream ds(errorString);
138
0
   switch (e)
139
0
   {
140
0
      case 0:
141
0
         ds << "None";
142
0
         break;
143
0
      case EAGAIN:
144
0
         ds << "No data ready to read: " << strerror(e);
145
0
         break;
146
0
      case EINTR:
147
0
         ds << "The call was interrupted by a signal before any data was read: " << strerror(e);
148
0
         break;
149
0
      case EIO:
150
0
         ds << "I/O error: " << strerror(e);
151
0
         break;
152
0
      case EBADF:
153
0
         ds << "fd is not a valid file descriptor or is not open for reading: " << strerror(e);
154
0
         break;
155
0
      case EINVAL:
156
0
         ds << "fd is attached to an object which is unsuitable for reading: " << strerror(e);
157
0
         break;
158
0
      case EFAULT:
159
0
         ds << "buf is outside your accessible address space: " << strerror(e);
160
0
         break;
161
162
#if defined(WIN32)
163
      case WSAENETDOWN:
164
         ds << "The network subsystem has failed.";
165
         break;
166
      case WSAEFAULT:
167
         ds << "The buf or from parameters are not part of the user address space, "
168
               "or the fromlen parameter is too small to accommodate the peer address.";
169
         break;
170
      case WSAEINTR:
171
         ds << "The (blocking) call was canceled through WSACancelBlockingCall.";
172
         break;
173
      case WSAEINPROGRESS:
174
         ds << "A blocking Windows Sockets 1.1 call is in progress, or the "
175
               "service provider is still processing a callback function.";
176
         break;
177
      case WSAEINVAL:
178
         ds << "The socket has not been bound with bind, or an unknown flag was specified, "
179
               "or MSG_OOB was specified for a socket with SO_OOBINLINE enabled, "
180
               "or (for byte stream-style sockets only) len was zero or negative.";
181
         break;
182
      case WSAEISCONN :
183
         ds << "The socket is connected. This function is not permitted with a connected socket, "
184
               "whether the socket is connection-oriented or connectionless.";
185
         break;
186
      case WSAENETRESET:
187
         ds << "The connection has been broken due to the keep-alive activity "
188
               "detecting a failure while the operation was in progress.";
189
         break;
190
      case WSAENOTSOCK:
191
         ds << "The descriptor is not a socket.";
192
         break;
193
      case WSAEOPNOTSUPP:
194
         ds << " MSG_OOB was specified, but the socket is not stream-style such as type "
195
               "SOCK_STREAM, OOB data is not supported in the communication domain associated with this socket, "
196
               "or the socket is unidirectional and supports only send operations.";
197
         break;
198
      case WSAESHUTDOWN:
199
         ds << "The socket has been shut down; it is not possible to recvfrom on a socket after "
200
               "shutdown has been invoked with how set to SD_RECEIVE or SD_BOTH.";
201
         break;
202
      case WSAEMSGSIZE:
203
         ds << "The message was too large to fit into the specified buffer and was truncated.";
204
         break;
205
      case WSAETIMEDOUT:
206
         ds << "The connection has been dropped, because of a network failure or because the "
207
               "system on the other end went down without notice.";
208
         break;
209
      case WSAECONNRESET :
210
         ds << "Connection reset.";
211
         break;
212
      case WSAEWOULDBLOCK:
213
         ds << "Would block.";
214
         break;
215
      case WSAEHOSTUNREACH:
216
         ds << "A socket operation was attempted to an unreachable host.";
217
         break;
218
      case WSANOTINITIALISED:
219
         ds << "Either the application has not called WSAStartup or WSAStartup failed. "
220
               "The application may be accessing a socket that the current active task does not own (that is, trying to share a socket between tasks),"
221
               "or WSACleanup has been called too many times.";
222
         break;
223
      case WSAEACCES:
224
         ds << "An attempt was made to access a socket in a way forbidden by its access permissions.";
225
         break;
226
      case WSAENOBUFS:
227
         ds << "An operation on a socket could not be performed because the system lacked sufficient "
228
               "buffer space or because a queue was full.";
229
         break;
230
      case WSAENOTCONN:
231
         ds << "A request to send or receive data was disallowed because the socket is not connected "
232
               "and (when sending on a datagram socket using sendto) no address was supplied.";
233
         break;
234
      case WSAECONNABORTED:
235
         ds << "An established connection was aborted by the software in your host computer, possibly "
236
               "due to a data transmission time-out or protocol error.";
237
         break;
238
      case WSAEADDRNOTAVAIL:
239
         ds << "The requested address is not valid in its context. This normally results from an attempt to "
240
               "bind to an address that is not valid for the local computer.";
241
         break;
242
      case WSAEAFNOSUPPORT:
243
         ds << "An address incompatible with the requested protocol was used.";
244
         break;
245
      case WSAEDESTADDRREQ:
246
         ds << "A required address was omitted from an operation on a socket.";
247
         break;
248
      case WSAENETUNREACH:
249
         ds << "A socket operation was attempted to an unreachable network.";
250
         break;
251
#endif
252
253
0
      default:
254
0
         ds << "Some other error (" << e << "): " << strerror(e);
255
0
         break;
256
0
   }
257
0
   ds.flush();
258
0
   return errorString;
259
0
}
260
261
void
262
Transport::flowTerminated(const Tuple& flow, TransportFailure::FailureReason failureReason, int failureSubCode, const Data& failureString, const std::list<Data> additionalFailureStrings)
263
0
{
264
0
   mStateMachineFifo.add(new ConnectionTerminated(flow, failureReason, failureSubCode, failureString, additionalFailureStrings));
265
0
}
266
267
void
268
Transport::keepAlivePong(const Tuple& flow)
269
0
{
270
0
   mStateMachineFifo.add(new KeepAlivePong(flow));
271
0
}
272
273
void
274
Transport::fail(const Data& tid, TransportFailure::FailureReason reason, int subCode)
275
0
{
276
0
   if (!tid.empty())
277
0
   {
278
0
      mStateMachineFifo.add(new TransportFailure(tid, reason, subCode));
279
0
   }
280
0
}
281
282
void 
283
Transport::setTcpConnectState(const Data& tid, TcpConnectState::State state)
284
0
{
285
0
    if (!tid.empty())
286
0
    {
287
0
        mStateMachineFifo.add(new TcpConnectState(tid, state));
288
0
    }
289
0
}
290
291
std::unique_ptr<SendData>
292
Transport::makeSendData( const Tuple& dest, const Data& d, const Data& tid, const Data &sigcompId)
293
0
{
294
0
   resip_assert(dest.getPort() != -1);
295
0
   std::unique_ptr<SendData> data(new SendData(dest, d, tid, sigcompId));
296
0
   return data;
297
0
}
298
299
void
300
Transport::makeFailedResponse(const SipMessage& msg,
301
                              int responseCode,
302
                              const char * warning)
303
0
{
304
0
  if (msg.isResponse()) return;
305
306
0
  const Tuple& dest = msg.getSource();
307
308
0
  std::unique_ptr<SipMessage> errMsg(Helper::makeResponse(msg,
309
0
                                                        responseCode,
310
0
                                                        warning ? warning : "Original request had no Vias"));
311
312
  // make send data here w/ blank tid and blast it out.
313
  // encode message
314
0
  Data encoded;
315
0
  encoded.clear();
316
0
  DataStream encodeStream(encoded);
317
0
  errMsg->encode(encodeStream);
318
0
  encodeStream.flush();
319
0
  resip_assert(!encoded.empty());
320
321
0
  InfoLog(<<"Sending response directly to " << dest << " : " << errMsg->brief() );
322
323
  // Calculate compartment ID for outbound message
324
0
  Data remoteSigcompId;
325
0
   setRemoteSigcompId(*errMsg,remoteSigcompId);
326
0
  send(makeSendData(dest, encoded, Data::Empty, remoteSigcompId));
327
0
}
328
329
std::unique_ptr<SendData>
330
Transport::make503(SipMessage& msg, uint16_t retryAfter)
331
0
{
332
0
  std::unique_ptr<SendData> result;
333
0
  if (msg.isResponse()) return result;
334
335
0
   try
336
0
   {
337
0
      if(msg.method()==ACK)
338
0
      {
339
0
         return result;
340
0
      }
341
0
   }
342
0
   catch(BaseException&)
343
0
   {
344
      // .bwc. Parse failed on the start-line. Stop.
345
0
      return result;
346
0
   }
347
   
348
0
  const Tuple& dest = msg.getSource();
349
350
   // Calculate compartment ID for outbound message
351
0
   Data remoteSigcompId;
352
0
   setRemoteSigcompId(msg,remoteSigcompId);
353
354
   // .bwc. msg is completely unverified. Handle with caution.
355
0
   result=makeSendData(dest, Data::Empty, Data::Empty, remoteSigcompId);
356
0
   static const Data retryAfterHeader("Retry-After: ");
357
0
   Data value(retryAfter);
358
0
   Helper::makeRawResponse(result->data, msg, 503, retryAfterHeader+value+"\r\n");
359
360
0
  return result;
361
0
}
362
363
std::unique_ptr<SendData>
364
Transport::make100(SipMessage& msg)
365
0
{
366
0
  std::unique_ptr<SendData> result;
367
0
  if (msg.isResponse()) return result;
368
369
0
   try
370
0
   {
371
0
      if(msg.method()==ACK)
372
0
      {
373
0
         return result;
374
0
      }
375
0
   }
376
0
   catch(BaseException&)
377
0
   {
378
      // .bwc. Parse failed on the start-line. Stop.
379
0
      return result;
380
0
   }
381
   
382
0
  const Tuple& dest = msg.getSource();
383
384
   // Calculate compartment ID for outbound message
385
0
   Data remoteSigcompId;
386
0
   setRemoteSigcompId(msg,remoteSigcompId);
387
388
   // .bwc. msg is completely unverified. Handle with caution.
389
0
   result=makeSendData(dest, Data::Empty, Data::Empty, remoteSigcompId);
390
0
   Helper::makeRawResponse(result->data, msg, 100);
391
392
0
   return result;
393
0
}
394
395
void
396
Transport::setRemoteSigcompId(SipMessage& msg, Data& remoteSigcompId)
397
0
{
398
0
   if (mCompression.isEnabled())
399
0
   {
400
0
      try
401
0
      {
402
0
         const Via &topVia(msg.const_header(h_Vias).front());
403
         
404
0
         if(topVia.exists(p_comp) && topVia.param(p_comp) == "sigcomp")
405
0
         {
406
0
            if (topVia.exists(p_sigcompId))
407
0
            {
408
0
               remoteSigcompId = topVia.param(p_sigcompId);
409
0
            }
410
0
            else
411
0
            {
412
               // XXX rohc-sigcomp-sip-03 says "sent-by",
413
               // but this should probably be "received" if present,
414
               // and "sent-by" otherwise.
415
               // XXX Also, the spec is ambiguous about whether
416
               // to include the port in this identifier.
417
0
               remoteSigcompId = topVia.sentHost();
418
0
            }
419
0
         }
420
0
      }
421
0
      catch(BaseException&)
422
0
      {
423
         // ?bwc? Couldn't grab sigcomp compartment id. We don't even know if
424
         // the initial request was using sigcomp or not. 
425
         // What should we do here?
426
0
      }
427
0
   }
428
0
}
429
430
void
431
Transport::stampReceived(SipMessage* message)
432
0
{
433
   // set the received= and rport= parameters in the message if necessary !jf!
434
0
   if (message->isRequest() && message->exists(h_Vias) && !message->const_header(h_Vias).empty())
435
0
   {
436
0
      const Tuple& tuple = message->getSource();
437
0
      Data received = Tuple::inet_ntop(tuple);
438
0
      if(message->const_header(h_Vias).front().sentHost() != received)  // only add if received address is different from sent-by in Via
439
0
      {
440
0
         message->header(h_Vias).front().param(p_received) = received;
441
0
      }
442
      //message->header(h_Vias).front().param(p_received) = Tuple::inet_ntop(tuple);
443
0
      if (message->const_header(h_Vias).front().exists(p_rport))
444
0
      {
445
0
         message->header(h_Vias).front().param(p_rport).port() = tuple.getPort();
446
0
      }
447
0
   }
448
0
   DebugLog (<< "incoming from: " << message->getSource());
449
0
   StackLog (<< endl << endl << *message);
450
0
}
451
452
bool
453
Transport::basicCheck(const SipMessage& msg)
454
0
{
455
0
   resip::Data reason;
456
0
   if (msg.isExternal())
457
0
   {
458
0
      try
459
0
      {
460
0
         if (!Helper::validateMessage(msg,&reason))
461
0
         {
462
0
            InfoLog(<<"Message Failed basicCheck :" << msg.brief());
463
0
            if (msg.isRequest() && msg.method()!=ACK )
464
0
            {
465
               // this is VERY low-level b/c we don't have a transaction...
466
               // here we make a response to warn the offending party.
467
0
               makeFailedResponse(msg,400,reason.c_str());
468
0
            }
469
0
            return false;
470
0
         }
471
0
         else if (mShuttingDown && msg.isRequest() && msg.method() != ACK)
472
0
         {
473
0
            InfoLog (<< "Server has been shutdown, reject message with 503");
474
            // this is VERY low-level b/c we don't have a transaction...
475
            // here we make a response to warn the offending party.
476
0
            makeFailedResponse(msg, 503, "Server has been shutdown");
477
0
            return false;
478
0
         }
479
0
      }
480
0
      catch (BaseException& e)
481
0
      {
482
0
         InfoLog (<< "Cannot make failure response to badly constructed message: " << e);
483
0
         return false;
484
0
      }
485
0
   }
486
0
   return true;
487
0
}
488
489
void
490
Transport::callSocketFunc(Socket sock)
491
0
{
492
0
   if (mSocketFunc)
493
0
   {
494
0
      mSocketFunc(sock, transport(), __FILE__, __LINE__);
495
0
   }
496
0
}
497
498
void
499
Transport::pushRxMsgUp(SipMessage* message)
500
0
{
501
0
   for(auto& handler : getSipMessageLoggingHandlers())
502
0
   {
503
0
       handler->inboundMessage(message->getSource(), message->getReceivedTransportTuple(), *message);
504
0
   }
505
506
0
   mStateMachineFifo.add(message);
507
0
}
508
509
bool
510
Transport::operator==(const Transport& rhs) const
511
0
{
512
0
   return ( ( mTuple.isV4() == rhs.isV4()) &&
513
0
            ( port() == rhs.port()) &&
514
0
            ( memcmp(&boundInterface(),&rhs.boundInterface(),mTuple.length()) == 0) );
515
0
}
516
517
EncodeStream&
518
resip::operator<<(EncodeStream& strm, const resip::Transport& rhs)
519
0
{
520
0
   strm << "Transport: " << rhs.mTuple;
521
0
   if (!rhs.mInterface.empty()) strm << " on " << rhs.mInterface;
522
0
   return strm;
523
0
}
524
525
/* ====================================================================
526
 * The Vovida Software License, Version 1.0
527
 *
528
 * Copyright (c) 2000 Vovida Networks, Inc.  All rights reserved.
529
 *
530
 * Redistribution and use in source and binary forms, with or without
531
 * modification, are permitted provided that the following conditions
532
 * are met:
533
 *
534
 * 1. Redistributions of source code must retain the above copyright
535
 *    notice, this list of conditions and the following disclaimer.
536
 *
537
 * 2. Redistributions in binary form must reproduce the above copyright
538
 *    notice, this list of conditions and the following disclaimer in
539
 *    the documentation and/or other materials provided with the
540
 *    distribution.
541
 *
542
 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
543
 *    and "Vovida Open Communication Application Library (VOCAL)" must
544
 *    not be used to endorse or promote products derived from this
545
 *    software without prior written permission. For written
546
 *    permission, please contact vocal@vovida.org.
547
 *
548
 * 4. Products derived from this software may not be called "VOCAL", nor
549
 *    may "VOCAL" appear in their name, without prior written
550
 *    permission of Vovida Networks, Inc.
551
 *
552
 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
553
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
554
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
555
 * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL VOVIDA
556
 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
557
 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
558
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
559
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
560
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
561
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
562
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
563
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
564
 * DAMAGE.
565
 *
566
 * ====================================================================
567
 *
568
 * This software consists of voluntary contributions made by Vovida
569
 * Networks, Inc. and many individuals on behalf of Vovida Networks,
570
 * Inc.  For more information on Vovida Networks, Inc., please see
571
 * <http://www.vovida.org/>.
572
 *
573
 * vi: set shiftwidth=3 expandtab:
574
 */