/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- buffer_init
- buffer_free
- buffer_readjust
- buffer_ready_for_read
- buffer_read
- buffer_ready_for_write
- buffer_write
- set_nonblock
- signal_handler
- client_loop
1 #include <unistd.h>
2 #include <sys/errno.h>
3 #include <sys/fcntl.h>
4 #include <sys/types.h>
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <signal.h>
8 #include <string.h>
9 #include <assert.h>
10
11 #define MAX(a,b) ((a) < (b) ? (b) : (a))
12
13 #define MAX_BUFFER_SIZE (64*1024)
14
15 struct Buffer {
16 char *buf;
17 int off;
18 int end;
19 int len;
20 };
21
22 static void buffer_init(struct Buffer *buf);
23 static void buffer_free(struct Buffer *buf);
24 static void buffer_read(struct Buffer *buf, int fd);
25 static void buffer_write(struct Buffer *buf, int fd);
26
27 int quit_pending = 0;
28 pid_t childPid = -1;
29 int remoteSock;
30 static struct Buffer stdin_buffer, stdout_buffer, stderr_buffer;
31
32 static void buffer_init(struct Buffer *buf)
33 {
34 assert(buf != NULL);
35 buf->buf = (char*) malloc(MAX_BUFFER_SIZE);
36 assert(buf->buf != NULL);
37 buf->off = 0;
38 buf->end = 0;
39 buf->len = MAX_BUFFER_SIZE;
40 }
41
42 static void buffer_free(struct Buffer *buf)
43 {
44 free(buf->buf);
45 buf->buf = NULL;
46 buf->len = 0;
47 }
48
49 static void buffer_readjust(struct Buffer *buf)
50 {
51 memmove(buf->buf, &buf->buf[buf->off], buf->end - buf->off);
52 buf->end -= buf->off;
53 buf->off = 0;
54 }
55
56 static bool buffer_ready_for_read(struct Buffer *buf)
57 {
58 assert(buf->buf != NULL && buf->len != 0);
59 return buf->end < buf->len - 1;
60 }
61
62 static void buffer_read(struct Buffer *buf, int fd)
63 {
64 assert(buf->buf != NULL && buf->len != 0);
65
66 if (buf->end < buf->len) {
67 size_t max = buf->len - buf->end;
68 ssize_t rc = read(fd, &buf->buf[buf->end], max);
69 if (rc == 0 || (rc == -1 && errno != EINTR)) {
70 quit_pending = 1;
71 return;
72 }
73 buf->end += rc;
74 }
75 }
76
77 static bool buffer_ready_for_write(struct Buffer *buf)
78 {
79 assert(buf->buf != NULL && buf->len != 0);
80 return buf->end > buf->off;
81 }
82
83 static void buffer_write(struct Buffer *buf, int fd)
84 {
85 assert(buf->buf != NULL && buf->len != 0);
86
87 assert(buf->end > buf->off);
88 size_t max = buf->end - buf->off;
89 ssize_t rc = write(fd, &buf->buf[buf->off], max);
90 if (rc == -1 && errno != EINTR) {
91 quit_pending = 1;
92 return;
93 }
94 buf->off += rc;
95 if (buf->off > buf->len / 2) {
96 buffer_readjust(buf);
97 }
98 }
99
100
101 /* set/unset filedescriptor to non-blocking */
102 static void set_nonblock(int fd)
103 {
104 int val;
105 val = fcntl(fd, F_GETFL, 0);
106 if (val < 0) {
107 perror("fcntl failed");
108 }
109 val |= O_NONBLOCK;
110 if (fcntl(fd, F_SETFL, val) == -1) {
111 perror("fcntl failed");
112 }
113 }
114
115 /*
116 * Signal handler for signals that cause the program to terminate. These
117 * signals must be trapped to restore terminal modes.
118 */
119 static void signal_handler(int sig)
120 {
121 quit_pending = 1;
122 if (childPid != -1) {
123 kill(childPid, sig);
124 }
125 }
126
127 void client_loop(int ssh_stdin, int ssh_stdout, int ssh_stderr, int sock)
128 {
129 remoteSock = sock;
130 /* Initialize buffers. */
131 buffer_init(&stdin_buffer);
132 buffer_init(&stdout_buffer);
133 buffer_init(&stderr_buffer);
134
135 /* enable nonblocking unless tty */
136 set_nonblock(fileno(stdin));
137 set_nonblock(fileno(stdout));
138 set_nonblock(fileno(stderr));
139
140 /*
141 * Set signal handlers, (e.g. to restore non-blocking mode)
142 * but don't overwrite SIG_IGN, matches behaviour from rsh(1)
143 */
144 if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
145 signal(SIGHUP, signal_handler);
146 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
147 signal(SIGINT, signal_handler);
148 if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
149 signal(SIGQUIT, signal_handler);
150 if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
151 signal(SIGTERM, signal_handler);
152 //signal(SIGWINCH, window_change_handler);
153
154 fd_set readset, writeset, errorset;
155 int max_fd = 0;
156
157 max_fd = MAX(ssh_stdin, ssh_stdout);
158 max_fd = MAX(max_fd, ssh_stderr);
159
160 /* Main loop of the client for the interactive session mode. */
161 while (!quit_pending) {
162 struct timeval tv = {10, 0};
163 FD_ZERO(&readset);
164 FD_ZERO(&writeset);
165 FD_ZERO(&errorset);
166 FD_SET(remoteSock, &errorset);
167
168 if (buffer_ready_for_read(&stdin_buffer)) {
169 FD_SET(STDIN_FILENO, &readset);
170 }
171 if (buffer_ready_for_read(&stdout_buffer)) {
172 FD_SET(ssh_stdout, &readset);
173 }
174 if (buffer_ready_for_read(&stderr_buffer)) {
175 FD_SET(ssh_stderr, &readset);
176 }
177
178 if (buffer_ready_for_write(&stdin_buffer)) {
179 FD_SET(ssh_stdin, &writeset);
180 }
181 if (buffer_ready_for_write(&stdout_buffer)) {
182 FD_SET(STDOUT_FILENO, &writeset);
183 }
184 if (buffer_ready_for_write(&stderr_buffer)) {
185 FD_SET(STDERR_FILENO, &writeset);
186 }
187
188 int ret = select(max_fd, &readset, &writeset, &errorset, &tv);
189 if (ret == -1 && errno == EINTR) {
190 continue;
191 }
192 if (ret == -1) {
193 perror("select failed");
194 return;
195 }
196
197 if (quit_pending)
198 break;
199
200 //Read from our STDIN or stdout/err of ssh
201 if (FD_ISSET(STDIN_FILENO, &readset)) {
202 buffer_read(&stdin_buffer, STDIN_FILENO);
203 }
204 if (FD_ISSET(ssh_stdout, &readset)) {
205 buffer_read(&stdout_buffer, ssh_stdout);
206 }
207 if (FD_ISSET(ssh_stderr, &readset)) {
208 buffer_read(&stderr_buffer, ssh_stderr);
209 }
210
211 // Write to our stdout/err or stdin of ssh
212 if (FD_ISSET(ssh_stdin, &writeset)) {
213 buffer_write(&stdin_buffer, ssh_stdin);
214 }
215 if (FD_ISSET(STDOUT_FILENO, &writeset)) {
216 buffer_write(&stdout_buffer, STDOUT_FILENO);
217 }
218 if (FD_ISSET(STDERR_FILENO, &writeset)) {
219 buffer_write(&stderr_buffer, STDERR_FILENO);
220 }
221
222 if (FD_ISSET(remoteSock, &errorset)) {
223 break;
224 }
225
226 if (quit_pending)
227 break;
228 }
229
230 /* Write pending data to our stdout/stderr */
231 if (buffer_ready_for_write(&stdout_buffer)) {
232 buffer_write(&stdout_buffer, STDOUT_FILENO);
233 }
234 if (buffer_ready_for_write(&stderr_buffer)) {
235 buffer_write(&stderr_buffer, STDERR_FILENO);
236 }
237
238 /* Clear and free any buffers. */
239 buffer_free(&stdin_buffer);
240 buffer_free(&stdout_buffer);
241 buffer_free(&stderr_buffer);
242 }