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

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.13    ! markus     31: RCSID("$Id: nchan.c,v 1.12 2000/03/28 20:34:14 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.13    ! markus     40: #include "ssh2.h"
        !            41: #include "compat.h"
1.3       markus     42:
1.13    ! markus     43: /* functions manipulating channel states */
1.3       markus     44: /*
1.6       markus     45:  * EVENTS update channel input/output states execute ACTIONS
1.3       markus     46:  */
1.13    ! markus     47: /* events concerning the INPUT from socket for channel (istate) */
        !            48: chan_event_fn *chan_rcvd_oclose                        = NULL;
        !            49: chan_event_fn *chan_read_failed                        = NULL;
        !            50: chan_event_fn *chan_ibuf_empty                 = NULL;
        !            51: /* events concerning the OUTPUT from channel for socket (ostate) */
        !            52: chan_event_fn *chan_rcvd_ieof                  = NULL;
        !            53: chan_event_fn *chan_write_failed               = NULL;
        !            54: chan_event_fn *chan_obuf_empty                 = NULL;
        !            55: /*
        !            56:  * ACTIONS: should never update the channel states
        !            57:  */
        !            58: static void    chan_send_ieof1(Channel *c);
        !            59: static void    chan_send_oclose1(Channel *c);
        !            60: static void    chan_send_close2(Channel *c);
        !            61: static void    chan_send_eof2(Channel *c);
        !            62:
        !            63: /* channel cleanup */
        !            64: chan_event_fn *chan_delete_if_full_closed      = NULL;
        !            65:
        !            66: /* helper */
        !            67: static void    chan_shutdown_write(Channel *c);
        !            68: static void    chan_shutdown_read(Channel *c);
        !            69:
        !            70: /*
        !            71:  * SSH1 specific implementation of event functions
        !            72:  */
1.6       markus     73:
1.13    ! markus     74: static void
        !            75: chan_rcvd_oclose1(Channel *c)
1.6       markus     76: {
1.13    ! markus     77:        debug("channel %d: rcvd oclose", c->self);
1.6       markus     78:        switch (c->istate) {
1.3       markus     79:        case CHAN_INPUT_WAIT_OCLOSE:
1.13    ! markus     80:                debug("channel %d: input wait_oclose -> closed", c->self);
1.6       markus     81:                c->istate = CHAN_INPUT_CLOSED;
1.3       markus     82:                break;
                     83:        case CHAN_INPUT_OPEN:
1.13    ! markus     84:                debug("channel %d: input open -> closed", c->self);
1.3       markus     85:                chan_shutdown_read(c);
1.13    ! markus     86:                chan_send_ieof1(c);
1.6       markus     87:                c->istate = CHAN_INPUT_CLOSED;
1.10      markus     88:                break;
                     89:        case CHAN_INPUT_WAIT_DRAIN:
                     90:                /* both local read_failed and remote write_failed  */
1.13    ! markus     91:                log("channel %d: input drain -> closed", c->self);
        !            92:                chan_send_ieof1(c);
1.10      markus     93:                c->istate = CHAN_INPUT_CLOSED;
1.3       markus     94:                break;
                     95:        default:
1.13    ! markus     96:                error("channel %d: protocol error: chan_rcvd_oclose for istate %d",
        !            97:                    c->self, c->istate);
1.10      markus     98:                return;
1.3       markus     99:        }
1.1       markus    100: }
1.13    ! markus    101: static void
        !           102: chan_read_failed_12(Channel *c)
1.6       markus    103: {
1.13    ! markus    104:        debug("channel %d: read failed", c->self);
1.6       markus    105:        switch (c->istate) {
1.3       markus    106:        case CHAN_INPUT_OPEN:
1.13    ! markus    107:                debug("channel %d: input open -> drain", c->self);
1.3       markus    108:                chan_shutdown_read(c);
1.6       markus    109:                c->istate = CHAN_INPUT_WAIT_DRAIN;
1.3       markus    110:                break;
                    111:        default:
1.13    ! markus    112:                error("channel %d: internal error: we do not read, but chan_read_failed for istate %d",
        !           113:                    c->self, c->istate);
1.3       markus    114:                break;
1.1       markus    115:        }
                    116: }
1.13    ! markus    117: static void
        !           118: chan_ibuf_empty1(Channel *c)
1.6       markus    119: {
1.13    ! markus    120:        debug("channel %d: ibuf empty", c->self);
1.6       markus    121:        if (buffer_len(&c->input)) {
1.13    ! markus    122:                error("channel %d: internal error: chan_ibuf_empty for non empty buffer",
        !           123:                    c->self);
1.3       markus    124:                return;
                    125:        }
1.6       markus    126:        switch (c->istate) {
1.3       markus    127:        case CHAN_INPUT_WAIT_DRAIN:
1.13    ! markus    128:                debug("channel %d: input drain -> wait_oclose", c->self);
        !           129:                chan_send_ieof1(c);
1.6       markus    130:                c->istate = CHAN_INPUT_WAIT_OCLOSE;
1.3       markus    131:                break;
                    132:        default:
1.13    ! markus    133:                error("channel %d: internal error: chan_ibuf_empty for istate %d",
        !           134:                    c->self, c->istate);
1.3       markus    135:                break;
1.1       markus    136:        }
                    137: }
1.13    ! markus    138: static void
        !           139: chan_rcvd_ieof1(Channel *c)
1.6       markus    140: {
1.13    ! markus    141:        debug("channel %d: rcvd ieof", c->self);
1.6       markus    142:        switch (c->ostate) {
1.3       markus    143:        case CHAN_OUTPUT_OPEN:
1.13    ! markus    144:                debug("channel %d: output open -> drain", c->self);
1.6       markus    145:                c->ostate = CHAN_OUTPUT_WAIT_DRAIN;
1.3       markus    146:                break;
                    147:        case CHAN_OUTPUT_WAIT_IEOF:
1.13    ! markus    148:                debug("channel %d: output wait_ieof -> closed", c->self);
1.6       markus    149:                c->ostate = CHAN_OUTPUT_CLOSED;
1.3       markus    150:                break;
                    151:        default:
1.13    ! markus    152:                error("channel %d: protocol error: chan_rcvd_ieof for ostate %d",
        !           153:                    c->self, c->ostate);
1.3       markus    154:                break;
                    155:        }
                    156: }
1.13    ! markus    157: static void
        !           158: chan_write_failed1(Channel *c)
1.6       markus    159: {
1.13    ! markus    160:        debug("channel %d: write failed", c->self);
1.6       markus    161:        switch (c->ostate) {
1.3       markus    162:        case CHAN_OUTPUT_OPEN:
1.13    ! markus    163:                debug("channel %d: output open -> wait_ieof", c->self);
        !           164:                chan_send_oclose1(c);
1.6       markus    165:                c->ostate = CHAN_OUTPUT_WAIT_IEOF;
1.3       markus    166:                break;
                    167:        case CHAN_OUTPUT_WAIT_DRAIN:
1.13    ! markus    168:                debug("channel %d: output wait_drain -> closed", c->self);
        !           169:                chan_send_oclose1(c);
1.6       markus    170:                c->ostate = CHAN_OUTPUT_CLOSED;
1.3       markus    171:                break;
                    172:        default:
1.13    ! markus    173:                error("channel %d: internal error: chan_write_failed for ostate %d",
        !           174:                    c->self, c->ostate);
1.3       markus    175:                break;
                    176:        }
                    177: }
1.13    ! markus    178: static void
        !           179: chan_obuf_empty1(Channel *c)
1.6       markus    180: {
1.13    ! markus    181:        debug("channel %d: obuf empty", c->self);
1.6       markus    182:        if (buffer_len(&c->output)) {
1.13    ! markus    183:                error("channel %d: internal error: chan_obuf_empty for non empty buffer",
        !           184:                    c->self);
1.3       markus    185:                return;
                    186:        }
1.6       markus    187:        switch (c->ostate) {
1.3       markus    188:        case CHAN_OUTPUT_WAIT_DRAIN:
1.13    ! markus    189:                debug("channel %d: output drain -> closed", c->self);
        !           190:                chan_send_oclose1(c);
1.6       markus    191:                c->ostate = CHAN_OUTPUT_CLOSED;
1.3       markus    192:                break;
                    193:        default:
1.13    ! markus    194:                error("channel %d: internal error: chan_obuf_empty for ostate %d",
        !           195:                    c->self, c->ostate);
1.3       markus    196:                break;
                    197:        }
                    198: }
                    199: static void
1.13    ! markus    200: chan_send_ieof1(Channel *c)
1.6       markus    201: {
1.13    ! markus    202:        debug("channel %d: send ieof", c->self);
1.6       markus    203:        switch (c->istate) {
1.3       markus    204:        case CHAN_INPUT_OPEN:
                    205:        case CHAN_INPUT_WAIT_DRAIN:
                    206:                packet_start(SSH_MSG_CHANNEL_INPUT_EOF);
                    207:                packet_put_int(c->remote_id);
                    208:                packet_send();
                    209:                break;
                    210:        default:
1.13    ! markus    211:                error("channel %d: internal error: cannot send ieof for istate %d",
        !           212:                    c->self, c->istate);
1.3       markus    213:                break;
1.1       markus    214:        }
                    215: }
1.3       markus    216: static void
1.13    ! markus    217: chan_send_oclose1(Channel *c)
1.6       markus    218: {
1.13    ! markus    219:        debug("channel %d: send oclose", c->self);
1.6       markus    220:        switch (c->ostate) {
1.3       markus    221:        case CHAN_OUTPUT_OPEN:
                    222:        case CHAN_OUTPUT_WAIT_DRAIN:
                    223:                chan_shutdown_write(c);
                    224:                buffer_consume(&c->output, buffer_len(&c->output));
                    225:                packet_start(SSH_MSG_CHANNEL_OUTPUT_CLOSE);
                    226:                packet_put_int(c->remote_id);
                    227:                packet_send();
                    228:                break;
                    229:        default:
1.13    ! markus    230:                error("channel %d: internal error: cannot send oclose for ostate %d",
        !           231:                     c->self, c->ostate);
1.3       markus    232:                break;
1.1       markus    233:        }
                    234: }
1.13    ! markus    235: static void
        !           236: chan_delete_if_full_closed1(Channel *c)
        !           237: {
        !           238:        if (c->istate == CHAN_INPUT_CLOSED && c->ostate == CHAN_OUTPUT_CLOSED) {
        !           239:                debug("channel %d: full closed", c->self);
        !           240:                channel_free(c->self);
        !           241:        }
        !           242: }
1.6       markus    243:
1.13    ! markus    244: /*
        !           245:  * the same for SSH2
        !           246:  */
        !           247: static void
        !           248: chan_rcvd_oclose2(Channel *c)
        !           249: {
        !           250:        debug("channel %d: rcvd close", c->self);
        !           251:        if (c->flags & CHAN_CLOSE_RCVD)
        !           252:                error("channel %d: protocol error: close rcvd twice", c->self);
        !           253:        c->flags |= CHAN_CLOSE_RCVD;
        !           254:        if (c->type == SSH_CHANNEL_LARVAL) {
        !           255:                /* tear down larval channels immediately */
        !           256:                c->ostate = CHAN_OUTPUT_CLOSED;
        !           257:                c->istate = CHAN_INPUT_CLOSED;
        !           258:                return;
        !           259:        }
        !           260:        switch (c->ostate) {
        !           261:        case CHAN_OUTPUT_OPEN:
        !           262:                /* wait until a data from the channel is consumed if a CLOSE is received */
        !           263:                debug("channel %d: output open -> drain", c->self);
        !           264:                c->ostate = CHAN_OUTPUT_WAIT_DRAIN;
        !           265:                break;
        !           266:        }
        !           267:        switch (c->istate) {
        !           268:        case CHAN_INPUT_OPEN:
        !           269:                debug("channel %d: input open -> closed", c->self);
        !           270:                chan_shutdown_read(c);
        !           271:                break;
        !           272:        case CHAN_INPUT_WAIT_DRAIN:
        !           273:                debug("channel %d: input drain -> closed", c->self);
        !           274:                chan_send_eof2(c);
        !           275:                break;
        !           276:        }
        !           277:        c->istate = CHAN_INPUT_CLOSED;
        !           278: }
        !           279: static void
        !           280: chan_ibuf_empty2(Channel *c)
        !           281: {
        !           282:        debug("channel %d: ibuf empty", c->self);
        !           283:        if (buffer_len(&c->input)) {
        !           284:                error("channel %d: internal error: chan_ibuf_empty for non empty buffer",
        !           285:                     c->self);
        !           286:                return;
        !           287:        }
        !           288:        switch (c->istate) {
        !           289:        case CHAN_INPUT_WAIT_DRAIN:
        !           290:                debug("channel %d: input drain -> closed", c->self);
        !           291:                if (!(c->flags & CHAN_CLOSE_SENT))
        !           292:                        chan_send_eof2(c);
        !           293:                c->istate = CHAN_INPUT_CLOSED;
        !           294:                break;
        !           295:        default:
        !           296:                error("channel %d: internal error: chan_ibuf_empty for istate %d",
        !           297:                     c->self, c->istate);
        !           298:                break;
        !           299:        }
        !           300: }
        !           301: static void
        !           302: chan_rcvd_ieof2(Channel *c)
        !           303: {
        !           304:        debug("channel %d: rcvd eof", c->self);
        !           305:        if (c->ostate == CHAN_OUTPUT_OPEN) {
        !           306:                debug("channel %d: output open -> drain", c->self);
        !           307:                c->ostate = CHAN_OUTPUT_WAIT_DRAIN;
        !           308:        }
        !           309: }
        !           310: static void
        !           311: chan_write_failed2(Channel *c)
        !           312: {
        !           313:        debug("channel %d: write failed", c->self);
        !           314:        switch (c->ostate) {
        !           315:        case CHAN_OUTPUT_OPEN:
        !           316:                debug("channel %d: output open -> closed", c->self);
        !           317:                chan_shutdown_write(c); // ??
        !           318:                c->ostate = CHAN_OUTPUT_CLOSED;
        !           319:                break;
        !           320:        case CHAN_OUTPUT_WAIT_DRAIN:
        !           321:                debug("channel %d: output drain -> closed", c->self);
        !           322:                chan_shutdown_write(c);
        !           323:                c->ostate = CHAN_OUTPUT_CLOSED;
        !           324:                break;
        !           325:        default:
        !           326:                error("channel %d: internal error: chan_write_failed for ostate %d",
        !           327:                    c->self, c->ostate);
        !           328:                break;
        !           329:        }
        !           330: }
        !           331: static void
        !           332: chan_obuf_empty2(Channel *c)
        !           333: {
        !           334:        debug("channel %d: obuf empty", c->self);
        !           335:        if (buffer_len(&c->output)) {
        !           336:                error("internal error: chan_obuf_empty %d for non empty buffer",
        !           337:                    c->self);
        !           338:                return;
        !           339:        }
        !           340:        switch (c->ostate) {
        !           341:        case CHAN_OUTPUT_WAIT_DRAIN:
        !           342:                debug("channel %d: output drain -> closed", c->self);
        !           343:                chan_shutdown_write(c);
        !           344:                c->ostate = CHAN_OUTPUT_CLOSED;
        !           345:                break;
        !           346:        default:
        !           347:                error("channel %d: internal error: chan_obuf_empty for ostate %d",
        !           348:                    c->self, c->ostate);
        !           349:                break;
        !           350:        }
        !           351: }
1.3       markus    352: static void
1.13    ! markus    353: chan_send_eof2(Channel *c)
1.6       markus    354: {
1.13    ! markus    355:        debug("channel %d: send eof", c->self);
        !           356:        switch (c->istate) {
        !           357:        case CHAN_INPUT_WAIT_DRAIN:
        !           358:                packet_start(SSH2_MSG_CHANNEL_EOF);
        !           359:                packet_put_int(c->remote_id);
        !           360:                packet_send();
        !           361:                break;
        !           362:        default:
        !           363:                error("channel %d: internal error: cannot send eof for istate %d",
        !           364:                    c->self, c->istate);
        !           365:                break;
        !           366:        }
1.1       markus    367: }
1.3       markus    368: static void
1.13    ! markus    369: chan_send_close2(Channel *c)
1.6       markus    370: {
1.13    ! markus    371:        debug("channel %d: send close", c->self);
        !           372:        if (c->ostate != CHAN_OUTPUT_CLOSED ||
        !           373:            c->istate != CHAN_INPUT_CLOSED) {
        !           374:                error("channel %d: internal error: cannot send close for istate/ostate %d/%d",
        !           375:                    c->self, c->istate, c->ostate);
        !           376:        } else if (c->flags & CHAN_CLOSE_SENT) {
        !           377:                error("channel %d: internal error: already sent close", c->self);
        !           378:        } else {
        !           379:                packet_start(SSH2_MSG_CHANNEL_CLOSE);
        !           380:                packet_put_int(c->remote_id);
        !           381:                packet_send();
        !           382:                c->flags |= CHAN_CLOSE_SENT;
        !           383:        }
1.1       markus    384: }
1.13    ! markus    385: static void
        !           386: chan_delete_if_full_closed2(Channel *c)
1.6       markus    387: {
                    388:        if (c->istate == CHAN_INPUT_CLOSED && c->ostate == CHAN_OUTPUT_CLOSED) {
1.13    ! markus    389:                if (!(c->flags & CHAN_CLOSE_SENT)) {
        !           390:                        chan_send_close2(c);
        !           391:                }
        !           392:                if ((c->flags & CHAN_CLOSE_SENT) &&
        !           393:                    (c->flags & CHAN_CLOSE_RCVD)) {
        !           394:                        debug("channel %d: full closed2", c->self);
        !           395:                        channel_free(c->self);
        !           396:                }
1.1       markus    397:        }
1.3       markus    398: }
1.13    ! markus    399:
        !           400: /* shared */
1.3       markus    401: void
1.6       markus    402: chan_init_iostates(Channel *c)
                    403: {
                    404:        c->ostate = CHAN_OUTPUT_OPEN;
                    405:        c->istate = CHAN_INPUT_OPEN;
1.13    ! markus    406:        c->flags = 0;
        !           407: }
        !           408:
        !           409: /* init */
        !           410: void
        !           411: chan_init(void)
        !           412: {
        !           413:        if (compat20) {
        !           414:                chan_rcvd_oclose                = chan_rcvd_oclose2;
        !           415:                chan_read_failed                = chan_read_failed_12;
        !           416:                chan_ibuf_empty                 = chan_ibuf_empty2;
        !           417:
        !           418:                chan_rcvd_ieof                  = chan_rcvd_ieof2;
        !           419:                chan_write_failed               = chan_write_failed2;
        !           420:                chan_obuf_empty                 = chan_obuf_empty2;
        !           421:
        !           422:                chan_delete_if_full_closed      = chan_delete_if_full_closed2;
        !           423:        } else {
        !           424:                chan_rcvd_oclose                = chan_rcvd_oclose1;
        !           425:                chan_read_failed                = chan_read_failed_12;
        !           426:                chan_ibuf_empty                 = chan_ibuf_empty1;
        !           427:
        !           428:                chan_rcvd_ieof                  = chan_rcvd_ieof1;
        !           429:                chan_write_failed               = chan_write_failed1;
        !           430:                chan_obuf_empty                 = chan_obuf_empty1;
        !           431:
        !           432:                chan_delete_if_full_closed      = chan_delete_if_full_closed1;
        !           433:        }
        !           434: }
        !           435:
        !           436: /* helper */
        !           437: static void
        !           438: chan_shutdown_write(Channel *c)
        !           439: {
        !           440:        buffer_consume(&c->output, buffer_len(&c->output));
        !           441:        if (compat20 && c->type == SSH_CHANNEL_LARVAL)
        !           442:                return;
        !           443:        /* shutdown failure is allowed if write failed already */
        !           444:        debug("channel %d: close_write", c->self);
        !           445:        if (c->sock != -1) {
        !           446:                if (shutdown(c->sock, SHUT_WR) < 0)
        !           447:                        debug("channel %d: chan_shutdown_write: shutdown() failed for fd%d: %.100s",
        !           448:                            c->self, c->sock, strerror(errno));
        !           449:        } else {
        !           450:                if (close(c->wfd) < 0)
        !           451:                        log("channel %d: chan_shutdown_write: close() failed for fd%d: %.100s",
        !           452:                            c->self, c->wfd, strerror(errno));
        !           453:                c->wfd = -1;
        !           454:        }
        !           455: }
        !           456: static void
        !           457: chan_shutdown_read(Channel *c)
        !           458: {
        !           459:        if (compat20 && c->type == SSH_CHANNEL_LARVAL)
        !           460:                return;
        !           461:        debug("channel %d: close_read", c->self);
        !           462:        if (c->sock != -1) {
        !           463:                if (shutdown(c->sock, SHUT_RD) < 0)
        !           464:                        error("channel %d: chan_shutdown_read: shutdown() failed for fd%d [i%d o%d]: %.100s",
        !           465:                            c->self, c->sock, c->istate, c->ostate, strerror(errno));
        !           466:        } else {
        !           467:                if (close(c->rfd) < 0)
        !           468:                        log("channel %d: chan_shutdown_read: close() failed for fd%d: %.100s",
        !           469:                            c->self, c->rfd, strerror(errno));
        !           470:                c->rfd = -1;
        !           471:        }
1.1       markus    472: }