#!/usr/bin/python

import socket
import fcntl
import struct
import netifaces as ni

from mininet.topo import Topo
from mininet.net import Mininet
from mininet.node import Node
from mininet.log import setLogLevel, info
from mininet.cli import CLI

def ip_checksum(void* vdata,size_t length):
    char* data=(char*)vdata
    uint32_t acc=0xffff
    size_t i=0
    for i<length :
      uint16_t word
      memcpy(&word,data+i,2)
      acc+=ntohs(word)
      if acc>0xffff :
          acc-=0xffff
      i+=2
    
   
    if length&1 :
      uint16_t word=0
      memcpy(&word,data+length-1,1)
      acc+=ntohs(word)
      if acc>0xffff :
         acc-=0xffff
    
    
    return htons(~acc)
    

class LinuxRouter( Node ):
    "A Node with IP forwarding enabled."

    def config( self, **params ):
        super( LinuxRouter, self).config( **params )
        # Enable forwarding on the router
        self.cmd( 'sysctl net.ipv4.ip_forward=1' )

    def terminate( self ):
        self.cmd( 'sysctl net.ipv4.ip_forward=0' )
        super( LinuxRouter, self ).terminate()

class NetworkTopo( Topo ):
    "A LinuxRouter connecting three IP subnets"

    def build( self, **_opts ):

        defaultIP = '192.168.1.1/24'  # IP address for r0-eth1
        router = self.addNode( 'r0', cls=LinuxRouter, ip=defaultIP )

        s1, s2, s3 = [ self.addSwitch( s ) for s in ( 's1', 's2', 's3' ) ]

        self.addLink( s1, router, intfName2='r0-eth1',
                      params2={ 'ip' : defaultIP } )  # for clarity
        self.addLink( s2, router, intfName2='r0-eth2',
                      params2={ 'ip' : '172.16.0.1/12' } )
        self.addLink( s3, router, intfName2='r0-eth3',
                      params2={ 'ip' : '10.0.0.1/8' } )

        h1x1 = self.addHost( 'h1x1', ip='192.168.1.101/24', mac='00:00:00:00:00:11',
                           defaultRoute='via 192.168.1.1' )
        h1x2 = self.addHost( 'h1x2', ip='192.168.1.102/24', mac='00:00:00:00:00:12',
                           defaultRoute='via 192.168.1.1' )
        h2x1 = self.addHost( 'h2x1', ip='172.16.0.101/12', mac='00:00:00:00:00:21',
                           defaultRoute='via 172.16.0.1' )
        h2x2 = self.addHost( 'h2x2', ip='172.16.0.102/12', mac='00:00:00:00:00:22',
                           defaultRoute='via 172.16.0.1' )
        h3x1 = self.addHost( 'h3x1', ip='10.0.0.101/8', mac='00:00:00:00:00:31',
                           defaultRoute='via 10.0.0.1' )
        h3x2 = self.addHost( 'h3x2', ip='10.0.0.102/8', mac='00:00:00:00:00:32',
                           defaultRoute='via 10.0.0.1' )

        for h, s in [ (h1x1, s1), (h1x2, s1), (h2x1, s2), (h2x2, s2), (h3x1, s3), (h3x2, s3) ]:
            self.addLink( h, s )

def run():

    topo = NetworkTopo()
    net = Mininet( topo=topo )  # controller is used by s1-s3
    net.start()
    info( '*** Routing Table on Router:\n' )
    info( net[ 'r0' ].cmd( 'route' ) )
    mode=raw_input(‘send or recv’)

    interfacename=rawinput('input interfacename')
    intfIP= ni.ifaddresses(interfacename)[ni.AF_INET][0]['addr']

    if mode == 'send':
         destIP=rawinput('input destIP')
         routerIP=rawinput('input router')
         buf=rawinput('input message')
	 message=ip_checksum(buf, 20)

         s=socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
 	 s.bind((intfIP, 7777))
         s.send(buf)

         s.close

    elif mode == 'recv':
         s=socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
 	 s.bind((intfIP, 7777))
         
	 data = s.recv(2048)
	 print('receive:')
	 print data

         s.close

    else:
         print(''Error')
         exit()


if __name__ == '__main__':
    setLogLevel( 'info' )
    run()
