#include <NetInfo/config.h>
#include "ni_server.h"
#include <sys/socket.h>
#include <sys/time.h>
#include <NetInfo/systhread.h>
#include <stdio.h>
#include <NetInfo/system_log.h>
#include <NetInfo/network.h>
#include "ni_globals.h"
#include <NetInfo/mm.h>
#include "getstuff.h"
#include "ni_notify.h"
#include <NetInfo/socket_lock.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <rpc/xdr.h>
const char *procname(int);
const bool_t takes_arg(int);
unsigned int clone_count = 0;
#define NI_SEPARATOR '/'
#define NOTIFY_TIMEOUT 60
typedef struct client_node *clone_list;
struct client_node
{
ni_name name;
unsigned long addr;
ni_name tag;
syslock *lock;
long lastupdate;
bool_t up_to_date;
clone_list next;
int retain;
};
#define NO_SEQUENCE_NUMBER -1
typedef union write_any_args
{
ni_create_args create_args;
ni_destroy_args destroy_args;
ni_proplist_stuff write_args;
ni_createprop_args createprop_args;
ni_prop_args destroyprop_args;
ni_propname_args renameprop_args;
ni_writeprop_args writeprop_args;
ni_createname_args createname_args;
ni_nameindex_args destroy_name_args;
ni_writename_args writename_args;
} write_any_args;
typedef union write_any_res
{
ni_create_res create_res;
ni_id_res destroy_res;
ni_id_res write_res;
ni_id_res createprop_res;
ni_id_res destroyprop_res;
ni_id_res renameprop_res;
ni_id_res writeprop_res;
ni_id_res createname_res;
ni_id_res destroyname_res;
ni_id_res writename_res;
} write_any_res;
typedef struct xdr_table_entry
{
unsigned proc;
unsigned insize;
xdrproc_t xdr_in;
unsigned outsize;
xdrproc_t xdr_out;
} xdr_table_entry;
#define PUSH(proc, arg_type, res_type) \
{ proc, sizeof(arg_type), xdr_##arg_type, \
sizeof(res_type), xdr_##res_type }
static const xdr_table_entry xdr_table[] =
{
PUSH(_NI_CREATE, ni_create_args, ni_create_res),
PUSH(_NI_DESTROY, ni_destroy_args, ni_id_res),
PUSH(_NI_WRITE, ni_proplist_stuff, ni_id_res),
PUSH(_NI_CREATEPROP, ni_createprop_args, ni_id_res),
PUSH(_NI_DESTROYPROP, ni_prop_args, ni_id_res),
PUSH(_NI_RENAMEPROP, ni_propname_args, ni_id_res),
PUSH(_NI_WRITEPROP, ni_writeprop_args, ni_id_res),
PUSH(_NI_CREATENAME, ni_createname_args, ni_id_res),
PUSH(_NI_WRITEPROP, ni_writeprop_args, ni_id_res),
PUSH(_NI_CREATENAME, ni_createname_args, ni_id_res),
PUSH(_NI_DESTROYNAME, ni_nameindex_args, ni_id_res),
PUSH(_NI_WRITENAME, ni_writename_args, ni_id_res),
PUSH(_NI_RESYNC, void, ni_status),
};
#undef PUSH
#define XDR_TABLE_SIZE (sizeof(xdr_table)/sizeof(xdr_table[0]))
static const xdr_table_entry *xdr_table_lookup(unsigned);
typedef struct notify_node *notify_list;
struct notify_node
{
unsigned proc;
unsigned checksum;
write_any_args args;
clone_list newlist;
notify_list next;
};
typedef struct notify_args
{
clone_list list;
unsigned checksum;
} notify_args;
static void notify(notify_args *);
static volatile notify_list notifications;
static syslock *notify_syslock = NULL;
static syslock *subthread_syslock;
static volatile int notify_subthread_count = 0;
static volatile long next_update_number = 0;
typedef struct
{
clone_list clones;
notify_list updates;
long seqno;
} fork_push_args;
static void push(clone_list, notify_list updates, long seq);
static void fork_push(clone_list, notify_list updates, long seq);
static void push_thread_stub(fork_push_args *);
unsigned count_procs(notify_list);
bool_t udp_getregister(ni_name, ni_name, struct sockaddr_in,
struct timeval, nibind_getregister_res *, char *);
bool_t tcp_getregister(ni_name, ni_name, struct sockaddr_in,
struct timeval, nibind_getregister_res *, char *);
clone_list global_clone_list = NULL;
static void
clnt_destroy_lock(CLIENT *cl, int sock)
{
socket_lock();
clnt_destroy(cl);
close(sock);
socket_unlock();
}
static unsigned
servesdot(ni_entry entry, ni_index ei, ni_name *name, ni_name *tag)
{
ni_name sep;
ni_name slashname;
unsigned addr;
ni_namelist nl;
ni_id id;
if (entry.names == NULL) return (0);
id.nii_object = entry.id;
slashname = entry.names->ninl_val[ei];
sep = index(slashname, NI_SEPARATOR);
if (sep == NULL) return 0;
if (!ni_name_match_seg(NAME_DOT, slashname, sep - slashname)) return 0;
NI_INIT(&nl);
if (ni_lookupprop(db_ni, &id, NAME_IP_ADDRESS, &nl) != NI_OK) return 0;
if (nl.ninl_len == 0) return 0;
addr = inet_addr(nl.ninl_val[0]);
ni_namelist_free(&nl);
*tag = ni_name_dup(sep + 1);
NI_INIT(&nl);
if (ni_lookupprop(db_ni, &id, NAME_NAME, &nl) != NI_OK)
{
*name = NULL;
}
else
{
if (nl.ninl_len > 0) *name = ni_name_dup(nl.ninl_val[0]);
ni_namelist_free(&nl);
}
return (addr);
}
static clone_list
clonelist_retain(clone_list clist)
{
if (clist == NULL) return clist;
clist->retain++;
return clist;
}
static void
clonelist_release(clone_list clist)
{
clone_list l;
if (clist == NULL) return;
clist->retain--;
if (clist->retain > 0) return;
while (clist != NULL)
{
l = clist;
clist = clist->next;
ni_name_free(&l->name);
ni_name_free(&l->tag);
syslock_free(l->lock);
MM_FREE(l);
}
}
static clone_list
clonelist_create()
{
ni_id id;
ni_index i;
unsigned addr;
struct in_addr x;
clone_list new;
clone_list clist;
ni_name name = NULL;
ni_name tag = NULL;
ni_idlist idlist;
ni_entrylist entries;
clone_count = 0;
if (ni_root(db_ni, &id) != NI_OK) return NULL;
NI_INIT(&idlist);
if (ni_lookup(db_ni, &id, NAME_NAME, NAME_MACHINES, &idlist) != NI_OK)
return NULL;
id.nii_object = idlist.niil_val[0];
ni_idlist_free(&idlist);
if (ni_list_const(db_ni, &id, NAME_SERVES, &entries) != NI_OK) return NULL;
clist = NULL;
for (i = 0; i < entries.niel_len; i++)
{
ni_entry entry = entries.niel_val[i];
int i;
if (entry.names == NULL) continue;
for (i = 0; i < entry.names->ninl_len; i++)
{
addr = servesdot(entry, i, &name, &tag);
if (addr == 0) continue;
x.s_addr = addr;
if ((sys_is_my_address(&x)) && (!strcmp(tag, db_tag)))
{
ni_name_free(&name);
ni_name_free(&tag);
continue;
}
clone_count++;
MM_ALLOC(new);
new->name = name;
new->addr = addr;
new->tag = tag;
new->lastupdate = 0;
new->lock = syslock_new(0);
new->up_to_date = TRUE;
new->next = clist;
new->retain = 1;
clist = new;
}
}
ni_list_const_free(db_ni);
return (clist);
}
static int have_notifier;
int
notify_start(void)
{
notify_args *args;
clone_list clist;
clone_list xlist;
systhread *t;
clist = clonelist_create();
xlist = global_clone_list;
global_clone_list = clonelist_retain(clist);
clonelist_release(xlist);
if (clist == NULL) return 0;
MM_ALLOC(args);
args->list = clist;
args->checksum = ni_getchecksum(db_ni);
if (notify_syslock == NULL) notify_syslock = syslock_new(0);
if (subthread_syslock == NULL) subthread_syslock = syslock_new(0);
t = systhread_new();
systhread_set_name(t, "notify");
systhread_run(t, (void(*)(void *))notify, (void *)args);
have_notifier++;
return 1;
}
void
notify_resync(void)
{
notify_args *args;
clone_list clist;
clone_list xlist;
systhread *t;
clist = clonelist_create();
xlist = global_clone_list;
global_clone_list = clonelist_retain(clist);
clonelist_release(xlist);
get_readall_info(db_ni, &max_readall_proxies, &strict_proxies);
max_subthreads = get_max_subthreads(db_ni);
update_latency_secs = get_update_latency(db_ni);
if (!have_notifier)
{
if (clist != NULL)
{
MM_ALLOC(args);
args->list = clist;
args->checksum = ni_getchecksum(db_ni);
if (notify_syslock == NULL) notify_syslock = syslock_new(0);
if (subthread_syslock == NULL) subthread_syslock = syslock_new(0);
t = systhread_new();
systhread_set_name(t, "notify");
systhread_run(t, (void(*)(void *))notify, (void *)args);
have_notifier++;
}
}
else
{
notify_clients(_NI_RESYNC, clist);
}
}
static void
notify(notify_args *args)
{
clone_list l;
notify_list newlist;
notify_list lastelt;
struct timeval tv;
CLIENT *cl;
int sock;
struct sockaddr_in sin;
nibind_getregister_res res;
bool_t notify_waited = FALSE;
enum clnt_stat cstat;
int clones_skipped = 0;
tv.tv_sec = NOTIFY_TIMEOUT;
tv.tv_usec = 0;
sin.sin_family = AF_INET;
MM_ZERO(sin.sin_zero);
system_log(LOG_INFO,
"ni_crashed notification starting {%u}: %d clone%s",
ni_getchecksum(db_ni), count_clones(), 1 == count_clones() ? "" : "s");
systhread_set_name(systhread_current(), "notify-crashed");
for (l = args->list; l != NULL; l = l->next)
{
sin.sin_port = 0;
sin.sin_addr.s_addr = l->addr;
if (! (udp_getregister(l->name, l->tag, sin, tv, &res, "ni_crashed") ||
tcp_getregister(l->name, l->tag, sin, tv, &res, "ni_crashed")))
{
clones_skipped++;
continue;
}
if (res.status != NI_OK)
{
system_log(LOG_WARNING,
"ni_crashed found %s/%s unregistered",
inet_ntoa(sin.sin_addr), l->tag);
clones_skipped++;
continue;
}
sin.sin_port = htons(res.nibind_getregister_res_u.addrs.tcp_port);
sock = socket_connect(&sin, NI_PROG, NI_VERS);
if (sock < 0)
{
system_log(LOG_WARNING, "ni_crashed can't connect to "
"%s/%s - %m",
inet_ntoa(sin.sin_addr), l->tag);
clones_skipped++;
continue;
}
FD_SET(sock, &clnt_fdset);
cl = clnttcp_create(&sin, NI_PROG, NI_VERS, &sock, 0, 0);
if (cl == NULL)
{
system_log(LOG_WARNING, "ni_crashed can't create "
"%s/%s%s",
inet_ntoa(sin.sin_addr), l->tag,
clnt_spcreateerror(""));
clones_skipped++;
socket_close(sock);
FD_CLR(sock, &clnt_fdset);
continue;
}
cstat = clnt_call(cl, _NI_CRASHED, xdr_u_int,
&args->checksum, xdr_void, NULL, tv);
if (RPC_SUCCESS != cstat)
{
system_log(LOG_WARNING, "ni_crashed can't send "
"to %s/%s - %s",
inet_ntoa(sin.sin_addr), l->tag,
clnt_sperrno(cstat));
clones_skipped++;
}
else
{
system_log(LOG_DEBUG,
"ni_crashed to %s[%s]/%s:%hu",
l->name, inet_ntoa(sin.sin_addr), l->tag,
ntohs(sin.sin_port));
}
clnt_destroy_lock(cl, sock);
FD_CLR(sock, &clnt_fdset);
}
if (0 == clones_skipped)
{
system_log(LOG_INFO, "ni_crashed sent");
}
else
{
system_log(LOG_INFO, "ni_crashed sent; %d clone%s skipped",
clones_skipped, (1 == clones_skipped ? "" : "s"));
}
clones_skipped = 0;
systhread_set_name(systhread_current(), "notify");
tv.tv_usec = 0;
syslock_lock(notify_syslock);
for (;;)
{
syslock_signal_wait(notify_syslock);
syslock_unlock(notify_syslock);
systhread_sleep(update_latency_secs);
syslock_lock(notify_syslock);
while (notifications != NULL)
{
if (notifications->proc == _NI_RESYNC)
{
syslock_unlock(notify_syslock);
syslock_lock(subthread_syslock);
systhread_set_name(systhread_current(), "notify-resync");
if (0 != notify_subthread_count)
{
system_log(LOG_DEBUG,
"resync waiting on %d thread%s",
notify_subthread_count,
1 == notify_subthread_count ?
"" : "s");
notify_waited = TRUE;
}
else
{
notify_waited = FALSE;
}
while (notify_subthread_count)
{
syslock_signal_wait(subthread_syslock);
}
syslock_unlock(subthread_syslock);
syslock_lock(notify_syslock);
if (notify_waited)
{
system_log(LOG_DEBUG, "resync continuing");
}
clonelist_release(args->list);
args->list = notifications->newlist;
lastelt = notifications;
notifications = notifications->next;
lastelt->next = NULL;
syslock_unlock(notify_syslock);
push(args->list, lastelt, next_update_number = 0);
syslock_lock(notify_syslock);
}
else
{
syslock_unlock(notify_syslock);
syslock_lock(subthread_syslock);
if (notify_subthread_count >= max_subthreads)
{
system_log(LOG_DEBUG,
"update %d awaiting a thread",
next_update_number);
}
while (notify_subthread_count >= max_subthreads)
{
syslock_signal_wait(subthread_syslock);
}
syslock_unlock(subthread_syslock);
syslock_lock(notify_syslock);
newlist = notifications;
lastelt = NULL;
while (newlist && (newlist->proc != _NI_RESYNC))
{
lastelt = newlist;
newlist = newlist->next;
}
if (lastelt)
{
lastelt->next = NULL;
fork_push(args->list, notifications, next_update_number);
}
notifications = newlist;
}
next_update_number++;
}
}
syslock_unlock(notify_syslock);
}
int
have_notifications_pending(void)
{
int num_threads;
if (notifications != NULL) {
return (1);
}
if (!subthread_syslock) {
return 0;
}
syslock_lock(subthread_syslock);
num_threads = notify_subthread_count;
syslock_unlock(subthread_syslock);
return (num_threads != 0);
}
void
notify_clients(
unsigned proc,
void *args
)
{
notify_list *l;
const xdr_table_entry *ent;
if (!have_notifier) {
if (!notify_start()) {
return;
}
}
ent = xdr_table_lookup(proc);
if (ent == NULL) {
return;
}
syslock_lock(notify_syslock);
for (l = (notify_list *)¬ifications; *l != NULL; l = &(*l)->next);
MM_ALLOC(*l);
(*l)->proc = proc;
if (proc == _NI_RESYNC)
{
(*l)->newlist = (clone_list)args;
}
else
{
bcopy(args, &(*l)->args, ent->insize);
bzero(args, ent->insize);
}
(*l)->checksum = ni_getchecksum(db_ni);
(*l)->next = NULL;
syslock_signal_send(notify_syslock);
syslock_unlock(notify_syslock);
}
static void
push(clone_list list, notify_list updates, long seq)
{
write_any_res res;
const xdr_table_entry *ent = NULL;
int sock;
struct sockaddr_in sin;
struct timeval tv;
CLIENT *cl;
clone_list l;
nibind_getregister_res gres;
notify_list this;
enum clnt_stat clstat;
int low_level_success;
char *msg_stage;
char *msg;
unsigned clones_skipped = 0;
unsigned clones_current = 0;
int nprocs;
int i;
nprocs = count_procs(updates);
system_log(LOG_INFO, "update %d starting: %d clone%s, %d operation%s",
seq, count_clones(), 1 == count_clones() ? "" : "s",
nprocs, 1 == nprocs ? "" : "s");
tv.tv_sec = NOTIFY_TIMEOUT;
tv.tv_usec = 0;
sin.sin_family = AF_INET;
MM_ZERO(sin.sin_zero);
for (l = list; l != NULL; l = l->next)
{
syslock_lock(l->lock);
while ((l->lastupdate < (seq - 1)) &&
(l->lastupdate != NO_SEQUENCE_NUMBER))
{
syslock_signal_wait(l->lock);
}
sin.sin_port = 0;
sin.sin_addr.s_addr = l->addr;
if (l->lastupdate == NO_SEQUENCE_NUMBER)
{
if (!l->up_to_date)
{
syslock_unlock(l->lock);
syslock_signal_broadcast(l->lock);
system_log(LOG_DEBUG,
"update %d: skipping %s[%s]/%s:%hu",
seq, l->name,
inet_ntoa(sin.sin_addr), l->tag,
ntohs(sin.sin_port));
clones_skipped++;
continue;
}
else
{
clones_current++;
}
}
low_level_success = 0;
msg_stage = "binder contacting";
if (! (udp_getregister(l->name, l->tag, sin, tv, &gres, "notify") ||
tcp_getregister(l->name, l->tag, sin, tv, &gres, "notify")))
{
msg = "couldn't getregister";
goto cleanup_locks;
}
if (gres.status != NI_OK) {
msg = NI_NORESPONSE == gres.status ?
"No response from clone" :
(char *)ni_error(gres.status);
goto cleanup_locks;
}
sin.sin_port =
htons(gres.nibind_getregister_res_u.addrs.tcp_port);
msg_stage = "contacting";
msg = "Couldn't get system resources ("
"socket or TCP connection)";
sock = socket_connect(&sin, NI_PROG, NI_VERS);
if (sock < 0) {
goto cleanup_locks;
}
FD_SET(sock, &clnt_fdset);
cl = clnttcp_create(&sin, NI_PROG, NI_VERS, &sock, 0, 0);
if (cl == NULL) {
socket_close(sock);
FD_CLR(sock, &clnt_fdset);
msg = clnt_spcreateerror("netinfo daemon");
goto cleanup_locks;
}
low_level_success = 1;
for (this = updates, i = 0; this; this = this->next, i++) {
ent = xdr_table_lookup(this->proc);
if (ent == NULL) {
abort();
}
bzero(&res, ent->outsize);
if (takes_arg(this->proc)) {
system_log(LOG_DEBUG,
0 == ((nprocs - i) % 50) ?
"update %d: %s %u to %s[%s]/%s:%hu {%u}, "
"%d procs to go" :
"update %d: %s %u to %s[%s]/%s:%hu {%u}",
seq, procname(this->proc),
this->args.create_args.id.nii_object,
l->name, inet_ntoa(sin.sin_addr), l->tag,
ntohs(sin.sin_port), this->checksum,
nprocs - i);
} else {
system_log(LOG_DEBUG,
0 == ((nprocs - i) % 50) ?
"update %d: %s to %s[%s]/%s:%hu {%u}, "
"%d procs to go" :
"update %d: %s to %s[%s]/%s:%hu {%u}",
seq, procname(this->proc), l->name,
inet_ntoa(sin.sin_addr), l->tag,
ntohs(sin.sin_port), this->checksum,
nprocs - i);
}
clstat = clnt_call(cl, this->proc, ent->xdr_in,
&this->args, ent->xdr_out, &res, tv);
if (clstat != RPC_SUCCESS) {
struct sockaddr_in us;
int count;
count = sizeof(us);
if (0 != getsockname(sock, (struct sockaddr *)&us,
&count)) {
us.sin_port = htons(-1);
}
system_log(LOG_ERR,
"update %d: %s from port %hu to %s[%s]/%s:%hu "
"RPC error - %s", seq,
procname(this->proc), ntohs(us.sin_port),
l->name, inet_ntoa(sin.sin_addr), l->tag,
ntohs(sin.sin_port), clnt_sperrno(clstat));
clnt_destroy_lock(cl, sock);
FD_CLR(sock, &clnt_fdset);
goto cleanup_locks;
}
if (res.write_res.status != NI_OK) {
struct sockaddr_in us;
int count;
count = sizeof(us);
if (0 != getsockname(sock, (struct sockaddr *)&us,
&count)) {
us.sin_port = htons(-1);
}
system_log(LOG_ERR,
"update %d: %s from port %hu to %s[%s]/%s:%hu "
"failed - %s", seq,
procname(this->proc), ntohs(us.sin_port),
l->name, inet_ntoa(sin.sin_addr), l->tag,
ntohs(sin.sin_port),
ni_error(res.write_res.status));
clnt_destroy_lock(cl, sock);
FD_CLR(sock, &clnt_fdset);
goto cleanup_locks;
}
}
clnt_destroy_lock(cl, sock);
FD_CLR(sock, &clnt_fdset);
l->lastupdate = seq;
l->up_to_date = TRUE;
syslock_unlock(l->lock);
syslock_signal_broadcast(l->lock);
continue;
cleanup_locks:
l->lastupdate = NO_SEQUENCE_NUMBER;
l->up_to_date = FALSE;
syslock_unlock(l->lock);
syslock_signal_broadcast(l->lock);
if (!low_level_success)
{
system_log(LOG_ERR,
"update %d to %s[%s]/%s failed during %s - "
"%s", seq,
l->name, inet_ntoa(sin.sin_addr), l->tag,
msg_stage, msg);
}
}
while (updates)
{
ent = xdr_table_lookup(updates->proc);
xdr_free(ent->xdr_in, (void *)&updates->args);
this = updates->next;
MM_FREE(updates);
updates = this;
}
if (0 == clones_skipped && 0 == clones_current)
{
system_log(LOG_INFO, "update %d sent", seq);
}
else if (0 == clones_skipped && 0 != clones_current)
{
system_log(LOG_INFO,
"update %d sent; %d clone%s included per TS enhancement",
seq, clones_current, (1 == clones_current ? "" : "s"));
}
else if (0 != clones_skipped && 0 == clones_current)
{
system_log(LOG_INFO, "update %d sent; %d clone%s skipped", seq,
clones_skipped, (1 == clones_skipped ? "" : "s"));
}
else
{
system_log(LOG_INFO, "update %d sent; %d clone%s skipped, "
"%d clone%s included per TS enhancement", seq,
clones_skipped, (1 == clones_skipped ? "" : "s"),
clones_current, (1 == clones_current ? "" : "s"));
}
}
static void
fork_push(clone_list clones, notify_list updates, long seq)
{
fork_push_args *args;
char buf[64];
systhread *t;
if (!(args = (fork_push_args *)malloc(sizeof(fork_push_args)))) return;
args->updates = updates;
args->clones = clones;
args->seqno = seq;
syslock_lock(subthread_syslock);
t = systhread_new();
sprintf(buf, "notify-%ld", seq);
systhread_set_name(t, buf);
systhread_run(t, (void(*)(void *))push_thread_stub, (void *)args);
notify_subthread_count++;
syslock_unlock(subthread_syslock);
return;
}
static void
push_thread_stub(fork_push_args *args)
{
push(args->clones, args->updates, args->seqno);
MM_FREE(args);
syslock_lock(subthread_syslock);
notify_subthread_count--;
syslock_signal_send(subthread_syslock);
syslock_unlock(subthread_syslock);
systhread_exit();
}
static const xdr_table_entry *
xdr_table_lookup(unsigned proc)
{
int i;
for (i = 0; i < XDR_TABLE_SIZE; i++)
{
if (xdr_table[i].proc == proc) return (&xdr_table[i]);
}
return NULL;
}
const char *
procname(int procnum)
{
static char *procname_array[] = {
"ping",
"statistics",
"root",
"self",
"parent",
"create",
"destroy",
"read",
"write",
"children",
"lookup",
"list",
"createprop",
"destroyprop",
"readprop",
"writeprop",
"renameprop",
"listprops",
"createname",
"destroyname",
"readname",
"writename",
"rparent",
"listall",
"bind",
"readall",
"crashed",
"resync",
"lookupread"};
return(procnum < (sizeof(procname_array) / sizeof(*procname_array)) ?
procname_array[procnum] :
"*UNKNOWN*");
}
int
notifications_pending(void)
{
int i;
notify_list n;
if (notify_syslock == NULL) return 0;
syslock_lock(notify_syslock);
for (i = 0, n = notifications; NULL != n; n = n->next) i++;
syslock_unlock(notify_syslock);
return i;
}
int
count_notify_subthreads(void)
{
return(notify_subthread_count);
}
int
count_clones(void)
{
return(clone_count);
}
const bool_t
takes_arg(int procnum)
{
switch (procnum)
{
case _NI_RESYNC:
case _NI_RPARENT:
case _NI_ROOT:
case _NI_STATISTICS:
case _NI_PING: return FALSE;
}
return TRUE;
}
unsigned
count_procs(notify_list updates)
{
int i;
notify_list n;
for (i = 0, n = updates; n != NULL; n = n->next) i++;
return i;
}
bool_t
udp_getregister(ni_name name, ni_name tag, struct sockaddr_in sin,
struct timeval tv, nibind_getregister_res *res, char *caller)
{
int sock;
CLIENT *cl;
enum clnt_stat clstat;
char *msg_stage;
char *msg;
sin.sin_port = 0;
msg_stage = "opening (UDP)";
sock = socket_open(&sin, NIBIND_PROG, NIBIND_VERS);
if (sock < 0)
{
msg = "socket_open failed";
goto failed;
}
msg_stage = "creating (UDP)";
FD_SET(sock, &clnt_fdset);
cl = clntudp_create(&sin, NIBIND_PROG, NIBIND_VERS, tv, &sock);
if (cl == NULL)
{
msg = clnt_spcreateerror("binder daemon");
socket_close(sock);
FD_CLR(sock, &clnt_fdset);
goto failed;
}
msg_stage = "connecting (UDP)";
if ((clstat = clnt_call(cl, NIBIND_GETREGISTER,
xdr_ni_name, &tag,
xdr_nibind_getregister_res,
res, tv)) != RPC_SUCCESS)
{
msg = clnt_sperrno(clstat);
clnt_destroy_lock(cl, sock);
FD_CLR(sock, &clnt_fdset);
goto failed;
}
clnt_destroy_lock(cl, sock);
FD_CLR(sock, &clnt_fdset);
return(TRUE);
failed:
system_log(LOG_WARNING, "%s's udp binder connection to %s[%s]/%s "
"failed during %s - %s", caller, name, inet_ntoa(sin.sin_addr),
tag, msg_stage, msg);
return(FALSE);
}
bool_t
tcp_getregister(ni_name name, ni_name tag, struct sockaddr_in sin,
struct timeval tv, nibind_getregister_res *res, char *caller)
{
int sock;
CLIENT *cl;
enum clnt_stat clstat;
char *msg_stage;
char *msg;
sin.sin_port = 0;
msg_stage = "opening (TCP)";
sock = socket_connect(&sin, NIBIND_PROG, NIBIND_VERS);
if (sock < 0)
{
msg = "socket_connect failed";
goto failed;
}
msg_stage = "creating (TCP)";
FD_SET(sock, &clnt_fdset);
cl = clnttcp_create(&sin, NIBIND_PROG, NIBIND_VERS, &sock, 0, 0);
if (cl == NULL)
{
msg = clnt_spcreateerror("binder daemon");
socket_close(sock);
FD_CLR(sock, &clnt_fdset);
goto failed;
}
msg_stage = "connecting (TCP)";
if ((clstat = clnt_call(cl, NIBIND_GETREGISTER,
xdr_ni_name, &tag, xdr_nibind_getregister_res,
res, tv)) != RPC_SUCCESS)
{
msg = clnt_sperrno(clstat);
clnt_destroy_lock(cl, sock);
FD_CLR(sock, &clnt_fdset);
goto failed;
}
clnt_destroy_lock(cl, sock);
FD_CLR(sock, &clnt_fdset);
return(TRUE);
failed:
system_log(LOG_WARNING, "%s's tcp binder connection to %s[%s]/%s "
"failed during %s - %s", caller, name, inet_ntoa(sin.sin_addr),
tag, msg_stage, msg);
return(FALSE);
}
void
notify_mark_clone(const unsigned long addr)
{
clone_list clist;
clone_list clone;
clone_list found_clone = NULL;
struct in_addr t_addr;
clist = clonelist_retain(global_clone_list);
for (clone = clist; clone != NULL; clone = clone->next)
{
if (addr == clone->addr)
{
if (NULL == found_clone)
{
found_clone = clone;
}
else
{
t_addr.s_addr = addr;
system_log(LOG_DEBUG,
"Multiple clones at %s[%s]; can't mark up_to_date",
clone->name, inet_ntoa(t_addr));
clonelist_release(clist);
return;
}
}
}
if (NULL == found_clone)
{
t_addr.s_addr = addr;
system_log(LOG_INFO,
"readall completed from unregistered clone at %s",
inet_ntoa(t_addr));
clonelist_release(clist);
return;
}
t_addr.s_addr = addr;
syslock_lock(found_clone->lock);
found_clone->up_to_date = TRUE;
system_log(LOG_INFO, "clone %s[%s]/%s marked current; was%s being skipped",
found_clone->name, inet_ntoa(t_addr), found_clone->tag,
NO_SEQUENCE_NUMBER == found_clone->lastupdate ? "" : "n't");
syslock_unlock(found_clone->lock);
clonelist_release(clist);
return;
}