Class: OverSIP::SIP::MessageParser

Inherits:
Object
  • Object
show all
Defined in:
ext/sip_parser/sip_parser_ruby.c

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#newObject

Creates a new parser.



842
843
844
845
846
847
848
849
850
851
852
853
854
# File 'ext/sip_parser/sip_parser_ruby.c', line 842

VALUE SipMessageParser_init(VALUE self)
{
  TRACE();
  sip_message_parser *parser = NULL;
  DATA_GET(self, sip_message_parser, parser);
  sip_message_parser_init(parser);

  /* NOTE: This allows the C struct to access to the VALUE element of the Ruby
  MessageParser instance. */
  parser->ruby_sip_parser = self;

  return self;
}

Class Method Details

.OverSIP::SIP::MessageParser.headarizeString

Tries to lookup the header name in a list of well-known headers. If so, returns the retrieved VALUE. It also works for short headers. In case the header is unknown, it normalizes it (by capitalizing the first letter and each letter under a “-” or “_” symbol).

Returns:

  • (String)


1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
# File 'ext/sip_parser/sip_parser_ruby.c', line 1158

VALUE SipMessageParser_Class_headerize(VALUE self, VALUE string)
{
  TRACE();
  if (TYPE(string) != T_STRING)
    rb_raise(rb_eTypeError, "Argument must be a String");

  if ((RSTRING_LEN(string)) == 0)
    rb_str_new(RSTRING_PTR(string), RSTRING_LEN(string));

  return(headerize(RSTRING_PTR(string), RSTRING_LEN(string)));
}

.OverSIP::SIP::MessageParser.parse_uri(string) ⇒ OverSIP::SIP::Uri

Returns:



1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
# File 'ext/sip_parser/sip_parser_ruby.c', line 1175

VALUE SipMessageParser_Class_parse_uri(VALUE self, VALUE string, VALUE allow_name_addr)
{
  TRACE();
  char *dptr = NULL;
  long dlen = 0;
  sip_uri_parser *parser;
  VALUE parsed;
  int int_allow_name_addr;

  /* Initialize the global SIP URI parser if not set yet. */
  if (global_sip_uri_parser == NULL) {
    /* Asign functions to the pointers of global_sip_uri_parser struct. */
    global_sip_uri_parser = ALLOC(sip_uri_parser);
    global_sip_uri_parser->uri.full                    = uri_full;
    global_sip_uri_parser->uri.scheme                  = uri_scheme;
    global_sip_uri_parser->uri.user                    = uri_user;
    global_sip_uri_parser->uri.host                    = uri_host;
    global_sip_uri_parser->uri.port                    = uri_port;
    global_sip_uri_parser->uri.param                   = uri_param;
    global_sip_uri_parser->uri.known_param             = uri_known_param;
    global_sip_uri_parser->uri.has_param               = uri_has_param;
    global_sip_uri_parser->uri.headers                 = uri_headers;
    global_sip_uri_parser->uri.display_name            = uri_display_name;
  }

  REQUIRE_TYPE(string, T_STRING);

  /* NOTE: We need to pass a \0 terminated string to the URI parser. StringValueCStr() gives
   * exactly that. So also increment dlen in 1. */
  dptr = StringValueCStr(string);
  dlen = RSTRING_LEN(string) + 1;

  if (TYPE(allow_name_addr) == T_TRUE) {
    parsed = rb_obj_alloc(cNameAddr);
    int_allow_name_addr = 1;
  }
  else {
    parsed = rb_obj_alloc(cUri);
    int_allow_name_addr = 0;
  }

  if (sip_uri_parser_execute(global_sip_uri_parser, dptr, dlen, parsed, int_allow_name_addr) == 0)
    return parsed;
  else
    return Qfalse;
}

Instance Method Details

#duplicated_core_header?Boolean

In case a core header is duplicated its name is returned as string. False otherwise.

Returns:

  • (Boolean)


1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
# File 'ext/sip_parser/sip_parser_ruby.c', line 1081

