/[dynamips]/upstream/dynamips-0.2.6-RC3/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

Annotation of /upstream/dynamips-0.2.6-RC3/dev_vtty.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 4 - (hide annotations)
Sat Oct 6 16:06:49 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 27096 byte(s)
dynamips-0.2.6-RC3

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

  ViewVC Help
Powered by ViewVC 1.1.26