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

1.7       markus      1: /*
1.30      markus      2:  * Copyright (c) 1999, 2000, 2001 Markus Friedl.  All rights reserved.
1.7       markus      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:  *
                     13:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
                     14:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
                     15:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
                     16:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
                     17:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
                     18:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
                     19:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
                     20:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
                     21:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
                     22:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     23:  */
                     24:
1.1       markus     25: #include "includes.h"
1.39    ! markus     26: RCSID("$OpenBSD: nchan.c,v 1.38 2002/01/14 13:22:35 markus Exp $");
1.1       markus     27:
1.22      markus     28: #include "ssh1.h"
                     29: #include "ssh2.h"
1.1       markus     30: #include "buffer.h"
1.3       markus     31: #include "packet.h"
1.1       markus     32: #include "channels.h"
1.13      markus     33: #include "compat.h"
1.22      markus     34: #include "log.h"
1.3       markus     35:
1.28      markus     36: /*
                     37:  * SSH Protocol 1.5 aka New Channel Protocol
                     38:  * Thanks to Martina, Axel and everyone who left Erlangen, leaving me bored.
                     39:  * Written by Markus Friedl in October 1999
                     40:  *
                     41:  * Protocol versions 1.3 and 1.5 differ in the handshake protocol used for the
                     42:  * tear down of channels:
                     43:  *
                     44:  * 1.3:        strict request-ack-protocol:
                     45:  *     CLOSE   ->
                     46:  *             <-  CLOSE_CONFIRM
                     47:  *
                     48:  * 1.5:        uses variations of:
                     49:  *     IEOF    ->
                     50:  *             <-  OCLOSE
                     51:  *             <-  IEOF
                     52:  *     OCLOSE  ->
                     53:  *     i.e. both sides have to close the channel
                     54:  *
                     55:  * 2.0: the EOF messages are optional
                     56:  *
                     57:  * See the debugging output from 'ssh -v' and 'sshd -d' of
                     58:  * ssh-1.2.27 as an example.
                     59:  *
                     60:  */
                     61:
1.13      markus     62: /* functions manipulating channel states */
1.3       markus     63: /*
1.6       markus     64:  * EVENTS update channel input/output states execute ACTIONS
1.3       markus     65:  */
1.13      markus     66: /* events concerning the INPUT from socket for channel (istate) */
                     67: chan_event_fn *chan_rcvd_oclose                        = NULL;
                     68: chan_event_fn *chan_read_failed                        = NULL;
                     69: chan_event_fn *chan_ibuf_empty                 = NULL;
                     70: /* events concerning the OUTPUT from channel for socket (ostate) */
                     71: chan_event_fn *chan_rcvd_ieof                  = NULL;
                     72: chan_event_fn *chan_write_failed               = NULL;
                     73: chan_event_fn *chan_obuf_empty                 = NULL;
                     74: /*
                     75:  * ACTIONS: should never update the channel states
                     76:  */
1.29      itojun     77: static void    chan_send_ieof1(Channel *);
                     78: static void    chan_send_oclose1(Channel *);
                     79: static void    chan_send_close2(Channel *);
                     80: static void    chan_send_eof2(Channel *);
1.13      markus     81:
                     82: /* helper */
1.29      itojun     83: static void    chan_shutdown_write(Channel *);
                     84: static void    chan_shutdown_read(Channel *);
1.13      markus     85:
1.37      markus     86: static char *ostates[] = { "open", "drain", "wait_ieof", "closed" };
                     87: static char *istates[] = { "open", "drain", "wait_oclose", "closed" };
                     88:
                     89: static void
                     90: chan_set_istate(Channel *c, u_int next)
                     91: {
                     92:        if (c->istate > CHAN_INPUT_CLOSED || next > CHAN_INPUT_CLOSED)
                     93:                fatal("chan_set_istate: bad state %d -> %d", c->istate, next);
                     94:        debug("channel %d: input %s -> %s", c->self, istates[c->istate],
                     95:            istates[next]);
                     96:        c->istate = next;
                     97: }
                     98: static void
                     99: chan_set_ostate(Channel *c, u_int next)
                    100: {
                    101:        if (c->ostate > CHAN_OUTPUT_CLOSED || next > CHAN_OUTPUT_CLOSED)
                    102:                fatal("chan_set_ostate: bad state %d -> %d", c->ostate, next);
                    103:        debug("channel %d: output %s -> %s", c->self, ostates[c->ostate],
                    104:            ostates[next]);
                    105:        c->ostate = next;
                    106: }
                    107:
