4
4
#include <unistd.h>
5
5
#include <string.h>
6
6
#include <getopt.h>
7
+ #include <fcntl.h>
8
+ #include <termios.h>
9
+ #include <sys/wait.h>
7
10
#include "ncp.h"
8
11
9
12
#define OLD_TELNET 1
39
42
#define OPT_SUPDUP 025
40
43
#define OPT_SUPDUP_OUTPUT 026
41
44
45
+ #define OMARK 0200
46
+ #define OBREAK 0201
47
+ #define ONOP 0202
48
+ #define ONOECHO 0203
49
+ #define OECHO 0204
50
+ #define OHIDE 0205
51
+ #define OASCII 0240
52
+ #define OTRANSPARENT 0241
53
+ #define OEBCDIC 0242
54
+
55
+ static pid_t reader_pid = 0 ;
56
+ static pid_t writer_pid = 0 ;
57
+ static struct termios saved ;
58
+
42
59
static char options [] = {
43
60
IAC , DO , OPT_ECHO ,
44
61
IAC , DO , OPT_SUPPRESS_GO_AHEAD ,
45
62
IAC , WILL , OPT_SUPPRESS_GO_AHEAD ,
46
63
0
47
64
};
48
65
49
- static void option (unsigned char c )
66
+ static void option (int fd )
50
67
{
68
+ unsigned char c ;
69
+ read (fd , & c , 1 );
51
70
switch (c ) {
52
71
case OPT_BINARY :
53
72
break ;
@@ -76,23 +95,23 @@ static void option (unsigned char c)
76
95
}
77
96
}
78
97
79
- static int special (unsigned char c , const unsigned char * data )
98
+ static int special (unsigned char c , int fd )
80
99
{
81
100
switch (c ) {
82
101
case IAC :
83
102
write (1 , & c , 1 );
84
103
return 0 ;
85
104
case DONT :
86
- option (* data );
105
+ option (fd );
87
106
return 1 ;
88
107
case DO :
89
- option (* data );
108
+ option (fd );
90
109
return 1 ;
91
110
case WONT :
92
- option (* data );
111
+ option (fd );
93
112
return 1 ;
94
113
case WILL :
95
- option (* data );
114
+ option (fd );
96
115
return 1 ;
97
116
case SB :
98
117
return 0 ;
@@ -122,32 +141,187 @@ static int special (unsigned char c, const unsigned char *data)
122
141
}
123
142
}
124
143
125
- static void process ( const unsigned char * data , int size )
144
+ static void process_new ( unsigned char data , int fd )
126
145
{
127
- int i ;
146
+ switch (data ) {
147
+ case NUL :
148
+ break ;
149
+ case IAC :
150
+ read (fd , & data , 1 );
151
+ special (data , fd );
152
+ break ;
153
+ default :
154
+ write (1 , & data , 1 );
155
+ break ;
156
+ }
157
+ }
128
158
129
- for (i = 0 ; i < size ; i ++ ) {
130
- switch (data [i ]) {
131
- case NUL :
132
- break ;
133
- case IAC :
134
- i ++ ;
135
- i += special (data [i ], & data [i + 1 ]);
136
- break ;
137
- default :
138
- write (1 , & data [i ], 1 );
139
- break ;
159
+ static void process_old (unsigned char data , int fd )
160
+ {
161
+ unsigned char crlf [] = { 015 , 012 };
162
+ switch (data ) {
163
+ case NUL :
164
+ break ;
165
+ case 001 : case 002 : case 003 : case 004 : case 005 : case 006 :
166
+ break ;
167
+ case 016 : case 017 : case 020 : case 021 : case 022 : case 023 :
168
+ case 024 : case 025 : case 026 : case 027 : case 030 : case 031 :
169
+ case 032 : case 033 : case 034 : case 035 : case 036 : case 037 :
170
+ break ;
171
+ case 0177 :
172
+ break ;
173
+ case 015 :
174
+ read (fd , & data , 1 );
175
+ if (data == NUL )
176
+ write (1 , crlf , 1 );
177
+ else if (data == 012 )
178
+ write (1 , crlf , 2 );
179
+ else
180
+ fprintf (stderr , "[CR without LF or NUL]" );
181
+ case OMARK :
182
+ fprintf (stderr , "[MARK]" ); fflush (stderr );
183
+ break ;
184
+ case OBREAK :
185
+ fprintf (stderr , "[BREAK]" ); fflush (stderr );
186
+ break ;
187
+ case ONOP :
188
+ fprintf (stderr , "[NOP]" ); fflush (stderr );
189
+ break ;
190
+ case ONOECHO :
191
+ fprintf (stderr , "[NOECHO]" ); fflush (stderr );
192
+ break ;
193
+ case OECHO :
194
+ fprintf (stderr , "[ECHO]" ); fflush (stderr );
195
+ break ;
196
+ case OHIDE :
197
+ fprintf (stderr , "[HIDE]" ); fflush (stderr );
198
+ break ;
199
+ case OASCII :
200
+ fprintf (stderr , "[ASCII]" ); fflush (stderr );
201
+ break ;
202
+ case OTRANSPARENT :
203
+ fprintf (stderr , "[TRANSPARENT]" ); fflush (stderr );
204
+ break ;
205
+ case OEBCDIC :
206
+ fprintf (stderr , "[EBCDIC]" ); fflush (stderr );
207
+ break ;
208
+ default :
209
+ write (1 , & data , 1 );
210
+ }
211
+ }
212
+
213
+ static int reader (int connection )
214
+ {
215
+ unsigned char data [200 ];
216
+ int size , flags ;
217
+ int fds [2 ];
218
+
219
+ if (pipe (fds ) == -1 )
220
+ exit (1 );
221
+
222
+ flags = fcntl (fds [0 ], F_GETFL );
223
+ fcntl (fds [0 ], F_SETFL , flags | O_NONBLOCK );
224
+
225
+ reader_pid = fork ();
226
+ if (reader_pid ) {
227
+ close (fds [1 ]);
228
+ return fds [0 ];
229
+ }
230
+ close (fds [0 ]);
231
+
232
+ if (ncp_init (NULL ) == -1 )
233
+ exit (1 );
234
+
235
+ for (;;) {
236
+ size = sizeof data ;
237
+ if (ncp_read (connection , data , & size ) == -1 ) {
238
+ fprintf (stderr , "NCP read error.\n" );
239
+ exit (1 );
140
240
}
241
+ if (size == 0 )
242
+ exit (0 );
243
+ if (write (fds [1 ], data , size ) == -1 )
244
+ exit (1 );
141
245
}
142
246
}
143
247
144
- static void telnet_client (int host , int sock , int new )
248
+ static int writer (int connection )
145
249
{
146
- unsigned char reply [1000 ];
147
- int connection , size ;
250
+ unsigned char data [200 ], * ptr ;
251
+ ssize_t n , m ;
252
+ int fds [2 ];
253
+ int size ;
254
+
255
+ if (pipe (fds ) == -1 )
256
+ exit (1 );
257
+
258
+ writer_pid = fork ();
259
+ if (writer_pid ) {
260
+ close (fds [0 ]);
261
+ return fds [1 ];
262
+ }
263
+ close (fds [1 ]);
264
+
265
+ if (ncp_init (NULL ) == -1 )
266
+ exit (1 );
267
+
268
+ size = strlen (options );
269
+ if (ncp_write (connection , options , & size ) == -1 ) {
270
+ fprintf (stderr , "NCP write error.\n" );
271
+ exit (1 );
272
+ }
273
+
274
+ for (;;) {
275
+ fd_set rfds ;
276
+ FD_ZERO (& rfds );
277
+ FD_SET (fds [0 ], & rfds );
278
+ n = select (33 , & rfds , NULL , NULL , NULL );
279
+ n = read (fds [0 ], data , 1 );
280
+ if (n == 0 )
281
+ exit (0 );
282
+ if (n < 0 )
283
+ continue ;
284
+ ptr = data ;
285
+ for (ptr = data , m = n ; m > 0 ; ptr += size , m -= size ) {
286
+ size = m ;
287
+ if (ncp_write (connection , ptr , & size ) == -1 ) {
288
+ fprintf (stderr , "NCP write error.\n" );
289
+ exit (1 );
290
+ }
291
+ if (size == 0 )
292
+ exit (0 );
293
+ }
294
+ }
295
+ }
296
+
297
+ static void restore_termios (void )
298
+ {
299
+ tcsetattr (0 , TCSAFLUSH , & saved );
300
+ }
301
+
302
+ static void raw (void )
303
+ {
304
+ struct termios new ;
305
+ new = saved ;
306
+ new .c_iflag = 0 ;
307
+ new .c_oflag = 0 ;
308
+ new .c_lflag = 0 ;
309
+ new .c_cc [VMIN ] = 1 ;
310
+ new .c_cc [VTIME ] = 0 ;
311
+ tcsetattr (0 , TCSAFLUSH , & new );
312
+ }
313
+
314
+ static void telnet_client (int host , int sock ,
315
+ void (* process ) (unsigned char , int ))
316
+ {
317
+ int connection ;
318
+ int reader_fd , writer_fd ;
148
319
149
320
printf ("TELNET to host %03o.\n" , host );
150
321
322
+ tcgetattr (0 , & saved );
323
+ raw ();
324
+
151
325
switch (ncp_open (host , sock , & connection )) {
152
326
case 0 :
153
327
break ;
@@ -160,19 +334,37 @@ static void telnet_client (int host, int sock, int new)
160
334
exit (1 );
161
335
}
162
336
163
- size = strlen (options );
164
- if (ncp_write (connection , options , & size ) == -1 ) {
165
- fprintf (stderr , "NCP write error.\n" );
166
- exit (1 );
167
- }
337
+ reader_fd = reader (connection );
338
+ writer_fd = writer (connection );
168
339
169
- size = sizeof reply ;
170
- if (ncp_read (connection , reply , & size ) == -1 ) {
171
- fprintf (stderr , "NCP read error.\n" );
172
- exit (1 );
340
+ for (;;) {
341
+ fd_set rfds ;
342
+ int n ;
343
+ FD_ZERO (& rfds );
344
+ FD_SET (0 , & rfds );
345
+ FD_SET (reader_fd , & rfds );
346
+ n = select (33 , & rfds , NULL , NULL , NULL );
347
+ if (n > 0 ) {
348
+ if (FD_ISSET (0 , & rfds )) {
349
+ unsigned char data ;
350
+ read (0 , & data , 1 );
351
+ if (data == 035 )
352
+ goto end ;
353
+ write (writer_fd , & data , 1 );
354
+ }
355
+ if (FD_ISSET (reader_fd , & rfds )) {
356
+ unsigned char data ;
357
+ n = read (reader_fd , & data , 1 );
358
+ if (n == 1 )
359
+ process (data , reader_fd );
360
+ }
361
+ }
173
362
}
174
363
175
- process (reply , size );
364
+ end :
365
+ kill (reader_pid , SIGTERM );
366
+ kill (writer_pid , SIGTERM );
367
+ restore_termios ();
176
368
177
369
if (ncp_close (connection ) == -1 ) {
178
370
fprintf (stderr , "NCP close error.\n" );
@@ -271,7 +463,7 @@ int main (int argc, char **argv)
271
463
}
272
464
273
465
if (client )
274
- telnet_client (host , sock , new );
466
+ telnet_client (host , sock , new ? process_new : process_old );
275
467
else if (server )
276
468
telnet_server (sock , new );
277
469
0 commit comments