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>