Stackdb
Stackdb is a stackable, multi-target and -level source debugger and memory forensics library.
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
generic_rpc.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013, 2014 The University of Utah
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of
7  * the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
17  */
18 
19 #include <stdsoap2.h>
20 #include <pthread.h>
21 #include <sys/prctl.h>
22 #include <signal.h>
23 #include <glib.h>
24 #include <stdlib.h>
25 #include <sys/time.h>
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <unistd.h>
29 
30 #include "log.h"
31 #include "alist.h"
32 #include "waitpipe.h"
33 #include "generic_rpc.h"
34 #include "util.h"
35 
36 #include "xsdcStub.h"
37 
38 struct svctype_info {
39  /* url -> listener */
40  GHashTable *url_listener_tab;
41  /* listener_id -> listener */
42  GHashTable *id_listener_tab;
43 
44  /* objid -> listener (authoritative) */
45  GHashTable *objid_listener_tab;
46  /* objid -> array_list(listener) */
48 };
49 
50 #define __DEFAULT_GENERIC_RPC_TMPDIR "/var/tmp"
51 
53 
54 static pthread_mutex_t generic_rpc_mutex = PTHREAD_MUTEX_INITIALIZER;
55 static int init_done = 0;
56 
57 static int generic_rpc_listener_count = 1;
58 
59 /* rpc_svctype_t -> struct svctype_info */
60 static GHashTable *svctype_info_tab;
61 
62 /* Prototypes. */
63 void _generic_rpc_unregister_svctype(rpc_svctype_t svctype,int no_hash_delete);
64 static void _generic_rpc_listener_free(struct generic_rpc_listener *l);
65 
69 void generic_rpc_init(void) {
70  char *tmpdir;
71  struct timeval tv;
72 
73  pthread_mutex_lock(&generic_rpc_mutex);
74 
75  if (init_done) {
76  pthread_mutex_unlock(&generic_rpc_mutex);
77  return;
78  }
79 
80  memset(&tv,0,sizeof(tv));
81  if (gettimeofday(&tv,NULL))
82  vwarn("gettimeofday: %s (not doing srand!)\n",strerror(errno));
83  else
84  srand((int)tv.tv_usec);
85 
86  if ((tmpdir = getenv("TMP")))
87  GENERIC_RPC_TMPDIR = strdup(tmpdir);
88  else
90 
91  /*
92  * We have to make sure waitpipe doesn't install a SIGCHLD handler!
93  */
94  waitpipe_init_ext(NULL);
95 
96  svctype_info_tab =
97  g_hash_table_new_full(g_direct_hash,g_direct_equal,NULL,NULL);
98 
99  init_done = 1;
100 
101  pthread_mutex_unlock(&generic_rpc_mutex);
102 }
103 
104 void generic_rpc_fini(void) {
105  GHashTableIter iter;
106  gpointer key;
107 
108  pthread_mutex_lock(&generic_rpc_mutex);
109 
110  if (!init_done) {
111  pthread_mutex_unlock(&generic_rpc_mutex);
112  return;
113  }
114 
115  g_hash_table_iter_init(&iter,svctype_info_tab);
116  while (g_hash_table_iter_next(&iter,&key,NULL)) {
117  /* XXX: this function looks up in the tab; does lookup work in iter? */
118  _generic_rpc_unregister_svctype((int)(uintptr_t)key,1);
119  }
120  g_hash_table_destroy(svctype_info_tab);
121  svctype_info_tab = NULL;
122 
125 
126  init_done = 0;
127 
128  pthread_mutex_unlock(&generic_rpc_mutex);
129 }
130 
132  return (struct svctype_info *) \
133  g_hash_table_lookup(svctype_info_tab,(gpointer)(uintptr_t)svctype);
134 }
135 
140  struct svctype_info *si;
141 
142  pthread_mutex_lock(&generic_rpc_mutex);
143 
144  if (__get_si(svctype)) {
145  pthread_mutex_unlock(&generic_rpc_mutex);
146  return;
147  }
148 
149  si = calloc(1,sizeof(*si));
150  si->url_listener_tab = g_hash_table_new(g_str_hash,g_str_equal);
151  si->id_listener_tab = g_hash_table_new(g_direct_hash,g_direct_equal);
152  /* We delete the listeners manually in a loop. */
153  si->objid_listener_tab =
154  g_hash_table_new_full(g_direct_hash,g_direct_equal,NULL,NULL);
156  g_hash_table_new_full(g_direct_hash,g_direct_equal,NULL,NULL);
157 
158  g_hash_table_insert(svctype_info_tab,(gpointer)(uintptr_t)svctype,si);
159 
160  pthread_mutex_unlock(&generic_rpc_mutex);
161 }
162 
163 void _generic_rpc_unregister_svctype(rpc_svctype_t svctype,int no_hash_delete) {
164  struct array_list *ll;
165  struct generic_rpc_listener *l;
166  GHashTableIter iter;
167  struct svctype_info *si;
168 
169  if (!(si = __get_si(svctype)))
170  return;
171 
172  /*
173  * We need to remove the listeners
174  */
175  ll = array_list_create_from_g_hash_table(si->id_listener_tab);
176  while (g_hash_table_iter_next(&iter,NULL,(gpointer *)&l)) {
177  _generic_rpc_listener_free(l);
178  }
179 
180  g_hash_table_destroy(si->url_listener_tab);
181  g_hash_table_destroy(si->id_listener_tab);
182  g_hash_table_destroy(si->objid_listener_tab);
183 
184  g_hash_table_iter_init(&iter,si->objid_listenerlist_tab);
185  while (g_hash_table_iter_next(&iter,NULL,(gpointer *)&ll)) {
186  array_list_free(ll);
187  }
188  g_hash_table_destroy(si->objid_listenerlist_tab);
189 
190  free(si);
191 
192  if (!no_hash_delete)
193  g_hash_table_remove(svctype_info_tab,(gpointer)(uintptr_t)svctype);
194 }
196  pthread_mutex_lock(&generic_rpc_mutex);
198  pthread_mutex_unlock(&generic_rpc_mutex);
199 }
200 
207  struct soap *soap;
208 };
209 
210 struct argp_option generic_rpc_argp_opts[] = {
211  { "port",'p',"PORT",0,
212  "Set the RPC server's port; if unspecified, uses stdin.",0 },
213  { "tmpdir",'T',"DIR",0,
214  "Set the RPC server's tmpdir; if unspecified, $TMP, then /var/tmp.",0 },
215  { 0,0,0,0,0,0 }
216 };
217 
218 error_t generic_rpc_argp_parse_opt(int key,char *arg,struct argp_state *state) {
219  struct generic_rpc_config *cfg = (struct generic_rpc_config *)state->input;
220 
221  switch (key) {
222  case ARGP_KEY_ARG:
223  case ARGP_KEY_ARGS:
224  return ARGP_ERR_UNKNOWN;
225  case ARGP_KEY_END:
226  case ARGP_KEY_NO_ARGS:
227  case ARGP_KEY_SUCCESS:
228  case ARGP_KEY_ERROR:
229  case ARGP_KEY_FINI:
230  return 0;
231  case ARGP_KEY_INIT:
232  /* No child input for log child parser to init. */
233  cfg->port = -1;
234  return 0;
235 
236  case 'p':
237  if (arg)
238  cfg->port = atoi(arg);
239  else
240  return ARGP_ERR_UNKNOWN;
241  break;
242  case 'T':
243  if (arg)
244  GENERIC_RPC_TMPDIR = strdup(arg);
245  else
246  return ARGP_ERR_UNKNOWN;
247  break;
248 
249  default:
250  return ARGP_ERR_UNKNOWN;
251  }
252 
253  return 0;
254 }
255 
256 const struct argp_child generic_rpc_argp_children[2] = {
257  { &log_argp,0,log_argp_header,0 },
258  { NULL,0,NULL,0 },
259 };
260 
261 struct argp generic_rpc_argp = {
264 };
265 
266 int generic_rpc_handle_request(struct soap *soap) {
267  pthread_detach(pthread_self());
268 
269  //soap_set_recv_logfile(soap,NULL);
270  //soap_set_sent_logfile(soap,NULL);
271  //soap_set_test_logfile(soap,NULL);
272 
273  soap->fdebug[SOAP_INDEX_RECV] = stderr;
274  soap->fdebug[SOAP_INDEX_SENT] = stderr;
275  soap->fdebug[SOAP_INDEX_TEST] = stderr;
276 
277  soap_serve(soap);
278 
279  vdebug(8,LA_XML,LF_RPC,"finished request from %d.%d.%d.%d\n",
280  (soap->ip >> 24) & 0xff,(soap->ip >> 16) & 0xff,
281  (soap->ip >> 8) & 0xff,soap->ip & 0xff);
282 
283  soap_destroy(soap);
284  soap_end(soap);
285  soap_done(soap);
286 
287  free(soap);
288 
289  return 0;
290 }
291 
292 static void *_generic_rpc_handle_request(void *arg) {
293  struct generic_rpc_handler_state *state = \
294  (struct generic_rpc_handler_state *)arg;
295  char namebuf[16];
296 
297  /* Server never waits for us. */
298  pthread_detach(pthread_self());
299 
300  snprintf(namebuf,sizeof(namebuf),"%s_reqhand",state->cfg->name);
301  prctl(PR_SET_NAME,namebuf,NULL,NULL,NULL);
302 
303  /* This does all the work, AND frees its argument. */
304  state->cfg->handle_request(state->soap);
305 
306  free(state);
307 
308  return NULL;
309 }
310 
311 static void *generic_rpc_sigwaiter(void *arg) {
312  struct generic_rpc_config *cfg = (struct generic_rpc_config *)arg;
313  int rc;
314  siginfo_t siginfo;
315 
316  prctl(PR_SET_NAME,"sigwaiter",NULL,NULL,NULL);
317 
318  while (1) {
319  memset(&siginfo,0,sizeof(siginfo));
320  rc = sigwaitinfo(&cfg->sigset,&siginfo);
321  if (rc < 0) {
322  if (errno == EINTR || errno == EAGAIN)
323  continue;
324  else {
325  vwarn("sigwait: %s!\n",strerror(errno));
326  exit(4);
327  }
328  }
329  else if (rc == SIGINT) {
330  vwarn("interrupted, exiting!\n");
331  exit(0);
332  }
333  else if (rc == SIGCHLD) {
334  waitpipe_notify(rc,&siginfo);
335  sigaddset(&cfg->sigset,SIGCHLD);
336  }
337  else if (rc == SIGPIPE) {
338  vdebug(15,LA_XML,LF_SVC,"sigpipe!\n");
339  sigaddset(&cfg->sigset,SIGPIPE);
340  }
341  else {
342  vwarn("unexpected signal %d; ignoring!\n",rc);
343  }
344  }
345 
346  return NULL;
347 }
348 
350  struct generic_rpc_handler_state *state;
351  struct soap soap;
352  struct soap *tsoap;
353  SOAP_SOCKET m, s;
354  int rc;
355  pthread_t tid, sigtid;
356 
357  soap_init(&soap);
358  //soap_set_omode(&soap,SOAP_XML_GRAPH);
359 
360  //soap_set_recv_logfile(&soap,NULL);
361  //soap_set_sent_logfile(&soap,NULL);
362  //soap_set_test_logfile(&soap,NULL);
363 
364  soap.fdebug[SOAP_INDEX_RECV] = stderr;
365  soap.fdebug[SOAP_INDEX_SENT] = stderr;
366  soap.fdebug[SOAP_INDEX_TEST] = stderr;
367 
368  /*
369  * If no args, assume this is CGI coming in on stdin.
370  */
371  if (cfg->port <= 0) {
372  vdebug(5,LA_XML,LF_RPC,"Listening on stdin...\n");
373  soap_serve(&soap);
374  soap_destroy(&soap);
375  soap_end(&soap);
376  return 0;
377  }
378 
379  /*
380  * Otherwise, let's serve forever!
381  */
382  soap.send_timeout = 60;
383  soap.recv_timeout = 60;
384  soap.accept_timeout = 0;
385  soap.max_keep_alive = 100;
386 
387  /* Disable this once stability is reached. */
388  soap.bind_flags = SO_REUSEADDR;
389 
390  m = soap_bind(&soap,NULL,cfg->port,64);
391  if (!soap_valid_socket(m)) {
392  verror("Could not bind to port %d: ",cfg->port);
393  soap_print_fault(&soap,stderr);
394  verrorc("\n");
395  return -1;
396  }
397 
398  /*
399  * Create a thread for handling sigs specified in @cfg; the
400  * other threads block all sigs.
401  */
402  if ((rc = pthread_sigmask(SIG_BLOCK,&cfg->sigset,NULL))) {
403  verror("pthread_sigmask: %s\n",strerror(rc));
404  return -2;
405  }
406 
407  if ((rc = pthread_create(&sigtid,NULL,&generic_rpc_sigwaiter,cfg))) {
408  verror("pthread: %s\n",strerror(rc));
409  return -3;
410  }
411 
412  vdebug(5,LA_XML,LF_RPC,"Listening on port %d\n",cfg->port);
413 
414  while (1) {
415  s = soap_accept(&soap);
416  if (!soap_valid_socket(s)) {
417  if (soap.errnum) {
418  verror("SOAP: ");
419  soap_print_fault(&soap,stderr);
420  soap_destroy(&soap);
421  soap_end(&soap);
422  soap_done(&soap);
423  return -1;
424  }
425  verror("SOAP: server timed out\n");
426  break;
427  }
428  vdebug(8,LA_XML,LF_RPC,"connection from %d.%d.%d.%d\n",
429  (soap.ip >> 24) & 0xff,(soap.ip >> 16) & 0xff,
430  (soap.ip >> 8) & 0xff,soap.ip & 0xff);
431 
432  tsoap = soap_copy(&soap);
433  if (!tsoap) {
434  verror("could not copy SOAP data to handle connection; exiting!\n");
435  break;
436  }
437 
438  state = calloc(1,sizeof(*state));
439  state->soap = tsoap;
440  state->cfg = cfg;
441 
442  pthread_create(&tid,NULL,_generic_rpc_handle_request,(void *)state);
443  }
444 
445  soap_destroy(&soap);
446  soap_end(&soap);
447  soap_done(&soap);
448 
449  return 0;
450 }
451 
452 
456 struct generic_rpc_listener *
458  struct svctype_info *si;
459 
460  if (!(si = __get_si(svctype)))
461  return NULL;
462 
463  return (struct generic_rpc_listener *) \
464  g_hash_table_lookup(si->url_listener_tab,url);
465 }
466 struct generic_rpc_listener *
468  struct generic_rpc_listener *l;
469 
470  pthread_mutex_lock(&generic_rpc_mutex);
471  l = _generic_rpc_lookup_listener_url(svctype,url);
472  pthread_mutex_unlock(&generic_rpc_mutex);
473 
474  return l;
475 }
476 
477 struct generic_rpc_listener *
479  struct svctype_info *si;
480 
481  if (!(si = __get_si(svctype)))
482  return NULL;
483 
484  return (struct generic_rpc_listener *) \
485  g_hash_table_lookup(si->id_listener_tab,(gpointer)(uintptr_t)listener_id);
486 }
487 struct generic_rpc_listener *
489  struct generic_rpc_listener *l;
490 
491  pthread_mutex_lock(&generic_rpc_mutex);
492  l = _generic_rpc_lookup_listener_id(svctype,listener_id);
493  pthread_mutex_unlock(&generic_rpc_mutex);
494 
495  return l;
496 }
497 
499  struct generic_rpc_listener *l = NULL;
500  struct svctype_info *si;
501 
502  if (!(si = __get_si(svctype)))
503  return -1;
504 
505  if (_generic_rpc_lookup_listener_url(svctype,url))
506  return -1;
507 
508  l = calloc(1,sizeof(*l));
509 
510  l->id = generic_rpc_listener_count++;
511  l->svctype = svctype;
512  l->url = strdup(url);
513  l->svctype = svctype;
514  l->objid_tab = g_hash_table_new(g_direct_hash,g_direct_equal);
515 
516  soap_init2(&l->soap,SOAP_IO_KEEPALIVE,SOAP_IO_KEEPALIVE);
517  l->soap.socket_flags = MSG_NOSIGNAL;
518  l->soap.tcp_keep_alive = 1;
519  /*
520  * These are default timeouts for non-owner listener notifications.
521  *
522  * If the listener is being notified about an object it owns, we
523  * increase the timeouts a lot (but not the connect_timeout -- it
524  * should be able to *connect* quickly).
525  */
526  l->soap.connect_timeout = 4;
527  l->soap.send_timeout = 4;
528  l->soap.recv_timeout = 4;
529 
530  g_hash_table_insert(si->url_listener_tab,url,l);
531  g_hash_table_insert(si->id_listener_tab,(gpointer)(uintptr_t)l->id,l);
532 
533  return l->id;
534 }
536  int rc;
537 
538  pthread_mutex_lock(&generic_rpc_mutex);
539  rc = _generic_rpc_insert_listener(svctype,url);
540  pthread_mutex_unlock(&generic_rpc_mutex);
541 
542  return rc;
543 }
544 
545 static void _generic_rpc_listener_free(struct generic_rpc_listener *l) {
546  /* Cleanup any soap state */
547  if (soap_valid_socket(l->soap.socket))
548  soap_closesock(&(l->soap));
549  /* Make sure these has happened... */
550  soap_destroy(&l->soap);
551  soap_end(&l->soap);
552  /* This must be done here, I think. */
553  soap_done(&l->soap);
554  g_hash_table_destroy(l->objid_tab);
555  free(l->url);
556  free(l);
557 }
558 
559 int _generic_rpc_remove_listener(rpc_svctype_t svctype,int listener_id,
560  int no_objid_deletes) {
561  struct generic_rpc_listener *l;
562  struct generic_rpc_listener *tmpl;
563  struct svctype_info *si;
564  struct array_list *ll;
565  GHashTableIter iter;
566  int i;
567 
568  if (!(si = __get_si(svctype)))
569  return -1;
570 
571  l = (struct generic_rpc_listener *) \
572  g_hash_table_lookup(si->id_listener_tab,(gpointer)(uintptr_t)listener_id);
573  if (!l)
574  return -1;
575 
576  g_hash_table_remove(si->id_listener_tab,(gpointer)(uintptr_t)listener_id);
577  g_hash_table_remove(si->url_listener_tab,l->url);
578 
579  /*
580  * We have to go through the objid_listenerlist_table, and remove
581  * this listener from any objid/list.
582  */
583  if (!no_objid_deletes) {
584  /* Do the authoritative listener tab */
585  g_hash_table_iter_init(&iter,si->objid_listener_tab);
586  while (g_hash_table_iter_next(&iter,NULL,(gpointer *)&tmpl)) {
587  if (l == tmpl)
588  g_hash_table_iter_remove(&iter);
589  }
590 
591  /* Do the non-auth listener tab */
592  g_hash_table_iter_init(&iter,si->objid_listenerlist_tab);
593  while (g_hash_table_iter_next(&iter,NULL,(gpointer *)&ll)) {
594  array_list_foreach(ll,i,tmpl) {
595  if (l == tmpl) {
597  break;
598  }
599  }
600  }
601  }
602 
603  _generic_rpc_listener_free(l);
604 
605  return 0;
606 }
607 
609  int rc;
610 
611  pthread_mutex_lock(&generic_rpc_mutex);
612  rc = _generic_rpc_remove_listener(svctype,listener_id,0);
613  pthread_mutex_unlock(&generic_rpc_mutex);
614 
615  return rc;
616 }
617 
618 struct generic_rpc_listener *
620  struct svctype_info *si;
621 
622  if (!(si = __get_si(svctype))) {
623  return NULL;
624  }
625 
626  return (struct generic_rpc_listener *) \
627  g_hash_table_lookup(si->objid_listener_tab,(gpointer)(uintptr_t)objid);
628 }
629 
631  int objid) {
632  struct svctype_info *si;
633  struct array_list *ll;
634  struct generic_rpc_listener *l;
635  struct generic_rpc_listener *tmpl;
636  int i;
637 
638  if (!(si = __get_si(svctype))) {
639  return -1;
640  }
641 
642  if (!(l = _generic_rpc_lookup_listener_id(svctype,listener_id))) {
643  return -1;
644  }
645 
646  /*
647  * Remove the owner, if this binding is the owner.
648  */
649  if ((l == _generic_rpc_listener_lookup_owner(svctype,objid)))
650  g_hash_table_remove(si->objid_listener_tab,(gpointer)(uintptr_t)objid);
651 
652  ll = (struct array_list *) \
653  g_hash_table_lookup(si->objid_listenerlist_tab,(gpointer)(uintptr_t)objid);
654  if (!ll || array_list_len(ll) < 1)
655  return 0;
656 
657  /*
658  * Remove the listener from the object's list of bound listeners
659  */
660  array_list_foreach(ll,i,tmpl) {
661  if (tmpl == l) {
663  break;
664  }
665  }
666 
667  g_hash_table_remove(l->objid_tab,(gpointer)(uintptr_t)objid);
668 
669  /*
670  * If this is a dynamic listener, and it has no more objects it is
671  * listening to, nuke it!
672  */
673  if (l->is_dynamic && g_hash_table_size(l->objid_tab) == 0) {
674  _generic_rpc_remove_listener(svctype,l->id,0);
675  }
676 
677  return 0;
678 }
679 
681  int objid) {
682  int rc;
683 
684  pthread_mutex_lock(&generic_rpc_mutex);
685  rc = _generic_rpc_unbind_listener_objid(svctype,listener_id,objid);
686  pthread_mutex_unlock(&generic_rpc_mutex);
687 
688  return rc;
689 }
690 
692  struct array_list *ll;
693  struct svctype_info *si;
694  int i;
695  struct generic_rpc_listener *l;
696 
697  if (!(si = __get_si(svctype)))
698  return -1;
699 
700  ll = (struct array_list *)g_hash_table_lookup(si->objid_listenerlist_tab,
701  (gpointer)(uintptr_t)objid);
702 
703  if (!ll)
704  return 0;
705 
706  /*
707  * Have to clone it so that we don't edit the real copy in the
708  * function calls below!
709  */
710  ll = array_list_clone(ll,0);
711 
712  array_list_foreach(ll,i,l) {
713  _generic_rpc_unbind_listener_objid(svctype,l->id,objid);
714  if (l->is_dynamic && g_hash_table_size(l->objid_tab) == 0)
715  _generic_rpc_remove_listener(svctype,l->id,0);
716  }
717 
718  array_list_free(ll);
719 
720  /*
721  * Now actually remove the objid bindings.
722  */
723  ll = (struct array_list *)g_hash_table_lookup(si->objid_listenerlist_tab,
724  (gpointer)(uintptr_t)objid);
725 
726  array_list_free(ll);
727  g_hash_table_remove(si->objid_listenerlist_tab,(gpointer)(uintptr_t)objid);
728  g_hash_table_remove(si->objid_listener_tab,(gpointer)(uintptr_t)objid);
729 
730  return 0;
731 }
732 
734  int rc;
735 
736  pthread_mutex_lock(&generic_rpc_mutex);
737  rc = _generic_rpc_unbind_all_listeners_objid(svctype,objid);
738  pthread_mutex_unlock(&generic_rpc_mutex);
739 
740  return rc;
741 }
742 
743 int generic_rpc_bind_listener_objid(rpc_svctype_t svctype,int listener_id,
744  int objid,int owns) {
745  struct svctype_info *si;
746  struct array_list *ll;
747  struct generic_rpc_listener *l;
748 
749  pthread_mutex_lock(&generic_rpc_mutex);
750 
751  if (!(si = __get_si(svctype))) {
752  pthread_mutex_unlock(&generic_rpc_mutex);
753  return -1;
754  }
755 
756  if (!(l = _generic_rpc_lookup_listener_id(svctype,listener_id))) {
757  pthread_mutex_unlock(&generic_rpc_mutex);
758  verror("listener %d does not exist!\n",listener_id);
759  return -1;
760  }
761 
762  if (owns) {
763  if (g_hash_table_lookup(si->objid_listener_tab,
764  (gpointer)(uintptr_t)objid)) {
765  pthread_mutex_unlock(&generic_rpc_mutex);
766  return -1;
767  }
768 
769  g_hash_table_insert(si->objid_listener_tab,(gpointer)(uintptr_t)objid,l);
770  }
771 
772  if (!(ll = (struct array_list *) \
773  g_hash_table_lookup(si->objid_listenerlist_tab,
774  (gpointer)(uintptr_t)objid))) {
775  ll = array_list_create(1);
776  g_hash_table_insert(si->objid_listenerlist_tab,
777  (gpointer)(uintptr_t)objid,ll);
778  }
779  else if (array_list_find(ll,l) != -1) {
780  pthread_mutex_unlock(&generic_rpc_mutex);
781  if (owns)
782  /* This should be impossible, see above if (owns) check. */
783  return 0;
784  else {
785  verror("listener %d already on objid %d's list!\n",
786  listener_id,objid);
787  return -1;
788  }
789  }
790 
791  /* If there is a dynamic one already, make it static! */
792  l->is_dynamic = 0;
793 
794  /* Record the binding in the listener's table. */
795  g_hash_table_insert(l->objid_tab,(gpointer)(uintptr_t)objid,l);
796 
797  array_list_append(ll,l);
798 
799  pthread_mutex_unlock(&generic_rpc_mutex);
800 
801  return 0;
802 }
803 
805  int objid,int owns) {
806  struct svctype_info *si;
807  struct array_list *ll;
808  struct generic_rpc_listener *l;
809 
810  pthread_mutex_lock(&generic_rpc_mutex);
811 
812  if (!(si = __get_si(svctype))) {
813  pthread_mutex_unlock(&generic_rpc_mutex);
814  return -1;
815  }
816 
817  if (!(l = _generic_rpc_lookup_listener_url(svctype,listener_url))) {
818  _generic_rpc_insert_listener(svctype,listener_url);
819  l = _generic_rpc_lookup_listener_url(svctype,listener_url);
820  l->is_dynamic = 1;
821  }
822 
823  if (owns) {
824  if (g_hash_table_lookup(si->objid_listener_tab,
825  (gpointer)(uintptr_t)objid)) {
826  pthread_mutex_unlock(&generic_rpc_mutex);
827  return -1;
828  }
829 
830  g_hash_table_insert(si->objid_listener_tab,(gpointer)(uintptr_t)objid,l);
831  }
832 
833  if (!(ll = (struct array_list *) \
834  g_hash_table_lookup(si->objid_listenerlist_tab,
835  (gpointer)(uintptr_t)objid))) {
836  ll = array_list_create(1);
837  g_hash_table_insert(si->objid_listenerlist_tab,
838  (gpointer)(uintptr_t)objid,ll);
839  }
840  else if (array_list_find(ll,l) != -1) {
841  pthread_mutex_unlock(&generic_rpc_mutex);
842  if (owns)
843  /* This should be impossible, see above if (owns) check. */
844  return 0;
845  else {
846  verror("listener %d already on objid %d's list!\n",
847  l->id,objid);
848  return -1;
849  }
850  }
851 
852  l->is_dynamic = 1;
853 
854  /* Record the binding in the listener's table. */
855  g_hash_table_insert(l->objid_tab,(gpointer)(uintptr_t)objid,l);
856 
857  array_list_append(ll,l);
858 
859  pthread_mutex_unlock(&generic_rpc_mutex);
860 
861  return 0;
862 }
863 
865  int objid) {
866  int rc;
867  struct generic_rpc_listener *l;
868 
869  pthread_mutex_lock(&generic_rpc_mutex);
870  if (!(l = _generic_rpc_lookup_listener_url(svctype,listener_url))) {
871  pthread_mutex_unlock(&generic_rpc_mutex);
872  return -1;
873  }
874  rc = _generic_rpc_unbind_listener_objid(svctype,l->id,objid);
875  pthread_mutex_unlock(&generic_rpc_mutex);
876 
877  return rc;
878 }
879 
881  struct svctype_info *si;
882  struct array_list *ll;
883  int rc = 0;
884 
885  pthread_mutex_lock(&generic_rpc_mutex);
886 
887  if (!(si = __get_si(svctype))) {
888  pthread_mutex_unlock(&generic_rpc_mutex);
889  return 0;
890  }
891 
892  ll = (struct array_list *) \
893  g_hash_table_lookup(si->objid_listenerlist_tab,(gpointer)(uintptr_t)objid);
894  if (ll)
895  rc = array_list_len(ll);
896 
897  pthread_mutex_unlock(&generic_rpc_mutex);
898 
899  return rc;
900 }
901 
904  void *data) {
905  struct array_list *ll;
906  int i;
907  int rc;
908  struct generic_rpc_listener *l;
909  struct generic_rpc_listener *owner = NULL;
910  struct svctype_info *si;
911 
912  pthread_mutex_lock(&generic_rpc_mutex);
913 
914  if (!(si = __get_si(svctype))) {
915  pthread_mutex_unlock(&generic_rpc_mutex);
916  return -1;
917  }
918 
919  owner = _generic_rpc_listener_lookup_owner(svctype,objid);
920 
921  ll = (struct array_list *) \
922  g_hash_table_lookup(si->objid_listenerlist_tab,
923  (gpointer)(uintptr_t)objid);
924 
925  if (!ll || array_list_len(ll) < 1) {
926  pthread_mutex_unlock(&generic_rpc_mutex);
927  return 0;
928  }
929 
930  /*
931  * First, contact the authoritative listener. Change the soap
932  * timeouts temporarily; we need to wait for the owner.
933  */
934  if (owner) {
935  owner->soap.connect_timeout = 24 * 60 * 60;
936  owner->soap.send_timeout = 24 * 60 * 60;
937  owner->soap.recv_timeout = 24 * 60 * 60;
938 
939  rc = notifier(owner,1,data);
940 
941  owner->soap.connect_timeout = 4;
942  owner->soap.send_timeout = 4;
943  owner->soap.recv_timeout = 4;
944  }
945 
946  /*
947  * Then do the others.
948  */
949  array_list_foreach(ll,i,l) {
950  if (l == owner)
951  continue;
952 
953  rc = notifier(l,0,data);
954  if (rc < 0) {
956  "notifier returned %d on %s for (%d,%d); removing!\n",
957  rc,l->url,svctype,objid);
958  /*
959  * We *must* delete this listener from the list we are
960  * iterating through, because the remove_listener function
961  * will try to remove it and mess up our loop!
962  */
964  /* Now the list we're currently on will not be touched
965  * (unless there are duplicates, which cannot happen).
966  */
967  _generic_rpc_remove_listener(svctype,l->id,0);
968  }
969  else {
970  vdebug(9,LA_XML,LF_RPC,"notified %s for (%d,%d)\n",
971  l->url,svctype,objid);
972  }
973  }
974 
975  pthread_mutex_unlock(&generic_rpc_mutex);
976 
977  return 0;
978 }
979 
980 struct xsd__hexBinary *
982  char *filename,int max_size) {
983  int rc;
984  struct stat statbuf;
985  int fd;
986  int sz;
987  struct xsd__hexBinary *retval;
988 
989  memset(&statbuf,0,sizeof(statbuf));
990  if (stat(filename,&statbuf)) {
991  verror("could not stat logfile %s: %s\n",filename,strerror(errno));
992  return NULL;
993  }
994  else if ((fd = open(filename,O_RDONLY)) < 0) {
995  verror("could not open logfile %s: %s\n",
996  filename,strerror(errno));
997  return NULL;
998  }
999  else {
1000  retval = SOAP_CALLOC(soap,1,sizeof(*retval));
1001  if (statbuf.st_size > 0) {
1002  sz = statbuf.st_size;
1003  if (max_size > 0 && max_size < statbuf.st_size)
1004  sz = max_size;
1005  retval->__ptr = SOAP_CALLOC(soap,1,sz);
1006  retval->__size = sz;
1007 
1008  /* Read it all */
1009  lseek(fd,statbuf.st_size - sz,SEEK_SET);
1010  rc = 0;
1011  errno = 0;
1012  __SAFE_IO(read,"read",fd,retval->__ptr,sz,rc);
1013  if (rc != sz && errno) {
1014  vwarn("only read %d of %d bytes for logfile %s: %s\n",
1015  rc,sz,filename,strerror(errno));
1016  }
1017  if (rc != sz) {
1018  vwarn("only read %d of %d bytes for logfile %s (no error)\n",
1019  rc,sz,filename);
1020  retval->__size = rc;
1021  }
1022  }
1023  close(fd);
1024  }
1025 
1026  return retval;
1027 }
const struct argp_child generic_rpc_argp_children[2]
Definition: generic_rpc.c:256
#define vwarnopt(level, area, flags, format,...)
Definition: log.h:37
GHashTable * objid_tab
Definition: generic_rpc.h:90
int( generic_rpc_listener_notifier_t)(struct generic_rpc_listener *l, int is_owner, void *data)
Definition: generic_rpc.h:107
int generic_rpc_serve(struct generic_rpc_config *cfg)
Definition: generic_rpc.c:349
int _generic_rpc_remove_listener(rpc_svctype_t svctype, int listener_id, int no_objid_deletes)
Definition: generic_rpc.c:559
#define SOAP_CALLOC(soap, nmemb, size)
Definition: util.h:25
struct argp generic_rpc_argp
Definition: generic_rpc.c:261
int generic_rpc_unbind_dynlistener_objid(rpc_svctype_t svctype, char *listener_url, int objid)
Definition: generic_rpc.c:864
static uint64_t unsigned int i
Definition: log.h:204
rpc_svctype_t svctype
Definition: generic_rpc.h:85
void generic_rpc_init(void)
Definition: generic_rpc.c:69
char * GENERIC_RPC_TMPDIR
Definition: generic_rpc.c:52
int generic_rpc_unbind_all_listeners_objid(rpc_svctype_t svctype, int objid)
Definition: generic_rpc.c:733
int _generic_rpc_unbind_listener_objid(rpc_svctype_t svctype, int listener_id, int objid)
Definition: generic_rpc.c:630
#define log_argp_header
Definition: log.h:28
struct argp log_argp
Definition: log.c:413
struct generic_rpc_config * cfg
Definition: generic_rpc.c:206
GHashTable * objid_listener_tab
Definition: generic_rpc.c:45
#define verror(format,...)
Definition: log.h:30
#define verrorc(format,...)
Definition: log.h:32
#define vwarn(format,...)
Definition: log.h:33
void free(void *ptr)
Definition: debugserver.c:207
int generic_rpc_insert_listener(rpc_svctype_t svctype, char *url)
Definition: generic_rpc.c:535
int _generic_rpc_insert_listener(rpc_svctype_t svctype, char *url)
Definition: generic_rpc.c:498
unsigned char * __ptr
Definition: xsdc.gsm.h:13
int generic_rpc_remove_listener(rpc_svctype_t svctype, int listener_id)
Definition: generic_rpc.c:608
#define array_list_foreach(alist, lpc, placeholder)
Definition: alist.h:371
void waitpipe_notify(int signo, siginfo_t *siginfo)
Definition: waitpipe.c:49
struct soap soap
Definition: generic_rpc.h:97
GHashTable * url_listener_tab
Definition: generic_rpc.c:40
#define generic_rpc_argp_header
Definition: generic_rpc.h:33
GHashTable * id_listener_tab
Definition: generic_rpc.c:42
struct argp_option generic_rpc_argp_opts[]
Definition: generic_rpc.c:210
#define __DEFAULT_GENERIC_RPC_TMPDIR
Definition: generic_rpc.c:50
Definition: log.h:203
int generic_rpc_unbind_listener_objid(rpc_svctype_t svctype, int listener_id, int objid)
Definition: generic_rpc.c:680
struct xsd__hexBinary * generic_rpc_read_file_into_hexBinary(struct soap *soap, char *filename, int max_size)
Definition: generic_rpc.c:981
rpc_svctype_t
Definition: generic_rpc.h:28
void generic_rpc_register_svctype(rpc_svctype_t svctype)
Definition: generic_rpc.c:139
int generic_rpc_bind_dynlistener_objid(rpc_svctype_t svctype, char *listener_url, int objid, int owns)
Definition: generic_rpc.c:804
int _generic_rpc_unbind_all_listeners_objid(rpc_svctype_t svctype, int objid)
Definition: generic_rpc.c:691
#define vdebug(devel, areas, flags, format,...)
Definition: log.h:302
Definition: log.h:72
void * calloc(size_t nmemb, size_t size)
Definition: debugserver.c:200
void generic_rpc_fini(void)
Definition: generic_rpc.c:104
struct generic_rpc_listener * generic_rpc_lookup_listener_url(rpc_svctype_t svctype, char *url)
Definition: generic_rpc.c:467
struct generic_rpc_listener * _generic_rpc_lookup_listener_id(rpc_svctype_t svctype, int listener_id)
Definition: generic_rpc.c:478
int generic_rpc_listener_notify_all(rpc_svctype_t svctype, int objid, generic_rpc_listener_notifier_t *notifier, void *data)
Definition: generic_rpc.c:902
int generic_rpc_bind_listener_objid(rpc_svctype_t svctype, int listener_id, int objid, int owns)
Definition: generic_rpc.c:743
int(* handle_request)(struct soap *soap)
Definition: generic_rpc.h:51
#define __SAFE_IO(fn, fns, fd, buf, buflen, rc)
Definition: generic_rpc.h:164
struct generic_rpc_listener * _generic_rpc_listener_lookup_owner(rpc_svctype_t svctype, int objid)
Definition: generic_rpc.c:619
int generic_rpc_handle_request(struct soap *soap)
Definition: generic_rpc.c:266
#define array_list_foreach_delete(alist, lpc)
Definition: alist.h:389
struct generic_rpc_listener * generic_rpc_lookup_listener_id(rpc_svctype_t svctype, int listener_id)
Definition: generic_rpc.c:488
void _generic_rpc_unregister_svctype(rpc_svctype_t svctype, int no_hash_delete)
Definition: generic_rpc.c:163
void generic_rpc_unregister_svctype(rpc_svctype_t svctype)
Definition: generic_rpc.c:195
struct svctype_info * __get_si(rpc_svctype_t svctype)
Definition: generic_rpc.c:131
GHashTable * objid_listenerlist_tab
Definition: generic_rpc.c:47
int generic_rpc_count_listeners(rpc_svctype_t svctype, int objid)
Definition: generic_rpc.c:880
int waitpipe_init_ext(void(*alt_handler)(int, siginfo_t *, void *))
Definition: waitpipe.c:124
error_t generic_rpc_argp_parse_opt(int key, char *arg, struct argp_state *state)
Definition: generic_rpc.c:218
struct generic_rpc_listener * _generic_rpc_lookup_listener_url(rpc_svctype_t svctype, char *url)
Definition: generic_rpc.c:457