[BACK]Return to nchan.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / ssh

Annotation of src/usr.bin/ssh/nchan.c, Revision 1.11

1.7       markus      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:
1.1       markus     30: #include "includes.h"
1.11    ! markus     31: RCSID("$Id: nchan.c,v 1.10 2000/01/10 10:15:28 markus Exp $");
1.2       markus     32:
1.1       markus     33: #include "ssh.h"
                     34:
                     35: #include "buffer.h"
1.3       markus     36: #include "packet.h"
1.1       markus     37: #include "channels.h"
                     38: #include "nchan.h"
                     39:
1.3       markus     40: static void chan_send_ieof(Channel *c);
                     41: static void chan_send_oclose(Channel *c);
                     42: static void chan_shutdown_write(Channel *c);
                     43: static void chan_shutdown_read(Channel *c);
                     44:
                     45: /*
1.6       markus     46:  * EVENTS update channel input/output states execute ACTIONS
1.3       markus     47:  */
1.6       markus     48:
1.3       markus     49: /* events concerning the INPUT from socket for channel (istate) */
1.1       markus     50: void
1.6       markus     51: chan_rcvd_oclose(Channel *c)
                     52: {
                     53:        switch (c->istate) {
1.3       markus     54:        case CHAN_INPUT_WAIT_OCLOSE:
1.4       markus     55:                debug("channel %d: INPUT_WAIT_OCLOSE -> INPUT_CLOSED [rcvd OCLOSE]", c->self);
1.6       markus     56:                c->istate = CHAN_INPUT_CLOSED;
1.3       markus     57:                break;
                     58:        case CHAN_INPUT_OPEN:
                     59:                debug("channel %d: INPUT_OPEN -> INPUT_CLOSED [rvcd OCLOSE, send IEOF]", c->self);
                     60:                chan_shutdown_read(c);
                     61:                chan_send_ieof(c);
1.6       markus     62:                c->istate = CHAN_INPUT_CLOSED;
1.10      markus     63:                break;
                     64:        case CHAN_INPUT_WAIT_DRAIN:
                     65:                /* both local read_failed and remote write_failed  */
                     66:                log("channel %d: INPUT_WAIT_DRAIN -> INPUT_CLOSED [rvcd OCLOSE, send IEOF]", c->self);
                     67:                debug("channel %d: INPUT_WAIT_DRAIN -> INPUT_CLOSED [rvcd OCLOSE, send IEOF]", c->self);
                     68:                chan_send_ieof(c);
                     69:                c->istate = CHAN_INPUT_CLOSED;
1.3       markus     70:                break;
                     71:        default:
1.9       markus     72:                error("protocol error: chan_rcvd_oclose %d for istate %d", c->self, c->istate);
1.10      markus     73:                return;
1.3       markus     74:        }
1.10      markus     75:        chan_delete_if_full_closed(c);
1.1       markus     76: }
                     77: void
1.6       markus     78: chan_read_failed(Channel *c)
                     79: {
                     80:        switch (c->istate) {
1.3       markus     81:        case CHAN_INPUT_OPEN:
                     82:                debug("channel %d: INPUT_OPEN -> INPUT_WAIT_DRAIN [read failed]", c->self);
                     83:                chan_shutdown_read(c);
1.6       markus     84:                c->istate = CHAN_INPUT_WAIT_DRAIN;
1.3       markus     85:                break;
                     86:        default:
1.9       markus     87:                error("internal error: we do not read, but chan_read_failed %d for istate %d",
1.6       markus     88:                      c->self, c->istate);
1.3       markus     89:                break;
1.1       markus     90:        }
                     91: }
                     92: void
1.6       markus     93: chan_ibuf_empty(Channel *c)
                     94: {
                     95:        if (buffer_len(&c->input)) {
1.9       markus     96:                error("internal error: chan_ibuf_empty %d for non empty buffer", c->self);
1.3       markus     97:                return;
                     98:        }
1.6       markus     99:        switch (c->istate) {
1.3       markus    100:        case CHAN_INPUT_WAIT_DRAIN:
1.4       markus    101:                debug("channel %d: INPUT_WAIT_DRAIN -> INPUT_WAIT_OCLOSE [inbuf empty, send IEOF]", c->self);
1.3       markus    102:                chan_send_ieof(c);
1.6       markus    103:                c->istate = CHAN_INPUT_WAIT_OCLOSE;
1.3       markus    104:                break;
                    105:        default:
1.9       markus    106:                error("internal error: chan_ibuf_empty %d for istate %d", c->self, c->istate);
1.3       markus    107:                break;
1.1       markus    108:        }
                    109: }
1.6       markus    110:
1.3       markus    111: /* events concerning the OUTPUT from channel for socket (ostate) */
1.1       markus    112: void
1.6       markus    113: chan_rcvd_ieof(Channel *c)
                    114: {
                    115:        switch (c->ostate) {
1.3       markus    116:        case CHAN_OUTPUT_OPEN:
                    117:                debug("channel %d: OUTPUT_OPEN -> OUTPUT_WAIT_DRAIN [rvcd IEOF]", c->self);
1.6       markus    118:                c->ostate = CHAN_OUTPUT_WAIT_DRAIN;
1.3       markus    119:                break;
                    120:        case CHAN_OUTPUT_WAIT_IEOF:
                    121:                debug("channel %d: OUTPUT_WAIT_IEOF -> OUTPUT_CLOSED [rvcd IEOF]", c->self);
1.6       markus    122:                c->ostate = CHAN_OUTPUT_CLOSED;
1.10      markus    123:                chan_delete_if_full_closed(c);
1.3       markus    124:                break;
                    125:        default:
1.9       markus    126:                error("protocol error: chan_rcvd_ieof %d for ostate %d", c->self, c->ostate);
1.3       markus    127:                break;
                    128:        }
                    129: }
                    130: void
