mp_s_pattern.C 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547
  1. /*
  2. * CDE - Common Desktop Environment
  3. *
  4. * Copyright (c) 1993-2012, The Open Group. All rights reserved.
  5. *
  6. * These libraries and programs are free software; you can
  7. * redistribute them and/or modify them under the terms of the GNU
  8. * Lesser General Public License as published by the Free Software
  9. * Foundation; either version 2 of the License, or (at your option)
  10. * any later version.
  11. *
  12. * These libraries and programs are distributed in the hope that
  13. * they will be useful, but WITHOUT ANY WARRANTY; without even the
  14. * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  15. * PURPOSE. See the GNU Lesser General Public License for more
  16. * details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public
  19. * License along with these libraries and programs; if not, write
  20. * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
  21. * Floor, Boston, MA 02110-1301 USA
  22. */
  23. //%% (c) Copyright 1993, 1994 Hewlett-Packard Company
  24. //%% (c) Copyright 1993, 1994 International Business Machines Corp.
  25. //%% (c) Copyright 1993, 1994 Sun Microsystems, Inc.
  26. //%% (c) Copyright 1993, 1994 Novell, Inc.
  27. //%% $XConsortium: mp_s_pattern.C /main/3 1995/10/23 11:57:37 rswiston $
  28. /*
  29. * @(#)mp_s_pattern.C 1.27 93/09/07
  30. *
  31. * mp_s_pattern.cc
  32. *
  33. * Copyright (c) 1990, 1992 by Sun Microsystems, Inc.
  34. */
  35. #include "mp_s_global.h"
  36. #include "mp/mp_arg.h"
  37. #include "mp_s_pat_context.h"
  38. #include "mp/mp_mp.h"
  39. #include "mp_s_mp.h"
  40. #include "mp_s_pattern.h"
  41. #include "mp_s_message.h"
  42. #include "mp_signature.h"
  43. #include "mp_observer.h"
  44. #include "mp_ptype.h"
  45. #include "mp_rpc_implement.h"
  46. #include "mp_s_session.h"
  47. #include "mp/mp_xdr_functions.h"
  48. #include "util/tt_enumname.h"
  49. #include "mp/mp_trace.h"
  50. #include "util/tt_global_env.h"
  51. #include "util/tt_assert.h"
  52. //
  53. // Creates a pattern from a signature object by extracting the relevant
  54. // fields from the signature.
  55. //
  56. _Tt_s_pattern::
  57. _Tt_s_pattern(const _Tt_signature_ptr &sig)
  58. {
  59. _timestamp = 0;
  60. set_id(_tt_s_mp->initial_session->address_string());
  61. set_category(sig->category());
  62. add_scope(sig->scope());
  63. add_op(sig->op());
  64. if (sig->opnum() != -1) {
  65. add_opnum(sig->opnum());
  66. }
  67. if (sig->category()!=TT_OBSERVE) {
  68. add_handler_ptype(sig->ptid());
  69. }
  70. if (sig->otid().len() > 0) {
  71. add_otype(sig->otid());
  72. add_paradigm(TT_OTYPE);
  73. add_paradigm(TT_OBJECT);
  74. } else {
  75. add_paradigm(TT_PROCEDURE);
  76. }
  77. add_reliability(sig->reliability());
  78. add_message_class(sig->message_class());
  79. // We share the arg list from the signature
  80. // by just assigning the pointer and letting the ref-counting
  81. // system do its thing. Conceivably, this might cause
  82. // consternation if we ever let clients update patterns created
  83. // from signatures, since updating the arg list would change
  84. // the in-memory copy of the signature and every other pattern
  85. // generated from the signature! However, the most likely
  86. // way such updates would be generated would be to send a whole
  87. // new pattern over from the client, so sharing the arg list
  88. // wouldn\'t cause trouble.
  89. _args = sig->args();
  90. // We *cannot* share the context list from the signature as
  91. // the signature contains plain _Tt_context entries, while
  92. // the pattern should contain _Tt_pat_context entries.
  93. _Tt_context_list_cursor c(sig->contexts());
  94. while (c.next()) {
  95. _Tt_pat_context_ptr nc = new _Tt_pat_context(**c);
  96. add_context(nc);
  97. }
  98. }
  99. _Tt_s_pattern::_Tt_s_pattern ()
  100. {
  101. _timestamp = 0;
  102. }
  103. _Tt_s_pattern::~_Tt_s_pattern ()
  104. {
  105. }
  106. //
  107. // Matches a pattern with a message and returns a number indicating how
  108. // well the pattern matches the message. 0 indicates no match whereas a
  109. // positive number indicates some level of matching. The greater the
  110. // level, the "better" the pattern matches the message. A level of 1
  111. // indicates all the pattern fields are wildcards so this is the minimum
  112. // level of matching. Any level greater than 1 is controlled by the
  113. // number returned from each field match. Thus twiddling these numbers
  114. // gives some control as to what field matches are to be considered more
  115. // important than others. Presently, the algorithm for selecting match
  116. // numbers is that wildcard matches count as 0 whereas any specific match
  117. // counts as 1. The total is added up for each field and returned as the
  118. // value of the match. The variable tm below holds the total count of
  119. // matches. It is initially 1 because wildcard matches don't increment
  120. // it. In any submethod called to do matching the variable tm is passed
  121. // to the method to be incremented.
  122. //
  123. int _Tt_s_pattern::
  124. match(const _Tt_s_message &msg, const _Tt_msg_trace &trace) const
  125. {
  126. int tm = 1;
  127. if (msg.is_handler_copy()) {
  128. // message is the original
  129. if ( (! _generating_ptype.is_null())
  130. && (category() == TT_OBSERVE))
  131. {
  132. //
  133. // A static observer pattern can only match
  134. // the message copy promised to it,
  135. // and cannot match the original.
  136. //
  137. return 0;
  138. }
  139. } else {
  140. // message is a copy promised to observer ptype
  141. if ( (_generating_ptype.is_null())
  142. || ( msg.observer()->ptid()
  143. != _generating_ptype->ptid()))
  144. {
  145. //
  146. // If this pattern is not owned by the
  147. // promised ptype, or is owned by no
  148. // ptype, then this pattern cannot
  149. // fulfill the promise.
  150. //
  151. return 0;
  152. }
  153. }
  154. trace << "Tt_message & Tt_pattern {\n";
  155. trace.incr_indent();
  156. trace << "timestamp:\t" << _timestamp << "\n";
  157. trace << *this;
  158. trace.decr_indent();
  159. trace << "} ";
  160. // The code for this method is quite repetitive. For each
  161. // field, the list is checked to see if there are any values. If
  162. // there are and the appropiate match method returns 0 then the
  163. // pattern fails to match. The only exception is match_scopes
  164. // which defaults to not matching if there are no values specified.
  165. // This function used to not match the op field of the
  166. // message, because in the usual code path it is
  167. // hashed on the basis of the op field so it would be
  168. // redundant to check the op field here. However, when
  169. // matching TT_HANDLER messages just to get callbacks run,
  170. // this is not the case. To save a little time, we skip
  171. // the op check if the message paradigm is not TT_HANDLER,
  172. // even though that looks really funny here!
  173. if (0 != _ops->count()) {
  174. if (msg.paradigm() == TT_HANDLER &&
  175. ! match_field(msg.op(), _ops,
  176. tm, trace, "op" ))
  177. {
  178. return(0);
  179. }
  180. tm++;
  181. }
  182. if (_reliabilities != 0) {
  183. if (!(_reliabilities&(1<<msg.reliability()))) {
  184. trace << "== 0; /* Tt_disposition */\n";
  185. return(0);
  186. }
  187. tm++;
  188. }
  189. if (_states != 0) {
  190. if (!(_states&(1<<msg.state()))) {
  191. trace << "== 0; /* Tt_state */\n";
  192. return(0);
  193. }
  194. tm++;
  195. }
  196. if (_classes != 0) {
  197. if (!(_classes&(1<<TT_CLASS_UNDEFINED))
  198. && !(_classes&(1<< msg.message_class()))) {
  199. trace << "== 0; /* Tt_class */\n";
  200. return(0);
  201. }
  202. tm++;
  203. }
  204. if (_paradigms != 0) {
  205. if (!(_paradigms&(1<<msg.paradigm()))) {
  206. trace << "== 0; /* Tt_address */\n";
  207. return(0);
  208. }
  209. tm++;
  210. }
  211. if (_handlers->count()) {
  212. _Tt_string h;
  213. if (! msg.handler().is_null()) {
  214. h = msg.handler()->id();
  215. }
  216. if (! match_field(h, _handlers, tm, trace, "handler")) {
  217. return(0);
  218. }
  219. }
  220. if (_handler_ptypes->count() &&
  221. ! match_field(msg.handler_ptype(), _handler_ptypes,
  222. tm, trace, "handler_ptype" ))
  223. {
  224. return(0);
  225. }
  226. if (! match_scopes(msg, tm, trace)) {
  227. return(0);
  228. }
  229. if (msg.scope() == TT_SESSION) {
  230. if (_files->count() &&
  231. ! match_field(msg.file(), _files,
  232. tm, trace, "file"))
  233. {
  234. return(0);
  235. }
  236. }
  237. if (_objects->count() &&
  238. ! match_field(msg.object(), _objects,
  239. tm, trace, "object"))
  240. {
  241. return(0);
  242. }
  243. if (_otypes->count() &&
  244. ! match_field(msg.otype(), _otypes,
  245. tm, trace, "otype"))
  246. {
  247. return(0);
  248. }
  249. if (_senders->count() &&
  250. ! match_field(msg.sender()->id(), _senders,
  251. tm, trace, "sender"))
  252. {
  253. return(0);
  254. }
  255. if (_sender_ptypes->count() &&
  256. ! match_field(msg.sender_ptype(), _sender_ptypes,
  257. tm, trace, "sender_ptype"))
  258. {
  259. return(0);
  260. }
  261. if (_args->count() && ! match_args(msg, tm, trace)) {
  262. return(0);
  263. }
  264. if (! match_contexts(msg, tm, trace)) {
  265. return(0);
  266. }
  267. trace << "== " << tm << ";\n";
  268. return(tm);
  269. }
  270. //
  271. // Generic matching function for lists of integers. If the given pattern
  272. // values, pvals, is empty then 0 is returned indicating a mismatch.
  273. // Otherwise, 1 is returned if "val" is in the list and the variable tm
  274. // is incremented to update the matching score in _Tt_pattern::match.
  275. //
  276. int _Tt_s_pattern::
  277. match_field(int val, const _Tt_int_rec_list_ptr &pvals, int &tm,
  278. const _Tt_msg_trace &trace, const char *failure_note) const
  279. {
  280. _Tt_int_rec_list_cursor c(pvals);
  281. while (c.next()) {
  282. if (val == c->val) {
  283. tm++;
  284. return(1);
  285. }
  286. }
  287. if (failure_note != 0) {
  288. trace << "== 0; /* " << failure_note << " */\n";
  289. }
  290. return(0);
  291. }
  292. //
  293. // Generic matching function for lists of strings. If the given pattern
  294. // values, pvals, is empty then 0 is returned indicating a mismatch.
  295. // Otherwise, 1 is returned if "val" is in the list and the variable tm
  296. // is incremented to update the matching score in _Tt_pattern::match.
  297. //
  298. int _Tt_s_pattern::
  299. match_field(const _Tt_string &val, const _Tt_string_list_ptr &pvals,
  300. int &tm, const _Tt_msg_trace &trace,
  301. const char *failure_note) const
  302. {
  303. _Tt_string_list_cursor c(pvals);
  304. if (val.len() != 0) {
  305. while (c.next()) {
  306. if (val == *c) {
  307. tm++;
  308. return(1);
  309. }
  310. }
  311. }
  312. if (failure_note != 0) {
  313. trace << "== 0; /* " << failure_note << " */\n";
  314. }
  315. return(0);
  316. }
  317. //
  318. // Matches the scope of the message with the pattern scopes. For the
  319. // different scopes, matching is defined differently as specified below.
  320. //
  321. int _Tt_s_pattern::
  322. match_scopes(const _Tt_message &msg, int &tm,
  323. const _Tt_msg_trace &trace) const
  324. {
  325. Tt_scope s = msg.scope();
  326. int valid_scope_mask = 0;
  327. int rval;
  328. ASSERT(TT_SCOPE_NONE==0 && TT_SESSION==1 && TT_FILE==2 &&
  329. TT_BOTH==3 && TT_FILE_IN_SESSION==4,
  330. "Tt_scope enum values changed. This breaks the following "
  331. "code, and also breaks binary compatibility for libtt users. "
  332. "You probably don't want to do that, do you?")
  333. static int valid_scope_masks[] = {
  334. 0, // TT_SCOPE_NONE
  335. (1<<TT_SESSION) | (1<<TT_BOTH), // TT_SESSION
  336. (1<<TT_FILE) | (1<<TT_BOTH), // TT_FILE
  337. (1<<TT_SESSION) | (1<<TT_FILE) | (1<<TT_BOTH), // TT_BOTH
  338. (1<<TT_FILE_IN_SESSION)}; // TT_FILE_IN_SESSION
  339. if (! (_scopes & valid_scope_masks[s])) {
  340. trace << "== 0; /* " << _tt_enumname(s) << " != Tt_scopes */\n";
  341. return 0;
  342. }
  343. // if this is not a file-scoped message and the pattern
  344. // doesn't contain a value for the _sessions list then we
  345. // immediately fail the match.
  346. if (s != TT_FILE &&
  347. (msg.session().is_null() || _sessions->count() == 0)) {
  348. trace << "== 0; /* pattern not joined to "
  349. "tt_message_session() */\n";
  350. return 0;
  351. }
  352. switch (s) {
  353. case TT_FILE:
  354. return match_field(msg.file(), _files,
  355. tm, trace, "file" );
  356. case TT_FILE_IN_SESSION:
  357. if (msg.session()->has_id(_sessions)) {
  358. return((_files->count() == 0)
  359. || match_field(msg.file(), _files,
  360. tm, trace, "file"));
  361. } else {
  362. trace << "== 0; /* file in session */\n";
  363. return(0);
  364. }
  365. case TT_SESSION:
  366. // The session-scope case is so common that we avoid
  367. // matching the session id by setting a flag on a
  368. // pattern that we know is in the session (see
  369. // _Tt_s_procid::add_pattern and
  370. // _Tt_session::mod_session_id_in_patterns to see how
  371. // the flag is set). This flag is turned on if this
  372. // pattern is joined to the current session or not.
  373. if (in_session()) {
  374. return(1);
  375. } else {
  376. trace << "== 0; /* session */\n";
  377. }
  378. return(0);
  379. case TT_BOTH:
  380. rval = (msg.session()->has_id(_sessions) +
  381. match_field(msg.file(), _files, tm, trace, 0));
  382. if (rval == 0) {
  383. trace << "== 0; /* file and session */\n";
  384. }
  385. return(rval);
  386. case TT_SCOPE_NONE:
  387. default:
  388. trace << "== 0; /* Tt_scope */\n";
  389. return(0);
  390. }
  391. }
  392. //
  393. // Returns 1 if the message's args match the pattern args. The
  394. // _Tt_arg::is_match method is used to do the bulk of the work.
  395. //
  396. int _Tt_s_pattern::
  397. match_args(const _Tt_message &msg, int &tm,
  398. const _Tt_msg_trace &trace) const
  399. {
  400. if (msg.args()->count() == 0) {
  401. // arg matching was specified but the
  402. // message doesn't contain any args.
  403. trace << "== 0; /* args */\n";
  404. return(0);
  405. }
  406. _Tt_arg_list_cursor p_args(_args);
  407. _Tt_arg_list_cursor m_args(msg.args());
  408. int cumulative_args_score = 0;
  409. while (p_args.next()) {
  410. if (!m_args.next()) {
  411. trace << "== 0; /* args */\n";
  412. return(0);
  413. }
  414. int used_wildcard;
  415. int score = p_args->match_score(*m_args, used_wildcard);
  416. if (score <= 0) {
  417. trace << "== 0; /* args */\n";
  418. return(0);
  419. }
  420. cumulative_args_score += score;
  421. }
  422. tm += cumulative_args_score;
  423. return(1);
  424. }
  425. //
  426. // Returns 1 if the message's contexts match pattern's contexts.
  427. //
  428. int _Tt_s_pattern::
  429. match_contexts(const _Tt_message &msg, int &tm,
  430. const _Tt_msg_trace &trace) const
  431. {
  432. _Tt_pat_context_list_cursor cntxtC( _contexts );
  433. while (cntxtC.next()) {
  434. if (((_Tt_s_pat_context &)**cntxtC).matchVal( msg ) == 0) {
  435. trace << "== 0; /* contexts */\n";
  436. return 0;
  437. }
  438. }
  439. tm++;
  440. return 1;
  441. }
  442. // Routines to set and get the ptype that this pattern was generated
  443. // from, and to test if it was so generate.
  444. _Tt_ptype_ptr &_Tt_s_pattern::
  445. generating_ptype(_Tt_ptype_ptr &pt)
  446. {
  447. _generating_ptype = pt;
  448. return pt;
  449. }
  450. _Tt_ptype_ptr &_Tt_s_pattern::
  451. generating_ptype()
  452. {
  453. return _generating_ptype;
  454. }
  455. int _Tt_s_pattern::
  456. is_from_ptype()
  457. {
  458. return !_generating_ptype.is_null();
  459. }
  460. Tt_status _Tt_s_pattern::
  461. join_context(const _Tt_msg_context &msgCntxt)
  462. {
  463. _Tt_pat_context_list_cursor contextC( _contexts );
  464. while (contextC.next()) {
  465. if (contextC->slotName() == msgCntxt.slotName()) {
  466. return contextC->addValue( msgCntxt );
  467. }
  468. }
  469. return TT_WRN_NOTFOUND;
  470. }
  471. Tt_status _Tt_s_pattern::
  472. quit_context(const _Tt_msg_context &msgCntxt)
  473. {
  474. _Tt_pat_context_list_cursor contextC( _contexts );
  475. while (contextC.next()) {
  476. if (contextC->slotName() == msgCntxt.slotName()) {
  477. return contextC->deleteValue( msgCntxt );
  478. }
  479. }
  480. return TT_WRN_NOTFOUND;
  481. }