nchan.c revision 1.4
1#include "includes.h"
2RCSID("$Id: nchan.c,v 1.4 1999/10/25 21:03:17 markus Exp $");
3
4#include "ssh.h"
5
6#include "buffer.h"
7#include "packet.h"
8#include "channels.h"
9#include "nchan.h"
10
11static void chan_send_ieof(Channel *c);
12static void chan_send_oclose(Channel *c);
13static void chan_shutdown_write(Channel *c);
14static void chan_shutdown_read(Channel *c);
15static void chan_delele_if_full_closed(Channel *c);
16
17/*
18 * EVENTS: update channel input/output states
19 *	   execute ACTIONS
20 */
21/* events concerning the INPUT from socket for channel (istate) */
22void
23chan_rcvd_oclose(Channel *c){
24	switch(c->istate){
25	case CHAN_INPUT_WAIT_OCLOSE:
26		debug("channel %d: INPUT_WAIT_OCLOSE -> INPUT_CLOSED [rcvd OCLOSE]", c->self);
27		c->istate=CHAN_INPUT_CLOSED;
28		chan_delele_if_full_closed(c);
29		break;
30	case CHAN_INPUT_OPEN:
31		debug("channel %d: INPUT_OPEN -> INPUT_CLOSED [rvcd OCLOSE, send IEOF]", c->self);
32		chan_shutdown_read(c);
33		chan_send_ieof(c);
34		c->istate=CHAN_INPUT_CLOSED;
35		chan_delele_if_full_closed(c);
36		break;
37	default:
38		debug("protocol error: chan_rcvd_oclose %d for istate %d",c->self,c->istate);
39		break;
40	}
41}
42void
43chan_read_failed(Channel *c){
44	switch(c->istate){
45	case CHAN_INPUT_OPEN:
46		debug("channel %d: INPUT_OPEN -> INPUT_WAIT_DRAIN [read failed]", c->self);
47		chan_shutdown_read(c);
48		c->istate=CHAN_INPUT_WAIT_DRAIN;
49		break;
50	default:
51		debug("internal error: we do not read, but chan_read_failed %d for istate %d",
52			c->self,c->istate);
53		break;
54	}
55}
56void
57chan_ibuf_empty(Channel *c){
58	if(buffer_len(&c->input)){
59		debug("internal error: chan_ibuf_empty %d for non empty buffer",c->self);
60		return;
61	}
62	switch(c->istate){
63	case CHAN_INPUT_WAIT_DRAIN:
64		debug("channel %d: INPUT_WAIT_DRAIN -> INPUT_WAIT_OCLOSE [inbuf empty, send IEOF]", c->self);
65		chan_send_ieof(c);
66		c->istate=CHAN_INPUT_WAIT_OCLOSE;
67		break;
68	default:
69		debug("internal error: chan_ibuf_empty %d for istate %d",c->self,c->istate);
70		break;
71	}
72}
73/* events concerning the OUTPUT from channel for socket (ostate) */
74void
75chan_rcvd_ieof(Channel *c){
76
77	/* X11: if we receive IEOF for X11, then we have to FORCE sending of IEOF,
78	 * this is from ssh-1.2.27 debugging output.
79	 */
80	if(c->x11){
81		debug("channel %d: OUTPUT_OPEN -> OUTPUT_CLOSED/INPUT_WAIT_OCLOSED [X11 FIX]", c->self);
82		chan_send_ieof(c);
83		c->istate=CHAN_INPUT_WAIT_OCLOSE;
84		chan_send_oclose(c);
85		c->ostate=CHAN_OUTPUT_CLOSED;
86		chan_delele_if_full_closed(c);
87		return;
88	}
89	switch(c->ostate){
90	case CHAN_OUTPUT_OPEN:
91		debug("channel %d: OUTPUT_OPEN -> OUTPUT_WAIT_DRAIN [rvcd IEOF]", c->self);
92		c->ostate=CHAN_OUTPUT_WAIT_DRAIN;
93		break;
94	case CHAN_OUTPUT_WAIT_IEOF:
95		debug("channel %d: OUTPUT_WAIT_IEOF -> OUTPUT_CLOSED [rvcd IEOF]", c->self);
96		c->ostate=CHAN_OUTPUT_CLOSED;
97		chan_delele_if_full_closed(c);
98		break;
99	default:
100		debug("protocol error: chan_rcvd_ieof %d for ostate %d", c->self,c->ostate);
101		break;
102	}
103}
104void
105chan_write_failed(Channel *c){
106	switch(c->ostate){
107	case CHAN_OUTPUT_OPEN:
108		debug("channel %d: OUTPUT_OPEN -> OUTPUT_WAIT_IEOF [write failed]", c->self);
109		chan_send_oclose(c);
110		c->ostate=CHAN_OUTPUT_WAIT_IEOF;
111		break;
112	case CHAN_OUTPUT_WAIT_DRAIN:
113		debug("channel %d: OUTPUT_WAIT_DRAIN -> OUTPUT_CLOSED [write failed]", c->self);
114		chan_send_oclose(c);
115		c->ostate=CHAN_OUTPUT_CLOSED;
116		chan_delele_if_full_closed(c);
117		break;
118	default:
119		debug("internal error: chan_write_failed %d for ostate %d",c->self,c->ostate);
120		break;
121	}
122}
123void
124chan_obuf_empty(Channel *c){
125	if(buffer_len(&c->output)){
126		debug("internal error: chan_obuf_empty %d for non empty buffer",c->self);
127		return;
128	}
129	switch(c->ostate){
130	case CHAN_OUTPUT_WAIT_DRAIN:
131		debug("channel %d: OUTPUT_WAIT_DRAIN -> OUTPUT_CLOSED [obuf empty, send OCLOSE]", c->self);
132		chan_send_oclose(c);
133		c->ostate=CHAN_OUTPUT_CLOSED;
134		chan_delele_if_full_closed(c);
135		break;
136	default:
137		debug("internal error: chan_obuf_empty %d for ostate %d",c->self,c->ostate);
138		break;
139	}
140}
141/*
142 * ACTIONS: should never update c->istate or c->ostate
143 */
144static void
145chan_send_ieof(Channel *c){
146	switch(c->istate){
147	case CHAN_INPUT_OPEN:
148	case CHAN_INPUT_WAIT_DRAIN:
149		packet_start(SSH_MSG_CHANNEL_INPUT_EOF);
150		packet_put_int(c->remote_id);
151		packet_send();
152		break;
153	default:
154		debug("internal error: channel %d: cannot send IEOF for istate %d",c->self,c->istate);
155		break;
156	}
157}
158static void
159chan_send_oclose(Channel *c){
160	switch(c->ostate){
161	case CHAN_OUTPUT_OPEN:
162	case CHAN_OUTPUT_WAIT_DRAIN:
163		chan_shutdown_write(c);
164		buffer_consume(&c->output, buffer_len(&c->output));
165		packet_start(SSH_MSG_CHANNEL_OUTPUT_CLOSE);
166		packet_put_int(c->remote_id);
167		packet_send();
168		break;
169	default:
170		debug("internal error: channel %d: cannot send OCLOSE for ostate %d",c->self,c->istate);
171		break;
172	}
173}
174/* helper */
175static void
176chan_shutdown_write(Channel *c){
177	debug("channel %d: shutdown_write", c->self);
178	if(shutdown(c->sock, SHUT_WR)<0)
179		error("chan_shutdown_write failed for #%d/fd%d: %.100s",
180			c->self, c->sock, strerror(errno));
181}
182static void
183chan_shutdown_read(Channel *c){
184	debug("channel %d: shutdown_read", c->self);
185	if(shutdown(c->sock, SHUT_RD)<0)
186		error("chan_shutdown_read failed for #%d/fd%d: %.100s",
187			c->self, c->sock, strerror(errno));
188}
189static void
190chan_delele_if_full_closed(Channel *c){
191	if(c->istate==CHAN_INPUT_CLOSED && c->ostate==CHAN_OUTPUT_CLOSED){
192		debug("channel %d: closing", c->self);
193		channel_free(c->self);
194	}
195}
196void
197chan_init_iostates(Channel *c){
198	c->ostate=CHAN_OUTPUT_OPEN;
199	c->istate=CHAN_INPUT_OPEN;
200}
201