//------------------------------------------------------------------- // clonetos.cpp (A revision of our ' msgserver.cpp' demo) // // This revision of our 'msgserver.cpp' echo-server will reply // to an incoming message with an outgoing message that has an // identical value in its IP-header's 'Type-of-Service' field, // thereby providing us with yet another example in which some // ancillary data gets delivered via the 'recvmsg()' function. // // to compile: $ g++ clonetos.cpp -o clonetos // to execute: $ ./clonetos // // programmer: ALLAN CRUSE // written on: 18 Feb 2009 //------------------------------------------------------------------- #include // for printf(), perror() #include // for exit() #include // for bzero() #include // for gethostname() #include // for inet_ntoa() #define SERVER_PORT 54321 int main( int argc, char **argv ) { //----------------------------------------------- // get this station's hostname for later display //----------------------------------------------- char hostname[ 64 ] = {0}; gethostname( hostname, 63 ); //------------------------------------------------------------------ // create an internet datagram socket to receive incomming messages //------------------------------------------------------------------ int sock = socket( AF_INET, SOCK_DGRAM, IPPROTO_IP ); if ( sock < 0 ) { perror( "socket" ); exit(1); } //--------------------------------------------------------- // set a socket-option allowing this socket to be reusable //--------------------------------------------------------- int oval = 1; int olen = sizeof( oval ); if ( setsockopt( sock, SOL_SOCKET, SO_REUSEADDR, &oval, olen ) < 0 ) { perror( "setsockopt" ); exit(1); } //------------------------------------------------------------------ // initialize a socket-address structure using a 'wildcard' address //------------------------------------------------------------------ struct sockaddr_in saddr = { 0 }; socklen_t salen = sizeof( saddr ); saddr.sin_family = AF_INET; saddr.sin_port = htons( SERVER_PORT ); saddr.sin_addr.s_addr = htonl( INADDR_ANY ); //-------------------------------------------------- // bind the socket to this socket-address structure //-------------------------------------------------- if ( bind( sock, (sockaddr*)&saddr, salen ) < 0 ) { perror( "bind" ); exit(1); } //----------------------------------------------------- // enable the IP_RECVTOS socket option for this socket //----------------------------------------------------- if ( setsockopt( sock, SOL_IP, IP_RECVTOS, &oval, olen ) < 0 ) { perror( "setsockopt RECVTOS" ); exit(1); } //-------------------------------------------------- // main loop to receive and echo incomming messages //-------------------------------------------------- int count = 0; do { //------------------------------------------------------- // setup structures needed in our 'struct msghdr' object //------------------------------------------------------- struct sockaddr_in from = { 0 }; socklen_t flen = sizeof( from ); char buf[ 1500 ] = {0}; int blen = sizeof( buf ); struct iovec myiov[ 1 ] = { { buf, blen } }; unsigned char cbuf[ 40 ]; //---------------------------------------------------- // allocate and initialize our 'struct msghdr' object //---------------------------------------------------- struct msghdr mymsg = { 0 }; size_t msglen = sizeof( mymsg ); mymsg.msg_name = &from; mymsg.msg_namelen = flen; mymsg.msg_iov = myiov; mymsg.msg_iovlen = 1; mymsg.msg_control = cbuf; mymsg.msg_controllen = sizeof( cbuf ); mymsg.msg_flags = 0; //--------------------------------------------------------- // show our socket's port-number and the name of this host //--------------------------------------------------------- printf( "\n ok, server is listening" ); printf( " to port %u on %s ... ", SERVER_PORT, hostname ); fflush( stdout ); //------------------------------------------------------- // receive a client's message sent to this server's port //------------------------------------------------------- int rx = recvmsg( sock, &mymsg, 0 ); if ( rx < 0 ) { perror( "recvmsg" ); exit(1); } //------------------------------------------------------- // extract this message's TOS-value from ancilliary data //------------------------------------------------------- int tos = 0; int tlen = 1; struct cmsghdr *cmsg; for ( cmsg = CMSG_FIRSTHDR( &mymsg ); cmsg != NULL; cmsg = CMSG_NXTHDR( &mymsg, cmsg ) ) { if (( cmsg->cmsg_level == SOL_IP ) &&( cmsg->cmsg_type == IP_TOS )) { memcpy( &tos, CMSG_DATA( cmsg ), tlen ); } } //------------------------------------------------------ // report the incomming message's size, source, and TOS //------------------------------------------------------ printf( "\n #%d received %d bytes ", ++count, rx ); printf( "from \'%s\' ", inet_ntoa( from.sin_addr ) ); printf( "with TOS=0x%02X \n\n", tos ); puts( buf ); //----------------------------------------------------- // modify our socket's default 'Type-of-Service' value //----------------------------------------------------- if ( setsockopt( sock, SOL_IP, IP_TOS, &tos, tlen ) < 0 ) { perror( "setsockopt TOS" ); exit(1); } //------------------------------------------------------- // send the message back with its same 'Type-of-Service' //------------------------------------------------------- myiov[0].iov_len = rx; mymsg.msg_control = NULL; mymsg.msg_controllen = 0; int tx = sendmsg( sock, &mymsg, 0 ); if ( tx < 0 ) { perror( "sendmsg" ); exit(1); } printf( "\n returned %d bytes ", tx ); printf( "to \'%s\' ", inet_ntoa( from.sin_addr ) ); printf( "with TOS=0x%02X \n\n", tos ); } while ( 1 ); }