|
|
1.1 root 1: #include "../chunix/chsys.h"
2: #include "../chunix/chconf.h"
3: #include "../chaos/chaos.h"
4:
5: /*
6: * Clock level processing.
7: * ch_clock should be called each clock tick (HZ per second)
8: * at a priority equal to or higher that LOCK.
9: *
10: * Terminology:
11: * Packet aging: Retransmitting packets that are not acked within
12: * AGERATE ticks
13: *
14: * Probe: The sending of a SNS packet if not all of the packets
15: * we have sent have been acknowledged
16: *
17: * Responding: Send a SNS every so often to see if the guy is still
18: * alive (after NRESPONDS we declare him dead)
19: *
20: * RFC aging: The retransmission of RFC packets
21: *
22: * Route aging: Increase the cost of transmitting over gateways so we
23: * will use another gateway if the current gateway goes
24: * down.
25: * Route broadcast: If we are connected to more than one subnet, broad
26: * cast our bridge status every BRIDGERATE seconds.
27: *
28: * Interface hung: Checking periodically for dead interfaces (or dead
29: * "other end"'s of point-to-point links).
30: *
31: * These rates might want to vary with the cost of getting to the host.
32: * They also might want to reside in the chconf.h file if they are not a real
33: * network standard.
34: *
35: * Since these rates are dependent on a run-time variable
36: * (This is a good idea if you think about it long enough),
37: * We might want to initialize specific variables at run-time to
38: * avoid recalculation if the profile of chclock is disturbing.
39: */
40: #define MINRATE ORATE /* Minimum of following rates */
41: #define HANGRATE (Chhz>>1) /* How often to check for hung
42: interfaces */
43: #define AGERATE (Chhz) /* Re-xmit pkt if not rcptd in time */
44: #define PROBERATE (Chhz<<3) /* Send SNS to get STS for receipts or
45: to make sure the conn. is alive */
46: #define ORATE (Chhz>>1) /* Xmit current (stream) output packet
47: if not touched in this time */
48: #define TESTRATE (Chhz*45) /* Respond testing rate */
49: #define ROUTERATE (Chhz<<2) /* Route aging rate */
50: #define BRIDGERATE (Chhz*15) /* Routing broadcast rate */
51: #define NRESPONDS 3 /* Test this many times before timing
52: out the connection */
53: #define UPTIME (NRESPONDS*TESTRATE) /* Nothing in this time and
54: the connection is flushed */
55: #define RFCRATE (Chhz*5) /* Retransmit RFC's this often */
56: #define RFCTIME (RFCRATE*CHRFCTRYS) /* Try CHRFCTRYS times to RFC */
57:
58: chtime Chclock;
59:
60: ch_clock()
61: {
62: register struct connection *conn;
63: register struct connection **connptr;
64: register struct packet *pkt;
65: chtime inactive;
66: int probing; /* are we probing this time ? */
67: static chtime nextclk = 1; /* next time to do anything */
68: static chtime nextprobe = 1; /* next time to probe */
69: static chtime nexthang = 1; /* next time to chxtime() */
70: static chtime nextroute = 1; /* next time to age routing */
71: static chtime nextbridge = 1; /* next time to send routing */
72:
73: if (nextclk != ++Chclock)
74: return;
75: nextclk += MINRATE;
76: if (cmp_gt(Chclock, nextprobe)) {
77: probing = 1;
78: nextprobe += PROBERATE;
79: } else
80: probing = 0;
81: if (cmp_gt(Chclock, nexthang)) {
82: chxtime();
83: nexthang += HANGRATE;
84: }
85: if (cmp_gt(Chclock, nextroute)) {
86: chroutage();
87: nextroute += ROUTERATE;
88: }
89: if (cmp_gt(Chclock, nextbridge)) {
90: chbridge();
91: nextbridge += BRIDGERATE;
92: }
93: debug(DNOCLK,return);
94: for (connptr = &Chconntab[0]; connptr < &Chconntab[CHNCONNS]; connptr++)
95: if ((conn = *connptr) == NOCONN)
96: continue;
97: else if (conn->cn_state == CSOPEN) {
98: #ifdef CHSTRCODE
99: /*
100: * Timeout the current output stream packet.
101: * The timeout value should vary per connection.
102: * (shades of x.29!!)
103: */
104: if ((pkt = conn->cn_toutput) != NOPKT &&
105: cmp_gt(Chclock, pkt->pk_time + ORATE) &&
106: !chtfull(conn)) {
107: conn->cn_toutput = NOPKT;
108: /*
109: * We don't care if the packet will
110: * be lost since either the connection
111: * is no longer open anyway, or an
112: * ANSOP was sent in the wrong state.
113: */
114: (void)ch_write(conn, pkt);
115: }
116: #endif
117: if (conn->cn_thead != NOPKT)
118: clkretran(conn);
119: if (probing) {
120: inactive = Chclock - conn->cn_active;
121: if (inactive >= UPTIME)
122: chdead(conn);
123: else if (conn->cn_tacked != conn->cn_tlast &&
124: inactive >= PROBERATE ||
125: inactive >= TESTRATE) {
126: debug(DCONN,
127: printf("Conn #%x: Probe: %D\n",
128: conn->cn_lidx,
129: inactive));
130: sendsns(conn);
131: }
132: }
133: } else if (conn->cn_state == CSRFCSENT) {
134: /*
135: * The RFC packet, if it has finished being sent out
136: * will be at cn_thead. If it is still in the process
137: * of being sent it will not be there yet.
138: */
139: pkt = conn->cn_thead;
140: inactive = Chclock - conn->cn_active;
141: if (inactive >= RFCTIME) {
142: debug(DCONN|DABNOR, printf("Conn #%x: RFC Timeout\n",conn->cn_lidx));
143: clsconn(conn, CSCLOSED, NOPKT);
144: } else if (pkt != NOPKT &&
145: cmp_gt(Chclock, pkt->pk_time + RFCRATE)) {
146: debug(DCONN|DABNOR,printf("Conn #%x: RFC Retransmit\n",conn->cn_lidx));
147: conn->cn_ttail = conn->cn_thead = NOPKT;
148: senddata(pkt);
149: }
150: }
151: }
152:
153: clkretran(conn)
154: struct connection *conn;
155: {
156: register struct packet *pkt, **opkt;
157: register struct packet *lastpkt;
158: struct packet *firstpkt = NOPKT;
159:
160: for (opkt = &conn->cn_thead; pkt = *opkt;)
161: if (cmp_gt(Chclock, pkt->pk_time + AGERATE)) {
162: if (firstpkt == NOPKT)
163: firstpkt = pkt;
164: else
165: lastpkt->pk_next = pkt;
166: lastpkt = pkt;
167: *opkt = pkt->pk_next;
168: pkt->pk_next = NOPKT;
169: } else
170: opkt = &pkt->pk_next;
171: if (firstpkt != NOPKT) {
172: debug(DCONN|DABNOR,
173: printf("Conn #%x: Rexmit (op:%d, pkn:%d)\n",
174: conn->cn_lidx, firstpkt->pk_op,
175: firstpkt->pk_pkn));
176: senddata(firstpkt);
177: }
178: }
179: /*
180: * The connection has been inactive too long, close it.
181: */
182: chdead(conn)
183: register struct connection *conn;
184: {
185: static char tomsg[] = "Foreign host not responding";
186: register struct packet *pkt;
187:
188: debug(DCONN|DABNOR,printf("Conn #%x: Timeout\n", conn->cn_lidx));
189: if ((pkt = pkalloc(sizeof(tomsg), 1)) != NOPKT) {
190: pkt = pktstr(pkt, tomsg, sizeof(tomsg));
191: pkt->pk_op = LOSOP;
192: }
193: clsconn(conn, CSINCT, pkt);
194: }
195: /*
196: * Increase the cost of accessing a subnet via a gateway
197: */
198: chroutage()
199: {
200: register struct chroute *r;
201:
202: for (r = Chroutetab; r < &Chroutetab[CHNSUBNET]; r++)
203: if ((r->rt_type == CHBRIDGE || r->rt_type == CHDIRECT) &&
204: r->rt_cost < CHHCOST)
205: r->rt_cost++;
206: }
207: /*
208: * Send routing packets on all directly connected subnets, unless we are on
209: * only one.
210: */
211: chbridge()
212: {
213: register struct chroute *r;
214: register struct packet *pkt;
215: register struct rut_data *rd;
216: register int ndirect;
217: register int n;
218:
219: /*
220: * Count the number of subnets to which we are directly connected.
221: * If not more than one, then we are not a bridge and shouldn't
222: * send out routing packets at all.
223: * While we're at it, count the number of subnets we know we
224: * have any access to. This number determines the size of the
225: * routine packet we need to send, if any.
226: */
227: n = ndirect = 0;
228: for (r = Chroutetab; r <= &Chroutetab[CHNSUBNET]; r++)
229: switch(r->rt_type) {
230: case CHDIRECT:
231: ndirect++;
232: default:
233: n++;
234: break;
235: case CHNOPATH:
236: ;
237: }
238: if (ndirect <= 1 ||
239: (pkt = pkalloc(n * sizeof(struct rut_data), 1)) == NOPKT)
240: return;
241: /*
242: * Build the routing packet to send out on each directly connected
243: * subnet. It is complete except for the cost of the directly
244: * connected subnet we are sending it out on. This cost must be
245: * added to each entry in the packet each time it is sent.
246: */
247: pkt->pk_len = n * sizeof(struct rut_data);
248: pkt->pk_op = RUTOP;
249: pkt->pk_type = pkt->pk_daddr = pkt->pk_sidx = pkt->pk_didx = 0;
250: pkt->pk_next = NOPKT;
251: rd = pkt->pk_rutdata;
252: for (n = 0, r = Chroutetab; r < &Chroutetab[CHNSUBNET]; r++, n++)
253: if (r->rt_type != CHNOPATH) {
254: rd->pk_subnet = n;
255: rd->pk_cost = r->rt_cost;
256: rd++;
257: }
258: /*
259: * Now send out this packet on each directly connected subnet.
260: * ndirect becomes zero on last such subnet.
261: */
262: for (r = Chroutetab; r < &Chroutetab[CHNSUBNET]; r++)
263: if (r->rt_type == CHDIRECT)
264: sendrut(pkt, r->rt_xcvr, r->rt_cost, --ndirect);
265: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.