1.6       markus    131: chan_write_failed(Channel *c)
                    132: {
                    133:        switch (c->ostate) {
1.3       markus    134:        case CHAN_OUTPUT_OPEN:
                    135:                debug("channel %d: OUTPUT_OPEN -> OUTPUT_WAIT_IEOF [write failed]", c->self);
                    136:                chan_send_oclose(c);
1.6       markus    137:                c->ostate = CHAN_OUTPUT_WAIT_IEOF;
1.3       markus    138:                break;
                    139:        case CHAN_OUTPUT_WAIT_DRAIN:
                    140:                debug("channel %d: OUTPUT_WAIT_DRAIN -> OUTPUT_CLOSED [write failed]", c->self);
                    141:                chan_send_oclose(c);
1.6       markus    142:                c->ostate = CHAN_OUTPUT_CLOSED;
1.10      markus    143:                chan_delete_if_full_closed(c);
1.3       markus    144:                break;
                    145:        default:
1.9       markus    146:                error("internal error: chan_write_failed %d for ostate %d", c->self, c->ostate);
1.3       markus    147:                break;
                    148:        }
                    149: }
                    150: void
1.6       markus    151: chan_obuf_empty(Channel *c)
                    152: {
                    153:        if (buffer_len(&c->output)) {
                    154:                debug("internal error: chan_obuf_empty %d for non empty buffer", c->self);
1.3       markus    155:                return;
                    156:        }
1.6       markus    157:        switch (c->ostate) {
1.3       markus    158:        case CHAN_OUTPUT_WAIT_DRAIN:
                    159:                debug("channel %d: OUTPUT_WAIT_DRAIN -> OUTPUT_CLOSED [obuf empty, send OCLOSE]", c->self);
                    160:                chan_send_oclose(c);
1.6       markus    161:                c->ostate = CHAN_OUTPUT_CLOSED;
1.10      markus    162:                chan_delete_if_full_closed(c);
1.3       markus    163:                break;
                    164:        default:
1.9       markus    165:                error("internal error: chan_obuf_empty %d for ostate %d", c->self, c->ostate);
1.3       markus    166:                break;
                    167:        }
                    168: }
1.6       markus    169:
1.3       markus    170: /*
1.6       markus    171:  * ACTIONS: should never update the channel states: c->istate or c->ostate
1.3       markus    172:  */
                    173: static void
1.6       markus    174: chan_send_ieof(Channel *c)
                    175: {
                    176:        switch (c->istate) {
1.3       markus    177:        case CHAN_INPUT_OPEN:
                    178:        case CHAN_INPUT_WAIT_DRAIN:
                    179:                packet_start(SSH_MSG_CHANNEL_INPUT_EOF);
                    180:                packet_put_int(c->remote_id);
                    181:                packet_send();
                    182:                break;
                    183:        default:
1.9       markus    184:                error("internal error: channel %d: cannot send IEOF for istate %d", c->self, c->istate);
1.3       markus    185:                break;
1.1       markus    186:        }
                    187: }
1.3       markus    188: static void
1.6       markus    189: chan_send_oclose(Channel *c)
                    190: {
                    191:        switch (c->ostate) {
1.3       markus    192:        case CHAN_OUTPUT_OPEN:
                    193:        case CHAN_OUTPUT_WAIT_DRAIN:
                    194:                chan_shutdown_write(c);
                    195:                buffer_consume(&c->output, buffer_len(&c->output));
                    196:                packet_start(SSH_MSG_CHANNEL_OUTPUT_CLOSE);
                    197:                packet_put_int(c->remote_id);
                    198:                packet_send();
                    199:                break;
                    200:        default:
1.9       markus    201:                error("internal error: channel %d: cannot send OCLOSE for ostate %d", c->self, c->istate);
1.3       markus    202:                break;
1.1       markus    203:        }
                    204: }
1.6       markus    205:
1.3       markus    206: /* helper */
                    207: static void
1.6       markus    208: chan_shutdown_write(Channel *c)
                    209: {
1.8       markus    210:        /* shutdown failure is allowed if write failed already */
1.3       markus    211:        debug("channel %d: shutdown_write", c->self);
1.6       markus    212:        if (shutdown(c->sock, SHUT_WR) < 0)
1.8       markus    213:                debug("chan_shutdown_write failed for #%d/fd%d: %.100s",
1.6       markus    214:                      c->self, c->sock, strerror(errno));
1.1       markus    215: }
1.3       markus    216: static void
1.6       markus    217: chan_shutdown_read(Channel *c)
                    218: {
1.3       markus    219:        debug("channel %d: shutdown_read", c->self);
1.6       markus    220:        if (shutdown(c->sock, SHUT_RD) < 0)
1.10      markus    221:                error("chan_shutdown_read failed for #%d/fd%d [i%d o%d]: %.100s",
                    222:                      c->self, c->sock, c->istate, c->ostate, strerror(errno));
1.1       markus    223: }
1.11    ! markus    224: void
1.10      markus    225: chan_delete_if_full_closed(Channel *c)
1.6       markus    226: {
                    227:        if (c->istate == CHAN_INPUT_CLOSED && c->ostate == CHAN_OUTPUT_CLOSED) {
1.10      markus    228:                debug("channel %d: full closed", c->self);
1.1       markus    229:                channel_free(c->self);
                    230:        }
1.3       markus    231: }
                    232: void
1.6       markus    233: chan_init_iostates(Channel *c)
                    234: {
                    235:        c->ostate = CHAN_OUTPUT_OPEN;
                    236:        c->istate = CHAN_INPUT_OPEN;
1.1       markus    237: }