/*
* 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
* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <signal.h>
#include <poll.h>
#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 int wakeup = 0;
/*
* 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 *
)
{
esi_portal_t *p;
if (p != NULL) {
if (((int *)ip6)[0] == 0x00 &&
} else {
p->sz = sizeof (in6_addr_t);
}
p->so = 0;
}
return (p);
}
/*
* ****************************************************************************
*
* free_esi_portal:
* Free a list of portal of one ESI event.
*
* p - the ESI portal.
*
* ****************************************************************************
*/
static void
esi_portal_t *p
)
{
esi_portal_t *n;
while (p != NULL) {
n = p->next;
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 *
)
{
return (NULL);
}
/* initialization time */
}
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
void *p1,
void *p2
)
{
if (p != NULL) {
}
}
} else {
/* just one second before the end of the world */
}
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
void *p1,
void *p2
)
{
if (esip != 0) {
} else {
}
} else {
}
}
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 *
)
{
esi_portal_t *p;
/* prepare for looking up entity object */
/* get the array of the portal uid(s) */
/* prepare for looking up portal object(s) */
if (uid != 0) {
if (intv != 0) {
p = new_esi_portal(uid,
if (p != NULL) {
list = p;
}
}
}
}
});
/* free up the portal uid array */
return (list);
}
/*
* ****************************************************************************
*
* ev_add:
* Add an ESI event.
*
* ev - the ESI event.
* init - 0: initialization time, otherwise not.
* return - error code.
*
* ****************************************************************************
*/
static int
int init
)
{
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 */
if (p != NULL) {
/* avoid running everything at the same time */
if (init != 0) {
/* generate random number within range (0, 1] */
}
} else {
/* no portal is registered for ESI monitoring, make */
/* an entry for entity registration expiration */
if (init != 0) {
t = intval;
}
}
/* schedule the event */
}
/*
* 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
int sig
)
{
/* wake up the idle */
(void) pthread_mutex_lock(&idl_mtx);
(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
)
{
int ec = 0;
/* make a new event */
/* put the new event to the list */
} else {
}
return (ec);
}
/*
* ****************************************************************************
*
* verify_esi_portal:
* Verify ESI port and add the ESI entries after the ESI are loaded.
*
* return - error code.
*
* ****************************************************************************
*/
int
)
{
int ec = 0;
/* add each event from the list */
}
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
)
{
int ec = 0;
/* make a new event */
/* interrupt idle */
} else {
}
return (ec);
}
/*
* ****************************************************************************
*
* esi_remove:
* Remove an ESI event immediately.
*
* uid - the Entity object UID.
* return - always successful.
*
* ****************************************************************************
*/
int
)
{
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
const isns_obj_t *obj,
int pending
)
{
case OBJ_PORTAL:
break;
case OBJ_ENTITY:
uid = 0;
break;
default:
puid = 0;
break;
}
if (puid != 0) {
}
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.
*
* ****************************************************************************
*/
int flag
)
{
uint32_t t;
/* not re-schedule, wake up idle */
(void) pthread_mutex_lock(&idl_mtx);
if (flag != 0) {
(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.
*
* ****************************************************************************
*/
void *p
)
{
}
/*
* ****************************************************************************
*
* 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
void *p,
)
{
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
void *p,
int flag,
int pending
)
{
int has_portal = 0;
int state;
/* remove one portal only */
if (portal_uid != 0) {
/* found the match portal */
/* mark it as removed */
if (flag != 0) {
/* not in use, remove it physically */
} else {
}
} else {
/* one or more esi portals are available */
has_portal = 1;
}
}
}
}
/* no portal available */
if (has_portal == 0) {
switch (state) {
case 0x0:
/* mark the event as removed */
"%s [%d] is marked as removed.",
break;
case 0x1:
/* physically remove the event */
break;
case 0x2:
case 0x3:
/* mark the event as removal pending */
"%s [%d] is marked as removal pending.",
has_portal = 1;
break;
default:
break;
}
} else {
}
return (has_portal);
}
/*
* ****************************************************************************
*
* ev_free:
* Free an ESI event.
*
* p - the ESI event.
*
* ****************************************************************************
*/
void
void *p
)
{
/* free up all of portals */
"%s [%d] is physically removed.",
/* free the event */
}
/*
* ****************************************************************************
*
* evf_init:
* Check the initial flag of an ESI event.
*
* p - the ESI event.
* return - 0: not initial, otherwise yes.
*
* ****************************************************************************
*/
int
void *p
)
{
}
/*
* ****************************************************************************
*
* 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
void *p
)
{
}
/*
* ****************************************************************************
*
* 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
void *p
)
{
}
/*
* ****************************************************************************
*
* 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
void *p
)
{
}
/*
* ****************************************************************************
*
* 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
void *p
)
{
"%s [%d] is changed to REG_EXP.",
}
return (1);
}
return (0);
}
/*
* ****************************************************************************
*
* evf_zero:
* Reset the event flag.
*
* p - the ESI event.
*
* ****************************************************************************
*/
void
void *p
)
{
/* not acutally clear it, need to set again flag */
/* and keep the removal pending flag */
}
/*
* ****************************************************************************
*
* 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
void *p
)
{
}
/*
* ****************************************************************************
*
* 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
void *p
)
{
if (ev == p) {
break;
}
}
}
/*
* ****************************************************************************
*
* 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
int pending
)
{
/* found it */
/* lock the event */
/* mark it as removed */
/* unlock the event */
/* tell caller removal is done */
return (1);
}
}
/* not found it */
return (0);
}
/*
* ****************************************************************************
*
* 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
)
{
int idl_int = 0;
/* hold the mutex for stopwatch update */
(void) pthread_mutex_lock(&stw_mtx);
do {
if (t > ALARM_MAX) {
} else {
t1 = t;
}
/* start alarm */
/* hold the mutex for idle condition */
(void) pthread_mutex_lock(&idl_mtx);
/* wait on condition variable to wake up idle */
while (wakeup == 0) {
}
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 */
/* seconds actually slept */
t -= t3;
} while (t > 0 && idl_int == 0);
/* increate the stopwatch by the actually slept time */
/* 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
)
{
case EV_ESI:
esi_monitor, (void *)ev) != 0) {
/* reschedule for next occurence */
} else {
/* increase the thread ref count */
}
break;
case EV_REG_EXP:
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 *
void *arg
)
{
void *evp;
while (time_to_exit == B_FALSE) {
/* caculate the idle time */
} else {
t = 0;
}
} else {
t = INFINITY;
}
do {
/* block for a certain amount of time */
if (t > 0) {
"idle for %d seconds.", t);
} else {
t1 = 0;
}
if (t1 > 0) {
"idle interrupted after idle for "
"%d seconds.", t - t1);
}
if (time_to_exit != B_FALSE) {
if (t1 > 0) {
/* not naturally waken up */
/* reschedule current event */
t = t1;
} else {
/* excute */
"excute the cron job[%d].",
}
}
}
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
int so,
)
{
int try_cnt = 0;
int alive = 0;
do {
ISNS_RCV_SHORT_TIMEOUT) > 0) {
#ifdef DEBUG
#endif
alive = 1;
break;
}
} else {
/* retry after 1 second */
(void) sleep(1);
}
try_cnt ++;
} while (try_cnt < esi_threshold);
}
return (alive);
}
/*
* ****************************************************************************
*
* esi_monitor:
* Child thread for client status mornitoring.
*
* arg - the ESI event.
*
* ****************************************************************************
*/
static void *
void *arg
)
{
esi_portal_t *p;
int so;
time_t t;
int feedback;
/* lock the event for esi monitoring */
goto mon_done;
} else if (evf_rem_pending(ev) != 0) {
goto mon_done;
}
/* timestamp */
/* allocate ESI PDU */
/* no memory, will retry later */
goto mon_done;
}
/* set pdu head */
/* keep the current lenght of the playload */
while (p != NULL) {
if (p->ref != 0 &&
/* skip IPv6 portal */
p->sz != sizeof (in6_addr_t) &&
sizeof (in6_addr_t), (void *)p->ip6, 0) == 0 &&
4, (void *)p->port, 0) == 0) {
/* connect once */
if (so != -1) {
/* p->so = so; */
} else {
/* cannot connect, portal is dead */
feedback = 0;
}
if (feedback == 0) {
"ESI ping failed.");
(void *)p->ref);
} else {
goto mon_done;
}
}
p = p->next;
}
/* unlock the event after esi monitoring is done */
/* clean up pdu */
}
/* set reschedule flags */
/* reschedule for next occurence */
/* decrease the thread ref count */
return (NULL);
}
/*
* ****************************************************************************
*
* portal_dies:
* Handles the dead portal that ESI detected.
*
* uid - the Portal object UID.
*
* ****************************************************************************
*/
void
)
{
int ec = 0;
/* prepare the lookup control for deregistration */
/* lock the cache for object deregistration */
(void) cache_lock_write();
/* deregister the portal */
/* unlock cache and sync with data store */
(void) cache_unlock_sync(ec);
}
/*
* ****************************************************************************
*
* portal_dies:
* Handles the Entity registration expiration.
*
* p - the ESI event.
*
* ****************************************************************************
*/
void
void *p
)
{
int ec = 0;
/* prepare the lookup control for deregistration */
/* lock the cache for object deregistration */
(void) cache_lock_write();
/* deregister the entity */
/* unlock cache and sync with data store */
if (ec == 0) {
/* successfuk, mark ev as removed */
} else {
/* failed, retry after 3 mintues */
"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 */
}