#include #ifdef WIN32 #include #else #include // used for validting ipv6 addresses (should be replaced w/ boost/asio.hpp for better portability) #endif // workaround to compile with cygwin // (AF_INET6 is not included by arpa/inet.h and we could not find the // correct header to include without having conflicting definitions) #ifdef __CYGWIN__ #define AF_INET6 23 #endif #include "gen_classes.h" #include "Regex.h" namespace t3devlib { namespace gen { // Definition of character classes used to be used in the regular expressions // (within []) #define SDPCHARS_VCHAR "\\x21-\\x7e" #define SDPCHARS_EMAIL_SAFE "\\x01-\\x09\\x0b\\x0c\\x0e-\\x27\\x2a-\\x3b\\x3d\\x3f-\\xff" #define SDPCHARS_ATEXT "a-zA-Z0-9!#$%&'*+-/=?^_`{|}~" #define SDPCHARS_BYTE_STRING "\\x01-\\x09\\x0b\\x0c\\x0e-\\xff" // Definition of common regular expression reused many times within the // decoder // // Note: these definitions shall not contain any group match '(' ')' to avoid // side effect (the index of the subsequent group match would be shifted) // -> all parenthesis group needed should be implemented with '(?:' ')' so // that they are not indexed #define SDPREG_SP " " #define SDPREG_NON_WS_STRING "[" SDPCHARS_VCHAR "\\x80-\\xff]+" #define SDPREG_TOKEN "[\\x21\\x23-\\x27\\x2a\\x2b\\x2d\\x2e\\x30-\\x39\\x41-\\x5a\\x5e-\\x7e]+" #define SDPREG_DECIMAL_UCHAR "(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(?![0-9])" #define SDPREG_IP4_ADDRESS SDPREG_DECIMAL_UCHAR "(?:[.]" SDPREG_DECIMAL_UCHAR"){3}" #define SDPREG_INTEGER "[1-9][0-9]*" #define SDPREG_TIME_INTEGER "[0-9][0-9]*" #define SDPREG_BYTE_STRING "["SDPCHARS_BYTE_STRING"]+" // TODO: support the folding whitespaces/obsolete addresses/... ? #define SDPREG_ADDR_SPEC "[" SDPCHARS_ATEXT "][." SDPCHARS_ATEXT "]*@[" SDPCHARS_ATEXT "][." SDPCHARS_ATEXT "]*" // This regex differs from the BNF to avoid matching a space or dash at the // end of the number #define SDPREG_PHONE "[+]?[0-9](?:[- 0-9]*[0-9])?" inline bool logical_xor (bool a, bool b) { return (a && !b) || (!a && b); } // // Implementation of the decoder for SDP // void SDP_Message::PreDecode (Buffer& buffer) throw (DecodeError) { Get_protocol_version().SetFormat(Integer::AsciiDecimal); } void pre_decode_optional_field_multiple_times (RecordOfSetOf& value, int id, Buffer& buffer, const char* field_letter, void (*hyp_size_func)(int), void (*hyp_field_length_func)(int) ) { static Regex reg_field ("((?:\r\n)?)(([a-z])=)([^\\r\\n\\x00]*)"); if (!reg_field.Match (buffer)) goto finished; if (logical_xor (id, reg_field.GetMatchedLength (1))) // the first line MUST NOT be preceeded by CRLF // the next lines MUST be preceeded by CRLF // -> otherwise we assume this is the last field goto finished; if (reg_field.GetMatchedString (3) != field_letter) { assert (id > 0);// the field letter is already checked in // SDP_Message::PreDecodeField // the assertion is useful to ensure // that we cannot have an empty // record of (in that case the field // must be omitted in SDP_Message) goto finished; } (*hyp_field_length_func) (reg_field.GetMatchedLength(4)); reg_field.MovePast (buffer, 2); return; finished: // did not match -> last field (*hyp_size_func) (-2); } void SDP_Message::PreDecodeField (int id, Buffer& buffer) throw (DecodeError) { static Regex reg_field("^(([a-z])=)([^\\r\\n\\x00]*)"); const char* expected = NULL; switch (id) { case id_protocol_version: expected = "v"; goto mandatory; case id_origin: expected = "o"; goto mandatory; case id_session_name: expected = "s"; goto mandatory; case id_information: expected = "i"; goto optional_once; // TODO: check that this is a valid URI ??? case id_uri: expected = "u"; goto optional_once; case id_emails: expected = "e"; goto optional_many; case id_phone_numbers: expected = "p"; goto optional_many; case id_connection: expected = "c"; goto optional_once; case id_bandwidth: expected = "b"; goto optional_many; case id_times: return; // times is not optional => always present // FIXME: SDP_timezone_list should not be here -> the TTCN-3 types should be changed // in the BNF, "z=" is allowed once after each "t=" fields (not after // the last one only) case id_timezone_adjustments: expected = "z"; goto optional_once; case id_key: expected = "k"; goto optional_once; case id_attributes: expected = "a"; goto optional_many; case id_media_list: expected = "m"; goto optional_many; } return; mandatory: reg_field.AssertMatch (buffer, this); SetHypFieldLength (id, reg_field.GetMatchedLength(3)); if (reg_field.GetMatchedString(2) != expected) { DecodeError e(this); e.Msg() << "missing mandatory field " << expected << "= before field " << reg_field.GetMatchedString(1) << endl; throw e; } reg_field.MovePast (buffer, 1); return; optional_once: if (reg_field.Match (buffer) && reg_field.GetMatchedString(2) == expected) { // the field is present SetHypFieldIsPresent (id, 1); SetHypFieldLength (id, reg_field.GetMatchedLength(3)); reg_field.MovePast (buffer, 1); } else { // the field is not present SetHypFieldIsPresent (id, 0); } return; optional_many: SetHypFieldIsPresent (id, (reg_field.Match (buffer) && reg_field.GetMatchedString(2) == expected) ? 1 : 0); } void SDP_Message::PostDecodeField (int id, Buffer& buffer) throw (DecodeError) { // Here we match the trailing CRLF in the case the field is present static Regex reg_crlf ("^\r\n"); if (!IsPresent (id)) return; // the time field is not declared as optional // therefore we must check that the list is not empty if ((id == id_times) && (Get_times().GetSize() == 0)) return; reg_crlf.AssertMatch (buffer, this); reg_crlf.MovePast (buffer); } void SDP_Origin::PreDecode (Buffer& buffer) throw (DecodeError) { static Regex reg_origin ("("SDPREG_NON_WS_STRING")" // username SDPREG_SP "([0-9]+)" // session-id SDPREG_SP "([0-9]+)" // session-version SDPREG_SP "("SDPREG_TOKEN")" // net-type SDPREG_SP "("SDPREG_TOKEN")" // addr-type SDPREG_SP "("SDPREG_NON_WS_STRING")"); // unicast-address reg_origin.AssertMatch (buffer, this); for (int i=0 ; i<6 ; i++) { SetHypFieldLength (i, reg_origin.GetMatchedLength(i+1)); } } void SDP_Origin::PreDecodeField (int id, Buffer& buffer) throw (DecodeError) { if (id) { static Regex reg_sp (" "); reg_sp.AssertMatch (buffer, this); reg_sp.MovePast (buffer); } } #define SDP_CODET_HEADER_LIST(letter, type) \ void type::PreDecodeField (int id, Buffer& buffer) throw (DecodeError) \ { \ pre_decode_optional_field_multiple_times (*this, id, buffer, letter, &SetHypSize, &SetHypFieldLength); \ } SDP_CODET_HEADER_LIST ("e", SDP_email_list); SDP_CODET_HEADER_LIST ("p", SDP_phone_list); SDP_CODET_HEADER_LIST ("b", SDP_bandwidth_list); SDP_CODET_HEADER_LIST ("r", SDP_repeat_list); SDP_CODET_HEADER_LIST ("a", SDP_attribute_list); SDP_CODET_HEADER_LIST ("c", SDP_connection_list); void dummy (int a) { } // SDL_time and SDP_media_desc list are a little unusual compared to other // headers since these record can contain a list of headers // // In order to be able to decode it, we will not put any length // constraint on this header (thus passing &dummy instead of // &SetHypFieldLength), then it will be possible to decode the // repeate headers after the CRLF void SDP_time_list::PreDecodeField (int id, Buffer& buffer) throw (DecodeError) { pre_decode_optional_field_multiple_times (*this, id, buffer, "t", &SetHypSize, &dummy); } void SDP_media_desc_list::PreDecodeField (int id, Buffer& buffer) throw (DecodeError) { pre_decode_optional_field_multiple_times (*this, id, buffer, "m", &SetHypSize, &dummy); } void SDP_contact::PreDecode (Buffer& buffer) throw (DecodeError) { static Regex reg_addrspec_comment ("^(" SDPREG_ADDR_SPEC ")(" SDPREG_SP "[(](["SDPCHARS_EMAIL_SAFE"]+)[)])?"); static Regex reg_dispname_and_addr ("^(["SDPCHARS_EMAIL_SAFE"]+)" SDPREG_SP "<(" SDPREG_ADDR_SPEC ")>"); static Regex reg_phone_comment ("^(" SDPREG_PHONE ")(" SDPREG_SP "[(](["SDPCHARS_EMAIL_SAFE"]+)[)])?"); static Regex reg_dispname_and_phone ("^(["SDPCHARS_EMAIL_SAFE"]+)" SDPREG_SP "<(" SDPREG_PHONE ")>"); Regex *reg_normal, *reg_reverse; if (dynamic_cast(GetParent())) { // this is a phone contact reg_normal = ®_phone_comment; reg_reverse = ®_dispname_and_phone; } else { // this is an email contact reg_normal = ®_addrspec_comment; reg_reverse = ®_dispname_and_addr; } // by default we assume that there is no name displayed SetHypFieldIsPresent (id_disp_name, 0); if (reg_normal->Match (buffer)) { mReverseOrder = false; SetHypFieldLength (id_addr_or_phone, reg_normal->GetMatchedLength (1)); mHasComment = reg_normal->GetMatchedLength (2); if (mHasComment) { SetHypFieldIsPresent (id_disp_name, 1); SetHypFieldLength (id_disp_name, reg_normal->GetMatchedLength (3)); } } else if (reg_reverse->Match (buffer)) { mReverseOrder = true; SetHypFieldLength (id_addr_or_phone, reg_reverse->GetMatchedLength (2)); SetHypFieldIsPresent (id_disp_name, 1); SetHypFieldLength (id_disp_name, reg_reverse->GetMatchedLength (1)); // remember the position of the display name to be able // to decode it later mNextPosition = buffer.GetPosition(); // then place the cursor of the buffer at the position of the // email address reg_reverse->MoveAt (buffer, 2); } else { throw DecodeError (this, "Cannot match email address or phone number\n"); } } void SDP_contact::PostDecodeField (int id, Buffer& buffer) throw (DecodeError) { if (mReverseOrder) { if (id == id_addr_or_phone) { int disp_name_position = mNextPosition; // remember the position past the closing ">" mNextPosition = buffer.GetPosition() + 8; buffer.SetPosition (disp_name_position); } else { // once everything is decoded we move forward to the // end of the message field buffer.SetPosition (mNextPosition); } } else if (mHasComment) { buffer.SetPosition (buffer.GetPosition() + ( (id == id_addr_or_phone) ? 16 // move past the " (" : 8 // move past the ")" )); } } void SDP_connection::PreDecodeField (int id, Buffer& buffer) throw (DecodeError) { if (id == id_net_type) { static Regex reg_connection ("^(" SDPREG_TOKEN ") (" SDPREG_TOKEN ") (" SDPREG_NON_WS_STRING ")"); reg_connection.AssertMatch (buffer, this); SetHypFieldLength (id_net_type, reg_connection.GetMatchedLength (1)); SetHypFieldLength (id_addr_type, reg_connection.GetMatchedLength (2)); SetHypFieldLength (id_conn_addr, reg_connection.GetMatchedLength (3)); } else { buffer.SetPosition (buffer.GetPosition() + 8); // move past the SP } } void SDP_conn_addr::PreDecodeField (int id, Buffer& buffer) throw (DecodeError) { if (id == id_addr) { static Regex reg_ip4 ("^("SDPREG_IP4_ADDRESS")((?:[/]("SDPREG_INTEGER"))?((?:[/]("SDPREG_INTEGER"))?))"); static Regex reg_ip6 ("^([0-9a-fA-F.:]+)((?:[/]("SDPREG_INTEGER"))?)"); unsigned char ip6_addr[16]; // use ascii format for the integers Get_ttl().SetFormat(Integer::AsciiDecimal); Get_num_of_addr().SetFormat(Integer::AsciiDecimal); // ttl and addr_num are not present by default SetHypFieldIsPresent (id_ttl, 0); SetHypFieldIsPresent (id_num_of_addr, 0); /* reg_ip4.AssertMatch (buffer, this); for (int i=0 ; i<6 ; i++) { cerr << "Matched string " << i << " -> " << reg_ip4.GetMatchedString (i) << endl; cerr << "Matched length " << i << " -> " << reg_ip4.GetMatchedLength (i) << endl; } */ if (reg_ip4.Match (buffer)) { SetHypFieldLength (id_addr, reg_ip4.GetMatchedLength (1)); if (atoi (reg_ip4.GetMatchedString(1).c_str()) < 224) { // unicast address if (reg_ip4.GetMatchedLength(2) | reg_ip4.GetMatchedLength(4)) throw DecodeError (this, "TTL and/or number of connections fields can be present only with multicast addresses\n"); } else { // multicast address if (! reg_ip4.GetMatchedLength (2)) throw DecodeError (this, "IPv4 multicast address must be followed with the TTL"); SetHypFieldIsPresent (id_ttl, 1); SetHypFieldLength (id_ttl, reg_ip4.GetMatchedLength (3)); if (reg_ip4.GetMatchedLength (4)) { SetHypFieldIsPresent (id_num_of_addr, 1); SetHypFieldLength (id_num_of_addr, reg_ip4.GetMatchedLength (5)); } } } else if ( reg_ip6.Match (buffer) #ifndef WIN32 // FIXME: inet_pton does not exist in WIN32 && (inet_pton (AF_INET6, reg_ip6.GetMatchedString(1).c_str(), &ip6_addr) == 1) // if it does not contain a valid ipv6 address, then // we will parse it as another address family #endif ) { SetHypFieldLength (id_addr, reg_ip6.GetMatchedLength (1)); if (ip6_addr[0] != 0xFF) { // unicast address if (reg_ip4.GetMatchedLength(2)) throw DecodeError (this, "The number of connections can be present only with multicast addresses\n"); } else { // multicast address if (reg_ip6.GetMatchedLength (2)) { SetHypFieldIsPresent (id_num_of_addr, 1); SetHypFieldLength (id_num_of_addr, reg_ip6.GetMatchedLength (3)); } } } else { // if it is not an ipv4 or ipv6 address // then we put everything in the addr field } } else if (GetHypFieldIsPresent (id)) { buffer.SetPosition (buffer.GetPosition() + 8); // move past the "/" } } void SDP_bandwidth::PreDecodeField (int id, Buffer& buffer) throw (DecodeError) { if (id == id_modifier) { static Regex reg_bw ("^(" SDPREG_TOKEN "):([0-9]+)"); reg_bw.AssertMatch (buffer, this); SetHypFieldLength (id_modifier, reg_bw.GetMatchedLength(1)); SetHypFieldLength (id_bandwidth, reg_bw.GetMatchedLength(2)); } else { Get_bandwidth().SetFormat(Integer::AsciiDecimal); Unsigned(8).Decode(buffer); // move past the colon } } void SDP_time::PreDecodeField (int id, Buffer& buffer) throw (DecodeError) { if (id == id_time_repeat) { static Regex reg_repeat ("^(\r\n)r="); if (reg_repeat.Match (buffer)) { SetHypFieldIsPresent (id, 1); reg_repeat.MovePast (buffer, 1); } else { SetHypFieldIsPresent (id, 0); } } } void SDP_time_field::PreDecodeField (int id, Buffer& buffer) throw (DecodeError) { if (id == id_start_time) { static Regex reg_times ("^(" SDPREG_TIME_INTEGER ")" SDPREG_SP "(" SDPREG_TIME_INTEGER ")"); reg_times.AssertMatch (buffer, this); SetHypFieldLength (id_start_time, reg_times.GetMatchedLength (1)); SetHypFieldLength (id_stop_time, reg_times.GetMatchedLength (2)); } else { Unsigned(8).Decode (buffer); // move past the SP } } void SDP_typed_time::PreDecode (Buffer& buffer) throw (DecodeError) { static Regex reg_ttime ("^(-?[0-9]*)([dhms]?)"); reg_ttime.AssertMatch (buffer, this); Get_time().SetFormat(Integer::AsciiDecimal); SetHypFieldLength (id_time, reg_ttime.GetMatchedLength (1)); bool has_unit = reg_ttime.GetMatchedLength (2); SetHypFieldIsPresent (id_unit, has_unit ? 1 : 0); if (has_unit) { SetHypFieldLength (id_unit, 8); } } void SDP_repeat::PreDecodeField (int id, Buffer& buffer) throw (DecodeError) { if (id == id_active) { static Regex reg_sp ("^" SDPREG_SP); reg_sp.AssertMatch (buffer, this); reg_sp.MovePast (buffer, 0); } } void SDP_typed_time_list::PreDecodeField (int id, Buffer& buffer) throw (DecodeError) { static Regex reg_sp ("^(" SDPREG_SP ")[0-9]+"); if (reg_sp.Match (buffer)) { reg_sp.MovePast (buffer, 1); } else { SetHypSize (-2); } } void SDP_timezone_list::PostDecodeField (int id, Buffer& buffer) throw (DecodeError) { static Regex reg_sp ("^(" SDPREG_SP ")[0-9]"); if (reg_sp.Match (buffer)) { reg_sp.MovePast (buffer, 1); } else { SetHypSize (-2); } } void SDP_timezone::PreDecodeField (int id, Buffer& buffer) throw (DecodeError) { if (id == id_adjustment_time) { static Regex reg_tz ("^([1-9][0-9]*)" SDPREG_SP); reg_tz.AssertMatch (buffer, this); SetHypFieldLength (id_adjustment_time, reg_tz.GetMatchedLength(1)); } else { Unsigned(8).Decode(buffer); // move past the SP } } void SDP_key::PreDecodeField (int id, Buffer& buffer) throw (DecodeError) { if (id == id_method) { static Regex reg_method ("^(prompt|clear|base64|uri)(:?)"); reg_method.AssertMatch (buffer, this); if (reg_method.GetMatchedString(1) == "prompt") { if (reg_method.GetMatchedLength(2)) throw DecodeError (this, "the 'prompt' method must not be followed by a value\n"); } else { if (!reg_method.GetMatchedLength(2)) throw DecodeError (this, "the method must not be followed by a value\n"); } SetHypFieldLength (id_method, reg_method.GetMatchedLength (1)); SetHypFieldIsPresent (id_key, reg_method.GetMatchedLength (2) ? 1 : 0); } else { if (GetHypFieldIsPresent (id)) { Unsigned(8).Decode(buffer); // move past the colon // TODO: validate the content of the key ? } } } class SdpAttributeMap { public: struct Entry { Entry (const char* name, int id_attr) : mName (name), mIdAttribute (id_attr) {} const std::string mName; const int mIdAttribute; }; static const Entry& GetByName (const std::string& key) { const mMapName_t& m = msInstance.mMapName; mMapName_t::const_iterator it = m.find (key); if (it != m.end()) { return *it->second; } else { return *msInstance.mUndef; } } static const Entry& GetByIdMessageHeader (int key) { const std::map& m = msInstance.mMapIdAttribute; std::map ::const_iterator it = m.find (key); if (it != m.end()) { return *it->second; } else { return *msInstance.mUndef; } } private: void AddEntry (const Entry& entry) { mEntries.push_back(entry); Entry& e = *mEntries.rbegin(); //TODO: check unicity mMapName[e.mName] = &e; mMapIdAttribute[e.mIdAttribute] = &e; } SdpAttributeMap() { #define SDP_ATTRIBUTE_ADD(name) AddEntry (Entry (#name, SDP_attribute::id_ ## name)); // Name SDP_ATTRIBUTE_ADD (cat); SDP_ATTRIBUTE_ADD (keywds); SDP_ATTRIBUTE_ADD (tool); SDP_ATTRIBUTE_ADD (ptime); SDP_ATTRIBUTE_ADD (recvonly); SDP_ATTRIBUTE_ADD (sendrecv); SDP_ATTRIBUTE_ADD (sendonly); SDP_ATTRIBUTE_ADD (inactive); SDP_ATTRIBUTE_ADD (orient); AddEntry (Entry ("type", SDP_attribute::id_sdp_type)); SDP_ATTRIBUTE_ADD (sdp_type); SDP_ATTRIBUTE_ADD (charset); SDP_ATTRIBUTE_ADD (sdplang); SDP_ATTRIBUTE_ADD (lang); SDP_ATTRIBUTE_ADD (framerate); SDP_ATTRIBUTE_ADD (quality); SDP_ATTRIBUTE_ADD (fmtp); SDP_ATTRIBUTE_ADD (rtpmap); SDP_ATTRIBUTE_ADD (rtcp); // RFC 3312 attributes SDP_ATTRIBUTE_ADD (curr); SDP_ATTRIBUTE_ADD (des); SDP_ATTRIBUTE_ADD (conf); { mEntries.push_back(Entry("", SDP_attribute::id_unknown)); Entry& e = *mEntries.rbegin(); mMapIdAttribute[e.mIdAttribute] = &e; mUndef = &e; } } static SdpAttributeMap msInstance; std::list mEntries; Entry* mUndef; typedef std::map mMapName_t; mMapName_t mMapName; std::map mMapIdAttribute; }; SdpAttributeMap SdpAttributeMap::msInstance; void SDP_attribute::PreDecode (Buffer& buffer) throw (DecodeError) { Regex reg_attr ("^("SDPREG_TOKEN")(?:(:)("SDPREG_BYTE_STRING"))?"); reg_attr.AssertMatch (buffer, this); int id = SdpAttributeMap::GetByName (reg_attr.GetMatchedString(1)).mIdAttribute; SetHypChosenId (id); if (id != id_unknown) { SetHypLength (reg_attr.GetMatchedLength(3)); reg_attr.MovePast(buffer, (reg_attr.GetMatchedLength(2) ? 2 : 1) ); } } void SDP_attribute_unknown::PreDecodeField (int id, Buffer& buffer) throw (DecodeError) { if (id == id_name) { Regex reg_attr ("^("SDPREG_TOKEN")((?::("SDPREG_BYTE_STRING"))?)"); reg_attr.AssertMatch (buffer, this); SetHypFieldLength (id_name, reg_attr.GetMatchedLength (1)); int val_len = reg_attr.GetMatchedLength(3); SetHypFieldIsPresent (id_attr_value, (val_len ? 1 : 0)); if (val_len) SetHypFieldLength (id_attr_value, val_len); } else if (GetHypFieldIsPresent (id)){ Unsigned(8).Decode(buffer); // move past the colon } } void SDP_attribute_curr::PreDecodeField (int id, Buffer& buffer) throw (DecodeError) { if (id == 0) { Regex reg_attr ("^("SDPREG_TOKEN")" SDPREG_SP "(e2e|local|remote)" SDPREG_SP "(none|sendrecv|send|recv)"); reg_attr.AssertMatch (buffer, this); SetHypFieldLength (0, reg_attr.GetMatchedLength (1)); SetHypFieldLength (1, reg_attr.GetMatchedLength (2)); SetHypFieldLength (2, reg_attr.GetMatchedLength (3)); } else if (GetHypFieldIsPresent (id)){ Unsigned(8).Decode(buffer); // move past the space } } void SDP_attribute_des::PreDecodeField (int id, Buffer& buffer) throw (DecodeError) { if (id == 0) { Regex reg_attr ("^("SDPREG_TOKEN")" SDPREG_SP "(mandatory|optional|none|failure|unknown)" SDPREG_SP "(e2e|local|remote)" SDPREG_SP "(none|sendrecv|send|recv)"); reg_attr.AssertMatch (buffer, this); SetHypFieldLength (0, reg_attr.GetMatchedLength (1)); SetHypFieldLength (1, reg_attr.GetMatchedLength (2)); SetHypFieldLength (2, reg_attr.GetMatchedLength (3)); SetHypFieldLength (3, reg_attr.GetMatchedLength (4)); } else if (GetHypFieldIsPresent (id)){ Unsigned(8).Decode(buffer); // move past the space } } void SDP_attribute_conf::PreDecodeField (int id, Buffer& buffer) throw (DecodeError) { if (id == 0) { Regex reg_attr ("^("SDPREG_TOKEN")" SDPREG_SP "(e2e|local|remote)" SDPREG_SP "(none|sendrecv|send|recv)"); reg_attr.AssertMatch (buffer, this); SetHypFieldLength (0, reg_attr.GetMatchedLength (1)); SetHypFieldLength (1, reg_attr.GetMatchedLength (2)); SetHypFieldLength (2, reg_attr.GetMatchedLength (3)); } else if (GetHypFieldIsPresent (id)){ Unsigned(8).Decode(buffer); // move past the space } } void SDP_media_field::PreDecodeField (int id, Buffer& buffer) throw (DecodeError) { static Regex reg_media ("^("SDPREG_TOKEN")" SDPREG_SP "([0-9/]+)" SDPREG_SP "("SDPREG_TOKEN"(?:/"SDPREG_TOKEN")*)" ); if (id==0) { reg_media.AssertMatch (buffer, this); SetHypFieldLength (id_media, reg_media.GetMatchedLength (1)); SetHypFieldLength (id_ports, reg_media.GetMatchedLength (2)); SetHypFieldLength (id_transport, reg_media.GetMatchedLength (3)); } else if (id != id_fmts) { Unsigned(8).Decode(buffer); // move past the SP } } void SDP_media_field::PostDecodeField (int id, Buffer& buffer) throw (DecodeError) { static Regex reg_space ("^"SDPREG_SP); if(id == id_ports) { // Necessary as 2nd part of SDP_media_port regex // could be a mismatch (ex: num-of_ports=0) ! reg_space.AssertMatch(buffer, this); } } void SDP_media_port::PreDecodeField (int id, Buffer& buffer) throw (DecodeError) { static Regex reg_port ("^([0-9]+)(/("SDPREG_INTEGER"))?"); if (id == 0) { reg_port.AssertMatch (buffer, this); Get_port_number().SetFormat(Integer::AsciiDecimal); SetHypFieldLength (id_port_number, reg_port.GetMatchedLength(1)); if (reg_port.GetMatchedLength (2)) { SetHypFieldIsPresent (id_num_of_ports, 1); SetHypFieldLength (id_num_of_ports, reg_port.GetMatchedLength(3)); Get_num_of_ports().SetFormat(Integer::AsciiDecimal); } else { SetHypFieldIsPresent (id_num_of_ports, 0); } } else { if (GetHypFieldIsPresent (id)) { Unsigned(8).Decode(buffer); // move past the '/' } } } void SDP_fmt_list::PreDecodeField (int id, Buffer& buffer) throw (DecodeError) { static Regex reg_fmt ("^"SDPREG_SP"("SDPREG_TOKEN")"); if (reg_fmt.Match (buffer)) { reg_fmt.MoveAt (buffer, 1); SetHypFieldLength (reg_fmt.GetMatchedLength(1)); } else { SetHypSize (-2); } } void SDP_media_desc::PreDecodeField (int id, Buffer& buffer) throw (DecodeError) { if (id == id_media_field) // media_field is always present and the "m=" was // already processed by SDP_message::PreDecodeField() return; static Regex reg_field("^(([a-z])=)([^\\r\\n\\x00]*)"); const char* expected = NULL; switch (id) { case id_information: expected = "i"; goto optional_once; case id_connections: expected = "c"; goto optional_many; case id_bandwidth: expected = "b"; goto optional_once; case id_key: expected = "k"; goto optional_once; case id_attributes: expected = "a"; goto optional_many; } return; mandatory: reg_field.AssertMatch (buffer, this); SetHypFieldLength (id, reg_field.GetMatchedLength(3)); if (reg_field.GetMatchedString(2) != expected) { DecodeError e(this); e.Msg() << "missing mandatory field " << expected << "= before field " << reg_field.GetMatchedString(1) << endl; throw e; } reg_field.MovePast (buffer, 1); return; optional_once: if (reg_field.Match (buffer) && reg_field.GetMatchedString(2) == expected) { // the field is present SetHypFieldIsPresent (id, 1); SetHypFieldLength (id, reg_field.GetMatchedLength(3)); reg_field.MovePast (buffer, 1); } else { // the field is not present SetHypFieldIsPresent (id, 0); } return; optional_many: SetHypFieldIsPresent (id, (reg_field.Match (buffer) && reg_field.GetMatchedString(2) == expected) ? 1 : 0); } void SDP_media_desc::PostDecodeField (int id, Buffer& buffer) throw (DecodeError) { static Regex reg_crlf ("^\r\n"); if (IsPresent (id)) { reg_crlf.AssertMatch (buffer, this); reg_crlf.MovePast (buffer); } } void SDP_media_desc::PostDecode (Buffer& buffer) throw (DecodeError) { buffer.SetPosition(buffer.GetPosition()-16); // go back 2 chars so that the CRLF is matched by the SDP_Message::PostDecodeField(); } // // Implementation of the encoder for SDP // void SDP_Message::PreEncodeField (int field_id, Buffer& buffer) throw (EncodeError) { Charstring csHeader; if(IsPresent(field_id)) { switch(field_id) { case id_protocol_version: Get_protocol_version().SetFormat(Integer::AsciiDecimal); csHeader.SetValue("v="); csHeader.Encode(buffer); break; case id_origin: csHeader.SetValue("o="); csHeader.Encode(buffer); break; case id_session_name: csHeader.SetValue("s="); csHeader.Encode(buffer); break; case id_information: csHeader.SetValue("i="); csHeader.Encode(buffer); break; case id_uri: csHeader.SetValue("u="); csHeader.Encode(buffer); break; case id_connection: csHeader.SetValue("c="); csHeader.Encode(buffer); break; case id_key: csHeader.SetValue("k="); csHeader.Encode(buffer); break; case id_timezone_adjustments: csHeader.SetValue("z="); csHeader.Encode(buffer); break; } } } void SDP_Message::PostEncodeField (int field_id, Buffer& buffer) throw (EncodeError) { Charstring csCRLF; csCRLF.SetValue("\r\n"); switch(field_id) { case id_protocol_version: case id_origin: case id_session_name: case id_information: case id_uri: case id_connection: case id_key: case id_timezone_adjustments: if(IsPresent(field_id)) { csCRLF.Encode(buffer); } break; case id_emails: case id_phone_numbers: case id_bandwidth: case id_times: case id_attributes: case id_media_list: break; } } void SDP_Origin::PreEncodeField (int field_id, Buffer& buffer) throw (EncodeError) { Charstring csSpace; csSpace.SetValue(" "); if(field_id != 0) { csSpace.Encode(buffer); } } void SDP_connection::PreEncodeField (int field_id, Buffer& buffer) throw (EncodeError) { Charstring csSpace; csSpace.SetValue(" "); if(field_id != 0) { csSpace.Encode(buffer); } } void SDP_conn_addr::PreEncode (Buffer& buffer) throw (EncodeError) { Get_ttl().SetFormat(Integer::AsciiDecimal); Get_num_of_addr().SetFormat(Integer::AsciiDecimal); } void SDP_conn_addr::PreEncodeField (int field_id, Buffer& buffer) throw (EncodeError) { Charstring csSlash; csSlash.SetValue("/"); if(IsPresent(field_id)) { switch(field_id) { case id_ttl: case id_num_of_addr: csSlash.Encode(buffer); break; } } } void SDP_email_list::PreEncodeField (int field_id, Buffer& buffer) throw (EncodeError) { Charstring csHeader; csHeader.SetValue("e="); csHeader.Encode(buffer); } void SDP_email_list::PostEncodeField (int field_id, Buffer& buffer) throw (EncodeError) { Charstring csCRLF; csCRLF.SetValue("\r\n"); csCRLF.Encode(buffer); } void SDP_phone_list::PreEncodeField (int field_id, Buffer& buffer) throw (EncodeError) { Charstring csHeader; csHeader.SetValue("p="); csHeader.Encode(buffer); } void SDP_phone_list::PostEncodeField (int field_id, Buffer& buffer) throw (EncodeError) { Charstring csCRLF; csCRLF.SetValue("\r\n"); csCRLF.Encode(buffer); } void SDP_bandwidth_list::PreEncodeField (int field_id, Buffer& buffer) throw (EncodeError) { } void SDP_bandwidth::PostEncode (Buffer& buffer) throw (EncodeError) { Charstring csCRLF; csCRLF.SetValue("\r\n"); csCRLF.Encode(buffer); } void SDP_bandwidth::PreEncode (Buffer& buffer) throw (EncodeError) { Charstring csHeader; csHeader.SetValue("b="); csHeader.Encode(buffer); Get_bandwidth().SetFormat(Integer::AsciiDecimal); } void SDP_bandwidth::PostEncodeField (int field_id, Buffer& buffer) throw (EncodeError) { Charstring csColon; csColon.SetValue(":"); if(field_id == id_modifier) { csColon.Encode(buffer); } } void SDP_timezone::PreEncodeField (int field_id, Buffer& buffer) throw (EncodeError) { Charstring csSpace; csSpace.SetValue(" "); if(field_id != 0) { csSpace.Encode(buffer); } } void SDP_timezone_list::PreEncodeField (int field_id, Buffer& buffer) throw (EncodeError) { Charstring csSpace; csSpace.SetValue(" "); if(field_id != 0) { csSpace.Encode(buffer); } } void SDP_typed_time::PreEncode (Buffer& buffer) throw (EncodeError) { Get_time().SetFormat(Integer::AsciiDecimal); } void SDP_attribute_list::PreEncodeField (int field_id, Buffer& buffer) throw (EncodeError) { Charstring csHeader; csHeader.SetValue("a="); csHeader.Encode(buffer); } void SDP_attribute_list::PostEncodeField (int field_id, Buffer& buffer) throw (EncodeError) { Charstring csCRLF; csCRLF.SetValue("\r\n"); csCRLF.Encode(buffer); } void SDP_media_field::PreEncode (Buffer& buffer) throw (EncodeError) { Charstring csHeader; csHeader.SetValue("m="); csHeader.Encode(buffer); } void SDP_media_field::PreEncodeField (int field_id, Buffer& buffer) throw (EncodeError) { Charstring csSpace; csSpace.SetValue(" "); if(field_id != 0) { csSpace.Encode(buffer); } } void SDP_fmt_list::PreEncodeField (int field_id, Buffer& buffer) throw (EncodeError) { Charstring csSpace; csSpace.SetValue(" "); if(field_id != 0) { csSpace.Encode(buffer); } } void SDP_media_port::PreEncode (Buffer& buffer) throw (EncodeError) { Get_port_number().SetFormat(Integer::AsciiDecimal); } void SDP_media_port::PreEncodeField (int field_id, Buffer& buffer) throw (EncodeError) { Charstring csSlash; csSlash.SetValue("/"); if((field_id == id_num_of_ports) && IsPresent(id_num_of_ports)) { Get_num_of_ports().SetFormat(Integer::AsciiDecimal); csSlash.Encode(buffer); } } void SDP_media_field::PostEncode (Buffer& buffer) throw (EncodeError) { Charstring csCRLF; csCRLF.SetValue("\r\n"); csCRLF.Encode(buffer); } void SDP_media_desc::PreEncodeField (int field_id, Buffer& buffer) throw (EncodeError) { Charstring csHeader; if(IsPresent(field_id)) { switch(field_id) { case id_information: csHeader.SetValue("i="); csHeader.Encode(buffer); break; case id_key: csHeader.SetValue("k="); csHeader.Encode(buffer); break; } } } void SDP_media_desc::PostEncodeField (int field_id, Buffer& buffer) throw (EncodeError) { Charstring csCRLF; csCRLF.SetValue("\r\n"); switch(field_id) { case id_information: case id_key: if(IsPresent(field_id)) { csCRLF.Encode(buffer); } break; } } void SDP_connection_list::PreEncodeField (int field_id, Buffer& buffer) throw (EncodeError) { Charstring csHeader; csHeader.SetValue("c="); csHeader.Encode(buffer); } void SDP_connection_list::PostEncodeField (int field_id, Buffer& buffer) throw (EncodeError) { Charstring csCRLF; csCRLF.SetValue("\r\n"); csCRLF.Encode(buffer); } void SDP_key::PreEncodeField (int field_id, Buffer& buffer) throw (EncodeError) { Charstring csColon; csColon.SetValue(":"); if((field_id == id_key) && IsPresent(id_key)) { csColon.Encode(buffer); } } void SDP_contact::PreEncodeField (int field_id, Buffer& buffer) throw (EncodeError) { Charstring csLeftPar, csSpace; csLeftPar.SetValue("("); csSpace.SetValue(" "); if((field_id == id_disp_name) && IsPresent(id_disp_name)) { csSpace.Encode(buffer); csLeftPar.Encode(buffer); } } void SDP_contact::PostEncodeField (int field_id, Buffer& buffer) throw (EncodeError) { Charstring csRightPar; csRightPar.SetValue(")"); if((field_id == id_disp_name) && IsPresent(id_disp_name)) { csRightPar.Encode(buffer); } } void SDP_repeat_list::PreEncodeField (int field_id, Buffer& buffer) throw (EncodeError) { Charstring csHeader; csHeader.SetValue("r="); csHeader.Encode(buffer); } void SDP_repeat_list::PostEncodeField (int field_id, Buffer& buffer) throw (EncodeError) { Charstring csCRLF; csCRLF.SetValue("\r\n"); csCRLF.Encode(buffer); } void SDP_repeat::PreEncodeField (int field_id, Buffer& buffer) throw (EncodeError) { Charstring csSpace; csSpace.SetValue(" "); if(field_id == id_active) { csSpace.Encode(buffer); } } void SDP_typed_time_list::PreEncodeField (int field_id, Buffer& buffer) throw (EncodeError) { Charstring csSpace; csSpace.SetValue(" "); csSpace.Encode(buffer); } void SDP_time_field::PreEncode (Buffer& buffer) throw (EncodeError) { Charstring csHeader; csHeader.SetValue("t="); csHeader.Encode(buffer); } void SDP_time_field::PostEncode (Buffer& buffer) throw (EncodeError) { Charstring csCRLF; csCRLF.SetValue("\r\n"); csCRLF.Encode(buffer); } void SDP_time_field::PreEncodeField (int field_id, Buffer& buffer) throw (EncodeError) { Charstring csSpace; csSpace.SetValue(" "); if(field_id == id_stop_time) { csSpace.Encode(buffer); } } void SDP_attribute_cat::PreEncode (Buffer& buffer) throw (EncodeError) { Charstring csAttrName; csAttrName.SetValue("cat:"); csAttrName.Encode(buffer); } void SDP_attribute_keywds::PreEncode (Buffer& buffer) throw (EncodeError) { Charstring csAttrName; csAttrName.SetValue("keywds:"); csAttrName.Encode(buffer); } void SDP_attribute_tool::PreEncode (Buffer& buffer) throw (EncodeError) { Charstring csAttrName; csAttrName.SetValue("tool:"); csAttrName.Encode(buffer); } void SDP_attribute_ptime::PreEncode (Buffer& buffer) throw (EncodeError) { Charstring csAttrName; csAttrName.SetValue("ptime:"); csAttrName.Encode(buffer); } void SDP_attribute_recvonly::PreEncode (Buffer& buffer) throw (EncodeError) { Charstring csAttrName; csAttrName.SetValue("recvonly"); csAttrName.Encode(buffer); } void SDP_attribute_sendrecv::PreEncode (Buffer& buffer) throw (EncodeError) { Charstring csAttrName; csAttrName.SetValue("sendrecv"); csAttrName.Encode(buffer); } void SDP_attribute_sendonly::PreEncode (Buffer& buffer) throw (EncodeError) { Charstring csAttrName; csAttrName.SetValue("sendonly"); csAttrName.Encode(buffer); } void SDP_attribute_inactive::PreEncode (Buffer& buffer) throw (EncodeError) { Charstring csAttrName; csAttrName.SetValue("inactive"); csAttrName.Encode(buffer); } void SDP_attribute_orient::PreEncode (Buffer& buffer) throw (EncodeError) { Charstring csAttrName; csAttrName.SetValue("orient:"); csAttrName.Encode(buffer); } void SDP_attribute_type::PreEncode (Buffer& buffer) throw (EncodeError) { Charstring csAttrName; csAttrName.SetValue("type:"); csAttrName.Encode(buffer); } void SDP_attribute_charset::PreEncode (Buffer& buffer) throw (EncodeError) { Charstring csAttrName; csAttrName.SetValue("charset:"); csAttrName.Encode(buffer); } void SDP_attribute_sdplang::PreEncode (Buffer& buffer) throw (EncodeError) { Charstring csAttrName; csAttrName.SetValue("sdplang:"); csAttrName.Encode(buffer); } void SDP_attribute_lang::PreEncode (Buffer& buffer) throw (EncodeError) { Charstring csAttrName; csAttrName.SetValue("lang:"); csAttrName.Encode(buffer); } void SDP_attribute_framerate::PreEncode (Buffer& buffer) throw (EncodeError) { Charstring csAttrName; csAttrName.SetValue("framerate:"); csAttrName.Encode(buffer); } void SDP_attribute_quality::PreEncode (Buffer& buffer) throw (EncodeError) { Charstring csAttrName; csAttrName.SetValue("quality:"); csAttrName.Encode(buffer); } void SDP_attribute_fmtp::PreEncode (Buffer& buffer) throw (EncodeError) { Charstring csAttrName; csAttrName.SetValue("fmtp:"); csAttrName.Encode(buffer); } void SDP_attribute_curr::PreEncode (Buffer& buffer) throw (EncodeError) { Charstring csAttrName; csAttrName.SetValue("curr:"); csAttrName.Encode(buffer); } void SDP_attribute_curr::PreEncodeField (int field_id, Buffer& buffer) throw (EncodeError) { Charstring csSpace; csSpace.SetValue(" "); if(field_id != 0) { csSpace.Encode(buffer); } } void SDP_attribute_des::PreEncode (Buffer& buffer) throw (EncodeError) { Charstring csAttrName; csAttrName.SetValue("des:"); csAttrName.Encode(buffer); } void SDP_attribute_des::PreEncodeField (int field_id, Buffer& buffer) throw (EncodeError) { Charstring csSpace; csSpace.SetValue(" "); if(field_id != 0) { csSpace.Encode(buffer); } } void SDP_attribute_conf::PreEncode (Buffer& buffer) throw (EncodeError) { Charstring csAttrName; csAttrName.SetValue("conf:"); csAttrName.Encode(buffer); } void SDP_attribute_conf::PreEncodeField (int field_id, Buffer& buffer) throw (EncodeError) { Charstring csSpace; csSpace.SetValue(" "); if(field_id != 0) { csSpace.Encode(buffer); } } void SDP_attribute_rtpmap::PreEncode (Buffer& buffer) throw (EncodeError) { Charstring csAttrName; csAttrName.SetValue("rtpmap:"); csAttrName.Encode(buffer); } void SDP_attribute_rtcp::PreEncode (Buffer& buffer) throw (EncodeError) { Charstring csAttrName; csAttrName.SetValue("rtcp:"); csAttrName.Encode(buffer); } void SDP_attribute_unknown::PreEncodeField (int field_id, Buffer& buffer) throw (EncodeError) { Charstring csColon; csColon.SetValue(":"); if((field_id == id_attr_value) && IsPresent(id_attr_value)) { csColon.Encode(buffer); } } }} // namespaces