VALUE SipMessageParser_has_duplicated_core_header(VALUE self)
{
  TRACE();
  sip_message_parser *parser = NULL;
  DATA_GET(self, sip_message_parser, parser);

  /* NOTE: Good moment for counting the num of Via values and store it. */
  rb_ivar_set(parser->parsed, id_num_vias, INT2FIX(parser->num_via));

  if (parser->num_from > 1)
    return string_From;
  else if (parser->num_to > 1)
    return string_To;
  else if (parser->num_cseq > 1)
    return string_CSeq;
  else if (parser->num_call_id > 1)
    return string_Call_ID;
  else if (parser->num_max_forwards > 1)
    return string_Max_Forwards;
  else if (parser->num_content_length > 1)
    return string_Content_Length;

  return Qfalse;
}

#errorString

Returns a String showing the error by enclosing the exact wrong char between }}.

Returns:

  • (String)


949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
# File 'ext/sip_parser/sip_parser_ruby.c', line 949

VALUE SipMessageParser_error(VALUE self)
{
  TRACE();
  sip_message_parser *parser = NULL;
  DATA_GET(self, sip_message_parser, parser);

  if(sip_message_parser_has_error(parser)) {
    char *parsing_error_str;
    int parsing_error_str_len;
    int i;
    int j;
    VALUE rb_error_str;

    /* Duplicate error string length so '\r' and '\n' are displayed as CR and LF.
    Let 6 chars more for allocating {{{ and }}}. */
    parsing_error_str = ALLOC_N(char, 2*parser->error_len + 6);

    parsing_error_str_len=0;
    for(i=0, j=0; i < parser->error_len; i++) {
      if (i != parser->error_pos) {
        if (parser->error_start[i] == '\r') {
          parsing_error_str[j++] = '\\';
          parsing_error_str[j++] = 'r';
          parsing_error_str_len += 2;
        }
        else if (parser->error_start[i] == '\n') {
          parsing_error_str[j++] = '\\';
          parsing_error_str[j++] = 'n';
          parsing_error_str_len += 2;
        }
        else {
          parsing_error_str[j++] = parser->error_start[i];
          parsing_error_str_len++;
        }
      }
      else {
        parsing_error_str[j++] = '{';
        parsing_error_str[j++] = '{';
        parsing_error_str[j++] = '{';
        if (parser->error_start[i] == '\r') {
          parsing_error_str[j++] = '\\';
          parsing_error_str[j++] = 'r';
          parsing_error_str_len += 2;
        }
        else if (parser->error_start[i] == '\n') {
          parsing_error_str[j++] = '\\';
          parsing_error_str[j++] = 'n';
          parsing_error_str_len += 2;
        }
        else {
          parsing_error_str[j++] = parser->error_start[i];
          parsing_error_str_len++;
        }
        parsing_error_str[j++] = '}';
        parsing_error_str[j++] = '}';
        parsing_error_str[j++] = '}';
        parsing_error_str_len += 6;
      }
    }

    rb_error_str = rb_str_new(parsing_error_str, parsing_error_str_len);
    xfree(parsing_error_str);
    return rb_error_str;
  }
  else
    return Qnil;
}

#error?Boolean

Tells you whether the parser is in an error state.

Returns:

  • (Boolean)


933
934
935
936
937
938
939
940
# File 'ext/sip_parser/sip_parser_ruby.c', line 933

VALUE SipMessageParser_has_error(VALUE self)
{
  TRACE();
  sip_message_parser *parser = NULL;
  DATA_GET(self, sip_message_parser, parser);

  return sip_message_parser_has_error(parser) ? Qtrue : Qfalse;
}

#execute(buffer, start) ⇒ Integer

Returns:

  • (Integer)


897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
# File 'ext/sip_parser/sip_parser_ruby.c', line 897

VALUE SipMessageParser_execute(VALUE self, VALUE buffer, VALUE start)
{
  TRACE();
  sip_message_parser *parser = NULL;
  int from = 0;
  char *dptr = NULL;
  long dlen = 0;

  REQUIRE_TYPE(buffer, T_STRING);
  REQUIRE_TYPE(start, T_FIXNUM);

  DATA_GET(self, sip_message_parser, parser);

  from = FIX2INT(start);
  dptr = RSTRING_PTR(buffer);
  dlen = RSTRING_LEN(buffer);

  /* This should never occur or there is an error in the parser. */
  if(from >= dlen)
    rb_raise(eSIPMessageParserError, "requested start is after buffer end.");

  sip_message_parser_execute(parser, dptr, dlen, from);

  if (sip_message_parser_has_error(parser))
    return Qfalse;
  else
    return INT2FIX(sip_message_parser_nread(parser));
}