1.13      markus    108: /*
                    109:  * SSH1 specific implementation of event functions
                    110:  */
1.6       markus    111:
1.13      markus    112: static void
                    113: chan_rcvd_oclose1(Channel *c)
1.6       markus    114: {
1.13      markus    115:        debug("channel %d: rcvd oclose", c->self);
1.6       markus    116:        switch (c->istate) {
1.3       markus    117:        case CHAN_INPUT_WAIT_OCLOSE:
1.37      markus    118:                chan_set_istate(c, CHAN_INPUT_CLOSED);
1.3       markus    119:                break;
                    120:        case CHAN_INPUT_OPEN:
                    121:                chan_shutdown_read(c);
1.13      markus    122:                chan_send_ieof1(c);
1.37      markus    123:                chan_set_istate(c, CHAN_INPUT_CLOSED);
1.10      markus    124:                break;
                    125:        case CHAN_INPUT_WAIT_DRAIN:
                    126:                /* both local read_failed and remote write_failed  */
1.13      markus    127:                chan_send_ieof1(c);
1.37      markus    128:                chan_set_istate(c, CHAN_INPUT_CLOSED);
1.3       markus    129:                break;
                    130:        default:
1.28      markus    131:                error("channel %d: protocol error: rcvd_oclose for istate %d",
1.13      markus    132:                    c->self, c->istate);
1.10      markus    133:                return;
1.3       markus    134:        }
1.1       markus    135: }
1.13      markus    136: static void
                    137: chan_read_failed_12(Channel *c)
1.6       markus    138: {
1.13      markus    139:        debug("channel %d: read failed", c->self);
1.6       markus    140:        switch (c->istate) {
1.3       markus    141:        case CHAN_INPUT_OPEN:
                    142:                chan_shutdown_read(c);
1.37      markus    143:                chan_set_istate(c, CHAN_INPUT_WAIT_DRAIN);
1.3       markus    144:                break;
                    145:        default:
1.28      markus    146:                error("channel %d: chan_read_failed for istate %d",
1.13      markus    147:                    c->self, c->istate);
1.3       markus    148:                break;
1.1       markus    149:        }
                    150: }
1.13      markus    151: static void
                    152: chan_ibuf_empty1(Channel *c)
1.6       markus    153: {
1.13      markus    154:        debug("channel %d: ibuf empty", c->self);
1.6       markus    155:        if (buffer_len(&c->input)) {
1.28      markus    156:                error("channel %d: chan_ibuf_empty for non empty buffer",
1.13      markus    157:                    c->self);
1.3       markus    158:                return;
                    159:        }
1.6       markus    160:        switch (c->istate) {
1.3       markus    161:        case CHAN_INPUT_WAIT_DRAIN:
1.39    ! markus    162:                if (compat20) {
        !           163:                        if (!(c->flags & CHAN_CLOSE_SENT))
        !           164:                                chan_send_eof2(c);
        !           165:                        chan_set_istate(c, CHAN_INPUT_CLOSED);
        !           166:                } else {
        !           167:                        chan_send_ieof1(c);
        !           168:                        chan_set_istate(c, CHAN_INPUT_WAIT_OCLOSE);
        !           169:                }
1.3       markus    170:                break;
                    171:        default:
1.28      markus    172:                error("channel %d: chan_ibuf_empty for istate %d",
1.13      markus    173:                    c->self, c->istate);
1.3       markus    174:                break;
1.1       markus    175:        }
                    176: }
