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

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