blob: b9a8ba49cd08b1a1d61dff31ec8bc1a0aeb636ff [file] [log] [blame]
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001#include "includes.h"
Damien Miller95def091999-11-25 00:26:21 +11002RCSID("$Id: nchan.c,v 1.2 1999/11/24 13:26:22 damien Exp $");
Damien Millerd4a8b7e1999-10-27 13:42:43 +10003
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/*
Damien Miller95def091999-11-25 00:26:21 +110018 * EVENTS update channel input/output states execute ACTIONS
Damien Millerd4a8b7e1999-10-27 13:42:43 +100019 */
Damien Miller95def091999-11-25 00:26:21 +110020
Damien Millerd4a8b7e1999-10-27 13:42:43 +100021/* events concerning the INPUT from socket for channel (istate) */
22void
Damien Miller95def091999-11-25 00:26:21 +110023chan_rcvd_oclose(Channel *c)
24{
25 switch (c->istate) {
Damien Millerd4a8b7e1999-10-27 13:42:43 +100026 case CHAN_INPUT_WAIT_OCLOSE:
27 debug("channel %d: INPUT_WAIT_OCLOSE -> INPUT_CLOSED [rcvd OCLOSE]", c->self);
Damien Miller95def091999-11-25 00:26:21 +110028 c->istate = CHAN_INPUT_CLOSED;
Damien Millerd4a8b7e1999-10-27 13:42:43 +100029 chan_delele_if_full_closed(c);
30 break;
31 case CHAN_INPUT_OPEN:
32 debug("channel %d: INPUT_OPEN -> INPUT_CLOSED [rvcd OCLOSE, send IEOF]", c->self);
33 chan_shutdown_read(c);
34 chan_send_ieof(c);
Damien Miller95def091999-11-25 00:26:21 +110035 c->istate = CHAN_INPUT_CLOSED;
Damien Millerd4a8b7e1999-10-27 13:42:43 +100036 chan_delele_if_full_closed(c);
37 break;
38 default:
Damien Miller95def091999-11-25 00:26:21 +110039 debug("protocol error: chan_rcvd_oclose %d for istate %d", c->self, c->istate);
Damien Millerd4a8b7e1999-10-27 13:42:43 +100040 break;
41 }
42}
43void
Damien Miller95def091999-11-25 00:26:21 +110044chan_read_failed(Channel *c)
45{
46 switch (c->istate) {
Damien Millerd4a8b7e1999-10-27 13:42:43 +100047 case CHAN_INPUT_OPEN:
48 debug("channel %d: INPUT_OPEN -> INPUT_WAIT_DRAIN [read failed]", c->self);
49 chan_shutdown_read(c);
Damien Miller95def091999-11-25 00:26:21 +110050 c->istate = CHAN_INPUT_WAIT_DRAIN;
Damien Millerd4a8b7e1999-10-27 13:42:43 +100051 break;
52 default:
53 debug("internal error: we do not read, but chan_read_failed %d for istate %d",
Damien Miller95def091999-11-25 00:26:21 +110054 c->self, c->istate);
Damien Millerd4a8b7e1999-10-27 13:42:43 +100055 break;
56 }
57}
58void
Damien Miller95def091999-11-25 00:26:21 +110059chan_ibuf_empty(Channel *c)
60{
61 if (buffer_len(&c->input)) {
62 debug("internal error: chan_ibuf_empty %d for non empty buffer", c->self);
Damien Millerd4a8b7e1999-10-27 13:42:43 +100063 return;
64 }
Damien Miller95def091999-11-25 00:26:21 +110065 switch (c->istate) {
Damien Millerd4a8b7e1999-10-27 13:42:43 +100066 case CHAN_INPUT_WAIT_DRAIN:
67 debug("channel %d: INPUT_WAIT_DRAIN -> INPUT_WAIT_OCLOSE [inbuf empty, send IEOF]", c->self);
68 chan_send_ieof(c);
Damien Miller95def091999-11-25 00:26:21 +110069 c->istate = CHAN_INPUT_WAIT_OCLOSE;
Damien Millerd4a8b7e1999-10-27 13:42:43 +100070 break;
71 default:
Damien Miller95def091999-11-25 00:26:21 +110072 debug("internal error: chan_ibuf_empty %d for istate %d", c->self, c->istate);
Damien Millerd4a8b7e1999-10-27 13:42:43 +100073 break;
74 }
75}
Damien Miller95def091999-11-25 00:26:21 +110076
Damien Millerd4a8b7e1999-10-27 13:42:43 +100077/* events concerning the OUTPUT from channel for socket (ostate) */
78void
Damien Miller95def091999-11-25 00:26:21 +110079chan_rcvd_ieof(Channel *c)
80{
81 switch (c->ostate) {
Damien Millerd4a8b7e1999-10-27 13:42:43 +100082 case CHAN_OUTPUT_OPEN:
83 debug("channel %d: OUTPUT_OPEN -> OUTPUT_WAIT_DRAIN [rvcd IEOF]", c->self);
Damien Miller95def091999-11-25 00:26:21 +110084 c->ostate = CHAN_OUTPUT_WAIT_DRAIN;
Damien Millerd4a8b7e1999-10-27 13:42:43 +100085 break;
86 case CHAN_OUTPUT_WAIT_IEOF:
87 debug("channel %d: OUTPUT_WAIT_IEOF -> OUTPUT_CLOSED [rvcd IEOF]", c->self);
Damien Miller95def091999-11-25 00:26:21 +110088 c->ostate = CHAN_OUTPUT_CLOSED;
Damien Millerd4a8b7e1999-10-27 13:42:43 +100089 chan_delele_if_full_closed(c);
90 break;
91 default:
Damien Miller95def091999-11-25 00:26:21 +110092 debug("protocol error: chan_rcvd_ieof %d for ostate %d", c->self, c->ostate);
Damien Millerd4a8b7e1999-10-27 13:42:43 +100093 break;
94 }
95}
96void
Damien Miller95def091999-11-25 00:26:21 +110097chan_write_failed(Channel *c)
98{
99 switch (c->ostate) {
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000100 case CHAN_OUTPUT_OPEN:
101 debug("channel %d: OUTPUT_OPEN -> OUTPUT_WAIT_IEOF [write failed]", c->self);
102 chan_send_oclose(c);
Damien Miller95def091999-11-25 00:26:21 +1100103 c->ostate = CHAN_OUTPUT_WAIT_IEOF;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000104 break;
105 case CHAN_OUTPUT_WAIT_DRAIN:
106 debug("channel %d: OUTPUT_WAIT_DRAIN -> OUTPUT_CLOSED [write failed]", c->self);
107 chan_send_oclose(c);
Damien Miller95def091999-11-25 00:26:21 +1100108 c->ostate = CHAN_OUTPUT_CLOSED;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000109 chan_delele_if_full_closed(c);
110 break;
111 default:
Damien Miller95def091999-11-25 00:26:21 +1100112 debug("internal error: chan_write_failed %d for ostate %d", c->self, c->ostate);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000113 break;
114 }
115}
116void
Damien Miller95def091999-11-25 00:26:21 +1100117chan_obuf_empty(Channel *c)
118{
119 if (buffer_len(&c->output)) {
120 debug("internal error: chan_obuf_empty %d for non empty buffer", c->self);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000121 return;
122 }
Damien Miller95def091999-11-25 00:26:21 +1100123 switch (c->ostate) {
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000124 case CHAN_OUTPUT_WAIT_DRAIN:
125 debug("channel %d: OUTPUT_WAIT_DRAIN -> OUTPUT_CLOSED [obuf empty, send OCLOSE]", c->self);
126 chan_send_oclose(c);
Damien Miller95def091999-11-25 00:26:21 +1100127 c->ostate = CHAN_OUTPUT_CLOSED;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000128 chan_delele_if_full_closed(c);
129 break;
130 default:
Damien Miller95def091999-11-25 00:26:21 +1100131 debug("internal error: chan_obuf_empty %d for ostate %d", c->self, c->ostate);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000132 break;
133 }
134}
Damien Miller95def091999-11-25 00:26:21 +1100135
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000136/*
Damien Miller95def091999-11-25 00:26:21 +1100137 * ACTIONS: should never update the channel states: c->istate or c->ostate
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000138 */
139static void
Damien Miller95def091999-11-25 00:26:21 +1100140chan_send_ieof(Channel *c)
141{
142 switch (c->istate) {
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000143 case CHAN_INPUT_OPEN:
144 case CHAN_INPUT_WAIT_DRAIN:
145 packet_start(SSH_MSG_CHANNEL_INPUT_EOF);
146 packet_put_int(c->remote_id);
147 packet_send();
148 break;
149 default:
Damien Miller95def091999-11-25 00:26:21 +1100150 debug("internal error: channel %d: cannot send IEOF for istate %d", c->self, c->istate);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000151 break;
152 }
153}
154static void
Damien Miller95def091999-11-25 00:26:21 +1100155chan_send_oclose(Channel *c)
156{
157 switch (c->ostate) {
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000158 case CHAN_OUTPUT_OPEN:
159 case CHAN_OUTPUT_WAIT_DRAIN:
160 chan_shutdown_write(c);
161 buffer_consume(&c->output, buffer_len(&c->output));
162 packet_start(SSH_MSG_CHANNEL_OUTPUT_CLOSE);
163 packet_put_int(c->remote_id);
164 packet_send();
165 break;
166 default:
Damien Miller95def091999-11-25 00:26:21 +1100167 debug("internal error: channel %d: cannot send OCLOSE for ostate %d", c->self, c->istate);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000168 break;
169 }
170}
Damien Miller95def091999-11-25 00:26:21 +1100171
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000172/* helper */
173static void
Damien Miller95def091999-11-25 00:26:21 +1100174chan_shutdown_write(Channel *c)
175{
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000176 debug("channel %d: shutdown_write", c->self);
Damien Miller95def091999-11-25 00:26:21 +1100177 if (shutdown(c->sock, SHUT_WR) < 0)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000178 error("chan_shutdown_write failed for #%d/fd%d: %.100s",
Damien Miller95def091999-11-25 00:26:21 +1100179 c->self, c->sock, strerror(errno));
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000180}
181static void
Damien Miller95def091999-11-25 00:26:21 +1100182chan_shutdown_read(Channel *c)
183{
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000184 debug("channel %d: shutdown_read", c->self);
Damien Miller95def091999-11-25 00:26:21 +1100185 if (shutdown(c->sock, SHUT_RD) < 0)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000186 error("chan_shutdown_read failed for #%d/fd%d: %.100s",
Damien Miller95def091999-11-25 00:26:21 +1100187 c->self, c->sock, strerror(errno));
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000188}
189static void
Damien Miller95def091999-11-25 00:26:21 +1100190chan_delele_if_full_closed(Channel *c)
191{
192 if (c->istate == CHAN_INPUT_CLOSED && c->ostate == CHAN_OUTPUT_CLOSED) {
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000193 debug("channel %d: closing", c->self);
194 channel_free(c->self);
195 }
196}
197void
Damien Miller95def091999-11-25 00:26:21 +1100198chan_init_iostates(Channel *c)
199{
200 c->ostate = CHAN_OUTPUT_OPEN;
201 c->istate = CHAN_INPUT_OPEN;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000202}