Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import (
- "fmt"
- "time"
- "sync"
- "rand"
- )
- type Address struct {
- IP string
- port int16
- }
- func (addr Address) String() string {
- return addr.IP + ":" + fmt.Sprintf("%d", addr.port)
- }
- type Type int8
- const (
- CALL Type = 0
- REPLY Type = 1
- ACK Type = 2
- NACK Type = 3
- )
- var DefaultAddr Address
- var ACKPacket *Packet = &Packet{DefaultAddr, DefaultAddr, 1, ACK, 10, ""}
- var NACKPacket *Packet = &Packet{DefaultAddr, DefaultAddr, 1, NACK, 10, ""}
- type Packet struct {
- SRC Address
- DST Address
- TTL int16
- Type
- Size int64
- Data string
- }
- type Channel struct {
- IN chan Packet
- OUT chan Packet
- State chan bool
- UP bool
- onWire int64
- onWireLock sync.RWMutex
- Bandwidth int64
- Delay int64
- Reliability float
- }
- type Link struct {
- UP *Channel
- DOWN Channel
- }
- type Links []Link
- type Route struct {
- DST *Address
- NextHop *Channel
- TotDelay int64
- TotBandwidth int64
- TotReliability float
- Hops int
- }
- type Routes []Route
- type RoutingTable map[string]Routes
- type Router struct {
- Links
- RoutingTable
- }
- /*
- (Channel) pkt
- --> OUT -->
- --> OUT -->
- --> OUT --> PacketReceiver
- --> Routing()
- -->
- -->
- --> IN --> PacketSender --> OUT
- -->
- -->
- */
- func (ch *Channel) PacketSender() {
- // send packet to OUT chan
- send := func(pkt Packet) {
- // random packet loss (reliability based)
- if ch.Reliability < rand.Float() {
- return
- }
- // if link failed, reset onWire and don't send anything
- if ch.UP == false {
- ch.onWireLock.Lock()
- ch.onWire = 0
- ch.onWireLock.Unlock()
- return
- }
- // increase OnWire
- ch.onWireLock.Lock()
- ch.onWire += pkt.Size
- ch.onWireLock.Unlock()
- // packet on wire for Delay nanoseconds
- time.Sleep(ch.Delay)
- // wait for other end to accept it
- ch.OUT <- pkt
- // decrease OnWire
- ch.onWireLock.Lock()
- ch.onWire -= pkt.Size
- ch.onWireLock.Unlock()
- }
- check := func(size int64) bool {
- ch.onWireLock.RLock()
- defer ch.onWireLock.RUnlock()
- // enough bandwidth to send?
- if ch.onWire+size <= ch.Bandwidth {
- return true
- }
- return false
- }
- go func() {
- for {
- select {
- case pkt := <-ch.IN:
- // wait until enough bandwidth
- for {
- if check(pkt.Size) {
- break
- }
- // retry in 1ms
- time.Sleep(1e6)
- }
- go send(pkt)
- case s := <-ch.State:
- // link failed, stop accepting packets
- if !s {
- ch.UP = false
- return
- }
- }
- }
- }()
- }
- func (ch *Channel) PacketReceiver(routing chan *Packet) {
- go func() {
- for {
- pkt := <-ch.OUT
- if ch.UP == false {
- return
- }
- routing <- &pkt
- }
- }()
- }
- type Node struct {
- Address
- Link
- }
- func (n *Node) Start(peers []*Node) chan bool {
- quit1 := make(chan bool)
- quit2 := make(chan bool)
- sink := make(chan *Packet)
- sinker := func() {
- for {
- select {
- case <-quit1:
- quit2 <- true
- return
- case pkt := <-sink:
- fmt.Println(n.Address.String() + " | <- " + pkt.Data)
- }
- }
- }
- generator := func() {
- ticker := time.NewTicker(1e9)
- for {
- select {
- case <- quit2:
- return
- case <-ticker.C:
- if rand.Float() > 0.3 {
- i := rand.Intn(len(peers) - 1)
- pkt := new(Packet)
- pkt.SRC = n.Address
- pkt.DST = peers[i].Address
- pkt.Type = CALL
- pkt.TTL = 64
- pkt.Size = 16
- pkt.Data = "PING"
- n.Link.UP.IN <- pkt
- }
- }
- }
- }
- go n.Link.UP.PacketSender()
- go n.Link.DOWN.PacketReceiver(sink)
- go sinker()
- go generator()
- return quit1
- }
- func mkChannel(bandwidth int64, delay int64, reliability float) Channel {
- var ch Channel
- ch.IN = make(chan Packet)
- ch.OUT = make(chan Packet)
- ch.State = make(chan bool)
- ch.onWire = 0
- ch.Bandwidth = bandwidth
- ch.Delay = delay
- ch.Reliability = reliability
- ch.UP = true
- return ch
- }
- func mkLink(up *Channel, down Channel) Link {
- var link Link
- link.UP = up
- link.DOWN = down
- return link
- }
- func main() {
- tx := mkChannel(1e9, 2e9, 0.50)
- rx := mkChannel(1e9, 1e9, 0.45)
- link1 := mkLink(&tx, rx)
- link2 := mkLink(&rx, tx)
- n1 := Node(Address("127.0.0.1", 1000), link1)
- n2 := Node(Address("127.0.0.1", 1001), link2)
- n1.Start()
- n2.Start()
- time.Sleep(60 * 1e9)
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement