1 // PHZ
2 // 2018-5-16
3
4 #if defined(WIN32) || defined(_WIN32)
5 #ifndef _CRT_SECURE_NO_WARNINGS
6 #define _CRT_SECURE_NO_WARNINGS
7 #endif
8 #endif
9
10 #include "RtspMessage.h"
11 #include "media.h"
12
13 using namespace std;
14 using namespace xop;
15
ParseRequest(BufferReader * buffer)16 bool RtspRequest::ParseRequest(BufferReader *buffer)
17 {
18 if(buffer->Peek()[0] == '$') {
19 method_ = RTCP;
20 return true;
21 }
22
23 bool ret = true;
24 while(1) {
25 if(state_ == kParseRequestLine) {
26 const char* firstCrlf = buffer->FindFirstCrlf();
27 if(firstCrlf != nullptr)
28 {
29 ret = ParseRequestLine(buffer->Peek(), firstCrlf);
30 buffer->RetrieveUntil(firstCrlf + 2);
31 }
32
33 if (state_ == kParseHeadersLine) {
34 continue;
35 }
36 else {
37 break;
38 }
39 }
40 else if(state_ == kParseHeadersLine) {
41 const char* lastCrlf = buffer->FindLastCrlf();
42 if(lastCrlf != nullptr) {
43 ret = ParseHeadersLine(buffer->Peek(), lastCrlf);
44 buffer->RetrieveUntil(lastCrlf + 2);
45 }
46 break;
47 }
48 else if(state_ == kGotAll) {
49 buffer->RetrieveAll();
50 return true;
51 }
52 }
53
54 return ret;
55 }
56
ParseRequestLine(const char * begin,const char * end)57 bool RtspRequest::ParseRequestLine(const char* begin, const char* end)
58 {
59 string message(begin, end);
60 char method[64] = {0};
61 char url[512] = {0};
62 char version[64] = {0};
63
64 if(sscanf(message.c_str(), "%s %s %s", method, url, version) != 3) {
65 return true;
66 }
67
68 string method_str(method);
69 if(method_str == "OPTIONS") {
70 method_ = OPTIONS;
71 }
72 else if(method_str == "DESCRIBE") {
73 method_ = DESCRIBE;
74 }
75 else if(method_str == "SETUP") {
76 method_ = SETUP;
77 }
78 else if(method_str == "PLAY") {
79 method_ = PLAY;
80 }
81 else if(method_str == "TEARDOWN") {
82 method_ = TEARDOWN;
83 }
84 else if(method_str == "GET_PARAMETER") {
85 method_ = GET_PARAMETER;
86 }
87 else {
88 method_ = NONE;
89 return false;
90 }
91
92 if(strncmp(url, "rtsp://", 7) != 0) {
93 return false;
94 }
95
96 // parse url
97 uint16_t port = 0;
98 char ip[64] = {0};
99 char suffix[256] = {0};
100
101 if(sscanf(url+7, "%[^:]:%hu/%s", ip, &port, suffix) == 3) {
102
103 }
104 else if(sscanf(url+7, "%[^/]/%s", ip, suffix) == 2) {
105 port = 554;
106 }
107 else {
108 return false;
109 }
110
111 request_line_param_.emplace("url", make_pair(string(url), 0));
112 request_line_param_.emplace("url_ip", make_pair(string(ip), 0));
113 request_line_param_.emplace("url_port", make_pair("", (uint32_t)port));
114 request_line_param_.emplace("url_suffix", make_pair(string(suffix), 0));
115 request_line_param_.emplace("version", make_pair(string(version), 0));
116 request_line_param_.emplace("method", make_pair(move(method_str), 0));
117
118 state_ = kParseHeadersLine;
119 return true;
120 }
121
ParseHeadersLine(const char * begin,const char * end)122 bool RtspRequest::ParseHeadersLine(const char* begin, const char* end)
123 {
124 string message(begin, end);
125 if(!ParseCSeq(message)) {
126 if (header_line_param_.find("cseq") == header_line_param_.end()) {
127 return false;
128 }
129 }
130
131 if (method_ == DESCRIBE || method_ == SETUP || method_ == PLAY) {
132 ParseAuthorization(message);
133 }
134
135 if(method_ == OPTIONS) {
136 state_ = kGotAll;
137 return true;
138 }
139
140 if(method_ == DESCRIBE) {
141 if(ParseAccept(message)) {
142 state_ = kGotAll;
143 }
144 return true;
145 }
146
147 if(method_ == SETUP) {
148 if(ParseTransport(message)) {
149 ParseMediaChannel(message);
150 state_ = kGotAll;
151 }
152
153 return true;
154 }
155
156 if(method_ == PLAY) {
157 if(ParseSessionId(message)) {
158 state_ = kGotAll;
159 }
160 return true;
161 }
162
163 if(method_ == TEARDOWN) {
164 state_ = kGotAll;
165 return true;
166 }
167
168 if(method_ == GET_PARAMETER) {
169 state_ = kGotAll;
170 return true;
171 }
172
173 return true;
174 }
175
ParseCSeq(std::string & message)176 bool RtspRequest::ParseCSeq(std::string& message)
177 {
178 std::size_t pos = message.find("CSeq");
179 if (pos != std::string::npos) {
180 uint32_t cseq = 0;
181 sscanf(message.c_str()+pos, "%*[^:]: %u", &cseq);
182 header_line_param_.emplace("cseq", make_pair("", cseq));
183 return true;
184 }
185
186 return false;
187 }
188
ParseAccept(std::string & message)189 bool RtspRequest::ParseAccept(std::string& message)
190 {
191 if ((message.rfind("Accept")==std::string::npos)
192 || (message.rfind("sdp")==std::string::npos)) {
193 return false;
194 }
195
196 return true;
197 }
198
ParseTransport(std::string & message)199 bool RtspRequest::ParseTransport(std::string& message)
200 {
201 std::size_t pos = message.find("Transport");
202 if(pos != std::string::npos) {
203 if((pos=message.find("RTP/AVP/TCP")) != std::string::npos) {
204 transport_ = RTP_OVER_TCP;
205 uint16_t rtpChannel = 0, rtcpChannel = 0;
206 if (sscanf(message.c_str() + pos, "%*[^;];%*[^;];%*[^=]=%hu-%hu", &rtpChannel, &rtcpChannel) != 2) {
207 return false;
208 }
209 header_line_param_.emplace("rtp_channel", make_pair("", rtpChannel));
210 header_line_param_.emplace("rtcp_channel", make_pair("", rtcpChannel));
211 }
212 else if((pos=message.find("RTP/AVP")) != std::string::npos) {
213 uint16_t rtp_port = 0, rtcpPort = 0;
214 if(((message.find("unicast", pos)) != std::string::npos)) {
215 transport_ = RTP_OVER_UDP;
216 if(sscanf(message.c_str()+pos, "%*[^;];%*[^;];%*[^=]=%hu-%hu",
217 &rtp_port, &rtcpPort) != 2)
218 {
219 return false;
220 }
221
222 }
223 else if((message.find("multicast", pos)) != std::string::npos) {
224 transport_ = RTP_OVER_MULTICAST;
225 }
226 else {
227 return false;
228 }
229
230 header_line_param_.emplace("rtp_port", make_pair("", rtp_port));
231 header_line_param_.emplace("rtcp_port", make_pair("", rtcpPort));
232 }
233 else {
234 return false;
235 }
236
237 return true;
238 }
239
240 return false;
241 }
242
ParseSessionId(std::string & message)243 bool RtspRequest::ParseSessionId(std::string& message)
244 {
245 std::size_t pos = message.find("Session");
246 if (pos != std::string::npos) {
247 uint32_t session_id = 0;
248 if (sscanf(message.c_str() + pos, "%*[^:]: %u", &session_id) != 1) {
249 return false;
250 }
251 return true;
252 }
253
254 return false;
255 }
256
ParseMediaChannel(std::string & message)257 bool RtspRequest::ParseMediaChannel(std::string& message)
258 {
259 channel_id_ = channel_0;
260
261 auto iter = request_line_param_.find("url");
262 if(iter != request_line_param_.end()) {
263 std::size_t pos = iter->second.first.find("track1");
264 if (pos != std::string::npos) {
265 channel_id_ = channel_1;
266 }
267 }
268
269 return true;
270 }
271
ParseAuthorization(std::string & message)272 bool RtspRequest::ParseAuthorization(std::string& message)
273 {
274 std::size_t pos = message.find("Authorization");
275 if (pos != std::string::npos) {
276 if ((pos = message.find("response=")) != std::string::npos) {
277 auth_response_ = message.substr(pos + 10, 32);
278 if (auth_response_.size() == 32) {
279 return true;
280 }
281 }
282 }
283
284 auth_response_.clear();
285 return false;
286 }
287
GetCSeq() const288 uint32_t RtspRequest::GetCSeq() const
289 {
290 uint32_t cseq = 0;
291 auto iter = header_line_param_.find("cseq");
292 if(iter != header_line_param_.end()) {
293 cseq = iter->second.second;
294 }
295
296 return cseq;
297 }
298
GetIp() const299 std::string RtspRequest::GetIp() const
300 {
301 auto iter = request_line_param_.find("url_ip");
302 if(iter != request_line_param_.end()) {
303 return iter->second.first;
304 }
305
306 return "";
307 }
308
GetRtspUrl() const309 std::string RtspRequest::GetRtspUrl() const
310 {
311 auto iter = request_line_param_.find("url");
312 if(iter != request_line_param_.end()) {
313 return iter->second.first;
314 }
315
316 return "";
317 }
318
GetRtspUrlSuffix() const319 std::string RtspRequest::GetRtspUrlSuffix() const
320 {
321 auto iter = request_line_param_.find("url_suffix");
322 if(iter != request_line_param_.end()) {
323 return iter->second.first;
324 }
325
326 return "";
327 }
328
GetRtspUrlSession() const329 std::string RtspRequest::GetRtspUrlSession() const
330 {
331 auto iter = request_line_param_.find("url_suffix");
332 if(iter != request_line_param_.end()) {
333 int found = iter->second.first.find('?');
334 if (found != std::string::npos)
335 return iter->second.first.substr(0, found);
336 return iter->second.first;
337 }
338
339 return "";
340 }
341
GetRtspUrlQueryString() const342 std::string RtspRequest::GetRtspUrlQueryString() const
343 {
344 auto iter = request_line_param_.find("url_suffix");
345 if(iter != request_line_param_.end()) {
346 int found = iter->second.first.find('?');
347 if (found != std::string::npos)
348 return iter->second.first.substr(found+1, std::string::npos);
349 }
350
351 return "";
352 }
353
GetAuthResponse() const354 std::string RtspRequest::GetAuthResponse() const
355 {
356 return auth_response_;
357 }
358
GetRtpChannel() const359 uint8_t RtspRequest::GetRtpChannel() const
360 {
361 auto iter = header_line_param_.find("rtp_channel");
362 if(iter != header_line_param_.end()) {
363 return iter->second.second;
364 }
365
366 return 0;
367 }
368
GetRtcpChannel() const369 uint8_t RtspRequest::GetRtcpChannel() const
370 {
371 auto iter = header_line_param_.find("rtcp_channel");
372 if(iter != header_line_param_.end()) {
373 return iter->second.second;
374 }
375
376 return 0;
377 }
378
GetRtpPort() const379 uint16_t RtspRequest::GetRtpPort() const
380 {
381 auto iter = header_line_param_.find("rtp_port");
382 if(iter != header_line_param_.end()) {
383 return iter->second.second;
384 }
385
386 return 0;
387 }
388
GetRtcpPort() const389 uint16_t RtspRequest::GetRtcpPort() const
390 {
391 auto iter = header_line_param_.find("rtcp_port");
392 if(iter != header_line_param_.end()) {
393 return iter->second.second;
394 }
395
396 return 0;
397 }
398
BuildOptionRes(const char * buf,int buf_size)399 int RtspRequest::BuildOptionRes(const char* buf, int buf_size)
400 {
401 memset((void*)buf, 0, buf_size);
402 snprintf((char*)buf, buf_size,
403 "RTSP/1.0 200 OK\r\n"
404 "CSeq: %u\r\n"
405 "Public: OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY\r\n"
406 "\r\n",
407 this->GetCSeq());
408
409 return (int)strlen(buf);
410 }
411
BuildDescribeRes(const char * buf,int buf_size,const char * sdp)412 int RtspRequest::BuildDescribeRes(const char* buf, int buf_size, const char* sdp)
413 {
414 memset((void*)buf, 0, buf_size);
415 snprintf((char*)buf, buf_size,
416 "RTSP/1.0 200 OK\r\n"
417 "CSeq: %u\r\n"
418 "Content-Length: %d\r\n"
419 "Content-Type: application/sdp\r\n"
420 "\r\n"
421 "%s",
422 this->GetCSeq(),
423 (int)strlen(sdp),
424 sdp);
425
426 return (int)strlen(buf);
427 }
428
BuildSetupMulticastRes(const char * buf,int buf_size,const char * multicast_ip,uint16_t port,uint32_t session_id)429 int RtspRequest::BuildSetupMulticastRes(const char* buf, int buf_size, const char* multicast_ip, uint16_t port, uint32_t session_id)
430 {
431 memset((void*)buf, 0, buf_size);
432 snprintf((char*)buf, buf_size,
433 "RTSP/1.0 200 OK\r\n"
434 "CSeq: %u\r\n"
435 "Transport: RTP/AVP;multicast;destination=%s;source=%s;port=%u-0;ttl=255\r\n"
436 "Session: %u\r\n"
437 "\r\n",
438 this->GetCSeq(),
439 multicast_ip,
440 this->GetIp().c_str(),
441 port,
442 session_id);
443
444 return (int)strlen(buf);
445 }
446
BuildSetupUdpRes(const char * buf,int buf_size,uint16_t rtp_chn,uint16_t rtcp_chn,uint32_t session_id)447 int RtspRequest::BuildSetupUdpRes(const char* buf, int buf_size, uint16_t rtp_chn, uint16_t rtcp_chn, uint32_t session_id)
448 {
449 memset((void*)buf, 0, buf_size);
450 snprintf((char*)buf, buf_size,
451 "RTSP/1.0 200 OK\r\n"
452 "CSeq: %u\r\n"
453 "Transport: RTP/AVP;unicast;client_port=%hu-%hu;server_port=%hu-%hu\r\n"
454 "Session: %u\r\n"
455 "\r\n",
456 this->GetCSeq(),
457 this->GetRtpPort(),
458 this->GetRtcpPort(),
459 rtp_chn,
460 rtcp_chn,
461 session_id);
462
463 return (int)strlen(buf);
464 }
465
BuildSetupTcpRes(const char * buf,int buf_size,uint16_t rtp_chn,uint16_t rtcp_chn,uint32_t session_id)466 int RtspRequest::BuildSetupTcpRes(const char* buf, int buf_size, uint16_t rtp_chn, uint16_t rtcp_chn, uint32_t session_id)
467 {
468 memset((void*)buf, 0, buf_size);
469 snprintf((char*)buf, buf_size,
470 "RTSP/1.0 200 OK\r\n"
471 "CSeq: %u\r\n"
472 "Transport: RTP/AVP/TCP;unicast;interleaved=%d-%d\r\n"
473 "Session: %u\r\n"
474 "\r\n",
475 this->GetCSeq(),
476 rtp_chn, rtcp_chn,
477 session_id);
478
479 return (int)strlen(buf);
480 }
481
BuildPlayRes(const char * buf,int buf_size,const char * rtpInfo,uint32_t session_id)482 int RtspRequest::BuildPlayRes(const char* buf, int buf_size, const char* rtpInfo, uint32_t session_id)
483 {
484 memset((void*)buf, 0, buf_size);
485 snprintf((char*)buf, buf_size,
486 "RTSP/1.0 200 OK\r\n"
487 "CSeq: %d\r\n"
488 "Range: npt=0.000-\r\n"
489 "Session: %u; timeout=60\r\n",
490 this->GetCSeq(),
491 session_id);
492
493 if (rtpInfo != nullptr) {
494 snprintf((char*)buf + strlen(buf), buf_size - strlen(buf), "%s\r\n", rtpInfo);
495 }
496
497 snprintf((char*)buf + strlen(buf), buf_size - strlen(buf), "\r\n");
498 return (int)strlen(buf);
499 }
500
BuildTeardownRes(const char * buf,int buf_size,uint32_t session_id)501 int RtspRequest::BuildTeardownRes(const char* buf, int buf_size, uint32_t session_id)
502 {
503 memset((void*)buf, 0, buf_size);
504 snprintf((char*)buf, buf_size,
505 "RTSP/1.0 200 OK\r\n"
506 "CSeq: %d\r\n"
507 "Session: %u\r\n"
508 "\r\n",
509 this->GetCSeq(),
510 session_id);
511
512 return (int)strlen(buf);
513 }
514
BuildGetParamterRes(const char * buf,int buf_size,uint32_t session_id)515 int RtspRequest::BuildGetParamterRes(const char* buf, int buf_size, uint32_t session_id)
516 {
517 memset((void*)buf, 0, buf_size);
518 snprintf((char*)buf, buf_size,
519 "RTSP/1.0 200 OK\r\n"
520 "CSeq: %d\r\n"
521 "Session: %u\r\n"
522 "\r\n",
523 this->GetCSeq(),
524 session_id);
525
526 return (int)strlen(buf);
527 }
528
BuildNotFoundRes(const char * buf,int buf_size)529 int RtspRequest::BuildNotFoundRes(const char* buf, int buf_size)
530 {
531 memset((void*)buf, 0, buf_size);
532 snprintf((char*)buf, buf_size,
533 "RTSP/1.0 404 Stream Not Found\r\n"
534 "CSeq: %u\r\n"
535 "\r\n",
536 this->GetCSeq());
537
538 return (int)strlen(buf);
539 }
540
BuildServerErrorRes(const char * buf,int buf_size)541 int RtspRequest::BuildServerErrorRes(const char* buf, int buf_size)
542 {
543 memset((void*)buf, 0, buf_size);
544 snprintf((char*)buf, buf_size,
545 "RTSP/1.0 500 Internal Server Error\r\n"
546 "CSeq: %u\r\n"
547 "\r\n",
548 this->GetCSeq());
549
550 return (int)strlen(buf);
551 }
552
BuildUnsupportedRes(const char * buf,int buf_size)553 int RtspRequest::BuildUnsupportedRes(const char* buf, int buf_size)
554 {
555 memset((void*)buf, 0, buf_size);
556 snprintf((char*)buf, buf_size,
557 "RTSP/1.0 461 Unsupported transport\r\n"
558 "CSeq: %d\r\n"
559 "\r\n",
560 this->GetCSeq());
561
562 return (int)strlen(buf);
563 }
564
BuildUnauthorizedRes(const char * buf,size_t buf_size)565 size_t RtspRequest::BuildUnauthorizedRes(const char *buf, size_t buf_size)
566 {
567 snprintf((char*)buf, buf_size,
568 "RTSP/1.0 401 Unauthorized\r\n"
569 "CSeq: %d\r\n"
570 "\r\n",
571 this->GetCSeq()
572 );
573
574 return strlen(buf);
575 }
576
BuildUnauthorizedRes(const char * buf,size_t buf_size,const char * realm,const char * nonce)577 size_t RtspRequest::BuildUnauthorizedRes(const char* buf, size_t buf_size, const char* realm, const char* nonce)
578 {
579 memset((void*)buf, 0, buf_size);
580 snprintf((char*)buf, buf_size,
581 "RTSP/1.0 401 Unauthorized\r\n"
582 "CSeq: %d\r\n"
583 "WWW-Authenticate: Digest realm=\"%s\", nonce=\"%s\"\r\n"
584 "\r\n",
585 this->GetCSeq(),
586 realm,
587 nonce);
588
589 return strlen(buf);
590 }
591
ParseResponse(xop::BufferReader * buffer)592 bool RtspResponse::ParseResponse(xop::BufferReader *buffer)
593 {
594 if (strstr(buffer->Peek(), "\r\n\r\n") != NULL) {
595 if (strstr(buffer->Peek(), "OK") == NULL) {
596 return false;
597 }
598
599 char* ptr = strstr(buffer->Peek(), "Session");
600 if (ptr != NULL) {
601 char session_id[50] = {0};
602 if (sscanf(ptr, "%*[^:]: %s", session_id) == 1)
603 session_ = session_id;
604 }
605
606 cseq_++;
607 buffer->RetrieveUntil("\r\n\r\n");
608 }
609
610 return true;
611 }
612
BuildOptionReq(const char * buf,int buf_size)613 int RtspResponse::BuildOptionReq(const char* buf, int buf_size)
614 {
615 memset((void*)buf, 0, buf_size);
616 snprintf((char*)buf, buf_size,
617 "OPTIONS %s RTSP/1.0\r\n"
618 "CSeq: %u\r\n"
619 "User-Agent: %s\r\n"
620 "\r\n",
621 rtsp_url_.c_str(),
622 this->GetCSeq() + 1,
623 user_agent_.c_str());
624
625 method_ = OPTIONS;
626 return (int)strlen(buf);
627 }
628
BuildAnnounceReq(const char * buf,int buf_size,const char * sdp)629 int RtspResponse::BuildAnnounceReq(const char* buf, int buf_size, const char *sdp)
630 {
631 memset((void*)buf, 0, buf_size);
632 snprintf((char*)buf, buf_size,
633 "ANNOUNCE %s RTSP/1.0\r\n"
634 "Content-Type: application/sdp\r\n"
635 "CSeq: %u\r\n"
636 "User-Agent: %s\r\n"
637 "Session: %s\r\n"
638 "Content-Length: %d\r\n"
639 "\r\n"
640 "%s",
641 rtsp_url_.c_str(),
642 this->GetCSeq() + 1,
643 user_agent_.c_str(),
644 this->GetSession().c_str(),
645 (int)strlen(sdp),
646 sdp);
647
648 method_ = ANNOUNCE;
649 return (int)strlen(buf);
650 }
651
BuildDescribeReq(const char * buf,int buf_size)652 int RtspResponse::BuildDescribeReq(const char* buf, int buf_size)
653 {
654 memset((void*)buf, 0, buf_size);
655 snprintf((char*)buf, buf_size,
656 "DESCRIBE %s RTSP/1.0\r\n"
657 "CSeq: %u\r\n"
658 "Accept: application/sdp\r\n"
659 "User-Agent: %s\r\n"
660 "\r\n",
661 rtsp_url_.c_str(),
662 this->GetCSeq() + 1,
663 user_agent_.c_str());
664
665 method_ = DESCRIBE;
666 return (int)strlen(buf);
667 }
668
BuildSetupTcpReq(const char * buf,int buf_size,int trackId)669 int RtspResponse::BuildSetupTcpReq(const char* buf, int buf_size, int trackId)
670 {
671 int interleaved[2] = { 0, 1 };
672 if (trackId == 1) {
673 interleaved[0] = 2;
674 interleaved[1] = 3;
675 }
676
677 memset((void*)buf, 0, buf_size);
678 snprintf((char*)buf, buf_size,
679 "SETUP %s/track%d RTSP/1.0\r\n"
680 "Transport: RTP/AVP/TCP;unicast;mode=record;interleaved=%d-%d\r\n"
681 "CSeq: %u\r\n"
682 "User-Agent: %s\r\n"
683 "Session: %s\r\n"
684 "\r\n",
685 rtsp_url_.c_str(),
686 trackId,
687 interleaved[0],
688 interleaved[1],
689 this->GetCSeq() + 1,
690 user_agent_.c_str(),
691 this->GetSession().c_str());
692
693 method_ = SETUP;
694 return (int)strlen(buf);
695 }
696
BuildRecordReq(const char * buf,int buf_size)697 int RtspResponse::BuildRecordReq(const char* buf, int buf_size)
698 {
699 memset((void*)buf, 0, buf_size);
700 snprintf((char*)buf, buf_size,
701 "RECORD %s RTSP/1.0\r\n"
702 "Range: npt=0.000-\r\n"
703 "CSeq: %u\r\n"
704 "User-Agent: %s\r\n"
705 "Session: %s\r\n"
706 "\r\n",
707 rtsp_url_.c_str(),
708 this->GetCSeq() + 1,
709 user_agent_.c_str(),
710 this->GetSession().c_str());
711
712 method_ = RECORD;
713 return (int)strlen(buf);
714 }
715