1.13      markus    177: static void
                    178: chan_rcvd_ieof1(Channel *c)
1.6       markus    179: {
1.13      markus    180:        debug("channel %d: rcvd ieof", c->self);
1.6       markus    181:        switch (c->ostate) {
1.3       markus    182:        case CHAN_OUTPUT_OPEN:
1.37      markus    183:                chan_set_ostate(c, CHAN_OUTPUT_WAIT_DRAIN);
1.3       markus    184:                break;
                    185:        case CHAN_OUTPUT_WAIT_IEOF:
1.37      markus    186:                chan_set_ostate(c, CHAN_OUTPUT_CLOSED);
1.3       markus    187:                break;
                    188:        default:
1.28      markus    189:                error("channel %d: protocol error: rcvd_ieof for ostate %d",
1.13      markus    190:                    c->self, c->ostate);
1.3       markus    191:                break;
                    192:        }
                    193: }
1.13      markus    194: static void
                    195: chan_write_failed1(Channel *c)
1.6       markus    196: {
1.13      markus    197:        debug("channel %d: write failed", c->self);
1.6       markus    198:        switch (c->ostate) {
1.3       markus    199:        case CHAN_OUTPUT_OPEN:
1.38      markus    200:                chan_shutdown_write(c);
1.13      markus    201:                chan_send_oclose1(c);
1.37      markus    202:                chan_set_ostate(c, CHAN_OUTPUT_WAIT_IEOF);
1.3       markus    203:                break;
                    204:        case CHAN_OUTPUT_WAIT_DRAIN:
1.38      markus    205:                chan_shutdown_write(c);
1.13      markus    206:                chan_send_oclose1(c);
1.37      markus    207:                chan_set_ostate(c, CHAN_OUTPUT_CLOSED);
1.3       markus    208:                break;
                    209:        default:
1.28      markus    210:                error("channel %d: chan_write_failed for ostate %d",
1.13      markus    211:                    c->self, c->ostate);
1.3       markus    212:                break;
                    213:        }
                    214: }
1.13      markus    215: static void
                    216: chan_obuf_empty1(Channel *c)
1.6       markus    217: {
1.13      markus    218:        debug("channel %d: obuf empty", c->self);
1.6       markus    219:        if (buffer_len(&c->output)) {
1.28      markus    220:                error("channel %d: chan_obuf_empty for non empty buffer",
1.13      markus    221:                    c->self);
1.3       markus    222:                return;
                    223:        }
1.6       markus    224:        switch (c->ostate) {
1.3       markus    225:        case CHAN_OUTPUT_WAIT_DRAIN:
1.38      markus    226:                chan_shutdown_write(c);
1.39    ! markus    227:                if (!compat20)
        !           228:                        chan_send_oclose1(c);
1.37      markus    229:                chan_set_ostate(c, CHAN_OUTPUT_CLOSED);
1.3       markus    230:                break;
                    231:        default:
1.28      markus    232:                error("channel %d: internal error: obuf_empty for ostate %d",
1.13      markus    233:                    c->self, c->ostate);
1.3       markus    234:                break;
                    235:        }
                    236: }
                    237: static void
1.13      markus    238: chan_send_ieof1(Channel *c)
1.6       markus    239: {
1.13      markus    240:        debug("channel %d: send ieof", c->self);
1.6       markus    241:        switch (c->istate) {
1.3       markus    242:        case CHAN_INPUT_OPEN:
                    243:        case CHAN_INPUT_WAIT_DRAIN:
                    244:                packet_start(SSH_MSG_CHANNEL_INPUT_EOF);
                    245:                packet_put_int(c->remote_id);
                    246:                packet_send();
                    247:                break;
                    248:        default:
1.28      markus    249:                error("channel %d: cannot send ieof for istate %d",
1.13      markus    250:                    c->self, c->istate);
1.3       markus    251:                break;
1.1       markus    252:        }
                    253: }
