kernel: new DEBUG_RACE option. try to provoke race conditions between processes.
[minix.git] / commands / telnetd / telnet.c
blob0bbe6552b399a839e08efedfc13bee2e9bbaa4b3
1 /*
2 * TNET A server program for MINIX which implements the TCP/IP
3 * suite of networking protocols. It is based on the
4 * TCP/IP code written by Phil Karn et al, as found in
5 * his NET package for Packet Radio communications.
7 * This module handles telnet option processing.
9 * Author: Michael Temari, <temari@temari.ae.ge.com> 01/13/93
12 #include <sys/types.h>
13 #include <string.h>
14 #include <fcntl.h>
15 #include <errno.h>
16 #include <unistd.h>
17 #include <termios.h>
18 #include "telnetd.h"
19 #include "telnet.h"
20 #include <stdio.h>
21 #include <sys/ioctl.h>
24 #define IN_DATA 0
25 #define IN_CR 1
26 #define IN_IAC 2
27 #define IN_IAC2 3
28 #define IN_SB 4
30 _PROTOTYPE(static void dowill, (int c));
31 _PROTOTYPE(static void dowont, (int c));
32 _PROTOTYPE(static void dodo, (int c));
33 _PROTOTYPE(static void dodont, (int c));
34 _PROTOTYPE(static void respond, (int ack, int option));
35 _PROTOTYPE(static void respond_really, (int ack, int option));
37 #define LASTTELOPT TELOPT_SGA
39 static int r_winch = 0;
41 static int TelROpts[LASTTELOPT+1];
42 static int TelLOpts[LASTTELOPT+1];
44 static int telfdout;
46 void tel_init()
48 int i;
50 for(i = 0; i <= LASTTELOPT; i++) {
51 TelROpts[i] = 0;
52 TelLOpts[i] = 0;
56 void telopt(fdout, what, option)
57 int fdout;
58 int what;
59 int option;
61 char buf[3];
62 int len;
64 buf[0] = IAC;
65 buf[1] = what;
66 buf[2] = option;
67 len = 0;
69 switch(what) {
70 case DO:
71 if(option <= LASTTELOPT) {
72 TelROpts[option] = 1;
73 len = 3;
74 } else if(option == TELOPT_WINCH && !r_winch) { r_winch = 1; len = 3; }
75 break;
76 case DONT:
77 if(option <= LASTTELOPT) {
78 TelROpts[option] = 1;
79 len = 3;
81 break;
82 case WILL:
83 if(option <= LASTTELOPT) {
84 TelLOpts[option] = 1;
85 len = 3;
87 break;
88 case WONT:
89 if(option <= LASTTELOPT) {
90 TelLOpts[option] = 1;
91 len = 3;
93 break;
95 if(len > 0)
96 (void) write(fdout, buf, len);
99 int set_winsize(int fd, unsigned int cols, unsigned int rows)
101 struct winsize w;
102 memset(&w, 0, sizeof(w));
103 w.ws_col = cols;
104 w.ws_row = rows;
105 ioctl(fd, TIOCSWINSZ, (char *) &w);
108 int tel_in(fdout, telout, buffer, len)
109 int fdout;
110 int telout;
111 char *buffer;
112 int len;
114 static int InState = IN_DATA;
115 static int ThisOpt = 0;
116 char *p;
117 char *p2;
118 int size;
119 int c;
121 telfdout = telout;
122 p = p2 = buffer;
123 size = 0;
125 while(len > 0) {
126 c = (unsigned char)*p++; len--;
127 switch(InState) {
128 case IN_CR:
129 InState = IN_DATA;
130 if(c == 0 || c == '\n')
131 break;
132 /* fall through */
133 case IN_DATA:
134 if(c == IAC) {
135 InState = IN_IAC;
136 break;
138 *p2++ = c; size++;
139 if(c == '\r') InState = IN_CR;
140 break;
141 case IN_IAC:
142 switch(c) {
143 case IAC:
144 *p2++ = c; size++;
145 InState = IN_DATA;
146 break;
147 case WILL:
148 case WONT:
149 case DO:
150 case DONT:
151 InState = IN_IAC2;
152 ThisOpt = c;
153 break;
154 case SB:
155 InState = IN_SB;
156 break;
157 case EOR:
158 case SE:
159 case NOP:
160 case BREAK:
161 case IP:
162 case AO:
163 case AYT:
164 case EC:
165 case EL:
166 case GA:
167 break;
168 default:
169 break;
171 break;
172 case IN_IAC2:
173 if(size > 0) {
174 write(fdout, buffer, size);
175 p2 = buffer;
176 size = 0;
178 InState = IN_DATA;
179 switch(ThisOpt) {
180 case WILL: dowill(c); break;
181 case WONT: dowont(c); break;
182 case DO: dodo(c); break;
183 case DONT: dodont(c); break;
185 break;
186 case IN_SB:
188 static int winchpos = -1;
189 /* Subnegotiation. */
190 if(winchpos >= 0) {
191 static unsigned int winchbuf[5], iacs = 0;
192 winchbuf[winchpos] = c;
193 /* IAC is escaped - unescape it. */
194 if(c == IAC) iacs++; else { iacs = 0; winchpos++; }
195 if(iacs == 2) { winchpos++; iacs = 0; }
196 if(winchpos >= 4) {
197 /* End of WINCH data. */
198 set_winsize(fdout,
199 (winchbuf[0] << 8) | winchbuf[1],
200 (winchbuf[2] << 8) | winchbuf[3]);
201 winchpos = -1;
203 } else {
204 static int lastiac = 0;
205 switch(c) {
206 case TELOPT_WINCH:
207 /* Start listening. */
208 winchpos = 0;
209 break;
210 case SE:
211 if(lastiac) InState = IN_DATA;
212 break;
213 default:
214 break;
216 if(c == IAC) lastiac = 1;
217 else lastiac = 0;
221 break;
226 if(size > 0)
227 write(fdout, buffer, size);
230 int tel_out(fdout, buf, size)
231 int fdout;
232 char *buf;
233 int size;
235 char *p;
236 int got_iac, len;
238 p = buf;
239 while(size > 0) {
240 buf = p;
241 got_iac = 0;
242 if((p = (char *)memchr(buf, IAC, size)) != (char *)NULL) {
243 got_iac = 1;
244 p++;
245 } else
246 p = buf + size;
247 len = p - buf;
248 if(len > 0)
249 (void) write(fdout, buf, len);
250 if(got_iac)
251 (void) write(fdout, p - 1, 1);
252 size = size - len;
256 static void dowill(c)
257 int c;
259 int ack;
261 switch(c) {
262 case TELOPT_BINARY:
263 case TELOPT_ECHO:
264 case TELOPT_SGA:
265 if(TelROpts[c] == 1)
266 return;
267 TelROpts[c] = 1;
268 ack = DO;
269 break;
270 case TELOPT_WINCH:
271 if(r_winch) return;
272 r_winch = 1;
273 ack = DO;
274 respond_really(ack, c);
275 return;
276 default:
277 ack = DONT;
280 respond(ack, c);
283 static void dowont(c)
284 int c;
286 if(c <= LASTTELOPT) {
287 if(TelROpts[c] == 0)
288 return;
289 TelROpts[c] = 0;
291 respond(DONT, c);
294 static void dodo(c)
295 int c;
297 int ack;
299 switch(c) {
300 default:
301 ack = WONT;
303 respond(ack, c);
306 static void dodont(c)
307 int c;
309 if(c <= LASTTELOPT) {
310 if(TelLOpts[c] == 0)
311 return;
312 TelLOpts[c] = 0;
314 respond(WONT, c);
317 static void respond(ack, option)
318 int ack, option;
320 unsigned char c[3];
322 c[0] = IAC;
323 c[1] = ack;
324 c[2] = option;
325 /* write(telfdout, c, 3); */
328 static void respond_really(ack, option)
329 int ack, option;
331 unsigned char c[3];
333 c[0] = IAC;
334 c[1] = ack;
335 c[2] = option;
336 write(telfdout, c, 3);