2 ** Copyright 2002, Travis Geiselbrecht. All rights reserved.
3 ** Distributed under the terms of the NewOS License.
5 #include <sys/syscalls.h>
6 #include <newos/errors.h>
11 #include <newos/tty_priv.h>
13 static int debug_fd
; // debug spew to the console
14 static int tty_master_fd
;
15 static int tty_slave_fd
;
18 static sem_id wait_sem
;
20 // XXX fix for big endian (move to libnet or whatever it's gonna be called)
21 static short ntohs(short value
)
23 return ((value
>>8)&0xff) | ((value
&0xff)<<8);
38 OPT_SUPPRESS_GO_AHEAD
= 3,
42 static void process_subblock(int sb_type
, unsigned char *buf
, int len
)
46 sprintf(temp
, "process_subblock: type %d, len %d\r\n", sb_type
, len
);
47 write(debug_fd
, temp
, strlen(temp
));
49 if(sb_type
== OPT_NAWS
) {
50 struct tty_winsize ws
;
52 ws
.cols
= ntohs(*(unsigned short *)&buf
[0]);
53 ws
.rows
= ntohs(*(unsigned short *)&buf
[2]);
54 sprintf(temp
, "NAWS %d %d\r\n", ws
.cols
, ws
.rows
);
55 write(debug_fd
, temp
, strlen(temp
));
57 ioctl(tty_master_fd
, _TTY_IOCTL_SET_WINSIZE
, &ws
, sizeof(ws
));
61 static int telnet_reader(void *arg
)
63 unsigned char buf
[4096];
64 unsigned char sb
[4096];
74 int output_start
, output_len
;
80 /* read from the socket */
81 len
= read(socket_fd
, buf
, sizeof(buf
));
87 for(i
= 0; i
< len
; i
++) {
88 // try to remove commands
94 write(tty_master_fd
, &buf
[output_start
], output_len
);
96 write(debug_fd
, "NORMAL: IAC\r\n", strlen("NORMAL: IAC\r\n"));
102 sprintf(temp
, "SEEN_IAC: 0x%x\r\n", buf
[i
]);
103 write(debug_fd
, temp
, strlen(temp
));
106 } else if(buf
[i
] == IAC
) {
111 state
= SEEN_OPT_NEGOTIATION
;
114 case SEEN_OPT_NEGOTIATION
:
115 sprintf(temp
, "SEEN_OPT_NEGOTIATION: 0x%x\r\n", buf
[i
]);
116 write(debug_fd
, temp
, strlen(temp
));
117 // we can transition back to normal now, we've eaten this option
123 sprintf(temp
, "SEEN_SB: 0x%x\r\n", buf
[i
]);
124 write(debug_fd
, temp
, strlen(temp
));
130 curr_sb_type
= buf
[i
];
136 sprintf(temp
, "IN_SB: 0x%x\r\n", buf
[i
]);
137 write(debug_fd
, temp
, strlen(temp
));
142 } else if(buf
[i
] == IAC
) {
143 process_subblock(curr_sb_type
, sb
, sb_len
);
145 sb
[sb_len
++] = buf
[i
];
151 write(tty_master_fd
, &buf
[output_start
], output_len
);
154 _kern_sem_release(wait_sem
, 1);
160 static int telnet_writer(void *arg
)
167 /* read from the tty's master end */
168 len
= read(tty_master_fd
, buf
, sizeof(buf
));
172 write_len
= write(socket_fd
, buf
, len
);
177 _kern_sem_release(wait_sem
, 1);
183 static int send_opts()
187 // negotiate the only options I care about
193 buf
[5] = OPT_SUPPRESS_GO_AHEAD
;
198 return write(socket_fd
, buf
, 9);
201 static void sigchld_handler(int signal
)
203 _kern_sem_release(wait_sem
, 1);
206 int main(int argc
, char **argv
)
215 printf("%s: not enough arguments\n", argv
[0]);
219 // we're a session leader
222 // build an array of args to pass anything we start up
223 spawn_argc
= argc
- 1;
224 spawn_argv
= (char **)malloc(sizeof(char *) * spawn_argc
);
225 if(spawn_argv
== NULL
)
227 for(i
= 0; i
< spawn_argc
; i
++) {
228 spawn_argv
[i
] = argv
[i
+ 1];
231 // register for SIGCHLD signals
232 signal(SIGCHLD
, &sigchld_handler
);
234 // debug_fd = open("/dev/console", 0);
237 wait_sem
= _kern_sem_create(0, "telnetd wait sem");
241 tty_master_fd
= open("/dev/tty/master", 0);
242 if(tty_master_fd
< 0)
245 tty_num
= ioctl(tty_master_fd
, _TTY_IOCTL_GET_TTY_NUM
, NULL
, 0);
250 struct tty_flags flags
;
252 ioctl(tty_master_fd
, _TTY_IOCTL_GET_TTY_FLAGS
, &flags
, sizeof(flags
));
253 flags
.input_flags
|= TTY_FLAG_CRNL
;
254 ioctl(tty_master_fd
, _TTY_IOCTL_SET_TTY_FLAGS
, &flags
, sizeof(flags
));
259 sprintf(temp
, "/dev/tty/slave/%d", tty_num
);
261 tty_slave_fd
= open(temp
, 0);
266 // move the stdin and stdout out of the way
267 socket_fd
= dup(0); // assume stdin, stdout, and stderr are the same socket
272 // set the endpoints to the tty slave endpoint
273 dup2(tty_slave_fd
, 0);
274 dup2(tty_slave_fd
, 1);
275 dup2(tty_slave_fd
, 2);
278 // send some options over to the other side
282 pid
= _kern_proc_create_proc(spawn_argv
[0], spawn_argv
[0], spawn_argv
, spawn_argc
, 5, PROC_FLAG_NEW_PGROUP
);
286 tid
= _kern_thread_create_thread("telnet reader", &telnet_reader
, NULL
);
287 _kern_thread_set_priority(tid
, 30);
288 _kern_thread_resume_thread(tid
);
290 tid
= _kern_thread_create_thread("telnet writer", &telnet_writer
, NULL
);
291 _kern_thread_set_priority(tid
, 30);
292 _kern_thread_resume_thread(tid
);
294 _kern_sem_acquire(wait_sem
, 1);