nchan.c revision 181111
1181111Sdes/* $OpenBSD: nchan.c,v 1.60 2008/06/30 12:16:02 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) { 16492555Sdes if (!(c->flags & CHAN_CLOSE_SENT)) 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); 28160573Skris if (c->flags & CHAN_CLOSE_RCVD) 28260573Skris error("channel %d: protocol error: close rcvd twice", c->self); 28360573Skris c->flags |= CHAN_CLOSE_RCVD; 28460573Skris if (c->type == SSH_CHANNEL_LARVAL) { 28560573Skris /* tear down larval channels immediately */ 28692555Sdes chan_set_ostate(c, CHAN_OUTPUT_CLOSED); 28792555Sdes chan_set_istate(c, CHAN_INPUT_CLOSED); 28860573Skris return; 28960573Skris } 29060573Skris switch (c->ostate) { 29160573Skris case CHAN_OUTPUT_OPEN: 29292555Sdes /* 29392555Sdes * wait until a data from the channel is consumed if a CLOSE 29492555Sdes * is received 29592555Sdes */ 29692555Sdes chan_set_ostate(c, CHAN_OUTPUT_WAIT_DRAIN); 29760573Skris break; 29860573Skris } 29960573Skris switch (c->istate) { 30060573Skris case CHAN_INPUT_OPEN: 30160573Skris chan_shutdown_read(c); 30292555Sdes chan_set_istate(c, CHAN_INPUT_CLOSED); 30360573Skris break; 30460573Skris case CHAN_INPUT_WAIT_DRAIN: 30560573Skris chan_send_eof2(c); 30692555Sdes chan_set_istate(c, CHAN_INPUT_CLOSED); 30760573Skris break; 30860573Skris } 30957429Smarkm} 310181111Sdesvoid 311181111Sdeschan_rcvd_eow(Channel *c) 312181111Sdes{ 313181111Sdes debug2("channel %d: rcvd eow", c->self); 314181111Sdes switch (c->istate) { 315181111Sdes case CHAN_INPUT_OPEN: 316181111Sdes chan_shutdown_read(c); 317181111Sdes chan_set_istate(c, CHAN_INPUT_CLOSED); 318181111Sdes break; 319181111Sdes } 320181111Sdes} 32157429Smarkmstatic void 32292555Sdeschan_rcvd_eof2(Channel *c) 32357429Smarkm{ 324124208Sdes debug2("channel %d: rcvd eof", c->self); 32598675Sdes c->flags |= CHAN_EOF_RCVD; 32692555Sdes if (c->ostate == CHAN_OUTPUT_OPEN) 32792555Sdes chan_set_ostate(c, CHAN_OUTPUT_WAIT_DRAIN); 32860573Skris} 32960573Skrisstatic void 33060573Skrischan_write_failed2(Channel *c) 33160573Skris{ 332124208Sdes debug2("channel %d: write failed", c->self); 33360573Skris switch (c->ostate) { 33460573Skris case CHAN_OUTPUT_OPEN: 33560573Skris case CHAN_OUTPUT_WAIT_DRAIN: 33660573Skris chan_shutdown_write(c); 337181111Sdes if (strcmp(c->ctype, "session") == 0) 338181111Sdes chan_send_eow2(c); 33992555Sdes chan_set_ostate(c, CHAN_OUTPUT_CLOSED); 34060573Skris break; 34160573Skris default: 34292555Sdes error("channel %d: chan_write_failed for ostate %d", 34360573Skris c->self, c->ostate); 34460573Skris break; 34560573Skris } 34660573Skris} 34760573Skrisstatic void 34860573Skrischan_send_eof2(Channel *c) 34960573Skris{ 350124208Sdes debug2("channel %d: send eof", c->self); 35160573Skris switch (c->istate) { 35260573Skris case CHAN_INPUT_WAIT_DRAIN: 35360573Skris packet_start(SSH2_MSG_CHANNEL_EOF); 35460573Skris packet_put_int(c->remote_id); 35560573Skris packet_send(); 35698675Sdes c->flags |= CHAN_EOF_SENT; 35760573Skris break; 35860573Skris default: 35992555Sdes error("channel %d: cannot send eof for istate %d", 36060573Skris c->self, c->istate); 36160573Skris break; 36260573Skris } 36360573Skris} 36460573Skrisstatic void 36560573Skrischan_send_close2(Channel *c) 36660573Skris{ 367124208Sdes debug2("channel %d: send close", c->self); 36860573Skris if (c->ostate != CHAN_OUTPUT_CLOSED || 36960573Skris c->istate != CHAN_INPUT_CLOSED) { 37092555Sdes error("channel %d: cannot send close for istate/ostate %d/%d", 37160573Skris c->self, c->istate, c->ostate); 37260573Skris } else if (c->flags & CHAN_CLOSE_SENT) { 37392555Sdes error("channel %d: already sent close", c->self); 37460573Skris } else { 37560573Skris packet_start(SSH2_MSG_CHANNEL_CLOSE); 37660573Skris packet_put_int(c->remote_id); 37760573Skris packet_send(); 37860573Skris c->flags |= CHAN_CLOSE_SENT; 37960573Skris } 38060573Skris} 381181111Sdesstatic void 382181111Sdeschan_send_eow2(Channel *c) 383181111Sdes{ 384181111Sdes debug2("channel %d: send eow", c->self); 385181111Sdes if (c->ostate == CHAN_OUTPUT_CLOSED) { 386181111Sdes error("channel %d: must not sent eow on closed output", 387181111Sdes c->self); 388181111Sdes return; 389181111Sdes } 390181111Sdes packet_start(SSH2_MSG_CHANNEL_REQUEST); 391181111Sdes packet_put_int(c->remote_id); 392181111Sdes packet_put_cstring("eow@openssh.com"); 393181111Sdes packet_put_char(0); 394181111Sdes packet_send(); 395181111Sdes} 39676259Sgreen 39776259Sgreen/* shared */ 39876259Sgreen 39992555Sdesvoid 40092555Sdeschan_rcvd_ieof(Channel *c) 40192555Sdes{ 40292555Sdes if (compat20) 40392555Sdes chan_rcvd_eof2(c); 40492555Sdes else 40592555Sdes chan_rcvd_ieof1(c); 40692555Sdes if (c->ostate == CHAN_OUTPUT_WAIT_DRAIN && 40798675Sdes buffer_len(&c->output) == 0 && 40898675Sdes !CHANNEL_EFD_OUTPUT_ACTIVE(c)) 40992555Sdes chan_obuf_empty(c); 41092555Sdes} 41192555Sdesvoid 41292555Sdeschan_rcvd_oclose(Channel *c) 41392555Sdes{ 41492555Sdes if (compat20) 41592555Sdes chan_rcvd_close2(c); 41692555Sdes else 41792555Sdes chan_rcvd_oclose1(c); 41892555Sdes} 41992555Sdesvoid 42092555Sdeschan_write_failed(Channel *c) 42192555Sdes{ 42292555Sdes if (compat20) 42392555Sdes chan_write_failed2(c); 42492555Sdes else 42592555Sdes chan_write_failed1(c); 42692555Sdes} 42792555Sdes 42892555Sdesvoid 42992555Sdeschan_mark_dead(Channel *c) 43092555Sdes{ 43192555Sdes c->type = SSH_CHANNEL_ZOMBIE; 43292555Sdes} 43392555Sdes 43476259Sgreenint 435137015Sdeschan_is_dead(Channel *c, int do_send) 43660573Skris{ 43792555Sdes if (c->type == SSH_CHANNEL_ZOMBIE) { 438124208Sdes debug2("channel %d: zombie", c->self); 43992555Sdes return 1; 44092555Sdes } 44176259Sgreen if (c->istate != CHAN_INPUT_CLOSED || c->ostate != CHAN_OUTPUT_CLOSED) 44276259Sgreen return 0; 44376259Sgreen if (!compat20) { 444124208Sdes debug2("channel %d: is dead", c->self); 44576259Sgreen return 1; 44676259Sgreen } 44798675Sdes if ((datafellows & SSH_BUG_EXTEOF) && 44898675Sdes c->extended_usage == CHAN_EXTENDED_WRITE && 44998675Sdes c->efd != -1 && 45098675Sdes buffer_len(&c->extended) > 0) { 45198675Sdes debug2("channel %d: active efd: %d len %d", 45298675Sdes c->self, c->efd, buffer_len(&c->extended)); 45398675Sdes return 0; 45498675Sdes } 45598675Sdes if (!(c->flags & CHAN_CLOSE_SENT)) { 456137015Sdes if (do_send) { 45798675Sdes chan_send_close2(c); 45898675Sdes } else { 45998675Sdes /* channel would be dead if we sent a close */ 46098675Sdes if (c->flags & CHAN_CLOSE_RCVD) { 461124208Sdes debug2("channel %d: almost dead", 46298675Sdes c->self); 46398675Sdes return 1; 46492555Sdes } 46560573Skris } 46657429Smarkm } 46798675Sdes if ((c->flags & CHAN_CLOSE_SENT) && 46898675Sdes (c->flags & CHAN_CLOSE_RCVD)) { 469124208Sdes debug2("channel %d: is dead", c->self); 47098675Sdes return 1; 47198675Sdes } 47276259Sgreen return 0; 47357429Smarkm} 47460573Skris 47560573Skris/* helper */ 47660573Skrisstatic void 47760573Skrischan_shutdown_write(Channel *c) 47860573Skris{ 47992555Sdes buffer_clear(&c->output); 48060573Skris if (compat20 && c->type == SSH_CHANNEL_LARVAL) 48160573Skris return; 48260573Skris /* shutdown failure is allowed if write failed already */ 483124208Sdes debug2("channel %d: close_write", c->self); 48460573Skris if (c->sock != -1) { 48560573Skris if (shutdown(c->sock, SHUT_WR) < 0) 486124208Sdes debug2("channel %d: chan_shutdown_write: " 48792555Sdes "shutdown() failed for fd%d: %.100s", 48860573Skris c->self, c->sock, strerror(errno)); 48960573Skris } else { 49092555Sdes if (channel_close_fd(&c->wfd) < 0) 491124208Sdes logit("channel %d: chan_shutdown_write: " 49292555Sdes "close() failed for fd%d: %.100s", 49360573Skris c->self, c->wfd, strerror(errno)); 49460573Skris } 49560573Skris} 49660573Skrisstatic void 49760573Skrischan_shutdown_read(Channel *c) 49860573Skris{ 49960573Skris if (compat20 && c->type == SSH_CHANNEL_LARVAL) 50060573Skris return; 501124208Sdes debug2("channel %d: close_read", c->self); 50260573Skris if (c->sock != -1) { 50398937Sdes /* 50498937Sdes * shutdown(sock, SHUT_READ) may return ENOTCONN if the 50598937Sdes * write side has been closed already. (bug on Linux) 50698937Sdes * HP-UX may return ENOTCONN also. 50798937Sdes */ 50898937Sdes if (shutdown(c->sock, SHUT_RD) < 0 50998937Sdes && errno != ENOTCONN) 51092555Sdes error("channel %d: chan_shutdown_read: " 51192555Sdes "shutdown() failed for fd%d [i%d o%d]: %.100s", 51292555Sdes c->self, c->sock, c->istate, c->ostate, 51392555Sdes strerror(errno)); 51460573Skris } else { 51592555Sdes if (channel_close_fd(&c->rfd) < 0) 516124208Sdes logit("channel %d: chan_shutdown_read: " 51792555Sdes "close() failed for fd%d: %.100s", 51860573Skris c->self, c->rfd, strerror(errno)); 51960573Skris } 52060573Skris} 521