Annotation of src/usr.bin/ssh/nchan.c, Revision 1.13
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.13 ! markus 31: RCSID("$Id: nchan.c,v 1.12 2000/03/28 20:34:14 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.13 ! markus 40: #include "ssh2.h"
! 41: #include "compat.h"
1.3 markus 42:
1.13 ! markus 43: /* functions manipulating channel states */
1.3 markus 44: /*
1.6 markus 45: * EVENTS update channel input/output states execute ACTIONS
1.3 markus 46: */
1.13 ! markus 47: /* events concerning the INPUT from socket for channel (istate) */
! 48: chan_event_fn *chan_rcvd_oclose = NULL;
! 49: chan_event_fn *chan_read_failed = NULL;
! 50: chan_event_fn *chan_ibuf_empty = NULL;
! 51: /* events concerning the OUTPUT from channel for socket (ostate) */
! 52: chan_event_fn *chan_rcvd_ieof = NULL;
! 53: chan_event_fn *chan_write_failed = NULL;
! 54: chan_event_fn *chan_obuf_empty = NULL;
! 55: /*
! 56: * ACTIONS: should never update the channel states
! 57: */
! 58: static void chan_send_ieof1(Channel *c);
! 59: static void chan_send_oclose1(Channel *c);
! 60: static void chan_send_close2(Channel *c);
! 61: static void chan_send_eof2(Channel *c);
! 62:
! 63: /* channel cleanup */
! 64: chan_event_fn *chan_delete_if_full_closed = NULL;
! 65:
! 66: /* helper */
! 67: static void chan_shutdown_write(Channel *c);
! 68: static void chan_shutdown_read(Channel *c);
! 69:
! 70: /*
! 71: * SSH1 specific implementation of event functions
! 72: */
1.6 markus 73:
1.13 ! markus 74: static void
! 75: chan_rcvd_oclose1(Channel *c)
1.6 markus 76: {
1.13 ! markus 77: debug("channel %d: rcvd oclose", c->self);
1.6 markus 78: switch (c->istate) {
1.3 markus 79: case CHAN_INPUT_WAIT_OCLOSE:
1.13 ! markus 80: debug("channel %d: input wait_oclose -> closed", c->self);
1.6 markus 81: c->istate = CHAN_INPUT_CLOSED;
1.3 markus 82: break;
83: case CHAN_INPUT_OPEN:
1.13 ! markus 84: debug("channel %d: input open -> closed", c->self);
1.3 markus 85: chan_shutdown_read(c);
1.13 ! markus 86: chan_send_ieof1(c);
1.6 markus 87: c->istate = CHAN_INPUT_CLOSED;
1.10 markus 88: break;
89: case CHAN_INPUT_WAIT_DRAIN:
90: /* both local read_failed and remote write_failed */
1.13 ! markus 91: log("channel %d: input drain -> closed", c->self);
! 92: chan_send_ieof1(c);
1.10 markus 93: c->istate = CHAN_INPUT_CLOSED;
1.3 markus 94: break;
95: default:
1.13 ! markus 96: error("channel %d: protocol error: chan_rcvd_oclose for istate %d",
! 97: c->self, c->istate);
1.10 markus 98: return;
1.3 markus 99: }
1.1 markus 100: }
1.13 ! markus 101: static void
! 102: chan_read_failed_12(Channel *c)
1.6 markus 103: {
1.13 ! markus 104: debug("channel %d: read failed", c->self);
1.6 markus 105: switch (c->istate) {
1.3 markus 106: case CHAN_INPUT_OPEN:
1.13 ! markus 107: debug("channel %d: input open -> drain", c->self);
1.3 markus 108: chan_shutdown_read(c);
1.6 markus 109: c->istate = CHAN_INPUT_WAIT_DRAIN;
1.3 markus 110: break;
111: default:
1.13 ! markus 112: error("channel %d: internal error: we do not read, but chan_read_failed for istate %d",
! 113: c->self, c->istate);
1.3 markus 114: break;
1.1 markus 115: }
116: }
1.13 ! markus 117: static void
! 118: chan_ibuf_empty1(Channel *c)
1.6 markus 119: {
1.13 ! markus 120: debug("channel %d: ibuf empty", c->self);
1.6 markus 121: if (buffer_len(&c->input)) {
1.13 ! markus 122: error("channel %d: internal error: chan_ibuf_empty for non empty buffer",
! 123: c->self);
1.3 markus 124: return;
125: }
1.6 markus 126: switch (c->istate) {
1.3 markus 127: case CHAN_INPUT_WAIT_DRAIN:
1.13 ! markus 128: debug("channel %d: input drain -> wait_oclose", c->self);
! 129: chan_send_ieof1(c);
1.6 markus 130: c->istate = CHAN_INPUT_WAIT_OCLOSE;
1.3 markus 131: break;
132: default:
1.13 ! markus 133: error("channel %d: internal error: chan_ibuf_empty for istate %d",
! 134: c->self, c->istate);
1.3 markus 135: break;
1.1 markus 136: }
137: }
1.13 ! markus 138: static void
! 139: chan_rcvd_ieof1(Channel *c)
1.6 markus 140: {
1.13 ! markus 141: debug("channel %d: rcvd ieof", c->self);
1.6 markus 142: switch (c->ostate) {
1.3 markus 143: case CHAN_OUTPUT_OPEN:
1.13 ! markus 144: debug("channel %d: output open -> drain", c->self);
1.6 markus 145: c->ostate = CHAN_OUTPUT_WAIT_DRAIN;
1.3 markus 146: break;
147: case CHAN_OUTPUT_WAIT_IEOF:
1.13 ! markus 148: debug("channel %d: output wait_ieof -> closed", c->self);
1.6 markus 149: c->ostate = CHAN_OUTPUT_CLOSED;
1.3 markus 150: break;
151: default:
1.13 ! markus 152: error("channel %d: protocol error: chan_rcvd_ieof for ostate %d",
! 153: c->self, c->ostate);
1.3 markus 154: break;
155: }
156: }
1.13 ! markus 157: static void
! 158: chan_write_failed1(Channel *c)
1.6 markus 159: {
1.13 ! markus 160: debug("channel %d: write failed", c->self);
1.6 markus 161: switch (c->ostate) {
1.3 markus 162: case CHAN_OUTPUT_OPEN:
1.13 ! markus 163: debug("channel %d: output open -> wait_ieof", c->self);
! 164: chan_send_oclose1(c);
1.6 markus 165: c->ostate = CHAN_OUTPUT_WAIT_IEOF;
1.3 markus 166: break;
167: case CHAN_OUTPUT_WAIT_DRAIN:
1.13 ! markus 168: debug("channel %d: output wait_drain -> closed", c->self);
! 169: chan_send_oclose1(c);
1.6 markus 170: c->ostate = CHAN_OUTPUT_CLOSED;
1.3 markus 171: break;
172: default:
1.13 ! markus 173: error("channel %d: internal error: chan_write_failed for ostate %d",
! 174: c->self, c->ostate);
1.3 markus 175: break;
176: }
177: }
1.13 ! markus 178: static void
! 179: chan_obuf_empty1(Channel *c)
1.6 markus 180: {
1.13 ! markus 181: debug("channel %d: obuf empty", c->self);
1.6 markus 182: if (buffer_len(&c->output)) {
1.13 ! markus 183: error("channel %d: internal error: chan_obuf_empty for non empty buffer",
! 184: c->self);
1.3 markus 185: return;
186: }
1.6 markus 187: switch (c->ostate) {
1.3 markus 188: case CHAN_OUTPUT_WAIT_DRAIN:
1.13 ! markus 189: debug("channel %d: output drain -> closed", c->self);
! 190: chan_send_oclose1(c);
1.6 markus 191: c->ostate = CHAN_OUTPUT_CLOSED;
1.3 markus 192: break;
193: default:
1.13 ! markus 194: error("channel %d: internal error: chan_obuf_empty for ostate %d",
! 195: c->self, c->ostate);
1.3 markus 196: break;
197: }
198: }
199: static void
1.13 ! markus 200: chan_send_ieof1(Channel *c)
1.6 markus 201: {
1.13 ! markus 202: debug("channel %d: send ieof", c->self);
1.6 markus 203: switch (c->istate) {
1.3 markus 204: case CHAN_INPUT_OPEN:
205: case CHAN_INPUT_WAIT_DRAIN:
206: packet_start(SSH_MSG_CHANNEL_INPUT_EOF);
207: packet_put_int(c->remote_id);
208: packet_send();
209: break;
210: default:
1.13 ! markus 211: error("channel %d: internal error: cannot send ieof for istate %d",
! 212: c->self, c->istate);
1.3 markus 213: break;
1.1 markus 214: }
215: }
1.3 markus 216: static void
1.13 ! markus 217: chan_send_oclose1(Channel *c)
1.6 markus 218: {
1.13 ! markus 219: debug("channel %d: send oclose", c->self);
1.6 markus 220: switch (c->ostate) {
1.3 markus 221: case CHAN_OUTPUT_OPEN:
222: case CHAN_OUTPUT_WAIT_DRAIN:
223: chan_shutdown_write(c);
224: buffer_consume(&c->output, buffer_len(&c->output));
225: packet_start(SSH_MSG_CHANNEL_OUTPUT_CLOSE);
226: packet_put_int(c->remote_id);
227: packet_send();
228: break;
229: default:
1.13 ! markus 230: error("channel %d: internal error: cannot send oclose for ostate %d",
! 231: c->self, c->ostate);
1.3 markus 232: break;
1.1 markus 233: }
234: }
1.13 ! markus 235: static void
! 236: chan_delete_if_full_closed1(Channel *c)
! 237: {
! 238: if (c->istate == CHAN_INPUT_CLOSED && c->ostate == CHAN_OUTPUT_CLOSED) {
! 239: debug("channel %d: full closed", c->self);
! 240: channel_free(c->self);
! 241: }
! 242: }
1.6 markus 243:
1.13 ! markus 244: /*
! 245: * the same for SSH2
! 246: */
! 247: static void
! 248: chan_rcvd_oclose2(Channel *c)
! 249: {
! 250: debug("channel %d: rcvd close", c->self);
! 251: if (c->flags & CHAN_CLOSE_RCVD)
! 252: error("channel %d: protocol error: close rcvd twice", c->self);
! 253: c->flags |= CHAN_CLOSE_RCVD;
! 254: if (c->type == SSH_CHANNEL_LARVAL) {
! 255: /* tear down larval channels immediately */
! 256: c->ostate = CHAN_OUTPUT_CLOSED;
! 257: c->istate = CHAN_INPUT_CLOSED;
! 258: return;
! 259: }
! 260: switch (c->ostate) {
! 261: case CHAN_OUTPUT_OPEN:
! 262: /* wait until a data from the channel is consumed if a CLOSE is received */
! 263: debug("channel %d: output open -> drain", c->self);
! 264: c->ostate = CHAN_OUTPUT_WAIT_DRAIN;
! 265: break;
! 266: }
! 267: switch (c->istate) {
! 268: case CHAN_INPUT_OPEN:
! 269: debug("channel %d: input open -> closed", c->self);
! 270: chan_shutdown_read(c);
! 271: break;
! 272: case CHAN_INPUT_WAIT_DRAIN:
! 273: debug("channel %d: input drain -> closed", c->self);
! 274: chan_send_eof2(c);
! 275: break;
! 276: }
! 277: c->istate = CHAN_INPUT_CLOSED;
! 278: }
! 279: static void
! 280: chan_ibuf_empty2(Channel *c)
! 281: {
! 282: debug("channel %d: ibuf empty", c->self);
! 283: if (buffer_len(&c->input)) {
! 284: error("channel %d: internal error: chan_ibuf_empty for non empty buffer",
! 285: c->self);
! 286: return;
! 287: }
! 288: switch (c->istate) {
! 289: case CHAN_INPUT_WAIT_DRAIN:
! 290: debug("channel %d: input drain -> closed", c->self);
! 291: if (!(c->flags & CHAN_CLOSE_SENT))
! 292: chan_send_eof2(c);
! 293: c->istate = CHAN_INPUT_CLOSED;
! 294: break;
! 295: default:
! 296: error("channel %d: internal error: chan_ibuf_empty for istate %d",
! 297: c->self, c->istate);
! 298: break;
! 299: }
! 300: }
! 301: static void
! 302: chan_rcvd_ieof2(Channel *c)
! 303: {
! 304: debug("channel %d: rcvd eof", c->self);
! 305: if (c->ostate == CHAN_OUTPUT_OPEN) {
! 306: debug("channel %d: output open -> drain", c->self);
! 307: c->ostate = CHAN_OUTPUT_WAIT_DRAIN;
! 308: }
! 309: }
! 310: static void
! 311: chan_write_failed2(Channel *c)
! 312: {
! 313: debug("channel %d: write failed", c->self);
! 314: switch (c->ostate) {
! 315: case CHAN_OUTPUT_OPEN:
! 316: debug("channel %d: output open -> closed", c->self);
! 317: chan_shutdown_write(c); // ??
! 318: c->ostate = CHAN_OUTPUT_CLOSED;
! 319: break;
! 320: case CHAN_OUTPUT_WAIT_DRAIN:
! 321: debug("channel %d: output drain -> closed", c->self);
! 322: chan_shutdown_write(c);
! 323: c->ostate = CHAN_OUTPUT_CLOSED;
! 324: break;
! 325: default:
! 326: error("channel %d: internal error: chan_write_failed for ostate %d",
! 327: c->self, c->ostate);
! 328: break;
! 329: }
! 330: }
! 331: static void
! 332: chan_obuf_empty2(Channel *c)
! 333: {
! 334: debug("channel %d: obuf empty", c->self);
! 335: if (buffer_len(&c->output)) {
! 336: error("internal error: chan_obuf_empty %d for non empty buffer",
! 337: c->self);
! 338: return;
! 339: }
! 340: switch (c->ostate) {
! 341: case CHAN_OUTPUT_WAIT_DRAIN:
! 342: debug("channel %d: output drain -> closed", c->self);
! 343: chan_shutdown_write(c);
! 344: c->ostate = CHAN_OUTPUT_CLOSED;
! 345: break;
! 346: default:
! 347: error("channel %d: internal error: chan_obuf_empty for ostate %d",
! 348: c->self, c->ostate);
! 349: break;
! 350: }
! 351: }
1.3 markus 352: static void
1.13 ! markus 353: chan_send_eof2(Channel *c)
1.6 markus 354: {
1.13 ! markus 355: debug("channel %d: send eof", c->self);
! 356: switch (c->istate) {
! 357: case CHAN_INPUT_WAIT_DRAIN:
! 358: packet_start(SSH2_MSG_CHANNEL_EOF);
! 359: packet_put_int(c->remote_id);
! 360: packet_send();
! 361: break;
! 362: default:
! 363: error("channel %d: internal error: cannot send eof for istate %d",
! 364: c->self, c->istate);
! 365: break;
! 366: }
1.1 markus 367: }
1.3 markus 368: static void
1.13 ! markus 369: chan_send_close2(Channel *c)
1.6 markus 370: {
1.13 ! markus 371: debug("channel %d: send close", c->self);
! 372: if (c->ostate != CHAN_OUTPUT_CLOSED ||
! 373: c->istate != CHAN_INPUT_CLOSED) {
! 374: error("channel %d: internal error: cannot send close for istate/ostate %d/%d",
! 375: c->self, c->istate, c->ostate);
! 376: } else if (c->flags & CHAN_CLOSE_SENT) {
! 377: error("channel %d: internal error: already sent close", c->self);
! 378: } else {
! 379: packet_start(SSH2_MSG_CHANNEL_CLOSE);
! 380: packet_put_int(c->remote_id);
! 381: packet_send();
! 382: c->flags |= CHAN_CLOSE_SENT;
! 383: }
1.1 markus 384: }
1.13 ! markus 385: static void
! 386: chan_delete_if_full_closed2(Channel *c)
1.6 markus 387: {
388: if (c->istate == CHAN_INPUT_CLOSED && c->ostate == CHAN_OUTPUT_CLOSED) {
1.13 ! markus 389: if (!(c->flags & CHAN_CLOSE_SENT)) {
! 390: chan_send_close2(c);
! 391: }
! 392: if ((c->flags & CHAN_CLOSE_SENT) &&
! 393: (c->flags & CHAN_CLOSE_RCVD)) {
! 394: debug("channel %d: full closed2", c->self);
! 395: channel_free(c->self);
! 396: }
1.1 markus 397: }
1.3 markus 398: }
1.13 ! markus 399:
! 400: /* shared */
1.3 markus 401: void
1.6 markus 402: chan_init_iostates(Channel *c)
403: {
404: c->ostate = CHAN_OUTPUT_OPEN;
405: c->istate = CHAN_INPUT_OPEN;
1.13 ! markus 406: c->flags = 0;
! 407: }
! 408:
! 409: /* init */
! 410: void
! 411: chan_init(void)
! 412: {
! 413: if (compat20) {
! 414: chan_rcvd_oclose = chan_rcvd_oclose2;
! 415: chan_read_failed = chan_read_failed_12;
! 416: chan_ibuf_empty = chan_ibuf_empty2;
! 417:
! 418: chan_rcvd_ieof = chan_rcvd_ieof2;
! 419: chan_write_failed = chan_write_failed2;
! 420: chan_obuf_empty = chan_obuf_empty2;
! 421:
! 422: chan_delete_if_full_closed = chan_delete_if_full_closed2;
! 423: } else {
! 424: chan_rcvd_oclose = chan_rcvd_oclose1;
! 425: chan_read_failed = chan_read_failed_12;
! 426: chan_ibuf_empty = chan_ibuf_empty1;
! 427:
! 428: chan_rcvd_ieof = chan_rcvd_ieof1;
! 429: chan_write_failed = chan_write_failed1;
! 430: chan_obuf_empty = chan_obuf_empty1;
! 431:
! 432: chan_delete_if_full_closed = chan_delete_if_full_closed1;
! 433: }
! 434: }
! 435:
! 436: /* helper */
! 437: static void
! 438: chan_shutdown_write(Channel *c)
! 439: {
! 440: buffer_consume(&c->output, buffer_len(&c->output));
! 441: if (compat20 && c->type == SSH_CHANNEL_LARVAL)
! 442: return;
! 443: /* shutdown failure is allowed if write failed already */
! 444: debug("channel %d: close_write", c->self);
! 445: if (c->sock != -1) {
! 446: if (shutdown(c->sock, SHUT_WR) < 0)
! 447: debug("channel %d: chan_shutdown_write: shutdown() failed for fd%d: %.100s",
! 448: c->self, c->sock, strerror(errno));
! 449: } else {
! 450: if (close(c->wfd) < 0)
! 451: log("channel %d: chan_shutdown_write: close() failed for fd%d: %.100s",
! 452: c->self, c->wfd, strerror(errno));
! 453: c->wfd = -1;
! 454: }
! 455: }
! 456: static void
! 457: chan_shutdown_read(Channel *c)
! 458: {
! 459: if (compat20 && c->type == SSH_CHANNEL_LARVAL)
! 460: return;
! 461: debug("channel %d: close_read", c->self);
! 462: if (c->sock != -1) {
! 463: if (shutdown(c->sock, SHUT_RD) < 0)
! 464: error("channel %d: chan_shutdown_read: shutdown() failed for fd%d [i%d o%d]: %.100s",
! 465: c->self, c->sock, c->istate, c->ostate, strerror(errno));
! 466: } else {
! 467: if (close(c->rfd) < 0)
! 468: log("channel %d: chan_shutdown_read: close() failed for fd%d: %.100s",
! 469: c->self, c->rfd, strerror(errno));
! 470: c->rfd = -1;
! 471: }
1.1 markus 472: }