1.3       markus    254: static void
1.13      markus    255: chan_send_oclose1(Channel *c)
1.6       markus    256: {
1.13      markus    257:        debug("channel %d: send oclose", c->self);
1.6       markus    258:        switch (c->ostate) {
1.3       markus    259:        case CHAN_OUTPUT_OPEN:
                    260:        case CHAN_OUTPUT_WAIT_DRAIN:
1.34      markus    261:                buffer_clear(&c->output);
1.3       markus    262:                packet_start(SSH_MSG_CHANNEL_OUTPUT_CLOSE);
                    263:                packet_put_int(c->remote_id);
                    264:                packet_send();
                    265:                break;
                    266:        default:
1.28      markus    267:                error("channel %d: cannot send oclose for ostate %d",
1.33      deraadt   268:                    c->self, c->ostate);
1.3       markus    269:                break;
1.1       markus    270:        }
                    271: }
1.6       markus    272:
1.13      markus    273: /*
                    274:  * the same for SSH2
                    275:  */
                    276: static void
                    277: chan_rcvd_oclose2(Channel *c)
                    278: {
                    279:        debug("channel %d: rcvd close", c->self);
                    280:        if (c->flags & CHAN_CLOSE_RCVD)
                    281:                error("channel %d: protocol error: close rcvd twice", c->self);
                    282:        c->flags |= CHAN_CLOSE_RCVD;
                    283:        if (c->type == SSH_CHANNEL_LARVAL) {
                    284:                /* tear down larval channels immediately */
1.37      markus    285:                chan_set_ostate(c, CHAN_OUTPUT_CLOSED);
                    286:                chan_set_istate(c, CHAN_INPUT_CLOSED);
1.13      markus    287:                return;
                    288:        }
                    289:        switch (c->ostate) {
                    290:        case CHAN_OUTPUT_OPEN:
1.28      markus    291:                /*
                    292:                 * wait until a data from the channel is consumed if a CLOSE
                    293:                 * is received
                    294:                 */
1.37      markus    295:                chan_set_ostate(c, CHAN_OUTPUT_WAIT_DRAIN);
1.13      markus    296:                break;
                    297:        }
                    298:        switch (c->istate) {
                    299:        case CHAN_INPUT_OPEN:
                    300:                chan_shutdown_read(c);
                    301:                break;
                    302:        case CHAN_INPUT_WAIT_DRAIN:
                    303:                chan_send_eof2(c);
                    304:                break;
                    305:        }
1.37      markus    306:        chan_set_istate(c, CHAN_INPUT_CLOSED);
1.13      markus    307: }
                    308: static void
                    309: chan_ibuf_empty2(Channel *c)
                    310: {
1.39    ! markus    311:        chan_ibuf_empty1(c);
1.13      markus    312: }
                    313: static void
                    314: chan_rcvd_ieof2(Channel *c)
                    315: {
                    316:        debug("channel %d: rcvd eof", c->self);
1.37      markus    317:        if (c->ostate == CHAN_OUTPUT_OPEN)
                    318:                chan_set_ostate(c, CHAN_OUTPUT_WAIT_DRAIN);
1.13      markus    319: }
                    320: static void
                    321: chan_write_failed2(Channel *c)
                    322: {
                    323:        debug("channel %d: write failed", c->self);
                    324:        switch (c->ostate) {
                    325:        case CHAN_OUTPUT_OPEN:
1.15      markus    326:                chan_shutdown_write(c); /* ?? */
1.37      markus    327:                chan_set_ostate(c, CHAN_OUTPUT_CLOSED);
1.13      markus    328:                break;
                    329:        case CHAN_OUTPUT_WAIT_DRAIN:
                    330:                chan_shutdown_write(c);
1.37      markus    331:                chan_set_ostate(c, CHAN_OUTPUT_CLOSED);
1.13      markus    332:                break;
                    333:        default:
1.28      markus    334:                error("channel %d: chan_write_failed for ostate %d",
1.13      markus    335:                    c->self, c->ostate);
                    336:                break;
                    337:        }
                    338: }
                    339: static void
                    340: chan_obuf_empty2(Channel *c)
                    341: {
1.39    ! markus    342:        chan_obuf_empty1(c);
1.13      markus    343: }
1.3       markus    344: static void
1.13      markus    345: chan_send_eof2(Channel *c)
1.6       markus    346: {
1.13      markus    347:        debug("channel %d: send eof", c->self);
                    348:        switch (c->istate) {
                    349:        case CHAN_INPUT_WAIT_DRAIN:
                    350:                packet_start(SSH2_MSG_CHANNEL_EOF);
                    351:                packet_put_int(c->remote_id);
                    352:                packet_send();
                    353:                break;
                    354:        default:
1.28      markus    355:                error("channel %d: cannot send eof for istate %d",
1.13      markus    356:                    c->self, c->istate);
                    357:                break;
                    358:        }
1.1       markus    359: }
1.3       markus    360: static void
1.13      markus    361: chan_send_close2(Channel *c)
1.6       markus    362: {
1.13      markus    363:        debug("channel %d: send close", c->self);
                    364:        if (c->ostate != CHAN_OUTPUT_CLOSED ||
                    365:            c->istate != CHAN_INPUT_CLOSED) {
1.28      markus    366:                error("channel %d: cannot send close for istate/ostate %d/%d",
1.13      markus    367:                    c->self, c->istate, c->ostate);
                    368:        } else if (c->flags & CHAN_CLOSE_SENT) {
1.28      markus    369:                error("channel %d: already sent close", c->self);
1.13      markus    370:        } else {
                    371:                packet_start(SSH2_MSG_CHANNEL_CLOSE);
                    372:                packet_put_int(c->remote_id);
                    373:                packet_send();
                    374:                c->flags |= CHAN_CLOSE_SENT;
                    375:        }
1.1       markus    376: }
1.23      markus    377:
                    378: /* shared */
                    379:
