[BACK]Return to ServerHost.c++ CVS log [TXT][DIR] Up to [Development] / fam / fam

Annotation of fam/fam/ServerHost.c++, Revision 1.1.1.1

1.1       trev        1: //  Copyright (C) 1999 Silicon Graphics, Inc.  All Rights Reserved.
                      2: //
                      3: //  This program is free software; you can redistribute it and/or modify it
                      4: //  under the terms of version 2 of the GNU General Public License as
                      5: //  published by the Free Software Foundation.
                      6: //
                      7: //  This program is distributed in the hope that it would be useful, but
                      8: //  WITHOUT ANY WARRANTY; without even the implied warranty of
                      9: //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  Further, any
                     10: //  license provided herein, whether implied or otherwise, is limited to
                     11: //  this program in accordance with the express provisions of the GNU
                     12: //  General Public License.  Patent licenses, if any, provided herein do not
                     13: //  apply to combinations of this program with other product or programs, or
                     14: //  any other product whatsoever.  This program is distributed without any
                     15: //  warranty that the program is delivered free of the rightful claim of any
                     16: //  third person by way of infringement or the like.  See the GNU General
                     17: //  Public License for more details.
                     18: //
                     19: //  You should have received a copy of the GNU General Public License along
                     20: //  with this program; if not, write the Free Software Foundation, Inc., 59
                     21: //  Temple Place - Suite 330, Boston MA 02111-1307, USA.
                     22:
                     23: #include "ServerHost.h"
                     24:
                     25: #include <netdb.h>
                     26: #include <rpc/rpc.h>
                     27: #include <rpc/pmap_clnt.h>
                     28: #include <string.h>
                     29: #include <sys/socket.h>
                     30: #include <unistd.h>
                     31:
                     32: #include "FileSystem.h"
                     33: #include "Event.h"
                     34: #include "Listener.h"
                     35: #include "Log.h"
                     36: #include "Pollster.h"
                     37: #include "Scheduler.h"
                     38: #include "ServerConnection.h"
                     39:
                     40: ///////////////////////////////////////////////////////////////////////////////
                     41: //  Construction/Destruction
                     42:
                     43: ServerHost::ServerHost(const hostent& hent)
                     44:     : refcount(0), connector(Listener::FAMPROG, Listener::FAMVERS,
                     45: 		((in_addr *) hent.h_addr)->s_addr, connect_handler, this),
                     46:       connection(NULL), unique_request(1), deferred_scans(NULL), last(NULL),
                     47:       min_time(0)
                     48: {
                     49:     // Save first component of full hostname.
                     50:
                     51:     char *p = strchr(hent.h_name, '.');
                     52:     unsigned int nchar;
                     53:     if (p)
                     54: 	nchar = p - hent.h_name;
                     55:     else
                     56: 	nchar = strlen(hent.h_name);
                     57:
                     58:     myname = new char[nchar + 1];
                     59:     (void) strncpy(myname, hent.h_name, nchar);
                     60:     myname[nchar] = '\0';
                     61: }
                     62:
                     63: ServerHost::~ServerHost()
                     64: {
                     65:     assert(!active());
                     66:     Scheduler::remove_onetime_task(deferred_scan_task, this);
                     67:     if (is_connected())
                     68:     {	delete connection;
                     69: 	Scheduler::remove_onetime_task(timeout_task, this);
                     70:     }
                     71:     else
                     72: 	Pollster::forget(this);
                     73:     delete [] myname;
                     74:
                     75:     DeferredScan *ds = deferred_scans, *dsp;
                     76:     while (ds != NULL)
                     77:     {
                     78:         dsp = ds;
                     79:         ds = ds->next;
                     80:         delete dsp;
                     81:     }
                     82: }
                     83:
                     84: //////////////////////////////////////////////////////////////////////////////
                     85: //  Activation.  "Active" means that something on this host needs monitoring.
                     86:
                     87: void
                     88: ServerHost::activate()
                     89: {
                     90:     if (is_connected())
                     91:         Scheduler::remove_onetime_task(timeout_task, this);
                     92:     else
                     93:     {   connector.activate();
                     94: 	Pollster::watch(this);
                     95:     }
                     96: }
                     97:
                     98: void
                     99: ServerHost::deactivate()
                    100: {
                    101:     assert(!active());
                    102:     if (is_connected())
                    103:     {   timeval t;
                    104: 	(void) gettimeofday(&t, NULL);
                    105: 	t.tv_sec += Pollster::interval();
                    106: 	Scheduler::install_onetime_task(t, timeout_task, this);
                    107:     }
                    108:     else
                    109:     {   connector.deactivate();
                    110: 	Pollster::forget(this);
                    111:     }
                    112: }
                    113:
                    114: void
                    115: ServerHost::timeout_task(void *closure)
                    116: {
                    117:     ServerHost *host = (ServerHost *) closure;
                    118:     assert(host->is_connected());
                    119:     Log::debug("disconnecting from server fam@%s "
                    120: 	       "after %d seconds of inactivity",
                    121: 	       host->name(), Pollster::interval());
                    122:     delete host->connection;
                    123:     host->connection = NULL;
                    124: }
                    125:
                    126: //////////////////////////////////////////////////////////////////////////////
                    127: //  Connection.  Both connection and disconnection are async. events.
                    128:
                    129: void
                    130: ServerHost::connect_handler(int fd, void *closure)
                    131: {
                    132:     ServerHost *host = (ServerHost *) closure;
                    133:     assert(host->active());
                    134:     assert(!host->is_connected());
                    135:     host->connection = new ServerConnection(fd, event_handler,
                    136: 					    disconnect_handler, host);
                    137:     Pollster::forget(host);
                    138:
                    139:     //  Tell the server's fam who we are.
                    140:
                    141:     char myname[MAXHOSTNAMELEN + 11];
                    142:     (void) strcpy(myname, "client fam@");
                    143:     int rc = gethostname(myname + 11, sizeof myname - 11);
                    144:     assert(rc == 0);
                    145:     host->connection->send_name(myname);
                    146:     Log::debug("connected to server fam@%s", host->name());
                    147:
                    148:     //  Tell the server's fam about existing requests.
                    149:
                    150:     for (Request r = host->requests.first(); r; r = host->requests.next(r))
                    151:     {   ClientInterest *ci = host->requests.find(r);
                    152: 	char remote_path[PATH_MAX];
                    153: 	ci->filesystem()->hl_map_path(remote_path, ci->name(), ci->cred());
                    154: 	host->connection->send_monitor(ci->type(), r, remote_path, ci->cred());
                    155: 	Log::debug("told server fam@%s: request %d monitor file \"%s\"",
                    156: 		   host->name(), r, remote_path);
                    157: 	if (!ci->active())
                    158: 	    host->send_suspend(r);
                    159:     }
                    160: }
                    161:
                    162: void
                    163: ServerHost::disconnect_handler(void *closure)
                    164: {
                    165:     ServerHost *host = (ServerHost *) closure;
                    166:     Log::debug("lost connection to server fam@%s", host->name());
                    167:     if (host->active()) {
                    168:         assert(host->is_connected());
                    169:         delete host->connection;
                    170:         host->connection = NULL;
                    171:         Pollster::watch(host);
                    172:         host->connector.activate();		// Try to reconnect.
                    173:     } else {
                    174:         // We're in the timeout period waiting to close the
                    175:         // connection.  Remove the timeout callback and don't poll
                    176:         // this host
                    177:         Scheduler::remove_onetime_task(timeout_task, host);
                    178:         delete host->connection;
                    179:         host->connection = NULL;
                    180:     }
                    181: }
                    182:
                    183: ///////////////////////////////////////////////////////////////////////////////
                    184: //  Input.  For every event of interest, we perform an immediate scan
                    185: //  and then we queue a second scan to be done later on.  This is
                    186: //  necessary because NFS caches attribute information and we have to
                    187: //  wait for old cached info to be out of date.
                    188: //
                    189: //  For "Changed" events, we save the path because we need it to look
                    190: //  up a DirEntry.  We don't save the result of the first lookup
                    191: //  because result may become invalid while we're sleeping.
                    192: //
                    193: //  There is no way to avoid the deferred scan short of adding a
                    194: //  hook in the kernel to invalidate an entry in the attribute cache.
                    195:
                    196: void
                    197: ServerHost::event_handler(const Event* event, Request r,
                    198: 					  const char *path, void *closure)
                    199: {
                    200:     ServerHost *host = (ServerHost *) closure;
                    201:     Log::debug("server fam@%s said request %d \"%s\" %s",
                    202: 	       host->name(), r, path, event->name());
                    203:
                    204:     //  If we care about this event, tell the ClientInterest to scan itself.
                    205:     //	Also enqueue a deferred task to rescan later.
                    206:
                    207:     if (*event == Event::Changed || *event == Event::Deleted ||
                    208: 	*event == Event::Created || *event == Event::Exists)
                    209:     {
                    210: 	ClientInterest *cip = host->requests.find(r);
                    211: 	if (!cip)
                    212: 	    return;
                    213: 	Interest *ip;
                    214:
                    215: 	if (*event == Event::Changed || *event == Event::Deleted)
                    216: 	{   ip = cip->find_name(path);
                    217: 	    if (!ip)
                    218: 		return;
                    219: 	}
                    220: 	else
                    221: 	{   ip = cip;
                    222: 	    path = NULL;
                    223: 	}
                    224: 	ip->scan();
                    225: 	int wait = cip->filesystem()->get_attr_cache_timeout();
                    226: 	if (wait > 0) {
                    227:             host->defer_scan(wait < RETRY_INTERVAL ?
                    228:                              wait :
                    229:                              RETRY_INTERVAL,(int)((wait-1)/RETRY_INTERVAL),
                    230:                              r, path);
                    231:         }
                    232:     }
                    233: }
                    234:
                    235: inline
                    236: ServerHost::DeferredScan::DeferredScan(int then, int rtrys, Request r, const char *s)
                    237:     : when(then), retries(rtrys), next(NULL), myrequest(r)
                    238: {
                    239:     assert(!s || strlen(s) < sizeof mypath);
                    240:     if (s)
                    241:     {
                    242: 	strncpy(mypath, s, (sizeof mypath) - 1);
                    243:         mypath[(sizeof mypath) - 1] = '\0';
                    244:     }
                    245:     else
                    246: 	mypath[0] = '\0';
                    247: }
                    248:
                    249: void
                    250: ServerHost::defer_scan(int when, int retries, Request r, const char *path)
                    251: {
                    252:     timeval t;
                    253:     (void) gettimeofday(&t, NULL);
                    254:     int then = t.tv_sec + when + 1;
                    255:
                    256:     DeferredScan *ds = new DeferredScan(then, retries, r, path);
                    257:     //  In most cases, our new element will go either
                    258:     //  at the beginning or end of the list.
                    259:     if ((deferred_scans == NULL) || (deferred_scans->when >= then))
                    260:     {
                    261:         ds->next = deferred_scans;
                    262:         deferred_scans = ds;
                    263:         if (last == NULL) last = ds;
                    264:     }
                    265:     else if (last->when <= then)
                    266:     {
                    267:         last = last->next = ds;
                    268:     }
                    269:     else
                    270:     {
                    271:         //  It's in the middle after all.  Put it in the right spot.
                    272:         DeferredScan *prev = deferred_scans;
                    273:         while ((prev->next != NULL) && (prev->next->when < then))
                    274:         {
                    275:             prev = prev->next;
                    276:         }
                    277:         ds->next = prev->next;
                    278:         prev->next = ds;
                    279:         //  last still points to an element after ds.
                    280:     }
                    281:
                    282:     //  If this new request needs to happen before our previously-first task,
                    283:     //  or we didn't have any task scheduled at all, tell the scheduler.
                    284:     if (!min_time || then < min_time)
                    285:     {	if (min_time)
                    286: 	    Scheduler::remove_onetime_task(deferred_scan_task, this);
                    287: 	min_time = then;
                    288: 	timeval t = { then, 0 };
                    289: 	Scheduler::install_onetime_task(t, deferred_scan_task, this);
                    290:     }
                    291: }
                    292:
                    293: void
                    294: ServerHost::deferred_scan_task(void *closure)
                    295: {
                    296:     ServerHost *host = (ServerHost *) closure;
                    297:     int& min_time = host->min_time;
                    298:     DeferredScan *ds = host->deferred_scans, *dsp;
                    299:     assert(ds);
                    300:     if(ds == NULL) return;
                    301:
                    302:     bool changed;
                    303:
                    304:     timeval t;
                    305:     (void) gettimeofday(&t, NULL);
                    306:     while ((ds != NULL) && (ds->when <= t.tv_sec))
                    307:     {
                    308:         ClientInterest *cip = host->requests.find(ds->request());
                    309: 	if (cip)
                    310: 	{
                    311:             Interest *ip = ds->path() ? cip->find_name(ds->path()) : cip;
                    312: 	    if (ip)
                    313:             {
                    314:                 Log::debug("Handing a defered scan on: %s (Request %i)",
                    315:                            ip->name(), ds->request());
                    316:                 changed = ip->scan();
                    317:                 if (!changed) {
                    318:                     if (ds->retries > 0) {
                    319:                         Log::debug(
                    320:                             "Nothing changed, so rescheduling for %i seconds "
                    321:                             "(%i retries left)", RETRY_INTERVAL, ds->retries-1);
                    322:                         host->defer_scan(RETRY_INTERVAL, ds->retries-1, ds->request(), ds->path());
                    323:                     }
                    324:                 }
                    325:             }
                    326:         }
                    327:         dsp = host->deferred_scans;
                    328:         ds = host->deferred_scans = ds->next;
                    329:         if (ds == NULL) host->last = NULL;
                    330:         delete dsp;
                    331:     }
                    332:     if (ds != NULL)
                    333:     {
                    334:         //  We still have some deferred scans which need to happen later.
                    335:         min_time = ds->when;
                    336:         timeval t = { ds->when, 0 };
                    337:         Scheduler::install_onetime_task(t, deferred_scan_task, host);
                    338:     }
                    339:     else min_time = 0;
                    340: }
                    341:
                    342: ///////////////////////////////////////////////////////////////////////////////
                    343: //  Output
                    344:
                    345: Request
                    346: ServerHost::send_monitor(ClientInterest *ci,
                    347: 			 ClientInterest::Type type,
                    348: 			 const char *remote_path)
                    349: {
                    350:     if (!active())
                    351: 	activate();
                    352:
                    353:     //  Find a unique request number.
                    354:
                    355:     Request r = unique_request++;
                    356:     assert(!requests.find(r));
                    357:
                    358:     //  Send the monitor message to the remote fam.
                    359:
                    360:     if (is_connected())
                    361:     {   connection->send_monitor(type, r, remote_path, ci->cred());
                    362: 	Log::debug("told server fam@%s: request %d monitor file \"%s\"",
                    363: 		   name(), r, remote_path);
                    364:     }
                    365:
                    366:     //  Store the request number in the request table.
                    367:
                    368:     requests.insert(r, ci);
                    369:     return r;
                    370: }
                    371:
                    372: void
                    373: ServerHost::send_cancel(Request r)
                    374: {
                    375:     assert(requests.find(r));
                    376:     if (connection)
                    377:     {   connection->send_cancel(r);
                    378: 	Log::debug("told server fam@%s: cancel request %d", name(), r);
                    379:     }
                    380:     requests.remove(r);
                    381:     if (requests.size() == 0)
                    382: 	deactivate();
                    383: }
                    384:
                    385: void
                    386: ServerHost::send_suspend(Request r)
                    387: {
                    388:     if (connection)
                    389:     {   connection->send_suspend(r);
                    390: 	Log::debug("told server fam@%s: suspend request %d", name(), r);
                    391:     }
                    392: }
                    393:
                    394: void
                    395: ServerHost::send_resume(Request r)
                    396: {
                    397:     if (connection)
                    398:     {   connection->send_resume(r);
                    399: 	Log::debug("told server fam@%s: resume request %d", name(), r);
                    400:     }
                    401: }
                    402:
                    403: //////////////////////////////////////////////////////////////////////////////
                    404: //  Polling
                    405:
                    406: void
                    407: ServerHost::poll()
                    408: {
                    409:     for (Request r = requests.first(); r; r = requests.next(r))
                    410: 	requests.find(r)->poll();
                    411: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>