diff options
author | Damien Miller <djm@mindrot.org> | 1999-10-27 13:42:43 +1000 |
---|---|---|
committer | Damien Miller <djm@mindrot.org> | 1999-10-27 13:42:43 +1000 |
commit | d4a8b7e34dd619a4debf9a206c81db26d1402ea6 (patch) | |
tree | a47d770a2f790f40d18b0982d4e55fa7cfb1fa3b /nchan.c |
Initial revision
Diffstat (limited to 'nchan.c')
-rw-r--r-- | nchan.c | 187 |
1 files changed, 187 insertions, 0 deletions
diff --git a/nchan.c b/nchan.c new file mode 100644 index 000000000..fcaeae405 --- /dev/null +++ b/nchan.c | |||
@@ -0,0 +1,187 @@ | |||
1 | #include "includes.h" | ||
2 | RCSID("$Id: nchan.c,v 1.1 1999/10/27 03:42:44 damien Exp $"); | ||
3 | |||
4 | #include "ssh.h" | ||
5 | |||
6 | #include "buffer.h" | ||
7 | #include "packet.h" | ||
8 | #include "channels.h" | ||
9 | #include "nchan.h" | ||
10 | |||
11 | static void chan_send_ieof(Channel *c); | ||
12 | static void chan_send_oclose(Channel *c); | ||
13 | static void chan_shutdown_write(Channel *c); | ||
14 | static void chan_shutdown_read(Channel *c); | ||
15 | static 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) */ | ||
22 | void | ||
23 | chan_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 | } | ||
42 | void | ||
43 | chan_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 | } | ||
56 | void | ||
57 | chan_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) */ | ||
74 | void | ||
75 | chan_rcvd_ieof(Channel *c){ | ||
76 | switch(c->ostate){ | ||
77 | case CHAN_OUTPUT_OPEN: | ||
78 | debug("channel %d: OUTPUT_OPEN -> OUTPUT_WAIT_DRAIN [rvcd IEOF]", c->self); | ||
79 | c->ostate=CHAN_OUTPUT_WAIT_DRAIN; | ||
80 | break; | ||
81 | case CHAN_OUTPUT_WAIT_IEOF: | ||
82 | debug("channel %d: OUTPUT_WAIT_IEOF -> OUTPUT_CLOSED [rvcd IEOF]", c->self); | ||
83 | c->ostate=CHAN_OUTPUT_CLOSED; | ||
84 | chan_delele_if_full_closed(c); | ||
85 | break; | ||
86 | default: | ||
87 | debug("protocol error: chan_rcvd_ieof %d for ostate %d", c->self,c->ostate); | ||
88 | break; | ||
89 | } | ||
90 | } | ||
91 | void | ||
92 | chan_write_failed(Channel *c){ | ||
93 | switch(c->ostate){ | ||
94 | case CHAN_OUTPUT_OPEN: | ||
95 | debug("channel %d: OUTPUT_OPEN -> OUTPUT_WAIT_IEOF [write failed]", c->self); | ||
96 | chan_send_oclose(c); | ||
97 | c->ostate=CHAN_OUTPUT_WAIT_IEOF; | ||
98 | break; | ||
99 | case CHAN_OUTPUT_WAIT_DRAIN: | ||
100 | debug("channel %d: OUTPUT_WAIT_DRAIN -> OUTPUT_CLOSED [write failed]", c->self); | ||
101 | chan_send_oclose(c); | ||
102 | c->ostate=CHAN_OUTPUT_CLOSED; | ||
103 | chan_delele_if_full_closed(c); | ||
104 | break; | ||
105 | default: | ||
106 | debug("internal error: chan_write_failed %d for ostate %d",c->self,c->ostate); | ||
107 | break; | ||
108 | } | ||
109 | } | ||
110 | void | ||
111 | chan_obuf_empty(Channel *c){ | ||
112 | if(buffer_len(&c->output)){ | ||
113 | debug("internal error: chan_obuf_empty %d for non empty buffer",c->self); | ||
114 | return; | ||
115 | } | ||
116 | switch(c->ostate){ | ||
117 | case CHAN_OUTPUT_WAIT_DRAIN: | ||
118 | debug("channel %d: OUTPUT_WAIT_DRAIN -> OUTPUT_CLOSED [obuf empty, send OCLOSE]", c->self); | ||
119 | chan_send_oclose(c); | ||
120 | c->ostate=CHAN_OUTPUT_CLOSED; | ||
121 | chan_delele_if_full_closed(c); | ||
122 | break; | ||
123 | default: | ||
124 | debug("internal error: chan_obuf_empty %d for ostate %d",c->self,c->ostate); | ||
125 | break; | ||
126 | } | ||
127 | } | ||
128 | /* | ||
129 | * ACTIONS: should never update c->istate or c->ostate | ||
130 | */ | ||
131 | static void | ||
132 | chan_send_ieof(Channel *c){ | ||
133 | switch(c->istate){ | ||
134 | case CHAN_INPUT_OPEN: | ||
135 | case CHAN_INPUT_WAIT_DRAIN: | ||
136 | packet_start(SSH_MSG_CHANNEL_INPUT_EOF); | ||
137 | packet_put_int(c->remote_id); | ||
138 | packet_send(); | ||
139 | break; | ||
140 | default: | ||
141 | debug("internal error: channel %d: cannot send IEOF for istate %d",c->self,c->istate); | ||
142 | break; | ||
143 | } | ||
144 | } | ||
145 | static void | ||
146 | chan_send_oclose(Channel *c){ | ||
147 | switch(c->ostate){ | ||
148 | case CHAN_OUTPUT_OPEN: | ||
149 | case CHAN_OUTPUT_WAIT_DRAIN: | ||
150 | chan_shutdown_write(c); | ||
151 | buffer_consume(&c->output, buffer_len(&c->output)); | ||
152 | packet_start(SSH_MSG_CHANNEL_OUTPUT_CLOSE); | ||
153 | packet_put_int(c->remote_id); | ||
154 | packet_send(); | ||
155 | break; | ||
156 | default: | ||
157 | debug("internal error: channel %d: cannot send OCLOSE for ostate %d",c->self,c->istate); | ||
158 | break; | ||
159 | } | ||
160 | } | ||
161 | /* helper */ | ||
162 | static void | ||
163 | chan_shutdown_write(Channel *c){ | ||
164 | debug("channel %d: shutdown_write", c->self); | ||
165 | if(shutdown(c->sock, SHUT_WR)<0) | ||
166 | error("chan_shutdown_write failed for #%d/fd%d: %.100s", | ||
167 | c->self, c->sock, strerror(errno)); | ||
168 | } | ||
169 | static void | ||
170 | chan_shutdown_read(Channel *c){ | ||
171 | debug("channel %d: shutdown_read", c->self); | ||
172 | if(shutdown(c->sock, SHUT_RD)<0) | ||
173 | error("chan_shutdown_read failed for #%d/fd%d: %.100s", | ||
174 | c->self, c->sock, strerror(errno)); | ||
175 | } | ||
176 | static void | ||
177 | chan_delele_if_full_closed(Channel *c){ | ||
178 | if(c->istate==CHAN_INPUT_CLOSED && c->ostate==CHAN_OUTPUT_CLOSED){ | ||
179 | debug("channel %d: closing", c->self); | ||
180 | channel_free(c->self); | ||
181 | } | ||
182 | } | ||
183 | void | ||
184 | chan_init_iostates(Channel *c){ | ||
185 | c->ostate=CHAN_OUTPUT_OPEN; | ||
186 | c->istate=CHAN_INPUT_OPEN; | ||
187 | } | ||