1 /* ------------------------------------------------------------------
2 * Copyright (C) 1998-2009 PacketVideo
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
13 * express or implied.
14 * See the License for the specific language governing permissions
15 * and limitations under the License.
16 * -------------------------------------------------------------------
17 */
18
19 #include "rtsp_par_com.h"
20 #include "oscl_string_utils.h"
21 #include "rtsp_range_utils.h"
22
23 OSCL_EXPORT_REF void
reset()24 RTSPIncomingMessage::reset()
25 {
26 RTSPGenericMessage::reset();
27
28 #ifdef RTSP_PLAYLIST_SUPPORT
29 playlistRangeField.setPtrLen("", 0);
30 playlistRangeFieldIsSet = false;
31 // need to figure out how to store all the error fields.. we may not actually need to
32 playlistErrorFieldIsSet = false;
33 playlistErrorFieldCount = 0;
34 for (int ii = 0; ii < RTSP_MAX_NUMBER_OF_PLAYLIST_ERROR_ENTRIES; ++ii)
35 {
36 playlistErrorField[ii].setPtrLen("", 0);
37 }
38
39 supportedFieldIsSet = false;
40 numOfSupportedEntries = 0;
41 for (int jj = 0; jj < RTSP_MAX_NUMBER_OF_SUPPORTED_ENTRIES; ++jj)
42 {
43 supportedField[jj].setPtrLen("", 0);
44 }
45
46 playlistRangeUrl.setPtrLen("", 0);
47 playlistRangeClipIndex = 0;
48 playlistRangeClipOffset = 0;
49 playlistRangeNptTime = 0;
50 #endif
51
52 amMalformed = RTSPOk;
53 rtspVersionString = "";
54 }
55
56 void
parseFirstFields()57 RTSPIncomingMessage::parseFirstFields()
58 {
59
60 char * endOfString;
61
62 // The first thing to do is to parse the status line;
63 // the rest of the parsing (regular fields) can be parsed out by
64 // parseNextPortion() method, since it has to know how to do that anyway.
65 // We also have to find out if Content-length is there, etc.
66
67 // so, let's set up the pointers first
68 //
69 secondaryBufferSpace = secondaryBuffer;
70 if (CHAR_CR == *secondaryBufferSpace)
71 {
72 ++secondaryBufferSpace;
73 }
74 if (CHAR_LF == *secondaryBufferSpace)
75 {
76 ++secondaryBufferSpace;
77 }
78
79 #ifdef SIMPLE_HTTP_SUPPORT
80 if (secondaryBufferSizeUsed >= 4)
81 {// Real http cloaking. H\02\00\00
82 if (('H' != secondaryBufferSpace[0])
83 || ('T' != secondaryBufferSpace[1])
84 || ('T' != secondaryBufferSpace[2])
85 || ('P' != secondaryBufferSpace[3])
86 )
87 {
88 if ('H' == secondaryBufferSpace[0])
89 {//HTTP_RESPONSE
90 uint32 nOptionLen = secondaryBufferSpace[1];
91 secondaryBufferSpace += (2 + nOptionLen);
92 }
93 /* TBD
94 else if('r' == secondaryBufferSpace[0])
95 {//HTTP_RV_RESPONSE
96 }
97 */
98 }
99 }
100 #endif
101
102 numPtrFields = 0;
103
104 char * wordPtr[3] = { NULL, NULL, NULL };
105 char * endOfLine;
106 int wordCount;
107 bool wordCountTrigger;
108
109 for (endOfLine = secondaryBufferSpace, wordCount = 0, wordCountTrigger = true;
110 (endOfLine < secondaryBufferSpace + secondaryBufferSizeUsed)
111 && (CHAR_CR != *endOfLine)
112 && (CHAR_LF != *endOfLine);
113 ++endOfLine
114 )
115 {
116 switch (wordCountTrigger)
117 {
118 case true: // if non-space, then it's a beginning of a new word
119 {
120 if ((*endOfLine >= 0x09 && *endOfLine <= 0x0D) || *endOfLine == 0x20)
121 { // spaces
122 }
123 else
124 { // word
125 if (3 > wordCount)
126 {
127 wordPtr[wordCount] = endOfLine;
128 }
129 ++wordCount;
130
131 // uncock the trigger
132 wordCountTrigger = false;
133 }
134
135 break;
136 }
137
138 case false: // if space, then cock the trigger
139 {
140 if ((*endOfLine >= 0x09 && *endOfLine <= 0x0D) || *endOfLine == 0x20)
141 { // yeah, space
142 wordCountTrigger = true;
143 }
144 else
145 { // still a word
146 }
147 break;
148 }
149
150 default:
151 // ERROR: internal inconsistency, a switch on a boolean should not hit
152 // this point
153 ;;
154 }
155 }
156
157 if (3 > wordCount)
158 { // only two words in the status line - error
159
160 amMalformed = RTSPErrorSyntax;
161 return;
162 }
163
164 if (CHAR_CR == *endOfLine)
165 {
166 *(endOfLine++) = CHAR_NULL;
167 if (CHAR_LF == *endOfLine)
168 {
169 *(endOfLine++) = CHAR_NULL;
170 }
171 }
172 else if (CHAR_LF == *endOfLine)
173 {
174 *(endOfLine++) = CHAR_NULL;
175 }
176 else
177 {
178 // ran to the end of input, didn't find a single newline....
179 // most probably the message was too big to handle, but parser still
180 // created a message hoping that at least something can be found...
181 //
182
183 amMalformed = RTSPErrorSyntax;
184
185 return;
186 }
187
188
189
190 // figure out the format of the message - request or response?
191 //
192 // make out the first word... don't forget about '$'
193 //
194
195 //// endOfString = secondaryBufferSpace;
196 //// while( ! isspace(*endOfString) )
197 //// ++endOfString;
198
199 endOfString = wordPtr[1];
200 while (--endOfString >= secondaryBufferSpace
201 && ((*endOfString >= 0x09 && *endOfString <= 0x0D) || *endOfString == 0x20)
202 )
203 {
204 *endOfString = CHAR_NULL;
205 }
206
207 //// *endOfString = CHAR_NULL;
208 //// StrCSumPtrLen firstWordPLSS = secondaryBufferSpace;
209 StrCSumPtrLen firstWordPLSS = wordPtr[0];
210
211 if (('R' == *(wordPtr[0]))
212 && ('T' == *(wordPtr[0] + 1))
213 && ('S' == *(wordPtr[0] + 2))
214 && ('P' == *(wordPtr[0] + 3))
215 && ('/' == *(wordPtr[0] + 4))
216 )
217 {
218 // it has to be a response
219 //
220 msgType = RTSPResponseMsg;
221 rtspVersionString = firstWordPLSS;
222
223 // if there is a mismatch, let the Engine know about it and stop parsing
224 if (rtspVersionString != RTSPVersionString)
225 {
226 amMalformed = RTSPErrorVersion;
227 return;
228 }
229
230 // get the code
231 //// secondaryBufferSpace = endOfString+1;
232 //// while( isspace(*secondaryBufferSpace) )
233 //// {
234 //// ++secondaryBufferSpace;
235 //// }
236
237 //// statusCode = atoi( secondaryBufferSpace );
238 uint32 atoi_tmp;
239 PV_atoi(wordPtr[1], 'd', atoi_tmp);
240 statusCode = (RTSPStatusCode)atoi_tmp;
241
242 // get the reason string
243
244 //// while( ! isspace( *secondaryBufferSpace ) )
245 //// {
246 //// ++secondaryBufferSpace;
247 //// }
248
249 //// while( isspace( *secondaryBufferSpace ) )
250 //// {
251 //// ++secondaryBufferSpace;
252 //// }
253
254 //// endOfString = secondaryBufferSpace;
255 //// while( (CHAR_CR != *endOfString)
256 //// && (CHAR_LF != *endOfString)
257 //// )
258 //// {
259 //// ++endOfString;
260 //// }
261
262 //// *endOfString = CHAR_NULL;
263 //// reasonString = secondaryBufferSpace;
264 reasonString = wordPtr[2];
265
266 // now, resync to the next line
267 //// secondaryBufferSpace = endOfString+1;
268 //// if( CHAR_LF == *secondaryBufferSpace )
269 //// {
270 //// ++secondaryBufferSpace;
271 //// }
272
273 secondaryBufferSpace = endOfLine;
274 }
275 #ifdef SIMPLE_HTTP_SUPPORT
276 else if (('H' == *(wordPtr[0]))
277 && ('T' == *(wordPtr[0] + 1))
278 && ('T' == *(wordPtr[0] + 2))
279 && ('P' == *(wordPtr[0] + 3))
280 && ('/' == *(wordPtr[0] + 4))
281 )
282 {
283 msgType = RTSPResponseMsg;
284 rtspVersionString = firstWordPLSS;
285
286 // if there is a mismatch, let the Engine know about it and stop parsing
287 if ((rtspVersionString != HTTPVersion_1_0_String)
288 && (rtspVersionString != HTTPVersion_1_1_String))
289 {
290 amMalformed = RTSPErrorVersion;
291 return;
292 }
293 uint32 atoi_tmp;
294 PV_atoi(wordPtr[1], 'd', atoi_tmp);
295 statusCode = (RTSPStatusCode)atoi_tmp;
296 reasonString = wordPtr[2];
297 secondaryBufferSpace = endOfLine;
298 }
299 #endif
300 else
301 { // okay, it could be a request
302
303 // but for requests there must be exactly three words on the
304 // status line
305 if (3 != wordCount)
306 {
307 amMalformed = RTSPErrorSyntax;
308 return;
309 }
310
311 msgType = RTSPRequestMsg;
312
313 methodString = firstWordPLSS;
314
315 if (firstWordPLSS == RtspRequestMethodStringDescribe)
316 {
317 method = METHOD_DESCRIBE;
318 }
319 else if (firstWordPLSS == RtspRequestMethodStringGetParameter)
320 {
321 method = METHOD_GET_PARAMETER;
322 }
323 else if (firstWordPLSS == RtspRequestMethodStringOptions)
324 {
325 method = METHOD_OPTIONS;
326 }
327 else if (firstWordPLSS == RtspRequestMethodStringPause)
328 {
329 method = METHOD_PAUSE;
330 }
331 else if (firstWordPLSS == RtspRequestMethodStringPlay)
332 {
333 method = METHOD_PLAY;
334 }
335 else if (firstWordPLSS == RtspRequestMethodStringSetup)
336 {
337 method = METHOD_SETUP;
338 }
339 else if (firstWordPLSS == RtspRequestMethodStringRecord)
340 {
341 method = METHOD_RECORD;
342 }
343 else if (firstWordPLSS == RtspRequestMethodStringTeardown)
344 {
345 method = METHOD_TEARDOWN;
346 }
347 else if (firstWordPLSS == RtspRequestMethodStringEndOfStream)
348 {
349 method = METHOD_END_OF_STREAM;
350 }
351 /* TBD: add Announce, SetParameter and Redirect later
352 else if( firstWordPLSS == RtspRequestMethodStringAnnounce )
353 {
354 method = METHOD_ANNOUNCE;
355 }
356 */
357 else if (firstWordPLSS == RtspRequestMethodStringSetParameter)
358 {
359 method = METHOD_SET_PARAMETER;
360 }
361
362 else if (firstWordPLSS == RtspRequestMethodStringRedirect) //SS
363 {
364 method = METHOD_REDIRECT; ////SS
365 }
366 // now, we could put binary data here, but it's not exactly the same
367 // thing; since it requires special care, let's not confuse things by
368 // putting generic-looking stuff here
369 else
370 {
371 method = METHOD_UNRECOGNIZED;
372 }
373
374 // get the URI
375
376 //// secondaryBufferSpace = endOfString +1;
377 //// while( isspace( *secondaryBufferSpace ) )
378 //// {
379 //// ++secondaryBufferSpace;
380 //// }
381
382 //// endOfString = secondaryBufferSpace;
383 //// while( ! isspace( *endOfString ) )
384 //// {
385 //// ++endOfString;
386 //// }
387 //// *endOfString = CHAR_NULL;
388
389 //// originalURI = secondaryBufferSpace;
390 endOfString = wordPtr[2];
391 while ((--endOfString) >= wordPtr[1]
392 && ((*endOfString >= 0x09 && *endOfString <= 0x0D) || *endOfString == 0x20)
393 )
394 {
395 *endOfString = CHAR_NULL;
396 }
397 originalURI = wordPtr[1];
398
399 // get the RTSP version
400 //// secondaryBufferSpace = endOfString +1;
401 //// while( isspace( *secondaryBufferSpace ) )
402 //// {
403 //// ++secondaryBufferSpace;
404 //// }
405 //// endOfString = secondaryBufferSpace;
406 //// while( !isspace(*endOfString) )
407 //// {
408 //// ++endOfString;
409 //// }
410
411 //// *endOfString = CHAR_NULL;
412 //// rtspVersionString = secondaryBufferSpace;
413 endOfString = endOfLine;
414 while (--endOfString >= wordPtr[2]
415 && (((*endOfString >= 0x09 && *endOfString <= 0x0D) || *endOfString == 0x20)
416 || CHAR_NULL == *endOfString
417 )
418 )
419 {
420 *endOfString = CHAR_NULL;
421 }
422 rtspVersionString = wordPtr[2];
423
424 // if there is a mismatch, let the Engine know about it and stop parsing
425 if (rtspVersionString != RTSPVersionString)
426 {
427 amMalformed = RTSPErrorVersion;
428 return;
429 }
430
431 // now, resync to the next line
432 //// secondaryBufferSpace = endOfString + 1;
433 //// if( CHAR_LF == *secondaryBufferSpace )
434 //// {
435 //// ++secondaryBufferSpace;
436 //// }
437 secondaryBufferSpace = endOfLine;
438
439 // extra URI validation
440 {
441 if (1 == originalURI.length())
442 { // Is it a star
443 if (CHAR_STAR != originalURI.c_str()[0])
444 {
445 amMalformed = RTSPErrorSyntax;
446 return;
447 }
448 }
449 else
450 { // it's a normal URI
451
452 // let's validate the scheme
453 char colonStr[2];
454 colonStr[0] = CHAR_COLON;
455 colonStr[1] = NULL_TERM_CHAR;
456 const char * colonPtr = oscl_strstr(originalURI.c_str(), colonStr);
457 if (NULL == colonPtr)
458 {
459 // no colon
460 amMalformed = RTSPErrorSyntax;
461 return;
462 }
463
464 // now, the first character of the scheme is a character
465 const char * ptr = originalURI.c_str();
466 if (!((*ptr >= 'A' && *ptr <= 'Z') || (*ptr >= 'a' && *ptr <= 'z')))
467
468 {
469 // the URI doesn't start with a character
470 amMalformed = RTSPErrorSyntax;
471 return;
472 }
473
474 // the rest of the characters must be either characters, or
475 // plus/minus, or dots...
476 for (++ptr; ptr < colonPtr; ++ptr)
477 {
478 if (!(((*ptr >= 'A' && *ptr <= 'Z') || (*ptr >= 'a' && *ptr <= 'z'))
479 || (*ptr >= '0' || *ptr <= '9')
480 || CHAR_PLUS == *ptr
481 || CHAR_MINUS == *ptr
482 || CHAR_DOT == *ptr
483 ))
484 {
485 amMalformed = RTSPErrorSyntax;
486 return;
487 }
488 }
489 }
490 }
491
492 // finish off the URI processing
493
494 {
495 // look for the base
496 uint32 ii;
497 int32 ee;
498 uint32 length = originalURI.length();
499
500 for (ii = 0; ii < length; ++ii)
501 {
502 if (CHAR_SLASH == originalURI.c_str()[ii])
503 {
504 if (CHAR_SLASH != originalURI.c_str()[++ii])
505 {
506 break;
507 }
508 else
509 { // no, it's a separator, skip over it, continue
510 }
511 }
512 }
513 originalURIBase = originalURI.c_str() + ii;
514
515 // look for the control candidate
516 for (ee = originalURIBase.length() - 1;
517 ee >= 0;
518 --ee
519 )
520 {
521 if ((CHAR_SLASH == originalURIBase.c_str()[ee])
522 || (CHAR_SEMICOLON == originalURIBase.c_str()[ee])
523 )
524 {
525 break;
526 }
527 }
528 originalURIControlCandidate = originalURIBase.c_str() + ee + 1;
529
530 }
531 }
532
533
534 // determine the total number of fields remaining to be seen
535
536 endOfString = secondaryBuffer + secondaryBufferSizeUsed;
537 *(--endOfString) = CHAR_NULL;
538 --secondaryBufferSizeUsed;
539 if (CHAR_CR == *(endOfString - 1))
540 {
541 *(--endOfString) = CHAR_NULL;
542 --secondaryBufferSizeUsed;
543 }
544
545
546 totalFields = 0;
547 for (char * ptr = secondaryBufferSpace; ptr < endOfString; ++ptr)
548 {
549 if (CHAR_LF == *ptr)
550 {
551 ++totalFields;
552 }
553 else if (CHAR_CR == *ptr)
554 {
555 if (CHAR_LF != *(ptr + 1))
556 {
557 ++totalFields;
558 }
559 }
560 }
561
562 totalFieldsParsed = 0;
563 parseNextPortion();
564
565 if (getTotalFields() != getTotalFieldsParsed())
566 {
567 amMalformed = RTSPErrorTooManyFields;
568 }
569 }
570
571 bool
parseNextPortion()572 RTSPIncomingMessage::parseNextPortion()
573 {
574 if (totalFieldsParsed == totalFields)
575 {
576 return false;
577 }
578
579 char * endOfMessage = secondaryBuffer + secondaryBufferSizeUsed;
580 char * ptr = secondaryBufferSpace;
581
582 // printf ("parcom::parseNextPortion: secondaryBuffer is \n %s \n",secondaryBuffer);
583
584
585 for (numPtrFields = 0;
586 (numPtrFields < RTSP_MAX_NUMBER_OF_FIELDS) && (ptr < endOfMessage);
587 ++numPtrFields)
588 {
589 char *endOfValue = ptr;
590 while (CHAR_LF != *(endOfValue)
591 && CHAR_CR != *(endOfValue)
592 && CHAR_NULL != *(endOfValue))
593 {
594 ++endOfValue;
595 }
596
597 if (CHAR_CR == *(endOfValue) && CHAR_LF == *(endOfValue + 1))
598 {
599 // need to increment endOfValue for CR-LF, because
600 // it is needed later to step into the next field by shifting by 1
601 *(endOfValue) = CHAR_NULL;
602 *(++endOfValue) = CHAR_NULL;
603 }
604 else
605 {
606 *endOfValue = CHAR_NULL;
607 }
608
609 char * separator = ptr;
610
611 while ((CHAR_COLON != *separator) && (CHAR_NULL != *separator))
612 {
613 ++separator;
614 }
615
616 if (CHAR_COLON != *separator)
617 {
618 //amMalformed = RTSPErrorSyntax;
619 //ignore the unknown lines
620 ptr = endOfValue + 1;
621 continue;
622 }
623 else
624 {
625 *separator = CHAR_NULL;
626
627 // get name pointer
628 char * namePtr = ptr;
629 // eat through trailing whitespace
630 for (char * wPtr1 = separator - 1;
631 (wPtr1 >= namePtr) && ((*wPtr1 >= 0x09 && *wPtr1 <= 0x0D) || *wPtr1 == 0x20);
632 --wPtr1)
633 {
634 *wPtr1 = CHAR_NULL;
635 }
636 // eat through leading whitespace
637 while ((*namePtr >= 0x09 && *namePtr <= 0x0D) || *namePtr == 0x20)
638 {
639 ++namePtr;
640 }
641
642 // get value pointer
643 char * valuePtr = separator + 1;
644 // eat through trailing whitespace
645 for (char * wPtr2 = endOfValue - 1;
646 (wPtr2 > separator)
647 && ((*wPtr2 >= 0x09 && *wPtr2 <= 0x0D) || *wPtr2 == 0x20);
648 --wPtr2)
649 {
650 *wPtr2 = CHAR_NULL;
651 }
652 //eat through leading whitespace
653 while ((*valuePtr >= 0x09 && *valuePtr <= 0x0D) || *valuePtr == 0x20)
654 {
655 ++valuePtr;
656 }
657
658 // all right, set the pointers
659
660 fieldKeys[ numPtrFields ] = namePtr;
661 fieldVals[ numPtrFields ] = valuePtr;
662
663 // determine if we are supposed to recognize this
664 if (fieldKeys[ numPtrFields ].isCIEquivalentTo(
665 RtspRecognizedFieldSessionId))
666 {
667 {
668 StrPtrLen tmp = fieldVals[ numPtrFields ];
669 int Len = tmp.length();
670 char * beginPtr = (char*)tmp.c_str();
671 char * endPtr = beginPtr + Len;
672
673 while (beginPtr < endPtr)
674 {
675 if (*beginPtr == ';')
676 {//we got timeout field
677 while (beginPtr < endPtr)
678 {
679 if ((*beginPtr == 't') && (beginPtr[6] == 't'))
680 {//a little bit validation
681 beginPtr += 8;
682 PV_atoi(beginPtr, 'd', timeout);
683 beginPtr = endPtr;
684 }
685 beginPtr++;
686 }
687 }
688 beginPtr++;
689 }
690 }
691 sessionId = fieldVals[ numPtrFields ];
692 sessionIdIsSet = true;
693 }
694 if (fieldKeys[ numPtrFields ].isCIEquivalentTo(
695 RtspRecognizedFieldCSeq))
696 {
697 PV_atoi(valuePtr, 'd', cseq);
698 cseqIsSet = true;
699 }
700 if (fieldKeys[ numPtrFields ].isCIEquivalentTo(
701 RtspRecognizedFieldBufferSize
702 ))
703 {
704 PV_atoi(valuePtr, 'd', bufferSize);
705 bufferSizeIsSet = true;
706 }
707 if (fieldKeys[ numPtrFields ].isCIEquivalentTo(
708 RtspRecognizedFieldContentType))
709 {
710 contentType = fieldVals[ numPtrFields ];
711 contentTypeIsSet = true;
712 }
713 if (fieldKeys[ numPtrFields ].isCIEquivalentTo(
714 RtspRecognizedFieldContentBase))
715 {
716 contentBase = fieldVals[ numPtrFields ];
717 contentBaseMode = CONTENT_BASE_SET;
718 }
719 if (fieldKeys[ numPtrFields ].isCIEquivalentTo(
720 RtspRecognizedFieldContentLength))
721 {
722 PV_atoi(valuePtr, 'd', contentLength);
723 contentLengthIsSet = true;
724 }
725 if (fieldKeys[ numPtrFields].isCIEquivalentTo(
726 RtspRecognizedFieldUserAgent))
727 {
728 userAgent = fieldVals[ numPtrFields ];
729 userAgentIsSet = true;
730 }
731 if (fieldKeys[ numPtrFields ].isCIEquivalentTo(
732 RtspRecognizedFieldAccept))
733 {
734 accept = fieldVals[ numPtrFields ];
735 acceptIsSet = true;
736 }
737 if (fieldKeys[ numPtrFields ].isCIEquivalentTo(
738 RtspRecognizedFieldRequire))
739 {
740 require = fieldVals[ numPtrFields ];
741 requireIsSet = true;
742 }
743 if (fieldKeys[ numPtrFields ].isCIEquivalentTo(
744 RtspRecognizedFieldRTPInfo
745 ))
746 {
747 parseRTPInfo(numPtrFields);
748 }
749
750 if (fieldKeys[ numPtrFields ].isCIEquivalentTo(
751 RtspRecognizedFieldRange))
752 {
753 parseRtspRange(fieldVals[ numPtrFields].c_str(), fieldVals[ numPtrFields].length(), range);
754 rangeIsSet = true;
755 }
756 if (fieldKeys[ numPtrFields ].isCIEquivalentTo(
757 RtspRecognizedFieldTransport))
758 {
759 parseTransport(numPtrFields);
760 }
761 #ifdef RTSP_PLAYLIST_SUPPORT
762 if (fieldKeys[ numPtrFields ].isCIEquivalentTo(
763 RtspRecognizedFieldSupported))
764 {
765 parseSupported(fieldVals[ numPtrFields].c_str(), fieldVals[ numPtrFields].length() + 1);
766 supportedFieldIsSet = true;
767 }
768 #endif
769 }
770
771 ptr = endOfValue + 1;
772 }
773
774 totalFieldsParsed += numPtrFields;
775
776 secondaryBufferSpace = ptr;
777
778 return true;
779 }
780
781 #ifdef RTSP_PLAYLIST_SUPPORT
782
783 void
parseSupported(const char * supportedString,int length)784 RTSPIncomingMessage::parseSupported(const char *supportedString, int length)
785 {
786 const StrPtrLen methodEosString("method.eos");
787 const StrPtrLen comPvPlaylistString("com.pv.server_playlist");
788
789 const char *end = supportedString + length;
790
791 char *sptr;//, *eptr;
792
793 sptr = (char*)supportedString;
794
795 while ((sptr < end) && (numOfSupportedEntries < RTSP_MAX_NUMBER_OF_SUPPORTED_ENTRIES))
796 {
797 char * separator = sptr;
798
799 while ((CHAR_COMMA != *separator)
800 && (CHAR_NULL != *separator)
801 && (separator < end)
802 )
803 {
804 ++separator;
805 }
806
807 if (CHAR_COMMA == *separator)
808 {
809 // make sure there is a terminating char
810 // in the other case, there will already be one because its the end of the line
811 // and the field parsing that called this function put one there
812 *separator = CHAR_NULL;
813 }
814
815 // get name pointer
816 char * namePtr = sptr;
817 // eat through trailing whitespace
818 for (char * wPtr1 = separator - 1;
819 (wPtr1 >= namePtr)
820 && ((*wPtr1 >= 0x09 && *wPtr1 <= 0x0D) || *wPtr1 == 0x20);
821 --wPtr1)
822 {
823 *wPtr1 = CHAR_NULL;
824 }
825 // eat through leading whitespace
826 while ((*namePtr >= 0x09 && *namePtr <= 0x0D) || *namePtr == 0x20)
827 {
828 ++namePtr;
829 }
830
831 supportedField[numOfSupportedEntries++] = namePtr;
832
833 if (!oscl_strncmp(namePtr, methodEosString.c_str(), methodEosString.length()))
834 {
835 methodEosIsSet = true;
836 }
837 else if (!oscl_strncmp(namePtr, comPvPlaylistString.c_str(), comPvPlaylistString.length()))
838 {
839 comPvServerPlaylistIsSet = true;
840 }
841
842 sptr = separator + 1;
843
844 } // end while
845 }
846
847 #endif /* RTSP_PLAYLIST_SUPPORT */
848
849
850 // relevant constants
851 const int MIN_CHANNEL_VALUE = 0;
852 const int MAX_CHANNEL_VALUE = 255;
853 const int PORT_MIN_VALUE = 0;
854 const int PORT_MAX_VALUE = 65535;
855
856 #define interleaved_str "interleaved="
857 #define interleaved_str_len 12
858
859 #define client_port_str "client_port="
860 #define client_port_str_len 12
861
862 #define server_port_str "server_port="
863 #define server_port_str_len 12
864
865 #define ttl_str "ttl="
866 #define ttl_str_len 4
867
868 #define mode_str "mode="
869 #define mode_str_len 5
870
871 #define port_str "port="
872 #define port_str_len 5
873
874 #define layers_str "layers="
875 #define layers_str_len 7
876
877 #define ssrc_str "ssrc="
878 #define ssrc_str_len 5
879
880 #define destination_str "destination"
881 #define destination_str_len 11
882
883 void
parseTransport(uint16 fieldIdx)884 RTSPIncomingMessage::parseTransport(uint16 fieldIdx)
885 {
886 char * cPtr;
887 char * finishPtr;
888
889 cPtr = const_cast<char*>(fieldVals[ fieldIdx ].c_str());
890 finishPtr = cPtr + fieldVals[ fieldIdx ].length();
891
892 do
893 {
894 parseOneTransportEntry(cPtr, finishPtr);
895
896 }
897 while (RTSPOk == amMalformed
898 && cPtr < finishPtr
899 );
900 }
901
902
903 void
parseOneTransportEntry(char * & trans,char * final_end)904 RTSPIncomingMessage::parseOneTransportEntry(char*& trans, char *final_end)
905 {
906 const char *startPtr, *endPtr, *nxtPtr;
907 char *transSepPtr;
908
909
910
911 // check the counter
912 //
913 if (RTSP_MAX_NUMBER_OF_TRANSPORT_ENTRIES == numOfTransportEntries)
914 { // limit reached
915 amMalformed = RTSPErrorSyntax; // should it be different?
916 return;
917 }
918
919 RtspTransport* rtspTrans = transport + numOfTransportEntries;
920 numOfTransportEntries++;
921
922 startPtr = trans;
923
924 if (*startPtr == ',')
925 {
926 // skip over any starting commas
927 ++startPtr;
928 }
929
930 rtspTrans->appendIsSet = false;
931 rtspTrans->channelIsSet = false;
932 rtspTrans->client_portIsSet = false;
933 rtspTrans->deliveryIsSet = false;
934 rtspTrans->layersIsSet = false;
935 rtspTrans->modeIsSet = false;
936 rtspTrans->portIsSet = false;
937 rtspTrans->profileIsSet = false;
938 rtspTrans->protocolIsSet = false;
939 rtspTrans->transportTypeIsSet = false;
940 rtspTrans->server_portIsSet = false;
941 rtspTrans->ttlIsSet = false;
942 rtspTrans->destinationIsSet = false;
943
944
945
946 // see if there is a tranport list separator
947 transSepPtr = OSCL_CONST_CAST(char*, oscl_strstr(startPtr, ","));
948 if (transSepPtr)
949 {
950
951 const char *quotePtr = oscl_strstr(startPtr, "\"");
952 if (quotePtr && quotePtr < transSepPtr)
953 {
954 // this may be a comma in the mode list -- so find the end of the mode list
955 const char *quote_end = oscl_strstr(quotePtr + 1, "\"");
956 if (quote_end)
957 {
958 // look for another comma
959 if (NULL != (transSepPtr = OSCL_CONST_CAST(char*, oscl_strstr(quote_end, ","))))
960 {
961 // temporarily write a terminator to separate the transport specs.
962 *transSepPtr = '\0';
963 }
964 }
965 }
966 else
967 {
968 // temporarily write a terminator to separate the transport specs.
969 *transSepPtr = '\0';
970 }
971 }
972
973
974 // for (; startPtr < final_end && isspace(*startPtr); ++startPtr);
975 for (; startPtr < final_end && ((*startPtr >= 0x09 && *startPtr <= 0x0D) || *startPtr == 0x20); ++startPtr);
976
977 do
978 {
979 if (NULL == (endPtr = oscl_strstr(startPtr, "/")))
980 {
981 endPtr = final_end;
982 }
983
984 rtspTrans->protocolIsSet = true;
985
986 if (!oscl_strncmp(startPtr, "RTP", endPtr - startPtr))
987 {
988 rtspTrans->protocol = RtspTransport::RTP_PROTOCOL;
989 }
990 else if (!oscl_strncmp(startPtr, "x-pn-tng", endPtr - startPtr))
991 {
992 rtspTrans->protocol = RtspTransport::RDT_PROTOCOL;
993 }
994 else
995 {
996 rtspTrans->protocol = RtspTransport::UNKNOWN_PROTOCOL;
997 }
998
999 if (endPtr == final_end)
1000 {
1001 break;
1002 }
1003
1004 // increment the startPtr past the separator
1005 startPtr = endPtr + 1;
1006
1007 // look for either the '/' or ';' separators
1008 endPtr = oscl_strstr(startPtr, "/");
1009 const char *endPtr2 = oscl_strstr(startPtr, ";");
1010
1011 if (!endPtr)
1012 {
1013 endPtr = endPtr2;
1014 }
1015
1016 if (endPtr2 && endPtr2 < endPtr)
1017 {
1018 endPtr = endPtr2;
1019 }
1020
1021 if (!endPtr)
1022 {
1023 endPtr = final_end;
1024 }
1025
1026 rtspTrans->profile = RtspTransport::UNKNOWN_PROFILE;
1027 rtspTrans->profileIsSet = true;
1028 if (!oscl_strncmp(startPtr, "AVP", endPtr - startPtr))
1029 {
1030 rtspTrans->profile = RtspTransport::AVP_PROFILE;
1031 }
1032 else if (!oscl_strncmp(startPtr, "tcp", endPtr - startPtr))
1033 {//RDT "x-pn-tng/tcp"
1034 rtspTrans->profile = RtspTransport::TCP_PROFILE;
1035 }
1036
1037 if (*endPtr == '/')
1038 {
1039 // there is an optional transport spec
1040 startPtr = endPtr + 1;
1041
1042 if (NULL == (endPtr = oscl_strstr(startPtr, ";")))
1043 {
1044 endPtr = final_end;
1045 }
1046
1047 rtspTrans->transportType = RtspTransport::UNKNOWN_TRANSPORT;
1048 rtspTrans->transportTypeIsSet = true;
1049
1050 if (!oscl_strncmp(startPtr, "UDP", endPtr - startPtr))
1051 {
1052 rtspTrans->transportType = RtspTransport::UDP_TRANSPORT;
1053 }
1054 else if (!oscl_strncmp(startPtr, "TCP", endPtr - startPtr))
1055 {
1056 rtspTrans->transportType = RtspTransport::TCP_TRANSPORT;
1057 }
1058 }
1059
1060 if (endPtr == final_end)
1061 {
1062 break;
1063 }
1064
1065 // increment the startPtr past the separator
1066 startPtr = endPtr + 1;
1067
1068 }
1069 while (0); // only go through this once
1070
1071
1072 while (startPtr < final_end)
1073 {
1074
1075 for (; startPtr < final_end && ((*startPtr >= 0x09 && *startPtr <= 0x0D) || *startPtr == 0x20); ++startPtr);
1076
1077 char *sepPtr;
1078 // find the next separator
1079 if (NULL == (sepPtr = (char*)(endPtr = oscl_strstr(startPtr, ";"))))
1080 {
1081 endPtr = final_end;
1082 }
1083
1084 if (sepPtr)
1085 {
1086 *sepPtr = '\0';
1087 }
1088
1089 if (!oscl_strncmp(startPtr, "unicast", endPtr - startPtr))
1090 {
1091 rtspTrans->delivery = RtspTransport::UNICAST_DELIVERY;
1092 rtspTrans->deliveryIsSet = true;
1093 }
1094 if (!oscl_strncmp(startPtr, "multicast", endPtr - startPtr))
1095 {
1096 rtspTrans->delivery = RtspTransport::MULTICAST_DELIVERY;
1097 rtspTrans->deliveryIsSet = true;
1098 }
1099 else if (!oscl_strncmp(startPtr, "append", endPtr - startPtr))
1100 {
1101 rtspTrans->append = true;
1102 rtspTrans->appendIsSet = true;
1103 }
1104 else if (!oscl_strncmp(startPtr, destination_str,
1105 destination_str_len))
1106 {
1107 nxtPtr = startPtr + destination_str_len;
1108 char *curEndPtr = OSCL_CONST_CAST(char*, oscl_strstr(nxtPtr, "="));
1109 if (curEndPtr)
1110 {
1111 nxtPtr = curEndPtr + 1;
1112
1113 // skip leading whitespace
1114 for (; nxtPtr < endPtr && ((*nxtPtr >= 0x09 && *nxtPtr <= 0x0D) || *nxtPtr == 0x20); ++nxtPtr);
1115
1116 // now find the end
1117 for (curEndPtr = (char*)nxtPtr; curEndPtr < endPtr && !((*curEndPtr >= 0x09 && *curEndPtr <= 0x0D) || *curEndPtr == 0x20);
1118 ++curEndPtr);
1119
1120 if (curEndPtr - nxtPtr > 0)
1121 {
1122 if (curEndPtr < endPtr)
1123 {
1124 *curEndPtr = '\0';
1125 }
1126 else if (sepPtr)
1127 {
1128 // clear sepPtr so it won't overwrite the NULL character
1129 sepPtr = NULL;
1130 }
1131 rtspTrans->destination.setPtrLen(nxtPtr,
1132 curEndPtr - nxtPtr);
1133 rtspTrans->destinationIsSet = true;
1134 }
1135 }
1136
1137 }
1138 else if (!oscl_strncmp(startPtr, interleaved_str,
1139 interleaved_str_len))
1140 {
1141 int tmp;
1142 nxtPtr = startPtr + interleaved_str_len;
1143 char *curEndPtr = OSCL_CONST_CAST(char*, oscl_strstr(nxtPtr, "-"));
1144 if (curEndPtr) *curEndPtr = '\0';
1145 uint32 atoi_tmp;
1146 PV_atoi(nxtPtr, 'd', atoi_tmp);
1147 tmp = atoi_tmp;
1148 if (tmp < MIN_CHANNEL_VALUE || tmp > MAX_CHANNEL_VALUE)
1149 {
1150 amMalformed = RTSPErrorSyntax;
1151 if (sepPtr)
1152 {
1153 *sepPtr = ';';
1154 };
1155 break;
1156 }
1157 rtspTrans->channel1 = tmp;
1158 if (!curEndPtr)
1159 {
1160 if (rtspTrans->channel1 >= MAX_CHANNEL_VALUE)
1161 {
1162 amMalformed = RTSPErrorSyntax;
1163 if (sepPtr)
1164 {
1165 *sepPtr = ';';
1166 };
1167 break;
1168 }
1169 rtspTrans->channel2 = rtspTrans->channel1 + 1;
1170 rtspTrans->channelIsSet = true;
1171 }
1172 else
1173 {
1174 nxtPtr = curEndPtr + 1;
1175 *curEndPtr = '-';
1176 PV_atoi(nxtPtr, 'd', atoi_tmp);
1177 tmp = atoi_tmp;
1178 if (tmp < MIN_CHANNEL_VALUE || tmp > MAX_CHANNEL_VALUE)
1179 {
1180 amMalformed = RTSPErrorSyntax;
1181 if (sepPtr)
1182 {
1183 *sepPtr = ';';
1184 };
1185 break;
1186 }
1187 rtspTrans->channel2 = tmp;
1188 rtspTrans->channelIsSet = true;
1189 }
1190 }
1191 else if (!oscl_strncmp(startPtr, client_port_str,
1192 client_port_str_len))
1193 {
1194 int tmp;
1195 uint32 atoi_tmp;
1196 nxtPtr = startPtr + client_port_str_len;
1197 char *curEndPtr = OSCL_CONST_CAST(char*, oscl_strstr(nxtPtr, "-"));
1198 if (curEndPtr) *curEndPtr = '\0';
1199 PV_atoi(nxtPtr, 'd', atoi_tmp);
1200 tmp = atoi_tmp;
1201 if (tmp < PORT_MIN_VALUE || tmp > PORT_MAX_VALUE)
1202 {
1203 amMalformed = RTSPErrorSyntax;
1204 if (sepPtr)
1205 {
1206 *sepPtr = ';';
1207 };
1208 break;
1209 }
1210 rtspTrans->client_port1 = tmp;
1211 if (!curEndPtr)
1212 {
1213 if (rtspTrans->client_port1 >= PORT_MAX_VALUE)
1214 {
1215 amMalformed = RTSPErrorSyntax;
1216 if (sepPtr)
1217 {
1218 *sepPtr = ';';
1219 };
1220 break;
1221 }
1222 rtspTrans->client_port2 = rtspTrans->client_port1 + 1;
1223 rtspTrans->client_portIsSet = true;
1224 }
1225 else
1226 {
1227 nxtPtr = curEndPtr + 1;
1228 *curEndPtr = '-';
1229 PV_atoi(nxtPtr, 'd', atoi_tmp);
1230 tmp = atoi_tmp;
1231 if (tmp < PORT_MIN_VALUE || tmp > PORT_MAX_VALUE)
1232 {
1233 amMalformed = RTSPErrorSyntax;
1234 if (sepPtr)
1235 {
1236 *sepPtr = ';';
1237 };
1238 break;
1239 }
1240 rtspTrans->client_port2 = tmp;
1241 rtspTrans->client_portIsSet = true;
1242 }
1243 }
1244 else if (!oscl_strncmp(startPtr, server_port_str,
1245 server_port_str_len))
1246 {
1247 int tmp;
1248 uint32 atoi_tmp;
1249 nxtPtr = startPtr + server_port_str_len;
1250 char *curEndPtr = OSCL_CONST_CAST(char*, oscl_strstr(nxtPtr, "-"));
1251 if (curEndPtr) *curEndPtr = '\0';
1252 PV_atoi(nxtPtr, 'd', atoi_tmp);
1253 tmp = atoi_tmp;
1254 if (tmp < PORT_MIN_VALUE || tmp > PORT_MAX_VALUE)
1255 {
1256 amMalformed = RTSPErrorSyntax;
1257 if (sepPtr)
1258 {
1259 *sepPtr = ';';
1260 };
1261 break;
1262 }
1263 rtspTrans->server_port1 = tmp;
1264 if (!curEndPtr)
1265 {
1266 if (rtspTrans->server_port1 >= PORT_MAX_VALUE)
1267 {
1268 amMalformed = RTSPErrorSyntax;
1269 if (sepPtr)
1270 {
1271 *sepPtr = ';';
1272 };
1273 break;
1274 }
1275 rtspTrans->server_port2 = rtspTrans->server_port1 + 1;
1276 rtspTrans->server_portIsSet = true;
1277 }
1278 else
1279 {
1280 nxtPtr = curEndPtr + 1;
1281 *curEndPtr = '-';
1282 PV_atoi(nxtPtr, 'd', atoi_tmp);
1283 tmp = atoi_tmp;
1284 if (tmp < PORT_MIN_VALUE || tmp > PORT_MAX_VALUE)
1285 {
1286 amMalformed = RTSPErrorSyntax;
1287 if (sepPtr)
1288 {
1289 *sepPtr = ';';
1290 };
1291 break;
1292 }
1293 rtspTrans->server_port2 = tmp;
1294 rtspTrans->server_portIsSet = true;
1295 }
1296 }
1297 else if (!oscl_strncmp(startPtr, ttl_str, ttl_str_len))
1298 {
1299 nxtPtr = startPtr + ttl_str_len;
1300 int tmp;
1301 uint32 atoi_tmp;
1302 PV_atoi(nxtPtr, 'd', atoi_tmp);
1303 tmp = atoi_tmp;
1304 if (tmp < 0 || tmp > 255)
1305 {
1306 amMalformed = RTSPErrorSyntax;
1307 if (sepPtr)
1308 {
1309 *sepPtr = ';';
1310 };
1311 break;
1312 }
1313 rtspTrans->ttl = tmp;
1314 rtspTrans->ttlIsSet = true;
1315 }
1316 else if (!oscl_strncmp(startPtr, mode_str, mode_str_len))
1317 {
1318 rtspTrans->mode.play_mode = false;
1319 rtspTrans->mode.record_mode = false;
1320 nxtPtr = startPtr + mode_str_len;
1321 rtspTrans->modeIsSet = true;
1322 char *quotePtr = NULL;
1323 const char *wordEndPtr;
1324 if (*nxtPtr == '\"')
1325 {
1326 ++nxtPtr;
1327 if (NULL != (quotePtr = OSCL_CONST_CAST(char*, oscl_strstr(nxtPtr, "\""))))
1328 {
1329 *quotePtr = '\0';
1330 }
1331 }
1332 while (nxtPtr < endPtr)
1333 {
1334 if (NULL == (wordEndPtr = oscl_strstr(nxtPtr, ",")))
1335 {
1336 wordEndPtr = endPtr;
1337 }
1338
1339 if (!oscl_strncmp(nxtPtr, "PLAY", wordEndPtr - nxtPtr))
1340 {
1341 rtspTrans->mode.play_mode = true;
1342 }
1343 else if (!oscl_strncmp(nxtPtr, "RECORD", wordEndPtr - nxtPtr))
1344 {
1345 rtspTrans->mode.record_mode = true;
1346 }
1347 nxtPtr = wordEndPtr + 1;
1348
1349 }
1350
1351 if (quotePtr)
1352 {
1353 *quotePtr = '\"';
1354 }
1355 }
1356 else if (!oscl_strncmp(startPtr, port_str, port_str_len))
1357 {
1358 int tmp;
1359 uint32 atoi_tmp;
1360 nxtPtr = startPtr + port_str_len;
1361 char *curEndPtr = OSCL_CONST_CAST(char*, oscl_strstr(nxtPtr, "-"));
1362 if (curEndPtr) *curEndPtr = '\0';
1363 PV_atoi(nxtPtr, 'd', atoi_tmp);
1364 tmp = atoi_tmp;
1365 if (tmp < PORT_MIN_VALUE || tmp > PORT_MAX_VALUE)
1366 {
1367 amMalformed = RTSPErrorSyntax;
1368 if (sepPtr)
1369 {
1370 *sepPtr = ';';
1371 };
1372 break;
1373 }
1374 rtspTrans->port1 = tmp;
1375 if (!curEndPtr)
1376 {
1377 if (rtspTrans->port1 >= PORT_MAX_VALUE)
1378 {
1379 amMalformed = RTSPErrorSyntax;
1380 if (sepPtr)
1381 {
1382 *sepPtr = ';';
1383 };
1384 break;
1385 }
1386 rtspTrans->port2 = rtspTrans->port1 + 1;
1387 rtspTrans->portIsSet = true;
1388 }
1389 else
1390 {
1391 nxtPtr = curEndPtr + 1;
1392 *curEndPtr = '-';
1393 PV_atoi(nxtPtr, 'd', atoi_tmp);
1394 tmp = atoi_tmp;
1395 if (tmp < PORT_MIN_VALUE || tmp > PORT_MAX_VALUE)
1396 {
1397 amMalformed = RTSPErrorSyntax;
1398 if (sepPtr)
1399 {
1400 *sepPtr = ';';
1401 };
1402 break;
1403 }
1404 rtspTrans->port2 = tmp;
1405 rtspTrans->portIsSet = true;
1406 }
1407 }
1408 else if (!oscl_strncmp(startPtr, layers_str, layers_str_len))
1409 {
1410 nxtPtr = startPtr + layers_str_len;
1411 PV_atoi(nxtPtr, 'd', rtspTrans->layers);
1412 rtspTrans->layersIsSet = true;
1413 }
1414 else if (!oscl_strncmp(startPtr, ssrc_str, ssrc_str_len))
1415 {
1416 nxtPtr = startPtr + ssrc_str_len;
1417 rtspTrans->ssrc = 0;
1418 rtspTrans->ssrcIsSet = false;
1419 if (!PV_atoi(nxtPtr, 'x', rtspTrans->ssrc))
1420 {
1421 amMalformed = RTSPErrorSyntax;
1422 if (sepPtr)
1423 {
1424 *sepPtr = ';';
1425 };
1426 break;
1427 }
1428 rtspTrans->ssrcIsSet = true;
1429 }
1430
1431 if (sepPtr)
1432 {
1433 *sepPtr = ';';
1434 }
1435
1436 startPtr = endPtr + 1;
1437
1438 }
1439
1440 if (transSepPtr)
1441 {
1442 // put the separator character back
1443 *transSepPtr = ',';
1444 trans = transSepPtr;
1445 }
1446 else
1447 {
1448 trans = final_end;
1449 }
1450
1451 }
1452
1453 void
parseRTPInfo(uint16 fieldIdx)1454 RTSPIncomingMessage::parseRTPInfo(uint16 fieldIdx)
1455 {
1456 char * cPtr;
1457 char * finishPtr;
1458
1459 cPtr = const_cast<char*>(fieldVals[ fieldIdx ].c_str());
1460 finishPtr = cPtr + fieldVals[ fieldIdx ].length();
1461
1462 do
1463 {
1464 parseOneRTPInfoEntry(cPtr, finishPtr);
1465
1466 }
1467 while (RTSPOk == amMalformed
1468 && cPtr < finishPtr
1469 );
1470 }
1471
1472 void
parseOneRTPInfoEntry(char * & cPtr,char * finishPtr)1473 RTSPIncomingMessage::parseOneRTPInfoEntry(char * & cPtr, char * finishPtr)
1474 {
1475 bool getOut;
1476 char * subFieldName;
1477 char * separator;
1478 char * endOfIt;
1479
1480 // check the counter
1481 //
1482 if (RTSP_MAX_NUMBER_OF_RTP_INFO_ENTRIES == numOfRtpInfoEntries)
1483 { // limit reached
1484 amMalformed = RTSPErrorSyntax; // should it be different?
1485 return;
1486 }
1487 ++numOfRtpInfoEntries;
1488
1489 // skip comma, if necessary
1490 //
1491 if (CHAR_COMMA == *cPtr)
1492 {
1493 ++cPtr;
1494 }
1495
1496 getOut = false;
1497
1498 while ((!getOut) && cPtr < finishPtr && CHAR_COMMA != *cPtr)
1499 {
1500 // reset pointers
1501
1502 subFieldName = NULL;
1503 separator = NULL;
1504 endOfIt = NULL;
1505
1506 // skip whitespace
1507
1508 while (cPtr < finishPtr
1509 && (CHAR_SPACE == *cPtr
1510 || CHAR_TAB == *cPtr
1511 || CHAR_SEMICOLON == *cPtr
1512 || CHAR_NULL == *cPtr
1513 )
1514 )
1515 {
1516 ++cPtr;
1517 }
1518 if (cPtr >= finishPtr || CHAR_COMMA == *cPtr)
1519 {
1520 return;
1521 }
1522
1523 // we see the beginning
1524 subFieldName = cPtr;
1525
1526 // get the separator
1527 while (cPtr < finishPtr
1528 && CHAR_EQUAL != *cPtr
1529 )
1530 {
1531 ++cPtr;
1532 }
1533 if (cPtr >= finishPtr)
1534 {
1535 return;
1536 }
1537 // we see the separator
1538 separator = cPtr;
1539
1540 // get the end of it
1541 while (cPtr < finishPtr
1542 && CHAR_SEMICOLON != *cPtr
1543 && CHAR_SPACE != *cPtr
1544 && CHAR_TAB != *cPtr
1545 && CHAR_COMMA != *cPtr
1546 )
1547 {
1548 ++cPtr;
1549 }
1550
1551 endOfIt = cPtr;
1552
1553 if (3 == separator - subFieldName)
1554 { // url?
1555 if (('u' == (subFieldName[0] | OSCL_ASCII_CASE_MAGIC_BIT))
1556 && ('r' == (subFieldName[1] | OSCL_ASCII_CASE_MAGIC_BIT))
1557 && ('l' == (subFieldName[2] | OSCL_ASCII_CASE_MAGIC_BIT))
1558 )
1559 {
1560 rtpInfo[ numOfRtpInfoEntries-1 ].url.setPtrLen(
1561 separator + 1,
1562 endOfIt - separator - 1
1563 );
1564 rtpInfo[ numOfRtpInfoEntries-1 ].urlIsSet = true;
1565 if (CHAR_COMMA == *endOfIt)
1566 {
1567 getOut = true;
1568 }
1569 *endOfIt = CHAR_NULL;
1570 if (getOut)
1571 {
1572 // skip ahead beyond the whitespace
1573 // since we overwrote the comma with a NULL
1574 while (cPtr < finishPtr
1575 && (CHAR_SPACE == *cPtr
1576 || CHAR_TAB == *cPtr
1577 || CHAR_SEMICOLON == *cPtr
1578 || CHAR_NULL == *cPtr
1579 )
1580 )
1581 {
1582 ++cPtr;
1583 }
1584 }
1585 }
1586 // or, maybe, seq?
1587 else if (('s' == (subFieldName[0] | OSCL_ASCII_CASE_MAGIC_BIT))
1588 && ('e' == (subFieldName[1] | OSCL_ASCII_CASE_MAGIC_BIT))
1589 && ('q' == (subFieldName[2] | OSCL_ASCII_CASE_MAGIC_BIT))
1590 )
1591 {
1592 uint32 atoi_tmp;
1593 PV_atoi(separator + 1, 'd', atoi_tmp);
1594 rtpInfo[ numOfRtpInfoEntries-1 ].seq = (RtpSeqType)atoi_tmp;
1595
1596 rtpInfo[ numOfRtpInfoEntries-1 ].seqIsSet = true;
1597 }
1598 else
1599 {
1600 amMalformed = RTSPErrorSyntax;
1601 return;
1602 }
1603 }
1604 else if (7 == separator - subFieldName)
1605 { // rtptime?
1606 if (('r' == (subFieldName[0] | OSCL_ASCII_CASE_MAGIC_BIT))
1607 && ('t' == (subFieldName[1] | OSCL_ASCII_CASE_MAGIC_BIT))
1608 && ('p' == (subFieldName[2] | OSCL_ASCII_CASE_MAGIC_BIT))
1609 && ('t' == (subFieldName[3] | OSCL_ASCII_CASE_MAGIC_BIT))
1610 && ('i' == (subFieldName[4] | OSCL_ASCII_CASE_MAGIC_BIT))
1611 && ('m' == (subFieldName[5] | OSCL_ASCII_CASE_MAGIC_BIT))
1612 && ('e' == (subFieldName[6] | OSCL_ASCII_CASE_MAGIC_BIT))
1613 )
1614 {
1615 uint32 rtptime = 0;
1616 PV_atoi((separator + 1), 'd', rtptime);
1617 rtpInfo[ numOfRtpInfoEntries-1 ].rtptime = rtptime;
1618 rtpInfo[ numOfRtpInfoEntries-1 ].rtptimeIsSet = true;
1619 }
1620 else
1621 {
1622 amMalformed = RTSPErrorSyntax;
1623 return;
1624 }
1625 }
1626
1627 else
1628 {
1629 amMalformed = RTSPErrorSyntax;
1630 return;
1631 }
1632
1633 cPtr = endOfIt;
1634 }
1635 }
1636
1637 #if (defined(ASF_STREAMING) || defined(RTSP_PLAYLIST_SUPPORT))
1638 OSCL_EXPORT_REF bool
parseEntityBody(RTSPEntityBody * entityBody)1639 RTSPIncomingMessage::parseEntityBody(RTSPEntityBody * entityBody)
1640 {
1641 char * endOfMessage = (char *) entityBody->ptr + entityBody->len;
1642 char * ptr;
1643
1644 for (ptr = (char *) entityBody->ptr;
1645 ptr < endOfMessage ;
1646 ++numPtrFields
1647 )
1648 {
1649 char * endOfValue = ptr;
1650 while (CHAR_LF != *(endOfValue)
1651 && CHAR_CR != *(endOfValue)
1652 && CHAR_NULL != *(endOfValue))
1653 {
1654 ++endOfValue;
1655 }
1656
1657 if (CHAR_CR == *(endOfValue) && CHAR_LF == *(endOfValue + 1))
1658 {
1659 // need to increment endOfValue for CR-LF, because
1660 // it is needed later to step into the next field by shifting by 1
1661 *(endOfValue) = CHAR_NULL;
1662 *(++endOfValue) = CHAR_NULL;
1663 }
1664 else
1665 {
1666 *endOfValue = CHAR_NULL;
1667 }
1668
1669 char * separator = ptr;
1670
1671 while ((CHAR_COLON != *separator)
1672 && (CHAR_NULL != *separator)
1673 )
1674 {
1675 ++separator;
1676 }
1677
1678 if (CHAR_COLON != *separator)
1679 {
1680 amMalformed = RTSPErrorSyntax;
1681 }
1682 else
1683 { // field is pretty much normal
1684
1685 *separator = CHAR_NULL;
1686
1687 // get name pointer
1688 char * namePtr = ptr;
1689 // eat through trailing whitespace
1690 for (char * wPtr1 = separator - 1;
1691 (wPtr1 >= namePtr)
1692 && ((*wPtr1 >= 0x09 && *wPtr1 <= 0x0D) || *wPtr1 == 0x20);
1693 --wPtr1)
1694 {
1695 *wPtr1 = CHAR_NULL;
1696 }
1697 // eat through leading whitespace
1698 while ((*namePtr >= 0x09 && *namePtr <= 0x0D) || *namePtr == 0x20)
1699 {
1700 ++namePtr;
1701 }
1702
1703 // get value pointer
1704 char * valuePtr = separator + 1;
1705 // eat through trailing whitespace
1706 for (char * wPtr2 = endOfValue - 1;
1707 (wPtr2 > separator)
1708 && ((*wPtr2 >= 0x09 && *wPtr2 <= 0x0D) || *wPtr2 == 0x20);
1709 --wPtr2)
1710 {
1711 *wPtr2 = CHAR_NULL;
1712 }
1713 //eat through leading whitespace
1714 while ((*valuePtr >= 0x09 && *valuePtr <= 0x0D) || *valuePtr == 0x20)
1715 {
1716 ++valuePtr;
1717 }
1718
1719 // set the pointers
1720
1721 fieldKeys[ numPtrFields ] = namePtr;
1722 fieldVals[ numPtrFields ] = valuePtr;
1723
1724 // now, figure out if we are supposed to recognize this
1725 if (fieldKeys[ numPtrFields ].isCIEquivalentTo(
1726 RtspRecognizedFieldSessionId))
1727 {
1728 sessionId = fieldVals[ numPtrFields ];
1729 sessionIdIsSet = true;
1730 }
1731 //RTSP_PAR_COM_CONSTANTS_H_
1732 #define RtspRecognizedFieldEOF "EOF"
1733
1734 if (fieldKeys[ numPtrFields ].isCIEquivalentTo(
1735 RtspRecognizedFieldEOF))
1736 {
1737 eofField = fieldVals[ numPtrFields ];
1738 eofFieldIsSet = true;
1739 }
1740 #ifdef RTSP_PLAYLIST_SUPPORT
1741 if (fieldKeys[ numPtrFields ].isCIEquivalentTo(
1742 RtspRecognizedFieldPlaylistRange))
1743 {
1744 playlistRangeField = fieldVals[ numPtrFields ]; // not sure we really need to store this, but do it for now anyway
1745 playlistRangeFieldIsSet = true;
1746 // now parse the entry
1747 /*playlistRangeField.setPtrLen("",0);
1748 playlistRangeFieldIsSet = false;
1749 playlistErrorFieldIsSet = false;
1750 playlistErrorFieldCount = 0;
1751 playlistRangeUrl.setPtrLen("",0);
1752 playlistRangeClipIndex=0;
1753 playlistRangeClipOffset=0;
1754 playlistRangeNptTime=0;*/
1755 char* curr = valuePtr; // set curr to the start of the entry after the colon, whitespace was already removed
1756 StrPtrLen eStr;
1757
1758 eStr = curr;
1759 // look for playlist_play_time
1760 const StrPtrLen RtspPlaylistPlayTimeStr = "playlist_play_time";
1761 if (0 && RtspPlaylistPlayTimeStr.isCIPrefixOf(eStr))
1762 {
1763 curr += 18; // move past "playlist_play_time"
1764 // eat through leading whitespace
1765 while ((*curr >= 0x09 && *curr <= 0x0D) || *curr == 0x20)
1766 {
1767 ++curr;
1768 }
1769 if (*curr != CHAR_EQUAL)
1770 {
1771 // problem
1772 }
1773 // could be more whitespace
1774 while ((*curr >= 0x09 && *curr <= 0x0D) || *curr == 0x20)
1775 {
1776 ++curr;
1777 }
1778 if (*curr != CHAR_LT)
1779 {
1780 // problem
1781 }
1782 ++curr; // move past '<'
1783 // could be even more whitespace
1784 while ((*curr >= 0x09 && *curr <= 0x0D) || *curr == 0x20)
1785 {
1786 ++curr;
1787 }
1788 // now comes the url
1789 // find the end first
1790 char* end = curr;
1791 while (*end != CHAR_COMMA)
1792 {
1793 ++end;
1794 }
1795 char* endtmp = end;
1796 // may have trailing whitespace
1797 if (*(endtmp - 1) == 0x09 || *(endtmp - 1) == 0x0D || *(endtmp - 1) == 0x20)
1798 {
1799 --endtmp;
1800 while ((*endtmp >= 0x09 && *endtmp <= 0x0D) || *endtmp == 0x20)
1801 {
1802 --endtmp;
1803 }
1804 // will be on a non space char, move it over
1805 ++endtmp;
1806 }
1807 // to do - not sure if we need a '\0' here..
1808 playlistRangeUrl.setPtrLen(curr, endtmp - curr);
1809
1810 curr = end + 1;
1811 // next should be the clip index
1812 // of course, could be more whitespace
1813 while ((*curr >= 0x09 && *curr <= 0x0D) || *curr == 0x20)
1814 {
1815 ++curr;
1816 }
1817 // find next comma
1818 end = curr;
1819 while (*end != CHAR_COMMA)
1820 {
1821 ++end;
1822 }
1823 // may have trailing whitespace
1824 // dont worry about it for now atoi should be ok
1825 /*if(*(end-1) == 0x09 ||*(end-1) == 0x0D ||*(end-1) == 0x20)
1826 {
1827 --end;
1828 while( (*end >= 0x09 && *end <= 0x0D) || *end == 0x20 )
1829 {
1830 --end;
1831 }
1832 // will be on a non space char, move it over
1833 ++end;
1834 }*/
1835 // finally get the value
1836 uint32 atoi_tmp;
1837 PV_atoi(curr, 'd', atoi_tmp);
1838 playlistRangeClipIndex = atoi_tmp;
1839
1840 curr = end + 1;
1841 // next should be the clip offset
1842 // of course, could be more whitespace
1843 while ((*curr >= 0x09 && *curr <= 0x0D) || *curr == 0x20)
1844 {
1845 ++curr;
1846 }
1847 // find next comma
1848 end = curr;
1849 while (*end != CHAR_GT)
1850 {
1851 ++end;
1852 }
1853 // may have trailing whitespace
1854 // dont worry about it for now atoi should be ok
1855 /*if(*(end-1) == 0x09 ||*(end-1) == 0x0D ||*(end-1) == 0x20)
1856 {
1857 --end;
1858 while( (*end >= 0x09 && *end <= 0x0D) || *end == 0x20 )
1859 {
1860 --end;
1861 }
1862 // will be on a non space char, move it over
1863 ++end;
1864 }*/
1865 // finally get the value
1866 PV_atoi(curr, 'd', atoi_tmp);
1867 playlistRangeClipOffset = atoi_tmp;
1868
1869 }
1870 else
1871 {
1872 // problem
1873 }
1874 }
1875 if (fieldKeys[ numPtrFields ].isCIEquivalentTo(
1876 RtspRecognizedFieldPlaylistError))
1877 {
1878 if (playlistErrorFieldCount < RTSP_MAX_NUMBER_OF_PLAYLIST_ERROR_ENTRIES)
1879 {
1880 playlistErrorField[playlistErrorFieldCount++] = fieldVals[ numPtrFields ]; // this needs to be an array since the number can be unbounded
1881 playlistErrorFieldIsSet = true;
1882 }
1883 }
1884 #endif
1885 }
1886 ptr = endOfValue + 1;
1887 }
1888 return true;
1889 }
1890
1891 #endif
1892
1893