|
|
1.1 root 1: #include "../chunix/chsys.h"
2: #include "../chunix/chconf.h"
3: #include "../chaos/chaos.h"
4:
5: /*
6: * User (top level) interface routines. Mostly assumed called from low
7: * priority unless otherwise mentioned.
8: */
9: static struct packet *rfcseen; /* used by ch_rnext and ch_listen */
10: /*
11: * Open a connection (send a RFC) given a destination host a RFC
12: * packet, and a default receive window size.
13: * Return the connection, on which the RFC has been sent.
14: * The connection is not necessarily open at this point.
15: */
16: struct connection *
17: ch_open(destaddr, rwsize, pkt)
18: struct packet *pkt;
19: {
20: register struct connection *conn;
21:
22: if ((conn = allconn()) == NOCONN) {
23: ch_free((char *)pkt);
24: return(NOCONN);
25: }
26: conn->cn_faddr = destaddr;
27: conn->cn_state = CSRFCSENT;
28: conn->cn_fidx = 0;
29: conn->cn_rwsize = rwsize;
30: conn->cn_rsts = rwsize / 2;
31: conn->cn_active = Chclock;
32: pkt->pk_op = RFCOP;
33: pkt->pk_fc = 0;
34: pkt->pk_ackn = 0;
35: debug(DCONN,printf("Conn #%x: RFCS state\n", conn->cn_lidx));
36: /*
37: * By making the RFC packet written like a data packet,
38: * it will be freed by the normal receipting mechanism, enabling
39: * to easily be kept around for automatic retransmission.
40: * xmitdone (first half) and rcvpkt (handling OPEN pkts) help here.
41: * Since allconn clears the connection (including cn_tlast) the
42: * packet number of the RFC will be 1 (ch_write does pkn = ++tlast)
43: */
44: LOCK;
45: (void)ch_write(conn, pkt); /* No errors possible */
46: UNLOCK;
47: return(conn);
48: }
49: /*
50: * Start a listener, given a packet with the contact name in it.
51: * In all cases packet is consumed.
52: * Connection returned is in the listen state.
53: */
54: struct connection *
55: ch_listen(pkt)
56: struct packet *pkt;
57: {
58: register struct connection *conn;
59: register struct packet *pktl, *opkt;
60:
61: if ((conn = allconn()) == NOCONN) {
62: ch_free((char *)pkt);
63: return(NOCONN);
64: }
65: conn->cn_state = CSLISTEN;
66: pkt->pk_op = LSNOP;
67: setpkt(conn, pkt);
68: LOCK;
69: opkt = NOPKT;
70: for (pktl = Chrfclist; pktl != NOPKT; pktl = (opkt = pktl)->pk_next)
71: if (concmp(pktl, pkt->pk_cdata, (int)pkt->pk_len)) {
72: if(opkt == NOPKT)
73: Chrfclist = pktl->pk_next;
74: else
75: opkt->pk_next = pktl->pk_next;
76: if (pktl == Chrfctail)
77: Chrfctail = opkt;
78: if (pktl == rfcseen)
79: rfcseen = NOPKT;
80: ch_free((char *)pkt);
81: lsnmatch(pktl, conn);
82: UNLOCK;
83: return(conn);
84: }
85: /*
86: * Should we check for duplicate listeners??
87: * Or is it better to allow more than one?
88: */
89: pkt->pk_next = Chlsnlist;
90: Chlsnlist = pkt;
91: debug(DCONN,printf("Conn #%x: LISTEN state\n", conn->cn_lidx));
92: UNLOCK;
93: return(conn);
94: }
95: /*
96: * Send a new data packet on a connection.
97: * Called at high priority since window size check is elsewhere.
98: */
99: ch_write(conn, pkt)
100: register struct connection *conn;
101: register struct packet *pkt;
102: {
103: setpkt(conn, pkt);
104: pkt->pk_next = NOPKT; /* just to be sure! */
105: switch (pkt->pk_op) {
106: case ANSOP:
107: case FWDOP:
108: if (conn->cn_state != CSRFCRCVD ||
109: (conn->cn_flags & CHANSWER) == 0)
110: goto err;
111: ch_close(conn, pkt, 0);
112: return 0;
113: case RFCOP:
114: if (conn->cn_state != CSRFCSENT)
115: goto err;
116: break;
117: case UNCOP:
118: pkt->pk_pkn = 0;
119: senddata(pkt);
120: return 0;
121: default:
122: if (!ISDATOP(pkt))
123: goto err;
124: case OPNOP:
125: case EOFOP:
126: if (conn->cn_state != CSOPEN)
127: goto err;
128: break;
129: }
130: pkt->pk_pkn = ++conn->cn_tlast;
131: senddata(pkt);
132: return 0;
133: err:
134: ch_free((char *)pkt);
135: return CHERROR;
136: }
137: /*
138: * Consume the packet at the head of the received packet queue (rhead).
139: * Assumes high priority because check for available is elsewhere
140: */
141: ch_read(conn)
142: register struct connection *conn;
143: {
144: register struct packet *pkt;
145:
146: if ((pkt = conn->cn_rhead) == NOPKT)
147: return;
148: conn->cn_rhead = pkt->pk_next;
149: if (conn->cn_rtail == pkt)
150: conn->cn_rtail = NOPKT;
151: if (CONTPKT(pkt)) {
152: conn->cn_rread = pkt->pk_pkn;
153: if (pkt->pk_op == EOFOP ||
154: 3 * (short)(conn->cn_rread - conn->cn_racked) > conn->cn_rwsize) {
155: debug(DPKT,
156: printf("Conn#%x: rread=%d rackd=%d rsts=%d\n",
157: conn->cn_lidx, conn->cn_rread,
158: conn->cn_racked, conn->cn_rsts));
159: pkt->pk_next = NOPKT;
160: makests(conn, pkt);
161: reflect(pkt);
162: return;
163: }
164: }
165: ch_free((char *)pkt);
166: }
167: /*
168: * Send an eof packet on a channel.
169: */
170: ch_eof(conn)
171: struct connection *conn;
172: {
173: register struct packet *pkt;
174: register int ret = 0;
175:
176: if ((pkt = pkalloc(0, 0)) != NOPKT) {
177: pkt->pk_op = EOFOP;
178: pkt->pk_len = 0;
179: ret = ch_write(conn, pkt);
180: }
181: return ret;
182: }
183: /*
184: * Close a connection, giving close pkt to send (CLS or ANS).
185: */
186: ch_close(conn, pkt, release)
187: register struct connection *conn;
188: register struct packet *pkt;
189: {
190: int s = spl6();
191:
192: switch (conn->cn_state) {
193: case CSOPEN:
194: case CSRFCRCVD:
195: if (pkt != NOPKT) {
196: pkt->pk_ackn = pkt->pk_pkn = 0;
197: setpkt(conn, pkt);
198: sendctl(pkt);
199: pkt = NOPKT;
200: }
201: /* Fall into... */
202: case CSRFCSENT:
203: clsconn(conn, CSCLOSED, NOPKT);
204: break;
205: case CSLISTEN:
206: rmlisten(conn);
207: break;
208: default:
209: break;
210: }
211: if (pkt)
212: ch_free((char *)pkt);
213: splx(s);
214: if (release)
215: rlsconn(conn);
216: }
217: /*
218: * Top level raw sts sender - at high priority, like ch_write.
219: */
220: ch_sts(conn)
221: struct connection *conn;
222: {
223: sendsts(conn); /* This must be locked */
224: }
225: /*
226: * Accept an RFC, called on a connection in the CSRFCRCVD state.
227: */
228: ch_accept(conn)
229: struct connection *conn;
230: {
231: conn->cn_state = CSOPEN;
232: sendopn(conn);
233: }
234: /*
235: * Return the next rfc packet on the list, flushing the one previously
236: * looked at if it hasn't been consumed (or skipped) yet.
237: * Flushed RFC's get a Close packet sent back.
238: * LOCK must be in effect when called. - High priority.
239: */
240: struct packet *
241: ch_rnext()
242: {
243: register struct packet *pkt, *lpkt;
244:
245: if ((pkt = Chrfclist) != NOPKT && rfcseen == pkt) {
246: if ((Chrfclist = pkt->pk_next) == NOPKT)
247: Chrfctail = NOPKT;
248: UNLOCK;
249: if ((pkt = pktstr(pkt, "Contact name refused", 20)) != NOPKT) {
250: pkt->pk_op = CLSOP;
251: pkt->pk_fc = 0;
252: pkt->pk_ackn = pkt->pk_pkn = 0;
253: reflect(pkt);
254: }
255: LOCK;
256: pkt = Chrfclist;
257: rfcseen = NOPKT;
258: }
259: for (lpkt = pkt; pkt != NOPKT && pkt->pk_ackn != 0; pkt = pkt->pk_next)
260: lpkt = pkt;
261: if (pkt != NOPKT) {
262: if (pkt != Chrfclist) {
263: Chrfctail->pk_next = Chrfclist;
264: Chrfclist = pkt;
265: lpkt->pk_next = NOPKT;
266: Chrfctail = lpkt;
267: }
268: rfcseen = pkt;
269: }
270: return (pkt);
271: }
272: /*
273: * Skip the RFC at the head of the unmatched-rfc list, and mark it so that
274: * ch_rnext never sees it again. This is to allow an unmatched rfc server
275: * to basically say that the RFC should be handled by a specific listener.
276: * This would be necessary in the case where two calls for a given
277: * specific listener - say login - came so close together that the
278: * login server did not get done with the first one, and back inside the
279: * listen before the next one came in. Called at low priority from top level.
280: * To mark te RFC we set the pk_ackn to non-zero. It is assured to be zero
281: * when first queued.
282: */
283: ch_rskip()
284: {
285: register struct packet *pkt;
286:
287: if ((pkt = Chrfclist) != NOPKT && rfcseen == pkt) {
288: pkt->pk_ackn = 1;
289: rfcseen = NOPKT;
290: }
291: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.