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