srs/trunk/src/kernel/srs_kernel_utility.hpp
Winlin 35e2808f0c Support IPv6 for all protocols: RTMP, HTTP/HTTPS, WebRTC, SRT, RTSP. v7.0.67 (#4457)
This PR adds comprehensive IPv6 support to SRS for all major protocols,
enabling dual-stack (IPv4/IPv6) operation across the entire streaming
server.

Key Features:

* RTMP/RTMPS: IPv6 support for streaming ingestion and playback
* HTTP/HTTPS: IPv6 support for HTTP-FLV streaming and API endpoints
* WebRTC: IPv6 support for UDP/TCP media transport (WHIP/WHEP)
* SRT: IPv6 support for low-latency streaming
* RTSP: IPv6 support for standards-based streaming

For config, see `conf/console.ipv46.conf` for example.

Publish RTMP or RTMPS via IPv6:

```bash
ffmpeg -re -i ./doc/source.flv -c copy -f flv 'rtmp://[::1]:1935/live/livestream'
ffmpeg -re -i ./doc/source.flv -c copy -f flv 'rtmps://[::1]:1443/live/livestream'
```

Play RTMP or RTMPS stream via IPv6 by ffplay:

```bash
ffplay 'rtmp://[::1]:1935/live/livestream'
ffplay 'rtmps://[::1]:1443/live/livestream'
```

Play by IPv6 via HTTP streaming:
* HTTP-FLV:
[http://[::1]:8080/live/livestream.flv](http://[::1]:8080/players/srs_player.html)
* HTTPS-FLV:
[https://[::1]:8088/live/livestream.flv](https://[::1]:8088/players/srs_player.html)

To access HTTP API via IPv6:

* HTTP API: `curl 'http://[::1]:1985/api/v1/versions'`
* HTTPS API: `curl -k 'https://[::1]:1990/api/v1/versions'`

```json
{
  "code": 0,
  "data": {
    "major": 7,
    "minor": 0,
    "revision": 66,
    "version": "7.0.66"
  }
}
```

Using HTTP API, publish by IPv6 WHIP via
[HTTP](http://[::1]:8080/players/whip.html), and play by
[WHEP](http://[::1]:8080/players/whep.html)

* WHIP: `http://[::1]:1985/rtc/v1/whip/?app=live&stream=livestream`
* WHEP: `http://[::1]:1985/rtc/v1/whep/?app=live&stream=livestream`

Using HTTPS API, publish by IPv6 WHIP via
[WHIP](https://[::1]:8088/players/whip.html), and play by
[WHEP](https://[::1]:8088/players/whep.html)

* WHIP: `https://[::1]:1990/rtc/v1/whip/?app=live&stream=livestream`
* WHEP: `https://[::1]:1990/rtc/v1/whep/?app=live&stream=livestream`

Publish SRT stream by FFmpeg via IPv6:

```bash
ffmpeg -re -i ./doc/source.flv -c copy -pes_payload_size 0 -f mpegts \
  'srt://[::1]:10080?streamid=#!::r=live/livestream,m=publish'
```

Play SRT stream by ffplay via IPv6:

```bash
ffplay 'srt://[::1]:10080?streamid=#!::r=live/livestream,m=request'
```

Play RTSP stream by ffplay via IPv6:

```bash
ffplay -rtsp_transport tcp -i 'rtsp://[::1]:8554/live/livestream'
```

---------

Co-authored-by: OSSRS-AI <winlinam@gmail.com>
2025-08-30 08:52:21 -04:00

271 lines
11 KiB
C++

//
// Copyright (c) 2013-2025 The SRS Authors
//
// SPDX-License-Identifier: MIT
//
#ifndef SRS_KERNEL_UTILITY_HPP
#define SRS_KERNEL_UTILITY_HPP
#include <srs_core.hpp>
#include <map>
#include <sstream>
#include <string>
#include <vector>
class SrsBuffer;
class SrsBitBuffer;
class ISrsReader;
// Basic compare function.
#define srs_min(a, b) (((a) < (b)) ? (a) : (b))
#define srs_max(a, b) (((a) < (b)) ? (b) : (a))
// Get current system time in srs_utime_t, use cache to avoid performance problem
extern srs_utime_t srs_time_now_cached();
extern srs_utime_t srs_time_since_startup();
// A daemon st-thread updates it.
extern srs_utime_t srs_time_now_realtime();
// For utest to mock it.
#include <sys/time.h>
#ifdef SRS_OSX
#define _srs_gettimeofday gettimeofday
#else
typedef int (*srs_gettimeofday_t)(struct timeval *tv, struct timezone *tz);
#endif
// Whether system is little endian
extern bool srs_is_little_endian();
// Parse the int64 value to string.
extern std::string srs_strconv_format_int(int64_t value);
// Parse the float value to string, precise is 2.
extern std::string srs_strconv_format_float(double value);
// Convert bool to switch value, true to "on", false to "off".
extern std::string srs_strconv_format_bool(bool v);
// Replace old_str to new_str of str
extern std::string srs_strings_replace(std::string str, std::string old_str, std::string new_str);
// Trim char in trim_chars of str
extern std::string srs_strings_trim_end(std::string str, std::string trim_chars);
// Trim char in trim_chars of str
extern std::string srs_strings_trim_start(std::string str, std::string trim_chars);
// Remove char in remove_chars of str
extern std::string srs_strings_remove(std::string str, std::string remove_chars);
// Remove first substring from str
extern std::string srs_erase_first_substr(std::string str, std::string erase_string);
// Remove last substring from str
extern std::string srs_erase_last_substr(std::string str, std::string erase_string);
// Whether string end with
extern bool srs_strings_ends_with(std::string str, std::string flag);
extern bool srs_strings_ends_with(std::string str, std::string flag0, std::string flag1);
extern bool srs_strings_ends_with(std::string str, std::string flag0, std::string flag1, std::string flag2);
extern bool srs_strings_ends_with(std::string str, std::string flag0, std::string flag1, std::string flag2, std::string flag3);
// Whether string starts with
extern bool srs_strings_starts_with(std::string str, std::string flag);
extern bool srs_strings_starts_with(std::string str, std::string flag0, std::string flag1);
extern bool srs_strings_starts_with(std::string str, std::string flag0, std::string flag1, std::string flag2);
extern bool srs_strings_starts_with(std::string str, std::string flag0, std::string flag1, std::string flag2, std::string flag3);
// Whether string contains with
extern bool srs_strings_contains(std::string str, std::string flag);
extern bool srs_strings_contains(std::string str, std::string flag0, std::string flag1);
extern bool srs_strings_contains(std::string str, std::string flag0, std::string flag1, std::string flag2);
// Count each char of flag in string
extern int srs_strings_count(std::string str, std::string flag);
// Find the min match in str for flags.
extern std::string srs_strings_min_match(std::string str, std::vector<std::string> flags);
// Split the string by seperator to array.
extern std::vector<std::string> srs_strings_split(std::string s, std::string seperator);
extern std::vector<std::string> srs_strings_split(std::string s, std::vector<std::string> seperators);
// Format to a string.
extern std::string srs_fmt_sprintf(const char *fmt, ...);
// Dump string(str in length) to hex, it will process min(limit, length) chars.
// Append seperator between each elem, and newline when exceed line_limit, '\0' to ignore.
extern std::string srs_strings_dumps_hex(const std::string &str);
extern std::string srs_strings_dumps_hex(const char *str, int length);
extern std::string srs_strings_dumps_hex(const char *str, int length, int limit);
extern std::string srs_strings_dumps_hex(const char *str, int length, int limit, char seperator, int line_limit, char newline);
// join string in vector with indicated separator
template <typename T>
std::string srs_strings_join(std::vector<T> &vs, std::string separator)
{
std::stringstream ss;
for (int i = 0; i < (int)vs.size(); i++) {
ss << vs.at(i);
if (i != (int)vs.size() - 1) {
ss << separator;
}
}
return ss.str();
}
// Compare two vector with string.
template <typename T>
bool srs_strings_equal(std::vector<T> &a, std::vector<T> &b)
{
if (a.size() != b.size()) {
return false;
}
for (int i = 0; i < (int)a.size(); i++) {
if (a.at(i) != b.at(i)) {
return false;
}
}
return true;
}
// Compare the memory in bytes.
// @return true if completely equal; otherwise, false.
extern bool srs_bytes_equal(void *pa, void *pb, int size);
// Create dir recursively
extern srs_error_t srs_os_mkdir_all(std::string dir);
// Whether path exists.
extern bool srs_path_exists(std::string path);
// Get the dirname of path, for instance, dirname("/live/livestream")="/live"
extern std::string srs_path_filepath_dir(std::string path);
// Get the basename of path, for instance, basename("/live/livestream")="livestream"
extern std::string srs_path_filepath_base(std::string path);
// Get the filename of path, for instance, filename("livestream.flv")="livestream"
extern std::string srs_path_filepath_filename(std::string path);
// Get the file extension of path, for instance, filext("live.flv")=".flv"
extern std::string srs_path_filepath_ext(std::string path);
// Covert hex string p to uint8 data, for example:
// srs_hex_decode_string(data, string("139056E5A0"))
// which outputs the data in hex {0x13, 0x90, 0x56, 0xe5, 0xa0}.
extern int srs_hex_decode_string(uint8_t *data, const char *p, int size);
// Convert data string to hex, for example:
// srs_hex_encode_to_string(des, {0xf3, 0x3f}, 2)
// which outputs the des is string("F33F").
extern char *srs_hex_encode_to_string(char *des, const uint8_t *src, int len);
// Output in lowercase, such as string("f33f").
extern char *srs_hex_encode_to_string_lowercase(char *des, const uint8_t *src, int len);
// Generate ramdom data for handshake.
extern void srs_rand_gen_bytes(char *bytes, int size);
// Generate random string [0-9a-z] in size of len bytes.
extern std::string srs_rand_gen_str(int len);
// Generate random value, use srandom(now_us) to init seed if not initialized.
extern long srs_rand_integer();
// Whether string is digit number
// is_digit("0") is true
// is_digit("0000000000") is true
// is_digit("1234567890") is true
// is_digit("0123456789") is true
// is_digit("1234567890a") is false
// is_digit("a1234567890") is false
// is_digit("10e3") is false
// is_digit("!1234567890") is false
// is_digit("") is false
extern bool srs_is_digit_number(std::string str);
// Read all content util EOF.
extern srs_error_t srs_io_readall(ISrsReader *in, std::string &content);
// Split the host:port to host and port.
// @remark the hostport format in <host[:port]>, where port is optional.
extern void srs_net_split_hostport(std::string hostport, std::string &host, int &port);
// Parse the endpoint to ip and port.
// @remark The hostport format in <[ip:]port>, where ip is default to "0.0.0.0".
extern void srs_net_split_for_listener(std::string hostport, std::string &ip, int &port);
// The "ANY" address to listen, it's "0.0.0.0" for ipv4, and "::" for ipv6.
// @remark We prefer ipv4, only use ipv6 if ipv4 is disabled.
extern std::string srs_net_address_any();
// Check whether the ip is valid.
extern bool srs_net_is_valid_ip(std::string ip);
// Check whether the endpoint is valid.
extern bool srs_net_is_valid_endpoint(std::string endpoint);
// Whether domain is an IPv4 address.
extern bool srs_net_is_ipv4(std::string domain);
// Convert an IPv4 from string to uint32_t.
extern uint32_t srs_net_ipv4_to_integer(std::string ip);
// Whether the IPv4 is in an IP mask.
extern bool srs_net_ipv4_within_mask(std::string ip, std::string network, std::string mask);
// Get the CIDR (Classless Inter-Domain Routing) mask for a network address.
extern std::string srs_net_get_cidr_mask(std::string network_address);
// Get the CIDR (Classless Inter-Domain Routing) IPv4 for a network address.
extern std::string srs_net_get_cidr_ipv4(std::string network_address);
// Whether the url is starts with http:// or https://
extern bool srs_net_url_is_http(std::string url);
extern bool srs_net_url_is_rtmp(std::string url);
/**
* parse the tcUrl, output the schema, host, vhost, app and port.
* @param tcUrl, the input tcUrl, for example,
* rtmp://192.168.1.10:19350/live?vhost=vhost.ossrs.net
* @param schema, for example, rtmp
* @param host, for example, 192.168.1.10
* @param vhost, for example, vhost.ossrs.net.
* vhost default to host, when user not set vhost in query of app.
* @param app, for example, live
* @param port, for example, 19350
* default to 1935 if not specified.
* param param, for example, vhost=vhost.ossrs.net
* @remark The param stream is input and output param, that is:
* input: tcUrl+stream
* output: schema, host, vhost, app, stream, port, param
*/
extern void srs_net_url_parse_tcurl(std::string tcUrl, std::string &schema, std::string &host, std::string &vhost, std::string &app,
std::string &stream, int &port, std::string &param);
// Guessing stream by app and param, to make OBS happy. For example:
// rtmp://ip/live/livestream
// rtmp://ip/live/livestream?secret=xxx
// rtmp://ip/live?secret=xxx/livestream
extern void srs_net_url_guess_stream(std::string &app, std::string &param, std::string &stream);
// parse query string to map(k,v).
// must format as key=value&...&keyN=valueN
extern void srs_net_url_parse_query(std::string q, std::map<std::string, std::string> &query);
/**
* generate the tcUrl without param.
* @remark Use host as tcUrl.vhost if vhost is default vhost.
*/
extern std::string srs_net_url_encode_tcurl(std::string schema, std::string host, std::string vhost, std::string app, int port);
/**
* Generate the stream with param.
* @remark Append vhost in query string if not default vhost.
*/
extern std::string srs_net_url_encode_stream(std::string host, std::string vhost, std::string stream, std::string param, bool with_vhost);
// get the stream identify, vhost/app/stream.
extern std::string srs_net_url_encode_sid(std::string vhost, std::string app, std::string stream);
// parse the rtmp url to tcUrl/stream,
// for example, rtmp://v.ossrs.net/live/livestream to
// tcUrl: rtmp://v.ossrs.net/live
// stream: livestream
extern void srs_net_url_parse_rtmp_url(std::string url, std::string &tcUrl, std::string &stream);
// Genereate the rtmp url, for instance, rtmp://server:port/app/stream?param
// @remark We always put vhost in param, in the query of url.
extern std::string srs_net_url_encode_rtmp_url(std::string server, int port, std::string host, std::string vhost, std::string app, std::string stream, std::string param);
#endif