1204917Sdes/* $OpenBSD: nchan.c,v 1.63 2010/01/26 01:28:35 djm Exp $ */ 257429Smarkm/* 392555Sdes * Copyright (c) 1999, 2000, 2001, 2002 Markus Friedl. All rights reserved. 457429Smarkm * 557429Smarkm * Redistribution and use in source and binary forms, with or without 657429Smarkm * modification, are permitted provided that the following conditions 757429Smarkm * are met: 857429Smarkm * 1. Redistributions of source code must retain the above copyright 957429Smarkm * notice, this list of conditions and the following disclaimer. 1057429Smarkm * 2. Redistributions in binary form must reproduce the above copyright 1157429Smarkm * notice, this list of conditions and the following disclaimer in the 1257429Smarkm * documentation and/or other materials provided with the distribution. 1357429Smarkm * 1457429Smarkm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1557429Smarkm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1657429Smarkm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1757429Smarkm * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1857429Smarkm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 1957429Smarkm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2057429Smarkm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2157429Smarkm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2257429Smarkm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2357429Smarkm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2457429Smarkm */ 2557429Smarkm 2657429Smarkm#include "includes.h" 2757429Smarkm 28162852Sdes#include <sys/types.h> 29162852Sdes#include <sys/socket.h> 30162852Sdes 31162852Sdes#include <errno.h> 32162852Sdes#include <string.h> 33162852Sdes#include <stdarg.h> 34162852Sdes 35181111Sdes#include "openbsd-compat/sys-queue.h" 3676259Sgreen#include "ssh1.h" 3776259Sgreen#include "ssh2.h" 3857429Smarkm#include "buffer.h" 3957429Smarkm#include "packet.h" 4057429Smarkm#include "channels.h" 4160573Skris#include "compat.h" 4276259Sgreen#include "log.h" 4357429Smarkm 4492555Sdes/* 4592555Sdes * SSH Protocol 1.5 aka New Channel Protocol 4692555Sdes * Thanks to Martina, Axel and everyone who left Erlangen, leaving me bored. 4792555Sdes * Written by Markus Friedl in October 1999 4892555Sdes * 4992555Sdes * Protocol versions 1.3 and 1.5 differ in the handshake protocol used for the 5092555Sdes * tear down of channels: 5192555Sdes * 5292555Sdes * 1.3: strict request-ack-protocol: 53137015Sdes * CLOSE -> 54137015Sdes * <- CLOSE_CONFIRM 5592555Sdes * 5692555Sdes * 1.5: uses variations of: 57137015Sdes * IEOF -> 58137015Sdes * <- OCLOSE 59137015Sdes * <- IEOF 60137015Sdes * OCLOSE -> 61137015Sdes * i.e. both sides have to close the channel 6292555Sdes * 6392555Sdes * 2.0: the EOF messages are optional 6492555Sdes * 6592555Sdes * See the debugging output from 'ssh -v' and 'sshd -d' of 6692555Sdes * ssh-1.2.27 as an example. 6792555Sdes * 6892555Sdes */ 6992555Sdes 7060573Skris/* functions manipulating channel states */ 7157429Smarkm/* 7257429Smarkm * EVENTS update channel input/output states execute ACTIONS 7357429Smarkm */ 7460573Skris/* 7560573Skris * ACTIONS: should never update the channel states 7660573Skris */ 7792555Sdesstatic void chan_send_ieof1(Channel *); 7892555Sdesstatic void chan_send_oclose1(Channel *); 7992555Sdesstatic void chan_send_close2(Channel *); 8092555Sdesstatic void chan_send_eof2(Channel *); 81181111Sdesstatic void chan_send_eow2(Channel *); 8257429Smarkm 8360573Skris/* helper */ 8492555Sdesstatic void chan_shutdown_write(Channel *); 8592555Sdesstatic void chan_shutdown_read(Channel *); 8660573Skris 8792555Sdesstatic char *ostates[] = { "open", "drain", "wait_ieof", "closed" }; 8892555Sdesstatic char *istates[] = { "open", "drain", "wait_oclose", "closed" }; 8992555Sdes 9092555Sdesstatic void 9192555Sdeschan_set_istate(Channel *c, u_int next) 9292555Sdes{ 9392555Sdes if (c->istate > CHAN_INPUT_CLOSED || next > CHAN_INPUT_CLOSED) 9492555Sdes fatal("chan_set_istate: bad state %d -> %d", c->istate, next); 95124208Sdes debug2("channel %d: input %s -> %s", c->self, istates[c->istate], 9692555Sdes istates[next]); 9792555Sdes c->istate = next; 9892555Sdes} 9992555Sdesstatic void 10092555Sdeschan_set_ostate(Channel *c, u_int next) 10192555Sdes{ 10292555Sdes if (c->ostate > CHAN_OUTPUT_CLOSED || next > CHAN_OUTPUT_CLOSED) 10392555Sdes fatal("chan_set_ostate: bad state %d -> %d", c->ostate, next); 104124208Sdes debug2("channel %d: output %s -> %s", c->self, ostates[c->ostate], 10592555Sdes ostates[next]); 10692555Sdes c->ostate = next; 10792555Sdes} 10892555Sdes 10960573Skris/* 11060573Skris * SSH1 specific implementation of event functions 11160573Skris */ 11260573Skris 11360573Skrisstatic void 11460573Skrischan_rcvd_oclose1(Channel *c) 11557429Smarkm{ 116124208Sdes debug2("channel %d: rcvd oclose", c->self); 11757429Smarkm switch (c->istate) { 11857429Smarkm case CHAN_INPUT_WAIT_OCLOSE: 11992555Sdes chan_set_istate(c, CHAN_INPUT_CLOSED); 12057429Smarkm break; 12157429Smarkm case CHAN_INPUT_OPEN: 12257429Smarkm chan_shutdown_read(c); 12360573Skris chan_send_ieof1(c); 12492555Sdes chan_set_istate(c, CHAN_INPUT_CLOSED); 12557429Smarkm break; 12657429Smarkm case CHAN_INPUT_WAIT_DRAIN: 12757429Smarkm /* both local read_failed and remote write_failed */ 12860573Skris chan_send_ieof1(c); 12992555Sdes chan_set_istate(c, CHAN_INPUT_CLOSED); 13057429Smarkm break; 13157429Smarkm default: 13292555Sdes error("channel %d: protocol error: rcvd_oclose for istate %d", 13360573Skris c->self, c->istate); 13457429Smarkm return; 13557429Smarkm } 13657429Smarkm} 13792555Sdesvoid 13892555Sdeschan_read_failed(Channel *c) 13957429Smarkm{ 140124208Sdes debug2("channel %d: read failed", c->self); 14157429Smarkm switch (c->istate) { 14257429Smarkm case CHAN_INPUT_OPEN: 14357429Smarkm chan_shutdown_read(c); 14492555Sdes chan_set_istate(c, CHAN_INPUT_WAIT_DRAIN); 14557429Smarkm break; 14657429Smarkm default: 14792555Sdes error("channel %d: chan_read_failed for istate %d", 14860573Skris c->self, c->istate); 14957429Smarkm break; 15057429Smarkm } 15157429Smarkm} 15292555Sdesvoid 15392555Sdeschan_ibuf_empty(Channel *c) 15457429Smarkm{ 155124208Sdes debug2("channel %d: ibuf empty", c->self); 15657429Smarkm if (buffer_len(&c->input)) { 15792555Sdes error("channel %d: chan_ibuf_empty for non empty buffer", 15860573Skris c->self); 15957429Smarkm return; 16057429Smarkm } 16157429Smarkm switch (c->istate) { 16257429Smarkm case CHAN_INPUT_WAIT_DRAIN: 16392555Sdes if (compat20) { 164204917Sdes if (!(c->flags & (CHAN_CLOSE_SENT|CHAN_LOCAL))) 16592555Sdes chan_send_eof2(c); 16692555Sdes chan_set_istate(c, CHAN_INPUT_CLOSED); 16792555Sdes } else { 16892555Sdes chan_send_ieof1(c); 16992555Sdes chan_set_istate(c, CHAN_INPUT_WAIT_OCLOSE); 17092555Sdes } 17157429Smarkm break; 17257429Smarkm default: 17392555Sdes error("channel %d: chan_ibuf_empty for istate %d", 17460573Skris c->self, c->istate); 17557429Smarkm break; 17657429Smarkm } 17757429Smarkm} 17860573Skrisstatic void 17960573Skrischan_rcvd_ieof1(Channel *c) 18057429Smarkm{ 181124208Sdes debug2("channel %d: rcvd ieof", c->self); 18257429Smarkm switch (c->ostate) { 18357429Smarkm case CHAN_OUTPUT_OPEN: 18492555Sdes chan_set_ostate(c, CHAN_OUTPUT_WAIT_DRAIN); 18557429Smarkm break; 18657429Smarkm case CHAN_OUTPUT_WAIT_IEOF: 18792555Sdes chan_set_ostate(c, CHAN_OUTPUT_CLOSED); 18857429Smarkm break; 18957429Smarkm default: 19092555Sdes error("channel %d: protocol error: rcvd_ieof for ostate %d", 19160573Skris c->self, c->ostate); 19257429Smarkm break; 19357429Smarkm } 19457429Smarkm} 19560573Skrisstatic void 19660573Skrischan_write_failed1(Channel *c) 19757429Smarkm{ 198124208Sdes debug2("channel %d: write failed", c->self); 19957429Smarkm switch (c->ostate) { 20057429Smarkm case CHAN_OUTPUT_OPEN: 20192555Sdes chan_shutdown_write(c); 20260573Skris chan_send_oclose1(c); 20392555Sdes chan_set_ostate(c, CHAN_OUTPUT_WAIT_IEOF); 20457429Smarkm break; 20557429Smarkm case CHAN_OUTPUT_WAIT_DRAIN: 20692555Sdes chan_shutdown_write(c); 20760573Skris chan_send_oclose1(c); 20892555Sdes chan_set_ostate(c, CHAN_OUTPUT_CLOSED); 20957429Smarkm break; 21057429Smarkm default: 21192555Sdes error("channel %d: chan_write_failed for ostate %d", 21260573Skris c->self, c->ostate); 21357429Smarkm break; 21457429Smarkm } 21557429Smarkm} 21692555Sdesvoid 21792555Sdeschan_obuf_empty(Channel *c) 21857429Smarkm{ 219124208Sdes debug2("channel %d: obuf empty", c->self); 22057429Smarkm if (buffer_len(&c->output)) { 22192555Sdes error("channel %d: chan_obuf_empty for non empty buffer", 22260573Skris c->self); 22357429Smarkm return; 22457429Smarkm } 22557429Smarkm switch (c->ostate) { 22657429Smarkm case CHAN_OUTPUT_WAIT_DRAIN: 22792555Sdes chan_shutdown_write(c); 22892555Sdes if (!compat20) 22992555Sdes chan_send_oclose1(c); 23092555Sdes chan_set_ostate(c, CHAN_OUTPUT_CLOSED); 23157429Smarkm break; 23257429Smarkm default: 23392555Sdes error("channel %d: internal error: obuf_empty for ostate %d", 23460573Skris c->self, c->ostate); 23557429Smarkm break; 23657429Smarkm } 23757429Smarkm} 23857429Smarkmstatic void 23960573Skrischan_send_ieof1(Channel *c) 24057429Smarkm{ 241124208Sdes debug2("channel %d: send ieof", c->self); 24257429Smarkm switch (c->istate) { 24357429Smarkm case CHAN_INPUT_OPEN: 24457429Smarkm case CHAN_INPUT_WAIT_DRAIN: 24557429Smarkm packet_start(SSH_MSG_CHANNEL_INPUT_EOF); 24657429Smarkm packet_put_int(c->remote_id); 24757429Smarkm packet_send(); 24857429Smarkm break; 24957429Smarkm default: 25092555Sdes error("channel %d: cannot send ieof for istate %d", 25160573Skris c->self, c->istate); 25257429Smarkm break; 25357429Smarkm } 25457429Smarkm} 25557429Smarkmstatic void 25660573Skrischan_send_oclose1(Channel *c) 25757429Smarkm{ 258124208Sdes debug2("channel %d: send oclose", c->self); 25957429Smarkm switch (c->ostate) { 26057429Smarkm case CHAN_OUTPUT_OPEN: 26157429Smarkm case CHAN_OUTPUT_WAIT_DRAIN: 26292555Sdes buffer_clear(&c->output); 26357429Smarkm packet_start(SSH_MSG_CHANNEL_OUTPUT_CLOSE); 26457429Smarkm packet_put_int(c->remote_id); 26557429Smarkm packet_send(); 26657429Smarkm break; 26757429Smarkm default: 26892555Sdes error("channel %d: cannot send oclose for ostate %d", 26992555Sdes c->self, c->ostate); 27057429Smarkm break; 27157429Smarkm } 27257429Smarkm} 27357429Smarkm 27460573Skris/* 27560573Skris * the same for SSH2 27660573Skris */ 27757429Smarkmstatic void 27892555Sdeschan_rcvd_close2(Channel *c) 27957429Smarkm{ 280124208Sdes debug2("channel %d: rcvd close", c->self); 281204917Sdes if (!(c->flags & CHAN_LOCAL)) { 282204917Sdes if (c->flags & CHAN_CLOSE_RCVD) 283204917Sdes error("channel %d: protocol error: close rcvd twice", 284204917Sdes c->self); 285204917Sdes c->flags |= CHAN_CLOSE_RCVD; 286204917Sdes } 28760573Skris if (c->type == SSH_CHANNEL_LARVAL) { 28860573Skris /* tear down larval channels immediately */ 28992555Sdes chan_set_ostate(c, CHAN_OUTPUT_CLOSED); 29092555Sdes chan_set_istate(c, CHAN_INPUT_CLOSED); 29160573Skris return; 29260573Skris } 29360573Skris switch (c->ostate) { 29460573Skris case CHAN_OUTPUT_OPEN: 29592555Sdes /* 29692555Sdes * wait until a data from the channel is consumed if a CLOSE 29792555Sdes * is received 29892555Sdes */ 29992555Sdes chan_set_ostate(c, CHAN_OUTPUT_WAIT_DRAIN); 30060573Skris break; 30160573Skris } 30260573Skris switch (c->istate) { 30360573Skris case CHAN_INPUT_OPEN: 30460573Skris chan_shutdown_read(c); 30592555Sdes chan_set_istate(c, CHAN_INPUT_CLOSED); 30660573Skris break; 30760573Skris case CHAN_INPUT_WAIT_DRAIN: 308204917Sdes if (!(c->flags & CHAN_LOCAL)) 309204917Sdes chan_send_eof2(c); 31092555Sdes chan_set_istate(c, CHAN_INPUT_CLOSED); 31160573Skris break; 31260573Skris } 31357429Smarkm} 314204917Sdes 315181111Sdesvoid 316181111Sdeschan_rcvd_eow(Channel *c) 317181111Sdes{ 318181111Sdes debug2("channel %d: rcvd eow", c->self); 319181111Sdes switch (c->istate) { 320181111Sdes case CHAN_INPUT_OPEN: 321181111Sdes chan_shutdown_read(c); 322181111Sdes chan_set_istate(c, CHAN_INPUT_CLOSED); 323181111Sdes break; 324181111Sdes } 325181111Sdes} 32657429Smarkmstatic void 32792555Sdeschan_rcvd_eof2(Channel *c) 32857429Smarkm{ 329124208Sdes debug2("channel %d: rcvd eof", c->self); 33098675Sdes c->flags |= CHAN_EOF_RCVD; 33192555Sdes if (c->ostate == CHAN_OUTPUT_OPEN) 33292555Sdes chan_set_ostate(c, CHAN_OUTPUT_WAIT_DRAIN); 33360573Skris} 33460573Skrisstatic void 33560573Skrischan_write_failed2(Channel *c) 33660573Skris{ 337124208Sdes debug2("channel %d: write failed", c->self); 33860573Skris switch (c->ostate) { 33960573Skris case CHAN_OUTPUT_OPEN: 34060573Skris case CHAN_OUTPUT_WAIT_DRAIN: 34160573Skris chan_shutdown_write(c); 342181111Sdes if (strcmp(c->ctype, "session") == 0) 343181111Sdes chan_send_eow2(c); 34492555Sdes chan_set_ostate(c, CHAN_OUTPUT_CLOSED); 34560573Skris break; 34660573Skris default: 34792555Sdes error("channel %d: chan_write_failed for ostate %d", 34860573Skris c->self, c->ostate); 34960573Skris break; 35060573Skris } 35160573Skris} 35260573Skrisstatic void 35360573Skrischan_send_eof2(Channel *c) 35460573Skris{ 355124208Sdes debug2("channel %d: send eof", c->self); 35660573Skris switch (c->istate) { 35760573Skris case CHAN_INPUT_WAIT_DRAIN: 35860573Skris packet_start(SSH2_MSG_CHANNEL_EOF); 35960573Skris packet_put_int(c->remote_id); 36060573Skris packet_send(); 36198675Sdes c->flags |= CHAN_EOF_SENT; 36260573Skris break; 36360573Skris default: 36492555Sdes error("channel %d: cannot send eof for istate %d", 36560573Skris c->self, c->istate); 36660573Skris break; 36760573Skris } 36860573Skris} 36960573Skrisstatic void 37060573Skrischan_send_close2(Channel *c) 37160573Skris{ 372124208Sdes debug2("channel %d: send close", c->self); 37360573Skris if (c->ostate != CHAN_OUTPUT_CLOSED || 37460573Skris c->istate != CHAN_INPUT_CLOSED) { 37592555Sdes error("channel %d: cannot send close for istate/ostate %d/%d", 37660573Skris c->self, c->istate, c->ostate); 37760573Skris } else if (c->flags & CHAN_CLOSE_SENT) { 37892555Sdes error("channel %d: already sent close", c->self); 37960573Skris } else { 38060573Skris packet_start(SSH2_MSG_CHANNEL_CLOSE); 38160573Skris packet_put_int(c->remote_id); 38260573Skris packet_send(); 38360573Skris c->flags |= CHAN_CLOSE_SENT; 38460573Skris } 38560573Skris} 386181111Sdesstatic void 387181111Sdeschan_send_eow2(Channel *c) 388181111Sdes{ 389181111Sdes debug2("channel %d: send eow", c->self); 390181111Sdes if (c->ostate == CHAN_OUTPUT_CLOSED) { 391181111Sdes error("channel %d: must not sent eow on closed output", 392181111Sdes c->self); 393181111Sdes return; 394181111Sdes } 395192595Sdes if (!(datafellows & SSH_NEW_OPENSSH)) 396192595Sdes return; 397181111Sdes packet_start(SSH2_MSG_CHANNEL_REQUEST); 398181111Sdes packet_put_int(c->remote_id); 399181111Sdes packet_put_cstring("eow@openssh.com"); 400181111Sdes packet_put_char(0); 401181111Sdes packet_send(); 402181111Sdes} 40376259Sgreen 40476259Sgreen/* shared */ 40576259Sgreen 40692555Sdesvoid 40792555Sdeschan_rcvd_ieof(Channel *c) 40892555Sdes{ 40992555Sdes if (compat20) 41092555Sdes chan_rcvd_eof2(c); 41192555Sdes else 41292555Sdes chan_rcvd_ieof1(c); 41392555Sdes if (c->ostate == CHAN_OUTPUT_WAIT_DRAIN && 41498675Sdes buffer_len(&c->output) == 0 && 41598675Sdes !CHANNEL_EFD_OUTPUT_ACTIVE(c)) 41692555Sdes chan_obuf_empty(c); 41792555Sdes} 41892555Sdesvoid 41992555Sdeschan_rcvd_oclose(Channel *c) 42092555Sdes{ 42192555Sdes if (compat20) 42292555Sdes chan_rcvd_close2(c); 42392555Sdes else 42492555Sdes chan_rcvd_oclose1(c); 42592555Sdes} 42692555Sdesvoid 42792555Sdeschan_write_failed(Channel *c) 42892555Sdes{ 42992555Sdes if (compat20) 43092555Sdes chan_write_failed2(c); 43192555Sdes else 43292555Sdes chan_write_failed1(c); 43392555Sdes} 43492555Sdes 43592555Sdesvoid 43692555Sdeschan_mark_dead(Channel *c) 43792555Sdes{ 43892555Sdes c->type = SSH_CHANNEL_ZOMBIE; 43992555Sdes} 44092555Sdes 44176259Sgreenint 442137015Sdeschan_is_dead(Channel *c, int do_send) 44360573Skris{ 44492555Sdes if (c->type == SSH_CHANNEL_ZOMBIE) { 445124208Sdes debug2("channel %d: zombie", c->self); 44692555Sdes return 1; 44792555Sdes } 44876259Sgreen if (c->istate != CHAN_INPUT_CLOSED || c->ostate != CHAN_OUTPUT_CLOSED) 44976259Sgreen return 0; 45076259Sgreen if (!compat20) { 451124208Sdes debug2("channel %d: is dead", c->self); 45276259Sgreen return 1; 45376259Sgreen } 45498675Sdes if ((datafellows & SSH_BUG_EXTEOF) && 45598675Sdes c->extended_usage == CHAN_EXTENDED_WRITE && 45698675Sdes c->efd != -1 && 45798675Sdes buffer_len(&c->extended) > 0) { 45898675Sdes debug2("channel %d: active efd: %d len %d", 45998675Sdes c->self, c->efd, buffer_len(&c->extended)); 46098675Sdes return 0; 46198675Sdes } 462204917Sdes if (c->flags & CHAN_LOCAL) { 463204917Sdes debug2("channel %d: is dead (local)", c->self); 464204917Sdes return 1; 465204917Sdes } 46698675Sdes if (!(c->flags & CHAN_CLOSE_SENT)) { 467137015Sdes if (do_send) { 46898675Sdes chan_send_close2(c); 46998675Sdes } else { 47098675Sdes /* channel would be dead if we sent a close */ 47198675Sdes if (c->flags & CHAN_CLOSE_RCVD) { 472124208Sdes debug2("channel %d: almost dead", 47398675Sdes c->self); 47498675Sdes return 1; 47592555Sdes } 47660573Skris } 47757429Smarkm } 47898675Sdes if ((c->flags & CHAN_CLOSE_SENT) && 47998675Sdes (c->flags & CHAN_CLOSE_RCVD)) { 480124208Sdes debug2("channel %d: is dead", c->self); 48198675Sdes return 1; 48298675Sdes } 48376259Sgreen return 0; 48457429Smarkm} 48560573Skris 48660573Skris/* helper */ 48760573Skrisstatic void 48860573Skrischan_shutdown_write(Channel *c) 48960573Skris{ 49092555Sdes buffer_clear(&c->output); 49160573Skris if (compat20 && c->type == SSH_CHANNEL_LARVAL) 49260573Skris return; 49360573Skris /* shutdown failure is allowed if write failed already */ 494124208Sdes debug2("channel %d: close_write", c->self); 49560573Skris if (c->sock != -1) { 49660573Skris if (shutdown(c->sock, SHUT_WR) < 0) 497124208Sdes debug2("channel %d: chan_shutdown_write: " 498192595Sdes "shutdown() failed for fd %d: %.100s", 49960573Skris c->self, c->sock, strerror(errno)); 50060573Skris } else { 50192555Sdes if (channel_close_fd(&c->wfd) < 0) 502124208Sdes logit("channel %d: chan_shutdown_write: " 503192595Sdes "close() failed for fd %d: %.100s", 50460573Skris c->self, c->wfd, strerror(errno)); 50560573Skris } 50660573Skris} 50760573Skrisstatic void 50860573Skrischan_shutdown_read(Channel *c) 50960573Skris{ 51060573Skris if (compat20 && c->type == SSH_CHANNEL_LARVAL) 51160573Skris return; 512124208Sdes debug2("channel %d: close_read", c->self); 51360573Skris if (c->sock != -1) { 51498937Sdes /* 51598937Sdes * shutdown(sock, SHUT_READ) may return ENOTCONN if the 51698937Sdes * write side has been closed already. (bug on Linux) 51798937Sdes * HP-UX may return ENOTCONN also. 51898937Sdes */ 51998937Sdes if (shutdown(c->sock, SHUT_RD) < 0 52098937Sdes && errno != ENOTCONN) 52192555Sdes error("channel %d: chan_shutdown_read: " 522192595Sdes "shutdown() failed for fd %d [i%d o%d]: %.100s", 52392555Sdes c->self, c->sock, c->istate, c->ostate, 52492555Sdes strerror(errno)); 52560573Skris } else { 52692555Sdes if (channel_close_fd(&c->rfd) < 0) 527124208Sdes logit("channel %d: chan_shutdown_read: " 528192595Sdes "close() failed for fd %d: %.100s", 52960573Skris c->self, c->rfd, strerror(errno)); 53060573Skris } 53160573Skris} 532