1 /* $TOG: agent.c /main/2 1998/03/16 14:42:16 mgreess $ */
3 * (c) Copyright 1993, 1994 Hewlett-Packard Company
4 * (c) Copyright 1993, 1994 International Business Machines Corp.
5 * (c) Copyright 1993, 1994 Novell, Inc.
6 * (c) Copyright 1993, 1994 Sun Microsystems, Inc.
16 # include <sys/poll.h>
20 #if defined(SunOS) || defined(USL) || defined(__uxp__)
21 #include <netconfig.h>
24 #include <sys/signal.h>
25 #include <sys/socket.h>
26 #include <sys/errno.h>
27 #endif /* SunOS || USL || __uxp__ */
28 #include <X11/Intrinsic.h>
40 * - contain update information from backend
42 typedef struct cb_info {
51 static _CallbackInfo *cb_head = NULL, *cb_tail = NULL;
53 u_long _DtCm_transient = 0;
55 static u_long prognum = 0x40000000;
56 static int mapped = 0;
58 /******************************************************************************
59 * forward declaration of static functions used within the file
60 ******************************************************************************/
61 #if defined(SunOS) || defined(USL) || defined(__uxp__)
62 static u_long gettransient (u_long version);
64 static u_long gettransient (int proto, u_long vers, int *sockp);
66 static void _DtCm_handle_callback();
67 static CSA_return_code _ConvertCallbackData(cmcb_update_callback_args *args,
69 static CSA_return_code _CopyAttributeNames(uint fnum, char **fnames,
70 CSA_uint32 *tnum, char ***tnames);
71 static boolean_t _ProcessV1Callback(_CallbackInfo *ptr);
72 static boolean_t _ProcessV2Callback(_CallbackInfo *ptr);
73 static void _FreeCallbackInfo(_CallbackInfo *ptr);
75 /*****************************************************************************
76 * extern functions used in the library
77 *****************************************************************************/
80 * Register rpc service for server callback
88 #if defined(SunOS) && SunOS < 55 || defined(USL) || defined(__uxp__)
89 extern boolean_t rpc_reg(const u_long, const u_long, const u_long,
90 const char *(*)(), const xdrproc_t, const xdrproc_t,
94 #if defined(SunOS) || defined(USL)|| defined(__uxp__)
95 extern void (*sigset(int, void (*)(int)))(int);
97 extern void (*sigset())();
100 /* locking candidate for MT-safe purpose */
104 DP(("libdtcm: _DtCm_init_agent\n"));
106 #if defined(SunOS) || defined(USL) || defined(__uxp__)
107 (void)rpcb_unset(_DtCm_transient, AGENTVERS, NULL);
108 if ((_DtCm_transient = gettransient((u_long)1)) == 0) {
109 _DtCm_print_errmsg("Cannot get transient program number\n");
110 _DtCm_print_errmsg("Callback cannot be enabled.\n");
114 /* register v1 callback */
115 if (rpc_reg(_DtCm_transient, AGENTVERS, update_callback,
116 (const char *(*)())_DtCm_update_callback_1, _DtCm_xdr_Table_Res_4,
117 _DtCm_xdr_Update_Status, "udp") == -1) {
118 _DtCm_print_errmsg("Cannot register v1 callback handler\n");
119 _DtCm_print_errmsg("Callback cannot be enabled.\n");
122 /* register v2 callback */
123 if (rpc_reg(_DtCm_transient, AGENTVERS_2, CMCB_UPDATE_CALLBACK,
124 (const char *(*)())cmcb_update_callback_2_svc,
125 xdr_cmcb_update_callback_args, xdr_void, "udp") == -1) {
126 _DtCm_print_errmsg("Cannot register v2 callback handler\n");
127 _DtCm_print_errmsg("Callback cannot be enabled.\n");
131 (void)pmap_unset(_DtCm_transient, AGENTVERS);
132 if ((_DtCm_transient = gettransient(IPPROTO_UDP,(u_long)1, &s)) == 0) {
133 _DtCm_print_errmsg("Cannot get transient program number\n");
134 _DtCm_print_errmsg("Callback cannot be enabled.\n");
138 if (registerrpc(_DtCm_transient, AGENTVERS, update_callback,
139 (char *(*)())_DtCm_update_callback_1, _DtCm_xdr_Table_Res_4,
140 _DtCm_xdr_Update_Status) == -1) {
141 _DtCm_print_errmsg("Cannot register v1 callback handler\n");
142 _DtCm_print_errmsg("Callback cannot be enabled.\n");
145 if (registerrpc(_DtCm_transient, AGENTVERS_2, CMCB_UPDATE_CALLBACK,
146 (char *(*)())cmcb_update_callback_2_svc,
147 xdr_cmcb_update_callback_args, xdr_void) == -1) {
148 _DtCm_print_errmsg("Cannot register v2 callback handler\n");
149 _DtCm_print_errmsg("Callback cannot be enabled.\n");
152 #endif /* SunOS || USL || __uxp__ */
154 /* locking candidate for MT-safe purpose */
159 * Unregister with the rpc service.
162 _DtCm_destroy_agent()
167 DP(("libdtcm: _DtCm_destroy_agent\n"));
169 #if defined(SunOS) || defined(USL) || defined(__uxp__)
170 (void) rpcb_unset(_DtCm_transient, AGENTVERS, NULL);
171 (void) rpcb_unset(_DtCm_transient, AGENTVERS_2, NULL);
173 (void) pmap_unset(_DtCm_transient, AGENTVERS);
174 (void) pmap_unset(_DtCm_transient, AGENTVERS_2);
175 #endif /* SunOS || USL || __uxp__ */
177 /* locking candidate for MT-safe purpose */
182 _DtCm_process_updates()
186 fd_mask fmask, *inbits;
187 struct pollfd pfd[FD_SETSIZE];
193 rpc_bits = svc_fdset;
195 /* convert to pollfd structure */
196 inbits = rpc_bits.fds_bits;
198 for (i = 0; i < FD_SETSIZE; i += NFDBITS) {
200 for (j = 0; fmask != 0 ; j++, fmask >>= 1) {
203 if (p->fd >= FD_SETSIZE)
212 /* poll and return right away */
215 nfd = poll(pfd, i, 0);
221 /* if set, handle rpc calls */
223 /* convert back to fd_set structure */
227 for (p = pfd; i-- > 0; p++) {
230 inbits = &rpc_bits.fds_bits[j];
233 if (p->revents & POLLIN) {
234 *inbits |= (1 << (p->fd % NFDBITS));
240 svc_getreqset(&rpc_bits);
245 * The server calls this routine when an update event occurs;
246 * It's job is to notify CM asynchronously that an
247 * update has occurred. It has to do it this
248 * way (i.e. raise a signal) because the client
249 * can't make an rpc call until this procedure call has
250 * returned to the server.
254 _DtCm_update_callback_1(Table_Res_4 *t, void *dummy)
256 static Update_Status status = update_succeeded;
259 DP(("agent.c: _DtCm_update_callback_1()\n"));
262 * no point to save data for version 4 and before
263 * since the info from old backends does not contain
265 * so we just invoke all registered callback with no data
267 if (cbi = (_CallbackInfo *)calloc(1, sizeof(_CallbackInfo))) {
268 cbi->vers = AGENTVERS;
278 /* handle callback from backend */
279 _DtCm_handle_callback();
285 * Handler for v2 callback protocol
288 cmcb_update_callback_2_svc(cmcb_update_callback_args *args, struct svc_req *d)
292 DP(("agent.c: cmcb_update_callback_2_svc()\n"));
297 if (_ConvertCallbackData(args, &cbi) == CSA_SUCCESS) {
298 cbi->vers = AGENTVERS_2;
307 /* handle callback from backend */
308 _DtCm_handle_callback();
314 /******************************************************************************
315 * static functions used within in the file
316 ******************************************************************************/
319 * get transient program number for callbacks.
321 #if defined(SunOS) || defined(USL) || defined(__uxp__)
323 gettransient (u_long version)
326 struct nd_hostserv host = {HOST_SELF, "rpcbind"};
327 struct nd_addrlist *addrp;
330 struct netconfig *netconf;
332 netconf = getnetconfigent("udp");
334 DP(("(gettransient) getnetconfigent(udp) failed\n"));
335 freenetconfigent(netconf);
339 stat = netdir_getbyname(netconf, &host, &addrp);
341 DP(("(gettransient) netdir_getbyname failed\n"));
342 netdir_free(addrp, ND_ADDRLIST);
343 freenetconfigent(netconf);
347 if (addrp->n_cnt < 1) {
348 DP(("(gettransient) netdir_getbyname - zero addresses\n"));
349 netdir_free(addrp, ND_ADDRLIST);
350 freenetconfigent(netconf);
354 addr = addrp->n_addrs;
356 while (!rpcb_set(prognum++, version, netconf, addr))
358 netdir_free(addrp, ND_ADDRLIST);
359 freenetconfigent(netconf);
365 #else /* SunOS || USL || __uxp__ */
368 gettransient (int proto, u_long vers, int *sockp)
370 int s, len, socktype;
371 struct sockaddr_in addr;
375 socktype = SOCK_DGRAM;
378 socktype = SOCK_STREAM;
381 DP(("unknown protocol type\n"));
385 if (*sockp == RPC_ANYSOCK) {
386 if ((s = socket(AF_INET, socktype, 0)) < 0) {
394 addr.sin_addr.s_addr = 0;
395 addr.sin_family = AF_INET;
399 if (bind(s, (struct sockaddr *)&addr, len) != 0) {
404 if (getsockname(s, (struct sockaddr *)&addr, &len) < 0) {
405 perror("getsockname");
409 while (!pmap_set(prognum++, vers, proto, ntohs(addr.sin_port)))
415 #endif /* not SunOS || USL || __uxp__ */
418 _DtCm_handle_callback()
420 _CallbackInfo *ptr, *prev;
422 _DtCmCallbackEntry *cb;
423 boolean_t keep = B_FALSE;
425 DP(("agent.c: _DtCm_handle_callback()\n"));
427 for (ptr = cb_head, prev = NULL; ptr != NULL; ) {
428 /* we only handle version 1 and version 2 */
429 if (ptr->vers == AGENTVERS)
430 keep = _ProcessV1Callback(ptr);
432 keep = _ProcessV2Callback(ptr);
438 prev->next = ptr->next;
440 _FreeCallbackInfo(ptr);
450 static CSA_return_code
451 _ConvertCallbackData(cmcb_update_callback_args *args, _CallbackInfo **cbi)
454 CSA_calendar_user *user;
455 CSA_logon_callback_data *ldata;
456 CSA_calendar_deleted_callback_data *rdata;
457 CSA_calendar_attr_update_callback_data *cdata;
458 CSA_add_entry_callback_data *adata;
459 CSA_delete_entry_callback_data *ddata;
460 CSA_update_entry_callback_data *udata;
461 char timebuf[BUFSIZ];
463 if ((ncbi = (_CallbackInfo *)calloc(1, sizeof(_CallbackInfo))) == NULL)
464 return (CSA_E_INSUFFICIENT_MEMORY);
466 if (args->calendar && (ncbi->cal = strdup(args->calendar)) == NULL) {
468 return (CSA_E_INSUFFICIENT_MEMORY);
471 if (args->user && (ncbi->user = strdup(args->user)) == NULL) {
472 _FreeCallbackInfo(ncbi);
473 return (CSA_E_INSUFFICIENT_MEMORY);
476 if ((user = (CSA_calendar_user *)calloc(1, sizeof(CSA_calendar_user)))
478 _FreeCallbackInfo(ncbi);
479 return (CSA_E_INSUFFICIENT_MEMORY);
481 user->user_name = ncbi->user;
483 ncbi->reason = args->data.reason;
484 switch (ncbi->reason) {
485 case CSA_CB_CALENDAR_LOGON:
486 if ((ldata = (CSA_logon_callback_data *)calloc(1,
487 sizeof(CSA_logon_callback_data))) == NULL) {
489 _FreeCallbackInfo(ncbi);
490 return (CSA_E_INSUFFICIENT_MEMORY);
493 ncbi->data = (void *)ldata;
496 case CSA_CB_CALENDAR_DELETED:
497 if ((rdata = (CSA_calendar_deleted_callback_data *)calloc(1,
498 sizeof(CSA_calendar_deleted_callback_data))) == NULL) {
500 _FreeCallbackInfo(ncbi);
501 return (CSA_E_INSUFFICIENT_MEMORY);
504 ncbi->data = (void *)rdata;
507 case CSA_CB_CALENDAR_ATTRIBUTE_UPDATED:
508 if ((cdata = (CSA_calendar_attr_update_callback_data *)
510 CSA_calendar_attr_update_callback_data))) == NULL) {
512 _FreeCallbackInfo(ncbi);
513 return (CSA_E_INSUFFICIENT_MEMORY);
516 ncbi->data = (void *)cdata;
518 if (_CopyAttributeNames(args->data.data.cdata->num_names,
519 args->data.data.cdata->names, &cdata->number_attributes,
520 &cdata->attribute_names)) {
521 _FreeCallbackInfo(ncbi);
522 return (CSA_E_INSUFFICIENT_MEMORY);
527 case CSA_CB_ENTRY_ADDED:
528 if ((adata = (CSA_add_entry_callback_data *)calloc(1,
529 sizeof(CSA_add_entry_callback_data))) == NULL) {
531 _FreeCallbackInfo(ncbi);
532 return (CSA_E_INSUFFICIENT_MEMORY);
535 ncbi->data = (void *)adata;
537 if (args->data.data.adata->id && (adata->added_entry_id.data =
538 (unsigned char *)strdup(args->data.data.adata->id))
540 _FreeCallbackInfo(ncbi);
541 return (CSA_E_INSUFFICIENT_MEMORY);
543 adata->added_entry_id.size =
544 strlen((char *)adata->added_entry_id.data);
548 case CSA_CB_ENTRY_DELETED:
549 if ((ddata = (CSA_delete_entry_callback_data *)calloc(1,
550 sizeof(CSA_delete_entry_callback_data))) == NULL) {
552 _FreeCallbackInfo(ncbi);
553 return (CSA_E_INSUFFICIENT_MEMORY);
556 ncbi->data = (void *)ddata;
558 if (args->data.data.ddata->id && (ddata->deleted_entry_id.data =
559 (unsigned char *)strdup(args->data.data.ddata->id))
561 _FreeCallbackInfo(ncbi);
562 return (CSA_E_INSUFFICIENT_MEMORY);
564 ddata->deleted_entry_id.size =
565 strlen((char *)ddata->deleted_entry_id.data);
567 _csa_tick_to_iso8601(args->data.data.ddata->time, timebuf);
568 if ((ddata->date_and_time = strdup(timebuf)) == NULL) {
569 _FreeCallbackInfo(ncbi);
570 return (CSA_E_INSUFFICIENT_MEMORY);
573 ddata->scope = args->data.data.ddata->scope;
576 case CSA_CB_ENTRY_UPDATED:
577 if ((udata = (CSA_update_entry_callback_data *)calloc(1,
578 sizeof(CSA_update_entry_callback_data))) == NULL) {
580 _FreeCallbackInfo(ncbi);
581 return (CSA_E_INSUFFICIENT_MEMORY);
584 ncbi->data = (void *)udata;
586 if (args->data.data.udata->newid && (udata->new_entry_id.data =
587 (unsigned char *)strdup(args->data.data.udata->newid))
589 _FreeCallbackInfo(ncbi);
590 return (CSA_E_INSUFFICIENT_MEMORY);
592 udata->new_entry_id.size =
593 strlen((char *)udata->new_entry_id.data);
595 if (args->data.data.udata->oldid && (udata->old_entry_id.data =
596 (unsigned char *)strdup(args->data.data.udata->oldid))
598 _FreeCallbackInfo(ncbi);
599 return (CSA_E_INSUFFICIENT_MEMORY);
601 udata->old_entry_id.size =
602 strlen((char *)udata->old_entry_id.data);
604 _csa_tick_to_iso8601(args->data.data.udata->time, timebuf);
605 if ((udata->date_and_time = strdup(timebuf)) == NULL) {
606 _FreeCallbackInfo(ncbi);
607 return (CSA_E_INSUFFICIENT_MEMORY);
610 udata->scope = args->data.data.udata->scope;
615 return (CSA_SUCCESS);
618 static CSA_return_code
619 _CopyAttributeNames(uint fnum, char **fnames, CSA_uint32 *tnum, char ***tnames)
627 return (CSA_SUCCESS);
630 if ((nnames = calloc(1, sizeof(char *) * fnum)) == NULL)
631 return (CSA_E_INSUFFICIENT_MEMORY);
633 for (i = 0; i < fnum; i++) {
634 if ((nnames[i] = strdup(fnames[i])) == NULL)
641 return (CSA_SUCCESS);
643 _DtCm_free_character_pointers(i, nnames);
645 return (CSA_E_INSUFFICIENT_MEMORY);
650 * pre callback protocol V2, there is no distinction
651 * between different reasons, and no data passed. So
652 * there's only one possible thing to do, and that's
653 * run all the callbacks.
656 _ProcessV1Callback(_CallbackInfo *ptr)
659 _DtCmCallbackEntry *cb;
660 boolean_t keep = B_FALSE;
662 for (cal = _DtCm_active_cal_list; cal != NULL; cal = cal->next) {
663 if (cal->rpc_version >= _DtCM_FIRST_EXTENSIBLE_SERVER_VERSION)
666 if (cal->do_reasons &
667 (CSA_CB_ENTRY_ADDED | CSA_CB_ENTRY_DELETED |
668 CSA_CB_ENTRY_UPDATED))
670 /* only do dumb processing if it was a V4 server */
671 for (cb = cal->cb_list; cb != NULL; cb = cb->next) {
672 if (cal->do_reasons & cb->reason) {
673 cb->handler((CSA_session_handle)cal,
674 cal->do_reasons & cb->reason,
677 (CSA_extension*) NULL);
680 } else if (cal->all_reasons & (CSA_CB_ENTRY_ADDED |
681 CSA_CB_ENTRY_DELETED | CSA_CB_ENTRY_UPDATED))
689 _ProcessV2Callback(_CallbackInfo *ptr)
692 _DtCmCallbackEntry *cb;
693 boolean_t keep = B_FALSE;
695 for (cal = _DtCm_active_cal_list; cal != NULL; cal = cal->next) {
696 if (cal->rpc_version < _DtCM_FIRST_EXTENSIBLE_SERVER_VERSION ||
697 strcmp(ptr->cal, cal->name))
700 if (cal->do_reasons & ptr->reason) {
702 /* only do dumb processing if it was a V4 server */
703 for (cb = cal->cb_list; cb != NULL; cb = cb->next) {
704 if (ptr->reason & cb->reason) {
705 cb->handler((CSA_session_handle)cal,
707 (CSA_buffer)ptr->data,
709 (CSA_extension*) NULL);
712 } else if (cal->all_reasons & ptr->reason)
720 _FreeCallbackInfo(_CallbackInfo *ptr)
722 CSA_logon_callback_data *ldata;
723 CSA_calendar_deleted_callback_data *rdata;
724 CSA_calendar_attr_update_callback_data *cdata;
725 CSA_add_entry_callback_data *adata;
726 CSA_delete_entry_callback_data *ddata;
727 CSA_update_entry_callback_data *udata;
730 if (ptr->cal) free(ptr->cal);
731 if (ptr->user) free(ptr->user);
733 if (ptr->data) switch (ptr->reason) {
734 case CSA_CB_CALENDAR_LOGON:
736 if (ldata->user) free(ldata->user);
739 case CSA_CB_CALENDAR_DELETED:
741 if (rdata->user) free(rdata->user);
744 case CSA_CB_CALENDAR_ATTRIBUTE_UPDATED:
745 cdata = (CSA_calendar_attr_update_callback_data *)
747 if (cdata->user) free(cdata->user);
748 if (cdata->number_attributes > 0)
749 _DtCm_free_character_pointers(
750 cdata->number_attributes,
751 cdata->attribute_names);
754 case CSA_CB_ENTRY_ADDED:
755 adata = (CSA_add_entry_callback_data *)ptr->data;
756 if (adata->user) free(adata->user);
757 if (adata->added_entry_id.data)
758 free(adata->added_entry_id.data);
761 case CSA_CB_ENTRY_DELETED:
762 ddata = (CSA_delete_entry_callback_data *)ptr->data;
763 if (ddata->date_and_time) free(ddata->date_and_time);
764 if (ddata->user) free(ddata->user);
765 if (ddata->deleted_entry_id.data)
766 free(ddata->deleted_entry_id.data);
769 case CSA_CB_ENTRY_UPDATED:
770 udata = (CSA_update_entry_callback_data *)ptr->data;
771 if (udata->user) free(udata->user);
772 if (udata->date_and_time) free(udata->date_and_time);
773 if (udata->old_entry_id.data)
774 free(udata->old_entry_id.data);
775 if (udata->new_entry_id.data)
776 free(udata->new_entry_id.data);