1.24      markus    380: void
                    381: chan_mark_dead(Channel *c)
                    382: {
1.26      markus    383:        c->type = SSH_CHANNEL_ZOMBIE;
1.24      markus    384: }
                    385:
1.23      markus    386: int
1.32      markus    387: chan_is_dead(Channel *c, int send)
1.6       markus    388: {
1.26      markus    389:        if (c->type == SSH_CHANNEL_ZOMBIE) {
                    390:                debug("channel %d: zombie", c->self);
1.24      markus    391:                return 1;
1.26      markus    392:        }
1.23      markus    393:        if (c->istate != CHAN_INPUT_CLOSED || c->ostate != CHAN_OUTPUT_CLOSED)
                    394:                return 0;
                    395:        if (!compat20) {
                    396:                debug("channel %d: is dead", c->self);
                    397:                return 1;
                    398:        }
                    399:        /*
                    400:         * we have to delay the close message if the efd (for stderr) is
                    401:         * still active
                    402:         */
                    403:        if (((c->extended_usage != CHAN_EXTENDED_IGNORE) &&
                    404:            buffer_len(&c->extended) > 0)
                    405: #if 0
                    406:            || ((c->extended_usage == CHAN_EXTENDED_READ) &&
                    407:            c->efd != -1)
                    408: #endif
                    409:            ) {
                    410:                debug2("channel %d: active efd: %d len %d type %s",
                    411:                    c->self, c->efd, buffer_len(&c->extended),
                    412:                    c->extended_usage==CHAN_EXTENDED_READ ?
1.33      deraadt   413:                    "read": "write");
1.23      markus    414:        } else {
1.13      markus    415:                if (!(c->flags & CHAN_CLOSE_SENT)) {
1.32      markus    416:                        if (send) {
                    417:                                chan_send_close2(c);
                    418:                        } else {
                    419:                                /* channel would be dead if we sent a close */
                    420:                                if (c->flags & CHAN_CLOSE_RCVD) {
                    421:                                        debug("channel %d: almost dead",
                    422:                                            c->self);
                    423:                                        return 1;
                    424:                                }
                    425:                        }
1.13      markus    426:                }
1.14      markus    427:                if ((c->flags & CHAN_CLOSE_SENT) &&
1.13      markus    428:                    (c->flags & CHAN_CLOSE_RCVD)) {
1.23      markus    429:                        debug("channel %d: is dead", c->self);
                    430:                        return 1;
1.14      markus    431:                }
1.1       markus    432:        }
1.23      markus    433:        return 0;
1.3       markus    434: }
1.13      markus    435:
1.3       markus    436: void
1.6       markus    437: chan_init_iostates(Channel *c)
                    438: {
                    439:        c->ostate = CHAN_OUTPUT_OPEN;
                    440:        c->istate = CHAN_INPUT_OPEN;
1.13      markus    441:        c->flags = 0;
                    442: }
                    443:
                    444: /* init */
                    445: void
                    446: chan_init(void)
                    447: {
                    448:        if (compat20) {
                    449:                chan_rcvd_oclose                = chan_rcvd_oclose2;
                    450:                chan_read_failed                = chan_read_failed_12;
                    451:                chan_ibuf_empty                 = chan_ibuf_empty2;
                    452:
                    453:                chan_rcvd_ieof                  = chan_rcvd_ieof2;
                    454:                chan_write_failed               = chan_write_failed2;
                    455:                chan_obuf_empty                 = chan_obuf_empty2;
                    456:        } else {
                    457:                chan_rcvd_oclose                = chan_rcvd_oclose1;
                    458:                chan_read_failed                = chan_read_failed_12;
                    459:                chan_ibuf_empty                 = chan_ibuf_empty1;
                    460:
                    461:                chan_rcvd_ieof                  = chan_rcvd_ieof1;
                    462:                chan_write_failed               = chan_write_failed1;
                    463:                chan_obuf_empty                 = chan_obuf_empty1;
                    464:        }
                    465: }
                    466:
                    467: /* helper */
                    468: static void
                    469: chan_shutdown_write(Channel *c)
                    470: {
1.34      markus    471:        buffer_clear(&c->output);
1.13      markus    472:        if (compat20 && c->type == SSH_CHANNEL_LARVAL)
                    473:                return;
                    474:        /* shutdown failure is allowed if write failed already */
                    475:        debug("channel %d: close_write", c->self);
                    476:        if (c->sock != -1) {
                    477:                if (shutdown(c->sock, SHUT_WR) < 0)
1.28      markus    478:                        debug("channel %d: chan_shutdown_write: "
                    479:                            "shutdown() failed for fd%d: %.100s",
1.13      markus    480:                            c->self, c->sock, strerror(errno));
                    481:        } else {
1.31      markus    482:                if (channel_close_fd(&c->wfd) < 0)
1.28      markus    483:                        log("channel %d: chan_shutdown_write: "
                    484:                            "close() failed for fd%d: %.100s",
1.13      markus    485:                            c->self, c->wfd, strerror(errno));
                    486:        }
                    487: }
                    488: static void
                    489: chan_shutdown_read(Channel *c)
                    490: {
                    491:        if (compat20 && c->type == SSH_CHANNEL_LARVAL)
                    492:                return;
                    493:        debug("channel %d: close_read", c->self);
                    494:        if (c->sock != -1) {
                    495:                if (shutdown(c->sock, SHUT_RD) < 0)
1.28      markus    496:                        error("channel %d: chan_shutdown_read: "
                    497:                            "shutdown() failed for fd%d [i%d o%d]: %.100s",
                    498:                            c->self, c->sock, c->istate, c->ostate,
                    499:                            strerror(errno));
1.13      markus    500:        } else {
1.31      markus    501:                if (channel_close_fd(&c->rfd) < 0)
1.28      markus    502:                        log("channel %d: chan_shutdown_read: "
                    503:                            "close() failed for fd%d: %.100s",
1.13      markus    504:                            c->self, c->rfd, strerror(errno));
                    505:        }
1.1       markus    506: }