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