package main import ( "bufio" "fmt" "iptcp/pkg/ipstack" // "iptcp/pkg/tcpstack" "net/netip" "os" "strconv" "strings" ) func main() { if len(os.Args) == 1 { fmt.Printf("Usage: %s \n", os.Args[0]) os.Exit(1) } fileName := os.Args[2] err := ipstack.Initialize(fileName) if err != nil { return } ipstack.RegisterProtocolHandler(ipstack.TEST_PROTOCOL) ipstack.RegisterProtocolHandler(ipstack.TCP_PROTOCOL) // create a map of sockets sockets := make(map[int]*ipstack.VTCPConn) scanner := bufio.NewScanner(os.Stdin) for scanner.Scan() { line := scanner.Text() tokens := strings.Split(line, " ") switch tokens[0] { case "li": fmt.Println("Name\tAddr/Prefix\tState") fmt.Println(ipstack.SprintInterfaces()) case "ln": fmt.Println("Iface\tVIP\tUDPAddr") fmt.Println(ipstack.SprintNeighbors()) case "lr": fmt.Println("T\tPrefix\tNext Hop\tCost") fmt.Println(ipstack.SprintRoutingTable()) case "q": ipstack.CleanUp() os.Exit(0) case "exit": ipstack.CleanUp() os.Exit(0) case "down": // get interface name ifaceName := tokens[1] ipstack.InterfaceDownREPL(ifaceName) case "up": // get interface name ifaceName := tokens[1] ipstack.InterfaceUpREPL(ifaceName) case "send": // get IP address and message that follows it IPAndMessage := strings.Split(line, " ") ipAddr := IPAndMessage[1] message := IPAndMessage[2:] // combine message into one string messageToSend := strings.Join(message, " ") messageToSendBytes := []byte(messageToSend) address, _ := netip.ParseAddr(ipAddr) hop, err := ipstack.Route(address) if err != nil { fmt.Println(err) continue } myAddr := hop.Interface.IpPrefix.Addr() for _, neighbor := range ipstack.GetNeighbors()[hop.Interface.Name] { if neighbor.VipAddr == address || neighbor.VipAddr == hop.VIP && hop.Type == "S" { bytesWritten, err := ipstack.SendIP(&myAddr, neighbor, ipstack.TEST_PROTOCOL, messageToSendBytes, ipAddr, nil) fmt.Printf("Sent %d bytes to %s\n", bytesWritten, neighbor.VipAddr.String()) if err != nil { fmt.Println(err) } } } // ********************************************TCP REPL*************************************************************** case "a": // accept a connection // get the port number port := line[2:] uint16Port, err := strconv.ParseUint(port, 10, 16) if err != nil { fmt.Println(err) continue } // listen on the port listener, err := ipstack.VListen(uint16(uint16Port)) if err != nil { fmt.Println(err) continue } go func() { conn, err := listener.VAccept() if err != nil { fmt.Println(err) } sockets[conn.Socket] = conn }() case "c": if len(tokens) != 3 { fmt.Println("Invalid command: ", line) continue } // connect to a port vipAddr := tokens[1] port := tokens[2] uint16Port, err := strconv.ParseUint(port, 10, 16) if err != nil { fmt.Println(err) continue } conn, err := ipstack.VConnect(vipAddr, uint16(uint16Port)) if err != nil { fmt.Println(err) continue } sockets[conn.Socket] = conn case "ls": // list sockets fmt.Println("SID\tLAddr\t\tLPort\tRAddr\t\tRPort\tRStatus") fmt.Println(ipstack.SprintSockets()) case "s": if len(tokens) < 3 { fmt.Println("Invalid command: ", line) continue } socketID, err := strconv.Atoi(tokens[1]) if err != nil { fmt.Println(err) continue } conn, _ := sockets[socketID] message := tokens[2:] messageToSend := strings.Join(message, " ") messageToSendBytes := []byte(messageToSend) bytesWritten, err := conn.VWrite(messageToSendBytes) if err != nil { fmt.Println(err) continue } fmt.Printf("Sent %d bytes\n", bytesWritten) case "r": if len(tokens) != 3 { fmt.Println("Invalid command: ", line) continue } socketID, err := strconv.Atoi(tokens[1]) if err != nil { fmt.Println(err) continue } numberOfBytes, err := strconv.Atoi(tokens[2]) if err != nil { fmt.Println(err) continue } conn, _ := sockets[socketID] // buffer := make([]byte, numberOfBytes) bytesRead, message, err := conn.VRead(numberOfBytes) if err != nil { fmt.Println(err) continue } fmt.Printf("Read %d bytes: %s\n", bytesRead, message) case "cl": // close a socket if len(tokens) != 2 { fmt.Println("Invalid command: ", line) continue } socketID, err := strconv.Atoi(tokens[1]) if err != nil { fmt.Println(err) continue } conn, _ := sockets[socketID] err = conn.VClose() if err != nil { fmt.Println(err) continue } default: fmt.Println("Invalid command: ", line) fmt.Println("Commands: ") fmt.Println(" exit Terminate this program") fmt.Println(" li List interfaces") fmt.Println(" lr List routes") fmt.Println(" ln List available neighbors") fmt.Println(" up Enable an interface") fmt.Println(" down Disable an interface") fmt.Println(" send Send test packet") continue } } }