//------------------------------------------------------------------- // trychat.cpp // // This experimental version of our 'nicchat.cpp' application // broadcasts each keystroke to all the other stations on our // local network (but places a value in the type/length field // of the packet's ethernet-header that causes those messages // to be discarded by customary network software). Note that // this program uses our 'withpoll.c' device-driver services. // // programmer: ALLAN CRUSE // written on: 24 APR 2005 //------------------------------------------------------------------- #include // for printf(), perror() #include // for open() #include // for exit() #include // for read(), write(), close() #include // for memset(), memcpy() #include // for tcgetattr(), tcsetattr() #include // for ntohs(), htons() #include // for ioctl() #define CHAT_ID 0x0635 // identifier for our protocol typedef struct { unsigned char dst[6]; unsigned char src[6]; unsigned short typlen; unsigned short nbytes; unsigned char inch[48]; } CHAT_FRAME; void handle_kbd_input( int, int ); void handle_nic_input( int ); char devname[] = "/dev/nic"; char devaddr[ 6 ]; int done = 0; int main( int argc, char **argv ) { // open device-file and obtain device's hardware-address int nic = open( devname, O_RDWR ); if ( nic < 0 ) { perror( devname ); exit(1); } if ( ioctl( nic, 0, devaddr ) < 0 ) { perror( "ioctl" ); exit(1); } // setup our terminal for noncanonical input-mode struct termios orig_term; int kbd = STDIN_FILENO; tcgetattr( kbd, &orig_term ); struct termios work_term = orig_term; work_term.c_lflag &= ~( ECHO | ICANON ); work_term.c_cc[ VMIN ] = 1; work_term.c_cc[ VTIME ] = 0; tcsetattr( kbd, TCSAFLUSH, &work_term ); // main program loop to handle multiplexed device-input do { fd_set readset; FD_ZERO( &readset ); FD_SET( nic, &readset ); FD_SET( kbd, &readset ); if ( select( 1+nic, &readset, 0, 0, 0 ) < 0 ) break; if ( FD_ISSET( kbd, &readset ) ) handle_kbd_input( kbd, nic ); if ( FD_ISSET( nic, &readset ) ) handle_nic_input( nic ); } while ( !done ); // restore our terminal's original settings tcsetattr( kbd, TCSAFLUSH, &orig_term ); printf( "\n" ); } void handle_nic_input( int nic ) { CHAT_FRAME msg = {0}; // reads next message received by the network interface int nbytes = read( nic, &msg, sizeof( msg ) ); // disregard the message if not sent by our application if ( ntohs( msg.typlen ) != CHAT_ID ) return; // otherwise echo the message's keystroke to the screen write( STDOUT_FILENO, msg.inch, msg.nbytes ); } void handle_kbd_input( int kbd, int nic ) { unsigned char inch[ 8 ] = {0}; // reads the next keystroke typed by the local user int nbytes = read( kbd, inch, sizeof( inch ) ); if ( nbytes < 0 ) return; // echo the keystroke to the local display screen write( STDOUT_FILENO, inch, nbytes ); // also transmit this keystroke to other stations CHAT_FRAME msg = {0}; memset( msg.dst, 0xFF, 6 ); // dest'n address memcpy( msg.src, devaddr, 6 ); // source address msg.typlen = htons( CHAT_ID ); // set type field msg.nbytes = nbytes; // count of chars memcpy( msg.inch, inch, nbytes ); // copy bytes write( nic, &msg, sizeof( msg ) ); // to network // set 'done' flag if -key was pressed if ( *(int*)inch == '\e' ) done = 1; }