Annotation of src/usr.bin/ssh/nchan.c, Revision 1.11
1.7 markus 1: /*
2: * Copyright (c) 1999 Markus Friedl. All rights reserved.
3: *
4: * Redistribution and use in source and binary forms, with or without
5: * modification, are permitted provided that the following conditions
6: * are met:
7: * 1. Redistributions of source code must retain the above copyright
8: * notice, this list of conditions and the following disclaimer.
9: * 2. Redistributions in binary form must reproduce the above copyright
10: * notice, this list of conditions and the following disclaimer in the
11: * documentation and/or other materials provided with the distribution.
12: * 3. All advertising materials mentioning features or use of this software
13: * must display the following acknowledgement:
14: * This product includes software developed by Markus Friedl.
15: * 4. The name of the author may not be used to endorse or promote products
16: * derived from this software without specific prior written permission.
17: *
18: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28: */
29:
1.1 markus 30: #include "includes.h"
1.11 ! markus 31: RCSID("$Id: nchan.c,v 1.10 2000/01/10 10:15:28 markus Exp $");
1.2 markus 32:
1.1 markus 33: #include "ssh.h"
34:
35: #include "buffer.h"
1.3 markus 36: #include "packet.h"
1.1 markus 37: #include "channels.h"
38: #include "nchan.h"
39:
1.3 markus 40: static void chan_send_ieof(Channel *c);
41: static void chan_send_oclose(Channel *c);
42: static void chan_shutdown_write(Channel *c);
43: static void chan_shutdown_read(Channel *c);
44:
45: /*
1.6 markus 46: * EVENTS update channel input/output states execute ACTIONS
1.3 markus 47: */
1.6 markus 48:
1.3 markus 49: /* events concerning the INPUT from socket for channel (istate) */
1.1 markus 50: void
1.6 markus 51: chan_rcvd_oclose(Channel *c)
52: {
53: switch (c->istate) {
1.3 markus 54: case CHAN_INPUT_WAIT_OCLOSE:
1.4 markus 55: debug("channel %d: INPUT_WAIT_OCLOSE -> INPUT_CLOSED [rcvd OCLOSE]", c->self);
1.6 markus 56: c->istate = CHAN_INPUT_CLOSED;
1.3 markus 57: break;
58: case CHAN_INPUT_OPEN:
59: debug("channel %d: INPUT_OPEN -> INPUT_CLOSED [rvcd OCLOSE, send IEOF]", c->self);
60: chan_shutdown_read(c);
61: chan_send_ieof(c);
1.6 markus 62: c->istate = CHAN_INPUT_CLOSED;
1.10 markus 63: break;
64: case CHAN_INPUT_WAIT_DRAIN:
65: /* both local read_failed and remote write_failed */
66: log("channel %d: INPUT_WAIT_DRAIN -> INPUT_CLOSED [rvcd OCLOSE, send IEOF]", c->self);
67: debug("channel %d: INPUT_WAIT_DRAIN -> INPUT_CLOSED [rvcd OCLOSE, send IEOF]", c->self);
68: chan_send_ieof(c);
69: c->istate = CHAN_INPUT_CLOSED;
1.3 markus 70: break;
71: default:
1.9 markus 72: error("protocol error: chan_rcvd_oclose %d for istate %d", c->self, c->istate);
1.10 markus 73: return;
1.3 markus 74: }
1.10 markus 75: chan_delete_if_full_closed(c);
1.1 markus 76: }
77: void
1.6 markus 78: chan_read_failed(Channel *c)
79: {
80: switch (c->istate) {
1.3 markus 81: case CHAN_INPUT_OPEN:
82: debug("channel %d: INPUT_OPEN -> INPUT_WAIT_DRAIN [read failed]", c->self);
83: chan_shutdown_read(c);
1.6 markus 84: c->istate = CHAN_INPUT_WAIT_DRAIN;
1.3 markus 85: break;
86: default:
1.9 markus 87: error("internal error: we do not read, but chan_read_failed %d for istate %d",
1.6 markus 88: c->self, c->istate);
1.3 markus 89: break;
1.1 markus 90: }
91: }
92: void
1.6 markus 93: chan_ibuf_empty(Channel *c)
94: {
95: if (buffer_len(&c->input)) {
1.9 markus 96: error("internal error: chan_ibuf_empty %d for non empty buffer", c->self);
1.3 markus 97: return;
98: }
1.6 markus 99: switch (c->istate) {
1.3 markus 100: case CHAN_INPUT_WAIT_DRAIN:
1.4 markus 101: debug("channel %d: INPUT_WAIT_DRAIN -> INPUT_WAIT_OCLOSE [inbuf empty, send IEOF]", c->self);
1.3 markus 102: chan_send_ieof(c);
1.6 markus 103: c->istate = CHAN_INPUT_WAIT_OCLOSE;
1.3 markus 104: break;
105: default:
1.9 markus 106: error("internal error: chan_ibuf_empty %d for istate %d", c->self, c->istate);
1.3 markus 107: break;
1.1 markus 108: }
109: }
1.6 markus 110:
1.3 markus 111: /* events concerning the OUTPUT from channel for socket (ostate) */
1.1 markus 112: void
1.6 markus 113: chan_rcvd_ieof(Channel *c)
114: {
115: switch (c->ostate) {
1.3 markus 116: case CHAN_OUTPUT_OPEN:
117: debug("channel %d: OUTPUT_OPEN -> OUTPUT_WAIT_DRAIN [rvcd IEOF]", c->self);
1.6 markus 118: c->ostate = CHAN_OUTPUT_WAIT_DRAIN;
1.3 markus 119: break;
120: case CHAN_OUTPUT_WAIT_IEOF:
121: debug("channel %d: OUTPUT_WAIT_IEOF -> OUTPUT_CLOSED [rvcd IEOF]", c->self);
1.6 markus 122: c->ostate = CHAN_OUTPUT_CLOSED;
1.10 markus 123: chan_delete_if_full_closed(c);
1.3 markus 124: break;
125: default:
1.9 markus 126: error("protocol error: chan_rcvd_ieof %d for ostate %d", c->self, c->ostate);
1.3 markus 127: break;
128: }
129: }
130: void
1.6 markus 131: chan_write_failed(Channel *c)
132: {
133: switch (c->ostate) {
1.3 markus 134: case CHAN_OUTPUT_OPEN:
135: debug("channel %d: OUTPUT_OPEN -> OUTPUT_WAIT_IEOF [write failed]", c->self);
136: chan_send_oclose(c);
1.6 markus 137: c->ostate = CHAN_OUTPUT_WAIT_IEOF;
1.3 markus 138: break;
139: case CHAN_OUTPUT_WAIT_DRAIN:
140: debug("channel %d: OUTPUT_WAIT_DRAIN -> OUTPUT_CLOSED [write failed]", c->self);
141: chan_send_oclose(c);
1.6 markus 142: c->ostate = CHAN_OUTPUT_CLOSED;
1.10 markus 143: chan_delete_if_full_closed(c);
1.3 markus 144: break;
145: default:
1.9 markus 146: error("internal error: chan_write_failed %d for ostate %d", c->self, c->ostate);
1.3 markus 147: break;
148: }
149: }
150: void
1.6 markus 151: chan_obuf_empty(Channel *c)
152: {
153: if (buffer_len(&c->output)) {
154: debug("internal error: chan_obuf_empty %d for non empty buffer", c->self);
1.3 markus 155: return;
156: }
1.6 markus 157: switch (c->ostate) {
1.3 markus 158: case CHAN_OUTPUT_WAIT_DRAIN:
159: debug("channel %d: OUTPUT_WAIT_DRAIN -> OUTPUT_CLOSED [obuf empty, send OCLOSE]", c->self);
160: chan_send_oclose(c);
1.6 markus 161: c->ostate = CHAN_OUTPUT_CLOSED;
1.10 markus 162: chan_delete_if_full_closed(c);
1.3 markus 163: break;
164: default:
1.9 markus 165: error("internal error: chan_obuf_empty %d for ostate %d", c->self, c->ostate);
1.3 markus 166: break;
167: }
168: }
1.6 markus 169:
1.3 markus 170: /*
1.6 markus 171: * ACTIONS: should never update the channel states: c->istate or c->ostate
1.3 markus 172: */
173: static void
1.6 markus 174: chan_send_ieof(Channel *c)
175: {
176: switch (c->istate) {
1.3 markus 177: case CHAN_INPUT_OPEN:
178: case CHAN_INPUT_WAIT_DRAIN:
179: packet_start(SSH_MSG_CHANNEL_INPUT_EOF);
180: packet_put_int(c->remote_id);
181: packet_send();
182: break;
183: default:
1.9 markus 184: error("internal error: channel %d: cannot send IEOF for istate %d", c->self, c->istate);
1.3 markus 185: break;
1.1 markus 186: }
187: }
1.3 markus 188: static void
1.6 markus 189: chan_send_oclose(Channel *c)
190: {
191: switch (c->ostate) {
1.3 markus 192: case CHAN_OUTPUT_OPEN:
193: case CHAN_OUTPUT_WAIT_DRAIN:
194: chan_shutdown_write(c);
195: buffer_consume(&c->output, buffer_len(&c->output));
196: packet_start(SSH_MSG_CHANNEL_OUTPUT_CLOSE);
197: packet_put_int(c->remote_id);
198: packet_send();
199: break;
200: default:
1.9 markus 201: error("internal error: channel %d: cannot send OCLOSE for ostate %d", c->self, c->istate);
1.3 markus 202: break;
1.1 markus 203: }
204: }
1.6 markus 205:
1.3 markus 206: /* helper */
207: static void
1.6 markus 208: chan_shutdown_write(Channel *c)
209: {
1.8 markus 210: /* shutdown failure is allowed if write failed already */
1.3 markus 211: debug("channel %d: shutdown_write", c->self);
1.6 markus 212: if (shutdown(c->sock, SHUT_WR) < 0)
1.8 markus 213: debug("chan_shutdown_write failed for #%d/fd%d: %.100s",
1.6 markus 214: c->self, c->sock, strerror(errno));
1.1 markus 215: }
1.3 markus 216: static void
1.6 markus 217: chan_shutdown_read(Channel *c)
218: {
1.3 markus 219: debug("channel %d: shutdown_read", c->self);
1.6 markus 220: if (shutdown(c->sock, SHUT_RD) < 0)
1.10 markus 221: error("chan_shutdown_read failed for #%d/fd%d [i%d o%d]: %.100s",
222: c->self, c->sock, c->istate, c->ostate, strerror(errno));
1.1 markus 223: }
1.11 ! markus 224: void
1.10 markus 225: chan_delete_if_full_closed(Channel *c)
1.6 markus 226: {
227: if (c->istate == CHAN_INPUT_CLOSED && c->ostate == CHAN_OUTPUT_CLOSED) {
1.10 markus 228: debug("channel %d: full closed", c->self);
1.1 markus 229: channel_free(c->self);
230: }
1.3 markus 231: }
232: void
1.6 markus 233: chan_init_iostates(Channel *c)
234: {
235: c->ostate = CHAN_OUTPUT_OPEN;
236: c->istate = CHAN_INPUT_OPEN;
1.1 markus 237: }