/[dynamips]/upstream/dynamips-0.2.7-RC1/dev_vtty.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /upstream/dynamips-0.2.7-RC1/dev_vtty.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 7 - (show annotations)
Sat Oct 6 16:23:47 2007 UTC (12 years, 1 month ago) by dpavlin
File MIME type: text/plain
File size: 28825 byte(s)
dynamips-0.2.7-RC1

1 /*
2 * Cisco router simulation platform.
3 * Copyright (c) 2005,2006 Christophe Fillot (cf@utc.fr)
4 *
5 * Virtual console TTY.
6 *
7 * "Interactive" part idea by Mtve.
8 * TCP console added by Mtve.
9 * Serial console by Peter Ross (suxen_drol@hotmail.com)
10 */
11
12 /* By default, Cygwin supports only 64 FDs with select()! */
13 #ifdef __CYGWIN__
14 #define FD_SETSIZE 1024
15 #endif
16
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <unistd.h>
21 #include <sys/types.h>
22 #include <sys/socket.h>
23 #include <termios.h>
24 #include <fcntl.h>
25 #include <errno.h>
26 #include <assert.h>
27
28 #include <arpa/telnet.h>
29
30 #include "utils.h"
31 #include "cpu.h"
32 #include "vm.h"
33 #include "dynamips.h"
34 #include "mips64_exec.h"
35 #include "ppc32_exec.h"
36 #include "device.h"
37 #include "memory.h"
38 #include "dev_c7200.h"
39 #include "dev_c3600.h"
40 #include "dev_c2691.h"
41 #include "dev_c3725.h"
42 #include "dev_c3745.h"
43 #include "dev_c2600.h"
44 #include "dev_vtty.h"
45
46 /* VTTY list */
47 static pthread_mutex_t vtty_list_mutex = PTHREAD_MUTEX_INITIALIZER;
48 static vtty_t *vtty_list = NULL;
49 static pthread_t vtty_thread;
50
51 #define VTTY_LIST_LOCK() pthread_mutex_lock(&vtty_list_mutex);
52 #define VTTY_LIST_UNLOCK() pthread_mutex_unlock(&vtty_list_mutex);
53
54 static struct termios tios,tios_orig;
55
56 /* Send Telnet command: WILL TELOPT_ECHO */
57 static void vtty_telnet_will_echo(vtty_t *vtty)
58 {
59 u_char cmd[] = { IAC, WILL, TELOPT_ECHO };
60 write(vtty->fd,cmd,sizeof(cmd));
61 }
62
63 /* Send Telnet command: Suppress Go-Ahead */
64 static void vtty_telnet_will_suppress_go_ahead(vtty_t *vtty)
65 {
66 u_char cmd[] = { IAC, WILL, TELOPT_SGA };
67 write(vtty->fd,cmd,sizeof(cmd));
68 }
69
70 /* Send Telnet command: Don't use linemode */
71 static void vtty_telnet_dont_linemode(vtty_t *vtty)
72 {
73 u_char cmd[] = { IAC, DONT, TELOPT_LINEMODE };
74 write(vtty->fd,cmd,sizeof(cmd));
75 }
76
77 /* Send Telnet command: does the client support terminal type message? */
78 static void vtty_telnet_do_ttype(vtty_t *vtty)
79 {
80 u_char cmd[] = { IAC, DO, TELOPT_TTYPE };
81 write(vtty->fd,cmd,sizeof(cmd));
82 }
83
84 /* Restore TTY original settings */
85 static void vtty_term_reset(void)
86 {
87 tcsetattr(STDIN_FILENO,TCSANOW,&tios_orig);
88 }
89
90 /* Initialize real TTY */
91 static void vtty_term_init(void)
92 {
93 tcgetattr(STDIN_FILENO,&tios);
94
95 memcpy(&tios_orig,&tios,sizeof(struct termios));
96 atexit(vtty_term_reset);
97
98 tios.c_cc[VTIME] = 0;
99 tios.c_cc[VMIN] = 1;
100
101 /* Disable Ctrl-C, Ctrl-S, Ctrl-Q and Ctrl-Z */
102 tios.c_cc[VINTR] = 0;
103 tios.c_cc[VSTART] = 0;
104 tios.c_cc[VSTOP] = 0;
105 tios.c_cc[VSUSP] = 0;
106
107 tios.c_lflag &= ~(ICANON|ECHO);
108 tios.c_iflag &= ~ICRNL;
109 tcsetattr(STDIN_FILENO, TCSANOW, &tios);
110 tcflush(STDIN_FILENO,TCIFLUSH);
111 }
112
113 /* Wait for a TCP connection */
114 static int vtty_tcp_conn_wait(vtty_t *vtty)
115 {
116 struct sockaddr_in serv;
117 int one = 1;
118
119 vtty->state = VTTY_STATE_TCP_INVALID;
120
121 if ((vtty->accept_fd = socket(PF_INET,SOCK_STREAM,0)) < 0) {
122 perror("vtty_tcp_waitcon: socket");
123 return(-1);
124 }
125
126 if (setsockopt(vtty->accept_fd,SOL_SOCKET,SO_REUSEADDR,
127 &one,sizeof(one)) < 0)
128 {
129 perror("vtty_tcp_waitcon: setsockopt(SO_REUSEADDR)");
130 goto error;
131 }
132
133 memset(&serv,0,sizeof(serv));
134 serv.sin_family = AF_INET;
135 serv.sin_addr.s_addr = htonl(INADDR_ANY);
136 serv.sin_port = htons(vtty->tcp_port);
137
138 if (bind(vtty->accept_fd,(struct sockaddr *)&serv,sizeof(serv)) < 0) {
139 perror("vtty_tcp_waitcon: bind");
140 goto error;
141 }
142
143 if (listen(vtty->accept_fd,1) < 0) {
144 perror("vtty_tcp_waitcon: listen");
145 goto error;
146 }
147
148 vm_log(vtty->vm,"VTTY","%s: waiting connection on tcp port %d (FD %d)\n",
149 vtty->name,vtty->tcp_port,vtty->accept_fd);
150
151 vtty->select_fd = &vtty->accept_fd;
152 vtty->state = VTTY_STATE_TCP_WAITING;
153 return(0);
154
155 error:
156 close(vtty->accept_fd);
157 vtty->accept_fd = -1;
158 vtty->select_fd = NULL;
159 return(-1);
160 }
161
162 /* Accept a TCP connection */
163 static int vtty_tcp_conn_accept(vtty_t *vtty)
164 {
165 if ((vtty->fd = accept(vtty->accept_fd,NULL,NULL)) < 0) {
166 fprintf(stderr,"vtty_tcp_conn_accept: accept on port %d failed %s\n",
167 vtty->tcp_port,strerror(errno));
168 return(-1);
169 }
170
171 vm_log(vtty->vm,"VTTY","%s is now connected (accept_fd=%d,conn_fd=%d)\n",
172 vtty->name,vtty->accept_fd,vtty->fd);
173
174 /* Adapt Telnet settings */
175 if (vtty->terminal_support) {
176 vtty_telnet_do_ttype(vtty);
177 vtty_telnet_will_echo(vtty);
178 vtty_telnet_will_suppress_go_ahead(vtty);
179 vtty_telnet_dont_linemode(vtty);
180 vtty->input_state = VTTY_INPUT_TELNET;
181 }
182
183 if (!(vtty->fstream = fdopen(vtty->fd, "wb"))) {
184 close(vtty->fd);
185 vtty->fd = -1;
186 return(-1);
187 }
188
189 fprintf(vtty->fstream,
190 "Connected to Dynamips VM \"%s\" (ID %u, type %s) - %s\r\n\r\n",
191 vtty->vm->name, vtty->vm->instance_id, vm_get_type(vtty->vm),
192 vtty->name);
193
194 vtty->select_fd = &vtty->fd;
195 vtty->state = VTTY_STATE_TCP_RUNNING;
196 return(0);
197 }
198
199 /*
200 * Parse serial interface descriptor string, return 0 if success
201 * string takes the form "device:baudrate:databits:parity:stopbits:hwflow"
202 * device is mandatory, other options are optional (default=9600,8,N,1,0).
203 */
204 int vtty_parse_serial_option(vtty_serial_option_t *option, char *optarg)
205 {
206 char *array[6];
207 int count;
208
209 if ((count = m_strtok(optarg, ':', array, 6)) < 1) {
210 fprintf(stderr,"vtty_parse_serial_option: invalid string\n");
211 return(-1);
212 }
213
214 if (!(option->device = strdup(array[0]))) {
215 fprintf(stderr,"vtty_parse_serial_option: unable to copy string\n");
216 return(-1);
217 }
218
219 option->baudrate = (count>1) ? atoi(array[1]) : 9600;
220 option->databits = (count>2) ? atoi(array[2]) : 8;
221
222 if (count > 3) {
223 switch(*array[3]) {
224 case 'o':
225 case 'O':
226 option->parity = 1; /* odd */
227 case 'e':
228 case 'E':
229 option->parity = 2; /* even */
230 default:
231 option->parity = 0; /* none */
232 }
233 } else {
234 option->parity = 0;
235 }
236
237 option->stopbits = (count>4) ? atoi(array[4]) : 1;
238 option->hwflow = (count>5) ? atoi(array[5]) : 0;
239 return(0);
240 }
241
242 #if defined(__CYGWIN__) || defined(SUNOS)
243 void cfmakeraw(struct termios *termios_p) {
244 termios_p->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|
245 INLCR|IGNCR|ICRNL|IXON);
246 termios_p->c_oflag &= ~OPOST;
247 termios_p->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
248 termios_p->c_cflag &= ~(CSIZE|PARENB);
249 termios_p->c_cflag |= CS8;
250 }
251 #endif
252
253 /*
254 * Setup serial port, return 0 if success.
255 */
256 static int vtty_serial_setup(vtty_t *vtty, const vtty_serial_option_t *option)
257 {
258 struct termios tio;
259 int tio_baudrate;
260
261 if (tcgetattr(vtty->fd, &tio) != 0) {
262 fprintf(stderr, "error: tcgetattr failed\n");
263 return(-1);
264 }
265
266 cfmakeraw(&tio);
267
268 tio.c_cflag = 0
269 |CLOCAL // ignore modem control lines
270 ;
271
272 tio.c_cflag &= ~CREAD;
273 tio.c_cflag |= CREAD;
274
275 switch(option->baudrate) {
276 case 50 : tio_baudrate = B50; break;
277 case 75 : tio_baudrate = B75; break;
278 case 110 : tio_baudrate = B110; break;
279 case 134 : tio_baudrate = B134; break;
280 case 150 : tio_baudrate = B150; break;
281 case 200 : tio_baudrate = B200; break;
282 case 300 : tio_baudrate = B300; break;
283 case 600 : tio_baudrate = B600; break;
284 case 1200 : tio_baudrate = B1200; break;
285 case 1800 : tio_baudrate = B1800; break;
286 case 2400 : tio_baudrate = B2400; break;
287 case 4800 : tio_baudrate = B4800; break;
288 case 9600 : tio_baudrate = B9600; break;
289 case 19200 : tio_baudrate = B19200; break;
290 case 38400 : tio_baudrate = B38400; break;
291 case 57600 : tio_baudrate = B57600; break;
292 #if defined(B76800)
293 case 76800 : tio_baudrate = B76800; break;
294 #endif
295 case 115200 : tio_baudrate = B115200; break;
296 #if defined(B230400)
297 case 230400 : tio_baudrate = B230400; break;
298 #endif
299 default:
300 fprintf(stderr, "error: unsupported baudrate\n");
301 return(-1);
302 }
303
304 cfsetospeed(&tio, tio_baudrate);
305 cfsetispeed(&tio, tio_baudrate);
306
307 tio.c_cflag &= ~CSIZE; /* clear size flag */
308 switch(option->databits) {
309 case 5 : tio.c_cflag |= CS5; break;
310 case 6 : tio.c_cflag |= CS6; break;
311 case 7 : tio.c_cflag |= CS7; break;
312 case 8 : tio.c_cflag |= CS8; break;
313 default :
314 fprintf(stderr, "error: unsupported databits\n");
315 return(-1);
316 }
317
318 tio.c_iflag &= ~INPCK; /* clear parity flag */
319 tio.c_cflag &= ~(PARENB|PARODD);
320 switch(option->parity) {
321 case 0 : break;
322 case 2 : tio.c_iflag|=INPCK; tio.c_cflag|=PARENB; break; /* even */
323 case 1 : tio.c_iflag|=INPCK; tio.c_cflag|=PARENB|PARODD; break; /* odd */
324 default:
325 fprintf(stderr, "error: unsupported parity\n");
326 return(-1);
327 }
328
329 tio.c_cflag &= ~CSTOPB; /* clear stop flag */
330 switch(option->stopbits) {
331 case 1 : break;
332 case 2 : tio.c_cflag |= CSTOPB; break;
333 default :
334 fprintf(stderr, "error: unsupported stopbits\n");
335 return(-1);
336 }
337
338 #if defined(CRTSCTS)
339 tio.c_cflag &= ~CRTSCTS;
340 #endif
341 #if defined(CNEW_RTSCTS)
342 tio.c_cflag &= ~CNEW_RTSCTS;
343 #endif
344 if (option->hwflow) {
345 #if defined(CRTSCTS)
346 tio.c_cflag |= CRTSCTS;
347 #else
348 tio.c_cflag |= CNEW_RTSCTS;
349 #endif
350 }
351
352 tio.c_cc[VTIME] = 0;
353 tio.c_cc[VMIN] = 1; /* block read() until one character is available */
354
355 #if 0
356 /* not neccessary unless O_NONBLOCK used */
357 if (fcntl(vtty->fd, F_SETFL, 0) != 0) { /* enable blocking mode */
358 fprintf(stderr, "error: fnctl F_SETFL failed\n");
359 return(-1);
360 }
361 #endif
362
363 if (tcflush(vtty->fd, TCIOFLUSH) != 0) {
364 fprintf(stderr, "error: tcflush failed\n");
365 return(-1);
366 }
367
368 if (tcsetattr(vtty->fd, TCSANOW, &tio) != 0 ) {
369 fprintf(stderr, "error: tcsetattr failed\n");
370 return(-1);
371 }
372
373 return(0);
374 }
375
376 /* Create a virtual tty */
377 vtty_t *vtty_create(vm_instance_t *vm,char *name,int type,int tcp_port,
378 const vtty_serial_option_t *option)
379 {
380 vtty_t *vtty;
381
382 if (!(vtty = malloc(sizeof(*vtty)))) {
383 fprintf(stderr,"VTTY: unable to create new virtual tty.\n");
384 return NULL;
385 }
386
387 memset(vtty,0,sizeof(*vtty));
388 vtty->name = name;
389 vtty->type = type;
390 vtty->vm = vm;
391 vtty->fd = -1;
392 vtty->fstream = NULL;
393 vtty->accept_fd = -1;
394 pthread_mutex_init(&vtty->lock,NULL);
395 vtty->terminal_support = 1;
396 vtty->input_state = VTTY_INPUT_TEXT;
397
398 switch (vtty->type) {
399 case VTTY_TYPE_NONE:
400 vtty->select_fd = NULL;
401 break;
402
403 case VTTY_TYPE_TERM:
404 vtty_term_init();
405 vtty->fd = STDIN_FILENO;
406 vtty->select_fd = &vtty->fd;
407 vtty->fstream = stdout;
408 break;
409
410 case VTTY_TYPE_TCP:
411 vtty->tcp_port = tcp_port;
412 vtty_tcp_conn_wait(vtty);
413 break;
414
415 case VTTY_TYPE_SERIAL:
416 vtty->fd = open(option->device, O_RDWR);
417 if (vtty->fd < 0) {
418 fprintf(stderr,"VTTY: open failed\n");
419 free(vtty);
420 return NULL;
421 }
422 if (vtty_serial_setup(vtty,option)) {
423 fprintf(stderr,"VTTY: setup failed\n");
424 close(vtty->fd);
425 free(vtty);
426 return NULL;
427 }
428 vtty->select_fd = &vtty->fd;
429 vtty->terminal_support = 0;
430 break;
431
432 default:
433 fprintf(stderr,"tty_create: bad vtty type %d\n",vtty->type);
434 return NULL;
435 }
436
437 /* Add this new VTTY to the list */
438 VTTY_LIST_LOCK();
439 vtty->next = vtty_list;
440 vtty->pprev = &vtty_list;
441
442 if (vtty_list != NULL)
443 vtty_list->pprev = &vtty->next;
444
445 vtty_list = vtty;
446 VTTY_LIST_UNLOCK();
447 return vtty;
448 }
449
450 /* Delete a virtual tty */
451 void vtty_delete(vtty_t *vtty)
452 {
453 if (vtty != NULL) {
454 if (vtty->pprev != NULL) {
455 VTTY_LIST_LOCK();
456 if (vtty->next)
457 vtty->next->pprev = vtty->pprev;
458 *(vtty->pprev) = vtty->next;
459 VTTY_LIST_UNLOCK();
460 }
461
462 if ((vtty->fstream) && (vtty->fstream != stdout))
463 fclose(vtty->fstream);
464
465 /* We don't close FD 0 since it is stdin */
466 if (vtty->fd > 0) {
467 vm_log(vtty->vm,"VTTY","%s: closing FD %d\n",vtty->name,vtty->fd);
468 close(vtty->fd);
469 }
470
471 if (vtty->accept_fd != -1) {
472 vm_log(vtty->vm,"VTTY","%s: closing accept FD %d\n",
473 vtty->name,vtty->accept_fd);
474 close(vtty->accept_fd);
475 }
476
477 free(vtty);
478 }
479 }
480
481 /* Store a character in the FIFO buffer */
482 static int vtty_store(vtty_t *vtty,u_char c)
483 {
484 u_int nwptr;
485
486 VTTY_LOCK(vtty);
487 nwptr = vtty->write_ptr + 1;
488 if (nwptr == VTTY_BUFFER_SIZE)
489 nwptr = 0;
490
491 if (nwptr == vtty->read_ptr) {
492 VTTY_UNLOCK(vtty);
493 return(-1);
494 }
495
496 vtty->buffer[vtty->write_ptr] = c;
497 vtty->write_ptr = nwptr;
498 VTTY_UNLOCK(vtty);
499 return(0);
500 }
501
502 /* Store a string in the FIFO buffer */
503 int vtty_store_str(vtty_t *vtty,char *str)
504 {
505 if (!vtty)
506 return(0);
507
508 while(*str != 0) {
509 if (vtty_store(vtty,*str) == -1)
510 return(-1);
511
512 str++;
513 }
514
515 vtty->input_pending = TRUE;
516 return(0);
517 }
518
519 /* Store CTRL+C in buffer */
520 int vtty_store_ctrlc(vtty_t *vtty)
521 {
522 if (vtty)
523 vtty_store(vtty,0x03);
524 return(0);
525 }
526
527 /*
528 * Read a character from the terminal.
529 */
530 static int vtty_term_read(vtty_t *vtty)
531 {
532 u_char c;
533
534 if (read(vtty->fd,&c,1) == 1)
535 return(c);
536
537 perror("read from vtty failed");
538 return(-1);
539 }
540
541 /*
542 * Read a character from the TCP connection.
543 */
544 static int vtty_tcp_read(vtty_t *vtty)
545 {
546 u_char c;
547
548 switch(vtty->state) {
549 case VTTY_STATE_TCP_RUNNING:
550 if (read(vtty->fd,&c,1) == 1)
551 return(c);
552
553 /* Problem with the connection: Re-enter wait mode */
554 shutdown(vtty->fd,2);
555 fclose(vtty->fstream);
556 close(vtty->fd);
557 vtty->fstream = NULL;
558 vtty->fd = -1;
559 vtty->select_fd = &vtty->accept_fd;
560 vtty->state = VTTY_STATE_TCP_WAITING;
561 return(-1);
562
563 case VTTY_STATE_TCP_WAITING:
564 /* A new connection has arrived */
565 vtty_tcp_conn_accept(vtty);
566 return(-1);
567 }
568
569 /* Shouldn't happen... */
570 return(-1);
571 }
572
573 /*
574 * Read a character from the virtual TTY.
575 *
576 * If the VTTY is a TCP connection, restart it in case of error.
577 */
578 static int vtty_read(vtty_t *vtty)
579 {
580 switch(vtty->type) {
581 case VTTY_TYPE_TERM:
582 case VTTY_TYPE_SERIAL:
583 return(vtty_term_read(vtty));
584 case VTTY_TYPE_TCP:
585 return(vtty_tcp_read(vtty));
586 default:
587 fprintf(stderr,"vtty_read: bad vtty type %d\n",vtty->type);
588 return(-1);
589 }
590
591 /* NOTREACHED */
592 return(-1);
593 }
594
595 /* Remote control for MIPS64 processors */
596 static int remote_control_mips64(vtty_t *vtty,char c,cpu_mips_t *cpu)
597 {
598 switch(c) {
599 /* Show information about JIT compiled pages */
600 case 'b':
601 printf("\nCPU0: %u JIT compiled pages [Exec Area Pages: %lu/%lu]\n",
602 cpu->compiled_pages,
603 (u_long)cpu->exec_page_alloc,
604 (u_long)cpu->exec_page_count);
605 break;
606
607 /* Non-JIT mode statistics */
608 case 'j':
609 mips64_dump_stats(cpu);
610 break;
611
612 default:
613 return(FALSE);
614 }
615
616 return(TRUE);
617 }
618
619 /* Remote control for PPC32 processors */
620 static int remote_control_ppc32(vtty_t *vtty,char c,cpu_ppc_t *cpu)
621 {
622 switch(c) {
623 /* Show information about JIT compiled pages */
624 case 'b':
625 printf("\nCPU0: %u JIT compiled pages [Exec Area Pages: %lu/%lu]\n",
626 cpu->compiled_pages,
627 (u_long)cpu->exec_page_alloc,
628 (u_long)cpu->exec_page_count);
629 break;
630
631 /* Non-JIT mode statistics */
632 case 'j':
633 ppc32_dump_stats(cpu);
634 break;
635
636 default:
637 return(FALSE);
638 }
639
640 return(TRUE);
641 }
642
643 /* Process remote control char */
644 static void remote_control(vtty_t *vtty,u_char c)
645 {
646 vm_instance_t *vm = vtty->vm;
647 cpu_gen_t *cpu0;
648
649 cpu0 = vm->boot_cpu;
650
651 /* Specific commands for the different CPU models */
652 if (cpu0) {
653 switch(cpu0->type) {
654 case CPU_TYPE_MIPS64:
655 if (remote_control_mips64(vtty,c,CPU_MIPS64(cpu0)))
656 return;
657 break;
658 case CPU_TYPE_PPC32:
659 if (remote_control_ppc32(vtty,c,CPU_PPC32(cpu0)))
660 return;
661 break;
662 }
663 }
664
665 switch(c) {
666 /* Show the object list */
667 case 'o':
668 vm_object_dump(vm);
669 break;
670
671 /* Stop the MIPS VM */
672 case 'q':
673 vm->status = VM_STATUS_SHUTDOWN;
674 break;
675
676 /* Reboot the C7200 */
677 case 'k':
678 #if 0
679 if (vm->type == VM_TYPE_C7200)
680 c7200_boot_ios(VM_C7200(vm));
681 #endif
682 break;
683
684 /* Show the device list */
685 case 'd':
686 dev_show_list(vm);
687 pci_dev_show_list(vm->pci_bus[0]);
688 pci_dev_show_list(vm->pci_bus[1]);
689 break;
690
691 /* Show info about Port Adapters or Network Modules */
692 case 'p':
693 switch(vm->type) {
694 case VM_TYPE_C3600:
695 c3600_nm_show_all_info(VM_C3600(vm));
696 break;
697 case VM_TYPE_C7200:
698 c7200_pa_show_all_info(VM_C7200(vm));
699 break;
700 case VM_TYPE_C2691:
701 c2691_nm_show_all_info(VM_C2691(vm));
702 break;
703 case VM_TYPE_C3725:
704 c3725_nm_show_all_info(VM_C3725(vm));
705 break;
706 case VM_TYPE_C3745:
707 c3745_nm_show_all_info(VM_C3745(vm));
708 break;
709 case VM_TYPE_C2600:
710 c2600_nm_show_all_info(VM_C2600(vm));
711 break;
712 }
713 break;
714
715 /* Dump the MIPS registers */
716 case 'r':
717 if (cpu0) cpu0->reg_dump(cpu0);
718 break;
719
720 /* Dump the latest memory accesses */
721 case 'm':
722 if (cpu0) memlog_dump(cpu0);
723 break;
724
725 /* Suspend CPU emulation */
726 case 's':
727 vm_suspend(vm);
728 break;
729
730 /* Resume CPU emulation */
731 case 'u':
732 vm_resume(vm);
733 break;
734
735 /* Dump the MMU information */
736 case 't':
737 if (cpu0) cpu0->mmu_dump(cpu0);
738 break;
739
740 /* Dump the MMU information (raw mode) */
741 case 'z':
742 if (cpu0) cpu0->mmu_raw_dump(cpu0);
743 break;
744
745 /* Memory translation cache statistics */
746 case 'l':
747 if (cpu0) cpu0->mts_show_stats(cpu0);
748 break;
749
750 /* Extract the configuration from the NVRAM */
751 case 'c':
752 vm_ios_save_config(vm);
753 break;
754
755 /* Determine an idle pointer counter */
756 case 'i':
757 if (cpu0)
758 cpu0->get_idling_pc(cpu0);
759 break;
760
761 /* Experimentations / Tests */
762 case 'x':
763 if (cpu0) {
764 /* IRQ triggering */
765 vm_set_irq(vm,2);
766 }
767 break;
768
769 case 'y':
770 if (cpu0) {
771 /* IRQ clearing */
772 vm_clear_irq(vm,2);
773 }
774 break;
775
776 /* Twice Ctrl + ']' (0x1d, 29), or Alt-Gr + '*' (0xb3, 179) */
777 case 0x1d:
778 case 0xb3:
779 vtty_store(vtty,c);
780 break;
781
782 default:
783 printf("\n\nInstance %s (ID %d)\n\n",vm->name,vm->instance_id);
784
785 printf("o - Show the VM object list\n"
786 "d - Show the device list\n"
787 "r - Dump CPU registers\n"
788 "t - Dump MMU information\n"
789 "z - Dump MMU information (raw mode)\n"
790 "m - Dump the latest memory accesses\n"
791 "s - Suspend CPU emulation\n"
792 "u - Resume CPU emulation\n"
793 "q - Quit the emulator\n"
794 "k - Reboot the virtual machine\n"
795 "b - Show info about JIT compiled pages\n"
796 "l - MTS cache statistics\n"
797 "c - Write IOS configuration to disk\n"
798 "j - Non-JIT mode statistics\n"
799 "i - Determine an idling pointer counter\n"
800 "x - Experimentations (can crash the box!)\n"
801 "^] - Send ^]\n"
802 "Other - This help\n");
803 }
804 }
805
806
807 /* Read a character (until one is available) and store it in buffer */
808 static void vtty_read_and_store(vtty_t *vtty)
809 {
810 int c;
811
812 /* wait until we get a character input */
813 c = vtty_read(vtty);
814
815 /* if read error, do nothing */
816 if (c < 0) return;
817
818 if (!vtty->terminal_support) {
819 vtty_store(vtty,c);
820 return;
821 }
822
823 switch(vtty->input_state) {
824 case VTTY_INPUT_TEXT :
825 switch(c) {
826 case 0x1b:
827 vtty->input_state = VTTY_INPUT_VT1;
828 return;
829
830 /* Ctrl + ']' (0x1d, 29), or Alt-Gr + '*' (0xb3, 179) */
831 case 0x1d:
832 case 0xb3:
833 vtty->input_state = VTTY_INPUT_REMOTE;
834 return;
835 case IAC :
836 vtty->input_state = VTTY_INPUT_TELNET;
837 return;
838 case 0: /* NULL - Must be ignored - generated by Linux telnet */
839 case 10: /* LF (Line Feed) - Must be ignored on Windows platform */
840 return;
841 default:
842 /* Store a standard character */
843 vtty_store(vtty,c);
844 return;
845 }
846
847 case VTTY_INPUT_VT1 :
848 switch(c) {
849 case 0x5b:
850 vtty->input_state = VTTY_INPUT_VT2;
851 return;
852 default:
853 vtty_store(vtty,0x1b);
854 vtty_store(vtty,c);
855 }
856 vtty->input_state = VTTY_INPUT_TEXT;
857 return;
858
859 case VTTY_INPUT_VT2 :
860 switch(c) {
861 case 0x41: /* Up Arrow */
862 vtty_store(vtty,16);
863 break;
864 case 0x42: /* Down Arrow */
865 vtty_store(vtty,14);
866 break;
867 case 0x43: /* Right Arrow */
868 vtty_store(vtty,6);
869 break;
870 case 0x44: /* Left Arrow */
871 vtty_store(vtty,2);
872 break;
873 default:
874 vtty_store(vtty,0x5b);
875 vtty_store(vtty,0x1b);
876 vtty_store(vtty,c);
877 break;
878 }
879 vtty->input_state = VTTY_INPUT_TEXT;
880 return;
881
882 case VTTY_INPUT_REMOTE :
883 remote_control(vtty, c);
884 vtty->input_state = VTTY_INPUT_TEXT;
885 return;
886
887 case VTTY_INPUT_TELNET :
888 vtty->telnet_cmd = c;
889 switch(c) {
890 case WILL:
891 case WONT:
892 case DO:
893 case DONT:
894 vtty->input_state = VTTY_INPUT_TELNET_IYOU;
895 return;
896 case SB :
897 vtty->telnet_cmd = c;
898 vtty->input_state = VTTY_INPUT_TELNET_SB1;
899 return;
900 case SE:
901 break;
902 case IAC :
903 vtty_store(vtty, IAC);
904 break;
905 }
906 vtty->input_state = VTTY_INPUT_TEXT;
907 return;
908
909 case VTTY_INPUT_TELNET_IYOU :
910 vtty->telnet_opt = c;
911 /* if telnet client can support ttype, ask it to send ttype string */
912 if ((vtty->telnet_cmd == WILL) &&
913 (vtty->telnet_opt == TELOPT_TTYPE))
914 {
915 vtty_put_char(vtty, IAC);
916 vtty_put_char(vtty, SB);
917 vtty_put_char(vtty, TELOPT_TTYPE);
918 vtty_put_char(vtty, TELQUAL_SEND);
919 vtty_put_char(vtty, IAC);
920 vtty_put_char(vtty, SE);
921 }
922 vtty->input_state = VTTY_INPUT_TEXT;
923 return;
924
925 case VTTY_INPUT_TELNET_SB1 :
926 vtty->telnet_opt = c;
927 vtty->input_state = VTTY_INPUT_TELNET_SB2;
928 return;
929
930 case VTTY_INPUT_TELNET_SB2 :
931 vtty->telnet_qual = c;
932 if ((vtty->telnet_opt == TELOPT_TTYPE) &&
933 (vtty->telnet_qual == TELQUAL_IS))
934 vtty->input_state = VTTY_INPUT_TELNET_SB_TTYPE;
935 else
936 vtty->input_state = VTTY_INPUT_TELNET_NEXT;
937 return;
938
939 case VTTY_INPUT_TELNET_SB_TTYPE :
940 /* parse ttype string: first char is sufficient */
941 /* if client is xterm or vt, set the title bar */
942 if ((c == 'x') || (c == 'X') || (c == 'v') || (c == 'V')) {
943 fprintf(vtty->fstream, "\033]0;Dynamips(%i): %s, %s\07",
944 vtty->vm->instance_id, vtty->vm->name, vtty->name);
945 }
946 vtty->input_state = VTTY_INPUT_TELNET_NEXT;
947 return;
948
949 case VTTY_INPUT_TELNET_NEXT :
950 /* ignore all chars until next IAC */
951 if (c == IAC)
952 vtty->input_state = VTTY_INPUT_TELNET;
953 return;
954 }
955 }
956
957 /* Read a character from the buffer (-1 if the buffer is empty) */
958 int vtty_get_char(vtty_t *vtty)
959 {
960 u_char c;
961
962 VTTY_LOCK(vtty);
963
964 if (vtty->read_ptr == vtty->write_ptr) {
965 VTTY_UNLOCK(vtty);
966 return(-1);
967 }
968
969 c = vtty->buffer[vtty->read_ptr++];
970
971 if (vtty->read_ptr == VTTY_BUFFER_SIZE)
972 vtty->read_ptr = 0;
973
974 VTTY_UNLOCK(vtty);
975 return(c);
976 }
977
978 /* Returns TRUE if a character is available in buffer */
979 int vtty_is_char_avail(vtty_t *vtty)
980 {
981 int res;
982
983 VTTY_LOCK(vtty);
984 res = (vtty->read_ptr != vtty->write_ptr);
985 VTTY_UNLOCK(vtty);
986 return(res);
987 }
988
989 /* Put char to vtty */
990 void vtty_put_char(vtty_t *vtty, char ch)
991 {
992 switch(vtty->type) {
993 case VTTY_TYPE_NONE:
994 break;
995
996 case VTTY_TYPE_TERM:
997 fwrite(&ch, 1, 1, vtty->fstream);
998 break;
999
1000 case VTTY_TYPE_TCP:
1001 if ((vtty->state == VTTY_STATE_TCP_RUNNING) &&
1002 (fwrite(&ch, 1, 1, vtty->fstream) != 1))
1003 {
1004 vm_log(vtty->vm,"VTTY","%s: put char %d failed (%s)\n",
1005 vtty->name,(int)ch,strerror(errno));
1006 }
1007 break;
1008
1009 case VTTY_TYPE_SERIAL:
1010 if (write(vtty->fd,&ch,1) != 1) {
1011 vm_log(vtty->vm,"VTTY","%s: put char 0x%x failed (%s)\n",
1012 vtty->name,(int)ch,strerror(errno));
1013 }
1014 break;
1015
1016 default:
1017 fprintf(stderr,"vtty_put_char: bad vtty type %d\n",vtty->type);
1018 exit(1);
1019 }
1020 }
1021
1022 /* Put a buffer to vtty */
1023 void vtty_put_buffer(vtty_t *vtty,char *buf,size_t len)
1024 {
1025 size_t i;
1026
1027 for(i=0;i<len;i++)
1028 vtty_put_char(vtty,buf[i]);
1029 }
1030
1031 /* Flush VTTY output */
1032 void vtty_flush(vtty_t *vtty)
1033 {
1034 switch(vtty->type) {
1035 case VTTY_TYPE_TERM:
1036 case VTTY_TYPE_TCP:
1037 if (vtty->fstream)
1038 fflush(vtty->fstream);
1039 break;
1040
1041 case VTTY_TYPE_SERIAL:
1042 fsync(vtty->fd);
1043 break;
1044 }
1045 }
1046
1047 /* VTTY thread */
1048 static void *vtty_thread_main(void *arg)
1049 {
1050 vtty_t *vtty;
1051 struct timeval tv;
1052 int fd,fd_max,res;
1053 fd_set rfds;
1054
1055 for(;;) {
1056 VTTY_LIST_LOCK();
1057
1058 /* Build the FD set */
1059 FD_ZERO(&rfds);
1060 fd_max = -1;
1061 for(vtty=vtty_list;vtty;vtty=vtty->next) {
1062 if (!vtty->select_fd)
1063 continue;
1064
1065 if ((fd = *vtty->select_fd) < 0)
1066 continue;
1067
1068 if (fd > fd_max) fd_max = fd;
1069 FD_SET(fd,&rfds);
1070 }
1071 VTTY_LIST_UNLOCK();
1072
1073 /* Wait for incoming data */
1074 tv.tv_sec = 0;
1075 tv.tv_usec = 50 * 1000; /* 50 ms */
1076 res = select(fd_max+1,&rfds,NULL,NULL,&tv);
1077
1078 if (res == -1) {
1079 if (errno != EINTR) {
1080 perror("vtty_thread: select");
1081
1082 for(vtty=vtty_list;vtty;vtty=vtty->next) {
1083 fprintf(stderr," %-15s: %s, FD %d\n",
1084 vtty->vm->name,vtty->name,vtty->fd);
1085 }
1086 }
1087 continue;
1088 }
1089
1090 /* Examine active FDs and call user handlers */
1091 VTTY_LIST_LOCK();
1092 for(vtty=vtty_list;vtty;vtty=vtty->next) {
1093 if (!vtty->select_fd)
1094 continue;
1095
1096 if ((fd = *vtty->select_fd) < 0)
1097 continue;
1098
1099 if (FD_ISSET(fd,&rfds)) {
1100 vtty_read_and_store(vtty);
1101 vtty->input_pending = TRUE;
1102 }
1103
1104 if (vtty->input_pending) {
1105 if (vtty->read_notifier != NULL)
1106 vtty->read_notifier(vtty);
1107
1108 vtty->input_pending = FALSE;
1109 }
1110
1111 /* Flush any pending output */
1112 if (!vtty->managed_flush)
1113 vtty_flush(vtty);
1114 }
1115 VTTY_LIST_UNLOCK();
1116 }
1117
1118 return NULL;
1119 }
1120
1121 /* Initialize the VTTY thread */
1122 int vtty_init(void)
1123 {
1124 if (pthread_create(&vtty_thread,NULL,vtty_thread_main,NULL)) {
1125 perror("vtty: pthread_create");
1126 return(-1);
1127 }
1128
1129 return(0);
1130 }

  ViewVC Help
Powered by ViewVC 1.1.26