/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include #include "isns_server.h" #include "isns_cache.h" #include "isns_obj.h" #include "isns_pdu.h" #include "isns_func.h" #include "isns_qry.h" #include "isns_msgq.h" #include "isns_log.h" #include "isns_sched.h" #include "isns_scn.h" #include "isns_esi.h" /* * global variables. */ /* * local variables. */ static ev_t *ev_list = NULL; static uint32_t stopwatch = 0; static pthread_mutex_t stw_mtx = PTHREAD_MUTEX_INITIALIZER; static int wakeup = 0; static pthread_mutex_t idl_mtx = PTHREAD_MUTEX_INITIALIZER; static pthread_cond_t idl_cond = PTHREAD_COND_INITIALIZER; /* * external variables. */ extern const int UID_ATTR_INDEX[MAX_OBJ_TYPE_FOR_SIZE]; extern boolean_t time_to_exit; extern msg_queue_t *sys_q; extern uint64_t esi_threshold; #ifdef DEBUG extern void dump_pdu1(isns_pdu_t *); #endif /* * local functions. */ static void *esi_monitor(void *); /* * **************************************************************************** * * new_esi_portal: * Make a new portal for ESI event. * * uid - the portal object UID. * ip6 - the portal IPv6 format IP address. * port - the portal port. * esip - the ESI port. * return - the new ESI portal. * * **************************************************************************** */ static esi_portal_t * new_esi_portal( uint32_t uid, in6_addr_t *ip6, uint32_t port, uint32_t esip ) { esi_portal_t *p; p = (esi_portal_t *)malloc(sizeof (esi_portal_t)); if (p != NULL) { if (((int *)ip6)[0] == 0x00 && ((int *)ip6)[1] == 0x00 && ((uchar_t *)ip6)[8] == 0x00 && ((uchar_t *)ip6)[9] == 0x00 && ((uchar_t *)ip6)[10] == 0xFF && ((uchar_t *)ip6)[11] == 0xFF) { p->sz = sizeof (in_addr_t); p->ip4 = ((uint32_t *)ip6)[3]; } else { p->sz = sizeof (in6_addr_t); } p->ip6 = ip6; p->port = port; p->esip = esip; p->ref = uid; p->so = 0; p->next = NULL; } return (p); } /* * **************************************************************************** * * free_esi_portal: * Free a list of portal of one ESI event. * * p - the ESI portal. * * **************************************************************************** */ static void free_esi_portal( esi_portal_t *p ) { esi_portal_t *n; while (p != NULL) { n = p->next; free(p->ip6); free(p); p = n; } } /* * **************************************************************************** * * ev_new: * Make a new ESI event. * * uid - the Entity object UID. * eid - the Entity object name. * len - the length of the name. * return - the ESI event. * * **************************************************************************** */ static ev_t * ev_new( uint32_t uid, uchar_t *eid, uint32_t len ) { ev_t *ev; ev = (ev_t *)malloc(sizeof (ev_t)); if (ev != NULL) { if (pthread_mutex_init(&ev->mtx, NULL) != 0 || (ev->eid = (uchar_t *)malloc(len)) == NULL) { free(ev); return (NULL); } ev->uid = uid; (void) strcpy((char *)ev->eid, (char *)eid); ev->eid_len = len; /* initialization time */ ev->flags = EV_FLAG_INIT; } return (ev); } /* * **************************************************************************** * * cb_portal_uids: * Callback function which makes a copy of the portal child object * UIDs from a Network Entity object. * * p1 - the Network Entity object. * p2 - the lookup control data. * return - the number of portal object UIDs. * * **************************************************************************** */ static int cb_portal_uids( void *p1, void *p2 ) { isns_obj_t *obj = (isns_obj_t *)p1; lookup_ctrl_t *lcp = (lookup_ctrl_t *)p2; isns_attr_t *attr; uint32_t *cuidp; uint32_t num = 0; uint32_t *p = NULL; cuidp = get_child_t(obj, OBJ_PORTAL); if (cuidp != NULL) { p = (uint32_t *)malloc(*cuidp * sizeof (*p)); if (p != NULL) { num = *cuidp ++; (void) memcpy(p, cuidp, num * sizeof (*p)); lcp->data[1].ptr = (uchar_t *)p; } } attr = &obj->attrs[ATTR_INDEX_ENTITY(ISNS_ENTITY_REG_PERIOD_ATTR_ID)]; if (attr->tag != 0 && attr->value.ui != 0) { lcp->data[2].ui = attr->value.ui; } else { /* just one second before the end of the world */ lcp->data[2].ui = INFINITY - 1; } return (num); } /* * **************************************************************************** * * cb_esi_portal: * Callback function which gets ESI port number and ESI interval * from a portal object. * * p1 - the Portal object. * p2 - the lookup control data. * return - the ESI interval. * * **************************************************************************** */ static int cb_esi_portal( void *p1, void *p2 ) { uint32_t intval = 0; isns_obj_t *obj; lookup_ctrl_t *lcp; in6_addr_t *ip; uint32_t esip; isns_attr_t *attr; if (cb_clone_attrs(p1, p2) == 0) { obj = (isns_obj_t *)p1; lcp = (lookup_ctrl_t *)p2; ip = lcp->data[1].ip; esip = lcp->data[2].ui; if (esip != 0) { attr = &obj->attrs[ATTR_INDEX_PORTAL( ISNS_PORTAL_PORT_ATTR_ID)]; lcp->data[0].ui = attr->value.ui; attr = &obj->attrs[ATTR_INDEX_PORTAL( ISNS_ESI_INTERVAL_ATTR_ID)]; if (attr->tag != 0 && attr->value.ui != 0) { intval = attr->value.ui; } else { intval = DEFAULT_ESI_INTVAL; } } else { free(ip); } } return ((int)intval); } /* * **************************************************************************** * * extract_esi_portal: * Extract a list of portal which have an ESI port for an Entity. * * uid - the Entity object UID. * intval - the ESI interval for returnning. * return - the list of portals. * * **************************************************************************** */ static esi_portal_t * extract_esi_portal( uint32_t uid, uint32_t *intval ) { esi_portal_t *list = NULL; esi_portal_t *p; lookup_ctrl_t lc; uint32_t num_of_portal; uint32_t *portal_uids; uint32_t intv; /* prepare for looking up entity object */ SET_UID_LCP(&lc, OBJ_ENTITY, uid); lc.data[1].ptr = NULL; lc.data[2].ui = INFINITY - 1; /* get the array of the portal uid(s) */ num_of_portal = (uint32_t)cache_lookup(&lc, NULL, cb_portal_uids); portal_uids = (uint32_t *)lc.data[1].ptr; *intval = lc.data[2].ui; /* prepare for looking up portal object(s) */ SET_UID_LCP(&lc, OBJ_PORTAL, 0); lc.id[1] = ISNS_PORTAL_IP_ADDR_ATTR_ID; lc.id[2] = ISNS_ESI_PORT_ATTR_ID; FOR_EACH_OBJS(portal_uids, num_of_portal, uid, { if (uid != 0) { lc.data[0].ui = uid; intv = cache_lookup(&lc, NULL, cb_esi_portal); if (intv != 0) { p = new_esi_portal(uid, (in6_addr_t *)lc.data[1].ip, lc.data[0].ui, lc.data[2].ui); if (p != NULL) { p->next = list; list = p; if (*intval > intv) { *intval = intv; } } } } }); /* free up the portal uid array */ free(portal_uids); return (list); } /* * **************************************************************************** * * ev_add: * Add an ESI event. * * ev - the ESI event. * init - 0: initialization time, otherwise not. * return - error code. * * **************************************************************************** */ static int ev_add( ev_t *ev, int init ) { uint32_t intval; esi_portal_t *p; double rnd; uint32_t t = 0; /* get the portal(s) which are registered for ESI monitoring */ /* and the second interval for ESI or registration expiration */ p = extract_esi_portal(ev->uid, &intval); ev->intval = intval; if (p != NULL) { ev->type = EV_ESI; ev->portal = p; /* avoid running everything at the same time */ if (init != 0) { /* generate random number within range (0, 1] */ rnd = (rand() + 1) / (double)(RAND_MAX + 1); t = (uint32_t)(intval * rnd); } } else { /* no portal is registered for ESI monitoring, make */ /* an entry for entity registration expiration */ ev->type = EV_REG_EXP; ev->portal = NULL; if (init != 0) { t = intval; } } /* schedule the event */ return (el_add(ev, t, NULL)); } /* * global functions. */ /* * **************************************************************************** * * sigalrm: * The signal handler for SIGALRM, the ESI proc uses the SIGALRM * for waking up to perform the client status inquery. * * sig - the signal. * * **************************************************************************** */ /*ARGSUSED*/ void sigalrm( int sig ) { /* wake up the idle */ (void) pthread_mutex_lock(&idl_mtx); wakeup = 1; /* wake up naturally */ (void) pthread_cond_signal(&idl_cond); (void) pthread_mutex_unlock(&idl_mtx); } /* * **************************************************************************** * * esi_load: * Load an ESI event from data store. * * uid - the Entity object UID. * eid - the Entity object name. * len - the length of the name. * return - error code. * * **************************************************************************** */ int esi_load( uint32_t uid, uchar_t *eid, uint32_t len ) { int ec = 0; /* make a new event */ ev_t *ev = ev_new(uid, eid, len); /* put the new event to the list */ if (ev != NULL) { ev->next = ev_list; ev_list = ev; } else { ec = ISNS_RSP_INTERNAL_ERROR; } return (ec); } /* * **************************************************************************** * * verify_esi_portal: * Verify ESI port and add the ESI entries after the ESI are loaded. * * return - error code. * * **************************************************************************** */ int verify_esi_portal( ) { int ec = 0; ev_t *ev; /* add each event from the list */ while (ev_list != NULL && ec == 0) { ev = ev_list; ev_list = ev->next; ev->next = NULL; ec = ev_add(ev, 1); } return (ec); } /* * **************************************************************************** * * esi_add: * Add a new ESI event when a new Entity is registered. * * uid - the Entity object UID. * eid - the Entity object name. * len - the length of the name. * return - error code. * * **************************************************************************** */ int esi_add( uint32_t uid, uchar_t *eid, uint32_t len ) { int ec = 0; /* make a new event */ ev_t *ev = ev_new(uid, eid, len); if (ev != NULL) { /* interrupt idle */ ev->flags |= EV_FLAG_WAKEUP; ec = ev_add(ev, 0); } else { ec = ISNS_RSP_INTERNAL_ERROR; } return (ec); } /* * **************************************************************************** * * esi_remove: * Remove an ESI event immediately. * * uid - the Entity object UID. * return - always successful. * * **************************************************************************** */ int esi_remove( uint32_t uid ) { (void) el_remove(uid, 0, 0); return (0); } /* * **************************************************************************** * * esi_remove_obj: * Update an ESI event when a Entity object or a Portal object is * removed from server. If the object is being removed because of * ESI failure, the ESI event will be removed with a pending time, * otherwise, the ESI will be removed immediately. * * obj - the object being removed. * pending - the pending flag. * return - always successful. * * **************************************************************************** */ int esi_remove_obj( const isns_obj_t *obj, int pending ) { uint32_t puid, uid; switch (obj->type) { case OBJ_PORTAL: puid = get_parent_uid(obj); uid = get_obj_uid(obj); break; case OBJ_ENTITY: puid = get_obj_uid(obj); uid = 0; break; default: puid = 0; break; } if (puid != 0) { (void) el_remove(puid, uid, pending); } return (0); } /* * **************************************************************************** * * get_stopwatch: * Get the stopwatch. It might need to signal the condition to * wake up the idle so the stopwatch gets updated. * * flag - wake up flag. * return - the stopwatch. * * **************************************************************************** */ uint32_t get_stopwatch( int flag ) { uint32_t t; /* not re-schedule, wake up idle */ (void) pthread_mutex_lock(&idl_mtx); if (flag != 0) { wakeup = 2; /* wake up manually */ (void) pthread_cond_signal(&idl_cond); } else { wakeup = 0; /* clear previous interruption */ } (void) pthread_mutex_unlock(&idl_mtx); /* get most current time */ (void) pthread_mutex_lock(&stw_mtx); t = stopwatch; (void) pthread_mutex_unlock(&stw_mtx); return (t); } /* * **************************************************************************** * * ev_intval: * Get the time interval of an ESI event. * * p - the ESI event. * return - the time interval. * * **************************************************************************** */ uint32_t ev_intval( void *p ) { return (((ev_t *)p)->intval); } /* * **************************************************************************** * * ev_match: * Check the ESI event maching an Entity object. * * p - the ESI event. * uid - the Entity object UID. * return - 1: match, otherwise not. * * **************************************************************************** */ int ev_match( void *p, uint32_t uid ) { if (((ev_t *)p)->uid == uid) { return (1); } else { return (0); } } /* * **************************************************************************** * * ev_remove: * Remove a portal or an ESI event. If all of ESI portal has been * removed, the ESI event will be marked as removal pending, which * will result in removing the Entity object after the pending time. * * p - the ESI event. * portal_uid - the Portal object UID. * flag - 0: the ESI is currently in use, otherwise it is scheduled. * pending - flag for the ESI removal pending. * return - 0: the ESI is physically removed, otherwise not. * * **************************************************************************** */ int ev_remove( void *p, uint32_t portal_uid, int flag, int pending ) { ev_t *ev = (ev_t *)p; esi_portal_t **pp, *portal; int has_portal = 0; int state; /* remove one portal only */ if (portal_uid != 0) { pp = &ev->portal; portal = *pp; while (portal != NULL) { /* found the match portal */ if (portal->ref == portal_uid) { /* mark it as removed */ portal->ref = 0; if (flag != 0) { /* not in use, remove it physically */ *pp = portal->next; portal->next = NULL; free_esi_portal(portal); } else { pp = &portal->next; } } else { /* one or more esi portals are available */ if (portal->ref != 0) { has_portal = 1; } pp = &portal->next; } portal = *pp; } } /* no portal available */ if (has_portal == 0) { state = (pending << 1) | flag; switch (state) { case 0x0: /* mark the event as removed */ ev->flags |= EV_FLAG_REMOVE; isnslog(LOG_DEBUG, "ev_remove", "%s [%d] is marked as removed.", ev->type == EV_ESI ? "ESI" : "REG_EXP", ev->uid); break; case 0x1: /* physically remove the event */ ev_free(ev); break; case 0x2: case 0x3: /* mark the event as removal pending */ isnslog(LOG_DEBUG, "ev_remove", "%s [%d] is marked as removal pending.", ev->type == EV_ESI ? "ESI" : "REG_EXP", ev->uid); ev->flags |= EV_FLAG_REM_P1; has_portal = 1; break; default: break; } } else { isnslog(LOG_DEBUG, "ev_remove", "%s [%d] removed portal %d.", ev->type == EV_ESI ? "ESI" : "REG_EXP", ev->uid, portal_uid); } return (has_portal); } /* * **************************************************************************** * * ev_free: * Free an ESI event. * * p - the ESI event. * * **************************************************************************** */ void ev_free( void *p ) { ev_t *ev = (ev_t *)p; /* free up all of portals */ free_esi_portal(ev->portal); isnslog(LOG_DEBUG, "ev_free", "%s [%d] is physically removed.", ev->type == EV_ESI ? "ESI" : "REG_EXP", ev->uid); free(ev->eid); /* free the event */ free(ev); } /* * **************************************************************************** * * evf_init: * Check the initial flag of an ESI event. * * p - the ESI event. * return - 0: not initial, otherwise yes. * * **************************************************************************** */ int evf_init( void *p ) { return (((ev_t *)p)->flags & EV_FLAG_INIT); } /* * **************************************************************************** * * evf_again: * Check the again flag of an ESI event. * (this flag might be eliminated and use the init flag.) * * p - the ESI event. * return - 0: not again, otherwise yes. * * **************************************************************************** */ int evf_again( void *p ) { return (((ev_t *)p)->flags & EV_FLAG_AGAIN); } /* * **************************************************************************** * * evf_wakeup: * Check the wakeup flag of an ESI event. The idle might need to * wake up before the event is scheduled. * * p - the ESI event. * return - 0: no wakeup, otherwise yes. * * **************************************************************************** */ int evf_wakeup( void *p ) { return (((ev_t *)p)->flags & EV_FLAG_WAKEUP); } /* * **************************************************************************** * * evf_rem: * Check the removal flag of an ESI event. The ESI entry might be * marked as removal. * * p - the ESI event. * return - 0: not removed, otherwise yes. * * **************************************************************************** */ int evf_rem( void *p ) { return (((ev_t *)p)->flags & EV_FLAG_REMOVE); } /* * **************************************************************************** * * evf_rem_pending: * Check the removal pending flag of an ESI event. The ESI entry * might be marked as removal pending. If it is, we will switch the * event type and change the time interval. * * p - the ESI event. * return - 0: not removal pending, otherwise yes. * * **************************************************************************** */ int evf_rem_pending( void *p ) { ev_t *ev = (ev_t *)p; if ((ev->flags & EV_FLAG_REM_P) != 0) { if (ev->type != EV_REG_EXP) { isnslog(LOG_DEBUG, "ev_rem_pending", "%s [%d] is changed to REG_EXP.", ev->type == EV_ESI ? "ESI" : "REG_EXP", ev->uid); ev->type = EV_REG_EXP; ev->intval *= 2; /* after 2 ESI interval */ } return (1); } return (0); } /* * **************************************************************************** * * evf_zero: * Reset the event flag. * * p - the ESI event. * * **************************************************************************** */ void evf_zero( void *p ) { ev_t *ev = (ev_t *)p; /* not acutally clear it, need to set again flag */ /* and keep the removal pending flag */ ev->flags = EV_FLAG_AGAIN | (ev->flags & EV_FLAG_REM_P); } /* * **************************************************************************** * * evl_append: * Append an ESI event to the list, the list contains all of * ESI events which are being processed at present. * * p - the ESI event. * * **************************************************************************** */ void evl_append( void *p ) { ev_t *ev; ev = (ev_t *)p; ev->next = ev_list; ev_list = ev; } /* * **************************************************************************** * * evl_strip: * Strip off an ESI event from the list after the event is being * processed, it will be scheduled in the scheduler. * * p - the ESI event. * * **************************************************************************** */ void evl_strip( void *p ) { ev_t **evp = &ev_list; ev_t *ev = *evp; while (ev != NULL) { if (ev == p) { *evp = ev->next; break; } evp = &ev->next; ev = *evp; } } /* * **************************************************************************** * * evl_remove: * Remove an ESI event or a portal of an ESI event from the event list. * * id1 - the Entity object UID. * id2 - the Portal object UID. * pending - the pending flag. * return - 1: found a match event, otherwise not. * * **************************************************************************** */ int evl_remove( uint32_t id1, uint32_t id2, int pending ) { ev_t *ev = ev_list; while (ev != NULL) { /* found it */ if (ev_match(ev, id1) != 0) { /* lock the event */ (void) pthread_mutex_lock(&ev->mtx); /* mark it as removed */ (void) ev_remove(ev, id2, 0, pending); /* unlock the event */ (void) pthread_mutex_unlock(&ev->mtx); /* tell caller removal is done */ return (1); } ev = ev->next; } /* not found it */ return (0); } #define ALARM_MAX (21427200) /* * **************************************************************************** * * idle: * Idle for certain amount of time or a wakeup signal is recieved. * * t - the idle time. * return - the time that idle left. * * **************************************************************************** */ static int idle( uint32_t t ) { uint32_t t1, t2, t3 = 0; int idl_int = 0; /* hold the mutex for stopwatch update */ (void) pthread_mutex_lock(&stw_mtx); do { if (t > ALARM_MAX) { t1 = ALARM_MAX; } else { t1 = t; } /* start alarm */ (void) alarm(t1); /* hold the mutex for idle condition */ (void) pthread_mutex_lock(&idl_mtx); /* wait on condition variable to wake up idle */ while (wakeup == 0) { (void) pthread_cond_wait(&idl_cond, &idl_mtx); } if (wakeup == 2) { idl_int = 1; } /* clean wakeup flag */ wakeup = 0; /* release the mutex for idle condition */ (void) pthread_mutex_unlock(&idl_mtx); /* stop alarm */ t2 = alarm(0); /* seconds actually slept */ t3 += t1 - t2; t -= t3; } while (t > 0 && idl_int == 0); /* increate the stopwatch by the actually slept time */ stopwatch += t3; /* release the mutex after stopwatch is updated */ (void) pthread_mutex_unlock(&stw_mtx); /* return the amount of time which is not slept */ return (t); } /* * **************************************************************************** * * ev_ex: * Execute an event. To inquiry the client status or * perform registration expiration. * * ev - the event. * * **************************************************************************** */ static void ev_ex( ev_t *ev ) { pthread_t tid; switch (ev->type) { case EV_ESI: if (pthread_create(&tid, NULL, esi_monitor, (void *)ev) != 0) { isnslog(LOG_DEBUG, "ev_ex", "pthread_create() failed."); /* reschedule for next occurence */ (void) el_add(ev, 0, NULL); } else { /* increase the thread ref count */ inc_thr_count(); } break; case EV_REG_EXP: (void) queue_msg_set(sys_q, REG_EXP, (void *)ev); break; default: break; } } /* * **************************************************************************** * * esi_proc: * ESI thread entry, which: * 1: fetch an event from schedule, * 2: idle for some time, * 3: execute the event or re-schedule it, * 4: repeat from step 1 before server is being shutdown. * * arg - the thread argument. * * **************************************************************************** */ /*ARGSUSED*/ void * esi_proc( void *arg ) { uint32_t t, t1, pt; ev_t *ev; void *evp; while (time_to_exit == B_FALSE) { ev = (ev_t *)el_first(&pt); /* caculate the idle time */ if (ev != NULL) { if (pt > stopwatch) { t = pt - stopwatch; } else { t = 0; } } else { t = INFINITY; } do { /* block for a certain amount of time */ if (t > 0) { isnslog(LOG_DEBUG, "esi_proc", "idle for %d seconds.", t); t1 = idle(t); } else { t1 = 0; } if (t1 > 0) { isnslog(LOG_DEBUG, "esi_proc", "idle interrupted after idle for " "%d seconds.", t - t1); } if (time_to_exit != B_FALSE) { ev = NULL; /* force break */ } else if (ev != NULL) { if (t1 > 0) { /* not naturally waken up */ /* reschedule current event */ evp = NULL; (void) el_add(ev, pt, &evp); ev = (ev_t *)evp; t = t1; } else { /* excute */ isnslog(LOG_DEBUG, "esi_proc", "excute the cron job[%d].", ev->uid); ev_ex(ev); ev = NULL; } } } while (ev != NULL); } return (NULL); } /* * **************************************************************************** * * esi_ping: * Ping the client with the ESI retry threshold for status inquiry. * * so - the socket descriptor. * pdu - the ESI packet. * pl - the length of packet. * return - 1: status inquired, otherwise not. * * **************************************************************************** */ static int esi_ping( int so, isns_pdu_t *pdu, size_t pl ) { int try_cnt = 0; isns_pdu_t *rsp = NULL; size_t rsp_sz; int alive = 0; do { if (isns_send_pdu(so, pdu, pl) == 0) { if (isns_rcv_pdu(so, &rsp, &rsp_sz, ISNS_RCV_SHORT_TIMEOUT) > 0) { #ifdef DEBUG dump_pdu1(rsp); #endif alive = 1; break; } } else { /* retry after 1 second */ (void) sleep(1); } try_cnt ++; } while (try_cnt < esi_threshold); if (rsp != NULL) { free(rsp); } return (alive); } /* * **************************************************************************** * * esi_monitor: * Child thread for client status mornitoring. * * arg - the ESI event. * * **************************************************************************** */ static void * esi_monitor( void *arg ) { ev_t *ev = (ev_t *)arg; esi_portal_t *p; int so; isns_pdu_t *pdu = NULL; size_t sz; size_t pl; size_t half; time_t t; int feedback; /* lock the event for esi monitoring */ (void) pthread_mutex_lock(&ev->mtx); if (evf_rem(ev) != 0) { goto mon_done; } else if (evf_rem_pending(ev) != 0) { goto mon_done; } /* timestamp */ t = time(NULL); /* allocate ESI PDU */ if (pdu_reset_esi(&pdu, &pl, &sz) != 0 || pdu_add_tlv(&pdu, &pl, &sz, ISNS_TIMESTAMP_ATTR_ID, 8, (void *)&t, 1) != 0 || pdu_add_tlv(&pdu, &pl, &sz, ISNS_EID_ATTR_ID, ev->eid_len, (void *)ev->eid, 0) != 0) { /* no memory, will retry later */ goto mon_done; } /* set pdu head */ pdu->version = htons((uint16_t)ISNSP_VERSION); pdu->func_id = htons((uint16_t)ISNS_ESI); pdu->xid = htons(get_server_xid()); /* keep the current lenght of the playload */ half = pl; p = ev->portal; while (p != NULL) { if (p->ref != 0 && /* skip IPv6 portal */ p->sz != sizeof (in6_addr_t) && pdu_add_tlv(&pdu, &pl, &sz, ISNS_PORTAL_IP_ADDR_ATTR_ID, sizeof (in6_addr_t), (void *)p->ip6, 0) == 0 && pdu_add_tlv(&pdu, &pl, &sz, ISNS_PORTAL_PORT_ATTR_ID, 4, (void *)p->port, 0) == 0) { /* connect once */ so = connect_to(p->sz, p->ip4, p->ip6, p->esip); if (so != -1) { feedback = esi_ping(so, pdu, pl); (void) close(so); /* p->so = so; */ } else { /* cannot connect, portal is dead */ feedback = 0; } if (feedback == 0) { isnslog(LOG_DEBUG, "esi_monitor", "ESI ping failed."); (void) queue_msg_set(sys_q, DEAD_PORTAL, (void *)p->ref); } else { goto mon_done; } } pl = half; p = p->next; } mon_done: /* unlock the event after esi monitoring is done */ (void) pthread_mutex_unlock(&ev->mtx); /* clean up pdu */ if (pdu != NULL) { free(pdu); } /* set reschedule flags */ ev->flags |= EV_FLAG_WAKEUP; /* reschedule for next occurence */ (void) el_add(ev, 0, NULL); /* decrease the thread ref count */ dec_thr_count(); return (NULL); } /* * **************************************************************************** * * portal_dies: * Handles the dead portal that ESI detected. * * uid - the Portal object UID. * * **************************************************************************** */ void portal_dies( uint32_t uid ) { int ec = 0; lookup_ctrl_t lc; /* prepare the lookup control for deregistration */ SET_UID_LCP(&lc, OBJ_PORTAL, uid); /* lock the cache for object deregistration */ (void) cache_lock_write(); /* deregister the portal */ ec = dereg_object(&lc, 1); /* unlock cache and sync with data store */ (void) cache_unlock_sync(ec); } /* * **************************************************************************** * * portal_dies: * Handles the Entity registration expiration. * * p - the ESI event. * * **************************************************************************** */ void reg_expiring( void *p ) { int ec = 0; ev_t *ev = (ev_t *)p; lookup_ctrl_t lc; /* prepare the lookup control for deregistration */ SET_UID_LCP(&lc, OBJ_ENTITY, ev->uid); /* lock the cache for object deregistration */ (void) cache_lock_write(); if (evf_rem(ev) == 0) { /* deregister the entity */ ec = dereg_object(&lc, 0); /* unlock cache and sync with data store */ ec = cache_unlock_sync(ec); if (ec == 0) { /* successfuk, mark ev as removed */ ev->flags |= EV_FLAG_REMOVE; } else { /* failed, retry after 3 mintues */ ev->intval = 3 * 60; isnslog(LOG_DEBUG, "reg_expiring", "dereg failed, retry after 3 mintues."); } } else { /* ev is marked as removed, no need to dereg */ (void) cache_unlock_nosync(); } /* reschedule it for next occurence */ (void) el_add(ev, 0, NULL); }