blob: 957c45618de9d5cef5f7db0e750790224c3566eb [file] [log] [blame]
Damien Miller5428f641999-11-25 11:54:57 +11001/*
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.
Damien Miller5428f641999-11-25 11:54:57 +110012 *
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
Damien Millerd4a8b7e1999-10-27 13:42:43 +100025#include "includes.h"
Ben Lindstromc0dee1a2001-06-05 20:52:50 +000026RCSID("$OpenBSD: nchan.c,v 1.26 2001/05/28 23:14:49 markus Exp $");
Damien Millerd4a8b7e1999-10-27 13:42:43 +100027
Ben Lindstrom226cfa02001-01-22 05:34:40 +000028#include "ssh1.h"
29#include "ssh2.h"
Damien Millerd4a8b7e1999-10-27 13:42:43 +100030#include "buffer.h"
31#include "packet.h"
32#include "channels.h"
33#include "nchan.h"
Damien Miller33b13562000-04-04 14:38:59 +100034#include "compat.h"
Ben Lindstrom226cfa02001-01-22 05:34:40 +000035#include "log.h"
Damien Millerd4a8b7e1999-10-27 13:42:43 +100036
Damien Miller33b13562000-04-04 14:38:59 +100037/* functions manipulating channel states */
Damien Millerd4a8b7e1999-10-27 13:42:43 +100038/*
Damien Miller95def091999-11-25 00:26:21 +110039 * EVENTS update channel input/output states execute ACTIONS
Damien Millerd4a8b7e1999-10-27 13:42:43 +100040 */
41/* events concerning the INPUT from socket for channel (istate) */
Damien Miller33b13562000-04-04 14:38:59 +100042chan_event_fn *chan_rcvd_oclose = NULL;
43chan_event_fn *chan_read_failed = NULL;
44chan_event_fn *chan_ibuf_empty = NULL;
45/* events concerning the OUTPUT from channel for socket (ostate) */
46chan_event_fn *chan_rcvd_ieof = NULL;
47chan_event_fn *chan_write_failed = NULL;
48chan_event_fn *chan_obuf_empty = NULL;
49/*
50 * ACTIONS: should never update the channel states
51 */
52static void chan_send_ieof1(Channel *c);
53static void chan_send_oclose1(Channel *c);
54static void chan_send_close2(Channel *c);
55static void chan_send_eof2(Channel *c);
56
Damien Miller33b13562000-04-04 14:38:59 +100057/* helper */
58static void chan_shutdown_write(Channel *c);
59static void chan_shutdown_read(Channel *c);
60
61/*
62 * SSH1 specific implementation of event functions
63 */
64
65static void
66chan_rcvd_oclose1(Channel *c)
Damien Miller95def091999-11-25 00:26:21 +110067{
Damien Miller33b13562000-04-04 14:38:59 +100068 debug("channel %d: rcvd oclose", c->self);
Damien Miller95def091999-11-25 00:26:21 +110069 switch (c->istate) {
Damien Millerd4a8b7e1999-10-27 13:42:43 +100070 case CHAN_INPUT_WAIT_OCLOSE:
Damien Miller33b13562000-04-04 14:38:59 +100071 debug("channel %d: input wait_oclose -> closed", c->self);
Damien Miller95def091999-11-25 00:26:21 +110072 c->istate = CHAN_INPUT_CLOSED;
Damien Millerd4a8b7e1999-10-27 13:42:43 +100073 break;
74 case CHAN_INPUT_OPEN:
Damien Miller33b13562000-04-04 14:38:59 +100075 debug("channel %d: input open -> closed", c->self);
Damien Millerd4a8b7e1999-10-27 13:42:43 +100076 chan_shutdown_read(c);
Damien Miller33b13562000-04-04 14:38:59 +100077 chan_send_ieof1(c);
Damien Miller95def091999-11-25 00:26:21 +110078 c->istate = CHAN_INPUT_CLOSED;
Damien Miller34132e52000-01-14 15:45:46 +110079 break;
80 case CHAN_INPUT_WAIT_DRAIN:
81 /* both local read_failed and remote write_failed */
Damien Miller33b13562000-04-04 14:38:59 +100082 log("channel %d: input drain -> closed", c->self);
83 chan_send_ieof1(c);
Damien Miller34132e52000-01-14 15:45:46 +110084 c->istate = CHAN_INPUT_CLOSED;
Damien Millerd4a8b7e1999-10-27 13:42:43 +100085 break;
86 default:
Damien Miller33b13562000-04-04 14:38:59 +100087 error("channel %d: protocol error: chan_rcvd_oclose for istate %d",
88 c->self, c->istate);
Damien Miller34132e52000-01-14 15:45:46 +110089 return;
Damien Millerd4a8b7e1999-10-27 13:42:43 +100090 }
91}
Damien Miller33b13562000-04-04 14:38:59 +100092static void
93chan_read_failed_12(Channel *c)
Damien Miller95def091999-11-25 00:26:21 +110094{
Damien Miller33b13562000-04-04 14:38:59 +100095 debug("channel %d: read failed", c->self);
Damien Miller95def091999-11-25 00:26:21 +110096 switch (c->istate) {
Damien Millerd4a8b7e1999-10-27 13:42:43 +100097 case CHAN_INPUT_OPEN:
Damien Miller33b13562000-04-04 14:38:59 +100098 debug("channel %d: input open -> drain", c->self);
Damien Millerd4a8b7e1999-10-27 13:42:43 +100099 chan_shutdown_read(c);
Damien Miller95def091999-11-25 00:26:21 +1100100 c->istate = CHAN_INPUT_WAIT_DRAIN;
Damien Miller30c3d422000-05-09 11:02:59 +1000101 if (buffer_len(&c->input) == 0) {
102 debug("channel %d: input: no drain shortcut", c->self);
103 chan_ibuf_empty(c);
104 }
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000105 break;
106 default:
Damien Miller33b13562000-04-04 14:38:59 +1000107 error("channel %d: internal error: we do not read, but chan_read_failed for istate %d",
108 c->self, c->istate);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000109 break;
110 }
111}
Damien Miller33b13562000-04-04 14:38:59 +1000112static void
113chan_ibuf_empty1(Channel *c)
Damien Miller95def091999-11-25 00:26:21 +1100114{
Damien Miller33b13562000-04-04 14:38:59 +1000115 debug("channel %d: ibuf empty", c->self);
Damien Miller95def091999-11-25 00:26:21 +1100116 if (buffer_len(&c->input)) {
Damien Miller33b13562000-04-04 14:38:59 +1000117 error("channel %d: internal error: chan_ibuf_empty for non empty buffer",
118 c->self);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000119 return;
120 }
Damien Miller95def091999-11-25 00:26:21 +1100121 switch (c->istate) {
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000122 case CHAN_INPUT_WAIT_DRAIN:
Damien Miller33b13562000-04-04 14:38:59 +1000123 debug("channel %d: input drain -> wait_oclose", c->self);
124 chan_send_ieof1(c);
Damien Miller95def091999-11-25 00:26:21 +1100125 c->istate = CHAN_INPUT_WAIT_OCLOSE;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000126 break;
127 default:
Damien Miller33b13562000-04-04 14:38:59 +1000128 error("channel %d: internal error: chan_ibuf_empty for istate %d",
129 c->self, c->istate);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000130 break;
131 }
132}
Damien Miller33b13562000-04-04 14:38:59 +1000133static void
134chan_rcvd_ieof1(Channel *c)
Damien Miller95def091999-11-25 00:26:21 +1100135{
Damien Miller33b13562000-04-04 14:38:59 +1000136 debug("channel %d: rcvd ieof", c->self);
Damien Millere247cc42000-05-07 12:03:14 +1000137 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 }
Damien Miller95def091999-11-25 00:26:21 +1100156 switch (c->ostate) {
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000157 case CHAN_OUTPUT_OPEN:
Damien Miller33b13562000-04-04 14:38:59 +1000158 debug("channel %d: output open -> drain", c->self);
Damien Miller95def091999-11-25 00:26:21 +1100159 c->ostate = CHAN_OUTPUT_WAIT_DRAIN;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000160 break;
161 case CHAN_OUTPUT_WAIT_IEOF:
Damien Miller33b13562000-04-04 14:38:59 +1000162 debug("channel %d: output wait_ieof -> closed", c->self);
Damien Miller95def091999-11-25 00:26:21 +1100163 c->ostate = CHAN_OUTPUT_CLOSED;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000164 break;
165 default:
Damien Miller33b13562000-04-04 14:38:59 +1000166 error("channel %d: protocol error: chan_rcvd_ieof for ostate %d",
167 c->self, c->ostate);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000168 break;
169 }
170}
Damien Miller33b13562000-04-04 14:38:59 +1000171static void
172chan_write_failed1(Channel *c)
Damien Miller95def091999-11-25 00:26:21 +1100173{
Damien Miller33b13562000-04-04 14:38:59 +1000174 debug("channel %d: write failed", c->self);
Damien Miller95def091999-11-25 00:26:21 +1100175 switch (c->ostate) {
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000176 case CHAN_OUTPUT_OPEN:
Damien Miller33b13562000-04-04 14:38:59 +1000177 debug("channel %d: output open -> wait_ieof", c->self);
178 chan_send_oclose1(c);
Damien Miller95def091999-11-25 00:26:21 +1100179 c->ostate = CHAN_OUTPUT_WAIT_IEOF;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000180 break;
181 case CHAN_OUTPUT_WAIT_DRAIN:
Damien Miller33b13562000-04-04 14:38:59 +1000182 debug("channel %d: output wait_drain -> closed", c->self);
183 chan_send_oclose1(c);
Damien Miller95def091999-11-25 00:26:21 +1100184 c->ostate = CHAN_OUTPUT_CLOSED;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000185 break;
186 default:
Damien Miller33b13562000-04-04 14:38:59 +1000187 error("channel %d: internal error: chan_write_failed for ostate %d",
188 c->self, c->ostate);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000189 break;
190 }
191}
Damien Miller33b13562000-04-04 14:38:59 +1000192static void
193chan_obuf_empty1(Channel *c)
Damien Miller95def091999-11-25 00:26:21 +1100194{
Damien Miller33b13562000-04-04 14:38:59 +1000195 debug("channel %d: obuf empty", c->self);
Damien Miller95def091999-11-25 00:26:21 +1100196 if (buffer_len(&c->output)) {
Damien Miller33b13562000-04-04 14:38:59 +1000197 error("channel %d: internal error: chan_obuf_empty for non empty buffer",
198 c->self);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000199 return;
200 }
Damien Miller95def091999-11-25 00:26:21 +1100201 switch (c->ostate) {
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000202 case CHAN_OUTPUT_WAIT_DRAIN:
Damien Miller33b13562000-04-04 14:38:59 +1000203 debug("channel %d: output drain -> closed", c->self);
204 chan_send_oclose1(c);
Damien Miller95def091999-11-25 00:26:21 +1100205 c->ostate = CHAN_OUTPUT_CLOSED;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000206 break;
207 default:
Damien Miller33b13562000-04-04 14:38:59 +1000208 error("channel %d: internal error: chan_obuf_empty for ostate %d",
209 c->self, c->ostate);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000210 break;
211 }
212}
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000213static void
Damien Miller33b13562000-04-04 14:38:59 +1000214chan_send_ieof1(Channel *c)
Damien Miller95def091999-11-25 00:26:21 +1100215{
Damien Miller33b13562000-04-04 14:38:59 +1000216 debug("channel %d: send ieof", c->self);
Damien Miller95def091999-11-25 00:26:21 +1100217 switch (c->istate) {
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000218 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:
Damien Miller33b13562000-04-04 14:38:59 +1000225 error("channel %d: internal error: cannot send ieof for istate %d",
226 c->self, c->istate);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000227 break;
228 }
229}
230static void
Damien Miller33b13562000-04-04 14:38:59 +1000231chan_send_oclose1(Channel *c)
Damien Miller95def091999-11-25 00:26:21 +1100232{
Damien Miller33b13562000-04-04 14:38:59 +1000233 debug("channel %d: send oclose", c->self);
Damien Miller95def091999-11-25 00:26:21 +1100234 switch (c->ostate) {
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000235 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:
Damien Miller33b13562000-04-04 14:38:59 +1000244 error("channel %d: internal error: cannot send oclose for ostate %d",
245 c->self, c->ostate);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000246 break;
247 }
248}
Damien Miller33b13562000-04-04 14:38:59 +1000249
250/*
251 * the same for SSH2
252 */
253static void
254chan_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}
285static void
286chan_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}
307static void
308chan_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}
316static void
317chan_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);
Damien Millere247cc42000-05-07 12:03:14 +1000323 chan_shutdown_write(c); /* ?? */
Damien Miller33b13562000-04-04 14:38:59 +1000324 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}
337static void
338chan_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}
358static void
359chan_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}
374static void
375chan_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}
Ben Lindstrom7fbd4552001-03-05 06:16:11 +0000391
392/* shared */
393
Ben Lindstrom99c73b32001-05-05 04:09:47 +0000394void
395chan_mark_dead(Channel *c)
396{
Ben Lindstromc0dee1a2001-06-05 20:52:50 +0000397 c->type = SSH_CHANNEL_ZOMBIE;
Ben Lindstrom99c73b32001-05-05 04:09:47 +0000398}
399
Ben Lindstrom7fbd4552001-03-05 06:16:11 +0000400int
401chan_is_dead(Channel *c)
Damien Miller33b13562000-04-04 14:38:59 +1000402{
Ben Lindstromc0dee1a2001-06-05 20:52:50 +0000403 if (c->type == SSH_CHANNEL_ZOMBIE) {
404 debug("channel %d: zombie", c->self);
Ben Lindstrom99c73b32001-05-05 04:09:47 +0000405 return 1;
Ben Lindstromc0dee1a2001-06-05 20:52:50 +0000406 }
Ben Lindstrom7fbd4552001-03-05 06:16:11 +0000407 if (c->istate != CHAN_INPUT_CLOSED || c->ostate != CHAN_OUTPUT_CLOSED)
408 return 0;
409 if (!compat20) {
410 debug("channel %d: is dead", c->self);
411 return 1;
412 }
413 /*
414 * we have to delay the close message if the efd (for stderr) is
415 * still active
416 */
417 if (((c->extended_usage != CHAN_EXTENDED_IGNORE) &&
418 buffer_len(&c->extended) > 0)
419#if 0
420 || ((c->extended_usage == CHAN_EXTENDED_READ) &&
421 c->efd != -1)
422#endif
423 ) {
424 debug2("channel %d: active efd: %d len %d type %s",
425 c->self, c->efd, buffer_len(&c->extended),
426 c->extended_usage==CHAN_EXTENDED_READ ?
427 "read": "write");
428 } else {
Damien Miller33b13562000-04-04 14:38:59 +1000429 if (!(c->flags & CHAN_CLOSE_SENT)) {
430 chan_send_close2(c);
431 }
Damien Miller4af51302000-04-16 11:18:38 +1000432 if ((c->flags & CHAN_CLOSE_SENT) &&
Damien Miller33b13562000-04-04 14:38:59 +1000433 (c->flags & CHAN_CLOSE_RCVD)) {
Ben Lindstrom7fbd4552001-03-05 06:16:11 +0000434 debug("channel %d: is dead", c->self);
435 return 1;
Damien Miller4af51302000-04-16 11:18:38 +1000436 }
Damien Miller33b13562000-04-04 14:38:59 +1000437 }
Ben Lindstrom7fbd4552001-03-05 06:16:11 +0000438 return 0;
Damien Miller33b13562000-04-04 14:38:59 +1000439}
440
Damien Miller33b13562000-04-04 14:38:59 +1000441void
442chan_init_iostates(Channel *c)
443{
444 c->ostate = CHAN_OUTPUT_OPEN;
445 c->istate = CHAN_INPUT_OPEN;
446 c->flags = 0;
447}
448
449/* init */
450void
451chan_init(void)
452{
453 if (compat20) {
454 chan_rcvd_oclose = chan_rcvd_oclose2;
455 chan_read_failed = chan_read_failed_12;
456 chan_ibuf_empty = chan_ibuf_empty2;
457
458 chan_rcvd_ieof = chan_rcvd_ieof2;
459 chan_write_failed = chan_write_failed2;
460 chan_obuf_empty = chan_obuf_empty2;
Damien Miller33b13562000-04-04 14:38:59 +1000461 } else {
462 chan_rcvd_oclose = chan_rcvd_oclose1;
463 chan_read_failed = chan_read_failed_12;
464 chan_ibuf_empty = chan_ibuf_empty1;
465
466 chan_rcvd_ieof = chan_rcvd_ieof1;
467 chan_write_failed = chan_write_failed1;
468 chan_obuf_empty = chan_obuf_empty1;
Damien Miller33b13562000-04-04 14:38:59 +1000469 }
470}
Damien Miller95def091999-11-25 00:26:21 +1100471
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000472/* helper */
473static void
Damien Miller95def091999-11-25 00:26:21 +1100474chan_shutdown_write(Channel *c)
475{
Damien Miller33b13562000-04-04 14:38:59 +1000476 buffer_consume(&c->output, buffer_len(&c->output));
477 if (compat20 && c->type == SSH_CHANNEL_LARVAL)
478 return;
Damien Miller5428f641999-11-25 11:54:57 +1100479 /* shutdown failure is allowed if write failed already */
Damien Miller33b13562000-04-04 14:38:59 +1000480 debug("channel %d: close_write", c->self);
481 if (c->sock != -1) {
482 if (shutdown(c->sock, SHUT_WR) < 0)
483 debug("channel %d: chan_shutdown_write: shutdown() failed for fd%d: %.100s",
484 c->self, c->sock, strerror(errno));
485 } else {
486 if (close(c->wfd) < 0)
487 log("channel %d: chan_shutdown_write: close() failed for fd%d: %.100s",
488 c->self, c->wfd, strerror(errno));
Ben Lindstromc0dee1a2001-06-05 20:52:50 +0000489 c->wfd = -1;
Damien Miller33b13562000-04-04 14:38:59 +1000490 }
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000491}
492static void
Damien Miller95def091999-11-25 00:26:21 +1100493chan_shutdown_read(Channel *c)
494{
Damien Miller33b13562000-04-04 14:38:59 +1000495 if (compat20 && c->type == SSH_CHANNEL_LARVAL)
496 return;
497 debug("channel %d: close_read", c->self);
498 if (c->sock != -1) {
Kevin Stevesef4eea92001-02-05 12:42:17 +0000499 /*
Damien Miller0f091bd2000-08-07 15:47:48 +1000500 * shutdown(sock, SHUT_READ) may return ENOTCONN if the
501 * write side has been closed already. (bug on Linux)
Kevin Stevesefe5fd82001-04-03 13:02:48 +0000502 * HP-UX will return EINVAL.
Damien Miller0f091bd2000-08-07 15:47:48 +1000503 */
504 if (shutdown(c->sock, SHUT_RD) < 0
Kevin Stevesefe5fd82001-04-03 13:02:48 +0000505 && (errno != ENOTCONN && errno != EINVAL))
Damien Miller33b13562000-04-04 14:38:59 +1000506 error("channel %d: chan_shutdown_read: shutdown() failed for fd%d [i%d o%d]: %.100s",
507 c->self, c->sock, c->istate, c->ostate, strerror(errno));
508 } else {
509 if (close(c->rfd) < 0)
510 log("channel %d: chan_shutdown_read: close() failed for fd%d: %.100s",
511 c->self, c->rfd, strerror(errno));
Ben Lindstromc0dee1a2001-06-05 20:52:50 +0000512 c->rfd = -1;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000513 }
514}