123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652 |
- /*
- * SRT - Secure, Reliable, Transport
- * Copyright (c) 2018 Haivision Systems Inc.
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/.
- *
- */
- /*****************************************************************************
- Copyright (c) 2001 - 2016, The Board of Trustees of the University of Illinois.
- All rights reserved.
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are
- met:
- * Redistributions of source code must retain the above
- copyright notice, this list of conditions and the
- following disclaimer.
- * Redistributions in binary form must reproduce the
- above copyright notice, this list of conditions
- and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
- * Neither the name of the University of Illinois
- nor the names of its contributors may be used to
- endorse or promote products derived from this
- software without specific prior written permission.
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *****************************************************************************/
- /*****************************************************************************
- written by
- Yunhong Gu, last updated 07/25/2010
- modified by
- Haivision Systems Inc.
- *****************************************************************************/
- #define SRT_IMPORT_TIME 1
- #include "platform_sys.h"
- #include <string>
- #include <sstream>
- #include <cmath>
- #include <iostream>
- #include <iomanip>
- #include <iterator>
- #include <vector>
- #include "udt.h"
- #include "md5.h"
- #include "common.h"
- #include "netinet_any.h"
- #include "logging.h"
- #include "packet.h"
- #include "threadname.h"
- #include <srt_compat.h> // SysStrError
- using namespace std;
- using namespace srt::sync;
- using namespace srt_logging;
- namespace srt_logging
- {
- extern Logger inlog;
- }
- namespace srt
- {
- const char* strerror_get_message(size_t major, size_t minor);
- } // namespace srt
- srt::CUDTException::CUDTException(CodeMajor major, CodeMinor minor, int err):
- m_iMajor(major),
- m_iMinor(minor)
- {
- if (err == -1)
- m_iErrno = NET_ERROR;
- else
- m_iErrno = err;
- }
- const char* srt::CUDTException::getErrorMessage() const ATR_NOTHROW
- {
- return strerror_get_message(m_iMajor, m_iMinor);
- }
- std::string srt::CUDTException::getErrorString() const
- {
- return getErrorMessage();
- }
- #define UDT_XCODE(mj, mn) (int(mj)*1000)+int(mn)
- int srt::CUDTException::getErrorCode() const
- {
- return UDT_XCODE(m_iMajor, m_iMinor);
- }
- int srt::CUDTException::getErrno() const
- {
- return m_iErrno;
- }
- void srt::CUDTException::clear()
- {
- m_iMajor = MJ_SUCCESS;
- m_iMinor = MN_NONE;
- m_iErrno = 0;
- }
- #undef UDT_XCODE
- //
- bool srt::CIPAddress::ipcmp(const sockaddr* addr1, const sockaddr* addr2, int ver)
- {
- if (AF_INET == ver)
- {
- sockaddr_in* a1 = (sockaddr_in*)addr1;
- sockaddr_in* a2 = (sockaddr_in*)addr2;
- if ((a1->sin_port == a2->sin_port) && (a1->sin_addr.s_addr == a2->sin_addr.s_addr))
- return true;
- }
- else
- {
- sockaddr_in6* a1 = (sockaddr_in6*)addr1;
- sockaddr_in6* a2 = (sockaddr_in6*)addr2;
- if (a1->sin6_port == a2->sin6_port)
- {
- for (int i = 0; i < 16; ++ i)
- if (*((char*)&(a1->sin6_addr) + i) != *((char*)&(a2->sin6_addr) + i))
- return false;
- return true;
- }
- }
- return false;
- }
- void srt::CIPAddress::ntop(const sockaddr_any& addr, uint32_t ip[4])
- {
- if (addr.family() == AF_INET)
- {
- // SRT internal format of IPv4 address.
- // The IPv4 address is in the first field. The rest is 0.
- ip[0] = addr.sin.sin_addr.s_addr;
- ip[1] = ip[2] = ip[3] = 0;
- }
- else
- {
- std::memcpy(ip, addr.sin6.sin6_addr.s6_addr, 16);
- }
- }
- namespace srt {
- bool checkMappedIPv4(const uint16_t* addr)
- {
- static const uint16_t ipv4on6_model [8] =
- {
- 0, 0, 0, 0, 0, 0xFFFF, 0, 0
- };
- // Compare only first 6 words. Remaining 2 words
- // comprise the IPv4 address, if these first 6 match.
- const uint16_t* mbegin = ipv4on6_model;
- const uint16_t* mend = ipv4on6_model + 6;
- return std::equal(mbegin, mend, addr);
- }
- }
- // XXX This has void return and the first argument is passed by reference.
- // Consider simply returning sockaddr_any by value.
- void srt::CIPAddress::pton(sockaddr_any& w_addr, const uint32_t ip[4], const sockaddr_any& peer)
- {
- //using ::srt_logging::inlog;
- uint32_t* target_ipv4_addr = NULL;
- if (peer.family() == AF_INET)
- {
- sockaddr_in* a = (&w_addr.sin);
- target_ipv4_addr = (uint32_t*) &a->sin_addr.s_addr;
- }
- else // AF_INET6
- {
- // Check if the peer address is a model of IPv4-mapped-on-IPv6.
- // If so, it means that the `ip` array should be interpreted as IPv4.
- const bool is_mapped_ipv4 = checkMappedIPv4((uint16_t*)peer.sin6.sin6_addr.s6_addr);
- sockaddr_in6* a = (&w_addr.sin6);
- // This whole above procedure was only in order to EXCLUDE the
- // possibility of IPv4-mapped-on-IPv6. This below may only happen
- // if BOTH peers are IPv6. Otherwise we have a situation of cross-IP
- // version connection in which case the address in question is always
- // IPv4 in various mapping formats.
- if (!is_mapped_ipv4)
- {
- // Here both agent and peer use IPv6, in which case
- // `ip` contains the full IPv6 address, so just copy
- // it as is.
- std::memcpy(a->sin6_addr.s6_addr, ip, 16);
- return; // The address is written, nothing left to do.
- }
- //
- // IPv4 mapped on IPv6
- // Here agent uses IPv6 with IPPROTO_IPV6/IPV6_V6ONLY == 0
- // In this case, the address in `ip` is always an IPv4,
- // although we are not certain as to whether it's using the
- // IPv6 encoding (0::FFFF:IPv4) or SRT encoding (IPv4::0);
- // this must be extra determined.
- //
- // Unfortunately, sockaddr_in6 doesn't give any straightforward
- // method for it, although the official size of a single element
- // of the IPv6 address is 16-bit.
- memset((a->sin6_addr.s6_addr), 0, sizeof a->sin6_addr.s6_addr);
- // The sin6_addr.s6_addr32 is non that portable to use here.
- uint32_t* paddr32 = (uint32_t*)a->sin6_addr.s6_addr;
- uint16_t* paddr16 = (uint16_t*)a->sin6_addr.s6_addr;
- // layout: of IPv4 address 192.168.128.2
- // 16-bit:
- // [0000: 0000: 0000: 0000: 0000: FFFF: 192.168:128.2]
- // 8-bit
- // [00/00/00/00/00/00/00/00/00/00/FF/FF/192/168/128/2]
- // 32-bit
- // [00000000 && 00000000 && 0000FFFF && 192.168.128.2]
- // Spreading every 16-bit word separately to avoid endian dilemmas
- paddr16[2 * 2 + 1] = 0xFFFF;
- target_ipv4_addr = &paddr32[3];
- }
- // Now we have two possible formats of encoding the IPv4 address:
- // 1. If peer is IPv4, it's IPv4::0
- // 2. If peer is IPv6, it's 0::FFFF:IPv4.
- //
- // Has any other possibility happen here, copy an empty address,
- // which will be the only sign of an error.
- const uint16_t* peeraddr16 = (uint16_t*)ip;
- const bool is_mapped_ipv4 = checkMappedIPv4(peeraddr16);
- if (is_mapped_ipv4)
- {
- *target_ipv4_addr = ip[3];
- HLOGC(inlog.Debug, log << "pton: Handshake address: " << w_addr.str() << " provided in IPv6 mapping format");
- }
- // Check SRT IPv4 format.
- else if ((ip[1] | ip[2] | ip[3]) == 0)
- {
- *target_ipv4_addr = ip[0];
- HLOGC(inlog.Debug, log << "pton: Handshake address: " << w_addr.str() << " provided in SRT IPv4 format");
- }
- else
- {
- LOGC(inlog.Error, log << "pton: IPE or net error: can't determine IPv4 carryover format: " << std::hex
- << peeraddr16[0] << ":"
- << peeraddr16[1] << ":"
- << peeraddr16[2] << ":"
- << peeraddr16[3] << ":"
- << peeraddr16[4] << ":"
- << peeraddr16[5] << ":"
- << peeraddr16[6] << ":"
- << peeraddr16[7] << std::dec);
- *target_ipv4_addr = 0;
- if (peer.family() != AF_INET)
- {
- // Additionally overwrite the 0xFFFF that has been
- // just written 50 lines above.
- w_addr.sin6.sin6_addr.s6_addr[10] = 0;
- w_addr.sin6.sin6_addr.s6_addr[11] = 0;
- }
- }
- }
- namespace srt {
- static string ShowIP4(const sockaddr_in* sin)
- {
- ostringstream os;
- union
- {
- in_addr sinaddr;
- unsigned char ip[4];
- };
- sinaddr = sin->sin_addr;
- os << int(ip[0]);
- os << ".";
- os << int(ip[1]);
- os << ".";
- os << int(ip[2]);
- os << ".";
- os << int(ip[3]);
- return os.str();
- }
- static string ShowIP6(const sockaddr_in6* sin)
- {
- ostringstream os;
- os.setf(ios::uppercase);
- bool sep = false;
- for (size_t i = 0; i < 16; ++i)
- {
- int v = sin->sin6_addr.s6_addr[i];
- if ( v )
- {
- if ( sep )
- os << ":";
- os << hex << v;
- sep = true;
- }
- }
- return os.str();
- }
- string CIPAddress::show(const sockaddr* adr)
- {
- if ( adr->sa_family == AF_INET )
- return ShowIP4((const sockaddr_in*)adr);
- else if ( adr->sa_family == AF_INET6 )
- return ShowIP6((const sockaddr_in6*)adr);
- else
- return "(unsupported sockaddr type)";
- }
- } // namespace srt
- //
- void srt::CMD5::compute(const char* input, unsigned char result[16])
- {
- md5_state_t state;
- md5_init(&state);
- md5_append(&state, (const md5_byte_t *)input, (int) strlen(input));
- md5_finish(&state, result);
- }
- namespace srt {
- std::string MessageTypeStr(UDTMessageType mt, uint32_t extt)
- {
- using std::string;
- static const char* const udt_types [] = {
- "handshake",
- "keepalive",
- "ack",
- "lossreport",
- "cgwarning", //4
- "shutdown",
- "ackack",
- "dropreq",
- "peererror", //8
- };
- static const char* const srt_types [] = {
- "EXT:none",
- "EXT:hsreq",
- "EXT:hsrsp",
- "EXT:kmreq",
- "EXT:kmrsp",
- "EXT:sid",
- "EXT:congctl",
- "EXT:filter",
- "EXT:group"
- };
- if ( mt == UMSG_EXT )
- {
- if ( extt >= Size(srt_types) )
- return "EXT:unknown";
- return srt_types[extt];
- }
- if ( size_t(mt) > Size(udt_types) )
- return "unknown";
- return udt_types[mt];
- }
- std::string ConnectStatusStr(EConnectStatus cst)
- {
- return
- cst == CONN_CONTINUE ? "INDUCED/CONCLUDING"
- : cst == CONN_RUNNING ? "RUNNING"
- : cst == CONN_ACCEPT ? "ACCEPTED"
- : cst == CONN_RENDEZVOUS ? "RENDEZVOUS (HSv5)"
- : cst == CONN_AGAIN ? "AGAIN"
- : cst == CONN_CONFUSED ? "MISSING HANDSHAKE"
- : "REJECTED";
- }
- std::string TransmissionEventStr(ETransmissionEvent ev)
- {
- static const char* const vals [] =
- {
- "init",
- "ack",
- "ackack",
- "lossreport",
- "checktimer",
- "send",
- "receive",
- "custom",
- "sync"
- };
- size_t vals_size = Size(vals);
- if (size_t(ev) >= vals_size)
- return "UNKNOWN";
- return vals[ev];
- }
- bool SrtParseConfig(const string& s, SrtConfig& w_config)
- {
- using namespace std;
- vector<string> parts;
- Split(s, ',', back_inserter(parts));
- w_config.type = parts[0];
- for (vector<string>::iterator i = parts.begin()+1; i != parts.end(); ++i)
- {
- vector<string> keyval;
- Split(*i, ':', back_inserter(keyval));
- if (keyval.size() != 2)
- return false;
- if (keyval[1] != "")
- w_config.parameters[keyval[0]] = keyval[1];
- }
- return true;
- }
- } // namespace srt
- namespace srt_logging
- {
- // Value display utilities
- // (also useful for applications)
- std::string SockStatusStr(SRT_SOCKSTATUS s)
- {
- if (int(s) < int(SRTS_INIT) || int(s) > int(SRTS_NONEXIST))
- return "???";
- static struct AutoMap
- {
- // Values start from 1, so do -1 to avoid empty cell
- std::string names[int(SRTS_NONEXIST)-1+1];
- AutoMap()
- {
- #define SINI(statename) names[SRTS_##statename-1] = #statename
- SINI(INIT);
- SINI(OPENED);
- SINI(LISTENING);
- SINI(CONNECTING);
- SINI(CONNECTED);
- SINI(BROKEN);
- SINI(CLOSING);
- SINI(CLOSED);
- SINI(NONEXIST);
- #undef SINI
- }
- } names;
- return names.names[int(s)-1];
- }
- #if ENABLE_BONDING
- std::string MemberStatusStr(SRT_MEMBERSTATUS s)
- {
- if (int(s) < int(SRT_GST_PENDING) || int(s) > int(SRT_GST_BROKEN))
- return "???";
- static struct AutoMap
- {
- std::string names[int(SRT_GST_BROKEN)+1];
- AutoMap()
- {
- #define SINI(statename) names[SRT_GST_##statename] = #statename
- SINI(PENDING);
- SINI(IDLE);
- SINI(RUNNING);
- SINI(BROKEN);
- #undef SINI
- }
- } names;
- return names.names[int(s)];
- }
- #endif
- // Logging system implementation
- #if ENABLE_LOGGING
- srt::logging::LogDispatcher::Proxy::Proxy(LogDispatcher& guy) : that(guy), that_enabled(that.CheckEnabled())
- {
- if (that_enabled)
- {
- i_file = "";
- i_line = 0;
- flags = that.src_config->flags;
- // Create logger prefix
- that.CreateLogLinePrefix(os);
- }
- }
- LogDispatcher::Proxy LogDispatcher::operator()()
- {
- return Proxy(*this);
- }
- void LogDispatcher::CreateLogLinePrefix(std::ostringstream& serr)
- {
- using namespace std;
- using namespace srt;
- SRT_STATIC_ASSERT(ThreadName::BUFSIZE >= sizeof("hh:mm:ss.") * 2, // multiply 2 for some margin
- "ThreadName::BUFSIZE is too small to be used for strftime");
- char tmp_buf[ThreadName::BUFSIZE];
- if ( !isset(SRT_LOGF_DISABLE_TIME) )
- {
- // Not necessary if sending through the queue.
- timeval tv;
- gettimeofday(&tv, NULL);
- struct tm tm = SysLocalTime((time_t) tv.tv_sec);
- if (strftime(tmp_buf, sizeof(tmp_buf), "%X.", &tm))
- {
- serr << tmp_buf << setw(6) << setfill('0') << tv.tv_usec;
- }
- }
- string out_prefix;
- if ( !isset(SRT_LOGF_DISABLE_SEVERITY) )
- {
- out_prefix = prefix;
- }
- // Note: ThreadName::get needs a buffer of size min. ThreadName::BUFSIZE
- if ( !isset(SRT_LOGF_DISABLE_THREADNAME) && ThreadName::get(tmp_buf) )
- {
- serr << "/" << tmp_buf << out_prefix << ": ";
- }
- else
- {
- serr << out_prefix << ": ";
- }
- }
- std::string LogDispatcher::Proxy::ExtractName(std::string pretty_function)
- {
- if ( pretty_function == "" )
- return "";
- size_t pos = pretty_function.find('(');
- if ( pos == std::string::npos )
- return pretty_function; // return unchanged.
- pretty_function = pretty_function.substr(0, pos);
- // There are also template instantiations where the instantiating
- // parameters are encrypted inside. Therefore, search for the first
- // open < and if found, search for symmetric >.
- int depth = 1;
- pos = pretty_function.find('<');
- if ( pos != std::string::npos )
- {
- size_t end = pos+1;
- for(;;)
- {
- ++pos;
- if ( pos == pretty_function.size() )
- {
- --pos;
- break;
- }
- if ( pretty_function[pos] == '<' )
- {
- ++depth;
- continue;
- }
- if ( pretty_function[pos] == '>' )
- {
- --depth;
- if ( depth <= 0 )
- break;
- continue;
- }
- }
- std::string afterpart = pretty_function.substr(pos+1);
- pretty_function = pretty_function.substr(0, end) + ">" + afterpart;
- }
- // Now see how many :: can be found in the name.
- // If this occurs more than once, take the last two.
- pos = pretty_function.rfind("::");
- if ( pos == std::string::npos || pos < 2 )
- return pretty_function; // return whatever this is. No scope name.
- // Find the next occurrence of :: - if found, copy up to it. If not,
- // return whatever is found.
- pos -= 2;
- pos = pretty_function.rfind("::", pos);
- if ( pos == std::string::npos )
- return pretty_function; // nothing to cut
- return pretty_function.substr(pos+2);
- }
- #endif
- } // (end namespace srt_logging)
|