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