Mercurial > hg > freeDiameter
comparison libfreeDiameter/messages.c @ 34:0e2b57789361
Backup for the WE, some warnings remaining
author | Sebastien Decugis <sdecugis@nict.go.jp> |
---|---|
date | Fri, 30 Oct 2009 17:23:06 +0900 |
parents | e5af94b04946 |
children | 6486e97f56ae |
comparison
equal
deleted
inserted
replaced
33:e6fcdf12b9a0 | 34:0e2b57789361 |
---|---|
121 struct { | 121 struct { |
122 void (*fct)(void *, struct msg **); | 122 void (*fct)(void *, struct msg **); |
123 void * data; | 123 void * data; |
124 } msg_cb; /* Callback to be called when an answer is received, if not NULL */ | 124 } msg_cb; /* Callback to be called when an answer is received, if not NULL */ |
125 char * msg_src_id; /* Diameter Id of the peer this message was received from. This string is malloc'd and must be freed */ | 125 char * msg_src_id; /* Diameter Id of the peer this message was received from. This string is malloc'd and must be freed */ |
126 uint32_t msg_src_hash; /* Hash of the msg_src_id value */ | |
127 }; | 126 }; |
128 | 127 |
129 /* Macro to compute the message header size */ | 128 /* Macro to compute the message header size */ |
130 #define GETMSGHDRSZ() 20 | 129 #define GETMSGHDRSZ() 20 |
131 | 130 |
665 msg->msg_public.msg_code, | 664 msg->msg_public.msg_code, |
666 msg->msg_public.msg_appl, | 665 msg->msg_public.msg_appl, |
667 msg->msg_public.msg_hbhid, | 666 msg->msg_public.msg_hbhid, |
668 msg->msg_public.msg_eteid | 667 msg->msg_public.msg_eteid |
669 ); | 668 ); |
670 fd_log_debug(INOBJHDR "intern: rwb:%p rt:%d cb:%p(%p) qry:%p h:%x src:%s\n", | 669 fd_log_debug(INOBJHDR "intern: rwb:%p rt:%d cb:%p(%p) qry:%p src:%s\n", |
671 INOBJHDRVAL, msg->msg_rawbuffer, msg->msg_routable, msg->msg_cb.fct, msg->msg_cb.data, msg->msg_query, msg->msg_src_hash, msg->msg_src_id?:"(nil)"); | 670 INOBJHDRVAL, msg->msg_rawbuffer, msg->msg_routable, msg->msg_cb.fct, msg->msg_cb.data, msg->msg_query, msg->msg_src_id?:"(nil)"); |
672 } | 671 } |
673 | 672 |
674 #define DUMP_VALUE(_format, _parms...) fd_log_debug(INOBJHDR "value : t:'%s' v:'" _format "'\n", INOBJHDRVAL, typename, ## _parms); | 673 #define DUMP_VALUE(_format, _parms...) fd_log_debug(INOBJHDR "value : t:'%s' v:'" _format "'\n", INOBJHDRVAL, typename, ## _parms); |
675 /* Dump an AVP value that is not a constant */ | 674 /* Dump an AVP value that is not a constant */ |
676 static void dump_basic_type(union avp_value * value, enum dict_avp_basetype type, const char * typename, int indent) | 675 static void dump_basic_type(union avp_value * value, enum dict_avp_basetype type, const char * typename, int indent) |
1074 | 1073 |
1075 return (msg->msg_routable == 1) ? 1 : 0; | 1074 return (msg->msg_routable == 1) ? 1 : 0; |
1076 } | 1075 } |
1077 | 1076 |
1078 /* Associate source peer */ | 1077 /* Associate source peer */ |
1079 int fd_msg_source_set( struct msg * msg, char * diamid, uint32_t hash, int add_rr, struct dictionary * dict ) | 1078 int fd_msg_source_set( struct msg * msg, char * diamid, int add_rr, struct dictionary * dict ) |
1080 { | 1079 { |
1081 TRACE_ENTRY( "%p %p %x %d %p", msg, diamid, hash, add_rr, dict); | 1080 TRACE_ENTRY( "%p %p %d %p", msg, diamid, add_rr, dict); |
1082 | 1081 |
1083 /* Check we received a valid message */ | 1082 /* Check we received a valid message */ |
1084 CHECK_PARAMS( CHECK_MSG(msg) && dict ); | 1083 CHECK_PARAMS( CHECK_MSG(msg) && dict ); |
1085 | 1084 |
1086 /* Cleanup any previous source */ | 1085 /* Cleanup any previous source */ |
1087 free(msg->msg_src_id); msg->msg_src_id = NULL; | 1086 free(msg->msg_src_id); msg->msg_src_id = NULL; |
1088 | 1087 |
1089 /* If the request is to cleanup the source, we are done */ | 1088 /* If the request is to cleanup the source, we are done */ |
1090 if (diamid == NULL) { | 1089 if (diamid == NULL) { |
1091 msg->msg_src_hash = 0; | |
1092 return 0; | 1090 return 0; |
1093 } | 1091 } |
1094 | 1092 |
1095 /* Otherwise save the new informations */ | 1093 /* Otherwise save the new informations */ |
1096 CHECK_MALLOC( msg->msg_src_id = strdup(diamid) ); | 1094 CHECK_MALLOC( msg->msg_src_id = strdup(diamid) ); |
1097 msg->msg_src_hash = hash; | |
1098 | 1095 |
1099 if (add_rr) { | 1096 if (add_rr) { |
1100 struct dict_object *avp_rr_model; | 1097 struct dict_object *avp_rr_model; |
1101 avp_code_t code = AC_ROUTE_RECORD; | 1098 avp_code_t code = AC_ROUTE_RECORD; |
1102 struct avp *avp; | 1099 struct avp *avp; |
1120 | 1117 |
1121 /* done */ | 1118 /* done */ |
1122 return 0; | 1119 return 0; |
1123 } | 1120 } |
1124 | 1121 |
1125 int fd_msg_source_get( struct msg * msg, char ** diamid, uint32_t *hash ) | 1122 int fd_msg_source_get( struct msg * msg, char ** diamid ) |
1126 { | 1123 { |
1127 TRACE_ENTRY( "%p %p %p", msg, diamid, hash); | 1124 TRACE_ENTRY( "%p %p", msg, diamid); |
1128 | 1125 |
1129 /* Check we received valid parameters */ | 1126 /* Check we received valid parameters */ |
1130 CHECK_PARAMS( CHECK_MSG(msg) ); | 1127 CHECK_PARAMS( CHECK_MSG(msg) ); |
1131 CHECK_PARAMS( diamid ); | 1128 CHECK_PARAMS( diamid ); |
1132 | 1129 |
1133 /* Copy the informations */ | 1130 /* Copy the informations */ |
1134 *diamid = msg->msg_src_id; | 1131 *diamid = msg->msg_src_id; |
1135 if (hash) | |
1136 *hash = msg->msg_src_hash; | |
1137 | 1132 |
1138 /* done */ | 1133 /* done */ |
1139 return 0; | 1134 return 0; |
1140 } | 1135 } |
1141 | 1136 |
1860 } | 1855 } |
1861 } | 1856 } |
1862 | 1857 |
1863 /* We use this structure as parameter for the next function */ | 1858 /* We use this structure as parameter for the next function */ |
1864 struct parserules_data { | 1859 struct parserules_data { |
1865 struct fd_list * sentinel; /* Sentinel of the list of children AVP */ | 1860 struct fd_list * sentinel; /* Sentinel of the list of children AVP */ |
1866 struct dict_object * ruleavp; /* If the rule conflicts, save the rule_avp here (we don't have direct access to the rule but it can be searched) */ | 1861 struct fd_pei * pei; /* If the rule conflicts, save the error here */ |
1867 }; | 1862 }; |
1863 | |
1864 /* Create an empty AVP of a given model (to use in Failed-AVP) */ | |
1865 static struct avp * empty_avp(struct dict_object * model_avp) | |
1866 { | |
1867 TODO("Create the AVP instance and set a 0 value"); | |
1868 return NULL; | |
1869 } | |
1868 | 1870 |
1869 /* Check that a list of AVPs is compliant with a given rule -- will be iterated on the list of rules */ | 1871 /* Check that a list of AVPs is compliant with a given rule -- will be iterated on the list of rules */ |
1870 static int parserules_check_one_rule(void * data, struct dict_rule_data *rule) | 1872 static int parserules_check_one_rule(void * data, struct dict_rule_data *rule) |
1871 { | 1873 { |
1872 int ret = 0, count, first, last, min; | 1874 int count, first, last, min; |
1873 struct parserules_data * pr_data = (struct parserules_data *) data; | 1875 struct parserules_data * pr_data = data; |
1874 | 1876 |
1875 TRACE_ENTRY("%p %p", data, rule); | 1877 TRACE_ENTRY("%p %p", data, rule); |
1876 | 1878 |
1877 /* Get statistics of the AVP concerned by this rule in the message instance */ | 1879 /* Get statistics of the AVP concerned by this rule in the parent instance */ |
1878 parserules_stat_avps( rule->rule_avp, pr_data->sentinel, &count, &first, &last); | 1880 parserules_stat_avps( rule->rule_avp, pr_data->sentinel, &count, &first, &last); |
1879 | 1881 |
1880 if (TRACE_BOOL(ANNOYING)) | 1882 if (TRACE_BOOL(ANNOYING)) |
1881 { | 1883 { |
1882 struct dict_avp_data avpdata; | 1884 struct dict_avp_data avpdata; |
1885 int ret; | |
1883 ret = fd_dict_getval(rule->rule_avp, &avpdata); | 1886 ret = fd_dict_getval(rule->rule_avp, &avpdata); |
1884 | 1887 |
1885 TRACE_DEBUG(ANNOYING, "Checking rule: p:%d(%d) m/M:%2d/%2d. Counted %d (first: %d, last:%d) of AVP '%s'", | 1888 TRACE_DEBUG(ANNOYING, "Checking rule: p:%d(%d) m/M:%2d/%2d. Counted %d (first: %d, last:%d) of AVP '%s'", |
1886 rule->rule_position, | 1889 rule->rule_position, |
1887 rule->rule_order, | 1890 rule->rule_order, |
1893 (ret == 0) ? avpdata.avp_name : "???" | 1896 (ret == 0) ? avpdata.avp_name : "???" |
1894 ); | 1897 ); |
1895 } | 1898 } |
1896 | 1899 |
1897 /* Now check the rule is not conflicting */ | 1900 /* Now check the rule is not conflicting */ |
1898 ret = 0; | |
1899 | 1901 |
1900 /* Check the "min" value */ | 1902 /* Check the "min" value */ |
1901 if ((min = rule->rule_min) == -1) { | 1903 if ((min = rule->rule_min) == -1) { |
1902 if (rule->rule_position == RULE_OPTIONAL) | 1904 if (rule->rule_position == RULE_OPTIONAL) |
1903 min = 0; | 1905 min = 0; |
1904 else | 1906 else |
1905 min = 1; | 1907 min = 1; |
1906 } | 1908 } |
1907 if (count < min) { | 1909 if (count < min) { |
1908 TRACE_DEBUG(INFO, "Conflicting rule: the number of occurences (%d) is < the rule min (%d).", count, min); | 1910 TRACE_DEBUG(INFO, "Conflicting rule: the number of occurences (%d) is < the rule min (%d).", count, min); |
1909 ret = EBADMSG; | 1911 if (pr_data->pei) { |
1910 goto end; | 1912 pr_data->pei->pei_errcode = "DIAMETER_MISSING_AVP"; |
1913 pr_data->pei->pei_avp = empty_avp(rule->rule_avp); | |
1914 } | |
1915 return EBADMSG; | |
1911 } | 1916 } |
1912 | 1917 |
1913 /* Check the "max" value */ | 1918 /* Check the "max" value */ |
1914 if ((rule->rule_max != -1) && (count > rule->rule_max)) { | 1919 if ((rule->rule_max != -1) && (count > rule->rule_max)) { |
1915 TRACE_DEBUG(INFO, "Conflicting rule: the number of occurences (%d) is > the rule max (%d).", count, rule->rule_max); | 1920 TRACE_DEBUG(INFO, "Conflicting rule: the number of occurences (%d) is > the rule max (%d).", count, rule->rule_max); |
1916 ret = EBADMSG; | 1921 if (pr_data->pei) { |
1917 goto end; | 1922 if (rule->rule_max == 0) |
1923 pr_data->pei->pei_errcode = "DIAMETER_AVP_NOT_ALLOWED"; | |
1924 else | |
1925 pr_data->pei->pei_errcode = "DIAMETER_AVP_OCCURS_TOO_MANY_TIMES"; | |
1926 pr_data->pei->pei_avp = empty_avp(rule->rule_avp); /* Well we are supposed to return the (max + 1)th instance of the AVP instead... Pfff... */ TODO("Improve..."); | |
1927 } | |
1928 return EBADMSG; | |
1918 } | 1929 } |
1919 | 1930 |
1920 /* Check the position and order (if relevant) */ | 1931 /* Check the position and order (if relevant) */ |
1921 switch (rule->rule_position) { | 1932 switch (rule->rule_position) { |
1922 case RULE_OPTIONAL: | 1933 case RULE_OPTIONAL: |
1926 | 1937 |
1927 case RULE_FIXED_HEAD: | 1938 case RULE_FIXED_HEAD: |
1928 /* Since "0*1<fixed>" is a valid rule specifier, we only reject cases where the AVP appears *after* its fixed position */ | 1939 /* Since "0*1<fixed>" is a valid rule specifier, we only reject cases where the AVP appears *after* its fixed position */ |
1929 if (first > rule->rule_order) { | 1940 if (first > rule->rule_order) { |
1930 TRACE_DEBUG(INFO, "Conflicting rule: the FIXED_HEAD AVP appears first in (%d) position, the rule requires (%d).", first, rule->rule_order); | 1941 TRACE_DEBUG(INFO, "Conflicting rule: the FIXED_HEAD AVP appears first in (%d) position, the rule requires (%d).", first, rule->rule_order); |
1931 ret = EBADMSG; | 1942 if (pr_data->pei) { |
1932 goto end; | 1943 pr_data->pei->pei_errcode = "DIAMETER_MISSING_AVP"; |
1944 pr_data->pei->pei_message = "AVP was not in its fixed position"; | |
1945 pr_data->pei->pei_avp = empty_avp(rule->rule_avp); | |
1946 } | |
1947 return EBADMSG; | |
1933 } | 1948 } |
1934 break; | 1949 break; |
1935 | 1950 |
1936 case RULE_FIXED_TAIL: | 1951 case RULE_FIXED_TAIL: |
1937 /* Since "0*1<fixed>" is a valid rule specifier, we only reject cases where the AVP appears *before* its fixed position */ | 1952 /* Since "0*1<fixed>" is a valid rule specifier, we only reject cases where the AVP appears *before* its fixed position */ |
1938 if (last > rule->rule_order) { /* We have a ">" here because we count in reverse order (i.e. from the end) */ | 1953 if (last > rule->rule_order) { /* We have a ">" here because we count in reverse order (i.e. from the end) */ |
1939 TRACE_DEBUG(INFO, "Conflicting rule: the FIXED_TAIL AVP appears last in (%d) position, the rule requires (%d).", last, rule->rule_order); | 1954 TRACE_DEBUG(INFO, "Conflicting rule: the FIXED_TAIL AVP appears last in (%d) position, the rule requires (%d).", last, rule->rule_order); |
1940 ret = EBADMSG; | 1955 if (pr_data->pei) { |
1941 goto end; | 1956 pr_data->pei->pei_errcode = "DIAMETER_MISSING_AVP"; |
1957 pr_data->pei->pei_message = "AVP was not in its fixed position"; | |
1958 pr_data->pei->pei_avp = empty_avp(rule->rule_avp); | |
1959 } | |
1960 return EBADMSG; | |
1942 } | 1961 } |
1943 break; | 1962 break; |
1944 | 1963 |
1945 default: | 1964 default: |
1946 /* What is this position ??? */ | 1965 /* What is this position ??? */ |
1947 ASSERT(0); | 1966 ASSERT(0); |
1948 ret = ENOTSUP; | 1967 return ENOTSUP; |
1949 } | 1968 } |
1950 | 1969 |
1951 /* We've checked all the parameters */ | 1970 /* We've checked all the parameters */ |
1952 end: | 1971 return 0; |
1953 if (ret == EBADMSG) { | |
1954 pr_data->ruleavp = rule->rule_avp; | |
1955 } | |
1956 | |
1957 return ret; | |
1958 } | 1972 } |
1959 | 1973 |
1960 /* Check the rules recursively */ | 1974 /* Check the rules recursively */ |
1961 static int parserules_do ( struct dictionary * dict, msg_or_avp * object, struct dict_object ** conflict_rule, int mandatory) | 1975 static int parserules_do ( struct dictionary * dict, msg_or_avp * object, struct fd_pei *error_info, int mandatory) |
1962 { | 1976 { |
1963 int ret = 0; | |
1964 struct parserules_data data; | 1977 struct parserules_data data; |
1965 struct dict_object * model = NULL; | 1978 struct dict_object * model = NULL; |
1966 | 1979 |
1967 TRACE_ENTRY("%p %p %p %d", dict, object, conflict_rule, mandatory); | 1980 TRACE_ENTRY("%p %p %p %d", dict, object, error_info, mandatory); |
1968 | 1981 |
1969 /* object has already been checked and dict-parsed when we are called. */ | 1982 /* object has already been checked and dict-parsed when we are called. */ |
1970 | 1983 |
1971 /* First, handle the cases where there is no model */ | 1984 /* First, handle the cases where there is no model */ |
1972 { | 1985 { |
1978 model = _M(object)->msg_model; | 1991 model = _M(object)->msg_model; |
1979 } | 1992 } |
1980 /* Commands MUST be supported in the dictionary */ | 1993 /* Commands MUST be supported in the dictionary */ |
1981 if (model == NULL) { | 1994 if (model == NULL) { |
1982 TRACE_DEBUG(INFO, "Message with no dictionary model. EBADMSG"); | 1995 TRACE_DEBUG(INFO, "Message with no dictionary model. EBADMSG"); |
1996 if (error_info) { | |
1997 error_info->pei_errcode = "DIAMETER_COMMAND_UNSUPPORTED"; | |
1998 error_info->pei_protoerr = 1; | |
1999 } | |
1983 return EBADMSG; | 2000 return EBADMSG; |
1984 } | 2001 } |
1985 } | 2002 } |
1986 | 2003 |
1987 /* AVP with the 'M' flag must also be recognized in the dictionary -- except inside an optional grouped AVP */ | 2004 /* AVP with the 'M' flag must also be recognized in the dictionary -- except inside an optional grouped AVP */ |
1988 if (CHECK_AVP(object) && ((model = _A(object)->avp_model) == NULL)) { | 2005 if (CHECK_AVP(object) && ((model = _A(object)->avp_model) == NULL)) { |
1989 if ( mandatory && (_A(object)->avp_public.avp_flags & AVP_FLAG_MANDATORY)) { | 2006 if ( mandatory && (_A(object)->avp_public.avp_flags & AVP_FLAG_MANDATORY)) { |
1990 /* Return an error in this case */ | 2007 /* Return an error in this case */ |
1991 TRACE_DEBUG(INFO, "Mandatory AVP with no dictionary model. EBADMSG"); | 2008 TRACE_DEBUG(INFO, "Mandatory AVP with no dictionary model. EBADMSG"); |
2009 if (error_info) { | |
2010 error_info->pei_errcode = "DIAMETER_AVP_UNSUPPORTED"; | |
2011 error_info->pei_avp = object; | |
2012 } | |
1992 return EBADMSG; | 2013 return EBADMSG; |
1993 } else { | 2014 } else { |
1994 /* We don't know any rule for this object, so assume OK */ | 2015 /* We don't know any rule for this object, so assume OK */ |
1995 TRACE_DEBUG(FULL, "Unknown informational AVP, ignoring..."); | 2016 TRACE_DEBUG(FULL, "Unknown informational AVP, ignoring..."); |
1996 return 0; | 2017 return 0; |
2016 struct fd_list * ch = NULL; | 2037 struct fd_list * ch = NULL; |
2017 if ( CHECK_MSG(object) | 2038 if ( CHECK_MSG(object) |
2018 || (mandatory && (_A(object)->avp_public.avp_flags & AVP_FLAG_MANDATORY)) ) | 2039 || (mandatory && (_A(object)->avp_public.avp_flags & AVP_FLAG_MANDATORY)) ) |
2019 is_child_mand = 1; | 2040 is_child_mand = 1; |
2020 for (ch = _C(object)->children.next; ch != &_C(object)->children; ch = ch->next) { | 2041 for (ch = _C(object)->children.next; ch != &_C(object)->children; ch = ch->next) { |
2021 CHECK_FCT( parserules_do ( dict, _C(ch->o), conflict_rule, is_child_mand ) ); | 2042 CHECK_FCT( parserules_do ( dict, _C(ch->o), error_info, is_child_mand ) ); |
2022 } | 2043 } |
2023 } | 2044 } |
2024 | 2045 |
2025 /* Now check all rules of this object */ | 2046 /* Now check all rules of this object */ |
2026 data.sentinel = &_C(object)->children; | 2047 data.sentinel = &_C(object)->children; |
2027 data.ruleavp = NULL; | 2048 data.pei = error_info; |
2028 ret = fd_dict_iterate_rules ( model, &data, parserules_check_one_rule ); | 2049 CHECK_FCT( fd_dict_iterate_rules ( model, &data, parserules_check_one_rule ) ); |
2029 | 2050 |
2030 /* Save the reference to the eventual conflicting rule; otherwise set to NULL */ | 2051 return 0; |
2031 if (conflict_rule && data.ruleavp) { | 2052 } |
2032 /* data.ruleavp contains the AVP, and model is the parent */ | 2053 |
2033 struct dict_object * rule = NULL; | 2054 int fd_msg_parse_rules ( msg_or_avp * object, struct dictionary * dict, struct fd_pei *error_info) |
2034 struct dict_rule_request req = { model, data.ruleavp }; | 2055 { |
2035 | 2056 TRACE_ENTRY("%p %p %p", object, dict, error_info); |
2036 CHECK_FCT_DO( fd_dict_search ( dict, DICT_RULE, RULE_BY_AVP_AND_PARENT, &req, &rule, ENOENT), rule = NULL ); | |
2037 | |
2038 *conflict_rule = rule; | |
2039 } | |
2040 | |
2041 return ret; | |
2042 } | |
2043 | |
2044 int fd_msg_parse_rules ( msg_or_avp * object, struct dictionary * dict, struct dict_object ** rule) | |
2045 { | |
2046 TRACE_ENTRY("%p %p", object, rule); | |
2047 | 2057 |
2048 /* Resolve the dictionary objects when missing. This also validates the object. */ | 2058 /* Resolve the dictionary objects when missing. This also validates the object. */ |
2049 CHECK_FCT( fd_msg_parse_dict ( object, dict ) ); | 2059 CHECK_FCT( fd_msg_parse_dict ( object, dict ) ); |
2050 | 2060 |
2061 if (error_info) | |
2062 memset(error_info, 0, sizeof(struct fd_pei)); | |
2063 | |
2051 /* Call the recursive function */ | 2064 /* Call the recursive function */ |
2052 return parserules_do ( dict, object, rule, 1 ) ; | 2065 return parserules_do ( dict, object, error_info, 1 ) ; |
2053 } | 2066 } |
2054 | 2067 |
2055 /***************************************************************************************************************/ | 2068 /***************************************************************************************************************/ |
2056 | 2069 |
2057 /* Compute the lengh of an object and its subtree. */ | 2070 /* Compute the lengh of an object and its subtree. */ |