1#if defined(HAVE_CONFIG_H)
14#define RESIPROCATE_SUBSYSTEM Subsystem::SIP
59static inline int c2i(
unsigned char c)
61 return static_cast<int>(c);
66 for(
unsigned int charIndex = 0; charIndex <= UCHAR_MAX; ++charIndex)
72 for(
const char *charPtr =
"abcdefghijklmnopqrstuvwxyz"
73 "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-.!%*_+`'~";
200 for (
int charCategory = 0;
212 State afterLineBreakState)
419#if defined(RESIP_MSG_HEADER_SCANNER_DEBUG)
421static void printText(
const char * text,
422 unsigned int textLength)
424 const char *charPtr = text;
425 for (
unsigned int counter = 0; counter < textLength; ++charPtr, ++counter)
430 case '\\': printf(
"\\\\");
432 case '\r': printf(
"\\r");
434 case '\n': printf(
"\\n");
436 case '\t': printf(
"\\t");
438 case '\0': printf(
"\\0");
454 case ccColon:
return "\\\":\\\"";
459 case ccComma:
return "\\\",\\\"";
472 case ccOther:
return "ccOther";
475 case ccColon:
return "ccColon";
480 case ccComma:
return "ccComma";
488cleanName(
const char * name)
491 static char *leaders[] = {
497 const int nLeaders =
sizeof(leaders)/
sizeof(*leaders);
499 for(
int i = 0 ; i < nLeaders ; i++)
501 unsigned int l = strlen(leaders[i]);
502 if (strstr(name,leaders[i]) == name &&
504 isupper(
static_cast< unsigned char >(name[l])))
510 return &name[offset];
514stateName(
State state)
516 const char *stateName;
520 stateName =
"sMsgStart";
523 stateName =
"sHalfLineBreakAtMsgStart";
526 stateName =
"sScanStatusLine";
529 stateName =
"sHalfLineBreakAfterStatusLine";
532 stateName =
"sAfterLineBreakAfterStatusLine";
535 stateName =
"sScanFieldName";
538 stateName =
"sScanWhitespaceAfter1FieldName";
541 stateName =
"sScanWhitespaceAfterNFieldName";
544 stateName =
"sScanWhitespaceOr1Value";
547 stateName =
"sScanWhitespaceOrNValue";
550 stateName =
"sHalfLineBreakInWhitespaceBefore1Value";
553 stateName =
"sHalfLineBreakInWhitespaceBeforeNValue";
556 stateName =
"sAfterLineBreakInWhitespaceBefore1Value";
559 stateName =
"sAfterLineBreakInWhitespaceBeforeNValue";
562 stateName =
"sScan1Value";
565 stateName =
"sScanNValue";
568 stateName =
"sHalfLineBreakIn1Value";
571 stateName =
"sHalfLineBreakInNValue";
574 stateName =
"sAfterLineBreakIn1Value";
577 stateName =
"sAfterLineBreakInNValue";
580 stateName =
"sScanNValueInQuotes";
583 stateName =
"sAfterEscCharInQuotesInNValue";
586 stateName =
"sHalfLineBreakInQuotesInNValue";
589 stateName =
"sAfterLineBreakInQuotesInNValue";
592 stateName =
"sScanNValueInAngles";
595 stateName =
"sHalfLineBreakInAnglesInNValue";
598 stateName =
"sAfterLineBreakInAnglesInNValue";
601 stateName =
"sHalfLineBreakAfterLineBreak";
604 stateName =
"<unknown>";
612 const char *transitionActionName;
613 switch (transitionAction)
616 transitionActionName =
"taNone";
619 transitionActionName =
"taTermStatusLine";
622 transitionActionName =
"taTermFieldName";
625 transitionActionName =
"taBeyondEmptyValue";
628 transitionActionName =
"taTermValueAfterLineBreak";
631 transitionActionName =
"taTermValue";
634 transitionActionName =
"taStartText";
637 transitionActionName =
"taEndHeader";
640 transitionActionName =
"taChunkTermSentinel";
643 transitionActionName =
"taError";
646 transitionActionName =
"<unknown>";
648 return transitionActionName;
652printStateTransition(
State state,
656 printf(
" %s['", cleanName(stateName(state)));
657 printText(&character, 1);
658 printf(
"']: %s\n", cleanName(trActionName(transitionAction)));
660#if !defined(RESIP_MSG_HEADER_SCANNER_DEBUG)
661static const char* stateName(
const char*)
662{
return "RECOMPILE_WITH_SCANNER_DEBUG"; }
663static const char* trActionName(
const char*)
664{
return stateName(0); }
673 FILE *fp = fdopen(fd,
"w");
676 fprintf(stderr,
"MsgHeaderScanner:: unable to open output file\n");
681 fprintf(fp,
"digraph MsgHeaderScannerFSM {\n");
682 fprintf(fp,
"\tnode[shape=record\n\t\tfontsize=8\n\t\tfontname=\"Helvetica\"\n\t]\n");
683 fprintf(fp,
"\tedge [ fontsize=6 fontname=\"Helvetica\"]\n");
685 fprintf(fp,
"\tgraph [ ratio=0.8\n\t\tfontsize=6 compound=true ]");
686 for(
int state = 0 ; state <
numStates; ++state)
689 " %s [ label = \"%d|%s\" ]\n",
690 cleanName(stateName(state)),
692 cleanName(stateName(state))
703 " %s -> %s [label=\"%s\\n%s\" ]\n",
704 cleanName(stateName(state)),
705 cleanName(stateName(
stateMachine[state][category].nextState)),
706 categorySymbol(category),
707 cleanName(trActionName(
stateMachine[state][category].action)));
720#if defined(RESIP_MSG_HEADER_SCANNER_DEBUG)
722static const char *
const multiValuedFieldNameArray[] = {
731 "subscription-state",
744 "proxy-authenticate",
745 "proxy-authorization",
755 unsigned int *fieldNameLength,
758 bool *isMultiValueAllowed)
760 *isMultiValueAllowed =
false;
761 const char *
const *multiValuedFieldNamePtr = multiValuedFieldNameArray;
764 const char *multiValuedFieldName = *multiValuedFieldNamePtr;
765 if (!multiValuedFieldName)
769 if (strncmp(fieldName, multiValuedFieldName, *fieldNameLength) == 0)
771 *isMultiValueAllowed =
true;
774 ++multiValuedFieldNamePtr;
783 unsigned int lineTextLength,
786 printf(
"status line: ");
787 printText(lineText, lineTextLength);
797 const char * fieldName,
798 unsigned int fieldNameLength,
800 unsigned int valueTextLength,
803 printText(fieldName, fieldNameLength);
805 printText(valueText, valueTextLength);
819 unsigned int *fieldNameLength,
822 bool *isMultiValueAllowed)
826 *isMultiValueAllowed =
837 unsigned int lineTextLength,
863 const char * fieldName,
864 unsigned int fieldNameLength,
866 unsigned int valueTextLength,
879bool MsgHeaderScanner::mInitialized =
false;
895 mPrevScanChunkNumSavedTextChars = 0;
911 mPrevScanChunkNumSavedTextChars = 0;
917 unsigned int chunkLength,
918 char ** unprocessedCharPtr)
923 State localState = mState;
924 char *charPtr = chunk + mPrevScanChunkNumSavedTextChars;
925 char *termCharPtr = chunk + chunkLength;
926 char saveChunkTermChar = *termCharPtr;
928 char *textStartCharPtr;
930 if (mPrevScanChunkNumSavedTextChars == 0)
932 textStartCharPtr = 0;
936 textStartCharPtr = chunk;
943 CharInfo *charInfo = &localCharInfoArray[((
unsigned char) (*charPtr))];
946 determineTransitionFromCharCategory:
948 &(localStateMachine[(unsigned)localState][(
size_t)charCategory]);
950#if defined(RESIP_MSG_HEADER_SCANNER_DEBUG)
951 printStateTransition(localState, *charPtr, transitionAction);
954 if (transitionAction ==
taNone)
continue;
957 switch (transitionAction)
962 (
unsigned int)(charPtr - textStartCharPtr),
963 localTextPropBitMask))
966 *unprocessedCharPtr = charPtr;
969 textStartCharPtr = 0;
973 mFieldNameLength = (
unsigned int)(charPtr - textStartCharPtr);
974 bool isMultiValueAllowed;
977 localTextPropBitMask,
979 &isMultiValueAllowed);
980 mFieldName = textStartCharPtr;
981 textStartCharPtr = 0;
982 if (isMultiValueAllowed)
997 goto performStartTextAction;
1004 (
unsigned int)((charPtr - textStartCharPtr) - 2),
1005 localTextPropBitMask);
1007 goto performStartTextAction;
1014 (
unsigned int)(charPtr - textStartCharPtr),
1015 localTextPropBitMask);
1016 textStartCharPtr = 0;
1020 performStartTextAction:
1021 textStartCharPtr = charPtr;
1022 localTextPropBitMask = 0;
1027 *unprocessedCharPtr = charPtr + 1;
1031 if (charPtr == termCharPtr)
1034 mState = localState;
1035 if (textStartCharPtr == 0)
1037 mPrevScanChunkNumSavedTextChars = 0;
1041 mPrevScanChunkNumSavedTextChars = (
unsigned int)(termCharPtr - textStartCharPtr);
1043 mTextPropBitMask = localTextPropBitMask;
1045 *unprocessedCharPtr = termCharPtr - mPrevScanChunkNumSavedTextChars;
1052 goto determineTransitionFromCharCategory;
1057 *unprocessedCharPtr = charPtr;
1062 *termCharPtr = saveChunkTermChar;
1066 const char* failedChar = *unprocessedCharPtr;
1067 const char* lineBegin = failedChar;
1068 while (lineBegin > chunk)
1070 char c = *(lineBegin - 1);
1071 if (!isprint(
static_cast< unsigned char >(c)) && c !=
'\t')
1075 const char* lineEnd = failedChar;
1076 while (lineEnd < termCharPtr)
1079 if (!isprint(
static_cast< unsigned char >(c)) && c !=
'\t')
1086 strm <<
"Message header scanning failed at position " << (failedChar - chunk) <<
'\n';
1087 strm.write(lineBegin, lineEnd - lineBegin);
1089 static const char filler[] =
" ";
1090 unsigned int n = (
unsigned int)(failedChar - lineBegin);
1091 while (n >
sizeof(filler) - 1)
1093 strm.write(filler,
sizeof(filler) - 1);
1094 n -=
sizeof(filler) - 1;
1096 strm.write(filler, n);
1097 strm <<
"^ (character codes:";
1100 auto print_hex = [&p](
char c)
1102 static const char hex_charset[16] = {
'0',
'1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9',
'a',
'b',
'c',
'd',
'e',
'f' };
1103 *p++ = hex_charset[(
static_cast< unsigned char >(c) >> 4u) & 0x0F];
1104 *p++ = hex_charset[
static_cast< unsigned char >(c) & 0x0F];
1106 if ((failedChar - chunk) >= 2)
1109 print_hex(*(failedChar - 2));
1111 if ((failedChar - chunk) >= 1)
1114 print_hex(*(failedChar - 1));
1116 if ((termCharPtr - failedChar) >= 1)
1120 print_hex(*failedChar);
1123 if ((termCharPtr - failedChar) >= 2)
1126 print_hex(*(failedChar + 1));
1128 if ((termCharPtr - failedChar) >= 3)
1131 print_hex(*(failedChar + 2));
1134 strm.write(buf, p - buf);
1141MsgHeaderScanner::initialize()
1153#if defined(RESIP_MSG_HEADER_SCANNER_DEBUG) && defined(MSG_SCANNER_STANDALONE)
1165 "allow: foo, bar, \"don,\\\"xyz\r\n zy\", buzz\r\n\r\n";
1174 printf(
"Scanning another chunk '.");
1184 printf(
"Error %d at character %d.\n",
#define RESIPROCATE_SUBSYSTEM
static bool genericLogCheckLevel(resip::Log::Level level, const resip::Subsystem &sub)
int main(int argc, char **argv)
Implementation for logging macros.
EncodeStream & asStream()
Represents a SIP message.
void setStartLine(const char *start, uint32_t len)
void addHeader(Headers::Type header, const char *headerName, uint32_t headerNameLen, const char *value, uint32_t valuelen)
Add HeaderFieldValue given enum, header name and value.
dcm! – add UnusedChecking(_enum) below;
void processMsgHeaderFieldNameAndValue(SipMessage *msg, int fieldKind, const char *fieldName, unsigned int fieldNameLength, char *valueText, unsigned int valueTextLength, MsgHeaderScanner::TextPropBitMask valueTextPropBitMask)
static void initStateMachine()
static void specHalfLineBreakState(State halfLineBreakState, State afterLineBreakState)
@ taTermValueAfterLineBreak
@ sAfterLineBreakInAnglesInNValue
@ sHalfLineBreakAfterStatusLine
@ sAfterLineBreakInQuotesInNValue
@ sHalfLineBreakAtMsgStart
@ sAfterLineBreakInWhitespaceBeforeNValue
@ sHalfLineBreakAfterLineBreak
@ sAfterLineBreakAfterStatusLine
@ sHalfLineBreakInQuotesInNValue
@ sScanWhitespaceOrNValue
@ sHalfLineBreakInWhitespaceBefore1Value
@ sAfterLineBreakInWhitespaceBefore1Value
@ sAfterEscCharInQuotesInNValue
@ sScanWhitespaceAfter1FieldName
@ sAfterLineBreakInNValue
@ sScanWhitespaceOr1Value
@ sAfterLineBreakIn1Value
@ sScanWhitespaceAfterNFieldName
@ sHalfLineBreakInWhitespaceBeforeNValue
@ sHalfLineBreakInAnglesInNValue
static void specDefaultTransition(State state, TransitionAction action, State nextState)
bool processMsgHeaderStatusLine(SipMessage *msg, char *lineText, unsigned int lineTextLength, MsgHeaderScanner::TextPropBitMask lineTextPropBitMask)
static void specXValueStates(int stateDelta)
static void initCharInfoArray()
static TransitionInfo stateMachine[numStates][numCharCategories]
static int c2i(unsigned char c)
void lookupMsgHeaderFieldInfo(char *fieldName, unsigned int *fieldNameLength, MsgHeaderScanner::TextPropBitMask fieldNameTextPropBitMask, int *fieldKind, bool *isMultiValueAllowed)
defined(RESIP_MSG_HEADER_SCANNER_DEBUG) } {
static CharInfo charInfoArray[UCHAR_MAX+1]
void specTransition(State state, CharCategory charCategory, TransitionAction action, State nextState)
@ deltaOfNStateFrom1State
MsgHeaderScanner::TextPropBitMask textPropBitMask