Annotation of src/usr.bin/ssh/nchan.c, Revision 1.12
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.12 ! markus 31: RCSID("$Id: nchan.c,v 1.11 2000/03/28 20:31:27 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.1 markus 75: }
76: void
1.6 markus 77: chan_read_failed(Channel *c)
78: {
79: switch (c->istate) {
1.3 markus 80: case CHAN_INPUT_OPEN:
81: debug("channel %d: INPUT_OPEN -> INPUT_WAIT_DRAIN [read failed]", c->self);
82: chan_shutdown_read(c);
1.6 markus 83: c->istate = CHAN_INPUT_WAIT_DRAIN;
1.3 markus 84: break;
85: default:
1.9 markus 86: error("internal error: we do not read, but chan_read_failed %d for istate %d",
1.6 markus 87: c->self, c->istate);
1.3 markus 88: break;
1.1 markus 89: }
90: }
91: void
1.6 markus 92: chan_ibuf_empty(Channel *c)
93: {
94: if (buffer_len(&c->input)) {
1.9 markus 95: error("internal error: chan_ibuf_empty %d for non empty buffer", c->self);
1.3 markus 96: return;
97: }
1.6 markus 98: switch (c->istate) {
1.3 markus 99: case CHAN_INPUT_WAIT_DRAIN:
1.4 markus 100: debug("channel %d: INPUT_WAIT_DRAIN -> INPUT_WAIT_OCLOSE [inbuf empty, send IEOF]", c->self);
1.3 markus 101: chan_send_ieof(c);
1.6 markus 102: c->istate = CHAN_INPUT_WAIT_OCLOSE;
1.3 markus 103: break;
104: default:
1.9 markus 105: error("internal error: chan_ibuf_empty %d for istate %d", c->self, c->istate);
1.3 markus 106: break;
1.1 markus 107: }
108: }
1.6 markus 109:
1.3 markus 110: /* events concerning the OUTPUT from channel for socket (ostate) */
1.1 markus 111: void
1.6 markus 112: chan_rcvd_ieof(Channel *c)
113: {
114: switch (c->ostate) {
1.3 markus 115: case CHAN_OUTPUT_OPEN:
116: debug("channel %d: OUTPUT_OPEN -> OUTPUT_WAIT_DRAIN [rvcd IEOF]", c->self);
1.6 markus 117: c->ostate = CHAN_OUTPUT_WAIT_DRAIN;
1.3 markus 118: break;
119: case CHAN_OUTPUT_WAIT_IEOF:
120: debug("channel %d: OUTPUT_WAIT_IEOF -> OUTPUT_CLOSED [rvcd IEOF]", c->self);
1.6 markus 121: c->ostate = CHAN_OUTPUT_CLOSED;
1.3 markus 122: break;
123: default:
1.9 markus 124: error("protocol error: chan_rcvd_ieof %d for ostate %d", c->self, c->ostate);
1.3 markus 125: break;
126: }
127: }
128: void
1.6 markus 129: chan_write_failed(Channel *c)
130: {
131: switch (c->ostate) {
1.3 markus 132: case CHAN_OUTPUT_OPEN:
133: debug("channel %d: OUTPUT_OPEN -> OUTPUT_WAIT_IEOF [write failed]", c->self);
134: chan_send_oclose(c);
1.6 markus 135: c->ostate = CHAN_OUTPUT_WAIT_IEOF;
1.3 markus 136: break;
137: case CHAN_OUTPUT_WAIT_DRAIN:
138: debug("channel %d: OUTPUT_WAIT_DRAIN -> OUTPUT_CLOSED [write failed]", c->self);
139: chan_send_oclose(c);
1.6 markus 140: c->ostate = CHAN_OUTPUT_CLOSED;
1.3 markus 141: break;
142: default:
1.9 markus 143: error("internal error: chan_write_failed %d for ostate %d", c->self, c->ostate);
1.3 markus 144: break;
145: }
146: }
147: void
1.6 markus 148: chan_obuf_empty(Channel *c)
149: {
150: if (buffer_len(&c->output)) {
151: debug("internal error: chan_obuf_empty %d for non empty buffer", c->self);
1.3 markus 152: return;
153: }
1.6 markus 154: switch (c->ostate) {
1.3 markus 155: case CHAN_OUTPUT_WAIT_DRAIN:
156: debug("channel %d: OUTPUT_WAIT_DRAIN -> OUTPUT_CLOSED [obuf empty, send OCLOSE]", c->self);
157: chan_send_oclose(c);
1.6 markus 158: c->ostate = CHAN_OUTPUT_CLOSED;
1.3 markus 159: break;
160: default:
1.9 markus 161: error("internal error: chan_obuf_empty %d for ostate %d", c->self, c->ostate);
1.3 markus 162: break;
163: }
164: }
1.6 markus 165:
1.3 markus 166: /*
1.6 markus 167: * ACTIONS: should never update the channel states: c->istate or c->ostate
1.3 markus 168: */
169: static void
1.6 markus 170: chan_send_ieof(Channel *c)
171: {
172: switch (c->istate) {
1.3 markus 173: case CHAN_INPUT_OPEN:
174: case CHAN_INPUT_WAIT_DRAIN:
175: packet_start(SSH_MSG_CHANNEL_INPUT_EOF);
176: packet_put_int(c->remote_id);
177: packet_send();
178: break;
179: default:
1.9 markus 180: error("internal error: channel %d: cannot send IEOF for istate %d", c->self, c->istate);
1.3 markus 181: break;
1.1 markus 182: }
183: }
1.3 markus 184: static void
1.6 markus 185: chan_send_oclose(Channel *c)
186: {
187: switch (c->ostate) {
1.3 markus 188: case CHAN_OUTPUT_OPEN:
189: case CHAN_OUTPUT_WAIT_DRAIN:
190: chan_shutdown_write(c);
191: buffer_consume(&c->output, buffer_len(&c->output));
192: packet_start(SSH_MSG_CHANNEL_OUTPUT_CLOSE);
193: packet_put_int(c->remote_id);
194: packet_send();
195: break;
196: default:
1.9 markus 197: error("internal error: channel %d: cannot send OCLOSE for ostate %d", c->self, c->istate);
1.3 markus 198: break;
1.1 markus 199: }
200: }
1.6 markus 201:
1.3 markus 202: /* helper */
203: static void
1.6 markus 204: chan_shutdown_write(Channel *c)
205: {
1.8 markus 206: /* shutdown failure is allowed if write failed already */
1.3 markus 207: debug("channel %d: shutdown_write", c->self);
1.6 markus 208: if (shutdown(c->sock, SHUT_WR) < 0)
1.8 markus 209: debug("chan_shutdown_write failed for #%d/fd%d: %.100s",
1.6 markus 210: c->self, c->sock, strerror(errno));
1.1 markus 211: }
1.3 markus 212: static void
1.6 markus 213: chan_shutdown_read(Channel *c)
214: {
1.3 markus 215: debug("channel %d: shutdown_read", c->self);
1.6 markus 216: if (shutdown(c->sock, SHUT_RD) < 0)
1.10 markus 217: error("chan_shutdown_read failed for #%d/fd%d [i%d o%d]: %.100s",
218: c->self, c->sock, c->istate, c->ostate, strerror(errno));
1.1 markus 219: }
1.11 markus 220: void
1.10 markus 221: chan_delete_if_full_closed(Channel *c)
1.6 markus 222: {
223: if (c->istate == CHAN_INPUT_CLOSED && c->ostate == CHAN_OUTPUT_CLOSED) {
1.10 markus 224: debug("channel %d: full closed", c->self);
1.1 markus 225: channel_free(c->self);
226: }
1.3 markus 227: }
228: void
1.6 markus 229: chan_init_iostates(Channel *c)
230: {
231: c->ostate = CHAN_OUTPUT_OPEN;
232: c->istate = CHAN_INPUT_OPEN;
1.1 markus 233: }