RegistrationTable.cpp
Go to the documentation of this file.
1 /*----------------------------------------------------------------------------*/
2 /* */
3 /* Copyright (c) 1995, 2004 IBM Corporation. All rights reserved. */
4 /* Copyright (c) 2005-2009 Rexx Language Association. All rights reserved. */
5 /* */
6 /* This program and the accompanying materials are made available under */
7 /* the terms of the Common Public License v1.0 which accompanies this */
8 /* distribution. A copy is also available at the following address: */
9 /* http://www.ibm.com/developerworks/oss/CPLv1.0.htm */
10 /* */
11 /* Redistribution and use in source and binary forms, with or */
12 /* without modification, are permitted provided that the following */
13 /* conditions are met: */
14 /* */
15 /* Redistributions of source code must retain the above copyright */
16 /* notice, this list of conditions and the following disclaimer. */
17 /* Redistributions in binary form must reproduce the above copyright */
18 /* notice, this list of conditions and the following disclaimer in */
19 /* the documentation and/or other materials provided with the distribution. */
20 /* */
21 /* Neither the name of Rexx Language Association nor the names */
22 /* of its contributors may be used to endorse or promote products */
23 /* derived from this software without specific prior written permission. */
24 /* */
25 /* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */
26 /* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */
27 /* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS */
28 /* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT */
29 /* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */
30 /* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED */
31 /* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, */
32 /* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY */
33 /* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING */
34 /* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS */
35 /* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
36 /* */
37 /*----------------------------------------------------------------------------*/
38 
39 #include "RegistrationTable.hpp"
40 
41 
42 /**
43  * Create registration data for a library registration item.
44  *
45  * @param n The callback name.
46  * @param m The callback library.
47  * @param regData The additional registration data sent with the message.
48  */
49 RegistrationData::RegistrationData(const char *n, const char *m, SessionID s, ServiceRegistrationData *regData)
50 {
51  next = NULL;
52  name = dupString(n);
53  moduleName = dupString(m);
55  owner = s;
56  dropAuthority = regData->dropAuthority;
57  userData[0] = regData->userData[0];
58  userData[1] = regData->userData[1];
59  entryPoint = 0;
60  references = NULL;
61 }
62 
63 /**
64  * Register an inprocess item.
65  *
66  * @param n The name of the callback.
67  * @param s The session id.
68  * @param regData The service registration data.
69  */
71 {
72  next = NULL;
73  name = dupString(n);
74  moduleName = NULL;
75  procedureName = NULL;
76  owner = s;
77  dropAuthority = regData->dropAuthority;
78  userData[0] = regData->userData[0];
79  userData[1] = regData->userData[1];
80  entryPoint = regData->entryPoint;
81  references = NULL;
82 }
83 
84 /**
85  * Destructor for a registration data item.
86  */
88 {
89  delete [] name;
90  delete [] moduleName;
91  delete [] procedureName;
92 
93  SessionCookie *cookie = references;
94  while (cookie != NULL)
95  {
96  SessionCookie *localnext = cookie->next;
97  delete cookie;
98  cookie = localnext;
99  }
100 }
101 
102 
103 /**
104  * Copy the registration information into a message
105  * data item to be returned to the client.
106  *
107  * @param regData The returned registration data.
108  */
110 {
111  if (moduleName != NULL)
112  {
113  strcpy(regData.moduleName, moduleName);
114  }
115  else
116  {
117  strcpy(regData.moduleName, "");
118  }
119 
120  if (procedureName != NULL)
121  {
122  strcpy(regData.procedureName, procedureName);
123  }
124  else
125  {
126  strcpy(regData.procedureName, "");
127  }
128  regData.userData[0] = userData[0];
129  regData.userData[1] = userData[1];
130  regData.entryPoint = entryPoint;
131  regData.dropAuthority = dropAuthority;
132 }
133 
134 /**
135  * Add an additional reference to a session.
136  *
137  * @param s The session id to add.
138  */
140 {
141  SessionCookie *cookie = findSessionReference(s);
142  // already there? just add a reference.
143  if (cookie != NULL)
144  {
145  cookie->addReference();
146  }
147  else
148  {
149  cookie = new SessionCookie(s);
150  cookie->next = references;
151  references = cookie;
152  }
153 }
154 
155 /**
156  * Decrement a session reference count.
157  *
158  * @param s The session identifier.
159  */
161 {
162  SessionCookie *cookie = findSessionReference(s);
163  // already there? just add a reference.
164  if (cookie != NULL)
165  {
166  if (cookie->removeReference() == 0)
167  {
168  removeSessionReference(cookie);
169  }
170  }
171 }
172 
173 /**
174  * Locate a session reference cound.
175  *
176  * @param s The target session identifier.
177  *
178  * @return The session cookie associated with the session, or NULL
179  * if the session has not been tracked yet.
180  */
182 {
183  SessionCookie *cookie = references;
184  while (cookie != NULL)
185  {
186  if (cookie->session == s)
187  {
188  return cookie;
189  }
190  cookie = cookie->next;
191  }
192  return NULL;
193 }
194 
195 /**
196  * Remove a session reference cookie from the chain.
197  *
198  * @param s The cookit to remove.
199  */
201 {
202  if (s == references)
203  {
204  references = s->next;
205  }
206  else
207  {
208  SessionCookie * current = references;
209  while (current != NULL)
210  {
211  if (current->next == s)
212  {
213  current->next = s->next;
214  break;
215  }
216  current = current->next;
217  }
218  }
219  delete s;
220 }
221 
222 
223 
224 // Add a library registration item to the table.
225 // Message arguments have the following meanings:
226 //
227 // parameter1 -- registration type
228 // nameArg -- name of the registered object
230 {
232  // get the argument names
233  const char *name = message.nameArg;
234  const char *module = regData->moduleName;
235 
236  RegistrationData *callback = locate(name, module);
237  // update the reference counts to make sure drops don't
238  // clear things out for other processes.
239  if (callback != NULL)
240  {
241  callback->addSessionReference(message.session);
243  }
244  else
245  {
246  callback = new RegistrationData(name, module, message.session, regData);
247 
248  // add to the chain
249  callback->next = firstLibrary;
250  firstLibrary = callback;
251 
252  if (locate(name, message.session) != NULL)
253  {
255  }
256  else
257  {
259  }
260  }
261 
262  // make sure the data message buffer is not passed back.
263  message.freeMessageData();
264 }
265 
266 
267 // Add an exe registration item to the table.
268 // Message arguments have the following meanings:
269 //
270 // parameter1 -- registration type
271 // parameter2 -- drop authority flag
272 // nameArg -- The registration name
274 {
276  // get the argument name
277  const char *name = message.nameArg;
278 
279  // now locate an exe registration.
280  RegistrationData *callback = locate(name, message.session);
281  // update the reference counts to make sure drops don't
282  // clear things out for other processes.
283  if (callback != NULL)
284  {
286  }
287  else
288  {
289  callback = new RegistrationData(name, message.session, regData);
290 
291  // add to the chain
292  callback->next = firstEntryPoint;
293  firstEntryPoint = callback;
294 
295  // see if this is duplicated in library form
296  if (locate(firstLibrary, name) != NULL)
297  {
299  }
300  else
301  {
303  }
304  }
305  // make sure the data message buffer is not passed back.
306  message.freeMessageData();
307 }
308 
309 // General query by name only. Can return either form of registraction.
310 // Message arguments have the following meanings:
311 //
312 // parameter1 -- registration type
313 // nameArg -- The registration name
315 {
316  // get the argument name (local copy only)
317  const char *name = message.nameArg;
318 
319  // now check the exe version first.
320  RegistrationData *callback = locate(name, message.session);
321  // not found? try a library version
322  if (callback == NULL || callback->owner != message.session)
323  {
324  callback = locate(firstLibrary, name);
325  }
326  // copy the data into the buffer if we found one
327  if (callback != NULL)
328  {
330  // copy the registration information
331  callback->getRegistrationData(*regData);
332  message.setResult(CALLBACK_EXISTS);
333  }
334  else
335  {
336  message.setResult(CALLBACK_NOT_FOUND);
337  }
338 }
339 
340 
341 // General query by name and qualified module name. Can return only the EXE version
342 // Message arguments have the following meanings:
343 //
344 // parameter1 -- registration type
345 // nameArg -- The registration name
347 {
348  // we're sent an extra registration block here with input data. We can just
349  // reuse this buffer to send the information back.
351  // get the argument name (local copy only)
352  const char *name = message.nameArg;
353  const char *module = regData->moduleName;
354 
355  // if not requesting by module name, handle like a normal request
356  if (strlen(module) == 0)
357  {
358  queryCallback(message);
359  return;
360  }
361 
362  // now check a library version first.
363  RegistrationData *callback = locate(name, module);
364  // copy the data if we found this
365  if (callback != NULL)
366  {
367  // copy the registration information
368  callback->getRegistrationData(*regData);
369  message.setResult(CALLBACK_EXISTS);
370  }
371  else
372  {
373  message.setResult(CALLBACK_NOT_FOUND);
374  // make sure the data message buffer is not passed back.
375  message.freeMessageData();
376  }
377 }
378 
379 
380 // Update a library-based callback after a successful load event.
381 // Message arguments have the following meanings:
382 //
383 // parameter1 -- registration type
384 // nameArg -- The registration name
386 {
388  // get the argument name (local copy only)
389  const char *name = message.nameArg;
390  const char *module = regData->moduleName;
391 
392  // now check a library version first.
393  RegistrationData *callback = locate(name, module);
394  // copy the data if we found this
395  if (callback != NULL)
396  {
397  // we're only updating the entry point data
398  callback->entryPoint = regData->entryPoint;
399  message.setResult(CALLBACK_EXISTS);
400  }
401  else
402  {
403  message.setResult(CALLBACK_NOT_FOUND);
404  }
405  // make sure the data message buffer is not passed back.
406  message.freeMessageData();
407 }
408 
409 
410 // Drop a callback by name only.
411 // Message arguments have the following meanings:
412 //
413 // parameter1 -- registration type
414 // nameArg -- The registration name
416 {
417  // get the argument name (local copy only)
418  const char *name = message.nameArg;
419  RegistrationData **anchor = &firstEntryPoint;
420 
421  // now check the exe version first.
422  RegistrationData *callback = locate(name, message.session);
423  // not found? try a library version
424  if (callback == NULL)
425  {
426  callback = locate(firstLibrary, name);
427  anchor = &firstLibrary;
428  }
429  if (callback != NULL)
430  {
431  // an attempt to drop by somebody other than the owner?
432  if (callback->dropAuthority == OWNER_ONLY && callback->owner != message.session)
433  {
435  }
436  else
437  {
438 
439  // remove this session reference.
440  callback->removeSessionReference(message.session);
441  // still referenced by other processes?
442  if (callback->hasReferences())
443  {
445  }
446  else
447  {
448  remove(anchor, callback);
449  delete callback;
450  message.setResult(CALLBACK_DROPPED);
451  }
452  }
453  }
454  else
455  {
456  message.setResult(CALLBACK_NOT_FOUND);
457  }
458  // make sure the data message buffer is not passed back.
459  message.freeMessageData();
460 }
461 
462 
463 // Drop a callback by qualified name. Can only drop a library registration.
464 // Message arguments have the following meanings:
465 //
466 // parameter1 -- registration type
467 // nameArg -- The registration name
469 {
470  // we're sent an extra registration block here with input data. We can just
471  // reuse this buffer to send the information back.
473  // get the argument name (local copy only)
474  const char *name = message.nameArg;
475  const char *module = regData->moduleName;
476 
477  // if not requesting by module name, handle like a normal request
478  if (strlen(module) == 0)
479  {
480  queryCallback(message);
481  return;
482  }
483 
484  // now check a library version first.
485  RegistrationData *callback = locate(name, module);
486 
487  // copy the data into the buffer if we found one
488  if (callback != NULL)
489  {
490  // an attempt to drop by somebody other than the owner?
491  if (callback->dropAuthority == OWNER_ONLY && callback->owner != message.session)
492  {
494  }
495  else
496  {
497 
498  // remove this session reference.
499  callback->removeSessionReference(message.session);
500  // still referenced by other processes?
501  if (callback->hasReferences())
502  {
504  }
505  else
506  {
507  if (callback->isEntryPoint())
508  {
509  remove(&firstEntryPoint, callback);
510  }
511  else
512  {
513  remove(&firstLibrary, callback);
514  }
515  delete callback;
516  message.setResult(CALLBACK_DROPPED);
517  }
518  }
519  }
520  else
521  {
522  message.setResult(CALLBACK_NOT_FOUND);
523  }
524  // make sure the data message buffer is not passed back.
525  message.freeMessageData();
526 }
527 
528 /**
529  * search for a name-only registration
530  *
531  * @param anchor The chain anchor.
532  * @param name The target callback name.
533  *
534  * @return The callback descriptor or NULL if the item is not found.
535  */
537 {
538  RegistrationData *current = anchor;
539  RegistrationData *previous = NULL;
540 
541  while (current != NULL) /* while more queues */
542  {
543  // find the one we want?
544  if (current->matches(name))
545  {
546  return current;
547  }
548  previous = current; /* remember this block */
549  current = current->next; /* step to the next block */
550  }
551  return NULL;
552 }
553 
554 /**
555  * search for a name-only registration and remove it from
556  * the chain.
557  *
558  * @param anchor The chain anchor position.
559  * @param block The block to locate.
560  */
562 {
563  RegistrationData *current = *anchor;
564  RegistrationData *previous = NULL;
565 
566  while (current != NULL) /* while more queues */
567  {
568  // find the one we want?
569  if (current == block)
570  {
571  // is this the first one?
572  if (previous == NULL)
573  {
574  // update the anchor position
575  *anchor = current->next;
576  }
577  else
578  {
579  // close the chain and get out of here
580  previous->next = current->next;
581  }
582  return;
583  }
584  previous = current; /* remember this block */
585  current = current->next; /* step to the next block */
586  }
587 }
588 
589 /**
590  * search for a library-type registration, qualified by
591  * name and library.
592  *
593  * @param name The callback name.
594  * @param module The target module.
595  *
596  * @return The descriptor for the item, or NULL if not found.
597  */
598 RegistrationData *RegistrationTable::locate(const char *name, const char *module)
599 {
600  RegistrationData *current = firstLibrary;
601  RegistrationData *previous = NULL;
602 
603  while (current != NULL) /* while more queues */
604  {
605  // find the one we want?
606  if (current->matches(name, module))
607  {
608  // move this to the front so we find it quickly
609  reorderBlocks(firstLibrary, current, previous);
610  return current;
611  }
612  previous = current; /* remember this block */
613  current = current->next; /* step to the next block */
614  }
615  return NULL;
616 }
617 
618 /**
619  * search for a library-type registration
620  *
621  * @param name The target name.
622  *
623  * @return The descriptor for the callback, or NULL if it doesn't
624  * exist.
625  */
627 {
628  RegistrationData *callback = locate(firstLibrary, name);
629  if (callback == NULL)
630  {
631  callback = locate(firstEntryPoint, name);
632  }
633  return callback;
634 }
635 
636 /**
637  * search for a local type registration
638  *
639  * @param name The target registration name.
640  * @param session The session identifier.
641  *
642  * @return The registration data for the item, or NULL if not
643  * found.
644  */
646 {
648  RegistrationData *previous = NULL;
649 
650  while (current != NULL) /* while more queues */
651  {
652  // find the one we want?
653  if (current->matches(name, session))
654  {
655  // move this to the front so we find it quickly
656  reorderBlocks(firstEntryPoint, current, previous);
657  return current;
658  }
659  previous = current; /* remember this block */
660  current = current->next; /* step to the next block */
661  }
662  return NULL;
663 }
664 
665 
666 /**
667  * Reorder the registration blocks so that we put the
668  * most recently referenced registrations at the front
669  * of the queue.
670  *
671  * @param anchor The chain anchor.
672  * @param current The block we're reordering.
673  * @param previous The previous block in the chain (can be NULL if this
674  * item is already at the head of the chain).
675  */
677 {
678  if (previous != NULL) // if we have a predecessor
679  {
680  // rearrange to get "most recently used" behavior
681  previous->next = current->next;
682  current->next = anchor;
683  anchor = current;
684  }
685 }
686 
687 
688 /**
689  * It will remove all the registration entries for a specific process
690  *
691  * @param session The session identifier.
692  */
694 {
696  RegistrationData *previous = NULL;
697 
698  while (current != NULL)
699  {
700  if (current->owner == session)
701  {
702  if (previous == NULL)
703  {
704  firstEntryPoint = current->next;
705  delete current;
706  current = firstEntryPoint;
707  }
708  else
709  {
710  previous->next = current->next;
711  delete current;
712  current = current->next;
713  }
714  }
715  else
716  {
717  previous = current;
718  current = current->next;
719  }
720  }
721 }
722 
char * dupString(const char *oldString)
@ CALLBACK_EXISTS
@ CALLBACK_NOT_FOUND
@ CALLBACK_DROPPED
@ DROP_NOT_AUTHORIZED
@ DUPLICATE_REGISTRATION
@ REGISTRATION_COMPLETED
uintptr_t SessionID
@ OWNER_ONLY
RegistrationData * next
bool matches(const char *n, const char *m)
void getRegistrationData(ServiceRegistrationData &regData)
SessionCookie * findSessionReference(SessionID s)
RegistrationData(const char *n, const char *m, SessionID s, ServiceRegistrationData *regData)
void addSessionReference(SessionID s)
const char * moduleName
void removeSessionReference(SessionID s)
SessionCookie * references
const char * procedureName
RegistrationData * firstEntryPoint
RegistrationData * firstLibrary
void queryLibraryCallback(ServiceMessage &message)
void updateCallback(ServiceMessage &message)
void queryCallback(ServiceMessage &message)
void freeProcessEntries(SessionID session)
RegistrationData * locate(RegistrationData *anchor, const char *name)
void registerLibraryCallback(ServiceMessage &message)
void registerCallback(ServiceMessage &message)
void remove(RegistrationData **anchor, RegistrationData *block)
void dropLibraryCallback(ServiceMessage &message)
void reorderBlocks(RegistrationData *&anchor, RegistrationData *current, RegistrationData *previous)
void dropCallback(ServiceMessage &message)
char nameArg[NAMESIZE]
void * allocateMessageData(size_t length)
void setResult(ServiceReturn code)
void * getMessageData()
char procedureName[MAX_NAME_LENGTH]
char moduleName[MAX_NAME_LENGTH]