dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / isns / isnsd / esi.c
blob76c8e806ae3da9b5be8dc995c05d4d1b5495d37c
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <unistd.h>
31 #include <sys/types.h>
32 #include <time.h>
33 #include <signal.h>
34 #include <poll.h>
36 #include "isns_server.h"
37 #include "isns_cache.h"
38 #include "isns_obj.h"
39 #include "isns_pdu.h"
40 #include "isns_func.h"
41 #include "isns_qry.h"
42 #include "isns_msgq.h"
43 #include "isns_log.h"
44 #include "isns_sched.h"
45 #include "isns_scn.h"
46 #include "isns_esi.h"
49 * global variables.
53 * local variables.
55 static ev_t *ev_list = NULL;
57 static uint32_t stopwatch = 0;
58 static pthread_mutex_t stw_mtx = PTHREAD_MUTEX_INITIALIZER;
60 static int wakeup = 0;
61 static pthread_mutex_t idl_mtx = PTHREAD_MUTEX_INITIALIZER;
62 static pthread_cond_t idl_cond = PTHREAD_COND_INITIALIZER;
65 * external variables.
67 extern const int UID_ATTR_INDEX[MAX_OBJ_TYPE_FOR_SIZE];
69 extern boolean_t time_to_exit;
71 extern msg_queue_t *sys_q;
73 extern uint64_t esi_threshold;
75 #ifdef DEBUG
76 extern void dump_pdu1(isns_pdu_t *);
77 #endif
80 * local functions.
82 static void *esi_monitor(void *);
85 * ****************************************************************************
87 * new_esi_portal:
88 * Make a new portal for ESI event.
90 * uid - the portal object UID.
91 * ip6 - the portal IPv6 format IP address.
92 * port - the portal port.
93 * esip - the ESI port.
94 * return - the new ESI portal.
96 * ****************************************************************************
98 static esi_portal_t *
99 new_esi_portal(
100 uint32_t uid,
101 in6_addr_t *ip6,
102 uint32_t port,
103 uint32_t esip
106 esi_portal_t *p;
108 p = (esi_portal_t *)malloc(sizeof (esi_portal_t));
109 if (p != NULL) {
110 if (((int *)ip6)[0] == 0x00 &&
111 ((int *)ip6)[1] == 0x00 &&
112 ((uchar_t *)ip6)[8] == 0x00 &&
113 ((uchar_t *)ip6)[9] == 0x00 &&
114 ((uchar_t *)ip6)[10] == 0xFF &&
115 ((uchar_t *)ip6)[11] == 0xFF) {
116 p->sz = sizeof (in_addr_t);
117 p->ip4 = ((uint32_t *)ip6)[3];
118 } else {
119 p->sz = sizeof (in6_addr_t);
121 p->ip6 = ip6;
122 p->port = port;
123 p->esip = esip;
124 p->ref = uid;
125 p->so = 0;
126 p->next = NULL;
129 return (p);
133 * ****************************************************************************
135 * free_esi_portal:
136 * Free a list of portal of one ESI event.
138 * p - the ESI portal.
140 * ****************************************************************************
142 static void
143 free_esi_portal(
144 esi_portal_t *p
147 esi_portal_t *n;
149 while (p != NULL) {
150 n = p->next;
151 free(p->ip6);
152 free(p);
153 p = n;
158 * ****************************************************************************
160 * ev_new:
161 * Make a new ESI event.
163 * uid - the Entity object UID.
164 * eid - the Entity object name.
165 * len - the length of the name.
166 * return - the ESI event.
168 * ****************************************************************************
170 static ev_t *
171 ev_new(
172 uint32_t uid,
173 uchar_t *eid,
174 uint32_t len
177 ev_t *ev;
179 ev = (ev_t *)malloc(sizeof (ev_t));
180 if (ev != NULL) {
181 if (pthread_mutex_init(&ev->mtx, NULL) != 0 ||
182 (ev->eid = (uchar_t *)malloc(len)) == NULL) {
183 free(ev);
184 return (NULL);
186 ev->uid = uid;
187 (void) strcpy((char *)ev->eid, (char *)eid);
188 ev->eid_len = len;
189 /* initialization time */
190 ev->flags = EV_FLAG_INIT;
193 return (ev);
197 * ****************************************************************************
199 * cb_portal_uids:
200 * Callback function which makes a copy of the portal child object
201 * UIDs from a Network Entity object.
203 * p1 - the Network Entity object.
204 * p2 - the lookup control data.
205 * return - the number of portal object UIDs.
207 * ****************************************************************************
209 static int
210 cb_portal_uids(
211 void *p1,
212 void *p2
215 isns_obj_t *obj = (isns_obj_t *)p1;
216 lookup_ctrl_t *lcp = (lookup_ctrl_t *)p2;
218 isns_attr_t *attr;
220 uint32_t *cuidp;
222 uint32_t num = 0;
223 uint32_t *p = NULL;
225 cuidp = get_child_t(obj, OBJ_PORTAL);
226 if (cuidp != NULL) {
227 p = (uint32_t *)malloc(*cuidp * sizeof (*p));
228 if (p != NULL) {
229 num = *cuidp ++;
230 (void) memcpy(p, cuidp, num * sizeof (*p));
231 lcp->data[1].ptr = (uchar_t *)p;
235 attr = &obj->attrs[ATTR_INDEX_ENTITY(ISNS_ENTITY_REG_PERIOD_ATTR_ID)];
236 if (attr->tag != 0 && attr->value.ui != 0) {
237 lcp->data[2].ui = attr->value.ui;
238 } else {
239 /* just one second before the end of the world */
240 lcp->data[2].ui = INFINITY - 1;
243 return (num);
247 * ****************************************************************************
249 * cb_esi_portal:
250 * Callback function which gets ESI port number and ESI interval
251 * from a portal object.
253 * p1 - the Portal object.
254 * p2 - the lookup control data.
255 * return - the ESI interval.
257 * ****************************************************************************
259 static int
260 cb_esi_portal(
261 void *p1,
262 void *p2
265 uint32_t intval = 0;
267 isns_obj_t *obj;
268 lookup_ctrl_t *lcp;
270 in6_addr_t *ip;
271 uint32_t esip;
273 isns_attr_t *attr;
275 if (cb_clone_attrs(p1, p2) == 0) {
276 obj = (isns_obj_t *)p1;
277 lcp = (lookup_ctrl_t *)p2;
278 ip = lcp->data[1].ip;
279 esip = lcp->data[2].ui;
280 if (esip != 0) {
281 attr = &obj->attrs[ATTR_INDEX_PORTAL(
282 ISNS_PORTAL_PORT_ATTR_ID)];
283 lcp->data[0].ui = attr->value.ui;
284 attr = &obj->attrs[ATTR_INDEX_PORTAL(
285 ISNS_ESI_INTERVAL_ATTR_ID)];
286 if (attr->tag != 0 && attr->value.ui != 0) {
287 intval = attr->value.ui;
288 } else {
289 intval = DEFAULT_ESI_INTVAL;
291 } else {
292 free(ip);
296 return ((int)intval);
300 * ****************************************************************************
302 * extract_esi_portal:
303 * Extract a list of portal which have an ESI port for an Entity.
305 * uid - the Entity object UID.
306 * intval - the ESI interval for returnning.
307 * return - the list of portals.
309 * ****************************************************************************
311 static esi_portal_t *
312 extract_esi_portal(
313 uint32_t uid,
314 uint32_t *intval
317 esi_portal_t *list = NULL;
318 esi_portal_t *p;
320 lookup_ctrl_t lc;
322 uint32_t num_of_portal;
323 uint32_t *portal_uids;
325 uint32_t intv;
327 /* prepare for looking up entity object */
328 SET_UID_LCP(&lc, OBJ_ENTITY, uid);
329 lc.data[1].ptr = NULL;
330 lc.data[2].ui = INFINITY - 1;
332 /* get the array of the portal uid(s) */
333 num_of_portal = (uint32_t)cache_lookup(&lc, NULL, cb_portal_uids);
334 portal_uids = (uint32_t *)lc.data[1].ptr;
335 *intval = lc.data[2].ui;
337 /* prepare for looking up portal object(s) */
338 SET_UID_LCP(&lc, OBJ_PORTAL, 0);
339 lc.id[1] = ISNS_PORTAL_IP_ADDR_ATTR_ID;
340 lc.id[2] = ISNS_ESI_PORT_ATTR_ID;
341 FOR_EACH_OBJS(portal_uids, num_of_portal, uid, {
342 if (uid != 0) {
343 lc.data[0].ui = uid;
344 intv = cache_lookup(&lc, NULL, cb_esi_portal);
345 if (intv != 0) {
346 p = new_esi_portal(uid,
347 (in6_addr_t *)lc.data[1].ip,
348 lc.data[0].ui, lc.data[2].ui);
349 if (p != NULL) {
350 p->next = list;
351 list = p;
352 if (*intval > intv) {
353 *intval = intv;
360 /* free up the portal uid array */
361 free(portal_uids);
363 return (list);
367 * ****************************************************************************
369 * ev_add:
370 * Add an ESI event.
372 * ev - the ESI event.
373 * init - 0: initialization time, otherwise not.
374 * return - error code.
376 * ****************************************************************************
378 static int
379 ev_add(
380 ev_t *ev,
381 int init
384 uint32_t intval;
385 esi_portal_t *p;
387 double rnd;
388 uint32_t t = 0;
390 /* get the portal(s) which are registered for ESI monitoring */
391 /* and the second interval for ESI or registration expiration */
392 p = extract_esi_portal(ev->uid, &intval);
393 ev->intval = intval;
394 if (p != NULL) {
395 ev->type = EV_ESI;
396 ev->portal = p;
397 /* avoid running everything at the same time */
398 if (init != 0) {
399 /* generate random number within range (0, 1] */
400 rnd = (rand() + 1) / (double)(RAND_MAX + 1);
401 t = (uint32_t)(intval * rnd);
403 } else {
404 /* no portal is registered for ESI monitoring, make */
405 /* an entry for entity registration expiration */
406 ev->type = EV_REG_EXP;
407 ev->portal = NULL;
408 if (init != 0) {
409 t = intval;
413 /* schedule the event */
414 return (el_add(ev, t, NULL));
418 * global functions.
422 * ****************************************************************************
424 * sigalrm:
425 * The signal handler for SIGALRM, the ESI proc uses the SIGALRM
426 * for waking up to perform the client status inquery.
428 * sig - the signal.
430 * ****************************************************************************
432 /*ARGSUSED*/
433 void
434 sigalrm(
435 int sig
438 /* wake up the idle */
439 (void) pthread_mutex_lock(&idl_mtx);
440 wakeup = 1; /* wake up naturally */
441 (void) pthread_cond_signal(&idl_cond);
442 (void) pthread_mutex_unlock(&idl_mtx);
446 * ****************************************************************************
448 * esi_load:
449 * Load an ESI event from data store.
451 * uid - the Entity object UID.
452 * eid - the Entity object name.
453 * len - the length of the name.
454 * return - error code.
456 * ****************************************************************************
459 esi_load(
460 uint32_t uid,
461 uchar_t *eid,
462 uint32_t len
465 int ec = 0;
467 /* make a new event */
468 ev_t *ev = ev_new(uid, eid, len);
470 /* put the new event to the list */
471 if (ev != NULL) {
472 ev->next = ev_list;
473 ev_list = ev;
474 } else {
475 ec = ISNS_RSP_INTERNAL_ERROR;
478 return (ec);
482 * ****************************************************************************
484 * verify_esi_portal:
485 * Verify ESI port and add the ESI entries after the ESI are loaded.
487 * return - error code.
489 * ****************************************************************************
492 verify_esi_portal(
495 int ec = 0;
497 ev_t *ev;
499 /* add each event from the list */
500 while (ev_list != NULL && ec == 0) {
501 ev = ev_list;
502 ev_list = ev->next;
503 ev->next = NULL;
504 ec = ev_add(ev, 1);
507 return (ec);
511 * ****************************************************************************
513 * esi_add:
514 * Add a new ESI event when a new Entity is registered.
516 * uid - the Entity object UID.
517 * eid - the Entity object name.
518 * len - the length of the name.
519 * return - error code.
521 * ****************************************************************************
524 esi_add(
525 uint32_t uid,
526 uchar_t *eid,
527 uint32_t len
530 int ec = 0;
532 /* make a new event */
533 ev_t *ev = ev_new(uid, eid, len);
535 if (ev != NULL) {
536 /* interrupt idle */
537 ev->flags |= EV_FLAG_WAKEUP;
538 ec = ev_add(ev, 0);
539 } else {
540 ec = ISNS_RSP_INTERNAL_ERROR;
543 return (ec);
547 * ****************************************************************************
549 * esi_remove:
550 * Remove an ESI event immediately.
552 * uid - the Entity object UID.
553 * return - always successful.
555 * ****************************************************************************
558 esi_remove(
559 uint32_t uid
562 (void) el_remove(uid, 0, 0);
564 return (0);
568 * ****************************************************************************
570 * esi_remove_obj:
571 * Update an ESI event when a Entity object or a Portal object is
572 * removed from server. If the object is being removed because of
573 * ESI failure, the ESI event will be removed with a pending time,
574 * otherwise, the ESI will be removed immediately.
576 * obj - the object being removed.
577 * pending - the pending flag.
578 * return - always successful.
580 * ****************************************************************************
583 esi_remove_obj(
584 const isns_obj_t *obj,
585 int pending
588 uint32_t puid, uid;
590 switch (obj->type) {
591 case OBJ_PORTAL:
592 puid = get_parent_uid(obj);
593 uid = get_obj_uid(obj);
594 break;
595 case OBJ_ENTITY:
596 puid = get_obj_uid(obj);
597 uid = 0;
598 break;
599 default:
600 puid = 0;
601 break;
604 if (puid != 0) {
605 (void) el_remove(puid, uid, pending);
608 return (0);
612 * ****************************************************************************
614 * get_stopwatch:
615 * Get the stopwatch. It might need to signal the condition to
616 * wake up the idle so the stopwatch gets updated.
618 * flag - wake up flag.
619 * return - the stopwatch.
621 * ****************************************************************************
623 uint32_t
624 get_stopwatch(
625 int flag
628 uint32_t t;
630 /* not re-schedule, wake up idle */
631 (void) pthread_mutex_lock(&idl_mtx);
632 if (flag != 0) {
633 wakeup = 2; /* wake up manually */
634 (void) pthread_cond_signal(&idl_cond);
635 } else {
636 wakeup = 0; /* clear previous interruption */
638 (void) pthread_mutex_unlock(&idl_mtx);
640 /* get most current time */
641 (void) pthread_mutex_lock(&stw_mtx);
642 t = stopwatch;
643 (void) pthread_mutex_unlock(&stw_mtx);
645 return (t);
649 * ****************************************************************************
651 * ev_intval:
652 * Get the time interval of an ESI event.
654 * p - the ESI event.
655 * return - the time interval.
657 * ****************************************************************************
659 uint32_t
660 ev_intval(
661 void *p
664 return (((ev_t *)p)->intval);
668 * ****************************************************************************
670 * ev_match:
671 * Check the ESI event maching an Entity object.
673 * p - the ESI event.
674 * uid - the Entity object UID.
675 * return - 1: match, otherwise not.
677 * ****************************************************************************
680 ev_match(
681 void *p,
682 uint32_t uid
685 if (((ev_t *)p)->uid == uid) {
686 return (1);
687 } else {
688 return (0);
693 * ****************************************************************************
695 * ev_remove:
696 * Remove a portal or an ESI event. If all of ESI portal has been
697 * removed, the ESI event will be marked as removal pending, which
698 * will result in removing the Entity object after the pending time.
700 * p - the ESI event.
701 * portal_uid - the Portal object UID.
702 * flag - 0: the ESI is currently in use, otherwise it is scheduled.
703 * pending - flag for the ESI removal pending.
704 * return - 0: the ESI is physically removed, otherwise not.
706 * ****************************************************************************
709 ev_remove(
710 void *p,
711 uint32_t portal_uid,
712 int flag,
713 int pending
716 ev_t *ev = (ev_t *)p;
717 esi_portal_t **pp, *portal;
719 int has_portal = 0;
720 int state;
722 /* remove one portal only */
723 if (portal_uid != 0) {
724 pp = &ev->portal;
725 portal = *pp;
726 while (portal != NULL) {
727 /* found the match portal */
728 if (portal->ref == portal_uid) {
729 /* mark it as removed */
730 portal->ref = 0;
731 if (flag != 0) {
732 /* not in use, remove it physically */
733 *pp = portal->next;
734 portal->next = NULL;
735 free_esi_portal(portal);
736 } else {
737 pp = &portal->next;
739 } else {
740 /* one or more esi portals are available */
741 if (portal->ref != 0) {
742 has_portal = 1;
744 pp = &portal->next;
746 portal = *pp;
750 /* no portal available */
751 if (has_portal == 0) {
752 state = (pending << 1) | flag;
753 switch (state) {
754 case 0x0:
755 /* mark the event as removed */
756 ev->flags |= EV_FLAG_REMOVE;
757 isnslog(LOG_DEBUG, "ev_remove",
758 "%s [%d] is marked as removed.",
759 ev->type == EV_ESI ? "ESI" : "REG_EXP",
760 ev->uid);
761 break;
762 case 0x1:
763 /* physically remove the event */
764 ev_free(ev);
765 break;
766 case 0x2:
767 case 0x3:
768 /* mark the event as removal pending */
769 isnslog(LOG_DEBUG, "ev_remove",
770 "%s [%d] is marked as removal pending.",
771 ev->type == EV_ESI ? "ESI" : "REG_EXP",
772 ev->uid);
773 ev->flags |= EV_FLAG_REM_P1;
774 has_portal = 1;
775 break;
776 default:
777 break;
779 } else {
780 isnslog(LOG_DEBUG, "ev_remove", "%s [%d] removed portal %d.",
781 ev->type == EV_ESI ? "ESI" : "REG_EXP",
782 ev->uid, portal_uid);
785 return (has_portal);
789 * ****************************************************************************
791 * ev_free:
792 * Free an ESI event.
794 * p - the ESI event.
796 * ****************************************************************************
798 void
799 ev_free(
800 void *p
803 ev_t *ev = (ev_t *)p;
805 /* free up all of portals */
806 free_esi_portal(ev->portal);
808 isnslog(LOG_DEBUG, "ev_free",
809 "%s [%d] is physically removed.",
810 ev->type == EV_ESI ? "ESI" : "REG_EXP",
811 ev->uid);
813 free(ev->eid);
815 /* free the event */
816 free(ev);
820 * ****************************************************************************
822 * evf_init:
823 * Check the initial flag of an ESI event.
825 * p - the ESI event.
826 * return - 0: not initial, otherwise yes.
828 * ****************************************************************************
831 evf_init(
832 void *p
835 return (((ev_t *)p)->flags & EV_FLAG_INIT);
839 * ****************************************************************************
841 * evf_again:
842 * Check the again flag of an ESI event.
843 * (this flag might be eliminated and use the init flag.)
845 * p - the ESI event.
846 * return - 0: not again, otherwise yes.
848 * ****************************************************************************
851 evf_again(
852 void *p
855 return (((ev_t *)p)->flags & EV_FLAG_AGAIN);
859 * ****************************************************************************
861 * evf_wakeup:
862 * Check the wakeup flag of an ESI event. The idle might need to
863 * wake up before the event is scheduled.
865 * p - the ESI event.
866 * return - 0: no wakeup, otherwise yes.
868 * ****************************************************************************
871 evf_wakeup(
872 void *p
875 return (((ev_t *)p)->flags & EV_FLAG_WAKEUP);
879 * ****************************************************************************
881 * evf_rem:
882 * Check the removal flag of an ESI event. The ESI entry might be
883 * marked as removal.
885 * p - the ESI event.
886 * return - 0: not removed, otherwise yes.
888 * ****************************************************************************
891 evf_rem(
892 void *p
895 return (((ev_t *)p)->flags & EV_FLAG_REMOVE);
899 * ****************************************************************************
901 * evf_rem_pending:
902 * Check the removal pending flag of an ESI event. The ESI entry
903 * might be marked as removal pending. If it is, we will switch the
904 * event type and change the time interval.
906 * p - the ESI event.
907 * return - 0: not removal pending, otherwise yes.
909 * ****************************************************************************
912 evf_rem_pending(
913 void *p
916 ev_t *ev = (ev_t *)p;
917 if ((ev->flags & EV_FLAG_REM_P) != 0) {
918 if (ev->type != EV_REG_EXP) {
919 isnslog(LOG_DEBUG, "ev_rem_pending",
920 "%s [%d] is changed to REG_EXP.",
921 ev->type == EV_ESI ? "ESI" : "REG_EXP",
922 ev->uid);
923 ev->type = EV_REG_EXP;
924 ev->intval *= 2; /* after 2 ESI interval */
926 return (1);
929 return (0);
933 * ****************************************************************************
935 * evf_zero:
936 * Reset the event flag.
938 * p - the ESI event.
940 * ****************************************************************************
942 void
943 evf_zero(
944 void *p
947 ev_t *ev = (ev_t *)p;
949 /* not acutally clear it, need to set again flag */
950 /* and keep the removal pending flag */
951 ev->flags = EV_FLAG_AGAIN | (ev->flags & EV_FLAG_REM_P);
955 * ****************************************************************************
957 * evl_append:
958 * Append an ESI event to the list, the list contains all of
959 * ESI events which are being processed at present.
961 * p - the ESI event.
963 * ****************************************************************************
965 void
966 evl_append(
967 void *p
970 ev_t *ev;
972 ev = (ev_t *)p;
973 ev->next = ev_list;
974 ev_list = ev;
978 * ****************************************************************************
980 * evl_strip:
981 * Strip off an ESI event from the list after the event is being
982 * processed, it will be scheduled in the scheduler.
984 * p - the ESI event.
986 * ****************************************************************************
988 void
989 evl_strip(
990 void *p
993 ev_t **evp = &ev_list;
994 ev_t *ev = *evp;
996 while (ev != NULL) {
997 if (ev == p) {
998 *evp = ev->next;
999 break;
1001 evp = &ev->next;
1002 ev = *evp;
1007 * ****************************************************************************
1009 * evl_remove:
1010 * Remove an ESI event or a portal of an ESI event from the event list.
1012 * id1 - the Entity object UID.
1013 * id2 - the Portal object UID.
1014 * pending - the pending flag.
1015 * return - 1: found a match event, otherwise not.
1017 * ****************************************************************************
1020 evl_remove(
1021 uint32_t id1,
1022 uint32_t id2,
1023 int pending
1026 ev_t *ev = ev_list;
1028 while (ev != NULL) {
1029 /* found it */
1030 if (ev_match(ev, id1) != 0) {
1031 /* lock the event */
1032 (void) pthread_mutex_lock(&ev->mtx);
1033 /* mark it as removed */
1034 (void) ev_remove(ev, id2, 0, pending);
1035 /* unlock the event */
1036 (void) pthread_mutex_unlock(&ev->mtx);
1037 /* tell caller removal is done */
1038 return (1);
1040 ev = ev->next;
1043 /* not found it */
1044 return (0);
1047 #define ALARM_MAX (21427200)
1050 * ****************************************************************************
1052 * idle:
1053 * Idle for certain amount of time or a wakeup signal is recieved.
1055 * t - the idle time.
1056 * return - the time that idle left.
1058 * ****************************************************************************
1060 static int
1061 idle(
1062 uint32_t t
1065 uint32_t t1, t2, t3 = 0;
1066 int idl_int = 0;
1068 /* hold the mutex for stopwatch update */
1069 (void) pthread_mutex_lock(&stw_mtx);
1071 do {
1072 if (t > ALARM_MAX) {
1073 t1 = ALARM_MAX;
1074 } else {
1075 t1 = t;
1078 /* start alarm */
1079 (void) alarm(t1);
1081 /* hold the mutex for idle condition */
1082 (void) pthread_mutex_lock(&idl_mtx);
1084 /* wait on condition variable to wake up idle */
1085 while (wakeup == 0) {
1086 (void) pthread_cond_wait(&idl_cond, &idl_mtx);
1088 if (wakeup == 2) {
1089 idl_int = 1;
1091 /* clean wakeup flag */
1092 wakeup = 0;
1094 /* release the mutex for idle condition */
1095 (void) pthread_mutex_unlock(&idl_mtx);
1097 /* stop alarm */
1098 t2 = alarm(0);
1100 /* seconds actually slept */
1101 t3 += t1 - t2;
1102 t -= t3;
1103 } while (t > 0 && idl_int == 0);
1105 /* increate the stopwatch by the actually slept time */
1106 stopwatch += t3;
1108 /* release the mutex after stopwatch is updated */
1109 (void) pthread_mutex_unlock(&stw_mtx);
1111 /* return the amount of time which is not slept */
1112 return (t);
1116 * ****************************************************************************
1118 * ev_ex:
1119 * Execute an event. To inquiry the client status or
1120 * perform registration expiration.
1122 * ev - the event.
1124 * ****************************************************************************
1126 static void
1127 ev_ex(
1128 ev_t *ev
1131 pthread_t tid;
1133 switch (ev->type) {
1134 case EV_ESI:
1135 if (pthread_create(&tid, NULL,
1136 esi_monitor, (void *)ev) != 0) {
1137 isnslog(LOG_DEBUG, "ev_ex", "pthread_create() failed.");
1138 /* reschedule for next occurence */
1139 (void) el_add(ev, 0, NULL);
1140 } else {
1141 /* increase the thread ref count */
1142 inc_thr_count();
1144 break;
1145 case EV_REG_EXP:
1146 (void) queue_msg_set(sys_q, REG_EXP, (void *)ev);
1147 break;
1148 default:
1149 break;
1154 * ****************************************************************************
1156 * esi_proc:
1157 * ESI thread entry, which:
1158 * 1: fetch an event from schedule,
1159 * 2: idle for some time,
1160 * 3: execute the event or re-schedule it,
1161 * 4: repeat from step 1 before server is being shutdown.
1163 * arg - the thread argument.
1165 * ****************************************************************************
1167 /*ARGSUSED*/
1168 void *
1169 esi_proc(
1170 void *arg
1173 uint32_t t, t1, pt;
1174 ev_t *ev;
1176 void *evp;
1178 while (time_to_exit == B_FALSE) {
1179 ev = (ev_t *)el_first(&pt);
1181 /* caculate the idle time */
1182 if (ev != NULL) {
1183 if (pt > stopwatch) {
1184 t = pt - stopwatch;
1185 } else {
1186 t = 0;
1188 } else {
1189 t = INFINITY;
1192 do {
1193 /* block for a certain amount of time */
1194 if (t > 0) {
1195 isnslog(LOG_DEBUG, "esi_proc",
1196 "idle for %d seconds.", t);
1197 t1 = idle(t);
1198 } else {
1199 t1 = 0;
1201 if (t1 > 0) {
1202 isnslog(LOG_DEBUG, "esi_proc",
1203 "idle interrupted after idle for "
1204 "%d seconds.", t - t1);
1206 if (time_to_exit != B_FALSE) {
1207 ev = NULL; /* force break */
1208 } else if (ev != NULL) {
1209 if (t1 > 0) {
1210 /* not naturally waken up */
1211 /* reschedule current event */
1212 evp = NULL;
1213 (void) el_add(ev, pt, &evp);
1214 ev = (ev_t *)evp;
1215 t = t1;
1216 } else {
1217 /* excute */
1218 isnslog(LOG_DEBUG, "esi_proc",
1219 "excute the cron job[%d].",
1220 ev->uid);
1221 ev_ex(ev);
1222 ev = NULL;
1225 } while (ev != NULL);
1228 return (NULL);
1232 * ****************************************************************************
1234 * esi_ping:
1235 * Ping the client with the ESI retry threshold for status inquiry.
1237 * so - the socket descriptor.
1238 * pdu - the ESI packet.
1239 * pl - the length of packet.
1240 * return - 1: status inquired, otherwise not.
1242 * ****************************************************************************
1244 static int
1245 esi_ping(
1246 int so,
1247 isns_pdu_t *pdu,
1248 size_t pl
1251 int try_cnt = 0;
1252 isns_pdu_t *rsp = NULL;
1253 size_t rsp_sz;
1255 int alive = 0;
1257 do {
1258 if (isns_send_pdu(so, pdu, pl) == 0) {
1259 if (isns_rcv_pdu(so, &rsp, &rsp_sz,
1260 ISNS_RCV_SHORT_TIMEOUT) > 0) {
1261 #ifdef DEBUG
1262 dump_pdu1(rsp);
1263 #endif
1264 alive = 1;
1265 break;
1267 } else {
1268 /* retry after 1 second */
1269 (void) sleep(1);
1271 try_cnt ++;
1272 } while (try_cnt < esi_threshold);
1274 if (rsp != NULL) {
1275 free(rsp);
1278 return (alive);
1282 * ****************************************************************************
1284 * esi_monitor:
1285 * Child thread for client status mornitoring.
1287 * arg - the ESI event.
1289 * ****************************************************************************
1291 static void *
1292 esi_monitor(
1293 void *arg
1296 ev_t *ev = (ev_t *)arg;
1298 esi_portal_t *p;
1299 int so;
1301 isns_pdu_t *pdu = NULL;
1302 size_t sz;
1303 size_t pl;
1304 size_t half;
1306 time_t t;
1308 int feedback;
1310 /* lock the event for esi monitoring */
1311 (void) pthread_mutex_lock(&ev->mtx);
1313 if (evf_rem(ev) != 0) {
1314 goto mon_done;
1315 } else if (evf_rem_pending(ev) != 0) {
1316 goto mon_done;
1319 /* timestamp */
1320 t = time(NULL);
1322 /* allocate ESI PDU */
1323 if (pdu_reset_esi(&pdu, &pl, &sz) != 0 ||
1324 pdu_add_tlv(&pdu, &pl, &sz,
1325 ISNS_TIMESTAMP_ATTR_ID, 8, (void *)&t, 1) != 0 ||
1326 pdu_add_tlv(&pdu, &pl, &sz,
1327 ISNS_EID_ATTR_ID, ev->eid_len, (void *)ev->eid, 0) != 0) {
1328 /* no memory, will retry later */
1329 goto mon_done;
1332 /* set pdu head */
1333 pdu->version = htons((uint16_t)ISNSP_VERSION);
1334 pdu->func_id = htons((uint16_t)ISNS_ESI);
1335 pdu->xid = htons(get_server_xid());
1337 /* keep the current lenght of the playload */
1338 half = pl;
1340 p = ev->portal;
1341 while (p != NULL) {
1342 if (p->ref != 0 &&
1343 /* skip IPv6 portal */
1344 p->sz != sizeof (in6_addr_t) &&
1345 pdu_add_tlv(&pdu, &pl, &sz,
1346 ISNS_PORTAL_IP_ADDR_ATTR_ID,
1347 sizeof (in6_addr_t), (void *)p->ip6, 0) == 0 &&
1348 pdu_add_tlv(&pdu, &pl, &sz,
1349 ISNS_PORTAL_PORT_ATTR_ID,
1350 4, (void *)p->port, 0) == 0) {
1351 /* connect once */
1352 so = connect_to(p->sz, p->ip4, p->ip6, p->esip);
1353 if (so != -1) {
1354 feedback = esi_ping(so, pdu, pl);
1355 (void) close(so);
1356 /* p->so = so; */
1357 } else {
1358 /* cannot connect, portal is dead */
1359 feedback = 0;
1361 if (feedback == 0) {
1362 isnslog(LOG_DEBUG, "esi_monitor",
1363 "ESI ping failed.");
1364 (void) queue_msg_set(sys_q, DEAD_PORTAL,
1365 (void *)p->ref);
1366 } else {
1367 goto mon_done;
1370 pl = half;
1371 p = p->next;
1374 mon_done:
1375 /* unlock the event after esi monitoring is done */
1376 (void) pthread_mutex_unlock(&ev->mtx);
1378 /* clean up pdu */
1379 if (pdu != NULL) {
1380 free(pdu);
1383 /* set reschedule flags */
1384 ev->flags |= EV_FLAG_WAKEUP;
1386 /* reschedule for next occurence */
1387 (void) el_add(ev, 0, NULL);
1389 /* decrease the thread ref count */
1390 dec_thr_count();
1392 return (NULL);
1396 * ****************************************************************************
1398 * portal_dies:
1399 * Handles the dead portal that ESI detected.
1401 * uid - the Portal object UID.
1403 * ****************************************************************************
1405 void
1406 portal_dies(
1407 uint32_t uid
1410 int ec = 0;
1412 lookup_ctrl_t lc;
1414 /* prepare the lookup control for deregistration */
1415 SET_UID_LCP(&lc, OBJ_PORTAL, uid);
1417 /* lock the cache for object deregistration */
1418 (void) cache_lock_write();
1420 /* deregister the portal */
1421 ec = dereg_object(&lc, 1);
1423 /* unlock cache and sync with data store */
1424 (void) cache_unlock_sync(ec);
1428 * ****************************************************************************
1430 * portal_dies:
1431 * Handles the Entity registration expiration.
1433 * p - the ESI event.
1435 * ****************************************************************************
1437 void
1438 reg_expiring(
1439 void *p
1442 int ec = 0;
1443 ev_t *ev = (ev_t *)p;
1444 lookup_ctrl_t lc;
1446 /* prepare the lookup control for deregistration */
1447 SET_UID_LCP(&lc, OBJ_ENTITY, ev->uid);
1449 /* lock the cache for object deregistration */
1450 (void) cache_lock_write();
1452 if (evf_rem(ev) == 0) {
1453 /* deregister the entity */
1454 ec = dereg_object(&lc, 0);
1456 /* unlock cache and sync with data store */
1457 ec = cache_unlock_sync(ec);
1459 if (ec == 0) {
1460 /* successfuk, mark ev as removed */
1461 ev->flags |= EV_FLAG_REMOVE;
1462 } else {
1463 /* failed, retry after 3 mintues */
1464 ev->intval = 3 * 60;
1465 isnslog(LOG_DEBUG, "reg_expiring",
1466 "dereg failed, retry after 3 mintues.");
1468 } else {
1469 /* ev is marked as removed, no need to dereg */
1470 (void) cache_unlock_nosync();
1473 /* reschedule it for next occurence */
1474 (void) el_add(ev, 0, NULL);