]> andersk Git - openssh.git/blob - nchan.c
Initial revision
[openssh.git] / nchan.c
1 #include "includes.h"
2 RCSID("$Id$");
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 }
This page took 0.056137 seconds and 5 git commands to generate.