winlin

refine bandwidth server-side, use bandwidth sample and kbps limit service

@@ -36,6 +36,17 @@ using namespace std; @@ -36,6 +36,17 @@ using namespace std;
36 #include <srs_core_autofree.hpp> 36 #include <srs_core_autofree.hpp>
37 #include <srs_kernel_utility.hpp> 37 #include <srs_kernel_utility.hpp>
38 #include <srs_app_utility.hpp> 38 #include <srs_app_utility.hpp>
  39 +#include <srs_app_kbps.hpp>
  40 +
  41 +SrsBandwidthSample::SrsBandwidthSample()
  42 +{
  43 + duration_ms = 3000;
  44 + interval_ms = actual_duration_ms = bytes = 0;
  45 +}
  46 +
  47 +SrsBandwidthSample::~SrsBandwidthSample()
  48 +{
  49 +}
39 50
40 SrsBandwidth::SrsBandwidth() 51 SrsBandwidth::SrsBandwidth()
41 { 52 {
@@ -47,7 +58,7 @@ SrsBandwidth::~SrsBandwidth() @@ -47,7 +58,7 @@ SrsBandwidth::~SrsBandwidth()
47 { 58 {
48 } 59 }
49 60
50 -int SrsBandwidth::bandwidth_check(SrsRtmpServer* rtmp, SrsRequest* req, string local_ip) 61 +int SrsBandwidth::bandwidth_check(SrsRtmpServer* rtmp, ISrsProtocolStatistic* io_stat, SrsRequest* req, string local_ip)
51 { 62 {
52 int ret = ERROR_SUCCESS; 63 int ret = ERROR_SUCCESS;
53 64
@@ -68,7 +79,7 @@ int SrsBandwidth::bandwidth_check(SrsRtmpServer* rtmp, SrsRequest* req, string l @@ -68,7 +79,7 @@ int SrsBandwidth::bandwidth_check(SrsRtmpServer* rtmp, SrsRequest* req, string l
68 } 79 }
69 80
70 // shared global last check time, 81 // shared global last check time,
71 - // to avoid attach by bandwidth check, 82 + // to prevent bandwidth check attack,
72 // if client request check in the window(specifeid by interval), 83 // if client request check in the window(specifeid by interval),
73 // directly reject the request. 84 // directly reject the request.
74 static int64_t last_check_time = 0; 85 static int64_t last_check_time = 0;
@@ -93,25 +104,23 @@ int SrsBandwidth::bandwidth_check(SrsRtmpServer* rtmp, SrsRequest* req, string l @@ -93,25 +104,23 @@ int SrsBandwidth::bandwidth_check(SrsRtmpServer* rtmp, SrsRequest* req, string l
93 srs_error("response connect app failed. ret=%d", ret); 104 srs_error("response connect app failed. ret=%d", ret);
94 return ret; 105 return ret;
95 } 106 }
  107 +
  108 + // create a limit object.
  109 + SrsKbps kbps;
  110 + kbps.set_io(io_stat, io_stat);
96 111
97 - return do_bandwidth_check(); 112 + int limit_kbps = _srs_config->get_bw_check_limit_kbps(_req->vhost);
  113 + SrsKbpsLimit limit(&kbps, limit_kbps);
  114 +
  115 + return do_bandwidth_check(&limit);
98 } 116 }
99 117
100 -int SrsBandwidth::do_bandwidth_check() 118 +int SrsBandwidth::do_bandwidth_check(SrsKbpsLimit* limit)
101 { 119 {
102 int ret = ERROR_SUCCESS; 120 int ret = ERROR_SUCCESS;
103 121
104 - int play_duration_ms = 3000;  
105 - int play_interval_ms = 0;  
106 - int play_actual_duration_ms = 0;  
107 - int play_bytes = 0;  
108 -  
109 - int publish_duration_ms = 3000;  
110 - int publish_interval_ms = 0;  
111 - int publish_actual_duration_ms = 0;  
112 - int publish_bytes = 0;  
113 -  
114 - int limit_kbps = _srs_config->get_bw_check_limit_kbps(_req->vhost); 122 + SrsBandwidthSample play_sample;
  123 + SrsBandwidthSample publish_sample;
115 124
116 int64_t start_time = srs_get_system_time_ms(); 125 int64_t start_time = srs_get_system_time_ms();
117 126
@@ -35,6 +35,36 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -35,6 +35,36 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35 35
36 class SrsRequest; 36 class SrsRequest;
37 class SrsRtmpServer; 37 class SrsRtmpServer;
  38 +class SrsKbpsLimit;
  39 +class ISrsProtocolStatistic;
  40 +
  41 +/**
  42 +* bandwidth check/test sample.
  43 +*/
  44 +class SrsBandwidthSample
  45 +{
  46 +public:
  47 + /**
  48 + * the plan, how long to do the test, in ms,
  49 + * if exceed the duration, abort the test.
  50 + */
  51 + int duration_ms;
  52 + /**
  53 + * the plan, interval for each check/test packet, in ms
  54 + */
  55 + int interval_ms;
  56 + /**
  57 + * the actual test duration, in ms.
  58 + */
  59 + int actual_duration_ms;
  60 + /**
  61 + * the actual test bytes
  62 + */
  63 + int bytes;
  64 +public:
  65 + SrsBandwidthSample();
  66 + virtual ~SrsBandwidthSample();
  67 +};
38 68
39 /** 69 /**
40 * bandwidth test agent which provides the interfaces for bandwidth check. 70 * bandwidth test agent which provides the interfaces for bandwidth check.
@@ -84,15 +114,17 @@ public: @@ -84,15 +114,17 @@ public:
84 /** 114 /**
85 * do the bandwidth check. 115 * do the bandwidth check.
86 * @param rtmp, server RTMP protocol object, send/recv RTMP packet to/from client. 116 * @param rtmp, server RTMP protocol object, send/recv RTMP packet to/from client.
  117 + * @param io_stat, the underlayer io statistic, provides send/recv bytes count.
87 * @param req, client request object, specifies the request info from client. 118 * @param req, client request object, specifies the request info from client.
88 * @param local_ip, the ip of server which client connected at 119 * @param local_ip, the ip of server which client connected at
89 */ 120 */
90 - virtual int bandwidth_check(SrsRtmpServer* rtmp, SrsRequest* req, std::string local_ip); 121 + virtual int bandwidth_check(SrsRtmpServer* rtmp, ISrsProtocolStatistic* io_stat, SrsRequest* req, std::string local_ip);
91 private: 122 private:
92 /** 123 /**
93 * used to process band width check from client. 124 * used to process band width check from client.
  125 + * @param limit, the bandwidth limit object, to slowdown if exceed the kbps.
94 */ 126 */
95 - virtual int do_bandwidth_check(); 127 + virtual int do_bandwidth_check(SrsKbpsLimit* limit);
96 virtual int check_play(int duration_ms, int interval_ms, int& actual_duration_ms, int& play_bytes, int max_play_kbps); 128 virtual int check_play(int duration_ms, int interval_ms, int& actual_duration_ms, int& play_bytes, int max_play_kbps);
97 virtual int check_publish(int duration_ms, int interval_ms, int& actual_duration_ms, int& publish_bytes, int max_pub_kbps); 129 virtual int check_publish(int duration_ms, int interval_ms, int& actual_duration_ms, int& publish_bytes, int max_pub_kbps);
98 }; 130 };
@@ -28,6 +28,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -28,6 +28,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 #include <srs_protocol_io.hpp> 28 #include <srs_protocol_io.hpp>
29 #include <srs_kernel_utility.hpp> 29 #include <srs_kernel_utility.hpp>
30 30
  31 +#define _SRS_BANDWIDTH_LIMIT_INTERVAL_MS 100
  32 +
31 SrsKbpsSample::SrsKbpsSample() 33 SrsKbpsSample::SrsKbpsSample()
32 { 34 {
33 bytes = time = 0; 35 bytes = time = 0;
@@ -244,3 +246,29 @@ void SrsKbps::sample() @@ -244,3 +246,29 @@ void SrsKbps::sample()
244 os.sample(); 246 os.sample();
245 } 247 }
246 248
  249 +SrsKbpsLimit::SrsKbpsLimit(SrsKbps* kbps, int limit_kbps)
  250 +{
  251 + _kbps = kbps;
  252 + _limit_kbps = limit_kbps;
  253 +}
  254 +
  255 +SrsKbpsLimit::~SrsKbpsLimit()
  256 +{
  257 +}
  258 +
  259 +void SrsKbpsLimit::recv_limit()
  260 +{
  261 + while (_kbps->get_recv_kbps() > _limit_kbps) {
  262 + _kbps->sample();
  263 + st_usleep(_SRS_BANDWIDTH_LIMIT_INTERVAL_MS * 1000);
  264 + }
  265 +}
  266 +
  267 +void SrsKbpsLimit::send_limit()
  268 +{
  269 + while (_kbps->get_send_kbps() > _limit_kbps) {
  270 + _kbps->sample();
  271 + st_usleep(_SRS_BANDWIDTH_LIMIT_INTERVAL_MS * 1000);
  272 + }
  273 +}
  274 +
@@ -198,4 +198,26 @@ public: @@ -198,4 +198,26 @@ public:
198 virtual void sample(); 198 virtual void sample();
199 }; 199 };
200 200
  201 +/**
  202 +* the kbps limit, if exceed the kbps, slow down.
  203 +*/
  204 +class SrsKbpsLimit
  205 +{
  206 +private:
  207 + int _limit_kbps;
  208 + SrsKbps* _kbps;
  209 +public:
  210 + SrsKbpsLimit(SrsKbps* kbps, int limit_kbps);
  211 + virtual ~SrsKbpsLimit();
  212 +public:
  213 + /**
  214 + * limit the recv bandwidth.
  215 + */
  216 + virtual void recv_limit();
  217 + /**
  218 + * limit the send bandwidth.
  219 + */
  220 + virtual void send_limit();
  221 +};
  222 +
201 #endif 223 #endif
@@ -216,7 +216,7 @@ int SrsRtmpConn::service_cycle() @@ -216,7 +216,7 @@ int SrsRtmpConn::service_cycle()
216 216
217 // do bandwidth test if connect to the vhost which is for bandwidth check. 217 // do bandwidth test if connect to the vhost which is for bandwidth check.
218 if (_srs_config->get_bw_check_enabled(req->vhost)) { 218 if (_srs_config->get_bw_check_enabled(req->vhost)) {
219 - return bandwidth->bandwidth_check(rtmp, req, local_ip); 219 + return bandwidth->bandwidth_check(rtmp, io, req, local_ip);
220 } 220 }
221 221
222 if ((ret = rtmp->response_connect_app(req, local_ip.c_str())) != ERROR_SUCCESS) { 222 if ((ret = rtmp->response_connect_app(req, local_ip.c_str())) != ERROR_SUCCESS) {