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