1511b41d2SMark Murray /* 2511b41d2SMark Murray * Copyright (c) 1999 Markus Friedl. All rights reserved. 3511b41d2SMark Murray * 4511b41d2SMark Murray * Redistribution and use in source and binary forms, with or without 5511b41d2SMark Murray * modification, are permitted provided that the following conditions 6511b41d2SMark Murray * are met: 7511b41d2SMark Murray * 1. Redistributions of source code must retain the above copyright 8511b41d2SMark Murray * notice, this list of conditions and the following disclaimer. 9511b41d2SMark Murray * 2. Redistributions in binary form must reproduce the above copyright 10511b41d2SMark Murray * notice, this list of conditions and the following disclaimer in the 11511b41d2SMark Murray * documentation and/or other materials provided with the distribution. 12511b41d2SMark Murray * 3. All advertising materials mentioning features or use of this software 13511b41d2SMark Murray * must display the following acknowledgement: 14511b41d2SMark Murray * This product includes software developed by Markus Friedl. 15511b41d2SMark Murray * 4. The name of the author may not be used to endorse or promote products 16511b41d2SMark Murray * derived from this software without specific prior written permission. 17511b41d2SMark Murray * 18511b41d2SMark Murray * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19511b41d2SMark Murray * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20511b41d2SMark Murray * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21511b41d2SMark Murray * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22511b41d2SMark Murray * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23511b41d2SMark Murray * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24511b41d2SMark Murray * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25511b41d2SMark Murray * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26511b41d2SMark Murray * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27511b41d2SMark Murray * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28511b41d2SMark Murray */ 29511b41d2SMark Murray 30511b41d2SMark Murray #include "includes.h" 31a04a10f8SKris Kennaway RCSID("$Id: nchan.c,v 1.17 2000/05/08 17:44:54 markus Exp $"); 32511b41d2SMark Murray 33511b41d2SMark Murray #include "ssh.h" 34511b41d2SMark Murray 35511b41d2SMark Murray #include "buffer.h" 36511b41d2SMark Murray #include "packet.h" 37511b41d2SMark Murray #include "channels.h" 38511b41d2SMark Murray #include "nchan.h" 39511b41d2SMark Murray 40a04a10f8SKris Kennaway #include "ssh2.h" 41a04a10f8SKris Kennaway #include "compat.h" 42511b41d2SMark Murray 43a04a10f8SKris Kennaway /* functions manipulating channel states */ 44511b41d2SMark Murray /* 45511b41d2SMark Murray * EVENTS update channel input/output states execute ACTIONS 46511b41d2SMark Murray */ 47511b41d2SMark Murray /* events concerning the INPUT from socket for channel (istate) */ 48a04a10f8SKris Kennaway chan_event_fn *chan_rcvd_oclose = NULL; 49a04a10f8SKris Kennaway chan_event_fn *chan_read_failed = NULL; 50a04a10f8SKris Kennaway chan_event_fn *chan_ibuf_empty = NULL; 51a04a10f8SKris Kennaway /* events concerning the OUTPUT from channel for socket (ostate) */ 52a04a10f8SKris Kennaway chan_event_fn *chan_rcvd_ieof = NULL; 53a04a10f8SKris Kennaway chan_event_fn *chan_write_failed = NULL; 54a04a10f8SKris Kennaway chan_event_fn *chan_obuf_empty = NULL; 55a04a10f8SKris Kennaway /* 56a04a10f8SKris Kennaway * ACTIONS: should never update the channel states 57a04a10f8SKris Kennaway */ 58a04a10f8SKris Kennaway static void chan_send_ieof1(Channel *c); 59a04a10f8SKris Kennaway static void chan_send_oclose1(Channel *c); 60a04a10f8SKris Kennaway static void chan_send_close2(Channel *c); 61a04a10f8SKris Kennaway static void chan_send_eof2(Channel *c); 62a04a10f8SKris Kennaway 63a04a10f8SKris Kennaway /* channel cleanup */ 64a04a10f8SKris Kennaway chan_event_fn *chan_delete_if_full_closed = NULL; 65a04a10f8SKris Kennaway 66a04a10f8SKris Kennaway /* helper */ 67a04a10f8SKris Kennaway static void chan_shutdown_write(Channel *c); 68a04a10f8SKris Kennaway static void chan_shutdown_read(Channel *c); 69a04a10f8SKris Kennaway 70a04a10f8SKris Kennaway /* 71a04a10f8SKris Kennaway * SSH1 specific implementation of event functions 72a04a10f8SKris Kennaway */ 73a04a10f8SKris Kennaway 74a04a10f8SKris Kennaway static void 75a04a10f8SKris Kennaway chan_rcvd_oclose1(Channel *c) 76511b41d2SMark Murray { 77a04a10f8SKris Kennaway debug("channel %d: rcvd oclose", c->self); 78511b41d2SMark Murray switch (c->istate) { 79511b41d2SMark Murray case CHAN_INPUT_WAIT_OCLOSE: 80a04a10f8SKris Kennaway debug("channel %d: input wait_oclose -> closed", c->self); 81511b41d2SMark Murray c->istate = CHAN_INPUT_CLOSED; 82511b41d2SMark Murray break; 83511b41d2SMark Murray case CHAN_INPUT_OPEN: 84a04a10f8SKris Kennaway debug("channel %d: input open -> closed", c->self); 85511b41d2SMark Murray chan_shutdown_read(c); 86a04a10f8SKris Kennaway chan_send_ieof1(c); 87511b41d2SMark Murray c->istate = CHAN_INPUT_CLOSED; 88511b41d2SMark Murray break; 89511b41d2SMark Murray case CHAN_INPUT_WAIT_DRAIN: 90511b41d2SMark Murray /* both local read_failed and remote write_failed */ 91a04a10f8SKris Kennaway log("channel %d: input drain -> closed", c->self); 92a04a10f8SKris Kennaway chan_send_ieof1(c); 93511b41d2SMark Murray c->istate = CHAN_INPUT_CLOSED; 94511b41d2SMark Murray break; 95511b41d2SMark Murray default: 96a04a10f8SKris Kennaway error("channel %d: protocol error: chan_rcvd_oclose for istate %d", 97a04a10f8SKris Kennaway c->self, c->istate); 98511b41d2SMark Murray return; 99511b41d2SMark Murray } 100511b41d2SMark Murray } 101a04a10f8SKris Kennaway static void 102a04a10f8SKris Kennaway chan_read_failed_12(Channel *c) 103511b41d2SMark Murray { 104a04a10f8SKris Kennaway debug("channel %d: read failed", c->self); 105511b41d2SMark Murray switch (c->istate) { 106511b41d2SMark Murray case CHAN_INPUT_OPEN: 107a04a10f8SKris Kennaway debug("channel %d: input open -> drain", c->self); 108511b41d2SMark Murray chan_shutdown_read(c); 109511b41d2SMark Murray c->istate = CHAN_INPUT_WAIT_DRAIN; 110a04a10f8SKris Kennaway if (buffer_len(&c->input) == 0) { 111a04a10f8SKris Kennaway debug("channel %d: input: no drain shortcut", c->self); 112a04a10f8SKris Kennaway chan_ibuf_empty(c); 113a04a10f8SKris Kennaway } 114511b41d2SMark Murray break; 115511b41d2SMark Murray default: 116a04a10f8SKris Kennaway error("channel %d: internal error: we do not read, but chan_read_failed for istate %d", 117511b41d2SMark Murray c->self, c->istate); 118511b41d2SMark Murray break; 119511b41d2SMark Murray } 120511b41d2SMark Murray } 121a04a10f8SKris Kennaway static void 122a04a10f8SKris Kennaway chan_ibuf_empty1(Channel *c) 123511b41d2SMark Murray { 124a04a10f8SKris Kennaway debug("channel %d: ibuf empty", c->self); 125511b41d2SMark Murray if (buffer_len(&c->input)) { 126a04a10f8SKris Kennaway error("channel %d: internal error: chan_ibuf_empty for non empty buffer", 127a04a10f8SKris Kennaway c->self); 128511b41d2SMark Murray return; 129511b41d2SMark Murray } 130511b41d2SMark Murray switch (c->istate) { 131511b41d2SMark Murray case CHAN_INPUT_WAIT_DRAIN: 132a04a10f8SKris Kennaway debug("channel %d: input drain -> wait_oclose", c->self); 133a04a10f8SKris Kennaway chan_send_ieof1(c); 134511b41d2SMark Murray c->istate = CHAN_INPUT_WAIT_OCLOSE; 135511b41d2SMark Murray break; 136511b41d2SMark Murray default: 137a04a10f8SKris Kennaway error("channel %d: internal error: chan_ibuf_empty for istate %d", 138a04a10f8SKris Kennaway c->self, c->istate); 139511b41d2SMark Murray break; 140511b41d2SMark Murray } 141511b41d2SMark Murray } 142a04a10f8SKris Kennaway static void 143a04a10f8SKris Kennaway chan_rcvd_ieof1(Channel *c) 144511b41d2SMark Murray { 145a04a10f8SKris Kennaway debug("channel %d: rcvd ieof", c->self); 146a04a10f8SKris Kennaway if (c->type != SSH_CHANNEL_OPEN) { 147a04a10f8SKris Kennaway debug("channel %d: non-open", c->self); 148a04a10f8SKris Kennaway if (c->istate == CHAN_INPUT_OPEN) { 149a04a10f8SKris Kennaway debug("channel %d: non-open: input open -> wait_oclose", c->self); 150a04a10f8SKris Kennaway chan_shutdown_read(c); 151a04a10f8SKris Kennaway chan_send_ieof1(c); 152a04a10f8SKris Kennaway c->istate = CHAN_INPUT_WAIT_OCLOSE; 153a04a10f8SKris Kennaway } else { 154a04a10f8SKris Kennaway error("channel %d: istate %d != open", c->self, c->istate); 155a04a10f8SKris Kennaway } 156a04a10f8SKris Kennaway if (c->ostate == CHAN_OUTPUT_OPEN) { 157a04a10f8SKris Kennaway debug("channel %d: non-open: output open -> closed", c->self); 158a04a10f8SKris Kennaway chan_send_oclose1(c); 159a04a10f8SKris Kennaway c->ostate = CHAN_OUTPUT_CLOSED; 160a04a10f8SKris Kennaway } else { 161a04a10f8SKris Kennaway error("channel %d: ostate %d != open", c->self, c->ostate); 162a04a10f8SKris Kennaway } 163a04a10f8SKris Kennaway return; 164a04a10f8SKris Kennaway } 165511b41d2SMark Murray switch (c->ostate) { 166511b41d2SMark Murray case CHAN_OUTPUT_OPEN: 167a04a10f8SKris Kennaway debug("channel %d: output open -> drain", c->self); 168511b41d2SMark Murray c->ostate = CHAN_OUTPUT_WAIT_DRAIN; 169511b41d2SMark Murray break; 170511b41d2SMark Murray case CHAN_OUTPUT_WAIT_IEOF: 171a04a10f8SKris Kennaway debug("channel %d: output wait_ieof -> closed", c->self); 172511b41d2SMark Murray c->ostate = CHAN_OUTPUT_CLOSED; 173511b41d2SMark Murray break; 174511b41d2SMark Murray default: 175a04a10f8SKris Kennaway error("channel %d: protocol error: chan_rcvd_ieof for ostate %d", 176a04a10f8SKris Kennaway c->self, c->ostate); 177511b41d2SMark Murray break; 178511b41d2SMark Murray } 179511b41d2SMark Murray } 180a04a10f8SKris Kennaway static void 181a04a10f8SKris Kennaway chan_write_failed1(Channel *c) 182511b41d2SMark Murray { 183a04a10f8SKris Kennaway debug("channel %d: write failed", c->self); 184511b41d2SMark Murray switch (c->ostate) { 185511b41d2SMark Murray case CHAN_OUTPUT_OPEN: 186a04a10f8SKris Kennaway debug("channel %d: output open -> wait_ieof", c->self); 187a04a10f8SKris Kennaway chan_send_oclose1(c); 188511b41d2SMark Murray c->ostate = CHAN_OUTPUT_WAIT_IEOF; 189511b41d2SMark Murray break; 190511b41d2SMark Murray case CHAN_OUTPUT_WAIT_DRAIN: 191a04a10f8SKris Kennaway debug("channel %d: output wait_drain -> closed", c->self); 192a04a10f8SKris Kennaway chan_send_oclose1(c); 193511b41d2SMark Murray c->ostate = CHAN_OUTPUT_CLOSED; 194511b41d2SMark Murray break; 195511b41d2SMark Murray default: 196a04a10f8SKris Kennaway error("channel %d: internal error: chan_write_failed for ostate %d", 197a04a10f8SKris Kennaway c->self, c->ostate); 198511b41d2SMark Murray break; 199511b41d2SMark Murray } 200511b41d2SMark Murray } 201a04a10f8SKris Kennaway static void 202a04a10f8SKris Kennaway chan_obuf_empty1(Channel *c) 203511b41d2SMark Murray { 204a04a10f8SKris Kennaway debug("channel %d: obuf empty", c->self); 205511b41d2SMark Murray if (buffer_len(&c->output)) { 206a04a10f8SKris Kennaway error("channel %d: internal error: chan_obuf_empty for non empty buffer", 207a04a10f8SKris Kennaway c->self); 208511b41d2SMark Murray return; 209511b41d2SMark Murray } 210511b41d2SMark Murray switch (c->ostate) { 211511b41d2SMark Murray case CHAN_OUTPUT_WAIT_DRAIN: 212a04a10f8SKris Kennaway debug("channel %d: output drain -> closed", c->self); 213a04a10f8SKris Kennaway chan_send_oclose1(c); 214511b41d2SMark Murray c->ostate = CHAN_OUTPUT_CLOSED; 215511b41d2SMark Murray break; 216511b41d2SMark Murray default: 217a04a10f8SKris Kennaway error("channel %d: internal error: chan_obuf_empty for ostate %d", 218a04a10f8SKris Kennaway c->self, c->ostate); 219511b41d2SMark Murray break; 220511b41d2SMark Murray } 221511b41d2SMark Murray } 222511b41d2SMark Murray static void 223a04a10f8SKris Kennaway chan_send_ieof1(Channel *c) 224511b41d2SMark Murray { 225a04a10f8SKris Kennaway debug("channel %d: send ieof", c->self); 226511b41d2SMark Murray switch (c->istate) { 227511b41d2SMark Murray case CHAN_INPUT_OPEN: 228511b41d2SMark Murray case CHAN_INPUT_WAIT_DRAIN: 229511b41d2SMark Murray packet_start(SSH_MSG_CHANNEL_INPUT_EOF); 230511b41d2SMark Murray packet_put_int(c->remote_id); 231511b41d2SMark Murray packet_send(); 232511b41d2SMark Murray break; 233511b41d2SMark Murray default: 234a04a10f8SKris Kennaway error("channel %d: internal error: cannot send ieof for istate %d", 235a04a10f8SKris Kennaway c->self, c->istate); 236511b41d2SMark Murray break; 237511b41d2SMark Murray } 238511b41d2SMark Murray } 239511b41d2SMark Murray static void 240a04a10f8SKris Kennaway chan_send_oclose1(Channel *c) 241511b41d2SMark Murray { 242a04a10f8SKris Kennaway debug("channel %d: send oclose", c->self); 243511b41d2SMark Murray switch (c->ostate) { 244511b41d2SMark Murray case CHAN_OUTPUT_OPEN: 245511b41d2SMark Murray case CHAN_OUTPUT_WAIT_DRAIN: 246511b41d2SMark Murray chan_shutdown_write(c); 247511b41d2SMark Murray buffer_consume(&c->output, buffer_len(&c->output)); 248511b41d2SMark Murray packet_start(SSH_MSG_CHANNEL_OUTPUT_CLOSE); 249511b41d2SMark Murray packet_put_int(c->remote_id); 250511b41d2SMark Murray packet_send(); 251511b41d2SMark Murray break; 252511b41d2SMark Murray default: 253a04a10f8SKris Kennaway error("channel %d: internal error: cannot send oclose for ostate %d", 254a04a10f8SKris Kennaway c->self, c->ostate); 255511b41d2SMark Murray break; 256511b41d2SMark Murray } 257511b41d2SMark Murray } 258a04a10f8SKris Kennaway static void 259a04a10f8SKris Kennaway chan_delete_if_full_closed1(Channel *c) 260a04a10f8SKris Kennaway { 261a04a10f8SKris Kennaway if (c->istate == CHAN_INPUT_CLOSED && c->ostate == CHAN_OUTPUT_CLOSED) { 262a04a10f8SKris Kennaway debug("channel %d: full closed", c->self); 263a04a10f8SKris Kennaway channel_free(c->self); 264a04a10f8SKris Kennaway } 265a04a10f8SKris Kennaway } 266a04a10f8SKris Kennaway 267a04a10f8SKris Kennaway /* 268a04a10f8SKris Kennaway * the same for SSH2 269a04a10f8SKris Kennaway */ 270a04a10f8SKris Kennaway static void 271a04a10f8SKris Kennaway chan_rcvd_oclose2(Channel *c) 272a04a10f8SKris Kennaway { 273a04a10f8SKris Kennaway debug("channel %d: rcvd close", c->self); 274a04a10f8SKris Kennaway if (c->flags & CHAN_CLOSE_RCVD) 275a04a10f8SKris Kennaway error("channel %d: protocol error: close rcvd twice", c->self); 276a04a10f8SKris Kennaway c->flags |= CHAN_CLOSE_RCVD; 277a04a10f8SKris Kennaway if (c->type == SSH_CHANNEL_LARVAL) { 278a04a10f8SKris Kennaway /* tear down larval channels immediately */ 279a04a10f8SKris Kennaway c->ostate = CHAN_OUTPUT_CLOSED; 280a04a10f8SKris Kennaway c->istate = CHAN_INPUT_CLOSED; 281a04a10f8SKris Kennaway return; 282a04a10f8SKris Kennaway } 283a04a10f8SKris Kennaway switch (c->ostate) { 284a04a10f8SKris Kennaway case CHAN_OUTPUT_OPEN: 285a04a10f8SKris Kennaway /* wait until a data from the channel is consumed if a CLOSE is received */ 286a04a10f8SKris Kennaway debug("channel %d: output open -> drain", c->self); 287a04a10f8SKris Kennaway c->ostate = CHAN_OUTPUT_WAIT_DRAIN; 288a04a10f8SKris Kennaway break; 289a04a10f8SKris Kennaway } 290a04a10f8SKris Kennaway switch (c->istate) { 291a04a10f8SKris Kennaway case CHAN_INPUT_OPEN: 292a04a10f8SKris Kennaway debug("channel %d: input open -> closed", c->self); 293a04a10f8SKris Kennaway chan_shutdown_read(c); 294a04a10f8SKris Kennaway break; 295a04a10f8SKris Kennaway case CHAN_INPUT_WAIT_DRAIN: 296a04a10f8SKris Kennaway debug("channel %d: input drain -> closed", c->self); 297a04a10f8SKris Kennaway chan_send_eof2(c); 298a04a10f8SKris Kennaway break; 299a04a10f8SKris Kennaway } 300a04a10f8SKris Kennaway c->istate = CHAN_INPUT_CLOSED; 301a04a10f8SKris Kennaway } 302a04a10f8SKris Kennaway static void 303a04a10f8SKris Kennaway chan_ibuf_empty2(Channel *c) 304a04a10f8SKris Kennaway { 305a04a10f8SKris Kennaway debug("channel %d: ibuf empty", c->self); 306a04a10f8SKris Kennaway if (buffer_len(&c->input)) { 307a04a10f8SKris Kennaway error("channel %d: internal error: chan_ibuf_empty for non empty buffer", 308a04a10f8SKris Kennaway c->self); 309a04a10f8SKris Kennaway return; 310a04a10f8SKris Kennaway } 311a04a10f8SKris Kennaway switch (c->istate) { 312a04a10f8SKris Kennaway case CHAN_INPUT_WAIT_DRAIN: 313a04a10f8SKris Kennaway debug("channel %d: input drain -> closed", c->self); 314a04a10f8SKris Kennaway if (!(c->flags & CHAN_CLOSE_SENT)) 315a04a10f8SKris Kennaway chan_send_eof2(c); 316a04a10f8SKris Kennaway c->istate = CHAN_INPUT_CLOSED; 317a04a10f8SKris Kennaway break; 318a04a10f8SKris Kennaway default: 319a04a10f8SKris Kennaway error("channel %d: internal error: chan_ibuf_empty for istate %d", 320a04a10f8SKris Kennaway c->self, c->istate); 321a04a10f8SKris Kennaway break; 322a04a10f8SKris Kennaway } 323a04a10f8SKris Kennaway } 324a04a10f8SKris Kennaway static void 325a04a10f8SKris Kennaway chan_rcvd_ieof2(Channel *c) 326a04a10f8SKris Kennaway { 327a04a10f8SKris Kennaway debug("channel %d: rcvd eof", c->self); 328a04a10f8SKris Kennaway if (c->ostate == CHAN_OUTPUT_OPEN) { 329a04a10f8SKris Kennaway debug("channel %d: output open -> drain", c->self); 330a04a10f8SKris Kennaway c->ostate = CHAN_OUTPUT_WAIT_DRAIN; 331a04a10f8SKris Kennaway } 332a04a10f8SKris Kennaway } 333a04a10f8SKris Kennaway static void 334a04a10f8SKris Kennaway chan_write_failed2(Channel *c) 335a04a10f8SKris Kennaway { 336a04a10f8SKris Kennaway debug("channel %d: write failed", c->self); 337a04a10f8SKris Kennaway switch (c->ostate) { 338a04a10f8SKris Kennaway case CHAN_OUTPUT_OPEN: 339a04a10f8SKris Kennaway debug("channel %d: output open -> closed", c->self); 340a04a10f8SKris Kennaway chan_shutdown_write(c); /* ?? */ 341a04a10f8SKris Kennaway c->ostate = CHAN_OUTPUT_CLOSED; 342a04a10f8SKris Kennaway break; 343a04a10f8SKris Kennaway case CHAN_OUTPUT_WAIT_DRAIN: 344a04a10f8SKris Kennaway debug("channel %d: output drain -> closed", c->self); 345a04a10f8SKris Kennaway chan_shutdown_write(c); 346a04a10f8SKris Kennaway c->ostate = CHAN_OUTPUT_CLOSED; 347a04a10f8SKris Kennaway break; 348a04a10f8SKris Kennaway default: 349a04a10f8SKris Kennaway error("channel %d: internal error: chan_write_failed for ostate %d", 350a04a10f8SKris Kennaway c->self, c->ostate); 351a04a10f8SKris Kennaway break; 352a04a10f8SKris Kennaway } 353a04a10f8SKris Kennaway } 354a04a10f8SKris Kennaway static void 355a04a10f8SKris Kennaway chan_obuf_empty2(Channel *c) 356a04a10f8SKris Kennaway { 357a04a10f8SKris Kennaway debug("channel %d: obuf empty", c->self); 358a04a10f8SKris Kennaway if (buffer_len(&c->output)) { 359a04a10f8SKris Kennaway error("internal error: chan_obuf_empty %d for non empty buffer", 360a04a10f8SKris Kennaway c->self); 361a04a10f8SKris Kennaway return; 362a04a10f8SKris Kennaway } 363a04a10f8SKris Kennaway switch (c->ostate) { 364a04a10f8SKris Kennaway case CHAN_OUTPUT_WAIT_DRAIN: 365a04a10f8SKris Kennaway debug("channel %d: output drain -> closed", c->self); 366a04a10f8SKris Kennaway chan_shutdown_write(c); 367a04a10f8SKris Kennaway c->ostate = CHAN_OUTPUT_CLOSED; 368a04a10f8SKris Kennaway break; 369a04a10f8SKris Kennaway default: 370a04a10f8SKris Kennaway error("channel %d: internal error: chan_obuf_empty for ostate %d", 371a04a10f8SKris Kennaway c->self, c->ostate); 372a04a10f8SKris Kennaway break; 373a04a10f8SKris Kennaway } 374a04a10f8SKris Kennaway } 375a04a10f8SKris Kennaway static void 376a04a10f8SKris Kennaway chan_send_eof2(Channel *c) 377a04a10f8SKris Kennaway { 378a04a10f8SKris Kennaway debug("channel %d: send eof", c->self); 379a04a10f8SKris Kennaway switch (c->istate) { 380a04a10f8SKris Kennaway case CHAN_INPUT_WAIT_DRAIN: 381a04a10f8SKris Kennaway packet_start(SSH2_MSG_CHANNEL_EOF); 382a04a10f8SKris Kennaway packet_put_int(c->remote_id); 383a04a10f8SKris Kennaway packet_send(); 384a04a10f8SKris Kennaway break; 385a04a10f8SKris Kennaway default: 386a04a10f8SKris Kennaway error("channel %d: internal error: cannot send eof for istate %d", 387a04a10f8SKris Kennaway c->self, c->istate); 388a04a10f8SKris Kennaway break; 389a04a10f8SKris Kennaway } 390a04a10f8SKris Kennaway } 391a04a10f8SKris Kennaway static void 392a04a10f8SKris Kennaway chan_send_close2(Channel *c) 393a04a10f8SKris Kennaway { 394a04a10f8SKris Kennaway debug("channel %d: send close", c->self); 395a04a10f8SKris Kennaway if (c->ostate != CHAN_OUTPUT_CLOSED || 396a04a10f8SKris Kennaway c->istate != CHAN_INPUT_CLOSED) { 397a04a10f8SKris Kennaway error("channel %d: internal error: cannot send close for istate/ostate %d/%d", 398a04a10f8SKris Kennaway c->self, c->istate, c->ostate); 399a04a10f8SKris Kennaway } else if (c->flags & CHAN_CLOSE_SENT) { 400a04a10f8SKris Kennaway error("channel %d: internal error: already sent close", c->self); 401a04a10f8SKris Kennaway } else { 402a04a10f8SKris Kennaway packet_start(SSH2_MSG_CHANNEL_CLOSE); 403a04a10f8SKris Kennaway packet_put_int(c->remote_id); 404a04a10f8SKris Kennaway packet_send(); 405a04a10f8SKris Kennaway c->flags |= CHAN_CLOSE_SENT; 406a04a10f8SKris Kennaway } 407a04a10f8SKris Kennaway } 408a04a10f8SKris Kennaway static void 409a04a10f8SKris Kennaway chan_delete_if_full_closed2(Channel *c) 410a04a10f8SKris Kennaway { 411a04a10f8SKris Kennaway if (c->istate == CHAN_INPUT_CLOSED && c->ostate == CHAN_OUTPUT_CLOSED) { 412a04a10f8SKris Kennaway if (!(c->flags & CHAN_CLOSE_SENT)) { 413a04a10f8SKris Kennaway chan_send_close2(c); 414a04a10f8SKris Kennaway } 415a04a10f8SKris Kennaway if ((c->flags & CHAN_CLOSE_SENT) && 416a04a10f8SKris Kennaway (c->flags & CHAN_CLOSE_RCVD)) { 417a04a10f8SKris Kennaway debug("channel %d: full closed2", c->self); 418a04a10f8SKris Kennaway channel_free(c->self); 419a04a10f8SKris Kennaway } 420a04a10f8SKris Kennaway } 421a04a10f8SKris Kennaway } 422a04a10f8SKris Kennaway 423a04a10f8SKris Kennaway /* shared */ 424a04a10f8SKris Kennaway void 425a04a10f8SKris Kennaway chan_init_iostates(Channel *c) 426a04a10f8SKris Kennaway { 427a04a10f8SKris Kennaway c->ostate = CHAN_OUTPUT_OPEN; 428a04a10f8SKris Kennaway c->istate = CHAN_INPUT_OPEN; 429a04a10f8SKris Kennaway c->flags = 0; 430a04a10f8SKris Kennaway } 431a04a10f8SKris Kennaway 432a04a10f8SKris Kennaway /* init */ 433a04a10f8SKris Kennaway void 434a04a10f8SKris Kennaway chan_init(void) 435a04a10f8SKris Kennaway { 436a04a10f8SKris Kennaway if (compat20) { 437a04a10f8SKris Kennaway chan_rcvd_oclose = chan_rcvd_oclose2; 438a04a10f8SKris Kennaway chan_read_failed = chan_read_failed_12; 439a04a10f8SKris Kennaway chan_ibuf_empty = chan_ibuf_empty2; 440a04a10f8SKris Kennaway 441a04a10f8SKris Kennaway chan_rcvd_ieof = chan_rcvd_ieof2; 442a04a10f8SKris Kennaway chan_write_failed = chan_write_failed2; 443a04a10f8SKris Kennaway chan_obuf_empty = chan_obuf_empty2; 444a04a10f8SKris Kennaway 445a04a10f8SKris Kennaway chan_delete_if_full_closed = chan_delete_if_full_closed2; 446a04a10f8SKris Kennaway } else { 447a04a10f8SKris Kennaway chan_rcvd_oclose = chan_rcvd_oclose1; 448a04a10f8SKris Kennaway chan_read_failed = chan_read_failed_12; 449a04a10f8SKris Kennaway chan_ibuf_empty = chan_ibuf_empty1; 450a04a10f8SKris Kennaway 451a04a10f8SKris Kennaway chan_rcvd_ieof = chan_rcvd_ieof1; 452a04a10f8SKris Kennaway chan_write_failed = chan_write_failed1; 453a04a10f8SKris Kennaway chan_obuf_empty = chan_obuf_empty1; 454a04a10f8SKris Kennaway 455a04a10f8SKris Kennaway chan_delete_if_full_closed = chan_delete_if_full_closed1; 456a04a10f8SKris Kennaway } 457a04a10f8SKris Kennaway } 458511b41d2SMark Murray 459511b41d2SMark Murray /* helper */ 460511b41d2SMark Murray static void 461511b41d2SMark Murray chan_shutdown_write(Channel *c) 462511b41d2SMark Murray { 463a04a10f8SKris Kennaway buffer_consume(&c->output, buffer_len(&c->output)); 464a04a10f8SKris Kennaway if (compat20 && c->type == SSH_CHANNEL_LARVAL) 465a04a10f8SKris Kennaway return; 466511b41d2SMark Murray /* shutdown failure is allowed if write failed already */ 467a04a10f8SKris Kennaway debug("channel %d: close_write", c->self); 468a04a10f8SKris Kennaway if (c->sock != -1) { 469511b41d2SMark Murray if (shutdown(c->sock, SHUT_WR) < 0) 470a04a10f8SKris Kennaway debug("channel %d: chan_shutdown_write: shutdown() failed for fd%d: %.100s", 471511b41d2SMark Murray c->self, c->sock, strerror(errno)); 472a04a10f8SKris Kennaway } else { 473a04a10f8SKris Kennaway if (close(c->wfd) < 0) 474a04a10f8SKris Kennaway log("channel %d: chan_shutdown_write: close() failed for fd%d: %.100s", 475a04a10f8SKris Kennaway c->self, c->wfd, strerror(errno)); 476a04a10f8SKris Kennaway c->wfd = -1; 477a04a10f8SKris Kennaway } 478511b41d2SMark Murray } 479511b41d2SMark Murray static void 480511b41d2SMark Murray chan_shutdown_read(Channel *c) 481511b41d2SMark Murray { 482a04a10f8SKris Kennaway if (compat20 && c->type == SSH_CHANNEL_LARVAL) 483a04a10f8SKris Kennaway return; 484a04a10f8SKris Kennaway debug("channel %d: close_read", c->self); 485a04a10f8SKris Kennaway if (c->sock != -1) { 486511b41d2SMark Murray if (shutdown(c->sock, SHUT_RD) < 0) 487a04a10f8SKris Kennaway error("channel %d: chan_shutdown_read: shutdown() failed for fd%d [i%d o%d]: %.100s", 488511b41d2SMark Murray c->self, c->sock, c->istate, c->ostate, strerror(errno)); 489a04a10f8SKris Kennaway } else { 490a04a10f8SKris Kennaway if (close(c->rfd) < 0) 491a04a10f8SKris Kennaway log("channel %d: chan_shutdown_read: close() failed for fd%d: %.100s", 492a04a10f8SKris Kennaway c->self, c->rfd, strerror(errno)); 493a04a10f8SKris Kennaway c->rfd = -1; 494511b41d2SMark Murray } 495511b41d2SMark Murray } 496