[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.9

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