cache.cc revision 004388ebfdfe2ed7dfd2d153a876dfcc22d2c006
/*
* 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 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include "mt.h"
#include <stdio.h>
#include <ctype.h>
#include <malloc.h>
#include <string.h>
#include <values.h>
#include <syslog.h>
#include "cache.h"
#include "cold_start.h"
#include "nis_cache.h"
int __nis_debuglevel = 0;
extern char *__nis_server;
extern "C" {
static int compare(const void *, const void *);
}
{
gen = 0;
}
{
}
{
/* see if directory is already in cache */
if (err == NIS_SUCCESS)
return (err);
/* Exists in local cache, but has expired; refresh it */
/*
* If we're still getting NIS_CACHEEXPIRED, we'll
* continue using the expired object until the next
* refresh attempt.
*/
if (err == NIS_CACHEEXPIRED)
return (NIS_SUCCESS);
}
/* get directory object */
if (err != NIS_SUCCESS)
return (err);
/* lookup directory again (it should be there) */
return (err);
}
{
int i;
/*
* See if the directory is in the cache and, if not,
* load it.
*/
/* Exists in local cache, but has expired; refresh it */
/*
* If we're still getting NIS_CACHEEXPIRED, we'll
* continue using the expired object until the next
* refresh attempt.
*/
if (err == NIS_CACHEEXPIRED)
err = NIS_SUCCESS;
}
if (err != NIS_SUCCESS) {
/* directory is not in the cache, load it */
if (err != NIS_SUCCESS)
return (err);
if (err != NIS_SUCCESS)
return (err);
}
/* see if we have a binding to the master server */
break;
}
return (NIS_SUCCESS);
}
/* we have the directory, but not the master server */
if (err != NIS_SUCCESS)
return (err);
/*
* Search for the directory again. It should be there and
* should have a binding for the master server.
*/
if (err == NIS_SUCCESS)
return (err);
}
{
binding = (nis_bound_directory *)
if (binding == 0)
return (NIS_NOMEMORY);
return (NIS_NOMEMORY);
}
/* check to see if we already have a binding to the server */
return (NIS_SUCCESS);
}
/* we don't have a binding, ping the server */
if (err != NIS_SUCCESS)
return (err);
binding = (nis_bound_directory *)
if (binding == 0)
return (NIS_NOMEMORY);
return (NIS_NOMEMORY);
}
return (NIS_SUCCESS);
}
{
return (loadDirectory(dname, 0));
}
{
int i;
int length;
char **names;
int home_refreshed = 0;
int *refreshed;
/* get list of names between coldstart directory and target */
if (err != NIS_SUCCESS)
return (err);
return (NIS_NOMEMORY);
}
/* get binding for coldstart directory */
if (err != NIS_SUCCESS) {
if (err == NIS_CACHEEXPIRED) {
}
/* need to reload cold start */
if (!readColdStart()) {
return (NIS_COLDSTART_ERR);
} else {
if (err == NIS_CACHEEXPIRED) {
}
if (err != NIS_SUCCESS)
return (err);
}
}
if (length == 0 && force_finddir) {
/*
* It's the cold start directory, and we really want to
* retrieve a new copy from the NIS+ server.
*/
err = NIS_NOMEMORY;
/* We now expect to just skip the for-loop below */
/* Still skipping for-loop */
} else {
}
}
for (i = 0; i < length; i++) {
if (err == NIS_SUCCESS) {
} else {
if (err == NIS_CACHEEXPIRED) {
new_binding = NULL;
}
err = NIS_NOMEMORY;
break;
if (i == 0 && home_refreshed ||
i != 0 && refreshed[i-1]) {
break;
}
}
if (i == 0)
home_refreshed = 1;
else
goto again;
break;
} else {
}
if (err != NIS_SUCCESS)
break;
}
/* get the newly stored binding */
if (err != NIS_SUCCESS)
break;
}
}
return (err);
}
{
int i;
int j;
int n;
int rank;
int bound;
int count;
int generation;
int nep;
void *local_interfaces;
int optimal_rank = -1;
int min_rank = -1;
int max_rank = -1;
/*
* If we are rpc.nisd, then we want to make calls into
* our own data base. Check to see if we are listed.
*/
return (NIS_SUCCESS);
count = 0;
for (i = 0; i < nsrv; i++)
return (NIS_NOMEMORY);
generation = nextGeneration();
n = 0;
for (i = 0; i < nsrv; i++) {
for (j = 0; j < nep; j++) {
if (bound)
optimal_rank = rank;
n++;
}
}
/*
* If we already have an optimal server (min_rank == optimal_rank),
* then we only want to ping other optimal servers. This gives
* us load balancing among optimal servers.
*
* If we already have a server (min_rank != -1), but it is not
* an optimal server, then we only want to ping servers that
* have a better ranking than our current server. We don't
* want to do load balancing on non-optimal servers.
*/
if (min_rank == optimal_rank) {
}
/*
* If pref_option is PREF_ONLY_VAL, then we only want to
* ping servers that have a preference set (rank != MAXINT).
* However, if we don't have any preferred servers at all
* (optimal_rank == MAXINT), then we ignore the pref_option
* because that would prevent us from being able to talk
* to any servers at all.
*
* If __nis_server is specified, then we want to behave as
* if PREF_ONLY_VAL is set so that we are guaranteed to
* use the given server if it serves the directory.
*/
if (err == NIS_SUCCESS) {
/* extractAddress will free binding.bep_val for us */
}
}
return (err);
}
int
{
int generation;
if (err == NIS_SUCCESS) {
return (1); /* someone else did the work */
} else if (err == NIS_CACHEEXPIRED) {
}
/*
* If this is the cold start directory, then the normal bindReplica()
* path through the code will re-load from the cold start file without
* going to the NIS+ server. So, we short-circuit by forcing a read
* from the wire.
*/
/*
* Temporary problem (?); no need to put back old binding,
* since we never removed it in the first place.
*/
if (err != NIS_SUCCESS) {
return (0);
}
} else {
}
err != NIS_BADOBJECT) {
/*
* Temporary problem (?); put back the old binding.
* The createBinding()
* routine expects an allocated directory object,
* so we copy the directory object. We also clear
* the directory object in the binding so that
* it is not freed in nis_free_binding().
*/
if (dobj) {
sizeof (directory_obj));
(void) createBinding(dobj);
}
return (0);
}
return (1);
}
int
{
return (0); /* can't refresh */
#ifdef NOTYET
/*
* This code does not work yet.
*/
return (0); /* can't refresh */
}
/* someone else did the work already */
return (1);
}
/* get new server address */
return (0); /* can't refresh */
}
return (1);
#endif /* NOTYET */
}
int
{
return (0);
#ifdef NOTYET
/* XXX STILL NEED TO DO THIS CODE XXX */
#endif /* NOTYET */
}
{
return (0);
return (0);
}
if (err != NIS_SUCCESS)
return (0);
return (1);
}
{
/* set default to 1 hour */
return (0);
return (0);
}
ul = loadPreferredServers();
if (ul > 0)
if (err != NIS_SUCCESS)
return (0);
return (1);
}
{
int st;
if (dobj == 0) {
return (NIS_NOMEMORY);
}
if (!st) {
return (NIS_SYSTEMERROR);
}
return (createBinding(dobj));
}
{
int nsrv;
if (err != NIS_SUCCESS) {
return (err);
}
binding = (nis_bound_directory *)
return (NIS_NOMEMORY);
}
/*
* Record any new or modified public keys from this directory.
* Note that by doing this after the pingServers() above, we're
* implicitly assuming that the server ping can proceed without
* public keys. That's true right now, but caveat emptor.
*/
/* set generation and copy directory object into binding */
return (NIS_SUCCESS);
}
void
{
return;
if (__nis_debuglevel == 6) {
} else {
if (__nis_debuglevel)
}
}
void
{
return;
if (__nis_debuglevel == 6) {
} else {
if (__nis_debuglevel)
}
}
void
{
return;
else
(void) printf(" local");
(void) printf(" remote");
(void) printf(" remote(%d)",
else
(void) printf("\n");
}
{
return (NULL);
return (act);
}
void
{
if (act) {
}
}
void *
{
int status;
void *data;
(char *)binding);
return (NULL);
if (!status) {
return (NULL);
}
return (data);
}
{
binding = (nis_bound_directory *)
if (binding == 0)
return (NULL);
return (NULL);
}
return (binding);
}
void *
{
int status;
void *data;
(char *)act);
return (NULL);
if (!status) {
return (NULL);
}
return (data);
}
{
if (act == 0)
return (NULL);
return (NULL);
}
return (act);
}
{
}
int
{
int n;
n = gen++;
return (n);
}
void
{
int i;
char *name;
case NIS :
(void) printf("NIS:");
break;
case SUNYP :
(void) printf("YP:");
break;
case DNS :
(void) printf("DNS:");
break;
default :
break;
}
(void) printf("\"%d:%d:%d\"",
if (i == 0)
(void) printf(":");
else
(void) printf(",");
}
(void) printf("\n");
}
int
{
int nlen;
int rank;
/*
* If __nis_server is specified, then we want that server to
* have the best ranking and all other server to have the
* worst ranking.
*/
if (__nis_server) {
return (0);
}
return (MAXINT);
}
return (rank);
return (0);
return (MAXINT);
}
void
{
sizeof (nis_bound_endpoint), compare);
}
extern "C" {
static
int
{
}
}
void
{
}
void
{
prefer.backupList();
}
void
{
}
void
{
}
void
{
}
void
{
}
}
}
void
{
int rank;
int sign;
char *interface;
return;
while (*value) {
rank = 0;
value++;
if (*value == '\0')
break;
/* server info */
*value != '/')
value++;
/* interface info */
*value++ = '\0';
value ++;
}
/* weight info */
if (*value == '(') {
*value++ = '\0';
if (*value == '-') {
value++;
sign = -1;
} else {
if (*value == '+')
value++;
sign = 1;
}
rank = 0;
value++;
}
if (*value == ')')
value++;
}
*value++ = '\0';
if (rank < 0)
else
}
}
/*
* Create active server entries for each bound endpoint and then
* free the list of bound endpoints. This allows us to pack
* a bound directory without the bound endpoints, which saves
* space.
*/
void
{
int i;
int next_gen;
next_gen = nextGeneration();
for (i = 0; i < nbep; i++) {
(char *)&bep[i]);
continue;
}
if (activeCheck(ep)) {
(char *)&bep[i]);
continue;
}
act = (nis_active_endpoint *)
(char *)&bep[i]);
continue;
}
else
activeRemove(ep, 0);
}
}
/*
* Create a bound endpoint for every active server for a directory.
*/
void
{
int i;
int j;
int n;
int nsrv;
int nep;
int nbep = 0;
int min_rank = -1;
}
/* count the number of bound endpoints */
for (i = 0; i < nsrv; i++) {
for (j = 0; j < nep; j++) {
if (activeCheck(&ep[j]))
nbep++;
}
}
if (nbep == 0) {
return;
}
return;
}
/* fill in list of bound endpoints */
n = 0;
for (i = 0; i < nsrv; i++) {
for (j = 0; j < nep; j++) {
continue;
/*
* Another thread could have changed
* the list of active servers.
*/
if (n >= nbep)
break;
n++;
}
}
/*
* If we only want to talk to preferred servers, remove
* non-preferred servers (rank == MAXINT). If the directory
* is not served by a preferred server at all, then we
* ignore the option.
*/
for (i = 0; i < n; i++) {
break;
}
}
}
}
void
{
int i;
int n;
int rank;
void *local_interfaces = __inet_get_local_interfaces();
n = getAllActive(&actlist);
for (i = 0; i < n; i++) {
} else {
activeFree(actlist[i]);
}
}
}
/*
* These are stubs so that we can avoid using pure virtual functions
* in the NisCache class. If we use pure virtual functions, then
* applications would have to link with -lC.
*/
int
{
return (1);
}
/*
* Dot File routines. Dot file format:
* line 1: TTL "%u"
* line 2: [optional] server list separated by comma "%s/%s(%d)"
* line 3: [optional] preference type "%s"
*
* Load from dot file. If file exists and TTL has not expired, load the
* information. Otherwise, don't bother.
*/
{
char *p, buf[2048];
size_t l;
return (0);
/*
* read TTL: TTL must be the first line in this file
* unless the file is empty.
*/
/* empty file */
return (0);
}
if (!isdigit(*p)) {
/* invalid TTL */
return (0);
}
/* TTL expired */
return (0);
}
/*
* read preferred server list
* This line can be empty
*/
/* file without any preferred info */
return (exptime);
}
l = strlen(p) - 1;
if (p[l] == '\n')
p[l] = '\0';
mergePreference(p);
/*
* read options: valid options are "all" and
* "pref_only". Default is "all".
*/
/* file without any preferred info */
return (exptime);
}
l = strlen(p) - 1;
if (p[l] == '\n')
p[l] = '\0';
if (l != 0)
mergeOption(p);
else
/* ignore the rest of the file */
return (exptime);
}
{
return (0);
}
{
return (0);
}
int
{
return (1);
}
{
return (NIS_SYSTEMERROR);
}
void
{
}
void
{
}
void
{
}
int
{
return (0);
}
int
{
return (0);
}
int
{
return (0);
}
void
{
}
void
{
}
int
{
return (0);
}
int
{
return (0);
}
char *
{
return (cold_start_dir);
}
int
return (refreshBinding(binding));
}
/*
* HostList Routines.
*/
{
}
{
while (entries) {
}
}
void
{
while (entries) {
}
}
void
{
while (old_entries) {
del = old_entries;
}
old_entries = NULL;
}
void
{
if (old_entries)
}
void
{
if (entries)
deleteList();
old_entries = NULL;
}
void
{
int dummy;
return;
/* don't add value again if it is already there */
return;
return;
if (srv) {
return;
}
} else
return;
}
} else
while (scan) {
}
if (prev)
else
}
int
{
if (interface) {
== 0) {
return (1);
}
} else {
/*
* To match: both interfaces must
* be NULL.
*/
return (1);
}
}
}
}
return (0);
}
/*
* NOTE: uaddr and name must always have a value.
*
* Matching criteria:
* 1. name argument and scan->name must match
* 2. a) find entry with interface matching the uaddr (IP
* address portion).
* b) if a) is not found, find entry with NO interface defined
* (wildcard).
*/
int
{
found = 0;
ulen--;
ulen--;
if (!found) {
found = 1;
}
} else {
== 0) {
found = 1;
break;
}
}
}
}
return (found);
}
/*
* Check to see if a directory object is served by a preferred
* server (rank != MAXINT).
*/
int
{
int i;
int j;
int rank;
int nep;
int nsrv;
for (i = 0; i < nsrv; i++) {
for (j = 0; j < nep; j++) {
return (1);
}
}
}
return (0);
}
int
{
int n = 0;
if (n++)
}
return (n);
}
void
{
pref_option = value;
}
void
{
switch (pref_option) {
case PREF_ALL_VAL:
break;
case PREF_ONLY_VAL:
break;
}
}