#finishObject

Finishes a parser early which could put in a “good” or bad state. You should call reset after finish it or bad things will happen.



882
883
884
885
886
887
888
889
890
# File 'ext/sip_parser/sip_parser_ruby.c', line 882

VALUE SipMessageParser_finish(VALUE self)
{
  TRACE();
  sip_message_parser *parser = NULL;
  DATA_GET(self, sip_message_parser, parser);
  sip_message_parser_finish(parser);

  return sip_message_parser_is_finished(parser) ? Qtrue : Qfalse;
}

#finished?Boolean

Tells you whether the parser is finished or not and in a good state.

Returns:

  • (Boolean)


1024
1025
1026
1027
1028
1029
1030
1031
# File 'ext/sip_parser/sip_parser_ruby.c', line 1024

VALUE SipMessageParser_is_finished(VALUE self)
{
  TRACE();
  sip_message_parser *parser = NULL;
  DATA_GET(self, sip_message_parser, parser);

  return sip_message_parser_is_finished(parser) ? Qtrue : Qfalse;
}

#missing_core_header?Boolean

In case a core header is missing its name is returned as string. False otherwise.

Returns:

  • (Boolean)


1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
# File 'ext/sip_parser/sip_parser_ruby.c', line 1114

VALUE SipMessageParser_has_missing_core_header(VALUE self)
{
  TRACE();
  sip_message_parser *parser = NULL;
  DATA_GET(self, sip_message_parser, parser);

  if (parser->num_via == 0)
    return string_Via;
  else if (parser->num_from == 0)
    return string_From;
  else if (parser->num_to == 0)
    return string_To;
  else if (parser->num_cseq == 0)
    return string_CSeq;
  else if (parser->num_call_id == 0)
    return string_Call_ID;

  return Qfalse;
}

#nreadInteger

Returns the amount of data processed so far during this processing cycle. It is set to 0 on initialize or reset calls and is incremented each time execute is called.

Returns:

  • (Integer)


1064
1065
1066
1067
1068
1069
1070
1071
# File 'ext/sip_parser/sip_parser_ruby.c', line 1064

VALUE SipMessageParser_nread(VALUE self)
{
  TRACE();
  sip_message_parser *parser = NULL;
  DATA_GET(self, sip_message_parser, parser);

  return INT2FIX(parser->nread);
}

#parsedOverSIP::Request, ...

Returns the parsed object. It doesn’t meant that the parsing has succedded. The returned object could be a message identified as a Request or Response or :outbound_keepalive, but later the message has been detected as invalid. So the parsed object is incomplete.

In case the parsing has failed in the first char the method returns nil.

Returns:

  • (OverSIP::Request, OverSIP::Response, nil)


1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
# File 'ext/sip_parser/sip_parser_ruby.c', line 1044

VALUE SipMessageParser_parsed(VALUE self)
{
  TRACE();
  sip_message_parser *parser = NULL;
  DATA_GET(self, sip_message_parser, parser);

  /* NOTE: We can safely access here to parser->parsed as its content is also referenced
   * by id_parsed so it cannot be garbage collected while the OverSIP::MessageParser
   * still alives. */
  return parser->parsed;
}

#post_parsingObject



1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
# File 'ext/sip_parser/sip_parser_ruby.c', line 1135

VALUE SipMessageParser_post_parsing(VALUE self)
{
  TRACE();
  sip_message_parser *parser = NULL;
  DATA_GET(self, sip_message_parser, parser);

  /* We just parse Contact if it's a single header with a single Name Addr within it. */
  if (! (parser->contact_is_valid == 1 && parser->num_contact == 1))
    rb_ivar_set(parser->parsed, id_contact, Qnil);

  return Qnil;
}

#resetnil

Resets the parser to it’s initial state so that you can reuse it rather than making new ones.

Returns:

  • (nil)


864
865
866
867
868
869
870
871
872
# File 'ext/sip_parser/sip_parser_ruby.c', line 864

VALUE SipMessageParser_reset(VALUE self)
{
  TRACE();
  sip_message_parser *parser = NULL;
  DATA_GET(self, sip_message_parser, parser);
  sip_message_parser_init(parser);

  return Qnil;
}