|
|
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.