1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 2010-2017. All Rights Reserved. 5%% 6%% Licensed under the Apache License, Version 2.0 (the "License"); 7%% you may not use this file except in compliance with the License. 8%% You may obtain a copy of the License at 9%% 10%% http://www.apache.org/licenses/LICENSE-2.0 11%% 12%% Unless required by applicable law or agreed to in writing, software 13%% distributed under the License is distributed on an "AS IS" BASIS, 14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15%% See the License for the specific language governing permissions and 16%% limitations under the License. 17%% 18%% %CopyrightEnd% 19%% 20 21%% 22%% This module turns a dictionary file into the orddict that 23%% diameter_codegen.erl in turn morphs into .erl and .hrl files for 24%% encode and decode of Diameter messages and AVPs. 25%% 26 27-module(diameter_dict_util). 28 29-export([parse/2, 30 format_error/1, 31 format/1]). 32 33-include("diameter_vsn.hrl"). 34 35-define(RETURN(T), throw({T, ?MODULE, ?LINE})). 36-define(RETURN(T, Args), ?RETURN({T, Args})). 37 38-define(A, list_to_atom). 39-define(L, atom_to_list). 40-define(I, integer_to_list). 41-define(F, io_lib:format). 42 43%% =========================================================================== 44%% parse/2 45%% =========================================================================== 46 47-spec parse(File, Opts) 48 -> {ok, orddict:orddict()} 49 | {error, term()} 50 when File :: {path, file:name_all()} 51 | iolist() 52 | binary(), 53 Opts :: list(). 54 55parse(File, Opts) -> 56 putr(verbose, lists:member(verbose, Opts)), 57 try 58 {ok, do_parse(File, Opts)} 59 catch 60 {Reason, ?MODULE, _Line} -> 61 {error, Reason} 62 after 63 eraser(verbose) 64 end. 65 66%% =========================================================================== 67%% format_error/1 68%% =========================================================================== 69 70format_error({read, Reason}) -> 71 file:format_error(Reason); 72format_error({scan, Reason}) -> 73 diameter_dict_scanner:format_error(Reason); 74format_error({parse, {Line, _Mod, Reason}}) -> 75 lists:flatten(["Line ", ?I(Line), ", ", Reason]); 76 77format_error(T) -> 78 {Fmt, As} = fmt(T), 79 lists:flatten(io_lib:format(Fmt, As)). 80 81fmt({avp_code_already_defined = E, [Code, false, Name, Line, L]}) -> 82 {fmt(E), [Code, "", Name, Line, L]}; 83fmt({avp_code_already_defined = E, [Code, Vid, Name, Line, L]}) -> 84 {fmt(E), [Code, ?F("/~p", [Vid]), Name, Line, L]}; 85 86fmt({uint32_out_of_range = E, [id | T]}) -> 87 {fmt(E), ["@id", "application identifier" | T]}; 88fmt({uint32_out_of_range = E, [K | T]}) 89 when K == vendor; 90 K == avp_vendor_id -> 91 {fmt(E), [?F("@~p", [K]), "vendor id" | T]}; 92fmt({uint32_out_of_range = E, [K, Name | T]}) 93 when K == enum; 94 K == define -> 95 {fmt(E), [?F("@~p ~s", [K, Name]), "value" | T]}; 96fmt({uint32_out_of_range = E, [avp_types, Name | T]}) -> 97 {fmt(E), ["AVP " ++ Name, "AVP code" | T]}; 98fmt({uint32_out_of_range = E, [grouped, Name | T]}) -> 99 {fmt(E), ["Grouped AVP " ++ Name | T]}; 100fmt({uint32_out_of_range = E, [messages, Name | T]}) -> 101 {fmt(E), ["Message " ++ Name, "command code" | T]}; 102 103fmt({Reason, As}) -> 104 {fmt(Reason), As}; 105 106fmt(avp_code_already_defined) -> 107 "AVP ~p~s (~s) at line ~p already defined at line ~p"; 108 109fmt(uint32_out_of_range) -> 110 "~s specifies ~s ~p at line ~p that is out of range for a value of " 111 "Diameter type Unsigned32"; 112 113fmt(imported_avp_already_defined) -> 114 "AVP ~s imported by @inherits ~p at line ~p defined at line ~p"; 115fmt(duplicate_import) -> 116 "AVP ~s is imported by more than one @inherits, both at line ~p " 117 "and at line ~p"; 118 119fmt(duplicate_section) -> 120 "Section @~s at line ~p already declared at line ~p"; 121 122fmt(already_declared) -> 123 "Section @~p ~s at line ~p already declared at line ~p"; 124 125fmt(inherited_avp_already_defined) -> 126 "AVP ~s inherited at line ~p defined in @avp_types at line ~p"; 127fmt(avp_already_defined) -> 128 "AVP ~s at line ~p already in @~p at line ~p"; 129fmt(key_already_defined) -> 130 "Value for ~s:~s in @~p at line ~p already provided at line ~p"; 131 132fmt(messages_without_id) -> 133 "@messages at line ~p but @id not declared"; 134 135fmt(avp_name_already_defined) -> 136 "AVP ~s at line ~p already defined at line ~p"; 137fmt(avp_has_unknown_type) -> 138 "AVP ~s at line ~p defined with unknown type ~s"; 139fmt(avp_has_invalid_flag) -> 140 "AVP ~s at line ~p specifies invalid flag ~c"; 141fmt(avp_has_duplicate_flag) -> 142 "AVP ~s at line ~p specifies duplicate flag ~c"; 143fmt(avp_has_vendor_id) -> 144 "AVP ~s at line ~p does not specify V flag " 145 "but is assigned vendor id ~p at line ~p"; 146fmt(avp_has_no_vendor) -> 147 "AVP ~s at line ~p specifies V flag " 148 "but neither @vendor_avp_id nor @vendor supplies a value"; 149 150fmt(group_already_defined) -> 151 "Group ~s at line ~p already defined at line ~p"; 152fmt(grouped_avp_code_mismatch) -> 153 "AVP ~s at line ~p has with code ~p " 154 "but @avp_types specifies ~p at line ~p"; 155fmt(grouped_avp_has_wrong_type) -> 156 "Grouped AVP ~s at line ~p defined with type ~s at line ~p"; 157fmt(grouped_avp_not_defined) -> 158 "Grouped AVP ~s on line ~p not defined in @avp_types"; 159fmt(grouped_avp_not_grouped) -> 160 "Grouped AVP ~s on line ~p not defined in @grouped"; 161fmt(grouped_vendor_id_without_flag) -> 162 "Grouped AVP ~s at line ~p has vendor id " 163 "but definition at line ~p does not specify V flag"; 164fmt(grouped_vendor_id_mismatch) -> 165 "Grouped AVP ~s at line ~p has vendor id ~p " 166 "but ~p specified at line ~p"; 167 168fmt(message_name_already_defined) -> 169 "Message ~s at line ~p already defined at line ~p"; 170fmt(message_code_already_defined) -> 171 "~s message with code ~p at line ~p already defined at line ~p"; 172fmt(message_has_duplicate_flag) -> 173 "Message ~s has duplicate flag ~s at line ~p"; 174fmt(message_application_id_mismatch) -> 175 "Message ~s has application id ~p at line ~p " 176 "but @id specifies ~p at line ~p"; 177 178fmt(invalid_avp_order) -> 179 "AVP reference ~c~s~c at line ~p breaks fixed/required/optional order"; 180fmt(required_avp_has_zero_max_arity) -> 181 "Required AVP has maximum arity 0 at line ~p"; 182fmt(required_avp_has_zero_min_arity) -> 183 "Required AVP has minimum arity 0 at line ~p"; 184fmt(optional_avp_has_nonzero_min_arity) -> 185 "Optional AVP has non-zero minimum arity at line ~p"; 186fmt(qualifier_has_min_greater_than_max) -> 187 "Qualifier ~p*~p at line ~p has Min > Max"; 188fmt(avp_already_referenced) -> 189 "AVP ~s at line ~p already referenced at line ~p"; 190 191fmt(message_missing) -> 192 "~s message at line ~p but no ~s message is defined"; 193 194fmt(requested_avp_not_found) -> 195 "@inherit ~s at line ~p requests AVP ~s at line ~p " 196 "but module does not define that AVP"; 197 198fmt(enumerated_avp_has_wrong_local_type) -> 199 "Enumerated AVP ~s in @enum at line ~p defined with type ~s at line ~p"; 200fmt(enumerated_avp_has_wrong_inherited_type) -> 201 "Enumerated AVP ~s in @enum at line ~p " 202 "inherited with type ~s from module ~s at line ~p"; 203fmt(enumerated_avp_not_defined) -> 204 "Enumerated AVP ~s in @enum at line ~p neither defined nor inherited"; 205 206fmt(avp_not_defined) -> 207 "AVP ~s referenced at line ~p neither defined nor inherited"; 208 209fmt(recompile) -> 210 "Module ~p appears to have been compiler with an incompatible " 211 "version of the dictionary compiler and must be recompiled"; 212fmt(not_loaded) -> 213 "Module ~p is not on the code path or could not be loaded"; 214fmt(no_dict) -> 215 "Module ~p does not appear to be a diameter dictionary". 216 217%% =========================================================================== 218%% format/1 219%% 220%% Turn dict/0 output back into a dictionary file (with line ending = $\n). 221 222-spec format(Dict) 223 -> iolist() 224 when Dict :: orddict:orddict(). 225 226-define(KEYS, [id, name, prefix, vendor, 227 inherits, codecs, custom_types, 228 avp_types, 229 messages, 230 grouped, 231 enum, define]). 232 233format(Dict) -> 234 Io = orddict:fold(fun io/3, [], Dict), 235 [S || {_,S} <- lists:sort(fun keysort/2, Io)]. 236 237keysort({A,_}, {B,_}) -> 238 [HA, HB] = [H || K <- [A,B], 239 H <- [lists:takewhile(fun(X) -> X /= K end, ?KEYS)]], 240 HA < HB. 241 242%% =========================================================================== 243 244-define(INDENT, " "). 245-define(SP, " "). 246-define(NL, $\n). 247 248%% io/3 249 250io(K, _, Acc) 251 when K == command_codes; 252 K == import_avps; 253 K == import_groups; 254 K == import_enums -> 255 Acc; 256 257io(Key, Body, Acc) -> 258 [{Key, io(Key, Body)} | Acc]. 259 260%% io/2 261 262io(K, Id) 263 when K == id; 264 K == name; 265 K == prefix -> 266 [?NL, section(K), ?SP, tok(Id)]; 267 268io(vendor = K, {Id, Name}) -> 269 [?NL, section(K) | [[?SP, tok(X)] || X <- [Id, Name]]]; 270 271io(_, []) -> 272 []; 273 274io(avp_types = K, Body) -> 275 [?NL, ?NL, section(K), ?NL, [body(K,A) || A <- Body]]; 276 277io(K, Body) 278 when K == messages; 279 K == grouped -> 280 [?NL, ?NL, section(K), [body(K,A) || A <- Body]]; 281 282io(K, Body) 283 when K == avp_vendor_id; 284 K == inherits; 285 K == custom_types; 286 K == codecs; 287 K == enum; 288 K == define -> 289 [[?NL, pairs(K, T)] || T <- Body]. 290 291pairs(K, {Id, Avps}) -> 292 [?NL, section(K), ?SP, tok(Id), ?NL, [[?NL, body(K, A)] || A <- Avps]]. 293 294body(K, AvpName) 295 when K == avp_vendor_id; 296 K == inherits; 297 K == custom_types; 298 K == codecs -> 299 [?INDENT, word(AvpName)]; 300 301body(K, {Name, N}) 302 when K == enum; 303 K == define -> 304 [?INDENT, word(Name), ?SP, ?I(N)]; 305 306body(avp_types = K, {Name, Code, Type, ""}) -> 307 body(K, {Name, Code, Type, "-"}); 308body(avp_types, {Name, Code, Type, Flags}) -> 309 [?NL, ?INDENT, word(Name), 310 [[?SP, ?SP, S] || S <- [?I(Code), Type, Flags]]]; 311 312body(messages, {"answer-message", _, _, [], Avps}) -> 313 [?NL, ?NL, ?INDENT, 314 "answer-message ::= < Diameter Header: code, ERR [PXY] >", 315 f_avps(Avps)]; 316body(messages, {Name, Code, Flags, ApplId, Avps}) -> 317 [?NL, ?NL, ?INDENT, word(Name), " ::= ", header(Code, Flags, ApplId), 318 f_avps(Avps)]; 319 320body(grouped, {Name, Code, Vid, Avps}) -> 321 [?NL, ?NL, ?INDENT, word(Name), " ::= ", avp_header(Code, Vid), 322 f_avps(Avps)]. 323 324header(Code, Flags, ApplId) -> 325 ["< Diameter Header: ", 326 ?I(Code), 327 [[", ", ?L(F)] || F <- Flags], 328 [[" ", ?I(N)] || N <- ApplId], 329 " >"]. 330 331avp_header(Code, Vid) -> 332 ["< AVP Header: ", 333 ?I(Code), 334 [[" ", ?I(V)] || V <- Vid], 335 " >"]. 336 337f_avps(L) -> 338 [[?NL, ?INDENT, ?INDENT, f_avp(A)] || A <- L]. 339 340f_avp({Q, A}) -> 341 [D | _] = Avp = f_delim(A), 342 f_avp(f_qual(D, Q), Avp); 343f_avp(A) -> 344 f_avp("", f_delim(A)). 345 346f_delim({{A}}) -> 347 [$<, word(A), $>]; 348f_delim({A}) -> 349 [${, word(A), $}]; 350f_delim([A]) -> 351 [$[, word(A), $]]. 352 353f_avp(Q, [L, Avp, R]) -> 354 Len = length(lists:flatten([Q])), 355 [io_lib:format("~*s", [-1*max(Len+1, 6) , Q]), L, " ", Avp, " ", R]. 356 357f_qual(${, '*') -> 358 "1*"; %% Equivalent to "*" but the more common/obvious rendition 359f_qual(_, '*') -> 360 "*"; 361f_qual(_, {'*', N}) -> 362 [$*, ?I(N)]; 363f_qual(_, {N, '*'}) -> 364 [?I(N), $*]; 365f_qual(_, {M,N}) -> 366 [?I(M), $*, ?I(N)]. 367 368section(Key) -> 369 ["@", ?L(Key)]. 370 371tok(N) 372 when is_integer(N) -> 373 ?I(N); 374tok(N) -> 375 word(N). 376 377word(Str) -> 378 word(diameter_dict_scanner:is_name(Str), Str). 379 380word(true, Str) -> 381 Str; 382word(false, Str) -> 383 [$', Str, $']. 384 385%% =========================================================================== 386 387do_parse(File, Opts) -> 388 Bin = do([fun read/1, File], read), 389 Toks = do([fun diameter_dict_scanner:scan/1, Bin], scan), 390 Tree = do([fun diameter_dict_parser:parse/1, Toks], parse), 391 make_dict(Tree, Opts). 392 393do([F|A], E) -> 394 case apply(F,A) of 395 {ok, T} -> 396 T; 397 {error, Reason} -> 398 ?RETURN({E, Reason}) 399 end. 400 401read({path, Path}) -> 402 file:read_file(Path); 403read(File) -> 404 {ok, iolist_to_binary([File])}. 405 406make_dict(Parse, Opts) -> 407 Dict = pass3(pass2(pass1(reset(make_dict(Parse), Opts))), Opts), 408 ok = examine(Dict), 409 make_orddict(Dict). 410 411%% make_orddict/1 412 413make_orddict(Dict) -> 414 dict:fold(fun mo/3, 415 orddict:from_list([{K,[]} || K <- [avp_types, 416 messages, 417 grouped, 418 inherits, 419 custom_types, 420 codecs, 421 avp_vendor_id, 422 enum, 423 define]]), 424 Dict). 425 426mo(K, Sects, Dict) 427 when is_atom(K) -> 428 orddict:store(K, make(K, Sects), Dict); 429 430mo(_, _, Dict) -> 431 Dict. 432 433make(K, [[_Line, {_, _, X}]]) 434 when K == id; 435 K == name; 436 K == prefix -> 437 X; 438 439make(vendor, [[_Line, {_, _, Id}, {_, _, Name}]]) -> 440 {Id, Name}; 441 442make(K, T) 443 when K == command_codes; 444 K == import_avps; 445 K == import_groups; 446 K == import_enums -> 447 T; 448 449make(K, Sects) -> 450 post(K, foldl(fun([_L|B], A) -> make(K,B,A) end, 451 [], 452 Sects)). 453 454post(avp_types, L) -> 455 lists:sort(L); 456 457post(K, L) 458 when K == grouped; 459 K == messages; 460 K == enum; 461 K == define -> 462 lists:reverse(L); 463 464post(_, L) -> 465 L. 466 467make(K, [{_,_,Name} | Body], Acc) 468 when K == enum; 469 K == define; 470 K == avp_vendor_id; 471 K == custom_types; 472 K == inherits; 473 K == codecs -> 474 [{Name, mk(K, Body)} | Acc]; 475 476make(K, Body, Acc) -> 477 foldl(fun(T,A) -> [mk(K, T) | A] end, Acc, Body). 478 479mk(avp_types, [{_,_,Name}, {_,_,Code}, {_,_,Type}, {_,_,Flags}]) -> 480 {Name, Code, type(Type), Flags}; 481 482mk(messages, [{'answer-message' = A, _}, false | Avps]) -> 483 {?L(A), -1, ['ERR', 'PXY'], [], make_body(Avps)}; 484 485mk(messages, [{_,_,Name}, [{_,_,Code}, Flags, ApplId] | Avps]) -> 486 {Name, 487 Code, 488 lists:map(fun({F,_}) -> F end, Flags), 489 opt(ApplId), 490 make_body(Avps)}; 491 492mk(grouped, [{_,_,Name}, [{_,_,Code}, Vid] | Avps]) -> 493 {Name, Code, opt(Vid), make_body(Avps)}; 494 495mk(K, Body) 496 when K == enum; 497 K == define -> 498 lists:map(fun([{_,_,Name}, {_,_,Value}]) -> {Name, Value} end, Body); 499 500mk(K, Avps) 501 when K == avp_vendor_id; 502 K == custom_types; 503 K == inherits; 504 K == codecs -> 505 lists:map(fun({_,_,N}) -> N end, Avps). 506 507opt(false) -> 508 []; 509opt({_,_,X}) -> 510 [X]. 511 512make_body(Avps) -> 513 lists:map(fun avp/1, Avps). 514 515avp([false, D, Avp]) -> 516 avp(D, Avp); 517avp([Q, D, Avp]) -> 518 case {qual(D, Q), avp(D, Avp)} of 519 {{0,1}, A} when D == $[ -> 520 A; 521 {{1,1}, A} -> 522 A; 523 T -> 524 T 525 end. 526%% Could just store the qualifier as a pair in all cases but the more 527%% compact form is easier to parse visually so live with a bit of 528%% mapping. Ditto the use of '*'. 529 530avp(D, {'AVP', _}) -> 531 delim(D, "AVP"); 532avp(D, {_, _, Name}) -> 533 delim(D, Name). 534 535delim($<, N) -> 536 {{N}}; 537delim(${, N) -> 538 {N}; 539delim($[, N) -> 540 [N]. 541 542%% There's a difference between max = 0 and not specifying an AVP: 543%% reception of an AVP with max = 0 will always be an error, otherwise 544%% it depends on the existence of 'AVP' and the M flag. 545 546qual(${, {{_,L,0}, _}) -> 547 ?RETURN(required_avp_has_zero_min_arity, [L]); 548qual(${, {_, {_,L,0}}) -> 549 ?RETURN(required_avp_has_zero_max_arity, [L]); 550 551qual($[, {{_,L,N}, _}) 552 when 0 < N -> 553 ?RETURN(optional_avp_has_nonzero_min_arity, [L]); 554 555qual(_, {{_,L,Min}, {_,_,Max}}) 556 when Min > Max -> 557 ?RETURN(qualifier_has_min_greater_than_max, [Min, Max, L]); 558 559qual(_, true) -> 560 '*'; 561 562qual(${, {true, {_,_,N}}) -> 563 {1, N}; 564qual(_, {true, {_,_,N}}) -> 565 {0, N}; 566 567qual(D, {{_,_,N}, true}) 568 when D == ${, N == 1; 569 D /= ${, N == 0 -> 570 '*'; 571qual(_, {{_,_,N}, true}) -> 572 {N, '*'}; 573 574qual(_, {{_,_,Min}, {_,_,Max}}) -> 575 {Min, Max}. 576 577%% Optional reports when running verbosely. 578report(What, [F | A]) 579 when is_function(F) -> 580 report(What, apply(F, A)); 581report(What, Data) -> 582 report(getr(verbose), What, Data). 583 584report(true, Tag, Data) -> 585 io:format("##~n## ~p ~p~n", [Tag, Data]); 586report(false, _, _) -> 587 ok. 588 589%% ------------------------------------------------------------------------ 590%% make_dict/1 591%% 592%% Turn a parsed dictionary into an dict. 593 594make_dict(Parse) -> 595 foldl(fun(T,A) -> 596 report(section, T), 597 section(T,A) 598 end, 599 dict:new(), 600 Parse). 601 602section([{T, L} | Rest], Dict) 603 when T == name; 604 T == prefix; 605 T == id; 606 T == vendor -> 607 case find(T, Dict) of 608 [] -> 609 dict:store(T, [[L | Rest]], Dict); 610 [[Line | _]] -> 611 ?RETURN(duplicate_section, [T, L, Line]) 612 end; 613 614section([{T, L} | Rest], Dict) 615 when T == avp_types; 616 T == messages; 617 T == grouped; 618 T == inherits; 619 T == custom_types; 620 T == codecs; 621 T == avp_vendor_id; 622 T == enum; 623 T == define -> 624 dict:append(T, [L | Rest], Dict). 625 626%% =========================================================================== 627%% reset/2 628%% 629%% Reset sections from options. 630 631reset(Dict, Opts) -> 632 foldl([fun reset/3, Opts], Dict, [name, prefix, inherits]). 633 634reset(K, Dict, Opts) -> 635 foldl(fun opt/2, Dict, [T || {A,_} = T <- Opts, A == K]). 636 637opt({inherits = Key, "-"}, Dict) -> 638 dict:erase(Key, Dict); 639 640opt({inherits = Key, Mod}, Dict) -> 641 case lists:splitwith(fun(C) -> C /= $/ end, Mod) of 642 {Mod, ""} -> 643 dict:append(Key, [0, {word, 0, Mod}], Dict); 644 {From, [$/|To]} -> 645 dict:store(Key, 646 [reinherit(From, To, M) || M <- find(Key, Dict)], 647 Dict) 648 end; 649 650opt({Key, Val}, Dict) -> 651 dict:store(Key, [[0, {word, 0, Val}]], Dict); 652 653opt(_, Dict) -> 654 Dict. 655 656reinherit(From, To, [L, {word, _, From} = T | Avps]) -> 657 [L, setelement(3, T, To) | Avps]; 658reinherit(_, _, T) -> 659 T. 660 661%% =========================================================================== 662%% pass1/1 663%% 664%% Explode sections into additional dictionary entries plus semantic 665%% checks. 666 667pass1(Dict) -> 668 true = no_messages_without_id(Dict), 669 670 foldl(fun(K,D) -> foldl([fun p1/3, K], D, find(K,D)) end, 671 Dict, 672 [id, 673 vendor, 674 avp_types, %% must precede inherits, grouped, enum 675 avp_vendor_id, 676 custom_types, 677 codecs, 678 inherits, 679 grouped, 680 messages, 681 enum, 682 define]). 683 684%% Multiple sections are allowed as long as their bodies don't 685%% overlap. (Except enum/define.) 686 687p1([_Line, N], Dict, id = K) -> 688 true = is_uint32(N, [K]), 689 Dict; 690 691p1([_Line, Id, _Name], Dict, vendor = K) -> 692 true = is_uint32(Id, [K]), 693 Dict; 694 695p1([_Line, X | Body], Dict, K) 696 when K == avp_vendor_id; 697 K == custom_types; 698 K == codecs; 699 K == inherits -> 700 foldl([fun explode/4, X, K], Dict, Body); 701 702p1([_Line, X | Body], Dict, K) 703 when K == define; 704 K == enum -> 705 {_, L, Name} = X, 706 foldl([fun explode2/4, X, K], 707 store_new({K, Name}, 708 [L, Body], 709 Dict, 710 [K, Name, L], 711 already_declared), 712 Body); 713 714p1([_Line | Body], Dict, K) 715 when K == avp_types; 716 K == grouped; 717 K == messages -> 718 foldl([fun explode/3, K], Dict, Body). 719 720no_messages_without_id(Dict) -> 721 case find(messages, Dict) of 722 [] -> 723 true; 724 [[Line | _] | _] -> 725 [] /= find(id, Dict) orelse ?RETURN(messages_without_id, [Line]) 726 end. 727 728%% Note that the AVP's in avp_vendor_id, custom_types, codecs and 729%% enum can all be inherited, as can the AVP content of messages and 730%% grouped AVP's. Check that the referenced AVP's exist after 731%% importing definitions. 732 733%% explode/4 734%% 735%% {avp_vendor_id, AvpName} -> [Lineno, Id::integer()] 736%% {custom|inherits, AvpName} -> [Lineno, Mod::string()] 737 738explode({_, Line, AvpName}, Dict, {_, _, X} = T, K) -> 739 true = K /= avp_vendor_id orelse is_uint32(T, [K]), 740 true = K /= inherits orelse avp_not_local(AvpName, Line, Dict), 741 742 store_new({key(K), AvpName}, 743 [Line, X], 744 Dict, 745 [AvpName, Line, K], 746 avp_already_defined). 747 748%% explode2/4 749 750%% {define, {Name, Key}} -> [Lineno, Value::integer(), enum|define] 751 752explode2([{_, Line, Key}, {_, _, Value} = T], Dict, {_, _, Name}, K) -> 753 true = is_uint32(T, [K, Name]), 754 755 store_new({key(K), {Name, Key}}, 756 [Line, Value, K], 757 Dict, 758 [Name, Key, K, Line], 759 key_already_defined). 760 761%% key/1 762%% 763%% Conflate keys that are equivalent as far as uniqueness of 764%% definition goes. 765 766key(K) 767 when K == enum; 768 K == define -> 769 define; 770key(K) 771 when K == custom_types; 772 K == codecs -> 773 custom; 774key(K) -> 775 K. 776 777%% explode/3 778 779%% {avp_types, AvpName} -> [Line | Toks] 780%% {avp_types, {Code, IsReq}} -> [Line, AvpName] 781%% 782%% where AvpName = string() 783%% Code = integer() 784%% IsReq = boolean() 785 786explode([{_, Line, Name} | Toks], Dict0, avp_types = K) -> 787 %% Each AVP can be defined only once. 788 Dict = store_new({K, Name}, 789 [Line | Toks], 790 Dict0, 791 [Name, Line], 792 avp_name_already_defined), 793 794 [{number, _, _Code} = C, {word, _, Type}, {word, _, _Flags}] = Toks, 795 796 true = avp_type_known(Type, Name, Line), 797 true = is_uint32(C, [K, Name]), 798 799 Dict; 800 801%% {grouped, Name} -> [Line, HeaderTok | AvpToks] 802%% {grouped, {Name, AvpName}} -> [Line, Qual, Delim] 803%% 804%% where Name = string() 805%% AvpName = string() 806%% Qual = {Q, Q} | boolean() 807%% Q = true | NumberTok 808%% Delim = $< | ${ | $[ 809 810explode([{_, Line, Name}, Header | Avps], Dict0, grouped = K) -> 811 Dict = store_new({K, Name}, 812 [Line, Header | Avps], 813 Dict0, 814 [Name, Line], 815 group_already_defined), 816 817 [{_,_, Code} = C, Vid] = Header, 818 {DefLine, {_, _, Flags}} = grouped_flags(Name, Code, Dict0, Line), 819 V = lists:member($V, Flags), 820 821 true = is_uint32(C, [K, Name, "AVP code"]), 822 true = is_uint32(Vid, [K, Name, "vendor id"]), 823 false = vendor_id_mismatch(Vid, V, Name, Dict0, Line, DefLine), 824 825 explode_avps(Avps, Dict, K, Name); 826 827%% {messages, Name} -> [Line, HeaderTok | AvpToks] 828%% {messages, {Code, IsReq}} -> [Line, NameTok] 829%% {messages, Code} -> [[Line, NameTok, IsReq]] 830%% {messages, {Name, Flag}} -> [Line] 831%% {messages, {Name, AvpName}} -> [Line, Qual, Delim] 832%% 833%% where Name = string() 834%% Code = integer() 835%% IsReq = boolean() 836%% Flag = 'REQ' | 'PXY' 837%% AvpName = string() 838%% Qual = true | {Q,Q} 839%% Q = true | NumberTok 840%% Delim = $< | ${ | ${ 841 842explode([{'answer-message' = A, Line}, false = H | Avps], 843 Dict0, 844 messages = K) -> 845 Name = ?L(A), 846 Dict1 = store_new({K, Name}, 847 [Line, H, Avps], 848 Dict0, 849 [Name, Line], 850 message_name_already_defined), 851 852 explode_avps(Avps, Dict1, K, Name); 853 854explode([{_, Line, MsgName} = M, Header | Avps], 855 Dict0, 856 messages = K) -> 857 %% There can be at most one message with a given name. 858 Dict1 = store_new({K, MsgName}, 859 [Line, Header | Avps], 860 Dict0, 861 [MsgName, Line], 862 message_name_already_defined), 863 864 [{_, _, Code} = C, Bits, ApplId] = Header, 865 866 %% Don't check any application id since it's required to be 867 %% the same as @id. 868 true = is_uint32(C, [K, MsgName]), 869 870 %% An application id specified as part of the message definition 871 %% has to agree with @id. The former is parsed just because RFC 872 %% 3588 specifies it. 873 false = application_id_mismatch(ApplId, Dict1, MsgName), 874 875 IsReq = lists:keymember('REQ', 1, Bits), 876 877 %% For each command code, there can be at most one request and 878 %% one answer. 879 Dict2 = store_new({K, {Code, IsReq}}, 880 [Line, M], 881 Dict1, 882 [choose(IsReq, "Request", "Answer"), Code, Line], 883 message_code_already_defined), 884 885 %% For each message, each flag can occur at most once. 886 Dict3 = foldl(fun({F,L},D) -> 887 store_new({K, {MsgName, F}}, 888 [L], 889 D, 890 [MsgName, ?L(F)], 891 message_has_duplicate_flag) 892 end, 893 Dict2, 894 Bits), 895 896 dict:append({K, Code}, 897 [Line, M, IsReq], 898 explode_avps(Avps, Dict3, K, MsgName)). 899 900%% explode_avps/4 901%% 902%% Ensure required AVP order and sane qualifiers. Can't check for AVP 903%% names until after they've been imported. 904%% 905%% RFC 3588 allows a trailing fixed while 3588bis doesn't. Parse the 906%% former. 907 908explode_avps(Avps, Dict, Key, Name) -> 909 xa("<{[<", Avps, Dict, Key, Name). 910 911xa(_, [], Dict, _, _) -> 912 Dict; 913 914xa(Ds, [[Qual, D, {'AVP', Line}] | Avps], Dict, Key, Name) -> 915 xa(Ds, [[Qual, D, {word, Line, "AVP"}] | Avps], Dict, Key, Name); 916 917xa([], [[_Qual, D, {_, Line, Name}] | _], _, _, _) -> 918 ?RETURN(invalid_avp_order, [D, Name, close(D), Line]); 919 920xa([D|_] = Ds, [[Qual, D, {_, Line, AvpName}] | Avps], Dict, Key, Name) -> 921 xa(Ds, 922 Avps, 923 store_new({Key, {Name, AvpName}}, 924 [Line, Qual, D], 925 Dict, 926 [AvpName, Line], 927 avp_already_referenced), 928 Key, 929 Name); 930 931xa([_|Ds], Avps, Dict, Key, Name) -> 932 xa(Ds, Avps, Dict, Key, Name). 933 934close($<) -> $>; 935close(${) -> $}; 936close($[) -> $]. 937 938%% is_uint32/2 939 940is_uint32(false, _) -> 941 true; 942is_uint32({Line, _, N}, Args) -> 943 N < 1 bsl 32 orelse ?RETURN(uint32_out_of_range, Args ++ [N, Line]). 944%% Can't call diameter_types here since it may not exist yet. 945 946%% application_id_mismatch/3 947 948application_id_mismatch({number, Line, Id}, Dict, MsgName) -> 949 [[_, {_, L, I}]] = dict:fetch(id, Dict), 950 951 I /= Id andalso ?RETURN(message_application_id_mismatch, 952 [MsgName, Id, Line, I, L]); 953 954application_id_mismatch(false = No, _, _) -> 955 No. 956 957%% avp_not_local/3 958 959avp_not_local(Name, Line, Dict) -> 960 A = find({avp_types, Name}, Dict), 961 962 [] == A orelse ?RETURN(inherited_avp_already_defined, 963 [Name, Line, hd(A)]). 964 965%% avp_type_known/3 966 967avp_type_known(Type, Name, Line) -> 968 false /= type(Type) 969 orelse ?RETURN(avp_has_unknown_type, [Name, Line, Type]). 970 971%% vendor_id_mismatch/6 972%% 973%% Require a vendor id specified on a group to match any specified 974%% in @avp_vendor_id. Note that both locations for the value are 975%% equivalent, both in the value being attributed to a locally 976%% defined AVP and ignored when imported from another dictionary. 977 978vendor_id_mismatch({_,_,_}, false, Name, _, Line, DefLine) -> 979 ?RETURN(grouped_vendor_id_without_flag, [Name, Line, DefLine]); 980 981vendor_id_mismatch({_, _, I}, true, Name, Dict, Line, _) -> 982 case vendor_id(Name, Dict) of 983 {avp_vendor_id, L, N} -> 984 I /= N andalso 985 ?RETURN(grouped_vendor_id_mismatch, [Name, Line, I, N, L]); 986 _ -> 987 false 988 end; 989 990vendor_id_mismatch(_, _, _, _, _, _) -> 991 false. 992 993%% grouped_flags/4 994 995grouped_flags(Name, Code, Dict, Line) -> 996 case find({avp_types, Name}, Dict) of 997 [L, {_, _, Code}, {_, _, "Grouped"}, Flags] -> 998 {L, Flags}; 999 [_, {_, L, C}, {_, _, "Grouped"}, _Flags] -> 1000 ?RETURN(grouped_avp_code_mismatch, [Name, Line, Code, C, L]); 1001 [_, _Code, {_, L, T}, _] -> 1002 ?RETURN(grouped_avp_has_wrong_type, [Name, Line, T, L]); 1003 [] -> 1004 ?RETURN(grouped_avp_not_defined, [Name, Line]) 1005 end. 1006 1007%% vendor_id/2 1008 1009%% Look for a vendor id in @avp_vendor_id, then @vendor. 1010vendor_id(Name, Dict) -> 1011 case find({avp_vendor_id, Name}, Dict) of 1012 [Line, Id] when is_integer(Id) -> 1013 {avp_vendor_id, Line, Id}; 1014 [] -> 1015 vendor(Dict) 1016 end. 1017 1018vendor(Dict) -> 1019 case find(vendor, Dict) of 1020 [[_Line, {_, _, Id}, {_, _, _}]] -> 1021 {vendor, Id}; 1022 [] -> 1023 false 1024 end. 1025 1026%% find/2 1027 1028find(Key, Dict) -> 1029 case dict:find(Key, Dict) of 1030 {ok, L} when is_list(L) -> 1031 L; 1032 error -> 1033 [] 1034 end. 1035 1036%% store_new/5 1037 1038store_new(Key, Value, Dict, Args, Err) -> 1039 case dict:find(Key, Dict) of 1040 {ok, [L | _]} -> 1041 ?RETURN(Err, Args ++ [L]); 1042 error -> 1043 dict:store(Key, Value, Dict) 1044 end. 1045 1046%% type/1 1047 1048type("DiamIdent") -> 1049 "DiameterIdentity"; 1050type("DiamURI") -> 1051 "DiameterURI"; 1052type(T) 1053 when T == "OctetString"; 1054 T == "Integer32"; 1055 T == "Integer64"; 1056 T == "Unsigned32"; 1057 T == "Unsigned64"; 1058 T == "Float32"; 1059 T == "Float64"; 1060 T == "Grouped"; 1061 T == "Enumerated"; 1062 T == "Address"; 1063 T == "Time"; 1064 T == "UTF8String"; 1065 T == "DiameterIdentity"; 1066 T == "DiameterURI"; 1067 T == "IPFilterRule"; 1068 T == "QoSFilterRule" -> 1069 T; 1070type(_) -> 1071 false. 1072 1073%% =========================================================================== 1074%% pass2/1 1075%% 1076%% More explosion, but that requires the previous pass to write its 1077%% entries. 1078 1079pass2(Dict) -> 1080 foldl(fun(K,D) -> foldl([fun p2/3, K], D, find(K,D)) end, 1081 Dict, 1082 [avp_types]). 1083 1084p2([_Line | Body], Dict, avp_types) -> 1085 foldl(fun explode_avps/2, Dict, Body); 1086 1087p2([], Dict, _) -> 1088 Dict. 1089 1090explode_avps([{_, Line, Name} | Toks], Dict) -> 1091 [{number, _, Code}, {word, _, _Type}, {word, _, Flags}] = Toks, 1092 1093 true = avp_flags_valid(Flags, Name, Line), 1094 1095 Vid = avp_vendor_id(Flags, Name, Line, Dict), 1096 1097 %% An AVP is uniquely defined by its AVP code and vendor id (if any). 1098 %% Ensure there are no duplicates. 1099 store_new({avp_types, {Code, Vid}}, 1100 [Line, Name], 1101 Dict, 1102 [Code, Vid, Name, Line], 1103 avp_code_already_defined). 1104 1105%% avp_flags_valid/3 1106 1107avp_flags_valid(Flags, Name, Line) -> 1108 Bad = lists:filter(fun(C) -> not lists:member(C, "MVP") end, Flags), 1109 [] == Bad 1110 orelse ?RETURN(avp_has_invalid_flag, [Name, Line, hd(Bad)]), 1111 1112 Dup = Flags -- "MVP", 1113 [] == Dup 1114 orelse ?RETURN(avp_has_duplicate_flag, [Name, Line, hd(Dup)]). 1115 1116%% avp_vendor_id/4 1117 1118avp_vendor_id(Flags, Name, Line, Dict) -> 1119 V = lists:member($V, Flags), 1120 1121 case vendor_id(Name, Dict) of 1122 {avp_vendor_id, _, I} when V -> 1123 I; 1124 {avp_vendor_id, L, I} -> 1125 ?RETURN(avp_has_vendor_id, [Name, Line, I, L]); 1126 {vendor, I} when V -> 1127 I; 1128 false when V -> 1129 ?RETURN(avp_has_no_vendor, [Name, Line]); 1130 _ -> 1131 false 1132 end. 1133 1134%% =========================================================================== 1135%% pass3/2 1136%% 1137%% Import AVPs. 1138 1139pass3(Dict, Opts) -> 1140 import_enums(import_groups(import_avps(insert_codes(Dict), Opts))). 1141 1142%% insert_codes/1 1143%% 1144%% command_codes -> [{Code, ReqNameTok, AnsNameTok}] 1145 1146insert_codes(Dict) -> 1147 dict:store(command_codes, 1148 dict:fold(fun make_code/3, [], Dict), 1149 Dict). 1150 1151make_code({messages, Code}, Names, Acc) 1152 when is_integer(Code) -> 1153 [mk_code(Code, Names) | Acc]; 1154make_code(_, _, Acc) -> 1155 Acc. 1156 1157mk_code(Code, [[_, _, false] = Ans, [_, _, true] = Req]) -> 1158 mk_code(Code, [Req, Ans]); 1159 1160mk_code(Code, [[_, {_,_,Req}, true], [_, {_,_,Ans}, false]]) -> 1161 {Code, Req, Ans}; 1162 1163mk_code(_Code, [[Line, _Name, IsReq]]) -> 1164 ?RETURN(message_missing, [choose(IsReq, "Request", "Answer"), 1165 Line, 1166 choose(IsReq, "answer", "request")]). 1167 1168%% import_avps/2 1169 1170import_avps(Dict, Opts) -> 1171 Import = inherit(Dict, Opts), 1172 report(imported, Import), 1173 1174 %% examine/1 tests that all referenced AVP's are either defined 1175 %% or imported. 1176 1177 dict:store(import_avps, 1178 lists:map(fun({M, _, As}) -> {M, [A || {_,A} <- As]} end, 1179 lists:reverse(Import)), 1180 foldl(fun explode_imports/2, Dict, Import)). 1181 1182explode_imports({Mod, Line, Avps}, Dict) -> 1183 foldl([fun xi/4, Mod, Line], Dict, Avps). 1184 1185xi({L, {Name, _Code, _Type, _Flags} = A}, Dict, Mod, Line) -> 1186 store_new({avp_types, Name}, 1187 [0, Mod, Line, L, A], 1188 store_new({import, Name}, 1189 [Line], 1190 Dict, 1191 [Name, Line], 1192 duplicate_import), 1193 [Name, Mod, Line], 1194 imported_avp_already_defined). 1195 1196%% import_groups/1 1197%% import_enums/1 1198%% 1199%% For each inherited module, store the content of imported AVP's of 1200%% type grouped/enumerated in a new key. 1201 1202import_groups(Dict) -> 1203 dict:store(import_groups, import(grouped, Dict), Dict). 1204 1205import_enums(Dict) -> 1206 dict:store(import_enums, import(enum, Dict), Dict). 1207 1208import(Key, Dict) -> 1209 flatmap([fun import_key/2, Key], dict:fetch(import_avps, Dict)). 1210 1211import_key({Mod, Avps}, Key) -> 1212 As = lists:flatmap(fun(T) -> 1213 N = element(1,T), 1214 choose(lists:keymember(N, 1, Avps), [T], []) 1215 end, 1216 orddict:fetch(Key, dict(Mod))), 1217 if As == [] -> 1218 []; 1219 true -> 1220 [{Mod, As}] 1221 end. 1222 1223%% ------------------------------------------------------------------------ 1224%% inherit/2 1225%% 1226%% Return a {Mod, Line, [{Lineno, Avp}]} list, where Mod is a module 1227%% name, Line points to the corresponding @inherit and each Avp is 1228%% from Mod:dict(). Lineno is 0 if the import is implicit. 1229 1230inherit(Dict, Opts) -> 1231 code:add_pathsa([D || {include, D} <- Opts]), 1232 foldl(fun inherit_avps/2, [], find(inherits, Dict)). 1233%% Note that the module order of the returned lists is reversed 1234%% relative to @inherits. 1235 1236inherit_avps([Line, {_,_,M} | Names], Acc) -> 1237 Mod = ?A(M), 1238 report(inherit_from, Mod), 1239 case find_avps(Names, avps_from_module(Mod)) of 1240 {_, [{_, L, N} | _]} -> 1241 ?RETURN(requested_avp_not_found, [Mod, Line, N, L]); 1242 {Found, []} -> 1243 [{Mod, Line, lists:sort(Found)} | Acc] 1244 end. 1245 1246%% Import everything not defined locally ... 1247find_avps([], Avps) -> 1248 {[{0, A} || A <- Avps], []}; 1249 1250%% ... or specified AVPs. 1251find_avps(Names, Avps) -> 1252 foldl(fun acc_avp/2, {[], Names}, Avps). 1253 1254acc_avp({Name, _Code, _Type, _Flags} = A, {Found, Not} = Acc) -> 1255 case lists:keyfind(Name, 3, Not) of 1256 {_, Line, Name} -> 1257 {[{Line, A} | Found], lists:keydelete(Name, 3, Not)}; 1258 false -> 1259 Acc 1260 end. 1261 1262%% avps_from_module/2 1263 1264avps_from_module(Mod) -> 1265 orddict:fetch(avp_types, dict(Mod)). 1266 1267dict(Mod) -> 1268 try Mod:dict() of 1269 [?VERSION | Dict] -> 1270 Dict; 1271 _ -> 1272 ?RETURN(recompile, [Mod]) 1273 catch 1274 error: _ -> 1275 ?RETURN(choose(false == code:is_loaded(Mod), 1276 not_loaded, 1277 no_dict), 1278 [Mod]) 1279 end. 1280 1281%% =========================================================================== 1282%% examine/1 1283%% 1284%% Sanity checks. 1285 1286examine(Dict) -> 1287 dict:fold(fun(K, V, _) -> x(K, V, Dict) end, ok, Dict), 1288 ok. 1289 1290%% Ensure enum AVP's have type Enumerated. 1291x({enum, Name}, [Line | _], Dict) 1292 when is_list(Name) -> 1293 true = is_enumerated_avp(Name, Dict, Line); 1294 1295%% Ensure all referenced AVP's are either defined locally or imported. 1296x({K, {Name, AvpName}}, [Line | _], Dict) 1297 when (K == grouped orelse K == messages), 1298 is_list(Name), 1299 is_list(AvpName), 1300 AvpName /= "AVP" -> 1301 true = avp_is_defined(AvpName, Dict, Line); 1302 1303%% Ditto. 1304x({K, AvpName}, [Line | _], Dict) 1305 when K == avp_vendor_id; 1306 K == custom -> 1307 true = avp_is_defined(AvpName, Dict, Line); 1308 1309%% Ensure that all local AVP's of type Grouped are also present in @grouped. 1310x({avp_types, Name}, [Line | Toks], Dict) 1311 when 0 < Line, is_list(Name) -> 1312 [{number, _, _Code}, {word, _, Type}, {word, _, _Flags}] = Toks, 1313 "Grouped" == Type 1314 andalso error == dict:find({grouped, Name}, Dict) 1315 andalso ?RETURN(grouped_avp_not_grouped, [Name, Line]), 1316 ok; 1317 1318x(_, _, _) -> 1319 ok. 1320 1321%% has_enumerated_type/3 1322 1323is_enumerated_avp(Name, Dict, Line) -> 1324 case find({avp_types, Name}, Dict) of 1325 [_Line, _Code, {_, _, "Enumerated"}, _Flags] -> %% local 1326 true; 1327 [_Line, _Code, {_, L, T}, _] -> 1328 ?RETURN(enumerated_avp_has_wrong_local_type, 1329 [Name, Line, T, L]); 1330 [0, _, _, _, {_Name, _Code, "Enumerated", _Flags}] -> %% inherited 1331 true; 1332 [0, Mod, LM, LA, {_Name, _Code, Type, _Flags}] -> 1333 ?RETURN(enumerated_avp_has_wrong_inherited_type, 1334 [Name, Line, Type, Mod, choose(0 == LA, LM, LA)]); 1335 [] -> 1336 ?RETURN(enumerated_avp_not_defined, [Name, Line]) 1337 end. 1338 1339avp_is_defined(Name, Dict, Line) -> 1340 case find({avp_types, Name}, Dict) of 1341 [_Line, _Code, _Type, _Flags] -> %% local 1342 true; 1343 [0, _, _, _, {Name, _Code, _Type, _Flags}] -> %% inherited 1344 true; 1345 [] -> 1346 ?RETURN(avp_not_defined, [Name, Line]) 1347 end. 1348 1349%% =========================================================================== 1350 1351putr(Key, Value) -> 1352 put({?MODULE, Key}, Value). 1353 1354getr(Key) -> 1355 get({?MODULE, Key}). 1356 1357eraser(Key) -> 1358 erase({?MODULE, Key}). 1359 1360choose(true, X, _) -> X; 1361choose(false, _, X) -> X. 1362 1363foldl(F, Acc, List) -> 1364 lists:foldl(fun(T,A) -> eval([F,T,A]) end, Acc, List). 1365 1366flatmap(F, List) -> 1367 lists:flatmap(fun(T) -> eval([F,T]) end, List). 1368 1369eval([[F|X] | A]) -> 1370 eval([F | A ++ X]); 1371eval([F|A]) -> 1372 apply(F,A). 1373