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