reSIProcate
SIP stack, Dialog Usage Manager and related libraries
Loading...
Searching...
No Matches
HepAgent.cxx
Go to the documentation of this file.
1#if defined(HAVE_CONFIG_H)
2#include "config.h"
3#endif
4
5#include <stdexcept>
6#include <utility>
7
8#include "rutil/rtcp/re_rtp.h"
9
12#include "rutil/DnsUtil.hxx"
13#include "rutil/DataStream.hxx"
14#include "rutil/Logger.hxx"
15
16using namespace resip;
17using namespace std;
18
19#define RESIPROCATE_SUBSYSTEM Subsystem::EEP
20
21HepAgent::HepAgent(const Data &captureHost, int capturePort, int captureAgentID)
22 : mCaptureHost(captureHost), mCapturePort(capturePort), mCaptureAgentID(captureAgentID)
23{
24 bool initV4Socket = true;
25 struct sockaddr_storage myaddr;
26 memset(&myaddr, 0, sizeof(myaddr));
27 int sockaddrlen;
28#ifdef USE_IPV6
29 if (!DnsUtil::isIpV4Address(captureHost))
30 {
31 initV4Socket = false;
32
33 struct sockaddr_in6* myaddrv6 = (struct sockaddr_in6*)&myaddr;
34 sockaddrlen = sizeof(struct sockaddr_in6);
35 myaddrv6->sin6_family = AF_INET6;
36 myaddrv6->sin6_addr = in6addr_any; // FIXME - make it configurable
37 myaddrv6->sin6_port = 0; // FIXME - make it configurable
38 mSocket = ::socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
39
40 int no = 0;
41#if !defined(WIN32)
42 ::setsockopt(mSocket, IPPROTO_IPV6, IPV6_V6ONLY, &no, sizeof(no));
43#else
44 // Note: On linux this allows the IPV6 socket to send to V4 destination, however this doesn't
45 // appear to work on windows. The sendTo call in sendToHOMER ends up return 10014
46 // (The system detected an invalid pointer address in attempting to use a pointer argument in a call.)
47 // The above call to isIpV4Address was added to address this.
48 ::setsockopt(mSocket, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&no, sizeof(no));
49#endif
50 }
51
52#endif // USE_IPV6
53
54 if (initV4Socket)
55 {
56 struct sockaddr_in* myaddrv4 = (struct sockaddr_in*)&myaddr;
57 sockaddrlen = sizeof(struct sockaddr_in);
58 myaddrv4->sin_family = AF_INET;
59 myaddrv4->sin_addr.s_addr = INADDR_ANY; // FIXME - make it configurable
60 myaddrv4->sin_port = 0; // FIXME - make it configurable
61
62 mSocket = ::socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
63 }
64
65 if(mSocket < 0)
66 {
67 ErrLog(<<"Failed to create socket");
68 throw std::runtime_error("Failed to create socket");
69 }
70
71 // make it non-blocking
72 // FIXME - HEP messages are lost if the transmit buffer fills up
73 // Messages should be queued and sent as part of the main loop
74 if(!makeSocketNonBlocking(mSocket))
75 {
76 ErrLog(<<"Failed to set O_NONBLOCK");
77 throw std::runtime_error("Failed to set O_NONBLOCK");
78 }
79
80 if(::bind(mSocket, (struct sockaddr*)&myaddr, sockaddrlen) < 0)
81 {
82 ErrLog(<<"bind failed");
83 throw std::runtime_error("bind failed");
84 }
85
86 // create destination Tuple
87 struct addrinfo *rset;
88 if(getaddrinfo(mCaptureHost.c_str(), 0, 0, &rset) != 0)
89 {
90 ErrLog(<<"getaddrinfo failed");
91 throw std::runtime_error("getaddrinfo failed");
92 }
93 if(rset == 0)
94 {
95 ErrLog(<<"no results from getaddrinfo");
96 throw std::runtime_error("no results from getaddrinfo");
97 }
98 const struct addrinfo& dest = rset[0];
99 switch(dest.ai_family)
100 {
101 case AF_INET:
102 memcpy(&mDestination.v4Address, dest.ai_addr, dest.ai_addrlen);
103 mDestination.v4Address.sin_port = htons(mCapturePort);
104 break;
105#ifdef IPPROTO_IPV6
106 case AF_INET6:
107 memcpy(&mDestination.v6Address, dest.ai_addr, dest.ai_addrlen);
108 mDestination.v6Address.sin6_port = htons(mCapturePort);
109 break;
110#endif
111 default:
112 ErrLog(<<"unsupported address family");
113 throw std::runtime_error("unsupported address family");
114 }
115 freeaddrinfo(rset);
116 InfoLog(<<"HEP capture agent ready to send to " << mDestination);
117}
118
122
123inline int32_t
124ntoh_cpl(const void *x)
125{
126 unsigned char c[4];
127 uint32_t *v = reinterpret_cast<uint32_t *>(c);
128
129 memcpy(c, x, 4);
130
131 // replace the fraction lost (8 bits) by sign of the 24 bit value
132 c[0] = (c[1] & 0x80) ? 0xff : 0;
133
134 return (int32_t)(ntohl(*v));
135}
136
137void
138encodeRRvec(DataStream& stream, const struct rtcp_rr *rr_vec, int rrCount)
139{
140 stream << "\"report_blocks\":[";
141
142 for(int i = 0 ; i < rrCount; i++)
143 {
144 const struct rtcp_rr *rr = &rr_vec[i];
145 stream << ((i>0) ? "," : "")
146 << "{"
147 << "\"source_ssrc\":" << ntohl(rr->ssrc) << ","
148 << "\"highest_seq_no\":" << ntohl(rr->last_seq) << ","
149 << "\"fraction_lost\":" << +(reinterpret_cast<const uint8_t *>(&rr->fraction_lost_32))[0] << "," // 8 bits
150 << "\"ia_jitter\":" << ntohl(rr->jitter) << ","
151 << "\"packets_lost\":" << ntoh_cpl(&rr->fraction_lost_32) << ","
152 << "\"lsr\":" << ntohl(rr->lsr) << ","
153 << "\"dlsr\":" << ntohl(rr->dlsr)
154 << "}";
155 }
156
157 stream << "],\"report_count\":" << rrCount;
158}
159
160Data
162{
163 const uint8_t* raw = reinterpret_cast<const uint8_t*>(rtcpRaw.data());
164 const struct rtcp_msg* msg = reinterpret_cast<const struct rtcp_msg*>(rtcpRaw.data());
165
166 StackLog(<< "buffer size: " << rtcpRaw.size());
167 resip_assert(rtcpRaw.size() >= 8);
168
169 if(rtcpRaw.size() < 8)
170 {
171 ErrLog(<<"too small to be a valid RTCP packet");
172 return "";
173 }
174 // FIXME - check size more carefully depending on the type of RTCP packet
175
176 // FIXME - check for multiple RTCP packets in a single UDP datagram
177 // - does HOMER require these to be submitted as separate HEP messages?
178
179 Data json;
180 DataStream stream(json);
181
182#ifdef RTCP_TRUST_BIT_FIELD_ORDER
183 unsigned int version = msg->hdr.version;
184 unsigned int rrCount = msg->hdr.count;
185 bool p = msg->hdr.p;
186#else
187 // we can't trust the order of bit-fields in a struct
188 // on all compilers and platforms to match the order
189 // on the wire
190 uint8_t byte0 = raw[0];
191 unsigned int version = (byte0 & 0xc0) >> 6;
192 unsigned int rrCount = (byte0 & 0x1f);
193 bool p = (byte0 & 0x20) >> 5;
194#endif
195 unsigned int pt = msg->hdr.pt;
196
197 StackLog(<<"RTCP version: " << version << " p " << p
198 << " RR count: " << rrCount
199 << " packet type: " << pt
200 << " length: " << (ntohs(msg->hdr.length)*2) << " bytes");
201
202 resip_assert(version == 2);
203 if(version != 2)
204 {
205 ErrLog(<<"unsupported RTCP version: " << version);
206 return "";
207 }
208
209 stream << "{" << "\"type\":" << pt << ",";
210
211 const struct rtcp_rr *rr;
212 switch (pt)
213 {
214 case RTCP_SR:
215 stream << "\"sender_information\":{"
216 << "\"ntp_timestamp_sec\":" << ntohl(msg->r.sr.ntp_sec) << ","
217 << "\"ntp_timestamp_usec\":" << ntohl(msg->r.sr.ntp_frac) << ","
218 << "\"octets\":" << ntohl(msg->r.sr.osent) << ","
219 << "\"rtp_timestamp\":" << ntohl(msg->r.sr.rtp_ts) << ","
220 << "\"packets\":" << ntohl(msg->r.sr.psent)
221 << "},"
222 << "\"ssrc\":" << ntohl(msg->r.sr.ssrc) << ",";
223 rr = reinterpret_cast<const struct rtcp_rr*>(&msg->r.sr.rrv);
224 encodeRRvec(stream, rr, rrCount);
225 break;
226
227 case RTCP_RR:
228 stream << "\"ssrc\":" << ntohl(msg->r.rr.ssrc) << ",";
229 rr = reinterpret_cast<const struct rtcp_rr*>(&msg->r.rr.rrv);
230 encodeRRvec(stream, rr, rrCount);
231 break;
232
233 default:
234 WarningLog(<<"unhandled RTCP packet type: " << pt);
235 }
236
237 stream << "}";
238 stream.flush();
239
240 return json;
241}
242
243void
244HepAgent::sendRTCP(const TransportType type, const GenericIPAddress& source, const GenericIPAddress& destination, const Data& rtcpRaw, const Data& correlationId)
245{
246 Data json(convertRTCPtoJSON(rtcpRaw));
247
248 StackLog(<< "source: " << source
249 << " destination: " << destination
250 << " constructed RTCP JSON: " << json);
251
252 sendToHOMER<Data>(resip::UDP,
253 source, destination,
255 correlationId);
256}
257
258bool
259HepAgent::sendToWire(const Data& buf) const
260{
261 return sendto(mSocket, buf.data(), (int)buf.size(), 0, &mDestination.address, (int)mDestination.length()) < 0;
262}
263
264/* ====================================================================
265 *
266 * Copyright (c) 2022, Software Freedom Institute https://softwarefreedom.institute
267 * Copyright (c) 2021-2022, Daniel Pocock https://danielpocock.com
268 *
269 * Redistribution and use in source and binary forms, with or without
270 * modification, are permitted provided that the following conditions
271 * are met:
272 *
273 * 1. Redistributions of source code must retain the above copyright
274 * notice, this list of conditions and the following disclaimer.
275 *
276 * 2. Redistributions in binary form must reproduce the above copyright
277 * notice, this list of conditions and the following disclaimer in
278 * the documentation and/or other materials provided with the
279 * distribution.
280 *
281 * 3. Neither the name of the author(s) nor the names of any contributors
282 * may be used to endorse or promote products derived from this software
283 * without specific prior written permission.
284 *
285 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTORS "AS IS" AND
286 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
287 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
288 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTORS BE LIABLE
289 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
290 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
291 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
292 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
293 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
294 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
295 * SUCH DAMAGE.
296 *
297 * ====================================================================
298 *
299 *
300 */
void encodeRRvec(DataStream &stream, const struct rtcp_rr *rr_vec, int rrCount)
Definition HepAgent.cxx:138
int32_t ntoh_cpl(const void *x)
Definition HepAgent.cxx:124
#define StackLog(args_)
Definition Logger.hxx:125
#define InfoLog(args_)
Definition Logger.hxx:131
#define WarningLog(args_)
Definition Logger.hxx:134
#define ErrLog(args_)
Definition Logger.hxx:137
#define resip_assert(x)
This file needs to work for both C and C++ code.
An iostream that operates on an existing Data.
An alternative to std::string, encapsulates an arbitrary buffer of bytes.
Definition Data.hxx:90
const char * c_str() const
Returns a null-terminated string representing.
Definition Data.cxx:1097
size_type size() const noexcept
Returns the number of bytes in this Data.
Definition Data.hxx:599
const char * data() const noexcept
Returns a pointer to the contents of this Data.
Definition Data.hxx:608
static bool isIpV4Address(const Data &ipAddress)
Definition DnsUtil.cxx:290
HepAgent(const Data &captureHost, int capturePort, int captureAgentID)
Definition HepAgent.cxx:21
virtual Data convertRTCPtoJSON(const Data &rtcpRaw)
Definition HepAgent.cxx:161
virtual ~HepAgent()
Definition HepAgent.cxx:119
void sendRTCP(const TransportType type, const GenericIPAddress &source, const GenericIPAddress &destination, const Data &rtcpRaw, const Data &correlationId)
Definition HepAgent.cxx:244
virtual bool sendToWire(const Data &buf) const
Definition HepAgent.cxx:259
dcm! – add UnusedChecking(_enum) below;
TransportType
An enumeration of transport protocols.
bool makeSocketNonBlocking(Socket fd)
Definition Socket.cxx:21
unsigned char uint8_t
Definition Stun.hxx:29
Interface to Real-time Transport Protocol and RTCP.
@ RTCP_RR
Receiver Report
Definition re_rtp.h:40
@ RTCP_SR
Sender Report
Definition re_rtp.h:39
unsigned int uint32_t
Definition stdint.h:85
signed int int32_t
Definition stdint.h:82
unsigned char uint8_t
Definition stdint.h:83
Represents an IP-address and port (V4 or V6).
unsigned int p
Padding flag
Definition re_rtp.h:99
unsigned int pt
RTCP packet type
Definition re_rtp.h:101
unsigned int count
Varies by packet type
Definition re_rtp.h:100
unsigned int version
Protocol version
Definition re_rtp.h:98
uint16_t length
Packet length in words.
Definition re_rtp.h:102
One RTCP Message.
Definition re_rtp.h:95
union rtcp_msg::@11 r
uint32_t ntp_sec
NTP timestamp - seconds
Definition re_rtp.h:108
uint32_t osent
RTP octets sent
Definition re_rtp.h:112
struct rtcp_msg::rtcp_hdr hdr
struct rtcp_msg::@11::@12 sr
Sender report (SR)
uint32_t ssrc
Sender generating report
Definition re_rtp.h:107
struct rtcp_msg::@11::@13 rr
Reception report (RR)
uint32_t ntp_frac
NTP timestamp - fractions.
Definition re_rtp.h:109
struct rtcp_rr rrv[1]
Reception report blocks
Definition re_rtp.h:113
uint32_t psent
RTP packets sent
Definition re_rtp.h:111
uint32_t rtp_ts
RTP timestamp
Definition re_rtp.h:110
Reception report block.
Definition re_rtp.h:76
uint32_t lsr
Last SR packet from this source.
Definition re_rtp.h:83
uint32_t dlsr
Delay since last SR packet
Definition re_rtp.h:84
uint32_t jitter
Interarrival jitter
Definition re_rtp.h:82
uint32_t fraction_lost_32
Combine the previous two fields.
Definition re_rtp.h:80
uint32_t ssrc
Data source being reported
Definition re_rtp.h:77
uint32_t last_seq
Extended last seq.
Definition re_rtp.h:81