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