/* * mainloop.c: * * Copyright (c) 2008 James McKenzie , * All rights reserved. * */ static char rcsid[] = "$Id$"; /* * $Log$ * Revision 1.34 2012/06/22 10:22:24 james * *** empty log message *** * * Revision 1.33 2008/05/09 12:35:57 james * *** empty log message *** * * Revision 1.32 2008/03/11 17:56:50 james * *** empty log message *** * * Revision 1.31 2008/03/11 17:56:04 james * *** empty log message *** * * Revision 1.30 2008/03/11 17:47:24 james * *** empty log message *** * * Revision 1.29 2008/03/10 11:49:32 james * *** empty log message *** * * Revision 1.28 2008/03/07 13:56:39 james * *** empty log message *** * * Revision 1.27 2008/03/07 13:16:02 james * *** empty log message *** * * Revision 1.26 2008/03/06 21:34:09 james * *** empty log message *** * * Revision 1.25 2008/03/06 21:33:02 james * *** empty log message *** * * Revision 1.24 2008/03/06 16:49:39 james * *** empty log message *** * * Revision 1.23 2008/03/06 16:49:05 james * *** empty log message *** * * Revision 1.22 2008/03/03 06:04:42 james * *** empty log message *** * * Revision 1.21 2008/03/02 10:27:24 james * *** empty log message *** * * Revision 1.20 2008/02/28 16:57:51 james * *** empty log message *** * * Revision 1.19 2008/02/28 16:37:16 james * *** empty log message *** * * Revision 1.18 2008/02/28 11:27:48 james * *** empty log message *** * * Revision 1.17 2008/02/27 09:42:53 james * *** empty log message *** * * Revision 1.16 2008/02/27 09:42:21 james * *** empty log message *** * * Revision 1.15 2008/02/27 01:31:38 james * *** empty log message *** * * Revision 1.14 2008/02/27 01:31:14 james * *** empty log message *** * * Revision 1.13 2008/02/26 23:56:12 james * *** empty log message *** * * Revision 1.12 2008/02/26 23:23:16 james * *** empty log message *** * * Revision 1.11 2008/02/24 00:43:55 james * *** empty log message *** * * Revision 1.10 2008/02/23 13:05:57 staffcvs * *** empty log message *** * * Revision 1.9 2008/02/23 11:48:51 james * *** empty log message *** * * Revision 1.8 2008/02/22 23:39:30 james * *** empty log message *** * * Revision 1.7 2008/02/20 20:16:07 james * *** empty log message *** * * Revision 1.6 2008/02/20 19:44:37 james * @@ * * Revision 1.5 2008/02/20 18:31:44 james * *** empty log message *** * * Revision 1.4 2008/02/20 17:18:33 james * *** empty log message *** * * Revision 1.3 2008/02/20 02:11:35 james * *** empty log message *** * * Revision 1.2 2008/02/16 10:58:52 james * *** empty log message *** * * Revision 1.13 2008/02/15 23:52:12 james * *** empty log message *** * * Revision 1.12 2008/02/15 03:32:07 james * *** empty log message *** * * Revision 1.11 2008/02/14 16:21:17 james * *** empty log message *** * * Revision 1.10 2008/02/14 10:39:14 james * *** empty log message *** * * Revision 1.9 2008/02/14 10:34:47 james * *** empty log message *** * * Revision 1.8 2008/02/14 10:34:30 james * *** empty log message *** * * Revision 1.7 2008/02/14 02:46:44 james * *** empty log message *** * * Revision 1.6 2008/02/14 00:57:58 james * *** empty log message *** * * Revision 1.5 2008/02/13 18:05:06 james * *** empty log message *** * * Revision 1.4 2008/02/13 17:21:55 james * *** empty log message *** * * Revision 1.3 2008/02/08 15:06:52 james * *** empty log message *** * * Revision 1.2 2008/02/07 15:42:49 james * *** empty log message *** * * Revision 1.1 2008/02/05 14:25:49 james * *** empty log message *** * */ #include #include #include "mainloop.h" #include "clients.h" static inline char * stop_wno_unused_on_rcsid (void) { return rcsid; } typedef struct { int nclients; int lines; int baud; int crtscts; int cd_edge_sec; int blocked; int bootstrap; } Status; static Status get_status (TTY * t, Clients * cs) { static struct timeval last_cd_edge = { 0 }; static int last_cd_state = -1; int cd; struct timeval now, dif; TTY_Status tty_status = { 0 }; Status status; tty_get_status (t, &tty_status); status.bootstrap = 1; if (cs) status.nclients = cs->n; else status.nclients = 0; status.lines = tty_status.lines; status.baud = tty_status.baud; status.crtscts = (tty_status.termios.c_cflag & CRTSCTS) ? 1 : 0; status.blocked = tty_status.blocked; cd = (tty_status.lines & TIOCM_CD) ? 1 : 0; if (cd != last_cd_state) { gettimeofday (&last_cd_edge, NULL); last_cd_state = cd; } gettimeofday (&now, NULL); timersub (&now, &last_cd_edge, &dif); status.cd_edge_sec = dif.tv_sec; return status; } static char * line_to_name (int l) { switch (l) { #ifdef TIOCM_LE case TIOCM_LE: return "LE"; #endif #ifdef TIOCM_DTR case TIOCM_DTR: return "DTR"; #endif #ifdef TIOCM_RTS case TIOCM_RTS: return "RTS"; #endif #ifdef TIOCM_ST case TIOCM_ST: return "ST"; #endif #ifdef TIOCM_SR case TIOCM_SR: return "SR"; #endif #ifdef TIOCM_CTS case TIOCM_CTS: return "CTS"; #endif #ifdef TIOCM_CD case TIOCM_CD: return "CD"; #endif #ifdef TIOCM_RI case TIOCM_RI: return "RI"; #endif #ifdef TIOCM_DSR case TIOCM_DSR: return "DSR"; #endif } return "??"; } static void log_line_changes (Context * ctx, int old, int new) { int dif = old ^ new; int c = 1; char buf[1024], *ptr = buf; char *n; if (!dif) return; if (!ctx->l) return; n = "= c) { if (dif & c) { *(ptr++) = ' '; *(ptr++) = (new & c) ? '+' : '-'; n = line_to_name (c); while (*n) *(ptr++) = *(n++); } c <<= 1; } *(ptr++) = '>'; *ptr = 0; ctx->l->log (ctx->l, buf); } static char * do_line (char *ptr, int lines, int line) { char *lname; if (!(lines & line)) return ptr; lname = line_to_name (line); *(ptr++) = ' '; while (*lname) *(ptr++) = *(lname++); return ptr; } static void check_status (Context * c, Clients * cs) { static Status old_status = { 0 }; Status status; char buf[1024]; char *ptr = buf; char *t; status = get_status (c->t, cs); if (!memcmp (&status, &old_status, sizeof (status))) return; log_line_changes (c, old_status.lines, status.lines); old_status = status; ptr += sprintf (ptr, "CTRL-B "); t = c->t->name; if (!strncmp (t, "/dev/", 5)) t += 5; while (*t) *(ptr++) = *(t++); ptr += sprintf (ptr, " %db", status.baud); ptr = do_line (ptr, status.lines, TIOCM_RTS); ptr = do_line (ptr, status.lines, TIOCM_CTS); ptr = do_line (ptr, status.lines, TIOCM_DTR); ptr = do_line (ptr, status.lines, TIOCM_DSR); ptr = do_line (ptr, status.lines, TIOCM_RI); ptr = do_line (ptr, status.lines, TIOCM_CD); if (status.blocked) { t = ", Locked"; while (*t) *(ptr++) = *(t++); } if (status.crtscts) { t = ", Flow"; while (*t) *(ptr++) = *(t++); } #if 0 if (status.lines & TIOCM_CD) { ptr += sprintf (ptr, ", On %d.%d", status.cd_edge_sec / 60, status.cd_edge_sec % 60); } else { ptr += sprintf (ptr, ", Off %d.%d", status.cd_edge_sec / 60, status.cd_edge_sec % 60); } #endif ptr += sprintf (ptr, ", %d client%s", status.nclients, (status.nclients == 1) ? "" : "s"); if (c->tp->biterrs) { ptr += sprintf (ptr, ", %d err%s", c->tp->biterrs, (c->tp->biterrs == 1) ? "" : "s"); if (c->tp->guessed_baud == -1) { ptr += sprintf (ptr, " try higher"); } else if (c->tp->guessed_baud > 0) { ptr += sprintf (ptr, " try %db", c->tp->guessed_baud); } } *ptr = 0; #if 0 log_f (c->l, "%s:%d %s", __FILE__, __LINE__, buf); #endif if (cs) send_status (cs, buf); else cmd_new_status (c->d, c, buf); } static int msg_from_server (ANSI * a, IPC_Msg * m, Context * c) { int err = 0; switch (m->hdr.type) { case IPC_MSG_TYPE_NOOP: break; case IPC_MSG_TYPE_DEBUG: // fprintf (stderr,"%p [%d] %s\n", m, m->hdr.size , m->debug.msg ); break; case IPC_MSG_TYPE_HISTORY: history_add (c->h, m->history.history.line); break; case IPC_MSG_TYPE_VT102: if (sizeof (VT102) != m->vt102.len) crash_out ("sizeof(VT102) differs in client and server"); *(c->v) = m->vt102.vt102; if (a->one_shot) { a->one_shot (a, &c->v->crt); err++; /* Simulate a fatal write error enclosing tty */ } break; case IPC_MSG_TYPE_TERM: err += tty_parse (c, (uint8_t *) m->term.term, m->term.len); break; case IPC_MSG_TYPE_STATUS: cmd_new_status (c->d, c, m->status.status); break; default: fprintf (stderr, "Unhandeled message type %d\n", m->hdr.type); } return err; } void mainloop (Context * c, ANSI * ansi, Socket * server_socket, Socket * client_socket) { fd_set rfds, wfds; Clients *clients; c->tp = tty_parser_new (); c->u = utf8_new (); /* are we being fed by a tty or a socket */ if (client_socket) { if (server_socket) crash_out ("mainloop cannot both be a server and a client"); c->k = keydis_ipc_new (client_socket); } else { if (!c->t) crash_out ("mainloop must have either a client_socket or a terminal"); c->k = keydis_vt102_new (); } /* do we have an upstream terminal to talk to */ /* if so start a command parser */ if (ansi) { c->d = cmd_new (); } else { c->d = NULL; } vt102_reset (c); if (server_socket) { if (client_socket) crash_out ("mainloop cannot both be a server and a client"); clients = clients_new (); } else { clients = NULL; } for (;;) { struct timeval tv = { 0, 250000 }; if ((c->d) && (c->d->disconnect)) break; /* update the status lines, locally or remotely */ if (c->t) check_status (c, clients); FD_ZERO (&rfds); FD_ZERO (&wfds); if (c->t) tty_pre_select (c->t, &rfds, &wfds); if (server_socket) { FD_SET (server_socket->fd, &rfds); clients_pre_select (clients, &rfds, &wfds); } if (client_socket) socket_pre_select (client_socket, &rfds, &wfds); if (ansi && ansi->terminal) tty_pre_select (ansi->terminal, &rfds, &wfds); select (FD_SETSIZE, &rfds, &wfds, NULL, &tv); /* any message from clients, or new connexions */ if (server_socket) { Socket *new_client_socket; if (FD_ISSET (server_socket->fd, &rfds) && ((new_client_socket = socket_accept (server_socket)))) { { Client *new_client; /* New client connexion */ new_client = clients_new_client (clients, new_client_socket, c); } } clients_post_select (clients, c, &rfds, &wfds); } /* any data from the port */ if (c->t && FD_ISSET (c->t->rfd, &rfds)) { char buf[IPC_MAX_BUF]; int red; red = c->t->recv (c->t, buf, sizeof (buf)); if (red < 0) break; if (red) { if (clients) send_output (clients, buf, red); if (tty_parse (c, (uint8_t *) buf, red)) break; } } /* any data from the server */ if (client_socket) { int err = 0; if (socket_post_select (client_socket, &rfds, &wfds)) break; while (client_socket->msg && !err) { err += msg_from_server (ansi, client_socket->msg, c); socket_consume_msg (client_socket); } if (err) break; } /* update our local screen */ if (ansi) { if (ansi->dispatch) if (ansi->dispatch (ansi, c)) break; if (ansi->update) if (ansi->update (ansi, c)) break; } } if (clients) clients_shutdown (clients, c); log_f (c->l, ""); }